18
18
*/
19
19
#include " kernel/yosys.h"
20
20
#include " kernel/celltypes.h"
21
+ #include " kernel/sigtools.h"
21
22
#include " backends/rtlil/rtlil_backend.h"
22
23
23
24
USING_YOSYS_NAMESPACE
24
25
PRIVATE_NAMESPACE_BEGIN
25
26
26
- std::optional<std::string> format (std::string fmt, const dict<IdString, Const> ¶meters)
27
+ bool has_fmt_field (std::string fmt, std::string field_name)
28
+ {
29
+ auto it = fmt.begin ();
30
+ while (it != fmt.end ()) {
31
+ if (*it == ' {' ) {
32
+ it++;
33
+ auto beg = it;
34
+ while (it != fmt.end () && *it != ' }' ) it++;
35
+ if (it == fmt.end ())
36
+ return false ;
37
+
38
+ if (std::string (beg, it) == field_name)
39
+ return true ;
40
+ }
41
+ it++;
42
+ }
43
+ return false ;
44
+ }
45
+
46
+ struct ContextData {
47
+ std::string unused_outputs;
48
+ };
49
+
50
+ std::optional<std::string> format (std::string fmt, const dict<IdString, Const> ¶meters,
51
+ const ContextData &context)
27
52
{
28
53
std::stringstream result;
29
54
@@ -38,13 +63,19 @@ std::optional<std::string> format(std::string fmt, const dict<IdString, Const> &
38
63
return {};
39
64
}
40
65
41
- auto id = RTLIL::escape_id (std::string (beg, it));
42
- if (!parameters.count (id)) {
43
- log (" Parameter %s referenced in format string '%s' not found\n " , log_id (id), fmt.c_str ());
44
- return {};
45
- }
66
+ std::string param_name = {beg, it};
46
67
47
- RTLIL_BACKEND::dump_const (result, parameters.at (id));
68
+ if (param_name == " %unused" ) {
69
+ result << context.unused_outputs ;
70
+ } else {
71
+ auto id = RTLIL::escape_id (std::string (beg, it));
72
+ if (!parameters.count (id)) {
73
+ log (" Parameter %s referenced in format string '%s' not found\n " , log_id (id), fmt.c_str ());
74
+ return {};
75
+ }
76
+
77
+ RTLIL_BACKEND::dump_const (result, parameters.at (id));
78
+ }
48
79
} else {
49
80
result << *it;
50
81
}
@@ -54,6 +85,45 @@ std::optional<std::string> format(std::string fmt, const dict<IdString, Const> &
54
85
return {result.str ()};
55
86
}
56
87
88
+ struct Chunk {
89
+ IdString port;
90
+ int base, len;
91
+
92
+ Chunk (IdString id, int base, int len)
93
+ : port(id), base(base), len(len) {}
94
+
95
+ IdString format (Cell *cell)
96
+ {
97
+ if (len == cell->getPort (port).size ())
98
+ return port;
99
+ else if (len == 1 )
100
+ return stringf (" %s[%d]" , port.c_str (), base);
101
+ else
102
+ return stringf (" %s[%d:%d]" , port.c_str (), base + len - 1 , base);
103
+ }
104
+
105
+ SigSpec sample (Cell *cell)
106
+ {
107
+ return cell->getPort (port).extract (base, len);
108
+ }
109
+ };
110
+
111
+ // Joins contiguous runs of bits into a 'Chunk'
112
+ std::vector<Chunk> collect_chunks (std::vector<std::pair<IdString, int >> bits)
113
+ {
114
+ std::vector<Chunk> ret;
115
+ std::sort (bits.begin (), bits.end ());
116
+ for (auto it = bits.begin (); it != bits.end ();) {
117
+ auto sep = it + 1 ;
118
+ for (; sep != bits.end () &&
119
+ sep->first == it->first &&
120
+ sep->second == (sep - 1 )->second + 1 ; sep++);
121
+ ret.emplace_back (it->first , it->second , sep - it);
122
+ it = sep;
123
+ }
124
+ return ret;
125
+ }
126
+
57
127
struct WrapcellPass : Pass {
58
128
WrapcellPass () : Pass(" wrapcell" , " wrap individual cells into new modules" ) {}
59
129
@@ -68,6 +138,10 @@ struct WrapcellPass : Pass {
68
138
log (" parameter values as specified in curly brackets. If the named module already\n " );
69
139
log (" exists, it is reused.\n " );
70
140
log (" \n " );
141
+ log (" If the template contains the special string '{%%unused}', the command tracks\n " );
142
+ log (" unused output ports -- specialized wrapper modules will be generated per every\n " );
143
+ log (" distinct set of unused port bits as appearing on any selected cell.\n " );
144
+ log (" \n " );
71
145
log (" -setattr <attribute-name>\n " );
72
146
log (" set the given boolean attribute on each created wrapper module\n " );
73
147
log (" \n " );
@@ -114,43 +188,89 @@ struct WrapcellPass : Pass {
114
188
CellTypes ct;
115
189
ct.setup ();
116
190
191
+ bool tracking_unused = has_fmt_field (name_fmt, " %unused" );
192
+
117
193
for (auto module : d->selected_modules ()) {
194
+ SigPool unused;
195
+
196
+ for (auto wire : module->wires ())
197
+ if (wire->has_attribute (ID::unused_bits)) {
198
+ std::string str = wire->get_string_attribute (ID::unused_bits);
199
+ for (auto it = str.begin (); it != str.end ();) {
200
+ auto sep = it;
201
+ for (; sep != str.end () && *sep != ' ' ; sep++);
202
+ unused.add (SigBit (wire, std::stoi (std::string (it, sep))));
203
+ for (it = sep; it != str.end () && *it == ' ' ; it++);
204
+ }
205
+ }
206
+
118
207
for (auto cell : module->selected_cells ()) {
119
- std::optional<std::string> unescaped_name = format (name_fmt, cell->parameters );
208
+ Module *subm;
209
+ Cell *subcell;
210
+
211
+ if (!ct.cell_known (cell->type ))
212
+ log_error (" Non-internal cell type '%s' on cell '%s' in module '%s' unsupported\n " ,
213
+ log_id (cell->type ), log_id (cell), log_id (module));
214
+
215
+ std::vector<std::pair<IdString, int >> unused_outputs, used_outputs;
216
+ for (auto conn : cell->connections ()) {
217
+ if (ct.cell_output (cell->type , conn.first ))
218
+ for (int i = 0 ; i < conn.second .size (); i++) {
219
+ if (tracking_unused && unused.check (conn.second [i]))
220
+ unused_outputs.emplace_back (conn.first , i);
221
+ else
222
+ used_outputs.emplace_back (conn.first , i);
223
+ }
224
+ }
225
+
226
+ ContextData context;
227
+ if (!unused_outputs.empty ()) {
228
+ context.unused_outputs += " _unused" ;
229
+ for (auto chunk : collect_chunks (unused_outputs))
230
+ context.unused_outputs += " _" + RTLIL::unescape_id (chunk.format (cell));
231
+ }
232
+
233
+ std::optional<std::string> unescaped_name = format (name_fmt, cell->parameters , context);
120
234
if (!unescaped_name)
121
235
log_error (" Formatting error when processing cell '%s' in module '%s'\n " ,
122
236
log_id (cell), log_id (module));
123
237
124
238
IdString name = RTLIL::escape_id (unescaped_name.value ());
239
+ if (d->module (name))
240
+ goto replace_cell;
125
241
126
- if (d->module (name)) {
127
- cell->type = name;
128
- cell->parameters .clear ();
129
- continue ;
242
+ subm = d->addModule (name);
243
+ subcell = subm->addCell (" $1" , cell->type );
244
+ for (auto conn : cell->connections ()) {
245
+ if (ct.cell_output (cell->type , conn.first )) {
246
+ // Insert marker bits as placehodlers which need to be replaced
247
+ subcell->setPort (conn.first , SigSpec (RTLIL::Sm, conn.second .size ()));
248
+ } else {
249
+ Wire *w = subm->addWire (conn.first , conn.second .size ());
250
+ w->port_input = true ;
251
+ subcell->setPort (conn.first , w);
252
+ }
130
253
}
131
254
132
- if (!ct.cell_known (cell->type ))
133
- log_error (" Non-internal cell type '%s' on cell '%s' in module '%s' unsupported\n " ,
134
- log_id (cell->type ), log_id (cell), log_id (module));
255
+ for (auto chunk : collect_chunks (used_outputs)) {
256
+ Wire *w = subm->addWire (chunk.format (cell), chunk.len );
257
+ w->port_output = true ;
258
+ subcell->connections_ [chunk.port ].replace (chunk.base , w);
259
+ }
135
260
136
- Module *subm = d->addModule (name);
137
- Cell *subcell = subm->addCell (" $1" , cell->type );
138
- for (auto conn : cell->connections ()) {
139
- Wire *w = subm->addWire (conn.first , conn.second .size ());
140
- if (ct.cell_output (cell->type , w->name ))
141
- w->port_output = true ;
142
- else
143
- w->port_input = true ;
144
- subcell->setPort (conn.first , w);
261
+ for (auto chunk : collect_chunks (unused_outputs)) {
262
+ Wire *w = subm->addWire (chunk.format (cell), chunk.len );
263
+ subcell->connections_ [chunk.port ].replace (chunk.base , w);
145
264
}
265
+
146
266
subcell->parameters = cell->parameters ;
147
267
subm->fixup_ports ();
148
268
149
269
for (auto rule : attributes) {
150
270
if (rule.value_fmt .empty ()) {
151
271
subm->set_bool_attribute (rule.name );
152
272
} else {
153
- std::optional<std::string> value = format (rule.value_fmt , cell->parameters );
273
+ std::optional<std::string> value = format (rule.value_fmt , cell->parameters , context );
154
274
155
275
if (!value)
156
276
log_error (" Formatting error when processing cell '%s' in module '%s'\n " ,
@@ -160,8 +280,20 @@ struct WrapcellPass : Pass {
160
280
}
161
281
}
162
282
163
- cell-> type = name;
283
+ replace_cell:
164
284
cell->parameters .clear ();
285
+
286
+ dict<IdString, SigSpec> new_connections;
287
+
288
+ for (auto conn : cell->connections ())
289
+ if (!ct.cell_output (cell->type , conn.first ))
290
+ new_connections[conn.first ] = conn.second ;
291
+
292
+ for (auto chunk : collect_chunks (used_outputs))
293
+ new_connections[chunk.format (cell)] = chunk.sample (cell);
294
+
295
+ cell->type = name;
296
+ cell->connections_ = new_connections;
165
297
}
166
298
}
167
299
}
0 commit comments