{-| Copyright : (C) 2015-2016, University of Twente License : BSD2 (see the file LICENSE) Maintainer : Christiaan Baaij <christiaan.baaij@gmail.com> ROMs -} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE Safe #-} {-# OPTIONS_HADDOCK show-extensions #-} module CLaSH.Prelude.ROM ( -- * Asynchronous ROM asyncRom , asyncRomPow2 -- * Synchronous ROM synchronised to the system clock , rom , romPow2 -- * Synchronous ROM synchronised to an arbitrary clock , rom' , romPow2' -- * Internal , asyncRom# , rom# ) where import Data.Array ((!),listArray) import GHC.TypeLits (KnownNat, type (^)) import CLaSH.Signal (Signal) import CLaSH.Signal.Explicit (Signal', SClock, systemClock) import CLaSH.Sized.Unsigned (Unsigned) import CLaSH.Signal.Explicit (register') import CLaSH.Sized.Vector (Vec, maxIndex, toList) {-# INLINE asyncRom #-} -- | An asynchronous/combinational ROM with space for @n@ elements -- -- Additional helpful information: -- -- * See "CLaSH.Sized.Fixed#creatingdatafiles" and "CLaSH.Prelude.BlockRam#usingrams" -- for ideas on how to use ROMs and RAMs asyncRom :: (KnownNat n, Enum addr) => Vec n a -- ^ ROM content -- -- __NB:__ must be a constant -> addr -- ^ Read address @rd@ -> a -- ^ The value of the ROM at address @rd@ asyncRom content rd = asyncRom# content (fromEnum rd) {-# INLINE asyncRomPow2 #-} -- | An asynchronous/combinational ROM with space for 2^@n@ elements -- -- Additional helpful information: -- -- * See "CLaSH.Sized.Fixed#creatingdatafiles" and "CLaSH.Prelude.BlockRam#usingrams" -- for ideas on how to use ROMs and RAMs asyncRomPow2 :: (KnownNat (2^n), KnownNat n) => Vec (2^n) a -- ^ ROM content -- -- __NB:__ must be a constant -> Unsigned n -- ^ Read address @rd@ -> a -- ^ The value of the ROM at address @rd@ asyncRomPow2 = asyncRom {-# NOINLINE asyncRom# #-} -- | asyncROM primitive asyncRom# :: KnownNat n => Vec n a -- ^ ROM content -- -- __NB:__ must be a constant -> Int -- ^ Read address @rd@ -> a -- ^ The value of the ROM at address @rd@ asyncRom# content rd = arr ! rd where szI = maxIndex content arr = listArray (0,szI) (toList content) {-# INLINE rom #-} -- | 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' -- -- Additional helpful information: -- -- * See "CLaSH.Sized.Fixed#creatingdatafiles" and "CLaSH.Prelude.BlockRam#usingrams" -- for ideas on how to use ROMs and RAMs rom :: (KnownNat n, KnownNat m) => Vec n a -- ^ ROM content -- -- __NB:__ must be a constant -> Signal (Unsigned m) -- ^ Read address @rd@ -> Signal a -- ^ The value of the ROM at address @rd@ rom = rom' systemClock {-# INLINE romPow2 #-} -- | 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' -- -- Additional helpful information: -- -- * See "CLaSH.Sized.Fixed#creatingdatafiles" and "CLaSH.Prelude.BlockRam#usingrams" -- for ideas on how to use ROMs and RAMs romPow2 :: (KnownNat (2^n), KnownNat n) => Vec (2^n) a -- ^ ROM content -- -- __NB:__ must be a constant -> Signal (Unsigned n) -- ^ Read address @rd@ -> Signal a -- ^ The value of the ROM at address @rd@ romPow2 = rom' systemClock {-# INLINE romPow2' #-} -- | 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' -- -- Additional helpful information: -- -- * See "CLaSH.Sized.Fixed#creatingdatafiles" and "CLaSH.Prelude.BlockRam#usingrams" -- for ideas on how to use ROMs and RAMs romPow2' :: (KnownNat (2^n), KnownNat n) => SClock clk -- ^ 'Clock' to synchronize to -> Vec (2^n) a -- ^ ROM content -- -- __NB:__ must be a constant -> Signal' clk (Unsigned n) -- ^ Read address @rd@ -> Signal' clk a -- ^ The value of the ROM at address @rd@ romPow2' = rom' {-# INLINE rom' #-} -- | 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' -- -- Additional helpful information: -- -- * See "CLaSH.Sized.Fixed#creatingdatafiles" and "CLaSH.Prelude.BlockRam#usingrams" -- for ideas on how to use ROMs and RAMs rom' :: (KnownNat n, Enum addr) => SClock clk -- ^ 'Clock' to synchronize to -> Vec n a -- ^ ROM content -- -- __NB:__ must be a constant -> Signal' clk addr -- ^ Read address @rd@ -> Signal' clk a -- ^ The value of the ROM at address @rd@ from the previous clock cycle rom' clk content rd = rom# clk content (fromEnum <$> rd) {-# NOINLINE rom# #-} -- | ROM primitive rom# :: KnownNat n => SClock clk -- ^ 'Clock' to synchronize to -> Vec n a -- ^ ROM content -- -- __NB:__ must be a constant -> Signal' clk Int -- ^ Read address @rd@ -> Signal' clk a -- ^ The value of the ROM at address @rd@ from the previous clock cycle rom# clk content rd = register' clk undefined ((arr !) <$> rd) where szI = maxIndex content arr = listArray (0,szI) (toList content)