Module Hardcaml.Signal

include Hardcaml__.Signal_intf.Signal
type signal_op =
| Signal_add
| Signal_sub
| Signal_mulu
| Signal_muls
| Signal_and
| Signal_or
| Signal_xor
| Signal_eq
| Signal_not
| Signal_lt
| Signal_cat
| Signal_mux

simple operators

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 * Bits.t
| Op of signal_id * signal_op
| Wire of signal_id * t Hardcaml__.Import.ref
| Select of signal_id * Hardcaml__.Import.int * Hardcaml__.Import.int
| Reg of signal_id * register
| Mem of signal_id * Uid.t * register * memory
| Multiport_mem of signal_id * Hardcaml__.Import.int * write_port Hardcaml__.Import.array
| Mem_read_port of signal_id * t * t
| Inst of signal_id * Uid.t * 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;
}
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

returns the (private) signal_id. For internal use only.

val uid : t -> Uid.t

returns the unique id of the signal

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_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_op : signal_op -> t -> Hardcaml__.Import.bool

is the signal the given operator?

val const_value : t -> Bits.t

return the (binary) string representing a constants value

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 -> t -> 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 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.

module Const_prop : sig ... end

Combinatorial signal API

include Comb.S with type t := t
type t
val sexp_of_t : t -> Ppx_sexp_conv_lib.Sexp.t
include Hardcaml__.Import.Equal.S with type t := t
type t
val equal : t Hardcaml__.Import.Equal.equal
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 index num_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 if num_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 number x, 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 consti : width:Hardcaml__.Import.int -> Hardcaml__.Import.int -> t

convert integer to constant

val consti32 : width:Hardcaml__.Import.int -> Hardcaml__.Import.int32 -> t
val consti64 : width:Hardcaml__.Import.int -> Hardcaml__.Import.int64 -> t
val consthu : width:Hardcaml__.Import.int -> Hardcaml__.Import.string -> t

convert unsigned hex string to constant

val consths : width:Hardcaml__.Import.int -> Hardcaml__.Import.string -> t

convert signed hex string to constant

val constd : width:Hardcaml__.Import.int -> Hardcaml__.Import.string -> t

convert decimal string to constant

val constv : Hardcaml__.Import.string -> t

convert verilog style string to constant

val constibl : Hardcaml__.Import.int Hardcaml__.Import.list -> t

convert IntbitsList to constant

val const : Hardcaml__.Import.string -> t

convert verilog style or binary string to constant

val concat : 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 if ts is empty or if any t in ts is empty.

val concat_e : t Hardcaml__.Import.list -> t

same as concat except empty signals are first filtered out

val (@:) : t -> t -> t

concatenate two signals.

let c = a @: b in ...

equivalent to concat [ a; b ]

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 width w

val ones : Hardcaml__.Import.int -> t

ones w makes a constant of all ones of width w

val one : Hardcaml__.Import.int -> t

one w makes a one valued constant of width w

val select : t -> Hardcaml__.Import.int -> Hardcaml__.Import.int -> t

select t hi lo selects from t bits in the range hi...lo, inclusive. select raises unless hi and lo fall within 0 .. width t - 1 and hi >= lo.

val select_e : t -> Hardcaml__.Import.int -> Hardcaml__.Import.int -> t

same as select except invalid indices return empty

val bit : t -> Hardcaml__.Import.int -> t

select a single bit

val msb : t -> t

get most significant bit

val lsbs : t -> t

get least significant bits

val lsb : t -> t

get least significant bit

val msbs : t -> t

get most significant bits

val drop_bottom : t -> Hardcaml__.Import.int -> t

drop_bottom s n drop bottom n bits of s

val drop_top : t -> Hardcaml__.Import.int -> t

drop_top s n drop top n bits of s

val sel_bottom : t -> Hardcaml__.Import.int -> t

sel_bottom s n select bottom n bits of s

val sel_top : t -> Hardcaml__.Import.int -> t

sel_top s n select top n bits of s

val insert : into:t -> t -> at_offset:Hardcaml__.Import.int -> t

insert ~into:t x ~at_offset insert x into t at given offet

val sel : t -> (Hardcaml__.Import.int * Hardcaml__.Import.int) -> t
val mux : t -> t Hardcaml__.Import.list -> t

multiplexer.

let m = mux sel inputs in ...

Given l = List.length inputs and w = width sel the following conditions must hold.

l <= 2**w, l >= 2

If 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. Selects t if c is high otherwise f.

t and f must have same width and c must be 1 bit.

Equivalent to mux c [f; t]

val mux_init : t -> Hardcaml__.Import.int -> f:(Hardcaml__.Import.int -> t) -> t
val cases : t -> t -> (Hardcaml__.Import.int * t) Hardcaml__.Import.list -> t

case mux

val matches : ?⁠resize:(t -> Hardcaml__.Import.int -> t) -> ?⁠default:t -> t -> (Hardcaml__.Import.int * t) Hardcaml__.Import.list -> t

match mux

val (&:) : t -> t -> t

logical and

val (&:.) : t -> Hardcaml__.Import.int -> t
val (&&:) : t -> t -> t

a <>:. 0 &: b <>:. 0

val (|:) : t -> t -> t

logical or

val (|:.) : t -> Hardcaml__.Import.int -> t
val (||:) : t -> t -> t

a <>:. 0 |: b <>:. 0

val (^:) : t -> t -> t

logic xor

val (^:.) : t -> Hardcaml__.Import.int -> t
val (~:) : t -> t

logical not

val (+:) : t -> t -> t

addition

val (+:.) : t -> Hardcaml__.Import.int -> t
val (-:) : t -> t -> t

subtraction

val (-:.) : t -> Hardcaml__.Import.int -> t
val negate : t -> t

negation

val (*:) : t -> t -> t

unsigned multiplication

val (*+) : t -> t -> t

signed multiplication

val (==:) : t -> t -> t

equality

val (==:.) : t -> Hardcaml__.Import.int -> t
val (<>:) : t -> t -> t

inequality

val (<>:.) : t -> Hardcaml__.Import.int -> t
val (<:) : t -> t -> t

less than

val (<:.) : t -> Hardcaml__.Import.int -> t
val lt : t -> t -> t
val (>:) : t -> t -> t

greater than

val (>:.) : t -> Hardcaml__.Import.int -> t
val (<=:) : t -> t -> t

less than or equal to

val (<=:.) : t -> Hardcaml__.Import.int -> t
val (>=:) : t -> t -> t

greater than or equal to

val (>=:.) : t -> Hardcaml__.Import.int -> t
val (<+) : t -> t -> t

signed less than

val (<+.) : t -> Hardcaml__.Import.int -> t
val (>+) : t -> t -> t

signed greater than

val (>+.) : t -> Hardcaml__.Import.int -> t
val (<=+) : t -> t -> t

signed less than or equal to

val (<=+.) : t -> Hardcaml__.Import.int -> t
val (>=+) : t -> t -> t

signed greated than or equal to

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 treats t as unsigned and resizes it to fit exactly within an OCaml Int.t.

  • If width t > Int.num_bits then the upper bits are truncated.
  • If width t >= Int.num_bits and bit t (Int.num_bits-1) = vdd (i.e. the msb of the resulting Int.t is set), then the result is negative.
  • If t is Signal.t and not a constant value, an exception is raised.
val to_sint : t -> Hardcaml__.Import.int

to_sint t treats t as signed and resizes it to fit exactly within an OCaml Int.t.

  • If width t > Int.num_bits then the upper bits are truncated.
  • If t is Signal.t and not a constant value, an exception is raised.
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_bstr : t -> Hardcaml__.Import.string

create binary string from signal

val bits : t -> t Hardcaml__.Import.list

convert signal to a list of bits, msb first

val to_array : t -> t Hardcaml__.Import.array

to_array s convert signal s to array of bits with lsb at index 0

val of_array : t Hardcaml__.Import.array -> t

of_array a convert array a of bits to signal with lsb at index 0

val repeat : t -> Hardcaml__.Import.int -> t

repeat signal n times

val split_in_half : t -> t * t

split signal in half

val split : ?⁠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. If exact is true the input signal width must be exactly divisable by part_width.

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 log_shift : (t -> Hardcaml__.Import.int -> t) -> t -> t -> t

shift by variable amount

val uresize : t -> Hardcaml__.Import.int -> t

uresize t w returns the unsigned resize of t to width w. If w = width t, this is a no-op. If w < width t, this selects the w low bits of t. If w > width t, this extends t with zero (width t - w).

val sresize : t -> Hardcaml__.Import.int -> t

sresize t w returns the signed resize of t to width w. If w = width t, this is a no-op. If w < width t, this selects the w low bits of t. If w > width t, this extends t with width t - w copies of msb t.

val ue : t -> t

unsigned resize by +1 bit

val se : t -> t

signed resize by +1 bit

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 in l and applies resize 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 applies resize x w to a and b where w is the maximum of their widths. It then returns f a b

val reduce : f:('a -> 'a -> 'a) -> 'a Hardcaml__.Import.list -> 'a

fold 'op' though list

val reverse : t -> t

reverse bits

val mod_counter : max:Hardcaml__.Import.int -> t -> t

mod_counter max t is if 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 if input = [].

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 whose valid signal is high. valid will be set low in the returned With_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 returns default 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 is valid 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 in t.

val is_pow2 : (t -> t) Hardcaml__.Comb_intf.optional_branching_factor

is_pow2 t returns a bit to indicate if t is a power of 2.

val leading_ones : (t -> t) Hardcaml__.Comb_intf.optional_branching_factor

leading_ones t returns the number of consecutive 1s from the most significant bit of t down.

val trailing_ones : (t -> t) Hardcaml__.Comb_intf.optional_branching_factor

trailing_ones t returns the number of consecutive 1s from the least significant bit of t up.

val leading_zeros : (t -> t) Hardcaml__.Comb_intf.optional_branching_factor

leading_zeros t returns the number of consecutive 0s from the most significant bit of t down.

val trailing_zeros : (t -> t) Hardcaml__.Comb_intf.optional_branching_factor

trailing_zeros t returns the number of consecutive 0s from the least significant bit of t 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 of x. x is treated as unsigned and an error is indicated by valid = gnd in the return value if x = 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 of x. x is treated as unsigned and an error is indicated by valid = gnd in the return value if x = 0.

val binary_to_onehot : t -> t

convert binary to onehot

val onehot_to_binary : t -> t

convert onehot to binary

val binary_to_gray : t -> t

convert binary to gray code

val gray_to_binary : t -> t

convert gray code to binary

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
module Signed : TypedMath
module Uop : TypedMath with type v := t

Unsigned operations compatible with type t

module Sop : TypedMath with type v := t

Signed operations compatible with type t

val wire : Hardcaml__.Import.int -> t

creates an unassigned wire

val wireof : t -> t

creates an assigned 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 Reg_spec_ : sig ... end

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_.

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 : Hardcaml__.Import.int -> write_port:write_port -> read_port:read_port -> t
val ram_rbw : Hardcaml__.Import.int -> write_port:write_port -> read_port:read_port -> t
val multiport_memory : 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.