; 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]