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