/* ** HPASM.C -- Assembler for HP2100 */ /****************************************************/ #include #include /****************************************************/ #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[] = "hpasm.lst"; FILE *listfile; /****************************************************/ start_listing () { /* ** Initialize listing output file */ 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[] = "hpasm.out"; FILE *outfile; long outaddr; long outcount; long outbufsize=27; long outbuf[27]; /****************************************************/ start_output () { /* ** Initialize binary output file */ 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); } /****************************************************/ 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= 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 && digMXLABEL) { 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 (line[lp]==' ') lp++; parse_sum (out); } /****************************************************/ parse_oct (out) long *out; { long sign,val; 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 (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]=='.' || line[lp]=='E') { num = atof( &(line[save]) ); while (isdigit(line[lp]) || line[lp]=='.' || 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]==',' && 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]==',' && line[lp+1]=='C') { out += 001000; lp += 2; } code[0] = out; } /****************************************************/ overflow_group (opcode, code) int opcode; long *code; { code[0] = opcode; 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 (i0 && 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 (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]==',' && 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"); exit (-1); } start_output (); start_listing (); 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); } /****************************************************/