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

Subversion Repositories nanoblaze

[/] [nanoblaze/] [trunk/] [Tools/] [nanoasm.pl] - Blame information for rev 12

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 7 fcorthay
#!/usr/bin/env perl
2
 
3
my $indent = ' ' x 2;
4
my $separator = '-' x 80;
5
 
6
################################################################################
7
# Input arguments
8
#
9
use Getopt::Std;
10
my %opts;
11 12 fcorthay
getopts('hva:d:r:kz', \%opts);
12 7 fcorthay
 
13
die("\n".
14
    "Usage: $0 [options] fileSpec\n".
15
    "\n".
16
    "Options:\n".
17
    "${indent}-h        display this help message\n".
18
    "${indent}-v        verbose\n".
19
    "${indent}-a bitNb  the number of program address bits\n".
20
    "${indent}-d bitNb  the number of data bits\n".
21
    "${indent}-r bitNb  the number of register address bits\n".
22
    "${indent}-k        keep source comments in VHDL code\n".
23 12 fcorthay
    "${indent}-z        zero don't care bits in VHDL ROM code\n".
24 7 fcorthay
    "\n".
25
    "Assemble code to VHDL for the nanoBlaze processor.\n".
26
    "\n".
27
    "More information with: perldoc $0\n".
28
    "\n".
29
    ""
30
   ) if ($opts{h});
31
 
32
my $verbose              = $opts{v};
33
my $keepComments         = $opts{k};
34 12 fcorthay
my $zeroDontCares        = $opts{z};
35 7 fcorthay
my $addressBitNb         = $opts{a} || 10;
36
my $registerBitNb        = $opts{d} || 8;
37
my $registerAddressBitNb = $opts{r} || 4;
38
 
39
my $asmFileSpec = $ARGV[0] || 'nanoTest.asm';
40
my $outFileSpec = $ARGV[1] || 'rom_mapped.vhd';
41
 
42
#-------------------------------------------------------------------------------
43
# System constants
44
#
45
my $binaryOpCodeLength = 6;
46
my $binaryBranchLength = 5;
47
my $binaryBranchConditionLength = 3;
48
 
49
my $opCodeBaseLength = 10;
50
my $vhdlAddressLength = 14;
51
 
52
#-------------------------------------------------------------------------------
53
# Derived values
54
#
55
                                                                    # file specs
56
my $baseFileSpec = $asmFileSpec;
57
$baseFileSpec =~ s/\..*//i;
58
my $asm1FileSpec = "$baseFileSpec.asm1";        # formatted assembly code
59
my $asm2FileSpec = "$baseFileSpec.asm2";        # code with addresses replaced
60
my $vhdlFileSpec = "$baseFileSpec.vhd";
61
                                                            # instruction length
62
my $binaryOperationInstructionLength =
63
  $binaryOpCodeLength +
64
  $registerAddressBitNb +
65
  $registerBitNb;
66
my $binaryBranchInstructionLength =
67
  $binaryBranchLength +
68
  $binaryBranchConditionLength +
69
  $addressBitNb;
70
my $binaryInstructionLength = $binaryOperationInstructionLength;
71
if ($binaryBranchInstructionLength > $binaryInstructionLength) {
72
  $binaryInstructionLength = $binaryBranchInstructionLength
73
}
74
                                                      # assembler string lengths
75
my $registerCharNb = int( ($registerBitNb-1)/4 ) + 1;
76
my $addressCharNb = int( ($addressBitNb-1)/4 ) + 1;
77
                                                           # vhdl string lengths
78
my $vhdlOpCodeLength = $binaryOpCodeLength + 4;
79
my $opCodeTotalLength = 22 + $registerCharNb;
80
my $vhdlOperand1Length = $registerAddressBitNb + 3;
81
my $vhdlOperand2Length = $registerBitNb + 4;
82
if ($addressBitNb + 3 > $vhdlOperand2Length) {
83
  $vhdlOperand2Length = $addressBitNb + 3
84
}
85
my $vhdlTotalLength = $vhdlOpCodeLength;
86
$vhdlTotalLength = $vhdlTotalLength + $vhdlOperand1Length + $vhdlOperand2Length;
87
$vhdlTotalLength = $vhdlTotalLength + 2*2; # '& '
88
$vhdlTotalLength = $vhdlTotalLength + 1;   # ','
89
 
90
#-------------------------------------------------------------------------------
91
# System variables
92
#
93
my %constants = ();
94
my %addresses = ();
95
 
96
################################################################################
97
# Functions
98
#
99
 
100
#-------------------------------------------------------------------------------
101
# Find constant from "CONSTANT" statement
102
#
103
sub findNewConstant {
104
  my ($codeLine) = @_;
105
 
106
  $codeLine =~ s/CONSTANT\s+//;
107
  my ($name, $value) = split(/,\s*/, $codeLine);
108
  $value = hex($value);
109
 
110
  return ($name, $value);
111
}
112
 
113
#-------------------------------------------------------------------------------
114
# Find address from "ADDRESS" statement
115
#
116
sub findNewAddress {
117
  my ($codeLine) = @_;
118
 
119
  $codeLine =~ s/ADDRESS\s*//;
120
  my $address = hex($codeLine);
121
 
122
  return $address;
123
}
124
 
125
#-------------------------------------------------------------------------------
126
# Format opcodes
127
#
128
sub prettyPrint {
129
  my ($codeLine) = @_;
130
 
131
  my ($opcode, $arguments) = split(/ /, $codeLine, 2);
132
  $opcode = $opcode . ' ' x ($opCodeBaseLength - length($opcode));
133
  $arguments =~ s/,*\s+/, /;
134
  $codeLine = $opcode . $arguments;
135
 
136
  return $codeLine;
137
}
138
 
139
#-------------------------------------------------------------------------------
140
# Format to binary
141
#
142
sub toBinary {
143
  my ($operand, $bitNb) = @_;
144
 
145
  #$operand = sprintf("%0${bitNb}b", $operand);
146
 
147
  my $hexCharNb = int($bitNb/4) + 1;
148
  $operand = sprintf("%0${hexCharNb}X", $operand);
149
  $operand =~ s/0/0000/g;
150
  $operand =~ s/1/0001/g;
151
  $operand =~ s/2/0010/g;
152
  $operand =~ s/3/0011/g;
153
  $operand =~ s/4/0100/g;
154
  $operand =~ s/5/0101/g;
155
  $operand =~ s/6/0110/g;
156
  $operand =~ s/7/0111/g;
157
  $operand =~ s/8/1000/g;
158
  $operand =~ s/9/1001/g;
159
  $operand =~ s/A/1010/g;
160
  $operand =~ s/B/1011/g;
161
  $operand =~ s/C/1100/g;
162
  $operand =~ s/D/1101/g;
163
  $operand =~ s/E/1110/g;
164
  $operand =~ s/F/1111/g;
165
  $operand = substr($operand, length($operand)-$bitNb, $bitNb);
166
 
167
  return $operand;
168
}
169
 
170
################################################################################
171
# Program start
172
#
173
 
174
#-------------------------------------------------------------------------------
175
# Display information
176
#
177
if ($verbose > 0) {
178
  print "$separator\n";
179
  print "Assembling $asmFileSpec to $vhdlFileSpec\n";
180
}
181
 
182
#-------------------------------------------------------------------------------
183
# Calculate adresses, store address labels
184
#
185
if ($verbose > 0) {
186
  print "${indent}Pass 1: from $asmFileSpec to $asm1FileSpec\n";
187
}
188
 
189
my $romAddress = 0;
190
open(asm1File, ">$asm1FileSpec") or die "Unable to open file, $!";
191
open(asmFile, "<$asmFileSpec") or die "Unable to open file, $!";
192
while(my $line = <asmFile>) {
193
  chomp($line);
194
                                                        # split code and comment
195
  my ($codeLine, $comment) = split(/;/, $line, 2);
196
                                                          # handle address label
197
  if ($codeLine =~ m/:/) {
198
    (my $label, $codeLine) = split(/:/, $codeLine);
199
    $label =~ s/\s*//;
200
    print asm1File "; _${label}_:\n";
201
    $addresses{$label} = sprintf("%0${addressCharNb}X", $romAddress);
202
  }
203
                                                                  # cleanup code
204
  $codeLine =~ s/\s+/ /g;
205
  $codeLine =~ s/\A\s//;
206
  $codeLine =~ s/\s\Z//;
207
  $codeLine =~ s/\s,/,/;
208
  if ($codeLine) {
209
                                                    # handle ADDRESS declaration
210
    if ($codeLine =~ m/ADDRESS/) {
211
      $romAddress = findNewAddress($codeLine);
212
    }
213
                                                   # handle CONSTANT declaration
214
    elsif ($codeLine =~ m/CONSTANT/) {
215
      ($name, $value) = findNewConstant($codeLine);
216
      $constants{$name} = sprintf("%0${registerCharNb}X", $value);
217
    }
218
                                                         # print cleaned-up code
219
    else {
220
      $codeLine = prettyPrint($codeLine);
221
      print asm1File sprintf("%0${addressCharNb}X", $romAddress), ": $codeLine";
222
      if ($comment) {
223
        print asm1File " ;$comment";
224
      }
225
      print asm1File "\n";
226
      $romAddress = $romAddress + 1;
227
    }
228
  }
229
  else {
230
    print asm1File ";$comment\n";
231
  }
232
}
233
close(asmFile);
234
close(asm1File);
235
 
236
#-------------------------------------------------------------------------------
237
# Replace constant values and address labels
238
#
239
if ($verbose > 0) {
240
  print "${indent}Pass 2: from $asm1FileSpec to $asm2FileSpec\n";
241
}
242
 
243
open(asm2File, ">$asm2FileSpec") or die "Unable to open file, $!";
244
open(asm1File, "<$asm1FileSpec") or die "Unable to open file, $!";
245
while(my $line = <asm1File>) {
246
  chomp($line);
247
                                                        # split code and comment
248
  my ($opcode, $comment) = split(/;/, $line, 2);
249
  if ( ($line =~ m/;/) and ($comment eq '') ) {
250
    $comment = ' ';
251
  }
252
                                                                  # cleanup code
253
  $opcode =~ s/\s+\Z//;
254
                                                             # replace constants
255
  foreach my $name (keys %constants) {
256
    $opcode =~ s/$name/$constants{$name}/g;
257
  }
258
                                                             # replace addresses
259
  foreach my $label (keys %addresses) {
260
    $opcode =~ s/$label/$addresses{$label}/g;
261
  }
262
                                                                  # cleanup code
263
  $opcode = uc($opcode);
264
  $opcode =~ s/\sS([0-9A-F])/ s$1/g;
265
                                                         # print cleaned-up code
266
  if ($comment) {
267
    if ($opcode) {
268
      $opcode = $opcode . ' ' x ($opCodeTotalLength - length($opcode));
269
    }
270
    $comment =~ s/\s+\Z//;
271
    print asm2File "$opcode;$comment\n";
272
  }
273
  else {
274
    print asm2File "$opcode\n";
275
  }
276
}
277
close(asm1File);
278
close(asm2File);
279
 
280
#-------------------------------------------------------------------------------
281
# Write VHDL ROM code
282
#
283
if ($verbose > 0) {
284
  print "${indent}Pass 3: from $asm2FileSpec to $vhdlFileSpec\n";
285
}
286
open(vhdlFile, ">$vhdlFileSpec") or die "Unable to open file, $!";
287
print vhdlFile <<DONE;
288
ARCHITECTURE mapped OF programRom IS
289
 
290
  subtype opCodeType is std_ulogic_vector(5 downto 0);
291
  constant opLoadC   : opCodeType := "000000";
292
  constant opLoadR   : opCodeType := "000001";
293
  constant opInputC  : opCodeType := "000100";
294
  constant opInputR  : opCodeType := "000101";
295
  constant opFetchC  : opCodeType := "000110";
296
  constant opFetchR  : opCodeType := "000111";
297
  constant opAndC    : opCodeType := "001010";
298
  constant opAndR    : opCodeType := "001011";
299
  constant opOrC     : opCodeType := "001100";
300
  constant opOrR     : opCodeType := "001101";
301
  constant opXorC    : opCodeType := "001110";
302
  constant opXorR    : opCodeType := "001111";
303
  constant opTestC   : opCodeType := "010010";
304
  constant opTestR   : opCodeType := "010011";
305
  constant opCompC   : opCodeType := "010100";
306
  constant opCompR   : opCodeType := "010101";
307
  constant opAddC    : opCodeType := "011000";
308
  constant opAddR    : opCodeType := "011001";
309
  constant opAddCyC  : opCodeType := "011010";
310
  constant opAddCyR  : opCodeType := "011011";
311
  constant opSubC    : opCodeType := "011100";
312
  constant opSubR    : opCodeType := "011101";
313
  constant opSubCyC  : opCodeType := "011110";
314
  constant opSubCyR  : opCodeType := "011111";
315
  constant opShRot   : opCodeType := "100000";
316
  constant opOutputC : opCodeType := "101100";
317
  constant opOutputR : opCodeType := "101101";
318
  constant opStoreC  : opCodeType := "101110";
319
  constant opStoreR  : opCodeType := "101111";
320
 
321
  subtype shRotCinType is std_ulogic_vector(2 downto 0);
322
  constant shRotLdC : shRotCinType := "00-";
323
  constant shRotLdM : shRotCinType := "01-";
324
  constant shRotLdL : shRotCinType := "10-";
325
  constant shRotLd0 : shRotCinType := "110";
326
  constant shRotLd1 : shRotCinType := "111";
327
 
328
  constant registerAddressBitNb : positive := $registerAddressBitNb;
329
  constant shRotPadLength : positive
330
    := dataOut'length - opCodeType'length - registerAddressBitNb
331
     - 1 - shRotCinType'length;
332
  subtype shRotDirType is std_ulogic_vector(1+shRotPadLength-1 downto 0);
333
  constant shRotL : shRotDirType := (0 => '0', others => '-');
334
  constant shRotR : shRotDirType := (0 => '1', others => '-');
335
 
336
  subtype branchCodeType is std_ulogic_vector(4 downto 0);
337
  constant brRet  : branchCodeType := "10101";
338
  constant brCall : branchCodeType := "11000";
339
  constant brJump : branchCodeType := "11010";
340
  constant brReti : branchCodeType := "11100";
341
  constant brEni  : branchCodeType := "11110";
342
 
343
  subtype branchConditionType is std_ulogic_vector(2 downto 0);
344
  constant brDo : branchConditionType := "000";
345
  constant brZ  : branchConditionType := "100";
346
  constant brNZ : branchConditionType := "101";
347
  constant brC  : branchConditionType := "110";
348
  constant brNC : branchConditionType := "111";
349
 
350
  subtype memoryWordType is std_ulogic_vector(dataOut'range);
351
  type memoryArrayType is array (0 to 2**address'length-1) of memoryWordType;
352
 
353
  signal memoryArray : memoryArrayType := (
354
DONE
355
open(asm2File, "<$asm2FileSpec") or die "Unable to open file, $!";
356
while(my $line = <asm2File>) {
357
  chomp($line);
358
                                                        # split code and comment
359
  my ($opcode, $comment) = split(/;/, $line, 2);
360
  if ( ($line =~ m/;/) and ($comment eq '') ) {
361
    $comment = ' ';
362
  }
363
                                                             # addresses to VHDL
364
  my $address;
365
  if ($opcode) {
366
    ($address, $opcode) = split(/:\s+/, $opcode, 2);
367
    $address = '16#' . $address . '# =>';
368
    $address = ' ' x ($vhdlAddressLength - length($address)) . $address;
369
  }
370
                                                                # opcode to VHDL
371
  if ($opcode) {
372
    if ($comment eq '') {
373
      $comment = ' ' . $opcode;
374
    }
375
    else {
376
      $comment = ' ' . $opcode . ';' . $comment;
377
    }
378
                                                                   # replace NOP
379
    $opcode =~ s/\ANOP/LOAD s0, s0/;
380
                                                    # split opcodes and operands
381
    $opcode =~ s/\s+/ /;
382
    $opcode =~ s/\s+\Z//;
383
    ($opcode, my $operand1, my $operand2) = split(/\s/, $opcode);
384
    $operand1 =~ s/,//;
385
    $operand1 =~ s/S/s/;
386
    $operand2 =~ s/S/s/;
387
    if ( ($opcode =~ m/\ASL/) or ($opcode =~ m/\ASR/) ) {
388
      $operand2 = substr($opcode, 0, 3);
389
      $opcode = 'SHIFT';
390
    }
391
    if ( ($opcode =~ m/\ARL/)  or ($opcode =~ m/\ARR/) ) {
392
      $operand2 = substr($opcode, 0, 2);
393
      $opcode = 'ROT';
394
    }
395
    if ( ($opcode eq 'JUMP') or ($opcode eq 'CALL') or ($opcode eq 'RETURN') ) {
396
      unless ($operand2) {
397
        unless ($opcode eq 'RETURN') {
398
          $operand2 = $operand1;
399
        }
400
        $operand1 = 'AW'; # AlWays
401
      }
402
    }
403
    #...........................................................................
404
                                                               # opcodes to VHDL
405
    $opcode =~ s/LOAD/opLoadC/;
406
    $opcode =~ s/AND/opAndC/;
407
    $opcode =~ s/XOR/opXorC/;
408
    $opcode =~ s/ADDCY/opAddCyC/;
409
    $opcode =~ s/SUBCY/opSubCyC/;
410
    $opcode =~ s/ADD/opAddC/;
411
    $opcode =~ s/SUB/opSubC/;
412
    $opcode =~ s/SHIFT/opShRot/;
413
    $opcode =~ s/ROT/opShRot/;
414
    $opcode =~ s/COMPARE/opCompC/;
415
    $opcode =~ s/TEST/opTestC/;
416
    $opcode =~ s/FETCH/opFetchC/;
417
    $opcode =~ s/STORE/opStoreC/;
418
    $opcode =~ s/OR/opOrC/;
419
    $opcode =~ s/INPUT/opInputC/;
420
    $opcode =~ s/OUTPUT/opOutputC/;
421
    $opcode =~ s/JUMP/brJump/;
422
    $opcode =~ s/CALL/brCall/;
423
    $opcode =~ s/RETURN/brRet/;
424
    if ($operand2 =~ m/s[0-9A-F]/) {
425
      $opcode =~ s/C\Z/R/;
426
    }
427
    $opcode = $opcode . ' ' x ($vhdlOpCodeLength - length($opcode)) . '& ';
428
    #...........................................................................
429
                                                     # register as first operand
430
    if ($operand1 =~ m/s[0-9A-F]/) {
431
      $operand1 =~ s/\As//;
432
      $operand1 = '"' . toBinary($operand1, $registerAddressBitNb) . '"';
433
    }
434
                                                                # test condition
435
    $operand1 =~ s/NC/brNC/;
436
    $operand1 =~ s/NZ/brNZ/;
437
    $operand1 =~ s/\AC/brC/;
438
    $operand1 =~ s/\AZ/brZ/;
439
    $operand1 =~ s/AW/brDo/;
440
    if ($opcode =~ m/brRet/) {
441
      $operand2 = 0;
442
    }
443
    if ($operand2 eq '') {
444
      $operand1 = $operand1 . ',';
445
    }
446
    $operand1 = $operand1 . ' ' x ($vhdlOperand1Length - length($operand1));
447
    unless ($operand2 eq '') {
448
      $operand1 = $operand1 . '& ';
449
    }
450
#print "|$opcode| |$operand1| |$operand2|\n";
451
    #...........................................................................
452
                                                    # register as second operand
453
    $operand2 =~ s/\A\((.*)\)\Z/$1/;
454
    if ($operand2 =~ m/s[0-9A-F]/) {
455
      $operand2 =~ s/\As//;
456
      $operand2 = toBinary($operand2, $registerAddressBitNb);
457
      if ($registerBitNb > $registerAddressBitNb) {
458
        $operand2 = $operand2 . '-' x ($registerBitNb - $registerAddressBitNb);
459 12 fcorthay
        if ($zeroDontCares) {
460
          $operand2 =~ s/\-/0/g;
461
        }
462 7 fcorthay
      }
463
    }
464
                                                     # address as second operand
465
    elsif ($opcode =~ m/\Abr/) {
466
      my $fill = '';
467
      if ($binaryBranchInstructionLength < $binaryInstructionLength) {
468
        $fill = '-' x ($binaryInstructionLength - $binaryBranchInstructionLength);
469 12 fcorthay
        if ($zeroDontCares) {
470
          $fill =~ s/\-/0/g;
471
        }
472 7 fcorthay
      }
473
      if ( ($opcode =~ m/Ret/) ) {
474
        $operand2 = $fill . '-' x $addressBitNb;
475
      }
476
      else {
477
        $operand2 = $fill . toBinary(hex($operand2), $addressBitNb);
478
      }
479
    }
480
                                                  # shift and rotate operators
481
    elsif ($opcode =~ m/opShRot/) {
482
      $operand2 =~ s/SL0/shRotL & shRotLd0/;
483
      $operand2 =~ s/SL1/shRotL & shRotLd1/;
484
      $operand2 =~ s/SLX/shRotL & shRotLdL/;
485
      $operand2 =~ s/SLA/shRotL & shRotLdC/;
486
      $operand2 =~ s/SR0/shRotR & shRotLd0/;
487
      $operand2 =~ s/SR1/shRotR & shRotLd1/;
488
      $operand2 =~ s/SRX/shRotR & shRotLdM/;
489
      $operand2 =~ s/SRA/shRotR & shRotLdC/;
490
      $operand2 =~ s/RL/shRotL & shRotLdH/;
491
      $operand2 =~ s/RR/shRotR & shRotLdL/;
492
    }
493
                                                  # constant as second operand
494
    else {
495
      $operand2 = toBinary(hex($operand2), $registerBitNb);
496
      if ($registerAddressBitNb > $registerBitNb) {
497
        $operand2 = '-' x ($registerAddressBitNb - $registerBitNb) . $operand2;
498
      }
499
    }
500
    unless ($opcode =~ m/opShRot/) {
501
      $operand2 = '"' . $operand2 . '"';
502
    }
503
                                                          # add separator at end
504
    if ($operand2) {
505
      $operand2 = $operand2 . ',';
506
    }
507
    #...........................................................................
508
                                               # concatenate opcode and operands
509
    $opcode = $opcode . $operand1 . $operand2;
510
  }
511
  else {
512
    $address = ' ' x $vhdlAddressLength;
513
  }
514
                                                               # print VHDL code
515
  if ($keepComments == 0) {
516
    if ($opcode) {
517
      print vhdlFile "$address $opcode\n";
518
    }
519
  }
520
  else {
521
    $opcode = $opcode . ' ' x ($vhdlTotalLength - length($opcode));
522
    if ($comment) {
523
      $comment =~ s/\s+\Z//;
524
      print vhdlFile "$address $opcode--$comment\n";
525
    }
526
    else {
527
      print vhdlFile "$address $opcode\n";
528
    }
529
  }
530
}
531
close(asm2File);
532
print vhdlFile <<DONE;
533
    others => (others => '0')
534
  );
535
 
536
BEGIN
537
 
538
  process (clock)
539
  begin
540
    if rising_edge(clock) then
541
      if en = '1' then
542
        dataOut <= memoryArray(to_integer(address));
543
      end if;
544
    end if;
545
  end process;
546
 
547
END ARCHITECTURE mapped;
548
DONE
549
close(vhdlFile);
550
 
551
#-------------------------------------------------------------------------------
552
# Delete original file and copy VHDL file
553
#
554
if ($verbose > 0) {
555
  print "Copying $vhdlFileSpec to $outFileSpec\n";
556
}
557
 
558
use File::Copy;
559
unlink($outFileSpec);
560
copy($vhdlFileSpec, $outFileSpec) or die "File cannot be copied.";
561
#rename($vhdlFileSpec, $outFileSpec);
562
 
563
if ($verbose > 0) {
564
  print "$separator\n";
565
}

powered by: WebSVN 2.1.0

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