VOGONS

Common searches


Games with joystick problems with high cycle counts

Topic actions

  • This topic is locked. You cannot reply or edit posts.

First post, by Justice

User metadata
Rank Newbie
Rank
Newbie

There are two joystick problems with WC3. One, is that it jumps all over, but this seems to be fixed with HAL9000's timer fix (I haven't verified that this is exactly what fixed it, but it is in HCl's dosbox build, so that seems most likely. I haven't found a .patch or .diff that includes this change yet).

The second appears to be a bug or "missing feature" in the 0x201 port read. The attenuation of the axis doesn't appear to be based on time at all. WC3 seems to take into account how long it should really take for the axes to hit 0, and when this happens much too quickly (like it does with cycles = 40000), it doesn't wind up with a large enough range of values to work correctly. Adding a sort of delay into the source code that skips xcount-- and ycount-- for a few reads in a row (really, you could calculate what the rate of decrease should be), and that makes WC3 happy.

Unfortunately, "fixing" this "problem", if it is one, (it may very well be that I'm not understanding something as well) would slow down any game reading the joystick this way, both by slowing down the emulation and forcing it to use more cycles to get a clean reading.

Reply 2 of 80, by Qbix

User metadata
Rank DOSBox Author
Rank
DOSBox Author

yes. our current joystick code has only one timeout. after certain amount of time the joystick will always be zero. but this is the oposite of you want.

The current code is not safe with different amount of cycles. Especially amounts of 40000 were not considered when we created that code. (my pc still maxes out on 10000)

Which amount of delay did you add? (please post the code).

Water flows down the stream
How to ask questions the smart way!

Reply 3 of 80, by Justice

User metadata
Rank Newbie
Rank
Newbie

I didn't figure out what would be a correct delay to use, I just hacked something in really fast to make sure I was correct. This would not work for lower or higher cycle counts than I was using. Basically:

//up top
static Bit32u last_read_dec = 0;

//down in read_p201
Bit8u ret=0xff;
if (stick[0].enabled) {
if( last_read_dec - CPU_Cycles > 12 )
{
if (stick[0].xcount) stick[0].xcount--; else ret&=~1;
if (stick[0].ycount) stick[0].ycount--; else ret&=~2;
if (stick[0].button[0]) ret&=~16;
if (stick[0].button[1]) ret&=~32;

//LOG_MSG( "READ A %d, %d, %d, %d", stick[0].xcount, stick[0].ycount, last_read_dec, CPU_Cycles );
last_read_dec = CPU_Cycles;
}
else
{
if (stick[0].xcount) stick[0].xcount; else ret&=~1;
if (stick[0].ycount) stick[0].ycount; else ret&=~2;
if (stick[0].button[0]) ret&=~16;
if (stick[0].button[1]) ret&=~32;
//LOG_MSG( "READ B %d, %d, %d, %d", stick[0].xcount, stick[0].ycount, last_read_dec, CPU_Cycles );
}

//down in write_p201
last_read_dec = CPU_Cycles;

(yes, its bad, I know, that's why I didn't paste it in to begin with. This was just a quick test to confirm my suspicion.)
I was going to look into the correct falloff this weekend, I really don't have time right now. This problem was just driving me nuts in WC3 so I thought I'd see if I could figure out the cause.

Thanks for the reply! If I come up with anything this weekend (which I probably will), I'll definately post it here.

Reply 4 of 80, by Justice

User metadata
Rank Newbie
Rank
Newbie

http://www.hackcanada.com/blackcrawl/elctrnic/gameport.txt seems to have the formula needed:

time = 24.2 + ( 0.011 * resistance )

where time is in microseconds and resistance is in Ohms (and 0 < resistance < 100,000 ).

I'd put this to the test now, but I really only have a few minutes here and there until at least this evening, and I'm totally unfamiliar with DosBox code and what I should use for timing, so I'll probably need 30 minutes to an hour to find what I need (that PIC_Ticks thing it is currently using looks to only have a resolution of 1 second, so that's out of the question)

Reply 6 of 80, by Justice

User metadata
Rank Newbie
Rank
Newbie

Well, 1 ms isn't good enough either. According to the formula, if the axis is at max it takes about 1.1 ms to count down. If that's the best timer we've got, I'd imagine I'd have to try to determine the number of cycles it should take at the current speed, and use the cycle count.

Unless there's something else I can use that I haven't found yet, which is likely.

Reply 7 of 80, by Qbix

User metadata
Rank DOSBox Author
Rank
DOSBox Author

that is probably a working method.
We have created our own high resolution timer that way as well.
(by scheduling in smaller amount of cycles if a timer event has to happen within that millisecond sdl offers us)

Else you might see if you can make that delay function of yours a bit more cycle independant.

Water flows down the stream
How to ask questions the smart way!

Reply 8 of 80, by Shed

User metadata
Rank Newbie
Rank
Newbie

sorry...Qbix...when i'm coding MSDos stuff i use something like this C code ....

I only put here for it helps to you with joystick routines...but i'm not sure how you implement at emulation level....anyway..here's the Snipped page and the source code for Joystick routine using Union REGS structure with interrupts...

C Snippets page commented:
http://www.cs.umu.se/~isak/snippets/

/*
** JOYSTICK.H
**
** Joystick support functions
**
** Public domain demo by Bob Stout
*/

typedef enum {ERROR = -1, FALSE, TRUE} LOGICAL;

#define BOOL(x) (!(!(x)))
#define SUCCESS 0

struct joystick {
LOGICAL switch_0;
LOGICAL switch_1;
LOGICAL switch_2;
LOGICAL switch_3;

int pos_Ax;
int pos_Ay;
int pos_Bx;
int pos_By;
};

LOGICAL read_joystick(void);

/*
** JOYSTICK.C
**
** Joystick support functions
**
** Public domain demo by Bob Stout
*/

#include <dos.h>
#include "joystick.h"

struct joystick JoyStick;

/*
** read_joystick()
**
** returns SUCCESS or ERROR
**
** fills in global JoyStick structure
*/

LOGICAL read_joystick(void)
{
union REGS regs;

regs.h.ah = 0x84; /* Read the switches */
regs.x.dx = 0;
int86(0x15, &regs, &regs);
if (regs.x.cflag)
return ERROR;
JoyStick.switch_0 = BOOL(regs.h.al & 0x10);
JoyStick.switch_1 = BOOL(regs.h.al & 0x20);
JoyStick.switch_2 = BOOL(regs.h.al & 0x40);
JoyStick.switch_3 = BOOL(regs.h.al & 0x80);

regs.h.ah = 0x84; /* Read positions */
regs.x.dx = 1;
int86(0x15, &regs, &regs);
if (regs.x.cflag)
return ERROR;
JoyStick.pos_Ax = regs.x.ax;
JoyStick.pos_Ay = regs.x.bx;
JoyStick.pos_Bx = regs.x.cx;
JoyStick.pos_By = regs.x.dx;

return SUCCESS;
}

Reply 9 of 80, by Justice

User metadata
Rank Newbie
Rank
Newbie
that is probably a working method. We have created our own high resolution timer that way as well. (by scheduling in smaller a […]
Show full quote

that is probably a working method.
We have created our own high resolution timer that way as well.
(by scheduling in smaller amount of cycles if a timer event has to happen within that millisecond sdl offers us)

Else you might see if you can make that delay function of yours a bit more cycle independant.

Doing by the actual timing should be the most widely compatible method, and has the added bonus of not causing joystick calibration to drift when you run dosbox at a different speed.

That's another WC3 problem, actually, for the same reason - changing the cycles causes the calibration to drift (I think) because you're changing the amount of time it takes for the read to hit zero. This is noticeable when adjusting up and down from much lower cycle settings. I don't have 100% irrefutable proof that this causes the drift, but I will when I fix it 😉

large code snippet

If WC3 used that method, there wouldn't be a problem, but WC3 apparently does things the hard way. DosBox appears to handle that interrupt by just spewing back the values like you would expect.

Almost time to go home. Barring any more calls from my real estate agent, I should have another post tonight (one that actually has something useful in it).

Reply 11 of 80, by Justice

User metadata
Rank Newbie
Rank
Newbie

Thanks for the pointer, hal.

Here we go - joystick patch.

I don't have all that many DOS games to try it with, but it is compatible with Wing Commander 2, Wing Commander Privateer, and fixes Wing Commander 3. It does not work with HCl's hacked version of Armada (that was made to work specifically with the current dosbox's joystick implementation *shrug*). Only HCl could probably tell us what is wrong with Armada's joystick routines... maybe he could change it to just use the BIOS call? With WC3, as I expected, you can even crank the cycles up and down during the game without throwing off the calibration.

I'm not totally confident this is the best solution. At the very least, RANGE could probably be reduced considerably yet, and I wouldn't be surprised if this fix breaks some games.

Edit: Almost forgot, before applying this patch, apply h-a-l-9000's timerpatch2.txt patch to fix the jumpiness, if you haven't yet (I'm assuming its not in CVS - I'm actually working off the 0.65 release tarball)

Edit2: Just because I posted this, don't assume I'm done. I'm going to experiment with the RANGE value (maybe it should be in the .conf?) and see if I can't find something that works well for all my games at various speed settings. I have a couple more joystick dos games I could install for testing (Absolute Zero, Mechwarrior 2, maybe more), so we'll see. That'll be tomorrow though, because I'm very tired and need to get up early.

Attachments

  • Filename
    joystick.diff
    File size
    3.02 KiB
    Downloads
    83 downloads
    File license
    Fair use/fair dealing exception

Reply 14 of 80, by Qbix

User metadata
Rank DOSBox Author
Rank
DOSBox Author

uhm range configurable will not make it into the official CVS. I'm very conservative about options in there.
In your patch you speak of 24.2 ms + some formula. isn't that very long ?
(The timeout used by dosbox (mostly for loderunner) is 10 ms)

Water flows down the stream
How to ask questions the smart way!

Reply 15 of 80, by h-a-l-9000

User metadata
Rank DOSBox Author
Rank
DOSBox Author

@Qbix: 24 µs.

@Justice: Maybe you shouldn't worry too much about breaking something until you actually find something broken (if at all). It looks good (as far as my understanding goes). Does unpatched Armada work with the joystick?

1+1=10

Reply 16 of 80, by Justice

User metadata
Rank Newbie
Rank
Newbie

Ok, I'll leave that out (of the config) then.

Its 24.2 microseconds + some formula. Yes, 24.2 milliseconds would be really, really long. It can get up to about 1.1 milliseconds total with RANGE == 50000, which is still kinda long, which is why I will be trying lower values and testing with a wider variety of games.

EDIT: Just saw hal's post. It doesn't work very well with unpatched Armada, because unpatched Armada doesn't work very well with any joysticks in any environment in my experience - even my old 2 button analog sticks on my old dos machine had problems. It works for a little while after calibration, but then Armada seems to lose track of the stick completely for a while. I think I have a good chance of finding some values that work reasonably well for more or less everything I have to test with though, maybe even Armada. I also had, in a couple of hours of gameplay, something similar happen in WC3 twice, although it recovered from that.

Reply 17 of 80, by h-a-l-9000

User metadata
Rank DOSBox Author
Rank
DOSBox Author

1.1ms is what you would get with the formula. As for the perfect RANGE value, that's what the calibraiton tools in each and every game are for. Not all joysticks are 100kOhms - I have one here with 220kOhms. Reducing the RANGE too much may lead to inexact readings.
The 1.1ms (the time it takes to charge the capacitor) is probably also the reason why some games don't use the bios routine. That routine will have to "waste" one or more milliseconds to determine the joystick position on a real computer (in Dosbox it takes about zero time 😉 ). By reading the joystick directly the game can do something else meanwhile. It looks at the joystick now and then doing its own stuff in between and if the bit toggeled it uses its own time tracking mechanism to calculate the stick position.

1+1=10

Reply 18 of 80, by h-a-l-9000

User metadata
Rank DOSBox Author
Rank
DOSBox Author

Does your CPU usage hit 100%? That might mess up timings. There is also a issue with my timer patch found by Qbix - in the read_latch(...) function there is a

if (pit[counter].go_read_latch == true)
counter_latch(counter);

at the beginning. This should be moved inside the big else{ } block.

1+1=10

Reply 19 of 80, by Justice

User metadata
Rank Newbie
Rank
Newbie

Thanks, I'll check into both of those when I get home. I was keeping an eye on my CPU usage, and it didn't seem to get thrown off when it spiked up to max, at least with WC3. It definately worked fine (didn't drift or jump) when I turned up the cycles to a very high value in the calibration program (well beyond what my computer could actually handle in realtime).