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:
- Returns:
The RTLIL text and signal dictionary of the lowered fragment.
- Return type:
- 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:
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:
- 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:
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:
- 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:
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:
- Returns:
The JSON netlist and signal dictionary of the lowered fragment.
- Return type:
- 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:
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}