TITLE "mp6.a by Douglas W. Jones, Nov. 14, 2014" ; Code to virtualize Hawk LIL and memory reference instructions ; Overlay this over the Sparrowhawk monitor to support the full ; Hawk instruction set (except for coprocessor support). STRICTSPARROW = 1 USE "sparrowhawk.h" USE "ascii.h" USE "monitor.h" PC = R0 ; added for clarity ; ---------------------------------- ; static memory allocation support MACRO ALLOC =n . = . + n ENDMAC ; ---------------------------------- ; machine configuration ; trap vector INSTRTRAP = #20 POSTTRAP = #100 ; location beyond the trap vector ; ---------------------------------- ; trap handler framework ; the following code intercepts all traps and interrupts, ; saves registers in the trap save area. Note that it is ; essential that trap service routines that intend to return ; to the user not cause traps themselves. ; save area structure (displacements from start of area) LC = . . = 0 PSWSV: ALLOC 4 TMASV: ALLOC 4 PCSV: ALLOC 4 R1SV: ALLOC 4 R2SV: ALLOC 4 R3SV: ALLOC 4 R4SV: ALLOC 4 R5SV: ALLOC 4 R6SV: ALLOC 4 R7SV: ALLOC 4 R8SV: ALLOC 4 R9SV: ALLOC 4 RASV: ALLOC 4 RBSV: ALLOC 4 RCSV: ALLOC 4 RDSV: ALLOC 4 RESV: ALLOC 4 RFSV: ALLOC 4 SVSTACK:ALLOC 4 ; minimum stack needed by PUTHEX SVSIZE: . = LC COMMON SVINSTR,SVSIZE ; trap save area for instruction trap SUBTITLE "Trap vector code" ;------------------------ . = INSTRTRAP CPUSET R2,TSV ; 2 LIS R2,INSTCON >> 8 ; 2 ORIS R2,INSTCON & #FF; 2 JSRS R2,R2 ; 2 -- tricky code W SVINSTR+R1SV ; 4 ; 4 bytes unused SUBTITLE "Instruction Trap Continuation" ;------------------------ . = #500 ; address set by inspecting end of sparrowmon.l ; addresses of monitor routines DSPINIP:W DSPINI PUTSP: W PUTS PUTHEXP:W PUTHEX INSTMSG:ASCII "Instruction Trap. Trap PC = #",0 MSGXX: ASCII " ",0 ALIGN 2 INSTCON: ; assumes TSV = oldR2 ; R2 points to pointer to savearea->r1sv ; all other registers still hold user values ; including PSW, TMA and TPC LOADS R2,R2 ; -- get save area pointer STORES R1,R2 ; savearea->r1sv = oldR1 ADJUST R2,PLUS8 STORES R3,R2 ; savearea->r3sv = oldR3 ADJUST R2,PLUS4 STORES R4,R2 ; savearea->r4sv = oldR4 ADJUST R2,PLUS4 STORES R5,R2 ; savearea->r5sv = oldR5 ADJUST R2,PLUS4 STORES R6,R2 ; savearea->r6sv = oldR6 ADJUST R2,PLUS4 STORES R7,R2 ; savearea->r7sv = oldR7 ; here: oldR1, oldR3 - oldR7 are properly saved ; R2 points to savearea->r7sv ; next: save TSV (oldR2), PSW, TMA and TPC LIS R1,PSWSV-R7SV PLUS R1,R2 CPUGET R3,PSW STORES R3,R1 ; savearea->pswsv = oldPSW ADJUST R1,PLUS4 CPUGET R3,TMA STORES R3,R1 ; savearea->tmasv = TMA ADJUST R1,PLUS4 CPUGET R3,TPC STORES R3,R1 ; savearea->pcsv = TPC = oldPC ADJUST R1,PLUS8 CPUGET R3,TSV STORES R3,R1 ; savearea->r2sv = TSV = oldR2 ; here: (R1-R7, PSW, TMA and TPC) all saved in savearea ; R2 -- still points to savearea->r7sv ; next: resume saving registers ADJUST R2,PLUS4 STORES R8,R2 ; savearea->r8sv = oldR8 ADJUST R2,PLUS4 STORES R9,R2 ; savearea->r9sv = oldR9 ADJUST R2,PLUS4 STORES R10,R2 ; savearea->r10sv = oldR10 ADJUST R2,PLUS4 STORES R11,R2 ; savearea->r11sv = oldR11 ADJUST R2,PLUS4 STORES R12,R2 ; savearea->r12sv = oldR12 ADJUST R2,PLUS4 STORES R13,R2 ; savearea->r13sv = oldR13 ADJUST R2,PLUS4 STORES R14,R2 ; savearea->r14sv = oldR14 ADJUST R2,PLUS4 STORES R15,R2 ; savearea->r15sv = oldR15 ; here: (R1-R15, PSW, TMA and TPC) all saved in savearea ; R2 -- points to savearea->r15sv ; next: decode instruction that caused trap ; uses: R3 = points to savearea->pc ; R4 = pc -- user's ; R5 = M[pc] -- fullword ; R6 = ir = M[pc] -- halfword ; R7 = op field of IR (bits 7 to 4) ; R8 = dst field of IR (bits 3 to 0) LIS R3,PCSV-RFSV PLUS R3,R2 ; -- point to user's pc LOADS R4,R3 ; -- get user's pc LOADS R5,R4 ; -- fetch instruction word EXTH R6,R5,R4 ; ir = M[tpc] EXTB R7,R6,R0 ; -- get first byte MOVE R8,R7 SR R7,4 ; op = ir & #00F0 >> 4 TRUNC R8,4 ; dst = ir & #000F BTRUNC R7,4 ; select (op) in { -- note, CC's unchanged! BR INSTBR ; -- opcode 0000 BR INSTTWO ; -- opcode 0001 BR INSTNOPE ; -- never 0010 BR INSTNOPE ; -- never 0011 BR INSTNOPE ; -- never 0100 BR INSTNOPE ; -- never 0101 BR INSTNOPE ; -- never 0110 BR INSTNOPE ; -- never 0111 BR INSTNOPE ; -- never 1000 BR INSTNOPE ; -- never 1001 BR INSTNOPE ; -- never 1010 BR INSTNOPE ; -- never 1011 BR INSTNOPE ; -- never 1100 BR INSTNOPE ; -- never 1101 BR INSTLIL ; -- opcode 1110 BR INSTMEM ; -- opcode 1111 INSTNOPE: ; case 0010 to 1101 -- should never happen INSTBR: ; case 0000 -- dst = 1000 is undefined INSTTWO: ; case 0001 { -- op1 = 1000 is undefined ; -- op1 = 001x is COGET/COSET ADDSI R2,4 ; -- setup for monitor calls VVV= DSPINIP-(.+6) LIS R1,VVV >> 8 ORIS R1,VVV & #FF PLUS R1,PC LOADS R1,R1 JSRS R1,R1 ; (columns, lines) = dspini() -- uses R3-4 VVV= INSTMSG-(.+6) LIS R3,VVV >> 8 ORIS R3,VVV & #FF PLUS R3,PC ; -- parameter instmsg VVV= PUTSP-(.+6) LIS R1,VVV >> 8 ORIS R1,VVV & #FF PLUS R1,PC JSRS R1,R1 ; puts( "Inst trap. PC=#" ) -- uses R3-7 LIS R4,PCSV-SVSTACK PLUS R4,R2 LOADS R3,R4 ; -- parameter pcsv STORES R0,R4 ; pc = 0 -- force restart on return VVV= PUTHEXP-(.+6) LIS R1,VVV >> 8 ORIS R1,VVV & #FF PLUS R1,PC JSRS R1,R1 ; puthex( pcsv ) -- uses R3-7, 1 word stack ADDSI R2,-4 ; -- takedown after monitor calls BR INSTDONE ; } INSTLIL: ; case 1110 { -- LIL instruction ; here: R3 = points to savearea->pc ; R4 = pc -- user's ; R5 = M[pc] -- fullword ; R6 = ir = M[pc] -- halfword ; R7 = op field of IR (bits 7 to 4) ; R8 = dst field of IR (bits 3 to 0) BZS INSTNOPE ; if (dst = 0) go fail MOVE R7,R6 SR R7,8 ; acc = ir bits 8 to 15 -- part 1 of const ADDSI R4,2 ; pc = pc + 2 LOADS R5,R4 EXTH R6,R5,R4 ; ir = M[pc] -- part 2 of const ADDSI R4,2 ; pc = pc + 2 SL R6,16 SR R6,8 OR R7,R6 ; acc = acc | sxt(ir << 8) ADDSL R8,R3,2 ; -- compute address of saved r[dst] STORES R7,R8 ; r[dst] = acc STORES R4,R3 ; -- save updated pc to finish job BR INSTDONE ; } INSTMEM: ; case 1111 { -- sparrowhawk long mem instrs ; here: R3 = points to savearea->pc ; R4 = pc -- user's ; R5 = M[pc] -- fullword ; R6 = ir = M[pc] -- halfword ; R7 = op field of IR (bits 7 to 4), used as temp ; R8 = dst field of IR (bits 3 to 0) ; uses: R9 = x field of IR (bits 11 to 8), then r[x], then ea, M[ea] ; R10 = cc's to result, if needed ; ---- FEWER THAN 100 LINES OF CODE HAVE BEEN DELETED HERE ---- INSTDONE: ; } ; here: (R1-R7, PSW, TMA and TPC) all saved in savearea ; R2 -- points to r15sv ; next: restore (R4-R7) to prepare for restart LOADS R15,R2 ; R15 = savearea.r15sv ADDSI R2,-4 LOADS R14,R2 ; R14 = savearea.r14sv ADDSI R2,-4 LOADS R13,R2 ; R13 = savearea.r13sv ADDSI R2,-4 LOADS R12,R2 ; R12 = savearea.r12sv ADDSI R2,-4 LOADS R11,R2 ; R11 = savearea.r11sv ADDSI R2,-4 LOADS R10,R2 ; R10 = savearea.r10sv ADDSI R2,-4 LOADS R9,R2 ; R9 = savearea.r9sv ADDSI R2,-4 LOADS R8,R2 ; R8 = savearea.r8sv ADDSI R2,-4 LOADS R7,R2 ; R7 = savearea.r7sv ADDSI R2,-4 LOADS R6,R2 ; R6 = savearea.r6sv ADDSI R2,-4 LOADS R5,R2 ; R5 = savearea.r5sv ADDSI R2,-4 LOADS R4,R2 ; R4 = savearea.r4sv ; here: R2 -- points to SVR4 ; Then, stop to restore (TPC, PSW) before restoring (R1-R3) LIS R3,PSWSV-R4SV PLUS R3,R2 LOADS R1,R3 CPUSET R1,PSW ; PSW = savearea->pswsv ADJUST R3,PLUS8 ; -- skip TMA (no need to restore it) LOADS R1,R3 ; R1 = savearea->pcsv CPUSET R1,TPC ; TPC = R1 = pcsv ADJUST R3,PLUS4 LOADS R1,R3 ; R1 = savearea->r1sv ADJUST R3,PLUS4 LOADS R2,R3 ; R2 = savearea->r2sv ADJUST R3,PLUS4 LOADS R3,R3 ; R3 = savearea->r3sv RTT ; -- done! END