12-24-2014, 09:39 AM
My full reply and suggestions for alteration of your IS. This isn't all that edited, and considering how much time I spent formatting it, I'm sure you can see why I don't want to deal with this post anymore. I will also add that there is no reason to delete the thread simply because we disagree on the presence of an opcode at 0x00. This would be addressed at some point, and you were lucky enough to get stuck with it.
Code:
# bin hex short name effect
___________________________________________________________________
0 00000 0x00 NOP No Operation Does Nothing
1 00001 0x01 AND And Logical And
2 00010 0x02 OR Or Logical Or
3 00011 0x03 XOR Xor Logical Exclusive Or
4 00100 0x04 ADD Add Add
5 00101 0x05 SUB Subtract Subtract
6 00110 0x06 MUL Multiply Multiplies
7 00111 0x07 DIV Divide Divides
8 01000 0x08 PUH Push Push register to stack
9 01001 0x09 POP Pop Pops stack to register
10 01010 0x0A PUI Push Im Push value to stack
11 01011 0x0B SBM Stack Bit Mode Set Bit Mode Of Stack
12 01100 0x0C STR Store Store to Register
13 01101 0x0D LAD Load Load one register from another
14 01110 0x0E STI Store Im Store immediate
15 01111 0x0F RBM Register Mode Set bit size mode for register
16 10000 0x10 CSJ Conditional Jmp Jump stack conditionally
17 10001 0x11 JUP Jump Jump unconditionally
18 10010 0x12 CRJ Cond. reg. jmp Jump Register conditionally
19 10011 0x13 RTN Return Return point of subroutine
20 10100 0x14 SUT Subroutine Subroutine
21 10101 0x15 EBW Bus Write Write to external bus
22 10110 0x16 EBR Bus Read Read from external bus buffer
23 10111 0x17 RST Reset Clear all registers
24 11000 0x18 SME Same Same as previous operation
25 11001 0x19 HLT Halt Stop System
____________________________________________________________________________________
Groups:
Nop
Math (7, 3 logic, 4 arithmetic)
Stack (4, 2 redundant pairs)
Regs (4, 2 redundant pairs)
jumps (3, 1 redundant pair)
subroutines (2, semi-redundant to other instructions)
I/O (2)
Reset
SME (redundant)
HLT (could be better placed)
_____________________________________________________________________________
The first thing I'm going to do is define what I assume to be your machine
architecture, with a few modifications of my own.
This is a "stack machine" where there is only one directly operable stack as
well as a second stack on the instruction register. The individual registers
do not have their own stacks.
Registers: I will assume a total of 16 because 'cuz.
EAX-EJX (named E_X because 'cuz)
El Stacko (EST)
Instruction Stack (INS)
Instruction Pointer (INP)
I/O bus (IOP)
FLAGS:
0: Carry Flag (set by add and mul)
1: Overflow Flag (set by sub and div)
2: Sign Flag (set if number is negative)
3: Zero Flag (set if most recent output is zero)
4&5: Register Bit flags (00: 4 bit, 01: 8 bit, 10: 16 bit, 11: 32 bit)
6&7: Stack Bit flags (00: 4 bit, 01: 8 bit, 10: 16 bit, 11: 32 bit)
I will assume nothing about the instruction set except the following: the
Instruction set will be able to address two registers per instruction.
If we look at this instruction set immediately, issues, oversights, and
over-complications can be spotted. The most important: you have not defined a
Move operation. This means that you do not have a useful general operation
that simply moves values from one place to another. Instead, you define several
more complex operations for each case. This is important because SBM, STR, LAD,
STI (sort of), RBM, RTN, SME, EBW, and EBR are all the same instruction: MOV. This is why
all computers use a Move instruction.
SBM nn: MOV val, FLAGS
RBM nn: MOV val, FLAGS
STR EAX, EBX: MOV EAX, EBX
LAD EAX, EBX: MOV EBX, EAX
STI EAX, val: MOV val, EAX
RTN: MOV INS, INP
SME: MOV INP-1, INP
EBW EAX: MOV EAX, IOP
EBR EAX: MOV IOP, EAX
So that fixes that, but still more repeats exist. If it is a dedicated stack
machine, then you should be fully aware that moving a value from a stack is
the same as popping it, so:
POP EAX: MOV EST, EAX
PUS EAX: MOV EAX, EST
PUI val: MOV val, EST
Okay, so we have fixed some stuff. Now for useless opcodes and maybe even some
changes for better performance. (remember, the more directly your opcode
translates to actual hardware properties, the better)
Useless:
CRJ/CSJ: what does CRJ even do? Anyway, it's a redundant pair, kill one.
SME: are you really that lazy? Besides, how often do you perform
sequential operations multiple times in a row on the same
registers with the same opcode. Truly useless opcode.
So, a quick refresher:
0 00000 0x00 NOP No Operation Does Nothing
1 00001 0x01 AND And Logical And
2 00010 0x02 OR Or Logical Or
3 00011 0x03 XOR Xor Logical Exclusive Or
4 00100 0x04 ADD Add Add
5 00101 0x05 SUB Subtract Subtract
6 00110 0x06 MUL Multiply Multiplies
7 00111 0x07 DIV Divide Divides
16 10000 0x10 CSJ Conditional Jmp Jumps conditionally
17 10001 0x11 JUP Jump Jumps unconditionally
20 10100 0x14 SUT Subroutine Subroutine
23 10111 0x17 RST Reset Clear all registers
25 11001 0x19 HLT Halt Stop System
#MOV is in there somewhere
SUT is an interesting opcode. It codes as MOV INP, INS; MOV val, INP. In
English: push the instruction pointer to the stack, then jump somewhere.
Return then codes as, "pop the instruction stack," which would, of course, jump
back to the original location set by the SUT command. You can leave SUT out of
the instruction list if you know what it does, or you can keep it if you feel
lazy. That is entirely up to you.
Okay, so now we have (with move included):
0 00000 0x00 NOP No Operation Does Nothing
1 00001 0x01 AND And Logical And
2 00010 0x02 OR Or Logical Or
3 00011 0x03 XOR Xor Logical Exclusive Or
4 00100 0x04 ADD Add Add
5 00101 0x05 SUB Subtract Subtract
6 00110 0x06 MUL Multiply Multiplies
7 00111 0x07 DIV Divide Divides
8 01000 0x08 CSJ Conditional Jmp Jumps conditionally
9 01001 0x09 JUP Jump Jumps unconditionally
10 01010 0x0A RST Reset Clear all registers
11 01011 0x0B HLT Halt Stop System
12 01100 0x0C MOV Move Moves values between registers
So, now let's do some simple thought, and then we will reorganize.
ADD/SUB use the same unit, except that SUB EAX, EBX is ADC EAX, EBX', while
SBB is ADD EAX, EBX'. Therefore, those four operations are easily consolidated
into a single unit with opcodes where the 0 bit is the carry and the 1 bit is
the inverter. These all fall into the arithmetic group, along with the DIV and
MUL. Now, DIV will only return the integer portion of a division, so a special
operation is needed to determine the remainder: I call it MOD, and MOD EAX,
EBX = B mod(A), which is the remainder of B/A.
The logic unit can now be altered slightly using De Morgan's laws
AB = (A'+B')'
A+B = A+B = (A'B')'
(AB)' = A'+B'
(A+B)' = (A+B)' = A'B'
A XOR B = A'B + B'A = (A'B' + AB)'
A XNOR B = (A'B + B'A)' = A'B' + AB
A' = A'+0 = A'1 = A'0' = A'1 + 0A
AB' = (A'+B)'
This seems tricky, but it isn't once you think about it.
We have 8 opcodes in the logic unit and we have 3 different things to mess
with, piece of cake.
The selector is on bit 2. In section 0, the output inversion is bit 0, and the
AB inversion is on bit 1. In section 1, the output inversion is on bit 0 and
the A'B enable is on bit 1. If the A'B enable is zero, and the inversion is 1,
then A will be set to 0 throughout.
000 A+B
001 (A+B)'
010 A'+B'
011 (A'+B')'
100 AB'
101 A+B'
110 A'B + B'A
111 (A'B + B'A)'
Okay, now onto the "stack" section:
It's gone
The Register section:
I chose to keep MOV and MVI just for simplicity's sake. So moving an immediate
value is still a separate operation.
Jump:
We just have JMP and CSJ now, so that's that.
Subroutines and I/O were killed.
NOP, RST, and HLT are special control cases.
So, currently, NOP is on 0x00. This is... okay, but HLT is a much better
candidate for 0x00. If you make the instruction pointer increment by the OR of
all bits in the opcode AND'ed with the Clock, then if the opcode is zero, the
instruction pointer will not increment. OR the output of the mask with a Trap
control and you have the ability to override the HLT when the time comes. One
other thing comes to mind, though. NOP is only valid if the architecture has a
pipeline, so it isn't needed per se.
The new Instruction List now has several interesting properties that one would
not have forseen.
0 00000 0x00 HLT Halt Stop system
1 00001 0x01 MUL Multiply Multiplies
2 00010 0x02 DIV Divide Integer divide
3 00011 0x03 MOD Modulus Remainder of divide
4 00100 0x04 ADD Add Add without carry
5 00101 0x05 ADC Add Carry Add with carry of 1
6 00110 0x06 SBB Sub Borrow Subtract with borrow of 1
7 00111 0x07 SUB Subtract Subtract without borrow
8 01000 0x08 OR Logical OR Bitwise OR of two registers
9 01001 0x09 NOR Logical NOR Bitwise NOR of two registers
10 01010 0x0A NAND Logical NAND Bitwise NAND of two registers
11 01011 0x0B AND Logical AND Bitwise AND of two registers
12 01100 0x0C IMP Implies Bitwise AND of A with B'
13 01101 0x0D NOT Logical NOT Bitwise inversion of register
14 01110 0x0E XOR Logical XOR Bitwise XOR of two registers
15 01111 0x0F XNOR Logical XNOR Bitwise XNOR of two registers
16 10000 0x10 MOV Move Move values between registers
19 10001 0x11 MVI Move Immediate Move Immediate value
17 10010 0x12 CSJ Conditional jmp Jump conditionally
18 10011 0x13 JMP Jump Jump unconditionally
19 10100 0x14 RST Reset Resets all registers
21-23 101xx 0x15-17 ??? ??? Undefined operations
24-32 11xxx 0x18-1F ROL Rotate Left Rotate to the left xxx places
I use rotate instead of shift because you can rotate an amount, then cut out
the bits that should be zero, therefore you can rotate in such a way as to
shift up or down all with the same instruction.
ROL 111, EAX; AND 01111111, EAX = SHR 1, EAX
ROL 001, EAX; AND 11111110, EAX = SHL 1, EAX
In this way, it becomes easy to perform any type of shift, but it doesn't stop
there. To shift a larger register, simply do the following (assuming a shift
up and [EBX,EAX] as the form):
MOV EAX, ECX
AND 00001111, EAX
ROT 100, EAX
ROT 100, EBX
AND 11110000, EBX
AND 00001111, ECX
OR ECX, EBX
result: [EBX,EAX]
This is the 4 bit shift of a 16 bit number in two registers. The 4 bit
rotation has slightly more code.
One should note the opening of 3 undefined opcodes at 21-23. Do with
them as you may, they all are 101xx.
To finish, the groups are:
00000: HLT
00xxx: Arithmetic Operations
01xxx: Logical Operations
1000x: MOV, MVI
1001x: Jump Operations
10100: RST
101xx: Undefined
11xxx: Shift Operations
Or, more generally
00000: HLT
00xxx: Arithmetic
01xxx: Logic
10xxx: Data flow
11xxx: Shift
As you can see, I broke the groups up by eight so that the related operations all have the same prefix. This, along with killing your MOV duplicates, was my goal the entire time.