-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlua6502.lua
More file actions
127 lines (108 loc) · 3.66 KB
/
Copy pathlua6502.lua
File metadata and controls
127 lines (108 loc) · 3.66 KB
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
-- 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