-- Assert correct behavior: -- -- Undefined enable: -- The written-to address should read 'undefined', but other addresses -- should still have their data. -- -- Undefined write address: -- All addresses should read 'undefined'. -- -- OOB write address -- All addresses should read 'undefined. -- -- Undefined write data: -- The written-to address should read 'undefined', but other addresses -- should still have their data. -- -- Deasserted enable -- It shouldn't matter that other write inputs are 'undefined'. -- -- Deasserted enable, OOB address -- It shouldn't matter that it is out of bounds. -- -- OOB read address -- The sample should be undefined, nothing more. -- -- Read address strictness -- If the read result is not used, out-of-bounds read address shouldn't -- matter (equivalent to issue #1458). {-# LANGUAGE NoImplicitPrelude #-} module Clash.Tests.Ram (tests) where import qualified Data.List as L import Test.Tasty import Test.Tasty.HUnit import Clash.Explicit.Prelude import Clash.Explicit.RAM type Ram = ( Signal System Int -> Signal System Bool -> Signal System Int -> Signal System Int -> Signal System (Maybe Int) ) ram :: Ram ram rd we wr din = maybeIsX <$> asyncRam# clockGen clockGen enableGen d2 rd we wr din maskOobRead :: Ram maskOobRead rd we wr din = maybeIsX <$> mux (rd .<. 2) ram0 (pure 4) where ram0 = asyncRam# clockGen clockGen enableGen d2 rd we wr din type Samples = [(Int, Bool, Int, Int, Maybe Int)] initMem, undefEn, undefWAddr, oobWAddr, undefWData, enFalse, enFalseOobWAddr, oobRAddr, oobRAddrStrict :: Samples -- rd enable waddr wdata dout initMem = [ ( 0, True , 0 , 0 , Nothing) , ( 0, True , 1 , 1 , Just 0 ) ] undefEn = initMem <> [ ( 0, undefined, 0 , 2 , Just 0 ) , ( 0, False , 0 , 3 , Nothing) , ( 1, False , 0 , 3 , Just 1 ) ] undefWAddr = initMem <> [ ( 0, True , undefined, 2 , Just 0 ) , ( 0, False , 0 , 3 , Nothing) , ( 1, False , 0 , 3 , Nothing) ] oobWAddr = initMem <> [ ( 0, True , 3 , 2 , Just 0 ) , ( 0, False , 0 , 3 , Nothing) , ( 1, False , 0 , 3 , Nothing) ] undefWData = initMem <> [ ( 0, True , 0 , undefined, Just 0 ) , ( 0, False , 0 , 3 , Nothing) , ( 1, False , 0 , 3 , Just 1 ) ] enFalse = initMem <> [ ( 0, False , undefined, undefined, Just 0) , ( 0, False , undefined, undefined, Just 0) , ( 1, False , undefined, undefined, Just 1) ] enFalseOobWAddr = initMem <> [ ( 0, False , 255 , 2 , Just 0 ) , ( 0, False , 0 , 3 , Just 0 ) , ( 1, False , 0 , 3 , Just 1 ) ] oobRAddr = initMem <> [ ( 2, False , 0 , 3 , Nothing) , ( 0, False , 0 , 3 , Just 0 ) , ( 1, False , 0 , 3 , Just 1 ) ] oobRAddrStrict = initMem <> [ ( 1, False , 0 , 3 , Just 1 ) , ( 2, False , 0 , 3 , Just 4 ) , ( 0, False , 0 , 3 , Just 0 ) ] ramAssertion :: Ram -> Samples -> Assertion ramAssertion ram0 samples = actual @?= expectedOutput where (rd, we, wr, din, expectedOutput) = L.unzip5 samples actual = sampleN (L.length samples) $ ram0 (fromList rd) (fromList we) (fromList wr) (fromList din) tests :: TestTree tests = testGroup "Ram" [ testCase "Undefined enable" $ ramAssertion ram undefEn , testCase "Undefined write address" $ ramAssertion ram undefWAddr , testCase "OOB write address" $ ramAssertion ram oobWAddr , testCase "Undefined write data" $ ramAssertion ram undefWData , testCase "Deasserted enable" $ ramAssertion ram enFalse , testCase "Deasserted enable, OOB address" $ ramAssertion ram enFalseOobWAddr , testCase "OOB read address" $ ramAssertion ram oobRAddr , testCase "Read address strictness" $ ramAssertion maskOobRead oobRAddrStrict ]