#include #include #include "gate.h" #include "error.h" #define GATE_MAX 1024 #define INPUT_MAX 1024 #define OUTPUT_MAX 1024 static size_t gate_count; static size_t input_count; static size_t output_count; static struct gate gates[GATE_MAX]; static struct gate inputs[INPUT_MAX]; static struct gate outputs[OUTPUT_MAX]; int count_guard(int c, int max, char *desc) { if (c >= max) { emit_error("Internal: too many %s\n", desc); return 1; } return 0; } int gate_add_generic(struct gate *array, size_t array_index, char *name, enum BINARY (*operation)(enum BINARY, enum BINARY), struct gate *in1, struct gate *in2) { struct gate g = {0}; if (name == NULL) { g.name = NULL; } else { g.name = strdup(name); if (g.name == NULL) { emit_error("strdup failed"); return 1; } } g.operation = operation; g.in1 = in1; g.in2 = in2; array[array_index] = g; return 0; } struct gate* gate_get_input_by_name(char *name) { struct gate *res = NULL; size_t i = 0; for (i = 0; i < input_count; i++) { if (inputs[i].name == NULL) { emit_error("input at index %zd has NULL name, ignoring", i); continue; } if (strcmp(inputs[i].name, name) == 0) { res = &inputs[i]; break; } } return res; } int gate_input_add(char *name) { int res = 0; if (count_guard(input_count, INPUT_MAX, "inputs")) { return 1; } if (gate_get_input_by_name(name) != NULL) { emit_error("Already an input called \"%s\"!\n", name); return 1; } res = gate_add_generic(inputs, input_count, name, logic_and, NULL, NULL); input_count++; return res; } int gate_add(char *name, enum BINARY (*operation)(enum BINARY, enum BINARY), struct gate *in1, struct gate *in2) { if (count_guard(gate_count, GATE_MAX, "gates")) { return 1; } gate_add_generic(gates, gate_count, name, operation, in1, in2); gate_count++; return 0; } void gate_free_all() { size_t i = 0; for (i = 0; i < gate_count; i++) { if (gates[i].name != NULL) { free(gates[i].name); } } } int tick(void) { /* FIXME */ return 1; } void gate_init(void) { gate_count = 0; input_count = 0; memset(gates, 0, sizeof(gates)); memset(inputs, 0, sizeof(inputs)); } void gate_dump(void) { size_t i = 0; emit_info("Gates:\n"); for (i = 0; i < gate_count; i++) { emit_info("gate '%s': %s\n", gates[i].name, gates[i].output == LOGIC_HIGH ? "HIGH" : "LOW"); } } int gate_set_input(char *name, enum BINARY value) { struct gate *g = NULL; if (NULL == (g = gate_get_input_by_name(name))) { emit_error("No such input %s", name); return 1; } g->output = value; return 0; } void gate_update() { size_t i = 0; struct gate *g = NULL; enum BINARY in1 = LOGIC_LOW; enum BINARY in2 = LOGIC_LOW; /* FIXME should be input->output flow path */ /* FIXME data flow doesn't matter yet because gate chaining isn't allowed */ for (i = 0; i < gate_count; i++) { g = &gates[i]; in1 = g->in1->output; in2 = g->in2->output; g->output = (g->operation)(in1, in2); } }