I'm having one heck of a time trying to emulate this thing.
How in the world does the disk drive transfer bytes to and from the RAM adapter?
Starting with the .fds format, we'll first lop off the optional (not in No-Intro) 16-byte fwNES header, for a 65500 byte file.
We get numbered, ... blocks? 01 {info}, 02 {file count}, 03 {file header}, 04 {file data}, 03 {file header}, 04 {file data}, ...
The wiki further says that the actual raw disks have large gaps between blocks. ~28300 bits on the first block, then ~976 bytes on the rest. All gap bytes are 0x0, and each gap ends with a 0x80 byte. Yet when I look at Hubz' .bin FDS dumps, I see 0x709 bytes of pre-gap before the first track, which is half of the minimum bits before the first track per NESdev wiki.
Further, the wiki says that even WITH the gaps, the actual capacity is 65500 bytes. Yet Hubz' .bin dumps are larger than 65500 bytes. Usually 67000 bytes. It varies per game.
The .raw dumps are over 400KiB and kind of terrify me. I think that's too low-level for me right now ...
I am told it takes ~6 seconds for the motor to scan across the entire disk side. So at 21477272hz crystal clock, that's ~1967 clock cycles per byte read.
The BIOS starts up and starts writing to $4025:
#$2e
#$2e
#$2f
#$2d
#$2e
#$2f
#$2d
#$6d
#$ed
At this point, it expects an interrupt to fire on each byte read, and if it doesn't start reading the first track (01 2a 4e 49 ...), it will return disk error 22.
So from this, I gather than $4025.d0 must be set to transfer data, and that $4025.d6 must also be set. It doesn't actually put a read byte into $4031 and set the byte transferred flag in $4030 unless it's a real byte and not a gap byte (0x00 or 0x80).
The BIOS then happily continues reading along data, accepting IRQs, until reading one past the end of the first block, eg it reads (01 2a ... ff ff ff ff ff 00 00 00 00 02). After that it writes #$fd to $4205, clearing the CRC counter. And now it writes #$2d, #$6d, #$ed back to $4205. And now it expects the next IRQ transfer byte to be #$02 that it already read before, otherwise you get disk error 23.
My thinking is ... we have to emulate the gaps. The last byte of track 1 should be a gap byte, and get discarded. Yet it somehow must fire an interrupt as a transferred byte to stop the BIOS from waiting on the next valid byte, #$02 ...
So as a cheap hack, I made it so writing $4205.d7=1 will subtract the .fds disk data by 1 if it's not zero. Then we get this:
$4205 = fd
read 02
$4205 = 2d, 6d, ed
read 02
read 07
read 03
<okay, it read block two to get the total number of files>
$4205 = fd
read 03
$4205 = 2d, 6d, ed
read 03, 00, 00, 4b, 59, 4f, 44, 41, 4b, 55, 2d
<reads the file name and then stops>
$4205 = ed
reads 2d
$4205 = ed
reads 2d
$4205 = ed
reads 2d, 00, 28
$4205 = fd
reads 28
$4205 = 2d, 6d, ed
reads 28 <it's expecting 04 here most likely>
It resets $4205.d0 (restarting the drive motor), re-reads the disk error, and then now I get disk error 25.
I'm at a loss. Does anyone emulate the FDS at a lower level than HLE BIOS hooks?
Does the motor actually pause and stop reading more disk data when $4205.d6 is clear?
If you turn the motor off and on again, does this reset the motor head to the outer edge (start) of the disk, or does it still have to wait for the entire disk to be scanned before starting over again?
Once the entire disk is scanned, does it disable the motor at that point?
Are the checksums relevant in any way? I see Mesen hooks bus address reads in the BIOS to simulate things via HLE, and performs CRC calculations in there ...
Anything else I should know, any insights anyone could share? :/
How in the world does the disk drive transfer bytes to and from the RAM adapter?
Starting with the .fds format, we'll first lop off the optional (not in No-Intro) 16-byte fwNES header, for a 65500 byte file.
We get numbered, ... blocks? 01 {info}, 02 {file count}, 03 {file header}, 04 {file data}, 03 {file header}, 04 {file data}, ...
The wiki further says that the actual raw disks have large gaps between blocks. ~28300 bits on the first block, then ~976 bytes on the rest. All gap bytes are 0x0, and each gap ends with a 0x80 byte. Yet when I look at Hubz' .bin FDS dumps, I see 0x709 bytes of pre-gap before the first track, which is half of the minimum bits before the first track per NESdev wiki.
Further, the wiki says that even WITH the gaps, the actual capacity is 65500 bytes. Yet Hubz' .bin dumps are larger than 65500 bytes. Usually 67000 bytes. It varies per game.
The .raw dumps are over 400KiB and kind of terrify me. I think that's too low-level for me right now ...
I am told it takes ~6 seconds for the motor to scan across the entire disk side. So at 21477272hz crystal clock, that's ~1967 clock cycles per byte read.
The BIOS starts up and starts writing to $4025:
#$2e
#$2e
#$2f
#$2d
#$2e
#$2f
#$2d
#$6d
#$ed
At this point, it expects an interrupt to fire on each byte read, and if it doesn't start reading the first track (01 2a 4e 49 ...), it will return disk error 22.
So from this, I gather than $4025.d0 must be set to transfer data, and that $4025.d6 must also be set. It doesn't actually put a read byte into $4031 and set the byte transferred flag in $4030 unless it's a real byte and not a gap byte (0x00 or 0x80).
The BIOS then happily continues reading along data, accepting IRQs, until reading one past the end of the first block, eg it reads (01 2a ... ff ff ff ff ff 00 00 00 00 02). After that it writes #$fd to $4205, clearing the CRC counter. And now it writes #$2d, #$6d, #$ed back to $4205. And now it expects the next IRQ transfer byte to be #$02 that it already read before, otherwise you get disk error 23.
My thinking is ... we have to emulate the gaps. The last byte of track 1 should be a gap byte, and get discarded. Yet it somehow must fire an interrupt as a transferred byte to stop the BIOS from waiting on the next valid byte, #$02 ...
So as a cheap hack, I made it so writing $4205.d7=1 will subtract the .fds disk data by 1 if it's not zero. Then we get this:
$4205 = fd
read 02
$4205 = 2d, 6d, ed
read 02
read 07
read 03
<okay, it read block two to get the total number of files>
$4205 = fd
read 03
$4205 = 2d, 6d, ed
read 03, 00, 00, 4b, 59, 4f, 44, 41, 4b, 55, 2d
<reads the file name and then stops>
$4205 = ed
reads 2d
$4205 = ed
reads 2d
$4205 = ed
reads 2d, 00, 28
$4205 = fd
reads 28
$4205 = 2d, 6d, ed
reads 28 <it's expecting 04 here most likely>
It resets $4205.d0 (restarting the drive motor), re-reads the disk error, and then now I get disk error 25.
I'm at a loss. Does anyone emulate the FDS at a lower level than HLE BIOS hooks?
Does the motor actually pause and stop reading more disk data when $4205.d6 is clear?
If you turn the motor off and on again, does this reset the motor head to the outer edge (start) of the disk, or does it still have to wait for the entire disk to be scanned before starting over again?
Once the entire disk is scanned, does it disable the motor at that point?
Are the checksums relevant in any way? I see Mesen hooks bus address reads in the BIOS to simulate things via HLE, and performs CRC calculations in there ...
Anything else I should know, any insights anyone could share? :/