Skip to content

Instantly share code, notes, and snippets.

@rmmh
Created April 9, 2012 04:36
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save rmmh/2341455 to your computer and use it in GitHub Desktop.
DPCU-16 Spec Suggestions

DCPU-16 Spec Suggestions

  1. Evaluate b before a

This makes instructions that address the stack twice meaningful instead of confusing and useless.

ADD PEEK, POP should pop the top of the stack and add it to the second entry, but currently the PEEK is evaluated before the POP occurs.

  1. Add [SP+next word] addressing

This makes writing functions that store extra variables or arguments on the stack easier.

POP isn't useful as an a value, and PUSH isn't useful as a b value, so they should be combined into one value, with postincrement and predecrement determined by whether they're in a/b.

  1. Make opcodes 5 bits

A literal a value is not very useful, and having 2x more opcodes is very useful. bbbbbbaaaaaaoooo becomes bbbbbbaaaaaooooo

  1. Make literal range include -1.

Shift the literal range from [0, 31] to [-1, 30].

Having -1 as a literal lets you useful one-word instructions like:

    NOT X --> XOR X, -1```

5. Rename O register to EX or OV
-------------------------------------
O and 0 are very easy to confuse, other special registers are two characters, and it doesn't always represent overflow.

6. Add signed MUL/DIV instructions
--------------------------------------
Signed operations make maneuvers, targeting, and fixed-point trigonometry routines more efficient.

Suggested mnemonics: `MLI`, `DVI`.

7. Add signed right shift (ASR)
-----------------------------------------
Signed operations are useful.

8. Add additional IF instructions
------------------------------------
Supporting all the relations (<, >, <=, >=) will make assembly easier to write and read. Suggested mnemonics and effects:

    0x11: IFB a, b - performs next instruction only if (a&b)!=0       (Bit set)
    0x12: IFE a, b - performs next instruction only if a==b           (Equal)
    0x13: IFN a, b - performs next instruction only if a!=b           (Not equal)
    0x14: IFG a, b - performs next instruction only if a>b (signed)   (Greater)
    0x15: IFA a, b - performs next instruction only if a>b (unsigned) (Above)
    0x16: IFL a, b - performs next instruction only if a<b (signed)   (Less)
    0x17: IFU a, b - performs next instruction only if a<b (unsigned) (Under)


Appendix A.
===========
1. Fix line drawing characters
------------------------------
As [jecowa noted on reddit](http://www.reddit.com/r/dcpu16/comments/sio8u/dcpu_font_help_what_are_those_first_30ish_glyphs/c4ekx9u), you can't make full boxes with the current line drawing characters.

These 22 glyphs let you draw boxes:

│─└┌┐┘┴├┬┤┼

║═╚╔╗╝╩╠╦╣╬

Suggestions for extra 5 glyphs:

° (Degree) and ♠♥♦♣ (Card suits)

Note that the full block █ with fg color X is equivalent to space with bg X. Replace it with a dithered ▒ half-block.
DCPU-16 Specification
Copyright 2012 Mojang
Version 1.1 (Check 0x10c.com for updated versions)
* 16 bit words
* 0x10000 words of ram
* 8 registers (A, B, C, X, Y, Z, I, J)
* program counter (PC)
* stack pointer (SP)
* extra/excess (EX)
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 are 1-3 words long and are fully defined by the first word.
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 a and a six bit value b.
a is always handled by the processor after b, and is the lower five bits.
In bits (with the least significant being last), a basic instruction has the format: bbbbbbaaaaaooooo
Values: (5/6 bits)
0x00-0x07: register (A, B, C, X, Y, Z, I or J, in that order)
0x08-0x0f: [register]
0x10-0x17: [register + next word]
0x18: (PUSH / [--SP]) if in a, or (POP / [SP++]) if in b
0x19: [SP] / PEEK
0x1a: [SP + next word] / PICK n
0x1b: SP
0x1c: PC
0x1d: EX
0x1e: [next word]
0x1f: next word (literal)
0x20-0x3f: literal value 0xffff-0x1e (-1..30) (literal) (only for b)
* "next word" really means "[PC++]". These increase the word length of the instruction by 1.
* 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 PEEK, POP/PUSH, and PICK there's a reverse stack starting at memory location 0xffff. Example: "SET PUSH, 10", "SET X, POP"
Basic opcodes: (5 bits)
0x0: special instruction - see below
0x1: SET a, b - sets a to b
0x2: ADD a, b - sets a to a+b, sets EX to 0x0001 if there's an overflow, 0x0 otherwise
0x3: SUB a, b - sets a to a-b, sets EX to 0xffff if there's an underflow, 0x0 otherwise
0x4: MUL a, b - sets a to a*b, sets EX to ((a*b)>>16)&0xffff (treats a, b as unsigned)
0x5: MLI a, b - like MUL, but treat a, b as signed
0x6: DIV a, b - sets a to a/b, sets EX to ((a<<16)/b)&0xffff. if b==0, sets a and EX to 0 instead. (treats a, b as unsigned)
0x7: DVI a, b - like DIV, but treat a, b as signed
0x8: MOD a, b - sets a to a%b. if b==0, sets a to 0 instead.
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: SHR a, b - sets a to a>>>b, sets EX to ((a<<16)>>b)&0xffff (logical shift)
0xd: ASR a, b - sets a to a>>b, sets EX to ((a<<16)>>>b)&0xffff (arithmetic shift) (treats a as signed)
0xe: SHL a, b - sets a to a<<b, sets EX to ((a<<b)>>16)&0xffff
0x10: special instruction - see below
0x11: IFB a, b - performs next instruction only if (a&b)!=0 (Bit set)
0x12: IFE a, b - performs next instruction only if a==b (Equal)
0x13: IFN a, b - performs next instruction only if a!=b (Not equal)
0x14: IFG a, b - performs next instruction only if a>b (signed) (Greater)
0x15: IFA a, b - performs next instruction only if a>b (unsigned) (Above)
0x16: IFL a, b - performs next instruction only if a<b (signed) (Less)
0x17: IFU a, b - performs next instruction only if a<b (unsigned) (Under)
* SET, AND, BOR and XOR take 1 cycle, plus the cost of a and b
* ADD, SUB, MUL, MLI, SHR, SHL, and ASR take 2 cycles, plus the cost of a and b
* DIV, DVI, and MOD take 3 cycles, plus the cost of a and b
* IFs take 2 cycles, plus the cost of a and b, plus 1 if the test fails
* JSR takes 2 cycles, plus the cost of a.
* Signed numbers are represented using two's complement.
Special opcodes always have their lower four bits unset, have one value and a six bit opcode.
In binary, they have the format: aaaaaaoooooo0000
The value (a) is in the same six bit format as defined earlier.
Special opcodes: (6 bits)
0x00: reserved for future expansion
0x01: JSR a - pushes the address of the next instruction to the stack, then sets PC to a
0x02-0x3f: reserved
@0xabad1dea
Copy link

I would also suggest PUSHALL and POPALL to conserve program size, even if they take the exact same amount of cycles as doing it manually

@marcan
Copy link

marcan commented Apr 9, 2012

I wrote an analysis of the architecture and a modified proposal that (coincidentally) addresses almost all of these points and a few others :) (except for the first one, but I changed it to a load-store architecture so that one becomes irrelevant).

http://fail0verflow.com/blog/2012/dcpu-16-review.html

@tyrel
Copy link

tyrel commented Apr 21, 2012

I notice this still says "Special opcodes always have their lower four bits unset", but don't we actually need five bits to be unset in order for the lower 5 bits to be 0, coinciding with the 5-bit "special instruction" opcode?

Then the next question is: is the special opcode 6 bits with a 5 bit value, or is it 5 bits with a 6 bit value? I think I'd go for the 6 bit value to allow for the literals to go in this single value, so 5 bit opcode here.

@rmmh
Copy link
Author

rmmh commented Apr 21, 2012

Note that I've reserved both 0x00 and 0x10 as "special instruction" opcodes-- the 5th bit is used as the low bit in the special opcodes.

Special instructions have a 6 bit opcode and a 6 bit value.

@tyrel
Copy link

tyrel commented Apr 21, 2012

Ah, missed that. Thanks rmmh.

Since Notch said on reddit a few days ago that he's going to implement all of these changes, I'm making my emulator to follow this, to hopefully get a head start. :-)

@BytecraftLimited
Copy link

Minor comment. Update the version number.
Interesting changes, lots of room for optimization in generated code. Literal -1 will be very useful. 1970's coding styles ofter used -1 as an undefined flag as well as the other examples cited

@Olathe
Copy link

Olathe commented Jun 23, 2012

You could copy the old IBM characters: http://www.ascii-codes.com/

Has smiley faces, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment