Copyright | (C) 2015-2016 University of Twente 2017 Google Inc. 2019 Myrtle Software Ltd 2021-2022 QBayLogic B.V. |
---|---|
License | BSD2 (see the file LICENSE) |
Maintainer | QBayLogic B.V. <devops@qbaylogic.com> |
Safe Haskell | Unsafe |
Language | Haskell2010 |
Extensions |
|
Initializing a block RAM with a data file
Block RAM primitives that can be initialized with a data file. The BNF grammar for this data file is simple:
FILE = LINE+ LINE = BIT+ BIT = '0' | '1'
Consecutive LINE
s correspond to consecutive memory addresses starting at 0
.
For example, a data file memory.bin
containing the 9-bit unsigned numbers
7
to 13
looks like:
000000111 000001000 000001001 000001010 000001011 000001100 000001101
Such a file can be produced with memFile
:
writeFile "memory.bin" (memFile Nothing [7 :: Unsigned 9 .. 13])
We can instantiate a block RAM using the contents of the file above like so:
f :: KnownDomain dom => Clock dom -> Enable dom -> Signal dom (Unsigned 3) -> Signal dom (Unsigned 9) f clk en rd =unpack
<$>
blockRamFile
clk en d7 "memory.bin" rd (signal Nothing)
In the example above, we basically treat the block RAM as a synchronous ROM. We can see that it works as expected:
>>> import qualified Data.List as L >>> L.tail $ sampleN 4 $ f systemClockGen enableGen (fromList [3..5]) [10,11,12]
However, we can also interpret the same data as a tuple of a 6-bit unsigned number, and a 3-bit signed number:
g :: KnownDomain dom => Clock dom -> Enable dom -> Signal dom (Unsigned 3) -> Signal dom (Unsigned 6,Signed 3) g clk en rd =unpack
<$>
blockRamFile
clk en d7 "memory.bin" rd (signal Nothing)
And then we would see:
>>> import qualified Data.List as L >>> L.tail $ sampleN 4 $ g systemClockGen enableGen (fromList [3..5]) [(1,2),(1,3)(1,-4)]
Synopsis
- blockRamFile :: (KnownDomain dom, KnownNat m, Enum addr, NFDataX addr, HasCallStack) => Clock dom -> Enable dom -> SNat n -> FilePath -> Signal dom addr -> Signal dom (Maybe (addr, BitVector m)) -> Signal dom (BitVector m)
- blockRamFilePow2 :: forall dom n m. (KnownDomain dom, KnownNat m, KnownNat n, HasCallStack) => Clock dom -> Enable dom -> FilePath -> Signal dom (Unsigned n) -> Signal dom (Maybe (Unsigned n, BitVector m)) -> Signal dom (BitVector m)
- memFile :: forall a f. (BitPack a, Foldable f, HasCallStack) => Maybe Bit -> f a -> String
- blockRamFile# :: forall m dom n. (KnownDomain dom, KnownNat m, HasCallStack) => Clock dom -> Enable dom -> SNat n -> FilePath -> Signal dom Int -> Signal dom Bool -> Signal dom Int -> Signal dom (BitVector m) -> Signal dom (BitVector m)
- initMem :: KnownNat n => FilePath -> IO [BitVector n]
Block RAM synchronized to an arbitrary clock
:: (KnownDomain dom, KnownNat m, Enum addr, NFDataX addr, HasCallStack) | |
=> Clock dom |
|
-> Enable dom |
|
-> SNat n | Size of the BRAM |
-> FilePath | File describing the initial content of the BRAM |
-> Signal dom addr | Read address |
-> Signal dom (Maybe (addr, BitVector m)) | (write address |
-> Signal dom (BitVector m) | Value of the BRAM at address |
Create a block RAM with space for n
elements
- NB: Read value is delayed by 1 cycle
- NB: Initial output value is undefined, reading it will throw an
XException
- NB: This function might not work for specific combinations of code-generation backends and hardware targets. Please check the support table below:
VHDL | Verilog | SystemVerilog | |
---|---|---|---|
Altera/Quartus | Broken | Works | Works |
Xilinx/ISE | Works | Works | Works |
ASIC | Untested | Untested | Untested |
See also:
- See Clash.Explicit.BlockRam for more information on how to use a block RAM.
- Use the adapter
readNew
for obtaining write-before-read semantics like this:
.readNew
clk rst en (blockRamFile
clk en size file) rd wrM - See Clash.Explicit.BlockRam.File for more information on how to instantiate a block RAM with the contents of a data file.
- See
memFile
for creating a data file with Clash. - See Clash.Sized.Fixed for more ideas on how to create your own data files.
:: forall dom n m. (KnownDomain dom, KnownNat m, KnownNat n, HasCallStack) | |
=> Clock dom |
|
-> Enable dom |
|
-> FilePath | File describing the initial content of the BRAM |
-> Signal dom (Unsigned n) | Read address |
-> Signal dom (Maybe (Unsigned n, BitVector m)) | (write address |
-> Signal dom (BitVector m) | Value of the BRAM at address |
Create a block RAM with space for 2^n
elements
- NB: Read value is delayed by 1 cycle
- NB: Initial output value is undefined, reading it will throw an
XException
- NB: This function might not work for specific combinations of code-generation backends and hardware targets. Please check the support table below:
VHDL | Verilog | SystemVerilog | |
---|---|---|---|
Altera/Quartus | Broken | Works | Works |
Xilinx/ISE | Works | Works | Works |
ASIC | Untested | Untested | Untested |
See also:
- See Clash.Prelude.BlockRam for more information on how to use a block RAM.
- Use the adapter
readNew
for obtaining write-before-read semantics like this:
.readNew
clk rst en (blockRamFilePow2' clk en file) rd wrM - See Clash.Explicit.BlockRam.File for more information on how to instantiate a block RAM with the contents of a data file.
- See
memFile
for creating a data file with Clash. - See Clash.Explicit.Fixed for more ideas on how to create your own data files.
Producing files
:: forall a f. (BitPack a, Foldable f, HasCallStack) | |
=> Maybe Bit | Value to map don't care bits to. |
-> f a | Values to convert |
-> String | Contents of the memory file |
Convert data to the String
contents of a memory file.
- NB: Not synthesizable
The following document the several ways to instantiate components with files:
- See Clash.Sized.Fixed for more ideas on how to create your own data files.
Example
The Maybe
datatype has don't care bits, where the actual value does not
matter. But the bits need a defined value in the memory. Either 0 or 1 can be
used, and both are valid representations of the data.
>>>
let es = [ Nothing, Just (7 :: Unsigned 8), Just 8]
>>>
mapM_ (putStrLn . show . pack) es
0b0_...._.... 0b1_0000_0111 0b1_0000_1000>>>
putStr (memFile (Just 0) es)
000000000 100000111 100001000>>>
putStr (memFile (Just 1) es)
011111111 100000111 100001000
Internal
:: forall m dom n. (KnownDomain dom, KnownNat m, HasCallStack) | |
=> Clock dom |
|
-> Enable dom |
|
-> SNat n | Size of the BRAM |
-> FilePath | File describing the initial content of the BRAM |
-> Signal dom Int | Read address |
-> Signal dom Bool | Write enable |
-> Signal dom Int | Write address |
-> Signal dom (BitVector m) | Value to write (at address |
-> Signal dom (BitVector m) | Value of the BRAM at address |
blockRamFile primitive