#!/usr/bin/perl # # Copyright © 2015-2020 by Vincent Slyngstad # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS LISTED ABOVE BE LIABLE # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the names of the authors above # shall not be used in advertising or otherwise to promote the sale, use # or other dealings in this Software without prior written authorization # from those authors. # # Given a BIN format image, create the corresponding 2764 ROM image # needed by the DECmate III. # # # First, read in the BINary. # # Issue: Many of the DEC tapes have the location bit set in # their checksums, so we allow that. open(INPUT, $ARGV[0]) || die "$ARGV[0]: $!"; binmode(INPUT); @core1 = (); $loc = $store = undef; $sum = $add = $field = 0; while (read(INPUT, $top, 1)) { $top = unpack("C", $top); next if $top == 0200; # Leader or Trailer last if $top == 0232; # End of file # It isn't trailer. That implies time to store the previous word # if any. if (defined($store)) { $core1[$field*4096+$loc] = $store; $max = $field*4096+$loc unless $max > $field*4096+$loc; $store = undef; $loc = ($loc + 1) & 07777; $sum += $add; $fortran = 0; } if ($top & 0200) { # Better be field setting! die "$ARGV[0]: Invalid field setting" unless $top >= 0300; die "$ARGV[0]: Invalid field setting" if $top & 0007; $fortran = 1 if $top == 0340; $field = ($top & 070) >> 3; next; } # Read and verify the format of the bottom half. read(INPUT, $bot, 1) || die "$ARGV[0] read: $!"; $bot = unpack("c", $bot); die "$ARGV[0]: ".$bot." not in bin format ". tell(INPUT) unless $bot <= 077; # Assemble the word, and figure out the checksum update. $word = ($top << 6) + $bot; $add = $top + $bot; # Update checksum # If the word has the 010000 bit set, it's a location setting. if ($word > 07777) { # # Change location counter $loc = $word & 07777; #printf "Loc == %04o\n", $loc; $sum += $add; } else { die "$ARGV[0]: no location counter" unless defined($loc); $store = $word; } } close(INPUT); if ($fortran) { die "$ARGV[0]: 4K Fortran Binary\n" if $fortran; $sum += 0640; # 4K Fortran loader counts 0300 and 0340 } if (!defined($store)) { # This is that weird case where the checksum has location bit set! $store = $loc; $sum -= $add; } $sum &= 07777; printf "$ARGV[0]: Checksum is %04o, not %04o\n", $sum, $store if $sum != $store; #printf STDERR "$ARGV[0]: Checksum is %04o, not %04o\n", $sum, $store if $sum != $store; # # Check for loading outside the ROMs! # for ($loc = 000000; $loc < 070000; $loc++) { next unless defined $core1[$loc]; printf "%05o)%04o is outside ROM\n", $loc, $core[$loc]; $status = 1; } # # At this point @core1 contains the program. # Dump the ROM in an appropriate format.. # $status = 0; $f = $ARGV[0]; $f =~ s/[.]bin//; die if $f eq $ARGV[0]; # Do not over-write input! open(ROM, ">$f") || die "$f: $!"; binmode(ROM); for ($loc = 070000; $loc <= 077777; $loc++) { $byte = $core1[$loc] >> 8; $byte |= $byte << 4; # Replicate the nibble printf ROM "%c", $byte; } for ($loc = 070000; $loc <= 077777; $loc++) { $byte = $core1[$loc] & 0377; printf ROM "%c", $byte; } exit $status;