A personal project into making a fast instruction-level emulator for the MOS 6502.
It's not really useful for any real-world applications and certainly can't be dropped in to any existing emulator.
The goal was to make a clean-room implementation from online documentation and to experiment with micro-optimisations just for fun. It involved a lot of fiddling, a bit of profiling, and even some learning!
- Passes Klaus Doorman's 6502 functional tests - This seems a common benchmark.
- Zero-alloc - Entirely by accident.
- Most functions can be inlined -
ADCandSBCfail the complexity checks. - Bounds checks elided on memory - No boilerplate to panic because we can't access invalid indexes.
- Bit twiddling in favour of boolean states - Profiled where branch prediction was faster though!
- Avoids dynamic dispatch - Deliberately not using an interface for memory reading or function tables for instructions
- Cycle accounting and speed limiting - Optional, use the
cyclestag. Not sure why I added it really.
Without cycle accounting:
$ go test -bench=. -run BenchFunctional -benchtime 10s
goos: linux
goarch: amd64
pkg: mos6502
cpu: AMD Ryzen 7 3700X 8-Core Processor
BenchmarkHandler-16 1000000000 4.179 ns/op
PASS
ok mos6502 4.619The step function is generated from metadata. To regenerate it run:
$ go run ./cpu_step_gen.goBuild, test, or bench with -tags cycles
$ go test -bench=. -run BenchFunctional -benchtime 10s -tags cycles
goos: linux
goarch: amd64
pkg: mos6502
cpu: AMD Ryzen 7 3700X 8-Core Processor
BenchmarkHandler-16 1000000000 4.355 ns/op
PASS
ok mos6502 4.804s- https://masswerk.at/6502/6502_instruction_set.html
- https://github.com/Klaus2m5/6502_65C02_functional_tests
- https://www.c64-wiki.com
- This project is licensed under Apache 2.0. See LICENSE.
- Test data in the
testdatadirectory is licensed under GPL v3. See LICENSE-testdata.