summaryrefslogtreecommitdiff
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
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.
-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;
+}