File size: 3,749 Bytes
50dd446 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | -- 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
|