128kB VRAM gebruiken in ML Genic Clubguide, 00-00-00 Nvdr. De nu volgende tekst is ook te vinden op de BBS-Waterland en is geschreven door Ramon van der Winkel die GENIC toestemming heeft gegeven voor deze publicatie. Aan de publicatie van dit artikel hebben meegewerkt: Ramon van der Winkel (De schrijver van het artikel) Rudy Oppers (De man van de modem) Alex van der Wal (Initiatiefnemer & editor) G E B R U I K 1 2 8 K B V R A M I N M L ================================================= In deze tekstfile wordt uiteengezet hoe het volledige 128 Kilobytes van het video RAM van de MSX te gebruiken is. Het VRAM is, net zoals bij een memory mapper, onderverdeeld in pagina's van 16 kilobytes. In totaal zijn er dus 8 pagina's die met maar 1 pagina tegelijk aan te schakelen zijn. Om een pagina en een adres daarbinnen te kiezen, moeten we een aantal waardes achter elkaar op de commando poort van de VDP zetten, waarna we via de datapoort het VRAM kunnen uitlezen of schrijven. De commando poort is standaard poort 099h en de datapoort is standaard 098h. Deze twee poorten zijn ook via adres 0006 en 0007 van de mainrom te vinden (voor de commando poort er een bij optellen), maar het zijn nu al weet ik hoeveel jaar lang dezelfde poorten geweest, dus rechtstreeks gebruik zonder controle kan geen kwaad. We kunnen de data-transfer altijd maar een kant tegelijk op doen. Het is dus niet mogelijk om 10 bytes te lezen en daarna, zonder opnieuw te adresseren, 21 bytes te schrijven en dan meteen er maar weer 5 te lezen. We geven met bit 10 van het adres op of we willen schrijven. Raar bit, die bit 10, maar dat is heeleenvoudig te verklaren: Omdat er pagina's zijn van 16 kilobytes (16384 bytes, 4000h) kunnen we nooit meer als 16 Kilobytes in een keer verplaatsen. Dus als we willen schrijven, dan OR-en we 40h bij het MSB van het adres en versturen we dit naar de vdp, anders kunnen we lezen. Stel, we willen vanaf pagina 5, adres 2BF5 lezen, dan versturen we de volgende reeks codes door de vdp commando poort (99h): 05h, 8Eh, 0F5h, 2Bh. Willen we schrijven, dan wordt de reeks: 05h, 8Eh, 0F5h, 6Bh. 6Bh is dus 2Bh or 40h. De 8E die je in allebij de reeksen ziet staan, is voor de vdp een aanduiding dat we register #14 (0Eh) willen schrijven (or 80h). Dit is een standaard methode voor de vdp. Wat we dan doen, is eerst de data op door de vdp commando poort sturen en daarna het register nummer OR 80h. In dit geval moeten we na de pagina in de data-byte (eerste code) ook nog eens het adres erachteraan sturen (derde en vierde code). Het is mogelijk om van de ene pagina door te schrijven naar de volgende. Na iedere byte die gelezen of geschreven is, wordt het adres automatisch verhoogd. Na adres 3FFFh in bijvoorbeeld pagina 2, komt meteen adres 0000h in pagina 3. Wat er na pagina 7, adres 3FFFh gebeurd weet ik niet, dat heb ik nog nooit geprobeerd. Tijd voor een universele routine, waarbij we in A het pagina nummer opgeven en in HL het adres, waarbij bit 10 al gezet moet zijn als we willen schrijven: VRMADR: DI DI OUT (099H),A of: LD C,099H LD A,08Eh OUT (C),A OUT (099H),A LD A,08EH LD A,L OUT (C),A OUT (099H),A OUT (C),L LD A,H OUT (C),H OUT (099H),A Nu willen we data gaan transporteren. Dat doen we via de VDP datapoort. Nadat we het adres geschreven hebben, staat de datapoort klaar om tekens te ontvangen of versturen (ligt aan bit 10 van het adres). Door poort 098h te lezen, krijgen we de data binnen, door hem te schrijven gaat het naar het VRAM. Nu hebben we echter nog een probleem: Timing. Ik heb net daarboven twee routines naast elkaar gezet. Waarschijnlijk zal de linker wel werken en de rechter niet zondermeer. Waarom niet zou je zeggen? Als data op de bus van de vdp zetten, dan heeft die tijd nodig om deze er vanaf te halen. Sturen we de data nu zo snel dat de geen tijd genoeg heeft om hem er vanaf te halen, dan werkt het simpelweg niet. Dit geld overigens alleen voor de commando poort, bij de datapoort kunnen we net zo snel data versturen als we willen. Een NOP tussen alle outs in de rechter routine zou genoeg moeten zijn, anders twee keer een EX (SP),HL of twee stack operaties ofzo. Het is mij opgevallen dat als je wilt lezen van het VRAM, je twee EX (SP),HL 's of een PUSH en een POP achter de adressering van de linker routine moet zetten (daar blijf ik voorlopig maar bij). In het voorbeeld staat een PUSH en een POP. Nu dan twee routines die een deel van het VRAM naar het RAM kunnen verplaatsen en de andere kant op. In register B moet het aantal bytes staan, wat in blokken van 256 bytes verstuurd gaat worden. Een kleine modificatie in deze routine en je kan iedere hoeveelheid bytes vanplaatsen. Voor de verplaatsing van en naar het VRAM heb ik even twee routines gemaakt, zodat bit 10 van het adres niet meer gezet hoeft te worden en omdat er bij de het lezen met IN's en bij het schrijven met OUT's moet worden gewerkt: ; ; TOVRAM - Verplaats B blokken van 256 bytes vanaf pagina A ; en adres HL naar het VRAM, vanaf RAM, adres DE ; TOVRAM: DI ;Voorkom ander vram gebruik OUT (099H),A ;Pagina LD A,08EH ;VDP #14 <- Pagina OUT (099H),A LD A,L ;Adres LSB OUT (099H),A LD A,H ;Adres MSB AND 03FH ;Maximaal 16K en wis bit 10 OR 40H ;Zet bit 10 voor schrijven OUT (099H),A PUSH DE ;Adres naar HL voor OTIR POP HL LD E,B ;Aantal blokken LD C,098H ;VDP datapoort voor OTIR TOVLUS: LD B,0 ;Aantal bytes voor OTIR OTIR ;Verplaats de data DEC E ;Nog meer blokken? JR NZ,TOVLUS ;Ja! RET ; ; FRMVRM - Verplaats B blokken van 256 bytes vanuit het ram ; vanaf adres DE naar het vram, pagina A adres HL ; FRMVRM: DI ;Voorkom ander vram gebruik OUT (099H),A ;Pagina LD A,08EH ;VDP#14 <- Pagina OUT (099H),A LD A,L ;Adres LSB OUT (099H),A LD A,H ;Adres MSB AND 03FH ;Maximaal 16K, wis bit 10 OUT (099H),A PUSH DE ;Adres naar HL voor INIR POP HL ; maar ook meteen delay LD E,B ;Aantal blokken LD C,098H ;VDP datapoort voor INIR FRVLUS LD B,0 ;256 bytes per verplaatsing INIR ;Lees uit het vram DEC E ;Nog meer blokken? JR NZ,TOVLUS ;Ja RET Ik hoop dat deze gegevens een beetje te gebruiken zijn. Het adresseren van de videochip en het verplaatsen van een naar het VRAM kan natuurlijk ook met de MAINROM, maar dan moet je de routines daar een beetje gaan misleiden om bij de 2e 64 kB te kunnen komen. Dit kan door op adres 0FAF6h de waarde 0 voor de 1e 64K en de waarde 1 voor de 2e 64K neer te zetten en daarna NSETRD en NSETWR aan te roepen. Dit komt ongeveer overeen met set pagina ,0 en set page ,1 op screen 8. Het adres bevat in ieder geval de 'active page'. Op adres 0FAF5h staat de 'diplay page', maar dat is verder niet zinnig om te weten. Kijk voor het gebruik van meer dan 16 kilobytes vram wel even hoeveel VRAM er aanwezig is. Dit kan door op pagina 3 en 7 op adres 0000h bijvoorbeeld de waarde 3 in pagina 3 en daarna de waarde 7 in pagina 7 te schrijven. Als er daarna in pagina 3 een 7 staat, dan is er dus maar 64 Kilobytes aanwezig. Ook kan je naar adres 0FAFCh kijken. De MSX2 SUBROM heeft daar al neergezet hoeveel VRAM die gevonden heeft. Ik geloof dat bit 4 daar gezet is als er 128 kB aanwezig is en bit 2 als er 64 kB aanwezig is. Het is natuurlijk gewoon uit te proberen: Voor screen 0 tot en met 4 is maar 16 Kilobyte nodig, voor screen 5 en 6 maar 64 kilobyte en voor de rest minimaal 128. Door bijvoorbeeld 2 op 0FAFCh te poken en dan SCREEN 8 in te typen, dan zal dat waarschijnlijk niet werken. Het is ook handig voor een RAMdisk programma bijvoorbeeld, om de originele waarde van dit adres op te slaan en er 0 ofzo neer te zetten als de RAMdisk het VRAM benut. Dan kan ten eerste er geen data meer verminkt worden door een screen commando en ten tweede kunnen andere 'nette' programma's aan adres 0FAFCh zien dat het VRAM al in gebruik is. Veel plezier ermee, Ramon van der Winkel (Nvdr. deze technieken worden toegepast bij de SCREEN 5/12 superimpose routine. U kunt daar dus meteen een toepassing bekijken.) |