Secondary storage is essential for most systems to hold programs for the long term. Attaching secondary storage to your system is a challenge, but a challenge worth investing time into. You can choose many different flavors of secondary storage to add to your system, and I have chosen to use a compact flash card that will provide almost limitless storage capability for the computer while maintaining a very simple 8-bit interface.
There are a lot of choices regarding 8-bit secondary storage mediums. From old technology to new technology it can be overwhelming to find one that will work without introducing a whole new set of complications. For instance SD Cards could be used if you can replicate the SPI protocol via the Z80, or a compact flash card could be used in its regular mode by introducing some extra circuitry in the form of latches to account for the default 16-bit mode ,but I want a much simpler interface. I would like to connect the medium right to the microprocessor, and talk directly to it for data exchange. This is where the compact flash card gets a bit interesting.
You see compact flash cards have been around a long time, and just like keyboards they need to incorporate a legacy mode to support older hardware. In keyboards, specifically USB keyboards the legacy mode is to fall back to a PS/2 mode to support all of those USB to PS/2 adapters everyone had when peripherals were making the switch to exclusively USB. The same can be said of the CF Card. Its legacy mode is 8-bit XT-IDE which was later the basis for ATA-1 (PATA/IDE). XT-IDE hardware is generally hard to find, so I am just glad that whoever has been keeping the compact flash specification in-check decided not to let go of this very useful yet outdated feature.
The compact flash card interface is exactly the same as normal except instead of using 16-bits of data the card exchanges 8-bits of data at a time. This is perfect for us since the Z80 can only handle 8 bits of data per transaction. So now it just comes down the how to connect the compact flash card to our system electrically. First we need an adapter to convert the CF card into IDE. These can be found online for under $10. This small piece of hardware is not necessary, but will save you quite the headache of breaking out all of those tiny pins CF cards need. The adapter is basically a pin-breakout of the CF card to a 40 pin IDE interface. The pin-out for this can be found here (https://en.wikipedia.org/wiki/Parallel_ATA). Most of the connections are generally not needed to get things going. What you will need at a minimum however are the connections seen below,
As seen above, all you need to hook up are the chip selects, three address lines, lower eight data lines, the I/O read/write control signals, and master reset control signal. In my design I mapped the CF card to I/O address $20 → $3F only needing the first 8 addresses for access to all of the CF cards registers. The above connections are all you need for the electrical side of things.
Although it is very easy to electrically connect the CF card to an 8-bit system, it is not so easy software-wise. To interface with the CF card we first must know the CF card’s registers, initialize the CF card, and finally read a sector of 512 bytes into a RAM buffer. Using LBA mode (because cylinder mode makes no sense) the registers are as follows,
The first register we will need is the features register for initialization. There are a whole set of features that can be implemented in a CF card to enable and disable certain features. We only need to concern ourselves with one feature $01 which enables 8-bit data transfers. Write the data value $01 to features register address $01 and then issue the set features command to set-up and enable this feature. To issue the set features command write the data value $EF to the command register address $07. The CF card should now be set-up for 8-bit data transfers.
The above might seem a bit awkward, but this is generally how the software will flow for CF cards, you will first setup some registers with bytes of data by writing to those registers, and then write another piece of data to the command register to issue a specific command that will work with the registers you setup earlier. (confused yet …?)
After initializing the CF card to ‘8-bit mode’ we can test out if everything is working by reading a sector from the card. If you have formatted the card then sector 0 normally will contains some data that we can read. If you read other sectors on a formatted card you will be reading all zeros which can become confusing for verification. I recommend before reading a sector from the card to plug the card into a Windows or Linux machine and use a Hex Editor like ‘HxD’ on Windows to read the hex data directly from sector 0 on the disk. (you can screen shot this data to compare what you read later on the Z80 side.)
To actually read the sector we need to setup sector count and LBA registers $02-$06. Sector count register $02 could be setup ahead of time during initialization since it only needs to be setup once. This register contains the number of sectors that you want to read or write at a time when issuing a read or write sector command. The sectors by default are normally 512 bytes a sector so I would just write $01 to this register as this is a lot of data to deal with. LBA registers $03-$06 need to contain the full 24 bit value that refers to the sector number that you want to access. Since we want to access sector 0 we will write the value $00 to LBA registers $03-$05, and the value $E0 to LBA register $06 to account for the leading three ones that specify LBA mode.
Once these registers are setup we can finally issue the read command $20 to the command register. Write the read command $20 to command register address $07 to initiate the sector read. When this has been done you can start reading sector 0’s data from data register address $00 into RAM one byte at a time. I use my hex dump command after I copy each byte from the sector to verify against the snapshot of the sector we made earlier in our hex editor on Windows.
What I did not explain above that is very important is to check the status register after you read or write anything to the CF card. I setup routines to handle this which can be seen in the CFDriver.asm code on my Github page. (LOOP_DAT_RDY / LOOP_CMD_RDY / LOOP_BUSY)
If all goes well you will be reading exactly what is in sector 0 on the CF card, and you should have a good idea as to how to implement other commands for a CF card in 8-bit mode. I will probably touch on other commands in my next post and start to polish out the code to do some more useful stuff. For now though this is a good step in the right direction and verifies that all of the hardware is solid. (even if it is still on a breadboard).
All Files from this project can be downloaded from my GitHub Repository,