/* * Z80 - Assembler * Copyright (C) 1987-1992 by Udo Munk * * History: * 17-SEP-1987 Development under Digital Research CP/M 2.2 * 28-JUN-1988 Switched to Unix System V.3 */ /* * Dieses Modul enthaelt alle Funktionen, die Output * ins List-, Object- und Fehlerfile erzeugen. */ #include #include "z80a.h" #include "z80aglb.h" static char *errmsg[] = { /* Fehlermeldungen fuer asmerr() */ "illegal opcode", /* 0 */ "illegal operand", /* 1 */ "missing operand", /* 2 */ "multiply defined symbol", /* 3 */ "undefined symbol", /* 4 */ "value out of range", /* 5 */ "missing )", /* 6 */ "missing string separator", /* 7 */ "memory override", /* 8 */ "missing IF", /* 9 */ "IF nesting to deep", /* 10 */ "missing ENDIF", /* 11 */ "INCLUDE nesting to deep" /* 12 */ }; #define MAXHEX 32 /* maximale Anzahl Bytes/Hex-Record */ static unsigned short hex_adr; /* aktuelle Adresse Hex-Record */ static int hex_cnt; /* aktuelle Anzahl Bytes im Hex-Puffer */ static unsigned char hex_buf[MAXHEX]; /* Code-Puffer fuer einen Hex-Record */ static char hex_out[MAXHEX*2+11]; /* ASCII-Puffer fuer einen Hex-Record */ /* * Fehlermeldungen auf den Fehlerkanal (Listfile oder stdout) * ausgeben und Fehlerzaehler erhoehen. */ asmerr(i) register int i; { if (pass == 1) { fprintf(errfp, "Error in file: %s Line: %d\n", srcfn, c_line); fprintf(errfp, errmsg[i]); fprintf(errfp, "\n\n"); } else errnum = i; errors++; } /* * Die Funktion beginnt eine neue Seite in der Listdatei */ lst_header() { fprintf(lstfp, "\fZ80-Assembler\t\tRelease %s\t\t\t\tPage %d\n", REL, ++page); fprintf(lstfp, "Source file: %s\n", srcfn); fprintf(lstfp, "Title: %s\n", title); p_line = 3; } /* * Ueberschrift fuer die Quellzeilen erzeugen */ lst_attl() { fprintf(lstfp, "\nLOC OBJECT CODE LINE STMT SOURCE CODE\n"); p_line += 2; } /* * Eine Zeile in der Listdatei erzeugen, * wenn Option -l gegeben. */ lst_line(val, opanz) register int val, opanz; { register int i; if (!list_flag || sd_flag == 4) { sd_flag = 0; return; } if ((p_line >= ppl) || (c_line == 1)) { lst_header(); lst_attl(); } switch (sd_flag) { case 0: fprintf(lstfp, "%04x ", val & 0xffff); break; case 1: fprintf(lstfp, "%04x ", sd_val & 0xffff); break; case 2: fprintf(lstfp, " "); break; case 3: fprintf(lstfp, "%04x ", sd_val & 0xffff); goto no_data; default: fatal(F_INTERN, "illegal listflag for function lst_line"); break; } if (opanz >= 1) fprintf(lstfp, "%02x ", ops[0] & 0xff); else fprintf(lstfp, " "); if (opanz >= 2) fprintf(lstfp, "%02x ", ops[1] & 0xff); else fprintf(lstfp, " "); if (opanz >= 3) fprintf(lstfp, "%02x ", ops[2] & 0xff); else fprintf(lstfp, " "); if (opanz >= 4) fprintf(lstfp, "%02x ", ops[3] & 0xff); else fprintf(lstfp, " "); no_data: fprintf(lstfp, "%6d %6d %s", c_line, s_line, line); if (errnum) { fprintf(errfp, "=> %s", errmsg[errnum]); putc('\n', errfp); errnum = 0; p_line++; } sd_flag = 0; p_line++; if (opanz > 4 && sd_flag == 0) { opanz -= 4; i = 4; sd_val = val; while (opanz > 0) { if (p_line >= ppl) { lst_header(); lst_attl(); } s_line++; sd_val += 4; fprintf(lstfp, "%04x ", sd_val & 0xffff); if (opanz-- > 0) fprintf(lstfp, "%02x ", ops[i++] & 0xff); else fprintf(lstfp, " "); if (opanz-- > 0) fprintf(lstfp, "%02x ", ops[i++] & 0xff); else fprintf(lstfp, " "); if (opanz-- > 0) fprintf(lstfp, "%02x ", ops[i++] & 0xff); else fprintf(lstfp, " "); if (opanz-- > 0) fprintf(lstfp, "%02x ", ops[i++] & 0xff); else fprintf(lstfp, " "); fprintf(lstfp, "%6d %6d\n", c_line, s_line); p_line++; } } } /* * Symboltabelle ins Listfile in der gespeicherten * Reihenfolge direkt aus der Hash-Tabelle ausgeben */ lst_sym() { register int i, j; register struct sym *np; char *strcpy(); p_line = j = 0; strcpy(title,"Symboltable"); for (i = 0; i < HASHSIZE; i++) { if (symtab[i] != NULL) { for (np = symtab[i]; np != NULL; np = np->sym_next) { if (p_line == 0) { lst_header(); fputs("\n", lstfp); p_line += 1; } fprintf(lstfp, "%-8s %04x\t", np->sym_name, np->sym_wert & 0xffff); if (++j == 4) { fprintf(lstfp, "\n"); if (p_line++ >= ppl) p_line = 0; j = 0; } } } } } /* * Sortierte Symboltabelle ins Listfile ausgeben */ lst_sort_sym(len) register int len; { register int i, j; char *strcpy(); p_line = i = j = 0; strcpy(title, "Symboltable"); while (i < len) { if (p_line == 0) { lst_header(); fputs("\n", lstfp); p_line += 1; } fprintf(lstfp, "%-8s %04x\t", symarray[i]->sym_name, symarray[i]->sym_wert & 0xffff); if (++j == 4) { fprintf(lstfp, "\n"); if (p_line++ >= ppl) p_line = 0; j = 0; } i++; } } /* * Header-Record ins Objectfile ausgeben */ obj_header() { switch (out_form) { case OUTBIN: break; case OUTMOS: putc(0xff, objfp); putc(prg_adr & 0xff, objfp); putc(prg_adr >> 8, objfp); break; case OUTHEX: hex_adr = prg_adr; break; } } /* * Ende-Record ins Objectfile ausgeben */ obj_end() { switch (out_form) { case OUTBIN: break; case OUTMOS: break; case OUTHEX: flush_hex(); fprintf(objfp, ":0000000000\n"); break; } } /* * Op-Codes in ops[] ins Objectfile ausgeben */ obj_writeb(opanz) register int opanz; { register int i; switch (out_form) { case OUTBIN: fwrite(ops, 1, opanz, objfp); break; case OUTMOS: fwrite(ops, 1, opanz, objfp); break; case OUTHEX: for (i = 0; opanz; opanz--) { if (hex_cnt >= MAXHEX) flush_hex(); hex_buf[hex_cnt++] = ops[i++]; } break; } } /* * Bytes mit 0xff ins Objectfile ausgeben */ obj_fill(count) register int count; { switch (out_form) { case OUTBIN: while (count--) putc(0xff, objfp); break; case OUTMOS: while (count--) putc(0xff, objfp); break; case OUTHEX: flush_hex(); hex_adr += count; break; } } /* * Einen Hex-Record in ASCII erzeugen und ausgeben */ flush_hex() { char *p; register int i; if (!hex_cnt) return; p = hex_out; *p++ = ':'; btoh((unsigned char) hex_cnt, &p); btoh((unsigned char) (hex_adr >> 8), &p); btoh((unsigned char) (hex_adr & 0xff), &p); *p++ = '0'; *p++ = '0'; for (i = 0; i < hex_cnt; i++) btoh(hex_buf[i], &p); btoh((unsigned char) chksum(), &p); *p++ = '\n'; *p = '\0'; fwrite(hex_out, 1, strlen(hex_out), objfp); hex_adr += hex_cnt; hex_cnt = 0; } /* * Ein unsigned char in ASCII-Hex umwandeln und an Adresse, * auf die p zeigt, ablegen. Der Pointer p wird dann um * zwei erhoeht. */ btoh(byte, p) unsigned char byte; register char **p; { register unsigned char c; c = byte >> 4; *(*p)++ = (c < 10) ? (c + '0') : (c - 10 + 'A'); c = byte & 0xf; *(*p)++ = (c < 10) ? (c + '0') : (c - 10 + 'A'); } /* * Pruefsumme fuer einen Intel-Hex-Record berechnen */ chksum() { register int i, j, sum; sum = hex_cnt; sum += hex_adr >> 8; sum += hex_adr & 0xff; for (i = 0; i < hex_cnt; i++) { j = hex_buf[i]; sum += j & 0xff; } return (0x100 - (sum & 0xff)); }