zigzagjoe
Well-known member
Early days, but I'm discovering some bits worth of note so I figured it's time for a worklog thread. I have been wanting to tinker with CF cards for a while, as the nice parallel bus should mate nicely to first PDS and later (with more work) NuBus. Due to the low complexity it should allow for good speeds.
Currently, I have built a prototype board and have bodged it to life. It's capable of 3 cycle reads and 4 cycle writes against a 16 bit CF, so this gives a theoretical maximum read speed of 6.27 MB/s into main memory (15666720 / ( 6 card cycles + 4 ram cycles) * 4 bytes) and 5.22 MB/s for writes. Subject to card's ability to sustain this. The card is being run with PIO-4 timings which every test card I've got is able to sustain.
At the moment 5 megabyte/s reads and 4 megabyte/s writes are possible, as measured by Norton System Info. Attached are some (almost legible) performance figures. Built-in SCSI tops out at 1.5MB/s, so it easily provides 3x the performance of a zuluscsi slim on the SCSI port. It's also beating Quadras' stock SCSI.
All measurements on the SE/30 are with one of my Booster 2.0 accelerators installed, though the stock CPU is not significantly slower since this is an IO-bound scenario. Both Quadras were running at 40mhz. I've just now got it booting off the CF card, which AFAIK makes this the first bootable PDS card that isn't a vintage design! It shaves a solid 7 seconds off the boot time of system 7.5.5, more than I was expecting.

How to make bootable PDS/Nubus cards.
An excerpt from DC&D is attached. Fundamentally, it requires a sRsrcBootRec (type=6) entry on the sResource for your device (not the board sResource with the inits!) which points to a SExecBlock just like the Inits. The flags on the sResource must also have fOpenAtBoot set.
This BootRec entry will be executed at two times, potentially.
1) At early boot, after primaryInit, IF PRAM is appropriately set to point to this card as a bootable device
2) After SecondaryInit, after OS patches are loaded and before extensions
If bootrec is present, mac os will never open the driver under any circumstances, as it would otherwise do. You are responsible for doing that in the BootRec!
I haven't quite found documentation supporting this: if your driver is being loaded at boot it should not call PBMountVol, this will crash the system. The ROM will (try?) to mount it for you. If your driver is being loaded later (new drive number != 1), then you should mount it in the driver code. Remains to be seen if floppy boot is still possible, or what happens if the drive is not bootable.
Here's some sample code. Barely tested: I only just got this working a little bit ago!
You'll notice a catch 22 above, if you clear PRAM you will not be able to boot from your card! However, I think with some hueristics in primaryInit to detect empty PRAM it will be possible to fix this in a reasonably sane & user friendly manner. More testing needs to be done to make sure floppy boot still works with card boot, and similar permutations... and test the SE/30 ROM, and more.... much work remains.
Initialization (partitioning) will present a particular issue too. But, this I think I could carefully bundle some basic functionality in to the card. I particularly want to support the case where an existing hard drive image (i.e used by ZuluScsi, PiSCSI, BlueScsi, etc) can be directly copied to the card (dd) and have it just work as that's my use case
Other points of interest:
Partition support is tied to the SCSI manager, so your driver needs to understand partition maps if you want to support multiple volumes. And also handle this in the Prime routine.
Documentation surrounding Control/Status codes used by disk drives also seem to be MIA, my list is attached from working through SuperMario sources.
If you want to have "fast" formatting of the drive, you must support both Format and Verify Control calls (verifyCC, formatCC) but you just need to return noErr. Otherwise, mac OS will instead write every sector.
All of this is HIGHLY experimental, so take with a grain of salt.
Currently, I have built a prototype board and have bodged it to life. It's capable of 3 cycle reads and 4 cycle writes against a 16 bit CF, so this gives a theoretical maximum read speed of 6.27 MB/s into main memory (15666720 / ( 6 card cycles + 4 ram cycles) * 4 bytes) and 5.22 MB/s for writes. Subject to card's ability to sustain this. The card is being run with PIO-4 timings which every test card I've got is able to sustain.
At the moment 5 megabyte/s reads and 4 megabyte/s writes are possible, as measured by Norton System Info. Attached are some (almost legible) performance figures. Built-in SCSI tops out at 1.5MB/s, so it easily provides 3x the performance of a zuluscsi slim on the SCSI port. It's also beating Quadras' stock SCSI.
All measurements on the SE/30 are with one of my Booster 2.0 accelerators installed, though the stock CPU is not significantly slower since this is an IO-bound scenario. Both Quadras were running at 40mhz. I've just now got it booting off the CF card, which AFAIK makes this the first bootable PDS card that isn't a vintage design! It shaves a solid 7 seconds off the boot time of system 7.5.5, more than I was expecting.

How to make bootable PDS/Nubus cards.
An excerpt from DC&D is attached. Fundamentally, it requires a sRsrcBootRec (type=6) entry on the sResource for your device (not the board sResource with the inits!) which points to a SExecBlock just like the Inits. The flags on the sResource must also have fOpenAtBoot set.
This BootRec entry will be executed at two times, potentially.
1) At early boot, after primaryInit, IF PRAM is appropriately set to point to this card as a bootable device
2) After SecondaryInit, after OS patches are loaded and before extensions
If bootrec is present, mac os will never open the driver under any circumstances, as it would otherwise do. You are responsible for doing that in the BootRec!
I haven't quite found documentation supporting this: if your driver is being loaded at boot it should not call PBMountVol, this will crash the system. The ROM will (try?) to mount it for you. If your driver is being loaded later (new drive number != 1), then you should mount it in the driver code. Remains to be seen if floppy boot is still possible, or what happens if the drive is not bootable.
Here's some sample code. Barely tested: I only just got this working a little bit ago!
C:
#pragma parameter __D0 BootRec(__A0)
UInt32 BootRec(SEBlock* seblock) {
Ptr a32 = (Ptr) (0xF0000000 | ((UInt32)seblock->seSlot << 24));
seblock->seStatus = 1; // code was executed
dbg_labelhexl("BootRec seBootState",seblock->seBootState); // 0 = early boot, 1 = secondaryInit
OSErr ret;
SlotDevParam pb;
char name[] = driverNamePascal;
// lifted from SuperMario/Patches/VideoPatch.a #1006-1013
pb.ioSlot = seblock->seSlot;
pb.ioID = sRsrc_CFDisk; // your sResource ID containing the bootrec and driver
pb.ioNamePtr = (StringPtr)&driverNamePascal; // (length of string).Driver_Name, must have the period denoting driver
pb.ioSFlags = 0;
pb.ioSPermssn = 0;
pb.ioSMix = nil;
ret = PBHOpen((HParamBlockRec*)&pb, false /* not async */);
dbg_labelhexl(" HOpen", ret);
if (ret == noErr) { // return refnum of driver
dbg_labelhexl(" ioSRefNum", pb.ioSRefNum);
return pb.ioSRefNum;
} else
dbg_prints("Failed to open drvr in BootRec\n");
return 0;
}
You'll notice a catch 22 above, if you clear PRAM you will not be able to boot from your card! However, I think with some hueristics in primaryInit to detect empty PRAM it will be possible to fix this in a reasonably sane & user friendly manner. More testing needs to be done to make sure floppy boot still works with card boot, and similar permutations... and test the SE/30 ROM, and more.... much work remains.
Initialization (partitioning) will present a particular issue too. But, this I think I could carefully bundle some basic functionality in to the card. I particularly want to support the case where an existing hard drive image (i.e used by ZuluScsi, PiSCSI, BlueScsi, etc) can be directly copied to the card (dd) and have it just work as that's my use case
Other points of interest:
Partition support is tied to the SCSI manager, so your driver needs to understand partition maps if you want to support multiple volumes. And also handle this in the Prime routine.
Documentation surrounding Control/Status codes used by disk drives also seem to be MIA, my list is attached from working through SuperMario sources.
If you want to have "fast" formatting of the drive, you must support both Format and Verify Control calls (verifyCC, formatCC) but you just need to return noErr. Otherwise, mac OS will instead write every sector.
All of this is HIGHLY experimental, so take with a grain of salt.