123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350openBasemoduletypeSignal=sig(** Signal data type and low-level functions *)(** simple operators *)typesignal_op=|Signal_add|Signal_sub|Signal_mulu|Signal_muls|Signal_and|Signal_or|Signal_xor|Signal_eq|Signal_lt[@@derivingsexp_of,compare,hash]moduleUid:sigtypet=int64[@@derivingcompare,hash,sexp_of]includeComparator.Swithtypet:=tincludeEqual.Swithtypet:=tendmoduleUid_set:sigtypet=Set.M(Uid).t[@@derivingsexp_of]valempty:tendmoduleUid_map:moduletypeofMap.M(Uid)(** internal structure for tracking signals *)typesignal_id={s_id:Uid.t;mutables_names:stringlist;s_width:int;mutables_attributes:Rtl_attribute.tlist(** Making this mutable turns hardcaml from pretty functional to pretty imperative.
however, if used carefully and only with the library, we can provide a
potentially easier way of changing the graph structure in some cases *);mutables_deps:tlist;caller_id:Caller_id.toption}(** main signal data type *)andt=|Empty|Constof{signal_id:signal_id;constant:Bits.t}|Op2of{signal_id:signal_id;op:signal_op;arg_a:t;arg_b:t}|Muxof{signal_id:signal_id;select:t;cases:tlist}|Catof{signal_id:signal_id;args:tlist}|Notof{signal_id:signal_id;arg:t}|Wireof{signal_id:signal_id;driver:tref}|Selectof{signal_id:signal_id;arg:t;high:int;low:int}|Regof{signal_id:signal_id;register:register;d:t}|Memof{signal_id:signal_id;extra_uid:Uid.t;register:register;memory:memory}|Multiport_memof{signal_id:signal_id;size:int;write_ports:write_portarray}|Mem_read_portof{signal_id:signal_id;memory:t;read_address:t}|Instof{signal_id:signal_id;extra_uid:Uid.t;instantiation:instantiation}andwrite_port={write_clock:t;write_address:t;write_enable:t;write_data:t}andread_port={read_clock:t;read_address:t;read_enable:t}(** These types are used to define a particular type of register as per the following
template, where each part is optional:
{v
always @(?edge clock, ?edge reset)
if (reset == reset_level) d <= reset_value;
else if (clear == clear_level) d <= clear_value;
else if (enable) d <= ...;
v} *)andregister={reg_clock:t(** clock *);reg_clock_edge:Edge.t(** active clock edge *);reg_reset:t(** asynchronous reset *);reg_reset_edge:Edge.t(** asynchronous reset edge *);reg_reset_value:t(** asychhronous reset value *);reg_clear:t(** synchronous clear *);reg_clear_level:Level.t(** synchronous clear level *);reg_clear_value:t(** sychhronous clear value *);reg_enable:t(** global system enable *)}andmemory={mem_size:int;mem_read_address:t;mem_write_address:t;mem_write_data:t}andinstantiation={inst_name:string(** name of circuit *);inst_instance:string(** instantiation label *);inst_generics:Parameter.tlist(** [Parameter.int ...] *);inst_inputs:(string*t)list(** name and input signal *);inst_outputs:(string*(int*int))list(** name, width and low index of output *);inst_lib:string;inst_arch:string}typesignal=t(** returns the (private) signal_id. For internal use only. *)valsignal_id:t->signal_idoption(** returns the unique id of the signal *)valuid:t->Uid.t(** returns the signal's dependencies *)valdeps:t->tlist(** returns the list of names assigned to the signal *)valnames:t->stringlist(** Add an attribute to node. This is currently supported only in Verilog. *)valadd_attribute:t->Rtl_attribute.t->t(** Returns attributes associated to the signal *)valattributes:t->Rtl_attribute.tlistvalhas_name:t->bool(** is the signal a register? *)valis_reg:t->bool(** is the signal a memory, or multiport memory? *)valis_mem:t->bool(** is the signal a multiport memory? *)valis_multiport_mem:t->bool(** is the signal a memory read port? *)valis_mem_read_port:t->bool(** is the signal an instantiation? *)valis_inst:t->bool(** is the signal a constant? *)valis_const:t->bool(** is the signal a part selection? *)valis_select:t->bool(** is the signal a wire? *)valis_wire:t->bool(** is the signal the given operator? *)valis_op2:signal_op->t->bool(** is the signal concatenation? *)valis_cat:t->bool(** is the signal a multiplexer? *)valis_mux:t->bool(** is the signal a not> *)valis_not:t->bool(** return the (binary) string representing a constants value *)valconst_value:t->Bits.t(** creates a new signal uid *)valnew_id:unit->Uid.t(** resets the signal identifiers *)valreset_id:unit->unit(** constructs a signal_id type *)valmake_id:int->tlist->signal_id(** perform a recursive structural comparison of two signals *)valstructural_compare:?check_names:bool->?check_deps:bool->?initial_deps:Uid_set.t->t->t->Uid_set.t*bool(** [sexp_of_signal_recursive ~depth signal] converts a signal recursively to a sexp for
up to [depth] levels. If [show_uids] is false then signal identifiers will not be
printed. [max_list_length] controls how many [mux] and [concat] arguments
(dependancies) are printed. *)valsexp_of_signal_recursive:?show_uids:bool(** default is [false] *)->depth:int->t->Sexp.t(** Combinatorial signal API. This API automatically performs constant propogations
(eg: replacing (a + 1 + 5) with (a + 6)). This reduces the amount of work that needs
to be done during simulation by simply reducing the number of simulation nodes.
To use raw signals, ie: keeping the simulation nodes as described, use [Raw]
below.
*)includeComb.Swithtypet:=t(** creates an unassigned wire *)valwire:int->t(** creates an assigned wire *)valwireof:t->t(** assigns to wire *)val(<==):t->t->unitvalassign:t->t->unit(** creates an input *)valinput:string->int->t(** creates an output *)valoutput:string->t->t(** Comb logic API without constant propogation optimizations. *)moduleUnoptimized:Comb.Swithtypet=t(** [Reg_spec_] is a register specification. It is named [Reg_spec_] rather than
[Reg_spec] so that people consistently use the name [Hardcaml.Reg_spec] rather
than [Hardcaml.Signal.Reg_spec_]. *)moduleReg_spec_:sigtypet=register[@@derivingsexp_of]valcreate:?clear:signal->?reset:signal->unit->clock:signal->tvaloverride:?clock:signal->?clock_edge:Edge.t->?reset:signal->?reset_edge:Edge.t->?reset_to:signal->?clear:signal->?clear_level:Level.t->?clear_to:signal->?global_enable:signal->t->tvalclock:t->signalvalclear:t->signalvalreset:t->signalendvalreg:Reg_spec_.t->?enable:t->t->tvalreg_fb:?enable:t->Reg_spec_.t->width:int->f:(t->t)->t(** Pipeline a signal [n] times with the given register specification. If set, a list of
RTL attributes will also be applied to each register created. *)valpipeline:?attributes:Rtl_attribute.tlist->Reg_spec_.t->n:int->?enable:t->t->tvalmemory:int->write_port:write_port->read_address:t->tvalram_wbr:?attributes:Rtl_attribute.tlist->write_port:write_port->read_port:read_port->int->tvalram_rbw:?attributes:Rtl_attribute.tlist->write_port:write_port->read_port:read_port->int->tvalmultiport_memory:?name:string->?attributes:Rtl_attribute.tlist->int->write_ports:write_portarray->read_addresses:tarray->tarray(** Pretty printer. *)valpp:Formatter.t->t->unitend