mirror of
https://github.com/bobbimanners/Zapple-II.git
synced 2024-06-12 16:29:28 +00:00
Initial commit of z80asm (without Apple II mods.)
This commit is contained in:
parent
109a8caafa
commit
8696185cae
41
z80asm/Makefile
Normal file
41
z80asm/Makefile
Normal 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
78
z80asm/README
Normal 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
46
z80asm/license.de
Normal 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
41
z80asm/license.us
Normal 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
146
z80asm/z80a.h
Normal 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
64
z80asm/z80aglb.c
Normal 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
60
z80asm/z80aglb.h
Normal 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
498
z80asm/z80amain.c
Normal 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
317
z80asm/z80anum.c
Normal 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
175
z80asm/z80aopc.c
Normal 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
361
z80asm/z80aout.c
Normal 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
442
z80asm/z80apfun.c
Normal 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
3329
z80asm/z80arfun.c
Normal file
File diff suppressed because it is too large
Load Diff
272
z80asm/z80atab.c
Normal file
272
z80asm/z80atab.c
Normal 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);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user