💾 Archived View for uscoffings.net › retro-computing › systems › TI994a › assemblers › tiasm › src ›… captured on 2024-08-18 at 22:08:19.

View Raw

More Information

⬅️ Previous capture (2022-07-16)

🚧 View Differences

-=-=-=-=-=-=-

%start list

%{
#include "TIasm.h"
#include <stdio.h>
#include "mio.h"

short	isbuf;				/* A place to build object */
short	lcctr = 0;			/* The relocation counter */

extern int Ofd;				/* The object file */
extern FILE *Sdvec[];			/* For doing our funny I/O */

extern char yytext[];
extern int yyleng;

extern flag Ferror;
extern flag Error;
extern int Debug;

%}

%union	{
	short	val;				/* Any old integer */
	struct p {				/* Pointer to a stab ent */
		struct stab *pntr;
		flag enterd;
	} sinfo;
	struct infop opspec;			/* Operand spec info */
}

%token  <sinfo>		OPTYP1	1
%token	<sinfo>		OPTYP2	2
%token	<sinfo>		OPTYP3	3
%token	<sinfo>		OPTYP4	4
%token	<sinfo>		OPTYP5	5
%token	<sinfo>		OPTYP6	6
%token	<sinfo>		OPTYP7	7
%token	<sinfo>		OPTYP8	8
%token	<sinfo>		OPTYP9	9
%token	<sinfo>		OPTYP10	10
%token	<sinfo>		OPTYP11	11
%token	<val>		STRINGDIR
%token	<val>		EXTNLDIR
%token	<val>		WORDDIR
%token	<val>		DATADIR
%token	<val>		REG
%token	<sinfo>		IDENT
%token	<val>		STRING
%token	<val>		NUMBER
%token	<val>		ERROR

%type	<opspec>	mopnd
%type	<val>		pcrel
%type	<val>		indir
%type	<val>		iauto
%type	<opspec>	symbol
%type	<opspec>	isymb
%type	<sinfo>		ident

%%

list	:	/* EMPTY */
			{
			DEBUG (10, "list -> EMPTY\n", NULL);
			DEBUG (10, "lcctr = 0X%x\n", lcctr);
			}
	|	list line
			{
			DEBUG (10, "list -> list line\n", NULL);
			DEBUG (10, "lcctr = 0X%x\n", lcctr);
			}
	|	error
			{
			DEBUG (10, "list -> error\n", NULL);
			DEBUG (10, "lcctr = 0X%x\n", lcctr);
			}
	;

line	:	ident ':'
			{
			struct j_lst *tptr, *t2ptr;
			unsigned tmp;

			DEBUG (10, "line -> ident ':'\n", NULL);
			/* The ONLY place an address may be resolved is here */
			if ($1.pntr->st_type & TYRSLVD) {
				yyerror ("Redeclaration error");
				YYERROR;
			}
			$1.pntr->st_type |= TYRSLVD;
			$1.pntr->en_addr = lcctr;
			DEBUG (9, "Resolving \"%s\"", $1.pntr->st_symnm);
			DEBUG (9, " to addr 0X%x\n", $1.pntr->en_addr);

			/* Now resolve jumps and make these patches */
			for (tptr = $1.pntr->en_jl; tptr != NULL; ) {
				DEBUG (9, "Resolving jumps, addr = 0x%x\n",
				    tptr->j_addr);
				DEBUG (9, "0x%x - ", lcctr);
				DEBUG (9, "0x%x / 2 = ", tptr->j_addr);
				DEBUG (9, "0x%x\n", (lcctr - tptr->j_addr) / 2);
				/* We KNOW this is a forward reference so
				 * we can just make the following subtraction.
				 */
				if ((tmp = (lcctr - tptr->j_addr) / 2) > 0x7f) {
					yyerror ("Jump target out of range");
					
				} else {
					/* Offset size of execute header */
					xseek (Ofd, (long )tptr->j_addr
					    + sizeof(struct format) - 1, 0);
					xwrite (Ofd, tmp, 1);
					xseek (Ofd, (long )0, 2);
				}
				t2ptr = tptr;
				tptr = tptr->j_next;
				rmjinf (t2ptr);
			}
			/* It is possible to trip through the above loop
			 * again. So......
			 */
			$1.pntr->en_jl = NULL;
			}
	|	stmnt
			{
			DEBUG (10, "line -> stmnt\n", NULL);
			}

	;

stmnt	:	OPTYP1	mopnd ',' mopnd
			{
			DEBUG (10, "stmnt -> OPTYP1 mopnd ',' mopnd\n", NULL);
			isbuf = $1.pntr->st_opc;
			/* Source */
			isbuf |= ((0x3 & $2.t) << 4);
			isbuf |= (0xf & $2.r);
			/* Destination */
			isbuf |= ((0x3 & $4.t) << 10);
			isbuf |= ((0xf & $4.r) << 6);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			if ($2.in_tag & SYMTAG) {
				if ($2.in_tag & RELOCATABLE)
					adrinf($2.in_stb, lcctr);
				lcctr += sizeof($2.in_loc);
				xwrite (Ofd, $2.in_loc, sizeof($2.in_loc));
			} if ($4.in_tag & SYMTAG) {
				if ($4.in_tag & RELOCATABLE)
					adrinf($4.in_stb, lcctr);
				lcctr += sizeof($4.in_loc);
				xwrite (Ofd, $4.in_loc, sizeof($4.in_loc));
			}
			}
	|	OPTYP2	pcrel
			{
			DEBUG (10, "fmt2 -> OPTYP2 pcrel\n", NULL);
			isbuf = $1.pntr->st_opc;
			isbuf |= (0xff & $2);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			}
	|	OPTYP2 symbol
			{
			int tmp;

			DEBUG (10, "fmt2 -> OPTYP2 symbol\n", NULL);
			isbuf = $1.pntr->st_opc;
			if ($2.in_stb->st_type & TYRSLVD) {
				DEBUG (9, "fmt2: Label resolved do jump now\n",
				    NULL);
				/* This reference is definately rearward
				 * so the following is legal.
				 */
				tmp = ($2.in_stb->en_addr - lcctr - 2) / 2;
				if ( tmp < -0x7f) {
					yyerror ("Jump target out of range");
					YYERROR;
				} else
					isbuf |= (0xff & (unsigned )tmp);
			} else {
				DEBUG (9, "fmt2: Not resolved, save addr\n",
				    NULL);
				adjinf ($2.in_stb, lcctr + 1);
			}
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			}
	|	OPTYP3	mopnd ',' REG
			{
			DEBUG (10, "fmt3 -> OPTYP3 mopnd ',' REG\n",  NULL);
			isbuf = $1.pntr->st_opc;
			/* source */
			isbuf |= ((0x3 & $2.t) << 4);
			isbuf |= (0xf & $2.r);
			/* Destination register */
			isbuf |= ((0xf & $4) << 6);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			if ($2.in_tag & SYMTAG) {
				if ($2.in_tag & RELOCATABLE)
					adrinf($2.in_stb, lcctr);
				lcctr += sizeof($2.in_loc);
				xwrite (Ofd, $2.in_loc, sizeof($2.in_loc));
			}
			}
	|	OPTYP4	mopnd ',' NUMBER
			{
			DEBUG (10, "fmt4 -> OPTYP4 mopnd ',' NUMBER\n", NULL);
			isbuf = $1.pntr->st_opc;
			/* Register */
			isbuf |= ((0x3 & $2.t) << 4);
			isbuf |= (0xf & $2.r);
			/* count */
			if ($4 < 0) {
				yyerror("transfer/shift count < 0");
				YYERROR;
			}
			if ($4 > 0xf) {
				yyerror ("transfer/shift count > 0xf");
				YYERROR;
			}
			isbuf |= ((0xf & $4) << 6);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			if ($2.in_tag & SYMTAG) {
				if ($2.in_tag & RELOCATABLE)
					adrinf($2.in_stb, lcctr);
				lcctr += sizeof($2.in_loc);
				xwrite (Ofd, $2.in_loc, sizeof($2.in_loc));
			}
			}
	|	OPTYP5	REG ',' NUMBER
			{
			DEBUG (10, "fmt5 -> OPTYP5 REG ',' NUMBER\n", NULL);
			isbuf = $1.pntr->st_opc;
			/* register */
			isbuf |= (0xf & $2);
			/* Count/shift */
			if ($4 < 0) {
				yyerror("transfer/shift count < 0");
				YYERROR;
			}
			if ($4 > 0xf) {
				yyerror("transfer/shift count > 0xf");
				YYERROR;
			}
			isbuf |= ((0xf & $4) << 4);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			}
	|	OPTYP6	mopnd
			{
			DEBUG (10, "fmt6 -> OPTYP6 mopnd\n", NULL);
			isbuf = $1.pntr->st_opc;
			/* Source */
			isbuf |= ((0x3 & $2.t) << 4);
			isbuf |= (0xf & $2.r);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			if ($2.in_tag & SYMTAG) {
				if ($2.in_tag & RELOCATABLE)
					adrinf ($2.in_stb, lcctr);
				lcctr += sizeof($2.in_loc);
				xwrite (Ofd, $2.in_loc, sizeof($2.in_loc));
			}
			}
	|	OPTYP7
			{
			DEBUG (10, "fmt7 -> OPTYP7\n", NULL);
			isbuf = $1.pntr->st_opc;
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			}
	|	OPTYP8	REG ',' symbol
			{
			DEBUG (10, "fmt8 -> OPTYP8 REG ',' symbol\n", NULL);
			isbuf = $1.pntr->st_opc;
			/* Destination */
			isbuf |= (0xf & $2);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			/* Source */
			if ($4.in_tag & RELOCATABLE)
				adrinf ($4.in_stb, lcctr);
			lcctr += sizeof($4.in_loc);
			xwrite (Ofd, $4.in_loc, sizeof($4.in_loc));
			}
	|	OPTYP9	mopnd ',' NUMBER
			{
			DEBUG (10, "OPTYP9 mopnd ',' NUM (%d)\n", $4);
			isbuf = $1.pntr->st_opc;
			/* Destination register */
			isbuf |= ((0xf & $4) << 6);
			/* Source */
			isbuf |= ((0x3 & $2.t) << 4);
			isbuf |= (0xf & $2.r);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			if ($2.in_tag & SYMTAG) {
				if ($2.in_tag & RELOCATABLE)
					/* Enter it to the list of addrs.
					 * So, there is garbage in the slot;
					 * We need to reserve space for the
					 * patch anyway. Who cares what is in
					 * there?
					 */
					adrinf($2.in_stb, lcctr);
				lcctr += sizeof($2.in_loc);
				xwrite (Ofd, $2.in_loc, sizeof($2.in_loc));
			}
			}
	|	OPTYP10 symbol
			{
			DEBUG (10, "stmnt -> OPTYP10\n", NULL);
			isbuf = $1.pntr->st_opc;
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			if ($2.in_tag & RELOCATABLE)
				adrinf ($2.in_stb, lcctr);
			lcctr += sizeof($2.in_loc);
			xwrite (Ofd, $2.in_loc, sizeof($2.in_loc));
			}
	|	OPTYP11 REG
			{
			DEBUG (10, "stmnt -> OPTYP11\n", NULL);
			isbuf = $1.pntr->st_opc;
			isbuf |= (0xf & $2);
			lcctr += sizeof(isbuf);
			xwrite (Ofd, isbuf, sizeof(isbuf));
			}
	|	dirctv
			{
			DEBUG (10, "stmnt -> dirctv\n", NULL);
			}
	;
dirctv	:	STRINGDIR STRING
			{
			char null = NULL; /* Will want address, so.... */

			DEBUG (10, "dirctv -> STRINGDIR STRING\n", NULL);
			dostr (yytext, &yyleng);
			if (Error == TRUE) {
				yyerror ("Illegal meta-character(s) in string");
				YYERROR;
			}
			lcctr += yyleng;
			/* The I/O macros force this..... BE CAREFUL if
			 * you change them!
			 */
			xwrite (Ofd, yytext[0], yyleng);
			/* If odd length, then align */
			if (odd(yyleng)) {
				lcctr += 1;
				xwrite (Ofd, null, 1);
			}
			}

	|	EXTNLDIR ident
			{
			DEBUG (10, "dirctv -> EXTNLDIR ident\n", NULL);
			$2.pntr->st_type |= TYEXTID;
			}
	|	WORDDIR NUMBER
			{
			short awrd;
			short x;

			DEBUG (10, "dirctv -> WORDDIR number\n", NULL);
			lcctr += $2 * 2;
			for (x = 0; x < $2; ++x)
				xwrite (Ofd, awrd, sizeof(awrd));
			}
	|	WORDDIR
			{
			short awrd;

			DEBUG (10, "dirctv -> WORDDIR\n", NULL);
			lcctr += 2;
			xwrite (Ofd, awrd, sizeof(awrd));
			}
	|	DATADIR symbol
			{
			DEBUG (10, "dirctv -> DATADIR symbol\n", NULL);
			xwrite (Ofd, $2.in_loc, sizeof($2.in_loc));
			if ($2.in_tag & RELOCATABLE)
				adrinf ($2.in_stb, lcctr);
			lcctr += 2;
			}
	;

mopnd	:	REG
			{
			DEBUG (10, "mopnd -> REG\n", NULL);
			$.t = 0;
			$.r = $1;
			$.in_tag &= ~SYMTAG;		/* Paranoid */
			}
	|	iauto
			{
			DEBUG (10, "mopnd -> iauto\n", NULL);
			$.t = 03;
			$.r = $1;
			$.in_tag &= ~SYMTAG;		/* Paranoid */
			}
	|	isymb
			{
			DEBUG (10, "mopnd -> isymb\n", NULL);
			$ = $1;
			$.t = 02;
			/* Register to index off of is already set */
			}
	|	symbol
			{
			DEBUG (10, "mopnd -> symbol\n", NULL);
			$ = $1;
			$.t = 02;
			$.r = 0;		/* Force non-indexed */
			}
	|	indir
			{
			DEBUG (10, "mopnd -> indir\n", NULL);
			$.t = 01;
			$.r = $1;
			$.in_tag &= ~SYMTAG;		/* Paranoid */
			}
	;

pcrel	:	'



			{
			DEBUG (10, "pcrel -> '


\n", NULL);
			$ = lcctr;
			}
	|	'


 '+' NUMBER
			{
			DEBUG (10, "pcrel -> '


 '+' NUMBER\n", NULL);
			$ = lcctr + $3;
			/* Check signed 8 bit jump range */
			if (abs($) > 0x7f) {
				yyerror ("Jump target out of range");
				YYERROR;
			}
			}
	|	'


 '-' NUMBER
			{
			DEBUG (10, "pcrel -> '


 '-' NUMBER\n", NULL);
			$ = lcctr - $3;
			/* Check signed 8 bit jump range */
			if (abs($) > 0xff) {
				yyerror ("Jump out of range");
				YYERROR;
			}
			}
	;

indir	:	'(' REG ')'
			{
			DEBUG (10, "indir -> '(' REG ')'\n", NULL);
			$ = $2;
			}
	;

iauto	:	'(' REG ')' '+'
			{
			DEBUG (10, "iauto -> '(' REG ')' '+'\n", NULL);
			$ = $2;
			}
	;

isymb	:	symbol '[' REG ']' 
			{
			DEBUG (10, "isymb -> symbol '[' REG ']'\n", NULL);
			/* The identifier/absolute address */
			$ = $1;
			$.r = $3; /* Change this field to reflect indexed */
			}
	;

symbol	:	ident
			{
			DEBUG (10, "symbol -> ident\n",  NULL);
			/* The identifier is entered into the relocation
			 * table already.
			 */
			$.in_tag = SYMTAG | RELOCATABLE;
			$.in_stb = $1.pntr;
			}
	|	NUMBER
			{
			DEBUG (10, "symbol -> NUMBER\n", NULL);
			/* An absolute address */
			$.in_tag |= SYMTAG & ~RELOCATABLE;
			$.in_loc = $1;
			}
	;

ident	:	IDENT
			{
			/* This way so that we can enter it into the
			 * relocation table here
			 */
			extern struct stab *insert();

			DEBUG (10, "ident -> IDENT; name = %s\n",
			    $1.pntr->st_symnm);
			if ($1.enterd != TRUE) {
				/* Mark it as entered */
				$1.enterd = TRUE;
				/* And, enter it */
				if (insert($1.pntr) == NULL)
					aabort ("Symbol table overflow\n");
			}
			$ = $1;
			}
	;

%%

/* yyerror
 * The assemblers error reporting, flagging, clearing routine.
 *
 * Returns:
 *	Nothing, though for consistency it must be declared int
 */

int yyerror (string)
char	*string;
{
	char	c;
	extern flag Ferror;
	extern int Lincnt;
	fprintf (stderr, "%d: %s\n", Lincnt, string);
/*
	while ((c = input()) != '\n' && c != 0)
		;
	unput(c);

	Ferror = TRUE;
}