Diablo-drives are central components for the RC3600/RC7000 computers, but suffer from a tendency to head-crash, which given our finite and limited number of spare-parts, in particular disc cartridges, makes it impossible for us to construct a RC3600 system for frequent demonstration and use.
The idea behind this project is to modify a drive to neutralize the head-crash issue, while retaining as much as possible of the tangible experience of the Diablo-drive, from cartridge load/unload to the rattle and hum of the operating drive.
(We obviously also want to have fully functional diablo-drives, if nothing else for data-preservation, but these drives should be used only sparingly and generally protected).
The plan is to take a non-functioning Diablo-drive and augment its electronics with a small ARM-based computer which takes over the data-storage task.
Strategy and Ambitions
The Turbo-diablo should have three modes:
1) Mechanically active.
2) Mechanically inactive, simulated authentic timing.
3) Turbo-mode, eliminating seek-times etc.
If possible, the Turbo-diablo should be able to simulate multiple drives at the same time.
A USB "back-door" will allow up/download of disk images.
It should be possible to select from multiple stored disk-images without attaching a computer.
Diablo-drives, an overview
Up to four diablodrives can be connected to the daisy-chain bus which connects them to the computer.
Each drive consists of three almost independent subsystems:
Cartridge & Rotation
Load/Unload of cartridge, spin-up/down, speed-servo, write-protect, index marker & sector numbers.
Bus-output: Index-pulses og 5-bit sector-numbers.
Head load/unload, servo-motor, drive-ready.
Bus-input: 8-bit binary cylinder-number, various handshake lines
Bus-output: Ready output
Read/write and erase heads, their drivers and amplifiers, clock/data separators.
Bus-input: Head select, write gate, write clock+data
Bus-output: Read clock, read data, write-error
The Diablo-drives comes in a large number of variants, the important ones in this context are: 12 sectors, 1440 kbit/sec.
Bits & Pieces
- ARM computer STM32-H407 from Olimex.
- RTOS ChibiOS by Giovanni DiSirio
Read data production
Producing the data and clock signals from which the computer will "read" the disk must happen continuously, as we have no way of knowing when the computer pays attention to the signals.
The total number of bits per track is given by the bitrate and the speed of rotation: 1.44 MHz / 1500 RPM = 57600 bits/track.
The simple way to do this, is simply to build an array of 57600 bytes, and DMA them to a GPIO port at a rate of 1,440,000 bytes a second.
This gives us a total of 8 bit-rate signals which we can use as follows:
- two data signals (side 0/1)
- two index pulses
- 4-bit sector address number
The clock signal and the data signal er both pulse based, the clock pulse happens between bit-cells, the data pulses happen approximately in the middle of the bit-cells.
Producing the clock signal using the counters PWM facility is trivial, and the data-gate can be created by combining two PWM signals.
This code has been prototyped.
Write data capture
This is more tricky, and still under study.
The data and clock signals arrive from the computer as pulses on a single line and need to be separated either in hardware or software.
Separating them in software requires us to sample the signal fast enough to resolve the timing.
If we divide the pulse-stream by two we get the same signal which would normally be written to the disk, consisting of full and half bit periods, and sampling at a rate of four times the bitrate would be necessary to resolve the split bit-cells.
The bitstream can probably be deserialized with the ARM's SPI peripheral and will require approx (4 * (57600/12) / 8) = 2400 bytes of RAM for a single sector.
Extracting the data bits from this bit stream will require a fair bit of processing, and it is not immediately obvious that we will be able to handle back-to-back sector writes.
Another option is to measure the timing of the individual pulses using a TIMER peripherals "capture" facility. Since we capture all the pulses, worst case RAM usage is 9600 timestamps of 16 bits or 19200 bytes of RAM.
Extracting the data bits should just be a question of thresholding the inter-pulse intervals.
Separating clock and data in hardware requires a somewhat involved circuit which would ordinarily be unattractive, but exactly such a circuit sits pre-trimmed and ready to be used in the Diablo-drives read-electronics.
The resulting separated clock+data stream can be captured with the SPI peripheral running in slave mode, into a buffer of only ((57600/12) / 8) = 600 bytes.
Extracting the data bits amounts to finding the first one-bit and shifting the next 4096 bits into position in 512 bytes.
That is going to be my first attempt.
There is only one opto-sensor for both index and sector pulses which are separated by a one-shot (J9-D35) which turns the second of two closely spaced pulses into an index pulse.
Both the Index and Sector pulses are used for the spindle-speed servo-loop, so we cannot disconnect them from the actual rotation.
The separated Index & Sector pulses are tranferred to J8, which has the sector counter and the interface driver for the Index pulse.
It seems that the best place to hook in is between the two cards, that minimizes wiring since we get the sector counter for free, and it puts us after the one-shots which depend on the number of sectors per cylinder.
Index pulse from J9-4 to J8-5 is positive pulse, 5µs wide.
Sector pulse from J9-3 to J8-3 is positive pulse, 5µs wide.
Played around with the ARM and the sacrificial Diablo drive.
First experiment was hooking the separated clock and data to a 7474 to stretch the data pulse so that the leading flank of the clock pulse can sample it, that worked fine.
Ran into a pin-multiplexing conflict on the ARM: The SPI1 and TIMER8 are of course multiplexed to the exact same pins.
Went over the entire pin-assignment table a couple of times and but didn't find the solution until I woke up this morning:
Run TIMER8 "center" mode and twice as fast. This allows us to generate the data strobe and clock signals directly on only two outputs, rather than the tree+gates previously planned. The crucial trick is that the Update event from TIMER8 can be cut in half with the RCR register, so that the DMA buffer does not need to be twice as long.
Moved the DMA->GPIO port from PORTE to PORTG, so that all the connections we will need are available on the "Arduino" connectors, this will make the mechanics simpler.
Studied the Data/head multiplexing, and decided that a 74157 (or 74158, depending on polarity) will do the job nicely: Select = Head, Enable = Data strobe.
So it looks like we can fit it all on an Arduino Shield with just two TTL chips.
Tried out my "exerciser" program on the real RC3600 and did a lot of seeks on the diablo-drive to measure the seek-times.
Got the SPI port on the ARM to function in programmed-IO mode, using input signals from the DMA port.
Managed to capture three sectors off the disk yesterday, proving that the SPI-port idea works.
This capture allowed me to verify that the CRC is the same as the DGC Floppy/Diablo controller which I previously reverse-engineered.
My "almost too easy" idea for capturing the write data stream however does not work: The write circuit overloads the read amplifiers and nothing useful comes out.
Next attempt: Feed the TTL-level write data directly to the data-separator at digital levels.
Tonight I changed the SPI code to use DMA, this seems necessary to keep up with the SPI port, programmed IO was too slow and overran a couple of times in the captured disk-data.