2 # SPDX-License-Identifier: GPL-2.0-or-later
4 # NCR 53c810 script assembler
6 # iX Multiuser Multitasking Magazine
8 # Copyright 1993, Drew Eckhardt
10 # (Unix and Linux consulting and custom programming)
14 # Support for 53c710 (via -ncr7x0_family switch) added by Richard
15 # Hirst <richard@sleepie.demon.co.uk> - 15th March 1997
17 # TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
21 # Basically, I follow the NCR syntax documented in the NCR53c710
22 # Programmer's guide, with the new instructions, registers, etc.
25 # Differences between this assembler and NCR's are that
26 # 1. PASS, REL (data, JUMPs work fine), and the option to start a new
27 # script, are unimplemented, since I didn't use them in my scripts.
29 # 2. I also emit a script_u.h file, which will undefine all of
30 # the A_*, E_*, etc. symbols defined in the script. This
31 # makes including multiple scripts in one program easier
33 # 3. This is a single pass assembler, which only emits
38 # XXX - set these with command line options
39 $debug = 0; # Print general debugging messages
40 $debug_external = 0; # Print external/forward reference messages
41 $list_in_array = 1; # Emit original SCRIPTS assembler in comments in
43 #$prefix; # (set by perl -s)
44 # define all arrays having this prefix so we
45 # don't have name space collisions after
46 # assembling this file in different ways for
47 # different host adapters
52 # Table of the SCSI phase encodings
54 'DATA_OUT', 0x00_
00_
00_
00, 'DATA_IN', 0x01_
00_
00_
00, 'CMD', 0x02_
00_
00_
00,
55 'STATUS', 0x03_
00_
00_
00, 'MSG_OUT', 0x06_
00_
00_
00, 'MSG_IN', 0x07_
00_
00_
00
58 # XXX - replace references to the *_810 constants with general constants
59 # assigned at compile time based on chip type.
61 # Table of operator encodings
62 # XXX - NCR53c710 only implements
63 # move (nop) = 0x00_00_00_00
70 '|', 0x02_
00_
00_
00, 'OR', 0x02_
00_
00_
00,
71 '&', 0x04_
00_
00_
00, 'AND', 0x04_
00_
00_
00,
78 '|', 0x02_
00_
00_
00, 'OR', 0x02_
00_
00_
00,
80 '&', 0x04_
00_
00_
00, 'AND', 0x04_
00_
00_
00,
82 # Note : low bit of the operator bit should be set for add with
88 # Table of register addresses
92 'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
93 'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
94 'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11,
95 'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
96 'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
97 'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23,
98 'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27,
99 'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
100 'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34, 'LCRC', 35,
101 'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
102 'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
103 'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
104 'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
105 'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
106 'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
107 'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
112 'SCNTL0', 0, 'SCNTL1', 1, 'SCNTL2', 2, 'SCNTL3', 3,
113 'SCID', 4, 'SXFER', 5, 'SDID', 6, 'GPREG', 7,
114 'SFBR', 8, 'SOCL', 9, 'SSID', 10, 'SBCL', 11,
115 'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
116 'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
118 'CTEST0', 24, 'CTEST1', 25, 'CTEST2', 26, 'CTEST3', 27,
119 'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
120 'DFIFO', 32, 'CTEST4', 33, 'CTEST5', 34, 'CTEST6', 35,
121 'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
122 'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
123 'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
124 'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
125 'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
126 'SCRATCHA0', 52, 'SCRATCHA1', 53, 'SCRATCHA2', 54, 'SCRATCHA3', 55,
127 'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
128 'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
129 'SIEN0', 64, 'SIEN1', 65, 'SIST0', 66, 'SIST1', 67,
130 'SLPAR', 68, 'MACNTL', 70, 'GPCNTL', 71,
131 'STIME0', 72, 'STIME1', 73, 'RESPID', 74,
132 'STEST0', 76, 'STEST1', 77, 'STEST2', 78, 'STEST3', 79,
136 'SCRATCHB0', 92, 'SCRATCHB1', 93, 'SCRATCHB2', 94, 'SCRATCHB3', 95
140 # Parsing regular expressions
141 $identifier = '[A-Za-z_][A-Za-z_0-9]*';
143 $hexnum = '0[xX][0-9A-Fa-f]+';
144 $constant = "$hexnum|$decnum";
146 # yucky - since we can't control grouping of # $constant, we need to
147 # expand out each alternative for $value.
149 $value = "$identifier|$identifier\\s*[+\-]\\s*$decnum|".
150 "$identifier\\s*[+-]\s*$hexnum|$constant";
152 print STDERR
"value regex = $value\n" if ($debug);
154 $phase = join ('|', keys %scsi_phases);
155 print STDERR
"phase regex = $phase\n" if ($debug);
156 $register = join ('|', keys %registers);
158 # yucky - since %operators includes meta-characters which must
159 # be escaped, I can't use the join() trick I used for the register
162 if ($ncr7x0_family) {
163 $operator = '\||OR|AND|\&|\+';
166 $operator = '\||OR|AND|XOR|\&|\+';
171 %symbol_values = (%registers) ; # Traditional symbol table
173 %symbol_references = () ; # Table of symbol references, where
174 # the index is the symbol name,
175 # and the contents a white space
176 # delimited list of address,size
177 # tuples where size is in bytes.
179 @code = (); # Array of 32 bit words for SIOP
181 @entry = (); # Array of entry point names
183 @label = (); # Array of label names
185 @absolute = (); # Array of absolute names
187 @relative = (); # Array of relative names
189 @external = (); # Array of external names
191 $address = 0; # Address of current instruction
193 $lineno = 0; # Line number we are parsing
195 $output = 'script.h'; # Output file
196 $outputu = 'scriptu.h';
198 # &patch ($address, $offset, $length, $value) patches $code[$address]
199 # so that the $length bytes at $offset have $value added to
202 @inverted_masks = (0x00_
00_
00_
00, 0x00_
00_
00_ff
, 0x00_
00_ff_ff
, 0x00_ff_ff_ff
,
206 local ($address, $offset, $length, $value) = @_;
208 print STDERR
"Patching $address at offset $offset, length $length to $value\n";
209 printf STDERR
"Old code : %08x\n", $code[$address];
212 $mask = ($inverted_masks[$length] << ($offset * 8));
214 $code[$address] = ($code[$address] & ~$mask) |
215 (($code[$address] & $mask) + ($value << ($offset * 8)) &
218 printf STDERR
"New code : %08x\n", $code[$address] if ($debug);
221 # &parse_value($value, $word, $offset, $length) where $value is
222 # an identifier or constant, $word is the word offset relative to
223 # $address, $offset is the starting byte within that word, and
224 # $length is the length of the field in bytes.
226 # Side effects are that the bytes are combined into the @code array
227 # relative to $address, and that the %symbol_references table is
228 # updated as appropriate.
231 local ($value, $word, $offset, $length) = @_;
236 if ($value =~ /^REL\s*\(\s*($identifier)\s*\)\s*(.*)/i) {
240 print STDERR
"Relative reference $symbol\n" if ($debug);
241 } elsif ($value =~ /^($identifier)\s*(.*)/) {
245 print STDERR
"Absolute reference $symbol\n" if ($debug);
249 print STDERR
"Referencing symbol $1, length = $length in $_\n" if ($debug);
250 $tmp = ($address + $word) * 4 + $offset;
251 if ($symbol_references{$symbol} ne undef) {
252 $symbol_references{$symbol} =
253 "$symbol_references{$symbol} $relative,$tmp,$length";
255 if (!defined($symbol_values{$symbol})) {
256 print STDERR
"forward $1\n" if ($debug_external);
257 $forward{$symbol} = "line $lineno : $_";
259 $symbol_references{$symbol} = "$relative,$tmp,$length";
263 $value = eval $value;
264 &patch
($address + $word, $offset, $length, $value);
267 # &parse_conditional ($conditional) where $conditional is the conditional
268 # clause from a transfer control instruction (RETURN, CALL, JUMP, INT).
270 sub parse_conditional
{
271 local ($conditional) = @_;
272 if ($conditional =~ /^\s*(IF|WHEN)\s*(.*)/i) {
275 if ($if =~ /WHEN/i) {
277 $code[$address] |= 0x00_
01_
00_
00;
279 print STDERR
"$0 : parsed WHEN\n" if ($debug);
282 print STDERR
"$0 : parsed IF\n" if ($debug);
285 die "$0 : syntax error in line $lineno : $_
290 if ($conditional =~ /^NOT\s+(.*)$/i) {
294 print STDERR
"$0 : parsed NOT\n" if ($debug);
296 $code[$address] |= 0x00_
08_
00_
00;
302 if ($conditional =~ /^ATN\s*(.*)/i) {#
303 die "$0 : syntax error in line $lineno : $_
304 WHEN conditional is incompatible with ATN
306 $code[$address] |= 0x00_
02_
00_
00;
308 print STDERR
"$0 : parsed ATN\n" if ($debug);
309 } elsif ($conditional =~ /^($phase)\s*(.*)/i) {
310 $phase_index = "\U$1\E";
311 $p = $scsi_phases{$phase_index};
312 $code[$address] |= $p | 0x00_
02_
00_
00;
314 print STDERR
"$0 : parsed phase $phase_index\n" if ($debug);
320 print STDERR
"Parsing conjunction, expecting $other\n" if ($debug);
321 if ($conditional =~ /^(AND|OR)\s*(.*)/i) {
325 die "$0 : syntax error in line $lineno : $_
326 Illegal use of $1. Valid uses are
327 ".$not."<phase> $1 data
330 die "$0 : syntax error in line $lineno : $_
331 Illegal use of $conjunction. Valid syntaxes are
332 NOT <phase>|ATN OR data
334 " if ($conjunction !~ /\s*$other\s*/i);
335 print STDERR
"$0 : parsed $1\n" if ($debug);
339 print STDERR
"looking for data in $conditional\n" if ($debug);
340 if ($conditional=~ /^($value)\s*(.*)/i) {
341 $code[$address] |= 0x00_
04_
00_
00;
343 &parse_value
($1, 0, 0, 1);
344 print STDERR
"$0 : parsed data\n" if ($debug);
346 die "$0 : syntax error in line $lineno : $_
352 if ($conditional =~ /^\s*,\s*(.*)/) {
354 if ($conditional =~ /^AND\s\s*MASK\s\s*($value)\s*(.*)/i) {
355 &parse_value
($1, 0, 1, 1);
356 print STDERR
"$0 parsed AND MASK $1\n" if ($debug);
357 die "$0 : syntax error in line $lineno : $_
358 expected end of line, not \"$2\"
361 die "$0 : syntax error in line $lineno : $_
362 expected \",AND MASK <data>\", not \"$2\"
365 } elsif ($conditional !~ /^\s*$/) {
366 die "$0 : syntax error in line $lineno : $_
367 expected end of line" . (($need_data) ?
" or \"AND MASK <data>\"" : "") . "
380 $lineno = $lineno + 1;
381 $list[$address] = $list[$address].$_;
382 s/;.*$//; # Strip comments
385 chop; # Leave new line out of error messages
387 # Handle symbol definitions of the form label:
388 if (/^\s*($identifier)\s*:(.*)/) {
389 if (!defined($symbol_values{$1})) {
390 $symbol_values{$1} = $address * 4; # Address is an index into
391 delete $forward{$1}; # an array of longs
395 die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
399 # Handle symbol definitions of the form ABSOLUTE or RELATIVE identifier =
401 if (/^\s*(ABSOLUTE|RELATIVE)\s+(.*)/i) {
404 foreach $rest (split (/\s*,\s*/, $rest)) {
405 if ($rest =~ /^($identifier)\s*=\s*($constant)\s*$/) {
406 local ($id, $cnst) = ($1, $2);
407 if ($symbol_values{$id} eq undef) {
408 $symbol_values{$id} = eval $cnst;
409 delete $forward{$id};
410 if ($is_absolute =~ /ABSOLUTE/i) {
411 push (@absolute , $id);
413 push (@relative, $id);
416 die "$0 : redefinition of symbol $id in line $lineno : $_\n";
420 "$0 : syntax error in line $lineno : $_
421 expected <identifier> = <value>
425 } elsif (/^\s*EXTERNAL\s+(.*)/i) {
427 foreach $external (split (/,/,$externals)) {
428 if ($external =~ /\s*($identifier)\s*$/) {
430 push (@external, $external);
431 delete $forward{$external};
432 if (defined($symbol_values{$external})) {
433 die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
435 $symbol_values{$external} = $external;
436 print STDERR
"defined external $1 to $external\n" if ($debug_external);
439 "$0 : syntax error in line $lineno : $_
440 expected <identifier>, got $external
444 # Process ENTRY identifier declarations
445 } elsif (/^\s*ENTRY\s+(.*)/i) {
446 if ($1 =~ /^($identifier)\s*$/) {
450 "$0 : syntax error in line $lineno : $_
451 expected ENTRY <identifier>
454 # Process MOVE length, address, WITH|WHEN phase instruction
455 } elsif (/^\s*MOVE\s+(.*)/i) {
457 if ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
461 print STDERR
"Parsing MOVE FROM $transfer_addr, $with_when $3\n" if ($debug);
462 $code[$address] = 0x18_
00_
00_
00 | (($with_when =~ /WITH/i) ?
463 0x00_
00_
00_
00 : 0x08_
00_
00_
00) | $scsi_phases{$scsi_phase};
464 &parse_value
($transfer_addr, 1, 0, 4);
466 } elsif ($rest =~ /^($value)\s*,\s*(PTR\s+|)($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
472 $code[$address] = (($with_when =~ /WITH/i) ?
0x00_
00_
00_
00 :
473 0x08_
00_
00_
00) | (($ptr =~ /PTR/i) ?
(1 << 29) : 0) |
474 $scsi_phases{$scsi_phase};
475 &parse_value
($transfer_len, 0, 0, 3);
476 &parse_value
($transfer_addr, 1, 0, 4);
478 } elsif ($rest =~ /^MEMORY\s+(.*)/i) {
480 $code[$address] = 0xc0_
00_
00_
00;
481 if ($rest =~ /^($value)\s*,\s*($value)\s*,\s*($value)\s*$/) {
485 print STDERR
"Parsing MOVE MEMORY $count, $source, $dest\n" if ($debug);
486 &parse_value
($count, 0, 0, 3);
487 &parse_value
($source, 1, 0, 4);
488 &parse_value
($dest, 2, 0, 4);
489 printf STDERR
"Move memory instruction = %08x,%08x,%08x\n",
490 $code[$address], $code[$address+1], $code[$address +2] if
496 "$0 : syntax error in line $lineno : $_
497 expected <count>, <source>, <destination>
500 } elsif ($1 =~ /^(.*)\s+(TO|SHL|SHR)\s+(.*)/i) {
501 print STDERR
"Parsing register to register move\n" if ($debug);
506 $code[$address] = 0x40_
00_
00_
00;
508 $force = ($op !~ /TO/i);
511 print STDERR
"Forcing register source \n" if ($force && $debug);
513 if (!$force && $src =~
514 /^($register)\s+(-|$operator)\s+($value)\s*$/i) {
515 print STDERR
"register operand data8 source\n" if ($debug);
521 die "- is not implemented yet.\n"
523 } elsif ($src =~ /^($register)\s*$/i) {
524 print STDERR
"register source\n" if ($debug);
526 # Encode register to register move as a register | 0
532 } elsif (!$force && $src =~ /^($value)\s*$/i) {
533 print STDERR
"data8 source\n" if ($debug);
540 "$0 : syntax error in line $lineno : $_
543 <register> <operand> <data8>
547 "$0 : syntax error in line $lineno : $_
552 if ($rest =~ /^($register)\s*(.*)$/i) {
557 "$0 : syntax error in $lineno : $_
558 expected <register>, got $rest
562 if ($rest =~ /^WITH\s+CARRY\s*(.*)/i) {
565 $code[$address] |= 0x01_
00_
00_
00;
568 "$0 : syntax error in $lineno : $_
569 WITH CARRY option is incompatible with the $op operator.
574 if ($rest !~ /^\s*$/) {
576 "$0 : syntax error in $lineno : $_
577 Expected end of line, got $rest
581 print STDERR
"source = $src_reg, data = $data8 , destination = $dst_reg\n"
583 # Note that Move data8 to reg is encoded as a read-modify-write
585 if (($src_reg eq undef) || ($src_reg eq $dst_reg)) {
586 $code[$address] |= 0x38_
00_
00_
00 |
587 ($registers{$dst_reg} << 16);
588 } elsif ($dst_reg =~ /SFBR/i) {
589 $code[$address] |= 0x30_
00_
00_
00 |
590 ($registers{$src_reg} << 16);
591 } elsif ($src_reg =~ /SFBR/i) {
592 $code[$address] |= 0x28_
00_
00_
00 |
593 ($registers{$dst_reg} << 16);
596 "$0 : Illegal combination of registers in line $lineno : $_
597 Either source and destination registers must be the same,
598 or either source or destination register must be SFBR.
602 $code[$address] |= $operators{$op};
604 &parse_value
($data8, 0, 1, 1);
605 $code[$address] |= $operators{$op};
606 $code[$address + 1] = 0x00_
00_
00_
00;# Reserved
610 "$0 : syntax error in line $lineno : $_
611 expected (initiator) <length>, <address>, WHEN <phase>
612 (target) <length>, <address>, WITH <phase>
613 MEMORY <length>, <source>, <destination>
614 <expression> TO <register>
617 # Process SELECT {ATN|} id, fail_address
618 } elsif (/^\s*(SELECT|RESELECT)\s+(.*)/i) {
620 if ($rest =~ /^(ATN|)\s*($value)\s*,\s*($identifier)\s*$/i) {
624 $code[$address] = 0x40_
00_
00_
00 |
625 (($atn =~ /ATN/i) ?
0x01_
00_
00_
00 : 0);
626 $code[$address + 1] = 0x00_
00_
00_
00;
627 &parse_value
($id, 0, 2, 1);
628 &parse_value
($alt_addr, 1, 0, 4);
630 } elsif ($rest =~ /^(ATN|)\s*FROM\s+($value)\s*,\s*($identifier)\s*$/i) {
634 $code[$address] = 0x42_
00_
00_
00 |
635 (($atn =~ /ATN/i) ?
0x01_
00_
00_
00 : 0);
636 $code[$address + 1] = 0x00_
00_
00_
00;
637 &parse_value
($addr, 0, 0, 3);
638 &parse_value
($alt_addr, 1, 0, 4);
642 "$0 : syntax error in line $lineno : $_
643 expected SELECT id, alternate_address or
644 SELECT FROM address, alternate_address or
645 RESELECT id, alternate_address or
646 RESELECT FROM address, alternate_address
649 } elsif (/^\s*WAIT\s+(.*)/i) {
651 print STDERR
"Parsing WAIT $rest\n" if ($debug);
652 if ($rest =~ /^DISCONNECT\s*$/i) {
653 $code[$address] = 0x48_
00_
00_
00;
654 $code[$address + 1] = 0x00_
00_
00_
00;
656 } elsif ($rest =~ /^(RESELECT|SELECT)\s+($identifier)\s*$/i) {
658 $code[$address] = 0x50_
00_
00_
00;
659 &parse_value
($alt_addr, 1, 0, 4);
663 "$0 : syntax error in line $lineno : $_
664 expected (initiator) WAIT DISCONNECT or
665 (initiator) WAIT RESELECT alternate_address or
666 (target) WAIT SELECT alternate_address
669 # Handle SET and CLEAR instructions. Note that we should also do something
670 # with this syntax to set target mode.
671 } elsif (/^\s*(SET|CLEAR)\s+(.*)/i) {
674 $code[$address] = ($set =~ /SET/i) ?
0x58_
00_
00_
00 :
676 foreach $arg (split (/\s+AND\s+/i,$list)) {
677 if ($arg =~ /ATN/i) {
678 $code[$address] |= 0x00_
00_
00_
08;
679 } elsif ($arg =~ /ACK/i) {
680 $code[$address] |= 0x00_
00_
00_
40;
681 } elsif ($arg =~ /TARGET/i) {
682 $code[$address] |= 0x00_
00_
02_
00;
683 } elsif ($arg =~ /CARRY/i) {
684 $code[$address] |= 0x00_
00_
04_
00;
687 "$0 : syntax error in line $lineno : $_
688 expected $set followed by a AND delimited list of one or
689 more strings from the list ACK, ATN, CARRY, TARGET.
693 $code[$address + 1] = 0x00_
00_
00_
00;
695 } elsif (/^\s*(JUMP|CALL|INT)\s+(.*)/i) {
698 if ($instruction =~ /JUMP/i) {
699 $code[$address] = 0x80_
00_
00_
00;
700 } elsif ($instruction =~ /CALL/i) {
701 $code[$address] = 0x88_
00_
00_
00;
703 $code[$address] = 0x98_
00_
00_
00;
705 print STDERR
"parsing JUMP, rest = $rest\n" if ($debug);
708 if ($rest =~ /^(REL\s*\(\s*$identifier\s*\))\s*(.*)/i) {
711 print STDERR
"parsing JUMP REL, addr = $addr, rest = $rest\n" if ($debug);
712 $code[$address] |= 0x00_
80_
00_
00;
713 &parse_value
($addr, 1, 0, 4);
714 # Absolute jump, requires no more gunk
715 } elsif ($rest =~ /^($value)\s*(.*)/) {
718 &parse_value
($addr, 1, 0, 4);
721 "$0 : syntax error in line $lineno : $_
722 expected <address> or REL (address)
726 if ($rest =~ /^,\s*(.*)/) {
727 &parse_conditional
($1);
728 } elsif ($rest =~ /^\s*$/) {
729 $code[$address] |= (1 << 19);
732 "$0 : syntax error in line $lineno : $_
733 expected , <conditional> or end of line, got $1
738 } elsif (/^\s*(RETURN|INTFLY)\s*(.*)/i) {
741 print STDERR
"Parsing $instruction\n" if ($debug);
742 $code[$address] = ($instruction =~ /RETURN/i) ?
0x90_
00_
00_
00 :
744 if ($conditional =~ /^,\s*(.*)/) {
746 &parse_conditional
($conditional);
747 } elsif ($conditional !~ /^\s*$/) {
749 "$0 : syntax error in line $lineno : $_
750 expected , <conditional>
753 $code[$address] |= 0x00_
08_
00_
00;
756 $code[$address + 1] = 0x00_
00_
00_
00;
758 } elsif (/^\s*DISCONNECT\s*$/) {
759 $code[$address] = 0x48_
00_
00_
00;
760 $code[$address + 1] = 0x00_
00_
00_
00;
762 # I'm not sure that I should be including this extension, but
764 } elsif (/^\s*NOP\s*$/i) {
765 $code[$address] = 0x80_
88_
00_
00;
766 $code[$address + 1] = 0x00_
00_
00_
00;
768 # Ignore lines consisting entirely of white space
772 "$0 : syntax error in line $lineno: $_
773 expected label:, ABSOLUTE, CLEAR, DISCONNECT, EXTERNAL, MOVE, RESELECT,
779 # Fill in label references
781 @undefined = keys %forward;
782 if ($#undefined >= 0) {
783 print STDERR
"Undefined symbols : \n";
784 foreach $undef (@undefined) {
785 print STDERR
"$undef in $forward{$undef}\n";
792 @external_patches = ();
794 @absolute = sort @absolute;
796 foreach $i (@absolute) {
797 foreach $j (split (/\s+/,$symbol_references{$i})) {
798 $j =~ /(REL|ABS),(.*),(.*)/;
803 "$0 : $symbol $i has invalid relative reference at address $address,
807 &patch
($address / 4, $address % 4, $length, $symbol_values{$i});
811 foreach $external (@external) {
812 print STDERR
"checking external $external \n" if ($debug_external);
813 if ($symbol_references{$external} ne undef) {
814 for $reference (split(/\s+/,$symbol_references{$external})) {
815 $reference =~ /(REL|ABS),(.*),(.*)/;
821 "$0 : symbol $label is external, has invalid relative reference at $address,
826 "$0 : symbol $label has invalid reference at $address, size $length\n"
827 if ((($address % 4) !=0) || ($length != 4));
829 $symbol = $symbol_values{$external};
830 $add = $code[$address / 4];
832 $code[$address / 4] = $symbol;
834 $add = sprintf ("0x%08x", $add);
835 $code[$address / 4] = "$symbol + $add";
838 print STDERR
"referenced external $external at $1\n" if ($debug_external);
843 foreach $label (@label) {
844 if ($symbol_references{$label} ne undef) {
845 for $reference (split(/\s+/,$symbol_references{$label})) {
846 $reference =~ /(REL|ABS),(.*),(.*)/;
851 if ((($address % 4) !=0) || ($length != 4)) {
852 die "$0 : symbol $label has invalid reference at $1, size $2\n";
855 if ($type eq 'ABS') {
856 $code[$address / 4] += $symbol_values{$label};
857 push (@label_patches, $address / 4);
860 # - The address of the reference should be in the second and last word
862 # - Relative jumps, etc. are relative to the DSP of the _next_ instruction
864 # So, we need to add four to the address of the reference, to get
865 # the address of the next instruction, when computing the reference.
867 $tmp = $symbol_values{$label} -
870 # Relative addressing is limited to 24 bits.
871 "$0 : symbol $label is too far ($tmp) from $address to reference as
872 relative/\n" if (($tmp >= 0x80_
00_
00) || ($tmp < -0x80_
00_
00));
873 $code[$address / 4] = $tmp & 0x00_ff_ff_ff
;
879 # Output SCRIPT[] array, one instruction per line. Optionally
880 # print the original code too.
882 open (OUTPUT
, ">$output") || die "$0 : can't open $output for writing\n";
883 open (OUTPUTU
, ">$outputu") || die "$0 : can't open $outputu for writing\n";
885 ($_ = $0) =~ s
:.*/::;
886 print OUTPUT
"/* DO NOT EDIT - Generated automatically by ".$_." */\n";
887 print OUTPUT
"static u32 ".$prefix."SCRIPT[] = {\n";
889 for ($i = 0; $i < $#code; ) {
890 if ($list_in_array) {
891 printf OUTPUT
"/*\n$list[$i]\nat 0x%08x : */", $i;
893 printf OUTPUT
"\t0x%08x,", $code[$i];
894 printf STDERR
"Address $i = %x\n", $code[$i] if ($debug);
895 if ($code[$i + 1] =~ /\s*($identifier)(.*)$/) {
896 push (@external_patches, $i+1, $1);
897 printf OUTPUT
"0%s,", $2
899 printf OUTPUT
"0x%08x,",$code[$i+1];
902 if (($code[$i] & 0xff_
00_
00_
00) == 0xc0_
00_
00_
00) {
903 if ($code[$i + 2] =~ /$identifier/) {
904 push (@external_patches, $i+2, $code[$i+2]);
905 printf OUTPUT
"0,\n";
907 printf OUTPUT
"0x%08x,\n",$code[$i+2];
916 print OUTPUT
"};\n\n";
918 foreach $i (@absolute) {
919 printf OUTPUT
"#define A_$i\t0x%08x\n", $symbol_values{$i};
920 if (defined($prefix) && $prefix ne '') {
921 printf OUTPUT
"#define A_".$i."_used ".$prefix."A_".$i."_used\n";
922 printf OUTPUTU
"#undef A_".$i."_used\n";
924 printf OUTPUTU
"#undef A_$i\n";
926 printf OUTPUT
"static u32 A_".$i."_used\[\] __attribute((unused)) = {\n";
927 printf STDERR
"$i is used $symbol_references{$i}\n" if ($debug);
928 foreach $j (split (/\s+/,$symbol_references{$i})) {
929 $j =~ /(ABS|REL),(.*),(.*)/;
933 printf OUTPUT
"\t0x%08x,\n", $address / 4;
936 printf OUTPUT
"};\n\n";
939 foreach $i (sort @entry) {
940 printf OUTPUT
"#define Ent_$i\t0x%08x\n", $symbol_values{$i};
941 printf OUTPUTU
"#undef Ent_$i\n", $symbol_values{$i};
945 # NCR assembler outputs label patches in the form of indices into
948 printf OUTPUT
"static u32 ".$prefix."LABELPATCHES[] __attribute((unused)) = {\n";
949 for $patch (sort {$a <=> $b} @label_patches) {
950 printf OUTPUT
"\t0x%08x,\n", $patch;
952 printf OUTPUT
"};\n\n";
954 $num_external_patches = 0;
955 printf OUTPUT
"static struct {\n\tu32\toffset;\n\tvoid\t\t*address;\n".
956 "} ".$prefix."EXTERNAL_PATCHES[] __attribute((unused)) = {\n";
957 while ($ident = pop(@external_patches)) {
958 $off = pop(@external_patches);
959 printf OUTPUT
"\t{0x%08x, &%s},\n", $off, $ident;
960 ++$num_external_patches;
962 printf OUTPUT
"};\n\n";
964 printf OUTPUT
"static u32 ".$prefix."INSTRUCTIONS __attribute((unused))\t= %d;\n",
966 printf OUTPUT
"static u32 ".$prefix."PATCHES __attribute((unused))\t= %d;\n",
968 printf OUTPUT
"static u32 ".$prefix."EXTERNAL_PATCHES_LEN __attribute((unused))\t= %d;\n",
969 $num_external_patches;