Module Hardcaml.Signal
Hardware design datatype suitable for simulation and netlist generation
type signal_op
=
|
Signal_add
|
Signal_sub
|
Signal_mulu
|
Signal_muls
|
Signal_and
|
Signal_or
|
Signal_xor
|
Signal_eq
|
Signal_lt
simple operators
val sexp_of_signal_op : signal_op -> Ppx_sexp_conv_lib.Sexp.t
val compare_signal_op : signal_op -> signal_op -> Hardcaml__.Import.int
val hash_fold_signal_op : Base.Hash.state -> signal_op -> Base.Hash.state
val hash_signal_op : signal_op -> Base.Hash.hash_value
module Uid : sig ... end
module Uid_map : Hardcaml__.Map.S with module Key := Uid
module Uid_set : sig ... end
type signal_id
=
{
s_id : Uid.t;
mutable s_names : Hardcaml__.Import.string Hardcaml__.Import.list;
s_width : Hardcaml__.Import.int;
mutable s_attributes : Rtl_attribute.t Hardcaml__.Import.list;
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
mutable s_deps : t Hardcaml__.Import.list;
caller_id : Caller_id.t Hardcaml__.Import.option;
}
internal structure for tracking signals
and t
=
|
Empty
|
Const of
{
signal_id : signal_id;
constant : Bits.t;
}
|
Op2 of
{
signal_id : signal_id;
op : signal_op;
arg_a : t;
arg_b : t;
}
|
Mux of
{
signal_id : signal_id;
select : t;
cases : t Hardcaml__.Import.list;
}
|
Cat of
{
signal_id : signal_id;
args : t Hardcaml__.Import.list;
}
|
Not of
{
signal_id : signal_id;
arg : t;
}
|
Wire of
{
signal_id : signal_id;
driver : t Hardcaml__.Import.ref;
}
|
Select of
{
signal_id : signal_id;
arg : t;
high : Hardcaml__.Import.int;
low : Hardcaml__.Import.int;
}
|
Reg of
{
signal_id : signal_id;
register : register;
d : t;
}
|
Mem of
{
signal_id : signal_id;
extra_uid : Uid.t;
register : register;
memory : memory;
}
|
Multiport_mem of
{
signal_id : signal_id;
size : Hardcaml__.Import.int;
write_ports : write_port Hardcaml__.Import.array;
}
|
Mem_read_port of
{
signal_id : signal_id;
memory : t;
read_address : t;
}
|
Inst of
{
signal_id : signal_id;
extra_uid : Uid.t;
instantiation : instantiation;
}
main signal data type
and write_port
=
{
write_clock : t;
write_address : t;
write_enable : t;
write_data : t;
}
and read_port
=
{
read_clock : t;
read_address : t;
read_enable : t;
}
and register
=
{
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
}
These types are used to define a particular type of register as per the following template, where each part is optional:
always @(?edge clock, ?edge reset) if (reset == reset_level) d <= reset_value; else if (clear == clear_level) d <= clear_value; else if (enable) d <= ...;
and memory
=
{
mem_size : Hardcaml__.Import.int;
mem_read_address : t;
mem_write_address : t;
mem_write_data : t;
}
and instantiation
=
{
inst_name : Hardcaml__.Import.string;
name of circuit
inst_instance : Hardcaml__.Import.string;
instantiation label
inst_generics : Parameter.t Hardcaml__.Import.list;
Parameter.int ...
inst_inputs : (Hardcaml__.Import.string * t) Hardcaml__.Import.list;
name and input signal
inst_outputs : (Hardcaml__.Import.string * (Hardcaml__.Import.int * Hardcaml__.Import.int)) Hardcaml__.Import.list;
name, width and low index of output
inst_lib : Hardcaml__.Import.string;
inst_arch : Hardcaml__.Import.string;
}
type signal
= t
val signal_id : t -> signal_id Hardcaml__.Import.option
returns the (private) signal_id. For internal use only.
val deps : t -> t Hardcaml__.Import.list
returns the signal's dependencies
val names : t -> Hardcaml__.Import.string Hardcaml__.Import.list
returns the list of names assigned to the signal
val add_attribute : t -> Rtl_attribute.t -> t
Add an attribute to node. This is currently supported only in Verilog.
val attributes : t -> Rtl_attribute.t Hardcaml__.Import.list
Returns attributes associated to the signal
val has_name : t -> Hardcaml__.Import.bool
val is_reg : t -> Hardcaml__.Import.bool
is the signal a register?
val is_mem : t -> Hardcaml__.Import.bool
is the signal a memory, or multiport memory?
val is_multiport_mem : t -> Hardcaml__.Import.bool
is the signal a multiport memory?
val is_mem_read_port : t -> Hardcaml__.Import.bool
is the signal a memory read port?
val is_inst : t -> Hardcaml__.Import.bool
is the signal an instantiation?
val is_const : t -> Hardcaml__.Import.bool
is the signal a constant?
val is_select : t -> Hardcaml__.Import.bool
is the signal a part selection?
val is_wire : t -> Hardcaml__.Import.bool
is the signal a wire?
val is_op2 : signal_op -> t -> Hardcaml__.Import.bool
is the signal the given operator?
val is_cat : t -> Hardcaml__.Import.bool
is the signal concatenation?
val is_mux : t -> Hardcaml__.Import.bool
is the signal a multiplexer?
val is_not : t -> Hardcaml__.Import.bool
is the signal a not>
val new_id : Hardcaml__.Import.unit -> Uid.t
creates a new signal uid
val reset_id : Hardcaml__.Import.unit -> Hardcaml__.Import.unit
resets the signal identifiers
val make_id : Hardcaml__.Import.int -> t Hardcaml__.Import.list -> signal_id
constructs a signal_id type
val structural_compare : ?check_names:Hardcaml__.Import.bool -> ?check_deps:Hardcaml__.Import.bool -> ?initial_deps:Uid_set.t -> t -> t -> Uid_set.t * Hardcaml__.Import.bool
perform a recursive structural comparison of two signals
val sexp_of_signal_recursive : ?show_uids:Hardcaml__.Import.bool -> depth:Hardcaml__.Import.int -> t -> Hardcaml__.Import.Sexp.t
sexp_of_signal_recursive ~depth signal
converts a signal recursively to a sexp for up todepth
levels. Ifshow_uids
is false then signal identifiers will not be printed.max_list_length
controls how manymux
andconcat
arguments (dependancies) are printed.
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.
include Comb.S with type t := t
val sexp_of_t : t -> Ppx_sexp_conv_lib.Sexp.t
val empty : t
the empty signal
val is_empty : t -> Hardcaml__.Import.bool
val (--) : t -> Hardcaml__.Import.string -> t
names a signal
let a = a -- "a" in ...
signals may have multiple names.
val width : t -> Hardcaml__.Import.int
returns the width (number of bits) of a signal.
let w = width s in ...
val address_bits_for : Hardcaml__.Import.int -> Hardcaml__.Import.int
addess_bits_for num_elements
returns the address width required to indexnum_elements
.It is the same as
Int.ceil_log2
, except it wll return a minimum value of 1 (since you cannot have 0 width vectors). Raises ifnum_elements
is< 0
.
val num_bits_to_represent : Hardcaml__.Import.int -> Hardcaml__.Import.int
num_bits_to_represent x
returns the number of bits required to represent the numberx
, which should be>= 0
.
val of_constant : Constant.t -> t
val to_constant : t -> Constant.t
val constb : Hardcaml__.Import.string -> t
convert binary string to constant
val of_bit_string : Hardcaml__.Import.string -> t
val of_int : width:Hardcaml__.Import.int -> Hardcaml__.Import.int -> t
convert integer to constant
val of_int32 : width:Hardcaml__.Import.int -> Hardcaml__.Import.int32 -> t
val of_int64 : width:Hardcaml__.Import.int -> Hardcaml__.Import.int64 -> t
val of_hex : ?signedness:Constant.Signedness.t -> width:Hardcaml__.Import.int -> Hardcaml__.Import.string -> t
convert hex string to a constant. If the target width is greater than the hex length and
signedness
isSigned
then the result is sign extended. Otherwise the result is zero padded.
val of_string : Hardcaml__.Import.string -> t
convert verilog style or binary string to constant
val of_bit_list : Hardcaml__.Import.int Hardcaml__.Import.list -> t
convert IntbitsList to constant
val of_decimal_string : width:Hardcaml__.Import.int -> Hardcaml__.Import.string -> t
val of_char : Hardcaml__.Import.char -> t
convert a
char
to an 8 bit constant
val constv : Hardcaml__.Import.string -> t
val consti : width:Hardcaml__.Import.int -> Hardcaml__.Import.int -> t
val consti32 : width:Hardcaml__.Import.int -> Hardcaml__.Import.int32 -> t
val consti64 : width:Hardcaml__.Import.int -> Hardcaml__.Import.int64 -> t
val constibl : Hardcaml__.Import.int Hardcaml__.Import.list -> t
val consthu : width:Hardcaml__.Import.int -> Hardcaml__.Import.string -> t
val consths : width:Hardcaml__.Import.int -> Hardcaml__.Import.string -> t
val const : Hardcaml__.Import.string -> t
val constd : width:Hardcaml__.Import.int -> Hardcaml__.Import.string -> t
val concat_msb : t Hardcaml__.Import.list -> t
concat ts
concatenates a list of signals - the msb of the head of the list will become the msb of the result.let c = concat [ a; b; c ] in ...
concat
raises ifts
is empty or if anyt
ints
is empty.
val concat_lsb : t Hardcaml__.Import.list -> t
Similar to
concat_msb
except the lsb of the head of the list will become the lsb of the result.
val concat_msb_e : t Hardcaml__.Import.list -> t
same as
concat_msb
except empty signals are first filtered out
val concat_lsb_e : t Hardcaml__.Import.list -> t
same as
concat_lsb
except empty signals are first filtered out
val vdd : t
logic 1
val is_vdd : t -> Hardcaml__.Import.bool
val gnd : t
logic 0
val is_gnd : t -> Hardcaml__.Import.bool
val zero : Hardcaml__.Import.int -> t
zero w
makes a the zero valued constant of widthw
val ones : Hardcaml__.Import.int -> t
ones w
makes a constant of all ones of widthw
val one : Hardcaml__.Import.int -> t
one w
makes a one valued constant of widthw
val select : t -> Hardcaml__.Import.int -> Hardcaml__.Import.int -> t
select t hi lo
selects fromt
bits in the rangehi
...lo
, inclusive.select
raises unlesshi
andlo
fall within0 .. width t - 1
andhi >= lo
.
val select_e : t -> Hardcaml__.Import.int -> Hardcaml__.Import.int -> t
same as
select
except invalid indices returnempty
val bit : t -> Hardcaml__.Import.int -> t
select a single bit
val drop_bottom : t -> Hardcaml__.Import.int -> t
drop_bottom s n
drop bottomn
bits ofs
val drop_top : t -> Hardcaml__.Import.int -> t
drop_top s n
drop topn
bits ofs
val sel_bottom : t -> Hardcaml__.Import.int -> t
sel_bottom s n
select bottomn
bits ofs
val sel_top : t -> Hardcaml__.Import.int -> t
sel_top s n
select topn
bits ofs
val (.:[]) : t -> (Hardcaml__.Import.int * Hardcaml__.Import.int) -> t
x.:[hi, lo]
==select x hi lo
val (.:+[]) : t -> (Hardcaml__.Import.int * Hardcaml__.Import.int Hardcaml__.Import.option) -> t
x.:+[lo, width]
==select x (lo + width - 1) lo
. Ifwidth
isNone
it selects all remaining msbs of the vector iex.:+[lo,None]
==drop_bottom x lo
val (.:-[]) : t -> (Hardcaml__.Import.int Hardcaml__.Import.option * Hardcaml__.Import.int) -> t
x.:-[hi, width]
==select x hi (hi - width + 1)
. Ifhi
isNone
it defaults to the msb of the vector iex.:-[None, width]
==sel_top x width
val (.:()) : t -> Hardcaml__.Import.int -> t
x.(i)
==bit x i
val insert : into:t -> t -> at_offset:Hardcaml__.Import.int -> t
insert ~into:t x ~at_offset
insertx
intot
at given offet
val mux : t -> t Hardcaml__.Import.list -> t
multiplexer.
let m = mux sel inputs in ...
Given
l
=List.length inputs
andw
=width sel
the following conditions must hold.l
<= 2**w
,l
>= 2If
l
< 2**w
, the last input is repeated.All inputs provided must have the same width, which will in turn be equal to the width of
m
.
val mux2 : t -> t -> t -> t
mux2 c t f
2 input multiplexer. Selectst
ifc
is high otherwisef
.t
andf
must have same width andc
must be 1 bit.Equivalent to
mux c [f; t]
val mux_init : t -> Hardcaml__.Import.int -> f:(Hardcaml__.Import.int -> t) -> t
val (&:) : t -> t -> t
logical and
val (^:.) : t -> Hardcaml__.Import.int -> t
val (~:) : t -> t
logical not
val (-:.) : t -> Hardcaml__.Import.int -> t
val negate : t -> t
negation
val (>=+.) : t -> Hardcaml__.Import.int -> t
val to_string : t -> Hardcaml__.Import.string
create string from signal
val to_int : t -> Hardcaml__.Import.int
to_int t
treatst
as unsigned and resizes it to fit exactly within an OCamlInt.t
.- If
width t > Int.num_bits
then the upper bits are truncated. - If
width t >= Int.num_bits
andbit t (Int.num_bits-1) = vdd
(i.e. the msb of the resultingInt.t
is set), then the result is negative. - If
t
isSignal.t
and not a constant value, an exception is raised.
- If
val to_sint : t -> Hardcaml__.Import.int
to_sint t
treatst
as signed and resizes it to fit exactly within an OCamlInt.t
.- If
width t > Int.num_bits
then the upper bits are truncated. - If
t
isSignal.t
and not a constant value, an exception is raised.
- If
val to_int32 : t -> Hardcaml__.Import.int32
val to_sint32 : t -> Hardcaml__.Import.int32
val to_int64 : t -> Hardcaml__.Import.int64
val to_sint64 : t -> Hardcaml__.Import.int64
val to_char : t -> Hardcaml__.Import.char
Convert signal to a
char
. The signal must be 8 bits wide.
val to_bstr : t -> Hardcaml__.Import.string
create binary string from signal
val bits_msb : t -> t Hardcaml__.Import.list
convert signal to a list of bits with msb at head of list
val bits_lsb : t -> t Hardcaml__.Import.list
convert signal to a list of bits with lsb at head of list
val to_array : t -> t Hardcaml__.Import.array
to_array s
convert signals
to array of bits with lsb at index 0
val of_array : t Hardcaml__.Import.array -> t
of_array a
convert arraya
of bits to signal with lsb at index 0
val repeat : t -> Hardcaml__.Import.int -> t
repeat signal n times
val split_in_half_msb : t -> t * t
split signal in half. The most significant bits will be in the left half of the returned tuple.
val split_lsb : ?exact:Hardcaml__.Import.bool -> part_width:Hardcaml__.Import.int -> t -> t Hardcaml__.Import.list
Split signal into a list of signals with width equal to
part_width
. The least significant bits are at the head of the returned list. Ifexact
istrue
the input signal width must be exactly divisable bypart_width
. Whenexact
isfalse
and the input signal width is not exactly divisible bypart_width
, the last element will contains residual bits.eg:
split_lsb ~part_width:4 16b0001_0010_0011_0100 = [ 4b0100; 4b0011; 4b0010; 4b0001 ] split_lsb ~exact:false ~part_width:4 17b11_0001_0010_0011_0100 = [ 4b0100; 4b0011; 4b0010; 4b0001; 2b11 ]
val split_msb : ?exact:Hardcaml__.Import.bool -> part_width:Hardcaml__.Import.int -> t -> t Hardcaml__.Import.list
Like
split_lsb
except the most significant bits are at the head of the returned list. Residual bits whenexact
isfalse
goes to the last element of the list, so in the general casesplit_lsb
is not necessarily equivalent tosplit_msb |> List.rev
.
val bswap : t -> t
val sll : t -> Hardcaml__.Import.int -> t
shift left logical
val srl : t -> Hardcaml__.Import.int -> t
shift right logical
val sra : t -> Hardcaml__.Import.int -> t
shift right arithmetic
val rotl : t -> Hardcaml__.Import.int -> t
rotate left
val rotr : t -> Hardcaml__.Import.int -> t
rotate right
val uresize : t -> Hardcaml__.Import.int -> t
uresize t w
returns the unsigned resize oft
to widthw
. Ifw = width t
, this is a no-op. Ifw < width t
, thisselect
s thew
low bits oft
. Ifw > width t
, this extendst
withzero (width t - w)
.
val sresize : t -> Hardcaml__.Import.int -> t
sresize t w
returns the signed resize oft
to widthw
. Ifw = width t
, this is a no-op. Ifw < width t
, thisselect
s thew
low bits oft
. Ifw > width t
, this extendst
withwidth t - w
copies ofmsb t
.
val resize_list : resize:(t -> Hardcaml__.Import.int -> t) -> t Hardcaml__.Import.list -> t Hardcaml__.Import.list
resize_list ?resize l
finds the maximum width inl
and appliesresize el max
to each element.
val resize_op2 : resize:(t -> Hardcaml__.Import.int -> t) -> (t -> t -> t) -> t -> t -> t
resize_op2 ~resize f a b
appliesresize x w
toa
andb
wherew
is the maximum of their widths. It then returnsf a b
val reduce : f:('a -> 'a -> 'a) -> 'a Hardcaml__.Import.list -> 'a
fold 'op' though list
val mod_counter : max:Hardcaml__.Import.int -> t -> t
mod_counter max t
isif t = max then 0 else (t + 1)
, and can be used to count from 0 to (max-1) then from zero again. If max == 1<<n, then a comparator is not generated and overflow arithmetic used instead. If
val tree : arity:Hardcaml__.Import.int -> f:('a Hardcaml__.Import.list -> 'a) -> 'a Hardcaml__.Import.list -> 'a
tree ~arity ~f input
creates a tree of operations. The arity of the operator is configurable.tree
raises ifinput = []
.
val priority_select : (t With_valid.t Hardcaml__.Import.list -> t With_valid.t) Hardcaml__.Comb_intf.optional_branching_factor
priority_select cases
returns the value associated with the first case whosevalid
signal is high.valid
will be set low in the returnedWith_valid.t
if no case is selected.
val priority_select_with_default : (t With_valid.t Hardcaml__.Import.list -> default:t -> t) Hardcaml__.Comb_intf.optional_branching_factor
Same as
priority_select
except returnsdefault
if no case matches.
val onehot_select : (t With_valid.t Hardcaml__.Import.list -> t) Hardcaml__.Comb_intf.optional_branching_factor
Select a case where one and only one
valid
signal is enabled. If more than one case isvalid
then the return value is undefined. If no cases are valid,0
is returned by the current implementation, though this should not be relied upon.
val popcount : (t -> t) Hardcaml__.Comb_intf.optional_branching_factor
popcount t
returns the number of bits set int
.
val is_pow2 : (t -> t) Hardcaml__.Comb_intf.optional_branching_factor
is_pow2 t
returns a bit to indicate ift
is a power of 2.
val leading_ones : (t -> t) Hardcaml__.Comb_intf.optional_branching_factor
leading_ones t
returns the number of consecutive1
s from the most significant bit oft
down.
val trailing_ones : (t -> t) Hardcaml__.Comb_intf.optional_branching_factor
trailing_ones t
returns the number of consecutive1
s from the least significant bit oft
up.
val leading_zeros : (t -> t) Hardcaml__.Comb_intf.optional_branching_factor
leading_zeros t
returns the number of consecutive0
s from the most significant bit oft
down.
val trailing_zeros : (t -> t) Hardcaml__.Comb_intf.optional_branching_factor
trailing_zeros t
returns the number of consecutive0
s from the least significant bit oft
up.
val floor_log2 : (t -> t With_valid.t) Hardcaml__.Comb_intf.optional_branching_factor
floor_log2 x
returns the floor of log-base-2 ofx
.x
is treated as unsigned and an error is indicated byvalid = gnd
in the return value ifx = 0
.
val ceil_log2 : (t -> t With_valid.t) Hardcaml__.Comb_intf.optional_branching_factor
ceil_log2 x
returns the ceiling of log-base-2 ofx
.x
is treated as unsigned and an error is indicated byvalid = gnd
in the return value ifx = 0
.
val random : width:Hardcaml__.Import.int -> t
create random constant vector of given width
module type TypedMath = Hardcaml__.Comb_intf.TypedMath with type t := t
val wire : Hardcaml__.Import.int -> t
creates an unassigned wire
val (<==) : t -> t -> Hardcaml__.Import.unit
assigns to wire
val assign : t -> t -> Hardcaml__.Import.unit
val input : Hardcaml__.Import.string -> Hardcaml__.Import.int -> t
creates an input
val output : Hardcaml__.Import.string -> t -> t
creates an output
module Unoptimized : Comb.S with type t = t
Comb logic API without constant propogation optimizations.
module Reg_spec_ : sig ... end
Reg_spec_
is a register specification. It is namedReg_spec_
rather thanReg_spec
so that people consistently use the nameHardcaml.Reg_spec
rather thanHardcaml.Signal.Reg_spec_
.
val reg : Reg_spec_.t -> enable:t -> t -> t
val reg_fb : Reg_spec_.t -> enable:t -> w:Hardcaml__.Import.int -> (t -> t) -> t
val pipeline : Reg_spec_.t -> n:Hardcaml__.Import.int -> enable:t -> t -> t
val memory : Hardcaml__.Import.int -> write_port:write_port -> read_address:t -> t
val ram_wbr : ?attributes:Rtl_attribute.t Hardcaml__.Import.list -> write_port:write_port -> read_port:read_port -> Hardcaml__.Import.int -> t
val ram_rbw : ?attributes:Rtl_attribute.t Hardcaml__.Import.list -> write_port:write_port -> read_port:read_port -> Hardcaml__.Import.int -> t
val multiport_memory : ?name:Hardcaml__.Import.string -> ?attributes:Rtl_attribute.t Hardcaml__.Import.list -> Hardcaml__.Import.int -> write_ports:write_port Hardcaml__.Import.array -> read_addresses:t Hardcaml__.Import.array -> t Hardcaml__.Import.array
val pp : Hardcaml__.Import.Formatter.t -> t -> Hardcaml__.Import.unit
Pretty printer.