# Using Blackbox to instantiate some HDL

**URL:** <https://clash-lang.discourse.group/t/using-blackbox-to-instantiate-some-hdl/52>\
**Category:** Clash Help\
**Created:** [November 13, 2024, 7:23pm UTC](https://clash-lang.discourse.group/t/using-blackbox-to-instantiate-some-hdl/52 "2024-11-13T19:23:30Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![zebrasecret](https://avatars.discourse-cdn.com/v4/letter/z/ecae2f/32.png) [@zebrasecret](https://clash-lang.discourse.group/u/zebrasecret)\
**Post date:** [November 13, 2024, 7:23pm UTC](https://clash-lang.discourse.group/t/using-blackbox-to-instantiate-some-hdl/52/1 "2024-11-13T19:23:30Z")

</div>

I’m trying to use `BlackBox`, but I’m having a hard time getting things to work  
in the way I want.

What I wanna do is have the Clash generated Verilog instantiate into my  
BlackBox’d Verilog module.

First, my verilog file. I checked that this compiles / has valid syntax using  
Verilator. Didn’t really check to see if it works:

```verilog
module counter(input CLK, input RST, input EN, output [15:0] DATA);

reg [15:0] iDATA;
initial iDATA = 0;

assign DATA = iDATA;

always @(posedge CLK)
  begin
    if (RST) 
      iDATA <= 0;
    else if (EN)
      begin
        iDATA <= iDATA + 1;
      end
  end

endmodule

```

Next, my clash file:

```haskell
import Clash.Prelude
import Clash.Annotations.Primitive

{-# ANN counter (Primitive [Verilog] "C:/path/to/my/verilog/counter.v") #-}
{-# ANN counter hasBlackBox #-}
{-# NOINLINE counter #-}
counter :: Clock System
        -> Reset System
        -> Enable System
        -> Signal System (Unsigned 16)
counter = undefined

top :: Clock System
    -> Reset System
    -> Enable System
    -> Signal System (Unsigned 16)
top = counter

{-# ANN top 
   (Synthesize
    { t_name = "myCounter"
    , t_inputs = [ PortName "CLK"
                 , PortName "RST"
                 , PortName "EN"
                 ]
    , t_output = PortName "DATA"
    }) #-}

```

When I call clash, I get an error:

```bash
GHC: Setting up GHC took: 2.285s
GHC: Compiling and loading modules took: 0.192s

<no location info>: error:
    Clash error call:
    No BlackBox definition for '<MODULE>.counter' even though thi
s value was annotated with 'HasBlackBox'.
    CallStack (from HasCallStack):
      error, called at src\Clash\Primitives\Util.hs:150:11 in clash-lib-1.8.1-
JBnXUEN9hOK2TSlskJFs4:Clash.Primitives.Util

```

If I remove the `hasBlackBox` annotation, clash generates Verilog. But the  
Verilog doesn’t do what I expect.

```verilog
/* AUTOMATICALLY GENERATED VERILOG-2001 SOURCE CODE.
** GENERATED BY CLASH 1.8.1. DO NOT MODIFY.
*/
`default_nettype none
`timescale 100fs/100fs
module myCounter
    ( // Inputs
      input wire CLK // clock
    , input wire RST // reset
    , input wire EN // enable

      // Outputs
    , output wire [15:0] DATA
    );

  <MODULE>_top_counter <MODULE>_top_counter_DATA
    ( .result (DATA)
    , .c$arg (CLK)
    , .c$arg_0 (RST)
    , .c$arg_1 (EN) );

endmodule

```

I’d like the generated verilog to be:

```verilog
module myCounter
    ( // Inputs
      input wire CLK // clock
    , input wire RST // reset
    , input wire EN // enable

      // Outputs
    , output wire [15:0] DATA
    );

  counter <MODULE>_top_counter_DATA
    ( .DATA (DATA)
    , .CLK (CLK)
    , .RST (RST)
    , .EN (EN) );

endmodule

```

Any ideas? My guess is that I’m not providing the path to BlackBox in the right  
way.

---

<div class="post-metadata">

**Author:** ![lmbollen](https://yyz2.discourse-cdn.com/free1/user_avatar/clash-lang.discourse.group/lmbollen/32/10_2.png) [@lmbollen](https://clash-lang.discourse.group/u/lmbollen)\
**Post date:** [November 14, 2024, 10:03am UTC](https://clash-lang.discourse.group/t/using-blackbox-to-instantiate-some-hdl/52/2 "2024-11-14T10:03:32Z")

</div>

As you can tell from the generated verilog that you want, you don’t need to provide the path to your module in Clash since it would not end up in the HDL.

There’s multiple ways that you can solve this problem. The first one is writing your own blackbox instantiation template, the second method is using the currently experimental `inst` function.

**Using the experimental inst function**  
Creating instances is pretty straightforward and have an experimental feature to create instances. We’ll probably move it later, but on our master branch you can find it under  
[Clash.Cores.Xilinx.Xpm.Cdc.Internal](https://github.com/clash-lang/clash-compiler/blob/master/clash-cores/src/Clash/Cores/Xilinx/Xpm/Cdc/Internal.hs#L345-L369).

This allows you to write the blackbox as follows:

```auto
module Example where

import Clash.Prelude
import Clash.Cores.Xilinx.Xpm.Cdc.Internal

counter :: Clock System
        -> Reset System
        -> Enable System
        -> Signal System (Unsigned 16)
counter clk rst ena = unPort @(Port "DATA" System (Unsigned 16)) $
  inst
    (instConfig "counter")
      (ClockPort @"CLK" clk)
      (ResetPort @"RST" @'ActiveHigh rst)
      (Port @"ENA" $ fromEnable ena)

-- Create your top entity
top :: Clock System
    -> Reset System
    -> Enable System
    -> Signal System (Unsigned 16)
top = counter

{-# ANN top
   (Synthesize
    { t_name = "myCounter"
    , t_inputs = [ PortName "CLK"
                 , PortName "RST"
                 , PortName "EN"
                 ]
    , t_output = PortName "DATA"
    }) #-}

```

There are some more examples to be found across our [clash-compiler](https://github.com/clash-lang/clash-compiler) repository and the [bittide-hardware](https://github.com/bittide/bittide-hardware) repository, but I’ll leave it up to you to find them 🙂

Like I said, this feature is still experimental but I much prefer it over the alternative.

**Creating a custom blackbox template**  
The recommended method of creating your own static blackboxes is using the [InlineYamlPrimitive](https://hackage.haskell.org/package/clash-prelude-1.8.1/docs/Clash-Annotations-Primitive.html#v:InlineYamlPrimitive). You can use this to write a template for the HDL you want to be inserted in your design.

For your counter, I’d write:

```auto
module Example where

import Clash.Prelude
import Clash.Annotations.Primitive
import Data.String.Interpolate

counter :: Clock System
        -> Reset System
        -> Enable System
        -> Signal System (Unsigned 16)
counter !_clock !_reset !_enable = deepErrorX "counter: simulation output undefined"
-- ^ This exclamation mark is a bang pattern

-- Prevent compiler optimizations to affect our counter function
{-# OPAQUE counter #-}

-- Create a Verilog and Systemverilog primitive for the counter function
{-# ANN counter (
    let
      funcName = 'counter -- Get the name of the counter function as a string
    in
      InlineYamlPrimitive [Verilog, SystemVerilog]
        [__i|
          BlackBox:
            kind: Declaration
            name: #{funcName}
            template: |
              counter ~GENSYM[counter][0] // Generate a unique name "counter" with index 0
                ( .DATA (~RESULT) // Connect the DATA output to the RESULT of counter
                , .CLK (~ARG[0]) // Connect the CLK input to the first argument of counter
                , .RST (~ARG[1]) // Connect the RST input to the second argument of counter
                , .EN (~ARG[2]) // Connect the EN input to the third argument of counter
                );
        |]) #-}

-- Create your top entity
top :: Clock System
    -> Reset System
    -> Enable System
    -> Signal System (Unsigned 16)
top = counter

{-# ANN top
   (Synthesize
    { t_name = "myCounter"
    , t_inputs = [ PortName "CLK"
                 , PortName "RST"
                 , PortName "EN"
                 ]
    , t_output = PortName "DATA"
    }) #-}

```

For a more extensive overview of how to use the templating language, see [Clash.Tutorial](https://hackage.haskell.org/package/clash-prelude-1.8.1/docs/Clash-Tutorial.html#g:14).  
\* The indices of  
\* [BangPatterns](https://downloads.haskell.org/ghc/7.8.3/docs/html/users_guide/bang-patterns.html) Force GHC to evaluate an argument, making sure that whatever is driving it ends up in the HDL.

**EDIT: Adjusted template comment style to match verilog**

---

<div class="post-metadata">

**Author:** ![zebrasecret](https://avatars.discourse-cdn.com/v4/letter/z/ecae2f/32.png) [@zebrasecret](https://clash-lang.discourse.group/u/zebrasecret)\
**Post date:** [November 14, 2024, 5:32pm UTC](https://clash-lang.discourse.group/t/using-blackbox-to-instantiate-some-hdl/52/3 "2024-11-14T17:32:06Z")

</div>

Thank you so much @Imbollen! I am very interested in the `inst` functionality,  
I’ll have to play with that later.

The BlackBox code you provided works, with some surprising effects I’d love to  
talk about.

Firstly, the generated Verilog:

```verilog
/* AUTOMATICALLY GENERATED VERILOG-2001 SOURCE CODE.
** GENERATED BY CLASH 1.8.1. DO NOT MODIFY.
*/
`default_nettype none
`timescale 100fs/100fs
module myCounter
    ( // Inputs
      input wire CLK // clock
    , input wire RST // reset
    , input wire EN // enable

      // Outputs
    , output wire [15:0] DATA
    );

  counter counter -- Generate a unique name "counter" with index 0
    ( .DATA (DATA) -- Connect the DATA output to the RESULT of counter
    , .CLK (CLK) -- Connect the CLK input to the first argument of counter
    , .RST (RST) -- Connect the RST input to the second argument of counter
    , .EN (EN) -- Connect the EN input to the third argument of counter
    );

endmodule

```

I was really surprised to see the Haskell comments in the Verilog, but that’s not  
too big a deal.

Quick update to the Annotation, which updates the comments to be `//`:

```haskell
{-# ANN counter (
    let
      funcName = 'counter -- Get the name of the counter function as a string
    in
      InlineYamlPrimitive [Verilog, SystemVerilog]
        [__i|
          BlackBox:
            kind: Declaration
            name: #{funcName}
            template: |
              counter ~GENSYM[counter][0] // Generate a unique name "counter" with index 0
                ( .DATA (~RESULT) // Connect the DATA output to the RESULT of counter
                , .CLK (~ARG[0]) // Connect the CLK input to the first argument of counter
                , .RST (~ARG[1]) // Connect the RST input to the second argument of counter
                , .EN (~ARG[2]) // Connect the EN input to the third argument of counter
                );
        |]) #-}

```

Quick notes on the _magic_ from the [Clash.Tutorial](https://hackage.haskell.org/package/clash-prelude-1.8.1/docs/Clash-Tutorial.html#g:14):

- `~ARG[N]`: (N+1)'th argument to the function.
- `~GENSYM[<NAME>][N]`: Create a unique name, trying to stay as close to the given as possible. This unique symbol can be referred to in other places using `~SYM[N]`.
- `~RESULT`: Signal to which the result of a primitive must be assigned to. NB: Only used in a declaration primitive.

I really like the flexibility here - we can change function parameters from  
Haskell into Verilog parameters:

```haskell
counter :: Clock System
        -> Reset System
        -> Enable System
        -> Unsigned 16 
        -> Signal System (Unsigned 16)
counter !_clk !_rst !_en !_thresh = deepErrorX "TODO: Define counter simulation output"

```

Update to Blackbox:

```haskell
...
            template: |
                counter \#(.THRESHOLD (~ARG[3])) ~GENSYM[counter][0] // Generate a unique name "counter" with index 0
...

```

Update to `top`:

```haskell
top clk rst en = counter clk rst en 10 + counter clk rst en 12

```

Which generates the following Verilog:

```verilog
/* AUTOMATICALLY GENERATED VERILOG-2001 SOURCE CODE.
** GENERATED BY CLASH 1.8.1. DO NOT MODIFY.
*/
`default_nettype none
`timescale 100fs/100fs
module myCounter
    ( // Inputs
      input wire CLK // clock
    , input wire RST // reset
    , input wire EN // enable

      // Outputs
    , output wire [15:0] DATA
    );
  wire [15:0] c$app_arg;
  wire [15:0] c$app_arg_0;

  counter #(.THRESHOLD (16'd12)) counter // Generate a unique name "counter" with index 0
  ( .DATA (c$app_arg) // Connect the DATA output to the RESULT of counter
  , .CLK (CLK) // Connect the CLK input to the first argument of counter
  , .RST (RST) // Connect the RST input to the second argument of counter
  , .EN (EN) // Connect the EN input to the third argument of counter
  );

  counter #(.THRESHOLD (16'd10)) counter_0 // Generate a unique name "counter" with index 0
  ( .DATA (c$app_arg_0) // Connect the DATA output to the RESULT of counter
  , .CLK (CLK) // Connect the CLK input to the first argument of counter
  , .RST (RST) // Connect the RST input to the second argument of counter
  , .EN (EN) // Connect the EN input to the third argument of counter
  );

  assign DATA = c$app_arg_0 + c$app_arg;

endmodule

```

So so cool!

---

<div class="post-metadata">

**Author:** ![lmbollen](https://yyz2.discourse-cdn.com/free1/user_avatar/clash-lang.discourse.group/lmbollen/32/10_2.png) [@lmbollen](https://clash-lang.discourse.group/u/lmbollen)\
**Post date:** [November 15, 2024, 9:49am UTC](https://clash-lang.discourse.group/t/using-blackbox-to-instantiate-some-hdl/52/4 "2024-11-15T09:49:03Z")

</div>

Aahh the comment style is an oversight on my part. Thanks for pointing that out!
