(* * CBG SQUANDERER EVENT DRIVEN SIMULATOR cbgeds.sml * * A basic EDA event driven simulator written in sml/mosml. * (C) 1999 DJ Greaves. * *) (*--------------------------------------------------------*) (* * Datastructure for the model and netlist. * * * A net has a string name and a width. * A net may be high z, dont know or contain an integer from 0 up to 2**width - 1. * A net has a list of driving and reading models. * A model has a unique instance name, a delay, a form and a list of nets it has contact with. * It also may have some internal state, held in the last field. *) datatype value_t = V_n of int | V_z | V_x; datatype m_t = M_AND | M_OR | M_INV | M_XOR | M_DFF | M_BUFIF | M_TLATCH | M_CLOCK; datatype internal_state_t = IS_NONE | IS_DFF of value_t ref | IS_CLOCK of int ref ; datatype net_t = NET of value_t ref * string * int * model_t list ref * model_t list ref and model_t = MODEL of string * int * m_t * net_t list * internal_state_t (*hardcoded*) (* Also need a soft-coded model with a frament of imperative language inside it. *) ; (* Constructor for a new net *) fun net(s, w) = NET(ref V_x, s, w, ref nil, ref nil); (* Function to set the new value of a net and return a list of * any models that must be executed because they are sensitive to * changes in this net. *) fun net_setvalue(NET(value, s, w, drivers, sensitives), new_value) = if (!value = new_value) then nil else ( value := new_value; !sensitives ) ; (* Function to read current value of a net *) fun netvalue(NET(value, s, w, drivers, sensitives)) = !value ; (* Constructor for a new model. Connects itself to each net in use. *) fun model(s, d, form, output_nets, input_nets) = let val internal_state = if (form = M_DFF) then IS_DFF(ref V_x) else if (form = M_CLOCK) then IS_CLOCK(ref 0) else IS_NONE val nets = output_nets @ input_nets val m = MODEL(s, d, form, nets, internal_state) fun connect_output(NET(v, s, w, drivers, sensitives)) = drivers := m :: (!drivers) fun connect_input(NET(v, s, w, drivers, sensitives)) = sensitives := m :: (!sensitives) val _ = app connect_output output_nets val _ = app connect_input input_nets in m end ; (*--------------------------------------------------------*) (* * Datastructure for an event list and also the current global time, tnow. * * The fields of an event are the time that it occurs, the net it changes and * the new value on that net. It also has a pointer to the next event in time * order. *) type time_t = int; val tnow = ref 0; datatype event_t = EVENT of time_t * net_t * value_t * event_t ref | EMPTY ; val eventlist = ref EMPTY; (* Constructor for a new event that also inserts it at the correct point in the sorted event list. *) fun event(time, net, value) = let fun a e = case !e of (A as EMPTY) => e := EVENT(time, net, value, ref A) | (A as EVENT(t, n, v, e')) => if (t > time) then e := EVENT(time, net, value, ref A) else a e' in a eventlist end ; (*--------------------------------------------------------*) (* * Some code for example models is provided here. These models * are just the standard logic gates found in most digital * electronic systems. *) fun example_models(MODEL(iname, delay, M_INV, nets, _)) = let val input = hd(tl nets) val output = hd nets fun invert (V_n 0) = V_n 1 | invert (V_n 1) = V_n 0 | invert (other) = V_x in event(!tnow+delay, output, invert (netvalue input)) end | example_models(MODEL(iname, delay, M_AND, nets, _)) = let val i1 = hd(tl(tl nets)) val i2 = hd(tl nets) val output = hd nets fun AND (V_n 0, _) = V_n 0 | AND (_, V_n 0) = V_n 0 | AND (V_n 1, Vn_1) = V_n 1 | AND (other) = V_x in event(!tnow+delay, output, AND (netvalue i1, netvalue i2)) end | example_models(MODEL(iname, delay, M_OR, nets, _)) = let val i1 = hd(tl(tl nets)) val i2 = hd(tl nets) val output = hd nets fun OR (V_n 1, _) = V_n 1 | OR (_, V_n 1) = V_n 1 | OR (V_n 0, Vn_0) = V_n 0 | OR (other) = V_x in event(!tnow+delay, output, OR (netvalue i1, netvalue i2)) end | example_models(MODEL(iname, delay, M_DFF, nets, IS_DFF(old_clk))) = let val d = netvalue(hd(tl(tl nets))) val clk = netvalue(hd(tl nets)) val output = hd nets (* Positive edge detector here *) fun posedge (V_n 1, V_n 0) = true | posedge (_, _) = false val active_edge = posedge(clk, !old_clk) val _ = old_clk := clk in if (active_edge) then event(!tnow+delay, output, d) else () end | example_models(MODEL(iname, delay, M_CLOCK, nets, IS_CLOCK(state))) = let val output = hd nets val nv = 1 - (!state) val _ = state := nv in event(!tnow+delay, output, V_n nv) end | example_models(MODEL(iname, delay, other, nets, _)) = print ("No model provided for instance " ^ iname ^ "\n") ; (*--------------------------------------------------------*) (* * Dispatcher for a single event. Takes the event from the head of the * event queue, updates the net and the current time and activates * all of the models that are sensitive to that net. *) fun dispatch_one_event() = if (!eventlist = EMPTY) then print("simulation finished - no more events\n") else let val EVENT(time, net, value, e') = !eventlist in ( eventlist := !e'; tnow := time; app example_models (net_setvalue(net, value)) ) end ; (*--------------------------------------------------------*) (* * Top-level simulation * *) fun main() = ( (* ... put the code to create your circuit here ... *) while (!eventlist <> EMPTY) do dispatch_one_event() ) ; val _ = quit(); (* eof cbg *)