8 general-purpose 8-bit numeric registers R0-R7.
- R5 is reserved as the interrupt mask (IM)
- R6 is reserved as the interrupt status (IS)
- R7 is reserved as the stack pointer (SP)
These registers only hold values between 0-255. After performing math on registers in the emulator, bitwise-AND the result with 0xFF (255) to keep the register values in that range.
PC
: Program Counter, address of the currently executing instructionIR
: Instruction Register, contains a copy of the currently executing instructionMAR
: Memory Address Register, holds the memory address we're reading or writingMDR
: Memory Data Register, holds the value to write or the value just readFL
: Flags, see below
The flags register FL
holds the current flags status. These flags
can change based on the operands given to the CMP
opcode.
The register is made up of 8 bits. If a particular bit is set, that flag is "true".
FL
bits: 00000LGE
L
Less-than: during aCMP
, set to 1 if registerA is less than registerB, zero otherwise.G
Greater-than: during aCMP
, set to 1 if registerA is greater than registerB, zero otherwise.E
Equal: during aCMP
, set to 1 if registerA is equal to registerB, zero otherwise.
The LS-8 has 8-bit addressing, so can address 256 bytes of RAM total.
Memory map:
top of RAM
+-----------------------+
| FF I7 vector | Interrupt vector table
| FE I6 vector |
| FD I5 vector |
| FC I4 vector |
| FB I3 vector |
| FA I2 vector |
| F9 I1 vector |
| F8 I0 vector |
| F7 Reserved |
| F6 Reserved |
| F5 Reserved |
| F4 Key pressed | Holds the most recent key pressed on the keyboard
| F3 Start of Stack |
| F2 [more stack] | Stack grows down
| ... |
| 01 [more program] |
| 00 Program entry | Program loaded upward in memory starting at 0
+-----------------------+
bottom of RAM
The SP points at the value at the top of the stack (most recently pushed), or at
address F4
if the stack is empty.
There are 8 interrupts, I0-I7.
When an interrupt occurs from an external source or from an INT
instruction, the appropriate bit in the IS register will be set.
Prior to instruction fetch, the following steps occur:
- The IM register is bitwise AND-ed with the IS register and the
results stored as
maskedInterrupts
. - Each bit of
maskedInterrupts
is checked, starting from 0 and going up to the 7th bit, one for each interrupt. - If a bit is found to be set, follow the next sequence of steps. Stop
further checking of
maskedInterrupts
.
If a bit is set:
- Disable further interrupts.
- Clear the bit in the IS register.
- The
PC
register is pushed on the stack. - The
FL
register is pushed on the stack. - Registers R0-R6 are pushed on the stack in that order.
- The address (vector in interrupt terminology) of the appropriate handler is looked up from the interrupt vector table.
- Set the PC is set to the handler address.
While an interrupt is being serviced (between the handler being called
and the IRET
), further interrupts are disabled.
See IRET
, below, for returning from an interrupt.
- 0: Timer interrupt. This interrupt triggers once per second.
- 1: Keyboard interrupt. This interrupt triggers when a key is pressed.
The value of the key pressed is stored in address
0xF4
.
When the LS-8 is booted, the following steps occur:
R0
-R6
are cleared to0
.R7
is set to0xF4
.PC
andFL
registers are cleared to0
.- RAM is cleared to
0
.
Subsequently, the program can be loaded into RAM starting at address 0x00
.
- The instruction pointed to by the
PC
is fetched from RAM, decoded, and executed. - If the instruction does not set the
PC
itself, thePC
is advanced to point to the subsequent instruction. - If the CPU is not halted by a
HLT
instruction, go to step 1.
Some instructions set the PC directly. These are:
- CALL
- INT
- IRET
- JMP
- JNE
- JEQ
- JGT
- JGE
- JLT
- JLE
- RET
In these cases, the PC
does not automatically advance to the next instruction,
since it was set explicitly.
Meanings of the bits in the first byte of each instruction: AABCDDDD
AA
Number of operands for this opcode, 0-2B
1 if this is an ALU operationC
1 if this instruction sets the PCDDDD
Instruction identifier
The number of operands AA
is useful to know because the total number of bytes in any
instruction is the number of operands + 1 (for the opcode). This
allows you to know how far to advance the PC
with each instruction.
It might also be useful to check the other bits in an emulator implementation, but there are other ways to code it that don't do these checks.
Glossary:
-
immediate: takes a constant integer value as an argument
-
register: takes a register number as an argument
-
iiiiiiii
: 8-bit immediate value -
00000rrr
: Register number -
00000aaa
: Register number -
00000bbb
: Register number
Machine code values shown in both binary and hexadecimal.
This is an instruction handled by the ALU.
ADD registerA registerB
Add the value in two registers and store the result in registerA.
Machine code:
10100000 00000aaa 00000bbb
A0 0a 0b
This is an instruction handled by the ALU.
AND registerA registerB
Bitwise-AND the values in registerA and registerB, then store the result in registerA.
Machine code:
10101000 00000aaa 00000bbb
A8 0a 0b
CALL register
Calls a subroutine (function) at the address stored in the register.
- The address of the instruction directly after
CALL
is pushed onto the stack. This allows us to return to where we left off when the subroutine finishes executing. - The PC is set to the address stored in the given register. We jump to that location in RAM and execute the first instruction in the subroutine. The PC can move forward or backwards from its current location.
Machine code:
01010000 00000rrr
50 0r
This is an instruction handled by the ALU.
CMP registerA registerB
Compare the values in two registers.
-
If they are equal, set the Equal
E
flag to 1, otherwise set it to 0. -
If registerA is less than registerB, set the Less-than
L
flag to 1, otherwise set it to 0. -
If registerA is greater than registerB, set the Greater-than
G
flag to 1, otherwise set it to 0.
Machine code:
10100111 00000aaa 00000bbb
A7 0a 0b
This is an instruction handled by the ALU.
DEC register
Decrement (subtract 1 from) the value in the given register.
Machine code:
01100110 00000rrr
66 0r
This is an instruction handled by the ALU.
DIV registerA registerB
Divide the value in the first register by the value in the second, storing the result in registerA.
If the value in the second register is 0, the system should print an error message and halt.
Machine code:
10100011 00000aaa 00000bbb
A3 0a 0b
HLT
Halt the CPU (and exit the emulator).
Machine code:
00000001
01
This is an instruction handled by the ALU.
INC register
Increment (add 1 to) the value in the given register.
Machine code:
01100101 00000rrr
65 0r
INT register
Issue the interrupt number stored in the given register.
This will set the _n_th bit in the IS
register to the value in the given
register.
Machine code:
01010010 00000rrr
52 0r
IRET
Return from an interrupt handler.
The following steps are executed:
- Registers R6-R0 are popped off the stack in that order.
- The
FL
register is popped off the stack. - The return address is popped off the stack and stored in
PC
. - Interrupts are re-enabled
Machine code:
00010011
13
JEQ register
If equal
flag is set (true), jump to the address stored in the given register.
Machine code:
01010101 00000rrr
55 0r
JGE register
If greater-than
flag or equal
flag is set (true), jump to the address stored
in the given register.
01011010 00000rrr
5A 0r
JGT register
If greater-than
flag is set (true), jump to the address stored in the given
register.
Machine code:
01010111 00000rrr
57 0r
JLE register
If less-than
flag or equal
flag is set (true), jump to the address stored in the given
register.
01011001 00000rrr
59 0r
JLT register
If less-than
flag is set (true), jump to the address stored in the given
register.
Machine code:
01011000 00000rrr
58 0r
JMP register
Jump to the address stored in the given register.
Set the PC
to the address stored in the given register.
Machine code:
01010100 00000rrr
54 0r
JNE register
If E
flag is clear (false, 0), jump to the address stored in the given
register.
Machine code:
01010110 00000rrr
56 0r
LD registerA registerB
Loads registerA with the value at the memory address stored in registerB.
This opcode reads from memory.
Machine code:
10000011 00000aaa 00000bbb
83 0a 0b
LDI register immediate
Set the value of a register to an integer.
Machine code:
10000010 00000rrr iiiiiiii
82 0r ii
This is an instruction handled by the ALU.
MOD registerA registerB
Divide the value in the first register by the value in the second, storing the remainder of the result in registerA.
If the value in the second register is 0, the system should print an error message and halt.
Machine code:
10100100 00000aaa 00000bbb
A4 0a 0b
This is an instruction handled by the ALU.
MUL registerA registerB
Multiply the values in two registers together and store the result in registerA.
Machine code:
10100010 00000aaa 00000bbb
A2 0a 0b
NOP
No operation. Do nothing for this instruction.
Machine code:
00000000
00
This is an instruction handled by the ALU.
NOT register
Perform a bitwise-NOT on the value in a register, storing the result in the register.
Machine code:
01101001 00000rrr
69 0r
This is an instruction handled by the ALU.
OR registerA registerB
Perform a bitwise-OR between the values in registerA and registerB, storing the result in registerA.
Machine code:
10101010 00000aaa 00000bbb
AA 0a 0b
POP register
Pop the value at the top of the stack into the given register.
- Copy the value from the address pointed to by
SP
to the given register. - Increment
SP
.
Machine code:
01000110 00000rrr
46 0r
PRA register
pseudo-instruction
Print alpha character value stored in the given register.
Print to the console the ASCII character corresponding to the value in the register.
Machine code:
01001000 00000rrr
48 0r
PRN register
pseudo-instruction
Print numeric value stored in the given register.
Print to the console the decimal integer value that is stored in the given register.
Machine code:
01000111 00000rrr
47 0r
PUSH register
Push the value in the given register on the stack.
- Decrement the
SP
. - Copy the value in the given register to the address pointed to by
SP
.
Machine code:
01000101 00000rrr
45 0r
RET
Return from subroutine.
Pop the value from the top of the stack and store it in the PC
.
Machine Code:
00010001
11
This is an instruction handled by the ALU.
Shift the value in registerA left by the number of bits specified in registerB, filling the low bits with 0.
10101100 00000aaa 00000bbb
AC 0a 0b
This is an instruction handled by the ALU.
Shift the value in registerA right by the number of bits specified in registerB, filling the high bits with 0.
10101101 00000aaa 00000bbb
AD 0a 0b
ST registerA registerB
Store value in registerB in the address stored in registerA.
This opcode writes to memory.
Machine code:
10000100 00000aaa 00000bbb
84 0a 0b
This is an instruction handled by the ALU.
SUB registerA registerB
Subtract the value in the second register from the first, storing the result in registerA.
Machine code:
10100001 00000aaa 00000bbb
A1 0a 0b
This is an instruction handled by the ALU.
XOR registerA registerB
Perform a bitwise-XOR between the values in registerA and registerB, storing the result in registerA.
Machine code:
10101011 00000aaa 00000bbb
AB 0a 0b