diff --git a/z80asm/Makefile b/z80asm/Makefile new file mode 100644 index 0000000..106e3b1 --- /dev/null +++ b/z80asm/Makefile @@ -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 diff --git a/z80asm/README b/z80asm/README new file mode 100644 index 0000000..9c04b4e --- /dev/null +++ b/z80asm/README @@ -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 - set program address + EQU - define constant symbol + DEFL - define variable symbol + DEFB - write bytes in memory + DEFW - write words (16 bits) in memory + DEFM <'string'> - write character string in memory + DEFS - reserve space in memory + + +Conditional assembly: + +IFDEF - assemble if symbol defined +IFNDEF - assemble if symbol not defined +IFEQ - assemble if equal +IFNEQ - assemble if not equal +ELSE - else for all conditionals +ENDIF - end of conditional assembly + + +Manipulation of list file: + +PAGE - number of lines/page +EJECT - skip to new page +LIST - listing on +NOLIST - listing off +TITLE <'string'> - define title for page header + + +Others: + +INCLUDE - include another source file +PRINT <'string'> - print string to stdout in pass one diff --git a/z80asm/license.de b/z80asm/license.de new file mode 100644 index 0000000..488f693 --- /dev/null +++ b/z80asm/license.de @@ -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 diff --git a/z80asm/license.us b/z80asm/license.us new file mode 100644 index 0000000..674f59f --- /dev/null +++ b/z80asm/license.us @@ -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 diff --git a/z80asm/z80a.h b/z80asm/z80a.h new file mode 100644 index 0000000..c18d5ba --- /dev/null +++ b/z80asm/z80a.h @@ -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 */ diff --git a/z80asm/z80aglb.c b/z80asm/z80aglb.c new file mode 100644 index 0000000..d67b936 --- /dev/null +++ b/z80asm/z80aglb.c @@ -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 +#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 , Daten aus */ + /* = 1: Adresse aus , Daten aus */ + /* = 2: keine Adresse, Daten aus */ + /* = 3: Adresse aus , 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 */ diff --git a/z80asm/z80aglb.h b/z80asm/z80aglb.h new file mode 100644 index 0000000..9615ba2 --- /dev/null +++ b/z80asm/z80aglb.h @@ -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[]; diff --git a/z80asm/z80amain.c b/z80asm/z80amain.c new file mode 100644 index 0000000..f47d33f --- /dev/null +++ b/z80asm/z80amain.c @@ -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 +#include +#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); +} diff --git a/z80asm/z80anum.c b/z80asm/z80anum.c new file mode 100644 index 0000000..47b7c17 --- /dev/null +++ b/z80asm/z80anum.c @@ -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 +#include +#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); + } +} diff --git a/z80asm/z80aopc.c b/z80asm/z80aopc.c new file mode 100644 index 0000000..a57cf9d --- /dev/null +++ b/z80asm/z80aopc.c @@ -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 +#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); diff --git a/z80asm/z80aout.c b/z80asm/z80aout.c new file mode 100644 index 0000000..8fb6ef4 --- /dev/null +++ b/z80asm/z80aout.c @@ -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 +#include "z80a.h" +#include "z80aglb.h" + +static char *errmsg[] = { /* Fehlermeldungen fuer asmerr() */ + "illegal opcode", /* 0 */ + "illegal operand", /* 1 */ + "missing operand", /* 2 */ + "multiply defined symbol", /* 3 */ + "undefined symbol", /* 4 */ + "value out of range", /* 5 */ + "missing )", /* 6 */ + "missing string separator", /* 7 */ + "memory override", /* 8 */ + "missing IF", /* 9 */ + "IF nesting to deep", /* 10 */ + "missing ENDIF", /* 11 */ + "INCLUDE nesting to deep" /* 12 */ +}; + +#define MAXHEX 32 /* maximale Anzahl Bytes/Hex-Record */ + +static unsigned short hex_adr; /* aktuelle Adresse Hex-Record */ +static int hex_cnt; /* aktuelle Anzahl Bytes im Hex-Puffer */ + +static unsigned char hex_buf[MAXHEX]; /* Code-Puffer fuer einen Hex-Record */ +static char hex_out[MAXHEX*2+11]; /* ASCII-Puffer fuer einen Hex-Record */ + +/* + * Fehlermeldungen auf den Fehlerkanal (Listfile oder stdout) + * ausgeben und Fehlerzaehler erhoehen. + */ +asmerr(i) +register int i; +{ + if (pass == 1) { + fprintf(errfp, "Error in file: %s Line: %d\n", srcfn, c_line); + fprintf(errfp, errmsg[i]); + fprintf(errfp, "\n\n"); + } else + errnum = i; + errors++; +} + +/* + * Die Funktion beginnt eine neue Seite in der Listdatei + */ +lst_header() +{ + fprintf(lstfp, "\fZ80-Assembler\t\tRelease %s\t\t\t\tPage %d\n", REL, ++page); + fprintf(lstfp, "Source file: %s\n", srcfn); + fprintf(lstfp, "Title: %s\n", title); + p_line = 3; +} + +/* + * Ueberschrift fuer die Quellzeilen erzeugen + */ +lst_attl() +{ + fprintf(lstfp, "\nLOC OBJECT CODE LINE STMT SOURCE CODE\n"); + p_line += 2; +} + +/* + * Eine Zeile in der Listdatei erzeugen, + * wenn Option -l gegeben. + */ +lst_line(val, opanz) +register int val, opanz; +{ + register int i; + + if (!list_flag || sd_flag == 4) { + sd_flag = 0; + return; + } + if ((p_line >= ppl) || (c_line == 1)) { + lst_header(); + lst_attl(); + } + switch (sd_flag) { + case 0: + fprintf(lstfp, "%04x ", val & 0xffff); + break; + case 1: + fprintf(lstfp, "%04x ", sd_val & 0xffff); + break; + case 2: + fprintf(lstfp, " "); + break; + case 3: + fprintf(lstfp, "%04x ", sd_val & 0xffff); + goto no_data; + default: + fatal(F_INTERN, "illegal listflag for function lst_line"); + break; + } + if (opanz >= 1) fprintf(lstfp, "%02x ", ops[0] & 0xff); + else fprintf(lstfp, " "); + if (opanz >= 2) fprintf(lstfp, "%02x ", ops[1] & 0xff); + else fprintf(lstfp, " "); + if (opanz >= 3) fprintf(lstfp, "%02x ", ops[2] & 0xff); + else fprintf(lstfp, " "); + if (opanz >= 4) fprintf(lstfp, "%02x ", ops[3] & 0xff); + else fprintf(lstfp, " "); + no_data: + fprintf(lstfp, "%6d %6d %s", c_line, s_line, line); + if (errnum) { + fprintf(errfp, "=> %s", errmsg[errnum]); + putc('\n', errfp); + errnum = 0; + p_line++; + } + sd_flag = 0; + p_line++; + if (opanz > 4 && sd_flag == 0) { + opanz -= 4; + i = 4; + sd_val = val; + while (opanz > 0) { + if (p_line >= ppl) { + lst_header(); + lst_attl(); + } + s_line++; + sd_val += 4; + fprintf(lstfp, "%04x ", sd_val & 0xffff); + if (opanz-- > 0) fprintf(lstfp, "%02x ", ops[i++] & 0xff); + else fprintf(lstfp, " "); + if (opanz-- > 0) fprintf(lstfp, "%02x ", ops[i++] & 0xff); + else fprintf(lstfp, " "); + if (opanz-- > 0) fprintf(lstfp, "%02x ", ops[i++] & 0xff); + else fprintf(lstfp, " "); + if (opanz-- > 0) fprintf(lstfp, "%02x ", ops[i++] & 0xff); + else fprintf(lstfp, " "); + fprintf(lstfp, "%6d %6d\n", c_line, s_line); + p_line++; + } + } +} + +/* + * Symboltabelle ins Listfile in der gespeicherten + * Reihenfolge direkt aus der Hash-Tabelle ausgeben + */ +lst_sym() +{ + register int i, j; + register struct sym *np; + char *strcpy(); + + p_line = j = 0; + strcpy(title,"Symboltable"); + for (i = 0; i < HASHSIZE; i++) { + if (symtab[i] != NULL) { + for (np = symtab[i]; np != NULL; np = np->sym_next) { + if (p_line == 0) { + lst_header(); + fputs("\n", lstfp); + p_line += 1; + } + fprintf(lstfp, "%-8s %04x\t", np->sym_name, + np->sym_wert & 0xffff); + if (++j == 4) { + fprintf(lstfp, "\n"); + if (p_line++ >= ppl) + p_line = 0; + j = 0; + } + } + } + } +} + +/* + * Sortierte Symboltabelle ins Listfile ausgeben + */ +lst_sort_sym(len) +register int len; +{ + register int i, j; + char *strcpy(); + + p_line = i = j = 0; + strcpy(title, "Symboltable"); + while (i < len) { + if (p_line == 0) { + lst_header(); + fputs("\n", lstfp); + p_line += 1; + } + fprintf(lstfp, "%-8s %04x\t", symarray[i]->sym_name, + symarray[i]->sym_wert & 0xffff); + if (++j == 4) { + fprintf(lstfp, "\n"); + if (p_line++ >= ppl) + p_line = 0; + j = 0; + } + i++; + } +} + +/* + * Header-Record ins Objectfile ausgeben + */ +obj_header() +{ + switch (out_form) { + case OUTBIN: + break; + case OUTMOS: + putc(0xff, objfp); + putc(prg_adr & 0xff, objfp); + putc(prg_adr >> 8, objfp); + break; + case OUTHEX: + hex_adr = prg_adr; + break; + } +} + +/* + * Ende-Record ins Objectfile ausgeben + */ +obj_end() +{ + switch (out_form) { + case OUTBIN: + break; + case OUTMOS: + break; + case OUTHEX: + flush_hex(); + fprintf(objfp, ":0000000000\n"); + break; + } +} + +/* + * Op-Codes in ops[] ins Objectfile ausgeben + */ +obj_writeb(opanz) +register int opanz; +{ + register int i; + + switch (out_form) { + case OUTBIN: + fwrite(ops, 1, opanz, objfp); + break; + case OUTMOS: + fwrite(ops, 1, opanz, objfp); + break; + case OUTHEX: + for (i = 0; opanz; opanz--) { + if (hex_cnt >= MAXHEX) + flush_hex(); + hex_buf[hex_cnt++] = ops[i++]; + } + break; + } +} + +/* + * Bytes mit 0xff ins Objectfile ausgeben + */ +obj_fill(count) +register int count; +{ + switch (out_form) { + case OUTBIN: + while (count--) + putc(0xff, objfp); + break; + case OUTMOS: + while (count--) + putc(0xff, objfp); + break; + case OUTHEX: + flush_hex(); + hex_adr += count; + break; + } +} + +/* + * Einen Hex-Record in ASCII erzeugen und ausgeben + */ +flush_hex() +{ + char *p; + register int i; + + if (!hex_cnt) + return; + p = hex_out; + *p++ = ':'; + btoh((unsigned char) hex_cnt, &p); + btoh((unsigned char) (hex_adr >> 8), &p); + btoh((unsigned char) (hex_adr & 0xff), &p); + *p++ = '0'; + *p++ = '0'; + for (i = 0; i < hex_cnt; i++) + btoh(hex_buf[i], &p); + btoh((unsigned char) chksum(), &p); + *p++ = '\n'; + *p = '\0'; + fwrite(hex_out, 1, strlen(hex_out), objfp); + hex_adr += hex_cnt; + hex_cnt = 0; +} + +/* + * Ein unsigned char in ASCII-Hex umwandeln und an Adresse, + * auf die p zeigt, ablegen. Der Pointer p wird dann um + * zwei erhoeht. + */ +btoh(byte, p) +unsigned char byte; +register char **p; +{ + register unsigned char c; + + c = byte >> 4; + *(*p)++ = (c < 10) ? (c + '0') : (c - 10 + 'A'); + c = byte & 0xf; + *(*p)++ = (c < 10) ? (c + '0') : (c - 10 + 'A'); +} + +/* + * Pruefsumme fuer einen Intel-Hex-Record berechnen + */ +chksum() +{ + register int i, j, sum; + + sum = hex_cnt; + sum += hex_adr >> 8; + sum += hex_adr & 0xff; + for (i = 0; i < hex_cnt; i++) { + j = hex_buf[i]; + sum += j & 0xff; + } + return (0x100 - (sum & 0xff)); +} diff --git a/z80asm/z80apfun.c b/z80asm/z80apfun.c new file mode 100644 index 0000000..4045cb5 --- /dev/null +++ b/z80asm/z80apfun.c @@ -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 +#include +#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); +} diff --git a/z80asm/z80arfun.c b/z80asm/z80arfun.c new file mode 100644 index 0000000..96af9c3 --- /dev/null +++ b/z80asm/z80arfun.c @@ -0,0 +1,3329 @@ +/* + * 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 Op-Codes + */ + +#include +#include "z80a.h" +#include "z80aglb.h" + +/* + * Diese Funktion behandelt alle Op-Codes, + * die keine Argumente benoetigen, und + * ein Byte Op-Code Laenge haben + */ +op_1b(b1, dummy) +int b1, dummy; +{ + if (pass == 1) { /* Pass 1 */ + if (*label) + put_label(); + } else /* Pass 2 */ + ops[0] = b1; + return(1); +} + +/* + * Diese Funktion behandelt alle Op-Codes, + * die keine Argumente benoetigen, und + * zwei Byte Op-Code Laenge haben + */ +op_2b(b1, b2) +int b1, b2; +{ + if (pass == 1) { /* Pass 1 */ + if (*label) + put_label(); + } else { /* Pass 2 */ + ops[0] = b1; + ops[1] = b2; + } + return(2); +} + +/* + * Diese Funktion behandelt die Op-Codes IM + */ +op_im() +{ + if (pass == 1) + if (*label) + put_label(); + if (pass == 2) { + ops[0] = 0xed; + switch(eval(operand)) { + case 0: + ops[1] = 0x46; + break; + case 1: + ops[1] = 0x56; + break; + case 2: + ops[1] = 0x5e; + break; + default: + ops[1] = 0; + asmerr(E_ILLOPE); + break; + } + } + return(2); +} + +/* + * Diese Funktion behandelt die Op-Codes PUSH und POP + */ +op_pupo(op_code, dummy) +int op_code, dummy; +{ + register int len; + + if (pass == 1) + if (*label) + put_label(); + switch (get_reg(operand)) { + case REGAF: + if (pass == 2) { + if (op_code == 1) + ops[0] = 0xf1; /* POP AF */ + else + ops[0] = 0xf5; /* PUSH AF */ + } + len = 1; + break; + case REGBC: + if (pass == 2) { + if (op_code == 1) + ops[0] = 0xc1; /* POP BC */ + else + ops[0] = 0xc5; /* PUSH BC */ + } + len = 1; + break; + case REGDE: + if (pass == 2) { + if (op_code == 1) + ops[0] = 0xd1; /* POP DE */ + else + ops[0] = 0xd5; /* PUSH DE */ + } + len = 1; + break; + case REGHL: + if (pass == 2) { + if (op_code == 1) + ops[0] = 0xe1; /* POP HL */ + else + ops[0] = 0xe5; /* PUSH HL */ + } + len = 1; + break; + case REGIX: + if (pass == 2) { + if (op_code == 1) { + ops[0] = 0xdd; /* POP IX */ + ops[1] = 0xe1; + } else { + ops[0] = 0xdd; /* PUSH IX */ + ops[1] = 0xe5; + } + } + len = 2; + break; + case REGIY: + if (pass == 2) { + if (op_code == 1) { + ops[0] = 0xfd; /* POP IY */ + ops[1] = 0xe1; + } else { + ops[0] = 0xfd; /* PUSH IY */ + ops[1] = 0xe5; + } + } + len = 2; + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Diese Funktion behandelt den EX Op-Code + */ +op_ex() +{ + register int len; + + if (pass == 1) + if (*label) + put_label(); + if (strncmp(operand, "DE,HL", 5) == 0) { + ops[0] = 0xeb; + len = 1; + } else if (strncmp(operand, "AF,AF'", 7) == 0) { + ops[0] = 0x08; + len = 1; + } else if (strncmp(operand, "(SP),HL", 7) == 0) { + ops[0] = 0xe3; + len = 1; + } else if (strncmp(operand, "(SP),IX", 7) == 0) { + ops[0] = 0xdd; + ops[1] = 0xe3; + len = 2; + } else if (strncmp(operand, "(SP),IY", 7) == 0) { + ops[0] = 0xfd; + ops[1] = 0xe3; + len = 2; + } else { + ops[0] = 0; + len = 1; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Diese Funktion behandelt den CALL Op-Code + */ +op_call() +{ + char *strchr(); + register char *p1, *p2; + register int i; + + if (pass == 1) { /* PASS 1 */ + if (*label) + put_label(); + } else { /* PASS 2 */ + p1 = operand; + p2 = tmp; + while (*p1 != ',' && *p1 != '\0') + *p2++ = *p1++; + *p2 = '\0'; + switch (get_reg(tmp)) { + case REGC: /* CALL C,nn */ + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xdc; + ops[1] = i & 0xff; + ops[2] = i >> 8; + break; + case FLGNC: /* CALL NC,nn */ + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xd4; + ops[1] = i & 0xff; + ops[2] = i >> 8; + break; + case FLGZ: /* CALL Z,nn */ + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xcc; + ops[1] = i & 0xff; + ops[2] = i >> 8; + break; + case FLGNZ: /* CALL NZ,nn */ + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xc4; + ops[1] = i & 0xff; + ops[2] = i >> 8; + break; + case FLGPE: /* CALL PE,nn */ + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xec; + ops[1] = i & 0xff; + ops[2] = i >> 8; + break; + case FLGPO: /* CALL PO,nn */ + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xe4; + ops[1] = i & 0xff; + ops[2] = i >> 8; + break; + case FLGM: /* CALL M,nn */ + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xfc; + ops[1] = i & 0xff; + ops[2] = i >> 8; + break; + case FLGP: /* CALL P,nn */ + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xf4; + ops[1] = i & 0xff; + ops[2] = i >> 8; + break; + case NOREG: /* CALL nn */ + i = eval(operand); + ops[0] = 0xcd; + ops[1] = i & 0xff; + ops[2] = i >> 8; + break; + case NOOPERA: /* Operand fehlt */ + ops[0] = 0; + ops[1] = 0; + ops[2] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + ops[0] = 0; + ops[1] = 0; + ops[2] = 0; + asmerr(E_ILLOPE); + } + } + return(3); +} + +/* + * Diese Funktion behandelt den RST Op-Code + */ +op_rst() +{ + register int op; + + if (pass == 1) { /* PASS 1 */ + if (*label) + put_label(); + } else { /* PASS 2 */ + op = eval(operand); + if ((op / 8 > 7) || (op % 8 != 0)) { + ops[0] = 0; + asmerr(E_VALOUT); + } else + ops[0] = 0xc7 + op; + } + return(1); +} + +/* + * Diese Funktion behandelt den RET Op-Code + */ +op_ret() +{ + if (pass == 1) { /* PASS 1 */ + if (*label) + put_label(); + } else { /* PASS 2 */ + switch (get_reg(operand)) { + case NOOPERA: /* RET */ + ops[0] = 0xc9; + break; + case REGC: /* RET C */ + ops[0] = 0xd8; + break; + case FLGNC: /* RET NC */ + ops[0] = 0xd0; + break; + case FLGZ: /* RET Z */ + ops[0] = 0xc8; + break; + case FLGNZ: /* RET NZ */ + ops[0] = 0xc0; + break; + case FLGPE: /* RET PE */ + ops[0] = 0xe8; + break; + case FLGPO: /* RET PO */ + ops[0] = 0xe0; + break; + case FLGM: /* RET M */ + ops[0] = 0xf8; + break; + case FLGP: /* RET P */ + ops[0] = 0xf0; + break; + default: /* ungueltiger Operand */ + ops[0] = 0; + asmerr(E_ILLOPE); + } + } + return(1); +} + +/* + * Diese Funktion behandelt den JP Op-Code + */ +op_jp() +{ + char *strchr(); + register char *p1, *p2; + register int i, len; + + if (pass == 1) + if (*label) + put_label(); + p1 = operand; + p2 = tmp; + while (*p1 != ',' && *p1 != '\0') + *p2++ = *p1++; + *p2 = '\0'; + switch (get_reg(tmp)) { + case REGC: /* JP C,nn */ + len = 3; + if (pass == 2) { + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xda; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case FLGNC: /* JP NC,nn */ + len = 3; + if (pass == 2) { + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xd2; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case FLGZ: /* JP Z,nn */ + len = 3; + if (pass == 2) { + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xca; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case FLGNZ: /* JP NZ,nn */ + len = 3; + if (pass == 2) { + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xc2; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case FLGPE: /* JP PE,nn */ + len = 3; + if (pass == 2) { + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xea; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case FLGPO: /* JP PO,nn */ + len = 3; + if (pass == 2) { + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xe2; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case FLGM: /* JP M,nn */ + len = 3; + if (pass == 2) { + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xfa; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case FLGP: /* JP P,nn */ + len = 3; + if (pass == 2) { + i = eval(strchr(operand, ',') + 1); + ops[0] = 0xf2; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case REGIHL: /* JP (HL) */ + ops[0] = 0xe9; + len = 1; + break; + case REGIIX: /* JP (IX) */ + ops[0] = 0xdd; + ops[1] = 0xe9; + len = 2; + break; + case REGIIY: /* JP (IY) */ + ops[0] = 0xfd; + ops[1] = 0xe9; + len = 2; + break; + case NOREG: /* JP nn */ + len = 3; + if (pass == 2) { + i = eval(operand); + ops[0] = 0xc3; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case NOOPERA: /* Operand fehlt */ + ops[0] = 0; + len = 1; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + ops[0] = 0; + len = 1; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Diese Funktion behandelt den JR Op-Code + */ +op_jr() +{ + char *strchr(); + register char *p1, *p2; + + if (pass == 1) { /* PASS 1 */ + if (*label) + put_label(); + } else { /* PASS 2 */ + p1 = operand; + p2 = tmp; + while (*p1 != ',' && *p1 != '\0') + *p2++ = *p1++; + *p2 = '\0'; + switch (get_reg(tmp)) { + case REGC: /* JR C,n */ + ops[0] = 0x38; + ops[1] = chk_v2(eval(strchr(operand, ',') + 1) - pc - 2); + break; + case FLGNC: /* JR NC,n */ + ops[0] = 0x30; + ops[1] = chk_v2(eval(strchr(operand, ',') + 1) - pc - 2); + break; + case FLGZ: /* JR Z,n */ + ops[0] = 0x28; + ops[1] = chk_v2(eval(strchr(operand, ',') + 1) - pc - 2); + break; + case FLGNZ: /* JR NZ,n */ + ops[0] = 0x20; + ops[1] = chk_v2(eval(strchr(operand, ',') + 1) - pc - 2); + break; + case NOREG: /* JR n */ + ops[0] = 0x18; + ops[1] = chk_v2(eval(operand) - pc - 2); + break; + case NOOPERA: /* Operand fehlt */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_ILLOPE); + } + } + return(2); +} + +/* + * Diese Funktion behandelt den DJNZ Op-Code + */ +op_djnz() +{ + if (pass == 1) { /* PASS 1 */ + if (*label) + put_label(); + } else { /* PASS 2 */ + ops[0] = 0x10; + ops[1] = chk_v2(eval(operand) - pc - 2); + } + return(2); +} + +/* + * Diese Funktion behandelt die LD Op-Codes + */ +op_ld() +{ + register int len; + register char *p1, *p2; + char *get_second(); + + if (pass == 1) + if (*label) + put_label(); + p1 = operand; + p2 = tmp; + while (*p1 != ',' && *p1 != '\0') + *p2++ = *p1++; + *p2 = '\0'; + switch (get_reg(tmp)) { + case REGA: /* LD A,? */ + len = lda(); + break; + case REGB: /* LD B,? */ + len = ldb(); + break; + case REGC: /* LD C,? */ + len = ldc(); + break; + case REGD: /* LD D,? */ + len = ldd(); + break; + case REGE: /* LD E,? */ + len = lde(); + break; + case REGH: /* LD H,? */ + len = ldh(); + break; + case REGL: /* LD L,? */ + len = ldl(); + break; + case REGI: /* LD I,A */ + if (get_reg(get_second(operand)) == REGA) { + len = 2; + ops[0] = 0xed; + ops[1] = 0x47; + break; + } + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + break; + case REGR: /* LD R,A */ + if (get_reg(get_second(operand)) == REGA) { + len = 2; + ops[0] = 0xed; + ops[1] = 0x4f; + break; + } + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + break; + case REGBC: /* LD BC,? */ + len = ldbc(); + break; + case REGDE: /* LD DE,? */ + len = ldde(); + break; + case REGHL: /* LD HL,? */ + len = ldhl(); + break; + case REGIX: /* LD IX,? */ + len = ldix(); + break; + case REGIY: /* LD IY,? */ + len = ldiy(); + break; + case REGSP: /* LD SP,? */ + len = ldsp(); + break; + case REGIHL: /* LD (HL),? */ + len = ldihl(); + break; + case REGIBC: /* LD (BC),A */ + if (get_reg(get_second(operand)) == REGA) { + len = 1; + ops[0] = 0x02; + break; + } + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + break; + case REGIDE: /* LD (DE),A */ + if (get_reg(get_second(operand)) == REGA) { + len = 1; + ops[0] = 0x12; + break; + } + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + if (strncmp(operand, "(IX+", 4) == 0) + len = ldiix(); /* LD (IX+d),? */ + else if (strncmp(operand, "(IY+", 4) == 0) + len = ldiiy(); /* LD (IY+d),? */ + else if (*operand == '(') + len = ldinn(); /* LD (nn),? */ + else { + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD A,? + */ +lda() +{ + char *get_second(), *strchr(); + register int op; + register int i, len; + register char *p; + + p = get_second(operand); + switch (op = get_reg(p)) { + case REGA: /* LD A,A */ + case REGB: /* LD A,B */ + case REGC: /* LD A,C */ + case REGD: /* LD A,D */ + case REGE: /* LD A,E */ + case REGH: /* LD A,H */ + case REGL: /* LD A,L */ + case REGIHL: /* LD A,(HL) */ + len = 1; + ops[0] = 0x78 + op; + break; + case REGI: /* LD A,I */ + len = 2; + ops[0] = 0xed; + ops[1] = 0x57; + break; + case REGR: /* LD A,R */ + len = 2; + ops[0] = 0xed; + ops[1] = 0x5f; + break; + case REGIBC: /* LD A,(BC) */ + len = 1; + ops[0] = 0x0a; + break; + case REGIDE: /* LD A,(DE) */ + len = 1; + ops[0] = 0x1a; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(p, "(IX+", 4) == 0) { /* LD A,(IX+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x7e; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + if (strncmp(p, "(IY+", 4) == 0) { /* LD A,(IY+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x7e; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + if (*p == '(' && *(p + strlen(p) - 1) == ')') { + len = 3; /* LD A,(nn) */ + if (pass == 2) { + i = calc_val(p + 1); + ops[0] = 0x3a; + ops[1] = i & 255; + ops[2] = i >> 8; + } + break; + } + len = 2; /* LD A,n */ + if (pass == 2) { + ops[0] = 0x3e; + ops[1] = chk_v1(eval(p)); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD B,? + */ +ldb() +{ + char *get_second(), *strchr(); + register int op; + register int len; + register char *p; + + p = get_second(operand); + switch (op = get_reg(p)) { + case REGA: /* LD B,A */ + case REGB: /* LD B,B */ + case REGC: /* LD B,C */ + case REGD: /* LD B,D */ + case REGE: /* LD B,E */ + case REGH: /* LD B,H */ + case REGL: /* LD B,L */ + case REGIHL: /* LD B,(HL) */ + len = 1; + ops[0] = 0x40 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(p, "(IX+", 4) == 0) { /* LD B,(IX+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x46; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + if (strncmp(p, "(IY+", 4) == 0) { /* LD B,(IY+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x46; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + len = 2; /* LD B,n */ + if (pass == 2) { + ops[0] = 0x06; + ops[1] = chk_v1(eval(p)); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD C,? + */ +ldc() +{ + char *get_second(), *strchr(); + register int op; + register int len; + register char *p; + + p = get_second(operand); + switch (op = get_reg(p)) { + case REGA: /* LD C,A */ + case REGB: /* LD C,B */ + case REGC: /* LD C,C */ + case REGD: /* LD C,D */ + case REGE: /* LD C,E */ + case REGH: /* LD C,H */ + case REGL: /* LD C,L */ + case REGIHL: /* LD C,(HL) */ + len = 1; + ops[0] = 0x48 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(p, "(IX+", 4) == 0) { /* LD C,(IX+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x4e; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + if (strncmp(p, "(IY+", 4) == 0) { /* LD C,(IY+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x4e; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + len = 2; /* LD C,n */ + if (pass == 2) { + ops[0] = 0x0e; + ops[1] = chk_v1(eval(p)); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD D,? + */ +ldd() +{ + char *get_second(), *strchr(); + register int op; + register int len; + register char *p; + + p = get_second(operand); + switch (op = get_reg(p)) { + case REGA: /* LD D,A */ + case REGB: /* LD D,B */ + case REGC: /* LD D,C */ + case REGD: /* LD D,D */ + case REGE: /* LD D,E */ + case REGH: /* LD D,H */ + case REGL: /* LD D,L */ + case REGIHL: /* LD D,(HL) */ + len = 1; + ops[0] = 0x50 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(p, "(IX+", 4) == 0) { /* LD D,(IX+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x56; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + if (strncmp(p, "(IY+", 4) == 0) { /* LD D,(IY+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x56; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + len = 2; /* LD D,n */ + if (pass == 2) { + ops[0] = 0x16; + ops[1] = chk_v1(eval(p)); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD E,? + */ +lde() +{ + char *get_second(), *strchr(); + register int op; + register int len; + register char *p; + + p = get_second(operand); + switch (op = get_reg(p)) { + case REGA: /* LD E,A */ + case REGB: /* LD E,B */ + case REGC: /* LD E,C */ + case REGD: /* LD E,D */ + case REGE: /* LD E,E */ + case REGH: /* LD E,H */ + case REGL: /* LD E,L */ + case REGIHL: /* LD E,(HL) */ + len = 1; + ops[0] = 0x58 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(p, "(IX+", 4) == 0) { /* LD E,(IX+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x5e; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + if (strncmp(p, "(IY+", 4) == 0) { /* LD E,(IY+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x5e; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + len = 2; /* LD E,n */ + if (pass == 2) { + ops[0] = 0x1e; + ops[1] = chk_v1(eval(p)); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD H,? + */ +ldh() +{ + char *get_second(), *strchr(); + register int op; + register int len; + register char *p; + + p = get_second(operand); + switch (op = get_reg(p)) { + case REGA: /* LD H,A */ + case REGB: /* LD H,B */ + case REGC: /* LD H,C */ + case REGD: /* LD H,D */ + case REGE: /* LD H,E */ + case REGH: /* LD H,H */ + case REGL: /* LD H,L */ + case REGIHL: /* LD H,(HL) */ + len = 1; + ops[0] = 0x60 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(p, "(IX+", 4) == 0) { /* LD H,(IX+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x66; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + if (strncmp(p, "(IY+", 4) == 0) { /* LD H,(IY+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x66; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + len = 2; /* LD H,n */ + if (pass == 2) { + ops[0] = 0x26; + ops[1] = chk_v1(eval(p)); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD L,? + */ +ldl() +{ + char *get_second(), *strchr(); + register int op; + register int len; + register char *p; + + p = get_second(operand); + switch (op = get_reg(p)) { + case REGA: /* LD L,A */ + case REGB: /* LD L,B */ + case REGC: /* LD L,C */ + case REGD: /* LD L,D */ + case REGE: /* LD L,E */ + case REGH: /* LD L,H */ + case REGL: /* LD L,L */ + case REGIHL: /* LD L,(HL) */ + len = 1; + ops[0] = 0x68 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(p, "(IX+", 4) == 0) { /* LD L,(IX+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x6e; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + if (strncmp(p, "(IY+", 4) == 0) { /* LD L,(IY+d) */ + len = 3; + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x6e; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + break; + } + len = 2; /* LD L,n */ + if (pass == 2) { + ops[0] = 0x2e; + ops[1] = chk_v1(eval(p)); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD BC,? + */ +ldbc() +{ + register int i, len; + register char *p; + char *get_second(); + + p = get_second(operand); + switch (get_reg(p)) { + case NOREG: /* Operand ist kein Register */ + if (*p == '(' && *(p + strlen(p) - 1) == ')') { + len = 4; /* LD BC,(nn) */ + if (pass == 2) { + i = calc_val(p + 1); + ops[0] = 0xed; + ops[1] = 0x4b; + ops[2] = i & 0xff; + ops[3] = i >> 8; + } + break; + } + len = 3; /* LD BC,nn */ + if (pass == 2) { + i = eval(p); + ops[0] = 0x01; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD DE,? + */ +ldde() +{ + register int i, len; + register char *p; + char *get_second(); + + p = get_second(operand); + switch (get_reg(p)) { + case NOREG: /* Operand ist kein Register */ + if (*p == '(' && *(p + strlen(p) - 1) == ')') { + len = 4; /* LD DE,(nn) */ + if (pass == 2) { + i = calc_val(p + 1); + ops[0] = 0xed; + ops[1] = 0x5b; + ops[2] = i & 0xff; + ops[3] = i >> 8; + } + break; + } + len = 3; /* LD DE,nn */ + if (pass == 2) { + i = eval(p); + ops[0] = 0x11; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD HL,? + */ +ldhl() +{ + register int i, len; + register char *p; + char *get_second(); + + p = get_second(operand); + switch (get_reg(p)) { + case NOREG: /* Operand ist kein Register */ + if (*p == '(' && *(p + strlen(p) - 1) == ')') { + len = 3; /* LD HL,(nn) */ + if (pass == 2) { + i = calc_val(p + 1); + ops[0] = 0x2a; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + } + len = 3; /* LD HL,nn */ + if (pass == 2) { + i = eval(p); + ops[0] = 0x21; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD IX,? + */ +ldix() +{ + register int i, len; + register char *p; + char *get_second(); + + p = get_second(operand); + switch (get_reg(p)) { + case NOREG: /* Operand ist kein Register */ + if (*p == '(' && *(p + strlen(p) - 1) == ')') { + len = 4; /* LD IX,(nn) */ + if (pass == 2) { + i = calc_val(p + 1); + ops[0] = 0xdd; + ops[1] = 0x2a; + ops[2] = i & 0xff; + ops[3] = i >> 8; + } + break; + } + len = 4; /* LD IX,nn */ + if (pass == 2) { + i = eval(p); + ops[0] = 0xdd; + ops[1] = 0x21; + ops[2] = i & 0xff; + ops[3] = i >> 8; + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD IY,? + */ +ldiy() +{ + register int i, len; + register char *p; + char *get_second(); + + p = get_second(operand); + switch (get_reg(p)) { + case NOREG: /* Operand ist kein Register */ + if (*p == '(' && *(p + strlen(p) - 1) == ')') { + len = 4; /* LD IY,(nn) */ + if (pass == 2) { + i = calc_val(p + 1); + ops[0] = 0xfd; + ops[1] = 0x2a; + ops[2] = i & 0xff; + ops[3] = i >> 8; + } + break; + } + len = 4; /* LD IY,nn */ + if (pass == 2) { + i = eval(p); + ops[0] = 0xfd; + ops[1] = 0x21; + ops[2] = i & 0xff; + ops[3] = i >> 8; + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD SP,? + */ +ldsp() +{ + register int i, len; + register char *p; + char *get_second(); + + p = get_second(operand); + switch (get_reg(p)) { + case REGHL: /* LD SP,HL */ + len = 1; + ops[0] = 0xf9; + break; + case REGIX: /* LD SP,IX */ + len = 2; + ops[0] = 0xdd; + ops[1] = 0xf9; + break; + case REGIY: /* LD SP,IY */ + len = 2; + ops[0] = 0xfd; + ops[1] = 0xf9; + break; + case NOREG: /* Operand ist kein Register */ + if (*p == '(' && *(p + strlen(p) - 1) == ')') { + len = 4; /* LD SP,(nn) */ + if (pass == 2) { + i = calc_val(p + 1); + ops[0] = 0xed; + ops[1] = 0x7b; + ops[2] = i & 0xff; + ops[3] = i >> 8; + } + break; + } + len = 3; /* LD SP,nn */ + if (pass == 2) { + i = eval(p); + ops[0] = 0x31; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD (HL),? + */ +ldihl() +{ + register int op; + register int len; + register char *p; + char *get_second(); + + p = get_second(operand); + switch (op = get_reg(p)) { + case REGA: /* LD (HL),A */ + case REGB: /* LD (HL),B */ + case REGC: /* LD (HL),C */ + case REGD: /* LD (HL),D */ + case REGE: /* LD (HL),E */ + case REGH: /* LD (HL),H */ + case REGL: /* LD (HL),L */ + len = 1; + ops[0] = 0x70 + op; + break; + case NOREG: /* Operand ist kein Register */ + len = 2; /* LD (HL),n */ + if (pass == 2) { + ops[0] = 0x36; + ops[1] = chk_v1(eval(p)); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD (IX+d),? + */ +ldiix() +{ + char *get_second(), *strchr(); + register int op; + register int len; + register char *p; + + p = get_second(operand); + switch (op = get_reg(p)) { + case REGA: /* LD (IX+d),A */ + case REGB: /* LD (IX+d),B */ + case REGC: /* LD (IX+d),C */ + case REGD: /* LD (IX+d),D */ + case REGE: /* LD (IX+d),E */ + case REGH: /* LD (IX+d),H */ + case REGL: /* LD (IX+d),L */ + len = 3; + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x70 + op; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + break; + case NOREG: /* LD (IX+d),n */ + len = 4; + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x36; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = chk_v1(eval(p)); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD (IY+d),? + */ +ldiiy() +{ + char *get_second(), *strchr(); + register int op; + register int len; + register char *p; + + p = get_second(operand); + switch (op = get_reg(p)) { + case REGA: /* LD (IY+d),A */ + case REGB: /* LD (IY+d),B */ + case REGC: /* LD (IY+d),C */ + case REGD: /* LD (IY+d),D */ + case REGE: /* LD (IY+d),E */ + case REGH: /* LD (IY+d),H */ + case REGL: /* LD (IY+d),L */ + len = 3; + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x70 + op; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + break; + case NOREG: /* LD (IY+d),n */ + len = 4; + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x36; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = chk_v1(eval(p)); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes LD (nn),? + */ +ldinn() +{ + register int i, len; + register char *p; + char *get_second(); + + p = get_second(operand); + switch (get_reg(p)) { + case REGA: /* LD (nn),A */ + len = 3; + if (pass == 2) { + i = calc_val(operand + 1); + ops[0] = 0x32; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case REGBC: /* LD (nn),BC */ + len = 4; + if (pass == 2) { + i = calc_val(operand + 1); + ops[0] = 0xed; + ops[1] = 0x43; + ops[2] = i & 0xff; + ops[3] = i >> 8; + } + break; + case REGDE: /* LD (nn),DE */ + len = 4; + if (pass == 2) { + i = calc_val(operand + 1); + ops[0] = 0xed; + ops[1] = 0x53; + ops[2] = i & 0xff; + ops[3] = i >> 8; + } + break; + case REGHL: /* LD (nn),HL */ + len = 3; + if (pass == 2) { + i = calc_val(operand + 1); + ops[0] = 0x22; + ops[1] = i & 0xff; + ops[2] = i >> 8; + } + break; + case REGSP: /* LD (nn),SP */ + len = 4; + if (pass == 2) { + i = calc_val(operand + 1); + ops[0] = 0xed; + ops[1] = 0x73; + ops[2] = i & 0xff; + ops[3] = i >> 8; + } + break; + case REGIX: /* LD (nn),IX */ + len = 4; + if (pass == 2) { + i = calc_val(operand + 1); + ops[0] = 0xdd; + ops[1] = 0x22; + ops[2] = i & 0xff; + ops[3] = i >> 8; + } + break; + case REGIY: /* LD (nn),IY */ + len = 4; + if (pass == 2) { + i = calc_val(operand + 1); + ops[0] = 0xfd; + ops[1] = 0x22; + ops[2] = i & 0xff; + ops[3] = i >> 8; + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes ADD ?,? + */ +op_add() +{ + register int len; + register char *p1, *p2; + + if (pass == 1) + if (*label) + put_label(); + p1 = operand; + p2 = tmp; + while (*p1 != ',' && *p1 != '\0') + *p2++ = *p1++; + *p2 = '\0'; + switch (get_reg(tmp)) { + case REGA: /* ADD A,? */ + len = adda(); + break; + case REGHL: /* ADD HL,? */ + len = addhl(); + break; + case REGIX: /* ADD IX,? */ + len = addix(); + break; + case REGIY: /* ADD IY,? */ + len = addiy(); + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes ADD A,? + */ +adda() +{ + char *get_second(), *strchr(); + register int op; + register int len; + register char *p; + + p = get_second(operand); + switch (op = get_reg(p)) { + case REGA: /* ADD A,A */ + case REGB: /* ADD A,B */ + case REGC: /* ADD A,C */ + case REGD: /* ADD A,D */ + case REGE: /* ADD A,E */ + case REGH: /* ADD A,H */ + case REGL: /* ADD A,L */ + case REGIHL: /* ADD A,(HL) */ + len = 1; + ops[0] = 0x80 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(p, "(IX+", 4) == 0) { + len = 3; /* ADD A,(IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x86; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + } else if (strncmp(p, "(IY+", 4) == 0) { + len = 3; /* ADD A,(IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x86; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + } else { + len = 2; /* ADD A,n */ + if (pass == 2) { + ops[0] = 0xc6; + ops[1] = chk_v1(eval(p)); + } + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes ADD HL,? + */ +addhl() +{ + char *get_second(); + + switch (get_reg(get_second(operand))) { + case REGBC: /* ADD HL,BC */ + ops[0] = 0x09; + break; + case REGDE: /* ADD HL,DE */ + ops[0] = 0x19; + break; + case REGHL: /* ADD HL,HL */ + ops[0] = 0x29; + break; + case REGSP: /* ADD HL,SP */ + ops[0] = 0x39; + break; + case NOOPERA: /* Operand fehlt */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_ILLOPE); + } + return(1); +} + +/* + * Die Funktion behandelt alle Op-Codes ADD IX,? + */ +addix() +{ + char *get_second(); + + switch (get_reg(get_second(operand))) { + case REGBC: /* ADD IX,BC */ + ops[0] = 0xdd; + ops[1] = 0x09; + break; + case REGDE: /* ADD IX,DE */ + ops[0] = 0xdd; + ops[1] = 0x19; + break; + case REGIX: /* ADD IX,IX */ + ops[0] = 0xdd; + ops[1] = 0x29; + break; + case REGSP: /* ADD IX,SP */ + ops[0] = 0xdd; + ops[1] = 0x39; + break; + case NOOPERA: /* Operand fehlt */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_ILLOPE); + } + return(2); +} + +/* + * Die Funktion behandelt alle Op-Codes ADD IY,? + */ +addiy() +{ + char *get_second(); + + switch (get_reg(get_second(operand))) { + case REGBC: /* ADD IY,BC */ + ops[0] = 0xfd; + ops[1] = 0x09; + break; + case REGDE: /* ADD IY,DE */ + ops[0] = 0xfd; + ops[1] = 0x19; + break; + case REGIY: /* ADD IY,IY */ + ops[0] = 0xfd; + ops[1] = 0x29; + break; + case REGSP: /* ADD IY,SP */ + ops[0] = 0xfd; + ops[1] = 0x39; + break; + case NOOPERA: /* Operand fehlt */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_ILLOPE); + } + return(2); +} + +/* + * Die Funktion behandelt alle Op-Codes ADC ?,? + */ +op_adc() +{ + register int len; + register char *p1, *p2; + + if (pass == 1) + if (*label) + put_label(); + p1 = operand; + p2 = tmp; + while (*p1 != ',' && *p1 != '\0') + *p2++ = *p1++; + *p2 = '\0'; + switch (get_reg(tmp)) { + case REGA: /* ADC A,? */ + len = adca(); + break; + case REGHL: /* ADC HL,? */ + len = adchl(); + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes ADC A,? + */ +adca() +{ + char *get_second(), *strchr(); + register int op; + register int len; + register char *p; + + p = get_second(operand); + switch (op = get_reg(p)) { + case REGA: /* ADC A,A */ + case REGB: /* ADC A,B */ + case REGC: /* ADC A,C */ + case REGD: /* ADC A,D */ + case REGE: /* ADC A,E */ + case REGH: /* ADC A,H */ + case REGL: /* ADC A,L */ + case REGIHL: /* ADC A,(HL) */ + len = 1; + ops[0] = 0x88 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(p, "(IX+", 4) == 0) { + len = 3; /* ADC A,(IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x8e; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + } else if (strncmp(p, "(IY+", 4) == 0) { + len = 3; /* ADC A,(IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x8e; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + } else { + len = 2; /* ADD A,n */ + if (pass == 2) { + ops[0] = 0xce; + ops[1] = chk_v1(eval(p)); + } + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes ADC HL,? + */ +adchl() +{ + char *get_second(); + + switch (get_reg(get_second(operand))) { + case REGBC: /* ADC HL,BC */ + ops[0] = 0xed; + ops[1] = 0x4a; + break; + case REGDE: /* ADC HL,DE */ + ops[0] = 0xed; + ops[1] = 0x5a; + break; + case REGHL: /* ADC HL,HL */ + ops[0] = 0xed; + ops[1] = 0x6a; + break; + case REGSP: /* ADC HL,SP */ + ops[0] = 0xed; + ops[1] = 0x7a; + break; + case NOOPERA: /* Operand fehlt */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_ILLOPE); + } + return(2); +} + +/* + * Die Funktion behandelt alle Op-Codes SUB ? + */ +op_sub() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* SUB A */ + case REGB: /* SUB B */ + case REGC: /* SUB C */ + case REGD: /* SUB D */ + case REGE: /* SUB E */ + case REGH: /* SUB H */ + case REGL: /* SUB L */ + case REGIHL: /* SUB (HL) */ + len = 1; + ops[0] = 0x90 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 3; /* SUB (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x96; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 3; /* SUB (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x96; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else { + len = 2; /* SUB n */ + if (pass == 2) { + ops[0] = 0xd6; + ops[1] = chk_v1(eval(operand)); + } + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes SBC ?,? + */ +op_sbc() +{ + register int len; + register char *p1, *p2; + + if (pass == 1) + if (*label) + put_label(); + p1 = operand; + p2 = tmp; + while (*p1 != ',' && *p1 != '\0') + *p2++ = *p1++; + *p2 = '\0'; + switch (get_reg(tmp)) { + case REGA: /* SBC A,? */ + len = sbca(); + break; + case REGHL: /* SBC HL,? */ + len = sbchl(); + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes SBC A,? + */ +sbca() +{ + char *get_second(), *strchr(); + register int op; + register int len; + register char *p; + + p = get_second(operand); + switch (op = get_reg(p)) { + case REGA: /* SBC A,A */ + case REGB: /* SBC A,B */ + case REGC: /* SBC A,C */ + case REGD: /* SBC A,D */ + case REGE: /* SBC A,E */ + case REGH: /* SBC A,H */ + case REGL: /* SBC A,L */ + case REGIHL: /* SBC A,(HL) */ + len = 1; + ops[0] = 0x98 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(p, "(IX+", 4) == 0) { + len = 3; /* SBC A,(IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x9e; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + } else if (strncmp(p, "(IY+", 4) == 0) { + len = 3; /* SBC A,(IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x9e; + ops[2] = chk_v2(calc_val(strchr(p, '+') + 1)); + } + } else { + len = 2; /* SBC A,n */ + if (pass == 2) { + ops[0] = 0xde; + ops[1] = chk_v1(eval(p)); + } + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes SBC HL,? + */ +sbchl() +{ + char *get_second(); + + switch (get_reg(get_second(operand))) { + case REGBC: /* SBC HL,BC */ + ops[0] = 0xed; + ops[1] = 0x42; + break; + case REGDE: /* SBC HL,DE */ + ops[0] = 0xed; + ops[1] = 0x52; + break; + case REGHL: /* SBC HL,HL */ + ops[0] = 0xed; + ops[1] = 0x62; + break; + case REGSP: /* SBC HL,SP */ + ops[0] = 0xed; + ops[1] = 0x72; + break; + case NOOPERA: /* Operand fehlt */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_ILLOPE); + } + return(2); +} + +/* + * Die Funktion behandelt alle Op-Codes INC ? + */ +op_inc() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* INC A */ + case REGB: /* INC B */ + case REGC: /* INC C */ + case REGD: /* INC D */ + case REGE: /* INC E */ + case REGH: /* INC H */ + case REGL: /* INC L */ + case REGIHL: /* INC (HL) */ + len = 1; + ops[0] = 0x04 + (op << 3); + break; + case REGBC: /* INC BC */ + len = 1; + ops[0] = 0x03; + break; + case REGDE: /* INC DE */ + len = 1; + ops[0] = 0x13; + break; + case REGHL: /* INC HL */ + len = 1; + ops[0] = 0x23; + break; + case REGSP: /* INC SP */ + len = 1; + ops[0] = 0x33; + break; + case REGIX: /* INC IX */ + len = 2; + ops[0] = 0xdd; + ops[1] = 0x23; + break; + case REGIY: /* INC IY */ + len = 2; + ops[0] = 0xfd; + ops[1] = 0x23; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 3; /* INC (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x34; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 3; /* INC (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x34; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else { + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes DEC ? + */ +op_dec() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* DEC A */ + case REGB: /* DEC B */ + case REGC: /* DEC C */ + case REGD: /* DEC D */ + case REGE: /* DEC E */ + case REGH: /* DEC H */ + case REGL: /* DEC L */ + case REGIHL: /* DEC (HL) */ + len = 1; + ops[0] = 0x05 + (op << 3); + break; + case REGBC: /* DEC BC */ + len = 1; + ops[0] = 0x0b; + break; + case REGDE: /* DEC DE */ + len = 1; + ops[0] = 0x1b; + break; + case REGHL: /* DEC HL */ + len = 1; + ops[0] = 0x2b; + break; + case REGSP: /* DEC SP */ + len = 1; + ops[0] = 0x3b; + break; + case REGIX: /* DEC IX */ + len = 2; + ops[0] = 0xdd; + ops[1] = 0x2b; + break; + case REGIY: /* DEC IY */ + len = 2; + ops[0] = 0xfd; + ops[1] = 0x2b; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 3; /* DEC (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0x35; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 3; /* DEC (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0x35; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else { + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes OR ? + */ +op_or() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* OR A */ + case REGB: /* OR B */ + case REGC: /* OR C */ + case REGD: /* OR D */ + case REGE: /* OR E */ + case REGH: /* OR H */ + case REGL: /* OR L */ + case REGIHL: /* OR (HL) */ + len = 1; + ops[0] = 0xb0 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 3; /* OR (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xb6; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 3; /* OR (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xb6; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else { + len = 2; /* OR n */ + if (pass == 2) { + ops[0] = 0xf6; + ops[1] = chk_v1(eval(operand)); + } + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes XOR ? + */ +op_xor() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* XOR A */ + case REGB: /* XOR B */ + case REGC: /* XOR C */ + case REGD: /* XOR D */ + case REGE: /* XOR E */ + case REGH: /* XOR H */ + case REGL: /* XOR L */ + case REGIHL: /* XOR (HL) */ + len = 1; + ops[0] = 0xa8 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 3; /* XOR (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xae; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 3; /* XOR (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xae; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else { + len = 2; /* XOR n */ + if (pass == 2) { + ops[0] = 0xee; + ops[1] = chk_v1(eval(operand)); + } + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes AND ? + */ +op_and() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* AND A */ + case REGB: /* AND B */ + case REGC: /* AND C */ + case REGD: /* AND D */ + case REGE: /* AND E */ + case REGH: /* AND H */ + case REGL: /* AND L */ + case REGIHL: /* AND (HL) */ + len = 1; + ops[0] = 0xa0 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 3; /* AND (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xa6; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 3; /* AND (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xa6; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else { + len = 2; /* AND n */ + if (pass == 2) { + ops[0] = 0xe6; + ops[1] = chk_v1(eval(operand)); + } + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt alle Op-Codes CP ? + */ +op_cp() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* CP A */ + case REGB: /* CP B */ + case REGC: /* CP C */ + case REGD: /* CP D */ + case REGE: /* CP E */ + case REGH: /* CP H */ + case REGL: /* CP L */ + case REGIHL: /* CP (HL) */ + len = 1; + ops[0] = 0xb8 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 3; /* CP (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xbe; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 3; /* CP (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xbe; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + } + } else { + len = 2; /* OR n */ + if (pass == 2) { + ops[0] = 0xfe; + ops[1] = chk_v1(eval(operand)); + } + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt den RL Op-Code + */ +op_rl() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* RL A */ + case REGB: /* RL B */ + case REGC: /* RL C */ + case REGD: /* RL D */ + case REGE: /* RL E */ + case REGH: /* RL H */ + case REGL: /* RL L */ + case REGIHL: /* RL (HL) */ + len = 2; + ops[0] = 0xcb; + ops[1] = 0x10 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 4; /* RL (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x16; + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 4; /* RL (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x16; + } + } else { + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt den RR Op-Code + */ +op_rr() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* RR A */ + case REGB: /* RR B */ + case REGC: /* RR C */ + case REGD: /* RR D */ + case REGE: /* RR E */ + case REGH: /* RR H */ + case REGL: /* RR L */ + case REGIHL: /* RR (HL) */ + len = 2; + ops[0] = 0xcb; + ops[1] = 0x18 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 4; /* RR (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x1e; + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 4; /* RR (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x1e; + } + } else { + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt den SLA Op-Code + */ +op_sla() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* SLA A */ + case REGB: /* SLA B */ + case REGC: /* SLA C */ + case REGD: /* SLA D */ + case REGE: /* SLA E */ + case REGH: /* SLA H */ + case REGL: /* SLA L */ + case REGIHL: /* SLA (HL) */ + len = 2; + ops[0] = 0xcb; + ops[1] = 0x20 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 4; /* SLA (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x26; + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 4; /* SLA (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x26; + } + } else { + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt den SRA Op-Code + */ +op_sra() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* SRA A */ + case REGB: /* SRA B */ + case REGC: /* SRA C */ + case REGD: /* SRA D */ + case REGE: /* SRA E */ + case REGH: /* SRA H */ + case REGL: /* SRA L */ + case REGIHL: /* SRA (HL) */ + len = 2; + ops[0] = 0xcb; + ops[1] = 0x28 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 4; /* SRA (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x2e; + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 4; /* SRA (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x2e; + } + } else { + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt den SRL Op-Code + */ +op_srl() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* SRL A */ + case REGB: /* SRL B */ + case REGC: /* SRL C */ + case REGD: /* SRL D */ + case REGE: /* SRL E */ + case REGH: /* SRL H */ + case REGL: /* SRL L */ + case REGIHL: /* SRL (HL) */ + len = 2; + ops[0] = 0xcb; + ops[1] = 0x38 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 4; /* SRL (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x3e; + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 4; /* SRL (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x3e; + } + } else { + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt den RLC Op-Code + */ +op_rlc() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* RLC A */ + case REGB: /* RLC B */ + case REGC: /* RLC C */ + case REGD: /* RLC D */ + case REGE: /* RLC E */ + case REGH: /* RLC H */ + case REGL: /* RLC L */ + case REGIHL: /* RLC (HL) */ + len = 2; + ops[0] = 0xcb; + ops[1] = 0x00 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 4; /* RLC (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x06; + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 4; /* RLC (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x06; + } + } else { + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt den RRC Op-Code + */ +op_rrc() +{ + char *strchr(); + register int len, op; + + if (pass == 1) + if (*label) + put_label(); + switch (op = get_reg(operand)) { + case REGA: /* RRC A */ + case REGB: /* RRC B */ + case REGC: /* RRC C */ + case REGD: /* RRC D */ + case REGE: /* RRC E */ + case REGH: /* RRC H */ + case REGL: /* RRC L */ + case REGIHL: /* RRC (HL) */ + len = 2; + ops[0] = 0xcb; + ops[1] = 0x08 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(operand, "(IX+", 4) == 0) { + len = 4; /* RRC (IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x0e; + } + } else if (strncmp(operand, "(IY+", 4) == 0) { + len = 4; /* RRC (IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x0e; + } + } else { + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + break; + case NOOPERA: /* Operand fehlt */ + len = 1; + ops[0] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + len = 1; + ops[0] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion behandelt den OUT Op-Code + */ +op_out() +{ + register int op; + char *get_second(); + + if (pass == 1) { /* PASS 1 */ + if (*label) + put_label(); + } else { /* PASS 2 */ + if (strncmp(operand, "(C),", 4) == 0) { + switch(op = get_reg(get_second(operand))) { + case REGA: /* OUT (C),A */ + case REGB: /* OUT (C),B */ + case REGC: /* OUT (C),C */ + case REGD: /* OUT (C),D */ + case REGE: /* OUT (C),E */ + case REGH: /* OUT (C),H */ + case REGL: /* OUT (C),L */ + ops[0] = 0xed; + ops[1] = 0x41 + (op << 3); + break; + case NOOPERA: /* Operand fehlt */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_ILLOPE); + } + } else { + ops[0] = 0xd3; /* OUT (n),A */ + ops[1] = chk_v1(calc_val(operand + 1)); + } + } + return(2); +} + +/* + * Die Funktion behandelt den IN Op-Code + */ +op_in() +{ + char *get_second(); + register char *p1, *p2; + register int op; + + if (pass == 1) { /* PASS 1 */ + if (*label) + put_label(); + } else { /* PASS 2 */ + p1 = operand; + p2 = tmp; + while (*p1 != ',' && *p1 != '\0') + *p2++ = *p1++; + *p2 = '\0'; + switch (op = get_reg(tmp)) { + case REGA: + if (strncmp(operand, "A,(C)", 5) == 0) { + ops[0] = 0xed; /* IN A,(C) */ + ops[1] = 0x78; + } else { + ops[0] = 0xdb; /* IN A,(n) */ + ops[1] = chk_v1(calc_val(get_second(operand) + 1)); + } + break; + case REGB: /* IN B,(C) */ + case REGC: /* IN C,(C) */ + case REGD: /* IN D,(C) */ + case REGE: /* IN E,(C) */ + case REGH: /* IN H,(C) */ + case REGL: /* IN L,(C) */ + ops[0] = 0xed; + ops[1] = 0x40 + (op << 3); + break; + default: /* ungueltiger Operand */ + ops[0] = 0; + ops[1] = 0; + asmerr(E_ILLOPE); + } + } + return(2); +} + +/* + * Diese Funktion behandelt den SET Op-Code + */ +op_set() +{ + char *strchr(); + register char *p1, *p2; + register int len; + register int i; + register int op; + + len = 2; + i = 0; + if (pass == 1) + if (*label) + put_label(); + ops[0] = 0xcb; + p1 = operand; + p2 = tmp; + while (*p1 != ',' && *p1 != '\0') + *p2++ = *p1++; + *p2 = '\0'; + if (pass == 2) { + i = eval(tmp); + if (i < 0 || i > 7) + asmerr(E_VALOUT); + } + switch (op = get_reg(++p1)) { + case REGA: /* SET n,A */ + case REGB: /* SET n,B */ + case REGC: /* SET n,C */ + case REGD: /* SET n,D */ + case REGE: /* SET n,E */ + case REGH: /* SET n,H */ + case REGL: /* SET n,L */ + case REGIHL: /* SET n,(HL) */ + ops[1] = 0xc0 + i * 8 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(p1, "(IX+", 4) == 0) { + len = 4; /* SET n,(IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0xc6 + i * 8; + } + } else if (strncmp(p1, "(IY+", 4) == 0) { + len = 4; /* SET n,(IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0xc6 + i * 8; + } + } else { + ops[1] = 0; + asmerr(E_ILLOPE); + } + break; + case NOOPERA: /* Operand fehlt */ + ops[1] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + ops[1] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Diese Funktion behandelt den RES Op-Code + */ +op_res() +{ + char *strchr(); + register char *p1, *p2; + register int len; + register int i; + register int op; + + len = 2; + i = 0; + if (pass == 1) + if (*label) + put_label(); + ops[0] = 0xcb; + p1 = operand; + p2 = tmp; + while (*p1 != ',' && *p1 != '\0') + *p2++ = *p1++; + *p2 = '\0'; + if (pass == 2) { + i = eval(tmp); + if (i < 0 || i > 7) + asmerr(E_VALOUT); + } + switch (op = get_reg(++p1)) { + case REGA: /* RES n,A */ + case REGB: /* RES n,B */ + case REGC: /* RES n,C */ + case REGD: /* RES n,D */ + case REGE: /* RES n,E */ + case REGH: /* RES n,H */ + case REGL: /* RES n,L */ + case REGIHL: /* RES n,(HL) */ + ops[1] = 0x80 + i * 8 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(p1, "(IX+", 4) == 0) { + len = 4; /* RES n,(IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x86 + i * 8; + } + } else if (strncmp(p1, "(IY+", 4) == 0) { + len = 4; /* RES n,(IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x86 + i * 8; + } + } else { + ops[1] = 0; + asmerr(E_ILLOPE); + } + break; + case NOOPERA: /* Operand fehlt */ + ops[1] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + ops[1] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Diese Funktion behandelt den BIT Op-Code + */ +op_bit() +{ + char *strchr(); + register char *p1, *p2; + register int len; + register int i; + register int op; + + len = 2; + i = 0; + if (pass == 1) + if (*label) + put_label(); + ops[0] = 0xcb; + p1 = operand; + p2 = tmp; + while (*p1 != ',' && *p1 != '\0') + *p2++ = *p1++; + *p2 = '\0'; + if (pass == 2) { + i = eval(tmp); + if (i < 0 || i > 7) + asmerr(E_VALOUT); + } + switch (op = get_reg(++p1)) { + case REGA: /* BIT n,A */ + case REGB: /* BIT n,B */ + case REGC: /* BIT n,C */ + case REGD: /* BIT n,D */ + case REGE: /* BIT n,E */ + case REGH: /* BIT n,H */ + case REGL: /* BIT n,L */ + case REGIHL: /* BIT n,(HL) */ + ops[1] = 0x40 + i * 8 + op; + break; + case NOREG: /* Operand ist kein Register */ + if (strncmp(p1, "(IX+", 4) == 0) { + len = 4; /* BIT n,(IX+d) */ + if (pass == 2) { + ops[0] = 0xdd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x46 + i * 8; + } + } else if (strncmp(p1, "(IY+", 4) == 0) { + len = 4; /* BIT n,(IY+d) */ + if (pass == 2) { + ops[0] = 0xfd; + ops[1] = 0xcb; + ops[2] = chk_v2(calc_val(strchr(operand, '+') + 1)); + ops[3] = 0x46 + i * 8; + } + } else { + ops[1] = 0; + asmerr(E_ILLOPE); + } + break; + case NOOPERA: /* Operand fehlt */ + ops[1] = 0; + asmerr(E_MISOPE); + break; + default: /* ungueltiger Operand */ + ops[1] = 0; + asmerr(E_ILLOPE); + } + return(len); +} + +/* + * Die Funktion liefert einen Pointer auf den zweiten Operanden + * bei Befehlen der Form: Op-Code destination,source + * Fehlt ,source wird ein NULL-Pointer geliefert. + */ +char *get_second(s) +register char *s; +{ + char *strchr(); + register char *p; + + if ((p = strchr(s, ',')) != NULL) + return(p + 1); + else + return(NULL); +} + +/* + * Die Funktion bestimmt den Wert eines Reststrings der + * Form: expression) + * Z.B.: LD A,(IX+7) + * -- + */ +calc_val(s) +register char *s; +{ + register char *p; + register int i; + char *strrchr(), *strncpy(); + + if ((p = strrchr(s, ')')) == NULL) { + asmerr(E_MISPAR); + return(0); + } + i = p - s; + strncpy(tmp, s, i); + *(tmp + i) = '\0'; + return(eval(tmp)); +} diff --git a/z80asm/z80atab.c b/z80asm/z80atab.c new file mode 100644 index 0000000..33217cb --- /dev/null +++ b/z80asm/z80atab.c @@ -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 +#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); +}