Sunday, June 12, 2016

Converting LU Disc Drivers for SimH Nova

This page is a part of the "Understanding IRIS" collection.  Many thanks to David Takle, for figuring this out, and sharing this with us:

-----------------------------------------------------------

Turns out that I now that with a few minor changes, we can create an IRIS driver for any of the disk drives supported by simH.
So whenever it is possible to match up the driver being used by IRIS with a supporting drive that uses the same number of sectors per track and has at least as many tracks per cylinder, that means we can migrate the system without moving or expanding DMAP, which is the biggest problem in the whole thing.

Turns out that the 6103 drive is a perfect replacement for the IRIS on your CC tapes.
It could be configured with 16 sectors per track, and 16 tracks per cylinder.

By overlaying the driver in IRIS in the REX file and in the boot sector, it ought to be possible to boot without hardly any other IRIS modifications.
And given that we already have a running IRIS system with which to manipulate another drive, it might not be too strenuous at all.


I'm attaching the PHP program I used to convert LUs 1,2,3,4. You can see from that the kind of challenges that have to be overcome to move the DMAP file without breaking the LU. But keep in mind that LU0 is even more difficult.

---------------------------------------------------------------------

<?php
// conv-c114-lux.php === convert data LUx for Century 114

$logicalUnit = 1;  // MODIFY
$dmapNBLK = octdec('011');

// location of DMAP in INDEX, and where it needs to go
$dmapEntry = array('current'=>'041000', 'target'=>'0100');

// for moving other INDEX entries // set to NULL if not needed
$iEntryMove = array (  
'012040'=>'0110',
'013400'=>'0120',
'042030'=>'0130',
'052400'=>'0140',
);
// $indexMove = NULL;

// for moving INDEX blocks
$indexMOVE = array(   
'014'=>'035',
'015'=>'041',
'016'=>'0115',
'017'=>'0136'
);

//================================================
// constants for IRIS / Centry 114
$LUxfile = "f:\\www\\nova\\iris" . $logicalUnit . "c.dkp";
$LUx = fopen($LUxfile, "r+b");

$xLRCD = octdec('014') + 1;
$dmapLRCD = octdec('026');

$xNRPB = octdec('015') + 1;
$dmapNRPB = octdec('013');

$xNBLK = octdec('011') + 1;
$xNRCD = octdec('016') + 1;
$x7 = octdec('07') + 1;
$x177 = octdec('0177') + 1;
$x200 = octdec('0200') + 1;
$x213 = octdec('0213') + 1;
$x377 = octdec('0377') + 1;
$dmapHdr = octdec('014');
$zero = pack('v', 0);  // single word
$blockZero = array();
for ($x=1; $x<=256; $x++) {
$blockZero[$x] = 0;
}

//=================================================

// Get INDEX header
$IHDR = readBlock (1);

// fix DMAP entry in INDEX
$HRDA = pack('v', $dmapHdr); // header block rda
if ( $dmapEntry['current'] == $dmapEntry['target'] )  {
// not moving anywhere, just need to update
$seekAddr = convertIndexAddr2Seek( $dmapEntry['current'] );
} else {
$seekAddr = moveIndexEntry( $dmapEntry['current'], $dmapEntry['target'] );
}
$seekAddr += 14;
fseek($LUx, $seekAddr);
fwrite($LUx, $HRDA);

// move index entries to open up blocks
if ($iEntryMove) {
foreach ( $iEntryMove as $from=>$to ) {
$seekAddr = moveIndexEntry( $from, $to );
}
}

// fix index header
// shift header blocks back
for ($i=$x213; $i<=$x377; $i++) {  
$IHDR[$i-4] = $IHDR[$i];
}
$IHDR[256] = 0;
$IHDR[255] = 0;
$IHDR[254] = 0;
$IHDR[253] = 0;
// fix NBLK and NRCD
$IHDR[$xNBLK] = $IHDR[$xNBLK] - 4;
$IHDR[$xNRCD] = $IHDR[$xNRCD] - octdec('0200');
rewriteBlock($IHDR, 1);

// move INDEX blocks needed by DMAP
foreach ($indexMOVE as $from=>$to) {
// read
$blkDisp = octdec($from) * 512;
fseek($LUx, $blkDisp);
$Iblock = fread($LUx, 512);
// write
$blkDisp = octdec($to) * 512;
fseek($LUx, $blkDisp);
fwrite($LUx, $Iblock);
}

// move DMAP header back from installed location
$DHDR = readBlock( octdec('020') );
// fix internal header info
$DHDR[$xNBLK] = $dmapNBLK;
$DHDR[$xLRCD] = $dmapLRCD;
$DHDR[$xNRPB] = $dmapNRPB;
// fix block#s
for ($b=$x177; $b<=$x377; $b++) {
$DHDR[$b] = 0;
}
$Blk = $dmapHdr;
$b = $x177;
for ($x=1; $x<=$dmapNBLK; $x++) {
$DHDR[$b] = $Blk;
$Blk++;
$b++;
}
rewriteBlock($DHDR, $dmapHdr);

// get all existing account IDs
$idSystem  = octdec('0140000');
$idManager = octdec('0100001');
$idOther = array();
$AcctHdr = readBlock(3);
$AcctRda = $AcctHdr[$x200];
$AcctBlock = readBlock($AcctRda);
for ($rec=0; $rec<=256-16; $rec=$rec+16) {
$inUse = $AcctBlock[$rec+1];
if (!$inUse) continue;
$AcctNum = $AcctBlock[$rec+9];
$idOther[] = $AcctNum;
if ($AcctNum > 32768)
$AcctBlock[$rec+9] = $AcctNum - 16384;
}
// now fix account priviledge levels
for ($ix=$x200; $ix<=$x377; $ix++) {
$RDA = $IHDR[$ix];
if ($RDA == 0) break;
$Iblock = readBlock($RDA);
for ($row=0; $row<=256-8; $row=$row+8) {
$name = $Iblock[$row+1];
if ($name == 0) continue;
$hdr = $Iblock[$row+8];
$HDR = readBlock($hdr);
$self = $HDR[$x177];
$ACCT = $HDR[$x7];
if ($self != $hdr) die("block does not match index: $self");
if ($ACCT < 32768) continue; // low protect
if ($ACCT == $idSystem or $ACCT == $idManager) continue;
$lowID = $ACCT - 16384;
$newID = pack('v', $lowID);
$blkDisp = $hdr * 512 + 14;  // location to replace ACCT
fseek($LUx, $blkDisp);
fwrite($LUx, $newID);
}
}
rewriteBlock($AcctBlock, $AcctRda);

fclose($LUx);
exit;

function readBlock ($rda) {
global $LUx;
$seek = $rda * 512;  // displk of block on IRIS
fseek($LUx, $seek); // position drive
$block = fread($LUx, 512); // read block
$array = unpack('v*', $block);
return $array;
}
function rewriteBlock($array, $rda)  {
global $LUx;
$update = '';
foreach ($array as $cell) {
$update .= pack('v', $cell);
}
fseek($LUx, $rda * 512); // block displ
fwrite($LUx, $update);
}

function moveIndexEntry($octFrom, $octTo)  {
global $LUx, $zero;
$seekFrom = convertIndexAddr2Seek($octFrom);
$raw = fread($LUx, 16);  // index entry
$seekTo = convertIndexAddr2Seek($octTo);
fwrite($LUx, $raw);  // index entry
// erase old entry
fseek($LUx, $seekFrom);
fwrite($LUx, $zero);  // index entry
return $seekTo; // return new address
}

function convertIndexAddr2Seek ($octAddr) {
global $LUx, $IHDR;
$decAddr = octdec($octAddr);
$blkRel = floor($decAddr / 256); // Block# relative to Index file
$entryDispl = $decAddr - $blkRel * 256;  // displ into block (in words)
$RDA = $IHDR[129 + $blkRel]; // rda containing entry
$seekLoc = $RDA * 512 + $entryDispl * 2;
fseek($LUx, $seekLoc);
return $seekLoc;
}

function xdisplay($block) {
echo '<pre>';
for ($row=0; $row<=256-8; $row=$row+8) {
$address = decoct($row);
echo '<br>' . $address . ': ';
for ($cell=0; $cell<=7; $cell++) {
$value = $block[$row+$cell+1];
$octal = decoct($value);
$len = strlen($octal);
$listing = substr("       " . $octal, $len);
echo $listing . '  ';
}
}
echo '</pre>';
}
?>

------------------------------------------------------------------------------------

This page is a part of the "Understanding IRIS" collection.  

No comments:

Post a Comment