Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
You are not logged in - nap
CSDb User Forums


Forums > C64 Coding > Drive lockup when accessed too early - solutions?
2012-11-06 13:08
Frantic

Registered: Mar 2003
Posts: 1648
Drive lockup when accessed too early - solutions?

Hi!

When the C64 is reset, the drive also reinitializes. If I send commands to the drive too early, when the drive init is not yet finished, my cartridge based drive code routines crash. If the drive init is finished, my code works fine. But waiting is boring.

So.. is there a way to check whether the drive is available yet or not. Some kind of simple polling? If so, what to check?

Different kinds of drives seems to take different time to execute their init code, so a fixed delay loop doesn't seem to be the way to go either.

I know that carts like Action Replay and similar also fail if you try to access the drive too early after reset, so the problem seems to be a general one. ...but can it be avoided?

EDIT:
The following seems to work, but I am not sure if it is a good idea to use this code anyway. I have a feeling that this would be quite unreliable. Won't work with certain drives, or such? ...and of course the code below would simply freeze if the drive init was finished before this code even started to execute, for some potential device with a very quick init. (I do have other init code in my cart which is executed before this wait loop is reached.)

	;Wait until drive init is finished
	bit $dd00
	bmi *-3
	bit $dd00
	bpl *-3
	;Drive seems to be ready here... (?)


I have the feeling that something more sophisticated would be needed, right?
2012-11-06 15:19
SIDWAVE
Account closed

Registered: Apr 2002
Posts: 2238
you could try to get the drive status ? the one that says cbm dos vxx, this crash too ?
2012-11-06 15:34
raven
Account closed

Registered: Jan 2002
Posts: 137
Look here for a documented 1541 ROM disassembly:
http://www.ffd2.com/fridge/docs/1541dis.html

Search for "reset routine", should give you some ideas.
2012-11-07 08:06
Frantic

Registered: Mar 2003
Posts: 1648
@sidwave: can't communicate with the drive before the init is finished.

@raven: Hmhhh.. yep.. hehe.. thanks! I was hoping to be able to draw on someone's experience with many different drives etc, but yes.. if noone knows about this for sure already, then a disassembly (including those for other drives) would of course be the place to start digging. Anyway.. it actually seems to work now. I use code similar to above, but with one addition: for drives where this seems to fail (can only try some drive types in VICE, since I don't have any other physical drives than 1541-II drives, which is not optimal of course), such as 1581, I also have a timeout kind of thing as part of the polling/checking loop. ...and by the time it has timed out, the drive init is finished anyway. Not extremely sophisticated, but still an improvement over a plain delay loop.

Will leave it at that for now, and see whether it causes any problems later on or not. If it does, I'll have to dig deeper...
2012-11-07 09:03
Mace

Registered: May 2002
Posts: 1799
Frantic, either Krill or 6R6 should know more about this, don't you think?
2012-11-07 16:05
Frantic

Registered: Mar 2003
Posts: 1648
@Mace: That is definitely what I am thinking. That is also part of the reason why I don't dig deeper in the issue. (but, yes.. that's not exactly what I wrote).
2012-11-07 20:00
Mace

Registered: May 2002
Posts: 1799
Have you had a look at how the kernal deals with this, btw?
For instance, the RS-232 is checked (jsr $f0a4) before anything else.
After that it's checked if data is already being sent.
This is not relevant, since you are talking about the situation where you just did a reset.

Next, this happens (I compressed several JSRs to a single column of code):

     lda $dd00
     and $df
     sta $dd00
     cmp #$3f
     bne !+
     lda $dd00
     and #$ef
     sta $dd00
+:   lda $dd00
     ora #$08
     sta $dd00
     sei
     lda $dd00
     ora #$10
     sta $dd00
     lda $dd00
     and $df
     sta $dd00
     (1ms time loop)
     lda $dd00
     and $df
     sta $dd00
!:   lda $dd00
     cmp $dd00     
     bne !-
     asl
     bcs DEVICE_NOT_PRESENT
     etcetera...


Quite an elaborate checking before saying the device is not there.
Perhaps you should try this too? :-)
2012-11-08 11:54
Frantic

Registered: Mar 2003
Posts: 1648
hmm.. would maybe be relevant to have a look at, and I did have a little look now, but.. crucially.. the kernal doesn't actually check/prevent the problem I mention. If you try to do something simple like Graham's example on codebase64 on how to read the error channel of the drive, you find that it fails in the call to CHKIN/$FFC6 if you execute it before the drive init has finished. ...and it actually executes the routine that you mention before it gets to the point where it ends up in some eternal looping around. So.. whatever checking the Kernal does, it fails and thus do not adress the problem.

...or did I miss your point somehow?

Anyway.. my solution mentioned above of more or less simply doing this:
	;Wait until drive init is finished
	bit $dd00
	bmi *-3
	bit $dd00
	bpl *-3
	;Drive seems to be ready here... (?)

...actually seems to work fine, except on 1581 (tested in VICE). So.. to deal with 1581 as well, I just put in slightly more code that makes sure that the looping will time out after a while (becomes like a standard delay loop in that case) instead of waiting forever, and this also solves the problem to the extent that you won't at least access the 1581 too early, and avoid the crash that way. On other drives (1541, 1541-II, 1570, 1571) the $dd00-polling part of the loop works perfectly and finishes the loop exactly (to the extent that my eyes can judge this) at the point where the drive led goes off at the drive. And if I execute code that access the drive at that precise point in time, it works just fine.

I guess it remains to be seen if this works with other devices as well (uIEC and stuff like that comes to mind), but for the time being, this solution seems to work for my purposes at least. At least the timeout option of my loop ensures that the worst thing that can happen is that you get delay loop behavior instead of the more precisely timed behavior where the loop ends exactly when the drive has finished its init. So, something along the lines of this:
	ldy #0
	ldx #0
@wait1:
	nop ;To make the delay loop behavior take a little more time
	nop
	iny
	beq @yfallthrough ;Needed to make sure 1581 drives (and no-drive-connected) won't end up in eternal loop
	bit $dd00
	bmi @wait1
	bpl @wait2 ;Skip to second loop
@yfallthrough:
	inx
	bne @wait1
@wait2:
	bit $dd00
	bpl @wait2


Maybe I should put it on Codebase, and if someone else find a better solution, they can just change the page.
RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
Guests online: 104
Top Demos
1 Next Level  (9.7)
2 13:37  (9.7)
3 Mojo  (9.7)
4 Coma Light 13  (9.6)
5 Edge of Disgrace  (9.6)
6 What Is The Matrix 2  (9.6)
7 The Demo Coder  (9.6)
8 Uncensored  (9.6)
9 Comaland 100%  (9.6)
10 Wonderland XIV  (9.6)
Top onefile Demos
1 No Listen  (9.6)
2 Layers  (9.6)
3 Cubic Dream  (9.6)
4 Party Elk 2  (9.6)
5 Copper Booze  (9.6)
6 Dawnfall V1.1  (9.5)
7 Rainbow Connection  (9.5)
8 Onscreen 5k  (9.5)
9 Morph  (9.5)
10 Libertongo  (9.5)
Top Groups
1 Performers  (9.3)
2 Booze Design  (9.3)
3 Oxyron  (9.3)
4 Triad  (9.3)
5 Censor Design  (9.3)
Top NTSC-Fixers
1 Pudwerx  (10)
2 Booze  (9.7)
3 Stormbringer  (9.7)
4 Fungus  (9.6)
5 Grim Reaper  (9.3)

Home - Disclaimer
Copyright © No Name 2001-2024
Page generated in: 0.041 sec.