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