Important detail on the disk "record number" counting mode

Juergen Buchmueller pullmoll at t-online.de
Sat Jun 16 23:17:14 PDT 2007


The INCRECNO operation is a little strange, which you will realize only
after carefully studying the schematics for the two shifters (74195) parts
#36 and #37 that implement it.

The initial state of recno after a KADR<- is 0, because both A inputs of the
shifters are tied to ground. KADR<- loads the shifters with these bits:
	#37 (LSB)	#36 (MSB)
	-----------------------------
	A = 0		A = 0
	B = BUS[13]	B = BUS[12]
	C = BUS[11]	C = BUS[10]
	D = BUS[9]	D = BUS[8]

The outputs are RECNO(0) = #37 QA, and RECNO(1) = #36 QA
RECNO(0) goes to J and K' of #36
RECNO(1) is inverted and goes to J and K' of #37

This is the reason for the following table:

 shift/   RECNO(0)    RECNO(1)     R/W/C presented
  load      #37         #36        to the drive
---------------------------------------------------
  load       0           0         HEADER
1st shift    1           0         LABEL
2nd shift    1           1         DATA
3rd shift    0           1         (none) 0 = read
[ 4th        0           0         (none) 1 = check ]
[ 5th        1           0         (none) 3 = write ]
[ 6th        1           1         (none) 2 = write ]

A 4th, 5th etc. shift (INCRECNO) should not happen, because the shifter
would then begin to shift the previous RECNO values to the QD
outputs of the shifter, while in theory its possible.

The INCRECNO could be implemented using an array like this:

void increcno(void)
{
	static int successor[4] = {1,3,0,2};
	recno = successor[recno];
}

The load KADR<- would remember the bus and reset recno to 0:

void load_kadr(void)
{
	kadr = bus;
	recno = 0;
}

And because of this sequence, the address modifier that is returned for RWC
depends on the current state of recno like this:

void rwc(void)
{
	/* map for read, check, write, write (yes, write = 2 or 3) */
	static int branch_map[4] = {0,2,3,3};

	switch (record) {
	case 0: /* KADR[8-9] HEADER read/write/check */
		branch = branch_map[(kadr >> 6) & 3];
		break;
	case 1: /* KADR[10-11] LABEL read/write/check */
		branch = branch_map[(kadr >> 4) & 3];
		break;
	case 2: /* 0,0 from recnod, which maps to READ */
		branch = 0;
		break;
	case 3: /* KADR[12-13] (DATA read/write/check) */
		branch = branch_map[(kadr >> 2) & 3];
		break;
	}
}

Now the "only" thing left to analyze is the timing between the records.
Some hints can be found in the microcode constants listings that Al
provided, i.e. the AltoConsts23.mu files cons_1.tiff to cons_7.tiff.

>From the comments there:

MIROBL: disk inter record read delay is 4 words
MRPAL: disk read postamble length is 3 words
MFROBL: disk header preamble is 34 words

It seems important to include these pre- and postambles in the timing for
the disk tasks, or you would most probably overrun them with data.

I think that the header preamble is the time between a sector start and the
first word of the header coming in, while the inter record read delay
suggests that there's a 4 words delay between HEADER and LABEL, LABEL and
DATA, and probably also after the DATA record and before the next sector
begins...

I'll report more details once I got this sorted out.


More information about the Altogether-devel mailing list