clash-lang / clash-compiler

Haskell to VHDL/Verilog/SystemVerilog compiler
https://clash-lang.org/
Other
1.4k stars 147 forks source link

Can't put synthesis attribute on output tuple #2594

Open DigitalBrains1 opened 8 months ago

DigitalBrains1 commented 8 months ago

We can't put Clash.Annotations.SynthesisAttributes on a top entity output when the output is a tuple. Specifying SynthesisAttributes on output tuple elements causes them to silently disappear from the output. But something like a tuple is necessary to have outputs with multiple clock domains, so this is a rather significant omission.

Example

So for example I'd like to do

type PinAttr loc =
        [ 'StringAttr "chip_pin" loc
        , 'StringAttr "altera_attribute" "-name IO_STANDARD \"3.3-V LVTTL\""
        ]

properTopEntity
  :: Clock Input `Annotate` PinAttr "R8"
  -> Reset Input `Annotate` PinAttr "J15"
  -> ( Signal DomA Bit `Annotate` PinAttr "D1"
     , Signal DomB Bit `Annotate` PinAttr "A11"
     , Signal DomC Bit `Annotate` PinAttr "B13"
     , Signal DomD Bit `Annotate` PinAttr "A13"
     , Signal DomE Bit `Annotate` PinAttr "A15"
     )

in the following code, but I have to jump through weird hoops and write topEntity instead:

MultiBlinker.hs ```haskell {-# OPTIONS_GHC -Wno-orphans #-} module MultiBlinker where import Clash.Explicit.Prelude import Clash.Intel.ClockGen import Clash.Annotations.SynthesisAttributes createDomain vSystem{vName="Input", vPeriod=20000, vResetPolarity=ActiveLow} createDomain vSystem{vName="DomA", vPeriod=9000} createDomain vSystem{vName="DomB", vPeriod=11000} createDomain vSystem{vName="DomC", vPeriod=13000} createDomain vSystem{vName="DomD", vPeriod=15000} createDomain vSystem{vName="DomE", vPeriod=17000} type PinAttr loc = [ 'StringAttr "chip_pin" loc , 'StringAttr "altera_attribute" "-name IO_STANDARD \"3.3-V LVTTL\"" ] {-# ANN topEntity (Synthesize { t_name = "blinker" , t_inputs = [ PortName "CLOCK_50" , PortName "KEY0" ] , t_output = PortName "LED" }) #-} topEntity :: Clock Input `Annotate` PinAttr "R8" -> Reset Input `Annotate` PinAttr "J15" -> Signal DomA (BitVector 5) `Annotate` PinAttr "D1, A11, B13, A13, A15" topEntity clkIn rstIn = pack <$> bundle ( ledA , syn ledB , syn ledC , syn ledD , syn ledE ) where (ledA, ledB, ledC, ledD, ledE) = properTopEntity clkIn rstIn syn :: KnownDomain domIn => Signal domIn a -> Signal DomA a syn = unsafeSynchronizer undefined undefined {-# OPAQUE topEntity #-} properTopEntity :: Clock Input `Annotate` PinAttr "R8" -> Reset Input `Annotate` PinAttr "J15" -> ( Signal DomA Bit `Annotate` PinAttr "D1" , Signal DomB Bit `Annotate` PinAttr "A11" , Signal DomC Bit `Annotate` PinAttr "B13" , Signal DomD Bit `Annotate` PinAttr "A13" , Signal DomE Bit `Annotate` PinAttr "A15" ) properTopEntity clkIn rstIn = ( blink clkA rstA , blink clkB rstB , blink clkC rstC , blink clkD rstD , blink clkE rstE ) where blink clk rst = let cnt = register clk rst enableGen (0 :: Unsigned 26) $ cnt + 1 in msb <$> cnt (clkA, rstA, clkB, rstB, clkC, rstC, clkD, rstD, clkE, rstE) = altpllSync clkIn rstIn ```