162306a36Sopenharmony_ci#!/usr/bin/perl -s
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0-or-later
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci# NCR 53c810 script assembler
562306a36Sopenharmony_ci# Sponsored by
662306a36Sopenharmony_ci#       iX Multiuser Multitasking Magazine
762306a36Sopenharmony_ci#
862306a36Sopenharmony_ci# Copyright 1993, Drew Eckhardt
962306a36Sopenharmony_ci#      Visionary Computing
1062306a36Sopenharmony_ci#      (Unix and Linux consulting and custom programming)
1162306a36Sopenharmony_ci#      drew@Colorado.EDU
1262306a36Sopenharmony_ci#      +1 (303) 786-7975
1362306a36Sopenharmony_ci#
1462306a36Sopenharmony_ci#   Support for 53c710 (via -ncr7x0_family switch) added by Richard
1562306a36Sopenharmony_ci#   Hirst <richard@sleepie.demon.co.uk> - 15th March 1997
1662306a36Sopenharmony_ci#
1762306a36Sopenharmony_ci# TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
1862306a36Sopenharmony_ci#
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#
2162306a36Sopenharmony_ci# Basically, I follow the NCR syntax documented in the NCR53c710
2262306a36Sopenharmony_ci# Programmer's guide, with the new instructions, registers, etc.
2362306a36Sopenharmony_ci# from the NCR53c810.
2462306a36Sopenharmony_ci#
2562306a36Sopenharmony_ci# Differences between this assembler and NCR's are that
2662306a36Sopenharmony_ci# 1.  PASS, REL (data, JUMPs work fine), and the option to start a new
2762306a36Sopenharmony_ci#	script,  are unimplemented, since I didn't use them in my scripts.
2862306a36Sopenharmony_ci#
2962306a36Sopenharmony_ci# 2.  I also emit a script_u.h file, which will undefine all of
3062306a36Sopenharmony_ci# 	the A_*, E_*, etc. symbols defined in the script.  This
3162306a36Sopenharmony_ci#	makes including multiple scripts in one program easier
3262306a36Sopenharmony_ci#
3362306a36Sopenharmony_ci# 3.  This is a single pass assembler, which only emits
3462306a36Sopenharmony_ci#	.h files.
3562306a36Sopenharmony_ci#
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci# XXX - set these with command line options
3962306a36Sopenharmony_ci$debug = 0;		# Print general debugging messages
4062306a36Sopenharmony_ci$debug_external = 0;	# Print external/forward reference messages
4162306a36Sopenharmony_ci$list_in_array = 1;	# Emit original SCRIPTS assembler in comments in
4262306a36Sopenharmony_ci			# script.h
4362306a36Sopenharmony_ci#$prefix;		# (set by perl -s)
4462306a36Sopenharmony_ci                        # define all arrays having this prefix so we
4562306a36Sopenharmony_ci			# don't have name space collisions after
4662306a36Sopenharmony_ci			# assembling this file in different ways for
4762306a36Sopenharmony_ci			# different host adapters
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci# Constants
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci# Table of the SCSI phase encodings
5362306a36Sopenharmony_ci%scsi_phases = (
5462306a36Sopenharmony_ci    'DATA_OUT', 0x00_00_00_00, 'DATA_IN', 0x01_00_00_00, 'CMD', 0x02_00_00_00,
5562306a36Sopenharmony_ci    'STATUS', 0x03_00_00_00, 'MSG_OUT', 0x06_00_00_00, 'MSG_IN', 0x07_00_00_00
5662306a36Sopenharmony_ci);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci# XXX - replace references to the *_810 constants with general constants
5962306a36Sopenharmony_ci# assigned at compile time based on chip type.
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci# Table of operator encodings
6262306a36Sopenharmony_ci# XXX - NCR53c710 only implements
6362306a36Sopenharmony_ci# 	move (nop) = 0x00_00_00_00
6462306a36Sopenharmony_ci#	or = 0x02_00_00_00
6562306a36Sopenharmony_ci# 	and = 0x04_00_00_00
6662306a36Sopenharmony_ci# 	add = 0x06_00_00_00
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ciif ($ncr7x0_family) {
6962306a36Sopenharmony_ci  %operators = (
7062306a36Sopenharmony_ci    '|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
7162306a36Sopenharmony_ci    '&', 0x04_00_00_00, 'AND', 0x04_00_00_00,
7262306a36Sopenharmony_ci    '+', 0x06_00_00_00
7362306a36Sopenharmony_ci  );
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_cielse {
7662306a36Sopenharmony_ci  %operators = (
7762306a36Sopenharmony_ci    'SHL',  0x01_00_00_00,
7862306a36Sopenharmony_ci    '|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
7962306a36Sopenharmony_ci    'XOR', 0x03_00_00_00,
8062306a36Sopenharmony_ci    '&', 0x04_00_00_00, 'AND', 0x04_00_00_00,
8162306a36Sopenharmony_ci    'SHR', 0x05_00_00_00,
8262306a36Sopenharmony_ci    # Note : low bit of the operator bit should be set for add with
8362306a36Sopenharmony_ci    # carry.
8462306a36Sopenharmony_ci    '+', 0x06_00_00_00
8562306a36Sopenharmony_ci  );
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci# Table of register addresses
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ciif ($ncr7x0_family) {
9162306a36Sopenharmony_ci  %registers = (
9262306a36Sopenharmony_ci    'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
9362306a36Sopenharmony_ci    'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
9462306a36Sopenharmony_ci    'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11,
9562306a36Sopenharmony_ci    'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
9662306a36Sopenharmony_ci    'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
9762306a36Sopenharmony_ci    'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23,
9862306a36Sopenharmony_ci    'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27,
9962306a36Sopenharmony_ci    'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
10062306a36Sopenharmony_ci    'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34, 'LCRC', 35,
10162306a36Sopenharmony_ci    'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
10262306a36Sopenharmony_ci    'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
10362306a36Sopenharmony_ci    'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
10462306a36Sopenharmony_ci    'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
10562306a36Sopenharmony_ci    'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
10662306a36Sopenharmony_ci    'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
10762306a36Sopenharmony_ci    'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
10862306a36Sopenharmony_ci  );
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_cielse {
11162306a36Sopenharmony_ci  %registers = (
11262306a36Sopenharmony_ci    'SCNTL0', 0, 'SCNTL1', 1, 'SCNTL2', 2, 'SCNTL3', 3,
11362306a36Sopenharmony_ci    'SCID', 4, 'SXFER', 5, 'SDID', 6, 'GPREG', 7,
11462306a36Sopenharmony_ci    'SFBR', 8, 'SOCL', 9, 'SSID', 10, 'SBCL', 11,
11562306a36Sopenharmony_ci    'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
11662306a36Sopenharmony_ci    'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
11762306a36Sopenharmony_ci    'ISTAT', 20,
11862306a36Sopenharmony_ci    'CTEST0', 24, 'CTEST1', 25, 'CTEST2', 26, 'CTEST3', 27,
11962306a36Sopenharmony_ci    'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
12062306a36Sopenharmony_ci    'DFIFO', 32, 'CTEST4', 33, 'CTEST5', 34, 'CTEST6', 35,
12162306a36Sopenharmony_ci    'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
12262306a36Sopenharmony_ci    'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
12362306a36Sopenharmony_ci    'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
12462306a36Sopenharmony_ci    'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
12562306a36Sopenharmony_ci    'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
12662306a36Sopenharmony_ci    'SCRATCHA0', 52, 'SCRATCHA1', 53, 'SCRATCHA2', 54, 'SCRATCHA3', 55,
12762306a36Sopenharmony_ci    'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
12862306a36Sopenharmony_ci    'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
12962306a36Sopenharmony_ci    'SIEN0', 64, 'SIEN1', 65, 'SIST0', 66, 'SIST1', 67,
13062306a36Sopenharmony_ci    'SLPAR', 68, 	      'MACNTL', 70, 'GPCNTL', 71,
13162306a36Sopenharmony_ci    'STIME0', 72, 'STIME1', 73, 'RESPID', 74,
13262306a36Sopenharmony_ci    'STEST0', 76, 'STEST1', 77, 'STEST2', 78, 'STEST3', 79,
13362306a36Sopenharmony_ci    'SIDL', 80,
13462306a36Sopenharmony_ci    'SODL', 84,
13562306a36Sopenharmony_ci    'SBDL', 88,
13662306a36Sopenharmony_ci    'SCRATCHB0', 92, 'SCRATCHB1', 93, 'SCRATCHB2', 94, 'SCRATCHB3', 95
13762306a36Sopenharmony_ci  );
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci# Parsing regular expressions
14162306a36Sopenharmony_ci$identifier = '[A-Za-z_][A-Za-z_0-9]*';
14262306a36Sopenharmony_ci$decnum = '-?\\d+';
14362306a36Sopenharmony_ci$hexnum = '0[xX][0-9A-Fa-f]+';
14462306a36Sopenharmony_ci$constant = "$hexnum|$decnum";
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci# yucky - since we can't control grouping of # $constant, we need to
14762306a36Sopenharmony_ci# expand out each alternative for $value.
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci$value = "$identifier|$identifier\\s*[+\-]\\s*$decnum|".
15062306a36Sopenharmony_ci    "$identifier\\s*[+-]\s*$hexnum|$constant";
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ciprint STDERR "value regex = $value\n" if ($debug);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci$phase = join ('|', keys %scsi_phases);
15562306a36Sopenharmony_ciprint STDERR "phase regex = $phase\n" if ($debug);
15662306a36Sopenharmony_ci$register = join ('|', keys %registers);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci# yucky - since %operators includes meta-characters which must
15962306a36Sopenharmony_ci# be escaped, I can't use the join() trick I used for the register
16062306a36Sopenharmony_ci# regex
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ciif ($ncr7x0_family) {
16362306a36Sopenharmony_ci  $operator = '\||OR|AND|\&|\+';
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_cielse {
16662306a36Sopenharmony_ci  $operator = '\||OR|AND|XOR|\&|\+';
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci# Global variables
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci%symbol_values = (%registers) ;		# Traditional symbol table
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci%symbol_references = () ;		# Table of symbol references, where
17462306a36Sopenharmony_ci					# the index is the symbol name,
17562306a36Sopenharmony_ci					# and the contents a white space
17662306a36Sopenharmony_ci					# delimited list of address,size
17762306a36Sopenharmony_ci					# tuples where size is in bytes.
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci@code = ();				# Array of 32 bit words for SIOP
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci@entry = ();				# Array of entry point names
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci@label = ();				# Array of label names
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci@absolute = ();				# Array of absolute names
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci@relative = ();				# Array of relative names
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci@external = ();				# Array of external names
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci$address = 0;				# Address of current instruction
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci$lineno = 0;				# Line number we are parsing
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci$output = 'script.h';			# Output file
19662306a36Sopenharmony_ci$outputu = 'scriptu.h';
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci# &patch ($address, $offset, $length, $value) patches $code[$address]
19962306a36Sopenharmony_ci# 	so that the $length bytes at $offset have $value added to
20062306a36Sopenharmony_ci# 	them.
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci@inverted_masks = (0x00_00_00_00, 0x00_00_00_ff, 0x00_00_ff_ff, 0x00_ff_ff_ff,
20362306a36Sopenharmony_ci    0xff_ff_ff_ff);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cisub patch {
20662306a36Sopenharmony_ci    local ($address, $offset, $length, $value) = @_;
20762306a36Sopenharmony_ci    if ($debug) {
20862306a36Sopenharmony_ci	print STDERR "Patching $address at offset $offset, length $length to $value\n";
20962306a36Sopenharmony_ci	printf STDERR "Old code : %08x\n", $code[$address];
21062306a36Sopenharmony_ci     }
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci    $mask = ($inverted_masks[$length] << ($offset * 8));
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci    $code[$address] = ($code[$address] & ~$mask) |
21562306a36Sopenharmony_ci	(($code[$address] & $mask) + ($value << ($offset * 8)) &
21662306a36Sopenharmony_ci	$mask);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci    printf STDERR "New code : %08x\n", $code[$address] if ($debug);
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci# &parse_value($value, $word, $offset, $length) where $value is
22262306a36Sopenharmony_ci# 	an identifier or constant, $word is the word offset relative to
22362306a36Sopenharmony_ci#	$address, $offset is the starting byte within that word, and
22462306a36Sopenharmony_ci#	$length is the length of the field in bytes.
22562306a36Sopenharmony_ci#
22662306a36Sopenharmony_ci# Side effects are that the bytes are combined into the @code array
22762306a36Sopenharmony_ci#	relative to $address, and that the %symbol_references table is
22862306a36Sopenharmony_ci# 	updated as appropriate.
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cisub parse_value {
23162306a36Sopenharmony_ci    local ($value, $word, $offset, $length) = @_;
23262306a36Sopenharmony_ci    local ($tmp);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci    $symbol = '';
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci    if ($value =~ /^REL\s*\(\s*($identifier)\s*\)\s*(.*)/i) {
23762306a36Sopenharmony_ci	$relative = 'REL';
23862306a36Sopenharmony_ci	$symbol = $1;
23962306a36Sopenharmony_ci	$value = $2;
24062306a36Sopenharmony_ciprint STDERR "Relative reference $symbol\n" if ($debug);
24162306a36Sopenharmony_ci    } elsif ($value =~ /^($identifier)\s*(.*)/) {
24262306a36Sopenharmony_ci	$relative = 'ABS';
24362306a36Sopenharmony_ci	$symbol = $1;
24462306a36Sopenharmony_ci	$value = $2;
24562306a36Sopenharmony_ciprint STDERR "Absolute reference $symbol\n" if ($debug);
24662306a36Sopenharmony_ci    }
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci    if ($symbol ne '') {
24962306a36Sopenharmony_ciprint STDERR "Referencing symbol $1, length = $length in $_\n" if ($debug);
25062306a36Sopenharmony_ci     	$tmp = ($address + $word) * 4 + $offset;
25162306a36Sopenharmony_ci	if ($symbol_references{$symbol} ne undef) {
25262306a36Sopenharmony_ci	    $symbol_references{$symbol} =
25362306a36Sopenharmony_ci		"$symbol_references{$symbol} $relative,$tmp,$length";
25462306a36Sopenharmony_ci	} else {
25562306a36Sopenharmony_ci	    if (!defined($symbol_values{$symbol})) {
25662306a36Sopenharmony_ciprint STDERR "forward $1\n" if ($debug_external);
25762306a36Sopenharmony_ci		$forward{$symbol} = "line $lineno : $_";
25862306a36Sopenharmony_ci	    }
25962306a36Sopenharmony_ci	    $symbol_references{$symbol} = "$relative,$tmp,$length";
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci    }
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci    $value = eval $value;
26462306a36Sopenharmony_ci    &patch ($address + $word, $offset, $length, $value);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci# &parse_conditional ($conditional) where $conditional is the conditional
26862306a36Sopenharmony_ci# clause from a transfer control instruction (RETURN, CALL, JUMP, INT).
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cisub parse_conditional {
27162306a36Sopenharmony_ci    local ($conditional) = @_;
27262306a36Sopenharmony_ci    if ($conditional =~ /^\s*(IF|WHEN)\s*(.*)/i) {
27362306a36Sopenharmony_ci	$if = $1;
27462306a36Sopenharmony_ci	$conditional = $2;
27562306a36Sopenharmony_ci	if ($if =~ /WHEN/i) {
27662306a36Sopenharmony_ci	    $allow_atn = 0;
27762306a36Sopenharmony_ci	    $code[$address] |= 0x00_01_00_00;
27862306a36Sopenharmony_ci	    $allow_atn = 0;
27962306a36Sopenharmony_ci	    print STDERR "$0 : parsed WHEN\n" if ($debug);
28062306a36Sopenharmony_ci	} else {
28162306a36Sopenharmony_ci	    $allow_atn = 1;
28262306a36Sopenharmony_ci	    print STDERR "$0 : parsed IF\n" if ($debug);
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci    } else {
28562306a36Sopenharmony_ci	    die "$0 : syntax error in line $lineno : $_
28662306a36Sopenharmony_ci	expected IF or WHEN
28762306a36Sopenharmony_ci";
28862306a36Sopenharmony_ci    }
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci    if ($conditional =~ /^NOT\s+(.*)$/i) {
29162306a36Sopenharmony_ci	$not = 'NOT ';
29262306a36Sopenharmony_ci	$other = 'OR';
29362306a36Sopenharmony_ci	$conditional = $1;
29462306a36Sopenharmony_ci	print STDERR "$0 : parsed NOT\n" if ($debug);
29562306a36Sopenharmony_ci    } else {
29662306a36Sopenharmony_ci	$code[$address] |= 0x00_08_00_00;
29762306a36Sopenharmony_ci	$not = '';
29862306a36Sopenharmony_ci	$other = 'AND'
29962306a36Sopenharmony_ci    }
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci    $need_data = 0;
30262306a36Sopenharmony_ci    if ($conditional =~ /^ATN\s*(.*)/i) {#
30362306a36Sopenharmony_ci	die "$0 : syntax error in line $lineno : $_
30462306a36Sopenharmony_ci	WHEN conditional is incompatible with ATN
30562306a36Sopenharmony_ci" if (!$allow_atn);
30662306a36Sopenharmony_ci	$code[$address] |= 0x00_02_00_00;
30762306a36Sopenharmony_ci	$conditional = $1;
30862306a36Sopenharmony_ci	print STDERR "$0 : parsed ATN\n" if ($debug);
30962306a36Sopenharmony_ci    } elsif ($conditional =~ /^($phase)\s*(.*)/i) {
31062306a36Sopenharmony_ci	$phase_index = "\U$1\E";
31162306a36Sopenharmony_ci	$p = $scsi_phases{$phase_index};
31262306a36Sopenharmony_ci	$code[$address] |= $p | 0x00_02_00_00;
31362306a36Sopenharmony_ci	$conditional = $2;
31462306a36Sopenharmony_ci	print STDERR "$0 : parsed phase $phase_index\n" if ($debug);
31562306a36Sopenharmony_ci    } else {
31662306a36Sopenharmony_ci	$other = '';
31762306a36Sopenharmony_ci	$need_data = 1;
31862306a36Sopenharmony_ci    }
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ciprint STDERR "Parsing conjunction, expecting $other\n" if ($debug);
32162306a36Sopenharmony_ci    if ($conditional =~ /^(AND|OR)\s*(.*)/i) {
32262306a36Sopenharmony_ci	$conjunction = $1;
32362306a36Sopenharmony_ci	$conditional = $2;
32462306a36Sopenharmony_ci	$need_data = 1;
32562306a36Sopenharmony_ci	die "$0 : syntax error in line $lineno : $_
32662306a36Sopenharmony_ci	    Illegal use of $1.  Valid uses are
32762306a36Sopenharmony_ci	    ".$not."<phase> $1 data
32862306a36Sopenharmony_ci	    ".$not."ATN $1 data
32962306a36Sopenharmony_ci" if ($other eq '');
33062306a36Sopenharmony_ci	die "$0 : syntax error in line $lineno : $_
33162306a36Sopenharmony_ci	Illegal use of $conjunction.  Valid syntaxes are
33262306a36Sopenharmony_ci		NOT <phase>|ATN OR data
33362306a36Sopenharmony_ci		<phase>|ATN AND data
33462306a36Sopenharmony_ci" if ($conjunction !~ /\s*$other\s*/i);
33562306a36Sopenharmony_ci	print STDERR "$0 : parsed $1\n" if ($debug);
33662306a36Sopenharmony_ci    }
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci    if ($need_data) {
33962306a36Sopenharmony_ciprint STDERR "looking for data in $conditional\n" if ($debug);
34062306a36Sopenharmony_ci	if ($conditional=~ /^($value)\s*(.*)/i) {
34162306a36Sopenharmony_ci	    $code[$address] |= 0x00_04_00_00;
34262306a36Sopenharmony_ci	    $conditional = $2;
34362306a36Sopenharmony_ci	    &parse_value($1, 0, 0, 1);
34462306a36Sopenharmony_ci	    print STDERR "$0 : parsed data\n" if ($debug);
34562306a36Sopenharmony_ci	} else {
34662306a36Sopenharmony_ci	die "$0 : syntax error in line $lineno : $_
34762306a36Sopenharmony_ci	expected <data>.
34862306a36Sopenharmony_ci";
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci    }
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci    if ($conditional =~ /^\s*,\s*(.*)/) {
35362306a36Sopenharmony_ci	$conditional = $1;
35462306a36Sopenharmony_ci	if ($conditional =~ /^AND\s\s*MASK\s\s*($value)\s*(.*)/i) {
35562306a36Sopenharmony_ci	    &parse_value ($1, 0, 1, 1);
35662306a36Sopenharmony_ci	    print STDERR "$0 parsed AND MASK $1\n" if ($debug);
35762306a36Sopenharmony_ci	    die "$0 : syntax error in line $lineno : $_
35862306a36Sopenharmony_ci	expected end of line, not \"$2\"
35962306a36Sopenharmony_ci" if ($2 ne '');
36062306a36Sopenharmony_ci	} else {
36162306a36Sopenharmony_ci	    die "$0 : syntax error in line $lineno : $_
36262306a36Sopenharmony_ci	expected \",AND MASK <data>\", not \"$2\"
36362306a36Sopenharmony_ci";
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci    } elsif ($conditional !~ /^\s*$/) {
36662306a36Sopenharmony_ci	die "$0 : syntax error in line $lineno : $_
36762306a36Sopenharmony_ci	expected end of line" . (($need_data) ? " or \"AND MASK <data>\"" : "") . "
36862306a36Sopenharmony_ci	not \"$conditional\"
36962306a36Sopenharmony_ci";
37062306a36Sopenharmony_ci    }
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci# Parse command line
37462306a36Sopenharmony_ci$output = shift;
37562306a36Sopenharmony_ci$outputu = shift;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci# Main loop
37962306a36Sopenharmony_ciwhile (<STDIN>) {
38062306a36Sopenharmony_ci    $lineno = $lineno + 1;
38162306a36Sopenharmony_ci    $list[$address] = $list[$address].$_;
38262306a36Sopenharmony_ci    s/;.*$//;				# Strip comments
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci    chop;				# Leave new line out of error messages
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci# Handle symbol definitions of the form label:
38862306a36Sopenharmony_ci    if (/^\s*($identifier)\s*:(.*)/) {
38962306a36Sopenharmony_ci	if (!defined($symbol_values{$1})) {
39062306a36Sopenharmony_ci	    $symbol_values{$1} = $address * 4;	# Address is an index into
39162306a36Sopenharmony_ci	    delete $forward{$1};		# an array of longs
39262306a36Sopenharmony_ci	    push (@label, $1);
39362306a36Sopenharmony_ci	    $_ = $2;
39462306a36Sopenharmony_ci	} else {
39562306a36Sopenharmony_ci	    die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci    }
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci# Handle symbol definitions of the form ABSOLUTE or RELATIVE identifier =
40062306a36Sopenharmony_ci# value
40162306a36Sopenharmony_ci    if (/^\s*(ABSOLUTE|RELATIVE)\s+(.*)/i) {
40262306a36Sopenharmony_ci	$is_absolute = $1;
40362306a36Sopenharmony_ci	$rest = $2;
40462306a36Sopenharmony_ci	foreach $rest (split (/\s*,\s*/, $rest)) {
40562306a36Sopenharmony_ci	    if ($rest =~ /^($identifier)\s*=\s*($constant)\s*$/) {
40662306a36Sopenharmony_ci	        local ($id, $cnst) = ($1, $2);
40762306a36Sopenharmony_ci		if ($symbol_values{$id} eq undef) {
40862306a36Sopenharmony_ci		    $symbol_values{$id} = eval $cnst;
40962306a36Sopenharmony_ci		    delete $forward{$id};
41062306a36Sopenharmony_ci		    if ($is_absolute =~ /ABSOLUTE/i) {
41162306a36Sopenharmony_ci			push (@absolute , $id);
41262306a36Sopenharmony_ci		    } else {
41362306a36Sopenharmony_ci			push (@relative, $id);
41462306a36Sopenharmony_ci		    }
41562306a36Sopenharmony_ci		} else {
41662306a36Sopenharmony_ci		    die "$0 : redefinition of symbol $id in line $lineno : $_\n";
41762306a36Sopenharmony_ci		}
41862306a36Sopenharmony_ci	    } else {
41962306a36Sopenharmony_ci		die
42062306a36Sopenharmony_ci"$0 : syntax error in line $lineno : $_
42162306a36Sopenharmony_ci	    expected <identifier> = <value>
42262306a36Sopenharmony_ci";
42362306a36Sopenharmony_ci	    }
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci    } elsif (/^\s*EXTERNAL\s+(.*)/i) {
42662306a36Sopenharmony_ci	$externals = $1;
42762306a36Sopenharmony_ci	foreach $external (split (/,/,$externals)) {
42862306a36Sopenharmony_ci	    if ($external =~ /\s*($identifier)\s*$/) {
42962306a36Sopenharmony_ci		$external = $1;
43062306a36Sopenharmony_ci		push (@external, $external);
43162306a36Sopenharmony_ci		delete $forward{$external};
43262306a36Sopenharmony_ci		if (defined($symbol_values{$external})) {
43362306a36Sopenharmony_ci			die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
43462306a36Sopenharmony_ci		}
43562306a36Sopenharmony_ci		$symbol_values{$external} = $external;
43662306a36Sopenharmony_ciprint STDERR "defined external $1 to $external\n" if ($debug_external);
43762306a36Sopenharmony_ci	    } else {
43862306a36Sopenharmony_ci		die
43962306a36Sopenharmony_ci"$0 : syntax error in line $lineno : $_
44062306a36Sopenharmony_ci	expected <identifier>, got $external
44162306a36Sopenharmony_ci";
44262306a36Sopenharmony_ci	    }
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci# Process ENTRY identifier declarations
44562306a36Sopenharmony_ci    } elsif (/^\s*ENTRY\s+(.*)/i) {
44662306a36Sopenharmony_ci	if ($1 =~ /^($identifier)\s*$/) {
44762306a36Sopenharmony_ci	    push (@entry, $1);
44862306a36Sopenharmony_ci	} else {
44962306a36Sopenharmony_ci	    die
45062306a36Sopenharmony_ci"$0 : syntax error in line $lineno : $_
45162306a36Sopenharmony_ci	expected ENTRY <identifier>
45262306a36Sopenharmony_ci";
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci# Process MOVE length, address, WITH|WHEN phase instruction
45562306a36Sopenharmony_ci    } elsif (/^\s*MOVE\s+(.*)/i) {
45662306a36Sopenharmony_ci	$rest = $1;
45762306a36Sopenharmony_ci	if ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
45862306a36Sopenharmony_ci	    $transfer_addr = $1;
45962306a36Sopenharmony_ci	    $with_when = $2;
46062306a36Sopenharmony_ci	    $scsi_phase = $3;
46162306a36Sopenharmony_ciprint STDERR "Parsing MOVE FROM $transfer_addr, $with_when $3\n" if ($debug);
46262306a36Sopenharmony_ci	    $code[$address] = 0x18_00_00_00 | (($with_when =~ /WITH/i) ?
46362306a36Sopenharmony_ci		0x00_00_00_00 : 0x08_00_00_00) | $scsi_phases{$scsi_phase};
46462306a36Sopenharmony_ci	    &parse_value ($transfer_addr, 1, 0, 4);
46562306a36Sopenharmony_ci	    $address += 2;
46662306a36Sopenharmony_ci	} elsif ($rest =~ /^($value)\s*,\s*(PTR\s+|)($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
46762306a36Sopenharmony_ci	    $transfer_len = $1;
46862306a36Sopenharmony_ci	    $ptr = $2;
46962306a36Sopenharmony_ci	    $transfer_addr = $3;
47062306a36Sopenharmony_ci	    $with_when = $4;
47162306a36Sopenharmony_ci	    $scsi_phase = $5;
47262306a36Sopenharmony_ci	    $code[$address] = (($with_when =~ /WITH/i) ? 0x00_00_00_00 :
47362306a36Sopenharmony_ci		0x08_00_00_00)  | (($ptr =~ /PTR/i) ? (1 << 29) : 0) |
47462306a36Sopenharmony_ci		$scsi_phases{$scsi_phase};
47562306a36Sopenharmony_ci	    &parse_value ($transfer_len, 0, 0, 3);
47662306a36Sopenharmony_ci	    &parse_value ($transfer_addr, 1, 0, 4);
47762306a36Sopenharmony_ci	    $address += 2;
47862306a36Sopenharmony_ci	} elsif ($rest =~ /^MEMORY\s+(.*)/i) {
47962306a36Sopenharmony_ci	    $rest = $1;
48062306a36Sopenharmony_ci	    $code[$address] = 0xc0_00_00_00;
48162306a36Sopenharmony_ci	    if ($rest =~ /^($value)\s*,\s*($value)\s*,\s*($value)\s*$/) {
48262306a36Sopenharmony_ci		$count = $1;
48362306a36Sopenharmony_ci		$source = $2;
48462306a36Sopenharmony_ci		$dest =  $3;
48562306a36Sopenharmony_ciprint STDERR "Parsing MOVE MEMORY $count, $source, $dest\n" if ($debug);
48662306a36Sopenharmony_ci		&parse_value ($count, 0, 0, 3);
48762306a36Sopenharmony_ci		&parse_value ($source, 1, 0, 4);
48862306a36Sopenharmony_ci		&parse_value ($dest, 2, 0, 4);
48962306a36Sopenharmony_ciprintf STDERR "Move memory instruction = %08x,%08x,%08x\n",
49062306a36Sopenharmony_ci		$code[$address], $code[$address+1], $code[$address +2] if
49162306a36Sopenharmony_ci		($debug);
49262306a36Sopenharmony_ci		$address += 3;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	    } else {
49562306a36Sopenharmony_ci		die
49662306a36Sopenharmony_ci"$0 : syntax error in line $lineno : $_
49762306a36Sopenharmony_ci	expected <count>, <source>, <destination>
49862306a36Sopenharmony_ci"
49962306a36Sopenharmony_ci	    }
50062306a36Sopenharmony_ci	} elsif ($1 =~ /^(.*)\s+(TO|SHL|SHR)\s+(.*)/i) {
50162306a36Sopenharmony_ciprint STDERR "Parsing register to register move\n" if ($debug);
50262306a36Sopenharmony_ci	    $src = $1;
50362306a36Sopenharmony_ci	    $op = "\U$2\E";
50462306a36Sopenharmony_ci	    $rest = $3;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	    $code[$address] = 0x40_00_00_00;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	    $force = ($op !~ /TO/i);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ciprint STDERR "Forcing register source \n" if ($force && $debug);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	    if (!$force && $src =~
51462306a36Sopenharmony_ci		/^($register)\s+(-|$operator)\s+($value)\s*$/i) {
51562306a36Sopenharmony_ciprint STDERR "register operand  data8 source\n" if ($debug);
51662306a36Sopenharmony_ci		$src_reg = "\U$1\E";
51762306a36Sopenharmony_ci		$op = "\U$2\E";
51862306a36Sopenharmony_ci		if ($op ne '-') {
51962306a36Sopenharmony_ci		    $data8 = $3;
52062306a36Sopenharmony_ci		} else {
52162306a36Sopenharmony_ci		    die "- is not implemented yet.\n"
52262306a36Sopenharmony_ci		}
52362306a36Sopenharmony_ci	    } elsif ($src =~ /^($register)\s*$/i) {
52462306a36Sopenharmony_ciprint STDERR "register source\n" if ($debug);
52562306a36Sopenharmony_ci		$src_reg = "\U$1\E";
52662306a36Sopenharmony_ci		# Encode register to register move as a register | 0
52762306a36Sopenharmony_ci		# move to register.
52862306a36Sopenharmony_ci		if (!$force) {
52962306a36Sopenharmony_ci		    $op = '|';
53062306a36Sopenharmony_ci		}
53162306a36Sopenharmony_ci		$data8 = 0;
53262306a36Sopenharmony_ci	    } elsif (!$force && $src =~ /^($value)\s*$/i) {
53362306a36Sopenharmony_ciprint STDERR "data8 source\n" if ($debug);
53462306a36Sopenharmony_ci		$src_reg = undef;
53562306a36Sopenharmony_ci		$op = 'NONE';
53662306a36Sopenharmony_ci		$data8 = $1;
53762306a36Sopenharmony_ci	    } else {
53862306a36Sopenharmony_ci		if (!$force) {
53962306a36Sopenharmony_ci		    die
54062306a36Sopenharmony_ci"$0 : syntax error in line $lineno : $_
54162306a36Sopenharmony_ci	expected <register>
54262306a36Sopenharmony_ci		<data8>
54362306a36Sopenharmony_ci		<register> <operand> <data8>
54462306a36Sopenharmony_ci";
54562306a36Sopenharmony_ci		} else {
54662306a36Sopenharmony_ci		    die
54762306a36Sopenharmony_ci"$0 : syntax error in line $lineno : $_
54862306a36Sopenharmony_ci	expected <register>
54962306a36Sopenharmony_ci";
55062306a36Sopenharmony_ci		}
55162306a36Sopenharmony_ci	    }
55262306a36Sopenharmony_ci	    if ($rest =~ /^($register)\s*(.*)$/i) {
55362306a36Sopenharmony_ci		$dst_reg = "\U$1\E";
55462306a36Sopenharmony_ci		$rest = $2;
55562306a36Sopenharmony_ci	    } else {
55662306a36Sopenharmony_ci	    die
55762306a36Sopenharmony_ci"$0 : syntax error in $lineno : $_
55862306a36Sopenharmony_ci	expected <register>, got $rest
55962306a36Sopenharmony_ci";
56062306a36Sopenharmony_ci	    }
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	    if ($rest =~ /^WITH\s+CARRY\s*(.*)/i) {
56362306a36Sopenharmony_ci		$rest = $1;
56462306a36Sopenharmony_ci		if ($op eq '+') {
56562306a36Sopenharmony_ci		    $code[$address] |= 0x01_00_00_00;
56662306a36Sopenharmony_ci		} else {
56762306a36Sopenharmony_ci		    die
56862306a36Sopenharmony_ci"$0 : syntax error in $lineno : $_
56962306a36Sopenharmony_ci	WITH CARRY option is incompatible with the $op operator.
57062306a36Sopenharmony_ci";
57162306a36Sopenharmony_ci		}
57262306a36Sopenharmony_ci	    }
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	    if ($rest !~ /^\s*$/) {
57562306a36Sopenharmony_ci		die
57662306a36Sopenharmony_ci"$0 : syntax error in $lineno : $_
57762306a36Sopenharmony_ci	Expected end of line, got $rest
57862306a36Sopenharmony_ci";
57962306a36Sopenharmony_ci	    }
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	    print STDERR "source = $src_reg, data = $data8 , destination = $dst_reg\n"
58262306a36Sopenharmony_ci		if ($debug);
58362306a36Sopenharmony_ci	    # Note that Move data8 to reg is encoded as a read-modify-write
58462306a36Sopenharmony_ci	    # instruction.
58562306a36Sopenharmony_ci	    if (($src_reg eq undef) || ($src_reg eq $dst_reg)) {
58662306a36Sopenharmony_ci		$code[$address] |= 0x38_00_00_00 |
58762306a36Sopenharmony_ci		    ($registers{$dst_reg} << 16);
58862306a36Sopenharmony_ci	    } elsif ($dst_reg =~ /SFBR/i) {
58962306a36Sopenharmony_ci		$code[$address] |= 0x30_00_00_00 |
59062306a36Sopenharmony_ci		    ($registers{$src_reg} << 16);
59162306a36Sopenharmony_ci	    } elsif ($src_reg =~ /SFBR/i) {
59262306a36Sopenharmony_ci		$code[$address] |= 0x28_00_00_00 |
59362306a36Sopenharmony_ci		    ($registers{$dst_reg} << 16);
59462306a36Sopenharmony_ci	    } else {
59562306a36Sopenharmony_ci		die
59662306a36Sopenharmony_ci"$0 : Illegal combination of registers in line $lineno : $_
59762306a36Sopenharmony_ci	Either source and destination registers must be the same,
59862306a36Sopenharmony_ci	or either source or destination register must be SFBR.
59962306a36Sopenharmony_ci";
60062306a36Sopenharmony_ci	    }
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	    $code[$address] |= $operators{$op};
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	    &parse_value ($data8, 0, 1, 1);
60562306a36Sopenharmony_ci	    $code[$address] |= $operators{$op};
60662306a36Sopenharmony_ci	    $code[$address + 1] = 0x00_00_00_00;# Reserved
60762306a36Sopenharmony_ci	    $address += 2;
60862306a36Sopenharmony_ci	} else {
60962306a36Sopenharmony_ci	    die
61062306a36Sopenharmony_ci"$0 : syntax error in line $lineno : $_
61162306a36Sopenharmony_ci	expected (initiator) <length>, <address>, WHEN <phase>
61262306a36Sopenharmony_ci		 (target) <length>, <address>, WITH <phase>
61362306a36Sopenharmony_ci		 MEMORY <length>, <source>, <destination>
61462306a36Sopenharmony_ci		 <expression> TO <register>
61562306a36Sopenharmony_ci";
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci# Process SELECT {ATN|} id, fail_address
61862306a36Sopenharmony_ci    } elsif (/^\s*(SELECT|RESELECT)\s+(.*)/i) {
61962306a36Sopenharmony_ci	$rest = $2;
62062306a36Sopenharmony_ci	if ($rest =~ /^(ATN|)\s*($value)\s*,\s*($identifier)\s*$/i) {
62162306a36Sopenharmony_ci	    $atn = $1;
62262306a36Sopenharmony_ci	    $id = $2;
62362306a36Sopenharmony_ci	    $alt_addr = $3;
62462306a36Sopenharmony_ci	    $code[$address] = 0x40_00_00_00 |
62562306a36Sopenharmony_ci		(($atn =~ /ATN/i) ? 0x01_00_00_00 : 0);
62662306a36Sopenharmony_ci	    $code[$address + 1] = 0x00_00_00_00;
62762306a36Sopenharmony_ci	    &parse_value($id, 0, 2, 1);
62862306a36Sopenharmony_ci	    &parse_value($alt_addr, 1, 0, 4);
62962306a36Sopenharmony_ci	    $address += 2;
63062306a36Sopenharmony_ci	} elsif ($rest =~ /^(ATN|)\s*FROM\s+($value)\s*,\s*($identifier)\s*$/i) {
63162306a36Sopenharmony_ci	    $atn = $1;
63262306a36Sopenharmony_ci	    $addr = $2;
63362306a36Sopenharmony_ci	    $alt_addr = $3;
63462306a36Sopenharmony_ci	    $code[$address] = 0x42_00_00_00 |
63562306a36Sopenharmony_ci		(($atn =~ /ATN/i) ? 0x01_00_00_00 : 0);
63662306a36Sopenharmony_ci	    $code[$address + 1] = 0x00_00_00_00;
63762306a36Sopenharmony_ci	    &parse_value($addr, 0, 0, 3);
63862306a36Sopenharmony_ci	    &parse_value($alt_addr, 1, 0, 4);
63962306a36Sopenharmony_ci	    $address += 2;
64062306a36Sopenharmony_ci        } else {
64162306a36Sopenharmony_ci	    die
64262306a36Sopenharmony_ci"$0 : syntax error in line $lineno : $_
64362306a36Sopenharmony_ci	expected SELECT id, alternate_address or
64462306a36Sopenharmony_ci		SELECT FROM address, alternate_address or
64562306a36Sopenharmony_ci		RESELECT id, alternate_address or
64662306a36Sopenharmony_ci		RESELECT FROM address, alternate_address
64762306a36Sopenharmony_ci";
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci    } elsif (/^\s*WAIT\s+(.*)/i) {
65062306a36Sopenharmony_ci	    $rest = $1;
65162306a36Sopenharmony_ciprint STDERR "Parsing WAIT $rest\n" if ($debug);
65262306a36Sopenharmony_ci	if ($rest =~ /^DISCONNECT\s*$/i) {
65362306a36Sopenharmony_ci	    $code[$address] = 0x48_00_00_00;
65462306a36Sopenharmony_ci	    $code[$address + 1] = 0x00_00_00_00;
65562306a36Sopenharmony_ci	    $address += 2;
65662306a36Sopenharmony_ci	} elsif ($rest =~ /^(RESELECT|SELECT)\s+($identifier)\s*$/i) {
65762306a36Sopenharmony_ci	    $alt_addr = $2;
65862306a36Sopenharmony_ci	    $code[$address] = 0x50_00_00_00;
65962306a36Sopenharmony_ci	    &parse_value ($alt_addr, 1, 0, 4);
66062306a36Sopenharmony_ci	    $address += 2;
66162306a36Sopenharmony_ci	} else {
66262306a36Sopenharmony_ci	    die
66362306a36Sopenharmony_ci"$0 : syntax error in line $lineno : $_
66462306a36Sopenharmony_ci	expected (initiator) WAIT DISCONNECT or
66562306a36Sopenharmony_ci		 (initiator) WAIT RESELECT alternate_address or
66662306a36Sopenharmony_ci		 (target) WAIT SELECT alternate_address
66762306a36Sopenharmony_ci";
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci# Handle SET and CLEAR instructions.  Note that we should also do something
67062306a36Sopenharmony_ci# with this syntax to set target mode.
67162306a36Sopenharmony_ci    } elsif (/^\s*(SET|CLEAR)\s+(.*)/i) {
67262306a36Sopenharmony_ci	$set = $1;
67362306a36Sopenharmony_ci	$list = $2;
67462306a36Sopenharmony_ci	$code[$address] = ($set =~ /SET/i) ?  0x58_00_00_00 :
67562306a36Sopenharmony_ci	    0x60_00_00_00;
67662306a36Sopenharmony_ci	foreach $arg (split (/\s+AND\s+/i,$list)) {
67762306a36Sopenharmony_ci	    if ($arg =~ /ATN/i) {
67862306a36Sopenharmony_ci		$code[$address] |= 0x00_00_00_08;
67962306a36Sopenharmony_ci	    } elsif ($arg =~ /ACK/i) {
68062306a36Sopenharmony_ci		$code[$address] |= 0x00_00_00_40;
68162306a36Sopenharmony_ci	    } elsif ($arg =~ /TARGET/i) {
68262306a36Sopenharmony_ci		$code[$address] |= 0x00_00_02_00;
68362306a36Sopenharmony_ci	    } elsif ($arg =~ /CARRY/i) {
68462306a36Sopenharmony_ci		$code[$address] |= 0x00_00_04_00;
68562306a36Sopenharmony_ci	    } else {
68662306a36Sopenharmony_ci		die
68762306a36Sopenharmony_ci"$0 : syntax error in line $lineno : $_
68862306a36Sopenharmony_ci	expected $set followed by a AND delimited list of one or
68962306a36Sopenharmony_ci	more strings from the list ACK, ATN, CARRY, TARGET.
69062306a36Sopenharmony_ci";
69162306a36Sopenharmony_ci	    }
69262306a36Sopenharmony_ci	}
69362306a36Sopenharmony_ci	$code[$address + 1] = 0x00_00_00_00;
69462306a36Sopenharmony_ci	$address += 2;
69562306a36Sopenharmony_ci    } elsif (/^\s*(JUMP|CALL|INT)\s+(.*)/i) {
69662306a36Sopenharmony_ci	$instruction = $1;
69762306a36Sopenharmony_ci	$rest = $2;
69862306a36Sopenharmony_ci	if ($instruction =~ /JUMP/i) {
69962306a36Sopenharmony_ci	    $code[$address] = 0x80_00_00_00;
70062306a36Sopenharmony_ci	} elsif ($instruction =~ /CALL/i) {
70162306a36Sopenharmony_ci	    $code[$address] = 0x88_00_00_00;
70262306a36Sopenharmony_ci	} else {
70362306a36Sopenharmony_ci	    $code[$address] = 0x98_00_00_00;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ciprint STDERR "parsing JUMP, rest = $rest\n" if ($debug);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci# Relative jump.
70862306a36Sopenharmony_ci	if ($rest =~ /^(REL\s*\(\s*$identifier\s*\))\s*(.*)/i) {
70962306a36Sopenharmony_ci	    $addr = $1;
71062306a36Sopenharmony_ci	    $rest = $2;
71162306a36Sopenharmony_ciprint STDERR "parsing JUMP REL, addr = $addr, rest = $rest\n" if ($debug);
71262306a36Sopenharmony_ci	    $code[$address]  |= 0x00_80_00_00;
71362306a36Sopenharmony_ci	    &parse_value($addr, 1, 0, 4);
71462306a36Sopenharmony_ci# Absolute jump, requires no more gunk
71562306a36Sopenharmony_ci	} elsif ($rest =~ /^($value)\s*(.*)/) {
71662306a36Sopenharmony_ci	    $addr = $1;
71762306a36Sopenharmony_ci	    $rest = $2;
71862306a36Sopenharmony_ci	    &parse_value($addr, 1, 0, 4);
71962306a36Sopenharmony_ci	} else {
72062306a36Sopenharmony_ci	    die
72162306a36Sopenharmony_ci"$0 : syntax error in line $lineno : $_
72262306a36Sopenharmony_ci	expected <address> or REL (address)
72362306a36Sopenharmony_ci";
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if ($rest =~ /^,\s*(.*)/) {
72762306a36Sopenharmony_ci	    &parse_conditional($1);
72862306a36Sopenharmony_ci	} elsif ($rest =~ /^\s*$/) {
72962306a36Sopenharmony_ci	    $code[$address] |= (1 << 19);
73062306a36Sopenharmony_ci	} else {
73162306a36Sopenharmony_ci	    die
73262306a36Sopenharmony_ci"$0 : syntax error in line $lineno : $_
73362306a36Sopenharmony_ci	expected , <conditional> or end of line, got $1
73462306a36Sopenharmony_ci";
73562306a36Sopenharmony_ci	}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	$address += 2;
73862306a36Sopenharmony_ci    } elsif (/^\s*(RETURN|INTFLY)\s*(.*)/i) {
73962306a36Sopenharmony_ci	$instruction = $1;
74062306a36Sopenharmony_ci	$conditional = $2;
74162306a36Sopenharmony_ciprint STDERR "Parsing $instruction\n" if ($debug);
74262306a36Sopenharmony_ci	$code[$address] = ($instruction =~ /RETURN/i) ? 0x90_00_00_00 :
74362306a36Sopenharmony_ci	    0x98_10_00_00;
74462306a36Sopenharmony_ci	if ($conditional =~ /^,\s*(.*)/) {
74562306a36Sopenharmony_ci	    $conditional = $1;
74662306a36Sopenharmony_ci	    &parse_conditional ($conditional);
74762306a36Sopenharmony_ci	} elsif ($conditional !~ /^\s*$/) {
74862306a36Sopenharmony_ci	    die
74962306a36Sopenharmony_ci"$0 : syntax error in line $lineno : $_
75062306a36Sopenharmony_ci	expected , <conditional>
75162306a36Sopenharmony_ci";
75262306a36Sopenharmony_ci	} else {
75362306a36Sopenharmony_ci	    $code[$address] |= 0x00_08_00_00;
75462306a36Sopenharmony_ci	}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	$code[$address + 1] = 0x00_00_00_00;
75762306a36Sopenharmony_ci	$address += 2;
75862306a36Sopenharmony_ci    } elsif (/^\s*DISCONNECT\s*$/) {
75962306a36Sopenharmony_ci	$code[$address] = 0x48_00_00_00;
76062306a36Sopenharmony_ci	$code[$address + 1] = 0x00_00_00_00;
76162306a36Sopenharmony_ci	$address += 2;
76262306a36Sopenharmony_ci# I'm not sure that I should be including this extension, but
76362306a36Sopenharmony_ci# what the hell?
76462306a36Sopenharmony_ci    } elsif (/^\s*NOP\s*$/i) {
76562306a36Sopenharmony_ci	$code[$address] = 0x80_88_00_00;
76662306a36Sopenharmony_ci	$code[$address + 1] = 0x00_00_00_00;
76762306a36Sopenharmony_ci	$address += 2;
76862306a36Sopenharmony_ci# Ignore lines consisting entirely of white space
76962306a36Sopenharmony_ci    } elsif (/^\s*$/) {
77062306a36Sopenharmony_ci    } else {
77162306a36Sopenharmony_ci	die
77262306a36Sopenharmony_ci"$0 : syntax error in line $lineno: $_
77362306a36Sopenharmony_ci	expected label:, ABSOLUTE, CLEAR, DISCONNECT, EXTERNAL, MOVE, RESELECT,
77462306a36Sopenharmony_ci	    SELECT SET, or WAIT
77562306a36Sopenharmony_ci";
77662306a36Sopenharmony_ci    }
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci# Fill in label references
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci@undefined = keys %forward;
78262306a36Sopenharmony_ciif ($#undefined >= 0) {
78362306a36Sopenharmony_ci    print STDERR "Undefined symbols : \n";
78462306a36Sopenharmony_ci    foreach $undef (@undefined) {
78562306a36Sopenharmony_ci	print STDERR "$undef in $forward{$undef}\n";
78662306a36Sopenharmony_ci    }
78762306a36Sopenharmony_ci    exit 1;
78862306a36Sopenharmony_ci}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci@label_patches = ();
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci@external_patches = ();
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci@absolute = sort @absolute;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ciforeach $i (@absolute) {
79762306a36Sopenharmony_ci    foreach $j (split (/\s+/,$symbol_references{$i})) {
79862306a36Sopenharmony_ci	$j =~ /(REL|ABS),(.*),(.*)/;
79962306a36Sopenharmony_ci	$type = $1;
80062306a36Sopenharmony_ci	$address = $2;
80162306a36Sopenharmony_ci	$length = $3;
80262306a36Sopenharmony_ci	die
80362306a36Sopenharmony_ci"$0 : $symbol $i has invalid relative reference at address $address,
80462306a36Sopenharmony_ci    size $length\n"
80562306a36Sopenharmony_ci	if ($type eq 'REL');
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	&patch ($address / 4, $address % 4, $length, $symbol_values{$i});
80862306a36Sopenharmony_ci    }
80962306a36Sopenharmony_ci}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ciforeach $external (@external) {
81262306a36Sopenharmony_ciprint STDERR "checking external $external \n" if ($debug_external);
81362306a36Sopenharmony_ci    if ($symbol_references{$external} ne undef) {
81462306a36Sopenharmony_ci	for $reference (split(/\s+/,$symbol_references{$external})) {
81562306a36Sopenharmony_ci	    $reference =~ /(REL|ABS),(.*),(.*)/;
81662306a36Sopenharmony_ci	    $type = $1;
81762306a36Sopenharmony_ci	    $address = $2;
81862306a36Sopenharmony_ci	    $length = $3;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	    die
82162306a36Sopenharmony_ci"$0 : symbol $label is external, has invalid relative reference at $address,
82262306a36Sopenharmony_ci    size $length\n"
82362306a36Sopenharmony_ci		if ($type eq 'REL');
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	    die
82662306a36Sopenharmony_ci"$0 : symbol $label has invalid reference at $address, size $length\n"
82762306a36Sopenharmony_ci		if ((($address % 4) !=0) || ($length != 4));
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	    $symbol = $symbol_values{$external};
83062306a36Sopenharmony_ci	    $add = $code[$address / 4];
83162306a36Sopenharmony_ci	    if ($add eq 0) {
83262306a36Sopenharmony_ci		$code[$address / 4] = $symbol;
83362306a36Sopenharmony_ci	    } else {
83462306a36Sopenharmony_ci		$add = sprintf ("0x%08x", $add);
83562306a36Sopenharmony_ci		$code[$address / 4] = "$symbol + $add";
83662306a36Sopenharmony_ci	    }
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ciprint STDERR "referenced external $external at $1\n" if ($debug_external);
83962306a36Sopenharmony_ci	}
84062306a36Sopenharmony_ci    }
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ciforeach $label (@label) {
84462306a36Sopenharmony_ci    if ($symbol_references{$label} ne undef) {
84562306a36Sopenharmony_ci	for $reference (split(/\s+/,$symbol_references{$label})) {
84662306a36Sopenharmony_ci	    $reference =~ /(REL|ABS),(.*),(.*)/;
84762306a36Sopenharmony_ci	    $type = $1;
84862306a36Sopenharmony_ci	    $address = $2;
84962306a36Sopenharmony_ci	    $length = $3;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	    if ((($address % 4) !=0) || ($length != 4)) {
85262306a36Sopenharmony_ci		die "$0 : symbol $label has invalid reference at $1, size $2\n";
85362306a36Sopenharmony_ci	    }
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	    if ($type eq 'ABS') {
85662306a36Sopenharmony_ci		$code[$address / 4] += $symbol_values{$label};
85762306a36Sopenharmony_ci		push (@label_patches, $address / 4);
85862306a36Sopenharmony_ci	    } else {
85962306a36Sopenharmony_ci#
86062306a36Sopenharmony_ci# - The address of the reference should be in the second and last word
86162306a36Sopenharmony_ci#	of an instruction
86262306a36Sopenharmony_ci# - Relative jumps, etc. are relative to the DSP of the _next_ instruction
86362306a36Sopenharmony_ci#
86462306a36Sopenharmony_ci# So, we need to add four to the address of the reference, to get
86562306a36Sopenharmony_ci# the address of the next instruction, when computing the reference.
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci		$tmp = $symbol_values{$label} -
86862306a36Sopenharmony_ci		    ($address + 4);
86962306a36Sopenharmony_ci		die
87062306a36Sopenharmony_ci# Relative addressing is limited to 24 bits.
87162306a36Sopenharmony_ci"$0 : symbol $label is too far ($tmp) from $address to reference as
87262306a36Sopenharmony_ci    relative/\n" if (($tmp >= 0x80_00_00) || ($tmp < -0x80_00_00));
87362306a36Sopenharmony_ci		$code[$address / 4] = $tmp & 0x00_ff_ff_ff;
87462306a36Sopenharmony_ci	    }
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci    }
87762306a36Sopenharmony_ci}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci# Output SCRIPT[] array, one instruction per line.  Optionally
88062306a36Sopenharmony_ci# print the original code too.
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ciopen (OUTPUT, ">$output") || die "$0 : can't open $output for writing\n";
88362306a36Sopenharmony_ciopen (OUTPUTU, ">$outputu") || die "$0 : can't open $outputu for writing\n";
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci($_ = $0) =~ s:.*/::;
88662306a36Sopenharmony_ciprint OUTPUT "/* DO NOT EDIT - Generated automatically by ".$_." */\n";
88762306a36Sopenharmony_ciprint OUTPUT "static u32 ".$prefix."SCRIPT[] = {\n";
88862306a36Sopenharmony_ci$instructions = 0;
88962306a36Sopenharmony_cifor ($i = 0; $i < $#code; ) {
89062306a36Sopenharmony_ci    if ($list_in_array) {
89162306a36Sopenharmony_ci	printf OUTPUT "/*\n$list[$i]\nat 0x%08x : */", $i;
89262306a36Sopenharmony_ci    }
89362306a36Sopenharmony_ci    printf OUTPUT "\t0x%08x,", $code[$i];
89462306a36Sopenharmony_ci    printf STDERR "Address $i = %x\n", $code[$i] if ($debug);
89562306a36Sopenharmony_ci    if ($code[$i + 1] =~ /\s*($identifier)(.*)$/) {
89662306a36Sopenharmony_ci	push (@external_patches, $i+1, $1);
89762306a36Sopenharmony_ci	printf OUTPUT "0%s,", $2
89862306a36Sopenharmony_ci    } else {
89962306a36Sopenharmony_ci	printf OUTPUT "0x%08x,",$code[$i+1];
90062306a36Sopenharmony_ci    }
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci    if (($code[$i] & 0xff_00_00_00) == 0xc0_00_00_00) {
90362306a36Sopenharmony_ci	if ($code[$i + 2] =~ /$identifier/) {
90462306a36Sopenharmony_ci	    push (@external_patches, $i+2, $code[$i+2]);
90562306a36Sopenharmony_ci	    printf OUTPUT "0,\n";
90662306a36Sopenharmony_ci	} else {
90762306a36Sopenharmony_ci	    printf OUTPUT "0x%08x,\n",$code[$i+2];
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci	$i += 3;
91062306a36Sopenharmony_ci    } else {
91162306a36Sopenharmony_ci	printf OUTPUT "\n";
91262306a36Sopenharmony_ci	$i += 2;
91362306a36Sopenharmony_ci    }
91462306a36Sopenharmony_ci    $instructions += 1;
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ciprint OUTPUT "};\n\n";
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ciforeach $i (@absolute) {
91962306a36Sopenharmony_ci    printf OUTPUT "#define A_$i\t0x%08x\n", $symbol_values{$i};
92062306a36Sopenharmony_ci    if (defined($prefix) && $prefix ne '') {
92162306a36Sopenharmony_ci	printf OUTPUT "#define A_".$i."_used ".$prefix."A_".$i."_used\n";
92262306a36Sopenharmony_ci	printf OUTPUTU "#undef A_".$i."_used\n";
92362306a36Sopenharmony_ci    }
92462306a36Sopenharmony_ci    printf OUTPUTU "#undef A_$i\n";
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci    printf OUTPUT "static u32 A_".$i."_used\[\] __attribute((unused)) = {\n";
92762306a36Sopenharmony_ciprintf STDERR "$i is used $symbol_references{$i}\n" if ($debug);
92862306a36Sopenharmony_ci    foreach $j (split (/\s+/,$symbol_references{$i})) {
92962306a36Sopenharmony_ci	$j =~ /(ABS|REL),(.*),(.*)/;
93062306a36Sopenharmony_ci	if ($1 eq 'ABS') {
93162306a36Sopenharmony_ci	    $address = $2;
93262306a36Sopenharmony_ci	    $length = $3;
93362306a36Sopenharmony_ci	    printf OUTPUT "\t0x%08x,\n", $address / 4;
93462306a36Sopenharmony_ci	}
93562306a36Sopenharmony_ci    }
93662306a36Sopenharmony_ci    printf OUTPUT "};\n\n";
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ciforeach $i (sort @entry) {
94062306a36Sopenharmony_ci    printf OUTPUT "#define Ent_$i\t0x%08x\n", $symbol_values{$i};
94162306a36Sopenharmony_ci    printf OUTPUTU "#undef Ent_$i\n", $symbol_values{$i};
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci#
94562306a36Sopenharmony_ci# NCR assembler outputs label patches in the form of indices into
94662306a36Sopenharmony_ci# the code.
94762306a36Sopenharmony_ci#
94862306a36Sopenharmony_ciprintf OUTPUT "static u32 ".$prefix."LABELPATCHES[] __attribute((unused)) = {\n";
94962306a36Sopenharmony_cifor $patch (sort {$a <=> $b} @label_patches) {
95062306a36Sopenharmony_ci    printf OUTPUT "\t0x%08x,\n", $patch;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ciprintf OUTPUT "};\n\n";
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci$num_external_patches = 0;
95562306a36Sopenharmony_ciprintf OUTPUT "static struct {\n\tu32\toffset;\n\tvoid\t\t*address;\n".
95662306a36Sopenharmony_ci    "} ".$prefix."EXTERNAL_PATCHES[] __attribute((unused)) = {\n";
95762306a36Sopenharmony_ciwhile ($ident = pop(@external_patches)) {
95862306a36Sopenharmony_ci    $off = pop(@external_patches);
95962306a36Sopenharmony_ci    printf OUTPUT "\t{0x%08x, &%s},\n", $off, $ident;
96062306a36Sopenharmony_ci    ++$num_external_patches;
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ciprintf OUTPUT "};\n\n";
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ciprintf OUTPUT "static u32 ".$prefix."INSTRUCTIONS __attribute((unused))\t= %d;\n",
96562306a36Sopenharmony_ci    $instructions;
96662306a36Sopenharmony_ciprintf OUTPUT "static u32 ".$prefix."PATCHES __attribute((unused))\t= %d;\n",
96762306a36Sopenharmony_ci    $#label_patches+1;
96862306a36Sopenharmony_ciprintf OUTPUT "static u32 ".$prefix."EXTERNAL_PATCHES_LEN __attribute((unused))\t= %d;\n",
96962306a36Sopenharmony_ci    $num_external_patches;
97062306a36Sopenharmony_ciclose OUTPUT;
97162306a36Sopenharmony_ciclose OUTPUTU;
972