A
ccumulatorX
, Y
indexP
rocessor statusS
tack pointer
LDA STA LDX ... ; load / store A, X, Y
TAX TXA ... ; transfer A to X
PHA PLA ; push A / pull A
CMP ; compare with A
ADC SBC ; add / subtract with carry
CLC SEC ; clear / set carry
JMP ; jump
BEQ BNE BCS BCC ; branch ==, !=, carry set/clear
BMI BPL ... ; <0, >=0
JSR ; jump to subroutine
RTS ; return from subroutine
a9 20 LDA #$20 ; A = 0x20
a5 70 LDA $70 ; A = readmem(0x70)
ad 34 12 LDA $1234 ; A = readmem(0x1234)
bd 34 12 LDA $1234, X ; A = readmem(0x1234 + X)
b9 34 12 LDA $1234, Y ; A = readmem(0x1234 + Y)
b1 70 LDA ($70), Y ; t1 = readmem(0x70)
; t2 = readmem(0x71)
; addr = t1 | (t2<<8)
; A = readmem(addr + Y)
b5 70 LDA $70, X ; A = readmem(0x70 + X)
var a = 0, x = 0, y = 0, pc = readword(0xfffe);
while (true) {
switch (readmem(pc++)) {
case 0xa9: // LDA #imm
a = readmem(pc++); break;
case 0xad: // LDA $addr
var addr = readword(pc); pc += 2;
a = readmem(addr);
break;
// and so on for all other instructions...
}
}
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
Negative | oVerflow | - | - | Decimal | Interrupt disable |
Zero | Carry |
case 0xa9: // LDA #imm
a = readmem(pc++);
p.z = !a;
p.n = !!(a & 0x80);
break;
0x10000 | |
---|---|
0xff00 | 256 bytes OS ROM |
0xfe00 | 256 bytes hardware |
0xfd00 | 256 bytes ROM |
0xfc00 | 256 bytes hardware |
↑ ↑ ↑ 0xc000 |
15.5KB OS ROM |
↑ ↑ ↑ ↑ 0x8000 |
16KB Paged ROM |
↑ ↑ ↑ ↑ 0x4000 |
16KB RAM |
↑ ↑ ↑ ↑ 0x0000 |
16KB RAM |
var ram = new Uint8Array(0x8000), romsel = 0, roms = [];
var os = load("OS");
roms[15] = load("BASIC");
function readmem(addr) {
if (addr < 0x8000) return ram[addr];
if (addr < 0xc000) return roms[romsel][addr - 0x8000];
if ((addr >= 0xfe00 && addr < 0xff00)
|| (addr >= 0xfc00 && addr < 0xfd00))
return readhw(addr);
return os[addr - 0xc000];
}
function writemem(addr, b) {
if (addr < 0x8000) ram[addr] = b;
if (addr >= 0xfe00 && addr < 0xff00) writehw(addr, b);
// else does nothing - it's ROM
}
case 0xa9: // LDA #imm
a = readmem(pc++);
p.z = !a;
p.n = !!(a & 0x80);
video.run(2);
timers.run(2);
break;
$84 10000100 | STY zp |
---|---|
$85 10000101 | STA zp |
$86 10000110 | STX zp |
$87 10000111 | ??? |
+-----+-----+-----+ | A | X | Y | +-----+-----+-----+ | | | /+--------- | --- | (!s && !t) || | | | +----------+ | | | | opcode|| | | | | | 100001st |------->t | | +----------+ | | | ^ \---------- | --->s | | \ | / | \ | / select write bus store
+-----+-----+-----+ | A | X | Y | +-----+-----+-----+ | | | /+--------- | --- | (!s && !t) || | | | +----------+ | | | | opcode|| | | | | | 100001st |------->t | | +----------+ | | | ^ \---------- | --->s | | \ | / | \ | / select write bus store
$84 10000100 | STY zp |
---|---|
$85 10000101 | STA zp |
$86 10000110 | STX zp |
$87 10000111 | SAX zp |
Cycle | Read / Write | Address | Description |
---|---|---|---|
0 | Read | 0d2d | Read opcode (2e) |
1 | Read | 0d2e | Read low byte of address (48) |
2 | Read | 0d2f | Read high byte of address (fe) |
3 | Read | fe48 | Read memory at $fe48 |
4 | Write | fe48 | Do rotate — writes unmodified value! |
5 | Write | fe48 | Store to $fe48 |
case 0x2e: // ROL abs
addr = readword(pc); pc += 2;
hardware.run(3);
val = readbyte(addr);
hardware.run(1);
writebyte(addr, val); // unmodified value
hardware.run(1);
val = (val << 1) | (carry ? 1);
carry = val & 0x100;
writebyte(addr, val & 0xff); // modified value
hardware.run(1);
break;