Open Jhana1 opened 3 years ago
We do have a branch from a while ago that @christiaanb was working on, but I'm not sure what state it's in. I'm not that familiar with the AutoReg
stuff though, maybe it needs more adaptation to work with DSignals
@Jhana1 Interesting, I'll post a rewrite of what you wanted that shouldn't blow up compile times; after I've had my breakfast.
@Jhana1 The following should compile relatively quickly:
module DAutoReg where
import Clash.Prelude
dAutoRegN ::
forall dom a delay n .
(HiddenClockResetEnable dom, AutoReg a, Default a, KnownNat delay) =>
SNat n ->
DSignal dom delay a ->
DSignal dom (delay + n) a
dAutoRegN s@SNat = unsafeFromSignal . go (toUNat s) . toSignal
where
go :: UNat n -> Signal dom a -> Signal dom a
go UZero inp = inp
go (USucc _) inp =
let shIn = init (inp `Cons` shOut)
shOut = map (autoReg def) (lazyV @n shIn)
in last shOut
topEntity xs = dAutoRegN @System @(Vec 10 (Maybe Int)) @0 (SNat @200) xs
So the 200 stage deep pipeline of type Vec 10 (Maybe Int)
for me gives:
$ time cabal run clash -- --vhdl DAutoReg.hs
Up to date
Loaded package environment from /home/christiaan/clash-compiler/.ghc.environment.x86_64-linux-8.10.4
GHC: Parsing and optimising modules took: 1.413s
GHC: Loading external modules from interface files took: 0.000s
GHC: Parsing annotations took: 0.001s
Clash: Parsing and compiling primitives took 0.142s
GHC+Clash: Loading modules cumulatively took 2.793s
Clash: Compiling DAutoReg.topEntity
Clash: Normalization took 0.291s
Clash: Netlist generation took 0.024s
Clash: Total compilation took 3.130s
real 0m3.743s
user 0m3.378s
sys 0m0.176s
This is on HEAD of master
, but I don't expect much difference for the 1.4.2 release.
dAugoRegN
can actually be simplified to:
dAutoRegN ::
forall dom a delay n .
(HiddenClockResetEnable dom, AutoReg a, Default a, KnownNat delay) =>
SNat n ->
DSignal dom delay a ->
DSignal dom (delay + n) a
dAutoRegN SNat = unsafeFromSignal . go . toSignal
where
go inp =
let shIn = init (inp :> shOut)
shOut = map (autoReg def) (lazyV @n shIn)
in last (inp :> shOut)
The reason this doesn't blow up is because it allows the Clash compiler to take hard-coded "short-cuts" where it doesn't have to unroll the definitions for init
, map
, lazyV
and last
, but can use their "blackbox" implementations instead:
init
: https://github.com/clash-lang/clash-compiler/blob/1c81d8f7e4c208559de2c31cafb3114fc9aefe89/clash-lib/prims/vhdl/Clash_Sized_Vector.primitives#L25-L32map
: https://github.com/clash-lang/clash-compiler/blob/1c81d8f7e4c208559de2c31cafb3114fc9aefe89/clash-lib/prims/vhdl/Clash_Sized_Vector.primitives#L102-L128last
: https://github.com/clash-lang/clash-compiler/blob/1c81d8f7e4c208559de2c31cafb3114fc9aefe89/clash-lib/prims/vhdl/Clash_Sized_Vector.primitives#L17-L24lazyV
: https://github.com/clash-lang/clash-compiler/blob/1c81d8f7e4c208559de2c31cafb3114fc9aefe89/clash-lib/prims/common/Clash_Sized_Vector.primitives#L2-L10Another thing to note: lazyV
is there to ensure we have a "spine" of Cons / (:>)
constructors to map
over.
Thanks, I'm trying it now. Much appreciated!
Some additional AutoReg convenience functions would be really nice, replicating the
delay
,delayN
,delayI
interface would be great. I've tried to do the same, but the following (a blatant copy paste ofdelayN
) blows out compile times (so I imagine some internal special casing must happen on these functions to prevent that)