home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / drivers / scsi / script_asm.pl < prev    next >
Encoding:
Perl Script  |  1995-02-06  |  26.6 KB  |  928 lines

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