nxu/uxnbot.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!')