Zapple-II/z80asm/z80aout.c

362 lines
7.3 KiB
C

/*
* 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 <stdio.h>
#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;
}
}
/*
* <count> 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));
}