From 4f33308d2a72b2a2ad79da416b2dbcf3aef1e16f Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 2 Nov 2017 18:17:11 +0000 Subject: [PATCH] as: incomplete 6809 code Doesn't build yet but I figure we might as well make all of our platforms able to use the same object file format, linker, library tools for self hosting work. --- Applications/MWC/cmd/asz80/as.h | 103 +++++ Applications/MWC/cmd/asz80/as1-6809.c | 527 ++++++++++++++++++++++++++ Applications/MWC/cmd/asz80/as6-6809.c | 218 +++++++++++ 3 files changed, 848 insertions(+) create mode 100644 Applications/MWC/cmd/asz80/as1-6809.c create mode 100644 Applications/MWC/cmd/asz80/as6-6809.c diff --git a/Applications/MWC/cmd/asz80/as.h b/Applications/MWC/cmd/asz80/as.h index e562ed83..1d37c480 100644 --- a/Applications/MWC/cmd/asz80/as.h +++ b/Applications/MWC/cmd/asz80/as.h @@ -345,6 +345,109 @@ typedef uint32_t VALUE; /* For symbol values */ #define BAD_PCREL BRA_RANGE #define SEGMENT_CLASH 31 +#elif TARGET_6809 + +typedef uint16_t VALUE; /* For symbol values */ + +#define NSEGMENT 4 /* # of segments */ + +#define ARCH OA_6809 +#define ARCH_FLAGS 0 + +#define TARGET_BIGENDIAN +#define TARGET_USES_SQUARE + +/* + * 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 0x007F /* 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 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 */ +/* CPU specific codes */ +#define THI 0x1100 /* all modes opcodes 0x80+ */ +#define THIW 0x1200 /* ditto word mode */ +#define THINOIMM 0x1300 /* ditto byte no immediate */ +#define THIWNOIMM 0x1400 /* ditto word no immediate */ +#define TIMM8 0x1500 /* 8bit immediate only */ +#define TEXG 0x1600 /* registers as 8bit immediate */ +#define TPUSH 0x1700 /* register mask as 8bit immediate */ +#define TIMP 0x1800 /* implied by instruction */ +#define TLO 0x1900 /* low instructions with some modes */ +#define TLEA 0x1A00 /* lea */ +#define TBR 0x1B00 /* branch */ +#define TLBR 0x1C00 /* long branch */ + +#define TAIMM 0x0000 /* #x :immediate mode 8bit */ +#define TADIR 0x0010 /* dp:x */ +#define TAIND 0x0020 /* Indexed postbyte forms */ +#define TAEXT 0x0030 /* xx : extended addressing */ + +/* + * Registers. + */ +#define A 0 /* re-arrange to match bit patterns */ +#define B 1 +#define DP 2 +#define CC 3 +#define D 4 +#define U 5 +#define X 6 +#define Y 7 +#define S 8 +#define PCR 9 + +/* + * Error message numbers: FIXME - sort general first + */ + +#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 +#define SEGMENT_CLASH 29 + #else #error "Unknown target" #endif diff --git a/Applications/MWC/cmd/asz80/as1-6809.c b/Applications/MWC/cmd/asz80/as1-6809.c new file mode 100644 index 00000000..7e088823 --- /dev/null +++ b/Applications/MWC/cmd/asz80/as1-6809.c @@ -0,0 +1,527 @@ +/* + * Z-80 assembler. + * Assemble one line of input. + * Knows all the dirt. + */ +#include "as.h" + + +/* + * Deal with the syntactic mess 6809 assembler has + * + * In some cases (JSR JMP and definitions - eg .word) + * $ABCD means a constant everywhere else that is #ABCD + */ + +static void constify(ADDR *ap) +{ + if ((ap->a_type & TMMODE) == (TUSER|TMINDIR)) + ap->a_type = TUSER; +} + +static void constant_to_dp(ADDR *ap) +{ + if (ap->a_segment != ABSOLUTE || ap->a_sym) + return; + /* FIMXE: need to support .setdp */ + if (ap->a_value > 255) + return; + ap->a_segment = ZP; + return; +} + +/* + * 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. + */ +uint8_t getaddr(ADDR *ap, uint8_t *extbyte, uint8_t size) +{ + int c; + ADDR tmp; + ADDR off; + + ap->a_type = 0; + ap->a_flags = 0; + ap->a_sym = NULL; + + c = getnb(); + + /* Immediate */ + if (c == '#') { + c = getnb(); + if (c == '<') + ap->a_flags |= A_LOW; + else if (c == '>') + ap->a_flags |= A_HIGH; + else + unget(c); + expr1(ap, LOPRI, 0); + istuser(ap); + return size; + } + + /* [xx] */ + if (c == '[') { + getaddr_sub(ap, extbyte, size); + c = getnb(); + if (c != ']') + err('s', SQUARE_EXPECTED); + if ((ap->ap_type & TADDR) == TAEXT) { + if (!(*extbyte & 0x80)) { + /* Convert from 5bit to 8bit */ + size = 1; + *extbyte &= 0x60; + *extbyte |= 0x88; /* 8 bit offset */ + } + c = (*extbyte & 0x9F); + /* Not allowed to indirect a - / + just -- and ++ */ + if (c == 0x80 || c == 0x82) + err('a', INVALID_INDIR); + *extbyte |= 0x10; + ap->a_type |= TAEXT|TMINDIR; + return size; + } + return; + } + unget(c); + getaddr_sub(ap, extbyte, size, &off); +} + +/* + * Perform the main work of decoding modes that can be direct or + * indrected + */ +uint8_t getaddr_sub(ADDR *ap, uint8_t *extbyte, ADDR *off) +{ + int reg; + int c; + ADDR tmp; + ADDR off; + int index = 0; + + /* ,foo is the same as 0,foo */ + off.a_type = TUSER; + off.a_value = 0; + + /* We need to decode + + reg, reg + offset,reg + address + dp:address + autodec(2) reg + reg autoinc(2) + offset,pc + */ + c = getnb(); + if (c != ',') { + /* The left of the comma can be a constant or A/B/D register */ + unget(c); + expr1(&off, LOPRI, 0); + ireg = reg_expr(ap); + if (reg != -1) { + if (ireg != A || ireg != B || ireg != D) + error(INVALID_REGISTER); + index = 2; + /* We are doing reg,index */ + } else { /* Must be a constant */ + istuser(&off); + if (ap->a_value != 0) + index = 1; + c = get(); + if (c != ',') { + /* Extended or DP addressing - lda foo */ + unget(c); + /* FIXME figure out extbyte etc */ + ap->a_type = TUSER; + ap->a_value = off.a_value; + ap->a_sym = off.a_sym; + ap->a_segment = off.a_segment; + return; + } + unget(c); + } + comma(); + } + + /* Afer the comma should be a register but it may have a - -- prefix */ + c = getnb(); + if (c == '-') { + if (index) + aerr(BAD_MODE); + extop = 0x82; + c = get(); + if (c == '-') + extop = 0x83; + else + unget(c); + } else + unget(c); + + /* Compute the expression that follows. Should be a register */ + expr1(ap, LOPRI, 1); + + reg = reg_expr(ap); + if (reg == -1) + aerr(BAD_MODE); + c = get(); + if (c == '+') { + if (extop || index) + aerr(BAD_MODE); + c = get(); + extop = 0x81; + if (c == '+') + extop = 0x80; + else + unget(c); + } else + unget(c); + + if (index == 2) { + /* encode a/b/d, reg */ + switch(ireg) + { + case A: + *extbyte = 0x86; + break; + case B: + *extbyte = 0x85; + break; + case D: + *extbyte = 0x8B; + break; + default: + qerr(SYNTAX_ERROR); + } + *extbyte |= toindex(reg); + return 0; + } + if (extop) { + /* No offset with increment/decrement */ + if (index) + aerr(BAD_MDOE); + /* --/-/+/++ */ + *extbyte = extop | toindex(reg); + return 0; + } + /* Simple offset. Only it's not so simple because it might be a + symbol that is external. In which case we must assume the worst + FIXME: check this logic works for TNEW */ + + if (ap->a_segment != ABSOLUTE) + off = ap->a_value - dot[segment]; + + /* Is this a relocation that we can compute te value of ? */ + if (ap->a_sym == NULL || (ap->a_type & TMMODE) == TUSER) { + /* Is it within our segment or absolute */ + if (ap->a_segment == segment || ap->a_segment == ABSOLUTE) { + /* In which case we can actually use the short forms */ + if (reg != PCR && offset5bit(off)) { + *extbyte = offset5bit(off)|toindex(reg); + return 0; + } + if (offset8bit(off)) { + if (reg == PCR) + *extbyte = 0x8C; + else + *extbyte = 0x88 | toindex(reg); + return 1; + } + } + } + /* Otherwise we use the long form to be safe for linking */ + if (reg == PCR) + *extbyte = 0x8D; + else + *extbyte = 0x89; + return 2; +} + +/* + * Assemble one line. + * The line in in "ib", the "ip" + * scans along it. The code is written + * right out. + */ +void asmline(void) +{ + SYM *sp; + int c; + int opcode; + int disp; + int reg; + int srcreg; + int cc; + VALUE value; + int delim; + SYM *sp1; + char id[NCPS]; + char id1[NCPS]; + ADDR a1; + ADDR a2; + int user; + +loop: + if ((c=getnb())=='\n' || c==';') + return; + if (isalpha(c) == 0 && c != '_' && c != '.') + qerr(UNEXPECTED_CHR); + getid(id, c); + if ((c=getnb()) == ':') { + sp = lookup(id, uhash, 1); + if (pass == 0) { + if ((sp->s_type&TMMODE) != TNEW + && (sp->s_type&TMASG) == 0) + sp->s_type |= TMMDF; + sp->s_type &= ~TMMODE; + sp->s_type |= TUSER; + sp->s_value = dot[segment]; + sp->s_segment = segment; + } else { + if ((sp->s_type&TMMDF) != 0) + err('m', MULTIPLE_DEFS); + if (sp->s_value != dot[segment]) + err('p', PHASE_ERROR); + } + goto loop; + } + /* + * If the first token is an + * id and not an operation code, + * assume that it is the name in front + * of an "equ" assembler directive. + */ + if ((sp=lookup(id, phash, 0)) == NULL) { + getid(id1, c); + if ((sp1=lookup(id1, phash, 0)) == NULL + || (sp1->s_type&TMMODE) != TEQU) { + err('o', SYNTAX_ERROR); + return; + } + getaddr(&a1); + constify(&a1); + istuser(&a1); + sp = lookup(id, uhash, 1); + if ((sp->s_type&TMMODE) != TNEW + && (sp->s_type&TMASG) == 0) + err('m', MULTIPLE_DEFS); + sp->s_type &= ~(TMMODE|TPUBLIC); + sp->s_type |= TUSER|TMASG; + sp->s_value = a1.a_value; + sp->s_segment = a1.a_segment; + /* FIXME: review .equ to an external symbol/offset and + what should happen */ + goto loop; + } + unget(c); + opcode = sp->s_value; + switch (sp->s_type&TMMODE) { + case TORG: + getaddr(&a1); + constify(&a1); + istuser(&a1); + if (a1.a_segment != ABSOLUTE) + qerr(MUST_BE_ABSOLUTE); + segment = ABSOLUTE; + dot[segment] = a1.a_value; + /* Tell the binary generator we've got a new absolute + segment. */ + outabsolute(a1.a_value); + break; + + case TEXPORT: + getid(id, getnb()); + sp = lookup(id, uhash, 1); + sp->s_type |= TPUBLIC; + break; + /* .code etc */ + + case TSEGMENT: + segment = sp->s_value; + /* Tell the binary generator about a segment switch to a non + absolute segnent */ + outsegment(segment); + break; + + case TDEFB: + do { + getaddr(&a1); + constify(&a1); + istuser(&a1); + outrab(&a1); + } while ((c=getnb()) == ','); + unget(c); + break; + + case TDEFW: + do { + getaddr(&a1); + constify(&a1); + istuser(&a1); + outraw(&a1); + } while ((c=getnb()) == ','); + unget(c); + break; + + case TDEFM: + if ((delim=getnb()) == '\n') + qerr(MISSING_DELIMITER); + while ((c=get()) != delim) { + if (c == '\n') + qerr(MISSING_DELIMITER); + outab(c); + } + break; + + case TDEFS: + getaddr(&a1); + constify(&a1); + istuser(&a1); + /* Write out the bytes. The BSS will deal with the rest */ + for (value = 0 ; value < a1.a_value; value++) + outab(0); + break; + + case TBRA: + /* FIXME: sort out symbols here and on 6502 */ + getaddr(&a1); + disp = a1.a_value-dot[segment]-2; + if (disp<-128 || disp>127 || a1.a_segment != segment) + aerr(BRA_RANGE); + outab(opcode); + outab(disp); + break; + + case TLBRA: + /* FIXME: support this with symbols */ + getaddr(&a1); + disp = a1.a_value-dot[segment]-2; + if (disp<-32768 || disp> 32767 || a1.a_segment != segment) + aerr(LBRA_RANGE); + outab(opcode); + outab(disp); + break; + + case TIMPL: + if (opcode >> 8) + outab(opcode >> 8); + outab(opcode); + break; + + case TLO: + size = getaddr(&a1, &ext); + + if (opcode >> 8) + outab(opcode >> 8); + switch(a1.a_type & TMADDR) { + case 0: + aerr(NO_IMMEDIATE); + break; + case TEXT: + outab(opcode + 0x70); + outraw(&a1); + break; + case TDP: + outab(opcode); + outrab(&a1); + break; + case TIND: + outab(opcode + 0x60); + outrab(ext); + if (size == 1) + outrab(&a1); + else if (size == 2) + outraw(&a1); + } + break; + case TLEA: + size = getaddr(&a1, &ext); + if ((a1.a1_type & TMADDR) != TEXT) + aerr(MUST_BE_INDEXED); + outab(opcode); + outab(ext); + if (size == 1) + outrabs(a1); + else if (size == 2) + outraws(a1); + break; + case THI: + case THIW: + case THINOIMM: + case THIWNOIMM: + size = getaddr(&a1, &ext); + mode = a1.a1_type & TMADDR; + + if (opcode >> 8) + outab(opcode >> 8); + + switch(mode) { + case 0: + outab(opcode); + switch(sp->s_type & TMMODE) { + case THIW: + outraw(&a1); + break; + case THI: + outrab(&a1); + break; + default: + aerr(NO_IMMEDIATE); + } + break; + case TEXT: + outab(opcode + 0x30); + outraw(&a1); + break; + case TDP: + outab(opcode + 0x10); + outrab(&a1); + break; + case TIND: + outab(opcode + 0x20); + outrab(ext); + if (size == 1) + outrabs(&a1); + else if (size == 2) + outraws(&a1); + } + break; + + case TIMM8: + getaddr(&a1); + istuser(&a1); + if (a1.a_value > 255) + aerr(CONSTANT_TOO_LARGE); + if (opcode >> 8) + outab(opcode >> 8); + outab(opcode); + outrab(a1); + break; + + case TEXG: + r1 = get_register(); + comma(); + r2 = get_register(); + opcode |= ???? + outab(opcode); + break; + + case TPUSH: + mask |= 1 << get_register_mask(); + while((c = getnb()) == ',') { + mask |= 1 << get_register_mask(); + unget(c); + outab(opcde); + outab(mask); + break; + + default: + aerr(SYNTAX_ERROR); + } + goto loop; +} diff --git a/Applications/MWC/cmd/asz80/as6-6809.c b/Applications/MWC/cmd/asz80/as6-6809.c new file mode 100644 index 00000000..ab3e0d10 --- /dev/null +++ b/Applications/MWC/cmd/asz80/as6-6809.c @@ -0,0 +1,218 @@ +/* + * Z-80 assembler. + * Basic symbol tables. + * Contain all of the instructions + * and register names. + */ +#include "as.h" + +/* + * This array of symbol nodes + * make up the basic symbol table. + * The "syminit" routine links these + * nodes into the builtin symbol hash + * table at start-up time. + */ +SYM sym[] = { + { 0, "a", TBR, A }, + { 0, "b", TBR, B }, + { 0, "dp", TBR, DP }, + { 0, "cc", TBR, CC }, + { 0, "d", TWR, D }, + { 0, "u", TWR, U }, + { 0, "x", TWR, X }, + { 0, "y", TWR, Y }, + { 0, "s", TWR, S }, + { 0, "pc", TWR, PCR }, + { 0, "pcr", TWR, PCR }, + { 0, "defw", TDEFW, XXXX }, + { 0, "defs", TDEFS, XXXX }, + { 0, "defm", TDEFM, XXXX }, + { 0, "org", TORG, XXXX }, + { 0, "equ", TEQU, XXXX }, + { 0, "export", TEXPORT, XXXX }, + { 0, ".byte", TDEFB, XXXX }, + { 0, ".word", TDEFW, XXXX }, + { 0, ".blkb", TDEFS, XXXX }, + { 0, ".ascii", TDEFM, XXXX }, + { 0, ".org", TORG, XXXX }, + { 0, ".equ", TEQU, XXXX }, + { 0, ".export", TEXPORT, XXXX }, + { 0, "cond", TCOND, XXXX }, + { 0, "endc", TENDC, XXXX }, + { 0, "code", TSEGMENT, CODE }, + { 0, "data", TSEGMENT, DATA }, + { 0, "bss", TSEGMENT, BSS }, + { 0, ".code", TSEGMENT, CODE }, + { 0, ".data", TSEGMENT, DATA }, + { 0, ".bss", TSEGMENT, BSS }, + { 0, ".dp", TSEGMENT, ZP }, + { 0, "adca", THI, 0x89 }, + { 0, "adcb", THI, 0xC9 }, + { 0, "adda", THI, 0x8B }, + { 0, "addb", THI, 0xCB }, + { 0, "addd", THIW, 0xC3 }, + { 0, "anda", THI, 0x84 }, + { 0, "andb", THI, 0xC4 }, + { 0, "adcc", TIMM8, 0x1C }, + { 0, "asla", TIMP, 0x48 }, + { 0, "aslb", TIMP, 0x58 }, + { 0, "asl", TLO, 0x08 }, + { 0, "asra", TIMP, 0x47 }, + { 0, "asrb", TIMP, 0x57 }, + { 0, "asr", TLO, 0x07 }, + /* TODO Bxx */ + { 0, "bita", THI, 0x85 }, + { 0, "bitb", THI, 0xC5 }, + { 0, "clra", TIMP, 0x4F }, + { 0, "clrb", TIMP, 0x5F }, + { 0, "clr", TLO, 0x0F }, + { 0, "cmpa", THI, 0x81 }, + { 0, "cmpb", THI, 0xC1 }, + { 0, "cmpd", THIW, 0x1083 }, + { 0, "cmps", THIW, 0x118C }, + { 0, "cmpu", THIW, 0x1183 }, + { 0, "cmpx", THIW, 0x8C }, + { 0, "cmpy", THIW, 0x108C }, + { 0, "coma", TIMP, 0x43 }, + { 0, "comb", TIMP, 0x53 }, + { 0, "com", TLO, 0x03 }, + { 0, "cwai", TIMM8, 0x3C }, + { 0, "daa", TIMP, 0x19 }, + { 0, "deca", TIMP, 0x4A }, + { 0, "decb", TIMP, 0x5A }, + { 0, "dec", TLO, 0x08 }, + { 0, "eora", THI, 0x88 }, + { 0, "eorb", THI, 0xC8 }, + { 0, "exg", TEXG, 0x1E }, + { 0, "inca", TIMP, 0x4C }, + { 0, "incb", TIMP, 0x5C }, + { 0, "inc", TLO, 0x0C }, + { 0, "jmp", TLO, 0x0E }, + { 0, "jsr", TLO, 0x9D }, + /* TODO: lbxx */ + { 0, "lda", THI, 0x86 }, + { 0, "ldb", THI, 0xC6 }, + { 0, "ldd", THIW, 0xCC }, + { 0, "lds", THIW, 0x10CE }, + { 0, "ldu", THIW, 0xCE }, + { 0, "ldx", THIW, 0x8E }, + { 0, "ldy", THIW, 0x108E }, + { 0, "leas", TLEA, 0x32 }, + { 0, "leau", TLEA, 0x33 }, + { 0, "leax", TLEA, 0x30 }, + { 0, "leay", TLEA, 0x31 }, + { 0, "lsla", TIMP, 0x48 }, + { 0, "lslb", TIMP, 0x49 }, + { 0 "lsl", TLO, 0x08 }, + { 0, "lsra", TIMP, 0x44 }, + { 0, "lsrb", TIMP, 0x54 }, + { 0, "lsr", TLO, 0x04 }, + { 0, "mul", TIMP, 0x3D }, + { 0, "nega", TIMP, 0x40 }, + { 0, "negb", TIMP, 0x50 }, + { 0, "neg", TLO, 0x00 }, + { 0, "nop", TIMP, 0x12 }, + { 0, "ora", THI, 0x8A }, + { 0, "orb", THI, 0xCA }, + { 0, "orcc", TIMM8, 0x1A }, + { 0, "pshs", TPUSH, 0x34 }, + { 0, "pshu", TPUSH, 0x36 }, + { 0, "puls", TPUSH, 0x35 }, + { 0, "pulu", TPUSH, 0x37 }, + { 0, "rola", TIMP, 0x49 }, + { 0, "rolb", TIMP, 0x59 }, + { 0, "rol", TLO, 0x09 }, + { 0, "rora", TIMP, 0x46 }, + { 0, "rorb", TIMP, 0x56 }, + { 0, "ror", TLO, 0x06 }, + { 0, "rti", TIMP, 0x3B }, + { 0, "rts", TIMP, 0x39 }, + { 0, "sbca", THI, 0x82 }, + { 0, "sbcb", THI, 0xC2 }, + { 0, "sex", TIMP, 0x1D }, + { 0, "sta", THINOIMM, 0x87 }, + { 0, "stb", THINOIMM, 0xC7 }, + { 0, "std", THIWNOIMM, 0xCD }, + { 0, "sts", THIWNOIMM, 0x10CF }, + { 0, "stu", THIWNOIMM, 0xCF }, + { 0, "stx", THIWNOIMM, 0x8F }, + { 0, "sty", THIWNOIMM, 0x108F }, + { 0, "suba", THI, 0x80 }, + { 0, "subb", THI, 0xC0 }, + { 0, "subd", THIW, 0x83 }, + { 0, "swi", TIMP, 0x3F }, + { 0, "swi2", TIMP, 0x103F }, + { 0, "swi3", TIMP, 0x113F }, + { 0, "sync", TIMP, 0x13 }, + { 0, "tfr", TEXG,/*check*/ 0x1F }, + { 0, "tsta", TIMP, 0x4D }, + { 0, "tstb", TIMP, 0x5D }, + { 0 "tst", TLO, 0x0D }, +}; + +/* + * Set up the symbol table. + * Sweep through the initializations + * of the "phash", and link them into the + * buckets. Because it is here, a + * "sizeof" works. + */ +void syminit(void) +{ + SYM *sp; + int hash; + + sp = &sym[0]; + while (sp < &sym[sizeof(sym)/sizeof(SYM)]) { + hash = symhash(sp->s_id); + sp->s_fp = phash[hash]; + phash[hash] = sp; + ++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", + "segment conflict" +}; + +/* + * 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); +} -- 2.34.1