SigSpec refactoring: renamed chunks and width to __chunks and __width
[yosys.git] / passes / techmap / simplemap.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "kernel/register.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/log.h"
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 extern void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
29
30 static void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell)
31 {
32 int width = cell->parameters.at("\\Y_WIDTH").as_int();
33
34 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
35 sig_a.extend(width, cell->parameters.at("\\A_SIGNED").as_bool());
36 sig_a.expand();
37
38 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
39 sig_y.expand();
40
41 for (int i = 0; i < width; i++) {
42 RTLIL::Cell *gate = new RTLIL::Cell;
43 gate->name = NEW_ID;
44 gate->type = "$_INV_";
45 gate->connections["\\A"] = sig_a.__chunks.at(i);
46 gate->connections["\\Y"] = sig_y.__chunks.at(i);
47 module->add(gate);
48 }
49 }
50
51 static void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell)
52 {
53 int width = cell->parameters.at("\\Y_WIDTH").as_int();
54
55 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
56 sig_a.extend(width, cell->parameters.at("\\A_SIGNED").as_bool());
57
58 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
59
60 module->connections.push_back(RTLIL::SigSig(sig_y, sig_a));
61 }
62
63 static void simplemap_bu0(RTLIL::Module *module, RTLIL::Cell *cell)
64 {
65 int width = cell->parameters.at("\\Y_WIDTH").as_int();
66
67 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
68 sig_a.extend_u0(width, cell->parameters.at("\\A_SIGNED").as_bool());
69
70 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
71
72 module->connections.push_back(RTLIL::SigSig(sig_y, sig_a));
73 }
74
75 static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell)
76 {
77 int width = cell->parameters.at("\\Y_WIDTH").as_int();
78
79 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
80 sig_a.extend_u0(width, cell->parameters.at("\\A_SIGNED").as_bool());
81 sig_a.expand();
82
83 RTLIL::SigSpec sig_b = cell->connections.at("\\B");
84 sig_b.extend_u0(width, cell->parameters.at("\\B_SIGNED").as_bool());
85 sig_b.expand();
86
87 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
88 sig_y.expand();
89
90 if (cell->type == "$xnor")
91 {
92 RTLIL::SigSpec sig_t = module->addWire(NEW_ID, width);
93 sig_t.expand();
94
95 for (int i = 0; i < width; i++) {
96 RTLIL::Cell *gate = new RTLIL::Cell;
97 gate->name = NEW_ID;
98 gate->type = "$_INV_";
99 gate->connections["\\A"] = sig_t.__chunks.at(i);
100 gate->connections["\\Y"] = sig_y.__chunks.at(i);
101 module->add(gate);
102 }
103
104 sig_y = sig_t;
105 }
106
107 std::string gate_type;
108 if (cell->type == "$and") gate_type = "$_AND_";
109 if (cell->type == "$or") gate_type = "$_OR_";
110 if (cell->type == "$xor") gate_type = "$_XOR_";
111 if (cell->type == "$xnor") gate_type = "$_XOR_";
112 log_assert(!gate_type.empty());
113
114 for (int i = 0; i < width; i++) {
115 RTLIL::Cell *gate = new RTLIL::Cell;
116 gate->name = NEW_ID;
117 gate->type = gate_type;
118 gate->connections["\\A"] = sig_a.__chunks.at(i);
119 gate->connections["\\B"] = sig_b.__chunks.at(i);
120 gate->connections["\\Y"] = sig_y.__chunks.at(i);
121 module->add(gate);
122 }
123 }
124
125 static void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell)
126 {
127 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
128 sig_a.expand();
129
130 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
131
132 if (sig_y.__width == 0)
133 return;
134
135 if (sig_a.__width == 0) {
136 if (cell->type == "$reduce_and") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.__width)));
137 if (cell->type == "$reduce_or") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.__width)));
138 if (cell->type == "$reduce_xor") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.__width)));
139 if (cell->type == "$reduce_xnor") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.__width)));
140 if (cell->type == "$reduce_bool") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.__width)));
141 return;
142 }
143
144 if (sig_y.__width > 1) {
145 module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.__width-1), RTLIL::SigSpec(0, sig_y.__width-1)));
146 sig_y = sig_y.extract(0, 1);
147 }
148
149 std::string gate_type;
150 if (cell->type == "$reduce_and") gate_type = "$_AND_";
151 if (cell->type == "$reduce_or") gate_type = "$_OR_";
152 if (cell->type == "$reduce_xor") gate_type = "$_XOR_";
153 if (cell->type == "$reduce_xnor") gate_type = "$_XOR_";
154 if (cell->type == "$reduce_bool") gate_type = "$_OR_";
155 log_assert(!gate_type.empty());
156
157 RTLIL::SigSpec *last_output = NULL;
158
159 while (sig_a.__width > 1)
160 {
161 RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig_a.__width / 2);
162 sig_t.expand();
163
164 for (int i = 0; i < sig_a.__width; i += 2)
165 {
166 if (i+1 == sig_a.__width) {
167 sig_t.append(sig_a.__chunks.at(i));
168 continue;
169 }
170
171 RTLIL::Cell *gate = new RTLIL::Cell;
172 gate->name = NEW_ID;
173 gate->type = gate_type;
174 gate->connections["\\A"] = sig_a.__chunks.at(i);
175 gate->connections["\\B"] = sig_a.__chunks.at(i+1);
176 gate->connections["\\Y"] = sig_t.__chunks.at(i/2);
177 last_output = &gate->connections["\\Y"];
178 module->add(gate);
179 }
180
181 sig_a = sig_t;
182 }
183
184 if (cell->type == "$reduce_xnor") {
185 RTLIL::SigSpec sig_t = module->addWire(NEW_ID);
186 RTLIL::Cell *gate = new RTLIL::Cell;
187 gate->name = NEW_ID;
188 gate->type = "$_INV_";
189 gate->connections["\\A"] = sig_a;
190 gate->connections["\\Y"] = sig_t;
191 last_output = &gate->connections["\\Y"];
192 module->add(gate);
193 sig_a = sig_t;
194 }
195
196 if (last_output == NULL) {
197 module->connections.push_back(RTLIL::SigSig(sig_y, sig_a));
198 } else {
199 *last_output = sig_y;
200 }
201 }
202
203 static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig)
204 {
205 sig.expand();
206
207 while (sig.__width > 1)
208 {
209 RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig.__width / 2);
210 sig_t.expand();
211
212 for (int i = 0; i < sig.__width; i += 2)
213 {
214 if (i+1 == sig.__width) {
215 sig_t.append(sig.__chunks.at(i));
216 continue;
217 }
218
219 RTLIL::Cell *gate = new RTLIL::Cell;
220 gate->name = NEW_ID;
221 gate->type = "$_OR_";
222 gate->connections["\\A"] = sig.__chunks.at(i);
223 gate->connections["\\B"] = sig.__chunks.at(i+1);
224 gate->connections["\\Y"] = sig_t.__chunks.at(i/2);
225 module->add(gate);
226 }
227
228 sig = sig_t;
229 }
230
231 if (sig.__width == 0)
232 sig = RTLIL::SigSpec(0, 1);
233 }
234
235 static void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell)
236 {
237 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
238 logic_reduce(module, sig_a);
239
240 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
241
242 if (sig_y.__width == 0)
243 return;
244
245 if (sig_y.__width > 1) {
246 module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.__width-1), RTLIL::SigSpec(0, sig_y.__width-1)));
247 sig_y = sig_y.extract(0, 1);
248 }
249
250 RTLIL::Cell *gate = new RTLIL::Cell;
251 gate->name = NEW_ID;
252 gate->type = "$_INV_";
253 gate->connections["\\A"] = sig_a;
254 gate->connections["\\Y"] = sig_y;
255 module->add(gate);
256 }
257
258 static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell)
259 {
260 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
261 logic_reduce(module, sig_a);
262
263 RTLIL::SigSpec sig_b = cell->connections.at("\\B");
264 logic_reduce(module, sig_b);
265
266 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
267
268 if (sig_y.__width == 0)
269 return;
270
271 if (sig_y.__width > 1) {
272 module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.__width-1), RTLIL::SigSpec(0, sig_y.__width-1)));
273 sig_y = sig_y.extract(0, 1);
274 }
275
276 std::string gate_type;
277 if (cell->type == "$logic_and") gate_type = "$_AND_";
278 if (cell->type == "$logic_or") gate_type = "$_OR_";
279 log_assert(!gate_type.empty());
280
281 RTLIL::Cell *gate = new RTLIL::Cell;
282 gate->name = NEW_ID;
283 gate->type = gate_type;
284 gate->connections["\\A"] = sig_a;
285 gate->connections["\\B"] = sig_b;
286 gate->connections["\\Y"] = sig_y;
287 module->add(gate);
288 }
289
290 static void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell)
291 {
292 int width = cell->parameters.at("\\WIDTH").as_int();
293
294 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
295 sig_a.expand();
296
297 RTLIL::SigSpec sig_b = cell->connections.at("\\B");
298 sig_b.expand();
299
300 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
301 sig_y.expand();
302
303 for (int i = 0; i < width; i++) {
304 RTLIL::Cell *gate = new RTLIL::Cell;
305 gate->name = NEW_ID;
306 gate->type = "$_MUX_";
307 gate->connections["\\A"] = sig_a.__chunks.at(i);
308 gate->connections["\\B"] = sig_b.__chunks.at(i);
309 gate->connections["\\S"] = cell->connections.at("\\S");
310 gate->connections["\\Y"] = sig_y.__chunks.at(i);
311 module->add(gate);
312 }
313 }
314
315 static void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell)
316 {
317 int offset = cell->parameters.at("\\OFFSET").as_int();
318 RTLIL::SigSpec sig_a = cell->connections.at("\\A");
319 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
320 module->connections.push_back(RTLIL::SigSig(sig_y, sig_a.extract(offset, sig_y.__width)));
321 }
322
323 static void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
324 {
325 RTLIL::SigSpec sig_ab = cell->connections.at("\\A");
326 sig_ab.append(cell->connections.at("\\B"));
327 RTLIL::SigSpec sig_y = cell->connections.at("\\Y");
328 module->connections.push_back(RTLIL::SigSig(sig_y, sig_ab));
329 }
330
331 static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
332 {
333 int width = cell->parameters.at("\\WIDTH").as_int();
334 char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N';
335 char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N';
336
337 RTLIL::SigSpec sig_s = cell->connections.at("\\SET");
338 sig_s.expand();
339
340 RTLIL::SigSpec sig_r = cell->connections.at("\\CLR");
341 sig_r.expand();
342
343 RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
344 sig_q.expand();
345
346 std::string gate_type = stringf("$_SR_%c%c_", set_pol, clr_pol);
347
348 for (int i = 0; i < width; i++) {
349 RTLIL::Cell *gate = new RTLIL::Cell;
350 gate->name = NEW_ID;
351 gate->type = gate_type;
352 gate->connections["\\S"] = sig_s.__chunks.at(i);
353 gate->connections["\\R"] = sig_r.__chunks.at(i);
354 gate->connections["\\Q"] = sig_q.__chunks.at(i);
355 module->add(gate);
356 }
357 }
358
359 static void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
360 {
361 int width = cell->parameters.at("\\WIDTH").as_int();
362 char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
363
364 RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK");
365
366 RTLIL::SigSpec sig_d = cell->connections.at("\\D");
367 sig_d.expand();
368
369 RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
370 sig_q.expand();
371
372 std::string gate_type = stringf("$_DFF_%c_", clk_pol);
373
374 for (int i = 0; i < width; i++) {
375 RTLIL::Cell *gate = new RTLIL::Cell;
376 gate->name = NEW_ID;
377 gate->type = gate_type;
378 gate->connections["\\C"] = sig_clk;
379 gate->connections["\\D"] = sig_d.__chunks.at(i);
380 gate->connections["\\Q"] = sig_q.__chunks.at(i);
381 module->add(gate);
382 }
383 }
384
385 static void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell)
386 {
387 int width = cell->parameters.at("\\WIDTH").as_int();
388 char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
389 char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N';
390 char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N';
391
392 RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK");
393
394 RTLIL::SigSpec sig_s = cell->connections.at("\\SET");
395 sig_s.expand();
396
397 RTLIL::SigSpec sig_r = cell->connections.at("\\CLR");
398 sig_r.expand();
399
400 RTLIL::SigSpec sig_d = cell->connections.at("\\D");
401 sig_d.expand();
402
403 RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
404 sig_q.expand();
405
406 std::string gate_type = stringf("$_DFFSR_%c%c%c_", clk_pol, set_pol, clr_pol);
407
408 for (int i = 0; i < width; i++) {
409 RTLIL::Cell *gate = new RTLIL::Cell;
410 gate->name = NEW_ID;
411 gate->type = gate_type;
412 gate->connections["\\C"] = sig_clk;
413 gate->connections["\\S"] = sig_s.__chunks.at(i);
414 gate->connections["\\R"] = sig_r.__chunks.at(i);
415 gate->connections["\\D"] = sig_d.__chunks.at(i);
416 gate->connections["\\Q"] = sig_q.__chunks.at(i);
417 module->add(gate);
418 }
419 }
420
421 static void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell)
422 {
423 int width = cell->parameters.at("\\WIDTH").as_int();
424 char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N';
425 char rst_pol = cell->parameters.at("\\ARST_POLARITY").as_bool() ? 'P' : 'N';
426
427 std::vector<RTLIL::State> rst_val = cell->parameters.at("\\ARST_VALUE").bits;
428 while (int(rst_val.size()) < width)
429 rst_val.push_back(RTLIL::State::S0);
430
431 RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK");
432 RTLIL::SigSpec sig_rst = cell->connections.at("\\ARST");
433
434 RTLIL::SigSpec sig_d = cell->connections.at("\\D");
435 sig_d.expand();
436
437 RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
438 sig_q.expand();
439
440 std::string gate_type_0 = stringf("$_DFF_%c%c0_", clk_pol, rst_pol);
441 std::string gate_type_1 = stringf("$_DFF_%c%c1_", clk_pol, rst_pol);
442
443 for (int i = 0; i < width; i++) {
444 RTLIL::Cell *gate = new RTLIL::Cell;
445 gate->name = NEW_ID;
446 gate->type = rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0;
447 gate->connections["\\C"] = sig_clk;
448 gate->connections["\\R"] = sig_rst;
449 gate->connections["\\D"] = sig_d.__chunks.at(i);
450 gate->connections["\\Q"] = sig_q.__chunks.at(i);
451 module->add(gate);
452 }
453 }
454
455 static void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell)
456 {
457 int width = cell->parameters.at("\\WIDTH").as_int();
458 char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N';
459
460 RTLIL::SigSpec sig_en = cell->connections.at("\\EN");
461
462 RTLIL::SigSpec sig_d = cell->connections.at("\\D");
463 sig_d.expand();
464
465 RTLIL::SigSpec sig_q = cell->connections.at("\\Q");
466 sig_q.expand();
467
468 std::string gate_type = stringf("$_DLATCH_%c_", en_pol);
469
470 for (int i = 0; i < width; i++) {
471 RTLIL::Cell *gate = new RTLIL::Cell;
472 gate->name = NEW_ID;
473 gate->type = gate_type;
474 gate->connections["\\E"] = sig_en;
475 gate->connections["\\D"] = sig_d.__chunks.at(i);
476 gate->connections["\\Q"] = sig_q.__chunks.at(i);
477 module->add(gate);
478 }
479 }
480
481 void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers)
482 {
483 mappers["$not"] = simplemap_not;
484 mappers["$pos"] = simplemap_pos;
485 mappers["$bu0"] = simplemap_bu0;
486 mappers["$and"] = simplemap_bitop;
487 mappers["$or"] = simplemap_bitop;
488 mappers["$xor"] = simplemap_bitop;
489 mappers["$xnor"] = simplemap_bitop;
490 mappers["$reduce_and"] = simplemap_reduce;
491 mappers["$reduce_or"] = simplemap_reduce;
492 mappers["$reduce_xor"] = simplemap_reduce;
493 mappers["$reduce_xnor"] = simplemap_reduce;
494 mappers["$reduce_bool"] = simplemap_reduce;
495 mappers["$logic_not"] = simplemap_lognot;
496 mappers["$logic_and"] = simplemap_logbin;
497 mappers["$logic_or"] = simplemap_logbin;
498 mappers["$mux"] = simplemap_mux;
499 mappers["$slice"] = simplemap_slice;
500 mappers["$concat"] = simplemap_concat;
501 mappers["$sr"] = simplemap_sr;
502 mappers["$dff"] = simplemap_dff;
503 mappers["$dffsr"] = simplemap_dffsr;
504 mappers["$adff"] = simplemap_adff;
505 mappers["$dlatch"] = simplemap_dlatch;
506 }
507
508 struct SimplemapPass : public Pass {
509 SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { }
510 virtual void help()
511 {
512 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
513 log("\n");
514 log(" simplemap [selection]\n");
515 log("\n");
516 log("This pass maps a small selection of simple coarse-grain cells to yosys gate\n");
517 log("primitives. The following internal cell types are mapped by this pass:\n");
518 log("\n");
519 log(" $not, $pos, $bu0, $and, $or, $xor, $xnor\n");
520 log(" $reduce_and, $reduce_or, $reduce_xor, $reduce_xnor, $reduce_bool\n");
521 log(" $logic_not, $logic_and, $logic_or, $mux\n");
522 log(" $sr, $dff, $dffsr, $adff, $dlatch\n");
523 log("\n");
524 }
525 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
526 {
527 log_header("Executing SIMPLEMAP pass (map simple cells to gate primitives).\n");
528 extra_args(args, 1, design);
529
530 std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers;
531 simplemap_get_mappers(mappers);
532
533 for (auto &mod_it : design->modules) {
534 if (!design->selected(mod_it.second))
535 continue;
536 std::vector<RTLIL::Cell*> delete_cells;
537 for (auto &cell_it : mod_it.second->cells) {
538 if (mappers.count(cell_it.second->type) == 0)
539 continue;
540 if (!design->selected(mod_it.second, cell_it.second))
541 continue;
542 log("Mapping %s.%s (%s).\n", RTLIL::id2cstr(mod_it.first), RTLIL::id2cstr(cell_it.first), RTLIL::id2cstr(cell_it.second->type));
543 mappers.at(cell_it.second->type)(mod_it.second, cell_it.second);
544 delete_cells.push_back(cell_it.second);
545 }
546 for (auto &it : delete_cells) {
547 mod_it.second->cells.erase(it->name);
548 delete it;
549 }
550 }
551 }
552 } SimplemapPass;
553