*----------------------------------------------------------- Title[Various.mc...June 12, 1982 3:15 PM...Taft]; *----------------------------------------------------------- % Miscellaneous subroutines that various emulators may want to use. Contents, by order of appearance: MulSub unsigned 16-bit by 16-bit multiply DivSub unsigned 32-bit by 16-bit divide RequestAUT request action by Asynchronous Utility Task SetDMuxAddress set DMux address and read muffler % * Relative register declarations RVRel[XTemp17, 17]; RVRel[XTemp17, 17]; RVRel[XTemp16, 16]; DontKnowRBase; *----------------------------------------------------------- MulSub: * unsigned 16-bit by 16-bit multiply * Entry conditions: * T = multiplicand * Q = multiplier * Exit conditions: * T = high-order 16 bits of product * Q = low-order 16 bits of product * Clobbers XTemp17 *----------------------------------------------------------- Subroutine; XTemp17← Q; XTemp17, Cnt← 16S, Branch[.+2, R odd]; XTemp17← A0, Multiply, Branch[M0]; XTemp17← A0, Multiply, Branch[M1]; *----------------------------------------------------------- DispTable[4]; * here after Q[14] was 0 (no add) and continue M0: XTemp17← (A← XTemp17), Multiply, DblBranch[M0E, M0, Cnt=0&-1]; * here after Q[14] was 0 (no add) and exit M0E: XTemp17← (A← XTemp17), Multiply, Branch[MXIT0]; * here after Q[14] was 1 (add) and continue M1: XTemp17← (XTemp17)+T, Multiply, DblBranch[M0E, M0, Cnt=0&-1]; * here after Q[14] was 1 (add) and exit XTemp17← (XTemp17)+T, Multiply, Branch[MXIT0]; *----------------------------------------------------------- * Must squash pending Multiply dispatches before returning. MXIT0: T← XTemp17, DispTable[1, 2, 2]; Return, DispTable[1, 2, 2]; *----------------------------------------------------------- DivSub: * unsigned 32-bit by 16-bit divide * Entry conditions: * T,,Q = dividend * XTemp17 = divisor * Call by: SCall[DivSub] * Exit conditions: * +1 return: normal: T=remainder, Q=quotient * +2 return: divide check: T=trap code * Clobbers XTemp16 *----------------------------------------------------------- Subroutine; PD← T-(XTemp17); * Trap if T >= XTemp17 (unsigned) PD← XTemp17, Branch[DivTrap, Carry]; Cnt← 17S, PD← T, Branch[Dneg, ALU<0]; T← T-(XTemp17), Divide, DblBranch[NormalExit, D3, Cnt=0&-1]; D2: T← T+(XTemp17), Divide, Branch[NormalExit, Cnt=0&-1]; D3: Branch[D2, Carry']; T← T-(XTemp17), Divide, Branch[D3, Cnt#0&-1]; NormalExit: Branch[DaddLabel, Carry']; T-(XTemp17), Divide; T← T-(XTemp17), DblBranch[FinalAdd, OKExit, ALU<0]; DaddLabel: T+(XTemp17), Divide; T← T+(XTemp17), Branch[FinalAdd, ALU<0]; OKExit: Return; FinalAdd: T← T+(XTemp17), Return; Dneg: XTemp16← T+T, Branch[Dneg1, ALU<0]; Dneg0: T← A← T, Divide, Branch[Fudge2, Cnt=0&-1]; XTemp16← T+T, DblBranch[Dneg1, Dneg0, R<0]; Dneg1: T← T-(XTemp17), Divide, Branch[Fudge3, Cnt=0&-1]; Dneg3: PD← T, Branch[.+2, Carry']; XTemp16← T+T, DblBranch[Dneg1, Dneg0, ALU<0]; T← T+(XTemp17), Divide, Branch[Fudge4, Cnt=0&-1]; DnegG: PD← T, Branch[.+2, ALU>=0]; T← T-(XTemp17), CDivide, DblBranch[Fudge4, DnegG, Cnt=0&-1]; XTemp16← T+T, DblBranch[Dneg1, Dneg0, ALU<0]; Fudge2: PD← T-(XTemp17); Fudge21: Branch[F23, Carry]; F22: PD← A← T, Divide, Return; F23: PD← T-(XTemp17), Divide, Branch[Fudge42]; Fudge3: PD← T-(XTemp17), Branch[Fudge21, Carry]; PD← A← T, CDivide, Branch[FinalAdd]; Fudge4: PD← T-(XTemp17), Branch[.+2, ALU<0]; DblBranch[F23, F22, Carry]; PD← T-(XTemp17), CDivide; Fudge42: T← T-(XTemp17), Return; DivTrap: T← 14S, Branch[.+2, ALU#0]; * Carry← 0 Return[Carry']; * Mesa sZeroDivisor (=14B), return +2 T← T+1, Return[Carry']; * Mesa sDivideCheck (=15B), return +2 *----------------------------------------------------------- RequestAUT: * Request action by Asynchronous Utility Task. * Entry: T = desired starting PC * Exit: T = ALU = 0 if failed to submit request because one was * already pending; # 0 if succeeded. * RBase clobbered. * Note: the code beginning at the specified PC will execute as AUT, * and should finish by branching to AUTStart. The state of task-specific * registers is undefined at start and finish. * Note: RequestAUT will never fail when called by the Emulator, assuming * all emulator calls are with TaskingOn. *----------------------------------------------------------- Subroutine; RBase← RBase[AUTPC]; AUTPC← (AUTPC) OR (100000C), Branch[.+2, R>=0]; * Test and set flag * AUT request already pending. Return with ALU=0. T← A0, Return; * AUT is free, and we have now locked out further requests. * Set the desired starting PC, awaken the task, and return with ALU#0. * Note that AUTPC = 100000 here. AUTPC← T← T OR (AUTPC), Wakeup[AUT], Return; *----------------------------------------------------------- * The AUT code itself. * AUTPC = 0 => no request is pending. * AUTPC = 100000 + starting PC => request is pending. *----------------------------------------------------------- Subroutine; DontKnowRBase; Set[XTask, IP[AUT]]; AUTInitPC: AUTPC← A0; * Task initialization AUTDispatch: T← AUT, CoReturn; TopLevel; * Microcode routines started by AUT finish by branching here, or by returning. * AUTPC[0]=1 => new request is pending. AUTStart: RBase← RBase[AUTPC]; T← AUTPC← A0, Link← AUTPC, Branch[AUTDispatch, R<0]; TIOA← T, Block, Branch[AUTStart]; * Nothing to do *----------------------------------------------------------- SetDMuxAddress: * Load DMux address and read muffler. * Enter: T[4:15] = DMux address * Exit: T[0] = XTemp17[0] = muffler data * Clobbers T and XTemp17. *----------------------------------------------------------- Subroutine; XTemp17← 13C; SetDLp: T← T+(MidasStrobe← T); * Shift address bit from B[4] XTemp17← NOT (XTemp17), Branch[., R>=0]; * Delay 2 cycles XTemp17← (XTemp17)-1, Branch[SetDLp, ALU#0]; T← XTemp17← ALUFMem, Return;