Linux Audio

Check our new training course

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