-
Notifications
You must be signed in to change notification settings - Fork 147
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
exception :verilog and :vhdl #1648
Comments
Is there any way you could provide a MWE that you can share? There may be a simple source level fix to the problem. |
will try.. |
Okay, we know what the bug is. The compile time evaluator never took impredicative instantiation into account. That is, given:
we never took into account that
We mistakenly assumed that for "primitives" such as NB: We're not saying that you're using impredicative types and that you shouldn't do that. It's most likely that GHC is actually using them under the hood somewhere, i.e. you're most likely not using impredicative types explicitly at all. Regardless, impredicative types are something that Clash should just handle properly. |
@christiaanb @alex-mckenna different question - How I can use data from imported module and feed it to "top_entity`? using list is not great idea (eg listToVecTH) |
You mean as a work-around for this issue? |
as I understand only ListToVecTH is available. or I missed something similar/proper/better? |
work around is only ListToVecTH atm. but I'd prefer to pack data in custom data type rather then unpack individual elements (of the same type!) from List and convert to Vec |
You can define a custom type and pass that around normally. If you also derive BitPack for it then you're free to convert that type to/from BitVectors of the same width. If you want a vector though, at some point you'll have to create a vector... Would it be possible to share just the |
Ah, another work-around would be to use
where
This will use TH to force that "constant", To give a concrete example, let's say that;
then
into
at TH compile-time, which happens before Clash does it compile-time evaluation |
@christiaanb Cool!...and Can I pass "4" into that example as a parameter from command line? |
Ehm.... yes... using the C pre processor....
and then call Clash with:
But this is veering into hacky ducktape monkeypatch territory... |
well. The idea to have same source(in clash) but able to generate different hardware without any extra tool(s) eg. not use matlab/python/anything else/ or without editing external file(s) |
I see your point... you could also do:
and then call Clash with:
to compile
to compile |
@christiaanb I am afraid I can't use this approach as I need to generate a bunch of different Filters with different sample rates and frequencies responses, where for example the number of coefficients would depend on pass band, stop band and other paramaters. |
You could create a generic one, then have clash produce entities for specialised instantiations. i.e. myGenericFilter :: <some type>
filterConfigA = myGenericFilter <specialize arguments>
filterConfigB = myGenericFilter <specialize arguments> if you add a Synthesize Annotation then Clash will generate different HDL files for the different specialised versions |
An example: -- some generic definition of an adder, polymorphic over number repr and width
adder :: forall (repr :: Nat -> Type) (width :: Nat). repr width -> repr width -> repr width
adder = -- some definition
{-# ANN unsigned4Adder (Synthesize { t_name = "unsigned_4_adder"
, t_inputs = [PortName "x", PortName "y"]
, t_output = PortName "r"
}) #-}
unsigned4Adder :: Unsigned 4 -> Unsigned 4 -> Unsigned 4
unsigned4Adder = adder would give you a VHDL module something similar to entity unsigned_4_adder is
port ( x, y : in std_logic_vector(3 downto 0);
r : out std_logic_vector(3 downto 0)
);
end unsigned_4_adder; (assuming I haven't made a mistake here) |
@postoroniy Do you need a general solution that will work once this issue #1648 is fixed? or a work-around until this issue #1648 is fixed? |
@alex-mckenna thanks for given examples, but I can't see how I can avoid to have different ANNs (not adding them at all) and rather to use a parameter from command line. |
@christiaanb I have workaround as I said, but I need the general and concrete solution for things I mentioned above :) |
Another option is to have the following directory structure:
and then have module MyCircuit where
import Coeffs
topEntity = g coeffs and have module Coeffs where
coefss = $(lift (f 4)) and have module Coeffs where
coefss = $(lift (f 8)) and then call Clash with:
to generate the hardware with the "X" set of coefficients, and output the HDL in the and do:
to generate the hardware with the "Y" set of coefficients, and output the HDL in the |
@christiaanb thanks, as I can see only extra file.. will think about it |
I know some people approach their Clash hardware designs with a two-phase compilation process. The first compilation generates .hs files and the second compilation uses both static and generated .hs files to generate the hardware. It's not precisely what you're looking for, but it does offer the option to just pass regular command line arguments to the first phase, which then alters the generated .hs files. |
@DigitalBrains1 |
Yes, design is a creative process, so some approaches click well with some, while other approaches click better with others. So it might be that nmigen works better for the creation of some hardware designs, and Clash works better on other hardware designs. With Clash, we allow the designer to use native Haskell features, such as e.g case-expressions, to describe the switching behavior of the circuit. With nmigen, you have to use its Now, the trade-off that we had to make for this is that in order to turn a Clash/Haskell description into HDL code is that we have to do a lot of static analysis. This makes it a lot harder to have the "shape" of a circuit depends on non-source inputs, e.g. data-files that you read from disks, or arguments from Again, I genuinely believe that there are designs where being able to use sum-of-product types, pattern matching, and other Haskell features natively in the behavior of your circuits make Clash "better" than other approaches. On the other hand, if you're not using any of those features, I can definitely see an EDSL approach, whether it's blarney or nmigen, being more productive. |
@christiaanb I didn't mean to blame clash and you guys, I've just noted that clash as such is not simple to use and has some solutions/workarounds which are neither obvious nor in tutorial/FAQ( is it true?). And may be "2 files" solution is better for my case. |
AFAIK |
@DigitalBrains1 thanks for your "the 2 file" solution :) |
@alex-mckenna yep that's what I found too, but I burnt too much time on it :), my fault...and just imagine to have this things/thoughts/recommendations in FAQ :))) |
@alex-mckenna module TestLib (
TestT(..)
,myConfig
,myConfigC
)where
import Prelude
import GHC.Generics
data TestT0 = TestT0{
p :: Integer,
q :: Integer
} deriving (Generic, Show, Eq, Ord)
data TestT = TestT{
testT0 :: TestT0,
coeff_list:: [[Integer]]
} deriving (Generic, Show, Eq, Ord)
myConfig:: Integer ->Integer-> TestT
myConfig i j = o
where
iT = TestT0 j (j+1)
o = TestT iT [[j+1,j+2],[j+30,j+40]]
myConfigC = myConfig 100 99 file test.hs @alex-mckenna sorry before here was wrong source and I had to fix it import TestLib
import Clash.Prelude
import qualified Data.List as L
topEntity:: Integer->Integer->Integer
topEntity i j = o
where
coeff_l = coeff_list(myConfigC)
coeff1 = coeff_l L.!!0
o = coeff1 L.!! 0 only tested on clashi
|
I am wondering how you are using the vector that you generate? If by any chance it is/could be used to initialize a ROM/RAM, maybe you could use the version of the primitive that uses a memory initialization file: https://hackage.haskell.org/package/clash-prelude-1.2.5/docs/Clash-Prelude-ROM-File.html#v:romFile If that is the case, you should be able to generate the file as a separate step using any language. This has the added benefit that you can re-generate the ROM file even after Clash compilation as the generated Verilog/VHDL references that file. |
@basile-henry Generated vector is in fact coefficients for FIR filter. |
It may not be a complete solution for your entire program, but this commit succeeds in building the MWE |
It does nothing for the not a tylam error, but if the commit works for your program I'll merge it and fix the other issue in a separate PR |
@alex-mckenna I don't see exception for given example :) and created verilog is what I'd expect to see |
If you need to be sure that the constants are fully inlined close to the DSPs this might not be the best approach. But just to comment on this:
That is possible with the approach I mentioned! {-# LANGUAGE DataKinds #-}
{-# LANGUAGE NoImplicitPrelude #-}
import Clash.Prelude
import Numeric
import qualified Prelude
import System.Environment
myRomPath :: FilePath
myRomPath = "my_rom.bin"
------------------------------
-- Runtime generation of ROM
main :: IO ()
main = do
x <- Prelude.read . Prelude.head <$> getArgs
listToFile myRomPath [ x * i | i <- [0..15] ]
listToFile :: FilePath -> [Unsigned 8] -> IO ()
listToFile path content = do
let binRepr x = showIntAtBase 2 (\b ->
case b of
0 -> '0'
1 -> '1'
)
x
""
contentString = unlines (fmap binRepr content)
Prelude.writeFile path contentString
------------------------------
-- Hardware description
topEntity :: Unsigned 4 -> Unsigned 8
topEntity = unpack . asyncRomFile d4 myRomPath Then you can generate the ROM with: runhaskell Example.hs 3 (where And generate Verilog with: clash -outputdir out --verilog Example.hs You can still simulate the top entity in plain Haskell, for example with ➜ clashi -e "topEntity 2" Example.hs
6 |
I think what we should learn from this (and probably most of us knew this already) is that Clash would really benefit from a lot more ("soft") documentation in the form of FAQs, HowTo's and "best" practices |
fixed on master at 70718d0 |
Reopening for now: this issue mentions some other things which should be done / have new issues made for:
|
clash hash 833ac34
Can't provide whole source.
but suspecting problem in usage clash.
I need to calculate filter coefficients( function is designed and works as expected in Haskell Prelude)
but attempt to use it I got exception below. Can you guys point me to right direction? how to calc coefficients in runtime and feed them into topEntity?
for :verilog option
for :vhdl option
The text was updated successfully, but these errors were encountered: