OpenCores
URL https://opencores.org/ocsvn/socgen/socgen/trunk

Subversion Repositories socgen

[/] [socgen/] [trunk/] [tools/] [fizzim/] [fizzim.pl] - Blame information for rev 117

Details | Compare with Previous | View Log

Line No. Rev Author Line
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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.