**Dorado Smalltalk Microcode -- Model 1, XM version ** last edited July 9, 1979 10:14 AM by Deutsch ** last edited September 20, 1982 10:08 AM by Haugeland ** Interface to the Nova emulator and the IFU Title[DsmallInt.MC]; Top Level; M[TrapXIfuReg, IFUReg[#1, 2, MDS, rbAemRegs, #2, 17, 0, 0]]; M[TrapXIfuPause, IFUPause[#1, 2, MDS, rbAemRegs, #2, 17, 0, 0]]; InsSet[AEmuInsSet, 1]; * assemble as Alto emulator instruction *** All Smalltalk returns to the Nova emulator come through here: *EMStart is the normal entry point to the Emulator EMStart: Q_ T, Call[RestoreEMState], global; Call[StopIfu]; T_ Q, Branch[Start]; *Start is the emulator's actual entry point *EMTrap is the entry point to the Emulator trap *EMTrap: * Call[RestoreEMState]; * Branch[NPTrap]; *Go to emulator trap * Subroutine to restore Emulator state Subroutine; RestoreEMState: RBase _ RBase[Arg1]; T _ Arg1, RBase _ RBase[AemRegs]; StkP_ spAC0; Stack _ T, Return; * don't need to set membase Top Level; *EMRun is for trapped instructions that don't want Ac0 _ Arg1 ** not needed any more **EMRun: ** RBase _ RBase[AemRegs]; ** MemBase _ AemMemBase; ** Branch[Start]; *** The Nova emulator enters Smalltalk here: * RBase = AemRegs, IReg = trapped instruction ** After dispatching, control arrives at the instruction code with ** RBase = AemRegs except for NovaReturns, which get RBase = State ** replaced by ifujumps to the various labels dispatched to below % TrapX: KnowRBase[AEMRegs]; T _ Ac0; Arg1 _ T; T _ Ldf[Ireg, 4, 10]; *Ireg has actual instruction//load low 4 bits BigBDispatch _ T; Branch[OpCodeDispatch]; OpCodeDispatch: Branch[Extract], At[Dispatch1, 0]; *700xx Branch[Inject], At[Dispatch1, 1]; *704xx Branch[RefCt], At[Dispatch1, 2]; *710xx Branch[Trap], At[Dispatch1, 3]; *714xx Branch[Sundry], At[Dispatch1, 4]; *720xx Branch[ReadWriteR], At[Dispatch1, 5]; *724xx Branch[Trap], At[Dispatch1, 6]; Branch[Trap], At[Dispatch1, 7]; Branch[Trap], At[Dispatch1, 10]; Branch[Trap], At[Dispatch1, 11]; Branch[StartByterp], At[Dispatch1, 12]; *750xx Branch[Trap], At[Dispatch1, 13]; Branch[Trap], At[Dispatch1, 14]; Branch[Trap], At[Dispatch1, 15]; Branch[NovaRet], At[Dispatch1, 16]; *770xx Branch[Trap], At[Dispatch1, 17]; % * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * StartByterp0: Call[GetPC]; SavPc_ T + 1; * save Alto PC StkP_ spAC0; T_ Stack; Arg1_ T,branch[StartByterp]; TrapXIfuReg[172, StartByterp0]; * 75000-75377 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Sundry: *720xx arrive here, i.e. Nova special ops StkP_ spAC0; * preserve AC0 T_ Stack; Arg1_ T; call[GetPC], ETemp_ Id; SavPc_ T + 1; BDispatch _ ETemp; *dispatch is on low 3 bits only Branch[OpsDispatch]; TrapXIfuPause[164, Sundry]; * 72000-72377 OpsDispatch: Branch[IvalTP], At[Dispatch2, 0]; Branch[HashT], At[Dispatch2, 1]; Branch[Snat], At[Dispatch2, 4]; ** end Sundry code * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *NovaCall and NovaRet--Call to Nova from microcode and return DontKnowRbase; NovaCall: MemBase _ MDS; T _ T + (400c); *Page1BR has disappeared T _ T + (130c); *Load trap op from T (400+130+T) Fetch _ T; RBase _ RBase[AemRegs]; T _ Ireg; SavDisp _ T; T _ Md, Branch[EmStart]; *jump into trap vector (to Nova Instrs.) KnowRBase[AemRegs]; NovaRet: ETemp1 _ (Id) and (37C); *Get low 4 bits of Alto instruction call[GetPC]; SavPc_ T + 1; StkP_ spAC0; T_ Stack; Arg1_ T; call[StartIFU]; * start IFU for smalltalk RBase _ RBase[SavDisp]; T _ SavDisp, RBase _ RBase[AemRegs]; Ireg _ T; BDispatch _ ETemp1; RBase _ RBase[State], Branch[NovaReturns]; TrapXIfuPause[176, NovaRet]; *77000-77377 NovaReturns: Branch[OvRet], At[Dispatch8, 0]; Branch[FiRet], At[Dispatch8, 1]; Branch[FltRet], At[Dispatch8, 2]; Branch[AllocRet], At[Dispatch8, 3]; Branch[PrimFail], At[Dispatch8, 4]; Branch[SndMsg], At[Dispatch8, 5]; Branch[SupRet], At[Dispatch8, 6]; Branch[PrimRet], At[Dispatch8, 7]; FetchTPc: Fetch _ T; T _ Md, Branch[EMStart]; *ReadR/WriteR: Read an R register, with argument in Ac0--returns in/stores Ac1 KnowRBase[AemRegs]; ReadWriteR: ETemp1_ Id; StkP_ spAC0; ETemp1, DblBranch[.ReadR, .WriteR, R Even]; *0=Read, 1=Write .ReadR: BigBDispatch _ Stack&+1; RBase _ RBase[State], Branch[.RRegs]; .WriteR: KnowRBase[AemRegs]; BigBDispatch _ Stack&+1; T _ Stack, RBase _ RBase[State], Branch[.WRegs]; .RRegs: Nop, At[Dispatch9, 0]; *to make dispatch work Breakpoint, At[Dispatch9, 14]; Branch[.ReadPcb], At[Dispatch9, 15]; T _ AOop, Branch[.ReadOut], At[Dispatch9, 17]; T _ Name, Branch[.ReadOut], At[Dispatch9, 44]; RBase _ RBase[ACoreBase], At[Dispatch9, 52]; T _ ACoreBase, Branch[.ReadOut]; KnowRBase[State]; T _ Father, Branch[.ReadOut], At[Dispatch9, 53]; T _ MinAt, Branch[.ReadOut], At[Dispatch9, 54]; Breakpoint, At[Dispatch9, 55]; Breakpoint, At[Dispatch9, 56]; RBase _ RBase[ArecBase], At[Dispatch9, 60]; T _ ArecBase, Branch[.ReadOut]; KnowRBase[State]; Branch[.ReadSavDisp], At[Dispatch9, 62]; RBase _ RBase[BCoreBase], At[Dispatch9, 63]; T _ BCoreBase, Branch[.ReadOut]; KnowRBase[State]; T _ Name, Branch[.ReadOut], At[Dispatch9, 64]; T _ BOop, Branch[.ReadOut], At[Dispatch9, 65]; RBase _ RBase[LocFrameBase], At[Dispatch9, 66]; T _ LocFrameBase, Branch[.ReadOut]; KnowRBase[State]; T _ StackP, Branch[.ReadOut], At[Dispatch9, 67]; T _ Top, Branch[.ReadOut], At[Dispatch9, 70]; Branch[.ReadCaddr], At[Dispatch9, 71]; RBase _ RBase[TFrameBase], At[Dispatch9, 72]; T _ TFrameBase, Branch[.ReadOut]; KnowRBase[State]; RBase _ RBase[SelfBase], At[Dispatch9, 73]; T _ SelfBase, Branch[.ReadOut]; KnowRBase[State]; T _ SupMod, Branch[.ReadOut], At[Dispatch9, 74]; T _ Ctxt, Branch[.ReadOut], At[Dispatch9, 76]; .WRegs: Nop, At[Dispatch10, 0]; *to make dispatch work MemBase _ CoreBaseBr, Branch[.WBr], At[Dispatch10, 14]; Branch[.WritePcb], At[Dispatch10, 15]; AOop _ T, Branch[.JumpOut], At[Dispatch10, 17]; Name _ T, Branch[.JumpOut], At[Dispatch10, 44]; ACoreBase _ T, At[Dispatch10, 52]; MemBase _ ACoreBr, Branch[.WBr]; * Father _ T, Branch[.JumpOut], At[Dispatch10, 53]; Father _ T, At[Dispatch10, 53]; ** this initialization used to be done in the .mb file loaded by midas ** but with etherloading, that doesn't work ** WriteReg #53 is the first time Smalltalk touches the ucode!!! Pcb_ T - T - 1; T_ Rot0Em.c; Rot0Em_ T; T_ RotCMsk.c; RotCMsk_ T; MemBx_ 0S; Branch[.JumpOut]; MinAt _ T, Branch[.JumpOut], At[Dispatch10, 54]; MemBase _ PmBaseBr, Branch[.WBr], At[Dispatch10, 55]; Branch[.WriteRotBase], At[Dispatch10, 56]; ArecBase _ T, At[Dispatch10, 60]; MemBase _ ArecBr, Branch[.WBr]; Branch[.WriteSavDisp], At[Dispatch10, 62]; BCoreBase _ T, At[Dispatch10, 63]; MemBase _ BCoreBr, Branch[.WBr]; Name _ T, Branch[.JumpOut], At[Dispatch10, 64]; BOop _ T, Branch[.JumpOut], At[Dispatch10, 65]; LocFrameBase _ T, At[Dispatch10, 66]; MemBase _ LocFrameBr, Branch[.WBr]; StackP _ T, Branch[.JumpOut], At[Dispatch10, 67]; Top _ T, Branch[.JumpOut], At[Dispatch10, 70]; Branch[.WriteCaddr], At[Dispatch10, 71]; TFrameBase _ T, At[Dispatch10, 72]; MemBase _ TFrameBr, Branch[.WBr]; SelfBase _ T, At[Dispatch10, 73]; MemBase _ SelfBr, Branch[.WBr]; SupMod _ T, Branch[.JumpOut], At[Dispatch10, 74]; Ctxt _ T, Branch[.JumpOut], At[Dispatch10, 76]; TrapXIfuPause[165, ReadWriteR]; * 72400-72777 .ReadPcb: RBase _ RBase[Pcb]; T _ Pcb, Branch[.ReadOut]; .WritePcb: RBase _ RBase[AemRegs]; StkP_ spAC1; T _ Stack&+2; Pcb _ T, Branch[.rjo]; KnowRBase[State]; .WriteRotBase: RBase _ RBase[Hash]; T _ T - (RotCMsk); *address end of Rot RotBase _ T; MemBase _ RotBaseBr; BrLo _ T; RBase _ RBase[AemRegs]; T _ (EmuBrHiReg) - 1; *always carries into high part BrHi _ T, Branch[.Initialize]; KnowRBase[State]; .ReadSavDisp: Breakpoint; *Smalltalk not allowed to read SavDisp .WriteSavDisp: PD _ T - (207c); Branch[.+2, Alu=0]; Breakpoint; *Smalltalk only allowed to write 207 (SendAgain) into SavDisp SavDisp _ T - T - 1, Branch[.JumpOut]; *see FetchMsg/.Nid1 for why -1 .ReadCaddr: RBase _ RBase[Caddr]; T _ Caddr, Branch[.ReadOut]; .WriteCaddr: RBase _ RBase[AemRegs]; StkP_ spAC1; T _ Stack&+2; Caddr _ T, Branch[.rjo]; .WBr: BrLo _ T, Branch[.JumpOut]; .ReadOut: RBase _ RBase[AEMRegs]; StkP_ spAC0; Stack&+3 _ T; .rjo: T_ Stack, branch[start]; *Jmp @.return (StkP -> AC3) .JumpOut: RBase _ RBase[AEMRegs]; StkP_ spAC3, branch[.rjo]; *Initialize: set all base register high bytes to zero (i.e., use low 64K) .Initialize: RBase _ RBase[AemRegs]; T _ EmuBrHiReg; MemBase _ CoreBaseBr, Call[.LoadBrHi]; MemBase _ PmBaseBr, Call[.LoadBrHi]; MemBase _ LocFrameBr, Call[.LoadBrHi]; MemBase _ ArecBr, Call[.LoadBrHi]; MemBase _ TFrameBr, Call[.LoadBrHi]; MemBase _ SelfBr, Call[.LoadBrHi]; MemBase _ ACoreBr, Call[.LoadBrHi]; MemBase _ BCoreBr, Call[.LoadBrHi]; MemBase _ NamesBr, Call[.LoadBrHi]; MemBase _ CodeBr, Call[.LoadBrHi]; call[InitIFU]; Branch[.JumpOut]; Subroutine; .LoadBrHi: BrHi _ T, Return; Top Level; *Nova Hash trap HashT: RBase _ RBase[State]; Call[Hash]; AT[NHRetLoc!], *So failure will go to HFail0 RBase _ RBase[SavPc]; SavPc _ (SavPc) + 1, RBase _ RBase[Hash]; Q _ MyTemp; *old Rot0 left here Residue _ (Residue) - (RpcBit.c); *undo final inc of reprobe count T _ LDF[Residue, 3, 10], Branch[.LoadAcs]; *extract reprobe count HFail0: *Hash leaves reprobe count in MyTemp RBase _ RBase[Hash]; T _ Rsh[Residue, 13]; T _ A _ MyTemp, Q _ B _ T, Branch[.LoadAcs]; *Ac3 _ Res for miss (Insert) .LoadAcs: rbase_ rbase[AemRegs]; StkP_ spAC3; Stack&-2 _ Q; *Ac3 _ old Rot0 for hits, Residue for misses Stack&+1 _ T; *AC1_ reprobe count rbase_ rbase[RotA]; T _ RotA; T _ (RotBase) + T; Stack _ T, RBase _ RBase[SavPc]; T _ SavPc, Branch[EMStart]; *Nova RefCt trap KnowRBase[AemRegs]; RefCt: StkP_ spAC0; T_ Stack; Arg1_ T; Call[GetPC], ETemp_ Id; * 2nd byte of Alto instruction SavSp _ T + 1; A _ ETemp, RBase _ RBase[State], Branch[.NRefD, R Odd]; Nop; *Placement Call[RefCkInc]; *ETemp even, do RefI Branch[RsSp]; TrapXIfuPause[162, RefCt]; * 71000-71377 .NRefD: Call[RefCkDec]; *ETemp odd, do RefD RsSp: RBase _ RBase[SavSp]; T _ SavSp, Branch[EMStart]; *Nova Ival trap KnowRBase[AemRegs]; IvalTp: *Assumes RBase = AemRegs Rbase_ Rbase[SavPc]; SavSp_ SavPc; RBase _ RBase[State]; Call[Ival]; AT[NIRetLoc!], *So failure in Ival will go to PrimFail Arg1 _ T, Branch[RsSp]; *EMStart does Ac0 _ Arg1 *Skip not Atom KnowRBase[AemRegs]; Snat: T _ Stack, RBase _ RBase[MinAt]; * stack = AC0 PD _ T - (MinAt); RBase _ RBase[SavPc], Branch[NotAt, Carry]; T_ (SavPc) + 1, branch[EMStart]; * do skip return NotAt: T_ SavPc, branch[EMStart]; *Extract // 70000 Disp = KnowRBase[AemRegs]; Extract: Stkp_ spAC0; Call[.LoadLshWidth]; *Execute common code T _ (20c); T _ T - (ETemp1); *ETemp1 is LShift T _ T and (17c); T _ Lsh[T, 10]; *Put it in SC field of SHC T _ (T) + (20c); T _ (T) - (ETemp2); *Low nybble is LMask=(16-Width) SHC _ T; *Load shift control word T _ ShiftLMask[Stack]; * shift AC0 Stack+1 _ T, IFUJump[0]; * result in AC1 TrapXIfuReg[160, Extract]; * 70000-70377 *Inject // 70400 Disp = KnowRBase[AemRegs]; Inject: Stkp_ spAC0; Call[.LoadLshWidth]; *Execute common code T _ Lsh[ETemp1, 10]; *Put LShift in SC MyTemp _ Rsh[T, 4]; T _ T + (MyTemp); *Put LShift in RMask T _ (T) + (20c); T _ (T) - (ETemp2); T _ (T) - (ETemp1); *Put 16-(Width+LShift) in LMask MyTemp _ T - (SHC _ T) - 1; *Load SHC, also set MyTemp _ -1 T _ ShiftBothMasks[MyTemp]; *Put 1's in field of zeros Stack _ (Stack) and Not (T); *put zeroes in field of Ac0 Stack&+1; T _ ShiftBothMasks[Stack]; *Use same WF parameter Stack&-1; Stack _ (Stack) or (T), IFUJump[0]; *Lor in Ac1 TrapXIfuReg[161, Inject]; * 70400-70777 Subroutine; KnowRBase[AemRegs]; .LoadLshWidth: T _ Id; ETemp1 _ Ldf[T, 4, 0]; *Lshift field--low nybble of low byte ETemp2 _ Ldf[T, 4, 4], Return; *Width field--high nybble of low byte Top Level; ** IFU interface ** IFU exceptional conditions IfuFault: AT[200], Breakpoint; IfuFGParity: AT[204], Breakpoint; IfuReschedule: AT[214], Branch[ReSched]; IfuNotReady: AT[234], IfuJump[0]; IfuRamPE: AT[274], Breakpoint; ReSched: NoReschedule; *do first to handle race with higher priority tasks RBase _ RBase[AemRegs]; PD _ Nww, RBase _ RBase[State], Branch[.DontInt, R<0]; *interrupts disabled PD _ Mode, Branch[.DontInt1, Alu=0]; *no interrupt PD _ (SupMod)+1, RBase _ RBase[IfuState], Branch[.DontInt2, Alu#0]; *don't separate Smash and following bytecode T _ 2c, Branch[.DontInt3, Alu#0]; *don't separate Super and following byte Q_ T; *trap to loc. 2 to handle interrupt Call[StopForReSched]; T_ Q, RescheduleNow, Branch[EMStart]; *so Nova emulator will notice Nww .DontInt2: Reschedule, Branch[.TestLoad]; *interrupt again after current bytecode .DontInt3: Reschedule, Branch[.TestLoad]; *interrupt again after current bytecode .DontInt: RBase _ RBase[IfuState], Branch[.TestLoad]; .DontInt1: RBase _ RBase[IfuState], Branch[.TestLoad]; .TestLoad: A _ Pcb, Branch[.Loaded, R<0]; *check if reload required Nop; *placement Call[StartIfu]; Pcb_ T - T - 1, IfuJump[0]; * know rbase is OK .Loaded: T _ Not (PCX'), Branch[JumpIfu]; *do preempted instruction * Load state and start IFU, if not already fetching Subroutine; StartIfu: NoReschedule; RBase _ RBase[IfuState]; InsSetOrEvent_ SmtInset; MemBX_ 0S; T _ (Pcb) rsh 1, Branch[.Started, R<0]; T _ (Caddr) - T, MemBase _ CodeBr; *compute code base Brlo _ T; CodeBase _ T; PCF _ Pcb; .Started: ReSchedule; RBase _ RBase[State], Return; *Pcb is set to -1 by IFUJump[0] * Set code base to T MapCode: RBase _ RBase[IfuState]; Caddr _ T, MemBase _ LocFrameBr; T _ T + (3c); BrLo _ T; LocFrameBase _ T; T _ (Pcb) rsh 1; Caddr _ (Caddr) + T, RBase _ RBase[State], Return; * Stop IFU and unload state, if not already stopped *** Not OK to StopIfu if no IfuJump since last StartIfu ** if Pcb<0 then we know Smalltalk has done an IFUJump[0] StopIfu: RBase _ RBase[IfuState]; A _ Pcb, MemBase _ CodeBr, Branch[.Stopped, R>=0]; Pcb _ (Id) - (PCX') - 1, Branch[.GetCaddr]; * Id = length StopForReSched: *same as StopIfu, but Pcb=PCX RBase _ RBase[IfuState]; A _ Pcb, MemBase _ CodeBr, Branch[.Stopped1, R>=0]; Pcb _ Not (PCX'); .GetCaddr: T _ (Pcb) rsh 1; Caddr _ (CodeBase) + T; .Stopped: RBase _ RBase[State], Return; .Stopped1: RBase _ RBase[State], Return; * Initialize the IFU DontKnowRBase; InitIfu: T _ 100400c; *instruction set 1 SmtInset _ T, Return; Top Level; (500)\1b163B1b46B229b66B1b51B135b49B78b39B165b62B103b226B903b64B118b50B1b64B227b45B123b19B1b125B630b44B368b79B2158b181B1033b49B1105b74B549b15B785b17B275b44B106b16B250b15B232b41B404b44B1b40B592b43B216b17B2b30B1267b52B330b21B186b166B438b21B * Set PCF to T and restart IFU JumpIfu: PCF _ T; Nop; *hardware glitch IfuJump[0]; (1270)\1b31B