Skip to content
Open
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
2 changes: 2 additions & 0 deletions changelog/2025-08-18T20_57_06+02_00_fix_2988_2809
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FIXED: Verilog and System Verilog code gen bug for `map head` [#2809](https://github.com/clash-lang/clash-compiler/issues/2809)
FIXED: Error parsing blackbox: `Clash.Sized.Vector.head` [#2988](https://github.com/clash-lang/clash-compiler/issues/2988)
8 changes: 7 additions & 1 deletion clash-lib/src/Clash/Netlist/BlackBox.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}

module Clash.Netlist.BlackBox where
module Clash.Netlist.BlackBox
( mkBlackBoxContext
, extractPrimWarnOrFail
, mkPrimitive
, prepareBlackBox
, isLiteral
) where

import Control.Exception (throw)
import Control.Lens ((%=))
Expand Down
4 changes: 2 additions & 2 deletions clash-lib/src/Clash/Netlist/BlackBox/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ pElemE = pTagE

-- | Parse SigD
pSigD :: Parser [Element]
pSigD = some (pTagE <|> (Text (pack "[") <$ (pack <$> string "[\\"))
<|> (Text (pack "]") <$ (pack <$> string "\\]"))
pSigD = some (pTagE <|> (EscapedSymbol SquareBracketOpen <$ string "[\\")
<|> (EscapedSymbol SquareBracketClose <$ string "\\]")
<|> (Text <$> (pack <$> some (satisfyRange '\000' '\90')))
<|> (Text <$> (pack <$> some (satisfyRange '\94' '\125'))))

Expand Down
7 changes: 7 additions & 0 deletions clash-lib/src/Clash/Netlist/BlackBox/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module Clash.Netlist.BlackBox.Types
, BlackBoxTemplate
, TemplateKind (..)
, Element(..)
, EscapedSymbol(..)
, Decl(..)
, HdlSyn(..)
, RenderVoid(..)
Expand Down Expand Up @@ -211,6 +212,12 @@ data Element
| CtxName
-- ^ The "context name", name set by `Clash.Magic.setName`, defaults to the
-- name of the closest binder
| EscapedSymbol EscapedSymbol
-- ^ Used for "[\" and "\]", they'll be rendered as "[" and "]",
-- but pretty printed as "[\" and "\]".
deriving (Show, Generic, NFData, Binary, Eq, Hashable)

data EscapedSymbol = SquareBracketOpen | SquareBracketClose
deriving (Show, Generic, NFData, Binary, Eq, Hashable)

-- | Component instantiation hole. First argument indicates which function argument
Expand Down
38 changes: 33 additions & 5 deletions clash-lib/src/Clash/Netlist/BlackBox/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,21 @@
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}

module Clash.Netlist.BlackBox.Util where
module Clash.Netlist.BlackBox.Util
( renderTemplate
, walkElement
, verifyBlackBoxContext
, onBlackBox
, setSym
, extractLiterals
, renderBlackBox
, getUsedArguments
, renderFilePath
, exprToString
, renderElem
, getDomainConf
, prettyBlackBox
) where

import Control.Exception (throw)
import Control.Lens
Expand Down Expand Up @@ -126,6 +140,7 @@ inputHole = \case
DevNull _ -> Nothing
SigD _ nM -> nM
CtxName -> Nothing
EscapedSymbol _ -> Nothing

-- | Determine if the number of normal\/literal\/function inputs of a blackbox
-- context at least matches the number of argument that is expected by the
Expand Down Expand Up @@ -403,7 +418,7 @@ renderElem b (Component (Decl n subN (l:ls))) = do
Just (templ0,_,libs,imps,inc,pCtx) -> do
let b' = pCtx { bbResults = [(o,oTy)], bbInputs = bbInputs pCtx ++ is }
layoutOptions = LayoutOptions (AvailablePerLine 120 0.4)
render = N.BBTemplate . parseFail . renderLazy . layoutPretty layoutOptions
render = N.BBTemplate . parseFail b' . renderLazy . layoutPretty layoutOptions

templ1 <-
case templ0 of
Expand Down Expand Up @@ -660,10 +675,15 @@ generalGetDomainConf getDomainMap ty = case (snd . stripAttributes . stripVoid)
Nothing -> error $ "Can't find domain " <> show dom <> ". Please report an issue at https://github.com/clash-lang/clash-compiler/issues."
Just conf -> pure conf

parseFail :: Text -> BlackBoxTemplate
parseFail t = case runParse t of
parseFail :: BlackBoxContext -> Text -> BlackBoxTemplate
parseFail b t = case runParse t of
Failure errInfo ->
error (show (_errDoc errInfo))
error $ unlines
[ "error while parsing blackbox: " <> Data.Text.unpack (bbName b)
, "in component " <> Data.Text.unpack (Id.toText $ bbCompName b)
, "error:"
, show (_errDoc errInfo)
]
Success templ -> templ

idToExpr
Expand Down Expand Up @@ -904,6 +924,9 @@ renderTag b CtxName = case bbCtxName b of
-> return (Id.toLazyText t)
_ -> error "internal error"

renderTag _ (EscapedSymbol sym) = case sym of
SquareBracketOpen -> return "["
SquareBracketClose -> return "]"

renderTag _ e = do e' <- getAp (prettyElem e)
error $ $(curLoc) ++ "Unable to evaluate: " ++ show e'
Expand Down Expand Up @@ -1108,6 +1131,9 @@ prettyElem (Template bbname source) = do
<> brackets (string $ Text.concat bbname')
<> brackets (string $ Text.concat source'))
prettyElem CtxName = return "~CTXNAME"
prettyElem (EscapedSymbol sym) = case sym of
SquareBracketOpen -> return "[\\"
SquareBracketClose -> return "\\]"

-- | Recursively walk @Element@, applying @f@ to each element in the tree.
walkElement
Expand Down Expand Up @@ -1178,6 +1204,7 @@ walkElement f el = maybeToList (f el) ++ walked
Repeat es1 es2 ->
concatMap go es1 ++ concatMap go es2
CtxName -> []
EscapedSymbol _ -> []

-- | Determine variables used in an expression. Used for VHDL sensitivity list.
-- Also see: https://github.com/clash-lang/clash-compiler/issues/365
Expand Down Expand Up @@ -1266,6 +1293,7 @@ getUsedArguments (N.BBTemplate t) = nub (concatMap (walkElement matchArg) t)
TypM _ -> Nothing
Vars _ -> Nothing
CtxName -> Nothing
EscapedSymbol _ -> Nothing

onBlackBox
:: (BlackBoxTemplate -> r)
Expand Down
1 change: 1 addition & 0 deletions tests/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@ runClashTest = defaultMain
, runTest "T2845" def{hdlSim=[],hdlTargets=[Verilog]}
, runTest "T2904" def
, runTest "T2966" def{hdlSim=[],hdlTargets=[Verilog]}
, runTest "T2988" def{hdlSim=[]}
] <>
if compiledWith == Cabal then
-- This tests fails without environment files present, which are only
Expand Down
15 changes: 15 additions & 0 deletions tests/shouldwork/Issues/T2988.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE CPP #-}

module T2988 where

import Clash.Prelude
import Prelude ()

topEntity :: Signal System (Vec 4 (Vec 4 (Unsigned 32))) -> Signal System (Vec 4 (Unsigned 32))
topEntity = f
{-# CLASH_OPAQUE topEntity #-}

f :: Signal System (Vec n (Vec 4 (Unsigned 32))) -> Signal System (Vec n (Unsigned 32))
f x = fmap (fmap head) x
{-# CLASH_OPAQUE f #-}
Loading