/************************************************************************* Copyright (c) 1984 by Nick de Smith This software is supplied for interest and non-profit making purposes only. Under no circumstance shall it be lent, copied or otherwise used for profit. All rights regarding the use and ownership of this software shall at all times remain with the author, who does not guarantee the accuracy or reliabilty of this software and who will not accept any liability for its use. This software may not be copied or distributed without the inclusion of the above copyright notice. January 31st 1984 *************************************************************************/ /************************************************************************* Program : CAM Module : PASS2.C Author : Nick de Smith November/December 1982 Description : Second pass of the object module disassembler *************************************************************************/ #define MODULE #include #include "cam.h" #include "camtbl.h" /************************************************************************* * * * p a s s _ 2 * ----------- * * Second pass through the object file. This pass does not actually * generate the code, but it attempts to interpret all instructions * and to label referenced locations. * *************************************************************************/ global pass_2() { pass = 2; rewind(ip); rec_num = 0; b_init(); eom = FALSE; dbg("Started PASS_2\n"); if (code) decode(); dbg("Ended PASS_2\n"); } /************************************************************************* * * * d e c o d e * ----------- * * Pass two of the decode. * *************************************************************************/ local decode() { int name[2]; register int flags; dbg("In PASS_2 DECODE\n"); do { line_new(); dot.d_value = seg_ptr->p_dot; switch ((flags = get_item(IR)) & A_TYPE) { case A_EOM: dbg("EOM hit\n"); eom = TRUE; break; case A_LMOD: dbg("LMOD hit\n"); seg_ptr->p_dot = next_two_bytes(b_current); r_next(b_current); break; case A_LDEF: dbg("LDEF hit\n"); name[0] = next_two_bytes(b_current); name[1] = next_two_bytes(b_current); seg_ptr = &segtbl[seg_cur = find(name)]; seg_ptr->p_dot = next_two_bytes(b_current); seg_ptr->p_count++; r_next(b_current); break; case A_DATA: dbg("Data item\n"); if (b_flag) break; if (flags & A_B) break; if (flags & A_RELA) break; proc_ir(); break; default: bug("Strange flags in PASS_2 DECODE, %06o", flags); } } while (!eom); dbg("Leaving PASS_2 DECODE\n"); } /************************************************************************* * * * p r o c _ i r * ------------- * * Process the IR (instruction register). Return TRUE is all was * well with the decode, FALSE else. * *************************************************************************/ local proc_ir() { register TREE_PTR node; register int _ir; register int offset; int name[2]; /* Dummy for call to lookup */ SYMBOL_PTR lookup(); offset = 014; node = ((_ir = IR->d_value) & 0100000 ? x1 : x0); for (;;) { if ((node = &node[(_ir & (007 << offset)) >> offset])->t_flags & T_END) break; node = node->t_next; offset -= 3; } dbg("%06o = \"%-6s\", type %o\n", _ir, node->t_next, node->t_flags & T_TYPE); switch (node->t_flags & T_TYPE) { case T_NOPS: /* No operands */ break; case T_SSDD: /* SS,DD type (MOV etc) */ return (do_2_args(_ir)); case T_RDD: /* R,DD reg, dest (JSR + XOR) */ case T_SSR: /* SS,R src, reg (MUL etc) */ case T_SS: /* SS src (JMP, CLR etc) */ return (do_1_arg(_ir)); case T_R: /* R reg (RTS, FADD etc) */ break; case T_ROO: /* R,OO reg, 6 bit off (SOB) */ if (!bounded(offset = seg_ptr->p_dot - (2 * (_ir & 077)))) return (FALSE); insert(seg_cur, offset, name, S_WEAK | S_CREF | S_LOCAL); break; case T_OO: /* OOO 8 bit off (branches) */ offset = _ir & 0377; if (_ir & 0200) /* Extend sign if needed */ offset |= 0177400; offset *= 2; if (!bounded(offset += seg_ptr->p_dot)) return (FALSE); insert(seg_cur, offset, name, S_WEAK | S_CREF | S_LOCAL); break; case T_NNNNNN: /* NNNNNN 16 bit data (.WORD) */ case T_NNN: /* NNN 8 bit data (EMT + TRAP) */ case T_NN: /* NN 6 bit data (MARK) */ case T_N: /* N 3 bit data (SPL) */ break; case T_AFSS: /* Fsrc, acc (MULF, MODF etc) */ case T_AFDD: /* Acc, Fdst (STF + STCFD) */ case T_FSS: /* Fsrc (CLRF etc) */ if (!fltmod(_ir)) { on_stack(D1); return (FALSE); } break; case T_ASS: /* Src, acc (LDCIF + LDEXP) */ case T_ADD: /* Acc, dst (STCFI + STEXP) */ return (do_1_arg(_ir)); case M_JMPX: case M_CALL: return (do_1_arg(_ir)); case M_RETURN: break; case M_PUSH: /* clr -(sp) 0005046 */ /* mov x, -(sp) 001xx46 */ if (!(_ir & 0010000)) { /* Must be a CLR type */ if ((_ir & 077) == 046) break; /* Its PUSH */ return (do_1_arg(_ir)); /* No, its a CLR */ } if ((_ir & 077) == 046) /* Is it a PUSH ? */ return (do_1_arg(_ir >> 6)); return (do_2_args(_ir)); /* No, its a MOV */ case M_POP: /* tst (sp)+ 0005726 */ /* mov (sp)+, x 00126xx */ if (!(_ir & 0010000)) { /* Must be a TST type */ if ((_ir & 077) == 026) break; /* Its POP */ return (do_1_arg(_ir)); /* Its a TST */ } if ((_ir & 07700) == 02600) /* Is it a POP ? */ return (do_1_arg(_ir)); return (do_2_args(_ir)); /* Its a MOV */ } return (TRUE); } /************************************************************************* * * * d o _ 1 _ a r g * --------------- * * Handle a "regmod" type argument. We assume that the argument is * in the low 6 bits of the passed IR. Also, we assume that the only * place to put the data (if any) is in D1. These are both perfectly * safe assumptions. * *************************************************************************/ local do_1_arg(_ir) register _ir; { if (!regmod(D1, _ir)) { on_stack(D1); return (FALSE); } return (TRUE); } /************************************************************************* * * * d o _ 2 _ a r g s * ----------------- * * Handle a 'regmod, regmod' type argument. General form here is * for T_SSDD type opcodes. This is separated out as the 'macro' * types include a 'mov' in 'push' and 'pull' that may need to be * treated as a 'mov' and not a macro. * *************************************************************************/ local do_2_args(_ir) register int _ir; { register DATA_PTR d_ptr; if (!regmod(d_ptr = D1, _ir >> 6)) { on_stack(D1); return (FALSE); } if (d_ptr->d_flags & A_VALID) d_ptr = D2; if (!regmod(d_ptr, _ir)) { on_stack(D1); on_stack(D2); return (FALSE); } return (TRUE); } /************************************************************************* * * * f l t m o d * ----------- * * Handle general floating point register/mode arguments. Note that * there are only six KEF-11/FP-11 registers, AC0 to AC5. If any * other is detected, force a .word. For all floating point instr- * uctions, the only place that Fsrc/Fdst can be found is in the low * six bits. * *************************************************************************/ local fltmod(_ir) register int _ir; { if (_ir & 070) return (regmod(D1, _ir)); return (((_ir & 006) == 6) ? FALSE : (flt_f = TRUE)); } /************************************************************************* * * * r e g m o d * ----------- * * Generate the register/mode argument. Return TRUE if all * is well, false else. * *************************************************************************/ local regmod(d_ptr, bits) register DATA_PTR d_ptr; int bits; { register int reg, flags; int name[2]; SYMBOL_PTR lookup(); reg = bits & 07; switch ((bits & 070) >> 3) { case 0: case 1: break; case 2: case 3: if (reg == 7) if (((flags = get_item(d_ptr)) & A_TYPE) != A_DATA || flags & (A_B | A_LIMIT)) return (FALSE); break; case 4: case 5: if (reg == 7) return (FALSE); break; case 6: case 7: if (((flags = get_item(d_ptr)) & A_TYPE) != A_DATA || flags & (A_B | A_LIMIT)) return (FALSE); if (reg == 7 && !(flags & A_RELA)) insert(seg_cur, d_ptr->d_value + seg_ptr->p_dot, name, S_WEAK | S_CREF | S_DREF | S_LOCAL); break; } return (TRUE); }