Skip to content

DWMC-16: Instruction Set V0.5 - Deprecated

Yes... I know that I've put up the V0.4 revision of the Instruction Set just yesterday, but over night, thank you brain, I've mentally gone over a discussion I've read on the Usagi Electric Discord that involved someone else making their own instruction set and emulator. And how they were splitting the opcode from the addressing modes.

And... With the instruction set having grown to over 40 instructions in the last revision, I thought that maybe I should change the instruction set to also split the opcode from 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 limit myself to just two bits for the addressing moves, leaving six bits for 64 instructions.

Adressing Mode Example Bitcode
Immediate (Constants) ld R00, 0x0F0F 0b00
Direct Local ld R00, [0x0F0F] 0b01
Direct (Global) ld R00, [0x0F0F0F] 0b10
Register/Indirect add R00, R01
ld R00 0b11

I have lumped in the Indirect Addressing mode and the Register Addressing mode together. It depends on the operation, whether it will be Register or Indirect Addressing mode, which will be noted in the Operation List below. There is the possibility of an Indexed Address mode, but that will be only inside the Assembler, not in the actual operations. It will be in the form of ldi R00, 4 which will more or less just insert add ZL, 4 in front of ldi R00.

OpCode Encoding

With the addition of the addressing modes, I will need to change the OpCode Encoding as well. Depending on the Address Mode, there maybe one or two Words after the actual Opcode.

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 Register/Flag 0 0 0 0
Type 3: One Word, two registers
Word 1 Opcode Address Mode Destination Register Source Register
Addressing Mode: Direct Local
Word 2 Low Address Word (16 bit)
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 Rgister Modes OpType Affected Flags
Load ld Rd, Adr/C Rd <= Memory[Addr]/C 0b000010 0b00, 0b01, 0b10, 0b11 (Indirect) 2 None
Load st Rs, Addr16 Memory[Addr] <= Rs 0b000100 0b00, 0b01, 0b10, 0b11 (Indirect) 2 None
Move mv Rd, Rs Rd <= Rs 0b001000 N.A. 3 None

With the new addressing modes, I can easily reduce the eight Operations from V0.4 back down to just three, even getting rid of the Load Constant Operation and the Load Indirect Operation.

Arythmic Logical Operations (13 Operations)

Command Mnemonic Operation Opcode Register Modes OpType Affected Flags
Add add Rd, Rs/C Rd <= Rd + Rs/C 0b010001 0b00, 0b11 (Register) 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 `0b00, 0b11 (Register)` 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 `0b00, 0b11 (Register)` 3 Z
Bitwise OR or Rd, Rs/C Rd <= Rd Rs/C 0b010110 `0b00, 0b11 (Register)` 3
Bitwise XOR xor Rd, Rs/C Rd <= Rd ^ Rs/C 0b010111 `0b00, 0b11 (Register)` 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

The number of OpCodes for the Arithmetic Operations does not change, but it allows me to add Constants to at least some of the Operations. I have also gotten rid of the specific OpCode Encoding, as I previously had hoped to directly shunt the selection of the ALU operation from the OpCode into the ALU. But I do not think that its possible anymore with the drop of Opcode Length from eight to six bits, and me using the two upper bits to denominate that type of Operation.

Conditional Branch Instructions (10 Operations)

Command Mnemonic Operation Opcode Register Modes OpType Affected Flags
Branch local if Flag blf F, Addr if (F == 0): PCL <= Addr/Z 0b100000 0b01, 0b10, 0b11 (Indirect) 2 None
Branch if not Flag bnf F, Addr if (F != 0): PCL <= Addr/Z 0b100001 0b01, 0b10, 0b11 (Indirect) 2 None
Branch if Bit bb B, Addr if (B == 0): PC <= Addr/Z 0b100010 0b01, 0b10, 0b11 (Indirect) 2 None
Branch if not Bit bnb B, Addr if (B !=0): PC <= Addr/Z 0b100011 0b01, 0b10, 0b11 (Indirect) 2 None
Branch if Zero, Decrement bzd Rd, Addr if (Rd == 0): PCL <= Addr/Z
else Rd <= Rd - 1 0b100100 0b01, 0b10, 0b11 (Indirect) 2 C, Z, N
Branch if not Zero, Decrement bnzd Rd, Addr if (Rd != 0): PCL <= Addr/Z
else Rd <= Rd - 1 0b100101 0b01, 0b10, 0b11 (Indirect) 2 C, Z, N
Branch if Registers Equal breq Rs, Rs2, Addr if (Rs == Rs2): PCL <= Addr/Z 0b100110 0b01, 0b10, 0b11 (Indirect) 3 C, Z, N
Branch if Registers not Equal brne Rs, Rs2, Addr if (Rs != Rs2): PCL <= Addr/Z 0b100111 0b01, 0b10, 0b11 (Indirect) 3 C, Z, N
Branch if greater then bgt Rs, Rs2, Addr if (Rs > Rs2): PCL <= Addr/Z 0b101000 0b01, 0b10, 0b11 (Indirect) 3 C, Z, N
Branch if greater then or equal bge Rs, Rs2, Addr if (Rs >= Rs2): PCL <= Addr/Z 0b101001 0b01, 0b10, 0b11 (Indirect) 3 C, Z, N

Like with the Arithmetic Operations, there is not change in the number of operations here, but it now does allow to do more 'global' jumps if there is a branching operations. I will also allow indirect jumps through the Z Index Register.

Other Operations ( 11 Operations)

Command Mnemonic Operation Opcode Register Modes OpType Affected Flags
Jump jp Addr PCL <= Addr/Z 0b110000 0b01, 0b10, 0b11 (Indirect) 1 None
Jump to Subroutine jls Addr16 ST <= PC + 1;
PCL <= Addr 0b110001 0b01, 0b10 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 0xFF N.A. 1 None

With the new Addressing Modes, I can reduce the number of other operations down to eleven, getting rid of the Indirect Jump, as well as the 'local' and 'global' jumps I added in V0.4. The other operations do not really change at all. I also decided to just give the nop a fixed 16 bit opcode, since... Why not? :p

Conclusions

Maybe I should have taken a bigger think for the last v0.4 revision of the Instruction Set, when I added local and global addresses, especially since the same discussion inspired that revision I noted earlier. But it took a while before the penny with the address modes dropped for me.

Maybe I should let things like this stew a little longer in the back of my mind to grow a little more, before committing them to paper/a post.

But, now I am back down to 37 operations, after v0.4 rose up to 45 from 37. A thought might be to see if I could drop the differences between the Flag and Bit Test/Set operations by abusing the Register modes. That way, I would safe another four operations. Potentially I could do the same with Return/Return from Subroutine. That way I could get down to a cool 32 instructions.

With the Address Modes, I can certainly put a lot of potential operations and hide them in the Assembler. I can still have ldi in the assembler, which would change the operation to an ld operation for the machine code.