And again… Here I am, doing another revision of the Instruction set, this time very much centered around the Addressing modes.
Legend
Rd | Destination Register |
Rs, Rs2 | Source Registers |
PR | Program Counter |
C | Constant Number |
Addr | Memory Address |
ST | Stack Pointer |
F | Flag bit |
MSB | Most Significant Bit |
LSB | Least Significent Bit |
Addressing Modes
Since I have eight bits of opcode available, I want to leave six bits for 64 instructions.
Previously, I worried about adding other Addressing modes, compared to the modes in v0.5 with only two bits available, before I realised I can do variable length. I can encode up two addressing modes with two bits, and any more addressing modes with more than two, say four bit. I just have to move the register/flag of Type 2 operations to the lowest four bits of the word.
Adressing Mode | Example | Bitcode | Comment |
---|---|---|---|
Register | add R00, R01 | 0b00 | |
Indirect (Register) | ld R00, @R01 | 0b01 | |
Immediate (Constants) | ld R00, 0x0F0F | 0b1000 | |
Direct Sector | ld R00, [0x0F0F ] | 0b1001 | |
Direct Absolute | ld R00, [0x0F0F0F ] | 0b1010 | |
Indirect (Z) | ld R00 | 0b1011 | |
Indexed (Z) | ld R00, +0x000F | 0b1100 | Adds the second operant to the Z-Index Register |
This means that I have seven addressing modes available.
But… Not for all Operations. Going through the list, I did realise that this kind of variable length Addressing mode will not work for four of the branch operations breq/brneq and bgt/bge
, as these branch operations need two Registers to compare, which makes it necessary that I put their Addressing modes into its own list…
Adressing Mode | Example | Bitcode |
---|---|---|
Direct Sector | bre R00, R01, [0x0F0F] | 0b00 |
Direct Absolute | bre R00, R01, [0x0F0F0F ] | 0b01 |
Indirect (Z) | bre R00, R01 | 0b10 |
Indexed (Z) | bre R00, R01, 0x000F | 0b11 |
I certainly dislike having to do it this way, but for the time being, I do not have an idea how to integrate both sides together and keep 6 bits of opcode.
OpCode Encoding
The change of the addressing modes does change the opcode encoding, again, as this time, Type 2 and Type 3 encoded operations are possible with the same operation, depending on the addressing mode. The new Branch Address Modes also make it necessary to add a Type 4 for opcode design.
MSB | LSB | |||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | |
Type 1: One word, no registers | ||||||||||||||||
Word 1 | Opcode | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |||||
Type 2: One Word, one register | ||||||||||||||||
Word 1 | Opcode | Address Mode | 0 | 0 | Register/Flag | |||||||||||
Type 3: One Word, two registers | ||||||||||||||||
Word 1 | Opcode | Address Mode | Source Register | Destination Register | ||||||||||||
Type 4: One Word, one Register, Branch Operation | ||||||||||||||||
Word1 | Opcode | Address Mode | 0 | 0 | 0 | 0 | Register | |||||||||
Addressing Mode: Direct Local/Constants/Indexed | ||||||||||||||||
Word 2 | Low Address Word (16 bit)/Constants/Indexed | |||||||||||||||
Addressing Mode: Direct (Global) | ||||||||||||||||
Word 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | High Address Word (8 bit) | |||||||
Word 3 | Low Address Word (16 bit) |
Data Transfer Operations (3 Operations)
Command | Mnemonic | Operation | Opcode | Address Modes | OpType | Affected Flags |
---|---|---|---|---|---|---|
Load | ld Rd, Adr/C | Rd <= Memory[Addr]/C | 0b000010 | all Address | 2 | None |
Store | st Rs, Addr16 | Memory[Addr] <= Rs | 0b000100 |
| 2 | None |
Move | mv Rd, Rs | Rd <= Rs | 0b001000 | N.A. | 3 | None |
The Load and Store operations certainly allow the use of all Address Modes.
Arythmic Logical Operations (13 Operations)
Command | Mnemonic | Operation | Opcode | Address Modes | OpType | Affected Flags |
---|---|---|---|---|---|---|
Add | add Rd, Rs/C | Rd <= Rd + Rs/C | 0b010001 |
| 3 | C, QC, HC, TC, Z, N, O |
Increment | inc Rd | Rd <= Rd + 1 | 0b010010 | N.A. | 2 | C, QC, HC, TC, Z, N, O |
Substract | sub Rd, Rs/C | Rd <= Rd – Rs/C | 0b010011 |
| 3 | C, QC, HC, TC, Z, N, O |
Decrement | dec Rd | Rd <= Rd – 1 | 0b010100 | N.A. | 2 | C, QC, HC, TC, Z, N, O |
Bitwise AND | and Rd, Rs/C | Rd <= Rd & Rs/C | 0b010101 |
| 3 | Z |
Bitwise OR | or Rd, Rs/C | Rd <= Rd | Rs/C | 0b010110 |
| 3 | Z |
Bitwise XOR | xor Rd, Rs/C | Rd <= Rd ^ Rs/C | 0b010111 |
| 3 | Z |
Bitwise NOT | not Rd | Rd <= ~Rd | 0b011000 | N.A. | 2 | Z |
Logical Shift Left | lsl Rd | Rd <= Rd << 1 LSB <= Carry Carry <= MSB | 0b011001 | N.A. | 2 | C, Z |
Logical Shift Right | lsr Rd | Rd <= Rd >> 1 MSB <= Carry Carry <= LSB | 0b011010 | N.A. | 2 | C, Z |
Logical Rotate Left | lrl Rd | Rd <= Rd << 1 LSB <= MSB | 0b011011 | N.A. | 2 | None |
Logical Rotate Right | lrr Rd | Rd <= Rd >> 1 MSB <= LSB | 0b011100 | N.A. | 2 | None |
Logical Switch Byte | lsb Rd | Rd[Low] <= Rd[High] Rd[High] <= Rd[Low] | 0b011101 | N.A. | 2 | None |
Here, of course, all operations with two operants allow the use of all conventional addressing modes.
Conditional Branch Instructions (10 Operations)
Command | Mnemonic | Operation | Opcode | Address Modes | OpType | Affected Flags |
---|---|---|---|---|---|---|
Branch local if Flag | blf F, Addr | if (F == 0): PCL <= Addr/Z | 0b100000 | All Branch Address Modes | 2 | None |
Branch if not Flag | bnf F, Addr | if (F != 0): PCL <= Addr/Z | 0b100001 |
| 2 | None |
Branch if Bit | bb B, Addr | if (B == 0): PC <= Addr/Z | 0b100010 |
| 2 | None |
Branch if not Bit | bnb B, Addr | if (B !=0): PC <= Addr/Z | 0b100011 |
| 2 | None |
Branch if Zero, Decrement | bzd Rd, Addr | if (Rd == 0): PCL <= Addr/Z else Rd <= Rd – 1 | 0b100100 |
| 2 | C, Z, N |
Branch if not Zero, Decrement | bnzd Rd, Addr | if (Rd != 0): PCL <= Addr/Z else Rd <= Rd – 1 | 0b100101 |
| 2 | C, Z, N |
Branch if Registers Equal | breq Rs, Rs2, Addr | if (Rs == Rs2): PCL <= Addr/Z | 0b100110 |
| 4 | C, Z, N |
Branch if Registers not Equal | brne Rs, Rs2, Addr | if (Rs != Rs2): PCL <= Addr/Z | 0b100111 |
| 4 | C, Z, N |
Branch if greater then | bgt Rs, Rs2, Addr | if (Rs > Rs2): PCL <= Addr/Z | 0b101000 |
| 4 | C, Z, N |
Branch if greater then or equal | bge Rs, Rs2, Addr | if (Rs >= Rs2): PCL <= Addr/Z | 0b101001 |
| 4 | C, Z, N |
I like to repeat again that I dislike the need to use a separate table for Branch Address Modes, but for the moment it is how it is.
Other Operations ( 11 Operations)
Command | Mnemonic | Operation | Opcode | Address Modes | OpType | Affected Flags |
---|---|---|---|---|---|---|
Jump | jp Addr | PCL <= Addr/Z | 0b110000 |
| 1 | None |
Jump to Subroutine | jls Addr | ST <= PC + 1; PCL <= Addr | 0b110001 |
| 1 | None |
Return | ret | PC <= ST | 0b110010 | N.A. | 1 | None |
Return from Interrupt | reti | PC <= ST (see post) | 0b110011 | N.A. | 1 | Any |
Push to Stack | push Rs | ST <= Rs | 0b110100 | N.A. | 2 | None, Any |
Pop from Stack | pop Rd | Rd <= ST | 0b110101 | N.A. | 2 | None, Any |
Set Flag | sf F | F <= 1 | 0b110101 | N.A. | 2 | Any |
Reset Flag | rf F | F <= 0 | 0b110111 | N.A. | 2 | Any |
Set Bit | sb B | R08[B] <= 1 | 0b111000 | N.A. | 2 | None |
Reset Bit | rb B | R08[B] <= 0 | 0b111001 | N.A. | 2 | None |
No operation | nop | No operation | 0xF F | N.A. | 1 | None |
With the two jump operations being the only operations that really need and Address modes, it does not really make any sense to give them all address modes, so I am limiting them to the the two Direct modes, as well as Indirect and Indexed via the Z Index Register.
Conclusions
The number of operations does not change here, but hopefully makes the addressing more powerful.
And I really hope that I find some way to get rid of that damned additional Branch Addressing Mode Table…