From cacf4f6f3718b02ceda977e4f3255d0a36c86c50 Mon Sep 17 00:00:00 2001 From: d_m Date: Fri, 20 Jan 2023 10:23:53 -0500 Subject: [PATCH] add uxnbot code --- uxnbot.lua | 1215 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1215 insertions(+) create mode 100644 uxnbot.lua diff --git a/uxnbot.lua b/uxnbot.lua new file mode 100644 index 0000000..a055059 --- /dev/null +++ b/uxnbot.lua @@ -0,0 +1,1215 @@ +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, 120, 53, 160, 3, 177, 46, 160, 7, 76, 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, 74, 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, 76, 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, 78, + 160, 5, 93, 53, 160, 5, 97, 52, 29, 128, 7, 13, 160, 7, 95, 160, 5, 93, 53, + 160, 5, 95, 52, 160, 4, 57, 46, 160, 5, 99, 52, 29, 128, 29, 13, 160, 7, + 74, 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, 120, 52, 160, 12, 215, 57, 160, 3, 123, 46, 160, 2, 170, 160, 3, + 108, 46, 160, 224, 0, 160, 7, 120, 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, 193, 21, 160, 66, 2, 30, 160, + 6, 207, 21, 160, 130, 2, 30, 160, 6, 219, 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, 74, 53, 160, 1, 0, 6, 38, 160, 5, 89, 53, 160, 5, 77, 21, 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, 67, 46, 85, 128, 8, 13, 111, 160, 5, 85, 53, 35, 52, 44, 34, + 98, 160, 5, 177, 56, 52, 44, 11, 151, 11, 47, 11, 71, 9, 242, 7, 193, 8, + 56, 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, 93, 14, 6, 79, 28, + 128, 61, 13, 38, 160, 0, 4, 42, 128, 53, 13, 157, 128, 0, 8, 128, 46, 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, 12, 13, 192, 64, 127, 128, + 0, 15, 15, 120, 33, 128, 220, 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, 67, 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, 237, 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, 52, 46, 29, 128, 19, 13, 160, 5, 84, 148, 1, 5, 5, 21, 128, 2, + 160, 5, 77, 20, 29, 160, 5, 77, 21, 108, 160, 5, 85, 52, 160, 6, 52, 46, + 29, 128, 243, 13, 160, 5, 84, 148, 128, 1, 25, 6, 36, 21, 128, 230, 13, + 128, 2, 128, 255, 30, 160, 5, 77, 20, 28, 160, 5, 77, 21, 108, 160, 5, 76, + 20, 128, 59, 13, 160, 5, 104, 160, 6, 67, 46, 128, 9, 13, 34, 160, 10, 216, + 160, 5, 99, 53, 108, 160, 7, 120, 52, 36, 53, 160, 0, 0, 160, 7, 131, 46, + 160, 0, 0, 160, 7, 131, 46, 160, 5, 85, 52, 160, 7, 141, 46, 128, 4, 160, + 5, 77, 20, 29, 160, 5, 77, 21, 108, 128, 20, 160, 5, 77, 20, 29, 160, 5, + 77, 21, 108, 160, 5, 77, 20, 128, 16, 28, 128, 8, 13, 160, 5, 85, 52, 160, + 7, 141, 46, 108, 128, 0, 160, 7, 122, 46, 128, 20, 128, 255, 30, 160, 5, + 77, 20, 28, 160, 5, 77, 21, 108, 160, 5, 102, 128, 29, 14, 128, 7, 13, 160, + 0, 0, 160, 7, 131, 46, 160, 0, 2, 56, 160, 5, 108, 53, 108, 160, 5, 108, + 52, 128, 3, 14, 2, 34, 108, 160, 6, 67, 46, 128, 19, 13, 180, 160, 5, 89, + 52, 40, 128, 7, 13, 160, 11, 23, 160, 5, 99, 53, 128, 1, 108, 160, 7, 120, + 52, 36, 53, 160, 0, 0, 160, 7, 131, 46, 160, 0, 0, 160, 7, 131, 46, 160, 5, + 85, 52, 160, 7, 141, 46, 160, 7, 120, 52, 160, 5, 89, 52, 160, 7, 131, 46, + 128, 0, 108, 160, 0, 0, 160, 5, 89, 53, 128, 0, 160, 5, 206, 46, 128, 8, + 13, 160, 10, 114, 160, 5, 99, 53, 108, 160, 6, 238, 44, 160, 5, 85, 52, + 148, 6, 128, 3, 13, 2, 34, 108, 160, 6, 251, 46, 33, 128, 240, 12, 128, + 160, 160, 6, 251, 46, 128, 82, 14, 160, 6, 247, 44, 128, 75, 14, 160, 6, + 229, 46, 128, 1, 13, 108, 160, 5, 76, 20, 128, 0, 8, 160, 5, 99, 52, 29, + 29, 128, 7, 13, 160, 10, 134, 160, 5, 99, 53, 108, 128, 40, 14, 160, 5, 89, + 52, 57, 160, 0, 3, 57, 38, 160, 0, 128, 43, 15, 38, 160, 255, 127, 42, 79, + 29, 128, 9, 13, 34, 160, 10, 159, 160, 5, 99, 53, 108, 160, 6, 229, 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, 67, 46, 15, 36, 38, 128, 47, 5, 5, 21, 79, 128, 18, 13, 33, + 160, 5, 85, 53, 160, 0, 2, 56, 160, 6, 67, 46, 128, 3, 13, 52, 108, 34, 34, + 160, 5, 76, 20, 128, 0, 8, 128, 7, 13, 160, 10, 181, 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, 114, 160, 5, 99, 53, 108, 160, 6, 229, 46, 2, 108, 160, 6, + 251, 46, 2, 108, 128, 160, 160, 6, 251, 46, 160, 6, 247, 44, 160, 6, 119, + 46, 128, 4, 13, 160, 6, 251, 44, 128, 1, 160, 5, 206, 46, 12, 128, 6, 12, + 128, 216, 12, 128, 225, 12, 128, 3, 22, 128, 224, 10, 128, 50, 13, 160, 5, + 104, 160, 6, 67, 46, 128, 31, 13, 148, 128, 2, 13, 34, 108, 166, 160, 6, + 52, 46, 33, 56, 36, 160, 5, 110, 46, 160, 5, 99, 52, 29, 128, 3, 13, 128, + 227, 12, 34, 108, 34, 160, 10, 197, 160, 5, 99, 53, 108, 160, 10, 254, 160, + 5, 99, 53, 108, 128, 3, 22, 128, 224, 10, 128, 239, 13, 160, 7, 120, 52, + 160, 5, 85, 52, 160, 7, 141, 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, 85, 110, 114, 101, 99, 111, 103, 110, 105, 115, + 101, 100, 32, 116, 111, 107, 101, 110, 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, 82, + 101, 99, 117, 114, 115, 105, 111, 110, 32, 108, 101, 118, 101, 108, 32, + 116, 111, 111, 32, 100, 101, 101, 112, 0, 76, 97, 98, 101, 108, 32, 114, + 101, 100, 101, 102, 105, 110, 101, 100, 0, 0, 0, 0, 0, 40, 0, 7, 162, 11, + 39, 0, 0, 41, 0, 7, 194, 0, 0, 0, 0, 40, 0, 7, 174, 11, 55, 0, 0, 41, 0, 7, + 219, 11, 63, 11, 79, 123, 0, 7, 193, 0, 0, 0, 0, 125, 0, 8, 75, 0, 0, 0, 0, + 34, 0, 8, 228, 11, 87, 0, 0, 35, 0, 9, 196, 11, 95, 11, 111, 36, 0, 8, 207, + 0, 0, 0, 0, 37, 0, 7, 234, 11, 103, 11, 135, 38, 0, 8, 121, 0, 0, 0, 0, 40, + 0, 7, 174, 11, 127, 11, 143, 41, 0, 7, 219, 0, 0, 0, 0, 44, 0, 9, 40, 11, + 119, 11, 183, 46, 0, 9, 5, 0, 0, 0, 0, 58, 0, 8, 254, 11, 159, 11, 175, 59, + 0, 8, 248, 0, 0, 0, 0, 64, 0, 8, 96, 11, 167, 11, 199, 123, 0, 7, 193, 0, + 0, 0, 0, 124, 0, 8, 200, 11, 191, 11, 207, 125, 0, 7, 193, 0, 0, 0, 0, 126, + 0, 10, 80, 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 BRK/LIT + function(self, k, r, s) + local value + 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) + 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) + + 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!')