The first of the “Glaring Deficiencies” in need of a solution was the missing conditional branch (jump). This is how I went about solving it. Firstly a review of how PISC encodes an instruction:-
IR 15:0
MRD MWR ARGx3 DRGx3 LTS/ CY-IN ALUx5
1 0 111 xxx 1 11 0-0000
A sixteen bit instruction where:-
MRD = Memory/IO Read MWR = Memory/IO Write ARG = Address Bus Register Select x 3 bits (ALU A Input) DRG = Data Bus Register Select x 3 bits (ALU B Input) LTS/ = Latch Status (Both CY & EQ) when low CY-IN = Carry In Signal Select x 2 bits ALU = ALU Function x 5 bits
The actual values above are taken from Brad’s original paper and are in fact the hard coded Fetch Instruction. The data bus register select is shown as “xxx” for “don’t care” because during the Fetch Cycle the normal write to Register File (port C-in) is inhibited and the data bus contents are instead latched into the “Instruction Register”. If one looks to the actual circuit diagram for PISC 1.0a we can see that this register select happens to be wired all high (R7). So the actual Fetch Instruction is:-
10111111 11100000 or $BFE0
This instruction translates to:-
- Read memory (destination is the Instruction Latch during fetch cycle).
- Address Register set to R7 (the Program Counter).
- Do NOT latch the status bits (high)
- CY-IN Select = ’11’ which is a numerical one “1” indicated by a logic low.
- The five 74181 ALU Function Bits correspond to “Arithmetic Operation F=A+CY
So the result is that the register R7 the Program Counter is used as the address to read and is then post incremented because the CY-IN is hard selected for a “1”.
Probably also worth showing the Carry-In select truth table for the original PISC 1.0a at this point:-
00 = CY 01 = EQ 10 = "0" (logic level high) 11 = "1" (logic level low)
Now that all this is behind us let’s get down to the details of the modification. From Brad’s original paper he observes that the 74181 can be selected for either a Logic or Arithmetic operation. This is controlled by IR:4 which I separated out above as the leading “0-” in the fetch instruction to make it stand out.
Brad goes on to make the important observation that if IR:4 is set high for a logic operation then the CY-IN selection bits IR:6 and IR:5 are irrelevant because the Carry-In is not used for logic operations. So this is where we shall implement our conditional branch.
We are going to arrange it such that “if a carry-in *is* specified for a logic operation” which notionally makes no sense because why would you bother if it is going to be ignored. Then this will trigger the process of a conditional operation which uses the “truth” of the the CY-IN as a signal which will either inhibit or allow the write back to the Register File from the ALU output.
But for this to all work nicely we first need to re-order the selection table for the CY-IN select. So in my PISC 1.0c version this select table looks like this (obviously at this point any code Brad wrote for his 1.0a version is not going to run on mine ;-).
00 = "1" (logic level low) 01 = CY 10 = EQ 11 = "0" (logic level high)
Also note that this change plays with the order of the “0” and “1” as well. Which means that we must change the hard coded Fetch Instruction such that it is now:
10111111 10000000 or $BF80
The re-ordering of the “1” and “0” gives us some very important additional functionality which I’ll get to shortly. But was not strictly required for conditional jumps.
So this now gives us a instruction table subset for bits IR:6, IR:5 and IR:4 that looks like this:
00-1 = Valid Logic Function write to Register File enabled WEA/ = Low 01-1 = Conditional Write to Register File dependent on CY status bit 10-1 = Conditional Write to Register File dependant on EQ status bit 11-1 = Write back to Register File is forcibly inhibited WEA/ = High
The last combination in the table “11-1” is the reason for swapping the order of the “0” and “1” around. This arrangement enables us to programmatically stop PISC from writing the result of an ALU Logic Operation back to the A-Register. When would you wish to do this? When you are performing a logic operation and you are only interested in setting the Flags (EQ & CY). But *do not* wish to destroy the contents of your A-Register while doing so.
Normally PISC 1.0a will always write the result of the ALU logic function back into the register specified for the Address Bus or ALU “A” input (same thing). There is no way of stopping this. Now there is, so a instruction like this:
CMP R0,R4
Which is “Compare registers R0 and R4 and set the EQ flag if equal”. Can be crafted such that the contents of register R0 is not overwritten by the operation. Quite a useful feature! Sadly this only works for ALU Logic operations and not for Arithmetic operations. Oh well, I’ll take those features I can get cheaply.
So what do the actual PISC Assembler instructions look like? We can now craft an instruction like this:
MOV R7,R4 IF EQ
Translated: Copy the contents of R4 to R7 (R7 being the Program Counter) but only if the EQ flag is set “1” (logic level low). If the copy is successful then a jump to the location in R4 happens. If the copy is inhibited then the next instruction is executed. Conditional branch.
Of course my PISC Assembler allows you to normally code this instruction as something like:
JEQ LOOP
Jump if Equal to address LOOP.
So how expensive is the modification? Three gates (besides the re-wiring mentioned above). Looks like this: