Files
open-simh.simtools/crossassemblers/hpasm.c

931 lines
26 KiB
C

/*
** HPASM.C -- Assembler for HP2100
*/
/****************************************************/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/****************************************************/
#define MXSYM 1500
#define MXLABEL 5
#define ALLOW_SPECIALS_IN_LABEL 1
/****************************************************/
typedef struct {
char name[MXLABEL+1];
long value;
} SYM;
/****************************************************/
long nbsyms;
SYM symtab[MXSYM];
long pass;
long addr;
char line[80];
long lp;
long line_count;
long err_count;
long print_flag; /* =1 if current line has been printed */
int ifn_flag=0; /* =1 if IFN does not skip */
int ifz_flag=0; /* =1 if IFZ does not skip */
int xif_flag=0; /* =1 if we are skipping until XIF */
int rep_count=0; /* >0 if REP statement in process */
/****************************************************/
/*
** Variables for listing output routines
*/
char listfilename[256];
FILE *listfile;
/****************************************************/
start_listing (nam)
/*
** Initialize listing output file
*/
char *nam;
{
char *ppos;
strncpy (listfilename, nam, 250);
if (ppos = strrchr (listfilename, '.')) strcpy (ppos, ".lst");
else strcat (listfilename, ".lst");
listfile = fopen (listfilename, "w");
}
/****************************************************/
finish_listing () {
/*
** Finish off listing output file
*/
fclose (listfile);
printf ("Listing is in %s\n", listfilename);
}
/****************************************************/
/*
** Variables for binary output routines
*/
char outfilename[256];
FILE *outfile;
long outaddr;
long outcount;
long outbufsize=27;
long outbuf[27];
/****************************************************/
start_output (nam)
/*
** Initialize binary output file
*/
char *nam;
{
char *ppos;
strncpy (outfilename, nam, 250);
if (ppos = strrchr (outfilename, '.')) strcpy (ppos, ".bin");
else strcat (outfilename, ".bin");
outfile = fopen (outfilename, "wb");
outaddr = 0;
outcount = 0;
}
/****************************************************/
send_output () {
/*
** Write block to binary output file
*/
long ii,sum;
fputc (outcount, outfile);
fputc (0, outfile);
fputc (outaddr >> 8, outfile);
fputc (outaddr & 255, outfile);
sum = outaddr;
for (ii=0 ; ii < outcount ; ii++) {
fputc (outbuf[ii] >> 8, outfile);
fputc (outbuf[ii] & 255, outfile);
sum += outbuf[ii];
}
fputc (sum >> 8, outfile);
fputc (sum & 255, outfile);
outcount = 0;
}
/****************************************************/
output_word (addr,word)
/*
** Write word to binary output file
*/
long addr;
long word;
{
if (outcount && (outaddr + outcount) != addr) {
send_output();
}
if (!outcount) outaddr = addr;
outbuf[outcount++] = word;
if (outcount == outbufsize) {
send_output();
}
}
/****************************************************/
finish_output () {
/*
** Finish current output block, write trailing leader,
** and close output file
*/
int ii;
if (outcount) send_output();
for (ii=0; ii<20; ii++) fputc (0, outfile);
fclose (outfile);
printf ("Output is in %s\n", outfilename);
}
/****************************************************/
emit (code)
long code;
{
fprintf (listfile, " %05lo %06lo ", addr, code);
if (!print_flag) {
fprintf (listfile, "%s", line);
print_flag = 1;
}
fprintf (listfile, "\n");
output_word (addr, code);
addr++;
}
/****************************************************/
err (text)
char *text;
{
if (!print_flag) {
fprintf (listfile, " %12s %s\n", " ", line);
print_flag = 1;
}
fprintf (listfile, "ERROR: %s\n", text);
err_count++;
}
/****************************************************/
int is_valid_label_char (ch)
char ch;
{
if (isalpha(ch)) return (1);
if (isdigit(ch)) return (1);
if (ch=='.') return (1);
#if ALLOW_SPECIALS_IN_LABEL
if (ch=='&') return (1);
if (ch=='?') return (1);
if (ch=='#') return (1);
if (ch=='/') return (1);
if (ch=='%') return (1);
if (ch=='$') return (1);
if (ch=='[') return (1);
if (ch=='@') return (1);
if (ch=='!') return (1);
if (ch=='^') return (1);
#endif
return (0);
}
/****************************************************/
void insert_label (label, value)
char *label;
long value;
/*
** Insert label into symbol table
*/
{
long i;
if (strlen(label)>MXLABEL) {
err ("Symbol name > 5");
return;
}
for (i=0; i<nbsyms; i++) {
if (!strcmp(symtab[i].name, label)) {
err ("Duplicate symbol");
return;
}
}
if (nbsyms == MXSYM) {
err ("Symbol table is full!");
return;
}
strcpy (symtab[nbsyms].name, label);
symtab[nbsyms].value = value;
nbsyms++;
}
/****************************************************/
void find_label (label, value)
char *label;
long *value;
{
long i;
for (i=0; i<nbsyms; i++) {
if (!strcmp(symtab[i].name, label)) {
*value = symtab[i].value;
return;
}
}
err ("Undefined symbol");
*value=0;
}
/****************************************************/
show_labels ()
{
long i;
for (i=0; i<nbsyms; i++) {
fprintf (listfile, "%-6s %06lo \n", symtab[i].name, symtab[i].value );
}
}
/****************************************************/
int double_to_hp (num, a, b)
double num;
long *a,*b;
/*
** Convert floating point number to HP 21xx format
** Accepts:
** num Number to convert
** Returns:
** a,b Number in HP format
** ret 0=Success, -2=Underflow, -3=Overflow
*/
{
int neg=0;
long frac;
int exp=0;
*a = 0; *b = 0;
if (num == 0.0) return (0);
if (num < 0.0) { num = -num; neg = 1; }
while (num >= 1.0) { num = num / 2; exp++; }
while (num < 0.5) { num = num * 2; exp--; }
if (neg) num = -num;
if (neg) num += (0177 / 65536.0 / 65536.0);
else num += (0200 / 65536.0 / 65536.0);
if (neg && num >= -0.5) { num = num * 2; exp--; }
if (!neg && num >= 1.0) { num = num / 2; exp++; }
if (exp < -128) return (-2);
if (exp > 127) {
if (neg) { *a = 0x8000; *b = 0x01FE; }
else { *a = 0x7FFF; *b = 0xFFFE; }
return (-3);
}
frac = num * 65536.0 * 128.0 * 256.0;
exp = exp << 1;
if (exp < 0) exp++;
*a = (frac >> 16) & 0xFFFF;
*b = (frac & 0xFF00) | (exp & 0x00FF);
return (0);
}
/****************************************************/
parse_digits (base, out)
int base;
long *out;
{
long dig, val;
val = 0;
dig = line[lp] - '0';
while (dig>=0 && dig<base) {
val = val*base + dig;
dig = line[++lp] - '0';
}
*out = val;
}
/****************************************************/
parse_const (out)
long *out;
{
long save, val;
save = lp;
parse_digits (10, &val);
if (toupper(line[lp])=='B') {
lp = save;
parse_digits (8,&val);
if (toupper(line[lp])=='B') lp++;
else err ("Illegal octal digit");
}
*out = val;
}
/****************************************************/
parse_sym (out)
long *out;
{
char sym[MXLABEL+1];
int count,done;
char ch;
count=0;
done=0;
while (!done) {
ch = line[lp];
if (is_valid_label_char(ch)) {
if (count<MXLABEL) sym[count]=ch;
count++;
lp++;
} else {
done=1;
}
}
if (count>MXLABEL) {
err ("Illegal symbol");
*out=0;
} else {
sym[count]=0;
find_label (sym, out);
}
}
/****************************************************/
parse_term (out)
long *out;
{
char ch;
ch = line[lp];
if (isdigit(ch)) parse_const (out);
else if (is_valid_label_char(ch)) parse_sym (out);
else if (ch=='*') { lp++; *out = addr; }
else {
err ("Syntax error in expression");
*out=0;
}
}
/****************************************************/
parse_neg (out)
long *out;
{
long temp;
if (line[lp]=='-') {
lp++;
parse_term (&temp);
*out = (-temp) & 0xFFFF;
} else if (line[lp]=='+') {
lp++;
parse_term (out);
} else {
parse_term (out);
}
}
/****************************************************/
parse_sum (out)
long *out;
{
long v1,v2,op;
parse_neg (&v1);
while (line[lp]=='+' || line[lp]=='-') {
op = line[lp++];
parse_neg (&v2);
if (op=='+') v1 = v1 + v2;
if (op=='-') v1 = v1 - v2;
}
*out = v1 & 0xFFFF;
}
/****************************************************/
parse_arg (out)
long *out;
{
while (isspace (line[lp])) lp++;
/* while (line[lp]==' ') lp++; */
parse_sum (out);
}
/****************************************************/
parse_oct (out)
long *out;
{
long sign,val;
while (isspace (line[lp])) lp++;
/* while (line[lp]==' ') lp++; */
sign = line[lp];
if (sign=='+' || sign=='-') lp++;
parse_digits (8, &val);
if (sign=='-') val = (-val) & 0xFFFF;
*out =val;
}
/****************************************************/
parse_dec (out, nbwords)
long *out, *nbwords;
{
long save,sign,val,a,b;
extern double atof();
double num;
while (isspace (line[lp])) lp++;
/* while (line[lp]==' ') lp++; */
save = lp;
sign = line[lp];
if (sign=='+' || sign=='-') lp++;
parse_digits (10, &val);
if (sign=='-') val = (-val) & 0xFFFF;
out[0] = val;
*nbwords = 1;
if (line[lp]=='.' || toupper(line[lp])=='E') {
num = atof( &(line[save]) );
while (isdigit(line[lp]) || line[lp]=='.' || toupper(line[lp])=='E') lp++;
double_to_hp (num, &a, &b);
out[0] = a;
out[1] = b;
*nbwords = 2;
}
}
/****************************************************/
mem_group (opcode, code)
int opcode;
long *code;
{
long arg, out;
parse_arg (&arg);
if (arg < 02000) {
out = opcode + arg;
} else if ((arg & 0776000) == (addr & 0776000)) {
out = opcode + 02000 + (arg & 01777);
} else {
err ("Operand page error");
out = opcode;
}
if (line[lp]==',' && toupper(line[lp+1])=='I') {
out = out + 0100000L;
lp += 2;
}
code[0] = out;
}
/****************************************************/
io_group (opcode, code)
int opcode;
long *code;
{
long arg, out;
parse_arg (&arg);
if (arg > 077) {
err ("Select code > 77B");
arg = 0;
}
out = opcode + arg;
if (line[lp]==',' && toupper(line[lp+1])=='C') {
out += 001000;
lp += 2;
}
code[0] = out;
}
/****************************************************/
overflow_group (opcode, code)
int opcode;
long *code;
{
code[0] = opcode;
if (isspace (line[lp]) && toupper(line[lp+1])=='C') {
/* if (line[lp]==' ' && line[lp+1]=='C') { */
code[0] += 001000;
lp += 2;
}
}
/****************************************************/
parse_label (label)
char *label;
{
int i=0;
while (is_valid_label_char(line[lp])) {
if (i<MXLABEL) label[i++]=line[lp];
lp++;
}
label[i]=0;
}
/****************************************************/
int try (instr)
char *instr;
{
int ii,out;
for (ii=0; instr[ii]; ii++) {
if (toupper(line[lp+ii]) != instr[ii]) {
return (0);
}
}
if (isalpha(line[lp+ii])) out=0;
else {
lp += ii;
if (line[lp]==',') lp++;
out=1;
}
return (out);
}
/****************************************************/
int end_of_line()
{
int ll,out;
ll=lp;
out=0;
if (isspace (line[ll])) return 1;
while (isspace (line[ll])) ll++;
/* if (line[ll]=' ') return(1);
while (line[ll]==' ') ll++; */
if (line[ll]==';' || line[ll]=='\n' || line[ll]==0) {
out=1;
}
return (out);
}
/****************************************************/
int try_mem_group (code)
long *code;
{
int ok=1;
if (try("NOP")) code[0]=0;
else if (try("AND")) mem_group (010000, code);
else if (try("XOR")) mem_group (020000, code);
else if (try("IOR")) mem_group (030000, code);
else if (try("JSB")) mem_group (014000, code);
else if (try("JMP")) mem_group (024000, code);
else if (try("ISZ")) mem_group (034000, code);
else if (try("ADA")) mem_group (040000, code);
else if (try("ADB")) mem_group (044000, code);
else if (try("CPA")) mem_group (050000, code);
else if (try("CPB")) mem_group (054000, code);
else if (try("LDA")) mem_group (060000, code);
else if (try("LDB")) mem_group (064000, code);
else if (try("STA")) mem_group (070000, code);
else if (try("STB")) mem_group (074000, code);
else ok=0;
return (ok);
}
/****************************************************/
int try_srg_a (code)
long *code;
{
int ok=0;
long out=0;
long save=lp;
if (try("ALS")) out += 001000;
else if (try("ARS")) out += 001100;
else if (try("RAL")) out += 001200;
else if (try("RAR")) out += 001300;
else if (try("ALR")) out += 001400;
else if (try("ERA")) out += 001500;
else if (try("ELA")) out += 001600;
else if (try("ALF")) out += 001700;
if (try("CLE")) out += 000040;
if (try("SLA")) out += 000010;
if (try("ALS")) out += 000020;
else if (try("ARS")) out += 000021;
else if (try("RAL")) out += 000022;
else if (try("RAR")) out += 000023;
else if (try("ALR")) out += 000024;
else if (try("ERA")) out += 000025;
else if (try("ELA")) out += 000026;
else if (try("ALF")) out += 000027;
if (out && end_of_line()) {
code[0] = out;
ok=1;
} else {
lp = save;
ok=0;
}
return (ok);
}
/****************************************************/
int try_srg_b (code)
long *code;
{
int ok=0;
long out=0;
long save=lp;
if (try("BLS")) out += 001000;
else if (try("BRS")) out += 001100;
else if (try("RBL")) out += 001200;
else if (try("RBR")) out += 001300;
else if (try("BLR")) out += 001400;
else if (try("ERB")) out += 001500;
else if (try("ELB")) out += 001600;
else if (try("BLF")) out += 001700;
if (try("CLE")) out += 000040;
if (try("SLB")) out += 000010;
if (try("BLS")) out += 000020;
else if (try("BRS")) out += 000021;
else if (try("RBL")) out += 000022;
else if (try("RBR")) out += 000023;
else if (try("BLR")) out += 000024;
else if (try("ERB")) out += 000025;
else if (try("ELB")) out += 000026;
else if (try("BLF")) out += 000027;
if (out && end_of_line()) {
code[0] = out + 004000;
ok=1;
} else {
lp = save;
ok=0;
}
return (ok);
}
/****************************************************/
int try_asg_a (code)
long *code;
{
int ok=0;
long out=0;
long save=lp;
if (try("CLA")) out += 000400;
else if (try("CMA")) out += 001000;
else if (try("CCA")) out += 001400;
if (try("SEZ")) out += 000040;
if (try("CLE")) out += 000100;
else if (try("CME")) out += 000200;
else if (try("CCE")) out += 000300;
if (try("SSA")) out += 000020;
if (try("SLA")) out += 000010;
if (try("INA")) out += 000004;
if (try("SZA")) out += 000002;
if (try("RSS")) out += 000001;
if (out && end_of_line()) {
code[0] = out + 002000;
ok=1;
} else {
lp = save;
ok=0;
}
return (ok);
}
/****************************************************/
int try_asg_b (code)
long *code;
{
int ok=0;
long out=0;
long save=lp;
if (try("CLB")) out += 000400;
else if (try("CMB")) out += 001000;
else if (try("CCB")) out += 001400;
if (try("SEZ")) out += 000040;
if (try("CLE")) out += 000100;
else if (try("CME")) out += 000200;
else if (try("CCE")) out += 000300;
if (try("SSB")) out += 000020;
if (try("SLB")) out += 000010;
if (try("INB")) out += 000004;
if (try("SZB")) out += 000002;
if (try("RSS")) out += 000001;
if (out && end_of_line()) {
code[0] = out + 006000;
ok=1;
} else {
lp = save;
ok=0;
}
return (ok);
}
/****************************************************/
int try_io_group (code)
long *code;
{
int ok=1;
if (try("NOP")) code[0]=0;
else if (try("HLT")) io_group (0102000, code);
else if (try("STF")) io_group (0102100, code);
else if (try("CLF")) io_group (0103100, code);
else if (try("SFC")) io_group (0102200, code);
else if (try("SFS")) io_group (0102300, code);
else if (try("MIA")) io_group (0102400, code);
else if (try("MIB")) io_group (0106400, code);
else if (try("LIA")) io_group (0102500, code);
else if (try("LIB")) io_group (0106500, code);
else if (try("OTA")) io_group (0102600, code);
else if (try("OTB")) io_group (0106600, code);
else if (try("STC")) io_group (0102700, code);
else if (try("CLC")) io_group (0106700, code);
else ok=0;
return (ok);
}
/****************************************************/
int try_overflow (code)
long *code;
{
int ok=1;
if (try("STO")) code[0] = 0102101;
else if (try("CLO")) code[0] = 0103101;
else if (try("SOC")) overflow_group (0102201, code);
else if (try("SOS")) overflow_group (0102301, code);
else ok=0;
return (ok);
}
/****************************************************/
asm_pass (f)
FILE *f;
{
int done,count;
char label[MXLABEL+1];
long arg,code[2];
done=0;
while (!done) {
if (!fgets(line, sizeof(line), f)) {
done=1;
} else {
line_count++;
lp=strlen(line);
if (lp>0 && line[lp-1]=='\n') line[lp-1]=0;
print_flag = 0;
count = rep_count;
if (!count) count=1;
rep_count=0;
if (line[0]=='*') {
if (pass==2) {
fprintf (listfile, "%s\n", line);
print_flag = 1;
}
} else
while (count > 0) {
count--;
lp=0;
parse_label (label);
while (isspace (line[lp])) lp++;
/* while (line[lp]==' ') lp++; */
if (try("IFN")) {
if (!ifn_flag) xif_flag=1;
} else if (try("IFZ")) {
if (!ifz_flag) xif_flag=1;
} else if (try("XIF")) {
xif_flag=0;
} else if (xif_flag) {
while (line[lp]) lp++;
} else if (try("ORG")) {
parse_arg (&arg);
addr = arg;
if (pass==2) {
fprintf (listfile, " %05lo %s\n", addr, line);
print_flag = 1;
if (strlen(label)) err ("Unexpected label");
}
} else if (try("EQU")) {
parse_arg (&arg);
if (pass==1) {
if (strlen(label)) insert_label (label, arg);
} else {
fprintf (listfile, " %05lo %s\n", arg, line);
print_flag = 1;
if (!strlen(label)) err ("Label required");
}
} else if (!isalpha(line[lp])) {
if (pass==2) err ("No instruction on line");
} else {
if (pass==1 && strlen(label)) insert_label (label,addr);
if (try("HED") || try("SUP") || try("SPC") ||
try("SKP") || try("UNS") || try("UNL") ||
try("LST")) {
/* Listing control ops are ignored */
} else if (try("END")) {
/* No action required */
} else if (try("REP")) {
parse_arg (&arg);
if (arg < 1 || arg > 9999) {
err ("Illegal repeat count");
} else {
rep_count = arg;
}
} else if (try("ABS")) {
if (pass==1) addr++;
else {
parse_arg (code);
emit (code[0]);
}
} else if (try("DEF")) {
if (pass==1) addr++;
else {
parse_arg (code);
if (line[lp]==',' && toupper(line[lp+1])=='I') {
code[0] |= 0x8000;
lp += 2;
}
emit (code[0]);
}
} else if (try("DEC")) {
long nbwords;
parse_dec (code, &nbwords);
if (pass==1) addr += nbwords;
else {
if (nbwords > 0) emit (code[0]);
if (nbwords > 1) emit (code[1]);
}
} else if (try("OCT")) {
while (1) {
parse_oct (code);
if (pass==1) addr++;
else emit (code[0]);
if (line[lp]==',') lp++;
else break;
}
} else if (try("ASC")) {
long nbwords,c1,c2;
parse_arg (&nbwords);
if (pass==1) addr += nbwords;
else if (line[lp++]!=',') err ("Missing comma");
else
while (nbwords>0) {
if (line[lp]>31) c1=line[lp++]; else c1=' ';
if (line[lp]>31) c2=line[lp++]; else c2=' ';
emit (c1*256 + c2);
nbwords--;
}
} else if (try("BSS")) {
long nbwords;
if (pass==2) {
fprintf (listfile, " %05lo %s\n",
addr, line);
print_flag = 1;
}
parse_arg (&nbwords);
addr += nbwords;
}
else if (pass==1) addr++;
else if (try_mem_group(code)) emit (code[0]);
else if (try_srg_a(code)) emit (code[0]);
else if (try_srg_b(code)) emit (code[0]);
else if (try_asg_a(code)) emit (code[0]);
else if (try_asg_b(code)) emit (code[0]);
else if (try_io_group(code)) emit (code[0]);
else if (try_overflow(code)) emit (code[0]);
else {
emit (0L);
err ("Unknown instruction");
}
}
if (pass==2 && !end_of_line()) err ("Missing End-of-line");
if (pass==2 && !print_flag) fprintf (listfile, " %12s %s\n",
" ", line);
}
}
}
}
/****************************************************/
main (argc,argv)
int argc;
char *argv[];
{
FILE *f1;
int ii,jj;
jj=1;
for (ii=1 ; ii < argc ; ii++) {
if (!strcmp(argv[ii],"-n")) ifn_flag=1;
else if (!strcmp(argv[ii],"-z")) ifz_flag=1;
else argv[jj++] = argv[ii];
}
argc = jj;
if (argc < 2) {
printf ("Usage: hpasm options filename...\n");
return (-1);
}
start_output (argv[1]);
start_listing (argv[1]);
printf ("<< PASS 1 >>\n");
nbsyms=0;
err_count=0;
pass=1;
for (ii=1 ; ii < argc; ii++) {
f1 = fopen (argv[ii], "r");
if (!f1) {
printf ("File '%s' not found!\n\n", argv[ii]);
} else {
line_count=0;
printf ("%s ", argv[ii]);
fflush (stdout);
asm_pass (f1);
fclose (f1);
printf ("%d lines\n", line_count);
}
}
show_labels();
printf ("<< PASS 2 >>\n");
pass=2;
for (ii=1 ; ii < argc; ii++) {
f1 = fopen (argv[ii], "r");
if (!f1) {
printf ("File '%s' not found!\n\n", argv[ii]);
} else {
line_count=0;
printf ("%s ", argv[ii]);
fflush (stdout);
asm_pass (f1);
printf ("%d lines\n", line_count);
fclose (f1);
}
}
fprintf (listfile, "%ld ERRORS\n", err_count);
printf ("%ld ERRORS\n", err_count);
finish_output();
finish_listing();
return (0);
}
/****************************************************/