

/*************************************************************************

                      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	<stdio.h>

#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);
}

