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