Initial commit of z80asm (without Apple II mods.)

This commit is contained in:
Bobbi Webber-Manners 2019-10-12 19:17:55 -04:00
parent 109a8caafa
commit 8696185cae
14 changed files with 5870 additions and 0 deletions

41
z80asm/Makefile Normal file
View File

@ -0,0 +1,41 @@
CFLAGS = -c -O
LFLAGS = -s
OBJ = z80amain.o \
z80atab.o \
z80anum.o \
z80aout.o \
z80arfun.o \
z80apfun.o \
z80aopc.o \
z80aglb.o
z80asm : $(OBJ)
cc $(OBJ) $(LFLAGS) -o z80asm
z80amain.o : z80amain.c z80a.h z80aglb.h
cc $(CFLAGS) z80amain.c
z80atab.o : z80atab.c z80a.h z80aglb.h
cc $(CFLAGS) z80atab.c
z80anum.o : z80anum.c z80a.h z80aglb.h
cc $(CFLAGS) z80anum.c
z80aout.o : z80aout.c z80a.h z80aglb.h
cc $(CFLAGS) z80aout.c
z80arfun.o : z80arfun.c z80a.h z80aglb.h
cc $(CFLAGS) z80arfun.c
z80apfun.o : z80apfun.c z80a.h z80aglb.h
cc $(CFLAGS) z80apfun.c
z80aopc.o : z80aopc.c z80a.h
cc $(CFLAGS) z80aopc.c
z80aglb.o : z80aglb.c z80a.h
cc $(CFLAGS) z80aglb.c
clean:
rm -f core *.o z80asm

78
z80asm/README Normal file
View File

@ -0,0 +1,78 @@
Usage:
z80asm -ofile -f[b|m|h] -l[file] -s[n|a] -v -dsymbol ... file ...
A maximum of 512 source files is allowed. If the filename of a source
doesn't have an extension the default extension ".asm" will be
concated. Source file names may have a path, the maximum length of
a full qualified filename is 128 characters.
If one use relative paths, the extension must be given, because all
after a "." would be used as extension!
Option o:
To override the default name of the output file. Without this option
the name of the output file becomes the name of the input file,
but with the extension ".bin". The output file may have a path,
the maximum length is limited to 128 characters.
Option f:
Format of the output file:
-fb -> binary file
-fm -> binary file with Mostek header
-fh -> Intel hex
Option l:
Without this option no list file will be generated. With -l a list
file with the name of the source file but extension ".lis" will be
generated. An optional file name with path (128 characters maximum)
may be added to this option.
Option s:
This option writes the unsorted symbol table (-s), sorted by name (-sn)
or sorted by address (-sa) into the list file. This options works
only, if option -l was given.
Option v:
Verbose operation of the assembler.
Option d:
With this option one can predefine symbols with a value of 0.
The number of this option is not limited in the command line.
Pseudo Operations:
Definition of symbols and allocation of memory:
ORG <expression> - set program address
<symbol> EQU <expression> - define constant symbol
<symbol> DEFL <expression> - define variable symbol
<symbol> DEFB <exp,'char',..> - write bytes in memory
<symbol> DEFW <exp,exp..> - write words (16 bits) in memory
<symbol> DEFM <'string'> - write character string in memory
<symbol> DEFS <expression> - reserve space in memory
Conditional assembly:
IFDEF <symbol> - assemble if symbol defined
IFNDEF <symbol> - assemble if symbol not defined
IFEQ <exp1,exp2> - assemble if equal
IFNEQ <exp1,exp2> - assemble if not equal
ELSE - else for all conditionals
ENDIF - end of conditional assembly
Manipulation of list file:
PAGE <expression> - number of lines/page
EJECT - skip to new page
LIST - listing on
NOLIST - listing off
TITLE <'string'> - define title for page header
Others:
INCLUDE <filename> - include another source file
PRINT <'string'> - print string to stdout in pass one

46
z80asm/license.de Normal file
View File

@ -0,0 +1,46 @@
Lizenz fuer Z80-CPU Crossassembler
Das in dieser Lizenz beschriebene Programm ist ein durch Copyright
geschuetztes Produkt. Das Programm darf unter folgenden Voraussetzungen
mittels beliebiger Medien kopiert und weitergegeben werden:
1. Der Empfaenger erhaelt alle Quellen des Programmes inklusive
dieser Lizenz.
2. Fuer die Uebertragung und Weitergabe des Programms darf eine
angemessene Aufwandsentschaedigung verlangt werden. Das Programm
selbst darf nicht ohne ausdrueckliche Genehmigung des Autors
verkauft werden.
Nutzungsrechte fuer Anwender des Programms:
1. Dieses Programm darf fuer nicht kommerzielle Anwendungen
kostenlos angewendet werden.
2. Fuer kommerzielle Anwendungen des Programms ist eine
Nutzungsgebuehr mit dem Autor des Programms zu vereinbaren.
Der Fairness wegen wird die Hoehe der Gebuehr hier nicht
festgelegt, sie richtet sich nach dem jeweiligen Anwendungsfall.
Grosse Unternehmen mit hohen Gewinnen zahlen in jedem Fall
mehr, als ein einzelner, selbstaendiger Software Entwickler!
Veraenderungen des Programms:
Alle Programmteile duefern vom Anwender nur zwecks Beseitigung von
Fehlern veraendert werden! Der Anwender ist verpflichtet, solche
erforderlichen Aenderungen dem Autor mitzuteilen. Diese Massnahme soll
eine Versionsvielfalt verhindern, und den Support der
kommerziellen Anwender durch den Autor sicherstellen!
EIN VERSTOSS GEGEN DIE BEDINGUNGEN DIESER LIZENZ FUEHRT ZUM
SOFORTIGEN VERLUST DES NUTZUNGSRECHTES DES PROGRAMMES!
DIESE SOFTWARE WIRD OHNE GARANTIE FUER EINE BESTIMMTE VERWENDUNG
AUSGELIEFERT. DER AUTOR HAFTET WEDER FUER FEHLER IN DIESEM PROGRAMM,
NOCH FUER FEHLER, ODER SCHAEDEN, DIE DURCH ANWENDUNG DIESES PROGRAMMES
ENTSTEHEN.
Udo Munk Tel.: +49 2131 275348
Oberstr. 21 E-Mail: udo@umunk.GUN.de
4040 Neuss 1 ...!{mcshh,smurf,unido}!easix!umunk!udo
Germany CompuServe: 100021,2515

41
z80asm/license.us Normal file
View File

@ -0,0 +1,41 @@
License Agreement for Z80-CPU crossassembler
The program described in this license is copyrighted by the law of Germany.
The program may be copied and shared under the following terms:
1. The user receives all the source-codes of the program including the license.
2. For the physical act of transfer and sharing of the package, a small fee may
be demanded. The program itself must not be sold without the author's
permission.
License to the user of the program:
1. This program may be used free of fee for non-comercial usages.
2. For comercial usage of the program, a fee must be amounted to the author.
In cause of fairness, a big company will have to pay more for a license than
a single software developer. So the amount of the fee must be negotiated
with the autor of the program.
Modification of the program:
All program-parts may be only modified by the user for debugging. The user
is bound to inform the author about those modifications. This should
prevent an uncontrolled number of versions and ensure the support to
comercial users through the author.
VIOLATIONS AGAINST THIS LICENSE RESULTS IN A LOSS OF RIGHTS TO USE
THIS PROGRAM.
THE PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL
THE AUTOR BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING ANY LOST PROFITS,
LOST SAVINGS OR OTHER INCIDENTAL OR CONSEQUENTAL DAMAGES ARISING OUT OF
THE USE OF THE PROGRAM.
Udo Munk voice: +49 2131 275348
Oberstr. 21 mail : udo@umunk.GUN.de
4040 Neuss 1 ...!{mcshh,smurf,unido}!easix!umunk!udo
Germany CompuServe: 100021,2515

146
z80asm/z80a.h Normal file
View File

@ -0,0 +1,146 @@
/*
* 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
*/
/*
* Rechner und Betriebssystem abhaengige Definitionen
*/
#define LENFN 128 /* max. Laenge von Filenamen */
#define READA "r" /* file open mode read ascii */
#define WRITEA "w" /* file open mode write ascii */
#define WRITEB "w" /* file open mode write binary */
/*
* Diverse Konstanten
*/
#define REL "1.1"
#define COPYR "Copyright (C) 1988, 89, 90 by Udo Munk"
#define SRCEXT ".asm" /* Filenamen-Extension der Quelle */
#define OBJEXT ".bin" /* Filenamen-Extension des Object Code */
#define LSTEXT ".lis" /* Filenamen-Extension des Listings */
#define OUTBIN 1 /* Format der Objektdatei: binaer */
#define OUTMOS 2 /* Mostek binaer */
#define OUTHEX 3 /* Intel hex */
#define OUTDEF OUTMOS /* Default-Format der Objektdatei */
#define COMMENT ';' /* Kommentar-Zeichen */
#define LINCOM '*' /* wenn in Spalte 1, Kommentarzeile */
#define LABSEP ':' /* Label-Seperator */
#define STRSEP '\'' /* String-Separator */
#define ENDFILE "END" /* Ende der Quelle */
#define MAXFN 512 /* max. Anzahl Quellen */
#define MAXLINE 128 /* max. Laenge einer Zeile Quelle */
#define PLENGTH 65 /* Default Anzahl Zeilen/Seite im Listing */
#define SYMSIZE 8 /* max. Laenge Symbole */
#define INCNEST 5 /* INCLUDE Verschachtelungstiefe */
#define IFNEST 5 /* IF.. Verschachtelungstiefe */
#define HASHSIZE 500 /* Anzahl Eintraege in Symbol-Hash-Array */
#define OPCARRAY 256 /* Groesse des Arrays fuer generierte Ops */
#define SYMINC 100 /* Anfangsgroesse des sortierten Symbol-Array */
/*
* Struktur der OP-Code Tabelle
*/
struct opc {
char *op_name; /* Op-Code Name */
int (*op_fun) (); /* Pointer auf Funktion zur Codeerzeugung */
int op_c1; /* erster Basis-OP-Code */
int op_c2; /* zweiter Basis-OP-Code */
};
/*
* Struktur der Operanden Tabelle
*/
struct ope {
char *ope_name; /* Operand Name */
int ope_sym; /* Symbolischer Wert des Operanden */
};
/*
* Struktur der Symbol-Tabelleneintraege
*/
struct sym {
char *sym_name; /* Symbol Name */
int sym_wert; /* Symbol Wert */
struct sym *sym_next; /* naechster Eintrag */
};
/*
* Struktur fuer verschachtelte INCLUDE's
*/
struct inc {
unsigned inc_line; /* Zeilenzaehler fuers Listing */
char *inc_fn; /* Filename der Datei mit INCLUDE */
FILE *inc_fp; /* Filepointer der Datei mit INCLUDE */
};
/*
* Definition der Symbole fuer die Operanden.
* Die Definitionen fuer Register A, B, C, D, H, L
* und (HL) entsprechen den Bits in den Opcodes
* und duerfen auf keinen Fall geaendert werden!
*/
#define REGB 0 /* Register B */
#define REGC 1 /* Register C */
#define REGD 2 /* Register D */
#define REGE 3 /* Register E */
#define REGH 4 /* Register H */
#define REGL 5 /* Register L */
#define REGIHL 6 /* Register indirekt HL */
#define REGA 7 /* Register A */
#define REGI 8 /* Register I */
#define REGR 9 /* Register R */
#define REGAF 10 /* Registerpaar AF */
#define REGBC 11 /* Registerpaar BC */
#define REGDE 12 /* Registerpaar DE */
#define REGHL 13 /* Registerpaar HL */
#define REGIX 14 /* Register IX */
#define REGIY 15 /* Register IY */
#define REGSP 16 /* Register SP */
#define REGIBC 17 /* Register indirekt BC */
#define REGIDE 18 /* Register indirekt DE */
#define REGIIX 19 /* Register indirekt IX */
#define REGIIY 20 /* Register indirekt IY */
#define REGISP 21 /* Register indirekt SP */
#define FLGNC 30 /* Flag no carry */
#define FLGNZ 31 /* Flag not zerro */
#define FLGZ 32 /* Flag zerro */
#define FLGM 33 /* Flag minus */
#define FLGP 34 /* Flag plus */
#define FLGPE 35 /* Flag parrity even */
#define FLGPO 36 /* Flag parrity odd */
#define NOOPERA 98 /* kein Operand vorhanden */
#define NOREG 99 /* Operand ist kein Register */
/*
* Definition der Assembler-Fehler-Nummern, die
* zu Fehlermeldungen im Listfile fuehren
* (siehe asmerr)
*/
#define E_ILLOPC 0 /* illegaler Opcode */
#define E_ILLOPE 1 /* illegaler Operand */
#define E_MISOPE 2 /* fehlender Operand */
#define E_MULSYM 3 /* mehrfach definiertes Symbol */
#define E_UNDSYM 4 /* undefiniertes Symbol */
#define E_VALOUT 5 /* Wert ausserhalb Bereich */
#define E_MISPAR 6 /* Klammer fehlt */
#define E_MISHYP 7 /* String Separator fehlt */
#define E_MEMOVR 8 /* memory override (ORG) */
#define E_MISIFF 9 /* fehlendes IF bei ELSE oder ENDIF */
#define E_IFNEST 10 /* IF zu tief verschachtelt */
#define E_MISEIF 11 /* fehlendes ENDIF */
#define E_INCNEST 12 /* INCLUDE zu tief verschachtelt */
/*
* Definition der Fehlernummern, die zum sofortigen
* Abbruch des Programms fuehren (siehe fatal)
*/
#define F_OUTMEM 0 /* out of memory */
#define F_USAGE 1 /* usage: .... */
#define F_HALT 2 /* Assembly halted */
#define F_FOPEN 3 /* can't open file */
#define F_INTERN 4 /* internal error */

64
z80asm/z80aglb.c Normal file
View File

@ -0,0 +1,64 @@
/*
* 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 globalen Variablen des
* Assemblers, ausser der CPU spezifischen Tabellen.
*/
#include <stdio.h>
#include "z80a.h"
char *infiles[MAXFN], /* Filenamen aller Quellen */
objfn[LENFN + 1], /* Filename des Object Code */
lstfn[LENFN + 1], /* Filename des Listing */
*srcfn, /* Filename der gerade bearbeiteten Quelle */
line[MAXLINE], /* Puffer fuer eine Zeile Quelle */
tmp[MAXLINE], /* termoraerer Puffer */
label[SYMSIZE+1], /* Puffer fuer extrahiertes Label */
opcode[MAXLINE], /* Puffer fuer extrahierten Op-Code */
operand[MAXLINE], /* Puffer fuer extrahierten Operanden */
ops[OPCARRAY], /* Puffer fuer generierten Op-Code */
title[MAXLINE]; /* Puffer fuer Titel der Quelle */
int list_flag, /* Flag fuer Option -l */
sym_flag, /* Flag fuer Option -s */
ver_flag, /* Flag fuer Option -v */
pc, /* Programm-Counter */
pass, /* Momentaner Durchlauf */
iflevel, /* aktuelle Verschachtelungstiefe der IF's */
gencode = 1, /* Flag fuer conditional Codegenerierung */
errors, /* Zaehler fuer errors */
errnum, /* Fehler Nummer in Pass 2 */
sd_flag, /* List-Flag fuer PSEUDO Op-Codes */
/* = 0: Adresse aus <val>, Daten aus <ops> */
/* = 1: Adresse aus <sd_val>, Daten aus <ops> */
/* = 2: keine Adresse, Daten aus <ops> */
/* = 3: Adresse aus <sd_val>, keine Daten */
/* = 4: ganze Zeile unterdruecken */
sd_val, /* Ausgabewert fuer PSEUDO Op-Codes */
prg_adr, /* Startadresse des Programms */
prg_flag, /* Flag fuer prg_adr gueltig */
out_form = OUTDEF, /* Format der Objektdatei */
symsize; /* Groesse von symarray */
FILE *srcfp, /* Filepointer fuer aktuelle Quelle */
*objfp, /* Filepointer fuer Object Code */
*lstfp, /* Filepointer fuer Listing */
*errfp; /* Filepointer fuer Fehler */
/* abhaengig von -l lstfp oder stdout */
unsigned c_line, /* aktuelle Zeile der aktuellen Quelle */
s_line, /* Zeilenzaehler fuers Listing */
p_line, /* Anzahl gedruckter Zeilen auf der Seite */
ppl = PLENGTH, /* Anzahl Zeilen/Seite */
page; /* Seitenzaehler fuer Listing */
struct sym *symtab[HASHSIZE], /* Symboltabelle */
**symarray; /* sortierte Symboltabelle */

60
z80asm/z80aglb.h Normal file
View File

@ -0,0 +1,60 @@
/*
* 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
*/
/*
* Extern Declaration der globalen Variablen
*/
extern char *infiles[],
objfn[],
lstfn[],
*srcfn,
line[],
tmp[],
label[],
opcode[],
operand[],
ops[],
title[];
extern int list_flag,
sym_flag,
ver_flag,
pc,
pass,
iflevel,
gencode,
errors,
errnum,
sd_flag,
sd_val,
prg_adr,
prg_flag,
out_form,
symsize,
no_opcodes,
no_operands;
extern FILE *srcfp,
*objfp,
*lstfp,
*errfp;
extern unsigned c_line,
s_line,
p_line,
ppl,
page;
extern struct sym *symtab[],
**symarray;
extern struct opc opctab[];
extern struct ope opetab[];

498
z80asm/z80amain.c Normal file
View File

@ -0,0 +1,498 @@
/*
* 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
*/
#include <stdio.h>
#include <ctype.h>
#include "z80a.h"
#include "z80aglb.h"
static char *errmsg[] = { /* Fehlermeldungen fuer fatal() */
"out of memory: %s", /* 0 */
"usage: z80asm -ofile -f[b|m|h] -l[file] -s[n|a] -v -dsymbol ... file ...",
"Assembly halted", /* 2 */
"can't open file %s", /* 3 */
"internal error: %s" /* 4 */
};
main(argc, argv)
int argc;
char *argv[];
{
int len;
init();
options(argc, argv);
printf("Z80 - Assembler Release %s, %s\n", REL, COPYR);
pass1();
pass2();
if (list_flag) {
switch (sym_flag) {
case 0: /* keine Symboltabelle */
break;
case 1: /* unsortierte Symboltabelle */
lst_sym();
break;
case 2: /* nach Namen sortierte Symboltabelle */
len = copy_sym();
n_sort_sym(len);
lst_sort_sym(len);
break;
case 3: /* nach Adressen sortierte Symboltabelle */
len = copy_sym();
a_sort_sym(len);
lst_sort_sym(len);
break;
default:
break;
}
fclose(lstfp);
}
return(errors);
}
/*
* Initialisierung
*/
init()
{
errfp = stdout;
}
/*
* Diese Funktion bearbeitet die beim Aufruf angegebenen Options.
* Die uebergebenen Dateinamen werden in die entsprechenden
* Strings uebernommen.
*/
options(argc, argv)
int argc;
char *argv[];
{
register char *s, *t;
register int i;
char *malloc();
while (--argc > 0 && (*++argv)[0] == '-')
for (s = argv[0]+1; *s != '\0'; s++)
switch (*s) {
case 'o':
case 'O':
if (*++s == '\0') {
puts("name missing in option -o");
usage();
}
get_fn(objfn, s, OBJEXT);
s += (strlen(s) - 1);
break;
case 'l':
case 'L':
if (*(s + 1) != '\0') {
get_fn(lstfn, ++s, LSTEXT);
s += (strlen(s) - 1);
}
list_flag = 1;
break;
case 's':
case 'S':
if (*(s + 1) == '\0')
sym_flag = 1;
else if ((*(s + 1) == 'n') || (*(s + 1) == 'N'))
sym_flag = 2;
else if ((*(s + 1) == 'a') || (*(s + 1) == 'A'))
sym_flag = 3;
else {
printf("unknown option -%s\n", s);
usage();
}
s += (strlen(s) - 1);
break;
case 'f':
case 'F':
if ((*(s + 1) == 'b') || (*(s + 1) == 'B'))
out_form = OUTBIN;
else if ((*(s + 1) == 'm') || (*(s + 1) == 'M'))
out_form = OUTMOS;
else if ((*(s + 1) == 'h') || (*(s + 1) == 'H'))
out_form = OUTHEX;
else {
printf("unknown option -%s\n", s);
usage();
}
s += (strlen(s) - 1);
break;
case 'd':
case 'D':
if (*++s == '\0') {
puts("name missing in option -d");
usage();
}
t = tmp;
while (*s)
*t++ = islower(*s) ? toupper(*s++) : *s++;
s--;
*t = '\0';
if (put_sym(tmp, 0))
fatal(F_OUTMEM, "symbols");
break;
case 'v':
case 'V':
ver_flag = 1;
break;
default :
printf("unknown option %c\n", *s);
usage();
}
i = 0;
while ((argc--) && (i < MAXFN)) {
if ((infiles[i] = malloc(LENFN + 1)) == NULL)
fatal(F_OUTMEM, "filenames");
get_fn(infiles[i], *argv++, SRCEXT);
i++;
}
if (i == 0) {
printf("no input file given\n");
usage();
}
}
/*
* An den Argumenten in der Befehlszeile ist was falsch,
* Gebrauchsanleitung ausgeben und abbrechen.
*/
usage()
{
fatal(F_USAGE, NULL);
}
/*
* Fehlermeldung ausgeben und abbrechen
*/
fatal(i, arg)
register int i;
register char *arg;
{
void exit();
printf(errmsg[i], arg);
putchar('\n');
exit(1);
}
/*
* Pass 1:
* - Lauf ueber alle Quelldateien
*/
pass1()
{
register int fi;
pass = 1;
pc = 0;
fi = 0;
if (!ver_flag)
puts("Pass 1");
open_o_files(infiles[fi]);
while (infiles[fi] != NULL) {
if (!ver_flag)
printf(" Read %s\n", infiles[fi]);
p1_file(infiles[fi]);
fi++;
}
if (errors) {
fclose(objfp);
unlink(objfn);
printf("%d error(s)\n", errors);
fatal(F_HALT, NULL);
}
}
/*
* Pass 1:
* - Lauf ueber eine Quelldatei
*
* Input: Name der zu bearbeitenden Quelldatei
*/
p1_file(fn)
char *fn;
{
c_line = 0;
srcfn = fn;
if ((srcfp = fopen(fn, READA)) == NULL)
fatal(F_FOPEN, fn);
while (p1_line())
;
fclose(srcfp);
if (iflevel)
asmerr(E_MISEIF);
}
/*
* Pass 1:
* - Eine Zeile Quelle verarbeiten
*
* Output: 1 Zeile verarbeitet
* 0 EOF erreicht
*/
p1_line()
{
register char *p;
register int i;
register struct opc *op;
char *get_label(), *get_opcode(), *get_arg();
struct opc *search_op();
if ((p = fgets(line, MAXLINE, srcfp)) == NULL)
return(0);
c_line++;
p = get_label(label, p);
p = get_opcode(opcode, p);
p = get_arg(operand, p);
if (strcmp(opcode, ENDFILE) == 0)
return(0);
if (*opcode) {
if ((op = search_op(opcode)) != NULL) {
i = (*op->op_fun)(op->op_c1, op->op_c2);
if (gencode)
pc += i;
} else
asmerr(E_ILLOPC);
} else
if (*label)
put_label();
return(1);
}
/*
* Pass 2:
* - Lauf ueber alle Quelldateien
*/
pass2()
{
register int fi;
pass = 2;
pc = 0;
fi = 0;
if (!ver_flag)
puts("Pass 2");
obj_header();
while (infiles[fi] != NULL) {
if (!ver_flag)
printf(" Read %s\n", infiles[fi]);
p2_file(infiles[fi]);
fi++;
}
obj_end();
fclose(objfp);
printf("%d error(s)\n", errors);
}
/*
* Pass 2:
* - Lauf ueber eine Quelldatei
*
* Input: Name der zu bearbeitenden Quelldatei
*/
p2_file(fn)
char *fn;
{
c_line = 0;
srcfn = fn;
if ((srcfp = fopen(fn, READA)) == NULL)
fatal(F_FOPEN, fn);
while (p2_line())
;
fclose(srcfp);
}
/*
* Pass 2:
* - Eine Zeile Quelle verarbeiten
*
* Output: 1 Zeile verarbeitet
* 0 EOF erreicht
*/
p2_line()
{
register char *p;
register int op_count;
register struct opc *op;
char *get_label(), *get_opcode(), *get_arg();
struct opc *search_op();
if ((p = fgets(line, MAXLINE, srcfp)) == NULL)
return(0);
c_line++;
s_line++;
p = get_label(label, p);
p = get_opcode(opcode, p);
p = get_arg(operand, p);
if (strcmp(opcode, ENDFILE) == 0) {
lst_line(pc, 0);
return(0);
}
if (*opcode) {
op = search_op(opcode);
op_count = (*op->op_fun)(op->op_c1, op->op_c2);
if (gencode) {
lst_line(pc, op_count);
obj_writeb(op_count);
pc += op_count;
} else {
sd_flag = 2;
lst_line(0, 0);
}
} else {
sd_flag = 2;
lst_line(0, 0);
}
return(1);
}
/*
* Oeffnen der Ausgabedateien: Objectdatei und bei Option
* -l der Listdatei. Der Dateiname der Quelldatei wird
* uebergeben. Die Dateinamen der Object- und Listdatei
* werden, wenn nicht hinter den Optionen -l und -o angegeben,
* aus dem Quelldateinamen erzeugt.
*/
open_o_files(source)
register char *source;
{
char *strcpy(), *strcat(), *strrchr();
register char *p;
if (*objfn == '\0')
strcpy(objfn, source);
if ((p = strrchr(objfn, '.')) != NULL)
strcpy(p, OBJEXT);
else
strcat(objfn, OBJEXT);
if (out_form == OUTHEX)
objfp = fopen(objfn, WRITEA);
else
objfp = fopen(objfn, WRITEB);
if (objfp == NULL)
fatal(F_FOPEN, objfn);
if (list_flag) {
if (*lstfn == '\0')
strcpy(lstfn, source);
if ((p = strrchr(lstfn, '.')) != NULL)
strcpy(p, LSTEXT);
else
strcat(lstfn, LSTEXT);
if ((lstfp = fopen(lstfn, WRITEA)) == NULL)
fatal(F_FOPEN, lstfn);
errfp = lstfp;
}
}
/*
* Einen Dateinamen in "dest" aus "src" und "ext" zusammenbauen
*/
get_fn(dest, src, ext)
char *dest, *src, *ext;
{
char *strrchr(), *strcat();
register int i;
register char *sp, *dp;
i = 0;
sp = src;
dp = dest;
while ((i++ < LENFN) && (*sp != '\0'))
*dp++ = *sp++;
*dp = '\0';
if ((strrchr(dest,'.') == NULL) && (strlen(dest) <= (LENFN-strlen(ext))))
strcat(dest, ext);
}
/*
* Extrahieren der Labels, Konstanten und Variablen aus
* einer Zeile Quelltext mit Umwandlung in Grosschrift
* und Begrenzung der Laenge.
*/
char *get_label(s, l)
register char *s, *l;
{
register int i;
i = 0;
if (*l == LINCOM)
goto comment;
while (!isspace(*l) && *l != COMMENT && *l != LABSEP && i < SYMSIZE) {
*s++ = islower(*l) ? toupper(*l++) : *l++;
i++;
}
comment:
*s = '\0';
return(l);
}
/*
* Extrahieren des Op-Codes aus einer Zeile Quelltext ab der
* uebergebenen Position. Der String wird bei der Uebertragung
* in Grosschrift umgewandelt.
*/
char *get_opcode(s, l)
register char *s, *l;
{
if (*l == LINCOM)
goto comment;
while (!isspace(*l) && *l != COMMENT && *l != LABSEP)
l++;
if (*l == LABSEP)
l++;
while (*l == ' ' || *l == '\t')
l++;
while (!isspace(*l) && *l != COMMENT)
*s++ = islower(*l) ? toupper(*l++) : *l++;
comment:
*s = '\0';
return(l);
}
/*
* Extrahieren des Operanden aus einer Zeile Quelltext ab der
* uebergebenen Position. Der String wird bei der Uebertragung
* in Grosschrift umgewandelt und Blanks sowie Tabs werden
* ueberlesen. Strings, die in ' eingeschlossen sind, werden
* ohne Aenderung kopiert.
*/
char *get_arg(s, l)
register char *s, *l;
{
if (*l == LINCOM)
goto comment;
while (*l == ' ' || *l == '\t')
l++;
while (*l != '\n' && *l != COMMENT) {
if (isspace(*l)) {
l++;
continue;
}
if (*l != STRSEP) {
*s++ = islower(*l) ? toupper(*l) : *l;
l++;
continue;
}
*s++ = *l++;
if (*(s - 2) == 'F') /* EX AF,AF' !!!!! */
continue;
while (*l != STRSEP) {
if (*l == '\n' || *l == '\0' || *l == COMMENT)
goto comment;
*s++ = *l++;
}
*s++ = *l++;
}
comment:
*s = '\0';
return(l);
}

317
z80asm/z80anum.c Normal file
View File

@ -0,0 +1,317 @@
/*
* 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 die numerischen
* Rechen- und Umwandlungsfunktionen.
*/
#include <stdio.h>
#include <ctype.h>
#include "z80a.h"
#include "z80aglb.h"
#ifndef isxdigit
#define isxdigit(c) (isdigit(c) || (c>='a' && c<='f') || (c>='A' && c<='F'))
#endif
/*
* Definition Operatoren-Symbole fuer den Expression-Parser
*/
#define OPEDEC 1 /* Dezimalzahl */
#define OPEHEX 2 /* Hexzahl */
#define OPEOCT 3 /* Octalzahl */
#define OPEBIN 4 /* Binaerzahl */
#define OPESUB 5 /* arithmetisches - */
#define OPEADD 6 /* arithmetisches + */
#define OPEMUL 7 /* arithmetisches * */
#define OPEDIV 8 /* arithmetisches / */
#define OPEMOD 9 /* arithmetisches Modulo */
#define OPESHL 10 /* logisches shift left */
#define OPESHR 11 /* logisches shift right */
#define OPELOR 12 /* logisches OR */
#define OPELAN 13 /* logisches AND */
#define OPEXOR 14 /* logisches XOR */
#define OPECOM 15 /* logisches Komplement */
#define OPESYM 99 /* Symbol */
/*
* Rekursiver Expression-Parser
*
* Input: Pointer auf den restlichen Argument-String
*
* Output: berechneter Wert
*/
eval(s)
register char *s;
{
register char *p;
register int val;
char word[MAXLINE];
struct sym *sp, *get_sym();
val = 0;
while (*s) {
p = word;
if (*s == '(') {
s++;
while (*s != ')') {
if (*s == '\0') {
asmerr(E_MISPAR);
goto eval_break;
}
*p++ = *s++;
}
*p = '\0';
s++;
val = eval(word);
continue;
}
if (*s == STRSEP) {
s++;
while (*s != STRSEP) {
if (*s == '\n' || *s == '\0') {
asmerr(E_MISHYP);
goto hyp_error;
}
*p++ = *s++;
}
s++;
hyp_error:
*p = '\0';
val = strval(word);
continue;
}
if (isari(*s))
*p++ = *s++;
else
while (!isspace(*s) && !isari(*s) && (*s != '\0'))
*p++ = *s++;
*p = '\0';
switch (get_type(word)) {
case OPESYM: /* Symbol */
if (strcmp(word, "$") == 0) {
val = pc;
break;
}
if (strlen(word) > SYMSIZE)
word[SYMSIZE] = '\0';
if ((sp = get_sym(word)) != NULL)
val = sp->sym_wert;
else
asmerr(E_UNDSYM);
break;
case OPEDEC: /* Dezimalzahl */
val = atoi(word);
break;
case OPEHEX: /* Hexzahl */
val = axtoi(word);
break;
case OPEBIN: /* Binaerzahl */
val = abtoi(word);
break;
case OPEOCT: /* Oktalzahl */
val = aotoi(word);
break;
case OPESUB: /* arithmetisches - */
val -= eval(s);
goto eval_break;
case OPEADD: /* arithmetisches + */
val += eval(s);
goto eval_break;
case OPEMUL: /* arithmetisches * */
val *= eval(s);
goto eval_break;
case OPEDIV: /* arithmetisches / */
val /= eval(s);
goto eval_break;
case OPEMOD: /* arithmetisches Modulo */
val %= eval(s);
goto eval_break;
case OPESHL: /* logisches shift left */
val <<= eval(s);
goto eval_break;
case OPESHR: /* logisches shift right */
val >>= eval(s);
goto eval_break;
case OPELOR: /* logisches OR */
val |= eval(s);
goto eval_break;
case OPELAN: /* logisches AND */
val &= eval(s);
goto eval_break;
case OPEXOR: /* logisches XOR */
val ^= eval(s);
goto eval_break;
case OPECOM: /* logisches Komplement */
val = ~(eval(s));
goto eval_break;
}
}
eval_break:
return(val);
}
/*
* Operanden Typ-Bestimmung
*
* Input: Pointer auf zu bestimmenden String
*
* Output: Operanden Typ
*/
get_type(s)
char *s;
{
if (isdigit(*s)) { /* numerischer Operand */
if (isdigit(*(s + strlen(s) - 1))) /* Dezimalzahl */
return(OPEDEC);
else if (*(s + strlen(s) - 1) == 'H') /* Hexzahl */
return(OPEHEX);
else if (*(s + strlen(s) - 1) == 'B') /* Binaerzahl */
return(OPEBIN);
else if (*(s + strlen(s) - 1) == 'O') /* Oktalzahl */
return(OPEOCT);
} else if (*s == '-') /* arithmetischer Operand - */
return(OPESUB);
else if (*s == '+') /* arithmetischer Operand + */
return(OPEADD);
else if (*s == '*') /* arithmetischer Operand * */
return(OPEMUL);
else if (*s == '/') /* arithmetischer Operand / */
return(OPEDIV);
else if (*s == '%') /* arithmetisches Modulo */
return(OPEMOD);
else if (*s == '<') /* logisches shift left */
return(OPESHL);
else if (*s == '>') /* logisches shift rigth */
return(OPESHR);
else if (*s == '|') /* logisches OR */
return(OPELOR);
else if (*s == '&') /* logisches AND */
return(OPELAN);
else if (*s == '^') /* logisches XOR */
return(OPEXOR);
else if (*s == '~') /* logisches Komplement */
return(OPECOM);
return(OPESYM); /* Operand ist ein Symbol */
}
/*
* Die Funktion prueft einen Character auf die arithmetischen
* Operatoren +, -, *, /, %, <, >, |, &, ~ und ^.
*/
isari(c)
register int c;
{
return((c) == '+' || (c) == '-' || (c) == '*' ||
(c) == '/' || (c) == '%' || (c) == '<' ||
(c) == '>' || (c) == '|' || (c) == '&' ||
(c) == '~' || (c) == '^');
}
/*
* Umwandlung eines ASCII-Strings mit einer Hexzahl in
* einen Integer.
* Format: nnnnH oder 0nnnnH wenn 1.Ziffer > 9
*/
axtoi(str)
register char *str;
{
register int num;
num = 0;
while (isxdigit(*str)) {
num *= 16;
num += *str - ((*str <= '9') ? '0' : '7');
str++;
}
return(num);
}
/*
* Umwandlung eines ASCII-Strings mit einer Oktalzahl in
* einen Integer.
* Format: nnnnO
*/
aotoi(str)
register char *str;
{
register int num;
num = 0;
while ('0' <= *str && *str <= '7') {
num *= 8;
num += (*str++) - '0';
}
return(num);
}
/*
* Umwandlung eines ASCII-Strings mit einer Binaerzahl in
* einen Integer.
* Format: nnnnnnnnnnnnnnnnB
*/
abtoi(str)
register char *str;
{
register int num;
num = 0;
while ('0' <= *str && *str <= '1') {
num *= 2;
num += (*str++) - '0';
}
return(num);
}
/*
* Umwandlung eines ASCII-Strings in einen Integer.
*/
strval(str)
register char *str;
{
register int num;
num = 0;
while (*str) {
num <<= 8;
num += (int) *str++;
}
return(num);
}
/*
* Die Funktion prueft einen Wert auf -256 < Wert < 256
* Output: Wert wenn im Bereich, sonst 0 und Fehlermeldung
*/
chk_v1(i)
register int i;
{
if (i >= -255 && i <= 255)
return(i);
else {
asmerr(E_VALOUT);
return(0);
}
}
/*
* Die Funktion prueft einen Wert auf -128 < Wert < 128
* Output: Wert wenn im Bereich, sonst 0 und Fehlermeldung
*/
chk_v2(i)
register int i;
{
if (i >= -127 && i <= 127)
return(i);
else {
asmerr(E_VALOUT);
return(0);
}
}

175
z80asm/z80aopc.c Normal file
View File

@ -0,0 +1,175 @@
/*
* 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
*/
/*
* Diese Modul enthaelt die Op-Code-Tabelle. In ihr
* sind fuer jeden Z80 Op-Code und alle Pseudo-Op-Codes
* ausser END Eintraege vorhanden. Die Tabelle muss
* aufsteigend nach den Op-Code-Namen sortiert sein !
*
* Die zweite Tabelle im Modul enthaelt die Namen aller
* reservierten Operanden (Register, Registerpaare und Flags.
* Sie muss ebenfalls nach den Namen sortiert sein !
*/
#include <stdio.h>
#include "z80a.h"
/*
* Die Funktionen zur Codegenerierung der einzelnen
* Op-Codes muessen forward deklariert werden:
*/
extern int op_1b(), op_2b(), op_pupo(), op_ex(), op_ld();
extern int op_call(), op_ret(), op_jp(), op_jr(), op_djnz(), op_rst();
extern int op_add(), op_adc(), op_sub(), op_sbc(), op_cp();
extern int op_inc(), op_dec(), op_or(), op_xor(), op_and();
extern int op_rl(), op_rr(), op_sla(), op_sra(), op_srl(), op_rlc(), op_rrc();
extern int op_out(), op_in(), op_im();
extern int op_set(), op_res(), op_bit();
extern int op_org(), op_dl(), op_equ();
extern int op_ds(), op_db(), op_dw(), op_dm();
extern int op_misc();
extern int op_cond();
extern int op_glob();
struct opc opctab[] = {
{ "ADC", op_adc, 0, 0 },
{ "ADD", op_add, 0, 0 },
{ "AND", op_and, 0, 0 },
{ "BIT", op_bit, 0, 0 },
{ "CALL", op_call, 0, 0 },
{ "CCF", op_1b, 0x3f, 0 },
{ "CP", op_cp, 0, 0 },
{ "CPD", op_2b, 0xed, 0xa9 },
{ "CPDR", op_2b, 0xed, 0xb9 },
{ "CPI", op_2b, 0xed, 0xa1 },
{ "CPIR", op_2b, 0xed, 0xb1 },
{ "CPL", op_1b, 0x2f, 0 },
{ "DAA", op_1b, 0x27, 0 },
{ "DEC", op_dec, 0, 0 },
{ "DEFB", op_db, 0, 0 },
{ "DEFL", op_dl, 0, 0 },
{ "DEFM", op_dm, 0, 0 },
{ "DEFS", op_ds, 0, 0 },
{ "DEFW", op_dw, 0, 0 },
{ "DI", op_1b, 0xf3, 0 },
{ "DJNZ", op_djnz, 0, 0 },
{ "EI", op_1b, 0xfb, 0 },
{ "EJECT", op_misc, 1, 0 },
{ "ELSE", op_cond, 98, 0 },
{ "ENDIF", op_cond, 99, 0 },
{ "EQU", op_equ, 0, 0 },
{ "EX", op_ex, 0, 0 },
{ "EXTRN", op_glob, 1, 0 },
{ "EXX", op_1b, 0xd9, 0 },
{ "HALT", op_1b, 0x76, 0 },
{ "IFDEF", op_cond, 1, 0 },
{ "IFEQ", op_cond, 3, 0 },
{ "IFNDEF", op_cond, 2, 0 },
{ "IFNEQ", op_cond, 4, 0 },
{ "IM", op_im, 0, 0 },
{ "IN", op_in, 0, 0 },
{ "INC", op_inc, 0, 0 },
{ "INCLUDE", op_misc, 6, 0 },
{ "IND", op_2b, 0xed, 0xaa },
{ "INDR", op_2b, 0xed, 0xba },
{ "INI", op_2b, 0xed, 0xa2 },
{ "INIR", op_2b, 0xed, 0xb2 },
{ "JP", op_jp, 0, 0 },
{ "JR", op_jr, 0, 0 },
{ "LD", op_ld, 0, 0 },
{ "LDD", op_2b, 0xed, 0xa8 },
{ "LDDR", op_2b, 0xed, 0xb8 },
{ "LDI", op_2b, 0xed, 0xa0 },
{ "LDIR", op_2b, 0xed, 0xb0 },
{ "LIST", op_misc, 2, 0 },
{ "NEG", op_2b, 0xed, 0x44 },
{ "NOLIST", op_misc, 3, 0 },
{ "NOP", op_1b, 0, 0 },
{ "OR", op_or, 0, 0 },
{ "ORG", op_org, 0, 0 },
{ "OTDR", op_2b, 0xed, 0xbb },
{ "OTIR", op_2b, 0xed, 0xb3 },
{ "OUT", op_out, 0, 0 },
{ "OUTD", op_2b, 0xed, 0xab },
{ "OUTI", op_2b, 0xed, 0xa3 },
{ "PAGE", op_misc, 4, 0 },
{ "POP", op_pupo, 1, 0 },
{ "PRINT", op_misc, 5, 0 },
{ "PUBLIC", op_glob, 2, 0 },
{ "PUSH", op_pupo, 2, 0 },
{ "RES", op_res, 0, 0 },
{ "RET", op_ret, 0, 0 },
{ "RETI", op_2b, 0xed, 0x4d },
{ "RETN", op_2b, 0xed, 0x45 },
{ "RL", op_rl, 0, 0 },
{ "RLA", op_1b, 0x17, 0 },
{ "RLC", op_rlc, 0, 0 },
{ "RLCA", op_1b, 0x07, 0 },
{ "RLD", op_2b, 0xed, 0x6f },
{ "RR", op_rr, 0, 0 },
{ "RRA", op_1b, 0x1f, 0 },
{ "RRC", op_rrc, 0, 0 },
{ "RRCA", op_1b, 0x0f, 0 },
{ "RRD", op_2b, 0xed, 0x67 },
{ "RST", op_rst, 0, 0 },
{ "SBC", op_sbc, 0, 0 },
{ "SCF", op_1b, 0x37, 0 },
{ "SET", op_set, 0, 0 },
{ "SLA", op_sla, 0, 0 },
{ "SRA", op_sra, 0, 0 },
{ "SRL", op_srl, 0, 0 },
{ "SUB", op_sub, 0, 0 },
{ "TITLE", op_misc, 7, 0 },
{ "XOR", op_xor, 0, 0 }
};
/*
* Die Anzahl der Eintraege in der Op-Code Tabelle wird fuer die
* Suchfunktion search_op() in der Variablen no_opcodes abgelegt.
*/
int no_opcodes = sizeof(opctab) / sizeof(struct opc);
struct ope opetab[] = {
{ "(BC)", REGIBC },
{ "(DE)", REGIDE },
{ "(HL)", REGIHL },
{ "(IX)", REGIIX },
{ "(IY)", REGIIY },
{ "(SP)", REGISP },
{ "A", REGA },
{ "AF", REGAF },
{ "B", REGB },
{ "BC", REGBC },
{ "C", REGC },
{ "D", REGD },
{ "DE", REGDE },
{ "E", REGE },
{ "H", REGH },
{ "HL", REGHL },
{ "I", REGI },
{ "IX", REGIX },
{ "IY", REGIY },
{ "L", REGL },
{ "M", FLGM },
{ "NC", FLGNC },
{ "NZ", FLGNZ },
{ "P", FLGP },
{ "PE", FLGPE },
{ "PO", FLGPO },
{ "R", REGR },
{ "SP", REGSP },
{ "Z", FLGZ }
};
/*
* Hier wird ebenfalls die Anzahl der Tabelleneintraege
* bekannt gemacht.
*/
int no_operands = sizeof(opetab) / sizeof(struct ope);

361
z80asm/z80aout.c Normal file
View File

@ -0,0 +1,361 @@
/*
* 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));
}

442
z80asm/z80apfun.c Normal file
View File

@ -0,0 +1,442 @@
/*
* 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 die Funktionen zur Bearbeitung
* aller Pseudo-Op-Codes
*/
#include <stdio.h>
#include <ctype.h>
#include "z80a.h"
#include "z80aglb.h"
/*
* Diese Funktion behandelt den Pseudo-Op-Code ORG
*/
op_org()
{
register int i;
if (!gencode)
return(0);
i = eval(operand);
if (i < pc) {
asmerr(E_MEMOVR);
return(0);
}
if (pass == 1) { /* PASS 1 */
if (!prg_flag) {
prg_adr = i;
prg_flag++;
}
} else { /* PASS 2 */
if (++prg_flag > 2)
obj_fill(i - pc);
sd_flag = 2;
}
pc = i;
return(0);
}
/*
* Diese Funktion behandelt den Pseudo-Op-Code EQU
*/
op_equ()
{
struct sym *get_sym();
if (!gencode)
return(0);
if (pass == 1) { /* Pass 1 */
if (get_sym(label) == NULL) {
sd_val = eval(operand);
if (put_sym(label, sd_val))
fatal(F_OUTMEM, "symbols");
} else
asmerr(E_MULSYM);
} else { /* Pass 2 */
sd_flag = 1;
sd_val = eval(operand);
}
return(0);
}
/*
* Diese Funktion behandelt den Pseudo-Op-Code DEFL
*/
op_dl()
{
if (!gencode)
return(0);
sd_flag = 1;
sd_val = eval(operand);
if (put_sym(label, sd_val))
fatal(F_OUTMEM, "symbols");
return(0);
}
/*
* Diese Funktion behandelt den Pseudo-Op-Code DEFS
*/
op_ds()
{
register int val;
if (!gencode)
return(0);
if (pass == 1)
if (*label)
put_label();
sd_val = pc;
sd_flag = 3;
val = eval(operand);
if (pass == 2)
obj_fill(val);
pc += val;
return(0);
}
/*
* Diese Funktion behandelt den Pseudo-Op-Code DEFB
*/
op_db()
{
register int i;
register char *p;
register char *s;
if (!gencode)
return(0);
i = 0;
p = operand;
if (pass == 1)
if (*label)
put_label();
while (*p) {
if (*p == STRSEP) {
p++;
while (*p != STRSEP) {
if (*p == '\n' || *p == '\0') {
asmerr(E_MISHYP);
goto hyp_error;
}
ops[i++] = *p++;
if (i >= OPCARRAY)
fatal(F_INTERN, "Op-Code buffer overflow");
}
p++;
} else {
s = tmp;
while (*p != ',' && *p != '\0')
*s++ = *p++;
*s = '\0';
ops[i++] = eval(tmp);
if (i >= OPCARRAY)
fatal(F_INTERN, "Op-Code buffer overflow");
}
if (*p == ',')
p++;
}
hyp_error:
return(i);
}
/*
* Diese Funktion behandelt den Pseudo-Op-Code DEFM
*/
op_dm()
{
register int i;
register char *p;
if (!gencode)
return(0);
i = 0;
p = operand;
if (pass == 1)
if (*label)
put_label();
if (*p != STRSEP) {
asmerr(E_MISHYP);
return(0);
}
p++;
while (*p != STRSEP) {
if (*p == '\n' || *p == '\0') {
asmerr(E_MISHYP);
break;
}
ops[i++] = *p++;
if (i >= OPCARRAY)
fatal(F_INTERN, "Op-Code buffer overflow");
}
return(i);
}
/*
* Diese Funktion behandelt den Pseudo-Op-Code DEFW
*/
op_dw()
{
register int i, len, temp;
register char *p;
register char *s;
if (!gencode)
return(0);
p = operand;
i = len = 0;
if (pass == 1)
if (*label)
put_label();
while (*p) {
s = tmp;
while (*p != ',' && *p != '\0')
*s++ = *p++;
*s = '\0';
if (pass == 2) {
temp = eval(tmp);
ops[i++] = temp & 0xff;
ops[i++] = temp >> 8;
if (i >= OPCARRAY)
fatal(F_INTERN, "Op-Code buffer overflow");
}
len += 2;
if (*p == ',')
p++;
}
return(len);
}
/*
* Diese Funktion behandelt die Pseudo-Op-Codes
* EJECT, LIST, NOLIST, PAGE, PRINT, TITLE, INCLUDE
*/
op_misc(op_code, dummy)
int op_code, dummy;
{
register char *p, *d;
static char fn[LENFN];
static int incnest;
static struct inc incl[INCNEST];
if (!gencode)
return(0);
sd_flag = 2;
switch(op_code) {
case 1: /* EJECT */
if (pass == 2)
p_line = ppl;
break;
case 2: /* LIST */
if (pass == 2)
list_flag = 1;
break;
case 3: /* NOLIST */
if (pass == 2)
list_flag = 0;
break;
case 4: /* PAGE */
if (pass == 2)
ppl = eval(operand);
break;
case 5: /* PRINT */
if (pass == 1) {
p = operand;
while (*p) {
if (*p != STRSEP)
putchar(*p++);
else
p++;
}
putchar('\n');
}
break;
case 6: /* INCLUDE */
if (incnest >= INCNEST) {
asmerr(E_INCNEST);
break;
}
incl[incnest].inc_line = c_line;
incl[incnest].inc_fn = srcfn;
incl[incnest].inc_fp = srcfp;
incnest++;
p = line;
d = fn;
while(isspace(*p)) /* white space bis INCLUDE ueberlesen */
p++;
while(!isspace(*p)) /* INCLUDE ueberlesen */
p++;
while(isspace(*p)) /* white space bis Filename ueberlesen */
p++;
while(!isspace(*p) && *p != COMMENT) /* Filename uebernehmen */
*d++ = *p++;
*d = '\0';
if (pass == 1) { /* PASS 1 */
if (!ver_flag)
printf(" Include %s\n", fn);
p1_file(fn);
} else { /* PASS 2 */
sd_flag = 2;
lst_line(0, 0);
if (!ver_flag)
printf(" Include %s\n", fn);
p2_file(fn);
}
incnest--;
c_line = incl[incnest].inc_line;
srcfn = incl[incnest].inc_fn;
srcfp = incl[incnest].inc_fp;
printf(" Resume %s\n", srcfn);
if (list_flag && (pass == 2)) {
lst_header();
lst_attl();
}
sd_flag = 4;
break;
case 7: /* TITLE */
if (pass == 2) {
p = line;
d = title;
while (isspace(*p)) /* white space bis TITLE ueberlesen */
p++;
while (!isspace(*p)) /* TITLE ueberlesen */
p++;
while (isspace(*p)) /* white space bis Titel ueberlesen */
p++;
if (*p == STRSEP)
p++;
while (*p != '\n' && *p != STRSEP && *p != COMMENT)
*d++ = *p++;
*d = '\0';
}
break;
default:
fatal(F_INTERN, "illegal opcode for function op_misc");
break;
}
return(0);
}
/*
* Diese Funktion behandelt die Pseudo-Op-Codes
* IFDEF, IFNDEF, IFEQ, IFNEQ, ELSE, ENDIF
*/
op_cond(op_code, dummy)
int op_code, dummy;
{
register char *p, *p1, *p2;
static int condnest[IFNEST];
struct sym *get_sym();
char *strchr();
switch(op_code) {
case 1: /* IFDEF */
if (iflevel >= IFNEST) {
asmerr(E_IFNEST);
break;
}
condnest[iflevel++] = gencode;
if (gencode)
if (get_sym(operand) == NULL)
gencode = 0;
break;
case 2: /* IFNDEF */
if (iflevel >= IFNEST) {
asmerr(E_IFNEST);
break;
}
condnest[iflevel++] = gencode;
if (gencode)
if (get_sym(operand) != NULL)
gencode = 0;
break;
case 3: /* IFEQ */
if (iflevel >= IFNEST) {
asmerr(E_IFNEST);
break;
}
condnest[iflevel++] = gencode;
p = operand;
if (!*p || !(p1 = strchr(operand, ','))) {
asmerr(E_MISOPE);
break;
}
if (gencode) {
p2 = tmp;
while (*p != ',')
*p2++ = *p++;
*p2 = '\0';
if (eval(tmp) != eval(++p1))
gencode = 0;
}
break;
case 4: /* IFNEQ */
if (iflevel >= IFNEST) {
asmerr(E_IFNEST);
break;
}
condnest[iflevel++] = gencode;
p = operand;
if (!*p || !(p1 = strchr(operand, ','))) {
asmerr(E_MISOPE);
break;
}
if (gencode) {
p2 = tmp;
while (*p != ',')
*p2++ = *p++;
*p2 = '\0';
if (eval(tmp) == eval(++p1))
gencode = 0;
}
break;
case 98: /* ELSE */
if (!iflevel)
asmerr(E_MISIFF);
else
if ((iflevel == 0) || (condnest[iflevel - 1] == 1))
gencode = !gencode;
break;
case 99: /* ENDIF */
if (!iflevel)
asmerr(E_MISIFF);
else
gencode = condnest[--iflevel];
break;
default:
fatal(F_INTERN, "illegal opcode for function op_cond");
break;
}
sd_flag = 2;
return(0);
}
/*
* Diese Funktion behandelt die Pseudo-Op-Codes
* EXTRN und PUBLIC
*/
op_glob(op_code, dummy)
int op_code, dummy;
{
if (!gencode)
return(0);
sd_flag = 2;
switch(op_code) {
case 1: /* EXTRN */
break;
case 2: /* PUBLIC */
break;
default:
fatal(F_INTERN, "illegal opcode for function op_glob");
break;
}
return(0);
}

3329
z80asm/z80arfun.c Normal file

File diff suppressed because it is too large Load Diff

272
z80asm/z80atab.c Normal file
View File

@ -0,0 +1,272 @@
/*
* 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 Operationen, die die
* Tabellen durchsuchen oder veraendern.
*/
#include <stdio.h>
#include "z80a.h"
#include "z80aglb.h"
/* Die folgende Funktion fuehrt die binaere Suche
* in der alphabetisch sortierten OP-Code-Tabelle
* 'opctab' aus.
*
* Input: Zeiger auf String mit dem OP-Code
*
* Output: Zeiger auf das Tabellenelement oder
* einen NULL-Pointer, wenn OP-Code
* nicht gefunden
*/
struct opc *search_op(op_name)
register char *op_name;
{
register int cond;
register struct opc *low, *high, *mid;
low = &opctab[0];
high = &opctab[no_opcodes - 1];
while (low <= high) {
mid = low + (high - low) / 2;
if ((cond = strcmp(op_name, mid->op_name)) < 0)
high = mid - 1;
else if (cond > 0)
low = mid + 1;
else
return(mid);
}
return(NULL);
}
/* Die folgende Funktion fuehrt die binaere Suche
* in der alphabetisch sortierten Operanden-Tabelle
* 'opetab' aus.
*
* Input: Zeiger auf String mit dem Operanden
*
* Output: Symbol fuer den Operanden
* NOOPERA, wenn Operand leer ist
* NOREG, wenn Operand nicht gefunden
*/
get_reg(s)
register char *s;
{
register int cond;
register struct ope *low, *high, *mid;
if (s == NULL || *s == '\0')
return(NOOPERA);
low = &opetab[0];
high = &opetab[no_operands - 1];
while (low <= high) {
mid = low + (high - low) / 2;
if ((cond = strcmp(s, mid->ope_name)) < 0)
high = mid - 1;
else if (cond > 0)
low = mid + 1;
else
return(mid->ope_sym);
}
return(NOREG);
}
/* Die folgende Funktion fuehrt die Suche in der Symboltabelle
* 'symtab' durch. Dazu wird ein HASH-Algorithmus verwendet.
*
* Input: Zeiger auf String mit dem Symbol
*
* Output: Zeiger auf das Tabellenelement oder
* einen NULL-Pointer, wenn Symbol
* nicht gefunden
*/
struct sym *get_sym(sym_name)
register char *sym_name;
{
register struct sym *np;
for (np = symtab[hash(sym_name)]; np != NULL; np = np->sym_next)
if (strcmp(sym_name, np->sym_name) == 0)
return(np);
return(NULL);
}
/* Die folgende Funktion traegt ein Symbol in die Symboltabelle
* 'symtab' ein. Ist das Symbol in der Tabelle noch nicht
* vorhanden, wird es neu angelegt, sonst wird 'sym_wert'
* in den vorhandenen Eintrag uebernommen.
* Fuer die Symboltabellen-Zugriffe wird ein HASH-Algorithmus
* verwendet.
*
* Input: sym_name Zeiger auf String mit dem Symbol
* sym_wert Wert des Symbols
*
* Output: 0 = eingetragen
* 1 = kein Speicherplatz mehr frei
*/
put_sym(sym_name, sym_wert)
char *sym_name;
int sym_wert;
{
char *strsave(), *malloc();
struct sym *get_sym();
register int hashval;
register struct sym *np;
if (!gencode)
return(0);
if ((np = get_sym(sym_name)) == NULL) {
np = (struct sym *) malloc(sizeof (struct sym));
if (np == NULL)
return(1);
if ((np->sym_name = strsave(sym_name)) == NULL)
return(1);
hashval = hash(sym_name);
np->sym_next = symtab[hashval];
symtab[hashval] = np;
}
np->sym_wert = sym_wert;
return(0);
}
/*
* Diese Funktion traegt ein Label in die Symboltabelle ein.
* Vorher wird geprueft, ob dieses Symbol bereits vorhanden
* ist, was zu einer entsprechenden Fehlermeldung fuehrt.
*/
put_label()
{
struct sym *get_sym();
if (get_sym(label) == NULL) {
if (put_sym(label, pc))
fatal(F_OUTMEM, "symbols");
} else
asmerr(E_MULSYM);
}
/* Hier folget der HASH-Algorithmus selbst.
*
* Input: Zeiger auf String mit dem Namen
*
* Output: HASH-Wert
*/
hash(name)
register char *name;
{
register int hashval;
for (hashval = 0; *name;)
hashval += *name++;
return(hashval % HASHSIZE);
}
/* Diese Funktion kopiert einen String auf einen
* angeforderten Speicherplatz.
*
* Input: Zeiger auf den String
*
* Output: Zeiger auf den Speicherplatz
*/
char *strsave(s)
register char *s;
{
char *malloc(), *strcpy();
register char *p;
if ((p = malloc((unsigned) strlen(s)+1)) != NULL)
strcpy(p, s);
return(p);
}
/*
* Diese Funktion kopiert alle Eintraege aus der
* Symbol-Hashtabelle in ein dynamisch erzeugtes
* Pointer-Array
*/
copy_sym()
{
char *malloc(), *realloc();
register int i, j;
register struct sym *np;
symarray = (struct sym **) malloc(SYMINC * sizeof(struct sym *));
if (symarray == NULL)
fatal(F_OUTMEM, "sorting symbol table");
symsize = SYMINC;
for (i = 0, j = 0; i < HASHSIZE; i++) {
if (symtab[i] != NULL) {
for (np = symtab[i]; np != NULL; np = np->sym_next) {
symarray[j++] = np;
if (j == symsize) {
symarray = (struct sym **) realloc((char *) symarray, symsize * sizeof(struct sym *) + SYMINC * sizeof(struct sym *));
if (symarray == NULL)
fatal(F_OUTMEM, "sorting symbol table");
symsize += SYMINC;
}
}
}
}
return(j);
}
/*
* Symboltabelle nach Namen sortieren
*/
n_sort_sym(len)
register int len;
{
register int gap, i, j;
register struct sym *temp;
for (gap = len/2; gap > 0; gap /= 2)
for (i = gap; i < len; i++)
for (j = i-gap; j >= 0; j -= gap) {
if (strcmp(symarray[j]->sym_name, symarray[j+gap]->sym_name) <= 0)
break;
temp = symarray[j];
symarray[j] = symarray[j+gap];
symarray[j+gap] = temp;
}
}
/*
* Symboltabelle nach Adressen sortieren
*/
a_sort_sym(len)
register int len;
{
register int gap, i, j;
register struct sym *temp;
for (gap = len/2; gap > 0; gap /= 2)
for (i = gap; i < len; i++)
for (j = i-gap; j >= 0; j -= gap) {
if (numcmp(symarray[j]->sym_wert, symarray[j+gap]->sym_wert) <= 0)
break;
temp = symarray[j];
symarray[j] = symarray[j+gap];
symarray[j+gap] = temp;
}
}
/*
* Vergleicht zwei 16-Bit Werte, Ergebnis wie strcmp
*/
numcmp(n1, n2)
register int n1, n2;
{
if ((unsigned) (n1 & 0xffff) < (unsigned) (n2 & 0xffff))
return(-1);
else if ((unsigned) (n1 & 0xffff) > (unsigned) (n2 & 0xffff))
return(1);
else
return(0);
}