content: {-# LANGUAGE MagicHash, TypeApplications, DataKinds #-}
  module BenchRAM (ramBench) where
  
  import Criterion (Benchmark, env, bench, nf, bgroup, envWithCleanup)
  import System.Directory
  import System.IO
  
  import Clash.Explicit.BlockRam
  import Clash.Explicit.BlockRam.File
  import Clash.Explicit.RAM
  import Clash.Explicit.ROM
  import Clash.Explicit.Signal
  import Clash.Prelude.ROM
  import Clash.Promoted.Nat
  import Clash.Promoted.Nat.Literals
  import qualified Clash.Sized.Vector as V
  import Clash.Sized.Internal.BitVector (undefined#)
  
  ramBench :: Benchmark
  ramBench = bgroup "RAMs"
    [ asyncRamBench
    , asyncRomBench
    , blockRamBench
    , blockRamROBench
    , blockRamFileBench
    , blockRamFileROBench
    , romBench
    ]
  
  asyncRamBench :: Benchmark
  asyncRamBench = env setup $ \m ->
    bench "asyncRam#" $
    nf (take 298 . drop 2 . simulate_lazy
          (\rw -> let (r,w) = unbundle rw
                  in  asyncRam# @System
                        clockGen
                        clockGen
                        enableGen
                        (SNat @4096)
                        r
                        (pure True)
                        w
                        w
                     )) m
    where
      setup   = pure (zip [556,557..856] [557,558..857])
  
  asyncRomBench :: Benchmark
  asyncRomBench = env setup $ \m ->
    bench "asyncRom#" $
    nf (take 98 . drop 2 . fmap (asyncRom# ramInit)) m
    where
      ramInit = V.replicate d1024 (1 :: Int)
      setup   = pure ([557,558..857])
  
  blockRamBench :: Benchmark
  blockRamBench = env setup $ \m ->
    bench "blockRam# (100% writes)" $
    nf (take 8298 . drop 2 . simulate_lazy
          (\w -> ram w
                      (pure True)
                      w
                      w
                     )) (cycle m)
    where
      ramInit = V.replicate (SNat @4096) (1 :: Int)
      setup   = pure ([557,558..857])
      ram     = blockRam# @System
                      clockGen
                      enableGen
                      ramInit
  
  blockRamROBench :: Benchmark
  blockRamROBench = env setup $ \m ->
    bench "blockRam# (0% writes)" $
    nf (take 8298 . drop 2 . simulate_lazy
          (\w -> ram w
                      (pure False)
                      w
                      w
                     )) (cycle m)
    where
      ramInit = V.replicate (SNat @4096) (1 :: Int)
      setup   = pure ([557,558..857])
      ram     = blockRam# @System
                      clockGen
                      enableGen
                      ramInit
  
  blockRamFileBench :: Benchmark
  blockRamFileBench = envWithCleanup setup cleanup $ \(~(m,_,ram)) ->
    bench "blockRamFile# (100% writes)" $
    nf (take 8298 . drop 2 . simulate_lazy
          (\w -> ram  w
                      (pure True)
                      w
                      (pure undefined#)
                     )) (cycle m)
    where
      setup = do
        (fp,h) <- openTempFile "." "mem.bin"
        hPutStr h (unlines (replicate 4096 (replicate 63 '0' ++ ['1'])))
        hClose h
        let ram = blockRamFile# @64 @System
                clockGen
                enableGen
                (SNat @4096)
                fp
        fp `seq` ram `seq` return ([557,558..857],fp,ram)
  
      cleanup (_,f,_) = removeFile f
  
  blockRamFileROBench :: Benchmark
  blockRamFileROBench = envWithCleanup setup cleanup $ \(~(m,_,ram)) ->
    bench "blockRamFile# (0% writes)" $
    nf (take 8298 . drop 2 . simulate_lazy
          (\w -> ram w
                     (pure False)
                     w
                     (pure undefined#)
                     )) (cycle m)
    where
      setup = do
        (fp,h) <- openTempFile "." "mem.bin"
        hPutStr h (unlines (replicate 4096 (replicate 63 '0' ++ ['1'])))
        hClose h
        let ram = blockRamFile# @64 @System
                      clockGen
                      enableGen
                      (SNat @4096)
                      fp
        fp `seq` ram `seq` return ([557,558..857], fp, ram)
  
      cleanup (_,f,_) = removeFile f
  
  romBench :: Benchmark
  romBench = env setup $ \m ->
    bench "rom#" $
    nf (take 98 . drop 2 . simulate_lazy
          (\r -> rom# @System
                      clockGen
                      enableGen
                      ramInit
                      r
                     )) m
    where
      ramInit = V.replicate d1024 (1 :: Int)
      setup   = pure ([557,558..857])
  