Skip to content

Instantly share code, notes, and snippets.

@nullsauce
Created April 5, 2012 07:20
Show Gist options
  • Save nullsauce/2308725 to your computer and use it in GitHub Desktop.
Save nullsauce/2308725 to your computer and use it in GitHub Desktop.
DCPU-16
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <flavio.roth@gmail.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return.
# ----------------------------------------------------------------------------
#
###
A minimal CoffeeScript implementation of Notch's DCPU-16.
Only the instruction required to run Notch's example were implemented.
See http://0x10c.com/doc/dcpu-16.txt for specification.
###
class DCPU
@instructions =
["NONBASIC","SET", "ADD", "SUB", "MUL", "DIV", "MOD", "SHL", "SHR", "AND", "BOR", "XOR", "IFE", "IFN", "IFG", "IFB"]
constructor:->
@mem = new Uint16Array 0x20000
@reg = new Uint16Array ["a","b","c","x","y","z","i","j"].length
@pc = 0
@sp = 0
@ov = 0
next:->
@mem[@pc++]
getValue:(val)->
if val >= 0x00 && val <= 0x07 # register[ i ]
return (q)=>
@reg[val] = q if q? # set
return @reg[val] # get
else if val >= 0x08 && val <= 0x0f # mem[ reg ]
return (q)=>
@mem[@reg[val-0x08]] = q if q? #set
return @mem[@reg[val-0x08]] #get
else if val >= 0x10 && val <= 0x17
offset = @next()
return (q)=>
@mem[@reg[val-0x10]+offset] = q if q? # set
return @mem[@reg[val-0x10]+offset] # get
else if val == 0x1a # push
return ()=>
return @mem[--@sp]
else if val == 0x18 # pop
return ()=>
return @mem[@sp++]
else if val == 0x1c # pc
return (q)=>
@pc = q if q? # set
return @pc # get
else if val == 0x1e # next word ptr
ptr = @next()
return (q)=>
@mem[ptr] = q if q? # set
return @mem[ptr] # get
else if val == 0x1f # next word value, readonly
v = @next()
return ()=>
return v
else if val >= 0x20 && val <= 0x3f # immediate value, readonly
return ()=>
return val - 0x20 # get
else
throw "Unknown value type #{hex(val)}"
fetch:->
instruction = @next()
opcode = instruction & 0x0F
a = (instruction & 0x3F0) >> 4
b = (instruction & 0xFC00) >> 10
ma = @getValue a
mb = @getValue b
[opcode, a, b, ma, mb]
process:->
[opcode, a, b, ma, mb] = @fetch()
if opcode != 0 #basic
switch opcode
when 0x01 # SET
ma(mb())
when 0x02 # ADD
res = ma() + mb()
if res > 0xFFFF # overflow
@ov = 0x0001
res = res & 0xFFFF
else
@ov = 0x00
ma(res)
when 0x03 # SUB
res = ma() - mb()
if res < 0 # underflow
@ov = 0xFFFF
res = res & 0xFFFF
else
@ov = 0x00
ma(res)
when 0x07# SHL
ma(ma() << mb())
when 0x0A # BOR
ma(ma() | mb())
when 0x0d # IFN
if ma() == mb()
@fetch() # skip next instruction
else
throw "Unknown basic opcode #{hex(opcode)}"
else #non-basic
opcode = a
ma = mb
switch opcode
when 0x01 # JSR
@mem[@sp--]
@pc = ma()
else
throw "Unknown non-basic opcode #{hex(opcode)}"
cpu = new DCPU
cpu.mem.set [
0x7c01, 0x0030, 0x7de1, 0x1000, 0x0020, 0x7803, 0x1000, 0xc00d,
0x7dc1, 0x001a, 0xa861, 0x7c01, 0x2000, 0x2161, 0x2000, 0x8463,
0x806d, 0x7dc1, 0x000d, 0x9031, 0x7c10, 0x0018, 0x7dc1, 0x001a,
0x9037, 0x61c1, 0x7dc1, 0x001a, 0x0000, 0x0000, 0x0000, 0x0000
]
cpu.process() while true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment