Hi all,
I'm working on a floppy driver, but I've run into some trouble. According to the intel docs, the only way to be able to get any data off the disc requires interrupts. Unfortunately, my OS can't use interrupts, and any attempt to use sti causes an exception in the emulator and forces real hardware into an immediate reboot. Can anyone suggest how I can get data off the floppy? (io ports only)
-ReKleSS
www.ca-osi.com
Floppy IO without BIOS and without ints
-
jamethiel
RE:Floppy IO without BIOS and without ints
This is definately possible. I do it in my OS. You may need DMA, however, depending on your computer (some systems don't support non-DMA operation).
The basic procedure is fairly straightforward. You just have to busy-wait on the FDC Status Register instead of waiting for an interrupt. I hope to be in a better position to explain tonight.
Dare I ask why your OS can't use interrupts?
The basic procedure is fairly straightforward. You just have to busy-wait on the FDC Status Register instead of waiting for an interrupt. I hope to be in a better position to explain tonight.
Dare I ask why your OS can't use interrupts?
-
ReKleSS
RE:Floppy IO without BIOS and without ints
Hi,
I can't use interrupts because a call to sti freezes up the whole box/emulator, for some reason. I suspect it has something to do with GRUB, but there's not really much I can do about it (although it does make sti good for resetting the computer). That, and I find interrupts difficult and annoying to do (linux, no setVect(), etc.).
-ReKleSS
I can't use interrupts because a call to sti freezes up the whole box/emulator, for some reason. I suspect it has something to do with GRUB, but there's not really much I can do about it (although it does make sti good for resetting the computer). That, and I find interrupts difficult and annoying to do (linux, no setVect(), etc.).
-ReKleSS
-
jamethiel
RE:Floppy IO without BIOS and without ints
Okay, I'm not entirely sure what is different between IRQ and non-IRQ operation, as I've never worked with a system that used FDC IRQs. I'm going to try to summarize my approach to working with the FDC, but I make no guarantees as to it's coherence or usefulness. I substituted constants suited for 1.44 meg floppies for all variables to do with floppy types. If you need to support different floppy types, you may need to change the values for what is written to port 0x3f7 during init, and the parameters for the SPECIFY and READ commands. If you need to support other than floppy drive A:, you will need to change the floppy motor on procedure and probably something else... I'm afraid I forget what.
When sending a command or reading a result from the FDC, you busy wait on port 0x3f4.
When 0x3f4 & 0x80 == 0x00, then the FDC is busy.
When 0x3f4 & 0xC0 == 0x80, then the FDC is expecting a command byte.
When 0x3f4 & 0xC0 == 0xC0, then the FDC has a result byte.
Basically, wait until 0x3f4 & 0x80 is 0x80, then signal an error if 0x3f4 & 0x40 isn't what you wanted.
The interesting commands are SPECIFY, Sense Interrupt Status (SIS), RECALIBRATE, and SEEK. We'll deal with READ and WRITE later...
To send the SPECIFY command, send the command byte sequence 0x03, 0xdf, 0x02.
To send the SEEK command, send the command byte sequence 0x0f, 0x00, and the track number that you wish to seek to as the third command byte.
To send the RECALIBRATE command, send the command byte sequence 0x07, 0x00.
After sending the SEEK or RECALIBRATE sequences, send the SIS sequence as follows:
To send SIS and wait for its result, send the command byte 0x08. Then read the first result byte when it is ready (this will be Disk Status Register 0). Next, wait for the next result byte (the FDC may sit in the "expecting command byte" state for a while while you're waiting, so don't error out if it happens), this will be the current track the disk is on (should be 0 if you issued RECALIBRATE, or whatever track you picked if you issued SEEK).
To turn the floppy drive motor off, write the value 0x00 to port 0x3f2.
To turn the floppy drive motor on, write the value 0x1c to port 0x3f2 and wait about 130/1000 of a second for the drive motor to spin up.
To initialize the FDC, do the following:
Turn the drive motor off.
Write the value 0x00 to port 0x3f7.
Write the value 0x0c to port 0x3f2.
Send the SPECIFY command.
To read the bootsector from a disk, do the following:
Initialize the FDC as above.
Turn the drive motor on.
Send the SIS command and wait for its result. Do it three more times.
Send the RECALIBRATE command, followed by the usual SIS sequence.
Set up the FDC DMA channel to recieve 512 bytes of data.
Send the following 9 command bytes: 0xc6, 0x00, 0x00, 0x00, 0x01, 0x02, 0x12, 0x1b, 0xff.
Wait for the FDC to have result bytes ready.
Read all the result bytes (there should be 7 of them).
Turn the floppy motor off.
If all went well, you just read the bootsector from the disk in the first floppy drive to wherever you put your DMA buffer.
These are the basics. You'll probably need the datasheet or a more comprehensive tutorial in order to get things working properly, but this should point you in the right direction. If you run into any problems or you need some more detailed explanation of some point, feel free to ask.
When sending a command or reading a result from the FDC, you busy wait on port 0x3f4.
When 0x3f4 & 0x80 == 0x00, then the FDC is busy.
When 0x3f4 & 0xC0 == 0x80, then the FDC is expecting a command byte.
When 0x3f4 & 0xC0 == 0xC0, then the FDC has a result byte.
Basically, wait until 0x3f4 & 0x80 is 0x80, then signal an error if 0x3f4 & 0x40 isn't what you wanted.
The interesting commands are SPECIFY, Sense Interrupt Status (SIS), RECALIBRATE, and SEEK. We'll deal with READ and WRITE later...
To send the SPECIFY command, send the command byte sequence 0x03, 0xdf, 0x02.
To send the SEEK command, send the command byte sequence 0x0f, 0x00, and the track number that you wish to seek to as the third command byte.
To send the RECALIBRATE command, send the command byte sequence 0x07, 0x00.
After sending the SEEK or RECALIBRATE sequences, send the SIS sequence as follows:
To send SIS and wait for its result, send the command byte 0x08. Then read the first result byte when it is ready (this will be Disk Status Register 0). Next, wait for the next result byte (the FDC may sit in the "expecting command byte" state for a while while you're waiting, so don't error out if it happens), this will be the current track the disk is on (should be 0 if you issued RECALIBRATE, or whatever track you picked if you issued SEEK).
To turn the floppy drive motor off, write the value 0x00 to port 0x3f2.
To turn the floppy drive motor on, write the value 0x1c to port 0x3f2 and wait about 130/1000 of a second for the drive motor to spin up.
To initialize the FDC, do the following:
Turn the drive motor off.
Write the value 0x00 to port 0x3f7.
Write the value 0x0c to port 0x3f2.
Send the SPECIFY command.
To read the bootsector from a disk, do the following:
Initialize the FDC as above.
Turn the drive motor on.
Send the SIS command and wait for its result. Do it three more times.
Send the RECALIBRATE command, followed by the usual SIS sequence.
Set up the FDC DMA channel to recieve 512 bytes of data.
Send the following 9 command bytes: 0xc6, 0x00, 0x00, 0x00, 0x01, 0x02, 0x12, 0x1b, 0xff.
Wait for the FDC to have result bytes ready.
Read all the result bytes (there should be 7 of them).
Turn the floppy motor off.
If all went well, you just read the bootsector from the disk in the first floppy drive to wherever you put your DMA buffer.
These are the basics. You'll probably need the datasheet or a more comprehensive tutorial in order to get things working properly, but this should point you in the right direction. If you run into any problems or you need some more detailed explanation of some point, feel free to ask.
-
DaveHK
RE:Floppy IO without BIOS and without ints
Interesting, When I started my OS, I used a floppy system that was interrupt driven, not DMA, because frankly, it's faster, the DMA on modern PCs has failed to develop in line with the rest of the hardware and is really a through back to 8086 days, doing floppy transfer via interrupts is faster, and I suspect that polled I/O will be of similar speed, however I eventually abandoned the scheme and now use a more conventional DMA approach, because, as you correctly noted earlier, some (indeed most in my experience) PCs do not support non-DMA operation. It worked fine on my intitial development PC, but as soon as I tried testing on other PCs, it fell flat on its face
-
jamethiel
RE:Floppy IO without BIOS and without ints
Oops. I misread my code for the SIS operation. It should be:
To send SIS and wait for its result, send the command byte 0x08. Then read the first result byte when it is ready (this will be Disk Status Register 0). Next, see if the controller has another result byte. If it does not, go back and re-send command byte 0x08 until it returns a second result byte. This second byte will be the current track the disk is on, and only appears if the drive head is not being moved (as by a SEEK or RECALIBRATE command).
Sorry about that.
To send SIS and wait for its result, send the command byte 0x08. Then read the first result byte when it is ready (this will be Disk Status Register 0). Next, see if the controller has another result byte. If it does not, go back and re-send command byte 0x08 until it returns a second result byte. This second byte will be the current track the disk is on, and only appears if the drive head is not being moved (as by a SEEK or RECALIBRATE command).
Sorry about that.
-
jamethiel
RE:Floppy IO without BIOS and without ints
Mmm... I might have figured it out sooner if the machine I was using when I started supported non-DMA operation, but instead I was confused for quite a while trying to figure out why code that apparently should have worked, didn't.
I was basing the driver source on a program I had written for someone else to control a standard PC FDC setup from a 6502-based system (no interrupts, no DMA), which worked. Timing was awful tight, but it worked.
And I couldn't test it on another machine because the source to more than half of the system was stored on the hard drive, and there was no practical way to copy it off... Last time I make -that- mistake.
I was basing the driver source on a program I had written for someone else to control a standard PC FDC setup from a 6502-based system (no interrupts, no DMA), which worked. Timing was awful tight, but it worked.
And I couldn't test it on another machine because the source to more than half of the system was stored on the hard drive, and there was no practical way to copy it off... Last time I make -that- mistake.
-
ReKleSS
RE:Floppy IO without BIOS and without ints
OK, I think I might have actually got it this time... I discovered it's possible to check for the INT signal through Status Register A, so I've got that figured out, but if I'm not using DMA, I get the data through the FIFO buffer (0x3F5), right?
-ReKleSS
-ReKleSS
-
jamethiel
RE:Floppy IO without BIOS and without ints
No! Don't go there, that's where the monster is hiding!
More seriously, yes. Same FIFO you sent your commands and data through. You still busy-wait on the usual status register, but it uses different status bits to indicate that the data on the FIFO is disk data rather than commands or results.
Still, however, you'd be better off with DMA. It's -far- more likely to work on whatever PC you encounter. And it's not exactly difficult to set up.
More seriously, yes. Same FIFO you sent your commands and data through. You still busy-wait on the usual status register, but it uses different status bits to indicate that the data on the FIFO is disk data rather than commands or results.
Still, however, you'd be better off with DMA. It's -far- more likely to work on whatever PC you encounter. And it's not exactly difficult to set up.