2048: slight VT100 changes (arrow characters, clear screen) and added uz80as as Linux assembler
This commit is contained in:
parent
442870b868
commit
8139d51b26
@ -13,12 +13,15 @@
|
|||||||
; Compile:
|
; Compile:
|
||||||
;
|
;
|
||||||
; TASM -80 -b 2048.ASM 2048.COM
|
; TASM -80 -b 2048.ASM 2048.COM
|
||||||
|
; -or-
|
||||||
|
; uz80as 2048.ASM 2048.COM
|
||||||
;
|
;
|
||||||
; Credits:
|
; Credits:
|
||||||
;
|
;
|
||||||
; Based on 2048 created by Gabriele Cirulli.
|
; Based on 2048 created by Gabriele Cirulli.
|
||||||
; Based on the console version for GNU/Linux by Maurits van der Schee
|
; Based on the console version for GNU/Linux by Maurits van der Schee
|
||||||
; Ported to Z80 and CP/M by Marco Maccaferri <macca@maccasoft.com>
|
; Ported to Z80 and CP/M by Marco Maccaferri <macca@maccasoft.com>
|
||||||
|
; Slight VT100 compatibility changes by acn128 <acn@acn.wtf>
|
||||||
|
|
||||||
|
|
||||||
CTRL_A .EQU 1
|
CTRL_A .EQU 1
|
||||||
@ -945,7 +948,8 @@ DIV16:
|
|||||||
LD HL,0
|
LD HL,0
|
||||||
LD B,16
|
LD B,16
|
||||||
|
|
||||||
DL1 SLL C ; Undoc. 0CBH, 31H
|
DL1 SCF
|
||||||
|
RL C
|
||||||
RLA
|
RLA
|
||||||
ADC HL,HL
|
ADC HL,HL
|
||||||
SBC HL,DE
|
SBC HL,DE
|
||||||
@ -1041,7 +1045,7 @@ POINTS .DW 0000H
|
|||||||
.DW 4096H
|
.DW 4096H
|
||||||
.DW 8192H
|
.DW 8192H
|
||||||
|
|
||||||
INIT: .DB 12, 1BH, "[?25l", EOS
|
INIT: .DB 1BH, "[?25l", 1BH, "[2J", EOS
|
||||||
TERM: .DB 1BH, "[?25h"
|
TERM: .DB 1BH, "[?25h"
|
||||||
RESET: .DB 1BH, "[0m", EOS
|
RESET: .DB 1BH, "[0m", EOS
|
||||||
|
|
||||||
@ -1061,16 +1065,16 @@ BTMBORDER .DB 0DFH
|
|||||||
.DB 0DFH, 0DFH, 0DFH, 0DFH, 0DFH, 0DFH, 0DFH
|
.DB 0DFH, 0DFH, 0DFH, 0DFH, 0DFH, 0DFH, 0DFH
|
||||||
.DB 0DFH, EOS
|
.DB 0DFH, EOS
|
||||||
|
|
||||||
MSG1: .DB 1BH, "[0m",
|
MSG1: .DB 1BH, "[0m"
|
||||||
.DB " ", 11H, ",", 1EH, ",", 10H, ",", 1FH, " or q "
|
.DB " <,>,^,v or q "
|
||||||
.DB EOS
|
.DB EOS
|
||||||
MSG2: .DB 1BH, "[0m"
|
MSG2: .DB 1BH, "[0m"
|
||||||
.DB " QUIT? (y/n) ",
|
.DB " QUIT? (y/n) "
|
||||||
.DB EOS
|
.DB EOS
|
||||||
MSG3: .DB 1BH, "[0m",
|
MSG3: .DB 1BH, "[0m"
|
||||||
.DB " GAME OVER! "
|
.DB " GAME OVER! "
|
||||||
.DB BEL, CR, LF, EOS
|
.DB BEL, CR, LF, EOS
|
||||||
MSG4: .DB 1BH, "[0m",
|
MSG4: .DB 1BH, "[0m"
|
||||||
.DB "2048 pts"
|
.DB "2048 pts"
|
||||||
.DB EOS
|
.DB EOS
|
||||||
|
|
||||||
|
BIN
2048/2048.COM
BIN
2048/2048.COM
Binary file not shown.
@ -19,7 +19,15 @@ When two tiles with the same number touch, they merge into one.
|
|||||||
|
|
||||||
## Compile:
|
## Compile:
|
||||||
|
|
||||||
TASM -80 -b 2048.ASM 2048.COM
|
If using TASM, the command is: ``TASM -80 -b 2048.ASM 2048.COM``
|
||||||
|
|
||||||
|
The "Micro Z80 Assembler" was used to assemble ``2048.COM`` on Linux.
|
||||||
|
It is provided in the directory ``uz80as``, just compile it using ``make``.
|
||||||
|
|
||||||
|
The command for assembling 2048 is: ``uz80as 2048.ASM 2048.COM``.
|
||||||
|
|
||||||
|
uz80as can be found here: https://github.com/jorgicor/uz80as
|
||||||
|
The uz80as directory here is taken from the RomWBW source tree.
|
||||||
|
|
||||||
## License:
|
## License:
|
||||||
|
|
||||||
|
67
2048/uz80as/Makefile
Normal file
67
2048/uz80as/Makefile
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# ===========================================================================
|
||||||
|
# uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
# ===========================================================================
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -g
|
||||||
|
|
||||||
|
OBJECTS = ngetopt.o main.o options.o \
|
||||||
|
utils.o err.o incl.o sym.o \
|
||||||
|
expr.o exprint.o pp.o list.o \
|
||||||
|
prtable.o uz80as.o targets.o \
|
||||||
|
z80.o gbcpu.o \
|
||||||
|
dp2200.o i4004.o \
|
||||||
|
i8008.o i8048.o \
|
||||||
|
i8051.o i8080.o \
|
||||||
|
mos6502.o mc6800.o
|
||||||
|
|
||||||
|
SOURCES = \
|
||||||
|
config.h \
|
||||||
|
ngetopt.c ngetopt.h \
|
||||||
|
main.c \
|
||||||
|
options.c options.h \
|
||||||
|
utils.c utils.h \
|
||||||
|
err.c err.h \
|
||||||
|
incl.c incl.h \
|
||||||
|
sym.c sym.h \
|
||||||
|
expr.c expr.h \
|
||||||
|
exprint.c exprint.h \
|
||||||
|
pp.c pp.h \
|
||||||
|
list.c list.h \
|
||||||
|
prtable.c prtable.h \
|
||||||
|
uz80as.c uz80as.h \
|
||||||
|
targets.c targets.h \
|
||||||
|
z80.c \
|
||||||
|
gbcpu.c \
|
||||||
|
dp2200.c \
|
||||||
|
i4004.c \
|
||||||
|
i8008.c \
|
||||||
|
i8048.c \
|
||||||
|
i8051.c \
|
||||||
|
i8080.c \
|
||||||
|
mos6502.c \
|
||||||
|
mc6800.c
|
||||||
|
|
||||||
|
all: uz80as
|
||||||
|
|
||||||
|
clobber: clean
|
||||||
|
-rm -f uz80as uz80as
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm -f $(OBJECTS)
|
||||||
|
|
||||||
|
uz80as: $(OBJECTS)
|
||||||
|
$(CC) $(CFLAGS) -o uz80as $(OBJECTS)
|
||||||
|
|
||||||
|
TESTS=test*.asm
|
||||||
|
|
||||||
|
test: uz80as
|
||||||
|
echo "running tests"
|
||||||
|
for i in $(TESTS) ; do \
|
||||||
|
echo "====== $$i ======" ; \
|
||||||
|
./uz80as $$i ; \
|
||||||
|
cat $$(basename $$i .asm).lst ; \
|
||||||
|
done
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) $(CFLAGS) -I. -c $< -o $@
|
29
2048/uz80as/config.h
Normal file
29
2048/uz80as/config.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/* config.h. Generated from config.h.in by configure. */
|
||||||
|
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||||
|
|
||||||
|
/* Years of copyright */
|
||||||
|
#define COPYRIGHT_YEARS "2018"
|
||||||
|
|
||||||
|
/* Name of package */
|
||||||
|
#define PACKAGE "uz80as"
|
||||||
|
|
||||||
|
/* Define to the address where bug reports for this package should be sent. */
|
||||||
|
#define PACKAGE_BUGREPORT "jorge.giner@hotmail.com"
|
||||||
|
|
||||||
|
/* Define to the full name of this package. */
|
||||||
|
#define PACKAGE_NAME "uz80as"
|
||||||
|
|
||||||
|
/* Define to the full name and version of this package. */
|
||||||
|
#define PACKAGE_STRING "uz80as 1.10"
|
||||||
|
|
||||||
|
/* Define to the one symbol short name of this package. */
|
||||||
|
#define PACKAGE_TARNAME "uz80as"
|
||||||
|
|
||||||
|
/* Define to the home page for this package. */
|
||||||
|
#define PACKAGE_URL "https://jorgicor.niobe.org/uz80as"
|
||||||
|
|
||||||
|
/* Define to the version of this package. */
|
||||||
|
#define PACKAGE_VERSION "1.10"
|
||||||
|
|
||||||
|
/* Version number of package */
|
||||||
|
#define VERSION "1.10"
|
208
2048/uz80as/dp2200.c
Normal file
208
2048/uz80as/dp2200.c
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Datapoint 2200.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Datapoint 2200 Version I, 2K to 8K mem (program counter 13 bits).
|
||||||
|
* Datapoint 2200 Version II, 2K to 16K mem (protram counter 14 bits).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pp.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "uz80as.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* pat:
|
||||||
|
* a: expr
|
||||||
|
* b: ADA,ADB,ADC,ADD,ADH,ADL,ADM,
|
||||||
|
* ACA,ACB,ACC,ACD,ACH,ACL,ACM,
|
||||||
|
* SUA,SUB,SUC,SUD,SUH,SUL,SUM,
|
||||||
|
* SBA,SBB,SBC,SBD,SBH,SBL,SBM,
|
||||||
|
* NDA,NDB,NDC,NDD,NDH,NDL,NDM,
|
||||||
|
* XRA,XRB,XRC,XRD,XRH,XRL,XRM,
|
||||||
|
* ORA,ORB,ORC,ORD,ORH,ORL,ORM,
|
||||||
|
* CPA,CPB,CPC,CPD,CPH,CPL,CPM
|
||||||
|
* c: NOP,LAB,LAC,LAD,LAE,LAH,LAL,LAM,
|
||||||
|
* LBA,LBC,LBD,LBE,LBH,LBL,LBM,
|
||||||
|
* LCA,LCB,LCD,LCE,LCH,LCL,LCM,
|
||||||
|
* LDA,LDB,LDC,LDE,LDH,LDL,LDM,
|
||||||
|
* LEA,LEB,LEC,LED,LEH,LEL,LEM,
|
||||||
|
* LHA,LHB,LHC,LHD,LHE,LHL,LHM,
|
||||||
|
* LLA,LLB,LLC,LLD,LLE,LLH,LLM,
|
||||||
|
* LMA,LMB,LMC,LMD,LME,LMH,LML,HALT
|
||||||
|
* d: ADR,STATUS,DATA,WRITE,COM1,COM2,COM3,COM4
|
||||||
|
* BEEP,CLICK,DECK1,DECK2,
|
||||||
|
* RBK,WBK,BSP,SF,SB,REWND,TSTOP
|
||||||
|
* e: RFC,RFS,RTC,RTS,RFZ,RFP,RTZ,RTP
|
||||||
|
* f: JFC,JFZ,JFS,JFP,JTC,JTZ,JTS,JTP
|
||||||
|
* g: AD,SU,ND,OR,AC,SB,XR,CP
|
||||||
|
* h: LA,LB,LC,LD,LE,LH,LL
|
||||||
|
* i: CFC,CFZ,CFS,CFP,CTC,CTZ,CTS,CTP
|
||||||
|
*
|
||||||
|
* gen:
|
||||||
|
* .: output lastbyte
|
||||||
|
* b: (op << 3) | lastbyte
|
||||||
|
* c: op | lastbyte
|
||||||
|
* d: lastbyte = op as 8 bit value
|
||||||
|
* e: output op as word (no '.' should follow)
|
||||||
|
* f: (op << 1) + lastbyte
|
||||||
|
* g: (op << 4) | lastbyte
|
||||||
|
*/
|
||||||
|
|
||||||
|
const struct matchtab s_matchtab_dp2200[] = {
|
||||||
|
{ "SLC", "02.", 3, 0 },
|
||||||
|
{ "SRC", "0A.", 3, 0 },
|
||||||
|
{ "RETURN", "07.", 3, 0 },
|
||||||
|
{ "INPUT", "41.", 3, 0 },
|
||||||
|
{ "b", "80c0.", 3, 0 },
|
||||||
|
{ "c", "C0c0.", 3, 0 },
|
||||||
|
{ "EX d", "51f0.", 3, 0 },
|
||||||
|
{ "e", "03b0.", 3, 0 },
|
||||||
|
{ "g a", "04b0.d1.", 3, 0, "e8" },
|
||||||
|
{ "h a", "06b0.d1.", 3, 0, "e8"},
|
||||||
|
{ "f a", "40b0.e1", 3, 0 },
|
||||||
|
{ "i a", "42b0.e1", 3, 0 },
|
||||||
|
{ "JMP a", "44.e0", 3, 0 },
|
||||||
|
{ "CALL a", "46.e0", 3, 0 },
|
||||||
|
/* version II */
|
||||||
|
{ "BETA", "10.", 2, 0 },
|
||||||
|
{ "DI", "20.", 2, 0 },
|
||||||
|
{ "POP", "30.", 2, 0 },
|
||||||
|
{ "ALPHA", "18.", 2, 0 },
|
||||||
|
{ "EI", "28.", 2, 0 },
|
||||||
|
{ "PUSH", "38.", 2, 0 },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const bval[] = {
|
||||||
|
"ADA", "ADB", "ADC", "ADD", "ADE", "ADH", "ADL", "ADM",
|
||||||
|
"ACA", "ACB", "ACC", "ACD", "ACE", "ACH", "ACL", "ACM",
|
||||||
|
"SUA", "SUB", "SUC", "SUD", "SUE", "SUH", "SUL", "SUM",
|
||||||
|
"SBA", "SBB", "SBC", "SBD", "SBE", "SBH", "SBL", "SBM",
|
||||||
|
"NDA", "NDB", "NDC", "NDD", "NDE", "NDH", "NDL", "NDM",
|
||||||
|
"XRA", "XRB", "XRC", "XRD", "XRE", "XRH", "XRL", "XRM",
|
||||||
|
"ORA", "ORB", "ORC", "ORD", "ORE", "ORH", "ORL", "ORM",
|
||||||
|
"CPA", "CPB", "CPC", "CPD", "CPE", "CPH", "CPL", "CPM",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const cval[] = {
|
||||||
|
"NOP", "LAB", "LAC", "LAD", "LAE", "LAH", "LAL", "LAM",
|
||||||
|
"LBA", "", "LBC", "LBD", "LBE", "LBH", "LBL", "LBM",
|
||||||
|
"LCA", "LCB", "", "LCD", "LCE", "LCH", "LCL", "LCM",
|
||||||
|
"LDA", "LDB", "LDC", "", "LDE", "LDH", "LDL", "LDM",
|
||||||
|
"LEA", "LEB", "LEC", "LED", "", "LEH", "LEL", "LEM",
|
||||||
|
"LHA", "LHB", "LHC", "LHD", "LHE", "", "LHL", "LHM",
|
||||||
|
"LLA", "LLB", "LLC", "LLD", "LLE", "LLH", "", "LLM",
|
||||||
|
"LMA", "LMB", "LMC", "LMD", "LME", "LMH", "LML", "HALT",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const dval[] = {
|
||||||
|
"ADR", "STATUS", "DATA", "WRITE", "COM1", "COM2", "COM3", "COM4",
|
||||||
|
"", "", "", "", "BEEP", "CLICK", "DECK1", "DECK2",
|
||||||
|
"RBK", "WBK", "", "BSP", "SF", "SB", "REWND", "TSTOP",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const eval[] = { "RFC", "RFZ", "RFS", "RFP",
|
||||||
|
"RTC", "RTZ", "RTS", "RTP",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const fval[] = { "JFC", "JFZ", "JFS", "JFP",
|
||||||
|
"JTC", "JTZ", "JTS", "JTP",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const gval[] = { "AD", "AC", "SU", "SB",
|
||||||
|
"ND", "XR", "OR", "CP",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const hval[] = { "LA", "LB", "LC", "LD",
|
||||||
|
"LE", "LH", "LL",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const ival[] = { "CFC", "CFZ", "CFS", "CFP",
|
||||||
|
"CTC", "CTZ", "CTS", "CTP",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const *const valtab[] = {
|
||||||
|
bval, cval, dval, eval, fval,
|
||||||
|
gval, hval, ival
|
||||||
|
};
|
||||||
|
|
||||||
|
static int match_dp2200(char c, const char *p, const char **q)
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
|
||||||
|
if (c <= 'i') {
|
||||||
|
v = mreg(p, valtab[(int) (c - 'b')], q);
|
||||||
|
} else {
|
||||||
|
v = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gen_dp2200(int *eb, char p, const int *vs, int i, int savepc)
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
|
||||||
|
b = *eb;
|
||||||
|
switch (p) {
|
||||||
|
case 'f': b += (vs[i] << 1); break;
|
||||||
|
case 'g': b |= (vs[i] << 4); break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*eb = b;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s_pat_char = 'b';
|
||||||
|
static int s_pat_index;
|
||||||
|
|
||||||
|
static void pat_char_rewind_dp2200(int c)
|
||||||
|
{
|
||||||
|
s_pat_char = c;
|
||||||
|
s_pat_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *pat_next_str_dp2200(void)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (s_pat_char >= 'b' && s_pat_char <= 'n') {
|
||||||
|
s = valtab[(int) (s_pat_char - 'b')][s_pat_index];
|
||||||
|
if (s != NULL) {
|
||||||
|
s_pat_index++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_dp2200 = {
|
||||||
|
.id = "dp2200",
|
||||||
|
.descr = "Datapoint 2200 Version I",
|
||||||
|
.matcht = s_matchtab_dp2200,
|
||||||
|
.matchf = match_dp2200,
|
||||||
|
.genf = gen_dp2200,
|
||||||
|
.pat_char_rewind = pat_char_rewind_dp2200,
|
||||||
|
.pat_next_str = pat_next_str_dp2200,
|
||||||
|
.mask = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_dp2200ii = {
|
||||||
|
.id = "dp2200ii",
|
||||||
|
.descr = "Datapoint 2200 Version II",
|
||||||
|
.matcht = s_matchtab_dp2200,
|
||||||
|
.matchf = match_dp2200,
|
||||||
|
.genf = gen_dp2200,
|
||||||
|
.pat_char_rewind = pat_char_rewind_dp2200,
|
||||||
|
.pat_next_str = pat_next_str_dp2200,
|
||||||
|
.mask = 2
|
||||||
|
};
|
196
2048/uz80as/err.c
Normal file
196
2048/uz80as/err.c
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Error reporting.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "incl.h"
|
||||||
|
|
||||||
|
#ifndef ASSERT_H
|
||||||
|
#include <assert.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CTYPE_H
|
||||||
|
#include <ctype.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STDARG_H
|
||||||
|
#include <stdarg.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STDIO_H
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STDLIB_H
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STRING_H
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Max number of errors before halt. */
|
||||||
|
#define MAXERR 64
|
||||||
|
|
||||||
|
int s_nerrors;
|
||||||
|
|
||||||
|
static void eprfl(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s:%d: ", curfile()->name, curfile()->linenum);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eprwarn(void)
|
||||||
|
{
|
||||||
|
fputs(_("warning:"), stderr);
|
||||||
|
fputc(' ', stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print the characters in [p, q[ to stderr. */
|
||||||
|
void echars(const char *p, const char *q)
|
||||||
|
{
|
||||||
|
while (*p != '\0' && p != q) {
|
||||||
|
fputc(*p, stderr);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a space, an opening parenthesis, the characters in [p, q[,
|
||||||
|
* and a closing parenthesis to stderr.
|
||||||
|
*/
|
||||||
|
void epchars(const char *p, const char *q)
|
||||||
|
{
|
||||||
|
fputs(" (", stderr);
|
||||||
|
echars(p, q);
|
||||||
|
fputs(")", stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increments the number of errors, and exit with failure if
|
||||||
|
* maximum number of errors allowed is reached.
|
||||||
|
*/
|
||||||
|
void newerr(void)
|
||||||
|
{
|
||||||
|
s_nerrors++;
|
||||||
|
if (s_nerrors >= MAXERR) {
|
||||||
|
eprogname();
|
||||||
|
fprintf(stderr, _("exiting: too many errors"));
|
||||||
|
enl();
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void evprint(int warn, const char *ecode, va_list args)
|
||||||
|
{
|
||||||
|
if (nfiles() > 0)
|
||||||
|
eprfl();
|
||||||
|
else
|
||||||
|
eprogname();
|
||||||
|
|
||||||
|
if (warn)
|
||||||
|
eprwarn();
|
||||||
|
|
||||||
|
assert(ecode != NULL);
|
||||||
|
vfprintf(stderr, ecode, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prints only the printable characters, the rst as space. */
|
||||||
|
static void eprint_printable(const char *p)
|
||||||
|
{
|
||||||
|
for (; *p != '\0'; p++) {
|
||||||
|
if (isprint(*p))
|
||||||
|
putc(*p, stderr);
|
||||||
|
else
|
||||||
|
putc(' ', stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prints the line and a marker pointing to the charcater q inside line. */
|
||||||
|
void eprcol(const char *line, const char *q)
|
||||||
|
{
|
||||||
|
putc(' ', stderr);
|
||||||
|
eprint_printable(line);
|
||||||
|
fputs("\n ", stderr);
|
||||||
|
while (line != q) {
|
||||||
|
putc(' ', stderr);
|
||||||
|
line++;
|
||||||
|
}
|
||||||
|
fputs("^\n", stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like fprintf but prints to stderr.
|
||||||
|
* If we are parsing any file (incl.c), print first the file and the line.
|
||||||
|
* If not, print first the program name.
|
||||||
|
*/
|
||||||
|
void eprint(const char *ecode, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, ecode);
|
||||||
|
evprint(0, ecode, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Same as eprint, but print "warning: " before ecode str. */
|
||||||
|
void wprint(const char *ecode, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, ecode);
|
||||||
|
evprint(1, ecode, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print \n on stderr. */
|
||||||
|
void enl(void)
|
||||||
|
{
|
||||||
|
fputc('\n', stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print the program name on stderr. */
|
||||||
|
void eprogname(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr, PACKAGE": ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call malloc, but if no memory, print that error and exit with failure. */
|
||||||
|
void *emalloc(size_t n)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if ((p = malloc(n)) == NULL) {
|
||||||
|
eprint(_("malloc fail\n"));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
// printf("emalloc: %d = %x\n", n, p);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call realloc, but if no memory, print that error and exit with failure. */
|
||||||
|
void *erealloc(void *p, size_t n)
|
||||||
|
{
|
||||||
|
// void *q = p;
|
||||||
|
if ((p = realloc(p, n)) == NULL) {
|
||||||
|
eprint(_("realloc fail\n"));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
// printf("erealloc: %x %d = %x\n", q, n, p);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call fopen, but if any error, print it and exit with failure. */
|
||||||
|
FILE *efopen(const char *fname, const char *ops)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if ((fp = fopen(fname, ops)) == NULL) {
|
||||||
|
eprint(_("cannot open file %s\n"), fname);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
return fp;
|
||||||
|
}
|
32
2048/uz80as/err.h
Normal file
32
2048/uz80as/err.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Error reporting.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ERR_H
|
||||||
|
#define ERR_H
|
||||||
|
|
||||||
|
#ifndef STDIO_H
|
||||||
|
#define STDIO_H
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _(str) (str)
|
||||||
|
|
||||||
|
extern int s_nerrors;
|
||||||
|
|
||||||
|
void newerr(void);
|
||||||
|
void eprogname(void);
|
||||||
|
void echars(const char *p, const char *q);
|
||||||
|
void epchars(const char *p, const char *q);
|
||||||
|
void eprint(const char *ecode, ...);
|
||||||
|
void wprint(const char *ecode, ...);
|
||||||
|
void eprcol(const char *line, const char *q);
|
||||||
|
void enl(void);
|
||||||
|
void *emalloc(size_t n);
|
||||||
|
void *erealloc(void *p, size_t n);
|
||||||
|
FILE *efopen(const char *fname, const char *ops);
|
||||||
|
|
||||||
|
#endif
|
459
2048/uz80as/expr.c
Normal file
459
2048/uz80as/expr.c
Normal file
@ -0,0 +1,459 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Expression parsing.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "expr.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "sym.h"
|
||||||
|
|
||||||
|
#ifndef ASSERT_H
|
||||||
|
#include <assert.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CTYPE_H
|
||||||
|
#include <ctype.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LIMITS_H
|
||||||
|
#include <limits.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STDIO_H
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STDLIB_H
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Max nested expressions. */
|
||||||
|
#define ESTKSZ 16
|
||||||
|
#define ESTKSZ2 (ESTKSZ*2)
|
||||||
|
|
||||||
|
/* Return -1 on syntax error.
|
||||||
|
* *p must be a digit already.
|
||||||
|
* *q points to one past the end of the number without suffix.
|
||||||
|
*/
|
||||||
|
static int takenum(const char *p, const char *q, int radix)
|
||||||
|
{
|
||||||
|
int k, n;
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
while (p != q) {
|
||||||
|
k = hexval(*p);
|
||||||
|
p++;
|
||||||
|
if (k >= 0 && k < radix)
|
||||||
|
n = n * radix + k;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Go to the end of a number (advance all digits or letters). */
|
||||||
|
static const char *goendnum(const char *p)
|
||||||
|
{
|
||||||
|
const char *q;
|
||||||
|
|
||||||
|
for (q = p; isalnum(*q); q++)
|
||||||
|
;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns NULL on error.
|
||||||
|
* '*p' must be a digit already.
|
||||||
|
*/
|
||||||
|
static const char *getnum(const char *p, int *v)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
char c;
|
||||||
|
const char *q;
|
||||||
|
|
||||||
|
assert(isdigit(*p));
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
q = goendnum(p) - 1;
|
||||||
|
if (isalpha(*q)) {
|
||||||
|
c = toupper(*q);
|
||||||
|
if (c == 'H') {
|
||||||
|
n = takenum(p, q, 16);
|
||||||
|
} else if (c == 'D') {
|
||||||
|
n = takenum(p, q, 10);
|
||||||
|
} else if (c == 'O') {
|
||||||
|
n = takenum(p, q, 8);
|
||||||
|
} else if (c == 'B') {
|
||||||
|
n = takenum(p, q, 2);
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n = takenum(p, q + 1, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*v = n;
|
||||||
|
return q + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets a number that was prefixed.
|
||||||
|
* Returns NULL on error.
|
||||||
|
*/
|
||||||
|
static const char *getpnum(const char *p, int radix, int *v)
|
||||||
|
{
|
||||||
|
const char *q;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
q = goendnum(p);
|
||||||
|
n = takenum(p, q, radix);
|
||||||
|
if (n < 0)
|
||||||
|
return NULL;
|
||||||
|
*v = n;
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Left shift */
|
||||||
|
static int shl(int r, int n)
|
||||||
|
{
|
||||||
|
n &= int_precission();
|
||||||
|
return r << n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Portable arithmetic right shift. */
|
||||||
|
static int ashr(int r, int n)
|
||||||
|
{
|
||||||
|
n &= int_precission();
|
||||||
|
if (r & INT_MIN) {
|
||||||
|
return ~(~r >> n);
|
||||||
|
} else {
|
||||||
|
return r >> n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parses expression pointed by 'p'.
|
||||||
|
* If success, returns pointer to the end of parsed expression, and
|
||||||
|
* 'v' contains the calculated value of the expression.
|
||||||
|
* Returns NULL if a syntactic error has occurred.
|
||||||
|
* Operators are evaluated left to right.
|
||||||
|
* To allow precedence use parenthesis.
|
||||||
|
* 'linepc' is the program counter to consider when we find the $ current
|
||||||
|
* pointer location symbol ($).
|
||||||
|
* 'allowfr' stands for 'allow forward references'. We will issue an error
|
||||||
|
* if we find a label that is not defined.
|
||||||
|
* 'ecode' will be valid if NULL is returned. NULL can be passed as ecode.
|
||||||
|
* 'ep' is the pointer to the position where the error ocurred. NULL can be
|
||||||
|
* passed as ep.
|
||||||
|
*/
|
||||||
|
const char *expr(const char *p, int *v, int linepc, int allowfr,
|
||||||
|
enum expr_ecode *ecode, const char **ep)
|
||||||
|
{
|
||||||
|
int si, usi, usl;
|
||||||
|
const char *q;
|
||||||
|
char last;
|
||||||
|
int stack[ESTKSZ2];
|
||||||
|
int uopstk[ESTKSZ];
|
||||||
|
int r, n;
|
||||||
|
struct sym *sym;
|
||||||
|
int err;
|
||||||
|
enum expr_ecode ec;
|
||||||
|
|
||||||
|
ec = EXPR_E_NO_EXPR;
|
||||||
|
err = 0;
|
||||||
|
usi = 0;
|
||||||
|
si = 0;
|
||||||
|
r = 0;
|
||||||
|
last = 'V'; /* first void */
|
||||||
|
usl = 0;
|
||||||
|
loop:
|
||||||
|
p = skipws(p);
|
||||||
|
if (*p == '(') {
|
||||||
|
if (last == 'n') {
|
||||||
|
goto end;
|
||||||
|
} else {
|
||||||
|
if (si >= ESTKSZ2) {
|
||||||
|
eprint(_("expression too complex\n"));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
stack[si++] = last;
|
||||||
|
stack[si++] = r;
|
||||||
|
stack[si++] = usl;
|
||||||
|
usl = usi;
|
||||||
|
p++;
|
||||||
|
r = 0;
|
||||||
|
last = 'v'; /* void */
|
||||||
|
}
|
||||||
|
} else if (*p == ')') {
|
||||||
|
if (last != 'n') {
|
||||||
|
ec = EXPR_E_CPAR;
|
||||||
|
goto esyntax;
|
||||||
|
} else if (si == 0) {
|
||||||
|
goto end;
|
||||||
|
} else {
|
||||||
|
p++;
|
||||||
|
n = r;
|
||||||
|
usl = stack[--si];
|
||||||
|
r = stack[--si];
|
||||||
|
last = (char) stack[--si];
|
||||||
|
goto oper;
|
||||||
|
}
|
||||||
|
} else if (*p == '+') {
|
||||||
|
p++;
|
||||||
|
if (last == 'n')
|
||||||
|
last = '+';
|
||||||
|
} else if (*p == '-') {
|
||||||
|
if (last == 'n') {
|
||||||
|
p++;
|
||||||
|
last = '-';
|
||||||
|
} else {
|
||||||
|
goto uoper;
|
||||||
|
}
|
||||||
|
} else if (*p == '~') {
|
||||||
|
goto uoper;
|
||||||
|
} else if (*p == '!') {
|
||||||
|
if (*(p + 1) == '=') {
|
||||||
|
if (last != 'n') {
|
||||||
|
ec = EXPR_E_OPER;
|
||||||
|
goto esyntax;
|
||||||
|
} else {
|
||||||
|
p += 2;
|
||||||
|
last = 'N';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
goto uoper;
|
||||||
|
}
|
||||||
|
} else if (*p == '*') {
|
||||||
|
if (last == 'n') {
|
||||||
|
last = *p++;
|
||||||
|
} else {
|
||||||
|
p++;
|
||||||
|
n = linepc;
|
||||||
|
goto oper;
|
||||||
|
}
|
||||||
|
} else if (*p == '/' || *p == '&' || *p == '|'
|
||||||
|
|| *p == '^')
|
||||||
|
{
|
||||||
|
if (last != 'n') {
|
||||||
|
ec = EXPR_E_OPER;
|
||||||
|
goto esyntax;
|
||||||
|
} else {
|
||||||
|
last = *p++;
|
||||||
|
}
|
||||||
|
} else if (*p == '>') {
|
||||||
|
if (last != 'n') {
|
||||||
|
ec = EXPR_E_OPER;
|
||||||
|
goto esyntax;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
if (*p == '=') {
|
||||||
|
last = 'G';
|
||||||
|
p++;
|
||||||
|
} else if (*p == '>') {
|
||||||
|
last = 'R';
|
||||||
|
p++;
|
||||||
|
} else {
|
||||||
|
last = '>';
|
||||||
|
}
|
||||||
|
} else if (*p == '<') {
|
||||||
|
if (last != 'n') {
|
||||||
|
ec = EXPR_E_OPER;
|
||||||
|
goto esyntax;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
if (*p == '=') {
|
||||||
|
last = 'S';
|
||||||
|
p++;
|
||||||
|
} else if (*p == '<') {
|
||||||
|
last = 'L';
|
||||||
|
p++;
|
||||||
|
} else {
|
||||||
|
last = '<';
|
||||||
|
}
|
||||||
|
} else if (*p == '=') {
|
||||||
|
if (last != 'n') {
|
||||||
|
ec = EXPR_E_OPER;
|
||||||
|
goto esyntax;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
if (*p == '=')
|
||||||
|
p++;
|
||||||
|
last = '=';
|
||||||
|
} else if (*p == '\'') {
|
||||||
|
if (last == 'n')
|
||||||
|
goto end;
|
||||||
|
p++;
|
||||||
|
n = *p++;
|
||||||
|
if (*p != '\'') {
|
||||||
|
ec = EXPR_E_CHAR;
|
||||||
|
goto esyntax;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
goto oper;
|
||||||
|
} else if (*p == '$') {
|
||||||
|
if (last == 'n')
|
||||||
|
goto end;
|
||||||
|
p++;
|
||||||
|
if (hexval(*p) < 0) {
|
||||||
|
n = linepc;
|
||||||
|
goto oper;
|
||||||
|
}
|
||||||
|
q = getpnum(p, 16, &n);
|
||||||
|
if (q == NULL) {
|
||||||
|
p--;
|
||||||
|
ec = EXPR_E_HEX;
|
||||||
|
goto esyntax;
|
||||||
|
}
|
||||||
|
p = q;
|
||||||
|
goto oper;
|
||||||
|
} else if (*p == '@') {
|
||||||
|
if (last == 'n')
|
||||||
|
goto end;
|
||||||
|
p++;
|
||||||
|
q = getpnum(p, 8, &n);
|
||||||
|
if (q == NULL) {
|
||||||
|
p--;
|
||||||
|
ec = EXPR_E_OCTAL;
|
||||||
|
goto esyntax;
|
||||||
|
}
|
||||||
|
p = q;
|
||||||
|
goto oper;
|
||||||
|
} else if (*p == '%') {
|
||||||
|
if (last == 'n') {
|
||||||
|
last = *p;
|
||||||
|
p++;
|
||||||
|
} else {
|
||||||
|
p++;
|
||||||
|
q = getpnum(p, 2, &n);
|
||||||
|
if (q == NULL) {
|
||||||
|
ec = EXPR_E_BIN;
|
||||||
|
goto esyntax;
|
||||||
|
}
|
||||||
|
p = q;
|
||||||
|
goto oper;
|
||||||
|
}
|
||||||
|
} else if ((p[0] == '0') && (p[1] == 'x')) {
|
||||||
|
p+=2;
|
||||||
|
q = getpnum(p, 16, &n);
|
||||||
|
if (q == NULL) {
|
||||||
|
p--;
|
||||||
|
ec = EXPR_E_HEX;
|
||||||
|
goto esyntax;
|
||||||
|
}
|
||||||
|
p = q;
|
||||||
|
goto oper;
|
||||||
|
} else if (isdigit(*p)) {
|
||||||
|
if (last == 'n')
|
||||||
|
goto end;
|
||||||
|
q = getnum(p, &n);
|
||||||
|
if (q == NULL) {
|
||||||
|
ec = EXPR_E_DEC;
|
||||||
|
goto esyntax;
|
||||||
|
}
|
||||||
|
p = q;
|
||||||
|
goto oper;
|
||||||
|
} else if (isidc0(*p)) {
|
||||||
|
if (last == 'n')
|
||||||
|
goto end;
|
||||||
|
q = p;
|
||||||
|
while (isidc(*p))
|
||||||
|
p++;
|
||||||
|
sym = lookup(q, p, 0, 0);
|
||||||
|
if (sym == NULL) {
|
||||||
|
n = 0;
|
||||||
|
if (!allowfr) {
|
||||||
|
err = 1;
|
||||||
|
eprint(_("undefined label"));
|
||||||
|
epchars(q, p);
|
||||||
|
enl();
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n = sym->val;
|
||||||
|
}
|
||||||
|
goto oper;
|
||||||
|
} else if (last == 'V') {
|
||||||
|
goto esyntax;
|
||||||
|
} else if (last != 'n') {
|
||||||
|
ec = EXPR_E_SYNTAX;
|
||||||
|
goto esyntax;
|
||||||
|
} else {
|
||||||
|
end: if (v != NULL)
|
||||||
|
*v = r;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
goto loop;
|
||||||
|
uoper:
|
||||||
|
if (last == 'n')
|
||||||
|
goto end;
|
||||||
|
if (usi >= ESTKSZ) {
|
||||||
|
eprint(_("expression too complex\n"));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
uopstk[usi++] = *p++;
|
||||||
|
goto loop;
|
||||||
|
oper:
|
||||||
|
while (usi > usl) {
|
||||||
|
usi--;
|
||||||
|
switch (uopstk[usi]) {
|
||||||
|
case '~': n = ~n; break;
|
||||||
|
case '-': n = -n; break;
|
||||||
|
case '!': n = !n; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (last) {
|
||||||
|
case 'V': r = n; break;
|
||||||
|
case 'v': r = n; break;
|
||||||
|
case '+': r += n; break;
|
||||||
|
case '-': r -= n; break;
|
||||||
|
case '*': r *= n; break;
|
||||||
|
case '&': r &= n; break;
|
||||||
|
case '|': r |= n; break;
|
||||||
|
case '^': r ^= n; break;
|
||||||
|
case '=': r = r == n; break;
|
||||||
|
case '<': r = r < n; break;
|
||||||
|
case '>': r = r > n ; break;
|
||||||
|
case 'G': r = r >= n; break;
|
||||||
|
case 'S': r = r <= n; break;
|
||||||
|
case 'N': r = r != n; break;
|
||||||
|
/* This would be logical right shift:
|
||||||
|
* case 'R': r = (unsigned int) r >> n; break;
|
||||||
|
*/
|
||||||
|
case 'R': r = ashr(r, n); break;
|
||||||
|
case 'L': r = shl(r, n); break;
|
||||||
|
case '~': r = ~n; break;
|
||||||
|
case '%':
|
||||||
|
if (n != 0) {
|
||||||
|
r %= n;
|
||||||
|
} else if (!err && !allowfr) {
|
||||||
|
err = 1;
|
||||||
|
eprint(_("modulo by zero\n"));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
if (n != 0) {
|
||||||
|
r /= n;
|
||||||
|
} else if (!err && !allowfr) {
|
||||||
|
err = 1;
|
||||||
|
eprint(_("division by zero\n"));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last = 'n';
|
||||||
|
goto loop;
|
||||||
|
esyntax:
|
||||||
|
if (ecode != NULL)
|
||||||
|
*ecode = ec;
|
||||||
|
if (ep != NULL)
|
||||||
|
*ep = p;
|
||||||
|
return NULL;
|
||||||
|
}
|
26
2048/uz80as/expr.h
Normal file
26
2048/uz80as/expr.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Expression parsing.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EXPR_H
|
||||||
|
#define EXPR_H
|
||||||
|
|
||||||
|
enum expr_ecode {
|
||||||
|
EXPR_E_NO_EXPR, /* There was no expression parsed. */
|
||||||
|
EXPR_E_SYNTAX, /* Syntax error. */
|
||||||
|
EXPR_E_CPAR,
|
||||||
|
EXPR_E_OPER,
|
||||||
|
EXPR_E_CHAR,
|
||||||
|
EXPR_E_HEX,
|
||||||
|
EXPR_E_OCTAL,
|
||||||
|
EXPR_E_BIN,
|
||||||
|
EXPR_E_DEC,
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *expr(const char *p, int *v, int linepc, int allowfr,
|
||||||
|
enum expr_ecode *ecode, const char **ep);
|
||||||
|
|
||||||
|
#endif
|
32
2048/uz80as/exprint.c
Normal file
32
2048/uz80as/exprint.c
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Expression error reporting.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "exprint.h"
|
||||||
|
#include "err.h"
|
||||||
|
|
||||||
|
static const char *expr_get_error_str(enum expr_ecode ecode)
|
||||||
|
{
|
||||||
|
switch (ecode) {
|
||||||
|
case EXPR_E_NO_EXPR: return _("expression expected\n");
|
||||||
|
case EXPR_E_SYNTAX: return _("syntax error in expression\n");
|
||||||
|
case EXPR_E_CPAR: return _("unexpected ')'\n");
|
||||||
|
case EXPR_E_OPER: return _("misplaced operator\n");
|
||||||
|
case EXPR_E_CHAR: return _("invalid character code\n");
|
||||||
|
case EXPR_E_HEX: return _("invalid hexadecimal constant\n");
|
||||||
|
case EXPR_E_OCTAL: return _("invalid octal constant\n");
|
||||||
|
case EXPR_E_BIN: return _("invalid binary constant\n");
|
||||||
|
case EXPR_E_DEC: return _("invalid decimal constant\n");
|
||||||
|
default: return "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void exprint(enum expr_ecode ecode, const char *pline, const char *ep)
|
||||||
|
{
|
||||||
|
eprint(expr_get_error_str(ecode));
|
||||||
|
eprcol(pline, ep);
|
||||||
|
}
|
17
2048/uz80as/exprint.h
Normal file
17
2048/uz80as/exprint.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Expression error reporting.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EXPRINT_H
|
||||||
|
#define EXPRINT_H
|
||||||
|
|
||||||
|
#ifndef EXPR_H
|
||||||
|
#include "expr.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void exprint(enum expr_ecode ecode, const char *pline, const char *ep);
|
||||||
|
|
||||||
|
#endif
|
301
2048/uz80as/gbcpu.c
Normal file
301
2048/uz80as/gbcpu.c
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Sharp LR35902 (Nintendo Gameboy CPU).
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pp.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "uz80as.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
Opcode Z80 GMB
|
||||||
|
---------------------------------------
|
||||||
|
08 EX AF,AF LD (nn),SP
|
||||||
|
10 DJNZ PC+dd STOP
|
||||||
|
22 LD (nn),HL LDI (HL),A
|
||||||
|
2A LD HL,(nn) LDI A,(HL)
|
||||||
|
32 LD (nn),A LDD (HL),A
|
||||||
|
3A LD A,(nn) LDD A,(HL)
|
||||||
|
D3 OUT (n),A -
|
||||||
|
D9 EXX RETI
|
||||||
|
DB IN A,(n) -
|
||||||
|
DD <IX> -
|
||||||
|
E0 RET PO LD (FF00+n),A
|
||||||
|
E2 JP PO,nn LD (FF00+C),A
|
||||||
|
E3 EX (SP),HL -
|
||||||
|
E4 CALL PO,nn -
|
||||||
|
E8 RET PE ADD SP,dd
|
||||||
|
EA JP PE,nn LD (nn),A
|
||||||
|
EB EX DE,HL -
|
||||||
|
EC CALL PE,nn -
|
||||||
|
ED <pref> -
|
||||||
|
F0 RET P LD A,(FF00+n)
|
||||||
|
F2 JP P,nn LD A,(FF00+C)
|
||||||
|
F4 CALL P,nn -
|
||||||
|
F8 RET M LD HL,SP+dd
|
||||||
|
FA JP M,nn LD A,(nn)
|
||||||
|
FC CALL M,nn -
|
||||||
|
FD <IY> -
|
||||||
|
CB3X SLL r/(HL) SWAP r/(HL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* pat:
|
||||||
|
* a: expr
|
||||||
|
* b: B,C,D,E,H,L,A
|
||||||
|
* c: *
|
||||||
|
* d: BC,DE,HL,SP
|
||||||
|
* e: *
|
||||||
|
* f: BC,DE,HL,AF
|
||||||
|
* g: ADD,ADC,SUB,SBC,AND,XOR,OR,CP
|
||||||
|
* h: INC,DEC
|
||||||
|
* i: *
|
||||||
|
* j: *
|
||||||
|
* k: *
|
||||||
|
* l: BIT,RES,SET
|
||||||
|
* m: *
|
||||||
|
* n: NZ,Z,NC,C
|
||||||
|
* o: RLC,RRC,RL,RR,SLA,SRA,SWAP,SRL
|
||||||
|
*
|
||||||
|
* gen:
|
||||||
|
* .: output lastbyte
|
||||||
|
* b: (op << 3) | lastbyte
|
||||||
|
* c: op | lastbyte
|
||||||
|
* d: lastbyte = op as 8 bit value
|
||||||
|
* e: output op as word (no '.' should follow)
|
||||||
|
* f: (op << 4) | lastbyte
|
||||||
|
* g: (op << 6) | lastbyte
|
||||||
|
* h: if op >= FF00 output last byte and then op as 8 bit value;
|
||||||
|
* else output (lastbyte | 0x0A) and output op as word
|
||||||
|
* (no '.' should follow)
|
||||||
|
* i: relative jump to op
|
||||||
|
* j: possible value to RST
|
||||||
|
* k: possible value to IM
|
||||||
|
* l: *
|
||||||
|
* m: check arithmetic used with A register
|
||||||
|
* n: check arithmetic used without A register
|
||||||
|
*/
|
||||||
|
|
||||||
|
const struct matchtab s_matchtab_gbcpu[] = {
|
||||||
|
{ "LD b,b", "40b0c1.", 1, 0 },
|
||||||
|
{ "LD b,(HL)", "46b0.", 1, 0 },
|
||||||
|
{ "LD A,(C)", "F2.", 1, 0 }, // * LD A,(FF00+C)
|
||||||
|
{ "LD A,(BC)", "0A.", 1, 0 },
|
||||||
|
{ "LD A,(DE)", "1A.", 1, 0 },
|
||||||
|
{ "LD A,(HLI)", "2A.", 1, 0 }, // *
|
||||||
|
{ "LD A,(HLD)", "3A.", 1, 0 }, // *
|
||||||
|
{ "LD A,(a)", "F0h0", 1, 0 }, // * LD A,(nn) & LD A,(FF00+n)
|
||||||
|
{ "LD b,a", "06b0.d1.", 1, 0, "e8" },
|
||||||
|
{ "LD SP,HL", "F9.", 1, 0 },
|
||||||
|
{ "LDHL SP,a", "F8.d0.", 1, 0, "e8" }, // * LD HL,SP+n
|
||||||
|
{ "LD d,a", "01f0.e1", 1, 0 },
|
||||||
|
{ "LD (C),A", "E2.", 1, 0 }, // * LD (FF00+C),A
|
||||||
|
{ "LD (HL),b", "70c0.", 1, 0 },
|
||||||
|
{ "LD (HL),a", "36.d0.", 1, 0, "e8" },
|
||||||
|
{ "LD (HLI),A", "22.", 1, 0 }, // *
|
||||||
|
{ "LD (HLD),A", "32.", 1, 0 }, // *
|
||||||
|
{ "LD (BC),A", "02.", 1, 0 },
|
||||||
|
{ "LD (DE),A", "12.", 1, 0 },
|
||||||
|
{ "LD (a),A", "E0h0", 1, 0 }, // * LD (nn),A & LD (FF00+n),A
|
||||||
|
{ "LD (a),SP", "08.e0", 1, 0 }, // *
|
||||||
|
{ "LDH A,(a)", "F0.d0.", 1, 0, "e8" }, // * LD A,(FF00+n)
|
||||||
|
{ "LDH (a),A", "E0.d0.", 1, 0, "e8" }, // * LD (FF00+n),A
|
||||||
|
{ "PUSH f", "C5f0.", 1, 0 },
|
||||||
|
{ "POP f", "C1f0.", 1, 0 },
|
||||||
|
{ "ADD HL,d", "09f0.", 1, 0 },
|
||||||
|
{ "ADD SP,a", "E8.d0.", 1, 0, "e8" }, // *
|
||||||
|
{ "g A,b", "m080b0c1.", 1, 0 },
|
||||||
|
{ "g A,(HL)", "m086b0.", 1, 0 },
|
||||||
|
{ "g A,a", "m0C6b0.d1.", 1, 0, "e8" },
|
||||||
|
{ "g b", "n080b0c1.", 1, 0 },
|
||||||
|
{ "g (HL)", "n086b0.", 1, 0 },
|
||||||
|
{ "g a", "n0C6b0.d1.", 1, 0, "e8" },
|
||||||
|
{ "h b", "04b1c0.", 1, 0 },
|
||||||
|
{ "h (HL)", "34c0.", 1, 0 },
|
||||||
|
{ "INC d", "03f0.", 1, 0 },
|
||||||
|
{ "DEC d", "0Bf0.", 1, 0 },
|
||||||
|
{ "DAA", "27.", 1, 0 },
|
||||||
|
{ "CPL", "2F.", 1, 0 },
|
||||||
|
{ "CCF", "3F.", 1, 0 },
|
||||||
|
{ "SCF", "37.", 1, 0 },
|
||||||
|
{ "NOP", "00.", 1, 0 },
|
||||||
|
{ "HALT", "76.", 1, 0 },
|
||||||
|
{ "DI", "F3.", 1, 0 },
|
||||||
|
{ "EI", "FB.", 1, 0 },
|
||||||
|
{ "RLCA", "07.", 1, 0 },
|
||||||
|
{ "RLA", "17.", 1, 0 },
|
||||||
|
{ "RRCA", "0F.", 1, 0 },
|
||||||
|
{ "RRA", "1F.", 1, 0 },
|
||||||
|
{ "o b", "CB.00b0c1.", 1, 0 },
|
||||||
|
{ "o (HL)", "CB.06b0.", 1, 0 },
|
||||||
|
{ "l a,b", "CB.00g0b1c2.", 1, 0, "b3" },
|
||||||
|
{ "l a,(HL)", "CB.06g0b1.", 1, 0, "b3" },
|
||||||
|
{ "JP (HL)", "E9.", 1, 0 },
|
||||||
|
{ "JP n,a", "C2b0.e1", 1, 0 }, // *
|
||||||
|
{ "JP a", "C3.e0", 1, 0 },
|
||||||
|
{ "JR n,a", "20b0.i1.", 1, 0, "r8" },
|
||||||
|
{ "JR a", "18.i0.", 1, 0, "r8" },
|
||||||
|
{ "STOP", "10.00.", 1, 0 }, // *
|
||||||
|
{ "CALL n,a", "C4b0.e1", 1, 0 }, // *
|
||||||
|
{ "CALL a", "CD.e0", 1, 0 },
|
||||||
|
{ "RETI", "D9.", 1, 0 }, // *
|
||||||
|
{ "RET n", "C0b0.", 1, 0 },
|
||||||
|
{ "RET", "C9.", 1, 0 },
|
||||||
|
{ "RST a", "C7j0.", 1, 0, "ss" },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const bval[] = { "B", "C", "D", "E",
|
||||||
|
"H", "L", "", "A", NULL };
|
||||||
|
static const char *const dval[] = { "BC", "DE", "HL", "SP", NULL };
|
||||||
|
static const char *const fval[] = { "BC", "DE", "HL", "AF", NULL };
|
||||||
|
static const char *const gval[] = { "ADD", "ADC", "SUB", "SBC",
|
||||||
|
"AND", "XOR", "OR", "CP", NULL };
|
||||||
|
static const char *const hval[] = { "INC", "DEC", NULL };
|
||||||
|
static const char *const lval[] = { "", "BIT", "RES", "SET", NULL };
|
||||||
|
static const char *const nval[] = { "NZ", "Z", "NC", "C", NULL };
|
||||||
|
static const char *const oval[] = { "RLC", "RRC", "RL", "RR",
|
||||||
|
"SLA", "SRA", "SWAP", "SRL", NULL };
|
||||||
|
static const char *const nullv[] = { NULL };
|
||||||
|
|
||||||
|
static const char *const *const valtab[] = {
|
||||||
|
bval, nullv, dval, nullv, fval,
|
||||||
|
gval, hval, nullv, nullv, nullv,
|
||||||
|
lval, nullv, nval, oval
|
||||||
|
};
|
||||||
|
|
||||||
|
static int match_gbcpu(char c, const char *p, const char **q)
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 'b':
|
||||||
|
case 'd':
|
||||||
|
case 'f':
|
||||||
|
case 'g':
|
||||||
|
case 'h':
|
||||||
|
case 'l':
|
||||||
|
case 'n':
|
||||||
|
case 'o':
|
||||||
|
v = mreg(p, valtab[(int) (c - 'b')], q);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
v = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gen_gbcpu(int *eb, char p, const int *vs, int i, int savepc)
|
||||||
|
{
|
||||||
|
int w, b;
|
||||||
|
|
||||||
|
b = *eb;
|
||||||
|
switch (p) {
|
||||||
|
case 'f': b |= (vs[i] << 4); break;
|
||||||
|
case 'g': b |= (vs[i] << 6); break;
|
||||||
|
case 'h': w = vs[i] & 0xffff;
|
||||||
|
if (w >= 0xff00) {
|
||||||
|
genb(b, s_pline_ep);
|
||||||
|
b = 0;
|
||||||
|
genb(w & 0xff, s_pline_ep);
|
||||||
|
} else {
|
||||||
|
b |= 0x0A;
|
||||||
|
genb(b, s_pline_ep);
|
||||||
|
b = 0;
|
||||||
|
genb(w & 0xff, s_pline_ep);
|
||||||
|
genb(w >> 8, s_pline_ep);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'i': b = (vs[i] - savepc - 2); break;
|
||||||
|
case 'j': if (s_pass > 0 && (vs[i] & ~56) != 0) {
|
||||||
|
eprint(_("invalid RST argument (%d)\n"),
|
||||||
|
vs[i]);
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
b |= vs[i];
|
||||||
|
break;
|
||||||
|
case 'k': if (s_pass > 0 && (vs[i] < 0 || vs[i] > 2)) {
|
||||||
|
eprint(_("invalid IM argument (%d)\n"),
|
||||||
|
vs[i]);
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
b = 0x46;
|
||||||
|
if (vs[i] == 1)
|
||||||
|
b = 0x56;
|
||||||
|
else if (vs[i] == 2)
|
||||||
|
b = 0x5E;
|
||||||
|
break;
|
||||||
|
case 'm': if (s_pass == 0 && !s_extended_op) {
|
||||||
|
if (vs[i] != 0 && vs[i] != 1 && vs[i] != 3) {
|
||||||
|
eprint(_("unofficial syntax\n"));
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'n': if (s_pass == 0 && !s_extended_op) {
|
||||||
|
if (vs[i] == 0 || vs[i] == 1 || vs[i] == 3) {
|
||||||
|
eprint(_("unofficial syntax\n"));
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*eb = b;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s_pat_char = 'b';
|
||||||
|
static int s_pat_index;
|
||||||
|
|
||||||
|
static void pat_char_rewind_gbcpu(int c)
|
||||||
|
{
|
||||||
|
s_pat_char = c;
|
||||||
|
s_pat_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *pat_next_str_gbcpu(void)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
switch (s_pat_char) {
|
||||||
|
case 'b':
|
||||||
|
case 'd':
|
||||||
|
case 'f':
|
||||||
|
case 'g':
|
||||||
|
case 'h':
|
||||||
|
case 'l':
|
||||||
|
case 'n':
|
||||||
|
case 'o':
|
||||||
|
s = valtab[(int) (s_pat_char - 'b')][s_pat_index];
|
||||||
|
if (s != NULL) {
|
||||||
|
s_pat_index++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_gbcpu = {
|
||||||
|
.id = "gbcpu",
|
||||||
|
.descr = "Sharp LR35902 (Nintendo Gameboy CPU)",
|
||||||
|
.matcht = s_matchtab_gbcpu,
|
||||||
|
.matchf = match_gbcpu,
|
||||||
|
.genf = gen_gbcpu,
|
||||||
|
.pat_char_rewind = pat_char_rewind_gbcpu,
|
||||||
|
.pat_next_str = pat_next_str_gbcpu,
|
||||||
|
.mask = 1
|
||||||
|
};
|
189
2048/uz80as/i4004.c
Normal file
189
2048/uz80as/i4004.c
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Intel 4004.
|
||||||
|
* Intel 4040.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Intel 4004. Max. memory 4K (12 bit addresses).
|
||||||
|
* Intel 4040. Max. memory 8K (13 bit addresses).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pp.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "uz80as.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* pat:
|
||||||
|
* a: expr
|
||||||
|
* b: ADD,SUB,LD,XCH,BBL,LDM
|
||||||
|
* c: WRM,WMP,WRR,WPM,WR0,WR1,WR2,WR3
|
||||||
|
* SBM,RDM,RDR,ADM,RD0,RD1,RD2,RD3
|
||||||
|
* d: CLB,CLC,IAC,CMC,CMA,RAL,RAR,TCC,
|
||||||
|
* DAC,TCS,STC,DAA,KBP,DCL,
|
||||||
|
* e: HLT,BBS,LCR,OR4,OR5,AN6,AN7
|
||||||
|
* DB0,DB1,SB0,SB1,EIN,DIN,RPM
|
||||||
|
* f: 0P,1P,2P,3P,4P,5P,6P,7P
|
||||||
|
*
|
||||||
|
* gen:
|
||||||
|
* .: output lastbyte
|
||||||
|
* b: (op << 3) | lastbyte
|
||||||
|
* c: op | lastbyte
|
||||||
|
* d: lastbyte = op as 8 bit value
|
||||||
|
* e: output op as word (no '.' should follow)
|
||||||
|
* f: op | lastbyte, op in [0-15]
|
||||||
|
* g: op | lastbyte, op in [0,2,4,6,8,10,12,14]
|
||||||
|
* h: output (op & 0xff0000 >> 8) | lastbyte;
|
||||||
|
* then ouput op as 8 bit value
|
||||||
|
* i: (op << 4) | lastbyte
|
||||||
|
* j: (op << 1) | lastbyte
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct matchtab s_matchtab_i4004[] = {
|
||||||
|
{ "NOP", "00.", 1, 0 },
|
||||||
|
{ "JCN a,a", "10f0.d1.", 1, 0, "b4e8" },
|
||||||
|
{ "FIM f,a", "20j0.d1.", 1, 0, "e8" },
|
||||||
|
{ "FIM a,a", "20g0.d1.", 1, 0, "ppe8" },
|
||||||
|
{ "SRC f", "21j0.", 1, 0 },
|
||||||
|
{ "SRC a", "21g0.", 1, 0, "pp" },
|
||||||
|
{ "FIN f", "30j0.", 1, 0 },
|
||||||
|
{ "FIN a", "30g0.", 1, 0, "pp" },
|
||||||
|
{ "JIN f", "31j0.", 1, 0 },
|
||||||
|
{ "JIN a", "31g0.", 1, 0, "pp" },
|
||||||
|
{ "JUN a", "40h0", 1, 0 },
|
||||||
|
{ "JMS a", "50h0", 1, 0 },
|
||||||
|
{ "INC a", "60f0.", 1, 0, "b4" },
|
||||||
|
{ "ISZ a,a", "70f0.d1.", 1, 0, "b4e8" },
|
||||||
|
{ "b a", "80i0f1.", 1, 0, "b4" },
|
||||||
|
{ "c", "E0c0.", 1, 0 },
|
||||||
|
{ "d", "F0c0.", 1, 0 },
|
||||||
|
{ "e", "00c0.", 2, 0 },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const bval[] = {
|
||||||
|
"ADD", "SUB", "LD", "XCH", "BBL", "LDM",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const cval[] = {
|
||||||
|
"WRM", "WMP", "WRR", "WPM", "WR0", "WR1", "WR2", "WR3",
|
||||||
|
"SBM", "RDM", "RDR", "ADM", "RD0", "RD1", "RD2", "RD3",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const dval[] = {
|
||||||
|
"CLB", "CLC", "IAC", "CMC", "CMA", "RAL", "RAR", "TCC",
|
||||||
|
"DAC", "TCS", "STC", "DAA", "KBP", "DCL",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const eval[] = {
|
||||||
|
"", "HLT", "BBS", "LCR", "OR4", "OR5", "AN6", "AN7",
|
||||||
|
"DB0", "DB1", "SB0", "SB1", "EIN", "DIN", "RPM",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const fval[] = {
|
||||||
|
"0P", "1P", "2P", "3P", "4P", "5P", "6P", "7P",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const *const valtab[] = {
|
||||||
|
bval, cval, dval, eval, fval
|
||||||
|
};
|
||||||
|
|
||||||
|
static int match_i4004(char c, const char *p, const char **q)
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
|
||||||
|
if (c <= 'f') {
|
||||||
|
v = mreg(p, valtab[(int) (c - 'b')], q);
|
||||||
|
} else {
|
||||||
|
v = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gen_i4004(int *eb, char p, const int *vs, int i, int savepc)
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
|
||||||
|
b = *eb;
|
||||||
|
switch (p) {
|
||||||
|
case 'f': if (s_pass > 0 && (vs[i] < 0 || vs[i] > 15)) {
|
||||||
|
eprint(_("argument (%d) must be in range [0-15]\n"),
|
||||||
|
vs[i]);
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
b |= vs[i];
|
||||||
|
break;
|
||||||
|
case 'g': if (s_pass > 0 && (vs[i] < 0 || vs[i] > 14 || (vs[i] & 1))) {
|
||||||
|
eprint(
|
||||||
|
_("argument (%d) must be an even number in range [0-14]\n"),
|
||||||
|
vs[i]);
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
b |= vs[i];
|
||||||
|
break;
|
||||||
|
case 'h': b |= ((vs[i] >> 8) & 0x0f);
|
||||||
|
genb(b, s_pline_ep);
|
||||||
|
genb(vs[i], s_pline_ep);
|
||||||
|
break;
|
||||||
|
case 'i': b |= (vs[i] << 4); break;
|
||||||
|
case 'j': b |= (vs[i] << 1); break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*eb = b;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s_pat_char = 'b';
|
||||||
|
static int s_pat_index;
|
||||||
|
|
||||||
|
static void pat_char_rewind_i4004(int c)
|
||||||
|
{
|
||||||
|
s_pat_char = c;
|
||||||
|
s_pat_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *pat_next_str_i4004(void)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (s_pat_char >= 'b' && s_pat_char <= 'f') {
|
||||||
|
s = valtab[(int) (s_pat_char - 'b')][s_pat_index];
|
||||||
|
if (s != NULL) {
|
||||||
|
s_pat_index++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_i4004 = {
|
||||||
|
.id = "i4004",
|
||||||
|
.descr = "Intel 4004",
|
||||||
|
.matcht = s_matchtab_i4004,
|
||||||
|
.matchf = match_i4004,
|
||||||
|
.genf = gen_i4004,
|
||||||
|
.pat_char_rewind = pat_char_rewind_i4004,
|
||||||
|
.pat_next_str = pat_next_str_i4004,
|
||||||
|
.mask = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_i4040 = {
|
||||||
|
.id = "i4040",
|
||||||
|
.descr = "Intel 4040",
|
||||||
|
.matcht = s_matchtab_i4004,
|
||||||
|
.matchf = match_i4004,
|
||||||
|
.genf = gen_i4004,
|
||||||
|
.pat_char_rewind = pat_char_rewind_i4004,
|
||||||
|
.pat_next_str = pat_next_str_i4004,
|
||||||
|
.mask = 3
|
||||||
|
};
|
||||||
|
|
220
2048/uz80as/i8008.c
Normal file
220
2048/uz80as/i8008.c
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Intel 8008.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Max. memory 16K (14 bits addresses). */
|
||||||
|
|
||||||
|
#include "pp.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "uz80as.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* pat:
|
||||||
|
* a: expr
|
||||||
|
* b: ADA,ADB,ADC,ADD,ADH,ADL,ADM,
|
||||||
|
* ACA,ACB,ACC,ACD,ACH,ACL,ACM,
|
||||||
|
* SUA,SUB,SUC,SUD,SUH,SUL,SUM,
|
||||||
|
* SBA,SBB,SBC,SBD,SBH,SBL,SBM,
|
||||||
|
* NDA,NDB,NDC,NDD,NDH,NDL,NDM,
|
||||||
|
* XRA,XRB,XRC,XRD,XRH,XRL,XRM,
|
||||||
|
* ORA,ORB,ORC,ORD,ORH,ORL,ORM,
|
||||||
|
* CPA,CPB,CPC,CPD,CPH,CPL,CPM
|
||||||
|
* c: NOP,LAB,LAC,LAD,LAE,LAH,LAL,LAM,
|
||||||
|
* LBA,LBB,LBC,LBD,LBE,LBH,LBL,LBM,
|
||||||
|
* LCA,LCB,LCC,LCD,LCE,LCH,LCL,LCM,
|
||||||
|
* LDA,LDB,LDC,LDD,LDE,LDH,LDL,LDM,
|
||||||
|
* LEA,LEB,LEC,LED,LEE,LEH,LEL,LEM,
|
||||||
|
* LHA,LHB,LHC,LHD,LHE,LHH,LHL,LHM,
|
||||||
|
* LLA,LLB,LLC,LLD,LLE,LLH,LLL,LLM,
|
||||||
|
* LMA,LMB,LMC,LMD,LME,LMH,LML,HLT
|
||||||
|
* d: JFC,CFC,JMP,CAL,JFZ,CFZ,
|
||||||
|
* JFS,CFS,JFP,CFP,
|
||||||
|
* JTC,CTC,JTZ,CTZ,
|
||||||
|
* JTS,CTS,JTP,CTP
|
||||||
|
* e: INB,INC,IND,INE,INH,INL
|
||||||
|
* f: DCB,DCC,DCD,DCE,DCH,DCL
|
||||||
|
* g: ADI,ACI,SUI,SBI,NDI,XRI,ORI,CPI
|
||||||
|
* h: LAI,LBI,LCI,LDI,LEI,LHI,LLI,LMI
|
||||||
|
* i: RFC,RFS,RTC,RTS,RFZ,RFP,RTZ,RTP
|
||||||
|
* j: RLC,RRC,RAL,RAR
|
||||||
|
*
|
||||||
|
* gen:
|
||||||
|
* .: output lastbyte
|
||||||
|
* b: (op << 3) | lastbyte
|
||||||
|
* c: op | lastbyte
|
||||||
|
* d: lastbyte = op as 8 bit value
|
||||||
|
* e: output op as word (no '.' should follow)
|
||||||
|
* f: (op << 1) | lastbyte, op in [0-7]
|
||||||
|
* g: (op << 1) | lastbyte, op in [8-31]
|
||||||
|
* h: (op << 4) | lastbyte
|
||||||
|
* i: (op << 1) | lastbyte
|
||||||
|
* j: (op << 3) | lastbyte, op in [0-7]
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct matchtab s_matchtab_i8008[] = {
|
||||||
|
{ "RET", "07.", 1, 0 },
|
||||||
|
{ "j", "02b0.", 1, 0 },
|
||||||
|
{ "i", "03b0.", 1, 0 },
|
||||||
|
{ "h a", "06b0.d1.", 1, 0, "e8" },
|
||||||
|
{ "g a", "04b0.d1.", 1, 0, "e8" },
|
||||||
|
{ "e", "00b0.", 1, 0 },
|
||||||
|
{ "f", "01b0.", 1, 0 },
|
||||||
|
{ "RST a", "05j0.", 1, 0, "b3" },
|
||||||
|
{ "d a", "40i0.e1", 1, 0 },
|
||||||
|
{ "INP a", "41f0.", 1, 0, "b3" },
|
||||||
|
{ "OUT a", "41g0.", 1, 0, "kk" },
|
||||||
|
{ "b", "80c0.", 1, 0 },
|
||||||
|
{ "c", "C0c0.", 1, 0 },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const bval[] = {
|
||||||
|
"ADA", "ADB", "ADC", "ADD", "ADE", "ADH", "ADL", "ADM",
|
||||||
|
"ACA", "ACB", "ACC", "ACD", "ACE", "ACH", "ACL", "ACM",
|
||||||
|
"SUA", "SUB", "SUC", "SUD", "SUE", "SUH", "SUL", "SUM",
|
||||||
|
"SBA", "SBB", "SBC", "SBD", "SBE", "SBH", "SBL", "SBM",
|
||||||
|
"NDA", "NDB", "NDC", "NDD", "NDE", "NDH", "NDL", "NDM",
|
||||||
|
"XRA", "XRB", "XRC", "XRD", "XRE", "XRH", "XRL", "XRM",
|
||||||
|
"ORA", "ORB", "ORC", "ORD", "ORE", "ORH", "ORL", "ORM",
|
||||||
|
"CPA", "CPB", "CPC", "CPD", "CPE", "CPH", "CPL", "CPM",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const cval[] = {
|
||||||
|
"NOP", "LAB", "LAC", "LAD", "LAE", "LAH", "LAL", "LAM",
|
||||||
|
"LBA", "LBB", "LBC", "LBD", "LBE", "LBH", "LBL", "LBM",
|
||||||
|
"LCA", "LCB", "LCC", "LCD", "LCE", "LCH", "LCL", "LCM",
|
||||||
|
"LDA", "LDB", "LDC", "LDD", "LDE", "LDH", "LDL", "LDM",
|
||||||
|
"LEA", "LEB", "LEC", "LED", "LEE", "LEH", "LEL", "LEM",
|
||||||
|
"LHA", "LHB", "LHC", "LHD", "LHE", "LHH", "LHL", "LHM",
|
||||||
|
"LLA", "LLB", "LLC", "LLD", "LLE", "LLH", "LLL", "LLM",
|
||||||
|
"LMA", "LMB", "LMC", "LMD", "LME", "LMH", "LML", "HLT",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const dval[] = {
|
||||||
|
"JFC", "CFC", "JMP", "CAL", "JFZ", "CFZ", "", "",
|
||||||
|
"JFS", "CFS", "", "", "JFP", "CFP", "", "",
|
||||||
|
"JTC", "CTC", "", "", "JTZ", "CTZ", "", "",
|
||||||
|
"JTS", "CTS", "", "", "JTP", "CTP",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const eval[] = { "", "INB", "INC", "IND",
|
||||||
|
"INE", "INH", "INL",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const fval[] = { "", "DCB", "DCC", "DCD",
|
||||||
|
"DCE", "DCH", "DCL",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const gval[] = { "ADI", "ACI", "SUI", "SBI",
|
||||||
|
"NDI", "XRI", "ORI", "CPI",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const hval[] = { "LAI", "LBI", "LCI", "LDI",
|
||||||
|
"LEI", "LHI", "LLI", "LMI",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const ival[] = { "RFC", "RFZ", "RFS", "RFP",
|
||||||
|
"RTC", "RTZ", "RTS", "RTP",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const jval[] = { "RLC", "RRC", "RAL", "RAR",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const *const valtab[] = {
|
||||||
|
bval, cval, dval, eval, fval,
|
||||||
|
gval, hval, ival, jval
|
||||||
|
};
|
||||||
|
|
||||||
|
static int match_i8008(char c, const char *p, const char **q)
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
|
||||||
|
if (c <= 'j') {
|
||||||
|
v = mreg(p, valtab[(int) (c - 'b')], q);
|
||||||
|
} else {
|
||||||
|
v = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gen_i8008(int *eb, char p, const int *vs, int i, int savepc)
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
|
||||||
|
b = *eb;
|
||||||
|
switch (p) {
|
||||||
|
case 'f': if (s_pass > 0 && (vs[i] < 0 || vs[i] > 7)) {
|
||||||
|
eprint(_("argument (%d) must be in range [0-7]\n"),
|
||||||
|
vs[i]);
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
b |= (vs[i] << 1);
|
||||||
|
break;
|
||||||
|
case 'g': if (s_pass > 0 && (vs[i] < 8 || vs[i] > 31)) {
|
||||||
|
eprint(_("argument (%d) must be in range [8-31]\n"),
|
||||||
|
vs[i]);
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
b |= (vs[i] << 1);
|
||||||
|
break;
|
||||||
|
case 'h': b |= (vs[i] << 4); break;
|
||||||
|
case 'i': b |= (vs[i] << 1); break;
|
||||||
|
case 'j': if (s_pass > 0 && (vs[i] < 0 || vs[i] > 7)) {
|
||||||
|
eprint(_("argument (%d) must be in range [0-7]\n"),
|
||||||
|
vs[i]);
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
b |= (vs[i] << 3);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*eb = b;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s_pat_char = 'b';
|
||||||
|
static int s_pat_index;
|
||||||
|
|
||||||
|
static void pat_char_rewind_i8008(int c)
|
||||||
|
{
|
||||||
|
s_pat_char = c;
|
||||||
|
s_pat_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *pat_next_str_i8008(void)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (s_pat_char >= 'b' && s_pat_char <= 'j') {
|
||||||
|
s = valtab[(int) (s_pat_char - 'b')][s_pat_index];
|
||||||
|
if (s != NULL) {
|
||||||
|
s_pat_index++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_i8008 = {
|
||||||
|
.id = "i8008",
|
||||||
|
.descr = "Intel 8008",
|
||||||
|
.matcht = s_matchtab_i8008,
|
||||||
|
.matchf = match_i8008,
|
||||||
|
.genf = gen_i8008,
|
||||||
|
.pat_char_rewind = pat_char_rewind_i8008,
|
||||||
|
.pat_next_str = pat_next_str_i8008,
|
||||||
|
.mask = 1
|
||||||
|
};
|
||||||
|
|
276
2048/uz80as/i8048.c
Normal file
276
2048/uz80as/i8048.c
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Intel 8021.
|
||||||
|
* Intel 8022.
|
||||||
|
* Intel 8041.
|
||||||
|
* Intel 8048.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pp.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "uz80as.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* pat:
|
||||||
|
* a: expr
|
||||||
|
* b: R0,R1,R2,R3,R4,R5,R6,R7
|
||||||
|
* c: R0,R1
|
||||||
|
* d: P1,P2
|
||||||
|
* e: P4,P5,P6,P7
|
||||||
|
* f: JB0,JB1,JB2,JB3,JB4,JB5,JB6,JB7
|
||||||
|
*
|
||||||
|
* gen:
|
||||||
|
* .: output lastbyte
|
||||||
|
* b: (op << 3) | lastbyte
|
||||||
|
* c: op | lastbyte
|
||||||
|
* d: lastbyte = op as 8 bit value
|
||||||
|
* e: output op as word (no '.' should follow)
|
||||||
|
* f: output lastbyte | ((op & 0x700) >> 3)
|
||||||
|
* output op as 8 bit value
|
||||||
|
* (no '.' should follow)
|
||||||
|
* g: (op << 5) | lastbyte
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct matchtab s_matchtab_i8048[] = {
|
||||||
|
{ "NOP", "00.", 1, 0 },
|
||||||
|
{ "ADD A,b", "68c0.", 1, 0 },
|
||||||
|
{ "ADD A,@c", "60c0.", 1, 0 },
|
||||||
|
{ "ADD A,#a", "03.d0.", 1, 0, "e8" },
|
||||||
|
{ "ADDC A,b", "78c0.", 1, 0 },
|
||||||
|
{ "ADDC A,@c", "70c0.", 1, 0 },
|
||||||
|
{ "ADDC A,#a", "13.d0.", 1, 0, "e8" },
|
||||||
|
{ "ANL A,b", "58c0.", 1, 0 },
|
||||||
|
{ "ANL A,@c", "50c0.", 1, 0 },
|
||||||
|
{ "ANL A,#a", "53.d0.", 1, 0, "e8" },
|
||||||
|
{ "ANL BUS,#a", "98.d0.", 32, 0, "e8" },
|
||||||
|
{ "ANL d,#a", "98c0.d1.", 4, 0, "e8" },
|
||||||
|
{ "ANLD e,A", "9Cc0.", 1, 0 },
|
||||||
|
{ "CALL a", "14f0", 1, 0 },
|
||||||
|
{ "CLR A", "27.", 1, 0 },
|
||||||
|
{ "CLR C", "97.", 1, 0 },
|
||||||
|
{ "CLR F1", "A5.", 4, 0 },
|
||||||
|
{ "CLR F0", "85.", 4, 0 },
|
||||||
|
{ "CPL A", "37.", 1, 0 },
|
||||||
|
{ "CPL C", "A7.", 1, 0 },
|
||||||
|
{ "CPL F0", "95.", 4, 0 },
|
||||||
|
{ "CPL F1", "B5.", 4, 0 },
|
||||||
|
{ "DA A", "57.", 1, 0 },
|
||||||
|
{ "DEC A", "07.", 1, 0 },
|
||||||
|
{ "DEC b", "C8c0.", 4, 0 },
|
||||||
|
{ "DIS I", "15.", 2, 0 },
|
||||||
|
{ "DIS TCNTI", "35.", 2, 0 },
|
||||||
|
{ "DJNZ b,a", "E8c0.d1.", 1, 0, "e8" },
|
||||||
|
{ "EN DMA", "E5.", 64, 0 },
|
||||||
|
{ "EN FLAGS", "F5.", 64, 0 },
|
||||||
|
{ "EN I", "05.", 2, 0 },
|
||||||
|
{ "EN TCNTI", "25.", 2, 0 },
|
||||||
|
{ "ENT0 CLK", "75.", 32, 0 },
|
||||||
|
{ "IN A,DBB", "22.", 64, 0 },
|
||||||
|
{ "IN A,P0", "08.", 8, 0 },
|
||||||
|
{ "IN A,d", "08c0.", 1, 0 },
|
||||||
|
{ "INC A", "17.", 1, 0 },
|
||||||
|
{ "INC b", "18c0.", 1, 0 },
|
||||||
|
{ "INC @c", "10c0.", 1, 0 },
|
||||||
|
{ "INS A,BUS", "08.", 32, 0 },
|
||||||
|
{ "f a", "12g0.d1.", 4, 0, "e8" },
|
||||||
|
{ "JC a", "F6.d0.", 1, 0, "e8" },
|
||||||
|
{ "JF0 a", "B6.d0.", 4, 0, "e8" },
|
||||||
|
{ "JF1 a", "76.d0.", 4, 0, "e8" },
|
||||||
|
{ "JMP a", "04f0", 1, 0, "e11" },
|
||||||
|
{ "JMPP @A", "B3.", 1, 0 },
|
||||||
|
{ "JNC a", "E6.d0.", 1, 0, "e8" },
|
||||||
|
{ "JNI a", "86.d0.", 32, 0, "e8" },
|
||||||
|
{ "JNIBF a", "D6.d0.", 64, 0, "e8" },
|
||||||
|
{ "JNT0 a", "26.d0.", 2, 0, "e8" },
|
||||||
|
{ "JNT1 a", "46.d0.", 1, 0, "e8" },
|
||||||
|
{ "JNZ a", "96.d0.", 1, 0, "e8" },
|
||||||
|
{ "JOBF a", "86.d0.", 64, 0, "e8" },
|
||||||
|
{ "JTF a", "16.d0.", 1, 0, "e8" },
|
||||||
|
{ "JT0 a", "36.d0.", 2, 0, "e8" },
|
||||||
|
{ "JT1 a", "56.d0.", 1, 0, "e8" },
|
||||||
|
{ "JZ a", "C6.d0.", 1, 0, "e8" },
|
||||||
|
{ "MOV A,#a", "23.d0.", 1, 0, "e8" },
|
||||||
|
{ "MOV A,PSW", "C7.", 4, 0 },
|
||||||
|
{ "MOV A,b", "F8c0.", 1, 0 },
|
||||||
|
{ "MOV A,@c", "F0c0.", 1, 0 },
|
||||||
|
{ "MOV A,T", "42.", 1, 0 },
|
||||||
|
{ "MOV PSW,A", "D7.", 4, 0 },
|
||||||
|
{ "MOV b,A", "A8c0.", 1, 0 },
|
||||||
|
{ "MOV b,#a", "B8c0.d1.", 1, 0, "e8" },
|
||||||
|
{ "MOV @c,A", "A0c0.", 1, 0 },
|
||||||
|
{ "MOV @c,#a", "B0c0.d1.", 1, 0, "e8" },
|
||||||
|
{ "MOV STS,A", "90.", 64, 0 },
|
||||||
|
{ "MOV T,A", "62.", 1, 0 },
|
||||||
|
{ "MOVD A,e", "0Cc0.", 1, 0 },
|
||||||
|
{ "MOVD e,A", "3Cc0.", 1, 0 },
|
||||||
|
{ "MOVP A,@A", "A3.", 1, 0 },
|
||||||
|
{ "MOVP3 A,@A", "E3.", 4, 0 },
|
||||||
|
{ "MOVX A,@c", "80c0.", 32, 0 },
|
||||||
|
{ "MOVX @c,A", "90c0.", 32, 0 },
|
||||||
|
{ "NOP", "00.", 1, 0 },
|
||||||
|
{ "ORL A,b", "48c0.", 1, 0 },
|
||||||
|
{ "ORL A,@c", "40c0.", 1, 0 },
|
||||||
|
{ "ORL A,#a", "43.d0.", 1, 0, "e8" },
|
||||||
|
{ "ORL BUS,#a", "88.d0.", 32, 0, "e8" },
|
||||||
|
{ "ORL d,#a", "88c0.d1.", 4, 0, "e8" },
|
||||||
|
{ "ORLD e,A", "8Cc0.", 1, 0 },
|
||||||
|
{ "OUT DBB,A", "02.", 64, 0 },
|
||||||
|
{ "OUTL BUS,A", "02.", 32, 0 },
|
||||||
|
{ "OUTL P0,A", "90.", 8, 0 },
|
||||||
|
{ "OUTL d,A", "38c0.", 1, 0 },
|
||||||
|
{ "RAD", "80.", 16, 0 },
|
||||||
|
{ "RET", "83.", 1, 0 },
|
||||||
|
{ "RETR", "93.", 4, 0 },
|
||||||
|
{ "RETI", "93.", 16, 0 },
|
||||||
|
{ "RL A", "E7.", 1, 0 },
|
||||||
|
{ "RLC A", "F7.", 1, 0 },
|
||||||
|
{ "RR A", "77.", 1, 0 },
|
||||||
|
{ "RRC A", "67.", 1, 0 },
|
||||||
|
{ "SEL AN0", "85.", 16, 0 },
|
||||||
|
{ "SEL AN1", "95.", 16, 0 },
|
||||||
|
{ "SEL MB0", "E5.", 32, 0 },
|
||||||
|
{ "SEL MB1", "F5.", 32, 0 },
|
||||||
|
{ "SEL RB0", "C5.", 4, 0 },
|
||||||
|
{ "SEL RB1", "D5.", 4, 0 },
|
||||||
|
{ "STOP TCNT", "65.", 1, 0 },
|
||||||
|
{ "STRT CNT", "45.", 1, 0 },
|
||||||
|
{ "STRT T", "55.", 1, 0 },
|
||||||
|
{ "SWAP A", "47.", 1, 0 },
|
||||||
|
{ "XCH A,b", "28c0.", 1, 0 },
|
||||||
|
{ "XCH A,@c", "20c0.", 1, 0 },
|
||||||
|
{ "XCHD A,@c", "30c0.", 1, 0 },
|
||||||
|
{ "XRL A,b", "D8c0.", 1, 0 },
|
||||||
|
{ "XRL A,@c", "D0c0.", 1, 0 },
|
||||||
|
{ "XRL A,#a", "D3.d0.", 1, 0, "e8" },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const bval[] = {
|
||||||
|
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const cval[] = {
|
||||||
|
"R0", "R1",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const dval[] = {
|
||||||
|
"", "P1", "P2",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const eval[] = {
|
||||||
|
"P4", "P5", "P6", "P7",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const fval[] = {
|
||||||
|
"JB0", "JB1", "JB2", "JB3", "JB4", "JB5", "JB6", "JB7",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const *const valtab[] = {
|
||||||
|
bval, cval, dval, eval, fval
|
||||||
|
};
|
||||||
|
|
||||||
|
static int match_i8048(char c, const char *p, const char **q)
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
|
||||||
|
if (c <= 'f') {
|
||||||
|
v = mreg(p, valtab[(int) (c - 'b')], q);
|
||||||
|
} else {
|
||||||
|
v = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gen_i8048(int *eb, char p, const int *vs, int i, int savepc)
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
|
||||||
|
b = *eb;
|
||||||
|
switch (p) {
|
||||||
|
case 'f': b |= ((vs[i] & 0x700) >> 3);
|
||||||
|
genb(b, s_pline_ep);
|
||||||
|
genb(vs[i], s_pline_ep);
|
||||||
|
break;
|
||||||
|
case 'g': b |= (vs[i] << 5);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*eb = b;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s_pat_char = 'b';
|
||||||
|
static int s_pat_index;
|
||||||
|
|
||||||
|
static void pat_char_rewind_i8048(int c)
|
||||||
|
{
|
||||||
|
s_pat_char = c;
|
||||||
|
s_pat_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *pat_next_str_i8048(void)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (s_pat_char >= 'b' && s_pat_char <= 'f') {
|
||||||
|
s = valtab[(int) (s_pat_char - 'b')][s_pat_index];
|
||||||
|
if (s != NULL) {
|
||||||
|
s_pat_index++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_i8041 = {
|
||||||
|
.id = "i8041",
|
||||||
|
.descr = "Intel 8041",
|
||||||
|
.matcht = s_matchtab_i8048,
|
||||||
|
.matchf = match_i8048,
|
||||||
|
.genf = gen_i8048,
|
||||||
|
.pat_char_rewind = pat_char_rewind_i8048,
|
||||||
|
.pat_next_str = pat_next_str_i8048,
|
||||||
|
.mask = 71
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_i8048 = {
|
||||||
|
.id = "i8048",
|
||||||
|
.descr = "Intel 8048",
|
||||||
|
.matcht = s_matchtab_i8048,
|
||||||
|
.matchf = match_i8048,
|
||||||
|
.genf = gen_i8048,
|
||||||
|
.pat_char_rewind = pat_char_rewind_i8048,
|
||||||
|
.pat_next_str = pat_next_str_i8048,
|
||||||
|
.mask = 39
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_i8021 = {
|
||||||
|
.id = "i8021",
|
||||||
|
.descr = "Intel 8021",
|
||||||
|
.matcht = s_matchtab_i8048,
|
||||||
|
.matchf = match_i8048,
|
||||||
|
.genf = gen_i8048,
|
||||||
|
.pat_char_rewind = pat_char_rewind_i8048,
|
||||||
|
.pat_next_str = pat_next_str_i8048,
|
||||||
|
.mask = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_i8022 = {
|
||||||
|
.id = "i8022",
|
||||||
|
.descr = "Intel 8022",
|
||||||
|
.matcht = s_matchtab_i8048,
|
||||||
|
.matchf = match_i8048,
|
||||||
|
.genf = gen_i8048,
|
||||||
|
.pat_char_rewind = pat_char_rewind_i8048,
|
||||||
|
.pat_next_str = pat_next_str_i8048,
|
||||||
|
.mask = 27
|
||||||
|
};
|
||||||
|
|
244
2048/uz80as/i8051.c
Normal file
244
2048/uz80as/i8051.c
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Intel 8051.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pp.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "uz80as.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* pat:
|
||||||
|
* a: expr
|
||||||
|
* b: R0,R1,R2,R3,R4,R5,R6,R7
|
||||||
|
* c: R0,R1
|
||||||
|
* d: ADD,ADDC,ORL,ANL,XRL,SUBB,XCH,MOV
|
||||||
|
*
|
||||||
|
* gen:
|
||||||
|
* .: output lastbyte
|
||||||
|
* b: (op << 3) | lastbyte
|
||||||
|
* c: op | lastbyte
|
||||||
|
* d: lastbyte = op as 8 bit value
|
||||||
|
* e: output op as word (no '.' should follow)
|
||||||
|
* f: output lastbyte | ((op & 0x700) >> 3)
|
||||||
|
* output op as 8 bit value
|
||||||
|
* (no '.' should follow)
|
||||||
|
* g: relative jump -2
|
||||||
|
* h: relative jump -3
|
||||||
|
* i: ouput op as big endian word
|
||||||
|
* j: b + (op << 4)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct matchtab s_matchtab_i8051[] = {
|
||||||
|
{ "ACALL a", "11f0", 1, 0, "e11" },
|
||||||
|
{ "d A,b", "08j0c1.", 1, 0 },
|
||||||
|
{ "d A,@c", "06j0c1.", 1, 0 },
|
||||||
|
{ "ADD A,#a", "24.d0.", 1, 0, "e8" },
|
||||||
|
{ "ADDC A,#a", "34.d0.", 1, 0, "e8" },
|
||||||
|
{ "ORL A,#a", "44.d0.", 1, 0, "e8" },
|
||||||
|
{ "ANL A,#a", "54.d0.", 1, 0, "e8" },
|
||||||
|
{ "XRL A,#a", "64.d0.", 1, 0, "e8" },
|
||||||
|
{ "SUBB A,#a", "94.d0.", 1, 0, "e8" },
|
||||||
|
{ "MOV A,#a", "74.d0.", 1, 0, "e8" },
|
||||||
|
{ "d A,a", "05j0.d1.", 1, 0, "e8" },
|
||||||
|
// { "ADD A,b", "28c0.", 1, 0 },
|
||||||
|
// { "ADD A,@c", "26c0.", 1, 0 },
|
||||||
|
// { "ADD A,a", "25.d0.", 1, 0, "e8" },
|
||||||
|
// { "ADDC A,b", "38c0.", 1, 0 },
|
||||||
|
// { "ADDC A,@c", "36c0.", 1, 0 },
|
||||||
|
// { "ADDC A,a", "35.d0.", 1, 0, "e8" },
|
||||||
|
{ "AJMP a", "01f0", 1, 0, "e11" },
|
||||||
|
// { "ANL A,b", "58c0.", 1, 0 },
|
||||||
|
// { "ANL A,@c", "56c0.", 1, 0 },
|
||||||
|
// { "ANL A,a", "55.d0.", 1, 0, "e8" },
|
||||||
|
{ "ANL C,/a", "B0.d0.", 1, 0, "e8" },
|
||||||
|
{ "ANL C,a", "82.d0.", 1, 0, "e8" },
|
||||||
|
{ "ANL a,A", "52.d0.", 1, 0 },
|
||||||
|
{ "ANL a,#a", "53.d0.d1.", 1, 0, "e8e8" },
|
||||||
|
{ "CJNE A,#a,a", "B4.d0.h1.", 1, 0, "e8r8" },
|
||||||
|
{ "CJNE b,#a,a", "B8c0.d1.h2.", 1, 0, "e8r8" },
|
||||||
|
{ "CJNE @c,#a,a", "B6c0.d1.h2.", 1, 0, "e8r8" },
|
||||||
|
{ "CJNE A,a,a", "B5.d0.h1.", 1, 0, "e8r8" },
|
||||||
|
{ "CLR A", "E4.", 1, 0 },
|
||||||
|
{ "CLR C", "C3.", 1, 0 },
|
||||||
|
{ "CLR a", "C2.d0.", 1, 0, "e8" },
|
||||||
|
{ "CPL A", "F4.", 1, 0 },
|
||||||
|
{ "CPL C", "B3.", 1, 0 },
|
||||||
|
{ "CPL a", "B2.d0.", 1, 0, "e8" },
|
||||||
|
{ "DA A", "D4.", 1, 0 },
|
||||||
|
{ "DEC A", "14.", 1, 0 },
|
||||||
|
{ "DEC b", "18c0.", 1, 0 },
|
||||||
|
{ "DEC @c", "16c0.", 1, 0 },
|
||||||
|
{ "DEC a", "15.d0.", 1, 0, "e8" },
|
||||||
|
{ "DIV AB", "84.", 1, 0 },
|
||||||
|
{ "DJNZ b,a", "D8c0.g1.", 1, 0, "r8" },
|
||||||
|
{ "DJNZ a,a", "D5.d0.h1.", 1, 0, "e8r8" },
|
||||||
|
{ "INC DPTR", "A3.", 1, 0 },
|
||||||
|
{ "INC A", "04.", 1, 0 },
|
||||||
|
{ "INC b", "08c0.", 1, 0 },
|
||||||
|
{ "INC @c", "06c0.", 1, 0 },
|
||||||
|
{ "INC a", "05.d0.", 1, 0, "e8" },
|
||||||
|
{ "JB a,a", "20.d0.h1.", 1, 0, "e8r8" },
|
||||||
|
{ "JBC a,a", "10.d0.h1.", 1, 0, "e8r8" },
|
||||||
|
{ "JC a", "40.g0.", 1, 0, "r8" },
|
||||||
|
{ "JMP @A+DPTR", "73.", 1, 0 },
|
||||||
|
{ "JNB a,a", "30.d0.h1.", 1, 0, "e8r8" },
|
||||||
|
{ "JNC a", "50.g0.", 1, 0, "r8" },
|
||||||
|
{ "JNZ a", "70.g0.", 1, 0, "r8" },
|
||||||
|
{ "JZ a", "60.g0.", 1, 0, "r8" },
|
||||||
|
{ "LCALL a", "12.i0", 1, 0 },
|
||||||
|
{ "LJMP a", "02.i0", 1, 0 },
|
||||||
|
// { "MOV A,b", "E8c0.", 1, 0 },
|
||||||
|
// { "MOV A,@c", "E6c0.", 1, 0 },
|
||||||
|
// { "MOV A,a", "E5.d0.", 1, 0, "e8" }, // MOV A,ACC not valid?
|
||||||
|
{ "MOV b,A", "F8c0.", 1, 0 },
|
||||||
|
{ "MOV b,#a", "78c0.d1.", 1, 0, "e8" },
|
||||||
|
{ "MOV b,a", "A8c0.d1.", 1, 0, "e8" },
|
||||||
|
{ "MOV @c,A", "F6c0.", 1, 0 },
|
||||||
|
{ "MOV @c,#a", "76c0.d1.", 1, 0, "e8" },
|
||||||
|
{ "MOV @c,a", "A6c0.d1.", 1, 0, "e8" },
|
||||||
|
{ "MOV C,a", "A2.d0.", 1, 0, "e8" },
|
||||||
|
{ "MOV DPTR,#a", "90.i0", 1, 0, "e8" },
|
||||||
|
{ "MOV a,A", "F5.d0.", 1, 0, "e8" },
|
||||||
|
{ "MOV a,C", "92.d0.", 1, 0, "e8" },
|
||||||
|
{ "MOV a,b", "88c1.d0.", 1, 0, "e8" },
|
||||||
|
{ "MOV a,@c", "86c1.d0.", 1, 0, "e8" },
|
||||||
|
{ "MOV a,#a", "75.d0.d1.", 1, 0, "e8e8" },
|
||||||
|
{ "MOV a,a", "85.d1.d0.", 1, 0, "e8e8" },
|
||||||
|
{ "MOVC A,@A+DPTR", "93.", 1, 0 },
|
||||||
|
{ "MOVC A,@A+PC", "83.", 1, 0 },
|
||||||
|
{ "MOVX A,@c", "E2c0.", 1, 0 },
|
||||||
|
{ "MOVX A,@DPTR", "E0.", 1, 0 },
|
||||||
|
{ "MOVX @c,A", "F2c0.", 1, 0 },
|
||||||
|
{ "MOVX @DPTR,A", "F0.", 1, 0 },
|
||||||
|
{ "MUL AB", "A4.", 1, 0 },
|
||||||
|
{ "NOP", "00.", 1, 0 },
|
||||||
|
// { "ORL A,b", "48c0.", 1, 0 },
|
||||||
|
// { "ORL A,@c", "46c0.", 1, 0 },
|
||||||
|
// { "ORL A,a", "45.d0.", 1, 0, "e8" },
|
||||||
|
{ "ORL C,/a", "A0.d0.", 1, 0, "e8" },
|
||||||
|
{ "ORL C,a", "72.d0.", 1, 0, "e8" },
|
||||||
|
{ "ORL a,A", "42.d0.", 1, 0, "e8" },
|
||||||
|
{ "ORL a,#a", "43.d0.d1.", 1, 0, "e8e8" },
|
||||||
|
{ "POP a", "D0.d0.", 1, 0, "e8" },
|
||||||
|
{ "PUSH a", "C0.d0.", 1, 0, "e8" },
|
||||||
|
{ "RET", "22.", 1, 0 },
|
||||||
|
{ "RETI", "32.", 1, 0 },
|
||||||
|
{ "RL A", "23.", 1, 0 },
|
||||||
|
{ "RLC A", "33.", 1, 0 },
|
||||||
|
{ "RR A", "03.", 1, 0 },
|
||||||
|
{ "RRC A", "13.", 1, 0 },
|
||||||
|
{ "SETB C", "D3.", 1, 0 },
|
||||||
|
{ "SETB a", "D2.d0.", 1, 0, "e8" },
|
||||||
|
{ "SJMP a", "80.g0.", 1, 0, "r8" },
|
||||||
|
// { "SUBB A,b", "98c0.", 1, 0 },
|
||||||
|
// { "SUBB A,@c", "96c0.", 1, 0 },
|
||||||
|
// { "SUBB A,a", "95.d0.", 1, 0, "e8" },
|
||||||
|
{ "SWAP A", "C4.", 1, 0 },
|
||||||
|
// { "XCH A,b", "C8c0.", 1, 0 },
|
||||||
|
// { "XCH A,@c", "C6c0.", 1, 0 },
|
||||||
|
// { "XCH A,a", "C5.d0.", 1, 0, "e8" },
|
||||||
|
{ "XCHD A,@c", "D6c0.", 1, 0 },
|
||||||
|
// { "XRL A,b", "68c0.", 1, 0 },
|
||||||
|
// { "XRL A,@c", "66c0.", 1, 0 },
|
||||||
|
// { "XRL A,a", "65.d0.", 1, 0, "e8" },
|
||||||
|
{ "XRL a,A", "62.d0.", 1, 0, "e8" },
|
||||||
|
{ "XRL a,#a", "63.d0.d1.", 1, 0, "e8e8" },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const bval[] = {
|
||||||
|
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const cval[] = {
|
||||||
|
"R0", "R1",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const dval[] = {
|
||||||
|
"", "", "ADD", "ADDC", "ORL", "ANL", "XRL", "",
|
||||||
|
"", "SUBB", "", "", "XCH", "", "MOV",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const *const valtab[] = {
|
||||||
|
bval, cval, dval
|
||||||
|
};
|
||||||
|
|
||||||
|
static int match_i8051(char c, const char *p, const char **q)
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
|
||||||
|
if (c <= 'd') {
|
||||||
|
v = mreg(p, valtab[(int) (c - 'b')], q);
|
||||||
|
} else {
|
||||||
|
v = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gen_i8051(int *eb, char p, const int *vs, int i, int savepc)
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
|
||||||
|
b = *eb;
|
||||||
|
switch (p) {
|
||||||
|
case 'f': b |= ((vs[i] & 0x700) >> 3);
|
||||||
|
genb(b, s_pline_ep);
|
||||||
|
genb(vs[i], s_pline_ep);
|
||||||
|
break;
|
||||||
|
case 'g': b = (vs[i] - savepc - 2); break;
|
||||||
|
break;
|
||||||
|
case 'h': b = (vs[i] - savepc - 3); break;
|
||||||
|
break;
|
||||||
|
case 'i': genb(vs[i] >> 8, s_pline_ep);
|
||||||
|
genb(vs[i], s_pline_ep);
|
||||||
|
break;
|
||||||
|
case 'j': b += (vs[i] << 4); break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*eb = b;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s_pat_char = 'b';
|
||||||
|
static int s_pat_index;
|
||||||
|
|
||||||
|
static void pat_char_rewind_i8051(int c)
|
||||||
|
{
|
||||||
|
s_pat_char = c;
|
||||||
|
s_pat_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *pat_next_str_i8051(void)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (s_pat_char >= 'b' && s_pat_char <= 'd') {
|
||||||
|
s = valtab[(int) (s_pat_char - 'b')][s_pat_index];
|
||||||
|
if (s != NULL) {
|
||||||
|
s_pat_index++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_i8051 = {
|
||||||
|
.id = "i8051",
|
||||||
|
.descr = "Intel 8051",
|
||||||
|
.matcht = s_matchtab_i8051,
|
||||||
|
.matchf = match_i8051,
|
||||||
|
.genf = gen_i8051,
|
||||||
|
.pat_char_rewind = pat_char_rewind_i8051,
|
||||||
|
.pat_next_str = pat_next_str_i8051,
|
||||||
|
.mask = 1
|
||||||
|
};
|
||||||
|
|
214
2048/uz80as/i8080.c
Normal file
214
2048/uz80as/i8080.c
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Intel 8080.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pp.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "uz80as.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* pat:
|
||||||
|
* a: expr
|
||||||
|
* b: B,C,D,E,H,L,M,A
|
||||||
|
* c: B,D,H,SP
|
||||||
|
* d: B,D
|
||||||
|
* e: B,D,H,PSW
|
||||||
|
* f: JNZ,JZ,JNC,JC,JPO,JPE,JP,JM
|
||||||
|
* g: CNZ,CZ,CNC,CC,CPO,CPE,CP,CM
|
||||||
|
* h: RNZ,RZ,RNC,RC,RPO,RPE,RP,RM
|
||||||
|
* i: B,C,D,E,H,L,A
|
||||||
|
* j: ADD,ADC,SUB,SBB,ANA,XRA,ORA,CMP
|
||||||
|
* k: RLC,RRC,RAL,RAR
|
||||||
|
* l: ADI,ACI,SUI,SBI,ANI,XRI,ORI,CPI
|
||||||
|
* m: SHLD,LHLD,STA,LDA
|
||||||
|
* n: DI,EI
|
||||||
|
* o: OUT,IN
|
||||||
|
* p: STC,CMC
|
||||||
|
* q: POP,PUSH
|
||||||
|
* r: STAX,LDAX
|
||||||
|
*
|
||||||
|
* gen:
|
||||||
|
* .: output lastbyte
|
||||||
|
* b: (op << 3) | lastbyte
|
||||||
|
* c: op | lastbyte
|
||||||
|
* d: lastbyte = op as 8 bit value
|
||||||
|
* e: output op as word (no '.' should follow)
|
||||||
|
* f: (op << 4) | lastbyte
|
||||||
|
* g: possible value to RST
|
||||||
|
* h: (op << 2) | lastbyte
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct matchtab s_matchtab_i8080[] = {
|
||||||
|
{ "MOV M,i", "70c0.", 3, 0 },
|
||||||
|
{ "MOV i,M", "46b0.", 3, 0 },
|
||||||
|
{ "MOV i,i", "40b0c1.", 3, 0 },
|
||||||
|
{ "MVI b,a", "06b0.d1.", 3, 0, "e8" },
|
||||||
|
{ "LXI c,a", "01f0.e1", 3, 0 },
|
||||||
|
{ "m a", "22b0.e1", 3, 0 },
|
||||||
|
{ "r d", "02b0f1.", 3, 0 },
|
||||||
|
{ "XCHG", "EB.", 3, 0 },
|
||||||
|
{ "j b", "80b0c1.", 3, 0 },
|
||||||
|
{ "l a", "C6b0.d1.", 3, 0, "e8" },
|
||||||
|
{ "INR b", "04b0.", 3, 0 },
|
||||||
|
{ "DCR b", "05b0.", 3, 0 },
|
||||||
|
{ "INX c", "03f0.", 3, 0 },
|
||||||
|
{ "DCX c", "0Bf0.", 3, 0 },
|
||||||
|
{ "DAD c", "09f0.", 3, 0 },
|
||||||
|
{ "DAA", "27.", 3, 0 },
|
||||||
|
{ "k", "07b0.", 3, 0 },
|
||||||
|
{ "CMA", "2F.", 3, 0 },
|
||||||
|
{ "p", "37b0.", 3, 0 },
|
||||||
|
{ "JMP a", "C3.e0", 3, 0 },
|
||||||
|
{ "f a", "C2b0.e1", 3, 0 },
|
||||||
|
{ "CALL a", "CD.e0", 3, 0 },
|
||||||
|
{ "g a", "C4b0.e1", 3, 0 },
|
||||||
|
{ "RET", "C9.", 3, 0 },
|
||||||
|
{ "h", "C0b0.", 3, 0 },
|
||||||
|
{ "RST a", "C7g0.", 3, 0, "b3" },
|
||||||
|
{ "PCHL", "E9.", 3, 0 },
|
||||||
|
{ "q e", "C1h0f1.", 3, 0 },
|
||||||
|
{ "XTHL", "E3.", 3, 0 },
|
||||||
|
{ "SPHL", "F9.", 3, 0 },
|
||||||
|
{ "o a", "D3b0.d1.", 3, 0, "e8" },
|
||||||
|
{ "n", "F3b0.", 3, 0 },
|
||||||
|
{ "HLT", "76.", 3, 0 },
|
||||||
|
{ "NOP", "00.", 3, 0 },
|
||||||
|
/* 8085 added instructions */
|
||||||
|
{ "RIM", "20.", 2, 0 },
|
||||||
|
{ "SIM", "30.", 2, 0 },
|
||||||
|
{ "ARHL", "10.", 2, 2 },
|
||||||
|
{ "DSUB", "08.", 2, 2 },
|
||||||
|
{ "RDEL", "18.", 2, 2 },
|
||||||
|
{ "LDHI a", "28.d0.", 2, 2, "e8" },
|
||||||
|
{ "LDSI a", "38.d0.", 2, 2, "e8" },
|
||||||
|
{ "RSTV", "CB.", 2, 2 },
|
||||||
|
{ "SHLX", "D9.", 2, 2 },
|
||||||
|
{ "LHLX", "ED.", 2, 2 },
|
||||||
|
{ "JNK a", "DD.e0", 2, 2 },
|
||||||
|
{ "JNX5 a", "DD.e0", 2, 2 },
|
||||||
|
{ "JNUI a", "DD.e0", 2, 2 },
|
||||||
|
{ "JK a", "FD.e0", 2, 2 },
|
||||||
|
{ "JX5 a", "FD.e0", 2, 2 },
|
||||||
|
{ "JUI a", "FD.e0", 2, 2 },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const bval[] = { "B", "C", "D", "E",
|
||||||
|
"H", "L", "M", "A", NULL };
|
||||||
|
static const char *const cval[] = { "B", "D", "H", "SP", NULL };
|
||||||
|
static const char *const dval[] = { "B", "D", NULL };
|
||||||
|
static const char *const eval[] = { "B", "D", "H", "PSW", NULL };
|
||||||
|
static const char *const fval[] = { "JNZ", "JZ", "JNC", "JC",
|
||||||
|
"JPO", "JPE", "JP", "JM", NULL };
|
||||||
|
static const char *const gval[] = { "CNZ", "CZ", "CNC", "CC",
|
||||||
|
"CPO", "CPE", "CP", "CM", NULL };
|
||||||
|
static const char *const hval[] = { "RNZ", "RZ", "RNC", "RC",
|
||||||
|
"RPO", "RPE", "RP", "RM", NULL };
|
||||||
|
static const char *const ival[] = { "B", "C", "D", "E",
|
||||||
|
"H", "L", "", "A", NULL };
|
||||||
|
static const char *const jval[] = { "ADD", "ADC", "SUB", "SBB",
|
||||||
|
"ANA", "XRA", "ORA", "CMP", NULL };
|
||||||
|
static const char *const kval[] = { "RLC", "RRC", "RAL", "RAR", NULL };
|
||||||
|
static const char *const lval[] = { "ADI", "ACI", "SUI", "SBI",
|
||||||
|
"ANI", "XRI", "ORI", "CPI", NULL };
|
||||||
|
static const char *const mval[] = { "SHLD", "LHLD", "STA", "LDA", NULL };
|
||||||
|
static const char *const nval[] = { "DI", "EI", NULL };
|
||||||
|
static const char *const oval[] = { "OUT", "IN", NULL };
|
||||||
|
static const char *const pval[] = { "STC", "CMC", NULL };
|
||||||
|
static const char *const qval[] = { "POP", "PUSH", NULL };
|
||||||
|
static const char *const rval[] = { "STAX", "LDAX", NULL };
|
||||||
|
|
||||||
|
static const char *const *const valtab[] = {
|
||||||
|
bval, cval, dval, eval, fval,
|
||||||
|
gval, hval, ival, jval, kval,
|
||||||
|
lval, mval, nval, oval, pval,
|
||||||
|
qval, rval
|
||||||
|
};
|
||||||
|
|
||||||
|
static int match_i8080(char c, const char *p, const char **q)
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
|
||||||
|
if (c <= 'r') {
|
||||||
|
v = mreg(p, valtab[(int) (c - 'b')], q);
|
||||||
|
} else {
|
||||||
|
v = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gen_i8080(int *eb, char p, const int *vs, int i, int savepc)
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
|
||||||
|
b = *eb;
|
||||||
|
switch (p) {
|
||||||
|
case 'f': b |= (vs[i] << 4); break;
|
||||||
|
case 'g': if (s_pass > 0 && (vs[i] & ~7) != 0) {
|
||||||
|
eprint(_("invalid RST argument (%d)\n"),
|
||||||
|
vs[i]);
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
b |= (vs[i] << 3);
|
||||||
|
break;
|
||||||
|
case 'h': b |= (vs[i] << 2); break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*eb = b;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s_pat_char = 'b';
|
||||||
|
static int s_pat_index;
|
||||||
|
|
||||||
|
static void pat_char_rewind_i8080(int c)
|
||||||
|
{
|
||||||
|
s_pat_char = c;
|
||||||
|
s_pat_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *pat_next_str_i8080(void)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (s_pat_char >= 'b' && s_pat_char <= 'r') {
|
||||||
|
s = valtab[(int) (s_pat_char - 'b')][s_pat_index];
|
||||||
|
if (s != NULL) {
|
||||||
|
s_pat_index++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_i8080 = {
|
||||||
|
.id = "i8080",
|
||||||
|
.descr = "Intel 8080",
|
||||||
|
.matcht = s_matchtab_i8080,
|
||||||
|
.matchf = match_i8080,
|
||||||
|
.genf = gen_i8080,
|
||||||
|
.pat_char_rewind = pat_char_rewind_i8080,
|
||||||
|
.pat_next_str = pat_next_str_i8080,
|
||||||
|
.mask = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_i8085 = {
|
||||||
|
.id = "i8085",
|
||||||
|
.descr = "Intel 8085",
|
||||||
|
.matcht = s_matchtab_i8080,
|
||||||
|
.matchf = match_i8080,
|
||||||
|
.genf = gen_i8080,
|
||||||
|
.pat_char_rewind = pat_char_rewind_i8080,
|
||||||
|
.pat_next_str = pat_next_str_i8080,
|
||||||
|
.mask = 2
|
||||||
|
};
|
81
2048/uz80as/incl.c
Normal file
81
2048/uz80as/incl.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Include file stack.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "incl.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "err.h"
|
||||||
|
|
||||||
|
#ifndef ASSERT_H
|
||||||
|
#include <assert.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STDIO_H
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STDLIB_H
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Max number of nested included files. */
|
||||||
|
#define NFILES 128
|
||||||
|
|
||||||
|
/* Number of nested files. */
|
||||||
|
static int s_nfiles;
|
||||||
|
|
||||||
|
/* Current file. */
|
||||||
|
static struct incfile *s_curfile;
|
||||||
|
|
||||||
|
/* Get the current file. Never returns NULL. */
|
||||||
|
struct incfile *curfile(void)
|
||||||
|
{
|
||||||
|
assert(s_curfile != NULL);
|
||||||
|
return s_curfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The number of nested files. 0 means no file loaded. */
|
||||||
|
int nfiles(void)
|
||||||
|
{
|
||||||
|
return s_nfiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leave the current included file. */
|
||||||
|
void popfile(void)
|
||||||
|
{
|
||||||
|
struct incfile *ifile;
|
||||||
|
|
||||||
|
assert(s_curfile != NULL);
|
||||||
|
fclose(s_curfile->fin);
|
||||||
|
ifile = s_curfile;
|
||||||
|
s_curfile = ifile->prev;
|
||||||
|
free(ifile);
|
||||||
|
s_nfiles--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Include a file whose name is [p, q[. */
|
||||||
|
void pushfile(const char *p, const char *q)
|
||||||
|
{
|
||||||
|
struct incfile *ifile;
|
||||||
|
|
||||||
|
if (s_nfiles == NFILES) {
|
||||||
|
eprint(_("maximum number of nested includes exceeded (%d)\n"),
|
||||||
|
NFILES);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("pushfile: %s\n", p);
|
||||||
|
ifile = emalloc((sizeof *ifile) + (q - p) + 1);
|
||||||
|
ifile->name = (char *) ((unsigned char *) ifile + sizeof *ifile);
|
||||||
|
copychars(ifile->name, p, q);
|
||||||
|
|
||||||
|
ifile->fin = efopen(ifile->name, "r");
|
||||||
|
ifile->linenum = 0;
|
||||||
|
ifile->prev = s_curfile;
|
||||||
|
s_curfile = ifile;
|
||||||
|
s_nfiles++;
|
||||||
|
}
|
28
2048/uz80as/incl.h
Normal file
28
2048/uz80as/incl.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Include file stack.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INCL_H
|
||||||
|
#define INCL_H
|
||||||
|
|
||||||
|
#ifndef STDIO_H
|
||||||
|
#define STDIO_H
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct incfile {
|
||||||
|
struct incfile *prev;
|
||||||
|
FILE *fin;
|
||||||
|
int linenum;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
void pushfile(const char *p, const char *q);
|
||||||
|
void popfile(void);
|
||||||
|
struct incfile *curfile(void);
|
||||||
|
int nfiles(void);
|
||||||
|
|
||||||
|
#endif
|
164
2048/uz80as/list.c
Normal file
164
2048/uz80as/list.c
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Assembly listing generation.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "err.h"
|
||||||
|
|
||||||
|
#ifndef STDIO_H
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STLIB_H
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STRING_H
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static FILE *s_list_file;
|
||||||
|
|
||||||
|
/* N characters in current line. */
|
||||||
|
static int s_nchars;
|
||||||
|
|
||||||
|
/* Generated data bytes in this line. */
|
||||||
|
static int s_nbytes;
|
||||||
|
|
||||||
|
/* Line text. */
|
||||||
|
static const char *s_line;
|
||||||
|
|
||||||
|
/* Line number. */
|
||||||
|
static int s_linenum;
|
||||||
|
|
||||||
|
/* Program counter. */
|
||||||
|
static int s_pc;
|
||||||
|
|
||||||
|
/* Number of current nested files. */
|
||||||
|
static int s_nfiles;
|
||||||
|
|
||||||
|
/* If listing line number, etc are generated or just the line. */
|
||||||
|
int s_codes = 1;
|
||||||
|
|
||||||
|
/* If listing is enabled or not. */
|
||||||
|
int s_list_on = 1;
|
||||||
|
|
||||||
|
/* If we are skipping lines. */
|
||||||
|
static int s_skip_on = 0;
|
||||||
|
|
||||||
|
void list_open(const char *fname)
|
||||||
|
{
|
||||||
|
s_list_file = fopen(fname, "w");
|
||||||
|
if (s_list_file == NULL) {
|
||||||
|
eprint(_("cannot open file %s\n"), fname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_close(void)
|
||||||
|
{
|
||||||
|
if (s_list_file != NULL)
|
||||||
|
fclose(s_list_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prhead(void)
|
||||||
|
{
|
||||||
|
int i, j, n;
|
||||||
|
|
||||||
|
s_nchars = fprintf(s_list_file, "%-.4d", s_linenum);
|
||||||
|
|
||||||
|
n = 7 - s_nchars;
|
||||||
|
if (n <= 0)
|
||||||
|
n = 1;
|
||||||
|
j = 0;
|
||||||
|
if (s_nfiles > 0)
|
||||||
|
j = s_nfiles - 1;
|
||||||
|
if (j > n)
|
||||||
|
j = n;
|
||||||
|
for (i = 0; i < j; i++)
|
||||||
|
fputc('+', s_list_file);
|
||||||
|
j = n - j;
|
||||||
|
while (j--)
|
||||||
|
fputc(' ', s_list_file);
|
||||||
|
s_nchars += n;
|
||||||
|
|
||||||
|
s_nchars += fprintf(s_list_file, "%.4X", s_pc);
|
||||||
|
if (s_skip_on)
|
||||||
|
fputc('~', s_list_file);
|
||||||
|
else
|
||||||
|
fputc(' ', s_list_file);
|
||||||
|
s_nchars += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prline(void)
|
||||||
|
{
|
||||||
|
if (s_line == NULL) {
|
||||||
|
fputs("\n", s_list_file);
|
||||||
|
} else {
|
||||||
|
if (s_codes) {
|
||||||
|
while (s_nchars < 24) {
|
||||||
|
s_nchars++;
|
||||||
|
fputc(' ', s_list_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(s_list_file, "%s\n", s_line);
|
||||||
|
s_line = NULL;
|
||||||
|
}
|
||||||
|
s_nchars = 0;
|
||||||
|
s_nbytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_startln(const char *line, int linenum, int pc, int nested_files)
|
||||||
|
{
|
||||||
|
if (s_list_file == NULL)
|
||||||
|
return;
|
||||||
|
s_linenum = linenum;
|
||||||
|
s_pc = pc;
|
||||||
|
s_line = line;
|
||||||
|
s_nchars = 0;
|
||||||
|
s_nbytes = 0;
|
||||||
|
s_nfiles = nested_files;
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_setpc(int pc)
|
||||||
|
{
|
||||||
|
s_pc = pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_skip(int on)
|
||||||
|
{
|
||||||
|
s_skip_on = on;
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_eject(void)
|
||||||
|
{
|
||||||
|
if (s_list_file == NULL || !s_list_on)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_genb(int b)
|
||||||
|
{
|
||||||
|
if (s_list_file == NULL || !s_codes || !s_list_on)
|
||||||
|
return;
|
||||||
|
if (s_nchars == 0)
|
||||||
|
prhead();
|
||||||
|
if (s_nbytes >= 4) {
|
||||||
|
prline();
|
||||||
|
prhead();
|
||||||
|
}
|
||||||
|
s_nchars += fprintf(s_list_file, "%2.2X ", (b & 0xff));
|
||||||
|
s_nbytes++;
|
||||||
|
s_pc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void list_endln(void)
|
||||||
|
{
|
||||||
|
if (s_list_file == NULL || !s_list_on)
|
||||||
|
return;
|
||||||
|
if (s_codes && s_nchars == 0)
|
||||||
|
prhead();
|
||||||
|
prline();
|
||||||
|
}
|
23
2048/uz80as/list.h
Normal file
23
2048/uz80as/list.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Assembly listing generation.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIST_H
|
||||||
|
#define LIST_H
|
||||||
|
|
||||||
|
extern int s_codes;
|
||||||
|
extern int s_list_on;
|
||||||
|
|
||||||
|
void list_open(const char *fname);
|
||||||
|
void list_close(void);
|
||||||
|
void list_startln(const char *line, int linenum, int pc, int nested_files);
|
||||||
|
void list_setpc(int pc);
|
||||||
|
void list_skip(int on);
|
||||||
|
void list_eject(void);
|
||||||
|
void list_genb(int b);
|
||||||
|
void list_endln(void);
|
||||||
|
|
||||||
|
#endif
|
303
2048/uz80as/main.c
Normal file
303
2048/uz80as/main.c
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* main(), handling of command line options.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "ngetopt.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "uz80as.h"
|
||||||
|
#include "prtable.h"
|
||||||
|
#include "targets.h"
|
||||||
|
|
||||||
|
#ifndef STDIO_H
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STDLIB_H
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STRING_H
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CTYPE_H
|
||||||
|
#include <ctype.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void print_copyright(FILE *f)
|
||||||
|
{
|
||||||
|
static const char *copyright =
|
||||||
|
"Copyright (C) " COPYRIGHT_YEARS " Jorge Giner Cordero.\n";
|
||||||
|
|
||||||
|
fputs(copyright, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_license(FILE *f)
|
||||||
|
{
|
||||||
|
static const char *license[] = {
|
||||||
|
"Permission is hereby granted, free of charge, to any person obtaining",
|
||||||
|
"a copy of this software and associated documentation files (the",
|
||||||
|
"\"Software\"), to deal in the Software without restriction, including",
|
||||||
|
"without limitation the rights to use, copy, modify, merge, publish,",
|
||||||
|
"distribute, sublicense, and/or sell copies of the Software, and to",
|
||||||
|
"permit persons to whom the Software is furnished to do so, subject to",
|
||||||
|
"the following conditions:",
|
||||||
|
"",
|
||||||
|
"The above copyright notice and this permission notice shall be included",
|
||||||
|
"in all copies or substantial portions of the Software.",
|
||||||
|
"",
|
||||||
|
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,",
|
||||||
|
"EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF",
|
||||||
|
"MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.",
|
||||||
|
"IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY",
|
||||||
|
"CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,",
|
||||||
|
"TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE",
|
||||||
|
"SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
|
||||||
|
};
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(license); i++) {
|
||||||
|
fprintf(f, "%s\n", license[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_version(FILE *f)
|
||||||
|
{
|
||||||
|
const struct target *p;
|
||||||
|
|
||||||
|
fputs(PACKAGE_STRING, f);
|
||||||
|
fputs("\n", f);
|
||||||
|
fputs("Targets:", f);
|
||||||
|
for (p = first_target(); p != NULL; p = next_target()) {
|
||||||
|
fprintf(f, " %s", p->id);
|
||||||
|
}
|
||||||
|
fputs("\n", f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_help(const char *argv0)
|
||||||
|
{
|
||||||
|
static const char *help =
|
||||||
|
"Usage: %s [OPTION]... ASM_FILE [OBJ_FILE [LST_FILE]]\n"
|
||||||
|
"\n"
|
||||||
|
"Assemble ASM_FILE into OBJ_FILE and generate the listing LST_FILE.\n"
|
||||||
|
"If not specified, OBJ_FILE is ASM_FILE with the extension changed to .obj.\n"
|
||||||
|
"If not specified, LST_FILE is ASM_FILE with the extension changed to .lst.\n"
|
||||||
|
"\n"
|
||||||
|
"Options:\n"
|
||||||
|
" -h, --help Display this help and exit.\n"
|
||||||
|
" -V, --verbose be chatty.\n"
|
||||||
|
" -v, --version Output version information and exit.\n"
|
||||||
|
" -l, --license Display the license text and exit.\n"
|
||||||
|
" -d, --define=MACRO Define a macro.\n"
|
||||||
|
" -f, --fill=n Fill memory with value n.\n"
|
||||||
|
" -q, --quiet Do not generate the listing file.\n"
|
||||||
|
" -x, --extended Enable extended instruction syntax.\n"
|
||||||
|
" -u, --undocumented Enable undocumented instructions.\n"
|
||||||
|
" -t, --target=NAME Select the target micro. z80 is the default.\n"
|
||||||
|
" -e, --list-targets List the targets supported.\n"
|
||||||
|
"\n"
|
||||||
|
"Examples:\n"
|
||||||
|
" " PACKAGE " p.asm Assemble p.asm into p.obj\n"
|
||||||
|
" " PACKAGE " p.asm p.bin Assemble p.asm into p.bin\n"
|
||||||
|
" " PACKAGE " -d\"MUL(a,b) (a*b)\" p.asm Define the macro MUL and assemble p.asm\n"
|
||||||
|
"\n"
|
||||||
|
"Report bugs to: <" PACKAGE_BUGREPORT ">.\n"
|
||||||
|
"Home page: <" PACKAGE_URL ">.\n";
|
||||||
|
|
||||||
|
printf(help, argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the filename part of fname (that is, for ../../fname.abc, get
|
||||||
|
* fname.abc).
|
||||||
|
* Then substitute the extension .abd by .ext or append .ext.
|
||||||
|
*/
|
||||||
|
static char *mkfname(const char *fname, const char *ext)
|
||||||
|
{
|
||||||
|
size_t alen, elen;
|
||||||
|
const char *p, *q;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
alen = strlen(fname);
|
||||||
|
elen = strlen(ext);
|
||||||
|
|
||||||
|
/* Find start of filename in path string */
|
||||||
|
p = fname + alen;
|
||||||
|
while (p > fname && *p != '/' && *p != '\\')
|
||||||
|
p--;
|
||||||
|
|
||||||
|
if (*p == '/' || *p == '\\')
|
||||||
|
p++;
|
||||||
|
|
||||||
|
/* Find the extension */
|
||||||
|
q = fname + alen;
|
||||||
|
while (q > p && *q != '.')
|
||||||
|
q--;
|
||||||
|
|
||||||
|
if (*q != '.')
|
||||||
|
q = fname + alen;
|
||||||
|
|
||||||
|
s = emalloc((q - p) + 1 + elen + 1);
|
||||||
|
if (q > p)
|
||||||
|
memmove(s, p, (q - p));
|
||||||
|
s[q - p] = '\0';
|
||||||
|
strcat(s, ".");
|
||||||
|
strcat(s, ext);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_fill_byte(const char *optarg)
|
||||||
|
{
|
||||||
|
int hi, lo;
|
||||||
|
|
||||||
|
if (strlen(optarg) != 2)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if ((hi = hexval(optarg[0])) < 0)
|
||||||
|
goto error;
|
||||||
|
if ((lo = hexval(optarg[1])) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
s_mem_fillval = hi * 16 + lo;
|
||||||
|
return;
|
||||||
|
|
||||||
|
error: eprogname();
|
||||||
|
fprintf(stderr, _("invalid command line fill value (%s)\n"), optarg);
|
||||||
|
eprogname();
|
||||||
|
fprintf(stderr, " ");
|
||||||
|
fprintf(stderr, _("Please, use two hexadecimal digits.\n"));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_target_id(const char *optarg)
|
||||||
|
{
|
||||||
|
const struct target *p;
|
||||||
|
|
||||||
|
p = find_target(optarg);
|
||||||
|
if (p == NULL) {
|
||||||
|
eprogname();
|
||||||
|
fprintf(stderr, _("invalid target '%s'\n"), optarg);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
s_target_id = p->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_targets(FILE *f)
|
||||||
|
{
|
||||||
|
const struct target *p;
|
||||||
|
|
||||||
|
for (p = first_target(); p != NULL; p = next_target()) {
|
||||||
|
fprintf(f, "%-14s%s\n", p->id, p->descr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
struct ngetopt ngo;
|
||||||
|
|
||||||
|
static struct ngetopt_opt ops[] = {
|
||||||
|
{ "define", 1, 'd' },
|
||||||
|
{ "extended", 0, 'x' },
|
||||||
|
{ "list-targets", 0, 'e' },
|
||||||
|
{ "fill", 1, 'f' },
|
||||||
|
{ "help", 0, 'h' },
|
||||||
|
{ "license", 0, 'l' },
|
||||||
|
{ "quiet", 0, 'q' },
|
||||||
|
{ "target", 1, 't' },
|
||||||
|
{ "undocumented", 0, 'u' },
|
||||||
|
{ "version", 0, 'v' },
|
||||||
|
{ "print-table", 1, 0 },
|
||||||
|
{ "print-delta", 1, 0 },
|
||||||
|
{ "verbose", 0, 'V' },
|
||||||
|
{ NULL, 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
ngetopt_init(&ngo, argc, argv, ops);
|
||||||
|
do {
|
||||||
|
c = ngetopt_next(&ngo);
|
||||||
|
switch (c) {
|
||||||
|
case 'V':
|
||||||
|
verbose++;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
print_version(stdout);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
case 'h':
|
||||||
|
print_help(argv[0]);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
case 'l':
|
||||||
|
print_copyright(stdout);
|
||||||
|
fputs("\n", stdout);
|
||||||
|
print_license(stdout);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
case 't':
|
||||||
|
parse_target_id(ngo.optarg);
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
list_targets(stdout);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
predefine(ngo.optarg);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
parse_fill_byte(ngo.optarg);
|
||||||
|
break;
|
||||||
|
case 'q':
|
||||||
|
s_listing = 0;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
s_extended_op = 1;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
s_undocumented_op = 1;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
eprint(_("unrecognized option %s\n"),
|
||||||
|
ngo.optarg);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
case ':':
|
||||||
|
eprint(_("%s needs an argument\n"),
|
||||||
|
ngo.optarg);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
case ';':
|
||||||
|
eprint(_("%s does not allow for arguments\n"),
|
||||||
|
ngo.optarg);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
case 0:
|
||||||
|
if (strcmp(ngo.optstr, "print-table") == 0) {
|
||||||
|
print_table(stdout, ngo.optarg);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (c != -1);
|
||||||
|
|
||||||
|
if (argc == ngo.optind) {
|
||||||
|
eprint(_("wrong number of arguments\n"));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
s_asmfname = argv[ngo.optind];
|
||||||
|
|
||||||
|
if (argc - ngo.optind > 1)
|
||||||
|
s_objfname = argv[ngo.optind + 1];
|
||||||
|
else
|
||||||
|
s_objfname = mkfname(s_asmfname, "obj");
|
||||||
|
|
||||||
|
if (argc - ngo.optind > 2)
|
||||||
|
s_lstfname = argv[ngo.optind + 2];
|
||||||
|
else
|
||||||
|
s_lstfname = mkfname(s_asmfname, "lst");
|
||||||
|
|
||||||
|
uz80as();
|
||||||
|
return 0;
|
||||||
|
}
|
338
2048/uz80as/mc6800.c
Normal file
338
2048/uz80as/mc6800.c
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Motorola 6800, 6801.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pp.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "uz80as.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* pat:
|
||||||
|
* a: expr
|
||||||
|
* b: NEGA,COMA,LSRA,RORA,ASRA,
|
||||||
|
* ROLA,DECA,INCA,TSTA,CLRA
|
||||||
|
* c: NEGB,COMB,LSRB,RORB,ASRB,
|
||||||
|
* ROLB,DECB,INCB,TSTB,CLRB
|
||||||
|
* d: NEG,COM,LSR,ROR,ASR,
|
||||||
|
* ROL,DEC,INC,TST,JMP,CLR
|
||||||
|
* e: SUBA,CMPA,SBCA,ANDA,BITA,LDAA,
|
||||||
|
* EORA,ADCA,ORAA,ADDA
|
||||||
|
* f: SUBB,CMPB,SBCB,ANDB,BITB,LDAB,
|
||||||
|
* EORB,ADCB,ORAB,ADDB
|
||||||
|
* g: INX,DEX,CLV,SEV,CLC,SEC,CLI,SEI
|
||||||
|
* h: BRA,BHI,BLS,BCC,BCS,BNE,BEQ,
|
||||||
|
* BVC,BVS,BPL,BMI,BGE,BLT,BGT,BLE
|
||||||
|
* i: TSX,INS,PULA,PULB,DES,TXS,PSHA,
|
||||||
|
* PSHB,RTS,RTI,WAI,SWI
|
||||||
|
*
|
||||||
|
* gen:
|
||||||
|
* .: output lastbyte
|
||||||
|
* b: (op << 3) | lastbyte
|
||||||
|
* c: op | lastbyte
|
||||||
|
* d: lastbyte = op as 8 bit value
|
||||||
|
* e: output op as word (no '.' should follow)
|
||||||
|
* f: ouput op as big endian word (no '.' should follow)
|
||||||
|
* g: if op<=$ff output lastbyte and output op as byte
|
||||||
|
* else output (lastbyte | 0x20) and output op as big endian word
|
||||||
|
* (no '.' should follow)
|
||||||
|
* h: relative - 2
|
||||||
|
* i: relative - 4
|
||||||
|
* i: relative - 5
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct matchtab s_matchtab_mc6800[] = {
|
||||||
|
{ "NOP", "01.", 1, 0 },
|
||||||
|
{ "TAP", "06.", 1, 0 },
|
||||||
|
{ "TPA", "07.", 1, 0 },
|
||||||
|
{ "g", "08c0.", 1, 0 },
|
||||||
|
{ "SBA", "10.", 1, 0 },
|
||||||
|
{ "CBA", "11.", 1, 0 },
|
||||||
|
{ "TAB", "16.", 1, 0 },
|
||||||
|
{ "TBA", "17.", 1, 0 },
|
||||||
|
{ "DAA", "19.", 1, 0 },
|
||||||
|
{ "ABA", "1B.", 1, 0 },
|
||||||
|
{ "i", "30c0.", 1, 0 },
|
||||||
|
{ "h a", "20c0.h1.", 1, 0, "r8" },
|
||||||
|
{ "b", "40c0.", 1, 0 },
|
||||||
|
{ "c", "50c0.", 1, 0 },
|
||||||
|
{ "d a,X", "60c0.d1.", 1, 0, "e8" },
|
||||||
|
{ "d a,Y", "18.60c0.d1.", 8, 0, "e8" },
|
||||||
|
{ "d a", "70c0.f1", 1, 0, "e16" },
|
||||||
|
{ "e #a", "80c0.d1.", 1, 0, "e8" },
|
||||||
|
{ "f #a", "C0c0.d1.", 1, 0, "e8" },
|
||||||
|
{ "e >a", "B0c0.f1", 1, 0, "e16" },
|
||||||
|
{ "f >a", "F0c0.f1", 1, 0, "e16" },
|
||||||
|
{ "e a,X", "A0c0.d1.", 1, 0, "e8" },
|
||||||
|
{ "f a,X", "E0c0.d1.", 1, 0, "e8" },
|
||||||
|
{ "e a,Y", "18.A0c0.d1.", 8, 0, "e8" },
|
||||||
|
{ "f a,Y", "18.E0c0.d1.", 8, 0, "e8" },
|
||||||
|
{ "e a", "90c0g1", 1, 0 },
|
||||||
|
{ "f a", "D0c0g1", 1, 0 },
|
||||||
|
{ "STAA >a", "B7.f0", 1, 0, "e16" },
|
||||||
|
{ "STAA a,X", "A7.d0.", 1, 0, "e8" },
|
||||||
|
{ "STAA a,Y", "18.A7.d0.", 8, 0, "e8" },
|
||||||
|
{ "STAA a", "97g0", 1, 0 },
|
||||||
|
{ "STAB >a", "F7.f0", 1, 0, "e16" },
|
||||||
|
{ "STAB a,X", "E7.d0.", 1, 0, "e8" },
|
||||||
|
{ "STAB a,Y", "18.E7.d0.", 8, 0, "e8" },
|
||||||
|
{ "STAB a", "D7g0", 1, 0 },
|
||||||
|
{ "CPX #a", "8C.f0", 1, 0, "e16" },
|
||||||
|
{ "CPX >a", "BC.f0", 1, 0, "e16" },
|
||||||
|
{ "CPX a,X", "AC.d0.", 1, 0, "e8" },
|
||||||
|
{ "CPX a,Y", "CD.AC.d0.", 8, 0, "e8" },
|
||||||
|
{ "CPX a", "9Cg0", 1, 0 },
|
||||||
|
{ "LDS #a", "8E.f0", 1, 0, "e16" },
|
||||||
|
{ "LDS >a", "BE.f0", 1, 0, "e16" },
|
||||||
|
{ "LDS a,X", "AE.d0.", 1, 0, "e8" },
|
||||||
|
{ "LDS a,Y", "18.AE.d0.", 8, 0, "e8" },
|
||||||
|
{ "LDS a", "9Eg0", 1, 0 },
|
||||||
|
{ "STS >a", "BF.f0", 1, 0, "e16" },
|
||||||
|
{ "STS a,X", "AF.d0.", 1, 0, "e8" },
|
||||||
|
{ "STS a,Y", "18.AF.d0.", 8, 0, "e8" },
|
||||||
|
{ "STS a", "9Fg0", 1, 0 },
|
||||||
|
{ "LDX #a", "CE.f0", 1, 0, "e16" },
|
||||||
|
{ "LDX >a", "FE.f0", 1, 0, "e16" },
|
||||||
|
{ "LDX a,X", "EE.d0.", 1, 0, "e8" },
|
||||||
|
{ "LDX a,Y", "CD.EE.d0.", 8, 0, "e8" },
|
||||||
|
{ "LDX a", "DEg0", 1, 0 },
|
||||||
|
{ "STX >a", "FF.f0", 1, 0, "e16" },
|
||||||
|
{ "STX a,X", "EF.d0.", 1, 0, "e8" },
|
||||||
|
{ "STX a,Y", "CD.EF.d0.", 8, 0, "e8" },
|
||||||
|
{ "STX a", "DFg0", 1, 0 },
|
||||||
|
{ "BSR a", "8D.h0.", 1, 0, "r8" },
|
||||||
|
{ "JSR >a", "BD.f0", 4, 0, "e16" },
|
||||||
|
{ "JSR a,X", "AD.d0.", 1, 0, "e8" },
|
||||||
|
{ "JSR a,Y", "18.AD.d0.", 8, 0, "e8" },
|
||||||
|
{ "JSR a", "BD.f0", 2, 0, "e16" },
|
||||||
|
{ "JSR a", "9Dg0", 4, 0 },
|
||||||
|
{ "ABX", "3A.", 4, 0 },
|
||||||
|
{ "ADDD #a", "C3.f0", 4, 0, "e16" },
|
||||||
|
{ "ADDD >a", "F3.f0", 4, 0, "e16" },
|
||||||
|
{ "ADDD a,X", "E3.d0.", 4, 0, "e8" },
|
||||||
|
{ "ADDD a,Y", "18.E3.d0.", 8, 0, "e8" },
|
||||||
|
{ "ADDD a", "D3g0", 4, 0 },
|
||||||
|
{ "ASLD", "05.", 4, 0 },
|
||||||
|
{ "LSLD", "05.", 4, 0 },
|
||||||
|
{ "BHS a", "24.h0.", 4, 0, "r8" },
|
||||||
|
{ "BLO a", "25.h0.", 4, 0, "r8" },
|
||||||
|
{ "BRN a", "21.h0.", 4, 0, "r8" },
|
||||||
|
{ "LDD #a", "CC.f0", 4, 0, "e16" },
|
||||||
|
{ "LDD >a", "FC.f0", 4, 0, "e16" },
|
||||||
|
{ "LDD a,X", "EC.d0.", 4, 0, "e8" },
|
||||||
|
{ "LDD a,Y", "18.EC.d0.", 8, 0, "e8" },
|
||||||
|
{ "LDD a", "DCg0", 4, 0 },
|
||||||
|
{ "LSL a,X", "68.d0.", 4, 0, "e8" },
|
||||||
|
{ "LSL a,Y", "18.68.d0.", 8, 0, "e8" },
|
||||||
|
{ "LSL a", "78.f0", 4, 0, "e16" },
|
||||||
|
{ "LSRD", "04.", 4, 0 },
|
||||||
|
{ "MUL", "3D.", 4, 0 },
|
||||||
|
{ "PSHX", "3C.", 4, 0 },
|
||||||
|
{ "PSHY", "18.3C.", 8, 0 },
|
||||||
|
{ "PULX", "38.", 4, 0 },
|
||||||
|
{ "PULY", "18.38.", 8, 0 },
|
||||||
|
{ "STD >a", "FD.f0", 4, 0, "e16" },
|
||||||
|
{ "STD a,X", "ED.d0.", 4, 0, "e8" },
|
||||||
|
{ "STD a,Y", "18.ED.d0.", 8, 0, "e8" },
|
||||||
|
{ "STD a", "DDg0", 4, 0 },
|
||||||
|
{ "SUBD #a", "83.f0", 4, 0, "e16" },
|
||||||
|
{ "SUBD >a", "B3.f0", 4, 0, "e16" },
|
||||||
|
{ "SUBD a,X", "A3.d0.", 4, 0, "e8" },
|
||||||
|
{ "SUBD a,Y", "18.A3.d0.", 8, 0, "e8" },
|
||||||
|
{ "SUBD a", "93g0", 4, 0 },
|
||||||
|
{ "TEST", "00.", 8, 0 },
|
||||||
|
{ "IDIV", "02.", 8, 0 },
|
||||||
|
{ "FDIV", "03.", 8, 0 },
|
||||||
|
{ "BRSET a,X,a,a", "1E.d0.d1.i2.", 8, 0, "e8e8r8" },
|
||||||
|
{ "BRSET a,Y,a,a", "18.1E.d0.d1.j2.", 8, 0, "e8e8r8" },
|
||||||
|
{ "BRSET a,a,a", "12.d0.d1.i2.", 8, 0, "e8e8r8" },
|
||||||
|
{ "BRCLR a,X,a,a", "1F.d0.d1.i2.", 8, 0, "e8e8r8" },
|
||||||
|
{ "BRCLR a,Y,a,a", "18.1F.d0.d1.j2.", 8, 0, "e8e8r8" },
|
||||||
|
{ "BRCLR a,a,a", "13.d0.d1.i2.", 8, 0, "e8e8r8" },
|
||||||
|
{ "BSET a,X,a", "1C.d0.d1.", 8, 0, "e8e8" },
|
||||||
|
{ "BSET a,Y,a", "18.1C.d0.d1.", 8, 0, "e8e8" },
|
||||||
|
{ "BSET a,a", "14.d0.d1.", 8, 0, "e8e8" },
|
||||||
|
{ "BCLR a,X,a", "1D.d0.d1.", 8, 0, "e8e8" },
|
||||||
|
{ "BCLR a,Y,a", "18.1D.d0.d1.", 8, 0, "e8e8" },
|
||||||
|
{ "BCLR a,a", "15.d0.d1.", 8, 0, "e8e8" },
|
||||||
|
{ "LSLA", "48.", 8, 0 },
|
||||||
|
{ "LSLB", "58.", 8, 0 },
|
||||||
|
{ "XGDX", "8F.", 8, 0 },
|
||||||
|
{ "STOP", "CF.", 8, 0 },
|
||||||
|
{ "ABY", "18.3A.", 8, 0 },
|
||||||
|
{ "CPY #a", "18.8C.f0", 8, 0, "e16" },
|
||||||
|
{ "CPY >a", "18.BC.f0", 8, 0, "e16" },
|
||||||
|
{ "CPY a,X", "1A.AC.d0.", 8, 0, "e8" },
|
||||||
|
{ "CPY a,Y", "18.AC.d0.", 8, 0, "e8" },
|
||||||
|
{ "CPY a", "18.9Cg0", 8, 0 },
|
||||||
|
{ "DEY", "18.09.", 8, 0 },
|
||||||
|
{ "INY", "18.08.", 8, 0 },
|
||||||
|
{ "LDY #a", "18.CE.f0", 8, 0, "e16" },
|
||||||
|
{ "LDY >a", "18.FE.f0", 8, 0, "e16" },
|
||||||
|
{ "LDY a,X", "1A.EE.d0.", 8, 0, "e8" },
|
||||||
|
{ "LDY a,Y", "18.EE.d0.", 8, 0, "e8" },
|
||||||
|
{ "LDY a", "18.DEg0", 8, 0 },
|
||||||
|
{ "STY >a", "18.FF.f0", 8, 0, "e16" },
|
||||||
|
{ "STY a,X", "1A.EF.d0.", 8, 0, "e8" },
|
||||||
|
{ "STY a,Y", "18.EF.d0.", 8, 0, "e8" },
|
||||||
|
{ "STY a", "18.DFg0", 8, 0 },
|
||||||
|
{ "TSY", "18.30.", 8, 0 },
|
||||||
|
{ "TYS", "18.35.", 8, 0 },
|
||||||
|
{ "XGDY", "18.8F.", 8, 0 },
|
||||||
|
{ "CPD #a", "1A.83.f0", 8, 0, "e16" },
|
||||||
|
{ "CPD >a", "1A.B3.f0", 8, 0, "e16" },
|
||||||
|
{ "CPD a,X", "1A.A3.d0.", 8, 0, "e8" },
|
||||||
|
{ "CPD a,Y", "CD.A3.d0.", 8, 0, "e8" },
|
||||||
|
{ "CPD a", "1A.93g0", 8, 0 },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const bval[] = {
|
||||||
|
"NEGA", "", "", "COMA", "LSRA", "", "RORA", "ASRA",
|
||||||
|
"ASLA", "ROLA", "DECA", "", "INCA", "TSTA", "", "CLRA",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const cval[] = {
|
||||||
|
"NEGB", "", "", "COMB", "LSRB", "", "RORB", "ASRB",
|
||||||
|
"ASLB", "ROLB", "DECB", "", "INCB", "TSTB", "", "CLRB",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const dval[] = {
|
||||||
|
"NEG", "", "", "COM", "LSR", "", "ROR", "ASR",
|
||||||
|
"ASL", "ROL", "DEC", "", "INC", "TST", "JMP", "CLR",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const eval[] = {
|
||||||
|
"SUBA", "CMPA", "SBCA", "", "ANDA", "BITA", "LDAA", "",
|
||||||
|
"EORA", "ADCA", "ORAA", "ADDA",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const fval[] = {
|
||||||
|
"SUBB", "CMPB", "SBCB", "", "ANDB", "BITB", "LDAB", "",
|
||||||
|
"EORB", "ADCB", "ORAB", "ADDB",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const gval[] = {
|
||||||
|
"INX", "DEX", "CLV", "SEV", "CLC", "SEC", "CLI", "SEI",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const hval[] = {
|
||||||
|
"BRA", "", "BHI", "BLS", "BCC", "BCS", "BNE", "BEQ",
|
||||||
|
"BVC", "BVS", "BPL", "BMI", "BGE", "BLT", "BGT", "BLE",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const ival[] = {
|
||||||
|
"TSX", "INS", "PULA", "PULB", "DES", "TXS", "PSHA",
|
||||||
|
"PSHB", "", "RTS", "", "RTI", "", "", "WAI", "SWI",
|
||||||
|
NULL };
|
||||||
|
|
||||||
|
static const char *const *const valtab[] = {
|
||||||
|
bval, cval, dval, eval, fval,
|
||||||
|
gval, hval, ival
|
||||||
|
};
|
||||||
|
|
||||||
|
static int match_mc6800(char c, const char *p, const char **q)
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
|
||||||
|
if (c <= 'i') {
|
||||||
|
v = mreg(p, valtab[(int) (c - 'b')], q);
|
||||||
|
} else {
|
||||||
|
v = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gen_mc6800(int *eb, char p, const int *vs, int i, int savepc)
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
|
||||||
|
b = *eb;
|
||||||
|
switch (p) {
|
||||||
|
case 'f': genb(vs[i] >> 8, s_pline_ep);
|
||||||
|
genb(vs[i], s_pline_ep);
|
||||||
|
break;
|
||||||
|
case 'g': if (vs[i] <= 255) {
|
||||||
|
genb(b, s_pline_ep);
|
||||||
|
genb(vs[i], s_pline_ep);
|
||||||
|
} else {
|
||||||
|
genb(b | 0x20, s_pline_ep);
|
||||||
|
genb(vs[i] >> 8, s_pline_ep);
|
||||||
|
genb(vs[i], s_pline_ep);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'h': b = (vs[i] - savepc - 2);
|
||||||
|
break;
|
||||||
|
case 'i': b = (vs[i] - savepc - 4);
|
||||||
|
break;
|
||||||
|
case 'j': b = (vs[i] - savepc - 5);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*eb = b;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s_pat_char = 'b';
|
||||||
|
static int s_pat_index;
|
||||||
|
|
||||||
|
static void pat_char_rewind_mc6800(int c)
|
||||||
|
{
|
||||||
|
s_pat_char = c;
|
||||||
|
s_pat_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *pat_next_str_mc6800(void)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (s_pat_char >= 'b' && s_pat_char <= 'i') {
|
||||||
|
s = valtab[(int) (s_pat_char - 'b')][s_pat_index];
|
||||||
|
if (s != NULL) {
|
||||||
|
s_pat_index++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_mc6800 = {
|
||||||
|
.id = "mc6800",
|
||||||
|
.descr = "Motorola 6800",
|
||||||
|
.matcht = s_matchtab_mc6800,
|
||||||
|
.matchf = match_mc6800,
|
||||||
|
.genf = gen_mc6800,
|
||||||
|
.pat_char_rewind = pat_char_rewind_mc6800,
|
||||||
|
.pat_next_str = pat_next_str_mc6800,
|
||||||
|
.mask = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_mc6801 = {
|
||||||
|
.id = "mc6801",
|
||||||
|
.descr = "Motorola 6801",
|
||||||
|
.matcht = s_matchtab_mc6800,
|
||||||
|
.matchf = match_mc6800,
|
||||||
|
.genf = gen_mc6800,
|
||||||
|
.pat_char_rewind = pat_char_rewind_mc6800,
|
||||||
|
.pat_next_str = pat_next_str_mc6800,
|
||||||
|
.mask = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_m68hc11 = {
|
||||||
|
.id = "m68hc11",
|
||||||
|
.descr = "Motorola 68HC11",
|
||||||
|
.matcht = s_matchtab_mc6800,
|
||||||
|
.matchf = match_mc6800,
|
||||||
|
.genf = gen_mc6800,
|
||||||
|
.pat_char_rewind = pat_char_rewind_mc6800,
|
||||||
|
.pat_next_str = pat_next_str_mc6800,
|
||||||
|
.mask = 13
|
||||||
|
};
|
385
2048/uz80as/mos6502.c
Normal file
385
2048/uz80as/mos6502.c
Normal file
@ -0,0 +1,385 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* MOS Technology 6502.
|
||||||
|
* Rockwell R6501.
|
||||||
|
* California Micro Devices G65SC02.
|
||||||
|
* Rockwell R65C02.
|
||||||
|
* Rockwell R65C29.
|
||||||
|
* Western Design Center W65C02S.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* mos6502, the original
|
||||||
|
*
|
||||||
|
* g65sc02 California Micro Devices, adds to mos6502:
|
||||||
|
* - zp ADC,AND,CMP,EOR,LDA,ORA,SBC,STA
|
||||||
|
* - DEC A, INC A
|
||||||
|
* - JMP (abs,X)
|
||||||
|
* - BRA
|
||||||
|
* - PHX,PHY,PLX,PLY
|
||||||
|
* - STZ
|
||||||
|
* - TRB
|
||||||
|
* - TSB
|
||||||
|
* - More addressing modes for BIT, etc
|
||||||
|
*
|
||||||
|
* r6501 Rockwell, adds to mos6502:
|
||||||
|
* - BBR, BBS
|
||||||
|
* - RMB, SMB
|
||||||
|
*
|
||||||
|
* r65c02 Rockwell, adds the instructions of the g65sc02 and r6501
|
||||||
|
*
|
||||||
|
* r65c29 Rockwell, adds to r65c02:
|
||||||
|
* - MUL
|
||||||
|
*
|
||||||
|
* w65c02s Western Design Center, adds to r65c02:
|
||||||
|
* - STP,WAI
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pp.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "uz80as.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* pat:
|
||||||
|
* a: expr
|
||||||
|
* b: ORA,AND,EOR,ADC,STA,LDA,CMP,SBC
|
||||||
|
* c: ORA,AND,EOR,ADC,LDA,CMP,SBC
|
||||||
|
* d: PHP,CLC,PLP,SEC,PHA,CLI,PLA,SEI,
|
||||||
|
* DEY,TYA,TAY,CLV,INY,CLD,INX,SED
|
||||||
|
* e: ASL,ROL,LSR,ROR
|
||||||
|
* f: DEC, INC
|
||||||
|
* g: BPL,BMI,BVC,BVS,BCC,BCS,BNE,BEQ
|
||||||
|
* h: TXA,TXS,TAX,TSX,DEX,NOP
|
||||||
|
* i: CPY,CPX
|
||||||
|
* j: TSB,TRB
|
||||||
|
* k: BBR0,BBR1,BBR2,BBR3,BBR4,BBR5,BBR6,BBR6,
|
||||||
|
* BBS0,BBS1,BBS2,BBS3,BBS4,BBS5,BBS6,BBS7
|
||||||
|
* l: RMB0,RMB1,RMB2,RMB3,RMB4,RMB5,EMB6,RMB7,
|
||||||
|
* SMB0,SMB1,SMB2,SMB3,SMB4,SMB5,SMB6,SMB7
|
||||||
|
* m: PHY,PLY
|
||||||
|
* n: PHX,PLX
|
||||||
|
* o: INC, DEC
|
||||||
|
*
|
||||||
|
* gen:
|
||||||
|
* .: output lastbyte
|
||||||
|
* b: (op << 3) | lastbyte
|
||||||
|
* c: op | lastbyte
|
||||||
|
* d: lastbyte = op as 8 bit value
|
||||||
|
* e: output op as word (no '.' should follow)
|
||||||
|
* f: (op << 5) | lastbyte
|
||||||
|
* g: if op <= $FF output last byte and then op as 8 bit value;
|
||||||
|
* else output (lastbyte | 0x08) and output op as word
|
||||||
|
* (no '.' should follow)
|
||||||
|
* h: (op << 4) | lastbyte
|
||||||
|
* i: relative jump to op (-2)
|
||||||
|
* j: if op <= $FF output $64 and op as 8 bit
|
||||||
|
* else output $9C and op as word
|
||||||
|
* (no '.' should follow)
|
||||||
|
* k: if op <= $FF ouput $74 and op as 8 bit
|
||||||
|
* else output $9E and op as word
|
||||||
|
* (no '.' should follow)
|
||||||
|
* l: relative jump to op (-3)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct matchtab s_matchtab_mos6502[] = {
|
||||||
|
{ "BRK", "00.", 1, 0 },
|
||||||
|
{ "JSR a", "20.e0", 1, 0 },
|
||||||
|
{ "RTI", "40.", 1, 0 },
|
||||||
|
{ "RTS", "60.", 1, 0 },
|
||||||
|
{ "h", "8Ah0.", 1, 0 },
|
||||||
|
{ "d", "08h0.", 1, 0 },
|
||||||
|
{ "c #a", "09f0.d1.", 1, 0, "e8" },
|
||||||
|
{ "b (a,X)", "01f0.d1.", 1, 0, "e8" },
|
||||||
|
{ "b (a),Y", "11f0.d1.", 1, 0, "e8" },
|
||||||
|
{ "b (a)", "12f0.d1.", 2, 0, "e8" },
|
||||||
|
{ "b a", "05f0g1", 1, 0 },
|
||||||
|
{ "b a,X", "15f0g1", 1, 0 },
|
||||||
|
{ "b a,Y", "19f0.e1", 1, 0 },
|
||||||
|
{ "e A", "0Af0.", 1, 0 },
|
||||||
|
{ "e a", "06f0g1", 1, 0 },
|
||||||
|
{ "e a,X", "16f0g1", 1, 0 },
|
||||||
|
{ "STX a", "86g0", 1, 0 },
|
||||||
|
{ "STX a,Y", "96.d0.", 1, 0, "e8" },
|
||||||
|
{ "LDX #a", "A2.d0.", 1, 0, "e8" },
|
||||||
|
{ "LDX a", "A6g0", 1, 0 },
|
||||||
|
{ "LDX a,Y", "B6g0", 1, 0 },
|
||||||
|
{ "o A", "1Af0.", 2, 0 },
|
||||||
|
{ "f a", "C6f0g1", 1, 0 },
|
||||||
|
{ "f a,X", "D6f0g1", 1, 0 },
|
||||||
|
{ "g a", "10f0.i1.", 1, 0, "r8" },
|
||||||
|
{ "BIT #a", "89.d0.", 2, 0, "e8" },
|
||||||
|
{ "BIT a", "24g0", 1, 0 },
|
||||||
|
{ "BIT a,X", "34g0", 2, 0 },
|
||||||
|
{ "JMP (a)", "6C.e0", 1, 0 },
|
||||||
|
{ "JMP (a,X)", "7C.e0", 2, 0 },
|
||||||
|
{ "JMP a", "4C.e0", 1, 0 },
|
||||||
|
{ "STY a", "84g0", 1, 0 },
|
||||||
|
{ "STY a,X", "94.d0.", 1, 0, "e8" },
|
||||||
|
{ "LDY #a", "A0.d0.", 1, 0, "e8" },
|
||||||
|
{ "LDY a", "A4g0", 1, 0 },
|
||||||
|
{ "LDY a,X", "B4g0", 1, 0 },
|
||||||
|
{ "i #a", "C0f0.d1.", 1, 0, "e8" },
|
||||||
|
{ "i a", "C4f0g1", 1, 0 },
|
||||||
|
{ "j a", "04h0g1", 2, 0 },
|
||||||
|
{ "k a,a", "0Fh0.d1.l2.", 4, 0, "e8r8" },
|
||||||
|
{ "l a", "07h0.d1.", 4, 0, "e8" },
|
||||||
|
{ "m", "5Af0.", 2, 0 },
|
||||||
|
{ "n", "DAf0.", 2, 0 },
|
||||||
|
{ "BRA a", "80.i0.", 2, 0, "r8" },
|
||||||
|
{ "STZ a,X", "k1", 2, 0 },
|
||||||
|
{ "STZ a", "j1", 2, 0 },
|
||||||
|
{ "MUL", "02.", 8, 0 },
|
||||||
|
{ "WAI", "CB.", 16, 0 },
|
||||||
|
{ "STP", "DB.", 16, 0 },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const bval[] = {
|
||||||
|
"ORA", "AND", "EOR", "ADC",
|
||||||
|
"STA", "LDA", "CMP", "SBC",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const cval[] = {
|
||||||
|
"ORA", "AND", "EOR", "ADC",
|
||||||
|
"", "LDA", "CMP", "SBC", NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const dval[] = {
|
||||||
|
"PHP", "CLC", "PLP", "SEC",
|
||||||
|
"PHA", "CLI", "PLA", "SEI",
|
||||||
|
"DEY", "TYA", "TAY", "CLV",
|
||||||
|
"INY", "CLD", "INX", "SED",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const char *const eval[] = {
|
||||||
|
"ASL", "ROL", "LSR", "ROR",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const fval[] = {
|
||||||
|
"DEC", "INC",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const gval[] = {
|
||||||
|
"BPL", "BMI", "BVC", "BVS",
|
||||||
|
"BCC", "BCS", "BNE", "BEQ",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const hval[] = {
|
||||||
|
"TXA", "TXS", "TAX", "TSX",
|
||||||
|
"DEX", "", "NOP",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const ival[] = {
|
||||||
|
"CPY", "CPX",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const jval[] = {
|
||||||
|
"TSB", "TRB",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const kval[] = {
|
||||||
|
"BBR0", "BBR1", "BBR2", "BBR3",
|
||||||
|
"BBR4", "BBR5", "BBR6", "BBR7",
|
||||||
|
"BBS0", "BBS1", "BBS2", "BBS3",
|
||||||
|
"BBS4", "BBS5", "BBS6", "BBS7",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const lval[] = {
|
||||||
|
"RMB0", "RMB1", "RMB2", "RMB3",
|
||||||
|
"RMB4", "RMB5", "RMB6", "RMB7",
|
||||||
|
"SMB0", "SMB1", "SMB2", "SMB3",
|
||||||
|
"SMB4", "SMB5", "SMB6", "SMB7",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const mval[] = {
|
||||||
|
"PHY", "PLY",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const nval[] = {
|
||||||
|
"PHX", "PLX",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const oval[] = {
|
||||||
|
"INC", "DEC",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const *const valtab[] = {
|
||||||
|
bval, cval, dval, eval, fval,
|
||||||
|
gval, hval, ival, jval, kval,
|
||||||
|
lval, mval, nval, oval
|
||||||
|
};
|
||||||
|
|
||||||
|
static int match_mos6502(char c, const char *p, const char **q)
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
|
||||||
|
if (c <= 'o') {
|
||||||
|
v = mreg(p, valtab[(int) (c - 'b')], q);
|
||||||
|
} else {
|
||||||
|
v = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gen_mos6502(int *eb, char p, const int *vs, int i, int savepc)
|
||||||
|
{
|
||||||
|
int b, w;
|
||||||
|
|
||||||
|
b = *eb;
|
||||||
|
switch (p) {
|
||||||
|
case 'f': b |= (vs[i] << 5); break;
|
||||||
|
case 'g': w = vs[i] & 0xffff;
|
||||||
|
if (w <= 0xff) {
|
||||||
|
genb(b, s_pline_ep);
|
||||||
|
b = 0;
|
||||||
|
genb(w, s_pline_ep);
|
||||||
|
} else {
|
||||||
|
b |= 0x08;
|
||||||
|
genb(b, s_pline_ep);
|
||||||
|
b = 0;
|
||||||
|
genb(w, s_pline_ep);
|
||||||
|
genb(w >> 8, s_pline_ep);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'h': b |= (vs[i] << 4); break;
|
||||||
|
case 'i': b = (vs[i] - savepc - 2); break;
|
||||||
|
case 'j': w = vs[i] & 0xffff;
|
||||||
|
if (w <= 0xff) {
|
||||||
|
genb(0x64, s_pline_ep);
|
||||||
|
b = 0;
|
||||||
|
genb(w, s_pline_ep);
|
||||||
|
} else {
|
||||||
|
genb(0x9C, s_pline_ep);
|
||||||
|
b = 0;
|
||||||
|
genb(w, s_pline_ep);
|
||||||
|
genb(w >> 8, s_pline_ep);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'k': w = vs[i] & 0xffff;
|
||||||
|
if (w <= 0xff) {
|
||||||
|
genb(0x74, s_pline_ep);
|
||||||
|
b = 0;
|
||||||
|
genb(w, s_pline_ep);
|
||||||
|
} else {
|
||||||
|
genb(0x9E, s_pline_ep);
|
||||||
|
b = 0;
|
||||||
|
genb(w, s_pline_ep);
|
||||||
|
genb(w >> 8, s_pline_ep);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'l': b = (vs[i] - savepc - 3); break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*eb = b;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s_pat_char = 'b';
|
||||||
|
static int s_pat_index;
|
||||||
|
|
||||||
|
static void pat_char_rewind_mos6502(int c)
|
||||||
|
{
|
||||||
|
s_pat_char = c;
|
||||||
|
s_pat_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *pat_next_str_mos6502(void)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (s_pat_char >= 'b' && s_pat_char <= 'o') {
|
||||||
|
s = valtab[(int) (s_pat_char - 'b')][s_pat_index];
|
||||||
|
if (s != NULL) {
|
||||||
|
s_pat_index++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_mos6502 = {
|
||||||
|
.id = "mos6502",
|
||||||
|
.descr = "MOS Technology 6502",
|
||||||
|
.matcht = s_matchtab_mos6502,
|
||||||
|
.matchf = match_mos6502,
|
||||||
|
.genf = gen_mos6502,
|
||||||
|
.pat_char_rewind = pat_char_rewind_mos6502,
|
||||||
|
.pat_next_str = pat_next_str_mos6502,
|
||||||
|
.mask = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_r6501 = {
|
||||||
|
.id = "r6501",
|
||||||
|
.descr = "Rockwell R6501",
|
||||||
|
.matcht = s_matchtab_mos6502,
|
||||||
|
.matchf = match_mos6502,
|
||||||
|
.genf = gen_mos6502,
|
||||||
|
.pat_char_rewind = pat_char_rewind_mos6502,
|
||||||
|
.pat_next_str = pat_next_str_mos6502,
|
||||||
|
.mask = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_g65sc02 = {
|
||||||
|
.id = "g65sc02",
|
||||||
|
.descr = "California Micro Devices G65SC02",
|
||||||
|
.matcht = s_matchtab_mos6502,
|
||||||
|
.matchf = match_mos6502,
|
||||||
|
.genf = gen_mos6502,
|
||||||
|
.pat_char_rewind = pat_char_rewind_mos6502,
|
||||||
|
.pat_next_str = pat_next_str_mos6502,
|
||||||
|
.mask = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_r65c02 = {
|
||||||
|
.id = "r65c02",
|
||||||
|
.descr = "Rockwell R65C02",
|
||||||
|
.matcht = s_matchtab_mos6502,
|
||||||
|
.matchf = match_mos6502,
|
||||||
|
.genf = gen_mos6502,
|
||||||
|
.pat_char_rewind = pat_char_rewind_mos6502,
|
||||||
|
.pat_next_str = pat_next_str_mos6502,
|
||||||
|
.mask = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_r65c29 = {
|
||||||
|
.id = "r65c29",
|
||||||
|
.descr = "Rockwell R65C29, R65C00/21",
|
||||||
|
.matcht = s_matchtab_mos6502,
|
||||||
|
.matchf = match_mos6502,
|
||||||
|
.genf = gen_mos6502,
|
||||||
|
.pat_char_rewind = pat_char_rewind_mos6502,
|
||||||
|
.pat_next_str = pat_next_str_mos6502,
|
||||||
|
.mask = 15
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_w65c02s = {
|
||||||
|
.id = "w65c02s",
|
||||||
|
.descr = "Western Design Center W65C02S",
|
||||||
|
.matcht = s_matchtab_mos6502,
|
||||||
|
.matchf = match_mos6502,
|
||||||
|
.genf = gen_mos6502,
|
||||||
|
.pat_char_rewind = pat_char_rewind_mos6502,
|
||||||
|
.pat_next_str = pat_next_str_mos6502,
|
||||||
|
.mask = 027
|
||||||
|
};
|
237
2048/uz80as/ngetopt.c
Normal file
237
2048/uz80as/ngetopt.c
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Handling of command line options, similar to getopt.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Changes:
|
||||||
|
*
|
||||||
|
* - Jul 22 2018: long options without short option character recognized.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ngetopt.h"
|
||||||
|
|
||||||
|
#ifndef STRING_H
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int find_short_opt(int val, struct ngetopt_opt *ops)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (ops[i].name != NULL) {
|
||||||
|
if (ops[i].val > 0 && ops[i].val == val)
|
||||||
|
return i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_long_opt(char *str, struct ngetopt_opt *ops)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const char *p, *q;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (ops[i].name != NULL) {
|
||||||
|
p = ops[i].name;
|
||||||
|
q = str;
|
||||||
|
while (*p != '\0' && *p == *q) {
|
||||||
|
p++;
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
if (*p == '\0' && (*q == '\0' || *q == '=')) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ngetopt_init(struct ngetopt *p, int argc, char *const *argv,
|
||||||
|
struct ngetopt_opt *ops)
|
||||||
|
{
|
||||||
|
p->argc = argc;
|
||||||
|
p->argv = argv;
|
||||||
|
p->ops = ops;
|
||||||
|
p->optind = 1;
|
||||||
|
p->subind = 0;
|
||||||
|
strcpy(p->str, "-X");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_short_opt(struct ngetopt *p)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *opt;
|
||||||
|
|
||||||
|
opt = p->argv[p->optind];
|
||||||
|
i = find_short_opt(opt[p->subind], p->ops);
|
||||||
|
if (i < 0) {
|
||||||
|
/* unrecognized option */
|
||||||
|
p->str[1] = (char) opt[p->subind];
|
||||||
|
p->optarg = p->str;
|
||||||
|
p->subind++;
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p->ops[i].has_arg) {
|
||||||
|
/* it's ok */
|
||||||
|
p->subind++;
|
||||||
|
return p->ops[i].val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* needs an argument */
|
||||||
|
if (opt[p->subind + 1] != '\0') {
|
||||||
|
/* the argument is the suffix */
|
||||||
|
p->optarg = &opt[p->subind + 1];
|
||||||
|
p->subind = 0;
|
||||||
|
p->optind++;
|
||||||
|
return p->ops[i].val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the argument is the next token */
|
||||||
|
p->optind++;
|
||||||
|
p->subind = 0;
|
||||||
|
if (p->optind < p->argc) {
|
||||||
|
p->optarg = p->argv[p->optind];
|
||||||
|
p->optind++;
|
||||||
|
return p->ops[i].val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ups, argument missing */
|
||||||
|
p->str[1] = (char) p->ops[i].val;
|
||||||
|
p->optarg = p->str;
|
||||||
|
return ':';
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_opt(struct ngetopt *p)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *opt, *optnext;
|
||||||
|
|
||||||
|
/* all arguments consumed */
|
||||||
|
if (p->optind >= p->argc)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
opt = p->argv[p->optind];
|
||||||
|
if (opt[0] != '-') {
|
||||||
|
/* non option */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* - */
|
||||||
|
if (opt[1] == '\0') {
|
||||||
|
/* stdin */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt[1] != '-') {
|
||||||
|
/* -xxxxx */
|
||||||
|
p->subind = 1;
|
||||||
|
return get_short_opt(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- */
|
||||||
|
if (opt[2] == '\0') {
|
||||||
|
/* found "--" */
|
||||||
|
p->optind++;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* long option */
|
||||||
|
i = find_long_opt(&opt[2], p->ops);
|
||||||
|
if (i < 0) {
|
||||||
|
/* not found */
|
||||||
|
p->optind++;
|
||||||
|
p->optarg = opt;
|
||||||
|
while (*opt != '\0' && *opt != '=') {
|
||||||
|
opt++;
|
||||||
|
}
|
||||||
|
*opt = '\0';
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* found, go to end of option */
|
||||||
|
optnext = opt + 2 + strlen(p->ops[i].name);
|
||||||
|
|
||||||
|
if (*optnext == '\0' && !p->ops[i].has_arg) {
|
||||||
|
/* doesn't need arguments */
|
||||||
|
p->optind++;
|
||||||
|
p->optstr = opt + 2;
|
||||||
|
return p->ops[i].val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*optnext == '=' && !p->ops[i].has_arg) {
|
||||||
|
/* does not need arguments but argument supplied */
|
||||||
|
*optnext = '\0';
|
||||||
|
p->optarg = opt;
|
||||||
|
return ';';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the argument is the next token */
|
||||||
|
if (*optnext == '\0') {
|
||||||
|
p->optind++;
|
||||||
|
if (p->optind < p->argc) {
|
||||||
|
p->optstr = opt + 2;
|
||||||
|
p->optarg = p->argv[p->optind];
|
||||||
|
p->optind++;
|
||||||
|
return p->ops[i].val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ups, argument missing */
|
||||||
|
p->optarg = opt;
|
||||||
|
p->optind++;
|
||||||
|
return ':';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *optnext == '=' */
|
||||||
|
*optnext = '\0';
|
||||||
|
p->optstr = opt + 2;
|
||||||
|
p->optarg = optnext + 1;
|
||||||
|
p->optind++;
|
||||||
|
return p->ops[i].val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If ok:
|
||||||
|
*
|
||||||
|
* - For a long option with a zero value single character option, 0 is
|
||||||
|
* returned, optstr is the string of the long option (without '-' or '--')
|
||||||
|
* and optarg is the option argument or NULL.
|
||||||
|
*
|
||||||
|
* - For anything else the single option character is returned and optarg
|
||||||
|
* is the option argument or NULL.
|
||||||
|
*
|
||||||
|
* If the option is not recognized, '?' is returned, and optarg is the
|
||||||
|
* literal string of the option not recognized (already with '-' or '--'
|
||||||
|
* prefixed).
|
||||||
|
*
|
||||||
|
* If the option is recognized but the argument is missing, ':' is
|
||||||
|
* returned and optarg is the option as supplied (with '-' or '--' prefixed).
|
||||||
|
*
|
||||||
|
* If the option is recognized and it is a long option followed by '=', but the
|
||||||
|
* option does not take arguments, ';' is returned and optarg is the option
|
||||||
|
* (with '-' or '--' prefixed).
|
||||||
|
*
|
||||||
|
* -1 is returned if no more options.
|
||||||
|
*/
|
||||||
|
int ngetopt_next(struct ngetopt *p)
|
||||||
|
{
|
||||||
|
if (p->subind == 0)
|
||||||
|
return get_opt(p);
|
||||||
|
|
||||||
|
/* p->subind > 0 */
|
||||||
|
if (p->argv[p->optind][p->subind] != '\0')
|
||||||
|
return get_short_opt(p);
|
||||||
|
|
||||||
|
/* no more options in this list of short options */
|
||||||
|
p->subind = 0;
|
||||||
|
p->optind++;
|
||||||
|
return get_opt(p);
|
||||||
|
}
|
40
2048/uz80as/ngetopt.h
Normal file
40
2048/uz80as/ngetopt.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Handling of command line options, similar to getopt.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NGETOPT_H
|
||||||
|
#define NGETOPT_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Changelog:
|
||||||
|
*
|
||||||
|
* - Jul 21 2018: long options without short option character recognized.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ngetopt_opt {
|
||||||
|
const char *name;
|
||||||
|
int has_arg;
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ngetopt {
|
||||||
|
char *optstr;
|
||||||
|
char *optarg;
|
||||||
|
/* private */
|
||||||
|
int optind;
|
||||||
|
int argc;
|
||||||
|
char *const *argv;
|
||||||
|
struct ngetopt_opt *ops;
|
||||||
|
int subind;
|
||||||
|
char str[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
void ngetopt_init(struct ngetopt *p, int argc, char *const *argv,
|
||||||
|
struct ngetopt_opt *ops);
|
||||||
|
int ngetopt_next(struct ngetopt *p);
|
||||||
|
|
||||||
|
#endif
|
33
2048/uz80as/options.c
Normal file
33
2048/uz80as/options.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Global options, normally coming from the command line.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "err.h"
|
||||||
|
|
||||||
|
const char *s_asmfname; /* Name of source file. */
|
||||||
|
const char *s_objfname; /* Name of generated binary file. */
|
||||||
|
const char *s_lstfname; /* Name of listing file. */
|
||||||
|
const char *s_target_id = "z80"; /* ID of target */
|
||||||
|
int s_listing = 1; /* If we generate the listing file or not. */
|
||||||
|
int s_extended_op = 0; /* Allow extended instruction syntax. */
|
||||||
|
int s_undocumented_op = 0; /* Allow undocumented instructions. */
|
||||||
|
int s_mem_fillval = 0; /* Default value to fill the 64K memory. */
|
||||||
|
|
||||||
|
/* Command line macro definitions. */
|
||||||
|
struct predef *s_predefs;
|
||||||
|
|
||||||
|
/* Predefine a macro in the command line that must persist between passes. */
|
||||||
|
void predefine(const char *text)
|
||||||
|
{
|
||||||
|
struct predef *pdef;
|
||||||
|
|
||||||
|
pdef = emalloc(sizeof(*pdef));
|
||||||
|
pdef->name = text;
|
||||||
|
pdef->next = s_predefs;
|
||||||
|
s_predefs = pdef;
|
||||||
|
}
|
29
2048/uz80as/options.h
Normal file
29
2048/uz80as/options.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Global options, normally coming from the command line.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef OPTIONS_H
|
||||||
|
#define OPTIONS_H
|
||||||
|
|
||||||
|
/* Predefined macro at the command line. */
|
||||||
|
struct predef {
|
||||||
|
struct predef *next;
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char *s_asmfname;
|
||||||
|
extern const char *s_objfname;
|
||||||
|
extern const char *s_lstfname;
|
||||||
|
extern const char *s_target_id;
|
||||||
|
extern int s_listing;
|
||||||
|
extern int s_extended_op;
|
||||||
|
extern int s_undocumented_op;
|
||||||
|
extern int s_mem_fillval;
|
||||||
|
extern struct predef *s_predefs;
|
||||||
|
|
||||||
|
void predefine(const char *name);
|
||||||
|
|
||||||
|
#endif
|
745
2048/uz80as/pp.c
Normal file
745
2048/uz80as/pp.c
Normal file
@ -0,0 +1,745 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Preprocessor.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "pp.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "incl.h"
|
||||||
|
#include "expr.h"
|
||||||
|
#include "exprint.h"
|
||||||
|
|
||||||
|
#ifndef CTYPE_H
|
||||||
|
#include <ctype.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STDIO_H
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STDLIB_H
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STRING_H
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Max number of macros. */
|
||||||
|
#define NMACROS 1000
|
||||||
|
|
||||||
|
/* Closest prime to NMACROS / 4. */
|
||||||
|
#define MACTABSZ 241
|
||||||
|
|
||||||
|
/* Max number of macro arguments. */
|
||||||
|
#define NPARAMS 20
|
||||||
|
|
||||||
|
#define DEFINESTR "DEFINE"
|
||||||
|
#define DEFCONTSTR "DEFCONT"
|
||||||
|
#define INCLUDESTR "INCLUDE"
|
||||||
|
#define IFSTR "IF"
|
||||||
|
#define IFDEFSTR "IFDEF"
|
||||||
|
#define IFNDEFSTR "IFNDEF"
|
||||||
|
#define ENDIFSTR "ENDIF"
|
||||||
|
#define ELSESTR "ELSE"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macro.
|
||||||
|
*
|
||||||
|
* For example, the macro:
|
||||||
|
*
|
||||||
|
* #define SUM(a,b) (a+b)
|
||||||
|
*
|
||||||
|
* is:
|
||||||
|
*
|
||||||
|
* name = SUM
|
||||||
|
* pars = a\0b\0
|
||||||
|
* ppars[0] points to &pars[0], that is to "a"
|
||||||
|
* ppars[1] points to &pars[2], that is to "b"
|
||||||
|
* npars = 2
|
||||||
|
* text is "(a+b)"
|
||||||
|
*/
|
||||||
|
struct macro {
|
||||||
|
struct macro *next; /* Next in hash chain. */
|
||||||
|
char *name; /* Identifier. */
|
||||||
|
char *pars; /* String with params separated by '\0'. */
|
||||||
|
char *text; /* Text to expand. */
|
||||||
|
char *ppars[NPARAMS]; /* Pointers to the beginning of each param. */
|
||||||
|
int npars; /* Valid number of params in ppars. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Hash table of preprocessor symbols. */
|
||||||
|
static struct macro *s_mactab[MACTABSZ];
|
||||||
|
|
||||||
|
/* Preprocessing line buffers. */
|
||||||
|
static char s_ppbuf[2][LINESZ];
|
||||||
|
|
||||||
|
/* If we are discarding lines; if not 0, level of if. */
|
||||||
|
int s_skipon;
|
||||||
|
|
||||||
|
/* Number of nested #if or #ifdef or #ifndef. */
|
||||||
|
static int s_nifs;
|
||||||
|
|
||||||
|
/* Last defined macro. */
|
||||||
|
static struct macro *s_lastmac;
|
||||||
|
|
||||||
|
/* Number of macros in table. */
|
||||||
|
static int s_nmacs;
|
||||||
|
|
||||||
|
/* The preprocessed line, points to one of s_ppbuf. */
|
||||||
|
char *s_pline;
|
||||||
|
|
||||||
|
/* Current program counter. */
|
||||||
|
int s_pc;
|
||||||
|
|
||||||
|
/* Current pass. */
|
||||||
|
int s_pass;
|
||||||
|
|
||||||
|
|
||||||
|
/* Only valid while in the call to pp_line(). */
|
||||||
|
static const char *s_line; /* original line */
|
||||||
|
static const char *s_line_ep; /* pointer inside s_line for error reporting */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy [p, q[ to [dp, dq[.
|
||||||
|
*/
|
||||||
|
static char *copypp(char *dp, char *dq, const char *p, const char *q)
|
||||||
|
{
|
||||||
|
while (dp < dq && p < q)
|
||||||
|
*dp++ = *p++;
|
||||||
|
return dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the 'argnum' argument in 'args' and return a pointer to it.
|
||||||
|
*
|
||||||
|
* 'args' is a list of arguments "([id [,id]*).
|
||||||
|
* 'argnum' is the argument number to find.
|
||||||
|
*
|
||||||
|
* Return not found.
|
||||||
|
*/
|
||||||
|
static const char *findarg(const char *args, int argnum)
|
||||||
|
{
|
||||||
|
if (*args == '(') {
|
||||||
|
do {
|
||||||
|
args++;
|
||||||
|
if (argnum == 0)
|
||||||
|
return args;
|
||||||
|
argnum--;
|
||||||
|
while (*args != '\0' && *args != ','
|
||||||
|
&& *args != ')')
|
||||||
|
{
|
||||||
|
args++;
|
||||||
|
}
|
||||||
|
} while (*args == ',');
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the 'argnum' argument in 'args' and copy it to [dp, dq[.
|
||||||
|
*
|
||||||
|
* 'args' points to a list of arguments "([id [,id]*).
|
||||||
|
* 'argnum' is the argument number to copy.
|
||||||
|
*
|
||||||
|
* Return the new 'dp' after copying.
|
||||||
|
*/
|
||||||
|
static char *copyarg(char *dp, char *dq, const char *args, int argnum)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
p = findarg(args, argnum);
|
||||||
|
if (p == NULL)
|
||||||
|
return dp;
|
||||||
|
|
||||||
|
while (dp < dq && *p != '\0' && *p != ',' && *p != ')')
|
||||||
|
*dp++ = *p++;
|
||||||
|
return dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sees if [idp, idq[ is a parameter of the macro 'pps'.
|
||||||
|
* If it is, return the number of parameter.
|
||||||
|
* Else return -1.
|
||||||
|
*/
|
||||||
|
static int findparam(const char *idp, const char *idq, struct macro *pps)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const char *p, *r;
|
||||||
|
|
||||||
|
for (i = 0; i < pps->npars; i++) {
|
||||||
|
p = pps->ppars[i];
|
||||||
|
r = idp;
|
||||||
|
while (*p != '\0' && r < idq && *p == *r) {
|
||||||
|
p++;
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
if (*p == '\0' && r == idq)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup the string in [p, q[ in 's_mactab'.
|
||||||
|
* Return the symbol or NULL if it is not in the table.
|
||||||
|
*/
|
||||||
|
static struct macro *pplookup(const char *p, const char *q)
|
||||||
|
{
|
||||||
|
int h;
|
||||||
|
struct macro *nod;
|
||||||
|
|
||||||
|
h = hash(p, q, MACTABSZ);
|
||||||
|
for (nod = s_mactab[h]; nod != NULL; nod = nod->next)
|
||||||
|
if (scmp(p, q, nod->name) == 0)
|
||||||
|
return nod;
|
||||||
|
|
||||||
|
return nod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expand macro in [dp, dq[.
|
||||||
|
*
|
||||||
|
* 'pps' is the macro to expand.
|
||||||
|
* 'args' points to the start of the arguments to substitute, if any.
|
||||||
|
*
|
||||||
|
* Return new dp.
|
||||||
|
*/
|
||||||
|
static char *expandid(char *dp, char *dq, struct macro *pps, const char *args)
|
||||||
|
{
|
||||||
|
const char *p, *q;
|
||||||
|
int validid, argnum;
|
||||||
|
|
||||||
|
validid = 1;
|
||||||
|
p = pps->text;
|
||||||
|
while (*p != '\0' && dp < dq) {
|
||||||
|
if (isidc0(*p)) {
|
||||||
|
for (q = p; isidc(*q); q++)
|
||||||
|
;
|
||||||
|
if (validid) {
|
||||||
|
argnum = findparam(p, q, pps);
|
||||||
|
if (argnum >= 0)
|
||||||
|
dp = copyarg(dp, dq, args, argnum);
|
||||||
|
else
|
||||||
|
dp = copypp(dp, dq, p, q);
|
||||||
|
} else {
|
||||||
|
dp = copypp(dp, dq, p, q);
|
||||||
|
}
|
||||||
|
p = q;
|
||||||
|
validid = 1;
|
||||||
|
} else {
|
||||||
|
validid = !isidc(*p);
|
||||||
|
*dp++ = *p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If 'p' points the the start of an argument list, that is, '(',
|
||||||
|
* point to one character past the first ')' after 'p'.
|
||||||
|
* Else return 'p'.
|
||||||
|
*/
|
||||||
|
static const char *skipargs(const char *p)
|
||||||
|
{
|
||||||
|
if (*p == '(') {
|
||||||
|
while (*p != '\0' && *p != ')')
|
||||||
|
p++;
|
||||||
|
if (*p == ')')
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expand macros found in 'p' (null terminated) into [dp, dq[.
|
||||||
|
* dq must be writable to put a final '\0'.
|
||||||
|
*/
|
||||||
|
static int expand_line(char *dp, char *dq, const char *p)
|
||||||
|
{
|
||||||
|
char *op;
|
||||||
|
int expanded, validid;
|
||||||
|
const char *s;
|
||||||
|
struct macro *nod;
|
||||||
|
|
||||||
|
validid = 1;
|
||||||
|
expanded = 0;
|
||||||
|
while (dp < dq && *p != '\0' && *p != ';') {
|
||||||
|
if (*p == '\'' && *(p + 1) != '\0' && *(p + 2) == '\'') {
|
||||||
|
/* characters */
|
||||||
|
dp = copypp(dp, dq, p, p + 3);
|
||||||
|
p += 3;
|
||||||
|
validid = 1;
|
||||||
|
} else if (*p == '\"') {
|
||||||
|
/* strings */
|
||||||
|
s = p;
|
||||||
|
p++;
|
||||||
|
/* skip over the string literal */
|
||||||
|
while (*p != '\0' && *p != '\"') {
|
||||||
|
if (p[0] == '\\' && p[1] == '\"')
|
||||||
|
p++;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
if (*p == '\"')
|
||||||
|
p++;
|
||||||
|
dp = copypp(dp, dq, s, p);
|
||||||
|
validid = 1;
|
||||||
|
} else if (isidc0(*p)) {
|
||||||
|
s = p;
|
||||||
|
while (isidc(*p))
|
||||||
|
p++;
|
||||||
|
if (validid) {
|
||||||
|
nod = pplookup(s, p);
|
||||||
|
if (nod != NULL) {
|
||||||
|
op = dp;
|
||||||
|
dp = expandid(dp, dq, nod, p);
|
||||||
|
expanded = dp != op;
|
||||||
|
p = skipargs(p);
|
||||||
|
} else {
|
||||||
|
dp = copypp(dp, dq, s, p);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dp = copypp(dp, dq, s, p);
|
||||||
|
}
|
||||||
|
validid = 1;
|
||||||
|
} else {
|
||||||
|
validid = *p != '.' && !isalnum(*p);
|
||||||
|
*dp++ = *p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*dp = '\0';
|
||||||
|
return expanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expand macros found in 'p' (null terminated).
|
||||||
|
* Return a pointer to an internal preprocessed line (null terminated).
|
||||||
|
*/
|
||||||
|
static char *expand_line0(const char *p)
|
||||||
|
{
|
||||||
|
int iter, expanded;
|
||||||
|
char *np, *nq, *op;
|
||||||
|
|
||||||
|
iter = 0;
|
||||||
|
np = &s_ppbuf[iter & 1][0];
|
||||||
|
nq = &s_ppbuf[iter & 1][LINESZ - 1];
|
||||||
|
expanded = expand_line(np, nq, p);
|
||||||
|
/* TODO: recursive macro expansion limit */
|
||||||
|
while (expanded && iter < 5) {
|
||||||
|
op = np;
|
||||||
|
iter++;
|
||||||
|
np = &s_ppbuf[iter & 1][0];
|
||||||
|
nq = &s_ppbuf[iter & 1][LINESZ - 1];
|
||||||
|
expanded = expand_line(np, nq, op);
|
||||||
|
}
|
||||||
|
return np;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if 'p' starts with the preprocessor directive 'ucq', that must be in
|
||||||
|
* upper case.
|
||||||
|
* 'p' can have any case.
|
||||||
|
* After the preprocessor directive must be a space or '\0'.
|
||||||
|
* Return 1 if all the above is true. 0 otherwise.
|
||||||
|
*/
|
||||||
|
static int isppid(const char *p, const char *ucq)
|
||||||
|
{
|
||||||
|
while (*p != '\0' && *ucq != '\0' && toupper(*p) == *ucq) {
|
||||||
|
p++;
|
||||||
|
ucq++;
|
||||||
|
}
|
||||||
|
return (*ucq == '\0') && (*p == '\0' || isspace(*p));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define a macro.
|
||||||
|
*
|
||||||
|
* [idp, idq[ is the macro id.
|
||||||
|
* [ap, aq[ is the macro argument list. If ap == aq there are no arguments.
|
||||||
|
* [tp, tq[ is the macro text.
|
||||||
|
*/
|
||||||
|
static void define(const char *idp, const char *idq,
|
||||||
|
const char *tp, const char *tq,
|
||||||
|
const char *ap, const char *aq)
|
||||||
|
{
|
||||||
|
int h;
|
||||||
|
char *p;
|
||||||
|
struct macro *nod;
|
||||||
|
|
||||||
|
h = hash(idp, idq, MACTABSZ);
|
||||||
|
for (nod = s_mactab[h]; nod != NULL; nod = nod->next) {
|
||||||
|
if (scmp(idp, idq, nod->name) == 0) {
|
||||||
|
/* Already defined. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_nmacs++;
|
||||||
|
if (s_nmacs >= NMACROS) {
|
||||||
|
eprint(_("maximum number of macros exceeded (%d)\n"), NMACROS);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
nod = emalloc((sizeof *nod) + (idq - idp) + (aq - ap) + 2);
|
||||||
|
nod->text = emalloc(tq - tp + 1);
|
||||||
|
nod->name = (char *) ((unsigned char *) nod + (sizeof *nod));
|
||||||
|
nod->pars = nod->name + (idq - idp + 1);
|
||||||
|
|
||||||
|
copychars(nod->name, idp, idq);
|
||||||
|
copychars(nod->text, tp, tq);
|
||||||
|
copychars(nod->pars, ap, aq);
|
||||||
|
|
||||||
|
// printf("DEF %s(%s) %s\n", nod->name, nod->pars, nod->text);
|
||||||
|
|
||||||
|
/* We don't check whether the arguments are different. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make ppars point to each argument and null terminate each one.
|
||||||
|
* Count the number of arguments.
|
||||||
|
*/
|
||||||
|
nod->npars = 0;
|
||||||
|
p = nod->pars;
|
||||||
|
while (*p != '\0') {
|
||||||
|
nod->ppars[nod->npars++] = p;
|
||||||
|
while (*p != '\0' && *p != ',')
|
||||||
|
p++;
|
||||||
|
if (*p == ',')
|
||||||
|
*p++ = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
nod->next = s_mactab[h];
|
||||||
|
s_mactab[h] = nod;
|
||||||
|
s_lastmac = nod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the text [p, q[ to the last macro text. */
|
||||||
|
static void defcont(const char *p, const char *q)
|
||||||
|
{
|
||||||
|
char *nt;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
len = strlen(s_lastmac->text);
|
||||||
|
nt = erealloc(s_lastmac->text, (q - p) + len + 1);
|
||||||
|
copychars(nt + len, p, q);
|
||||||
|
s_lastmac->text = nt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If 'p' points to a valid identifier start, go to the end of the identifier.
|
||||||
|
* Else return 'p'.
|
||||||
|
*/
|
||||||
|
static const char *getid(const char *p)
|
||||||
|
{
|
||||||
|
if (isidc0(*p)) {
|
||||||
|
while (isidc(*p))
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Issues error in a macro definition. */
|
||||||
|
static void macdeferr(int cmdline, const char *estr, const char *ep)
|
||||||
|
{
|
||||||
|
if (cmdline) {
|
||||||
|
eprint(_("error in command line macro definition\n"));
|
||||||
|
}
|
||||||
|
eprint(estr);
|
||||||
|
eprcol(s_line, ep);
|
||||||
|
if (cmdline) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse macro definition. */
|
||||||
|
static void pmacdef(const char *p, int cmdline)
|
||||||
|
{
|
||||||
|
const char *q, *ap, *aq, *idp, *idq;
|
||||||
|
|
||||||
|
idp = p;
|
||||||
|
idq = getid(idp);
|
||||||
|
if (idq == idp) {
|
||||||
|
macdeferr(cmdline, _("identifier excepted\n"), p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p = idq;
|
||||||
|
ap = aq = p;
|
||||||
|
if (*p == '(') {
|
||||||
|
p++;
|
||||||
|
ap = p;
|
||||||
|
while (isidc0(*p)) {
|
||||||
|
p = getid(p);
|
||||||
|
if (*p != ',')
|
||||||
|
break;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
if (*p != ')') {
|
||||||
|
macdeferr(cmdline, _("')' expected\n"), p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
aq = p;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
if (*p != '\0' && !isspace(*p)) {
|
||||||
|
macdeferr(cmdline, _("space expected\n"), p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p = skipws(p);
|
||||||
|
/* go to the end */
|
||||||
|
for (q = p; *q != '\0'; q++)
|
||||||
|
;
|
||||||
|
/* go to the first non white from the end */
|
||||||
|
while (q > p && isspace(*(q - 1)))
|
||||||
|
q--;
|
||||||
|
define(idp, idq, p, q, ap, aq);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse #define. */
|
||||||
|
static void pdefine(const char *p)
|
||||||
|
{
|
||||||
|
p = skipws(p + sizeof(DEFINESTR) - 1);
|
||||||
|
pmacdef(p, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse #defcont. */
|
||||||
|
static void pdefcont(const char *p)
|
||||||
|
{
|
||||||
|
const char *q;
|
||||||
|
|
||||||
|
p = skipws(p + sizeof(DEFCONTSTR) - 1);
|
||||||
|
|
||||||
|
/* go to the end */
|
||||||
|
for (q = p; *q != '\0'; q++)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* go to the first non white from the end */
|
||||||
|
while (q > p && isspace(*(q - 1)))
|
||||||
|
q--;
|
||||||
|
|
||||||
|
if (p == q) {
|
||||||
|
/* nothing to add */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_lastmac == NULL) {
|
||||||
|
eprint(_("#DEFCONT without a previous #DEFINE\n"));
|
||||||
|
eprcol(s_line, s_line_ep);
|
||||||
|
newerr();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
defcont(p, q);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse #include. */
|
||||||
|
static void pinclude(const char *p)
|
||||||
|
{
|
||||||
|
const char *q;
|
||||||
|
|
||||||
|
p = skipws(p + sizeof(INCLUDESTR) - 1);
|
||||||
|
if (*p != '\"') {
|
||||||
|
eprint(_("#INCLUDE expects a filename between quotes\n"));
|
||||||
|
eprcol(s_line, p);
|
||||||
|
newerr();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
q = ++p;
|
||||||
|
while (*q != '\0' && *q != '\"')
|
||||||
|
q++;
|
||||||
|
if (*q != '\"') {
|
||||||
|
wprint(_("no terminating quote\n"));
|
||||||
|
eprcol(s_line, q);
|
||||||
|
}
|
||||||
|
pushfile(p, q);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse #ifdef or #ifndef.
|
||||||
|
* 'idsz' is the length of the string 'ifdef' or 'ifndef', plus '\0'.
|
||||||
|
* 'ifdef' must be 1 if we are #ifdef, 0 if #ifndef.
|
||||||
|
*/
|
||||||
|
static void pifdef(const char *p, size_t idsz, int ifdef)
|
||||||
|
{
|
||||||
|
const char *q;
|
||||||
|
struct macro *nod;
|
||||||
|
|
||||||
|
s_nifs++;
|
||||||
|
if (s_skipon)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p = skipws(p + idsz - 1);
|
||||||
|
if (!isidc0(*p)) {
|
||||||
|
s_skipon = s_nifs;
|
||||||
|
eprint(_("identifier expected\n"));
|
||||||
|
eprcol(s_line, p);
|
||||||
|
newerr();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
q = p;
|
||||||
|
while (isidc(*q))
|
||||||
|
q++;
|
||||||
|
nod = pplookup(p, q);
|
||||||
|
if (ifdef == (nod != NULL))
|
||||||
|
s_skipon = 0;
|
||||||
|
else
|
||||||
|
s_skipon = s_nifs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse #else. */
|
||||||
|
static void pelse(const char *p)
|
||||||
|
{
|
||||||
|
if (s_nifs == 0) {
|
||||||
|
eprint(_("unbalanced #ELSE\n"));
|
||||||
|
eprcol(s_line, s_line_ep);
|
||||||
|
newerr();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_skipon && s_nifs == s_skipon)
|
||||||
|
s_skipon = 0;
|
||||||
|
else if (!s_skipon)
|
||||||
|
s_skipon = s_nifs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse #endif. */
|
||||||
|
static void pendif(const char *p)
|
||||||
|
{
|
||||||
|
if (s_nifs == 0) {
|
||||||
|
eprint(_("unbalanced #ENDIF\n"));
|
||||||
|
eprcol(s_line, s_line_ep);
|
||||||
|
newerr();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_skipon && s_nifs == s_skipon)
|
||||||
|
s_skipon = 0;
|
||||||
|
s_nifs--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse #if.
|
||||||
|
*/
|
||||||
|
static void pif(const char *p)
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
enum expr_ecode ex_ec;
|
||||||
|
const char *ep;
|
||||||
|
|
||||||
|
s_nifs++;
|
||||||
|
if (s_skipon)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p = skipws(p + sizeof(IFSTR) - 1);
|
||||||
|
if (!expr(p, &v, s_pc, 1, &ex_ec, &ep)) {
|
||||||
|
s_skipon = 1;
|
||||||
|
exprint(ex_ec, s_line, ep);
|
||||||
|
newerr();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v == 0)
|
||||||
|
s_skipon = s_nifs;
|
||||||
|
else
|
||||||
|
s_skipon = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse a preprocessor line.
|
||||||
|
* 'p' points to the next character after the '#'.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
parse_line(const char *p)
|
||||||
|
{
|
||||||
|
if (isppid(p, IFDEFSTR)) {
|
||||||
|
pifdef(p, sizeof IFDEFSTR, 1);
|
||||||
|
} else if (isppid(p, IFNDEFSTR)) {
|
||||||
|
pifdef(p, sizeof IFNDEFSTR, 0);
|
||||||
|
} else if (isppid(p, IFSTR)) {
|
||||||
|
pif(p);
|
||||||
|
} else if (isppid(p, ELSESTR)) {
|
||||||
|
pelse(p);
|
||||||
|
} else if (isppid(p, ENDIFSTR)) {
|
||||||
|
pendif(p);
|
||||||
|
} else if (s_skipon) {
|
||||||
|
;
|
||||||
|
} else if (isppid(p, INCLUDESTR)) {
|
||||||
|
pinclude(p);
|
||||||
|
} else if (isppid(p, DEFINESTR)) {
|
||||||
|
pdefine(p);
|
||||||
|
} else if (isppid(p, DEFCONTSTR)) {
|
||||||
|
pdefcont(p);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
|
eprint(_("unknown preprocessor directive\n"));
|
||||||
|
eprcol(s_line, s_line_ep);
|
||||||
|
newerr();
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Preprocess 'line' in 's_pline'.
|
||||||
|
* In this module, while we are preprocessing:
|
||||||
|
* s_line is the original line.
|
||||||
|
* s_line_ep is a pointer inside line that we keep for error reporting.
|
||||||
|
*/
|
||||||
|
void pp_line(const char *line)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
s_line = line;
|
||||||
|
s_line_ep = line;
|
||||||
|
|
||||||
|
p = skipws(line);
|
||||||
|
if ((*p == '#') || (*p == '.')) {
|
||||||
|
s_line_ep = p;
|
||||||
|
if (parse_line(p + 1)) {
|
||||||
|
s_ppbuf[0][0] = '\0';
|
||||||
|
s_pline = &s_ppbuf[0][0];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s_skipon) {
|
||||||
|
s_ppbuf[0][0] = '\0';
|
||||||
|
s_pline = &s_ppbuf[0][0];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s_pline = expand_line0(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset the module for other passes. */
|
||||||
|
void pp_reset(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct macro *nod, *cur;
|
||||||
|
|
||||||
|
s_nmacs = 0;
|
||||||
|
s_nifs = 0;
|
||||||
|
s_skipon = 0;
|
||||||
|
s_lastmac = NULL;
|
||||||
|
for (i = 0; i < MACTABSZ; i++) {
|
||||||
|
nod = s_mactab[i];
|
||||||
|
while (nod != NULL) {
|
||||||
|
cur = nod;
|
||||||
|
nod = nod->next;
|
||||||
|
free(cur->text);
|
||||||
|
free(cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memset(s_mactab, 0, MACTABSZ * sizeof(s_mactab[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
void pp_define(const char *mactext)
|
||||||
|
{
|
||||||
|
s_line = mactext;
|
||||||
|
s_line_ep = mactext;
|
||||||
|
pmacdef(mactext, 1);
|
||||||
|
s_lastmac = NULL;
|
||||||
|
}
|
23
2048/uz80as/pp.h
Normal file
23
2048/uz80as/pp.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Preprocessor.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PP_H
|
||||||
|
#define PP_H
|
||||||
|
|
||||||
|
/* Max line length after macro expansion + '\0'. */
|
||||||
|
#define LINESZ 512
|
||||||
|
|
||||||
|
extern char *s_pline;
|
||||||
|
extern int s_pc;
|
||||||
|
extern int s_pass;
|
||||||
|
extern int s_skipon;
|
||||||
|
|
||||||
|
void pp_line(const char *line);
|
||||||
|
void pp_reset(void);
|
||||||
|
void pp_define(const char *name);
|
||||||
|
|
||||||
|
#endif
|
343
2048/uz80as/prtable.c
Normal file
343
2048/uz80as/prtable.c
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
#include "prtable.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "targets.h"
|
||||||
|
#include "uz80as.h"
|
||||||
|
|
||||||
|
#ifndef STDLIB_H
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CTYPE_H
|
||||||
|
#include <ctype.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STRING_H
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum { STRSZ = 32 };
|
||||||
|
|
||||||
|
struct itext {
|
||||||
|
struct itext *next;
|
||||||
|
int undoc;
|
||||||
|
char str[STRSZ];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ilist {
|
||||||
|
struct itext *head;
|
||||||
|
int nelems;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct itable {
|
||||||
|
struct itext **table;
|
||||||
|
int nelems;
|
||||||
|
};
|
||||||
|
|
||||||
|
static char s_buf[STRSZ];
|
||||||
|
|
||||||
|
static void nomem(const char *str)
|
||||||
|
{
|
||||||
|
eprogname();
|
||||||
|
fprintf(stderr, _("not enough memory (%s)\n"), str);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compare(const void *pa, const void *pb)
|
||||||
|
{
|
||||||
|
const struct itext * const *ia;
|
||||||
|
const struct itext * const *ib;
|
||||||
|
|
||||||
|
ia = (const struct itext * const *) pa;
|
||||||
|
ib = (const struct itext * const *) pb;
|
||||||
|
return strcmp((*ia)->str, (*ib)->str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a new allocated itable of pointers that point to each element in the
|
||||||
|
* list ilist, alphabetically sorted.
|
||||||
|
*/
|
||||||
|
static struct itable *sort_list(struct ilist *ilist)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
struct itable *itable;
|
||||||
|
struct itext *p;
|
||||||
|
|
||||||
|
if ((itable = calloc(1, sizeof(*itable))) == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
itable->nelems = 0;
|
||||||
|
|
||||||
|
if (ilist->nelems == 0) {
|
||||||
|
return itable;
|
||||||
|
}
|
||||||
|
|
||||||
|
itable->table = malloc(ilist->nelems * sizeof(*itable->table));
|
||||||
|
if (itable->table == NULL) {
|
||||||
|
free(itable);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n = 0, p = ilist->head;
|
||||||
|
p != NULL && n < ilist->nelems;
|
||||||
|
p = p->next, n++)
|
||||||
|
{
|
||||||
|
itable->table[n] = p;
|
||||||
|
}
|
||||||
|
itable->nelems = n;
|
||||||
|
|
||||||
|
qsort(itable->table, itable->nelems, sizeof(*itable->table), compare);
|
||||||
|
return itable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_itable(struct itable *itable, FILE *f)
|
||||||
|
{
|
||||||
|
int i, col;
|
||||||
|
struct itext *p;
|
||||||
|
|
||||||
|
if (itable == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("@multitable @columnfractions .25 .25 .25 .25\n", f);
|
||||||
|
col = 0;
|
||||||
|
for (i = 0; i < itable->nelems; i++) {
|
||||||
|
p = itable->table[i];
|
||||||
|
if (col == 0) {
|
||||||
|
fputs("@item ", f);
|
||||||
|
} else {
|
||||||
|
fputs("@tab ", f);
|
||||||
|
}
|
||||||
|
if (p->undoc) {
|
||||||
|
fputs("* ", f);
|
||||||
|
}
|
||||||
|
fprintf(f, "%s\n", p->str);
|
||||||
|
col++;
|
||||||
|
if (col >= 4) {
|
||||||
|
col = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fputs("@end multitable\n", f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void print_ilist(struct ilist *ilist, FILE *f)
|
||||||
|
{
|
||||||
|
int col;
|
||||||
|
struct itext *p;
|
||||||
|
|
||||||
|
if (ilist == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("@multitable @columnfractions .25 .25 .25 .25\n", f);
|
||||||
|
col = 0;
|
||||||
|
for (p = ilist->head; p != NULL; p = p->next) {
|
||||||
|
if (col == 0) {
|
||||||
|
fputs("@item ", f);
|
||||||
|
} else {
|
||||||
|
fputs("@tab ", f);
|
||||||
|
}
|
||||||
|
if (p->undoc) {
|
||||||
|
fputs("* ", f);
|
||||||
|
}
|
||||||
|
fprintf(f, "%s\n", p->str);
|
||||||
|
col++;
|
||||||
|
if (col >= 4) {
|
||||||
|
col = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fputs("@end multitable\n", f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void bufset(int i, char c)
|
||||||
|
{
|
||||||
|
if (i >= STRSZ) {
|
||||||
|
eprogname();
|
||||||
|
fputs(_("prtable: please, increase s_buf size\n"), stderr);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
s_buf[i] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_inst2(struct ilist *ilist, char *instr, int undoc)
|
||||||
|
{
|
||||||
|
struct itext *p;
|
||||||
|
|
||||||
|
if ((p = malloc(sizeof(*p))) == NULL) {
|
||||||
|
nomem("gen_inst2");
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(p->str, STRSZ, "%s", instr);
|
||||||
|
p->undoc = undoc;
|
||||||
|
p->next = ilist->head;
|
||||||
|
ilist->head = p;
|
||||||
|
ilist->nelems++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gen_inst(struct ilist *ilist, const struct target *t,
|
||||||
|
unsigned char undoc, const char *p, size_t bufi,
|
||||||
|
const char *pr)
|
||||||
|
{
|
||||||
|
size_t bufk;
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
while (*p) {
|
||||||
|
if (!islower(*p)) {
|
||||||
|
if (*p == '@') {
|
||||||
|
bufset(bufi++, '@');
|
||||||
|
}
|
||||||
|
bufset(bufi++, *p);
|
||||||
|
p++;
|
||||||
|
} else if (*p == 'a') {
|
||||||
|
if (pr == NULL) {
|
||||||
|
bufset(bufi++, 'e');
|
||||||
|
} else if (pr[0] && pr[1]) {
|
||||||
|
if (pr[0] == pr[1]) {
|
||||||
|
bufset(bufi++, pr[0]);
|
||||||
|
pr += 2;
|
||||||
|
} else if (isdigit(pr[1])) {
|
||||||
|
bufset(bufi++, *pr);
|
||||||
|
pr++;
|
||||||
|
while (isdigit(*pr)) {
|
||||||
|
bufset(bufi++, *pr);
|
||||||
|
pr++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bufset(bufi++, pr[0]);
|
||||||
|
bufset(bufi++, pr[1]);
|
||||||
|
pr += 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bufset(bufi++, 'e');
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*p == '\0') {
|
||||||
|
bufset(bufi, '\0');
|
||||||
|
gen_inst2(ilist, s_buf, t->mask & undoc);
|
||||||
|
} else {
|
||||||
|
t->pat_char_rewind(*p);
|
||||||
|
while ((s = t->pat_next_str()) != NULL) {
|
||||||
|
if (s[0] != '\0') {
|
||||||
|
bufset(bufi, '\0');
|
||||||
|
bufk = bufi;
|
||||||
|
while (*s != '\0') {
|
||||||
|
bufset(bufk++, *s);
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
bufset(bufk, '\0');
|
||||||
|
gen_inst(ilist, t, undoc, p + 1, bufk, pr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate a list of instructions. */
|
||||||
|
static struct ilist *gen_list(const struct target *t, unsigned char mask2,
|
||||||
|
int delta)
|
||||||
|
{
|
||||||
|
int i, pr;
|
||||||
|
const struct matchtab *mt;
|
||||||
|
struct ilist *ilist;
|
||||||
|
|
||||||
|
if ((ilist = calloc(1, sizeof(*ilist))) == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
mt = t->matcht;
|
||||||
|
while (mt[i].pat != NULL) {
|
||||||
|
pr = 0;
|
||||||
|
if (t->mask == 1 && (mt[i].mask & 1)) {
|
||||||
|
pr = 1;
|
||||||
|
} else if (delta) {
|
||||||
|
if ((mt[i].mask & t->mask) &&
|
||||||
|
!(mt[i].mask & mask2))
|
||||||
|
{
|
||||||
|
pr = 1;
|
||||||
|
}
|
||||||
|
} else if (t->mask & mt[i].mask) {
|
||||||
|
pr = 1;
|
||||||
|
}
|
||||||
|
if (pr) {
|
||||||
|
gen_inst(ilist, t, mt[i].undoc, mt[i].pat,
|
||||||
|
0, mt[i].pr);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ilist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prints the instruction set of a target or if target_id is "target2,target1"
|
||||||
|
* prints the instructions in target2 not in target1.
|
||||||
|
*/
|
||||||
|
void print_table(FILE *f, const char *target_id)
|
||||||
|
{
|
||||||
|
struct ilist *ilist;
|
||||||
|
struct itable *itable;
|
||||||
|
const struct target *t, *t2;
|
||||||
|
char target1[STRSZ];
|
||||||
|
const char *target2;
|
||||||
|
unsigned char mask2;
|
||||||
|
int delta;
|
||||||
|
|
||||||
|
/* check if we have "target" or "target,target" as arguments */
|
||||||
|
if ((target2 = strchr(target_id, ',')) != NULL) {
|
||||||
|
delta = 1;
|
||||||
|
snprintf(target1, sizeof(target1), "%s", target_id);
|
||||||
|
target1[target2 - target_id] = '\0';
|
||||||
|
target2++;
|
||||||
|
} else {
|
||||||
|
delta = 0;
|
||||||
|
snprintf(target1, sizeof(target1), "%s", target_id);
|
||||||
|
target2 = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = find_target(target1);
|
||||||
|
if (t == NULL) {
|
||||||
|
eprogname();
|
||||||
|
fprintf(stderr, _("invalid target '%s'\n"), target1);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target2) {
|
||||||
|
t2 = find_target(target2);
|
||||||
|
if (t2 == NULL) {
|
||||||
|
eprogname();
|
||||||
|
fprintf(stderr, _("invalid target '%s'\n"), target2);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (t->matcht != t2->matcht) {
|
||||||
|
eprogname();
|
||||||
|
fprintf(stderr, _("unrelated targets %s,%s\n"),
|
||||||
|
target1, target2);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
mask2 = t2->mask;
|
||||||
|
} else {
|
||||||
|
mask2 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ilist = gen_list(t, mask2, delta)) == NULL) {
|
||||||
|
nomem("gen_list");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((itable = sort_list(ilist)) == NULL) {
|
||||||
|
nomem("sort_list");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_itable(itable, f);
|
||||||
|
|
||||||
|
/* We don't free ilist nor itable for now, since this is called
|
||||||
|
* from main and then the program terminated.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
11
2048/uz80as/prtable.h
Normal file
11
2048/uz80as/prtable.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef PRTABLE_H
|
||||||
|
#define PRTABLE_H
|
||||||
|
|
||||||
|
#ifndef STDIO_H
|
||||||
|
#define STDIO_H
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void print_table(FILE *f, const char *target_id);
|
||||||
|
|
||||||
|
#endif
|
103
2048/uz80as/sym.c
Normal file
103
2048/uz80as/sym.c
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Symbol table for labels.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "sym.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "err.h"
|
||||||
|
|
||||||
|
#ifndef STDIO_H
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STDLIB_H
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maximum number of symbols (labels) allowed.
|
||||||
|
* Must not be more than 64K.
|
||||||
|
*/
|
||||||
|
#define NSYMS 15000
|
||||||
|
|
||||||
|
/* Closest prime to NSYMS / 4. */
|
||||||
|
#define SYMTABSZ 3739
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Nodes for the s_symtab hash table.
|
||||||
|
* The symbol at index 0 is never used.
|
||||||
|
*/
|
||||||
|
static struct sym s_symlist[NSYMS];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hash table of indexes into s_symlist.
|
||||||
|
* 0 means that the bucket is empty.
|
||||||
|
*/
|
||||||
|
static unsigned short s_symtab[SYMTABSZ];
|
||||||
|
|
||||||
|
/* Next free symbol in s_symlist. Note: 0 not used. */
|
||||||
|
static int s_nsyms = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookups the string in [p, q[ in s_symtab.
|
||||||
|
* If !insert, returns the symbol or NULL if it is not in the table.
|
||||||
|
* If insert, inserts the symbol in the table if it is not there, and
|
||||||
|
* sets its .val to 'pc'.
|
||||||
|
*/
|
||||||
|
struct sym *lookup(const char *p, const char *q, int insert, int pc)
|
||||||
|
{
|
||||||
|
int h, k;
|
||||||
|
struct sym *nod;
|
||||||
|
|
||||||
|
if (q - p > SYMLEN - 1) {
|
||||||
|
/* Label too long, don't add. */
|
||||||
|
eprint(_("label too long"));
|
||||||
|
epchars(p, q);
|
||||||
|
enl();
|
||||||
|
newerr();
|
||||||
|
/*
|
||||||
|
* This would truncate:
|
||||||
|
* q = p + (SYMLEN - 1);
|
||||||
|
*/
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
h = hash(p, q, SYMTABSZ);
|
||||||
|
for (k = s_symtab[h]; k != 0; k = s_symlist[k].next) {
|
||||||
|
if (scmp(p, q, s_symlist[k].name) == 0) {
|
||||||
|
if (insert) {
|
||||||
|
if (!s_symlist[k].isequ) {
|
||||||
|
wprint("duplicate label (%s)\n",
|
||||||
|
s_symlist[k].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &s_symlist[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (insert) {
|
||||||
|
if (s_nsyms == NSYMS) {
|
||||||
|
eprint(_("maximum number of labels exceeded (%d)\n"),
|
||||||
|
NSYMS);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
nod = &s_symlist[s_nsyms];
|
||||||
|
nod->next = s_symtab[h];
|
||||||
|
s_symtab[h] = (unsigned short) s_nsyms;
|
||||||
|
s_nsyms++;
|
||||||
|
|
||||||
|
k = 0;
|
||||||
|
while (p != q && k < SYMLEN - 1)
|
||||||
|
nod->name[k++] = *p++;
|
||||||
|
nod->name[k] = '\0';
|
||||||
|
nod->val = pc;
|
||||||
|
return nod;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
23
2048/uz80as/sym.h
Normal file
23
2048/uz80as/sym.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Symbol table for labels.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SYM_H
|
||||||
|
#define SYM_H
|
||||||
|
|
||||||
|
/* Max symbol length + '\0'. */
|
||||||
|
#define SYMLEN 32
|
||||||
|
|
||||||
|
struct sym {
|
||||||
|
char name[SYMLEN]; /* null terminated string */
|
||||||
|
int val; /* value of symbol */
|
||||||
|
unsigned short next; /* index into symlist; 0 is no next */
|
||||||
|
unsigned char isequ; /* if val comes from EQU */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sym *lookup(const char *p, const char *q, int insert, int pc);
|
||||||
|
|
||||||
|
#endif
|
96
2048/uz80as/targets.c
Normal file
96
2048/uz80as/targets.c
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Target list.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "targets.h"
|
||||||
|
#include "uz80as.h"
|
||||||
|
|
||||||
|
#ifndef STRING_H
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const struct target s_target_z80;
|
||||||
|
extern const struct target s_target_hd64180;
|
||||||
|
extern const struct target s_target_gbcpu;
|
||||||
|
extern const struct target s_target_dp2200;
|
||||||
|
extern const struct target s_target_dp2200ii;
|
||||||
|
extern const struct target s_target_i4004;
|
||||||
|
extern const struct target s_target_i4040;
|
||||||
|
extern const struct target s_target_i8008;
|
||||||
|
extern const struct target s_target_i8021;
|
||||||
|
extern const struct target s_target_i8022;
|
||||||
|
extern const struct target s_target_i8041;
|
||||||
|
extern const struct target s_target_i8048;
|
||||||
|
extern const struct target s_target_i8051;
|
||||||
|
extern const struct target s_target_i8080;
|
||||||
|
extern const struct target s_target_i8085;
|
||||||
|
extern const struct target s_target_mos6502;
|
||||||
|
extern const struct target s_target_r6501;
|
||||||
|
extern const struct target s_target_g65sc02;
|
||||||
|
extern const struct target s_target_r65c02;
|
||||||
|
extern const struct target s_target_r65c29;
|
||||||
|
extern const struct target s_target_w65c02s;
|
||||||
|
extern const struct target s_target_mc6800;
|
||||||
|
extern const struct target s_target_mc6801;
|
||||||
|
extern const struct target s_target_m68hc11;
|
||||||
|
|
||||||
|
static const struct target *s_targets[] = {
|
||||||
|
&s_target_z80,
|
||||||
|
&s_target_hd64180,
|
||||||
|
&s_target_gbcpu,
|
||||||
|
&s_target_dp2200,
|
||||||
|
&s_target_dp2200ii,
|
||||||
|
&s_target_i4004,
|
||||||
|
&s_target_i4040,
|
||||||
|
&s_target_i8008,
|
||||||
|
&s_target_i8021,
|
||||||
|
&s_target_i8022,
|
||||||
|
&s_target_i8041,
|
||||||
|
&s_target_i8048,
|
||||||
|
&s_target_i8051,
|
||||||
|
&s_target_i8080,
|
||||||
|
&s_target_i8085,
|
||||||
|
&s_target_mos6502,
|
||||||
|
&s_target_r6501,
|
||||||
|
&s_target_g65sc02,
|
||||||
|
&s_target_r65c02,
|
||||||
|
&s_target_r65c29,
|
||||||
|
&s_target_w65c02s,
|
||||||
|
&s_target_mc6800,
|
||||||
|
&s_target_mc6801,
|
||||||
|
&s_target_m68hc11,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int s_index;
|
||||||
|
|
||||||
|
const struct target *find_target(const char *id)
|
||||||
|
{
|
||||||
|
const struct target **p;
|
||||||
|
|
||||||
|
for (p = s_targets; *p != NULL; p++) {
|
||||||
|
if (strcmp(id, (*p)->id) == 0) {
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct target *first_target(void)
|
||||||
|
{
|
||||||
|
s_index = 0;
|
||||||
|
return next_target();
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct target *next_target(void)
|
||||||
|
{
|
||||||
|
if (s_targets[s_index] != NULL) {
|
||||||
|
return s_targets[s_index++];
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
18
2048/uz80as/targets.h
Normal file
18
2048/uz80as/targets.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Target list.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TARGETS_H
|
||||||
|
#define TARGETS_H
|
||||||
|
|
||||||
|
struct target;
|
||||||
|
|
||||||
|
const struct target *find_target(const char *id);
|
||||||
|
|
||||||
|
const struct target *first_target(void);
|
||||||
|
const struct target *next_target(void);
|
||||||
|
|
||||||
|
#endif
|
8
2048/uz80as/test.asm
Normal file
8
2048/uz80as/test.asm
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.org 0x100
|
||||||
|
beep: .text "\"\"\"" ; comment
|
||||||
|
.align 4
|
||||||
|
.text "foo"
|
||||||
|
.align 16
|
||||||
|
.text "bar"
|
||||||
|
.db $45,0x67,'7'
|
||||||
|
.end
|
3
2048/uz80as/test1.asm
Normal file
3
2048/uz80as/test1.asm
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.org $100
|
||||||
|
beep: .text "x" ; comment
|
||||||
|
.end
|
137
2048/uz80as/utils.c
Normal file
137
2048/uz80as/utils.c
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Generic functions.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#ifndef CTYPE_H
|
||||||
|
#include <ctype.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LIMITS_H
|
||||||
|
#include <limits.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy [p, q[ to dst and null terminate dst.
|
||||||
|
*/
|
||||||
|
void copychars(char *dst, const char *p, const char *q)
|
||||||
|
{
|
||||||
|
// int i = 0;
|
||||||
|
// printf("copychars %x->%x to %x \'", p, q, dst);
|
||||||
|
while (p != q) {
|
||||||
|
// printf("%c", *p);
|
||||||
|
*dst++ = *p++;
|
||||||
|
// i++;
|
||||||
|
}
|
||||||
|
*dst = '\0';
|
||||||
|
// printf("\' %d %x %d\n", *dst, dst, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip space. */
|
||||||
|
const char *skipws(const char *p)
|
||||||
|
{
|
||||||
|
while (isspace(*p))
|
||||||
|
p++;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return 1 if *p is a valid start character for an identifier. */
|
||||||
|
int isidc0(char c)
|
||||||
|
{
|
||||||
|
return (c == '_') || isalpha(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return 1 if *p is a valid character for an identifier.
|
||||||
|
* Don't use for the first character.
|
||||||
|
*/
|
||||||
|
int isidc(char c)
|
||||||
|
{
|
||||||
|
return (c == '_') || (c == '.') || isalnum(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hash the string in [p, q[ to give a bucket in symtab. */
|
||||||
|
int hash(const char *p, const char *q, unsigned int tabsz)
|
||||||
|
{
|
||||||
|
unsigned int h;
|
||||||
|
|
||||||
|
h = 0;
|
||||||
|
while (p != q) {
|
||||||
|
h = 31 * h + (unsigned char) *p;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return h % tabsz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare the string in [p, q[ with the null-terminated string s.
|
||||||
|
* Return 0 if equal.
|
||||||
|
*/
|
||||||
|
int scmp(const char *p, const char *q, const char *s)
|
||||||
|
{
|
||||||
|
while (p < q) {
|
||||||
|
if (*p == *s) {
|
||||||
|
p++;
|
||||||
|
s++;
|
||||||
|
} else if (*s == '\0') {
|
||||||
|
return 1;
|
||||||
|
} else if (*p < *s) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*s == '\0')
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Given a hexadecimal character (in upper case), returns its integer value.
|
||||||
|
* Returns -1 if c is not a hexadecimal character.
|
||||||
|
*/
|
||||||
|
int hexvalu(char c)
|
||||||
|
{
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
return c - '0';
|
||||||
|
else if (c >= 'A' && c <= 'F')
|
||||||
|
return (c - 'A') + 10;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a hexadecimal character, returns its integer value.
|
||||||
|
* Returns -1 if c is not a hexadecimal character.
|
||||||
|
*/
|
||||||
|
int hexval(char c)
|
||||||
|
{
|
||||||
|
if (c >= 'a' && c <= 'f')
|
||||||
|
return (c - 'a') + 10;
|
||||||
|
else
|
||||||
|
return hexvalu(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int int_precission(void)
|
||||||
|
{
|
||||||
|
static int bits = 0;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (bits > 0)
|
||||||
|
return bits;
|
||||||
|
|
||||||
|
i = INT_MAX;
|
||||||
|
bits = 0;
|
||||||
|
while (i) {
|
||||||
|
bits++;
|
||||||
|
i >>= 1;
|
||||||
|
}
|
||||||
|
return bits;
|
||||||
|
}
|
26
2048/uz80as/utils.h
Normal file
26
2048/uz80as/utils.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Generic functions.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UTILS_H
|
||||||
|
#define UTILS_H
|
||||||
|
|
||||||
|
#define NELEMS(a) (sizeof(a)/sizeof(a[0]))
|
||||||
|
|
||||||
|
#define XSTR(n) STR(n)
|
||||||
|
#define STR(n) #n
|
||||||
|
|
||||||
|
void copychars(char *dst, const char *p, const char *q);
|
||||||
|
int hash(const char *p, const char *q, unsigned int tabsz);
|
||||||
|
int isidc0(char c);
|
||||||
|
int isidc(char c);
|
||||||
|
int scmp(const char *p, const char *q, const char *s);
|
||||||
|
const char *skipws(const char *p);
|
||||||
|
int hexvalu(char c);
|
||||||
|
int hexval(char c);
|
||||||
|
int int_precission(void);
|
||||||
|
|
||||||
|
#endif
|
1240
2048/uz80as/uz80as.c
Normal file
1240
2048/uz80as/uz80as.c
Normal file
File diff suppressed because it is too large
Load Diff
63
2048/uz80as/uz80as.h
Normal file
63
2048/uz80as/uz80as.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Assembler.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UZ80AS_H
|
||||||
|
#define UZ80AS_H
|
||||||
|
|
||||||
|
int verbose;
|
||||||
|
|
||||||
|
/* matchtab.flags */
|
||||||
|
enum {
|
||||||
|
MATCH_F_UNDOC = 1,
|
||||||
|
MATCH_F_EXTEN = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* pat:
|
||||||
|
* a: expr
|
||||||
|
* b - z: used by target
|
||||||
|
*
|
||||||
|
* gen:
|
||||||
|
* .: output lastbyte
|
||||||
|
* b: (op << 3) | lastbyte
|
||||||
|
* c: op | lastbyte
|
||||||
|
* d: lastbyte = op as 8 bit value
|
||||||
|
* e: output op as word (no '.' should follow)
|
||||||
|
* f - z: used by target
|
||||||
|
*
|
||||||
|
* pr:
|
||||||
|
* 8: e8
|
||||||
|
* f: e16
|
||||||
|
* r: relative jump
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct matchtab {
|
||||||
|
const char *pat;
|
||||||
|
const char *gen;
|
||||||
|
unsigned char mask;
|
||||||
|
unsigned char undoc;
|
||||||
|
const char *pr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct target {
|
||||||
|
const char *id;
|
||||||
|
const char *descr;
|
||||||
|
const struct matchtab *matcht;
|
||||||
|
int (*matchf)(char c, const char *p, const char **q);
|
||||||
|
int (*genf)(int *eb, char p, const int *vs, int i, int savepc);
|
||||||
|
void (*pat_char_rewind)(int c);
|
||||||
|
const char * (*pat_next_str)(void);
|
||||||
|
unsigned char mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char *s_pline_ep;
|
||||||
|
|
||||||
|
void genb(int b, const char *ep);
|
||||||
|
int mreg(const char *p, const char *const list[], const char **r);
|
||||||
|
|
||||||
|
void uz80as(void);
|
||||||
|
|
||||||
|
#endif
|
362
2048/uz80as/z80.c
Normal file
362
2048/uz80as/z80.c
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
/* ===========================================================================
|
||||||
|
* uz80as, an assembler for the Zilog Z80 and several other microprocessors.
|
||||||
|
*
|
||||||
|
* Zilog Z80 CPU.
|
||||||
|
* ===========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pp.h"
|
||||||
|
#include "err.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "uz80as.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* pat:
|
||||||
|
* a: expr
|
||||||
|
* b: B,C,D,E,H,L,A
|
||||||
|
* c: IX,IY (must be followed by + or -)
|
||||||
|
* d: BC,DE,HL,SP
|
||||||
|
* e: IX,IY
|
||||||
|
* f: BC,DE,HL,AF
|
||||||
|
* g: ADD,ADC,SUB,SBC,AND,XOR,OR,CP
|
||||||
|
* h: INC,DEC
|
||||||
|
* i: BC,DE,IX,SP
|
||||||
|
* j: BC,DE,IY,SP
|
||||||
|
* k: RLC,RRC,RL,RR,SLA,SRA,SRL
|
||||||
|
* l: BIT,RES,SET
|
||||||
|
* m: NZ,Z,NC,C,PO,PE,P,M
|
||||||
|
* n: NZ,Z,NC,C
|
||||||
|
* o: *
|
||||||
|
* p: B,C,D,E,IXH,IXL,A
|
||||||
|
* q: B,C,D,E,IYH,IYL,A
|
||||||
|
*
|
||||||
|
* gen:
|
||||||
|
* .: output lastbyte
|
||||||
|
* b: (op << 3) | lastbyte
|
||||||
|
* c: op | lastbyte
|
||||||
|
* d: lastbyte = op as 8 bit value
|
||||||
|
* e: output op as word (no '.' should follow)
|
||||||
|
* f: (op << 4) | lastbyte
|
||||||
|
* g: (op << 6) | lastbyte
|
||||||
|
* h: *
|
||||||
|
* i: relative jump to op
|
||||||
|
* j: possible value to RST
|
||||||
|
* k: possible value to IM
|
||||||
|
* m: check arithmetic used with A register
|
||||||
|
* n: check arithmetic used without A register
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct matchtab s_matchtab_z80[] = {
|
||||||
|
{ "LD b,b", "40b0c1.", 3, 0 },
|
||||||
|
{ "LD p,p", "DD.40b0c1.", 1, 1 },
|
||||||
|
{ "LD q,q", "FD.40b0c1.", 1, 1 },
|
||||||
|
{ "LD b,(HL)", "46b0.", 3, 0 },
|
||||||
|
{ "LD b,(e)", "d1.46b0.00.", 3, 0, "ii" },
|
||||||
|
{ "LD b,(ca)", "d1.46b0.d2.", 3, 0, "ii" },
|
||||||
|
{ "LD A,I", "ED.57.", 3, 0 },
|
||||||
|
{ "LD A,R", "ED.5F.", 3, 0 },
|
||||||
|
{ "LD A,(BC)", "0A.", 3, 0 },
|
||||||
|
{ "LD A,(DE)", "1A.", 3, 0 },
|
||||||
|
{ "LD A,(a)", "3A.e0", 3, 0 },
|
||||||
|
{ "LD b,a", "06b0.d1.", 3, 0, "e8" },
|
||||||
|
{ "LD p,a", "DD.06b0.d1.", 1, 1, "e8" },
|
||||||
|
{ "LD q,a", "FD.06b0.d1.", 1, 1, "e8" },
|
||||||
|
{ "LD I,A", "ED.47.", 3, 0 },
|
||||||
|
{ "LD R,A", "ED.4F.", 3, 0 },
|
||||||
|
{ "LD SP,HL", "F9.", 3, 0 },
|
||||||
|
{ "LD SP,e", "d0.F9.", 3, 0 },
|
||||||
|
{ "LD HL,(a)", "2A.e0", 3, 0 },
|
||||||
|
{ "LD d,(a)", "ED.4Bf0.e1", 3, 0 },
|
||||||
|
{ "LD d,a", "01f0.e1", 3, 0 },
|
||||||
|
{ "LD e,(a)", "d0.2A.e1", 3, 0 },
|
||||||
|
{ "LD e,a", "d0.21.e1", 3, 0 },
|
||||||
|
{ "LD (HL),b", "70c0.", 3, 0 },
|
||||||
|
{ "LD (HL),a", "36.d0.", 3, 0, "e8" },
|
||||||
|
{ "LD (BC),A", "02.", 3, 0 },
|
||||||
|
{ "LD (DE),A", "12.", 3, 0 },
|
||||||
|
{ "LD (e),b", "d0.70c1.00.", 3, 0, "ii" },
|
||||||
|
{ "LD (ca),b", "d0.70c2.d1.", 3, 0, "ii" },
|
||||||
|
{ "LD (e),a", "d0.36.00.d1.", 3, 0, "iie8" },
|
||||||
|
{ "LD (ca),a", "d0.36.d1.d2.", 3, 0, "iie8" },
|
||||||
|
{ "LD (a),A", "32.e0", 3, 0 },
|
||||||
|
{ "LD (a),HL", "22.e0", 3, 0 },
|
||||||
|
{ "LD (a),d", "ED.43f1.e0", 3, 0 },
|
||||||
|
{ "LD (a),e", "d1.22.e0", 3, 0 },
|
||||||
|
{ "PUSH f", "C5f0.", 3, 0 },
|
||||||
|
{ "PUSH e", "d0.E5.", 3, 0 },
|
||||||
|
{ "POP f", "C1f0.", 3, 0 },
|
||||||
|
{ "POP e", "d0.E1.", 3, 0 },
|
||||||
|
{ "EX DE,HL", "EB.", 3, 0 },
|
||||||
|
{ "EX AF,AF'", "08.", 3, 0 },
|
||||||
|
{ "EX (SP),HL", "E3.", 3, 0 },
|
||||||
|
{ "EX (SP),e", "d0.E3.", 3, 0 },
|
||||||
|
{ "EXX", "D9.", 3, 0 },
|
||||||
|
{ "LDI", "ED.A0.", 3, 0 },
|
||||||
|
{ "LDIR", "ED.B0.", 3, 0 },
|
||||||
|
{ "LDD", "ED.A8.", 3, 0 },
|
||||||
|
{ "LDDR", "ED.B8.", 3, 0 },
|
||||||
|
{ "CPI", "ED.A1.", 3, 0 },
|
||||||
|
{ "CPIR", "ED.B1.", 3, 0 },
|
||||||
|
{ "CPD", "ED.A9.", 3, 0 },
|
||||||
|
{ "CPDR", "ED.B9.", 3, 0 },
|
||||||
|
{ "ADD HL,d", "09f0.", 3, 0 },
|
||||||
|
{ "ADD IX,i", "DD.09f0.", 3, 0 },
|
||||||
|
{ "ADD IY,j", "FD.09f0.", 3, 0 },
|
||||||
|
{ "ADC HL,d", "ED.4Af0.", 3, 0 },
|
||||||
|
{ "SBC HL,d", "ED.42f0.", 3, 0 },
|
||||||
|
{ "g A,b", "m080b0c1.", 3, 0 },
|
||||||
|
{ "g A,p", "DD.m080b0c1.", 1, 1 },
|
||||||
|
{ "g A,q", "FD.m080b0c1.", 1, 1 },
|
||||||
|
{ "g A,(HL)", "m086b0.", 3, 0 },
|
||||||
|
{ "g A,(ca)", "m0d1.86b0.d2.", 3, 0, "ii" },
|
||||||
|
{ "g A,a", "m0C6b0.d1.", 3, 0, "e8" },
|
||||||
|
{ "g b", "n080b0c1.", 3, 0 },
|
||||||
|
{ "g p", "DD.n080b0c1.", 1, 1 },
|
||||||
|
{ "g q", "FD.n080b0c1.", 1, 1 },
|
||||||
|
{ "g (HL)", "n086b0.", 3, 0 },
|
||||||
|
{ "g (ca)", "n0d1.86b0.d2.", 3, 0, "ii" },
|
||||||
|
{ "g a", "n0C6b0.d1.", 3, 0, "e8" },
|
||||||
|
{ "h b", "04b1c0.", 3, 0 },
|
||||||
|
{ "h p", "DD.04b1c0.", 1, 1 },
|
||||||
|
{ "h q", "FD.04b1c0.", 1, 1 },
|
||||||
|
{ "h (HL)", "34c0.", 3, 0 },
|
||||||
|
{ "h (ca)", "d1.34c0.d2.", 3, 0, "ii" },
|
||||||
|
{ "h (e)", "d1.34c0.00.", 3, 0, "ii" },
|
||||||
|
{ "INC d", "03f0.", 3, 0 },
|
||||||
|
{ "INC e", "d0.23.", 3, 0 },
|
||||||
|
{ "DEC d", "0Bf0.", 3, 0 },
|
||||||
|
{ "DEC e", "d0.2B.", 3, 0 },
|
||||||
|
{ "DAA", "27.", 3, 0 },
|
||||||
|
{ "CPL", "2F.", 3, 0 },
|
||||||
|
{ "NEG", "ED.44.", 3, 0 },
|
||||||
|
{ "CCF", "3F.", 3, 0 },
|
||||||
|
{ "SCF", "37.", 3, 0 },
|
||||||
|
{ "NOP", "00.", 3, 0 },
|
||||||
|
{ "HALT", "76.", 3, 0 },
|
||||||
|
{ "DI", "F3.", 3, 0 },
|
||||||
|
{ "EI", "FB.", 3, 0 },
|
||||||
|
{ "IM a", "ED.k0.", 3, 0, "tt" },
|
||||||
|
{ "RLCA", "07.", 3, 0 },
|
||||||
|
{ "RLA", "17.", 3, 0 },
|
||||||
|
{ "RRCA", "0F.", 3, 0 },
|
||||||
|
{ "RRA", "1F.", 3, 0 },
|
||||||
|
{ "SLL b", "CB.30c0.", 1, 1 },
|
||||||
|
{ "SLL (HL)", "CB.36.", 1, 1 },
|
||||||
|
{ "SLL (ca)", "d0.CB.d1.36.", 1, 1, "ii" },
|
||||||
|
{ "SLL (ca),b", "d0.CB.d1.30c2.", 1, 1, "ii" },
|
||||||
|
{ "k b", "CB.00b0c1.", 3, 0 },
|
||||||
|
{ "k (HL)", "CB.06b0.", 3, 0 },
|
||||||
|
{ "k (ca)", "d1.CB.d2.06b0.", 3, 0, "ii" },
|
||||||
|
{ "k (ca),b", "d1.CB.d2.00b0c3.", 1, 1, "ii" },
|
||||||
|
{ "RLD", "ED.6F.", 3, 0 },
|
||||||
|
{ "RRD", "ED.67.", 3, 0 },
|
||||||
|
{ "l a,b", "CB.00g0b1c2.", 3, 0, "b3" },
|
||||||
|
{ "l a,(HL)", "CB.06g0b1.", 3, 0, "b3" },
|
||||||
|
{ "l a,(ca)", "d2.CB.d3.06g0b1.", 3, 0, "b3ii" },
|
||||||
|
{ "RES a,(ca),b", "d1.CB.d2.80b0c3.", 1, 1, "b3ii" },
|
||||||
|
{ "SET a,(ca),b", "d1.CB.d2.C0b0c3.", 1, 1, "b3ii" },
|
||||||
|
{ "JP (HL)", "E9.", 3, 0 },
|
||||||
|
{ "JP (e)", "d0.E9.", 3, 0 },
|
||||||
|
{ "JP m,a", "C2b0.e1", 3, 0 },
|
||||||
|
{ "JP a", "C3.e0", 3, 0 },
|
||||||
|
{ "JR n,a", "20b0.i1.", 3, 0, "r8" },
|
||||||
|
{ "JR a", "18.i0.", 3, 0, "r8" },
|
||||||
|
{ "DJNZ a", "10.i0.", 3, 0, "r8" },
|
||||||
|
{ "CALL m,a", "C4b0.e1", 3, 0 },
|
||||||
|
{ "CALL a", "CD.e0", 3, 0 },
|
||||||
|
{ "RETI", "ED.4D.", 3, 0 },
|
||||||
|
{ "RETN", "ED.45.", 3, 0 },
|
||||||
|
{ "RET m", "C0b0.", 3, 0 },
|
||||||
|
{ "RET", "C9.", 3, 0 },
|
||||||
|
{ "RST a", "C7j0.", 3, 0, "ss" },
|
||||||
|
{ "IN b,(C)", "ED.40b0.", 3, 0 },
|
||||||
|
{ "IN A,(a)", "DB.d0.", 3, 0, "e8" },
|
||||||
|
{ "IN F,(a)", "ED.70.", 3, 0 },
|
||||||
|
{ "IN (C)", "ED.70.", 1, 1 },
|
||||||
|
{ "INI", "ED.A2.", 3, 0 },
|
||||||
|
{ "INIR", "ED.B2.", 3, 0 },
|
||||||
|
{ "IND", "ED.AA.", 3, 0 },
|
||||||
|
{ "INDR", "ED.BA.", 3, 0 },
|
||||||
|
{ "OUT (C),0", "ED.71.", 1, 1 },
|
||||||
|
{ "OUT (C),b", "ED.41b0.", 3, 0 },
|
||||||
|
{ "OUT (a),A", "D3.d0.", 3, 0, "e8" },
|
||||||
|
{ "OUTI", "ED.A3.", 3, 0 },
|
||||||
|
{ "OTIR", "ED.B3.", 3, 0 },
|
||||||
|
{ "OUTD", "ED.AB.", 3, 0 },
|
||||||
|
{ "OTDR", "ED.BB.", 3, 0 },
|
||||||
|
/* hd64180 added instructions */
|
||||||
|
{ "IN0 b,(a)", "ED.00b0.d1.", 2, 0, "e8" },
|
||||||
|
{ "OUT0 (a),b", "ED.01b1.d0.", 2, 0, "e8" },
|
||||||
|
{ "OTDM", "ED.8B.", 2, 0 },
|
||||||
|
{ "OTDMR", "ED.9B.", 2, 0 },
|
||||||
|
{ "OTIM", "ED.83.", 2, 0 },
|
||||||
|
{ "OTIMR", "ED.93.", 2, 0 },
|
||||||
|
{ "MLT d", "ED.4Cf0.", 2, 0 },
|
||||||
|
{ "SLP", "ED.76.", 2, 0 },
|
||||||
|
{ "TST b", "ED.04b0.", 2, 0 },
|
||||||
|
{ "TST (HL)", "ED.34.", 2, 0 },
|
||||||
|
{ "TST a", "ED.64.d0.", 2, 0, "e8" },
|
||||||
|
{ "TSTIO a", "ED.74.d0.", 2, 0, "e8" },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const bval[] = { "B", "C", "D", "E",
|
||||||
|
"H", "L", "", "A", NULL };
|
||||||
|
static const char *const cval[] = { "IX", "IY", NULL };
|
||||||
|
static const char *const dval[] = { "BC", "DE", "HL", "SP", NULL };
|
||||||
|
static const char *const fval[] = { "BC", "DE", "HL", "AF", NULL };
|
||||||
|
static const char *const gval[] = { "ADD", "ADC", "SUB", "SBC",
|
||||||
|
"AND", "XOR", "OR", "CP", NULL };
|
||||||
|
static const char *const hval[] = { "INC", "DEC", NULL };
|
||||||
|
static const char *const ival[] = { "BC", "DE", "IX", "SP", NULL };
|
||||||
|
static const char *const jval[] = { "BC", "DE", "IY", "SP", NULL };
|
||||||
|
static const char *const kval[] = { "RLC", "RRC", "RL", "RR",
|
||||||
|
"SLA", "SRA", "", "SRL", NULL };
|
||||||
|
static const char *const lval[] = { "", "BIT", "RES", "SET", NULL };
|
||||||
|
static const char *const mval[] = { "NZ", "Z", "NC", "C",
|
||||||
|
"PO", "PE", "P", "M", NULL };
|
||||||
|
static const char *const nval[] = { "NZ", "Z", "NC", "C", NULL };
|
||||||
|
static const char *const pval[] = { "B", "C", "D", "E",
|
||||||
|
"IXH", "IXL", "", "A", NULL };
|
||||||
|
static const char *const qval[] = { "B", "C", "D", "E",
|
||||||
|
"IYH", "IYL", "", "A", NULL };
|
||||||
|
static const char *const nullv[] = { NULL };
|
||||||
|
|
||||||
|
static const char *const *const valtab[] = {
|
||||||
|
bval, cval, dval, dval, fval,
|
||||||
|
gval, hval, ival, jval, kval,
|
||||||
|
lval, mval, nval, nullv, pval,
|
||||||
|
qval
|
||||||
|
};
|
||||||
|
|
||||||
|
static int indval(const char *p, int disp, const char **q)
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
const char *r;
|
||||||
|
|
||||||
|
v = mreg(p, cval, &r);
|
||||||
|
if (v >= 0) {
|
||||||
|
v = (v == 0) ? 0xDD : 0xFD;
|
||||||
|
while (*r == ' ') r++;
|
||||||
|
if (!disp || *r == '+' || *r == '-') {
|
||||||
|
*q = r;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int match_z80(char c, const char *p, const char **q)
|
||||||
|
{
|
||||||
|
int v;
|
||||||
|
|
||||||
|
if (c == 'c' || c == 'e') {
|
||||||
|
v = indval(p, c == 'c', q);
|
||||||
|
} else if (c <= 'q') {
|
||||||
|
v = mreg(p, valtab[(int) (c - 'b')], q);
|
||||||
|
} else {
|
||||||
|
v = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gen_z80(int *eb, char p, const int *vs, int i, int savepc)
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
|
||||||
|
b = *eb;
|
||||||
|
switch (p) {
|
||||||
|
case 'f': b |= (vs[i] << 4); break;
|
||||||
|
case 'g': b |= (vs[i] << 6); break;
|
||||||
|
case 'i': b = (vs[i] - savepc - 2); break;
|
||||||
|
case 'j': if (s_pass > 0 && (vs[i] & ~56) != 0) {
|
||||||
|
eprint(_("invalid RST argument (%d)\n"),
|
||||||
|
vs[i]);
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
b |= vs[i];
|
||||||
|
break;
|
||||||
|
case 'k': if (s_pass > 0 && (vs[i] < 0 || vs[i] > 2)) {
|
||||||
|
eprint(_("invalid IM argument (%d)\n"),
|
||||||
|
vs[i]);
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
b = 0x46;
|
||||||
|
if (vs[i] == 1)
|
||||||
|
b = 0x56;
|
||||||
|
else if (vs[i] == 2)
|
||||||
|
b = 0x5E;
|
||||||
|
break;
|
||||||
|
case 'm': if (s_pass == 0 && !s_extended_op) {
|
||||||
|
if (vs[i] != 0 && vs[i] != 1 && vs[i] != 3) {
|
||||||
|
eprint(_("unofficial syntax\n"));
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'n': if (s_pass == 0 && !s_extended_op) {
|
||||||
|
if (vs[i] == 0 || vs[i] == 1 || vs[i] == 3) {
|
||||||
|
eprint(_("unofficial syntax\n"));
|
||||||
|
eprcol(s_pline, s_pline_ep);
|
||||||
|
newerr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*eb = b;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s_pat_char = 'b';
|
||||||
|
static int s_pat_index;
|
||||||
|
|
||||||
|
static void pat_char_rewind_z80(int c)
|
||||||
|
{
|
||||||
|
s_pat_char = c;
|
||||||
|
s_pat_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *pat_next_str_z80(void)
|
||||||
|
{
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (s_pat_char >= 'b' && s_pat_char <= 'q') {
|
||||||
|
s = valtab[(int) (s_pat_char - 'b')][s_pat_index];
|
||||||
|
if (s != NULL) {
|
||||||
|
s_pat_index++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_z80 = {
|
||||||
|
.id = "z80",
|
||||||
|
.descr = "Zilog Z80",
|
||||||
|
.matcht = s_matchtab_z80,
|
||||||
|
.matchf = match_z80,
|
||||||
|
.genf = gen_z80,
|
||||||
|
.pat_char_rewind = pat_char_rewind_z80,
|
||||||
|
.pat_next_str = pat_next_str_z80,
|
||||||
|
.mask = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct target s_target_hd64180 = {
|
||||||
|
.id = "hd64180",
|
||||||
|
.descr = "Hitachi HD64180",
|
||||||
|
.matcht = s_matchtab_z80,
|
||||||
|
.matchf = match_z80,
|
||||||
|
.genf = gen_z80,
|
||||||
|
.pat_char_rewind = pat_char_rewind_z80,
|
||||||
|
.pat_next_str = pat_next_str_z80,
|
||||||
|
.mask = 2
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user