Hardcaml_xilinx.Memory_builderA general-purpose means of representing memories. The Config.t type allows the user to configure the underlying memory implementations. Eg: Using URAM for bits 0-72, and BRAMs for bits 73-80. This module allows construction of memories in 1D or 2D Modes. See further documentation below.
module For_deriving : sig ... endmodule Config : sig ... endConfiguration for the memory builder. See documentation below for elaboration about the purpose of configuration fields.
module Port_label : sig ... endmodule Create (M : Hardcaml.Interface.S) : sig ... endval read_latency : _ t -> Base.intReturns the read latency of the memory, including possibly any combinational latency due to muxing.
val complete : _ t -> Base.unitMust be called strictly after all set_{read/write}_ functions have been called. This assigns to the underlying instantiated memories, and asserts that the memory satisfies the config's requirements.
1-dimensional memories are laid out the way one would expect. A memory of depth d, with columns shared between URAM and BRAM will have the following layout:
| URAM | BRAM | | x0 | | x1 | | .... | | xd-1 | ------------------------
Read_port_1d does not implement Hardcaml.Interface.S, since the address and data are not necessarily known without a config. To get something one can use in Hardcaml interfaces, you'll have to specialize it with Specialize.
module type Widths_1d = sig ... endmodule Read_port_1d : sig ... endGeneral purpose 1D read ports.
module Write_port_1d : sig ... endGeneral purpose 1D Write ports. Note that it is possible to write 'a Write_port_1d.M(Foo).t in type declarations in mlis.
val set_read_port_1d :
'data t ->
Port_label.t ->
Hardcaml.Signal.t Read_port_1d.t ->
'dataAssigns the read port for 1D memories. Raises a runtime exception when called on a non single dimensional memory.
val set_write_port_1d :
'data t ->
Port_label.t ->
( Hardcaml.Signal.t, 'data ) Write_port_1d.t ->
Base.unitSimilar to set_read_port_1d, but for write ports.
The more general-purporse memory builders can be used to construct memories with the layout H * V where every entry is B bits wide. One can read from any of the entires through the read ports. When writing, however, an entire horizontal index must be written to at once, namely x*, v. This is because the memory is represented using parallel columns of memories along the H axis.
Under the hood, this constructs a memory of depth V and width H * B using the underlying_memories constructs provided by the Config.t. When reading (h, v), the memory reads the underlying memory at index v, which returns H copies of the the data, and multiplexes them with h. For that reason, V must be a power of two, but H does not have to be.
Here's a possible underlying layout by using this memory builder, for H=3, V=8, implemented with 2 URAMs and 1 BRAMs.
| URAM | BRAM | BRAM | | x00 | x10 | x20 | | x01 | x11 | x21 | | x02 | x12 | x22 | | x03 | x13 | x23 | | x04 | x14 | x24 | | x05 | x15 | x25 | | x06 | x16 | x26 | | x07 | x17 | x27 | --------------------------------------
Since writes to a row are atomic, for a given v and d, all entries at x{0, 1, 2}d must be written to simultaneously.
Note that 1D memories are simply a special case of 2D memories where H = 1.
module type Widths_2d = sig ... endmodule Read_port_2d : sig ... endGeneral-purpose Read Ports.
module Write_port_2d : sig ... endGeneral purpose write ports. Note that it is possible to write 'a Write_port_2d.M(Foo).t in type declarations in mlis
val set_write_port_2d :
'data t ->
Port_label.t ->
( Hardcaml.Signal.t, 'data ) Write_port_2d.t ->
Base.unitSet the write port.
val set_read_port_2d :
'data t ->
Port_label.t ->
Hardcaml.Signal.t Read_port_2d.t ->
'dataSet the read port. This should only ever be called once.