From 7950298bf80fd1d1f311e7bd4f75b442df7c679c Mon Sep 17 00:00:00 2001 From: Alex AUVOLAT Date: Mon, 4 Nov 2013 23:47:56 +0100 Subject: C simulator quite completed. --- csim/load.c | 39 +++++++++++-- csim/main.c | 4 +- csim/sim.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ csim/sim.h | 22 +++++-- 4 files changed, 242 insertions(+), 13 deletions(-) (limited to 'csim') diff --git a/csim/load.c b/csim/load.c index 397af5a..05c5f70 100644 --- a/csim/load.c +++ b/csim/load.c @@ -11,16 +11,39 @@ #include "sim.h" +t_value read_bool(FILE *stream, t_value *mask) { + t_value r = 0; + t_value pow = 1; + + char c; + if (mask != NULL) *mask = 0; + + for(;;) { + fscanf(stream, "%c", &c); + if (c == '1') { + r |= pow; + } else if (c != '0') { + break; + } + if (mask != NULL) (*mask) |= pow; + + pow *= 2; + } + + return r; +} + void read_arg(FILE *stream, t_arg *dest) { - if (fscanf(stream, "$%Ld ", &(dest->val)) > 0) { - dest->source_var = -1; + dest->mask = 0; + if (fscanf(stream, "$") > 0) { + dest->Val = read_bool(stream, &dest->mask); } else { - fscanf(stream, "%d ", &(dest->source_var)); + fscanf(stream, "%d ", &(dest->SrcVar)); } } t_program *load_dumb_netlist (FILE *stream) { - int i; + int i, j; // let us suppose that the input to be read is well-formed. t_program *p = malloc(sizeof(t_program)); @@ -31,7 +54,9 @@ t_program *load_dumb_netlist (FILE *stream) { for (i = 0; i < p->n_vars; i++) { fscanf(stream, "%d ", &(p->vars[i].size)); - p->vars[i].mask = (0xFFFFFFFFFFFFFFFF >> (64 - p->vars[i].size)); + for(j = 0; j < p->vars[i].size; j++) { + p->vars[i].mask = (p->vars[i].mask << 1) | 1; + } p->vars[i].name = malloc(42); // let's bet that the name of a variable will never be longer than 42 chars fscanf(stream, "%s\n", p->vars[i].name); @@ -84,7 +109,7 @@ t_program *load_dumb_netlist (FILE *stream) { fscanf(stream, "%d %d ", &(p->eqs[i].Ram.addr_size), &(p->eqs[i].Ram.word_size)); read_arg(stream, &(p->eqs[i].Ram.read_addr)); read_arg(stream, &(p->eqs[i].Ram.write_enable)); - read_arg(stream, &(p->eqs[i].Ram.write_enable)); + read_arg(stream, &(p->eqs[i].Ram.write_addr)); read_arg(stream, &(p->eqs[i].Ram.data)); break; case C_CONCAT: @@ -101,4 +126,6 @@ t_program *load_dumb_netlist (FILE *stream) { break; } } + + return p; } diff --git a/csim/main.c b/csim/main.c index ce3f5b6..ad23cd8 100644 --- a/csim/main.c +++ b/csim/main.c @@ -23,7 +23,7 @@ void usage() { } // Arguments to be parsed -int steps = 42; +int steps = 12; char *romfile = NULL; char *filename = NULL; char *infile = NULL; @@ -80,10 +80,12 @@ int main(int argc, char **argv) { // Run t_machine *machine = init_machine(program); + i = 0; while (i < steps || steps == -1) { read_inputs(machine, input); machine_step(machine); write_outputs(machine, output); + i++; } // Cleanup diff --git a/csim/sim.c b/csim/sim.c index 27827d5..9b6906f 100644 --- a/csim/sim.c +++ b/csim/sim.c @@ -6,18 +6,208 @@ sim.c The code that actually runs the machine */ +#include +#include + #include "sim.h" +#define DEBUG 0 + +// Util + +int pow2(int exp) { + if (exp == 0) return 1; + if (exp == 1) return 2; + int k = pow2(exp / 2); + return (exp % 2 == 0 ? k * k : 2 * k * k); +} + +// The code + t_machine *init_machine (t_program *p) { + int i, j; + + t_machine *m = malloc(sizeof(t_machine)); + m->prog = p; + + m->var_values = malloc(p->n_vars * sizeof(t_value)); + for (i = 0; i < p->n_vars; i++) { + m->var_values[i] = 0; + } + + m->mem_data = malloc(p->n_eqs * sizeof(t_value)); + for (i =0; i < p->n_eqs; i++) { + if (p->eqs[i].type == C_REG) { + m->mem_data[i].RegVal = 0; + } else if (p->eqs[i].type == C_RAM) { + m->mem_data[i].RamData = malloc(pow2(p->eqs[i].Ram.addr_size) * sizeof(t_value)); + for (j = 0; j < pow2(p->eqs[i].Ram.addr_size); j++) { + m->mem_data[i].RamData[j] = 0; + } + } else { + // Leave uninitialized. Not as if anybody cares. + } + } + + return m; } void read_inputs(t_machine *m, FILE *stream) { + /* FORMAT : + For each input in the list, *in the order specified*, + the binary value for that variable. + */ + int i; + t_id var; + t_program *p = m->prog; + + if (p->n_inputs == 0) return; // nothing to do + + for (i = 0; i < p->n_inputs; i++) { + var = p->inputs[i]; + fscanf(stream, " "); + m->var_values[var] = read_bool(stream, NULL); + } + +} + +t_value get_var(t_machine *m, t_arg a) { + if (a.mask == 0) return m->var_values[a.SrcVar]; + return a.Val; +} + +t_value get_mask(t_machine *m, t_arg a) { + if (a.mask == 0) return m->prog->vars[a.SrcVar].mask; + return a.mask; } void machine_step(t_machine *m) { + int i, j; + t_value a, b, c, d, e, ma, mb, v; + t_program *p = m->prog; + + // READ REGISTERS && MEMORY + for (i = 0; i < p->n_eqs; i++) { + if (p->eqs[i].type == C_REG) { + m->var_values[p->eqs[i].dest_var] = m->mem_data[i].RegVal; + } else if (p->eqs[i].type == C_RAM) { + e = get_var(m, p->eqs[i].Ram.write_enable); + if (e == 0) { + a = get_var(m, p->eqs[i].Ram.read_addr); + m->var_values[p->eqs[i].dest_var] = m->mem_data[i].RamData[a]; + if (DEBUG) fprintf(stderr, "Read ram %lx = %lx\n", a, m->mem_data[i].RamData[a]); + } + } + } + + // DO THE LOGIC + for (i = 0; i < p->n_eqs; i++) { + if (p->eqs[i].type == C_REG || p->eqs[i].type == C_RAM) continue; + v = 0; + switch (p->eqs[i].type) { + case C_ARG: + v = get_var(m, p->eqs[i].Arg.a); + break; + case C_NOT: + v = ~get_var(m, p->eqs[i].Not.a); + break; + case C_BINOP: + a = get_var(m, p->eqs[i].Binop.a); + b = get_var(m, p->eqs[i].Binop.b); + if (p->eqs[i].Binop.op == OP_OR) v = a | b; + if (p->eqs[i].Binop.op == OP_AND) v = a & b; + if (p->eqs[i].Binop.op == OP_XOR) v = a ^ b; + if (p->eqs[i].Binop.op == OP_NAND) v = ~(a & b); + break; + case C_MUX: + a = get_var(m, p->eqs[i].Mux.a); + b = get_var(m, p->eqs[i].Mux.b); + c = get_var(m, p->eqs[i].Mux.c); + ma = get_mask(m, p->eqs[i].Mux.a); + if (ma == 1) { + v = (a ? c : b); + } else { + v = (a & c) | (~a & b); + } + break; + case C_ROM: + // TODO + break; + case C_CONCAT: + a = get_var(m, p->eqs[i].Concat.a); + b = get_var(m, p->eqs[i].Concat.b); + ma = get_mask(m, p->eqs[i].Concat.a); + mb = get_mask(m, p->eqs[i].Concat.b); + while (ma & mb) { + mb <<= 1; + b <<= 1; + } + v = (a & ma) | (b & mb); + if (DEBUG) fprintf (stderr, "concat %lx (%lx), %lx (%lx) = %lx .. ", a, ma, b, mb, v); + break; + case C_SLICE: + a = get_var(m, p->eqs[i].Slice.source); + ma = 1; + mb = 0; + for (j = 0; j <= p->eqs[i].Slice.end; j++) { + if (j >= p->eqs[i].Slice.begin) mb |= ma; + ma <<= 1; + } + v = (a & mb) >> p->eqs[i].Slice.begin; + if (DEBUG) fprintf(stderr, "slice %d-%d m=%lx %lx->%lx .. ", + p->eqs[i].Slice.begin, + p->eqs[i].Slice.end, + mb, a, v); + break; + case C_SELECT: + a = get_var(m, p->eqs[i].Select.source); + v = (a >> p->eqs[i].Select.i) & 1; + if (DEBUG) fprintf(stderr, "select %d %lx->%lx .. ", + p->eqs[i].Select.i, a, v); + break; + } + m->var_values[p->eqs[i].dest_var] = v & (p->vars[p->eqs[i].dest_var].mask); + if (DEBUG) fprintf(stderr, "%s &%lx : %lx\n", p->vars[p->eqs[i].dest_var].name, p->vars[p->eqs[i].dest_var].mask, m->var_values[p->eqs[i].dest_var]); + } + + // SAVE REGISTERS && MEMORY + for (i = 0; i < p->n_eqs; i++) { + if (p->eqs[i].type == C_REG) { + m->mem_data[i].RegVal = m->var_values[p->eqs[i].Reg.var]; + } else if (p->eqs[i].type == C_RAM) { + e = get_var(m, p->eqs[i].Ram.write_enable); + if (e != 0) { + a = get_var(m, p->eqs[i].Ram.write_addr); + d = get_var(m, p->eqs[i].Ram.data); + printf("Write ram %lx = %lx\n", a, d); + m->mem_data[i].RamData[a] = d; + } + } + } } void write_outputs(t_machine *m, FILE *stream) { + /* FORMAT : + For each output value, a line in the form + var_name binary_value + */ + int i; + t_id var; + t_program *p = m->prog; + + for (i = 0; i < p->n_outputs; i++) { + var = p->outputs[i]; + fprintf(stream, "%s\t", p->vars[var].name); + t_value v = m->var_values[var]; + t_value mask = p->vars[var].mask; + while (mask > 0) { + fprintf(stream, "%d", v & 1); + v >>= 1; + mask >>= 1; + } + fprintf(stream, "\n"); + } + fprintf(stream, "\n"); } diff --git a/csim/sim.h b/csim/sim.h index 75f3502..8e35c45 100644 --- a/csim/sim.h +++ b/csim/sim.h @@ -24,7 +24,11 @@ #define OP_NAND 3 // Data structures + + +// Use 64-bit ints as bit arrays. Bit index 0 is bitmask 1, bit index 1 is bitmask 2, etc. typedef unsigned long long int t_value; +// Identifier for the variables of the circuit. typedef int t_id; typedef struct { // a variable in the simulator @@ -34,8 +38,11 @@ typedef struct { // a variable in the simulator } t_variable; typedef struct { - t_value val; - t_id source_var; // if source_var == -1 then it's a direct value, else it's that variable + t_value mask; // if direct value, mask = all possible bits. Else mask = 0 + union { + t_value Val; + t_id SrcVar; // if source_var == -1 then it's a direct value, else it's that variable + }; } t_arg; typedef struct { @@ -93,20 +100,23 @@ typedef struct { // machine = execution instance typedef union { - t_value r_val; - t_value *mem_val; + t_value RegVal; + t_value *RamData; } t_mem_reg_data; typedef struct { t_program *prog; - t_value *var_values; - t_mem_reg_data *mem_data; + t_value *var_values; // indexed by variable ID + t_mem_reg_data *mem_data; // indexed by equation number } t_machine; // The functions for doing stuff with these data structures +t_value read_bool(FILE *stream, t_value* mask); + t_program *load_dumb_netlist(FILE *stream); + t_machine *init_machine(t_program *p); void read_inputs(t_machine *m, FILE *stream); void machine_step(t_machine *m); -- cgit v1.2.3