home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
405.lha
/
Z8_CrossAsm
/
z8ca1.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-06-05
|
34KB
|
1,739 lines
/* z8 Cross Assembler for Commodore Amiga.
Written by: Bob Bush (Compuserve-73105,1332) 14-Apr-1989
Copyright (C) 1989 R.Bush. All rights reserved.
This program is freely distributable as long as this copyright notice
is retained. It intended for personal, non-commercial use.
Brief Syntax notes:
R0 thru R15 always refer to working register set.
All other registers are addressed with the colon opertor eg.
ld r:$ff,#1 ;load absolute register 255 with a '1'
ld r:2,#0 ;load absolute register 2 with a '0'
Additional: If this code seems somewhat sporadic it no doubt is..
Could be due to the fact that the entire program was developed
in a few days while sitting in front of a terminal (Amiga).
This happens be my favorite method of program development <:
*/
/* Amiga note: Compiled with Lattice 'C' 4.0 lc -L -v -cw z8ca */
/* Modifications :
1) allow symbols to be case sensitive.
2) allow math operations on defs.
3) fixed bug in Intel Hex file output.
4) added sorted symbol table option.
5) enabled 'DS' pseudo op.
6) Bug fixed in 'DB' evaluation which prevented spaces after
pseudo op.
*/
#include <string.h>
#include <stdio.h>
/* #define DEBUG 1 */
struct symbol { /* symbol table entry */
struct symbol *next;
char *label;
int value;
};
#define HASHSIZE 101
struct symbol *hashtab[HASHSIZE];
struct symbol **spoint;
struct def { /* entry for a define */
struct def *next;
char *label;
char *substitute;
};
struct def *deftab[HASHSIZE];
struct optable {
int dest; /* valid operand for destination argument */
int source; /* valid operand for source argument */
int numbytes; /* number of bytes generated for this opcode */
int opcode; /* the primary opcode byte */
int opr1; /* formation rules for second byte */
int opr2; /* formation rules for third byte */
};
/* argument sub classification (8bit reg specification as working reg) */
#define WORKING 1
/* opcode formation rules for second and/or third bytes (used in optable) */
#define DESTSL4_OR_SOURCE 1
#define OPCODE_OR_DESTSL4 2
#define ZSOURCE 3
#define ZDEST 4
#define DATA8 5
#define OPCODE_OR_SOURCESL4 6
#define CC_OR_OP 7
#define RELATIVE 8
#define SOURCESL4_OR_DEST 9
/* operand address mode descriptors used in (optable) */
#define R4 1 /* working register 4 bit descriptor */
#define R8 2 /* 8 bit register */
#define IR4 3 /* indirect working register - 4 bits only */
#define IR8 4 /* indirect register - 8 bits */
#define IRR4 5 /* indirect working register pair */
#define IRR8 6 /* indirect register pair */
#define XX 7 /* indexed address */
#define RR8 9 /* register pair */
#define IM8 10 /* immediate 8-bit data */
#define DA 11 /* direct 16-bit address */
#define IMP 12 /* implied operand */
#define RR4 13 /* working register pair */
#define CC 14 /* condition code */
#define RA 15 /* relative address */
/* syntax descriptions for opcode (used in syntax structure) */
#define DEST_SOURCE 1 /* standard (dest,source) format */
#define DEST_ONLY 2 /* standard (dest) format */
#define IMPLIED 3 /* implied operand (eg. NOP) */
#define CREATE_JR 4 /* jump relative (eg JR NZ,DEST) */
#define CREATE_DJ 5 /* djnz */
#define CREATE_JP 6 /* cc jump */
#include "optab.h"
struct pseudo {
char *mne; /* ascii mneumonic */
};
struct pseudo ps[] = {
"Invalid",
"ORG",
"DB",
"DW",
"DS",
"EQU",
"DEF"
};
#define PSSIZE sizeof(ps) / sizeof(ps[0])
struct cc_code {
char *mne;
int cc_value;
};
/* note: hi nibble is the condition code */
struct cc_code cc[] = {
"C",0x70,
"NC",0xf0,
"Z",0x60,
"NZ",0xe0,
"PL",0xd0,
"MI",0x50,
"OV",0x40,
"NOV",0xc0,
"EQ",0x60,
"NE",0xe0,
"GE",0x90,
"LT",0x10,
"GT",0xa0,
"LE",0x20,
"UGE",0xf0,
"ULT",0x70,
"UGT",0xb0,
"ULE",0x30
};
#define CCSIZE sizeof (cc) / sizeof(cc[0])
char *args[] = {
" ",
" ",
" ",
" ",
" ",
" ",
};
char cur_sym[40];
char fbuff[101];
char dbuff[101];
int pc;
unsigned char bincode[25];
int bincode_index = 0;
unsigned char bin_line[128];
int bin_pc = 0;
int bindex = 0;
unsigned char checksum = 0;
int syntax_index;
int arg_val,arg_type,arg_subclass;
int arg1_val,arg1_type,arg1_subclass;
int arg2_val,arg2_type,arg2_subclass;
int radix;
int pcinc;
char *curline;
int pass;
unsigned char code_line[8];
int code_line_index;
int line_no;
int bytes_generated;
struct symbol *lookup();
struct def *lookup_def();
struct def *lookup_def1();
int special_def;
int sym_cmp();
int nsyms = 0;
int sym_list = 0; /* default no symbol table listing */
FILE *fpin = NULL;
FILE *fpout = NULL;
char out_fname[64];
char in_fname[64];
int listdb;
int list_on;
int fout_type;
/* .hex file types */
#define MOTOROLA 1
#define INTEL 2
#define Z8 3
char *parse_line;
main(argc,argv)
int argc;
char *argv[];
{
int j;
printf("\n\11z8 Cross Assembler Ver. 1.2\n");
strcpy(in_fname,argv[1]);
strcat(in_fname,".asm");
if(!(fpin = fopen(in_fname,"r")))
errexit2("Can't open input file");
strcpy(out_fname,argv[1]);
strcat(out_fname,".hex");
fout_type = MOTOROLA;
list_on = 0;
if(argc > 2)
for(j = 2; j < argc; j++)
sel_opt(argv[j]);
bytes_generated = 0;listdb = 1;
pass = 1; line_no = 1; pc = 0;
printf("Pass 1:\n");
while(fgets(fbuff,100,fpin)) {
strcpy(dbuff,fbuff);
/* strupr_esc(fbuff); */
curline = fbuff; /* establish current line pointer */
code_line_index = 0; pcinc = 0;
evaluate();
line_no++;
}
fclose(fpin); /* end of pass #1 */
pass = 2; line_no = 1; pc = 0;bytes_generated = 0;
printf("Pass 2:\n");
if(!(fpin = fopen(in_fname,"r")))
errexit2("Can't re-open input file");
if(!(fpout = fopen(out_fname,"w")))
errexit2("Can't open output file");
while(fgets(fbuff,100,fpin)) {
strcpy(dbuff,fbuff); /* save un-altered copy of source code */
/* strupr_esc(fbuff); convert to upper case */
curline = fbuff; /* establish current line pointer */
code_line_index = 0; pcinc = 0;
evaluate(); /* grunt out some code */
line_no++;
}
fclose(fpin);
if(fout_type == Z8)
fprintf(fpout,"+\n"); /* terminate for z8 Basic loader */
else
if(fout_type == MOTOROLA)
end_m();
else
end_i(); /* INTEL */
fclose(fpout);
printf("\n\11Assembly Complete..\n");
printf("\11%d Bytes Generated.\n",bytes_generated);
list_symbols();
}
errexit2(s) /* fatal (any:>) error exit */
char *s;
{
if(fpin)
fclose(fpin);
if(fpout)
fclose(fpout);
printf("\n ** Fatal Error ** at line # %d\n",line_no);
printf("%s",dbuff);
printf("%s\n",s);
printf("Assembly Terminated\n");
exit(0);
}
sel_opt(s)
char *s;
{
if(*s++ == '-') {
switch(*s) {
case 'l': list_on = 1;
break;
case 'z': fout_type = Z8;
break;
case 'm': fout_type = MOTOROLA;
break;
case 'i': fout_type = INTEL;
break;
case 's': sym_list = 1;
break;
default: errexit2("Invalid assembler option");
break;
}
}
}
syntax_error()
{
errexit2("Syntax Error .. Unable to evaluate..");
}
strupr_esc(buff)
char *buff;
{
while(*buff) {
if(*buff == '\'') {
buff++;
while(*buff){
if(*buff == '\'')
break;
else
buff++;
}
}
if(*buff) {
*buff = toupper(*buff); *buff++; }
}
}
/* primary line evaluator */
evaluate()
{
int status;
if(!(status = get_token(args[0]))) { /* get a word */
gen_line();
return(0); } /* comment -or- blank line */
if(checklabel(args[0],status)) { /* create a symbol if required */
if(pass == 1) {
create_symbol(args[0],pc);
strcpy(cur_sym,args[0]);
}
if(!(status = get_token(args[0]))) { /* get a word */
gen_line();
return(0); } /* comment -or- blank line */
}
/* check_defs here would allow user to create own instruction mne's */
/* check_defs(args[0]); */
syntax_index = scankey(args[0]); /* lookup mneumonic keyword */
if(syntax_index) {
get_token(args[1]); get_token(args[2]);
check_defs(args[1]); check_defs(args[2]); /* check for subs. */
switch(z8[syntax_index].opr_type) {
case DEST_SOURCE:
if(create_ds())
gen_line();
else
syntax_error();
break;
case DEST_ONLY:
if(create_d())
gen_line();
else
syntax_error();
break;
case IMPLIED:
if(create_i())
gen_line();
else
syntax_error();
break;
case CREATE_JR:
if(create_jr())
gen_line();
else
syntax_error();
break;
case CREATE_DJ:
if(create_dj())
gen_line();
else
syntax_error();
break;
case CREATE_JP:
if(create_jp())
gen_line();
else
syntax_error();
break;
}
}
else /* scan for pseudo op */
if((syntax_index = scan_pse(args[0])))
eval_pse(syntax_index);
else {
printf("Syntax error, %s is not a valid opcode or pseudo op\n",args[0]);
errexit2("** syntax **");
}
}
/* check for define substitutions, if found replace string */
check_defs(s)
char *s;
{
struct def *dp;
if(*s) {
if(!(dp = lookup_def(s)))
return(0);
else
if(special_def) {
strcpy(s,dp->substitute);
strcat(s,args[5]);
}
else
strcpy(s,dp->substitute);
}
}
/* evaluate a pseudo op */
eval_pse(ps_num)
int ps_num;
{
int equ_val,do_gen;
struct symbol *sp;
pcinc = 0;do_gen = 1;
switch(ps_num) {
case 1: /* org */
get_token(args[1]);
pc = eval(args[1]);
if(pass == 2) {
switch(fout_type) {
case Z8:
fprintf(fpout,"%%%x\n",pc);
break;
case MOTOROLA:
flush_m();
bin_pc = pc;
break;
case INTEL:
flush_i();
bin_pc = pc;
break;
}
}
break;
case 2: /* db */
get_db();
do_gen = 0;
break;
case 3: /* dw */
get_dw();
do_gen = 0;
break;
case 4: /* ds */
get_token(args[1]);
gen_line();
do_gen = 0;
pc+= eval(args[1]);
break;
case 5: /* equ */
if(pass == 1) { /* only do this on pass #1... */
get_token(args[1]);
equ_val = eval(args[1]);
if((sp = lookup(cur_sym)))
sp->value = equ_val;
else
printf("can't find symbol for equate \n");
}
break;
case 6: /* def */
if(pass == 1) {
get_token(args[1]); get_token(args[2]);
create_def(args[1],args[2]);
}
break;
}
if(do_gen)
gen_line();
}
/* generate listing on pass #2 */
gen_line()
{
int j;
if (pass == 2 && list_on) {
printf("%04x ",pc);
for(j=0;j<code_line_index;j++)
printf("%02x ",code_line[j]);
if(listdb)
otext(dbuff,pcinc);
else
printf("\n");
}
pc+= pcinc;
}
otext(buff,num)
char *buff;
int num;
{
switch(num) {
case 0: printf(" %s",buff);
break;
case 1: printf(" %s",buff);
break;
case 2: printf(" %s",buff);
break;
case 3: printf(" %s",buff);
}
}
/* create a dest,source type code */
create_ds()
{
int stat,j;
if(is_in(args[1],'(') || is_in(args[2],'(')) {
create_idx();
return(1);
}
stat = get_any(args[1]);
if(stat) {
arg1_val = arg_val; arg1_type = arg_type;
arg1_subclass = arg_subclass;
}
else {
printf("Eval 1 failed\n");
return(0);
}
stat = get_any(args[2]);
if(stat) {
arg2_val = arg_val; arg2_type = arg_type;
arg2_subclass = arg_subclass;
}
else {
printf("Eval 2 failed\n");
return(0);
}
/* check for standard argument set */
j = 0;
while(z8[syntax_index].otab[j].dest) {
if((arg1_type == z8[syntax_index].otab[j].dest) &&
(arg2_type == z8[syntax_index].otab[j].source)) {
build_code(z8[syntax_index].otab,j);
return(1);
}
j++;
}
/* check extended argument set #2 */
convert_arg2(); /* convert 4bit args to 8bit args */
j = 0;
while(z8[syntax_index].otab[j].dest) {
if((arg1_type == z8[syntax_index].otab[j].dest) &&
(arg2_type == z8[syntax_index].otab[j].source)) {
build_code(z8[syntax_index].otab,j);
return(1);
}
j++;
}
/* check extended argument set #1 */
convert_arg1(); /* convert 4bit args to 8bit args */
j = 0;
while(z8[syntax_index].otab[j].dest) {
if((arg1_type == z8[syntax_index].otab[j].dest) &&
(arg2_type == z8[syntax_index].otab[j].source)) {
build_code(z8[syntax_index].otab,j);
return(1);
}
j++;
}
/* syntax format not available for this opcode */
return(0);
}
/* convert 4bit arg to 8bit arg */
convert_arg1()
{
switch(arg1_type) {
case R4: arg1_type = R8;
break;
case IR4: arg1_type = IR8;
break;
case IRR4: arg1_type = IRR8;
break;
case RR4: arg1_type = RR8;
break;
}
}
/* convert 4bit arg to 8bit arg */
convert_arg2()
{
switch(arg2_type) {
case R4: arg2_type = R8;
break;
case IR4: arg2_type = IR8;
break;
case IRR4: arg2_type = IRR8;
break;
case RR4: arg2_type = RR8;
break;
}
}
/* create code for destination only type */
create_d()
{
int stat,j;
stat = get_any(args[1]);
if(stat) {
arg1_val = arg_val; arg1_type = arg_type;
arg1_subclass = arg_subclass;
}
else {
printf("Eval 1 failed\n");
return(0);
}
j = 0;
while(z8[syntax_index].otab[j].dest) {
if((arg1_type == z8[syntax_index].otab[j].dest)) {
build_code(z8[syntax_index].otab,j);
return(1);
}
j++;
}
/* check extended argument set #1 */
convert_arg1();
j = 0;
while(z8[syntax_index].otab[j].dest) {
if((arg1_type == z8[syntax_index].otab[j].dest)) {
build_code(z8[syntax_index].otab,j);
return(1);
}
j++;
}
return(0);
}
/* create code for implied op */
create_i()
{
build_code(z8[syntax_index].otab,0);
return(1);
}
/* build actual code via table entry */
build_code(optab,j)
struct optable optab[];
int j;
{
pcinc = optab[j].numbytes;
switch(optab[j].numbytes) {
case 1: switch(optab[j].opr1) {
case OPCODE_OR_DESTSL4:
generate((arg1_val<<4) | optab[j].opcode);
break;
default:
generate(optab[j].opcode);
break;
}
break;
case 2: switch(optab[j].opr1) {
case DESTSL4_OR_SOURCE:
generate(optab[j].opcode);
generate((arg1_val<<4) | arg2_val);
break;
case ZDEST:
generate(optab[j].opcode);
if(arg1_subclass == WORKING)
generate(0xe0 | arg1_val);
else
generate(arg1_val);
break;
case OPCODE_OR_SOURCESL4:
generate((arg2_val << 4) | optab[j].opcode);
generate(arg1_val);
break;
case OPCODE_OR_DESTSL4:
generate((arg1_val<<4) | optab[j].opcode);
if(arg2_subclass == WORKING)
generate(0xe0 | arg2_val);
else
generate(arg2_val);
break;
case SOURCESL4_OR_DEST:
generate(optab[j].opcode);
generate((arg2_val<<4) | arg1_val);
break;
}
break;
case 3: generate(optab[j].opcode);
switch(optab[j].opr1) {
case ZSOURCE:
if(arg2_subclass == WORKING)
generate(0xe0 | arg2_val);
else
generate(arg2_val);
break;
case ZDEST:
if(arg1_subclass == WORKING)
generate(0xe0 | arg1_val);
else {
if(optab[j].dest == DA) { /* 16 bit addr */
generate(arg1_val >> 8); /* hi byte */
generate(arg1_val & 0xff); /* lo byte */
}
else
generate(arg1_val);
}
break;
}
if(optab[j].opr2) {
switch(optab[j].opr2) {
case ZSOURCE:
if(arg2_subclass == WORKING)
generate(0xe0 | arg2_val);
else
generate(arg2_val);
break;
case ZDEST:
if(arg1_subclass == WORKING)
generate(0xe0 | arg1_val);
else
generate(arg1_val);
break;
}
}
break;
}
}
/* a hack for indexed mode addressing */
create_idx()
{
int ix_op,src,rindex,dest;
char *temp;
if(pass == 1) {
pcinc = 3; /* assume all ok for pass #1 */
return(1);
}
pcinc = 3;
if(is_in(args[1],'(')) {
ix_op = 0xd7; /* dest is indexed */
temp = args[1];
while((*temp++ != '(')); /* get pointer to index register */
get_any(args[1]); /* get base register, must be r8 */
if(arg_type != R8)
errexit2("dest INDEX Base not absolute");
else
dest = arg_val;
get_any(temp); /* get index register */
if(arg_type != R4)
errexit2("dest INDEX must be working reg.");
else
rindex = arg_val;
get_any(args[2]);
if(arg_type != R4)
errexit2("source must be working reg.");
else
src = arg_val;
generate(ix_op);
generate((src << 4) | rindex);
generate(dest);
return(1);
}
else {
if(is_in(args[2],'('))
ix_op = 0xc7; /* dest is r4 */
else
errexit2("Invalid index mode!");
temp = args[2];
while((*temp++ != '(')); /* get pointer to index register */
get_any(args[1]); /* get dest register, must be r4 */
if(arg_type != R4)
errexit2("dest must be working reg.");
else
dest = arg_val;
get_any(args[2]); /* get base register, must be r8 */
if(arg_type != R8)
errexit2("source INDEX Base not absolute");
else
src = arg_val;
get_any(temp); /* get index register */
if(arg_type != R4)
errexit2("source INDEX must be working reg.");
else
rindex = arg_val;
generate(ix_op);
generate((dest << 4) | rindex);
generate(src);
return(1);
}
}
is_in(s,c)
char *s;
char c;
{
while(*s) {
if(*s == c)
return(1);
s++;
}
return(0);
}
create_jr()
{
int cc_code,cc_disp,cc_op;
int cc_addr;
if(pass == 1) { /* assume everything ok */
pcinc = 2;
return(1);
}
cc_op = 0x0b;
if(isnull(args[2])) {
cc_code = 0x80;
cc_addr = eval(args[1]); /* will bomb if can't evaluate */
}
else {
cc_addr = eval(args[2]);
if(!(cc_code = find_cc_code(args[1])))
errexit2("Condition code invalid!!");
}
cc_disp = compute_relative(cc_addr,pc);
if((cc_disp > 127) | (cc_disp < -128))
errexit2("Relative branch out of range!!");
pcinc = 2;
generate(cc_op | cc_code);
generate(cc_disp & 0xff);
return(1);
}
/* create jp cc,dest */
create_jp()
{
int cc_code,cc_op;
int cc_addr;
if(pass == 1) { /* assume everything ok */
get_any(args[1]);
if(arg_type == IR4 || arg_type == IR8)
pcinc = 2;
else
pcinc = 3;
return(1);
}
if(isnull(args[2])) {
get_any(args[1]);
if(arg_type == IR4) {
cc_op = 0x30;
cc_addr = 0xe0 | arg_val;
generate(cc_op);
generate(cc_addr);
pcinc = 2;
return(1);
}
else
if(arg_type == IR8) {
cc_op = 0x30;
generate(cc_op);
generate(arg_val);
pcinc = 2;
return(1);
}
else
cc_code = 0x80;
cc_addr = eval(args[1]); /* will bomb if can't evaluate */
}
else {
cc_addr = eval(args[2]);
if(!(cc_code = find_cc_code(args[1])))
errexit2("Condition code invalid!!");
}
pcinc = 3;
cc_op = 0x0d;
generate(cc_op | cc_code);
generate(cc_addr >> 8);
generate(cc_addr & 0xff);
return(1);
}
/* create djnz code */
create_dj()
{
int dj_disp,dj_op;
int dj_addr;
if(pass == 1) { /* assume everything ok */
pcinc = 2;
return(1);
}
dj_op = 0x0a;
if(!(get_any(args[1])))
errexit2("Syntax error");
if(arg_type != R4)
errexit2("Invalid reg. spec");
dj_addr = eval(args[2]);
dj_disp = compute_relative(dj_addr,pc);
if((dj_disp > 127) | (dj_disp < -128))
errexit2("Relative branch out of range!!");
pcinc = 2;
generate((arg_val << 4) | dj_op);
generate(dj_disp & 0xff);
return(1);
}
find_cc_code(code)
char *code;
{
int j,cond;
for(j = 0; j < CCSIZE;j++) {
if((cond = stricmp(code,cc[j].mne)) == 0)
return(cc[j].cc_value);
}
return(0);
}
compute_relative(dest,apc)
int dest;
int apc;
{
apc += 2;
return(dest - apc);
}
isnull(s)
char *s;
{
if(*s)
return(0);
else
return(1);
}
generate(val)
int val;
{
code_line[code_line_index] = val;
code_line_index++;
if(pass == 2) {
switch(fout_type) {
case Z8: fprintf(fpout,"%%%02x\n",val);
break;
case MOTOROLA: mout(val);
break;
case INTEL: iout(val);
break;
}
}
bytes_generated++;
}
iout(val)
int val;
{
bin_line[bindex++] = val;
if(bindex == 32)
flush_i();
}
mout(val)
int val;
{
bin_line[bindex++] = val;
if(bindex == 32)
flush_m();
}
flush_m()
{
int j;
if(bindex) {
fprintf(fpout,"S1");
hexout(bindex+3);
checksum += bindex+3;
hexout(bin_pc >> 8);
hexout(bin_pc & 0xff);
checksum += (bin_pc>>8);
checksum += (bin_pc & 0xff);
bin_pc += bindex;
for(j = 0; j < bindex; j++) {
hexout(bin_line[j]);
checksum += bin_line[j];
}
hexout(~checksum);
fprintf(fpout,"\n");
bindex = 0; checksum = 0;
}
}
flush_i()
{
int j;
if(bindex) {
fprintf(fpout,":");
hexout(bindex);
checksum += bindex;
hexout(bin_pc >> 8);
hexout(bin_pc & 0xff);
checksum += (bin_pc>>8);
checksum += (bin_pc & 0xff);
hexout(0);
checksum += 0;
bin_pc += bindex;
for(j = 0; j < bindex; j++) {
hexout(bin_line[j]);
checksum += bin_line[j];
}
hexout(~checksum+1);
fprintf(fpout,"\n");
bindex = 0; checksum = 0;
}
}
end_m()
{
flush_m();
fprintf(fpout,"S9030000FC\n");
}
end_i()
{
flush_i();
fprintf(fpout,":00000001FF\n");
}
char *hexstr = { "0123456789ABCDEF" } ;
hexout(byte)
int byte;
{
byte = byte & 0xff;
fprintf(fpout,"%c%c",hexstr[byte>>4],hexstr[byte&017]);
}
get_any(st)
char *st;
{
int tempn1;
arg_subclass = 0;
if(strnicmp(st,"@RR",3)== 0) { /* indirect register pair */
if(st[3] == ':') {
tempn1 = eval(&st[4]);
if((tempn1 >= 0) && (tempn1 < 256)) {
arg_val = tempn1; arg_type = IRR8;
return(1);
}
}
else {
tempn1 = eval(&st[3]);
if((tempn1 >= 0) && (tempn1 < 16)) {
arg_val = tempn1; arg_type = IRR4;
arg_subclass = WORKING;
return(1);
}
else
return(0);
}
}
if(strnicmp(st,"RR",2)== 0) { /* register pair */
if(st[2] == ':') {
tempn1 = eval(&st[3]);
if((tempn1 >= 0) && (tempn1 < 256)) {
arg_val = tempn1; arg_type = RR8;
return(1);
}
}
else {
tempn1 = eval(&st[2]);
if((tempn1 >= 0) && (tempn1 < 16)) {
arg_val = tempn1; arg_type = RR4;
arg_subclass = WORKING;
return(1);
}
else
return(0);
}
}
if(strnicmp(st,"@R",2)== 0) { /* indirect reg specifier */
if(st[2] == ':') {
tempn1 = eval(&st[3]);
if((tempn1 >= 0) && (tempn1 < 256)) {
arg_val = tempn1; arg_type = IR8;
return(1);
}
}
else {
tempn1 = eval(&st[2]);
if((tempn1 >= 0) && (tempn1 < 16)) {
arg_val = tempn1; arg_type = IR4;
arg_subclass = WORKING;
return(1);
}
else
return(0);
}
}
if((st[0] == 'R') || st[0] == ('r')) {
if(st[1] == ':') {
tempn1 = eval(&st[2]);
if((tempn1 >= 0) && (tempn1 < 256)) {
arg_val = tempn1; arg_type = R8;
return(1);
}
}
else {
tempn1 = eval(&st[1]);
if((tempn1 >= 0) && (tempn1 < 16)) {
arg_val = tempn1; arg_type = R4;
arg_subclass = WORKING;
return(1);
}
else
return(0);
}
}
if(st[0] == '#') {
tempn1 = eval(&st[1]);
if((tempn1 >= 0) && (tempn1 < 256)) {
arg_val = tempn1; arg_type = IM8;
return(1);
}
else
return(0);
}
if(st[0]) {
tempn1 = eval(&st[0]);
if((tempn1 >= 0) && (tempn1 < 65536)) {
arg_val = tempn1; arg_type = DA;
return(1);
}
else
return(0);
}
return(0);
}
/* scans a passed string for keyword and return index */
scankey(word)
char *word;
{
int j,cond;
for(j = 1; j < Z8SIZE; j++) {
if((cond = stricmp(word,z8[j].mne)) == 0) {
return(j);
}
}
return(0);
}
/* scans a passed string for pseudo-op keyword and return index */
scan_pse(word)
char *word;
{
int j,cond;
for(j = 1; j < PSSIZE; j++) {
if((cond = stricmp(word,ps[j].mne)) == 0) {
return(j);
}
}
return(0);
}
checklabel(s,c)
char *s;
int c;
{
if(s[c-1] == ':') {
s[c-1] = '\0';
return(1);
}
else
return(0);
}
/* process define word */
get_dw()
{
int result;
while((get_token(args[1]))) {
result = eval(args[1]);
generate(result>>8);
generate(result & 0xff);
pcinc+=2;
gen_line();
pcinc = 0;code_line_index = 0;
listdb = 0; /* turn off line listing */
}
listdb = 1; /* turn back on line listing */
}
/* process define byte */
get_db()
{
char *c;
int result;
while((get_token1(args[1]))) {
c = args[1];
switch(*c) {
case '\'': /* ascii text */
c++;
while((*c) && (*c != '\'')) {
generate(*c);
pcinc++;c++;
if(pcinc == 3) {
gen_line();
pcinc = 0;code_line_index = 0;
listdb = 0;
}
}
break;
default: /* the rest */
result = eval(args[1]);
generate(result);pcinc++;
if(pcinc == 3) {
gen_line();
pcinc = 0;code_line_index = 0;
listdb = 0;
}
break;
}
}
if(pcinc) {
gen_line();
pcinc = 0;code_line_index = 0;
}
listdb = 1;
}
/* extract a token from current line and copy into 's'.
s = null string if no token is available. returns status:
status = 0 = no token extracted ,otherwise status =
number of characters in the token. */
get_token(s)
char *s;
{
int st;
st = 0;
while(isany(*curline," ,\11\12\0")) /* skip any special chars */
curline++;
while(*curline) {
if(isany(*curline," ,\11\12\0")) {
*s = '\0';
break;
}
else {
if(*curline == ';') /* handle comment here */
break;
*s++ = *curline++; st++;
}
}
*s = '\0';
return(st);
}
get_token1(s)
char *s;
{
int st;
st = 0;
while(isany(*curline," ,\11\12\0")) /* skip any special chars */
curline++;
if(*curline == '\'') { /* start of ascii text */
*s++ = *curline++; st++; }
while(*curline) {
if(isany(*curline,",\11\12\0")) {
*s = '\0';
break;
}
else {
if(*curline == ';') /* handle comment here */
break;
*s++ = *curline++; st++;
}
}
*s = '\0';
return(st);
}
isany(c,s)
char c;
char *s;
{
while(*s) {
if(*s == c)
return(1);
s++;
}
return(0);
}
/* base routines for symbol table manipulation */
unsigned int hash(s)
char *s;
{
unsigned hashval;
for(hashval = 0; *s != '\0'; *s++)
hashval = *s + 31 * hashval;
return(hashval % HASHSIZE);
}
/* lookup-- look for 's' in symbol table. returns pointer to symbol
structure -or- NULL if no match found */
struct symbol *lookup(s)
char *s;
{
struct symbol *sp;
for(sp = hashtab[hash(s)]; sp != NULL; sp = sp->next)
if(strcmp(s,sp->label) == 0)
return(sp);
return(NULL);
}
struct symbol *special_lookup(s)
char *s;
{
char *s1;
struct symbol *sp;
s1 = args[4]; /* safe temp storage area */
while(*s && (!(isany(*s,"!+-*/|&"))))
*s1++ = *s++; /* copy string */
*s1 = '\0';
sp = lookup(args[4]);
return(sp);
}
struct def *lookup_def(s)
char *s;
{
struct def *dp;
char *s1;
special_def = 0;
s1=args[4];
if(strpbrk(s,"!+-*/|&(")) {
/* printf("Special lookup of '%s'\n",s); */
while(*s && (!(isany(*s,"!+-*/|&("))))
*s1++ = *s++; /* copy string */
*s1 = '\0';
strcpy(args[5],s); /* save remainder of arg */
/* printf("Alternate lookup of '%s'\n",args[4]); */
dp = lookup_def1(args[4]);
if(dp)
special_def = 1; /* flag caller */
/* printf("Found '%s'\n",args[4]); */
return(dp);
}
else {
dp = lookup_def1(s);
/* printf("s = %s\n",s); */
return(dp);
}
}
struct def *lookup_def1(s)
char *s;
{
struct def *dp;
for(dp = deftab[hash(s)]; dp != NULL; dp = dp->next)
if(strcmp(s,dp->label) == 0)
return(dp);
return(NULL);
}
/* create symbol--- install a symbol into table */
create_symbol(name,value)
char *name;
int value;
{
struct symbol *sp;
unsigned int hashval;
if((sp = lookup(name)) == NULL) { /* not found */
sp = (struct symbol *) malloc(sizeof(*sp));
if(sp == NULL || (sp->label = (char *)strdup(name)) == NULL)
errexit2("Unable to allocte symbol table mem.");
sp->value = value;
hashval = hash(name);
sp->next = hashtab[hashval];
hashtab[hashval] = sp;
nsyms++;
}
else {
errexit2("Duplicate define");
}
return(1);
}
create_def(name,value)
char *name;
char *value;
{
struct def *dp;
unsigned int hashval;
if((dp = lookup_def(name)) == NULL) { /* not found */
dp = (struct def *) malloc(sizeof(*dp));
if(dp == NULL || (dp->label = (char *)strdup(name)) == NULL)
errexit2("Unable to alloc symbol table mem.");
if((dp->substitute = (char *)strdup(value)) == NULL)
errexit2("Unable to alloc symbol table mem.");
hashval = hash(name);
dp->next = deftab[hashval];
deftab[hashval] = dp;
}
else {
errexit2("Duplicate def");
}
return(1);
}
list_symbols()
{
int j,n;
struct symbol *sp;
if(!nsyms || !sym_list)
return(0);
if(!(spoint = (struct symbol**) malloc(sizeof(*spoint) * nsyms))) {
printf("Not enough memory for sorted symbol table\n");
return(0);
}
/* make list of all pointers to symbol entrys */
for(j=0,n=0; j < HASHSIZE;j++) {
if(hashtab[j]) {
for(sp = hashtab[j]; sp != NULL; sp = sp->next) {
spoint[n++] = sp;
}
}
}
/* sort list */
qsort(spoint,nsyms,sizeof(char *),sym_cmp);
printf("\n\nSymbol Table:\n\n");
/* print list */
for(j=0; j < nsyms;j++) {
sp = spoint[j];
printf(" %04X -- %s\n",sp->value,sp->label);
}
}
sym_cmp(a1,b1)
struct symbol *a1[],*b1[];
{
struct symbol *a,*b;
a = (struct symbol *) a1[0];
b = (struct symbol *) b1[0];
return(strnicmp(a->label,b->label,14));
}
/* Main expression evaluation.
gets the next value from parse_line buffer.
ends up pointing to next math operator or null
*/
get_exp_val()
{
struct symbol *sp;
int ret_val;
/* while((isany(*parse_line," ")))
parse_line++;
*/
if((isalpha(*parse_line))) { /* better be a label!!! */
sp = special_lookup(parse_line);
if(!sp) {
if(pass == 2)
errexit2("Undefined Label");
else {
scan_to_next_math_op();
return(0);
}
}
else {
scan_to_next_op();
if(parse_line) {
if (*parse_line == '!') { /* handle address operator */
parse_line++;
if(*parse_line == 'H' || *parse_line == 'h') {
scan_to_next_op();
return(sp->value >> 8); }
else
if(*parse_line == 'L'|| *parse_line == 'l') {
scan_to_next_op();
return(sp->value & 0xff); }
else
errexit2("Invalid address operator");
} else return(sp->value);
} else return(sp->value);
}
}
/* if we made it here we better have a constant */
if(!(isany(*parse_line,"%$'0123456789")))
errexit2("Invalid constant");
else {
ret_val = getval(parse_line);
scan_to_next_op();
return(ret_val);
}
}
scan_to_next_op()
{
while(!(isany(*parse_line,"+-*/!|&"))) {
if(*parse_line && *parse_line != ';')
parse_line++;
else {
parse_line = NULL;
return(0);
}
}
}
scan_to_next_math_op()
{
while(!(isany(*parse_line,"+-*/|&"))) {
if(*parse_line && *parse_line != ';')
parse_line++;
else {
parse_line = NULL;
return(0);
}
}
}
eval(curline) /* evaluate expression */
char *curline;
{
int left,right,operator;
left = 0;
parse_line = curline;
left = get_exp_val(); /* get leftmost operand */
while(parse_line) { /* get operator and next expression */
operator = *parse_line++;
right = get_exp_val();
switch (operator) {
case '+': left = left + right;
break;
case '-': left = left - right;
break;
case '*': left = left * right;
break;
case '/': if(right > 0)
left = left / right;
break;
case '|': left = left | right;
break;
case '&': left = left & right;
break;
}
}
return(left);
}
/* char digit connversion routines */
cvdig(ch) /* return value of digit or -1 */
char ch;
{
int z;
if((z = ch) >= '0' && z <= '9') z -= '0';
else
if((z &= 0137) >= 'A' && z <= 'F') z -= 'A' - 10;
else
return (-1);
if(z < radix)
return(z);
return (-1);
}
/* get numeric value from string, expects first char of string to
be the radix specifier. % = binary, $ = hex, @ = octal '0..9' = decimal.
returns converted value..
*/
getval(curline)
char *curline;
{
int j,n,k;
switch(*curline)
{ case '$': radix = 16; curline++; break;
case '%': radix = 2; curline++; break;
case '\'': radix = 255; curline++; break;
default: radix = 10;
}
j = 0;k = 0;
if(radix < 255) {
while(*curline) {
if((n = cvdig(*curline++)) < 0){
curline--;
break;}
j = j * radix + n;
k++;
}
}
else {
j = *curline++;
curline++;
}
return(j);
}