summaryrefslogtreecommitdiff
path: root/igen
diff options
context:
space:
mode:
authormrb0nk500 <b0nk@b0nk.xyz>2022-02-13 20:20:59 -0400
committermrb0nk500 <b0nk@b0nk.xyz>2022-02-13 20:20:59 -0400
commitf478e6c1223cc8370fa51d44b9244ec25be99788 (patch)
tree4abe8889888c0b098ea99ee020c446254822a923 /igen
parent6833f6bc2a5730169084c74d8e8fc0b76666b2a0 (diff)
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.
Diffstat (limited to 'igen')
-rw-r--r--igen/igen.c30
-rw-r--r--igen/lexer.c91
-rw-r--r--igen/lexer.h46
-rw-r--r--igen/misc.c77
-rw-r--r--igen/misc.h7
-rw-r--r--igen/sux-igen/addr-modes.igen91
-rw-r--r--igen/sux-igen/inst.igen245
-rw-r--r--igen/sux-igen/utils.igen50
8 files changed, 637 insertions, 0 deletions
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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "lexer.h"
+#include "misc.h"
+
+void usage(const char *name) {
+ printf("Usage: %s <file>\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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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 <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#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;
+}