summaryrefslogblamecommitdiff
path: root/csim/sim.c
blob: 94bf70ef8b3b295bc63194b446dee355a5064f8a (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 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");
}