#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 TMUL 0x2400 /* MUL */
+#define TIO180 0x2500 /* IN0/OUT0 */
/*
* Registers.
#define INVALID_ID 21
#define REG_MUST_BE_C 22
#define DIVIDE_BY_ZERO 23
-#define INVALID_CONSTANT 24
+#define CONSTANT_RANGE 24
#define DATA_IN_BSS 25
#define SEGMENT_OVERFLOW 26
-
+#define REQUIRE_Z180 27
typedef uint16_t VALUE; /* For symbol values */
extern int debug_write;
extern char *fname;
extern int noobj;
+extern int cpu_flags;
extern void asmline(void);
extern void asmld(void);
extern void outsegment(int);
extern void outaw(uint16_t);
extern void outab(uint8_t);
+extern void outabchk(uint16_t);
extern void outraw(ADDR *);
extern void outrab(ADDR *);
extern void outeof(void);
jmp_buf env;
int debug_write = 1 ;
int noobj;
-
+int cpu_flags = OA_8080_Z80;
/*
* Make up a file name.
if (*p == '-') {
while ((c = *++p) != 0) {
switch (c) {
+ case '1':
+ cpu_flags |= OA_8080_Z180;
+ break;
default:
fprintf(stderr, "Bad option %c\n", c);
exit(BAD);
#define OPJR 0x20 /* Opcode: jr cc base */
#define OPRET 0xC0 /* Opcode: ret cc base */
+static void require_z180(void)
+{
+ if (!(cpu_flags & OA_8080_Z180)) {
+ cpu_flags |= OA_8080_Z180;
+ err('1',REQUIRE_Z180);
+ }
+}
+
/*
* Assemble one line.
* The line in in "ib", the "ip"
outab(0);
break;
+ case TNOP180:
+ require_z180();
+ /* Fall through */
case TNOP:
if ((opcode&0xFF00) != 0)
outab(opcode >> 8);
outab(OPIM|(value<<3));
break;
+ case TIMMED8:
+ require_z180();
+ getaddr(&a1);
+ istuser(&a1);
+ outab(opcode);
+ outabchk(value);
+ break;
+
+ case TIO180: /* out0 and in0 */
+ require_z180();
+ getaddr((opcode & 1) ? &a2 : &a1);
+ comma();
+ getaddr((opcode & 1) ? &a1 : &a2);
+ if ((a1.a_type&TMMODE) == TBR && a2.a_type == (TUSER|TMINDIR)) {
+ reg = a1.a_type & TMREG;
+ if (reg == M || reg == IX || reg == IY)
+ aerr(INVALID_REG);
+ outab(opcode << 8);
+ outab(opcode | (reg << 3));
+ outabchk(a2.a_value);
+ break;
+ }
+ aerr(INVALID_REG);
+
case TIO:
getaddr(opcode==OPIN ? &a1 : &a2);
comma();
getaddr(opcode==OPIN ? &a2 : &a1);
if (a1.a_type==(TBR|A) && a2.a_type==(TUSER|TMINDIR)) {
outab(opcode);
- outab(a2.a_value);
+ outabchk(a2.a_value);
break;
}
if ((a1.a_type&TMMODE)==TBR && a2.a_type==(TBR|TMINDIR|C)) {
aerr(INVALID_REG);
break;
+ case TMUL:
+ getaddr(&a1);
+ if ((a1.a_type & TMMODE) == TWR) {
+ reg = a1.a_type & TMREG;
+ switch(reg) {
+ case IX:
+ case IY:
+ case AF:
+ case AFPRIME:
+ aerr(INVALID_REG);
+ break;
+ }
+ outab(opcode >> 8);
+ outab(opcode|(reg << 3));
+ break;
+ }
+ aerr(INVALID_REG);
+ break;
+
case TSUB:
getaddr(&a1);
if (a1.a_type == TUSER) {
outab(opcode | OPSUBI);
- outab(a1.a_value);
+ outabchk(a1.a_value);
break;
}
if ((a1.a_type&TMMODE) == TBR) {
if (a1.a_type == (TBR|A)) {
if (a2.a_type == TUSER) {
outab(opcode | OPSUBI);
- outab(a2.a_value);
+ outabchk(a2.a_value);
break;
}
if ((a2.a_type&TMMODE) == TBR) {
if (mdst == TBR) {
outab(0x06|(rdst<<3)); /* ld r8,#n */
if (indexap != NULL)
- outab(indexap->a_value);
+ outrab(indexap);
outrab(&src);
return;
}
"invalid id",
"must be C",
"divide by 0",
- "invalid constant",
+ "constant out of range",
"data in BSS",
- "segment overflow"
+ "segment overflow",
+ "Z180 instruction"
};
static void errstr(uint8_t code)
else if (c>='a' && c<='f')
c -= 'a'-10;
else
- err('n', INVALID_CONSTANT);
+ err('n', INVALID_CONST);
if (c >= radix)
- err('n', INVALID_CONSTANT);
+ err('n', INVALID_CONST);
value = radix*value + c;
}
ap->a_type = TUSER;
obh.o_size[i] = truesize[i];
}
obh.o_magic = 0;
- obh.o_arch = OA_Z80;
+ obh.o_arch = OA_8080;
obh.o_flags = 0;
- /* Will need changing if we add .Z180 and the Z180 ops */
- obh.o_cpuflags = 0;
+ obh.o_cpuflags = cpu_flags;
obh.o_symbase = base;
obh.o_dbgbase = 0; /* for now */
/* Number the symbols for output */
err('o', SEGMENT_OVERFLOW);
}
+void outabchk(uint16_t b)
+{
+ if (b > 255)
+ err('o', CONSTANT_RANGE);
+ outab(b);
+}
+
void outrab(ADDR *a)
{
/* FIXME: handle symbols */
outbyte(a->a_sym->s_number >> 8);
}
}
- outab(a->a_value);
+ outabchk(a->a_value);
}
static void putsymbol(SYM *s, FILE *ofp)
{ 0, "xor", TSUB, 0x00A8 },
{ 0, "or", TSUB, 0x00B0 },
{ 0, "cp", TSUB, 0x00B8 },
+ /* Z180 */
+ { 0, "slp", TNOP180, 0xED76 },
+ { 0, "otim", TNOP180, 0xED83 },
+ { 0, "otimr", TNOP180, 0xED93 },
+ { 0, "otdm", TNOP180, 0xED8B },
+ { 0, "otdmr", TNOP180, 0xED9B },
+ { 0, "tst", TTST180, 0xED04 },
+ { 0, "tstio", TIMMED8, 0xED74 },
+ { 0, "mlt", TMUL, 0xED4C },
+ { 0, "in0", TIO180, 0xED00 },
+ { 0, "out0", TIO180, 0xED01 },
+ /* The joys of ld */
{ 0, "ld", TLD, XXXX }
};