Reformulate number-to-real on vvp code generator
[iverilog.git] / t-dll.cc
blobb8d0686693cc1140690c9d5c1d07527c2c7eb746
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_precision = s->time_precision();
546 root_->time_units = s->time_unit();
547 root_->nattr = s->attr_cnt();
548 root_->attr = fill_in_attributes(s);
550 des_.nroots_++;
551 if (des_.roots_)
552 des_.roots_ = (ivl_scope_t *)realloc(des_.roots_, des_.nroots_ * sizeof(ivl_scope_t));
553 else
554 des_.roots_ = (ivl_scope_t *)malloc(des_.nroots_ * sizeof(ivl_scope_t));
555 des_.roots_[des_.nroots_ - 1] = root_;
558 bool dll_target::start_design(const Design*des)
560 list<NetScope *> root_scopes;
561 const char*dll_path_ = des->get_flag("DLL");
563 dll_ = ivl_dlopen(dll_path_);
565 if ((dll_ == 0) && (dll_path_[0] != '/')) {
566 size_t len = strlen(basedir) + 1 + strlen(dll_path_) + 1;
567 char*tmp = new char[len];
568 sprintf(tmp, "%s/%s", basedir, dll_path_);
569 dll_ = ivl_dlopen(tmp);
570 delete[]tmp;
573 if (dll_ == 0) {
574 cerr << "error: " << dll_path_ << " failed to load." << endl;
575 cerr << dll_path_ << ": " << dlerror() << endl;
576 return false;
579 stmt_cur_ = 0;
581 // Initialize the design object.
582 des_.self = des;
583 des_.time_precision = des->get_precision();
584 des_.nroots_ = 0;
585 des_.roots_ = NULL;
587 root_scopes = des->find_root_scopes();
588 for (list<NetScope*>::const_iterator scope = root_scopes.begin();
589 scope != root_scopes.end(); scope++)
590 add_root(des_, *scope);
592 des_.consts = (ivl_net_const_t*)
593 malloc(sizeof(ivl_net_const_t));
594 des_.nconsts = 0;
596 target_ = (target_design_f)ivl_dlsym(dll_, LU "target_design" TU);
597 if (target_ == 0) {
598 cerr << dll_path_ << ": error: target_design entry "
599 "point is missing." << endl;
600 return false;
603 return true;
607 * Here ivl is telling us that the design is scanned completely, and
608 * here is where we call the API to process the constructed design.
610 int dll_target::end_design(const Design*)
612 if (verbose_flag) {
613 cout << " ... invoking target_design" << endl;
616 int rc = (target_)(&des_);
617 ivl_dlclose(dll_);
618 return rc;
621 void dll_target::logic_attributes(struct ivl_net_logic_s *obj,
622 const NetNode*net)
624 obj->nattr = net->attr_cnt();
625 obj->attr = fill_in_attributes(net);
628 void dll_target::make_logic_delays_(struct ivl_net_logic_s*obj,
629 const NetObj*net)
631 obj->delay[0] = 0;
632 obj->delay[1] = 0;
633 obj->delay[2] = 0;
635 /* Translate delay expressions to ivl_target form. Try to
636 preserve pointer equality, not as a rule but to save on
637 expression trees. */
638 if (net->rise_time()) {
639 expr_ = 0;
640 net->rise_time()->expr_scan(this);
641 obj->delay[0] = expr_;
642 expr_ = 0;
644 if (net->fall_time()) {
645 if (net->fall_time() == net->rise_time()) {
646 obj->delay[1] = obj->delay[0];
647 } else {
648 expr_ = 0;
649 net->fall_time()->expr_scan(this);
650 obj->delay[1] = expr_;
651 expr_ = 0;
654 if (net->decay_time()) {
655 if (net->decay_time() == net->rise_time()) {
656 obj->delay[2] = obj->delay[0];
657 } else {
658 expr_ = 0;
659 net->decay_time()->expr_scan(this);
660 obj->delay[2] = expr_;
661 expr_ = 0;
667 * Add a bufz object to the scope that contains it.
669 * Note that in the ivl_target API a BUFZ device is a special kind of
670 * ivl_net_logic_t device, so create an ivl_net_logic_t cookie to
671 * handle it.
673 bool dll_target::bufz(const NetBUFZ*net)
675 struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
677 assert(net->pin_count() == 2);
679 obj->type_ = IVL_LO_BUFZ;
680 obj->width_= net->width();
681 obj->npins_= 2;
682 obj->pins_ = new ivl_nexus_t[2];
684 /* Get the ivl_nexus_t objects connected to the two pins.
686 (We know a priori that the ivl_nexus_t objects have been
687 allocated, because the signals have been scanned before
688 me. This saves me the trouble of allocating them.) */
690 assert(net->pin(0).nexus()->t_cookie());
691 obj->pins_[0] = net->pin(0).nexus()->t_cookie();
692 ivl_nexus_ptr_t out_ptr = nexus_log_add(obj->pins_[0], obj, 0);
695 switch (net->pin(0).drive0()) {
696 case Link::HIGHZ:
697 out_ptr->drive0 = IVL_DR_HiZ;
698 break;
699 case Link::WEAK:
700 out_ptr->drive0 = IVL_DR_WEAK;
701 break;
702 case Link::PULL:
703 out_ptr->drive0 = IVL_DR_PULL;
704 break;
705 case Link::STRONG:
706 out_ptr->drive0 = IVL_DR_STRONG;
707 break;
708 case Link::SUPPLY:
709 out_ptr->drive0 = IVL_DR_SUPPLY;
710 break;
713 switch (net->pin(0).drive1()) {
714 case Link::HIGHZ:
715 out_ptr->drive1 = IVL_DR_HiZ;
716 break;
717 case Link::WEAK:
718 out_ptr->drive1 = IVL_DR_WEAK;
719 break;
720 case Link::PULL:
721 out_ptr->drive1 = IVL_DR_PULL;
722 break;
723 case Link::STRONG:
724 out_ptr->drive1 = IVL_DR_STRONG;
725 break;
726 case Link::SUPPLY:
727 out_ptr->drive1 = IVL_DR_SUPPLY;
728 break;
731 assert(net->pin(1).nexus()->t_cookie());
732 obj->pins_[1] = net->pin(1).nexus()->t_cookie();
733 nexus_log_add(obj->pins_[1], obj, 1);
735 /* Attach the logic device to the scope that contains it. */
737 assert(net->scope());
738 ivl_scope_t scope = find_scope(des_, net->scope());
739 assert(scope);
741 obj->scope_ = scope;
743 obj->name_ = net->name();
744 logic_attributes(obj, net);
746 make_logic_delays_(obj, net);
748 scope_add_logic(scope, obj);
750 return true;
753 void dll_target::event(const NetEvent*net)
755 struct ivl_event_s *obj = new struct ivl_event_s;
757 ivl_scope_t scope = find_scope(des_, net->scope());
758 obj->name = net->name();
759 obj->scope = scope;
760 scope_add_event(scope, obj);
762 obj->nany = 0;
763 obj->nneg = 0;
764 obj->npos = 0;
766 if (net->nprobe() >= 1) {
768 for (unsigned idx = 0 ; idx < net->nprobe() ; idx += 1) {
769 const NetEvProbe*pr = net->probe(idx);
770 switch (pr->edge()) {
771 case NetEvProbe::ANYEDGE:
772 obj->nany += pr->pin_count();
773 break;
774 case NetEvProbe::NEGEDGE:
775 obj->nneg += pr->pin_count();
776 break;
777 case NetEvProbe::POSEDGE:
778 obj->npos += pr->pin_count();
779 break;
783 unsigned npins = obj->nany + obj->nneg + obj->npos;
784 obj->pins = (ivl_nexus_t*)calloc(npins, sizeof(ivl_nexus_t));
786 } else {
787 obj->pins = 0;
792 void dll_target::logic(const NetLogic*net)
794 struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
796 obj->width_ = net->width();
798 switch (net->type()) {
799 case NetLogic::AND:
800 obj->type_ = IVL_LO_AND;
801 break;
802 case NetLogic::BUF:
803 obj->type_ = IVL_LO_BUF;
804 break;
805 case NetLogic::BUFIF0:
806 obj->type_ = IVL_LO_BUFIF0;
807 break;
808 case NetLogic::BUFIF1:
809 obj->type_ = IVL_LO_BUFIF1;
810 break;
811 case NetLogic::CMOS:
812 obj->type_ = IVL_LO_CMOS;
813 break;
814 case NetLogic::NAND:
815 obj->type_ = IVL_LO_NAND;
816 break;
817 case NetLogic::NMOS:
818 obj->type_ = IVL_LO_NMOS;
819 break;
820 case NetLogic::NOR:
821 obj->type_ = IVL_LO_NOR;
822 break;
823 case NetLogic::NOT:
824 obj->type_ = IVL_LO_NOT;
825 break;
826 case NetLogic::NOTIF0:
827 obj->type_ = IVL_LO_NOTIF0;
828 break;
829 case NetLogic::NOTIF1:
830 obj->type_ = IVL_LO_NOTIF1;
831 break;
832 case NetLogic::OR:
833 obj->type_ = IVL_LO_OR;
834 break;
835 case NetLogic::PULLDOWN:
836 obj->type_ = IVL_LO_PULLDOWN;
837 break;
838 case NetLogic::PULLUP:
839 obj->type_ = IVL_LO_PULLUP;
840 break;
841 case NetLogic::RCMOS:
842 obj->type_ = IVL_LO_RCMOS;
843 break;
844 case NetLogic::RNMOS:
845 obj->type_ = IVL_LO_RNMOS;
846 break;
847 case NetLogic::RPMOS:
848 obj->type_ = IVL_LO_RPMOS;
849 break;
850 case NetLogic::PMOS:
851 obj->type_ = IVL_LO_PMOS;
852 break;
853 case NetLogic::XNOR:
854 obj->type_ = IVL_LO_XNOR;
855 break;
856 case NetLogic::XOR:
857 obj->type_ = IVL_LO_XOR;
858 break;
859 default:
860 assert(0);
861 obj->type_ = IVL_LO_NONE;
862 break;
865 /* Connect all the ivl_nexus_t objects to the pins of the
866 device. */
868 obj->npins_ = net->pin_count();
869 obj->pins_ = new ivl_nexus_t[obj->npins_];
871 ivl_nexus_ptr_t out_ptr = 0;
873 for (unsigned idx = 0 ; idx < obj->npins_ ; idx += 1) {
874 const Nexus*nex = net->pin(idx).nexus();
875 assert(nex->t_cookie());
876 obj->pins_[idx] = nex->t_cookie();
877 ivl_nexus_ptr_t tmp = nexus_log_add(obj->pins_[idx], obj, idx);
878 if (idx == 0)
879 out_ptr = tmp;
882 switch (net->pin(0).drive0()) {
883 case Link::HIGHZ:
884 out_ptr->drive0 = IVL_DR_HiZ;
885 break;
886 case Link::WEAK:
887 out_ptr->drive0 = IVL_DR_WEAK;
888 break;
889 case Link::PULL:
890 out_ptr->drive0 = IVL_DR_PULL;
891 break;
892 case Link::STRONG:
893 out_ptr->drive0 = IVL_DR_STRONG;
894 break;
895 case Link::SUPPLY:
896 out_ptr->drive0 = IVL_DR_SUPPLY;
897 break;
900 switch (net->pin(0).drive1()) {
901 case Link::HIGHZ:
902 out_ptr->drive1 = IVL_DR_HiZ;
903 break;
904 case Link::WEAK:
905 out_ptr->drive1 = IVL_DR_WEAK;
906 break;
907 case Link::PULL:
908 out_ptr->drive1 = IVL_DR_PULL;
909 break;
910 case Link::STRONG:
911 out_ptr->drive1 = IVL_DR_STRONG;
912 break;
913 case Link::SUPPLY:
914 out_ptr->drive1 = IVL_DR_SUPPLY;
915 break;
918 assert(net->scope());
919 ivl_scope_t scope = find_scope(des_, net->scope());
920 assert(scope);
922 obj->scope_= scope;
923 obj->name_ = net->name();
925 logic_attributes(obj, net);
927 make_logic_delays_(obj, net);
929 scope_add_logic(scope, obj);
932 bool dll_target::sign_extend(const NetSignExtend*net)
934 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
935 obj->type = IVL_LPM_SIGN_EXT;
936 obj->width = net->width();
937 obj->name = net->name();
938 obj->scope = find_scope(des_, net->scope());
939 assert(obj->scope);
941 const Nexus*nex;
943 nex = net->pin(0).nexus();
944 assert(nex->t_cookie());
946 obj->u_.reduce.q = nex->t_cookie();
947 nexus_lpm_add(obj->u_.reduce.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
949 nex = net->pin(1).nexus();
950 assert(nex->t_cookie());
952 obj->u_.reduce.a = nex->t_cookie();
953 nexus_lpm_add(obj->u_.reduce.a, obj, 1, IVL_DR_HiZ, IVL_DR_HiZ);
955 scope_add_lpm(obj->scope, obj);
957 return true;
960 bool dll_target::ureduce(const NetUReduce*net)
962 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
963 switch (net->type()) {
964 case NetUReduce::NONE:
965 assert(0);
966 return false;
967 case NetUReduce::AND:
968 obj->type = IVL_LPM_RE_AND;
969 break;
970 case NetUReduce::OR:
971 obj->type = IVL_LPM_RE_OR;
972 break;
973 case NetUReduce::XOR:
974 obj->type = IVL_LPM_RE_XOR;
975 break;
976 case NetUReduce::NAND:
977 obj->type = IVL_LPM_RE_NAND;
978 break;
979 case NetUReduce::NOR:
980 obj->type = IVL_LPM_RE_NOR;
981 break;
982 case NetUReduce::XNOR:
983 obj->type = IVL_LPM_RE_XNOR;
984 break;
987 obj->name = net->name();
988 obj->scope = find_scope(des_, net->scope());
989 assert(obj->scope);
991 obj->width = net->width();
993 const Nexus*nex;
995 nex = net->pin(0).nexus();
996 assert(nex->t_cookie());
998 obj->u_.reduce.q = nex->t_cookie();
999 nexus_lpm_add(obj->u_.reduce.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1001 nex = net->pin(1).nexus();
1002 assert(nex->t_cookie());
1004 obj->u_.reduce.a = nex->t_cookie();
1005 nexus_lpm_add(obj->u_.reduce.a, obj, 1, IVL_DR_HiZ, IVL_DR_HiZ);
1007 scope_add_lpm(obj->scope, obj);
1009 return true;
1012 void dll_target::net_case_cmp(const NetCaseCmp*net)
1014 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1015 obj->type = net->eeq()? IVL_LPM_CMP_EEQ : IVL_LPM_CMP_NEE;
1016 obj->name = net->name();
1017 obj->scope = find_scope(des_, net->scope());
1018 assert(obj->scope);
1020 obj->width = net->width();
1021 obj->u_.arith.signed_flag = 0;
1023 const Nexus*nex;
1025 nex = net->pin(1).nexus();
1026 assert(nex->t_cookie());
1028 obj->u_.arith.a = nex->t_cookie();
1029 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1031 nex = net->pin(2).nexus();
1032 assert(nex->t_cookie());
1034 obj->u_.arith.b = nex->t_cookie();
1035 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1037 nex = net->pin(0).nexus();
1038 assert(nex->t_cookie());
1040 obj->u_.arith.q = nex->t_cookie();
1041 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1043 scope_add_lpm(obj->scope, obj);
1046 bool dll_target::net_sysfunction(const NetSysFunc*net)
1048 unsigned idx;
1049 const Nexus*nex;
1051 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1052 obj->type = IVL_LPM_SFUNC;
1053 obj->name = net->name();
1054 obj->scope = find_scope(des_, net->scope());
1055 assert(obj->scope);
1057 obj->u_.sfunc.ports = net->pin_count();
1059 assert(net->pin_count() >= 1);
1060 obj->width = net->vector_width();
1062 obj->u_.sfunc.fun_name = net->func_name();
1064 obj->u_.sfunc.pins = new ivl_nexus_t[net->pin_count()];
1066 nex = net->pin(0).nexus();
1067 assert(nex->t_cookie());
1069 obj->u_.sfunc.pins[0] = nex->t_cookie();
1070 nexus_lpm_add(obj->u_.sfunc.pins[0], obj, 0,
1071 IVL_DR_STRONG, IVL_DR_STRONG);
1073 for (idx = 1 ; idx < net->pin_count() ; idx += 1) {
1074 nex = net->pin(idx).nexus();
1075 assert(nex->t_cookie());
1077 obj->u_.sfunc.pins[idx] = nex->t_cookie();
1078 nexus_lpm_add(obj->u_.sfunc.pins[idx], obj, 0,
1079 IVL_DR_HiZ, IVL_DR_HiZ);
1082 scope_add_lpm(obj->scope, obj);
1083 return true;
1087 * An IVL_LPM_UFUNC represents a node in a combinational expression
1088 * that calls a user defined function. I create an LPM object that has
1089 * the right connections, and refers to the ivl_scope_t of the
1090 * definition.
1092 bool dll_target::net_function(const NetUserFunc*net)
1094 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1095 obj->type = IVL_LPM_UFUNC;
1096 obj->name = net->name();
1097 obj->scope = find_scope(des_, net->scope());
1098 assert(obj->scope);
1100 /* Get the definition of the function and save it. */
1101 const NetScope*def = net->def();
1102 assert(def);
1104 obj->u_.ufunc.def = lookup_scope_(def);
1106 /* Save information about the ports in the ivl_lpm_s
1107 structure. Note that port 0 is the return value. */
1108 obj->u_.ufunc.ports = net->pin_count();
1110 assert(net->pin_count() >= 1);
1111 obj->width = net->port_width(0);
1113 /* Now collect all the pins and connect them to the nexa of
1114 the net. The output pins have strong drive, and the
1115 remaining input pins are HiZ. */
1117 obj->u_.ufunc.pins = new ivl_nexus_t[net->pin_count()];
1119 for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
1120 const Nexus*nex = net->pin(idx).nexus();
1121 assert(nex->t_cookie());
1122 ivl_nexus_t nn = nex->t_cookie();
1123 assert(nn);
1125 obj->u_.ufunc.pins[idx] = nn;
1126 ivl_drive_t drive = idx == 0 ? IVL_DR_STRONG : IVL_DR_HiZ;
1127 nexus_lpm_add(obj->u_.ufunc.pins[idx], obj, idx, drive, drive);
1130 /* All done. Add this LPM to the scope. */
1131 scope_add_lpm(obj->scope, obj);
1133 return true;
1136 void dll_target::udp(const NetUDP*net)
1138 struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
1140 obj->type_ = IVL_LO_UDP;
1142 /* The NetUDP class hasn't learned about width yet, so we
1143 assume a width of 1. */
1144 obj->width_ = 1;
1146 static map<perm_string,ivl_udp_t> udps;
1147 ivl_udp_t u;
1149 if (udps.find(net->udp_name()) != udps.end())
1151 u = udps[net->udp_name()];
1153 else
1155 u = new struct ivl_udp_s;
1156 u->nrows = net->rows();
1157 u->table = (ivl_udp_s::ccharp_t*)malloc((u->nrows+1)*sizeof(char*));
1158 assert(u->table);
1159 u->table[u->nrows] = 0x0;
1160 u->nin = net->nin();
1161 u->sequ = net->is_sequential();
1162 if (u->sequ)
1163 u->init = net->get_initial();
1164 u->name = net->udp_name();
1165 string inp;
1166 char out;
1167 unsigned int i = 0;
1168 if (net->first(inp, out))
1171 string tt = inp+out;
1172 u->table[i++] = strings_.add(tt.c_str());
1173 } while (net->next(inp, out));
1174 assert(i==u->nrows);
1176 udps[net->udp_name()] = u;
1179 obj->udp = u;
1181 // Some duplication of code here, see: dll_target::logic()
1183 /* Connect all the ivl_nexus_t objects to the pins of the
1184 device. */
1186 obj->npins_ = net->pin_count();
1187 obj->pins_ = new ivl_nexus_t[obj->npins_];
1188 for (unsigned idx = 0 ; idx < obj->npins_ ; idx += 1) {
1189 const Nexus*nex = net->pin(idx).nexus();
1191 /* Skip unconnected input pins. These will take on HiZ
1192 values by the code generators. */
1193 if (nex->t_cookie() == 0) {
1194 obj->pins_[idx] = 0;
1195 continue;
1198 assert(nex->t_cookie());
1199 obj->pins_[idx] = nex->t_cookie();
1200 nexus_log_add(obj->pins_[idx], obj, idx);
1203 assert(net->scope());
1204 ivl_scope_t scope = find_scope(des_, net->scope());
1205 assert(scope);
1207 obj->scope_= scope;
1208 obj->name_ = net->name();
1210 make_logic_delays_(obj, net);
1212 obj->nattr = 0;
1213 obj->attr = 0;
1215 scope_add_logic(scope, obj);
1218 void dll_target::lpm_add_sub(const NetAddSub*net)
1220 ivl_lpm_t obj = new struct ivl_lpm_s;
1221 if (net->attribute(perm_string::literal("LPM_Direction")) == verinum("SUB"))
1222 obj->type = IVL_LPM_SUB;
1223 else
1224 obj->type = IVL_LPM_ADD;
1225 obj->name = net->name(); // NetAddSub names are permallocated.
1226 assert(net->scope());
1227 obj->scope = find_scope(des_, net->scope());
1228 assert(obj->scope);
1230 obj->u_.arith.signed_flag = 0;
1232 /* Choose the width of the adder. If the carry bit is
1233 connected, then widen the adder by one and plan on leaving
1234 the fake inputs unconnected. */
1235 obj->width = net->width();
1236 if (net->pin_Cout().is_linked()) {
1237 obj->width += 1;
1241 const Nexus*nex;
1243 nex = net->pin_Result().nexus();
1244 assert(nex->t_cookie());
1246 obj->u_.arith.q = nex->t_cookie();
1247 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1249 nex = net->pin_DataA().nexus();
1250 assert(nex->t_cookie());
1252 obj->u_.arith.a = nex->t_cookie();
1253 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1255 nex = net->pin_DataB().nexus();
1256 assert(nex->t_cookie());
1258 obj->u_.arith.b = nex->t_cookie();
1259 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1261 /* If the carry output is connected, then connect the extra Q
1262 pin to the carry nexus and zero the a and b inputs. */
1263 if (net->pin_Cout().is_linked()) {
1264 cerr << "XXXX: t-dll.cc: Forgot how to connect cout." << endl;
1267 scope_add_lpm(obj->scope, obj);
1270 bool dll_target::lpm_array_dq(const NetArrayDq*net)
1272 ivl_lpm_t obj = new struct ivl_lpm_s;
1273 obj->type = IVL_LPM_ARRAY;
1274 obj->name = net->name();
1275 obj->u_.array.sig = find_signal(des_, net->mem());
1276 assert(obj->u_.array.sig);
1277 obj->scope = find_scope(des_, net->scope());
1278 assert(obj->scope);
1279 obj->width = net->width();
1280 obj->u_.array.swid = net->awidth();
1282 scope_add_lpm(obj->scope, obj);
1284 const Nexus*nex;
1286 nex = net->pin_Address().nexus();
1287 assert(nex->t_cookie());
1288 obj->u_.array.a = nex->t_cookie();
1289 nexus_lpm_add(obj->u_.array.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1291 nex = net->pin_Result().nexus();
1292 assert(nex->t_cookie());
1293 obj->u_.array.q = nex->t_cookie();
1294 nexus_lpm_add(obj->u_.array.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1296 return true;
1300 * The lpm_clshift device represents both left and right shifts,
1301 * depending on what is connected to the Direction pin. We convert
1302 * this device into SHIFTL or SHIFTR devices.
1304 void dll_target::lpm_clshift(const NetCLShift*net)
1306 ivl_lpm_t obj = new struct ivl_lpm_s;
1307 obj->type = IVL_LPM_SHIFTL;
1308 obj->name = net->name();
1309 assert(net->scope());
1310 obj->scope = find_scope(des_, net->scope());
1311 assert(obj->scope);
1313 /* Look at the direction input of the device, and select the
1314 shift direction accordingly. */
1315 if (net->right_flag())
1316 obj->type = IVL_LPM_SHIFTR;
1317 if (net->signed_flag())
1318 obj->u_.shift.signed_flag = 1;
1319 else
1320 obj->u_.shift.signed_flag = 0;
1322 obj->width = net->width();
1323 obj->u_.shift.select = net->width_dist();
1325 const Nexus*nex;
1327 nex = net->pin_Result().nexus();
1328 assert(nex->t_cookie());
1330 obj->u_.shift.q = nex->t_cookie();
1331 nexus_lpm_add(obj->u_.shift.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1333 nex = net->pin_Data().nexus();
1334 assert(nex->t_cookie());
1336 obj->u_.shift.d = nex->t_cookie();
1337 nexus_lpm_add(obj->u_.shift.d, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1339 nex = net->pin_Distance().nexus();
1340 assert(nex->t_cookie());
1342 obj->u_.shift.s = nex->t_cookie();
1343 nexus_lpm_add(obj->u_.shift.s, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1345 scope_add_lpm(obj->scope, obj);
1349 * Make out of the NetCompare object an ivl_lpm_s object. The
1350 * comparators in ivl_target do not support < or <=, but they can be
1351 * trivially converted to > and >= by swapping the operands.
1353 void dll_target::lpm_compare(const NetCompare*net)
1355 ivl_lpm_t obj = new struct ivl_lpm_s;
1356 obj->name = net->name(); // NetCompare names are permallocated
1357 assert(net->scope());
1358 obj->scope = find_scope(des_, net->scope());
1359 assert(obj->scope);
1361 bool swap_operands = false;
1363 obj->width = net->width();
1364 obj->u_.arith.signed_flag = net->get_signed()? 1 : 0;
1366 const Nexus*nex;
1368 nex = net->pin_DataA().nexus();
1369 assert(nex->t_cookie());
1371 obj->u_.arith.a = nex->t_cookie();
1373 nex = net->pin_DataB().nexus();
1374 assert(nex->t_cookie());
1376 obj->u_.arith.b = nex->t_cookie();
1379 if (net->pin_AGEB().is_linked()) {
1380 nex = net->pin_AGEB().nexus();
1381 obj->type = IVL_LPM_CMP_GE;
1383 assert(nex->t_cookie());
1384 obj->u_.arith.q = nex->t_cookie();
1385 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1386 IVL_DR_STRONG, IVL_DR_STRONG);
1388 } else if (net->pin_AGB().is_linked()) {
1389 nex = net->pin_AGB().nexus();
1390 obj->type = IVL_LPM_CMP_GT;
1392 assert(nex->t_cookie());
1393 obj->u_.arith.q = nex->t_cookie();
1394 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1395 IVL_DR_STRONG, IVL_DR_STRONG);
1397 } else if (net->pin_ALEB().is_linked()) {
1398 nex = net->pin_ALEB().nexus();
1399 obj->type = IVL_LPM_CMP_GE;
1401 assert(nex->t_cookie());
1402 obj->u_.arith.q = nex->t_cookie();
1403 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1404 IVL_DR_STRONG, IVL_DR_STRONG);
1406 swap_operands = true;
1408 } else if (net->pin_ALB().is_linked()) {
1409 nex = net->pin_ALB().nexus();
1410 obj->type = IVL_LPM_CMP_GT;
1412 assert(nex->t_cookie());
1413 obj->u_.arith.q = nex->t_cookie();
1414 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1415 IVL_DR_STRONG, IVL_DR_STRONG);
1417 swap_operands = true;
1419 } else if (net->pin_AEB().is_linked()) {
1420 nex = net->pin_AEB().nexus();
1421 obj->type = IVL_LPM_CMP_EQ;
1423 assert(nex->t_cookie());
1424 obj->u_.arith.q = nex->t_cookie();
1425 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1426 IVL_DR_STRONG, IVL_DR_STRONG);
1428 } else if (net->pin_ANEB().is_linked()) {
1429 nex = net->pin_ANEB().nexus();
1430 obj->type = IVL_LPM_CMP_NE;
1432 assert(nex->t_cookie());
1433 obj->u_.arith.q = nex->t_cookie();
1434 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1435 IVL_DR_STRONG, IVL_DR_STRONG);
1437 } else {
1438 assert(0);
1441 if (swap_operands) {
1442 ivl_nexus_t tmp = obj->u_.arith.a;
1443 obj->u_.arith.a = obj->u_.arith.b;
1444 obj->u_.arith.b = tmp;
1447 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1448 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1450 scope_add_lpm(obj->scope, obj);
1453 void dll_target::lpm_divide(const NetDivide*net)
1455 ivl_lpm_t obj = new struct ivl_lpm_s;
1456 obj->type = IVL_LPM_DIVIDE;
1457 obj->name = net->name();
1458 assert(net->scope());
1459 obj->scope = find_scope(des_, net->scope());
1460 assert(obj->scope);
1462 unsigned wid = net->width_r();
1464 obj->width = wid;
1465 obj->u_.arith.signed_flag = net->get_signed()? 1 : 0;
1467 const Nexus*nex;
1469 nex = net->pin_Result().nexus();
1470 assert(nex->t_cookie());
1472 obj->u_.arith.q = nex->t_cookie();
1473 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1475 nex = net->pin_DataA().nexus();
1476 assert(nex->t_cookie());
1478 obj->u_.arith.a = nex->t_cookie();
1479 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1481 nex = net->pin_DataB().nexus();
1482 assert(nex->t_cookie());
1484 obj->u_.arith.b = nex->t_cookie();
1485 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1488 scope_add_lpm(obj->scope, obj);
1491 void dll_target::lpm_modulo(const NetModulo*net)
1493 ivl_lpm_t obj = new struct ivl_lpm_s;
1494 obj->type = IVL_LPM_MOD;
1495 obj->name = net->name();
1496 assert(net->scope());
1497 obj->scope = find_scope(des_, net->scope());
1498 assert(obj->scope);
1500 unsigned wid = net->width_r();
1502 obj->width = wid;
1503 obj->u_.arith.signed_flag = 0;
1505 const Nexus*nex;
1507 nex = net->pin_Result().nexus();
1508 assert(nex->t_cookie());
1510 obj->u_.arith.q = nex->t_cookie();
1511 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1513 nex = net->pin_DataA().nexus();
1514 assert(nex->t_cookie());
1516 obj->u_.arith.a = nex->t_cookie();
1517 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1519 nex = net->pin_DataB().nexus();
1520 assert(nex->t_cookie());
1522 obj->u_.arith.b = nex->t_cookie();
1523 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1525 scope_add_lpm(obj->scope, obj);
1528 void dll_target::lpm_ff(const NetFF*net)
1530 ivl_lpm_t obj = new struct ivl_lpm_s;
1531 obj->type = IVL_LPM_FF;
1532 obj->name = net->name();
1533 obj->scope = find_scope(des_, net->scope());
1534 assert(obj->scope);
1536 obj->width = net->width();
1538 scope_add_lpm(obj->scope, obj);
1540 const Nexus*nex;
1542 /* Set the clk signal to point to the nexus, and the nexus to
1543 point back to this device. */
1544 nex = net->pin_Clock().nexus();
1545 assert(nex->t_cookie());
1546 obj->u_.ff.clk = nex->t_cookie();
1547 assert(obj->u_.ff.clk);
1548 nexus_lpm_add(obj->u_.ff.clk, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1550 /* If there is a clock enable, then connect it up to the FF
1551 device. */
1552 if (net->pin_Enable().is_linked()) {
1553 nex = net->pin_Enable().nexus();
1554 assert(nex->t_cookie());
1555 obj->u_.ff.we = nex->t_cookie();
1556 assert(obj->u_.ff.we);
1557 nexus_lpm_add(obj->u_.ff.we, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1558 } else {
1559 obj->u_.ff.we = 0;
1562 if (net->pin_Aclr().is_linked()) {
1563 nex = net->pin_Aclr().nexus();
1564 assert(nex->t_cookie());
1565 obj->u_.ff.aclr = nex->t_cookie();
1566 assert(obj->u_.ff.aclr);
1567 nexus_lpm_add(obj->u_.ff.aclr, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1568 } else {
1569 obj->u_.ff.aclr = 0;
1572 if (net->pin_Aset().is_linked()) {
1573 nex = net->pin_Aset().nexus();
1574 assert(nex->t_cookie());
1575 obj->u_.ff.aset = nex->t_cookie();
1576 assert(obj->u_.ff.aset);
1577 nexus_lpm_add(obj->u_.ff.aset, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1579 verinum tmp = net->aset_value();
1580 obj->u_.ff.aset_value = expr_from_value_(tmp);
1582 } else {
1583 obj->u_.ff.aset = 0;
1584 obj->u_.ff.aset_value = 0;
1587 if (net->pin_Sclr().is_linked()) {
1588 nex = net->pin_Sclr().nexus();
1589 assert(nex->t_cookie());
1590 obj->u_.ff.sclr = nex->t_cookie();
1591 assert(obj->u_.ff.sclr);
1592 nexus_lpm_add(obj->u_.ff.sclr, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1593 } else {
1594 obj->u_.ff.sclr = 0;
1597 if (net->pin_Sset().is_linked()) {
1598 nex = net->pin_Sset().nexus();
1599 assert(nex->t_cookie());
1600 obj->u_.ff.sset = nex->t_cookie();
1601 assert(obj->u_.ff.sset);
1602 nexus_lpm_add(obj->u_.ff.sset, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1604 verinum tmp = net->sset_value();
1605 obj->u_.ff.sset_value = expr_from_value_(tmp);
1607 } else {
1608 obj->u_.ff.sset = 0;
1609 obj->u_.ff.sset_value = 0;
1612 nex = net->pin_Q().nexus();
1613 assert(nex->t_cookie());
1614 obj->u_.ff.q.pin = nex->t_cookie();
1615 nexus_lpm_add(obj->u_.ff.q.pin, obj, 0,
1616 IVL_DR_STRONG, IVL_DR_STRONG);
1618 nex = net->pin_Data().nexus();
1619 assert(nex->t_cookie());
1620 obj->u_.ff.d.pin = nex->t_cookie();
1621 nexus_lpm_add(obj->u_.ff.d.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1626 * Make the NetMult object into an IVL_LPM_MULT node.
1628 void dll_target::lpm_mult(const NetMult*net)
1630 ivl_lpm_t obj = new struct ivl_lpm_s;
1631 obj->type = IVL_LPM_MULT;
1632 obj->name = net->name();
1633 assert(net->scope());
1634 obj->scope = find_scope(des_, net->scope());
1635 assert(obj->scope);
1637 unsigned wid = net->width_r();
1639 obj->width = wid;
1641 const Nexus*nex;
1643 nex = net->pin_Result().nexus();
1644 assert(nex->t_cookie());
1646 obj->u_.arith.q = nex->t_cookie();
1647 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1649 nex = net->pin_DataA().nexus();
1650 assert(nex->t_cookie());
1652 obj->u_.arith.a = nex->t_cookie();
1653 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1655 nex = net->pin_DataB().nexus();
1656 assert(nex->t_cookie());
1658 obj->u_.arith.b = nex->t_cookie();
1659 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1662 scope_add_lpm(obj->scope, obj);
1666 * Hook up the mux devices so that the select expression selects the
1667 * correct sub-expression with the ivl_lpm_data2 function.
1669 void dll_target::lpm_mux(const NetMux*net)
1671 ivl_lpm_t obj = new struct ivl_lpm_s;
1672 obj->type = IVL_LPM_MUX;
1673 obj->name = net->name(); // The NetMux perallocates its name.
1674 obj->scope = find_scope(des_, net->scope());
1675 assert(obj->scope);
1677 obj->width = net->width();
1678 obj->u_.mux.size = net->size();
1679 obj->u_.mux.swid = net->sel_width();
1681 scope_add_lpm(obj->scope, obj);
1683 const Nexus*nex;
1685 /* Connect the output bits. */
1686 nex = net->pin_Result().nexus();
1687 assert(nex->t_cookie());
1688 obj->u_.mux.q = nex->t_cookie();
1689 nexus_lpm_add(obj->u_.mux.q, obj, 0,
1690 IVL_DR_STRONG, IVL_DR_STRONG);
1692 /* Connect the select bits. */
1693 nex = net->pin_Sel().nexus();
1694 assert(nex->t_cookie());
1695 obj->u_.mux.s = nex->t_cookie();
1696 nexus_lpm_add(obj->u_.mux.s, obj, 0,
1697 IVL_DR_HiZ, IVL_DR_HiZ);
1699 unsigned selects = obj->u_.mux.size;
1701 obj->u_.mux.d = new ivl_nexus_t [selects];
1703 for (unsigned sdx = 0 ; sdx < selects ; sdx += 1) {
1704 nex = net->pin_Data(sdx).nexus();
1705 ivl_nexus_t tmp = nex->t_cookie();
1706 obj->u_.mux.d[sdx] = tmp;
1707 nexus_lpm_add(tmp, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1712 bool dll_target::concat(const NetConcat*net)
1714 ivl_lpm_t obj = new struct ivl_lpm_s;
1715 obj->type = IVL_LPM_CONCAT;
1716 obj->name = net->name(); // NetConcat names are permallocated
1717 assert(net->scope());
1718 obj->scope = find_scope(des_, net->scope());
1719 assert(obj->scope);
1721 obj->width = net->width();
1723 obj->u_.concat.inputs = net->pin_count() - 1;
1724 obj->u_.concat.pins = new ivl_nexus_t[obj->u_.concat.inputs+1];
1726 for (unsigned idx = 0 ; idx < obj->u_.concat.inputs+1 ; idx += 1) {
1727 ivl_drive_t dr = idx == 0? IVL_DR_STRONG : IVL_DR_HiZ;
1728 const Nexus*nex = net->pin(idx).nexus();
1729 assert(nex->t_cookie());
1731 obj->u_.concat.pins[idx] = nex->t_cookie();
1732 nexus_lpm_add(obj->u_.concat.pins[idx], obj, 0, dr, dr);
1735 scope_add_lpm(obj->scope, obj);
1737 return true;
1740 bool dll_target::part_select(const NetPartSelect*net)
1742 ivl_lpm_t obj = new struct ivl_lpm_s;
1743 switch (net->dir()) {
1744 case NetPartSelect::VP:
1745 obj->type = IVL_LPM_PART_VP;
1746 break;
1747 case NetPartSelect::PV:
1748 obj->type = IVL_LPM_PART_PV;
1749 break;
1750 case NetPartSelect::BI:
1751 obj->type = IVL_LPM_PART_BI;
1752 break;
1754 obj->name = net->name(); // NetPartSelect names are permallocated.
1755 assert(net->scope());
1756 obj->scope = find_scope(des_, net->scope());
1757 assert(obj->scope);
1759 /* Part selects are always unsigned. */
1760 obj->u_.part.signed_flag = 0;
1762 /* Choose the width of the part select. */
1763 obj->width = net->width();
1764 obj->u_.part.base = net->base();
1765 obj->u_.part.s = 0;
1767 const Nexus*nex;
1769 switch (obj->type) {
1770 case IVL_LPM_PART_VP:
1771 /* NetPartSelect:pin(0) is the output pin. */
1772 nex = net->pin(0).nexus();
1773 assert(nex->t_cookie());
1775 obj->u_.part.q = nex->t_cookie();
1777 /* NetPartSelect:pin(1) is the input pin. */
1778 nex = net->pin(1).nexus();
1779 assert(nex->t_cookie());
1781 obj->u_.part.a = nex->t_cookie();
1783 /* If the part select has an additional pin, that pin is
1784 a variable select base. */
1785 if (net->pin_count() >= 3) {
1786 nex = net->pin(2).nexus();
1787 assert(nex->t_cookie());
1788 obj->u_.part.s = nex->t_cookie();
1790 break;
1792 case IVL_LPM_PART_PV:
1793 /* NetPartSelect:pin(1) is the output pin. */
1794 nex = net->pin(1).nexus();
1795 assert(nex->t_cookie());
1797 obj->u_.part.q = nex->t_cookie();
1799 /* NetPartSelect:pin(0) is the input pin. */
1800 nex = net->pin(0).nexus();
1801 assert(nex->t_cookie());
1803 obj->u_.part.a = nex->t_cookie();
1804 break;
1806 case IVL_LPM_PART_BI:
1807 /* For now, handle this exactly the same as a PV */
1809 /* NetPartSelect:pin(0) is the output pin. */
1810 nex = net->pin(0).nexus();
1811 assert(nex->t_cookie());
1813 obj->u_.part.q = nex->t_cookie();
1815 /* NetPartSelect:pin(1) is the input pin. */
1816 nex = net->pin(1).nexus();
1817 assert(nex->t_cookie());
1819 obj->u_.part.a = nex->t_cookie();
1820 break;
1822 default:
1823 assert(0);
1826 nexus_lpm_add(obj->u_.part.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1828 /* If the device is a PART_BI, then the "input" is also a
1829 strength aware output, so attach it to the nexus with
1830 strong driver. */
1831 if (obj->type == IVL_LPM_PART_BI)
1832 nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1833 else
1834 nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1836 /* The select input is optional. */
1837 if (obj->u_.part.s)
1838 nexus_lpm_add(obj->u_.part.s, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1840 scope_add_lpm(obj->scope, obj);
1842 return true;
1845 bool dll_target::replicate(const NetReplicate*net)
1847 ivl_lpm_t obj = new struct ivl_lpm_s;
1848 obj->type = IVL_LPM_REPEAT;
1849 obj->name = net->name();
1850 assert(net->scope());
1851 obj->scope = find_scope(des_, net->scope());
1852 assert(obj->scope);
1854 obj->width = net->width();
1855 obj->u_.repeat.count = net->repeat();
1857 ivl_drive_t dr = IVL_DR_STRONG;
1858 const Nexus*nex = net->pin(0).nexus();
1859 assert(nex->t_cookie());
1861 obj->u_.repeat.q = nex->t_cookie();
1862 nexus_lpm_add(obj->u_.repeat.q, obj, 0, dr, dr);
1864 dr = IVL_DR_HiZ;
1865 nex = net->pin(1).nexus();
1866 assert(nex->t_cookie());
1868 obj->u_.repeat.a = nex->t_cookie();
1869 nexus_lpm_add(obj->u_.repeat.a, obj, 0, dr, dr);
1871 scope_add_lpm(obj->scope, obj);
1873 return true;
1877 * The assignment l-values are captured by the assignment statements
1878 * themselves in the process handling.
1880 void dll_target::net_assign(const NetAssign_*)
1884 bool dll_target::net_const(const NetConst*net)
1886 unsigned idx;
1887 char*bits;
1889 struct ivl_net_const_s *obj = new struct ivl_net_const_s;
1891 obj->type = IVL_VT_LOGIC;
1893 /* constants have a single vector output. */
1894 assert(net->pin_count() == 1);
1896 obj->width_ = net->width();
1897 if (obj->width_ <= sizeof(obj->b.bit_)) {
1898 bits = obj->b.bit_;
1900 } else {
1901 obj->b.bits_ = (char*)malloc(obj->width_);
1902 bits = obj->b.bits_;
1905 for (idx = 0 ; idx < obj->width_ ; idx += 1)
1906 switch (net->value(idx)) {
1907 case verinum::V0:
1908 bits[idx] = '0';
1909 break;
1910 case verinum::V1:
1911 bits[idx] = '1';
1912 break;
1913 case verinum::Vx:
1914 bits[idx] = 'x';
1915 break;
1916 case verinum::Vz:
1917 bits[idx] = 'z';
1918 break;
1921 /* Connect to all the nexus objects. Note that the one-bit
1922 case can be handled more efficiently without allocating
1923 array space. */
1925 ivl_drive_t drv0, drv1;
1926 drive_from_link(net->pin(0), drv0, drv1);
1927 const Nexus*nex = net->pin(0).nexus();
1928 assert(nex->t_cookie());
1929 obj->pin_ = nex->t_cookie();
1930 nexus_con_add(obj->pin_, obj, 0, drv0, drv1);
1933 des_.nconsts += 1;
1934 des_.consts = (ivl_net_const_t*)
1935 realloc(des_.consts, des_.nconsts * sizeof(ivl_net_const_t));
1936 des_.consts[des_.nconsts-1] = obj;
1938 return true;
1941 bool dll_target::net_literal(const NetLiteral*net)
1944 struct ivl_net_const_s *obj = new struct ivl_net_const_s;
1946 obj->type = IVL_VT_REAL;
1947 obj->width_ = 1;
1948 obj->signed_ = 1;
1949 obj->b.real_value = net->value_real().as_double();
1951 /* Connect to all the nexus objects. Note that the one-bit
1952 case can be handled more efficiently without allocating
1953 array space. */
1955 ivl_drive_t drv0, drv1;
1956 drive_from_link(net->pin(0), drv0, drv1);
1957 const Nexus*nex = net->pin(0).nexus();
1958 assert(nex->t_cookie());
1959 obj->pin_ = nex->t_cookie();
1960 nexus_con_add(obj->pin_, obj, 0, drv0, drv1);
1962 des_.nconsts += 1;
1963 des_.consts = (ivl_net_const_t*)
1964 realloc(des_.consts, des_.nconsts * sizeof(ivl_net_const_t));
1965 des_.consts[des_.nconsts-1] = obj;
1967 return true;
1970 void dll_target::net_probe(const NetEvProbe*net)
1974 void dll_target::scope(const NetScope*net)
1976 ivl_scope_t scope;
1978 if (net->parent() == 0) {
1979 unsigned i;
1980 scope = NULL;
1981 for (i = 0; i < des_.nroots_ && scope == NULL; i++) {
1982 if (strcmp(des_.roots_[i]->name_, net->basename()) == 0)
1983 scope = des_.roots_[i];
1985 assert(scope);
1987 } else {
1988 perm_string sname = make_scope_name(net->fullname());
1989 scope = new struct ivl_scope_s;
1990 scope->name_ = sname;
1991 scope->child_ = 0;
1992 scope->sibling_ = 0;
1993 scope->parent = find_scope(des_, net->parent());
1994 assert(scope->parent);
1995 scope->nsigs_ = 0;
1996 scope->sigs_ = 0;
1997 scope->nlog_ = 0;
1998 scope->log_ = 0;
1999 scope->nevent_ = 0;
2000 scope->event_ = 0;
2001 scope->nlpm_ = 0;
2002 scope->lpm_ = 0;
2003 scope->def = 0;
2004 make_scope_parameters(scope, net);
2005 scope->time_precision = net->time_precision();
2006 scope->time_units = net->time_unit();
2007 scope->nattr = net->attr_cnt();
2008 scope->attr = fill_in_attributes(net);
2010 switch (net->type()) {
2011 case NetScope::MODULE:
2012 scope->type_ = IVL_SCT_MODULE;
2013 scope->tname_ = net->module_name();
2014 break;
2015 case NetScope::TASK: {
2016 const NetTaskDef*def = net->task_def();
2017 if (def == 0) {
2018 cerr << "?:?" << ": internal error: "
2019 << "task " << scope->name_
2020 << " has no definition." << endl;
2022 assert(def);
2023 scope->type_ = IVL_SCT_TASK;
2024 scope->tname_ = def->scope()->basename();
2025 break;
2027 case NetScope::FUNC:
2028 scope->type_ = IVL_SCT_FUNCTION;
2029 scope->tname_ = net->func_def()->scope()->basename();
2030 break;
2031 case NetScope::BEGIN_END:
2032 scope->type_ = IVL_SCT_BEGIN;
2033 scope->tname_ = scope->name_;
2034 break;
2035 case NetScope::FORK_JOIN:
2036 scope->type_ = IVL_SCT_FORK;
2037 scope->tname_ = scope->name_;
2038 break;
2039 case NetScope::GENBLOCK:
2040 scope->type_ = IVL_SCT_GENERATE;
2041 scope->tname_ = scope->name_;
2042 break;
2045 assert(scope->parent != 0);
2047 scope->sibling_= scope->parent->child_;
2048 scope->parent->child_ = scope;
2052 void dll_target::signal(const NetNet*net)
2054 ivl_signal_t obj = new struct ivl_signal_s;
2056 obj->name_ = net->name();
2058 /* Attach the signal to the ivl_scope_t object that contains
2059 it. This involves growing the sigs_ array in the scope
2060 object, or creating the sigs_ array if this is the first
2061 signal. */
2062 obj->scope_ = find_scope(des_, net->scope());
2063 assert(obj->scope_);
2065 if (obj->scope_->nsigs_ == 0) {
2066 assert(obj->scope_->sigs_ == 0);
2067 obj->scope_->nsigs_ = 1;
2068 obj->scope_->sigs_ = (ivl_signal_t*)malloc(sizeof(ivl_signal_t));
2070 } else {
2071 assert(obj->scope_->sigs_);
2072 obj->scope_->nsigs_ += 1;
2073 obj->scope_->sigs_ = (ivl_signal_t*)
2074 realloc(obj->scope_->sigs_,
2075 obj->scope_->nsigs_*sizeof(ivl_signal_t));
2078 obj->scope_->sigs_[obj->scope_->nsigs_-1] = obj;
2081 /* Save the primitive properties of the signal in the
2082 ivl_signal_t object. */
2084 obj->width_ = net->vector_width();
2085 obj->signed_= net->get_signed()? 1 : 0;
2086 obj->lsb_index = net->lsb();
2087 obj->lsb_dist = net->msb() >= net->lsb() ? 1 : -1;
2088 obj->isint_ = false;
2089 obj->local_ = (net->local_flag() && (net->peek_eref() == 0))? 1 : 0;
2091 obj->array_dimensions_ = net->array_dimensions();
2093 switch (net->port_type()) {
2095 case NetNet::PINPUT:
2096 obj->port_ = IVL_SIP_INPUT;
2097 break;
2099 case NetNet::POUTPUT:
2100 obj->port_ = IVL_SIP_OUTPUT;
2101 break;
2103 case NetNet::PINOUT:
2104 obj->port_ = IVL_SIP_INOUT;
2105 break;
2107 default:
2108 obj->port_ = IVL_SIP_NONE;
2109 break;
2112 switch (net->type()) {
2114 case NetNet::REG:
2115 obj->type_ = IVL_SIT_REG;
2116 obj->isint_ = net->get_isint();
2117 break;
2119 /* The SUPPLY0/1 net types are replaced with pulldown/up
2120 by elaborate. They should not make it here. */
2121 case NetNet::SUPPLY0:
2122 assert(0);
2123 break;
2124 case NetNet::SUPPLY1:
2125 assert(0);
2126 break;
2128 case NetNet::TRI:
2129 case NetNet::WIRE:
2130 case NetNet::IMPLICIT:
2131 obj->type_ = IVL_SIT_TRI;
2132 break;
2134 case NetNet::TRI0:
2135 obj->type_ = IVL_SIT_TRI0;
2136 break;
2138 case NetNet::TRI1:
2139 obj->type_ = IVL_SIT_TRI1;
2140 break;
2142 case NetNet::TRIAND:
2143 case NetNet::WAND:
2144 obj->type_ = IVL_SIT_TRIAND;
2145 break;
2147 case NetNet::TRIOR:
2148 case NetNet::WOR:
2149 obj->type_ = IVL_SIT_TRIOR;
2150 break;
2152 default:
2153 obj->type_ = IVL_SIT_NONE;
2154 break;
2157 /* Initialize the path fields to be filled in later. */
2158 obj->npath = 0;
2159 obj->path = 0;
2161 obj->data_type = net->data_type();
2162 obj->nattr = net->attr_cnt();
2163 obj->attr = fill_in_attributes(net);
2166 /* Get the nexus objects for all the pins of the signal. If
2167 the signal has only one pin, then write the single
2168 ivl_nexus_t object into n.pin_. Otherwise, make an array of
2169 ivl_nexus_t cookies.
2171 When I create an ivl_nexus_t object, store it in the
2172 t_cookie of the Nexus object so that I find it again when I
2173 next encounter the nexus. */
2175 obj->array_base = net->array_first();
2176 obj->array_words = net->array_count();
2177 if (obj->array_words > 1)
2178 obj->pins = new ivl_nexus_t[obj->array_words];
2180 for (unsigned idx = 0 ; idx < obj->array_words ; idx += 1) {
2182 const Nexus*nex = net->pin(idx).nexus();
2183 if (nex->t_cookie()) {
2184 if (obj->array_words > 1) {
2185 obj->pins[idx] = nex->t_cookie();
2186 nexus_sig_add(obj->pins[idx], obj, idx);
2187 } else {
2188 obj->pin = nex->t_cookie();
2189 nexus_sig_add(obj->pin, obj, idx);
2191 } else {
2192 ivl_nexus_t tmp = nexus_sig_make(obj, idx);
2193 tmp->nexus_ = nex;
2194 tmp->name_ = 0;
2195 nex->t_cookie(tmp);
2196 if (obj->array_words > 1)
2197 obj->pins[idx] = tmp;
2198 else
2199 obj->pin = tmp;
2204 bool dll_target::signal_paths(const NetNet*net)
2206 /* Nothing to do if there are no paths for this signal. */
2207 if (net->delay_paths() == 0)
2208 return true;
2210 ivl_signal_t obj = find_signal(des_, net);
2211 assert(obj);
2213 /* We cannot have already set up the paths for this signal. */
2214 assert(obj->npath == 0);
2215 assert(obj->path == 0);
2217 /* Figure out how many paths there really are. */
2218 for (unsigned idx = 0 ; idx < net->delay_paths() ; idx += 1) {
2219 const NetDelaySrc*src = net->delay_path(idx);
2220 obj->npath += src->src_count();
2223 obj->path = new struct ivl_delaypath_s[obj->npath];
2225 unsigned ptr = 0;
2226 for (unsigned idx = 0 ; idx < net->delay_paths() ; idx += 1) {
2227 const NetDelaySrc*src = net->delay_path(idx);
2229 /* If this path has a condition, then hook it up. */
2230 ivl_nexus_t path_condit = 0;
2231 if (src->is_condit()) {
2232 const Nexus*nt = src->condit_pin().nexus();
2233 path_condit = nt->t_cookie();
2236 for (unsigned pin = 0; pin < src->src_count(); pin += 1) {
2237 const Nexus*nex = src->src_pin(pin).nexus();
2238 if (! nex->t_cookie()) {
2239 cerr << src->get_line() << ": internal error: "
2240 << "No signal connected to pin " << pin
2241 << " of delay path to " << net->name()
2242 << "." << endl;
2244 assert(nex->t_cookie());
2245 obj->path[ptr].src = nex->t_cookie();
2246 obj->path[ptr].condit = path_condit;
2247 obj->path[ptr].posedge = src->is_posedge();
2248 obj->path[ptr].negedge = src->is_negedge();
2249 for (unsigned pe = 0 ; pe < 12 ; pe += 1) {
2250 obj->path[ptr].delay[pe] = src->get_delay(pe);
2253 ptr += 1;
2258 return true;
2261 extern const struct target tgt_dll = { "dll", &dll_target_obj };