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