~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/scsi/script_asm.pl

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.