#!/usr/bin/perl

# Convert SIMH RX01/RX02 images to disk images.

# The bytes are packed.  Each sector is 128 (RX01) 
# or 256 (RX02) bytes.  There are 77 tracks and 
# 26 sectors/track.

# This gives a size of 128*77*26 = 256256 bytes 
# for RX01, and 512512 bytes for RX02.

# The RX8E (in 12 bit mode) packs 64(128) 12 bit
# words into the first 96(192) bytes of a sector,
# then zeroes the last 32(64) bytes.

# This means a 256 word OS/8 block requires 4(2)
# sectors, 77*26/4(2) would give a theoretical 
# capacity of 500(1000) blocks.
# OS/8 has the size at 494(988) blocks.  What of 
# the other 6(12)?

foreach $f (@ARGV) {
  open(INPUT, $f) || die "$f: $!";
  binmode(INPUT);
  $flp = $f; $f =~ s/[.]rx0[12]$//;
  $f .= ".dsk";
  ($_, $_, $_, $_, $_, $_, $_, $size) = stat(INPUT);
  die "$flp: volume is not a floppy image" if $size % (77*16);
  $size /= 77 * 26; # Calculate sector size
  die "$flp: volume is not a floppy image"
    unless ($size == 128) || ($size == 256);
  $ds = $size * 3 / 4;
  $waste = $size / 4;
  # Interleave is 2 for RX01, but 3 for RX02!
  $ileave = 2 + ($size > 128);

# die "$f: exists" if -f $f;
  open(OUTPUT, ">$f") || die "$f: $!";
  binmode(OUTPUT);

  # The tracks are in the right order.
  # Skip the first 06400 bytes!
  # RX01: 26*76 = 1976 sectors.  1976 sectors == 494 OS/8 blocks.
  # RX02: 26*76 = 1976 sectors.  1976 sectors == 988 OS/8 blocks.
  for ($track = 1; $track < 77; $track++) {
    $tpos = $track * 26 * $size;
    for ($lsect = 0; $lsect < 26; $lsect++) {
      # Note: Sector numbering is traditionally 1..26, not 0..25.
      # We use 0..25 here to make the match easier.
      # Sectors are interleaved within the track.
      $psect = ($lsect*2) % 26 + ($lsect > 12) if $ileave == 2;
      $psect = ($lsect*$ileave) % 26 unless $ileave == 2;
#print "$lsect: $psect\n";
      $spos = $tpos + $psect * $size;
      seek(INPUT, $spos, 0) || die "seek($flp): $!";
      $count = read(INPUT, $buf, $ds);
      die "read($flp): $!" if $count < 0;
      last unless $count;
      die "read($flp): wrong count $!" if $count != $ds;
      @buf = unpack("C*", $buf);
      while (@buf) {
        $word1 = (shift(@buf) << 16) + (shift(@buf) << 8) + shift(@buf);
        $word2 = $word1 & 07777;
        $word1 = $word1 >> 12;
        print OUTPUT pack("SS", $word1, $word2);
      }
      $count = read(INPUT, $buf, $waste);
      die "read($flp): wrong count $!" if $count != $waste;
    }
  }
}
exit 0;
