Skip to content

Instantly share code, notes, and snippets.

@marcizhu
Created August 2, 2018 22:22
Show Gist options
  • Save marcizhu/92796131f9dd0aed65b6f83cf0f79585 to your computer and use it in GitHub Desktop.
Save marcizhu/92796131f9dd0aed65b6f83cf0f79585 to your computer and use it in GitHub Desktop.
DCPU-16 Specifications (v1.7) + Peripherals
Name: Generic Clock (compatible)
ID: 0x12d0b402
Version: 1
Interrupts do different things depending on contents of the A register:
A | BEHAVIOR
---+----------------------------------------------------------------------------
0 | The B register is read, and the clock will tick 60/B times per second.
| If B is 0, the clock is turned off.
1 | Store number of ticks elapsed since last call to 0 in C register
2 | If register B is non-zero, turn on interrupts with message B. If B is zero,
| disable interrupts
---+----------------------------------------------------------------------------
When interrupts are enabled, the clock will trigger an interrupt whenever it
ticks.
DCPU-16 Specification
Copyright 1985 Mojang
Version 1.7
=== SUMMARY ====================================================================
* 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)
* 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.
=== INSTRUCTIONS ===============================================================
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 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<<a, sets EX to ((b<<a)>>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<a
2+| 0x17 | IFU b, a | performs next instruction only if b<a (signed)
- | 0x18 | - |
- | 0x19 | - |
3 | 0x1a | ADX b, a | sets b to b+a+EX, sets EX to 0x0001 if there is an over-
| | | flow, 0x0 otherwise
3 | 0x1b | SBX b, a | sets b to b-a+EX, sets EX to 0xFFFF if there is an under-
| | | flow, 0x0 otherwise
- | 0x1c | - |
- | 0x1d | - |
2 | 0x1e | STI b, a | sets b to a, then increases I and J by 1
2 | 0x1f | STD b, a | sets b to a, then decreases I and J by 1
---+------+----------+----------------------------------------------------------
* The branching opcodes take one cycle longer to perform if the test fails
When they skip an if instruction, they will skip an additional instruction
at the cost of one extra cycle. This lets you easily chain conditionals.
* Signed numbers are represented using two's complement.
Special opcodes always have their lower five bits unset, have one value and a
five bit opcode. In binary, they have the format: aaaaaaooooo00000
The value (a) is in the same six bit format as defined earlier.
--- 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.
Name: Generic Keyboard (compatible)
ID: 0x30cf7406
Version: 1
Interrupts do different things depending on contents of the A register:
A | BEHAVIOR
---+----------------------------------------------------------------------------
0 | Clear keyboard buffer
1 | Store next key typed in C register, or 0 if the buffer is empty
2 | Set C register to 1 if the key specified by the B register is pressed, or
| 0 if it's not pressed
3 | If register B is non-zero, turn on interrupts with message B. If B is zero,
| disable interrupts
---+----------------------------------------------------------------------------
When interrupts are enabled, the keyboard will trigger an interrupt when one or
more keys have been pressed, released, or typed.
Key numbers are:
0x10: Backspace
0x11: Return
0x12: Insert
0x13: Delete
0x20-0x7f: ASCII characters
0x80: Arrow up
0x81: Arrow down
0x82: Arrow left
0x83: Arrow right
0x90: Shift
0x91: Control
NE_LEM1802 v1.0
\ | ___
|\ \| ___
| \
NYA ELEKTRISKA
innovation information
DCPU-16 Hardware Info:
Name: LEM1802 - Low Energy Monitor
ID: 0x7349f615, version: 0x1802
Manufacturer: 0x1c6c8b36 (NYA_ELEKTRISKA)
Description:
The LEM1802 is a 128x96 pixel color display compatible with the DCPU-16.
The display is made up of 32x12 16 bit cells. Each cell displays one
monochrome 4x8 pixel character out of 128 available. Each cell has its own
foreground and background color out of a palette of 16 colors.
The LEM1802 is fully backwards compatible with LEM1801 (0x7349f615/0x1801),
and adds support for custom palettes and fixes the double buffer color
bleed bug.
Interrupt behavior:
When a HWI is received by the LEM1802, it reads the A register and does one
of the following actions:
0: MEM_MAP_SCREEN
Reads the B register, and maps the video ram to DCPU-16 ram starting
at address B. See below for a description of video ram.
If B is 0, the screen is disconnected.
When the screen goes from 0 to any other value, the the LEM1802 takes
about one second to start up. Other interrupts sent during this time
are still processed.
1: MEM_MAP_FONT
Reads the B register, and maps the font ram to DCPU-16 ram starting
at address B. See below for a description of font ram.
If B is 0, the default font is used instead.
2: MEM_MAP_PALETTE
Reads the B register, and maps the palette ram to DCPU-16 ram starting
at address B. See below for a description of palette ram.
If B is 0, the default palette is used instead.
3: SET_BORDER_COLOR
Reads the B register, and sets the border color to palette index B&0xF
4: MEM_DUMP_FONT
Reads the B register, and writes the default font data to DCPU-16 ram
starting at address B.
Halts the DCPU-16 for 256 cycles
5: MEM_DUMP_PALETTE
Reads the B register, and writes the default palette data to DCPU-16
ram starting at address B.
Halts the DCPU-16 for 16 cycles
Video ram:
The LEM1802 has no internal video ram, but rather relies on being assigned
an area of the DCPU-16 ram. The size of this area is 386 words, and is
made up of 32x12 cells of the following bit format (in LSB-0):
ffffbbbbBccccccc
The lowest 7 bits (ccccccc) select define character to display.
ffff and bbbb select which foreground and background color to use.
If B (bit 7) is set the character color will blink slowly.
Font ram:
The LEM1802 has a default built in font. If the user chooses, they may
supply their own font by mapping a 256 word memory region with two words
per character in the 128 character font.
By setting bits in these words, different characters and graphics can be
achieved. For example, the character F looks like this:
word0 = 1111111100001001
word1 = 0000100100000000
Or, split into octets:
word0 = 11111111 /
00001001
word1 = 00001001 /
00000000
Palette ram:
The LEM1802 has a default built in palette. If the user chooses, they may
supply their own palette by mapping a 16 word memory region with one word
per palette entry in the 16 color palette.
Each color entry has the following bit format (in LSB-0):
0000rrrrggggbbbb
Where r, g, b are the red, green and blue channels. A higher value means a
lighter color.
A message from Ola:
Hello!
It is fun to see that so many people use our products. When I was a small
boy, my dad used to tell me "Ola, take care of those who understand less
than you. Lack of knowledge is dangerous, but too much is worse".
Here at Nya Elektriska have we always tried to improve mankind by showing
them the tools required to improve and reach their true potential.
Together, you will wake up in time.
- Ola Kristian Carlsson
.!.
!!!!!.
. '!!!!!.
.!!!. '!!!!!.
.!!!!!!!. '!!!!!.
.!!!!!!!!!' .!!!!!!!.
'!!!!!!!' .!!!!!!!!!'
'!!!!!. '!!!!!!!'
'!!!!!. '!!!'
'!!!!!. '
'!!!!!
'!'
M A C K A P A R M E D I A
.---------------------.
----! DCPU-16 INFORMATION !-----------------------------------------------------
'---------------------'
Name: Mackapar 3.5" Floppy Drive (M35FD)
ID: 0x4fd524c5, version: 0x000b
Manufacturer: 0x1eb37e91 (MACKAPAR)
.-------------.
----! DESCRIPTION !-------------------------------------------------------------
'-------------'
The Mackapar 3.5" Floppy Drive is compatible with all standard 3.5" 1440 KB
floppy disks. The floppies need to be formatted in 16 bit mode, for a total of
737,280 words of storage. Data is saved on 80 tracks with 18 sectors per track,
for a total of 1440 sectors containing 512 words each.
The M35FD works is asynchronous, and has a raw read/write speed of 30.7kw/s.
Track seeking time is about 2.4 ms per track.
.--------------------.
----! INTERRUPT BEHAVIOR !------------------------------------------------------
'--------------------'
A, B, C, X, Y, Z, I, J below refer to the registers on the DCPU
A: Behavior:
0 Poll device. Sets B to the current state (see below) and C to the last error
since the last device poll.
1 Set interrupt. Enables interrupts and sets the message to X if X is anything
other than 0, disables interrupts if X is 0. When interrupts are enabled,
the M35FD will trigger an interrupt on the DCPU-16 whenever the state or
error message changes.
2 Read sector. Reads sector X to DCPU ram starting at Y.
Sets B to 1 if reading is possible and has been started, anything else if it
fails. Reading is only possible if the state is STATE_READY or
STATE_READY_WP.
Protects against partial reads.
3 Write sector. Writes sector X from DCPU ram starting at Y.
Sets B to 1 if writing is possible and has been started, anything else if it
fails. Writing is only possible if the state is STATE_READY.
Protects against partial writes.
.-------------.
----! STATE CODES !-------------------------------------------------------------
'-------------'
0x0000 STATE_NO_MEDIA There's no floppy in the drive.
0x0001 STATE_READY The drive is ready to accept commands.
0x0002 STATE_READY_WP Same as ready, except the floppy is write protected.
0x0003 STATE_BUSY The drive is busy either reading or writing a sector.
.-------------.
----! ERROR CODES !-------------------------------------------------------------
'-------------'
0x0000 ERROR_NONE There's been no error since the last poll.
0x0001 ERROR_BUSY Drive is busy performing an action
0x0002 ERROR_NO_MEDIA Attempted to read or write with no floppy inserted.
0x0003 ERROR_PROTECTED Attempted to write to write protected floppy.
0x0004 ERROR_EJECT The floppy was removed while reading or writing.
0x0005 ERROR_BAD_SECTOR The requested sector is broken, the data on it is lost.
0xffff ERROR_BROKEN There's been some major software or hardware problem,
try turning off and turning on the device again.
COPYRIGHT 1987 MACKAPAR MEDIA ALL RIGHTS RESERVED DO NOT DISTRIBUTE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment