#include "asmmon.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. */ uint8_t defined = 0; uint8_t isfixup = 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 & ~0xF)+(hi << 4)); for (uint8_t lo = 0; lo < 0x10; lo++) { printf("%02X", addr[(address & ~0xF)+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 *inst) { for(int i = 0; i < OPNUM; i++) { if (inst[0] == mne[i][0]) { if (!strcasecmp(inst, mne[i])) { printf("%s\t%s\n", mne[i], instdesc[i]); break; } } else if (inst[0] == 'a') { if (!strcasecmp(inst, "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; } void list(struct line *l, uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, uint8_t dbg) { uint16_t i = start; uint8_t j = 0; uint8_t flags = 0; uint8_t isstr; uint8_t iscom; uint8_t iscm = 0; uint8_t fall = 0; uint8_t bitnum; uint8_t opsize = 0; uint8_t spaces; uint8_t tabs; char mne_lower[4]; if (all) { end = lineidx; } for (; i < end; i++) { flags = 0; flags |= (l[i].dir != 0x00FF) << 0; flags |= (l[i].mne != 0x00FF) << 1; flags |= (l[i].rs != 0x00FF) << 2; flags |= (l[i].am != 0x00FF) << 3; flags |= (l[i].opbase != 0x00FF) << 4; flags |= (l[i].sym != 0xFFFF) << 5; flags |= (l[i].rs != 0x00FF) << 6; flags |= (l[i].am != 0x00FF) << 7; iscm = l[i].cm != 0xFF; isstr = l[i].str != 0xFFFF; iscom = l[i].com != 0xFFFF; if (dbg) { printf("list(): "); } if (ln) { printf("%u\t", l[i].linenum); } else if (addr) { printf("$%"PRIX64":\t", l[i].addr); } spaces = l[i].sspace; tabs = l[i].stab; while (spaces || tabs) { if (spaces) { putchar(' '); spaces--; } if (tabs) { putchar('\t'); tabs--; } } if (flags & 0x01) { printf(".%s ", dir_t[l[i].dir]); if (isstr) { printf("\"%s\"", string[l[i].str]); } } if (flags & 0x02) { for (; j < 3; j++) { mne_lower[j] = tolower(mne[l[i].mne][j]); } mne_lower[j] = '\0'; j = 0; printf("%s", mne_lower); } if (flags & 0x04) { printf("%s ", rs_t[l[i].rs]); } else if (flags & 0x02) { printf(" "); } if (flags & 0x7F) { switch (l[i].am) { case IMM: putchar('#'); break; case INDX: case INDY: case IND: putchar('('); break; } } if (flags & 0x20) { printf("%s", symbols[l[i].sym]->name); if (l[i].islabel) { printf(": "); } else if (l[i].issym) { printf(" = "); } } if (flags & 0x10) { if (flags & 0x04) { bitnum = (l[i].rs << 3); } else { opsize += (l[i].op <= 0x000000FF) + 0; opsize += (l[i].op > 0x000000FF) + 1; opsize += (l[i].op > 0x0000FFFF) + 2; opsize += (l[i].op > 0xFFFFFFFF) + 3; if (opsize) { bitnum = bitsize[opsize-1]; } } switch (l[i].opbase) { case BASE_HEX: printf("$%"PRIX64, l[i].op); break; case BASE_DEC: printf("%"PRIu64, l[i].op); break; case BASE_BIN: printf("%%%s", showbits(l[i].op, bitnum, dbg)); break; } bitnum = 0; opsize = 0; } if (iscm) { switch (l[i].cm) { case 0: putchar('+'); break; case 1: putchar ('-'); break; } opsize += (l[i].aop <= 0x000000FF) + 0; opsize += (l[i].aop > 0x000000FF) + 1; opsize += (l[i].aop > 0x0000FFFF) + 2; opsize += (l[i].aop > 0xFFFFFFFF) + 3; if (opsize) { bitnum = bitsize[opsize-1]; } switch (l[i].aopbase) { case BASE_HEX: printf("$%"PRIX64, l[i].aop); break; case BASE_DEC: printf("%"PRIu64, l[i].aop); break; case BASE_BIN: printf("%%%s", showbits(l[i].aop, bitnum, dbg)); break; } bitnum = 0; opsize = 0; } if (flags & 0x7F) { if (fall) { fall = 0; } switch (l[i].am) { case INDX: case ZMX: printf(", x"); if (l[i].am == ZMX) { break; } fall = 1; /* Falls Through. */ case INDY: fall = !fall; /* Falls Through. */ case IND: putchar(')'); if (!fall) { break; } /* Falls Through. */ case ZMY: printf(", y"); break; } } spaces = l[i].espace; tabs = l[i].etab; while (spaces || tabs) { if (spaces) { putchar(' '); spaces--; } if (tabs) { putchar('\t'); tabs--; } } if (iscom) { printf(";%s", comment[l[i].com]); } puts(""); } } uint64_t assemble(struct line *line, uint8_t dbg) { uint64_t bytecount = 0; uint64_t tmpaddr; uint64_t value; uint16_t flags = 0; uint16_t i = 0; uint16_t k = 0; uint16_t tmp; uint8_t c = 0; uint8_t prefix = 0; uint8_t opsize = 0; uint8_t skip = 0; uint64_t address; uint64_t op; uint64_t aop; uint16_t symid; uint16_t str; uint16_t com; uint8_t islabel; uint8_t opbase; uint8_t aopbase; uint8_t dir; uint8_t am; uint8_t cm; uint8_t rs; uint8_t ins; for (; i < lineidx; i++) { if (dbg) { printf("assemble(): i: $%X\n", i); } address = line[i].addr; tmpaddr = address; op = line[i].op; aop = line[i].aop; symid = line[i].sym; str = line[i].str; com = line[i].com; islabel = line[i].islabel; opbase = line[i].opbase; aopbase = line[i].aopbase; dir = line[i].dir; am = line[i].am; cm = line[i].cm; rs = line[i].rs; ins = line[i].mne; flags = 0; flags |= (dir != 0x00FF) << 0x00; flags |= (ins != 0x00FF) << 0x01; flags |= (rs != 0x00FF) << 0x02; flags |= (am != 0x00FF) << 0x03; flags |= (opbase != 0x00FF) << 0x04; flags |= (aopbase != 0x00FF) << 0x05; flags |= (symid != 0xFFFF) << 0x06; flags |= (islabel ) << 0x07; flags |= (am != 0x00FF) << 0x08; flags |= (cm != 0x00FF) << 0x09; flags |= (str != 0xFFFF) << 0x0A; if (dbg) { printf("assemble(): "); putchar('%'); printf("%u", str != 0xFFFF); printf("%u", cm != 0x00FF); printf("%u", am != 0x00FF); printf("%u", islabel ); printf("%u", symid != 0xFFFF); printf("%u", aopbase != 0x00FF); printf("%u", opbase != 0x00FF); printf("%u", am != 0x00FF); printf("%u", rs != 0x00FF); printf("%u", ins != 0x00FF); printf("%u", dir != 0x00FF); putchar('\n'); printf("assemble(): "); printf("flags: $%04X\n", flags); } if (!flags) { if (dbg) { printf("assemble(): "); puts("This line only contains a comment, so skip it."); } continue; } opsize = 0; skip = 0; if ((flags & 0x53) == 0x42) { value = symbols[symid]->val; } else { value = op; } if ((flags & 0x51) == 0x41) { value = symbols[symid]->val; } if (flags & 0x220) { switch (cm) { case 0: value += aop; break; case 1: value -= aop; break; } } if (dbg) { printf("assemble(): value: $%"PRIX64"\n", value); } switch (dir) { case DIR_ORG: tmpaddr = value; if (dbg) { printf("assemble(): "); printf("The Program Counter's origin is now at, $%"PRIX64".\n", value); } skip = 1; break; case DIR_BYTE: if (flags & 0x400) { for (k = 0; string[str][k] != '\0'; k++) { switch (string[str][k]) { case '\\': switch (string[str][k+1]) { case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case '0': c = '\0'; break; } k++; break; default: c = string[str][k]; break; } addr[tmpaddr++] = c; } addr[tmpaddr] = '\0'; if (dbg) { printf("assemble(): "); printf("Placed string \"%s\"", string[str]); printf(", at address(es) $%"PRIX64"-$%"PRIX64".\n", address, tmpaddr); } } else { addr[tmpaddr++] = value & 0xFF; } break; case DIR_QWORD: addr[tmpaddr+7] = value >> 0x38; addr[tmpaddr+6] = value >> 0x30; addr[tmpaddr+5] = value >> 0x28; addr[tmpaddr+4] = value >> 0x20; tmp+=4; case DIR_DWORD: addr[tmpaddr+3] = value >> 0x18; addr[tmpaddr+2] = value >> 0x10; tmp+=2; case DIR_WORD: addr[tmpaddr+1] = value >> 0x08; addr[tmpaddr ] = value & 0xFF; tmp+=2; break; case DIR_INCLUDE: incl[inc_file++] = line[i].incl; break; } tmpaddr += tmp; tmp = 0; if (skip || flags & 0x80) { if (dbg) { printf("assemble(): The address that this line starts at is, $%"PRIX64".\n", address); printf("assemble(): The address that this line ends on is, $%"PRIX64".\n", tmpaddr); } continue; } if (flags == 0x108) { if (dbg) { printf("assemble(): The address that this line starts at is, $%"PRIX64".\n", address); printf("assemble(): The address that this line ends on is, $%"PRIX64".\n", tmpaddr); } continue; } if (flags & 0x04) { prefix = (rs << 4) | 3; } else { rs = 0; } if (flags & 0x102) { if (ins == 80) { if (flags & 0x10) { am = IMM; prefix |= 0x13; } else { am = IMPL; addr[tmpaddr++] = opcodes[ins][IMM]; bytecount++; if (dbg) { printf("assemble(): The instruction that is being used is, %s.\n", mne[ins]); printf("assemble(): The addressing mode that this instruction is using is, %s.\n", adrmode[IMM]); printf("assemble(): The opcode for this instruction, and addressing mode is, $%02X.\n", opcodes[ins][IMM]); } } } opsize = 0; if (am != IMM && am != IMPL) { opsize = (value <= 0x00000000000000FF) ? 1 : opsize; opsize = (value > 0x00000000000000FF) ? 2 : opsize; opsize = (value > 0x000000000000FFFF) ? 3 : opsize; opsize = (value > 0x0000000000FFFFFF) ? 4 : opsize; opsize = (value > 0x00000000FFFFFFFF) ? 5 : opsize; opsize = (value > 0x000000FFFFFFFFFF) ? 6 : opsize; opsize = (value > 0x0000FFFFFFFFFFFF) ? 7 : opsize; opsize = (value > 0x00FFFFFFFFFFFFFF) ? 8 : opsize; if (opsize) { opsize--; prefix |= amp[opsize]; } } if (prefix) { if (dbg) { printf("assemble(): "); puts("Prefix byte detected."); } addr[tmpaddr++] = prefix; bytecount++; if (dbg) { uint8_t addrsize = (prefix & 0x0C) >> 2; uint8_t regsize = (prefix & 0x30) >> 4; printf("assemble(): "); printf("The values of the prefix bits are"); printf(", AM: %u, RS: %u\n", addrsize, regsize); } prefix = 0; } if (opcodes[ins][am] != 0xFF) { addr[tmpaddr++] = opcodes[ins][am]; bytecount++; if (dbg) { printf("assemble(): The instruction that is being used is, %s.\n", mne[ins]); printf("assemble(): The addressing mode that this instruction is using is, %s.\n", adrmode[am]); printf("assemble(): The opcode for this instruction, and addressing mode is, $%02X.\n", opcodes[ins][am]); } switch (am) { case IMM: switch (rs) { case 3: addr[tmpaddr+7] = value >> 0x38; addr[tmpaddr+6] = value >> 0x30; addr[tmpaddr+5] = value >> 0x28; addr[tmpaddr+4] = value >> 0x20; tmp+=4; case 2: addr[tmpaddr+3] = value >> 0x18; addr[tmpaddr+2] = value >> 0x10; tmp+=2; case 1: addr[tmpaddr+1] = value >> 0x08; tmp+=1; case 0: addr[tmpaddr ] = value & 0xFF; tmp+=1; } break; case ABS: case ZM: case ZMX: case ZMY: case IND: case INDX: case INDY: switch (opsize) { case 7: addr[tmpaddr+7] = value >> 0x38; tmp++; case 6: addr[tmpaddr+6] = value >> 0x30; tmp++; case 5: addr[tmpaddr+5] = value >> 0x28; tmp++; case 4: addr[tmpaddr+4] = value >> 0x20; tmp++; case 3: addr[tmpaddr+3] = value >> 0x18; tmp++; case 2: addr[tmpaddr+2] = value >> 0x10; tmp++; case 1: addr[tmpaddr+1] = value >> 0x08; tmp++; case 0: addr[tmpaddr ] = value & 0xFF; tmp++; } break; } tmpaddr += tmp; bytecount += tmp; tmp = 0; } } if (dbg) { printf("assemble(): The address that this line starts at is, $%"PRIX64".\n", address); printf("assemble(): The address that this line ends on is, $%"PRIX64".\n", tmpaddr); printf("assemble(): The program size is now at"); printf(", %"PRIu64" bytes in decimal", bytecount); printf(", and $%"PRIX64" bytes in hex.\n", bytecount); } } return bytecount; } int asmmon(const char *fn) { FILE *fp; FILE *fp2; 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; uint64_t bytecount = 0; uint8_t dbg = 0; uint8_t isinclude = 0; uint16_t tmp_lineidx = 0; uint8_t inc_count = 0; init_symbol(); 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; /* 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) { isshcmd = (cmd[1] == '\0' || cmd[1] == ' '); 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, "set" )) << 7; break; case ' ': case '\t': cmds = 0xFF; break; } switch (cmds) { case 0x01: free(path); fclose(fp); if (fp2 != NULL) { fclose(fp2); } 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 = BASE_HEX; i++; break; case '%': base = BASE_BIN; i++; break; default: j = i; for (; isdigit(tmp[j]); j++, isflag++); base = (isflag) ? BASE_DEC : 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) { switch (base) { case BASE_HEX: value = strtol(arg, NULL, 16); break; case BASE_BIN: value = strtol(arg, NULL, 2); break; case BASE_DEC: value = strtol(arg, NULL, 10); break; } 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++; } if (!isinclude) { list(tokline, start, end, isstart, islinenum, isaddr, isdebug); } else { list(tln, start, end, isstart, islinenum, isaddr, isdebug); } } else { if (!isinclude) { list(tokline, 0, 0, 1, 0, 0, 0); } else { list(tln, 0, 0, 1, 0, 0, 0); } } break; case 0x08: if (!isinclude) { puts("Assembling program."); bytecount = assemble(tokline, dbg); } else { bytecount += assemble(tln, dbg); } 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]]); printf("%s\n", fn2); if (!tmp_lineidx) { tmp_lineidx = lineidx; } lineidx = 0; linenum = 10; inc_file--; inc_count++; if (inc_file && fp2 != NULL) { fclose(fp2); } fp2 = fopen(fn2, "r"); if (fp2 == NULL) { free(path); fclose(fp); return 2; } } else if (!inc_file && tmp_lineidx) { lineidx = tmp_lineidx; } if (!isinclude) { puts("Finished assembling program."); printf("Total Assembled Program Size: %"PRIu64"/$%"PRIX64" bytes.\n", bytecount, bytecount); } 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; while (tmp[i] != '\0') { if (isspace(tmp[i])) { for (; isspace(tmp[i]); i++); } for (; !isspace(tmp[i]) && tmp[i] != '\0' && tmp[i] != '\n'; arg[j++] = tmp[i++]); arg[j] = '\0'; j = 0; isdebug = (arg[j] == 'd' || !strcasecmp(arg, "debug")); if (isdebug) { dbg = !dbg; if (dbg) { puts("Debug mode has been enabled."); } else { puts("Debug mode has been disabled."); } } i++; } } break; case 0xFF: break; default: if (!isinclude) { address = lex(lex_line, tokline, address, dbg); } else { address = lex(lex_line, tln, address, dbg); } break; } } } free(path); fclose(fp); if (fp2 != NULL) { fclose(fp2); } return 0; }