clash-prelude-0.9: src/CLaSH/Prelude/ROM/File.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE Unsafe #-}
{-# OPTIONS_HADDOCK show-extensions #-}
{-|
Copyright : (C) 2015, University of Twente
License : BSD2 (see the file LICENSE)
Maintainer : Christiaan Baaij <christiaan.baaij@gmail.com>
= Initialising a ROM with a data file #usingromfiles#
ROMs initialised 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 number
@7@ to @13@ looks like:
@
000000111
000001000
000001001
000001010
000001011
000001100
000001101
@
We can instantiate a synchronous ROM using the content of the above file like
so:
@
topEntity :: Signal (Unsigned 3) -> Signal (Unsigned 9)
topEntity rd = 'CLaSH.Class.BitPack.unpack' '<$>' 'romFile' d7 \"memory.bin\" rd
@
And see that it works as expected:
@
__>>> import qualified Data.List as L__
__>>> L.tail $ sampleN 4 $ topEntity (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:
@
topEntity2 :: Signal (Unsigned 3) -> Signal (Unsigned 6,Signed 3)
topEntity2 rd = 'CLaSH.Class.BitPack.unpack' '<$>' 'romFile' d7 \"memory.bin\" rd
@
And then we would see:
@
__>>> import qualified Data.List as L__
__>>> L.tail $ sampleN 4 $ topEntity2 (fromList [3..5])__
[(1,2),(1,3)(1,-4)]
@
-}
module CLaSH.Prelude.ROM.File
( -- * Asynchronous ROM
asyncRomFile
, asyncRomFilePow2
-- * Synchronous ROM synchronised to the system clock
, romFile
, romFilePow2
-- * Synchronous ROM synchronised to an arbitrary clock
, romFile'
, romFilePow2'
-- * Internal
, asyncRomFile#
, romFile#
)
where
import Data.Array (listArray,(!))
import GHC.TypeLits (KnownNat, type (^))
import CLaSH.Prelude.BlockRam.File (initMem)
import CLaSH.Promoted.Nat (SNat,snat,snatToInteger)
import CLaSH.Sized.BitVector (BitVector)
import CLaSH.Signal (Signal)
import CLaSH.Signal.Explicit (Signal', SClock, register', systemClock)
import CLaSH.Sized.Unsigned (Unsigned)
{-# INLINE asyncRomFile #-}
-- | An asynchronous/combinational ROM with space for @n@ elements
--
-- * __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 | No Verilog-2005 support | Works |
-- Xilinx/ISE | Works | Works | Works |
-- ASIC | Untested | Untested | Untested |
-- ===============+==========+=========================+===============+
-- @
--
-- Additional helpful information:
--
-- * See "CLaSH.Prelude.ROM.File#usingromfiles" for more information on how
-- to instantiate a ROM with the contents of a data file.
-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your
-- own data files.
asyncRomFile :: (KnownNat m, Enum addr)
=> SNat n -- ^ Size of the ROM
-> FilePath -- ^ File describing the content of the ROM
-> addr -- ^ Read address @rd@
-> BitVector m -- ^ The value of the ROM at address @rd@
asyncRomFile sz file rd = asyncRomFile# sz file (fromEnum rd)
{-# INLINE asyncRomFilePow2 #-}
-- | An asynchronous/combinational ROM with space for 2^@n@ elements
--
-- * __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 | No Verilog-2005 support | Works |
-- Xilinx/ISE | Works | Works | Works |
-- ASIC | Untested | Untested | Untested |
-- ===============+==========+=========================+===============+
-- @
--
-- Additional helpful information:
--
-- * See "CLaSH.Prelude.ROM.File#usingromfiles" for more information on how
-- to instantiate a ROM with the contents of a data file.
-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your
-- own data files.
asyncRomFilePow2 :: forall n m . (KnownNat m, KnownNat n, KnownNat (2^n))
=> FilePath -- ^ File describing the content of the ROM
-> Unsigned n -- ^ Read address @rd@
-> BitVector m -- ^ The value of the ROM at address @rd@
asyncRomFilePow2 = asyncRomFile (snat :: SNat (2^n))
{-# NOINLINE asyncRomFile# #-}
-- | asyncROMFile primitive
asyncRomFile# :: KnownNat m
=> SNat n -- ^ Size of the ROM
-> FilePath -- ^ File describing the content of the ROM
-> Int -- ^ Read address @rd@
-> BitVector m -- ^ The value of the ROM at address @rd@
asyncRomFile# sz file rd = content ! rd
where
content = listArray (0,szI-1) (initMem file)
szI = fromInteger (snatToInteger sz)
{-# INLINE romFile #-}
-- | A ROM with a synchronous read port, with space for @n@ elements
--
-- * __NB__: Read value is delayed by 1 cycle
-- * __NB__: Initial output value is 'undefined'
-- * __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 | No Verilog-2005 support | Works |
-- Xilinx/ISE | Works | Works | Works |
-- ASIC | Untested | Untested | Untested |
-- ===============+==========+=========================+===============+
-- @
--
-- Additional helpful information:
--
-- * See "CLaSH.Prelude.ROM.File#usingromfiles" for more information on how
-- to instantiate a ROM with the contents of a data file.
-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your
-- own data files.
romFile :: (KnownNat m, KnownNat k)
=> SNat n -- ^ Size of the ROM
-> FilePath -- ^ File describing the content of the ROM
-> Signal (Unsigned k) -- ^ Read address @rd@
-> Signal (BitVector m)
-- ^ The value of the ROM at address @rd@ from the previous clock cycle
romFile = romFile' systemClock
{-# INLINE romFilePow2 #-}
-- | A ROM with a synchronous read port, with space for 2^@n@ elements
--
-- * __NB__: Read value is delayed by 1 cycle
-- * __NB__: Initial output value is 'undefined'
-- * __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 | No Verilog-2005 support | Works |
-- Xilinx/ISE | Works | Works | Works |
-- ASIC | Untested | Untested | Untested |
-- ===============+==========+=========================+===============+
-- @
--
-- Additional helpful information:
--
-- * See "CLaSH.Prelude.ROM.File#usingromfiles" for more information on how
-- to instantiate a ROM with the contents of a data file.
-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your
-- own data files.
romFilePow2 :: forall n m . (KnownNat m, KnownNat n, KnownNat (2^n))
=> FilePath -- ^ File describing the content of the ROM
-> Signal (Unsigned n) -- ^ Read address @rd@
-> Signal (BitVector m)
-- ^ The value of the ROM at address @rd@ from the previous clock cycle
romFilePow2 = romFile' systemClock (snat :: SNat (2^n))
{-# INLINE romFilePow2' #-}
-- | A ROM with a synchronous read port, with space for 2^@n@ elements
--
-- * __NB__: Read value is delayed by 1 cycle
-- * __NB__: Initial output value is 'undefined'
-- * __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 | No Verilog-2005 support | Works |
-- Xilinx/ISE | Works | Works | Works |
-- ASIC | Untested | Untested | Untested |
-- ===============+==========+=========================+===============+
-- @
--
-- Additional helpful information:
--
-- * See "CLaSH.Prelude.ROM.File#usingromfiles" for more information on how
-- to instantiate a ROM with the contents of a data file.
-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your
-- own data files.
romFilePow2' :: forall clk n m . (KnownNat m, KnownNat n, KnownNat (2^n))
=> SClock clk -- ^ 'Clock' to synchronize to
-> FilePath -- ^ File describing the content of
-- the ROM
-> Signal' clk (Unsigned n) -- ^ Read address @rd@
-> Signal' clk (BitVector m)
-- ^ The value of the ROM at address @rd@ from the previous clock
-- cycle
romFilePow2' clk = romFile' clk (snat :: SNat (2^n))
{-# INLINE romFile' #-}
-- | A ROM with a synchronous read port, with space for @n@ elements
--
-- * __NB__: Read value is delayed by 1 cycle
-- * __NB__: Initial output value is 'undefined'
-- * __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 | No Verilog-2005 support | Works |
-- Xilinx/ISE | Works | Works | Works |
-- ASIC | Untested | Untested | Untested |
-- ===============+==========+=========================+===============+
-- @
--
-- Additional helpful information:
--
-- * See "CLaSH.Prelude.ROM.File#usingromfiles" for more information on how
-- to instantiate a ROM with the contents of a data file.
-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your
-- own data files.
romFile' :: (KnownNat m, Enum addr)
=> SClock clk -- ^ 'Clock' to synchronize to
-> SNat n -- ^ Size of the ROM
-> FilePath -- ^ File describing the content of the
-- ROM
-> Signal' clk addr -- ^ Read address @rd@
-> Signal' clk (BitVector m)
-- ^ The value of the ROM at address @rd@ from the previous clock cycle
romFile' clk sz file rd = romFile# clk sz file (fromEnum <$> rd)
{-# NOINLINE romFile# #-}
-- | romFile primitive
romFile# :: KnownNat m
=> SClock clk -- ^ 'Clock' to synchronize to
-> SNat n -- ^ Size of the ROM
-> FilePath -- ^ File describing the content of the
-- ROM
-> Signal' clk Int -- ^ Read address @rd@
-> Signal' clk (BitVector m)
-- ^ The value of the ROM at address @rd@ from the previous clock cycle
romFile# clk sz file rd = register' clk undefined ((content !) <$> rd)
where
content = listArray (0,szI-1) (initMem file)
szI = fromInteger (snatToInteger sz)