

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

                      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	:	PASS3.C

	Author	:	Nick de Smith		November/December 1982

	Description :

			Third pass of the object module disassembler

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

#define	MODULE

#include	<stdio.h>

#include	"cam.h"

#include	"camtbl.h"


/*************************************************************************
*
*
*				p a s s _ 3
*				-----------
*
*	Third pass through the object file. This does the actual output.
*
*************************************************************************/
global
pass_3()
{
	pass = 3;

	rewind(ip);

	rec_num = 0;

	b_init();			/* Initialise buffers		*/

	eom = FALSE;

	dbg("Started PASS_3\n");

	p_reset();			/* Reset the psect table flags	*/

	l_name();			/* Give real names to labels	*/

	if (debug)			/* And why not, may I ask?	*/
		s_dump();

	do_header();			/* Output a meaningful header	*/

	do_title();			/* Dump the module name		*/

	do_ident();			/* Dump the .ident		*/

	if (q_flag)
		do_p_defns();		/* Dump the psect definitions	*/

	if (ref_g)
		do_g_ref();		/* Dump global references	*/

	if (abs_g)
		do_g_abs();		/* Dump global absolutes	*/

	if (flt_f)
		do_f_names();		/* Define accumulator names	*/

	if (psect_f)
		do_p_table();		/* Output the psects in order	*/

	if (code)
		decode();		/* Do the dis-assembly		*/

	do_end();			/* Do the .end statement	*/

	dbg("Ended PASS_3\n");
}


/*************************************************************************
*
*
*			d o _ h e a d e r
*			-----------------
*
*	Print a meaningfull header to the output file.
*
*************************************************************************/
local
do_header()
{
	char	*ctime();

	putl(F_DIRECT, ".nlist");
	putl(F_DIRECT, ".enabl\tlc");
	putl(F_DIRECT, ".list");
	putl(F_LNUM | F_LABEL, ";+");
	sprintf(wbuf, "; \"%s\" dis-assembled on %s", file, ctime(0));
	putl(F_LNUM | F_LABEL, wbuf);
	putl(F_LNUM | F_LABEL, ";");
	sprintf(wbuf, "; %s", version);
	putl(F_LNUM | F_LABEL, wbuf);
	putl(F_LNUM | F_LABEL, ";");
	sprintf(wbuf, "; Options : %s", strlen(option) ? option : "<none>");
	putl(F_LNUM | F_LABEL, wbuf);
	putl(F_LNUM | F_LABEL, ";-");
}

/*************************************************************************
*
*
*			d o _ t i t l e
*			---------------
*
*	Print the .title directive if there was one.
*
*************************************************************************/
local
do_title()
{
	char *radmin();

	if (*modnam) {
		sprintf(wbuf, ".title\t%s", radmin(modnam));
		putl(F_LNUM | F_DIRECT, wbuf);
	}
}

/*************************************************************************
*
*
*			d o _ i d e n t
*			---------------
*
*	Do the .ident directive if there was one.
*
*************************************************************************/
local
do_ident()
{
	char	*radnam();

	if (ident_f) {
		sprintf(wbuf, ".ident\t\"%s\"", radnam(_ident));
		putl(F_LNUM | F_DIRECT, wbuf);
	}
}


/*************************************************************************
*
*
*			d o _ p _ d e f n s
*			-------------------
*
*	Print out the list of defined psects along with their flags.
*
*************************************************************************/
local
do_p_defns()
{
	register int i;
	register PSECT_PTR p_ptr;
	char	*radnam();

	if (seg_max < 0) {
		putl(F_PBL | F_LNUM | F_LABEL | F_TBL,
			"; There are no psects in this module");
		return;
	}

	putl(F_LNUM | F_LABEL | F_PBL, ";+");
	putl(F_LNUM | F_LABEL        , "; All defined psects");
	putl(F_LNUM | F_LABEL        , ";");
	putl(F_LNUM | F_LABEL        , "; Psect  Length    Name    Type");

	set_ptr(F_LABEL, wbuf);

	for (i = 0; i <= seg_max; i++) {
		arg_i();
		arg_s(";  ");
		arg_3o(i);
		arg_s("   ");
		arg_6o((p_ptr = &segtbl[i])->p_mlength);
		arg_s("   ");
		arg_s(radnam(p_ptr->p_name));
		arg_s("   ");
		p_type(p_ptr->p_flags);
		line_out(F_LNUM | F_LABEL);
	}
	putl(F_LNUM | F_LABEL | F_TBL, ";-");
}


/*************************************************************************
*
*
*			d o _ p _ t a b l e
*			-------------------
*
*	Output the list of psects in the order in which they were defined
*	in the GSD.
*
*************************************************************************/
local
do_p_table()
{
	register int i;

	if (seg_max < 0) {
		putl(F_PBL | F_LNUM | F_LABEL | F_TBL,
			"; No psects found in this module");
		return;
	}

	putl(F_LNUM | F_LABEL | F_PBL, ";+");
	putl(F_LNUM | F_LABEL        , "; All defined psects in order");
	putl(F_LNUM | F_LABEL | F_TBL, ";-");

	dot.d_value = 0;

	line_new();

	for (i = 0; i <= seg_max; i++) {
		psect_desc(&segtbl[i]);
		line_out(F_LNUM | F_PC | F_INST | F_ARGS);
	}
	putb();
}


/*************************************************************************
*
*
*			d o _ g _ r e f
*			---------------
*
*	Output the list of referenced global symbols. We output only
*	four per line so that the listing is a respectable width.
*
*************************************************************************/
local
do_g_ref()
{
	register SYMBOL_PTR s_ptr;
	register int col;
	char	*radnam();

	if (!(s_ptr = ref_st)) {
		putl(F_PBL | F_LNUM | F_LABEL | F_TBL,
			"; There are no global references");
		return;
	}

	putl(F_LNUM | F_LABEL | F_PBL, ";+");
	putl(F_LNUM | F_LABEL        , "; All global references");
	putl(F_LNUM | F_LABEL | F_TBL, ";-");

	set_ptr(F_DIRECT, ".globl");
	set_ptr(F_ARGS, wbuf);
	arg_i();

	col = 0;
	while (s_ptr) {
		if (col++ & 3)
			arg_s(",\t");
		else
			if (col > 1) {
				line_out(F_LNUM | F_DIRECT | F_ARGS);
				arg_i();
			}
		arg_s(radnam(s_ptr->s_name));
		s_ptr = s_ptr->s_next;
	}
	if (arg_n())
		line_out(F_LNUM | F_DIRECT | F_ARGS);
	putb();
}


/*************************************************************************
*
*
*			d o _ g _ a b s
*			---------------
*
*	Output the list of all defined absolute global symbols. If we
*	requested sorted absolute global definitions then we output the
*	name of the psect that we are printing.
*
*************************************************************************/
local
do_g_abs()
{
	register PSECT_PTR  p_ptr;
	register SYMBOL_PTR s_ptr;
	register int i;
	char	*radmin();

	if (!abs_f) {
		putl(F_LNUM | F_LABEL | F_PBL | F_TBL,
			"; There are no absolute globals");
		return;
	}

	putl(F_LNUM | F_LABEL | F_PBL, ";+");
	putl(F_LNUM | F_LABEL        , "; All absolute global definitions");
	putl(F_LNUM | F_LABEL | F_TBL, ";-");

	if (sort_g) {
		for (i = 0; i <= seg_max; i++)
			if ((p_ptr = &segtbl[i])->p_symb && !(p_ptr->p_flags & P_REL)) {
				sprintf(wbuf, "; Psect %03o \"%s\"", i, radmin(p_ptr->p_name));
				putl(F_LNUM | F_LABEL, wbuf);
				abs_print(p_ptr->p_symb);
			}
	} /* Tie in the next 'else' */
	else
		abs_print(abs_st);

	putb();
}


/*************************************************************************
*
*
*			a b s _ p r i n t
*			-----------------
*
*	Output a list of absolute definitions.
*
*************************************************************************/
local
abs_print(s_ptr)
register SYMBOL_PTR s_ptr;
{
	char *radmin();

	IR->d_flags = A_VALID;

	set_ptr(F_LABEL, buff);
	set_ptr(F_INST, wbuf);

	while (s_ptr) {
		if ((s_ptr->s_flags &  (S_STRONG | S_GLOBAL | S_STB)) ==
					S_STRONG | S_GLOBAL         ) {
			radmin(s_ptr->s_name);
			arg_i();
			arg_s("==\t");
			arg_o(IR->d_value = s_ptr->s_offset);
			line_out(F_LNUM | F_IR | F_LABEL | F_INST);
		}
		s_ptr = s_ptr->s_next;
	}
}


/*************************************************************************
*
*
*			d o _ f _ n a m e s
*			-------------------
*
*	Define the floating accumulator names. This is only done if
*	pass two detected any opcodes reqiring use of an FAC.
*
*************************************************************************/
local
do_f_names()
{
	register int i;

	putl(F_LNUM | F_LABEL | F_PBL, ";+");
	putl(F_LNUM | F_LABEL        , "; Define floating accumulators");
	putl(F_LNUM | F_LABEL | F_TBL, ";-");

	IR->d_flags = A_VALID;

	set_ptr(F_LABEL, lbuff);
	set_ptr(F_INST, wbuf);

	for (i = 0; i < 6; i++) {
		cpystr(lbuff, fltnam[i]);
		arg_i();
		arg_s("=\t%");
		arg_o(IR->d_value = i);
		line_out(F_LNUM | F_IR | F_LABEL | F_INST);
	}
}


/*************************************************************************
*
*
*				d e c o d e
*				-----------
*
*	Final pass of the object module decode. This bit actually does
*	the instruction decode.
*
*************************************************************************/
local
decode()
{
	int name[2];
	register int flags, l_flags, temp;
	int blkb;
	char	*radmin();

	dbg("In PASS_3 DECODE\n");

	blkb = 0;

	do {
		line_new();

		dot.d_value = seg_ptr->p_dot;

		do_labels();

		if (blkb) {
			arg_i();
			arg_o(blkb);
			set_ptr(F_INST, ".blkb");
			set_ptr(F_ARGS, wbuf);
			l_flags = F_ALL;
			line_out(l_flags | F_PBL);
			dot.d_value = (seg_ptr->p_dot += blkb);
			blkb = 0;
			line_new();
			do_labels();
		}

		l_flags = F_ALL;

		switch ((flags = get_item(IR)) & A_TYPE) {

			case A_EOM:
				eom = TRUE;
				break;

			case A_LMOD:
				arg_i();
				arg_o((temp = next_two_bytes(b_current)) -
					seg_ptr->p_dot);
				set_ptr(F_ARGS, wbuf);
				set_ptr(F_INST, ".blkb");
				seg_ptr->p_dot = temp;
				r_next(b_current);
				break;

			case A_LDEF:
				name[0] = next_two_bytes(b_current);
				name[1] = next_two_bytes(b_current);
				seg_ptr = &segtbl[seg_cur = find(name)];
				blkb = next_two_bytes(b_current) -
					(dot.d_value = seg_ptr->p_dot);
				r_next(b_current);

				l_flags |= (F_PBL | F_TBL);
				l_flags &= ~(F_LABEL | F_COM);
				psect_desc(seg_ptr);
				break;

			case A_DATA:
				if (flags & A_B) {
					byte_();
					break;
				}
				if (flags & A_RELA) {
					if (flags & A_LIMIT)
						limit_();
					else
						word_();
					break;
				}
				if (b_flag || !proc_ir())
					word_();
				break;

			default:
				bug("Strange flags in pass 3 DECODE, %06o", flags);
		}

		if (!eom)
			line_out(l_flags);

	} while (!eom);

	dbg("Leaving PASS_3 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;
		 char *sep_txt;
		 char *radmin();
	SYMBOL_PTR     lookup();

	sep_txt = ", ";

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

	arg_i();
	set_ptr(F_INST, node->t_next);
	set_ptr(F_ARGS, wbuf);

	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)	*/
			arg_s(regnam[(_ir & 0700) >> 6]);
			arg_s(sep_txt);
			return (do_1_arg(_ir));

		case T_SSR:		/* SS,R src, reg (MUL etc)	*/
			if (!do_1_arg(_ir))
				return (FALSE);
			arg_s(sep_txt);
			arg_s(regnam[(_ir & 0700) >> 6]);
			break;

		case T_SS:		/* SS src (JMP, CLR etc)	*/
			return (do_1_arg(_ir));

		case T_R:		/* R reg (RTS, FADD etc)	*/
			arg_s(regnam[_ir & 07]);
			break;

		case T_ROO:		/* R,OO reg, 6 bit off (SOB)	*/
			if (!bounded(offset = seg_ptr->p_dot - (2 * (_ir & 077))))
				return (FALSE);
			arg_s(regnam[(_ir & 0700) >> 6]);
			arg_s(sep_txt);
			arg_s(radmin((lookup(seg_cur, offset))->s_name));
			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);
			arg_s(radmin((lookup(seg_cur, offset))->s_name));
			break;

		case T_NNNNNN:		/* NNNNNN 16 bit data (.WORD)	*/
			arg_o(_ir);
			break;

		case T_NNN:		/* NNN 8 bit data (EMT + TRAP)	*/
			arg_o(_ir & 0377);
			break;

		case T_NN:		/* NN 6 bit data (MARK)		*/
			arg_o(_ir & 077);
			break;

		case T_N:		/* N 3 bit data (SPL)		*/
			arg_o(_ir & 07);
			break;

		case T_AFSS:		/* Fsrc, acc (MULF, MODF etc)	*/
			if (!fltmod(_ir)) {
				on_stack(D1);
				return (FALSE);
			}
			arg_s(sep_txt);
			arg_s(fltnam[(_ir & 0300) >> 6]);
			break;

		case T_AFDD:		/* Acc, Fdst (STF + STCFD)	*/
			arg_s(fltnam[(_ir & 0300) >> 6]);
			arg_s(sep_txt);
			if (!fltmod(_ir)) {
				on_stack(D1);
				return (FALSE);
			}
			break;

		case T_ASS:		/* Src, acc (LDCIF + LDEXP)	*/
			if (!do_1_arg(_ir))
				return (FALSE);
			arg_s(sep_txt);
			arg_s(fltnam[(_ir & 0300) >> 6]);
			break;

		case T_ADD:		/* Acc, dst (STCFI + STEXP)	*/
			arg_s(fltnam[(_ir & 0300) >> 6]);
			arg_s(sep_txt);
			return (do_1_arg(_ir));

		case T_FSS:		/* Fsrc (CLRF etc)		*/
			if (!fltmod(_ir)) {
				on_stack(D1);
				return (FALSE);
			}
			break;

		case M_JMPX:		/* JMP type macros		*/
			if (!do_1_arg(_ir))
				return (FALSE);

			if ((_ir & 037) == 037 && D1->d_flags & A_G) {
				set_ptr(F_INST, "jmpx");
				arg_i();
				arg_s(D1->d_text);
			}
			break;

		case M_RETURN:		/* RTS => RETURN macro		*/
			if ((_ir & 007) != 007)
				arg_s(regnam[_ir & 007]);
			break;

		case M_CALL:		/* JSR => CALL/CALLX macro	*/
			if (!do_1_arg(_ir))
				return (FALSE);

			if ((_ir & 077) == 037 && D1->d_flags & A_G) {
				set_ptr(F_INST, "callx");
				arg_i();
				arg_s(D1->d_text);
			}
			if ((_ir & 0700) != 0700) {
				arg_s(sep_txt);
				arg_s(regnam[(_ir & 0700) >> 6]);
			}
			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		*/

				set_ptr(F_INST, "clr");	/* Its a real CLR	*/
				return (do_1_arg(_ir));
			}

			if ((_ir & 077) == 046)		/* Is it a PUSH ?	*/
				return (do_1_arg(_ir >> 6));

			set_ptr(F_INST, "mov");		/* Its a real MOV	*/
			return (do_2_args(_ir));

		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		*/

				set_ptr(F_INST, "tst");	/* Its a real TST	*/
				return (do_1_arg(_ir));
			}

			if ((_ir & 07700) == 02600)	/* Is it a POP ?	*/
				return (do_1_arg(_ir));

			set_ptr(F_INST, "mov");		/* Must be a MOV 	*/
			return (do_2_args(_ir));

	}
	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 _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;
	arg_s(", ");			/* Should be 'sep_txt'		*/
	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;
{
	register int temp;

	if (_ir & 070)
		return (regmod(D1, _ir));

	if ((temp = _ir & 007) == 6 || temp == 7)
		return (FALSE);

	arg_s(fltnam[temp]);
	return (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;
	SYMBOL_PTR	lookup();
	char	*radmin();

	reg = bits & 07;

	if (bits & 010)
		arg_c('@');

	switch ((bits & 070) >> 3) {

		case 0:
		case 1:
			arg_s(regnam[reg]);
			break;

		case 2:
		case 3:
			if (reg != 7) {
				arg_c('(');
				arg_s(regnam[reg]);
				arg_s(")+");
				break;
			}
			if (((flags = get_item(d_ptr)) & A_TYPE) !=
			    A_DATA || flags & (A_B | A_LIMIT))
				return (FALSE);
			arg_c('#');
			if (flags & A_RELA)
				arg_s(d_ptr->d_text);
			else
				arg_o(d_ptr->d_value);
			break;

		case 4:
		case 5:
			if (reg == 7)
				return (FALSE);
			arg_s("-(");
			arg_s(regnam[reg]);
			arg_c(')');
			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) {
				if (flags & A_RELA)
					arg_s(d_ptr->d_text);
				else
					arg_s(radmin((lookup(seg_cur, d_ptr->d_value + seg_ptr->p_dot))->s_name));
				break;
			}
			if (flags & A_RELA)
				arg_s(d_ptr->d_text);
			else
				arg_o(d_ptr->d_value);
			arg_c('(');
			arg_s(regnam[reg]);
			arg_c(')');
			break;
	}
	return (TRUE);
}


/*************************************************************************
*
*
*			b o u n d e d
*			-------------
*
*	Check that the passed argument lies within the bounds of the
*	current psect. Return TRUE is it does, FALSE else.
*
*************************************************************************/
global
bounded(offset)
register unsigned int offset;
{
	return ( offset <= seg_ptr->p_mlength ? TRUE : FALSE );
}


/*************************************************************************
*
*
*			d o _ l a b e l s
*			-----------------
*
*	Output all the labels for the current dot.
*
*************************************************************************/
local
do_labels()
{
	register SYMBOL_PTR s_ptr;
		 SYMBOL_PTR lookup();
		 SYMBOL_PTR s_index();

	if (!(s_ptr = lookup(seg_cur, seg_ptr->p_dot)))
		return;

	set_ptr(F_LABEL, lbuff);

	label_(s_ptr);

	while (s_ptr = s_index(s_ptr, 2)) {

		line_out(F_LNUM | F_PC | F_LABEL);
		label_(s_ptr);

	}
}

/*************************************************************************
*
*
*			l a b e l _
*			-----------
*
*	Form a true label from a symbol pointer.
*
*************************************************************************/
local
label_(s_ptr)
register SYMBOL_PTR s_ptr;
{
	register char *temp;
	char	*radmin();

	temp = cpystr(lbuff, radmin(s_ptr->s_name));
	*temp++ = ':';
	if (s_ptr->s_flags & S_GLOBAL)
		*temp++ = ':';
	*temp = '\0';
	s_ptr->s_flags |= S_USED;
}


/*************************************************************************
*
*
*			b y t e _
*			---------
*
*	Output a .byte directive (always from the IR).
*
*************************************************************************/
local
byte_()
{
	arg_i();
	if (IR->d_flags & A_RELA)
		arg_s(IR->d_text);
	else
		arg_o(IR->d_value);
	set_ptr(F_ARGS, wbuf);
	set_ptr(F_INST, ".byte");
}

/*************************************************************************
*
*
*			w o r d _
*			---------
*
*	Output a .word directive (always from the IR).
*
*************************************************************************/
local
word_()
{
	arg_i();
	if (IR->d_flags & A_RELA)
		arg_s(IR->d_text);
	else
		arg_o(IR->d_value);
	set_ptr(F_ARGS, wbuf);
	set_ptr(F_INST, word);
}

/*************************************************************************
*
*
*			l i m i t _
*			-----------
*
*	Output a .limit directive.
*
*************************************************************************/
local
limit_()
{
	register int flags;

	arg_i();
	if ((flags = get_item(D1)) & (A_RELA | A_B) ||
	    (flags & A_TYPE) != A_DATA || D1->d_value)
		warn(".LIMIT not followed by blank word\n");
	set_ptr(F_ARGS, wbuf);
	set_ptr(F_INST, ".limit");
}


/*************************************************************************
*
*
*				p s e c t
*				---------
*
*	Handle the output of a psect command. Note: its a ...
*
*	".asect" if
*		a) Name is ". abs."
*		b) psect is ABS and nothing else
*	".csect" if
*		a) Name is blank
*		b) Attributes are REL
*	".csect name" if
*		a) Name is non-blank
*		b) Attributes are GBL, REL, OVR
*	".psect [name]" if
*		not one of the above.
*
*************************************************************************/
local
psect_desc(p_ptr)
register PSECT_PTR p_ptr;
{
	register int flags, temp;
	char	*radnam(), *radmin();

	arg_i();
	set_ptr(F_ARGS, wbuf);

	p_ptr->p_flags = (flags = p_ptr->p_flags) | P_USED;

	if (p_ptr->p_name[0] == 0127401 &&	/* .rad50 -. a-		*/
	    p_ptr->p_name[1] == 0007624 &&	/* .rad50 -bs.-		*/
			!(flags & P_REL)) {	/* ..and its ABS	*/
		set_ptr(F_INST, ".asect");
		return;
	}
	temp = p_ptr->p_name[0] | p_ptr->p_name[1];
	arg_s(radmin(p_ptr->p_name));
	if (((flags & P_ALL) == (P_GBL | P_REL | P_OVR) &&  temp) ||
	    ((flags & P_ALL) ==  P_REL			&& !temp)) {
		set_ptr(F_INST, ".csect");
		return;
	}
	set_ptr(F_INST, ".psect");
	if (!(flags & P_USED))
		p_type(flags);
}


/*************************************************************************
*
*
*				p _ t y p e
*				-----------
*
*	Output the flags for a psect.
*
*************************************************************************/
local
p_type(flags)
register int flags;
{
	arg_s(flags & P_RO   ? ", ro"   : ", rw" );
	arg_s(flags & P_D    ? ", d"    : ", i"  );
	arg_s(flags & P_GBL  ? ", gbl"  : ", lcl");
	arg_s(flags & P_REL  ? ", rel"  : ", abs");
	arg_s(flags & P_OVR  ? ", ovr"  : ", con");
	arg_s(flags & P_HIGH ? ", high" : ", low");
}

/*************************************************************************
*
*
*			p _ r e s e t
*			-------------
*
*	Reset all psect attributes for a new pass.
*
*************************************************************************/
local
p_reset()
{
	register PSECT_PTR p_ptr;
	register int i;

	for (i = 0; i <= seg_max; i++) {

		p_ptr = &segtbl[i];

		p_ptr->p_dot = 0;
		p_ptr->p_flags &= ~P_USED;

	}
}


/*************************************************************************
*
*
*				d o _ e n d
*				-----------
*
*	Handle the .end directive. We try to be flash here. If the trans-
*	fer address was not 000001 in ". abs."  and code is being output,
*	then get the name of the label at that location.
*
*************************************************************************/
local
do_end()
{
	SYMBOL_PTR	s_ptr;
	SYMBOL_PTR	lookup();
	char	*radmin();

	putb();
	line_new();
	IR->d_value = 1;
	IR->d_flags = A_VALID;
	set_ptr(F_INST, ".end");
	if (t_addr.s_flags & S_VALID && code) {
		s_ptr = lookup(t_addr.s_name[0], IR->d_value = t_addr.s_offset);
		set_ptr(F_ARGS, radmin(s_ptr->s_name));
		if (t_addr.s_flags & P_REL)
			IR->d_flags |= A_R;
	}
	line_out(F_LNUM | F_IR | F_INST | F_ARGS);
}
