Add support for conditional generate. In the process, fix bugs
[iverilog.git] / t-dll.cc
blob9cb116445be20134d590535671eb24aa48a117e3
1 /*
2 * Copyright (c) 2000-2005 Stephen Williams (steve@icarus.com)
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #ifdef HAVE_CVS_IDENT
20 #ident "$Id: t-dll.cc,v 1.171 2007/06/02 03:42:13 steve Exp $"
21 #endif
23 # include "config.h"
25 # include <iostream>
27 # include <stdio.h> // sprintf()
28 # include "compiler.h"
29 # include "t-dll.h"
30 # include "netmisc.h"
31 #ifdef HAVE_MALLOC_H
32 # include <malloc.h>
33 #endif
34 # include <stdlib.h>
36 #if defined(__WIN32__)
38 inline ivl_dll_t ivl_dlopen(const char *name)
40 ivl_dll_t res = (ivl_dll_t) LoadLibrary(name);
41 return res;
45 inline void * ivl_dlsym(ivl_dll_t dll, const char *nm)
47 FARPROC sym;
48 return (void*)GetProcAddress((HMODULE)dll, nm);
51 inline void ivl_dlclose(ivl_dll_t dll)
53 FreeLibrary((HMODULE)dll);
56 const char *dlerror(void)
58 static char msg[256];
59 unsigned long err = GetLastError();
60 FormatMessage(
61 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
62 NULL,
63 err,
64 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
65 (LPTSTR) &msg,
66 sizeof(msg) - 1,
67 NULL
69 return msg;
71 #elif defined(HAVE_DLFCN_H)
72 inline ivl_dll_t ivl_dlopen(const char*name)
73 { return dlopen(name,RTLD_LAZY); }
75 inline void* ivl_dlsym(ivl_dll_t dll, const char*nm)
77 void*sym = dlsym(dll, nm);
78 /* Not found? try without the leading _ */
79 if (sym == 0 && nm[0] == '_')
80 sym = dlsym(dll, nm+1);
81 return sym;
84 inline void ivl_dlclose(ivl_dll_t dll)
85 { dlclose(dll); }
87 #elif defined(HAVE_DL_H)
88 inline ivl_dll_t ivl_dlopen(const char*name)
89 { return shl_load(name, BIND_IMMEDIATE, 0); }
91 inline void* ivl_dlsym(ivl_dll_t dll, const char*nm)
93 void*sym;
94 int rc = shl_findsym(&dll, nm, TYPE_PROCEDURE, &sym);
95 return (rc == 0) ? sym : 0;
98 inline void ivl_dlclose(ivl_dll_t dll)
99 { shl_unload(dll); }
101 inline const char*dlerror(void)
102 { return strerror( errno ); }
103 #endif
106 * The custom new operator for the ivl_nexus_s type allows us to
107 * allocate nexus objects in blocks. There are generally lots of them
108 * permanently allocated, and allocating them in blocks reduces the
109 * allocation overhead.
111 static struct ivl_nexus_s * nexus_pool_ptr = 0;
112 static int nexus_pool_remaining = 0;
113 static const size_t NEXUS_POOL_SIZE = 4096;
115 void* ivl_nexus_s::operator new(size_t s)
117 assert(s == sizeof(struct ivl_nexus_s));
118 if (nexus_pool_remaining <= 0) {
119 nexus_pool_ptr = new struct ivl_nexus_s[NEXUS_POOL_SIZE];
120 nexus_pool_remaining = NEXUS_POOL_SIZE;
123 struct ivl_nexus_s*tmp = nexus_pool_ptr;
124 nexus_pool_ptr += 1;
125 nexus_pool_remaining -= 1;
127 return tmp;
130 inline static const char *basename(ivl_scope_t scope, const char *inst)
132 inst += strlen(ivl_scope_name(scope));
133 assert(*inst == '.');
134 return inst+1;
137 static perm_string make_scope_name(const hname_t&name)
139 if (! name.has_number())
140 return name.peek_name();
142 char buf[1024];
143 snprintf(buf, sizeof buf, "%s[%d]",
144 name.peek_name().str(), name.peek_number());
145 return lex_strings.make(buf);
148 static struct dll_target dll_target_obj;
150 static void drive_from_link(const Link&lnk, ivl_drive_t&drv0, ivl_drive_t&drv1)
152 switch (lnk.drive0()) {
153 case Link::HIGHZ:
154 drv0 = IVL_DR_HiZ;
155 break;
156 case Link::WEAK:
157 drv0 = IVL_DR_WEAK;
158 break;
159 case Link::PULL:
160 drv0 = IVL_DR_PULL;
161 break;
162 case Link::STRONG:
163 drv0 = IVL_DR_STRONG;
164 break;
165 case Link::SUPPLY:
166 drv0 = IVL_DR_SUPPLY;
167 break;
170 switch (lnk.drive1()) {
171 case Link::HIGHZ:
172 drv1 = IVL_DR_HiZ;
173 break;
174 case Link::WEAK:
175 drv1 = IVL_DR_WEAK;
176 break;
177 case Link::PULL:
178 drv1 = IVL_DR_PULL;
179 break;
180 case Link::STRONG:
181 drv1 = IVL_DR_STRONG;
182 break;
183 case Link::SUPPLY:
184 drv1 = IVL_DR_SUPPLY;
185 break;
189 ivl_attribute_s* dll_target::fill_in_attributes(const Attrib*net)
191 ivl_attribute_s*attr;
192 unsigned nattr = net->attr_cnt();
194 if (nattr == 0)
195 return 0;
197 attr = new struct ivl_attribute_s[nattr];
199 for (unsigned idx = 0 ; idx < nattr ; idx += 1) {
200 verinum tmp = net->attr_value(idx);
201 attr[idx].key = net->attr_key(idx);
202 if (tmp.is_string()) {
203 attr[idx].type = IVL_ATT_STR;
204 attr[idx].val.str = strings_.add(tmp.as_string().c_str());
206 } else if (tmp == verinum()) {
207 attr[idx].type = IVL_ATT_VOID;
209 } else {
210 attr[idx].type = IVL_ATT_NUM;
211 attr[idx].val.num = tmp.as_long();
215 return attr;
219 * This function locates an ivl_scope_t object that matches the
220 * NetScope object. The search works by looking for the parent scope,
221 * then scanning the parent scope for the NetScope object.
223 static ivl_scope_t find_scope_from_root(ivl_scope_t root, const NetScope*cur)
225 ivl_scope_t parent, tmp;
226 perm_string cur_name = make_scope_name(cur->fullname());
228 if (const NetScope*par = cur->parent()) {
229 parent = find_scope_from_root(root, par);
230 if (parent == 0)
231 return 0;
233 for (tmp = parent->child_ ; tmp ; tmp = tmp->sibling_)
234 if (strcmp(tmp->name_, cur_name) == 0)
235 return tmp;
237 } else {
238 if (strcmp(root->name_, cur_name) == 0)
239 return root;
242 return 0;
245 ivl_scope_t dll_target::find_scope(ivl_design_s &des, const NetScope*cur)
247 assert(cur);
249 ivl_scope_t scope = 0;
250 for (unsigned i = 0; i < des.nroots_ && scope == 0; i += 1) {
251 assert(des.roots_[i]);
252 scope = find_scope_from_root(des.roots_[i], cur);
254 return scope;
257 ivl_scope_t dll_target::lookup_scope_(const NetScope*cur)
259 return find_scope(des_, cur);
263 * This is a convenience function to locate an ivl_signal_t object
264 * given the NetESignal that has the signal name.
266 ivl_signal_t dll_target::find_signal(ivl_design_s &des, const NetNet*net)
268 ivl_scope_t scope = find_scope(des, net->scope());
269 assert(scope);
271 perm_string nname = net->name();
273 for (unsigned idx = 0 ; idx < scope->nsigs_ ; idx += 1) {
274 if (strcmp(scope->sigs_[idx]->name_, nname) == 0)
275 return scope->sigs_[idx];
278 assert(0);
279 return 0;
282 static ivl_nexus_t nexus_sig_make(ivl_signal_t net, unsigned pin)
284 ivl_nexus_t tmp = new struct ivl_nexus_s;
285 tmp->private_data = 0;
286 tmp->nptr_ = 1;
287 tmp->ptrs_ = (struct ivl_nexus_ptr_s*)
288 malloc(sizeof(struct ivl_nexus_ptr_s));
289 tmp->ptrs_[0].pin_ = pin;
290 tmp->ptrs_[0].type_ = __NEXUS_PTR_SIG;
291 tmp->ptrs_[0].l.sig = net;
293 ivl_drive_t drive = IVL_DR_HiZ;
294 switch (ivl_signal_type(net)) {
295 case IVL_SIT_REG:
296 drive = IVL_DR_STRONG;
297 break;
298 default:
299 break;
301 tmp->ptrs_[0].drive0 = drive;
302 tmp->ptrs_[0].drive1 = drive;
304 return tmp;
307 static void nexus_sig_add(ivl_nexus_t nex, ivl_signal_t net, unsigned pin)
309 unsigned top = nex->nptr_ + 1;
310 nex->ptrs_ = (struct ivl_nexus_ptr_s*)
311 realloc(nex->ptrs_, top * sizeof(struct ivl_nexus_ptr_s));
312 nex->nptr_ = top;
314 ivl_drive_t drive = IVL_DR_HiZ;
315 switch (ivl_signal_type(net)) {
316 case IVL_SIT_REG:
317 drive = IVL_DR_STRONG;
318 break;
319 default:
320 break;
323 nex->ptrs_[top-1].type_= __NEXUS_PTR_SIG;
324 nex->ptrs_[top-1].drive0 = drive;
325 nex->ptrs_[top-1].drive1 = drive;
326 nex->ptrs_[top-1].pin_ = pin;
327 nex->ptrs_[top-1].l.sig= net;
331 * Add the pin of the logic object to the nexus, and return the nexus
332 * pointer used for the pin.
334 * NOTE: This pointer is only valid until another pin is added to the
335 * nexus.
337 static ivl_nexus_ptr_t nexus_log_add(ivl_nexus_t nex,
338 ivl_net_logic_t net,
339 unsigned pin)
341 unsigned top = nex->nptr_ + 1;
342 nex->ptrs_ = (struct ivl_nexus_ptr_s*)
343 realloc(nex->ptrs_, top * sizeof(struct ivl_nexus_ptr_s));
344 nex->nptr_ = top;
346 nex->ptrs_[top-1].type_= __NEXUS_PTR_LOG;
347 nex->ptrs_[top-1].drive0 = (pin == 0)? IVL_DR_STRONG : IVL_DR_HiZ;
348 nex->ptrs_[top-1].drive1 = (pin == 0)? IVL_DR_STRONG : IVL_DR_HiZ;
349 nex->ptrs_[top-1].pin_ = pin;
350 nex->ptrs_[top-1].l.log= net;
352 return nex->ptrs_ + top - 1;
355 static void nexus_con_add(ivl_nexus_t nex, ivl_net_const_t net, unsigned pin,
356 ivl_drive_t drive0, ivl_drive_t drive1)
358 unsigned top = nex->nptr_ + 1;
359 nex->ptrs_ = (struct ivl_nexus_ptr_s*)
360 realloc(nex->ptrs_, top * sizeof(struct ivl_nexus_ptr_s));
361 nex->nptr_ = top;
363 nex->ptrs_[top-1].type_= __NEXUS_PTR_CON;
364 nex->ptrs_[top-1].drive0 = drive0;
365 nex->ptrs_[top-1].drive1 = drive1;
366 nex->ptrs_[top-1].pin_ = pin;
367 nex->ptrs_[top-1].l.con= net;
370 static void nexus_lpm_add(ivl_nexus_t nex, ivl_lpm_t net, unsigned pin,
371 ivl_drive_t drive0, ivl_drive_t drive1)
373 unsigned top = nex->nptr_ + 1;
374 nex->ptrs_ = (struct ivl_nexus_ptr_s*)
375 realloc(nex->ptrs_, top * sizeof(struct ivl_nexus_ptr_s));
376 nex->nptr_ = top;
378 nex->ptrs_[top-1].type_= __NEXUS_PTR_LPM;
379 nex->ptrs_[top-1].drive0 = drive0;
380 nex->ptrs_[top-1].drive1 = drive0;
381 nex->ptrs_[top-1].pin_ = pin;
382 nex->ptrs_[top-1].l.lpm= net;
386 void scope_add_logic(ivl_scope_t scope, ivl_net_logic_t net)
388 if (scope->nlog_ == 0) {
389 scope->nlog_ = 1;
390 scope->log_ = (ivl_net_logic_t*)malloc(sizeof(ivl_net_logic_t));
391 scope->log_[0] = net;
393 } else {
394 scope->nlog_ += 1;
395 scope->log_ = (ivl_net_logic_t*)
396 realloc(scope->log_, scope->nlog_*sizeof(ivl_net_logic_t));
397 scope->log_[scope->nlog_-1] = net;
402 void scope_add_event(ivl_scope_t scope, ivl_event_t net)
404 if (scope->nevent_ == 0) {
405 scope->nevent_ = 1;
406 scope->event_ = (ivl_event_t*)malloc(sizeof(ivl_event_t));
407 scope->event_[0] = net;
409 } else {
410 scope->nevent_ += 1;
411 scope->event_ = (ivl_event_t*)
412 realloc(scope->event_, scope->nevent_*sizeof(ivl_event_t));
413 scope->event_[scope->nevent_-1] = net;
418 static void scope_add_lpm(ivl_scope_t scope, ivl_lpm_t net)
420 if (scope->nlpm_ == 0) {
421 assert(scope->lpm_ == 0);
422 scope->nlpm_ = 1;
423 scope->lpm_ = (ivl_lpm_t*)malloc(sizeof(ivl_lpm_t));
424 scope->lpm_[0] = net;
426 } else {
427 assert(scope->lpm_);
428 scope->nlpm_ += 1;
429 scope->lpm_ = (ivl_lpm_t*)
430 realloc(scope->lpm_,
431 scope->nlpm_*sizeof(ivl_lpm_t));
432 scope->lpm_[scope->nlpm_-1] = net;
436 ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope,
437 const char*name)
439 unsigned idx = 0;
440 while (idx < scope->nparam_) {
441 if (strcmp(name, scope->param_[idx].basename) == 0)
442 return scope->param_ + idx;
444 idx += 1;
447 return 0;
451 * This method scans the parameters of the scope, and makes
452 * ivl_parameter_t objects. This involves saving the name and scanning
453 * the expression value.
455 void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net)
457 scope->nparam_ = net->parameters.size() + net->localparams.size();
458 if (scope->nparam_ == 0) {
459 scope->param_ = 0;
460 return;
463 scope->param_ = new struct ivl_parameter_s [scope->nparam_];
465 unsigned idx = 0;
466 typedef map<perm_string,NetScope::param_expr_t>::const_iterator pit_t;
468 for (pit_t cur_pit = net->parameters.begin()
469 ; cur_pit != net->parameters.end() ; cur_pit ++) {
471 assert(idx < scope->nparam_);
472 ivl_parameter_t cur_par = scope->param_ + idx;
473 cur_par->basename = (*cur_pit).first;
474 cur_par->scope = scope;
476 NetExpr*etmp = (*cur_pit).second.expr;
477 make_scope_param_expr(cur_par, etmp);
478 idx += 1;
480 for (pit_t cur_pit = net->localparams.begin()
481 ; cur_pit != net->localparams.end() ; cur_pit ++) {
483 assert(idx < scope->nparam_);
484 ivl_parameter_t cur_par = scope->param_ + idx;
485 cur_par->basename = (*cur_pit).first;
486 cur_par->scope = scope;
488 NetExpr*etmp = (*cur_pit).second.expr;
489 make_scope_param_expr(cur_par, etmp);
490 idx += 1;
494 void dll_target::make_scope_param_expr(ivl_parameter_t cur_par, NetExpr*etmp)
496 if (const NetEConst*e = dynamic_cast<const NetEConst*>(etmp)) {
498 expr_const(e);
499 assert(expr_);
501 switch (expr_->type_) {
502 case IVL_EX_STRING:
503 expr_->u_.string_.parameter = cur_par;
504 break;
505 case IVL_EX_NUMBER:
506 expr_->u_.number_.parameter = cur_par;
507 break;
508 default:
509 assert(0);
512 } else if (const NetECReal*e = dynamic_cast<const NetECReal*>(etmp)) {
514 expr_creal(e);
515 assert(expr_);
516 assert(expr_->type_ == IVL_EX_REALNUM);
517 expr_->u_.real_.parameter = cur_par;
521 cur_par->value = expr_;
522 expr_ = 0;
525 void dll_target::add_root(ivl_design_s &des_, const NetScope *s)
527 ivl_scope_t root_ = new struct ivl_scope_s;
528 perm_string name = s->basename();
529 root_->name_ = name;
530 root_->child_ = 0;
531 root_->sibling_ = 0;
532 root_->parent = 0;
533 root_->nsigs_ = 0;
534 root_->sigs_ = 0;
535 root_->nlog_ = 0;
536 root_->log_ = 0;
537 root_->nevent_ = 0;
538 root_->event_ = 0;
539 root_->nlpm_ = 0;
540 root_->lpm_ = 0;
541 root_->def = 0;
542 make_scope_parameters(root_, s);
543 root_->type_ = IVL_SCT_MODULE;
544 root_->tname_ = root_->name_;
545 root_->time_units = s->time_unit();
546 root_->nattr = s->attr_cnt();
547 root_->attr = fill_in_attributes(s);
549 des_.nroots_++;
550 if (des_.roots_)
551 des_.roots_ = (ivl_scope_t *)realloc(des_.roots_, des_.nroots_ * sizeof(ivl_scope_t));
552 else
553 des_.roots_ = (ivl_scope_t *)malloc(des_.nroots_ * sizeof(ivl_scope_t));
554 des_.roots_[des_.nroots_ - 1] = root_;
557 bool dll_target::start_design(const Design*des)
559 list<NetScope *> root_scopes;
560 const char*dll_path_ = des->get_flag("DLL");
562 dll_ = ivl_dlopen(dll_path_);
564 if ((dll_ == 0) && (dll_path_[0] != '/')) {
565 size_t len = strlen(basedir) + 1 + strlen(dll_path_) + 1;
566 char*tmp = new char[len];
567 sprintf(tmp, "%s/%s", basedir, dll_path_);
568 dll_ = ivl_dlopen(tmp);
569 delete[]tmp;
572 if (dll_ == 0) {
573 cerr << "error: " << dll_path_ << " failed to load." << endl;
574 cerr << dll_path_ << ": " << dlerror() << endl;
575 return false;
578 stmt_cur_ = 0;
580 // Initialize the design object.
581 des_.self = des;
582 des_.time_precision = des->get_precision();
583 des_.nroots_ = 0;
584 des_.roots_ = NULL;
586 root_scopes = des->find_root_scopes();
587 for (list<NetScope*>::const_iterator scope = root_scopes.begin();
588 scope != root_scopes.end(); scope++)
589 add_root(des_, *scope);
591 des_.consts = (ivl_net_const_t*)
592 malloc(sizeof(ivl_net_const_t));
593 des_.nconsts = 0;
595 target_ = (target_design_f)ivl_dlsym(dll_, LU "target_design" TU);
596 if (target_ == 0) {
597 cerr << dll_path_ << ": error: target_design entry "
598 "point is missing." << endl;
599 return false;
602 return true;
606 * Here ivl is telling us that the design is scanned completely, and
607 * here is where we call the API to process the constructed design.
609 int dll_target::end_design(const Design*)
611 if (verbose_flag) {
612 cout << " ... invoking target_design" << endl;
615 int rc = (target_)(&des_);
616 ivl_dlclose(dll_);
617 return rc;
620 void dll_target::logic_attributes(struct ivl_net_logic_s *obj,
621 const NetNode*net)
623 obj->nattr = net->attr_cnt();
624 obj->attr = fill_in_attributes(net);
627 void dll_target::make_logic_delays_(struct ivl_net_logic_s*obj,
628 const NetObj*net)
630 obj->delay[0] = 0;
631 obj->delay[1] = 0;
632 obj->delay[2] = 0;
634 /* Translate delay expressions to ivl_target form. Try to
635 preserve pointer equality, not as a rule but to save on
636 expression trees. */
637 if (net->rise_time()) {
638 expr_ = 0;
639 net->rise_time()->expr_scan(this);
640 obj->delay[0] = expr_;
641 expr_ = 0;
643 if (net->fall_time()) {
644 if (net->fall_time() == net->rise_time()) {
645 obj->delay[1] = obj->delay[0];
646 } else {
647 expr_ = 0;
648 net->fall_time()->expr_scan(this);
649 obj->delay[1] = expr_;
650 expr_ = 0;
653 if (net->decay_time()) {
654 if (net->decay_time() == net->rise_time()) {
655 obj->delay[2] = obj->delay[0];
656 } else {
657 expr_ = 0;
658 net->decay_time()->expr_scan(this);
659 obj->delay[2] = expr_;
660 expr_ = 0;
666 * Add a bufz object to the scope that contains it.
668 * Note that in the ivl_target API a BUFZ device is a special kind of
669 * ivl_net_logic_t device, so create an ivl_net_logic_t cookie to
670 * handle it.
672 bool dll_target::bufz(const NetBUFZ*net)
674 struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
676 assert(net->pin_count() == 2);
678 obj->type_ = IVL_LO_BUFZ;
679 obj->width_= net->width();
680 obj->npins_= 2;
681 obj->pins_ = new ivl_nexus_t[2];
683 /* Get the ivl_nexus_t objects connected to the two pins.
685 (We know a priori that the ivl_nexus_t objects have been
686 allocated, because the signals have been scanned before
687 me. This saves me the trouble of allocating them.) */
689 assert(net->pin(0).nexus()->t_cookie());
690 obj->pins_[0] = net->pin(0).nexus()->t_cookie();
691 ivl_nexus_ptr_t out_ptr = nexus_log_add(obj->pins_[0], obj, 0);
694 switch (net->pin(0).drive0()) {
695 case Link::HIGHZ:
696 out_ptr->drive0 = IVL_DR_HiZ;
697 break;
698 case Link::WEAK:
699 out_ptr->drive0 = IVL_DR_WEAK;
700 break;
701 case Link::PULL:
702 out_ptr->drive0 = IVL_DR_PULL;
703 break;
704 case Link::STRONG:
705 out_ptr->drive0 = IVL_DR_STRONG;
706 break;
707 case Link::SUPPLY:
708 out_ptr->drive0 = IVL_DR_SUPPLY;
709 break;
712 switch (net->pin(0).drive1()) {
713 case Link::HIGHZ:
714 out_ptr->drive1 = IVL_DR_HiZ;
715 break;
716 case Link::WEAK:
717 out_ptr->drive1 = IVL_DR_WEAK;
718 break;
719 case Link::PULL:
720 out_ptr->drive1 = IVL_DR_PULL;
721 break;
722 case Link::STRONG:
723 out_ptr->drive1 = IVL_DR_STRONG;
724 break;
725 case Link::SUPPLY:
726 out_ptr->drive1 = IVL_DR_SUPPLY;
727 break;
730 assert(net->pin(1).nexus()->t_cookie());
731 obj->pins_[1] = net->pin(1).nexus()->t_cookie();
732 nexus_log_add(obj->pins_[1], obj, 1);
734 /* Attach the logic device to the scope that contains it. */
736 assert(net->scope());
737 ivl_scope_t scope = find_scope(des_, net->scope());
738 assert(scope);
740 obj->scope_ = scope;
742 obj->name_ = net->name();
743 logic_attributes(obj, net);
745 make_logic_delays_(obj, net);
747 scope_add_logic(scope, obj);
749 return true;
752 void dll_target::event(const NetEvent*net)
754 struct ivl_event_s *obj = new struct ivl_event_s;
756 ivl_scope_t scope = find_scope(des_, net->scope());
757 obj->name = net->name();
758 obj->scope = scope;
759 scope_add_event(scope, obj);
761 obj->nany = 0;
762 obj->nneg = 0;
763 obj->npos = 0;
765 if (net->nprobe() >= 1) {
767 for (unsigned idx = 0 ; idx < net->nprobe() ; idx += 1) {
768 const NetEvProbe*pr = net->probe(idx);
769 switch (pr->edge()) {
770 case NetEvProbe::ANYEDGE:
771 obj->nany += pr->pin_count();
772 break;
773 case NetEvProbe::NEGEDGE:
774 obj->nneg += pr->pin_count();
775 break;
776 case NetEvProbe::POSEDGE:
777 obj->npos += pr->pin_count();
778 break;
782 unsigned npins = obj->nany + obj->nneg + obj->npos;
783 obj->pins = (ivl_nexus_t*)calloc(npins, sizeof(ivl_nexus_t));
785 } else {
786 obj->pins = 0;
791 void dll_target::logic(const NetLogic*net)
793 struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
795 obj->width_ = net->width();
797 switch (net->type()) {
798 case NetLogic::AND:
799 obj->type_ = IVL_LO_AND;
800 break;
801 case NetLogic::BUF:
802 obj->type_ = IVL_LO_BUF;
803 break;
804 case NetLogic::BUFIF0:
805 obj->type_ = IVL_LO_BUFIF0;
806 break;
807 case NetLogic::BUFIF1:
808 obj->type_ = IVL_LO_BUFIF1;
809 break;
810 case NetLogic::NAND:
811 obj->type_ = IVL_LO_NAND;
812 break;
813 case NetLogic::NMOS:
814 obj->type_ = IVL_LO_NMOS;
815 break;
816 case NetLogic::NOR:
817 obj->type_ = IVL_LO_NOR;
818 break;
819 case NetLogic::NOT:
820 obj->type_ = IVL_LO_NOT;
821 break;
822 case NetLogic::NOTIF0:
823 obj->type_ = IVL_LO_NOTIF0;
824 break;
825 case NetLogic::NOTIF1:
826 obj->type_ = IVL_LO_NOTIF1;
827 break;
828 case NetLogic::OR:
829 obj->type_ = IVL_LO_OR;
830 break;
831 case NetLogic::PULLDOWN:
832 obj->type_ = IVL_LO_PULLDOWN;
833 break;
834 case NetLogic::PULLUP:
835 obj->type_ = IVL_LO_PULLUP;
836 break;
837 case NetLogic::RNMOS:
838 obj->type_ = IVL_LO_RNMOS;
839 break;
840 case NetLogic::RPMOS:
841 obj->type_ = IVL_LO_RPMOS;
842 break;
843 case NetLogic::PMOS:
844 obj->type_ = IVL_LO_PMOS;
845 break;
846 case NetLogic::XNOR:
847 obj->type_ = IVL_LO_XNOR;
848 break;
849 case NetLogic::XOR:
850 obj->type_ = IVL_LO_XOR;
851 break;
852 default:
853 assert(0);
854 obj->type_ = IVL_LO_NONE;
855 break;
858 /* Connect all the ivl_nexus_t objects to the pins of the
859 device. */
861 obj->npins_ = net->pin_count();
862 obj->pins_ = new ivl_nexus_t[obj->npins_];
864 ivl_nexus_ptr_t out_ptr = 0;
866 for (unsigned idx = 0 ; idx < obj->npins_ ; idx += 1) {
867 const Nexus*nex = net->pin(idx).nexus();
868 assert(nex->t_cookie());
869 obj->pins_[idx] = nex->t_cookie();
870 ivl_nexus_ptr_t tmp = nexus_log_add(obj->pins_[idx], obj, idx);
871 if (idx == 0)
872 out_ptr = tmp;
875 switch (net->pin(0).drive0()) {
876 case Link::HIGHZ:
877 out_ptr->drive0 = IVL_DR_HiZ;
878 break;
879 case Link::WEAK:
880 out_ptr->drive0 = IVL_DR_WEAK;
881 break;
882 case Link::PULL:
883 out_ptr->drive0 = IVL_DR_PULL;
884 break;
885 case Link::STRONG:
886 out_ptr->drive0 = IVL_DR_STRONG;
887 break;
888 case Link::SUPPLY:
889 out_ptr->drive0 = IVL_DR_SUPPLY;
890 break;
893 switch (net->pin(0).drive1()) {
894 case Link::HIGHZ:
895 out_ptr->drive1 = IVL_DR_HiZ;
896 break;
897 case Link::WEAK:
898 out_ptr->drive1 = IVL_DR_WEAK;
899 break;
900 case Link::PULL:
901 out_ptr->drive1 = IVL_DR_PULL;
902 break;
903 case Link::STRONG:
904 out_ptr->drive1 = IVL_DR_STRONG;
905 break;
906 case Link::SUPPLY:
907 out_ptr->drive1 = IVL_DR_SUPPLY;
908 break;
911 assert(net->scope());
912 ivl_scope_t scope = find_scope(des_, net->scope());
913 assert(scope);
915 obj->scope_= scope;
916 obj->name_ = net->name();
918 logic_attributes(obj, net);
920 make_logic_delays_(obj, net);
922 scope_add_logic(scope, obj);
925 bool dll_target::sign_extend(const NetSignExtend*net)
927 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
928 obj->type = IVL_LPM_SIGN_EXT;
929 obj->width = net->width();
930 obj->name = net->name();
931 obj->scope = find_scope(des_, net->scope());
932 assert(obj->scope);
934 const Nexus*nex;
936 nex = net->pin(0).nexus();
937 assert(nex->t_cookie());
939 obj->u_.reduce.q = nex->t_cookie();
940 nexus_lpm_add(obj->u_.reduce.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
942 nex = net->pin(1).nexus();
943 assert(nex->t_cookie());
945 obj->u_.reduce.a = nex->t_cookie();
946 nexus_lpm_add(obj->u_.reduce.a, obj, 1, IVL_DR_HiZ, IVL_DR_HiZ);
948 scope_add_lpm(obj->scope, obj);
950 return true;
953 bool dll_target::ureduce(const NetUReduce*net)
955 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
956 switch (net->type()) {
957 case NetUReduce::NONE:
958 assert(0);
959 return false;
960 case NetUReduce::AND:
961 obj->type = IVL_LPM_RE_AND;
962 break;
963 case NetUReduce::OR:
964 obj->type = IVL_LPM_RE_OR;
965 break;
966 case NetUReduce::XOR:
967 obj->type = IVL_LPM_RE_XOR;
968 break;
969 case NetUReduce::NAND:
970 obj->type = IVL_LPM_RE_NAND;
971 break;
972 case NetUReduce::NOR:
973 obj->type = IVL_LPM_RE_NOR;
974 break;
975 case NetUReduce::XNOR:
976 obj->type = IVL_LPM_RE_XNOR;
977 break;
980 obj->name = net->name();
981 obj->scope = find_scope(des_, net->scope());
982 assert(obj->scope);
984 obj->width = net->width();
986 const Nexus*nex;
988 nex = net->pin(0).nexus();
989 assert(nex->t_cookie());
991 obj->u_.reduce.q = nex->t_cookie();
992 nexus_lpm_add(obj->u_.reduce.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
994 nex = net->pin(1).nexus();
995 assert(nex->t_cookie());
997 obj->u_.reduce.a = nex->t_cookie();
998 nexus_lpm_add(obj->u_.reduce.a, obj, 1, IVL_DR_HiZ, IVL_DR_HiZ);
1000 scope_add_lpm(obj->scope, obj);
1002 return true;
1005 void dll_target::net_case_cmp(const NetCaseCmp*net)
1007 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1008 obj->type = net->eeq()? IVL_LPM_CMP_EEQ : IVL_LPM_CMP_NEE;
1009 obj->name = net->name();
1010 obj->scope = find_scope(des_, net->scope());
1011 assert(obj->scope);
1013 obj->width = net->width();
1014 obj->u_.arith.signed_flag = 0;
1016 const Nexus*nex;
1018 nex = net->pin(1).nexus();
1019 assert(nex->t_cookie());
1021 obj->u_.arith.a = nex->t_cookie();
1022 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1024 nex = net->pin(2).nexus();
1025 assert(nex->t_cookie());
1027 obj->u_.arith.b = nex->t_cookie();
1028 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1030 nex = net->pin(0).nexus();
1031 assert(nex->t_cookie());
1033 obj->u_.arith.q = nex->t_cookie();
1034 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1036 scope_add_lpm(obj->scope, obj);
1039 bool dll_target::net_sysfunction(const NetSysFunc*net)
1041 unsigned idx;
1042 const Nexus*nex;
1044 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1045 obj->type = IVL_LPM_SFUNC;
1046 obj->name = net->name();
1047 obj->scope = find_scope(des_, net->scope());
1048 assert(obj->scope);
1050 obj->u_.sfunc.ports = net->pin_count();
1052 assert(net->pin_count() >= 1);
1053 obj->width = net->vector_width();
1055 obj->u_.sfunc.fun_name = net->func_name();
1057 obj->u_.sfunc.pins = new ivl_nexus_t[net->pin_count()];
1059 nex = net->pin(0).nexus();
1060 assert(nex->t_cookie());
1062 obj->u_.sfunc.pins[0] = nex->t_cookie();
1063 nexus_lpm_add(obj->u_.sfunc.pins[0], obj, 0,
1064 IVL_DR_STRONG, IVL_DR_STRONG);
1066 for (idx = 1 ; idx < net->pin_count() ; idx += 1) {
1067 nex = net->pin(idx).nexus();
1068 assert(nex->t_cookie());
1070 obj->u_.sfunc.pins[idx] = nex->t_cookie();
1071 nexus_lpm_add(obj->u_.sfunc.pins[idx], obj, 0,
1072 IVL_DR_HiZ, IVL_DR_HiZ);
1075 scope_add_lpm(obj->scope, obj);
1076 return true;
1080 * An IVL_LPM_UFUNC represents a node in a combinational expression
1081 * that calls a user defined function. I create an LPM object that has
1082 * the right connections, and refers to the ivl_scope_t of the
1083 * definition.
1085 bool dll_target::net_function(const NetUserFunc*net)
1087 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1088 obj->type = IVL_LPM_UFUNC;
1089 obj->name = net->name();
1090 obj->scope = find_scope(des_, net->scope());
1091 assert(obj->scope);
1093 /* Get the definition of the function and save it. */
1094 const NetScope*def = net->def();
1095 assert(def);
1097 obj->u_.ufunc.def = lookup_scope_(def);
1099 /* Save information about the ports in the ivl_lpm_s
1100 structure. Note that port 0 is the return value. */
1101 obj->u_.ufunc.ports = net->pin_count();
1103 assert(net->pin_count() >= 1);
1104 obj->width = net->port_width(0);
1106 /* Now collect all the pins and connect them to the nexa of
1107 the net. The output pins have strong drive, and the
1108 remaining input pins are HiZ. */
1110 obj->u_.ufunc.pins = new ivl_nexus_t[net->pin_count()];
1112 for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
1113 const Nexus*nex = net->pin(idx).nexus();
1114 assert(nex->t_cookie());
1115 ivl_nexus_t nn = nex->t_cookie();
1116 assert(nn);
1118 obj->u_.ufunc.pins[idx] = nn;
1119 ivl_drive_t drive = idx == 0 ? IVL_DR_STRONG : IVL_DR_HiZ;
1120 nexus_lpm_add(obj->u_.ufunc.pins[idx], obj, idx, drive, drive);
1123 /* All done. Add this LPM to the scope. */
1124 scope_add_lpm(obj->scope, obj);
1126 return true;
1129 void dll_target::udp(const NetUDP*net)
1131 struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
1133 obj->type_ = IVL_LO_UDP;
1135 /* The NetUDP class hasn't learned about width yet, so we
1136 assume a width of 1. */
1137 obj->width_ = 1;
1139 static map<perm_string,ivl_udp_t> udps;
1140 ivl_udp_t u;
1142 if (udps.find(net->udp_name()) != udps.end())
1144 u = udps[net->udp_name()];
1146 else
1148 u = new struct ivl_udp_s;
1149 u->nrows = net->rows();
1150 u->table = (ivl_udp_s::ccharp_t*)malloc((u->nrows+1)*sizeof(char*));
1151 assert(u->table);
1152 u->table[u->nrows] = 0x0;
1153 u->nin = net->nin();
1154 u->sequ = net->is_sequential();
1155 if (u->sequ)
1156 u->init = net->get_initial();
1157 u->name = net->udp_name();
1158 string inp;
1159 char out;
1160 unsigned int i = 0;
1161 if (net->first(inp, out))
1164 string tt = inp+out;
1165 u->table[i++] = strings_.add(tt.c_str());
1166 } while (net->next(inp, out));
1167 assert(i==u->nrows);
1169 udps[net->udp_name()] = u;
1172 obj->udp = u;
1174 // Some duplication of code here, see: dll_target::logic()
1176 /* Connect all the ivl_nexus_t objects to the pins of the
1177 device. */
1179 obj->npins_ = net->pin_count();
1180 obj->pins_ = new ivl_nexus_t[obj->npins_];
1181 for (unsigned idx = 0 ; idx < obj->npins_ ; idx += 1) {
1182 const Nexus*nex = net->pin(idx).nexus();
1184 /* Skip unconnected input pins. These will take on HiZ
1185 values by the code generators. */
1186 if (nex->t_cookie() == 0) {
1187 obj->pins_[idx] = 0;
1188 continue;
1191 assert(nex->t_cookie());
1192 obj->pins_[idx] = nex->t_cookie();
1193 nexus_log_add(obj->pins_[idx], obj, idx);
1196 assert(net->scope());
1197 ivl_scope_t scope = find_scope(des_, net->scope());
1198 assert(scope);
1200 obj->scope_= scope;
1201 obj->name_ = net->name();
1203 make_logic_delays_(obj, net);
1205 obj->nattr = 0;
1206 obj->attr = 0;
1208 scope_add_logic(scope, obj);
1211 void dll_target::lpm_add_sub(const NetAddSub*net)
1213 ivl_lpm_t obj = new struct ivl_lpm_s;
1214 if (net->attribute(perm_string::literal("LPM_Direction")) == verinum("SUB"))
1215 obj->type = IVL_LPM_SUB;
1216 else
1217 obj->type = IVL_LPM_ADD;
1218 obj->name = net->name(); // NetAddSub names are permallocated.
1219 assert(net->scope());
1220 obj->scope = find_scope(des_, net->scope());
1221 assert(obj->scope);
1223 obj->u_.arith.signed_flag = 0;
1225 /* Choose the width of the adder. If the carry bit is
1226 connected, then widen the adder by one and plan on leaving
1227 the fake inputs unconnected. */
1228 obj->width = net->width();
1229 if (net->pin_Cout().is_linked()) {
1230 obj->width += 1;
1234 const Nexus*nex;
1236 nex = net->pin_Result().nexus();
1237 assert(nex->t_cookie());
1239 obj->u_.arith.q = nex->t_cookie();
1240 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1242 nex = net->pin_DataA().nexus();
1243 assert(nex->t_cookie());
1245 obj->u_.arith.a = nex->t_cookie();
1246 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1248 nex = net->pin_DataB().nexus();
1249 assert(nex->t_cookie());
1251 obj->u_.arith.b = nex->t_cookie();
1252 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1254 /* If the carry output is connected, then connect the extra Q
1255 pin to the carry nexus and zero the a and b inputs. */
1256 if (net->pin_Cout().is_linked()) {
1257 cerr << "XXXX: t-dll.cc: Forgot how to connect cout." << endl;
1260 scope_add_lpm(obj->scope, obj);
1263 bool dll_target::lpm_array_dq(const NetArrayDq*net)
1265 ivl_lpm_t obj = new struct ivl_lpm_s;
1266 obj->type = IVL_LPM_ARRAY;
1267 obj->name = net->name();
1268 obj->u_.array.sig = find_signal(des_, net->mem());
1269 assert(obj->u_.array.sig);
1270 obj->scope = find_scope(des_, net->scope());
1271 assert(obj->scope);
1272 obj->width = net->width();
1273 obj->u_.array.swid = net->awidth();
1275 scope_add_lpm(obj->scope, obj);
1277 const Nexus*nex;
1279 nex = net->pin_Address().nexus();
1280 assert(nex->t_cookie());
1281 obj->u_.array.a = nex->t_cookie();
1282 nexus_lpm_add(obj->u_.array.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1284 nex = net->pin_Result().nexus();
1285 assert(nex->t_cookie());
1286 obj->u_.array.q = nex->t_cookie();
1287 nexus_lpm_add(obj->u_.array.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1289 return true;
1293 * The lpm_clshift device represents both left and right shifts,
1294 * depending on what is connected to the Direction pin. We convert
1295 * this device into SHIFTL or SHIFTR devices.
1297 void dll_target::lpm_clshift(const NetCLShift*net)
1299 ivl_lpm_t obj = new struct ivl_lpm_s;
1300 obj->type = IVL_LPM_SHIFTL;
1301 obj->name = net->name();
1302 assert(net->scope());
1303 obj->scope = find_scope(des_, net->scope());
1304 assert(obj->scope);
1306 /* Look at the direction input of the device, and select the
1307 shift direction accordingly. */
1308 if (net->right_flag())
1309 obj->type = IVL_LPM_SHIFTR;
1310 if (net->signed_flag())
1311 obj->u_.shift.signed_flag = 1;
1312 else
1313 obj->u_.shift.signed_flag = 0;
1315 obj->width = net->width();
1316 obj->u_.shift.select = net->width_dist();
1318 const Nexus*nex;
1320 nex = net->pin_Result().nexus();
1321 assert(nex->t_cookie());
1323 obj->u_.shift.q = nex->t_cookie();
1324 nexus_lpm_add(obj->u_.shift.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1326 nex = net->pin_Data().nexus();
1327 assert(nex->t_cookie());
1329 obj->u_.shift.d = nex->t_cookie();
1330 nexus_lpm_add(obj->u_.shift.d, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1332 nex = net->pin_Distance().nexus();
1333 assert(nex->t_cookie());
1335 obj->u_.shift.s = nex->t_cookie();
1336 nexus_lpm_add(obj->u_.shift.s, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1338 scope_add_lpm(obj->scope, obj);
1342 * Make out of the NetCompare object an ivl_lpm_s object. The
1343 * comparators in ivl_target do not support < or <=, but they can be
1344 * trivially converted to > and >= by swapping the operands.
1346 void dll_target::lpm_compare(const NetCompare*net)
1348 ivl_lpm_t obj = new struct ivl_lpm_s;
1349 obj->name = net->name(); // NetCompare names are permallocated
1350 assert(net->scope());
1351 obj->scope = find_scope(des_, net->scope());
1352 assert(obj->scope);
1354 bool swap_operands = false;
1356 obj->width = net->width();
1357 obj->u_.arith.signed_flag = net->get_signed()? 1 : 0;
1359 const Nexus*nex;
1361 nex = net->pin_DataA().nexus();
1362 assert(nex->t_cookie());
1364 obj->u_.arith.a = nex->t_cookie();
1366 nex = net->pin_DataB().nexus();
1367 assert(nex->t_cookie());
1369 obj->u_.arith.b = nex->t_cookie();
1372 if (net->pin_AGEB().is_linked()) {
1373 nex = net->pin_AGEB().nexus();
1374 obj->type = IVL_LPM_CMP_GE;
1376 assert(nex->t_cookie());
1377 obj->u_.arith.q = nex->t_cookie();
1378 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1379 IVL_DR_STRONG, IVL_DR_STRONG);
1381 } else if (net->pin_AGB().is_linked()) {
1382 nex = net->pin_AGB().nexus();
1383 obj->type = IVL_LPM_CMP_GT;
1385 assert(nex->t_cookie());
1386 obj->u_.arith.q = nex->t_cookie();
1387 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1388 IVL_DR_STRONG, IVL_DR_STRONG);
1390 } else if (net->pin_ALEB().is_linked()) {
1391 nex = net->pin_ALEB().nexus();
1392 obj->type = IVL_LPM_CMP_GE;
1394 assert(nex->t_cookie());
1395 obj->u_.arith.q = nex->t_cookie();
1396 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1397 IVL_DR_STRONG, IVL_DR_STRONG);
1399 swap_operands = true;
1401 } else if (net->pin_ALB().is_linked()) {
1402 nex = net->pin_ALB().nexus();
1403 obj->type = IVL_LPM_CMP_GT;
1405 assert(nex->t_cookie());
1406 obj->u_.arith.q = nex->t_cookie();
1407 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1408 IVL_DR_STRONG, IVL_DR_STRONG);
1410 swap_operands = true;
1412 } else if (net->pin_AEB().is_linked()) {
1413 nex = net->pin_AEB().nexus();
1414 obj->type = IVL_LPM_CMP_EQ;
1416 assert(nex->t_cookie());
1417 obj->u_.arith.q = nex->t_cookie();
1418 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1419 IVL_DR_STRONG, IVL_DR_STRONG);
1421 } else if (net->pin_ANEB().is_linked()) {
1422 nex = net->pin_ANEB().nexus();
1423 obj->type = IVL_LPM_CMP_NE;
1425 assert(nex->t_cookie());
1426 obj->u_.arith.q = nex->t_cookie();
1427 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1428 IVL_DR_STRONG, IVL_DR_STRONG);
1430 } else {
1431 assert(0);
1434 if (swap_operands) {
1435 ivl_nexus_t tmp = obj->u_.arith.a;
1436 obj->u_.arith.a = obj->u_.arith.b;
1437 obj->u_.arith.b = tmp;
1440 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1441 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1443 scope_add_lpm(obj->scope, obj);
1446 void dll_target::lpm_divide(const NetDivide*net)
1448 ivl_lpm_t obj = new struct ivl_lpm_s;
1449 obj->type = IVL_LPM_DIVIDE;
1450 obj->name = net->name();
1451 assert(net->scope());
1452 obj->scope = find_scope(des_, net->scope());
1453 assert(obj->scope);
1455 unsigned wid = net->width_r();
1457 obj->width = wid;
1458 obj->u_.arith.signed_flag = net->get_signed()? 1 : 0;
1460 const Nexus*nex;
1462 nex = net->pin_Result().nexus();
1463 assert(nex->t_cookie());
1465 obj->u_.arith.q = nex->t_cookie();
1466 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1468 nex = net->pin_DataA().nexus();
1469 assert(nex->t_cookie());
1471 obj->u_.arith.a = nex->t_cookie();
1472 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1474 nex = net->pin_DataB().nexus();
1475 assert(nex->t_cookie());
1477 obj->u_.arith.b = nex->t_cookie();
1478 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1481 scope_add_lpm(obj->scope, obj);
1484 void dll_target::lpm_modulo(const NetModulo*net)
1486 ivl_lpm_t obj = new struct ivl_lpm_s;
1487 obj->type = IVL_LPM_MOD;
1488 obj->name = net->name();
1489 assert(net->scope());
1490 obj->scope = find_scope(des_, net->scope());
1491 assert(obj->scope);
1493 unsigned wid = net->width_r();
1495 obj->width = wid;
1496 obj->u_.arith.signed_flag = 0;
1498 const Nexus*nex;
1500 nex = net->pin_Result().nexus();
1501 assert(nex->t_cookie());
1503 obj->u_.arith.q = nex->t_cookie();
1504 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1506 nex = net->pin_DataA().nexus();
1507 assert(nex->t_cookie());
1509 obj->u_.arith.a = nex->t_cookie();
1510 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1512 nex = net->pin_DataB().nexus();
1513 assert(nex->t_cookie());
1515 obj->u_.arith.b = nex->t_cookie();
1516 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1518 scope_add_lpm(obj->scope, obj);
1521 void dll_target::lpm_ff(const NetFF*net)
1523 ivl_lpm_t obj = new struct ivl_lpm_s;
1524 obj->type = IVL_LPM_FF;
1525 obj->name = net->name();
1526 obj->scope = find_scope(des_, net->scope());
1527 assert(obj->scope);
1529 obj->width = net->width();
1531 scope_add_lpm(obj->scope, obj);
1533 const Nexus*nex;
1535 /* Set the clk signal to point to the nexus, and the nexus to
1536 point back to this device. */
1537 nex = net->pin_Clock().nexus();
1538 assert(nex->t_cookie());
1539 obj->u_.ff.clk = nex->t_cookie();
1540 assert(obj->u_.ff.clk);
1541 nexus_lpm_add(obj->u_.ff.clk, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1543 /* If there is a clock enable, then connect it up to the FF
1544 device. */
1545 if (net->pin_Enable().is_linked()) {
1546 nex = net->pin_Enable().nexus();
1547 assert(nex->t_cookie());
1548 obj->u_.ff.we = nex->t_cookie();
1549 assert(obj->u_.ff.we);
1550 nexus_lpm_add(obj->u_.ff.we, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1551 } else {
1552 obj->u_.ff.we = 0;
1555 if (net->pin_Aclr().is_linked()) {
1556 nex = net->pin_Aclr().nexus();
1557 assert(nex->t_cookie());
1558 obj->u_.ff.aclr = nex->t_cookie();
1559 assert(obj->u_.ff.aclr);
1560 nexus_lpm_add(obj->u_.ff.aclr, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1561 } else {
1562 obj->u_.ff.aclr = 0;
1565 if (net->pin_Aset().is_linked()) {
1566 nex = net->pin_Aset().nexus();
1567 assert(nex->t_cookie());
1568 obj->u_.ff.aset = nex->t_cookie();
1569 assert(obj->u_.ff.aset);
1570 nexus_lpm_add(obj->u_.ff.aset, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1572 verinum tmp = net->aset_value();
1573 obj->u_.ff.aset_value = expr_from_value_(tmp);
1575 } else {
1576 obj->u_.ff.aset = 0;
1577 obj->u_.ff.aset_value = 0;
1580 if (net->pin_Sclr().is_linked()) {
1581 nex = net->pin_Sclr().nexus();
1582 assert(nex->t_cookie());
1583 obj->u_.ff.sclr = nex->t_cookie();
1584 assert(obj->u_.ff.sclr);
1585 nexus_lpm_add(obj->u_.ff.sclr, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1586 } else {
1587 obj->u_.ff.sclr = 0;
1590 if (net->pin_Sset().is_linked()) {
1591 nex = net->pin_Sset().nexus();
1592 assert(nex->t_cookie());
1593 obj->u_.ff.sset = nex->t_cookie();
1594 assert(obj->u_.ff.sset);
1595 nexus_lpm_add(obj->u_.ff.sset, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1597 verinum tmp = net->sset_value();
1598 obj->u_.ff.sset_value = expr_from_value_(tmp);
1600 } else {
1601 obj->u_.ff.sset = 0;
1602 obj->u_.ff.sset_value = 0;
1605 nex = net->pin_Q().nexus();
1606 assert(nex->t_cookie());
1607 obj->u_.ff.q.pin = nex->t_cookie();
1608 nexus_lpm_add(obj->u_.ff.q.pin, obj, 0,
1609 IVL_DR_STRONG, IVL_DR_STRONG);
1611 nex = net->pin_Data().nexus();
1612 assert(nex->t_cookie());
1613 obj->u_.ff.d.pin = nex->t_cookie();
1614 nexus_lpm_add(obj->u_.ff.d.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1619 * Make the NetMult object into an IVL_LPM_MULT node.
1621 void dll_target::lpm_mult(const NetMult*net)
1623 ivl_lpm_t obj = new struct ivl_lpm_s;
1624 obj->type = IVL_LPM_MULT;
1625 obj->name = net->name();
1626 assert(net->scope());
1627 obj->scope = find_scope(des_, net->scope());
1628 assert(obj->scope);
1630 unsigned wid = net->width_r();
1632 obj->width = wid;
1634 const Nexus*nex;
1636 nex = net->pin_Result().nexus();
1637 assert(nex->t_cookie());
1639 obj->u_.arith.q = nex->t_cookie();
1640 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1642 nex = net->pin_DataA().nexus();
1643 assert(nex->t_cookie());
1645 obj->u_.arith.a = nex->t_cookie();
1646 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1648 nex = net->pin_DataB().nexus();
1649 assert(nex->t_cookie());
1651 obj->u_.arith.b = nex->t_cookie();
1652 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1655 scope_add_lpm(obj->scope, obj);
1659 * Hook up the mux devices so that the select expression selects the
1660 * correct sub-expression with the ivl_lpm_data2 function.
1662 void dll_target::lpm_mux(const NetMux*net)
1664 ivl_lpm_t obj = new struct ivl_lpm_s;
1665 obj->type = IVL_LPM_MUX;
1666 obj->name = net->name(); // The NetMux perallocates its name.
1667 obj->scope = find_scope(des_, net->scope());
1668 assert(obj->scope);
1670 obj->width = net->width();
1671 obj->u_.mux.size = net->size();
1672 obj->u_.mux.swid = net->sel_width();
1674 scope_add_lpm(obj->scope, obj);
1676 const Nexus*nex;
1678 /* Connect the output bits. */
1679 nex = net->pin_Result().nexus();
1680 assert(nex->t_cookie());
1681 obj->u_.mux.q = nex->t_cookie();
1682 nexus_lpm_add(obj->u_.mux.q, obj, 0,
1683 IVL_DR_STRONG, IVL_DR_STRONG);
1685 /* Connect the select bits. */
1686 nex = net->pin_Sel().nexus();
1687 assert(nex->t_cookie());
1688 obj->u_.mux.s = nex->t_cookie();
1689 nexus_lpm_add(obj->u_.mux.s, obj, 0,
1690 IVL_DR_HiZ, IVL_DR_HiZ);
1692 unsigned selects = obj->u_.mux.size;
1694 obj->u_.mux.d = new ivl_nexus_t [selects];
1696 for (unsigned sdx = 0 ; sdx < selects ; sdx += 1) {
1697 nex = net->pin_Data(sdx).nexus();
1698 ivl_nexus_t tmp = nex->t_cookie();
1699 obj->u_.mux.d[sdx] = tmp;
1700 nexus_lpm_add(tmp, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1705 bool dll_target::concat(const NetConcat*net)
1707 ivl_lpm_t obj = new struct ivl_lpm_s;
1708 obj->type = IVL_LPM_CONCAT;
1709 obj->name = net->name(); // NetConcat names are permallocated
1710 assert(net->scope());
1711 obj->scope = find_scope(des_, net->scope());
1712 assert(obj->scope);
1714 obj->width = net->width();
1716 obj->u_.concat.inputs = net->pin_count() - 1;
1717 obj->u_.concat.pins = new ivl_nexus_t[obj->u_.concat.inputs+1];
1719 for (unsigned idx = 0 ; idx < obj->u_.concat.inputs+1 ; idx += 1) {
1720 ivl_drive_t dr = idx == 0? IVL_DR_STRONG : IVL_DR_HiZ;
1721 const Nexus*nex = net->pin(idx).nexus();
1722 assert(nex->t_cookie());
1724 obj->u_.concat.pins[idx] = nex->t_cookie();
1725 nexus_lpm_add(obj->u_.concat.pins[idx], obj, 0, dr, dr);
1728 scope_add_lpm(obj->scope, obj);
1730 return true;
1733 bool dll_target::part_select(const NetPartSelect*net)
1735 ivl_lpm_t obj = new struct ivl_lpm_s;
1736 switch (net->dir()) {
1737 case NetPartSelect::VP:
1738 obj->type = IVL_LPM_PART_VP;
1739 break;
1740 case NetPartSelect::PV:
1741 obj->type = IVL_LPM_PART_PV;
1742 break;
1743 case NetPartSelect::BI:
1744 obj->type = IVL_LPM_PART_BI;
1745 break;
1747 obj->name = net->name(); // NetPartSelect names are permallocated.
1748 assert(net->scope());
1749 obj->scope = find_scope(des_, net->scope());
1750 assert(obj->scope);
1752 /* Part selects are always unsigned. */
1753 obj->u_.part.signed_flag = 0;
1755 /* Choose the width of the part select. */
1756 obj->width = net->width();
1757 obj->u_.part.base = net->base();
1758 obj->u_.part.s = 0;
1760 const Nexus*nex;
1762 switch (obj->type) {
1763 case IVL_LPM_PART_VP:
1764 /* NetPartSelect:pin(0) is the output pin. */
1765 nex = net->pin(0).nexus();
1766 assert(nex->t_cookie());
1768 obj->u_.part.q = nex->t_cookie();
1770 /* NetPartSelect:pin(1) is the input pin. */
1771 nex = net->pin(1).nexus();
1772 assert(nex->t_cookie());
1774 obj->u_.part.a = nex->t_cookie();
1776 /* If the part select has an additional pin, that pin is
1777 a variable select base. */
1778 if (net->pin_count() >= 3) {
1779 nex = net->pin(2).nexus();
1780 assert(nex->t_cookie());
1781 obj->u_.part.s = nex->t_cookie();
1783 break;
1785 case IVL_LPM_PART_PV:
1786 /* NetPartSelect:pin(1) is the output pin. */
1787 nex = net->pin(1).nexus();
1788 assert(nex->t_cookie());
1790 obj->u_.part.q = nex->t_cookie();
1792 /* NetPartSelect:pin(0) is the input pin. */
1793 nex = net->pin(0).nexus();
1794 assert(nex->t_cookie());
1796 obj->u_.part.a = nex->t_cookie();
1797 break;
1799 case IVL_LPM_PART_BI:
1800 /* For now, handle this exactly the same as a PV */
1802 /* NetPartSelect:pin(0) is the output pin. */
1803 nex = net->pin(0).nexus();
1804 assert(nex->t_cookie());
1806 obj->u_.part.q = nex->t_cookie();
1808 /* NetPartSelect:pin(1) is the input pin. */
1809 nex = net->pin(1).nexus();
1810 assert(nex->t_cookie());
1812 obj->u_.part.a = nex->t_cookie();
1813 break;
1815 default:
1816 assert(0);
1819 nexus_lpm_add(obj->u_.part.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1821 /* If the device is a PART_BI, then the "input" is also a
1822 strength aware output, so attach it to the nexus with
1823 strong driver. */
1824 if (obj->type == IVL_LPM_PART_BI)
1825 nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1826 else
1827 nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1829 /* The select input is optional. */
1830 if (obj->u_.part.s)
1831 nexus_lpm_add(obj->u_.part.s, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1833 scope_add_lpm(obj->scope, obj);
1835 return true;
1838 bool dll_target::replicate(const NetReplicate*net)
1840 ivl_lpm_t obj = new struct ivl_lpm_s;
1841 obj->type = IVL_LPM_REPEAT;
1842 obj->name = net->name();
1843 assert(net->scope());
1844 obj->scope = find_scope(des_, net->scope());
1845 assert(obj->scope);
1847 obj->width = net->width();
1848 obj->u_.repeat.count = net->repeat();
1850 ivl_drive_t dr = IVL_DR_STRONG;
1851 const Nexus*nex = net->pin(0).nexus();
1852 assert(nex->t_cookie());
1854 obj->u_.repeat.q = nex->t_cookie();
1855 nexus_lpm_add(obj->u_.repeat.q, obj, 0, dr, dr);
1857 dr = IVL_DR_HiZ;
1858 nex = net->pin(1).nexus();
1859 assert(nex->t_cookie());
1861 obj->u_.repeat.a = nex->t_cookie();
1862 nexus_lpm_add(obj->u_.repeat.a, obj, 0, dr, dr);
1864 scope_add_lpm(obj->scope, obj);
1866 return true;
1870 * The assignment l-values are captured by the assignment statements
1871 * themselves in the process handling.
1873 void dll_target::net_assign(const NetAssign_*)
1877 bool dll_target::net_const(const NetConst*net)
1879 unsigned idx;
1880 char*bits;
1882 struct ivl_net_const_s *obj = new struct ivl_net_const_s;
1884 obj->type = IVL_VT_LOGIC;
1886 /* constants have a single vector output. */
1887 assert(net->pin_count() == 1);
1889 obj->width_ = net->width();
1890 if (obj->width_ <= sizeof(obj->b.bit_)) {
1891 bits = obj->b.bit_;
1893 } else {
1894 obj->b.bits_ = (char*)malloc(obj->width_);
1895 bits = obj->b.bits_;
1898 for (idx = 0 ; idx < obj->width_ ; idx += 1)
1899 switch (net->value(idx)) {
1900 case verinum::V0:
1901 bits[idx] = '0';
1902 break;
1903 case verinum::V1:
1904 bits[idx] = '1';
1905 break;
1906 case verinum::Vx:
1907 bits[idx] = 'x';
1908 break;
1909 case verinum::Vz:
1910 bits[idx] = 'z';
1911 break;
1914 /* Connect to all the nexus objects. Note that the one-bit
1915 case can be handled more efficiently without allocating
1916 array space. */
1918 ivl_drive_t drv0, drv1;
1919 drive_from_link(net->pin(0), drv0, drv1);
1920 const Nexus*nex = net->pin(0).nexus();
1921 assert(nex->t_cookie());
1922 obj->pin_ = nex->t_cookie();
1923 nexus_con_add(obj->pin_, obj, 0, drv0, drv1);
1926 des_.nconsts += 1;
1927 des_.consts = (ivl_net_const_t*)
1928 realloc(des_.consts, des_.nconsts * sizeof(ivl_net_const_t));
1929 des_.consts[des_.nconsts-1] = obj;
1931 return true;
1934 bool dll_target::net_literal(const NetLiteral*net)
1937 struct ivl_net_const_s *obj = new struct ivl_net_const_s;
1939 obj->type = IVL_VT_REAL;
1940 obj->width_ = 1;
1941 obj->signed_ = 1;
1942 obj->b.real_value = net->value_real().as_double();
1944 /* Connect to all the nexus objects. Note that the one-bit
1945 case can be handled more efficiently without allocating
1946 array space. */
1948 ivl_drive_t drv0, drv1;
1949 drive_from_link(net->pin(0), drv0, drv1);
1950 const Nexus*nex = net->pin(0).nexus();
1951 assert(nex->t_cookie());
1952 obj->pin_ = nex->t_cookie();
1953 nexus_con_add(obj->pin_, obj, 0, drv0, drv1);
1955 des_.nconsts += 1;
1956 des_.consts = (ivl_net_const_t*)
1957 realloc(des_.consts, des_.nconsts * sizeof(ivl_net_const_t));
1958 des_.consts[des_.nconsts-1] = obj;
1960 return true;
1963 void dll_target::net_probe(const NetEvProbe*net)
1967 void dll_target::scope(const NetScope*net)
1969 ivl_scope_t scope;
1971 if (net->parent() == 0) {
1972 unsigned i;
1973 scope = NULL;
1974 for (i = 0; i < des_.nroots_ && scope == NULL; i++) {
1975 if (strcmp(des_.roots_[i]->name_, net->basename()) == 0)
1976 scope = des_.roots_[i];
1978 assert(scope);
1980 } else {
1981 perm_string sname = make_scope_name(net->fullname());
1982 scope = new struct ivl_scope_s;
1983 scope->name_ = sname;
1984 scope->child_ = 0;
1985 scope->sibling_ = 0;
1986 scope->parent = find_scope(des_, net->parent());
1987 assert(scope->parent);
1988 scope->nsigs_ = 0;
1989 scope->sigs_ = 0;
1990 scope->nlog_ = 0;
1991 scope->log_ = 0;
1992 scope->nevent_ = 0;
1993 scope->event_ = 0;
1994 scope->nlpm_ = 0;
1995 scope->lpm_ = 0;
1996 scope->def = 0;
1997 make_scope_parameters(scope, net);
1998 scope->time_units = net->time_unit();
1999 scope->nattr = net->attr_cnt();
2000 scope->attr = fill_in_attributes(net);
2002 switch (net->type()) {
2003 case NetScope::MODULE:
2004 scope->type_ = IVL_SCT_MODULE;
2005 scope->tname_ = net->module_name();
2006 break;
2007 case NetScope::TASK: {
2008 const NetTaskDef*def = net->task_def();
2009 if (def == 0) {
2010 cerr << "?:?" << ": internal error: "
2011 << "task " << scope->name_
2012 << " has no definition." << endl;
2014 assert(def);
2015 scope->type_ = IVL_SCT_TASK;
2016 scope->tname_ = def->scope()->basename();
2017 break;
2019 case NetScope::FUNC:
2020 scope->type_ = IVL_SCT_FUNCTION;
2021 scope->tname_ = net->func_def()->scope()->basename();
2022 break;
2023 case NetScope::BEGIN_END:
2024 scope->type_ = IVL_SCT_BEGIN;
2025 scope->tname_ = scope->name_;
2026 break;
2027 case NetScope::FORK_JOIN:
2028 scope->type_ = IVL_SCT_FORK;
2029 scope->tname_ = scope->name_;
2030 break;
2031 case NetScope::GENBLOCK:
2032 scope->type_ = IVL_SCT_GENERATE;
2033 scope->tname_ = scope->name_;
2034 break;
2037 assert(scope->parent != 0);
2039 scope->sibling_= scope->parent->child_;
2040 scope->parent->child_ = scope;
2044 void dll_target::signal(const NetNet*net)
2046 ivl_signal_t obj = new struct ivl_signal_s;
2048 obj->name_ = net->name();
2050 /* Attach the signal to the ivl_scope_t object that contains
2051 it. This involves growing the sigs_ array in the scope
2052 object, or creating the sigs_ array if this is the first
2053 signal. */
2054 obj->scope_ = find_scope(des_, net->scope());
2055 assert(obj->scope_);
2057 if (obj->scope_->nsigs_ == 0) {
2058 assert(obj->scope_->sigs_ == 0);
2059 obj->scope_->nsigs_ = 1;
2060 obj->scope_->sigs_ = (ivl_signal_t*)malloc(sizeof(ivl_signal_t));
2062 } else {
2063 assert(obj->scope_->sigs_);
2064 obj->scope_->nsigs_ += 1;
2065 obj->scope_->sigs_ = (ivl_signal_t*)
2066 realloc(obj->scope_->sigs_,
2067 obj->scope_->nsigs_*sizeof(ivl_signal_t));
2070 obj->scope_->sigs_[obj->scope_->nsigs_-1] = obj;
2073 /* Save the primitive properties of the signal in the
2074 ivl_signal_t object. */
2076 obj->width_ = net->vector_width();
2077 obj->signed_= net->get_signed()? 1 : 0;
2078 obj->lsb_index = net->lsb();
2079 obj->lsb_dist = net->msb() >= net->lsb() ? 1 : -1;
2080 obj->isint_ = false;
2081 obj->local_ = (net->local_flag() && (net->peek_eref() == 0))? 1 : 0;
2083 obj->array_dimensions_ = net->array_dimensions();
2085 switch (net->port_type()) {
2087 case NetNet::PINPUT:
2088 obj->port_ = IVL_SIP_INPUT;
2089 break;
2091 case NetNet::POUTPUT:
2092 obj->port_ = IVL_SIP_OUTPUT;
2093 break;
2095 case NetNet::PINOUT:
2096 obj->port_ = IVL_SIP_INOUT;
2097 break;
2099 default:
2100 obj->port_ = IVL_SIP_NONE;
2101 break;
2104 switch (net->type()) {
2106 case NetNet::REG:
2107 obj->type_ = IVL_SIT_REG;
2108 obj->isint_ = net->get_isint();
2109 break;
2111 /* The SUPPLY0/1 net types are replaced with pulldown/up
2112 by elaborate. They should not make it here. */
2113 case NetNet::SUPPLY0:
2114 assert(0);
2115 break;
2116 case NetNet::SUPPLY1:
2117 assert(0);
2118 break;
2120 case NetNet::TRI:
2121 case NetNet::WIRE:
2122 case NetNet::IMPLICIT:
2123 obj->type_ = IVL_SIT_TRI;
2124 break;
2126 case NetNet::TRI0:
2127 obj->type_ = IVL_SIT_TRI0;
2128 break;
2130 case NetNet::TRI1:
2131 obj->type_ = IVL_SIT_TRI1;
2132 break;
2134 case NetNet::TRIAND:
2135 case NetNet::WAND:
2136 obj->type_ = IVL_SIT_TRIAND;
2137 break;
2139 case NetNet::TRIOR:
2140 case NetNet::WOR:
2141 obj->type_ = IVL_SIT_TRIOR;
2142 break;
2144 default:
2145 obj->type_ = IVL_SIT_NONE;
2146 break;
2149 /* Initialize the path fields to be filled in later. */
2150 obj->npath = 0;
2151 obj->path = 0;
2153 obj->data_type = net->data_type();
2154 obj->nattr = net->attr_cnt();
2155 obj->attr = fill_in_attributes(net);
2158 /* Get the nexus objects for all the pins of the signal. If
2159 the signal has only one pin, then write the single
2160 ivl_nexus_t object into n.pin_. Otherwise, make an array of
2161 ivl_nexus_t cookies.
2163 When I create an ivl_nexus_t object, store it in the
2164 t_cookie of the Nexus object so that I find it again when I
2165 next encounter the nexus. */
2167 obj->array_base = net->array_first();
2168 obj->array_words = net->array_count();
2169 if (obj->array_words > 1)
2170 obj->pins = new ivl_nexus_t[obj->array_words];
2172 for (unsigned idx = 0 ; idx < obj->array_words ; idx += 1) {
2174 const Nexus*nex = net->pin(idx).nexus();
2175 if (nex->t_cookie()) {
2176 if (obj->array_words > 1) {
2177 obj->pins[idx] = nex->t_cookie();
2178 nexus_sig_add(obj->pins[idx], obj, idx);
2179 } else {
2180 obj->pin = nex->t_cookie();
2181 nexus_sig_add(obj->pin, obj, idx);
2183 } else {
2184 ivl_nexus_t tmp = nexus_sig_make(obj, idx);
2185 tmp->nexus_ = nex;
2186 tmp->name_ = 0;
2187 nex->t_cookie(tmp);
2188 if (obj->array_words > 1)
2189 obj->pins[idx] = tmp;
2190 else
2191 obj->pin = tmp;
2196 bool dll_target::signal_paths(const NetNet*net)
2198 /* Nothing to do if there are no paths for this signal. */
2199 if (net->delay_paths() == 0)
2200 return true;
2202 ivl_signal_t obj = find_signal(des_, net);
2203 assert(obj);
2205 /* We cannot have already set up the paths for this signal. */
2206 assert(obj->npath == 0);
2207 assert(obj->path == 0);
2209 /* Figure out how many paths there really are. */
2210 for (unsigned idx = 0 ; idx < net->delay_paths() ; idx += 1) {
2211 const NetDelaySrc*src = net->delay_path(idx);
2212 obj->npath += src->src_count();
2215 obj->path = new struct ivl_delaypath_s[obj->npath];
2217 unsigned ptr = 0;
2218 for (unsigned idx = 0 ; idx < net->delay_paths() ; idx += 1) {
2219 const NetDelaySrc*src = net->delay_path(idx);
2221 /* If this path has a condition, then hook it up. */
2222 ivl_nexus_t path_condit = 0;
2223 if (src->is_condit()) {
2224 const Nexus*nt = src->condit_pin().nexus();
2225 path_condit = nt->t_cookie();
2228 for (unsigned pin = 0; pin < src->src_count(); pin += 1) {
2229 const Nexus*nex = src->src_pin(pin).nexus();
2230 if (! nex->t_cookie()) {
2231 cerr << src->get_line() << ": internal error: "
2232 << "No signal connected to pin " << pin
2233 << " of delay path to " << net->name()
2234 << "." << endl;
2236 assert(nex->t_cookie());
2237 obj->path[ptr].src = nex->t_cookie();
2238 obj->path[ptr].condit = path_condit;
2239 obj->path[ptr].posedge = src->is_posedge();
2240 obj->path[ptr].negedge = src->is_negedge();
2241 for (unsigned pe = 0 ; pe < 12 ; pe += 1) {
2242 obj->path[ptr].delay[pe] = src->get_delay(pe);
2245 ptr += 1;
2250 return true;
2253 extern const struct target tgt_dll = { "dll", &dll_target_obj };
2257 * $Log: t-dll.cc,v $
2258 * Revision 1.171 2007/06/02 03:42:13 steve
2259 * Properly evaluate scope path expressions.
2261 * Revision 1.170 2007/04/02 01:12:34 steve
2262 * Seperate arrayness from word count
2264 * Revision 1.169 2007/03/26 20:32:47 steve
2265 * More efficient allocate of ivl_nexus_t objects.
2267 * Revision 1.168 2007/03/26 18:17:51 steve
2268 * Remove pretense of general use for t_cookie.
2270 * Revision 1.167 2007/03/26 16:51:49 steve
2271 * do not calculate nexus name unless needed.
2273 * Revision 1.166 2007/03/02 06:13:22 steve
2274 * Add support for edge sensitive spec paths.
2276 * Revision 1.165 2007/03/01 06:19:39 steve
2277 * Add support for conditional specify delay paths.
2279 * Revision 1.164 2007/01/29 01:52:51 steve
2280 * Clarify the use of ivl_scope_def for not-functions.
2282 * Revision 1.163 2007/01/17 05:00:12 steve
2283 * Dead code for memories in scopes.
2285 * Revision 1.162 2007/01/16 05:44:15 steve
2286 * Major rework of array handling. Memories are replaced with the
2287 * more general concept of arrays. The NetMemory and NetEMemory
2288 * classes are removed from the ivl core program, and the IVL_LPM_RAM
2289 * lpm type is removed from the ivl_target API.
2291 * Revision 1.161 2006/11/10 05:44:45 steve
2292 * Process delay paths in second path over signals.
2294 * Revision 1.160 2006/10/15 03:25:58 steve
2295 * More detailed internal error message.
2297 * Revision 1.159 2006/09/28 00:29:49 steve
2298 * Allow specparams as constants in expressions.
2300 * Revision 1.158 2006/09/23 04:57:19 steve
2301 * Basic support for specify timing.
2303 * Revision 1.157 2006/06/18 04:15:50 steve
2304 * Add support for system functions in continuous assignments.
2306 * Revision 1.156 2006/04/10 00:37:42 steve
2307 * Add support for generate loops w/ wires and gates.
2309 * Revision 1.155 2006/01/02 05:33:19 steve
2310 * Node delays can be more general expressions in structural contexts.
2312 * Revision 1.154 2005/08/06 17:58:16 steve
2313 * Implement bi-directional part selects.
2315 * Revision 1.153 2005/07/11 16:56:51 steve
2316 * Remove NetVariable and ivl_variable_t structures.
2318 * Revision 1.152 2005/07/07 16:22:49 steve
2319 * Generalize signals to carry types.
2321 * Revision 1.151 2005/06/26 18:08:46 steve
2322 * Fix uninitialzied attr pointers for UDP devices.
2324 * Revision 1.150 2005/05/24 01:44:28 steve
2325 * Do sign extension of structuran nets.
2327 * Revision 1.149 2005/05/08 23:44:08 steve
2328 * Add support for variable part select.
2330 * Revision 1.148 2005/04/24 23:44:02 steve
2331 * Update DFF support to new data flow.
2333 * Revision 1.147 2005/04/06 05:29:08 steve
2334 * Rework NetRamDq and IVL_LPM_RAM nodes.
2336 * Revision 1.146 2005/04/01 06:04:30 steve
2337 * Clean up handle of UDPs.
2339 * Revision 1.145 2005/03/18 02:56:04 steve
2340 * Add support for LPM_UFUNC user defined functions.
2342 * Revision 1.144 2005/03/12 06:43:36 steve
2343 * Update support for LPM_MOD.
2345 * Revision 1.143 2005/03/09 05:52:04 steve
2346 * Handle case inequality in netlists.
2348 * Revision 1.142 2005/02/19 02:43:38 steve
2349 * Support shifts and divide.
2351 * Revision 1.141 2005/02/13 01:15:07 steve
2352 * Replace supply nets with wires connected to pullup/down supply devices.
2354 * Revision 1.140 2005/02/12 06:25:40 steve
2355 * Restructure NetMux devices to pass vectors.
2356 * Generate NetMux devices from ternary expressions,
2357 * Reduce NetMux devices to bufif when appropriate.
2359 * Revision 1.139 2005/02/08 00:12:36 steve
2360 * Add the NetRepeat node, and code generator support.
2362 * Revision 1.138 2005/02/03 04:56:20 steve
2363 * laborate reduction gates into LPM_RED_ nodes.
2365 * Revision 1.137 2005/01/28 05:39:33 steve
2366 * Simplified NetMult and IVL_LPM_MULT.
2368 * Revision 1.136 2005/01/22 01:06:55 steve
2369 * Change case compare from logic to an LPM node.
2371 * Revision 1.135 2005/01/16 04:20:32 steve
2372 * Implement LPM_COMPARE nodes as two-input vector functors.
2374 * Revision 1.134 2005/01/09 20:16:01 steve
2375 * Use PartSelect/PV and VP to handle part selects through ports.
2377 * Revision 1.133 2004/12/29 23:55:43 steve
2378 * Unify elaboration of l-values for all proceedural assignments,
2379 * including assing, cassign and force.
2381 * Generate NetConcat devices for gate outputs that feed into a
2382 * vector results. Use this to hande gate arrays. Also let gate
2383 * arrays handle vectors of gates when the outputs allow for it.
2385 * Revision 1.132 2004/12/11 02:31:28 steve
2386 * Rework of internals to carry vectors through nexus instead
2387 * of single bits. Make the ivl, tgt-vvp and vvp initial changes
2388 * down this path.
2390 * Revision 1.131 2004/10/04 01:10:55 steve
2391 * Clean up spurious trailing white space.
2393 * Revision 1.130 2004/06/30 02:16:27 steve
2394 * Implement signed divide and signed right shift in nets.
2396 * Revision 1.129 2004/02/20 18:53:35 steve
2397 * Addtrbute keys are perm_strings.
2399 * Revision 1.128 2004/02/20 06:22:58 steve
2400 * parameter keys are per_strings.
2402 * Revision 1.127 2004/02/19 06:57:10 steve
2403 * Memory and Event names use perm_string.
2405 * Revision 1.126 2004/02/18 17:11:58 steve
2406 * Use perm_strings for named langiage items.
2408 * Revision 1.125 2003/12/12 05:43:08 steve
2409 * Some systems dlsym requires leading _ or not on whim.
2411 * Revision 1.124 2003/11/26 01:37:38 steve
2412 * Warning about sprintf.
2414 * Revision 1.123 2003/11/13 05:55:33 steve
2415 * Move the DLL= flag to target config files.
2417 * Revision 1.122 2003/11/10 20:59:04 steve
2418 * Design::get_flag returns const char* instead of string.
2420 * Revision 1.121 2003/09/03 23:33:29 steve
2421 * Pass FF synchronous set values to code generator.
2423 * Revision 1.120 2003/08/22 04:14:33 steve
2424 * Fix uninitialized sset member.
2426 * Revision 1.119 2003/08/15 02:23:53 steve
2427 * Add synthesis support for synchronous reset.