summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Phillips <david@sighup.nz>2017-12-27 21:21:54 +1300
committerDavid Phillips <david@sighup.nz>2017-12-27 21:21:54 +1300
commitf23abfdde683aee4b808f2795af1a1418125156c (patch)
treef6faf313a32395b41ca4db628ef2eb4d4d950c1f
downloadhence-f23abfdde683aee4b808f2795af1a1418125156c.tar.xz
Initual dump of partial work on parser and data structure
-rw-r--r--.gitignore3
-rw-r--r--Makefile7
-rw-r--r--adder.lg9
-rw-r--r--error.h4
-rw-r--r--logic.c107
-rw-r--r--logic.h18
-rw-r--r--parser.c188
-rw-r--r--simulator.c8
-rw-r--r--wire.c106
-rw-r--r--wire.h27
10 files changed, 477 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7bb37c6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.o
+simulator
+parser
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..651c53c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,7 @@
+CFLAGS += "-std=c99"
+
+all: simulator
+
+simulator: simulator.o wire.o logic.o
+
+parser: parser.o wire.o logic.o
diff --git a/adder.lg b/adder.lg
new file mode 100644
index 0000000..a883081
--- /dev/null
+++ b/adder.lg
@@ -0,0 +1,9 @@
+module adder
+
+node input a
+node input b
+node output r0
+node output r1
+
+expr r0: xor a b
+expr r1: and a b
diff --git a/error.h b/error.h
new file mode 100644
index 0000000..e4f5351
--- /dev/null
+++ b/error.h
@@ -0,0 +1,4 @@
+#include <stdio.h>
+
+#define emit_error(...) fprintf(stderr, "Error: " __VA_ARGS__)
+#define emit_info(...) fprintf(stdout, "Info : " __VA_ARGS__)
diff --git a/logic.c b/logic.c
new file mode 100644
index 0000000..8eabb65
--- /dev/null
+++ b/logic.c
@@ -0,0 +1,107 @@
+#define NDEBUG
+#include <assert.h>
+
+#include "logic.h"
+#include "error.h"
+
+enum BINARY
+logic_not(enum BINARY input) {
+ switch (input) {
+ case LOGIC_HIGH:
+ return LOGIC_LOW;
+ case LOGIC_LOW:
+ return LOGIC_HIGH;
+ default:
+ emit_error("Severe: Invalid logic value found\n");
+ }
+}
+
+enum BINARY
+logic_and(enum BINARY a, enum BINARY b) {
+ if (a == LOGIC_HIGH && b == LOGIC_HIGH)
+ return LOGIC_HIGH;
+ else
+ return LOGIC_LOW;
+}
+
+enum BINARY
+logic_or(enum BINARY a, enum BINARY b) {
+ if (a == LOGIC_HIGH || b == LOGIC_HIGH)
+ return LOGIC_HIGH;
+ else
+ return LOGIC_LOW;
+}
+
+enum BINARY
+logic_xor(enum BINARY a, enum BINARY b) {
+ if ( (a == LOGIC_HIGH && b == LOGIC_LOW)
+ || (a == LOGIC_LOW && b == LOGIC_HIGH))
+ return LOGIC_HIGH;
+ else
+ return LOGIC_LOW;
+}
+
+enum BINARY
+logic_nand(enum BINARY a, enum BINARY b) {
+ return logic_not(logic_and(a, b));
+}
+
+enum BINARY
+logic_nor(enum BINARY a, enum BINARY b) {
+ return logic_not(logic_or(a, b));
+}
+
+void
+logic_test_and() {
+ emit_info("Testing AND\n");
+ assert(LOGIC_HIGH == logic_and(LOGIC_HIGH, LOGIC_HIGH));
+ assert(LOGIC_LOW == logic_and(LOGIC_HIGH, LOGIC_LOW ));
+ assert(LOGIC_LOW == logic_and(LOGIC_LOW , LOGIC_HIGH));
+ assert(LOGIC_LOW == logic_and(LOGIC_LOW , LOGIC_LOW ));
+}
+
+void
+logic_test_or() {
+ emit_info("Testing OR\n");
+ assert(LOGIC_HIGH == logic_or(LOGIC_HIGH, LOGIC_HIGH));
+ assert(LOGIC_HIGH == logic_or(LOGIC_HIGH, LOGIC_LOW ));
+ assert(LOGIC_HIGH == logic_or(LOGIC_LOW , LOGIC_HIGH));
+ assert(LOGIC_LOW == logic_or(LOGIC_LOW , LOGIC_LOW ));
+}
+
+void
+logic_test_xor() {
+ emit_info("Testing XOR\n");
+ assert(LOGIC_HIGH == logic_xor(LOGIC_HIGH, LOGIC_LOW ));
+ assert(LOGIC_HIGH == logic_xor(LOGIC_LOW , LOGIC_HIGH));
+ assert(LOGIC_LOW == logic_xor(LOGIC_HIGH, LOGIC_HIGH));
+ assert(LOGIC_LOW == logic_xor(LOGIC_LOW , LOGIC_LOW ));
+}
+
+void
+logic_test_nand() {
+ emit_info("Testing NAND\n");
+ assert(LOGIC_LOW == logic_nand(LOGIC_HIGH, LOGIC_HIGH));
+ assert(LOGIC_HIGH == logic_nand(LOGIC_HIGH, LOGIC_LOW ));
+ assert(LOGIC_HIGH == logic_nand(LOGIC_LOW , LOGIC_HIGH));
+ assert(LOGIC_HIGH == logic_nand(LOGIC_LOW , LOGIC_LOW ));
+}
+
+void
+logic_test_nor() {
+ emit_info("Testing NOR\n");
+ assert(LOGIC_HIGH == logic_nor(LOGIC_LOW , LOGIC_LOW ));
+ assert(LOGIC_LOW == logic_nor(LOGIC_LOW , LOGIC_HIGH));
+ assert(LOGIC_LOW == logic_nor(LOGIC_HIGH, LOGIC_LOW ));
+ assert(LOGIC_LOW == logic_nor(LOGIC_HIGH, LOGIC_HIGH));
+}
+
+
+void
+logic_test() {
+ logic_test_and();
+ logic_test_or();
+ logic_test_nand();
+ logic_test_nor();
+ logic_test_xor();
+}
diff --git a/logic.h b/logic.h
new file mode 100644
index 0000000..95d2663
--- /dev/null
+++ b/logic.h
@@ -0,0 +1,18 @@
+#ifndef LOGIC_H
+#define LOGIC_H
+
+enum BINARY {
+ LOGIC_HIGH,
+ LOGIC_LOW
+};
+
+enum BINARY logic_not(enum BINARY input);
+enum BINARY logic_and(enum BINARY a, enum BINARY b);
+enum BINARY logic_or(enum BINARY a, enum BINARY b);
+enum BINARY logic_xor(enum BINARY a, enum BINARY b);
+enum BINARY logic_nand(enum BINARY a, enum BINARY b);
+enum BINARY logic_nor(enum BINARY a, enum BINARY b);
+
+void logic_test();
+
+#endif
diff --git a/parser.c b/parser.c
new file mode 100644
index 0000000..b2218b1
--- /dev/null
+++ b/parser.c
@@ -0,0 +1,188 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "error.h"
+#include "logic.h"
+#include "wire.h"
+
+enum STATEMENT_TYPE {
+ DECL_EXPR,
+ DECL_INPUT,
+ DECL_OUTPUT,
+ MODULE_NAME
+};
+
+enum UNARY_OPERATOR {
+ UOP_NOT
+};
+
+enum BINARY_OPERATOR {
+ BOP_AND,
+ BOR_OR,
+ BOP_NAND,
+ BOP_NOR,
+ BOP_XOR
+};
+
+struct tok_lookup {
+ char *str;
+ int (*handler)(char*);
+};
+
+struct bop_lookup {
+ char *str;
+ enum BINARY (*handler)(enum BINARY, enum BINARY);
+};
+
+struct uop_lookup {
+ char *str;
+ enum BINARY (*handler)(enum BINARY);
+};
+
+static struct uop_lookup uop_handlers[] = {
+ {.str = "not", .handler = logic_not},
+};
+
+static struct bop_lookup bop_handlers[] = {
+ {.str = "and", .handler = logic_and},
+ {.str = "or", .handler = logic_or},
+ {.str = "nand", .handler = logic_nand},
+ {.str = "nor", .handler = logic_nor},
+ {.str = "xor", .handler = logic_xor}
+};
+
+int parse_uop(char *str, enum BINARY (*handler)(enum BINARY)) {
+ /**/
+ (void)str;
+ (void)handler;
+ emit_error("uop unimplemented\n");
+ return 0;
+}
+
+int parse_bop(char *str, enum BINARY (*handler)(enum BINARY, enum BINARY)) {
+ /**/
+ (void)str;
+ (void)handler;
+ emit_error("bop unimplemented\n");
+ return 0;
+}
+
+int
+parse_op(char *str) {
+ int match = 0;
+ size_t i = 0;
+
+ match = 0;
+ for (i = 0; i < sizeof(bop_handlers)/sizeof(bop_handlers[0]); i++) {
+ if (strcmp(bop_handlers[i].str, str) == 0) {
+ match = 1;
+ if (parse_bop("FIXME", bop_handlers[i].handler)) {
+ return 1;
+ }
+ }
+ }
+ for (i = 0; i < sizeof(uop_handlers)/sizeof(uop_handlers[0]); i++) {
+ if (strcmp(uop_handlers[i].str, str) == 0) {
+ match = 1;
+ if (parse_uop("FIXME", uop_handlers[i].handler)) {
+ return 1;
+ }
+ }
+ }
+ if (match == 0) {
+ emit_error("Invalid operator \"%s\"\n", str);
+ return 1;
+ }
+ return 0;
+}
+
+int
+parse_expr(char *str) {
+ printf("expression %s\n", str);
+ return 0;
+}
+
+int
+parse_node(char *str) {
+ enum NODE_TYPE type = NODE_OUTPUT;
+
+ strtok(str, " ");
+ if (strcmp(str, "output") == 0) {
+ type = NODE_OUTPUT;
+ } else if (strcmp(str, "input") == 0) {
+ type = NODE_INPUT;
+ } else {
+ emit_error("'%s' is not a valid node type\n", str);
+ return 1;
+ }
+
+ printf("FIXME need to add node of type %s\n", type == NODE_OUTPUT ? "oot" : "innnn");
+ return 0;
+}
+
+int
+parse_module(char *str) {
+ printf("FIXME module name is \"%s\" but modules are not implemented\n", str);
+ return 0;
+}
+
+
+
+
+static struct tok_lookup tok_handlers[] = {
+ {.str = "node", .handler = parse_node},
+ {.str = "module", .handler = parse_module},
+ {.str = "expr", .handler = parse_expr}
+};
+
+
+
+
+
+int
+parse_line(char *line) {
+ size_t i = 0;
+ char *tok = line;
+ char *delim = " ";
+ int match = 0;
+
+ if ( strlen(line) == 0
+ || (strlen(line) == 1 && isspace(line[0]))) {
+ return 0;
+ }
+
+ tok = strtok(line, delim);
+
+ match = 0;
+ for (i = 0; i < sizeof(tok_handlers)/sizeof(tok_handlers[0]); i++) {
+ if (strcmp(tok_handlers[i].str, tok) == 0) {
+ match = 1;
+ if ((tok_handlers[i].handler)(&tok[strlen(tok)+1])) {
+ return 1;
+ }
+ }
+ }
+
+ if (match == 0) {
+ emit_error("invalid token \"%s\"", tok);
+ return 1;
+ }
+ return 0;
+}
+
+int main(void) {
+ char buf[4096];
+ FILE *fd = stdin;
+
+ while (NULL != fgets(buf, sizeof(buf), fd)) {
+ buf[strcspn(buf, "\r\n")] = '\0';
+ if (parse_line(buf)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
diff --git a/simulator.c b/simulator.c
new file mode 100644
index 0000000..389adc3
--- /dev/null
+++ b/simulator.c
@@ -0,0 +1,8 @@
+#include "wire.h"
+#include "logic.h"
+
+int main(int argc, char **argv) {
+ logic_test();
+ wire_init();
+ return 0;
+}
diff --git a/wire.c b/wire.c
new file mode 100644
index 0000000..e181d83
--- /dev/null
+++ b/wire.c
@@ -0,0 +1,106 @@
+#include <string.h>
+
+#include "wire.h"
+#include "error.h"
+
+#define WIRE_MAX 1024
+#define NODE_MAX 1024
+
+static size_t wire_count;
+static size_t node_count;
+
+static struct wire wires[WIRE_MAX];
+static struct node nodes[NODE_MAX];
+
+int
+wire_count_guard(void) {
+ if (wire_count >= WIRE_MAX) {
+ emit_error("Internal: too many wires\n");
+ }
+ return 1;
+}
+
+/* check if the nodes in a wire are allowed to be joined together */
+int
+wire_nodes_valid(struct wire *w) {
+ /* FIXME needs to be more explicit if more than NODE_OUTPUT and NODE_INPUT
+ * out are added to node types */
+ if (w->b->type == w->b->type) {
+ emit_error("Cannot wire %sput to node of same type\n",
+ w->a->type == NODE_OUTPUT ? "out" : "in" );
+ return 1;
+ }
+ return 0;
+}
+
+int
+wire_add(size_t aoffs, size_t boffs) {
+ struct wire w = {0};
+
+ if (wire_count_guard()) {
+ return 1;
+ }
+
+ if (aoffs >= NODE_MAX || boffs >= NODE_MAX) {
+ emit_error("Internal: cannot wire between node(s) outside allowable range\n");
+ return 1;
+ }
+
+ /* FIXME check that nodes are initialised? */
+
+ w.a = &nodes[aoffs];
+ w.b = &nodes[boffs];
+
+ if (wire_nodes_valid(&w)) {
+ return 1;
+ }
+
+ wires[wire_count++] = w;
+
+ return 0;
+}
+
+int
+node_update(void) {
+ size_t i = 0;
+ struct node *na;
+ struct node *nb;
+
+ if (wire_count_guard()) {
+ return 1;
+ }
+
+ for (i = 0; i < wire_count; i++) {
+ na = wires[i].a;
+ nb = wires[i].b;
+ if (na->type == NODE_OUTPUT && nb->type == NODE_INPUT) {
+ nb->value = na->value;
+ }
+
+ if (na->type == NODE_INPUT && nb->type == NODE_OUTPUT) {
+ na->value = nb->value;
+ }
+ }
+ return 0;
+}
+
+
+int
+tick(void) {
+ nodes[0].value = logic_not(nodes[0].value);
+ node_update();
+ return 0;
+}
+
+void
+wire_init(void) {
+ wire_count = 0;
+ memset(wires, 0, sizeof(wires));
+ memset(nodes, 0, sizeof(nodes));
+
+ /* zeroth node is the clock source */
+ node_count = 1;
+ nodes[0].type = NODE_OUTPUT;
+ nodes[0].value = 0;
+}
+
diff --git a/wire.h b/wire.h
new file mode 100644
index 0000000..74ff29b
--- /dev/null
+++ b/wire.h
@@ -0,0 +1,27 @@
+#ifndef WIRE_H
+#define WIRE_H
+
+#include <stddef.h>
+
+#include "logic.h"
+
+enum NODE_TYPE {
+ NODE_OUTPUT,
+ NODE_INPUT
+};
+
+struct node {
+ enum NODE_TYPE type;
+ enum BINARY value;
+};
+
+struct wire {
+ struct node *a;
+ struct node *b;
+};
+
+int wire_add(size_t aoffs, size_t boffs);
+int tick(void);
+void wire_init(void);
+
+#endif