#include "asmmon.h" #include "lexer.h" uint16_t linenum = 10; uint16_t lineidx = 0; uint16_t stridx = 0; uint16_t comidx = 0; uint16_t inc_file = 0; /* Number of included files. */ uint16_t inc_count = 0; uint8_t defined = 0; uint8_t isfixup = 0; char lexeme[MAX_TOK]; char *string[MAX_TOK]; char *comment[MAX_TOK]; uint16_t incl[MAX_TOK]; line *lines; line *last_line; symbol *symbols = 0; symbol *last_sym = 0; fixup *fixups = 0; fixup *last_fix = 0; strln *first_strln = 0; strln *last_strln = 0; static char tstr[2048]; void viewmem(uint64_t address) { putchar('\n'); printf("\t\t\t"); for (uint8_t ind = 0; ind < 0x10; ind++) { printf("%02X", ind); if (ind < 0x0F) { putchar(' '); } } puts("\n"); for (uint8_t hi = 0; hi < 0x10; hi++) { printf("$%016"PRIX64":\t", (address)+(hi << 4)); for (uint8_t lo = 0; lo < 0x10; lo++) { printf("%02X", addr[(address)+lo+(hi << 4)]); if (lo < 0x0F) { putchar(' '); } } putchar('\n'); } } void usage() { puts("SuBAsm for CISC-0.2"); puts("Commands:"); puts("\tasm, a\t\t\tAssembles the currently written program."); puts("\tinst, i [inst]\t\tGet a descriptions of that instruction."); puts("\t\t\t\tIf no argument is specified, or the"); puts("\t\t\t\targument specified is \"all\", list all"); puts("\t\t\t\tinstructions, along with a description"); puts("\t\t\t\tfor each of them."); puts("\tlist, l [$%][start][-][$%][end] [d[ebug], l[inenum], a[ddress]]]"); puts("\t\t\t\tLists the currently written program."); puts("\tviewmem, v\t\tGet the contents of memory"); puts("\t\t\t\t(Displays 256 bytes of memory"); puts("\t\t\t\t starting from where the program counter"); puts("\t\t\t\t currently is)."); puts("\tquit, q\t\t\tQuit the emulator."); puts("\thelp, h\t\t\tDisplays this mesage."); } void instinfo(const char *instr) { for(int i = 0; i < OPNUM; i++) { if (instr[0] == mne[i][0]) { if (!strcasecmp(instr, mne[i])) { printf("%s\t%s\n", mne[i], instdesc[i]); break; } } else if (instr[0] == 'a') { if (!strcasecmp(instr, "all")) { printf("%s\t%s\n", mne[i], instdesc[i]); } } } } char *showbits(uint64_t value, uint8_t bitnum, uint8_t dbg) { if (dbg) { printf("showbits(): "); } char *bits = malloc((sizeof(uint64_t) << 3)+1); char bit = 0; uint8_t i; uint8_t j = 0; if (bitnum > 63) { bitnum = (sizeof(uint64_t) << 3) - 1; } if (!bitnum) { i = (sizeof(uint64_t) << 3) - 1; } else { i = bitnum; } for (; (value > 0 && !bitnum) || (j <= bitnum && bitnum); j++) { if (value > 0 && !bitnum) { bits[j] = (value & 1) ? '1' : '0'; value>>=1; } else { bits[j] = (value & ((uint64_t)1 << i)) ? '1' : '0'; i--; } } bits[j] = '\0'; if (dbg) { printf("bits: %s\n", bits); } return bits; } static inline uint8_t isopdone(token *t) { switch (t->id) { case TOK_OF : case TOK_HEX : case TOK_BIN : case TOK_DEC : case TOK_CHAR: case TOK_EXPR: return 0; default : return 1; } } void list(uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, uint64_t address, uint8_t dbg) { line *s = (!all) ? find_line(start, dbg) : lines; line *e = (!all) ? find_line( end, dbg) : NULL; uint8_t j = 0; uint8_t flags = 0; uint8_t isstr; uint8_t iscom; uint8_t iscm = 0; uint8_t bitnum; uint8_t opsize = 0; uint8_t spaces; uint8_t tabs; char mne_lower[4]; char ch[6]; do { address = s->addr; token *t = s->tok; uint8_t am = 0xFF; uint8_t rs = 0xFF; uint8_t am_done = 1; uint8_t op_done = 1; uint16_t bline = s->bline; const char *inst_name; for (; bline; bline--) { putchar('\n'); } if (dbg) { printf("list(): "); } if (ln) { printf("%5u\t\t", s->linenum); } else if (addr) { printf("$%"PRIX64":\t\t", s->addr); } while (t) { if (am != 0xFF && op_done && t->id != TOK_RS) { switch (am) { case IMM : putchar('#'); am_done = 1; break; case IND : case INDX: case INDY: putchar('('); am_done = 0; break; case ZMY : case ZMX : am_done = 0; break; } am = (am_done) ? 0xFF : am; } spaces = t->space; tabs = t->tab; while (spaces || tabs) { if (spaces) { putchar(' '); spaces--; } if (tabs) { putchar('\t'); tabs--; } } switch (t->id) { case TOK_DIR : printf(".%s", dir_t[t->type]); break; case TOK_RS : printf("%s", rs_t[t->type]); break; case TOK_EXTOP : case TOK_OPCODE: switch (t->id) { case TOK_EXTOP : inst_name = ext_mne[t->byte]; break; case TOK_OPCODE: inst_name = /**/mne[t->byte]; break; } for (; j < 3; j++) { mne_lower[j] = tolower(inst_name[j]); } mne_lower[j] = '\0'; j = 0; printf("%s", mne_lower); am = t->type; break; case TOK_OF: switch (t->type) { case 1: printf("sp"); break; case 2: printf("pc"); break; } break; case TOK_SYM: case TOK_LABEL: case TOK_STRUCT: case TOK_UNION: case TOK_MEMBER: if (t->type == 1) { putchar('@'); } printf("%s", (t->sym) ? t->sym->name : "unknown"); if (t->sym && t->sym->isstruct && t->next && t->next->id == TOK_SYM) { putchar('.'); } if (t->id == TOK_LABEL) { putchar(':'); } break; case TOK_HEX: if (t->id == TOK_HEX) { printf("$%0*"PRIX64, t->digits, t->qword); } else if (t->id == TOK_DEC) { case TOK_DEC: printf( "%0*"PRIu64, t->digits, t->qword); } else if (t->id == TOK_BIN) { case TOK_BIN: if (t->digits) { bitnum = t->digits; } else { opsize = 1; opsize = (t->qword > 0x000000FF) ? 2 : opsize; opsize = (t->qword > 0x0000FFFF) ? 3 : opsize; opsize = (t->qword > 0xFFFFFFFF) ? 4 : opsize; if (opsize) { bitnum = bitsize[opsize-1]; } } printf("%%%s", showbits(t->qword, bitnum, dbg)); bitnum = 0; opsize = 0; } else if (t->id == TOK_STRING) { case TOK_STRING: printf("\"%s\"", (t->str) ? t->str : ""); } else if (t->id == TOK_CHAR) { case TOK_CHAR: j = 0; switch (t->byte) { default : ch[j++] = t->byte; break; case '\n': ch[j++] = '\\'; ch[j++] = 'n' ; break; case '\r': ch[j++] = '\\'; ch[j++] = 'r' ; break; case '\t': ch[j++] = '\\'; ch[j++] = 't' ; break; case '\b': ch[j++] = '\\'; ch[j++] = 'b' ; break; case '\\': ch[j++] = '\\'; ch[j++] = '\\'; break; case '\0': ch[j++] = '\\'; ch[j++] = '0'; break; case '\'': ch[j++] = '\\'; ch[j++] = '\''; break; case '\"': ch[j++] = '\\'; ch[j++] = '\"'; break; } ch[j] = '\0'; j = 0; printf("\'%s\'", ch); } if (t->next) { switch (t->next->id) { case TOK_STRING: case TOK_HEX : case TOK_BIN : case TOK_DEC : case TOK_CHAR : putchar(','); break; } } break; case TOK_COMMENT: printf(";%s", (t->str) ? t->str : ""); break; case TOK_EXPR: switch (t->type) { case EXPR_PLUS : putchar('+'); break; case EXPR_MINUS: putchar('-'); break; case EXPR_LSHFT: putchar('<'); /* Falls through. */ case EXPR_HIGH : putchar('<'); break; case EXPR_RSHFT: putchar('>'); /* Falls through. */ case EXPR_LOW : putchar('>'); break; case EXPR_OR : putchar('|'); break; } break; } if (t->subspace || t->subtab) { spaces = t->subspace; tabs = t->subtab; while (spaces || tabs) { if (spaces) { putchar(' '); spaces--; } if (tabs) { putchar('\t'); tabs--; } } } if (t->next && !isopdone(t)) { op_done = isopdone(t->next); } if (am != 0xFF && op_done && t->id != TOK_RS) { switch (am) { case EIND: putchar('('); am_done = 0; break; case BREG: putchar('b'); am_done = 1; break; } } if (am != 0xFF && !am_done && op_done) { switch (am) { case INDX: case ZMX : printf(", x"); if (am == ZMX) { break; } /* Falls Through. */ case EIND: if (am == EIND) { putchar('e'); } /* Falls Through. */ case INDY: case IND : putchar(')'); if (am == IND || am == EIND) { break; } /* Falls Through. */ case ZMY : printf(", y"); break; } am = 0xFF; am_done = 1; } if (t == s->tok && t->id == TOK_SYM) { putchar('='); } t = t->next; } puts(""); s = s->next; } while (s != e && s); } strln *make_strln(char *str, int blanks) { strln *new_strln = malloc(sizeof(strln)); if (new_strln == NULL) { return NULL; } new_strln->next = NULL; new_strln->prev = NULL; new_strln->str = str; new_strln->blanks = blanks; if (last_strln == NULL) { first_strln = new_strln; } else { new_strln->prev = last_strln; last_strln->next = new_strln; } last_strln = new_strln; return new_strln; } int asmmon(const char *fn) { FILE *fp = NULL; FILE *fp2 = NULL; char *path = malloc(0x400); if (strcasecmp(fn, "stdin")) { uint16_t i = 0; uint8_t dir = 0; for (; fn[i] != '\0'; i++) dir = (fn[i] == '/') ? i : dir; if (dir) { memcpy(path, fn, dir); path[dir] = '\0'; } else { path[0] = '.'; path[1] = '\0'; } fp = fopen(fn, "r"); if (fp == NULL) { free(path); return 2; } } uint8_t done = 0; uint8_t use_lexer = 1; uint64_t address = 0; bytecount bc; uint64_t progsize = 0; uint64_t datasize = 0; uint8_t dbg = 0; uint8_t isinclude = 0; uint16_t tmp_lineidx = 0; uint16_t bline = 0; while (!done) { char *cmd; char *arg = malloc(sizeof(char *)*128); char *tmp = malloc(sizeof(char *)*128); char lex_line[0x1000]; uint16_t size = 0; uint8_t cmds = 0; uint8_t is_valid = 0; /* Is single character command. */ uint8_t isshcmd = 0; if (!isinclude) { fgets(lex_line, sizeof(lex_line), (!strcasecmp(fn, "stdin")) ? stdin : fp); } else { if (fp2 != NULL) { if (fgets(lex_line, sizeof(lex_line), fp2) == NULL && feof(fp2)) { lex_line[0] = 'a' ; lex_line[1] = '\n'; lex_line[2] = '\0'; } } } size = strlen(lex_line)+1; cmd = malloc(size); memcpy(cmd, lex_line, size); cmd = strtok_r(cmd, " \t\n", &tmp); if (cmd != NULL) { int cmd_len = strlen(cmd); isshcmd = (cmd_len > 0 && cmd_len <= 3 && (cmd[1] == '\0' || cmd[1] == ' ')); if (tmp) { int stop = 0; for (int i = 0; !(isdelm(tmp[i], 0) & 1) && !stop; i++) { switch (get_ptok(tmp[i], 0)) { case PTOK_NUMBER : case PTOK_ALPHA : case PTOK_DOLLAR : case PTOK_PERCENT: case PTOK_DQUOTE : case PTOK_SQUOTE : case PTOK_B : case PTOK_E : case PTOK_X : case PTOK_Y : case PTOK_S : case PTOK_P : case PTOK_A : case PTOK_C : case PTOK_D : case PTOK_F : case PTOK_R : case PTOK_MINUS : case PTOK_PLUS : is_valid = 1; break; default : is_valid = 0; stop = 1; break; } } if (strlen(tmp) <= 1) { is_valid = 1; } } if (is_valid) { switch (cmd[0]) { case 'q': cmds = (isshcmd || !strcasecmp(cmd, "quit" )) << 0; break; case 'v': cmds = (isshcmd || !strcasecmp(cmd, "viewmem")) << 1; break; case 'l': cmds = (isshcmd || !strcasecmp(cmd, "list" )) << 2; break; case 'a': cmds = (isshcmd || !strcasecmp(cmd, "asm" )) << 3; break; case 'h': cmds = (isshcmd || !strcasecmp(cmd, "help" )) << 4; break; case 'i': cmds = (isshcmd || !strcasecmp(cmd, "inst" )) << 5; break; case 'd': cmds = (isshcmd || !strcasecmp(cmd, "done" )) << 6; break; case 's': cmds = (isshcmd || !strcasecmp(cmd, "sett" )) << 7; break; case ' ': case '\t': default: is_valid = 0; cmds = 0xFF; break; } if (!cmds) { is_valid = 0; } } switch (cmds) { case 0x01: free(path); if (fp != NULL) { fclose(fp); } if (fp2 != NULL) { fclose(fp2); } cleanup(); return 2; case 0x02: viewmem(address); break; case 0x04: if (tmp != NULL) { uint16_t i = 0; uint16_t j = 0; uint16_t start = 0; uint16_t end = 0; uint16_t value = 0; uint8_t base = 0xFF; uint8_t isflag = 0; uint8_t isstart = 1; uint8_t isdebug = 0; uint8_t islinenum = 0; uint8_t isaddr = 0; while (tmp[i] != '\0') { if (isspace(tmp[i])) { for (; isspace(tmp[i]); i++); } switch (tmp[i]) { case '$': base = 16; i++; break; case '%': base = 2; i++; break; default: j = i; for (; isdigit(tmp[j]); j++, isflag++); base = (isflag) ? 10 : 0xFF; isflag = 0; j = 0; break; } for (; !isspace(tmp[i]) && tmp[i] != '-' && tmp[i] != '\0' && tmp[i] != '\n'; arg[j++] = tmp[i++]); arg[j] = '\0'; j = 0; if (base != 0xFF) { value = strtol(arg, NULL, base); base = 0xFF; (isstart) ? (start = value) : (end = value); if (isstart) { isstart = (tmp[i] != '-'); } } else { for (; isalpha(arg[j]); j++, isflag++); j = 0; if (isflag) { isdebug = (arg[j] == 'd' || !strcasecmp(arg, "debug" )); islinenum = (arg[j] == 'l' || !strcasecmp(arg, "linenum")); if (!islinenum) { isaddr = (arg[j] == 'a' || !strcasecmp(arg, "address")); } } isflag = 0; } i++; } list(start, end, isstart, islinenum, isaddr, 0, isdebug); } else { list(0, 0, 1, 0, 0, 0, 0); } break; case 0x08: if (!inc_count) { printf("Assembling %s\n", (strcasecmp(fn, "stdin")) ? fn : "typed in program."); } if (!inc_file) { puts("Now assembling."); address = 0; bc.progsize = 0; bc.datasize = 0; assemble(lines, &bc, dbg); progsize = bc.progsize; datasize = bc.datasize; } isinclude = (inc_file != 0); if (inc_file) { size = strlen(path)+strlen(string[incl[inc_count]])+1; char *fn2 = malloc(size+1); sprintf(fn2, "%s/%s", path, string[incl[inc_count]]); isinclude = (inc_file != 0); inc_file--; if (inc_file && fp2 != NULL) { fclose(fp2); } fp2 = fopen(fn2, "r"); if (fp2 == NULL) { fclose(fp); cleanup(); return 2; } printf("Including %s\n", string[incl[inc_count++]]); } if (!isinclude) { puts("Finished assembling."); printf("Total Assembled Program Size: %"PRIu64"/$%"PRIX64" bytes.\n", progsize, progsize); printf("Total Assembled Data Size: %"PRIu64"/$%"PRIX64" bytes.\n", datasize, datasize); } break; case 0x10: usage(); break; case 0x20: if (tmp != NULL) { instinfo(tmp); } else { instinfo("all"); } break; case 0x40: done = 1; break; case 0x80: if (tmp != NULL) { uint16_t i = 0; uint16_t j = 0; uint8_t isdebug = 0; is_valid = 0; while (tmp[i] != '\0') { if (isspace(tmp[i])) { for (; isspace(tmp[i]); i++); } for (; !(isdelm(tmp[i], 0) & 0x11); arg[j++] = tmp[i++]); arg[j] = '\0'; j = 0; isdebug = (arg[j] == 'd' || !strcasecmp(arg, "debug")); if (isdebug) { is_valid = 1; dbg = !dbg; if (dbg) { puts("Debug mode has been enabled."); } else { puts("Debug mode has been disabled."); } } i++; } } else { is_valid = 0; } case 0xFF: default : break; } if (!is_valid) { size_t len = strlen(lex_line); char *tmp = malloc(len+1); memcpy(tmp, lex_line, len); tmp[len] = '\0'; strln *dummy = make_strln(tmp, bline); address = lex(lex_line, address, bline, dbg); bline = 0; } } else if (lex_line[0] == '\n') { bline++; } } free(path); if (fp != NULL) { fclose(fp); } if (fp2 != NULL) { fclose(fp2); } cleanup(); return 0; }