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