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