Abstractly Hardcaml interfaces are made up of a polymorphic type with a single polymorphic variable and a set of functions which can manipulate that type In addition they contain a field which specifies for each contained in a string name which can be used to label the value and the bit width of it s representation as hardware Most commonly an interface will be of type where it will represent a set of Hardcaml signals within a hardware design or where it is used to interact with a Hardcaml simulator Interfaces actually contain many more convenience functions though they can all be derived from the functions shown above Record interfaces The most common form of interface is a record Below we implement an interface by hand for a record containing two fields and In the value we gave a 32 bit width to foo and a 1 bit width to bar Note also the names we specified were not the same as the record field name although much of the time it makes most sense if they are To reduce the amount of boilerplate code to write we provide a ppx called which can generate the above code for you from the type definition The type definition derives Hardcaml and various annotations exist to customize the names and widths of each field Note that each field in the record must be of type Some simple setup is required to use Hardcaml interfaces namely installing and adding it as a preprocessor in the build system Using interfaces Lets say defined the outputs of some hardware module Generally we would write something like Instead we can write Now lets say we have built a simulator over this module and want access to the output ports Other types of interface There are various use cases for interfaces where the outer type is not a record are one example and will be described later s are another where we abstract a Hardcaml value by restricting access to it s implementation They often come with a specialized API for manipulating the value type a t @@deriving sexp_of val iter a t > f a > unit > unit val iter2 a t > b t > f a > b > unit > unit val map a t > f a > b > b t val map2 a t > b t > f a > b > c > c t val to_list a t > a list val port_names_and_widths string * int t a a t Signal t t Bits t t foo bar module Explicit_interface_record_implementation struct module T struct type a t foo a bar a @@deriving equal localize sexp_of let map t f foo f t foo bar f t bar let map2 s t f foo f s foo t foo bar f s bar t bar let iter t f f t foo f t bar let iter2 s t f f s foo t foo f s bar t bar let to_list t t foo t bar let port_names_and_widths foo FOO_FOO 32 bar BAR_BAR 1 end include T include Hardcaml Interface Make T end port_names_and_widths ppx_hardcaml a module Simple_interface struct type a t foo a @bits 32 * Where a bit width is not specified it defaults to 1 * bar a @@deriving hardcaml end ppx_hardcaml Simple_interface let circuit Circuit create_exn name test output foo outputs foo output bar outputs bar let circuit Circuit create_exn name test Simple_interface map2 port_names outputs f Signal output |> to_list let outputs Simple_interface map port_names f Cyclesim out_port sim Enums Scalar
Map and Iter and functions are provided with up to 5 arguments Zip Between 2 and 5 interfaces can be combined using zip The result is an interface of tuples Fold and Scan passes each field of an interface along with an accumulator to the given function For example we can compute the total width of an interface as follows note this is also provided by the value is similar except it returns an interface The function returns the next value of the accumulator and the value of the result field We can compute the offset of each field in an interface as follows note this is also provide by the function and are also defined Association lists and Tags An interface can be converted to and from an association list with and Note that we do not choose to use the string name of fields as keys rather we define and abstract type and value which uniquely represent each fields in an interface Lists of Interfaces and convert between a list of interfaces and interface of lists The signatures should make the operation clearer Misc functions and provide direct access to the names and widths of fields in an interface sets each field to the value Of_signal and Of_bits Both these modules implement the signature They provides functions specialized to the types and respectively Converting from Ints and set each field to the given value by converting from a given integer and also convert from integers but each field may be specified individually Pack and Unpack flattens an interface into a single vector by concatenating all the fields reverses the operation Muxs selects between 2 interfaces and selects between an arbitrary number of interfaces Selection and all work the same way as the corresponding versions on normal signals expect they operate on all fields at once Of_signal specifics A few further functions apply only to the type creates an interface of wires performs wire assignment should be an interface of wires and apply registers or a pipeline of registers to the given interface and create the input and output ports for circuits will apply names to each field based on and a given prefix and suffix Of_always operates on interfaces of type converts an interface of variables to an interface of signals assigns variables with values It results in an always statement and define interfaces of variables will apply names to each field based on and a given prefix and suffix map iter # map5 a Simple_interface t > b Simple_interface t > c Simple_interface t > d Simple_interface t > e Simple_interface t > f a > b > c > d > e > f > f Simple_interface t <fun> # zip port_names port_widths string * int Simple_interface t foo foo 32 bar bar 1 fold f # fold port_widths init 0 f fun total width > total width int 33 sum_of_port_widths scan f # scan port_widths init 0 f fun acc width > acc width acc int Simple_interface t foo 0 bar 32 offsets fold2 scan2 to_alist of_alist tag tags of_interface_list to_interface_list # of_interface_list a Simple_interface t list > a list Simple_interface t <fun> # to_interface_list a list Simple_interface t > a Simple_interface t list <fun> port_names string t port_widths int t const c c Interface Comb Signal t t Bits t t of_unsigned_int of_signed_int of_int_trunc of_unsigned_ints of_signed_ints of_ints_trunc pack unpack mux2 mux priority_select priority_select_with_default onehot_select Signal t t wires assign a b a reg pipeline inputs outputs apply_names port_names Of_always Always Variable t t value assign reg wire apply_names port_names