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

Subversion Repositories socgen

[/] [socgen/] [trunk/] [tools/] [bin/] [fizzim] - Blame information for rev 106

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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