; PupTestCPMc.mu -- main microcode source for PupTest ComProc version ; Copyright Xerox Corporation 1979 ; Last modified September 10, 1978 6:15 PM by Boggs #AltoConsts23.mu; ; Reset locations of the tasks to be started in the Ram. !17, 20, Emulator, xREST, EREST, , , , CommProcTask, , MRT; ; Ram entry point for fielding undefined opcodes. !37, 1, TRAP1; ; Reserve 774-1003 for Ram Utility Area. %7, 1777, 774, RU774, RU775, RU776, RU777, RU1000, RU1001, RU1002, RU1003; ; For the moment, just throw these locations away. This is done only ; to squelch the "unused predef" warnings that would otherwise occur. ; If we ever run short of Ram, assign these to real instructions somewhere ; in microcode executed only by the Emulator. RU774: NOP; RU775: NOP; RU776: NOP; RU777: NOP; RU1000: NOP; RU1001: NOP; RU1002: NOP; RU1003: NOP; ; **** Modified Memory Refresh Task **** #CPMRT.mu; ; **** ComProc microcode **** #CommProc.mu; ; **** Extra Ethernet microcode **** $ECNTR $R14; $EPNTR $R15; #ExtraEther1.mu; $xCNTR $R16; $xPNTR $R17; #ExtraEther2.mu; ; Nova emulator conventions $START $L4020, 0, 0; $AC3 $R0; $AC2 $R1; $AC1 $R2; $AC0 $R3; $NWW $R4; $SAD $R5; $PC $R6; $XREG $R7; $XH $R10; $LREG $R40; Emulator: SWMODE; Switch to Rom1 :START; Nova emulator entry point ; Trap handler and dispatcher for instructions that trap into ; the RAM. In the following predefinition, the tags correspond ; to opcodes 60000, 60400, 61000, 61400, ... 77400. ; Note that opcodes 60000, 60400, 61000, 64400, 65000, 67000, and 77400 ; cannot be used since control never gets to the RAM for these. ; 61400 GetFrame ; 62000 Return ; 62400 BcplUtility ; 63000 SilentBoot ; 63400 EnableEIA ; 63400 SetLineTab (ComProc) ; 64000 PupChecksum ; 65400 ChangeControlReg (ComProc) ; 66000 BlockEq !37,40, TrapDispatch, , , GetFrame, Return, BcplUtility, SilentBoot, SetLineTab, PupChecksum, , , ChangeControlReg, BlockEq; ; Control comes here with the instruction LCY 8 in XREG TRAP1: T← 37; L← XREG AND T; TrapDispatch: SINK← M, BUS, TASK; :TrapDispatch; ; **** BCPL runtime microcode **** #GetFrame.mu; #BcplUtil.mu; ; SilentBoot instruction: ; Accepts in: ; AC0/ boot locus vector ; Sets the Boot Locus Vector and does a silent boot. SilentBoot: RMR← AC0; Set BLV from arg SINK← 100000, STARTF, :Emulator; Boot the machine, resume emulator ; SetLineTab subroutine: ; Accepts in: ; AC0/ LINTAB ; Specifies the address of the Line Table (LINTAB). SetLineTab: L← AC0, TASK; LINTAB← AC0 LINTAB← L, :Emulator; ; ChangeControlReg subroutine: ; Accepts in: ; AC0/ lineTimes4 ; AC1/ changeMask ; Changes (sets or resets) bits in the control word for a line. ; The change is atomic with respect to CommProc task execution. ; lineTimes4: 4 times the line number to be affected. ; changeMask: Bits 4:15 are a mask of bits to be affected and bit 0 is ; the desired new value of those bits. ChangeControlReg: L← AC0; lineTimes4 LINE*4← L; T← AC1; T← changeMask L← LCRetX#, :LIMCon0; L← LIMCon0 return index LCRetX: :Emulator; ; Pup Checksum instruction ; Computes the ones-complement add-and-cycle checksum over the block. ; Accepts in: ; AC0/ 0 initially ; AC1/ address of block ; AC3/ length of block (words) ; Returns: ; AC0/ result ; AC1/ address+length-1 ; AC3/ 0 ; This instruction is interruptible. If an interrupt occurs, intermediate ; state is stored in the ACs and the PC is backed up so the instruction will ; start over when the interrupt is dismissed. ; Timing: 9 cycles/word ; 2484 cycles (= 422 microseconds) per maximum-length Pup !1,2,PCMayI,PCNoI; !1,2,PCDoI,PCDisI; !1,2,PCNoCy,PCCy; !1,2,PCLoop,PCDone; !1,2,PCNoMZ,PCMinZ; PupChecksum: MAR← L← AC1, :PCLp1; Start fetch of first word ; Top of main loop PCLoop: MAR← L← AC1+1; Start fetch of next word PCLp1: AC1← L; Update pointer L← NWW, BUS=0; Test for interrupts T← AC0, SH<0, :PCMayI; [PCMayI, PCNoI] Get partial sum PCNoI: L← MD+T, :PCDisI; Add new word PCDisI: T← M, ALUCY; Test for carry out L← AC3-1, :PCNoCy; [PCNoCy, PCCy] Decrement count PCNoCy: AC3← L, L← T, SH=0, TASK, :PCLast; No carry PCCy: AC3← L, L← T← 0+T+1, SH=0, TASK; Do end-around carry PCLast: AC0← L MLSH 1, :PCLoop; [PCLoop, PCDone] Left cycle 1 ; Here when done PCDone: L← AC0+1; Test for minus zero (ones-complement) L← PC, SH=0; PCDn1: PC← L, L← 0, TASK, :PCNoMZ; [PCNoMZ, PCMinZ] PCNoMZ: :Emulator; PCMinZ: AC0← L, :Emulator; Minus zero, change to plus zero ; Here when have potential interrupt; branch pending on disable bit. PCMayI: L← MD+T, :PCDoI; [PCDoI, PCDisI] PCDoI: L← PC-1, :PCDn1; Back up PC ; Fast Block compare instruction ; Accepts in: ; AC0/ address of block0 ; AC1/ address of block1 ; AC3/ number of words to compare ; Returns: ; AC3/ offset of first not equal pair of words !1,2,BeMore,BeDone; !1,2,BeMaybeInt,BeNoInt; !1,2,BeError,BeMain; !1,2,BeDoInt,BeIntOff; BlockEq: L← AC1-1; AC1← L; MAR← L← AC0, :Be2; ; Main loop is 12 cycles - runs memory at full (single word) speed BeMain: MAR← L ← AC0+1; Fetch a word from block 0 Be2: AC0← L; L← AC3-1, BUS=0; Update count, check for done AC3← L, :BeMore; [BeMore,BeDone] BeMore: T← MD; MAR← L← AC1+1; Fetch a word from block 1 AC1← L; L← NWW, BUS=0; Check for interrupts SH<0, :BeMaybeInt; [BeMaybeInt,BeNoInt] BeNoInt: L← MD-T; Check for words equal BeIntOff: SH=0, TASK; :BeError; [BeError,BeMain] BeMaybeInt: L← MD-T, :BeDoInt; [BeDoInt,BeIntOff] BeDoInt: L← PC-1, TASK; Save state for interrupt PC← L; BeError: SWMODE, L← AC3+1, :Be3; Come here on compare error BeDone: SWMODE, L← AC3+1; Come here when done Be3: AC3← L, :START;