3 # NCR 53c810 script assembler
5 # iX Multiuser Multitasking Magazine
7 # Copyright 1993, Drew Eckhardt
9 # (Unix and Linux consulting and custom programming)
13 # Support for 53c710 (via -ncr7x0_family switch) added by Richard
14 # Hirst <richard@sleepie.demon.co.uk> - 15th March 1997
15 # Renamed to -ncr7x0_family to -ncr710, and added -ncr700 - 5th May 2000.
17 # This program is free software; you can redistribute it and/or modify
18 # it under the terms of the GNU General Public License as published by
19 # the Free Software Foundation; either version 2 of the License, or
20 # (at your option) any later version.
22 # This program is distributed in the hope that it will be useful,
23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 # GNU General Public License for more details.
27 # You should have received a copy of the GNU General Public License
28 # along with this program; if not, write to the Free Software
29 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 # TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
35 # Basically, I follow the NCR syntax documented in the NCR53c710
36 # Programmer's guide, with the new instructions, registers, etc.
39 # Differences between this assembler and NCR's are that
40 # 1. PASS, REL (data, JUMPs work fine), and the option to start a new
41 # script, are unimplemented, since I didn't use them in my scripts.
43 # 2. I also emit a script_u.h file, which will undefine all of
44 # the A_*, E_*, etc. symbols defined in the script. This
45 # makes including multiple scripts in one program easier
47 # 3. This is a single pass assembler, which only emits
52 # XXX - set these with command line options
53 $debug = 0; # Print general debugging messages
54 $debug_external = 0; # Print external/forward reference messages
55 $list_in_array = 1; # Emit original SCRIPTS assembler in comments in
57 $prefix = ''; # define all arrays having this prefix so we
58 # don't have name space collisions after
59 # assembling this file in different ways for
60 # different host adapters
65 # Table of the SCSI phase encodings
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
81 if ($ncr700 || $ncr710) {
83 '|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
84 '&', 0x04_00_00_00, 'AND', 0x04_00_00_00,
91 '|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
93 '&', 0x04_00_00_00, 'AND', 0x04_00_00_00,
95 # Note : low bit of the operator bit should be set for add with
101 # Table of register addresses
105 'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
106 'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
107 'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11,
108 'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
109 'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23,
110 'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27,
111 'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
112 'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34,
113 'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
114 'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
115 'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
116 'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
117 'DMODE', 52, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
122 'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
123 'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
124 'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11,
125 'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
126 'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
127 'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23,
128 'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27,
129 'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
130 'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34, 'LCRC', 35,
131 'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
132 'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
133 'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
134 'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
135 'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
136 'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
137 'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
142 'SCNTL0', 0, 'SCNTL1', 1, 'SCNTL2', 2, 'SCNTL3', 3,
143 'SCID', 4, 'SXFER', 5, 'SDID', 6, 'GPREG', 7,
144 'SFBR', 8, 'SOCL', 9, 'SSID', 10, 'SBCL', 11,
145 'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
146 'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
148 'CTEST0', 24, 'CTEST1', 25, 'CTEST2', 26, 'CTEST3', 27,
149 'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
150 'DFIFO', 32, 'CTEST4', 33, 'CTEST5', 34, 'CTEST6', 35,
151 'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
152 'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
153 'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
154 'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
155 'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
156 'SCRATCHA0', 52, 'SCRATCHA1', 53, 'SCRATCHA2', 54, 'SCRATCHA3', 55,
157 'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
158 'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
159 'SIEN0', 64, 'SIEN1', 65, 'SIST0', 66, 'SIST1', 67,
160 'SLPAR', 68, 'MACNTL', 70, 'GPCNTL', 71,
161 'STIME0', 72, 'STIME1', 73, 'RESPID', 74,
162 'STEST0', 76, 'STEST1', 77, 'STEST2', 78, 'STEST3', 79,
166 'SCRATCHB0', 92, 'SCRATCHB1', 93, 'SCRATCHB2', 94, 'SCRATCHB3', 95
170 # Parsing regular expressions
171 $identifier = '[A-Za-z_][A-Za-z_0-9]*';
173 $hexnum = '0[xX][0-9A-Fa-f]+';
174 $constant = "$hexnum|$decnum";
176 # yucky - since we can't control grouping of # $constant, we need to
177 # expand out each alternative for $value.
179 $value = "$identifier|$identifier\\s*[+\-]\\s*$decnum|".
180 "$identifier\\s*[+-]\s*$hexnum|$constant";
182 print STDERR "value regex = $value\n" if ($debug);
184 $phase = join ('|', keys %scsi_phases);
185 print STDERR "phase regex = $phase\n" if ($debug);
186 $register = join ('|', keys %registers);
188 # yucky - since %operators includes meta-characters which must
189 # be escaped, I can't use the join() trick I used for the register
192 if ($ncr700 || $ncr710) {
193 $operator = '\||OR|AND|\&|\+';
196 $operator = '\||OR|AND|XOR|\&|\+';
201 %symbol_values = (%registers) ; # Traditional symbol table
203 %symbol_references = () ; # Table of symbol references, where
204 # the index is the symbol name,
205 # and the contents a white space
206 # delimited list of address,size
207 # tuples where size is in bytes.
209 @code = (); # Array of 32 bit words for SIOP
211 @entry = (); # Array of entry point names
213 @label = (); # Array of label names
215 @absolute = (); # Array of absolute names
217 @relative = (); # Array of relative names
219 @external = (); # Array of external names
221 $address = 0; # Address of current instruction
223 $lineno = 0; # Line number we are parsing
225 $output = 'script.h'; # Output file
226 $outputu = 'scriptu.h';
228 # &patch ($address, $offset, $length, $value) patches $code[$address]
229 # so that the $length bytes at $offset have $value added to
232 @inverted_masks = (0x00_00_00_00, 0x00_00_00_ff, 0x00_00_ff_ff, 0x00_ff_ff_ff,
236 local ($address, $offset, $length, $value) = @_;
238 print STDERR "Patching $address at offset $offset, length $length to $value\n";
239 printf STDERR "Old code : %08x\n", $code[$address];
242 $mask = ($inverted_masks[$length] << ($offset * 8));
244 $code[$address] = ($code[$address] & ~$mask) |
245 (($code[$address] & $mask) + ($value << ($offset * 8)) &
248 printf STDERR "New code : %08x\n", $code[$address] if ($debug);
251 # &parse_value($value, $word, $offset, $length) where $value is
252 # an identifier or constant, $word is the word offset relative to
253 # $address, $offset is the starting byte within that word, and
254 # $length is the length of the field in bytes.
256 # Side effects are that the bytes are combined into the @code array
257 # relative to $address, and that the %symbol_references table is
258 # updated as appropriate.
261 local ($value, $word, $offset, $length) = @_;
266 if ($value =~ /^REL\s*\(\s*($identifier)\s*\)\s*(.*)/i) {
270 print STDERR "Relative reference $symbol\n" if ($debug);
271 } elsif ($value =~ /^($identifier)\s*(.*)/) {
275 print STDERR "Absolute reference $symbol\n" if ($debug);
279 print STDERR "Referencing symbol $1, length = $length in $_\n" if ($debug);
280 $tmp = ($address + $word) * 4 + $offset;
281 if ($symbol_references{$symbol} ne undef) {
282 $symbol_references{$symbol} =
283 "$symbol_references{$symbol} $relative,$tmp,$length";
285 if (!defined($symbol_values{$symbol})) {
286 print STDERR "forward $1\n" if ($debug_external);
287 $forward{$symbol} = "line $lineno : $_";
289 $symbol_references{$symbol} = "$relative,$tmp,$length";
293 $value = eval $value;
294 &patch ($address + $word, $offset, $length, $value);
297 # &parse_conditional ($conditional) where $conditional is the conditional
298 # clause from a transfer control instruction (RETURN, CALL, JUMP, INT).
300 sub parse_conditional {
301 local ($conditional) = @_;
302 if ($conditional =~ /^\s*(IF|WHEN)\s*(.*)/i) {
305 if ($if =~ /WHEN/i) {
307 $code[$address] |= 0x00_01_00_00;
309 print STDERR "$0 : parsed WHEN\n" if ($debug);
312 print STDERR "$0 : parsed IF\n" if ($debug);
315 die "$0 : syntax error in line $lineno : $_
320 if ($conditional =~ /^NOT\s+(.*)$/i) {
324 print STDERR "$0 : parsed NOT\n" if ($debug);
326 $code[$address] |= 0x00_08_00_00;
332 if ($conditional =~ /^ATN\s*(.*)/i) {#
333 die "$0 : syntax error in line $lineno : $_
334 WHEN conditional is incompatible with ATN
336 $code[$address] |= 0x00_02_00_00;
338 print STDERR "$0 : parsed ATN\n" if ($debug);
339 } elsif ($conditional =~ /^($phase)\s*(.*)/i) {
340 $phase_index = "\U$1\E";
341 $p = $scsi_phases{$phase_index};
342 $code[$address] |= $p | 0x00_02_00_00;
344 print STDERR "$0 : parsed phase $phase_index\n" if ($debug);
350 print STDERR "Parsing conjunction, expecting $other\n" if ($debug);
351 if ($conditional =~ /^(AND|OR)\s*(.*)/i) {
355 die "$0 : syntax error in line $lineno : $_
356 Illegal use of $1. Valid uses are
357 ".$not."<phase> $1 data
360 die "$0 : syntax error in line $lineno : $_
361 Illegal use of $conjunction. Valid syntaxes are
362 NOT <phase>|ATN OR data
364 " if ($conjunction !~ /\s*$other\s*/i);
365 print STDERR "$0 : parsed $1\n" if ($debug);
369 print STDERR "looking for data in $conditional\n" if ($debug);
370 if ($conditional=~ /^($value)\s*(.*)/i) {
371 $code[$address] |= 0x00_04_00_00;
373 &parse_value($1, 0, 0, 1);
374 print STDERR "$0 : parsed data\n" if ($debug);
376 die "$0 : syntax error in line $lineno : $_
382 if ($conditional =~ /^\s*,\s*(.*)/) {
384 if ($conditional =~ /^AND\s\s*MASK\s\s*($value)\s*(.*)/i) {
385 &parse_value ($1, 0, 1, 1);
386 print STDERR "$0 parsed AND MASK $1\n" if ($debug);
387 die "$0 : syntax error in line $lineno : $_
388 expected end of line, not \"$2\"
391 die "$0 : syntax error in line $lineno : $_
392 expected \",AND MASK <data>\", not \"$2\"
395 } elsif ($conditional !~ /^\s*$/) {
396 die "$0 : syntax error in line $lineno : $_
397 expected end of line" . (($need_data) ? " or \"AND MASK <data>\"" : "") . "
404 foreach $arg (@argv) {
405 if ($arg =~ /^-prefix\s*=\s*([_a-zA-Z][_a-zA-Z0-9]*)$/i) {
412 $lineno = $lineno + 1;
413 $list[$address] = $list[$address].$_;
414 s/;.*$//; # Strip comments
417 chop; # Leave new line out of error messages
419 # Handle symbol definitions of the form label:
420 if (/^\s*($identifier)\s*:(.*)/) {
421 if (!defined($symbol_values{$1})) {
422 $symbol_values{$1} = $address * 4; # Address is an index into
423 delete $forward{$1}; # an array of longs
427 die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
431 # Handle symbol definitions of the form ABSOLUTE or RELATIVE identifier =
433 if (/^\s*(ABSOLUTE|RELATIVE)\s+(.*)/i) {
436 foreach $rest (split (/\s*,\s*/, $rest)) {
437 if ($rest =~ /^($identifier)\s*=\s*($constant)\s*$/) {
438 local ($id, $cnst) = ($1, $2);
439 if ($symbol_values{$id} eq undef) {
440 $symbol_values{$id} = eval $cnst;
441 delete $forward{$id};
442 if ($is_absolute =~ /ABSOLUTE/i) {
443 push (@absolute , $id);
445 push (@relative, $id);
448 die "$0 : redefinition of symbol $id in line $lineno : $_\n";
452 "$0 : syntax error in line $lineno : $_
453 expected <identifier> = <value>
457 } elsif (/^\s*EXTERNAL\s+(.*)/i) {
459 foreach $external (split (/,/,$externals)) {
460 if ($external =~ /\s*($identifier)\s*$/) {
462 push (@external, $external);
463 delete $forward{$external};
464 if (defined($symbol_values{$external})) {
465 die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
467 $symbol_values{$external} = $external;
468 print STDERR "defined external $1 to $external\n" if ($debug_external);
471 "$0 : syntax error in line $lineno : $_
472 expected <identifier>, got $external
476 # Process ENTRY identifier declarations
477 } elsif (/^\s*ENTRY\s+(.*)/i) {
478 if ($1 =~ /^($identifier)\s*$/) {
482 "$0 : syntax error in line $lineno : $_
483 expected ENTRY <identifier>
486 # Process MOVE length, address, WITH|WHEN phase instruction
487 } elsif (/^\s*MOVE\s+(.*)/i) {
489 if (!$ncr700 && ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i)) {
493 print STDERR "Parsing MOVE FROM $transfer_addr, $with_when $3\n" if ($debug);
494 $code[$address] = 0x18_00_00_00 | (($with_when =~ /WITH/i) ?
495 0x00_00_00_00 : 0x08_00_00_00) | $scsi_phases{$scsi_phase};
496 &parse_value ($transfer_addr, 1, 0, 4);
498 } elsif ($rest =~ /^($value)\s*,\s*(PTR\s+|)($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
504 $code[$address] = (($with_when =~ /WITH/i) ? 0x00_00_00_00 :
505 0x08_00_00_00) | (($ptr =~ /PTR/i) ? (1 << 29) : 0) |
506 $scsi_phases{$scsi_phase};
507 &parse_value ($transfer_len, 0, 0, 3);
508 &parse_value ($transfer_addr, 1, 0, 4);
510 } elsif ($rest =~ /^MEMORY\s+(.*)/i) {
512 $code[$address] = 0xc0_00_00_00;
513 if ($rest =~ /^($value)\s*,\s*($value)\s*,\s*($value)\s*$/) {
517 print STDERR "Parsing MOVE MEMORY $count, $source, $dest\n" if ($debug);
518 &parse_value ($count, 0, 0, 3);
519 &parse_value ($source, 1, 0, 4);
520 &parse_value ($dest, 2, 0, 4);
521 printf STDERR "Move memory instruction = %08x,%08x,%08x\n",
522 $code[$address], $code[$address+1], $code[$address +2] if
528 "$0 : syntax error in line $lineno : $_
529 expected <count>, <source>, <destination>
532 } elsif ($1 =~ /^(.*)\s+(TO|SHL|SHR)\s+(.*)/i) {
533 print STDERR "Parsing register to register move\n" if ($debug);
538 $code[$address] = 0x40_00_00_00;
540 $force = ($op !~ /TO/i);
543 print STDERR "Forcing register source \n" if ($force && $debug);
545 if (!$force && $src =~
546 /^($register)\s+(-|$operator)\s+($value)\s*$/i) {
547 print STDERR "register operand data8 source\n" if ($debug);
553 die "- is not implemented yet.\n"
555 } elsif ($src =~ /^($register)\s*$/i) {
556 print STDERR "register source\n" if ($debug);
558 # Encode register to register move as a register | 0
564 } elsif (!$force && $src =~ /^($value)\s*$/i) {
565 print STDERR "data8 source\n" if ($debug);
572 "$0 : syntax error in line $lineno : $_
575 <register> <operand> <data8>
579 "$0 : syntax error in line $lineno : $_
584 if ($rest =~ /^($register)\s*(.*)$/i) {
589 "$0 : syntax error in $lineno : $_
590 expected <register>, got $rest
594 if ($rest =~ /^WITH\s+CARRY\s*(.*)/i) {
597 $code[$address] |= 0x01_00_00_00;
600 "$0 : syntax error in $lineno : $_
601 WITH CARRY option is incompatible with the $op operator.
606 if ($rest !~ /^\s*$/) {
608 "$0 : syntax error in $lineno : $_
609 Expected end of line, got $rest
613 print STDERR "source = $src_reg, data = $data8 , destination = $dst_reg\n"
615 # Note that Move data8 to reg is encoded as a read-modify-write
617 if (($src_reg eq undef) || ($src_reg eq $dst_reg)) {
618 $code[$address] |= 0x38_00_00_00 |
619 ($registers{$dst_reg} << 16);
620 } elsif ($dst_reg =~ /SFBR/i) {
621 $code[$address] |= 0x30_00_00_00 |
622 ($registers{$src_reg} << 16);
623 } elsif ($src_reg =~ /SFBR/i) {
624 $code[$address] |= 0x28_00_00_00 |
625 ($registers{$dst_reg} << 16);
628 "$0 : Illegal combination of registers in line $lineno : $_
629 Either source and destination registers must be the same,
630 or either source or destination register must be SFBR.
634 $code[$address] |= $operators{$op};
636 &parse_value ($data8, 0, 1, 1);
637 $code[$address] |= $operators{$op};
638 $code[$address + 1] = 0x00_00_00_00;# Reserved
642 "$0 : syntax error in line $lineno : $_
643 expected (initiator) <length>, <address>, WHEN <phase>
644 (target) <length>, <address>, WITH <phase>
645 MEMORY <length>, <source>, <destination>
646 <expression> TO <register>
649 # Process SELECT {ATN|} id, fail_address
650 } elsif (/^\s*(SELECT|RESELECT)\s+(.*)/i) {
652 if ($rest =~ /^(ATN|)\s*($value)\s*,\s*($identifier)\s*$/i) {
656 $code[$address] = 0x40_00_00_00 |
657 (($atn =~ /ATN/i) ? 0x01_00_00_00 : 0);
658 $code[$address + 1] = 0x00_00_00_00;
659 &parse_value($id, 0, 2, 1);
660 &parse_value($alt_addr, 1, 0, 4);
662 } elsif ($rest =~ /^(ATN|)\s*FROM\s+($value)\s*,\s*($identifier)\s*$/i) {
666 $code[$address] = 0x42_00_00_00 |
667 (($atn =~ /ATN/i) ? 0x01_00_00_00 : 0);
668 $code[$address + 1] = 0x00_00_00_00;
669 &parse_value($addr, 0, 0, 3);
670 &parse_value($alt_addr, 1, 0, 4);
674 "$0 : syntax error in line $lineno : $_
675 expected SELECT id, alternate_address or
676 SELECT FROM address, alternate_address or
677 RESELECT id, alternate_address or
678 RESELECT FROM address, alternate_address
681 } elsif (/^\s*WAIT\s+(.*)/i) {
683 print STDERR "Parsing WAIT $rest\n" if ($debug);
684 if ($rest =~ /^DISCONNECT\s*$/i) {
685 $code[$address] = 0x48_00_00_00;
686 $code[$address + 1] = 0x00_00_00_00;
688 } elsif ($rest =~ /^(RESELECT|SELECT)\s+($identifier)\s*$/i) {
690 $code[$address] = 0x50_00_00_00;
691 &parse_value ($alt_addr, 1, 0, 4);
695 "$0 : syntax error in line $lineno : $_
696 expected (initiator) WAIT DISCONNECT or
697 (initiator) WAIT RESELECT alternate_address or
698 (target) WAIT SELECT alternate_address
701 # Handle SET and CLEAR instructions. Note that we should also do something
702 # with this syntax to set target mode.
703 } elsif (/^\s*(SET|CLEAR)\s+(.*)/i) {
706 $code[$address] = ($set =~ /SET/i) ? 0x58_00_00_00 :
708 foreach $arg (split (/\s+AND\s+/i,$list)) {
709 if ($arg =~ /ATN/i) {
710 $code[$address] |= 0x00_00_00_08;
711 } elsif ($arg =~ /ACK/i) {
712 $code[$address] |= 0x00_00_00_40;
713 } elsif ($arg =~ /TARGET/i) {
714 $code[$address] |= 0x00_00_02_00;
715 } elsif ($arg =~ /CARRY/i) {
716 $code[$address] |= 0x00_00_04_00;
719 "$0 : syntax error in line $lineno : $_
720 expected $set followed by a AND delimited list of one or
721 more strings from the list ACK, ATN, CARRY, TARGET.
725 $code[$address + 1] = 0x00_00_00_00;
727 } elsif (/^\s*(JUMP|CALL|INT)\s+(.*)/i) {
730 if ($instruction =~ /JUMP/i) {
731 $code[$address] = 0x80_00_00_00;
732 } elsif ($instruction =~ /CALL/i) {
733 $code[$address] = 0x88_00_00_00;
735 $code[$address] = 0x98_00_00_00;
737 print STDERR "parsing JUMP, rest = $rest\n" if ($debug);
740 if ($rest =~ /^(REL\s*\(\s*$identifier\s*\))\s*(.*)/i) {
743 print STDERR "parsing JUMP REL, addr = $addr, rest = $rest\n" if ($debug);
744 $code[$address] |= 0x00_80_00_00;
745 &parse_value($addr, 1, 0, 4);
746 # Absolute jump, requires no more gunk
747 } elsif ($rest =~ /^($value)\s*(.*)/) {
750 &parse_value($addr, 1, 0, 4);
753 "$0 : syntax error in line $lineno : $_
754 expected <address> or REL (address)
758 if ($rest =~ /^,\s*(.*)/) {
759 &parse_conditional($1);
760 } elsif ($rest =~ /^\s*$/) {
761 $code[$address] |= (1 << 19);
764 "$0 : syntax error in line $lineno : $_
765 expected , <conditional> or end of line, got $1
770 } elsif (/^\s*(RETURN|INTFLY)\s*(.*)/i) {
773 print STDERR "Parsing $instruction\n" if ($debug);
774 $code[$address] = ($instruction =~ /RETURN/i) ? 0x90_00_00_00 :
776 if ($conditional =~ /^,\s*(.*)/) {
778 &parse_conditional ($conditional);
779 } elsif ($conditional !~ /^\s*$/) {
781 "$0 : syntax error in line $lineno : $_
782 expected , <conditional>
785 $code[$address] |= 0x00_08_00_00;
788 $code[$address + 1] = 0x00_00_00_00;
790 } elsif (/^\s*DISCONNECT\s*$/) {
791 $code[$address] = 0x48_00_00_00;
792 $code[$address + 1] = 0x00_00_00_00;
794 # I'm not sure that I should be including this extension, but
796 } elsif (/^\s*NOP\s*$/i) {
797 $code[$address] = 0x80_88_00_00;
798 $code[$address + 1] = 0x00_00_00_00;
800 # Ignore lines consisting entirely of white space
804 "$0 : syntax error in line $lineno: $_
805 expected label:, ABSOLUTE, CLEAR, DISCONNECT, EXTERNAL, MOVE, RESELECT,
811 # Fill in label references
813 @undefined = keys %forward;
814 if ($#undefined >= 0) {
815 print STDERR "Undefined symbols : \n";
816 foreach $undef (@undefined) {
817 print STDERR "$undef in $forward{$undef}\n";
824 @external_patches = ();
826 @absolute = sort @absolute;
828 foreach $i (@absolute) {
829 foreach $j (split (/\s+/,$symbol_references{$i})) {
830 $j =~ /(REL|ABS),(.*),(.*)/;
835 "$0 : $symbol $i has illegal relative reference at address $address,
839 &patch ($address / 4, $address % 4, $length, $symbol_values{$i});
843 foreach $external (@external) {
844 print STDERR "checking external $external \n" if ($debug_external);
845 if ($symbol_references{$external} ne undef) {
846 for $reference (split(/\s+/,$symbol_references{$external})) {
847 $reference =~ /(REL|ABS),(.*),(.*)/;
853 "$0 : symbol $label is external, has illegal relative reference at $address,
858 "$0 : symbol $label has illegal reference at $address, size $length\n"
859 if ((($address % 4) !=0) || ($length != 4));
861 $symbol = $symbol_values{$external};
862 $add = $code[$address / 4];
864 $code[$address / 4] = $symbol;
866 $add = sprintf ("0x%08x", $add);
867 $code[$address / 4] = "$symbol + $add";
870 print STDERR "referenced external $external at $1\n" if ($debug_external);
875 foreach $label (@label) {
876 if ($symbol_references{$label} ne undef) {
877 for $reference (split(/\s+/,$symbol_references{$label})) {
878 $reference =~ /(REL|ABS),(.*),(.*)/;
883 if ((($address % 4) !=0) || ($length != 4)) {
884 die "$0 : symbol $label has illegal reference at $1, size $2\n";
887 if ($type eq 'ABS') {
888 $code[$address / 4] += $symbol_values{$label};
889 push (@label_patches, $address / 4);
892 # - The address of the reference should be in the second and last word
894 # - Relative jumps, etc. are relative to the DSP of the _next_ instruction
896 # So, we need to add four to the address of the reference, to get
897 # the address of the next instruction, when computing the reference.
899 $tmp = $symbol_values{$label} -
902 # Relative addressing is limited to 24 bits.
903 "$0 : symbol $label is too far ($tmp) from $address to reference as
904 relative/\n" if (($tmp >= 0x80_00_00) || ($tmp < -0x80_00_00));
905 $code[$address / 4] = $tmp & 0x00_ff_ff_ff;
911 # Output SCRIPT[] array, one instruction per line. Optionally
912 # print the original code too.
914 open (OUTPUT, ">$output") || die "$0 : can't open $output for writing\n";
915 open (OUTPUTU, ">$outputu") || die "$0 : can't open $outputu for writing\n";
917 print OUTPUT "/* DO NOT EDIT - Generated automatically by ".$0." */\n";
918 print OUTPUT "static u32 ".$prefix."SCRIPT[] = {\n";
920 for ($i = 0; $i < $#code; ) {
921 if ($list_in_array) {
922 printf OUTPUT "/*\n$list[$i]\nat 0x%08x : */", $i;
924 printf OUTPUT "\t0x%08x,", $code[$i];
925 printf STDERR "Address $i = %x\n", $code[$i] if ($debug);
926 if ($code[$i + 1] =~ /\s*($identifier)(.*)$/) {
927 push (@external_patches, $i+1, $1);
928 printf OUTPUT "0%s,", $2
930 printf OUTPUT "0x%08x,",$code[$i+1];
933 if (($code[$i] & 0xff_00_00_00) == 0xc0_00_00_00) {
934 if ($code[$i + 2] =~ /$identifier/) {
935 push (@external_patches, $i+2, $code[$i+2]);
936 printf OUTPUT "0,\n";
938 printf OUTPUT "0x%08x,\n",$code[$i+2];
947 print OUTPUT "};\n\n";
949 foreach $i (@absolute) {
950 printf OUTPUT "#define A_$i\t0x%08x\n", $symbol_values{$i};
951 if (defined($prefix) && $prefix ne '') {
952 printf OUTPUT "#define A_".$i."_used ".$prefix."A_".$i."_used\n";
953 printf OUTPUTU "#undef A_".$i."_used\n";
955 printf OUTPUTU "#undef A_$i\n";
957 printf OUTPUT "static u32 A_".$i."_used\[\] __attribute((unused)) = {\n";
958 printf STDERR "$i is used $symbol_references{$i}\n" if ($debug);
959 foreach $j (split (/\s+/,$symbol_references{$i})) {
960 $j =~ /(ABS|REL),(.*),(.*)/;
964 printf OUTPUT "\t0x%08x,\n", $address / 4;
967 printf OUTPUT "};\n\n";
970 foreach $i (sort @entry) {
971 printf OUTPUT "#define Ent_$i\t0x%08x\n", $symbol_values{$i};
972 printf OUTPUTU "#undef Ent_$i\n", $symbol_values{$i};
976 # NCR assembler outputs label patches in the form of indices into
979 printf OUTPUT "static u32 ".$prefix."LABELPATCHES[] __attribute((unused)) = {\n";
980 for $patch (sort {$a <=> $b} @label_patches) {
981 printf OUTPUT "\t0x%08x,\n", $patch;
983 printf OUTPUT "};\n\n";
985 $num_external_patches = 0;
986 printf OUTPUT "static struct {\n\tu32\toffset;\n\tvoid\t\t*address;\n".
987 "} ".$prefix."EXTERNAL_PATCHES[] __attribute((unused)) = {\n";
988 while ($ident = pop(@external_patches)) {
989 $off = pop(@external_patches);
990 printf OUTPUT "\t{0x%08x, &%s},\n", $off, $ident;
991 ++$num_external_patches;
993 printf OUTPUT "};\n\n";
995 printf OUTPUT "static u32 ".$prefix."INSTRUCTIONS __attribute((unused))\t= %d;\n",
997 printf OUTPUT "static u32 ".$prefix."PATCHES __attribute((unused))\t= %d;\n",
999 printf OUTPUT "static u32 ".$prefix."EXTERNAL_PATCHES_LEN __attribute((unused))\t= %d;\n",
1000 $num_external_patches;