Skip to content

Instantly share code, notes, and snippets.

@Blecki
Created June 18, 2015 02:51
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Blecki/b96ebcbddd701f215b19 to your computer and use it in GitHub Desktop.
Save Blecki/b96ebcbddd701f215b19 to your computer and use it in GitHub Desktop.
Specification of the IN8 (inate) 8-bit CPU
Registers
{ Named registers implemented by the IN8 CPU.
A, B - Accumulator
C, D, E - Scratch
H, L - Scratch, and memory access
IP - Special 16-bit instruction pointer
SP - Special 16-bit stack pointer
O - Read-only overflow register
HL - A virtual register formed by interpretting H and L as a single 16-bit value.
* Encodable operands
Encoding Name Purpose
000 A Accumulator
001 B Accumulator
010 C Scratch
011 D Scratch
100 E Scratch
101 H High-byte of a memory address
110 L Low-byte of a memory address
111 N Next-word. Not valid for instructions that write.
}
IO Ports
{ Device attachments for the IN8.
The IN8 supports up to 256 8-bit IO ports.
Different device attachment points on the standard configuration motherboard are mapped to specific IO ports.
Most common IN8 hardware configuration
{
ATTACHMENT POINT IO PORT(S)
Power supply control line 0
Dedicated hardware clock 1
Primary display ribbon 4, 5
Drive ribbon(s) 16 through 23, in pairs
Variable-width serial ports 32, 33, 34, 35
}
}
Memory Mapping
{ Memory mapping for devices
The IN8 supports mapping 64 memory pages simultaneously. Only whole pages can be mapped.
Only pages 64 through 128 are available for mapping.
Which devices can use mapped memory is dependent on the hardware configuration.
}
Clock
{ System clock
The IN8 implements a 32 bit system clock with cycle-count precision.
Under ideal operating conditions, it is possible to overflow the hardware clock in a few minutes of computation.
Do not rely on the clock for long-term timing.
}
Instruction Encoding for basic instructions
{ The manner in which instructions are encoded into 8 bits
Paired operand instructions are the set that take 2 operands.
The first operand is always either A or B.
The second operand is any of A, B, C, D, E, H, L, or N.
[0000] [0] [000]
| | L--- Second operand - See operand encoding table
| L--- First operand - 0 = A; 1 = B
L--- Instruction code
Single operand instructions are the set that takes only 1 operand.
Single operand instructions can refer to all 8 registers.
[00000] [000]
| L--- Operand - See operand encoding table
L--- Instruction code
}
Instruction table
{ Every instruction implemented on the IN8 CPU.
* In a binary encoding, sequences in [brackets] can be expanded to every possible sequence.
* In this table, a binary code prefixed with '-' is an absolute code. The sequences in [brackets] should not be expanded, the brackets
remain soley for readability.
Cycles Binary Mnemonic Purpose
1 0000 [0] [000] MTA 1 2 Copy 2 to 1.
1 0001 [0] [000] MFA 1 2 Copy 1 to 2, unless 2 is N.
* In an assembler, 'MOV 1, 2' can be used, though A or B must always appear as an argument.
* Some instructions become non-operations and their encoding can be reused for other instructions.
4 -0000 [0] [000] CAL Interpret HL as an address, push IP to the stack, jump to HL. Replaces MTA A A
4 -0000 [1] [001] RET Pop two words from the stack to HL, jump to HL. Replaces MTA B B
-0001 [0] [000] SSR Shift A right by B bits Replaces MFA A A
-0001 [1] [001] SSL Shift A left by B bits Replaces MFA B B
-0001 [0] [001] IAQ Set HL as the interupt handler address. Replaces MFA A B - Same as MTA B A
-0001 [1] [000] RFQ Return from interupt handler. Replaces MFA B A - Same as MTA A B
* Since MFA cannot have a second operand of N, the encoding of that instruction is available.
2 -0001 [0] [111] NOT 1 Perform a binary not operation on 1.
* In all math operators, the result is stored in 2.
* In most cases, the accumulator operand is the second argument, but is encoded first.
* Math operations also set the overflow register.
2 0010 [0] [000] ADD 2 1 Add 2 to 1.
2 0011 [0] [000] SUB 2 1 Subtract 2 from 1.
8 0100 [0] [000] MUL 2 1 Multiply 2 by 1.
32 0101 [0] [000] DIV 1 2 Divide 1 by 2.
32 0110 [0] [000] MOD 1 2 Divide 1 by 2 and store the remainder in 1.
2 0111 [0] [000] AND 2 1 Perform a binary and between 2 and 1.
2 1000 [0] [000] BOR 2 1 Perform a binary or between 2 and 1.
2 1001 [0] [000] XOR 2 1 Perform a binary xor between 2 and 1.
* No-op math operations give us 4 more spots to fill in with useful operations.
1 -0111 [0] [000] OVE A Store O in A Replaces AND A A (Result is always A)
1 -0111 [1] [001] OVE B Store O in B Replaces AND B B (Result is always B)
8 -1000 [0] [000] MUS Multiply A by B, store the result in B; treat both as signed. Replaces BOR A A (Result is always A)
32 -1000 [1] [001] DIS Divide A by B, store the result in B; treat both as signed. Replaces BOR B B (Result is always B)
* XOR cannot be replaced: XOR A A is always equal to 0 but not always equal to A. Though, it makes little sense and may be replaced in
desperation. Code using it can replace XOR A A with MTA A 0.
* Similarily to XOR, SUB A A and SUB B B are possible points of expansion, as any sane program can replace these with MTA A 0 or MTA B 0.
* SP encodes the stack pointer. The stack grows downwards from the end of memory space.
4 10100 [000] PSH 1 Push 1 to the stack, decrement SP.
4 10101 [000] POP 1 Copy the top value on the stack to 1, increment SP, unless 1 is N.
2 10110 [000] PEK 1 Copy the value on the top of the stack to 1, unless 1 is N.
* Since POP and PEK can't write to N, reuse their encodings for some other stack-related instructions.
2 -10101 [111] RSP Load the value of SP into HL.
2 -10110 [111] SSP Set the value of SP from HL.
* Instructions for loading and storing to ram.
8 10111 [000] LOD 1 Interpret HL as a 16-bit memory address and load the value from that address into 1, unless 1 is N.
8 11000 [000] STR 1 Interpret HL as a 16-bit memory address and store the value of 1 into that address.
* LOD can't write to N. Use it for a two-word literal load to HL
2 -10111 [111] LLH Read the next two words in the code stream into HL.
* Miscelaneous instructions, such as non-branching jumps.
12 -11001 [000] LDW Load a double word. Interpret HL as a 16-bit memory address and load two values at that address into
A and B. The address must be aligned to 2 bytes. That is, L must be an even number.
12 -11001 [001] SDW Store a double word. Interpret HL as a 16-bit memory address and write the values of A and B to that
address. The address must be aligned to 2 bytes. That is, L must be an even number.
1 -11001 [010] STP Stop execution immediately.
2 -11001 [011] CFP Copy Frame Pointer. Copy the value of DE into HL. Ease implementation of frame pointers.
2 -11001 [100] SWP Swap the value of D with H and E with L. Ease manipulation of two memory pointers.
2 -11001 [101] RIP Load the value of IP into HL.
2 -11001 [110] JMP Interpret HL as a 16-bit memory address and jump to it. This is the same as setting IP to HL.
2 -11001 [111] JPL Interpret the next two words in the code stream as an address and jump to it. This also modifies HL.
* Branching functions
* Each will jump to the location stored in HL if it's condition is true.
8 -11010 [000] BIE A equals B
8 -11010 [001] BNE A does not equal B
8 -11010 [010] BGT A is greater than B
8 -11010 [011] BLT A is less than B
8 -11010 [100] BEG A is equal to or greater than B
8 -11010 [101] BEL A is equal to or less than B
8 -11010 [110] BSL A is less than B, treated as signed bytes
8 -11010 [111] BSG A is greater than B, treated as signed bytes
* These instructions make working with the HL virtual register easier.
* They also mean that HL can be used for 16 bit addition and subtraction.
4 11011 [000] CAD 1 Add 1 to L, carrying overflow into H
4 11100 [000] CSB 1 Subtract 1 from L, pulling overflow from H
* These instructions make working with the stack easier.
4 11101 [000] ADS 1 Add 1 to SP
4 11110 [000] SBS 1 Subtract 1 from SP
* I/O port handling instructions, short jumps
2 -11111 [000] OUT Write to an IO port. A contains the port number, B contains the byte to write
2 -11111 [001] IIN Read from an IO port. A contains the port number, data is placed in B
-11111 [010] LLD Long literal load to DE
-11111 [011] JIG If HL >= DE, interpret the next two words in the code stream as an address and jump to it. This also modifies HL.
-11111 [100]
4 -11111 [101] CLK Load the current clock value into DEHL
2 -11111 [110] SFJ Short forward jump. Read the next word and add it to IP
2 -11111 [111] SBJ Short backward jump. Read the next word and subtract it from IP
}
Samples
{
Assembly syntax
{
White space before an instruction mnemonic, after a period, and before newlines is trimmed.
Instructions are delimited by periods (.) or new-lines (\n, \r).
Comments begin with ; and extend to the end of the line.
Labels are : followed by a sequence of characters except periods or newlines such as ':LABEL'.
* Labels can contain spaces, but trailing whitespace will be trimmed.
* To refer to a label, all the whitespace has to match too.
$LABEL will be replaced with the value assigned to the label.
Literals are specified in the format '0X##', where '#' is a hex digit.
Instruction refering to 'N' should have the literal value encoded immediately after them.
* Example: PSH N. 0X02
* Here we have the instruction 'PSH N', followed by the literal '0X02', rather than a more difficult to parse 'PSH 0X02'.
Instructions can be condensed. 'PSH N' can be written as 'PSHN'. Each instruction has a unique condensed name.
}
Function call
{
PSH N. 0X02 ;Push arguments to stack
PSH N. 0X03
LLT. $FUNCTION
CAL
ADS N. 0X02 ;Pop arguments from stack
;A now contains 0X05
:FUNCTION
;Fetch an argument from the stack
RSP
CAD N. 0X03 ;Second argument is at SP + 2. (2 bytes used for return address)
STR C
CSB N. 0X01
STR D ;Arguments are now in CD.
MTA A C
ADD A D ;Do something trivial with them
RET ;Return value is in A
; In advanced cases, DE could be used as a frame pointer to implement some higher-level language
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment