/* V9t9: the TI Emulator! v6.0 Source Copyright (c) 1996 by Edward Swartz */ /* TI-99/4A Assembler For now, file formats are ordinary text/binary files. */ extern unsigned int _stklen = 32768; #if defined(__BORLANDC__) #include #else #include #endif #include #include #include #include #if defined(__GNUC__) || defined(__MWERKS__) char * strupr(char *s) { char *p = s; while (*p) { if (islower(*p)) *p = toupper(*p); p++; } return s; } #endif #if defined(__MWERKS__) void swab(unsigned char *a, unsigned char *b, int bytes) { while (bytes > 0) { unsigned char t = a[0], u = a[1]; b[0] = u; b[1] = t; a += 2; b += 2; bytes -= 2; } } #endif #include "expr.h" //typedef unsigned int word; //typedef unsigned char byte; // current input filename char inname[256]; // list file FILE *list; int pass; int errors; int warnings; #define DEBUG if (1) struct symbolrec { char name[16]; int line; int addr; struct symbolrec *left, *right; } *symtable; int assemble(char *filename); void breakup(char *line, char *label, char *inst, char *src, char *dest); char *skipspaces(char *line); char *copychars(char *from, char *to, int max); void dolisting(word start, word end, char *line, struct symbolrec *sym); int doaline(char *line, struct symbolrec **sym); int addsymbol(char *name, int defining, struct symbolrec **nw); int decode(char **pline, struct symbolrec *label, word orgaddr, byte optype); int getregister(char **pline, word orgaddr, byte start); int getjump(char **pline, word orgaddr); int getgen(char **pline, word orgaddr, byte tbit, byte bit); int getcnt(char **pline, word orgaddr, byte bit, char *type); int getbit(char **pline, word orgaddr); int getnumber(char **pline, word orgaddr, long *ret, byte * neither); int getexpr(char **pline, word orgaddr, byte size, long *ret); word addr; byte memory[0x8000]; char em[256]; // error message struct opcoderec { char name[6]; word opcode; byte src; byte dst; }; int opsort(struct opcoderec *a, struct opcoderec *b) { return (strcmp(a->name, b->name)); } static enum { NIL, REG, REGH, REG4, GEN, GENH, JMP, BIT, CNT, CNTH, BYT, WRD, DWD, EQU, IMM, XOP, BSS, AORG, INC, NIMM, AGAIN, EVEN }; static struct opcoderec opcodes[] = { {"DB", 0x0000, BYT, AGAIN}, {"BYTE", 0x0000, BYT, AGAIN}, {"TEXT", 0x0000, BYT, AGAIN}, {"DW", 0x0000, WRD, AGAIN}, {"DATA", 0x0000, WRD, AGAIN}, {"DD", 0x0000, DWD, AGAIN}, {"EQU", 0x0000, EQU, NIL}, {"BSS", 0x0000, BSS, NIL}, {"AORG", 0x0000, AORG, NIL}, {"INCL", 0x0000, INC, NIL}, {"EVEN", 0x0000, EVEN, NIL}, {"LI", 0x0200, REG, IMM}, {"AI", 0x0220, REG, IMM}, {"SI", 0x0220, REG, NIMM}, {"ANDI", 0x0240, REG, IMM}, {"ORI", 0x0260, REG, IMM}, {"CI", 0x0280, REG, IMM}, {"STWP", 0x02a0, REG, NIL}, {"STST", 0x02c0, REG, NIL}, {"LWPI", 0x02e0, IMM, NIL}, {"LIMI", 0x0300, IMM, NIL}, {"IDLE", 0x0340, NIL, NIL}, {"RSET", 0x0360, NIL, NIL}, {"RTWP", 0x0380, NIL, NIL}, {"CKON", 0x03a0, NIL, NIL}, {"CKOF", 0x03c0, NIL, NIL}, {"LREX", 0x03e0, NIL, NIL}, {"BLWP", 0x0400, GEN, NIL}, {"B", 0x0440, GEN, NIL}, {"RT", 0x045B, NIL, NIL}, {"X", 0x0480, GEN, NIL}, {"CLR", 0x04c0, GEN, NIL}, {"NEG", 0x0500, GEN, NIL}, {"INV", 0x0540, GEN, NIL}, {"INC", 0x0580, GEN, NIL}, {"INCT", 0x05c0, GEN, NIL}, {"DEC", 0x0600, GEN, NIL}, {"DECT", 0x0640, GEN, NIL}, {"BL", 0x0680, GEN, NIL}, {"SWPB", 0x06c0, GEN, NIL}, {"SETO", 0x0700, GEN, NIL}, {"ABS", 0x0740, GEN, NIL}, {"SRA", 0x0800, REG, CNT}, {"SRL", 0x0900, REG, CNT}, {"SLA", 0x0a00, REG, CNT}, {"SRC", 0x0b00, REG, CNT}, // v9t9 internal opcodes {"DSR", 0x0c00, NIL, NIL}, {"KEY", 0x0d80, NIL, NIL}, {"EMIT", 0x0dc0, NIL, NIL}, // R0 implicit {"DBG", 0x0de0, NIL, NIL}, {"-DBG", 0x0de1, NIL, NIL}, {"JMP", 0x1000, JMP, NIL}, {"NOP", 0x1000, NIL, NIL}, {"JLT", 0x1100, JMP, NIL}, {"JLE", 0x1200, JMP, NIL}, {"JBE", 0x1200, JMP, NIL}, {"JEQ", 0x1300, JMP, NIL}, {"JE", 0x1300, JMP, NIL}, {"JHE", 0x1400, JMP, NIL}, {"JAE", 0x1400, JMP, NIL}, {"JGT", 0x1500, JMP, NIL}, {"JG", 0x1500, JMP, NIL}, {"JNE", 0x1600, JMP, NIL}, {"JNC", 0x1700, JMP, NIL}, {"JOC", 0x1800, JMP, NIL}, {"JC", 0x1800, JMP, NIL}, {"JNO", 0x1900, JMP, NIL}, {"JL", 0x1A00, JMP, NIL}, {"JB", 0x1A00, JMP, NIL}, {"JH", 0x1B00, JMP, NIL}, {"JA", 0x1B00, JMP, NIL}, {"JOP", 0x1C00, JMP, NIL}, {"SBO", 0x1d00, BIT, NIL}, {"SBZ", 0x1e00, BIT, NIL}, {"TB", 0x1f00, BIT, NIL}, {"COC", 0x2000, GEN, REGH}, {"CZC", 0x2400, GEN, REGH}, {"XOR", 0x2800, GEN, REGH}, {"XOP", 0x2c00, GEN, XOP}, {"LDCR", 0x3000, GEN, CNTH}, {"STCR", 0x3400, GEN, CNTH}, {"MPY", 0x3800, GEN, REGH}, {"MUL", 0x3800, GEN, REGH}, {"DIV", 0x3c00, GEN, REGH}, {"SZC", 0x4000, GEN, GENH}, {"SZCB", 0x5000, GEN, GENH}, {"S", 0x6000, GEN, GENH}, {"SB", 0x7000, GEN, GENH}, {"C", 0x8000, GEN, GENH}, {"CB", 0x9000, GEN, GENH}, {"A", 0xa000, GEN, GENH}, {"AB", 0xb000, GEN, GENH}, {"MOV", 0xc000, GEN, GENH}, {"MOVB", 0xd000, GEN, GENH}, {"SOC", 0xe000, GEN, GENH}, {"SOCB", 0xf000, GEN, GENH}, {"", 0x0000, NIL, NIL} }; #define OPCOUNT (sizeof(opcodes)/sizeof(opcodes[0])) typedef int sorter(const void *, const void *); enum { A_rom = 1 << (0x0000 / 0x2000), A_module = 1 << (0x6000 / 0x2000), A_grom = 7 << (0x0000 / 0x2000), A_dsr = 1 << (0x4000 / 0x2000) } addrmask, warnmask; #define BANKUSED(a) (1 << ((a) / 0x2000)) #define INRANGE(a) (addrmask & BANKUSED(a)) int main(int argc, char *argv[]) { int ap; char *romout = 0, *modout = 0, *dsrout = 0, *gromout = 0; char *listout = 0; if (argc < 3) { printf ("TIASM [-r ] [-m ]\n" "[-d ] [-g ] []\n" "\n" "-r saves the 8k memory block at >0000.\n" "-m saves the 8k memory block at >6000.\n" "-d saves the 8k memory block at >4000.\n" "-g saves the 24k memory block at >0000. This can only be used with -m.\n"); return 1; } addrmask = 0; warnmask = 0; ap = 1; strcpy(inname, argv[ap++]); while (ap < argc) { if (strcmp(argv[ap], "-r") == 0) { romout = argv[++ap]; if (!(addrmask & A_rom)) addrmask |= A_rom; else { printf("-r specified twice, or -g also specified"); return 1; } } else if (strcmp(argv[ap], "-m") == 0) { modout = argv[++ap]; if (!(addrmask & A_module)) addrmask |= A_module; else { printf("-m specified twice"); return 1; } } else if (strcmp(argv[ap], "-d") == 0) { dsrout = argv[++ap]; if (!(addrmask & A_dsr)) addrmask |= A_dsr; else { printf("-d specified twice, or -g also specified"); return 1; } } else if (strcmp(argv[ap], "-g") == 0) { gromout = argv[++ap]; if (!(addrmask & A_grom)) addrmask |= A_grom; else { printf("-g specified twice, or -r|-d also specified"); return 1; } } else if (argv[ap][0] == '-') { printf("Unknown option %s\n", argv[ap]); return 1; } else listout = argv[ap]; ap++; } qsort((void *) opcodes, OPCOUNT - 1, sizeof(struct opcoderec), (sorter *) opsort); if (listout) { list = fopen(listout, "w"); if (list == NULL) { printf("Could not open listing file '%s'\n", listout); return 1; } } pass = 0; errors = 0; strcpy(inname, argv[1]); symtable = NULL; addr = 0; if (assemble(inname) == 0) { pass++; addr = 0; if (assemble(inname) == 0) { FILE *out; printf("Successful compilation.\n"); swab(memory, memory, 0x8000); if (romout) { out = fopen(romout, "wb"); if (out == NULL || fwrite(memory, 1, 8192, out) != 8192) { printf("main: couldn't create ROM file %s\n", romout); return 1; } fclose(out); } if (dsrout) { out = fopen(dsrout, "wb"); if (out == NULL || fwrite(memory + 0x4000, 1, 8192, out) != 8192) { printf("main: couldn't create DSR file %s\n", romout); return 1; } fclose(out); } if (modout) { out = fopen(modout, "wb"); if (out == NULL || fwrite(memory + 0x6000, 1, 8192, out) != 8192) { printf("main: couldn't create module file %s\n", romout); return 1; } fclose(out); } if (gromout) { out = fopen(gromout, "wb"); if (out == NULL || fwrite(memory, 1, 24576, out) != 24576) { printf("main: couldn't create GROM file %s\n", gromout); return 1; } fclose(out); } } else printf("PASS 2: %d errors.\n", errors); } else { printf("PASS 1: %d errors.\n", errors); } if (list) fclose(list); return errors != 0; } #define WARNING(s) { \ fprintf(stderr,"Warning: %s (%d): %s\n",inname,linenum,s); \ if (list) \ fprintf(list,"Warning: %s (%d): %s\n",inname,linenum,s); \ warnings++; \ } #define ERROR(s,v,r) { \ sprintf(em,s,v); \ fprintf(stderr,"Error: %s (%d): %s\n",inname,linenum,em); \ if (list) \ fprintf(list,"Error: %s (%d): %s\n",inname,linenum,em); \ errors++; \ return r; \ } #define FATAL(s) { \ fprintf(stderr,"Fatal: %s (%d): %s\n",inname,linenum,s); \ if (list) \ fprintf(list,"Fatal: %s (%d): %s\n",inname,linenum,s); \ exit(1); \ } #define FIXADDR addr=(addr+1)&0xfffe #define WORD(a) (*(word *)(memory+(a))) #define BYTE(a) (memory[(a)^1]) int linenum; int assemble(char *filename) { FILE *in; char line[256]; char orgline[256]; int err; word orgaddr; struct symbolrec *sym; int oldline; char oldname[256]; int last = 0; in = fopen(filename, "r"); if (in == NULL) { printf("parse: couldn't open input file %s\n", filename); return 1; } oldline = linenum; strcpy(oldname, inname); linenum = 1; strcpy(inname, filename); while (!feof(in) && !last) { sym = NULL; em[0] = 0; if (fgets(line, 256, in) != NULL) { if (line[strlen(line) - 1] != '\n') last = 1; // buggy fgets strcpy(orgline, line); orgaddr = addr; err = doaline(line, &sym); if (pass && list) dolisting(orgaddr, addr, orgline, sym); if (err) break; linenum++; } else last = 1; } fclose(in); if (pass && list) fprintf(list, "\n"); linenum = oldline; strcpy(inname, oldname); err |= errors; return err; } void dolisting(word start, word end, char *line, struct symbolrec *sym) { int first, printed; int trailing; if (start == end || !INRANGE(start)) if (sym == NULL) fprintf(list, "%05d \t%s", linenum, line); else if (sym->addr == start) fprintf(list, "%05d >%04X \t%s", linenum, sym->addr, line); else fprintf(list, "%05d >%04X \t%s", linenum, sym->addr, line); else { first = 1; trailing = 0; while (start < end && trailing < 5) { printed = 0; if (first) fprintf(list, "%05d >%04X=", linenum, start); else { fprintf(list, " "); trailing++; } while (printed < 3 && start < end) { if (start & 1) { fprintf(list, " >%02X ", BYTE(start)); start++; } else { fprintf(list, ">%04X ", WORD(start)); start += 2; } printed++; } while (printed < 3) { fprintf(list, " "); printed++; } if (first) { fprintf(list, " \t%s", line); first = 0; } else fprintf(list, "\n"); } } } char * skipspaces(char *line) { while (isspace(*line)) line++; return line; } char * copychars(char *from, char *to, int max) { while ((!isspace(*from)) && *from) if (max) { *to++ = *from++; max--; } else if (*from) from++; *to++ = 0; return from; } void losecomments(char *line) { char temp[256]; char ch; char *tp; // char *lst,*fst; strcpy(temp, line); tp = temp; // fst=line; while (*tp) { ch = *tp++; if (ch == '\n' || ch == ';') break; *line++ = ch; } /* lst=line-1; while (lst>fst && (*lst==' ' || *lst=='\t')) lst--; line=lst;*/ *line++ = 0; *line++ = 0; } int skipcommas(char **pline, int must) { char *line = *pline; line = skipspaces(line); if (*line++ != ',') if (must) ERROR("Comma expected", "", 1) else { *pline = line; return 1; } line = skipspaces(line); *pline = line; return 0; } int pushw(word w) { // FIXADDR; if (!INRANGE(addr)) { if (!(warnmask & BANKUSED(addr))) { WARNING("PUSHW: Writing to non-stored memory bank"); warnmask |= BANKUSED(addr); } } if (addr >= sizeof(memory)) FATAL("Address larger than memory\n"); WORD((addr + 1) & 0xfffe) = w; //DEBUG fprintf(stderr,"pushw: @>%04X := >%04X\n",addr,w); addr += 2; return 0; } int pushb(byte b) { if (!INRANGE(addr)) { if (!(warnmask & BANKUSED(addr))) { WARNING("PUSHB: Writing to non-stored memory bank"); warnmask |= BANKUSED(addr); } } if (addr >= sizeof(memory)) FATAL("Address larger than memory\n"); BYTE(addr) = b; //DEBUG fprintf(stderr,"pushb: @>%04X := >%02X\n",addr,b); addr++; return 0; } #if defined(__BORLANDC__) int swap(int a) { asm { mov ax, a ror ax, 8} return _AX; } #else word swap(word a) { return ((a & 0xff) << 8) | ((a & 0xff00) >> 8); } #endif int quoting, quotesize; char quoted[256]; int doaline(char *line, struct symbolrec **sym) { // struct instrec inst; // struct symbolrec *sym; char ch; char labelname[17]; char opcode[6]; struct opcoderec *om; byte optype; word orgaddr; orgaddr = addr; quoting = 0; ch = *line; losecomments(line); //DEBUG fprintf (stderr,"(%d) %s\n",linenum,line); // Get a label if (*line == 0) return 0; *sym = NULL; if (!isspace(ch)) { memset(labelname, 0, 16); line = copychars(line, labelname, 16); if (labelname[strlen(labelname) - 1] == ':') labelname[strlen(labelname) - 1] = 0; if (labelname[15]) { WARNING("Label name truncated"); labelname[15] = 0; } strupr(labelname); if (addsymbol(labelname, 1, sym)) return 0; } else *labelname = 0; line = skipspaces(line); if (*line) { line = copychars(line, opcode, 5); line = skipspaces(line); strupr(opcode); om = (struct opcoderec *) bsearch(opcode, opcodes, OPCOUNT - 1, sizeof(struct opcoderec), (sorter *) opsort); if (om != NULL) { orgaddr = addr; if (om->opcode) pushw(om->opcode); optype = om->src; if (optype == NIL || decode(&line, *sym, orgaddr, optype)); else do { if (om->dst == NIL) break; if (om->dst != AGAIN) { optype = om->dst; if (skipcommas(&line, 1)) return 0; if (decode(&line, *sym, orgaddr, optype)) return 0; } else { if (skipcommas(&line, 0)) break; if (decode(&line, *sym, orgaddr, om->src)) return 0; } } while (om->dst == AGAIN && *line); } else ERROR("Invalid mnemonic '%s'", opcode, 0); } return 0; } ///////////////////////////////////////////////////////////////////////// int findsymbol(char *buffer, struct symbolrec **ret) { struct symbolrec *s; char name[16]; int cmp; s = symtable; while (s != NULL) { strcpy(name, s->name); name[0] &= 0x7f; if ((cmp = strcmp(name, buffer)) == 0) { *ret = s; return 0; } if (cmp < 0) s = s->right; else s = s->left; } *ret = NULL; return 1; } /* Add a symbol to the symbol table. Returns FATAL error if memory full, ERROR if multiple symbols. Uppercases the symbol. */ int addsymbol(char *name, int defining, struct symbolrec **nw) { struct symbolrec *s, *n, *m, **l; int cmp; char compare[18]; n = malloc(sizeof(struct symbolrec)); if (n == NULL) { FATAL("Memory full!"); } else { strcpy(n->name, name); strupr(n->name); if ((strchr("0123456789>$", n->name[0]) != NULL) || (strpbrk(n->name, "+-=, ;*/<>") != NULL)) ERROR("Illegal character(s) in label '%s'", n->name, 1); if (!defining) { n->name[0] |= 0x80; // not defined yet } n->addr = addr; n->line = linenum; n->left = n->right = NULL; //DEBUG fprintf(stderr,"Adding symbol '%s' on line %d at >%04X\n",name,linenum,addr); } if (symtable == NULL) symtable = s = n; else { if (defining) { if (findsymbol(n->name, &m) == 0) { // found alreddy if (!(m->name[0] & 0x80) && !pass) // redefine? { ERROR("Multiple definition of '%s'", n->name, 1); } m->name[0] &= 0x7f; m->addr = addr; free(n); *nw = m; return 0; } } s = symtable; while (s != NULL) { strcpy(compare, s->name); compare[0] &= 0x7f; cmp = strcmp(compare, n->name); if (!pass && cmp == 0) ERROR("Multiple symbol '%s'", n->name, 0); if (cmp < 0) { l = &s->right; s = s->right; } else { l = &s->left; s = s->left; } } *l = n; } *nw = n; return 0; } /* This routine will return address of the name. If the symbol not found, a blank entry will be added to the symbol table and zero returned. If it's undefined, a new link will be made using record->addr and the address of the last link returned. The special symbol "$" is handled here. */ int getsymboladdress(word orgaddr, char *name, int *ret) { struct symbolrec *s; if (strcmp(name, "$") == 0) { *ret = orgaddr; return 0; } if (findsymbol(name, &s) == 0) // found, defined { if (pass == 0) { *ret = 0; return 0; } else if (s->name[0] & 0x80) ERROR("Unresolved symbol '%s'", name, 1) else { *ret = s->addr; // return defined addr return 0; } } else if (pass) ERROR("Undefined symbol '%s'", name, 1) else { if (addsymbol(name, 0, &s) == 0) // adding, undefined { *ret = 0; return 0; } else return 1; // ouch! } } ////////////////////////////////////////////////////////////////////// /* GETNUMBER will decode a number or an address as a long. *pline is non-null */ int getnumber(char **pline, word orgaddr, long *ret, byte * neither) { static char *abasestr = "0123456789ABCDEF"; char basestr[18]; char name[18]; char *line = *pline; char *start; char *where; long val; int base; byte dig; byte not; byte smt; char ch; char *format; int err; struct symbolrec *s; int addr; ch = *line; not = (ch == '~'); if (not) line++; if (ch == '>') { base = 16; line++; } else base = 10; start = line; memcpy(basestr, abasestr, base); basestr[base] = 0; val = 0; err = 0; smt = 0; while (!err) { where = strchr(basestr, toupper(*line)); if (where == NULL || *where == 0) { if (!smt) err = 1; else if (not) val = ~val; break; } dig = where - basestr; val = (val * base) + dig; line++; smt = 1; *neither = 0; } if (err) { line = start; dig = 0; while (strchr(", \t\n+-*/()&|[]^", *line) == NULL) { if (dig < 15) name[dig++] = (*line++); else line++; } name[dig] = 0; if (dig) { *neither = 0; strupr(name); if (getsymboladdress(orgaddr, name, &addr) == 0) val = addr; else return 1; } else { *neither = 1; return 1; } } *pline = line; *ret = val; return 0; } /* GETEXPR will decode an expression as a long. */ int getexpr(char **pline, word orgaddr, byte size, long *ret) { #define STMAX 32 static long stack[STMAX]; int sp = 0; char *line; long val; char name[16]; byte neither; line = *pline; line = skipspaces(line); if (*line == 0 && !quoting) { ERROR("Missing argument", "", 1); } do { if (sp >= STMAX) ERROR("Expression stack overflow!", "", 1); if (*line == '"') { quoting = 0; do // copy into quoted quoted[quoting++] = *line++; while (*line != '"' && *line); if (!*line) ERROR("Unterminated string", "", 1); line++; // skip last quote while ((quoting - 1) % size) quoted[quoting++] = 0; quotesize = quoting; quoting = 1; } if (quoting) // quoting? { if (size == 1) stack[sp++] = quoted[quoting] & 255; else if (size == 2) stack[sp++] = ((quoted[quoting] & 255) << 8) + (quoted[quoting + 1] & 255); else if (size == 4) stack[sp++] = ((quoted[quoting] & 255) << 24) + ((quoted[quoting + 1] & 255) << 16) + ((quoted[quoting + 2] & 255) << 8) + (quoted[quoting + 3] & 255); else ERROR("Invalid size passed to getexpr (%hd)!", size, 1); quoting += size; if (quoting >= quotesize) quoting = 0; } else if (getnumber(&line, orgaddr, &val, &neither) == 0) { if (sp >= 32) ERROR("Expression stack overflow at '%s'", line, 1) else stack[sp++] = val; } else if (!neither) return 1; else if (strchr("+-*/%|&^[]", *line) == NULL) break; else if (sp > 1) switch (*line) { case '+': sp--; line++; stack[sp - 1] += stack[sp]; break; case '-': sp--; line++; stack[sp - 1] -= stack[sp]; break; case '*': sp--; line++; stack[sp - 1] *= stack[sp]; break; case '/': sp--; line++; if (stack[sp]) stack[sp - 1] /= stack[sp]; else if (pass) ERROR("Divide by zero", "", 1); break; case '%': sp--; line++; stack[sp - 1] %= stack[sp]; break; case '|': sp--; line++; stack[sp - 1] |= stack[sp]; break; case '&': sp--; line++; stack[sp - 1] &= stack[sp]; break; case '^': sp--; line++; stack[sp - 1] ^= stack[sp]; break; case ']': sp--; line++; stack[sp - 1] >>= stack[sp]; break; case '[': sp--; line++; stack[sp - 1] <<= stack[sp]; break; default: ERROR("Illegal operator '%c'", *line, 1); } else ERROR("Stack underflow at '%s'", line, 1); line = skipspaces(line); } while (*line && *line != ','); if (sp > 1) ERROR("Unterminated expression", "", 1); *ret = stack[0]; *pline = line; return 0; } ///////////////////////////////////////////////////////// /* Decode will encode one operand of an instruction. The optype will be used to limit the type. All operands are separated by commas. When all parameters are read, return *line==0 */ int decode(char **pline, struct symbolrec *label, word orgaddr, byte optype) { char *line; long val; long val1, val2, val3, val4; byte reg, ts, td; word s, d, sa, da; line = *pline; if (*line == 0 && optype != EVEN) ERROR("Missing argument", "", 1); if (optype != BYT && optype != BSS) { FIXADDR; if (label && (label->addr & 1)) { label->addr = (label->addr + 1) & 0xfffe; // DEBUG fprintf(stderr,"decode:bumping label addr to %04X\n",label->addr); } } switch (optype) { case WRD: do { if (getexpr(&line, orgaddr, 2, &val)) return 1; if (val < -32768 || val > 65535) ERROR("Integer out of range (%ld)", val, 1); if (pushw(val)) return 1; } while (quoting); break; case BYT: do { if (getexpr(&line, orgaddr, 1, &val) == 0) { if (val < -128 || val > 255) ERROR("Byte out of range (%ld)", val, 1); if (pushb(val)) return 1; } else return 1; } while (quoting); break; case DWD: do { if (getexpr(&line, orgaddr, 4, &val) == 0) { if (pushw(val >> 16) || pushw(val & 0xffff)) return 1; } else return 1; } while (quoting); break; case EQU: if (getexpr(&line, orgaddr, 2, &val) == 0) { if (label != NULL) if (val >= -32768 && val < 65535) label->addr = val; else ERROR("Equate too large (%ld)", val, 1); } else return 1; break; case AORG: if (getexpr(&line, orgaddr, 2, &val) == 0) addr = val; else return 1; break; case BSS: if (getexpr(&line, orgaddr, 2, &val) == 0) addr += val; else return 1; break; case INC: line = skipspaces(line); return assemble(line); case EVEN: addr = (addr + 1) & 0xfffe; break; //////////////////////////////////////////////////////////////////// case IMM: if (getexpr(&line, orgaddr, 2, &val)) return 1; if (val < -32768 || val > 65535) ERROR("Integer out of range (%ld)", val, 1); if (pushw(val)) return 1; break; case NIMM: if (getexpr(&line, orgaddr, 2, &val)) return 1; if (val < -32768 || val > 65535) ERROR("Integer out of range (%ld)", val, 1); if (pushw(-val)) return 1; break; case REG: if (getregister(&line, orgaddr, 0)) return 1; break; case REGH: if (getregister(&line, orgaddr, 6)) return 1; break; case REG4: if (getregister(&line, orgaddr, 4)) return 1; break; case JMP: if (getjump(&line, orgaddr)) return 1; break; case BIT: if (getbit(&line, orgaddr)) return 1; break; case CNT: if (getcnt(&line, orgaddr, 4, "Shift count")) return 1; break; case CNTH: if (getcnt(&line, orgaddr, 6, "bit count")) return 1; break; case XOP: if (getcnt(&line, orgaddr, 6, "XOP vector")) return 1; break; case GEN: if (getgen(&line, orgaddr, 4, 0)) return 1; break; case GENH: if (getgen(&line, orgaddr, 10, 6)) return 1; break; default: FATAL("Operand type not implemented!"); } *pline = line; return 0; } ///////////////////////////////////////////////////////////////////// /* Get a register at pline and change the word at start. */ int getregister(char **pline, word orgaddr, byte start) { byte neither; long regval; if (getexpr(pline, orgaddr, 1, ®val) == 0) if (regval >= 0 && regval < 16) { WORD(orgaddr) |= (regval << start); } else ERROR("Illegal register specified (%d)", regval, 1) else return 1; return 0; } /* Get a jump offset and set. */ int getjump(char **pline, word orgaddr) { long val; long offs; if (getexpr(pline, orgaddr, 2, &val) == 0) { if (pass) { offs = (val - (signed) addr) / 2; if (offs < -127 || offs >= 128) ERROR("Jump range exceeded by %d words", (offs < 0 ? offs + 127 : offs - 128), 1); WORD(orgaddr) |= (offs & 255); } return 0; } else return 1; } /* Get a bit offset and set. */ int getbit(char **pline, word orgaddr) { long val; long offs; if (getexpr(pline, orgaddr, 1, &val) == 0) { if (pass) { offs = val; if (offs < -127 || offs >= 128) ERROR("Bit offset out of range (%d)", offs, 1); WORD(orgaddr) |= (offs & 255); } return 0; } else return 1; } /* Get a count. */ int getcnt(char **pline, word orgaddr, byte bit, char *type) { long val; long offs; char err[256]; if (getexpr(pline, orgaddr, 1, &val) == 0) { if (pass) { offs = val; if (offs < 0 || offs > 16) { sprintf(err, "%s illegal (%%d)", type); ERROR(err, offs, 1); } WORD(orgaddr) |= (offs & 15) << bit; } return 0; } else return 1; } /* Get a general thingie. */ int getgen(char **pline, word orgaddr, byte tbit, byte bit) { long val; byte t; char ch; ch = **pline; if (ch == '*') // indirect? ts=1 { t = 1; WORD(orgaddr) |= t << tbit; (*pline)++; if (getregister(pline, orgaddr, bit)) return 1; } else if (ch == '+') // autoincrement? ts=3 { t = 3; WORD(orgaddr) |= t << tbit; (*pline)++; ch = **pline; if (ch == '*') // better be this (*pline)++; else ERROR("Syntax error at '%s'", *pline, 1); if (getregister(pline, orgaddr, bit)) return 1; } else if (ch == '@') // symbolic or indexed? ts=2 { t = 2; WORD(orgaddr) |= t << tbit; (*pline)++; if (getexpr(pline, orgaddr, 2, &val)) return 1; if (val < -32768 || val > 65535) ERROR("Index/addr too large (%ld)", val, 1); if (pushw(val)) return 1; *pline = skipspaces(*pline); ch = **pline; if (ch == '(') // indexed memory? ts=2 { (*pline)++; if (getregister(pline, orgaddr, bit)) return 1; ch = **pline; if (ch != ')') ERROR("Unterminated index register", "", 1) else (*pline)++; } } else // register? ts = 0 if (getregister(pline, orgaddr, bit)) return 1; return 0; }