Skip to content

Instantly share code, notes, and snippets.

@nonchip
Last active October 14, 2016 18:00
Show Gist options
  • Save nonchip/80b2971b827d2cd234b3f62848629df0 to your computer and use it in GitHub Desktop.
Save nonchip/80b2971b827d2cd234b3f62848629df0 to your computer and use it in GitHub Desktop.
import RAM, BankSwitcher from require 'ram'
ops=require 'ops'
rom=require 'rom'
eprint=(...)->
for i in *{...}
io.stderr\write i..'\t'
io.stderr\write '\n'
bank1 = RAM!
bank2 = RAM!
bank3 = RAM!
switcher = BankSwitcher { bank1, bank2, bank3 }
regs = { running: true, ip: 0, a: 0, b: 0, c: 0, d: 0 }
eprint 'loading rom:'
da=0
if rom[0]==nil then
eprint 'starts at 1, fixing...'
da=1
for a=0,#rom-da
v=rom[a+da] or 0
eprint '%02X: %02X'\format a, v
bank1\set a, v
bool2tf = (bool) -> bool and 'T' or 'F'
eprint 'RUN\tIP\tOPCODE\tA\tB\tC\tD'
while regs.running and regs.ip < 256
opcode = switcher\get regs.ip
eprint '%s\t%02X\t%02X\t%02X\t%02X\t%02X\t%02X'\format bool2tf(regs.running), regs.ip, opcode,regs.a,regs.b,regs.c,regs.d
op=ops[opcode]
if op
op regs, switcher
else
regs.running=false
eprint '%02X.%02X: INVALID OPCODE %02X'\format switcher\getBank!, regs.ip, opcode
eprint '%s\t%02X\tHALTED\t%02X\t%02X\t%02X\t%02X'\format bool2tf(regs.running), regs.ip,regs.a,regs.b,regs.c,regs.d
bit = require 'bit'
loadRfromR=(t,f)->
(regs,ram) ->
regs[t]=regs[f]
regs.ip+=1
loadRfromV=(t)->
(regs,ram) ->
regs[t]=ram\get regs.ip+1
regs.ip+=2
{
-- 0x0 general
[0x00]: (regs,ram)-> --nop
regs.ip += 1
[0x01]: (regs,ram)-> --halt
regs.running = false
[0x02]: (regs,ram)-> --JMP val
regs.ip=ram\get regs.ip+1
[0x03]: (regs,ram)-> --JMP val if A
if regs.a>0
regs.ip=ram\get regs.ip+1
else
regs.ip=regs.ip+2
[0x04]: (regs,ram)-> --JMP val if !A
if regs.a==0
regs.ip=ram\get regs.ip+1
else
regs.ip=regs.ip+2
[0x05]: (regs,ram)-> --JMP val if A==1
if regs.a==1
regs.ip=ram\get regs.ip+1
else
regs.ip=regs.ip+2
[0x06]: (regs,ram)-> --JMP A
regs.ip=regs.b
[0x07]: (regs,ram)-> --JMP B
regs.ip=regs.b
[0x08]: (regs,ram)-> --JMP B if A
if regs.a>0
regs.ip=regs.b
else
regs.ip=regs.ip+1
[0x09]: (regs,ram)-> --JMP B if !A
if regs.a==0
regs.ip=regs.b
else
regs.ip=regs.ip+1
[0x0a]: (regs,ram)-> --JMP B if A==1
if regs.a==1
regs.ip=regs.b
else
regs.ip=regs.ip+1
-- 0x1 LOAD:
[0x10]: loadRfromV 'a'
[0x11]: loadRfromR 'a', 'b'
[0x12]: loadRfromR 'a', 'c'
[0x13]: loadRfromR 'a', 'd'
[0x14]: loadRfromR 'b', 'a'
[0x15]: loadRfromV 'b'
[0x16]: loadRfromR 'b', 'c'
[0x17]: loadRfromR 'b', 'd'
[0x18]: loadRfromR 'c', 'a'
[0x19]: loadRfromR 'c', 'b'
[0x1a]: loadRfromV 'c'
[0x1b]: loadRfromR 'c', 'd'
[0x1c]: loadRfromR 'd', 'a'
[0x1d]: loadRfromR 'd', 'b'
[0x1e]: loadRfromR 'd', 'c'
[0x1f]: loadRfromV 'd'
-- 0x2 IO:
[0x20]: (regs,ram)-> -- READ A, [val]
regs.a=ram\get ram\get regs.ip+1
regs.ip+=2
[0x21]: (regs,ram)-> -- READ A, [B]
regs.a=ram\get regs.b
regs.ip+=1
[0x22]: (regs,ram)-> -- WRITE [val], A
ram\set ram\get(regs.ip+1), regs.a
regs.ip+=2
[0x23]: (regs,ram)-> -- WRITE [B], A
ram\set regs.b, regs.a
regs.ip+=1
[0x24]: (regs,ram)-> -- READ A, stdin
regs.a=string.byte io.read(1)
regs.ip+=1
[0x25]: (regs,ram)-> -- WRITE stdout, A
io.write(string.char regs.a)
regs.ip+=1
-- 0x3 MATH:
[0x30]: (regs,ram)-> -- ADD A, val
regs.a+=ram\get regs.ip+1
regs.ip+=2
[0x31]: (regs,ram)-> -- ADD A, B
regs.a+=regs.b
regs.ip+=1
[0x32]: (regs,ram)-> -- MUL A, val
regs.a*=ram\get regs.ip+1
regs.ip+=2
[0x33]: (regs,ram)-> -- MUL A, B
regs.a*=regs.b
regs.ip+=1
[0x34]: (regs,ram)-> -- AND A, val
regs.a=bit.band regs.a, ram\get regs.ip+1
regs.ip+=2
[0x35]: (regs,ram)-> -- AND A, B
regs.a=bit.band regs.a, regs.b
regs.ip+=1
[0x36]: (regs,ram)-> -- OR A, val
regs.a=bit.bor regs.a, ram\get regs.ip+1
regs.ip+=2
[0x37]: (regs,ram)-> -- OR A, B
regs.a=bit.bor regs.a, regs.b
regs.ip+=1
[0x38]: (regs,ram)-> -- NOT A
regs.a=bit.bnot regs.a
regs.ip+=1
[0x39]: (regs,ram)-> -- XOR A, val
regs.a=bit.bxor regs.a, ram\get regs.ip+1
regs.ip+=2
[0x3a]: (regs,ram)-> -- XOR A, B
regs.a=bit.bxor regs.a, regs.b
regs.ip+=1
-- 0x4 CMP:
[0x40]: (regs,ram)-> -- A=CMP A, B (0<,1=,2>)
regs.a=((regs.a<regs.b) and 0) or ((regs.a>regs.b) and 2) or 1
regs.ip+=1
[0x41]: (regs,ram)-> -- A=CMP A, val (0<,1=,2>)
v=ram\get regs.ip+1
regs.a=((regs.a<v) and 0) or ((regs.a>v) and 2) or 1
regs.ip+=2
}
ffi = require 'ffi'
class RAM
new: (@size=256, @type='unsigned char') =>
@mem = ffi.new @type..'[?]', @size
get: (addr) =>
return nil, 'out of bounds' if addr < 0 or addr >= @size
tonumber(@mem[addr])
set: (addr, val) =>
return nil, 'out of bounds' if addr < 0 or addr >= @size
@mem[addr] = ffi.cast @type, tonumber(val)
true
class BankSwitcher
new: (@banks,@bank=0) =>
get: (addr) =>
@banks[@bank+1]\get addr
set: (addr, val) =>
@banks[@bank+1]\set addr, val
switch: (@bank) =>
true
getBank: =>
@bank
{ :RAM, :BankSwitcher }
STR= => @byte(1,#@)
{
0x15, 0x13 -- 00: LOAD B, 0x13
0x02, 0x05 -- 02: JMP 0x05
0x01 -- 04: HCF
0x21 -- 05: READ A, [B]
0x18 -- 06: LOAD C, A
0x41, 0x00 -- 07: CMP A, 0
0x05, 0x04 -- 09: =JMP 0x04
0x12 -- 0b: LOAD A, C
0x25 -- 0c: WRITE stdout, A
0x11 -- 0d: LOAD A, B
0x30, 1 -- 0e: ADD A, 1
0x14 -- 10: LOAD B, A
0x02, 0x05 -- 11: JMP 0x05
STR 'Hello World.\n'
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment