From f478e6c1223cc8370fa51d44b9244ec25be99788 Mon Sep 17 00:00:00 2001 From: mrb0nk500 Date: Sun, 13 Feb 2022 20:20:59 -0400 Subject: igen: Start work on writing an instruction handler generator. This will make it easier in the long run to modify instructions, add new instructions, and move the opcode tables around. --- igen/igen.c | 30 ++++++ igen/lexer.c | 91 ++++++++++++++++ igen/lexer.h | 46 ++++++++ igen/misc.c | 77 +++++++++++++ igen/misc.h | 7 ++ igen/sux-igen/addr-modes.igen | 91 ++++++++++++++++ igen/sux-igen/inst.igen | 245 ++++++++++++++++++++++++++++++++++++++++++ igen/sux-igen/utils.igen | 50 +++++++++ 8 files changed, 637 insertions(+) create mode 100644 igen/igen.c create mode 100644 igen/lexer.c create mode 100644 igen/lexer.h create mode 100644 igen/misc.c create mode 100644 igen/misc.h create mode 100644 igen/sux-igen/addr-modes.igen create mode 100644 igen/sux-igen/inst.igen create mode 100644 igen/sux-igen/utils.igen diff --git a/igen/igen.c b/igen/igen.c new file mode 100644 index 0000000..fa9f10f --- /dev/null +++ b/igen/igen.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include "lexer.h" +#include "misc.h" + +void usage(const char *name) { + printf("Usage: %s \n", name); +} + +int main(int argc, char **argv) { + char *buf; + long file_size = 0; + int dbg = 0; + int ret = 0; + if (argc < 2) { + usage(argv[0]); + ret = 1; + } + buf = read_file(argc[1], &file_size); + if (buf == NULL) { + printf("Error: read_file() returned NULL.\n"); + usage(argv[0]); + ret = 1; + } + + ret = lex(buf, dbg); + return ret; +} diff --git a/igen/lexer.c b/igen/lexer.c new file mode 100644 index 0000000..275bcdd --- /dev/null +++ b/igen/lexer.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include "lexer.h" +#include "misc.h" + +atom get_token_id(const char c, const int dbg) { + switch (c) { + case '(': return ATOM_LBRACK; + case ')': return ATOM_RBRACK; + case '/': return ATOM_SLASH; + case '+': return ATOM_PLUS; + case '-': return ATOM_MINUS; + case '*': return ATOM_ASTR; + case '%': return ATOM_PRCNT; + case '&': return ATOM_AMPR; + case '|': return ATOM_PIPE; + case '^': return ATOM_CARROT; + case '#': return ATOM_HASH; + case ':': return ATOM_COL; + case ';': return ATOM_SCOL; + case ' ': return ATOM_SPACE; + case '_': return ATOM_USCORE; + case '=': return ATOM_EQUAL; + case '.': return ATOM_DOT; + case '?': return ATOM_QMARK; + case '!': return ATOM_BANG; + case '<': return ATOM_LT; + case '>': return ATOM_GT; + case '%': return ATOM_PERCENT; + case ',': return ATOM_COMMA; + case '\\': return ATOM_BSLASH; + case '\"': return ATOM_QUOTE; + case '\'': return ATOM_SQUOTE; + case '\t': return ATOM_TAB; + case '\n': return ATOM_NLINE; + default: + if (isalpha(c)) { + return ATOM_ALPHA; + } else if (isdigit(c)) { + return ATOM_NUM; + } + break; + } + return ATOM_NONE; +} + +int get_atom_span(const char *str, const atom *atoms, int inv, int dbg) { + int i; + for (i = 0; str[i] != '\0'; ++i) { + const enum atom atom = get_atom_id(str[i], dbg); + for (int j = 0; atoms[j] != ATOM_NONE; ++j) { + const int is_done = (inv) ? (atom == atoms[j]) : (atom != atoms[j]); + if (is_done) { + return i; + } + } + } + return i; +} + +int lex(char *str, int dbg) { + int in_inst_stmt = 0; + lexeme *lex_start = NULL; + lexeme *lex_end = NULL; + + for (int i = 0; str[i] != '\0'; ++i) { + atom atom_id = get_atom_id(str[i], dbg); + switch (atom_id) { + case ATOM_PERCENT: + if (get_atom_id(str[++i]) == ATOM_PERCENT) { + in_inst_stmt = !in_inst_stmt; + } + break; + case ATOM_LBRACK: + break; + case ATOM_ALPHA: + do { + const int ident_len = get_atom_span(&str[i], (const atom []) { + ATOM_ALPHA, + ATOM_USCORE, + ATOM_NUM, + ATOM_NONE + }, 0, dbg); + char *ident = calloc(ident_len+1, sizeof(char)); + } while(0); + break; + } + } +} diff --git a/igen/lexer.h b/igen/lexer.h new file mode 100644 index 0000000..ba81cb1 --- /dev/null +++ b/igen/lexer.h @@ -0,0 +1,46 @@ +#ifndef LEXER_H +#define LEXER_H + +typedef enum atom atom; +typedef struct lexeme lexeme; + +enum atom { + ATOM_LBRACK, + ATOM_RBRACK, + ATOM_SLASH, + ATOM_PLUS, + ATOM_MINUS, + ATOM_ASTR, + ATOM_PRCNT, + ATOM_AMPR, + ATOM_PIPE, + ATOM_CARROT, + ATOM_HASH, + ATOM_COL, + ATOM_SCOL, + ATOM_SPACE, + ATOM_USCORE, + ATOM_EQUAL, + ATOM_DOT, + ATOM_QMARK, + ATOM_BANG, + ATOM_LT, + ATOM_GT, + ATOM_PERCENT, + ATOM_COMMA, + ATOM_BSLASH, + ATOM_QUOTE, + ATOM_SQUOTE, + ATOM_TAB, + ATOM_NLINE, + ATOM_ALPHA, + ATOM_NUM, + ATOM_NONE, + NUM_ATOMS +}; + +struct lexeme { +}; + +extern int lex(char *str, int dbg); +#endif diff --git a/igen/misc.c b/igen/misc.c new file mode 100644 index 0000000..ba8c755 --- /dev/null +++ b/igen/misc.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include +#include "misc.h" + +char *read_file(const char *filename, long *size) { + /* Open the file. */ + FILE *fp = fopen(filename, "r"); + /* Size of the file, in bytes. */ + long filesize = 0; + /* Buffer of the file contents. */ + char *buf; + + /* Return NULL, if we couldn't open the file. */ + if (fp == NULL) { + return NULL; + } + + /* Return NULL, if we couldn't seek to the end of the file. */ + if (fseek(fp, 0L, SEEK_END)) { + fclose(fp); + return NULL; + } + + /* Get the size of the file, in bytes. */ + filesize = ftell(fp); + + /* Return NULL, if the returned size is negative. */ + if (filesize < 0) { + fclose(fp); + return NULL; + } + + /* Allocate enough space for the entire file, plus one. */ + buf = calloc(filesize+1, sizeof(char)); + + /* Return NULL, if the buffer wasn't allocated. */ + if (buf == NULL) { + fclose(fp); + return NULL; + } + + /* Seek back to the start of the file. */ + rewind(fp); + /* Read the entire file contents into the buffer. */ + fread(buf, sizeof(char), filesize, fp); + /* Close the file. */ + fclose(fp); + + /* Return the filesize, in bytes. */ + *size = filesize; + /* Return the buffer. */ + return buf; +} + +char *get_line(char **str) { + char *s; + size_t i; + char *tmp = *str; + + for (i = 0; tmp[i] != '\n' && tmp[i] != '\0'; i++); + + s = calloc(i+1, sizeof(char)); + memcpy(s, *str, i); + + *str += (i+1); + return s; +} + +char *make_str(const char *str) { + const size_t length = strlen(str); + char *s = calloc(length+1, sizeof(char)); + memcpy(s, str, length+1); + return s; +} diff --git a/igen/misc.h b/igen/misc.h new file mode 100644 index 0000000..9216250 --- /dev/null +++ b/igen/misc.h @@ -0,0 +1,7 @@ +#ifndef MISC_H +#define MISC_H + +extern char *read_file(const char *filename, long *size); +extern char *get_line(char **str); +extern char *make_str(const char *str); +#endif diff --git a/igen/sux-igen/addr-modes.igen b/igen/sux-igen/addr-modes.igen new file mode 100644 index 0000000..3780ed2 --- /dev/null +++ b/igen/sux-igen/addr-modes.igen @@ -0,0 +1,91 @@ +#include "utils.igen" + +%% + +/* +am((abs|zm)[xy]?) { + if (am == zmx || am == absx) { + idx = cpu->x; + } else if (am == zmy || am == absy) { + idx = cpu->y; + } + + if (am == abs || am == absx || am == absy) { + is_abs = 1; + } + + size = ((prefix & 0xC) >> 1) | is_abs; + addr = read(cpu->pc, size) + idx; + value = read(addr, rs); +} + +am((a)?ind([xy])?) { + if (am == indx || am == aindx) { + idx = cpu->x; + pre_idx = 1; + } else if (am == indy || am == aindy) { + idx = cpu->y; + } + + if (am == aind || am == aindx || am == aindy) { + is_abs = 1; + } + + size = ((prefix & 0xC) >> 1) | is_abs; + + if (pre_idx) { + addr = read(read(cpu->pc + idx, size), 7); + } else { + addr = read(read(cpu->pc, size), 7) + idx; + } + + value = read(addr, rs); +} + +am(eind) { + addr = cpu->e; + value = read(addr, rs); +} +*/ + +am(abs|zm([xy])?) { + if (am == abs) { + mem_type = ABS; + } else { + if (am == zmx) { + idx = cpu->x; + } else if (am == zmy) { + idx = cpu->y; + } + mem_type = ZM; + } + addr = read_addr(prefix, mem_type) + idx; + value = read(addr, rs); +} + +am(ind([xy])?) { + if (am == indx) { + idx = cpu->x; + pre_idx = 1; + } else if (am == indy) { + idx = cpu->y; + } + mem_type = ZM; + addr = ind_idx_addr(prefix, mem_type, idx, pre_idx); + value = read(addr, rs); +} + +am(rel) { + addr = rel_addr(prefix); +} + +am(imm) { + value = read(cpu->pc, rs); + cpu->pc += rs+1; +} + +am(breg) { + value = cpu->b; +} + +%% diff --git a/igen/sux-igen/inst.igen b/igen/sux-igen/inst.igen new file mode 100644 index 0000000..791ad2c --- /dev/null +++ b/igen/sux-igen/inst.igen @@ -0,0 +1,245 @@ +#include "utils.igen" +#include "addr-modes.igen" + +%% + +(ad|sb|breg(in|de))c, and, (or|st|ld|t[bxy]|p[hl])a, xor, (ls|ro)[lr], mul, div, asr, cmp { + reg = &cpu->a; +} + +(ld|st|cp|in|de|ta|p[hl])b { + reg = &cpu->b; +} + +(ld|st|cp|in|de|t[ays]|p[hl])x { + reg = &cpu->x; +} + +(ld|st|cp|in|de|t[ax]|p[hl])y { + reg = &cpu->y; +} + +txs { + reg = &cpu->sp; +} + +cps, (cl|se)[cio], clv, b(po|n[ge]|[cv][sc]|eq|r[ak]), p[hl]p { + reg = &cpu->ps; +} + +ta[bxy] { + reg2 = &cpu->a; +} + +tba, ~breg(div) { + reg2 = &cpu->b; +} + +tx[ay], breg(div) { + reg2 = &cpu->x; +} + +ty[ax] { + reg2 = &cpu->y; +} + +tsx { + reg2 = &cpu->sp; +} + +ld[abxy] { + *reg = value; + update_flags_nz(value); +} + +st[abxy] { + value = *reg; + write(value, addr, rs); +} + +(in|de)[cbxy] { + if (addr_mode == impl) { + value = *reg; + } + if (inst.match[0] == in) { + ++value; + } else if (inst.match[0] == de) { + --value; + } + if (addr_mode != impl) { + msb = rs*8; + write(value, addr, rs); + } else { + *reg = value; + } + update_flags_nz(value); +} + +ph[abxyp] { + if (inst == php) { + rs = 0; + } + push(*reg, rs); +} + +pl[abxyp] { + if (inst == plp) { + rs = 0; + } + *reg = pull(rs); +} + +/* +ora, and, xor { + switch (inst) { + case and: sum = *reg & value; break; + case ora: sum = *reg | value; break; + case xor: sum = *reg ^ value; break; + } + *reg = sum; + update_flags_nz(sum); +} +*/ + +ora { + sum = *reg | value; + *reg = sum; + update_flags_nz(sum); +} + +and { + sum = *reg & value; + *reg = sum; + update_flags_nz(sum); +} + +xor { + sum = *reg ^ value; + *reg = sum; + update_flags_nz(sum); +} + +(se|cl)c { + cpu->ps.C = (inst == sec); +} + +(se|cl)i { + cpu->ps.I = (inst == sei); +} + +(se|cl)o { + if (ext == base && mode == base) { + cpu->ps.O = (inst == seo); + } +} + +clv { + cpu->ps.V = 0; +} + +cps { + cpu->ps = 0; +} + +b(po|ng) { + cpu->pc = jump(addr, cpu->pc, get_flag(inst, bpo, cpu->ps.N)); +} + +bc[sc] { + cpu->pc = jump(addr, cpu->pc, get_flag(inst, bcs, cpu->ps.C)); +} + +b(ne|eq) { + cpu->pc = jump(addr, cpu->pc, get_flag(inst, beq, cpu->ps.Z)); +} + +bv[sc] { + cpu->pc = jump(addr, cpu->pc, get_flag(inst, bvs, cpu->ps.V)); +} + +bra, j(mp|sr) { + if (inst == jsr) { + push(cpu->pc, (rs) ? rs : 7); + } + cpu->pc = jump(addr, cpu->pc, 1); +} + +intr(irq|nmi|reset), brk, wai { + if (inst == nmi) { + addr = 0xFFA0; + } else if (inst == reset) { + addr = 0xFFC0; + } else if (inst == irq) { + addr = 0xFFE0; + } else { + addr = 0xFFF0; + } + + if (inst != reset) { + if (!cpu->is_wait) { + push(cpu->pc, 7); + push(cpu->ps, 0); + cpu->ps.I = 1; + } + cpu->is_wait = (inst == wai); + } + if (inst != wai) { + addr = read(addr, 7); + cpu->pc = jump(addr, cpu->pc, 1); + } +} + +rt[si] { + if (inst == rti) { + cpu->ps = pull(0); + } + cpu->pc = pull(7); +} + +(ad|sb)c { + if (inst == sbc) { + value = ~value; + } + *reg = adc(*reg, value, cpu->ps.C); +} + +c(mp|p[bxy]) { + adc(*reg, ~value, 1); +} + +(asr|ls[lr]) { + if (inst == lsl) { + sum = (value < msb) ? shift(*reg, value, 0, <<) : 0; + cpu->ps.C = (*reg >> (msb-(value+!value))) & 1; + } else { + if (inst == asr) { + sign = -(uint64_t)(*reg >> (msb-1)) << (msb-1)-value; + } + sum = (value < msb) ? shift(*reg, value, sign, >>) : 0; + cpu->ps.C = (*reg >> (value-(value != 0))) & 1; + } +} + +ro[lr] { + if (inst == rol) { + rotate(sum, *reg, value, <<, >>, cpu->ps.C, cpu->ps.C << (value-1)); + cpu->ps.C = (*reg >> (msb-(value+!value))) & 1; + } else { + rotate(sum, *reg, value, >>, <<, cpu->ps.C << (msb-1), cpu->ps.C << (msb-value)); + cpu->ps.C = (*reg >> (value-(value != 0))) & 1; + } +} + +mul { + *reg = mul(*reg, value); +} + +div { + *reg = div(*reg, value, reg2); +} + +t(a[bxy]|ba|x[ays]|y[ax]|sx) { + *reg = *reg2; + update_flags_nz(*reg); +} +%% diff --git a/igen/sux-igen/utils.igen b/igen/sux-igen/utils.igen new file mode 100644 index 0000000..7385117 --- /dev/null +++ b/igen/sux-igen/utils.igen @@ -0,0 +1,50 @@ +update_flags_nz(value) { + cpu->ps.N = bit(value, msb-1); + cpu->ps.Z = value == 0; +} + +get_flag(name, match, flag) { + if (name == match) { + return flag; + } else { + return !flag; + } +} + +jump(addr, fallback, flag) { + if (flag) { + return addr; + } else { + return fallback; + } +} + +read(addr, size) { + return read_value(addr, size); +} + +write(value, addr, size) { + write_value(value, addr, size); +} + +adc(a, b, carry) { + sum = a + b + carry; + update_flags_nz(sum); + cpu->ps.C = sum < b; + cpu->ps.V = bit(a^b, msb-1) && bit(a^sum, msb-1); + return sum; +} + +mul(a, b) { + sum = a * b; + update_flags_nz(sum); + cpu->ps.V = bit(a^b, msb-1) && bit(a^sum, msb-1); + return sum; +} + +div(a, b, *rem) { + sum = a / b; + *rem = a % b; + update_flags_nz(sum); + return sum; +} -- cgit v1.2.3-13-gbd6f