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