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

Subversion Repositories light8080

[/] [light8080/] [trunk/] [util/] [uasm.pl] - Blame information for rev 80

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

Line No. Rev Author Line
1 2 ja_rd
################################################################################
2
# uasm.pl : light8080 core microcode assembler
3
################################################################################
4
# Usage: perl uasm.pl <microcode file name> <command list>
5
# 
6
# The command list is a space-separated sequence of the following:
7
#
8
# -lst      : Shows a listing of the assembled microinstructions next to their
9
#             assembler source lines. Not very useful because it does not show 
10
#             assembler pragma, label or comment lines.
11
# -labels   : Shows a list of all defined labels with their address and the 
12
#             number of times they are used.
13
# -bitfields: Shows a list of all the different microinstructions generated, 
14
#             plus the number of times they are used. Might be useful to encode
15
#             the microinstructions and save rom bits.
16
# -instructions: Shows a list of all defined instructions with the address their
17
#             microcode starts at.
18
# -rom_bin  : Shows a raw list of all the binary microinstructions.
19
# -rom_vhdl : Shows a vhdl block containing the microcode rom declaration.
20
#
21
# If none of the above commands is given, the program just exits silently. Any 
22
# unrecognized command is silently ignored.
23
################################################################################
24
# Assembler format (informal definition, source is the ultimate reference!):
25
#
26
#<microinstruction line> := 
27 62 ja_rd
#    [<label>] | (*1)
28
#    <operand stage control> ; <ALU stage control> [; [<flag list>]] |
29
#    JSR <destination address>|TJSR <destination address>
30 2 ja_rd
#
31
#<label> := {':' immediately followed by a common identifier}
32
#<destination address> := {an identifier defined as label anywhere in the file}
33
#<operand stage control> :=  <op_reg> = <op_src> | NOP
34
#<op_reg> := T1 | T2
35
#<op_src> := <register> | DI | <IR register>
36
#<IR register> := {s}|{d}|{p}0|{p}1 (*3)
37
#<register> := _a|_b|_c|_d|_e|_h|_l|_f|_a|_ph|_pl|_x|_y|_z|_w|_sh|_sl|
38
#<ALU stage control> := <alu_dst> = <alu_op> | NOP 
39
#<alu_dst> := <register> | DO
40
#<alu_op> := add|adc|sub|sbb| and|orl|not|xrl| rla|rra|rlca|rrca| aaa|
41
#            t1|rst|daa|cpc|sec|psw
42
#<flag list> := <flag> [, <flag> ...] 
43
#<flag> := #decode|#di|#ei|#io|#auxcy|#clrt1|#halt|#end|#ret|#rd|#wr|#setacy 
44 64 ja_rd
#          #ld_al|#ld_addr|#fp_c|#fp_r|#fp_rc|#clr_cy_ac  (*2)
45 2 ja_rd
#
46 62 ja_rd
#  *1 Labels appear alone by themselves in a line
47
#  *2 There are some restrictions on the flags that can be used together
48
#  *3 Registers are specified by IR field
49 2 ja_rd
#
50
################################################################################
51
# ALU operations 
52
#
53
#Operation      Encoding    ALU result
54
#===============================================================================
55
#ADD            001100      T2 + T1
56
#ADC            001101      T2 + T1 + CY
57
#SUB            001110      T2 - T1
58
#SBB            001111      T2 – T1 - CY
59
#AND            000100      T1 AND T2
60
#ORL            000101      T1 OR T2
61
#NOT            000110      NOT T1 
62
#XRL            000111      T1 XOR T2
63
#RLA            000000      8080 RLC
64
#RRA            000001      8080 RRC
65
#RLCA           000010      8080 RAL
66
#RRCA           000011      8080 RAR
67
#T1             010111      T1
68
#RST            011111      8*IR(5..3), as per RST instruction
69
#DAA            101000      DAA T1 (but only after executing 2 in a row)
70
#CPC            101100      UNDEFINED     (CY complemented)
71
#SEC            101101      UNDEFINED     (CY set)
72
################################################################################
73
# Flags :
74
# --- Flags from group 1: use only one of these
75
# #decode :  Load address counter and IR with contents of data input lines,
76
#            thus starting opcode decoging.
77
# #ei :      Set interrupt enable register.
78
# #di :      Reset interrupt enable register.
79
# #io :      Activate io signal for 1st cycle.
80
# #auxcy :   Use aux carry instead of regular carry for this operation. 
81
# #clrt1 :   Clear T1 at the end of 1st cycle.
82
# #halt :    Jump to microcode address 0x07 without saving return value.
83
# 
84
# --- Flags from group 2: use only one of these
85
# #setacy :  Set aux carry at the start of 1st cycle (used for ++).
86
# #end :     Jump to microinstruction address 3 after the present m.i.
87
# #ret :     Jump to address saved by the last JST or TJSR m.i.
88
# #rd :      Activate rd signal for the 2nd cycle.
89
# #wr :      Activate wr signal for the 2nd cycle.
90
# --- Independent flags: no restrictions
91
# #ld_al :   Load AL register with register bank output as read by operation 1.
92
#            (used in memory and io access). 
93
# #ld_addr : Load address register (H byte = register bank output as read by 
94
#            operation 1, L byte = AL). 
95
#            Activate vma signal for 1st cycle.
96 64 ja_rd
# #clr_acy : Instruction clears CY and AC flags. Use with #fp_rc.
97 2 ja_rd
# --- PSW update flags: use only one of these
98
# #fp_r :    This instruction updates all PSW flags except for C.
99
# #fp_c :    This instruction updates only the C flag in the PSW.
100
# #fp_rc :   This instruction updates all the flags in the PSW.
101
################################################################################
102
# Read the design notes for a brief reference to the micromachine internal
103
# behavior, including implicit loads/erases.
104
################################################################################
105
 
106
$file = shift(@ARGV);
107
 
108
open(INFO, $file) or die "unable to open file '$file'\n";
109
@lines = <INFO>;
110
close(INFO);
111
 
112
$field2_nop = '0'.'0000'.'00'.'0'.'0'.'000000';
113
$field2_jsr = '0'.'0000'.'00'.'0'.'0'.'000000';
114
 
115
%field1_ops =
116
  ( 'nop',        '000'.'000'.'00000'.'00'.'0000'.$field2_nop,
117
    'jsr',        '000'.'010'.'00000'.'00'.'0000'.$field2_jsr,
118
    'tjsr',       '000'.'100'.'00000'.'00'.'0000'.$field2_jsr,
119
 
120
    't1 = {s}',   '000'.'000'.'00101'.'01'.'0000'.$field2_nop,
121
    't1 = {d}',   '000'.'000'.'00101'.'10'.'0000'.$field2_nop,
122
    't1 = {p}0',  '000'.'000'.'00101'.'11'.'0000'.$field2_nop,
123
    't1 = {p}1',  '000'.'000'.'00101'.'11'.'0001'.$field2_nop,
124
    't1 = di',    '000'.'000'.'00100'.'00'.'0000'.$field2_nop,
125
    't1 = _b',    '000'.'000'.'00101'.'00'.'0000'.$field2_nop,
126
    't1 = _c',    '000'.'000'.'00101'.'00'.'0001'.$field2_nop,
127
    't1 = _d',    '000'.'000'.'00101'.'00'.'0010'.$field2_nop,
128
    't1 = _e',    '000'.'000'.'00101'.'00'.'0011'.$field2_nop,
129
    't1 = _h',    '000'.'000'.'00101'.'00'.'0100'.$field2_nop,
130
    't1 = _l',    '000'.'000'.'00101'.'00'.'0101'.$field2_nop,
131
    't1 = _a',    '000'.'000'.'00101'.'00'.'0111'.$field2_nop,
132
    't1 = _f',    '000'.'000'.'00101'.'00'.'0110'.$field2_nop,
133
    't1 = _ph',   '000'.'000'.'00101'.'00'.'1000'.$field2_nop,
134
    't1 = _pl',   '000'.'000'.'00101'.'00'.'1001'.$field2_nop,
135
    't1 = _x',    '000'.'000'.'00101'.'00'.'1010'.$field2_nop,
136
    't1 = _y',    '000'.'000'.'00101'.'00'.'1011'.$field2_nop,
137
    't1 = _z',    '000'.'000'.'00101'.'00'.'1100'.$field2_nop,
138
    't1 = _w',    '000'.'000'.'00101'.'00'.'1101'.$field2_nop,
139
    't1 = _sh',   '000'.'000'.'00101'.'00'.'1110'.$field2_nop,
140
    't1 = _sl',   '000'.'000'.'00101'.'00'.'1111'.$field2_nop,
141
 
142
    't2 = {s}',   '000'.'000'.'00011'.'01'.'0000'.$field2_nop,
143
    't2 = {d}',   '000'.'000'.'00011'.'10'.'0000'.$field2_nop,
144
    't2 = {p}0',  '000'.'000'.'00011'.'11'.'0000'.$field2_nop,
145
    't2 = {p}1',  '000'.'000'.'00011'.'11'.'0001'.$field2_nop,
146
    't2 = di',    '000'.'000'.'00010'.'00'.'0000'.$field2_nop,
147
    't2 = _b',    '000'.'000'.'00011'.'00'.'0000'.$field2_nop,
148
    't2 = _c',    '000'.'000'.'00011'.'00'.'0001'.$field2_nop,
149
    't2 = _d',    '000'.'000'.'00011'.'00'.'0010'.$field2_nop,
150
    't2 = _e',    '000'.'000'.'00011'.'00'.'0011'.$field2_nop,
151
    't2 = _h',    '000'.'000'.'00011'.'00'.'0100'.$field2_nop,
152
    't2 = _l',    '000'.'000'.'00011'.'00'.'0101'.$field2_nop,
153
    't2 = _a',    '000'.'000'.'00011'.'00'.'0111'.$field2_nop,
154
    't2 = _f',    '000'.'000'.'00011'.'00'.'0110'.$field2_nop,
155
    't2 = _ph',   '000'.'000'.'00011'.'00'.'1000'.$field2_nop,
156
    't2 = _pl',   '000'.'000'.'00011'.'00'.'1001'.$field2_nop,
157
    't2 = _x',    '000'.'000'.'00011'.'00'.'1010'.$field2_nop,
158
    't2 = _y',    '000'.'000'.'00011'.'00'.'1011'.$field2_nop,
159
    't2 = _z',    '000'.'000'.'00011'.'00'.'1100'.$field2_nop,
160
    't2 = _w',    '000'.'000'.'00011'.'00'.'1101'.$field2_nop,
161
    't2 = _sh',   '000'.'000'.'00011'.'00'.'1110'.$field2_nop,
162
    't2 = _sl',   '000'.'000'.'00011'.'00'.'1111'.$field2_nop
163
 
164
  );
165
 
166
 
167
$re_field1 = "(".join('|',keys %field1_ops).")";
168
$re_field1 =~ s/\[/\\\[/g;
169
$re_field1 =~ s/\]/\\\]/g;
170
 
171
%field2_ops =
172
  ( 'add',    '001100',
173
    'adc',    '001101',
174
    'sub',    '001110',
175
    'sbb',    '001111',
176
 
177
    'and',    '000100',
178
    'orl',    '000110',
179
    'not',    '000111',
180
    'xrl',    '000101',
181
 
182
    'rla',    '000000',
183
    'rra',    '000001',
184
    'rlca',   '000010',
185
    'rrca',   '000011',
186
 
187
    'aaa',    '111000',
188
 
189
    't1',     '010111',
190
    'rst',    '011111',
191
    'daa',    '101000',
192
    'cpc',    '101100',
193
    'sec',    '101101',
194
    'psw',    '110000'
195
  );
196
 
197
 
198
$re_f2_ops = "(".join('|',keys %field2_ops).")";
199
$re_f2_ops =~ s/\[/\\\[/g;
200
$re_f2_ops =~ s/\]/\\\]/g;
201
 
202
# 'parse' command line flags into a string
203
$cmdline = join ':', @ARGV;
204
 
205
$num_line = 0;
206
$addr = 0;
207
 
208
%labels = ();                 # <label, address>
209
@label_uses = ();             # <label, [addresses in which it's used]>
210
@undefined_targets = ();      # array of <label, address in which it's used>
211
$num_errors = 0;
212
 
213
@bitfields = ();
214
 
215
@rom = ();
216
@asm = ();
217
@errors = ();
218
@num_lines = ();
219
 
220
%asm_to_uaddr = ();           # opcode asm -> uaddress
221
%uaddr_to_asm = ();           # uaddress -> opcode asm
222
 
223
%uaddr_to_pattern = ();       # uaddress -> pattern
224
%pattern_to_uaddr = ();       # pattern -> uaddress -- simulation, decoder
225
 
226
LINE: foreach $line (@lines) {
227
 
228 62 ja_rd
  $num_line++;
229
 
230
  $line =~ tr/A-Z/a-z/;
231
  $line =~ s/(--|\/\/).*//;
232 2 ja_rd
  $line =~ s/^\s*//g;
233
  $line =~ s/\s*\$//g;
234
  chomp($line);
235
 
236
  $uinst = {
237
    field_1 => '',
238
    src     => '',
239
    special => '',
240
    field_2 => '',
241
    field_0 => '000000',
242
    flags   => '',
243
    error   => '',
244
    asm     => $line
245
  };
246
 
247
 
248
  # if line is whitespace or comment (which has been changed to whitespace)
249
  # then skip to next line
250
  if($line eq ''){
251
    next;
252
  }
253
 
254 62 ja_rd
  # if $line is a label declaration, get it and skip to next line
255 2 ja_rd
  # note labels come alone in the line, unlike other assemblers
256
  # TODO it'd be simple to change this...
257 62 ja_rd
  if($line =~ /^\s*:(\w+)/){
258
    # subroutine label (labels are only used for jsrs)
259
    $labels{$1} = $addr;
260
    next;
261
  }
262 2 ja_rd
 
263
  # if line is a pragma, process it
264
  if($line =~ /^\s*__/){
265
    # TODO process pragmas __reset, __fetch, __int
266
 
267
    #if($line =~ /^\s*__code\s+"([0|1|s|d|p|a|r]+)"/){
268
      # we do nothing with the opcode byte; it's for reference only
269
      #printf "%04d # %s\n",$addr,$1;
270
    #}
271
    if($line =~ /^\s*__asm\s+(.*)/){
272
      # save the start address for the CPU instruction
273
      # it will be used in the design of the decoder
274
      $asm_to_uaddr{$1} = $addr;
275
      $uaddr_to_asm{$addr} = $1;
276
    }
277
 
278
    if($line =~ /^\s*__code\s+"(.*)".*/){
279
      # save the start address for the CPU instruction
280
      # it will be used in the design of the decoder
281
      $pattern_to_uaddr{$1} = $addr;
282
      $uaddr_to_pattern{$addr} = $1;
283
    }
284
 
285
 
286
    next;
287
  }
288
 
289
  # get flags field (all text following 1st '#' included)
290
  # remove it so we're left with 'field1 ; field2 [;]'
291
  $line = process_flags($line);
292
 
293
  # break line in 1 or 2 fields
294
  @fields = split /;/, $line;
295
 
296
  # process 1st field...
297 62 ja_rd
  $done = process_field1($fields[0]);
298 2 ja_rd
 
299
  # ...and process 2nd field if there is one (depends on field1 format)
300
  # TODO check that there's no field2 when there shouldn't  
301 62 ja_rd
  if($done != 1){
302 2 ja_rd
    $done = process_field2($fields[1]);
303 62 ja_rd
  }
304 2 ja_rd
 
305
  # finally, process extra flags produced by field1 assembly (jsr/tjsr)
306
  process_extra_flags();
307
 
308
  # complete bitfield with flags...
309
  substr($uinst->{field1}, 0, 6) = $uinst->{field_0};
310
 
311
  # Now, we already have the bitfields.
312
 
313
  push(@rom, $uinst->{field1});
314
  push(@asm, substr($line,0,40));
315
  push(@num_lines, $num_line);
316
  if($uinst->{error} eq ''){
317
    push(@errors, '');
318
  }
319
  else{
320
    push(@errors, $uinst->{error});
321
  }
322
 
323
  $addr++;  #addr++ even for error uinsts
324
 
325
}
326
continue {
327
}
328
 
329
# Line processing finished (1st pass). Start 2nd pass and do listings 
330
# if requested
331
 
332
# 2nd pass
333
 
334
# now we know the value of all labels, fill in address field of forward jumps
335
foreach $target (@undefined_targets){
336
  @item = @{$target};
337
  $value = to_bin($labels{$item[0]}, 8);
338
  $adr = $item[1]*1;
339
 
340 62 ja_rd
  substr($rom[$adr], 20,2, substr($value, 0,2));
341
  substr($rom[$adr], 26,6, substr($value, 2,6));
342 2 ja_rd
}
343
 
344
foreach $bf (@rom){
345
  push(@bitfields, $bf);
346
}
347
 
348
# listings
349
 
350
if($cmdline =~ /-lst/){
351
  $do_lst = 1;
352
}
353
 
354
$i = 0;
355
foreach $bf (@rom){
356
  if($do_lst){
357
    printf "%02x %32s :: %s\n", $i,  $bf, $asm[$i];
358
    if($errors[$i] ne ''){
359
      printf "     ERROR (%d): %s\n", $num_lines[$i], $errors[$i];
360
    }
361
  }
362
 
363
  $i++;
364
}
365
 
366
if($do_lst){
367
  # completion message
368
  printf "\nDone. %d uinsts, %d errors.\n", $addr, $num_errors;
369
}
370
 
371
# label listing
372
if($cmdline =~ /\-labels/){
373
  label_list();
374
}
375
 
376
# bitfield histogram
377
if($cmdline =~ /\-bitfields/){
378
  bitfield_histogram();
379
}
380
 
381
# show cpu instruction microcode addresses
382
if($cmdline =~ /\-instructions/){
383
  foreach $asm (sort {$asm_to_uaddr{$a} <=> $asm_to_uaddr{$b}}(keys %asm_to_uaddr)){
384
    $uaddress = $asm_to_uaddr{$asm};
385
    printf "%02x %s  %s\n", $uaddress, $uaddr_to_pattern{$uaddress}, $asm;
386
  }
387
}
388
 
389
if($cmdline =~ /\-rom_vhdl/){
390
  show_decoder_table('vhdl');
391
}
392
 
393
if($cmdline =~ /\-rom_bin/){
394
  show_decoder_table('bin');
395
}
396
 
397
# end of main program
398
 
399
 
400
################################################################################
401
 
402
 
403
sub show_decoder_table {
404
 
405
  my $fmat = shift(@_);
406
 
407
  # show decoder rom contents
408
  %decoder_hash = ();
409
  foreach $pat (keys %pattern_to_uaddr){
410
    $add = $pattern_to_uaddr{$pat};
411
    $pat =~ s/[a-z]/\[01\]/g;
412
    $decoder_hash{$pat} = $add;
413
  }
414
 
415
  @decoder_rom = ();
416
  for($i = 0; $i<256; $i++){
417
    $b = to_bin($i, 8);
418
    $val = 0;
419
    # We'll match the opcode to the pattern with the shortest length; that is,
420
    # the one with the less wildcards in it. Crude but effective in this case.
421
    $len_matched_pat = 1000;
422
    foreach $pat (keys %decoder_hash){
423
      if($b =~ /$pat/){
424
        if(length($pat) < $len_matched_pat){
425
          $val = $decoder_hash{$pat};
426
          $len_matched_pat = length($pat);
427
        }
428
        #last;
429
      }
430
    }
431
    push @decoder_rom, $val;
432
  }
433
 
434
  if($fmat eq 'vhdl'){
435
    # print rom vhdl header...
436
    print "type t_rom is array (0 to 511) of std_logic_vector(31 downto 0);\n";
437
    print "signal rom : t_rom := (\n";
438
  }
439
 
440
  # The 1st half of the uinst rom holds 256 uinstructions
441
  my $i=0;
442
  foreach $bf (@rom){
443
    if($fmat eq 'vhdl'){
444
      printf "\"%s\", -- %03x\n", $bf, $i;
445
    }
446
    else{
447
      printf "%s\n", $bf;
448
    }
449
    $i++;
450
  }
451
  # Fill remaining slots with ENDs 
452
  for(;$i<256;$i++){
453
    my $val = '00000100000000000000000000000000';
454
    if($fmat eq 'vhdl'){
455
      printf "\"%s\", -- %03x\n", $val, $i;
456
    }
457
    else{
458
       printf "%s\n", $val;
459
    }
460
  }
461
 
462
  # The 2nd half (upper 256 entries) of the ucode rom contains a jump table
463
  # with a jsr for each of the 256 opcodes, serving as cheap decoder:
464
  foreach $entry (@decoder_rom){
465
    my $val = to_bin($entry, 8);
466
    $val = '00001000000000000000'.substr($val,0,2).'0000'.substr($val,2,6);
467
    $i++;
468
    if($fmat eq 'vhdl'){
469
      printf "\"%s\"", $val;
470
      if($i<512){
471
        print ",";
472
      }
473
      else{
474
        print " ";
475
      }
476
      printf " -- %03x\n", ($i - 1);
477
    }
478
    else{
479
      printf "%s\n", $val;
480
    }
481
  }
482
 
483
  if($fmat eq 'vhdl'){
484
    # close vhdl declaration
485
    print "\n);\n";
486
  }
487
 
488
}
489
 
490
sub label_list {
491
  # label table listing 
492
  print "\nlabels:\n";
493
  print "---------------------------------\n";
494
  print "label                addr    uses\n";
495
  print "---------------------------------\n";
496
 
497
  %hist_labels;
498
  $hist_labels{$_}++ for @label_uses;
499
 
500
  foreach $label (keys %hist_labels){
501
    printf "%-20s %04x    %d\n", $label, $labels{$label}, $hist_labels{$label};
502
  }
503
}
504
 
505
sub bitfield_histogram {
506
 
507
  %hist_bitfields;
508
  $hist_bitfields{$_}++ for @bitfields;
509
  @unique_bitfields = keys %hist_bitfields;
510
 
511
  printf "\nbitfield usage (total: %d)\n", $#unique_bitfields;
512
  print "------------------------------------------------\n";
513
  print "bitfield                            uses\n";
514
  print "------------------------------------------------\n";
515
 
516
  foreach $bfield (sort sortFieldsByFrequency(keys %hist_bitfields)){
517
    printf "%-32s    %d\n", $bfield, $hist_bitfields{$bfield};
518
  }
519
}
520
 
521
sub sortFieldsByFrequency {
522
   $hist_bitfields{$b} <=> $hist_bitfields{$a};
523
}
524
 
525
sub process_extra_flags {
526
 
527
  $flags1 = '';
528
  $flags2 = '';
529
 
530
 
531
  # first, process flags produced by 1st field processing
532
  if($uinst->{flags} =~ /#jsr/){
533
    if($flags2 ne ''){$error = 'incompatible flags'};
534
    $flags2 = '010';
535
  }
536
  if($uinst->{flags} =~ /#tjsr/){
537
    if($flags2 ne ''){$error = 'incompatible flags'};
538
    $flags2 = '100';
539
  }
540
 
541
  $provisional_flags2 = substr($uinst->{field_0},3,3);
542
  if($flags2 ne ''){
543
    if($provisional_flags2 ne '000'){
544
      $error = "flags incompatible with jsr/tjsr operation: "
545
                                                      .$provisional_flags2;
546
      $num_errors++;
547 62 ja_rd
      $uinst->{error} = $error;
548 2 ja_rd
    }
549
    else{
550
      substr($uinst->{field_0},3,3) = $flags2;
551
    }
552
  }
553
 
554
  if($uinst->{flags} =~ /#ld_al/){
555
    substr($uinst->{field1},7,1) = '1';
556
  }
557
  if($uinst->{flags} =~ /#ld_addr/){
558
    substr($uinst->{field1},6,1) = '1';
559
  }
560
 
561
  if($uinst->{flags} =~ /#fp_c/){
562
    substr($uinst->{field1},22,2) = '01';
563
  }
564
  if($uinst->{flags} =~ /#fp_r/){
565
    substr($uinst->{field1},22,2) = '10';
566
  }
567
  if($uinst->{flags} =~ /#fp_rc/){
568
    substr($uinst->{field1},22,2) = '11';
569
  }
570 64 ja_rd
  if($uinst->{flags} =~ /#clr_acy/){
571
    substr($uinst->{field1},17,1) = '1';
572
  }
573 2 ja_rd
 
574
}
575
 
576
sub process_flags {
577
 
578
  my $line = shift(@_);
579
 
580
  $line =~ s/#/##/;
581
  $line =~ /(.*)#(#.*)/;
582
 
583
  $flags1 = '';
584
  $flags2 = '';
585
 
586
 
587
  if($1 ne ''){
588
    $line_without_flags = $1;
589
    $flag_str = $2;
590
 
591
    @flags = split /,/, $flag_str;
592
    $error = '';
593
 
594
    if($flag_str =~ /#end/){
595
      if($flags2 ne ''){$error = 'incompatible flags'};
596
      $flags2 = '001';
597
    }
598
    if($flag_str =~ /#ret/){
599
      if($flags2 ne ''){$error = 'incompatible flags'};
600
      $flags2 = '011';
601
    }
602
    if($flag_str =~ /#rd/){
603
      if($flags2 ne ''){$error = 'incompatible flags'};
604
      $flags2 = '101';
605
    }
606
    if($flag_str =~ /#wr/){
607
      if($flags2 ne ''){$error = 'incompatible flags'};
608
      $flags2 = '110';
609
    }
610
    if($flag_str =~ /#auxcy/){
611
      if($flags1 ne ''){$error = 'incompatible flags'};
612
      $flags1 = '101';
613
    }
614
 
615
    if($flag_str =~ /#decode/){
616
      if($flags1 ne ''){$error = 'incompatible flags'};
617
      $flags1 = '001';
618
    }
619
    if($flag_str =~ /#clrt1/){
620
      if($flags1 ne ''){$error = 'incompatible flags'};
621
      $flags1 = '110';
622
    }
623
    if($flag_str =~ /#halt/){
624
      if($flags1 ne ''){$error = 'incompatible flags'};
625
      $flags1 = '111';
626
    }
627
    if($flag_str =~ /#di/){
628
      if($flags1 ne ''){$error = 'incompatible flags'};
629
      $flags1 = '010';
630
    }
631
    if($flag_str =~ /#ei/){
632
      if($flags1 ne ''){$error = 'incompatible flags'};
633
      $flags1 = '011';
634
    }
635
    if($flag_str =~ /#io/){
636
      if($flags1 ne ''){$error = 'incompatible flags'};
637
      $flags1 = '100';
638
    }
639
    if($flag_str =~ /#setacy/){
640
      if($flags2 ne ''){$error = 'incompatible flags:'.$flags2};
641
      $flags2 = '111';
642
    }
643
 
644
    if($flags2 eq ''){ $flags2 = '000';};
645
    if($flags1 eq ''){ $flags1 = '000';};
646
 
647
    $uinst->{field_0} = $flags1.$flags2;
648
 
649
    # Some of the flags must be processed after the rest of the uinst
650
    # has been assembled; save them into $uinst->{flags} for later.
651
 
652
    if($flag_str =~ /#ld_al/){
653
      $uinst->{flags} = $uinst->{flags}." #ld_al";
654
    }
655
    if($flag_str =~ /#ld_addr/){
656
      $uinst->{flags} = $uinst->{flags}." #ld_addr";
657
    }
658
    if($flag_str =~ /#fp_c/){
659
      $uinst->{flags} = $uinst->{flags}." #fp_c";
660
    }
661
    if($flag_str =~ /#fp_r/){
662
      $uinst->{flags} = $uinst->{flags}." #fp_r";
663
    }
664
    if($flag_str =~ /#fp_rc/){
665
      $uinst->{flags} = $uinst->{flags}." #fp_rc";
666
    }
667 64 ja_rd
    if($flag_str =~ /#clr_acy/){
668
      $uinst->{flags} = $uinst->{flags}." #clr_acy";
669
    }
670 2 ja_rd
 
671
    if($error ne ''){
672
      $num_errors++;
673
      $uinst->{error} = $error;
674
    };
675
 
676
    return $line_without_flags;
677
  }
678
 
679
  return $line;
680
}
681
 
682
 
683
sub process_field2 {
684
  my $field = shift(@_).";";
685
 
686
  $field =~ s/^\s*//g;
687
  $field =~ s/\s*;//g;
688
  $field =~ s/\s+/ /g;
689
 
690
  $field =~ s/A-Z/a-z/g;
691
 
692
 
693
  # check for special field2 formats: nop
694
  if($field =~ /(nop)/){
695
    # field2 is nop by default
696
    return 0;
697
  }
698
 
699
 
700
  if($field =~ /(_\w+|{p}0|{p}1|{d}|{s}|do) = (\w+|t1)/){
701
 
702
    #check that dst address is the same as field1's src address
703
    #(since they end up being the same physical bits)
704
    @parts = split /=/, $field;
705
    $dst = $parts[0];
706
    $dst =~ s/\s//g;
707
    if(($dst ne $uinst->{src})
708
       && ($dst ne 'do')
709
       && ($uinst->{src} ne 'di')
710
       && ($uinst->{src} ne '')){
711
      # field mismatch
712
      $num_errors++;
713
      $uinst->{error} = "field source/destination address mismatch";
714
      return 1;
715
    }
716
    else{
717
      # build bitfield for field2, including those bits that overlap
718
      # bits from field 1
719
 
720
      if($dst eq 'do'){
721
        substr($uinst->{field1}, 24, 1) = '1'; #ld_do
722
      }
723
      else{
724
        substr($uinst->{field1}, 25, 1) = '1'; #ld_reg
725
 
726
        if($dst eq '{p}0'){
727
          substr($uinst->{field1}, 11, 2) = '11';
728
          substr($uinst->{field1}, 13, 4) = '0000';
729
        }
730
        elsif($dst eq '{p}1'){
731
          substr($uinst->{field1}, 11, 2) = '11';
732
          substr($uinst->{field1}, 13, 4) = '0001';
733
        }
734
        elsif($dst eq '{d}'){
735
          substr($uinst->{field1}, 11, 2) = '10';
736
          substr($uinst->{field1}, 13, 4) = '0000';
737
        }
738
        elsif($dst eq '{s}'){
739
          substr($uinst->{field1}, 11, 2) = '01';
740
          substr($uinst->{field1}, 13, 4) = '0000';
741
        }
742
        else{
743
          %regs = ( '_b',0, '_c',1, '_d',2, '_e',3,
744
                    '_h',4, '_l',5, '_f',6, '_a',7,
745
                    '_ph',8, '_pl',9, '_x',10, '_y',11,
746
                    '_z',12, '_w',13, '_sh',14, '_sl',15);
747
 
748
          $val_reg = to_bin($regs{$dst},4);
749
          substr($uinst->{field1}, 11, 2) = '00';
750
          substr($uinst->{field1}, 13, 4) = $val_reg; # RD address; same as WR
751
        }
752
 
753
      }
754
 
755
      # TODO deal with flag pattern 
756
      $parts[1] =~ s/\s//g;
757
      $src = $field2_ops{$parts[1]}.'';
758
      if($src eq ''){
759
        $num_errors++;
760
        $uinst->{error} = "field 2 operation unknown: [".$parts[1]."]";
761
        return 1;
762
      }
763
      else{
764
        substr($uinst->{field1},26,6) = $src;
765
        return 0;
766
      }
767
    }
768
 
769
  }
770
  elsif($field =~ /(sec|cpc)/){
771
    substr($uinst->{field1},26,6) = $field2_ops{$1};
772
  }
773
  else{
774
    # field2 empty or invalid
775
    $num_errors++;
776
    $uinst->{error} = "field 2 empty or invalid: ".$re_field2;
777
    return 1;
778
  }
779
 
780
}
781
 
782
 
783
 
784 62 ja_rd
# return   !=0 when uinst is finished except for flags, 
785
#         0 when field2 has to be processed
786 2 ja_rd
 
787
sub process_field1 {
788
 
789
  my $field = shift(@_).";";
790
 
791
  $field =~ s/^\s*//g;
792
  $field =~ s/\s*;//g;
793
  $field =~ s/\s+/ /g;
794
 
795 62 ja_rd
  # look for special format uinsts: jsr, tjsr, nop
796
  if($field =~ /(jsr|tjsr)\s+([_\w]+)/){
797
    $opcode = $1;
798
    $target = $2;
799
    # set flag 
800
    $uinst->{flags} = $uinst->{flags}." #".$opcode." ";
801
 
802
    # check that target is defined, otherwise tag it for 2nd pass
803
    $target_addr = $labels{$target};
804 2 ja_rd
 
805 62 ja_rd
    tag_label_use($target, $addr);
806
 
807
    if($target_addr eq ''){
808
      push @undefined_targets, [$target, $addr];
809
      $code = $field1_ops{$opcode};
810
      $uinst->{field1} = $code;
811
    }
812
    else{
813
      # set up bitfield so we can fill the address in in 2nd pass
814
      $code = $field1_ops{$opcode};
815
      $a = to_bin($target_addr+0, 8);
816
      substr($code, 20,2, substr($a, 0,2));
817
      substr($code, 26,6, substr($a, 2,6));
818
      $uinst->{field1} = $code;
819
    }
820
    return 1;
821
  }
822
 
823
  if($field =~ /nop/){
824
    # TODO encode NOP as 1st field
825
    $uinst->{field1} = $field1_ops{'nop'};
826
    return 0;
827
  }
828 2 ja_rd
 
829 62 ja_rd
  # process regular field1 (register load): dst = src
830
 
831 2 ja_rd
  if($field =~ /$re_field1/){
832
    @parts = split /=/, $field;
833
 
834
    # if a src reg address literal is specified, it has to be the same 
835
    # address as for field2 dest; save it for later comparison.
836
 
837
    $src = $parts[1];
838
    $src =~ s/\s//g;
839
 
840
    $d = $field1_ops{$field}.'';
841
 
842
    if($d eq ''){
843
      # unrecognized source that somehow matches pattern (e.g. _pl0)
844 62 ja_rd
      $error = "invalid source in uinst field 1";
845
      $uinst->{field1} = $field1_ops{'nop'};
846
      $uinst->{error} = $error;
847
      $num_errors++;
848 2 ja_rd
      $uinst->{src} = '?';
849
      return 1;
850
    }
851
    else{
852
      $uinst->{src} = $src;
853
      $uinst->{field1} = $d;
854
    }
855
    return 0;
856
  }
857
  else{
858 62 ja_rd
    # field1 not recognized.
859
    $error = "uinst field 1 not recognized: '".$field."'";
860
    $uinst->{field1} = $field1_ops{'nop'};
861
    $uinst->{error} = $error;
862
    $num_errors++;
863 2 ja_rd
    return 1;
864
  }
865
 
866
}
867
 
868
sub tag_label_use {
869
 
870
  my $label = shift(@_);
871
  my $address = shift(@_);
872
 
873
  push(@label_uses, $label);
874
 
875
}
876
 
877
sub to_bin {
878
  my $number = shift(@_) * 1;
879
  my $length = shift(@_);
880
 
881
  $n = $number;
882
  $r = '';
883
  for( my $i=$length-1;$i>=0;$i--){
884
    $d = 2 ** $i;
885
 
886
    if($n >= $d){
887
      $r = $r.'1';
888
      $n = $n - $d;
889
    }
890
    else{
891
      $r = $r.'0';
892
    }
893
  }
894
 
895
  return $r;
896
}
897
 
898
# End of file

powered by: WebSVN 2.1.0

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