summaryrefslogblamecommitdiff
path: root/camlsim/machine.ml
blob: 232cb08e4e30fb337c6a923985f60940e4fecc24 (plain) (tree)













































































































































































                                                                                                                      
(* 
	Système Digital, cours de J.Vuillemin, 2013-2013
	Alex AUVOLAT, ENS INFO 2013

	Circuit Simulator, machine simulator

	ASSUMPTIONS:
	- Only one ROM chip
*)

open Netlist_ast

exception Error of string
exception Is_not_modified

let load_rom filename =
	() (* TODO *)


type ram_prop = int * int		(* addr size ; word size *)
type machine = {
	p				: program;
	mutable vars	: value Env.t;
	mutable regs	: value Env.t;
	ram_chips		: ram_prop array;
	ram				: value array array;
}

let rec two_to_the = function
	| 0 -> 1
	| n -> let k = (two_to_the (n/2)) in
		if n mod 2 = 1 then 2 * k else k

let create p =
	let ram_chips = Array.of_list
		(List.fold_left
			(fun x (_, v) -> match v with
			| Eram (a, w, _, _, _, _) ->
				(a, w)::x
			| _ -> x)
			[]
			p.p_eqs) in
	let vars = Env.fold
			(fun k v x -> 
				Env.add k
					(match v with
						| TBit -> VBit(false)
						| TBitArray(n) -> VBitArray(Array.make n false))
					x)
			p.p_vars
			Env.empty in
	{ 
		p = p;
		vars = vars;
		regs = Env.empty;	(* no use putting anything at the moment *)
		ram_chips = ram_chips;
		ram = Array.map
			(fun (a, w) -> Array.make (two_to_the a) (VBitArray (Array.make w false)))
			ram_chips;
	}

let read_inputs m f =
	List.iter
		(fun n ->
			m.vars <- Env.add n (f (n, Env.find n m.p.p_vars)) m.vars)
		m.p.p_inputs

let step m =
	let get = function
	| Avar(x) -> 
		begin match Env.find x m.vars with
		| VBit(x) -> VBit(x)
		| VBitArray(u) as s ->
			if Array.length u = 1 then VBit(u.(0)) else s
		end
	| Aconst(x) -> x
	in
	(* Load register values into dest variables *)
	Env.iter
		(fun k v ->
			m.vars <- Env.add k v m.vars)
		m.regs;
	(* Do all the logic *)
	List.iter
		(fun (varname, exp) ->
			let evaluate = function
			| Earg(k) -> get k
			| Ereg(_) -> raise Is_not_modified	(* do nothing, registers are handled somewhere else *)
			| Enot(k) -> 
				begin match get k with
				| VBit(u) -> VBit (not u)
				| VBitArray(u) -> VBitArray(Array.map (fun x -> not x) u)
				end
			| Ebinop(op, k1, k2) ->
				let f = begin match op with
				| Or -> (fun x y -> x || y)
				| Xor -> (fun x y -> (x || y) && (not (x && y)))
				| And -> (fun x y -> x && y)
				| Nand -> (fun x y -> not (x && y))
				end in
				begin match get k1, get k2 with
				| VBit(u), VBit(v) -> VBit(f u v)
				| VBitArray(u), VBitArray(v) when Array.length u = Array.length v ->
					let r = Array.make (Array.length u) false in
					for i = 0 to Array.length u - 1 do
						r.(i) <- (f u.(i) v.(i))
					done; VBitArray(r)
				| VBit(u), VBitArray(v) -> VBit(f u v.(0))
				| VBitArray(u), VBit(v) -> VBit(f u.(0) v)
				| _ -> raise (Error "Incompatible data types.")
				end
			| Emux (control, in0, in1) ->
				begin match get control, get in0, get in1 with
				| VBit(u), x, y ->
					if u then y else x
				| VBitArray(u), VBitArray(a), VBitArray(b)
					when Array.length a = Array.length b
					&& Array.length u = Array.length a ->
					let r = Array.make (Array.length u) false in
					for i = 0 to Array.length u - 1 do
						r.(i) <- (if u.(i) then b.(i) else a.(i))
					done;
					VBitArray(r)
				| _ -> raise (Error "Invalid data size in mux")
				end
			| Erom(_, w, _) -> VBitArray(Array.make w false) (* TODO *)
			| Eram(_, _, _,_, _, _) -> raise Is_not_modified (* TODO *)
			| Econcat(k1, k2) ->
				let a1 = match get k1 with
				| VBit(u) -> [|u|]
				| VBitArray(u) -> u
				in
				let a2 = match get k2 with
				| VBit(u) -> [|u|]
				| VBitArray(u) -> u
				in
				VBitArray(Array.append a1 a2)
			| Eslice (first, last, k) ->
				begin match get k with
				| VBit(u) when first = 0 && last = 0 -> VBit(u)
				| VBitArray(u) ->
					let r = Array.make (last - first) false in
					for i = first to last - 1 do
						r.(i - first) <- u.(i)
					done;
					VBitArray(u)
				| _ -> raise (Error "Invalid slicing parameters")
				end
			| Eselect(id, k) ->
				begin match get k with
				| VBit(u) when id = 0 -> VBit(u)
				| VBitArray(u) -> VBit(u.(id))
				| _ -> raise (Error "Invalid select parameters")
				end
			in
			try
				m.vars <- Env.add varname (evaluate exp) m.vars
			with Is_not_modified -> ())
		m.p.p_eqs;
	(* Saves register values *)
	m.regs <- List.fold_left
		(fun x (k, v) ->
			match v with
			| Ereg(n) -> Env.add k (Env.find n m.vars) x
			| _ -> x)
		Env.empty
		m.p.p_eqs

let print_outputs m f =
	List.iter
		(fun n ->
			f (n, Env.find n m.vars))
		m.p.p_outputs