TITLE Hawk Monitor and Standard Library ;USE "/group/22c018/hawk.macs" USE "hawk.macs" MACRO ALLOC =n . = . + n ENDMAC ; trap vector RESTARTTRAP = #00 BUSTRAP = #10 INSTRTRAP = #20 PRIVTRAP = #30 ; memory mapped display interface DISPBASE = #FF000000 DISPLINES = 0 DISPCOLS = 4 DISPTEXT = #100 ; keyboard interface KBDBASE = #FF100000 KBDDATA = 0 KBDSTAT = 4 ; 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. COMMON TRAPBUF,TRAPLIM ; trap save area LCSAVE=. .=TRAPBUF MASV: ALLOC 4 ; saved trap memory address PCSV: ALLOC 4 ; saved trap program counter PSSV: ALLOC 4 ; saved trap psw R1SV: ALLOC 4 ; saved register 1 R2SV: ALLOC 4 ; saved register 2 R3SV: ALLOC 4 ; saved register 3 R4SV: ALLOC 4 ; saved register 4 R5SV: ALLOC 4 ; saved register 5 R6SV: ALLOC 4 ; saved register 6 R7SV: ALLOC 4 ; saved register 7 ALIGN 4 STKBAS: ALLOC 16 ; monitor stack (not much depth needed) TRAPLIM: .=LCSAVE . = RESTARTTRAP CPUSET R1,TSV ; 2 LOAD R1,R5SVP ; 4 STORES R5,R1 ; 2 = 16 locations total LEA R5,RESMSG ; 4 JUMP TCOM ; 4 . = BUSTRAP CPUSET R1,TSV ; 2 LOAD R1,R5SVP ; 4 STORES R5,R1 ; 2 = 16 locations total LEA R5,BUSMSG ; 4 JUMP TCOM ; 4 . = INSTRTRAP CPUSET R1,TSV ; 2 LOAD R1,R5SVP ; 4 STORES R5,R1 ; 2 = 16 locations total LEA R5,INSMSG ; 4 JUMP TCOM ; 4 . = PRIVTRAP CPUSET R1,TSV ; 2 LOAD R1,R5SVP ; 4 STORES R5,R1 ; 2 = 16 locations total LEA R5,PRVMSG ; 4 JUMP TCOM ; 4 ALIGN 4 R5SVP: W R5SV ; pointer to R5 save loc PCSVP: W PCSV ; pointer to PC save loc MASVP: W MASV ; pointer to MA save loc PSSVP: W PSSV ; pointer to PS save loc TRAPBUP:W TRAPBUF ; pointer to whole save area STKBASP:W STKBAS ; pointer to base of stack RESMSG: ASCII "Restart Trap. ",0 INSMSG: ASCII "Instruction Trap.",0 BUSMSG: ASCII "Bus Trap. ",0 PRVMSG: ASCII "Privelege Trap. ",0 ALIGN 2 TCOM: ; common code shared by all traps ; come here with user's R1 in TSV, R5 in R5SV ; trap message in R5 LOAD R1,TRAPBUP ; setup for indexing STORE R2,R1,R2SV-TRAPBUF STORE R3,R1,R3SV-TRAPBUF STORE R4,R1,R4SV-TRAPBUF ; R5 already saved STORE R6,R1,R6SV-TRAPBUF STORE R7,R1,R7SV-TRAPBUF CPUGET R2,TPC CPUGET R3,TSV ; 2 CPUGET R4,TMA STORE R2,R1,PCSV-TRAPBUF STORE R3,R1,R1SV-TRAPBUF STORE R4,R1,MASV-TRAPBUF CPUGET R2,PSW STORE R2,R1,PSSV-TRAPBUF ; the following trap service code simply prints ; diagnostic output and terminates! LOAD R2,STKBASP ; setup for output JSR R1,DSPINI ; wipes out R3-4 MOVE R3,R5 ; output trap name JSR R1,DSPST ; wipes out R3-7 LEA R3,MSGPC ; output "PC =" JSR R1,DSPST ; wipes out R3-7 LOAD R4,PCSVP LOADS R3,R4 ; output PC value JSR R1,DSPHX ; wipes out R3-7 LEA R3,MSGXX ; output trailer JSR R1,DSPST ; wipes out R3-7 LIS R3,17 LIS R4,1 ; moveto (17,1) JSR R1,DSPAT ; wipes out R3-7 LEA R3,MSGMA ; output "MA =" JSR R1,DSPST ; wipes out R3-7 LIL R4,MASVP LOADS R3,R4 ; output MA value JSR R1,DSPHX ; wipes out R3-7 LEA R3,MSGXX ; output trailer JSR R1,DSPST ; wipes out R3-7 LIS R3,17 LIS R4,2 ; moveto (17,2) JSR R1,DSPAT ; wipes out R3-7 LEA R3,MSGPS ; output "PS =" JSR R1,DSPST ; wipes out R3-7 LIL R4,PSSVP LOADS R3,R4 ; output MA value JSR R1,DSPHX ; wipes out R3-7 LEA R3,MSGXX ; output trailer JSR R1,DSPST ; wipes out R3-7 LOAD R7,TRAPBUP ; setup to restore registers LOAD R1,R7,PSSV-TRAPBUF CPUSET R1,PSW LOAD R1,R7,R1SV-TRAPBUF LOAD R2,R7,R2SV-TRAPBUF LOAD R3,R7,R3SV-TRAPBUF LOAD R4,R7,R4SV-TRAPBUF LOAD R5,R7,R5SV-TRAPBUF LOAD R6,R7,R6SV-TRAPBUF LOAD R7,R7,R7SV-TRAPBUF JUMP 0000 MSGPC: ASCII " Trap PC = #",0 MSGMA: ASCII " Trap MA = #",0 MSGPS: ASCII " Trap PSW= #",0 MSGXX: ASCII " ",0 ; All support procedures are linked through R1. ; on procedure entry, R2 is the frame pointer. ; the stack frame grows up. Each support proc ; documents the registers it wipes; the caller ; must save these if they are valuable. ; All output procedures use DSPPTR. This ; pointer points to the most recent character ; output in Video RAM. It is incremented before ; use! COMMON DSPPTR,4 ; pointer to output in Video RAM ALIGN 4 DSPPTP: W DSPPTR ; pointer to the pointer! ALIGN 2 ;------------------------ INT EXIT EXIT = 0 ; terminate application ; no parameters, does nothing ;------------------------ INT DSPINI DSPINI: ; initialize for display ; returns R3=columns (width), R4=lines (height) ; does not use R2 LIW R3,DISPBASE+DISPTEXT-1 LOAD R4,DSPPTP STORES R3,R4 LIW R4,DISPBASE LOAD R3,R4,DISPCOLS LOAD R4,R4,DISPLINES JUMPS R1 ; return ;------------------------ INT DSPAT ; AR format indexed using R2: ; 0 ; return address DSPAAR = 4 ; total size DSPAT: ; move to X=R3, Y=R4 on display ; wipes out R3-7 MOVE R7,R3 ; set aside X coord STORES R1,R2 ; push old return address ADDSI R2,DSPAAR LIW R3,DISPBASE+DISPCOLS LOADS R3,R3 ; get columns times y coord JSR R1,MUL ; wipes out R4-6 ADD R3,R3,R7; add x coord LIW R5,DISPBASE+DISPTEXT-1 ADD R3,R3,R5; add display base (less 1) LOAD R4,DSPPTP STORES R3,R4 ; done! ADDSI R2,-DSPAAR LOADS R1,R2 ; restore return address JUMPS R1 ;------------------------ INT DSPCH DSPCH: ; output char in R3 ; wipes out R4-5 ; does not use R2 LOAD R4,DSPPTP LOADS R5,R4 ; get display pointer ADDSI R5,1 STORES R5,R4 ; save updated pointer LOADS R4,R5 STUFFB R4,R3,R5 STORES R4,R5 ; update display JUMPS R1 ; return ;------------------------ INT DSPST DSPST: ; output string pointed to by R3 ; wipes out R3-7 ; does not use R2 MOVE R7,R3 MOVE R6,R1 DSPSTL: LOADS R4,R7 ; get a character to display EXTB R3,R4,R7 BZS DSPSTQ ; quit loop if null JSR R1,DSPCH ; wipes out R4-5 ADDSI R7,1 ; advance to next char BR DSPSTL DSPSTQ: MOVE R1,R6 JUMPS R1 ;------------------------ INT DSPHX ; AR format indexed using R2: ; 0 ; return address DSPHAR = 4 ; total size DSPHX: ; output hex number in R3 ; wipes out R3-7 STORES R1,R2 ; push old return address ADDSI R2,DSPHAR MOVE R7,R3 LIS R6,8 ; initialize loop counter DSPHXL: MOVE R3,R7 ; loop top SRU R3,12 SRU R3,16 ; get one digit in place LIS R4,#F AND R3,R4 ; mask off surplus bits ADDI R3,'0' ; make an ASCII digit CMPI R3,'9' ; see if should make a letter BLE DSPHXN ADDI R3,'A'-('9'+1) DSPHXN: JSR R1,DSPCH ; wipes out R4-5 SL R7,4 ; advance to next digit ADDSI R6,-1 ; decrement loop counter BGT DSPHXL ADDSI R2,-DSPHAR LOADS R1,R2 ; restore return address JUMPS R1 ;------------------------ INT DSPDEC ; AR format, indexed using R2: ; 0 ; return address DSPDRM = 4 ; remainder after division by 10 DSPDFW = 8 ; field width DSPDAR = 12 ; total size DSPDEC: ; output R3 in signed decimal ; uses R4 as field width ; wipes out R3-6 STORES R1,R2 ; save ret addr in ar TESTR R3 ; test sign of number BNR DSPDMG ; skip the following if non-negative STORE R3,R2,DSPDRM STORE R4,R2,DSPDFW LIS R3,'-' JSR R1,DSPCH; output sign (wipe out R4-5) LOAD R3,R2,DSPDRM NEG R3,R3 ; restore and negate number LOAD R4,R2,DSPDFW ADDSI R4,-1 ; restore and decrement field width BR DSPDMG ; go merge with DSPDECU ;------------------------ INT DSPDECU ; AR format, indexed using R2: ; 0 ; return address DSPDRM = 4 ; remainder after division by 10 DSPDFW = 8 ; field width DSPDAR = 12 ; total size DSPDECU: ; output R3 in unsigned decimal ; uses R4 as field width ; wipes out R3-6 STORES R1,R2 ; save ret addr in ar DSPDMG: ; -- merge point from DSPDEC signed ADDSI R4,-1 ; decrement and save field width STORE R4,R2,DSPDFW LIS R4,10 JSR R1,DIVU ; divide number by 10 (wipe out R5-6) STORE R4,R2,DSPDRM TESTR R3 ; check quotient after save remainder BZS DSPDBL ; if zero, we have final digit LOAD R4,R2,DSPDFW ADDI R2,DSPDFW ; setup for recursion JSR R1,DSPDEC ; recursive call ADDI R2,-DSPDFW; (note that field width not needed) DSPDQT: LOAD R3,R2,DSPDRM ADDI R3,'0' ; convert remainder to ASCII JSR R1,DSPCH; output it (wipe out R4-5) LOADS R1,R2 ; recover ret addr from ar JUMPS R1 ; return ; by rights, the following else clause should be inside ; the above, but it's a bit more efficient to put it here DSPDBL: LOAD R6,R2,DSPDFW LIS R3,' ' DSPDLP: ADDSI R6,-1 ; decrement BLT DSPDQT ; quit if nothing left JSR R1,DSPCH; output blank (wipe out R4-5) BR DSPDLP ;------------------------------- INT KBGETC KBGETC: ; get char from keyboard ; return char in R3 ; wipe out R4 ; does not use R2 LIW R4,KBDBASE+KBDSTAT KBPOLL: ; loop awaiting input LOADSCC R3,R4 ; test status BZS KBPOLL LIW R4,KBDBASE+KBDDATA LOADS R3,R4 ; get char JUMPS R1 ; return ;------------------------------- INT KBGETS KBGETS: ; get string from keyboard ; expects R3 - pointer to string ; wipes out R3-7 ; does not use R2 MOVE R7,R1 ; save return addr MOVE R6,R3 ; set aside string pointer KBGSLP: JSR R1,KBGETC ; get a char CMPI R3," " ; see if printable BLT KBGSNP LOADS R5,R6 STUFFB R5,R3,R6 ; store character in string STORES R5,R6 ADDSI R6,1 ; advance string pointer JSR R1,DSPCH ; echo the char (wipe out R4-5) BR KBGSLP ; get next char! KBGSNP: CMPI R3,8#12 ; see if LF key BEQ KBGSQT CMPI R3,8#15 ; see if CR key BEQ KBGSQT CMPI R3,8#10 ; see if BS key BNE KBGSLP ; ignore char if not LOAD R4,DSPPTP LOADS R5,R4 ; get display pointer ADDSI R5,-1 STORES R5,R4 ; update display pointer ADDSI R5,1 ; now go back and erase a char LIS R4," " ; now go back and erase a char LOADS R3,R5 STUFFB R3,R4,R5 STORES R3,R5 ; erase char from display ADDSI R6,-1 ; also backup string pointer BR KBGSLP ; get next char KBGSQT: LOADS R5,R6 STUFFB R5,R0,R6 ; store null at end-string STORES R5,R6 JUMPS R7 ; return ;------------------------ INT MUL MUL: ; R3 = R3 * R4 (signed!) ; wipes out R4-6 ; does not use R2 MOVE R5,R3 ; set aside multiplicand CLR R3 SL R4,1 ; shift multiplier left 1 BCR .+4 ; if sign bit was 1 SUB R3,R0,R5; subtract multiplicand from accumulator LIS R6,31 ; load loop counter MULLP: SL R3,1 ; \ SL R4,1 ; \ BCR .+4 ; / 31 more multiply steps ADD R3,R3,R5; / ADDSI R6,-1 ; count BGT MULLP ; iterate JUMPS R1 ;------------------------ INT DIVU DIVU: ; R3 = R3 / R4; R4 = R3 mod R4 (unsigned!) ; wipes out R5-6 ; does not use R2 MOVE R5,R4 ; set aside divisor CLR R4 ; clear remainder LIS R6,32 ; load loop counter DIVULP: SL R3,1 ; shift dividend/quotient ROL R4 ; putting high bit into remainder CMP R4,R5 ; see if divisor divides remainder BLTU .+6 ; if not, skip SUB R4,R4,R5; if so, take away divisor ADDSI R3,1 ; and add a bit to the quotient ADDSI R6,-1 ; count BGT DIVULP ; iterate JUMPS R1 END