VDP 8 bit VRAM ADDRESSING emulation issue

Page 1/2
| 2

By PingPong

Prophet (3233)

PingPong's picture

09-05-2019, 19:44

the code below can be used to test if the trick used in SMS games to avoid the second out on vdp (see: http://www.smspower.org/Development/VDPProgrammingTechniques) work also on msx / 1 / 2 / 2+ / TR .
ASM is below, and basic code is following the ASM. Basically it pass to the USR a integer where the low byte is a 8 bit addr and high is the value to poke. The USR then perform a VPOKE LO(ARG),HI(ARG)>>8
THE BASIC CODE CALLS 255 times the routine. Result:

A stripe of 0x41 bytes written on the second 16K VRAM Bank of VDP at addresses beginning From 1. Please note: 1 not 0! as specified. That is because the ASM code does not out the second byte so the VDP cannot know that it is a write access and does a prefetch skipping 1 byte forward.

That's is the behavior on openMSX. And it is perfecly fine and logical.
However, if this behavior is correct, why the tecnique shown on smspower works? the example should not write at given offset instead at given offset+1.

So my question is:
1) Does the SMSPower example not correct and working only for vram read? (this is my guess also)
2) If the SMSPower work on SMS should it work even on MSX?
3) If on real MSX does work in write is there a emulation bug on openMSX?

Can anyone that have the physical hw available give some light ?

LD E,5
LD A,(0xF663)
CP 2
JP NZ,0x406F
LD HL,(0xF7F8)
LD A,L
DI
OUT (0x99),A
LD A,H
NOP
NOP
NOP
OUT (0x98),A
EI
RET
5 SCREEN 5: VPOKE 0,VPEEK(0): VDP(15)=1
10 DEFINT A-Z
20 GOSUB 20000
30 FORT=0TO255
40 DUMMY=USR(&H4100ORT)
50 NEXT 
60 T$=INPUT$(1)
10000 END
20000 CODE$="1E 05 3A 63 F6 FE 02 C2 6F 40 2A F8 F7 7D F3 D3 99 7C 00 00 00 D3 98 FB C9 $$"
20010 AD=&HC000: CNT=0: T=1
20020 V$=MID$(CODE$,T,2)
20030 IF V$="$$" THEN 20060
20040 POKEAD+CNT,VAL("&H"+V$):CNT=CNT+1: T=T+3
20050 GOTO 20020
20060 DEFUSR=AD
20070 RETURN

Login or register to post comments

By Grauw

Enlighted (7967)

Grauw's picture

09-05-2019, 20:20

On TMS9918, writing a byte immediately sets the LSB of the VRAM address pointer. This also means that setting a register value corrupts the VRAM address pointer as well. The LSB of the internal VRAM address pointer is used directly for setting register values. On the V9938 the LSB is stored in a separate latch (shared with the palette (9AH)), so this trick doesn’t work.

This is emulated on openMSX, so be sure to test on an MSX1 machine.

As you can also see there, to make sure another OUT (99H) will not be interpreted as an MSB byte, you must follow it with OUT (98H), IN (98H) or IN (99H). These reset 99H to the LSB.

By PingPong

Prophet (3233)

PingPong's picture

09-05-2019, 21:34

Emh, the question was a little different:
a) you said it work on msx1 tms. but i've tryed on msx2 openmsx machine and it does work (check the basic program)
b) it works as i expect: i set vram ptr to an address and then i out to data port, the first byte is stored at address + 1, instead of address. To me this sound fine. Because you do not output the second byte you were not able to set the 'inibit prefetch' bit (that is on second byte). so you output your byte at address+1 because vdp thinks it's a read operation.
But if it is the correct behavior the docs on smspowers are incorrect because if i'm not mistaken they say that you can do a vram memory write at address x by only outputting the lowbyte of address x. Instead they should say "you can write at address x by outputting the lowbyte of x-1 to 0x99". Or i'm wrong?

I always thought that the vdp does the read prefetch byte only when you have outputted the second byte. It does not appear to be...

By ricbit

Champion (432)

ricbit's picture

09-05-2019, 21:48

Grauw wrote:

On the V9938 the LSB is stored in a separate latch (shared with the palette (9AH)), so this trick doesn’t work.

What about V9958? The same as V9938? I would have lots of gain in my tmnt demo if this works on V9958.

By PingPong

Prophet (3233)

PingPong's picture

09-05-2019, 21:52

ricbit wrote:
Grauw wrote:

On the V9938 the LSB is stored in a separate latch (shared with the palette (9AH)), so this trick doesn’t work.

What about V9958? The same as V9938? I would have lots of gain in my tmnt demo if this works on V9958.

Read my first post. Try the basic program on v9958. on openMSX - v9938 work as expected i think the same on v9958

By Grauw

Enlighted (7967)

Grauw's picture

09-05-2019, 22:00

PingPong wrote:

a) you said it work on msx1 tms. but i've tryed on msx2 openmsx machine and it does work (check the basic program)

That can not be true; the block I highlighted is what openMSX executes for the LSB written to 99H, and it only modifies the VRAM pointer when it emulates the TMS9918.

PingPong wrote:

b) it works as i expect: i set vram ptr to an address and then i out to data port, the first byte is stored at address + 1, instead of address.

Hum I missed that part in your first post. I’m surprised by this result, if you omit the MSB I would expect that the direction does not to change, and without MSB it does not have a complete address to prefetch from. And if I look at the openMSX source code, the pre-fetch indeed only happens when the MSB is written, the LSB write does nothing except set the LSB of the address on TMS9918.

So if you were saying this happened on a real MSX there could be some unknown hardware behaviour, but I can’t explain your results from the source code of the very emulator you’re running it on. Are you sure your test program is correct?

ricbit wrote:

What about V9958? The same as V9938? I would have lots of gain in my tmnt demo if this works on V9958.

I’ve never seen anything where the V9958 behaved differently from the V9938. Except for the V9958’s additions, and its 5-bit DAC slightly affecting palette colour values, they are identical. OpenMSX source code also makes no mention of any differences.

By PingPong

Prophet (3233)

PingPong's picture

09-05-2019, 22:13

Quote:

That can not be true; the block I highlighted is what openMSX executes for the LSB written to 99H, and it only modifies the VRAM pointer when it emulates the TMS9918.

I saw your source code. but i see a different result that one can expect by only seeing the sources. Can you try with openMSX the basic program? the machine code routine is listed. I do not see any error but maybe i'm wrong.
the basic program load the assembly code and then execute it in a loop passing the low byte different (0-255) at each iteration. the first byte i wrote should be at address 0 if sms power is correctly interpreted by me but it was at address 1 instead. plus a openmsx NMS8245 work as you described for an msx 1 machine..... my openmsx binary is windowze 0.15.x

By PingPong

Prophet (3233)

PingPong's picture

09-05-2019, 22:21

Quote:

So if you were saying this happened on a real MSX there could be some unknown hardware behaviour, but I can’t explain your results from the source code of the very emulator you’re running it on. Are you sure your test program is correct?

wait. maybe i've found the trick. it is an unfortunate coincidence, due to the first VPEEK/VPOKE i've inserted at top to set vram ptr in the initial way.
Let me verify i will tell you very soon

By Grauw

Enlighted (7967)

Grauw's picture

09-05-2019, 22:51

Here is my test program. Execute in DOS in screen 0.

	org 100H

Main:
	ld hl,helloWorld
	ld a,0
	out (99h),a
	ld a,64
	out (99h),a
	ld c,98h
	ld b,12
	ld a,b
Loop:
	dec a
	out (99h),a
	outi
	jr nz,Loop
	ret

helloWorld:
	db "!dlroW olleH"

In openMSX TMS9918 (Yamaha CX5M), this prints “Hello World!” at location (0, 0).
In openMSX V9938 (Philips NMS 8245), this prints “!dlroW olleH” at location (0, 0).
In openMSX V9958 (Panasonic FS-A1GT), this prints “!dlroW olleH” at location (0, 0).

On a real TMS9929A (Sony HB-75P), this prints “Hello World!” at location (0, 0).
On a real V9938 (Yamaha CX5MII), this prints “!dlroW olleH” at location (0, 0).
On a real V9958 (Panasonic FS-A1GT), this prints “!dlroW olleH” at location (0, 0).

So I think that answers all questions Smile.

Executable binary here

By PingPong

Prophet (3233)

PingPong's picture

09-05-2019, 22:31

Me stupid. Is was an unfortunate coincidence.
look at line 5: there is some setup. the problem is the VPOKE/VPEEK instruction. this set the vram ptr to 0
next i effectively run a series of out(0x99),a followed by out(0x98).
as you said, on V9938 the first out does not do anything so the final result is like outputting to 0x98 data. but because vramptr is set now to 1 (due to the vpoke above) the first byte is outputted to address 1.
This appeared me to a prefetch inibit question just because i write from address 0 to 255 in the loop that call the usr machine code instruction. this fooled me making me think that vdp does a prefetch. It really does NOTHING but by coincidence because it is already pointing to address 1 because of the previous VPOKE it does appear as a prefetch

so on msx2 the effect is the same as doing a simple out(0x98) operation.
Never tested on msx1

I am really sorry.

By Grauw

Enlighted (7967)

Grauw's picture

09-05-2019, 22:42

Now if Piter Punk would test on the YM2220… Big smile

Page 1/2
| 2
My MSX profile