Copy to VRAM (VDP) programming question

Page 1/3
| 2 | 3

By treblig

Resident (60)

treblig's picture

21-06-2022, 13:38

I have a beginners question regarding VDP programming for MSX1. When I try to copy a 8x8 pattern to VRAM, not all data arrives on certain MSX1 machines. I'm really puzzled by this.

  • Line `$0005` is skipped on e.g. Philips VG8020, Canon V-20, CBIOS MSX1 (EU). If I change the order of color/pattern copying, a byte in the color pattern is missing.
  • In this tiny example, the problem does not occur on CBIOS MSX1 (JP), CBIOS MSX2 (EU) or Sony HB-700P
  • If I add di before copying data and ei after copying data, the problem does not occur.

Should interrupts be disabled when copying to VRAM? I thought that was only needed when writing to the registers.

Result from the openMSX debugger on a Philips VG8020 / CBIOS MSX1 (EU), line `$0005` with value `$05` is missing.

info for character 0 ($00)
Generator Data         Color data
$0000: 1.1.1.1. $AA      $2000: $12
$0001: .1.....1 $41      $2001: $13
$0002: 1.1..... $A0      $2002: $14
$0003: ...1...1 $11      $2003: $15
$0004: 1...1... $88      $2004: $17
$0005: 1.....1. $82      $2005: $16
$0006: .1.1.1.1 $55      $2006: $18
$0007: ........ $00      $2007: $19

Result from openMSX debugger on CBIOS MSX2, as expected, full pattern and colour pattern in VRAM.

info for character 0 ($00)
Generator Data         Color data
$0000: 1.1.1.1. $AA      $2000: $12
$0001: .1.....1 $41      $2001: $13
$0002: 1.1..... $A0      $2002: $14
$0003: ...1...1 $11      $2003: $15
$0004: 1...1... $88      $2004: $17
$0005: .....1.1 $05      $2005: $16
$0006: 1.....1. $82      $2006: $18
$0007: .1.1.1.1 $55      $2007: $19

The test program (compiles with Glass):

    ; ROM header
    org $4000
    db "AB"
    dw Main
    dw 0, 0, 0, 0, 0, 0

VDPData     equ $98
VDPControl  equ $99
CHGMOD      equ $005f
RomSize     equ $4000
TilePos     equ 0 * 8  ; Tile (x,y)=(0,0)

Main:
    ; Change to screen 2
    ld a, 2
    call CHGMOD
	 
    ; Pattern start address
    ld hl, $0000 + TilePos
    call SetVDPWriteAddress
    ; Pattern data
    ld hl, Pattern0
    ld b, 8
    ld c, VDPData
    otir

    ; Color start address
    ld hl, $2000 + TilePos
    call SetVDPWriteAddress
    ; Color data
    ld hl, Color0
    ld b, 8
    ld c, VDPData
    otir

    di
    halt

SetVDPWriteAddress:
    ld a, l
    out (VDPControl), a
    ld a, h
    or %01000000
    out (VDPControl), a
    ret
	
Pattern0:
    db %10101010
    db %01000001
    db %10100000
    db %00010001
    db %10001000
    db %00000101
    db %10000010
    db %01010101

Color0:
    db $12
    db $13
    db $14
    db $15
    db $17
    db $16
    db $18
    db $19

ProgEnd:
    ds $4000 + RomSize - ProgEnd, 255
Login or register to post comments

By santiontanon

Paragon (1873)

santiontanon's picture

21-06-2022, 13:48

Hi trblig, "otir" writes too fast to the VDP, and MSX1 machines have a limitation that (unless you are in vblank), you need to wait 29 t-states between VDP writes (while otir will do one write each 16 t-states). So, you have two choices:
1) wait for "vblank"
2) use a slower loop (e.g. "my_loop: outi; jp nz,my_loop"

You can read about this in the "access timing" section in Grauw's aVDP article here: http://map.grauw.nl/articles/vdp_tut.php

By treblig

Resident (60)

treblig's picture

21-06-2022, 14:24

Aha, that explains why it works well on MSX2, but not on MSX1. Thank you @santiontanon.

I changed the code and it works perfectly now.

By aoineko

Paragon (1209)

aoineko's picture

21-06-2022, 14:55

Just a detail: otir is 23 t-states during copy (18 for the last check).
It doesn't change anything for your use case.
The only case where it changes something, is for the text modes on MSX2 (where access time is 20 T-States max).

So, the 3 ways to write to VRAM:

 outi	; 18 T-States

 otir	; 23/18 T-States

 OutiToVram:  ; 29 T-States (18 + 11)
     outi
     jp nz, OutiToVram

To compare with each screen mode on MSX1 and 2 max access time (a same screen mode don't have the same acces time on both VDP).

By gdx

Enlighted (6644)

gdx's picture

21-06-2022, 15:43

I confirm to make sure your program works on all MSX1s, do not write to VRAM with OTIR, nor with OUTIs one after the other without putting at least two NOPs between them even during vblank.

By aoineko

Paragon (1209)

aoineko's picture

21-06-2022, 17:07

Even during V-Blank?
I have read several times that during the V-Blank the VRAM accesses were faster than a outi and that there were no more restrictions on the CPU side.
Is this not the case?

By bore

Master (189)

bore's picture

21-06-2022, 18:07

While I haven't done any specific tests on this I'm pretty sure that the 29 cycle limit comes from the 8us restriction in the TMS9918 datasheet. (8us * 3.58MHz = 28.64)
This means that the limit is for Graphics I and Graphics II.
In text or multicolor mode the restriction would be 12 or 13 T-states.
During vblank or if the display is disabled in register 1 the limit is 8 T-states.

8 T-states is more or less equivalent to no restriction.
I would think that you wouldn't have to care about the restriction in text mode either and just avoid doing back to back OUT (n),A in multicolor.

By ToriHino

Paladin (959)

ToriHino's picture

21-06-2022, 19:22

In general I just use the BIOS function LDIRVM. For most situations this is more than fast enough unless you really need the very last clock cycle. For me it works better to first get it functional and working before starting to micro-optimize these kind of things.

By treblig

Resident (60)

treblig's picture

21-06-2022, 23:22

Thank you @ToriHino. I've made a version using your recommended BIOS function. That works too now. The help in this forum is amazing. If someone is interested, I can post both working versions here for future reference.

By PingPong

Enlighted (4177)

PingPong's picture

22-06-2022, 00:46

santiontanon wrote:

Hi trblig, "otir" writes too fast to the VDP, and MSX1 machines have a limitation that (unless you are in vblank), you need to wait 29 t-states between VDP writes (while otir will do one write each 16 t-states). So, you have two choices:
1) wait for "vblank"
2) use a slower loop (e.g. "my_loop: outi; jp nz,my_loop"

You can read about this in the "access timing" section in Grauw's aVDP article here: http://map.grauw.nl/articles/vdp_tut.php

otir takes 21 t-states. on msx 23

By gdx

Enlighted (6644)

gdx's picture

22-06-2022, 01:48

Aoineko wrote:

Even during V-Blank?

Yes, I don't know in which cases it doesn't work but it does happen.

Page 1/3
| 2 | 3