mirror of
https://github.com/bobbimanners/Zapple-II.git
synced 2024-10-31 22:06:19 +00:00
362 lines
7.3 KiB
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));
|
|
}
|