Close

Entry 6: The Virtual 65C02

A project log for Aiie! - an embedded Apple //e emulator

A Teensy 4.1 running as an Apple //e

jorj-bauerJorj Bauer 02/19/2017 at 19:300 Comments

(This may take a little while; now that I'm reasonably happy with the code, I'm refactoring it while I describe it. I've just created a public github repo to hold it all. This entry refers to git commit 85a97abe13528bdf35c525f42aea7ffb003eafff.)

Emulating a CPU isn't difficult. It's mostly a matter of interpreting the next instruction, one instruction at a time, over and over again. The 65C02 is pretty straightforward: it has three 8-bit registers named a, x, and y; an 8-bit stack pointer, sp; an 8-bit status register that holds flags about the current state; and a 16-bit program counter (pc) which has the address of memory that's currently being executed.

One step of the CPU means getting the byte of memory at the PC; executing it so that it changes A, X, Y, STATUS, SP, and PC depending on the instruction; and incrementing the PC to the start of the next instruction.

All of that is in step().

The CPU can address 16 bits of memory. An easy version of the CPU would just have a 64k array that it reads from and writes to. But the memory on the Apple II is not that straightforward. If, for example, you read from memory address $C000 you'll get whatever key is pressed. If you write to anything between $C0C0 and $C0CF, you're interacting with whatever's in slot 6. All of which means we need an intermediate Memory Management Unit to broker all reads and writes. And that's what we now have: a CPU with an MMU model.

Pulling that together with a simple test harness lets us check that the CPU works properly. There's a great utility written by Klaus Dormann that tests all of the 6502's functionality. There are precompiled binaries in there that I've dropped in to the test harness that prove it works correctly:

$ make test
g++ -Wall -I .. -I . -O3 -DBASICTEST cpu.cpp util/testharness.cpp -o testharness.basic
g++ -Wall -I .. -I . -O3 -DVERBOSETEST cpu.cpp util/testharness.cpp -o testharness.verbose
g++ -Wall -I .. -I . -O3 -DEXTENDEDTEST cpu.cpp util/testharness.cpp -o testharness.extended

Start test 2
Start test 3
Start test 4
Start test 5
Start test 6
Start test 7
Start test 8
Start test 9
Start test 10
Start test 11
Start test 12
Start test 13
Start test 14
Start test 15
Start test 16
Start test 17
Start test 18
Start test 19
Start test 20
Start test 21
Start test 22
Start test 23
Start test 24
Start test 25
Start test 26
Start test 27
Start test 28
Start test 29
Start test 30
Start test 31
Start test 32
Start test 33
Start test 34
Start test 35
Start test 36
Start test 37
Start test 38
Start test 39
Start test 40
Start test 41
Start test 42
Start test 240
11 seconds
Ending PC: 0x3399
And that's success!

Discussions