1 |
117 |
jt_eaton |
eval 'exec `which perl` -S $0 ${1+"$@"}'
|
2 |
|
|
if 0;
|
3 |
|
|
# This file is part of fizzim
|
4 |
|
|
# Copyright (C) 2007 Zimmer Design Services
|
5 |
|
|
# Copyright (C) 2008 Zimmer Design Services
|
6 |
|
|
# Copyright (C) 2009 Zimmer Design Services
|
7 |
|
|
# Copyright (C) 2010 Zimmer Design Services
|
8 |
|
|
#
|
9 |
|
|
# This program is free software: you can redistribute it and/or modify
|
10 |
|
|
# it under the terms of the GNU General Public License as published by
|
11 |
|
|
# the Free Software Foundation, either version 3 of the License, or
|
12 |
|
|
# (at your option) any later version.
|
13 |
|
|
#
|
14 |
|
|
# This program is distributed in the hope that it will be useful,
|
15 |
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16 |
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17 |
|
|
# GNU General Public License for more details.
|
18 |
|
|
#
|
19 |
|
|
# You should have received a copy of the GNU General Public License
|
20 |
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
21 |
|
|
#
|
22 |
|
|
|
23 |
|
|
# Although not specifically required by GPL, if you improve/modify this
|
24 |
|
|
# software, please make it available to other users either by posting
|
25 |
|
|
# it yourself or sending it back to ZDS (paulzimmer@zimmerdesignservices.com)
|
26 |
|
|
# Consider this an ethical obligation rather than a legal one.
|
27 |
|
|
#
|
28 |
|
|
# $Id: fizzim.pl,v 4.41 2011/09/25 21:01:55 pzimmer Exp $
|
29 |
|
|
|
30 |
|
|
$| = 1; # force immediate output
|
31 |
|
|
|
32 |
|
|
# Make sure calling location is in INC path
|
33 |
|
|
use File::Basename;
|
34 |
|
|
$my_dir = &dirname($0);
|
35 |
|
|
$me = &basename($0);
|
36 |
|
|
unshift(@INC,"$my_dir");
|
37 |
|
|
|
38 |
|
|
# Figure out revision info
|
39 |
|
|
# The reference to Revision below will get RCS to input the revision
|
40 |
|
|
$scriptversion = '$Revision: 4.41 $';
|
41 |
|
|
# Extract the rev number
|
42 |
|
|
$scriptversion =~ s/^\$Revision: //;
|
43 |
|
|
$scriptversion =~ s/ \$//;
|
44 |
|
|
|
45 |
|
|
# Scan for -help and -version for early exit. If found, call parser
|
46 |
|
|
if (join(" ",@ARGV) =~ /-h/) {
|
47 |
|
|
&process_options;
|
48 |
|
|
exit; # redundant - will exit anyway
|
49 |
|
|
}
|
50 |
|
|
if (join(" ",@ARGV) =~ /-vers/) {
|
51 |
|
|
&process_options;
|
52 |
|
|
exit; # redundant - will exit anyway
|
53 |
|
|
} elsif (join(" ",@ARGV) =~ /-v(\s|$)/) {
|
54 |
|
|
print STDERR "Note that -v is ambiguous. If you want version, you must use at least -vers \n";
|
55 |
|
|
}
|
56 |
|
|
|
57 |
|
|
# Scan for -debug be_cmd before calling process_options
|
58 |
|
|
$debug_sections{"be_cmd"} = (join(" ",@ARGV) =~ /-d\S*\s+be_cmd/);
|
59 |
|
|
# Scan for -debug parse_input before calling parser
|
60 |
|
|
$debug_sections{"parse_input"} = (join(" ",@ARGV) =~ /-d\S*\s+parse_input/);
|
61 |
|
|
|
62 |
|
|
# Need to fetch the be_cmd from the file before parsing inputs.
|
63 |
|
|
# Call the option processing now to clear out options and leave only the
|
64 |
|
|
# file name. This makes "fizzim.pl foo.fzm" work as well as
|
65 |
|
|
# "fizzim.pl < foo.fzm".
|
66 |
|
|
# Then we can parse the file, add the be_cmd options, and
|
67 |
|
|
# parse again.
|
68 |
|
|
@orig_argv = @ARGV;
|
69 |
|
|
&process_options;
|
70 |
|
|
|
71 |
|
|
# Parse the input. Do this before option processing so that we can get
|
72 |
|
|
# be_cmd.
|
73 |
|
|
&set_myattributes; # sets the myattributes hash to know what to parse
|
74 |
|
|
&parse_input;
|
75 |
|
|
|
76 |
|
|
# Process command-line options
|
77 |
|
|
# Re-build @ARGV using the options from be_cmd FIRST (so actual command-line
|
78 |
|
|
# options will have priority)
|
79 |
|
|
($be_options = $globals{machine}{be_cmd}{value}) =~ s/^[^-]*//;
|
80 |
|
|
@ARGV = (split(/\s+/,$be_options),@orig_argv);
|
81 |
|
|
|
82 |
|
|
&process_options;
|
83 |
|
|
|
84 |
|
|
# check for minversion
|
85 |
|
|
if ($minversion && ($scriptversion < $minversion)) {
|
86 |
|
|
&error(0,"Version $scriptversion is less than required minversion $minversion");
|
87 |
|
|
}
|
88 |
|
|
|
89 |
|
|
# If -inst is set, create the instance and exit
|
90 |
|
|
if ($inst) {
|
91 |
|
|
foreach $output ((keys %reg_outputs),(keys %comb_outputs)) {
|
92 |
|
|
push(@lines,"${indent}.${output} (${output}),\n");
|
93 |
|
|
}
|
94 |
|
|
#$lines($#lines) =~ s/,//;
|
95 |
|
|
print @lines;
|
96 |
|
|
}
|
97 |
|
|
|
98 |
|
|
#print "is_stateline: " . &is_stateline(" state[S1_BIT]: if (in[0] && in[1])"). "\n"; exit;
|
99 |
|
|
|
100 |
|
|
# Output is a bit messy. To allow for -terse, output is held in a buffer
|
101 |
|
|
# (pbuf) and printed at the end. Warnings and "assertions" are held in their
|
102 |
|
|
# own arrays, with indexes to match the line they follow in pbuf.
|
103 |
|
|
# "assertions" are comment lines, other than warnings, to be added to the
|
104 |
|
|
# output.
|
105 |
|
|
# Init printbuffer
|
106 |
|
|
$pbuf[0] = "";
|
107 |
|
|
|
108 |
|
|
# Rename hashes
|
109 |
|
|
%states = %state; undef %state;
|
110 |
|
|
%transitions = %transition; undef %transition;
|
111 |
|
|
|
112 |
|
|
|
113 |
|
|
# Massage output data structures to more convenient ones.
|
114 |
|
|
foreach $output (sort keys %{ $globals{outputs} }) {
|
115 |
|
|
if ($globals{outputs}{$output}{type} eq "comb") {
|
116 |
|
|
if (exists $globals{"trans"}{$att}{"value"} && ($globals{"trans"}{$att}{"value"} ne "")) {
|
117 |
|
|
$comb_outputs{$output}{"default_value"} = $globals{"trans"}{$att}{"value"} ; # default value defined in transitions table (old gui did this)
|
118 |
|
|
} else {
|
119 |
|
|
$comb_outputs{$output}{"default_value"} = $globals{outputs}{$output}{value};
|
120 |
|
|
}
|
121 |
|
|
#print "debug: comb default: $comb_outputs{$output}{default_value}\n";
|
122 |
|
|
foreach $trans (keys %transitions) {
|
123 |
|
|
if (exists $transitions{$trans}{attributes}{$output}{value} && ($transitions{$trans}{attributes}{$output}{value} ne "")
|
124 |
|
|
&& ($comb_outputs{$output}{"default_value"} ne $transitions{$trans}{attributes}{$output}{value})
|
125 |
|
|
) {
|
126 |
|
|
#print "debug: in mot due to $output on transition $trans\n";
|
127 |
|
|
$in_mealy_on_transitions_mode = 1;
|
128 |
|
|
}
|
129 |
|
|
}
|
130 |
|
|
} elsif ($globals{outputs}{$output}{type} eq "reg") {
|
131 |
|
|
#print "Setting reg $output\n";
|
132 |
|
|
if ($encoding eq "onehot") {
|
133 |
|
|
# For onehot, all reg's are effectively regdp's
|
134 |
|
|
$regdp_outputs{$output}{"default_value"} = $globals{outputs}{$output}{value};
|
135 |
|
|
} else {
|
136 |
|
|
$reg_outputs{$output}{"default_value"} = &convert2bin($globals{outputs}{$output}{value},1);
|
137 |
|
|
}
|
138 |
|
|
} elsif ($globals{outputs}{$output}{type} eq "regdp") {
|
139 |
|
|
$regdp_outputs{$output}{"default_value"} = $globals{outputs}{$output}{value};
|
140 |
|
|
} elsif ($globals{outputs}{$output}{type} eq "flag") {
|
141 |
|
|
# no defaults for flags, but create the flags array
|
142 |
|
|
$flags{$output} = 1;
|
143 |
|
|
$flag_outputs{$output}{"default_value"} = $globals{outputs}{$output}{value};
|
144 |
|
|
#print "debug: flag default: $flag_outputs{$output}{default_value}\n";
|
145 |
|
|
foreach $trans (keys %transitions) {
|
146 |
|
|
if (exists $transitions{$trans}{attributes}{$output}{value} && ($transitions{$trans}{attributes}{$output}{value} ne "")
|
147 |
|
|
&& ($flag_outputs{$output}{"default_value"} ne $transitions{$trans}{attributes}{$output}{value})
|
148 |
|
|
) {
|
149 |
|
|
#print "debug: in mot due to $output on transition $trans\n";
|
150 |
|
|
$in_flag_on_transitions_mode = 1;
|
151 |
|
|
}
|
152 |
|
|
}
|
153 |
|
|
} else {
|
154 |
|
|
&error($indent,"No type found for output $output");
|
155 |
|
|
}
|
156 |
|
|
# Keep track of max output length for formatting
|
157 |
|
|
if (length($output) > $max_output_length) {
|
158 |
|
|
$max_output_length = length($output);
|
159 |
|
|
}
|
160 |
|
|
}
|
161 |
|
|
|
162 |
|
|
foreach $input (sort keys %{ $globals{inputs} }) {
|
163 |
|
|
# Keep track of max input length for formatting
|
164 |
|
|
if (length($input) > $max_input_length) {
|
165 |
|
|
$max_input_length = length($input);
|
166 |
|
|
}
|
167 |
|
|
}
|
168 |
|
|
|
169 |
|
|
# Figure max i/o length for formatting
|
170 |
|
|
if ($max_output_length > $max_input_length) {
|
171 |
|
|
$max_io_length = $max_output_length;
|
172 |
|
|
} else {
|
173 |
|
|
$max_io_length = $max_input_length;
|
174 |
|
|
}
|
175 |
|
|
$io_statement_length = $max_io_length + length("output logic , ");
|
176 |
|
|
|
177 |
|
|
# Search for parameters
|
178 |
|
|
foreach $attname (sort keys %{ $globals{machine} }) {
|
179 |
|
|
if ($globals{machine}{$attname}{type} eq "parameter") {
|
180 |
|
|
$parameters{$attname} = $globals{machine}{$attname}{value};
|
181 |
|
|
}
|
182 |
|
|
}
|
183 |
|
|
#foreach $param (sort keys %parameters) {
|
184 |
|
|
# print "$param : $parameters{$param}\n";
|
185 |
|
|
#}
|
186 |
|
|
|
187 |
|
|
# Determine undefined_states info
|
188 |
|
|
$use_undefined_goto_state = 0; # default off
|
189 |
|
|
$undefined_goto_state = ""; # default off
|
190 |
|
|
if ($globals{machine}{undefined_states_go_to}{value}) {
|
191 |
|
|
$undefined_goto_state = $globals{machine}{undefined_states_go_to}{value};
|
192 |
|
|
$use_undefined_goto_state = 1; # might get switched off - see below
|
193 |
|
|
} else {
|
194 |
|
|
foreach $state (keys %states) {
|
195 |
|
|
if ($states{$state}{attributes}{undefined_states_go_here}{value}) {
|
196 |
|
|
if ($undefined_goto_state) { # already defined!
|
197 |
|
|
&error($indent,"Attribute undefined_states_go_here set on more than one state ($undefined_goto_state and $state)");
|
198 |
|
|
} else {
|
199 |
|
|
$undefined_goto_state = $state;
|
200 |
|
|
$use_undefined_goto_state = 1; # might get switched off - see below
|
201 |
|
|
}
|
202 |
|
|
}
|
203 |
|
|
}
|
204 |
|
|
}
|
205 |
|
|
|
206 |
|
|
|
207 |
|
|
# Encodings:
|
208 |
|
|
# HEROS:
|
209 |
|
|
# Highly Encoded with Registered Outputs as Statebits
|
210 |
|
|
# All registered outputs will be encoded as state bits. Additional
|
211 |
|
|
# statebits will be added as needed to meet other requirements
|
212 |
|
|
# (mininum encoding, graycode transitions).
|
213 |
|
|
#
|
214 |
|
|
# onehot:
|
215 |
|
|
# One-hot encoding per Steve Golson. All reg'd outputs are effectively
|
216 |
|
|
# regdp's.
|
217 |
|
|
#
|
218 |
|
|
# Encoding cannot easily be an attribute on the fsm, because we need to know
|
219 |
|
|
# the encoding before we parse...
|
220 |
|
|
|
221 |
|
|
#######################
|
222 |
|
|
# State assignment
|
223 |
|
|
#######################
|
224 |
|
|
$section = "assign_states"; # for debug
|
225 |
|
|
|
226 |
|
|
# allstates is an array of all the states in alpha order, but with the
|
227 |
|
|
# reset state moved to the front (FIRST)
|
228 |
|
|
if (exists $globals{machine}{reset_state}{value}) {
|
229 |
|
|
$reset_state = $globals{machine}{reset_state}{value};
|
230 |
|
|
push(@allstates,$reset_state);
|
231 |
|
|
} else {
|
232 |
|
|
# If no reset, warn user
|
233 |
|
|
&warning($indent,"No reset specified");
|
234 |
|
|
}
|
235 |
|
|
foreach $state (sort keys %states) {
|
236 |
|
|
unless ($state eq $reset_state) {
|
237 |
|
|
push(@allstates,$state);
|
238 |
|
|
}
|
239 |
|
|
}
|
240 |
|
|
&debug("allstates is @allstates\n",0,"assign_states");
|
241 |
|
|
|
242 |
|
|
if ($encoding eq "heros") {
|
243 |
|
|
# Massage the data structures before calling assign_states
|
244 |
|
|
# Look at all registered outputs and assign them to state bits.
|
245 |
|
|
|
246 |
|
|
@outputs2check = (keys %reg_outputs);
|
247 |
|
|
|
248 |
|
|
# While doing this, check check to see if any comb outputs are actually
|
249 |
|
|
# constants in all states. If so, convert them to reg type.
|
250 |
|
|
# Don't do this is there are any gray coded transitions.
|
251 |
|
|
if ($comb2reg) {
|
252 |
|
|
foreach $trans (keys %transitions) {
|
253 |
|
|
if ($transitions{$trans}{attributes}{graycode}{value} || $transitions{$trans}{attributes}{graytransition}{value}) {
|
254 |
|
|
$design_has_graycodes = 1; last;
|
255 |
|
|
}
|
256 |
|
|
}
|
257 |
|
|
|
258 |
|
|
if (!$design_has_graycodes) {
|
259 |
|
|
push(@outputs2check,keys %comb_outputs)
|
260 |
|
|
}
|
261 |
|
|
}
|
262 |
|
|
|
263 |
|
|
$statebit = 0; # init statebit pointer
|
264 |
|
|
# Loop through all reg'd outputs
|
265 |
|
|
OUTPUT: foreach $output (sort @outputs2check) {
|
266 |
|
|
# Set flag for comb outputs
|
267 |
|
|
if ($globals{outputs}{$output}{type} eq "comb") {
|
268 |
|
|
$is_comb = 1;
|
269 |
|
|
} else {
|
270 |
|
|
$is_comb = 0;
|
271 |
|
|
}
|
272 |
|
|
&debug("Working on $output : is_comb is $is_comb",0,"$section");
|
273 |
|
|
# Determine upper and lower parts of [upper:lower]
|
274 |
|
|
if (($upper,$lower) = ($output =~ /\[(\d+):(\d+)\]/)) {
|
275 |
|
|
$reg_outputs{$output}{"range"} = "$upper:$lower";
|
276 |
|
|
} else {
|
277 |
|
|
# If no range match, this must be single bit
|
278 |
|
|
$upper = 0; $lower = 0;
|
279 |
|
|
}
|
280 |
|
|
# Set the lower (where the range will start to the current pointer)
|
281 |
|
|
$statebit_lower = $statebit;
|
282 |
|
|
# Bump the pointer up until we reach $upper
|
283 |
|
|
for (my $bit = $lower; $bit < $upper; $bit++) {
|
284 |
|
|
$statebit++;
|
285 |
|
|
}
|
286 |
|
|
# Set %fixedbits on all states to show these bits as fixed
|
287 |
|
|
foreach $state (keys %states) {
|
288 |
|
|
if ((!exists $states{$state}{attributes}{$output}{value}) || ($states{$state}{attributes}{$output}{value} eq "")) {
|
289 |
|
|
$value = $reg_outputs{$output}{"default_value"};
|
290 |
|
|
if ($value eq "") {
|
291 |
|
|
&error($indent,"No value for reg output $output in state $state and no default value set");
|
292 |
|
|
} else {
|
293 |
|
|
&debug("// Warning: No value for Moore bit $output for state $state - using default $value",0,"$section") if (!$is_comb);
|
294 |
|
|
}
|
295 |
|
|
} else {
|
296 |
|
|
$value = &convert2bin($states{$state}{attributes}{$output}{value},0);
|
297 |
|
|
#print "$states{$state}{attributes}{$output}{value} became $value\n"; # temp
|
298 |
|
|
}
|
299 |
|
|
# Make sure it is a legal binary value and the correct size
|
300 |
|
|
if ($value !~ /^[01]+$/) {
|
301 |
|
|
if ($is_comb) {
|
302 |
|
|
&debug("Bailed out on converting $output from comb to reg because it could not be converted to binary",0,"$section");
|
303 |
|
|
next OUTPUT;
|
304 |
|
|
} else {
|
305 |
|
|
&error($indent,"Value \"$states{$state}{attributes}{$output}{value}\" of output $output for state $state is not a legal binary number after conversion to \"$value\"");
|
306 |
|
|
}
|
307 |
|
|
}
|
308 |
|
|
# Checking the bit width make it impossible to use 'h0f (tic without size)
|
309 |
|
|
if (length($value) != $upper - $lower + 1) {
|
310 |
|
|
&error($indent,"Value $value of output $output for state $state is not the correct bit width") if (!$is_comb);
|
311 |
|
|
}
|
312 |
|
|
$target_valuebit = 0;
|
313 |
|
|
for ($target_statebit = $statebit; $target_statebit >= $statebit_lower; $target_statebit--) {
|
314 |
|
|
$bitvalue = substr($value,$target_valuebit,1);
|
315 |
|
|
if ($bitvalue eq "") {
|
316 |
|
|
if ($is_comb) {
|
317 |
|
|
&debug("Bailed out on converting $output from comb to reg because value had fewer bits than required",0,"$section");
|
318 |
|
|
next OUTPUT;
|
319 |
|
|
} else {
|
320 |
|
|
&error($indent,"Value of output $output in state $state has fewer bits than required\n");
|
321 |
|
|
}
|
322 |
|
|
}
|
323 |
|
|
&debug("Setting fixedbit $target_statebit to $bitvalue for output $output in state $state",0,"$section");
|
324 |
|
|
$fixedbits{$state}{$target_statebit} = $bitvalue;
|
325 |
|
|
$target_valuebit++;
|
326 |
|
|
}
|
327 |
|
|
}
|
328 |
|
|
if ($is_comb) {
|
329 |
|
|
&debug("Converted $output from comb to reg",0,"$section");
|
330 |
|
|
$globals{outputs}{$output}{type} = "reg";
|
331 |
|
|
$reg_outputs{$output}{"default_value"} = $comb_outputs{$output}{"default_value"};
|
332 |
|
|
delete $comb_outputs{$output};
|
333 |
|
|
}
|
334 |
|
|
|
335 |
|
|
if ($statebit == $statebit_lower) { # single bit
|
336 |
|
|
$reg_outputs{$output}{"statebit_range"} = $statebit;
|
337 |
|
|
&debug("Assigned $output to statebits $reg_outputs{$output}{statebit_range}",0,"$section");
|
338 |
|
|
} else {
|
339 |
|
|
$reg_outputs{$output}{"statebit_range"} = "$statebit:$statebit_lower";
|
340 |
|
|
&debug("Assigned $output to statebits $reg_outputs{$output}{statebit_range}",0,"$section");
|
341 |
|
|
}
|
342 |
|
|
$reg_outputs{$output}{"statebit_lower"} = $statebit_lower;
|
343 |
|
|
$reg_outputs{$output}{"statebit_upper"} = $statebit;
|
344 |
|
|
$statebit++;
|
345 |
|
|
|
346 |
|
|
}
|
347 |
|
|
$regbits = $statebit;
|
348 |
|
|
|
349 |
|
|
# Create graytransitions hash
|
350 |
|
|
foreach $trans (keys %transitions) {
|
351 |
|
|
if ($transitions{$trans}{attributes}{graycode}{value} || $transitions{$trans}{attributes}{graytransition}{value}) {
|
352 |
|
|
&debug("Setting transition $trans as gray",0,"$section");
|
353 |
|
|
push( @{ $graytransitions{"$transitions{$trans}{startState}"} },$transitions{$trans}{endState});
|
354 |
|
|
$design_has_graycodes = 1;
|
355 |
|
|
}
|
356 |
|
|
}
|
357 |
|
|
|
358 |
|
|
# Calculate limits of state assignment search
|
359 |
|
|
$required_bits = &required_bits($#allstates + 1);
|
360 |
|
|
$minbits = $required_bits;
|
361 |
|
|
# regbits is the number of fixed bits used
|
362 |
|
|
$minbits = $regbits if ($regbits > $minbits);
|
363 |
|
|
foreach ($statebit = 0; $statebit <= $regbits-1 ; $statebit++) {
|
364 |
|
|
$num0fixbits = 0;
|
365 |
|
|
$num1fixbits = 0;
|
366 |
|
|
foreach $state (@allstates) {
|
367 |
|
|
if ($fixedbits{$state}{$statebit} == 0) {
|
368 |
|
|
$num0fixbits++;
|
369 |
|
|
}
|
370 |
|
|
if ($fixedbits{$state}{$statebit} == 1) {
|
371 |
|
|
$num1fixbits++;
|
372 |
|
|
}
|
373 |
|
|
}
|
374 |
|
|
#print "num0fixbits for statebit $statebit is $num0fixbits\n";
|
375 |
|
|
#print "num1fixbits for statebit $statebit is $num1fixbits\n";
|
376 |
|
|
# Make sure we have enough bits to handle this fixbit value. If there are 13 0's, for example, we would need to make
|
377 |
|
|
# sure minbits is at least 5 (4 bits would only allow 16 0 values).
|
378 |
|
|
while ( ((2**$minbits)/2 < $num0fixbits) || ((2**$minbits)/2 < $num1fixbits)) {
|
379 |
|
|
$minbits++;
|
380 |
|
|
}
|
381 |
|
|
}
|
382 |
|
|
$minbits = $userminbits if ($userminbits); # option override
|
383 |
|
|
|
384 |
|
|
$maxbits = $required_bits + $regbits;
|
385 |
|
|
# Bump maxbits in the presence of graycodes
|
386 |
|
|
$maxbits = $maxbits + 2 if (scalar(keys %graytransitions));
|
387 |
|
|
|
388 |
|
|
$maxbits = $usermaxbits if ($usermaxbits); # option override
|
389 |
|
|
&debug("minbits is $minbits, maxbits is $maxbits",0,"assign_states");
|
390 |
|
|
|
391 |
|
|
# Force reset state to be allones or allzeros if requested by setting
|
392 |
|
|
# fixbits values.
|
393 |
|
|
if (exists $globals{machine}{reset_state}{value}) {
|
394 |
|
|
$reset_state = $globals{machine}{reset_state}{value};
|
395 |
|
|
if ($globals{machine}{reset_state}{type} eq "allzeros") {
|
396 |
|
|
for ($bit = 0; $bit <= $maxbits - 1 ; $bit++) {
|
397 |
|
|
# If there is a comflicting fixedbits setting from registered
|
398 |
|
|
# outputs, error out.
|
399 |
|
|
if ((exists $fixedbits{$reset_state}{$bit}) && $fixedbits{$reset_state}{$bit} == 1) {
|
400 |
|
|
&error($indent,"allzeros constraint for reset state $reset_state is incompatible with output setting");
|
401 |
|
|
}
|
402 |
|
|
$fixedbits{$reset_state}{$bit} = 0;
|
403 |
|
|
&debug("Setting fixedbit $bit to 0 for reset state $reset_state",0,"$section");
|
404 |
|
|
}
|
405 |
|
|
} elsif ($globals{machine}{reset_state}{type} eq "allones") {
|
406 |
|
|
for ($bit = 0; $bit <= $maxbits - 1 ; $bit++) {
|
407 |
|
|
# If there is a comflicting fixedbits setting from registered
|
408 |
|
|
# outputs, error out.
|
409 |
|
|
if ((exists $fixedbits{$reset_state}{$bit}) && $fixedbits{$reset_state}{$bit} == 0) {
|
410 |
|
|
&error($indent,"allones constraint for bit $bit of reset state $reset_state is incompatible with output setting");
|
411 |
|
|
}
|
412 |
|
|
$fixedbits{$reset_state}{$bit} = 1;
|
413 |
|
|
&debug("Setting fixedbit $bit to 1 for reset state $reset_state",0,"$section");
|
414 |
|
|
}
|
415 |
|
|
}
|
416 |
|
|
}
|
417 |
|
|
|
418 |
|
|
# Debug output prior to calling &assign_states
|
419 |
|
|
if ($global_debug || $debug_sections{"$section"}) {
|
420 |
|
|
foreach $state (@allstates) {
|
421 |
|
|
for ($statebit = 0; $statebit < $regbits; $statebit++) {
|
422 |
|
|
if (exists $fixedbits{$state}{$statebit}) {
|
423 |
|
|
&debug("fixedbits{$state}{$statebit} is $fixedbits{$state}{$statebit}",0,"$section");
|
424 |
|
|
}
|
425 |
|
|
}
|
426 |
|
|
}
|
427 |
|
|
&debug("regbits is $regbits",0,"$section");
|
428 |
|
|
foreach $trans (keys %graytransitions) {
|
429 |
|
|
&debug("graytransitions{$trans} is @{ $graytransitions{$trans} }",0,"$section");
|
430 |
|
|
}
|
431 |
|
|
}
|
432 |
|
|
|
433 |
|
|
# If undefined_states_go_to is set:
|
434 |
|
|
# 1) Check to see if there are not transitions into this state, and that
|
435 |
|
|
# it is not the reset state.
|
436 |
|
|
# 2) If not, check to try state assignment without this state.
|
437 |
|
|
# 3) If this assignment is "full", drop the uknown_states_go_to state.
|
438 |
|
|
|
439 |
|
|
if ($undefined_goto_state && !$force_keep_undefined_goto_state) {
|
440 |
|
|
foreach $trans (keys %transitions) {
|
441 |
|
|
if ($transitions{$trans}{"endState"} eq $undefined_goto_state) {
|
442 |
|
|
#&debug("Exiting undefined check because found a transition into state $undefined_goto_state\n",0,$section);
|
443 |
|
|
&debug("Found input transition to undefined_goto_state $undefined_goto_state - leaving it in\n",0,$section);
|
444 |
|
|
$has_input_transition = 1;
|
445 |
|
|
last;
|
446 |
|
|
}
|
447 |
|
|
}
|
448 |
|
|
if (!$has_input_transition && !($undefined_goto_state eq $reset_state)) {
|
449 |
|
|
&debug("Trying state assignment without $undefined_goto_state\n",0,$section);
|
450 |
|
|
@allstates_save = @allstates;
|
451 |
|
|
@allstates = &remove_from_array($undefined_goto_state,@allstates_save);
|
452 |
|
|
&debug("temporary allstates is @allstates\n",0,"assign_states");
|
453 |
|
|
@save = ($required_bits,$minbits);
|
454 |
|
|
$required_bits = &required_bits($#allstates + 1);
|
455 |
|
|
$minbits = $required_bits;
|
456 |
|
|
$minbits = $regbits if ($regbits > $minbits);
|
457 |
|
|
# Try state assignment without undefined_goto_state
|
458 |
|
|
&assign_states_hero;
|
459 |
|
|
# If the result is a full state graph, drop undefined_goto_state
|
460 |
|
|
if (2**$bits == $#allstates + 1) {
|
461 |
|
|
&debug("State assignment is full without $undefined_goto_state, dropping it\n",0,$section);
|
462 |
|
|
$use_undefined_goto_state = 0;
|
463 |
|
|
$states_assigned_without_undefined_goto_state = 1;
|
464 |
|
|
# Else, restore values
|
465 |
|
|
} else {
|
466 |
|
|
&debug("State assignment is not full without $undefined_goto_state, keeping it\n",0,$section);
|
467 |
|
|
($required_bits,$minbits) = @save;
|
468 |
|
|
@allstates = @allstates_save;
|
469 |
|
|
}
|
470 |
|
|
}
|
471 |
|
|
}
|
472 |
|
|
|
473 |
|
|
unless ($states_assigned_without_undefined_goto_state) {
|
474 |
|
|
# Call &assign_states_hero to do the state assignment
|
475 |
|
|
&assign_states_hero;
|
476 |
|
|
}
|
477 |
|
|
|
478 |
|
|
# Rename variables to standard names
|
479 |
|
|
$total_statebits = $bits;
|
480 |
|
|
%state_val2name = %$v2nref;
|
481 |
|
|
|
482 |
|
|
} elsif ($encoding eq "onehot") {
|
483 |
|
|
|
484 |
|
|
# Using undefined_states_go_to in onehot is likely to result in a very poor
|
485 |
|
|
# implementation. To keep the encoding independent of the state machine,
|
486 |
|
|
# just refuse to do this unless user has provided command line overrride.
|
487 |
|
|
if ($use_undefined_goto_state && !$force_undefined_goto_in_onehot) {
|
488 |
|
|
&warning($indent,"undefined_states_go_here attribute is set. With onehot encoding this is likely to result in a very poor implementation, so the attribute is being ignored. You can force it using -force_undefined_goto_in_onehot.\n");
|
489 |
|
|
$use_undefined_goto_state = 0;
|
490 |
|
|
# Suppress the state if it has no transition into it and it is not reset
|
491 |
|
|
foreach $trans (keys %transitions) {
|
492 |
|
|
if ($transitions{$trans}{"endState"} eq $undefined_goto_state) {
|
493 |
|
|
#&debug("Exiting undefined check because found a transition into state $undefined_goto_state\n",0,$section);
|
494 |
|
|
&debug("Found input transition to undefined_goto_state $undefined_goto_state - leaving it in\n",0,$section);
|
495 |
|
|
$has_input_transition = 1;
|
496 |
|
|
last;
|
497 |
|
|
}
|
498 |
|
|
}
|
499 |
|
|
if (!$has_input_transition && !($undefined_goto_state eq $reset_state)) {
|
500 |
|
|
@allstates = &remove_from_array($undefined_goto_state, @allstates);
|
501 |
|
|
}
|
502 |
|
|
}
|
503 |
|
|
|
504 |
|
|
# Check for errors
|
505 |
|
|
|
506 |
|
|
# No graycodes
|
507 |
|
|
foreach $trans (keys %transitions) {
|
508 |
|
|
if ($transitions{$trans}{attributes}{graycode}{value} || $transitions{$trans}{attributes}{graytransition}{value}) {
|
509 |
|
|
&error($indent,"Cannot have graycode transitions with onehot encoding");
|
510 |
|
|
}
|
511 |
|
|
}
|
512 |
|
|
|
513 |
|
|
# Reset state must not be allones or allzeros
|
514 |
|
|
if ($globals{machine}{reset_state}{type} =~ /(allones)|(allzeros)/) {
|
515 |
|
|
&error($indent,"Cannot have reset_state type of allones or allzeros with onehot encoding. Try changing to \"anyvalue\"");
|
516 |
|
|
}
|
517 |
|
|
|
518 |
|
|
$total_statebits = scalar(keys %states);
|
519 |
|
|
#$statebit = $total_statebits - 1 ; # init statebit pointer
|
520 |
|
|
$statebit = 0;
|
521 |
|
|
#foreach $state (keys %states) {
|
522 |
|
|
foreach $state (@allstates) {
|
523 |
|
|
$state_val2name{$statebit} = $state;
|
524 |
|
|
$statebit++;
|
525 |
|
|
}
|
526 |
|
|
$zero_padded_one = sprintf("%s'b%s%s",$total_statebits,"0" x ($total_statebits - 1), "1");
|
527 |
|
|
|
528 |
|
|
} else {
|
529 |
|
|
&error($indent,"undefined encoding $encoding\n");
|
530 |
|
|
}
|
531 |
|
|
|
532 |
|
|
$last_statebit = $total_statebits - 1;
|
533 |
|
|
|
534 |
|
|
# Figure out longest state name for formatting purposes
|
535 |
|
|
foreach $state (@allstates) {
|
536 |
|
|
$statename_length = length($state) if (length($state) > $statename_length);
|
537 |
|
|
}
|
538 |
|
|
# length of "state[IDLE]"
|
539 |
|
|
$statename_length_onehot = $statename_length + length($statevar) +2;
|
540 |
|
|
$nextstatename_length_onehot = $statename_length + length($nextstatevar) +2;
|
541 |
|
|
$level4indent = $indentstring x 4;
|
542 |
|
|
#eval "\$level4indent = \"$indentstring\" x 4";
|
543 |
|
|
|
544 |
|
|
|
545 |
|
|
#######################
|
546 |
|
|
# module open
|
547 |
|
|
#######################
|
548 |
|
|
|
549 |
|
|
# Handle top-of-file comments
|
550 |
|
|
if ($include_at_top_of_file = $globals{machine}{include_at_top_of_file}{value}) {
|
551 |
|
|
open(FILE,"<$include_at_top_of_file") or &warning($indent,"Could not open file $include_at_top_of_file specified by attribute insert_at_top_of_file");
|
552 |
|
|
while (<FILE>) {
|
553 |
|
|
print;
|
554 |
|
|
}
|
555 |
|
|
}
|
556 |
|
|
&print($indent,"$globals{machine}{insert_at_top_of_file}{value}\n");
|
557 |
|
|
|
558 |
|
|
# Output version data
|
559 |
|
|
if ($addversion) {
|
560 |
|
|
($sec,$min,$hour,$day, $month, $year) = (localtime)[0..5];
|
561 |
|
|
$date = sprintf("%04d:%02d:%02d",$year+1900,$month+1,$day);
|
562 |
|
|
$time = sprintf("%02d:%02d:%02d",$hour,$min,$sec);
|
563 |
|
|
&print($indent,"// Created by $me version $scriptversion on $date at $time (www.fizzim.com)\n\n");
|
564 |
|
|
if ($be_options) {
|
565 |
|
|
&print($indent,"// The following options were set in the be_cmd attribute and will be used unless overridden on the command line: $be_options\n\n");
|
566 |
|
|
}
|
567 |
|
|
#&print($indent,"\n");
|
568 |
|
|
}
|
569 |
|
|
|
570 |
|
|
# Handle module comments
|
571 |
|
|
if ($globals{machine}{name}{comment}) {
|
572 |
|
|
$comment = " // $globals{machine}{name}{comment}";
|
573 |
|
|
} else {
|
574 |
|
|
$comment = "";
|
575 |
|
|
}
|
576 |
|
|
|
577 |
|
|
# Print module line
|
578 |
|
|
if (%parameters) { # If parameters are present, take care of them
|
579 |
|
|
&print($indent++,"module $globals{machine}{name}{value} $comment\n");
|
580 |
|
|
&print($indent++,"#(\n");
|
581 |
|
|
foreach $param (sort keys %parameters) {
|
582 |
|
|
&print($indent,"parameter $param = $parameters{$param},\n");
|
583 |
|
|
}
|
584 |
|
|
# Remove , in final line
|
585 |
|
|
$pbuf[$#pbuf] =~ s/,//;
|
586 |
|
|
&print(--$indent,")(\n");
|
587 |
|
|
} else {
|
588 |
|
|
&print($indent++,"module $globals{machine}{name}{value} ($comment\n");
|
589 |
|
|
}
|
590 |
|
|
&print($indent,"$globals{machine}{insert_in_module_declaration}{value}\n") if $globals{machine}{insert_in_module_declaration}{value};
|
591 |
|
|
|
592 |
|
|
# outputs
|
593 |
|
|
foreach $output (sort keys %{ $globals{outputs} }) {
|
594 |
|
|
# Check for reserved words
|
595 |
|
|
if (exists $reserved_words{$output}) {
|
596 |
|
|
&error($indent,"
|
597 |
|
|
Cannot use reserved word \"$output\" as an output.
|
598 |
|
|
If you are trying to bring out the internal variables, look at the stateout and nextstateout attributes.
|
599 |
|
|
If you have an actual output of this name, try using the -statevar, -nextstatevar, or -statenamevar switches to rename the internal signal to avoid the conflict.
|
600 |
|
|
|
601 |
|
|
");
|
602 |
|
|
}
|
603 |
|
|
|
604 |
|
|
# skip the rest if suppress_portlist is set
|
605 |
|
|
next if ($globals{outputs}{$output}{useratts} =~ /suppress_portlist/);
|
606 |
|
|
|
607 |
|
|
&print($indent,&create_wirereg_statement("output ",$output,",",$io_statement_length));
|
608 |
|
|
}
|
609 |
|
|
|
610 |
|
|
# Handle stateout, nextstateout (hooks to allow state and nextstate to
|
611 |
|
|
# be outputs of the module - see documentation).
|
612 |
|
|
foreach $att ("stateout", "nextstateout") {
|
613 |
|
|
($var = $att) =~ s/out//; # turns "stateout" into "state"
|
614 |
|
|
$var = eval "\$${var}var"; # makes var = $statevar
|
615 |
|
|
if ($stateout = $globals{"machine"}{$att}{"value"}) {
|
616 |
|
|
# Check to make sure no bounds given
|
617 |
|
|
if ($stateout =~ /\[|\]/) {
|
618 |
|
|
&error($indent,"stateout signal \"$stateout\" should not have bit field - this will be determined automatically");
|
619 |
|
|
}
|
620 |
|
|
if ($language eq "verilog") {
|
621 |
|
|
if ($stateout eq $var) {
|
622 |
|
|
# suppress [0:0]
|
623 |
|
|
if ($last_statebit == 0) {
|
624 |
|
|
&print($indent,"output reg $stateout,\n");
|
625 |
|
|
} else {
|
626 |
|
|
&print($indent,"output reg [$last_statebit:0] $stateout,\n");
|
627 |
|
|
}
|
628 |
|
|
} else {
|
629 |
|
|
# suppress [0:0]
|
630 |
|
|
if ($last_statebit == 0) {
|
631 |
|
|
&print($indent,"output wire $stateout,\n");
|
632 |
|
|
} else {
|
633 |
|
|
&print($indent,"output wire [$last_statebit:0] $stateout,\n");
|
634 |
|
|
}
|
635 |
|
|
}
|
636 |
|
|
} elsif ($language eq "systemverilog") {
|
637 |
|
|
if ($stateout eq $var) {
|
638 |
|
|
&error($indent,"Cannot use state or nextstate variables as module ports in SystemVerilog - you must rename them. See documentation for details.");
|
639 |
|
|
} else {
|
640 |
|
|
&print($indent,"output logic [$last_statebit:0] $stateout,\n");
|
641 |
|
|
}
|
642 |
|
|
}
|
643 |
|
|
}
|
644 |
|
|
}
|
645 |
|
|
|
646 |
|
|
# Inputs (still doing the module statement...)
|
647 |
|
|
if ($language eq "verilog") {
|
648 |
|
|
$type = "wire";
|
649 |
|
|
} elsif ($language eq "systemverilog") {
|
650 |
|
|
$type = "logic";
|
651 |
|
|
}
|
652 |
|
|
|
653 |
|
|
foreach $input (sort keys %{ $globals{inputs} }) {
|
654 |
|
|
# Check for reserved words
|
655 |
|
|
if (exists $reserved_words{$input}) {
|
656 |
|
|
&error($indent,"
|
657 |
|
|
Cannot use reserved word \"$input\" as an input.
|
658 |
|
|
If you have an actual input of this name, try using the -statevar, -nextstatevar, or -statenamevar switches to rename the internal signal to avoid the conflict.
|
659 |
|
|
|
660 |
|
|
");
|
661 |
|
|
}
|
662 |
|
|
# Handle comments
|
663 |
|
|
if ($globals{inputs}{$input}{comment}) {
|
664 |
|
|
$comment = "// $globals{inputs}{$input}{comment}";
|
665 |
|
|
} else {
|
666 |
|
|
$comment = "";
|
667 |
|
|
}
|
668 |
|
|
|
669 |
|
|
# Handle multibit inputs
|
670 |
|
|
if (($name,$range) = ($input =~ /^([^\[]+)\s*(\[.*\])/)) {
|
671 |
|
|
&print($indent,sprintf("%-${io_statement_length}s %-s\n","input $type $range $name,",$comment));
|
672 |
|
|
} else {
|
673 |
|
|
&print($indent,sprintf("%-${io_statement_length}s %-s\n","input $type $input,",$comment));
|
674 |
|
|
}
|
675 |
|
|
# Remove trailing blanks
|
676 |
|
|
$pbuf[$#pbuf] =~ s/\s*\n$/\n/;
|
677 |
|
|
}
|
678 |
|
|
|
679 |
|
|
# print last line of module statement and close
|
680 |
|
|
if ($pbuf[$#pbuf] =~ s/^(.*),/\1 /) {
|
681 |
|
|
$pbuf[$#pbuf] = $pbuf[$#pbuf] . ");\n"; # Add ); on a new line
|
682 |
|
|
} else {
|
683 |
|
|
&error($indent,"No inputs or outputs specified");
|
684 |
|
|
}
|
685 |
|
|
&print($indent,"\n");
|
686 |
|
|
|
687 |
|
|
if ($insert_at_top_of_module = "$globals{machine}{insert_at_top_of_module}{value}") {
|
688 |
|
|
&print($indent,"// Inserted from attribute insert_at_top_of_module:\n");
|
689 |
|
|
eval "\$myindent = \"$indentstring\" x $indent";
|
690 |
|
|
$insert_at_top_of_module =~ s/(\n)/\1${myindent}/g; # put indent after any \n in the string
|
691 |
|
|
&print($indent,"$insert_at_top_of_module\n");
|
692 |
|
|
&print($indent,"\n");
|
693 |
|
|
}
|
694 |
|
|
|
695 |
|
|
|
696 |
|
|
#######################
|
697 |
|
|
# Print out state parameter definition
|
698 |
|
|
#######################
|
699 |
|
|
#&print($indent,"\n\n");
|
700 |
|
|
&print($indent,"// state bits\n");
|
701 |
|
|
|
702 |
|
|
# The systemverilog output in onehot is a slightly different format
|
703 |
|
|
# than the verilog output in onehot. Both use indexing, but the sv version
|
704 |
|
|
# assigns the state values to full vectors (with one bit set) rather than
|
705 |
|
|
# setting one bit in a zero vector. This is based on Cliff Cumming's
|
706 |
|
|
# preferred coding style, and allows for the default_state_is_x functionality
|
707 |
|
|
# in onehot.
|
708 |
|
|
#
|
709 |
|
|
# 4/30/2009: Changed the default_state_is_x verilog onehot to work like the
|
710 |
|
|
# systemverilog version, but with verilog syntax. That means that the output
|
711 |
|
|
# using verilog will look very different depending on whether default_state_is_x# is set or not.
|
712 |
|
|
|
713 |
|
|
# To accomplish this, sv+onehot requires an extra enum:
|
714 |
|
|
if ($language eq "systemverilog" && $encoding eq "onehot") {
|
715 |
|
|
&print($indent++,"enum {\n");
|
716 |
|
|
foreach $state (@allstates) {
|
717 |
|
|
&print($indent,"${state}_BIT,\n");
|
718 |
|
|
}
|
719 |
|
|
# Remove ,
|
720 |
|
|
$pbuf[$#pbuf] =~ s/^(.*),/\1/;
|
721 |
|
|
# print close of enum
|
722 |
|
|
&print(--$indent,"} $indexvar;\n\n");
|
723 |
|
|
|
724 |
|
|
# And verilog, onehot, defaultx requires an extra parameter statement:
|
725 |
|
|
} elsif ($language eq "verilog" && $encoding eq "onehot" && $globals{machine}{default_state_is_x}{value}) {
|
726 |
|
|
&print($indent,"parameter\n");
|
727 |
|
|
foreach $state (@allstates) {
|
728 |
|
|
# Search through all assigned values looking for the one that matches $state
|
729 |
|
|
foreach $val (keys %state_val2name) {
|
730 |
|
|
if ($state_val2name{$val} eq $state) {
|
731 |
|
|
&print($indent,"${state}_BIT = $val,\n");
|
732 |
|
|
}
|
733 |
|
|
}
|
734 |
|
|
}
|
735 |
|
|
# Change , in final line to ;
|
736 |
|
|
$pbuf[$#pbuf] =~ s/,/;/;
|
737 |
|
|
&print($indent,"\n");
|
738 |
|
|
}
|
739 |
|
|
|
740 |
|
|
|
741 |
|
|
if ($language eq "verilog") {
|
742 |
|
|
# DC gives a warning that not all tool support bounds on parameters, so
|
743 |
|
|
# don't use them.
|
744 |
|
|
#&print($indent,"parameter [$last_statebit:0]\n");
|
745 |
|
|
&print($indent,"parameter \n");
|
746 |
|
|
} elsif ($language eq "systemverilog") {
|
747 |
|
|
# SV uses enumerated types instead of parameters, but many of the details
|
748 |
|
|
# are the same.
|
749 |
|
|
&print($indent,"enum logic [$last_statebit:0] {\n");
|
750 |
|
|
$indent++; # indent the enum values
|
751 |
|
|
}
|
752 |
|
|
|
753 |
|
|
|
754 |
|
|
# Print out state encoding in @allstates order
|
755 |
|
|
foreach $state (@allstates) {
|
756 |
|
|
$comment = "";
|
757 |
|
|
# Search through all assigned values looking for the one that matches $state
|
758 |
|
|
foreach $val (keys %state_val2name) {
|
759 |
|
|
if ($state_val2name{$val} eq $state) {
|
760 |
|
|
# If there are output encoded ($regbits is not 0), prepare a comment
|
761 |
|
|
# that shows the value of each output in this state.
|
762 |
|
|
if ($regbits) {
|
763 |
|
|
$val_length = length($val);
|
764 |
|
|
foreach $regout (sort {
|
765 |
|
|
$reg_outputs{$a}{statebit_lower} <=>
|
766 |
|
|
$reg_outputs{$b}{statebit_lower}
|
767 |
|
|
} keys %reg_outputs) {
|
768 |
|
|
$lower = $reg_outputs{$regout}{statebit_lower};
|
769 |
|
|
$upper = $reg_outputs{$regout}{statebit_upper};
|
770 |
|
|
$bitvalue = substr($val,$val_length - $upper - 1,$upper - $lower + 1);
|
771 |
|
|
$comment = "$regout=${bitvalue} ${comment}";
|
772 |
|
|
}
|
773 |
|
|
|
774 |
|
|
# Do extra bits
|
775 |
|
|
if ($val_length - 1 > $upper) {
|
776 |
|
|
#$bitvalue = substr($val,($val_length - 1) - ($upper + 1),$val_length - $upper - 1);
|
777 |
|
|
$bitvalue = substr($val,0,$val_length - $upper - 1);
|
778 |
|
|
$comment = "extra=${bitvalue} ${comment}";
|
779 |
|
|
}
|
780 |
|
|
|
781 |
|
|
$comment = "// $comment";
|
782 |
|
|
} # end of encoded output comment code
|
783 |
|
|
|
784 |
|
|
|
785 |
|
|
if ($encoding eq "heros") {
|
786 |
|
|
&print($indent,sprintf("%-${statename_length}s%s","$state"," = ${total_statebits}'b${val}, ${comment}\n"));
|
787 |
|
|
|
788 |
|
|
} elsif ($encoding eq "onehot") {
|
789 |
|
|
if ($language eq "systemverilog" || ($language eq "verilog" && ($globals{machine}{default_state_is_x}{value} || exists $globals{machine}{default_state}{value}))) {
|
790 |
|
|
&print($indent,sprintf("%-${statename_length}s%s","$state"," = ${total_statebits}\'b1<<${state}_BIT, ${comment}\n"));
|
791 |
|
|
} elsif ($language eq "verilog") {
|
792 |
|
|
&print($indent,sprintf("%-${statename_length}s%s","$state"," = ${val}, ${comment}\n"));
|
793 |
|
|
}
|
794 |
|
|
}
|
795 |
|
|
}
|
796 |
|
|
}
|
797 |
|
|
}
|
798 |
|
|
|
799 |
|
|
if ($language eq "verilog") {
|
800 |
|
|
if ($encoding eq "onehot" && $globals{machine}{default_state_is_x}{value}) {
|
801 |
|
|
#&print($indent, sprintf("XXX = %s\'b%s;\n",$total_statebits,"x" x $total_statebits));
|
802 |
|
|
&print($indent, sprintf("%-${statename_length}s = %s\'b%s;\n","XXX",$total_statebits,"x"));
|
803 |
|
|
} else {
|
804 |
|
|
# Substitute ; for , and print last line.
|
805 |
|
|
$pbuf[$#pbuf] =~ s/^(.*),/\1;/;
|
806 |
|
|
}
|
807 |
|
|
} elsif ($language eq "systemverilog") {
|
808 |
|
|
# Print line
|
809 |
|
|
if ($globals{machine}{default_state_is_x}{value}) {
|
810 |
|
|
# Add XXX
|
811 |
|
|
&print($indent, "XXX = \'x\n");
|
812 |
|
|
} else {
|
813 |
|
|
$pbuf[$#pbuf] =~ s/^(.*),/\1 /; # get rid of last ,
|
814 |
|
|
}
|
815 |
|
|
# Add closing of enum statement
|
816 |
|
|
&print(--$indent, "} $statevar, $nextstatevar;\n");
|
817 |
|
|
}
|
818 |
|
|
|
819 |
|
|
# If undefined_states_go_to check caused state to be dropped, add comment
|
820 |
|
|
if ($states_assigned_without_undefined_goto_state) {
|
821 |
|
|
&print($indent,"// Note: State $undefined_goto_state (with undefined_states_go_here attribute) dropped because it had no transitions into it and the state map was full without it. Use -force_keep_undefined_goto_state to override this.\n");
|
822 |
|
|
}
|
823 |
|
|
|
824 |
|
|
|
825 |
|
|
#######################
|
826 |
|
|
# state, nextstate reg lines
|
827 |
|
|
#######################
|
828 |
|
|
&print($indent, "\n");
|
829 |
|
|
# Handle stateout, nextstateout attributes
|
830 |
|
|
foreach $att ("stateout", "nextstateout") {
|
831 |
|
|
($var = $att) =~ s/out//; # turns "stateout" into "state"
|
832 |
|
|
$var = eval "\$${var}var"; # makes var = $statevar
|
833 |
|
|
if ($stateout = $globals{"machine"}{$att}{"value"}) {
|
834 |
|
|
if ($stateout eq $var) {
|
835 |
|
|
# If stateout is set the same as $statevar, then the reg statement was
|
836 |
|
|
# done in the module header. Do nothing.
|
837 |
|
|
} else {
|
838 |
|
|
# If stateout is NOT set the same as $statevar, then the module statement
|
839 |
|
|
# had a "wire" for stateout and we need to create the reg statement
|
840 |
|
|
# here and an assign of the wire to the reg.
|
841 |
|
|
if ($language eq "verilog") {
|
842 |
|
|
# suppress [0:0]
|
843 |
|
|
if ($last_statebit == 0) {
|
844 |
|
|
&print($indent, "reg $var;\n");
|
845 |
|
|
} else {
|
846 |
|
|
&print($indent, "reg [$last_statebit:0] $var;\n");
|
847 |
|
|
}
|
848 |
|
|
} elsif ($language eq "systemverilog") {
|
849 |
|
|
# No need to do anything for sv. The state bits are enum types
|
850 |
|
|
#&print($indent, "logic [$last_statebit:0] $var;\n");
|
851 |
|
|
}
|
852 |
|
|
&print($indent, "assign $stateout = $var;\n");
|
853 |
|
|
}
|
854 |
|
|
} else {
|
855 |
|
|
# No attribute set - print out reg statement. For SV, do nothing (declared
|
856 |
|
|
# as logic type in the enum statement).
|
857 |
|
|
if ($language eq "verilog") {
|
858 |
|
|
# suppress [0:0]
|
859 |
|
|
if ($last_statebit == 0) {
|
860 |
|
|
&print($indent, "reg $var;\n");
|
861 |
|
|
} else {
|
862 |
|
|
&print($indent, "reg [$last_statebit:0] $var;\n");
|
863 |
|
|
}
|
864 |
|
|
}
|
865 |
|
|
}
|
866 |
|
|
}
|
867 |
|
|
|
868 |
|
|
#######################
|
869 |
|
|
# reg lines for outputs with suppress_portlist
|
870 |
|
|
#######################
|
871 |
|
|
foreach $output (sort keys %{ $globals{outputs} }) {
|
872 |
|
|
next if (!($globals{outputs}{$output}{useratts} =~ /suppress_portlist/));
|
873 |
|
|
&print($indent,&create_wirereg_statement("",$output,";",$max_io_length + length("reg ")));
|
874 |
|
|
}
|
875 |
|
|
|
876 |
|
|
#######################
|
877 |
|
|
# reg lines for flag "next_..." variables
|
878 |
|
|
#######################
|
879 |
|
|
foreach $flag (sort keys %flags) {
|
880 |
|
|
$line = &create_wirereg_statement("",$flag,";",$max_io_length + length("reg next"));
|
881 |
|
|
$flag =~ s/\s*\[\d+:\d+\]\s*//; # get rid of range field
|
882 |
|
|
$line =~ s/$flag/next_${flag}/;
|
883 |
|
|
$line =~ s/;\s*\/\/.*$/;/; # get rid of comment
|
884 |
|
|
&print($indent,$line);
|
885 |
|
|
}
|
886 |
|
|
|
887 |
|
|
#######################
|
888 |
|
|
# Output combinational block
|
889 |
|
|
#######################
|
890 |
|
|
$section = "comb_block";
|
891 |
|
|
&print($indent, "\n");
|
892 |
|
|
&print($indent, "// comb always block\n");
|
893 |
|
|
if ($language eq "verilog") {
|
894 |
|
|
&print($indent++, "always @* begin\n");
|
895 |
|
|
} elsif ($language eq "systemverilog") {
|
896 |
|
|
&print($indent++, "always_comb begin\n");
|
897 |
|
|
}
|
898 |
|
|
|
899 |
|
|
if ($encoding eq "heros") {
|
900 |
|
|
# For heros, defaults ahead of case depend on fsm attributes
|
901 |
|
|
if (!($globals{machine}{implied_loopback}{value} || $globals{machine}{default_state_is_x}{value})) {
|
902 |
|
|
&warning($indent,"Neither implied_loopback nor default_state_is_x attribute is set on state machine - defaulting to implied_loopback to avoid latches being inferred");
|
903 |
|
|
$globals{machine}{implied_loopback}{value} = 1;
|
904 |
|
|
}
|
905 |
|
|
if ($globals{machine}{implied_loopback}{value}) {
|
906 |
|
|
&print($indent, "$nextstatevar = $statevar; // default to hold value because implied_loopback is set\n");
|
907 |
|
|
} elsif ($globals{machine}{default_state_is_x}{value}) {
|
908 |
|
|
if ($language eq "verilog") {
|
909 |
|
|
# &print($indent, sprintf("$nextstatevar = ${total_statebits}\'b%s; // default to x because default_state_is_x is set\n","x"));
|
910 |
|
|
&print($indent, sprintf("$nextstatevar = ${total_statebits}\'b%s; // default to x because default_state_is_x is set\n","x" x ${total_statebits}));
|
911 |
|
|
} elsif ($language eq "systemverilog") {
|
912 |
|
|
&print($indent, sprintf("$nextstatevar = XXX; // default to x because default_state_is_x is set\n"));
|
913 |
|
|
}
|
914 |
|
|
} else {
|
915 |
|
|
&error("Internal error - cannot get here...");
|
916 |
|
|
}
|
917 |
|
|
|
918 |
|
|
} elsif ($encoding eq "onehot") {
|
919 |
|
|
# if ($language eq "systemverilog" || ($language eq "verilog" && $globals{machine}{default_state_is_x}{value})) {
|
920 |
|
|
# &print($indent, sprintf("$nextstatevar = XXX; // default to x because default_state_is_x is set\n"));
|
921 |
|
|
# } elsif ($language eq "verilog") {
|
922 |
|
|
# &print($indent, sprintf("$nextstatevar = ${total_statebits}\'b%s;\n","0" x $total_statebits));
|
923 |
|
|
# }
|
924 |
|
|
if ($globals{machine}{default_state_is_x}{value}) {
|
925 |
|
|
&print($indent, sprintf("$nextstatevar = XXX; // default to x because default_state_is_x is set\n"));
|
926 |
|
|
} elsif ($language eq "verilog") {
|
927 |
|
|
&print($indent, sprintf("$nextstatevar = ${total_statebits}\'b%s;\n","0" x $total_statebits));
|
928 |
|
|
}
|
929 |
|
|
}
|
930 |
|
|
|
931 |
|
|
# Combinational defaults.
|
932 |
|
|
# To get better synth results "out of the box", use a 0 default if no
|
933 |
|
|
# default is defined. To get the old "hold value"
|
934 |
|
|
# behavior, it will be necessary for the user to set the default to
|
935 |
|
|
# be the variable name (ie, if the variable name is "foo", make the default
|
936 |
|
|
# value "foo").
|
937 |
|
|
foreach $combout (sort keys %comb_outputs) {
|
938 |
|
|
if (exists $comb_outputs{$combout}{default_value} && ($comb_outputs{$combout}{default_value} ne "") ) {
|
939 |
|
|
$comb_defaults{$combout} = $comb_outputs{$combout}{default_value};
|
940 |
|
|
&print($indent,"$combout = $comb_defaults{$combout}; // default\n");
|
941 |
|
|
} else {
|
942 |
|
|
$comb_defaults{$combout} = "0"; # Use string zero
|
943 |
|
|
&warning($indent,"Combinational output $combout has no default value - using 0");
|
944 |
|
|
&print($indent,"$combout = $comb_defaults{$combout}; // default to zero for better synth results (no default set in .fzm file)\n");
|
945 |
|
|
#&print($indent,"$combout = $widths{$combout}'b$comb_defaults{$combout}; // default to zero for better synth results (no default set in .fzm file)\n");
|
946 |
|
|
}
|
947 |
|
|
}
|
948 |
|
|
|
949 |
|
|
# Do flags. They always default to their current value.
|
950 |
|
|
foreach $flag (sort keys %flags) {
|
951 |
|
|
$flag_defaults{$flag} = $flags{$flag}{default_value};
|
952 |
|
|
&print($indent,"next_${flag} = $flag;\n");
|
953 |
|
|
}
|
954 |
|
|
|
955 |
|
|
# State "case" block
|
956 |
|
|
&print_case_statement($statevar);
|
957 |
|
|
#&assertion($indent,"// Test assertions");
|
958 |
|
|
|
959 |
|
|
# Output state code in @allstates order
|
960 |
|
|
foreach $state (@allstates) {
|
961 |
|
|
%non_default_on_state_value_found = (); # hash to keep track of mealy/flag info
|
962 |
|
|
if ($states{$state}{attributes}{comment}) {
|
963 |
|
|
$comment = " // $states{$state}{attributes}{comment}";
|
964 |
|
|
} else {
|
965 |
|
|
$comment = "";
|
966 |
|
|
}
|
967 |
|
|
if ($encoding eq "heros") {
|
968 |
|
|
#&print($indent++,"$state:" . " begin${comment}\n");
|
969 |
|
|
&print($indent++,sprintf("%-${statename_length}s:",$state) . " begin${comment}\n");
|
970 |
|
|
|
971 |
|
|
} elsif ($encoding eq "onehot") {
|
972 |
|
|
if ($language eq "systemverilog" || ($language eq "verilog" && $globals{machine}{default_state_is_x}{value})) {
|
973 |
|
|
&print($indent++,sprintf("%-${statename_length_onehot}s:","$statevar\[${state}_BIT\]") . " begin${comment}\n");
|
974 |
|
|
} elsif ($language eq "verilog") {
|
975 |
|
|
&print($indent++,sprintf("%-${statename_length_onehot}s:","$statevar\[$state\]") . " begin${comment}\n");
|
976 |
|
|
}
|
977 |
|
|
}
|
978 |
|
|
# Search state attributes for outputs. If a combinational or flag output is
|
979 |
|
|
# found, assign its value here (maybe).
|
980 |
|
|
foreach $comb_output (sort keys %comb_outputs) {
|
981 |
|
|
if (exists $states{$state}{attributes}{$comb_output}{value}) {
|
982 |
|
|
$value = $states{$state}{attributes}{$comb_output}{value};
|
983 |
|
|
} else {
|
984 |
|
|
$value = $comb_outputs{$comb_output}{default_value};
|
985 |
|
|
}
|
986 |
|
|
|
987 |
|
|
# Check to see if output is assigned on transitions. If so, check to see
|
988 |
|
|
# if a non-default value has been assigned in this state.
|
989 |
|
|
# If so, output assignment statement, set flag and issue warning.
|
990 |
|
|
if ($in_mealy_on_transitions_mode) {
|
991 |
|
|
if ($value ne $comb_outputs{$comb_output}{default_value}) {
|
992 |
|
|
# If output has a non-default value in this state, warn user and print it anyway
|
993 |
|
|
&warning($indent,"Combinational output $comb_output is assigned on transitions, but has a non-default value \"$value\" in state $state");
|
994 |
|
|
# Check that resulting value is non-null
|
995 |
|
|
&error($indent,"Value of comb output $comb_output cannot be determined in state $state") if ($value eq "");
|
996 |
|
|
# Print the default statement anyway if it doesn't match default from above
|
997 |
|
|
&print($indent,"$comb_output = $value;\n") unless ($value eq $comb_defaults{$comb_output});
|
998 |
|
|
# Set flag to suppress non-default on-transition values in this state
|
999 |
|
|
$non_default_on_state_value_found{$comb_output} = $value;
|
1000 |
|
|
}
|
1001 |
|
|
} else {
|
1002 |
|
|
# NOT in mealy-on-transitions mode, so print the default statement
|
1003 |
|
|
# Check that resulting value is non-null
|
1004 |
|
|
&error($indent,"Value of comb output $comb_output cannot be determined in state $state") if ($value eq "");
|
1005 |
|
|
# Only print the default statement if the comb output is NOT assigned
|
1006 |
|
|
# on transitions (and it doesn't match default above)
|
1007 |
|
|
&print($indent,"$comb_output = $value;\n") unless ($value eq $comb_defaults{$comb_output});
|
1008 |
|
|
}
|
1009 |
|
|
}
|
1010 |
|
|
|
1011 |
|
|
# Now do flags.
|
1012 |
|
|
foreach $flag (sort keys %flags) {
|
1013 |
|
|
if ($states{$state}{attributes}{$flag}{value} ne "") {
|
1014 |
|
|
# Check to see if flag is assigned on transitions. If so, and it is
|
1015 |
|
|
# assigned in this state, set flag and issue warning.
|
1016 |
|
|
if ($in_flag_on_transitions_mode) {
|
1017 |
|
|
&warning($indent,"Flag $flag is assigned on transitions, but is also assigned value \"$states{$state}{attributes}{$flag}{value}\" in state $state");
|
1018 |
|
|
}
|
1019 |
|
|
# output assignment statement
|
1020 |
|
|
&print($indent,"next_${flag} = $states{$state}{attributes}{$flag}{value};\n");
|
1021 |
|
|
}
|
1022 |
|
|
}
|
1023 |
|
|
|
1024 |
|
|
# Search transitions for all those starting on this state.
|
1025 |
|
|
# Sort by priority, then output vlog if/elseif/else
|
1026 |
|
|
# equation to switch to correct endState.
|
1027 |
|
|
@transitions_from_this_state = ();
|
1028 |
|
|
foreach $trans (keys %transitions) {
|
1029 |
|
|
if ($transitions{$trans}{"startState"} eq $state) {
|
1030 |
|
|
&debug("Transition $trans starts on state $state, adding to array",0,$section);
|
1031 |
|
|
push(@transitions_from_this_state,$trans);
|
1032 |
|
|
}
|
1033 |
|
|
}
|
1034 |
|
|
|
1035 |
|
|
# nextstate determination
|
1036 |
|
|
# Sort by priority, followed by equation. The equation part ensures
|
1037 |
|
|
# that "1" will be last.
|
1038 |
|
|
@transitions_from_this_state = sort sort_by_priority_then_equation_equal_1 @transitions_from_this_state;
|
1039 |
|
|
#print("After sort, transitions_from_this_state for state $state is @transitions_from_this_state\n");
|
1040 |
|
|
&debug("After sort, transitions_from_this_state for state $state is @transitions_from_this_state",0,$section);
|
1041 |
|
|
|
1042 |
|
|
# Check for problems with priority
|
1043 |
|
|
undef %priorities_seen;
|
1044 |
|
|
if ($#transitions_from_this_state > 0) {
|
1045 |
|
|
for (my $i = 0; $i<=$#transitions_from_this_state; $i++) {
|
1046 |
|
|
$trans = $transitions_from_this_state[$i];
|
1047 |
|
|
$equation = $transitions{$trans}{attributes}{equation}{value};
|
1048 |
|
|
$equation =~ s/\n//g; # remove embedded cr's
|
1049 |
|
|
# If no priority exists, warn unless
|
1050 |
|
|
# 1) this is the last transition and equation is "1"
|
1051 |
|
|
# 2) There are only two transitions, and the last one has equation of "1"
|
1052 |
|
|
if (!($pri = $transitions{$trans}{attributes}{priority}{value})) {
|
1053 |
|
|
#print "looking at $trans: $i of $#transitions_from_this_state\n";
|
1054 |
|
|
#print "equation: $equation\n";
|
1055 |
|
|
unless (
|
1056 |
|
|
# last and equation is 1
|
1057 |
|
|
($equation eq "1" &&
|
1058 |
|
|
$i == $#transitions_from_this_state)
|
1059 |
|
|
||
|
1060 |
|
|
# Exactly 2 transitions and last has equation of 1
|
1061 |
|
|
($#transitions_from_this_state == 1 &&
|
1062 |
|
|
$transitions{$transitions_from_this_state[$#transitions_from_this_state]}{attributes}{equation}{value} eq "1")
|
1063 |
|
|
) {
|
1064 |
|
|
&warning($indent,"State $state has multiple exit transitions, and transition $trans has no defined priority");
|
1065 |
|
|
}
|
1066 |
|
|
} else {
|
1067 |
|
|
# If priority exists, but it's a duplicate, warn unless THIS transition
|
1068 |
|
|
# has an equation of 1 (note that sort means that if two transitions
|
1069 |
|
|
# have the same priority, the one with an equation of 1 will come last).
|
1070 |
|
|
if (exists $priorities_seen{$pri}) {
|
1071 |
|
|
unless ($equation eq "1") {
|
1072 |
|
|
&warning($indent,"State $state has multiple exit transitions, and transition $trans has the same priority as transition $priorities_seen{$pri}");
|
1073 |
|
|
}
|
1074 |
|
|
} else {
|
1075 |
|
|
$priorities_seen{$pri} = $trans;
|
1076 |
|
|
}
|
1077 |
|
|
}
|
1078 |
|
|
}
|
1079 |
|
|
}
|
1080 |
|
|
|
1081 |
|
|
$no_transitions_from_this_state = 1; # temp flag
|
1082 |
|
|
for (my $i = 0; $i<=$#transitions_from_this_state; $i++) {
|
1083 |
|
|
$no_transitions_from_this_state = 0; # temp flag
|
1084 |
|
|
$trans = $transitions_from_this_state[$i];
|
1085 |
|
|
$equation = $transitions{$trans}{attributes}{equation}{value};
|
1086 |
|
|
$equation =~ s/\n//g; # remove embedded cr's
|
1087 |
|
|
#print "trans is $trans\n";
|
1088 |
|
|
#print STDERR "equation is $equation\n";
|
1089 |
|
|
$equation = 1 unless ($equation); # force null string to "1"
|
1090 |
|
|
$eq1seen = 0;
|
1091 |
|
|
|
1092 |
|
|
# Check for unreachable transitions. If the equation is 1 and
|
1093 |
|
|
# there are more transitions following, it's an error.
|
1094 |
|
|
if ($equation eq "1" && $#transitions_from_this_state > $i) {
|
1095 |
|
|
&error($indent,"State $state has an always true equation for transition $trans, but has lower priority transitions as well");
|
1096 |
|
|
}
|
1097 |
|
|
|
1098 |
|
|
if ($i == 0) { # first item in list
|
1099 |
|
|
# If always true, just output "begin" without the if
|
1100 |
|
|
# (need a begin/end block in case there are comb outputs)
|
1101 |
|
|
if ($equation eq "1") {
|
1102 |
|
|
&print($indent++,"begin\n");
|
1103 |
|
|
$eq1seen = 1;
|
1104 |
|
|
} else {
|
1105 |
|
|
&print($indent++,"if ($equation) begin\n");
|
1106 |
|
|
}
|
1107 |
|
|
|
1108 |
|
|
} elsif ($i == $#transitions_from_this_state) { # last item in list
|
1109 |
|
|
# Note that this won't execute if there was only one item in
|
1110 |
|
|
# the list (due to use of elsif)
|
1111 |
|
|
if ($equation eq "1") {
|
1112 |
|
|
&print($indent++,"else begin\n");
|
1113 |
|
|
$eq1seen = 1;
|
1114 |
|
|
} else {
|
1115 |
|
|
&print($indent++,"else if ($equation) begin\n");
|
1116 |
|
|
}
|
1117 |
|
|
|
1118 |
|
|
} else { # intermediate terms
|
1119 |
|
|
&print($indent++,"else if ($equation) begin\n");
|
1120 |
|
|
}
|
1121 |
|
|
|
1122 |
|
|
$nextstate = $transitions{$trans}{endState};
|
1123 |
|
|
# Handle transition comments
|
1124 |
|
|
if ($transitions{$trans}{attributes}{comment}) {
|
1125 |
|
|
$comment = " // $transitions{$trans}{attributes}{comment}";
|
1126 |
|
|
} else {
|
1127 |
|
|
$comment = "";
|
1128 |
|
|
}
|
1129 |
|
|
if ($encoding eq "heros") {
|
1130 |
|
|
foreach $graystate (@{ $graytransitions{$state} }) {
|
1131 |
|
|
if ($graystate eq $nextstate) {
|
1132 |
|
|
$comment = $comment . " // graycoded";
|
1133 |
|
|
}
|
1134 |
|
|
}
|
1135 |
|
|
&print($indent,"$nextstatevar = $nextstate;$comment\n");
|
1136 |
|
|
} elsif ($encoding eq "onehot") {
|
1137 |
|
|
if ($language eq "systemverilog" || ($language eq "verilog" && $globals{machine}{default_state_is_x}{value})) {
|
1138 |
|
|
&print($indent,"$nextstatevar = $nextstate;$comment\n");
|
1139 |
|
|
} elsif ($language eq "verilog") {
|
1140 |
|
|
&print($indent,"$nextstatevar\[$nextstate\] = 1'b1;$comment\n");
|
1141 |
|
|
}
|
1142 |
|
|
}
|
1143 |
|
|
|
1144 |
|
|
# Add comb outputs and flags
|
1145 |
|
|
foreach $att (keys %{ $transitions{$trans}{attributes} }) {
|
1146 |
|
|
if ($transitions{$trans}{attributes}{$att}{type} eq "output") {
|
1147 |
|
|
if (exists $comb_outputs{$att}) {
|
1148 |
|
|
# comb outputs
|
1149 |
|
|
# Check if specific value exists for this comb output on this transition
|
1150 |
|
|
if (exists $transitions{$trans}{attributes}{$att}{value} &&
|
1151 |
|
|
($value = $transitions{$trans}{attributes}{$att}{value} ne "")
|
1152 |
|
|
) {
|
1153 |
|
|
$value = $transitions{$trans}{attributes}{$att}{value};
|
1154 |
|
|
# if not, set to default
|
1155 |
|
|
} else {
|
1156 |
|
|
$value = $comb_outputs{$att}{"default_value"};
|
1157 |
|
|
}
|
1158 |
|
|
|
1159 |
|
|
# Check that resulting value is non-null
|
1160 |
|
|
&error($indent,"Value of comb output $att cannot be determined on transition $trans") if ($value eq "");
|
1161 |
|
|
# Print if non-default state value was found and this value doesn't match either it or the default
|
1162 |
|
|
# or if no non-default state value was found and this value doesn't match the comb default
|
1163 |
|
|
#&print($indent,"debug: nondef: \"$non_default_on_state_value_found{$att}\" value: \"$value\" combdef: \"$comb_outputs{$att}{default_value}\"\n");
|
1164 |
|
|
if (exists $non_default_on_state_value_found{$att}
|
1165 |
|
|
&& ($value ne $non_default_on_state_value_found{$att})
|
1166 |
|
|
&& ($value ne $comb_outputs{$att}{default_value})
|
1167 |
|
|
|| !exists $non_default_on_state_value_found{$att}
|
1168 |
|
|
&& ($value ne $comb_outputs{$att}{default_value})
|
1169 |
|
|
) {
|
1170 |
|
|
&print($indent,"$att = $value;\n");
|
1171 |
|
|
}
|
1172 |
|
|
}
|
1173 |
|
|
if (exists $flags{$att}) {
|
1174 |
|
|
# flags
|
1175 |
|
|
if ($transitions{$trans}{attributes}{$att}{value} ne "") {
|
1176 |
|
|
&print($indent,"next_${att} = $transitions{$trans}{attributes}{$att}{value};\n");
|
1177 |
|
|
}
|
1178 |
|
|
}
|
1179 |
|
|
}
|
1180 |
|
|
}
|
1181 |
|
|
|
1182 |
|
|
&print(--$indent,"end\n"); # end of if/else/elseif ... or begin block
|
1183 |
|
|
}
|
1184 |
|
|
# implied_loopback is handled differently for onehot. Instead of
|
1185 |
|
|
# inserting a default value of "state" ahead of the case statement, we
|
1186 |
|
|
# need to actually add explicit "else..." clauses for any transition
|
1187 |
|
|
# that isn't a "1".
|
1188 |
|
|
# Also, watch for the case where there are NO
|
1189 |
|
|
# transitions out of the state - we need to add the extra code to stay
|
1190 |
|
|
# put there as well.
|
1191 |
|
|
if ($encoding eq "onehot") {
|
1192 |
|
|
if (!$eq1seen || $no_transitions_from_this_state) {
|
1193 |
|
|
if (!($globals{machine}{implied_loopback}{value} || $globals{machine}{default_state_is_x}{value})) {
|
1194 |
|
|
&warning($indent,"Neither implied_loopback nor default_state_is_x attribute is set on state machine - defaulting to implied_loopback to avoid latches being inferred");
|
1195 |
|
|
$globals{machine}{implied_loopback}{value} = 1;
|
1196 |
|
|
}
|
1197 |
|
|
# Note that implied loopback has priority over default_state_is_x
|
1198 |
|
|
if ($globals{machine}{implied_loopback}{value}) {
|
1199 |
|
|
if ($no_transitions_from_this_state) {
|
1200 |
|
|
} else {
|
1201 |
|
|
&print($indent++,"else begin\n");
|
1202 |
|
|
}
|
1203 |
|
|
if ($language eq "systemverilog") {
|
1204 |
|
|
&print($indent,"$nextstatevar = $state; // Added because implied_loopback is true\n");
|
1205 |
|
|
} elsif ($language eq "verilog") {
|
1206 |
|
|
&print($indent,"$nextstatevar\[$state\] = 1'b1; // Added because implied_loopback is true\n");
|
1207 |
|
|
}
|
1208 |
|
|
if ($no_transitions_from_this_state) {
|
1209 |
|
|
} else {
|
1210 |
|
|
&print(--$indent,"end\n");
|
1211 |
|
|
}
|
1212 |
|
|
|
1213 |
|
|
} elsif ($globals{machine}{default_state_is_x}{value}) {
|
1214 |
|
|
# Don't need anything. If we're doing onehot (see if above), and
|
1215 |
|
|
# we've got default_state_is_x on, we're using the sv XXX format, both
|
1216 |
|
|
# in sv and in verilog, so we do nothing.
|
1217 |
|
|
|
1218 |
|
|
} else {
|
1219 |
|
|
&error("Internal error - cannot get here...");
|
1220 |
|
|
}
|
1221 |
|
|
}
|
1222 |
|
|
}
|
1223 |
|
|
&print(--$indent,"end\n"); # end of case match
|
1224 |
|
|
}
|
1225 |
|
|
if ($use_undefined_goto_state) {
|
1226 |
|
|
&print($indent, "default : begin\n");
|
1227 |
|
|
if ($encoding eq "heros") {
|
1228 |
|
|
&print(++$indent,"$nextstatevar = $undefined_goto_state; // Added because undefined_states_go_here is set\n");
|
1229 |
|
|
} elsif ($encoding eq "onehot") {
|
1230 |
|
|
if ($language eq "systemverilog" || $globals{machine}{default_state_is_x}{value}) {
|
1231 |
|
|
&print(++$indent,"$nextstatevar = $undefined_goto_state; // Added because undefined_states_go_here is set\n");
|
1232 |
|
|
} elsif ($language eq "verilog") {
|
1233 |
|
|
&print(++$indent,"$nextstatevar\[$undefined_goto_state\] = 1'b1; // Added because undefined_states_go_here is set\n");
|
1234 |
|
|
}
|
1235 |
|
|
}
|
1236 |
|
|
&print(--$indent, "end\n");
|
1237 |
|
|
} elsif ($casedefault) {
|
1238 |
|
|
&print($indent,"default: ; // added because -casedefault is set\n");
|
1239 |
|
|
}
|
1240 |
|
|
&print(--$indent, "endcase\n");
|
1241 |
|
|
&print(--$indent, "end\n");
|
1242 |
|
|
|
1243 |
|
|
#######################
|
1244 |
|
|
# State sequential block
|
1245 |
|
|
#######################
|
1246 |
|
|
$section = "seq_block";
|
1247 |
|
|
&print($indent, "\n");
|
1248 |
|
|
|
1249 |
|
|
unless ($encoding eq "onehot") {
|
1250 |
|
|
&print($indent,"// Assign reg'd outputs to state bits\n");
|
1251 |
|
|
foreach $regout (sort {
|
1252 |
|
|
$reg_outputs{$a}{statebit_lower} <=>
|
1253 |
|
|
$reg_outputs{$b}{statebit_lower}
|
1254 |
|
|
} keys %reg_outputs) {
|
1255 |
|
|
# suppress [0:0]
|
1256 |
|
|
if ($total_statebits == 1) {
|
1257 |
|
|
&print($indent,"assign $regout = $statevar;\n");
|
1258 |
|
|
} else {
|
1259 |
|
|
&print($indent,"assign $regout = $statevar\[$reg_outputs{$regout}{statebit_range}\];\n");
|
1260 |
|
|
}
|
1261 |
|
|
}
|
1262 |
|
|
&print($indent,"\n");
|
1263 |
|
|
}
|
1264 |
|
|
|
1265 |
|
|
&print($indent, "// sequential always block\n");
|
1266 |
|
|
|
1267 |
|
|
# Create the always @ line using a sub so it can be used by datapath
|
1268 |
|
|
# as well.
|
1269 |
|
|
$line = &create_sequential_always;
|
1270 |
|
|
&print($indent++,"$line");
|
1271 |
|
|
|
1272 |
|
|
if ($reset_signal) {
|
1273 |
|
|
$bang = "!" if ($reset_edge =~ /neg/);
|
1274 |
|
|
&print($indent++,"if (${bang}${reset_signal})"); # no \n in case we add begin/end
|
1275 |
|
|
# Add begin if there are flags
|
1276 |
|
|
if (keys %flags) {
|
1277 |
|
|
&print(0," begin"); #
|
1278 |
|
|
}
|
1279 |
|
|
&print(0,"\n"); # add \n
|
1280 |
|
|
|
1281 |
|
|
if ($encoding eq "heros") {
|
1282 |
|
|
&print($indent,"$statevar <= $reset_state;\n");
|
1283 |
|
|
|
1284 |
|
|
} elsif ($encoding eq "onehot") {
|
1285 |
|
|
if ($language eq "systemverilog" || ($language eq "verilog" && $globals{machine}{default_state_is_x}{value})) {
|
1286 |
|
|
&print($indent,"$statevar <= $reset_state;\n");
|
1287 |
|
|
} elsif ($language eq "verilog") {
|
1288 |
|
|
&print($indent,"$statevar <= $zero_padded_one << $reset_state;\n");
|
1289 |
|
|
}
|
1290 |
|
|
}
|
1291 |
|
|
# Add flags
|
1292 |
|
|
foreach $flag (sort keys %flags) {
|
1293 |
|
|
# If value is defined in resetval, use it
|
1294 |
|
|
if ($globals{outputs}{$flag}{resetval} ne "") {
|
1295 |
|
|
&print($indent,"$flag <= $globals{outputs}{$flag}{resetval};\n");
|
1296 |
|
|
# Otherwise, use 0 and issue warning
|
1297 |
|
|
} else {
|
1298 |
|
|
&warning($indent,"No reset value set for flag $flag - using 0");
|
1299 |
|
|
&print($indent,"$flag <= $widths{$flag}'d0;\n");
|
1300 |
|
|
}
|
1301 |
|
|
}
|
1302 |
|
|
# Add end if there are flags
|
1303 |
|
|
if (keys %flags) {
|
1304 |
|
|
&print($indent,"end\n"); #
|
1305 |
|
|
}
|
1306 |
|
|
$indent--;
|
1307 |
|
|
|
1308 |
|
|
&print($indent,"else");
|
1309 |
|
|
}
|
1310 |
|
|
|
1311 |
|
|
# Else clause
|
1312 |
|
|
# Add begin if there are flags
|
1313 |
|
|
if (keys %flags) {
|
1314 |
|
|
&print(0," begin"); #
|
1315 |
|
|
}
|
1316 |
|
|
&print(0,"\n"); # add \n
|
1317 |
|
|
$indent++;
|
1318 |
|
|
&print($indent,"$statevar <= $nextstatevar;\n");
|
1319 |
|
|
# Add flags
|
1320 |
|
|
foreach $flag (sort keys %flags) {
|
1321 |
|
|
&print($indent,"$flag <= next_${flag};\n");
|
1322 |
|
|
}
|
1323 |
|
|
# Add end if there are flags
|
1324 |
|
|
if (keys %flags) {
|
1325 |
|
|
&print($indent,"end\n"); #
|
1326 |
|
|
}
|
1327 |
|
|
$indent--;
|
1328 |
|
|
|
1329 |
|
|
&print(--$indent,"end\n"); # end of always
|
1330 |
|
|
|
1331 |
|
|
#######################
|
1332 |
|
|
# Datapath sequential block
|
1333 |
|
|
#######################
|
1334 |
|
|
$section = "dp_seq_block";
|
1335 |
|
|
if (scalar(%regdp_outputs)) {
|
1336 |
|
|
&print($indent, "\n");
|
1337 |
|
|
|
1338 |
|
|
&print($indent, "// datapath sequential always block\n");
|
1339 |
|
|
|
1340 |
|
|
# Create the always @ line
|
1341 |
|
|
$line = &create_sequential_always;
|
1342 |
|
|
&print($indent++,"$line");
|
1343 |
|
|
|
1344 |
|
|
if ($reset_signal) {
|
1345 |
|
|
$bang = "!" if ($reset_edge =~ /neg/);
|
1346 |
|
|
&print($indent++,"if (${bang}${reset_signal}) begin\n");
|
1347 |
|
|
foreach $regdp_output (sort keys %regdp_outputs) {
|
1348 |
|
|
# Figure out a reset value
|
1349 |
|
|
|
1350 |
|
|
# This is different depending on whether this is a REAL regdp, or
|
1351 |
|
|
# a reg being treated as a regdp because we're in onehot
|
1352 |
|
|
$type = $globals{outputs}{$regdp_output}{type};
|
1353 |
|
|
|
1354 |
|
|
# If value is defined in resetval, use it
|
1355 |
|
|
if ($type eq "regdp" && $globals{outputs}{$regdp_output}{resetval} ne "") {
|
1356 |
|
|
$value = $globals{outputs}{$regdp_output}{resetval};
|
1357 |
|
|
|
1358 |
|
|
# If not, and a value exists in the reset state, use that and warn
|
1359 |
|
|
# Don't warn for type reg as this is the normal case.
|
1360 |
|
|
} elsif (exists $states{$reset_state}{attributes}{$regdp_output}{value}) {
|
1361 |
|
|
$value = $states{$reset_state}{attributes}{$regdp_output}{value};
|
1362 |
|
|
if ($type ne "reg") {
|
1363 |
|
|
&warning($indent,"No reset value set for datapath output $regdp_output. Assigning a reset value of $value based on value in reset state $reset_state");
|
1364 |
|
|
}
|
1365 |
|
|
|
1366 |
|
|
# Otherwise, use default value if there is one, and warn.
|
1367 |
|
|
} elsif ($regdp_outputs{$regdp_output}{default_value} ne "") {
|
1368 |
|
|
$value = $regdp_outputs{$regdp_output}{default_value};
|
1369 |
|
|
&warning($indent,"No reset value set for datapath output $regdp_output. Assigning a reset value of $value based on default");
|
1370 |
|
|
} else {
|
1371 |
|
|
$value = "$widths{$regdp_output}'d0;";
|
1372 |
|
|
&warning($indent,"No reset value could be determined for datapath output $regdp_output - using $value");
|
1373 |
|
|
}
|
1374 |
|
|
# Check that resulting value is non-null
|
1375 |
|
|
# Doesn't happen anymore due to 0 default above...
|
1376 |
|
|
# but maybe someday add a switch to disable reset to zero.
|
1377 |
|
|
&error($indent,"Reset value of datapath output $regdp_output cannot be determined ") if ($value eq "");
|
1378 |
|
|
&print($indent,"$regdp_output <= $value;\n");
|
1379 |
|
|
}
|
1380 |
|
|
&print(--$indent,"end\n");
|
1381 |
|
|
&print($indent++,"else begin\n");
|
1382 |
|
|
} else {
|
1383 |
|
|
&print(--$indent,"begin\n");
|
1384 |
|
|
}
|
1385 |
|
|
|
1386 |
|
|
# Output defaults.
|
1387 |
|
|
# To get better synth results "out of the box", use a 0 default if no
|
1388 |
|
|
# default is defined. To get the old "hold value in illegal states"
|
1389 |
|
|
# behavior, it will be necessary for the user to set the default to
|
1390 |
|
|
# be the variable name (ie, if the variable name is "foo", make the default
|
1391 |
|
|
# value "foo").
|
1392 |
|
|
foreach $regdp_output (sort keys %regdp_outputs) {
|
1393 |
|
|
if (exists $regdp_outputs{$regdp_output}{default_value} && ($regdp_outputs{$regdp_output}{default_value} ne "") ) {
|
1394 |
|
|
$dp_seq_defaults{$regdp_output} = $regdp_outputs{$regdp_output}{default_value};
|
1395 |
|
|
&print($indent,"$regdp_output <= $dp_seq_defaults{$regdp_output}; // default\n");
|
1396 |
|
|
} else {
|
1397 |
|
|
$dp_seq_defaults{$regdp_output} = "0"; # Use string zero
|
1398 |
|
|
&warning($indent,"Datapath output $regdp_output has no default value - using 0");
|
1399 |
|
|
&print($indent,"$regdp_output <= $dp_seq_defaults{$regdp_output}; // default to zero for better synth results (no default set in .fzm file)\n");
|
1400 |
|
|
#&print($indent,"$regdp_output <= $widths{$regdp_output}'b$dp_seq_defaults{$regdp_output}; // default to zero for better synth results (no default set in .fzm file)\n");
|
1401 |
|
|
}
|
1402 |
|
|
}
|
1403 |
|
|
|
1404 |
|
|
# State "case" block
|
1405 |
|
|
&print_case_statement($nextstatevar);
|
1406 |
|
|
|
1407 |
|
|
$keep_case = 0; # flag to keep case statement (at least one non-default found)
|
1408 |
|
|
foreach $state (@allstates) {
|
1409 |
|
|
$keep_state = 0; # flag to keep this state
|
1410 |
|
|
# Create state + begin (might be "popped" if $keep_state doesn't get set)
|
1411 |
|
|
if ($encoding eq "heros") {
|
1412 |
|
|
#&print($indent++,"$state: begin\n");
|
1413 |
|
|
&print($indent++,sprintf("%-${statename_length}s:",$state) . " begin\n");
|
1414 |
|
|
} elsif ($encoding eq "onehot") {
|
1415 |
|
|
if ($language eq "systemverilog" || ($language eq "verilog" && $globals{machine}{default_state_is_x}{value})) {
|
1416 |
|
|
&print($indent++,sprintf("%-${nextstatename_length_onehot}s:","$nextstatevar\[${state}_BIT\]") . " begin\n");
|
1417 |
|
|
} elsif ($language eq "verilog") {
|
1418 |
|
|
&print($indent++,sprintf("%-${nextstatename_length_onehot}s:","$nextstatevar\[$state\]") . " begin\n");
|
1419 |
|
|
}
|
1420 |
|
|
}
|
1421 |
|
|
# Search state attributes for regdp outputs. If a regdp output is found,
|
1422 |
|
|
# assign its value here
|
1423 |
|
|
foreach $regdp_output (sort keys %regdp_outputs) {
|
1424 |
|
|
if (exists $states{$state}{attributes}{$regdp_output}{value}) {
|
1425 |
|
|
$value = $states{$state}{attributes}{$regdp_output}{value};
|
1426 |
|
|
}
|
1427 |
|
|
if (exists($dp_seq_defaults{$regdp_output}) && ($value eq $dp_seq_defaults{$regdp_output})) {
|
1428 |
|
|
# skip - covered by default
|
1429 |
|
|
} else {
|
1430 |
|
|
# Check that resulting value is non-null
|
1431 |
|
|
&error($indent,"Value of regdp output $regdp_output cannot be determined in state $state") if ($value eq "");
|
1432 |
|
|
&print($indent,"$regdp_output <= $value;\n");
|
1433 |
|
|
$keep_state = 1;
|
1434 |
|
|
$keep_case = 1;
|
1435 |
|
|
}
|
1436 |
|
|
}
|
1437 |
|
|
|
1438 |
|
|
# If we did something here, output the end
|
1439 |
|
|
if ($keep_state) {
|
1440 |
|
|
&print(--$indent,"end\n"); # end of case match
|
1441 |
|
|
# Otherwise, pop the state + begin off the print buffer and clean up the indent.
|
1442 |
|
|
} else {
|
1443 |
|
|
$indent--;
|
1444 |
|
|
pop(@pbuf);
|
1445 |
|
|
}
|
1446 |
|
|
}
|
1447 |
|
|
|
1448 |
|
|
# Similarly, keep case and output endcase only if we found something no-default (flat is set)
|
1449 |
|
|
if ($keep_case) {
|
1450 |
|
|
if ($casedefault) {
|
1451 |
|
|
&print($indent,"default: ; // added because -casedefault is set\n");
|
1452 |
|
|
}
|
1453 |
|
|
&print(--$indent, "endcase\n");
|
1454 |
|
|
} else {
|
1455 |
|
|
pop(@pbuf);
|
1456 |
|
|
&warning($indent,"Did not find any non-default values for any datapath outputs - suppressing case statement");
|
1457 |
|
|
$indent--;
|
1458 |
|
|
}
|
1459 |
|
|
&print(--$indent,"end\n"); # end of if not reset
|
1460 |
|
|
&print(--$indent,"end\n"); # end of always
|
1461 |
|
|
}
|
1462 |
|
|
|
1463 |
|
|
#######################
|
1464 |
|
|
# State name-as-ascii block
|
1465 |
|
|
#######################
|
1466 |
|
|
if ($simcode) {
|
1467 |
|
|
$section = "ascii_block";
|
1468 |
|
|
&print($indent, "\n");
|
1469 |
|
|
&print($indent, "// This code allows you to see state names in simulation\n");
|
1470 |
|
|
#&print($indent, "// synopsys translate_off\n");
|
1471 |
|
|
&print($indent, "`ifndef SYNTHESIS\n");
|
1472 |
|
|
&print($indent, "reg [" . ($statename_length * 8 - 1) . ":0] $statenamevar;\n");
|
1473 |
|
|
&print($indent++, "always @* begin\n");
|
1474 |
|
|
|
1475 |
|
|
# State "case" block
|
1476 |
|
|
if ($encoding eq "heros") {
|
1477 |
|
|
&print($indent++,"case ($statevar)\n");
|
1478 |
|
|
} elsif ($encoding eq "onehot") {
|
1479 |
|
|
&print($indent++,"case (1\'b1)\n");
|
1480 |
|
|
}
|
1481 |
|
|
foreach $state (@allstates) {
|
1482 |
|
|
if ($encoding eq "heros") {
|
1483 |
|
|
&print($indent++,sprintf("%-${statename_length}s:",$state) . "\n");
|
1484 |
|
|
|
1485 |
|
|
} elsif ($encoding eq "onehot") {
|
1486 |
|
|
if ($language eq "systemverilog" || ($language eq "verilog" && $globals{machine}{default_state_is_x}{value})) {
|
1487 |
|
|
&print($indent++,sprintf("%-${statename_length_onehot}s:","$statevar\[${state}_BIT\]") . "\n");
|
1488 |
|
|
} elsif ($language eq "verilog") {
|
1489 |
|
|
&print($indent++,sprintf("%-${statename_length_onehot}s:","$statevar\[$state\]") . "\n");
|
1490 |
|
|
}
|
1491 |
|
|
}
|
1492 |
|
|
&print($indent++,"$statenamevar = \"$state\";\n");
|
1493 |
|
|
$indent--;
|
1494 |
|
|
$indent--;
|
1495 |
|
|
}
|
1496 |
|
|
# add default for X
|
1497 |
|
|
#&print($indent++,"default:\n");
|
1498 |
|
|
&print($indent++,sprintf("%-${statename_length}s:","default") . "\n");
|
1499 |
|
|
&print($indent++,sprintf("$statenamevar = \"%s\";\n", "X" x ($statename_length)));
|
1500 |
|
|
$indent--;
|
1501 |
|
|
$indent--;
|
1502 |
|
|
|
1503 |
|
|
&print(--$indent, "endcase\n");
|
1504 |
|
|
&print(--$indent, "end\n");
|
1505 |
|
|
|
1506 |
|
|
#&print($indent, "// synopsys translate_on\n\n");
|
1507 |
|
|
&print($indent, "`endif\n\n");
|
1508 |
|
|
}
|
1509 |
|
|
|
1510 |
|
|
if ($insert_at_bottom_of_module = "$globals{machine}{insert_at_bottom_of_module}{value}") {
|
1511 |
|
|
&print($indent,"// Inserted from attribute insert_at_bottom_of_module:\n");
|
1512 |
|
|
eval "\$myindent = \"$indentstring\" x $indent";
|
1513 |
|
|
$insert_at_bottom_of_module =~ s/(\n)/\1${myindent}/g; # put indent after any \n in the string
|
1514 |
|
|
&print($indent,"$insert_at_bottom_of_module\n");
|
1515 |
|
|
&print($indent,"\n");
|
1516 |
|
|
}
|
1517 |
|
|
|
1518 |
|
|
# endmodule and bottom-of-file
|
1519 |
|
|
|
1520 |
|
|
&print(--$indent,"endmodule\n");
|
1521 |
|
|
|
1522 |
|
|
&print($indent,"$globals{machine}{insert_at_bottom_of_file}{value}\n");
|
1523 |
|
|
|
1524 |
|
|
&print_output;
|
1525 |
|
|
|
1526 |
|
|
#######################################################################
|
1527 |
|
|
# Subroutines
|
1528 |
|
|
#######################################################################
|
1529 |
|
|
|
1530 |
|
|
# Create the wire/reg/logic statement. Routine is used by module port code
|
1531 |
|
|
# as well as suppress_portlist code.
|
1532 |
|
|
# argument is output to create statement for.
|
1533 |
|
|
# returns statement. Also sets range info globally.
|
1534 |
|
|
sub create_wirereg_statement {
|
1535 |
|
|
my ($prefix,$output,$suffix,$statement_length) = (@_);
|
1536 |
|
|
|
1537 |
|
|
# Handle comments
|
1538 |
|
|
if ($globals{outputs}{$output}{comment}) {
|
1539 |
|
|
$comment = "// $globals{outputs}{$output}{comment}";
|
1540 |
|
|
} else {
|
1541 |
|
|
$comment = "";
|
1542 |
|
|
}
|
1543 |
|
|
|
1544 |
|
|
|
1545 |
|
|
if ($language eq "verilog") {
|
1546 |
|
|
# Oddly, the comb outputs are reg's (because they will be assigned to
|
1547 |
|
|
# in the comb always block), but reg outputs are wire's (because they
|
1548 |
|
|
# will have continuous assignment to state bits). Regdp (registered
|
1549 |
|
|
# datapath) are reg's.
|
1550 |
|
|
if ($globals{outputs}{$output}{type} eq "comb") {
|
1551 |
|
|
$type = "reg";
|
1552 |
|
|
} elsif ($globals{outputs}{$output}{type} eq "reg") {
|
1553 |
|
|
if ($encoding eq "onehot") {
|
1554 |
|
|
$type = "reg";
|
1555 |
|
|
} else {
|
1556 |
|
|
$type = "wire";
|
1557 |
|
|
}
|
1558 |
|
|
} elsif ($globals{outputs}{$output}{type} eq "regdp") {
|
1559 |
|
|
$type = "reg";
|
1560 |
|
|
} elsif ($globals{outputs}{$output}{type} eq "flag") {
|
1561 |
|
|
$type = "reg";
|
1562 |
|
|
} else {
|
1563 |
|
|
&error($indent,"No type found for output $output");
|
1564 |
|
|
}
|
1565 |
|
|
} elsif ($language eq "systemverilog") {
|
1566 |
|
|
# In sv, everything is type logic
|
1567 |
|
|
$type = "logic";
|
1568 |
|
|
}
|
1569 |
|
|
|
1570 |
|
|
# Handle multibit outputs
|
1571 |
|
|
if (($name,$range) = ($output =~ /^([^\[]+)\s*(\[.*\])/)) {
|
1572 |
|
|
$line = sprintf("%-${statement_length}s %-s\n","${prefix}$type $range $name${suffix}",$comment);
|
1573 |
|
|
($upper,$lower) = $range =~ /(\d+):(\d+)/;
|
1574 |
|
|
$widths{$name} = abs($upper - $lower) + 1;
|
1575 |
|
|
} else {
|
1576 |
|
|
$line = sprintf("%-${statement_length}s %-s\n","${prefix}$type $output${suffix}",$comment);
|
1577 |
|
|
$widths{$output} = 1;
|
1578 |
|
|
}
|
1579 |
|
|
# Remove trailing blanks
|
1580 |
|
|
$line =~ s/\s*\n$/\n/;
|
1581 |
|
|
return($line);
|
1582 |
|
|
}
|
1583 |
|
|
|
1584 |
|
|
sub print_case_statement {
|
1585 |
|
|
# Print the case statement.
|
1586 |
|
|
my ($casevar) = (@_);
|
1587 |
|
|
|
1588 |
|
|
# For heros, it's pretty simple:
|
1589 |
|
|
if ($encoding eq "heros") {
|
1590 |
|
|
&print($indent++,"case ($casevar)\n");
|
1591 |
|
|
|
1592 |
|
|
# For onehot, it is based on the onehot pragma and the language
|
1593 |
|
|
# In verilog, defaults to "case (1'b1) synopsys parallel_case full_case".
|
1594 |
|
|
# In systemverilog, defaults to "unique case (1'b1)".
|
1595 |
|
|
# If pragma is set, always use "case (1'b1) // pragma", regardless
|
1596 |
|
|
# of language.
|
1597 |
|
|
} elsif ($encoding eq "onehot") {
|
1598 |
|
|
if (exists $globals{machine}{onehot_pragma}{value} ) {
|
1599 |
|
|
&warning($indent,"Using override value from attribute onehot_pragma");
|
1600 |
|
|
$pragma = $globals{machine}{onehot_pragma}{value};
|
1601 |
|
|
&print($indent++,"case (1'b1) // $pragma\n");
|
1602 |
|
|
} elsif ($language eq "verilog") {
|
1603 |
|
|
&print($indent++,"case (1'b1) // synopsys parallel_case full_case\n");
|
1604 |
|
|
} elsif ($language eq "systemverilog") {
|
1605 |
|
|
&print($indent++,"unique case (1'b1)\n");
|
1606 |
|
|
}
|
1607 |
|
|
}
|
1608 |
|
|
}
|
1609 |
|
|
|
1610 |
|
|
sub create_sequential_always {
|
1611 |
|
|
# Check to make sure clock data is ok
|
1612 |
|
|
if (exists $globals{machine}{clock}{value}) {
|
1613 |
|
|
$clk = $globals{machine}{clock}{value};
|
1614 |
|
|
} else {
|
1615 |
|
|
&error($indent,"No clock specified");
|
1616 |
|
|
}
|
1617 |
|
|
if (! exists $globals{inputs}{$clk}) {
|
1618 |
|
|
#&warning($indent,"Specified clock signal $clk is not an input");
|
1619 |
|
|
&error($indent,"Specified clock signal $clk is not an input");
|
1620 |
|
|
}
|
1621 |
|
|
if ($globals{machine}{clock}{type} !~ /^(pos)|(neg)edge$/) {
|
1622 |
|
|
&error($indent,"Clock type not specified as posedge or negedge");
|
1623 |
|
|
}
|
1624 |
|
|
# Build clock portion of always @(posedge...)
|
1625 |
|
|
if ($language eq "verilog") {
|
1626 |
|
|
$line = "always @(";
|
1627 |
|
|
} elsif ($language eq "systemverilog") {
|
1628 |
|
|
$line = "always_ff @(";
|
1629 |
|
|
}
|
1630 |
|
|
$line = $line . "$globals{machine}{clock}{type} $clk" ;
|
1631 |
|
|
|
1632 |
|
|
# Add reset if given
|
1633 |
|
|
if (exists $globals{machine}{reset_signal}{value}) {
|
1634 |
|
|
$reset_signal = $globals{machine}{reset_signal}{value};
|
1635 |
|
|
if (! exists $globals{inputs}{$reset_signal}) {
|
1636 |
|
|
#&warning($indent,"Specified reset signal $reset_signal is not an input");
|
1637 |
|
|
&error($indent,"Specified reset signal $reset_signal is not an input");
|
1638 |
|
|
}
|
1639 |
|
|
if ($globals{machine}{reset_signal}{type} =~ /^((neg)|(pos))edge$/) {
|
1640 |
|
|
$sync = "async";
|
1641 |
|
|
} elsif ($globals{machine}{reset_signal}{type} eq "positive") {
|
1642 |
|
|
$sync = "sync";
|
1643 |
|
|
} elsif ($globals{machine}{reset_signal}{type} eq "negative") {
|
1644 |
|
|
$sync = "sync";
|
1645 |
|
|
} else {
|
1646 |
|
|
&error($indent,"reset_signal $reset_signal not specified as type posedge, negedge, positive or negative");
|
1647 |
|
|
}
|
1648 |
|
|
$reset_edge = $globals{machine}{reset_signal}{type};
|
1649 |
|
|
if ($sync eq "async") {
|
1650 |
|
|
$line = $line . " or $reset_edge $reset_signal";
|
1651 |
|
|
}
|
1652 |
|
|
if (! exists $globals{machine}{reset_state}{value}) {
|
1653 |
|
|
&error($indent,"Reset signal given, but no reset state found.");
|
1654 |
|
|
} else {
|
1655 |
|
|
$reset_state = $globals{machine}{reset_state}{value};
|
1656 |
|
|
}
|
1657 |
|
|
}
|
1658 |
|
|
return $line = $line . ") begin\n";
|
1659 |
|
|
}
|
1660 |
|
|
|
1661 |
|
|
sub sort_by_priority_then_equation_equal_1 {
|
1662 |
|
|
#&debug("a priority: $a -> $transitions{$a}{attributes}{priority}{value}",0,$section);
|
1663 |
|
|
#&debug("a equation: $a -> $transitions{$a}{attributes}{equation}{value}",0,$section);
|
1664 |
|
|
#&debug("a: $a -> $a",0,$section);
|
1665 |
|
|
#&debug("b priority: $b -> $transitions{$b}{attributes}{priority}{value}",0,$section);
|
1666 |
|
|
#&debug("b equation: $b -> $transitions{$b}{attributes}{equation}{value}",0,$section);
|
1667 |
|
|
#&debug("b: $a -> $b",0,$section);
|
1668 |
|
|
# &debug("priority sort result is: " . $transitions{$a}{attributes}{priority}{value} <=> $transitions{$b}{attributes}{priority}{value},0,$section);
|
1669 |
|
|
|
1670 |
|
|
$transitions{$a}{attributes}{priority}{value} <=>
|
1671 |
|
|
$transitions{$b}{attributes}{priority}{value}
|
1672 |
|
|
||
|
1673 |
|
|
($transitions{$a}{attributes}{equation}{value} eq "1") cmp
|
1674 |
|
|
($transitions{$b}{attributes}{equation}{value} eq "1")
|
1675 |
|
|
# finally, sort by trans name just so order will be predictable
|
1676 |
|
|
||
|
1677 |
|
|
$a cmp $b
|
1678 |
|
|
}
|
1679 |
|
|
|
1680 |
|
|
|
1681 |
|
|
sub parse_input {
|
1682 |
|
|
|
1683 |
|
|
my %myattributes_forcompare;
|
1684 |
|
|
|
1685 |
|
|
&debug("Start of parse_input\"$_\"",0,"parse_input");
|
1686 |
|
|
|
1687 |
|
|
# Create local version of myattributes with substition done to enable
|
1688 |
|
|
# compares
|
1689 |
|
|
foreach $entry (keys %myattributes) {
|
1690 |
|
|
$entry =~ s/\*[^\*]*\*/[^\"]+/g;
|
1691 |
|
|
$myattributes_forcompare{$entry} = 1;
|
1692 |
|
|
}
|
1693 |
|
|
|
1694 |
|
|
while (<>) {
|
1695 |
|
|
chomp;
|
1696 |
|
|
s/##.*$// ;# Remove comments
|
1697 |
|
|
s/^\s*//; # Remove leading whitespace
|
1698 |
|
|
|
1699 |
|
|
# Toss status/endstatus
|
1700 |
|
|
if (/^\s*<status>/) {
|
1701 |
|
|
until (/^\s*<\/status>/) {
|
1702 |
|
|
$_ = <>;
|
1703 |
|
|
}
|
1704 |
|
|
next;
|
1705 |
|
|
}
|
1706 |
|
|
|
1707 |
|
|
# Ignore drawArea (strips this level entirely from out data
|
1708 |
|
|
# structures)
|
1709 |
|
|
next if (/drawArea/);
|
1710 |
|
|
|
1711 |
|
|
# Look for endtoken first to allow elsif to handle token case
|
1712 |
|
|
if (($endtoken) = (/^\s*<\/(.*)>/)) {
|
1713 |
|
|
&debug("endtoken: $endtoken from \"$_\"",0,"parse_input");
|
1714 |
|
|
&debug("ptr was \"$ptr\"",0,"parse_input");
|
1715 |
|
|
# Found an endtoken. If this is the array, clear the array value.
|
1716 |
|
|
# Otherwise, remove everything from this token to the end from ptr.
|
1717 |
|
|
if ($array eq $endtoken) {
|
1718 |
|
|
$array = "";
|
1719 |
|
|
$ptr = "";
|
1720 |
|
|
} else {
|
1721 |
|
|
$ptr =~ s/{\"\Q$endtoken\E\"}.*$//;
|
1722 |
|
|
}
|
1723 |
|
|
&debug("new array is \"${array}\"",0,"parse_input");
|
1724 |
|
|
&debug("new ptr is \"${ptr}\"",0,"parse_input");
|
1725 |
|
|
&debug("",0,"parse_input");
|
1726 |
|
|
} elsif (($token) = (/^\s*<(.*)>/)) {
|
1727 |
|
|
&debug("token: $token from \"$_\"",0,"parse_input");
|
1728 |
|
|
# Found new token. If array is blank, this is the new array.
|
1729 |
|
|
# Otherwise, append to ptr.
|
1730 |
|
|
if ($array eq "") {
|
1731 |
|
|
$array = "$token";
|
1732 |
|
|
} else {
|
1733 |
|
|
$ptr = $ptr . "{\"$token\"}";
|
1734 |
|
|
}
|
1735 |
|
|
&debug("new array is \"${array}\"",0,"parse_input");
|
1736 |
|
|
&debug("new ptr is \"${ptr}\"",0,"parse_input");
|
1737 |
|
|
&debug("",0,"parse_input");
|
1738 |
|
|
} else {
|
1739 |
|
|
$value = $_;
|
1740 |
|
|
&debug("value: $value from \"$_\"",0,"parse_input");
|
1741 |
|
|
# Found a value instead of a token. Use array and ptr to set
|
1742 |
|
|
# the value using eval.
|
1743 |
|
|
# First, turn state name (or transition name) into index
|
1744 |
|
|
&debug("old ptr (in value block) is \"$ptr\"",0,"parse_input");
|
1745 |
|
|
if ($ptr =~ s/({\"attributes\"}).*name.*value\"}/{\"$value\"}\1/) {
|
1746 |
|
|
# If this already exists, it means we have a duplicate entry!
|
1747 |
|
|
if (exists $${array}{"$value"}{"attributes"}) {
|
1748 |
|
|
&error($indent,"Error - found duplicate entry for $array $value");
|
1749 |
|
|
}
|
1750 |
|
|
&debug("new ptr (in value block) is \"$ptr\"",0,"parse_input");
|
1751 |
|
|
} else {
|
1752 |
|
|
$keep = 0;
|
1753 |
|
|
foreach $entry (keys %myattributes_forcompare) {
|
1754 |
|
|
#print STDERR "Looking at myatt $entry\n";
|
1755 |
|
|
#print STDERR " comparing to ${array}${ptr}\n";
|
1756 |
|
|
if ("${array}${ptr}" =~ $entry) {
|
1757 |
|
|
&debug("Got match to $entry\n",0,"parse_input");
|
1758 |
|
|
$keep = 1;
|
1759 |
|
|
}
|
1760 |
|
|
}
|
1761 |
|
|
#$cmd = "\$${array}${ptr} = q{${value}};";
|
1762 |
|
|
$value =~ s/"/\\"/g; # escape quotes for next line
|
1763 |
|
|
$value =~ s/\$/\\\$/g; # escape $ signs (in case code has $time...)
|
1764 |
|
|
|
1765 |
|
|
$cmd = "\$${array}${ptr} = \"$value\";";
|
1766 |
|
|
if ($keep) {
|
1767 |
|
|
&debug("cmd is \"$cmd\"",0,"parse_input");
|
1768 |
|
|
eval $cmd unless (!$array);
|
1769 |
|
|
} else {
|
1770 |
|
|
&debug("skipped cmd \"$cmd\"",0,"parse_input");
|
1771 |
|
|
}
|
1772 |
|
|
}
|
1773 |
|
|
}
|
1774 |
|
|
}
|
1775 |
|
|
|
1776 |
|
|
&debug("End of parse_input\"$_\"\n\n",0,"parse_input");
|
1777 |
|
|
|
1778 |
|
|
# Check some random values
|
1779 |
|
|
#&debug("state0 vis is $states{state0}{attributes}{vis}",0,"parse_input");
|
1780 |
|
|
#&debug("trans0 startState is $transitions{trans0}{startState}",0,"parse_input");
|
1781 |
|
|
#&debug("trans0 endState is $transitions{trans0}{endState}",0,"parse_input");
|
1782 |
|
|
}
|
1783 |
|
|
|
1784 |
|
|
sub assign_states_hero {
|
1785 |
|
|
my ($state);
|
1786 |
|
|
# print &dec2bin(1,5) . "\n";
|
1787 |
|
|
# print &dec2bin(17,5) . "\n";
|
1788 |
|
|
# @statevals = &get_statevals(5); # create global statevals
|
1789 |
|
|
# print "@statevals\n";
|
1790 |
|
|
# exit;
|
1791 |
|
|
|
1792 |
|
|
&debug("Starting assign_states_hero",0,"assign_states");
|
1793 |
|
|
|
1794 |
|
|
$as_iterations = 0;
|
1795 |
|
|
for ($bits = $minbits ; $bits <= $maxbits ; $bits++) {
|
1796 |
|
|
&debug("Trying $bits bits for states",0,"bits");
|
1797 |
|
|
&debug("Trying $bits bits for states",0,"assign_states");
|
1798 |
|
|
&verbose("Trying $bits bits for states",0,"");
|
1799 |
|
|
@statevals = &get_statevals($bits); # create global statevals
|
1800 |
|
|
&debug("statevals: @statevals",0,"assign_states");
|
1801 |
|
|
#print STDERR "statevals: @statevals\n";
|
1802 |
|
|
# Pre-determine legal state values for each state
|
1803 |
|
|
# This is much faster than checking all of them.
|
1804 |
|
|
%legal_statevals = ();
|
1805 |
|
|
foreach $state (@allstates) {
|
1806 |
|
|
STATEVAL : foreach $stateval (@statevals) {
|
1807 |
|
|
if (&matches_fixedbits($state,$stateval)) {
|
1808 |
|
|
push(@{ $legal_statevals{$state} }, $stateval);
|
1809 |
|
|
}
|
1810 |
|
|
}
|
1811 |
|
|
#print "$state @{ $legal_statevals{$state} }\n";
|
1812 |
|
|
&debug("legal values for state $state: @{ $legal_statevals{$state} }",0,"assign_states");
|
1813 |
|
|
}
|
1814 |
|
|
# Call recursive subroutine to assign states
|
1815 |
|
|
($success,$uaref,$v2nref) = &attempt_assign_states( \@allstates, \%state_val2name, 0);
|
1816 |
|
|
if ($success) {
|
1817 |
|
|
&debug("Found successful assignment with $bits bits",0,"assign_states");
|
1818 |
|
|
&verbose("Found successful assignment with $bits bits after $as_iterations iterations",0,"assign_states");
|
1819 |
|
|
last;
|
1820 |
|
|
}
|
1821 |
|
|
}
|
1822 |
|
|
|
1823 |
|
|
if (!$success) {
|
1824 |
|
|
$maxbitsplusone = $maxbits + 1;
|
1825 |
|
|
&error($indent,"No valid state assignment found in range of $minbits to $maxbits bits - try using -minbits $maxbitsplusone -maxbits $maxbitsplusone on the command line or in be_cmd.");
|
1826 |
|
|
}
|
1827 |
|
|
|
1828 |
|
|
}
|
1829 |
|
|
|
1830 |
|
|
sub attempt_assign_states {
|
1831 |
|
|
my ($uaref,$v2nref,$depth) = @_;
|
1832 |
|
|
my (@unassigned_states);
|
1833 |
|
|
my (%state_val2name);
|
1834 |
|
|
my ($state,$stateval);
|
1835 |
|
|
|
1836 |
|
|
# Dereference arguments into local data structures
|
1837 |
|
|
@unassigned_states = @$uaref;
|
1838 |
|
|
%state_val2name = %$v2nref;
|
1839 |
|
|
|
1840 |
|
|
if ($as_iterations >= $max_iterations) {
|
1841 |
|
|
if ($bits == $minbits) {
|
1842 |
|
|
&error($indent,"No valid state assignment found after $as_iterations iterations. Try increasing max iterations using -iterations");
|
1843 |
|
|
} else {
|
1844 |
|
|
&error($indent,"No valid state assignment found after $as_iterations iterations. Try using -minbits $bits or increase max iterations using -iterations");
|
1845 |
|
|
}
|
1846 |
|
|
}
|
1847 |
|
|
$as_iterations++;
|
1848 |
|
|
|
1849 |
|
|
&debug("attempt_assign_states called with unassigned states \"@unassigned_states\", depth=$depth",$depth,"assign_states");
|
1850 |
|
|
#if ($depth > 16) { exit; } # temp
|
1851 |
|
|
&debug("attempt_assign_states iterations: $as_iterations",$depth,"assign_states");
|
1852 |
|
|
foreach $temp (sort keys %state_val2name) {
|
1853 |
|
|
&debug("$temp: $state_val2name{$temp}",$depth,"assign_states");
|
1854 |
|
|
}
|
1855 |
|
|
|
1856 |
|
|
while ($state = shift(@unassigned_states)) {
|
1857 |
|
|
&debug("attempt_assign_states working on state $state",$depth,"assign_states");
|
1858 |
|
|
STATEVAL : foreach $stateval (@{ $legal_statevals{$state} }) {
|
1859 |
|
|
&debug("attempt_assign_states looking at stateval $stateval for uniqueness",$depth,"assign_states");
|
1860 |
|
|
next if ($state_val2name{$stateval}); # must be unique
|
1861 |
|
|
&debug("attempt_assign_states trying stateval $stateval for state $state",$depth,"assign_states");
|
1862 |
|
|
if (!$design_has_graycodes || &matches_graycodes($state,$stateval,%state_val2name)) {
|
1863 |
|
|
# looks good at this level
|
1864 |
|
|
&debug("$stateval for state $state passes checks at this level $depth",$depth,"assign_states");
|
1865 |
|
|
$state_val2name{$stateval} = $state;
|
1866 |
|
|
if (!@unassigned_states) { # if nothing left, we're done
|
1867 |
|
|
&debug("attempt_assign_states returning success",$depth,"assign_states");
|
1868 |
|
|
return (1, \@unassigned_states, \%state_val2name);
|
1869 |
|
|
} else { # otherwise, keep trying recursively
|
1870 |
|
|
$depth++;
|
1871 |
|
|
($found_state,$uaref1,$v2nref1) = &attempt_assign_states( \@unassigned_states, \%state_val2name,$depth);
|
1872 |
|
|
&debug("Call for $state value $stateval returned $found",$depth,"assign_states");
|
1873 |
|
|
|
1874 |
|
|
}
|
1875 |
|
|
if ($found_state) { # good right the way down
|
1876 |
|
|
&debug("good right the way down",0,"assign_states");
|
1877 |
|
|
%state_val2name = %$v2nref1;
|
1878 |
|
|
last STATEVAL;
|
1879 |
|
|
} else {
|
1880 |
|
|
&debug("stateval $stateval for state $state looked good, but failed recursively - trying next",$depth,"assign_states");
|
1881 |
|
|
delete $state_val2name{$stateval};
|
1882 |
|
|
$depth--;
|
1883 |
|
|
}
|
1884 |
|
|
} else {
|
1885 |
|
|
$found_state = 0;
|
1886 |
|
|
&debug("assignment failed fixedbits check",0,"assign_states");
|
1887 |
|
|
}
|
1888 |
|
|
}
|
1889 |
|
|
return ($found_state, \@unassigned_states, \%state_val2name);
|
1890 |
|
|
}
|
1891 |
|
|
}
|
1892 |
|
|
|
1893 |
|
|
sub matches_fixedbits {
|
1894 |
|
|
my ($state,$stateval) = @_;
|
1895 |
|
|
|
1896 |
|
|
# Use a bit index that runs right to left
|
1897 |
|
|
for ($bit = 0 ; $bit < length($stateval) ; $bit++) {
|
1898 |
|
|
$substrbit = length($stateval) - $bit - 1 ;
|
1899 |
|
|
&debug("matches_fixbits looking at bit $bit of $stateval (" . substr($stateval,$substrbit,1) . ") for $state",$depth,"mf");
|
1900 |
|
|
if ( (exists $fixedbits{$state}{$bit})
|
1901 |
|
|
&& ($fixedbits{$state}{$bit} ne (substr($stateval,$substrbit,1))) ) {
|
1902 |
|
|
&debug("matches_fixbits found an illegal value at bit $bit of $stateval for $state",$depth,"mf");
|
1903 |
|
|
return 0;
|
1904 |
|
|
}
|
1905 |
|
|
}
|
1906 |
|
|
return 1;
|
1907 |
|
|
}
|
1908 |
|
|
|
1909 |
|
|
sub matches_graycodes {
|
1910 |
|
|
my ($state,$stateval,%state_val2name) = @_;
|
1911 |
|
|
return ( &matches_graycodes_to_this_state($state,$stateval,%state_val2name)
|
1912 |
|
|
&& &matches_graycodes_from_this_state($state,$stateval,%state_val2name) );
|
1913 |
|
|
}
|
1914 |
|
|
|
1915 |
|
|
sub matches_graycodes_to_this_state {
|
1916 |
|
|
my ($state,$stateval,%state_val2name) = @_;
|
1917 |
|
|
my ($otherstateval,$graystate);
|
1918 |
|
|
|
1919 |
|
|
# look at each currently defined state (in state_val2name)
|
1920 |
|
|
foreach $otherstateval (keys %state_val2name) {
|
1921 |
|
|
$otherstate = $state_val2name{$otherstateval}; # get the name
|
1922 |
|
|
if (exists $graytransitions{$otherstate}) { # if it has a gray list
|
1923 |
|
|
foreach $graystate (@{ $graytransitions{$otherstate} }) { # look through the list
|
1924 |
|
|
if ($graystate eq $state) { #I'm in his list
|
1925 |
|
|
&debug("matches_graycodes_to_this_state checking $graystate ($otherstateval) against $state ($stateval)",$depth,"mgto");
|
1926 |
|
|
# check to see if it is legal
|
1927 |
|
|
if (!&isgraytransition($stateval,$otherstateval)) {
|
1928 |
|
|
return 0;
|
1929 |
|
|
}
|
1930 |
|
|
}
|
1931 |
|
|
}
|
1932 |
|
|
}
|
1933 |
|
|
}
|
1934 |
|
|
return 1; # if nothing illegal found, all must be legal
|
1935 |
|
|
}
|
1936 |
|
|
|
1937 |
|
|
sub matches_graycodes_from_this_state {
|
1938 |
|
|
my ($state,$stateval,%state_val2name) = @_;
|
1939 |
|
|
my ($otherstateval,$graystate);
|
1940 |
|
|
|
1941 |
|
|
# look at each state that should be a gray transition from this state
|
1942 |
|
|
return 1 if (!exists $graytransitions{$state});
|
1943 |
|
|
foreach $graystate (@{ $graytransitions{$state} }) {
|
1944 |
|
|
&debug("matches_graycodes_from_this_state looking at gray state $graystate for state $state",$depth,"mgfrom");
|
1945 |
|
|
# find the encoding for the gray state
|
1946 |
|
|
foreach $otherstateval (keys %state_val2name) {
|
1947 |
|
|
&debug("matches_graycodes_from_this_state looking at otherstateval $otherstateval",$depth,"mgfrom");
|
1948 |
|
|
if ($state_val2name{$otherstateval} eq $graystate) {
|
1949 |
|
|
&debug("Checking $graystate ($otherstateval) against $state ($stateval)",$depth,"mgfrom");
|
1950 |
|
|
# check to see if it is legal
|
1951 |
|
|
if (!&isgraytransition($stateval,$otherstateval)) {
|
1952 |
|
|
return 0;
|
1953 |
|
|
}
|
1954 |
|
|
}
|
1955 |
|
|
}
|
1956 |
|
|
}
|
1957 |
|
|
return 1; # if nothing illegal found, all must be legal
|
1958 |
|
|
}
|
1959 |
|
|
|
1960 |
|
|
sub isgraytransition {
|
1961 |
|
|
my ($stateval1,$stateval2) = @_;
|
1962 |
|
|
my ($diffs);
|
1963 |
|
|
|
1964 |
|
|
# using perl's normal left to right bit order
|
1965 |
|
|
&debug("isgraytransition checking $stateval1 against $stateval2",$depth,"isgraytrans");
|
1966 |
|
|
for ($bit = 0 ; $bit < length($stateval1) ; $bit++) {
|
1967 |
|
|
if (substr($stateval1,$bit,1) ne substr($stateval2,$bit,1)) {
|
1968 |
|
|
$diffs++
|
1969 |
|
|
}
|
1970 |
|
|
}
|
1971 |
|
|
&debug("isgraytransition found $diffs diffs",$depth,"isgraytrans");
|
1972 |
|
|
return ($diffs <= 1);
|
1973 |
|
|
}
|
1974 |
|
|
|
1975 |
|
|
sub required_bits {
|
1976 |
|
|
my ($n) = @_;
|
1977 |
|
|
$div= log($n) / log(2);
|
1978 |
|
|
$base = sprintf("%d",$div);
|
1979 |
|
|
if (($div - $base) > 0) {$base++;}
|
1980 |
|
|
return $base;
|
1981 |
|
|
}
|
1982 |
|
|
|
1983 |
|
|
|
1984 |
|
|
sub hex2bin {
|
1985 |
|
|
my ($hex) = @_;
|
1986 |
|
|
my ($bin,$i);
|
1987 |
|
|
|
1988 |
|
|
%hex2bin = ( 0 => "0000",
|
1989 |
|
|
1 => "0001",
|
1990 |
|
|
2 => "0010",
|
1991 |
|
|
3 => "0011",
|
1992 |
|
|
4 => "0100",
|
1993 |
|
|
5 => "0101",
|
1994 |
|
|
6 => "0110",
|
1995 |
|
|
7 => "0111",
|
1996 |
|
|
8 => "1000",
|
1997 |
|
|
9 => "1001",
|
1998 |
|
|
a => "1010",
|
1999 |
|
|
b => "1011",
|
2000 |
|
|
c => "1100",
|
2001 |
|
|
d => "1101",
|
2002 |
|
|
e => "1110",
|
2003 |
|
|
f => "1111",
|
2004 |
|
|
A => "1010",
|
2005 |
|
|
B => "1011",
|
2006 |
|
|
C => "1100",
|
2007 |
|
|
D => "1101",
|
2008 |
|
|
E => "1110",
|
2009 |
|
|
F => "1111",
|
2010 |
|
|
);
|
2011 |
|
|
|
2012 |
|
|
for ($i = 0; $i < length($hex) ; $i++) {
|
2013 |
|
|
$bin = $bin . $hex2bin{substr($hex,$i,1)};
|
2014 |
|
|
}
|
2015 |
|
|
return $bin;
|
2016 |
|
|
}
|
2017 |
|
|
|
2018 |
|
|
sub octal2bin {
|
2019 |
|
|
my ($octal) = @_;
|
2020 |
|
|
my ($bin,$i);
|
2021 |
|
|
|
2022 |
|
|
%octal2bin = ( 0 => "000",
|
2023 |
|
|
1 => "001",
|
2024 |
|
|
2 => "010",
|
2025 |
|
|
3 => "011",
|
2026 |
|
|
4 => "100",
|
2027 |
|
|
5 => "101",
|
2028 |
|
|
6 => "110",
|
2029 |
|
|
7 => "111",
|
2030 |
|
|
);
|
2031 |
|
|
|
2032 |
|
|
for ($i = 0; $i < length($octal) ; $i++) {
|
2033 |
|
|
$bin = $bin . $octal2bin{substr($octal,$i,1)};
|
2034 |
|
|
}
|
2035 |
|
|
return $bin;
|
2036 |
|
|
}
|
2037 |
|
|
|
2038 |
|
|
sub dec2bin {
|
2039 |
|
|
my ($dec,$bits) = @_;
|
2040 |
|
|
my ($hex,$bin,$i);
|
2041 |
|
|
|
2042 |
|
|
$hex = sprintf("%x",$dec);
|
2043 |
|
|
#print "hex is $hex\n";
|
2044 |
|
|
$bin = &hex2bin($hex);
|
2045 |
|
|
#print "bin is $bin\n";
|
2046 |
|
|
# Strip leading zeros
|
2047 |
|
|
$bin =~ s/^0*//;
|
2048 |
|
|
$bin = "0" if ($bin eq "");
|
2049 |
|
|
# Zero extend according to requested bitlength
|
2050 |
|
|
#print "dec2bin bin was $bin\n";
|
2051 |
|
|
if ($bits) {
|
2052 |
|
|
$bin = "0" x ($bits - length($bin)) . $bin;
|
2053 |
|
|
}
|
2054 |
|
|
#print "dec2bin extended bin is $bin\n";
|
2055 |
|
|
if ($bits) {
|
2056 |
|
|
substr($bin,length($bin) - $bits,$bits);
|
2057 |
|
|
}
|
2058 |
|
|
#print "dec2bin extended bin with bits applied is $bin\n";
|
2059 |
|
|
return $bin
|
2060 |
|
|
}
|
2061 |
|
|
|
2062 |
|
|
sub convert2bin {
|
2063 |
|
|
my ($value,$check) = @_;
|
2064 |
|
|
my ($bits,$val);
|
2065 |
|
|
my $bitlen = "";
|
2066 |
|
|
|
2067 |
|
|
#print "Starting convert2bin on value \"$value\n";
|
2068 |
|
|
|
2069 |
|
|
if (($bitlen,$format,$val) = ($value =~ /^(?:(\d*))?'(?:([bdoh]))?([0-9a-fA-F]*)$/)) {
|
2070 |
|
|
} elsif (($val) = ($value =~ /^(\d+)$/)) {
|
2071 |
|
|
$format = "d" unless ($format);
|
2072 |
|
|
} else {
|
2073 |
|
|
$format = "b" unless ($format);
|
2074 |
|
|
$val = $value;
|
2075 |
|
|
}
|
2076 |
|
|
#print "value: $value: bitlen: $bitlen format: $format val: $val\n";
|
2077 |
|
|
if ($format eq "b") {
|
2078 |
|
|
#print "converted a bin $value: bitlen: $bitlen format: $format val: $val\n";
|
2079 |
|
|
$bitlen = length($val) unless ($bitlen); # default length
|
2080 |
|
|
if ($bitlen != length($val)) {
|
2081 |
|
|
&error($indent,"Binary value $value has a size that doesn't match the value");
|
2082 |
|
|
}
|
2083 |
|
|
$value = substr($val,length($val) - $bitlen,$bitlen);
|
2084 |
|
|
} elsif ($format eq "h") {
|
2085 |
|
|
#print "converted a hex $value: bitlen: $bitlen format: $format val: $val\n";
|
2086 |
|
|
$bitlen = 4 * length($val) unless ($bitlen); # default length
|
2087 |
|
|
$value = &hex2bin($val);
|
2088 |
|
|
# Zero extend
|
2089 |
|
|
#print "value was $value\n";
|
2090 |
|
|
$value = "0" x ($bitlen - length($value)) . $value;
|
2091 |
|
|
#print "value extended is $value\n";
|
2092 |
|
|
$value = substr($value,length($value) - $bitlen,$bitlen);
|
2093 |
|
|
} elsif ($format eq "o") {
|
2094 |
|
|
#print "converted a octal $value: bitlen: $bitlen format: $format val: $val\n";
|
2095 |
|
|
$bitlen = 3 * length($val) unless ($bitlen); # default length
|
2096 |
|
|
$value = &octal2bin($val);
|
2097 |
|
|
$value = substr($value,length($value) - $bitlen,$bitlen);
|
2098 |
|
|
} elsif ($format eq "d") {
|
2099 |
|
|
#print "converted a dec $value: bitlen: $bitlen format: $format val: $val ";
|
2100 |
|
|
$value = &dec2bin($val,$bitlen);
|
2101 |
|
|
#print "to $value\n";
|
2102 |
|
|
} else {
|
2103 |
|
|
&error($indent,"Got an unrecognized format $format in convert2bin") unless (!$check);
|
2104 |
|
|
}
|
2105 |
|
|
|
2106 |
|
|
#print "returning $value\n";
|
2107 |
|
|
#print "\n";
|
2108 |
|
|
return $value;
|
2109 |
|
|
}
|
2110 |
|
|
|
2111 |
|
|
sub get_statevals {
|
2112 |
|
|
my($bits) = @_;
|
2113 |
|
|
my(@statevals);
|
2114 |
|
|
my($i);
|
2115 |
|
|
my($bin);
|
2116 |
|
|
|
2117 |
|
|
for ($i = 0 ; $i < 2 ** $bits ; $i++) {
|
2118 |
|
|
$bin = &dec2bin($i,$bits);
|
2119 |
|
|
push(@statevals,$bin);
|
2120 |
|
|
}
|
2121 |
|
|
return @statevals;
|
2122 |
|
|
}
|
2123 |
|
|
|
2124 |
|
|
|
2125 |
|
|
sub debug {
|
2126 |
|
|
my ($string,$depth,$section) = @_;
|
2127 |
|
|
if ($global_debug || $debug_sections{$section}) {
|
2128 |
|
|
print STDERR " " x $depth . "<db${section}>: $string\n";
|
2129 |
|
|
}
|
2130 |
|
|
}
|
2131 |
|
|
|
2132 |
|
|
sub verbose {
|
2133 |
|
|
my ($string,$depth,$section) = @_;
|
2134 |
|
|
if ($verbose) {
|
2135 |
|
|
print STDERR " " x $depth . "$string\n";
|
2136 |
|
|
}
|
2137 |
|
|
}
|
2138 |
|
|
|
2139 |
|
|
sub error {
|
2140 |
|
|
my ($indent,$string) = @_;
|
2141 |
|
|
|
2142 |
|
|
# indent is ignored. It is just there to make it easy to switch btw
|
2143 |
|
|
# warnings and errors.
|
2144 |
|
|
|
2145 |
|
|
&print_output;
|
2146 |
|
|
print "\n\nError: $string - exiting\n";
|
2147 |
|
|
print STDERR "\n\nError: $string - exiting\n";
|
2148 |
|
|
exit;
|
2149 |
|
|
}
|
2150 |
|
|
|
2151 |
|
|
sub warning {
|
2152 |
|
|
my($indent,$string) = @_;
|
2153 |
|
|
my($group,$number) = ();
|
2154 |
|
|
|
2155 |
|
|
# Determine warning number based on string. It would be cleaner to just
|
2156 |
|
|
# have the call use the number, but that makes it difficult to see what
|
2157 |
|
|
# the warning is when reading the code.
|
2158 |
|
|
|
2159 |
|
|
# R group - resets
|
2160 |
|
|
if ($string =~ /No reset specified/) {$group = "R"; $number = 1;}
|
2161 |
|
|
# elsif ($string =~ /No reset value for datapath output \S+ set in reset state \S+ - Assiging a reset value of \S+ based on default/) {$group = "R"; $number = 5;}
|
2162 |
|
|
# Now an error:
|
2163 |
|
|
#elsif ($string =~ /Specified reset signal \S+ is not an input/) {$group = "R"; $number = 6;}
|
2164 |
|
|
|
2165 |
|
|
# I group - implied loopback
|
2166 |
|
|
# P group - priority
|
2167 |
|
|
# C group - combinational outputs
|
2168 |
|
|
# D group - defaults
|
2169 |
|
|
# O group - overrides
|
2170 |
|
|
# F group - flags
|
2171 |
|
|
# N group - includes
|
2172 |
|
|
elsif ($string =~ /Neither implied_loopback nor default_state_is_x attribute is set on state machine - defaulting to implied_loopback to avoid latches being inferred/) {$group = "I"; $number = 2;}
|
2173 |
|
|
|
2174 |
|
|
elsif ($string =~ /State \S+ has multiple exit transitions, and transition \S+ has no defined priority/) {$group = "P"; $number = 3;}
|
2175 |
|
|
elsif ($string =~ /State \S+ has multiple exit transitions, and transition \S+ has the same priority as transition .*/) {$group = "P" ; $number = "4"}
|
2176 |
|
|
|
2177 |
|
|
elsif ($string =~ /Combinational output \S+ is assigned on transitions, but has a non-default value ".+" in state \S+/) {$group = "C" ; $number = 7;}
|
2178 |
|
|
|
2179 |
|
|
elsif ($string =~ /Neither implied_loopback nor default_state_is_x attribute is set on onehot state machine and there is no loopback arc - this could result in latches being inferred/) {$group = "I"; $number = 8;}
|
2180 |
|
|
|
2181 |
|
|
elsif ($string =~ /Did not find any non-default values for any datapath outputs - suppressing case statement/) {$group = "D"; $number = 9;}
|
2182 |
|
|
|
2183 |
|
|
elsif ($string =~ /Combinational output \S+ has no default value/) {$group = "C" ; $number = 10;}
|
2184 |
|
|
|
2185 |
|
|
elsif ($string =~ /Datapath output \S+ has no default value/) {$group = "D" ; $number = 11;}
|
2186 |
|
|
|
2187 |
|
|
elsif ($string =~ /Using override value from attribute/) {$group = "O" ; $number = 12;}
|
2188 |
|
|
|
2189 |
|
|
elsif ($string =~ /undefined_states_go_here.*onehot/) {$group = "O" ; $number = 13;}
|
2190 |
|
|
|
2191 |
|
|
elsif ($string =~ /No reset value set for flag/) {$group = "R"; $number = 14;}
|
2192 |
|
|
|
2193 |
|
|
elsif ($string =~ /Flag \S+ is assigned on transitions, but is also assigned value ".+" in state \S+/) {$group = "F" ; $number = 17;}
|
2194 |
|
|
|
2195 |
|
|
elsif ($string =~ /No reset value set for datapath.*reset state/) {$group = "R"; $number = 18;}
|
2196 |
|
|
|
2197 |
|
|
elsif ($string =~ /No reset value set for datapath.*default/) {$group = "R"; $number = 18;}
|
2198 |
|
|
|
2199 |
|
|
elsif ($string =~ /No reset value set for datapath.*using 0/) {$group = "R"; $number = 18;}
|
2200 |
|
|
|
2201 |
|
|
elsif ($string =~ /Could not open file/) {$group = "N"; $number = 19;}
|
2202 |
|
|
|
2203 |
|
|
|
2204 |
|
|
else {
|
2205 |
|
|
print "Unrecognized warning \"$string\" - exiting\n";
|
2206 |
|
|
print STDERR "Unrecognized warning \"$string\" - exiting\n";
|
2207 |
|
|
exit;
|
2208 |
|
|
}
|
2209 |
|
|
|
2210 |
|
|
# Output warning unless suppressed
|
2211 |
|
|
unless ($nowarns{"${group}${number}"} || $nowarns{$group}) {
|
2212 |
|
|
eval "\$myindent = \"$indentstring\" x $indent";
|
2213 |
|
|
if ($warnout eq "stdout" || $warnout eq "both") {
|
2214 |
|
|
# warnings are stored in an array whose indeces correspond to the
|
2215 |
|
|
# previous line of pbuf. Use concat in case there are multiple warnings
|
2216 |
|
|
# associated with the same line.
|
2217 |
|
|
$warnings[$#pbuf] = $warnings[$#pbuf] . "${myindent}// Warning $group$number: $string \n";
|
2218 |
|
|
}
|
2219 |
|
|
if ($warnout eq "stderr" || $warnout eq "both") {
|
2220 |
|
|
print STDERR "\n\nWarning $group$number: $string \n";
|
2221 |
|
|
}
|
2222 |
|
|
}
|
2223 |
|
|
}
|
2224 |
|
|
|
2225 |
|
|
sub assertion {
|
2226 |
|
|
my($indent,$string) = @_;
|
2227 |
|
|
|
2228 |
|
|
eval "\$myindent = \"$indentstring\" x $indent";
|
2229 |
|
|
$assertions[$#pbuf] = $assertions[$#pbuf] . "${myindent}${string}\n";
|
2230 |
|
|
}
|
2231 |
|
|
|
2232 |
|
|
sub print {
|
2233 |
|
|
my($indent,$string) = @_;
|
2234 |
|
|
my($skip,$maxlen,$thislen) = 0;
|
2235 |
|
|
my($tag) = "//tersetag";
|
2236 |
|
|
my($i,$j);
|
2237 |
|
|
|
2238 |
|
|
$section = "terse"; # for debug
|
2239 |
|
|
# -terse handling
|
2240 |
|
|
# If you plan to follow or modify the -terse code, be sure to have an
|
2241 |
|
|
# ample supply of barf bags near to hand. It is HORRIBLE.
|
2242 |
|
|
#
|
2243 |
|
|
# The basic idea is that all calls to &print go to an array (pbuf). This
|
2244 |
|
|
# is done even without -terse, just to be consistent. Warnings and
|
2245 |
|
|
# "comments" must go to separate arrays that parallel pbuf. This makes
|
2246 |
|
|
# it easier for the tersify code to find its way around.
|
2247 |
|
|
#
|
2248 |
|
|
# When -terse is on, it looks for "end" and "endcase" (plus wire statements),
|
2249 |
|
|
# and starts poking around in the pbuf to try to get rid of begin/end pairs.
|
2250 |
|
|
# When it finds an "endcase", it backs up through pbuf to tag lines as
|
2251 |
|
|
# statement and non-statement, and to calculate how much indent will be
|
2252 |
|
|
# required to make the assignment statements line up. It then goes back
|
2253 |
|
|
# forward through pbuf and makes these modifications.
|
2254 |
|
|
#
|
2255 |
|
|
# Yech!
|
2256 |
|
|
|
2257 |
|
|
# 1) Get rid of unnecessary wire statements
|
2258 |
|
|
if ($terse && ($string =~ /^\s*(in|out)put wire /)) {
|
2259 |
|
|
#&debug("line:\n$string\n",0,$section);
|
2260 |
|
|
($temp = $string) =~ s/\/\/.*$//; # temp is string without any comments
|
2261 |
|
|
unless ($temp =~ /\[\d+:\d+\]/) { # unless temp has [n:m]..
|
2262 |
|
|
$string =~ s/ wire//; # get rid of the wire statement
|
2263 |
|
|
$string =~ s/,/, /; # re-pad in case of comment
|
2264 |
|
|
$string =~ s/,\s*$/,\n/; # and strip trailing blanks
|
2265 |
|
|
}
|
2266 |
|
|
#&debug(" now:\n$string\n",0,$section);
|
2267 |
|
|
}
|
2268 |
|
|
# Ditto for logic inputs in sv
|
2269 |
|
|
if ($language eq "systemverilog" && $terse && ($string =~ /^\s*input logic /)) {
|
2270 |
|
|
($temp = $string) =~ s/\/\/.*$//; # temp is string without any comments
|
2271 |
|
|
unless ($temp =~ /\[\d+:\d+\]/) { # unless temp has [n:m]..
|
2272 |
|
|
$string =~ s/ logic//; # get rid of the wire statement
|
2273 |
|
|
$string =~ s/,/, /; # re-pad in case of comment
|
2274 |
|
|
$string =~ s/,\s*$/,\n/; # and strip trailing blanks
|
2275 |
|
|
}
|
2276 |
|
|
}
|
2277 |
|
|
|
2278 |
|
|
# 2) Get rid of extra begin/end pairs
|
2279 |
|
|
#
|
2280 |
|
|
if ($terse && ($string =~ /^\s*end\s*$/)) {
|
2281 |
|
|
# a) If we're on an "end" line and the next-to-previous line ends in begin,
|
2282 |
|
|
# strip the begin and newline and set skip flag.
|
2283 |
|
|
# ex:
|
2284 |
|
|
# if (foo) begin
|
2285 |
|
|
# bar <= 0
|
2286 |
|
|
# end
|
2287 |
|
|
# or:
|
2288 |
|
|
# begin
|
2289 |
|
|
# bar <= 0
|
2290 |
|
|
# end
|
2291 |
|
|
if (!&is_stateline($pbuf[$#pbuf - 1])
|
2292 |
|
|
&& $pbuf[$#pbuf - 1] =~ s/begin\s*$/\1/
|
2293 |
|
|
) {
|
2294 |
|
|
&debug("Doing step a on \"$string\"\n",0,$section);
|
2295 |
|
|
$skip = 1;
|
2296 |
|
|
# If resulting string is empty, remove it
|
2297 |
|
|
if ($pbuf[$#pbuf - 1] =~ /^\s*$/) {
|
2298 |
|
|
splice(@pbuf, $#pbuf -1, 1);
|
2299 |
|
|
}
|
2300 |
|
|
# Unindent
|
2301 |
|
|
eval "\$myindent = \"$indentstring\"";
|
2302 |
|
|
$pbuf[$#pbuf] =~ s/$myindent//;
|
2303 |
|
|
|
2304 |
|
|
# b) If we're on an "end" line and the next-to-previous line looks like
|
2305 |
|
|
# a "IDLE:" line, strip the begin and newline and set skip flag.
|
2306 |
|
|
# ex:
|
2307 |
|
|
# IDLE: begin
|
2308 |
|
|
# bar <= 0
|
2309 |
|
|
# end
|
2310 |
|
|
} elsif (&is_stateline($pbuf[$#pbuf - 1])) {
|
2311 |
|
|
&debug("Doing step b on \"$string\"\n",0,$section);
|
2312 |
|
|
if ($pbuf[$#pbuf - 1] =~ s/(\S+\s*:)\s+begin\s*$/\1/) {
|
2313 |
|
|
$skip = 1;
|
2314 |
|
|
# Unindent
|
2315 |
|
|
#eval "\$myindent = \"$indentstring\"";
|
2316 |
|
|
#$pbuf[$#pbuf] =~ s/$myindent//;
|
2317 |
|
|
}
|
2318 |
|
|
|
2319 |
|
|
# c) If we're on an "end" line and the next-to-previous line is "else",
|
2320 |
|
|
# 2 lines up from that is "if", and
|
2321 |
|
|
# 1 line from that is "state:"
|
2322 |
|
|
# IDLE: begin < -4
|
2323 |
|
|
# if (foo) < -3
|
2324 |
|
|
# bar <=1 < -2
|
2325 |
|
|
# else < -1
|
2326 |
|
|
# bar <= 0 < 0
|
2327 |
|
|
# end < curr
|
2328 |
|
|
#
|
2329 |
|
|
# remove the begin and newline, join the lines and set skip flag
|
2330 |
|
|
# (lines are joined explicitly because "case" step needs all "statements"
|
2331 |
|
|
# on a single line).
|
2332 |
|
|
# Also, scoot the -1 line (else) over by the length to the ":" plus 1
|
2333 |
|
|
#
|
2334 |
|
|
# Ends up as:
|
2335 |
|
|
# IDLE: if (foo) bar <=1 <-2
|
2336 |
|
|
# else bar <= 0 <-1
|
2337 |
|
|
# end < curr
|
2338 |
|
|
} elsif ($pbuf[$#pbuf -1] =~ /else /) {
|
2339 |
|
|
# Look for first if and previous state
|
2340 |
|
|
$n = 3;
|
2341 |
|
|
while ($pbuf[$#pbuf - $n] =~ /else if/) {
|
2342 |
|
|
$n = $n+2;
|
2343 |
|
|
}
|
2344 |
|
|
|
2345 |
|
|
if ($pbuf[$#pbuf - $n] =~ /^\s*if /
|
2346 |
|
|
&& $pbuf[$#pbuf - $n - 1] =~ /begin\s*$/ # no comment on state begin
|
2347 |
|
|
&& (&is_stateline($pbuf[$#pbuf - $n - 1]))
|
2348 |
|
|
) {
|
2349 |
|
|
|
2350 |
|
|
&debug("In step c, n is \"$n\"\n",0,$section);
|
2351 |
|
|
$stateline = $#pbuf - $n - 1;
|
2352 |
|
|
&debug("In step c, stateline is \"$stateline\"\n",0,$section);
|
2353 |
|
|
|
2354 |
|
|
&debug("Doing step c on \"$string\"\n",0,$section);
|
2355 |
|
|
$pbuf[$stateline] =~ s/(\S+\s*:)\s+begin\s*$/\1/; # strip begin
|
2356 |
|
|
|
2357 |
|
|
# Do the "scoot"
|
2358 |
|
|
$colonpos = index($pbuf[$stateline],":");
|
2359 |
|
|
($temp = $pbuf[$stateline]) =~ s/^(\s*).*$/\1/;
|
2360 |
|
|
$startpos = length($temp);
|
2361 |
|
|
$scoot = $colonpos - $startpos;
|
2362 |
|
|
&debug("Scoot is \"$scoot\"\n",0,$section);
|
2363 |
|
|
for ($i = $#pbuf-1; $i > $stateline+1; $i = $i - 2) {
|
2364 |
|
|
&debug("Scooting line \"$pbuf[$i]\"\n",0,$section);
|
2365 |
|
|
$pbuf[$i] = " " x $scoot . $pbuf[$i];
|
2366 |
|
|
}
|
2367 |
|
|
|
2368 |
|
|
# Remove indent on -3 and join -3 and -4 into -3
|
2369 |
|
|
# Might not be literally -3 and -4..., make it relative to stateline
|
2370 |
|
|
$pbuf[$stateline+1] =~ s/^$level4indent/ /;
|
2371 |
|
|
$pbuf[$stateline+1] = $pbuf[$stateline] . $pbuf[$stateline+1];
|
2372 |
|
|
# And snuff out -4
|
2373 |
|
|
&move_warnings_and_assertions($stateline,$stateline+1); # move warnings/assertions to -3
|
2374 |
|
|
splice(@pbuf, $stateline, 1);
|
2375 |
|
|
#$pbuf[$#pbuf - 4] = "";
|
2376 |
|
|
$skip = 1;
|
2377 |
|
|
}
|
2378 |
|
|
|
2379 |
|
|
# d) If we're on an "end" line and their are "stacked begin/begin end/end
|
2380 |
|
|
# sets, like this:
|
2381 |
|
|
# IDLE: begin < -?
|
2382 |
|
|
# begin < -?
|
2383 |
|
|
# bar <=1 < -?
|
2384 |
|
|
# bar <= 0 < -1
|
2385 |
|
|
# end < 0
|
2386 |
|
|
# end < curr
|
2387 |
|
|
# remove the inside begin/end pair, but do not set skip flag.
|
2388 |
|
|
} elsif ($pbuf[$#pbuf] =~ /^\s*end/) { # previous was ALSO end
|
2389 |
|
|
&debug("Doing step d on \"$string\"\n",0,$section);
|
2390 |
|
|
# troll through the buffer looking for the previous begin
|
2391 |
|
|
$i = $#pbuf-1;
|
2392 |
|
|
while ($pbuf[$i] !~ /^[^\/]*begin/ && $pbuf[$i] !~ /^\s*end/ && $i > 0) {
|
2393 |
|
|
$i--
|
2394 |
|
|
}
|
2395 |
|
|
# $i is now pointing at begin (or at end or start of buffer)
|
2396 |
|
|
# If it is begin, then do our thing
|
2397 |
|
|
if ($pbuf[$i] =~ /^\s*begin/) { # MUST be a PURE begin
|
2398 |
|
|
if ($pbuf[$i-1] =~ /^[^\/]*begin/) { # Previous is ALSO a begin
|
2399 |
|
|
# Note that pure begin/ends should not have warnings, so it is
|
2400 |
|
|
# safe to do the snuff...
|
2401 |
|
|
# snuff out $i entry
|
2402 |
|
|
splice(@pbuf, $i, 1);
|
2403 |
|
|
#$pbuf[$i] = "";
|
2404 |
|
|
# snuff out last entry (previous end)
|
2405 |
|
|
splice(@pbuf, $#pbuf, 1);
|
2406 |
|
|
#$pbuf[$#pbuf] = "";
|
2407 |
|
|
}
|
2408 |
|
|
}
|
2409 |
|
|
|
2410 |
|
|
# e) If we're on an "end" line and the next-to-previous line is "if",
|
2411 |
|
|
# 1 line from that is "state:"
|
2412 |
|
|
# IDLE: begin < -2
|
2413 |
|
|
# if (foo) < -1
|
2414 |
|
|
# bar <=1 < 0
|
2415 |
|
|
# end < curr
|
2416 |
|
|
# remove the begin and newline, join the lines and set skip flag
|
2417 |
|
|
# (lines are joined explicitly because "case" step needs all "statements"
|
2418 |
|
|
# on a single line).
|
2419 |
|
|
} elsif ( $pbuf[$#pbuf -1] =~ /if /
|
2420 |
|
|
&& $pbuf[$#pbuf -2] =~ /begin\s*$/ # no comment on state begin
|
2421 |
|
|
&& (&is_stateline($pbuf[$#pbuf - 2]))
|
2422 |
|
|
) {
|
2423 |
|
|
|
2424 |
|
|
&debug("Doing step e on \"$string\"\n",0,$section);
|
2425 |
|
|
$pbuf[$#pbuf - 2] =~ s/(\S+\s*:)\s+begin\s*$/\1/; # strip begin
|
2426 |
|
|
|
2427 |
|
|
|
2428 |
|
|
# Remove indent on 2 and join -1 and -2 into -1
|
2429 |
|
|
$pbuf[$#pbuf-1] =~ s/^$level4indent/ /;
|
2430 |
|
|
$pbuf[$#pbuf-1] = $pbuf[$#pbuf-2] . $pbuf[$#pbuf-1];
|
2431 |
|
|
# And snuff out -2
|
2432 |
|
|
&move_warnings_and_assertions($#pbuf-2,$#pbuf-1); # move warnings/assertions to -1
|
2433 |
|
|
splice(@pbuf, $#pbuf -2, 1);
|
2434 |
|
|
#$pbuf[$#pbuf - 2] = "";
|
2435 |
|
|
$skip = 1;
|
2436 |
|
|
|
2437 |
|
|
} else {
|
2438 |
|
|
#print $string;
|
2439 |
|
|
#print $pbuf[$#pbuf - 1];
|
2440 |
|
|
}
|
2441 |
|
|
}
|
2442 |
|
|
|
2443 |
|
|
# Change the statename (sim code) section to put state and assignment
|
2444 |
|
|
# on the same line
|
2445 |
|
|
if ($terse && ($string =~ /$statenamevar\s+=/)) {
|
2446 |
|
|
&debug("Found statename line \"$string\"\n",0,$section);
|
2447 |
|
|
&debug("$pbuf[$#pbuf]\n",0,$section);
|
2448 |
|
|
chomp($pbuf[$#pbuf]);
|
2449 |
|
|
}
|
2450 |
|
|
|
2451 |
|
|
# 3) At endcase, back up and re-format assignment lines to make them line up
|
2452 |
|
|
if ($terse && ($string =~ /^\s*endcase/)) {
|
2453 |
|
|
&debug("\nBefore 1st pass:\n",0,$section);
|
2454 |
|
|
&debug(join("",@pbuf),0,$section);
|
2455 |
|
|
#for ($i=0; $i<=$#pbuf; $i++) {
|
2456 |
|
|
# print "$i : $pbuf[$i]\n";
|
2457 |
|
|
#}
|
2458 |
|
|
|
2459 |
|
|
# "0th pass": Back up through buffer to the case statement and find
|
2460 |
|
|
# the max char location of equations.
|
2461 |
|
|
$max_eqpos = 0;
|
2462 |
|
|
$i = $#pbuf;
|
2463 |
|
|
while ($pbuf[$i] !~ /^\s*(unique )?case/ && $i > 0) {
|
2464 |
|
|
$nocomment = &nocomment($pbuf[$i]);
|
2465 |
|
|
if ($nocomment =~ /\s(if)|(else if)/) {
|
2466 |
|
|
&debug("Found eq line \"$nocomment\"\n",0,$section);
|
2467 |
|
|
$eqpos = index($nocomment,"(");
|
2468 |
|
|
$max_eqpos = $eqpos if ($eqpos > $max_eqpos);
|
2469 |
|
|
&debug("eqpos is $eqpos max_eqpos is $max_eqpos\n",0,$section);
|
2470 |
|
|
}
|
2471 |
|
|
$i--;
|
2472 |
|
|
}
|
2473 |
|
|
|
2474 |
|
|
# 1st pass: Back up through the buffer to the case statement and gather
|
2475 |
|
|
# information about the longest statement line. Also, tag the lines as
|
2476 |
|
|
# statement (#) and provide their length if applicable by pre-pending
|
2477 |
|
|
# the tag. This will be used and removed on the 2nd pass.
|
2478 |
|
|
$maxlen = 0;
|
2479 |
|
|
$i = $#pbuf;
|
2480 |
|
|
$thislen = 0;
|
2481 |
|
|
while ($pbuf[$i] !~ /^\s*(unique )?case/ && $i > 0) {
|
2482 |
|
|
&debug("\n\n1st pass line is:\n",0,$section);
|
2483 |
|
|
&debug("\"$pbuf[$i]\"",0,$section);
|
2484 |
|
|
if ($pbuf[$i] =~ /^\s*(if)|(else)|(end)|(begin)/ || &is_stateline($pbuf[$i])) {
|
2485 |
|
|
# "statement" lines
|
2486 |
|
|
&debug("\nIt's a statement line\n",0,$section);
|
2487 |
|
|
|
2488 |
|
|
# make sure we don't get fooled by ( in a comment...
|
2489 |
|
|
$nocomment = &nocomment($pbuf[$i]);
|
2490 |
|
|
|
2491 |
|
|
# Shift equations over
|
2492 |
|
|
if ($nocomment =~ /\(/) { # have a line with an equation
|
2493 |
|
|
$eqpos = index($nocomment,"(");
|
2494 |
|
|
$eq_shift = $max_eqpos - $eqpos;
|
2495 |
|
|
$eq_pad = " " x $eq_shift;
|
2496 |
|
|
&debug("eqpos is $eqpos eq_shift is $eq_shift eq_pad is \"$eq_pad\"\n",0,$section);
|
2497 |
|
|
&debug("unmodified equation line is \"$pbuf[$i]\"\n",0,$section);
|
2498 |
|
|
$pbuf[$i] =~ s/\(/$eq_pad(/; # insert spaces to move equation over
|
2499 |
|
|
# Adjust pad, unless pad is full maxlen (full maxlen means that
|
2500 |
|
|
# there was a newline)
|
2501 |
|
|
&debug(" modified equation line is \"$pbuf[$i]\"\n",0,$section);
|
2502 |
|
|
# re-create nocomment line
|
2503 |
|
|
$nocomment = &nocomment($pbuf[$i]);
|
2504 |
|
|
}
|
2505 |
|
|
|
2506 |
|
|
# Get length and set maxlen
|
2507 |
|
|
$thislen = length($nocomment);
|
2508 |
|
|
&debug("got a match: thislen is $thislen\n",0,$section);
|
2509 |
|
|
$maxlen = $thislen if ($maxlen < $thislen);
|
2510 |
|
|
|
2511 |
|
|
if ($pbuf[$i] =~ /\n$/) {
|
2512 |
|
|
# lines with eol should just to be marked
|
2513 |
|
|
$pbuf[$i] =~ s/^/## /;
|
2514 |
|
|
} else {
|
2515 |
|
|
# Tag with length (will be removed on 2nd pass)
|
2516 |
|
|
$pbuf[$i] =~ s/^/#$thislen /;
|
2517 |
|
|
}
|
2518 |
|
|
|
2519 |
|
|
} else {
|
2520 |
|
|
&debug("\nIt's an assignment line\n",0,$section);
|
2521 |
|
|
}
|
2522 |
|
|
&debug("\n1st pass modified line is:\n",0,$section);
|
2523 |
|
|
&debug("\"$pbuf[$i]\"",0,$section);
|
2524 |
|
|
$i--;
|
2525 |
|
|
}
|
2526 |
|
|
|
2527 |
|
|
&debug("\nBefore 2nd pass:\n",0,$section);
|
2528 |
|
|
&debug(join("",@pbuf),0,$section);
|
2529 |
|
|
|
2530 |
|
|
&debug("\nBefore 2nd pass, in detail:\n",0,$section);
|
2531 |
|
|
for ($j=$i+1;$j<$#pbuf;$j++) {
|
2532 |
|
|
&debug($pbuf[$j],0,$section)
|
2533 |
|
|
}
|
2534 |
|
|
&debug("\n**** end of detail ****\n",0,$section);
|
2535 |
|
|
|
2536 |
|
|
# 2nd pass: go forward through the case section of the buffer and make the
|
2537 |
|
|
# appropriate mods
|
2538 |
|
|
$maxlen++;
|
2539 |
|
|
&debug("maxlen is $maxlen\n",0,$section);
|
2540 |
|
|
&debug("max_eqpos is $max_eqpos\n",0,$section);
|
2541 |
|
|
# $i is from above!
|
2542 |
|
|
$i++; # go to next after case statement
|
2543 |
|
|
while ($i <= $#pbuf) {
|
2544 |
|
|
&debug("\n2nd pass line is:\n",0,$section);
|
2545 |
|
|
&debug("\"$pbuf[$i]\"",0,$section);
|
2546 |
|
|
if ($pbuf[$i] =~ /^#/) { # statement line of some sort
|
2547 |
|
|
if ($pbuf[$i] =~ s/^#(\d+) //) { # this is a line without a begin
|
2548 |
|
|
$pad = " " x ($maxlen - $1); # calculate pad for later lines
|
2549 |
|
|
} else {
|
2550 |
|
|
# "begin" lines will have a nl, so space following lines over
|
2551 |
|
|
# by the full maxlen
|
2552 |
|
|
$pbuf[$i] =~ s/^## //;
|
2553 |
|
|
$pad = " " x $maxlen;
|
2554 |
|
|
}
|
2555 |
|
|
|
2556 |
|
|
|
2557 |
|
|
&debug("taglen is $1 ; pad is \"$pad\"\n",0,$section);
|
2558 |
|
|
&debug("modified statement line is \"$pbuf[$i]\"\n",0,$section);
|
2559 |
|
|
} else {
|
2560 |
|
|
$pbuf[$i] =~ s/^\s*/$pad/;
|
2561 |
|
|
&debug("modified assignment line is \n\"$pbuf[$i]\"\n",0,$section);
|
2562 |
|
|
&debug("last 2 lines: \n" . $pbuf[$i-1] . $pbuf[$i],0,$section);
|
2563 |
|
|
}
|
2564 |
|
|
$i++;
|
2565 |
|
|
}
|
2566 |
|
|
#$max_eqpos = 0;
|
2567 |
|
|
}
|
2568 |
|
|
|
2569 |
|
|
#push(@pbuf,$indentstring x $indent . "$string") unless ($skip);
|
2570 |
|
|
# Handle indent in a way that makes regexp's work
|
2571 |
|
|
eval "\$myindent = \"$indentstring\" x $indent";
|
2572 |
|
|
$string = $myindent . $string;
|
2573 |
|
|
push(@pbuf,$string) unless ($skip);
|
2574 |
|
|
|
2575 |
|
|
&debug("\npbuf is now:\n",0,$section);
|
2576 |
|
|
&debug(join("",@pbuf),0,$section);
|
2577 |
|
|
&debug("\npbuf done:\n",0,$section);
|
2578 |
|
|
}
|
2579 |
|
|
|
2580 |
|
|
sub nocomment {
|
2581 |
|
|
my ($line) = @_;
|
2582 |
|
|
($nocomment = $line) =~ s/\s*\/\/.*$//;
|
2583 |
|
|
$nocomment =~ s/\s*\/\*.*$//; # for /* - not sure if this is necessary
|
2584 |
|
|
return $nocomment;
|
2585 |
|
|
}
|
2586 |
|
|
|
2587 |
|
|
sub print_output {
|
2588 |
|
|
# Dump print buffer and warnings
|
2589 |
|
|
for ($i=0; $i<=$#pbuf; $i++) {
|
2590 |
|
|
# print "$i : $pbuf[$i]";
|
2591 |
|
|
# if ($warnings[$i]) {
|
2592 |
|
|
# print "w$i : $warnings[$i]";
|
2593 |
|
|
# }
|
2594 |
|
|
#print "$i : $assertions[$i]";
|
2595 |
|
|
print $pbuf[$i];
|
2596 |
|
|
if ($pbuf[$i] =~ /\n/) {
|
2597 |
|
|
print $warnings[$i];
|
2598 |
|
|
print $assertions[$i];
|
2599 |
|
|
} else {
|
2600 |
|
|
# if line doesn't end in nl, append warning/assertion to next line
|
2601 |
|
|
$warnings[$i+1] = $warnings[$i] . $warnings[$i+1];
|
2602 |
|
|
$assertions[$i+1] = $assertions[$i] . $assertions[$i+1];
|
2603 |
|
|
}
|
2604 |
|
|
}
|
2605 |
|
|
}
|
2606 |
|
|
|
2607 |
|
|
sub move_warnings_and_assertions {
|
2608 |
|
|
my ($from,$to) = @_;
|
2609 |
|
|
if ($warnings[$from]) { # move warning to $to
|
2610 |
|
|
$warnings[$to] = $warnings[$to] . $warnings[$from];
|
2611 |
|
|
$warnings[$from] = "";
|
2612 |
|
|
}
|
2613 |
|
|
splice(@warnings, $from, 1); # snuff out $from
|
2614 |
|
|
if ($assertions[$from]) { # move assertion to $to
|
2615 |
|
|
$assertions[$to] = $assertions[$to] . $assertions[$from];
|
2616 |
|
|
$assertions[$from] = "";
|
2617 |
|
|
}
|
2618 |
|
|
splice(@assertions, $from, 1); # snuff out $from
|
2619 |
|
|
}
|
2620 |
|
|
|
2621 |
|
|
sub is_stateline {
|
2622 |
|
|
my($line) = @_;
|
2623 |
|
|
|
2624 |
|
|
#print "line was: $line\n";
|
2625 |
|
|
$line =~ s/\s*\/\/.*$//; # get rid of comments
|
2626 |
|
|
#$line =~ s/\[.*:.*\]//g; # get rid of all bit ranges
|
2627 |
|
|
#$line =~ s/\[[^\]]+\]//g; # get rid of all bit ranges
|
2628 |
|
|
$line =~ s/\[[^\]]+:[^\]]+\]//g; # get rid of all bit ranges foo[1:0]
|
2629 |
|
|
#print "line is: $line\n";
|
2630 |
|
|
|
2631 |
|
|
return
|
2632 |
|
|
($line =~ /$nextstatevar\[\S+\]\s*:/) # onehot
|
2633 |
|
|
|| ($line =~ /$statevar\[\S+\]\s*:/) # onehot "state[IDLE_BIT]:"
|
2634 |
|
|
|| ($line =~ /^\s+\S+\s*:/)
|
2635 |
|
|
|| ($line =~ /^\s*default\s*:/)
|
2636 |
|
|
;
|
2637 |
|
|
|
2638 |
|
|
}
|
2639 |
|
|
|
2640 |
|
|
sub remove_from_array {
|
2641 |
|
|
my ($delvalue,@array) = @_;
|
2642 |
|
|
my @return;
|
2643 |
|
|
foreach $value (@array) {
|
2644 |
|
|
if (!($value eq $delvalue)) {
|
2645 |
|
|
push(@return, $value);
|
2646 |
|
|
}
|
2647 |
|
|
}
|
2648 |
|
|
return @return;
|
2649 |
|
|
}
|
2650 |
|
|
|
2651 |
|
|
sub process_options {
|
2652 |
|
|
|
2653 |
|
|
# Debug stuff
|
2654 |
|
|
&debug("orig_argv: " . join(" ",@orig_argv),0,"be_cmd");
|
2655 |
|
|
&debug("ARGV: " . join(" ",@ARGV),0,"be_cmd");
|
2656 |
|
|
|
2657 |
|
|
use Getopt::Long;
|
2658 |
|
|
# Default non-null options
|
2659 |
|
|
$encoding = "heros";
|
2660 |
|
|
$statevar = "state";
|
2661 |
|
|
$nextstatevar = "nextstate";
|
2662 |
|
|
$statenamevar = "statename";
|
2663 |
|
|
$warnout = "both";
|
2664 |
|
|
$simcode = 2; # funny default so we can see if it was forced on for SV
|
2665 |
|
|
$indentstring = " ";
|
2666 |
|
|
$language = "verilog";
|
2667 |
|
|
$indexvar = "index";
|
2668 |
|
|
$addversion = "1";
|
2669 |
|
|
$max_iterations = 10000000;
|
2670 |
|
|
|
2671 |
|
|
# Process options
|
2672 |
|
|
die unless GetOptions(
|
2673 |
|
|
"help" => \$help,
|
2674 |
|
|
"verbose!" => \$verbose,
|
2675 |
|
|
"debug=s" => \@debug_sections,
|
2676 |
|
|
"encoding=s" => \$encoding,
|
2677 |
|
|
"simcode!" => \$simcode,
|
2678 |
|
|
"maxbits=s" => \$usermaxbits,
|
2679 |
|
|
"minbits=s" => \$userminbits,
|
2680 |
|
|
"statevar=s" => \$statevar,
|
2681 |
|
|
"nextstatevar=s" => \$nextstatevar,
|
2682 |
|
|
"statenamevar=s" => \$statenamevar,
|
2683 |
|
|
"indexvar=s" => \$indexvar,
|
2684 |
|
|
"warnout=s" => \$warnout,
|
2685 |
|
|
"nowarn=s" => \@nowarns,
|
2686 |
|
|
"version!" => \$version,
|
2687 |
|
|
"addversion!" => \$addversion,
|
2688 |
|
|
"terse!" => \$terse,
|
2689 |
|
|
"sunburst!" => \$terse,
|
2690 |
|
|
"indentstring=s" => \$indentstring,
|
2691 |
|
|
"language=s" => \$language,
|
2692 |
|
|
"comb2reg!" => \$comb2reg,
|
2693 |
|
|
#"casedefault!" => \$casedefault, # not yet - need to figure out if/when this is safe (doesn't change logic or cause latches)
|
2694 |
|
|
"minversion=s" => \$minversion,
|
2695 |
|
|
"inst!" => \$inst,
|
2696 |
|
|
"force_undefined_goto_in_onehot!" => \$force_undefined_goto_in_onehot,
|
2697 |
|
|
"force_keep_undefined_goto_state!" => \$force_keep_undefined_goto_state,
|
2698 |
|
|
"test_flags" => \$test_flags, # temp code
|
2699 |
|
|
"iterations=s" => \$max_iterations,
|
2700 |
|
|
);
|
2701 |
|
|
|
2702 |
|
|
if ($help) {
|
2703 |
|
|
&show_help;
|
2704 |
|
|
exit;
|
2705 |
|
|
}
|
2706 |
|
|
|
2707 |
|
|
if ($version) {
|
2708 |
|
|
print "$me version $scriptversion\n";
|
2709 |
|
|
exit;
|
2710 |
|
|
}
|
2711 |
|
|
|
2712 |
|
|
# Turn debug array into a hash
|
2713 |
|
|
foreach $section (@debug_sections) {
|
2714 |
|
|
$debug_sections{$section} = 1;
|
2715 |
|
|
}
|
2716 |
|
|
|
2717 |
|
|
# Turn nowarn array into a hash
|
2718 |
|
|
foreach $nowarn (@nowarns) {
|
2719 |
|
|
$nowarns{$nowarn} = 1;
|
2720 |
|
|
}
|
2721 |
|
|
|
2722 |
|
|
if ($language =~ /^verilog$/i) {
|
2723 |
|
|
$language = "verilog";
|
2724 |
|
|
} elsif ($language =~ /^s.*/i) {
|
2725 |
|
|
$language = "systemverilog";
|
2726 |
|
|
} else {
|
2727 |
|
|
die "Unrecognized language \"$language\"\n";
|
2728 |
|
|
}
|
2729 |
|
|
|
2730 |
|
|
if ($simcode == 2) { # default still
|
2731 |
|
|
if ($language eq "verilog") {
|
2732 |
|
|
$simcode = 1; # default on for verilog
|
2733 |
|
|
} elsif ($language eq "systemverilog") {
|
2734 |
|
|
$simcode = 0; # default on for sv
|
2735 |
|
|
}
|
2736 |
|
|
}
|
2737 |
|
|
|
2738 |
|
|
|
2739 |
|
|
# Create reserved words hash
|
2740 |
|
|
%reserved_words = (
|
2741 |
|
|
$statevar => 1,
|
2742 |
|
|
$nextstatevar => 1,
|
2743 |
|
|
$statenamevar => 1,
|
2744 |
|
|
$indexvar => 1,
|
2745 |
|
|
);
|
2746 |
|
|
|
2747 |
|
|
}
|
2748 |
|
|
|
2749 |
|
|
sub show_help {
|
2750 |
|
|
print STDERR "Syntax:
|
2751 |
|
|
$me [options]
|
2752 |
|
|
|
2753 |
|
|
options:
|
2754 |
|
|
-help Show this help
|
2755 |
|
|
-verbose Be Chatty
|
2756 |
|
|
-debug section Turn on debug messages for section <section>
|
2757 |
|
|
(Can be used multiple times)
|
2758 |
|
|
-encoding <encoding> Use encoding <encoding>
|
2759 |
|
|
-simcode Add code to add ascii state names in simulation
|
2760 |
|
|
-maxbits <value> For heros encoding, set upper limit of search range to <value>
|
2761 |
|
|
-minbits <value> For heros encoding, set lower limit of search range to <value>
|
2762 |
|
|
-statevar <name> Use <name> instead of \"state\" for the state variable
|
2763 |
|
|
-nextstatevar <name> Use <name> instead of \"nextstate\" for the nextstate variable
|
2764 |
|
|
-statenamevar <name> Use <name> instead of \"statename\" for the ASCII state name variable
|
2765 |
|
|
-indexvar <name> Use <name> instead of \"index\" for the ASCII index variable in systemverilog onehot
|
2766 |
|
|
-warnout <output> Control warning output. <output> = stdout | stderr | both
|
2767 |
|
|
-nowarn <number> Suppress warning number <number>
|
2768 |
|
|
(Can be used multiple times)
|
2769 |
|
|
-version Just echo version and exit
|
2770 |
|
|
-addversion Add version to output as a comment
|
2771 |
|
|
-terse/-sunburst Use Sunburst Design (Cliff Cummings) output format
|
2772 |
|
|
-indentstring <string> Use <string> instead of \"$indentstring\" for indenting
|
2773 |
|
|
-language <language> Language options are Verilog, SystemVerilog
|
2774 |
|
|
-comb2reg Try to convert any comb outputs with all-constant
|
2775 |
|
|
values to registered outputs.
|
2776 |
|
|
-minversion <version> Require at least version \"version\" or bail out
|
2777 |
|
|
-force_undefined_goto_in_onehot Don't ignore undefined_states_go_here attribute when doing onehot encoding
|
2778 |
|
|
-force_keep_undefined_goto_state Don't suppress undefined_states_go_here state even if state space is full without it
|
2779 |
|
|
-iterations <value> For heros encoding, set max number of iterations attempted before bailing out (default: $max_iterations)
|
2780 |
|
|
|
2781 |
|
|
Note: boolean switches accept the \"no\" syntax to turn them off
|
2782 |
|
|
(So, -nosimcode turns off simcode)
|
2783 |
|
|
|
2784 |
|
|
Recognized User Attributes:
|
2785 |
|
|
suppress_portlist - set on outputs to prevent them from appearing in the portlist
|
2786 |
|
|
|
2787 |
|
|
For details on recognized attributes, use \"-help -verbose\"
|
2788 |
|
|
\n";
|
2789 |
|
|
|
2790 |
|
|
|
2791 |
|
|
# -casedefault Add an empty \"default: ;\" to end of case statements
|
2792 |
|
|
|
2793 |
|
|
if ($verbose) {
|
2794 |
|
|
&set_myattributes;
|
2795 |
|
|
print STDERR "Recognized attributes:\n";
|
2796 |
|
|
foreach $entry (sort keys %myattributes) {
|
2797 |
|
|
$string = $myattributes{$entry};
|
2798 |
|
|
unless ($string =~ /^</) { # Skip entries marked with <>
|
2799 |
|
|
# Massage the output appearance
|
2800 |
|
|
#print "$entry:\n\t$string\n";
|
2801 |
|
|
foreach $array ("globals", "state", "transition") {
|
2802 |
|
|
$entry =~ s/^($array){"([^"]+)"}{/\1 > \2 > /;
|
2803 |
|
|
}
|
2804 |
|
|
#$entry =~ s/"//g;
|
2805 |
|
|
$entry =~ s/}{/ /g;
|
2806 |
|
|
$entry =~ s/[{}]//g;
|
2807 |
|
|
$entry =~ s/"value"/<value>/;
|
2808 |
|
|
$entry =~ s/"vis"/<vis>/;
|
2809 |
|
|
$entry =~ s/"type"/<type>/;
|
2810 |
|
|
$entry =~ s/ "attributes"//;
|
2811 |
|
|
$entry =~ s/ machine / state machine /;
|
2812 |
|
|
$entry =~ s/\*(\S+)\*/\$\1\$/g;
|
2813 |
|
|
$string =~ s/\*(\S+)\*/\$\1\$/g;
|
2814 |
|
|
print STDERR "$entry:\n\t$string\n\n";
|
2815 |
|
|
}
|
2816 |
|
|
}
|
2817 |
|
|
}
|
2818 |
|
|
}
|
2819 |
|
|
|
2820 |
|
|
sub set_myattributes {
|
2821 |
|
|
# Cannot set based on encoding because file must be parsed to figure out
|
2822 |
|
|
# the encoding. Cannot parse twice because it comes from STDIN.
|
2823 |
|
|
#if ($encoding eq "heros" || $encoding eq "onehot") {
|
2824 |
|
|
%myattributes = (
|
2825 |
|
|
'globals{"machine"}{"name"}{"value"}' => 'fsm module name',
|
2826 |
|
|
'globals{"machine"}{"clock"}{"value"}' => 'clock signal',
|
2827 |
|
|
'globals{"machine"}{"clock"}{"type"}' => 'clock signal type ("posedge", "negedge")',
|
2828 |
|
|
'globals{"machine"}{"reset_signal"}{"value"}' => 'reset signal',
|
2829 |
|
|
'globals{"machine"}{"reset_signal"}{"type"}' => 'reset signal type ("posedge", "negedge", "positive", "negative")',
|
2830 |
|
|
'globals{"machine"}{"reset_state"}{"value"}' => 'reset state',
|
2831 |
|
|
'globals{"machine"}{"reset_state"}{"type"}' => 'reset state type ("allzeros", "allones", "anyvalue")',
|
2832 |
|
|
'globals{"machine"}{"implied_loopback"}{"value"}' => 'Every state has an implied loopback (Note: overrides default_state_is_x)',
|
2833 |
|
|
'globals{"machine"}{"default_state_is_x"}{"value"}' => 'If no valid transition occur, set state to x',
|
2834 |
|
|
'globals{"machine"}{"undefined_states_go_to"}{"value"}' => 'undefined states got to <value>',
|
2835 |
|
|
'globals{"machine"}{"insert_at_top_of_file"}{"value"}' => 'Text to insert at the top of the file (use \n to get newline)',
|
2836 |
|
|
'globals{"machine"}{"insert_in_module_declaration"}{"value"}' => 'Text to insert at the top of the module (after module statement) (use \n to get newline)',
|
2837 |
|
|
'globals{"machine"}{"insert_at_top_of_module"}{"value"}' => 'Text to insert at the top of the module (after module statement) (use \n to get newline)',
|
2838 |
|
|
'globals{"machine"}{"insert_at_bottom_of_file"}{"value"}' => 'Text to insert at the bottom of the file (use \n to get newline)',
|
2839 |
|
|
'globals{"machine"}{"insert_at_bottom_of_module"}{"value"}' => 'Text to insert at the bottom of the module (after module statement) (use \n to get newline)',
|
2840 |
|
|
'globals{"machine"}{"stateout"}{"value"}' => 'Output on which to send out the state vector',
|
2841 |
|
|
'globals{"machine"}{"nextstateout"}{"value"}' => 'Output on which to send out the nextstate vector',
|
2842 |
|
|
'globals{"machine"}{"include_at_top_of_file"}{"value"}' => 'File to include (read) at the top of the file (value is file name)',
|
2843 |
|
|
'globals{"machine"}{"be_cmd"}{"value"}' => 'command to run backend',
|
2844 |
|
|
'globals{"machine"}{"onehot_pragma"}{"value"}' => 'Override for synopsys parallel_case full_case on onehot case statements',
|
2845 |
|
|
'globals{"inputs"}{"*input*"}{"value"}' => 'input signal *input*',
|
2846 |
|
|
'globals{"inputs"}{"*input*"}{"comment"}' => 'Comment for input signal *input*',
|
2847 |
|
|
'globals{"outputs"}{"*output*"}{"value"}' => 'output signal *output*',
|
2848 |
|
|
'globals{"outputs"}{"*output*"}{"type"}' => 'output signal type ("reg", "regdp" or "comb")',
|
2849 |
|
|
'globals{"outputs"}{"*output*"}{"comment"}' => 'Comment for output signal *output*',
|
2850 |
|
|
'globals{"outputs"}{"*output*"}{"useratts"}' => 'User attirbutes for output signal *output*',
|
2851 |
|
|
'globals{"outputs"}{"*output*"}{"resetval"}' => 'Reset value for output signal *output*',
|
2852 |
|
|
'globals{"machine"}{"name"}{"comment"}' => 'FSM name comment',
|
2853 |
|
|
'globals{"trans"}{"*output*"}{"value"}' => 'output signal *output* on transitions',
|
2854 |
|
|
'globals{"machine"}{".*"}{"value"}' => 'misc (indentified by type)',
|
2855 |
|
|
'globals{"machine"}{".*"}{"type"}' => 'misc types',
|
2856 |
|
|
|
2857 |
|
|
'state{"*state*"}{"attributes"}{"*output*"}{"value"}' => 'Value of output signal *state* (if *output* is an output)',
|
2858 |
|
|
'state{"*state*"}{"attributes"}{"vis"}' => '<internal - forces state to be parsed even if no outputs',
|
2859 |
|
|
'state{"*state*"}{"attributes"}{"comment"}' => 'Comment for state *state*',
|
2860 |
|
|
|
2861 |
|
|
'transition{"*transition*"}{"attributes"}{"equation"}{"value"}' => 'Transition equation for transition *transition*',
|
2862 |
|
|
'transition{"*transition*"}{"attributes"}{"*output*"}{"value"}' => 'Value of output signal *output* (if *output* is an output) in transition *transition*',
|
2863 |
|
|
'transition{"*transition*"}{"attributes"}{"*output*"}{"type"}' => 'Type of output signal *output* (if *output* is an output, it will be "output") in transition *transition*',
|
2864 |
|
|
'transition{"*transition*"}{"attributes"}{"priority"}{"value"}' => 'Priority of transition *transition* relative to other transitions FROM that state',
|
2865 |
|
|
'transition{"*transition*"}{"startState"}' => '<Internal>',
|
2866 |
|
|
'transition{"*transition*"}{"endState"}' => '<Internal>',
|
2867 |
|
|
'transition{"*transition*"}{"attributes"}{"graycode"}{"value"}' => 'If set, transition must be gray-coded',
|
2868 |
|
|
'transition{"*transition*"}{"attributes"}{"graytransition"}{"value"}' => '<Internal - backward compatibility>',
|
2869 |
|
|
'transition{"*transition*"}{"attributes"}{"comment"}' => 'Comment for transition *transition*',
|
2870 |
|
|
);
|
2871 |
|
|
#} else {
|
2872 |
|
|
# die "Can't do set_myattributes for encoding \"$encoding\"\n";
|
2873 |
|
|
#}
|
2874 |
|
|
}
|
2875 |
|
|
|
2876 |
|
|
|
2877 |
|
|
# when doing require or use we must return 1
|
2878 |
|
|
1
|