Initial commit
This commit is contained in:
commit
aedf6873a7
|
@ -0,0 +1,5 @@
|
||||||
|
*%
|
||||||
|
*~
|
||||||
|
*.o
|
||||||
|
*.orig
|
||||||
|
dsim
|
|
@ -0,0 +1,15 @@
|
||||||
|
.PHONY: all clean reformat
|
||||||
|
|
||||||
|
CFLAGS=-Wall -Werror -pedantic -std=c99 -O2 -mtune=native
|
||||||
|
REFORMAT=astyle --style=linux
|
||||||
|
|
||||||
|
all: dsim
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) *~ *% *.o *.orig
|
||||||
|
$(RM) dsim
|
||||||
|
|
||||||
|
reformat: $(wildcard *.c)
|
||||||
|
$(REFORMAT) $^
|
||||||
|
|
||||||
|
# vim:noet:sw=8:sts=8:
|
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
|
@ -0,0 +1,39 @@
|
||||||
|
# Hardware specifications for 0x10c
|
||||||
|
|
||||||
|
May 2014
|
||||||
|
|
||||||
|
This repository serves as a historical archive containing specifications for the fictional hardware of the game 0x10c. The game was to be a multiplayer sandbox game set in space, with a fully programmable CPU controlling a ship. The game was [cancelled in 2013][1] to much dismay of fans. A number of fan projects appeared aiming at continuing development, but they also appear to be abandoned.
|
||||||
|
|
||||||
|
There are a large number of fan works on GitHub, mainly implementations of the DCPU-16 hardware or code to run on it. GitHub still has a list of [DCPU-16 ASM trending repositories][2]. These usually included links to the official specifications which were either hosted on Pastebin or 0x10c.com. The later has been been offline since February 2014 (weirdly the domain was renewed for another year in April 2014), so this is my attempt to archive them for future reference.
|
||||||
|
|
||||||
|
## Official Specifications
|
||||||
|
|
||||||
|
* [DCPU-16](dcpu16.txt) - 16bit CPU.
|
||||||
|
* [LEM1802](lem1802.txt) - 128x96 pixel color display.
|
||||||
|
* [SPED-3](sped3.txt) - 3D vector display.
|
||||||
|
* [M35FD](m35fd.txt) - Floppy disk drive.
|
||||||
|
* [SPC2000](spc2000.txt) - Deep sleep chamber. This is part of 0x10c's backstory (the number of years to sleep was entered in the wrong byte order).
|
||||||
|
* [Clock](clock.txt) - Basic real time clock.
|
||||||
|
* [Keyboard](keyboard.txt) - Keyboard interface.
|
||||||
|
|
||||||
|
## Community Adopted Specifications
|
||||||
|
|
||||||
|
The floppy drive specification was released approximately six months after the release of the initial specifications. Before this time a fan work specification for the [HMD2043 floppy disk drive](https://gist.github.com/DanielKeep/2495578) was released. A number of emulators continue to use this rather than the official M35FD.
|
||||||
|
|
||||||
|
Although the specification of the LEM1802 says it must be initialised before use, most emulators start with the device already initialised with video memory mapped to 0x8000.
|
||||||
|
|
||||||
|
Although there is a specification for a keyboard device, Notch's alpha releases of 0x10c which included a functional DCPU-16 system did not follow this. Instead the keyboard is interfaced through a 16 letter ring buffer mapped at 0x9000 (non configurable). An address is 0 before a key is pressed, and should be written as 0 again after being read so it can be checked later. Most emulators follow this functionality.
|
||||||
|
|
||||||
|
The official specifications don't go too in depth into the format of the assembly language, and there has been no official assembler released. The code in the specification is similar to NASM and community assemblers are also based on this. Most support labels, and some add macros. The language has come to be known as DASM (DCPU-16 Assembly) and typically has the extension `dasm` or `dasm16`. Object code has the extension `bin`, `dcpu` or `dcpu16`.
|
||||||
|
|
||||||
|
## Copyright
|
||||||
|
|
||||||
|
The copyright notices in the specifications are assumed to be fictional due to the copyright dates being dated when the game was set (1980s), not when the fictional works were written (2012/2013). Even so, these fictional works are still assumed to be under the copyright of Mojang. They are being reproduced here to serve as a non-commerical archive which is permitted under most copyright laws around the world (including the US where GitHub is based, and the UK where I am based).
|
||||||
|
|
||||||
|
The implementation of these specifications in your own commerical work is permitted (it is just a specification and is not patented), however you probably should not reproduce these specification documents as is. Care should be taken with hardware and manufacturer names, as they may also be under the copyright of Mojang.
|
||||||
|
|
||||||
|
[Notch has said on Reddit][3] that Mojang didn't want these files to be distributed originally, as they didn't want the hardware to become fragmented before the game was finished. He has also said that implementing the hardware in your own games is allowed.
|
||||||
|
|
||||||
|
[1]: http://www.rockpapershotgun.com/2013/08/19/0x10c-cancelled-for-good-but-fans-plan-to-do-it-anyway/
|
||||||
|
[2]: https://github.com/trending?l=dcpu-16-asm
|
||||||
|
[3]: http://www.reddit.com/r/dcpu16/comments/1zykmx/hey_guys_what_sort_of_copyright_is_the_dcpu16/cfy7igf
|
|
@ -0,0 +1,17 @@
|
||||||
|
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.
|
|
@ -0,0 +1,212 @@
|
||||||
|
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.
|
|
@ -0,0 +1,31 @@
|
||||||
|
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
|
|
@ -0,0 +1,106 @@
|
||||||
|
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
|
|
@ -0,0 +1,102 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.!.
|
||||||
|
!!!!!.
|
||||||
|
. '!!!!!.
|
||||||
|
.!!!. '!!!!!.
|
||||||
|
.!!!!!!!. '!!!!!.
|
||||||
|
.!!!!!!!!!' .!!!!!!!.
|
||||||
|
'!!!!!!!' .!!!!!!!!!'
|
||||||
|
'!!!!!. '!!!!!!!'
|
||||||
|
'!!!!!. '!!!'
|
||||||
|
'!!!!!. '
|
||||||
|
'!!!!!
|
||||||
|
'!'
|
||||||
|
|
||||||
|
|
||||||
|
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
|
|
@ -0,0 +1,84 @@
|
||||||
|
NE_SPC2000 v1.1
|
||||||
|
|
||||||
|
\ | ___
|
||||||
|
|\ \| ___
|
||||||
|
| \
|
||||||
|
|
||||||
|
NYA ELEKTRISKA
|
||||||
|
innovation information
|
||||||
|
|
||||||
|
|
||||||
|
DCPU-16 Hardware Info:
|
||||||
|
Name: SPC2000 - Suspension Chamber 2000
|
||||||
|
ID: 0x40e41d9d, version: 0x005e
|
||||||
|
Manufacturer: 0x1c6c8b36 (NYA_ELEKTRISKA)
|
||||||
|
|
||||||
|
|
||||||
|
======================= WARNING WARNING WARNING WARNING ========================
|
||||||
|
FERMIONS NEAR THE ACTIVATION RADIUS ARE CATASTROPHICALLY DESTROYED. DO NOT
|
||||||
|
USE NEAR EARTH OR MARS OR ANY OTHER FUTURE EARTH COLONIES. DO NOT TAMPER
|
||||||
|
WITH THE VACUUM DETECTOR. DO NOT USE IN AN UNEVEN GRAVITATIONAL FIELD. DO
|
||||||
|
NOT USE WHEN ROTATING. DO NOT USE WHEN ACCELERATING. ABSOLUTELY NO WARRANTY
|
||||||
|
IS PROVIDED, USE AT YOUR OWN RISK.
|
||||||
|
THE ZEF882 INCLUDED IN THIS SUSPENSION CHAMBER IS ILLEGAL IN ALL COUNTRIES.
|
||||||
|
======================= WARNING WARNING WARNING WARNING ========================
|
||||||
|
|
||||||
|
Description:
|
||||||
|
The SPC2000 is a deep sleep cell based on the ZEF882 time dilation field
|
||||||
|
generator (available from Polytron Corporation Incorporated).
|
||||||
|
It provides safe and nearly instantaneous time passage, making long journeys
|
||||||
|
in space much easier on the passengers, and allowing cargo to reach its
|
||||||
|
destination with minimal aging occurring.
|
||||||
|
Due to the nature of the ZEF882, it affects the entire vessel (50 meter
|
||||||
|
radius, and will only engage in a near vacuum. Once the SPC2000 is active,
|
||||||
|
the vessel will be almost nowhere to an external observer, and detection of
|
||||||
|
the vessel is beyond unlikely.
|
||||||
|
Because of the strong extra-dimensional acceleration and non-linear temporal
|
||||||
|
distortion that occurs, it's highly recommended that passengers are strapped
|
||||||
|
in and asleep when triggering the SCP2000.
|
||||||
|
|
||||||
|
|
||||||
|
Improvements:
|
||||||
|
* Added the ability to set the unit to skip to something other than the
|
||||||
|
default setting of milliseconds.
|
||||||
|
|
||||||
|
|
||||||
|
Interrupt behavior:
|
||||||
|
When a HWI is received by the SPC2000, it reads the A register and does one
|
||||||
|
of the following actions:
|
||||||
|
|
||||||
|
0: GET_STATUS
|
||||||
|
Sets the C register to 1 if the SPC2000 is ready to trigger. If it's not,
|
||||||
|
the B register is set to one of the following values:
|
||||||
|
0x0000: ######################## - EVACUATE VESSEL IMMEDIATELY
|
||||||
|
0x0001: Not in a vacuum
|
||||||
|
0x0002: Not enough fuel
|
||||||
|
0x0003: Gravitational forces too uneven
|
||||||
|
0x0004: Too much angular momentum
|
||||||
|
0x0005: One or more cell doors are open
|
||||||
|
0x0006: Mechanical error
|
||||||
|
0xffff: Unknown error - EVACUATE VESSEL IMMEDIATELY
|
||||||
|
1: SET_UNIT_TO_SKIP
|
||||||
|
Reads the B register, and reads a 64 bit number from memory address B
|
||||||
|
in big endian, and sets the number of units to skip to that number.
|
||||||
|
2: TRIGGER_DEVICE
|
||||||
|
Performs GET_STATUS, and if C is 0, triggers the SCP2000. The status can
|
||||||
|
be read as the result of the GET_STATUS call.
|
||||||
|
3: SET_SKIP_UNIT
|
||||||
|
Reads the B register, and sets the size of the unit to skip to one of:
|
||||||
|
0x0000: Milliseconds
|
||||||
|
0x0001: Minutes
|
||||||
|
0x0002: Days
|
||||||
|
0x0003: Years
|
||||||
|
|
||||||
|
|
||||||
|
A message from Ola:
|
||||||
|
Good morning,
|
||||||
|
|
||||||
|
Thanks for purchasing this piece of hardware! I hope it will enlighten you
|
||||||
|
and give you new hope in life. As this suspension chamber basically works as
|
||||||
|
a one way time machine, I suppose I should wish you a pleasant journey, and
|
||||||
|
ask of you to enjoy the future. It is yours now. All of it.
|
||||||
|
|
||||||
|
- Ola Kristian Carlsson
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.!.
|
||||||
|
!!!!!.
|
||||||
|
. '!!!!!.
|
||||||
|
.!!!. '!!!!!.
|
||||||
|
.!!!!!!!. '!!!!!.
|
||||||
|
.!!!!!!!!!' .!!!!!!!.
|
||||||
|
'!!!!!!!' .!!!!!!!!!'
|
||||||
|
'!!!!!. '!!!!!!!'
|
||||||
|
'!!!!!. '!!!'
|
||||||
|
'!!!!!. '
|
||||||
|
'!!!!!
|
||||||
|
'!'
|
||||||
|
|
||||||
|
|
||||||
|
M A C K A P A R M E D I A
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.---------------------.
|
||||||
|
----! DCPU-16 INFORMATION !-----------------------------------------------------
|
||||||
|
'---------------------'
|
||||||
|
|
||||||
|
Name: Mackapar Suspended Particle Exciter Display, Rev 3 (SPED-3)
|
||||||
|
ID: 0x42babf3c, version: 0x0003
|
||||||
|
Manufactorer: 0x1eb37e91 (MACKAPAR)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.-------------.
|
||||||
|
----! DESCRIPTION !-------------------------------------------------------------
|
||||||
|
'-------------'
|
||||||
|
|
||||||
|
The Mackapar Suspended Particle Exciter Display, Rev 3 ("the device") is a 3D
|
||||||
|
vector display unit. Straight lines are drawn between consecutive vertices in a
|
||||||
|
constant loop, with customizable colors per vertex. The effect is similar to a
|
||||||
|
free floating 3D model.
|
||||||
|
The area of the projected model is about 1x1x1 meters, and projection occurs
|
||||||
|
1.5 meters above the device.
|
||||||
|
The emitters are capable to rotate around the Z axis at 50 degrees per second,
|
||||||
|
allowing for easy animation of projected models.
|
||||||
|
Up to 128 lines may be projected, but the more lines are projected, the more
|
||||||
|
severe the flickering gets.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.--------------------.
|
||||||
|
----! 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 Map region. Sets the memory map offset to X, and the total number of vertices
|
||||||
|
to render to Y. See below for the encoding information.
|
||||||
|
|
||||||
|
2 Rotate device. Sets the target rotation for the device to X%360 degrees.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.-----------------.
|
||||||
|
----! VERTEX ENCODING !---------------------------------------------------------
|
||||||
|
'-----------------'
|
||||||
|
|
||||||
|
Each vertex occupies two words of information in the main DCPU RAM. The data is
|
||||||
|
encoded as (in LSB-0 format):
|
||||||
|
First word: YYYYYYYYXXXXXXXX
|
||||||
|
Second word: 00000ICCYYYYYYYY
|
||||||
|
Where XXXXXXXX is the X-coordinate of the vertex, YYYYYYYY is the Y-coordinate,
|
||||||
|
ZZZZZZZZ is the Z-coordinate, CC is color, and I is intensity.
|
||||||
|
Z is deeper into the screen, if the device is placed face up on the ground, this
|
||||||
|
translates to "up" relative to the user.
|
||||||
|
Possible color values are 0: black, 1: red, 2: green, 3: blue.
|
||||||
|
If the intensity bit is set, the color is drawn as more intense.
|
||||||
|
The black color is meant to barely be visible at all, except for in very dim
|
||||||
|
environments, or if the intensity bit is set.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.-------------.
|
||||||
|
----! STATE CODES !-------------------------------------------------------------
|
||||||
|
'-------------'
|
||||||
|
|
||||||
|
0x0000 STATE_NO_DATA No vertices queued up, device is in stand-by
|
||||||
|
0x0001 STATE_RUNNING The device is projecting lines
|
||||||
|
0x0002 STATE_TURNING The device is projecting lines and turning
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.-------------.
|
||||||
|
----! ERROR CODES !-------------------------------------------------------------
|
||||||
|
'-------------'
|
||||||
|
|
||||||
|
0x0000 ERROR_NONE There's been no error since the last poll.
|
||||||
|
0xffff ERROR_BROKEN There's been some major software or hardware problem,
|
||||||
|
try turning off and turning on the device again.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
COPYRIGHT 1988 MACKAPAR MEDIA ALL RIGHTS RESERVED DO NOT DISTRIBUTE
|
|
@ -0,0 +1,500 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
uint16_t ram[0x10000];
|
||||||
|
uint16_t ra, rb, rc, rx, ry, rz, ri, rj;
|
||||||
|
uint16_t rpc, rsp, rex, ria;
|
||||||
|
bool skip_next;
|
||||||
|
uint64_t ticks;
|
||||||
|
bool running;
|
||||||
|
bool intq_en;
|
||||||
|
#define MAX_INTQ_SIZE 256
|
||||||
|
uint16_t intq[MAX_INTQ_SIZE];
|
||||||
|
unsigned int intq_size;
|
||||||
|
uint8_t intq_head;
|
||||||
|
|
||||||
|
void intq_push(uint16_t v)
|
||||||
|
{
|
||||||
|
if (intq_size < MAX_INTQ_SIZE) {
|
||||||
|
intq[intq_head] = v;
|
||||||
|
intq_head = (intq_head + 1) % MAX_INTQ_SIZE;
|
||||||
|
intq_size++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t intq_pop()
|
||||||
|
{
|
||||||
|
if (intq_size > 0) {
|
||||||
|
return intq[(intq_head-intq_size--) % MAX_INTQ_SIZE];
|
||||||
|
} else
|
||||||
|
return 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
ra = rb = rc = rx = ry = rz = ri = rj = 0;
|
||||||
|
rpc = rsp = rex = ria = 0;
|
||||||
|
|
||||||
|
intq_en = false;
|
||||||
|
intq_size = 0;
|
||||||
|
intq_head = 0;
|
||||||
|
|
||||||
|
skip_next = false;
|
||||||
|
ticks = 0;
|
||||||
|
|
||||||
|
running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*dev_t)(void);
|
||||||
|
|
||||||
|
struct dev_entry {
|
||||||
|
uint32_t vendor;
|
||||||
|
uint32_t product;
|
||||||
|
uint16_t version;
|
||||||
|
void (*irqh)();
|
||||||
|
void (*init)();
|
||||||
|
void (*free)();
|
||||||
|
void (*tick)();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dev_entry iodevs[] = {
|
||||||
|
{ 0, 0, 0, NULL, NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t lit[] = {
|
||||||
|
0xffff, 0, 1, 2, 3, 4, 5, 6,
|
||||||
|
7, 8, 9, 10, 11, 12, 13, 14,
|
||||||
|
15, 16, 17, 18, 19, 20, 21, 22,
|
||||||
|
23, 24, 25, 26, 27, 28, 29, 30
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t *val(int operand, bool is_a)
|
||||||
|
{
|
||||||
|
switch (operand) {
|
||||||
|
case 0x00:
|
||||||
|
return &ra;
|
||||||
|
case 0x01:
|
||||||
|
return &rb;
|
||||||
|
case 0x02:
|
||||||
|
return &rc;
|
||||||
|
case 0x03:
|
||||||
|
return ℞
|
||||||
|
case 0x04:
|
||||||
|
return &ry;
|
||||||
|
case 0x05:
|
||||||
|
return &rz;
|
||||||
|
case 0x06:
|
||||||
|
return &ri;
|
||||||
|
case 0x07:
|
||||||
|
return &rj;
|
||||||
|
case 0x08:
|
||||||
|
return &ram[ra];
|
||||||
|
case 0x09:
|
||||||
|
return &ram[rb];
|
||||||
|
case 0x0a:
|
||||||
|
return &ram[rc];
|
||||||
|
case 0x0b:
|
||||||
|
return &ram[rx];
|
||||||
|
case 0x0c:
|
||||||
|
return &ram[ry];
|
||||||
|
case 0x0d:
|
||||||
|
return &ram[rz];
|
||||||
|
case 0x0e:
|
||||||
|
return &ram[ri];
|
||||||
|
case 0x0f:
|
||||||
|
return &ram[rj];
|
||||||
|
case 0x10:
|
||||||
|
ticks++;
|
||||||
|
return &ram[ra+ram[rpc++]];
|
||||||
|
case 0x11:
|
||||||
|
ticks++;
|
||||||
|
return &ram[rb+ram[rpc++]];
|
||||||
|
case 0x12:
|
||||||
|
ticks++;
|
||||||
|
return &ram[rc+ram[rpc++]];
|
||||||
|
case 0x13:
|
||||||
|
ticks++;
|
||||||
|
return &ram[rx+ram[rpc++]];
|
||||||
|
case 0x14:
|
||||||
|
ticks++;
|
||||||
|
return &ram[ry+ram[rpc++]];
|
||||||
|
case 0x15:
|
||||||
|
ticks++;
|
||||||
|
return &ram[rz+ram[rpc++]];
|
||||||
|
case 0x16:
|
||||||
|
ticks++;
|
||||||
|
return &ram[ri+ram[rpc++]];
|
||||||
|
case 0x17:
|
||||||
|
ticks++;
|
||||||
|
return &ram[rj+ram[rpc++]];
|
||||||
|
case 0x18:
|
||||||
|
return (is_a ? &ram[rsp++] : &ram[--rsp]);
|
||||||
|
case 0x19:
|
||||||
|
return &ram[rsp];
|
||||||
|
case 0x1a:
|
||||||
|
ticks++;
|
||||||
|
return &ram[rsp+ram[rpc++]];
|
||||||
|
case 0x1b:
|
||||||
|
return &rsp;
|
||||||
|
case 0x1c:
|
||||||
|
return &rpc;
|
||||||
|
case 0x1d:
|
||||||
|
return &rex;
|
||||||
|
case 0x1e:
|
||||||
|
ticks++;
|
||||||
|
return &ram[ram[rpc++]];
|
||||||
|
case 0x1f:
|
||||||
|
ticks++;
|
||||||
|
return &ram[rpc++]; /* FIXME: write to literal */
|
||||||
|
default:
|
||||||
|
return &lit[operand-0x20];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oNOP(uint16_t *pa, uint16_t *pb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void oSET(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
*b = *a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oADD(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
uint16_t pre = *b;
|
||||||
|
|
||||||
|
*b += *a;
|
||||||
|
rex = (pre>*b ? 0x0001 : 0x0000);
|
||||||
|
ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oSUB(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
uint16_t pre = *b;
|
||||||
|
|
||||||
|
*b -= *a;
|
||||||
|
rex = (pre<*b ? 0xffff : 0x0000);
|
||||||
|
ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oMUL(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
uint32_t res = *b * *a;
|
||||||
|
|
||||||
|
*b = res & 0xffff;
|
||||||
|
rex = (res>>16) & 0xffff;
|
||||||
|
ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oMLI(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
int32_t res = (int16_t)*a * (int16_t)*b;
|
||||||
|
|
||||||
|
*b = (uint32_t)res & 0xffff;
|
||||||
|
rex = ((uint32_t)res>>16) & 0xffff;
|
||||||
|
ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oDIV(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
if (*a) {
|
||||||
|
rex = ((uint32_t)*b<<16) / *a;
|
||||||
|
*b /= *a;
|
||||||
|
} else {
|
||||||
|
*b = rex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oDVI(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
if (*a) {
|
||||||
|
rex = ((int32_t)*b<<16) / (int16_t)*a;
|
||||||
|
*b = (int16_t)*b / (int16_t)*a;
|
||||||
|
} else {
|
||||||
|
*b = rex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oMOD(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
if (*a) {
|
||||||
|
*b %= *a;
|
||||||
|
} else {
|
||||||
|
*b = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oMDI(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
if (*a) {
|
||||||
|
*b = (int16_t)*b / (int16_t)*a;
|
||||||
|
} else {
|
||||||
|
*b = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oAND(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
*b &= *a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oBOR(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
*b |= *a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oXOR(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
*b ^= *a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oSHR(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
uint16_t t;
|
||||||
|
|
||||||
|
t = (uint32_t)*b >> *a;
|
||||||
|
rex = ((uint64_t)*b << 16) >> *a;
|
||||||
|
*b = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oASR(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
uint16_t t;
|
||||||
|
|
||||||
|
t = *b >> *a;
|
||||||
|
rex = ((uint32_t)*b << 16) >> *a;
|
||||||
|
*b = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oSHL(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
uint16_t t;
|
||||||
|
|
||||||
|
t = *b << *a;
|
||||||
|
rex = ((uint64_t)*b << *a) >> 16;
|
||||||
|
*b = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DOIF(c) if (!(c)) skip_next = true
|
||||||
|
|
||||||
|
void oIFB(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
DOIF((*b & *a) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void oIFC(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
DOIF((*b & *a) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void oIFE(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
DOIF(*b == *a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void oIFN(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
DOIF(*b != *a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void oIFG(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
DOIF(*b > *a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void oIFA(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
DOIF((int16_t)*b > (int16_t)*a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void oIFL(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
DOIF(*b < *a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void oIFU(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
DOIF((int16_t)*b < (int16_t)*a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void oADX(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
uint16_t t = *b;
|
||||||
|
|
||||||
|
*b += *a + rex;
|
||||||
|
rex = (t>*b ? 0x0001 : 0x0000);
|
||||||
|
ticks += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oSBX(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
uint16_t t = *b;
|
||||||
|
|
||||||
|
*b -= *a - rex;
|
||||||
|
rex = (t<*b ? 0xffff : 0x0000);
|
||||||
|
ticks += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oSTI(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
*b = *a;
|
||||||
|
ri++;
|
||||||
|
rj++;
|
||||||
|
ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oSTD(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
*b = *a;
|
||||||
|
ri--;
|
||||||
|
rj--;
|
||||||
|
ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oJSR(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
ram[--rsp] = rpc;
|
||||||
|
rpc = *a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oINT(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
intq_push(*a);
|
||||||
|
ticks += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oIAG(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
*a = ria;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oIAS(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
ria = *a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void oRFI(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
intq_en = false;
|
||||||
|
ra = ram[rsp++];
|
||||||
|
rpc = ram[rsp++];
|
||||||
|
}
|
||||||
|
|
||||||
|
void oIAQ(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
intq_en = (*a != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void oHWN(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
*a = sizeof(iodevs) / sizeof(struct dev_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void oHWQ(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
uint16_t idx = *a;
|
||||||
|
|
||||||
|
if (idx < sizeof(iodevs) / sizeof(struct dev_entry)) {
|
||||||
|
ra = iodevs[idx].product & 0xffff;
|
||||||
|
rb = (iodevs[idx].product >> 16) & 0xffff;
|
||||||
|
rc = iodevs[idx].version;
|
||||||
|
rx = iodevs[idx].vendor & 0xffff;
|
||||||
|
ry = (iodevs[idx].vendor >> 16) & 0xffff;
|
||||||
|
} else {
|
||||||
|
ra = rb = rc = rx = ry = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oHWI(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
uint16_t idx = *a;
|
||||||
|
|
||||||
|
if (idx < sizeof(iodevs) / sizeof(struct dev_entry)) {
|
||||||
|
if (iodevs[idx].irqh)
|
||||||
|
iodevs[idx].irqh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void oHLT(uint16_t *a, uint16_t *b)
|
||||||
|
{
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*op_t)(uint16_t *, uint16_t *);
|
||||||
|
|
||||||
|
const op_t ops[] = {
|
||||||
|
oNOP, oSET, oADD, oSUB, oMUL, oMLI, oDIV, oDVI, /* 00-07 */
|
||||||
|
oMOD, oMDI, oAND, oBOR, oXOR, oSHR, oASR, oSHL, /* 08-0f */
|
||||||
|
oIFB, oIFC, oIFE, oIFN, oIFG, oIFA, oIFL, oIFU, /* 10-17 */
|
||||||
|
oNOP, oNOP, oADX, oSBX, oNOP, oNOP, oSTI, oSTD /* 18-1f */
|
||||||
|
};
|
||||||
|
|
||||||
|
const op_t sops[] = {
|
||||||
|
oNOP, oJSR, oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, /* 00-07 */
|
||||||
|
oINT, oIAG, oIAS, oRFI, oIAQ, oNOP, oNOP, oNOP, /* 08-0f */
|
||||||
|
oHWN, oHWQ, oHWI, oNOP, oNOP, oNOP, oNOP, oNOP, /* 10-17 */
|
||||||
|
oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, oNOP, oHLT /* 18-1f */
|
||||||
|
};
|
||||||
|
|
||||||
|
void dumpregs()
|
||||||
|
{
|
||||||
|
printf("%4s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s\n",
|
||||||
|
"PC","SP","A","B","C","X","Y","Z","I","J","EX","IA");
|
||||||
|
printf("%04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx %04hx\n",
|
||||||
|
rpc, rsp, ra, rb, rc, rx, ry, rz, ri, rj, rex, ria);
|
||||||
|
}
|
||||||
|
|
||||||
|
void next()
|
||||||
|
{
|
||||||
|
uint16_t ir;
|
||||||
|
int opcode, a, b;
|
||||||
|
uint16_t *pa, *pb;
|
||||||
|
op_t f;
|
||||||
|
uint16_t i;
|
||||||
|
|
||||||
|
if ((!intq_en) && (intq_size > 0)) {
|
||||||
|
i = intq_pop();
|
||||||
|
if (ria != 0) {
|
||||||
|
intq_en = true;
|
||||||
|
ram[--rsp] = rpc;
|
||||||
|
ram[--rsp] = ra;
|
||||||
|
rpc = ria;
|
||||||
|
ra = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dumpregs();
|
||||||
|
|
||||||
|
ir = ram[rpc++];
|
||||||
|
|
||||||
|
opcode = ir & 0x001f;
|
||||||
|
a = (ir >> 5) & 0x001f;
|
||||||
|
b = (ir >> 10) & 0x003f;
|
||||||
|
|
||||||
|
if (opcode == 0) { /* special instruction */
|
||||||
|
f = sops[b];
|
||||||
|
pa = val(a, true);
|
||||||
|
pb = NULL;
|
||||||
|
} else {
|
||||||
|
f = ops[opcode];
|
||||||
|
pa = val(a, true);
|
||||||
|
pb = val(b, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!skip_next)
|
||||||
|
f(pa, pb);
|
||||||
|
else
|
||||||
|
skip_next = false;
|
||||||
|
|
||||||
|
ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
while (running) next();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
Loading…
Reference in New Issue