343 lines
7.8 KiB
Lua
343 lines
7.8 KiB
Lua
-- ilo.lua
|
|
-- Partially derived from Ngaro in Lua
|
|
-- Copyright (c) 2010 - 2023, Charles Childers
|
|
--
|
|
-- This is only tested on Lua 5.4 and requires 32-bit
|
|
-- integers. (set `#define LUA_32BITS 1` in luaconf.h when
|
|
-- building Lua)
|
|
|
|
-- Variables
|
|
local ip = 0 -- instruction pointer
|
|
local sp = 0 -- stack pointer
|
|
local rp = 0 -- return pointer
|
|
local stack = {} -- data stack
|
|
local address = {} -- return stack
|
|
local memory = {} -- simulated ram
|
|
|
|
-- Support Code
|
|
local function file_size(filename)
|
|
local fh = assert(io.open(filename, 'rb'))
|
|
local len = assert(fh:seek('end'))
|
|
fh:close()
|
|
return len
|
|
end
|
|
|
|
local function constrain(n)
|
|
return (n > 0x7FFFFFFF) and (n - 0x100000000) or n
|
|
end
|
|
|
|
local function save_image()
|
|
local image = io.open('ilo.rom', 'wb')
|
|
local i = 0
|
|
while i < 65536 do
|
|
image:write(string.pack('<i4', memory[i]))
|
|
i = i + 1
|
|
end
|
|
image:close()
|
|
end
|
|
|
|
local function read_block()
|
|
local blocks = io.open('ilo.blocks', 'rb')
|
|
local buffer = stack[sp]
|
|
local block = stack[sp - 1]
|
|
sp = sp - 2
|
|
local i = 0
|
|
blocks:seek('set', block * 4096)
|
|
while i < 1024 do
|
|
memory[buffer] = string.unpack('<i4', blocks:read(4))
|
|
buffer = buffer + 1
|
|
i = i + 1
|
|
end
|
|
blocks:close()
|
|
end
|
|
|
|
local function write_block()
|
|
local blocks = io.open('ilo.blocks', 'r+b')
|
|
local buffer = stack[sp]
|
|
local block = stack[sp - 1]
|
|
sp = sp - 2
|
|
local i = 0
|
|
blocks:seek('set', block * 4096)
|
|
while i < 1024 do
|
|
local x = memory[buffer + i]
|
|
local b4=string.char(x%256) x=(x-x%256)/256
|
|
local b3=string.char(x%256) x=(x-x%256)/256
|
|
local b2=string.char(x%256) x=(x-x%256)/256
|
|
local b1=string.char(x%256) x=(x-x%256)/256
|
|
blocks:write(b4,b3,b2,b1)
|
|
i = i + 1
|
|
end
|
|
blocks:close()
|
|
end
|
|
|
|
local opcodes = {
|
|
[0] = function() end, -- no (nop)
|
|
[1] = function() -- li (lit)
|
|
sp = sp + 1
|
|
ip = ip + 1
|
|
stack[sp] = memory[ip]
|
|
end,
|
|
[2] = function() -- du (dup)
|
|
sp = sp + 1
|
|
stack[sp] = stack[sp - 1]
|
|
end,
|
|
[3] = function() -- dr (drop)
|
|
sp = sp - 1
|
|
end,
|
|
[4] = function() -- sw (swap)
|
|
local a = stack[sp]
|
|
stack[sp] = stack[sp - 1]
|
|
stack[sp - 1] = a
|
|
end,
|
|
[5] = function() -- pu (push)
|
|
rp = rp + 1
|
|
address[rp] = stack[sp]
|
|
sp = sp - 1
|
|
end,
|
|
[6] = function() -- po (pop)
|
|
sp = sp + 1
|
|
stack[sp] = address[rp]
|
|
rp = rp - 1
|
|
end,
|
|
[7] = function() -- ju (jump)
|
|
ip = stack[sp] - 1
|
|
sp = sp - 1
|
|
end,
|
|
[8] = function() -- ca (call)
|
|
rp = rp + 1
|
|
address[rp] = ip
|
|
ip = stack[sp] - 1
|
|
sp = sp - 1
|
|
end,
|
|
[9] = function() -- cc (cond. call)
|
|
if stack[sp - 1] ~= 0 then
|
|
rp = rp + 1
|
|
address[rp] = ip
|
|
ip = stack[sp] - 1
|
|
end
|
|
sp = sp - 2
|
|
end,
|
|
[10] = function() -- cj (cond. jump)
|
|
if stack[sp - 1] ~= 0 then
|
|
ip = stack[sp] - 1
|
|
end
|
|
sp = sp - 2
|
|
end,
|
|
[11] = function() -- re (return)
|
|
ip = address[rp]
|
|
rp = rp - 1
|
|
end,
|
|
[12] = function() -- eq (equality)
|
|
if stack[sp - 1] == stack[sp] then
|
|
stack[sp - 1] = -1
|
|
else
|
|
stack[sp - 1] = 0
|
|
end
|
|
sp = sp - 1
|
|
end,
|
|
[13] = function() -- ne (inequality)
|
|
if stack[sp - 1] == stack[sp] then
|
|
stack[sp - 1] = 0
|
|
else
|
|
stack[sp - 1] = -1
|
|
end
|
|
sp = sp - 1
|
|
end,
|
|
[14] = function() -- lt (less than)
|
|
if stack[sp - 1] < stack[sp] then
|
|
stack[sp - 1] = -1
|
|
else
|
|
stack[sp - 1] = 0
|
|
end
|
|
sp = sp - 1
|
|
end,
|
|
[15] = function() -- gt (greater than)
|
|
if stack[sp - 1] > stack[sp] then
|
|
stack[sp - 1] = -1
|
|
else
|
|
stack[sp - 1] = 0
|
|
end
|
|
sp = sp - 1
|
|
end,
|
|
[16] = function() -- fe (fetch)
|
|
stack[sp] = memory[stack[sp]]
|
|
end,
|
|
[17] = function() -- st (store)
|
|
memory[stack[sp]] = stack[sp - 1]
|
|
sp = sp - 2
|
|
end,
|
|
[18] = function() -- ad (add)
|
|
stack[sp - 1] = stack[sp - 1] + stack[sp]
|
|
sp = sp - 1
|
|
end,
|
|
[19] = function() -- su (subtract)
|
|
stack[sp - 1] = stack[sp - 1] - stack[sp]
|
|
sp = sp - 1
|
|
end,
|
|
[20] = function() -- mu (multiply)
|
|
stack[sp - 1] = stack[sp - 1] * stack[sp]
|
|
sp = sp - 1
|
|
end,
|
|
[21] = function() -- di (divide & remainder)
|
|
local b = stack[sp]
|
|
local a = stack[sp - 1]
|
|
local x = math.abs(b)
|
|
local y = math.abs(a)
|
|
local q = constrain(y // x)
|
|
local r = constrain(y % x)
|
|
if a < 0 and b < 0 then
|
|
r = r * -1
|
|
elseif a > 0 and b < 0 then
|
|
q = q * -1
|
|
elseif a < 0 and b > 0 then
|
|
r = r * -1
|
|
q = q * -1
|
|
end
|
|
stack[sp] = q
|
|
stack[sp - 1] = r
|
|
end,
|
|
[22] = function() -- an (and)
|
|
stack[sp - 1] = stack[sp - 1] & stack[sp]
|
|
sp = sp - 1
|
|
end,
|
|
[23] = function() -- or (or)
|
|
stack[sp - 1] = stack[sp - 1] | stack[sp]
|
|
sp = sp - 1
|
|
end,
|
|
[24] = function() -- xo (xor)
|
|
stack[sp - 1] = stack[sp - 1] ~ stack[sp]
|
|
sp = sp - 1
|
|
end,
|
|
[25] = function() -- sl (shift left)
|
|
stack[sp - 1] = stack[sp - 1] << stack[sp]
|
|
sp = sp - 1
|
|
end,
|
|
[26] = function() -- sr (shift right)
|
|
stack[sp - 1] = stack[sp - 1] >> stack[sp]
|
|
sp = sp - 1
|
|
end,
|
|
[27] = function() -- cp (compare)
|
|
local a = stack[sp] -- length
|
|
local b = stack[sp - 1] -- dest
|
|
local c = stack[sp - 2] -- source
|
|
local d = -1 -- flag
|
|
sp = sp - 3
|
|
while a > 0 do
|
|
if memory[b] ~= memory[c] then
|
|
d = 0
|
|
end
|
|
a = a - 1
|
|
b = b + 1
|
|
c = c + 1
|
|
end
|
|
sp = sp + 1
|
|
stack[sp] = d
|
|
end,
|
|
[28] = function() -- cy (copy)
|
|
local a = stack[sp] -- length
|
|
local b = stack[sp - 1] -- dest
|
|
local c = stack[sp - 2] -- source
|
|
sp = sp - 3
|
|
while a > 0 do
|
|
memory[b] = memory[c]
|
|
a = a - 1
|
|
b = b + 1
|
|
c = c + 1
|
|
end
|
|
end,
|
|
[29] = function() -- io
|
|
local d = stack[sp]
|
|
sp = sp - 1
|
|
if d == 0 then
|
|
io.write(string.char(stack[sp]))
|
|
sp = sp - 1
|
|
elseif d == 1 then
|
|
sp = sp + 1
|
|
stack[sp] = string.byte(io.read(1))
|
|
elseif d == 2 then
|
|
read_block()
|
|
elseif d == 3 then
|
|
write_block()
|
|
elseif d == 4 then
|
|
save_image()
|
|
elseif d == 5 then
|
|
load_image("ilo.rom")
|
|
ip = -1
|
|
sp = 0
|
|
rp = 0
|
|
elseif d == 6 then
|
|
ip = 65536
|
|
elseif d == 7 then
|
|
sp = sp + 1
|
|
stack[sp] = sp - 1
|
|
sp = sp + 1
|
|
stack[sp] = rp
|
|
end
|
|
end
|
|
}
|
|
|
|
-- -------------------------------------------------------------
|
|
-- process opcodes
|
|
local function process_opcode(opcode)
|
|
if opcode == 0 then return end -- skip NOP instructions
|
|
local op_fn = opcodes[opcode]
|
|
if op_fn then op_fn() end
|
|
end
|
|
|
|
local function process_opcodes()
|
|
local opcode = memory[ip]
|
|
process_opcode(opcode & 0xFF)
|
|
process_opcode(opcode>>8 & 0xFF)
|
|
process_opcode(opcode>>16 & 0xFF)
|
|
process_opcode(opcode>>24 & 0xFF)
|
|
end
|
|
|
|
-- Load image into memory
|
|
-- \ cells = size of image file (in cells)
|
|
-- \ image = pointer to retroImage file
|
|
local function load_image(file)
|
|
local cells = file_size(file) / 4
|
|
local image = io.open(file, 'rb')
|
|
local i = 0
|
|
while i < cells do
|
|
memory[i] = string.unpack('<i4', image:read(4))
|
|
i = i + 1
|
|
end
|
|
image:close()
|
|
while i < 65536 do
|
|
memory[i] = 0
|
|
i = i + 1
|
|
end
|
|
i = 0
|
|
while i < 33 do
|
|
stack[i] = 0
|
|
address[i] = 0
|
|
i = i + 1
|
|
end
|
|
while i < 257 do
|
|
address[i] = 0
|
|
i = i + 1
|
|
end
|
|
end
|
|
|
|
local function dump_stack()
|
|
while sp > 0 do
|
|
print(stack[sp])
|
|
sp = sp - 1
|
|
end
|
|
end
|
|
|
|
local function process_instructions()
|
|
while ip < 65536 do
|
|
process_opcodes()
|
|
ip = ip + 1
|
|
end
|
|
end
|
|
|
|
local function main()
|
|
load_image("ilo.rom")
|
|
process_instructions()
|
|
dump_stack()
|
|
end
|
|
|
|
main()
|