Post by Malban on Dec 5, 2016 11:20:24 GMT -5
Hi...
To keep up the tradition of posting Vide documentation :-):
Joyport Devices
Part one - Buttons!
Below I mainly explain how to use buttons to "transport" data to a device connected to the joyport. If you understand the below things - it will be easy to read such simple things as buttons states. So - for now I will not explain that :-)!
Vectrex has two joyports, both are wired:
Vectrex Controller & Port Connections:
Pin 1: Button 1
Pin 2: Button 2
Pin 3: Button 3
Pin 4: Button 4
Pin 5: Joystick: Horizontal
Pin 6: Joystick: Vertical
Pin 7: +5V
Pin 8: Ground
Pin 9: -5V
For easier writing, in the following I will say "button x" whenever I refer to "Pin x". And what I really mean is: the device connected to Pin x.
Specials:
Port 0 Button 4 is wired to 6809 FIRQ line
Port 1 Button 4 is wired to 6522 CA1 line
Both lines are DIRECTLY connected to the button outputs, these connections are not going thru PSG chip first!
Devices (except for e.g. paddles) on the joyports usually only use the four "buttons" to communicate with vectrex (Lightpen, Imager, LinkCables, VecSpeech).
Although in theory all devices can be plugged into both ports usually only port 1 is used for these devices, since:
the vectrex "user" is used to having a joystick in port 0
all programs making use of the devices have to adjust to the ports, and they usually don't do that
The only device known, that actually IS used in port 0 is the lightpen. There is one program (Engine Analyzer) which expects the lightpen in port 0.
Communication
There are two types of communication possible:
direct
Uni directional communication: Device → vectrex.
The direct communication can only be used FROM the device TO vectrex. This can only be done via "button 4" which is connected to CA1 or FIRQ.
indirect
Bi directional communication is possible using the PSG chip.
Port 0 button 1-4 are connected to the four lower bits of Port A of the PSG chip.
(button 1 to bit 0, button 2 to bit 1, button 3 to bit 2, button 4 to bit 3)
Port 1 button 1-4 are connected to the four upper bits of Port A of the PSG chip.
(button 1 to bit 4, button 2 to bit 5, button 3 to bit 6, button 4 to bit 7)
interlude PSG
It is worth noting, that the Port A has two modes:
Input mode (port A of PSG can be written to from the outside)
Output mode (port A of PSG can output data to the outside )
The mode of the port is set by bit 6 of register 7 of the PSG (0 = input, 1 = output).
It seems, that internally the PSG has a special storage area for output values. This "storage" is not effected by the values which are put to the port A lines (from the outside). Upon switching from input to output mode, the values from that internal storage are always restored and set to port A.
In INPUT-mode
It seems that the output values can ALSO be set while PSG is in input mode. (Setting output data while in input mode, sets the data to that internal "storage" area, the actual port A will always read $ff when read[from the outside] while in input mode.)
In OUTPUT-mode
The opposite does not seem to be true. When PSG is in output mode, it seems data can still be "correctly" read from the PSG side (meaning: reading from the vectrex side, reading out PSG register (reg 14) reads the state of the buttons (NOT $ff) - my first guess would have been to read a $ff if in output mode - but this is NOT the case)
interlude end
Accessing the Buttons
As mentioned above, the joyport buttons are directly connected to PSG port A. To read or write to the buttons the programmer must access Port A of PSG.
The PSG on the other hand is not connected/mapped to any memory location. To access PSG one has to go through VIA 6522.
Now it gets confusing.
VIA also has a Port A (Reg 1), the lines of VIA port A are "passed" through the PSG chip to the DAC. We are ignoring DAC and all that follows at the moment and just acknowledge the fact, that PSG chip is connected (with its DA0-7 lines [DA stands for Data/Address, you will see why later]) to VIA.
So - at the end of the day to read or write values to the PSG one has to go thru VIA (port A). (Needless to say, that Via port A also can be input or output, which in turn is configured by Via Reg 3 DDRA).
Now, PSG has only one 8 bit "line" (DA0 - DA7) as Input/Output for data. But we also have to tell the PSG what we want to do (read or write, and from where or where to). For that purpose there are two other PSG "pins" available (in reality 3, but we are ignoring BC2 here).
Pin:
BDIR (Bus Direction)
BC1 (Bus Control 1)
Those two pins taken together can be read as a two bit number with following meaning:
BDIR/BC1: 00 - inactive
BDIR/BC1: 01 - read from PSG
BDIR/BC1: 10 - write to PSG
BDIR/BC1: 11 - latch address
With configuring these pins in conjunction with the DA lines we access the PSG and can read or write values.
Simple example:
Task: read value of register 7
We set following "things" of PSG:
DA = 7
BDIR/BC1 = 00
BDIR/BC1 = 11
BDIR/BC1 = 00
BDIR/BC1 = 01
DA can now be read with the value of PSG Reg 7
Comments:
first set the register we are interested in to DA
(hence D"A" (ADDRESS we want to read))
set BDIR/BC1 = 00 to INACTIVE, this is NEEDED!
Switching the state of BDIR/BC1 can not be done directly!
Switching to a state (different 00) must ALLWAYS be done from state 00!
set BDIR/BC1 = 11, PSG remembers the value in DA (7) as the current latched address
meaning: the next read or write access will be done with that latched address
set BDIR/BC1 = 00 see above
set BDIR/BC1 = 01 read the currently latched register (7) to DA
(hence "D"A (since now it is filled with DATA of reg 7))
BDIR and BC1
These two pins are again set (can not be read!) by setting appropriate bits to VIA.
More specific both pins are connected to VIA port B.
Even still more specific:
BDIR is bit 4 of via port B
BC1 is bit 3 of via port B
Real world vectrex example:
Writing a value to joystick buttons
(value of A is "split" to two nibbles,
the lower nibble will end up in Port 0 buttons
the upper nibble will end up in port 1 buttons
- with vectrex, writings to port 0 will usually be discarded
by an ignorant joystick :-) )
Note:
BC1/BDIR = 00 is used at the end of each command. This is ok, if this is followed strictly, since before each setting BC1/BDIR must be 00, which is still "honoured".
Note:
The vectrex BIOS also supports PSG "operations". If you only use BIOS functions to access PSG, than all registers of the PSG are shadows at the RAM locations:
$c83f (register 14)
...
$c84c (register 0)
Yes - in reverse order!
You can read those values and use them as you would do "directly". To poke a value at register 7 you would do:
Part two - Joystick!
Reading values of the joystick is not as easy as one might think.
(Or - you just use the available BIOS functions - THAT makes it quite easy, but that is explained elsewhere).
The vectrex was one of the first machines to have analog joysticks. Below I will try to explain how they are implemented and accessed.
Each joystick direction is implemented as a potentiometer. Alltogether there can be four such potentiometers:
port 0: horizontal
port 0: vertical
port 1: horizontal
port 1: vertical
Do you remember how the integrators have access to DAC values? The DAC value goes "thru" a multiplexer. The multiplexer has two "SELECT" lines (Via port B bit 1+2). The select values "multiplex" the one input signal to one of four output lines. The output line is chosen by the value of the select lines.
Why am I telling you that?
Because with the joystick potentiometers this is the same.
REALLY the same, since the physical electronic part inside the vectrex is the same (4052b). That chip is a Multiplexer/DeMultiplexer. The same select lines (Via port B bits 1+2) select which of the 4 potentiometers is taken as input:
Bit2+Bit1:
00: port 0 horizontal
01: port 0 vertical
10: port 1 horizontal
11: port 1 vertical
The demultiplexer sets the voltage of the one selected potentiometer to a circuit which is connected to the DAC and a special other pin.
The circuit compares the value of the potentiomenter to the analog value received from the DAC. If the contents of the DAC (the analog representation of a digital signed value ranging from -128 to +127) is smaller than the value gotten from the potentiometer, than the above mentioned pin is set to true - otherwise false.
The pin (how could it be otherwise) is again part of Via - it can be found in Via port B bit 5. The bit/pin is cleverly named "comparator input bit" (meaning: input from the comparator, not input to the comparator!).
With that information, a digital request in pseudo code can be done like:
Question: is Joystick port B moved to right?
disable mux
dac = 0
mux sel = 00
enable mux
delay short
disable mux
delay "long"
load dac with some positive value
check compare bit
if set than joystick was moved right
To get an analog value in principle the same must be done, but you have to test more. The line "load dac with some positive value" - and the checking afterwards has to be done with increasing values till a point is reached where the flag is not set anymore. The last set value (or the first unset value) is the digital representation of the potentiometer of the current joystick axis.
This is, why it is usually a good idea to only use analog values if it absolutely neccessary, since it is time consuming to do the aproximation.
Real life example of a digital joystick "request" for port 0:
(not the BIOS function)
Malban
To keep up the tradition of posting Vide documentation :-):
Joyport Devices
Part one - Buttons!
Below I mainly explain how to use buttons to "transport" data to a device connected to the joyport. If you understand the below things - it will be easy to read such simple things as buttons states. So - for now I will not explain that :-)!
Vectrex has two joyports, both are wired:
Vectrex Controller & Port Connections:
Pin 1: Button 1
Pin 2: Button 2
Pin 3: Button 3
Pin 4: Button 4
Pin 5: Joystick: Horizontal
Pin 6: Joystick: Vertical
Pin 7: +5V
Pin 8: Ground
Pin 9: -5V
For easier writing, in the following I will say "button x" whenever I refer to "Pin x". And what I really mean is: the device connected to Pin x.
Specials:
Port 0 Button 4 is wired to 6809 FIRQ line
Port 1 Button 4 is wired to 6522 CA1 line
Both lines are DIRECTLY connected to the button outputs, these connections are not going thru PSG chip first!
Devices (except for e.g. paddles) on the joyports usually only use the four "buttons" to communicate with vectrex (Lightpen, Imager, LinkCables, VecSpeech).
Although in theory all devices can be plugged into both ports usually only port 1 is used for these devices, since:
the vectrex "user" is used to having a joystick in port 0
all programs making use of the devices have to adjust to the ports, and they usually don't do that
The only device known, that actually IS used in port 0 is the lightpen. There is one program (Engine Analyzer) which expects the lightpen in port 0.
Communication
There are two types of communication possible:
direct
Uni directional communication: Device → vectrex.
The direct communication can only be used FROM the device TO vectrex. This can only be done via "button 4" which is connected to CA1 or FIRQ.
indirect
Bi directional communication is possible using the PSG chip.
Port 0 button 1-4 are connected to the four lower bits of Port A of the PSG chip.
(button 1 to bit 0, button 2 to bit 1, button 3 to bit 2, button 4 to bit 3)
Port 1 button 1-4 are connected to the four upper bits of Port A of the PSG chip.
(button 1 to bit 4, button 2 to bit 5, button 3 to bit 6, button 4 to bit 7)
interlude PSG
It is worth noting, that the Port A has two modes:
Input mode (port A of PSG can be written to from the outside)
Output mode (port A of PSG can output data to the outside )
The mode of the port is set by bit 6 of register 7 of the PSG (0 = input, 1 = output).
It seems, that internally the PSG has a special storage area for output values. This "storage" is not effected by the values which are put to the port A lines (from the outside). Upon switching from input to output mode, the values from that internal storage are always restored and set to port A.
In INPUT-mode
It seems that the output values can ALSO be set while PSG is in input mode. (Setting output data while in input mode, sets the data to that internal "storage" area, the actual port A will always read $ff when read[from the outside] while in input mode.)
In OUTPUT-mode
The opposite does not seem to be true. When PSG is in output mode, it seems data can still be "correctly" read from the PSG side (meaning: reading from the vectrex side, reading out PSG register (reg 14) reads the state of the buttons (NOT $ff) - my first guess would have been to read a $ff if in output mode - but this is NOT the case)
interlude end
Accessing the Buttons
As mentioned above, the joyport buttons are directly connected to PSG port A. To read or write to the buttons the programmer must access Port A of PSG.
The PSG on the other hand is not connected/mapped to any memory location. To access PSG one has to go through VIA 6522.
Now it gets confusing.
VIA also has a Port A (Reg 1), the lines of VIA port A are "passed" through the PSG chip to the DAC. We are ignoring DAC and all that follows at the moment and just acknowledge the fact, that PSG chip is connected (with its DA0-7 lines [DA stands for Data/Address, you will see why later]) to VIA.
So - at the end of the day to read or write values to the PSG one has to go thru VIA (port A). (Needless to say, that Via port A also can be input or output, which in turn is configured by Via Reg 3 DDRA).
Now, PSG has only one 8 bit "line" (DA0 - DA7) as Input/Output for data. But we also have to tell the PSG what we want to do (read or write, and from where or where to). For that purpose there are two other PSG "pins" available (in reality 3, but we are ignoring BC2 here).
Pin:
BDIR (Bus Direction)
BC1 (Bus Control 1)
Those two pins taken together can be read as a two bit number with following meaning:
BDIR/BC1: 00 - inactive
BDIR/BC1: 01 - read from PSG
BDIR/BC1: 10 - write to PSG
BDIR/BC1: 11 - latch address
With configuring these pins in conjunction with the DA lines we access the PSG and can read or write values.
Simple example:
Task: read value of register 7
We set following "things" of PSG:
DA = 7
BDIR/BC1 = 00
BDIR/BC1 = 11
BDIR/BC1 = 00
BDIR/BC1 = 01
DA can now be read with the value of PSG Reg 7
Comments:
first set the register we are interested in to DA
(hence D"A" (ADDRESS we want to read))
set BDIR/BC1 = 00 to INACTIVE, this is NEEDED!
Switching the state of BDIR/BC1 can not be done directly!
Switching to a state (different 00) must ALLWAYS be done from state 00!
set BDIR/BC1 = 11, PSG remembers the value in DA (7) as the current latched address
meaning: the next read or write access will be done with that latched address
set BDIR/BC1 = 00 see above
set BDIR/BC1 = 01 read the currently latched register (7) to DA
(hence "D"A (since now it is filled with DATA of reg 7))
BDIR and BC1
These two pins are again set (can not be read!) by setting appropriate bits to VIA.
More specific both pins are connected to VIA port B.
Even still more specific:
BDIR is bit 4 of via port B
BC1 is bit 3 of via port B
Real world vectrex example:
Writing a value to joystick buttons
(value of A is "split" to two nibbles,
the lower nibble will end up in Port 0 buttons
the upper nibble will end up in port 1 buttons
- with vectrex, writings to port 0 will usually be discarded
by an ignorant joystick :-) )
; value given in A
; write value to joystick ports (buttons)
; Port A of PSG is kept in OUTPUT mode
; assuming that port A of VIA is in output mode
; and also that port B of VIA is otherwise configured to correct IO settings
write_A_toJoy2:
sta -01,s ; store given value on stack
; Latch Reg $07 of PSG
lda #$07 ; Register 7 of PSG
sta <VIA_port_a ; VIA A = 0x07
ldd #$9981 ; 1001 1001 / 1000 0001 1) bit 3+4 == 11, 2) bit 3+4 = 00
sta <VIA_port_b ; VIA Port B = 99, mux disabled, RAMP disabled, BC1/BDIR = 11 (Latch address)
stb <VIA_port_b ; VIA Port B = 81, mux disabled, RAMP disabled, BC1/BDIR = 00 (PSG inactive)
; write value of $7f to reg $07 (latched)
lda #$7F ; $7f to VIA A (DAC) $7f = 0111 1111, disable all noise and tone in psg,
; ENABLE OUTPUT on port A of PSG (port B irrelevant since it is a 8912)
sta <VIA_port_a ; $7f to VIA A (DAC)
ldd #$9181
sta <VIA_port_b ; VIA Port B = 91, mux disabled, RAMP disabled, BC1/BDIR = 10 (Write to PSG)
stb <VIA_port_b ; VIA Port B = 81, mux disabled, RAMP disabled, BC1/BDIR = 00 (PSG inactive)
; now port A of PSG is in output mode and can be written to
; Latch Reg $E of PSG (Port A)
lda #$0E
sta <VIA_port_a ; $0e to VIA A (DAC)
ldd #$9981 ; 1001 1001 / 1000 0001 1) bit 3+4 == 11, 2) bit 3+4 = 00
sta <VIA_port_b ; VIA Port B = 99, mux disabled, RAMP disabled, BC1/BDIR = 11 (Latch address)
stb <VIA_port_b ; VIA Port B = 81, mux disabled, RAMP disabled, BC1/BDIR = 00 (PSG inactive)
; write_A_to port
lda -01,s ; read value from stack
sta <VIA_port_a ; output value to via VIA port A to Port A of PSG (Joystick buttons)
ldd #$9181 ; 1001 0001 / 1000 0001 1) bit 3+4 == 10, 2) bit 3+4 = 00
sta <VIA_port_b ; VIA Port B = 91, mux disabled, RAMP disabled, BC1/BDIR = 10 (Write to PSG)
stb <VIA_port_b ; VIA Port B = 81, mux disabled, RAMP disabled, BC1/BDIR = 00 (PSG inactive)
rts
Note:
BC1/BDIR = 00 is used at the end of each command. This is ok, if this is followed strictly, since before each setting BC1/BDIR must be 00, which is still "honoured".
Note:
The vectrex BIOS also supports PSG "operations". If you only use BIOS functions to access PSG, than all registers of the PSG are shadows at the RAM locations:
$c83f (register 14)
...
$c84c (register 0)
Yes - in reverse order!
You can read those values and use them as you would do "directly". To poke a value at register 7 you would do:
ldb #$00 ; value to set
lda #$07 ; Register 7 of PSG
jsr Sound_Byte ; write byte to soundchip and to shadow registers
Part two - Joystick!
Reading values of the joystick is not as easy as one might think.
(Or - you just use the available BIOS functions - THAT makes it quite easy, but that is explained elsewhere).
The vectrex was one of the first machines to have analog joysticks. Below I will try to explain how they are implemented and accessed.
Each joystick direction is implemented as a potentiometer. Alltogether there can be four such potentiometers:
port 0: horizontal
port 0: vertical
port 1: horizontal
port 1: vertical
Do you remember how the integrators have access to DAC values? The DAC value goes "thru" a multiplexer. The multiplexer has two "SELECT" lines (Via port B bit 1+2). The select values "multiplex" the one input signal to one of four output lines. The output line is chosen by the value of the select lines.
Why am I telling you that?
Because with the joystick potentiometers this is the same.
REALLY the same, since the physical electronic part inside the vectrex is the same (4052b). That chip is a Multiplexer/DeMultiplexer. The same select lines (Via port B bits 1+2) select which of the 4 potentiometers is taken as input:
Bit2+Bit1:
00: port 0 horizontal
01: port 0 vertical
10: port 1 horizontal
11: port 1 vertical
The demultiplexer sets the voltage of the one selected potentiometer to a circuit which is connected to the DAC and a special other pin.
The circuit compares the value of the potentiomenter to the analog value received from the DAC. If the contents of the DAC (the analog representation of a digital signed value ranging from -128 to +127) is smaller than the value gotten from the potentiometer, than the above mentioned pin is set to true - otherwise false.
The pin (how could it be otherwise) is again part of Via - it can be found in Via port B bit 5. The bit/pin is cleverly named "comparator input bit" (meaning: input from the comparator, not input to the comparator!).
With that information, a digital request in pseudo code can be done like:
Question: is Joystick port B moved to right?
disable mux
dac = 0
mux sel = 00
enable mux
delay short
disable mux
delay "long"
load dac with some positive value
check compare bit
if set than joystick was moved right
To get an analog value in principle the same must be done, but you have to test more. The line "load dac with some positive value" - and the checking afterwards has to be done with increasing values till a point is reached where the flag is not set anymore. The last set value (or the first unset value) is the digital representation of the potentiometer of the current joystick axis.
This is, why it is usually a good idea to only use analog values if it absolutely neccessary, since it is time consuming to do the aproximation.
Real life example of a digital joystick "request" for port 0:
(not the BIOS function)
queryInputPort0:
lda #$D0 ; setup DP
tfr a,dp
direct $D0
lda #$03 ; mux disabled, mux sel = 01 (vertical pot port 0)
sta <VIA_port_b ;
clr <VIA_port_a ; dac = 0
dec <VIA_port_b ; mux enabled, mux sel = 01
ldb #$20 ; a wait loop 32 times a loop (waiting for the pots to "read" values, and feed to compare logic)
waitLoopV:
decb ; ...
bne waitLoopV ; wait...
inc <VIA_port_b ; disable mux
ldb #$20 ; load b with comparator bit (0010 0000)
lda #$40 ; load a with test value (positive y)
sta <VIA_port_a ; test value to DAC
lda #$01 ; default result value y was pushed UP
bitb <VIA_port_b ; test comparator
bne yReadDone ; if comparator not cleared - joystick was moved up
neg <VIA_port_a ; "load" with negative value
nega ; also switch the possible result in A
bitb <VIA_port_b ; test comparator again
beq yReadDone ; if cleared the joystick was moved down
clra ; if still not cleared, we clear a as the final vertical test result (no move at all)
yReadDone:
sta >joy_y ; remember the result in "our" joystick data
;
; now the same for horizontal
lda #$01 ; mux disabled, mux sel = 00 (horizontal pot port 0)
sta <VIA_port_b ;
clr <VIA_port_a ; dac = 0
dec <VIA_port_b ; mux enabled, mux sel = 01
ldb #$20 ; a wait loop 32 times a loop (waiting for the pots to "read" values, and feed to compare logic)
waitLoopH:
decb ; ...
bne waitLoopH ; wait...
inc <VIA_port_b ; disable mux
ldb #$20 ; load b with comparator bit (0010 0000)
lda #$40 ; load a with test value (positive x)
sta <VIA_port_a ; test value to DAC
lda #$01 ; default result value x was pushed right
bitb <VIA_port_b ; test comparator
bne xReadDone ; if comparator not
cleared - joystick was moved right
neg <VIA_port_a ; "load" with negative value
nega ; also switch the possible result in A
bitb <VIA_port_b ; test comparator again
beq xReadDone ; if cleared the joystick was moved left
clra ; if still not cleared, we clear a as the final vertical test result (no move at all)
xReadDone:
sta >joy_x ; remember the result in "our" joystick data
rts ; done
Malban