NFD r1 File Format

File format documentation

This is the floppy format that was used for later versions of T98-Next. It is the format used for any saves of NFD files within FIVEC.

This format was documented in detail by the original developer, and is thus relatively well understood. You can find his notes (in Japanese) here. Below, are the annotated notes (my additions in italics) once translated to English:

NFD r1 format file structure specification
                                                             2001/09/14 LED

□ Introduction

This text is a floppy disk image file for the PC9821 emulator T98-Next.
It defines the structure of NFD r1 format. Freely used for data analysis, tool development, etc.

□ About structure

The structure of NFD format is roughly divided into a header part and a data part.
The header part exists from the beginning of the file, and the data part exists after that.

[Header part]

The header part is further "overall information part" "sector information part" "special read information part"
Can be divided into

"Overall Information Department"
Stores information about the entire image. This part is fixed from the beginning of the file

typedef struct {
    char szFileID [sizeof (NFD_FILE_ID1)]; / * Identification ID "T98FDDIMAGE.R1" * /
    char Reserv1 [0x10-sizeof (NFD_FILE_ID1)]; / * Spare * /
    char szComment [0x100]; / * Comment * /
    DWORD dwHeadSize; / * Header size * / 
    BYTE flProtect; / * Other than write protect 0 * /
    BYTE by Head; / * Number of heads 1-2 * /
    char Reserv2 [0x10-4-1-1]; / * Spare * /
    DWORD dwTrackHead [164]; / ​​* Track ID position * /
    DWORD dwAddInfo; / * Address of additional information header * /
    char Reserv3 [0x10-4]; / ​​* Spare * /
Note) The boundary of the structure is in 1-byte units.
Fill the reserved area with 0

dwHeadSize indicates the size of the entire header
swTrackHead indicates the start position of the track in the sector information section with an absolute address.
However, if the track does not exist, 0 will be entered.
dwAddInfo is reserved and is currently fixed at 0.

"Sector information section" and "Special read information section" are added for each track 
after the overall information section.

Mix and enter

typedef struct {
     WORD wSector; / * Number of sector IDs * /
     WORD wDiag; / * Number of special IDs * /
     char Reserv1 [0x10-4]; / * Spare * /

Store the number of sectors in the track in wSector
Stores the number of special data in the track in wDiag

Stores sector information headers less than a few minutes of wSector

typedef struct {
    BYTE C; / * C * /
    BYTE H; / * H * /
    BYTE R; / * R * /
    BYTE N; / * N * /
    BYTE flMFM; / * MFM (1) / FM (0) * /
    BYTE flDDAM; / * DDAM (1) / DAM (0) * /
    BYTE by Status; / * READ DATA RESULT * /
    BYTE by STS0; / * ST0 * /
    BYTE by STS1; / * ST1 * /
    BYTE by STS2; / * ST2 * /
    BYTE by Retry; / * No RetryData (0) Yes (1-) * /
    BYTE by PDA; / * PDA * /
    char Reserv1 [0x10-12]; / * Spare * /

Store the sector ID of that sector in CHRN

In byStatus, the result when the sector is read by READDATA of INT 1Bh 
(AH=06H should be the call, see Disk_Status on p. 252) ) with PC98x1 Store
The same applies to by STS0-2, which stores ST0-2 of FDC.

(See PC-9801  Technical Data Book, PDF p. 255-258 for the read operation)
(The DISK_RESULT structure supplies these, see p. 252)

byRetry is for sectors with unstable data, when reading and storing data multiple times
If you use it, for example byRetry = 8, you can have 9 types of data.
T98-Next uses retry data in order if byRetry is non-zero
by PDA stores the value with the lower 4 bits of the corresponding device address set to 0.
When byPDA is 0, T98-Next automatically determines the media from the sector size.

After that, the special read information header is stored for the number of wDiag.

typedef struct {
0    BYTE Cmd; / * Command * /
1    BYTE C; / * C * /
2    BYTE H; / * H * /
3    BYTE R; / * R * /
4   BYTE N; / * N * /
5    BYTE by Status; / * READ DATA RESULT * /
6    BYTE by STS0; / * ST0 * /
7    BYTE by STS1; / * ST1 * /
8    BYTE by STS2; / * ST2 * /
9    BYTE by Retry; / * No RetryData (0) Yes (1-) * /
A-D    DWORD dwDataLen;
E    BYTE by PDA; / * PDA * /
F    char Reserv1 [0x10-15]; / * Spare * /

The command to perform special reading is stored in Cmd in the lower 4 bits of the AH value of INT 1Bh.
06h to specify special reading for READ DATA, 02h to specify READ DIAGNO STIC, etc.
CHRN stores the sector ID when special read is called
byStatus and bySTS0-2 store the status after special loading
byRetry is used like sector ID
dwDataLen stores the size of the data to be transferred
byPDA stores the value with the lower 4 bits of the corresponding device address set to 0.
When byPDA is 0, T98-Next automatically determines the media from the sector size.

T98-Next uses the information of special read data in preference to the sector ID.
By using this information, the read result in READ DIAGNOSTIC can be specified individually.
You will be able to do it

The information below NFD_TRACK_ID1 is repeated the number of times indicated by dwTrackHead.

[Data section]

The data part starts from the dwHeadSize byte of the header part from the beginning of the file.
The data part arranges the data continuously in the order stored in the header.

Additional Notes

Emulation Data
This one gets tricky, because in the case of additional emulation data, those headers are added to the track header, and those read result blocks are added to the data segment at the end.
As a result, particularly in the case of multiple read tries at different invalid values, the resulting image can easily be twice the logical disk size.  In the case of these entries being present,
the header size will vary.

Data Segment
Data in the data segment, which follows the last of the header, is ordered in the sequence it appears in the track listing (and the sector listing within that) as such, it does not necessarily
follow C/H/S ordering, and may have special read entries (of varying sizes) within the track segment.

HexEditor View

For our example above, the data segment would start with our first track, contain 16 sectors at 256 bytes each, in the order they appear there. After that data, we would have the data for the 7 special read entries, of the size specified in the entry. Then we would begin the next track entry, starting with the sectors in that, etc.

Back to the main page