Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hex and octal BitVector parsing per issue 1772 #2505

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Add hex and octal BitVector parsing. [#1772](https://github.com/clash-lang/clash-compiler/pull/2505)
2 changes: 2 additions & 0 deletions clash-prelude/src/Clash/Sized/BitVector.hs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ module Clash.Sized.BitVector
, maxIndex#
-- ** Construction
, bLit
, hLit
, oLit
-- ** Concatenation
, (++#)
-- * Modification
Expand Down
72 changes: 72 additions & 0 deletions clash-prelude/src/Clash/Sized/Internal/BitVector.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Copyright : (C) 2013-2016, University of Twente,
2019 , Gergő Érdi
2016-2019, Myrtle Software Ltd,
2021-2022, QBayLogic B.V.
2023 , Nadia Chambers
License : BSD2 (see the file LICENSE)
Maintainer : QBayLogic B.V. <devops@qbaylogic.com>
-}
Expand Down Expand Up @@ -57,6 +58,8 @@ module Clash.Sized.Internal.BitVector
, maxIndex#
-- ** Construction
, bLit
, hLit
, oLit
, undefined#
-- ** Concatenation
, (++#)
Expand Down Expand Up @@ -141,6 +144,7 @@ import Data.Proxy (Proxy (..))
import Data.Typeable (Typeable, typeOf)
import GHC.Generics (Generic)
import Data.Maybe (fromMaybe)
import Numeric (readOct, readHex)
import GHC.Exts
(Word#, Word (W#), eqWord#, int2Word#, isTrue#, uncheckedShiftRL#)
#if MIN_VERSION_base(4,15,0)
Expand Down Expand Up @@ -553,6 +557,74 @@ read# cs0 = (fromIntegral (length cs1), BV m v)
"Clash.Sized.Internal.bLit: unknown character: "
++ show c ++ " in input: " ++ cs0

-- | Create a hexadecimal literal
--
-- >>> $(hLit "dead")
-- 0b1101_1110_1010_1101
--
-- Don't care digits set 4 bits:
--
-- >>> $(hLit "de..")
-- 0b1101_1110_...._....
hLit :: String -> ExpQ
hLit s = pure (SigE body typ)
where
typ = ConT ''BitVector `AppT` LitT (NumTyLit (toInteger n))
body = VarE 'fromInteger# `AppE` iLit mask `AppE` iLit value

iLit = LitE . IntegerL . toInteger
(n, BV mask value) = read16# s :: (Natural, BitVector n)

read16# :: String -> (Natural, BitVector n)
read16# cs0 = (fromIntegral $ 4 * length cs1, BV m v)
where
cs1 = filter (/= '_') cs0
(vs, ms) = unzip $ map readHexDigit cs1
combineHexDigits = foldl (\b a -> 16*b+a) 0
v = combineHexDigits vs
m = combineHexDigits ms
-- The dot is a don't care, which applies to a whole digit.
readHexDigit '.' = (0, 0xf)
readHexDigit c = case readHex [c] of
[(n, "")] -> (n, 0)
_ -> error $
"Clash.Sized.Internal.hLit: unknown character: "
++ show c ++ " in input: " ++ cs0

-- | Create an octal literal
--
-- >>> $(oLit "5234")
-- 0b1010_1001_1100
--
-- Don't care digits set 3 bits:
--
-- >>> $(oLit "52..")
-- 0b1010_10.._....
oLit :: String -> ExpQ
oLit s = pure (SigE body typ)
where
typ = ConT ''BitVector `AppT` LitT (NumTyLit (toInteger n))
body = VarE 'fromInteger# `AppE` iLit mask `AppE` iLit value

iLit = LitE . IntegerL . toInteger
(n, BV mask value) = read8# s :: (Natural, BitVector n)

read8# :: String -> (Natural, BitVector n)
read8# cs0 = (fromIntegral $ 3 * length cs1, BV m v)
where
cs1 = filter (/= '_') cs0
(vs, ms) = unzip $ map readOctDigit cs1
combineOctDigits = foldl (\b a -> 8*b+a) 0
v = combineOctDigits vs
m = combineOctDigits ms
-- The dot is a don't care, which applies to a whole digit.
readOctDigit '.' = (0, 0o7)
readOctDigit c = case readOct [c] of
[(n, "")] -> (n, 0)
_ -> error $
"Clash.Sized.Internal.oLit: unknown character: "
++ show c ++ " in input: " ++ cs0


instance KnownNat n => Eq (BitVector n) where
(==) = eq#
Expand Down
11 changes: 10 additions & 1 deletion clash-prelude/tests/Clash/Tests/BitVector.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import qualified Test.Tasty.QuickCheck as Q
import Control.Applicative (liftA2)
#endif
import Clash.Prelude
(Bit, high, low, bitPattern, type (<=), type (-), natToInteger, msb, bLit)
martijnbastiaan marked this conversation as resolved.
Show resolved Hide resolved
(Bit, high, low, bitPattern, type (<=), type (-), natToInteger, msb, bLit, hLit, oLit)
import Clash.Sized.Internal.BitVector (BitVector (..))

import Clash.Tests.SizedNum
Expand Down Expand Up @@ -124,6 +124,15 @@ tests = localOption (Q.QuickCheckMaxRatio 2) $ testGroup "All"
, testCase "show11" $ show @(BitVector 5) $(bLit "1010.") @?= "0b1_010."
, testCase "show12" $ show @(BitVector 8) $(bLit "0001010.") @?= "0b0001_010."
, testCase "show13" $ show @(BitVector 9) $(bLit "10001010.") @?= "0b1_0001_010."

, testCase "show14" $ show @(BitVector 16) $(hLit "dead") @?= "0b1101_1110_1010_1101"
, testCase "show14" $ show @(BitVector 16) $(hLit "de.d") @?= "0b1101_1110_...._1101"
, testCase "show15" $ show @(BitVector 16) $(hLit "beef") @?= "0b1011_1110_1110_1111"
, testCase "show15" $ show @(BitVector 16) $(hLit ".eef") @?= "0b...._1110_1110_1111"
, testCase "show16" $ show @(BitVector 12) $(oLit "7734") @?= "0b1111_1101_1100"
, testCase "show16" $ show @(BitVector 12) $(oLit "77.4") @?= "0b1111_11.._.100"
, testCase "show17" $ show @(BitVector 12) $(oLit "5324") @?= "0b1010_1101_0100"
martijnbastiaan marked this conversation as resolved.
Show resolved Hide resolved
, testCase "show17" $ show @(BitVector 12) $(oLit ".324") @?= "0b...0_1101_0100"
]
]

Expand Down