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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [rtl/] [verilog/] [components/] [wb_sdram_ctrl/] [fizzim.pl] - Blame information for rev 49

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

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

powered by: WebSVN 2.1.0

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