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