clean
[linux-2.4.21-pre4.git] / drivers / scsi / script_asm.pl
1 #!/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;