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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [boards/] [actel/] [ordb1a3pe1500/] [rtl/] [verilog/] [versatile_mem_ctrl/] [rtl/] [verilog/] [fizzim.pl] - Blame information for rev 408

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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