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