Weird Science - Tales from the
Vectrex Academy Lab
Vectrex
Project Title
Project
Status
Synopsis
- An investigation of the Vectrex BIOS routine
Joy_Analog ($F1F5)
- Analysis of the precision of the analog joystick
resolution (Vec_Joy_Resltn, $C81A)
Results
- The BIOS Joy_Analog() routine computes signed
8-bit values for the analog Y and X positions of the
joystick of the Vectrex controller.
- The resolution of the resulting values can be set
by modifying the value of the BIOS variable
Vec_Joy_Resltn ($C81A). Only powers of two (one-hot
encoded bit-patterns) and the value zero are allowed
here. The lower the value, the finer the resolution
will be.
- Some sources to be found on the internet say "0x80
is least accurate, and 0x00 is most accurate."
However, a value of 0x80 causes the routine not to
finish and to stay within an infinite loop.
- That loop is not a bug. The official WT "Vectrex
Programmer's Manual Volume 2" calls Vec_Joy_Resltn
by the name of POTRES and states only the following
allowed values:
POTRES = Joystick resolution limit,
where
$00 – 8 bits (default)
$01 – 7 bits
$02 – 6 bits
$04 – 5 bits
$08 – 4 bits
$10 – 3 bits
$20 – 2 bits
$40 – 1 bit
- These values correspond to the following resulting
resolutions of the computed X/Y values:
Vec_Joy_Resltn
minimum value maximum
value resolution
delta
0b00000000
-128
+127
1
0b00000001
-128
+126
2
0b00000010
-128
+124
4
0b00000100
-128
+120
8
0b00001000
-128
+112
16
0b00010000
-128
+96
32
0b00100000
-128
+64
64
0b01000000
-128
0
128
- So each resolution should give you the complete
range from minimum to maximum in steps of delta when
moving the joystick completely from one end of an
axis to the other end.
- In a post
on the Vector Gaming Forum, Graham Toal wrote
that he had observed that joystick values still only
increment or decrement only in steps of 4, despite
using the maximum resolution setting. He approached
me and suggested a deeper investigation of this
phenomenon, and that is what I did.
- On my machine I also got values changing only in
steps of 4 when slowly moving the joystick, but not
always. Most of the times, the delta was 4, but at
some rare but specific steps the delta was 2, or
even the desired 1. An analysis of the BIOS source
code, and some heavy testing then revealed the
following:
- The reason for this behavior seems to be a timing
issue, or more precisely, a DAC delay issue, or a
delay issue of the comparator circuit which is used
by the VIA.
- Due to the design of the Vectrex hardware, the
actual values of the joystick potentiometers cannot
be read directly. Theirs values can only be compared
to a value which is stored to the DAC, and the VIA
reports whether the result of such a comparison is
"lower" or "greater or equal".
- Joy_Analog implements an iterative approximation
procedure which repeatedly compares its derived
value to the actual value of the joystick, by always
guessing the middle value of the remaining interval
(bisection method). Thus, in 8 steps (iterations),
each value of a full range of 256 values (1 Byte)
can precisely be analyzed. With fewer iterations,
the resolution gets coarser as indicated by the
tables above.
- Once the current value, which is to be compared to
the actual joystick input, is stored to the DAC, it
takes some cycles until the result, which is
returned by the comparator, becomes stable and
reliable. The BIOS routine does not use any explicit
wait-cycles here:
sta
<VIA_port_a ; store value to be
compared to the DAC
lda
#0x20
; select comparator
bita
<VIA_port_b ; get
comparator result
The effect seems to be that sometimes an iteration
incorrectly gets the result from the comparison of
the previous iteration. And that causes some bits of
the computed joystick position to be wrong, and the
overall result to be somewhat fuzzy. The higher the
chosen resolution, the more frequent and prominent
these inaccuracies become (this is inherent to the
Joy_Analog algorithm).
I do not know on exactly what the specific delay
depends (DAC, VIA, mode, manufacturer, age, ...?).
For my machine, I had to introduce a whopping delay
of 18(!) cycles, until everything worked fine.
sta <VIA_port_a
; store value to be compared to the
DAC
tfr
a,a
; 6 cycles nop
tfr
a,a
; 6 cycles nop
tfr
a,a
; 6 cycles nop
lda
#0x20
; select comparator
bita
<VIA_port_b ; get
comparator result
I do not think that 18 cycles are always necessary.
The effect caused by this DAC delay (or comparator
delay) seems to depend on the number of bits flipped
when storing a new value to the DAC (compared to its
previous value). But I had to go up to 18 cycles to
make the whole thing always work reliably.
- I have patched my BIOS accordingly, and now I
always get the full 8-bits resolution for the
joystick values when setting maximum resolution, and
I also get the correct values for lower resolutions.
- There are not many games which actually use the
analog joystick mode, and whether or not the effects
of such a patch become noticeable might vary from
Vectrex to Vectrex, depending on the hardware and
the state it is in. In my case I have so far found
two examples where I could see a difference.
- Hyperchase is infamous for its delicate analog
sideways steering of the car. It uses Joy_Analog
with maximum resolution, and with the patch the car
now moves a tiny bit more smoothly from side to
side.
- Starhawk, in analog joystick mode, uses a value of
4 for Vec_Joy_resltn. With the patch, I now get
exactly the corresponding reduced resolution,
without the occasional fuzziness. However, this
somehow makes the gameplay feel worse. I guess that
the previous fuzziness of the computed joystick
values here actually added to the benefit of
playability. I modified Starhawk to use maximum
resolution 0 for Vec_Joy_resltn, and now, with the
patched BIOS, I get a cross hair moving really
smoothly across the complete screen.
- The downside of the patch, of course, is that
Joy_Analog now eats up even more cycles than it
already does.
Trivia
- The way the approximation algorithm (iterated
bisection) is implemented in Joy_Analog is actually
quite clever and short. Really nice job of the
original programmers!
Update
- Instead of using an artificial delay of 18 cycles
in two places of the approximation algorithm (total
delay of 36 cycles), I now use a delay of 26 cycles
in just one place. That seems to work reliably, at
least on my machine.
- I have also optimized several other parts of the
code, and since Joy_Analog shares some parts of this
code with Joy_Digital, the side-effect is a slight
speed-up of Joy_Digital. Some numbers:
estimated cycle count of Joy_Digital
(original):
92 + ~224 * n
estimated cycle count of Joy_Analog
(maximum resolution, original): 99 + ~479
* n
estimated cycle count of Joy_Digital
(optimized):
86
+ ~222 * n
estimated cycle count of Joy_Analog
(maximum
resolution, optimized): 93 + ~664 * n
where n is the number of results to compute (between
0 and 4). So we see that the fix for getting the
optimum analog resolution comes at a price.
- The optimized code is one byte shorter than the
original and nicely fits into the respective ROM
space.
Author
Test
Program Screenshots
Downloads
- The program
uses several (custom) Joy_Analog routines.
- It will show
you the current x value of controller 1 (in
decimal and in binary), and the current
joystick resolution (binary only).
- Press buttons
1 and 2 to decrease or increase the
resolution (caveat: do not use value
0b10000000, see above).
- Press button 4
to cycle through the different versions of
the Joy_Analog routine. This allows you to
switch between the resident BIOS of your
machine, BIOS B796/7931 (both have the same
Joy_Analog code), BIOS 7adb (there is a
slight change in the code of Joy_Analog in
this BIOS version which might give some
better results), and my patched Joy_Analog
routine with additional wait cycles.
- Slowly move
the joystick from end to end and see what
values and actual resolution you get.
- I would be
interested to learn if you also get the
complete range and the correct values for
each resolution using my 18-cycles patch, or
if there might be more cycles necessary, so
please let me know.
- Downloads are free and for non-commercial use
only. Use at your own risk.
- Please
respect the copyright and credit the
author and the origin of this project.
Latest modification on 05/15/2024,
14:15
|