Last active
June 30, 2025 20:38
-
-
Save thacuber2a03/fed3d75a0516f42c35831df0334de50d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- an implementation of the Uxn VM in Lua, written by @thacuber2a03 | |
| -- compatible with 5.1 and JIT | |
| -- thanks to @soxfox42 for helping on stack issues with the keep flag | |
| -- and other things | |
| local unpack = table.unpack or unpack | |
| local ram, dev = {}, {} | |
| local wst, rst = {kidx=1,idx=1}, {kidx=1,idx=1} | |
| local function wrap(n, m) | |
| while n > m do n = n - m end | |
| while n < 1 do n = n + m end | |
| return n | |
| end | |
| local function idxwrap(i) return wrap(i, 0x100 ) end | |
| local function addrwrap(a) return wrap(a, 0x10000) end | |
| local function push(stk, v, t) | |
| if stk.kidx then stk.idx, stk.kidx = stk.kidx, nil end | |
| if t then | |
| stk[stk.idx] = (v >> 8) & 0xff | |
| stk.idx = idxwrap(stk.idx + 1) | |
| end | |
| stk[stk.idx] = v & 0xff | |
| stk.idx = idxwrap(stk.idx + 1) | |
| end | |
| local function pop(stk, t) | |
| stk.idx = idxwrap(stk.idx - 1) | |
| local v = stk[stk.idx] & 0xff | |
| if t then | |
| stk.idx = idxwrap(stk.idx - 1) | |
| v = ((stk[stk.idx] & 0xff) << 8) | v | |
| end | |
| return v | |
| end | |
| local function popn(s, t, n) | |
| local r = {} | |
| for i=1, n do r[#r+1] = pop(s,t) end | |
| return unpack(r) | |
| end | |
| local function pushn(s, t, ...) | |
| for _, n in ipairs{...} do push(s, t, n) end | |
| end | |
| local pc | |
| local instrs = { | |
| [0x01] = function(s, t) push(s,t, pop(s,t)+1) end, -- INC | |
| [0x02] = function(s, t) pop(s,t) end, -- POP | |
| [0x03] = function(s, t) local a,b=popn(s,t,2) push (s,t, a) end, -- NIP | |
| [0x04] = function(s, t) local a,b=popn(s,t,2) pushn(s,t, a,b) end, -- SWP | |
| [0x05] = function(s, t) local a,b,c=popn(s,t,3) pushn(s,t, c,a,b) end, -- ROT | |
| [0x18] = function(s, t) local a,b=popn(s,t,2) push(s,t,a+b) end, -- ADD | |
| [0x19] = function(s, t) local a,b=popn(s,t,2) push(s,t,a-b) end, -- SUB | |
| [0x1a] = function(s, t) local a,b=popn(s,t,2) push(s,t,a*b) end, -- MUL | |
| [0x1b] = function(s, t) local a,b=popn(s,t,2) push(s,t,b==0 and 0 or a/b) end, -- DIV | |
| [0x1c] = function(s, t) local a,b=popn(s,t,2) push(s,t,b&a) end, -- AND | |
| [0x1d] = function(s, t) local a,b=popn(s,t,2) push(s,t,b|a) end, -- ORA | |
| [0x1e] = function(s, t) local a,b=popn(s,t,2) push(s,t,b~a) end, -- EOR | |
| [0x1f] = function(s, t) local a,b=popn(s,t,2) push(s,t,b>>(a&0xf)<<(a>>4)) end, -- SFT | |
| } | |
| local function jmi() | |
| local off = ram[pc] << 8 | ram[pc+1] | |
| pc = idxwrap(pc + 2 + off) | |
| end | |
| local function eval(rv) | |
| assert(ram[1], "no program loaded") | |
| pc = addrwrap(rv) | |
| while true do | |
| local byt = ram[addrwrap(pc)] | |
| local ins = byt & 0x1f | |
| local flg = byt & 0xe0 | |
| pc = pc + 1 | |
| local s = wst | |
| if (flg & 0x80) ~= 0 then s = rst end | |
| local t = (flg & 0x40) ~= 0 | |
| local k = (flg & 0x20) ~= 0 | |
| if ins == 0x00 then | |
| if k then -- LIT[2r] | |
| for i=1, t and 1 or 2 do | |
| push(s, false, ram[pc]); pc = pc + 1 | |
| end | |
| elseif byt == 0x40 then jmi() | |
| elseif byt == 0x20 then -- JCI | |
| if pop(wst, false) ~= 0 then jmi() else pc = pc + 2 end | |
| elseif byt == 0x60 then | |
| push(rst, true, pc+2); jmi() -- JSI | |
| else return true end -- BRK | |
| else | |
| if k then s.kidx = s.idx end | |
| instrs[ins](s, t) | |
| s.kidx = nil | |
| end | |
| end | |
| end | |
| local function load(prg) | |
| for i=1, 0x10000 do ram[i] = 0 end | |
| for i=1, 0x100 do dev[i] = 0 end | |
| for i, b in ipairs(prg) do ram[0x100+i] = b end | |
| end | |
| return { | |
| load = load, | |
| eval = eval, | |
| ram = ram, | |
| dev = dev, | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment