define instruction set and opcode decoding tables

This commit is contained in:
2026-07-31 15:22:08 +02:00
parent 5de5730b68
commit 0606ecac2e
5 changed files with 787 additions and 7 deletions
+150
View File
@@ -0,0 +1,150 @@
pub const AddressingMode = enum {
implied,
accumulator,
immediate,
zero_page,
zero_page_x,
zero_page_y,
relative,
absolute,
absolute_x,
absolute_y,
indirect,
indexed_indirect_x,
indirect_indexed_y,
// 65C02 additions
zero_page_indirect,
absolute_indexed_indirect,
zero_page_relative,
};
pub const Operation = enum {
adc,
@"and",
asl,
bcc,
bcs,
beq,
bit,
bmi,
bne,
bpl,
brk,
bvc,
bvs,
clc,
cld,
cli,
clv,
cmp,
cpx,
cpy,
dec,
dex,
dey,
eor,
inc,
inx,
iny,
jmp,
jsr,
lda,
ldx,
ldy,
lsr,
nop,
ora,
pha,
php,
pla,
plp,
rol,
ror,
rti,
rts,
sbc,
sec,
sed,
sei,
sta,
stx,
sty,
tax,
tay,
tsx,
txa,
txs,
tya,
// Undocumented NMOS 6502 instructions
ahx,
alr,
anc,
arr,
axs,
dcp,
isc,
kil,
las,
lax,
rla,
rra,
sax,
shx,
shy,
slo,
sre,
tas,
xaa,
// 65C02 CMOS additions
bra,
phx,
phy,
plx,
ply,
stz,
trb,
tsb,
rmb0,
rmb1,
rmb2,
rmb3,
rmb4,
rmb5,
rmb6,
rmb7,
smb0,
smb1,
smb2,
smb3,
smb4,
smb5,
smb6,
smb7,
bbr0,
bbr1,
bbr2,
bbr3,
bbr4,
bbr5,
bbr6,
bbr7,
bbs0,
bbs1,
bbs2,
bbs3,
bbs4,
bbs5,
bbs6,
bbs7,
stp,
wai,
};
// Instruction contains strictly operation and addressing mode; cycles are dynamically accounted for by bus accesses.
const Instruction = @This();
operation: Operation,
mode: AddressingMode,
+291
View File
@@ -0,0 +1,291 @@
const Instruction = @import("../instruction.zig");
pub const instructions: [256]Instruction = .{
// 0x00 - 0x0f
.{ .operation = .brk, .mode = .implied },
.{ .operation = .ora, .mode = .indexed_indirect_x },
.{ .operation = .kil, .mode = .implied },
.{ .operation = .slo, .mode = .indexed_indirect_x },
.{ .operation = .nop, .mode = .zero_page },
.{ .operation = .ora, .mode = .zero_page },
.{ .operation = .asl, .mode = .zero_page },
.{ .operation = .slo, .mode = .zero_page },
.{ .operation = .php, .mode = .implied },
.{ .operation = .ora, .mode = .immediate },
.{ .operation = .asl, .mode = .accumulator },
.{ .operation = .anc, .mode = .immediate },
.{ .operation = .nop, .mode = .absolute },
.{ .operation = .ora, .mode = .absolute },
.{ .operation = .asl, .mode = .absolute },
.{ .operation = .slo, .mode = .absolute },
// 0x10 - 0x1f
.{ .operation = .bpl, .mode = .relative },
.{ .operation = .ora, .mode = .indirect_indexed_y },
.{ .operation = .kil, .mode = .implied },
.{ .operation = .slo, .mode = .indirect_indexed_y },
.{ .operation = .nop, .mode = .zero_page_x },
.{ .operation = .ora, .mode = .zero_page_x },
.{ .operation = .asl, .mode = .zero_page_x },
.{ .operation = .slo, .mode = .zero_page_x },
.{ .operation = .clc, .mode = .implied },
.{ .operation = .ora, .mode = .absolute_y },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .slo, .mode = .absolute_y },
.{ .operation = .nop, .mode = .absolute_x },
.{ .operation = .ora, .mode = .absolute_x },
.{ .operation = .asl, .mode = .absolute_x },
.{ .operation = .slo, .mode = .absolute_x },
// 0x20 - 0x2f
.{ .operation = .jsr, .mode = .absolute },
.{ .operation = .@"and", .mode = .indexed_indirect_x },
.{ .operation = .kil, .mode = .implied },
.{ .operation = .rla, .mode = .indexed_indirect_x },
.{ .operation = .bit, .mode = .zero_page },
.{ .operation = .@"and", .mode = .zero_page },
.{ .operation = .rol, .mode = .zero_page },
.{ .operation = .rla, .mode = .zero_page },
.{ .operation = .plp, .mode = .implied },
.{ .operation = .@"and", .mode = .immediate },
.{ .operation = .rol, .mode = .accumulator },
.{ .operation = .anc, .mode = .immediate },
.{ .operation = .bit, .mode = .absolute },
.{ .operation = .@"and", .mode = .absolute },
.{ .operation = .rol, .mode = .absolute },
.{ .operation = .rla, .mode = .absolute },
// 0x30 - 0x3f
.{ .operation = .bmi, .mode = .relative },
.{ .operation = .@"and", .mode = .indirect_indexed_y },
.{ .operation = .kil, .mode = .implied },
.{ .operation = .rla, .mode = .indirect_indexed_y },
.{ .operation = .nop, .mode = .zero_page_x },
.{ .operation = .@"and", .mode = .zero_page_x },
.{ .operation = .rol, .mode = .zero_page_x },
.{ .operation = .rla, .mode = .zero_page_x },
.{ .operation = .sec, .mode = .implied },
.{ .operation = .@"and", .mode = .absolute_y },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .rla, .mode = .absolute_y },
.{ .operation = .nop, .mode = .absolute_x },
.{ .operation = .@"and", .mode = .absolute_x },
.{ .operation = .rol, .mode = .absolute_x },
.{ .operation = .rla, .mode = .absolute_x },
// 0x40 - 0x4f
.{ .operation = .rti, .mode = .implied },
.{ .operation = .eor, .mode = .indexed_indirect_x },
.{ .operation = .kil, .mode = .implied },
.{ .operation = .sre, .mode = .indexed_indirect_x },
.{ .operation = .nop, .mode = .zero_page },
.{ .operation = .eor, .mode = .zero_page },
.{ .operation = .lsr, .mode = .zero_page },
.{ .operation = .sre, .mode = .zero_page },
.{ .operation = .pha, .mode = .implied },
.{ .operation = .eor, .mode = .immediate },
.{ .operation = .lsr, .mode = .accumulator },
.{ .operation = .alr, .mode = .immediate },
.{ .operation = .jmp, .mode = .absolute },
.{ .operation = .eor, .mode = .absolute },
.{ .operation = .lsr, .mode = .absolute },
.{ .operation = .sre, .mode = .absolute },
// 0x50 - 0x5f
.{ .operation = .bvc, .mode = .relative },
.{ .operation = .eor, .mode = .indirect_indexed_y },
.{ .operation = .kil, .mode = .implied },
.{ .operation = .sre, .mode = .indirect_indexed_y },
.{ .operation = .nop, .mode = .zero_page_x },
.{ .operation = .eor, .mode = .zero_page_x },
.{ .operation = .lsr, .mode = .zero_page_x },
.{ .operation = .sre, .mode = .zero_page_x },
.{ .operation = .cli, .mode = .implied },
.{ .operation = .eor, .mode = .absolute_y },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .sre, .mode = .absolute_y },
.{ .operation = .nop, .mode = .absolute_x },
.{ .operation = .eor, .mode = .absolute_x },
.{ .operation = .lsr, .mode = .absolute_x },
.{ .operation = .sre, .mode = .absolute_x },
// 0x60 - 0x6f
.{ .operation = .rts, .mode = .implied },
.{ .operation = .adc, .mode = .indexed_indirect_x },
.{ .operation = .kil, .mode = .implied },
.{ .operation = .rra, .mode = .indexed_indirect_x },
.{ .operation = .nop, .mode = .zero_page },
.{ .operation = .adc, .mode = .zero_page },
.{ .operation = .ror, .mode = .zero_page },
.{ .operation = .rra, .mode = .zero_page },
.{ .operation = .pla, .mode = .implied },
.{ .operation = .adc, .mode = .immediate },
.{ .operation = .ror, .mode = .accumulator },
.{ .operation = .arr, .mode = .immediate },
.{ .operation = .jmp, .mode = .indirect },
.{ .operation = .adc, .mode = .absolute },
.{ .operation = .ror, .mode = .absolute },
.{ .operation = .rra, .mode = .absolute },
// 0x70 - 0x7f
.{ .operation = .bvs, .mode = .relative },
.{ .operation = .adc, .mode = .indirect_indexed_y },
.{ .operation = .kil, .mode = .implied },
.{ .operation = .rra, .mode = .indirect_indexed_y },
.{ .operation = .nop, .mode = .zero_page_x },
.{ .operation = .adc, .mode = .zero_page_x },
.{ .operation = .ror, .mode = .zero_page_x },
.{ .operation = .rra, .mode = .zero_page_x },
.{ .operation = .sei, .mode = .implied },
.{ .operation = .adc, .mode = .absolute_y },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .rra, .mode = .absolute_y },
.{ .operation = .nop, .mode = .absolute_x },
.{ .operation = .adc, .mode = .absolute_x },
.{ .operation = .ror, .mode = .absolute_x },
.{ .operation = .rra, .mode = .absolute_x },
// 0x80 - 0x8f
.{ .operation = .nop, .mode = .immediate },
.{ .operation = .sta, .mode = .indexed_indirect_x },
.{ .operation = .nop, .mode = .immediate },
.{ .operation = .sax, .mode = .indexed_indirect_x },
.{ .operation = .sty, .mode = .zero_page },
.{ .operation = .sta, .mode = .zero_page },
.{ .operation = .stx, .mode = .zero_page },
.{ .operation = .sax, .mode = .zero_page },
.{ .operation = .dey, .mode = .implied },
.{ .operation = .nop, .mode = .immediate },
.{ .operation = .txa, .mode = .implied },
.{ .operation = .xaa, .mode = .immediate },
.{ .operation = .sty, .mode = .absolute },
.{ .operation = .sta, .mode = .absolute },
.{ .operation = .stx, .mode = .absolute },
.{ .operation = .sax, .mode = .absolute },
// 0x90 - 0x9f
.{ .operation = .bcc, .mode = .relative },
.{ .operation = .sta, .mode = .indirect_indexed_y },
.{ .operation = .kil, .mode = .implied },
.{ .operation = .ahx, .mode = .indirect_indexed_y },
.{ .operation = .sty, .mode = .zero_page_x },
.{ .operation = .sta, .mode = .zero_page_x },
.{ .operation = .stx, .mode = .zero_page_y },
.{ .operation = .sax, .mode = .zero_page_y },
.{ .operation = .tya, .mode = .implied },
.{ .operation = .sta, .mode = .absolute_y },
.{ .operation = .txs, .mode = .implied },
.{ .operation = .tas, .mode = .absolute_y },
.{ .operation = .shy, .mode = .absolute_x },
.{ .operation = .sta, .mode = .absolute_x },
.{ .operation = .shx, .mode = .absolute_y },
.{ .operation = .ahx, .mode = .absolute_y },
// 0xa0 - 0xaf
.{ .operation = .ldy, .mode = .immediate },
.{ .operation = .lda, .mode = .indexed_indirect_x },
.{ .operation = .ldx, .mode = .immediate },
.{ .operation = .lax, .mode = .indexed_indirect_x },
.{ .operation = .ldy, .mode = .zero_page },
.{ .operation = .lda, .mode = .zero_page },
.{ .operation = .ldx, .mode = .zero_page },
.{ .operation = .lax, .mode = .zero_page },
.{ .operation = .tay, .mode = .implied },
.{ .operation = .lda, .mode = .immediate },
.{ .operation = .tax, .mode = .implied },
.{ .operation = .lax, .mode = .immediate },
.{ .operation = .ldy, .mode = .absolute },
.{ .operation = .lda, .mode = .absolute },
.{ .operation = .ldx, .mode = .absolute },
.{ .operation = .lax, .mode = .absolute },
// 0xb0 - 0xbf
.{ .operation = .bcs, .mode = .relative },
.{ .operation = .lda, .mode = .indirect_indexed_y },
.{ .operation = .kil, .mode = .implied },
.{ .operation = .lax, .mode = .indirect_indexed_y },
.{ .operation = .ldy, .mode = .zero_page_x },
.{ .operation = .lda, .mode = .zero_page_x },
.{ .operation = .ldx, .mode = .zero_page_y },
.{ .operation = .lax, .mode = .zero_page_y },
.{ .operation = .clv, .mode = .implied },
.{ .operation = .lda, .mode = .absolute_y },
.{ .operation = .tsx, .mode = .implied },
.{ .operation = .las, .mode = .absolute_y },
.{ .operation = .ldy, .mode = .absolute_x },
.{ .operation = .lda, .mode = .absolute_x },
.{ .operation = .ldx, .mode = .absolute_y },
.{ .operation = .lax, .mode = .absolute_y },
// 0xc0 - 0xcf
.{ .operation = .cpy, .mode = .immediate },
.{ .operation = .cmp, .mode = .indexed_indirect_x },
.{ .operation = .nop, .mode = .immediate },
.{ .operation = .dcp, .mode = .indexed_indirect_x },
.{ .operation = .cpy, .mode = .zero_page },
.{ .operation = .cmp, .mode = .zero_page },
.{ .operation = .dec, .mode = .zero_page },
.{ .operation = .dcp, .mode = .zero_page },
.{ .operation = .iny, .mode = .implied },
.{ .operation = .cmp, .mode = .immediate },
.{ .operation = .dex, .mode = .implied },
.{ .operation = .axs, .mode = .immediate },
.{ .operation = .cpy, .mode = .absolute },
.{ .operation = .cmp, .mode = .absolute },
.{ .operation = .dec, .mode = .absolute },
.{ .operation = .dcp, .mode = .absolute },
// 0xd0 - 0xdf
.{ .operation = .bne, .mode = .relative },
.{ .operation = .cmp, .mode = .indirect_indexed_y },
.{ .operation = .kil, .mode = .implied },
.{ .operation = .dcp, .mode = .indirect_indexed_y },
.{ .operation = .nop, .mode = .zero_page_x },
.{ .operation = .cmp, .mode = .zero_page_x },
.{ .operation = .dec, .mode = .zero_page_x },
.{ .operation = .dcp, .mode = .zero_page_x },
.{ .operation = .cld, .mode = .implied },
.{ .operation = .cmp, .mode = .absolute_y },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .dcp, .mode = .absolute_y },
.{ .operation = .nop, .mode = .absolute_x },
.{ .operation = .cmp, .mode = .absolute_x },
.{ .operation = .dec, .mode = .absolute_x },
.{ .operation = .dcp, .mode = .absolute_x },
// 0xe0 - 0xef
.{ .operation = .cpx, .mode = .immediate },
.{ .operation = .sbc, .mode = .indexed_indirect_x },
.{ .operation = .nop, .mode = .immediate },
.{ .operation = .isc, .mode = .indexed_indirect_x },
.{ .operation = .cpx, .mode = .zero_page },
.{ .operation = .sbc, .mode = .zero_page },
.{ .operation = .inc, .mode = .zero_page },
.{ .operation = .isc, .mode = .zero_page },
.{ .operation = .inx, .mode = .implied },
.{ .operation = .sbc, .mode = .immediate },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .sbc, .mode = .immediate },
.{ .operation = .cpx, .mode = .absolute },
.{ .operation = .sbc, .mode = .absolute },
.{ .operation = .inc, .mode = .absolute },
.{ .operation = .isc, .mode = .absolute },
// 0xf0 - 0xff
.{ .operation = .beq, .mode = .relative },
.{ .operation = .sbc, .mode = .indirect_indexed_y },
.{ .operation = .kil, .mode = .implied },
.{ .operation = .isc, .mode = .indirect_indexed_y },
.{ .operation = .nop, .mode = .zero_page_x },
.{ .operation = .sbc, .mode = .zero_page_x },
.{ .operation = .inc, .mode = .zero_page_x },
.{ .operation = .isc, .mode = .zero_page_x },
.{ .operation = .sed, .mode = .implied },
.{ .operation = .sbc, .mode = .absolute_y },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .isc, .mode = .absolute_y },
.{ .operation = .nop, .mode = .absolute_x },
.{ .operation = .sbc, .mode = .absolute_x },
.{ .operation = .inc, .mode = .absolute_x },
.{ .operation = .isc, .mode = .absolute_x },
};
+2
View File
@@ -0,0 +1,2 @@
pub const nmos6502 = @import("nmos6502.zig");
pub const wdc65c02 = @import("wdc65c02.zig");
+291
View File
@@ -0,0 +1,291 @@
const Instruction = @import("../instruction.zig");
pub const instructions: [256]Instruction = .{
// 0x00 - 0x0f
.{ .operation = .brk, .mode = .implied },
.{ .operation = .ora, .mode = .indexed_indirect_x },
.{ .operation = .nop, .mode = .immediate },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .tsb, .mode = .zero_page },
.{ .operation = .ora, .mode = .zero_page },
.{ .operation = .asl, .mode = .zero_page },
.{ .operation = .rmb0, .mode = .zero_page },
.{ .operation = .php, .mode = .implied },
.{ .operation = .ora, .mode = .immediate },
.{ .operation = .asl, .mode = .accumulator },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .tsb, .mode = .absolute },
.{ .operation = .ora, .mode = .absolute },
.{ .operation = .asl, .mode = .absolute },
.{ .operation = .bbr0, .mode = .zero_page_relative },
// 0x10 - 0x1f
.{ .operation = .bpl, .mode = .relative },
.{ .operation = .ora, .mode = .indirect_indexed_y },
.{ .operation = .ora, .mode = .zero_page_indirect },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .trb, .mode = .zero_page },
.{ .operation = .ora, .mode = .zero_page_x },
.{ .operation = .asl, .mode = .zero_page_x },
.{ .operation = .rmb1, .mode = .zero_page },
.{ .operation = .clc, .mode = .implied },
.{ .operation = .ora, .mode = .absolute_y },
.{ .operation = .inc, .mode = .accumulator },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .trb, .mode = .absolute },
.{ .operation = .ora, .mode = .absolute_x },
.{ .operation = .asl, .mode = .absolute_x },
.{ .operation = .bbr1, .mode = .zero_page_relative },
// 0x20 - 0x2f
.{ .operation = .jsr, .mode = .absolute },
.{ .operation = .@"and", .mode = .indexed_indirect_x },
.{ .operation = .nop, .mode = .immediate },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .bit, .mode = .zero_page },
.{ .operation = .@"and", .mode = .zero_page },
.{ .operation = .rol, .mode = .zero_page },
.{ .operation = .rmb2, .mode = .zero_page },
.{ .operation = .plp, .mode = .implied },
.{ .operation = .@"and", .mode = .immediate },
.{ .operation = .rol, .mode = .accumulator },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .bit, .mode = .absolute },
.{ .operation = .@"and", .mode = .absolute },
.{ .operation = .rol, .mode = .absolute },
.{ .operation = .bbr2, .mode = .zero_page_relative },
// 0x30 - 0x3f
.{ .operation = .bmi, .mode = .relative },
.{ .operation = .@"and", .mode = .indirect_indexed_y },
.{ .operation = .@"and", .mode = .zero_page_indirect },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .bit, .mode = .zero_page_x },
.{ .operation = .@"and", .mode = .zero_page_x },
.{ .operation = .rol, .mode = .zero_page_x },
.{ .operation = .rmb3, .mode = .zero_page },
.{ .operation = .sec, .mode = .implied },
.{ .operation = .@"and", .mode = .absolute_y },
.{ .operation = .dec, .mode = .accumulator },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .bit, .mode = .absolute_x },
.{ .operation = .@"and", .mode = .absolute_x },
.{ .operation = .rol, .mode = .absolute_x },
.{ .operation = .bbr3, .mode = .zero_page_relative },
// 0x40 - 0x4f
.{ .operation = .rti, .mode = .implied },
.{ .operation = .eor, .mode = .indexed_indirect_x },
.{ .operation = .nop, .mode = .immediate },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .nop, .mode = .zero_page },
.{ .operation = .eor, .mode = .zero_page },
.{ .operation = .lsr, .mode = .zero_page },
.{ .operation = .rmb4, .mode = .zero_page },
.{ .operation = .pha, .mode = .implied },
.{ .operation = .eor, .mode = .immediate },
.{ .operation = .lsr, .mode = .accumulator },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .jmp, .mode = .absolute },
.{ .operation = .eor, .mode = .absolute },
.{ .operation = .lsr, .mode = .absolute },
.{ .operation = .bbr4, .mode = .zero_page_relative },
// 0x50 - 0x5f
.{ .operation = .bvc, .mode = .relative },
.{ .operation = .eor, .mode = .indirect_indexed_y },
.{ .operation = .eor, .mode = .zero_page_indirect },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .nop, .mode = .zero_page_x },
.{ .operation = .eor, .mode = .zero_page_x },
.{ .operation = .lsr, .mode = .zero_page_x },
.{ .operation = .rmb5, .mode = .zero_page },
.{ .operation = .cli, .mode = .implied },
.{ .operation = .eor, .mode = .absolute_y },
.{ .operation = .phy, .mode = .implied },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .nop, .mode = .absolute },
.{ .operation = .eor, .mode = .absolute_x },
.{ .operation = .lsr, .mode = .absolute_x },
.{ .operation = .bbr5, .mode = .zero_page_relative },
// 0x60 - 0x6f
.{ .operation = .rts, .mode = .implied },
.{ .operation = .adc, .mode = .indexed_indirect_x },
.{ .operation = .nop, .mode = .immediate },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .stz, .mode = .zero_page },
.{ .operation = .adc, .mode = .zero_page },
.{ .operation = .ror, .mode = .zero_page },
.{ .operation = .rmb6, .mode = .zero_page },
.{ .operation = .pla, .mode = .implied },
.{ .operation = .adc, .mode = .immediate },
.{ .operation = .ror, .mode = .accumulator },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .jmp, .mode = .indirect },
.{ .operation = .adc, .mode = .absolute },
.{ .operation = .ror, .mode = .absolute },
.{ .operation = .bbr6, .mode = .zero_page_relative },
// 0x70 - 0x7f
.{ .operation = .bvs, .mode = .relative },
.{ .operation = .adc, .mode = .indirect_indexed_y },
.{ .operation = .adc, .mode = .zero_page_indirect },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .stz, .mode = .zero_page_x },
.{ .operation = .adc, .mode = .zero_page_x },
.{ .operation = .ror, .mode = .zero_page_x },
.{ .operation = .rmb7, .mode = .zero_page },
.{ .operation = .sei, .mode = .implied },
.{ .operation = .adc, .mode = .absolute_y },
.{ .operation = .ply, .mode = .implied },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .jmp, .mode = .absolute_indexed_indirect },
.{ .operation = .adc, .mode = .absolute_x },
.{ .operation = .ror, .mode = .absolute_x },
.{ .operation = .bbr7, .mode = .zero_page_relative },
// 0x80 - 0x8f
.{ .operation = .bra, .mode = .relative },
.{ .operation = .sta, .mode = .indexed_indirect_x },
.{ .operation = .nop, .mode = .immediate },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .sty, .mode = .zero_page },
.{ .operation = .sta, .mode = .zero_page },
.{ .operation = .stx, .mode = .zero_page },
.{ .operation = .smb0, .mode = .zero_page },
.{ .operation = .dey, .mode = .implied },
.{ .operation = .bit, .mode = .immediate },
.{ .operation = .txa, .mode = .implied },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .sty, .mode = .absolute },
.{ .operation = .sta, .mode = .absolute },
.{ .operation = .stx, .mode = .absolute },
.{ .operation = .bbs0, .mode = .zero_page_relative },
// 0x90 - 0x9f
.{ .operation = .bcc, .mode = .relative },
.{ .operation = .sta, .mode = .indirect_indexed_y },
.{ .operation = .sta, .mode = .zero_page_indirect },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .sty, .mode = .zero_page_x },
.{ .operation = .sta, .mode = .zero_page_x },
.{ .operation = .stx, .mode = .zero_page_y },
.{ .operation = .smb1, .mode = .zero_page },
.{ .operation = .tya, .mode = .implied },
.{ .operation = .sta, .mode = .absolute_y },
.{ .operation = .txs, .mode = .implied },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .stz, .mode = .absolute },
.{ .operation = .sta, .mode = .absolute_x },
.{ .operation = .stz, .mode = .absolute_x },
.{ .operation = .bbs1, .mode = .zero_page_relative },
// 0xa0 - 0xaf
.{ .operation = .ldy, .mode = .immediate },
.{ .operation = .lda, .mode = .indexed_indirect_x },
.{ .operation = .ldx, .mode = .immediate },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .ldy, .mode = .zero_page },
.{ .operation = .lda, .mode = .zero_page },
.{ .operation = .ldx, .mode = .zero_page },
.{ .operation = .smb2, .mode = .zero_page },
.{ .operation = .tay, .mode = .implied },
.{ .operation = .lda, .mode = .immediate },
.{ .operation = .tax, .mode = .implied },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .ldy, .mode = .absolute },
.{ .operation = .lda, .mode = .absolute },
.{ .operation = .ldx, .mode = .absolute },
.{ .operation = .bbs2, .mode = .zero_page_relative },
// 0xb0 - 0xbf
.{ .operation = .bcs, .mode = .relative },
.{ .operation = .lda, .mode = .indirect_indexed_y },
.{ .operation = .lda, .mode = .zero_page_indirect },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .ldy, .mode = .zero_page_x },
.{ .operation = .lda, .mode = .zero_page_x },
.{ .operation = .ldx, .mode = .zero_page_y },
.{ .operation = .smb3, .mode = .zero_page },
.{ .operation = .clv, .mode = .implied },
.{ .operation = .lda, .mode = .absolute_y },
.{ .operation = .tsx, .mode = .implied },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .ldy, .mode = .absolute_x },
.{ .operation = .lda, .mode = .absolute_x },
.{ .operation = .ldx, .mode = .absolute_y },
.{ .operation = .bbs3, .mode = .zero_page_relative },
// 0xc0 - 0xcf
.{ .operation = .cpy, .mode = .immediate },
.{ .operation = .cmp, .mode = .indexed_indirect_x },
.{ .operation = .nop, .mode = .immediate },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .cpy, .mode = .zero_page },
.{ .operation = .cmp, .mode = .zero_page },
.{ .operation = .dec, .mode = .zero_page },
.{ .operation = .smb4, .mode = .zero_page },
.{ .operation = .iny, .mode = .implied },
.{ .operation = .cmp, .mode = .immediate },
.{ .operation = .dex, .mode = .implied },
.{ .operation = .wai, .mode = .implied },
.{ .operation = .cpy, .mode = .absolute },
.{ .operation = .cmp, .mode = .absolute },
.{ .operation = .dec, .mode = .absolute },
.{ .operation = .bbs4, .mode = .zero_page_relative },
// 0xd0 - 0xdf
.{ .operation = .bne, .mode = .relative },
.{ .operation = .cmp, .mode = .indirect_indexed_y },
.{ .operation = .cmp, .mode = .zero_page_indirect },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .nop, .mode = .zero_page_x },
.{ .operation = .cmp, .mode = .zero_page_x },
.{ .operation = .dec, .mode = .zero_page_x },
.{ .operation = .smb5, .mode = .zero_page },
.{ .operation = .cld, .mode = .implied },
.{ .operation = .cmp, .mode = .absolute_y },
.{ .operation = .phx, .mode = .implied },
.{ .operation = .stp, .mode = .implied },
.{ .operation = .nop, .mode = .absolute },
.{ .operation = .cmp, .mode = .absolute_x },
.{ .operation = .dec, .mode = .absolute_x },
.{ .operation = .bbs5, .mode = .zero_page_relative },
// 0xe0 - 0xef
.{ .operation = .cpx, .mode = .immediate },
.{ .operation = .sbc, .mode = .indexed_indirect_x },
.{ .operation = .nop, .mode = .immediate },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .cpx, .mode = .zero_page },
.{ .operation = .sbc, .mode = .zero_page },
.{ .operation = .inc, .mode = .zero_page },
.{ .operation = .smb6, .mode = .zero_page },
.{ .operation = .inx, .mode = .implied },
.{ .operation = .sbc, .mode = .immediate },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .cpx, .mode = .absolute },
.{ .operation = .sbc, .mode = .absolute },
.{ .operation = .inc, .mode = .absolute },
.{ .operation = .bbs6, .mode = .zero_page_relative },
// 0xf0 - 0xff
.{ .operation = .beq, .mode = .relative },
.{ .operation = .sbc, .mode = .indirect_indexed_y },
.{ .operation = .sbc, .mode = .zero_page_indirect },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .nop, .mode = .zero_page_x },
.{ .operation = .sbc, .mode = .zero_page_x },
.{ .operation = .inc, .mode = .zero_page_x },
.{ .operation = .smb7, .mode = .zero_page },
.{ .operation = .sed, .mode = .implied },
.{ .operation = .sbc, .mode = .absolute_y },
.{ .operation = .plx, .mode = .implied },
.{ .operation = .nop, .mode = .implied },
.{ .operation = .nop, .mode = .absolute },
.{ .operation = .sbc, .mode = .absolute_x },
.{ .operation = .inc, .mode = .absolute_x },
.{ .operation = .bbs7, .mode = .zero_page_relative },
};
+53 -7
View File
@@ -1,3 +1,6 @@
const _opcode = @import("opcode/root.zig");
const Instruction = @import("instruction.zig");
pub const Status = packed struct(u8) {
carry: bool = false,
zero: bool = false,
@@ -30,13 +33,6 @@ pub const Registers = struct {
sp: u8 = 0xfd,
pc: u16 = 0,
status: Status = .{},
pub fn dumpRegisters(self: Registers) void {
const std = @import("std");
std.debug.print("A:{X:02} X:{X:02} Y:{X:02} SP:{X:02} PC:{X:04}\n", .{
self.a, self.x, self.y, self.sp, self.pc,
});
}
};
pub const Model = enum {
@@ -49,22 +45,26 @@ pub const Model = enum {
r65c02,
pub fn features(self: Model) CpuFeatures {
// group variants sharing exact feature sets to eliminate duplication
return switch (self) {
.mos6502, .mos6507, .mos6510 => .{
.decimal_arithmetic = true,
.undocumented_opcodes = true,
.indirect_jump_bug = true,
},
.ricoh2a03, .ricoh2a07 => .{
.undocumented_opcodes = true,
.indirect_jump_bug = true,
},
.wdc65c02 => .{
.decimal_arithmetic = true,
.cmos_instructions = true,
.fixed_indirect_jump = true,
.wait_and_stop = true,
},
.r65c02 => .{
.decimal_arithmetic = true,
.cmos_instructions = true,
@@ -72,6 +72,24 @@ pub const Model = enum {
},
};
}
pub fn instructionTable(self: Model) *const [256]Instruction {
return switch (self) {
.mos6502, .mos6507, .mos6510, .ricoh2a03, .ricoh2a07 => &_opcode.nmos6502.instructions,
.wdc65c02, .r65c02 => &_opcode.wdc65c02.instructions,
};
}
pub fn instruction(self: Model, opcode: u8) Instruction {
return self.instructionTable()[opcode];
}
pub fn addressMask(self: Model) u16 {
return switch (self) {
.mos6507 => 0x1fff,
else => 0xffff,
};
}
};
pub const CpuFeatures = packed struct(u8) {
@@ -82,5 +100,33 @@ pub const CpuFeatures = packed struct(u8) {
fixed_indirect_jump: bool = false,
wait_and_stop: bool = false,
// remaining bit fields reserved for packed struct byte layout
_reserved: u2 = 0,
};
test "CPU Model Features & Opcode Map Verification" {
const testing = @import("std").testing;
// MOS 6502 family
try testing.expect(Model.mos6502.features().decimal_arithmetic);
try testing.expect(Model.mos6507.features().decimal_arithmetic);
try testing.expect(Model.mos6510.features().decimal_arithmetic);
try testing.expect(Model.mos6502.features().undocumented_opcodes);
// Ricoh family (No BCD)
try testing.expect(!Model.ricoh2a03.features().decimal_arithmetic);
try testing.expect(!Model.ricoh2a07.features().decimal_arithmetic);
try testing.expect(Model.ricoh2a07.features().undocumented_opcodes);
try testing.expect(Model.ricoh2a07.features().indirect_jump_bug);
// CMOS family
try testing.expect(Model.wdc65c02.features().cmos_instructions);
try testing.expect(Model.r65c02.features().cmos_instructions);
try testing.expect(Model.wdc65c02.features().wait_and_stop);
try testing.expect(!Model.r65c02.features().wait_and_stop);
// Opcode mapping sanity checks
try testing.expectEqual(Model.mos6502.instruction(0xEA).operation, .nop);
try testing.expectEqual(Model.ricoh2a07.instruction(0xEA).operation, .nop);
try testing.expectEqual(Model.r65c02.instruction(0x80).operation, .bra);
}