Back to home page

OSCL-LXR

 
 

    


0001 #!/usr/bin/perl -s
0002 # SPDX-License-Identifier: GPL-2.0-or-later
0003 
0004 # NCR 53c810 script assembler
0005 # Sponsored by 
0006 #       iX Multiuser Multitasking Magazine
0007 #
0008 # Copyright 1993, Drew Eckhardt
0009 #      Visionary Computing 
0010 #      (Unix and Linux consulting and custom programming)
0011 #      drew@Colorado.EDU
0012 #      +1 (303) 786-7975 
0013 #
0014 #   Support for 53c710 (via -ncr7x0_family switch) added by Richard
0015 #   Hirst <richard@sleepie.demon.co.uk> - 15th March 1997
0016 #
0017 # TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
0018 #
0019 
0020 # 
0021 # Basically, I follow the NCR syntax documented in the NCR53c710 
0022 # Programmer's guide, with the new instructions, registers, etc.
0023 # from the NCR53c810.
0024 #
0025 # Differences between this assembler and NCR's are that 
0026 # 1.  PASS, REL (data, JUMPs work fine), and the option to start a new 
0027 #   script,  are unimplemented, since I didn't use them in my scripts.
0028 # 
0029 # 2.  I also emit a script_u.h file, which will undefine all of 
0030 #   the A_*, E_*, etc. symbols defined in the script.  This 
0031 #   makes including multiple scripts in one program easier
0032 #   
0033 # 3.  This is a single pass assembler, which only emits 
0034 #   .h files.
0035 #
0036 
0037 
0038 # XXX - set these with command line options
0039 $debug = 0;     # Print general debugging messages
0040 $debug_external = 0;    # Print external/forward reference messages
0041 $list_in_array = 1; # Emit original SCRIPTS assembler in comments in
0042             # script.h
0043 #$prefix;       # (set by perl -s)
0044                         # define all arrays having this prefix so we 
0045             # don't have name space collisions after 
0046             # assembling this file in different ways for
0047             # different host adapters
0048 
0049 # Constants
0050 
0051 
0052 # Table of the SCSI phase encodings
0053 %scsi_phases = (            
0054     'DATA_OUT', 0x00_00_00_00, 'DATA_IN', 0x01_00_00_00, 'CMD', 0x02_00_00_00,
0055     'STATUS', 0x03_00_00_00, 'MSG_OUT', 0x06_00_00_00, 'MSG_IN', 0x07_00_00_00
0056 );
0057 
0058 # XXX - replace references to the *_810 constants with general constants
0059 # assigned at compile time based on chip type.
0060 
0061 # Table of operator encodings
0062 # XXX - NCR53c710 only implements 
0063 #   move (nop) = 0x00_00_00_00
0064 #   or = 0x02_00_00_00
0065 #   and = 0x04_00_00_00
0066 #   add = 0x06_00_00_00
0067 
0068 if ($ncr7x0_family) {
0069   %operators = (
0070     '|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
0071     '&', 0x04_00_00_00, 'AND', 0x04_00_00_00,
0072     '+', 0x06_00_00_00
0073   );
0074 }
0075 else {
0076   %operators = (
0077     'SHL',  0x01_00_00_00, 
0078     '|', 0x02_00_00_00, 'OR', 0x02_00_00_00, 
0079     'XOR', 0x03_00_00_00, 
0080     '&', 0x04_00_00_00, 'AND', 0x04_00_00_00, 
0081     'SHR', 0x05_00_00_00, 
0082     # Note : low bit of the operator bit should be set for add with 
0083     # carry.
0084     '+', 0x06_00_00_00 
0085   );
0086 }
0087 
0088 # Table of register addresses
0089 
0090 if ($ncr7x0_family) {
0091   %registers = (
0092     'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
0093     'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
0094     'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11,
0095     'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
0096     'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
0097     'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23,
0098     'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27,
0099     'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
0100     'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34, 'LCRC', 35,
0101     'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
0102     'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
0103     'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
0104     'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
0105     'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
0106     'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
0107     'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
0108   );
0109 }
0110 else {
0111   %registers = (
0112     'SCNTL0', 0, 'SCNTL1', 1, 'SCNTL2', 2, 'SCNTL3', 3,
0113     'SCID', 4, 'SXFER', 5, 'SDID', 6, 'GPREG', 7,
0114     'SFBR', 8, 'SOCL', 9, 'SSID', 10, 'SBCL', 11,
0115     'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
0116     'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
0117     'ISTAT', 20,
0118     'CTEST0', 24, 'CTEST1', 25, 'CTEST2', 26, 'CTEST3', 27,
0119     'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
0120     'DFIFO', 32, 'CTEST4', 33, 'CTEST5', 34, 'CTEST6', 35,
0121     'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
0122     'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
0123     'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
0124     'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
0125     'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
0126     'SCRATCHA0', 52, 'SCRATCHA1', 53, 'SCRATCHA2', 54, 'SCRATCHA3', 55,
0127     'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
0128     'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
0129     'SIEN0', 64, 'SIEN1', 65, 'SIST0', 66, 'SIST1', 67,
0130     'SLPAR', 68,          'MACNTL', 70, 'GPCNTL', 71,
0131     'STIME0', 72, 'STIME1', 73, 'RESPID', 74, 
0132     'STEST0', 76, 'STEST1', 77, 'STEST2', 78, 'STEST3', 79,
0133     'SIDL', 80,
0134     'SODL', 84,
0135     'SBDL', 88,
0136     'SCRATCHB0', 92, 'SCRATCHB1', 93, 'SCRATCHB2', 94, 'SCRATCHB3', 95
0137   );
0138 }
0139 
0140 # Parsing regular expressions
0141 $identifier = '[A-Za-z_][A-Za-z_0-9]*';     
0142 $decnum = '-?\\d+';
0143 $hexnum = '0[xX][0-9A-Fa-f]+';      
0144 $constant = "$hexnum|$decnum";
0145 
0146 # yucky - since we can't control grouping of # $constant, we need to 
0147 # expand out each alternative for $value.
0148 
0149 $value = "$identifier|$identifier\\s*[+\-]\\s*$decnum|".
0150     "$identifier\\s*[+-]\s*$hexnum|$constant";
0151 
0152 print STDERR "value regex = $value\n" if ($debug);
0153 
0154 $phase = join ('|', keys %scsi_phases);
0155 print STDERR "phase regex = $phase\n" if ($debug);
0156 $register = join ('|', keys %registers);
0157 
0158 # yucky - since %operators includes meta-characters which must
0159 # be escaped, I can't use the join() trick I used for the register
0160 # regex
0161 
0162 if ($ncr7x0_family) {
0163   $operator = '\||OR|AND|\&|\+';
0164 }
0165 else {
0166   $operator = '\||OR|AND|XOR|\&|\+';
0167 }
0168 
0169 # Global variables
0170 
0171 %symbol_values = (%registers) ;     # Traditional symbol table
0172 
0173 %symbol_references = () ;       # Table of symbol references, where
0174                     # the index is the symbol name, 
0175                     # and the contents a white space 
0176                     # delimited list of address,size
0177                     # tuples where size is in bytes.
0178 
0179 @code = ();             # Array of 32 bit words for SIOP 
0180 
0181 @entry = ();                # Array of entry point names
0182 
0183 @label = ();                # Array of label names
0184 
0185 @absolute = ();             # Array of absolute names
0186 
0187 @relative = ();             # Array of relative names
0188 
0189 @external = ();             # Array of external names
0190 
0191 $address = 0;               # Address of current instruction
0192 
0193 $lineno = 0;                # Line number we are parsing
0194 
0195 $output = 'script.h';           # Output file
0196 $outputu = 'scriptu.h';
0197 
0198 # &patch ($address, $offset, $length, $value) patches $code[$address]
0199 #   so that the $length bytes at $offset have $value added to
0200 #   them.  
0201 
0202 @inverted_masks = (0x00_00_00_00, 0x00_00_00_ff, 0x00_00_ff_ff, 0x00_ff_ff_ff, 
0203     0xff_ff_ff_ff);
0204 
0205 sub patch {
0206     local ($address, $offset, $length, $value) = @_;
0207     if ($debug) {
0208     print STDERR "Patching $address at offset $offset, length $length to $value\n";
0209     printf STDERR "Old code : %08x\n", $code[$address];
0210      }
0211 
0212     $mask = ($inverted_masks[$length] << ($offset * 8));
0213    
0214     $code[$address] = ($code[$address] & ~$mask) | 
0215     (($code[$address] & $mask) + ($value << ($offset * 8)) & 
0216     $mask);
0217     
0218     printf STDERR "New code : %08x\n", $code[$address] if ($debug);
0219 }
0220 
0221 # &parse_value($value, $word, $offset, $length) where $value is 
0222 #   an identifier or constant, $word is the word offset relative to 
0223 #   $address, $offset is the starting byte within that word, and 
0224 #   $length is the length of the field in bytes.
0225 #
0226 # Side effects are that the bytes are combined into the @code array
0227 #   relative to $address, and that the %symbol_references table is 
0228 #   updated as appropriate.
0229 
0230 sub parse_value {
0231     local ($value, $word, $offset, $length) = @_;
0232     local ($tmp);
0233 
0234     $symbol = '';
0235 
0236     if ($value =~ /^REL\s*\(\s*($identifier)\s*\)\s*(.*)/i) {
0237     $relative = 'REL';
0238     $symbol = $1;
0239     $value = $2;
0240 print STDERR "Relative reference $symbol\n" if ($debug);
0241     } elsif ($value =~ /^($identifier)\s*(.*)/) {
0242     $relative = 'ABS';
0243     $symbol = $1;
0244     $value = $2;
0245 print STDERR "Absolute reference $symbol\n" if ($debug);
0246     } 
0247 
0248     if ($symbol ne '') {
0249 print STDERR "Referencing symbol $1, length = $length in $_\n" if ($debug);
0250         $tmp = ($address + $word) * 4 + $offset;
0251     if ($symbol_references{$symbol} ne undef) {
0252         $symbol_references{$symbol} = 
0253         "$symbol_references{$symbol} $relative,$tmp,$length";
0254     } else {
0255         if (!defined($symbol_values{$symbol})) {
0256 print STDERR "forward $1\n" if ($debug_external);
0257         $forward{$symbol} = "line $lineno : $_";
0258         } 
0259         $symbol_references{$symbol} = "$relative,$tmp,$length";
0260     }
0261     } 
0262 
0263     $value = eval $value;
0264     &patch ($address + $word, $offset, $length, $value);
0265 }
0266 
0267 # &parse_conditional ($conditional) where $conditional is the conditional
0268 # clause from a transfer control instruction (RETURN, CALL, JUMP, INT).
0269 
0270 sub parse_conditional {
0271     local ($conditional) = @_;
0272     if ($conditional =~ /^\s*(IF|WHEN)\s*(.*)/i) {
0273     $if = $1;
0274     $conditional = $2;
0275     if ($if =~ /WHEN/i) {
0276         $allow_atn = 0;
0277         $code[$address] |= 0x00_01_00_00;
0278         $allow_atn = 0;
0279         print STDERR "$0 : parsed WHEN\n" if ($debug);
0280     } else {
0281         $allow_atn = 1;
0282         print STDERR "$0 : parsed IF\n" if ($debug);
0283     }
0284     } else {
0285         die "$0 : syntax error in line $lineno : $_
0286     expected IF or WHEN
0287 ";
0288     }
0289 
0290     if ($conditional =~ /^NOT\s+(.*)$/i) {
0291     $not = 'NOT ';
0292     $other = 'OR';
0293     $conditional = $1;
0294     print STDERR "$0 : parsed NOT\n" if ($debug);
0295     } else {
0296     $code[$address] |= 0x00_08_00_00;
0297     $not = '';
0298     $other = 'AND'
0299     }
0300 
0301     $need_data = 0;
0302     if ($conditional =~ /^ATN\s*(.*)/i) {#
0303     die "$0 : syntax error in line $lineno : $_
0304     WHEN conditional is incompatible with ATN 
0305 " if (!$allow_atn);
0306     $code[$address] |= 0x00_02_00_00;
0307     $conditional = $1;
0308     print STDERR "$0 : parsed ATN\n" if ($debug);
0309     } elsif ($conditional =~ /^($phase)\s*(.*)/i) {
0310     $phase_index = "\U$1\E";
0311     $p = $scsi_phases{$phase_index};
0312     $code[$address] |= $p | 0x00_02_00_00;
0313     $conditional = $2;
0314     print STDERR "$0 : parsed phase $phase_index\n" if ($debug);
0315     } else {
0316     $other = '';
0317     $need_data = 1;
0318     }
0319 
0320 print STDERR "Parsing conjunction, expecting $other\n" if ($debug);
0321     if ($conditional =~ /^(AND|OR)\s*(.*)/i) {
0322     $conjunction = $1;
0323     $conditional = $2;
0324     $need_data = 1;
0325     die "$0 : syntax error in line $lineno : $_
0326         Illegal use of $1.  Valid uses are 
0327         ".$not."<phase> $1 data
0328         ".$not."ATN $1 data
0329 " if ($other eq '');
0330     die "$0 : syntax error in line $lineno : $_
0331     Illegal use of $conjunction.  Valid syntaxes are 
0332         NOT <phase>|ATN OR data
0333         <phase>|ATN AND data
0334 " if ($conjunction !~ /\s*$other\s*/i);
0335     print STDERR "$0 : parsed $1\n" if ($debug);
0336     }
0337 
0338     if ($need_data) {
0339 print STDERR "looking for data in $conditional\n" if ($debug);
0340     if ($conditional=~ /^($value)\s*(.*)/i) {
0341         $code[$address] |= 0x00_04_00_00;
0342         $conditional = $2;
0343         &parse_value($1, 0, 0, 1);
0344         print STDERR "$0 : parsed data\n" if ($debug);
0345     } else {
0346     die "$0 : syntax error in line $lineno : $_
0347     expected <data>.
0348 ";
0349     }
0350     }
0351 
0352     if ($conditional =~ /^\s*,\s*(.*)/) {
0353     $conditional = $1;
0354     if ($conditional =~ /^AND\s\s*MASK\s\s*($value)\s*(.*)/i) {
0355         &parse_value ($1, 0, 1, 1);
0356         print STDERR "$0 parsed AND MASK $1\n" if ($debug);
0357         die "$0 : syntax error in line $lineno : $_
0358     expected end of line, not \"$2\"
0359 " if ($2 ne '');
0360     } else {
0361         die "$0 : syntax error in line $lineno : $_
0362     expected \",AND MASK <data>\", not \"$2\"
0363 ";
0364     }
0365     } elsif ($conditional !~ /^\s*$/) { 
0366     die "$0 : syntax error in line $lineno : $_
0367     expected end of line" . (($need_data) ? " or \"AND MASK <data>\"" : "") . "
0368     not \"$conditional\"
0369 ";
0370     }
0371 }
0372 
0373 # Parse command line
0374 $output = shift;
0375 $outputu = shift;
0376 
0377     
0378 # Main loop
0379 while (<STDIN>) {
0380     $lineno = $lineno + 1;
0381     $list[$address] = $list[$address].$_;
0382     s/;.*$//;               # Strip comments
0383 
0384 
0385     chop;               # Leave new line out of error messages
0386 
0387 # Handle symbol definitions of the form label:
0388     if (/^\s*($identifier)\s*:(.*)/) {
0389     if (!defined($symbol_values{$1})) {
0390         $symbol_values{$1} = $address * 4;  # Address is an index into
0391         delete $forward{$1};        # an array of longs
0392         push (@label, $1);
0393         $_ = $2;
0394     } else {
0395         die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
0396     }
0397     }
0398 
0399 # Handle symbol definitions of the form ABSOLUTE or RELATIVE identifier = 
0400 # value
0401     if (/^\s*(ABSOLUTE|RELATIVE)\s+(.*)/i) {
0402     $is_absolute = $1;
0403     $rest = $2;
0404     foreach $rest (split (/\s*,\s*/, $rest)) {
0405         if ($rest =~ /^($identifier)\s*=\s*($constant)\s*$/) {
0406             local ($id, $cnst) = ($1, $2);
0407         if ($symbol_values{$id} eq undef) {
0408             $symbol_values{$id} = eval $cnst;
0409             delete $forward{$id};
0410             if ($is_absolute =~ /ABSOLUTE/i) {
0411             push (@absolute , $id);
0412             } else {
0413             push (@relative, $id);
0414             }
0415         } else {
0416             die "$0 : redefinition of symbol $id in line $lineno : $_\n";
0417         }
0418         } else {
0419         die 
0420 "$0 : syntax error in line $lineno : $_
0421         expected <identifier> = <value>
0422 ";
0423         }
0424     }
0425     } elsif (/^\s*EXTERNAL\s+(.*)/i) {
0426     $externals = $1;
0427     foreach $external (split (/,/,$externals)) {
0428         if ($external =~ /\s*($identifier)\s*$/) {
0429         $external = $1;
0430         push (@external, $external);
0431         delete $forward{$external};
0432         if (defined($symbol_values{$external})) {
0433             die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
0434         }
0435         $symbol_values{$external} = $external;
0436 print STDERR "defined external $1 to $external\n" if ($debug_external);
0437         } else {
0438         die 
0439 "$0 : syntax error in line $lineno : $_
0440     expected <identifier>, got $external
0441 ";
0442         }
0443     }
0444 # Process ENTRY identifier declarations
0445     } elsif (/^\s*ENTRY\s+(.*)/i) {
0446     if ($1 =~ /^($identifier)\s*$/) {
0447         push (@entry, $1);
0448     } else {
0449         die
0450 "$0 : syntax error in line $lineno : $_
0451     expected ENTRY <identifier>
0452 ";
0453     }
0454 # Process MOVE length, address, WITH|WHEN phase instruction
0455     } elsif (/^\s*MOVE\s+(.*)/i) {
0456     $rest = $1;
0457     if ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
0458         $transfer_addr = $1;
0459         $with_when = $2;
0460         $scsi_phase = $3;
0461 print STDERR "Parsing MOVE FROM $transfer_addr, $with_when $3\n" if ($debug);
0462         $code[$address] = 0x18_00_00_00 | (($with_when =~ /WITH/i) ? 
0463         0x00_00_00_00 : 0x08_00_00_00) | $scsi_phases{$scsi_phase};
0464         &parse_value ($transfer_addr, 1, 0, 4);
0465         $address += 2;
0466     } elsif ($rest =~ /^($value)\s*,\s*(PTR\s+|)($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
0467         $transfer_len = $1;
0468         $ptr = $2;
0469         $transfer_addr = $3;
0470         $with_when = $4;
0471         $scsi_phase = $5;
0472         $code[$address] = (($with_when =~ /WITH/i) ? 0x00_00_00_00 : 
0473         0x08_00_00_00)  | (($ptr =~ /PTR/i) ? (1 << 29) : 0) | 
0474         $scsi_phases{$scsi_phase};
0475         &parse_value ($transfer_len, 0, 0, 3);
0476         &parse_value ($transfer_addr, 1, 0, 4);
0477         $address += 2;
0478     } elsif ($rest =~ /^MEMORY\s+(.*)/i) {
0479         $rest = $1;
0480         $code[$address] = 0xc0_00_00_00; 
0481         if ($rest =~ /^($value)\s*,\s*($value)\s*,\s*($value)\s*$/) {
0482         $count = $1;
0483         $source = $2;
0484         $dest =  $3;
0485 print STDERR "Parsing MOVE MEMORY $count, $source, $dest\n" if ($debug);
0486         &parse_value ($count, 0, 0, 3);
0487         &parse_value ($source, 1, 0, 4);
0488         &parse_value ($dest, 2, 0, 4);
0489 printf STDERR "Move memory instruction = %08x,%08x,%08x\n", 
0490         $code[$address], $code[$address+1], $code[$address +2] if
0491         ($debug);
0492         $address += 3;
0493     
0494         } else {
0495         die 
0496 "$0 : syntax error in line $lineno : $_
0497     expected <count>, <source>, <destination>
0498 "
0499         }
0500     } elsif ($1 =~ /^(.*)\s+(TO|SHL|SHR)\s+(.*)/i) {
0501 print STDERR "Parsing register to register move\n" if ($debug);
0502         $src = $1;
0503         $op = "\U$2\E";
0504         $rest = $3;
0505 
0506         $code[$address] = 0x40_00_00_00;
0507     
0508         $force = ($op !~ /TO/i); 
0509 
0510 
0511 print STDERR "Forcing register source \n" if ($force && $debug);
0512 
0513         if (!$force && $src =~ 
0514         /^($register)\s+(-|$operator)\s+($value)\s*$/i) {
0515 print STDERR "register operand  data8 source\n" if ($debug);
0516         $src_reg = "\U$1\E";
0517         $op = "\U$2\E";
0518         if ($op ne '-') {
0519             $data8 = $3;
0520         } else {
0521             die "- is not implemented yet.\n"
0522         }
0523         } elsif ($src =~ /^($register)\s*$/i) {
0524 print STDERR "register source\n" if ($debug);
0525         $src_reg = "\U$1\E";
0526         # Encode register to register move as a register | 0 
0527         # move to register.
0528         if (!$force) {
0529             $op = '|';
0530         }
0531         $data8 = 0;
0532         } elsif (!$force && $src =~ /^($value)\s*$/i) {
0533 print STDERR "data8 source\n" if ($debug);
0534         $src_reg = undef;
0535         $op = 'NONE';
0536         $data8 = $1;
0537         } else {
0538         if (!$force) {
0539             die 
0540 "$0 : syntax error in line $lineno : $_
0541     expected <register>
0542         <data8>
0543         <register> <operand> <data8>
0544 ";
0545         } else {
0546             die
0547 "$0 : syntax error in line $lineno : $_
0548     expected <register>
0549 ";
0550         }
0551         }
0552         if ($rest =~ /^($register)\s*(.*)$/i) {
0553         $dst_reg = "\U$1\E";
0554         $rest = $2;
0555         } else {
0556         die 
0557 "$0 : syntax error in $lineno : $_
0558     expected <register>, got $rest
0559 ";
0560         }
0561 
0562         if ($rest =~ /^WITH\s+CARRY\s*(.*)/i) {
0563         $rest = $1;
0564         if ($op eq '+') {
0565             $code[$address] |= 0x01_00_00_00;
0566         } else {
0567             die
0568 "$0 : syntax error in $lineno : $_
0569     WITH CARRY option is incompatible with the $op operator.
0570 ";
0571         }
0572         }
0573 
0574         if ($rest !~ /^\s*$/) {
0575         die
0576 "$0 : syntax error in $lineno : $_
0577     Expected end of line, got $rest
0578 ";
0579         }
0580 
0581         print STDERR "source = $src_reg, data = $data8 , destination = $dst_reg\n"
0582         if ($debug);
0583         # Note that Move data8 to reg is encoded as a read-modify-write
0584         # instruction.
0585         if (($src_reg eq undef) || ($src_reg eq $dst_reg)) {
0586         $code[$address] |= 0x38_00_00_00 | 
0587             ($registers{$dst_reg} << 16);
0588         } elsif ($dst_reg =~ /SFBR/i) {
0589         $code[$address] |= 0x30_00_00_00 |
0590             ($registers{$src_reg} << 16);
0591         } elsif ($src_reg =~ /SFBR/i) {
0592         $code[$address] |= 0x28_00_00_00 |
0593             ($registers{$dst_reg} << 16);
0594         } else {
0595         die
0596 "$0 : Illegal combination of registers in line $lineno : $_
0597     Either source and destination registers must be the same,
0598     or either source or destination register must be SFBR.
0599 ";
0600         }
0601 
0602         $code[$address] |= $operators{$op};
0603         
0604         &parse_value ($data8, 0, 1, 1);
0605         $code[$address] |= $operators{$op};
0606         $code[$address + 1] = 0x00_00_00_00;# Reserved
0607         $address += 2;
0608     } else {
0609         die 
0610 "$0 : syntax error in line $lineno : $_
0611     expected (initiator) <length>, <address>, WHEN <phase>
0612          (target) <length>, <address>, WITH <phase>
0613          MEMORY <length>, <source>, <destination>
0614          <expression> TO <register>
0615 ";
0616     }
0617 # Process SELECT {ATN|} id, fail_address
0618     } elsif (/^\s*(SELECT|RESELECT)\s+(.*)/i) {
0619     $rest = $2;
0620     if ($rest =~ /^(ATN|)\s*($value)\s*,\s*($identifier)\s*$/i) {
0621         $atn = $1;
0622         $id = $2;
0623         $alt_addr = $3;
0624         $code[$address] = 0x40_00_00_00 | 
0625         (($atn =~ /ATN/i) ? 0x01_00_00_00 : 0);
0626         $code[$address + 1] = 0x00_00_00_00;
0627         &parse_value($id, 0, 2, 1);
0628         &parse_value($alt_addr, 1, 0, 4);
0629         $address += 2;
0630     } elsif ($rest =~ /^(ATN|)\s*FROM\s+($value)\s*,\s*($identifier)\s*$/i) {
0631         $atn = $1;
0632         $addr = $2;
0633         $alt_addr = $3;
0634         $code[$address] = 0x42_00_00_00 | 
0635         (($atn =~ /ATN/i) ? 0x01_00_00_00 : 0);
0636         $code[$address + 1] = 0x00_00_00_00;
0637         &parse_value($addr, 0, 0, 3);
0638         &parse_value($alt_addr, 1, 0, 4);
0639         $address += 2;
0640         } else {
0641         die 
0642 "$0 : syntax error in line $lineno : $_
0643     expected SELECT id, alternate_address or 
0644         SELECT FROM address, alternate_address or 
0645         RESELECT id, alternate_address or
0646         RESELECT FROM address, alternate_address
0647 ";
0648     }
0649     } elsif (/^\s*WAIT\s+(.*)/i) {
0650         $rest = $1;
0651 print STDERR "Parsing WAIT $rest\n" if ($debug);
0652     if ($rest =~ /^DISCONNECT\s*$/i) {
0653         $code[$address] = 0x48_00_00_00;
0654         $code[$address + 1] = 0x00_00_00_00;
0655         $address += 2;
0656     } elsif ($rest =~ /^(RESELECT|SELECT)\s+($identifier)\s*$/i) {
0657         $alt_addr = $2;
0658         $code[$address] = 0x50_00_00_00;
0659         &parse_value ($alt_addr, 1, 0, 4);
0660         $address += 2;
0661     } else {
0662         die
0663 "$0 : syntax error in line $lineno : $_
0664     expected (initiator) WAIT DISCONNECT or 
0665          (initiator) WAIT RESELECT alternate_address or
0666          (target) WAIT SELECT alternate_address
0667 ";
0668     }
0669 # Handle SET and CLEAR instructions.  Note that we should also do something
0670 # with this syntax to set target mode.
0671     } elsif (/^\s*(SET|CLEAR)\s+(.*)/i) {
0672     $set = $1;
0673     $list = $2;
0674     $code[$address] = ($set =~ /SET/i) ?  0x58_00_00_00 : 
0675         0x60_00_00_00;
0676     foreach $arg (split (/\s+AND\s+/i,$list)) {
0677         if ($arg =~ /ATN/i) {
0678         $code[$address] |= 0x00_00_00_08;
0679         } elsif ($arg =~ /ACK/i) {
0680         $code[$address] |= 0x00_00_00_40;
0681         } elsif ($arg =~ /TARGET/i) {
0682         $code[$address] |= 0x00_00_02_00;
0683         } elsif ($arg =~ /CARRY/i) {
0684         $code[$address] |= 0x00_00_04_00;
0685         } else {
0686         die 
0687 "$0 : syntax error in line $lineno : $_
0688     expected $set followed by a AND delimited list of one or 
0689     more strings from the list ACK, ATN, CARRY, TARGET.
0690 ";
0691         }
0692     }
0693     $code[$address + 1] = 0x00_00_00_00;
0694     $address += 2;
0695     } elsif (/^\s*(JUMP|CALL|INT)\s+(.*)/i) {
0696     $instruction = $1;
0697     $rest = $2;
0698     if ($instruction =~ /JUMP/i) {
0699         $code[$address] = 0x80_00_00_00;
0700     } elsif ($instruction =~ /CALL/i) {
0701         $code[$address] = 0x88_00_00_00;
0702     } else {
0703         $code[$address] = 0x98_00_00_00;
0704     }
0705 print STDERR "parsing JUMP, rest = $rest\n" if ($debug);
0706 
0707 # Relative jump. 
0708     if ($rest =~ /^(REL\s*\(\s*$identifier\s*\))\s*(.*)/i) { 
0709         $addr = $1;
0710         $rest = $2;
0711 print STDERR "parsing JUMP REL, addr = $addr, rest = $rest\n" if ($debug);
0712         $code[$address]  |= 0x00_80_00_00;
0713         &parse_value($addr, 1, 0, 4);
0714 # Absolute jump, requires no more gunk
0715     } elsif ($rest =~ /^($value)\s*(.*)/) {
0716         $addr = $1;
0717         $rest = $2;
0718         &parse_value($addr, 1, 0, 4);
0719     } else {
0720         die
0721 "$0 : syntax error in line $lineno : $_
0722     expected <address> or REL (address)
0723 ";
0724     }
0725 
0726     if ($rest =~ /^,\s*(.*)/) {
0727         &parse_conditional($1);
0728     } elsif ($rest =~ /^\s*$/) {
0729         $code[$address] |= (1 << 19);
0730     } else {
0731         die
0732 "$0 : syntax error in line $lineno : $_
0733     expected , <conditional> or end of line, got $1
0734 ";
0735     }
0736     
0737     $address += 2;
0738     } elsif (/^\s*(RETURN|INTFLY)\s*(.*)/i) {
0739     $instruction = $1;
0740     $conditional = $2; 
0741 print STDERR "Parsing $instruction\n" if ($debug);
0742     $code[$address] = ($instruction =~ /RETURN/i) ? 0x90_00_00_00 :
0743         0x98_10_00_00;
0744     if ($conditional =~ /^,\s*(.*)/) {
0745         $conditional = $1;
0746         &parse_conditional ($conditional);
0747     } elsif ($conditional !~ /^\s*$/) {
0748         die
0749 "$0 : syntax error in line $lineno : $_
0750     expected , <conditional> 
0751 ";
0752     } else {
0753         $code[$address] |= 0x00_08_00_00;
0754     }
0755        
0756     $code[$address + 1] = 0x00_00_00_00;
0757     $address += 2;
0758     } elsif (/^\s*DISCONNECT\s*$/) {
0759     $code[$address] = 0x48_00_00_00;
0760     $code[$address + 1] = 0x00_00_00_00;
0761     $address += 2;
0762 # I'm not sure that I should be including this extension, but 
0763 # what the hell?
0764     } elsif (/^\s*NOP\s*$/i) {
0765     $code[$address] = 0x80_88_00_00;
0766     $code[$address + 1] = 0x00_00_00_00;
0767     $address += 2;
0768 # Ignore lines consisting entirely of white space
0769     } elsif (/^\s*$/) {
0770     } else {
0771     die 
0772 "$0 : syntax error in line $lineno: $_
0773     expected label:, ABSOLUTE, CLEAR, DISCONNECT, EXTERNAL, MOVE, RESELECT,
0774         SELECT SET, or WAIT
0775 ";
0776     }
0777 }
0778 
0779 # Fill in label references
0780 
0781 @undefined = keys %forward;
0782 if ($#undefined >= 0) {
0783     print STDERR "Undefined symbols : \n";
0784     foreach $undef (@undefined) {
0785     print STDERR "$undef in $forward{$undef}\n";
0786     }
0787     exit 1;
0788 }
0789 
0790 @label_patches = ();
0791 
0792 @external_patches = ();
0793 
0794 @absolute = sort @absolute;
0795 
0796 foreach $i (@absolute) {
0797     foreach $j (split (/\s+/,$symbol_references{$i})) {
0798     $j =~ /(REL|ABS),(.*),(.*)/;
0799     $type = $1;
0800     $address = $2;
0801     $length = $3;
0802     die 
0803 "$0 : $symbol $i has invalid relative reference at address $address,
0804     size $length\n"
0805     if ($type eq 'REL');
0806         
0807     &patch ($address / 4, $address % 4, $length, $symbol_values{$i});
0808     }
0809 }
0810 
0811 foreach $external (@external) {
0812 print STDERR "checking external $external \n" if ($debug_external);
0813     if ($symbol_references{$external} ne undef) {
0814     for $reference (split(/\s+/,$symbol_references{$external})) {
0815         $reference =~ /(REL|ABS),(.*),(.*)/;
0816         $type = $1;
0817         $address = $2;
0818         $length = $3;
0819         
0820         die 
0821 "$0 : symbol $label is external, has invalid relative reference at $address,
0822     size $length\n"
0823         if ($type eq 'REL');
0824 
0825         die 
0826 "$0 : symbol $label has invalid reference at $address, size $length\n"
0827         if ((($address % 4) !=0) || ($length != 4));
0828 
0829         $symbol = $symbol_values{$external};
0830         $add = $code[$address / 4];
0831         if ($add eq 0) {
0832         $code[$address / 4] = $symbol;
0833         } else {
0834         $add = sprintf ("0x%08x", $add);
0835         $code[$address / 4] = "$symbol + $add";
0836         }
0837         
0838 print STDERR "referenced external $external at $1\n" if ($debug_external);
0839     }
0840     }
0841 }
0842 
0843 foreach $label (@label) {
0844     if ($symbol_references{$label} ne undef) {
0845     for $reference (split(/\s+/,$symbol_references{$label})) {
0846         $reference =~ /(REL|ABS),(.*),(.*)/;
0847         $type = $1;
0848         $address = $2;
0849         $length = $3;
0850 
0851         if ((($address % 4) !=0) || ($length != 4)) {
0852         die "$0 : symbol $label has invalid reference at $1, size $2\n";
0853         }
0854 
0855         if ($type eq 'ABS') {
0856         $code[$address / 4] += $symbol_values{$label};
0857         push (@label_patches, $address / 4);
0858         } else {
0859 # 
0860 # - The address of the reference should be in the second and last word
0861 #   of an instruction
0862 # - Relative jumps, etc. are relative to the DSP of the _next_ instruction
0863 #
0864 # So, we need to add four to the address of the reference, to get 
0865 # the address of the next instruction, when computing the reference.
0866   
0867         $tmp = $symbol_values{$label} - 
0868             ($address + 4);
0869         die 
0870 # Relative addressing is limited to 24 bits.
0871 "$0 : symbol $label is too far ($tmp) from $address to reference as 
0872     relative/\n" if (($tmp >= 0x80_00_00) || ($tmp < -0x80_00_00));
0873         $code[$address / 4] = $tmp & 0x00_ff_ff_ff;
0874         }
0875     }
0876     }
0877 }
0878 
0879 # Output SCRIPT[] array, one instruction per line.  Optionally 
0880 # print the original code too.
0881 
0882 open (OUTPUT, ">$output") || die "$0 : can't open $output for writing\n";
0883 open (OUTPUTU, ">$outputu") || die "$0 : can't open $outputu for writing\n";
0884 
0885 ($_ = $0) =~ s:.*/::;
0886 print OUTPUT "/* DO NOT EDIT - Generated automatically by ".$_." */\n";
0887 print OUTPUT "static u32 ".$prefix."SCRIPT[] = {\n";
0888 $instructions = 0;
0889 for ($i = 0; $i < $#code; ) {
0890     if ($list_in_array) {
0891     printf OUTPUT "/*\n$list[$i]\nat 0x%08x : */", $i;
0892     }
0893     printf OUTPUT "\t0x%08x,", $code[$i];
0894     printf STDERR "Address $i = %x\n", $code[$i] if ($debug);
0895     if ($code[$i + 1] =~ /\s*($identifier)(.*)$/) {
0896     push (@external_patches, $i+1, $1);
0897     printf OUTPUT "0%s,", $2
0898     } else {
0899     printf OUTPUT "0x%08x,",$code[$i+1];
0900     }
0901 
0902     if (($code[$i] & 0xff_00_00_00) == 0xc0_00_00_00) {
0903     if ($code[$i + 2] =~ /$identifier/) {
0904         push (@external_patches, $i+2, $code[$i+2]);
0905         printf OUTPUT "0,\n";
0906     } else {
0907         printf OUTPUT "0x%08x,\n",$code[$i+2];
0908     }
0909     $i += 3;
0910     } else {
0911     printf OUTPUT "\n";
0912     $i += 2;
0913     }
0914     $instructions += 1;
0915 }
0916 print OUTPUT "};\n\n";
0917 
0918 foreach $i (@absolute) {
0919     printf OUTPUT "#define A_$i\t0x%08x\n", $symbol_values{$i};
0920     if (defined($prefix) && $prefix ne '') {
0921     printf OUTPUT "#define A_".$i."_used ".$prefix."A_".$i."_used\n";
0922     printf OUTPUTU "#undef A_".$i."_used\n";
0923     }
0924     printf OUTPUTU "#undef A_$i\n";
0925 
0926     printf OUTPUT "static u32 A_".$i."_used\[\] __attribute((unused)) = {\n";
0927 printf STDERR "$i is used $symbol_references{$i}\n" if ($debug);
0928     foreach $j (split (/\s+/,$symbol_references{$i})) {
0929     $j =~ /(ABS|REL),(.*),(.*)/;
0930     if ($1 eq 'ABS') {
0931         $address = $2;
0932         $length = $3;
0933         printf OUTPUT "\t0x%08x,\n", $address / 4;
0934     }
0935     }
0936     printf OUTPUT "};\n\n";
0937 }
0938 
0939 foreach $i (sort @entry) {
0940     printf OUTPUT "#define Ent_$i\t0x%08x\n", $symbol_values{$i};
0941     printf OUTPUTU "#undef Ent_$i\n", $symbol_values{$i};
0942 }
0943 
0944 #
0945 # NCR assembler outputs label patches in the form of indices into 
0946 # the code.
0947 #
0948 printf OUTPUT "static u32 ".$prefix."LABELPATCHES[] __attribute((unused)) = {\n";
0949 for $patch (sort {$a <=> $b} @label_patches) {
0950     printf OUTPUT "\t0x%08x,\n", $patch;
0951 }
0952 printf OUTPUT "};\n\n";
0953 
0954 $num_external_patches = 0;
0955 printf OUTPUT "static struct {\n\tu32\toffset;\n\tvoid\t\t*address;\n".
0956     "} ".$prefix."EXTERNAL_PATCHES[] __attribute((unused)) = {\n";
0957 while ($ident = pop(@external_patches)) {
0958     $off = pop(@external_patches);
0959     printf OUTPUT "\t{0x%08x, &%s},\n", $off, $ident;
0960     ++$num_external_patches;
0961 }
0962 printf OUTPUT "};\n\n";
0963 
0964 printf OUTPUT "static u32 ".$prefix."INSTRUCTIONS __attribute((unused))\t= %d;\n", 
0965     $instructions;
0966 printf OUTPUT "static u32 ".$prefix."PATCHES __attribute((unused))\t= %d;\n", 
0967     $#label_patches+1;
0968 printf OUTPUT "static u32 ".$prefix."EXTERNAL_PATCHES_LEN __attribute((unused))\t= %d;\n",
0969     $num_external_patches;
0970 close OUTPUT;
0971 close OUTPUTU;