From 99cae5a5a37f41f878a84857361eda47910303ba Mon Sep 17 00:00:00 2001 From: crecher Date: Tue, 13 Oct 2026 01:13:13 +0200 Subject: sprites!!!!!! --- cpu/cpu.go | 5 ++++ cpu/instructions.go | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++ cpu/opcodes.go | 15 ++++++++++ 3 files changed, 100 insertions(+) (limited to 'cpu') diff --git a/cpu/cpu.go b/cpu/cpu.go index 113adf0..b8b0a1e 100644 --- a/cpu/cpu.go +++ b/cpu/cpu.go @@ -111,6 +111,11 @@ func (c *CPU) interrupt(vector uint16, brk bool) { c.PC = c.read16(vector) } +// burns cycles without running anything, used while dma holds the cpu +func (c *CPU) Stall(cycles int) { + c.Cycles += uint64(cycles) +} + func (c *CPU) Step() int { if c.Jammed { c.Cycles++ diff --git a/cpu/instructions.go b/cpu/instructions.go index b74a2db..b4d4bbe 100644 --- a/cpu/instructions.go +++ b/cpu/instructions.go @@ -226,3 +226,83 @@ func jamExec(c *CPU, op operand) { c.Jammed = true c.PC-- } + +// and with immediate, then carry takes the sign bit +func ancExec(c *CPU, op operand) { + c.A &= c.operandValue(op) + c.setZN(c.A) + c.setFlag(FlagC, c.A&0x80 != 0) +} + +// and with immediate, then lsr a +func alrExec(c *CPU, op operand) { + v := c.A & c.operandValue(op) + c.setFlag(FlagC, v&0x01 != 0) + c.A = v >> 1 + c.setZN(c.A) +} + +// and with immediate, then ror a, but C and V come from bits 6 and 5 of the +// result (binary mode only, the 2A03 has no decimal mode) +func arrExec(c *CPU, op operand) { + v := c.A & c.operandValue(op) + var carryIn uint8 + if c.flag(FlagC) { + carryIn = 0x80 + } + c.A = v>>1 | carryIn + c.setZN(c.A) + c.setFlag(FlagC, c.A&0x40 != 0) + c.setFlag(FlagV, (c.A>>6^c.A>>5)&0x01 != 0) +} + +// x = (a & x) - immediate, like cmp: no borrow in, V untouched +func axsExec(c *CPU, op operand) { + v := c.A & c.X + imm := c.operandValue(op) + c.setFlag(FlagC, v >= imm) + c.X = v - imm + c.setZN(c.X) +} + +// memory & sp goes into a, x and sp +func lasExec(c *CPU, op operand) { + v := c.operandValue(op) & c.SP + c.A, c.X, c.SP = v, v, v + c.setZN(v) +} + +const unstableMagic uint8 = 0xEE + +func aneExec(c *CPU, op operand) { + c.A = (c.A | unstableMagic) & c.X & c.operandValue(op) + c.setZN(c.A) +} + +func lxaExec(c *CPU, op operand) { + c.A = (c.A | unstableMagic) & c.operandValue(op) + c.X = c.A + c.setZN(c.A) +} + +func (c *CPU) storeHighAnd(op operand, v uint8) { + baseHi := uint8(op.addr >> 8) + if op.pageCrossed { + baseHi-- + } + v &= baseHi + 1 + addr := op.addr + if op.pageCrossed { + addr = uint16(v)<<8 | addr&0x00FF + } + c.write(addr, v) +} + +func ahxExec(c *CPU, op operand) { c.storeHighAnd(op, c.A&c.X) } +func shxExec(c *CPU, op operand) { c.storeHighAnd(op, c.X) } +func shyExec(c *CPU, op operand) { c.storeHighAnd(op, c.Y) } + +func tasExec(c *CPU, op operand) { + c.SP = c.A & c.X + c.storeHighAnd(op, c.SP) +} diff --git a/cpu/opcodes.go b/cpu/opcodes.go index ea6e1b9..aa8f8a5 100644 --- a/cpu/opcodes.go +++ b/cpu/opcodes.go @@ -334,6 +334,21 @@ func init() { def(0xD2, "JAM", ModeImplied, 2, false, jamExec) def(0xF2, "JAM", ModeImplied, 2, false, jamExec) + def(0x0B, "ANC", ModeImmediate, 2, false, ancExec) + def(0x2B, "ANC", ModeImmediate, 2, false, ancExec) + def(0x4B, "ALR", ModeImmediate, 2, false, alrExec) + def(0x6B, "ARR", ModeImmediate, 2, false, arrExec) + def(0x8B, "ANE", ModeImmediate, 2, false, aneExec) + def(0xAB, "LXA", ModeImmediate, 2, false, lxaExec) + def(0xCB, "AXS", ModeImmediate, 2, false, axsExec) + def(0xBB, "LAS", ModeAbsoluteY, 4, true, lasExec) + + def(0x93, "AHX", ModeIndirectY, 6, false, ahxExec) + def(0x9F, "AHX", ModeAbsoluteY, 5, false, ahxExec) + def(0x9B, "TAS", ModeAbsoluteY, 5, false, tasExec) + def(0x9C, "SHY", ModeAbsoluteX, 5, false, shyExec) + def(0x9E, "SHX", ModeAbsoluteY, 5, false, shxExec) + // illegal / undocumented instructions def(0xA7, "LAX", ModeZeroPage, 3, false, laxExec) def(0xB7, "LAX", ModeZeroPageY, 4, false, laxExec) -- cgit v1.2.3