lua-6502/apple1/apple1.lua

192 lines
3.7 KiB
Lua
Executable File

#!/usr/bin/env lua5.3
require 'std.strict'
require 'lib' ("..")
local curses = require 'curses'
local _6502 = require '6502'
local cpu = _6502:new()
const = require "const"
local inspect = require "inspect"
-- Per Apple-1 Operation Manual (1976)
local _c = const {
DSPCR = 0xd013,
DSP = 0xd012,
KBDCR = 0xd011,
KBD = 0xd010 }
local stdscr
local screenX = 0
local screenY = 0
local running = true
local mmu = { ram = {},
immutable = {},
reset = function()
mmu.ram[_c.KBDCR] = 0
mmu.ram[_c.DSPCR] = 0
mmu.ram[_c.DSP] = 0
mmu.ram[_c.KBD] = 0x80
end,
}
local mmu_metatable = { __index = function(t, address)
if (address == _c.KBD) then t.ram[_c.KBDCR] = 0x27; return t.ram[_c.KBD] end
return t.ram[address] or 0
end,
__newindex = function(t, address, v)
if (address == _c.DSP) then
if ((t.ram[_c.DSPCR] & 0x04) == 0x04) then
t.ram[_c.DSP] = v
return
end
end
if (address == _c.KBDCR) then
if (t.ram[_c.KBDCR] == 0) then
v = 0x27
end
t.ram[_c.KBDCR] = v
return
end
if (t.immutable[address]) then
assert(0, "Tried to write to ROM")
return
end
t.ram[address] = v
end,
}
setmetatable(mmu, mmu_metatable)
cpu.ram = mmu
-- Load the monitor ROM @ 0xFF00
local f = assert(io.open("monitor.rom", "rb"), "Can't open monitor.rom")
local data = f:read("*a")
assert(#data == 256)
local i=0
while (i < #data) do
cpu:writemem(0xFF00 + i, data:byte(i+1))
mmu.immutable[0xFF00+i] = true
i = i + 1
end
-- Load the basic ROM @ 0xE000
local f = assert(io.open("basic.rom", "rb"), "Can't open basic.rom")
local data = f:read("*a")
assert(#data == 4096)
local i=0
while (i < #data) do
cpu:writemem(0xE000 + i, data:byte(i+1))
mmu.immutable[0xE000+i] = true
i = i + 1
end
cpu:init()
mmu.ram[_c.KBDCR] = 0
mmu.ram[_c.DSPCR] = 0
mmu.ram[_c.DSP] = 0
mmu.ram[_c.KBD] = 0x80
--mmu:reset()
cpu:rst()
stdscr = curses.initscr()
curses.cbreak()
curses.echo(false)
curses.nl(false)
stdscr:clear()
stdscr:nodelay(true)
stdscr:scrollok(true)
stdscr:refresh()
function checkForInput()
local ret = false
if (mmu[_c.KBDCR] == 0x27) then -- can handle input
local c = stdscr:getch()
if (c and c > 0 and c < 256) then
-- and we have input
c = c & 0x7F
if (c >= 0x61 and c <= 0x7A) then c = c & 0x5F end
if (c < 0x60) then
mmu[_c.KBD] = c | 0x80 -- write kbd
mmu[_c.KBDCR] = 0xA7 -- write KbdCr
ret = true
end
end
end
return ret
end
function updateScreen()
local dsp = mmu[_c.DSP]
-- High bit of the display character indicates there's something waiting to display
if (dsp & 0x80 == 0x80) then
dsp = dsp & 0x7F
local tmp = dsp
if (dsp >= 0x60 and dsp <= 0x7F) then
tmp = tmp & 0x5F
end
if (tmp == 0x0D) then
-- return key
screenX = 0
screenY = screenY + 1
else
if (tmp >= 0x20 and tmp <= 0x5F) then
stdscr:mvaddch(screenY, screenX, tmp)
screenX = screenX + 1
end
end
if (screenX == 40) then
screenX = 0
screenY = screenY + 1
end
if (screenY == 24) then
stdscr:scrl(1)
screenY = 23
end
-- draw the cursor
stdscr:move(screenY, screenX)
mmu[_c.DSP] = dsp -- write to dsp
end
stdscr:refresh()
end
local function err (err)
curses.endwin ()
print "Caught an error:"
print (debug.traceback (err, 2))
os.exit (2)
end
function main()
while (running) do
local pc = cpu.pc
local o = cpu:readmem(cpu.pc)
local cc = cpu:step()
checkForInput()
updateScreen()
end
end
xpcall(main, err)