content: {-| More efficient LFSR calculations based on tables rather than unrolling the LFSR updates.
      This is equivalent to unrolling the LFSR update, but I have found that Vivado has a much easier time optimising it.
  
      __FPGA proven__
   -}
  module Clash.LFSR.Table (
          makeLFSRTable,
          tableLFSR
      ) where
  
  import Clash.Prelude
  
  {-| Generates a table for use with `tableLFSR`. You may want to use template haskell to force the table to be evaluated at compile time. -}
  makeLFSRTable
      :: forall m n. KnownNat m
      => (BitVector m -> BitVector n) -- ^ Function that we are creating the table for
      -> Vec m (BitVector n)          -- ^ Resulting table
  makeLFSRTable func = map func $ reverse $ iterateI (`shiftL` 1) 1
  
  {-| Calculate the function using a table computed with `makeLFSRTable`. This exploits the linearity of the LFSR based function by computing it for each bit position in the input BitVector and xoring the results for each bit position that is a set in the input BitVector. 
  -}
  tableLFSR 
      :: forall m n. (KnownNat m, KnownNat n)
      => Vec (m + 1) (BitVector n) -- ^ Table generated by `makeLFSRTable`
      -> BitVector (m + 1)         -- ^ Input bitvector
      -> BitVector n               -- ^ Output
  tableLFSR table input = fold xor $ zipWith func (unpack input) table
      where
      func     :: Bool -> BitVector n -> BitVector n
      func x   =  pack . map (.&. x) . unpack 
  