Hardcaml_xilinx.Memory_builder
A 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 ... end
module Config : sig ... end
Configuration for the memory builder. See documentation below for elaboration about the purpose of configuration fields.
module Port_label : sig ... end
module Create (M : Hardcaml.Interface.S) : sig ... end
val read_latency : _ t -> Base.int
Returns the read latency of the memory, including possibly any combinational latency due to muxing.
val complete : _ t -> Base.unit
Must 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 ... end
module Read_port_1d : sig ... end
General purpose 1D read ports.
module Write_port_1d : sig ... end
General 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 ->
'data
Assigns 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.unit
Similar 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 | | x0
0
| x1
0
| x2
0
| | x0
1
| x1
1
| x2
1
| | x0
2
| x1
2
| x2
2
| | x0
3
| x1
3
| x2
3
| | x0
4
| x1
4
| x2
4
| | x0
5
| x1
5
| x2
5
| | x0
6
| x1
6
| x2
6
| | x0
7
| x1
7
| x2
7
| --------------------------------------
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 ... end
module Read_port_2d : sig ... end
General-purpose Read Ports.
module Write_port_2d : sig ... end
General 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.unit
Set the write port.
val set_read_port_2d :
'data t ->
Port_label.t ->
Hardcaml.Signal.t Read_port_2d.t ->
'data
Set the read port. This should only ever be called once.