123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264(** [Always] is a DSL that lets one describe a circuit in the same style as a Verliog
[always] block.
[if] and [switch] control constructs are provided. (<--) is used for assignment.
Code is written as lists of assignments, if and control statements.
variables;
{[
let r_sync = Reg_spec.create ~clock ~clear in
let var = wire (zero 8) in
let var = reg r_sync enable 8 in
]}
assignment;
{[
var <-- exp
]}
if statements;
{[
if_ condition [ ... ] [ ... ]
]}
switch statements;
{[
switch condition [
of_int ~width:3 0, [ ... ];
of_int ~width:3 1, [ ... ];
of_int ~width:3 2, [ ... ];
of_int ~width:3 3, [ ... ];
]
]}
signals;
{[
let (s:signal) = q (v:guarded) in
]}
compilation;
{[
compile [ ... ]
]}
example;
{v
let state = reg r_sync enable 2 in
let a = wire 8 in
compile [
if_ (a.value ==:. 4) [
a <-- of_int ~width:8 2
] [
switch state.value [
(of_int ~width:2 0) [
a <--. 3;
state <-- of_int ~width:2 1;
];
(of_int ~width:2 1) [
a <--. 2;
state <-- of_int ~width:2 2;
];
(of_int ~width:2 2) [
a <--. 1;
state <-- of_int ~width:2 3;
];
(of_int ~width:2 3) [
a <--. 0;
state <-- of_int ~width:2 4;
]
]
];
let state = state.value in
let a = a.value in
....
v} *)open!Core0moduletypeS=sigmoduleSignal:Signal.S(** The type of variables in guarded assignments. Variables may be asychronous [wire]s,
or synchronous [reg]s. The current value of the variable may be accessed through the
[value] field below. *)moduleVariable:sigtypeinternaltypet=private{value:Signal.t;internal:internal}[@@derivingsexp_of](** gets the current value of the variable *)valvalue:t->Signal.t(** create a wire *)valwire:here:[%call_pos]->default:Signal.t->unit->t(** create a register *)valreg:here:[%call_pos]->(width:int->t)Signal.with_register_spec(** creates a register which forwards its input value to the output during cycles in
which it is enabled. *)valcut_through_reg:(width:int->t)Signal.with_register_spec(** create a pipeline of registers *)valpipeline:here:[%call_pos]->(width:int->depth:int->t)Signal.with_register_specval__ppx_auto_name:t->string->tmoduleExpert:sig(** Transform the value within the Variable *)valmap_value:t->f:(Signal.t->Signal.t)->tendendtypeassign_internaltypeif_internaltypematch_internaltypeswitch_internaltypematch_=private{value:Signal.t*tlist;internal:match_internal}[@@derivingsexp_of]andt=private|Assignof{value:Variable.t*Signal.t;internal:assign_internal}|Ifof{value:Signal.t*tlist*tlist;internal:if_internal}|Switchof{value:Signal.t*match_list;internal:switch_internal}[@@derivingsexp_of]typealways:=ttype'acase='a*tlisttype'acases='acaselist(** if statement *)valif_:here:[%call_pos]->Signal.t->tlist->tlist->t(** else if branch *)valelif:here:[%call_pos]->Signal.t->tlist->tlist->tlist(** else branch (for readability) *)valelse_:tlist->tlist(** if sel then [...] else [] *)valwhen_:here:[%call_pos]->Signal.t->tlist->t(** if sel then [] else [...] *)valunless:here:[%call_pos]->Signal.t->tlist->t(** switch statement *)valswitch:here:[%call_pos]->Signal.t->Signal.tcases->t(** Allows sequences of expressions to be inserted into the code; a syntactic nicety. *)valproc:here:[%call_pos]->tlist->t(** assignment *)val(<--):Variable.t->Signal.t->t(** assign an integer constant - width is inferred and value is truncated. *)val(<--.):Variable.t->int->t(** assign an unsigned integer constant *)val(<-:.):Variable.t->int->t(** assign a signed integer constant *)val(<-+.):Variable.t->int->t(** increment (defaults to 1) *)valincr:?by:int->Variable.t->t(** decrement (defaults to 1) *)valdecr:?by:int->Variable.t->tmoduleState_machine:sigtype'at={current:Signal.t;is:'a->Signal.t;set_next:'a->always(** [switch cases] does a switch on all possible states. The cases must be
exhaustive and irredundant. If the cases are non-exhaustive, one can supply
[~default] to make them exhaustive. *);switch:here:[%call_pos]->?default:alwayslist->'acases->always}[@@derivingsexp_of]moduleEncoding:sigtypet=|Binary|Gray|Onehot[@@derivingsexp_of,enumerate]valto_string:t->stringendmoduletypeState=sigtypet[@@derivingcompare~localize,enumerate,sexp_of]end(** [create reg_spec ~e] creates a new state machine where the state is stored in a
register created from [reg_spec] and [e].
[encoding] chooses the state encoding from binary, gray or onehot. Generally
binary is correctly identified by synthesizers and transformed to onehot.
[auto_wave_format] will automatically make state names show in waveforms. *)valcreate:here:[%call_pos]->?encoding:Encoding.t(** default is [Binary] *)->?auto_wave_format:bool(** default is [true] *)->?attributes:Rtl_attribute.tlist(** attributes to apply to the state register. Default is one_hot encoding up
to 32 states, sequential otherwise. *)->?enable:Signal.t->?unreachable:'alist(** List of states in [State.all] that cannot be defined nor set. *)->(moduleStatewithtypet='a)->Signal.Reg_spec.t->'atval__ppx_auto_name:'at->string->'atend(** compile to structural code *)valcompile:tlist->unitendmoduletypeAlways=sigmoduletypeS=SincludeSwithmoduleSignal:=SignalmoduleClocked:sigincludeSwithmoduleSignal:=Clocked_signalvalset_variable_dom:Variable.t->dom:Clock_domain.Runtime.t->Variable.tmoduleVariable_overrides:sigvalwire:default:Clocked_signal.t->dom:Clock_domain.Runtime.t->Variable.tendendend