Category : Files from Magazines
Archive   : DDJ8612.ZIP
Filename : RODMAN.DEC

 
Output of file : RODMAN.DEC contained in archive : DDJ8612.ZIP

/* A32000.C - Series 32000 assembler
850903 rr fix addr ext, scaled index, acp, cxp 0.10
850902 rr add scaled index logic 0.09
850828 rr fix enter, setcfg, lpr/spr, index 0.08
850809 rr add equate logic 0.07
850730 rr add binary search in lookup 0.06
850729 rr symbol table mods, reglist 0.05

Still need:
--- register names for lpr/spr
--- linkable modules

Note: While 68000 is hilo (high-bytes at lower memory
addresses), 32000 is lohi (low-bytes at lower memory
addresses, like the Z80).

This is a 3-pass assembler; 3 passes to make
sure that relative branches are computed correctly. */

#define EOF -1

#define SYMSIZ 1024 /* symbol table size */

char inpbuf[ 256 ]; /* input buffer */
int inpcnt, inpptr; /* input counter, pointer */

char word_buffer[ 128 ]; /* buff for current word */
char ambig_buffer[ 128 ]; /* ambiguous refs here */

char listline[ 81 ]; /* line of listing output */
int listop, listcp; /* pointers for list output */

int paren = 0; /* used in gchar() */
int brack = 0;
int quote = 0;

int iwparen = 0; /* used in inword() */

int errors = 0; /* count of errors */

char *word; /* pointer to current word */
char *ambig[ 10 ]; /* filled in by match */
int ambcnt = 0; /* count of pointers in ambig[] */

int pass; /* pass = 1, 2 or 3 */
long int asmadr, codadr; /* assembly addr, code addr */
char filename[ 30 ];

int fasm, fobj; /* file numbers */

char objbuf[ 64 ]; /* object byte buffer */
long int objadr; /* addr of first byte of buf */
int objcnt = 0; /* count of bytes in buffer */

struct { /* Symbol table */
char *snam; /* symbol name */
long int sval; /* value */
} symbol[ SYMSIZ ];

int symcnt; /* count of symbols */

char hexchr[ 17 ] = "0123456789abcdef";

/* --- 32000 opcodes --- */

/* Note: Shortest form of opcode must be listed first. */

#define MAXOP 149

/* the opcode binary value should be a string of bits,
e.g. 0111xxxxx000b the opcode opopt character is used
to specify special operands, etc. */

/* opopts used here for the 32000 are:
blank nothing special
a gen
b gen short
c gen gen
d 00000 short
e gen gen reg
f reglist save/enter
g reglist restore/exit
h 00000 gen (sfsr)
i inss/exts
j movs/skps/cmps
k setcfg
l procreg, gen for lpr/spr
m index (operand order)
n ret/rett - postbyte
o movm
p cxp (disp after instruction) */

struct {
char *onam; /* opcode name */
int ocnt; /* operand count, negative if PC-rel */
char *obin; /* opcode binary value */
char oopt; /* opcode opopt char */
} opcode[ MAXOP ] = {

/* Format 1 ops (16) */

"bsr", -1, "02h", ' ',
"ret", 1, "12h", 'n',
"cxp", 1, "22h", 'p',
"rxp", 1, "32h", 'n',
"rett", 1, "42h", 'n',
"reti", 0, "52h", ' ',
"save", 1, "62h", 'f',
"restore", 1, "72h", 'g',
"enter", 2, "82h", 'f',
"exit", 1, "92h", 'g',
"nop", 0, "0a2h", ' ',
"wait", 0, "0b2h", ' ',
"dia", 0, "0c2h", ' ',
"flag", 0, "0d2h", ' ',
"svc", 0, "0e2h", ' ',
"bpt", 0, "0f2h", ' ',

/* Conditional branches (15) */

"beq", -1, "0ah", 'b',
"bne", -1, "1ah", 'b',
"bcs", -1, "2ah", 'b',
"bcc", -1, "3ah", 'b',
"bhi", -1, "4ah", 'b',
"bls", -1, "5ah", 'b',
"bgt", -1, "6ah", 'b',
"ble", -1, "7ah", 'b',
"bfs", -1, "8ah", 'b',
"bfc", -1, "9ah", 'b',
"blo", -1, "0aah", 'b',
"bhs", -1, "0bah", 'b',
"blt", -1, "0cah", 'b',
"bge", -1, "0dah", 'b',
"br", -1, "0eah", 'b',

/* Format 2 ops (7) */

"addq?", 2, "xxxxxxxxx00011iib", 'e',
"cmpq?", 2, "xxxxxxxxx00111iib", 'e',
"spr?", 2, "xxxxxxxxx01011iib", 'l',
"lpr?", 2, "xxxxxxxxx11011iib", 'l',

"seq?", 1, "xxxxx000001111iib", 'a',
"sne?", 1, "xxxxx000101111iib", 'a',
"scs?", 1, "xxxxx001001111iib", 'a',
"scc?", 1, "xxxxx001101111iib", 'a',
"shi?", 1, "xxxxx010001111iib", 'a',
"sls?", 1, "xxxxx010101111iib", 'a',
"sgt?", 1, "xxxxx011001111iib", 'a',
"sle?", 1, "xxxxx011101111iib", 'a',
"sfs?", 1, "xxxxx100001111iib", 'a',
"sfc?", 1, "xxxxx100101111iib", 'a',
"slo?", 1, "xxxxx101001111iib", 'a',
"shs?", 1, "xxxxx101101111iib", 'a',
"slt?", 1, "xxxxx110001111iib", 'a',
"sge?", 1, "xxxxx110101111iib", 'a',
"st?", 1, "xxxxx111001111iib", 'a',
"sf?", 1, "xxxxx111101111iib", 'a',

/* The acb instruction 3rd operand is a relative jump */

"acb?", -3, "xxxxxxxxx10011iib", 'e',
"movq?", 2, "xxxxxxxxx10111iib", 'e',

/* Format 3 instructions (7) */

"cxpd", 1, "xxxxx00001111111b", 'a',
"bicpsr?", 1, "xxxxx001011111iib", 'a',
"jump", 1, "xxxxx01001111111b", 'a',
"bispsr?", 1, "xxxxx011011111iib", 'a',
"adjsp?", 1, "xxxxx101011111iib", 'a',
"jsr", 1, "xxxxx11001111111b", 'a',
"case?", 1, "xxxxx111011111iib", 'a',

/* Format 11 ops (16) -
moved here so wildcards won't interfere */

"addf", 2, "xxxxxxxxxx00000110111110b", 'c',
"addl", 2, "xxxxxxxxxx00000010111110b", 'c',
"movf", 2, "xxxxxxxxxx00010110111110b", 'c',
"movl", 2, "xxxxxxxxxx00010010111110b", 'c',
"cmpf", 2, "xxxxxxxxxx00100110111110b", 'c',
"cmpl", 2, "xxxxxxxxxx00100010111110b", 'c',
"subf", 2, "xxxxxxxxxx01000110111110b", 'c',
"subl", 2, "xxxxxxxxxx01000010111110b", 'c',
"negf", 2, "xxxxxxxxxx01010110111110b", 'c',
"negl", 2, "xxxxxxxxxx01010010111110b", 'c',
"divf", 2, "xxxxxxxxxx10000110111110b", 'c',
"divl", 2, "xxxxxxxxxx10000010111110b", 'c',
"mulf", 2, "xxxxxxxxxx11000110111110b", 'c',
"mull", 2, "xxxxxxxxxx11000010111110b", 'c',
"absf", 2, "xxxxxxxxxx11010110111110b", 'c',
"absl", 2, "xxxxxxxxxx11010010111110b", 'c',

/* Format 4 instructions (12) */

"add?", 2, "xxxxxxxxxx0000iib", 'c',
"cmp?", 2, "xxxxxxxxxx0001iib", 'c',
"bic?", 2, "xxxxxxxxxx0010iib", 'c',
"addc?", 2, "xxxxxxxxxx0100iib", 'c',
"mov?", 2, "xxxxxxxxxx0101iib", 'c',
"or?", 2, "xxxxxxxxxx0110iib", 'c',
"sub?", 2, "xxxxxxxxxx1000iib", 'c',
"addr", 2, "xxxxxxxxxx100111b", 'c',
"lxpd", 2, "xxxxxxxxxx100111b", 'c',
"and?", 2, "xxxxxxxxxx1010iib", 'c',
"subc?", 2, "xxxxxxxxxx1100iib", 'c',
"tbit?", 2, "xxxxxxxxxx1101iib", 'c',
"xor?", 2, "xxxxxxxxxx1110iib", 'c',

/* Format 5 instructions (4) */

"movst", 1, "00000xxx100000ii00001110b", 'j',
"movs?", 1, "00000xxx000000ii00001110b", 'j',
"cmpst", 1, "00000xxx100001ii00001110b", 'j',
"cmps?", 1, "00000xxx000001ii00001110b", 'j',
"skpst", 1, "00000xxx100011ii00001110b", 'j',
"skps?", 1, "00000xxx000011ii00001110b", 'j',

"setcfg", 1, "00000xxxx000101100001110b", 'k',

/* Format 6 ops (14) */

"rot?", 2, "xxxxxxxxxx0000ii01001110b", 'c',
"ash?", 2, "xxxxxxxxxx0001ii01001110b", 'c',
"cbit?", 2, "xxxxxxxxxx0010ii01001110b", 'c',
"cbiti?", 2, "xxxxxxxxxx0011ii01001110b", 'c',
"lsh?", 2, "xxxxxxxxxx0101ii01001110b", 'c',
"sbit?", 2, "xxxxxxxxxx0110ii01001110b", 'c',
"sbiti?", 2, "xxxxxxxxxx0111ii01001110b", 'c',
"neg?", 2, "xxxxxxxxxx1000ii01001110b", 'c',
"not?", 2, "xxxxxxxxxx1001ii01001110b", 'c',
"subp?", 2, "xxxxxxxxxx1011ii01001110b", 'c',
"abs?", 2, "xxxxxxxxxx1100ii01001110b", 'c',
"com?", 2, "xxxxxxxxxx1101ii01001110b", 'c',
"ibit?", 2, "xxxxxxxxxx1110ii01001110b", 'c',
"addp?", 2, "xxxxxxxxxx1111ii01001110b", 'c',

/* Format 7 ops (15) */

"movm?", 3, "xxxxxxxxxx0000ii11001110b", 'o',
"cmpm?", 2, "xxxxxxxxxx0001ii11001110b", 'c',
"inss?", 4, "xxxxxxxxxx0010ii11001110b", 'i',
"exts?", 4, "xxxxxxxxxx0011ii11001110b", 'i',
"movxbw?", 2, "xxxxxxxxxx0100ii11001110b", 'c',
"movzbw?", 2, "xxxxxxxxxx0101ii11001110b", 'c',
"movz?d", 2, "xxxxxxxxxx0110ii11001110b", 'c',
"movx?d", 2, "xxxxxxxxxx0111ii11001110b", 'c',
"mul?", 2, "xxxxxxxxxx1000ii11001110b", 'c',
"mei?", 2, "xxxxxxxxxx1001ii11001110b", 'c',
"dei?", 2, "xxxxxxxxxx1011ii11001110b", 'c',
"quo?", 2, "xxxxxxxxxx1100ii11001110b", 'c',
"rem?", 2, "xxxxxxxxxx1101ii11001110b", 'c',
"mod?", 2, "xxxxxxxxxx1110ii11001110b", 'c',
"div?", 2, "xxxxxxxxxx1111ii11001110b", 'c',

/* Format 8 ops (8) */

"ext?", 4, "xxxxxxxxxxxxx0ii00101110b", 'm',
"cvtp", 3, "xxxxxxxxxxxxx01101101110b", 'm',
"ins?", 4, "xxxxxxxxxxxxx0ii10101110b", 'm',
"check?", 3, "xxxxxxxxxxxxx0ii11101110b", 'm',
"index?", 3, "xxxxxxxxxxxxx1ii00101110b", 'm',
"ffs?", 2, "xxxxxxxxxx0001ii01101110b", 'c',
"movsu?", 2, "xxxxxxxxxx0011ii10101110b", 'c',
"movus?", 2, "xxxxxxxxxx0111ii10101110b", 'c',

/* Format 9 ops (12) */

"movlf", 2, "xxxxxxxxxx0101ii00111110b", 'c',
"movfl", 2, "xxxxxxxxxx0111ii00111110b", 'c',
"mov?f", 2, "xxxxxxxxxx0001ii00111110b", 'c',
"mov?l", 2, "xxxxxxxxxx0000ii00111110b", 'c',
"lfsr", 1, "xxxxx0000000111100111110b", 'a',
"sfsr", 1, "00000xxxxx11011100111110b", 'h',
"roundf?", 2, "xxxxxxxxxx1001ii00111110b", 'c',
"roundl?", 2, "xxxxxxxxxx1000ii00111110b", 'c',
"truncf?", 2, "xxxxxxxxxx1011ii00111110b", 'c',
"truncl?", 2, "xxxxxxxxxx1010ii00111110b", 'c',
"floorf?", 2, "xxxxxxxxxx1111ii00111110b", 'c',
"floorl?", 2, "xxxxxxxxxx1110ii00111110b", 'c',

/* Format 14 instructions (4) */

"rdval", 1, "xxxxxxxxx000001100011110b", 'a',
"wrval", 1, "xxxxxxxxx000011100011110b", 'a',
"lmr", 2, "xxxxxxxxx000101100011110b", 'e',
"smr", 2, "xxxxxxxxx000111100011110b", 'e'
};

/* Address Mode Table */

#define MAXAM 42

struct {
char *mstr; /* mode match string */
char *gstr; /* output string to insert (gen) */
int mcnt; /* count of ambigs to be put into
extension bytes */

char mopt; /* mode option */
} admode[ MAXAM ] = {

/* Scaled index modes */

"*[r?:b]", "11100", 1, 's',
"*[r?:w]", "11101", 1, 's',
"*[r?:d]", "11110", 1, 's',
"*[r?:q]", "11111", 1, 's',

/* Simple register modes */

"r0", "00000", 0, ' ', /* main registers */
"r1", "00001", 0, ' ',
"r2", "00010", 0, ' ',
"r3", "00011", 0, ' ',
"r4", "00100", 0, ' ',
"r5", "00101", 0, ' ',
"r6", "00110", 0, ' ',
"r7", "00111", 0, ' ',

"f0", "00000", 0, ' ', /* floating point */
"f1", "00001", 0, ' ',
"f2", "00010", 0, ' ',
"f3", "00011", 0, ' ',
"f4", "00100", 0, ' ',
"f5", "00101", 0, ' ',
"f6", "00110", 0, ' ',
"f7", "00111", 0, ' ',

/* Indexed addressing modes */

"*(r0)", "01000", 1, ' ', /* indexed */
"*(r1)", "01001", 1, ' ',
"*(r2)", "01010", 1, ' ',
"*(r3)", "01011", 1, ' ',
"*(r4)", "01100", 1, ' ',
"*(r5)", "01101", 1, ' ',
"*(r6)", "01110", 1, ' ',
"*(r7)", "01111", 1, ' ',

"*(*(fp))", "10000", 2, 'r', /* frame ptr */
"*(*(sp))", "10001", 2, 'r', /* stack mem */
"*(*(sb))", "10010", 2, 'r', /* static mem */

"#*", "10100", 1, ' ', /* immediate */
"@*", "10101", 1, ' ', /* absolute */
"ext(*)+*", "10110", 2, ' ', /* external */
"tos", "10111", 0, ' ', /* top of stack */

"*(fp)", "11000", 1, ' ', /* frame mem */
"*(sp)", "11001", 1, ' ', /* stack mem */
"*(sb)", "11010", 1, ' ', /* static mem */

".+*", "11011", 1, ' ', /* program mem */

"[*]", "", 0, 'l', /* register list */

/* catch-all */

"*", "", 1, 'w' /* fits no pattern */
};

/*---MAIN PROGRAM---*/

main( argc, argv )
int argc;
char *argv[];
{
int i;

puts( "\nA32000 v0.10" );

if( argc < 2 ) {
puts( "\n?No file name specified" );
exit( 1 );
}

symcnt = 0;

for( pass = 1; pass <= 3; ++pass ) {

makename( argv[ 1 ], ".s" );
fasm = fopen( filename, "r" );

if( fasm == 0 ) {
puts( "\n?Unable to open source file" );
exit( 1 );
}

if( pass == 3 ) {
makename( argv[ 1 ], ".hex" );
fobj = fopen( filename, "w" );
if( ! fobj ) {
puts( "\n?No directory space" );
exit( 1 );
}
}

puts( "\nPass " );
putchar( pass + '0' );

asmadr = 0;
codadr = 0;

if( pass == 3 ) {
objflush();
listnl();
}
inpload();

while( gword() ) {

if( match( word, "end" )) break;

/* Each word is processed by the following nested if
statement, which attempts to identify what it is.
Note that any successful identification stops the
process of the statement. */

if( ! islabel( word ))
if( ! ispseudo( word ))
if( ! isopcode( word ))
if( ! isequate( word ))
error( '?', word );
}

fclose( fasm );

/* Sort symbols after pass 1. */

if( pass == 1 ) sortsyms();

if( pass == 3 ) {
objflush();

putc( ':', fobj ); /* write eof record */
for( i = 0; i < 10; ++i ) putc( '0', fobj );
putc( '\n', fobj );

fclose( fobj );
}
}

listpr();
puts( "\n\n" );
dumpsyms();

if( errors )
puts( "\n---Fix errors and reassemble---" );
}

/* Construct a filename from two strings. */

makename( p, q )
char *p, *q;
{
char *r;
r = &filename[ 0 ];
while( *p ) *r++ = *p++;
while( *q ) *r++ = *q++;
*r = '\0';
}

/* Check to see if the word is a label, and if it is, add
its value to the symbol table */

int islabel( w )
char *w;
{
while( *w ) ++w;
if( *--w != ':' ) return 0;
*w = '\0'; /* take off the colon */

addsymbol( word, codadr );
return 1;
}

/* Check the word to see if it is a pseudo-op. */

int ispseudo( w )
char *w;
{
long int getarg(), temp;

if( match( w, "org" )) {
asmadr = getarg();
codadr = asmadr;
if( pass == 3 ) objflush();
return 1;
}

if( match( w, "db" )) { /* Note: Allow msgs? */
temp = getarg(); /* get argument */
objout( temp & 0xFF ); /* output byte */
return 1;
}

if( match( w, "dw" )) {
temp = getarg(); /* get argument */
objout( temp & 0xFF ); /* output lsb */
objout(( temp >> 8 ) & 0xFF ); /* output msb */
return 1;
}

if( match( w, "dd" )) {
temp = getarg(); /* get argument */
objout( temp & 0xFF ); /* output lsb */
objout(( temp >> 8 ) & 0xFF );
objout(( temp >> 16 ) & 0xFF );
objout(( temp >> 24 ) & 0xFF ); /* output msb */
return 1;
}

if( match( w, "even" ) && ( codadr & 1 )) {
objout( 0 ); /* send 1 byte to go to word bndry */
return 1;
}

return 0;
}

/* Check to see if the word is an opcode, and if it is,
get any operands required and generate code. */

int isopcode( w )
char *w;
{
long int value(), bitbin(), decbin(), o, ocodadr;
char opbuf[ 33 ], bytbuf[ 33 ], extbuf[ 128 ];
char opopt, modopt, opsiz, opcnt;
int i, j, k, l;
char *p, *q, *cpystr(), *regbits();

/* postbytes & scaled indexes */
int opexbt[ 4 ], opexct;

int adexct, adexln[ 8 ];
char *adexpt[ 8 ], *eoadex; /* addressing extensions */

ocodadr = codadr; /* save addr of begin of instr */

opexct = 0; /* no postbytes as yet */
adexct = 0; /* no extensions as yet */
eoadex = &extbuf[ 0 ]; /* point to begin of extbuf */

for( i = 0; i < MAXOP; ++i )
if( match( w, opcode[ i ].onam )) {

opopt = opcode[ i ].oopt;

if( opopt == 'x' ) {
error( 'x', w ); /* unimplemented instruction */
return 1;
}

p = cpystr( opcode[ i ].obin, &opbuf[ 0 ] );

/* see if length modifier */

if( ambcnt > 0 ) {
p = &opbuf[ 0 ];
opsiz = *ambig[ 0 ];

while( *p && *p != 'i' ) ++p;

if( ! *p ) error( 'l', w );
else {
switch( opsiz ) {

case 'b' : *p++ = '0';
*p++ = '0';
break;

case 'w' : *p++ = '0';
*p++ = '1';
break;

case 'd' : *p++ = '1';
*p++ = '1';
}
}
}

/* now parse operands */

/* get count of operands.
Take abs value (neg = PC-relative) */

opcnt = opcode[ i ].ocnt;
if( opcnt < 0 ) opcnt = 0 - opcnt;

p = &opbuf[ 0 ]; /* modified parts start at beg. */

for( j = 0; j < opcnt; ++j ) {
gword(); /* get operand */

/* find addr mode */

k = 0;
while(( k < MAXAM )
&& ! match( word, admode[ k ].mstr )) ++k;

modopt = admode[ k ].mopt;

/* move bit string into place */

q = admode[ k ].gstr;

/* if opopt h, sfsr, skip 5 bits */

if( opopt == 'h' ) p += 5;

/* for most opopts, move the bits in */

if(( opopt == ' ' )
|| ( opopt == 'a' )
|| ( opopt == 'c' )
|| ( opopt == 'e' && j == 1 )
|| ( opopt == 'h' )
|| ( opopt == 'i' && j < 2 )
|| ( opopt == 'l' && j == 1 )
|| ( opopt == 'm' && j > 0 && j < 3 )
|| ( opopt == 'o' && j < 2 ))
while( *q ) *p++ = *q++;

/* Double the effort for scaled index mode. create an
extension postbyte opexbt[] with basemode as upper
5 bits, reg as lower 3 bits. */

if( admode[ k ].mopt == 's' ) {
l = ( *ambig[ 1 ] ) & 7;
q = cpystr( ambig[ 0 ], &bytbuf[ 0 ] );

/* find basemode */

k = 0;
while(( k < MAXAM )
&& ! match( &bytbuf[ 0 ],
admode[ k ].mstr )) ++k;

modopt = admode[ k ].mopt;

/* move bit string into postbyte. use bitbin, because
value() destroys ambig[] array which we still need. */

q = cpystr( admode[ k ].gstr,
&bytbuf[ 0 ] );
--q; /* back up to null */
*q++ = '0' + (( l >> 2 ) & 1 );
*q++ = '0' + (( l >> 1 ) & 1 );
*q++ = '0' + ( l & 1 );
*q = '\0';

opexbt[ opexct++ ] = bitbin( &bytbuf[ 0 ] );
q = admode[ k ].gstr;
}

/* funny handling of reg: index operation (opopt 'm') */

if( opopt == 'm' && j == 0 ) {
p = &opbuf[ 10 ]; /* off to reg */
q += 2; /* skip 0 bits */
while( *q ) *p++ = *q++;
p = &opbuf[ 0 ]; /* reset */
}

/* move ambigs into extension bytes. set length to
variable (0). For some addressing modes, the
extensions go in in reverse order */

if( modopt == 'r' )
for( l = admode[ k ].mcnt - 1; l >= 0;
--l ) {
adexpt[ adexct ] = eoadex;
adexln[ adexct ] = 0;
++adexct;
eoadex = cpystr( ambig[ l ], \
eoadex );
} else for( l = 0; l < admode[ k ].mcnt; ++l ) {
adexpt[ adexct ] = eoadex;
adexln[ adexct ] = 0;
++adexct;
eoadex = cpystr( ambig[ l ], \
eoadex );
}

/* special logic for register list for "enter", "save",
"restore", "exit" */

if(( j == 0 && opopt == 'f' ) || opopt == 'g' ) {
adexpt[ adexct ] = eoadex;
adexln[ adexct ] = 1;
++adexct;
eoadex = regbits( word, eoadex, opopt );
}

/* shorten extension to 1 byte for enter, return */

if(( j == 1 && opopt == 'f' ) || opopt == 'n' ) {
if( adexct > 0 ) adexln[ adexct - 1 ] = 1;
else error( 'e', w );
}

/* opopts 'e' or 'd': immed data becomes 4 bit value */

if(( j == 0 && opopt == 'e' ) || opopt == 'd' ) {
if( ! adexct ) error( 'e', w );
else {
l = value( adexpt[ --adexct ] );
p = &opbuf[ 5 ];
*p++ = '0' + (( l >> 3 ) & 1 );
*p++ = '0' + (( l >> 2 ) & 1 );
*p++ = '0' + (( l >> 1 ) & 1 );
*p = '0' + ( l & 1 );
p = &opbuf[ 0 ];
}
}

/* opopt 'i': combine last two ambigs into one postbyte.
Put it in bytbuf and set length to 1 */

if( opopt == 'i' && j == 3 ) {
if( adexct < 2 ) error( 'e', w );
else {
l = ( value( adexpt[ --adexct ] ) - 1 )
& 31;
l += ( value( adexpt[ --adexct ] )
& 7 ) << 5;
bytbuf[ 0 ] = '0' +
(( l / 100 ) % 10 );
bytbuf[ 1 ] = '0' +
(( l / 10 ) % 10 );
bytbuf[ 2 ] = '0' + ( l % 10 );
bytbuf[ 3 ] = '\0';
adexpt[ adexct ] = &bytbuf[ 0 ];
adexln[ adexct++ ] = 1;
}
}

/* opopt 'j': uwb bits for movs, cmps, skps */

if( opopt == 'j' ) {
p += 5;
uwbbits( word, p );
adexct = 0; /* in case no paren */
}

/* opopt 'k': config bits for setcfg */

if( opopt == 'k' ) {
p += 5;
cfgbits( word, p );
}

/* opopt 'l': operand 1 becomes 4 bit value */

if( opopt == 'l' && j == 0 ) {
adexct = 0; /* unjunk extensions */
l = -1;
if( strcmp( word, "upsr" ) == 0 ) l = 0;
if( strcmp( word, "fp" ) == 0 ) l = 8;
if( strcmp( word, "sp" ) == 0 ) l = 9;
if( strcmp( word, "sb" ) == 0 ) l = 10;
if( strcmp( word, "psr" ) == 0 ) l = 13;
if( strcmp( word, "intbase" ) == 0 ) l = 14;
if( strcmp( word, "mod" ) == 0 ) l = 15;
if( l == -1 ) error( 'p', word );
else {
p = &opbuf[ 5 ];
*p++ = '0' + (( l >> 3 ) & 1 );
*p++ = '0' + (( l >> 2 ) & 1 );
*p++ = '0' + (( l >> 1 ) & 1 );
*p = '0' + ( l & 1 );
p = &opbuf[ 0 ];
}
}

/* odd length extension for movm, opopt 'o' */

if( j == 2 && opopt == 'o' ) {
if( adexct > 0 ) adexln[ --adexct ] = 1;
else error( 'e', w );
l = value( adexpt[ adexct ] ) - 1;
switch( opsiz ) {
case 'd' : l *= 4; break;
case 'w' : l *= 2; break;
}
bytbuf[ 0 ] = '0' + (( l / 100 ) % 10 );
bytbuf[ 1 ] = '0' + (( l / 10 ) % 10 );
bytbuf[ 2 ] = '0' + ( l % 10 );
bytbuf[ 3 ] = '\0';
adexpt[ adexct++ ] = &bytbuf[ 0 ];
}

} /* done operands */

o = value( &opbuf[ 0 ] );

l = strlen( opbuf );

/* Send as many opcode bytes as necessary */

objout( o % 256 );
if( l > 9 ) objout(( o / 256 ) % 256 );
if( l > 17 ) objout( o / 65536 );

/* Send postbytes for scaled index mode */

for( l = 0; l < opexct; ++l )
objout( opexbt[ l ] );

/* Send addressing extensions.
adexln = length of extension word in bytes if +.
If 0, it is a variable-length signed displacement.
If -1, indicates code-relative */

/* If opcode ocnt was negative, last address extension is
code relative. */

if( opcode[ i ].ocnt < 0 )
adexln[ adexct - 1 ] = -1;

/* send extension words */

for( j = 0; j < adexct; ++j ) {


o = value( adexpt[ j ] );

/* if adexln[] negative, operand(s) code-relative.
Note: on the 32000 you don't correct by adding 2 to
codadr first */

if( adexln[ j ] < 0 ) o -= ocodadr;

/* Compute variable-length signed displacement */

if( adexln[ j ] <= 0 ) {
if( o < 63 && o > -64 ) {
o = ( o & 0x7F );
l = 1; /* one-byte */
} else if( o < 8191 && o > -8192 ) {
o = ( o & 0x3FFF ) + 0x8000;
l = 2;
} else {
o = ( o & 0x3FFFFFFF )
+ 0xC0000000;
l = 4;
}
} else l = adexln[ j ];

/* address extensions are sent in lohi order */

if( l > 3 ) objout(( o >> 24 ) & 0xFF );
if( l > 2 ) objout(( o >> 16 ) & 0xFF );
if( l > 1 ) objout(( o >> 8 ) & 0xFF );
objout( o % 256 );
}
return 1;
}
return 0;
}

/* Special to create extension word for register list */

/* Regbits may look like "r0" or may look like "[r0,r2]"
or like "[r0-r7]". */

char *regbits( src, dst, flg )
char *src, *dst, flg;
{
int bits, reg, loreg, hireg;

bits = 0;

if( *src == '[' ) ++src; /* strip parens */
else error( '[', src );

while( *src ) {
if( *src++ != 'r' ) error( 'r', src );
reg = ( *src++ ) - '0';
bits = bits | ( 1 << reg );
if( *src++ == '-' ) {
loreg = reg;
if( *src++ != 'r' ) error( 'r', src );
hireg = ( *src++ ) - '0';
if( hireg < loreg ) {
reg = hireg;
hireg = loreg;
loreg = reg;
} /* swap if out of order */
for( reg = loreg; reg <= hireg; ++reg )
bits = bits | ( 1 << reg );
++src; /* skip over the comma */
}
if( *src == ']' ) break;
}

/* if flg = 'f', save/enter, need to swap bit
significance. The routine above constructed it in
reversed order in the first place, because of the
routine below */

if( flg == 'f' ) {
hireg = 0;
for( reg = 0; reg < 8; ++reg ) {
hireg = ( hireg << 1 ) + ( bits & 1 );
bits = ( bits >> 1 );
}
bits = hireg;
}

/* now create a binary string for the extension.
Note that bit significance becomes reversed again */

for( reg = 0; reg < 8; ++reg ) {
*dst++ = '0' + ( bits & 1 );
bits = ( bits >> 1 );
}

*dst++ = 'b'; /* add b for binary */
*dst++ = '\0'; /* terminate */

return dst;
}

/* put config bits into instruction */

cfgbits( src, dst )
char *src, *dst;
{
char b[ 4 ];

b[ 0 ] = '0';
b[ 1 ] = '0';
b[ 2 ] = '0';
b[ 3 ] = '0';

if( *src == '[' ) ++src; /* strip parens */
else error( '[', src );

while( *src ) {
switch( *src++ ) {

case 'c' : b[ 0 ] = '1';
break;

case 'm' : b[ 1 ] = '1';
break;

case 'f' : b[ 2 ] = '1';
break;

case 'i' : b[ 3 ] = '1';
}

if( *src++ == ']' ) break;
}
*dst++ = b[ 0 ];
*dst++ = b[ 1 ];
*dst++ = b[ 2 ];
*dst = b[ 3 ];
}

/* put uwb bits into instruction */

uwbbits( src, dst )
char *src, *dst;
{
char b[ 3 ];

b[ 0 ] = '0'; /* default = forward */
b[ 1 ] = '0'; /* default = neither */
b[ 2 ] = '0';

while( *src ) {
switch( *src++ ) {

case 'b' : b[ 2 ] = '1'; /* backward */
break;

case 'u' : b[ 0 ] = '1'; /* until match */
b[ 1 ] = '1';
break;

case 'w' : b[ 0 ] = '0'; /* while match */
b[ 1 ] = '1';
}
}
*dst++ = b[ 0 ];
*dst++ = b[ 1 ];
*dst = b[ 2 ];
}

/* Check to see if the word begins an equate, and if it
does, add the symbol to the symbol table. */

int isequate( w )
char *w;
{
char tempword[ 128 ];
char *q, *cpystr();

long int l, getarg();

q = cpystr( w, &tempword[ 0 ] );

gword(); /* get next word */

if( strcmp( word, "equ" ) == 0 ||
strcmp( word, "=" ) == 0 ) {
l = getarg(); /* get argument */

addsymbol( &tempword[ 0 ], l );

return 1; /* it was an equate */
}

return 0; /* we lost a word */
}

/* Get an argument value (for use above). */

long int getarg()
{
long int value();

gword(); /* get next word */
return value( word );
}

/* copy string and return new ending address */

char *cpystr( src, dst )
char *src, *dst;
{
while( *src ) *dst++ = *src++;
*dst++ = '\0'; /* terminate copied string */
return dst; /* return next address */
}

/* Calculate the value of a word. It may be a symbol, a
constant, or a computed value (must be enclosed in
parentheses.) */

long int value( w )
char *w;
{
long int hexbin(), octbin(), bitbin(), decbin(), v;
int lookup(), i, negate;

char *q;

char *wp[ 16 ];
int wpcnt;

negate = 0;

if( *w == '-' ) { /* Unary negation */
negate = 1;
++w;
}

if( strcmp( w, "." ) == 0 )
return codadr; /* . = code address */
if( strcmp( w, ".." ) == 0 )
return asmadr; /* .. = assembly address */

if( isdigit( *w )) {
if( match( w, "*h" )) v = hexbin( w );
else if( match( w, "*q" )) v = octbin( w );
else if( match( w, "*b" ))
v = bitbin( w );
else v = decbin( w );
} else {

if( *w == '(' ) { /* --- FORMULA --- */
++w; /* skip ( */
q = w;
while( *q ) ++q; /* find end of string */
--q;
if( *q != ')' ) error( ')', q );
else *q = '\0'; /* zap ) */

iwparen = 0; /* no parens now */

wpcnt = 0;

while( 1 ) { /* find beg of word */
while( inword( *w )) ++w;

if( ! *w ) break;

wp[ wpcnt++ ] = w; /* ptr to value */

iwparen = 0; /* find end of word */
while( *w && ! inword( *w )) ++w;
if( ! *w ) break;
*w++ = '\0'; /* terminate it */

if( wpcnt == 16 ) {
error( 'l', w ); /* too long */
break;
}
}

if(( wpcnt % 2 ) == 0 ) {
error( 'v', w ); /* must be odd */
--wpcnt;
}

v = value( wp[ 0 ] );

for( i = 1; i < wpcnt; i += 2 ) {
if( strcmp( wp[ i ], "+" ) == 0 ) {
v += value( wp[ i + 1 ] );
goto opdone;
}
if( strcmp( wp[ i ], "-" ) == 0 ) {
v -= value( wp[ i + 1 ] );
goto opdone;
}
if( strcmp( wp[ i ], "*" ) == 0 ) {
v *= value( wp[ i + 1 ] );
goto opdone;
}
if( strcmp( wp[ i ], "/" ) == 0 ) {
v /= value( wp[ i + 1 ] );
goto opdone;
}
error( 'o', wp[ i ] ); /* unknown op */
opdone:
i = i; /* get around c/80 bug */
}

} else { /* --- PLAIN VALUE --- */

i = lookup( w ); /* look up symbol */
if( i < 0 ) return 0; /* unknown symbol */
v = symbol[ i ].sval; /* return sym value */
}
}

if( negate ) v = 0 - v;

return v;
}

/* function for value() */

int inword( c )
char c;
{
if( c == '(' ) ++iwparen; /* special var for this */
if( c == ')' ) --iwparen; /* function */

if( iwparen ) return 0;

if( c == ' ' ) return 1; /* is space */

return 0;
}

/* --- SYMBOL TABLE LOGIC --- */

/* add new symbol to symbol table */

addsymbol( p, v )
char *p;
long int v;
{
char *w, *cpystr(), *alloc();
int i, lookup();

i = lookup( p ); /* see if already known */

if( i < 0 ) { /* new symbol */
i = symcnt;
++symcnt; /* count a new symbol */

symbol[ i ].snam = alloc( strlen( p ) + 1 );
w = cpystr( p, symbol[ i ].snam );
}

symbol[ i ].sval = v; /* update value in table */
}

/* lookup - returns symbol number or -1 if not found */

int lookup( p )
char *p;
{
char *w;
int i, j, k, found;

found = 0; /* not found yet */

/* pass 1 - use linear search */

if( pass == 1 ) {
for( i = 0; i < symcnt && ! found; ++i ) {
w = symbol[ i ].snam;
found = ( strcmp( p, w ) == 0 );
}
} else {

/* passes 2 and 3 - use binary search */

j = ( symcnt + 1 ) / 4; /* step to use */
i = symcnt / 2; /* starting point */
k = j + 1; /* one-step count */

while( 1 ) {
w = symbol[ i ].snam;
found = strcmp( p, w );
if( found == 0 ) {
found = 1;
break;
} else if( found < 0 ) i -= j;
else i += j;

if( i < 0 ) i = 0;
if( i >= symcnt ) i = symcnt - 1;

j /= 2; /* halve step */

if( j == 0 ) {
if( k-- == 0 ) {
found = 0; /* not found */
break;
}
j = 1;
}
}
}

if( ! found ) {
if( pass != 1 ) error( 'u', w );
return -1;
}

return i;
}

/* display error code */

error( c, p )
char c;
char *p;
{
puts( "\n>>---> Error " );
putchar( c );
puts( " at " );
puts( p );

++errors;
}

/* sort symbols by shell sort */

sortsyms()
{
int jump, done, k, l;
char *n;
long int v;

jump = symcnt; /* set jmp to cnt of elements */

while( jump > 0 ) {
jump = jump / 2;

while( 1 ) {
done = 1;
for( k = 0; k < ( symcnt - jump ); ++k ) {
l = k + jump;
if( strcmp( symbol[ k ].snam,
symbol[ l ].snam ) > 0 ) {
n = symbol[ k ].snam;
v = symbol[ k ].sval;
symbol[ k ].snam = symbol[ l ].snam;
symbol[ k ].sval = symbol[ l ].sval;
symbol[ l ].snam = n;
symbol[ l ].sval = v;
done = 0;
}
}
if( done ) break;
}
}
}

/* dump symbol table */

dumpsyms()
{
char *w;
int i;
long int v;

puts( "\nSymbol and Value\n" );

for( i = 0; i < symcnt; ++i ) {
puts( symbol[ i ].snam );
puts( " = " );
v = symbol[ i ].sval;
puthex( v >> 24, 0 );
puthex(( v >> 16 ) & 0xFF, 0 );
puthex(( v >> 8 ) & 0xFF, 0 );
puthex( v & 0xFF, 0 ); /* print value */
putchar( '\n' );
}
}

/* Match string. If match, returns 1; else returns 0.
Ambiguous values from the matches are saved and
pointed to by the array of char pointers ambig[], so
they can be checked later. */

int match( w1, w2 )
char *w1, *w2;
{
char c;
char *next_ambig;

next_ambig = &ambig_buffer[ 0 ]; /* init ambig buff */
ambcnt = 0; /* ambigs so far */

while( *w1 ) {
c = *w2++;
if( c == '*' ) {
ambig[ ambcnt++ ] = next_ambig;
while( *w1 && *w1 != *w2 )
*next_ambig++ = *w1++;
if( ! *w1 && *w2 ) return 0;
*next_ambig++ = '\0'; /* terminate this ambig */
} else if( c == '?' ) {
ambig[ ambcnt++ ] = next_ambig;
*next_ambig++ = *w1++; /* 1-char ambig */
*next_ambig++ = '\0'; /* terminate it */
} else if( c != *w1++ ) return 0;
}
return 1;
}

int gword()
{
char *p, *q;
char c, gchar();

p = &word_buffer[ 0 ];

c = ' ';

while( isdelim( c )) c = gchar();

while( ! isdelim( c )) {
*p++ = tolower( c );
c = gchar();
}

*p = '\0'; /* terminate word */

word = &word_buffer[ 0 ];

return 1;
}

/* is the character a delimeter? */

isdelim( c )
char c;
{
if( paren || quote || brack )
return 0; /* not a delim */

if( c == ' ' || c == ',' || c == ';' || c == '\n' \
|| c == '\r' || c == '\t' )
return 1;
return 0;
}

/* get next char from source file */

char gchar()
{
char c, getch();

c = getch(); /* get char from file */

if( c == '\'' ) quote = ! quote;
if( c == '"' ) quote = ! quote;
if( c == '(' ) ++paren;
if( c == ')' ) --paren;
if( c == '[' ) ++brack;
if( c == ']' ) --brack;

if( ! quote && ! paren && ! brack ) {

while( c == ';' ) { /* ;comment\n */
while( getch() != '\n' ) ;
c = getch();
}
}

return c;
}

puts( p )
char *p;
{
while( *p ) putchar( *p++ );
}

/* --- source file routines --- */

char getch()
{
while( inpcnt == 0 ) { /* if input buf empty, */
listpr(); /* print listing line */
inpload(); /* reload input buffer */
}

--inpcnt;
return( inpbuf[ inpptr++ ] );
}

inpload()
{
char c, getc();

inpcnt = 0;
inpptr = 0;

while((( c = getc( fasm )) != '\n' ) && ( c != EOF )) {
inpbuf[ inpcnt++ ] = c;
if( listcp < 81 ) listline[ listcp++ ] = c;
}

inpbuf[ inpcnt++ ] = '\n';
}

/* --- listing file routines --- */

listnl() /* list new line */
{
int i;

if( pass != 3 ) return;

for( i = 0; i < 26; ++i ) listline[ i ] = ' ';
for( i = 26; i < 81; ++i ) listline[ i ] = '\0';

listop = 0; /* flag to cause addr output */
listcp = 26;
}

lbyt( b ) /* put object byte in list file */
unsigned int b;
{
char c;

if( pass != 3 ) return;

c = (( b / 16 ) % 16 ) + '0';
if( c > '9' ) c += ( 'a' - ':' );
listline[ listop++ ] = c;

c = ( b % 16 ) + '0';
if( c > '9' ) c += ( 'a' - ':' );
listline[ listop++ ] = c;

if( listop > 24 ) listpr(); /* print list line */
}

listpr() /* print list line */
{
if( pass != 3 ) return;

putchar( '\n' );
puts( listline );
listnl();
}

/* --- object file routines --- */

objout( c )
char c;
{
asmadr++; /* incr asmadr, codadr. DON'T incr*/
codadr++; /* objadr, it is addr of 1st byte */
if( pass != 3 ) return; /* skip if not last pass */
objbuf[ objcnt++ ] = c; /* put new byte in buffer */
if( objcnt == 32 ) objflush();

if( listop == 0 ) { /* print address? */
lbyt( asmadr / 16777216 );
lbyt(( asmadr / 65536 ) % 256 );
lbyt(( asmadr / 256 ) % 256 );
lbyt( asmadr % 256 );
listop = 9;
}
lbyt( c ); /* send byte to listing too */
}

objflush()
{
int i, cksum;

if( pass != 3 ) return; /* just in case we get here */

cksum = 0;

if( objcnt > 0 ) {
putc( ':', fobj );
puthex( objcnt, fobj );
puthex( objadr / 256, fobj );
puthex( objadr % 256, fobj );
puthex( 0, fobj );
cksum =
objcnt + ( objadr / 256 ) + ( objadr % 256 );
for( i = 0; i < objcnt; ++i ) {
puthex( objbuf[ i ], fobj );
cksum += objbuf[ i ];
}
puthex( 0 - cksum, fobj );
putc( '\n', fobj );
}

objadr = asmadr;
objcnt = 0;}

puthex( b, c )
int b, c;
{
int v;

v = ( b & 0x00F0 ) >> 4;
if( v > 9 ) v += 'A' - 10; else v += '0';
putc( v, c );
v = ( b & 0x000F );
if( v > 9 ) v += 'A' - 10; else v += '0';
putc( v, c );
}

long int hexbin( p )
char *p;
{
long int v;

v = 0;

while( *p ) {
if( isdigit( *p )) v = ( 16 * v ) + *p++ - '0';
else if( *p >= 'a' && *p <= 'f' )
v = ( 16 * v ) + *p++ - 'a' + 10;
else ++p;
}

return v;
}

long int octbin( p )
char *p;
{
long int v;

v = 0;

while( *p ) {
if( *p >= '0' && *p <= '7' )
v = ( 8 * v ) + *p++ - '0';
else ++p;
}
return v;
}

long int bitbin( p )
char *p;
{
long int v;

v = 0;

while( *p ) {
if( *p == '0' || *p == '1' )
v = ( 2 * v ) + *p++ - '0';
else ++p;
}
return v;
}

long int decbin( p )
char *p;
{
long int v;

v = 0;

while( *p ) {
if( isdigit( *p )) v = ( 10 * v ) + *p++ - '0';
else ++p;
}
return v;
}

#include "stdlib.c"