:TITLE[MesaIO]; *3 October 1983 by Fiala %This file assembles a driver for one of the io kludges. At present the choice lies between the floating point board io kludge (for Petit), CCA board (for Thacker/Petit), and DES board (for Gifford). These each use MISC 14b for the driver. % :IF[WithCCABoard]; ******************************** %At entry to the opcode, there are starting at TOS: Long pointer to the blocks of tester data (Table starts at word 8-- the first two quadwords are used by the opcode for temp storage); Long pointer to step control info. Cardinal count of number of steps to execute; The cardinal count should be non-zero originally; it is kept in a register decremented after each successful step. If the step includes data comparison, and if the comparison fails, the count is not decremented and the opcode terminates with that count as its result. Interrupts are NOT allowed between steps. Step-control info is a packed array with 1 nibble/step where the left-most two bits of each nibble are the count minus one of quadwords to output for the current step, the third bit is 1 if the second input quadword should be checked, and the fourth bit is 1 if the first input quadword should be checked. This array must begin on a quadaligned storage boundary. Tester data for each step consists of 1 to 4 output quadwords followed by 0 (no input checking), 2 (1 input quadword checked) or 4 (both input quadwords checked) input quadwords. The first of each pair of input quadwords is the correct value for the data and the second is a comparison mask. Input checking is carried out as follows: IOStore4 stores the results which are then PFetch4'ed into RM; then the expected quadword is read and xor'ed; finally, the xor'ed result is anded with the mask quadword. If the result is non-zero, the instruction exits with the step number at which the comparison was non-zero at TOS. Register assignments: LP/LPhi point at the tester data; LPDest/LPDesthi point at the step-control data; zBuf2/zBuf3 point at the temporary quadword. xBuf-xBuf3 for quadwords of tester data being output and for results which are first IOStore4'ed in storage and then PFetch4'ed; yBuf-yBuf3 expected data; mask; zBuf current word of step-control info; zBuf1 counts steps remaining in the current word; Stack step count. % Set[ccTask,0]; Set[ccOut,Add[LShift[ccTask,4],1]]; Set[ccIn,Add[LShift[ccTask,4],1]]; @ccOpr: T _ Stack&-1, LoadPage[opPage1], At[EscD10,7]; LPhi _ T, CallP[StackLPy]; *StackLPy returns after LP,,LPhi _ TOS-1,,TOS with stack popped twice, *LPhi bounds-checked and in base register format, LP in T. zBuf2 _ T, LoadPage[ccPage]; *Base reg pointing at temp storage T _ LPhi; OnPage[ccPage]; zBuf3 _ T; LP _ (LP) + (10C); *Advance LP past temp storage *Next do the same thing for the LPDest,,LPDesthi base register (but no *subroutine is available for this one). T _ Stack&-1; LPDestHi _ T; LPDestHi _ (LSh[LPDestHi,10]) + T + 1; T _ Stack&-1; *Point StkP at step-count LPDest _ T; cc4Step: PFetch1[LPDest,zBuf,0]; *Fetch next step control word. zBuf1 _ 3C; cc1Step: IOFetch4[LP,ccOut,0], Call[ccAdLP]; LU _ (zBuf) and (140000C); *Test for another output block zBuf _ (zBuf) - (40000C), GoTo[cc1Step,ALU#0]; LU _ (zBuf) and (30000C); *check for any check/read required LU _ (zBuf) and (10000C), Skip[ALU#0]; *check for first block Stack _ (Stack)-1, GoTo[ccNoChk]; PFetch4[LP,yBuf,0], GoTo[SecondOnly,ALU=0]; *some block not first => second LP _ (LP) + (4C), Call[ccAdLP1]; *we are checking some block(s) IOStore4[zBuf2,ccIn,0]; *tester to core, first block LU _ (zBuf) and (20000C); PFetch4[zBuf2, xBuf,0], GoTo[FirstOnly,ALU=0]; *core to R, first block *Here, we know we are to check both blocks of tester data. The first block's *tester data is in xBuf, and the desired result is in yBuf. T _ yBuf, Call[ccChk1A]; IOStore4[zBuf2, ccIn, 4]; *tester to core, second block T _ xBuf; yBuf _ (yBuf) and T; T _ xBuf1, Skip[ALU=0]; LoadPage[opPage3], GoTo[ccExit]; yBuf1 _ (yBuf1) and T; T _ xBuf2, Skip[ALU=0]; LoadPage[opPage3], GoTo[ccExit]; yBuf2 _ (yBuf2) and T; T _ yBuf3, Skip[ALU=0]; LoadPage[opPage3], GoTo[ccExit]; PFetch4[LP,yBuf,0]; *second block desired results LP _ (LP) + (4C), Call[ccAdLP1]; xBuf3 _ (xBuf3) and T; PFetch4[zBuf2,xBuf,4], Skip[ALU=0]; *core to R, second block LoadPage[opPage3], GoTo[ccExit]; T _ yBuf; xBuf _ (xBuf) xor T, Call[ccChk1A1]; T _ yBuf, goto[FOx]; SecondOnly: LP _ (LP) + (4C); *increment LP IOStore4[zBuf2, ccIn,0],Skip[Carry']; *tester to core, first (useless) block LPHi _ (LPHi) + (400C) + 1; IOStore4[zBuf2, ccIn,4]; *tester to core, second block PFetch4[zBuf2, xBuf,4]; *core to R, second block FirstOnly: T _ yBuf; xBuf _ (xBuf) xor T, Call[ccChk1A1]; T _ yBuf; FOx: xBuf _ (xBuf) and T; T _ yBuf1, Skip[ALU=0]; LoadPage[opPage3], GoTo[ccExit]; xBuf1 _ (xBuf1) and T; T _ yBuf2, Skip[ALU=0]; LoadPage[opPage3], GoTo[ccExit]; xBuf2 _ (xBuf2) and T; T _ yBuf3, Skip[ALU=0]; LoadPage[opPage3], GoTo[ccExit]; xBuf3 _ (xBuf3) and T; Skip[ALU=0]; LoadPage[opPage3], GoTo[ccExit]; Stack _ (Stack)-1; ccNoChk: zBuf1 _ (zBuf1)-1, Skip[ALU#0]; *check for count exhausted LoadPage[opPage3], GoTo[ccExit]; LU _ (LPDest) + 1, Skip[ALU<0]; *check for step control word exhausted zBuf _ LSh[zBuf,4], GoTo[cc1Step]; *Another step in this word LPDest _ (LPDest) + 1, GoTo[cc4Step,Carry']; LPDestHi _ (LPDestHi) + (400C) + 1; GoTo[cc4Step]; *1 mi required after LPDestHi_ before ref. ccChk1A: xBuf _ (xBuf) xor T; ccChk1A1: T _ yBuf1; xBuf1 _ (xBuf1) xor T; T _ yBuf2; xBuf2 _ (xBuf2) xor T; T _ yBuf3; PFetch4[LP,yBuf,0]; *Retrieve mask LP _ (LP) + (4C); xBuf3 _ (xBuf3) xor T, Skip[Carry']; LPHi _ (LPHi) + (400C) + 1, Return; Return; ccAdLP: LP _ (LP) + (4C); ccAdLP1: Skip[Carry']; LPHi _ (LPHi) + (400C) + 1, Return; Return; ccExit: GoToP[P7Tail]; :ELSE; ******************************************** xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD10,7]; :ENDIF; ******************************************* :IF[WithFPBoard]; ********************************* %This is a general purpose opcode for driving the floating point board, which must have been initialized to run on behalf of task 0. TOS,,TOS-1 Long pointer to quadword for arguments TOS-2 Count of quadwords to be output (.ge. 1) TOS-3 Count of quadwords to be input (.ge. 1) Leaves stack cleared. Approximate execution time = 79.5 + 10/extra IOFetch4 or IOStore4 cycles. % Set[fpTask,0]; *Has to be 0 for IOStrobe to go to correct device (?) Set[fpBOut,Add[LShift[fpTask,4],0]]; Set[fpBIn,Add[LShift[fpTask,4],3]]; @FPOPR: T _ Stack&-1, LoadPage[opPage1], At[EscD10,10]; LPhi _ T, CallP[StackLPy]; *StackLPy returns after LP,,LPhi _ TOS-1,,TOS with stack popped twice, *LPhi bounds-checked and in base register format. T _ (Stack&-1) - 1, LoadPage[fpbPage0]; *T _ quadword argument count RTemp _ T, IOStrobe, GoToP[.+1]; *Zero FP board address register OnPage[fpbPage0]; IOFetch4[LP,fpBOut,0]; *Output arguments LP _ (LP) + (4C), Call[AdvLP4]; RTemp, GoTo[.-2,R>=0]; *** T _ Stack&-1, LoadPage[opPage1]; *** CallP[StackLPx]; *The IOStrobe must not occur sooner than the 2nd mi after the task wakeup T _ (Stack&-1) - 1, Call[Kill2]; *This IOStrobe must not occur until the last word from the previous IOFetch4 *has been received by the FP board; this seems to imply that the IOStrobe *must occur 17 cycles after the IOFetch4 starts plus at most 6 cycles for *additional delay until the IOFetch4 has started on MC2 (??). Nop; Call[Kill2]; Call[Kill2]; Nop; RTemp _ T, IOStrobe, Call[.+1]; *Start FP board running *Must not test IOAtten sooner than the 2nd mi after tasking. Nop; Skip[IOAtten]; *Wait for it to finish Kill2: Return; Nop; IOStore4[LP,fpBIn,0]; *Read back results LP _ (LP) + (4C), Call[AdvLP4]; RTemp, GoTo[.-2,R>=0]; LU _ NextInst[IBuf], Call[P4Tailx]; AdvLP4: RTemp _ (RTemp) - 1, Skip[Carry']; LPhi _ (LPhi) + (400C) + 1, Return; *64k boundary crossing Return; :ELSE; ******************************************** xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD10,10]; :ENDIF; ******************************************* :IF[WithDESBoard]; ******************************** ER[No.code.for.desKludge]; :ELSE; ******************************************** xfTrapParm0 _ T, LoadPage[opPage0], GoTo[moUnimpx], At[EscD10,12]; :ENDIF; ******************************************* :END[MesaIO]; (2048)\f2