; DoradoMc.Mu -- Alto microcode to facilitate controlling Dorado ; Last editted: April 6, 1979 4:42 PM ; Dedicated S-registers $UTILOUT $R52; Address of Diablo Printer output register $UTILIN $R53; Address of Diablo Printer input register ; Sensible names for existing constants! $1 $1; $400 $400; $4000 $4000; $10000 $10000; ; RDMux instruction ; AC0: clock bits (DAddrBit and Strobe must be 0) ; AC1: starting DMux address (must be 0) ; AC3: pointer to DMuxTab ; Reads all 2048 DMux addresses except 2047 ; Stores DMux bit i into bit i mod 16 of word i/16 of DMuxTab, which ; should be zeroed initially. ; AC1← 0 upon normal termination. If an interrupt occurs, AC1 ← some ; intermediate address at which the instruction resumes when the interrupt ; is dismissed. ; This code is optimized for Alto-II, though it should work on Alto-I also. ; Timing: 223 + (27 * number of zero data bits) + (35 * number of one bits) ; microinstructions (assuming no interrupts). ; Execution time (assuming equal number of zeroes and ones): ; = 63711 microinstructions = 10.83 ms !1,2,DInitL,DInitD; !1,2,DMaybe,DNoInt; !1,2,DDoInt,DDisab; !7,10,,,IRBr2,IRBr3,,,IRBr6,IRBr7; !1,2,DData1,DData0; !17,20,DBit0,DBit1,DBit2,DBit3,DBit4,DBit5,DBit6,DBit7, DBit8,DBit9,DBit10,DBit11,DBit12,DBit13,DBit14,DBit15; !1,2,RDLoop,DDone; !1,2,NDone,Exit; ; Initialize by shifting four zeroes and then the high-order 10 bits of ; the DMux address into the address register. RDMux: L← AC1; Initial DMux address SAD← L LSH 1; L← 16, TASK; Iteration count XREG← L; ; Initialization loop DInitL: T← SAD; MAR← UTILOUT; Start store of address bit with strobe off T← 100000 . T; Extract address bit L← T← AC0 OR T; Merge into clock bits as DAddrBit MD← M; L← SAD; MAR← UTILOUT; Start store of address bit with strobe on SAD← L LSH 1; SAD← address lsh 1 for next iteration L← 100 OR T; Strobe = 100 MD← M; MAR← UTILOUT; Start store of address bit with strobe off L← XREG-1; Decrement and test count XREG← L, L← T, SH=0, TASK; MD← M, :DInitL; [DInitL, DInitD] ; SAD now has the low-order address bit in bit 0, rest zeroes DInitD: T← SAD; L← AC0 OR T; Set DAddrBit if appropriate AC0← L; Store clock bits for first main iteration L← AC1, TASK; SAD← current address rsh 1 SAD← L RSH 1; ; RDMux instruction (cont'd) ; Main DMux address generator loop. ; AC0: clock bits (DAddrBit = low bit of current DMux address, Strobe = 0) ; AC1: current DMux address ; AC3: pointer to DMuxTab ; SAD: current DMux address right-shifted 1 RDLoop: MAR← UTILOUT; Start store of address bit with strobe off L← NWW, BUS=0; Test for interrupts L← SAD, SH<0, :DMaybe; [DMaybe, DNoInt] Get DMux address rsh 1 DMaybe: MD← T← AC0, :DDoInt; [DDoInt, DDisab] DNoInt: MD← T← AC0; Pending branch can't take DDisab: SAD← L RSH 1; SAD ← DMux address rsh 2 MAR← UTILOUT; Start store of address bit with strobe on L← 100 OR T; Strobe = 100 T← SAD; MD← M, L← T, TASK; SAD← L RSH 1; SAD ← DMux address rsh 3 MAR← UTILOUT; Start store of address bit with strobe off IR← AC1; Load DISP, branch on DMux address bits 5-7 T← 100000, :IRBr2; DAddrBit -- prepare to set next address bit IRBr2: MD← AC0, L← AC0 OR T, TASK, :IRBrX; Bit 5 = bit 7, generate a 1 IRBr7: MD← AC0, L← AC0 OR T, TASK, :IRBrX; IRBr3: MD← AC0, L← AC0 AND NOT T, TASK, :IRBrX; Bit 5 # bit 7, generate a 0 IRBr6: MD← AC0, L← AC0 AND NOT T, TASK, :IRBrX; IRBrX: AC0← L; Update clock bits for next iteration ; *** Delay to permit clock (trailing edge of strobe) to get all the way ; *** out to the Dorado and the resulting data to get all the way back. NOP; NOP; NOP; TASK; NOP; MAR← UTILIN; Start fetch of DMux data L← SAD; SAD← L RSH 1; SAD ← DMux address rsh 4 T← 4000; L← MD AND T; Mask DMux data bit T← SAD, SH=0; DMux address rsh 4 = word offset in table MAR← L← AC3+T, :DData1; [DData1, DData0] Start fetch of DMuxTab word ; Data bit is a 1. Set bit in table. IR (DISP) contains DMux address. DData1: SINK← DISP, SINK← X17, BUS; 16-way branch on bit number :DBit0; [DBit0 .. DBit15] DBit0: T← 100000, :DBitS; DBit1: T← 40000, :DBitS; DBit2: T← 20000, :DBitS; DBit3: T← 10000, :DBitS; DBit4: T← 4000, :DBitS; DBit5: T← 2000, :DBitS; DBit6: T← 1000, :DBitS; DBit7: T← 400, :DBitS; DBit8: T← 200, :DBitS; DBit9: T← 100, :DBitS; DBit10: T← 40, :DBitS; DBit11: T← 20, :DBitS; DBit12: T← 10, :DBitS; DBit13: T← 4, :DBitS; DBit14: T← 2, :DBitS; DBit15: T← 1, :DBitS; DBitS: T← MD OR T; Merge bit into existing table word MAR← M; Store it back L← T, TASK; MD← M; ; RDMux instruction (cont'd) ; Here if data bit is a 0. Now generate next address. ; High-order bit (= DAddrBit) of AC0 already contains next address bit. DData0: T← AC1; Current DMux address L← 1777 AND T; Strip off high bit SAD← L; Store next address rsh 1 for next iteration T← AC0, SH=0, TASK; AC1← L MLSH 1, :RDLoop; [RDLoop, DDone] ; Maybe we are done -- make sure DDone: SINK← AC1, BUS=0, TASK; Whole address zero? :NDone; [NDone, Exit] NDone: :RDLoop; No, repeat ; Here if an interrupt occurs DDoInt: T← 100000; Mask out DAddrBit L← AC0 AND NOT T; AC0← L; L← PC-1, TASK; Back up pc PC← L; Exit: SWMODE; :START; ; InitMc instruction ; Initializes S-registers needed by the DMux-reading instructions InitMc: T← 177000; L← 16 OR T; Manufacture constant 177016 UTILOUT← L; L← 30 OR T, TASK; Manufacture constant 177030 UTILIN← L, :Exit; ; DStrobe instruction ; Strobes data into the Dorado control register ; AC0: control bits (Strobe should be zero) DStrobe: MAR← UTILOUT; Start store with Strobe off NOP; MD← T← AC0; MAR← UTILOUT; Start store with Strobe on L← 100 OR T; Strobe = 100 MD← M; MAR← UTILOUT; Start store with Strobe off TASK; MD← AC0, :Exit; ; MIRLoad instruction ; Accepts the following arguments: ; AC0: control word (Strobe should be zero) ; AC1: pointer to 4-word block of data for MIR0..MIR3 ; Executes the following sequence: ; DStrobe[AC0] ; DStrobe[AC0+ClrStop+ClrMIR] ; DStrobe[AC0] ; DStrobe[AC1!0] ; DStrobe[AC1!1] ; DStrobe[AC1!2] ; DStrobe[AC1!3] ; Execution time: 130 microinstructions = 22 microseconds !7, 10, DStrR0, DStrR1, DStrR2, DStrR3, DStrR4, DStrR5, DStrR6; MIRLoad: MAR← UTILOUT; DStrobe[AC0] IR← 0; Init return index to 0 L← T← AC0, :DStrS1; DStrR0: T← AC0; DStrobe[AC0+42000] T← 40000 OR T; T← 2000 OR T, :DStrSub; DStrR1: T← AC0, :DStrSub; DStrobe[AC0] DStrR2: MAR← L← AC1, :MIRL1; DStrobe[AC1!0] DStrR3: MAR← L← XREG+1, :MIRL1; DStrobe[AC1!1] DStrR4: MAR← L← XREG+1, :MIRL1; DStrobe[AC1!2] DStrR5: MAR← L← XREG+1, :MIRL1; DStrobe[AC1!3] DStrR6: :Exit; MIRL1: XREG← L; T← MD, :DStrSub; ; DStrobe subroutine; called with control word in T and ; return index -1 in IR; increments IR. DStrSub: MAR← UTILOUT; Start store with Strobe off L← DISP+1; Increment return index IR← M, L← T; DStrS1: MD← M; MAR← UTILOUT; Start store with Strobe on SAD← L; L← 100 OR T, TASK; Strobe = 100 MD← M; MAR← UTILOUT; Start store with Strobe off SINK← DISP, BUS, TASK; Dispatch on return index MD← SAD, :DStrR0; [DStrR0..DStrR6]