(*
* 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 *)