3

我想将时钟速率(以 Hz 为单位)作为术语级别的值访问,以便我可以在计数器中使用它。

到目前为止,我能够想出的一种方法是将类型级别的Domain 解压缩到其时钟周期(以 ps 为单位),然后将其转换为时钟速率。但是,这需要一个额外的KnownNat ps约束,然后会感染所有试图使用它的东西,一直到topLevel

clkPeriod :: forall dom gated name ps. (dom ~ Dom name ps, KnownNat ps) => Clock dom gated -> Integer
clkPeriod clk = natVal (Proxy :: Proxy ps)

clkRate :: (dom ~ Dom name ps, KnownNat ps) => Clock dom gated -> Integer
clkRate clk = 10^12 `div` clkPeriod clk

另一种避免引入额外KnownNat约束的方法是在 上导入Clash.Signal.Internal和模式匹配Clock,因为它包含SNat期间的见证:

import Clash.Signal.Internal (Clock(..))

clkPeriod :: Clock dom gated -> Integer
clkPeriod (Clock _ period) = snatToInteger period
clkPeriod (GatedClock _ period _) = snatToInteger period

clkRate :: Clock dom gated -> Integer
clkRate clk = 10^12 `div` clkPeriod clk

但这会使合成器崩溃(我猜我不应该导入Clash.Signal.Internal):

*** Exception: Clash.Rewrite.Util(566): 
Can't create selector ("Clash.Normalize.Transformations(1136):doPatBndr",1,0) for:
($dKnownNat23000 :: GHC.Natural.Natural)

Additional info: TyCon has no DataCons: 
Name {nameSort = User, nameOcc = GHC.Natural.Natural3674937295934324782, nameLoc = UnhelpfulSpan "<no location info>"} GHC.Natural.Natural3674937295934324782

这是一个展示此问题的完整模块(我尝试将其合成:vhdl以获得上述错误):

module Test where

import Clash.Prelude hiding (clkPeriod)
import Data.Word
import Clash.Signal.Internal (Clock(..))

type FromHz rate = 1000000000000 `Div` rate
type Dom25 = Dom "CLK_25MHZ" (FromHz 25175000)

topEntity
    :: Clock Dom25 Source
    -> Reset Dom25 Asynchronous
    -> Signal Dom25 Bit
topEntity = exposeClockReset board
  where
    board = boolToBit <$> r

    r = regEn False (counter .==. 0) (not <$> r)
    counter = register clkrt $ mux (counter .==. 0) (pure clkrt) (pred <$> counter)
    clkrt = fromIntegral $ hideClock clkRate

clkPeriod :: Clock dom gated -> Integer
clkPeriod (Clock _ period) = snatToInteger period
clkPeriod (GatedClock _ period _) = snatToInteger period

clkRate :: Clock dom gated -> Integer
clkRate clk = 10^12 `div` clkPeriod clk

我的问题是,有没有一种方法可以clkRate在不引入任何额外KnownNat约束或导入任何Internal模块的情况下在术语级别进行具体化?

4

2 回答 2

1

看起来这已被 Clash 主要开发人员 Christiaan Baaij 承认为Issue #348中的 Clash 编译器错误。引用他在该问题报告中的评论:

所以问题是我们得到的核心是对某种类型的模式匹配Integer并暴露其表示的内部;编译器显然无法处理的东西。我将创建一个解决方法/hack 以始终选择Integer适合 [-2^63 .. 2^63-1] 范围内的分支,因为 Clash 目前“错误地”转换Integer为 64 位数字。

于 2018-09-22T21:30:13.893 回答
0

使用 Clash 1.0.0,这可以在没有爬行KnownNat约束或不导入任何Internal模块的情况下完成。诀窍是用于knownDomain获取SDomainConfiguration给定时钟域的 ,它将包含SNat period单个时钟周期的长度(以皮秒为单位)。通过SNat构造函数上的模式匹配,KnownNat见证被引入范围。

clkPeriod :: forall dom. (KnownDomain dom) => Clock dom -> Integer
clkPeriod clk = case knownDomain @dom of
    SDomainConfiguration _ rate@SNat{} _ _ _ _ -> natVal rate

clkRate :: (KnownDomain dom) => Clock dom -> Integer
clkRate clk = 1_000_000_000_000 `div` clkPeriod clk

这是更新的顶级定义:

{-# LANGUAGE NumericUnderscores #-}
module Test where

import Clash.Prelude hiding (clkPeriod)
import Data.Word

createDomain vSystem{vName="Dom25", vPeriod = hzToPeriod 25_000_000}

topEntity
    :: Clock Dom25
    -> Reset Dom25
    -> Enable Dom25
    -> Signal Dom25 Bit
topEntity = exposeClockResetEnable board
  where
    board = boolToBit <$> r

    r = regEn False (counter .==. 0) (not <$> r)
    counter = register clkrt $ mux (counter .==. 0) (pure clkrt) (pred <$> counter)
    clkrt = fromInteger @Word32 $ hideClock clkRate

我已经测试过这适用于综合,并且将周期长度转换为时钟速率的除法是在编译时完成的。

于 2019-10-29T11:25:06.470 回答