In my last post, I’ve taken a few initial thoughts regarding opcodes. Added to that come first inklings to wanting to try my hand at writing an assembler in Python. But, to do that, I think I need to add at least one new command to load constant values from memory into memory, without having to resort to playing around with specific addresses.
I am also thinking I am keeping the split between the four forms of operations and use the upper nibble to designate the command type. Practically, that will mean I can tell a store operation from an add operation just by the upper nibble of the machine code.
|Most Significant Bit|
|Least Significent Bit|
Data Transfer Operations
|Load Direct||Rd <= Memory[Addr]||None|
|Load Indirect||Rd <= Memory[Z]||None|
|Load Constant||Rd <= C (PC+1)||None|
|Store Direct||Memory[Addr] <= Rs||None|
|Store Indirect||Memory[Z] <= Rs||None|
|Move||Rd <= Rs||None|
The Load Constant is the new operation, meant to directly load any 16 bit constant into a register, allowing to get around any Z register shenanigans.
Arythmic Logical Operations
|Add||Rd <= Rd + Rs||C, QC, HC, TC, Z, N, O|
|Increment||Rd <= Rd + 1||C, QC, HC, TC, Z, N, O|
|Substract||Rd <= Rd – Rs||C, QC, HC, TC, Z, N, O|
|Decrement||Rd <= Rd – 1||C, QC, HC, TC, Z, N, O|
|Bitwise AND||Rd <= Rd & Rs||Z|
|Bitwise OR||Rd <= Rd | Rs||Z|
|Bitwise XOR||Rd <= Rd ^ Rs||Z|
|Bitwise NOT||Rd <= ~Rd||Z|
|Logical Shift Left||Rd <= Rd << 1|
LSB <= Carry
Carry <= MSB
|Logical Shift Right||Rd <= Rd >> 1|
MSB <= Carry
Carry <= LSB
|Logical Rotate Left||Rd <= Rd << 1|
LSB <= MSB
|Logical Rotate Right||Rd <= Rd >> 1|
MSB <= LSB
|Logical Switch Byte||Rd[Low] <= Rd[High]|
Rd[High] <= Rd[Low]
The Opcodes for the Arythmic Logic Operations look a bit strange, but that is mostly because I want to push the lowest three bits of the Opcode directly into the ALU and the other three bits can then be used to distinguish between the other operations that are similar.
Like Addition, Sustraction making use of the same logic circuits, for example. I also just realised that I can use two of those bits to directly push into the ALU to set the type of ‘addition’. Bit 5 for indicating whether or not the operation is a substractive operation , while Bit 4 indicated of the operation is an increment/decrement.
The same is true for the Shift and Rotate operations, as they make use of the same logic, with the only difference being whether the shift happens through the carry bit or not.
The Logic Switch Byte is new, meant to switch the two bytes of the 16 bit words used by the DWMC-16 quickly, an operation useful if a program needs to push/pul data from an 8 bit IO device.
Conditional Branch Instructions
|Branch if Flag||if (F == 0): PC <= Addr||None|
|Branch if not Flag||if (F != 0): PC <= Addr||None|
|Branch if Zero, Decrement||if (Rd == 0): PC <= Addr|
else Rd <= Rd – 1
|C, Z, N|
|Branch if not Zero, Decrement||if (Rd != 0): PC <= Addr|
else Rd <= Rd – 1
|C, Z, N|
|Branch if Registers Equal||if (Rs == Rs2): PC <= Addr||C, Z, N|
|Branch if Registers not Equal||if (Rs != Rs2): PC <= Addr||C, Z, N|
|Branch if greater then||if (Rs > Rs2): PC <= Addr||C, Z, N|
|Branch if greater then or equal||if (Rs >= Rs2): PC <= Addr||C, Z, N|
|Jump Direct||PC <= Addr||None|
|Jump Indirect||PC <= Z||None|
|Jump to Subroutine||ST <= PC + 1;|
PC <= Addr
|Return||PC <= ST||None|
|Return from Interrupt||PC <= ST (see last post)||Any|
|Push to Stack||ST <= Rs||None, Any|
|Pop from Stack||Rd <= ST||None, Any|
|Set Flag||F <= 1||Any|
|Reset Flag||F <= 0||Any|
|No operation||No operation||None|
The Return from Interrupt operation does what it says on the tin, and was discussed in my previous post.
With that, the number of instructions, for now, raises to 37 again, after my last modification of the initial instruction set by slashing four operations.