News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_endangermice

Emulating the FDC

Started by endangermice, 16:35, 23 September 16

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

endangermice

Hi Guys,

I'm not sure if this is the right place for this question - my apologies if not.

I'm currently working on extending XNACPC to include floppy support - I thought it would be an interesting project. So far things are going quite well, I can successfully receive floppy commands and populate the status registers / parameter bits from the emulated system.

I'm a bit confused about one thing. When I perform an action on the drive for example enter CAT, the drive issues the command 07 - recalib.seek. I handle this by seeking the emulated drive to track 0. I'm a bit confused on how to set the Main Status Register to tell the computer that the operation is complete (this command does not post a result) and therefore the MSR must be set up correctly so that it can be read by the computer.

I'm currently sending the MSR to 0xC1 i.e. which sets bit 7 and 6 to 1 and bit 0 to 1 all other bits are 0. This doesn't seem quite right. Does anyone know how I need to set the MSR to tell the computer that the seek operation is complete? I'm expecting the computer  to issue a Sense Interrupt State command so I can terminate the seek/recalibrate command but it doesn't seem to get that far.

Many thanks,

Damien
For all the latest Starquake remake news check out my website - www.endangermice.co.uk

TFM

#1
The result of a Recalibrate / Seek command is not given in the HSR (guess it was Status 0 or so iirc). Look at the FDC765 sheet, they explain it well. Or CPC's Floppy book.  :)
TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

endangermice


Hi TFM,


Thank you very much for the info. I've been looking threough the 765 datasheet and under the Recalibrate command the is no result section which ties into the document on this site 765 FDC - CPCWiki that says this command does not pass through a result, however it appears I still need to set something so the computer can determine that the operation is complete.


On the Wiki page it says "The Recalibrate and Seek Track commands do not return result bytes directly, instead the program must wait until the Main Status Register signalizes that the command has been completed, and then it must (!) send a Sense Interrupt State command to 'terminate' the Seek/Recalibrate command.". This implies that I need to set something in the Main Status Register once I have executed the command but I am still unclear what that needs to be.


It appears that once the computer understands that the drive has completed the command it needs to send a "Sense Interrupt state". I am not receiving this from the emulated computer which leads me to suspect that I am not setting the MSR correctly.


Thank you for all you help so far :) .


Cheers,


Damien
For all the latest Starquake remake news check out my website - www.endangermice.co.uk

Tai

If I understand it correctly and looking at Fano's FDC library (you can grab the source code What is the Lowest Memory method of reading from disk?) it seems you have to set bit 5 of ST0 to 1 and set track number to 0.


;**********************************
;*** GOTO TRACK 0 (RECALIBRATE) ***
;**********************************
;BC, AF , AF' corrupted

.FDC_Track0         
    ld   A,cmd_goto_track0
    call FDC_send                ;command
    call FDC_GetIdd
    call FDC_send                ;IDD
    call FDC_waitdone            ;wait exection done
    or A                        ;are we on track 0 ?
    jr nz,FDC_Track0             ;if not , retry
    ld (current_track),A
    ret

;*********************************
;*** WAIT FOR OPERATION ENDING ***
;*********************************
;get ST0 status to see if operation ended
;and return track in A
;BC , F , AF' corrupted
.FDC_waitdone
    ld   A,cmd_int_state
    call FDC_send

    call FDC_get        ;ST0
    ld   (st0),A
    call FDC_get        ;track
    ld B,A                ;save track in B
    xor  A
    ld   (st1),A                   
    ld   (st2),A
    ld   A,(st0)

    bit  5,A              ;is instruction finished ?               
    jr z,FDC_waitdone
    ld A,B                ;return track in A

    ret


Hope it helps

arnoldemu

#4
@endangermice:

The seek and recalibrate commands take some time to execute AND you can do them in parallel on multiple drives. You send one seek and then another to a different drive, both then step in parallel.

When the seek command has been sent there is no execution phase or result phase, fdc returns back idle phase (ready to accept commands).

The FDC will continue to make the drives seek. (Each drive has it's own PCN inside the FDC).

You can then send other commands but only some are accepted until seek is completed. (e.g. read or write will not be accepted until it has completed, but other sense will succeed).

At the end of the seek of any drive, the fdc triggers an int. On CPC it's not connected so we can send a command to check for it.

Normally code will send a loop of "sense interrupt status" after a single seek.

(EDIT: If you do a seek on multiple drives you can send multiple "sense interrupt status" to get the state of each drive. When the "sense interrupt status" is done, the int is cleared. NOTE: If multiple drives have finished, the sense interrupt status returns the results in fdd order 0-3.).

A single 0x080 is returned if no int has been signalled. (No drives finished seek or all finished seek and you already did a sense interrupt status and the int was cleared).

But if the int has been signalled then the result is two bytes.

ST0 (indicating seek end, or equipment check if more than 77 tracks seeked), the drive that finished and the PCN for the drive which is the the track the FDC thinks it got to.

The recalibrate is needed to sync the FDC with the drives actual position. At reset the internal PCN could be any value and the drive could be at any position so you need to make them agree.

Drive can only report track 0 status so the recalibrate ensures both the drive and fdc agree on track 0, from then on, the fdc assumes each step pulse will move the track backwards or forwards as appropiate and that the drive executes it and succeeds and it updates it's internal PCN.

It is entirely possible to do a seek, and wait a long enough time and then just do a read.

The fdc will accept that, clear the int and execute the command.

If you need to test then you can use my "acid test suite". There is one called "fdctest".

I'm writing another one which will check even more stuff.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

endangermice

#5
That's great, thanks guys lots of very useful info here. I rewrote a my floppy code and the computer is now sending the SenseInterruptState as I expected so I think I just made a bit of a "cock-up" in the initial code.

I'm now beginning to progress quite nicely. I can accept commands, set the various registers and parameters and signal to the computer that I have data to send back. I just need to finish off sending parameters back to the Data register when it is read and I should have a framework ready to implement the actual meat of carrying out the commands.

For all the latest Starquake remake news check out my website - www.endangermice.co.uk

TFM

Yes, you're right. Seek and Checking for it's end are different commends.


You issue an SEEK / Recalibrate


Wait... drink tea... eat white sausage from Bavaria... wait...


Check (as often as needed) for the end of the seek. See FDC manual for that command, it's &00 (sense interrupt status). Write &00 as command to the FDC, then read Status 0 register and track number (after seek). So you read two bytes.


Status 0 Bit 5 contains the Seek End bit: This bit is set to 1 when seek has ended.
TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

endangermice

#7
Hehe, yes it is a bit like that, I've essentially implemented a queuing system that writes the data to the computer byte by byte. I now have something that's beginning to work. I spent today decoding the Extended DSK image format and I think I have it just about right. I'm now at the stage where I can catalogue a disc, and the listing I receive back is almost correct i.e. I get file names and extensions though the sizes are a bit wrong so I'm not 100% there yet but I'm very pleased with my progress so far :) .


Quick question, do the sectors start from 0 or 1. It appears to be 1 from what I can tell. Can someone confirm...?


Thanks,


Damien
For all the latest Starquake remake news check out my website - www.endangermice.co.uk

endangermice

#8
I have a few further questions:


1. If a disk contains a lot of files can the file names occupy more than one sector?

2. I'm getting a sector size of 2 when I parse a disk image. What does this refer to? It is my understanding that sectors are 512 bytes in size.

3. The sectors on a standard data disc have IDs ranging from C1 - C9. The do not always appear in order. When a sector is requested for read, do I need to match it to the sector carrying the appropriate ID e.g. if sector 2 is requested would I match that to the sector with the ID of C2?

4. When a sector read is requested I presume I keep sending data back until the whole sector (512 bytes) have been read..?


Sorry for all the questions but the documentation I have thus far isn't very detailed.
For all the latest Starquake remake news check out my website - www.endangermice.co.uk

roudoudou

Quote from: endangermice on 12:44, 26 September 16
1. If a disk contains a lot of files can the file names occupy more than one sector?

2. I'm getting a sector size of 2 when I parse a disk image. What does this refer to? It is my understanding that sectors are 512 bytes in size.

3. The sectors on a standard data disc have IDs ranging from C1 - C9. The do not always appear in order. When a sector is requested for read, do I need to match it to the sector carrying the appropriate ID e.g. if sector 2 is requested would I match that to the sector with the ID of C2?

4. When a sector read is requested I presume I keep sending data back until the whole sector (1024 bytes) have been read..?


Sorry for all the questions but the documentation I have thus far isn't very detailed.


A standard directory use 4 sectors -> C1 to C4


If you don't know how "sector size" mean, you should MUST find a proper documentation...


When a sector is red, you keep sending data IF they are read in less than 28μs (see FDC765 datasheet). If not you stop and there is a bit to tell that there was a synchro error


http://www.cpcwiki.eu/imgs/f/f3/UPD765_Datasheet_OCRed.pdf


http://cpcrulez.fr/coding_fdc-01-fonctionnement_FDC__SOSP.htm (translate it to french with gtranslate) there is 40 other pages, very helpful
My pronouns are RASM and ACE

TFM

Usually sectors start from 1. &C1-&C9 for DATA format, or &41-&49 in System format. Or &01 to &08 for IBM format. Vortex has &01-&09.

TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

endangermice

#11
Roudoudou, thank you for the French documentation, it has been very useful, and provides exactly the additional information I was after. I now understand how the sector size of 0x02 refers to the actual size of 0x200. I have also been able to correct some errors in the setting of the MSR register which has allowed me to make a lot of progress this evening.


TFM, thanks for the sector info, that's how I understand it too. Decoding the image format, it appears that sectors are not always stored in order on the disc. I have therefore implemented a mapping system that uses the sector ID to ensure I read sectors in the correct order. I presume that if the Computer asks for sector 0x01 it is looking for C1 if this is a data disk...? I very nearly have this working now. The remaining issues are:

1. Disc size is showing up incorrectly. A blank formatted disc shows as as 154kb free rather than 178kb. The directory listings and file sizes are correct though.

2. I can read data off single sectors without issue. However if data is stored on multiple tracks /sectors, it appears to be scrambled with parts being repeated. I have tested this by loading an image which appears to be a corrupted version of the original. Without knowing which sectors should be read for a given operation, it is proving difficult to understand what is going wrong. I have been able to verify that the directory scan is correct as it cycles through C1, C2, C3 and C4 in order.

However when loading other longer data I'm unsure of the correct sequence. Does anyone know of any emulators / test utilities that might show the sectors and tracks that are read during a given operation on a specific disc as right now, I have nothing to compare my results to. Writing out a log of the operations, it appears as if some sectors are being read twice. The only reason I can imagine would be a disc read error (impossible on a disc image) - so I'm wondering if there is a problem with how I am returning the status registers - presumably reading off a data block should show some sort of sequence without any repetition of the sectors being read. Indeed when I try and load the image parts appear to be repeated which ties in with the logs.

I notice that the ReadID command is being issued. Is there anything specific I need to do to the registers before returning back the result for this command?

I know it's probably impossible to provide any answers without examining my code (which is somewhat lengthy). But I'm wondering if anyone encountered similar issues when trying to get FDC emulation to work. I fell I'm on the cusp of getting this right.  Thanks again and thank you for all the help so far - I really appreciate it!
For all the latest Starquake remake news check out my website - www.endangermice.co.uk

TFM

The physical order of sectors is different, for example for data format:

&C1, &C6, &C2, &C7, &C3, &C8, &C4, &C9, &C5   --- then the track is over and it starts again.

That's called interleave and comes from CP/M days, to actually speed up disc access.
For regular OS this is nice, so the OS can read one sector, process it (while the next sector runs by) and then read the next logical sector (which is the 2nd next in physical order). Hope I'm clear.  :)


FutureOS has the quickest FDC functions because it reads the sectors in physical order instead of logical order.  :)
TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

endangermice

#13
Hey,


Yes that makes perfect sense - thank you for the very clear description. I presume I do have to map these correctly i.e. if the computer requests sector 1 I need to return C1 and if it requests C2 I have to return C2 etc.


It is tempting to re-order the sectors by ID when I read in the image though considering the power of the PC I'm using to run this there would be negligible performance gain. On a real machine, I bet FutureOS makes a big difference :).


Cheers,


Damien
For all the latest Starquake remake news check out my website - www.endangermice.co.uk

arnoldemu

No, the computer will request sector c1 etc.

The raw disc structure that the fdc sees is "IBM system 34" written using MFM encoding. There are id blocks and data blocks.

http://ww1.microchip.com/downloads/en/DeviceDoc/37b72x.pdf

Page 60. "System 34"

The id block has 4 values (c,h,r,n), the data block has the data.

The os will write the c,h,r,n value in the read data command. The fdc will search the track and when it finds that id, it reads the data block that follows.


The way the disc is formatted on CPC, is based on CP/M.

CP/M Main Page

The directory structure, storage of the files etc is CPM based.


The DSK structure is just a simplified way to describe the disc structure of the real disc and is not accurate for a lot of copyprotections. It is ok for standard DATA and SYSTEM format discs.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

BTW almost all your questions are answered in the nec 765 PDF.

The link I have in the previous section is for the PC version of the FDC, the commands are very similar, perhaps it helps you to understand how it works?
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

endangermice


Hmm I must have something wrong with the code parsing the parameters - I have not seen the computer request the sectors as C1 etc. only as 01 etc. Do I need to set anything to tell the computer I am using a data disc? I'm wondering if this is where I'm going wrong...?

Thanks Kevin for the other link, I will take a look through that documentation when I next have a chance, I think I need a break now :).

I have confirmed by comparing the track seeks with WinApe that I'm seeking to the correct tracks when loading the picture so that bit of code seems good.
For all the latest Starquake remake news check out my website - www.endangermice.co.uk

endangermice

#17
Interesting, I compared the requested sectors with my emulated FDC with the drive information display in DevilMarcus' excellent JavaCPC. It appears I'm not being asked for the final sector for each track. I'll have to debug through the code again but I must be returning something unexpected to the emulated computer that prevents it from sending a final read sector command.


It moves on to the next track having asked for too few sectors. Having looked at this for several hours, I'm at a loss as to how this can even happen. The only place where I can see it might be possible to provide the computer with a sector count is within the Read track command, but this never gets issued. Is there another way to tell the computer how many sectors there are per track? I've been studying all the docs and I haven't been able to find anything thus far. Is there anything else that might cause it to move onto the next track before it has read all the cylinders?


This problem also explains why my disc sizes are smaller than expected, even in the process of getting the disc's contents, it would appear it's not reading the number of sectors correctly which makes me think that I need to send the correct info over to the computer somehow....


If I can get this working I reckon I might have cracked reading :) .
For all the latest Starquake remake news check out my website - www.endangermice.co.uk

arnoldemu

Amsdos auto detects the disc format. the read id command is sent. this command doesnt have an execution phase. all data is returned in results.

the c,h,r,n in the results will be from one of the sectors on the track that it has seeked to.

e.g. 0,0,c1,2 through to 0,0,c9,2 if on track 0 (depending on where the fdc reads from at that moment).

amsdos then determines the number of sectors by the id value only. c1 is 9 sectors per track. 01 is 8 sectors per track. 41 is 9 sectors per track.

based on the value stored in the dsk return those ids in your read id.

amsdos uses a limited set of commands (recalibrate, seek, read data and read id).

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

PulkoMandy

It would be best to NOT reorder the sectors. While it may look like a good idea at first, you will find out that some games with copy protection rely on precise timing of when the sector should be under the drive head, which you can't do right if you messed up the sector order.


I think what happens is:
1) AMSDOS asks for sector 01 to see if this is a SYSTEM disk. You should return a "sector not found"
2) AMSDOS asks for sector C1 to see if this is a DATA disk. You should return sector C1 data


Currently, your AMSDOS asks for sector 01 and you return sector C1, so AMSDOS thinks it is a SYSTEM disk and continues using that format (which has smaller capacity). From there it continues to ask for the 0x sectors instead of Cx.

endangermice

Thank you for both your replies, Kevin - that was the missing piece of the puzzle! I wasn't explicitly doing anything for the ReadID command. I was confused by the fact that in the FDC docs on the Wiki, the c,h,r,n parameters are not mentioned by name - but after re-reading the OCR'd documentation on the controller chip, I realised that these simply map to TR, HD, LS, SZ. I have added a method to my floppy disc object (which creates an object out of a parsed image file) which allows the ReadID command to interrogate a particular track. If the track is found, it reads though the sectors and records the sector with the highest SectorID. At the same time the sector size is captured. Both of these are returned back to the ReadID command as out parameters which I use to populate LS and SZ before sending these back as the results (HD is currently 0x00). This now works properly and I can finally read disc images on the Emulated computer which is exciting :) .

There's still a lot of work to do, I need to handle multiple heads, more tracks, writing, different disc formats, formatting etc. and I plan to tidy optimise all of my code before I do anything more but I'm very happy that I have been able to write my first piece of working emulation code, which would not have been possible without all the help on here!

PulkoMandy, thank you for the additional info - I will be sure to implement you advice when I come to supporting the other disc formats. I reached a similar conclusion with re-ordering the sectors, it is sensible to leave the disc image structure as intended and to be honest I suspect the actual speed gain would be negligible - unlike actual hardware, the emulated disc controller is doing relatively little so is likely to be far from the slowest code to execute in the emulator.

Thanks again for all your help. Now all I have to do is to rewrite the sound emulation due to MonoGame not having XNA's the dynamic sound effect capabilities, still I feel a bit more comfortable with this having wrapped the C++ SidPlay libraries into Managed C# code some years ago....
For all the latest Starquake remake news check out my website - www.endangermice.co.uk

arnoldemu

Technically if you use read id over and over it will give the c,h,r,n or tr,hd,ls,sz for each id as it sees it in the order on the disc.

So the results will be like this (in fdc speak) and for a standard data format disc with it's standard interleave:

st0,st1,st2,0,0,c1,2
st0,st1,st2,0,0,c6,2
st0,st1,st2,0,0,c2,2
st0,st1,st2,0,0,c7,2
st0,st1,st2,0,0,c3,2
st0,st1,st2,0,0,c8,2
st0,st1,st2,0,0,c4,2
st0,st1,st2,0,0,c9,2
st0,st1,st2,0,0,c5,2

and repeat..

so the read id is just reporting the tr,hd,ls,sz seen next as the disc rotates.

The N comes direct from SZ. It is not computed from the data block itself.


(You can format a disc with 1 sector size (e.g. 3 which is 1024 bytes), but tell it the ids you want with a different size (e.g. 2 which is 512 bytes).

When using read-data the fdc will read the id field and use that to determine the amount to read. So it will end up reading 512 bytes, try and read the crc which will not match because format wrote a larger sector and report a crc error).





My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

endangermice

I see, that's very helpful - thank you for all the hints so far, you've made my life a lot easier, I haven't written any emulation code before so I'm literally feeling my way!
For all the latest Starquake remake news check out my website - www.endangermice.co.uk

Fredouille

Since I have discovered the arnoldemu's acid tests, I am upgraded my FDC emulation to fit those tests.
But I also discovered fitting acid tests involves regressions to read protected software.


Today, I am wondering how/when the EN flag in ST1 is set during a read track operation.


In acid test &22, FDC is requested to read 1 sector in track 11 where sectors R are C1, C2...
CMD Command=READTRK : 42 01 0B 00 01 02 01 2A FF
RESULT Result=41 84 00 0B 00 01 02


In Hercule II LATIS protection, FDC is requested to read &C1 sectors.
In track &24, first sector is CHRN(24:0:CB:0). I believe sector &C1 is never detected.
CMD Command=READTRK : 42 00 24 00 C1 02 C1 2A FF
RESULT Result=40 34 20 24 00 C1 02


In first case, ST1_EN should be set to pass test.
In second case, ST1_EN should not be set to pass protection.


What is the logic ????

arnoldemu

Quote from: Fredouille on 12:50, 01 November 16
Since I have discovered the arnoldemu's acid tests, I am upgraded my FDC emulation to fit those tests.
But I also discovered fitting acid tests involves regressions to read protected software.


Today, I am wondering how/when the EN flag in ST1 is set during a read track operation.


In acid test &22, FDC is requested to read 1 sector in track 11 where sectors R are C1, C2...
CMD Command=READTRK : 42 01 0B 00 01 02 01 2A FF
RESULT Result=41 84 00 0B 00 01 02


In Hercule II LATIS protection, FDC is requested to read &C1 sectors.
In track &24, first sector is CHRN(24:0:CB:0). I believe sector &C1 is never detected.
CMD Command=READTRK : 42 00 24 00 C1 02 C1 2A FF
RESULT Result=40 34 20 24 00 C1 02


In first case, ST1_EN should be set to pass test.
In second case, ST1_EN should not be set to pass protection.


What is the logic ??? ?
I will need to add more tests to verify but:

34 indicates overrun, read error and no-data.

The read track for Hercule II is asked to read C1 (193!) sectors. EOT is the *number* of sectors in read track and not the last. The error says the protection code is reading less (looking at the results it read only 1 sector). This causes the fdc to signal "overrun" and quit the read. Therefore EOT sectors is not read and EN will not be set.

To set EN, EOT number of sectors must be read completely.

There is one more thing, Hercule II has sector size 0 (128 bytes), read track is reading size 2 (512 bytes), this will read sector data AND gaps etc.

EDIT: The "No Data" for read track means that the C,H,R,N in the read track command were not found on the disc. But so far every test I have done shows it will ALWAYS say "no data" :(

I will need to add more tests to verify the operation. (I did not yet have tests to trigger overrun on last sector and this kind of thing).
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Powered by SMFPacks Menu Editor Mod