implement 6502 addressing modes and refactor utils

This commit is contained in:
2026-07-26 17:30:12 +02:00
parent ae2b91fbe3
commit fee48f34fe
2 changed files with 247 additions and 11 deletions
+246
View File
@@ -0,0 +1,246 @@
const Instruction = @import("instruction.zig");
const AddressingMode = Instruction.AddressingMode;
const utils = @import("utils.zig");
// addressing mode operations monomorphized for Cpu
pub const Addressing = @This();
pub const addRelative = utils.addRelative;
pub const pageCrossed = utils.pageCrossed;
pub const bitNumber = utils.bitNumber;
pub fn readOperand(cpu: anytype, mode: AddressingMode) u8 {
return switch (mode) {
.immediate => cpu.fetchByte(),
.zero_page => blk: {
const address = cpu.fetchByte();
break :blk cpu.readCycle(address);
},
.zero_page_x => blk: {
const base = cpu.fetchByte();
_ = cpu.readCycle(base);
break :blk cpu.readCycle(base +% cpu.registers.x);
},
.zero_page_y => blk: {
const base = cpu.fetchByte();
_ = cpu.readCycle(base);
break :blk cpu.readCycle(base +% cpu.registers.y);
},
.zero_page_indirect => blk: {
const pointer = cpu.fetchByte();
const low = cpu.readCycle(pointer);
const high = cpu.readCycle(pointer +% 1);
break :blk cpu.readCycle(utils.makeWord(low, high));
},
.absolute => blk: {
const address = cpu.fetchWord();
break :blk cpu.readCycle(address);
},
.absolute_x => readAbsoluteIndexed(cpu, cpu.registers.x),
.absolute_y => readAbsoluteIndexed(cpu, cpu.registers.y),
.indexed_indirect_x => readIndexedIndirectX(cpu),
.indirect_indexed_y => readIndirectIndexedY(cpu),
else => unreachable,
};
}
pub fn readAbsoluteIndexed(cpu: anytype, index: u8) u8 {
const low = cpu.fetchByte();
const high = cpu.fetchByte();
const base = utils.makeWord(low, high);
const address = base +% index;
if (pageCrossed(base, address)) {
if (@TypeOf(cpu.*).features.cmos_instructions) {
_ = cpu.readCycle(cpu.registers.pc -% 1);
} else {
const dummy = (base & 0xff00) | (address & 0x00ff);
_ = cpu.readCycle(dummy);
}
}
return cpu.readCycle(address);
}
pub fn readIndexedIndirectX(cpu: anytype) u8 {
const operand = cpu.fetchByte();
_ = cpu.readCycle(operand);
const pointer = operand +% cpu.registers.x;
const low = cpu.readCycle(pointer);
const high = cpu.readCycle(pointer +% 1);
return cpu.readCycle(utils.makeWord(low, high));
}
pub fn readIndirectIndexedY(cpu: anytype) u8 {
const pointer = cpu.fetchByte();
const low = cpu.readCycle(pointer);
const high = cpu.readCycle(pointer +% 1);
const base = utils.makeWord(low, high);
const address = base +% cpu.registers.y;
if (pageCrossed(base, address)) {
if (@TypeOf(cpu.*).features.cmos_instructions) {
_ = cpu.readCycle(cpu.registers.pc -% 1);
} else {
const dummy = (base & 0xff00) | (address & 0x00ff);
_ = cpu.readCycle(dummy);
}
}
return cpu.readCycle(address);
}
pub fn writeOperand(cpu: anytype, mode: AddressingMode, value: u8) void {
switch (mode) {
.zero_page => {
const address = cpu.fetchByte();
cpu.writeCycle(address, value);
},
.zero_page_x => {
const base = cpu.fetchByte();
_ = cpu.readCycle(base);
cpu.writeCycle(base +% cpu.registers.x, value);
},
.zero_page_y => {
const base = cpu.fetchByte();
_ = cpu.readCycle(base);
cpu.writeCycle(base +% cpu.registers.y, value);
},
.zero_page_indirect => {
const pointer = cpu.fetchByte();
const low = cpu.readCycle(pointer);
const high = cpu.readCycle(pointer +% 1);
cpu.writeCycle(utils.makeWord(low, high), value);
},
.absolute => {
const address = cpu.fetchWord();
cpu.writeCycle(address, value);
},
.absolute_x => writeAbsoluteIndexed(cpu, cpu.registers.x, value),
.absolute_y => writeAbsoluteIndexed(cpu, cpu.registers.y, value),
.indexed_indirect_x => writeIndexedIndirectX(cpu, value),
.indirect_indexed_y => writeIndirectIndexedY(cpu, value),
else => unreachable,
}
}
pub fn writeAbsoluteIndexed(cpu: anytype, index: u8, value: u8) void {
const low = cpu.fetchByte();
const high = cpu.fetchByte();
const base = utils.makeWord(low, high);
const address = base +% index;
const dummy = (base & 0xff00) | (address & 0x00ff);
_ = cpu.readCycle(dummy);
cpu.writeCycle(address, value);
}
pub fn writeIndexedIndirectX(cpu: anytype, value: u8) void {
const operand = cpu.fetchByte();
_ = cpu.readCycle(operand);
const pointer = operand +% cpu.registers.x;
const low = cpu.readCycle(pointer);
const high = cpu.readCycle(pointer +% 1);
cpu.writeCycle(utils.makeWord(low, high), value);
}
pub fn writeIndirectIndexedY(cpu: anytype, value: u8) void {
const pointer = cpu.fetchByte();
const low = cpu.readCycle(pointer);
const high = cpu.readCycle(pointer +% 1);
const base = utils.makeWord(low, high);
const address = base +% cpu.registers.y;
const dummy = (base & 0xff00) | (address & 0x00ff);
_ = cpu.readCycle(dummy);
cpu.writeCycle(address, value);
}
pub fn modifyAddress(
cpu: anytype,
address: u16,
comptime operation: fn (*@TypeOf(cpu.*), u8) u8,
) void {
const old = cpu.readCycle(address);
if (@TypeOf(cpu.*).features.cmos_instructions) {
_ = cpu.readCycle(address);
} else {
cpu.writeCycle(address, old);
}
const new = operation(cpu, old);
cpu.writeCycle(address, new);
}
pub fn modifyAbsoluteIndexed(
cpu: anytype,
index: u8,
comptime operation: fn (*@TypeOf(cpu.*), u8) u8,
) void {
const low = cpu.fetchByte();
const high = cpu.fetchByte();
const base = utils.makeWord(low, high);
const address = base +% index;
if (@TypeOf(cpu.*).features.cmos_instructions) {
if (pageCrossed(base, address)) {
_ = cpu.readCycle(cpu.registers.pc -% 1);
}
} else {
const dummy = (base & 0xff00) | (address & 0x00ff);
_ = cpu.readCycle(dummy);
}
modifyAddress(cpu, address, operation);
}
pub fn modifyIndexedIndirectX(
cpu: anytype,
comptime operation: fn (*@TypeOf(cpu.*), u8) u8,
) void {
const operand = cpu.fetchByte();
_ = cpu.readCycle(operand);
const pointer = operand +% cpu.registers.x;
const low = cpu.readCycle(pointer);
const high = cpu.readCycle(pointer +% 1);
modifyAddress(cpu, utils.makeWord(low, high), operation);
}
pub fn modifyIndirectIndexedY(
cpu: anytype,
comptime operation: fn (*@TypeOf(cpu.*), u8) u8,
) void {
const pointer = cpu.fetchByte();
const low = cpu.readCycle(pointer);
const high = cpu.readCycle(pointer +% 1);
const base = utils.makeWord(low, high);
const address = base +% cpu.registers.y;
const dummy = (base & 0xff00) | (address & 0x00ff);
_ = cpu.readCycle(dummy);
modifyAddress(cpu, address, operation);
}
+1 -11
View File
@@ -1,16 +1,6 @@
// common 6502 helper utilities
const std = @import("std"); const std = @import("std");
pub inline fn packAddress(low: u8, high: u8) u16 {
return @as(u16, low) | (@as(u16, high) << 8);
}
pub inline fn unpackAddress(addr: u16) struct { low: u8, high: u8 } {
return .{
.low = @truncate(addr),
.high = @truncate(addr >> 8),
};
}
pub inline fn makeWord(low: u8, high: u8) u16 { pub inline fn makeWord(low: u8, high: u8) u16 {
return @as(u16, low) | (@as(u16, high) << 8); return @as(u16, low) | (@as(u16, high) << 8);
} }