Created
April 5, 2012 07:20
-
-
Save nullsauce/2308725 to your computer and use it in GitHub Desktop.
DCPU-16
This file contains 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
# | |
# ---------------------------------------------------------------------------- | |
# "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