our
@ISA
=
'Mpp::Scanner'
;
sub
new {
my
$self
=
&Mpp::Scanner::new
;
$self
->{MODULE_MAP}={};
$self
->{RESOLVED}={};
$self
->{UNRESOLVED}={};
$self
->{MODULE}=
undef
;
$self
;
}
sub
info_string {
die
"info_string doesn't work with Mpp::Scanner::Verilog"
;
}
*dont_scan
= \
&Mpp::Text::CONST0
;
sub
resolve_module {
my
(
$self
,
$cp
,
$module
,
$finfo
,
$visited
) =
@_
;
$visited
||= {};
return
1
if
$self
->{RESOLVED}{
$module
};
my
$map
=
$self
->{MODULE_MAP}{
$module
};
if
(
$map
) {
my
(
$nfinfo
,
@map
)=
@$map
;
for
(
@map
) {
if
(
$visited
->{
$_
}) {
warn
"module $_ contains itself\n"
;
}
else
{
my
$v
={
%$visited
};
$v
->{
$_
}=1;
$self
->resolve_module(
$cp
,
$_
,
$nfinfo
,
$v
)
or
return
undef
;
}
}
}
else
{
$self
->include(
$cp
,
"vlog"
,
$module
,
$finfo
) or
return
undef
;
}
$self
->{RESOLVED}{
$module
}=1;
return
1;
}
sub
resolve {
my
(
$self
,
$cp
) =
@_
;
while
(
my
@keys
=
keys
%{
$self
->{UNRESOLVED}}) {
my
$key
=
shift
(
@keys
);
$self
->resolve_module(
$cp
,
$key
,
$self
->{UNRESOLVED}{
$key
})
or
return
undef
;
delete
$self
->{UNRESOLVED}{
$key
};
}
1;
}
my
@primitives
=
qw{
and always assign attribute begin buf bufif0 bufif1 case cmos deassign
default defparam disable else endattribute end endtable endtask event
for force forever fork function highz0 highz1 if initial inout input
integer join large medium nand negedge nor not notif0 notif1 nmos or
output parameter pmos posedge pulldown pullup pull0 pull1 rcmos reg release
repeat rnmos rpmos rtran rtranif0 rtranif1 scalared small specify specparam
strong0 strong1 supply0 supply1 table task tran tranif0 tranif1 time
tri triand trior trireg tri0 tri1 vertored wait wand weak0 weak1 while
wire wor xor xnor
}
;
my
%is_prim
;
@is_prim
{
@primitives
} = (1..
@primitives
);
sub
scan_comment {
return
1;
}
sub
xscan_line
{
my
(
$self
,
@scan_Ctx
) =
@_
;
my
(
undef
,
undef
,
$finfo
,
undef
,
$fh
) =
@scan_Ctx
;
my
$state
=
$finfo
->{
"Mpp::Scanner::Verilog state"
} ||= {};
local
$_
= <
$fh
>;
return
unless
defined
;
if
(
$state
->{in_comment})
{
if
(s@^(.*?)\*/@@) {
$self
->scan_comment($1,
@scan_Ctx
) or
return
[];
$state
->{in_comment} = 0;
}
else
{
$self
->scan_comment(
$_
,
@scan_Ctx
) or
return
[];
return
""
;
}
}
while
(s@//(.*)@@)
{
my
$line_comment
= $1;
while
(s@/\*(.*?)\*/@@) {
$self
->scan_comment($1,
@scan_Ctx
) or
return
[];
}
if
(s@/\*(.*)@@) {
my
$block_comment
= $1;
if
(
$line_comment
=~ s@^(.*?)\*/@@)
{
$self
->scan_comment(
$block_comment
.
"//"
. $1,
@scan_Ctx
) or
return
[];
$_
.=
$line_comment
;
}
else
{
$self
->scan_comment(
$block_comment
.
"//"
.
$line_comment
,
@scan_Ctx
) or
return
[];
$state
->{in_comment} = 1;
}
}
else
{
$self
->scan_comment(
$line_comment
,
@scan_Ctx
) or
return
[];
}
}
for
my
$comment
(s@/\*(.*?)\*/@
@g
) {
$self
->scan_comment(
$comment
,
@scan_Ctx
) or
return
[];
}
if
(s@/\*(.*)@@) {
$self
->scan_comment($1,
@scan_Ctx
) or
return
[];
$state
->{in_comment} = 1;
}
return
$_
;
}
sub
xscan_file {
my
(
$self
,
@scan_Ctx
) =
@_
;
my
(
$cp
,
$tag
,
$finfo
,
$conditional
,
$fh
) =
@scan_Ctx
;
my
$absname
= absolute_filename
$finfo
;
my
$module
=
$self
->{MODULE};
my
$pend_module
;
my
$pend_imodule
;
local
$_
;
while
(
defined
(
$_
=
$self
->xscan_line(
@scan_Ctx
)) )
{
if
(
ref
$_
) {
return
undef
;
}
my
$directive
;
if
(s/^\s*\`\s*(\w+)\s+//) {
$directive
=$1;
if
(
$directive
eq
"include"
&& /^\
"([^"
]*)\"/) {
$self
->include(
$cp
,
"vinc"
, $1,
$finfo
)
or
return
;
}
elsif
(
$conditional
) {
if
(
$directive
eq
"define"
&&
/^(\w+)\s*(.*?)\s*$/
) {
$self
->set_var($1, $2);
}
elsif
(
$directive
eq
"undef"
&&
/^(\w+)\s*$/
) {
$self
->set_var($1,
undef
);
}
elsif
(
$directive
=~/^
if
(n)?def$/ &&
/^(\w+)\s*$/
) {
my
$def
=(
defined
$self
->get_var($1));
my
$no
=(
$directive
eq
"ifndef"
);
$self
->push_scope(
$no
? !
$def
:
$def
);
}
elsif
(
$directive
eq
"else"
) {
$self
->push_scope(!
$self
->pop_scope);
}
elsif
(
$directive
eq
"endif"
) {
$self
->pop_scope();
}
}
}
elsif
(
$self
->is_active) {
my
$pend_module_next
;
my
$pend_imodule_next
;
my
$imodule
;
if
(/^\s*(?:module|primitive)\s+(\w+|\\\S+)/
or (
$pend_module
and /^\s*(\w+|\\\S+)/)
) {
warn
"no closing endmodule for module $module in `$absname:$.'\n"
if
$module
;
$module
=$1;
$self
->{MODULE} =
$module
if
$conditional
;
my
$map
=
$self
->{MODULE_MAP};
if
(
$map
->{
$module
}) {
my
$n2
= absolute_filename
$map
->{
$module
}[0];
warn
"module $module multiply defined in `$absname' and `$n2'\n"
;
}
$map
->{
$module
}=[
$finfo
];
}
elsif
(m!^\s
*end
(?:module|primitive)\s*$!) {
undef
$module
;
$self
->{MODULE} =
undef
if
$conditional
;
}
elsif
(
(
$imodule
) = /^\s*(\w+|\\\S+)(?:\s+\
(
$imodule
=
$pend_imodule
and /^\s*\(/)
) {
if
(
$is_prim
{
$imodule
}) {
}
elsif
(
$module
) {
push
(@{
$self
->{MODULE_MAP}{
$module
}},
$imodule
);
$self
->{UNRESOLVED}{
$imodule
}=
$finfo
unless
$tag
eq
"vlib"
||
$self
->{RESOLVED}{
$imodule
};
}
else
{
warn
"instance of $imodule not enclosed in a module in `$absname:$.'\n"
;
}
}
elsif
(/^\s*(\w+|\\\S+)(?:\s+\
$pend_imodule_next
= $1;
}
elsif
(/^\s*(?:module|primitive)\s*$/) {
$pend_module_next
= 1;
}
elsif
(/^\s*$/) {
$pend_module_next
=
$pend_module
;
$pend_imodule_next
=
$pend_imodule
;
}
$pend_module
=
$pend_module_next
;
$pend_imodule
=
$pend_imodule_next
;
}
}
warn
"no closing endmodule for module $module in `$absname'\n"
if
$module
&&
$tag
ne
"vinc"
;
1;
}
1;