-
Notifications
You must be signed in to change notification settings - Fork 0
Instructions
This is Version 2 of the CPU design.
These instructions are implemented in the CPU hardware directly.
Four-character fixed-length mnemonics are used to simplify the assembler implementation.
The Flags column indicates how flags are affected by the operation:
-: Flag is not affected
0: Flag is cleared
1: Flag is set
S, Z, C, V: Flag value depends on result of operation
| Mnemonic | Description | Mode |
SZCV (Flags) |
Notes |
|---|---|---|---|---|
LDAL |
Immediate value into AA, lower nibble |
IMM | ---- |
|
LDAH |
Immediate value into AA, upper nibble |
IMM | ---- |
|
LDBL |
Immediate value into AB, lower nibble |
IMM | ---- |
|
LDBH |
Immediate value into AB, upper nibble |
IMM | ---- |
|
LJLL |
Immediate value into JL, lower nibble |
IMM | ---- |
|
LJLH |
Immediate value into JL, upper nibble |
IMM | ---- |
|
LJHL |
Immediate value into JH, lower nibble |
IMM | ---- |
|
LJHH |
Immediate value into JH, upper nibble |
IMM | ---- |
|
LOAD |
Memory into AA
|
IND | ---- |
|
STOR |
AA into memory |
IND | ---- |
|
MOVE |
Move register to/from AA
|
DIR | ---- |
|
PUSH |
Push register onto the stack | IMP | ---- |
Supports registers AA and FL only |
POPP |
Pop stack into register | IMP | ---- |
Supports registers AA and FL only |
COMP |
AA ^ AB, discard result |
DIR | 0Z00 |
Z flag set if AA and AB are the same |
SUBB |
AA <- AA - AB
|
DIR | SZCV |
Z flag set if AA and AB are the same |
ADDD |
AA <- AA + AB
|
DIR | SZCV |
|
ANDD |
AA <- AA & AB
|
DIR | 0Z00 |
|
ORRR |
AA <- AA | AB
|
DIR | 0Z00 |
|
XORR |
AA <- AA ^ AB
|
DIR | 0Z00 |
|
NAND |
AA <- ~(AA & AB) |
DIR | 0Z00 |
|
NORR |
AA <- ~(AA | AB) |
DIR | 0Z00 |
|
NOTT |
AA <- ~(AA) |
DIR | 0Z00 |
1's complement |
NEGA |
AA <- 0 - AA
|
DIR | 0Z00 |
2's complement |
XNOR |
AA <- ~(AA ^ AB) |
DIR | 0Z00 |
|
SHRL |
Shift right logical on AA
|
DIR | 0ZC0 |
Bit 0 is shifted into C; bit 7 is set to 0 |
SHLL |
Shift left logical on AA
|
DIR | 0ZC0 |
Bit 7 is shifted into C; bit 0 is set to 0 |
SHRA |
Shift right arithmetic on AA
|
DIR | 0ZC0 |
Bit 7 is shifted into itself and bit 6; bit 0 is shifted into C
|
SRLC |
Shift AA right using Carry flag |
DIR | 0ZC0 |
C is shifted into bit 7, bit 0 shifted into C
|
SLLC |
Shift AA left using Carry flag |
DIR | 0ZC0 |
C is shifted into bit 0, bit 7 shifted into C
|
INCA |
AA <- AA + 1 |
DIR | SZCV |
Implemented with ADDD and hardcoded 0x01 in ALU |
DECA |
AA <- AA - 1 |
DIR | SZCV |
Implemented with ADDD and hardcoded 0xFF in ALU |
INCB |
AB <- AB + 1 |
DIR | ---- |
Uses counter function in register |
INCM |
MR <- MR + 1 |
DIR | ---- |
|
INCC |
AC <- AC + 1 |
DIR | 0Z00 |
|
BCFL |
Clear a bit in FL
|
BIT | S|Z|C|V |
Only 1 flag bit can be changed at a time |
BSFL |
Set a bit in FL
|
BIT | S|Z|C|V |
Only 1 flag bit can be changed at a time |
LDA0 |
Load AA with $00 |
DIR | ---- |
Loads register with 8-bit value in single instruction |
LDB0 |
Load AB with $00 |
DIR | ---- |
Loads register with 8-bit value in single instruction |
LDC0 |
Load AC with $00 |
DIR | ---- |
Loads register with 8-bit value in single instruction |
JPVC |
Jump if Overflow flag is clear | IND | ---- |
If true, jump to address in JR
|
JPVS |
Jump if Overflow flag is set | IND | ---- |
If true, jump to address in JR
|
JPCC |
Jump if Carry flag is clear | IND | ---- |
If true, jump to address in JR
|
JPCS |
Jump if Carry flag is set | IND | ---- |
If true, jump to address in JR
|
JPZC |
Jump if Zero flag is clear | IND | ---- |
If true, jump to address in JR
|
JPZS |
Jump if Zero flag is set | IND | ---- |
If true, jump to address in JR
|
JPSC |
Jump if Sign flag is clear | IND | ---- |
If true, jump to address in JR
|
JPSS |
Jump if Sign flag is set | IND | ---- |
If true, jump to address in JR
|
JUMP |
Unconditional jump | IND | ---- |
Jump to address in JR
|
NOOP |
No operation | N/A | ---- |
|
HALT |
Stop fetching new instructions | N/A | ---- |
LOAD loads the contents of memory location pointed to by MR into AA. STOR stores the contents of register AA into the location pointed to by MR.
MOVE moves values between AA and another register. For example, MOVE AA->BA or MOVE JL->AA. Register AA must be the source or destination of the MOVE instruction.
The Carry bit is included in the sum or difference. Be sure to clear the Carry flag (BCFL C) before executing ADDD or SUBB if you don't want it included in the calculation.
In other words, ADDD is implemented as AA = AA + AB + C, and SUBB is implemented as AA = AA - AB - C.
The "shift logical through carry" instructions are included in order to simplify multi-byte shift operations. For example, if you wanted to divide a signed 16-bit value by 2, you could use the following:
LOAD (MR) ; Start with MSB
SHRA A ; Previous bit 0 of MSB is now in Carry flag
STOR (MR) ; Save updated MSB
INCM ; Move pointer to next byte
LOAD (MR) ; Get LSB
SRLC ; Bit 0 from MSB is shifted into bit 7 of LSB through Carry flag
STOR (MM) ; Save updated LSB
The set and clear instructions for the flags (BCFL and BSFL) are included in the core CPU instructions because it is cumbersome to perform this operation without any other side effects.
TBD: Should the HALT instruction set an externally accessible hardware line to signal that the CPU is halted?
In addition to core instructions listed above, several additional instructions will be supported by the assembler. These can be implemented by stringing together several core CPU instructions.
| Mnemonic | Description |
SZCV (Flags) |
Notes |
|---|---|---|---|
BCAA |
Clear a bit in AA
|
0Z00 |
Load AB with bit mask, then ANDD
|
BSAA |
Set a bit in AA
|
0Z00 |
Load AB with bit mask, then ORRR
|
EXCH |
Exchange AA with AB
|
---- |
PUSH AA, AB->AA, AA->AC, POP AA, AA->AB, AC->AA
|
LDAA |
8-bit immediate version of LDAx
|
---- |
LDAL, LDAH
|
LDAB |
8-bit immediate version of LDBx
|
---- |
LDBL, LDBH
|
LDJR |
16-bit immediate version of LJxx
|
---- |
LJLL, LJLH, LJHL, LJHH
|
AD16 |
Add two 16 bit values | SZCV |
|
SU16 |
Subtract two 16 bit values | SZCV |
|
CM16 |
2's complement 16 bit value | SZ00 |
|
XNOR |
Bitwise XNOR on AA
|
0Z00 |
XORR, NOTT
|
LJMP |
Long jump | ---- |
LJLL, LJLH, LJHL, LJHH, JUMP
|
CALL |
Call subroutine | ---- | Push PC to stack and jump to location in JR
|
RETU |
Return from subroutine | ---- | Pop JR from stack and jump to location in JR
|
CAZS |
Call subroutine if Zero flag set | ---- | |
CAZC |
Call subroutine if Zero flag clear | ---- | |
CACS |
Call subroutine if Carry flag set | ---- | |
CACC |
Call subroutine if Carry flag clear | ---- | |
CASS |
Call subroutine if Sign flag set | ---- | |
CASC |
Call subroutine if Sign flag clear | ---- | |
CAVS |
Call subroutine if Overflow flag set | ---- | |
CAVC |
Call subroutine if Overflow flag clear | ---- |
The CALL and CAxx instructions need to calculate the "future" PC value at the end of the call sequence, storing and pushing the value using JR. JR is not preserved by CALL and RETU. The calling routine needs to save/push whatever values it wants to preserve before calling the subroutine, and needs to restore/pop any previously saved values after returning. (Note that previously, I had CALL push all the registers to the stack and RETU to pop them back off. I realized that creates significant overhead for subroutine calls and created other design complications.)
The RETU instruction pops the return address to JH and JL and then use JUMP command to return to the instruction after the CALL.
Index mode instructions may be added later. They aren't strictly necessary, but make using arrays a lot easier.
| Date | Changes |
|---|---|
| 14-Oct-2025 | Created - Design Version 2 |
| 18-Oct-2025 | Optimizing the instruction set |
| 28-Oct-2025 | Add EXCH instruction, clarify PUSH, POPP
|
| 06-Dec-2025 | Instruction changes, see 06-Dec-2025 blog entry |