Committer: Michael Beasley <mike@snafu.setup>
[mikesnafu-overlay.git] / drivers / scsi / script_asm.pl
blob7d651d99afcbbcb0be0edf88f83b9ea9432c78b8
1 #!/usr/bin/perl -s
3 # NCR 53c810 script assembler
4 # Sponsored by
5 # iX Multiuser Multitasking Magazine
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
13 # Support for 53c710 (via -ncr7x0_family switch) added by Richard
14 # Hirst <richard@sleepie.demon.co.uk> - 15th March 1997
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.
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.
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.
30 # TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
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.
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.
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
46 # 3. This is a single pass assembler, which only emits
47 # .h files.
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
62 # Constants
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
71 # XXX - replace references to the *_810 constants with general constants
72 # assigned at compile time based on chip type.
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
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
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
101 # Table of register addresses
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,
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
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";
159 # yucky - since we can't control grouping of # $constant, we need to
160 # expand out each alternative for $value.
162 $value = "$identifier|$identifier\\s*[+\-]\\s*$decnum|".
163 "$identifier\\s*[+-]\s*$hexnum|$constant";
165 print STDERR "value regex = $value\n" if ($debug);
167 $phase = join ('|', keys %scsi_phases);
168 print STDERR "phase regex = $phase\n" if ($debug);
169 $register = join ('|', keys %registers);
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
175 if ($ncr7x0_family) {
176 $operator = '\||OR|AND|\&|\+';
178 else {
179 $operator = '\||OR|AND|XOR|\&|\+';
182 # Global variables
184 %symbol_values = (%registers) ; # Traditional symbol table
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.
192 @code = (); # Array of 32 bit words for SIOP
194 @entry = (); # Array of entry point names
196 @label = (); # Array of label names
198 @absolute = (); # Array of absolute names
200 @relative = (); # Array of relative names
202 @external = (); # Array of external names
204 $address = 0; # Address of current instruction
206 $lineno = 0; # Line number we are parsing
208 $output = 'script.h'; # Output file
209 $outputu = 'scriptu.h';
211 # &patch ($address, $offset, $length, $value) patches $code[$address]
212 # so that the $length bytes at $offset have $value added to
213 # them.
215 @inverted_masks = (0x00_00_00_00, 0x00_00_00_ff, 0x00_00_ff_ff, 0x00_ff_ff_ff,
216 0xff_ff_ff_ff);
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];
225 $mask = ($inverted_masks[$length] << ($offset * 8));
227 $code[$address] = ($code[$address] & ~$mask) |
228 (($code[$address] & $mask) + ($value << ($offset * 8)) &
229 $mask);
231 printf STDERR "New code : %08x\n", $code[$address] if ($debug);
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.
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.
243 sub parse_value {
244 local ($value, $word, $offset, $length) = @_;
245 local ($tmp);
247 $symbol = '';
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);
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 : $_";
272 $symbol_references{$symbol} = "$relative,$tmp,$length";
276 $value = eval $value;
277 &patch ($address + $word, $offset, $length, $value);
280 # &parse_conditional ($conditional) where $conditional is the conditional
281 # clause from a transfer control instruction (RETURN, CALL, JUMP, INT).
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);
297 } else {
298 die "$0 : syntax error in line $lineno : $_
299 expected IF or WHEN
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'
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;
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);
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>.
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\"
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\"
386 # Parse command line
387 $output = shift;
388 $outputu = shift;
391 # Main loop
392 while (<STDIN>) {
393 $lineno = $lineno + 1;
394 $list[$address] = $list[$address].$_;
395 s/;.*$//; # Strip comments
398 chop; # Leave new line out of error messages
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";
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);
428 } else {
429 die "$0 : redefinition of symbol $id in line $lineno : $_\n";
431 } else {
432 die
433 "$0 : syntax error in line $lineno : $_
434 expected <identifier> = <value>
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";
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
457 # Process ENTRY identifier declarations
458 } elsif (/^\s*ENTRY\s+(.*)/i) {
459 if ($1 =~ /^($identifier)\s*$/) {
460 push (@entry, $1);
461 } else {
463 "$0 : syntax error in line $lineno : $_
464 expected ENTRY <identifier>
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;
507 } else {
508 die
509 "$0 : syntax error in line $lineno : $_
510 expected <count>, <source>, <destination>
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;
519 $code[$address] = 0x40_00_00_00;
521 $force = ($op !~ /TO/i);
524 print STDERR "Forcing register source \n" if ($force && $debug);
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"
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 = '|';
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>
558 } else {
560 "$0 : syntax error in line $lineno : $_
561 expected <register>
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
575 if ($rest =~ /^WITH\s+CARRY\s*(.*)/i) {
576 $rest = $1;
577 if ($op eq '+') {
578 $code[$address] |= 0x01_00_00_00;
579 } else {
581 "$0 : syntax error in $lineno : $_
582 WITH CARRY option is incompatible with the $op operator.
587 if ($rest !~ /^\s*$/) {
589 "$0 : syntax error in $lineno : $_
590 Expected end of line, got $rest
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 {
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.
615 $code[$address] |= $operators{$op};
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>
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
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 {
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
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.
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;
718 print STDERR "parsing JUMP, rest = $rest\n" if ($debug);
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 {
734 "$0 : syntax error in line $lineno : $_
735 expected <address> or REL (address)
739 if ($rest =~ /^,\s*(.*)/) {
740 &parse_conditional($1);
741 } elsif ($rest =~ /^\s*$/) {
742 $code[$address] |= (1 << 19);
743 } else {
745 "$0 : syntax error in line $lineno : $_
746 expected , <conditional> or end of line, got $1
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*$/) {
762 "$0 : syntax error in line $lineno : $_
763 expected , <conditional>
765 } else {
766 $code[$address] |= 0x00_08_00_00;
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
792 # Fill in label references
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";
800 exit 1;
803 @label_patches = ();
805 @external_patches = ();
807 @absolute = sort @absolute;
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');
820 &patch ($address / 4, $address % 4, $length, $symbol_values{$i});
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;
833 die
834 "$0 : symbol $label is external, has invalid relative reference at $address,
835 size $length\n"
836 if ($type eq 'REL');
838 die
839 "$0 : symbol $label has invalid reference at $address, size $length\n"
840 if ((($address % 4) !=0) || ($length != 4));
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";
851 print STDERR "referenced external $external at $1\n" if ($debug_external);
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;
864 if ((($address % 4) !=0) || ($length != 4)) {
865 die "$0 : symbol $label has invalid reference at $1, size $2\n";
868 if ($type eq 'ABS') {
869 $code[$address / 4] += $symbol_values{$label};
870 push (@label_patches, $address / 4);
871 } else {
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
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.
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;
892 # Output SCRIPT[] array, one instruction per line. Optionally
893 # print the original code too.
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";
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;
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];
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];
922 $i += 3;
923 } else {
924 printf OUTPUT "\n";
925 $i += 2;
927 $instructions += 1;
929 print OUTPUT "};\n\n";
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";
937 printf OUTPUTU "#undef A_$i\n";
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;
949 printf OUTPUT "};\n\n";
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};
958 # NCR assembler outputs label patches in the form of indices into
959 # the code.
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;
965 printf OUTPUT "};\n\n";
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;
975 printf OUTPUT "};\n\n";
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;