#include "asmmon.h"
uint16_t linenum = 10;
uint16_t lineidx = 0;
uint16_t stridx = 0;
uint16_t comidx = 0;
uint16_t inc_file = 0;
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;
fixup *fixups = 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(uint16_t start, uint16_t end, uint8_t all, uint8_t ln, uint8_t addr, uint8_t dbg) {
line *s = (!all) ? find_line(start, dbg) : lines ;
line *e = (!all) ? find_line( end, dbg) : last_line;
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];
char ch[6];
do {
token *tok = s->tok;
token *t;
uint8_t am = 0xFF;
uint8_t rs = 0xFF;
if (dbg) {
printf("list(): ");
}
if (ln) {
printf("%u\t\t", s->linenum);
} else if (addr) {
printf("$%"PRIX64":\t\t", s->addr);
}
spaces = s->sspace;
tabs = s->stab;
while (spaces || tabs) {
if (spaces) {
putchar(' ');
spaces--;
}
if (tabs) {
putchar('\t');
tabs--;
}
}
for (; tok && tok->id != TOK_COMMENT && tok >= t; tok = tok->next) {
t = tok;
switch (t->id) {
case TOK_DIR : printf(".%s ", dir_t[t->type] ); break;
case TOK_OPCODE:
for (; j < 3; j++) {
mne_lower[j] = tolower(mne[t->byte][j]);
}
mne_lower[j] = '\0';
j = 0;
printf("%s", mne_lower);
am = t->type;
t = t->next;
if (t && t->id == TOK_RS) {
rs = t->type;
printf("%s", rs_t[t->type]);
}
putchar(' ');
switch (am) {
case IMM : putchar('#'); break;
case IND :
case INDX:
case INDY: putchar('('); break;
}
break;
case TOK_SYM:
case TOK_LABEL:
if (t->type == 1) {
putchar('@');
}
printf("%s", (t->sym) ? t->sym->name : "unknown");
if (t->id == TOK_LABEL) {
putchar(':');
} else if (t == s->tok && t->id == TOK_SYM) {
printf(" = ");
}
break;
case TOK_HEX:
if (t->id == TOK_HEX) {
printf("$%02"PRIX64, t->qword);
} else if (t->id == TOK_DEC) {
case TOK_DEC: printf( "%"PRIu64, t->qword);
} else if (t->id == TOK_BIN) {
case TOK_BIN: if (rs != 0xFF) {
bitnum = (rs << 3);
} else {
opsize += (t->qword <= 0x000000FF) + 0;
opsize += (t->qword > 0x000000FF) + 1;
opsize += (t->qword > 0x0000FFFF) + 2;
opsize += (t->qword > 0xFFFFFFFF) + 3;
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 '\b': ch[j++] = '\\'; ch[j++] = 'b' ; break;
case '\\': ch[j++] = '\\'; ch[j++] = '\\'; 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:
printf(", ");
break;
}
}
break;
case TOK_EXPR:
switch (t->type) {
case EXPR_PLUS : putchar('+'); break;
case EXPR_MINUS: putchar('-'); break;
}
break;
}
}
if (am != 0xFF) {
if (fall) {
fall = 0;
}
switch (am) {
case INDX:
case ZMX:
printf(", x");
if (am == ZMX) {
break;
}
fall = 1;
case INDY:
fall = !fall;
case IND:
putchar(')');
if (!fall) {
break;
}
case ZMY:
printf(", y");
break;
}
}
spaces = s->espace;
tabs = s->etab;
while (spaces || tabs) {
if (spaces) {
putchar(' ');
spaces--;
}
if (tabs) {
putchar('\t');
tabs--;
}
}
if (tok && tok->id == TOK_COMMENT) {
printf(";%s", (tok->str) ? tok->str : "");
}
puts("");
s = s->next;
} while (s != e && s);
}
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;
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 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);
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, isdebug);
} else {
list(0, 0, 1, 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.");
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) {
free(path);
fclose(fp);
cleanup();
return 2;
}
printf("Including %s\n", string[incl[inc_count++]]);
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;
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:
address = lex(lex_line, address, dbg);
break;
}
}
}
free(path);
if (fp != NULL) {
fclose(fp);
}
if (fp2 != NULL) {
fclose(fp2);
}
cleanup();
return 0;
}