exposEnable

33 views
Skip to first unread message

Chen-Mou Cheng

unread,
Apr 26, 2021, 6:14:51 AM4/26/21
to Clash - Hardware Description Language
Hi,

I am trying to control the enable signal going into a block RAM.  The following does not seem to work:
```
topEntity = exposeClockResetEnable $ \rden addr -> let
    bram = blockRamPow2 (repeat 0 :: Vec 1024 (Unsigned 32))
    dout = exposeEnable bram (toEnable $ rden .&&. fromEnable enableGen) addr (pure Nothing)
    in dout
```
Examining the output, it seems that rden (eta in the generated verilog) is not routed into the block RAM at all:
```
module topEntity
    ( // Inputs
      input clk // clock
    , input rst // reset
    , input en // enable
    , input eta
    , input [9:0] eta1
    .
    .
    .
  always @(posedge clk) begin : result_blockRam
    if (1'b0 & en) begin
      result_RAM[(result_res)] <= ({32 {1'bx}});
    end
    if (en) begin
      result <= result_RAM[(wild)];
    end
  end
```

However, if I just move exposeEnable around, then I can get rden (eta) routed into the block RAM:
```
topEntity = exposeClockResetEnable $ \rden addr -> let
    bram = exposeEnable $ blockRamPow2 (repeat 0 :: Vec 1024 (Unsigned 32))
    dout = bram (toEnable $ rden .&&. fromEnable enableGen) addr (pure Nothing)
    in dout
```
which synthesizes to:
```
  always @(posedge clk) begin : result_blockRam
    if (1'b0 & eta) begin
      result_RAM[(result_res)] <= ({32 {1'bx}});
    end
    if (eta) begin
      result <= result_RAM[(wild)];
    end
  end
```

Though not exactly what I expect, it's getting closer.  What is the right way to achieve my goal?  Any comments or suggestions would be greatly appreciated.

All the Best,
Chen-Mou Cheng

Christiaan Baaij

unread,
Apr 26, 2021, 8:01:08 AM4/26/21
to clash-l...@googlegroups.com
The "problem" is that the outer `exposeClockResetEnable` already binds/captures the hidden enable of `blockRamPow2` before the inner `exposeEnable` could capture any hidden enable of `bram`
One way to avoid that is to rewrite it like:

```
topEntity = exposeClockResetEnable $ \rden addr -> let
    dout = exposeEnable bram (toEnable $ rden .&&. fromEnable enableGen) addr (pure Nothing)
    in dout
  where
    bram rdAddr = blockRamPow2 (repeat 0 :: Vec 1024 (Unsigned 32)) rdAddr
```

that way the outer `exposeClockResetEnable`doesn't capture the hidden enable of `blockRamPow2` any longer.
Also, in this particular case, since the only hidden argument is a clock we could rewrite to:

```
topEntity = exposeClock $ \rden addr -> let

    dout = exposeEnable bram (toEnable $ rden .&&. fromEnable enableGen) addr (pure Nothing)
    in dout
  where
    bram rdAddr = blockRamPow2 (repeat 0 :: Vec 1024 (Unsigned 32)) rdAddr
```

Does that make sense?


--
You received this message because you are subscribed to the Google Groups "Clash - Hardware Description Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clash-languag...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/clash-language/476626e4-e230-4953-8712-3e415a03e0d9n%40googlegroups.com.

Peter Lebbing

unread,
Apr 26, 2021, 8:14:34 AM4/26/21
to clash-l...@googlegroups.com
On Mon, 26 Apr 2021, Christiaan Baaij wrote:
>     dout = exposeEnable bram (toEnable $ rden .&&. fromEnable enableGen) addr (pure Nothing)

Additionally, `enableGen` generates an always-on enable, so
`fromEnable enableGen` is synonymous to `pure True`.
`.&&.` is not very useful on a True value, so it can be shortened to:

    dout = exposeEnable bram (toEnable rden) addr (pure Nothing)

Peter.

Chen-Mou Cheng

unread,
Apr 26, 2021, 8:36:52 AM4/26/21
to clash-l...@googlegroups.com
Hi Peter & Christiaan,

Thank you very much for your prompt responses.  Please correct me if I am wrong, but you seem to be saying that exposeClockResetEnable f would recursively affect all blocks inside f whose clock, reset, and enable are hidden.  That could also explain why the following kind of works, as bram does have its enable signal exposed.
```
topEntity = exposeClockResetEnable $ \rden addr -> let
    bram = exposeEnable $ blockRamPow2 (repeat 0 :: Vec 1024 (Unsigned 32))
    dout = bram (toEnable $ rden .&&. fromEnable enableGen) addr (pure Nothing)
    in dout
```

All the Best,
Chen-Mou Cheng
--
You received this message because you are subscribed to the Google Groups "Clash - Hardware Description Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clash-languag...@googlegroups.com.

al...@qbaylogic.com

unread,
Apr 26, 2021, 9:22:47 AM4/26/21
to Clash - Hardware Description Language
Hi Chen-Mou Cheng,

This seems to be a case of Haskell's monomorphism restriction at work. In this example, it means that the type of `bram` is monomorphised over the domain `System`, instead of being the a type variable `dom` as in it's type signature. That means the call to `exposeClockResetEnable` captures/solves this hidden enable too. If you disable the monomorphism restriction by adding

```haskell
{-# LANGUAGE NoMonomorphismRestriction #-}
```

to the start of the Haskell source, or eta-expand the definition of `bram` to be

```haskell
bram a = blockRamPow2 (repeat 0 :: Vec 1024 (Unsigned 32)) a
```

then this should hopefully work as expected. This is because the hidden enable in `bram` will instead be captured by the call to `exposeEnable`.

Depending on your goal, you may find it easier to write some functions with explicit clocks / resets / enables and then hide them to provide a `HiddenX` API. The clash standard library has functions to help with this (e.g. hideClockResetEnable) which is how a lot of the non-explicit parts of the API are defined, e.g.

```haskell
blockRamPow2 = \cnt rd wrM -> hideEnable (hideClock E.blockRamPow2) cnt rd wrM
```

where `E.blockRamPow2` is the version of the function in `Clash.Explicit.BlockRam`.

Hope that helps,

  - Alex

Chen-Mou Cheng

unread,
Apr 26, 2021, 9:11:02 PM4/26/21
to clash-l...@googlegroups.com
Hi Alex,

Thank you very much for your insights.  Indeed I am happy to report that the two examples given at the beginning of this email thread synthesize to identical verilog with monomorphism restriction disabled.

All the Best,
Chen-Mou Cheng
Reply all
Reply to author
Forward
0 new messages