1
0
Fork 0

2048: slight VT100 changes (arrow characters, clear screen) and added uz80as as Linux assembler

This commit is contained in:
acn 2020-06-23 16:13:45 +02:00
parent 442870b868
commit 8139d51b26
44 changed files with 7392 additions and 8 deletions

View File

@ -13,12 +13,15 @@
; Compile:
;
; TASM -80 -b 2048.ASM 2048.COM
; -or-
; uz80as 2048.ASM 2048.COM
;
; Credits:
;
; Based on 2048 created by Gabriele Cirulli.
; 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>
; Slight VT100 compatibility changes by acn128 <acn@acn.wtf>
CTRL_A .EQU 1
@ -945,7 +948,8 @@ DIV16:
LD HL,0
LD B,16
DL1 SLL C ; Undoc. 0CBH, 31H
DL1 SCF
RL C
RLA
ADC HL,HL
SBC HL,DE
@ -1041,7 +1045,7 @@ POINTS .DW 0000H
.DW 4096H
.DW 8192H
INIT: .DB 12, 1BH, "[?25l", EOS
INIT: .DB 1BH, "[?25l", 1BH, "[2J", EOS
TERM: .DB 1BH, "[?25h"
RESET: .DB 1BH, "[0m", EOS
@ -1061,16 +1065,16 @@ BTMBORDER .DB 0DFH
.DB 0DFH, 0DFH, 0DFH, 0DFH, 0DFH, 0DFH, 0DFH
.DB 0DFH, EOS
MSG1: .DB 1BH, "[0m",
.DB " ", 11H, ",", 1EH, ",", 10H, ",", 1FH, " or q "
MSG1: .DB 1BH, "[0m"
.DB " <,>,^,v or q "
.DB EOS
MSG2: .DB 1BH, "[0m"
.DB " QUIT? (y/n) ",
.DB " QUIT? (y/n) "
.DB EOS
MSG3: .DB 1BH, "[0m",
MSG3: .DB 1BH, "[0m"
.DB " GAME OVER! "
.DB BEL, CR, LF, EOS
MSG4: .DB 1BH, "[0m",
MSG4: .DB 1BH, "[0m"
.DB "2048 pts"
.DB EOS

Binary file not shown.

View File

@ -19,7 +19,15 @@ When two tiles with the same number touch, they merge into one.
## 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:

67
2048/uz80as/Makefile Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,3 @@
.org $100
beep: .text "x" ; comment
.end

137
2048/uz80as/utils.c Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

63
2048/uz80as/uz80as.h Normal file
View 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
View 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
};