Nothing to do with the way the Input Routine has to receive the return codes from the Joystick. If it's working fine from the cursor key from the keyboard, then it won't be that.
Actually it has EVERYTHING to do with how the PC joystick interface works.
The problem stems from IBM cheaping out on the original game card and not putting a real analog to digital converter in there. Instead all there is for parts is a capacitor and a comparator. To read the position of the analog joystick you output $FF to the joystick port, which discharges the capacitor. The Joystick's pot is wired between the capacitor and power changing how fast the capacitor charges back up -- the comparator fires changing the value at the joystick port when the capacitor is fully charged.
So to read the joystick you send $FF to discharge, and then run a tight loop with interrupts disabled waiting to see how many times your code loops until the capacitor is charged. The number of times you loop is the joystick position... as such, it takes longer to read 'right' or 'bottom' than it does to read 'left' or 'top'...
Basically to read the joystick the code is this:
Code:
positionX:=0;
port[$201]:=$FF;
repeat inc(positionX) until (port[$201] and $01);
positionY:=0;
port[$201]:=$FF;
repeat inc(positionY) until (port[$201] and $02);
So when X is zero, the X loop takes less time to run, when Y is zero, the Y loop takes less time to run.
My joystick position code uses ASM and decrements CX -- that way I can leverage "loop" so that if no stick is plugged in the system doesn't go off to never never land.
Code:
function joystickPosition(stick:byte):word; assembler;
asm
mov ah,1
mov cl,stick
and cl,$03
shl ah,cl
mov cx,$3FFF
mov dx,stickPort
mov al,$FF
cli
out dx,al
@testLoop:
in al,dx
test al,ah
jz @done
loop @testLoop
@done:
sti
or cx,$C000
not cx
mov ax,cx
end;
Killing the interrupts makes the result have less "jitter".
It's 'cute' because while it makes the analog joystick interface really cheap to make, it is also inaccurate, inconsistent across systems, the values returned change based just on the speed of the machine you're running it on, can change just because the capacitor warms up during gameplay, etc, etc... There's a reason as soon as USB came along the PC joystick interface went the way of the Dodo.
The TRS-80 color computer was similarly afflicted, though nowhere near as badly as the PC. On their version of the interface they use the 6 bit DAC to output a reference voltage, which the comparator then returns if that reference voltage is higher or lower than the voltage returned by the stick... so to read the position you have to compare against every voltage the DAC can output. (best done with divide and conquer though many people just looped like on the PC)
Honestly, the PC version is such a flaky piece of trash, it's a miracle anyone was able to write games that worked with it in the first place.
With specs like those I would have been able to run that on my dream CPC machine, sadly the powers that be which only criticise the 8088 processor are missing out!
Yeah, even if you could port it those 8 bit registers just wouldn't be fast enough to keep up with the code... I was playing with the 160x200 PCJr/Tandy modes which are similar to the 160x200 of the amstrad -- and that drags the game performance down even further.
One cute thing about my using such a "low resolution" is it ends up less pixels to shove around per sprite... which is how I was able to get such smooth gameplay on a 8088 in the first place compared to 320x200 4 color games. A 5x5 sprite ends up (with 4 bits 'overscan') 30 bytes to write to memory where the scanlines are at least planar in a 16 color mode. Writing the same code to the CGA ends up needing more logic to handle the 'every other scanline' memory interlace, which ends up taking longer on top of having four times as many pixels to fill AND having to handle shifts across a 32 pixel area width... That's 80 bytes per sprite to send to memory and 640 bytes of RAM per sprite if you pre-store your shifted copies. The other alternative being weighing yourself down with RCR hi16; ROR lo16; LAHF; XOR AL,AL; AND AL,CFMask; SHL AL,CFShift, AND lo16,AX -- for every scanline (ouch).