#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;
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;
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('<');
case EXPR_HIGH : putchar('<'); break;
case EXPR_RSHFT: putchar('>');
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 && !t->next) {
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;
}
case EIND:
if (am == EIND) {
putchar('e');
}
case INDY:
case IND :
putchar(')');
if (am == IND || am == EIND) {
break;
}
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);
}
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;
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_X :
case PTOK_Y :
case PTOK_S :
case PTOK_P :
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, "set" )) << 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) {
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;
}