/* Système Digital 2013-2014 Alex AUVOLAT sim.c The code that actually runs the machine */ #include #include #include "sim.h" #define DEBUG 1 // 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; // Allocate variables m->var_values = malloc(p->n_vars * sizeof(t_value)); for (i = 0; i < p->n_vars; i++) { m->var_values[i] = 0; if (p->vars[i].name[0] == '$') { // setup constant value t_value a = 1; char *o = p->vars[i].name + 1; while (*o) { m->var_values[i] |= a; a >>= 1; o++; } } } // Allocate space for registers and rams m->reg_data = malloc(p->n_regs * sizeof(t_value)); for (i = 0; i < p->n_regs; i++) { m->reg_data[i] = 0; } m->ram_data = malloc(p->n_rams * sizeof(t_value*)); for (i = 0; i < p->n_rams; i++) { m->ram_data[i] = malloc(pow2(p->rams[i].addr_size) * sizeof(t_value)); for (j = 0; j < pow2(p->rams[i].addr_size); j++) { m->ram_data[i][j] = 0; } } return m; } 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_inputs(t_machine *m, FILE *stream) { /* FORMAT : For each input in the list, *in the order specified*, either '/' followed by the decimal value or the binary value */ 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, " "); if (fscanf(stream, "/%lu", &(m->var_values[var]))) { // ok, value is read } else { m->var_values[var] = read_bool(stream, NULL); } m->var_values[var] &= p->vars[var].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_regs; i++) { m->var_values[p->regs[i].dest] = m->reg_data[i]; if (DEBUG) fprintf(stderr, "%s <- reg %s : %lx\n", p->vars[p->regs[i].dest].name, p->vars[p->regs[i].dest].name, m->reg_data[i]); } for (i = 0; i < p->n_rams; i++) { e = m->var_values[p->rams[i].write_enable]; if (e == 0) { a = m->var_values[p->rams[i].read_addr]; b = m->ram_data[i][a]; m->var_values[p->rams[i].dest] = b; if (DEBUG) fprintf(stderr, "Read ram %lx = %lx\n", a, b); } } // DO THE LOGIC for (i = 0; i < p->n_eqs; i++) { v = 0; switch (p->eqs[i].type) { case C_COPY: v = m->var_values[p->eqs[i].Copy.a]; break; case C_NOT: v = ~m->var_values[p->eqs[i].Not.a]; break; case C_BINOP: a = m->var_values[p->eqs[i].Binop.a]; b = m->var_values[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 = m->var_values[p->eqs[i].Mux.a]; b = m->var_values[p->eqs[i].Mux.b]; c = m->var_values[p->eqs[i].Mux.c]; ma = m->prog->vars[p->eqs[i].Mux.a].mask; if (ma == 1) { v = (a ? c : b); } else { v = (a & c) | (~a & b); } break; case C_ROM: // TODO break; case C_CONCAT: a = m->var_values[p->eqs[i].Concat.a]; b = m->var_values[p->eqs[i].Concat.b]; ma = p->vars[p->eqs[i].Concat.a].mask; mb = p->vars[p->eqs[i].Concat.b].mask; b <<= p->eqs[i].Concat.shift; v = a | b; if (DEBUG) fprintf (stderr, "concat %lx (&%lx) %lx (&%lx) <%d = %lx .. ", a, ma, b, mb, p->eqs[i].Concat.shift, v); break; case C_SLICE: a = m->var_values[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 = m->var_values[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_regs; i++) { m->reg_data[i] = m->var_values[p->regs[i].source]; if (DEBUG) printf("reg %s <- %s : %lx\n", p->vars[p->regs[i].dest].name, p->vars[p->regs[i].source].name, m->reg_data[i]); } for (i = 0; i < p->n_rams; i++) { e = m->var_values[p->rams[i].write_enable]; if (e != 0) { a = m->var_values[p->rams[i].write_addr]; d = m->var_values[p->rams[i].data]; m->ram_data[i][a] = d; if (DEBUG) fprintf(stderr, "Write ram %lx = %lx\n", a, d); } } } void write_outputs(t_machine *m, FILE *stream) { /* FORMAT : For each output value, a line in the form var_name binary_value decimal_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, "\t%ld\n", m->var_values[var]); } fprintf(stream, "\n"); }