Torii Backends

Warning

The Torii API reference is a work in progress and we are actively working on improving it, however it may be deficient or missing in places.

Torii has 3 primary backends, RTLIL, Verilog, and CXXRTL, each takes a Torii Fragment or Elaboratable and produces an RTL netlist in the given output format. There is also the JSON backend for generic netlist output.

The primary lingua franca of the Torii backends is RTLIL, the Verilog, CXXRTL, and JSON backends first convert the IR into it, and then use Yosys to convert the RTLIL netlist into their respective output formats

RTLIL Backend

torii.back.rtlil.convert_fragment(fragment: Fragment, name: str = 'top', *, emit_src: bool = True) tuple[str, SignalDict]

Recursively lower the given Torii Fragment into RTLIL text and a signal map.

Parameters:
  • fragment (torii.hdl.ir.Fragment) – The Torii fragment hierarchy to lower.

  • name (str) – The name of the root fragment module. (default: 'top')

  • emit_src (bool) – Emit source line attributes in the resulting RTLIL text. (default: True)

Returns:

The RTLIL text and signal dictionary of the lowered fragment.

Return type:

tuple[str, torii.hdl.ast.SignalDict]

torii.back.rtlil.convert(elaboratable, name: str = 'top', platform=None, *, ports, emit_src=True, missing_domain=<function <lambda>>) str

Convert the given Torii Elaboratable into RTLIL text.

Parameters:
  • elaboratable (torii.hdl.ir.Elaboratable) – The Elaboratable to lower into RTLIL.

  • name (str) – The name of the resulting RTLIL module. (default: 'top')

  • platform (torii.build.plat.Platform) – The platform to use for Elaboratable evaluation. (default: None)

  • ports (list[]) – The list of ports on the top-level module.

  • emit_src (bool) – Emit source line attributes in the final RTLIL text. (default: True)

Returns:

The resulting RTLIL.

Return type:

str

Verilog Backend

torii.back.verilog.convert_fragment(fragment: Fragment, name: str = 'top', emit_src: bool = True, strip_internal_attrs: bool = False) tuple[str, SignalDict]

Recursively lower the given Torii Fragment into Verilog text and a signal map.

Parameters:
  • fragment (torii.hdl.ir.Fragment) – The Torii fragment hierarchy to lower.

  • name (str) – The name of the root fragment module. (default: 'top')

  • emit_src (bool) – Emit source line attributes in the resulting Verilog text. (default: True)

  • strip_internal_attrs (bool) – Remove Torii-specific attributes that were emitted into the resulting Verilog text. (default: False)

Returns:

The Verilog text and signal dictionary of the lowered fragment.

Return type:

tuple[str, torii.hdl.ast.SignalDict]

torii.back.verilog.convert(elaboratable: ~torii.hdl.ir.Fragment | ~torii.hdl.ir.Elaboratable, name: str = 'top', platform=None, *, ports, emit_src: bool = True, strip_internal_attrs: bool = False, missing_domain=<function <lambda>>) str

Convert the given Torii Elaboratable into Verilog text.

Parameters:
  • elaboratable (torii.hdl.ir.Elaboratable) – The Elaboratable to lower into Verilog.

  • name (str) – The name of the resulting Verilog module. (default: 'top')

  • platform (torii.build.plat.Platform) – The platform to use for Elaboratable evaluation. (default: None)

  • ports (list[]) – The list of ports on the top-level module.

  • emit_src (bool) – Emit source line attributes in the final Verilog text. (default: True)

  • strip_internal_attrs (bool) – Remove Torii-specific attributes that were emitted into the resulting Verilog text. (default: False)

Returns:

The resulting Verilog.

Return type:

str

CXXRTL Backend

torii.back.cxxrtl.convert_fragment(fragment: Fragment, name: str = 'top', emit_src: bool = True, black_boxes: dict[str, str] | None = None) tuple[str, SignalDict]

Recursively lower the given Torii Fragment into CXXRTL text and a signal map.

Parameters:
  • fragment (torii.hdl.ir.Fragment) – The Torii fragment hierarchy to lower.

  • name (str) – The name of the root fragment module. (default: 'top')

  • emit_src (bool) – Emit source line attributes in the resulting CXXRTL text. (default: True)

  • black_boxes (dict[str, str]) – A map of CXXRTL blackboxes to use in the resulting design. (default: None)

Returns:

The CXXRTL text and signal dictionary of the lowered fragment.

Return type:

tuple[str, torii.hdl.ast.SignalDict]

torii.back.cxxrtl.convert(elaboratable: ~torii.hdl.ir.Elaboratable, name: str = 'top', platform=None, black_boxes: dict[str, str] | None = None, *, ports, emit_src: bool = True, missing_domain=<function <lambda>>) str

Convert the given Torii Elaboratable into CXXRTL text.

Parameters:
  • elaboratable (torii.hdl.ir.Elaboratable) – The Elaboratable to lower into Verilog.

  • name (str) – The name of the resulting Verilog module. (default: 'top')

  • platform (torii.build.plat.Platform) – The platform to use for Elaboratable evaluation. (default: None)

  • ports (list[]) – The list of ports on the top-level module.

  • emit_src (bool) – Emit source line attributes in the final CXXRTL text. (default: True)

  • black_boxes (dict[str, str]) – A map of CXXRTL blackboxes to use in the resulting design. (default: None)

Returns:

The resulting CXXRTL.

Return type:

str

JSON Backend

torii.back.json.convert_fragment(fragment: Fragment, name: str = 'top', emit_src: bool = True) tuple[str, SignalDict]

Recursively lower the given Torii Fragment into a JSON netlist and a signal map.

Parameters:
  • fragment (torii.hdl.ir.Fragment) – The Torii fragment hierarchy to lower.

  • name (str) – The name of the root fragment module. (default: 'top')

  • emit_src (bool) – Emit source line attributes in the resulting JSON. (default: True)

Returns:

The JSON netlist and signal dictionary of the lowered fragment.

Return type:

tuple[str, torii.hdl.ast.SignalDict]

torii.back.json.convert(elaboratable: ~torii.hdl.ir.Fragment | ~torii.hdl.ir.Elaboratable, name: str = 'top', platform=None, *, ports, emit_src: bool = True, strip_internal_attrs: bool = False, missing_domain=<function <lambda>>) str

Convert the given Torii Elaboratable into a JSON netlist.

Parameters:
  • elaboratable (torii.hdl.ir.Elaboratable) – The Elaboratable to write the JSON netlist for.

  • name (str) – The name of the resulting JSON netlist. (default: 'top')

  • platform (torii.build.plat.Platform) – The platform to use for Elaboratable evaluation. (default: None)

  • ports (list[]) – The list of ports on the top-level module.

  • emit_src (bool) – Emit source line attributes in the final JSON netlist. (default: True)

Returns:

The resulting JSON netlist.

Return type:

str

Example

Lets say you have the following Torii design:

class Blinky(Elaboratable):
    def elaborate(self, platform) -> Module:
        led   = Signal()
        timer = Signal(20)

        m = Module()
        m.d.sync += timer.eq(timer + 1)
        m.d.comb += led.eq(timer[-1])
        return m

To convert it to the wanted format, call convert from the wanted backend and pass in the instance of the elaboratable.

1from torii.back.verilog import convert
2
3verilog = convert(Blinky(), name = 'blinker', ports = [])

Will result in:

 1(* top =  1  *)
 2(* generator = "Torii 0.8.0" *)
 3module blinker(rst, clk);
 4  reg \$auto$verilog_backend.cc:2373:dump_module$1  = 0;
 5  (* src = "<python-input-0>:9" *)
 6  wire [20:0] \$1 ;
 7  (* src = "<python-input-0>:9" *)
 8  wire [20:0] \$2 ;
 9  (* src = "torii/back/verilog.py:77" *)
10  input clk;
11  wire clk;
12  (* src = "<python-input-0>:5" *)
13  wire led;
14  (* src = "torii/back/verilog.py:77" *)
15  input rst;
16  wire rst;
17  (* src = "<python-input-0>:6" *)
18  reg [19:0] timer = 20'h00000;
19  (* src = "<python-input-0>:6" *)
20  reg [19:0] \timer$next ;
21  assign \$2  = timer + (* src = "<python-input-0>:9" *) 1'h1;
22  always @(posedge clk)
23    timer <= \timer$next ;
24  always @* begin
25    if (\$auto$verilog_backend.cc:2373:dump_module$1 ) begin end
26    \timer$next  = \$2 [19:0];
27    (* src = "torii/hdl/xfrm.py:556" *)
28    if (rst) begin
29      \timer$next  = 20'h00000;
30    end
31  end
32  assign \$1  = \$2 ;
33  assign led = timer[19];
34endmodule
1from torii.back.cxxrtl import convert
2
3cxxrtl = convert(Blinky(), name = 'blinker', ports = [])

Will result in:

  1#include <cxxrtl/cxxrtl.h>
  2
  3#if defined(CXXRTL_INCLUDE_CAPI_IMPL) || \
  4    defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)
  5#include <cxxrtl/capi/cxxrtl_capi.cc>
  6#endif
  7
  8#if defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)
  9#include <cxxrtl/capi/cxxrtl_capi_vcd.cc>
 10#endif
 11
 12using namespace cxxrtl_yosys;
 13
 14namespace cxxrtl_design {
 15
 16// \top: 1
 17// \generator: Torii 0.8.0
 18struct p_blinker : public module {
 19        // \src: <python-input-0>:6
 20        // \init: 0
 21        wire<20> p_timer;
 22        // \src: torii/back/cxxrtl.py:68
 23        /*input*/ value<1> p_rst;
 24        // \src: torii/back/cxxrtl.py:68
 25        /*input*/ value<1> p_clk;
 26        value<1> prev_p_clk;
 27        bool posedge_p_clk() const {
 28                return !prev_p_clk.slice<0>().val() && p_clk.slice<0>().val();
 29        }
 30        // \src: <python-input-0>:5
 31        /*outline*/ value<1> p_led;
 32        // \src: <python-input-0>:6
 33        /*outline*/ value<20> p_timer_24_next;
 34        p_blinker(interior) {}
 35        p_blinker() {
 36                reset();
 37        };
 38
 39        void reset() override;
 40
 41        bool eval(performer *performer = nullptr) override;
 42
 43        template<class ObserverT>
 44        bool commit(ObserverT &observer) {
 45                bool changed = false;
 46                if (p_timer.commit(observer)) changed = true;
 47                prev_p_clk = p_clk;
 48                return changed;
 49        }
 50
 51        bool commit() override {
 52                observer observer;
 53                return commit<>(observer);
 54        }
 55
 56        void debug_eval();
 57        debug_outline debug_eval_outline { std::bind(&p_blinker::debug_eval, this) };
 58
 59        void debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs = {}) override;
 60}; // struct p_blinker
 61
 62void p_blinker::reset() {
 63        p_timer = wire<20>{0u};
 64}
 65
 66bool p_blinker::eval(performer *performer) {
 67        bool converged = true;
 68        bool posedge_p_clk = this->posedge_p_clk();
 69        // cells $4 $procmux$1 $3
 70        if (posedge_p_clk) {
 71                p_timer.next = (p_rst ? value<20>{0u} : add_uu<21>(p_timer.curr, value<1>{0x1u}).slice<19,0>().val());
 72        }
 73        return converged;
 74}
 75
 76void p_blinker::debug_eval() {
 77        // cells $procmux$1 $3
 78        p_timer_24_next = (p_rst ? value<20>{0u} : add_uu<21>(p_timer.curr, value<1>{0x1u}).slice<19,0>().val());
 79        // connection
 80        p_led = p_timer.curr.slice<19>().val();
 81}
 82
 83CXXRTL_EXTREMELY_COLD
 84void p_blinker::debug_info(debug_items *items, debug_scopes *scopes, std::string path, metadata_map &&cell_attrs) {
 85        assert(path.empty() || path[path.size() - 1] == ' ');
 86        if (scopes) {
 87                scopes->add(path.empty() ? path : path.substr(0, path.size() - 1), "blinker", metadata_map({
 88                        { "top", UINT64_C(1) },
 89                        { "generator", "Torii 0.8.0" },
 90                }), std::move(cell_attrs));
 91        }
 92        if (items) {
 93                items->add(path, "led", "src\000s<python-input-0>:5\000", debug_eval_outline, p_led);
 94                items->add(path, "timer$next", "src\000s<python-input-0>:6\000", debug_eval_outline, p_timer_24_next);
 95                items->add(path, "timer", "src\000s<python-input-0>:6\000init\000u\000\000\000\000\000\000\000\000", p_timer, 0, debug_item::DRIVEN_SYNC);
 96                items->add(path, "rst", "src\000s/torii/back/cxxrtl.py:68\000", p_rst, 0, debug_item::INPUT|debug_item::UNDRIVEN);
 97                items->add(path, "clk", "src\000s/torii/back/cxxrtl.py:68\000", p_clk, 0, debug_item::INPUT|debug_item::UNDRIVEN);
 98        }
 99}
100
101} // namespace cxxrtl_design
102
103extern "C"
104cxxrtl_toplevel cxxrtl_design_create() {
105        return new _cxxrtl_toplevel { std::unique_ptr<cxxrtl_design::p_blinker>(new cxxrtl_design::p_blinker) };
106}
1from torii.back.json import convert
2
3json = convert(Blinky(), name = 'blinker', ports = [])

Will result in:

  1{
  2  "creator": "Yosys 0.55",
  3  "modules": {
  4    "blinker": {
  5      "attributes": {
  6        "top": "00000000000000000000000000000001",
  7        "generator": "Torii 0.8.0"
  8      },
  9      "ports": {
 10        "rst": {
 11          "direction": "input",
 12          "bits": [ 2 ]
 13        },
 14        "clk": {
 15          "direction": "input",
 16          "bits": [ 3 ]
 17        }
 18      },
 19      "cells": {
 20        "$3": {
 21          "hide_name": 1,
 22          "type": "$add",
 23          "parameters": {
 24            "A_SIGNED": "00000000000000000000000000000000",
 25            "A_WIDTH": "00000000000000000000000000010100",
 26            "B_SIGNED": "00000000000000000000000000000000",
 27            "B_WIDTH": "00000000000000000000000000000001",
 28            "Y_WIDTH": "00000000000000000000000000010101"
 29          },
 30          "attributes": {
 31            "src": "<python-input-0>:9"
 32          },
 33          "port_directions": {
 34            "A": "input",
 35            "B": "input",
 36            "Y": "output"
 37          },
 38          "connections": {
 39            "A": [ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 ],
 40            "B": [ "1" ],
 41            "Y": [ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44 ]
 42          }
 43        },
 44        "$4": {
 45          "hide_name": 1,
 46          "type": "$dff",
 47          "parameters": {
 48            "CLK_POLARITY": "00000000000000000000000000000001",
 49            "WIDTH": "00000000000000000000000000010100"
 50          },
 51          "attributes": {
 52          },
 53          "port_directions": {
 54            "CLK": "input",
 55            "D": "input",
 56            "Q": "output"
 57          },
 58          "connections": {
 59            "CLK": [ 3 ],
 60            "D": [ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64 ],
 61            "Q": [ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 ]
 62          }
 63        },
 64        "$procmux$1": {
 65          "hide_name": 1,
 66          "type": "$mux",
 67          "parameters": {
 68            "WIDTH": "00000000000000000000000000010100"
 69          },
 70          "attributes": {
 71            "src": "torii/hdl/xfrm.py:556"
 72          },
 73          "port_directions": {
 74            "A": "input",
 75            "B": "input",
 76            "S": "input",
 77            "Y": "output"
 78          },
 79          "connections": {
 80            "A": [ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43 ],
 81            "B": [ "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" ],
 82            "S": [ 2 ],
 83            "Y": [ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64 ]
 84          }
 85        }
 86      },
 87      "netnames": {
 88        "$1": {
 89          "hide_name": 1,
 90          "bits": [ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44 ],
 91          "attributes": {
 92            "src": "<python-input-0>:9"
 93          }
 94        },
 95        "$2": {
 96          "hide_name": 1,
 97          "bits": [ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44 ],
 98          "attributes": {
 99            "src": "<python-input-0>:9"
100          }
101        },
102        "$procmux$1_Y": {
103          "hide_name": 1,
104          "bits": [ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64 ],
105          "attributes": {
106          }
107        },
108        "$procmux$2_CMP": {
109          "hide_name": 1,
110          "bits": [ 2 ],
111          "attributes": {
112          }
113        },
114        "clk": {
115          "hide_name": 0,
116          "bits": [ 3 ],
117          "attributes": {
118            "src": "torii/back/json.py:55"
119          }
120        },
121        "led": {
122          "hide_name": 0,
123          "bits": [ 23 ],
124          "attributes": {
125            "src": "<python-input-0>:5"
126          }
127        },
128        "rst": {
129          "hide_name": 0,
130          "bits": [ 2 ],
131          "attributes": {
132            "src": "torii/back/json.py:55"
133          }
134        },
135        "timer": {
136          "hide_name": 0,
137          "bits": [ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 ],
138          "attributes": {
139            "init": "00000000000000000000",
140            "src": "<python-input-0>:6"
141          }
142        },
143        "timer$next": {
144          "hide_name": 0,
145          "bits": [ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64 ],
146          "attributes": {
147            "src": "<python-input-0>:6"
148          }
149        }
150      }
151    }
152  }
153}