From 18cb48dfe0361fe97a0113dd85808e1b281e0a4e Mon Sep 17 00:00:00 2001 From: Martijn Bastiaan Date: Thu, 2 Mar 2023 10:52:33 +0100 Subject: [PATCH 1/3] Move `trueDualPortBlockRam#` blackboxes to inline YAML To ease future iterations --- .../Clash_Explicit_BlockRam.primitives.yaml | 57 ----- .../Clash_Explicit_BlockRam.primitives.yaml | 58 ----- .../Clash_Explicit_BlockRam.primitives.yaml | 64 ------ clash-prelude/src/Clash/Explicit/BlockRam.hs | 204 +++++++++++++++++- 4 files changed, 202 insertions(+), 181 deletions(-) diff --git a/clash-lib/prims/systemverilog/Clash_Explicit_BlockRam.primitives.yaml b/clash-lib/prims/systemverilog/Clash_Explicit_BlockRam.primitives.yaml index b4dc597f05..0e83169735 100644 --- a/clash-lib/prims/systemverilog/Clash_Explicit_BlockRam.primitives.yaml +++ b/clash-lib/prims/systemverilog/Clash_Explicit_BlockRam.primitives.yaml @@ -131,60 +131,3 @@ end~FI assign ~RESULT = ~FROMBV[~SYM[2]][~TYP[10]]; // blockRam1 end -- BlackBox: - name: Clash.Explicit.BlockRam.trueDualPortBlockRam# - kind: Declaration - type: |- - trueDualPortBlockRam# :: - forall nAddrs domA domB a . - ( HasCallStack ~ARG[0] - , KnownNat nAddrs ~ARG[1] - , KnownDomain domA ~ARG[2] - , KnownDomain domB ~ARG[3] - , NFDataX a ~ARG[4] - ) => - - Clock domA -> ~ARG[5] - Signal domA Bool -> ~ARG[6] - Signal domA Bool -> ~ARG[7] - Signal domA (Index nAddrs) -> ~ARG[8] - Signal domA a -> ~ARG[9] - - Clock domB -> ~ARG[10] - Signal domB Bool -> ~ARG[11] - Signal domB Bool -> ~ARG[12] - Signal domB (Index nAddrs) -> ~ARG[13] - Signal domB a -> ~ARG[14] - (Signal domA a, Signal domB a) - template: |- - // trueDualPortBlockRam begin - // Shared memory - logic [~SIZE[~TYP[9]]-1:0] ~GENSYM[mem][0] [~LIT[1]-1:0]; - - ~SIGD[~GENSYM[data_slow][1]][9]; - ~SIGD[~GENSYM[data_fast][2]][14]; - - // Port A - always @(~IF~ACTIVEEDGE[Rising][2]~THENposedge~ELSEnegedge~FI ~ARG[5]) begin - if(~ARG[6]) begin - ~SYM[1] <= ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI]; - if(~ARG[7]) begin - ~SYM[1] <= ~ARG[9]; - ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI] <= ~ARG[9]; - end - end - end - - // Port B - always @(~IF~ACTIVEEDGE[Rising][3]~THENposedge~ELSEnegedge~FI ~ARG[10]) begin - if(~ARG[11]) begin - ~SYM[2] <= ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI]; - if(~ARG[12]) begin - ~SYM[2] <= ~ARG[14]; - ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI] <= ~ARG[14]; - end - end - end - - assign ~RESULT = {~SYM[1], ~SYM[2]}; - // end trueDualPortBlockRam diff --git a/clash-lib/prims/verilog/Clash_Explicit_BlockRam.primitives.yaml b/clash-lib/prims/verilog/Clash_Explicit_BlockRam.primitives.yaml index 5205693956..51a9b03069 100644 --- a/clash-lib/prims/verilog/Clash_Explicit_BlockRam.primitives.yaml +++ b/clash-lib/prims/verilog/Clash_Explicit_BlockRam.primitives.yaml @@ -142,61 +142,3 @@ ~RESULT <= ~SYM[0][~ARG[7]]; end~FI // blockRam1 end -- BlackBox: - name: Clash.Explicit.BlockRam.trueDualPortBlockRam# - kind: Declaration - type: |- - trueDualPortBlockRam# :: - forall nAddrs domA domB a . - ( HasCallStack ~ARG[0] - , KnownNat nAddrs ~ARG[1] - , KnownDomain domA ~ARG[2] - , KnownDomain domB ~ARG[3] - , NFDataX a ~ARG[4] - ) => - - Clock domA -> ~ARG[5] - Signal domA Bool -> ~ARG[6] - Signal domA Bool -> ~ARG[7] - Signal domA (Index nAddrs) -> ~ARG[8] - Signal domA a -> ~ARG[9] - - Clock domB -> ~ARG[10] - Signal domB Bool -> ~ARG[11] - Signal domB Bool -> ~ARG[12] - Signal domB (Index nAddrs) -> ~ARG[13] - Signal domB a -> ~ARG[14] - (Signal domA a, Signal domB a) - template: |- - // trueDualPortBlockRam begin - // Shared memory - reg [~SIZE[~TYP[9]]-1:0] ~GENSYM[mem][0] [~LIT[1]-1:0]; - - reg ~SIGD[~GENSYM[data_slow][1]][9]; - reg ~SIGD[~GENSYM[data_fast][2]][14]; - - // Port A - always @(~IF~ACTIVEEDGE[Rising][2]~THENposedge~ELSEnegedge~FI ~ARG[5]) begin - if(~ARG[6]) begin - ~SYM[1] <= ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI]; - if(~ARG[7]) begin - ~SYM[1] <= ~ARG[9]; - ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI] <= ~ARG[9]; - end - end - end - - // Port B - always @(~IF~ACTIVEEDGE[Rising][3]~THENposedge~ELSEnegedge~FI ~ARG[10]) begin - if(~ARG[11]) begin - ~SYM[2] <= ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI]; - if(~ARG[12]) begin - ~SYM[2] <= ~ARG[14]; - ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI] <= ~ARG[14]; - end - end - end - - assign ~RESULT = {~SYM[1], ~SYM[2]}; - - // end trueDualPortBlockRam diff --git a/clash-lib/prims/vhdl/Clash_Explicit_BlockRam.primitives.yaml b/clash-lib/prims/vhdl/Clash_Explicit_BlockRam.primitives.yaml index f485f6c997..6dbb756b24 100644 --- a/clash-lib/prims/vhdl/Clash_Explicit_BlockRam.primitives.yaml +++ b/clash-lib/prims/vhdl/Clash_Explicit_BlockRam.primitives.yaml @@ -171,67 +171,3 @@ end process; ~FI end block; --end blockRam1 -- BlackBox: - name: Clash.Explicit.BlockRam.trueDualPortBlockRam# - kind: Declaration - type: |- - trueDualPortBlockRam# :: - forall nAddrs domA domB a . - ( HasCallStack ~ARG[0] - , KnownNat nAddrs ~ARG[1] - , KnownDomain domA ~ARG[2] - , KnownDomain domB ~ARG[3] - , NFDataX a ~ARG[4] - ) => - - Clock domA -> ~ARG[5] - Signal domA Bool -> ~ARG[6] - Signal domA Bool -> ~ARG[7] - Signal domA (Index nAddrs) -> ~ARG[8] - Signal domA a -> ~ARG[9] - - Clock domB -> ~ARG[10] - Signal domB Bool -> ~ARG[11] - Signal domB Bool -> ~ARG[12] - Signal domB (Index nAddrs) -> ~ARG[13] - Signal domB a -> ~ARG[14] - (Signal domA a, Signal domB a) - template: |- - -- trueDualPortBlockRam begin - ~GENSYM[~RESULT_trueDualPortBlockRam][1] : block - -- Shared memory - type mem_type is array ( ~LIT[1]-1 downto 0 ) of ~TYP[9]; - shared variable mem : mem_type; - signal ~GENSYM[a_dout][2] : ~TYP[9]; - signal ~GENSYM[b_dout][3] : ~TYP[14]; - begin - - -- Port A - process(~ARG[5]) - begin - if(rising_edge(~ARG[5])) then - if(~ARG[6]) then - if(~ARG[7]) then - mem(~IF~SIZE[~TYP[8]]~THENto_integer(~ARG[8])~ELSE0~FI) := ~ARG[9]; - end if; - ~SYM[2] <= mem(~IF~SIZE[~TYP[8]]~THENto_integer(~ARG[8])~ELSE0~FI); - end if; - end if; - end process; - - -- Port B - process(~ARG[10]) - begin - if(rising_edge(~ARG[10])) then - if(~ARG[11]) then - if(~ARG[12]) then - mem(~IF~SIZE[~TYP[13]]~THENto_integer(~ARG[13])~ELSE0~FI) := ~ARG[14]; - end if; - ~SYM[3] <= mem(~IF~SIZE[~TYP[13]]~THENto_integer(~ARG[13])~ELSE0~FI); - end if; - end if; - end process; - - ~RESULT <= (~SYM[2], ~SYM[3]); - end block; - -- end trueDualPortBlockRam diff --git a/clash-prelude/src/Clash/Explicit/BlockRam.hs b/clash-prelude/src/Clash/Explicit/BlockRam.hs index 7e2ec77fd8..cc8a949679 100644 --- a/clash-prelude/src/Clash/Explicit/BlockRam.hs +++ b/clash-prelude/src/Clash/Explicit/BlockRam.hs @@ -2,7 +2,7 @@ Copyright : (C) 2013-2016, University of Twente, 2016-2017, Myrtle Software Ltd, 2017 , Google Inc., - 2021-2022, QBayLogic B.V., + 2021-2023, QBayLogic B.V., 2022 , Google Inc., License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. @@ -389,6 +389,8 @@ This concludes the short introduction to using 'blockRam'. {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE QuasiQuotes #-} +{-# LANGUAGE TemplateHaskellQuotes #-} {-# LANGUAGE Trustworthy #-} @@ -436,6 +438,7 @@ import GHC.Arr (STArray, unsafeReadSTArray, unsafeWriteSTArray) import qualified Data.Sequence as Seq import Data.Sequence (Seq) +import Data.String.Interpolate(__i) import Data.Tuple (swap) import GHC.Generics (Generic) import GHC.Stack (HasCallStack, withFrozenCallStack) @@ -443,7 +446,7 @@ import GHC.TypeLits (KnownNat, type (^), type (<=)) import Unsafe.Coerce (unsafeCoerce) import Clash.Annotations.Primitive - (hasBlackBox) + (Primitive(InlineYamlPrimitive), HDL(..), hasBlackBox) import Clash.Class.Num (SaturationMode(SatBound), satSucc) import Clash.Explicit.Signal (KnownDomain, Enable, register, fromEnable) import Clash.Signal.Internal @@ -1286,6 +1289,203 @@ trueDualPortBlockRam# clkA enA weA addrA datA clkB enB weB addrB datB labelB = "Port B" {-# NOINLINE trueDualPortBlockRam# #-} {-# ANN trueDualPortBlockRam# hasBlackBox #-} +{-# ANN trueDualPortBlockRam# ( + let + bbName = show 'trueDualPortBlockRam# + in + InlineYamlPrimitive [VHDL] [__i| + BlackBox: + name: "#{bbName}" + kind: Declaration + type: |- + trueDualPortBlockRam :: + forall nAddrs domA domB a . + ( HasCallStack ~ARG[0] + , KnownNat nAddrs ~ARG[1] + , KnownDomain domA ~ARG[2] + , KnownDomain domB ~ARG[3] + , NFDataX a ~ARG[4] + ) => + + Clock domA -> ~ARG[5] + Signal domA Bool -> ~ARG[6] + Signal domA Bool -> ~ARG[7] + Signal domA (Index nAddrs) -> ~ARG[8] + Signal domA a -> ~ARG[9] + + Clock domB -> ~ARG[10] + Signal domB Bool -> ~ARG[11] + Signal domB Bool -> ~ARG[12] + Signal domB (Index nAddrs) -> ~ARG[13] + Signal domB a -> ~ARG[14] + (Signal domA a, Signal domB a) + template: |- + -- trueDualPortBlockRam begin + ~GENSYM[~RESULT_trueDualPortBlockRam][1] : block + -- Shared memory + type mem_type is array ( ~LIT[1]-1 downto 0 ) of ~TYP[9]; + shared variable mem : mem_type; + signal ~GENSYM[a_dout][2] : ~TYP[9]; + signal ~GENSYM[b_dout][3] : ~TYP[14]; + begin + + -- Port A + process(~ARG[5]) + begin + if(rising_edge(~ARG[5])) then + if(~ARG[6]) then + if(~ARG[7]) then + mem(~IF~SIZE[~TYP[8]]~THENto_integer(~ARG[8])~ELSE0~FI) := ~ARG[9]; + end if; + ~SYM[2] <= mem(~IF~SIZE[~TYP[8]]~THENto_integer(~ARG[8])~ELSE0~FI); + end if; + end if; + end process; + + -- Port B + process(~ARG[10]) + begin + if(rising_edge(~ARG[10])) then + if(~ARG[11]) then + if(~ARG[12]) then + mem(~IF~SIZE[~TYP[13]]~THENto_integer(~ARG[13])~ELSE0~FI) := ~ARG[14]; + end if; + ~SYM[3] <= mem(~IF~SIZE[~TYP[13]]~THENto_integer(~ARG[13])~ELSE0~FI); + end if; + end if; + end process; + + ~RESULT <= (~SYM[2], ~SYM[3]); + end block; + -- end trueDualPortBlockRam +|]) #-} +{-# ANN trueDualPortBlockRam# ( + let + bbName = show 'trueDualPortBlockRam# + in + InlineYamlPrimitive [SystemVerilog] [__i| + BlackBox: + name: "#{bbName}" + kind: Declaration + type: |- + trueDualPortBlockRam :: + forall nAddrs domA domB a . + ( HasCallStack ~ARG[0] + , KnownNat nAddrs ~ARG[1] + , KnownDomain domA ~ARG[2] + , KnownDomain domB ~ARG[3] + , NFDataX a ~ARG[4] + ) => + + Clock domA -> ~ARG[5] + Signal domA Bool -> ~ARG[6] + Signal domA Bool -> ~ARG[7] + Signal domA (Index nAddrs) -> ~ARG[8] + Signal domA a -> ~ARG[9] + + Clock domB -> ~ARG[10] + Signal domB Bool -> ~ARG[11] + Signal domB Bool -> ~ARG[12] + Signal domB (Index nAddrs) -> ~ARG[13] + Signal domB a -> ~ARG[14] + (Signal domA a, Signal domB a) + template: |- + // trueDualPortBlockRam begin + // Shared memory + logic [~SIZE[~TYP[9]]-1:0] ~GENSYM[mem][0] [~LIT[1]-1:0]; + + ~SIGD[~GENSYM[data_slow][1]][9]; + ~SIGD[~GENSYM[data_fast][2]][14]; + + // Port A + always @(~IF~ACTIVEEDGE[Rising][2]~THENposedge~ELSEnegedge~FI ~ARG[5]) begin + if(~ARG[6]) begin + ~SYM[1] <= ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI]; + if(~ARG[7]) begin + ~SYM[1] <= ~ARG[9]; + ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI] <= ~ARG[9]; + end + end + end + + // Port B + always @(~IF~ACTIVEEDGE[Rising][3]~THENposedge~ELSEnegedge~FI ~ARG[10]) begin + if(~ARG[11]) begin + ~SYM[2] <= ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI]; + if(~ARG[12]) begin + ~SYM[2] <= ~ARG[14]; + ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI] <= ~ARG[14]; + end + end + end + + assign ~RESULT = {~SYM[1], ~SYM[2]}; + // end trueDualPortBlockRam +|]) #-} +{-# ANN trueDualPortBlockRam# ( + let + bbName = show 'trueDualPortBlockRam# + in + InlineYamlPrimitive [Verilog] [__i| + BlackBox: + name: "#{bbName}" + kind: Declaration + type: |- + trueDualPortBlockRam :: + forall nAddrs domA domB a . + ( HasCallStack ~ARG[0] + , KnownNat nAddrs ~ARG[1] + , KnownDomain domA ~ARG[2] + , KnownDomain domB ~ARG[3] + , NFDataX a ~ARG[4] + ) => + + Clock domA -> ~ARG[5] + Signal domA Bool -> ~ARG[6] + Signal domA Bool -> ~ARG[7] + Signal domA (Index nAddrs) -> ~ARG[8] + Signal domA a -> ~ARG[9] + + Clock domB -> ~ARG[10] + Signal domB Bool -> ~ARG[11] + Signal domB Bool -> ~ARG[12] + Signal domB (Index nAddrs) -> ~ARG[13] + Signal domB a -> ~ARG[14] + (Signal domA a, Signal domB a) + template: |- + // trueDualPortBlockRam begin + // Shared memory + reg [~SIZE[~TYP[9]]-1:0] ~GENSYM[mem][0] [~LIT[1]-1:0]; + + reg ~SIGD[~GENSYM[data_slow][1]][9]; + reg ~SIGD[~GENSYM[data_fast][2]][14]; + + // Port A + always @(~IF~ACTIVEEDGE[Rising][2]~THENposedge~ELSEnegedge~FI ~ARG[5]) begin + if(~ARG[6]) begin + ~SYM[1] <= ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI]; + if(~ARG[7]) begin + ~SYM[1] <= ~ARG[9]; + ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI] <= ~ARG[9]; + end + end + end + + // Port B + always @(~IF~ACTIVEEDGE[Rising][3]~THENposedge~ELSEnegedge~FI ~ARG[10]) begin + if(~ARG[11]) begin + ~SYM[2] <= ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI]; + if(~ARG[12]) begin + ~SYM[2] <= ~ARG[14]; + ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI] <= ~ARG[14]; + end + end + end + + assign ~RESULT = {~SYM[1], ~SYM[2]}; + + // end trueDualPortBlockRam +|]) #-} -- | Haskell model for the primitive 'trueDualPortBlockRam#'. From e80b4759840025e3add8d016bf8b043189631b0e Mon Sep 17 00:00:00 2001 From: Martijn Bastiaan Date: Thu, 2 Mar 2023 11:33:50 +0100 Subject: [PATCH 2/3] Use named symbols in `trueDualPortBlockRam#` blackboxes --- clash-prelude/src/Clash/Explicit/BlockRam.hs | 258 ++++++++++--------- 1 file changed, 137 insertions(+), 121 deletions(-) diff --git a/clash-prelude/src/Clash/Explicit/BlockRam.hs b/clash-prelude/src/Clash/Explicit/BlockRam.hs index cc8a949679..79c3d16410 100644 --- a/clash-prelude/src/Clash/Explicit/BlockRam.hs +++ b/clash-prelude/src/Clash/Explicit/BlockRam.hs @@ -395,8 +395,14 @@ This concludes the short introduction to using 'blockRam'. {-# LANGUAGE Trustworthy #-} {-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-} +{-# OPTIONS_GHC -fconstraint-solver-iterations=20 #-} {-# OPTIONS_HADDOCK show-extensions #-} +-- In the blackbox definitions of 'trueDualPortBlockRam#' we bind a 'Vec', which +-- GHC doesn't recognize as being complete (though it will throw a type error if +-- the left and right side of the pattern match disagree on their types). +{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} + -- See [Note: eta port names for trueDualPortBlockRam] {-# OPTIONS_GHC -fno-do-lambda-eta-expansion #-} @@ -459,6 +465,7 @@ import Clash.Sized.Unsigned (Unsigned) import Clash.Sized.Index (Index) import Clash.Sized.Vector (Vec, replicate, iterateI) import qualified Clash.Sized.Vector as CV +import Clash.Sized.Vector (Vec((:>), Nil)) import Clash.XException (maybeIsX, NFDataX(deepErrorX), defaultSeqX, fromJustX, undefined, XException (..), seqX, isX, errorX) @@ -1292,197 +1299,206 @@ trueDualPortBlockRam# clkA enA weA addrA datA clkB enB weB addrB datB {-# ANN trueDualPortBlockRam# ( let bbName = show 'trueDualPortBlockRam# - in - InlineYamlPrimitive [VHDL] [__i| + ( _hasCallStack + :> knownNatAddrs + :> _knownDomainA + :> _knownDomainB + :> _nfdataX + + :> clockA + :> enaA + :> wenaA + :> addrA + :> datA + + :> clockB + :> enaB + :> wenaB + :> addrB + :> datB + + :> Nil + ) = CV.indicesI @15 + + ( symBlockName + :> symDoutA + :> symDoutB + :> Nil + ) = CV.indicesI @3 + in InlineYamlPrimitive [VHDL] [__i| BlackBox: name: "#{bbName}" kind: Declaration - type: |- - trueDualPortBlockRam :: - forall nAddrs domA domB a . - ( HasCallStack ~ARG[0] - , KnownNat nAddrs ~ARG[1] - , KnownDomain domA ~ARG[2] - , KnownDomain domB ~ARG[3] - , NFDataX a ~ARG[4] - ) => - - Clock domA -> ~ARG[5] - Signal domA Bool -> ~ARG[6] - Signal domA Bool -> ~ARG[7] - Signal domA (Index nAddrs) -> ~ARG[8] - Signal domA a -> ~ARG[9] - - Clock domB -> ~ARG[10] - Signal domB Bool -> ~ARG[11] - Signal domB Bool -> ~ARG[12] - Signal domB (Index nAddrs) -> ~ARG[13] - Signal domB a -> ~ARG[14] - (Signal domA a, Signal domB a) template: |- -- trueDualPortBlockRam begin - ~GENSYM[~RESULT_trueDualPortBlockRam][1] : block + ~GENSYM[~RESULT_trueDualPortBlockRam][#{symBlockName}] : block -- Shared memory - type mem_type is array ( ~LIT[1]-1 downto 0 ) of ~TYP[9]; + type mem_type is array ( ~LIT[#{knownNatAddrs}]-1 downto 0 ) of ~TYP[#{datA}]; shared variable mem : mem_type; - signal ~GENSYM[a_dout][2] : ~TYP[9]; - signal ~GENSYM[b_dout][3] : ~TYP[14]; + signal ~GENSYM[a_dout][#{symDoutA}] : ~TYP[#{datA}]; + signal ~GENSYM[b_dout][#{symDoutB}] : ~TYP[#{datB}]; begin -- Port A - process(~ARG[5]) + process(~ARG[#{clockA}]) begin - if(rising_edge(~ARG[5])) then - if(~ARG[6]) then - if(~ARG[7]) then - mem(~IF~SIZE[~TYP[8]]~THENto_integer(~ARG[8])~ELSE0~FI) := ~ARG[9]; + if(rising_edge(~ARG[#{clockA}])) then + if(~ARG[#{enaA}]) then + if(~ARG[#{wenaA}]) then + mem(~IF~SIZE[~TYP[#{addrA}]]~THENto_integer(~ARG[#{addrA}])~ELSE0~FI) := ~ARG[#{datA}]; end if; - ~SYM[2] <= mem(~IF~SIZE[~TYP[8]]~THENto_integer(~ARG[8])~ELSE0~FI); + ~SYM[#{symDoutA}] <= mem(~IF~SIZE[~TYP[#{addrA}]]~THENto_integer(~ARG[#{addrA}])~ELSE0~FI); end if; end if; end process; -- Port B - process(~ARG[10]) + process(~ARG[#{clockB}]) begin - if(rising_edge(~ARG[10])) then - if(~ARG[11]) then - if(~ARG[12]) then - mem(~IF~SIZE[~TYP[13]]~THENto_integer(~ARG[13])~ELSE0~FI) := ~ARG[14]; + if(rising_edge(~ARG[#{clockB}])) then + if(~ARG[#{enaB}]) then + if(~ARG[#{wenaB}]) then + mem(~IF~SIZE[~TYP[#{addrB}]]~THENto_integer(~ARG[#{addrB}])~ELSE0~FI) := ~ARG[#{datB}]; end if; - ~SYM[3] <= mem(~IF~SIZE[~TYP[13]]~THENto_integer(~ARG[13])~ELSE0~FI); + ~SYM[#{symDoutB}] <= mem(~IF~SIZE[~TYP[#{addrB}]]~THENto_integer(~ARG[#{addrB}])~ELSE0~FI); end if; end if; end process; - ~RESULT <= (~SYM[2], ~SYM[3]); + ~RESULT <= (~SYM[#{symDoutA}], ~SYM[#{symDoutB}]); end block; -- end trueDualPortBlockRam |]) #-} {-# ANN trueDualPortBlockRam# ( let bbName = show 'trueDualPortBlockRam# - in - InlineYamlPrimitive [SystemVerilog] [__i| + ( _hasCallStack + :> knownNatAddrs + :> knownDomainA + :> knownDomainB + :> _nfdataX + + :> clockA + :> enaA + :> wenaA + :> addrA + :> datA + + :> clockB + :> enaB + :> wenaB + :> addrB + :> datB + + :> Nil + ) = CV.indicesI @15 + + ( symMem + :> symDoutA + :> symDoutB + :> Nil + ) = CV.indicesI @3 + in InlineYamlPrimitive [SystemVerilog] [__i| BlackBox: name: "#{bbName}" kind: Declaration - type: |- - trueDualPortBlockRam :: - forall nAddrs domA domB a . - ( HasCallStack ~ARG[0] - , KnownNat nAddrs ~ARG[1] - , KnownDomain domA ~ARG[2] - , KnownDomain domB ~ARG[3] - , NFDataX a ~ARG[4] - ) => - - Clock domA -> ~ARG[5] - Signal domA Bool -> ~ARG[6] - Signal domA Bool -> ~ARG[7] - Signal domA (Index nAddrs) -> ~ARG[8] - Signal domA a -> ~ARG[9] - - Clock domB -> ~ARG[10] - Signal domB Bool -> ~ARG[11] - Signal domB Bool -> ~ARG[12] - Signal domB (Index nAddrs) -> ~ARG[13] - Signal domB a -> ~ARG[14] - (Signal domA a, Signal domB a) template: |- // trueDualPortBlockRam begin // Shared memory - logic [~SIZE[~TYP[9]]-1:0] ~GENSYM[mem][0] [~LIT[1]-1:0]; + logic [~SIZE[~TYP[#{datA}]]-1:0] ~GENSYM[mem][#{symMem}] [~LIT[#{knownNatAddrs}]-1:0]; - ~SIGD[~GENSYM[data_slow][1]][9]; - ~SIGD[~GENSYM[data_fast][2]][14]; + ~SIGD[~GENSYM[data_slow][#{symDoutA}]][#{datA}]; + ~SIGD[~GENSYM[data_fast][#{symDoutB}]][#{datB}]; // Port A - always @(~IF~ACTIVEEDGE[Rising][2]~THENposedge~ELSEnegedge~FI ~ARG[5]) begin - if(~ARG[6]) begin - ~SYM[1] <= ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI]; - if(~ARG[7]) begin - ~SYM[1] <= ~ARG[9]; - ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI] <= ~ARG[9]; + always @(~IF~ACTIVEEDGE[Rising][#{knownDomainA}]~THENposedge~ELSEnegedge~FI ~ARG[#{clockA}]) begin + if(~ARG[#{enaA}]) begin + ~SYM[#{symDoutA}] <= ~SYM[#{symMem}][~IF~SIZE[~TYP[#{addrA}]]~THEN~ARG[#{addrA}]~ELSE0~FI]; + if(~ARG[#{wenaA}]) begin + ~SYM[#{symDoutA}] <= ~ARG[#{datA}]; + ~SYM[#{symMem}][~IF~SIZE[~TYP[#{addrA}]]~THEN~ARG[#{addrA}]~ELSE0~FI] <= ~ARG[#{datA}]; end end end // Port B - always @(~IF~ACTIVEEDGE[Rising][3]~THENposedge~ELSEnegedge~FI ~ARG[10]) begin - if(~ARG[11]) begin - ~SYM[2] <= ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI]; - if(~ARG[12]) begin - ~SYM[2] <= ~ARG[14]; - ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI] <= ~ARG[14]; + always @(~IF~ACTIVEEDGE[Rising][#{knownDomainB}]~THENposedge~ELSEnegedge~FI ~ARG[#{clockB}]) begin + if(~ARG[#{enaB}]) begin + ~SYM[#{symDoutB}] <= ~SYM[#{symMem}][~IF~SIZE[~TYP[#{addrB}]]~THEN~ARG[#{addrB}]~ELSE0~FI]; + if(~ARG[#{wenaB}]) begin + ~SYM[#{symDoutB}] <= ~ARG[#{datB}]; + ~SYM[#{symMem}][~IF~SIZE[~TYP[#{addrB}]]~THEN~ARG[#{addrB}]~ELSE0~FI] <= ~ARG[#{datB}]; end end end - assign ~RESULT = {~SYM[1], ~SYM[2]}; + assign ~RESULT = {~SYM[#{symDoutA}], ~SYM[#{symDoutB}]}; // end trueDualPortBlockRam |]) #-} {-# ANN trueDualPortBlockRam# ( let bbName = show 'trueDualPortBlockRam# - in - InlineYamlPrimitive [Verilog] [__i| + ( _hasCallStack + :> knownNatAddrs + :> knownDomainA + :> knownDomainB + :> _nfdataX + + :> clockA + :> enaA + :> wenaA + :> addrA + :> datA + + :> clockB + :> enaB + :> wenaB + :> addrB + :> datB + + :> Nil + ) = CV.indicesI @15 + + ( symMem + :> symDoutA + :> symDoutB + :> Nil + ) = CV.indicesI @3 + in InlineYamlPrimitive [Verilog] [__i| BlackBox: name: "#{bbName}" kind: Declaration - type: |- - trueDualPortBlockRam :: - forall nAddrs domA domB a . - ( HasCallStack ~ARG[0] - , KnownNat nAddrs ~ARG[1] - , KnownDomain domA ~ARG[2] - , KnownDomain domB ~ARG[3] - , NFDataX a ~ARG[4] - ) => - - Clock domA -> ~ARG[5] - Signal domA Bool -> ~ARG[6] - Signal domA Bool -> ~ARG[7] - Signal domA (Index nAddrs) -> ~ARG[8] - Signal domA a -> ~ARG[9] - - Clock domB -> ~ARG[10] - Signal domB Bool -> ~ARG[11] - Signal domB Bool -> ~ARG[12] - Signal domB (Index nAddrs) -> ~ARG[13] - Signal domB a -> ~ARG[14] - (Signal domA a, Signal domB a) template: |- // trueDualPortBlockRam begin // Shared memory - reg [~SIZE[~TYP[9]]-1:0] ~GENSYM[mem][0] [~LIT[1]-1:0]; + reg [~SIZE[~TYP[#{datA}]]-1:0] ~GENSYM[mem][#{symMem}] [~LIT[#{knownNatAddrs}]-1:0]; - reg ~SIGD[~GENSYM[data_slow][1]][9]; - reg ~SIGD[~GENSYM[data_fast][2]][14]; + reg ~SIGD[~GENSYM[data_slow][#{symDoutA}]][#{datA}]; + reg ~SIGD[~GENSYM[data_fast][#{symDoutB}]][#{datB}]; // Port A - always @(~IF~ACTIVEEDGE[Rising][2]~THENposedge~ELSEnegedge~FI ~ARG[5]) begin - if(~ARG[6]) begin - ~SYM[1] <= ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI]; - if(~ARG[7]) begin - ~SYM[1] <= ~ARG[9]; - ~SYM[0][~IF~SIZE[~TYP[8]]~THEN~ARG[8]~ELSE0~FI] <= ~ARG[9]; + always @(~IF~ACTIVEEDGE[Rising][#{knownDomainA}]~THENposedge~ELSEnegedge~FI ~ARG[#{clockA}]) begin + if(~ARG[#{enaA}]) begin + ~SYM[#{symDoutA}] <= ~SYM[#{symMem}][~IF~SIZE[~TYP[#{addrA}]]~THEN~ARG[#{addrA}]~ELSE0~FI]; + if(~ARG[#{wenaA}]) begin + ~SYM[#{symDoutA}] <= ~ARG[#{datA}]; + ~SYM[#{symMem}][~IF~SIZE[~TYP[#{addrA}]]~THEN~ARG[#{addrA}]~ELSE0~FI] <= ~ARG[#{datA}]; end end end // Port B - always @(~IF~ACTIVEEDGE[Rising][3]~THENposedge~ELSEnegedge~FI ~ARG[10]) begin - if(~ARG[11]) begin - ~SYM[2] <= ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI]; - if(~ARG[12]) begin - ~SYM[2] <= ~ARG[14]; - ~SYM[0][~IF~SIZE[~TYP[13]]~THEN~ARG[13]~ELSE0~FI] <= ~ARG[14]; + always @(~IF~ACTIVEEDGE[Rising][#{knownDomainB}]~THENposedge~ELSEnegedge~FI ~ARG[#{clockB}]) begin + if(~ARG[#{enaB}]) begin + ~SYM[#{symDoutB}] <= ~SYM[#{symMem}][~IF~SIZE[~TYP[#{addrB}]]~THEN~ARG[#{addrB}]~ELSE0~FI]; + if(~ARG[#{wenaB}]) begin + ~SYM[#{symDoutB}] <= ~ARG[#{datB}]; + ~SYM[#{symMem}][~IF~SIZE[~TYP[#{addrB}]]~THEN~ARG[#{addrB}]~ELSE0~FI] <= ~ARG[#{datB}]; end end end - assign ~RESULT = {~SYM[1], ~SYM[2]}; + assign ~RESULT = {~SYM[#{symDoutA}], ~SYM[#{symDoutB}]}; // end trueDualPortBlockRam |]) #-} From 0cda2e887bcf02626642af72bfd126ef22f34e10 Mon Sep 17 00:00:00 2001 From: Martijn Bastiaan Date: Fri, 10 Feb 2023 12:38:57 +0100 Subject: [PATCH 3/3] Remove domain ordering from 'trueDualPortBlockRam' Previous commits have removed the clock domain ordering sensitivity from the TDP BRAM model, but didn't remove the wrapper, nor the hack prepending `ClockB` to the result of `clockTicks`. Closes #2352 --- .gitignore | 3 + clash-prelude/src/Clash/Explicit/BlockRam.hs | 139 ++++++------------ .../Clash/Tests/AsyncFIFOSynchronizer.hs | 24 +-- 3 files changed, 60 insertions(+), 106 deletions(-) diff --git a/.gitignore b/.gitignore index 8162eea560..9b3a393a7d 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,6 @@ docs/env # rewrite histories *.dat + +# build_clash_dev.sh output +clash-dev.result diff --git a/clash-prelude/src/Clash/Explicit/BlockRam.hs b/clash-prelude/src/Clash/Explicit/BlockRam.hs index 79c3d16410..305b3d4a8f 100644 --- a/clash-prelude/src/Clash/Explicit/BlockRam.hs +++ b/clash-prelude/src/Clash/Explicit/BlockRam.hs @@ -445,7 +445,6 @@ import GHC.Arr import qualified Data.Sequence as Seq import Data.Sequence (Seq) import Data.String.Interpolate(__i) -import Data.Tuple (swap) import GHC.Generics (Generic) import GHC.Stack (HasCallStack, withFrozenCallStack) import GHC.TypeLits (KnownNat, type (^), type (<=)) @@ -458,9 +457,8 @@ import Clash.Explicit.Signal (KnownDomain, Enable, register, fromEnab import Clash.Signal.Internal (Clock(..), Reset, Signal (..), ClockAB (..), invertReset, (.&&.), mux, clockTicks) -import Clash.Promoted.Nat (SNat(..), snatToNum, natToNum) +import Clash.Promoted.Nat (SNat(..), natToNum) import Clash.Signal.Bundle (unbundle, bundle) -import Clash.Signal.Internal.Ambiguous (clockPeriod) import Clash.Sized.Unsigned (Unsigned) import Clash.Sized.Index (Index) import Clash.Sized.Vector (Vec, replicate, iterateI) @@ -1251,49 +1249,6 @@ trueDualPortBlockRamWrapper clkA enA weA addrA datA clkB enB weB addrB datB = trueDualPortBlockRam# clkA enA weA addrA datA clkB enB weB addrB datB {-# NOINLINE trueDualPortBlockRamWrapper #-} --- | Primitive of 'trueDualPortBlockRam'. -trueDualPortBlockRam#, trueDualPortBlockRamWrapper :: - forall nAddrs domA domB a . - ( HasCallStack - , KnownNat nAddrs - , KnownDomain domA - , KnownDomain domB - , NFDataX a - ) - => Clock domA - -- ^ Clock for port A - -> Signal domA Bool - -- ^ Enable for port A - -> Signal domA Bool - -- ^ Write enable for port A - -> Signal domA (Index nAddrs) - -- ^ Address to read from or write to on port A - -> Signal domA a - -- ^ Data in for port A; ignored when /write enable/ is @False@ - - -> Clock domB - -- ^ Clock for port B - -> Signal domB Bool - -- ^ Enable for port B - -> Signal domB Bool - -- ^ Write enable for port B - -> Signal domB (Index nAddrs) - -- ^ Address to read from or write to on port B - -> Signal domB a - -- ^ Data in for port B; ignored when /write enable/ is @False@ - - -> (Signal domA a, Signal domB a) - -- ^ Outputs data on /next/ cycle. If write enable is @True@, the data written - -- will be echoed. If write enable is @False@, the read data is returned. If - -- port enable is @False@, it is /undefined/. -trueDualPortBlockRam# clkA enA weA addrA datA clkB enB weB addrB datB - | snatToNum @Int (clockPeriod @domA) < snatToNum @Int (clockPeriod @domB) - = swap (trueDualPortBlockRamModel labelB clkB enB weB addrB datB labelA clkA enA weA addrA datA) - | otherwise - = trueDualPortBlockRamModel labelA clkA enA weA addrA datA labelB clkB enB weB addrB datB - where - labelA = "Port A" - labelB = "Port B" {-# NOINLINE trueDualPortBlockRam# #-} {-# ANN trueDualPortBlockRam# hasBlackBox #-} {-# ANN trueDualPortBlockRam# ( @@ -1407,8 +1362,8 @@ trueDualPortBlockRam# clkA enA weA addrA datA clkB enB weB addrB datB // Shared memory logic [~SIZE[~TYP[#{datA}]]-1:0] ~GENSYM[mem][#{symMem}] [~LIT[#{knownNatAddrs}]-1:0]; - ~SIGD[~GENSYM[data_slow][#{symDoutA}]][#{datA}]; - ~SIGD[~GENSYM[data_fast][#{symDoutB}]][#{datB}]; + ~SIGD[~GENSYM[a_dout][#{symDoutA}]][#{datA}]; + ~SIGD[~GENSYM[b_dout][#{symDoutB}]][#{datB}]; // Port A always @(~IF~ACTIVEEDGE[Rising][#{knownDomainA}]~THENposedge~ELSEnegedge~FI ~ARG[#{clockA}]) begin @@ -1473,8 +1428,8 @@ trueDualPortBlockRam# clkA enA weA addrA datA clkB enB weB addrB datB // Shared memory reg [~SIZE[~TYP[#{datA}]]-1:0] ~GENSYM[mem][#{symMem}] [~LIT[#{knownNatAddrs}]-1:0]; - reg ~SIGD[~GENSYM[data_slow][#{symDoutA}]][#{datA}]; - reg ~SIGD[~GENSYM[data_fast][#{symDoutB}]][#{datB}]; + reg ~SIGD[~GENSYM[a_dout][#{symDoutA}]][#{datA}]; + reg ~SIGD[~GENSYM[b_dout][#{symDoutB}]][#{datB}]; // Port A always @(~IF~ACTIVEEDGE[Rising][#{knownDomainA}]~THENposedge~ELSEnegedge~FI ~ARG[#{clockA}]) begin @@ -1503,53 +1458,52 @@ trueDualPortBlockRam# clkA enA weA addrA datA clkB enB weB addrB datB // end trueDualPortBlockRam |]) #-} - --- | Haskell model for the primitive 'trueDualPortBlockRam#'. +-- | Haskell model/primitive for 'trueDualPortBlockRam'. -- --- Warning: this model only works if @domFast@'s clock is faster than (or equal --- to) @domSlow@'s clock. -trueDualPortBlockRamModel :: - forall nAddrs domFast domSlow a . +trueDualPortBlockRam#, trueDualPortBlockRamWrapper :: + forall nAddrs domB domA a . ( HasCallStack , KnownNat nAddrs - , KnownDomain domSlow - , KnownDomain domFast + , KnownDomain domA + , KnownDomain domB , NFDataX a ) => - String -> - Clock domSlow -> - Signal domSlow Bool -> - Signal domSlow Bool -> - Signal domSlow (Index nAddrs) -> - Signal domSlow a -> - - String -> - Clock domFast -> - Signal domFast Bool -> - Signal domFast Bool -> - Signal domFast (Index nAddrs) -> - Signal domFast a -> - - (Signal domSlow a, Signal domFast a) -trueDualPortBlockRamModel labelA clkA enA weA addrA datA labelB clkB enB weB addrB datB = + Clock domA -> + -- | Enable + Signal domA Bool -> + -- | Write enable + Signal domA Bool -> + -- | Address + Signal domA (Index nAddrs) -> + -- | Write data + Signal domA a -> + + Clock domB -> + -- | Enable + Signal domB Bool -> + -- | Write enable + Signal domB Bool -> + -- | Address + Signal domB (Index nAddrs) -> + -- | Write data + Signal domB a -> + + (Signal domA a, Signal domB a) +trueDualPortBlockRam# clkA enA weA addrA datA clkB enB weB addrB datB = ( startA :- outA , startB :- outB ) where (outA, outB) = go (Seq.fromFunction (natToNum @nAddrs) initElement) - -- ensure 'go' hits 'goFast' first for 1 cycle, then execute 'goBoth' - -- once, followed by the regular cadence of either 'ceil(tA / tB)' or - -- 'floor(tA / tB)' cycles for the fast clock followed by 1 cycle of the - -- slow clock - (ClockB : clockTicks clkA clkB) + (clockTicks clkA clkB) (bundle (enA, weA, fromIntegral <$> addrA, datA)) (bundle (enB, weB, fromIntegral <$> addrB, datB)) startA startB - startA = deepErrorX $ "trueDualPortBlockRam: " <> labelA <> ": First value undefined" - startB = deepErrorX $ "trueDualPortBlockRam: " <> labelB <> ": First value undefined" + startA = deepErrorX $ "trueDualPortBlockRam: Port A: First value undefined" + startB = deepErrorX $ "trueDualPortBlockRam: Port B: First value undefined" initElement :: Int -> a initElement n = @@ -1620,16 +1574,16 @@ trueDualPortBlockRamModel labelA clkA enA weA addrA datA labelB clkB enB weB add go :: Seq a -> [ClockAB] -> - Signal domSlow (Bool, Bool, Int, a) -> - Signal domFast (Bool, Bool, Int, a) -> + Signal domA (Bool, Bool, Int, a) -> + Signal domB (Bool, Bool, Int, a) -> a -> a -> - (Signal domSlow a, Signal domFast a) + (Signal domA a, Signal domB a) go _ [] _ _ = - error "trueDualPortBlockRamModel.go: `ticks` should have been an infinite list" + error "trueDualPortBlockRamModel#.go: `ticks` should have been an infinite list" go ram0 (tick:ticks) as0 bs0 = case tick of - ClockA -> goSlow - ClockB -> goFast + ClockA -> goA + ClockB -> goB ClockAB -> goBoth where (enA_, weA_, addrA_, datA_) :- as1 = as0 @@ -1669,25 +1623,22 @@ trueDualPortBlockRamModel labelA clkA enA weA addrA datA labelB clkB enB weB add outB2 = if enB_ then outB1 else prevB (as2,bs2) = go ram2 ticks as1 bs1 outA2 outB2 - -- 1 iteration here, as this is the slow clock. - goSlow _ prevB | enA_ = out0 `seqX` (out0 :- as2, bs2) + goA _ prevB | enA_ = out0 `seqX` (out0 :- as2, bs2) where (wrote, !ram1) = writeRam weA_ addrA_ datA_ ram0 out0 = fromMaybe (ram1 `Seq.index` addrA_) wrote (as2, bs2) = go ram1 ticks as1 bs0 out0 prevB - goSlow prevA prevB = (prevA :- as2, bs2) + goA prevA prevB = (prevA :- as2, bs2) where (as2,bs2) = go ram0 ticks as1 bs0 prevA prevB - -- 1 or more iterations here, as this is the fast clock. First iteration - -- happens here. - goFast prevA _ | enB_ = out0 `seqX` (as2, out0 :- bs2) + goB prevA _ | enB_ = out0 `seqX` (as2, out0 :- bs2) where (wrote, !ram1) = writeRam weB_ addrB_ datB_ ram0 out0 = fromMaybe (ram1 `Seq.index` addrB_) wrote (as2, bs2) = go ram1 ticks as0 bs1 prevA out0 - goFast prevA prevB = (as2, prevB :- bs2) + goB prevA prevB = (as2, prevB :- bs2) where (as2,bs2) = go ram0 ticks as0 bs1 prevA prevB diff --git a/clash-prelude/tests/Clash/Tests/AsyncFIFOSynchronizer.hs b/clash-prelude/tests/Clash/Tests/AsyncFIFOSynchronizer.hs index d26bbf26f5..5d5d74d0ca 100644 --- a/clash-prelude/tests/Clash/Tests/AsyncFIFOSynchronizer.hs +++ b/clash-prelude/tests/Clash/Tests/AsyncFIFOSynchronizer.hs @@ -279,7 +279,7 @@ test2R1 = testR sync2R1 , (False,(Nothing,True)) , (False,(Nothing,True)) , (False,(Nothing,True)) - , (False,(Nothing,True)) + , (False,(Just 1,True)) , (False,(Just 1,True)) , (False,(Just 1,False)) , (False,(Just 1,False)) @@ -289,7 +289,7 @@ test2R1 = testR sync2R1 , (True,(Just 3,False)) , (True,(Just 4,False)) , (False,(Nothing,True)) - , (False,(Nothing,True)) + , (False,(Just 5,True)) , (False,(Just 5,True)) , (False,(Just 5,False)) , (False,(Just 5,False)) @@ -364,7 +364,7 @@ test2R2 = testR sync2R2 , (False,(Nothing,True)) , (False,(Nothing,True)) , (False,(Nothing,True)) - , (False,(Nothing,True)) + , (False,(Just 1,True)) , (False,(Just 1,True)) , (False,(Just 1,False)) , (False,(Just 1,False)) @@ -374,7 +374,7 @@ test2R2 = testR sync2R2 , (True,(Just 2,False)) , (True,(Just 3,False)) , (True,(Just 4,False)) - , (False,(Nothing,True)) + , (False,(Just 5,True)) , (False,(Just 5,True)) , (False,(Just 5,False)) , (False,(Just 5,False)) @@ -454,7 +454,7 @@ test2R3 = testR sync2R3 , (False,(Nothing,True)) , (False,(Nothing,True)) , (False,(Nothing,True)) - , (False,(Nothing,True)) + , (False,(Just 1,True)) , (False,(Just 1,True)) , (False,(Just 1,False)) , (False,(Just 1,False)) @@ -464,7 +464,7 @@ test2R3 = testR sync2R3 , (True,(Just 3,False)) , (True,(Just 4,False)) , (False,(Nothing,True)) - , (False,(Nothing,True)) + , (False,(Just 5,True)) , (False,(Just 5,True)) , (False,(Just 5,False)) , (False,(Just 5,False)) @@ -542,7 +542,7 @@ test2R4 = testR sync2R4 , (False,(Nothing,True)) , (False,(Nothing,True)) , (False,(Nothing,True)) - , (False,(Nothing,True)) + , (False,(Just 1,True)) , (False,(Just 1,True)) , (False,(Just 1,False)) , (False,(Just 1,False)) @@ -552,7 +552,7 @@ test2R4 = testR sync2R4 , (True,(Just 2,False)) , (True,(Just 3,False)) , (True,(Just 4,False)) - , (False,(Nothing,True)) + , (False,(Just 5,True)) , (False,(Just 5,True)) , (False,(Just 5,False)) , (False,(Just 5,False)) @@ -643,7 +643,7 @@ test4R5 = testR sync4R5 , (False,(Nothing,True)) , (False,(Nothing,True)) , (False,(Nothing,True)) - , (False,(Nothing,True)) + , (False,(Just 1,True)) , (False,(Just 1,True)) , (False,(Just 1,False)) , (False,(Just 1,False)) @@ -778,7 +778,7 @@ test4R6 = testR sync4R6 , (False,(Nothing,True)) , (False,(Nothing,True)) , (False,(Nothing,True)) - , (False,(Nothing,True)) + , (False,(Just 1,True)) , (False,(Just 1,True)) , (False,(Just 1,False)) , (False,(Just 1,False)) @@ -786,7 +786,7 @@ test4R6 = testR sync4R6 , (True,(Just 2,False)) , (True,(Just 3,False)) , (False,(Nothing,True)) - , (False,(Nothing,True)) + , (False,(Just 4,True)) , (False,(Just 4,True)) , (False,(Just 4,False)) , (False,(Just 4,False)) @@ -911,7 +911,7 @@ test6R7 = testR sync6R7 , (False,(Nothing,True)) , (False,(Nothing,True)) , (False,(Nothing,True)) - , (False,(Nothing,True)) + , (False,(Just 1,True)) , (False,(Just 1,True)) , (True,(Just 1,False)) , (False,(Just 2,True))