summaryrefslogtreecommitdiff
path: root/csim
diff options
context:
space:
mode:
authorAlex AUVOLAT <alex.auvolat@ens.fr>2013-11-04 23:47:56 +0100
committerAlex AUVOLAT <alex.auvolat@ens.fr>2013-11-04 23:47:56 +0100
commit7950298bf80fd1d1f311e7bd4f75b442df7c679c (patch)
treeefb935d351a6dd798795641461f63cf17ca9f390 /csim
parent62705818bf8227a9a35fff6879306c1b861e9dfd (diff)
downloadSystDigit-Projet-7950298bf80fd1d1f311e7bd4f75b442df7c679c.tar.gz
SystDigit-Projet-7950298bf80fd1d1f311e7bd4f75b442df7c679c.zip
C simulator quite completed.
Diffstat (limited to 'csim')
-rw-r--r--csim/load.c39
-rw-r--r--csim/main.c4
-rw-r--r--csim/sim.c190
-rw-r--r--csim/sim.h22
4 files changed, 242 insertions, 13 deletions
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 <stdlib.h>
+#include <stdio.h>
+
#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);