implement 6502 addressing modes and refactor utils
This commit is contained in:
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user