.TITLE DISASM .IDENT "V1.7" ; ; Author: D. Mischler 10-JUN-87 ; ; This module disassembles a single PDP-11 instruction ; and buffers the resulting text line. ; .PSECT RODATA,D,RO ; ; Opcode class dispatch table. ; CLSTBL: .WORD BRANCH ; 0 - Branch instructions. .WORD COND ; 1 - Condition code instructions. .WORD DOUBLE ; 2 - Double operand instructions. .WORD IMMED ; 3 - 3-bit immediate instructions. .WORD FPADST ; 4 - Floating point accumulator destination. .WORD FPASRC ; 5 - Floating point accumulator source. .WORD IMMED ; 6 - 6-bit immediate instructions. .WORD NONE ; 7 - No operands. .WORD IMMED ; 10 - 8-bit immediate instructions. .WORD REG ; 11 - Single register operand. .WORD REGDST ; 12 - Register destination with any source. .WORD REGSRC ; 13 - Register source with any destination. .WORD SINGLE ; 14 - Single operand. .WORD SOB ; 15 - Subtract one and branch instruction. .WORD ILLEGAL ; 16 - Illegal class. .WORD ILLEGAL ; 17 - Illegal class. ; ; Condition code bit mask identifier table. ; CONTBL: .ASCIZ "NZVC" .EVEN ; ; Adressing mode dispatch table. ; MODTBL: .WORD REG ; 0 - Register direct. .WORD REGDEF ; 1 - Register deferred. .WORD REGINC ; 2 - Register deferred post-increment. .WORD REGINI ; 3 - Register deferred post-increment indirect. .WORD DECREG ; 4 - Register deferred pre-decrement. .WORD DEREGI ; 5 - Register deferred pre-decrement indirect. .WORD INDEX ; 6 - Register base indexed. .WORD INDEXI ; 7 - Register base indexed indirect. ; ; Illegal opcode "mnemonic" text. ; ILLOPC: .ASCIZ "ILLEGAL" .EVEN .PAGE .PSECT CODE,I,RO ; ; Subroutine to disassemble an instruction. ; On entry: R0 points to disassembly buffer. ; R5 contains instruction address. ; ; On exit: R0 points after the disassembled instruction text. ; R1 and R2 are destroyed. ; R5 has been incremented past the instruction. ; The carry will be set if an error is detected. ; DISASM:: CALL M$RI5P ; Fetch instruction word, OK? BCS ADRERR ; No, addressing error. CALL FNDOPC ; Find opcode table entry, OK? BCS 10$ ; No, indicate illegal opcode. MOV R1,-(SP) ; Save opcode word for later. MOV (R2)+,-(SP) ; Save opcode class word on stack. MOV (R2)+,R1 ; Get first RAD50 mnemonic word. CALL C$R50 ; Convert it to ASCII. MOV (R2)+,R1 ; Get second RAD50 mnemonic word. CALL C$R50 ; Convert it too. MOVB #' ,(R0)+ ; Buffer a couple blanks. MOVB #' ,(R0)+ MOV (SP)+,R2 ; Recover opcode class word. BIC #007777,R2 ; Leave only the class number. SWAB R2 ; Put class in low byte. ASR R2 ; Position class for word table index. ASR R2 ASR R2 MOV (SP)+,R1 ; Recover opcode word. CALLR @CLSTBL(R2) ; Disassemble operands. ; ; Illegal opcode: tell the poor slob debugging it. ; 10$: MOV #ILLOPC,R1 ; Point to illegal opcode text. 20$: MOVB (R1)+,(R0)+ ; Copy text into place. BNE 20$ CLC ; Indicate success anyway. RETURN ; ; Addressing error: a question mark should do it. ; ADRERR: MOVB #'<,(R0)+ ; Indicate an addressing error occurred. MOVB #'?,(R0)+ MOVB #'>,(R0)+ ILLEGA: SEC ; Indicate failure. RETURN .PAGE ; ; Process instructions with no operands. ; NONE: CALL U$RMTB ; Remove trailing blanks. CLC ; Indicate everything is OK. RETURN ; ; Process a single operand. ; SINGLE: MOV R1,R2 ; Copy instruction word. BIC #^C<70>,R2 ; Mask to addressing mode. ASR R2 ; Put mode in place for word dispatch. ASR R2 CALLR @MODTBL(R2) ; Dispatch on addressing mode. ; ; Print out the correct mnemonic for the register in R1(0:2). ; REG: BIC #^C<7>,R1 ; Mask to register number. ASL R1 ; Make it a word offset. ADD #REGTBL,R1 ; Point into register table. MOVB (R1)+,(R0)+ ; Buffer register mnemonic. MOVB (R1)+,(R0)+ RETURN ; ; Handle register deferred post-increment indirect. ; REGINI: MOVB #'@,(R0)+ ; Buffer indirection sign. ; ; Handle register deferred post-increment. ; REGINC: MOV R1,R2 ; Copy instruction word. BIC #^C<7>,R1 ; Mask to register number. CMP #7,R1 ; Is the register the PC? BEQ 10$ ; Yes, process as immediate mode. CALL REGDEF ; Process register deferred. MOVB #'+,(R0)+ ; Drop plus sign. RETURN ; Process full 16-bit immediate mode. 10$: MOVB #'#,(R0)+ ; Indicate immediate addressing. CALL M$RI5P ; Fetch operand word, OK? BCS ADRERR ; No, buffer a question mark. CALL C$VALU ; Convert value to ASCII. CLC ; Indicate everything is OK. RETURN .PAGE ; ; Process indexed indirect addressing. ; INDEXI: MOVB #'@,(R0)+ ; Indicate indirect addressing. ; ; Handle indexed addressing. ; INDEX: BIC #^C<7>,R1 ; Mask opcode to register number. MOV R1,R2 ; Copy it for safe keeping. CALL M$RI5P ; Fetch operand word, OK? BCS ADRERR ; No, indicate failure. CMP #7,R2 ; Is the register the PC? BEQ 10$ ; Yes, handle it as relative mode. CALL C$VALU ; Convert value to ASCII. MOV R2,R1 ; Recover register number. BR REGDEF ; Put parenthesis around the register. ; Take care of full 16-bit relative addressing. 10$: ADD R5,R1 ; Offset relative address value by the PC. CALL C$VALU ; Convert value to ASCII. CLC ; Indicate everything is OK. RETURN ; ; Handle pre-decrement register deferred indirect addressing. ; DEREGI: MOVB #'@,(R0)+ ; Buffer indirection indicator. ; ; Process pre-decrement register deferred. ; DECREG: MOVB #'-,(R0)+ ; Buffer pre-decrement indicator. ; ; Process register deferred addressing. ; REGDEF: MOVB #'(,(R0)+ ; Dump open parenthesis. CALL REG ; Process register. MOVB #'),(R0)+ ; Drop close parenthesis. RETURN .PAGE ; ; Process instructions with a FP accumulator as source. ; FPASRC: BIC #177400,R1 ; Trick REGSRC into working right. ; ; Process register source instructions. ; REGSRC: BIC #177000,R1 ; Make source mode field looks OK. ; ; Process double operand instructions. ; DOUBLE: MOV R1,-(SP) ; Save instruction word. ASH #-6,R1 ; Position source operand. CALL SINGLE ; Process source operand. MOVB #',,(R0)+ ; Separate source and destination. MOV (SP)+,R1 ; Pop instruction word. CALLR SINGLE ; Process destination operand and return. ; ; Process short immediate instructions. ; IMMED: ASR R2 ; Correct number of bits. MOV R2,-(SP) ; Stack it. MOV #-1,R2 ; Turn all bits on. ASH (SP)+,R2 ; Shift in the correct number of zeroes. BIC R2,R1 ; Mask to immediate mode field. CLR R2 ; Suppress leading zeroes. CALL C$NUMB ; Convert short value to ASCII. CLC ; Make sure success is indicated. RETURN ; ; Process instructions with a FP accumulator as destination. ; FPADST: BIC #177400,R1 ; Dispose of extraneous fewmets. ; ; Process register destination instructions. ; REGDST: MOV R1,-(SP) ; Save instruction word. CALL SINGLE ; Process source operand. MOVB #',,(R0)+ ; Separate source and destination. MOV (SP)+,R1 ; Recover instruction word. ASH #-6,R1 ; Position destination register. CALLR REG ; Finish up and return. .PAGE ; ; Take care of the SOB instruction. ; SOB: MOV R1,-(SP) ; Save instruction word. ASH #-6,R1 ; Position register. CALL REG ; Take care of register. MOVB #',,(R0)+ ; Separate source and destination. MOV (SP)+,R1 ; Recover instruction word. BIC #^C<77>,R1 ; Mask to branch offset. NEG R1 ; Correct sign of branch offset. ; ; Handle branch instructions. ; BRANCH: MOVB R1,R1 ; Sign extend branch offset to 16 bits. ASL R1 ; Produce byte offset. ADD R5,R1 ; Produce branch target address. CALLR C$VALU ; Convert value to ASCII and return. ; ; Take care of condition code instructions. ; COND: CALL U$RMTB ; Remove blanks after mnemonic. ASH #12.,R1 ; Put condition bits in top of word. MOV #CONTBL,R2 ; Point to condition code table. 10$: ASL R1 ; Current bit set? BCC 20$ ; No, check next. MOVB (R2),(R0)+ ; Buffer bit identifier. 20$: TSTB (R2)+ ; All done? BNE 10$ ; No, try next bit. RETURN .PAGE ; ; Subroutine to locate the appropriate opcode table entry. ; On entry: R1 contains instruction word. ; On exit: R2 points to opcode table entry. ; The carry will be set if an appropriate entry cannot be found. ; FNDOPC: MOV R0,-(SP) ; Save volatile registers. MOV R1,-(SP) MOV #OPCTBL,R2 ; Point to start of opcode table. BR 20$ ; Enter loop at test. ; Loop to find the correct opcode. 10$: BIC #170000,R0 ; Mask class word to decode mask. MOV (SP),R1 ; Recover instruction word. BIC R0,R1 ; Mask off don't cares. CMP OP.VAL(R2),R1 ; Hit on this table entry? BEQ 30$ ; Yup, take it with us (carry is clear). ADD #OP.LEN,R2 ; Point to next table entry. 20$: MOV (R2),R0 ; Get opcode class, zero? BNE 10$ ; No, check it out. ; End of table reached. SEC ; Indicate failure. ; Return with opcode pointer (carry is already set up). 30$: MOV (SP)+,R1 ; Pop saved registers. MOV (SP)+,R0 RETURN .END