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

Subversion Repositories nanoblaze

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

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

powered by: WebSVN 2.1.0

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