Advertisement
osmarks

PotatoASM

Jul 25th, 2020 (edited)
1,289
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.21 KB | None | 0 0
  1. local function fill_arr(length, with)
  2.     local t = {}
  3.     for i = 1, length do
  4.         t[i] = 0
  5.     end
  6.     return t
  7. end
  8.  
  9. --[[
  10. registers are 16 bits
  11. registers 0 to 15 are r0 to rf
  12. register 0 always contains 0 because this makes many things more elegant
  13. register 15 is additionally the program counter because why not
  14. ]]
  15.  
  16. local function init(code)
  17.     -- preallocate 64KiB of memory
  18.     -- 64KiB is enough for anyone
  19.     -- (TODO: allow moar somehow?)
  20.     local memory = fill_arr(65536, 0)
  21.     -- load code into memory, at start
  22.     for i = 1, #code do
  23.         memory[i] = code:byte(i)
  24.     end
  25.     return {
  26.         memory = memory,
  27.         registers = fill_arr(16, 0)
  28.     }
  29. end
  30.  
  31. --[[
  32. instructions (everything >8 bits is big endian):
  33. HALT - 00 - halt execution
  34. NOP  - 01 - do nothing
  35. PEEK - 02 [register 1][register 2] [16-bit constant] - load value at (constant + ri2) in memory into ri1
  36. POKE - 03 [register 1][register 2] [16-bit constant] - ↑ but other way round
  37. ADD  - 04 [register 1][register 2] [16-bit constant] - save (constant + ri2) to ri1
  38. JEQ  - 05 [register 1][register 2] [16-bit constant] - set program counter to constant if ri1 = ri2
  39. JNE  - 06 [register 1][register 2] [16-bit constant] - set program counter to constant if ri1 != ri2
  40. JLT  - 07 [register 1][register 2] [16-bit constant] - set program counter to constant if ri1 < ri2
  41. SUB  - 08 [register 1][register 2] [16-bit constant] - save (ri2 - constant) to ri1
  42. MUL  - 09 [register 1][register 2] [16-bit constant] - save (ri2 * constant) to ri1
  43. DIV  - 10 [register 1][register 2] [16-bit constant] - save (ri2 / constant) to ri1
  44. MOD  - 11 [register 1][register 2] [16-bit constant] - save (ri2 % constant) to ri1
  45. SYSC - 12 something whatever TODO
  46.  
  47. TODO: bitops, syscalls
  48.  
  49. Integers are always unsigned because negative numbers are hard.
  50. ]]
  51.  
  52. local band = bit.band
  53. local brshift = bit.brshift
  54.  
  55. local function hi_nybble(x) return brshift(x, 4) end
  56. local function lo_nybble(x) return band(x, 0xF) end
  57. local function u16from(hi, lo) return hi * 0x100 + lo end
  58. local function truncate(x) return band(0xFFFF, x) end
  59. local function u16_add(x, y) return truncate(x + y) end
  60. local function u16_sub(x, y) return truncate(x - y) end
  61. local function u16_div(x, y) return truncate(x / y) end
  62. local function u16_mod(x, y) return truncate(x % y) end
  63. local function u16to(x) return brshift(x, 8), band(x, 0xFF) end
  64.  
  65. local function step(state)
  66.     local function get_reg(ix)
  67.         if ix == 0 then return 0
  68.         else return state.registers[ix + 1] end
  69.     end
  70.     local function set_reg(ix, x) if ix ~= 0 then state.registers[ix + 1] = x end end
  71.     local function get_mem(pos)
  72.         return u16from(state.memory[pos + 1], state.memory[pos  + 2])
  73.     end
  74.     local function set_mem(pos, x)
  75.         local b1, b2 = u16to(x)
  76.         state.memory[pos + 1] = b1
  77.         state.memory[pos + 2] = b2
  78.     end
  79.  
  80.     local bpos = state.registers[16]
  81.     -- read four bytes from program counter location onward
  82.     local b1, b2, b3, b4 = unpack(state.memory, bpos + 1, bpos + 5)
  83.  
  84.     -- increment program counter
  85.     state.registers[16] = bpos + 4
  86.     if state.registers[16] > #state.memory then
  87.         return false
  88.     end
  89.  
  90.     -- HALT
  91.     if b1 == 0x00 then
  92.         return false
  93.     -- NOP
  94.     elseif b1 == 0x01 then
  95.         -- do nothing whatsoever
  96.         -- still doing nothing
  97.     -- PEEK
  98.     elseif b1 == 0x02 then
  99.         -- calculate address - sum constant + provided register value
  100.         local addr = u16_add(u16from(b3, b4), get_reg(lo_nybble(b2)))
  101.         set_reg(hi_nybble(b2), get_mem(addr))
  102.     -- POKE
  103.     elseif b1 == 0x03 then
  104.         local addr = u16_add(u16from(b3, b4), get_reg(lo_nybble(b2)))
  105.         set_mem(addr, get_reg(hi_nybble(b2)))
  106.     -- ADD
  107.     elseif b1 == 0x04 then
  108.         set_reg(hi_nybble(b2), u16_add(u16from(b3, b4), get_reg(lo_nybble(b2))))
  109.     -- JEQ
  110.     elseif b1 == 0x05 then
  111.         if get_reg(hi_nybble(b2)) == get_reg(lo_nybble(b2)) then
  112.             state.registers[16] = u16from(b3, b4)
  113.         end
  114.     -- JNE - maybe somehow factor out the logic here, as it's very close to JEQ
  115.     elseif b1 == 0x06 then
  116.         if get_reg(hi_nybble(b2)) ~= get_reg(lo_nybble(b2)) then
  117.             state.registers[16] = u16from(b3, b4)
  118.         end
  119.     -- JLT - see JNE
  120.     elseif b1 == 0x07 then
  121.         if get_reg(hi_nybble(b2)) < get_reg(lo_nybble(b2)) then
  122.             state.registers[16] = u16from(b3, b4)
  123.         end
  124.     -- SUB
  125.     elseif b1 == 0x08 then
  126.         set_reg(hi_nybble(b2), u16_sub(get_reg(lo_nybble(b2)), u16from(b3, b4)))
  127.     -- MUL
  128.     elseif b1 == 0x09 then
  129.         set_reg(hi_nybble(b2), u16_mul(u16from(b3, b4), get_reg(lo_nybble(b2))))
  130.     -- DIV
  131.     elseif b1 == 0x10 then
  132.         set_reg(hi_nybble(b2), u16_div(get_reg(lo_nybble(b2)), u16from(b3, b4)))
  133.     -- MOD
  134.     elseif b1 == 0x11 then
  135.         set_reg(hi_nybble(b2), u16_mod(get_reg(lo_nybble(b2)), u16from(b3, b4)))
  136.     -- TEST
  137.     elseif b1 == 0xFF then
  138.         for i, v in ipairs(state.registers) do
  139.             print(("r%x: %04x"):format(i - 1, v))
  140.         end
  141.     else
  142.         error(("illegal opcode %02x at %04x"):format(b1, state.registers[16]))
  143.     end
  144.  
  145.     return true
  146. end
  147.  
  148. local function unhexize(s)
  149.     local s = s:gsub("[^0-9A-Fa-f]", "")
  150.     local out = {}
  151.     for i = 1, #s, 2 do
  152.         local pair = s:sub(i, i + 1)
  153.         table.insert(out, string.char(tonumber(pair, 16)))
  154.     end
  155.     return table.concat(out)
  156. end
  157.  
  158. local state = init(unhexize [[04 b0 00 08
  159. 04 10 01 ff
  160. 04 e0 ff 02
  161. 03 e0 a0 00
  162. 04 de 03 01
  163. 02 c0 a0 00
  164. 02 dd a0 00
  165. ff 00 00 00
  166. 04 44 00 01
  167. 03 40 20 01
  168. 04 aa 00 01
  169. 07 ab 00 00]])
  170.  
  171. while step(state) do end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement