Combinational logic is formed from boolean functions whose outputs are fully determined by their current inputs This is in contrast to sequential logic where the outputs are a function of their current and previous inputs At the lowest level combinational circuits are built from simple primitives such as NAND gates in ASIC designs or LUTs in FPGA designs Building circuits with such low level primitives is tedious so instead we provide a set of higher level primitives with which to design circuits The module type provides these primitives Combinational circuits can be thought of as graphs with nodes representing logic operations and edges representing often also referred to as These graphs are directed and must not contain any cycles Comb S wires signals

Vectors and Widths

The fundamental type in Hardcaml is a vector with a specified width The width can be one or more bits There exists a special signal called which has zero width but is rarely used and exists for internal use In Hardcaml the types and are used to represent vectors For now we will consider s The simplest way to create a value is the function Note that in both the specification of the bit vector with and the printing of the value we treat the left most 1 or 0 as the most significant bit We can now interrogate the width of this value It is always possible to get the width of a Hardcaml vector empty Signal t Bits t Bits t Bits t of_string # open Hardcaml Bits # let x of_string 11001 val x t 11001 of_string x # width x int 5

Binary Constants and Converting to OCaml Ints

takes a string which consists of s and s s are also allowed and are ignored The first character in the string becomes the most significant bit msb of the vector The vector width is the sum of the number of and characters in the string A feature of the module but not s is the ability to convert back to an OCaml value We can do so with the function has interpreted as an unsigned three bit integer value will treat it as a signed twos complement integer value If the resulting value cannot fit in an integer then the functions will raise may be useful in such cases if used carefully of_string 0 1 _ 0 1 # let x of_string 100 val x t 100 Bits Signal to_unsigned_int # to_unsigned_int x int 4 to_unsigned_int x to_signed_int # to_signed_int x int 4 to_int_trunc

Richer Constants

Probably the most useful constant generating functions are and If the given value is negative it will be sign extended to the appropriate width Values too large or too small to be represented in bits will raise an exception will silently truncate the input value Variants for and are also provided The function is actually more general than just converting binary values It can also parse a specification string which roughly follows the Verilog constant format Binary decimal octal and hexadecimal notations are supported If the format specifier is capitalized the leading bit in the given value will be used for sign extension only relevant for the binary octal and hex specifiers of_unsigned_int of_signed_int # of_unsigned_int width 10 514 t 1000000010 # of_signed_int width 10 1 t 1111111111 width of_int_trunc Int32 t Int64 t of_string <width> <format><value> b d o h # of_string 5 b1101 t 01101 # of_string 5 hd t 01101 # of_string 5 d13 t 01101 # of_string 5 B1101 t 11101 # of_string 5 Hd t 11101

Operators, Widths, and Their Names

Hardcaml provides a set of operators providing the usual functions such as logical arithmetic and comparison operations A key API design point is Hardcaml does not encode signedness into the type of vectors Instead the operator suffix indicates how to interpret the operands For example there are two less than operators Operators ending with treat operands as signed Operators ending with treat operands as unsigned For example there are two distinct less than operators for signed less than for unsigned less than Many operators are agnostic to signedness The addition operator is an example of this Addition requires both arguments to have the same bit width otherwise it raises a runtime exception and the bit by bit addition process produces identical results whether the values are interpreted as signed or unsigned The carry behavior is the same only the semantic interpretation of the result differs < <

API Tour

The following describes several key functions See the documentation for for other useful functions Arithmetic addition subtraction Both arguments must be the same width The result will be the width of the arguments unsigned multiplication signed multiplication The arguments can have arbitrary widths The result will be the sum of the widths of the arguments Logical logical and logical or logical xor Both arguments must be the same width The result will be the width of the arguments logical not The result will be the width of the argument Comparison equals not equals unsigned comparisons signed comparisons Both arguments must be the same width The result will be 1 bit Multiplexers selects when is high and when is low should be 1 bit wide and must be the same width selects the element in at position The range of must not exceed the length of can be shorter however and the last element in the list is logically repeated as much as needed Cases The function is similar to a multiplexer in that it selects one of its inputs to output It is given a signal and each case has a corresponding value The first case where is output If no case matches the value is output Select A range of bits can be extracted from the vector using The upper and lower indexes are inclusive Selecting outside the range of the input value raises The operator provides a nice syntax for this The operator can also be used similar to Verilog Other selection functions include and a richer set of operators for special circumstances Concatenation Vectors can be concatenated using the following functions The _msb and _lsb suffix in the functions indicates whether the head of the list holds the most significant bit or least significant bit respectively Comb S * * & | ^ <> < < > > < < > > mux2 sel t f t sel f sel sel t f mux sel lst lst sel sel lst lst # List init 4 f fun sel > mux of_unsigned_int width 2 sel gnd vdd t list 0 1 1 1 cases select match select match # let cases select cases default of_unsigned_int width 8 10 of_unsigned_int width 4 select of_unsigned_int width 4 2 of_unsigned_int width 8 20 of_unsigned_int width 4 3 of_unsigned_int width 8 30 of_unsigned_int width 4 6 of_unsigned_int width 8 60 |> to_unsigned_int val cases int > int <fun> # cases 3 int 30 # cases 6 int 60 default # cases 4 int 10 select # select of_string 0011000 high 4 low 3 t 11 # of_string 001100 3 2 t 11 Some x # of_string 001100 3 Some 2 t 01 sel_top sel_bottom drop_top drop_bottom # vdd @ gnd t 10 # concat_msb vdd gnd t 10 # concat_lsb gnd vdd t 10

Integer Arguments

Various operators can take an integer as their right hand argument The right hand argument will be converted to a vector by inferring the required width from the left hand argument Such operators are suffixed with a # of_string 011 1 t 100

Richer Operations on Vectors

The functions on vectors described so far form a small subset of the full API provided by Hardcaml However all the other functions are expressed in terms of this subset Splitting and split a vector into multiple parts defines the width of each part By default the original vector must be exactly divisible by Shifting shift a vector by a constant amount rotate by a constant amount builds a variable width shift circuit Resizing and resize a vector to the given width which may be larger or smaller When growing larger adds 0 s at the top while repeats the msb Reductions takes a list of vectors and an operation to perform between them all Or reduction Summation does much the same thing as except it forms the computation in a tree structure Additional the operation it performs can take more than 2 arguments as specified by an value We commonly use and together With_valid is a record type with a 1 bit signal and an arbitrary signal It is meant to work a little like an Option type where means and means Priority based selectors takes a list of and returns the first one whose is high It returns a single whose valid is low if no case was selected adds a default value which is output if no case is selected Counting bits all count some number of bits within a vector Their implementations are tree based and have logic depth Onehot and Gray and convert between onehot and binary representations Similarly for and Random creates a random constant vector of the given width Mostly useful for testbenches Bits set is equivalent to is equivalent to is equivalent to With_zero_width We disallow zero width vectors in Hardcaml allows us to represent them The type is where indicates zero width The functions provided try to do sane things with zero width vectors TypedMath and are modules with signature They provide arithmetic and comparison operators Since they know the signedness of the type they can for example add or compare vectors of different widths Additionally addition and subtraction grow their result width by one bit to ensure overflow is impossible This extra bit captures the carry that might result from the operation split_lsb split_msb part_width part_width # split_lsb part_width 4 of_string 16 H4321 t list 0001 0010 0011 0100 # split_msb part_width 4 exact false of_string 15 H4321 t list 1000 0110 0100 001 sll srl sra rotr rotl log_shift # sra of_string 10 by 1 t 11 # log_shift of_string 0100 f rotl by of_string 10 t 0001 uresize sresize uresize sresize reduce # reduce f | bits_lsb of_string 00100 t 1 # reduce f List map 1 3 5 6 f of_unsigned_int width 6 t 001111 tree reduce arity # tree arity 4 of_string 111111 |> bits_lsb f function a > a | a b > a & b | a b c > a & b & c | a b c d > a & b & c & d | _ > failwith impossible t 1 tree reduce # tree arity 4 of_string 111111 |> bits_lsb f reduce f & t 1 With_valid valid value valid 0 None valid 1 Some value priority_select With_valids valid With_valid priority_select_with_default # priority_select_with_default default of_string 1111 valid gnd value of_string 0001 valid gnd value of_string 0100 t 1111 # priority_select_with_default default of_string 1111 valid vdd value of_string 0001 valid vdd value of_string 0100 t 0001 popcount leading_zeros leading_ones trailing_zeros trailing_ones log width # popcount of_string 1100011 t 100 # trailing_zeros of_string 1110010100 t 0010 binary_to_onehot onehot_to_binary gray_to_binary binary_to_gray # binary_to_onehot of_string 110 t 01000000 # onehot_to_binary of_string 01000 t 011 # binary_to_gray of_string 110 t 101 # gray_to_binary of_string 01000 t 01111 random any_bits_set x <> 0 all_bits_set x 1 no_bits_set x 0 With_zero_width Comb t option None # With_zero_width concat_msb None ones 2 zero 0 zero 1 Some of_string 1101 With_zero_width t Base Option Some 1101101 Unsigned Signed TypedMath