Routine to measure read sector time (DMA/FDC Programming)

GFA, ASM, STOS, ...

Moderators: simonsunnyboy, Mug UK, Zorro 2, Moderator Team

User avatar
DrCoolZic
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2188
Joined: Mon Oct 03, 2005 7:03 pm
Location: France
Contact:

Routine to measure read sector time (DMA/FDC Programming)

Postby DrCoolZic » Thu Jun 15, 2006 9:41 am

As you may know the Rob Northen protection mechanism is using a so called long sector which takes in the order of 17.2ms to read instead of normal 16.4ms sector.
I would like to write a routine to precisely measure the length of time taken by the WD1772 to read a specific sector. I would appreciate if somebody as already some code available or some hints on the best way to code this.

Note I have been coding in C++ for a long time and assembly is a pain for me! Any chance to do this kind of very low level routine in C? So far all the pieces of code I have seen to directly access the FDC/DMA were written in assembly!

Thanks
Jean
Last edited by DrCoolZic on Wed Jun 28, 2006 12:10 pm, edited 2 times in total.

User avatar
unseenmenace
Atari God
Atari God
Posts: 1961
Joined: Tue Sep 21, 2004 9:33 pm
Location: Margate, Kent, UK
Contact:

Postby unseenmenace » Thu Jun 15, 2006 10:12 am

I'm pretty sure you're going to need assembly for the kind of precision timing that would be involved for that kind of thing. Nyh was recently suggesting Pure C since you can use assembler in it as well as C. See the following thread:-
http://www.atari-forum.com/viewtopic.php?t=9101
UNSEEN MENACE
Several STFM's, 4MB STE, 2MB TT with 1.2GB Hard Drive and 14MB Falcon with 540MB Hard Drive,
Lynx 2 and Jaguar with JagCD
Member of GamebaseST and AtariLegend team
Check out my website at http://unseenmenace.110mb.com

User avatar
charles
10 GOTO 10
10 GOTO 10
Posts: 2407
Joined: Tue Aug 17, 2004 12:11 am
Location: ont. Canada
Contact:

i know ,,but in basic

Postby charles » Thu Jun 15, 2006 10:37 am

instruct drive to read sector on command
set loop harnessing timer .

once loop has been exited the timer within has stopped timin so print result to screen.

well i like midi so maybe we're worlds apart.

contact me privatly if nessesary.

callaghan
The radioactive half-life : )
Atari is a lifestyle,not a hobby.
HOLD ON ! ! ! Im printing unreadable characters ...!

User avatar
DrCoolZic
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2188
Joined: Mon Oct 03, 2005 7:03 pm
Location: France
Contact:

Postby DrCoolZic » Thu Jun 15, 2006 11:39 am

Sorry but I am not too much familiar with the Atari programing ...

callaghan wrote:set loop harnessing timer.


Sorry I do not understand what you mean? I looked at the Atari schematic and found that timer B input is connected to shifter DE output. Is it what you refer to?

once loop has been exited the timer within has stopped timin so print result to screen.

Here again I do not understand?

Do you mean that I start the timer B just after telling the FDC to read the sector and stop the same timer when the sector is read and see how much it has been incremented/decremented?
If I am right the timing (for 50Hz machine) of DE = 28µs in mono and 64µs in color?

The 68901 receive a 4MHz clock. Is it possible to use/program one of the 4 timers as a precise counter or are they all used by the HW and/or OS and not available to user?

How do I know when the reading of the sector is finished? Is it by looking (polling? / interrupt?) at the input I5 of 68901 which seems to be connected to INTR of the FDC (again looking at the schematic)?

Actually s there a good document on how to program the HW of the Atari at low level (below BIOS)?

User avatar
charles
10 GOTO 10
10 GOTO 10
Posts: 2407
Joined: Tue Aug 17, 2004 12:11 am
Location: ont. Canada
Contact:

timer

Postby charles » Thu Jun 15, 2006 9:33 pm

well i supose that its like any thing else in programming and wont continue on with the next command until its current task is complete.

now don't get me wrong but the timer is for physical time not hertz or uf or any thing. its a 200 millisecond clock builtr into the processor of our ataris.

so set a timer ..in basic its as simple as the word "timer "
index the desisred sector into an array and sub tract the difference from the time it started reading and indexing from the time it ended reading and indexing.. and that is our obtainable results.

what purpose does this serve?
are you clocking the frequencies ?
i sure would like to fully assist but this seems rediculous compared to write midi code so i'll cut conversation off and wait for responce.
'---------------------------
t=timer
'
do
"your code to read sector right here"
exit if eof !or array we create is full eof =end of file
loop
'
tt=timer
'
a=tt-t
'
print "time to read sector :" + a
'
'
------------------------------------
quick somebody proof ythis for me , its in gfa basic but sence nobody else is willing to help , i'd try.
----------------------------
The radioactive half-life : )
Atari is a lifestyle,not a hobby.
HOLD ON ! ! ! Im printing unreadable characters ...!

User avatar
leonard
Moderator
Moderator
Posts: 640
Joined: Thu May 23, 2002 10:48 pm
Contact:

Postby leonard » Fri Jun 16, 2006 12:35 pm

you almost can do *everything* in C , I love that :-)

If I enderstand well your purpose (correct me if i'm wrong), you're not interested by the time (in second) to read a sector, but better by a different time between two sector read no? If it's true, you can increment a counter, on a fixed hardware (I mean ATARI-ST for exemple).

You need some stuff:
-defined machine (as you'll use a counter loop, you have to know the machine: the result will not be the same on an ST or a FALCON)
-switch off interruptions (clearing MFP enabling bits $fffa06.l = 0)
-doing read sector command
-polling the end of the sector by reading the FDC DMA position.

count = 0
read sector at adress "ad"
loop:
ad2 = read DMA adress
count++
if ad2 < ad + 512 goto loop

then you can compare the "count" value for several sectors.

If you're an MFP programmer warrior, you can even use the MFP data counter to get a time information, independant of machine (ST, Falcon etc...) but it's more complicated than that.

Hope it helps.
Leonard/OXYGENE.

ijor
Hardware Guru
Hardware Guru
Posts: 3624
Joined: Sat May 29, 2004 7:52 pm
Contact:

Postby ijor » Fri Jun 16, 2006 2:52 pm

DrCoolZic wrote:Sorry but I am not too much familiar with the Atari programing ...
How do I know when the reading of the sector is finished? ...
Actually s there a good document on how to program the HW of the Atari at low level (below BIOS)?


Sorry, but you are asking a question in a way that doesn’t making any sense.

You are asking a very advanced question yet you lack minimal knowledge about the ST hardware basics. The reply would need a whole book. I suggest you start with more basic tasks.

If you still want to see how this is done, the best way is to look at the protection routine in original games. Grab the debug build of Steem. Load any Pasti image with CopyLock protection. Put a Past breakpoint at the protected sector. And that’s it, you get the routine that measures the sector.

User avatar
DrCoolZic
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2188
Joined: Mon Oct 03, 2005 7:03 pm
Location: France
Contact:

Postby DrCoolZic » Fri Jun 16, 2006 9:11 pm

leonard wrote:If I enderstand well your purpose (correct me if i'm wrong), you're not interested by the time (in second) to read a sector, but better by a different time between two sector read no?

Yes you are right the main goal is to compare time to read different sectors... However if possible absolute time would also be appreciated.
polling the end of the sector by reading the FDC DMA position.

Correct me if I am wrong but i thought that at the end of the read command the FDC was setting the busy bit and raising an interrupt. If I look at the schematic it seems that this interupt goes to the MFP where it can either be polled or generate an interupt. Is this an easier way to find out about the end of reading a sector or is there a particular hidden reason that force to look at the DMA?

Otherwise I beleive I can make sense of the loop you describe... even so I really newbie to Atari HW ... see comment below

Yes information you provided help me :wink:

ijor wrote:Sorry, but you are asking a question in a way that doesn’t making any sense.

Do you mean that it does not make sense because of my poor english or it does not make sense because I am asking "uneducated" questions? 8O

You are asking a very advanced question yet you lack minimal knowledge about the ST hardware basics. The reply would need a whole book. I suggest you start with more basic tasks.

Yes are perfectly right moving from large C++ application development to low level Atari hardware programming in assembly is a little bit steep. However I should be able to do it even if it may take time...
You are right I probably need to review basic stuff before. As I already came to this conclusion I just bought yesterday a book that, I beleive, should help me understand the Atari HW. The book is called "ATARI ST Internals Authoritative Insider's Guide" and I think I have seen it referenced several time on this forum. Its on his way from the USA (I hope). I am also teaching myself 68000 assembly and basic programming for the Atari ... This should get me started...

If you still want to see how this is done, the best way is to look at the protection routine in original games. Grab the debug build of Steem. Load any Pasti image with CopyLock protection. Put a Past breakpoint at the protected sector. And that’s it, you get the routine that measures the sector.

What you describe here probably make sense but seems to me a daunting task. I do not know how to run a debug build of steem and finding the right stop in the program and diassemble the code there does not sound to me too easy.
Really what I would prefer is to get a nicely documented source code that I can look at as I am a strong beleiver of learning by example.
But I may not have this luck?
By the way I am learning a lot on low level assembly programming of the FDC/DMA by reading and playing with the source code from David Small.

Jean

ijor
Hardware Guru
Hardware Guru
Posts: 3624
Joined: Sat May 29, 2004 7:52 pm
Contact:

Postby ijor » Sat Jun 17, 2006 2:33 am

DrCoolZic wrote:Do you mean that it does not make sense because of my poor english or it does not make sense because I am asking "uneducated" questions?


I wasn’t talking about your English (mine is not much better). And certainly I didn’t mean your question was “uneducated”. What I meant is that the answer to your question, considering your current knowledge about the ST, would need a whole book.

What would you answer if somebody asks you? “Hi, I’m new to computing, can you explain to me what C++ “pure virtual functions” and “anonymous unions” are?

I mention this because in a way you are making me feel uncomfortable (yeah, I know that this wasn’t your intention). I’m probably the most suitable person to answer you. And everybody knows that I like to give detailed and comprehensive answers. But in this case I can’t (because, again, it would be too long), and this doesn’t make me feel so good.

If you still want to see how this is done, the best way is to look at the protection routine in original games. Grab the debug build of Steem. Load any Pasti image with CopyLock protection. Put a Past breakpoint at the protected sector. And that’s it, you get the routine that measures the sector.

What you describe here probably make sense but seems to me a daunting task. I do not know how to run a debug build of steem and finding the right stop in the program and diassemble the code there does not sound to me too easy.


It is not nearly a daunting task at all. Running Steem’s debugger is as easy as running the “normal” Steem. You don’t need to find the right stop. The Pasti breakpoint will put you right on the stop. And you don’t need to do any disassemble, the debugger will show you the disassembled code already.

Really what I would prefer is to get a nicely documented source code that I can look at as I am a strong beleiver of learning by example. But I may not have this luck?


If you are talking about my source code, then yes. You are out of lack at this time. Sorry, the source code for Pasti is currently not available.

User avatar
DrCoolZic
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2188
Joined: Mon Oct 03, 2005 7:03 pm
Location: France
Contact:

Postby DrCoolZic » Sun Jun 18, 2006 7:47 pm

leonard wrote:you almost can do *everything* in C , I love that

Yep me too ...

I have decided to follow the advice from ijor and step back a little bit ... as I am still missing a lot of information. However I beleive it should not be so difficult once I found the right information. I am (was) much more familiar with the Intel family but seems like the MFP is somewhat equivalent to a combination of 8255 8259 8253 and WD1772 to 8271/8272 (if this still mean something to someone?). I used to code all these peripherals in 8085 and 8086 assembly long long time ago (uuh I would need almost six hands to count the years!) ...

Anyway as you seems to use C for low level routines on Atari you may be able to tell me if there is a .h file somewhere that defines the address of the peripherals and the "system varaibles"? I have browsed the directories from Lattice/DRI/Laser/Pure/Turbo C compilers but could not find any??? But I found several for assembler (like osbind.i, atari.s ...)

It is easy to do, but if you already have one it should help.

By the way the end goal is to be able to get the following king of info

Code: Select all

= Layout for Track=00 Head=0 - 6248 Bytes - length=200.043ms
  Good/Bad ID=10/0 - Good/Bad Data=9/1 - Good/Bad Sync=20/0
  GAP1 59 bytes position=0.000ms length=1913.21us
  ---+------+---------------+------+------+----------------------+---------
  Sct|GAP2  |ID             |GAP3a |GAP3b |DATA                  |GAP4
  #  |Bt Lgt|Pos Lgt CRC TV |Bt Lgt|Bt Lgt|Bt  Lgt   CRC TV  Clk |Bt  Lgt
  ---+------+---------------+------+------+----------------------+---------
    1|15 458|  2 223 OK    0|22 700|15 475|515 16435 OK    0 3.99| 30  954
    2|15 477| 21 222 OK    0|22 700|15 475|515 16437 OK    0 3.99| 30  955
    3|15 477| 40 222 OK    0|22 699|15 475|515 16439 OK    0 3.99| 30  958
    4|15 479| 60 223 OK    0|22 702|15 476|515 16408 OK    0 3.98| 30  957
    5|15 478| 79 223 OK    0|22 702|15 476|515 16422 OK    0 3.98| 30  954
    6|15 477| 98 222 OK    0|22 700|15 475|515 17206 BAD   2 4.18| 91 2923
    7|15 472|120 222 OK    0|22 699|15 474|515 16425 OK    0 3.99| 30  956
    8|15 477|139 222 OK    0|22 699|15 474|515 16413 OK    0 3.98| 30  959
    9|15 480|159 223 OK    0|22 703|15 477|515 16417 OK    0 3.98| 30  957
   10|15 478|178 223 OK    0|22 702|15 476|515 16424 OK    0 3.99|119 3764
  ---+------+---------------+------+------+----------------------+---------

This is one output of my program using the Discovery Cartridge on the Copylock protected "populous" game. It shows the timing (with a 62ns precision) for all the fields as well as tthe timing violation (TV), etc...

Of course I do not think it will be possible to reach this level of detail timing directly from the Atari HW ...

PS Iwill be out of town next week ... Thanks in advance

User avatar
Nyh
Atari God
Atari God
Posts: 1496
Joined: Tue Oct 12, 2004 2:25 pm
Location: Netherlands

Re: Routine to measure read sector time lenth

Postby Nyh » Sun Jun 18, 2006 9:37 pm

DrCoolZic wrote:Note I have been coding in C++ for a long time and assembly is a pain for me! Any chance to do this kind of very low level routine in C? So far all the pieces of code I have seen to directly access the FDC/DMA were written in assembly!

Included are the IA_disk_dma routines. They build in Pure C a library with all the fdc disk routines you may need.

Learning about their correct use is something different. If you want to learn all about it read:
Scheibenkleister II
Massenspeicher am ST
Eschborn: Maxon-Computer-GmbH, 1991.
873 S.. - ISBN 3-927065-00-5.
(ATARI ST).
Claus Brod ; Anton Stepper
The 873 pages contain all there is to know about the floppydisk interface of the ST.

Hans Wessels

Edit:
Note the whole library was written in C. There is not much stuff you only can do in assembly.
You do not have the required permissions to view the files attached to this post.

User avatar
DrCoolZic
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2188
Joined: Mon Oct 03, 2005 7:03 pm
Location: France
Contact:

Postby DrCoolZic » Sat Jun 24, 2006 10:31 am

Thanks Hans,

I browsed the code and it contains a lot of useful information!
This combine with a pointer provided by Zorro 2 should get me rolling.

Thanks again,
Jean

User avatar
DrCoolZic
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2188
Joined: Mon Oct 03, 2005 7:03 pm
Location: France
Contact:

Postby DrCoolZic » Mon Jun 26, 2006 10:10 am

Hi Hans,
I have analyzed most of the code you provided and this is great stuff!
I pretty much figure out the content of the code and how to use it, but there is something I do not quite understand. I do not have access to Scheibenkleister II and I do not speak German and therefore if you can answer the question it would be great:
It is about the following code:

Code: Select all

int rq_DMAstatus(int r_w) {
   register word *ptr = (word *)DMA_ADDR + 3;
   register word sectcountreg = 0x90 | ((r_w == 1) ? 0x100 : 0);
   *ptr = sectcountreg;
   return (*ptr) & 0x7;
}


In order to get the DMA status why do I need to write $90 or $190 at $ffff8606 ? I thought the status was directly accessible at this address without writing first (like this is done in peek_DMAstatus).

And what is the usage of the $90 or $190? Does this means that the DMA keep a different status when in read or write mode???

Does rq_DMAstatus returns something different from peek_DMAstatus?

The same questions apply to get DMA address and count

I am looking at the BIOS in the flop.s section and did not find any mention of this?

Thanks
Jean

ijor
Hardware Guru
Hardware Guru
Posts: 3624
Joined: Sat May 29, 2004 7:52 pm
Contact:

Postby ijor » Mon Jun 26, 2006 5:52 pm

DrCoolZic wrote:In order to get the DMA status why do I need to write $90 or $190 at $ffff8606 ?


You don't need to.

Does this means that the DMA keep a different status when in read or write mode???


No.

The same questions apply to get DMA address and count


You don't need to write anything for reading the DMA address register. But you do for the sector count register, because that one is multiplexed with the FDC access.

User avatar
DrCoolZic
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2188
Joined: Mon Oct 03, 2005 7:03 pm
Location: France
Contact:

Postby DrCoolZic » Tue Jun 27, 2006 7:50 pm

I have spent some time to learn more on the DMA/FDC by reading several documents (By the way I have received the Atari ST Internals book from the US and I was a little bit disapointed as it does not provide much info on Atari HW and custom chips programming!!!). I think I understand the reason of the r_w field in the library provided by Hans.

Information provided above by Ijor is correct as usual!

I have summarized what I have found on the DMA/FDC in a short document attached to this post. I know there are probably tons of doc on the subject but It may be useful for someone? I have also noted most of the references to original documents that I have used. If anybody has comment on this doc please feel free to reply.

I have checked the BIOS listing provided by Lp (specially the flop.s section) and I am now writing a library for the DMA/FDC in C largely based on the code provided by Hans.

Jean
You do not have the required permissions to view the files attached to this post.

User avatar
DrCoolZic
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2188
Joined: Mon Oct 03, 2005 7:03 pm
Location: France
Contact:

Postby DrCoolZic » Wed Jun 28, 2006 12:07 pm

I spent more time reviewing the FDC/DMA programming subject and found that some information in my document where wrong:

The DMA has 2 FIFO but I had indicated wrongly (based on an incorrect document) that one was used for reading and the other one for writing. In fact the two FIFOs are used alternatively so that bytes continue to accumulate in one FIFO while the DMA request the bus and transfer the data from/to memory from the other FIFO...

Added more information on the flock variable used by the _flopvlb routine. This is a must to set this varaible so that the VBL routine does not mess up with the DMA during transfer, and it must be reset after FDC usage so that the drive is automatically deselected when motor is turned off by FDC (leaving a drive selected is a very bad idea!).

Also the bit 3 & 7 of mode register has been clarified (one for CS and one for DRQ acknoledge): be aware that bit 7 has to be one for DMA bus cycle to occur (even when accessing FDC).

The FDC/DMA sequnce has been updated ...

Jean
You do not have the required permissions to view the files attached to this post.

User avatar
Mug UK
Administrator
Administrator
Posts: 11343
Joined: Thu Apr 29, 2004 7:16 pm
Location: Stockport (UK)
Contact:

Postby Mug UK » Wed Jun 28, 2006 1:14 pm

Looking good .. you want to put it onto the Wiki whenever you want as I'm sure it'd be very useful to other coders.
My main site: http://www.mug-uk.co.uk - slowly digging up the bits from my past (and re-working a few): Atari ST, Sega 8-bit (game hacks) and NDS (Music ripping guide).

I develop a free Word (for Windows) add-in that's available for Word 2007 upwards. It's a fix-it toolbox that will allow power Word users to fix document errors. You can find it at: http://www.mikestoolbox.co.uk

User avatar
DrCoolZic
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2188
Joined: Mon Oct 03, 2005 7:03 pm
Location: France
Contact:

Postby DrCoolZic » Thu Jul 06, 2006 7:04 am

Hi Mug,

I am in the process of writing some code to access the FDC/DMA. Beside collecting the info I am also experimenting to make sure the information provided is exact... When I will have a working solution I can complete the documentation and why not publish it on the Atari Forum Wiki which seems to have already lots of interesting stuffs.

Jean

User avatar
DrCoolZic
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2188
Joined: Mon Oct 03, 2005 7:03 pm
Location: France
Contact:

Postby DrCoolZic » Tue Jan 09, 2007 10:22 am

Long time no news and no much work done on my side …

But I am now getting back to the library coding I no have most of the basic functions running, but I have a problem concerning the programming of the FDC and maybe someone has answers to that.
I have a read_address function that calls the FDC "read address" functions many times to pass the DMA buffer… It works fine and returns all the sectors (several times) but of course the first sector to be read is random.
As I would like to know what is the first sector on the track I have though of using the FDC force interrupt with the "every index pulse" condition, but I have difficulties to make it work.

Reminder from doc: At the completion of every command an INTRQ is generated. It is reset by reading status or loading another command (page 5).
Force interrupt can be loaded at any time and terminate current command. When the condition for interrupt is met the INTRQ is raised (page 16)

I interpreted the above information as the following for the force interrupt on every index pulse:

Send the force interrupt command ($D4). As any command wait for the INTRQ to indicate completion. Read the status to reset the INTRQ. If the bit S1 (IP signal) is set we are done otherwise poll the INTRQ line (test bit 5 of MFP) until status with IP signal set. Do a force interrupt with no condition ($D0) to reset FDC.
Here I was expecting to be just after the index pulse? But does not seems to work as expected?

Questions:
Does the above expectation seem right?
When in interrupt "every index pulse" does the FDC generate an interrupt every time the FDC received the IP signal (as name imply) or only the first time? When is this interrupt reset (i.e. INTRQ reset)? Is it by reading the status (as normal command)? or what?

My guess is following:
- Send command $d4 – intrq set when command done – reset by reading status
- Every time FDC receive IP signal: intrq raised – reset by reading status
- terminate (reset int condition) by sending $d0

But as mentioned does not seem to work… I even tried to test that intrq is reset after $d4 + read status, before waiting for a new intrq for IP. Seems better but still not getting first sector…

Result is:
- Not random anymore
- always same sector [for same track see info below] returned on different machine (consistent)
- but first sector read is somehow related to track number ????????? i.e. diff track => diff 1st sector ????????

ijor
Hardware Guru
Hardware Guru
Posts: 3624
Joined: Sat May 29, 2004 7:52 pm
Contact:

Postby ijor » Tue Jan 09, 2007 5:03 pm

Hmm, I am facing a difficult situation and don't know what to do.

If I ignore the question, everybody would realize and I would be blamed of not sharing my knowledge.

If I just answer the question, then people would think that they are not getting much beyond, or will get the feeling that I'm not telling everything.

If I elaborate, then some might say I am trying to impress people using high language.

I feel I cannot win this one... anyway, here it is, everybody is free to think as he likes. And don't take the above serious, just trying to bring some humor :)

DrCoolZic wrote:Send the force interrupt command ($D4). As any command wait for the INTRQ to indicate completion. Read the status to reset the INTRQ. If the bit S1 (IP signal) is set we are done otherwise


Don't check the S1 bit in the status register. You already know you are on the index. See the section titled "Status register" right after the description of the Force Interrupt commands.

Yes, it keeps "interrupting", not just once.
And yes, reading the status register terminates the interrupt.

- but first sector read is somehow related to track number ????????? i.e. diff track => diff 1st sector ????????


Can't say without more details. But I suppose you realize some disks are formatted exactly like that. Sometimes called twisted, sometimes with a custom interleave, to optimize the reading.

ijor
Hardware Guru
Hardware Guru
Posts: 3624
Joined: Sat May 29, 2004 7:52 pm
Contact:

Postby ijor » Tue Jan 09, 2007 6:51 pm

Just one more thing. I'm not sure this kind of stuff is very suitable to implement with a third party library. You might need to take care of many smaller and finer details. And the library might interface in unexpected ways.

It would probably be a better idea to implement your own low level code. You do need good understanding of the FDC behavior, but you need it anyway. And you still can borrow code from the library's source. Just make sure you understand exactly every step when you copy portions of the code.

User avatar
DrCoolZic
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2188
Joined: Mon Oct 03, 2005 7:03 pm
Location: France
Contact:

Postby DrCoolZic » Tue Jan 09, 2007 8:14 pm

ijor wrote:It would probably be a better idea to implement your own low level code. You do need good understanding of the FDC behavior, but you need it anyway. And you still can borrow code from the library's source. Just make sure you understand exactly every step when you copy portions of the code.
?????
I probably did not explain myself well? This is exactly what I am doing: I am creating a library in C (initially borowing code provided by Nyh) that allow very low level FDC / MFP / PSG / DMA (so far) and medium/high level FD.
Note that the low level stuffs, for all the above mentioned devices, are currently only focused on the FDC. Low level for FDC is done at about 90% and high level about 50%.

I did not reply to your previous input, because I want to make sure that I analyze carefully your answer so we avoid previous communication problem. And yes I have read, read, read and read again the type IV commands and the Status Register paragraphs.

I am obviously doing something wrong because the floppy I am looking at is a basic floppy created on PC. And to be 100% sure I have also analyzed the diskette with DC and all tracks are done with 9 sectors ordered 1 to 9 always starting with 1 ... so ... I originally thought of a timing problem but reading sector 9 as the first sector means a big big timing problem!
thanks

ijor
Hardware Guru
Hardware Guru
Posts: 3624
Joined: Sat May 29, 2004 7:52 pm
Contact:

Postby ijor » Tue Jan 09, 2007 8:40 pm

DrCoolZic wrote:I probably did not explain myself well? This is exactly what I am doing:


I see, sorry for the misunderstand. Just ignore that message then.

I did not reply to your previous input, because I want to make sure that I analyze carefully your answer so we avoid previous communication problem.


Let's not overreact :) That's why I really added that humoristic intro, for breaking the ice.

And yes I have read, read, read and read again the type IV commands and the Status Register paragraphs.


Short answer: Again, don't read the S1 bit in the status register. After the interrupt you already know you are over the index.

Long answer: As described in that section of the DataSheet, the Force Interrupt command might not update all the bits in the status register. It depends on which command was currently in process when the Force Interrupt command was issued.

I am obviously doing something wrong because the floppy I am looking at is a basic floppy created on PC.


Did you try ignoring the S1 bit as recommended above?

Note that you don't necessarily need to use the Force Interrupt. You can just poll the status register, now yes monitoring the leading edge of the S1 bit. You are polling and not actually using the interrupt anyway, right?

If it doesn't help, send me the program, I'll take a look. It would help if you could reduce it to bare minimum to be able to duplicate the problem. No need for the source, a binary should be enough.

User avatar
DrCoolZic
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2188
Joined: Mon Oct 03, 2005 7:03 pm
Location: France
Contact:

Postby DrCoolZic » Wed Jan 10, 2007 3:51 pm

Still does not work, still does not make sense!!!

What is now clear:
1) Force interrupt with IP condition ($d4) raises INTRQ each time IP signal received from drive.
2) When reading status for this interrupt Bit S1 is always set (make sense) as well as bit S7 (motor on) and eventually bit S2 (TRK00) when on track 0 all other bits are set to 0 (status = $82 or $86)
3) To stop interrupts for IP a $d0 command need to be send.
4) As mentioned by Ijor if goal is to test IP better just read the status directly (without using $d4 command) and test for bit S1 set.
5) Status not very well documented? Says that status is updated at command start and completion or by force interrupt command. In fact it seems that bit S8 (motor) and S2 (IP) are always updated outside of any command execution/completion. This allow to look for IP as mentioned above or to test motor off to deselect drive (remember do not deselect before motor is off otherwise motor will stay on forever!).

So I implemented my fd_read_address function based on above assumption code looks like this:

Code: Select all

   fd_select(drive, side);                  // select drive and side
   set_dma(buffer, 1, READ_MODE);               // prepare DMA for transfer
   fd_goto_track(track));
   while (--time) {
      if (fdc_read_reg(FDC_CMDS) & FDC_IP) break;
   }   // wait for index pulse in status

   while (--loop) {
      if (!fdc_read_address()) break;
      // the RNF, CRC, LOST DATA errors are ORed for all IDs read
      status |= (byte)(fdc_read_reg(FDC_CMDS) & 0x1A);
   }   // read_address 24 times to pass buffer

Where fdc_read_address is:

Code: Select all

int fdc_read_address() {
   int      time = LONG_TIMEOUT;
   fdc_write_reg(FDC_CMDS, 0xC0);
   while (--time) {
      if (fdc_intr_status()) break;
   }   // timeout
   return time;
}   // end of fdc_read_address
The functions should be easy to follow?

But the result is extremely strange:
1) I always get the same first sector for a specific track on same or different machines (STE and STF). This means that results are predictable and not random (testing IP gets this result).
2) Result is for track 0 first sector 0, for track 1 sector 6, for track 2 sector 2, for track 3 sector 7, etc (wrapping from 9 to 1) !!! ???
3) Somehow the first sector to be read is directly dependant on the track number (diskette formated on STE with standard 9 s/t) !!!
4) Originally I thought that this could be caused by routine taking too much time to execute: first ID sector is about 75 bytes from IP that is roughly over 2 ms and subsequent sector ID are about 600 bytes apart or roughly 19 ms. But 2 ms should be enough time + it does not explain why getting different results on different tracks.

I must be doing something stupid by I checked the code many times and could not found any obvious problem (apart from code not optimized).

Attached is a test executable that shows the results. As well as a debug version that does not work correctly because it is too slow printing debug information (e.g. it may loop forever waiting for IP!) but it can be usefull as it shows the sequence of calls of all the functions + returned values.

Any ideas is welcomed???

Other subsidiary problem after exit from one execution sometimes system is "unstable" and will bomb and/or program will not execute twice in that case reset the system (need to investigate later)
You do not have the required permissions to view the files attached to this post.

ijor
Hardware Guru
Hardware Guru
Posts: 3624
Joined: Sat May 29, 2004 7:52 pm
Contact:

Postby ijor » Wed Jan 10, 2007 5:33 pm

I can't reproduce the behavior, I constantly get the first header on all tracks.

I did note that apparently you are selecting/deselecting the drive without disabling interrupts. That's too bad. That might explain everything because you would get all sort of strange behavior.

For further tests, please do as I asked. Reduce the program to the bare minimum for reproducing the problem. Make sure you are still getting the problem with the reduced version.


Social Media

     

Return to “Coding”

Who is online

Users browsing this forum: Bing [Bot] and 7 guests