Routines Hans Kester, 00-00-00 ; Deze subroutines zijn bedoeld om vele MSX-ers een duwtje in de rug te ; geven en het maken van machinetaal-programma's makkelijker te maken. Voor de ; duidelijkheid: deze routines zijn Public Domain; ze mogen door iedereen ; gebruikt en gekopi‰erd worden. Ze mogen zelfs voor commerci‰le programma's ; aangewend worden. Heeft u vragen of opmerkingen, dan kunt u mij altijd ; schrijven of mailen in Jos-Tel (05149-1837) of Risoft (01804-15958). ; Ik wens iedereen veel plezier hiermee! ; ; Hans Kester ; Van Limburg Stirumstraat 18 ; 4102 HA Culemborg ; ; Belangrijk: - voor een goede werking van de routines moet in vele gevallen ; de routine INIT eerst aangeroepen worden. ; - de systeem-adressen en BIOS-calls dienen ook in de source-code ; te staan, anders zal uw assembler foutmeldingen geven van ; niet-aanwezige adressen. ; Systeemadressen TXTNAM EQU 0F3B3h ; Bevat beginadres naamtabel TXTCOL EQU 0F3B5h ; Bevat beginadres kleurtabel CSRY EQU 0F3DCh ; CurSoR Y-position CSRX EQU 0F3DDh ; CurSoR X-position PUTPNT EQU 0F3F8h GETPNT EQU 0F3FAh FNKSTR EQU 0F87Fh ; Funktietoets-definitie ; MSX-1 BIOS-routines RDSLT EQU 000Ch ; ReaD SLoT CALSLT EQU 001Ch ; CALl SloT WRTVDP EQU 0047h ; WRiTe to VDP CHGET EQU 009Fh ; CHaracter GETter CHPUT EQU 00A2h ; CHaracter PUTter XBEEP EQU 00C0h ; BEEP (X i.v.m. BEEP-macro) ; Macro's ten behoeve van de programmeur (alleen voor GEN80 en M80) ; Definieer LOCATE als in BASIC. ; Bijvoorbeeld: LOCATE 10,10 LOCATE MACRO @XPOS,@YPOS PUSH HL LD HL,(@XPOS+1)*256+(@YPOS+1) LD (CSRY),HL POP HL ENDM ; Definieer het commando BEEP BEEP MACRO LD IX,XBEEP CALL BIOS1 ENDM ; Trek een horizontale lijn ; Voorbeeld: HORLIJN 0,0,80 ; Dit levert vanaf positie (0,0) een 80 karakters lange lijn HORLIJN MACRO @XPOS,@YPOS,@LENGTE ; horizontale lijn trekken LD B,@XPOS ; bijvoorbeeld: LD C,@YPOS ; HORLIJN 12,13,20 LD A,@LENGTE CALL LIJN_HOR ENDM ; Trek een verticale lijn ; Voorbeeld: VERTLIJN 12,10,13 ; Dit levert vanaf positie (12,10) een 13 karakters lange lijn naar onder VERTLIJN MACRO @XPOS,@YPOS,@LENGTE ; verticale lijn trekken LD B,@XPOS ; bijvoorbeeld: LD C,@YPOS ; VERTLIJN 12,3,15 LD A,@LENGTE CALL LIJN_VERT ENDM ; Deze routine leest de poort-adressen uit ROM en zet ze op de adressen VDP_DR ; en VDP_DW. Zonder aanroep van deze routine werken vele andere routines niet! ; Hoeft slechts 1 keer aangeroepen te worden, liefst aan begin v/h programma. INIT LD IX,RDSLT ; lees adres HL in een slot LD HL,0006h ; adres is 0006h LD A,(0FCC1h) ; en het slot is slot 0 CALL BIOS1 ; lees dat adres LD (VDP_DR),A ; zet VDP-leespoort neer INC HL ; nu adres 0007h LD A,(#FCC1) ; lees ook die CALL BIOS1 LD (VDP_DW),A ; en zet schrijfpoort neer RET ; keer terug ; Deze routine roept de MSX1-BIOS aan op het adres dat in IX staat ; en keert weer terug naar het aanroepadres BIOS1 PUSH IY ; Bewaar inhoud IY LD IY,(#FCC0) ; Laad met EXPTBL CALL CALSLT ; Roep routine in IX aan EI ; Interrupts weer aan POP IY ; Haal IY terug RET ; En terug naar waar we waren ; Deze routine doet hetzelfde als BIOS1 , maar dan met de MSX2-BIOS i.p.v. ; de MSX1-BIOS (SUB-ROM) BIOS2 PUSH IY LD IY,(#FAF7) ; EXBRSA i.p.v. EXPTBL CALL CALSLT EI POP IY RET ; Deze routine vult vanaf adres HL het geheugen BC maal met A BLOKFILL PUSH DE ; bewaar DE DEC BC ; verlaag BC ivm eerste byte LD D,H ; DE gelijk aan HL LD E,L INC DE ; DE wijst op byte achter HL LD (HL),A ; vul adres HL met A LDIR ; en alle volgende adressen ook POP DE ; haal DE terug RET ; Deze routine haalt een J of een N van het toetsenbord ; Uitvoer: J -> A=1 of N -> A=0 GET_ZEKWET CALL GETCHAR ; vraag om toets OR A ; was er wel een toetsdruk? JR Z,GET_ZEKWET ; nee, nog een keer dan CALL UPPER ; maak er een hoofdletter van CP "J" ; was het ja? JR Z,ZEKWET_J ; goed zo CP "N" ; of misschien nee? JR Z,ZEKWET_N ; dat is ook goed JR GET_ZEKWET ; verkeerde toets ingedrukt ZEKWET_J LD A,1 ; ja is 1 RET ZEKWET_N XOR A ; nee is 0 RET ; Deze routine maakt van de letter in A een hoofdletter (indien mogelijk). UPPER CP "z"+1 ; groter dan "z"? RET NC ; ja, kan dus niet RET Z CP "a" ; kleiner dan "a"? RET C ; mag ook niet XOR 32 ; draai bitje om RET ; en keer terug ; Deze routine maakt van de letter in A een kleine letter (indien mogelijk). LOWER CP "Z"+1 ; groter dan "Z"? RET NC ; dan gaat het niet door RET Z CP "A" ; kleiner dan "A"? RET C ; gaat ook niet XOR 32 ; draai bitje om RET ; en terug ; Deze routine wacht tot er geen functietoets meer is ingedrukt WAITFUNC CALL GETFUNC ; haal functie-toets OR A ; was er nog ‚‚n? JR NZ,WAITFUNC ; ja, nogmaals RET ; nee, terug ; Deze routine kijkt of er een functietoets is ingedrukt ; Na aanroep bevat A het nummer van de functietoets (1...10) ; of 0 als er niets ingedrukt was GETFUNC LD HL,(#FBEB) ; Haal stukje NEWKEY matrix XOR A ; Teller op 0 BIT 0,L ; SHIFT ? CALL Z,SHIFT_FUNC ; Ja, zet teller op 5 BIT 5,L ; F1 ? JR Z,FUNC1 BIT 6,L ; F2 ? JR Z,FUNC2 BIT 7,L ; F3 ? JR Z,FUNC3 BIT 0,H ; F4 ? JR Z,FUNC4 BIT 1,H ; F5 ? JR Z,FUNC5 JR FUNC_END SHIFT_FUNC ADD A,5 ; Vijf bijtellen RET FUNC1 ADD A,1 ; Functienummer bijtellen JR FUNC_END FUNC2 ADD A,2 JR FUNC_END FUNC3 ADD A,3 JR FUNC_END FUNC4 ADD A,4 JR FUNC_END FUNC5 ADD A,5 JR FUNC_END FUNC_END CP 5 ; Is A=5 en ook SHIFT ? RET NZ ; want dan is er alleen BIT 0,L ; SHIFT ingedrukt en geen F5 !! RET NZ XOR A ; Jep, A moet 0 zijn... RET ; Deze routine maakt alle functietoets-definities leeg KILLFUNC LD B,159 ; Lengte van het blok (10*16) LD HL,FNKSTR ; Startadres XOR A ; Vullen met nullen (rijmt!) KILL_LOOP LD (HL),A INC HL DJNZ KILL_LOOP RET ; Deze routine kijkt of er een toets is ingedrukt en haalt hem dan ; uit de buffer. ; Na aanroep bevat A het karakter of 0 als er geen karakter was GETCHAR PUSH HL ; bewaar HL en IX PUSH IX LD HL,(GETPNT) ; is GETPNT gelijk aan PUTPNT? LD A,(PUTPNT) SUB L JR Z,NO_CHAR ; ja, dan geen tekens in buffer LD IX,CHGET ; wel teken, haal uit de buffer CALL BIOS1 ; via de BIOS JR CHAR_END ; en verlaat de routine NO_CHAR XOR A ; geen tekens, A=0 CHAR_END POP IX ; herstel IX en HL POP HL RET ; Deze routine trekt een horizontale lijn op positie (B,C) met lengte A ; Zie ook de MACRO!! LIJN_HOR DI ; interrupts uit PUSH HL ; bewaar registers PUSH DE PUSH BC PUSH AF CALL GET_ADRES ; bepaal het adres in VRAM PUSH AF ; bewaar de lengte eventjes CALL SETWRT ; zet VDP klaar voor schrijven POP AF ; lengte weer in A LD BC,(VDP_DW) ; in C de schrijf-poort LD B,A ; lengte nu in B LD A,23 ; teken van streepje in A HOR_LUS2 OUT (C),A ; geef door aan VDP DJNZ HOR_LUS2 ; en dat B maal POP AF ; herstel registers POP BC POP DE POP HL EI ; interrupt weer aan RET ; Deze routine trekt een verticale lijn op positie (B,C) met lengte A ; Zie ook de MACRO!! LIJN_VERT DI ; interrupt uit PUSH HL ; bewaar registers PUSH DE PUSH BC PUSH AF CALL GET_ADRES ; bepaal VRAM-adres PUSH AF ; bewaar de lengte eventjes CALL SETWRT ; VDP op schrijven voorbereiden POP AF ; lengte in A LD BC,(VDP_DW) ; in C de schrijf-poort LD B,A ; lengte in B LD DE,80 ; voor 80 bytes verder in VRAM VERT_LUS2 LD A,22 ; streepjescode in A OUT (C),A ; naar de VDP sturen ADD HL,DE ; 80 bytes verder in VRAM CALL SETWRT ; en dat adres weer schrijven DJNZ VERT_LUS2 ; totdat B nul is POP AF ; herstel de registers POP BC POP DE POP HL EI ; en interrupt weer aan RET ; keer terug ; Deze routine zet een regel tekst op het scherm ; Bij aanroep wijst HL naar het begin van de tekst, afgesloten met een 0 byte PRINT LD A,(HL) ; neem een teken INC HL ; verhoog de wijzer OR A ; is het teken een 0? RET Z ; ja, einde CALL PUTCHAR ; nee, zet teken op het scherm JR PRINT ; en neem volgende teken ; Deze routine zet een letter op het scherm, ASCII-code in A PUTCHAR PUSH IX ; bewaar IX LD IX,CHPUT ; en roep de CHPUT routine aan CALL BIOS1 ; in de BIOS POP IX ; herstel IX RET ; terug ; Snellere printroutine. Zelfde parameters als PRINT. FAST_PRINT DI ; interrupts uit PUSH BC ; bewaar registers PUSH DE PUSH HL LD A,(CSRX) ; x-positie in A DEC A ; met 1 verlagen LD B,A ; x-positie nu in B LD A,(CSRY) ; zelfde met y-positie DEC A LD C,A ; gaat naar C CALL GET_ADRES ; bepaal adres in VRAM CALL SETWRT ; schrijf adres naar de VDP POP HL ; haal tekstwijzer terug LD BC,(VDP_DW) ; VDP-schrijfpoort naar C FP_LUS2 LD A,(HL) ; neem teken INC HL ; verhoog wijzer OR A ; einde tekst? JR Z,FP_END ; ja OUT (C),A ; nee, teken naar VDP JR FP_LUS2 ; tot einde tekst FP_END POP DE ; herstel registers POP BC EI ; interrupt weer aan RET ; en einde routine ; Deze routine maakt een balkje met lengte A op positie (B,C) ; Deze balkjes kunnen knipperen en van een kleur worden voorzien door resp. ; de routines KNIPPER en KNIPKLEUR aan te roepen (zie onder) BALKJE PUSH HL ; bewaar registers PUSH BC PUSH DE PUSH AF PUSH AF ; A nogmaals bewaren LD HL,(TXTCOL) ; adres in VRAM van blakjes LD A,C ; neem de y-co”rdinaat ADD A,A ; vermenigvuldig die met 10 LD C,A ADD A,A ADD A,A ADD A,C LD D,0 ; maak DE gelijk aan A LD E,A ADD HL,DE ; tel dat bij het adres op LD E,B ; neem x-co”rdinaat SRL E ; deel die door 8 SRL E SRL E ADD HL,DE ; tel op bij VRAM-adres ; HL bevat nu het juiste adres in VRAM, nu wordt er een masker gemaakt om ; de bits in VRAM te kunnen zetten. LD A,B ; x-co”rdinaat in B AND 7 ; alleen laagste 3 bits nemen INC A ; en verhogen LD B,A ; bewaren in B XOR A ; A=0 SCF ; zet carry-flag BLUS RRA ; roteer de carry B maal in A DJNZ BLUS ; zodat het masker goed is LD B,A ; masker in B LD A,(VDP_DR) ; VDP-leespoort in C LD C,A LD A,(VDP_DW) ; VDP-schrijfpoort in E LD E,A POP AF ; haal lengte terug LD D,A ; lengte in D zetten XOR A ; A=0 DI ; interrupt uit, niet storen CALL SETRD ; VDP klaar voor lezen BLUS1 IN A,(C) ; lees byte uit VRAM CALL SETWRT ; zet VDP meteen schrijfklaar BLUS2 OR B ; zet het juiste bit op 1 DEC D ; is de juiste lengte bereikt? JR Z,EIND_BLOKJE ; ja, einde van het balkje RR B ; nee, roteer masker JR C,ZET_BLOKJE ; nieuw byte lezen? JR BLUS2 ; nee, volgende bit ; masker is "doorgedraaid", schrijf byte naar VRAM ZET_BLOKJE PUSH BC ; bewaar B en C LD C,E ; schrijfpoort naar C OUT (C),A ; schrijf A naar VRAM POP BC ; herstel B en C INC HL ; verhoog VRAM adres CALL SETRD ; zet VDP op lezen RR B ; roteer masker weer goed JR BLUS1 ; en ga nog even verder EIND_BLOKJE LD C,E ; schrijf laatste byte weg OUT (C),A ; naar VRAM POP AF ; en herstel de gewijzigde POP DE ; registers POP BC POP HL EI ; mag weer storen RET ; Haal het balkje op positie (B,C) met lengte A weer weg BALKJE_WEG PUSH HL ; bewaar registers PUSH BC PUSH DE PUSH AF PUSH AF ; A nogmaals bewaren LD HL,(TXTCOL) ; adres in VRAM van blakjes LD A,C ; neem de y-co”rdinaat ADD A,A ; vermenigvuldig die met 10 LD C,A ADD A,A ADD A,A ADD A,C LD D,0 ; maak DE gelijk aan A LD E,A ADD HL,DE ; tel dat bij het adres op LD E,B ; neem x-co”rdinaat SRL E ; deel die door 8 SRL E SRL E ADD HL,DE ; tel op bij VRAM-adres ; HL bevat nu het juiste adres in VRAM, nu wordt er een masker gemaakt om ; de bits in VRAM te kunnen zetten. LD A,B ; x-co”rdinaat in B AND 7 ; alleen laagste 3 bits nemen INC A ; en verhogen LD B,A ; bewaren in B XOR A ; A=0 SCF ; zet carry-flag BWLUS RRA ; roteer de carry B maal in A DJNZ BWLUS ; zodat het masker goed is CPL ; neem daar het complement van LD B,A ; masker in B LD A,(VDP_DR) ; VDP-leespoort in C LD C,A LD A,(VDP_DW) ; VDP-schrijfpoort in E LD E,A POP AF ; haal lengte terug LD D,A ; lengte in D zetten XOR A ; A=0 DI ; interrupt uit, niet storen CALL SETRD ; VDP klaar voor lezen BWLUS1 IN A,(C) ; lees byte uit VRAM CALL SETWRT ; zet VDP meteen schrijfklaar BWLUS2 AND B ; zet het juiste bit op 0 DEC D ; is de juiste lengte bereikt? JR Z,EIND_WBLOKJE ; ja, einde van het balkje RR B ; nee, roteer masker JR NC,ZET_WBLOKJE ; nieuw byte lezen? JR BWLUS2 ; nee, volgende bit ; masker is "doorgedraaid", schrijf byte naar VRAM ZET_WBLOKJE PUSH BC ; bewaar B en C LD C,E ; schrijfpoort naar C OUT (C),A ; schrijf A naar VRAM POP BC ; herstel B en C INC HL ; verhoog VRAM adres CALL SETRD ; zet VDP op lezen RR B ; roteer masker weer goed JR BWLUS1 ; en ga nog even verder EIND_WBLOKJE LD C,E ; schrijf laatste byte weg OUT (C),A ; naar VRAM POP AF ; en herstel de gewijzigde POP DE ; registers POP BC POP HL EI ; mag weer storen RET ; Deze routine wist alle balkjes op het scherm WEGBALK DI ; niet meer storen PUSH HL ; bewaar registers die PUSH BC ; veranderd gaan worden PUSH AF PUSH DE LD HL,(TXTCOL) ; vanaf 0800H CALL SETWRT ; VDP schrijfklaar LD DE,270 ; 27 regels van 10 bytes LD BC,(VDP_DW) ; in C poortadres WEGBALK2 XOR A ; A=0 OUT (C),A ; schrijf A naar VRAM DEC DE ; verlaag de teller LD A,E ; is de teller al 0? OR D JR NZ,WEGBALK2 ; nee, nog eens EI ; ja, interrupt weer aan POP DE ; herstel registers POP AF POP BC POP HL RET ; en weer terug ; LDIRMV en LDIRVM, maar dan onder MSXDOS ; Kopi‰ren respectievelijk VRAM naar RAM en RAM naar VRAM ; Bij aanroep bevat HL het adres waar de data vandaan komt en DE het adres waar ; de data heen moet gaan. BC geeft de lengte van het blok aan. LDIRMV DI ; niet storen CALL SETRD ; zet VDP op lezen LD H,B ; HL=BC (teller) LD L,C LD BC,(VDP_DR) ; C bevat poort-adres MV_LUS IN A,(C) ; neem teken uit VRAM LD (DE),A ; zet dat in RAM op adres DE INC DE ; verhoog RAM-wijzer DEC HL ; verlaag teller HL LD A,H ; is de teller al nul? OR L JR NZ,MV_LUS ; nee, ga verder EI ; ja, stoor maar weer RET ; einde routine LDIRVM DI ; ook niet storen EX DE,HL ; verwissel adressen CALL SETWRT ; zet VDP op schrijven LD H,B ; HL=BC (teller) LD L,C LD BC,(VDP_DW) ; C bevat poort-adres VM_LUS LD A,(DE) ; neem teken uit RAM OUT (C),A ; en zet dat in VRAM INC DE ; verhoog RAM-wijzer DEC HL ; verlaag de teller LD A,H ; is de teller al nul? OR L JR NZ,VM_LUS ; nee, nogmaals EI ; ja, mag weer storen RET ; en keer terug ; Deze routine zorgt voor het knipperen van de VDP-balkjes ; In high-B staat de tijd die de balkjes te zien zijn en in low-B de tijd ; dat ze weg zijn. Tijd in vijfden van seconden. Maximum is 15. KNIPPER PUSH BC ; bewaar BC PUSH IX ; en IX LD C,13 ; C bevat VDP register-nummer LD IX,WRTVDP ; schrijf via de BIOS de tijd CALL BIOS1 POP IX ; en herstel de registers POP BC RET ; Deze routine zet de knipperkleur in het VDP register ; In high-B staat de voorgrondkleur en in low-B de achtergrondkleur KNIPKLEUR PUSH BC ; bewaar BC en IX PUSH IX LD C,12 ; registernummer voor kleur LD IX,WRTVDP ; schrijf ook via de BIOS CALL BIOS1 POP IX ; herstel registers POP BC RET ; Zet VDP-schrijf adres op adres HL. INTERRUPTS GAAN UIT EN BLIJVEN UIT !!!! SETRD DI ; niet storen!! PUSH HL ; bewaar HL en BC PUSH BC RES 7,H ; vertel dat er gelezen wordt RES 6,H LD BC,(VDP_DW) ; neem schrijfpoort-adres INC C ; en tel daar 1 bij op OUT (C),L ; schrijf resp. lage en hoge OUT (C),H ; deel v/h adres POP BC ; en herstel de boel weer POP HL RET ; keer terug met interrupt uit! ; Stel schrijfadres VDP in op adres HL, INTERRUPTS GAAN UIT EN BLIJVEN UIT!!!! SETWRT DI ; niet storen!! PUSH HL ; bewaar registers PUSH BC SET 6,H ; we gaan schrijven, meneer VDP RES 7,H LD BC,(VDP_DW) ; neem schrijf-poort+1 INC C OUT (C),L ; eerste lage deel, dan hoge OUT (C),H POP BC ; en herstel de boel POP HL RET ; Deze routine bepaalt het adres in de naamtabel (VRAM) van positie (B,C) ; Adres komt in HL GET_ADRES PUSH DE ; bewaar registers PUSH BC PUSH AF LD HL,(TXTNAM) ; begin van de naamtabel (VRAM) LD A,C ; neem y-positie LD C,B ; zet x-positie in BC LD B,0 ADD HL,BC ; en tel die bij HL op OR A ; kijk of y-positie nul is JR Z,ADRES_END ; ja. einde routine LD B,A ; zet y-positie in B LD DE,80 ; en tel bij HL B*80 op ADRES_LUS ADD HL,DE DJNZ ADRES_LUS ADRES_END POP AF ; herstel registers POP BC POP DE RET ; keer terug, HL bevat nu adres ; hier komen de poort-adressn van de VDP VDP_DR DEFB #00 ; VDP-read poortadres VDP_DW DEFB #00 ; VDP-write poortadres |