Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Starting to implement the CPU

  • Loading branch information...
commit 9aa480369204040f232b102133e8bc3b1f6ffef1 1 parent 42b4d1b
Daniel Parnell authored
8  README.md
Source Rendered
... ...
@@ -1,7 +1,7 @@
1 1
 What is this?
2 2
 =============
3 3
 
4  
-This is a simple template for an OTP application.  It is based on one found [here](https://github.com/zpeters/ErlangOtpTemplate) and some information on [StackOverflow](http://stackoverflow.com/questions/1582818/what-tool-do-you-use-to-build-an-erlang-program).
  4
+This is a go at implementing the DCPU-16 processor in the upcoming game [0x10<sup>c</sup>](http://0x10c.com/).
5 5
 
6 6
 Compiling
7 7
 ---------
@@ -12,8 +12,8 @@ Running
12 12
 -------
13 13
 
14 14
     erl -pa ebin
15  
-    application:start(myapp).
16  
-    myapp_server:test_call("Call").
17  
-    myapp_server:test_cast("Cast").
  15
+    application:start(dcpu16).
  16
+    dcpu16_server:test_call("Call").
  17
+    dcpu16_server:test_cast("Cast").
18 18
 
19 19
 
143  doc/dcpu-16.txt
... ...
@@ -0,0 +1,143 @@
  1
+DCPU-16 Specification
  2
+Copyright 2012 Mojang
  3
+Version 1.1 (Check 0x10c.com for updated versions)
  4
+
  5
+* 16 bit unsigned words
  6
+* 0x10000 words of ram
  7
+* 8 registers (A, B, C, X, Y, Z, I, J)
  8
+* program counter (PC)
  9
+* stack pointer (SP)
  10
+* overflow (O)
  11
+
  12
+In this document, anything within [brackets] is shorthand for "the value of the RAM at the location of the value inside the brackets".
  13
+For example, SP means stack pointer, but [SP] means the value of the RAM at the location the stack pointer is pointing at.
  14
+
  15
+Whenever the CPU needs to read a word, it reads [PC], then increases PC by one. Shorthand for this is [PC++].
  16
+In some cases, the CPU will modify a value before reading it, in this case the shorthand is [++PC].
  17
+
  18
+Instructions are 1-3 words long and are fully defined by the first word.
  19
+In a basic instruction, the lower four bits of the first word of the instruction are the opcode,
  20
+and the remaining twelve bits are split into two six bit values, called a and b.
  21
+a is always handled by the processor before b, and is the lower six bits.
  22
+In bits (with the least significant being last), a basic instruction has the format: bbbbbbaaaaaaoooo
  23
+
  24
+
  25
+
  26
+Values: (6 bits)
  27
+    0x00-0x07: register (A, B, C, X, Y, Z, I or J, in that order)
  28
+    0x08-0x0f: [register]
  29
+    0x10-0x17: [next word + register]
  30
+         0x18: POP / [SP++]
  31
+         0x19: PEEK / [SP]
  32
+         0x1a: PUSH / [--SP]
  33
+         0x1b: SP
  34
+         0x1c: PC
  35
+         0x1d: O
  36
+         0x1e: [next word]
  37
+         0x1f: next word (literal)
  38
+    0x20-0x3f: literal value 0x00-0x1f (literal)
  39
+    
  40
+* "next word" really means "[PC++]". These increase the word length of the instruction by 1. 
  41
+* If any instruction tries to assign a literal value, the assignment fails silently. Other than that, the instruction behaves as normal.
  42
+* All values that read a word (0x10-0x17, 0x1e, and 0x1f) take 1 cycle to look up. The rest take 0 cycles.
  43
+* By using 0x18, 0x19, 0x1a as POP, PEEK and PUSH, there's a reverse stack starting at memory location 0xffff. Example: "SET PUSH, 10", "SET X, POP"
  44
+
  45
+
  46
+
  47
+Basic opcodes: (4 bits)
  48
+    0x0: non-basic instruction - see below
  49
+    0x1: SET a, b - sets a to b
  50
+    0x2: ADD a, b - sets a to a+b, sets O to 0x0001 if there's an overflow, 0x0 otherwise
  51
+    0x3: SUB a, b - sets a to a-b, sets O to 0xffff if there's an underflow, 0x0 otherwise
  52
+    0x4: MUL a, b - sets a to a*b, sets O to ((a*b)>>16)&0xffff
  53
+    0x5: DIV a, b - sets a to a/b, sets O to ((a<<16)/b)&0xffff. if b==0, sets a and O to 0 instead.
  54
+    0x6: MOD a, b - sets a to a%b. if b==0, sets a to 0 instead.
  55
+    0x7: SHL a, b - sets a to a<<b, sets O to ((a<<b)>>16)&0xffff
  56
+    0x8: SHR a, b - sets a to a>>b, sets O to ((a<<16)>>b)&0xffff
  57
+    0x9: AND a, b - sets a to a&b
  58
+    0xa: BOR a, b - sets a to a|b
  59
+    0xb: XOR a, b - sets a to a^b
  60
+    0xc: IFE a, b - performs next instruction only if a==b
  61
+    0xd: IFN a, b - performs next instruction only if a!=b
  62
+    0xe: IFG a, b - performs next instruction only if a>b
  63
+    0xf: IFB a, b - performs next instruction only if (a&b)!=0
  64
+    
  65
+* SET, AND, BOR and XOR take 1 cycle, plus the cost of a and b
  66
+* ADD, SUB, MUL, SHR, and SHL take 2 cycles, plus the cost of a and b
  67
+* DIV and MOD take 3 cycles, plus the cost of a and b
  68
+* IFE, IFN, IFG, IFB take 2 cycles, plus the cost of a and b, plus 1 if the test fails
  69
+    
  70
+
  71
+    
  72
+Non-basic opcodes always have their lower four bits unset, have one value and a six bit opcode.
  73
+In binary, they have the format: aaaaaaoooooo0000
  74
+The value (a) is in the same six bit format as defined earlier.
  75
+
  76
+Non-basic opcodes: (6 bits)
  77
+         0x00: reserved for future expansion
  78
+         0x01: JSR a - pushes the address of the next instruction to the stack, then sets PC to a
  79
+    0x02-0x3f: reserved
  80
+    
  81
+* JSR takes 2 cycles, plus the cost of a.
  82
+
  83
+
  84
+
  85
+FAQ:
  86
+
  87
+Q: Why is there no JMP or RET?
  88
+A: They're not needed! "SET PC, <target>" is a one-instruction JMP.
  89
+   For small relative jumps in a single word, you can even do "ADD PC, <dist>" or "SUB PC, <dist>".
  90
+   For RET, simply do "SET PC, POP"
  91
+   
  92
+
  93
+Q: How does the overflow (O) work?
  94
+A: O is set by certain instructions (see above), but never automatically read. You can use its value in instructions, however.
  95
+   For example, to do a 32 bit add of 0x12345678 and 0xaabbccdd, do this:
  96
+      SET [0x1000], 0x5678    ; low word
  97
+      SET [0x1001], 0x1234    ; high word
  98
+      ADD [0x1000], 0xccdd    ; add low words, sets O to either 0 or 1 (in this case 1)
  99
+      ADD [0x1001], O         ; add O to the high word
  100
+      ADD [0x1001], 0xaabb    ; add high words, sets O again (to 0, as 0xaabb+0x1235 is lower than 0x10000)
  101
+
  102
+Q: How do I do 32 or 64 bit division using O?
  103
+A: This is left as an exercise for the reader.
  104
+     
  105
+Q: How about a quick example?
  106
+A: Sure! Here's some sample assembler, and a memory dump of the compiled code:
  107
+
  108
+        ; Try some basic stuff
  109
+                      SET A, 0x30              ; 7c01 0030
  110
+                      SET [0x1000], 0x20       ; 7de1 1000 0020
  111
+                      SUB A, [0x1000]          ; 7803 1000
  112
+                      IFN A, 0x10              ; c00d 
  113
+                         SET PC, crash         ; 7dc1 001a [*]
  114
+                      
  115
+        ; Do a loopy thing
  116
+                      SET I, 10                ; a861
  117
+                      SET A, 0x2000            ; 7c01 2000
  118
+        :loop         SET [0x2000+I], [A]      ; 2161 2000
  119
+                      SUB I, 1                 ; 8463
  120
+                      IFN I, 0                 ; 806d
  121
+                         SET PC, loop          ; 7dc1 000d [*]
  122
+        
  123
+        ; Call a subroutine
  124
+                      SET X, 0x4               ; 9031
  125
+                      JSR testsub              ; 7c10 0018 [*]
  126
+                      SET PC, crash            ; 7dc1 001a [*]
  127
+        
  128
+        :testsub      SHL X, 4                 ; 9037
  129
+                      SET PC, POP              ; 61c1
  130
+                        
  131
+        ; Hang forever. X should now be 0x40 if everything went right.
  132
+        :crash        SET PC, crash            ; 7dc1 001a [*]
  133
+        
  134
+        ; [*]: Note that these can be one word shorter and one cycle faster by using the short form (0x00-0x1f) of literals,
  135
+        ;      but my assembler doesn't support short form labels yet.     
  136
+
  137
+  Full memory dump:
  138
+  
  139
+        0000: 7c01 0030 7de1 1000 0020 7803 1000 c00d
  140
+        0008: 7dc1 001a a861 7c01 2000 2161 2000 8463
  141
+        0010: 806d 7dc1 000d 9031 7c10 0018 7dc1 001a
  142
+        0018: 9037 61c1 7dc1 001a 0000 0000 0000 0000
  143
+        
0  ebin/myapp.app → ebin/dcpu16.app
File renamed without changes
4  src/myapp_app.erl → src/dcpu16_app.erl
... ...
@@ -1,4 +1,4 @@
1  
--module(myapp_app).
  1
+-module(dcpu16_app).
2 2
 -behaviour(application).
3 3
 
4 4
 -export([
@@ -7,7 +7,7 @@
7 7
 	 ]).
8 8
 
9 9
 start(_Type, _StartArgs) ->
10  
-    case myapp_sup:start_link() of
  10
+    case dcpu16_sup:start_link() of
11 11
 	{ok, Pid} ->
12 12
 	    {ok, Pid};
13 13
 	Other ->
23  src/dcpu16_core.erl
... ...
@@ -0,0 +1,23 @@
  1
+%%%-------------------------------------------------------------------
  2
+%%% @author  <Daniel Parnell>
  3
+%%% @copyright (C) 2012, 
  4
+%%% @doc
  5
+%%%     DCPU16 core
  6
+%%% @end
  7
+%%% Created : 8 Apr 2012 by  <Daniel Parnell>
  8
+%%%-------------------------------------------------------------------
  9
+
  10
+-module(dcpu16_core).
  11
+
  12
+-import(array, [new/1, new/2]).
  13
+
  14
+-export([init/1, cycle/1]).
  15
+
  16
+-record(cpu, {a = 0, b = 0, c = 0, x = 0, y = 0, z = 0, i = 0, j = 0, pc = 0, sp = 16#ffff, overflow = 0 }).
  17
+
  18
+
  19
+init([]) ->
  20
+    { #cpu{}, array:new(16#10000, {default,0}), 0, [] }.
  21
+
  22
+cycle({cpu, ram, cycles, micro_ops}) ->
  23
+    ok.
15  src/dcpu16_core.erl~
... ...
@@ -0,0 +1,15 @@
  1
+%%%-------------------------------------------------------------------
  2
+%%% @author  <Daniel Parnell>
  3
+%%% @copyright (C) 2012, 
  4
+%%% @doc
  5
+%%%     DCPU16 application server
  6
+%%% @end
  7
+%%% Created : 8 Apr 2012 by  <Daniel Parnell>
  8
+%%%-------------------------------------------------------------------
  9
+
  10
+-module(dcpu16_server).
  11
+
  12
+-export([init/1]).
  13
+
  14
+-record(state, {}).
  15
+
10  src/myapp_server.erl → src/dcpu16_server.erl
... ...
@@ -1,12 +1,12 @@
1 1
 %%%-------------------------------------------------------------------
2  
-%%% @author  <Zach@ZACH-PC>
3  
-%%% @copyright (C) 2011, 
  2
+%%% @author  <Daniel Parnell>
  3
+%%% @copyright (C) 2012, 
4 4
 %%% @doc
5  
-%%%     Sample application server
  5
+%%%     DCPU16 application server
6 6
 %%% @end
7  
-%%% Created : 23 Mar 2011 by  <Zach@ZACH-PC>
  7
+%%% Created : 8 Apr 2012 by  <Daniel Parnell>
8 8
 %%%-------------------------------------------------------------------
9  
--module(myapp_server).
  9
+-module(dcpu16_server).
10 10
 
11 11
 -behaviour(gen_server).
12 12
 
6  src/myapp_sup.erl → src/dcpu16_sup.erl
... ...
@@ -1,4 +1,4 @@
1  
--module(myapp_sup).
  1
+-module(dcpu16_sup).
2 2
 -behaviour(supervisor).
3 3
 
4 4
 %% API
@@ -13,8 +13,8 @@ start_link() ->
13 13
     supervisor:start_link({local, ?SERVER}, ?MODULE, []).
14 14
 
15 15
 init([]) ->
16  
-    Server = {myapp_server, {myapp_server, start_link, []},
17  
-	      permanent, 2000, worker, [myapp_server]},
  16
+    Server = {dcpu16_server, {dcpu16_server, start_link, []},
  17
+	      permanent, 2000, worker, [dcpu16_server]},
18 18
     Children = [Server],
19 19
     RestartStrategy = {one_for_one, 3, 1},
20 20
     {ok, {RestartStrategy, Children}}.

0 notes on commit 9aa4803

Please sign in to comment.
Something went wrong with that request. Please try again.