Add file and line information for parameters, etc.
[sverilog.git] / t-dll.cc
blobfd7ba497efc3efbc3d3b16ce25027a31780b9021
1 /*
2 * Copyright (c) 2000-2008 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
20 # include "config.h"
22 # include <iostream>
24 # include <cstring>
25 # include <stdio.h> // sprintf()
26 # include "compiler.h"
27 # include "t-dll.h"
28 # include "netmisc.h"
29 #ifdef HAVE_MALLOC_H
30 # include <malloc.h>
31 #endif
32 # include <stdlib.h>
34 #if defined(__WIN32__)
36 inline ivl_dll_t ivl_dlopen(const char *name)
38 ivl_dll_t res = (ivl_dll_t) LoadLibrary(name);
39 return res;
43 inline void * ivl_dlsym(ivl_dll_t dll, const char *nm)
45 FARPROC sym;
46 return (void*)GetProcAddress((HMODULE)dll, nm);
49 inline void ivl_dlclose(ivl_dll_t dll)
51 FreeLibrary((HMODULE)dll);
54 const char *dlerror(void)
56 static char msg[256];
57 unsigned long err = GetLastError();
58 FormatMessage(
59 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
60 NULL,
61 err,
62 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
63 (LPTSTR) &msg,
64 sizeof(msg) - 1,
65 NULL
67 return msg;
69 #elif defined(HAVE_DLFCN_H)
70 inline ivl_dll_t ivl_dlopen(const char*name)
71 { return dlopen(name,RTLD_LAZY); }
73 inline void* ivl_dlsym(ivl_dll_t dll, const char*nm)
75 void*sym = dlsym(dll, nm);
76 /* Not found? try without the leading _ */
77 if (sym == 0 && nm[0] == '_')
78 sym = dlsym(dll, nm+1);
79 return sym;
82 inline void ivl_dlclose(ivl_dll_t dll)
83 { dlclose(dll); }
85 #elif defined(HAVE_DL_H)
86 inline ivl_dll_t ivl_dlopen(const char*name)
87 { return shl_load(name, BIND_IMMEDIATE, 0); }
89 inline void* ivl_dlsym(ivl_dll_t dll, const char*nm)
91 void*sym;
92 int rc = shl_findsym(&dll, nm, TYPE_PROCEDURE, &sym);
93 return (rc == 0) ? sym : 0;
96 inline void ivl_dlclose(ivl_dll_t dll)
97 { shl_unload(dll); }
99 inline const char*dlerror(void)
100 { return strerror( errno ); }
101 #endif
104 * The custom new operator for the ivl_nexus_s type allows us to
105 * allocate nexus objects in blocks. There are generally lots of them
106 * permanently allocated, and allocating them in blocks reduces the
107 * allocation overhead.
109 static struct ivl_nexus_s * nexus_pool_ptr = 0;
110 static int nexus_pool_remaining = 0;
111 static const size_t NEXUS_POOL_SIZE = 4096;
113 void* ivl_nexus_s::operator new(size_t s)
115 assert(s == sizeof(struct ivl_nexus_s));
116 if (nexus_pool_remaining <= 0) {
117 nexus_pool_ptr = new struct ivl_nexus_s[NEXUS_POOL_SIZE];
118 nexus_pool_remaining = NEXUS_POOL_SIZE;
121 struct ivl_nexus_s*tmp = nexus_pool_ptr;
122 nexus_pool_ptr += 1;
123 nexus_pool_remaining -= 1;
125 return tmp;
128 inline static const char *basename(ivl_scope_t scope, const char *inst)
130 inst += strlen(ivl_scope_name(scope));
131 assert(*inst == '.');
132 return inst+1;
135 static perm_string make_scope_name(const hname_t&name)
137 if (! name.has_number())
138 return name.peek_name();
140 char buf[1024];
141 snprintf(buf, sizeof buf, "%s[%d]",
142 name.peek_name().str(), name.peek_number());
143 return lex_strings.make(buf);
146 static struct dll_target dll_target_obj;
148 static void drive_from_link(const Link&lnk, ivl_drive_t&drv0, ivl_drive_t&drv1)
150 switch (lnk.drive0()) {
151 case Link::HIGHZ:
152 drv0 = IVL_DR_HiZ;
153 break;
154 case Link::WEAK:
155 drv0 = IVL_DR_WEAK;
156 break;
157 case Link::PULL:
158 drv0 = IVL_DR_PULL;
159 break;
160 case Link::STRONG:
161 drv0 = IVL_DR_STRONG;
162 break;
163 case Link::SUPPLY:
164 drv0 = IVL_DR_SUPPLY;
165 break;
168 switch (lnk.drive1()) {
169 case Link::HIGHZ:
170 drv1 = IVL_DR_HiZ;
171 break;
172 case Link::WEAK:
173 drv1 = IVL_DR_WEAK;
174 break;
175 case Link::PULL:
176 drv1 = IVL_DR_PULL;
177 break;
178 case Link::STRONG:
179 drv1 = IVL_DR_STRONG;
180 break;
181 case Link::SUPPLY:
182 drv1 = IVL_DR_SUPPLY;
183 break;
187 ivl_attribute_s* dll_target::fill_in_attributes(const Attrib*net)
189 ivl_attribute_s*attr;
190 unsigned nattr = net->attr_cnt();
192 if (nattr == 0)
193 return 0;
195 attr = new struct ivl_attribute_s[nattr];
197 for (unsigned idx = 0 ; idx < nattr ; idx += 1) {
198 verinum tmp = net->attr_value(idx);
199 attr[idx].key = net->attr_key(idx);
200 if (tmp.is_string()) {
201 attr[idx].type = IVL_ATT_STR;
202 attr[idx].val.str = strings_.add(tmp.as_string().c_str());
204 } else if (tmp == verinum()) {
205 attr[idx].type = IVL_ATT_VOID;
207 } else {
208 attr[idx].type = IVL_ATT_NUM;
209 attr[idx].val.num = tmp.as_long();
213 return attr;
217 * This function locates an ivl_scope_t object that matches the
218 * NetScope object. The search works by looking for the parent scope,
219 * then scanning the parent scope for the NetScope object.
221 static ivl_scope_t find_scope_from_root(ivl_scope_t root, const NetScope*cur)
223 ivl_scope_t parent, tmp;
224 perm_string cur_name = make_scope_name(cur->fullname());
226 if (const NetScope*par = cur->parent()) {
227 parent = find_scope_from_root(root, par);
228 if (parent == 0)
229 return 0;
231 for (tmp = parent->child_ ; tmp ; tmp = tmp->sibling_)
232 if (strcmp(tmp->name_, cur_name) == 0)
233 return tmp;
235 } else {
236 if (strcmp(root->name_, cur_name) == 0)
237 return root;
240 return 0;
243 ivl_scope_t dll_target::find_scope(ivl_design_s &des, const NetScope*cur)
245 assert(cur);
247 ivl_scope_t scope = 0;
248 for (unsigned i = 0; i < des.nroots_ && scope == 0; i += 1) {
249 assert(des.roots_[i]);
250 scope = find_scope_from_root(des.roots_[i], cur);
252 return scope;
255 ivl_scope_t dll_target::lookup_scope_(const NetScope*cur)
257 return find_scope(des_, cur);
261 * This is a convenience function to locate an ivl_signal_t object
262 * given the NetESignal that has the signal name.
264 ivl_signal_t dll_target::find_signal(ivl_design_s &des, const NetNet*net)
266 ivl_scope_t scope = find_scope(des, net->scope());
267 assert(scope);
269 perm_string nname = net->name();
271 for (unsigned idx = 0 ; idx < scope->nsigs_ ; idx += 1) {
272 if (strcmp(scope->sigs_[idx]->name_, nname) == 0)
273 return scope->sigs_[idx];
276 assert(0);
277 return 0;
280 static ivl_nexus_t nexus_sig_make(ivl_signal_t net, unsigned pin)
282 ivl_nexus_t tmp = new struct ivl_nexus_s;
283 tmp->private_data = 0;
284 tmp->nptr_ = 1;
285 tmp->ptrs_ = (struct ivl_nexus_ptr_s*)
286 malloc(sizeof(struct ivl_nexus_ptr_s));
287 tmp->ptrs_[0].pin_ = pin;
288 tmp->ptrs_[0].type_ = __NEXUS_PTR_SIG;
289 tmp->ptrs_[0].l.sig = net;
291 ivl_drive_t drive = IVL_DR_HiZ;
292 switch (ivl_signal_type(net)) {
293 case IVL_SIT_REG:
294 drive = IVL_DR_STRONG;
295 break;
296 default:
297 break;
299 tmp->ptrs_[0].drive0 = drive;
300 tmp->ptrs_[0].drive1 = drive;
302 return tmp;
305 static void nexus_sig_add(ivl_nexus_t nex, ivl_signal_t net, unsigned pin)
307 unsigned top = nex->nptr_ + 1;
308 nex->ptrs_ = (struct ivl_nexus_ptr_s*)
309 realloc(nex->ptrs_, top * sizeof(struct ivl_nexus_ptr_s));
310 nex->nptr_ = top;
312 ivl_drive_t drive = IVL_DR_HiZ;
313 switch (ivl_signal_type(net)) {
314 case IVL_SIT_REG:
315 drive = IVL_DR_STRONG;
316 break;
317 default:
318 break;
321 nex->ptrs_[top-1].type_= __NEXUS_PTR_SIG;
322 nex->ptrs_[top-1].drive0 = drive;
323 nex->ptrs_[top-1].drive1 = drive;
324 nex->ptrs_[top-1].pin_ = pin;
325 nex->ptrs_[top-1].l.sig= net;
329 * Add the pin of the logic object to the nexus, and return the nexus
330 * pointer used for the pin.
332 * NOTE: This pointer is only valid until another pin is added to the
333 * nexus.
335 static ivl_nexus_ptr_t nexus_log_add(ivl_nexus_t nex,
336 ivl_net_logic_t net,
337 unsigned pin)
339 unsigned top = nex->nptr_ + 1;
340 nex->ptrs_ = (struct ivl_nexus_ptr_s*)
341 realloc(nex->ptrs_, top * sizeof(struct ivl_nexus_ptr_s));
342 nex->nptr_ = top;
344 nex->ptrs_[top-1].type_= __NEXUS_PTR_LOG;
345 nex->ptrs_[top-1].drive0 = (pin == 0)? IVL_DR_STRONG : IVL_DR_HiZ;
346 nex->ptrs_[top-1].drive1 = (pin == 0)? IVL_DR_STRONG : IVL_DR_HiZ;
347 nex->ptrs_[top-1].pin_ = pin;
348 nex->ptrs_[top-1].l.log= net;
350 return nex->ptrs_ + top - 1;
353 static void nexus_con_add(ivl_nexus_t nex, ivl_net_const_t net, unsigned pin,
354 ivl_drive_t drive0, ivl_drive_t drive1)
356 unsigned top = nex->nptr_ + 1;
357 nex->ptrs_ = (struct ivl_nexus_ptr_s*)
358 realloc(nex->ptrs_, top * sizeof(struct ivl_nexus_ptr_s));
359 nex->nptr_ = top;
361 nex->ptrs_[top-1].type_= __NEXUS_PTR_CON;
362 nex->ptrs_[top-1].drive0 = drive0;
363 nex->ptrs_[top-1].drive1 = drive1;
364 nex->ptrs_[top-1].pin_ = pin;
365 nex->ptrs_[top-1].l.con= net;
368 static void nexus_lpm_add(ivl_nexus_t nex, ivl_lpm_t net, unsigned pin,
369 ivl_drive_t drive0, ivl_drive_t drive1)
371 unsigned top = nex->nptr_ + 1;
372 nex->ptrs_ = (struct ivl_nexus_ptr_s*)
373 realloc(nex->ptrs_, top * sizeof(struct ivl_nexus_ptr_s));
374 nex->nptr_ = top;
376 nex->ptrs_[top-1].type_= __NEXUS_PTR_LPM;
377 nex->ptrs_[top-1].drive0 = drive0;
378 nex->ptrs_[top-1].drive1 = drive0;
379 nex->ptrs_[top-1].pin_ = pin;
380 nex->ptrs_[top-1].l.lpm= net;
384 void scope_add_logic(ivl_scope_t scope, ivl_net_logic_t net)
386 if (scope->nlog_ == 0) {
387 scope->nlog_ = 1;
388 scope->log_ = (ivl_net_logic_t*)malloc(sizeof(ivl_net_logic_t));
389 scope->log_[0] = net;
391 } else {
392 scope->nlog_ += 1;
393 scope->log_ = (ivl_net_logic_t*)
394 realloc(scope->log_, scope->nlog_*sizeof(ivl_net_logic_t));
395 scope->log_[scope->nlog_-1] = net;
400 void scope_add_event(ivl_scope_t scope, ivl_event_t net)
402 if (scope->nevent_ == 0) {
403 scope->nevent_ = 1;
404 scope->event_ = (ivl_event_t*)malloc(sizeof(ivl_event_t));
405 scope->event_[0] = net;
407 } else {
408 scope->nevent_ += 1;
409 scope->event_ = (ivl_event_t*)
410 realloc(scope->event_, scope->nevent_*sizeof(ivl_event_t));
411 scope->event_[scope->nevent_-1] = net;
416 static void scope_add_lpm(ivl_scope_t scope, ivl_lpm_t net)
418 if (scope->nlpm_ == 0) {
419 assert(scope->lpm_ == 0);
420 scope->nlpm_ = 1;
421 scope->lpm_ = (ivl_lpm_t*)malloc(sizeof(ivl_lpm_t));
422 scope->lpm_[0] = net;
424 } else {
425 assert(scope->lpm_);
426 scope->nlpm_ += 1;
427 scope->lpm_ = (ivl_lpm_t*)
428 realloc(scope->lpm_,
429 scope->nlpm_*sizeof(ivl_lpm_t));
430 scope->lpm_[scope->nlpm_-1] = net;
434 ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope,
435 const char*name)
437 unsigned idx = 0;
438 while (idx < scope->nparam_) {
439 if (strcmp(name, scope->param_[idx].basename) == 0)
440 return scope->param_ + idx;
442 idx += 1;
445 return 0;
449 * This method scans the parameters of the scope, and makes
450 * ivl_parameter_t objects. This involves saving the name and scanning
451 * the expression value.
453 void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net)
455 scope->nparam_ = net->parameters.size() + net->localparams.size();
456 if (scope->nparam_ == 0) {
457 scope->param_ = 0;
458 return;
461 scope->param_ = new struct ivl_parameter_s [scope->nparam_];
463 unsigned idx = 0;
464 typedef map<perm_string,NetScope::param_expr_t>::const_iterator pit_t;
466 for (pit_t cur_pit = net->parameters.begin()
467 ; cur_pit != net->parameters.end() ; cur_pit ++) {
469 assert(idx < scope->nparam_);
470 ivl_parameter_t cur_par = scope->param_ + idx;
471 cur_par->basename = (*cur_pit).first;
472 cur_par->scope = scope;
473 cur_par->file = (*cur_pit).second.file;
474 cur_par->lineno = (*cur_pit).second.lineno;
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;
487 cur_par->file = (*cur_pit).second.file;
488 cur_par->lineno = (*cur_pit).second.lineno;
490 NetExpr*etmp = (*cur_pit).second.expr;
491 make_scope_param_expr(cur_par, etmp);
492 idx += 1;
496 void dll_target::make_scope_param_expr(ivl_parameter_t cur_par, NetExpr*etmp)
498 if (const NetEConst*e = dynamic_cast<const NetEConst*>(etmp)) {
500 expr_const(e);
501 assert(expr_);
503 switch (expr_->type_) {
504 case IVL_EX_STRING:
505 expr_->u_.string_.parameter = cur_par;
506 break;
507 case IVL_EX_NUMBER:
508 expr_->u_.number_.parameter = cur_par;
509 break;
510 default:
511 assert(0);
514 } else if (const NetECReal*e = dynamic_cast<const NetECReal*>(etmp)) {
516 expr_creal(e);
517 assert(expr_);
518 assert(expr_->type_ == IVL_EX_REALNUM);
519 expr_->u_.real_.parameter = cur_par;
523 cur_par->value = expr_;
524 expr_ = 0;
527 void dll_target::add_root(ivl_design_s &des_, const NetScope *s)
529 ivl_scope_t root_ = new struct ivl_scope_s;
530 perm_string name = s->basename();
531 root_->name_ = name;
532 FILE_NAME(root_, s);
533 root_->child_ = 0;
534 root_->sibling_ = 0;
535 root_->parent = 0;
536 root_->nsigs_ = 0;
537 root_->sigs_ = 0;
538 root_->nlog_ = 0;
539 root_->log_ = 0;
540 root_->nevent_ = 0;
541 root_->event_ = 0;
542 root_->nlpm_ = 0;
543 root_->lpm_ = 0;
544 root_->def = 0;
545 make_scope_parameters(root_, s);
546 root_->type_ = IVL_SCT_MODULE;
547 root_->tname_ = root_->name_;
548 root_->time_precision = s->time_precision();
549 root_->time_units = s->time_unit();
550 root_->nattr = s->attr_cnt();
551 root_->attr = fill_in_attributes(s);
553 des_.nroots_++;
554 if (des_.roots_)
555 des_.roots_ = (ivl_scope_t *)realloc(des_.roots_, des_.nroots_ * sizeof(ivl_scope_t));
556 else
557 des_.roots_ = (ivl_scope_t *)malloc(des_.nroots_ * sizeof(ivl_scope_t));
558 des_.roots_[des_.nroots_ - 1] = root_;
561 bool dll_target::start_design(const Design*des)
563 list<NetScope *> root_scopes;
564 const char*dll_path_ = des->get_flag("DLL");
566 dll_ = ivl_dlopen(dll_path_);
568 if ((dll_ == 0) && (dll_path_[0] != '/')) {
569 size_t len = strlen(basedir) + 1 + strlen(dll_path_) + 1;
570 char*tmp = new char[len];
571 sprintf(tmp, "%s/%s", basedir, dll_path_);
572 dll_ = ivl_dlopen(tmp);
573 delete[]tmp;
576 if (dll_ == 0) {
577 cerr << "error: " << dll_path_ << " failed to load." << endl;
578 cerr << dll_path_ << ": " << dlerror() << endl;
579 return false;
582 stmt_cur_ = 0;
584 // Initialize the design object.
585 des_.self = des;
586 des_.time_precision = des->get_precision();
587 des_.nroots_ = 0;
588 des_.roots_ = NULL;
590 root_scopes = des->find_root_scopes();
591 for (list<NetScope*>::const_iterator scope = root_scopes.begin();
592 scope != root_scopes.end(); scope++)
593 add_root(des_, *scope);
595 des_.consts = (ivl_net_const_t*)
596 malloc(sizeof(ivl_net_const_t));
597 des_.nconsts = 0;
599 target_ = (target_design_f)ivl_dlsym(dll_, LU "target_design" TU);
600 if (target_ == 0) {
601 cerr << dll_path_ << ": error: target_design entry "
602 "point is missing." << endl;
603 return false;
606 return true;
610 * Here ivl is telling us that the design is scanned completely, and
611 * here is where we call the API to process the constructed design.
613 int dll_target::end_design(const Design*)
615 if (verbose_flag) {
616 cout << " ... invoking target_design" << endl;
619 int rc = (target_)(&des_);
620 ivl_dlclose(dll_);
621 return rc;
624 void dll_target::logic_attributes(struct ivl_net_logic_s *obj,
625 const NetNode*net)
627 obj->nattr = net->attr_cnt();
628 obj->attr = fill_in_attributes(net);
631 void dll_target::make_logic_delays_(struct ivl_net_logic_s*obj,
632 const NetObj*net)
634 obj->delay[0] = 0;
635 obj->delay[1] = 0;
636 obj->delay[2] = 0;
638 /* Translate delay expressions to ivl_target form. Try to
639 preserve pointer equality, not as a rule but to save on
640 expression trees. */
641 if (net->rise_time()) {
642 expr_ = 0;
643 net->rise_time()->expr_scan(this);
644 obj->delay[0] = expr_;
645 expr_ = 0;
647 if (net->fall_time()) {
648 if (net->fall_time() == net->rise_time()) {
649 obj->delay[1] = obj->delay[0];
650 } else {
651 expr_ = 0;
652 net->fall_time()->expr_scan(this);
653 obj->delay[1] = expr_;
654 expr_ = 0;
657 if (net->decay_time()) {
658 if (net->decay_time() == net->rise_time()) {
659 obj->delay[2] = obj->delay[0];
660 } else {
661 expr_ = 0;
662 net->decay_time()->expr_scan(this);
663 obj->delay[2] = expr_;
664 expr_ = 0;
669 void dll_target::make_lpm_delays_(struct ivl_lpm_s*obj,
670 const NetObj*net)
672 obj->delay[0] = 0;
673 obj->delay[1] = 0;
674 obj->delay[2] = 0;
676 /* Translate delay expressions to ivl_target form. Try to
677 preserve pointer equality, not as a rule but to save on
678 expression trees. */
679 if (net->rise_time()) {
680 expr_ = 0;
681 net->rise_time()->expr_scan(this);
682 obj->delay[0] = expr_;
683 expr_ = 0;
685 if (net->fall_time()) {
686 if (net->fall_time() == net->rise_time()) {
687 obj->delay[1] = obj->delay[0];
688 } else {
689 expr_ = 0;
690 net->fall_time()->expr_scan(this);
691 obj->delay[1] = expr_;
692 expr_ = 0;
695 if (net->decay_time()) {
696 if (net->decay_time() == net->rise_time()) {
697 obj->delay[2] = obj->delay[0];
698 } else {
699 expr_ = 0;
700 net->decay_time()->expr_scan(this);
701 obj->delay[2] = expr_;
702 expr_ = 0;
707 void dll_target::make_const_delays_(struct ivl_net_const_s*obj,
708 const NetObj*net)
710 obj->delay[0] = 0;
711 obj->delay[1] = 0;
712 obj->delay[2] = 0;
714 /* Translate delay expressions to ivl_target form. Try to
715 preserve pointer equality, not as a rule but to save on
716 expression trees. */
717 if (net->rise_time()) {
718 expr_ = 0;
719 net->rise_time()->expr_scan(this);
720 obj->delay[0] = expr_;
721 expr_ = 0;
723 if (net->fall_time()) {
724 if (net->fall_time() == net->rise_time()) {
725 obj->delay[1] = obj->delay[0];
726 } else {
727 expr_ = 0;
728 net->fall_time()->expr_scan(this);
729 obj->delay[1] = expr_;
730 expr_ = 0;
733 if (net->decay_time()) {
734 if (net->decay_time() == net->rise_time()) {
735 obj->delay[2] = obj->delay[0];
736 } else {
737 expr_ = 0;
738 net->decay_time()->expr_scan(this);
739 obj->delay[2] = expr_;
740 expr_ = 0;
746 * Add a bufz object to the scope that contains it.
748 * Note that in the ivl_target API a BUFZ device is a special kind of
749 * ivl_net_logic_t device, so create an ivl_net_logic_t cookie to
750 * handle it.
752 bool dll_target::bufz(const NetBUFZ*net)
754 struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
756 assert(net->pin_count() == 2);
758 obj->type_ = IVL_LO_BUFZ;
759 obj->width_= net->width();
760 obj->npins_= 2;
761 obj->pins_ = new ivl_nexus_t[2];
763 /* Get the ivl_nexus_t objects connected to the two pins.
765 (We know a priori that the ivl_nexus_t objects have been
766 allocated, because the signals have been scanned before
767 me. This saves me the trouble of allocating them.) */
769 assert(net->pin(0).nexus()->t_cookie());
770 obj->pins_[0] = net->pin(0).nexus()->t_cookie();
771 ivl_nexus_ptr_t out_ptr = nexus_log_add(obj->pins_[0], obj, 0);
774 switch (net->pin(0).drive0()) {
775 case Link::HIGHZ:
776 out_ptr->drive0 = IVL_DR_HiZ;
777 break;
778 case Link::WEAK:
779 out_ptr->drive0 = IVL_DR_WEAK;
780 break;
781 case Link::PULL:
782 out_ptr->drive0 = IVL_DR_PULL;
783 break;
784 case Link::STRONG:
785 out_ptr->drive0 = IVL_DR_STRONG;
786 break;
787 case Link::SUPPLY:
788 out_ptr->drive0 = IVL_DR_SUPPLY;
789 break;
792 switch (net->pin(0).drive1()) {
793 case Link::HIGHZ:
794 out_ptr->drive1 = IVL_DR_HiZ;
795 break;
796 case Link::WEAK:
797 out_ptr->drive1 = IVL_DR_WEAK;
798 break;
799 case Link::PULL:
800 out_ptr->drive1 = IVL_DR_PULL;
801 break;
802 case Link::STRONG:
803 out_ptr->drive1 = IVL_DR_STRONG;
804 break;
805 case Link::SUPPLY:
806 out_ptr->drive1 = IVL_DR_SUPPLY;
807 break;
810 assert(net->pin(1).nexus()->t_cookie());
811 obj->pins_[1] = net->pin(1).nexus()->t_cookie();
812 nexus_log_add(obj->pins_[1], obj, 1);
814 /* Attach the logic device to the scope that contains it. */
816 assert(net->scope());
817 ivl_scope_t scope = find_scope(des_, net->scope());
818 assert(scope);
820 obj->scope_ = scope;
822 obj->name_ = net->name();
823 logic_attributes(obj, net);
825 make_logic_delays_(obj, net);
827 scope_add_logic(scope, obj);
829 return true;
832 void dll_target::event(const NetEvent*net)
834 struct ivl_event_s *obj = new struct ivl_event_s;
836 ivl_scope_t scope = find_scope(des_, net->scope());
837 obj->name = net->name();
838 obj->scope = scope;
839 scope_add_event(scope, obj);
841 obj->nany = 0;
842 obj->nneg = 0;
843 obj->npos = 0;
845 if (net->nprobe() >= 1) {
847 for (unsigned idx = 0 ; idx < net->nprobe() ; idx += 1) {
848 const NetEvProbe*pr = net->probe(idx);
849 switch (pr->edge()) {
850 case NetEvProbe::ANYEDGE:
851 obj->nany += pr->pin_count();
852 break;
853 case NetEvProbe::NEGEDGE:
854 obj->nneg += pr->pin_count();
855 break;
856 case NetEvProbe::POSEDGE:
857 obj->npos += pr->pin_count();
858 break;
862 unsigned npins = obj->nany + obj->nneg + obj->npos;
863 obj->pins = (ivl_nexus_t*)calloc(npins, sizeof(ivl_nexus_t));
865 } else {
866 obj->pins = 0;
871 void dll_target::logic(const NetLogic*net)
873 struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
875 obj->width_ = net->width();
877 switch (net->type()) {
878 case NetLogic::AND:
879 obj->type_ = IVL_LO_AND;
880 break;
881 case NetLogic::BUF:
882 obj->type_ = IVL_LO_BUF;
883 break;
884 case NetLogic::BUFIF0:
885 obj->type_ = IVL_LO_BUFIF0;
886 break;
887 case NetLogic::BUFIF1:
888 obj->type_ = IVL_LO_BUFIF1;
889 break;
890 case NetLogic::CMOS:
891 obj->type_ = IVL_LO_CMOS;
892 break;
893 case NetLogic::NAND:
894 obj->type_ = IVL_LO_NAND;
895 break;
896 case NetLogic::NMOS:
897 obj->type_ = IVL_LO_NMOS;
898 break;
899 case NetLogic::NOR:
900 obj->type_ = IVL_LO_NOR;
901 break;
902 case NetLogic::NOT:
903 obj->type_ = IVL_LO_NOT;
904 break;
905 case NetLogic::NOTIF0:
906 obj->type_ = IVL_LO_NOTIF0;
907 break;
908 case NetLogic::NOTIF1:
909 obj->type_ = IVL_LO_NOTIF1;
910 break;
911 case NetLogic::OR:
912 obj->type_ = IVL_LO_OR;
913 break;
914 case NetLogic::PULLDOWN:
915 obj->type_ = IVL_LO_PULLDOWN;
916 break;
917 case NetLogic::PULLUP:
918 obj->type_ = IVL_LO_PULLUP;
919 break;
920 case NetLogic::RCMOS:
921 obj->type_ = IVL_LO_RCMOS;
922 break;
923 case NetLogic::RNMOS:
924 obj->type_ = IVL_LO_RNMOS;
925 break;
926 case NetLogic::RPMOS:
927 obj->type_ = IVL_LO_RPMOS;
928 break;
929 case NetLogic::PMOS:
930 obj->type_ = IVL_LO_PMOS;
931 break;
932 case NetLogic::XNOR:
933 obj->type_ = IVL_LO_XNOR;
934 break;
935 case NetLogic::XOR:
936 obj->type_ = IVL_LO_XOR;
937 break;
938 default:
939 assert(0);
940 obj->type_ = IVL_LO_NONE;
941 break;
944 /* Connect all the ivl_nexus_t objects to the pins of the
945 device. */
947 obj->npins_ = net->pin_count();
948 obj->pins_ = new ivl_nexus_t[obj->npins_];
950 ivl_nexus_ptr_t out_ptr = 0;
952 for (unsigned idx = 0 ; idx < obj->npins_ ; idx += 1) {
953 const Nexus*nex = net->pin(idx).nexus();
954 assert(nex->t_cookie());
955 obj->pins_[idx] = nex->t_cookie();
956 ivl_nexus_ptr_t tmp = nexus_log_add(obj->pins_[idx], obj, idx);
957 if (idx == 0)
958 out_ptr = tmp;
961 switch (net->pin(0).drive0()) {
962 case Link::HIGHZ:
963 out_ptr->drive0 = IVL_DR_HiZ;
964 break;
965 case Link::WEAK:
966 out_ptr->drive0 = IVL_DR_WEAK;
967 break;
968 case Link::PULL:
969 out_ptr->drive0 = IVL_DR_PULL;
970 break;
971 case Link::STRONG:
972 out_ptr->drive0 = IVL_DR_STRONG;
973 break;
974 case Link::SUPPLY:
975 out_ptr->drive0 = IVL_DR_SUPPLY;
976 break;
979 switch (net->pin(0).drive1()) {
980 case Link::HIGHZ:
981 out_ptr->drive1 = IVL_DR_HiZ;
982 break;
983 case Link::WEAK:
984 out_ptr->drive1 = IVL_DR_WEAK;
985 break;
986 case Link::PULL:
987 out_ptr->drive1 = IVL_DR_PULL;
988 break;
989 case Link::STRONG:
990 out_ptr->drive1 = IVL_DR_STRONG;
991 break;
992 case Link::SUPPLY:
993 out_ptr->drive1 = IVL_DR_SUPPLY;
994 break;
997 assert(net->scope());
998 ivl_scope_t scope = find_scope(des_, net->scope());
999 assert(scope);
1001 obj->scope_= scope;
1002 obj->name_ = net->name();
1004 logic_attributes(obj, net);
1006 make_logic_delays_(obj, net);
1008 scope_add_logic(scope, obj);
1011 bool dll_target::sign_extend(const NetSignExtend*net)
1013 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1014 obj->type = IVL_LPM_SIGN_EXT;
1015 obj->width = net->width();
1016 obj->name = net->name();
1017 obj->scope = find_scope(des_, net->scope());
1018 assert(obj->scope);
1020 const Nexus*nex;
1022 nex = net->pin(0).nexus();
1023 assert(nex->t_cookie());
1025 obj->u_.reduce.q = nex->t_cookie();
1026 nexus_lpm_add(obj->u_.reduce.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1028 nex = net->pin(1).nexus();
1029 assert(nex->t_cookie());
1031 obj->u_.reduce.a = nex->t_cookie();
1032 nexus_lpm_add(obj->u_.reduce.a, obj, 1, IVL_DR_HiZ, IVL_DR_HiZ);
1034 make_lpm_delays_(obj, net);
1036 scope_add_lpm(obj->scope, obj);
1038 return true;
1041 bool dll_target::ureduce(const NetUReduce*net)
1043 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1044 switch (net->type()) {
1045 case NetUReduce::NONE:
1046 assert(0);
1047 return false;
1048 case NetUReduce::AND:
1049 obj->type = IVL_LPM_RE_AND;
1050 break;
1051 case NetUReduce::OR:
1052 obj->type = IVL_LPM_RE_OR;
1053 break;
1054 case NetUReduce::XOR:
1055 obj->type = IVL_LPM_RE_XOR;
1056 break;
1057 case NetUReduce::NAND:
1058 obj->type = IVL_LPM_RE_NAND;
1059 break;
1060 case NetUReduce::NOR:
1061 obj->type = IVL_LPM_RE_NOR;
1062 break;
1063 case NetUReduce::XNOR:
1064 obj->type = IVL_LPM_RE_XNOR;
1065 break;
1068 obj->name = net->name();
1069 obj->scope = find_scope(des_, net->scope());
1070 assert(obj->scope);
1072 obj->width = net->width();
1074 const Nexus*nex;
1076 nex = net->pin(0).nexus();
1077 assert(nex->t_cookie());
1079 obj->u_.reduce.q = nex->t_cookie();
1080 nexus_lpm_add(obj->u_.reduce.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1082 nex = net->pin(1).nexus();
1083 assert(nex->t_cookie());
1085 obj->u_.reduce.a = nex->t_cookie();
1086 nexus_lpm_add(obj->u_.reduce.a, obj, 1, IVL_DR_HiZ, IVL_DR_HiZ);
1088 make_lpm_delays_(obj, net);
1090 scope_add_lpm(obj->scope, obj);
1092 return true;
1095 void dll_target::net_case_cmp(const NetCaseCmp*net)
1097 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1098 obj->type = net->eeq()? IVL_LPM_CMP_EEQ : IVL_LPM_CMP_NEE;
1099 obj->name = net->name();
1100 obj->scope = find_scope(des_, net->scope());
1101 assert(obj->scope);
1103 obj->width = net->width();
1104 obj->u_.arith.signed_flag = 0;
1106 const Nexus*nex;
1108 nex = net->pin(1).nexus();
1109 assert(nex->t_cookie());
1111 obj->u_.arith.a = nex->t_cookie();
1112 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1114 nex = net->pin(2).nexus();
1115 assert(nex->t_cookie());
1117 obj->u_.arith.b = nex->t_cookie();
1118 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1120 nex = net->pin(0).nexus();
1121 assert(nex->t_cookie());
1123 obj->u_.arith.q = nex->t_cookie();
1124 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1126 make_lpm_delays_(obj, net);
1128 scope_add_lpm(obj->scope, obj);
1131 bool dll_target::net_sysfunction(const NetSysFunc*net)
1133 unsigned idx;
1134 const Nexus*nex;
1136 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1137 obj->type = IVL_LPM_SFUNC;
1138 FILE_NAME(obj, net);
1139 obj->name = net->name();
1140 obj->scope = find_scope(des_, net->scope());
1141 assert(obj->scope);
1143 obj->u_.sfunc.ports = net->pin_count();
1145 assert(net->pin_count() >= 1);
1146 obj->width = net->vector_width();
1148 obj->u_.sfunc.fun_name = net->func_name();
1150 obj->u_.sfunc.pins = new ivl_nexus_t[net->pin_count()];
1152 nex = net->pin(0).nexus();
1153 assert(nex->t_cookie());
1155 obj->u_.sfunc.pins[0] = nex->t_cookie();
1156 nexus_lpm_add(obj->u_.sfunc.pins[0], obj, 0,
1157 IVL_DR_STRONG, IVL_DR_STRONG);
1159 for (idx = 1 ; idx < net->pin_count() ; idx += 1) {
1160 nex = net->pin(idx).nexus();
1161 assert(nex->t_cookie());
1163 obj->u_.sfunc.pins[idx] = nex->t_cookie();
1164 nexus_lpm_add(obj->u_.sfunc.pins[idx], obj, 0,
1165 IVL_DR_HiZ, IVL_DR_HiZ);
1168 make_lpm_delays_(obj, net);
1170 scope_add_lpm(obj->scope, obj);
1171 return true;
1175 * An IVL_LPM_UFUNC represents a node in a combinational expression
1176 * that calls a user defined function. I create an LPM object that has
1177 * the right connections, and refers to the ivl_scope_t of the
1178 * definition.
1180 bool dll_target::net_function(const NetUserFunc*net)
1182 struct ivl_lpm_s*obj = new struct ivl_lpm_s;
1183 obj->type = IVL_LPM_UFUNC;
1184 obj->name = net->name();
1185 obj->scope = find_scope(des_, net->scope());
1186 assert(obj->scope);
1188 /* Get the definition of the function and save it. */
1189 const NetScope*def = net->def();
1190 assert(def);
1192 obj->u_.ufunc.def = lookup_scope_(def);
1194 /* Save information about the ports in the ivl_lpm_s
1195 structure. Note that port 0 is the return value. */
1196 obj->u_.ufunc.ports = net->pin_count();
1198 assert(net->pin_count() >= 1);
1199 obj->width = net->port_width(0);
1201 /* Now collect all the pins and connect them to the nexa of
1202 the net. The output pins have strong drive, and the
1203 remaining input pins are HiZ. */
1205 obj->u_.ufunc.pins = new ivl_nexus_t[net->pin_count()];
1207 for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
1208 const Nexus*nex = net->pin(idx).nexus();
1209 assert(nex->t_cookie());
1210 ivl_nexus_t nn = nex->t_cookie();
1211 assert(nn);
1213 obj->u_.ufunc.pins[idx] = nn;
1214 ivl_drive_t drive = idx == 0 ? IVL_DR_STRONG : IVL_DR_HiZ;
1215 nexus_lpm_add(obj->u_.ufunc.pins[idx], obj, idx, drive, drive);
1218 make_lpm_delays_(obj, net);
1220 /* All done. Add this LPM to the scope. */
1221 scope_add_lpm(obj->scope, obj);
1223 return true;
1226 void dll_target::udp(const NetUDP*net)
1228 struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
1230 obj->type_ = IVL_LO_UDP;
1232 /* The NetUDP class hasn't learned about width yet, so we
1233 assume a width of 1. */
1234 obj->width_ = 1;
1236 static map<perm_string,ivl_udp_t> udps;
1237 ivl_udp_t u;
1239 if (udps.find(net->udp_name()) != udps.end())
1241 u = udps[net->udp_name()];
1243 else
1245 u = new struct ivl_udp_s;
1246 u->nrows = net->rows();
1247 u->table = (ivl_udp_s::ccharp_t*)malloc((u->nrows+1)*sizeof(char*));
1248 assert(u->table);
1249 u->table[u->nrows] = 0x0;
1250 u->nin = net->nin();
1251 u->sequ = net->is_sequential();
1252 if (u->sequ)
1253 u->init = net->get_initial();
1254 else
1255 u->init = 'x';
1256 u->name = net->udp_name();
1257 string inp;
1258 char out;
1259 unsigned int i = 0;
1260 if (net->first(inp, out))
1263 string tt = inp+out;
1264 u->table[i++] = strings_.add(tt.c_str());
1265 } while (net->next(inp, out));
1266 assert(i==u->nrows);
1268 udps[net->udp_name()] = u;
1271 obj->udp = u;
1273 // Some duplication of code here, see: dll_target::logic()
1275 /* Connect all the ivl_nexus_t objects to the pins of the
1276 device. */
1278 obj->npins_ = net->pin_count();
1279 obj->pins_ = new ivl_nexus_t[obj->npins_];
1280 for (unsigned idx = 0 ; idx < obj->npins_ ; idx += 1) {
1281 const Nexus*nex = net->pin(idx).nexus();
1283 /* Skip unconnected input pins. These will take on HiZ
1284 values by the code generators. */
1285 if (nex->t_cookie() == 0) {
1286 obj->pins_[idx] = 0;
1287 continue;
1290 assert(nex->t_cookie());
1291 obj->pins_[idx] = nex->t_cookie();
1292 nexus_log_add(obj->pins_[idx], obj, idx);
1295 assert(net->scope());
1296 ivl_scope_t scope = find_scope(des_, net->scope());
1297 assert(scope);
1299 obj->scope_= scope;
1300 obj->name_ = net->name();
1302 make_logic_delays_(obj, net);
1304 obj->nattr = 0;
1305 obj->attr = 0;
1307 scope_add_logic(scope, obj);
1310 void dll_target::lpm_add_sub(const NetAddSub*net)
1312 ivl_lpm_t obj = new struct ivl_lpm_s;
1313 if (net->attribute(perm_string::literal("LPM_Direction")) == verinum("SUB"))
1314 obj->type = IVL_LPM_SUB;
1315 else
1316 obj->type = IVL_LPM_ADD;
1317 obj->name = net->name(); // NetAddSub names are permallocated.
1318 assert(net->scope());
1319 obj->scope = find_scope(des_, net->scope());
1320 assert(obj->scope);
1322 obj->u_.arith.signed_flag = 0;
1324 /* Choose the width of the adder. If the carry bit is
1325 connected, then widen the adder by one and plan on leaving
1326 the fake inputs unconnected. */
1327 obj->width = net->width();
1328 if (net->pin_Cout().is_linked()) {
1329 obj->width += 1;
1333 const Nexus*nex;
1335 nex = net->pin_Result().nexus();
1336 assert(nex->t_cookie());
1338 obj->u_.arith.q = nex->t_cookie();
1339 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1341 nex = net->pin_DataA().nexus();
1342 assert(nex->t_cookie());
1344 obj->u_.arith.a = nex->t_cookie();
1345 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1347 nex = net->pin_DataB().nexus();
1348 assert(nex->t_cookie());
1350 obj->u_.arith.b = nex->t_cookie();
1351 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1353 /* If the carry output is connected, then connect the extra Q
1354 pin to the carry nexus and zero the a and b inputs. */
1355 if (net->pin_Cout().is_linked()) {
1356 cerr << "XXXX: t-dll.cc: Forgot how to connect cout." << endl;
1359 make_lpm_delays_(obj, net);
1361 scope_add_lpm(obj->scope, obj);
1364 bool dll_target::lpm_array_dq(const NetArrayDq*net)
1366 ivl_lpm_t obj = new struct ivl_lpm_s;
1367 obj->type = IVL_LPM_ARRAY;
1368 obj->name = net->name();
1369 obj->u_.array.sig = find_signal(des_, net->mem());
1370 assert(obj->u_.array.sig);
1371 obj->scope = find_scope(des_, net->scope());
1372 assert(obj->scope);
1373 obj->width = net->width();
1374 obj->u_.array.swid = net->awidth();
1376 make_lpm_delays_(obj, net);
1378 scope_add_lpm(obj->scope, obj);
1380 const Nexus*nex;
1382 nex = net->pin_Address().nexus();
1383 assert(nex->t_cookie());
1384 obj->u_.array.a = nex->t_cookie();
1385 nexus_lpm_add(obj->u_.array.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1387 nex = net->pin_Result().nexus();
1388 assert(nex->t_cookie());
1389 obj->u_.array.q = nex->t_cookie();
1390 nexus_lpm_add(obj->u_.array.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1392 return true;
1396 * The lpm_clshift device represents both left and right shifts,
1397 * depending on what is connected to the Direction pin. We convert
1398 * this device into SHIFTL or SHIFTR devices.
1400 void dll_target::lpm_clshift(const NetCLShift*net)
1402 ivl_lpm_t obj = new struct ivl_lpm_s;
1403 obj->type = IVL_LPM_SHIFTL;
1404 obj->name = net->name();
1405 assert(net->scope());
1406 obj->scope = find_scope(des_, net->scope());
1407 assert(obj->scope);
1409 /* Look at the direction input of the device, and select the
1410 shift direction accordingly. */
1411 if (net->right_flag())
1412 obj->type = IVL_LPM_SHIFTR;
1413 if (net->signed_flag())
1414 obj->u_.shift.signed_flag = 1;
1415 else
1416 obj->u_.shift.signed_flag = 0;
1418 obj->width = net->width();
1419 obj->u_.shift.select = net->width_dist();
1421 const Nexus*nex;
1423 nex = net->pin_Result().nexus();
1424 assert(nex->t_cookie());
1426 obj->u_.shift.q = nex->t_cookie();
1427 nexus_lpm_add(obj->u_.shift.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1429 nex = net->pin_Data().nexus();
1430 assert(nex->t_cookie());
1432 obj->u_.shift.d = nex->t_cookie();
1433 nexus_lpm_add(obj->u_.shift.d, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1435 nex = net->pin_Distance().nexus();
1436 assert(nex->t_cookie());
1438 obj->u_.shift.s = nex->t_cookie();
1439 nexus_lpm_add(obj->u_.shift.s, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1441 make_lpm_delays_(obj, net);
1443 scope_add_lpm(obj->scope, obj);
1447 * Make out of the NetCompare object an ivl_lpm_s object. The
1448 * comparators in ivl_target do not support < or <=, but they can be
1449 * trivially converted to > and >= by swapping the operands.
1451 void dll_target::lpm_compare(const NetCompare*net)
1453 ivl_lpm_t obj = new struct ivl_lpm_s;
1454 obj->name = net->name(); // NetCompare names are permallocated
1455 assert(net->scope());
1456 obj->scope = find_scope(des_, net->scope());
1457 assert(obj->scope);
1459 bool swap_operands = false;
1461 obj->width = net->width();
1462 obj->u_.arith.signed_flag = net->get_signed()? 1 : 0;
1464 const Nexus*nex;
1466 nex = net->pin_DataA().nexus();
1467 assert(nex->t_cookie());
1469 obj->u_.arith.a = nex->t_cookie();
1471 nex = net->pin_DataB().nexus();
1472 assert(nex->t_cookie());
1474 obj->u_.arith.b = nex->t_cookie();
1477 if (net->pin_AGEB().is_linked()) {
1478 nex = net->pin_AGEB().nexus();
1479 obj->type = IVL_LPM_CMP_GE;
1481 assert(nex->t_cookie());
1482 obj->u_.arith.q = nex->t_cookie();
1483 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1484 IVL_DR_STRONG, IVL_DR_STRONG);
1486 } else if (net->pin_AGB().is_linked()) {
1487 nex = net->pin_AGB().nexus();
1488 obj->type = IVL_LPM_CMP_GT;
1490 assert(nex->t_cookie());
1491 obj->u_.arith.q = nex->t_cookie();
1492 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1493 IVL_DR_STRONG, IVL_DR_STRONG);
1495 } else if (net->pin_ALEB().is_linked()) {
1496 nex = net->pin_ALEB().nexus();
1497 obj->type = IVL_LPM_CMP_GE;
1499 assert(nex->t_cookie());
1500 obj->u_.arith.q = nex->t_cookie();
1501 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1502 IVL_DR_STRONG, IVL_DR_STRONG);
1504 swap_operands = true;
1506 } else if (net->pin_ALB().is_linked()) {
1507 nex = net->pin_ALB().nexus();
1508 obj->type = IVL_LPM_CMP_GT;
1510 assert(nex->t_cookie());
1511 obj->u_.arith.q = nex->t_cookie();
1512 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1513 IVL_DR_STRONG, IVL_DR_STRONG);
1515 swap_operands = true;
1517 } else if (net->pin_AEB().is_linked()) {
1518 nex = net->pin_AEB().nexus();
1519 obj->type = IVL_LPM_CMP_EQ;
1521 assert(nex->t_cookie());
1522 obj->u_.arith.q = nex->t_cookie();
1523 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1524 IVL_DR_STRONG, IVL_DR_STRONG);
1526 } else if (net->pin_ANEB().is_linked()) {
1527 nex = net->pin_ANEB().nexus();
1528 obj->type = IVL_LPM_CMP_NE;
1530 assert(nex->t_cookie());
1531 obj->u_.arith.q = nex->t_cookie();
1532 nexus_lpm_add(obj->u_.arith.q, obj, 0,
1533 IVL_DR_STRONG, IVL_DR_STRONG);
1535 } else {
1536 assert(0);
1539 if (swap_operands) {
1540 ivl_nexus_t tmp = obj->u_.arith.a;
1541 obj->u_.arith.a = obj->u_.arith.b;
1542 obj->u_.arith.b = tmp;
1545 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1546 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1548 make_lpm_delays_(obj, net);
1550 scope_add_lpm(obj->scope, obj);
1553 void dll_target::lpm_divide(const NetDivide*net)
1555 ivl_lpm_t obj = new struct ivl_lpm_s;
1556 obj->type = IVL_LPM_DIVIDE;
1557 obj->name = net->name();
1558 assert(net->scope());
1559 obj->scope = find_scope(des_, net->scope());
1560 assert(obj->scope);
1562 unsigned wid = net->width_r();
1564 obj->width = wid;
1565 obj->u_.arith.signed_flag = net->get_signed()? 1 : 0;
1567 const Nexus*nex;
1569 nex = net->pin_Result().nexus();
1570 assert(nex->t_cookie());
1572 obj->u_.arith.q = nex->t_cookie();
1573 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1575 nex = net->pin_DataA().nexus();
1576 assert(nex->t_cookie());
1578 obj->u_.arith.a = nex->t_cookie();
1579 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1581 nex = net->pin_DataB().nexus();
1582 assert(nex->t_cookie());
1584 obj->u_.arith.b = nex->t_cookie();
1585 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1587 make_lpm_delays_(obj, net);
1589 scope_add_lpm(obj->scope, obj);
1592 void dll_target::lpm_modulo(const NetModulo*net)
1594 ivl_lpm_t obj = new struct ivl_lpm_s;
1595 obj->type = IVL_LPM_MOD;
1596 obj->name = net->name();
1597 assert(net->scope());
1598 obj->scope = find_scope(des_, net->scope());
1599 assert(obj->scope);
1601 unsigned wid = net->width_r();
1603 obj->width = wid;
1604 obj->u_.arith.signed_flag = 0;
1606 const Nexus*nex;
1608 nex = net->pin_Result().nexus();
1609 assert(nex->t_cookie());
1611 obj->u_.arith.q = nex->t_cookie();
1612 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1614 nex = net->pin_DataA().nexus();
1615 assert(nex->t_cookie());
1617 obj->u_.arith.a = nex->t_cookie();
1618 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1620 nex = net->pin_DataB().nexus();
1621 assert(nex->t_cookie());
1623 obj->u_.arith.b = nex->t_cookie();
1624 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1626 make_lpm_delays_(obj, net);
1628 scope_add_lpm(obj->scope, obj);
1631 void dll_target::lpm_ff(const NetFF*net)
1633 ivl_lpm_t obj = new struct ivl_lpm_s;
1634 obj->type = IVL_LPM_FF;
1635 obj->name = net->name();
1636 obj->scope = find_scope(des_, net->scope());
1637 assert(obj->scope);
1639 obj->width = net->width();
1641 scope_add_lpm(obj->scope, obj);
1643 const Nexus*nex;
1645 /* Set the clk signal to point to the nexus, and the nexus to
1646 point back to this device. */
1647 nex = net->pin_Clock().nexus();
1648 assert(nex->t_cookie());
1649 obj->u_.ff.clk = nex->t_cookie();
1650 assert(obj->u_.ff.clk);
1651 nexus_lpm_add(obj->u_.ff.clk, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1653 /* If there is a clock enable, then connect it up to the FF
1654 device. */
1655 if (net->pin_Enable().is_linked()) {
1656 nex = net->pin_Enable().nexus();
1657 assert(nex->t_cookie());
1658 obj->u_.ff.we = nex->t_cookie();
1659 assert(obj->u_.ff.we);
1660 nexus_lpm_add(obj->u_.ff.we, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1661 } else {
1662 obj->u_.ff.we = 0;
1665 if (net->pin_Aclr().is_linked()) {
1666 nex = net->pin_Aclr().nexus();
1667 assert(nex->t_cookie());
1668 obj->u_.ff.aclr = nex->t_cookie();
1669 assert(obj->u_.ff.aclr);
1670 nexus_lpm_add(obj->u_.ff.aclr, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1671 } else {
1672 obj->u_.ff.aclr = 0;
1675 if (net->pin_Aset().is_linked()) {
1676 nex = net->pin_Aset().nexus();
1677 assert(nex->t_cookie());
1678 obj->u_.ff.aset = nex->t_cookie();
1679 assert(obj->u_.ff.aset);
1680 nexus_lpm_add(obj->u_.ff.aset, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1682 verinum tmp = net->aset_value();
1683 obj->u_.ff.aset_value = expr_from_value_(tmp);
1685 } else {
1686 obj->u_.ff.aset = 0;
1687 obj->u_.ff.aset_value = 0;
1690 if (net->pin_Sclr().is_linked()) {
1691 nex = net->pin_Sclr().nexus();
1692 assert(nex->t_cookie());
1693 obj->u_.ff.sclr = nex->t_cookie();
1694 assert(obj->u_.ff.sclr);
1695 nexus_lpm_add(obj->u_.ff.sclr, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1696 } else {
1697 obj->u_.ff.sclr = 0;
1700 if (net->pin_Sset().is_linked()) {
1701 nex = net->pin_Sset().nexus();
1702 assert(nex->t_cookie());
1703 obj->u_.ff.sset = nex->t_cookie();
1704 assert(obj->u_.ff.sset);
1705 nexus_lpm_add(obj->u_.ff.sset, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1707 verinum tmp = net->sset_value();
1708 obj->u_.ff.sset_value = expr_from_value_(tmp);
1710 } else {
1711 obj->u_.ff.sset = 0;
1712 obj->u_.ff.sset_value = 0;
1715 nex = net->pin_Q().nexus();
1716 assert(nex->t_cookie());
1717 obj->u_.ff.q.pin = nex->t_cookie();
1718 nexus_lpm_add(obj->u_.ff.q.pin, obj, 0,
1719 IVL_DR_STRONG, IVL_DR_STRONG);
1721 nex = net->pin_Data().nexus();
1722 assert(nex->t_cookie());
1723 obj->u_.ff.d.pin = nex->t_cookie();
1724 nexus_lpm_add(obj->u_.ff.d.pin, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1729 * Make the NetMult object into an IVL_LPM_MULT node.
1731 void dll_target::lpm_mult(const NetMult*net)
1733 ivl_lpm_t obj = new struct ivl_lpm_s;
1734 obj->type = IVL_LPM_MULT;
1735 obj->name = net->name();
1736 assert(net->scope());
1737 obj->scope = find_scope(des_, net->scope());
1738 assert(obj->scope);
1740 unsigned wid = net->width_r();
1742 obj->width = wid;
1744 const Nexus*nex;
1746 nex = net->pin_Result().nexus();
1747 assert(nex->t_cookie());
1749 obj->u_.arith.q = nex->t_cookie();
1750 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1752 nex = net->pin_DataA().nexus();
1753 assert(nex->t_cookie());
1755 obj->u_.arith.a = nex->t_cookie();
1756 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1758 nex = net->pin_DataB().nexus();
1759 assert(nex->t_cookie());
1761 obj->u_.arith.b = nex->t_cookie();
1762 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1764 make_lpm_delays_(obj, net);
1766 scope_add_lpm(obj->scope, obj);
1770 * Hook up the mux devices so that the select expression selects the
1771 * correct sub-expression with the ivl_lpm_data2 function.
1773 void dll_target::lpm_mux(const NetMux*net)
1775 ivl_lpm_t obj = new struct ivl_lpm_s;
1776 obj->type = IVL_LPM_MUX;
1777 obj->name = net->name(); // The NetMux perallocates its name.
1778 obj->scope = find_scope(des_, net->scope());
1779 assert(obj->scope);
1781 obj->width = net->width();
1782 obj->u_.mux.size = net->size();
1783 obj->u_.mux.swid = net->sel_width();
1785 make_lpm_delays_(obj, net);
1787 scope_add_lpm(obj->scope, obj);
1789 const Nexus*nex;
1791 /* Connect the output bits. */
1792 nex = net->pin_Result().nexus();
1793 assert(nex->t_cookie());
1794 obj->u_.mux.q = nex->t_cookie();
1795 nexus_lpm_add(obj->u_.mux.q, obj, 0,
1796 IVL_DR_STRONG, IVL_DR_STRONG);
1798 /* Connect the select bits. */
1799 nex = net->pin_Sel().nexus();
1800 assert(nex->t_cookie());
1801 obj->u_.mux.s = nex->t_cookie();
1802 nexus_lpm_add(obj->u_.mux.s, obj, 0,
1803 IVL_DR_HiZ, IVL_DR_HiZ);
1805 unsigned selects = obj->u_.mux.size;
1807 obj->u_.mux.d = new ivl_nexus_t [selects];
1809 for (unsigned sdx = 0 ; sdx < selects ; sdx += 1) {
1810 nex = net->pin_Data(sdx).nexus();
1811 ivl_nexus_t tmp = nex->t_cookie();
1812 obj->u_.mux.d[sdx] = tmp;
1813 nexus_lpm_add(tmp, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1819 * Make the NetPow object into an IVL_LPM_POW node.
1821 void dll_target::lpm_pow(const NetPow*net)
1823 ivl_lpm_t obj = new struct ivl_lpm_s;
1824 obj->type = IVL_LPM_POW;
1825 FILE_NAME(obj, net);
1826 obj->name = net->name();
1827 assert(net->scope());
1828 obj->scope = find_scope(des_, net->scope());
1829 assert(obj->scope);
1831 unsigned wid = net->width_r();
1832 obj->u_.arith.signed_flag = net->get_signed()? 1 : 0;
1834 obj->width = wid;
1836 const Nexus*nex;
1838 nex = net->pin_Result().nexus();
1839 assert(nex->t_cookie());
1841 obj->u_.arith.q = nex->t_cookie();
1842 nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1844 nex = net->pin_DataA().nexus();
1845 assert(nex->t_cookie());
1847 obj->u_.arith.a = nex->t_cookie();
1848 nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1850 nex = net->pin_DataB().nexus();
1851 assert(nex->t_cookie());
1853 obj->u_.arith.b = nex->t_cookie();
1854 nexus_lpm_add(obj->u_.arith.b, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1856 make_lpm_delays_(obj, net);
1858 scope_add_lpm(obj->scope, obj);
1861 bool dll_target::concat(const NetConcat*net)
1863 ivl_lpm_t obj = new struct ivl_lpm_s;
1864 obj->type = IVL_LPM_CONCAT;
1865 obj->name = net->name(); // NetConcat names are permallocated
1866 assert(net->scope());
1867 obj->scope = find_scope(des_, net->scope());
1868 assert(obj->scope);
1870 obj->width = net->width();
1872 obj->u_.concat.inputs = net->pin_count() - 1;
1873 obj->u_.concat.pins = new ivl_nexus_t[obj->u_.concat.inputs+1];
1875 for (unsigned idx = 0 ; idx < obj->u_.concat.inputs+1 ; idx += 1) {
1876 ivl_drive_t dr = idx == 0? IVL_DR_STRONG : IVL_DR_HiZ;
1877 const Nexus*nex = net->pin(idx).nexus();
1878 assert(nex->t_cookie());
1880 obj->u_.concat.pins[idx] = nex->t_cookie();
1881 nexus_lpm_add(obj->u_.concat.pins[idx], obj, 0, dr, dr);
1884 make_lpm_delays_(obj, net);
1886 scope_add_lpm(obj->scope, obj);
1888 return true;
1891 bool dll_target::part_select(const NetPartSelect*net)
1893 ivl_lpm_t obj = new struct ivl_lpm_s;
1894 switch (net->dir()) {
1895 case NetPartSelect::VP:
1896 obj->type = IVL_LPM_PART_VP;
1897 break;
1898 case NetPartSelect::PV:
1899 obj->type = IVL_LPM_PART_PV;
1900 break;
1901 case NetPartSelect::BI:
1902 obj->type = IVL_LPM_PART_BI;
1903 break;
1905 obj->name = net->name(); // NetPartSelect names are permallocated.
1906 assert(net->scope());
1907 obj->scope = find_scope(des_, net->scope());
1908 assert(obj->scope);
1910 /* Part selects are always unsigned. */
1911 obj->u_.part.signed_flag = 0;
1913 /* Choose the width of the part select. */
1914 obj->width = net->width();
1915 obj->u_.part.base = net->base();
1916 obj->u_.part.s = 0;
1918 const Nexus*nex;
1920 switch (obj->type) {
1921 case IVL_LPM_PART_VP:
1922 /* NetPartSelect:pin(0) is the output pin. */
1923 nex = net->pin(0).nexus();
1924 assert(nex->t_cookie());
1926 obj->u_.part.q = nex->t_cookie();
1928 /* NetPartSelect:pin(1) is the input pin. */
1929 nex = net->pin(1).nexus();
1930 assert(nex->t_cookie());
1932 obj->u_.part.a = nex->t_cookie();
1934 /* If the part select has an additional pin, that pin is
1935 a variable select base. */
1936 if (net->pin_count() >= 3) {
1937 nex = net->pin(2).nexus();
1938 assert(nex->t_cookie());
1939 obj->u_.part.s = nex->t_cookie();
1941 break;
1943 case IVL_LPM_PART_PV:
1944 /* NetPartSelect:pin(1) is the output pin. */
1945 nex = net->pin(1).nexus();
1946 assert(nex->t_cookie());
1948 obj->u_.part.q = nex->t_cookie();
1950 /* NetPartSelect:pin(0) is the input pin. */
1951 nex = net->pin(0).nexus();
1952 assert(nex->t_cookie());
1954 obj->u_.part.a = nex->t_cookie();
1955 break;
1957 case IVL_LPM_PART_BI:
1958 /* For now, handle this exactly the same as a PV */
1960 /* NetPartSelect:pin(0) is the output pin. */
1961 nex = net->pin(0).nexus();
1962 assert(nex->t_cookie());
1964 obj->u_.part.q = nex->t_cookie();
1966 /* NetPartSelect:pin(1) is the input pin. */
1967 nex = net->pin(1).nexus();
1968 assert(nex->t_cookie());
1970 obj->u_.part.a = nex->t_cookie();
1971 break;
1973 default:
1974 assert(0);
1977 nexus_lpm_add(obj->u_.part.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1979 /* If the device is a PART_BI, then the "input" is also a
1980 strength aware output, so attach it to the nexus with
1981 strong driver. */
1982 if (obj->type == IVL_LPM_PART_BI)
1983 nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
1984 else
1985 nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1987 /* The select input is optional. */
1988 if (obj->u_.part.s)
1989 nexus_lpm_add(obj->u_.part.s, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
1991 make_lpm_delays_(obj, net);
1993 scope_add_lpm(obj->scope, obj);
1995 return true;
1998 bool dll_target::replicate(const NetReplicate*net)
2000 ivl_lpm_t obj = new struct ivl_lpm_s;
2001 obj->type = IVL_LPM_REPEAT;
2002 obj->name = net->name();
2003 assert(net->scope());
2004 obj->scope = find_scope(des_, net->scope());
2005 assert(obj->scope);
2007 obj->width = net->width();
2008 obj->u_.repeat.count = net->repeat();
2010 ivl_drive_t dr = IVL_DR_STRONG;
2011 const Nexus*nex = net->pin(0).nexus();
2012 assert(nex->t_cookie());
2014 obj->u_.repeat.q = nex->t_cookie();
2015 nexus_lpm_add(obj->u_.repeat.q, obj, 0, dr, dr);
2017 dr = IVL_DR_HiZ;
2018 nex = net->pin(1).nexus();
2019 assert(nex->t_cookie());
2021 obj->u_.repeat.a = nex->t_cookie();
2022 nexus_lpm_add(obj->u_.repeat.a, obj, 0, dr, dr);
2024 make_lpm_delays_(obj, net);
2026 scope_add_lpm(obj->scope, obj);
2028 return true;
2032 * The assignment l-values are captured by the assignment statements
2033 * themselves in the process handling.
2035 void dll_target::net_assign(const NetAssign_*)
2039 bool dll_target::net_const(const NetConst*net)
2041 unsigned idx;
2042 char*bits;
2044 struct ivl_net_const_s *obj = new struct ivl_net_const_s;
2046 obj->type = IVL_VT_LOGIC;
2048 /* constants have a single vector output. */
2049 assert(net->pin_count() == 1);
2051 obj->width_ = net->width();
2052 if (obj->width_ <= sizeof(obj->b.bit_)) {
2053 bits = obj->b.bit_;
2055 } else {
2056 obj->b.bits_ = (char*)malloc(obj->width_);
2057 bits = obj->b.bits_;
2060 for (idx = 0 ; idx < obj->width_ ; idx += 1)
2061 switch (net->value(idx)) {
2062 case verinum::V0:
2063 bits[idx] = '0';
2064 break;
2065 case verinum::V1:
2066 bits[idx] = '1';
2067 break;
2068 case verinum::Vx:
2069 bits[idx] = 'x';
2070 break;
2071 case verinum::Vz:
2072 bits[idx] = 'z';
2073 break;
2076 /* Connect to all the nexus objects. Note that the one-bit
2077 case can be handled more efficiently without allocating
2078 array space. */
2080 ivl_drive_t drv0, drv1;
2081 drive_from_link(net->pin(0), drv0, drv1);
2082 const Nexus*nex = net->pin(0).nexus();
2083 assert(nex->t_cookie());
2084 obj->pin_ = nex->t_cookie();
2085 nexus_con_add(obj->pin_, obj, 0, drv0, drv1);
2088 des_.nconsts += 1;
2089 des_.consts = (ivl_net_const_t*)
2090 realloc(des_.consts, des_.nconsts * sizeof(ivl_net_const_t));
2091 des_.consts[des_.nconsts-1] = obj;
2093 make_const_delays_(obj, net);
2095 return true;
2098 bool dll_target::net_literal(const NetLiteral*net)
2101 struct ivl_net_const_s *obj = new struct ivl_net_const_s;
2103 obj->type = IVL_VT_REAL;
2104 obj->width_ = 1;
2105 obj->signed_ = 1;
2106 obj->b.real_value = net->value_real().as_double();
2108 /* Connect to all the nexus objects. Note that the one-bit
2109 case can be handled more efficiently without allocating
2110 array space. */
2112 ivl_drive_t drv0, drv1;
2113 drive_from_link(net->pin(0), drv0, drv1);
2114 const Nexus*nex = net->pin(0).nexus();
2115 assert(nex->t_cookie());
2116 obj->pin_ = nex->t_cookie();
2117 nexus_con_add(obj->pin_, obj, 0, drv0, drv1);
2119 des_.nconsts += 1;
2120 des_.consts = (ivl_net_const_t*)
2121 realloc(des_.consts, des_.nconsts * sizeof(ivl_net_const_t));
2122 des_.consts[des_.nconsts-1] = obj;
2124 make_const_delays_(obj, net);
2126 return true;
2129 void dll_target::net_probe(const NetEvProbe*net)
2133 void dll_target::scope(const NetScope*net)
2135 ivl_scope_t scope;
2137 if (net->parent() == 0) {
2138 unsigned i;
2139 scope = NULL;
2140 for (i = 0; i < des_.nroots_ && scope == NULL; i++) {
2141 if (strcmp(des_.roots_[i]->name_, net->basename()) == 0)
2142 scope = des_.roots_[i];
2144 assert(scope);
2146 } else {
2147 perm_string sname = make_scope_name(net->fullname());
2148 scope = new struct ivl_scope_s;
2149 scope->name_ = sname;
2150 FILE_NAME(scope, net);
2151 scope->child_ = 0;
2152 scope->sibling_ = 0;
2153 scope->parent = find_scope(des_, net->parent());
2154 assert(scope->parent);
2155 scope->nsigs_ = 0;
2156 scope->sigs_ = 0;
2157 scope->nlog_ = 0;
2158 scope->log_ = 0;
2159 scope->nevent_ = 0;
2160 scope->event_ = 0;
2161 scope->nlpm_ = 0;
2162 scope->lpm_ = 0;
2163 scope->def = 0;
2164 make_scope_parameters(scope, net);
2165 scope->time_precision = net->time_precision();
2166 scope->time_units = net->time_unit();
2167 scope->nattr = net->attr_cnt();
2168 scope->attr = fill_in_attributes(net);
2170 switch (net->type()) {
2171 case NetScope::MODULE:
2172 scope->type_ = IVL_SCT_MODULE;
2173 scope->tname_ = net->module_name();
2174 break;
2175 case NetScope::TASK: {
2176 const NetTaskDef*def = net->task_def();
2177 if (def == 0) {
2178 cerr << "?:?" << ": internal error: "
2179 << "task " << scope->name_
2180 << " has no definition." << endl;
2182 assert(def);
2183 scope->type_ = IVL_SCT_TASK;
2184 scope->tname_ = def->scope()->basename();
2185 break;
2187 case NetScope::FUNC:
2188 scope->type_ = IVL_SCT_FUNCTION;
2189 scope->tname_ = net->func_def()->scope()->basename();
2190 break;
2191 case NetScope::BEGIN_END:
2192 scope->type_ = IVL_SCT_BEGIN;
2193 scope->tname_ = scope->name_;
2194 break;
2195 case NetScope::FORK_JOIN:
2196 scope->type_ = IVL_SCT_FORK;
2197 scope->tname_ = scope->name_;
2198 break;
2199 case NetScope::GENBLOCK:
2200 scope->type_ = IVL_SCT_GENERATE;
2201 scope->tname_ = scope->name_;
2202 break;
2205 assert(scope->parent != 0);
2207 scope->sibling_= scope->parent->child_;
2208 scope->parent->child_ = scope;
2212 void dll_target::signal(const NetNet*net)
2214 ivl_signal_t obj = new struct ivl_signal_s;
2216 obj->name_ = net->name();
2218 /* Attach the signal to the ivl_scope_t object that contains
2219 it. This involves growing the sigs_ array in the scope
2220 object, or creating the sigs_ array if this is the first
2221 signal. */
2222 obj->scope_ = find_scope(des_, net->scope());
2223 obj->file = perm_string::literal("N/A");
2224 obj->lineno = 0;
2225 assert(obj->scope_);
2227 if (obj->scope_->nsigs_ == 0) {
2228 assert(obj->scope_->sigs_ == 0);
2229 obj->scope_->nsigs_ = 1;
2230 obj->scope_->sigs_ = (ivl_signal_t*)malloc(sizeof(ivl_signal_t));
2232 } else {
2233 assert(obj->scope_->sigs_);
2234 obj->scope_->nsigs_ += 1;
2235 obj->scope_->sigs_ = (ivl_signal_t*)
2236 realloc(obj->scope_->sigs_,
2237 obj->scope_->nsigs_*sizeof(ivl_signal_t));
2240 obj->scope_->sigs_[obj->scope_->nsigs_-1] = obj;
2243 /* Save the primitive properties of the signal in the
2244 ivl_signal_t object. */
2246 obj->width_ = net->vector_width();
2247 obj->signed_= net->get_signed()? 1 : 0;
2248 obj->lsb_index = net->lsb();
2249 obj->lsb_dist = net->msb() >= net->lsb() ? 1 : -1;
2250 obj->isint_ = false;
2251 obj->local_ = net->local_flag()? 1 : 0;
2253 obj->array_dimensions_ = net->array_dimensions();
2255 switch (net->port_type()) {
2257 case NetNet::PINPUT:
2258 obj->port_ = IVL_SIP_INPUT;
2259 break;
2261 case NetNet::POUTPUT:
2262 obj->port_ = IVL_SIP_OUTPUT;
2263 break;
2265 case NetNet::PINOUT:
2266 obj->port_ = IVL_SIP_INOUT;
2267 break;
2269 default:
2270 obj->port_ = IVL_SIP_NONE;
2271 break;
2274 switch (net->type()) {
2276 case NetNet::REG:
2277 obj->type_ = IVL_SIT_REG;
2278 obj->isint_ = net->get_isint();
2279 break;
2281 /* The SUPPLY0/1 net types are replaced with pulldown/up
2282 by elaborate. They should not make it here. */
2283 case NetNet::SUPPLY0:
2284 assert(0);
2285 break;
2286 case NetNet::SUPPLY1:
2287 assert(0);
2288 break;
2290 case NetNet::TRI:
2291 case NetNet::WIRE:
2292 case NetNet::IMPLICIT:
2293 obj->type_ = IVL_SIT_TRI;
2294 break;
2296 case NetNet::TRI0:
2297 obj->type_ = IVL_SIT_TRI0;
2298 break;
2300 case NetNet::TRI1:
2301 obj->type_ = IVL_SIT_TRI1;
2302 break;
2304 case NetNet::TRIAND:
2305 case NetNet::WAND:
2306 obj->type_ = IVL_SIT_TRIAND;
2307 break;
2309 case NetNet::TRIOR:
2310 case NetNet::WOR:
2311 obj->type_ = IVL_SIT_TRIOR;
2312 break;
2314 default:
2315 obj->type_ = IVL_SIT_NONE;
2316 break;
2319 /* Initialize the path fields to be filled in later. */
2320 obj->npath = 0;
2321 obj->path = 0;
2323 obj->data_type = net->data_type();
2324 obj->nattr = net->attr_cnt();
2325 obj->attr = fill_in_attributes(net);
2328 /* Get the nexus objects for all the pins of the signal. If
2329 the signal has only one pin, then write the single
2330 ivl_nexus_t object into n.pin_. Otherwise, make an array of
2331 ivl_nexus_t cookies.
2333 When I create an ivl_nexus_t object, store it in the
2334 t_cookie of the Nexus object so that I find it again when I
2335 next encounter the nexus. */
2337 obj->array_base = net->array_first();
2338 obj->array_words = net->array_count();
2339 if (obj->array_words > 1)
2340 obj->pins = new ivl_nexus_t[obj->array_words];
2342 for (unsigned idx = 0 ; idx < obj->array_words ; idx += 1) {
2344 const Nexus*nex = net->pin(idx).nexus();
2345 if (nex->t_cookie()) {
2346 if (obj->array_words > 1) {
2347 obj->pins[idx] = nex->t_cookie();
2348 nexus_sig_add(obj->pins[idx], obj, idx);
2349 } else {
2350 obj->pin = nex->t_cookie();
2351 nexus_sig_add(obj->pin, obj, idx);
2353 } else {
2354 ivl_nexus_t tmp = nexus_sig_make(obj, idx);
2355 tmp->nexus_ = nex;
2356 tmp->name_ = 0;
2357 nex->t_cookie(tmp);
2358 if (obj->array_words > 1)
2359 obj->pins[idx] = tmp;
2360 else
2361 obj->pin = tmp;
2366 bool dll_target::signal_paths(const NetNet*net)
2368 /* Nothing to do if there are no paths for this signal. */
2369 if (net->delay_paths() == 0)
2370 return true;
2372 ivl_signal_t obj = find_signal(des_, net);
2373 assert(obj);
2375 /* We cannot have already set up the paths for this signal. */
2376 assert(obj->npath == 0);
2377 assert(obj->path == 0);
2379 /* Figure out how many paths there really are. */
2380 for (unsigned idx = 0 ; idx < net->delay_paths() ; idx += 1) {
2381 const NetDelaySrc*src = net->delay_path(idx);
2382 obj->npath += src->src_count();
2385 obj->path = new struct ivl_delaypath_s[obj->npath];
2387 unsigned ptr = 0;
2388 for (unsigned idx = 0 ; idx < net->delay_paths() ; idx += 1) {
2389 const NetDelaySrc*src = net->delay_path(idx);
2391 /* If this path has a condition, then hook it up. */
2392 ivl_nexus_t path_condit = 0;
2393 if (src->has_condit()) {
2394 const Nexus*nt = src->condit_pin().nexus();
2395 path_condit = nt->t_cookie();
2398 for (unsigned pin = 0; pin < src->src_count(); pin += 1) {
2399 const Nexus*nex = src->src_pin(pin).nexus();
2400 if (! nex->t_cookie()) {
2401 cerr << src->get_fileline() << ": internal error: "
2402 << "No signal connected to pin " << pin
2403 << " of delay path to " << net->name()
2404 << "." << endl;
2406 assert(nex->t_cookie());
2407 obj->path[ptr].scope = lookup_scope_(src->scope());
2408 obj->path[ptr].src = nex->t_cookie();
2409 obj->path[ptr].condit = path_condit;
2410 obj->path[ptr].conditional = src->is_condit();
2411 obj->path[ptr].posedge = src->is_posedge();
2412 obj->path[ptr].negedge = src->is_negedge();
2413 for (unsigned pe = 0 ; pe < 12 ; pe += 1) {
2414 obj->path[ptr].delay[pe] = src->get_delay(pe);
2417 ptr += 1;
2422 return true;
2425 extern const struct target tgt_dll = { "dll", &dll_target_obj };