dcpu16 spec updated to v1.7, no code changes yet
authorJustin Wind <justin.wind@gmail.com>
Sat, 5 May 2012 19:38:44 +0000 (12:38 -0700)
committerJustin Wind <justin.wind@gmail.com>
Sat, 5 May 2012 19:38:44 +0000 (12:38 -0700)
docs/dcpu-16.txt

index 2e99ed2ce83be0a3f54d1d742646ea19df06a1c9..6445121222e7ea6c6890f48d25457dc647a3ed2c 100644 (file)
 DCPU-16 Specification\r
-Copyright 2012 Mojang\r
-Version 1.1 (Check 0x10c.com for updated versions)\r
+Copyright 1985 Mojang\r
+Version 1.7\r
 \r
-* 16 bit unsigned words\r
+\r
+\r
+=== SUMMARY ====================================================================\r
+\r
+* 16 bit words\r
 * 0x10000 words of ram\r
 * 8 registers (A, B, C, X, Y, Z, I, J)\r
 * program counter (PC)\r
 * stack pointer (SP)\r
-* overflow (O)\r
+* extra/excess (EX)\r
+* interrupt address (IA)\r
+\r
+In this document, anything within [brackets] is shorthand for "the value of the\r
+RAM at the location of the value inside the brackets". For example, SP means\r
+stack pointer, but [SP] means the value of the RAM at the location the stack\r
+pointer is pointing at.\r
+\r
+Whenever the CPU needs to read a word, it reads [PC], then increases PC by one.\r
+Shorthand for this is [PC++]. In some cases, the CPU will modify a value before\r
+reading it, in this case the shorthand is [++PC].\r
+\r
+For stability and to reduce bugs, it's strongly suggested all multi-word\r
+operations use little endian in all DCPU-16 programs, wherever possible.\r
+\r
 \r
-In this document, anything within [brackets] is shorthand for "the value of the RAM at the location of the value inside the brackets".\r
-For example, SP means stack pointer, but [SP] means the value of the RAM at the location the stack pointer is pointing at.\r
 \r
-Whenever the CPU needs to read a word, it reads [PC], then increases PC by one. Shorthand for this is [PC++].\r
-In some cases, the CPU will modify a value before reading it, in this case the shorthand is [++PC].\r
+=== INSTRUCTIONS ===============================================================\r
 \r
 Instructions are 1-3 words long and are fully defined by the first word.\r
-In a basic instruction, the lower four bits of the first word of the instruction are the opcode,\r
-and the remaining twelve bits are split into two six bit values, called a and b.\r
-a is always handled by the processor before b, and is the lower six bits.\r
-In bits (with the least significant being last), a basic instruction has the format: bbbbbbaaaaaaoooo\r
-\r
-\r
-\r
-Values: (6 bits)\r
-    0x00-0x07: register (A, B, C, X, Y, Z, I or J, in that order)\r
-    0x08-0x0f: [register]\r
-    0x10-0x17: [next word + register]\r
-         0x18: POP / [SP++]\r
-         0x19: PEEK / [SP]\r
-         0x1a: PUSH / [--SP]\r
-         0x1b: SP\r
-         0x1c: PC\r
-         0x1d: O\r
-         0x1e: [next word]\r
-         0x1f: next word (literal)\r
-    0x20-0x3f: literal value 0x00-0x1f (literal)\r
-    \r
-* "next word" really means "[PC++]". These increase the word length of the instruction by 1. \r
-* If any instruction tries to assign a literal value, the assignment fails silently. Other than that, the instruction behaves as normal.\r
-* All values that read a word (0x10-0x17, 0x1e, and 0x1f) take 1 cycle to look up. The rest take 0 cycles.\r
-* 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"\r
-\r
-\r
-\r
-Basic opcodes: (4 bits)\r
-    0x0: non-basic instruction - see below\r
-    0x1: SET a, b - sets a to b\r
-    0x2: ADD a, b - sets a to a+b, sets O to 0x0001 if there's an overflow, 0x0 otherwise\r
-    0x3: SUB a, b - sets a to a-b, sets O to 0xffff if there's an underflow, 0x0 otherwise\r
-    0x4: MUL a, b - sets a to a*b, sets O to ((a*b)>>16)&0xffff\r
-    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.\r
-    0x6: MOD a, b - sets a to a%b. if b==0, sets a to 0 instead.\r
-    0x7: SHL a, b - sets a to a<<b, sets O to ((a<<b)>>16)&0xffff\r
-    0x8: SHR a, b - sets a to a>>b, sets O to ((a<<16)>>b)&0xffff\r
-    0x9: AND a, b - sets a to a&b\r
-    0xa: BOR a, b - sets a to a|b\r
-    0xb: XOR a, b - sets a to a^b\r
-    0xc: IFE a, b - performs next instruction only if a==b\r
-    0xd: IFN a, b - performs next instruction only if a!=b\r
-    0xe: IFG a, b - performs next instruction only if a>b\r
-    0xf: IFB a, b - performs next instruction only if (a&b)!=0\r
-    \r
-* SET, AND, BOR and XOR take 1 cycle, plus the cost of a and b\r
-* ADD, SUB, MUL, SHR, and SHL take 2 cycles, plus the cost of a and b\r
-* DIV and MOD take 3 cycles, plus the cost of a and b\r
-* IFE, IFN, IFG, IFB take 2 cycles, plus the cost of a and b, plus 1 if the test fails\r
-    \r
+In a basic instruction, the lower five bits of the first word of the instruction\r
+are the opcode, and the remaining eleven bits are split into a five bit value b\r
+and a six bit value a.\r
+b is always handled by the processor after a, and is the lower five bits.\r
+In bits (in LSB-0 format), a basic instruction has the format: aaaaaabbbbbooooo\r
+\r
+In the tables below, C is the time required in cycles to look up the value, or\r
+perform the opcode, VALUE is the numerical value, NAME is the mnemonic, and\r
+DESCRIPTION is a short text that describes the opcode or value.\r
+\r
+\r
+\r
+--- Values: (5/6 bits) ---------------------------------------------------------\r
+ C | VALUE     | DESCRIPTION\r
+---+-----------+----------------------------------------------------------------\r
+ 0 | 0x00-0x07 | register (A, B, C, X, Y, Z, I or J, in that order)\r
+ 0 | 0x08-0x0f | [register]\r
+ 1 | 0x10-0x17 | [register + next word]\r
+ 0 |      0x18 | (PUSH / [--SP]) if in b, or (POP / [SP++]) if in a\r
+ 0 |      0x19 | [SP] / PEEK\r
+ 1 |      0x1a | [SP + next word] / PICK n\r
+ 0 |      0x1b | SP\r
+ 0 |      0x1c | PC\r
+ 0 |      0x1d | EX\r
+ 1 |      0x1e | [next word]\r
+ 1 |      0x1f | next word (literal)\r
+ 0 | 0x20-0x3f | literal value 0xffff-0x1e (-1..30) (literal) (only for a)\r
+ --+-----------+----------------------------------------------------------------\r
+  \r
+* "next word" means "[PC++]". Increases the word length of the instruction by 1.\r
+* By using 0x18, 0x19, 0x1a as PEEK, POP/PUSH, and PICK there's a reverse stack\r
+  starting at memory location 0xffff. Example: "SET PUSH, 10", "SET X, POP"\r
+* Attempting to write to a literal value fails silently\r
+\r
+\r
+\r
+--- Basic opcodes (5 bits) ----------------------------------------------------\r
+ C | VAL  | NAME     | DESCRIPTION\r
+---+------+----------+---------------------------------------------------------\r
+ - | 0x00 | n/a      | special instruction - see below\r
+ 1 | 0x01 | SET b, a | sets b to a\r
+ 2 | 0x02 | ADD b, a | sets b to b+a, sets EX to 0x0001 if there's an overflow, \r
+   |      |          | 0x0 otherwise\r
+ 2 | 0x03 | SUB b, a | sets b to b-a, sets EX to 0xffff if there's an underflow,\r
+   |      |          | 0x0 otherwise\r
+ 2 | 0x04 | MUL b, a | sets b to b*a, sets EX to ((b*a)>>16)&0xffff (treats b,\r
+   |      |          | a as unsigned)\r
+ 2 | 0x05 | MLI b, a | like MUL, but treat b, a as signed\r
+ 3 | 0x06 | DIV b, a | sets b to b/a, sets EX to ((b<<16)/a)&0xffff. if a==0,\r
+   |      |          | sets b and EX to 0 instead. (treats b, a as unsigned)\r
+ 3 | 0x07 | DVI b, a | like DIV, but treat b, a as signed. Rounds towards 0\r
+ 3 | 0x08 | MOD b, a | sets b to b%a. if a==0, sets b to 0 instead.\r
+ 3 | 0x09 | MDI b, a | like MOD, but treat b, a as signed. (MDI -7, 16 == -7)\r
+ 1 | 0x0a | AND b, a | sets b to b&a\r
+ 1 | 0x0b | BOR b, a | sets b to b|a\r
+ 1 | 0x0c | XOR b, a | sets b to b^a\r
+ 1 | 0x0d | SHR b, a | sets b to b>>>a, sets EX to ((b<<16)>>a)&0xffff \r
+   |      |          | (logical shift)\r
+ 1 | 0x0e | ASR b, a | sets b to b>>a, sets EX to ((b<<16)>>>a)&0xffff \r
+   |      |          | (arithmetic shift) (treats b as signed)\r
+ 1 | 0x0f | SHL b, a | sets b to b<<a, sets EX to ((b<<a)>>16)&0xffff\r
+\r
+ 2+| 0x10 | IFB b, a | performs next instruction only if (b&a)!=0\r
+ 2+| 0x11 | IFC b, a | performs next instruction only if (b&a)==0\r
+ 2+| 0x12 | IFE b, a | performs next instruction only if b==a \r
+ 2+| 0x13 | IFN b, a | performs next instruction only if b!=a \r
+ 2+| 0x14 | IFG b, a | performs next instruction only if b>a \r
+ 2+| 0x15 | IFA b, a | performs next instruction only if b>a (signed)\r
+ 2+| 0x16 | IFL b, a | performs next instruction only if b<a \r
+ 2+| 0x17 | IFU b, a | performs next instruction only if b<a (signed)\r
+ - | 0x18 | -        |\r
+ - | 0x19 | -        |\r
+ 3 | 0x1a | ADX b, a | sets b to b+a+EX, sets EX to 0x0001 if there is an over-\r
+   |      |          | flow, 0x0 otherwise\r
+ 3 | 0x1b | SBX b, a | sets b to b-a+EX, sets EX to 0xFFFF if there is an under-\r
+   |      |          | flow, 0x0 otherwise\r
+ - | 0x1c | -        | \r
+ - | 0x1d | -        |\r
+ 2 | 0x1e | STI b, a | sets b to a, then increases I and J by 1\r
+ 2 | 0x1f | STD b, a | sets b to a, then decreases I and J by 1\r
+---+------+----------+----------------------------------------------------------\r
+\r
+* The branching opcodes take one cycle longer to perform if the test fails\r
+  When they skip an if instruction, they will skip an additional instruction\r
+  at the cost of one extra cycle. This lets you easily chain conditionals.  \r
+* Signed numbers are represented using two's complement.\r
 \r
     \r
-Non-basic opcodes always have their lower four bits unset, have one value and a six bit opcode.\r
-In binary, they have the format: aaaaaaoooooo0000\r
+Special opcodes always have their lower five bits unset, have one value and a\r
+five bit opcode. In binary, they have the format: aaaaaaooooo00000\r
 The value (a) is in the same six bit format as defined earlier.\r
 \r
-Non-basic opcodes: (6 bits)\r
-         0x00: reserved for future expansion\r
-         0x01: JSR a - pushes the address of the next instruction to the stack, then sets PC to a\r
-    0x02-0x3f: reserved\r
-    \r
-* JSR takes 2 cycles, plus the cost of a.\r
-\r
-\r
-\r
-FAQ:\r
-\r
-Q: Why is there no JMP or RET?\r
-A: They're not needed! "SET PC, <target>" is a one-instruction JMP.\r
-   For small relative jumps in a single word, you can even do "ADD PC, <dist>" or "SUB PC, <dist>".\r
-   For RET, simply do "SET PC, POP"\r
-   \r
-Q: How does the overflow (O) work?\r
-A: O is set by certain instructions (see above), but never automatically read. You can use its value in instructions, however.\r
-   For example, to do a 32 bit add of 0x12345678 and 0xaabbccdd, do this:\r
-      SET [0x1000], 0x5678    ; low word\r
-      SET [0x1001], 0x1234    ; high word\r
-      ADD [0x1000], 0xccdd    ; add low words, sets O to either 0 or 1 (in this case 1)\r
-      ADD [0x1001], O         ; add O to the high word\r
-      ADD [0x1001], 0xaabb    ; add high words, sets O again (to 0, as 0xaabb+0x1235 is lower than 0x10000)\r
-\r
-Q: How do I do 32 or 64 bit division using O?\r
-A: This is left as an exercise for the reader.\r
-     \r
-Q: How about a quick example?\r
-A: Sure! Here's some sample assembler, and a memory dump of the compiled code:\r
-\r
-        ; Try some basic stuff\r
-                      SET A, 0x30              ; 7c01 0030\r
-                      SET [0x1000], 0x20       ; 7de1 1000 0020\r
-                      SUB A, [0x1000]          ; 7803 1000\r
-                      IFN A, 0x10              ; c00d \r
-                         SET PC, crash         ; 7dc1 001a [*]\r
-                      \r
-        ; Do a loopy thing\r
-                      SET I, 10                ; a861\r
-                      SET A, 0x2000            ; 7c01 2000\r
-        :loop         SET [0x2000+I], [A]      ; 2161 2000\r
-                      SUB I, 1                 ; 8463\r
-                      IFN I, 0                 ; 806d\r
-                         SET PC, loop          ; 7dc1 000d [*]\r
-        \r
-        ; Call a subroutine\r
-                      SET X, 0x4               ; 9031\r
-                      JSR testsub              ; 7c10 0018 [*]\r
-                      SET PC, crash            ; 7dc1 001a [*]\r
-        \r
-        :testsub      SHL X, 4                 ; 9037\r
-                      SET PC, POP              ; 61c1\r
-                        \r
-        ; Hang forever. X should now be 0x40 if everything went right.\r
-        :crash        SET PC, crash            ; 7dc1 001a [*]\r
-        \r
-        ; [*]: Note that these can be one word shorter and one cycle faster by using the short form (0x00-0x1f) of literals,\r
-        ;      but my assembler doesn't support short form labels yet.     \r
-\r
-  Full memory dump:\r
-  \r
-        0000: 7c01 0030 7de1 1000 0020 7803 1000 c00d\r
-        0008: 7dc1 001a a861 7c01 2000 2161 2000 8463\r
-        0010: 806d 7dc1 000d 9031 7c10 0018 7dc1 001a\r
-        0018: 9037 61c1 7dc1 001a 0000 0000 0000 0000\r
-        
\ No newline at end of file
+--- Special opcodes: (5 bits) --------------------------------------------------\r
+ C | VAL  | NAME  | DESCRIPTION\r
+---+------+-------+-------------------------------------------------------------\r
+ - | 0x00 | n/a   | reserved for future expansion\r
+ 3 | 0x01 | JSR a | pushes the address of the next instruction to the stack,\r
+   |      |       | then sets PC to a\r
+ - | 0x02 | -     |\r
+ - | 0x03 | -     |\r
+ - | 0x04 | -     |\r
+ - | 0x05 | -     |\r
+ - | 0x06 | -     |\r
+ - | 0x07 | -     | \r
+ 4 | 0x08 | INT a | triggers a software interrupt with message a\r
+ 1 | 0x09 | IAG a | sets a to IA \r
+ 1 | 0x0a | IAS a | sets IA to a\r
+ 3 | 0x0b | RFI a | disables interrupt queueing, pops A from the stack, then \r
+   |      |       | pops PC from the stack\r
+ 2 | 0x0c | IAQ a | if a is nonzero, interrupts will be added to the queue\r
+   |      |       | instead of triggered. if a is zero, interrupts will be\r
+   |      |       | triggered as normal again\r
+ - | 0x0d | -     |\r
+ - | 0x0e | -     |\r
+ - | 0x0f | -     |\r
+ 2 | 0x10 | HWN a | sets a to number of connected hardware devices\r
+ 4 | 0x11 | HWQ a | sets A, B, C, X, Y registers to information about hardware a\r
+   |      |       | A+(B<<16) is a 32 bit word identifying the hardware id\r
+   |      |       | C is the hardware version\r
+   |      |       | X+(Y<<16) is a 32 bit word identifying the manufacturer\r
+ 4+| 0x12 | HWI a | sends an interrupt to hardware a\r
+ - | 0x13 | -     |\r
+ - | 0x14 | -     |\r
+ - | 0x15 | -     |\r
+ - | 0x16 | -     |\r
+ - | 0x17 | -     |\r
+ - | 0x18 | -     |\r
+ - | 0x19 | -     |\r
+ - | 0x1a | -     |\r
+ - | 0x1b | -     |\r
+ - | 0x1c | -     |\r
+ - | 0x1d | -     |\r
+ - | 0x1e | -     |\r
+ - | 0x1f | -     |\r
+---+------+-------+-------------------------------------------------------------\r
+\r
+\r
+\r
+=== INTERRUPTS =================================================================    \r
+\r
+The DCPU-16 will perform at most one interrupt between each instruction. If\r
+multiple interrupts are triggered at the same time, they are added to a queue.\r
+If the queue grows longer than 256 interrupts, the DCPU-16 will catch fire. \r
+\r
+When IA is set to something other than 0, interrupts triggered on the DCPU-16\r
+will turn on interrupt queueing, push PC to the stack, followed by pushing A to\r
+the stack, then set the PC to IA, and A to the interrupt message.\r
\r
+If IA is set to 0, a triggered interrupt does nothing. Software interrupts still\r
+take up four clock cycles, but immediately return, incoming hardware interrupts\r
+are ignored. Note that a queued interrupt is considered triggered when it leaves\r
+the queue, not when it enters it.\r
+\r
+Interrupt handlers should end with RFI, which will disable interrupt queueing\r
+and pop A and PC from the stack as a single atomic instruction.\r
+IAQ is normally not needed within an interrupt handler, but is useful for time\r
+critical code.\r
+\r
+\r
+\r
+\r
+=== HARDWARE ===================================================================    \r
+\r
+The DCPU-16 supports up to 65535 connected hardware devices. These devices can\r
+be anything from additional storage, sensors, monitors or speakers.\r
+How to control the hardware is specified per hardware device, but the DCPU-16\r
+supports a standard enumeration method for detecting connected hardware via\r
+the HWN, HWQ and HWI instructions.\r
+\r
+Interrupts sent to hardware can't contain messages, can take additional cycles,\r
+and can read or modify any registers or memory adresses on the DCPU-16. This\r
+behavior changes per hardware device and is described in the hardware's\r
+documentation.\r
+\r
+Hardware must NOT start modifying registers or ram on the DCPU-16 before at\r
+least one HWI call has been made to the hardware.\r
+\r
+The DPCU-16 does not support hot swapping hardware. The behavior of connecting\r
+or disconnecting hardware while the DCPU-16 is running is undefined.\r
+\r