
|
Muizenissen Alex vd Wal, 00-00-00
MUIZENISSEN
Het valt me telkens weer op dat er op MSX maar weinig
gebruik gemaakt wordt van de muis. Dit in tegenstelling tot
andere systemen waar de muis een absolute noodzaak is
geworden. Het is dan ook een heel slim apparaatje dat een
gigantische brug kan slaan tussen de software en de
gebruiker. Het is toch fantastisch dat er zo'n doosje is dat
als je het beweegt een gelijksoortige beweging van een
voorwerp op het scherm teweeg brengt!
DE GESCHIEDENIS
De muis is n van de belangerijkste computerontwikkelingen
van de afgelopen 15 jaar. Voorheen moesten alle commando's
domweg ingetikt worden en dat maakte de computer niet echt
toegankelijk voor het grote publiek omdat de besturing van
die dingen alleen maar door een klein elitair groepje mensen
gedaan kon worden. Daar is met de komst van de muis nu een
radikaal einde aan gekomen. De muis is zelfs zo 'makkelijk'
dat een kind dat nog maar amper praten al met een computer
overweg kan omdat de besturing zo eenvoudig is geworden.
De muis op zich is niet duur, maar de verdere (grafische)
weergave bleek ontzettend duur te zijn. Daar kwam pas
verandering in toen computers goedkoper werden omdat de
produktie omhoog ging. Plotseling werden massaal video
kaarten (en losse VDP's) gemaakt die de muis nu ook voor het
grote publiek toegankelijk maakten.
DE MUIZEN VAN NU
Nu, zoveel jaar later kost een muis niet meer dan 150
gulden. Er zijn muizen in alle soorten en maten en er is
gelukkig een zekere standarisatie van aansluiting.
Natuurlijk had IBM in haar oneindige wijsheid besloten om de
zaken zo aan te pakken dat er een behoorlijke connector voor
nodig is om een muis aan een PC te hangen, maar er waren
gelukkig ook verstandige mensen die de muis gewoon aan de
bekende 'Joystick' poort connector gehangen hebben.
Bij mijn weten gebruiken MSX, Amiga en Atari deze connector
en ze zijn ook volledig uitwisselbaar (alhoewel de standaard
meegeleverde muizen van de laatste twee matig tot slecht van
kwaliteit zijn).
DE WERKING
Er zijn ruwweg 3 soorten muizen, waarvan er twee weer op
elkaar lijken, nl:
- de elektro mechanische muis
- de opto mechanische muis
- de optische muis
De eerste vorm is meteen ook de oudste en gebruikt het
overbekende 'balletje tegen asje' systeem. Aan die twee
assen zitten echter twee pot-meters (variabele weerstand)
die 360 graden kunnen draaien. Door nu de weerstand te meten
kon de positie van de muis berekend worden. Deze vorm had
echter als nadeel dat het balletje makkelijk over de as
gleed waardoor de as niet draaide. Dit slippen werd weer
veroorzaakt doordat de pot-meter teveel wrijvingsweerstand
genereerde. Verder sleten de pot-meters snel waardoor de
weerstandsmeting niet meer goed ging. Deze muizen worden
tegenwoordig niet meer gemaakt en wie er n heeft moet dat
ding maar in de kast leggen, want het kon wel eens een
museumstuk worden.
De tweede soort muis is de meest gebruikte muis, en werkt
precies hetzelfde als de eerste vorm met het verschil dat de
pot-meters vervangen zijn door twee 'wieltjes' met gaten.
Affijn, omdat de meeste mensen de rest van de werking wel
weten zal ik er verder geen woorden over vuil maken. Het
voordeel van deze muis boven de eerste is dat hij niet slijt
en dat er heel weinig wrijvingsenergie op de asjes komt.
Deze eerste twee vormen hebben echter een gezamelijk nadeel;
als ze vuil worden gaan ze haperen (oftewel wrijving). Dit
nadeel is opgelost met de komst van de volgende generatie
muizen, de optische muis. Deze muis heeft geen bewegende
onderdelen en wrijving heeft dus geen invloed op de
prestaties. Het komt er op neer dat er in de muis een
lichtje brandt samen met een element dat licht opvangt. De
muis wordt bewogen over een mat met horizontale en vertikale
lijnen die licht weerkaatsen. Affijn, als het licht
weerkaatst vangt het andere element het op en zo herkent de
muis dat hij beweegt.
Al deze muizen werken echter wel met het principe dat ze
verplaatsing meten en niet plaats. Ze leveren dus de
afgelegde afstand tussen twee metingen aan de computer af
die deze meting dan in een positie omzet. Dit gebeurd door
de afstand bij de vorige positie op te tellen.
DE MUIS LEESAKTIE
Er is in het verleden nogal wat verwarring geweest over de
vraag hoe een MSX2 de muis leest omdat de VDP van een MSX2
een hardwarematische muisleesroutine bevat, die echter niet
gebruikt wordt. De twee joystickpoorten zitten op alle
MSX'en aan register 14 en 15 van de PSG en de VDP heeft er
geen bal mee te maken.
Om een komplete leesaktie te doen is nogal wat nodig omdat
de muis maar de beschikking heeft over een 4 bits databus.
Om dus 2 keer een 8 bits offset te lezen (X en Y) moet er
dus 4 keer gelezen worden waarbij de muis eerst verteld moet
worden dat er gelezen gaat worden. Aan de hand van de
routine (GTMOUS) zal ik nu het algoritme verklaren.
We nemen even aan dat de muis in poort 1 zit. In dat geval
staat in (PORT) de waarde 10111111B en in (PORT+1) de waarde
00010000B
GTMOUS:
- Lees PSG register 15
- Wis bit 6, dit geeft aan dat de muis in poort 1 zit
(Zet bit 6 om aan te geven dat de muis in poort 2 zit)
- Zet bit 4, zodat de muis weet dat nu XH klaargezet moet
worden. Bit 5 doet hetzelfde voor poort 2
Opm: XH/YH = Bit 4-7 van X/Y offset
XL/YL = Bit 0-3 van X/Y offset
- Wacht even op muis (het is een relatief traag ding)
- Lees XH (Verdere details volgen)
- Lees XL
- Lees YH
- Lees YL
Dit lezen is niet eenvoudig omdat de muis niet automatisch
weet wanneer n van de waarden gelezen is. Om aan de muis
te vertellen dat je de waarde gelezen hebt, moet bit 4
(indien de muis in poort 2 zit bit 5) van PSG register 15
genverteerd worden. Als tijdens de volgende leesaktie
register 15 weer geschreven wordt zal de muis dit
genverteerde bit zien waarop het beestje de volgende te
lezen waarde op zijn 4 bits databus zet. Na een kleine
wachttijd wordt deze waarde dan uit register 14 gelezen.
EEN MUISBESTURINGSPROGRAMMA
Laat ik beginnen met het bedanken van Stefan Boer die het
basisprogramma voor de muisbesturing heeft gemaakt waar ik
op voortgeborduurd heb.
De routine is vrij universeel en werkt gegarandeerd op alle
MSX'en (vanaf MSX2). Als uitvoer zal een sprite op het
scherm getekend worden die de beweging van de muis volgt.
Wat meteen opvalt is dat het programma nogal groot is
geworden, maar dat komt omdat er maar heel weinig BIOS calls
gebruikt worden. De muisroutine van de MSX2 en turbo R staat
nl. in een subslot en dat maakt de routine relatief traag.
Voor de meeste routines is dit niet zo'n bezwaar, maar als
een routine vaak aangeroepen wordt is het toch wel handig
dat alles zo vlot mogelijk verloopt.
Verder bevat het programma een schat aan andere nuttige
informatie. Wat dacht je bv. van de vuurknop uitleesroutine
die feitelijk een kopie is van de routine die in de
interruptafhandelingsroutine van FD9FH staat. Deze routine
kijkt naar alle vuurknoppen (0 t/m 5) en doet dit 5 keer zo
snel als de BIOS routine omdat je die in dit geval 5 keer
aan zou moeten roepen. In principe is deze routine overbodig
omdat er in het systeem RAM ook een byte is waar de huidige
vuurknop status in staat, maar ik heb hem er toch bij gezet
omdat er onder MSX programmeurs de trend bestaat om het hele
systeem plat te leggen zodat er geen processortijd verloren
gaat aan -voor hen- overbodige dingen en in dat geval wordt
dit byte niet meer gezet.
Verder bevat het programma een routine die voor SCREEN 5,
page 0 twee sprites initialiseert en alle andere sprites weg
definieert. Je merkt het al, dit programma bevat meer dan
alleen maar een simpele muisbesturing.
HOE WERKT HET
Als het programma opgestart wordt zullen eerst de benodigde
sprites genitialiseerd worden. Daarna zal naar een muis
gezocht worden (CHKPRT) die in de variabele (PORT & PORT+1)
aangeeft of en in welke poort de muis zich bevindt. Is geen
muis aangesloten dan zal de waarde 0 in (PORT) staan. Nu
wordt nog een interruptroutine genstalleerd die bij elke
interrupt de sprites zal herplaatsen.
Verder zal de routine ook altijd met de cursorkeys werken
(logisch nietwaar??). Het uiteindelijke resultaat is dus
een hele snelle routine die zelf wel uitzoekt of en waar een
muis is aangesloten en die zowel met muis als met de
cursorkeys tegelijkertijd een 'arrow' over het scherm kan
bewegen in een van tevoren opgegeven venster.
Een ander leuk detail is dat de muisroutine op zich ook op
MSX1 werkt, maar dat dan wel de muisplaats en initialiseer
routines herschreven moeten worden.
Voor meer informatie over het hoe en wat van sprites moet ik
jullie naar n van mijn eerdere artikelen verwijzen die op
de GENIC ClubGuide Special #2 staat.
Het programma staat los op deze disk (hoop ik) en heet
MOUSE.ASC Als u niet zo'n ster bent in het bedienen van een
assembler kunt u ook gewoon het programma MOUSE.BIN
opstarten.
Ik hoop dat ik wat duidelijkheid heb gebracht in de wereld
van MSX muizen en natuurlijk wil ik in de toekomst een
stormvloed van programma's zien die de muis gebruiken, dat
spreekt voor zich (ik bedoel dus dat ik hoop dat dit muisje
nog een staartje krijgt).
Alex van der Wal
; Een UITERST snelle muisbesturing.
; Gepubliceerd op de Sunrise Magazine Special #1
; Geschreven: 25 april 1992 door Alex van der Wal
; Copyright: Copyright ?? (<= variatie op Smith & Jones grap)
;
VDPBF1: EQU &HF3DF ; MSX1 RAM VDP registerbuffer-0 (0 t/m 7)
VDPBF2: EQU &HFFDF ; MSX2 RAM VDP registerbuffer-8 (8 t/m 23)
PSGWRT: EQU &H93
PSGRD: EQU &H96
GTSTCK: EQU &HD5
GTTRIG: EQU &HD8
SPRPOS: EQU &H7600 ; Start spritepositie tabel
PAGE: EQU 0 ; Eerste 64kB van VRAM
MSESPD: EQU 15 ; >, dan tragere beweging van cursor
CURSPD: EQU 15 ; idem, maar nu zonder muis aangesloten
WACHT1: EQU 7 ; Wachtvariabele (Copyright Steve Soft)
WACHT2: EQU 40 ; Idem
MIN_X: EQU 10 ; 4 keer raden !
MAX_X: EQU 255-10
MIN_Y: EQU 10
MAX_Y: EQU 211-10
ORG &HB000
RUN: LD A,5
CALL &H5F ; SCREEN 5
CALL INICUR
MAIN: CALL MOVCUR
JR Z,MAIN ; Geen knop ingedrukt
PUSH BC
CALL STPCUR
XOR A
CALL &H5F
POP AF ; In A staat nu de ingedrukte knop
RET
INICUR: DI
LD A,15 ; Init sprites op page 0, screen 5
OUT (&H99),A
LD (VDPBF1+6),A
LD A,128+6
OUT (&H99),A ; Zet startadres van patroontabel
LD A,239
OUT (&H99),A
LD (VDPBF1+5),A ; referentieadres waaruit het startadres
LD A,128+5 ; van zowel de positietabel als de
OUT (&H99),A ; kleurtabel gehaald kan worden.
LD A,0
OUT (&H99),A
LD (VDPBF2+11),A
LD A,128+11
OUT (&H99),A ; idem (Reg 5 en Reg 11 vormen samen 1 adres)
LD HL,&H7800 ; Patroontabel startadres
LD C,0
CALL NSTWRT
EI
LD HL,SPRDAT
LD BC,&H4098
OTIR ; Stuur spritedata uit
LD HL,&H7600 ; Positietabel startadres
LD C,0
DI
CALL NSTWRT
EI
LD B,32 ; 4 bytes per sprite en 32 sprites
INC_L1: LD A,216
OUT (&H98),A ; Y
XOR A
OUT (&H98),A ; X
XOR A
OUT (&H98),A ; Spritenummer
XOR A
OUT (&H98),A ; Gereserveerd
DJNZ INC_L1
LD HL,&H7400 ; Kleurtabel
LD C,0
DI
CALL NSTWRT
EI
LD A,1
LD B,16
INC_L2: OUT (&H98),A ; Kleur sprite 0 is 1 (zwart)
DJNZ INC_L2
LD A,15 ; Kleur sprite 1 is 15 (wit)
LD B,16
INC_L3: OUT (&H98),A
DJNZ INC_L3
LD BC,&H98 ; Wis rest buffer, om rotzooi sprites te
LD DE,30*16 ; voorkomen
INC_L4: OUT (C),B
DEC DE
LD A,D
OR E
JR NZ,INC_L4
LD A,(VDPBF1+1)
RES 0,A ; Magnitude is klein
SET 1,A ; Grootte is 16x16
DI
OUT (&H99),A
LD (VDPBF1+1),A
LD A,128+1
OUT (&H99),A ; Sprite Size = 16*16, magnify = off
LD A,(VDPBF2+8)
RES 1,A
OUT (&H99),A
LD (VDPBF2+8),A
LD A,128+8
OUT (&H99),A ; Zet sprites aan
EI
LD A,120 ; Start X en Y waarden
LD (X_COOR),A
LD A,96
LD (Y_COOR),A
CALL CHKPRT ; Zoek en installeer muis
CALL INIMOV ; Zet int. hooks
LD A,CURSPD
LD (CUR_V1),A
LD (CUR_V2),A
LD A,(PORT)
AND A
RET Z
LD A,MSESPD
LD (CUR_V1),A
LD (CUR_V2),A
RET
INIMOV: DI
LD HL,&HFD9F
LD DE,OLDHOK
LD BC,5
LDIR
LD A,&HC3 ; Interrupt voor cursor naar scherm rout.
LD (&HFD9F),A
LD HL,PUTSPR
LD (&HFDA0),HL
EI
RET
STPCUR: DI
LD HL,OLDHOK ; Herstel oude int. hook
LD DE,&HFD9F
LD BC,5
LDIR
LD A,(VDPBF2+8)
SET 1,A
OUT (&H99),A
LD (VDPBF2+8),A
LD A,128+8
OUT (&H99),A ; Zet de sprites uit
EI
RET
CHKPRT: LD A,&B10111111
LD (PORT),A
LD A,&B00010000
LD (PORT+1),A
CALL CHP_P1
RET NZ ; Muis in poort 1 aanwezig
EI
HALT
HALT
LD A,&B11111111
LD (PORT),A
LD A,&B00100000
LD (PORT+1),A
CALL CHP_P1
RET NZ ; Muis in poort 2 aanwezig
XOR A
LD (PORT),A ; Geen muis aangesloten
RET
CHP_P1: CALL GTMOUS ; Test of cursor langzaam naar de
EI ; rechteronderhoek beweegt. Is dit zo
HALT ; dan is er geen muis in de te testen
HALT ; poort aangesloten.
CALL GTMOUS
LD A,H
CP 255
RET NZ
LD A,L
CP 255
RET
MOVCUR: CALL MOUSE ; Lees muis (indien aanwezig)
CALL CURSOR ; Lees cursor
CALL FIRE ; Lees vuurknoppen
RET ; Z_flag hoog, dan geen knop ingedrukt
MOUSE: LD A,(PORT)
AND A
RET Z ; Geen muis aangesloten
LD A,(MSE_V2)
AND A
RET Z
XOR A
LD (MSE_V2),A ; Er is een interrupt geweest
CALL GTMOUS
LD C,L
LD A,H ; X_offset
NEG ; Naar rechts, dan X_offset is negatief
LD HL,X_COOR ; met NEG wordt deze pos. gemaakt
CALL XBORDR
LD (HL),A ; X_coordinaat
INC HL
LD A,C ; Y_offset
NEG
CALL YBORDR
LD (HL),A ; Y_coordinaat
RET
GTMOUS: LD A,15
CALL PSGRD ; Lees PSG reg. 15
LD IX,PORT
AND (IX+0) ; Geef opdracht tot muis leesaktie
OR (IX+1)
LD E,A
LD B,WACHT2
CALL GTOFS2 ; Lees bit 7-4 van X-offset
RLCA
RLCA
RLCA
RLCA
LD C,A
CALL GTOFST ; Lees bit 3-0 van X-offset
OR C
LD H,A ; Sla komplete offset in H op
CALL GTOFST ; Lees bit 7-4 van Y-offset
RLCA
RLCA
RLCA
RLCA
LD C,A
CALL GTOFST ; Lees bit 3-0 van Y-offset
OR C
LD L,A ; Sla komplete offset in L op
RET
GTOFST: LD B,WACHT1
GTOFS2: LD A,15
CALL PSGWRT ; Schrijf E naar PSG reg. 15
LD A,(IX+1)
XOR E ; Geef door dat volgend nibble verstuurd
LD E,A ; moet worden.
WACHT: DJNZ WACHT ; Wacht tot informatie aanwezig is
LD A,14
CALL PSGRD ; Lees PSG reg. 14
AND &H0F ; Alleen bits 3-0 zijn geldig
RET
XBORDR: BIT 7,A ; Zorg dat cursor binnen gedefinieerde
JR Z,XBO_S1 ; border blijft voor de X beweging
NEG
LD B,A
LD A,(HL)
SUB B
JR C,XBO_S2
CP MIN_X
RET NC
XBO_S2: LD A,MIN_X
RET
XBO_S1: ADD A,(HL)
JR C,XBO_S3
CP MAX_X
RET C
XBO_S3: LD A,MAX_X
RET
YBORDR: BIT 7,A ; Idem als XBORDR, maar nu voor de
JP Z,YBO_S1 ; Y beweging
NEG
LD B,A
LD A,(HL)
SUB B
JR C,YBO_S2
CP MIN_Y
RET NC
YBO_S2: LD A,MIN_Y
RET
YBO_S1: ADD A,(HL)
CP MAX_Y
RET C
LD A,MAX_Y
RET
; Cursor besturing
;
CURSOR: CALL CURDLY ; Cursor vertraging
RET NZ
XOR A
CALL GTSTCK ; A=STICK(0)
EI
RLCA
LD E,A
LD D,0
LD HL,CURBUF ; Cursor bewegingsbuffer
ADD HL,DE
LD A,(HL) ; Y beweging
LD B,A
PUSH BC
INC HL
LD A,(HL) ; X beweging
LD HL,X_COOR
CALL XBORDR
LD (HL),A ; X coordinaat
INC HL
POP AF
CALL YBORDR
LD (HL),A ; Y coordinaat
RET
CURDLY: LD A,(CUR_V1) ; Vertraag de cursor
DEC A ; Omdat hij anders VEEL te snel zou
LD (CUR_V1),A ; gaan.
RET NZ
LD A,(CUR_V2)
LD (CUR_V1),A
RET
FIRE: XOR A
CALL FIR_P1
AND &H30 ; Poort 1 op bit 4+5
PUSH AF
LD A,1
CALL FIR_P1
AND &H30
RRCA
RRCA ; Poort 2 op bit 3+4
POP BC
OR B
PUSH AF
CALL FIR_P2
AND 1
RRCA
RRCA ; Spatie op bit 6
POP BC
OR B
RRCA
RRCA
CPL
LD B,1
BIT 4,A
RET NZ
INC B
BIT 2,A
RET NZ
INC B
BIT 0,A
RET NZ
INC B
BIT 3,A
RET NZ
INC B
BIT 1,A
RET
FIR_P1: LD B,A
LD A,15
DI
CALL PSGRD
DJNZ FIR_S1
AND &HDF
OR &H4C
JR FIR_S2
FIR_S1: AND &HAF
OR 3
FIR_S2: OUT (&HA1),A
LD A,14
CALL PSGRD
EI
RET
FIR_P2: DI
IN A,(&HAA)
AND &HF0
ADD A,8
OUT (&HAA),A
IN A,(&HA9)
EI
RET
PUTSPR: LD A,2 ; Indien de VDP al met een aktie bezig
CALL QRSTAT ; is wordt er niets met de VDP gedaan
RRCA
JR C,OLDHOK
DI
LD HL,SPRPOS
LD C,PAGE
CALL NSTWRT
LD A,(Y_COOR)
LD B,A
OUT (&H98),A ; Y
LD A,(X_COOR)
LD C,A
OUT (&H98),A ; X
XOR A
OUT (&H98),A ; Sprite nummer
XOR A
OUT (&H98),A
LD A,B
OUT (&H98),A ; Y
LD A,C
OUT (&H98),A ; X
LD A,4
OUT (&H98),A ; Sprite nummer
LD (MSE_V2),A ; Zorg voor timing muisroutine
OLDHOK: DS 5 ; Hier komt de oude hook te staan
QRSTAT: DI ; Lees een VDP statusregister
OUT (&H99),A
LD A,128+15 ; Zet het te lezen statusregister
OUT (&H99),A ; VDP register 15
NOP
NOP ; Vertraging die VDP nodig heeft
IN A,(&H99) ; Lees statusregister
EX AF,AF
XOR A
OUT (&H99),A
LD A,128+15 ; zet register 15 weer op 0 (Dit MOET !!)
OUT (&H99),A
EX AF,AF
EI
RET
NSTWRT: LD A,H ; Zet het 'direct VRAM write adress'
AND &H3F ; Het adres staat in C & HL
OR &H40 ; C bevat alleen bit 16 van het adres
EX AF,AF ; en HL bevat bits 0 t/m 15
LD A,H
AND &HC0
OR C
RLCA
RLCA
OUT (&H99),A
LD A,128+14
OUT (&H99),A
LD A,L
OUT (&H99),A
EX AF,AF
OUT (&H99),A
RET
;
; ** Data
;
X_COOR: DB 128 ; X coor. van cursor/muis
Y_COOR: DB 106 ; Raad eens !
PORT: DB 0 ; Poort waar muis in zit
DB 0
CUR_V1: DB 0 ; Vertragingsvariabele
CUR_V2: DB 0 ; idem.
MSE_V2: DB 0 ; interrupt vlag
CURBUF: DB 0,0,255,0,255,1,0,1,1,1,1,0,1,255,0,255,255,255
; Patroondata van de twee sprites
SPRDAT: DB &HC0,&HA0,&H90,&H88,&H84,&H82,&H81,&H87
DB &H84,&HA2,&HE2,&H91,&H11,&H08,&H08,&H07
DB &H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00
DB &H00,&H00,&H00,&H00,&H00,&H80,&H80,&H00
DB &H00,&H40,&H60,&H70,&H78,&H7C,&H7E,&H78
DB &H78,&H5C,&H1C,&H0E,&H0E,&H07,&H07,&H00
DB &H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00
DB &H00,&H00,&H00,&H00,&H00,&H00,&H00,&H00
END
|