script_asm.pl
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:29k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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