lua-6502/README.md

150 lines
5.5 KiB
Markdown

This is a complete pure-Lua 65C02 emulator.
This requires Lua 5.3 (because of the bitwise functions). Yes, you
could probably port it to 5.2 and 5.1 fairly easily with one of the
Lua bitwise libraries. I'm more inclined to just leave it at Lua
5.3+. If you want to fork, then have at it!
# How would you use this?
Well, if I wanted to build an (original) Apple ][ emulator, I would
probably do it similarly to how I structured the tests. First build a
CPU...
``` lua
local _6502 = require '6502'
local cpu = _6502:new()
```
... and then override the simple memory array with a memory management
unit, which implements the various pieces of Apple ][ memory magic:
``` lua
local mmu = { ram = {} }
local mmu_metatable = { __index = function(t, key)
return t.ram[key] or 0
end,
__newindex = function(t, k, v)
if (k == 0xF001 and v ~= nil) then
io.write(string.format("%c", v))
end
if (k == 0x200 and v ~= nil) then
if (v == 240) then
print("All tests successful!")
os.exit(0)
end
print(string.format("Start test %d", v))
end
t.ram[k] = v
end,
}
setmetatable(mmu, mmu_metatable)
cpu.ram = mmu
```
Basically, the **__index** function gets called for any memory "read"; and
the **__newindex** function gets called for any "write". This MMU was
specifically built for the verbose CPU test; whenever it wants to
output a character, the test writes it to memory location 0xF001; and
whenever it starts a new test, it writes to memory location 0x200. So
those two memory locations are treated specially when writing to this
MMU; but it returns straight out of its "ram" table when reading
(since there's nothing special about its reads).
For memory in an Apple ][, it would do straight reads and writes for
any memory <= 0xC000. For 0xC000 through 0xCFFF, you'd do something
with the hardware I/O (where reads and writes are both special); and
then from 0xD000 through 0xFFFF you have ROM, which will need to be
loaded from a file or some such:
``` lua
local f = assert(io.open("apple2o.rom", "rb") )
local data = f:read("*a")
assert(#data == 12288)
local i = 0
while (i < #data) do
mmu[0xC000 + i] = data:byte(i+1)
i = i + 1
end
```
Finally, you would reinitialize the CPU, perform a reset, and then
start running it in a loop.
``` lua
cpu:init()
cpu:rst()
while (true) do
cpu:step()
end
```
Of course, then you get in to I/O issues, like keyboards and disk
drives; how you're going to draw a display; performance issues; what
about proper speed timing?; and details, details, details...
# Tests
The tests are from the fantastic project
https://github.com/Klaus2m5/6502_65C02_functional_tests
The tests in the tests/ directory are...
## 6502_functional_test.lua
from git commit fe99e5616243a1bdbceaf5907390ce4443de7db0
using files
6502_functional_test.bin
6502_functional_test.lst
This is basic testing of all core 6502 functions. In all, there are 43
tests; it takes some time to execute them (about 40 seconds on my 2015
Macbook Pro).
## 6502_functional_test_verbose.lua
from git commit fe99e5616243a1bdbceaf5907390ce4443de7db0
which I assembled with as65, with 'report' enabled
6502_functional_test_verbose.bin
6502_functional_test_verbose.lst
These are the same tests as above, but I assembled it in verbose mode;
if there's a test failure, it's much more explicit about it. An error
elicits output like this:
```
regs Y X A PS PCLPCH
01F9 04 02 20 B0 0B 2F 30
000C 20 00 00 00 00 00 00
0200 1E 00 00 00 00 00 00 00
press C to continue
```
(Of course, I haven't implemented "press C to continue" so it just
busy-loops forever.)
## 65C02_extended_opcodes_test.lua
from git commit f54e9a77efad2d78077107a919a412407c106f22
65C02_extended_opcodes_test.bin
65C02_extended_opcodes_test.lst
This tests much of the 65C02's extended behavior, including the
"invalid" opcodes. This has 21 tests and should end with "All tests
successful!" just like the other two tests.
## decimal_tests/*
The BCD "decimal mode" ADC and SBC operations behave in unexpected and difficult to explain ways - particularly the oVerflow flag, and especially when operating on "invalid" BCD numbers. For example - in Decimal mode, the operation "0x19 ADC 0x01" (hex 19 plus 1 -- or 25 + 1 in decimal) equals "0x20" (32). That's binary coded decimal, where the "hex" number 0x20 actually represents the decimal number 20.
So what happens when you tell it to add 0x1C + 0x01? 0x1C isn't a valid BCD number, so it's not obvious what should happen.
The test **65c02-all.bin** is a complete test of all decimal mode addition and subtraction, with validation of all of the N, V, Z, and C status flags. The wrapper 6502_decimal_test.lua take a "-f" argument that tells it which of the .bin files you want to load and execute. So it's invoked like this:
```
$ tests/decimal-tests/6502_decimal_test.lua -f tests/decimal-tests/65c02-all.bin
```
## Questions?
You can try emailing me at jorj@jorj.org. Glad to answer what I can, but my mailbox overfloweth perpetually and sometimes it takes a while for a reply!