-- lua6502.lua -- Minimal 6502 NMOS emulator for use as a Mixture-of-Agents orchestrator -- inside LuaLaTeX compilation. -- -- Memory Map: -- 0x2000 : ANU Quantum Entropy input (write before vm:execute()) -- 0x2001 : MoA multiplier output (read after vm:execute()) -- -- Authors: Ahmad Ali Parr, Jessica L. Williams (SNAPKITTYWEST) -- Part of: sovereign-trinity-kernel local vm = { PC = 0x0600, A = 0x00, X = 0x00, Y = 0x00, SP = 0xFF, P = 0x20, -- processor status (unused flag set) flags = { C = 0, Z = 0, N = 0, V = 0 }, mem = {} } function vm:reset() self.PC = 0x0600 self.A = 0x00 self.X = 0x00 self.Y = 0x00 self.SP = 0xFF self.flags = { C = 0, Z = 0, N = 0, V = 0 } end function vm:write_mem(addr, val) self.mem[addr] = val & 0xFF end function vm:read_mem(addr) return self.mem[addr] or 0x00 end function vm:load_hex(hex_str, start_addr) self:reset() self.PC = start_addr local addr = start_addr for byte in hex_str:gmatch("%S+") do self:write_mem(addr, tonumber(byte, 16)) addr = addr + 1 end end function vm:set_nz(val) self.flags.Z = (val == 0) and 1 or 0 self.flags.N = ((val & 0x80) ~= 0) and 1 or 0 end function vm:execute(max_cycles) max_cycles = max_cycles or 1000 local cycles = 0 while cycles < max_cycles do local opcode = self:read_mem(self.PC) self.PC = self.PC + 1 cycles = cycles + 1 if opcode == 0x00 then -- BRK break elseif opcode == 0xA9 then -- LDA imm self.A = self:read_mem(self.PC) self.PC = self.PC + 1 self:set_nz(self.A) elseif opcode == 0xAD then -- LDA abs local lo = self:read_mem(self.PC) local hi = self:read_mem(self.PC + 1) local addr = lo + hi * 256 self.A = self:read_mem(addr) self.PC = self.PC + 2 self:set_nz(self.A) elseif opcode == 0x8D then -- STA abs local lo = self:read_mem(self.PC) local hi = self:read_mem(self.PC + 1) local addr = lo + hi * 256 self:write_mem(addr, self.A) self.PC = self.PC + 2 elseif opcode == 0xC9 then -- CMP imm local val = self:read_mem(self.PC) self.PC = self.PC + 1 self.flags.C = (self.A >= val) and 1 or 0 self.flags.Z = (self.A == val) and 1 or 0 local result = (self.A - val) & 0xFF self.flags.N = ((result & 0x80) ~= 0) and 1 or 0 elseif opcode == 0x90 then -- BCC rel local rel = self:read_mem(self.PC) self.PC = self.PC + 1 if self.flags.C == 0 then if rel > 127 then rel = rel - 256 end self.PC = self.PC + rel end elseif opcode == 0xB0 then -- BCS rel local rel = self:read_mem(self.PC) self.PC = self.PC + 1 if self.flags.C == 1 then if rel > 127 then rel = rel - 256 end self.PC = self.PC + rel end elseif opcode == 0xEA then -- NOP -- nothing else if tex then tex.print("\\PackageWarning{lua6502}{Illegal opcode: " .. string.format("$%02X", opcode) .. " at PC=" .. string.format("$%04X", self.PC - 1) .. "}") end break end end return self:read_mem(0x2001) end return vm