From f23abfdde683aee4b808f2795af1a1418125156c Mon Sep 17 00:00:00 2001 From: David Phillips Date: Wed, 27 Dec 2017 21:21:54 +1300 Subject: Initual dump of partial work on parser and data structure --- .gitignore | 3 + Makefile | 7 +++ adder.lg | 9 +++ error.h | 4 ++ logic.c | 107 ++++++++++++++++++++++++++++++++++ logic.h | 18 ++++++ parser.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ simulator.c | 8 +++ wire.c | 106 ++++++++++++++++++++++++++++++++++ wire.h | 27 +++++++++ 10 files changed, 477 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 adder.lg create mode 100644 error.h create mode 100644 logic.c create mode 100644 logic.h create mode 100644 parser.c create mode 100644 simulator.c create mode 100644 wire.c create mode 100644 wire.h 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 + +#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 + +#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 +#include +#include + +#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 + +#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 + +#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 -- cgit v1.1