diff --git a/.ci/docker/Dockerfile b/.ci/docker/Dockerfile index bf24a1bb1d..5d6aab556a 100644 --- a/.ci/docker/Dockerfile +++ b/.ci/docker/Dockerfile @@ -21,6 +21,7 @@ FROM builder AS build-ghdl ARG DEPS_GHDL="gnat-10 llvm-13-dev" RUN apt-get install -y --no-install-recommends $DEPS_GHDL +# TODO when updating this see if you can enable the Int32 part of tests/shouldwork/Numbers/Bits.hs ARG ghdl_version="2.0.0" RUN curl -L "https://github.com/ghdl/ghdl/archive/v$ghdl_version.tar.gz" \ | tar -xz \ diff --git a/changelog/2024-03-04T17_11_12+01_00_fix_numeric_issues b/changelog/2024-03-04T17_11_12+01_00_fix_numeric_issues new file mode 100644 index 0000000000..fca3d09f06 --- /dev/null +++ b/changelog/2024-03-04T17_11_12+01_00_fix_numeric_issues @@ -0,0 +1 @@ +FIXED: various issues with black boxes and evaluator rules for number-related primitives diff --git a/clash-ghc/src-ghc/Clash/GHC/Evaluator/Primitive.hs b/clash-ghc/src-ghc/Clash/GHC/Evaluator/Primitive.hs index e7dd62ebbc..db8317878f 100644 --- a/clash-ghc/src-ghc/Clash/GHC/Evaluator/Primitive.hs +++ b/clash-ghc/src-ghc/Clash/GHC/Evaluator/Primitive.hs @@ -2,7 +2,7 @@ Copyright : (C) 2013-2016, University of Twente, 2016-2017, Myrtle Software Ltd, 2017-2022, Google Inc., - 2017-2023, QBayLogic B.V. + 2017-2024, QBayLogic B.V. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. -} @@ -486,7 +486,7 @@ ghcPrimStep tcm isSubj pInfo tys args mach = case primName pInfo of -> reduce . integerToWordLiteral . toInteger . popCount . (fromInteger :: Integer -> Word16) $ i "GHC.Prim.popCnt32#" | [i] <- wordLiterals' args -> reduce . integerToWordLiteral . toInteger . popCount . (fromInteger :: Integer -> Word32) $ i - "GHC.Prim.popCnt64#" | [i] <- wordLiterals' args + "GHC.Prim.popCnt64#" | [i] <- word64Literals' args -> reduce . integerToWordLiteral . toInteger . popCount . (fromInteger :: Integer -> Word64) $ i "GHC.Prim.popCnt#" | [i] <- wordLiterals' args -> reduce . integerToWordLiteral . toInteger . popCount . (fromInteger :: Integer -> Word) $ i @@ -497,7 +497,7 @@ ghcPrimStep tcm isSubj pInfo tys args mach = case primName pInfo of -> reduce . integerToWordLiteral . toInteger . countLeadingZeros . (fromInteger :: Integer -> Word16) $ i "GHC.Prim.clz32#" | [i] <- wordLiterals' args -> reduce . integerToWordLiteral . toInteger . countLeadingZeros . (fromInteger :: Integer -> Word32) $ i - "GHC.Prim.clz64#" | [i] <- wordLiterals' args + "GHC.Prim.clz64#" | [i] <- word64Literals' args -> reduce . integerToWordLiteral . toInteger . countLeadingZeros . (fromInteger :: Integer -> Word64) $ i "GHC.Prim.clz#" | [i] <- wordLiterals' args -> reduce . integerToWordLiteral . toInteger . countLeadingZeros . (fromInteger :: Integer -> Word) $ i @@ -508,7 +508,7 @@ ghcPrimStep tcm isSubj pInfo tys args mach = case primName pInfo of -> reduce . integerToWordLiteral . toInteger . countTrailingZeros . (fromInteger :: Integer -> Word) $ i .&. (bit 16 - 1) "GHC.Prim.ctz32#" | [i] <- wordLiterals' args -> reduce . integerToWordLiteral . toInteger . countTrailingZeros . (fromInteger :: Integer -> Word) $ i .&. (bit 32 - 1) - "GHC.Prim.ctz64#" | [i] <- wordLiterals' args + "GHC.Prim.ctz64#" | [i] <- word64Literals' args -> reduce . integerToWordLiteral . toInteger . countTrailingZeros . (fromInteger :: Integer -> Word64) $ i .&. (bit 64 - 1) "GHC.Prim.ctz#" | [i] <- wordLiterals' args -> reduce . integerToWordLiteral . toInteger . countTrailingZeros . (fromInteger :: Integer -> Word) $ i @@ -517,7 +517,7 @@ ghcPrimStep tcm isSubj pInfo tys args mach = case primName pInfo of -> reduce . integerToWordLiteral . toInteger . byteSwap16 . (fromInteger :: Integer -> Word16) $ i "GHC.Prim.byteSwap32#" | [i] <- wordLiterals' args -> reduce . integerToWordLiteral . toInteger . byteSwap32 . (fromInteger :: Integer -> Word32) $ i - "GHC.Prim.byteSwap64#" | [i] <- wordLiterals' args + "GHC.Prim.byteSwap64#" | [i] <- word64Literals' args -> reduce . integerToWordLiteral . toInteger . byteSwap64 . (fromInteger :: Integer -> Word64) $ i "GHC.Prim.byteSwap#" | [i] <- wordLiterals' args -- assume 64bits -> reduce . integerToWordLiteral . toInteger . byteSwap64 . (fromInteger :: Integer -> Word64) $ i @@ -531,7 +531,7 @@ ghcPrimStep tcm isSubj pInfo tys args mach = case primName pInfo of -> reduce . integerToWordLiteral . toInteger . bitReverse16 . fromInteger $ i "GHC.Prim.bitReverse32#" | [i] <- wordLiterals' args -> reduce . integerToWordLiteral . toInteger . bitReverse32 . fromInteger $ i - "GHC.Prim.bitReverse64#" | [i] <- wordLiterals' args + "GHC.Prim.bitReverse64#" | [i] <- word64Literals' args -> reduce . integerToWordLiteral . toInteger . bitReverse64 . fromInteger $ i #endif ------------ @@ -1861,6 +1861,8 @@ ghcPrimStep tcm isSubj pInfo tys args mach = case primName pInfo of | [Lit l] <- args -> error ("IP: " <> show l) "GHC.Num.Integer.IN" + | [Lit (ByteArrayLiteral (BA.ByteArray ba))] <- args + -> reduce (Literal (IntegerLiteral (IN ba))) | [Lit l] <- args -> error ("IN: " <> show l) #else @@ -4864,16 +4866,20 @@ word32Literal :: Value -> Maybe Integer word32Literal x = case x of Lit (Word32Literal i) -> Just i _ -> Nothing +#endif -#if MIN_VERSION_base(4,17,0) word64Literals' :: [Value] -> [Integer] word64Literals' = listOf word64Literal +#if MIN_VERSION_base(4,17,0) word64Literal :: Value -> Maybe Integer word64Literal x = case x of Lit (Word64Literal i) -> Just i _ -> Nothing -#endif +#else +-- Prior to GHC 9.4 Word64# didn't exist, 64 bit primitives took Word# instead +word64Literal :: Value -> Maybe Integer +word64Literal= wordLiteral #endif charLiterals :: [Value] -> Maybe (Char,Char) diff --git a/clash-ghc/src-ghc/Clash/GHC/GHC2Core.hs b/clash-ghc/src-ghc/Clash/GHC/GHC2Core.hs index 1ccad9fadc..95ac337c6b 100644 --- a/clash-ghc/src-ghc/Clash/GHC/GHC2Core.hs +++ b/clash-ghc/src-ghc/Clash/GHC/GHC2Core.hs @@ -2,7 +2,7 @@ Copyright : (C) 2013-2016, University of Twente, 2016-2017, Myrtle Software Ltd, 2017-2022, Google Inc. - 2021, QBayLogic B.V., + 2021,2023 QBayLogic B.V., License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. -} @@ -676,9 +676,9 @@ coreToTerm primMap unlocs = term LitNumNatural -> C.NaturalLiteral i #endif LitNumInt -> C.IntLiteral i - LitNumInt64 -> C.IntLiteral i + LitNumInt64 -> C.Int64Literal i LitNumWord -> C.WordLiteral i - LitNumWord64 -> C.WordLiteral i + LitNumWord64 -> C.Word64Literal i #if MIN_VERSION_ghc(9,2,0) LitNumInt8 -> C.Int8Literal i LitNumInt16 -> C.Int16Literal i diff --git a/clash-lib/prims/commonverilog/Clash_Sized_Internal_Signed.primitives.yaml b/clash-lib/prims/commonverilog/Clash_Sized_Internal_Signed.primitives.yaml index 6bd5fcd425..96509bb02e 100644 --- a/clash-lib/prims/commonverilog/Clash_Sized_Internal_Signed.primitives.yaml +++ b/clash-lib/prims/commonverilog/Clash_Sized_Internal_Signed.primitives.yaml @@ -106,8 +106,11 @@ kind: Expression type: 'fromInteger# :: KnownNat n => Integer -> Signed (n :: Nat)' - template: ~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]]~THEN$signed(~VAR[i][1][0+:~SIZE[~TYPO]])~ELSE$signed({{(~SIZE[~TYPO]-~SIZE[~TYP[1]]) - {1'b0}},~VAR[i][1]})~FI + template: >- + ~IF~CMPLE[~SIZE[~TYPO]][~SIZE[~TYP[1]]] + ~THEN$signed(~VAR[i][1][0+:~SIZE[~TYPO]]) + ~ELSE$signed({{(~SIZE[~TYPO]-~SIZE[~TYP[1]]){~VAR[i][1][~SIZE[~TYP[1]]-1]}},~VAR[i][1]}) + ~FI workInfo: Never - BlackBox: name: Clash.Sized.Internal.Signed.toEnum# diff --git a/clash-lib/prims/commonverilog/GHC_Num_Integer.primitives.yaml b/clash-lib/prims/commonverilog/GHC_Num_Integer.primitives.yaml index 20c5848e36..51b0824726 100644 --- a/clash-lib/prims/commonverilog/GHC_Num_Integer.primitives.yaml +++ b/clash-lib/prims/commonverilog/GHC_Num_Integer.primitives.yaml @@ -150,8 +150,8 @@ name: GHC.Num.Integer.integerTestBit# kind: Expression type: 'integerTestBit - :: Integer -> Word# -> Bool' - template: ~VAR[input][0][~ARG[1]] == 1'b1 + :: Integer -> Word# -> Int#' + template: "((~VAR[input][0][~ARG[1]] == 1'b1) ? ~SIZE[~TYPO]'sd1 : ~SIZE[~TYPO]'sd0)" warning: 'GHC.Num.Integer.integerTestBit#: Integers are dynamically sized in simulation, but fixed-length after synthesis. Use carefully.' - BlackBox: diff --git a/clash-lib/prims/systemverilog/GHC_Prim.primitives.yaml b/clash-lib/prims/systemverilog/GHC_Prim.primitives.yaml index daf424b96f..8b67e72326 100644 --- a/clash-lib/prims/systemverilog/GHC_Prim.primitives.yaml +++ b/clash-lib/prims/systemverilog/GHC_Prim.primitives.yaml @@ -871,7 +871,7 @@ genvar ~GENSYM[k][18]; ~GENERATE for (~SYM[18]=0;~SYM[18]<8;~SYM[18]=~SYM[18]+1) begin : ~GENSYM[reverse][19] - assign ~SYM[1][~SYM[18]] = ~ARG[0][~SYM[18]]; + assign ~SYM[1][~SYM[18]] = ~VAR[][0][~SYM[18]]; end ~ENDGENERATE @@ -942,7 +942,7 @@ genvar ~GENSYM[k][18]; ~GENERATE for (~SYM[18]=0;~SYM[18]<16;~SYM[18]=~SYM[18]+1) begin : ~GENSYM[reverse][19] - assign ~SYM[1][~SYM[18]] = ~ARG[0][~SYM[18]]; + assign ~SYM[1][~SYM[18]] = ~VAR[][0][~SYM[18]]; end ~ENDGENERATE @@ -1029,7 +1029,7 @@ genvar ~GENSYM[k][18]; ~GENERATE for (~SYM[18]=0;~SYM[18]<32;~SYM[18]=~SYM[18]+1) begin : ~GENSYM[reverse][19] - assign ~SYM[1][~SYM[18]] = ~ARG[0][~SYM[18]]; + assign ~SYM[1][~SYM[18]] = ~VAR[][0][~SYM[18]]; end ~ENDGENERATE @@ -1132,7 +1132,7 @@ genvar ~GENSYM[k][18]; ~GENERATE for (~SYM[18]=0;~SYM[18]<64;~SYM[18]=~SYM[18]+1) begin : ~GENSYM[reverse][19] - assign ~SYM[1][~SYM[18]] = ~ARG[0][~SYM[18]]; + assign ~SYM[1][~SYM[18]] = ~VAR[][0][~SYM[18]]; end ~ENDGENERATE @@ -1144,7 +1144,7 @@ end ~ENDGENERATE - logic [0:47] a; + logic [0:47] ~GENSYM[a][4]; genvar ~GENSYM[i1][5]; ~GENERATE for (~SYM[5]=0;~SYM[5]<16;~SYM[5]=~SYM[5]+1) begin : ~GENSYM[mux_stage][6] @@ -1252,7 +1252,7 @@ genvar ~GENSYM[k][18]; ~GENERATE for (~SYM[18]=0;~SYM[18]<64;~SYM[18]=~SYM[18]+1) begin : ~GENSYM[reverse][19] - assign ~SYM[1][~SYM[18]] = ~ARG[0][~SYM[18]]; + assign ~SYM[1][~SYM[18]] = ~VAR[][0][~SYM[18]]; end ~ENDGENERATE @@ -1347,7 +1347,7 @@ genvar ~SYM[18]; ~GENERATE for (~SYM[18]=0;~SYM[18]<32;~SYM[18]=~SYM[18]+1) begin : ~SYM[19] - assign ~SYM[1][~SYM[18]] = ~ARG[0][~SYM[18]]; + assign ~SYM[1][~SYM[18]] = ~VAR[][0][~SYM[18]]; end ~ENDGENERATE diff --git a/clash-lib/prims/verilog/GHC_Prim.primitives.yaml b/clash-lib/prims/verilog/GHC_Prim.primitives.yaml index 110fd0c7b7..e174e1454a 100644 --- a/clash-lib/prims/verilog/GHC_Prim.primitives.yaml +++ b/clash-lib/prims/verilog/GHC_Prim.primitives.yaml @@ -920,7 +920,7 @@ genvar ~GENSYM[k][18]; ~GENERATE for (~SYM[18]=0;~SYM[18]<8;~SYM[18]=~SYM[18]+1) begin : ~GENSYM[reverse][19] - assign ~SYM[1][~SYM[18]] = ~ARG[0][~SYM[18]]; + assign ~SYM[1][~SYM[18]] = ~VAR[][0][~SYM[18]]; end ~ENDGENERATE @@ -991,7 +991,7 @@ genvar ~GENSYM[k][18]; ~GENERATE for (~SYM[18]=0;~SYM[18]<16;~SYM[18]=~SYM[18]+1) begin : ~GENSYM[reverse][19] - assign ~SYM[1][~SYM[18]] = ~ARG[0][~SYM[18]]; + assign ~SYM[1][~SYM[18]] = ~VAR[][0][~SYM[18]]; end ~ENDGENERATE @@ -1078,7 +1078,7 @@ genvar ~GENSYM[k][18]; ~GENERATE for (~SYM[18]=0;~SYM[18]<32;~SYM[18]=~SYM[18]+1) begin : ~GENSYM[reverse][19] - assign ~SYM[1][~SYM[18]] = ~ARG[0][~SYM[18]]; + assign ~SYM[1][~SYM[18]] = ~VAR[][0][~SYM[18]]; end ~ENDGENERATE @@ -1181,7 +1181,7 @@ genvar ~GENSYM[k][18]; ~GENERATE for (~SYM[18]=0;~SYM[18]<64;~SYM[18]=~SYM[18]+1) begin : ~GENSYM[reverse][19] - assign ~SYM[1][~SYM[18]] = ~ARG[0][~SYM[18]]; + assign ~SYM[1][~SYM[18]] = ~VAR[][0][~SYM[18]]; end ~ENDGENERATE @@ -1193,7 +1193,7 @@ end ~ENDGENERATE - reg [0:47] a; + reg [0:47] ~GENSYM[a][4]; genvar ~GENSYM[i1][5]; ~GENERATE for (~SYM[5]=0;~SYM[5]<16;~SYM[5]=~SYM[5]+1) begin : ~GENSYM[mux_stage][6] @@ -1300,7 +1300,7 @@ genvar ~GENSYM[k][18]; ~GENERATE for (~SYM[18]=0;~SYM[18]<64;~SYM[18]=~SYM[18]+1) begin : ~GENSYM[reverse][19] - assign ~SYM[1][~SYM[18]] = ~ARG[0][~SYM[18]]; + assign ~SYM[1][~SYM[18]] = ~VAR[][0][~SYM[18]]; end ~ENDGENERATE @@ -1395,7 +1395,7 @@ genvar ~SYM[18]; ~GENERATE for (~SYM[18]=0;~SYM[18]<32;~SYM[18]=~SYM[18]+1) begin : ~SYM[19] - assign ~SYM[1][~SYM[18]] = ~ARG[0][~SYM[18]]; + assign ~SYM[1][~SYM[18]] = ~VAR[][0][~SYM[18]]; end ~ENDGENERATE diff --git a/clash-lib/prims/vhdl/Clash_Sized_Internal_Signed.primitives.yaml b/clash-lib/prims/vhdl/Clash_Sized_Internal_Signed.primitives.yaml index a53754fe21..22ff12d42a 100644 --- a/clash-lib/prims/vhdl/Clash_Sized_Internal_Signed.primitives.yaml +++ b/clash-lib/prims/vhdl/Clash_Sized_Internal_Signed.primitives.yaml @@ -75,10 +75,16 @@ workInfo: Constant - BlackBox: name: Clash.Sized.Internal.Signed.*# - kind: Expression + kind: Declaration type: '(*#) :: KnownNat n => Signed n -> Signed n -> Signed n' - template: resize(~ARG[1] * ~ARG[2], ~LIT[0]) + template: |- + ~GENSYM[~RESULT_mult][0] : block + signal ~GENSYM[~RESULT_mult_full][1] : signed(~SIZE[~TYPO]*2-1 downto 0); + begin + ~SYM[1] <= ~ARG[1] * ~ARG[2]; + ~RESULT <= ~SYM[1](~SIZE[~TYPO]-1 downto 0); + end block; - BlackBox: name: Clash.Sized.Internal.Signed.negate# kind: Expression diff --git a/clash-lib/prims/vhdl/GHC_Int.primitives.yaml b/clash-lib/prims/vhdl/GHC_Int.primitives.yaml index 6dca820ce2..51242fc0b4 100644 --- a/clash-lib/prims/vhdl/GHC_Int.primitives.yaml +++ b/clash-lib/prims/vhdl/GHC_Int.primitives.yaml @@ -4,6 +4,7 @@ type: 'I8# :: Int# -> Int8' template: resize(~ARG[0],8) + # TODO Starting with ghc-9.0/base-4.16 this takes an I8# that is already properly sized and don't have to do this resize anymore. Same applies to the rest of this file. workInfo: Never - BlackBox: name: GHC.Int.I16# diff --git a/clash-lib/prims/vhdl/GHC_Integer_Type.primitives.yaml b/clash-lib/prims/vhdl/GHC_Integer_Type.primitives.yaml index 249241cc2d..d81e2efb2d 100644 --- a/clash-lib/prims/vhdl/GHC_Integer_Type.primitives.yaml +++ b/clash-lib/prims/vhdl/GHC_Integer_Type.primitives.yaml @@ -18,10 +18,16 @@ workInfo: Never - BlackBox: name: GHC.Integer.Type.timesInteger - kind: Expression + kind: Declaration type: 'timesInteger :: Integer -> Integer -> Integer' - template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO]) + template: |- + ~GENSYM[~RESULT_mult][0] : block + signal ~GENSYM[~RESULT_mult_full][1] : signed(~SIZE[~TYPO]*2-1 downto 0); + begin + ~SYM[1] <= ~ARG[0] * ~ARG[1]; + ~RESULT <= ~SYM[1](~SIZE[~TYPO]-1 downto 0); + end block; warning: 'GHC.Integer.Type.timesInteger: Integers are dynamically sized in simulation, but fixed-length after synthesis. Use carefully.' - BlackBox: diff --git a/clash-lib/prims/vhdl/GHC_Num_Integer.primitives.yaml b/clash-lib/prims/vhdl/GHC_Num_Integer.primitives.yaml index e855d90004..27d0223349 100644 --- a/clash-lib/prims/vhdl/GHC_Num_Integer.primitives.yaml +++ b/clash-lib/prims/vhdl/GHC_Num_Integer.primitives.yaml @@ -44,10 +44,16 @@ workInfo: Never - BlackBox: name: GHC.Num.Integer.integerMul - kind: Expression + kind: Declaration type: 'integerMul :: Integer -> Integer -> Integer' - template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO]) + template: |- + ~GENSYM[~RESULT_mult][0] : block + signal ~GENSYM[~RESULT_mult_full][1] : signed(~SIZE[~TYPO]*2-1 downto 0); + begin + ~SYM[1] <= ~ARG[0] * ~ARG[1]; + ~RESULT <= ~SYM[1](~SIZE[~TYPO]-1 downto 0); + end block; warning: 'GHC.Num.Integer.integerMul: Integers are dynamically sized in simulation, but fixed-length after synthesis. Use carefully.' - BlackBox: @@ -266,10 +272,10 @@ but fixed-length after synthesis. Use carefully.' - BlackBox: name: GHC.Num.Integer.integerTestBit# - kind: Expression + kind: Declaration type: 'integerTestBit - :: Integer -> Word# -> Bool' - template: ~VAR[input][0](to_integer(~ARG[1])) = '1' + :: Integer -> Word# -> Int#' + template: ~RESULT <= (0 => ~VAR[input][0](to_integer(~ARG[1])), others => '0'); warning: 'GHC.Num.Integer.integerTestBit#: Integers are dynamically sized in simulation, but fixed-length after synthesis. Use carefully.' - BlackBox: diff --git a/clash-lib/prims/vhdl/GHC_Prim.primitives.yaml b/clash-lib/prims/vhdl/GHC_Prim.primitives.yaml index a28feec028..041d149ba8 100644 --- a/clash-lib/prims/vhdl/GHC_Prim.primitives.yaml +++ b/clash-lib/prims/vhdl/GHC_Prim.primitives.yaml @@ -42,10 +42,16 @@ template: signed(std_logic_vector(resize(~ARG[0],~SIZE[~TYPO]))) - BlackBox: name: GHC.Prim.*# - kind: Expression + kind: Declaration type: '(*#) :: Int# -> Int# -> Int#' - template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO]) + template: |- + ~GENSYM[~RESULT_mult][0] : block + signal ~GENSYM[~RESULT_mult_full][1] : signed(~SIZE[~TYPO]*2-1 downto 0); + begin + ~SYM[1] <= ~ARG[0] * ~ARG[1]; + ~RESULT <= ~SYM[1](~SIZE[~TYPO]-1 downto 0); + end block; - BlackBox: name: GHC.Prim.remInt# kind: Declaration @@ -584,7 +590,7 @@ return ~SYM[2](3,a(0 to 5)); end function; begin - ~RESULT <= resize(~SYM[3](~ARG[0](7 downto 0)),~SIZE[~TYPO]); + ~RESULT <= resize(~SYM[3](~VAR[][0](7 downto 0)),~SIZE[~TYPO]); end block; -- clz8 end - BlackBox: @@ -628,7 +634,7 @@ return ~SYM[2](4,b(0 to 7)); end function; begin - ~RESULT <= resize(~SYM[3](~ARG[0](15 downto 0)),~SIZE[~TYPO]); + ~RESULT <= resize(~SYM[3](~VAR[][0](15 downto 0)),~SIZE[~TYPO]); end block; -- clz16 end - BlackBox: @@ -674,7 +680,7 @@ return ~SYM[2](5,c(0 to 9)); end function; begin - ~RESULT <= resize(~SYM[3](~ARG[0](31 downto 0)),~SIZE[~TYPO]); + ~RESULT <= resize(~SYM[3](~VAR[][0](31 downto 0)),~SIZE[~TYPO]); end block; -- clz32 end - BlackBox: @@ -941,7 +947,7 @@ signal ~GENSYM[w_reversed][5] : ~TYP[0]; begin ~GENSYM[reverse_loop][6] : for ~GENSYM[n][7] in ~VAR[w][0]'range generate - ~SYM[5](~VAR[w][0]'high - ~SYM[7]) <= ~VAR[w][0](~SYM[3]); + ~SYM[5](~VAR[w][0]'high - ~SYM[7]) <= ~VAR[w][0](~SYM[7]); end generate; ~IF ~IW64 ~THEN ~RESULT <= resize(~SYM[3](~SYM[5](63 downto 32)),~SIZE[~TYPO]); @@ -1273,8 +1279,14 @@ template: -~ARG[0] - BlackBox: name: GHC.Prim.timesInt8# - kind: Expression - template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO]) + kind: Declaration + template: |- + ~GENSYM[~RESULT_mult][0] : block + signal ~GENSYM[~RESULT_mult_full][1] : signed(~SIZE[~TYPO]*2-1 downto 0); + begin + ~SYM[1] <= ~ARG[0] * ~ARG[1]; + ~RESULT <= ~SYM[1](~SIZE[~TYPO]-1 downto 0); + end block; - BlackBox: name: GHC.Prim.quotInt8# kind: Declaration @@ -1523,8 +1535,14 @@ template: -~ARG[0] - BlackBox: name: GHC.Prim.timesInt16# - kind: Expression - template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO]) + kind: Declaration + template: |- + ~GENSYM[~RESULT_mult][0] : block + signal ~GENSYM[~RESULT_mult_full][1] : signed(~SIZE[~TYPO]*2-1 downto 0); + begin + ~SYM[1] <= ~ARG[0] * ~ARG[1]; + ~RESULT <= ~SYM[1](~SIZE[~TYPO]-1 downto 0); + end block; - BlackBox: name: GHC.Prim.quotInt16# kind: Declaration @@ -1773,8 +1791,14 @@ template: -~ARG[0] - BlackBox: name: GHC.Prim.timesInt32# - kind: Expression - template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO]) + kind: Declaration + template: |- + ~GENSYM[~RESULT_mult][0] : block + signal ~GENSYM[~RESULT_mult_full][1] : signed(~SIZE[~TYPO]*2-1 downto 0); + begin + ~SYM[1] <= ~ARG[0] * ~ARG[1]; + ~RESULT <= ~SYM[1](~SIZE[~TYPO]-1 downto 0); + end block; - BlackBox: name: GHC.Prim.quotInt32# kind: Declaration @@ -2023,8 +2047,14 @@ template: -~ARG[0] - BlackBox: name: GHC.Prim.timesInt64# - kind: Expression - template: resize(~ARG[0] * ~ARG[1],~SIZE[~TYPO]) + kind: Declaration + template: |- + ~GENSYM[~RESULT_mult][0] : block + signal ~GENSYM[~RESULT_mult_full][1] : signed(~SIZE[~TYPO]*2-1 downto 0); + begin + ~SYM[1] <= ~ARG[0] * ~ARG[1]; + ~RESULT <= ~SYM[1](~SIZE[~TYPO]-1 downto 0); + end block; - BlackBox: name: GHC.Prim.quotInt64# kind: Declaration diff --git a/clash-lib/src/Clash/Backend/VHDL.hs b/clash-lib/src/Clash/Backend/VHDL.hs index e91e896a75..4db0460b96 100644 --- a/clash-lib/src/Clash/Backend/VHDL.hs +++ b/clash-lib/src/Clash/Backend/VHDL.hs @@ -1,7 +1,7 @@ {-| Copyright : (C) 2015-2016, University of Twente, 2017-2018, Google Inc., - 2021-2023, QBayLogic B.V. + 2021-2024, QBayLogic B.V. 2022 , Google Inc. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. @@ -1863,7 +1863,7 @@ exprLit Nothing (NumLit i) = integer i exprLit (Just (hty,sz)) (NumLit i) = case hty of Unsigned n - | i < (-2^(31 :: Integer)) -> "unsigned" <> parens ("std_logic_vector" <> parens ("signed'" <> parens lit)) + | i <= (-2^(31 :: Integer))-> "unsigned" <> parens ("std_logic_vector" <> parens ("signed'" <> parens lit)) | i < 0 -> "unsigned" <> parens ("std_logic_vector" <> parens ("to_signed" <> parens(integer i <> "," <> int n))) | i < 2^(31 :: Integer) -> "to_unsigned" <> parens (integer i <> "," <> int n) | otherwise -> "unsigned'" <> parens lit diff --git a/clash-lib/src/Clash/Backend/Verilog.hs b/clash-lib/src/Clash/Backend/Verilog.hs index 1bce28c5a4..f88a3517bb 100644 --- a/clash-lib/src/Clash/Backend/Verilog.hs +++ b/clash-lib/src/Clash/Backend/Verilog.hs @@ -1,7 +1,7 @@ {-| Copyright : (C) 2015-2016, University of Twente, 2017-2018, Google Inc., - 2021-2023, QBayLogic B.V. + 2021-2024, QBayLogic B.V. 2022 , Google Inc. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. @@ -1216,7 +1216,7 @@ exprLitV = exprLit undefValue exprLit :: Lens' s (Maybe (Maybe Int)) -> Maybe (HWType,Size) -> Literal -> Ap (State s) Doc exprLit _ Nothing (NumLit i) = integer i -exprLit k (Just (hty,sz)) (NumLit i) = case hty of +exprLit k (Just (hty,sz)) (NumLit i0) = case hty of Unsigned _ | i < 0 -> string "-" <> int sz <> string "'d" <> integer (abs i) | otherwise -> int sz <> string "'d" <> integer i @@ -1227,6 +1227,11 @@ exprLit k (Just (hty,sz)) (NumLit i) = case hty of _ -> int sz <> string "'b" <> blit where blit = bits k (toBits sz i) + i = case hty of + Signed _ -> let mask = 2^(sz-1) in case divMod i0 mask of + (s,i'') | even s -> i'' + | otherwise -> i'' - mask + _ -> i0 `mod` 2^sz exprLit k (Just (_,sz)) (BitVecLit m i) = int sz <> string "'b" <> bvlit where bvlit = bits k (toBits' sz m i) diff --git a/clash-lib/src/Clash/Netlist.hs b/clash-lib/src/Clash/Netlist.hs index 88f16d9e18..fd241d9197 100644 --- a/clash-lib/src/Clash/Netlist.hs +++ b/clash-lib/src/Clash/Netlist.hs @@ -2,7 +2,7 @@ Copyright : (C) 2012-2016, University of Twente, 2016-2017, Myrtle Software Ltd, 2017-2018, Google Inc., - 2021-2022, QBayLogic B.V. + 2021-2024, QBayLogic B.V. 2022 , Google Inc. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. @@ -41,14 +41,8 @@ import Data.Maybe (listToMaybe, fromMaybe) import qualified Data.Map.Ordered as OMap import qualified Data.Set as Set -import Data.Primitive.ByteArray (ByteArray (..)) import qualified Data.Text as StrictText import GHC.Stack (HasCallStack) -#if MIN_VERSION_base(4,15,0) -import GHC.Num.Integer (Integer (..)) -#else -import GHC.Integer.GMP.Internals (Integer (..), BigNat (..)) -#endif #if MIN_VERSION_ghc(9,0,0) import GHC.Utils.Outputable (ppr, showSDocUnsafe) @@ -825,28 +819,7 @@ mkExpr :: HasCallStack -> NetlistMonad (Expr,[Declaration]) -- ^ Returned expression and a list of generate BlackBox declarations mkExpr _ _ _ (stripTicks -> Core.Literal l) = do iw <- Lens.view intWidth - case l of - IntegerLiteral i -> return (HW.Literal (Just (Signed iw,iw)) $ NumLit i, []) - IntLiteral i -> return (HW.Literal (Just (Signed iw,iw)) $ NumLit i, []) - WordLiteral w -> return (HW.Literal (Just (Unsigned iw,iw)) $ NumLit w, []) - Int64Literal i -> return (HW.Literal (Just (Signed 64,64)) $ NumLit i, []) - Word64Literal w -> return (HW.Literal (Just (Unsigned 64,64)) $ NumLit w, []) - Int8Literal i -> return (HW.Literal (Just (Signed 8,8)) $ NumLit i, []) - Int16Literal i -> return (HW.Literal (Just (Signed 16,16)) $ NumLit i, []) - Int32Literal i -> return (HW.Literal (Just (Signed 32,32)) $ NumLit i, []) - Word8Literal w -> return (HW.Literal (Just (Unsigned 8,8)) $ NumLit w, []) - Word16Literal w -> return (HW.Literal (Just (Unsigned 16,16)) $ NumLit w, []) - Word32Literal w -> return (HW.Literal (Just (Unsigned 32,32)) $ NumLit w, []) - CharLiteral c -> return (HW.Literal (Just (Unsigned 21,21)) . NumLit . toInteger $ ord c, []) - FloatLiteral w -> return (HW.Literal (Just (BitVector 32,32)) (NumLit $ toInteger w), []) - DoubleLiteral w -> return (HW.Literal (Just (BitVector 64,64)) (NumLit $ toInteger w), []) - NaturalLiteral n -> return (HW.Literal (Just (Unsigned iw,iw)) $ NumLit n, []) -#if MIN_VERSION_base(4,15,0) - ByteArrayLiteral (ByteArray ba) -> return (HW.Literal Nothing (NumLit (IP ba)),[]) -#else - ByteArrayLiteral (ByteArray ba) -> return (HW.Literal Nothing (NumLit (Jp# (BN# ba))),[]) -#endif - StringLiteral s -> return (HW.Literal Nothing $ StringLit s, []) + return (mkLiteral iw l, []) mkExpr bbEasD declType bndr app = let (appF,args,ticks) = collectArgsTicks app diff --git a/clash-lib/src/Clash/Netlist/BlackBox.hs b/clash-lib/src/Clash/Netlist/BlackBox.hs index 077f8071e1..1423cf65ac 100644 --- a/clash-lib/src/Clash/Netlist/BlackBox.hs +++ b/clash-lib/src/Clash/Netlist/BlackBox.hs @@ -3,7 +3,7 @@ Copyright : (C) 2012-2016, University of Twente, 2016-2017, Myrtle Software Ltd, 2017 , Google Inc., - 2021-2023, QBayLogic B.V. + 2021-2024, QBayLogic B.V. 2022 , Google Inc. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. @@ -29,7 +29,6 @@ import Control.Monad (when, replicateM, zipWithM) import Control.Monad.Extra (concatMapM) import Control.Monad.IO.Class (liftIO) import Data.Bifunctor (first, second) -import Data.Char (ord) import Data.Either (lefts, partitionEithers) import Data.Foldable (for_) import qualified Data.HashMap.Lazy as HashMap @@ -68,7 +67,7 @@ import Clash.Annotations.Primitive import Clash.Core.DataCon as D (dcTag) import Clash.Core.FreeVars (freeIds) import Clash.Core.HasType -import Clash.Core.Literal as L (Literal (..)) +import Clash.Core.Literal as C (Literal (..)) import Clash.Core.Name (Name (..), mkUnsafeSystemName) import qualified Clash.Netlist.Id as Id @@ -263,6 +262,7 @@ isLiteral e = case collectArgs e of (C.Literal _,_) -> True _ -> False + mkArgument :: TextS.Text -- ^ Blackbox function name @@ -291,36 +291,9 @@ mkArgument bbName bndr nArg e = do Just hwTy -> case collectArgsTicks e of (C.Var v,[],_) -> do return ((Identifier (Id.unsafeFromCoreId v) Nothing,hwTy,False),[]) - (C.Literal (IntegerLiteral i),[],_) -> - return ((N.Literal (Just (Signed iw,iw)) (N.NumLit i),hwTy,True),[]) - (C.Literal (IntLiteral i), [],_) -> - return ((N.Literal (Just (Signed iw,iw)) (N.NumLit i),hwTy,True),[]) - (C.Literal (WordLiteral w), [],_) -> - return ((N.Literal (Just (Unsigned iw,iw)) (N.NumLit w),hwTy,True),[]) - (C.Literal (CharLiteral c), [],_) -> - return ((N.Literal (Just (Unsigned 21,21)) (N.NumLit . toInteger $ ord c),hwTy,True),[]) - (C.Literal (StringLiteral s),[],_) -> - return ((N.Literal Nothing (N.StringLit s),hwTy,True),[]) - (C.Literal (Int64Literal i), [],_) -> - return ((N.Literal (Just (Signed 64,64)) (N.NumLit i),hwTy,True),[]) - (C.Literal (Word64Literal i), [],_) -> - return ((N.Literal (Just (Unsigned 64,64)) (N.NumLit i),hwTy,True),[]) -#if MIN_VERSION_base(4,16,0) - (C.Literal (Int8Literal i), [],_) -> - return ((N.Literal (Just (Signed 8,8)) (N.NumLit i),hwTy,True),[]) - (C.Literal (Int16Literal i), [],_) -> - return ((N.Literal (Just (Signed 16,16)) (N.NumLit i),hwTy,True),[]) - (C.Literal (Int32Literal i), [],_) -> - return ((N.Literal (Just (Signed 16,16)) (N.NumLit i),hwTy,True),[]) - (C.Literal (Word8Literal i), [],_) -> - return ((N.Literal (Just (Unsigned 8,8)) (N.NumLit i),hwTy,True),[]) - (C.Literal (Word16Literal i), [],_) -> - return ((N.Literal (Just (Unsigned 16,16)) (N.NumLit i),hwTy,True),[]) - (C.Literal (Word32Literal i), [],_) -> - return ((N.Literal (Just (Unsigned 32,32)) (N.NumLit i),hwTy,True),[]) -#endif - (C.Literal (NaturalLiteral n), [],_) -> - return ((N.Literal (Just (Unsigned iw,iw)) (N.NumLit n),hwTy,True),[]) + (C.Literal l,[],_) -> + return ((mkLiteral iw l,hwTy,True),[]) + (Prim pinfo,args,ticks) -> withTicks ticks $ \tickDecls -> do (e',d) <- mkPrimitive True False Concurrent (NetlistId bndr ty) pinfo args tickDecls case e' of diff --git a/clash-lib/src/Clash/Netlist/Util.hs b/clash-lib/src/Clash/Netlist/Util.hs index 20e069877c..a5c2031b0c 100644 --- a/clash-lib/src/Clash/Netlist/Util.hs +++ b/clash-lib/src/Clash/Netlist/Util.hs @@ -2,7 +2,7 @@ Copyright : (C) 2012-2016, University of Twente, 2017 , Myrtle Software Ltd 2017-2018, Google Inc. - 2021-2023, QBayLogic B.V. + 2021-2024, QBayLogic B.V. 2022 , Google Inc. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. @@ -36,6 +36,7 @@ import Control.Monad.State.Strict import Control.Monad.Trans.Except (ExceptT (..), runExcept, runExceptT, throwE) import Data.Bifunctor (second) +import Data.Char (ord) import Data.Either (partitionEithers) import Data.Foldable (Foldable(toList)) import Data.Functor (($>)) @@ -43,6 +44,7 @@ import Data.Hashable (Hashable) import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HashMap import qualified Data.IntSet as IntSet +import Data.Primitive.ByteArray (ByteArray (..)) import Control.Applicative (Alternative((<|>))) import Data.List (unzip4, partition) import qualified Data.List as List @@ -56,6 +58,13 @@ import qualified Data.Text as Text import Data.Text.Extra (showt) import Data.Text.Lazy (toStrict) import Data.Text.Prettyprint.Doc.Extra + +#if MIN_VERSION_base(4,15,0) +import GHC.Num.Integer (Integer (..)) +#else +import GHC.Integer.GMP.Internals (Integer (..), BigNat (..)) +#endif + import GHC.Stack (HasCallStack) #if MIN_VERSION_ghc(9,0,0) @@ -2111,3 +2120,29 @@ expandTopEntity ihwtys (oId, ohwty) topEntityM expandTopEntity _ _ topEntityM = error ("expandTopEntity expects a Synthesize annotation, but got: " <> show topEntityM) + +-- | Convert a Core 'C.Literal' to a Netlist v'HW.Literal' +mkLiteral :: Int -- ^ int width + -> C.Literal -> HW.Expr +mkLiteral iw lit = case lit of + C.IntegerLiteral i -> HW.Literal (Just (Signed iw,iw)) $ NumLit i + C.IntLiteral i -> HW.Literal (Just (Signed iw,iw)) $ NumLit i + C.WordLiteral w -> HW.Literal (Just (Unsigned iw,iw)) $ NumLit w + C.Int64Literal i -> HW.Literal (Just (Signed 64,64)) $ NumLit i + C.Word64Literal w -> HW.Literal (Just (Unsigned 64,64)) $ NumLit w + C.Int8Literal i -> HW.Literal (Just (Signed 8,8)) $ NumLit i + C.Int16Literal i -> HW.Literal (Just (Signed 16,16)) $ NumLit i + C.Int32Literal i -> HW.Literal (Just (Signed 32,32)) $ NumLit i + C.Word8Literal w -> HW.Literal (Just (Unsigned 8,8)) $ NumLit w + C.Word16Literal w -> HW.Literal (Just (Unsigned 16,16)) $ NumLit w + C.Word32Literal w -> HW.Literal (Just (Unsigned 32,32)) $ NumLit w + C.CharLiteral c -> HW.Literal (Just (Unsigned 21,21)) . NumLit . toInteger $ ord c + C.FloatLiteral w -> HW.Literal (Just (BitVector 32,32)) (NumLit $ toInteger w) + C.DoubleLiteral w -> HW.Literal (Just (BitVector 64,64)) (NumLit $ toInteger w) + C.NaturalLiteral n -> HW.Literal (Just (Unsigned iw,iw)) $ NumLit n +#if MIN_VERSION_base(4,15,0) + C.ByteArrayLiteral (ByteArray ba) -> HW.Literal Nothing (NumLit (IP ba)) +#else + C.ByteArrayLiteral (ByteArray ba) -> HW.Literal Nothing (NumLit (Jp# (BN# ba))) +#endif + C.StringLiteral s -> HW.Literal Nothing $ StringLit s diff --git a/tests/Main.hs b/tests/Main.hs index 719c33b0f8..74a8383b74 100755 --- a/tests/Main.hs +++ b/tests/Main.hs @@ -403,7 +403,6 @@ runClashTest = defaultMain $ clashTestRoot , runTest "NestedPrimitives2" def{hdlSim=[]} , runTest "NORX" def , runTest "Parameters" def{hdlTargets=[VHDL]} - , runTest "PopCount" def , runTest "RecordSumOfProducts" def{hdlSim=[]} , runTest "Replace" def , runTest "TestIndex" def{hdlSim=[]} @@ -832,6 +831,10 @@ runClashTest = defaultMain $ clashTestRoot #if MIN_VERSION_base(4,14,0) , runTest "BitReverse" def #endif + , runTest "BitsTB" def { buildTargets = BuildSpecific [ "bitsTB1" + , "bitsTB2" + , "bitsTB3" + ]} , -- vivado segfaults runTest "Bounds" def { hdlSim=hdlSim def \\ [Vivado] } diff --git a/tests/shouldwork/Basic/PopCount.hs b/tests/shouldwork/Basic/PopCount.hs deleted file mode 100644 index c5ef817563..0000000000 --- a/tests/shouldwork/Basic/PopCount.hs +++ /dev/null @@ -1,42 +0,0 @@ -{-# LANGUAGE CPP #-} -{-# LANGUAGE PartialTypeSignatures #-} -{-# OPTIONS_GHC -Wno-partial-type-signatures #-} - -module PopCount where - -import Clash.Prelude -import Clash.Explicit.Testbench -import GHC.Word -import GHC.Int -import Data.Bits - -topEntity :: Integer -> Vec _ Int -topEntity i = popCount @Word j - :> popCount @Word8 j - :> popCount @Word16 j - :> popCount @Word32 j - :> popCount @Word64 j - :> popCount @Int j - :> popCount @Int8 j - :> popCount @Int16 j - :> popCount @Int32 j - :> popCount @Int64 j - :> popCount @(BitVector 7) j - :> popCount @(Signed 9) j - :> popCount @(Signed 101) j - :> popCount @(Unsigned 11) j - :> Nil - where - j :: Num a => a - j = fromInteger i --- See: https://github.com/clash-lang/clash-compiler/pull/2511 -{-# CLASH_OPAQUE topEntity #-} - -testBench :: Signal System Bool -testBench = done - where - testInput = stimuliGenerator clk rst $(listToVecTH [1::Integer,3,8,50,0]) - expectedOutput = outputVerifier' clk rst $ fmap repeat $(listToVecTH ([1,2,1,3,0]::[Int])) - done = expectedOutput (topEntity <$> testInput) - clk = tbSystemClockGen (not <$> done) - rst = systemResetGen diff --git a/tests/shouldwork/Numbers/Bits.hs b/tests/shouldwork/Numbers/Bits.hs new file mode 100644 index 0000000000..9a55fba5f6 --- /dev/null +++ b/tests/shouldwork/Numbers/Bits.hs @@ -0,0 +1,104 @@ +{-# LANGUAGE CPP #-} +{-# LANGUAGE PartialTypeSignatures #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE ViewPatterns #-} +#if __GLASGOW_HASKELL__ < 900 +{-# LANGUAGE AllowAmbiguousTypes #-} +#endif + +{-# OPTIONS_GHC -Wno-partial-type-signatures #-} + +{-| +This checks that the methods of the Bits and FiniteBits typeclasses +do the same thing in HDL and Haskell. +The checks are split up into multiple parts to work around maximum +width issues in the $display function of verilator. +-} +module Bits where +import Clash.Prelude +import Clash.Explicit.Testbench +import Data.Int +import Data.Word +import Data.Bits + +testBits :: forall a. (Num a, Bits a) => Integer -> Integer -> _ +testBits x0@(fromInteger -> x) y0 = + ( testBitsNoPopCount @a x0 y0 + , popCount @a x + , bitSize @a x -- deprecated and undefined for Integer + ) + +testBitsNoPopCount :: forall a. (Num a, Bits a) => Integer -> Integer -> _ +testBitsNoPopCount (fromInteger @a -> x) y0@(fromInteger @a -> y) = + ( + ( (.&.) @a x y + , (.|.) @a x y + , xor @a x y + , complement @a x + , shift @a x yInt + , rotate @a x yInt + , zeroBits @a + ) + , ( bit @a yInt + , setBit @a x yInt + , clearBit @a x yInt + , complementBit @a x yInt + , testBit @a x yInt + , bitSizeMaybe @a x + , isSigned @a x + ) + , ( shiftL @a x yInt + , unsafeShiftL @a x yInt + , shiftR @a x yInt + , unsafeShiftR @a x yInt + , rotateL @a x yInt + , rotateR @a x yInt + ) + ) + where + yInt :: Int + yInt = (abs (fromInteger y0)) `mod` sz + sz = case bitSizeMaybe x of + Nothing -> 64 + Just x -> fromIntegral x + +testFiniteBits :: forall a. (Num a, FiniteBits a) => Integer -> Integer -> _ +testFiniteBits x0@(fromInteger -> x) y0@(fromInteger -> y) = + ( testBits @a x0 y0 + , finiteBitSize @a x + , countLeadingZeros @a x + , countTrailingZeros @a x + ) + +topEntity1 :: (Integer, Integer) -> _ +topEntity1 (x,y) = + ( testBitsNoPopCount @Integer x y + , testFiniteBits @Int x y + , testFiniteBits @Int8 x y + , testFiniteBits @Int16 x y + -- , testFiniteBits @Int32 x y -- TODO triggers GHDL bug #2618, re-enable after we get another GHDL + , testFiniteBits @Int64 x y + ) + +topEntity2 :: (Integer, Integer) -> _ +topEntity2 (x,y) = + ( testFiniteBits @Word x y + , testFiniteBits @Word8 x y + , testFiniteBits @Word16 x y + , testFiniteBits @Word32 x y + , testFiniteBits @Word64 x y + ) + +topEntity3 :: (Integer, Integer) -> _ +topEntity3 (x,y) = + ( testFiniteBits @(Signed 66) x y + , testFiniteBits @(Unsigned 66) (abs x) (abs y) + , testFiniteBits @(BitVector 66) (abs x) (abs y) + , testFiniteBits @(Index 128) (abs x `mod` 128) (abs y `mod` 128) + ) + +inputs :: Vec _ (Integer,Integer) +inputs = + $(let range = [0,42, (fromIntegral @Int64 maxBound), (fromIntegral @Int64 minBound) + , -1, -123] :: [Integer] + in listToVecTH [(a,b) | a <- range, b <- range]) diff --git a/tests/shouldwork/Numbers/BitsTB.hs b/tests/shouldwork/Numbers/BitsTB.hs new file mode 100644 index 0000000000..18ba99b2a0 --- /dev/null +++ b/tests/shouldwork/Numbers/BitsTB.hs @@ -0,0 +1,43 @@ +{-# LANGUAGE CPP #-} + +module BitsTB where +import Clash.Prelude +import Clash.Explicit.Testbench +import Bits +import Clash.Sized.Vector (unsafeFromList) + +expected1 = $(lift $ map topEntity1 $ inputs) +expected2 = $(lift $ map topEntity2 $ inputs) +expected3 = $(lift $ map topEntity3 $ inputs) + +topEntity = False + +bitsTB1 :: Signal System Bool +bitsTB1 = done + where + testInput = stimuliGenerator clk rst inputs + expectedOutput = outputVerifier' clk rst expected1 + done = expectedOutput (topEntity1 <$> testInput) + clk = tbSystemClockGen (not <$> done) + rst = systemResetGen +{-# ANN bitsTB1 (TestBench 'topEntity) #-} + +bitsTB2 :: Signal System Bool +bitsTB2 = done + where + testInput = stimuliGenerator clk rst inputs + expectedOutput = outputVerifier' clk rst expected2 + done = expectedOutput (topEntity2 <$> testInput) + clk = tbSystemClockGen (not <$> done) + rst = systemResetGen +{-# ANN bitsTB2 (TestBench 'topEntity) #-} + +bitsTB3 :: Signal System Bool +bitsTB3 = done + where + testInput = stimuliGenerator clk rst inputs + expectedOutput = outputVerifier' clk rst expected3 + done = expectedOutput (topEntity3 <$> testInput) + clk = tbSystemClockGen (not <$> done) + rst = systemResetGen +{-# ANN bitsTB3 (TestBench 'topEntity) #-} diff --git a/tests/shouldwork/Numbers/NumConstantFolding_2.hs b/tests/shouldwork/Numbers/NumConstantFolding_2.hs index b07bd1cca0..fb28eee9e1 100644 --- a/tests/shouldwork/Numbers/NumConstantFolding_2.hs +++ b/tests/shouldwork/Numbers/NumConstantFolding_2.hs @@ -98,8 +98,15 @@ tUFixed -- Bit? tInt = csGenericHaskell @Int +tInt8 = csGenericHaskell @Int8 tInt16 = csGenericHaskell @Int16 +tInt32 = csGenericHaskell @Int32 +tInt64 = csGenericHaskell @Int64 +tWord = csGenericHaskell @Word +tWord8 = csGenericHaskell @Word8 tWord16 = csGenericHaskell @Word16 +tWord32 = csGenericHaskell @Word32 +tWord64 = csGenericHaskell @Word64 topEntity = ( bvSpecific @@ -107,9 +114,18 @@ topEntity , tInteger , tNatural , tUFixed - , tInt - , tInt16 - , tWord16 + , ( tInt + , tInt8 + , tInt16 + , tInt32 + , tInt64 + ) + , ( tWord + , tWord8 + , tWord16 + , tWord32 + , tWord64 + ) ) -- See: https://github.com/clash-lang/clash-compiler/pull/2511 {-# CLASH_OPAQUE topEntity #-}