1 /*
2 * Copyright (c) 2003-2014 Stephen Williams (steve@icarus.com)
3 *
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 /*
21 * This is the driver for a purely generic LPM module writer. This
22 * uses LPM version 2 1 0 devices, without particularly considering
23 * the target technology.
24 *
25 * The LPM standard is EIA-IS/103-A October 1996
26 * The output is EDIF 2 0 0 format.
27 */
28
29 # include "device.h"
30 # include "fpga_priv.h"
31 # include "edif.h"
32 # include "generic.h"
33 # include <string.h>
34 # include <assert.h>
35
lpm_cell_buf(void)36 static edif_cell_t lpm_cell_buf(void)
37 {
38 static edif_cell_t tmp = 0;
39
40 if (tmp != 0)
41 return tmp;
42
43 tmp = edif_xcell_create(xlib, "BUF", 2);
44 edif_cell_portconfig(tmp, 0, "Result", IVL_SIP_OUTPUT);
45 edif_cell_portconfig(tmp, 1, "Data", IVL_SIP_INPUT);
46
47 /* A buffer is an inverted inverter. */
48 edif_cell_port_pstring(tmp, 0, "LPM_Polarity", "INVERT");
49
50 edif_cell_pstring(tmp, "LPM_TYPE", "LPM_INV");
51 edif_cell_pinteger(tmp, "LPM_Width", 1);
52 edif_cell_pinteger(tmp, "LPM_Size", 1);
53 return tmp;
54 }
55
lpm_cell_inv(void)56 static edif_cell_t lpm_cell_inv(void)
57 {
58 static edif_cell_t tmp = 0;
59
60 if (tmp != 0)
61 return tmp;
62
63 tmp = edif_xcell_create(xlib, "INV", 2);
64 edif_cell_portconfig(tmp, 0, "Result", IVL_SIP_OUTPUT);
65 edif_cell_portconfig(tmp, 1, "Data", IVL_SIP_INPUT);
66
67 edif_cell_pstring(tmp, "LPM_TYPE", "LPM_INV");
68 edif_cell_pinteger(tmp, "LPM_Width", 1);
69 edif_cell_pinteger(tmp, "LPM_Size", 1);
70 return tmp;
71 }
72
lpm_cell_bufif0(void)73 static edif_cell_t lpm_cell_bufif0(void)
74 {
75 static edif_cell_t tmp = 0;
76
77 if (tmp != 0)
78 return tmp;
79
80 tmp = edif_xcell_create(xlib, "BUFIF1", 3);
81 edif_cell_portconfig(tmp, 0, "TriData", IVL_SIP_OUTPUT);
82 edif_cell_portconfig(tmp, 1, "Data", IVL_SIP_INPUT);
83 edif_cell_portconfig(tmp, 2, "EnableDT", IVL_SIP_INPUT);
84
85 edif_cell_port_pstring(tmp, 2, "LPM_Polarity", "INVERT");
86
87 edif_cell_pstring(tmp, "LPM_TYPE", "LPM_BUSTRI");
88 edif_cell_pinteger(tmp, "LPM_Width", 1);
89 return tmp;
90 }
91
lpm_cell_bufif1(void)92 static edif_cell_t lpm_cell_bufif1(void)
93 {
94 static edif_cell_t tmp = 0;
95
96 if (tmp != 0)
97 return tmp;
98
99 tmp = edif_xcell_create(xlib, "BUFIF1", 3);
100 edif_cell_portconfig(tmp, 0, "TriData", IVL_SIP_OUTPUT);
101 edif_cell_portconfig(tmp, 1, "Data", IVL_SIP_INPUT);
102 edif_cell_portconfig(tmp, 2, "EnableDT", IVL_SIP_INPUT);
103
104 edif_cell_pstring(tmp, "LPM_TYPE", "LPM_BUSTRI");
105 edif_cell_pinteger(tmp, "LPM_Width", 1);
106 return tmp;
107 }
108
lpm_cell_or(unsigned siz)109 static edif_cell_t lpm_cell_or(unsigned siz)
110 {
111 unsigned idx;
112 edif_cell_t cell;
113 char name[32];
114
115 sprintf(name, "or%u", siz);
116
117 cell = edif_xlibrary_findcell(xlib, name);
118 if (cell != 0)
119 return cell;
120
121 cell = edif_xcell_create(xlib, strdup(name), siz+1);
122
123 edif_cell_portconfig(cell, 0, "Result0", IVL_SIP_OUTPUT);
124
125 for (idx = 0 ; idx < siz ; idx += 1) {
126 sprintf(name, "Data%ux0", idx);
127 edif_cell_portconfig(cell, idx+1, strdup(name), IVL_SIP_INPUT);
128 }
129
130 edif_cell_pstring(cell, "LPM_TYPE", "LPM_OR");
131 edif_cell_pinteger(cell, "LPM_Width", 1);
132 edif_cell_pinteger(cell, "LPM_Size", siz);
133
134 return cell;
135 }
136
lpm_cell_and(unsigned siz)137 static edif_cell_t lpm_cell_and(unsigned siz)
138 {
139 unsigned idx;
140 edif_cell_t cell;
141 char name[32];
142
143 sprintf(name, "and%u", siz);
144
145 cell = edif_xlibrary_findcell(xlib, name);
146 if (cell != 0)
147 return cell;
148
149 cell = edif_xcell_create(xlib, strdup(name), siz+1);
150
151 edif_cell_portconfig(cell, 0, "Result0", IVL_SIP_OUTPUT);
152
153 for (idx = 0 ; idx < siz ; idx += 1) {
154 sprintf(name, "Data%ux0", idx);
155 edif_cell_portconfig(cell, idx+1, strdup(name), IVL_SIP_INPUT);
156 }
157
158 edif_cell_pstring(cell, "LPM_TYPE", "LPM_AND");
159 edif_cell_pinteger(cell, "LPM_Width", 1);
160 edif_cell_pinteger(cell, "LPM_Size", siz);
161
162 return cell;
163 }
164
lpm_cell_xor(unsigned siz)165 static edif_cell_t lpm_cell_xor(unsigned siz)
166 {
167 unsigned idx;
168 edif_cell_t cell;
169 char name[32];
170
171 sprintf(name, "xor%u", siz);
172
173 cell = edif_xlibrary_findcell(xlib, name);
174 if (cell != 0)
175 return cell;
176
177 cell = edif_xcell_create(xlib, strdup(name), siz+1);
178
179 edif_cell_portconfig(cell, 0, "Result0", IVL_SIP_OUTPUT);
180
181 for (idx = 0 ; idx < siz ; idx += 1) {
182 sprintf(name, "Data%ux0", idx);
183 edif_cell_portconfig(cell, idx+1, strdup(name), IVL_SIP_INPUT);
184 }
185
186 edif_cell_pstring(cell, "LPM_TYPE", "LPM_XOR");
187 edif_cell_pinteger(cell, "LPM_Width", 1);
188 edif_cell_pinteger(cell, "LPM_Size", siz);
189
190 return cell;
191 }
192
lpm_cell_nor(unsigned siz)193 static edif_cell_t lpm_cell_nor(unsigned siz)
194 {
195 unsigned idx;
196 edif_cell_t cell;
197 char name[32];
198
199 sprintf(name, "nor%u", siz);
200
201 cell = edif_xlibrary_findcell(xlib, name);
202 if (cell != 0)
203 return cell;
204
205 cell = edif_xcell_create(xlib, strdup(name), siz+1);
206
207 edif_cell_portconfig(cell, 0, "Result0", IVL_SIP_OUTPUT);
208 edif_cell_port_pstring(cell, 0, "LPM_Polarity", "INVERT");
209
210 for (idx = 0 ; idx < siz ; idx += 1) {
211 sprintf(name, "Data%ux0", idx);
212 edif_cell_portconfig(cell, idx+1, strdup(name), IVL_SIP_INPUT);
213 }
214
215 edif_cell_pstring(cell, "LPM_TYPE", "LPM_OR");
216 edif_cell_pinteger(cell, "LPM_Width", 1);
217 edif_cell_pinteger(cell, "LPM_Size", siz);
218
219 return cell;
220 }
221
lpm_show_header(ivl_design_t des)222 static void lpm_show_header(ivl_design_t des)
223 {
224 unsigned idx;
225 ivl_scope_t root = ivl_design_root(des);
226 unsigned sig_cnt = ivl_scope_sigs(root);
227 unsigned nports = 0, pidx;
228
229 /* Count the ports I'm going to use. */
230 for (idx = 0 ; idx < sig_cnt ; idx += 1) {
231 ivl_signal_t sig = ivl_scope_sig(root, idx);
232
233 if (ivl_signal_port(sig) == IVL_SIP_NONE)
234 continue;
235
236 if (ivl_signal_attr(sig, "PAD") != 0)
237 continue;
238
239 nports += ivl_signal_pins(sig);
240 }
241
242 /* Create the base edf object. */
243 edf = edif_create(ivl_scope_basename(root), nports);
244
245
246 pidx = 0;
247 for (idx = 0 ; idx < sig_cnt ; idx += 1) {
248 edif_joint_t jnt;
249 ivl_signal_t sig = ivl_scope_sig(root, idx);
250
251 if (ivl_signal_port(sig) == IVL_SIP_NONE)
252 continue;
253
254 if (ivl_signal_attr(sig, "PAD") != 0)
255 continue;
256
257 if (ivl_signal_pins(sig) == 1) {
258 edif_portconfig(edf, pidx, ivl_signal_basename(sig),
259 ivl_signal_port(sig));
260
261 assert(ivl_signal_pins(sig) == 1);
262 jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, 0));
263 edif_port_to_joint(jnt, edf, pidx);
264
265 } else {
266 const char*name = ivl_signal_basename(sig);
267 ivl_signal_port_t dir = ivl_signal_port(sig);
268 char buf[128];
269 unsigned bit;
270 for (bit = 0 ; bit < ivl_signal_pins(sig) ; bit += 1) {
271 const char*tmp;
272 sprintf(buf, "%s[%u]", name, bit);
273 tmp = strdup(buf);
274 edif_portconfig(edf, pidx+bit, tmp, dir);
275
276 jnt = edif_joint_of_nexus(edf,ivl_signal_pin(sig,bit));
277 edif_port_to_joint(jnt, edf, pidx+bit);
278 }
279 }
280
281 pidx += ivl_signal_pins(sig);
282 }
283
284 assert(pidx == nports);
285
286 xlib = edif_xlibrary_create(edf, "LPM_LIBRARY");
287 }
288
lpm_show_footer(ivl_design_t des)289 static void lpm_show_footer(ivl_design_t des)
290 {
291 edif_print(xnf, edf);
292 }
293
hookup_logic_gate(ivl_net_logic_t net,edif_cell_t cell)294 static void hookup_logic_gate(ivl_net_logic_t net, edif_cell_t cell)
295 {
296 unsigned pin, idx;
297
298 edif_joint_t jnt;
299 edif_cellref_t ref = edif_cellref_create(edf, cell);
300
301 jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
302 pin = edif_cell_port_byname(cell, "Result0");
303 edif_add_to_joint(jnt, ref, pin);
304
305 for (idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) {
306 char name[32];
307
308 jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx));
309 sprintf(name, "Data%ux0", idx-1);
310 pin = edif_cell_port_byname(cell, name);
311 edif_add_to_joint(jnt, ref, pin);
312 }
313 }
314
lpm_logic(ivl_net_logic_t net)315 static void lpm_logic(ivl_net_logic_t net)
316 {
317 edif_cell_t cell;
318 edif_cellref_t ref;
319 edif_joint_t jnt;
320
321 switch (ivl_logic_type(net)) {
322
323 case IVL_LO_BUFZ:
324 case IVL_LO_BUF:
325 assert(ivl_logic_pins(net) == 2);
326 cell = lpm_cell_buf();
327 ref = edif_cellref_create(edf, cell);
328
329 jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
330 edif_add_to_joint(jnt, ref, 0);
331
332 jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
333 edif_add_to_joint(jnt, ref, 1);
334 break;
335
336 case IVL_LO_BUFIF0:
337 assert(ivl_logic_pins(net) == 3);
338 cell = lpm_cell_bufif0();
339 ref = edif_cellref_create(edf, cell);
340
341 jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
342 edif_add_to_joint(jnt, ref, 0);
343
344 jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
345 edif_add_to_joint(jnt, ref, 1);
346
347 jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2));
348 edif_add_to_joint(jnt, ref, 2);
349 break;
350
351 case IVL_LO_BUFIF1:
352 assert(ivl_logic_pins(net) == 3);
353 cell = lpm_cell_bufif1();
354 ref = edif_cellref_create(edf, cell);
355
356 jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
357 edif_add_to_joint(jnt, ref, 0);
358
359 jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
360 edif_add_to_joint(jnt, ref, 1);
361
362 jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2));
363 edif_add_to_joint(jnt, ref, 2);
364 break;
365
366 case IVL_LO_NOT:
367 assert(ivl_logic_pins(net) == 2);
368 cell = lpm_cell_inv();
369 ref = edif_cellref_create(edf, cell);
370
371 jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
372 edif_add_to_joint(jnt, ref, 0);
373
374 jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
375 edif_add_to_joint(jnt, ref, 1);
376 break;
377
378 case IVL_LO_OR:
379 cell = lpm_cell_or(ivl_logic_pins(net)-1);
380 hookup_logic_gate(net, cell);
381 break;
382
383 case IVL_LO_NOR:
384 cell = lpm_cell_nor(ivl_logic_pins(net)-1);
385 hookup_logic_gate(net, cell);
386 break;
387
388 case IVL_LO_AND:
389 cell = lpm_cell_and(ivl_logic_pins(net)-1);
390 hookup_logic_gate( net, cell);
391 break;
392
393 case IVL_LO_XOR:
394 cell = lpm_cell_xor(ivl_logic_pins(net)-1);
395 hookup_logic_gate( net, cell);
396 break;
397
398 default:
399 fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %d\n",
400 ivl_logic_type(net));
401 break;
402 }
403 }
404
405
lpm_show_dff(ivl_lpm_t net)406 static void lpm_show_dff(ivl_lpm_t net)
407 {
408 char name[64];
409 edif_cell_t cell;
410 edif_cellref_t ref;
411 edif_joint_t jnt;
412
413 unsigned idx;
414 unsigned pin, wid = ivl_lpm_width(net);
415
416 sprintf(name, "fd%s%s%s%s%s%u",
417 ivl_lpm_enable(net)? "ce" : "",
418 ivl_lpm_async_clr(net)? "cl" : "",
419 ivl_lpm_sync_clr(net)? "sc" : "",
420 ivl_lpm_async_set(net)? "se" : "",
421 ivl_lpm_sync_set(net)? "ss" : "",
422 wid);
423
424 cell = edif_xlibrary_findcell(xlib, name);
425
426 if (cell == 0) {
427 unsigned nports = 2 * wid + 1;
428 pin = 0;
429 if (ivl_lpm_enable(net))
430 nports += 1;
431 if (ivl_lpm_async_clr(net))
432 nports += 1;
433 if (ivl_lpm_sync_clr(net))
434 nports += 1;
435 if (ivl_lpm_async_set(net))
436 nports += 1;
437 if (ivl_lpm_sync_set(net))
438 nports += 1;
439
440 cell = edif_xcell_create(xlib, strdup(name), nports);
441 edif_cell_pstring(cell, "LPM_Type", "LPM_FF");
442 edif_cell_pinteger(cell, "LPM_Width", wid);
443
444 for (idx = 0 ; idx < wid ; idx += 1) {
445
446 sprintf(name, "Q%u", idx);
447 edif_cell_portconfig(cell, idx*2+0, strdup(name),
448 IVL_SIP_OUTPUT);
449
450 sprintf(name, "Data%u", idx);
451 edif_cell_portconfig(cell, idx*2+1, strdup(name),
452 IVL_SIP_INPUT);
453 }
454
455 pin = wid*2;
456
457 if (ivl_lpm_enable(net)) {
458 edif_cell_portconfig(cell, pin, "Enable", IVL_SIP_INPUT);
459 pin += 1;
460 }
461
462 if (ivl_lpm_async_clr(net)) {
463 edif_cell_portconfig(cell, pin, "Aclr", IVL_SIP_INPUT);
464 pin += 1;
465 }
466
467 if (ivl_lpm_sync_clr(net)) {
468 edif_cell_portconfig(cell, pin, "Sclr", IVL_SIP_INPUT);
469 pin += 1;
470 }
471
472 if (ivl_lpm_async_set(net)) {
473 edif_cell_portconfig(cell, pin, "Aset", IVL_SIP_INPUT);
474 pin += 1;
475 }
476
477 if (ivl_lpm_sync_set(net)) {
478 edif_cell_portconfig(cell, pin, "Sset", IVL_SIP_INPUT);
479 pin += 1;
480 }
481
482 edif_cell_portconfig(cell, pin, "Clock", IVL_SIP_INPUT);
483 pin += 1;
484
485 assert(pin == nports);
486 }
487
488 ref = edif_cellref_create(edf, cell);
489
490 pin = edif_cell_port_byname(cell, "Clock");
491
492 jnt = edif_joint_of_nexus(edf, ivl_lpm_clk(net));
493 edif_add_to_joint(jnt, ref, pin);
494
495 if (ivl_lpm_enable(net)) {
496 pin = edif_cell_port_byname(cell, "Enable");
497
498 jnt = edif_joint_of_nexus(edf, ivl_lpm_enable(net));
499 edif_add_to_joint(jnt, ref, pin);
500 }
501
502 if (ivl_lpm_async_clr(net)) {
503 pin = edif_cell_port_byname(cell, "Aclr");
504
505 jnt = edif_joint_of_nexus(edf, ivl_lpm_async_clr(net));
506 edif_add_to_joint(jnt, ref, pin);
507 }
508
509 if (ivl_lpm_sync_clr(net)) {
510 pin = edif_cell_port_byname(cell, "Sclr");
511
512 jnt = edif_joint_of_nexus(edf, ivl_lpm_sync_clr(net));
513 edif_add_to_joint(jnt, ref, pin);
514 }
515
516 if (ivl_lpm_async_set(net)) {
517 pin = edif_cell_port_byname(cell, "Aset");
518
519 jnt = edif_joint_of_nexus(edf, ivl_lpm_async_set(net));
520 edif_add_to_joint(jnt, ref, pin);
521 }
522
523 if (ivl_lpm_sync_set(net)) {
524 ivl_expr_t svalue = ivl_lpm_sset_value(net);
525
526 pin = edif_cell_port_byname(cell, "Sset");
527
528 jnt = edif_joint_of_nexus(edf, ivl_lpm_sync_set(net));
529 edif_add_to_joint(jnt, ref, pin);
530
531 edif_cellref_pinteger(ref, "LPM_Svalue", ivl_expr_uvalue(svalue));
532 }
533
534 for (idx = 0 ; idx < wid ; idx += 1) {
535
536 sprintf(name, "Q%u", idx);
537 pin = edif_cell_port_byname(cell, name);
538
539 jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
540 edif_add_to_joint(jnt, ref, pin);
541
542 sprintf(name, "Data%u", idx);
543 pin = edif_cell_port_byname(cell, name);
544
545 jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
546 edif_add_to_joint(jnt, ref, pin);
547 }
548 }
549
lpm_show_mux(ivl_lpm_t net)550 static void lpm_show_mux(ivl_lpm_t net)
551 {
552 edif_cell_t cell;
553 edif_cellref_t ref;
554 edif_joint_t jnt;
555
556 unsigned idx, rdx;
557
558 char cellname[32];
559
560 unsigned wid_r = ivl_lpm_width(net);
561 unsigned wid_s = ivl_lpm_selects(net);
562 unsigned wid_z = ivl_lpm_size(net);
563
564 sprintf(cellname, "mux%u_%u_%u", wid_r, wid_s, wid_z);
565 cell = edif_xlibrary_findcell(xlib, cellname);
566
567 if (cell == 0) {
568 unsigned pins = wid_r + wid_s + wid_r*wid_z;
569
570 cell = edif_xcell_create(xlib, strdup(cellname), pins);
571
572 /* Make the output ports. */
573 for (idx = 0 ; idx < wid_r ; idx += 1) {
574 sprintf(cellname, "Result%u", idx);
575 edif_cell_portconfig(cell, idx, strdup(cellname),
576 IVL_SIP_OUTPUT);
577 }
578
579 /* Make the select ports. */
580 for (idx = 0 ; idx < wid_s ; idx += 1) {
581 sprintf(cellname, "Sel%u", idx);
582 edif_cell_portconfig(cell, wid_r+idx, strdup(cellname),
583 IVL_SIP_INPUT);
584 }
585
586 for (idx = 0 ; idx < wid_z ; idx += 1) {
587 unsigned base = wid_r + wid_s + wid_r * idx;
588 unsigned rdx;
589
590 for (rdx = 0 ; rdx < wid_r ; rdx += 1) {
591 sprintf(cellname, "Data%ux%u", idx, rdx);
592 edif_cell_portconfig(cell, base+rdx, strdup(cellname),
593 IVL_SIP_INPUT);
594 }
595 }
596
597 edif_cell_pstring(cell, "LPM_Type", "LPM_MUX");
598 edif_cell_pinteger(cell, "LPM_Width", wid_r);
599 edif_cell_pinteger(cell, "LPM_WidthS", wid_s);
600 edif_cell_pinteger(cell, "LPM_Size", wid_z);
601 }
602
603
604 ref = edif_cellref_create(edf, cell);
605
606 /* Connect the pins of the instance to the nexa. Access the
607 cell pins by name. */
608 for (idx = 0 ; idx < wid_r ; idx += 1) {
609 unsigned pin;
610
611 sprintf(cellname, "Result%u", idx);
612 pin = edif_cell_port_byname(cell, cellname);
613
614 jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
615 edif_add_to_joint(jnt, ref, pin);
616 }
617
618 for (idx = 0 ; idx < wid_s ; idx += 1) {
619 unsigned pin;
620
621 sprintf(cellname, "Sel%u", idx);
622 pin = edif_cell_port_byname(cell, cellname);
623
624 jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, idx));
625 edif_add_to_joint(jnt, ref, pin);
626 }
627
628 for (idx = 0 ; idx < wid_z ; idx += 1) {
629 for (rdx = 0 ; rdx < wid_r ; rdx += 1) {
630 unsigned pin;
631
632 sprintf(cellname, "Data%ux%u", idx, rdx);
633 pin = edif_cell_port_byname(cell, cellname);
634
635 jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, idx, rdx));
636 edif_add_to_joint(jnt, ref, pin);
637 }
638 }
639 }
640
lpm_show_add(ivl_lpm_t net)641 static void lpm_show_add(ivl_lpm_t net)
642 {
643 unsigned idx;
644 unsigned cell_width;
645 char cellname[32];
646 edif_cell_t cell;
647 edif_cellref_t ref;
648 edif_joint_t jnt;
649
650 const char*type = "ADD";
651
652 if (ivl_lpm_type(net) == IVL_LPM_SUB)
653 type = "SUB";
654
655 /* Figure out the width of the cell. Normally, it is the LPM
656 width known by IVL. But if the top data input bits are
657 unconnected, then we really have a width one less, and we
658 can use the cout to fill out the output width. */
659 cell_width = ivl_lpm_width(net);
660 if ( (ivl_lpm_data(net,cell_width-1) == 0)
661 && (ivl_lpm_datab(net,cell_width-1) == 0) )
662 cell_width -= 1;
663
664 /* Find the correct ADD/SUB device in the library, search by
665 name. If the device is not there, then create it and put it
666 in the library. */
667 sprintf(cellname, "%s%u", type, cell_width);
668 cell = edif_xlibrary_findcell(xlib, cellname);
669
670 if (cell == 0) {
671 unsigned pins = cell_width * 3 + 1;
672
673 cell = edif_xcell_create(xlib, strdup(cellname), pins);
674
675 for (idx = 0 ; idx < cell_width ; idx += 1) {
676
677 sprintf(cellname, "Result%u", idx);
678 edif_cell_portconfig(cell, idx*3+0, strdup(cellname),
679 IVL_SIP_OUTPUT);
680
681 sprintf(cellname, "DataA%u", idx);
682 edif_cell_portconfig(cell, idx*3+1, strdup(cellname),
683 IVL_SIP_INPUT);
684
685 sprintf(cellname, "DataB%u", idx);
686 edif_cell_portconfig(cell, idx*3+2, strdup(cellname),
687 IVL_SIP_INPUT);
688 }
689
690 edif_cell_portconfig(cell, pins-1, "Cout", IVL_SIP_OUTPUT);
691
692 edif_cell_pstring(cell, "LPM_Type", "LPM_ADD_SUB");
693 edif_cell_pstring(cell, "LPM_Direction", type);
694 edif_cell_pinteger(cell, "LPM_Width", ivl_lpm_width(net));
695 }
696
697 ref = edif_cellref_create(edf, cell);
698
699 /* Connect the pins of the instance to the nexa. Access the
700 cell pins by name. */
701 for (idx = 0 ; idx < cell_width ; idx += 1) {
702 unsigned pin;
703
704 sprintf(cellname, "Result%u", idx);
705 pin = edif_cell_port_byname(cell, cellname);
706
707 jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
708 edif_add_to_joint(jnt, ref, pin);
709
710 sprintf(cellname, "DataA%u", idx);
711 pin = edif_cell_port_byname(cell, cellname);
712
713 jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
714 edif_add_to_joint(jnt, ref, pin);
715
716 sprintf(cellname, "DataB%u", idx);
717 pin = edif_cell_port_byname(cell, cellname);
718
719 jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx));
720 edif_add_to_joint(jnt, ref, pin);
721 }
722
723 if (cell_width < ivl_lpm_width(net)) {
724 unsigned pin = edif_cell_port_byname(cell, "Cout");
725
726 jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, cell_width));
727 edif_add_to_joint(jnt, ref, pin);
728 }
729 }
730
lpm_show_mult(ivl_lpm_t net)731 static void lpm_show_mult(ivl_lpm_t net)
732 {
733 char name[64];
734 unsigned idx;
735
736 edif_cell_t cell;
737 edif_cellref_t ref;
738
739 sprintf(name, "mult%u", ivl_lpm_width(net));
740 cell = edif_xlibrary_findcell(xlib, name);
741
742 if (cell == 0) {
743 cell = edif_xcell_create(xlib, strdup(name),
744 3 * ivl_lpm_width(net));
745
746 for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) {
747
748 sprintf(name, "Result%u", idx);
749 edif_cell_portconfig(cell, idx*3+0,
750 strdup(name),
751 IVL_SIP_OUTPUT);
752
753 sprintf(name, "DataA%u", idx);
754 edif_cell_portconfig(cell, idx*3+1,
755 strdup(name),
756 IVL_SIP_INPUT);
757
758 sprintf(name, "DataB%u", idx);
759 edif_cell_portconfig(cell, idx*3+2,
760 strdup(name),
761 IVL_SIP_INPUT);
762 }
763
764 edif_cell_pstring(cell, "LPM_Type", "LPM_MULT");
765 edif_cell_pinteger(cell, "LPM_WidthP", ivl_lpm_width(net));
766 edif_cell_pinteger(cell, "LPM_WidthA", ivl_lpm_width(net));
767 edif_cell_pinteger(cell, "LPM_WidthB", ivl_lpm_width(net));
768 }
769
770 ref = edif_cellref_create(edf, cell);
771
772 for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) {
773 unsigned pin;
774 ivl_nexus_t nex;
775 edif_joint_t jnt;
776
777 sprintf(name, "Result%u", idx);
778 pin = edif_cell_port_byname(cell, name);
779
780 jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
781 edif_add_to_joint(jnt, ref, pin);
782
783 if ( (nex = ivl_lpm_data(net, idx)) ) {
784 sprintf(name, "DataA%u", idx);
785 pin = edif_cell_port_byname(cell, name);
786
787 jnt = edif_joint_of_nexus(edf, nex);
788 edif_add_to_joint(jnt, ref, pin);
789 }
790
791 if ( (nex = ivl_lpm_datab(net, idx)) ) {
792 sprintf(name, "DataB%u", idx);
793 pin = edif_cell_port_byname(cell, name);
794
795 jnt = edif_joint_of_nexus(edf, nex);
796 edif_add_to_joint(jnt, ref, pin);
797 }
798 }
799
800 }
801
lpm_show_constant(ivl_net_const_t net)802 static void lpm_show_constant(ivl_net_const_t net)
803 {
804 edif_cell_t cell0 = edif_xlibrary_findcell(xlib, "cell0");
805 edif_cell_t cell1 = edif_xlibrary_findcell(xlib, "cell1");
806 edif_cellref_t ref0 = 0, ref1 = 0;
807
808 const char*bits;
809 unsigned idx;
810
811 if (cell0 == 0) {
812 cell0 = edif_xcell_create(xlib, "cell0", 1);
813 edif_cell_portconfig(cell0, 0, "Result0", IVL_SIP_OUTPUT);
814
815 edif_cell_pstring(cell0, "LPM_Type", "LPM_CONSTANT");
816 edif_cell_pinteger(cell0, "LPM_Width", 1);
817 edif_cell_pinteger(cell0, "LPM_CValue", 0);
818 }
819
820 if (cell1 == 0) {
821 cell1 = edif_xcell_create(xlib, "cell1", 1);
822 edif_cell_portconfig(cell1, 0, "Result0", IVL_SIP_OUTPUT);
823
824 edif_cell_pstring(cell1, "LPM_Type", "LPM_CONSTANT");
825 edif_cell_pinteger(cell1, "LPM_Width", 1);
826 edif_cell_pinteger(cell1, "LPM_CValue", 1);
827 }
828
829 bits = ivl_const_bits(net);
830 for (idx = 0 ; idx < ivl_const_pins(net) ; idx += 1) {
831 if (bits[idx] == '1') {
832 if (ref1 == 0)
833 ref1 = edif_cellref_create(edf, cell1);
834
835 } else {
836 if (ref0 == 0)
837 ref0 = edif_cellref_create(edf, cell0);
838 }
839 }
840
841 for (idx = 0 ; idx < ivl_const_pins(net) ; idx += 1) {
842 edif_joint_t jnt;
843
844 jnt = edif_joint_of_nexus(edf, ivl_const_pin(net,idx));
845 if (bits[idx] == '1')
846 edif_add_to_joint(jnt, ref1, 0);
847 else
848 edif_add_to_joint(jnt, ref0, 0);
849 }
850
851 }
852
853
854 const struct device_s d_lpm_edif = {
855 lpm_show_header,
856 lpm_show_footer,
857 0,
858 0,
859 lpm_logic,
860 lpm_show_dff, /* show_dff */
861 0,
862 0,
863 0,
864 0, /* show_cmp_gt */
865 lpm_show_mux, /* show_mux */
866 lpm_show_add, /* show_add */
867 lpm_show_add, /* show_sub */
868 0, /* show_shiftl */
869 0, /* show_shiftr */
870 lpm_show_mult, /* show_mult */
871 lpm_show_constant /* show_constant */
872 };
873