clash-lang / clash-compiler

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

`map writeToBiSignal` doesn't render to HDL #1138

Open leonschoorl opened 4 years ago

leonschoorl commented 4 years ago
module Search where
import Clash.Prelude
import Clash.Signal.BiSignal
import Clash.Explicit.Testbench

findSingleJust
  :: forall dom n a. ( n ~ 4, BitPack a, KnownNat n)
  => (a -> Maybe a) -> Signal dom (Vec n a) -> Signal dom a
findSingleJust p xs0 = sigOut
  where
    xs1 :: Vec n (Signal dom a)
    xs1 = unbundle xs0
    xs2 :: Vec n (Signal dom (Maybe a))
    xs2 = map (fmap p) xs1

    bisigOuts :: Vec n (BiSignalOut 'Floating dom (BitSize a))
    bisigOuts = map (writeToBiSignal bisigIn) xs2
    -- bisigOuts =  go xs2a :> go xs2b :> go xs2c :> go xs2d :> Nil
    --   where
    --     go = writeToBiSignal bisigIn
    --     xs2a :> xs2b :> xs2c :> xs2d :> Nil = xs2

    bisigOut :: BiSignalOut 'Floating dom (BitSize a)
    bisigOut = mergeBiSignalOuts bisigOuts

    bisigIn :: BiSignalIn 'Floating dom (BitSize a)
    bisigIn = veryUnsafeToBiSignalIn bisigOut

    sigOut :: Signal dom a
    sigOut = readFromBiSignal bisigIn

predToMaybe :: (a -> Bool) -> (a -> Maybe a)
predToMaybe p = \x -> if p x then Just x else Nothing

topEntity :: Signal System (Vec 4 (Unsigned 4)) -> Signal System (Unsigned 4)
topEntity = findSingleJust (predToMaybe (odd))

{-# NOINLINE topEntity #-}

testBench :: Signal System Bool
testBench = done
  where
    testInput      = stimuliGenerator clk rst input
    expectedOutput = outputVerifier' clk rst expected
    done           = expectedOutput (topEntity testInput)
    clk            = tbSystemClockGen (not <$> done)
    rst            = systemResetGen

input :: Vec 5 (Vec 4 (Unsigned 4))
input =
  (1:>0:>0:>0:>Nil) :>
  (0:>3:>0:>0:>Nil) :>
  (0:>0:>0:>5:>Nil) :>
  (0:>0:>7:>0:>Nil) :>
  (0:>9:>0:>0:>Nil) :>
  Nil
expected :: Vec 5 (Unsigned 4)
expected =
  1 :> 3 :> 5 :> 7 :> 9 :>
  Nil

If I manually unroll the map (writeToBiSignal bisigIn) it works fine.

leonschoorl commented 4 years ago

Compiling with -fclash-compile-ultra also works. Because it makes clash to unroll the map.

martijnbastiaan commented 4 years ago

The core of the issue is that RenderVoid only works on one layer at the moment. We should go over all HO primitives and make them check whether their function argument is a blackbox with RenderVoid (if that's possible at all in the current architecture). We'd probably need to change the RenderVoid datastructure to:

data RenderVoid
  = AlwaysRenderVoid
  | NeverRenderVoid
  | ConstantRenderVoid

with the last constructor indicating that a blackbox will render voids if one of their arguments does.