1228 lines
37 KiB
Lua
1228 lines
37 KiB
Lua
do
|
|
local orig_require, loaded, retval, source = _G.require, {}, {}, {['chat'] = [=[local Device = require('device')
|
|
local system_device
|
|
do
|
|
local c = Device:new()
|
|
c.name = 'system'
|
|
c:addPort(2, false, function(self)
|
|
return self.cpu.program_stack:len()
|
|
end)
|
|
c:addPort(3, false, function(self)
|
|
return self.cpu.return_stack:len()
|
|
end)
|
|
system_device = c
|
|
end
|
|
local console_device
|
|
do
|
|
local c = Device:new()
|
|
c.name = 'console'
|
|
c:addPort(8, false, nil, function(self, byte)
|
|
return table.insert(self.stdout, byte)
|
|
end)
|
|
c:addPort(9, false, nil, function(self, byte)
|
|
return table.insert(self.stderr, byte)
|
|
end)
|
|
console_device = c
|
|
end
|
|
local datetime_device
|
|
do
|
|
local dt = Device:new()
|
|
dt.name = 'datetime'
|
|
dt:addPort(0, true, function(self)
|
|
return tonumber(os.date('!%Y'))
|
|
end)
|
|
dt:addPort(2, false, function(self)
|
|
return tonumber(os.date('!%m')) - 1
|
|
end)
|
|
dt:addPort(3, false, function(self)
|
|
return tonumber(os.date('!%d'))
|
|
end)
|
|
dt:addPort(4, false, function(self)
|
|
return tonumber(os.date('!%H'))
|
|
end)
|
|
dt:addPort(5, false, function(self)
|
|
return tonumber(os.date('!%M'))
|
|
end)
|
|
dt:addPort(6, false, function(self)
|
|
return tonumber(os.date('!%S'))
|
|
end)
|
|
dt:addPort(7, false, function(self)
|
|
return tonumber(os.date('!%u')) % 7
|
|
end)
|
|
dt:addPort(8, true, function(self)
|
|
return tonumber(os.date('!%j')) - 1
|
|
end)
|
|
dt:addPort(10, true, function(self)
|
|
return 0
|
|
end)
|
|
datetime_device = dt
|
|
end
|
|
local Uxn
|
|
do
|
|
local m = require('uxn')
|
|
Uxn = function()
|
|
local u = m.Uxn:new()
|
|
u:addDevice(0x0, system_device)
|
|
u:addDevice(0x1, console_device)
|
|
u:addDevice(0xb, datetime_device)
|
|
return u
|
|
end
|
|
end
|
|
local load_memory
|
|
do
|
|
local mem_mt = {
|
|
__index = function(self, k)
|
|
return 0
|
|
end
|
|
}
|
|
load_memory = function(u, t)
|
|
u.memory = setmetatable((function()
|
|
local _tbl_0 = { }
|
|
for i, v in ipairs(t) do
|
|
_tbl_0[i + 255] = v
|
|
end
|
|
return _tbl_0
|
|
end)(), mem_mt)
|
|
end
|
|
end
|
|
local load_source
|
|
load_source = function(u, s)
|
|
for i = 1, #s do
|
|
u.memory[i + 0xdfff] = s:byte(i, i)
|
|
end
|
|
end
|
|
local u = Uxn()
|
|
local asma_rom = {
|
|
160, 12, 215, 160, 7, 119, 53, 160, 3, 177, 46, 160, 7, 75, 160, 5, 93, 53,
|
|
160, 240, 0, 160, 224, 0, 185, 160, 4, 195, 46, 34, 34, 160, 5, 99, 52, 29,
|
|
128, 48, 13, 0, 160, 3, 230, 46, 160, 240, 0, 160, 224, 0, 185, 160, 4,
|
|
195, 46, 34, 34, 160, 5, 99, 52, 29, 128, 22, 13, 128, 79, 128, 24, 23,
|
|
128, 75, 128, 24, 23, 160, 7, 73, 52, 4, 128, 24, 23, 128, 24, 23, 0, 160,
|
|
5, 99, 52, 160, 3, 108, 46, 128, 58, 128, 25, 23, 128, 32, 128, 25, 23,
|
|
160, 5, 87, 52, 160, 3, 108, 46, 128, 46, 128, 25, 23, 0, 0, 128, 1, 128,
|
|
167, 23, 38, 128, 168, 55, 128, 1, 128, 166, 23, 160, 5, 97, 53, 160, 5,
|
|
95, 53, 160, 3, 177, 46, 160, 7, 75, 160, 5, 93, 53, 160, 5, 95, 52, 160,
|
|
4, 57, 46, 160, 5, 99, 52, 29, 128, 71, 13, 160, 3, 230, 46, 160, 7, 77,
|
|
160, 5, 93, 53, 160, 5, 97, 52, 29, 128, 7, 13, 160, 7, 94, 160, 5, 93, 53,
|
|
160, 5, 95, 52, 160, 4, 57, 46, 160, 5, 99, 52, 29, 128, 29, 13, 160, 7,
|
|
73, 52, 160, 240, 0, 57, 160, 5, 93, 52, 46, 160, 5, 102, 160, 3, 12, 46,
|
|
160, 2, 65, 46, 160, 2, 118, 46, 108, 160, 1, 245, 46, 108, 128, 168, 54,
|
|
160, 3, 108, 46, 160, 2, 58, 160, 3, 108, 46, 160, 5, 78, 52, 160, 3, 123,
|
|
46, 128, 58, 128, 25, 23, 128, 32, 128, 25, 23, 160, 5, 99, 52, 160, 3,
|
|
108, 46, 128, 58, 128, 25, 23, 128, 32, 128, 25, 23, 160, 5, 87, 52, 160,
|
|
3, 108, 46, 128, 46, 128, 25, 23, 128, 10, 128, 25, 23, 108, 32, 108, 105,
|
|
110, 101, 32, 0, 160, 5, 101, 20, 128, 1, 28, 128, 0, 8, 128, 15, 13, 160,
|
|
5, 80, 52, 160, 3, 123, 46, 160, 2, 94, 160, 3, 108, 46, 108, 32, 108, 105,
|
|
110, 101, 115, 32, 111, 102, 32, 115, 111, 117, 114, 99, 101, 32, 99, 111,
|
|
100, 101, 46, 10, 0, 160, 5, 101, 20, 128, 8, 28, 128, 0, 8, 128, 38, 13,
|
|
160, 7, 119, 52, 160, 12, 215, 57, 160, 3, 123, 46, 160, 2, 170, 160, 3,
|
|
108, 46, 160, 224, 0, 160, 7, 119, 52, 57, 160, 3, 123, 46, 160, 2, 192,
|
|
160, 3, 108, 46, 108, 32, 98, 121, 116, 101, 115, 32, 111, 102, 32, 104,
|
|
101, 97, 112, 32, 117, 115, 101, 100, 44, 32, 0, 32, 98, 121, 116, 101,
|
|
115, 32, 102, 114, 101, 101, 46, 10, 0, 52, 157, 128, 2, 13, 34, 108, 38,
|
|
128, 245, 14, 128, 9, 128, 25, 23, 38, 160, 0, 4, 56, 38, 33, 36, 20, 6,
|
|
128, 0, 8, 128, 6, 13, 128, 25, 23, 128, 239, 12, 2, 128, 9, 128, 25, 23,
|
|
52, 160, 3, 123, 46, 128, 10, 128, 25, 23, 160, 0, 2, 56, 128, 195, 14,
|
|
108, 160, 5, 101, 20, 128, 4, 28, 128, 0, 8, 128, 5, 13, 52, 157, 128, 2,
|
|
13, 34, 108, 38, 128, 232, 14, 38, 160, 0, 4, 56, 148, 128, 65, 11, 128,
|
|
11, 13, 148, 128, 90, 10, 128, 4, 13, 34, 128, 41, 12, 38, 33, 36, 20, 6,
|
|
128, 0, 8, 128, 6, 13, 128, 25, 23, 128, 239, 12, 2, 128, 9, 128, 25, 23,
|
|
180, 160, 3, 123, 46, 128, 10, 128, 25, 23, 160, 0, 2, 56, 160, 2, 206, 46,
|
|
160, 0, 2, 56, 128, 161, 14, 108, 148, 6, 128, 3, 13, 2, 34, 108, 128, 25,
|
|
23, 33, 128, 241, 12, 128, 48, 128, 25, 23, 128, 120, 128, 25, 23, 7, 128,
|
|
4, 31, 128, 20, 14, 4, 128, 15, 28, 128, 13, 14, 6, 128, 4, 31, 128, 6, 14,
|
|
128, 15, 28, 128, 0, 12, 128, 48, 24, 6, 128, 58, 11, 128, 3, 13, 128, 39,
|
|
24, 128, 25, 23, 108, 160, 34, 2, 30, 160, 6, 192, 21, 160, 66, 2, 30, 160,
|
|
6, 206, 21, 160, 130, 2, 30, 160, 6, 218, 21, 128, 255, 160, 5, 76, 21,
|
|
160, 0, 0, 166, 160, 5, 99, 53, 160, 5, 102, 53, 160, 5, 104, 53, 160, 11,
|
|
215, 160, 5, 106, 53, 160, 5, 76, 20, 1, 160, 5, 76, 21, 160, 240, 0, 160,
|
|
7, 73, 53, 160, 1, 0, 38, 6, 160, 5, 77, 21, 160, 5, 89, 53, 160, 5, 91,
|
|
53, 160, 4, 57, 160, 4, 21, 185, 160, 4, 195, 46, 34, 34, 108, 37, 66, 82,
|
|
75, 32, 123, 32, 48, 48, 32, 125, 32, 37, 91, 32, 123, 32, 125, 32, 37, 93,
|
|
32, 123, 32, 125, 32, 64, 111, 110, 45, 114, 101, 115, 101, 116, 32, 160,
|
|
4, 195, 160, 0, 0, 37, 160, 224, 0, 38, 160, 240, 0, 37, 57, 37, 128, 14,
|
|
14, 160, 5, 99, 52, 29, 128, 0, 13, 34, 34, 34, 34, 34, 108, 160, 0, 0, 38,
|
|
37, 47, 37, 239, 128, 168, 55, 175, 128, 50, 51, 47, 175, 128, 48, 51, 38,
|
|
128, 78, 51, 128, 37, 14, 36, 165, 35, 39, 128, 172, 55, 128, 162, 54, 36,
|
|
46, 37, 36, 185, 35, 157, 128, 6, 13, 34, 98, 98, 111, 111, 108, 111, 36,
|
|
171, 12, 97, 57, 111, 111, 128, 199, 12, 160, 0, 0, 160, 0, 0, 170, 128,
|
|
15, 13, 39, 128, 170, 55, 128, 21, 50, 128, 172, 55, 39, 57, 128, 237, 12,
|
|
128, 170, 55, 128, 7, 50, 128, 172, 55, 128, 170, 55, 108, 0, 0, 37, 47,
|
|
39, 56, 39, 160, 224, 0, 40, 15, 38, 160, 240, 0, 41, 79, 28, 160, 5, 83,
|
|
21, 36, 175, 148, 128, 33, 11, 128, 4, 13, 33, 128, 245, 12, 170, 128, 13,
|
|
13, 160, 5, 83, 20, 128, 77, 13, 34, 34, 111, 111, 36, 108, 148, 128, 10,
|
|
9, 128, 0, 39, 21, 111, 128, 108, 14, 160, 5, 99, 52, 29, 128, 38, 13, 128,
|
|
7, 13, 128, 64, 50, 33, 128, 60, 51, 160, 5, 82, 20, 128, 5, 13, 33, 175,
|
|
128, 186, 12, 160, 5, 82, 20, 128, 1, 25, 160, 5, 82, 21, 33, 35, 111, 36,
|
|
108, 2, 34, 34, 239, 160, 5, 78, 53, 111, 160, 224, 0, 108, 34, 128, 0, 5,
|
|
5, 21, 111, 128, 39, 14, 111, 160, 224, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
38, 160, 5, 85, 53, 38, 160, 5, 87, 53, 148, 128, 2, 13, 34, 108, 33, 175,
|
|
212, 175, 192, 0, 47, 85, 128, 0, 160, 5, 77, 20, 153, 28, 38, 160, 5, 171,
|
|
56, 160, 6, 66, 46, 85, 128, 8, 13, 111, 160, 5, 85, 53, 35, 52, 44, 34,
|
|
98, 160, 5, 177, 56, 52, 44, 11, 127, 11, 7, 11, 31, 10, 18, 7, 192, 8, 52,
|
|
6, 128, 58, 11, 128, 8, 13, 6, 128, 96, 10, 128, 5, 13, 108, 128, 48, 25,
|
|
108, 128, 87, 25, 108, 15, 160, 5, 85, 52, 38, 128, 92, 14, 6, 79, 28, 128,
|
|
60, 13, 38, 160, 0, 4, 42, 128, 52, 13, 157, 128, 0, 8, 128, 45, 13, 160,
|
|
0, 2, 42, 5, 5, 224, 0, 0, 148, 6, 128, 9, 13, 2, 34, 111, 5, 1, 134, 24,
|
|
24, 108, 128, 177, 14, 6, 128, 240, 28, 128, 11, 13, 192, 64, 127, 192, 0,
|
|
15, 120, 33, 128, 221, 12, 98, 34, 34, 128, 0, 108, 47, 128, 7, 12, 25,
|
|
128, 10, 141, 34, 33, 97, 148, 212, 79, 157, 128, 242, 13, 111, 36, 108,
|
|
224, 0, 0, 128, 2, 12, 33, 97, 148, 128, 250, 13, 34, 111, 108, 160, 5, 85,
|
|
52, 47, 180, 29, 128, 4, 13, 98, 128, 1, 108, 52, 38, 160, 0, 4, 56, 239,
|
|
128, 196, 14, 128, 8, 13, 2, 34, 33, 35, 98, 128, 0, 108, 128, 128, 28,
|
|
128, 6, 31, 128, 0, 4, 47, 34, 34, 111, 56, 128, 209, 12, 160, 5, 85, 52,
|
|
38, 128, 181, 14, 160, 0, 3, 43, 128, 91, 13, 160, 0, 3, 56, 175, 212, 175,
|
|
192, 0, 47, 85, 160, 5, 106, 160, 6, 66, 46, 85, 128, 68, 13, 160, 11, 219,
|
|
57, 128, 3, 63, 6, 128, 0, 8, 128, 48, 13, 212, 79, 224, 0, 1, 120, 6, 128,
|
|
4, 13, 2, 98, 4, 108, 6, 128, 50, 9, 128, 7, 13, 2, 128, 0, 29, 128, 228,
|
|
12, 6, 128, 114, 9, 128, 7, 13, 2, 128, 0, 29, 128, 214, 12, 128, 107, 9,
|
|
128, 6, 13, 128, 0, 29, 128, 202, 12, 98, 34, 128, 1, 108, 128, 128, 128,
|
|
17, 14, 128, 14, 14, 108, 160, 5, 89, 180, 37, 56, 36, 53, 108, 4, 128, 0,
|
|
14, 160, 5, 89, 52, 160, 5, 91, 52, 171, 128, 13, 13, 168, 128, 20, 13,
|
|
128, 0, 128, 26, 14, 33, 128, 243, 12, 160, 10, 222, 160, 5, 99, 53, 34,
|
|
34, 2, 108, 34, 33, 38, 160, 5, 89, 53, 160, 5, 91, 53, 128, 29, 50, 38,
|
|
160, 255, 255, 40, 128, 8, 13, 175, 21, 111, 33, 128, 14, 51, 108, 160,
|
|
240, 0, 185, 160, 5, 93, 52, 46, 35, 128, 235, 12, 0, 0, 34, 108, 128, 170,
|
|
55, 160, 5, 97, 52, 128, 168, 55, 160, 240, 0, 128, 174, 55, 108, 157, 128,
|
|
2, 13, 34, 108, 160, 240, 0, 38, 37, 56, 36, 148, 128, 24, 23, 33, 170,
|
|
128, 247, 13, 34, 34, 108, 0, 0, 128, 251, 50, 161, 128, 247, 51, 21, 108,
|
|
128, 242, 50, 161, 33, 128, 237, 51, 53, 108, 47, 128, 231, 50, 128, 1, 12,
|
|
97, 212, 70, 175, 85, 33, 192, 247, 77, 98, 128, 215, 51, 108, 160, 5, 85,
|
|
52, 160, 6, 51, 46, 29, 128, 19, 13, 160, 5, 84, 148, 1, 5, 5, 21, 160, 5,
|
|
77, 20, 128, 2, 29, 160, 5, 77, 21, 108, 160, 5, 85, 52, 160, 6, 51, 46,
|
|
29, 128, 243, 13, 160, 5, 84, 148, 128, 1, 25, 6, 36, 21, 128, 230, 13,
|
|
160, 5, 77, 20, 128, 12, 28, 160, 5, 77, 21, 108, 160, 5, 76, 20, 128, 59,
|
|
13, 160, 5, 104, 160, 6, 66, 46, 128, 9, 13, 34, 160, 10, 201, 160, 5, 99,
|
|
53, 108, 160, 7, 119, 52, 36, 53, 160, 0, 0, 160, 7, 130, 46, 160, 0, 0,
|
|
160, 7, 130, 46, 160, 5, 85, 52, 160, 7, 140, 46, 160, 5, 77, 20, 128, 4,
|
|
29, 160, 5, 77, 21, 108, 160, 5, 77, 20, 128, 12, 29, 160, 5, 77, 21, 108,
|
|
160, 5, 77, 20, 128, 8, 28, 128, 8, 13, 160, 5, 85, 52, 160, 7, 140, 46,
|
|
108, 128, 0, 160, 7, 121, 46, 160, 5, 77, 20, 128, 2, 28, 160, 5, 77, 21,
|
|
108, 160, 5, 102, 128, 29, 14, 128, 7, 13, 160, 0, 0, 160, 7, 130, 46, 160,
|
|
0, 2, 56, 160, 5, 108, 53, 108, 160, 5, 108, 52, 128, 3, 14, 2, 34, 108,
|
|
160, 6, 66, 46, 128, 19, 13, 180, 160, 5, 89, 52, 40, 128, 7, 13, 160, 10,
|
|
239, 160, 5, 99, 53, 128, 1, 108, 160, 7, 119, 52, 36, 53, 160, 0, 0, 160,
|
|
7, 130, 46, 160, 0, 0, 160, 7, 130, 46, 160, 5, 85, 52, 160, 7, 140, 46,
|
|
160, 7, 119, 52, 160, 5, 89, 52, 160, 7, 130, 46, 128, 0, 108, 160, 0, 0,
|
|
160, 5, 89, 53, 128, 0, 160, 5, 206, 46, 128, 8, 13, 160, 10, 118, 160, 5,
|
|
99, 53, 108, 160, 6, 237, 44, 160, 5, 85, 52, 148, 6, 128, 3, 13, 2, 34,
|
|
108, 160, 6, 250, 46, 33, 128, 240, 12, 128, 160, 160, 6, 250, 46, 128,
|
|
121, 14, 160, 6, 246, 44, 128, 128, 160, 6, 250, 46, 128, 108, 14, 160, 6,
|
|
250, 46, 128, 1, 13, 108, 160, 5, 76, 20, 128, 0, 8, 160, 5, 99, 52, 29,
|
|
29, 128, 7, 13, 160, 10, 138, 160, 5, 99, 53, 108, 128, 32, 128, 2, 12,
|
|
128, 64, 160, 6, 250, 46, 128, 62, 14, 160, 5, 89, 52, 57, 160, 0, 2, 57,
|
|
160, 6, 246, 44, 128, 128, 160, 6, 250, 46, 128, 40, 14, 160, 5, 89, 52,
|
|
57, 160, 0, 2, 57, 38, 160, 0, 128, 43, 15, 38, 160, 255, 127, 42, 79, 29,
|
|
128, 9, 13, 34, 160, 10, 163, 160, 5, 99, 53, 108, 160, 6, 250, 46, 2, 108,
|
|
160, 5, 85, 52, 148, 128, 38, 9, 128, 12, 13, 33, 160, 5, 85, 53, 160, 5,
|
|
108, 52, 128, 57, 12, 148, 6, 128, 8, 13, 2, 34, 160, 5, 102, 128, 44, 12,
|
|
128, 47, 8, 128, 4, 13, 33, 128, 233, 12, 38, 128, 0, 5, 5, 21, 160, 5,
|
|
102, 160, 6, 66, 46, 15, 36, 38, 128, 47, 5, 5, 21, 79, 128, 18, 13, 33,
|
|
160, 5, 85, 53, 160, 0, 2, 56, 160, 6, 66, 46, 128, 3, 13, 52, 108, 34, 34,
|
|
160, 5, 76, 20, 128, 0, 8, 128, 7, 13, 160, 10, 185, 160, 5, 99, 53, 160,
|
|
5, 89, 52, 108, 128, 1, 160, 5, 206, 46, 12, 128, 6, 12, 128, 11, 12, 128,
|
|
20, 12, 160, 10, 118, 160, 5, 99, 53, 108, 160, 6, 228, 46, 2, 108, 160, 6,
|
|
250, 46, 2, 108, 128, 160, 160, 6, 250, 46, 160, 6, 246, 44, 160, 6, 118,
|
|
46, 128, 4, 13, 160, 6, 250, 44, 128, 1, 160, 5, 206, 46, 12, 128, 6, 12,
|
|
128, 216, 12, 128, 225, 12, 160, 5, 104, 160, 6, 66, 46, 128, 31, 13, 148,
|
|
128, 2, 13, 34, 108, 166, 160, 6, 51, 46, 33, 56, 36, 160, 5, 110, 46, 160,
|
|
5, 99, 52, 29, 128, 3, 13, 128, 227, 12, 34, 108, 34, 128, 96, 160, 9, 46,
|
|
44, 160, 7, 119, 52, 160, 5, 85, 52, 160, 7, 140, 46, 160, 4, 57, 46, 160,
|
|
5, 82, 148, 1, 5, 5, 21, 108, 73, 110, 118, 97, 108, 105, 100, 32, 104,
|
|
101, 120, 97, 100, 101, 99, 105, 109, 97, 108, 0, 65, 100, 100, 114, 101,
|
|
115, 115, 32, 110, 111, 116, 32, 105, 110, 32, 122, 101, 114, 111, 32, 112,
|
|
97, 103, 101, 0, 65, 100, 100, 114, 101, 115, 115, 32, 111, 117, 116, 115,
|
|
105, 100, 101, 32, 114, 97, 110, 103, 101, 0, 76, 97, 98, 101, 108, 32,
|
|
110, 111, 116, 32, 102, 111, 117, 110, 100, 0, 77, 97, 99, 114, 111, 32,
|
|
97, 108, 114, 101, 97, 100, 121, 32, 101, 120, 105, 115, 116, 115, 0, 77,
|
|
101, 109, 111, 114, 121, 32, 111, 118, 101, 114, 119, 114, 105, 116, 101,
|
|
0, 76, 97, 98, 101, 108, 32, 114, 101, 100, 101, 102, 105, 110, 101, 100,
|
|
0, 0, 0, 0, 0, 40, 0, 7, 161, 10, 255, 0, 0, 41, 0, 7, 193, 0, 0, 0, 0, 40,
|
|
0, 7, 173, 11, 15, 0, 0, 41, 0, 7, 218, 11, 23, 11, 39, 123, 0, 7, 192, 0,
|
|
0, 0, 0, 125, 0, 8, 71, 0, 0, 0, 0, 33, 0, 9, 44, 11, 47, 0, 0, 34, 0, 8,
|
|
221, 11, 55, 11, 79, 35, 0, 9, 228, 0, 0, 0, 0, 36, 0, 8, 200, 11, 71, 0,
|
|
0, 37, 0, 7, 230, 11, 63, 11, 111, 38, 0, 8, 114, 0, 0, 0, 0, 40, 0, 7,
|
|
173, 11, 95, 0, 0, 41, 0, 7, 218, 11, 103, 11, 119, 44, 0, 9, 66, 0, 0, 0,
|
|
0, 45, 0, 9, 4, 11, 87, 11, 175, 46, 0, 8, 254, 0, 0, 0, 0, 58, 0, 8, 247,
|
|
11, 135, 0, 0, 59, 0, 8, 241, 11, 143, 11, 167, 61, 0, 8, 247, 0, 0, 0, 0,
|
|
63, 0, 9, 39, 11, 159, 0, 0, 64, 0, 8, 89, 11, 151, 11, 199, 95, 0, 9, 72,
|
|
0, 0, 0, 0, 123, 0, 7, 192, 11, 183, 0, 0, 124, 0, 8, 193, 11, 191, 11,
|
|
207, 125, 0, 7, 192, 0, 0, 0, 0, 126, 0, 10, 93, 12, 39, 11, 255, 76, 73,
|
|
84, 0, 0, 0, 0, 0, 73, 78, 67, 0, 0, 0, 0, 0, 80, 79, 80, 0, 12, 167, 12,
|
|
15, 78, 73, 80, 0, 0, 0, 0, 0, 83, 87, 80, 0, 11, 239, 12, 111, 82, 79, 84,
|
|
0, 0, 0, 0, 0, 68, 85, 80, 0, 12, 191, 11, 231, 79, 86, 82, 0, 0, 0, 0, 0,
|
|
69, 81, 85, 0, 0, 0, 0, 0, 78, 69, 81, 0, 12, 175, 12, 71, 71, 84, 72, 0,
|
|
0, 0, 0, 0, 76, 84, 72, 0, 0, 0, 0, 0, 74, 77, 80, 0, 11, 223, 12, 55, 74,
|
|
67, 78, 0, 12, 63, 12, 103, 74, 83, 82, 0, 0, 0, 0, 0, 83, 84, 72, 0, 0, 0,
|
|
0, 0, 76, 68, 90, 0, 0, 0, 0, 0, 83, 84, 90, 0, 12, 119, 12, 87, 76, 68,
|
|
82, 0, 12, 127, 12, 159, 83, 84, 82, 0, 0, 0, 0, 0, 76, 68, 65, 0, 12, 207,
|
|
12, 79, 83, 84, 65, 0, 12, 183, 12, 143, 68, 69, 73, 0, 0, 0, 0, 0, 68, 69,
|
|
79, 0, 0, 0, 0, 0, 65, 68, 68, 0, 12, 95, 11, 247, 83, 85, 66, 0, 12, 47,
|
|
12, 31, 77, 85, 76, 0, 12, 135, 12, 199, 68, 73, 86, 0, 12, 151, 0, 0, 65,
|
|
78, 68, 0, 0, 0, 0, 0, 79, 82, 65, 0, 12, 7, 12, 23, 69, 79, 82, 0, 0, 0,
|
|
0, 0, 83, 70, 84, 0
|
|
}
|
|
local run
|
|
run = function(u)
|
|
console_device.stdout = { }
|
|
console_device.stderr = { }
|
|
u.program_stack.head = 0
|
|
u.return_stack.head = 0
|
|
u.ip = 0x100
|
|
return u:runUntilBreak()
|
|
end
|
|
local resume
|
|
resume = function(u)
|
|
u.ip = u.ip + 1
|
|
return u:runUntilBreak()
|
|
end
|
|
local quote
|
|
do
|
|
local translate
|
|
do
|
|
local _tbl_0 = { }
|
|
for i = 0, 255 do
|
|
_tbl_0[i] = ('\\x%02x'):format(i)
|
|
end
|
|
translate = _tbl_0
|
|
end
|
|
for i = 32, 126 do
|
|
translate[i] = string.char(i)
|
|
end
|
|
translate[0x0d] = '\\r'
|
|
translate[0x0a] = '\\n'
|
|
translate[0x22] = '\\"'
|
|
translate[0x5c] = '\\\\'
|
|
quote = function(t)
|
|
local out
|
|
do
|
|
local _tbl_0 = { }
|
|
for i, v in ipairs(t) do
|
|
_tbl_0[i + 1] = translate[v]
|
|
end
|
|
out = _tbl_0
|
|
end
|
|
out[1] = '"'
|
|
out[#out + 1] = '"'
|
|
return table.concat(out)
|
|
end
|
|
end
|
|
local preamble = [[|10 @Console $8 &write $1 &error $1
|
|
|b0 @DateTime [ &year $2 &month $1 &day $1 &hour $1 &minute $1 &second $1 &dotw $1 &doty $2 &isdst $1 ]
|
|
|0100 @reset
|
|
]]
|
|
local help_message = [[Hi, I'm uxnbot! Type a line of Uxntal and I'll run it and print out the stacks and Console output. Start the line with "hexdump" and, instead of running it, I'll print a hexdump of the assembled ROM. I also understand the word "help" to print this message. I only support DateTime and the Console/write and Console/error device bytes so far.]]
|
|
local chat
|
|
chat = function(command)
|
|
local remainder = command:match('^uxnbot:%s+(.*)$')
|
|
if remainder then
|
|
command = remainder
|
|
end
|
|
local help = command:match('^help(.?)')
|
|
if help and (help == '' or help:upper() == help:lower()) then
|
|
return help_message
|
|
end
|
|
local hexdump = command:match('^hexdump%s+(.*)')
|
|
if hexdump then
|
|
command = hexdump
|
|
end
|
|
load_memory(u, asma_rom)
|
|
load_source(u, preamble .. command)
|
|
local okay, err = pcall(run, u)
|
|
if not okay then
|
|
return 'internal assembly error, pass 1: ' .. (err:match('^[^:]*:[^:]*:%s*(.*)$') or 'unknown error')
|
|
end
|
|
if #console_device.stderr > 0 then
|
|
return 'assembly error, pass 1: ' .. table.concat((function()
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
local _list_0 = console_device.stderr
|
|
for _index_0 = 1, #_list_0 do
|
|
local c = _list_0[_index_0]
|
|
_accum_0[_len_0] = string.char(c)
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
return _accum_0
|
|
end)())
|
|
end
|
|
okay, err = pcall(resume, u)
|
|
if not okay then
|
|
return 'internal assembly error, pass 2: ' .. (err:match('^[^:]*:[^:]*:%s*(.*)$') or 'unknown error')
|
|
end
|
|
if #console_device.stdout == 4 and console_device.stdout[1] == 0x4f and console_device.stdout[2] == 0x4b then
|
|
local write_end = console_device.stdout[3] * 0x100 + console_device.stdout[4]
|
|
local assembled_code
|
|
do
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for i = 0xf000, write_end - 1 do
|
|
_accum_0[_len_0] = u.memory[i]
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
assembled_code = _accum_0
|
|
end
|
|
if hexdump then
|
|
local out
|
|
do
|
|
local _tbl_0 = { }
|
|
for i, v in ipairs(assembled_code) do
|
|
_tbl_0[i + 1] = ('%02x'):format(v)
|
|
end
|
|
out = _tbl_0
|
|
end
|
|
out[1] = 'ROM contents: '
|
|
out[#out] = out[#out] .. (', 0x%x bytes'):format(#assembled_code)
|
|
return table.concat(out, ' ')
|
|
end
|
|
load_memory(u, assembled_code)
|
|
okay, err = pcall(run, u)
|
|
if okay then
|
|
local parts = { }
|
|
if u.program_stack.head > 0 then
|
|
table.insert(parts, ('wst %s'):format(u.program_stack:debug()))
|
|
end
|
|
if u.return_stack.head > 0 then
|
|
table.insert(parts, ('rst %s'):format(u.return_stack:debug()))
|
|
end
|
|
if #console_device.stdout > 0 then
|
|
if #console_device.stdout > 100 then
|
|
table.insert(parts, ('%s and more on Console/write'):format(quote((function()
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for i = 1, 100 do
|
|
_accum_0[_len_0] = console_device.stdout[i]
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
return _accum_0
|
|
end)())))
|
|
else
|
|
table.insert(parts, ('%s on Console/write'):format(quote(console_device.stdout)))
|
|
end
|
|
end
|
|
if #console_device.stderr > 0 then
|
|
if #console_device.stderr > 100 then
|
|
table.insert(parts, ('%s and more on Console/error'):format(quote((function()
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
for i = 1, 100 do
|
|
_accum_0[_len_0] = console_device.stderr[i]
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
return _accum_0
|
|
end)())))
|
|
else
|
|
table.insert(parts, ('%s on Console/error'):format(quote(console_device.stderr)))
|
|
end
|
|
end
|
|
if #parts == 0 then
|
|
table.insert(parts, 'wst empty')
|
|
end
|
|
return table.concat(parts, ', ')
|
|
else
|
|
return 'runtime error: ' .. (err:match('^[^:]*:[^:]*:%s*(.*)$') or 'unknown error')
|
|
end
|
|
else
|
|
return 'assembly error, pass 2: ' .. table.concat((function()
|
|
local _accum_0 = { }
|
|
local _len_0 = 1
|
|
local _list_0 = console_device.stderr
|
|
for _index_0 = 1, #_list_0 do
|
|
local c = _list_0[_index_0]
|
|
_accum_0[_len_0] = string.char(c)
|
|
_len_0 = _len_0 + 1
|
|
end
|
|
return _accum_0
|
|
end)())
|
|
end
|
|
end
|
|
return chat
|
|
]=],
|
|
['device'] = [[local Device = {}
|
|
|
|
Device.DEBUG_NUM_CALLS = { read = {}, write = {}}
|
|
|
|
Device.__index = function(self, k)
|
|
if type(k) == "number" then
|
|
Device.DEBUG_NUM_CALLS.read[self.device_num or self] = (Device.DEBUG_NUM_CALLS.read[self.device_num or self] or 0) + 1
|
|
|
|
local value = self.portdata[k] or 0
|
|
local port = self.ports[k]
|
|
if port then
|
|
if port.onread then
|
|
value = port.onread(self)
|
|
if port.byte == "high" then
|
|
value = bit.rshift(value, 8)
|
|
end
|
|
end
|
|
end
|
|
return bit.band(value, 0xff)
|
|
elseif Device[k] then
|
|
return Device[k]
|
|
end
|
|
end
|
|
|
|
function Device:readShort(port)
|
|
return bit.lshift(self[port], 8) + self[port+1]
|
|
end
|
|
|
|
function Device:writeShort(port, short)
|
|
-- Write the low byte first since onwrite only triggers on the high byte
|
|
self[port+1] = bit.band(short, 0xff)
|
|
self[port] = bit.band(bit.rshift(short, 8), 0xff)
|
|
end
|
|
|
|
Device.__newindex = function(self, k, v)
|
|
if type(k) == "number" then
|
|
--Device.DEBUG_NUM_CALLS.write[self.device_num or self] = (Device.DEBUG_NUM_CALLS.write[self.device_num or self] or 0) + 1
|
|
self.portdata[k] = v
|
|
local port = self.ports[k]
|
|
if port then
|
|
-- Ignore write triggers for the low byte of a short
|
|
if port.onwrite and port.byte ~= "low" then
|
|
return port.onwrite(self, v)
|
|
end
|
|
end
|
|
-- If there's no handlers attached to this port, just store the value
|
|
if not (port and (port.onwrite or port.onread)) then
|
|
-- Cache the result
|
|
rawset(self, k, v)
|
|
end
|
|
else
|
|
return rawset(self, k, v)
|
|
end
|
|
end
|
|
|
|
function Device:new(devicenum)
|
|
local device = setmetatable({
|
|
ports = {},
|
|
portdata = {},
|
|
}, self)
|
|
|
|
-- Add vector port by default
|
|
device:addPort(0, true, false, function(self, value)
|
|
self.cpu.vectors[self.device_num] = self:readShort(0)
|
|
end)
|
|
|
|
return device
|
|
end
|
|
|
|
function Device:addPort(num, short, read, write)
|
|
if short then
|
|
self.ports[num] = {byte="high", onread=read, onwrite=write}
|
|
self.ports[num+1] = {byte="low", onread=read, onwrite=write}
|
|
else
|
|
self.ports[num] = {byte="single", onread=read, onwrite=write}
|
|
end
|
|
end
|
|
|
|
function Device:trigger()
|
|
self.cpu:triggerDevice(self.device_num)
|
|
end
|
|
|
|
return Device
|
|
]],
|
|
['uxn'] = [[local bit = require "bit"
|
|
local math = require "math"
|
|
|
|
local band, bor, bxor, bnot = bit.band, bit.bor, bit.bxor, bit.bnot
|
|
local arshift, rshift, lshift = bit.arshift, bit.rshift, bit.lshift
|
|
|
|
local function uint8_to_int8(byte)
|
|
byte = band(byte, 0xff)
|
|
if band(byte, 0x80) ~= 0 then
|
|
byte = byte - 0x100
|
|
end
|
|
|
|
return byte
|
|
end
|
|
|
|
local Stack = {}
|
|
|
|
Stack.__index = Stack
|
|
|
|
function Stack:new(limit)
|
|
local limit = limit or 256
|
|
return setmetatable({
|
|
limit = limit,
|
|
head = 0,
|
|
}, self)
|
|
end
|
|
|
|
function Stack:push(byte)
|
|
local head = self.head + 1
|
|
self[head] = byte
|
|
self.head = head
|
|
end
|
|
|
|
function Stack:pop()
|
|
local head = self.head
|
|
local byte = self[head]
|
|
self.head = head - 1
|
|
return byte
|
|
end
|
|
|
|
function Stack:check(n)
|
|
local new = self.head + n
|
|
return new >= 0 and new <= self.limit
|
|
end
|
|
|
|
-- 0-indexed non-destructive get
|
|
function Stack:getnth(n)
|
|
return self[self.head - n]
|
|
end
|
|
|
|
function Stack:len()
|
|
return self.head
|
|
end
|
|
|
|
function Stack:debug()
|
|
local t = {}
|
|
for i = 1, self.head do
|
|
t[#t + 1] = bit.tohex(self[i], 2)
|
|
end
|
|
return table.concat(t, " ")
|
|
end
|
|
|
|
local Memory = {
|
|
__index = function(self, k)
|
|
if type(k) == "number" then
|
|
-- Uninitialized memory should be randomized for robust testing
|
|
if self.ERROR_ON_UNINITIALIZED_READ then
|
|
error("READ UNINITIALIZED MEMORY @ "..bit.tohex(k))
|
|
end
|
|
return 0 --love.math.random(255)
|
|
end
|
|
end
|
|
}
|
|
|
|
local Uxn = {}
|
|
|
|
Uxn.__index = Uxn
|
|
|
|
function Uxn:new(mem)
|
|
return setmetatable({
|
|
ip = 1,
|
|
program_stack = Stack:new(),
|
|
return_stack = Stack:new(),
|
|
memory = setmetatable(mem or {}, Memory),
|
|
devices = {},
|
|
vectors = {},
|
|
-- DEBUG TABLES
|
|
debug_profile = {},
|
|
device_triggers = {}, -- Debug
|
|
device_reads = {}, -- DEBUG
|
|
device_writes = {}, -- DEBUG
|
|
}, self)
|
|
end
|
|
|
|
function Uxn:profile(...)
|
|
local name = table.concat({...}, "_")
|
|
self.debug_profile[name] = (self.debug_profile[name] or 0) + 1
|
|
end
|
|
|
|
function Uxn:print_profile()
|
|
local output = "name\t\tcount\n"
|
|
for k,v in pairs(self.debug_profile) do
|
|
output = output .. k.."\t\t"..v.."\n"
|
|
end
|
|
return output
|
|
end
|
|
|
|
function bytes_to_shorts(bytes)
|
|
local shorts = {}
|
|
for i = 1, #bytes, 2 do
|
|
local high_byte = bytes[i]
|
|
local low_byte = bytes[i+1]
|
|
shorts[#shorts + 1] = band(lshift(high_byte, 8) + low_byte, 0xffff)
|
|
end
|
|
return shorts
|
|
end
|
|
|
|
function bytes_to_short(high, low)
|
|
if not low then
|
|
low = high[2]
|
|
high = high[1]
|
|
end
|
|
return band(lshift(high, 8) + low, 0xffff)
|
|
end
|
|
|
|
function shorts_to_bytes(shorts)
|
|
local bytes = {}
|
|
|
|
for i = 1, #shorts do
|
|
local short = shorts[i]
|
|
local high_byte = rshift(short, 8)
|
|
-- Mask out the low byte
|
|
local low_byte = band(short, 0xff)
|
|
bytes[#bytes + 1] = high_byte
|
|
bytes[#bytes + 1] = low_byte
|
|
end
|
|
|
|
return bytes
|
|
end
|
|
|
|
function Uxn:get_n(n, keep_bit, return_bit, short_bit)
|
|
-- Choose which stack to operate on
|
|
local stack = return_bit and self.return_stack or self.program_stack
|
|
|
|
-- Fetch 2 bytes for each number needed
|
|
if short_bit then n = n * 2 end
|
|
|
|
-- Make sure the stack has enough space to fetch n bytes
|
|
if not stack:check(-n) then
|
|
error("Stack not big enough to get "..tostring(n).." bytes")
|
|
end
|
|
|
|
local output = {}
|
|
|
|
for i = 1, n do
|
|
if keep_bit then
|
|
output[(n - i) + 1] = stack:getnth(i-1)
|
|
else
|
|
output[(n - i) + 1] = stack:pop()
|
|
end
|
|
end
|
|
|
|
if short_bit then
|
|
output = bytes_to_shorts(output)
|
|
end
|
|
|
|
return output
|
|
end
|
|
|
|
function Uxn:push(value, k, r, s)
|
|
local stack = r and self.return_stack or self.program_stack
|
|
--assert(stack:check(1 + (s and 1 or 0)), "Can't push", value, "k", k, "r", r, "s", s)
|
|
|
|
if stack.head > 0xfe then
|
|
error(r and 'return stack overflow' or 'working stack overflow')
|
|
end
|
|
if s then
|
|
stack:push(band(rshift(value, 8), 0xff))
|
|
end
|
|
stack:push(band(value, 0xff))
|
|
end
|
|
|
|
function Uxn:pop(k, r, s)
|
|
local stack = r and self.return_stack or self.program_stack
|
|
local value
|
|
if k then
|
|
local offset = self.peek_offset
|
|
if s then
|
|
local low = stack:getnth(offset)
|
|
local high = stack:getnth(offset+1)
|
|
value = low and high and bytes_to_short(high, low)
|
|
offset = offset + 2
|
|
else
|
|
value = stack:getnth(offset)
|
|
offset = offset + 1
|
|
end
|
|
self.peek_offset = offset
|
|
else
|
|
if s then
|
|
local low = stack:pop()
|
|
local high = stack:pop()
|
|
value = low and high and bytes_to_short(high, low)
|
|
else
|
|
value = stack:pop()
|
|
end
|
|
end
|
|
if not value then
|
|
error(r and 'return stack underflow' or 'working stack underflow')
|
|
end
|
|
return value
|
|
end
|
|
|
|
local function extractOpcode(byte)
|
|
local keep_bit = band(byte, 0x80) ~= 0 -- 0b1000 0000
|
|
local return_bit = band(byte, 0x40) ~= 0 -- 0b0100 0000
|
|
local short_bit = band(byte, 0x20) ~= 0 -- 0b0010 0000
|
|
|
|
local opcode = band(byte, 0x1f) -- 0b0001 1111
|
|
|
|
return opcode, keep_bit, return_bit, short_bit
|
|
end
|
|
|
|
function Uxn:device_read(addr, k, r, s)
|
|
local device_num = rshift(addr, 4)
|
|
local device = self.devices[device_num]
|
|
|
|
if device then
|
|
self.device_reads[device_num] = (self.device_reads[device_num] or 0) + 1
|
|
local port = band(addr, 0x0f)
|
|
|
|
local value
|
|
if s then
|
|
value = device:readShort(port)
|
|
else
|
|
value = band(device[port], 0xff)
|
|
end
|
|
|
|
return value
|
|
else
|
|
return 0
|
|
end
|
|
end
|
|
|
|
function Uxn:device_write(addr, value, k, r, s)
|
|
local device_num = rshift(addr, 4)
|
|
local device = self.devices[device_num]
|
|
|
|
local port_num = band(addr, 0x0f)
|
|
|
|
if device then
|
|
--self:profile("DEO", device_num, port_num)
|
|
self.device_writes[device_num] = (self.device_writes[device_num] or 0) + 1
|
|
if self.PRINT then print("wrote", bit.tohex(value), "to", bit.tohex(addr)) end
|
|
|
|
if s then
|
|
device:writeShort(port_num, value)
|
|
else
|
|
device[port_num] = value
|
|
end
|
|
end
|
|
end
|
|
|
|
function Uxn:addDevice(device_num, device)
|
|
if self.devices[device_num] then
|
|
error("Device already exists at ", bit.tohex(device_num))
|
|
end
|
|
|
|
device.cpu = self
|
|
device.device_num = device_num
|
|
|
|
self.devices[device_num] = device
|
|
|
|
return device
|
|
end
|
|
|
|
function Uxn:triggerDevice(device_num)
|
|
local vector = self.vectors[device_num]
|
|
--local vector = self.devices[device_num]:readShort(0)
|
|
if vector then
|
|
self.device_triggers[device_num] = (self.device_triggers[device_num] or 0) + 1
|
|
self.ip = vector
|
|
return self:runUntilBreak()
|
|
end
|
|
end
|
|
|
|
local opNames = {
|
|
[0] = "LIT",
|
|
"INC",
|
|
"POP",
|
|
"DUP",
|
|
"NIP",
|
|
"SWAP",
|
|
"OVER",
|
|
"ROT",
|
|
|
|
"EQU",
|
|
"NEQ",
|
|
"GTH",
|
|
"LTH",
|
|
"JMP",
|
|
"JCN",
|
|
"JSR",
|
|
"STASH",
|
|
|
|
"LDZ",
|
|
"STZ",
|
|
"LDR",
|
|
"STR",
|
|
"LDA",
|
|
"STA",
|
|
"DEI",
|
|
"DEO",
|
|
|
|
"ADD",
|
|
"SUB",
|
|
"MUL",
|
|
"DIV",
|
|
"AND",
|
|
"OR",
|
|
"XOR",
|
|
"SHIFT",
|
|
}
|
|
|
|
local opTable = {
|
|
-- STACK
|
|
--
|
|
-- 0x00 JCI/JMI/JSI/LIT
|
|
function(self, k, r, s)
|
|
local value
|
|
if k then -- LIT2?r?
|
|
if s then
|
|
value = bytes_to_short(self.memory[self.ip], self.memory[self.ip+1])
|
|
else
|
|
value = self.memory[self.ip]
|
|
end
|
|
if self.PRINT then print("Push "..(s and "short" or "byte").." value = ",bit.tohex(value)) end
|
|
self:push(value, k, r, s)
|
|
self.ip = self.ip + (s and 2 or 1)
|
|
else
|
|
value = bytes_to_short(self.memory[self.ip], self.memory[self.ip+1])
|
|
self.ip = self.ip + 2
|
|
if not r then -- JCI
|
|
if self:pop(false, false, false) == 0 then return end
|
|
elseif r and s then -- JSI
|
|
self:push(self.ip, false, true, true)
|
|
end
|
|
self.ip = self.ip + value
|
|
end
|
|
end,
|
|
|
|
-- 0x01 INC
|
|
function(self, k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(a + 1, k, r, s)
|
|
end,
|
|
|
|
-- 0x02 POP
|
|
function(self, k, r, s)
|
|
self:pop(k, r, s)
|
|
end,
|
|
|
|
-- 0x03 NIP
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
self:pop(k, r, s)
|
|
self:push(b, k, r, s)
|
|
end,
|
|
|
|
-- 0x04 SWAP
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(b, k, r, s)
|
|
self:push(a, k, r, s)
|
|
end,
|
|
|
|
-- 0x05 ROT
|
|
function(self, k, r, s)
|
|
local c = self:pop(k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(b, k, r, s)
|
|
self:push(c, k, r, s)
|
|
self:push(a, k, r, s)
|
|
end,
|
|
|
|
-- 0x06 DUP
|
|
function(self, k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(a, k, r, s)
|
|
self:push(a, k, r, s)
|
|
end,
|
|
|
|
-- 0x07 OVER
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(a, k, r, s)
|
|
self:push(b, k, r, s)
|
|
self:push(a, k, r, s)
|
|
end,
|
|
|
|
|
|
-- LOGIC
|
|
--
|
|
-- 0x08 EQU
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
-- Push the flag as a single byte, so short mode is false in Uxn:push
|
|
self:push(a == b and 1 or 0, k, r, false)
|
|
end,
|
|
|
|
-- 0x09 NEQ
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(a ~= b and 1 or 0, k, r, false)
|
|
end,
|
|
|
|
-- 0x0a GTH
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(a > b and 1 or 0, k, r, false)
|
|
end,
|
|
|
|
-- 0x0b LTH
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(a < b and 1 or 0, k, r, false)
|
|
end,
|
|
|
|
-- 0x0c JMP
|
|
function(self, k, r, s)
|
|
local addr = self:pop(k, r, s)
|
|
if not s then
|
|
-- relative jump
|
|
addr = uint8_to_int8(addr) + self.ip
|
|
end
|
|
|
|
self.ip = addr
|
|
end,
|
|
|
|
-- 0x0d JCN
|
|
function(self, k, r, s)
|
|
local addr = self:pop(k, r, s)
|
|
local flag = self:pop(k, r, false)
|
|
|
|
if flag ~= 0 then
|
|
if not s then
|
|
addr = self.ip + uint8_to_int8(addr)
|
|
end
|
|
|
|
self.ip = addr
|
|
end
|
|
end,
|
|
|
|
-- 0x0e JSR
|
|
function(self, k, r, s)
|
|
local addr = self:pop(k, r, s)
|
|
if not s then
|
|
addr = uint8_to_int8(addr) + self.ip
|
|
end
|
|
|
|
-- Stash
|
|
self:push(self.ip, k, not r, true)
|
|
|
|
self.ip = addr
|
|
end,
|
|
|
|
-- 0x0f STH
|
|
function(self, k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(a, k, not r, s)
|
|
end,
|
|
|
|
-- MEMORY
|
|
--
|
|
-- 0x10 LDZ
|
|
function(self, k, r, s)
|
|
local offset = self:pop(k, r, false)
|
|
|
|
local value = self.memory[offset]
|
|
|
|
if s then
|
|
value = lshift(value, 8) + self.memory[offset + 1]
|
|
end
|
|
|
|
self:push(value, k, r, s)
|
|
end,
|
|
|
|
-- 0x11 STZ
|
|
function(self, k, r, s)
|
|
local data = self:get_n(s and 3 or 2, k, r, false)
|
|
|
|
local offset = table.remove(data)
|
|
|
|
self.memory[offset] = data[1]
|
|
|
|
if s then
|
|
self.memory[offset+1] = data[2]
|
|
end
|
|
end,
|
|
|
|
-- 0x12 LDR
|
|
function(self, k, r, s)
|
|
local offset = self:pop(k, r, false)
|
|
|
|
local addr = uint8_to_int8(offset) + self.ip
|
|
|
|
local value = self.memory[addr]
|
|
|
|
if s then
|
|
value = lshift(value, 8) + self.memory[addr+1]
|
|
end
|
|
|
|
self:push(value, k, r, s)
|
|
end,
|
|
|
|
-- 0x13 STR
|
|
function(self, k, r, s)
|
|
local data = self:get_n(s and 3 or 2, k, r, false)
|
|
|
|
local address = uint8_to_int8(table.remove(data)) + self.ip
|
|
|
|
self.memory[address] = data[1]
|
|
|
|
if s then
|
|
self.memory[address+1] = data[2]
|
|
end
|
|
end,
|
|
|
|
-- 0x14 LDA
|
|
function(self, k, r, s)
|
|
local addr = self:pop(k, r, true)
|
|
|
|
local value = self.memory[addr]
|
|
|
|
if s then
|
|
value = lshift(value, 8) + self.memory[addr+1]
|
|
end
|
|
|
|
self:push(value, k, r, s)
|
|
end,
|
|
|
|
-- 0x15 STA
|
|
function(self, k, r, s)
|
|
local data = self:get_n(s and 4 or 3, k, r, false)
|
|
|
|
local address = bytes_to_short(data[#data-1], data[#data])
|
|
|
|
self.memory[address] = data[1]
|
|
|
|
if s then
|
|
self.memory[address+1] = data[2]
|
|
end
|
|
end,
|
|
|
|
|
|
-- 0x16 DEI
|
|
function(self, k, r, s)
|
|
local offset = self:pop(k, r, false)
|
|
self:push(self:device_read(offset, k, r, s), k, r, s)
|
|
end,
|
|
|
|
|
|
-- 0x17 DEO
|
|
function(self, k, r, s)
|
|
local address = self:pop(k, r, false)
|
|
local value = self:pop(k, r, s)
|
|
|
|
self:device_write(address, value, k, r, s)
|
|
end,
|
|
|
|
|
|
-- ARITHMETIC
|
|
--
|
|
-- 0x18 ADD
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(a + b, k, r, s)
|
|
end,
|
|
|
|
-- 0x19 SUB
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(a - b, k, r, s)
|
|
end,
|
|
|
|
-- 0x1a MUL
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(a * b, k, r, s)
|
|
end,
|
|
|
|
-- 0x1b DIV
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
assert(b ~= 0, "Can't divide by zero!")
|
|
self:push(math.floor(a / b), k, r, s)
|
|
end,
|
|
|
|
-- 0x1c AND
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(band(a, b), k, r, s)
|
|
end,
|
|
|
|
-- 0x1d OR
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(bor(a, b), k, r, s)
|
|
end,
|
|
|
|
-- 0x1e EOR
|
|
function(self, k, r, s)
|
|
local b = self:pop(k, r, s)
|
|
local a = self:pop(k, r, s)
|
|
self:push(bxor(a, b), k, r, s)
|
|
end,
|
|
|
|
-- 0x1f SFT
|
|
-- "Shift in short mode expects a single byte"
|
|
function(self, k, r, s)
|
|
local amount = self:pop(k, r, false)
|
|
local value = self:pop(k, r, s)
|
|
|
|
value = arshift(value, band(amount, 0x0f))
|
|
value = lshift(value, rshift(band(amount, 0xf0), 4))
|
|
|
|
self:push(value, k, r, s)
|
|
end,
|
|
}
|
|
|
|
function Uxn:runUntilBreak()
|
|
local count = 0
|
|
local extractOpcode = extractOpcode
|
|
local memory = self.memory
|
|
while true do
|
|
local opline
|
|
local opByte = memory[self.ip]
|
|
if opByte == 0 then break end
|
|
if self.PRINT then
|
|
opline = bit.tohex(self.ip)
|
|
end
|
|
self.ip = self.ip + 1
|
|
|
|
local opcode, k, r, s = extractOpcode(opByte)
|
|
--self:profile(opNames[opcode])
|
|
if self.PRINT then
|
|
print(opline.." : "..opNames[opcode]..(s and "2" or "")..(r and "r" or "")..(k and "k" or ""))
|
|
print("PS", self.program_stack:debug())
|
|
print("RS", self.return_stack:debug())
|
|
end
|
|
-- Reset the peek offset so consective calls to :pop maintain state
|
|
if k then self.peek_offset = 0 end
|
|
opTable[opcode+1](self, k, r, s)
|
|
self.ip = self.ip % 0x10000
|
|
|
|
count = count + 1
|
|
if count > 1000000 then
|
|
error 'uxnbot got bored with all the looping'
|
|
end
|
|
end
|
|
return count
|
|
end
|
|
|
|
return {Uxn = Uxn, uint8_to_int8 = uint8_to_int8}
|
|
]],
|
|
}
|
|
_G.require = function (module_name)
|
|
if source[module_name] then
|
|
if not loaded[module_name] then
|
|
retval[module_name] = assert(loadstring(source[module_name]))()
|
|
loaded[module_name] = true
|
|
end
|
|
return retval[module_name]
|
|
else
|
|
return orig_require(module_name)
|
|
end
|
|
end
|
|
end
|
|
local chat = require('chat')
|
|
print('uxnrepl (ctrl-d to quit)')
|
|
local prompt
|
|
prompt = function()
|
|
io.write('> ')
|
|
return io.flush()
|
|
end
|
|
prompt()
|
|
for l in io.stdin:lines() do
|
|
print(chat(l))
|
|
prompt()
|
|
end
|
|
return print('bye!')
|