LINKER = sdcc
-FCC = ../../../../Library/tools/fcc -O2
+FCC = ../../../../Library/tools/fcc -O2 -DTARGET_Z80
PLATFORM =
#PLATFORM = -tzx128
#define NCODE 128 /* # of characters in code buffer */
#define NINPUT 128 /* # of characters in input line */
#define NLPP 60 /* # of lines on a page */
-#define NSEGMENT 4 /* # of segments */
#define XXXX 0 /* Unused value */
/*
#define GOOD 0
#define BAD 1
+#ifdef TARGET_Z80
+
+typedef uint16_t VALUE; /* For symbol values */
+
+#define NSEGMENT 4 /* # of segments */
+
+#define ARCH OA_8080
+#define ARCH_FLAGS OA_8080_Z80
+
/*
* Types. These are used
* in both symbols and in address
#define TEQU 0x0A00 /* equ */
#define TCOND 0x0B00 /* conditional */
#define TENDC 0x0C00 /* end conditional */
+#define TSEGMENT 0x0D00 /* segments by number */
+#define TEXPORT 0x0E00 /* symbol export */
#define TNOP 0x0F00 /* nop */
#define TRST 0x1000 /* restarts */
#define TREL 0x1100 /* djnz, jr */
#define TLD 0x1C00 /* ld */
#define TCC 0x1D00 /* condition code */
#define TSUB 0x1E00 /* sub et al */
-#define TSEGMENT 0x1F00 /* segments by number */
-#define TEXPORT 0x2000 /* symbol export */
#define TNOP180 0x2100 /* Z180 immediate */
#define TTST180 0x2200 /* TST m/g/(hl) */
#define TIMMED8 0x2300 /* TSTIO m */
#define CM 7
/*
- * Segments
+ * Error message numbers: FIXME - sort general first
*/
-#define UNKNOWN -1
-#define ABSOLUTE 0
-#define CODE 1
-#define DATA 2
-#define BSS 3
+
+#define BRACKET_EXPECTED 1
+#define MISSING_COMMA 2
+#define SQUARE_EXPECTED 3
+#define PERCENT_EXPECTED 4
+#define UNEXPECTED_CHR 10
+#define PHASE_ERROR 11
+#define MULTIPLE_DEFS 12
+#define SYNTAX_ERROR 13
+#define MUST_BE_ABSOLUTE 14
+#define MISSING_DELIMITER 15
+#define INVALID_CONST 16
+#define BRA_RANGE 17
+#define CONDCODE_ONLY 18
+#define INVALID_REG 19
+#define ADDR_REQUIRED 20
+#define INVALID_ID 21
+#define REG_MUST_BE_C 22
+#define DIVIDE_BY_ZERO 23
+#define CONSTANT_RANGE 24
+#define DATA_IN_BSS 25
+#define SEGMENT_OVERFLOW 26
+#define DATA_IN_ZP 27
+#define REQUIRE_Z180 28
+
+
+
+#elif TARGET_6502
+
+typedef uint16_t VALUE; /* For symbol values */
+
+#define NSEGMENT 5 /* # of segments */
+
+#define ARCH OA_6502
+#define ARCH_FLAGS OA_6502_BCD /* For now until CPU type properly settable */
+
+
+/*
+ * Types. These are used
+ * in both symbols and in address
+ * descriptions. Observe the way the
+ * symbol flags hide in the register
+ * field of the address.
+ */
+#define TMREG 0x000F /* Register code */
+#define TMMDF 0x0001 /* Multidef */
+#define TMASG 0x0002 /* Defined by "=" */
+#define TMMODE 0xFF00 /* Mode */
+#define TMINDIR 0x8000 /* Indirect flag in mode */
+#define TPUBLIC 0x0080 /* Exported symbol */
+#define TMADDR 0x00F0 /* Addressing mode bits */
+
+#define TZP 0x0010 /* 0000 is TUSER */
+#define TACCUM 0x0020
+#define TZPX 0x0030
+#define TZPY 0x0040
+#define TABSX 0x0050
+#define TABSY 0x0060
+#define TZPX_IND 0x0070
+#define TZPY_IND 0x0080
+#define TZP_IND 0x0090
+
+
+#define TNEW 0x0000 /* Virgin */
+#define TUSER 0x0100 /* User name */
+#define TBR 0x0200 /* Byte register */
+#define TWR 0x0300 /* Word register */
+#define TSR 0x0400 /* Special register (I, R) */
+#define TDEFB 0x0500 /* defb */
+#define TDEFW 0x0600 /* defw */
+#define TDEFS 0x0700 /* defs */
+#define TDEFM 0x0800 /* defm */
+#define TORG 0x0900 /* org */
+#define TEQU 0x0A00 /* equ */
+#define TCOND 0x0B00 /* conditional */
+#define TENDC 0x0C00 /* end conditional */
+#define TSEGMENT 0x0D00 /* segments by number */
+#define TEXPORT 0x0E00 /* symbol export */
+#define TCC 0x0F00
+/* CPU specific codes */
+#define TCLASS0 0x1000 /* xxxyyy00 instructions */
+#define TCLASS1 0x1100 /* xxxyyy01 instructions */
+#define TCLASS2 0x1200 /* xxxyyy10 instructions */
+#define TCLASS2Y 0x1300 /* ditto but taking Y */
+#define TJMP 0x1400 /* JMP */
+#define TREL8 0x1500 /* Bcc */
+#define TIMPL 0x1600 /* Implicit */
+#define TBRK 0x1700 /* BRK */
+#define TJSR 0x1800 /* JSR */
+
+/*
+ * Registers.
+ */
+#define A 0
+#define X 1
+#define Y 2
/*
* Error message numbers
#define MUST_BE_ABSOLUTE 14
#define MISSING_DELIMITER 15
#define INVALID_CONST 16
-#define JR_RANGE 17
+#define BRA_RANGE 17
#define CONDCODE_ONLY 18
#define INVALID_REG 19
#define ADDR_REQUIRED 20
#define INVALID_ID 21
-#define REG_MUST_BE_C 22
+#define BADMODE 22
#define DIVIDE_BY_ZERO 23
#define CONSTANT_RANGE 24
#define DATA_IN_BSS 25
#define SEGMENT_OVERFLOW 26
-#define REQUIRE_Z180 27
+#define DATA_IN_ZP 27
-typedef uint16_t VALUE; /* For symbol values */
+
+#else
+#error "Unknown target"
+#endif
+
+/*
+ * Segments
+ */
+#define UNKNOWN -1
+#define ABSOLUTE 0
+#define CODE 1
+#define DATA 2
+#define BSS 3
+
+/*
+ * Expression priority
+ */
+
+#define LOPRI 0
+#define ADDPRI 1
+#define MULPRI 2
+#define HIPRI 3
/*
* Address description.
extern int cpu_flags;
extern void asmline(void);
-extern void asmld(void);
-extern ADDR *getldaddr(ADDR *, int *, int *, ADDR *);
-extern void outop(int, ADDR *);
extern void comma(void);
extern void istuser(ADDR *);
-extern int ccfetch(ADDR *);
extern int symhash(char *);
extern void err(char, uint8_t);
extern void uerr(char *);
extern void outflush(void);
extern void syminit(void);
+extern char *etext[];
+
#include "obj.h"
jmp_buf env;
int debug_write = 1 ;
int noobj;
-int cpu_flags = OA_8080_Z80;
+int cpu_flags = ARCH_FLAGS;
/*
* Make up a file name.
#define OPJR 0x20 /* Opcode: jr cc base */
#define OPRET 0xC0 /* Opcode: ret cc base */
+static void asmld(void);
+static ADDR *getldaddr(ADDR *ap, int *modep, int *regp, ADDR *iap);
+static void outop(int op, ADDR *ap);
+static int ccfetch(ADDR *ap);
+
static void require_z180(void)
{
if (!(cpu_flags & OA_8080_Z180)) {
}
}
+/*
+ * Read in an address
+ * descriptor, and fill in
+ * the supplied "ADDR" structure
+ * with the mode and value.
+ * Exits directly to "qerr" if
+ * there is no address field or
+ * if the syntax is bad.
+ */
+void getaddr(ADDR *ap)
+{
+ int reg;
+ int c;
+
+ if ((c=getnb()) != '(') {
+ unget(c);
+ expr1(ap, LOPRI, 0);
+ return;
+ }
+ expr1(ap, LOPRI, 1);
+ if (getnb() != ')')
+ qerr(BRACKET_EXPECTED);
+ reg = ap->a_type&TMREG;
+ switch (ap->a_type&TMMODE) {
+ case TBR:
+ if (reg != C)
+ aerr(REG_MUST_BE_C);
+ ap->a_type |= TMINDIR;
+ break;
+ case TSR:
+ case TCC:
+ aerr(ADDR_REQUIRED);
+ break;
+ case TUSER:
+ ap->a_type |= TMINDIR;
+ break;
+ case TWR:
+ if (reg == HL)
+ ap->a_type = TBR|M;
+ else if (reg==IX || reg==IY)
+ ap->a_type = TBR|reg;
+ else if (reg==AF || reg==AFPRIME)
+ aerr(INVALID_REG);
+ else
+ ap->a_type |= TMINDIR;
+ }
+}
+
+
/*
* Assemble one line.
* The line in in "ib", the "ip"
istuser(&a1);
disp = a1.a_value-dot[segment]-2;
if (disp<-128 || disp>127 || a1.a_segment != segment)
- aerr(JR_RANGE);
+ aerr(BRA_RANGE);
outab(opcode);
outab(disp);
break;
* indexing. This layer just screens out the many
* cases, and emits the correct bytes.
*/
-void asmld(void)
+static void asmld(void)
{
int mdst;
int rdst;
* pointer "ap" if indexing is required, otherwise just
* pass the "iap" through.
*/
-ADDR *getldaddr(ADDR *ap, int *modep, int *regp, ADDR *iap)
+static ADDR *getldaddr(ADDR *ap, int *modep, int *regp, ADDR *iap)
{
int mode;
int reg;
* the address mode to see if the bytes
* are needed.
*/
-void outop(int op, ADDR *ap)
+static void outop(int op, ADDR *ap)
{
int needisp;
outrab(ap);
}
-/*
- * The next character
- * in the input must be a comma
- * or it is a fatal error.
- */
-void comma(void)
-{
- if (getnb() != ',')
- qerr(MISSING_COMMA);
-}
-
-/*
- * Check if the mode of
- * an ADDR is TUSER. If not, give
- * an error.
- */
-void istuser(ADDR *ap)
-{
- if ((ap->a_type&TMMODE) != TUSER)
- aerr(ADDR_REQUIRED);
-}
-
/*
* Try to interpret an "ADDR"
* as a condition code name. Return
* be interpreted as a condition. The
* "c" condition is a pain.
*/
-int ccfetch(ADDR *ap)
+static int ccfetch(ADDR *ap)
{
if (ap->a_type == (TBR|C))
return (CC);
return (hash&HMASK);
}
-/* We may want to move this out into a a helper app at the end to dump
- errors without using assembler space */
-
-static char *etext[] = {
- "unexpected character",
- "phase error",
- "multiple definitions",
- "syntax error",
- "must be absolute",
- "missing delimiter",
- "invalid constant",
- "JR out of range",
- "condition required",
- "invalid register for operation",
- "address required",
- "invalid id",
- "must be C",
- "divide by 0",
- "constant out of range",
- "data in BSS",
- "segment overflow",
- "Z180 instruction"
-};
-
static void errstr(uint8_t code)
{
if (code < 10) {
err('q', code);
}
+/*
+ * The next character
+ * in the input must be a comma
+ * or it is a fatal error.
+ */
+void comma(void)
+{
+ if (getnb() != ',')
+ qerr(MISSING_COMMA);
+}
+
/*
* Read identifier.
* The character "c" is the first
*/
#include "as.h"
-#define LOPRI 0
-#define ADDPRI 1
-#define MULPRI 2
-#define HIPRI 3
+
/*
- * Read in an address
- * descriptor, and fill in
- * the supplied "ADDR" structure
- * with the mode and value.
- * Exits directly to "qerr" if
- * there is no address field or
- * if the syntax is bad.
+ * Check if the mode of
+ * an ADDR is TUSER. If not, give
+ * an error.
*/
-void getaddr(ADDR *ap)
+void istuser(ADDR *ap)
{
- int reg;
- int c;
-
- if ((c=getnb()) != '(') {
- unget(c);
- expr1(ap, LOPRI, 0);
- return;
- }
- expr1(ap, LOPRI, 1);
- if (getnb() != ')')
- qerr(BRACKET_EXPECTED);
- reg = ap->a_type&TMREG;
- switch (ap->a_type&TMMODE) {
- case TBR:
- if (reg != C)
- aerr(REG_MUST_BE_C);
- ap->a_type |= TMINDIR;
- break;
- case TSR:
- case TCC:
+ if ((ap->a_type&TMMODE) != TUSER)
aerr(ADDR_REQUIRED);
- break;
- case TUSER:
- ap->a_type |= TMINDIR;
- break;
- case TWR:
- if (reg == HL)
- ap->a_type = TBR|M;
- else if (reg==IX || reg==IY)
- ap->a_type = TBR|reg;
- else if (reg==AF || reg==AFPRIME)
- aerr(INVALID_REG);
- else
- ap->a_type |= TMINDIR;
- }
}
+
static void chkabsolute(ADDR *a)
{
/* Not symbols, doesn't matter */
ap->a_type = TUSER;
ap->a_value = value;
ap->a_segment = ABSOLUTE;
+ ap->a_sym = NULL;
}
-/*
- * Make sure that the
- * mode and register fields of
- * the type of the "ADDR" pointed to
- * by "ap" can participate in an addition
- * or a subtraction.
- */
-void isokaors(ADDR *ap, int paren)
-{
- int mode;
- int reg;
-
- mode = ap->a_type&TMMODE;
- if (mode == TUSER)
- return;
- if (mode==TWR && paren!=0) {
- reg = ap->a_type&TMREG;
- if (reg==IX || reg==IY)
- return;
- }
- aerr(ADDR_REQUIRED);
-}
/* Lay the file out */
for (i = 1; i < NSEGMENT; i++) {
segbase[i] = base;
- if (i != BSS) {
+ if (i != BSS && i != ZP) {
obh.o_segbase[i] = base;
base += segsize[i] + 2; /* 2 for the EOF mark */
}
obh.o_size[i] = truesize[i];
}
obh.o_magic = 0;
- obh.o_arch = OA_8080;
+ obh.o_arch = ARCH;
obh.o_flags = 0;
obh.o_cpuflags = cpu_flags;
obh.o_symbase = base;
outab(w >> 8);
}
+static void check_store_allowed(uint8_t segment, uint16_t value)
+{
+ if (segment == BSS)
+ err('b', DATA_IN_BSS);
+ if (segment == ZP)
+ err('z', DATA_IN_ZP);
+}
+
void outraw(ADDR *a)
{
if (a->a_segment != ABSOLUTE) {
- if (segment == BSS)
- err('b', DATA_IN_BSS);
+ check_store_allowed(segment, a->a_value);
if (a->a_sym == NULL) {
outbyte(REL_ESC);
outbyte((1 << 4) | REL_SIMPLE | a->a_segment);
void outab(uint8_t b)
{
/* Not allowed to put data in the BSS except zero */
- if (segment == BSS && b)
- err('b', DATA_IN_BSS);
+ check_store_allowed(segment, b);
+ /* FIXME: wrong error ?? */
if (segment == ABSOLUTE)
err('A', MUST_BE_ABSOLUTE);
outbyte(b);
{
/* FIXME: handle symbols */
if (a->a_segment != ABSOLUTE) {
- if (segment == BSS)
- err('b', DATA_IN_BSS);
+ check_store_allowed(segment, a->a_value);
if (a->a_sym == NULL) {
outbyte(REL_ESC);
outbyte((0 << 4) | REL_SIMPLE | a->a_segment);
++sp;
}
}
+
+char *etext[] = {
+ "unexpected character",
+ "phase error",
+ "multiple definitions",
+ "syntax error",
+ "must be absolute",
+ "missing delimiter",
+ "invalid constant",
+ "JR out of range",
+ "condition required",
+ "invalid register for operation",
+ "address required",
+ "invalid id",
+ "must be C",
+ "divide by 0",
+ "constant out of range",
+ "data in BSS",
+ "segment overflow",
+ "Z180 instruction"
+};
+
+/*
+ * Make sure that the
+ * mode and register fields of
+ * the type of the "ADDR" pointed to
+ * by "ap" can participate in an addition
+ * or a subtraction.
+ */
+void isokaors(ADDR *ap, int paren)
+{
+ int mode;
+ int reg;
+
+ mode = ap->a_type&TMMODE;
+ if (mode == TUSER)
+ return;
+ if (mode==TWR && paren!=0) {
+ reg = ap->a_type&TMREG;
+ if (reg==IX || reg==IY)
+ return;
+ }
+ aerr(ADDR_REQUIRED);
+}
sp = o->syment;
for (i = 0; i < nsym; i++) {
type = fgetc(fp);
- if (!(type & S_UNKNOWN) && (type & S_SEGMENT) > BSS)
+ if (!(type & S_UNKNOWN) && (type & S_SEGMENT) > ZP)
error("bad symbol");
fread(name, 16, 1, fp);
name[16] = 0;
}
base[3] = base[2] + size[2];
+ /* ZP if any is assumed to be set on input */
+
if (base[3] < base[2] || base[3] + size[3] < base[3])
error("image too large");
/* Whoopee it fits */
if (code & REL_SIMPLE) {
uint8_t seg = code & S_SEGMENT;
/* Check entry is valid */
- if (seg == ABSOLUTE || seg > BSS || size > 2)
+ if (seg == ABSOLUTE || seg > ZP || size > 2)
error("invalid reloc");
/* If we are not building an absolute then keep the tag */
if (ldmode != LD_ABSOLUTE) {
break;
case 'b':
ldmode = LD_ABSOLUTE;
+ strip = 1;
+ break;
case 'v':
printf("FuzixLD 0.1\n");
break;
uint16_t o_magic;
uint8_t o_arch;
#define OA_8080 1
+#define OA_6502 2
uint8_t o_flags;
uint16_t o_cpuflags;
#define OA_8080_Z80 1
#define OA_8080_Z280 4
#define OA_8080_R800 8
#define OA_8080_8085 16
+
+#define OA_6502_BCD 1 /* Uses BCD instructions */
+#define OA_6502_NMOS 2 /* Uses NMOS undocumented */
+#define OA_6502_65C02 4 /* Uses 65C02 */
+#define OA_6502_BITOPS 8 /* Uses extended bit operations */
+#define OA_6502_65C816 16 /* 65C816 and relatives */
+#define OA_6502_ZPAT0 32 /* Binary Assumes ZP is at 0 */
+#define OA_6502_65CE02 64 /* Does anyone really care ? */
+
uint32_t o_segbase[OSEG];
uint16_t o_size[OSEG];
uint32_t o_symbase;
#define CODE 1
#define DATA 2
#define BSS 3
+#define ZP 4