Files
6soz/src/cpu/m6502/addressing.zig
T

247 lines
7.1 KiB
Zig

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);
}