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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [scsi/] [script_asm.pl] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
#!/usr/bin/perl -s
2
 
3
# NCR 53c810 script assembler
4
# Sponsored by 
5
#       iX Multiuser Multitasking Magazine
6
#
7
# Copyright 1993, Drew Eckhardt
8
#      Visionary Computing 
9
#      (Unix and Linux consulting and custom programming)
10
#      drew@Colorado.EDU
11
#      +1 (303) 786-7975 
12
#
13
#   Support for 53c710 (via -ncr7x0_family switch) added by Richard
14
#   Hirst <richard@sleepie.demon.co.uk> - 15th March 1997
15
#   Renamed to -ncr7x0_family to -ncr710, and added -ncr700 - 5th May 2000.
16
#
17
#   This program is free software; you can redistribute it and/or modify
18
#   it under the terms of the GNU General Public License as published by
19
#   the Free Software Foundation; either version 2 of the License, or
20
#   (at your option) any later version.
21
#
22
#   This program is distributed in the hope that it will be useful,
23
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
24
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25
#   GNU General Public License for more details.
26
#
27
#   You should have received a copy of the GNU General Public License
28
#   along with this program; if not, write to the Free Software
29
#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30
#
31
# TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
32
#
33
 
34
# 
35
# Basically, I follow the NCR syntax documented in the NCR53c710 
36
# Programmer's guide, with the new instructions, registers, etc.
37
# from the NCR53c810.
38
#
39
# Differences between this assembler and NCR's are that 
40
# 1.  PASS, REL (data, JUMPs work fine), and the option to start a new 
41
#       script,  are unimplemented, since I didn't use them in my scripts.
42
# 
43
# 2.  I also emit a script_u.h file, which will undefine all of 
44
#       the A_*, E_*, etc. symbols defined in the script.  This 
45
#       makes including multiple scripts in one program easier
46
#       
47
# 3.  This is a single pass assembler, which only emits 
48
#       .h files.
49
#
50
 
51
 
52
# XXX - set these with command line options
53
$debug = 0;              # Print general debugging messages
54
$debug_external = 0;     # Print external/forward reference messages
55
$list_in_array = 1;     # Emit original SCRIPTS assembler in comments in
56
                        # script.h
57
$prefix = '';           # define all arrays having this prefix so we 
58
                        # don't have name space collisions after 
59
                        # assembling this file in different ways for
60
                        # different host adapters
61
 
62
# Constants
63
 
64
 
65
# Table of the SCSI phase encodings
66
%scsi_phases = (
67
    'DATA_OUT', 0x00_00_00_00, 'DATA_IN', 0x01_00_00_00, 'CMD', 0x02_00_00_00,
68
    'STATUS', 0x03_00_00_00, 'MSG_OUT', 0x06_00_00_00, 'MSG_IN', 0x07_00_00_00
69
);
70
 
71
# XXX - replace references to the *_810 constants with general constants
72
# assigned at compile time based on chip type.
73
 
74
# Table of operator encodings
75
# XXX - NCR53c710 only implements 
76
#       move (nop) = 0x00_00_00_00
77
#       or = 0x02_00_00_00
78
#       and = 0x04_00_00_00
79
#       add = 0x06_00_00_00
80
 
81
if ($ncr700 || $ncr710) {
82
  %operators = (
83
    '|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
84
    '&', 0x04_00_00_00, 'AND', 0x04_00_00_00,
85
    '+', 0x06_00_00_00
86
  );
87
}
88
else {
89
  %operators = (
90
    'SHL',  0x01_00_00_00,
91
    '|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
92
    'XOR', 0x03_00_00_00,
93
    '&', 0x04_00_00_00, 'AND', 0x04_00_00_00,
94
    'SHR', 0x05_00_00_00,
95
    # Note : low bit of the operator bit should be set for add with 
96
    # carry.
97
    '+', 0x06_00_00_00
98
  );
99
}
100
 
101
# Table of register addresses
102
 
103
if ($ncr700) {
104
  %registers = (
105
    'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
106
    'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
107
    'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11,
108
    'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
109
    'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23,
110
    'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27,
111
    'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
112
    'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34,
113
    'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
114
    'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
115
    'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
116
    'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
117
    'DMODE', 52, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
118
  );
119
}
120
elsif ($ncr710) {
121
  %registers = (
122
    'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
123
    'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
124
    'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11,
125
    'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
126
    'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
127
    'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23,
128
    'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27,
129
    'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
130
    'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34, 'LCRC', 35,
131
    'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
132
    'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
133
    'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
134
    'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
135
    'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
136
    'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
137
    'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
138
  );
139
}
140
else {
141
  %registers = (
142
    'SCNTL0', 0, 'SCNTL1', 1, 'SCNTL2', 2, 'SCNTL3', 3,
143
    'SCID', 4, 'SXFER', 5, 'SDID', 6, 'GPREG', 7,
144
    'SFBR', 8, 'SOCL', 9, 'SSID', 10, 'SBCL', 11,
145
    'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
146
    'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
147
    'ISTAT', 20,
148
    'CTEST0', 24, 'CTEST1', 25, 'CTEST2', 26, 'CTEST3', 27,
149
    'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
150
    'DFIFO', 32, 'CTEST4', 33, 'CTEST5', 34, 'CTEST6', 35,
151
    'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
152
    'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
153
    'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
154
    'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
155
    'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
156
    'SCRATCHA0', 52, 'SCRATCHA1', 53, 'SCRATCHA2', 54, 'SCRATCHA3', 55,
157
    'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
158
    'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
159
    'SIEN0', 64, 'SIEN1', 65, 'SIST0', 66, 'SIST1', 67,
160
    'SLPAR', 68,              'MACNTL', 70, 'GPCNTL', 71,
161
    'STIME0', 72, 'STIME1', 73, 'RESPID', 74,
162
    'STEST0', 76, 'STEST1', 77, 'STEST2', 78, 'STEST3', 79,
163
    'SIDL', 80,
164
    'SODL', 84,
165
    'SBDL', 88,
166
    'SCRATCHB0', 92, 'SCRATCHB1', 93, 'SCRATCHB2', 94, 'SCRATCHB3', 95
167
  );
168
}
169
 
170
# Parsing regular expressions
171
$identifier = '[A-Za-z_][A-Za-z_0-9]*';
172
$decnum = '-?\\d+';
173
$hexnum = '0[xX][0-9A-Fa-f]+';
174
$constant = "$hexnum|$decnum";
175
 
176
# yucky - since we can't control grouping of # $constant, we need to 
177
# expand out each alternative for $value.
178
 
179
$value = "$identifier|$identifier\\s*[+\-]\\s*$decnum|".
180
    "$identifier\\s*[+-]\s*$hexnum|$constant";
181
 
182
print STDERR "value regex = $value\n" if ($debug);
183
 
184
$phase = join ('|', keys %scsi_phases);
185
print STDERR "phase regex = $phase\n" if ($debug);
186
$register = join ('|', keys %registers);
187
 
188
# yucky - since %operators includes meta-characters which must
189
# be escaped, I can't use the join() trick I used for the register
190
# regex
191
 
192
if ($ncr700 || $ncr710) {
193
  $operator = '\||OR|AND|\&|\+';
194
}
195
else {
196
  $operator = '\||OR|AND|XOR|\&|\+';
197
}
198
 
199
# Global variables
200
 
201
%symbol_values = (%registers) ;         # Traditional symbol table
202
 
203
%symbol_references = () ;               # Table of symbol references, where
204
                                        # the index is the symbol name, 
205
                                        # and the contents a white space 
206
                                        # delimited list of address,size
207
                                        # tuples where size is in bytes.
208
 
209
@code = ();                             # Array of 32 bit words for SIOP 
210
 
211
@entry = ();                            # Array of entry point names
212
 
213
@label = ();                            # Array of label names
214
 
215
@absolute = ();                         # Array of absolute names
216
 
217
@relative = ();                         # Array of relative names
218
 
219
@external = ();                         # Array of external names
220
 
221
$address = 0;                            # Address of current instruction
222
 
223
$lineno = 0;                             # Line number we are parsing
224
 
225
$output = 'script.h';                   # Output file
226
$outputu = 'scriptu.h';
227
 
228
# &patch ($address, $offset, $length, $value) patches $code[$address]
229
#       so that the $length bytes at $offset have $value added to
230
#       them.  
231
 
232
@inverted_masks = (0x00_00_00_00, 0x00_00_00_ff, 0x00_00_ff_ff, 0x00_ff_ff_ff,
233
    0xff_ff_ff_ff);
234
 
235
sub patch {
236
    local ($address, $offset, $length, $value) = @_;
237
    if ($debug) {
238
        print STDERR "Patching $address at offset $offset, length $length to $value\n";
239
        printf STDERR "Old code : %08x\n", $code[$address];
240
     }
241
 
242
    $mask = ($inverted_masks[$length] << ($offset * 8));
243
 
244
    $code[$address] = ($code[$address] & ~$mask) |
245
        (($code[$address] & $mask) + ($value << ($offset * 8)) &
246
        $mask);
247
 
248
    printf STDERR "New code : %08x\n", $code[$address] if ($debug);
249
}
250
 
251
# &parse_value($value, $word, $offset, $length) where $value is 
252
#       an identifier or constant, $word is the word offset relative to 
253
#       $address, $offset is the starting byte within that word, and 
254
#       $length is the length of the field in bytes.
255
#
256
# Side effects are that the bytes are combined into the @code array
257
#       relative to $address, and that the %symbol_references table is 
258
#       updated as appropriate.
259
 
260
sub parse_value {
261
    local ($value, $word, $offset, $length) = @_;
262
    local ($tmp);
263
 
264
    $symbol = '';
265
 
266
    if ($value =~ /^REL\s*\(\s*($identifier)\s*\)\s*(.*)/i) {
267
        $relative = 'REL';
268
        $symbol = $1;
269
        $value = $2;
270
print STDERR "Relative reference $symbol\n" if ($debug);
271
    } elsif ($value =~ /^($identifier)\s*(.*)/) {
272
        $relative = 'ABS';
273
        $symbol = $1;
274
        $value = $2;
275
print STDERR "Absolute reference $symbol\n" if ($debug);
276
    }
277
 
278
    if ($symbol ne '') {
279
print STDERR "Referencing symbol $1, length = $length in $_\n" if ($debug);
280
        $tmp = ($address + $word) * 4 + $offset;
281
        if ($symbol_references{$symbol} ne undef) {
282
            $symbol_references{$symbol} =
283
                "$symbol_references{$symbol} $relative,$tmp,$length";
284
        } else {
285
            if (!defined($symbol_values{$symbol})) {
286
print STDERR "forward $1\n" if ($debug_external);
287
                $forward{$symbol} = "line $lineno : $_";
288
            }
289
            $symbol_references{$symbol} = "$relative,$tmp,$length";
290
        }
291
    }
292
 
293
    $value = eval $value;
294
    &patch ($address + $word, $offset, $length, $value);
295
}
296
 
297
# &parse_conditional ($conditional) where $conditional is the conditional
298
# clause from a transfer control instruction (RETURN, CALL, JUMP, INT).
299
 
300
sub parse_conditional {
301
    local ($conditional) = @_;
302
    if ($conditional =~ /^\s*(IF|WHEN)\s*(.*)/i) {
303
        $if = $1;
304
        $conditional = $2;
305
        if ($if =~ /WHEN/i) {
306
            $allow_atn = 0;
307
            $code[$address] |= 0x00_01_00_00;
308
            $allow_atn = 0;
309
            print STDERR "$0 : parsed WHEN\n" if ($debug);
310
        } else {
311
            $allow_atn = 1;
312
            print STDERR "$0 : parsed IF\n" if ($debug);
313
        }
314
    } else {
315
            die "$0 : syntax error in line $lineno : $_
316
        expected IF or WHEN
317
";
318
    }
319
 
320
    if ($conditional =~ /^NOT\s+(.*)$/i) {
321
        $not = 'NOT ';
322
        $other = 'OR';
323
        $conditional = $1;
324
        print STDERR "$0 : parsed NOT\n" if ($debug);
325
    } else {
326
        $code[$address] |= 0x00_08_00_00;
327
        $not = '';
328
        $other = 'AND'
329
    }
330
 
331
    $need_data = 0;
332
    if ($conditional =~ /^ATN\s*(.*)/i) {#
333
        die "$0 : syntax error in line $lineno : $_
334
        WHEN conditional is incompatible with ATN
335
" if (!$allow_atn);
336
        $code[$address] |= 0x00_02_00_00;
337
        $conditional = $1;
338
        print STDERR "$0 : parsed ATN\n" if ($debug);
339
    } elsif ($conditional =~ /^($phase)\s*(.*)/i) {
340
        $phase_index = "\U$1\E";
341
        $p = $scsi_phases{$phase_index};
342
        $code[$address] |= $p | 0x00_02_00_00;
343
        $conditional = $2;
344
        print STDERR "$0 : parsed phase $phase_index\n" if ($debug);
345
    } else {
346
        $other = '';
347
        $need_data = 1;
348
    }
349
 
350
print STDERR "Parsing conjunction, expecting $other\n" if ($debug);
351
    if ($conditional =~ /^(AND|OR)\s*(.*)/i) {
352
        $conjunction = $1;
353
        $conditional = $2;
354
        $need_data = 1;
355
        die "$0 : syntax error in line $lineno : $_
356
            Illegal use of $1.  Valid uses are
357
            ".$not."<phase> $1 data
358
            ".$not."ATN $1 data
359
" if ($other eq '');
360
        die "$0 : syntax error in line $lineno : $_
361
        Illegal use of $conjunction.  Valid syntaxes are
362
                NOT <phase>|ATN OR data
363
                <phase>|ATN AND data
364
" if ($conjunction !~ /\s*$other\s*/i);
365
        print STDERR "$0 : parsed $1\n" if ($debug);
366
    }
367
 
368
    if ($need_data) {
369
print STDERR "looking for data in $conditional\n" if ($debug);
370
        if ($conditional=~ /^($value)\s*(.*)/i) {
371
            $code[$address] |= 0x00_04_00_00;
372
            $conditional = $2;
373
            &parse_value($1, 0, 0, 1);
374
            print STDERR "$0 : parsed data\n" if ($debug);
375
        } else {
376
        die "$0 : syntax error in line $lineno : $_
377
        expected <data>.
378
";
379
        }
380
    }
381
 
382
    if ($conditional =~ /^\s*,\s*(.*)/) {
383
        $conditional = $1;
384
        if ($conditional =~ /^AND\s\s*MASK\s\s*($value)\s*(.*)/i) {
385
            &parse_value ($1, 0, 1, 1);
386
            print STDERR "$0 parsed AND MASK $1\n" if ($debug);
387
            die "$0 : syntax error in line $lineno : $_
388
        expected end of line, not \"$2\"
389
" if ($2 ne '');
390
        } else {
391
            die "$0 : syntax error in line $lineno : $_
392
        expected \",AND MASK <data>\", not \"$2\"
393
";
394
        }
395
    } elsif ($conditional !~ /^\s*$/) {
396
        die "$0 : syntax error in line $lineno : $_
397
        expected end of line" . (($need_data) ? " or \"AND MASK <data>\"" : "") . "
398
        not \"$conditional\"
399
";
400
    }
401
}
402
 
403
# Parse command line 
404
foreach $arg (@argv) {
405
    if ($arg =~ /^-prefix\s*=\s*([_a-zA-Z][_a-zA-Z0-9]*)$/i) {
406
        $prefix = $1
407
    }
408
}
409
 
410
# Main loop
411
while (<STDIN>) {
412
    $lineno = $lineno + 1;
413
    $list[$address] = $list[$address].$_;
414
    s/;.*$//;                           # Strip comments
415
 
416
 
417
    chop;                               # Leave new line out of error messages
418
 
419
# Handle symbol definitions of the form label:
420
    if (/^\s*($identifier)\s*:(.*)/) {
421
        if (!defined($symbol_values{$1})) {
422
            $symbol_values{$1} = $address * 4;  # Address is an index into
423
            delete $forward{$1};                # an array of longs
424
            push (@label, $1);
425
            $_ = $2;
426
        } else {
427
            die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
428
        }
429
    }
430
 
431
# Handle symbol definitions of the form ABSOLUTE or RELATIVE identifier = 
432
# value
433
    if (/^\s*(ABSOLUTE|RELATIVE)\s+(.*)/i) {
434
        $is_absolute = $1;
435
        $rest = $2;
436
        foreach $rest (split (/\s*,\s*/, $rest)) {
437
            if ($rest =~ /^($identifier)\s*=\s*($constant)\s*$/) {
438
                local ($id, $cnst) = ($1, $2);
439
                if ($symbol_values{$id} eq undef) {
440
                    $symbol_values{$id} = eval $cnst;
441
                    delete $forward{$id};
442
                    if ($is_absolute =~ /ABSOLUTE/i) {
443
                        push (@absolute , $id);
444
                    } else {
445
                        push (@relative, $id);
446
                    }
447
                } else {
448
                    die "$0 : redefinition of symbol $id in line $lineno : $_\n";
449
                }
450
            } else {
451
                die
452
"$0 : syntax error in line $lineno : $_
453
            expected <identifier> = <value>
454
";
455
            }
456
        }
457
    } elsif (/^\s*EXTERNAL\s+(.*)/i) {
458
        $externals = $1;
459
        foreach $external (split (/,/,$externals)) {
460
            if ($external =~ /\s*($identifier)\s*$/) {
461
                $external = $1;
462
                push (@external, $external);
463
                delete $forward{$external};
464
                if (defined($symbol_values{$external})) {
465
                        die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
466
                }
467
                $symbol_values{$external} = $external;
468
print STDERR "defined external $1 to $external\n" if ($debug_external);
469
            } else {
470
                die
471
"$0 : syntax error in line $lineno : $_
472
        expected <identifier>, got $external
473
";
474
            }
475
        }
476
# Process ENTRY identifier declarations
477
    } elsif (/^\s*ENTRY\s+(.*)/i) {
478
        if ($1 =~ /^($identifier)\s*$/) {
479
            push (@entry, $1);
480
        } else {
481
            die
482
"$0 : syntax error in line $lineno : $_
483
        expected ENTRY <identifier>
484
";
485
        }
486
# Process MOVE length, address, WITH|WHEN phase instruction
487
    } elsif (/^\s*MOVE\s+(.*)/i) {
488
        $rest = $1;
489
        if (!$ncr700 && ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i)) {
490
            $transfer_addr = $1;
491
            $with_when = $2;
492
            $scsi_phase = $3;
493
print STDERR "Parsing MOVE FROM $transfer_addr, $with_when $3\n" if ($debug);
494
            $code[$address] = 0x18_00_00_00 | (($with_when =~ /WITH/i) ?
495
                0x00_00_00_00 : 0x08_00_00_00) | $scsi_phases{$scsi_phase};
496
            &parse_value ($transfer_addr, 1, 0, 4);
497
            $address += 2;
498
        } elsif ($rest =~ /^($value)\s*,\s*(PTR\s+|)($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
499
            $transfer_len = $1;
500
            $ptr = $2;
501
            $transfer_addr = $3;
502
            $with_when = $4;
503
            $scsi_phase = $5;
504
            $code[$address] = (($with_when =~ /WITH/i) ? 0x00_00_00_00 :
505
                0x08_00_00_00)  | (($ptr =~ /PTR/i) ? (1 << 29) : 0) |
506
                $scsi_phases{$scsi_phase};
507
            &parse_value ($transfer_len, 0, 0, 3);
508
            &parse_value ($transfer_addr, 1, 0, 4);
509
            $address += 2;
510
        } elsif ($rest =~ /^MEMORY\s+(.*)/i) {
511
            $rest = $1;
512
            $code[$address] = 0xc0_00_00_00;
513
            if ($rest =~ /^($value)\s*,\s*($value)\s*,\s*($value)\s*$/) {
514
                $count = $1;
515
                $source = $2;
516
                $dest =  $3;
517
print STDERR "Parsing MOVE MEMORY $count, $source, $dest\n" if ($debug);
518
                &parse_value ($count, 0, 0, 3);
519
                &parse_value ($source, 1, 0, 4);
520
                &parse_value ($dest, 2, 0, 4);
521
printf STDERR "Move memory instruction = %08x,%08x,%08x\n",
522
                $code[$address], $code[$address+1], $code[$address +2] if
523
                ($debug);
524
                $address += 3;
525
 
526
            } else {
527
                die
528
"$0 : syntax error in line $lineno : $_
529
        expected <count>, <source>, <destination>
530
"
531
            }
532
        } elsif ($1 =~ /^(.*)\s+(TO|SHL|SHR)\s+(.*)/i) {
533
print STDERR "Parsing register to register move\n" if ($debug);
534
            $src = $1;
535
            $op = "\U$2\E";
536
            $rest = $3;
537
 
538
            $code[$address] = 0x40_00_00_00;
539
 
540
            $force = ($op !~ /TO/i);
541
 
542
 
543
print STDERR "Forcing register source \n" if ($force && $debug);
544
 
545
            if (!$force && $src =~
546
                /^($register)\s+(-|$operator)\s+($value)\s*$/i) {
547
print STDERR "register operand  data8 source\n" if ($debug);
548
                $src_reg = "\U$1\E";
549
                $op = "\U$2\E";
550
                if ($op ne '-') {
551
                    $data8 = $3;
552
                } else {
553
                    die "- is not implemented yet.\n"
554
                }
555
            } elsif ($src =~ /^($register)\s*$/i) {
556
print STDERR "register source\n" if ($debug);
557
                $src_reg = "\U$1\E";
558
                # Encode register to register move as a register | 0 
559
                # move to register.
560
                if (!$force) {
561
                    $op = '|';
562
                }
563
                $data8 = 0;
564
            } elsif (!$force && $src =~ /^($value)\s*$/i) {
565
print STDERR "data8 source\n" if ($debug);
566
                $src_reg = undef;
567
                $op = 'NONE';
568
                $data8 = $1;
569
            } else {
570
                if (!$force) {
571
                    die
572
"$0 : syntax error in line $lineno : $_
573
        expected <register>
574
                <data8>
575
                <register> <operand> <data8>
576
";
577
                } else {
578
                    die
579
"$0 : syntax error in line $lineno : $_
580
        expected <register>
581
";
582
                }
583
            }
584
            if ($rest =~ /^($register)\s*(.*)$/i) {
585
                $dst_reg = "\U$1\E";
586
                $rest = $2;
587
            } else {
588
            die
589
"$0 : syntax error in $lineno : $_
590
        expected <register>, got $rest
591
";
592
            }
593
 
594
            if ($rest =~ /^WITH\s+CARRY\s*(.*)/i) {
595
                $rest = $1;
596
                if ($op eq '+') {
597
                    $code[$address] |= 0x01_00_00_00;
598
                } else {
599
                    die
600
"$0 : syntax error in $lineno : $_
601
        WITH CARRY option is incompatible with the $op operator.
602
";
603
                }
604
            }
605
 
606
            if ($rest !~ /^\s*$/) {
607
                die
608
"$0 : syntax error in $lineno : $_
609
        Expected end of line, got $rest
610
";
611
            }
612
 
613
            print STDERR "source = $src_reg, data = $data8 , destination = $dst_reg\n"
614
                if ($debug);
615
            # Note that Move data8 to reg is encoded as a read-modify-write
616
            # instruction.
617
            if (($src_reg eq undef) || ($src_reg eq $dst_reg)) {
618
                $code[$address] |= 0x38_00_00_00 |
619
                    ($registers{$dst_reg} << 16);
620
            } elsif ($dst_reg =~ /SFBR/i) {
621
                $code[$address] |= 0x30_00_00_00 |
622
                    ($registers{$src_reg} << 16);
623
            } elsif ($src_reg =~ /SFBR/i) {
624
                $code[$address] |= 0x28_00_00_00 |
625
                    ($registers{$dst_reg} << 16);
626
            } else {
627
                die
628
"$0 : Illegal combination of registers in line $lineno : $_
629
        Either source and destination registers must be the same,
630
        or either source or destination register must be SFBR.
631
";
632
            }
633
 
634
            $code[$address] |= $operators{$op};
635
 
636
            &parse_value ($data8, 0, 1, 1);
637
            $code[$address] |= $operators{$op};
638
            $code[$address + 1] = 0x00_00_00_00;# Reserved
639
            $address += 2;
640
        } else {
641
            die
642
"$0 : syntax error in line $lineno : $_
643
        expected (initiator) <length>, <address>, WHEN <phase>
644
                 (target) <length>, <address>, WITH <phase>
645
                 MEMORY <length>, <source>, <destination>
646
                 <expression> TO <register>
647
";
648
        }
649
# Process SELECT {ATN|} id, fail_address
650
    } elsif (/^\s*(SELECT|RESELECT)\s+(.*)/i) {
651
        $rest = $2;
652
        if ($rest =~ /^(ATN|)\s*($value)\s*,\s*($identifier)\s*$/i) {
653
            $atn = $1;
654
            $id = $2;
655
            $alt_addr = $3;
656
            $code[$address] = 0x40_00_00_00 |
657
                (($atn =~ /ATN/i) ? 0x01_00_00_00 : 0);
658
            $code[$address + 1] = 0x00_00_00_00;
659
            &parse_value($id, 0, 2, 1);
660
            &parse_value($alt_addr, 1, 0, 4);
661
            $address += 2;
662
        } elsif ($rest =~ /^(ATN|)\s*FROM\s+($value)\s*,\s*($identifier)\s*$/i) {
663
            $atn = $1;
664
            $addr = $2;
665
            $alt_addr = $3;
666
            $code[$address] = 0x42_00_00_00 |
667
                (($atn =~ /ATN/i) ? 0x01_00_00_00 : 0);
668
            $code[$address + 1] = 0x00_00_00_00;
669
            &parse_value($addr, 0, 0, 3);
670
            &parse_value($alt_addr, 1, 0, 4);
671
            $address += 2;
672
        } else {
673
            die
674
"$0 : syntax error in line $lineno : $_
675
        expected SELECT id, alternate_address or
676
                SELECT FROM address, alternate_address or
677
                RESELECT id, alternate_address or
678
                RESELECT FROM address, alternate_address
679
";
680
        }
681
    } elsif (/^\s*WAIT\s+(.*)/i) {
682
            $rest = $1;
683
print STDERR "Parsing WAIT $rest\n" if ($debug);
684
        if ($rest =~ /^DISCONNECT\s*$/i) {
685
            $code[$address] = 0x48_00_00_00;
686
            $code[$address + 1] = 0x00_00_00_00;
687
            $address += 2;
688
        } elsif ($rest =~ /^(RESELECT|SELECT)\s+($identifier)\s*$/i) {
689
            $alt_addr = $2;
690
            $code[$address] = 0x50_00_00_00;
691
            &parse_value ($alt_addr, 1, 0, 4);
692
            $address += 2;
693
        } else {
694
            die
695
"$0 : syntax error in line $lineno : $_
696
        expected (initiator) WAIT DISCONNECT or
697
                 (initiator) WAIT RESELECT alternate_address or
698
                 (target) WAIT SELECT alternate_address
699
";
700
        }
701
# Handle SET and CLEAR instructions.  Note that we should also do something
702
# with this syntax to set target mode.
703
    } elsif (/^\s*(SET|CLEAR)\s+(.*)/i) {
704
        $set = $1;
705
        $list = $2;
706
        $code[$address] = ($set =~ /SET/i) ?  0x58_00_00_00 :
707
            0x60_00_00_00;
708
        foreach $arg (split (/\s+AND\s+/i,$list)) {
709
            if ($arg =~ /ATN/i) {
710
                $code[$address] |= 0x00_00_00_08;
711
            } elsif ($arg =~ /ACK/i) {
712
                $code[$address] |= 0x00_00_00_40;
713
            } elsif ($arg =~ /TARGET/i) {
714
                $code[$address] |= 0x00_00_02_00;
715
            } elsif ($arg =~ /CARRY/i) {
716
                $code[$address] |= 0x00_00_04_00;
717
            } else {
718
                die
719
"$0 : syntax error in line $lineno : $_
720
        expected $set followed by a AND delimited list of one or
721
        more strings from the list ACK, ATN, CARRY, TARGET.
722
";
723
            }
724
        }
725
        $code[$address + 1] = 0x00_00_00_00;
726
        $address += 2;
727
    } elsif (/^\s*(JUMP|CALL|INT)\s+(.*)/i) {
728
        $instruction = $1;
729
        $rest = $2;
730
        if ($instruction =~ /JUMP/i) {
731
            $code[$address] = 0x80_00_00_00;
732
        } elsif ($instruction =~ /CALL/i) {
733
            $code[$address] = 0x88_00_00_00;
734
        } else {
735
            $code[$address] = 0x98_00_00_00;
736
        }
737
print STDERR "parsing JUMP, rest = $rest\n" if ($debug);
738
 
739
# Relative jump. 
740
        if ($rest =~ /^(REL\s*\(\s*$identifier\s*\))\s*(.*)/i) {
741
            $addr = $1;
742
            $rest = $2;
743
print STDERR "parsing JUMP REL, addr = $addr, rest = $rest\n" if ($debug);
744
            $code[$address]  |= 0x00_80_00_00;
745
            &parse_value($addr, 1, 0, 4);
746
# Absolute jump, requires no more gunk
747
        } elsif ($rest =~ /^($value)\s*(.*)/) {
748
            $addr = $1;
749
            $rest = $2;
750
            &parse_value($addr, 1, 0, 4);
751
        } else {
752
            die
753
"$0 : syntax error in line $lineno : $_
754
        expected <address> or REL (address)
755
";
756
        }
757
 
758
        if ($rest =~ /^,\s*(.*)/) {
759
            &parse_conditional($1);
760
        } elsif ($rest =~ /^\s*$/) {
761
            $code[$address] |= (1 << 19);
762
        } else {
763
            die
764
"$0 : syntax error in line $lineno : $_
765
        expected , <conditional> or end of line, got $1
766
";
767
        }
768
 
769
        $address += 2;
770
    } elsif (/^\s*(RETURN|INTFLY)\s*(.*)/i) {
771
        $instruction = $1;
772
        $conditional = $2;
773
print STDERR "Parsing $instruction\n" if ($debug);
774
        $code[$address] = ($instruction =~ /RETURN/i) ? 0x90_00_00_00 :
775
            0x98_10_00_00;
776
        if ($conditional =~ /^,\s*(.*)/) {
777
            $conditional = $1;
778
            &parse_conditional ($conditional);
779
        } elsif ($conditional !~ /^\s*$/) {
780
            die
781
"$0 : syntax error in line $lineno : $_
782
        expected , <conditional>
783
";
784
        } else {
785
            $code[$address] |= 0x00_08_00_00;
786
        }
787
 
788
        $code[$address + 1] = 0x00_00_00_00;
789
        $address += 2;
790
    } elsif (/^\s*DISCONNECT\s*$/) {
791
        $code[$address] = 0x48_00_00_00;
792
        $code[$address + 1] = 0x00_00_00_00;
793
        $address += 2;
794
# I'm not sure that I should be including this extension, but 
795
# what the hell?
796
    } elsif (/^\s*NOP\s*$/i) {
797
        $code[$address] = 0x80_88_00_00;
798
        $code[$address + 1] = 0x00_00_00_00;
799
        $address += 2;
800
# Ignore lines consisting entirely of white space
801
    } elsif (/^\s*$/) {
802
    } else {
803
        die
804
"$0 : syntax error in line $lineno: $_
805
        expected label:, ABSOLUTE, CLEAR, DISCONNECT, EXTERNAL, MOVE, RESELECT,
806
            SELECT SET, or WAIT
807
";
808
    }
809
}
810
 
811
# Fill in label references
812
 
813
@undefined = keys %forward;
814
if ($#undefined >= 0) {
815
    print STDERR "Undefined symbols : \n";
816
    foreach $undef (@undefined) {
817
        print STDERR "$undef in $forward{$undef}\n";
818
    }
819
    exit 1;
820
}
821
 
822
@label_patches = ();
823
 
824
@external_patches = ();
825
 
826
@absolute = sort @absolute;
827
 
828
foreach $i (@absolute) {
829
    foreach $j (split (/\s+/,$symbol_references{$i})) {
830
        $j =~ /(REL|ABS),(.*),(.*)/;
831
        $type = $1;
832
        $address = $2;
833
        $length = $3;
834
        die
835
"$0 : $symbol $i has illegal relative reference at address $address,
836
    size $length\n"
837
        if ($type eq 'REL');
838
 
839
        &patch ($address / 4, $address % 4, $length, $symbol_values{$i});
840
    }
841
}
842
 
843
foreach $external (@external) {
844
print STDERR "checking external $external \n" if ($debug_external);
845
    if ($symbol_references{$external} ne undef) {
846
        for $reference (split(/\s+/,$symbol_references{$external})) {
847
            $reference =~ /(REL|ABS),(.*),(.*)/;
848
            $type = $1;
849
            $address = $2;
850
            $length = $3;
851
 
852
            die
853
"$0 : symbol $label is external, has illegal relative reference at $address,
854
    size $length\n"
855
                if ($type eq 'REL');
856
 
857
            die
858
"$0 : symbol $label has illegal reference at $address, size $length\n"
859
                if ((($address % 4) !=0) || ($length != 4));
860
 
861
            $symbol = $symbol_values{$external};
862
            $add = $code[$address / 4];
863
            if ($add eq 0) {
864
                $code[$address / 4] = $symbol;
865
            } else {
866
                $add = sprintf ("0x%08x", $add);
867
                $code[$address / 4] = "$symbol + $add";
868
            }
869
 
870
print STDERR "referenced external $external at $1\n" if ($debug_external);
871
        }
872
    }
873
}
874
 
875
foreach $label (@label) {
876
    if ($symbol_references{$label} ne undef) {
877
        for $reference (split(/\s+/,$symbol_references{$label})) {
878
            $reference =~ /(REL|ABS),(.*),(.*)/;
879
            $type = $1;
880
            $address = $2;
881
            $length = $3;
882
 
883
            if ((($address % 4) !=0) || ($length != 4)) {
884
                die "$0 : symbol $label has illegal reference at $1, size $2\n";
885
            }
886
 
887
            if ($type eq 'ABS') {
888
                $code[$address / 4] += $symbol_values{$label};
889
                push (@label_patches, $address / 4);
890
            } else {
891
# 
892
# - The address of the reference should be in the second and last word
893
#       of an instruction
894
# - Relative jumps, etc. are relative to the DSP of the _next_ instruction
895
#
896
# So, we need to add four to the address of the reference, to get 
897
# the address of the next instruction, when computing the reference.
898
 
899
                $tmp = $symbol_values{$label} -
900
                    ($address + 4);
901
                die
902
# Relative addressing is limited to 24 bits.
903
"$0 : symbol $label is too far ($tmp) from $address to reference as
904
    relative/\n" if (($tmp >= 0x80_00_00) || ($tmp < -0x80_00_00));
905
                $code[$address / 4] = $tmp & 0x00_ff_ff_ff;
906
            }
907
        }
908
    }
909
}
910
 
911
# Output SCRIPT[] array, one instruction per line.  Optionally 
912
# print the original code too.
913
 
914
open (OUTPUT, ">$output") || die "$0 : can't open $output for writing\n";
915
open (OUTPUTU, ">$outputu") || die "$0 : can't open $outputu for writing\n";
916
 
917
print OUTPUT "/* DO NOT EDIT - Generated automatically by ".$0." */\n";
918
print OUTPUT "static u32 ".$prefix."SCRIPT[] = {\n";
919
$instructions = 0;
920
for ($i = 0; $i < $#code; ) {
921
    if ($list_in_array) {
922
        printf OUTPUT "/*\n$list[$i]\nat 0x%08x : */", $i;
923
    }
924
    printf OUTPUT "\t0x%08x,", $code[$i];
925
    printf STDERR "Address $i = %x\n", $code[$i] if ($debug);
926
    if ($code[$i + 1] =~ /\s*($identifier)(.*)$/) {
927
        push (@external_patches, $i+1, $1);
928
        printf OUTPUT "0%s,", $2
929
    } else {
930
        printf OUTPUT "0x%08x,",$code[$i+1];
931
    }
932
 
933
    if (($code[$i] & 0xff_00_00_00) == 0xc0_00_00_00) {
934
        if ($code[$i + 2] =~ /$identifier/) {
935
            push (@external_patches, $i+2, $code[$i+2]);
936
            printf OUTPUT "0,\n";
937
        } else {
938
            printf OUTPUT "0x%08x,\n",$code[$i+2];
939
        }
940
        $i += 3;
941
    } else {
942
        printf OUTPUT "\n";
943
        $i += 2;
944
    }
945
    $instructions += 1;
946
}
947
print OUTPUT "};\n\n";
948
 
949
foreach $i (@absolute) {
950
    printf OUTPUT "#define A_$i\t0x%08x\n", $symbol_values{$i};
951
    if (defined($prefix) && $prefix ne '') {
952
        printf OUTPUT "#define A_".$i."_used ".$prefix."A_".$i."_used\n";
953
        printf OUTPUTU "#undef A_".$i."_used\n";
954
    }
955
    printf OUTPUTU "#undef A_$i\n";
956
 
957
    printf OUTPUT "static u32 A_".$i."_used\[\] __attribute((unused)) = {\n";
958
printf STDERR "$i is used $symbol_references{$i}\n" if ($debug);
959
    foreach $j (split (/\s+/,$symbol_references{$i})) {
960
        $j =~ /(ABS|REL),(.*),(.*)/;
961
        if ($1 eq 'ABS') {
962
            $address = $2;
963
            $length = $3;
964
            printf OUTPUT "\t0x%08x,\n", $address / 4;
965
        }
966
    }
967
    printf OUTPUT "};\n\n";
968
}
969
 
970
foreach $i (sort @entry) {
971
    printf OUTPUT "#define Ent_$i\t0x%08x\n", $symbol_values{$i};
972
    printf OUTPUTU "#undef Ent_$i\n", $symbol_values{$i};
973
}
974
 
975
#
976
# NCR assembler outputs label patches in the form of indices into 
977
# the code.
978
#
979
printf OUTPUT "static u32 ".$prefix."LABELPATCHES[] __attribute((unused)) = {\n";
980
for $patch (sort {$a <=> $b} @label_patches) {
981
    printf OUTPUT "\t0x%08x,\n", $patch;
982
}
983
printf OUTPUT "};\n\n";
984
 
985
$num_external_patches = 0;
986
printf OUTPUT "static struct {\n\tu32\toffset;\n\tvoid\t\t*address;\n".
987
    "} ".$prefix."EXTERNAL_PATCHES[] __attribute((unused)) = {\n";
988
while ($ident = pop(@external_patches)) {
989
    $off = pop(@external_patches);
990
    printf OUTPUT "\t{0x%08x, &%s},\n", $off, $ident;
991
    ++$num_external_patches;
992
}
993
printf OUTPUT "};\n\n";
994
 
995
printf OUTPUT "static u32 ".$prefix."INSTRUCTIONS __attribute((unused))\t= %d;\n",
996
    $instructions;
997
printf OUTPUT "static u32 ".$prefix."PATCHES __attribute((unused))\t= %d;\n",
998
    $#label_patches+1;
999
printf OUTPUT "static u32 ".$prefix."EXTERNAL_PATCHES_LEN __attribute((unused))\t= %d;\n",
1000
    $num_external_patches;
1001
close OUTPUT;
1002
close OUTPUTU;

powered by: WebSVN 2.1.0

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