summaryrefslogblamecommitdiff
path: root/csim/sim.c
blob: e3d61dae79fd8e51d1cb69f2f914d14bcb6f6b7b (plain) (tree)
1
2
3
4
5
6
7
8
  


                    
 
                                                   

  


                   

                
               
 
 
                                        


































                                                                              


                                              




















                                                             


 
                                 












































































































                                                                                         


                                                





















                                                       


 
/*
    Système Digital
    2013-2014
    Alex AUVOLAT

    sim.c   The code that actually runs the machine
*/

#include <stdlib.h>
#include <stdio.h>

#include "sim.h"

#define DEBUG 0


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) {
                if (*o == '1') 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;
}

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]);
    }

    // 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:
                if (p->eqs[i].Rom.rom != NULL) {
                    a = m->var_values[p->eqs[i].Rom.read_addr];
                    v = p->eqs[i].Rom.rom->data[a];
                } else {
                    v = 0;
                }
                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;
            case C_READRAM:
                a = m->var_values[p->eqs[i].ReadRAM.source];
                v = m->ram_data[p->eqs[i].ReadRAM.ram_id][a];
                if (DEBUG) fprintf(stderr, "Read ram %lx = %lx\n", a, v);
        }
        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) fprintf(stderr, "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_value v, mask;
    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);
        v = m->var_values[var];
        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");
}