; SwatResident.asm -- OS-resident part of Swat ; Matching file in Swat is SwatResident.bcpl, which has detailed ; knowledge about everything in this file. ; Copyright Xerox Corporation 1979 ; Last modified May 5, 1979 8:09 PM by Boggs .titl SwatRes ; Keyboard commands: ; Abort current subsystem ; Invoke Swat debugger ; Trap instructions: generalTrap = 77400 ; General "get me to Swat" instruction parityTrap = 77401 ; PC -> parity error info block callSwatTrap = 77402 ; CallSwat(string [], string[]) errorTrap = 77403 ; AC0 -> error file name ; AC1 -> table [errcode,p1,p2,...] callReturnTrap = 77404 ; Return from procedure called from Swat screenTrap = 77405 ; Return from UserScreen ^U breakPtTrap = 77406 ; Normal breakpoint mpbpTrap = 77407 ; Multiple proceed breakpoint kbdTrap = 77410 ; abortTrap = 77411 ; teleSwatTrap = 77412 ; Become a TeleSwat Server ; Outgoing procedures .ent CallSwat .ent SwatTrap .ent SwatInterrupt ; Incoming procedures .bext OsFinish .bext UpdateTimer .bext InLd, OutLd ; Outgoing statics .bext lvAbortFlag .bext lvSwatContextProc .srel CallSwat: .CallSwat SwatTrap: .SwatTrap SwatInterrupt: .SwatInterrupt lvAbortFlag: abortOK ; 0 => Permit aborts lvSwatContextProc: swatCP ; -> Swat context switching procedure SimIns: .SimIns .nrel ; structure SI: // Simulated Instruction ; [ siInstr = 0 ; instr word // simulating instruction siDoIt = 1 ; doIt word // 0: default, 1: jmp, 2: bri siSim = 2 ; sim word // simulation routine siDisp = 3 ; disp word // sign extended displacement siBase = 4 ; baseReg word // 0 or -> trapAdd, trapAC2, or AC3 siInd = 5 ; ind word // number of times to indirect ; ] lenSI = 6 ; manifest lenSI = size SI/16 ; structure MPBP: // Multiple Proceed Break Point ; [ ; @SI mpbpAddr = lenSI ; mpbpAddr word // address for this MPBP mpbpCnt = lenSI+1 ; mpbpCnt word // proceed count ; ] lenMPBP = lenSI+2 ; manifest lenMPBP = size MPBP/16 numMPBP = 2 ; INVARIANT: trapVector!swatTrapNo = 567B -> this table: ;-------------- S W A T C O M M U N I C A T I O N T A B L E -------------- .SwatTrap: jmp TrapHandler ; Entry point for traps. 25. ; Swat Version number resumeFlag: .blk 1 ; Non-zero => jmp to codeVector on InLd temp: .blk 1 ; Padding to make FPs be in published place swateeFP: -1 ; FP for Swatee -- contains REAL disk address -1 -1 -1 -1 swatFP: -1 ; FP for swat -- contains REAL disk address -1 -1 -1 -1 MPBPTable: .blk numMPBP*lenMPBP SimIns ; Must be in codeVector-1 codeVector: .blk 35. ; Contents known only to Swat ;----------------------------------------------------------------------------- swatCP: .blk 1 ; zero or -> Swat context procedure .WW: 452 ; -> Wakeups waiting .Active: 453 ; -> Active interrupt channels KBLK = 521 .KBLK: KBLK ; -> Disk command chain head TrapPC = 527 IntPC = 500 .SCM: SwatTrap ; -> -> Swat Comm Table nMPBP1: numMPBP+1 lMPBP: lenMPBP oMPBP: MPBPTable-.SwatTrap .CallSwat: callSwatTrap ; All you do is just... jmp 1,3 ; All traps come here TrapHandler: ; Save machine state sta 2 @.userAC2 dirs mkzero 2 2 skp ; interrupts were off *** don't clobber carry mkminusone 2 2 ; interrupts were on *** don't clobber carry sta 2 @.userInt lda 2 .KBLK sta 0 userAC0-KBLK,2 sta 1 userAC1-KBLK,2 sta 3 userAC3-KBLK,2 subcl 0 0 sta 0 userCry-KBLK,2 ; carry bit ; Back up PC to point at trapping instruction and examine it. lda 3 TrapPC-KBLK,2 mkminusone 1 1 add 1 3 sta 3 @.userPC ; -> trapping instruction lda 0 0,3 lda 1 .abortTrap ; 77411 sub 1 0 szr ; abort trap (77411)? inc 0 1 snr ; keyboard trap (77410)? jmp trap7 ; yes, one of those inc 1 1 szr ; multiple-proceed breakpoint trap (77407)? jmp trap3 ; no, not a special kind of trap lda 2 @.SCM ; We hit a multiple proceed break point lda 0 nMPBP1 ; number of mpbp's +1 sta 0 temp lda 1 oMPBP ; offset of first mpbp trap5: dsz temp ; checked them all? add 1 2 skp ; no, -> next mpbp jmp trap3 ; hmmm. not in the table lda 1 lMPBP lda 0 mpbpAddr,2 se 0 3 ; is this the mpbp we hit? jmp trap5 ; no dsz mpbpCnt,2 ; has it expired? jmp .SimIns ; Simulate broken instr and plunge on trap3: mkminusone 0 0 ; not an abort trap jmp trap6 ; Time to call Swat trap7: lda 1 IntPC-KBLK,2 ; kbd & abort traps are special sta 1 @.userPC ; PC _ interrupt PC (from SwatInterrupt) dsz @.userInt ; Int _ true ; fall into trap6 ; Prepare to OutLd this core image onto Swatee ; ac0 = 0 if aborting, -1 otherwise trap6: sta 0 abortFlag ; abortFlag _ 0 if abort trap, -1 otherwise mkzero 0 0 ; We are about to swap out jsr CallSCP ; Call Swat context switching procedure. ; It skips the next word. swatOffset: swatFP-.SwatTrap ; ** PUBLISHED VALUE = 9. ** lda 0 @.KBLK ; Wait for the disk controller to stop sz 0 0 jmp .-2 incol 0 0 ; 3 = etherResetCommand sio ; Turn off the Ethernet interface jsr FlushWW ; Save all pending interrupts in WW lda 3 @.SCM sta 1 resumeFlag-.SwatTrap,3 ; 0 => simply resume lda 0 swateeOffset add 3 0 ; AC0 -> FP for Swatee jsrii .+1 ; OutLd onto Swatee. ac1=0: don't want message OutLd sz 0 0 ; what did we just do? jmp trap8 ; We are waking up via InLd isz abortFlag ; We just OutLded. Are we aborting? jmp trap9 ; yes lda 1 @.SCM ; No, entering Swat. Message is the SCM table lda 0 swatOffset add 1 0 ; AC0 -> FP for Swat jsrii .+1 ; InLd Swat InLd ; Control never returns here. trap9: eir ; a Mesa bug depends on this order of instrs lda 2 @.userAC2 ; stack for finishing mkone 0 0 ; fcAbort jsrii .+1 OsFinish ; Control never returns here. ; Here when we are resumed by InLd trap8: lda 2 @.WW jsr FlushWW ; Flush any interrupts pending now sta 2 @.WW ; Restore saved interrupt system state mkminusone 0 0 ; We have just swapped in jsr CallSCP ; Call Swat context switching procedure. ; It skips the next word. swateeOffset: swateeFP-.SwatTrap ; ** PUBLISHED VALUE = 4. ** lda 3 @.SCM lda 0 resumeFlag-.SwatTrap,3 mov 0 2 szr ; What shall we do? jmp codeVector-.SwatTrap,3 ; goto codeVector jmp useBRI ; Resume user code ; ac2=0 => no instruction to simulate ; Routine to flush pending interrupts into WW FlushWW: lda 0 @.Active mkzero 1 1 sta 1 @.Active eir dir sta 0 @.Active jmp 0,3 ; Call Swat context-switching procedure, if present, with argument in ac0. ; Always returns to caller+2. Note that the Swat context-switching procedure ; cannot be a BCPL procedure and cannot assume anything about the stack. ; Therefore it cannot care what is in caller+1 (normally # of args). CallSCP: lda 2 swatCP sz 2 2 jmp 0,2 jmp 1,3 .userPC: 700 ; -> trapping instruction userAC0 = 701 ; registers at time of trap userAC1 = 702 userAC2 = 703 .userAC2: userAC2 userAC3 = 704 .userAC3: userAC3 userCry = 705 ; 706 is dumperFlg .userInt: 707 ; 1 => interrupts on at trap, 0 => off .abortTrap: abortTrap ; Come here to simulate an instruction and resume user code. ; AC2 -> SI structure. Compute effective address, if any. ; Most of the work has already been done by Swat. .SimIns: lda 3 siBase,2 ; 0 or -> saved base register (pc, ac2, ac3) sz 3 3 lda 3 0,3 lda 0 siDisp,2 ; displacement, sign-extended if appropriate add 3 0 lda 1 siInd,2 ; number of indirections com 1 1 skp ea2: lda 0 @effAdd sta 0 effAdd inc 1 1 szr jmp ea2 ; Dispatch on instruction class. Dispatch indices known to Swat lda 1 siSim,2 jsr Dispatch jmp SimMA ; 0 jmp SimJmp ; 1 jmp SimJsr ; 2 jmp SimDirs ; 3 lda 0 @.IntPC ; 4 bri jmp SimJmp SimJsr: lda 1 @.userPC ; jsr, jsrii, jsris inc 1 1 sta 1 @.userAC3 SimJmp: sta 0 @.userPC ; jmp jmp DoIt SimDirs:isz @.userPC ; dirs lda 0 @.userInt sz 0 0 SimMA: isz @.userPC ; MRI, ALU, and NoPar except dirs and bri ; Fall into DoIt ; Execute a given instruction, then resume user code at a given address. DoIt: lda 0 @.userInt ; for test in default handling case lda 1 siDoIt,2 jsr Dispatch ; Default is to use whatever transfer instruction is right to restore ; the interrupt system state to that saved in userInt. snz 0 0 ; 0 -- dispatch indices known to Swat jmp useJmp ; 1 ; simulate the instruction and then use a BRI to resume user code. useBRI: lda 1 .bri ; 2 lda 3 .IntPC Exit: sta 1 exIns ; instruction to exit with sta 3 pResume ; -> resume pc sz 2 2 ; have an SI? if not, no inst to simulate lda 1 siInstr,2 ; get inst to simulate sta 1 ins lda 0 @.userPC sta 0 @pResume lda 3 .userAC3 lda 0 userCry-userAC3,3 ; carry movr 0 0 lda 0 userAC0-userAC3,3 lda 1 userAC1-userAC3,3 lda 2 userAC2-userAC3,3 lda 3 userAC3-userAC3,3 abortFlag: ; also temp for SwatTrap ins: .blk 1 ; instruction being simulated exIns: .blk 1 ; exit instruction: bri or jmp @resume isz @pResume ; simulating instruction skipped jmp .-2 pResume: .blk 1 ; 500 or lv resume effAdd: .blk 1 ; effective address -- must be at ins+5 ; simulate the instruction and then use a JMP to resume user code. useJmp: lda 1 .jmpres ; jmp @resume jsr Exit ; make ac3 -> resume resume: .blk 1 ; resume address used if interrupts off .jmpres: jmp @resume-exIns 1 .IntPC: IntPC ; Dispatch into table pointed to by ac3 using index in ac1 Dispatch: add 1 3 jmp 0,3 .SwatInterrupt: ; 16.666 ms vertical field interrupt sta 0 intAC0 ; save state *** except ac2 *** sta 1 intAC1 sta 3 intAC3 subcl 0 0 sta 0 intCry lda 3 .bri ; normal interrupt dismiss method lda 0 @.KBAD3 lda 1 c4 and 1 0 lda 1 keyState sta 0 keyState snz 0 0 ; key down? snz 1 1 ; yes, heavy fingers? jmp Dismiss ; no or yes, ignore lda 0 @.KBAD2 cycle 9. movzl# 0 0 szc ; key down too? jmp Dismiss ; no ; For keyboard trap ( or ), ; make it appear as if user executed a trap instruction. ; When the TrapHandler sees this it completes the transformation: ; .userPC _ @IntPC ; .userInt _ true lda 1 abortOK snz 1 1 ; aborting allowed? lda 3 .abortTrap ; yes, set keyboard trap cycle 11. movzl# 0 0 snc ; key down too? lda 3 .kbdTrap ; yes Dismiss: sta 3 SIRet jsrii .+1 UpdateTimer lda 0 intCry ; restore state movr 0 0 lda 0 intAC0 lda 1 intAC1 lda 3 intAC3 SIRet: .blk 1 ; patched to bri, 77410, or 77411 intAC0: .blk 1 intAC1: .blk 1 intAC3: .blk 1 intCry: .blk 1 .bri: bri ; put in SIRet to dismiss interrupt .kbdTrap: kbdTrap abortOK: .blk 1 ; 0 if aborts are allowed keyState: .blk 1 ; non-zero if key was up 16 ms ago c4: 4 ; key mask .KBAD2: 177036 ; kbd word containing & .KBAD3: 177037 ; kbd word containing .end