1 /*
2 * Copyright (c) 2000-2020 Stephen Williams (steve@icarus.com)
3 * Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
4 *
5 * This source code is free software; you can redistribute it
6 * and/or modify it in source code form under the terms of the GNU
7 * General Public License as published by the Free Software
8 * Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 # include "config.h"
22
23 # include <iostream>
24
25 # include <cstring>
26 # include <cstdio> // sprintf()
27 # include "compiler.h"
28 # include "t-dll.h"
29 # include "netclass.h"
30 # include "netqueue.h"
31 # include "netmisc.h"
32 # include "discipline.h"
33 # include <cstdlib>
34 # include "ivl_assert.h"
35 # include "ivl_alloc.h"
36
37 struct dll_target dll_target_obj;
38
39 #if defined(__WIN32__)
40
ivl_dlopen(const char * name)41 inline ivl_dll_t ivl_dlopen(const char *name)
42 {
43 ivl_dll_t res = (ivl_dll_t) LoadLibrary(name);
44 return res;
45 }
46
47
ivl_dlsym(ivl_dll_t dll,const char * nm)48 inline void * ivl_dlsym(ivl_dll_t dll, const char *nm)
49 {
50 return (void*)GetProcAddress((HMODULE)dll, nm);
51 }
52
ivl_dlclose(ivl_dll_t dll)53 inline void ivl_dlclose(ivl_dll_t dll)
54 {
55 FreeLibrary((HMODULE)dll);
56 }
57
dlerror(void)58 const char *dlerror(void)
59 {
60 static char msg[256];
61 unsigned long err = GetLastError();
62 FormatMessage(
63 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
64 NULL,
65 err,
66 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
67 (LPTSTR) &msg,
68 sizeof(msg) - 1,
69 NULL
70 );
71 return msg;
72 }
73 #elif defined(HAVE_DLFCN_H)
ivl_dlopen(const char * name)74 inline ivl_dll_t ivl_dlopen(const char*name)
75 { return dlopen(name,RTLD_LAZY); }
76
ivl_dlsym(ivl_dll_t dll,const char * nm)77 inline void* ivl_dlsym(ivl_dll_t dll, const char*nm)
78 {
79 void*sym = dlsym(dll, nm);
80 /* Not found? try without the leading _ */
81 if (sym == 0 && nm[0] == '_')
82 sym = dlsym(dll, nm+1);
83 return sym;
84 }
85
ivl_dlclose(ivl_dll_t dll)86 inline void ivl_dlclose(ivl_dll_t dll)
87 { dlclose(dll); }
88
89 #elif defined(HAVE_DL_H)
ivl_dlopen(const char * name)90 inline ivl_dll_t ivl_dlopen(const char*name)
91 { return shl_load(name, BIND_IMMEDIATE, 0); }
92
ivl_dlsym(ivl_dll_t dll,const char * nm)93 inline void* ivl_dlsym(ivl_dll_t dll, const char*nm)
94 {
95 void*sym;
96 int rc = shl_findsym(&dll, nm, TYPE_PROCEDURE, &sym);
97 return (rc == 0) ? sym : 0;
98 }
99
ivl_dlclose(ivl_dll_t dll)100 inline void ivl_dlclose(ivl_dll_t dll)
101 { shl_unload(dll); }
102
dlerror(void)103 inline const char*dlerror(void)
104 { return strerror( errno ); }
105 #endif
106
ivl_scope_s()107 ivl_scope_s::ivl_scope_s()
108 {
109 func_type = IVL_VT_NO_TYPE;
110 func_signed = false;
111 func_width = 0;
112 }
113
114 /*
115 * The custom new operator for the ivl_nexus_s type allows us to
116 * allocate nexus objects in blocks. There are generally lots of them
117 * permanently allocated, and allocating them in blocks reduces the
118 * allocation overhead.
119 */
120
pool_permalloc(size_t s)121 template <class TYPE> void* pool_permalloc(size_t s)
122 {
123 static TYPE * pool_ptr = 0;
124 static int pool_remaining = 0;
125 static const size_t POOL_SIZE = 4096;
126
127 assert(s == sizeof(TYPE));
128 if (pool_remaining <= 0) {
129 pool_ptr = new TYPE[POOL_SIZE];
130 pool_remaining = POOL_SIZE;
131 }
132
133 TYPE*tmp = pool_ptr;
134 pool_ptr += 1;
135 pool_remaining -= 1;
136
137 return tmp;
138 }
139
operator new(size_t s)140 void* ivl_nexus_s::operator new(size_t s)
141 {
142 return pool_permalloc<struct ivl_nexus_s>(s);
143 }
144
operator delete(void *,size_t)145 void ivl_nexus_s::operator delete(void*, size_t)
146 {
147 assert(0);
148 }
149
operator new(size_t s)150 void* ivl_net_const_s::operator new(size_t s)
151 {
152 return pool_permalloc<struct ivl_net_const_s>(s);
153 }
154
operator delete(void *,size_t)155 void ivl_net_const_s::operator delete(void*, size_t)
156 {
157 assert(0);
158 }
159
160 static StringHeapLex net_const_strings;
161
make_scope_name(const hname_t & name)162 static perm_string make_scope_name(const hname_t&name)
163 {
164 if (! name.has_numbers())
165 return name.peek_name();
166
167 char buf[1024];
168 snprintf(buf, sizeof buf, "%s", name.peek_name().str());
169
170 char*cp = buf + strlen(buf);
171 size_t ncp = sizeof buf - (cp-buf);
172
173 for (size_t idx = 0 ; idx < name.has_numbers() ; idx += 1) {
174 int len = snprintf(cp, ncp, "[%d]", name.peek_number(idx));
175 cp += len;
176 ncp -= len;
177 }
178
179 return lex_strings.make(buf);
180 }
181
drive_from_link(const Link & lnk,ivl_drive_t & drv0,ivl_drive_t & drv1)182 static void drive_from_link(const Link&lnk, ivl_drive_t&drv0, ivl_drive_t&drv1)
183 {
184 drv0 = lnk.drive0();
185 drv1 = lnk.drive1();
186 }
187
fill_in_attributes(const Attrib * net)188 ivl_attribute_s* dll_target::fill_in_attributes(const Attrib*net)
189 {
190 ivl_attribute_s*attr;
191 unsigned nattr = net->attr_cnt();
192
193 if (nattr == 0)
194 return 0;
195
196 attr = new struct ivl_attribute_s[nattr];
197
198 for (unsigned idx = 0 ; idx < nattr ; idx += 1) {
199 verinum tmp = net->attr_value(idx);
200 attr[idx].key = net->attr_key(idx);
201 if (tmp.is_string()) {
202 attr[idx].type = IVL_ATT_STR;
203 attr[idx].val.str = strings_.add(tmp.as_string().c_str());
204
205 } else if (tmp == verinum()) {
206 attr[idx].type = IVL_ATT_VOID;
207
208 } else {
209 attr[idx].type = IVL_ATT_NUM;
210 attr[idx].val.num = tmp.as_long();
211 }
212 }
213
214 return attr;
215 }
216
217 /*
218 * This function locates an ivl_scope_t object that matches the
219 * NetScope object. The search works by looking for the parent scope,
220 * then scanning the parent scope for the NetScope object.
221 */
find_scope_from_root(ivl_scope_t root,const NetScope * cur)222 static ivl_scope_t find_scope_from_root(ivl_scope_t root, const NetScope*cur)
223 {
224 if (const NetScope*par = cur->parent()) {
225 ivl_scope_t parent = find_scope_from_root(root, par);
226 if (parent == 0) {
227 return 0;
228 }
229
230 map<hname_t,ivl_scope_t>::iterator idx = parent->children.find(cur->fullname());
231 if (idx == parent->children.end())
232 return 0;
233 else
234 return idx->second;
235
236 } else {
237 perm_string cur_name = make_scope_name(cur->fullname());
238 if (strcmp(root->name_, cur_name) == 0)
239 return root;
240 }
241
242 return 0;
243 }
244
find_scope(ivl_design_s & des,const NetScope * cur)245 ivl_scope_t dll_target::find_scope(ivl_design_s &des, const NetScope*cur)
246 {
247 assert(cur);
248
249 // If the scope is a PACKAGE, then it is a special kind of
250 // root scope and it in the packages array instead.
251 if (cur->type() == NetScope::PACKAGE) {
252 perm_string cur_name = cur->module_name();
253 for (size_t idx = 0 ; idx < des.packages.size() ; idx += 1) {
254 if (des.packages[idx]->name_ == cur_name)
255 return des.packages[idx];
256 }
257 return 0;
258 }
259
260 for (unsigned idx = 0; idx < des.roots.size(); idx += 1) {
261 assert(des.roots[idx]);
262 ivl_scope_t scope = find_scope_from_root(des.roots[idx], cur);
263 if (scope)
264 return scope;
265 }
266
267 for (size_t idx = 0; idx < des.packages.size(); idx += 1) {
268 assert(des.packages[idx]);
269 ivl_scope_t scope = find_scope_from_root(des.packages[idx], cur);
270 if (scope)
271 return scope;
272 }
273
274 return 0;
275 }
276
lookup_scope_(const NetScope * cur)277 ivl_scope_t dll_target::lookup_scope_(const NetScope*cur)
278 {
279 return find_scope(des_, cur);
280 }
281
282 /*
283 * This is a convenience function to locate an ivl_signal_t object
284 * given the NetESignal that has the signal name.
285 */
find_signal(ivl_design_s & des,const NetNet * net)286 ivl_signal_t dll_target::find_signal(ivl_design_s &des, const NetNet*net)
287 {
288 ivl_scope_t scope = find_scope(des, net->scope());
289 assert(scope);
290
291 perm_string nname = net->name();
292
293 for (unsigned idx = 0 ; idx < scope->sigs_.size() ; idx += 1) {
294 if (strcmp(scope->sigs_[idx]->name_, nname) == 0)
295 return scope->sigs_[idx];
296 }
297
298 assert(0);
299 return 0;
300 }
301
nexus_sig_make(ivl_signal_t net,unsigned pin)302 static ivl_nexus_t nexus_sig_make(ivl_signal_t net, unsigned pin)
303 {
304 ivl_nexus_t tmp = new struct ivl_nexus_s;
305 tmp->ptrs_.resize(1);
306 tmp->ptrs_[0].pin_ = pin;
307 tmp->ptrs_[0].type_ = __NEXUS_PTR_SIG;
308 tmp->ptrs_[0].l.sig = net;
309
310 ivl_drive_t drive = IVL_DR_HiZ;
311 switch (ivl_signal_type(net)) {
312 case IVL_SIT_REG:
313 drive = IVL_DR_STRONG;
314 break;
315 default:
316 break;
317 }
318 tmp->ptrs_[0].drive0 = drive;
319 tmp->ptrs_[0].drive1 = drive;
320
321 return tmp;
322 }
323
nexus_sig_add(ivl_nexus_t nex,ivl_signal_t net,unsigned pin)324 static void nexus_sig_add(ivl_nexus_t nex, ivl_signal_t net, unsigned pin)
325 {
326 unsigned top = nex->ptrs_.size();
327 nex->ptrs_.resize(top+1);
328 ivl_drive_t drive = IVL_DR_HiZ;
329 switch (ivl_signal_type(net)) {
330 case IVL_SIT_REG:
331 drive = IVL_DR_STRONG;
332 break;
333 default:
334 break;
335 }
336
337 nex->ptrs_[top].type_= __NEXUS_PTR_SIG;
338 nex->ptrs_[top].drive0 = drive;
339 nex->ptrs_[top].drive1 = drive;
340 nex->ptrs_[top].pin_ = pin;
341 nex->ptrs_[top].l.sig= net;
342 }
343
nexus_bra_add(ivl_nexus_t nex,ivl_branch_t net,unsigned pin)344 static void nexus_bra_add(ivl_nexus_t nex, ivl_branch_t net, unsigned pin)
345 {
346 unsigned top = nex->ptrs_.size();
347 nex->ptrs_.resize(top+1);
348 nex->ptrs_[top].type_= __NEXUS_PTR_BRA;
349 nex->ptrs_[top].drive0 = 0;
350 nex->ptrs_[top].drive1 = 0;
351 nex->ptrs_[top].pin_ = pin;
352 nex->ptrs_[top].l.bra= net;
353 }
354
355 /*
356 * Add the pin of the logic object to the nexus, and return the nexus
357 * pointer used for the pin.
358 *
359 * NOTE: This pointer is only valid until another pin is added to the
360 * nexus.
361 */
nexus_log_add(ivl_nexus_t nex,ivl_net_logic_t net,unsigned pin)362 static ivl_nexus_ptr_t nexus_log_add(ivl_nexus_t nex,
363 ivl_net_logic_t net,
364 unsigned pin)
365 {
366 unsigned top = nex->ptrs_.size();
367 nex->ptrs_.resize(top+1);
368
369 nex->ptrs_[top].type_= __NEXUS_PTR_LOG;
370 nex->ptrs_[top].drive0 = (pin == 0)? IVL_DR_STRONG : IVL_DR_HiZ;
371 nex->ptrs_[top].drive1 = (pin == 0)? IVL_DR_STRONG : IVL_DR_HiZ;
372 nex->ptrs_[top].pin_ = pin;
373 nex->ptrs_[top].l.log= net;
374
375 return & (nex->ptrs_[top]);
376 }
377
nexus_con_add(ivl_nexus_t nex,ivl_net_const_t net,unsigned pin,ivl_drive_t drive0,ivl_drive_t drive1)378 static void nexus_con_add(ivl_nexus_t nex, ivl_net_const_t net, unsigned pin,
379 ivl_drive_t drive0, ivl_drive_t drive1)
380 {
381 unsigned top = nex->ptrs_.size();
382 nex->ptrs_.resize(top+1);
383
384 nex->ptrs_[top].type_= __NEXUS_PTR_CON;
385 nex->ptrs_[top].drive0 = drive0;
386 nex->ptrs_[top].drive1 = drive1;
387 nex->ptrs_[top].pin_ = pin;
388 nex->ptrs_[top].l.con= net;
389 }
390
nexus_lpm_add(ivl_nexus_t nex,ivl_lpm_t net,unsigned pin,ivl_drive_t drive0,ivl_drive_t drive1)391 static void nexus_lpm_add(ivl_nexus_t nex, ivl_lpm_t net, unsigned pin,
392 ivl_drive_t drive0, ivl_drive_t drive1)
393 {
394 unsigned top = nex->ptrs_.size();
395 nex->ptrs_.resize(top+1);
396
397 nex->ptrs_[top].type_= __NEXUS_PTR_LPM;
398 nex->ptrs_[top].drive0 = drive0;
399 nex->ptrs_[top].drive1 = drive1;
400 nex->ptrs_[top].pin_ = pin;
401 nex->ptrs_[top].l.lpm= net;
402 }
403
nexus_switch_add(ivl_nexus_t nex,ivl_switch_t net,unsigned pin)404 static void nexus_switch_add(ivl_nexus_t nex, ivl_switch_t net, unsigned pin)
405 {
406 unsigned top = nex->ptrs_.size();
407 nex->ptrs_.resize(top+1);
408
409 nex->ptrs_[top].type_= __NEXUS_PTR_SWI;
410 nex->ptrs_[top].drive0 = IVL_DR_HiZ;
411 nex->ptrs_[top].drive1 = IVL_DR_HiZ;
412 nex->ptrs_[top].pin_ = pin;
413 nex->ptrs_[top].l.swi= net;
414 }
415
scope_add_logic(ivl_scope_t scope,ivl_net_logic_t net)416 void scope_add_logic(ivl_scope_t scope, ivl_net_logic_t net)
417 {
418 if (scope->nlog_ == 0) {
419 scope->nlog_ = 1;
420 scope->log_ = (ivl_net_logic_t*)malloc(sizeof(ivl_net_logic_t));
421 scope->log_[0] = net;
422
423 } else {
424 scope->nlog_ += 1;
425 scope->log_ = (ivl_net_logic_t*)
426 realloc(scope->log_, scope->nlog_*sizeof(ivl_net_logic_t));
427 scope->log_[scope->nlog_-1] = net;
428 }
429
430 }
431
scope_add_event(ivl_scope_t scope,ivl_event_t net)432 void scope_add_event(ivl_scope_t scope, ivl_event_t net)
433 {
434 if (scope->nevent_ == 0) {
435 scope->nevent_ = 1;
436 scope->event_ = (ivl_event_t*)malloc(sizeof(ivl_event_t));
437 scope->event_[0] = net;
438
439 } else {
440 scope->nevent_ += 1;
441 scope->event_ = (ivl_event_t*)
442 realloc(scope->event_, scope->nevent_*sizeof(ivl_event_t));
443 scope->event_[scope->nevent_-1] = net;
444 }
445
446 }
447
scope_add_lpm(ivl_scope_t scope,ivl_lpm_t net)448 static void scope_add_lpm(ivl_scope_t scope, ivl_lpm_t net)
449 {
450 if (scope->nlpm_ == 0) {
451 assert(scope->lpm_ == 0);
452 scope->nlpm_ = 1;
453 scope->lpm_ = (ivl_lpm_t*)malloc(sizeof(ivl_lpm_t));
454 scope->lpm_[0] = net;
455
456 } else {
457 assert(scope->lpm_);
458 scope->nlpm_ += 1;
459 scope->lpm_ = (ivl_lpm_t*)
460 realloc(scope->lpm_,
461 scope->nlpm_*sizeof(ivl_lpm_t));
462 scope->lpm_[scope->nlpm_-1] = net;
463 }
464 }
465
scope_add_switch(ivl_scope_t scope,ivl_switch_t net)466 static void scope_add_switch(ivl_scope_t scope, ivl_switch_t net)
467 {
468 scope->switches.push_back(net);
469 }
470
scope_find_param(ivl_scope_t scope,const char * name)471 ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope,
472 const char*name)
473 {
474 unsigned idx = 0;
475 while (idx < scope->param.size()) {
476 if (strcmp(name, scope->param[idx].basename) == 0)
477 return &scope->param[idx];
478
479 idx += 1;
480 }
481
482 return 0;
483 }
484
485 /*
486 * This method scans the parameters of the scope, and makes
487 * ivl_parameter_t objects. This involves saving the name and scanning
488 * the expression value.
489 */
make_scope_parameters(ivl_scope_t scop,const NetScope * net)490 void dll_target::make_scope_parameters(ivl_scope_t scop, const NetScope*net)
491 {
492 if (net->parameters.empty()) {
493 scop->param.clear();
494 return;
495 }
496
497 scop->param.resize(net->parameters.size());
498
499 unsigned idx = 0;
500 typedef map<perm_string,NetScope::param_expr_t>::const_iterator pit_t;
501
502 for (pit_t cur_pit = net->parameters.begin()
503 ; cur_pit != net->parameters.end() ; ++ cur_pit ) {
504
505 assert(idx < scop->param.size());
506 ivl_parameter_t cur_par = &scop->param[idx];
507 cur_par->basename = cur_pit->first;
508 cur_par->local = cur_pit->second.local_flag;
509 /* Either both the MSB and LSB expressions are provided or
510 * neither are provided. */
511 if (cur_pit->second.msb) {
512 assert(cur_pit->second.lsb);
513 /* The MSB and LSB expressions must be integral constants. */
514 const NetEConst *msbc =
515 dynamic_cast<const NetEConst*>(cur_pit->second.msb);
516 const NetEConst *lsbc =
517 dynamic_cast<const NetEConst*>(cur_pit->second.lsb);
518 assert(msbc);
519 assert(lsbc);
520 cur_par->msb = msbc->value().as_long();
521 cur_par->lsb = lsbc->value().as_long();
522 } else {
523 assert(! cur_pit->second.lsb);
524 cur_par->msb = cur_pit->second.val->expr_width() - 1;
525 assert(cur_par->msb >= 0);
526 cur_par->lsb = 0;
527 }
528 cur_par->signed_flag = cur_pit->second.signed_flag;
529 cur_par->scope = scop;
530 FILE_NAME(cur_par, &(cur_pit->second));
531
532 NetExpr*etmp = cur_pit->second.val;
533 if (etmp == 0) {
534 cerr << "?:?: internal error: What is the parameter "
535 << "expression for " << cur_pit->first
536 << " in " << net->fullname() << "?" << endl;
537 }
538 assert(etmp);
539 make_scope_param_expr(cur_par, etmp);
540 idx += 1;
541 }
542 }
543
make_scope_param_expr(ivl_parameter_t cur_par,NetExpr * etmp)544 void dll_target::make_scope_param_expr(ivl_parameter_t cur_par, NetExpr*etmp)
545 {
546 if (const NetEConst*e = dynamic_cast<const NetEConst*>(etmp)) {
547
548 expr_const(e);
549 assert(expr_);
550
551 switch (expr_->type_) {
552 case IVL_EX_STRING:
553 expr_->u_.string_.parameter = cur_par;
554 break;
555 case IVL_EX_NUMBER:
556 expr_->u_.number_.parameter = cur_par;
557 break;
558 default:
559 assert(0);
560 }
561
562 } else if (const NetECReal*er = dynamic_cast<const NetECReal*>(etmp)) {
563
564 expr_creal(er);
565 assert(expr_);
566 assert(expr_->type_ == IVL_EX_REALNUM);
567 expr_->u_.real_.parameter = cur_par;
568
569 }
570
571 if (expr_ == 0) {
572 cerr << etmp->get_fileline() << ": internal error: "
573 << "Parameter expression not reduced to constant? "
574 << *etmp << endl;
575 }
576 ivl_assert(*etmp, expr_);
577
578 cur_par->value = expr_;
579 expr_ = 0;
580 }
581
fill_in_scope_function(ivl_scope_t scope,const NetScope * net)582 static void fill_in_scope_function(ivl_scope_t scope, const NetScope*net)
583 {
584 scope->type_ = IVL_SCT_FUNCTION;
585 const NetFuncDef*def = net->func_def();
586 assert(def);
587
588 if (def->is_void()) {
589 // Special case: If there is no return signal, this is
590 // apparently a VOID function.
591 scope->func_type = IVL_VT_VOID;
592 scope->func_signed = 0;
593 scope->func_width = 0;
594 } else {
595 const NetNet*return_sig = def->return_sig();
596 scope->func_type = return_sig->data_type();
597 scope->func_signed = return_sig->get_signed();
598 scope->func_width = return_sig->vector_width();
599 }
600
601 scope->tname_ = def->scope()->basename();
602 }
603
add_root(const NetScope * s)604 void dll_target::add_root(const NetScope *s)
605 {
606 ivl_scope_t root_ = new struct ivl_scope_s;
607 perm_string name = s->basename();
608 root_->name_ = name;
609 FILE_NAME(root_, s);
610 root_->parent = 0;
611 root_->nlog_ = 0;
612 root_->log_ = 0;
613 root_->nevent_ = 0;
614 root_->event_ = 0;
615 root_->nlpm_ = 0;
616 root_->lpm_ = 0;
617 root_->def = 0;
618 make_scope_parameters(root_, s);
619 root_->tname_ = root_->name_;
620 root_->time_precision = s->time_precision();
621 root_->time_units = s->time_unit();
622 root_->nattr = s->attr_cnt();
623 root_->attr = fill_in_attributes(s);
624 root_->is_auto = 0;
625 root_->is_cell = s->is_cell();
626 switch (s->type()) {
627 case NetScope::PACKAGE:
628 root_->type_ = IVL_SCT_PACKAGE;
629 break;
630 case NetScope::MODULE:
631 root_->type_ = IVL_SCT_MODULE;
632 break;
633 case NetScope::CLASS:
634 root_->type_ = IVL_SCT_CLASS;
635 break;
636 default:
637 assert(0);
638 }
639
640 switch (s->type()) {
641 case NetScope::MODULE:
642 root_->ports = s->module_port_nets();
643 if (root_->ports > 0) {
644 root_->u_.net = new NetNet*[root_->ports];
645 for (unsigned idx = 0; idx < root_->ports; idx += 1) {
646 root_->u_.net[idx] = s->module_port_net(idx);
647 }
648 }
649 root_->module_ports_info = s->module_port_info();
650
651 des_.roots.push_back(root_);
652 break;
653
654 case NetScope::PACKAGE:
655 root_->ports = 0;
656 des_.packages.push_back(root_);
657 break;
658
659 default:
660 assert(0);
661 break;
662 }
663 }
664
start_design(const Design * des)665 bool dll_target::start_design(const Design*des)
666 {
667 const char*dll_path_ = des->get_flag("DLL");
668
669 dll_ = ivl_dlopen(dll_path_);
670
671 if ((dll_ == 0) && (dll_path_[0] != '/')) {
672 size_t len = strlen(basedir) + 1 + strlen(dll_path_) + 1;
673 char*tmp = new char[len];
674 sprintf(tmp, "%s/%s", basedir, dll_path_);
675 dll_ = ivl_dlopen(tmp);
676 delete[]tmp;
677 }
678
679 if (dll_ == 0) {
680 cerr << "error: " << dll_path_ << " failed to load." << endl;
681 cerr << dll_path_ << ": " << dlerror() << endl;
682 return false;
683 }
684
685 stmt_cur_ = 0;
686
687 // Initialize the design object.
688 des_.self = des;
689 des_.time_precision = des->get_precision();
690
691 des_.disciplines.resize(disciplines.size());
692 unsigned idx = 0;
693 for (map<perm_string,ivl_discipline_t>::const_iterator cur = disciplines.begin()
694 ; cur != disciplines.end() ; ++ cur ) {
695 des_.disciplines[idx] = cur->second;
696 idx += 1;
697 }
698 assert(idx == des_.disciplines.size());
699
700 list<NetScope *> scope_list;
701
702 scope_list = des->find_package_scopes();
703 for (list<NetScope*>::const_iterator cur = scope_list.begin()
704 ; cur != scope_list.end(); ++ cur ) {
705 add_root(*cur);
706 }
707
708 scope_list = des->find_root_scopes();
709 for (list<NetScope*>::const_iterator cur = scope_list.begin()
710 ; cur != scope_list.end(); ++ cur ) {
711 add_root(*cur);
712 }
713
714 target_ = (target_design_f)ivl_dlsym(dll_, LU "target_design" TU);
715 if (target_ == 0) {
716 cerr << dll_path_ << ": error: target_design entry "
717 "point is missing." << endl;
718 return false;
719 }
720
721 return true;
722 }
723
724 /*
725 * Here ivl is telling us that the design is scanned completely, and
726 * here is where we call the API to process the constructed design.
727 */
end_design(const Design *)728 int dll_target::end_design(const Design*)
729 {
730 int rc;
731 if (errors == 0) {
732 if (verbose_flag) {
733 cout << " ... invoking target_design" << endl;
734 }
735
736 rc = (target_)(&des_);
737 } else {
738 if (verbose_flag) {
739 cout << " ... skipping target_design due to errors." << endl;
740 }
741 rc = errors;
742 }
743
744 ivl_dlclose(dll_);
745 return rc;
746 }
747
switch_attributes(struct ivl_switch_s * obj,const NetNode * net)748 void dll_target::switch_attributes(struct ivl_switch_s *obj,
749 const NetNode*net)
750 {
751 obj->nattr = net->attr_cnt();
752 obj->attr = fill_in_attributes(net);
753 }
754
logic_attributes(struct ivl_net_logic_s * obj,const NetNode * net)755 void dll_target::logic_attributes(struct ivl_net_logic_s *obj,
756 const NetNode*net)
757 {
758 obj->nattr = net->attr_cnt();
759 obj->attr = fill_in_attributes(net);
760 }
761
make_delays_(ivl_expr_t * delay,const NetObj * net)762 void dll_target::make_delays_(ivl_expr_t*delay, const NetObj*net)
763 {
764 delay[0] = 0;
765 delay[1] = 0;
766 delay[2] = 0;
767
768 /* Translate delay expressions to ivl_target form. Try to
769 preserve pointer equality, not as a rule but to save on
770 expression trees. */
771 if (net->rise_time()) {
772 expr_ = 0;
773 net->rise_time()->expr_scan(this);
774 delay[0] = expr_;
775 expr_ = 0;
776 }
777 if (net->fall_time()) {
778 if (net->fall_time() == net->rise_time()) {
779 delay[1] = delay[0];
780 } else {
781 expr_ = 0;
782 net->fall_time()->expr_scan(this);
783 delay[1] = expr_;
784 expr_ = 0;
785 }
786 }
787 if (net->decay_time()) {
788 if (net->decay_time() == net->rise_time()) {
789 delay[2] = delay[0];
790 } else {
791 expr_ = 0;
792 net->decay_time()->expr_scan(this);
793 delay[2] = expr_;
794 expr_ = 0;
795 }
796 }
797 }
798
make_logic_delays_(struct ivl_net_logic_s * obj,const NetObj * net)799 void dll_target::make_logic_delays_(struct ivl_net_logic_s*obj,
800 const NetObj*net)
801 {
802 make_delays_(obj->delay, net);
803 }
804
make_switch_delays_(struct ivl_switch_s * obj,const NetObj * net)805 void dll_target::make_switch_delays_(struct ivl_switch_s*obj,
806 const NetObj*net)
807 {
808 make_delays_(obj->delay, net);
809 }
810
make_lpm_delays_(struct ivl_lpm_s * obj,const NetObj * net)811 void dll_target::make_lpm_delays_(struct ivl_lpm_s*obj,
812 const NetObj*net)
813 {
814 make_delays_(obj->delay, net);
815 }
816
make_const_delays_(struct ivl_net_const_s * obj,const NetObj * net)817 void dll_target::make_const_delays_(struct ivl_net_const_s*obj,
818 const NetObj*net)
819 {
820 make_delays_(obj->delay, net);
821 }
822
branch(const NetBranch * net)823 bool dll_target::branch(const NetBranch*net)
824 {
825 struct ivl_branch_s*obj = net->target_obj();
826 ivl_assert(*net, net->pin_count() == 2);
827
828 assert(net->pin(0).nexus()->t_cookie());
829 obj->pins[0] = net->pin(0).nexus()->t_cookie();
830 nexus_bra_add(obj->pins[0], obj, 0);
831
832 assert(net->pin(1).nexus()->t_cookie());
833 obj->pins[1] = net->pin(1).nexus()->t_cookie();
834 nexus_bra_add(obj->pins[1], obj, 1);
835
836 obj->island = net->get_island();
837
838 return true;
839 }
840
841 /*
842 * Add a bufz object to the scope that contains it.
843 *
844 * Note that in the ivl_target API a BUFZ device is a special kind of
845 * ivl_net_logic_t device, so create an ivl_net_logic_t cookie to
846 * handle it.
847 */
bufz(const NetBUFZ * net)848 bool dll_target::bufz(const NetBUFZ*net)
849 {
850 struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
851
852 assert(net->pin_count() == 2);
853
854 obj->type_ = net->transparent()? IVL_LO_BUFT : IVL_LO_BUFZ;
855 obj->width_= net->width();
856 obj->is_cassign = 0;
857 obj->npins_= 2;
858 obj->pins_ = new ivl_nexus_t[2];
859 FILE_NAME(obj, net);
860
861 /* Get the ivl_nexus_t objects connected to the two pins.
862
863 (We know a priori that the ivl_nexus_t objects have been
864 allocated, because the signals have been scanned before
865 me. This saves me the trouble of allocating them.) */
866
867 assert(net->pin(0).nexus()->t_cookie());
868 obj->pins_[0] = net->pin(0).nexus()->t_cookie();
869 ivl_nexus_ptr_t out_ptr = nexus_log_add(obj->pins_[0], obj, 0);
870
871 out_ptr->drive0 = net->pin(0).drive0();
872 out_ptr->drive1 = net->pin(0).drive1();
873
874 assert(net->pin(1).nexus()->t_cookie());
875 obj->pins_[1] = net->pin(1).nexus()->t_cookie();
876 nexus_log_add(obj->pins_[1], obj, 1);
877
878 /* Attach the logic device to the scope that contains it. */
879
880 assert(net->scope());
881 ivl_scope_t scop = find_scope(des_, net->scope());
882 assert(scop);
883
884 obj->scope_ = scop;
885
886 obj->name_ = net->name();
887 logic_attributes(obj, net);
888
889 make_logic_delays_(obj, net);
890
891 scope_add_logic(scop, obj);
892
893 return true;
894 }
895
class_type(const NetScope * in_scope,netclass_t * net)896 bool dll_target::class_type(const NetScope*in_scope, netclass_t*net)
897 {
898 ivl_scope_t use_scope = find_scope(des_, in_scope);
899 use_scope->classes.push_back(net);
900 return true;
901 }
902
enumeration(const NetScope * in_scope,netenum_t * net)903 bool dll_target::enumeration(const NetScope*in_scope, netenum_t*net)
904 {
905 ivl_scope_t use_scope = find_scope(des_, in_scope);
906 use_scope->enumerations_.push_back(net);
907 return true;
908 }
909
event(const NetEvent * net)910 void dll_target::event(const NetEvent*net)
911 {
912 struct ivl_event_s *obj = new struct ivl_event_s;
913
914 FILE_NAME(obj, net);
915
916 ivl_scope_t scop = find_scope(des_, net->scope());
917 obj->name = net->name();
918 obj->scope = scop;
919 scope_add_event(scop, obj);
920
921 obj->nany = 0;
922 obj->nneg = 0;
923 obj->npos = 0;
924
925 if (net->nprobe() >= 1) {
926
927 for (unsigned idx = 0 ; idx < net->nprobe() ; idx += 1) {
928 const NetEvProbe*pr = net->probe(idx);
929 switch (pr->edge()) {
930 case NetEvProbe::ANYEDGE:
931 obj->nany += pr->pin_count();
932 break;
933 case NetEvProbe::NEGEDGE:
934 obj->nneg += pr->pin_count();
935 break;
936 case NetEvProbe::POSEDGE:
937 obj->npos += pr->pin_count();
938 break;
939 }
940 }
941
942 unsigned npins = obj->nany + obj->nneg + obj->npos;
943 obj->pins = (ivl_nexus_t*)calloc(npins, sizeof(ivl_nexus_t));
944
945 } else {
946 obj->pins = 0;
947 }
948
949 }
950
logic(const NetLogic * net)951 void dll_target::logic(const NetLogic*net)
952 {
953 struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
954
955 obj->width_ = net->width();
956
957 FILE_NAME(obj, net);
958
959 switch (net->type()) {
960 case NetLogic::AND:
961 obj->type_ = IVL_LO_AND;
962 break;
963 case NetLogic::BUF:
964 obj->type_ = IVL_LO_BUF;
965 break;
966 case NetLogic::BUFIF0:
967 obj->type_ = IVL_LO_BUFIF0;
968 break;
969 case NetLogic::BUFIF1:
970 obj->type_ = IVL_LO_BUFIF1;
971 break;
972 case NetLogic::CMOS:
973 obj->type_ = IVL_LO_CMOS;
974 break;
975 case NetLogic::EQUIV:
976 obj->type_ = IVL_LO_EQUIV;
977 break;
978 case NetLogic::IMPL:
979 obj->type_ = IVL_LO_IMPL;
980 break;
981 case NetLogic::NAND:
982 obj->type_ = IVL_LO_NAND;
983 break;
984 case NetLogic::NMOS:
985 obj->type_ = IVL_LO_NMOS;
986 break;
987 case NetLogic::NOR:
988 obj->type_ = IVL_LO_NOR;
989 break;
990 case NetLogic::NOT:
991 obj->type_ = IVL_LO_NOT;
992 break;
993 case NetLogic::NOTIF0:
994 obj->type_ = IVL_LO_NOTIF0;
995 break;
996 case NetLogic::NOTIF1:
997 obj->type_ = IVL_LO_NOTIF1;
998 break;
999 case NetLogic::OR:
1000 obj->type_ = IVL_LO_OR;
1001 break;
1002 case NetLogic::PULLDOWN:
1003 obj->type_ = IVL_LO_PULLDOWN;
1004 break;
1005 case NetLogic::PULLUP:
1006 obj->type_ = IVL_LO_PULLUP;
1007 break;
1008 case NetLogic::RCMOS:
1009 obj->type_ = IVL_LO_RCMOS;
1010 break;
1011 case NetLogic::RNMOS:
1012 obj->type_ = IVL_LO_RNMOS;
1013 break;
1014 case NetLogic::RPMOS:
1015 obj->type_ = IVL_LO_RPMOS;
1016 break;
1017 case NetLogic::PMOS:
1018 obj->type_ = IVL_LO_PMOS;
1019 break;
1020 case NetLogic::XNOR:
1021 obj->type_ = IVL_LO_XNOR;
1022 break;
1023 case NetLogic::XOR:
1024 obj->type_ = IVL_LO_XOR;
1025 break;
1026 default:
1027 assert(0);
1028 obj->type_ = IVL_LO_NONE;
1029 break;
1030 }
1031 /* Some of the logical gates are used to represent operators in a
1032 * continuous assignment, so set a flag if that is the case. */
1033 obj->is_cassign = net->is_cassign();
1034
1035 /* Connect all the ivl_nexus_t objects to the pins of the
1036 device. */
1037
1038 obj->npins_ = net->pin_count();
1039 obj->pins_ = new ivl_nexus_t[obj->npins_];
1040
1041 for (unsigned idx = 0 ; idx < obj->npins_ ; idx += 1) {
1042 const Nexus*nex = net->pin(idx).nexus();
1043 assert(nex->t_cookie());
1044 obj->pins_[idx] = nex->t_cookie();
1045 ivl_nexus_ptr_t tmp = nexus_log_add(obj->pins_[idx], obj, idx);
1046 if (idx == 0) {
1047 tmp->drive0 = net->pin(0).drive0();
1048 tmp->drive1 = net->pin(0).drive1();
1049 }
1050 }
1051
1052 assert(net->scope());
1053 ivl_scope_t scop = find_scope(des_, net->scope());
1054 assert(scop);
1055
1056 obj->scope_= scop;
1057 obj->name_ = net->name();
1058
1059 logic_attributes(obj, net);
1060
1061 make_logic_delays_(obj, net);
1062
1063 scope_add_logic(scop, obj);
1064 }
1065
tran(const NetTran * net)1066 bool dll_target::tran(const NetTran*net)
1067 {
1068 struct ivl_switch_s*obj = new struct ivl_switch_s;
1069 obj->type = net->type();
1070 obj->width = net->vector_width();
1071 obj->part = 0;
1072 obj->offset = 0;
1073 obj->name = net->name();
1074 obj->scope = find_scope(des_, net->scope());
1075 obj->island = net->get_island();
1076 assert(obj->scope);
1077 assert(obj->island);
1078 FILE_NAME(obj, net);
1079
1080 const Nexus*nex;
1081
1082 nex = net->pin(0).nexus();
1083 assert(nex->t_cookie());
1084 obj->pins[0] = nex->t_cookie();
1085
1086 nex = net->pin(1).nexus();
1087 assert(nex->t_cookie());
1088 obj->pins[1] = nex->t_cookie();
1089
1090 nexus_switch_add(obj->pins[0], obj, 0);
1091 nexus_switch_add(obj->pins[1], obj, 1);
1092
1093 if (net->pin_count() > 2) {
1094 nex = net->pin(2).nexus();
1095 assert(nex->t_cookie());
1096 obj->pins[2] = nex->t_cookie();
1097 nexus_switch_add(obj->pins[2], obj, 2);
1098 } else {
1099 obj->pins[2] = 0;
1100 }
1101
1102 if (obj->type == IVL_SW_TRAN_VP) {
1103 obj->part = net->part_width();
1104 obj->offset= net->part_offset();
1105 }
1106
1107 switch_attributes(obj, net);
1108 make_switch_delays_(obj, net);
1109 scope_add_switch(obj->scope, obj);
1110
1111 return true;
1112 }
1113
substitute(const NetSubstitute * net)1114 bool dll_target::substitute(const NetSubstitute*net)
1115 {
1116 ivl_lpm_t obj = new struct ivl_lpm_s;
1117 obj->type = IVL_LPM_SUBSTITUTE;
1118 obj->name = net->name();
1119 assert(net->scope());
1120 obj->scope = find_scope(des_, net->scope());
1121 assert(obj->scope);
1122 FILE_NAME(obj, net);
1123
1124 obj->width = net->width();
1125 obj->u_.substitute.base = net->base();
1126
1127 obj->u_.substitute.q = net->pin(0).nexus()->t_cookie();
1128 obj->u_.substitute.a = net->pin(1).nexus()->t_cookie();
1129 obj->u_.substitute.s = net->pin(2).nexus()->t_cookie();
1130 nexus_lpm_add(obj->u_.substitute.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1131 nexus_lpm_add(obj->u_.substitute.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1132 nexus_lpm_add(obj->u_.substitute.s, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1133
1134 make_lpm_delays_(obj, net);
1135 scope_add_lpm(obj->scope, obj);
1136
1137 return true;
1138 }
1139
sign_extend(const NetSignExtend * net)1140 bool dll_target::sign_extend(const NetSignExtend*net)
1141 {
1142 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1143 obj->type = IVL_LPM_SIGN_EXT;
1144 obj->width = net->width();
1145 obj->name = net->name();
1146 obj->scope = find_scope(des_, net->scope());
1147 assert(obj->scope);
1148 FILE_NAME(obj, net);
1149
1150 const Nexus*nex;
1151
1152 nex = net->pin(0).nexus();
1153 assert(nex->t_cookie());
1154
1155 obj->u_.reduce.q = nex->t_cookie();
1156 nexus_lpm_add(obj->u_.reduce.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1157
1158 nex = net->pin(1).nexus();
1159 assert(nex->t_cookie());
1160
1161 obj->u_.reduce.a = nex->t_cookie();
1162 nexus_lpm_add(obj->u_.reduce.a, obj, 1, IVL_DR_HiZ, IVL_DR_HiZ);
1163
1164 make_lpm_delays_(obj, net);
1165
1166 scope_add_lpm(obj->scope, obj);
1167
1168 return true;
1169 }
1170
ureduce(const NetUReduce * net)1171 bool dll_target::ureduce(const NetUReduce*net)
1172 {
1173 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1174 switch (net->type()) {
1175 case NetUReduce::NONE:
1176 assert(0);
1177 delete obj;
1178 return false;
1179 case NetUReduce::AND:
1180 obj->type = IVL_LPM_RE_AND;
1181 break;
1182 case NetUReduce::OR:
1183 obj->type = IVL_LPM_RE_OR;
1184 break;
1185 case NetUReduce::XOR:
1186 obj->type = IVL_LPM_RE_XOR;
1187 break;
1188 case NetUReduce::NAND:
1189 obj->type = IVL_LPM_RE_NAND;
1190 break;
1191 case NetUReduce::NOR:
1192 obj->type = IVL_LPM_RE_NOR;
1193 break;
1194 case NetUReduce::XNOR:
1195 obj->type = IVL_LPM_RE_XNOR;
1196 break;
1197 }
1198
1199 obj->name = net->name();
1200 obj->scope = find_scope(des_, net->scope());
1201 assert(obj->scope);
1202 FILE_NAME(obj, net);
1203
1204 obj->width = net->width();
1205
1206 const Nexus*nex;
1207
1208 nex = net->pin(0).nexus();
1209 assert(nex->t_cookie());
1210
1211 obj->u_.reduce.q = nex->t_cookie();
1212 nexus_lpm_add(obj->u_.reduce.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1213
1214 nex = net->pin(1).nexus();
1215 assert(nex->t_cookie());
1216
1217 obj->u_.reduce.a = nex->t_cookie();
1218 nexus_lpm_add(obj->u_.reduce.a, obj, 1, IVL_DR_HiZ, IVL_DR_HiZ);
1219
1220 make_lpm_delays_(obj, net);
1221
1222 scope_add_lpm(obj->scope, obj);
1223
1224 return true;
1225 }
1226
net_case_cmp(const NetCaseCmp * net)1227 void dll_target::net_case_cmp(const NetCaseCmp*net)
1228 {
1229 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1230 switch (net->kind()) {
1231 case NetCaseCmp::EEQ:
1232 obj->type = IVL_LPM_CMP_EEQ;
1233 break;
1234 case NetCaseCmp::NEQ:
1235 obj->type = IVL_LPM_CMP_NEE;
1236 break;
1237 case NetCaseCmp::WEQ:
1238 obj->type = IVL_LPM_CMP_WEQ;
1239 break;
1240 case NetCaseCmp::WNE:
1241 obj->type = IVL_LPM_CMP_WNE;
1242 break;
1243 case NetCaseCmp::XEQ:
1244 obj->type = IVL_LPM_CMP_EQX;
1245 break;
1246 case NetCaseCmp::ZEQ:
1247 obj->type = IVL_LPM_CMP_EQZ;
1248 break;
1249 }
1250 obj->name = net->name();
1251 obj->scope = find_scope(des_, net->scope());
1252 assert(obj->scope);
1253 FILE_NAME(obj, net);
1254
1255 obj->width = net->width();
1256 obj->u_.arith.signed_flag = 0;
1257
1258 const Nexus*nex;
1259
1260 nex = net->pin(1).nexus();
1261 assert(nex->t_cookie());
1262
1263 obj->u_.arith.a = nex->t_cookie();
1264 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1265
1266 nex = net->pin(2).nexus();
1267 assert(nex->t_cookie());
1268
1269 obj->u_.arith.b = nex->t_cookie();
1270 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1271
1272 nex = net->pin(0).nexus();
1273 assert(nex->t_cookie());
1274
1275 obj->u_.arith.q = nex->t_cookie();
1276 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1277
1278 make_lpm_delays_(obj, net);
1279
1280 scope_add_lpm(obj->scope, obj);
1281 }
1282
make_lpm_trigger(const NetEvWait * net)1283 ivl_event_t dll_target::make_lpm_trigger(const NetEvWait*net)
1284 {
1285 ivl_event_t trigger = 0;
1286 if (net) {
1287 const NetEvent*ev = net->event(0);
1288
1289 /* Locate the event by name. */
1290 ivl_scope_t ev_scope = lookup_scope_(ev->scope());
1291
1292 assert(ev_scope);
1293 assert(ev_scope->nevent_ > 0);
1294 for (unsigned idx = 0; idx < ev_scope->nevent_; idx += 1) {
1295 const char*ename =
1296 ivl_event_basename(ev_scope->event_[idx]);
1297 if (strcmp(ev->name(), ename) == 0) {
1298 trigger = ev_scope->event_[idx];
1299 break;
1300 }
1301 }
1302
1303 /* Connect up the probe pins. This wasn't done during the
1304 ::event method because the signals weren't scanned yet. */
1305 assert(ev->nprobe() == 1);
1306 const NetEvProbe*pr = ev->probe(0);
1307 for (unsigned bit = 0; bit < pr->pin_count(); bit += 1) {
1308 ivl_nexus_t nex = (ivl_nexus_t)
1309 pr->pin(bit).nexus()->t_cookie();
1310 assert(nex);
1311 trigger->pins[bit] = nex;
1312 }
1313 }
1314 return trigger;
1315 }
1316
net_sysfunction(const NetSysFunc * net)1317 bool dll_target::net_sysfunction(const NetSysFunc*net)
1318 {
1319 unsigned idx;
1320 const Nexus*nex;
1321
1322 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1323 obj->type = IVL_LPM_SFUNC;
1324 obj->name = net->name();
1325 obj->scope = find_scope(des_, net->scope());
1326 assert(obj->scope);
1327 FILE_NAME(obj, net);
1328
1329 obj->u_.sfunc.ports = net->pin_count();
1330
1331 assert(net->pin_count() >= 1);
1332 obj->width = net->vector_width();
1333
1334 obj->u_.sfunc.fun_name = net->func_name();
1335
1336 obj->u_.sfunc.pins = new ivl_nexus_t[net->pin_count()];
1337
1338 nex = net->pin(0).nexus();
1339 assert(nex->t_cookie());
1340
1341 obj->u_.sfunc.pins[0] = nex->t_cookie();
1342 nexus_lpm_add(obj->u_.sfunc.pins[0], obj, 0,
1343 IVL_DR_STRONG, IVL_DR_STRONG);
1344
1345 for (idx = 1 ; idx < net->pin_count() ; idx += 1) {
1346 nex = net->pin(idx).nexus();
1347 assert(nex->t_cookie());
1348
1349 obj->u_.sfunc.pins[idx] = nex->t_cookie();
1350 nexus_lpm_add(obj->u_.sfunc.pins[idx], obj, 0,
1351 IVL_DR_HiZ, IVL_DR_HiZ);
1352 }
1353
1354 /* Save information about the trigger event if it exists. */
1355 obj->u_.sfunc.trigger = make_lpm_trigger(net->trigger());
1356
1357 make_lpm_delays_(obj, net);
1358
1359 scope_add_lpm(obj->scope, obj);
1360 return true;
1361 }
1362
1363 /*
1364 * An IVL_LPM_UFUNC represents a node in a combinational expression
1365 * that calls a user defined function. I create an LPM object that has
1366 * the right connections, and refers to the ivl_scope_t of the
1367 * definition.
1368 */
net_function(const NetUserFunc * net)1369 bool dll_target::net_function(const NetUserFunc*net)
1370 {
1371 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1372 obj->type = IVL_LPM_UFUNC;
1373 obj->name = net->name();
1374 obj->scope = find_scope(des_, net->scope());
1375 assert(obj->scope);
1376 FILE_NAME(obj, net);
1377
1378 /* Get the definition of the function and save it. */
1379 const NetScope*def = net->def();
1380 assert(def);
1381
1382 obj->u_.ufunc.def = lookup_scope_(def);
1383
1384 /* Save information about the ports in the ivl_lpm_s
1385 structure. Note that port 0 is the return value. */
1386 obj->u_.ufunc.ports = net->pin_count();
1387
1388 assert(net->pin_count() >= 1);
1389 obj->width = net->port_width(0);
1390
1391 /* Now collect all the pins and connect them to the nexa of
1392 the net. The output pins have strong drive, and the
1393 remaining input pins are HiZ. */
1394
1395 obj->u_.ufunc.pins = new ivl_nexus_t[net->pin_count()];
1396
1397 for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
1398 const Nexus*nex = net->pin(idx).nexus();
1399 assert(nex->t_cookie());
1400 ivl_nexus_t nn = nex->t_cookie();
1401 assert(nn);
1402
1403 obj->u_.ufunc.pins[idx] = nn;
1404 ivl_drive_t drive = idx == 0 ? IVL_DR_STRONG : IVL_DR_HiZ;
1405 nexus_lpm_add(obj->u_.ufunc.pins[idx], obj, idx, drive, drive);
1406 }
1407
1408 /* Save information about the trigger event if it exists. */
1409 obj->u_.ufunc.trigger = make_lpm_trigger(net->trigger());
1410
1411 make_lpm_delays_(obj, net);
1412
1413 /* All done. Add this LPM to the scope. */
1414 scope_add_lpm(obj->scope, obj);
1415
1416 return true;
1417 }
1418
udp(const NetUDP * net)1419 void dll_target::udp(const NetUDP*net)
1420 {
1421 struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
1422
1423 obj->type_ = IVL_LO_UDP;
1424 FILE_NAME(obj, net);
1425
1426 /* The NetUDP class hasn't learned about width yet, so we
1427 assume a width of 1. */
1428 obj->width_ = 1;
1429 obj->is_cassign = 0;
1430
1431 static map<perm_string,ivl_udp_t> udps;
1432 ivl_udp_t u;
1433
1434 if (udps.find(net->udp_name()) != udps.end()) {
1435 u = udps[net->udp_name()];
1436 } else {
1437 u = new struct ivl_udp_s;
1438 u->nrows = net->rows();
1439 u->table = (ivl_udp_s::ccharp_t*)malloc((u->nrows+1)*sizeof(char*));
1440 u->table[u->nrows] = 0x0;
1441 u->nin = net->nin();
1442 u->sequ = net->is_sequential();
1443 u->file = net->udp_file();
1444 u->lineno = net->udp_lineno();
1445 if (u->sequ) u->init = net->get_initial();
1446 else u->init = 'x';
1447 u->name = net->udp_name();
1448 string inp;
1449 char out;
1450 unsigned int i = 0;
1451 if (net->first(inp, out)) do {
1452 string tt = inp+out;
1453 u->table[i++] = strings_.add(tt.c_str());
1454 } while (net->next(inp, out));
1455 assert(i==u->nrows);
1456 assert((u->nin + 1) == net->port_count());
1457 u->ports = new string [u->nin + 1];
1458 for(unsigned idx = 0; idx <= u->nin; idx += 1) {
1459 u->ports[idx] = net->port_name(idx);
1460 }
1461
1462 udps[net->udp_name()] = u;
1463 }
1464
1465 obj->udp = u;
1466
1467 // Some duplication of code here, see: dll_target::logic()
1468
1469 /* Connect all the ivl_nexus_t objects to the pins of the
1470 device. */
1471
1472 obj->npins_ = net->pin_count();
1473 obj->pins_ = new ivl_nexus_t[obj->npins_];
1474 for (unsigned idx = 0 ; idx < obj->npins_ ; idx += 1) {
1475 /* Skip unconnected input pins. These will take on HiZ
1476 values by the code generators. */
1477 if (! net->pin(idx).is_linked()) {
1478 obj->pins_[idx] = 0;
1479 continue;
1480 }
1481
1482 const Nexus*nex = net->pin(idx).nexus();
1483 ivl_assert(*net, nex && nex->t_cookie());
1484 obj->pins_[idx] = nex->t_cookie();
1485 nexus_log_add(obj->pins_[idx], obj, idx);
1486 }
1487
1488 assert(net->scope());
1489 ivl_scope_t scop = find_scope(des_, net->scope());
1490 assert(scop);
1491
1492 obj->scope_= scop;
1493 obj->name_ = net->name();
1494 FILE_NAME(obj, net);
1495
1496 make_logic_delays_(obj, net);
1497
1498 obj->nattr = 0;
1499 obj->attr = 0;
1500
1501 scope_add_logic(scop, obj);
1502 }
1503
lpm_abs(const NetAbs * net)1504 void dll_target::lpm_abs(const NetAbs*net)
1505 {
1506 ivl_lpm_t obj = new struct ivl_lpm_s;
1507 obj->type = IVL_LPM_ABS;
1508 obj->name = net->name(); // NetAddSub names are permallocated.
1509 assert(net->scope());
1510 obj->scope = find_scope(des_, net->scope());
1511 assert(obj->scope);
1512 FILE_NAME(obj, net);
1513
1514 obj->u_.arith.signed_flag = 0;
1515 obj->width = net->width();
1516
1517 const Nexus*nex;
1518 /* the output is pin(0) */
1519 nex = net->pin(0).nexus();
1520 assert(nex->t_cookie());
1521
1522 obj->u_.arith.q = nex->t_cookie();
1523 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1524
1525 nex = net->pin(1).nexus();
1526 assert(nex->t_cookie());
1527
1528 /* pin(1) is the input data. */
1529 obj->u_.arith.a = nex->t_cookie();
1530 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1531
1532 make_lpm_delays_(obj, net);
1533
1534 scope_add_lpm(obj->scope, obj);
1535 }
1536
lpm_add_sub(const NetAddSub * net)1537 void dll_target::lpm_add_sub(const NetAddSub*net)
1538 {
1539 ivl_lpm_t obj = new struct ivl_lpm_s;
1540 if (net->attribute(perm_string::literal("LPM_Direction")) == verinum("SUB"))
1541 obj->type = IVL_LPM_SUB;
1542 else
1543 obj->type = IVL_LPM_ADD;
1544 obj->name = net->name(); // NetAddSub names are permallocated.
1545 assert(net->scope());
1546 obj->scope = find_scope(des_, net->scope());
1547 assert(obj->scope);
1548 FILE_NAME(obj, net);
1549
1550 obj->u_.arith.signed_flag = 0;
1551
1552 /* Choose the width of the adder. If the carry bit is
1553 connected, then widen the adder by one and plan on leaving
1554 the fake inputs unconnected. */
1555 obj->width = net->width();
1556 if (net->pin_Cout().is_linked()) {
1557 obj->width += 1;
1558 }
1559
1560
1561 const Nexus*nex;
1562
1563 nex = net->pin_Result().nexus();
1564 assert(nex->t_cookie());
1565
1566 obj->u_.arith.q = nex->t_cookie();
1567 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1568
1569 nex = net->pin_DataA().nexus();
1570 assert(nex->t_cookie());
1571
1572 obj->u_.arith.a = nex->t_cookie();
1573 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1574
1575 nex = net->pin_DataB().nexus();
1576 assert(nex->t_cookie());
1577
1578 obj->u_.arith.b = nex->t_cookie();
1579 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1580
1581 /* If the carry output is connected, then connect the extra Q
1582 pin to the carry nexus and zero the a and b inputs. */
1583 if (net->pin_Cout().is_linked()) {
1584 cerr << "XXXX: t-dll.cc: Forgot how to connect cout." << endl;
1585 }
1586
1587 make_lpm_delays_(obj, net);
1588
1589 scope_add_lpm(obj->scope, obj);
1590 }
1591
lpm_array_dq(const NetArrayDq * net)1592 bool dll_target::lpm_array_dq(const NetArrayDq*net)
1593 {
1594 ivl_lpm_t obj = new struct ivl_lpm_s;
1595 obj->type = IVL_LPM_ARRAY;
1596 obj->name = net->name();
1597 obj->u_.array.sig = find_signal(des_, net->mem());
1598 assert(obj->u_.array.sig);
1599 obj->scope = find_scope(des_, net->scope());
1600 assert(obj->scope);
1601 FILE_NAME(obj, net);
1602 obj->width = net->width();
1603 obj->u_.array.swid = net->awidth();
1604
1605 make_lpm_delays_(obj, net);
1606
1607 scope_add_lpm(obj->scope, obj);
1608
1609 const Nexus*nex;
1610
1611 nex = net->pin_Address().nexus();
1612 assert(nex->t_cookie());
1613 obj->u_.array.a = nex->t_cookie();
1614 nexus_lpm_add(obj->u_.array.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1615
1616 nex = net->pin_Result().nexus();
1617 assert(nex->t_cookie());
1618 obj->u_.array.q = nex->t_cookie();
1619 nexus_lpm_add(obj->u_.array.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1620
1621 return true;
1622 }
1623
1624 /*
1625 * The lpm_clshift device represents both left and right shifts,
1626 * depending on what is connected to the Direction pin. We convert
1627 * this device into SHIFTL or SHIFTR devices.
1628 */
lpm_clshift(const NetCLShift * net)1629 void dll_target::lpm_clshift(const NetCLShift*net)
1630 {
1631 ivl_lpm_t obj = new struct ivl_lpm_s;
1632 obj->type = IVL_LPM_SHIFTL;
1633 obj->name = net->name();
1634 assert(net->scope());
1635 obj->scope = find_scope(des_, net->scope());
1636 assert(obj->scope);
1637 FILE_NAME(obj, net);
1638
1639 /* Look at the direction input of the device, and select the
1640 shift direction accordingly. */
1641 if (net->right_flag())
1642 obj->type = IVL_LPM_SHIFTR;
1643 if (net->signed_flag())
1644 obj->u_.shift.signed_flag = 1;
1645 else
1646 obj->u_.shift.signed_flag = 0;
1647
1648 obj->width = net->width();
1649 obj->u_.shift.select = net->width_dist();
1650
1651 const Nexus*nex;
1652
1653 nex = net->pin_Result().nexus();
1654 assert(nex->t_cookie());
1655
1656 obj->u_.shift.q = nex->t_cookie();
1657 nexus_lpm_add(obj->u_.shift.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1658
1659 nex = net->pin_Data().nexus();
1660 assert(nex->t_cookie());
1661
1662 obj->u_.shift.d = nex->t_cookie();
1663 nexus_lpm_add(obj->u_.shift.d, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1664
1665 nex = net->pin_Distance().nexus();
1666 assert(nex->t_cookie());
1667
1668 obj->u_.shift.s = nex->t_cookie();
1669 nexus_lpm_add(obj->u_.shift.s, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1670
1671 make_lpm_delays_(obj, net);
1672
1673 scope_add_lpm(obj->scope, obj);
1674 }
1675
lpm_arith1_(ivl_lpm_type_t lpm_type,unsigned width,bool signed_flag,const NetNode * net)1676 bool dll_target::lpm_arith1_(ivl_lpm_type_t lpm_type, unsigned width, bool signed_flag, const NetNode*net)
1677 {
1678 ivl_lpm_t obj = new struct ivl_lpm_s;
1679 obj->type = lpm_type;
1680 obj->name = net->name(); // NetCastInt2 names are permallocated
1681 assert(net->scope());
1682 obj->scope = find_scope(des_, net->scope());
1683 assert(obj->scope);
1684 FILE_NAME(obj, net);
1685
1686 obj->width = width;
1687 obj->u_.arith.signed_flag = signed_flag? 1 : 0;
1688
1689 const Nexus*nex;
1690
1691 nex = net->pin(0).nexus();
1692 assert(nex->t_cookie());
1693
1694 obj->u_.arith.q = nex->t_cookie();
1695
1696 nex = net->pin(1).nexus();
1697 assert(nex->t_cookie());
1698 obj->u_.arith.a = nex->t_cookie();
1699
1700 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1701 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1702
1703 make_lpm_delays_(obj, net);
1704
1705 scope_add_lpm(obj->scope, obj);
1706
1707 return true;
1708 }
1709
lpm_cast_int2(const NetCastInt2 * net)1710 bool dll_target::lpm_cast_int2(const NetCastInt2*net)
1711 {
1712 return lpm_arith1_(IVL_LPM_CAST_INT2, net->width(), true, net);
1713 }
1714
lpm_cast_int4(const NetCastInt4 * net)1715 bool dll_target::lpm_cast_int4(const NetCastInt4*net)
1716 {
1717 return lpm_arith1_(IVL_LPM_CAST_INT, net->width(), true, net);
1718 }
1719
lpm_cast_real(const NetCastReal * net)1720 bool dll_target::lpm_cast_real(const NetCastReal*net)
1721 {
1722 return lpm_arith1_(IVL_LPM_CAST_REAL, 0, net->signed_flag(), net);
1723 }
1724
1725 /*
1726 * Make out of the NetCompare object an ivl_lpm_s object. The
1727 * comparators in ivl_target do not support < or <=, but they can be
1728 * trivially converted to > and >= by swapping the operands.
1729 */
lpm_compare(const NetCompare * net)1730 void dll_target::lpm_compare(const NetCompare*net)
1731 {
1732 ivl_lpm_t obj = new struct ivl_lpm_s;
1733 obj->name = net->name(); // NetCompare names are permallocated
1734 assert(net->scope());
1735 obj->scope = find_scope(des_, net->scope());
1736 assert(obj->scope);
1737 FILE_NAME(obj, net);
1738
1739 bool swap_operands = false;
1740
1741 obj->width = net->width();
1742 obj->u_.arith.signed_flag = net->get_signed()? 1 : 0;
1743
1744 const Nexus*nex;
1745
1746 nex = net->pin_DataA().nexus();
1747 assert(nex->t_cookie());
1748
1749 obj->u_.arith.a = nex->t_cookie();
1750
1751 nex = net->pin_DataB().nexus();
1752 assert(nex->t_cookie());
1753
1754 obj->u_.arith.b = nex->t_cookie();
1755
1756
1757 if (net->pin_AGEB().is_linked()) {
1758 nex = net->pin_AGEB().nexus();
1759 obj->type = IVL_LPM_CMP_GE;
1760
1761 assert(nex->t_cookie());
1762 obj->u_.arith.q = nex->t_cookie();
1763 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1764 IVL_DR_STRONG, IVL_DR_STRONG);
1765
1766 } else if (net->pin_AGB().is_linked()) {
1767 nex = net->pin_AGB().nexus();
1768 obj->type = IVL_LPM_CMP_GT;
1769
1770 assert(nex->t_cookie());
1771 obj->u_.arith.q = nex->t_cookie();
1772 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1773 IVL_DR_STRONG, IVL_DR_STRONG);
1774
1775 } else if (net->pin_ALEB().is_linked()) {
1776 nex = net->pin_ALEB().nexus();
1777 obj->type = IVL_LPM_CMP_GE;
1778
1779 assert(nex->t_cookie());
1780 obj->u_.arith.q = nex->t_cookie();
1781 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1782 IVL_DR_STRONG, IVL_DR_STRONG);
1783
1784 swap_operands = true;
1785
1786 } else if (net->pin_ALB().is_linked()) {
1787 nex = net->pin_ALB().nexus();
1788 obj->type = IVL_LPM_CMP_GT;
1789
1790 assert(nex->t_cookie());
1791 obj->u_.arith.q = nex->t_cookie();
1792 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1793 IVL_DR_STRONG, IVL_DR_STRONG);
1794
1795 swap_operands = true;
1796
1797 } else if (net->pin_AEB().is_linked()) {
1798 nex = net->pin_AEB().nexus();
1799 obj->type = IVL_LPM_CMP_EQ;
1800
1801 assert(nex->t_cookie());
1802 obj->u_.arith.q = nex->t_cookie();
1803 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1804 IVL_DR_STRONG, IVL_DR_STRONG);
1805
1806 } else if (net->pin_ANEB().is_linked()) {
1807 nex = net->pin_ANEB().nexus();
1808 obj->type = IVL_LPM_CMP_NE;
1809
1810 assert(nex->t_cookie());
1811 obj->u_.arith.q = nex->t_cookie();
1812 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1813 IVL_DR_STRONG, IVL_DR_STRONG);
1814
1815 } else {
1816 assert(0);
1817 }
1818
1819 if (swap_operands) {
1820 ivl_nexus_t tmp = obj->u_.arith.a;
1821 obj->u_.arith.a = obj->u_.arith.b;
1822 obj->u_.arith.b = tmp;
1823 }
1824
1825 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1826 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1827
1828 make_lpm_delays_(obj, net);
1829
1830 scope_add_lpm(obj->scope, obj);
1831 }
1832
lpm_divide(const NetDivide * net)1833 void dll_target::lpm_divide(const NetDivide*net)
1834 {
1835 ivl_lpm_t obj = new struct ivl_lpm_s;
1836 obj->type = IVL_LPM_DIVIDE;
1837 obj->name = net->name();
1838 assert(net->scope());
1839 obj->scope = find_scope(des_, net->scope());
1840 assert(obj->scope);
1841 FILE_NAME(obj, net);
1842
1843 unsigned wid = net->width_r();
1844
1845 obj->width = wid;
1846 obj->u_.arith.signed_flag = net->get_signed()? 1 : 0;
1847
1848 const Nexus*nex;
1849
1850 nex = net->pin_Result().nexus();
1851 assert(nex->t_cookie());
1852
1853 obj->u_.arith.q = nex->t_cookie();
1854 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1855
1856 nex = net->pin_DataA().nexus();
1857 assert(nex->t_cookie());
1858
1859 obj->u_.arith.a = nex->t_cookie();
1860 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1861
1862 nex = net->pin_DataB().nexus();
1863 assert(nex->t_cookie());
1864
1865 obj->u_.arith.b = nex->t_cookie();
1866 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1867
1868 make_lpm_delays_(obj, net);
1869
1870 scope_add_lpm(obj->scope, obj);
1871 }
1872
lpm_modulo(const NetModulo * net)1873 void dll_target::lpm_modulo(const NetModulo*net)
1874 {
1875 ivl_lpm_t obj = new struct ivl_lpm_s;
1876 obj->type = IVL_LPM_MOD;
1877 obj->name = net->name();
1878 assert(net->scope());
1879 obj->scope = find_scope(des_, net->scope());
1880 assert(obj->scope);
1881 FILE_NAME(obj, net);
1882
1883 unsigned wid = net->width_r();
1884
1885 obj->width = wid;
1886 obj->u_.arith.signed_flag = net->get_signed()? 1 : 0;
1887
1888 const Nexus*nex;
1889
1890 nex = net->pin_Result().nexus();
1891 assert(nex->t_cookie());
1892
1893 obj->u_.arith.q = nex->t_cookie();
1894 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1895
1896 nex = net->pin_DataA().nexus();
1897 assert(nex->t_cookie());
1898
1899 obj->u_.arith.a = nex->t_cookie();
1900 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1901
1902 nex = net->pin_DataB().nexus();
1903 assert(nex->t_cookie());
1904
1905 obj->u_.arith.b = nex->t_cookie();
1906 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1907
1908 make_lpm_delays_(obj, net);
1909
1910 scope_add_lpm(obj->scope, obj);
1911 }
1912
lpm_ff(const NetFF * net)1913 void dll_target::lpm_ff(const NetFF*net)
1914 {
1915 ivl_lpm_t obj = new struct ivl_lpm_s;
1916 obj->type = IVL_LPM_FF;
1917 obj->name = net->name();
1918 obj->scope = find_scope(des_, net->scope());
1919 assert(obj->scope);
1920 FILE_NAME(obj, net);
1921
1922 obj->width = net->width();
1923
1924 scope_add_lpm(obj->scope, obj);
1925
1926 const Nexus*nex;
1927
1928 /* Set the clock polarity. */
1929 obj->u_.ff.negedge_flag = net->is_negedge();
1930
1931 /* Set the clk signal to point to the nexus, and the nexus to
1932 point back to this device. */
1933 nex = net->pin_Clock().nexus();
1934 assert(nex->t_cookie());
1935 obj->u_.ff.clk = nex->t_cookie();
1936 assert(obj->u_.ff.clk);
1937 nexus_lpm_add(obj->u_.ff.clk, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1938
1939 /* If there is a clock enable, then connect it up to the FF
1940 device. */
1941 if (net->pin_Enable().is_linked()) {
1942 nex = net->pin_Enable().nexus();
1943 assert(nex->t_cookie());
1944 obj->u_.ff.we = nex->t_cookie();
1945 assert(obj->u_.ff.we);
1946 nexus_lpm_add(obj->u_.ff.we, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1947 } else {
1948 obj->u_.ff.we = 0;
1949 }
1950
1951 if (net->pin_Aclr().is_linked()) {
1952 nex = net->pin_Aclr().nexus();
1953 assert(nex->t_cookie());
1954 obj->u_.ff.aclr = nex->t_cookie();
1955 assert(obj->u_.ff.aclr);
1956 nexus_lpm_add(obj->u_.ff.aclr, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1957 } else {
1958 obj->u_.ff.aclr = 0;
1959 }
1960
1961 if (net->pin_Aset().is_linked()) {
1962 nex = net->pin_Aset().nexus();
1963 assert(nex->t_cookie());
1964 obj->u_.ff.aset = nex->t_cookie();
1965 assert(obj->u_.ff.aset);
1966 nexus_lpm_add(obj->u_.ff.aset, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1967
1968 verinum tmp = net->aset_value();
1969 if (tmp.len() > 0)
1970 obj->u_.ff.aset_value = expr_from_value_(tmp);
1971 else
1972 obj->u_.ff.aset_value = 0;
1973
1974 } else {
1975 obj->u_.ff.aset = 0;
1976 obj->u_.ff.aset_value = 0;
1977 }
1978
1979 if (net->pin_Sclr().is_linked()) {
1980 nex = net->pin_Sclr().nexus();
1981 assert(nex->t_cookie());
1982 obj->u_.ff.sclr = nex->t_cookie();
1983 assert(obj->u_.ff.sclr);
1984 nexus_lpm_add(obj->u_.ff.sclr, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1985 } else {
1986 obj->u_.ff.sclr = 0;
1987 }
1988
1989 if (net->pin_Sset().is_linked()) {
1990 nex = net->pin_Sset().nexus();
1991 assert(nex->t_cookie());
1992 obj->u_.ff.sset = nex->t_cookie();
1993 assert(obj->u_.ff.sset);
1994 nexus_lpm_add(obj->u_.ff.sset, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1995
1996 verinum tmp = net->sset_value();
1997 if (tmp.len() > 0)
1998 obj->u_.ff.sset_value = expr_from_value_(tmp);
1999 else
2000 obj->u_.ff.sset_value = 0;
2001
2002 } else {
2003 obj->u_.ff.sset = 0;
2004 obj->u_.ff.sset_value = 0;
2005 }
2006
2007 nex = net->pin_Q().nexus();
2008 assert(nex->t_cookie());
2009 obj->u_.ff.q.pin = nex->t_cookie();
2010 nexus_lpm_add(obj->u_.ff.q.pin, obj, 0,
2011 IVL_DR_STRONG, IVL_DR_STRONG);
2012
2013 nex = net->pin_Data().nexus();
2014 assert(nex->t_cookie());
2015 obj->u_.ff.d.pin = nex->t_cookie();
2016 nexus_lpm_add(obj->u_.ff.d.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
2017 }
2018
lpm_latch(const NetLatch * net)2019 void dll_target::lpm_latch(const NetLatch*net)
2020 {
2021 ivl_lpm_t obj = new struct ivl_lpm_s;
2022 obj->type = IVL_LPM_LATCH;
2023 obj->name = net->name();
2024 obj->scope = find_scope(des_, net->scope());
2025 assert(obj->scope);
2026 FILE_NAME(obj, net);
2027
2028 obj->width = net->width();
2029
2030 scope_add_lpm(obj->scope, obj);
2031
2032 const Nexus*nex;
2033
2034 nex = net->pin_Enable().nexus();
2035 assert(nex->t_cookie());
2036 obj->u_.latch.e = nex->t_cookie();
2037 assert(obj->u_.latch.e);
2038 nexus_lpm_add(obj->u_.latch.e, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
2039
2040 nex = net->pin_Q().nexus();
2041 assert(nex->t_cookie());
2042 obj->u_.latch.q.pin = nex->t_cookie();
2043 nexus_lpm_add(obj->u_.latch.q.pin, obj, 0,
2044 IVL_DR_STRONG, IVL_DR_STRONG);
2045
2046 nex = net->pin_Data().nexus();
2047 assert(nex->t_cookie());
2048 obj->u_.latch.d.pin = nex->t_cookie();
2049 nexus_lpm_add(obj->u_.latch.d.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
2050 }
2051
2052 /*
2053 * Make the NetMult object into an IVL_LPM_MULT node.
2054 */
lpm_mult(const NetMult * net)2055 void dll_target::lpm_mult(const NetMult*net)
2056 {
2057 ivl_lpm_t obj = new struct ivl_lpm_s;
2058 obj->type = IVL_LPM_MULT;
2059 obj->name = net->name();
2060 assert(net->scope());
2061 obj->scope = find_scope(des_, net->scope());
2062 assert(obj->scope);
2063 FILE_NAME(obj, net);
2064
2065 unsigned wid = net->width_r();
2066
2067 obj->width = wid;
2068 obj->u_.arith.signed_flag = 0;
2069
2070 const Nexus*nex;
2071
2072 nex = net->pin_Result().nexus();
2073 assert(nex->t_cookie());
2074
2075 obj->u_.arith.q = nex->t_cookie();
2076 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
2077
2078 nex = net->pin_DataA().nexus();
2079 assert(nex->t_cookie());
2080
2081 obj->u_.arith.a = nex->t_cookie();
2082 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
2083
2084 nex = net->pin_DataB().nexus();
2085 assert(nex->t_cookie());
2086
2087 obj->u_.arith.b = nex->t_cookie();
2088 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
2089
2090 make_lpm_delays_(obj, net);
2091
2092 scope_add_lpm(obj->scope, obj);
2093 }
2094
2095 /*
2096 * Hook up the mux devices so that the select expression selects the
2097 * correct sub-expression with the ivl_lpm_data2 function.
2098 */
lpm_mux(const NetMux * net)2099 void dll_target::lpm_mux(const NetMux*net)
2100 {
2101 ivl_lpm_t obj = new struct ivl_lpm_s;
2102 obj->type = IVL_LPM_MUX;
2103 obj->name = net->name(); // The NetMux permallocates its name.
2104 obj->scope = find_scope(des_, net->scope());
2105 assert(obj->scope);
2106 FILE_NAME(obj, net);
2107
2108 obj->width = net->width();
2109 obj->u_.mux.size = net->size();
2110 obj->u_.mux.swid = net->sel_width();
2111
2112 make_lpm_delays_(obj, net);
2113
2114 scope_add_lpm(obj->scope, obj);
2115
2116 const Nexus*nex;
2117
2118 /* Connect the output bits. */
2119 nex = net->pin_Result().nexus();
2120 assert(nex->t_cookie());
2121 obj->u_.mux.q = nex->t_cookie();
2122 nexus_lpm_add(obj->u_.mux.q, obj, 0,
2123 net->pin_Result().drive0(),
2124 net->pin_Result().drive1());
2125
2126 /* Connect the select bits. */
2127 nex = net->pin_Sel().nexus();
2128 assert(nex->t_cookie());
2129 obj->u_.mux.s = nex->t_cookie();
2130 nexus_lpm_add(obj->u_.mux.s, obj, 0,
2131 IVL_DR_HiZ, IVL_DR_HiZ);
2132
2133 unsigned selects = obj->u_.mux.size;
2134
2135 obj->u_.mux.d = new ivl_nexus_t [selects];
2136
2137 for (unsigned sdx = 0 ; sdx < selects ; sdx += 1) {
2138 nex = net->pin_Data(sdx).nexus();
2139 ivl_nexus_t tmp = nex->t_cookie();
2140 obj->u_.mux.d[sdx] = tmp;
2141 if (tmp == 0) {
2142 cerr << net->get_fileline() << ": internal error: "
2143 << "dll_target::lpm_mux: "
2144 << "Missing data port " << sdx
2145 << " of mux " << obj->name << "." << endl;
2146 }
2147 ivl_assert(*net, tmp);
2148 nexus_lpm_add(tmp, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
2149 }
2150
2151 }
2152
2153 /*
2154 * Make the NetPow object into an IVL_LPM_POW node.
2155 */
lpm_pow(const NetPow * net)2156 void dll_target::lpm_pow(const NetPow*net)
2157 {
2158 ivl_lpm_t obj = new struct ivl_lpm_s;
2159 obj->type = IVL_LPM_POW;
2160 FILE_NAME(obj, net);
2161 obj->name = net->name();
2162 assert(net->scope());
2163 obj->scope = find_scope(des_, net->scope());
2164 assert(obj->scope);
2165 FILE_NAME(obj, net);
2166
2167 unsigned wid = net->width_r();
2168 obj->u_.arith.signed_flag = net->get_signed()? 1 : 0;
2169
2170 obj->width = wid;
2171
2172 const Nexus*nex;
2173
2174 nex = net->pin_Result().nexus();
2175 assert(nex->t_cookie());
2176
2177 obj->u_.arith.q = nex->t_cookie();
2178 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
2179
2180 nex = net->pin_DataA().nexus();
2181 assert(nex->t_cookie());
2182
2183 obj->u_.arith.a = nex->t_cookie();
2184 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
2185
2186 nex = net->pin_DataB().nexus();
2187 assert(nex->t_cookie());
2188
2189 obj->u_.arith.b = nex->t_cookie();
2190 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
2191
2192 make_lpm_delays_(obj, net);
2193
2194 scope_add_lpm(obj->scope, obj);
2195 }
2196
concat(const NetConcat * net)2197 bool dll_target::concat(const NetConcat*net)
2198 {
2199 ivl_lpm_t obj = new struct ivl_lpm_s;
2200 obj->type = net->transparent()? IVL_LPM_CONCATZ : IVL_LPM_CONCAT;
2201 obj->name = net->name(); // NetConcat names are permallocated
2202 assert(net->scope());
2203 obj->scope = find_scope(des_, net->scope());
2204 assert(obj->scope);
2205 FILE_NAME(obj, net);
2206
2207 obj->width = net->width();
2208
2209 obj->u_.concat.inputs = net->pin_count() - 1;
2210 obj->u_.concat.pins = new ivl_nexus_t[obj->u_.concat.inputs+1];
2211
2212 for (unsigned idx = 0 ; idx < obj->u_.concat.inputs+1 ; idx += 1) {
2213 ivl_drive_t dr = idx == 0? IVL_DR_STRONG : IVL_DR_HiZ;
2214 const Nexus*nex = net->pin(idx).nexus();
2215 assert(nex->t_cookie());
2216
2217 obj->u_.concat.pins[idx] = nex->t_cookie();
2218 nexus_lpm_add(obj->u_.concat.pins[idx], obj, 0, dr, dr);
2219 }
2220
2221 make_lpm_delays_(obj, net);
2222
2223 scope_add_lpm(obj->scope, obj);
2224
2225 return true;
2226 }
2227
part_select(const NetPartSelect * net)2228 bool dll_target::part_select(const NetPartSelect*net)
2229 {
2230 ivl_lpm_t obj = new struct ivl_lpm_s;
2231 switch (net->dir()) {
2232 case NetPartSelect::VP:
2233 obj->type = IVL_LPM_PART_VP;
2234 break;
2235 case NetPartSelect::PV:
2236 obj->type = IVL_LPM_PART_PV;
2237 break;
2238 }
2239 obj->name = net->name(); // NetPartSelect names are permallocated.
2240 assert(net->scope());
2241 obj->scope = find_scope(des_, net->scope());
2242 assert(obj->scope);
2243 FILE_NAME(obj, net);
2244
2245 /* Part selects are always unsigned, so we use this to indicate
2246 * if the part select base signal is signed or not. */
2247 if (net->signed_flag())
2248 obj->u_.part.signed_flag = 1;
2249 else
2250 obj->u_.part.signed_flag = 0;
2251
2252 /* Choose the width of the part select. */
2253 obj->width = net->width();
2254 obj->u_.part.base = net->base();
2255 obj->u_.part.s = 0;
2256
2257 const Nexus*nex;
2258
2259 switch (obj->type) {
2260 case IVL_LPM_PART_VP:
2261 /* NetPartSelect:pin(0) is the output pin. */
2262 nex = net->pin(0).nexus();
2263 assert(nex->t_cookie());
2264
2265 obj->u_.part.q = nex->t_cookie();
2266
2267 /* NetPartSelect:pin(1) is the input pin. */
2268 nex = net->pin(1).nexus();
2269 assert(nex->t_cookie());
2270
2271 obj->u_.part.a = nex->t_cookie();
2272
2273 /* If the part select has an additional pin, that pin is
2274 a variable select base. */
2275 if (net->pin_count() >= 3) {
2276 nex = net->pin(2).nexus();
2277 assert(nex->t_cookie());
2278 obj->u_.part.s = nex->t_cookie();
2279 }
2280 break;
2281
2282 case IVL_LPM_PART_PV:
2283 /* NetPartSelect:pin(1) is the output pin. */
2284 nex = net->pin(1).nexus();
2285 assert(nex->t_cookie());
2286
2287 obj->u_.part.q = nex->t_cookie();
2288
2289 /* NetPartSelect:pin(0) is the input pin. */
2290 nex = net->pin(0).nexus();
2291 assert(nex->t_cookie());
2292
2293 obj->u_.part.a = nex->t_cookie();
2294 break;
2295
2296 default:
2297 assert(0);
2298 }
2299
2300 nexus_lpm_add(obj->u_.part.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
2301 nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
2302
2303 /* The select input is optional. */
2304 if (obj->u_.part.s)
2305 nexus_lpm_add(obj->u_.part.s, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
2306
2307 make_lpm_delays_(obj, net);
2308
2309 scope_add_lpm(obj->scope, obj);
2310
2311 return true;
2312 }
2313
replicate(const NetReplicate * net)2314 bool dll_target::replicate(const NetReplicate*net)
2315 {
2316 ivl_lpm_t obj = new struct ivl_lpm_s;
2317 obj->type = IVL_LPM_REPEAT;
2318 obj->name = net->name();
2319 assert(net->scope());
2320 obj->scope = find_scope(des_, net->scope());
2321 assert(obj->scope);
2322 FILE_NAME(obj, net);
2323
2324 obj->width = net->width();
2325 obj->u_.repeat.count = net->repeat();
2326
2327 ivl_drive_t dr = IVL_DR_STRONG;
2328 const Nexus*nex = net->pin(0).nexus();
2329 assert(nex->t_cookie());
2330
2331 obj->u_.repeat.q = nex->t_cookie();
2332 nexus_lpm_add(obj->u_.repeat.q, obj, 0, dr, dr);
2333
2334 dr = IVL_DR_HiZ;
2335 nex = net->pin(1).nexus();
2336 assert(nex->t_cookie());
2337
2338 obj->u_.repeat.a = nex->t_cookie();
2339 nexus_lpm_add(obj->u_.repeat.a, obj, 0, dr, dr);
2340
2341 make_lpm_delays_(obj, net);
2342
2343 scope_add_lpm(obj->scope, obj);
2344
2345 return true;
2346 }
2347
2348 /*
2349 * The assignment l-values are captured by the assignment statements
2350 * themselves in the process handling.
2351 */
net_assign(const NetAssign_ *) const2352 void dll_target::net_assign(const NetAssign_*) const
2353 {
2354 }
2355
net_const(const NetConst * net)2356 bool dll_target::net_const(const NetConst*net)
2357 {
2358 unsigned idx;
2359 char*bits;
2360 static char*bits_tmp = 0;
2361 static unsigned bits_cnt = 0;
2362
2363 struct ivl_net_const_s *obj = new struct ivl_net_const_s;
2364
2365 if (net->is_string()) {
2366 obj->type = IVL_VT_STRING;
2367 assert((net->width() % 8) == 0);
2368 } else obj->type = IVL_VT_BOOL;
2369 assert(net->scope());
2370 obj->scope = find_scope(des_, net->scope());
2371 FILE_NAME(obj, net);
2372
2373 /* constants have a single vector output. */
2374 assert(net->pin_count() == 1);
2375
2376 obj->width_ = net->width();
2377 obj->signed_ = net->value().has_sign();
2378 if (obj->width_ <= sizeof(obj->b.bit_)) {
2379 bits = obj->b.bit_;
2380
2381 } else {
2382 if (obj->width_ >= bits_cnt) {
2383 bits_tmp = (char*)realloc(bits_tmp, obj->width_+1);
2384 bits_cnt = obj->width_+1;
2385 }
2386 bits = bits_tmp;
2387 }
2388
2389 for (idx = 0 ; idx < obj->width_ ; idx += 1)
2390 switch (net->value(idx)) {
2391 case verinum::V0:
2392 bits[idx] = '0';
2393 break;
2394 case verinum::V1:
2395 bits[idx] = '1';
2396 break;
2397 case verinum::Vx:
2398 if (obj->type == IVL_VT_BOOL)
2399 obj->type = IVL_VT_LOGIC;
2400 bits[idx] = 'x';
2401 assert(! net->is_string());
2402 break;
2403 case verinum::Vz:
2404 if (obj->type == IVL_VT_BOOL)
2405 obj->type = IVL_VT_LOGIC;
2406 bits[idx] = 'z';
2407 assert(! net->is_string());
2408 break;
2409 }
2410
2411 if (obj->width_ > sizeof(obj->b.bit_)) {
2412 bits[obj->width_] = 0;
2413 obj->b.bits_ = net_const_strings.make(bits);
2414 }
2415
2416 /* Connect to all the nexus objects. Note that the one-bit
2417 case can be handled more efficiently without allocating
2418 array space. */
2419
2420 ivl_drive_t drv0, drv1;
2421 drive_from_link(net->pin(0), drv0, drv1);
2422 const Nexus*nex = net->pin(0).nexus();
2423 assert(nex->t_cookie());
2424 obj->pin_ = nex->t_cookie();
2425 nexus_con_add(obj->pin_, obj, 0, drv0, drv1);
2426
2427 des_.consts.push_back(obj);
2428
2429 make_const_delays_(obj, net);
2430
2431 return true;
2432 }
2433
net_literal(const NetLiteral * net)2434 bool dll_target::net_literal(const NetLiteral*net)
2435 {
2436
2437 struct ivl_net_const_s *obj = new struct ivl_net_const_s;
2438
2439 obj->type = IVL_VT_REAL;
2440 assert(net->scope());
2441 obj->scope = find_scope(des_, net->scope());
2442 FILE_NAME(obj, net);
2443 obj->width_ = 1;
2444 obj->signed_ = 1;
2445 obj->b.real_value = net->value_real().as_double();
2446
2447 /* Connect to all the nexus objects. Note that the one-bit
2448 case can be handled more efficiently without allocating
2449 array space. */
2450
2451 ivl_drive_t drv0, drv1;
2452 drive_from_link(net->pin(0), drv0, drv1);
2453 const Nexus*nex = net->pin(0).nexus();
2454 assert(nex->t_cookie());
2455 obj->pin_ = nex->t_cookie();
2456 nexus_con_add(obj->pin_, obj, 0, drv0, drv1);
2457
2458 des_.consts.push_back(obj);
2459
2460 make_const_delays_(obj, net);
2461
2462 return true;
2463 }
2464
net_probe(const NetEvProbe *)2465 void dll_target::net_probe(const NetEvProbe*)
2466 {
2467 }
2468
scope(const NetScope * net)2469 void dll_target::scope(const NetScope*net)
2470 {
2471 if (net->parent() == 0) {
2472
2473 // Root scopes are already created...
2474
2475 } else {
2476 perm_string sname = make_scope_name(net->fullname());
2477 ivl_scope_t scop = new struct ivl_scope_s;
2478 scop->name_ = sname;
2479 FILE_NAME(scop, net);
2480 scop->parent = find_scope(des_, net->parent());
2481 assert(scop->parent);
2482 scop->parent->children[net->fullname()] = scop;
2483 scop->parent->child .push_back(scop);
2484 scop->nlog_ = 0;
2485 scop->log_ = 0;
2486 scop->nevent_ = 0;
2487 scop->event_ = 0;
2488 scop->nlpm_ = 0;
2489 scop->lpm_ = 0;
2490 scop->def = 0;
2491 make_scope_parameters(scop, net);
2492 scop->time_precision = net->time_precision();
2493 scop->time_units = net->time_unit();
2494 scop->nattr = net->attr_cnt();
2495 scop->attr = fill_in_attributes(net);
2496 scop->is_auto = net->is_auto();
2497 scop->is_cell = net->is_cell();
2498
2499 switch (net->type()) {
2500 case NetScope::PACKAGE:
2501 cerr << "?:?" << ": internal error: "
2502 << "Package scopes should not have parents." << endl;
2503 // fallthrough
2504 case NetScope::MODULE:
2505 scop->type_ = IVL_SCT_MODULE;
2506 scop->tname_ = net->module_name();
2507 scop->ports = net->module_port_nets();
2508 if (scop->ports > 0) {
2509 scop->u_.net = new NetNet*[scop->ports];
2510 for (unsigned idx = 0; idx < scop->ports; idx += 1) {
2511 scop->u_.net[idx] = net->module_port_net(idx);
2512 }
2513 }
2514 scop->module_ports_info = net->module_port_info();
2515 break;
2516
2517 case NetScope::TASK: {
2518 const NetTaskDef*def = net->task_def();
2519 if (def == 0) {
2520 cerr << "?:?" << ": internal error: "
2521 << "task " << scop->name_
2522 << " has no definition." << endl;
2523 }
2524 assert(def);
2525 scop->type_ = IVL_SCT_TASK;
2526 scop->tname_ = def->scope()->basename();
2527 break;
2528 }
2529 case NetScope::FUNC:
2530 fill_in_scope_function(scop, net);
2531 break;
2532 case NetScope::BEGIN_END:
2533 scop->type_ = IVL_SCT_BEGIN;
2534 scop->tname_ = scop->name_;
2535 break;
2536 case NetScope::FORK_JOIN:
2537 scop->type_ = IVL_SCT_FORK;
2538 scop->tname_ = scop->name_;
2539 break;
2540 case NetScope::GENBLOCK:
2541 scop->type_ = IVL_SCT_GENERATE;
2542 scop->tname_ = scop->name_;
2543 break;
2544 case NetScope::CLASS:
2545 scop->type_ = IVL_SCT_CLASS;
2546 scop->tname_ = scop->name_;
2547 break;
2548 }
2549 }
2550 }
2551
convert_module_ports(const NetScope * net)2552 void dll_target::convert_module_ports(const NetScope*net)
2553 {
2554 ivl_scope_t scop = find_scope(des_, net);
2555 if (scop->ports > 0) {
2556 NetNet**nets = scop->u_.net;
2557 scop->u_.nex = new ivl_nexus_t[scop->ports];
2558 for (unsigned idx = 0; idx < scop->ports; idx += 1) {
2559 ivl_signal_t sig = find_signal(des_, nets[idx]);
2560 scop->u_.nex[idx] = nexus_sig_make(sig, 0);
2561 }
2562 delete [] nets;
2563 }
2564 }
2565
signal(const NetNet * net)2566 void dll_target::signal(const NetNet*net)
2567 {
2568 ivl_signal_t obj = new struct ivl_signal_s;
2569
2570 obj->name_ = net->name();
2571
2572 /* Attach the signal to the ivl_scope_t object that contains
2573 it. This involves growing the sigs_ array in the scope
2574 object, or creating the sigs_ array if this is the first
2575 signal. */
2576 obj->scope_ = find_scope(des_, net->scope());
2577 assert(obj->scope_);
2578 FILE_NAME(obj, net);
2579
2580 obj->scope_->sigs_.push_back(obj);
2581
2582
2583 /* Save the primitive properties of the signal in the
2584 ivl_signal_t object. */
2585
2586 { size_t idx = 0;
2587 vector<netrange_t>::const_iterator cur;
2588 obj->packed_dims.resize(net->packed_dims().size());
2589 for (cur = net->packed_dims().begin(), idx = 0
2590 ; cur != net->packed_dims().end() ; ++cur, idx += 1) {
2591 obj->packed_dims[idx] = *cur;
2592 }
2593 }
2594
2595 obj->net_type = net->net_type();
2596 obj->local_ = net->local_flag()? 1 : 0;
2597 obj->forced_net_ = (net->type() != NetNet::REG) &&
2598 (net->peek_lref() > 0) ? 1 : 0;
2599 obj->discipline = net->get_discipline();
2600
2601 obj->array_dimensions_ = net->unpacked_dimensions();
2602 assert(obj->array_dimensions_ == net->unpacked_dimensions());
2603
2604 switch (net->port_type()) {
2605
2606 case NetNet::PINPUT:
2607 obj->port_ = IVL_SIP_INPUT;
2608 break;
2609
2610 case NetNet::POUTPUT:
2611 obj->port_ = IVL_SIP_OUTPUT;
2612 break;
2613
2614 case NetNet::PINOUT:
2615 obj->port_ = IVL_SIP_INOUT;
2616 break;
2617
2618 default:
2619 obj->port_ = IVL_SIP_NONE;
2620 break;
2621 }
2622
2623 obj->module_port_index_ = net->get_module_port_index();
2624
2625 switch (net->type()) {
2626
2627 case NetNet::REG:
2628 obj->type_ = IVL_SIT_REG;
2629 break;
2630
2631 /* The SUPPLY0/1 net types are replaced with pulldown/up
2632 by elaborate. They should not make it here. */
2633 case NetNet::SUPPLY0:
2634 assert(0);
2635 break;
2636 case NetNet::SUPPLY1:
2637 assert(0);
2638 break;
2639
2640 /* We will convert this to a TRI after we check that there
2641 is only one driver. */
2642 case NetNet::UNRESOLVED_WIRE:
2643 obj->type_ = IVL_SIT_UWIRE;
2644 break;
2645
2646 case NetNet::TRI:
2647 case NetNet::WIRE:
2648 case NetNet::IMPLICIT:
2649 obj->type_ = IVL_SIT_TRI;
2650 break;
2651
2652 case NetNet::TRI0:
2653 obj->type_ = IVL_SIT_TRI0;
2654 break;
2655
2656 case NetNet::TRI1:
2657 obj->type_ = IVL_SIT_TRI1;
2658 break;
2659
2660 case NetNet::TRIAND:
2661 case NetNet::WAND:
2662 obj->type_ = IVL_SIT_TRIAND;
2663 break;
2664
2665 case NetNet::TRIOR:
2666 case NetNet::WOR:
2667 obj->type_ = IVL_SIT_TRIOR;
2668 break;
2669
2670 default:
2671 obj->type_ = IVL_SIT_NONE;
2672 break;
2673 }
2674
2675 /* Initialize the path fields to be filled in later. */
2676 obj->npath = 0;
2677 obj->path = 0;
2678
2679 obj->nattr = net->attr_cnt();
2680 obj->attr = fill_in_attributes(net);
2681
2682 /* Get the nexus objects for all the pins of the signal. If
2683 the signal has only one pin, then write the single
2684 ivl_nexus_t object into n.pin_. Otherwise, make an array of
2685 ivl_nexus_t cookies.
2686
2687 When I create an ivl_nexus_t object, store it in the
2688 t_cookie of the Nexus object so that I find it again when I
2689 next encounter the nexus. */
2690
2691 if (obj->array_dimensions_ == 1) {
2692 const vector<netrange_t>& dims = net->unpacked_dims();
2693 if (dims[0].get_msb() < dims[0].get_lsb()) {
2694 obj->array_base = dims[0].get_msb();
2695 obj->array_addr_swapped = false;
2696 } else {
2697 obj->array_base = dims[0].get_lsb();
2698 obj->array_addr_swapped = true;
2699 }
2700 obj->array_words = net->unpacked_count();
2701 } else {
2702 // The back-end API doesn't yet support multi-dimension
2703 // unpacked arrays, so just report the canonical dimensions.
2704 obj->array_base = 0;
2705 // For a queue we pass the maximum queue size as the array words.
2706 if (obj->net_type->base_type() == IVL_VT_QUEUE) {
2707 long max_size = net->queue_type()->max_idx()+1;
2708 ivl_assert(*net, max_size >= 0);
2709 obj->array_words = max_size;
2710 } else
2711 obj->array_words = net->unpacked_count();
2712 obj->array_addr_swapped = 0;
2713 }
2714
2715 ivl_assert(*net, (obj->array_words == net->pin_count()) ||
2716 (obj->net_type->base_type() == IVL_VT_QUEUE));
2717 if (debug_optimizer && obj->array_words > 1000) cerr << "debug: "
2718 "t-dll creating nexus array " << obj->array_words << " long" << endl;
2719 if (obj->array_words > 1 && net->pins_are_virtual()) {
2720 obj->pins = NULL;
2721 if (debug_optimizer && obj->array_words > 1000) cerr << "debug: "
2722 "t-dll used NULL for big nexus array" << endl;
2723 return;
2724 }
2725 if (obj->array_words > 1)
2726 obj->pins = new ivl_nexus_t[obj->array_words];
2727
2728 for (unsigned idx = 0 ; idx < obj->array_words ; idx += 1) {
2729
2730 const Nexus*nex = net->pins_are_virtual() ? 0 : net->pin(idx).nexus();
2731 if (nex == 0) {
2732 // Special case: This pin is connected to
2733 // nothing. This can happen, for example, if the
2734 // variable is only used in behavioral
2735 // code. Create a stub nexus.
2736 ivl_nexus_t tmp = nexus_sig_make(obj, idx);
2737 tmp->nexus_ = nex;
2738 tmp->name_ = 0;
2739 if (obj->array_words > 1)
2740 obj->pins[idx] = tmp;
2741 else
2742 obj->pin = tmp;
2743 } else if (nex->t_cookie()) {
2744 if (obj->array_words > 1) {
2745 obj->pins[idx] = nex->t_cookie();
2746 nexus_sig_add(obj->pins[idx], obj, idx);
2747 } else {
2748 obj->pin = nex->t_cookie();
2749 nexus_sig_add(obj->pin, obj, idx);
2750 }
2751 } else {
2752 ivl_nexus_t tmp = nexus_sig_make(obj, idx);
2753 tmp->nexus_ = nex;
2754 tmp->name_ = 0;
2755 nex->t_cookie(tmp);
2756 if (obj->array_words > 1)
2757 obj->pins[idx] = tmp;
2758 else
2759 obj->pin = tmp;
2760 }
2761 }
2762 if (debug_optimizer && obj->array_words > 1000) cerr << "debug: t-dll done with big nexus array" << endl;
2763 }
2764
signal_paths(const NetNet * net)2765 bool dll_target::signal_paths(const NetNet*net)
2766 {
2767 /* Nothing to do if there are no paths for this signal. */
2768 if (net->delay_paths() == 0)
2769 return true;
2770
2771 ivl_signal_t obj = find_signal(des_, net);
2772 assert(obj);
2773
2774 /* We cannot have already set up the paths for this signal. */
2775 assert(obj->npath == 0);
2776 assert(obj->path == 0);
2777
2778 /* Figure out how many paths there really are. */
2779 for (unsigned idx = 0 ; idx < net->delay_paths() ; idx += 1) {
2780 const NetDelaySrc*src = net->delay_path(idx);
2781 obj->npath += src->src_count();
2782 }
2783
2784 obj->path = new struct ivl_delaypath_s[obj->npath];
2785
2786 unsigned ptr = 0;
2787 for (unsigned idx = 0 ; idx < net->delay_paths() ; idx += 1) {
2788 const NetDelaySrc*src = net->delay_path(idx);
2789
2790 /* If this path has a condition, then hook it up. */
2791 ivl_nexus_t path_condit = 0;
2792 if (src->has_condit()) {
2793 const Nexus*nt = src->condit_pin().nexus();
2794 path_condit = nt->t_cookie();
2795 }
2796
2797 for (unsigned pin = 0; pin < src->src_count(); pin += 1) {
2798 const Nexus*nex = src->src_pin(pin).nexus();
2799 if (! nex->t_cookie()) {
2800 cerr << src->get_fileline() << ": internal error: "
2801 << "No signal connected to pin " << pin
2802 << " of delay path to " << net->name()
2803 << "." << endl;
2804 }
2805 assert(nex->t_cookie());
2806 obj->path[ptr].scope = lookup_scope_(src->scope());
2807 obj->path[ptr].src = nex->t_cookie();
2808 obj->path[ptr].condit = path_condit;
2809 obj->path[ptr].conditional = src->is_condit();
2810 obj->path[ptr].parallel = src->is_parallel();
2811 obj->path[ptr].posedge = src->is_posedge();
2812 obj->path[ptr].negedge = src->is_negedge();
2813 for (unsigned pe = 0 ; pe < 12 ; pe += 1) {
2814 obj->path[ptr].delay[pe] = src->get_delay(pe);
2815 }
2816
2817 ptr += 1;
2818 }
2819
2820 }
2821
2822 return true;
2823 }
2824
2825
test_version(const char * target_name)2826 void dll_target::test_version(const char*target_name)
2827 {
2828 dll_ = ivl_dlopen(target_name);
2829
2830 if ((dll_ == 0) && (target_name[0] != '/')) {
2831 size_t len = strlen(basedir) + 1 + strlen(target_name) + 1;
2832 char*tmp = new char[len];
2833 sprintf(tmp, "%s/%s", basedir, target_name);
2834 dll_ = ivl_dlopen(tmp);
2835 delete[]tmp;
2836 }
2837
2838 if (dll_ == 0) {
2839 cout << "\n\nUnable to load " << target_name
2840 << " for version details." << endl;
2841 return;
2842 }
2843
2844 target_query_f target_query = (target_query_f)ivl_dlsym(dll_, LU "target_query" TU);
2845 if (target_query == 0) {
2846 cerr << "Target " << target_name
2847 << " has no version hooks." << endl;
2848 return;
2849 }
2850
2851 const char*version_string = (*target_query) ("version");
2852 if (version_string == 0) {
2853 cerr << "Target " << target_name
2854 << " has no version string" << endl;
2855 return;
2856 }
2857
2858 cout << target_name << ": " << version_string << endl;
2859 }
2860