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