add alu operations and cpu features

This commit is contained in:
2026-07-28 21:04:55 +02:00
parent fee48f34fe
commit 5de5730b68
2 changed files with 138 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
const types = @import("types.zig");
const Instruction = @import("instruction.zig");
// pure ALU arithmetic & bitwise operations monomorphized for Cpu
const Alu = @This();
pub inline fn updateNZ(cpu: anytype, value: u8) void {
cpu.registers.status.zero = (value == 0);
cpu.registers.status.negative = (value & 0x80) != 0;
}
pub fn compare(cpu: anytype, register: u8, value: u8) void {
const result = register -% value;
cpu.registers.status.carry = register >= value;
updateNZ(cpu, result);
}
pub fn adc(cpu: anytype, value: u8) void {
const accumulator = cpu.registers.a;
const carry: u16 = @intFromBool(cpu.registers.status.carry);
const sum = @as(u16, accumulator) + @as(u16, value) + carry;
const binary_result: u8 = @truncate(sum);
const overflow = ((accumulator ^ binary_result) & (value ^ binary_result) & 0x80) != 0;
const decimal = cpu.model.features().decimal_arithmetic and cpu.registers.status.decimal;
if (decimal and cpu.model.features().cmos_instructions) cpu.tick();
const out: struct { value: u8, carry: bool } = if (decimal) decimal: {
const low_sum = @as(u16, accumulator & 0x0f) + @as(u16, value & 0x0f) + carry;
var adjusted = sum;
if (low_sum > 9) adjusted += 6;
const carry_out = adjusted > 0x99;
if (carry_out) adjusted += 0x60;
break :decimal .{ .value = @truncate(adjusted), .carry = carry_out };
} else .{ .value = binary_result, .carry = sum > 0xff };
cpu.registers.status.carry = out.carry;
cpu.registers.status.overflow = overflow;
cpu.registers.a = out.value;
updateNZ(cpu, out.value);
}
pub fn sbc(cpu: anytype, value: u8) void {
const accumulator = cpu.registers.a;
const borrow: u16 = if (cpu.registers.status.carry) 0 else 1;
const diff: i16 = @as(i16, accumulator) - @as(i16, value) - @as(i16, @intCast(borrow));
const binary_result: u8 = @truncate(@as(u16, @bitCast(diff)));
const overflow = ((accumulator ^ binary_result) & (accumulator ^ value) & 0x80) != 0;
const no_borrow = diff >= 0;
const decimal = cpu.model.features().decimal_arithmetic and cpu.registers.status.decimal;
if (decimal and cpu.model.features().cmos_instructions) cpu.tick();
const result: u8 = if (decimal) decimal: {
var low: i16 = @as(i16, accumulator & 0x0f) - @as(i16, value & 0x0f) - @as(i16, @intCast(borrow));
var high: i16 = @as(i16, accumulator >> 4) - @as(i16, value >> 4);
if (low < 0) {
low -= 6;
high -= 1;
}
if (high < 0) high -= 6;
break :decimal (@as(u8, @intCast(high & 0x0f)) << 4) | @as(u8, @intCast(low & 0x0f));
} else binary_result;
cpu.registers.status.carry = no_borrow;
cpu.registers.status.overflow = overflow;
cpu.registers.a = result;
updateNZ(cpu, result);
}
pub fn asl(cpu: anytype, value: u8) u8 {
cpu.registers.status.carry = (value & 0x80) != 0;
const result = value << 1;
updateNZ(cpu, result);
return result;
}
pub fn lsr(cpu: anytype, value: u8) u8 {
cpu.registers.status.carry = (value & 1) != 0;
const result = value >> 1;
updateNZ(cpu, result);
return result;
}
pub fn rol(cpu: anytype, value: u8) u8 {
const carry: u8 = @intFromBool(cpu.registers.status.carry);
cpu.registers.status.carry = (value & 0x80) != 0;
const result = (value << 1) | carry;
updateNZ(cpu, result);
return result;
}
pub fn ror(cpu: anytype, value: u8) u8 {
const carry: u8 = if (cpu.registers.status.carry) 0x80 else 0;
cpu.registers.status.carry = (value & 1) != 0;
const result = (value >> 1) | carry;
updateNZ(cpu, result);
return result;
}
+36
View File
@@ -47,4 +47,40 @@ pub const Model = enum {
ricoh2a07, ricoh2a07,
wdc65c02, wdc65c02,
r65c02, r65c02,
pub fn features(self: Model) CpuFeatures {
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,
.fixed_indirect_jump = true,
},
};
}
};
pub const CpuFeatures = packed struct(u8) {
decimal_arithmetic: bool = false,
cmos_instructions: bool = false,
undocumented_opcodes: bool = false,
indirect_jump_bug: bool = false,
fixed_indirect_jump: bool = false,
wait_and_stop: bool = false,
_reserved: u2 = 0,
}; };