T425 uCode magic
The decoding of the Inmos Transputer ucode (which I extracted from the actual transputer devices using a ucode ROM test access mode) was a very slow and rather painful task. Not only was there very little material on the internet but the decoding of the column drivers often felt like a case of one step forward and two steps backwards most of the time.
At the start I worked on the simple instructions which I could determine the column drivers (e.g. rev, ldc, pfix, nfix). Then I used the instructions which I could determine the destination registers (including the undocumented test instructions). For the arithmetic instructions, I used a TIS appendix paper written by Guy Harriman (from Inmos) and the checkout (early transputer test code) to help with some of the ALU and shifting bits. As time went on it became more a guessing game in figuring out the remaining column driver functions (in particular the link interface controls).
On this web page you will find some details of the Inmos Transputer T425 Rev. C VBC. I don't intend to list the complete T425 VBC (aka ucode). Oh and by the way, VBC stands for Vogon Banana Code. Refer to my Simple 42 webpage for an explanation.
I have made a start with two of my favourite instructions since they both use a hidden trick to restore the DataIn register to its original entry value on completion of the instruction. The two instructions are gcall and ret. Also included is the rev instruction since it was one of the first to be decoded. Each instruction (below) has a high-level Occam description, a low-level Occam implementation and the VBC ucode.
For historical purposes, during the development of the T425 Transputer (as with the T414) at Inmos, the VBC ucode was hand written by Guy Harriman and Jon Beecroft, based on a high-level Occam instruction set description document (written by Roger Shepherd and David May). A Functional (or Datapath) simulator was used to test the VBC operation and correctness. The VBC reader and ROM optimiser tools (written by Jim Cownie) were used to reduce the ucode ROM size before being used by the Inmos ROM layout generator tool. To simulate the whole chip a hardware description language (simply called HDL) which included a ROM (loaded with the VBC output) was run on a proprietary Inmos simulation tool. This could run small programs to check it was working as expected.
GCALL: XbusfromIptrReg YbusfromConstBox OnesfromCbox ZbusFromXbus AregfromZbus DataRegfromAreg RETnext2 ;
RETnext2: XbusfromDataIn YbusfromConstBox OnesfromCbox ZbusFromXbus IptrRegFromZbus DataInfromPrevReadReg RETend ;
RETend: XbusfromConstBox OnesfromCbox YbusfromConstBox OregFrom0 Next ;
GCALL (low-level Occam):
IF NextInst = GCALL SEQ DataReg := Areg Areg := IptrReg NextInst := RETnext2
NextInst = RETnext2 SEQ IptrReg := DataInReg DataInReg := PrevReadReg NextInst := RETend
NextInst = RETend SEQ Oreg := 0 NextInst := 0
GCALL (high-level Occam):
SEQ DataReg := Areg Areg := IptrReg IptrReg := DataInReg DataInReg := PrevReadReg Oreg := 0 Notes: DataRegfromAreg actions: PrevReadReg <= DataInReg <= Areg; DataOutReg <= Areg DataReg (refers to both DataInReg and DataOutReg)
RET: XbusfromWptrReg YbusfromConstBox OnesfromCbox ZbusFromXbus MemRead DataMemAddrFromZbus RETnext1 ;
RETnext1: XbusfromWdescReg YbusfromConstBox SixteenfromCbox ZbusFromXbusPlusYbus WdescRegfromZbus RETnext2 ;
RETnext2: XbusfromDataIn YbusfromConstBox OnesfromCbox ZbusFromXbus IptrRegFromZbus DataInfromPrevReadReg RETend ;
RETend: XbusfromConstBox OnesfromCbox YbusfromConstBox OregFrom0 Next ;
RET (low-level Occam):
IF NextInst = RET SEQ RIndexWord (DataMemAddrReg, 0, DataInReg) NextInst := RETnext1
NextInst = RETnext1 SEQ AtWord (WdescReg, 4, WdescReg) NextInst := RETnext2
NextInst = RETnext2 SEQ IptrReg := DataInReg DataInReg := PrevReadReg NextInst := RETend
NextInst = RETend SEQ Oreg := 0 NextInst := 0
RET (high-level Occam):
SEQ RIndexWord (Wptr, 0, DataInReg) AtWord (WdescReg, 4, WdescReg) IptrReg := DataInReg DataInReg := PrevReadReg Oreg := 0 Notes: MemRead actions: requests a memory interface access in the next cycle: PrevReadReg <= DataInReg <= MemoryWord[DataMemAddrReg]
REV: XbusfromConstBox OnesfromCbox YbusfromConstBox AregfromBregSlave BregfromAregSlave OregFrom0 Next ;
REV (low-level Occam):
IF NextInst = REV SEQ Areg := Breg.Slave Breg := Areg.Slave Oreg := 0 NextInst := 0
REV (high-level Occam):
SEQ Areg := Breg.Slave Breg := Areg.Slave Oreg := 0 Notes: N/A
BSUB: XbusfromAreg YbusfromBreg ZbusFromXbusPlusYbus AregfromZbus BregfromCregSlave OregFrom0 Next ;
BSUB (low-level Occam):
IF NextInst = BSUB SEQ Areg := Areg + Breg Breg := Creg.Slave Oreg := 0 NextInst := 0
BSUB (high-level Occam):
SEQ Areg := Areg + Breg Breg := Creg.Slave Oreg := 0
Notes: N/A
GT: XbusfromAreg YbusfromBreg ZbusFromXbusMinusYbus EregfromZbus BregfromCregSlave Cond0FromNotZbusSubLessThan0 ( GTresultFalse, GTresultTrue ) ; // [1, 0 case]
GTresultTrue: XbusfromAreg YbusfromConstBox MachineTRUE ZbusFromYbus AregfromZbus OregFrom0 Next ;
GTresultFalse: XbusfromAreg YbusfromConstBox MachineFALSE ZbusFromYbus AregfromZbus OregFrom0 Next ;
GT (low-level Occam):
IF NextInst = GT SEQ Zbus := Areg - Breg UpdateAluFlags () Ereg := Zbus Breg := Creg.Slave IF NotZbusSubLessThan0 = 0 NextInst := GTresultTrue TRUE NextInst := GTresultFalse
NextInst = GTresultTrue SEQ Areg := MachineTRUE Oreg := 0 NextInst := 0
NextInst = GTresultFalse SEQ Areg := MachineFALSE Oreg := 0 NextInst := 0
GT (high-level Occam with transformation for comparision test):
SEQ -- Ereg := Areg - Breg IF ((Areg - Breg) < 0) -- which is equivalent to Breg > Areg Areg : = MachineTRUE TRUE Areg := MachineFALSE Breg := Creg.Slave Oreg := 0
GT (high-level Occam):
SEQ IF Breg > Areg Areg : = MachineTRUE TRUE Areg := MachineFALSE Breg := Creg.Slave Oreg := 0
Notes: The t425 transputer hardware conditional multiplexer input is NotZbusSubLessThan0. NotZbusSubLessThan0 := NOT (Zbus < 0) Ereg used to hold ALU result for test purposes
CJ: XbusfromAreg YbusfromConstBox OnesfromCbox ZbusFromXbus Cond0FromNotZbusEq0 ( CJpopStack, CJupdateInstReg ) ; // [1, 0 case]
CJupdateInstReg: XbusfromIptrReg YbusfromOreg ZbusFromXbusPlusYbus IptrRegFromZbus RETend ;
RETend: XbusfromConstBox OnesfromCbox YbusfromConstBox OregFrom0 Next ;
CJpopStack: XbusfromConstBox OnesfromCbox YbusfromConstBox AregfromBregSlave BregfromCregSlave OregFrom0 Next ;
CJ (low-level Occam):
IF NextInst = CJ SEQ Zbus := Areg UpdateAluFlags () IF NotZbusEq0 = 0 NextInst = CJupdateInstReg TRUE NextInst = CJpopStack
NextInst = CJupdateInstReg SEQ IptrReg := IptrReg + Oreg Oreg := 0 NextInst := 0
NextInst = CJpopStack SEQ Areg := Breg.Slave Breg := Areg.Slave Oreg := 0 NextInst := 0
CJ (high-level Occam):
SEQ IF Areg = 0 IptrReg := IptrReg + Oreg TRUE Areg := Breg.Slave Breg := Areg.Slave Oreg := 0
Notes: The t425 transputer hardware conditional multiplexer input is NotZbusEq0. NotZbusEq0 := NOT (Zbus = 0)
WCNT: XbusfromConstBox EightfromCbox YbusfromBreg ZbusFromMinusXbus DregfromZbus BregfromAregSlave CregfromBregSlave WCNTtestSign ;
WCNTtestSign: XbusfromAreg YbusfromConstBox OnesfromCbox ZbusFromXbus OregfromZbus Cond1FromBslaveMsb ( WCNTshiftNeg, WCNTshiftPos ) ; // [1, 0 case]
WCNTshiftPos: XbusfromConstBox OnesfromCbox YbusfromConstBox ZbusFrom0 ShiftRightBreg WordIncDreg Cond0FromNotIncDregCarryOut ( WCNTshiftPos, WCNTend1 ) ; // [1, 0 case]
WCNTend1: XbusfromConstBox OnesfromCbox YbusfromOreg YbusByteSelMask ZbusFromYbus BregfromZbus AregfromBregSlave OregFrom0 Next ;
WCNTshiftNeg: XbusfromConstBox OnesfromCbox YbusfromConstBox ZbusFromMinus1 ShiftRightBreg WordIncDreg Cond0FromNotIncDregCarryOut ( WCNTshiftNeg, WCNTend2 ) ; // [1, 0 case]
WCNTend2: XbusfromConstBox OnesfromCbox YbusfromOreg YbusByteSelMask ZbusFromYbus BregfromZbus AregfromBregSlave OregFrom0 Next ;
WCNT (low-level Occam):
IF NextInst = WCNT SEQ LoopCount (Dreg, 2) Breg := Areg.Slave Creg := Breg.Slave NextInst := WCNTtestSign NextInst = WCNTtestSign SEQ Oreg := Areg IF BslaveMsb NextInst := WCNTshiftNeg TRUE NextInst := WCNTshiftPos NextInst = WCNTshiftPos SEQ Zbus := 0 ShiftRightBreg () WordIncDreg () IF NotIncDregCarryOut = 0 NextInst := WCNTend1 TRUE NextInst := WCNTshiftPos NextInst = WCNTshiftNeg SEQ Zbus := -1 ShiftRightBreg () WordIncDreg () IF NotIncDregCarryOut = 0 NextInst := WCNTend2 TRUE NextInst := WCNTshiftNeg
NextInst = WCNTend1 SEQ Breg := Oreg /\ ByteSelectMask Areg := Breg.Slave Oreg := 0 NextInst := 0 NextInst = WCNTend2 SEQ Breg := Oreg /\ ByteSelectMask Areg := Breg.Slave Oreg := 0 NextInst := 0
WCNT (high-level Occam with transformation for WHILE replacement):
SEQ LoopCount (Dreg, 2) // loops twice Breg := Areg.Slave Creg := Breg.Slave Oreg := Areg
WCNT_loop: IF BslaveMsb Zbus := -1 TRUE Zbus := 0 ShiftRightBreg () WordIncDreg () IF NOT (NotIncDregCarryOut = 0) goto WCNT_loop TRUE goto WCNT_end WCNT_end: Breg := Oreg /\ ByteSelectMask Areg := Breg.Slave Oreg := 0
WCNT (high-level Occam):
SEQ LoopCount (Dreg, 2) // loops twice Breg := Areg.Slave Creg := Breg.Slave Oreg := Areg WHILE NOT (NotIncDregCarryOut = 0) // <> 0 SEQ IF BslaveMsb Zbus := -1 TRUE Zbus := 0 ShiftRightBreg () WordIncDreg () Breg := Oreg /\ ByteSelectMask Areg := Breg.Slave Oreg := 0
Notes: The high-level Occam has a WHILE loop which must be replaced during the initial transformation. ShiftRightBreg () does Breg := (Breg >> 1) \/ ( Zbus /\ #80000000) WordIncDreg () does Dreg := Dreg + BPW, and updates Dreg carry out flag LoopCount (Reg, X) does Reg := -X * BPW, and updates Reg carry out flag (macro intended for Dreg or Oreg) BytesPerWord (BPW) is 4 ByteSelectMask is #00000003 The t425 transputer hardware conditional multiplexer inputs are NotIncDregCarryOut and BslaveMsb.
GAJW: XbusfromWptrReg YbusfromConstBox OnesfromCbox ZbusFromXbus AregfromZbus DataRegfromAreg Cond1FromProcPriority ( GAJWprocLow, GAJWprocHigh ) ; // [1, 0 case]
GAJWprocHigh: XbusfromDataIn YbusfromConstBox OnesfromCbox ZbusFromXbus WdescRegfromZbus OregFrom0 Next ;
GAJWprocLow: XbusfromDataIn YbusfromConstBox OnesfromCbox ZbusFromXbusPlus1 WdescRegfromZbus OregFrom0 Next ;
GAJW (low-level Occam):
IF NextInst = GAJW SEQ DataReg := Areg Areg := WprtReg IF ProcPriority NextInst = GAJWprocLow TRUE NextInst = GAJWprocHigh
NextInst = GAJWprocLow SEQ WdescReg := DataInReg + 1 Oreg := 0 NextInst := 0
NextInst = GAJWprocHigh SEQ WdescReg := DataInReg Oreg := 0 NextInst := 0 GAJW (high-level Occam):
SEQ DataReg := Areg Areg := WprtReg IF ProcPriority WdescReg := DataInReg + 1 TRUE WdescReg := DataInReg Oreg := 0
Notes: The t425 transputer hardware conditional multiplexer input is ProcPriority. ProcPriority := (WdescReg /\ 1) DataReg (refers to both DataInReg and DataOutReg)
The following is a reconstruction of the VBC file contents for the T425 Rev. C Transputer (based on my column driver decoding and the text format used by the Simple 42 processor) which would have been initially hand written by the engineers at Inmos, and read by the VBC reader. The VBC comprised of two files - the declarations in t425.vbc and the definitions in t425with.vbc. The ROM optimiser tool would have also have read the VBC files, in order to reduce the ROM size and then save results in a new VBC output file. The optimiser tool could determine which entry point instruction addresses were fixed. The remaining non entry point ucode could be repositioned by the optimiser.
FIELD Microword[99,97,78,75,73,70,53:52,46,44] // X bus source select XbusfromIptrReg = #B1000000000 XbusfromConstBox = #B0100000000 XbusfromDreg = #B0010000000 XbusfromChannelData = #B0001000000 XbusfromDataIn = #B0000100000 XbusfromAreg = #B0000010000 XbusfromWptrReg = #B0000001000 XbusfromWdescReg = #B0000000100 XbusfromFPtrReg0 = #B0000000010 XbusfromFPtrReg1 = #B0000000001 ;
FIELD Microword[105:104,96,80,66,59:58,50,48,42,37,35,20] // Y bus source select YbusFromOregSL2 = #B1000000000000 YbusfromOreg = #B0100000000000 YbusfromConstBox = #B0010000000000 YbusfromEreg = #B0001000000000 YbusfromBreg = #B0000100000000 YbusFromCregSL1 = #B0000010000000 YbusfromCreg = #B0000001000000 YbusfromBPtrReg0 = #B0000000100000 YbusfromBPtrReg1 = #B0000000010000 YbusfromStatusReg = #B0000000001000 YbusfromClockReg1 = #B0000000000100 YbusfromClockReg0 = #B0000000000010 YbusByteSelMask = #B0000000000001 ;
FIELD Microword[21,19:14] // Alu operations ZbusFromXbusPlusYbus = #B0011000 // X + Y ZbusFromXbusPlus1 = #B0110010 // X + 1 ZbusFromYbusMinus(XbusPlus1) = #B1011000 // Y - (X + 1) ZbusFromXbusPlus0 = #B0110000 // X ZbusFromMinusXbus = #B1110010 // 0 - X ZbusFromYbusMinusXbus = #B1011010 // Y - X ZbusFromYbusPlusXbusPlus1 = #B0011010 // Y + X + 1 ZbusFromXbusMinusYbus = #B0100110 // X - Y ZbusFromMinusYbus = #B1100110 // 0 - Y ZbusFrom0 = #B0000001 // 0 ZbusFromNotXbusAndYbus = #B0100001 // ~X /\ Y ZbusFromNotXbus = #B0110001 // ~X ZbusFromXbusAndYbus = #B0001001 // X /\ Y ZbusFromYbus = #B0101001 // Y ZbusFromNotXbusOrYbus = #B0000101 // ~X \/ Y ZbusFromXbusXorYbus = #B0100101 // X >< Y ZbusFromNotYbus = #B0010101 // ~Y ZbusFromXbusOrYbus = #B0101101 // X \/ Y ZbusFromMinus1 = #B0111101 // -1 ZbusFromYbusAndNot(BPWminus1) = #B0101011 // Y /\ ~(4 - 1) ZbusFromXbus = #B0001101 ; // X SET ZbusFromOnes = ZbusFromMinus1 ;
FIELD Microword[103,98,79,77,69,65,57,51,49,47,45,43,41,38,36,34,12,8,0] // Z bus destination select OregfromZbus = #B1000000000000000000 IptrRegFromZbus = #B0100000000000000000 EregfromZbus = #B0010000000000000000 DregfromZbus = #B0001000000000000000 AregfromZbus = #B0000100000000000000 BregfromZbus = #B0000010000000000000 CregfromZbus = #B0000001000000000000 WdescRegfromZbus = #B0000000100000000000 BPtrReg0fromZbus = #B0000000010000000000 BPtrReg1fromZbus = #B0000000001000000000 FPtrReg0fromZbus = #B0000000000100000000 FPtrReg1fromZbus = #B0000000000010000000 StatusRegfromZbus = #B0000000000001000000 TNextReg1fromZbus = #B0000000000000100000 ClockReg0&1fromZbus = #B0000000000000010000 TNextReg0fromZbus = #B0000000000000001000 SelectChannelRegfromZbus = #B0000000000000000100 ChannelStackfromZbus = #B0000000000000000010 DataMemAddrFromZbus = #B0000000000000000001 ;
FIELD Microword[67,64,60,56,54] // A/B/C stack control AregfromBregSlave = #B10000 BregfromAregSlave = #B01000 BregfromCregSlave = #B00100 CregfromBregSlave = #B00010 CregFrom0 = #B00001 ;
FIELD Microword[68,63:61,55,23:22] // Shifting control ShiftRightAreg = #B1000000 ShiftLeftBreg = #B0100000 BregShIn0From1 = #B0010000 ShiftRightBreg = #B0001000 CregFromZbusSR1 = #B0000100 CregShInMsbfromCarryOut = #B0000010 CregShInMsbfromArithLogic = #B0000001 ;
FIELD Microword[27:25] // condition select for MIR[0] Cond0fromROMFeedback0 = #B000 Cond0FromNotCarryOut = #B001 Cond0FromNotZbusSubLessThan0 = #B010 Cond0FromNotAluPropAll1 = #B011 Cond0FromOverflow = #B100 Cond0FromNotIncOregCarryOut = #B101 Cond0FromNotIncDregCarryOut = #B110 Cond0FromNotPrInAnalyse = #B111 ;
SET Cond0FromNotZbusEq0 = Cond0FromNotAluPropAll1 Cond0FromNotLastRead = Cond0FromNotIncOregCarryOut Cond0FromNotLastWrite = Cond0FromNotIncDregCarryOut ;
FIELD Microword[30,28,32,31] // condition select for MIR[1] Cond1fromROMFeedback1 = #B0000 Cond1FromDivStep0 = #B0001 Cond1FromDivStep1 = #B0010 Cond1FromAslave0 = #B0011 Cond1FromBslave0 = #B0100 Cond1fromBslave1 = #B0101 Cond1FromBslaveMsb = #B0110 Cond1FromCslaveMsb = #B0111 Cond1FromNotTwoReadsToStart = #B1000 Cond1FromProcPriority = #B1001 Cond1FromChOrTimerReq = #B1011 Cond1FromChNotTimerReq = #B1100 Cond1FromHighNotLowReq = #B1101 Cond1FromBootFromRomNotLinks = #B1010 Cond1FromChannelReadyNotRun = #B1110 Cond1FromTimeOutReq = #B1111 ; FIELD Microword[39,33,13] // Timer control ResetTEnabled1 = #B100 ResetTEnabled0 = #B010 ResetTimeOutLatch = #B001 ;
FIELD Microword[102:100,76] // Incrementor control OregFrom0 = #B1000 OregFromZbusSL4 = #B0100 WordIncOreg = #B0010 WordIncDreg = #B0001 ;
FIELD Microword[109,106,83:81,72:71] // Interface Control Requests Next = #B1000000 AregfromDataIn = #B0100000 DataInfromPrevReadReg = #B0010000 MemWrite = #B0001000 MemRead = #B0000100 DataRegfromZbus = #B0000010 DataRegfromAreg = #B0000001 ;
FIELD Microword[108:107] // Byte move control ByteWriteStrobeEnable = #B10 DataRegfromByteShifter = #B01 ;
FIELD Microword[40] // Error status StatusErrorfromOverflow = #B1 ;
FIELD Microword[74,11:9,7:1] // Channel Control Requests ChannelDataRegfromUbus = #B10000000000 HighPriorityChannelAck = #B01000000000 LowPriorityChannelAck = #B00100000000 ResetChannel = #B00010000000 ResetChannelReadyNotRunlatch = #B00001000000 SetAltEnabledLatch = #B00000100000 ClearAltEnabledLatch = #B00000010000 DisableChannelStatus = #B00000001000 EnableChannelandEnableChannelStatus = #B00000000100 ResetChannelRunReqlatch = #B00000000010 DataMemAddrfromSelectChannelReg = #B00000000001 ;
FIELD Microword[117:110,29,24] // loads into MIR ROMFeedback[0] = #B0000000001 ROMFeedback[1] = #B0000000010 ROMFeedback[2] = #B0000000100 ROMFeedback[3] = #B0000001000 ROMFeedback[4] = #B0000010000 ROMFeedback[5] = #B0000100000 ROMFeedback[6] = #B0001000000 ROMFeedback[7] = #B0010000000 ROMFeedback[8] = #B0100000000 ROMFeedback[9] = #B1000000000 ;
FIELD Microword[95:84] // Constant box select bit0fromCbox = #B100000000000 bit1fromCbox = #B010000000000 bit2fromCbox = #B001000000000 bit3fromCbox = #B000100000000 bit4fromCbox = #B000010000000 bit5fromCbox = #B000001000000 bit6fromCbox = #B000000100000 bit7fromCbox = #B000000010000 bit15to8fromCbox = #B000000001000 bit22to16fromCbox = #B000000000100 bit30to23fromCbox = #B000000000010 bit31fromCbox = #B000000000001 Minus1fromCbox = #B111111111111 Minus2fromCbox = #B011111111111 Minus3fromCbox = #B101111111111 Minus4fromCbox = #B001111111111 Minus5fromCbox = #B110111111111 MinIntfromCbox = #B000000000001 MinIntplus1fromCbox = #B100000000001 MinIntplus2fromCbox = #B010000000001 MinIntplus3fromCbox = #B110000000001 ZerofromCbox = #B000000000000 OnefromCbox = #B100000000000 TwofromCbox = #B010000000000 ThreefromCbox = #B110000000000 FourfromCbox = #B001000000000 FivefromCbox = #B101000000000 EightfromCbox = #B000100000000 SixteenfromCbox = #B000010000000 EventfromCbox = #B000001000001 // 80000020 ExtendFunctionsfromCbox = #B000100100001 // 80000048 Link3InputfromCbox = #B001110000001 // 8000001C ByteMaskfromCbox = #B111111110000 // 000000FF MemStartfromCBox = #B000011100001 // 80000070 TptrLoc1fromCbox = #B000101000001 // 80000028 TptrLoc0fromCbox = #B001001000001 // 80000024 EregIntSaveLocfromCbox = #B001000100001 // 80000044 Link3OutputfromCbox = #B001100000001 // 8000000C MostPos = #B111111111110 // 7FFFFFFF MostPosMinus1 = #B011111111110 // 7FFFFFFE WdescIntSavefromCbox = #B001101000001 // 8000002C GotoSNPBitfromCbox = #B010000000000 // Status bit 1 IOBitfromCbox = #B001000000000 // Status bit 2 MovebitfromCbox = #B000100000000 // Status bit 3 TimeDelBitfromCbox = #B000010000000 // Status bit 4 TimeInsBitfromCbox = #B000001000000 // Status bit 5 DistAndInsBitfromCbox = #B000000100000 // Status bit 6 HaltOnErrorBitfromCbox = #B000000010000 // Status bit 7 Mov2dallfromCbox = #B000000001000 // Status bit 15 to 8 Mov2dnonaerofromCbox = #B000000000100 // Status bit 22 to 16 J0BreakFlagfromCbox = #B000000000010 // Status bit 30 to 23 ErrorFlagfromCbox = #B000000000001 // Status bit 31 DevIdfromCBox = #B010000000000 ; // RevC silicon = 02 (00 - 09)
SET OnesfromCbox = Minus1fromCBox NotProcess.p = MinIntfromCbox Enabling.p = MinIntplus1fromCbox Waiting.p = MinIntplus2fromCbox Ready.p = MinIntplus3fromCbox TimeSet.p = MinIntplus1fromCbox TimeNoSet.p = MinIntplus2fromCbox NoneSelected.o = Minus1fromCBox Iptr.s = Minus1fromCbox // -1 Link.s = Minus2fromCbox // -2 State.s = Minus3fromCbox // -3 Pointer.s = Minus3fromCbox // -3 TLink.s = Minus4fromCbox // -4 Time.s = Minus5fromCbox // -5 MachineTRUE = OnefromCbox MachineFALSE = ZerofromCbox ; USE "t425with.vbc" // definitions and predefined instruction label addresses (e.g. REV)
DO
REV: XbusfromConstBox OnesfromCbox YbusfromConstBox AregfromBregSlave BregfromAregSlave OregFrom0 Next ;
LDDEVID: XbusfromAreg YbusfromConstBox DevIdfromCbox ZbusFromYbus AregfromZbus BregfromAregSlave CregfromBregSlave OregFrom0 Next ;
// the rest of the t425 VBC code follows ...
// Fixed entry point (==opcodes) instruction addressesSET REV = #B0000000000 // 000 LB = #B0000000001 // 001 BSUB = #B0000000010 // 002 ENDP = #B0000000011 // 003 DIFF = #B0000000100 // 004 ADD = #B0000000101 // 005 GCALL = #B0000000110 // 006 IN = #B0000000111 // 007 PROD = #B0000001000 // 008 GT = #B0000001001 // 009 WSUB = #B0000001010 // 00A OUT = #B0000001011 // 00B SUB = #B0000001100 // 00C STARTP = #B0000001101 // 00D OUTBYTE = #B0000001110 // 00E OUTWORD = #B0000001111 // 00F SETERR = #B0000010000 // 010 RESETCH = #B0000010010 // 012 CSUB0 = #B0000010011 // 013 STOPP = #B0000010101 // 015 LADD = #B0000010110 // 016 STLB = #B0000010111 // 017 STHF = #B0000011000 // 018 NORM = #B0000011001 // 019 LDIV = #B0000011010 // 01A LDPI = #B0000011011 // 01B STLF = #B0000011100 // 01C XDBLE = #B0000011101 // 01D LDPRI = #B0000011110 // 01E REM = #B0000011111 // 01F RET = #B0000100000 // 020 LEND = #B0000100001 // 021 LDTIMER = #B0000100010 // 022 TESTLDS = #B0000100011 // 023 TESTLDE = #B0000100100 // 024 TESTLDD = #B0000100101 // 025 TESTSTS = #B0000100110 // 026 TESTSTE = #B0000100111 // 027 TESTSTD = #B0000101000 // 028 TESTERR = #B0000101001 // 029 TESTPRANAL = #B0000101010 // 02A TIN = #B0000101011 // 02B DIV = #B0000101100 // 02C TESTHARDCHAN = #B0000101101 // 02D DIST = #B0000101110 // 02E DISC = #B0000101111 // 02F DISS = #B0000110000 // 030 LMUL = #B0000110001 // 031 NOT = #B0000110010 // 032 XOR = #B0000110011 // 033 BCNT = #B0000110100 // 034 LSHR = #B0000110101 // 035 LSHL = #B0000110110 // 036 LSUM = #B0000110111 // 037 LSUB = #B0000111000 // 038 RUNP = #B0000111001 // 039 XWORD = #B0000111010 // 03A SB = #B0000111011 // 03B GAJW = #B0000111100 // 03C SAVEL = #B0000111101 // 03D SAVEH = #B0000111110 // 03E WCNT = #B0000111111 // 03F SHR = #B0001000000 // 040 SHL = #B0001000001 // 041 MINT = #B0001000010 // 042 ALT = #B0001000011 // 043 ALTWT = #B0001000100 // 044 ALTEND = #B0001000101 // 045 AND = #B0001000110 // 046 ENBT = #B0001000111 // 047 ENBC = #B0001001000 // 048 ENBS = #B0001001001 // 049 MOVE = #B0001001010 // 04A OR = #B0001001011 // 04B CSNGL = #B0001001100 // 04C CCNT1 = #B0001001101 // 04D TALT = #B0001001110 // 04E LDIFF = #B0001001111 // 04F STHB = #B0001010000 // 050 TALTWT = #B0001010001 // 051 SUM = #B0001010010 // 052 MUL = #B0001010011 // 053 STTIMER = #B0001010100 // 054 STOPERR = #B0001010101 // 055 CWORD = #B0001010110 // 056 CLRHALTERR = #B0001010111 // 057 SETHALTERR = #B0001011000 // 058 TESTHALTERR = #B0001011001 // 059 DUP = #B0001011010 // 05A MOVE2DINIT = #B0001011011 // 05B MOVE2DALL = #B0001011100 // 05C MOVE2DNONZERO = #B0001011101 // 05D MOVE2DZERO = #B0001011110 // 05E UNPACKSN = #B0001100011 // 063 POSTNORMSN = #B0001101100 // 06C ROUNDSN = #B0001101101 // 06D LDINF = #B0001110001 // 071 FMUL = #B0001110010 // 072 CFLERR = #B0001110011 // 073 CRCWORD = #B0001110100 // 074 CRCBYTE = #B0001110101 // 075 BITCNT = #B0001110110 // 076 BITREVWORD = #B0001110111 // 077 BITREVNBITS = #B0001111000 // 078 POP = #B0001111001 // 079 TIMERDISABLEH = #B0001111010 // 07A TIMERDISABLEL = #B0001111011 // 07B TIMERENABLEH = #B0001111100 // 07C TIMERENABLEL = #B0001111101 // 07D LDMEMSTARTVAL = #B0001111110 // 07E WSUBDB = #B0010000001 // 081 FPTESTERR = #B0010011100 // 09C BREAK = #B0010110001 // 0B1 CLRJ0BREAK = #B0010110010 // 0B2 SETJ0BREAK = #B0010110011 // 0B3 TESTJ0BREAK = #B0010110100 // 0B4 LDDEVID = #B0101111100 // 17C TIMER1REQ = #B0111111000 // 1F8 HandleTimerRequest1 TIMER0REQ = #B0111111001 // 1F9 HandleTimerRequest0 CHAN1REQ = #B0111111010 // 1FA HandleChannelRequest1 CHAN0REQ = #B0111111011 // 1FB HandleChannelRequest0 START = #B0111111111 // 1FF J = #B1000000000 // 200 LDLP = #B1000000001 // 201 PFIX = #B1000000010 // 202 LDNL = #B1000000011 // 203 LDC = #B1000000100 // 204 LDNLP = #B1000000101 // 205 NFIX = #B1000000110 // 206 LDL = #B1000000111 // 207 ADC = #B1000001000 // 208 CALL = #B1000001001 // 209 CJ = #B1000001010 // 20A AJW = #B1000001011 // 20B EQC = #B1000001100 // 20C STL = #B1000001101 // 20D STNL = #B1000001110 // 20E // Non-fixed VBC addresses generated by ROM optimiser (list below is not complete) GAJWprocHigh = #B0100011001 // 119
GAJWprocLow = #B0100011011 // 11B CJupdateInstReg = #B0100101000 // 128 CJpopStack = #B0100101001 // 129
WCNTend1 = #B0100110000 // 130 WCNTshiftPos = #B0100110001 // 131 WCNTend2 = #B0100110010 // 132 WCNTshiftNeg = #B0100110011 // 133
RETend = #B0111001001 // 1C9
GTresultTrue = #B0111100100 // 1E4 GTresultFalse = #B0111100101 // 1E5
RETnext1 = #B1000001111 // 20F
RETnext2 = #B1010001010 // 24A
WCNTtestSign = #B1001101000 ; // 268