Screen 4 - vram usage

Page 1/11
| 2 | 3 | 4 | 5 | 6

By Frederik Dumarey

Supporter (10)

Frederik Dumarey's picture

16-11-2022, 23:17

Hello,

Since a lot of games on MSX-2 are made in graphic 3 (screen 4) for the mixed tiles/sprites setup, the maximum vram size you use is 16KB (patterns, colors, names, sprites).

Questions:
- there is no page concept < screen 5, so I suppose the 0x04000 till 0x1FFFF range is unusable for graphics stuff?
- the hereabove mentioned range can be used to store other tiles or even variables I suppose using RAM to VRAM and/or VRAM to RAM high speed VDP commands?

Thanks,
Fred.

By Grauw

Ascended (10768)

Grauw's picture

16-11-2022, 23:46

Frederik Dumarey wrote:

- there is no page concept < screen 5, so I suppose the 0x04000 till 0x1FFFF range is unusable for graphics stuff?

There is, you can separately specify name / pattern / color table addresses in the full 128K range, which works exactly the same as the bitmap mode pages do.

Frederik Dumarey wrote:

- the hereabove mentioned range can be used to store other tiles or even variables I suppose using RAM to VRAM and/or VRAM to RAM high speed VDP commands?

One space wasting but cool application is to use 8 pages of patterns for pattern animations, so you can have 8-step animation sequences across a large group of tiles which only take a few VDP register writes updating the pattern and colour table to animate.

Combine it with name table updates as well and you could also have longer animation sequences at still relatively little CPU cost, since you only need to write the name table once every 8 frames.

Without taking advantage of the copious amounts of VRAM like this, you would have to either rewrite patterns + pattern colours every frame where CPU bandwidth is limiting, or pre-define the animation steps as separate patterns which reduces the pattern count available.

By Frederik Dumarey

Supporter (10)

Frederik Dumarey's picture

16-11-2022, 23:51

Thanks Grauw for the answer!

Yes indeed, already made a MSXBAS2ROM example for animating patterns and colors, but only in the 0x3FFF range Smile
Will try something in the future using Fusion-C, and above the 0x3FFF range Wink

By PingPong

Enlighted (4137)

PingPong's picture

17-11-2022, 14:37

Hi, the page concept used on screen 5 and upper screen modes in mainly a msxbasic abstraction. From the point of view of VDP it does mean only different values on vdp registers used to set the base address of vdp tables. So you can have pages even on screen 4 mode, by writing proper values on vdp registers.

For high speed commands it does depend. they (without trickery) do not work on v9938 and screen 4. they work (if enabled) on v9958 in any screen mode like in screen 8 mode.

By aoineko

Paladin (1002)

aoineko's picture

17-11-2022, 18:29

On the V9938, the notion of page is not abstract, it is a hardware specification used for automatic page switching or interlaced display.

By PingPong

Enlighted (4137)

PingPong's picture

17-11-2022, 18:54

aoineko wrote:

On the V9938, the notion of page is not abstract, it is a hardware specification used for automatic page switching or interlaced display.

It is not. instead the same concepts should have been applied even on screen 4. The vdp does not have a page register to be setup, it has only address registers. when you use setpage what is happening is that registers are updated according to the setpage you used. If you are referring to some special feature like page interlacing or swapping is is only a bit that is used in conjunction with the address registers to get the correct display address.

By the way the set page also define the "working page", the page where commands work, and again a MSX BASIC thing. Effectively what is happening is telling the BIOS commands to work at different addresses (by changing the Y coordinate), if the Vdp had a page concept the command register should have a a way to specify the page . instead it only have a x,y value or address register. No registers holding the page.

By aoineko

Paladin (1002)

aoineko's picture

17-11-2022, 19:55

Play with words if you want. The fact remains that this notion is absolutely not limited to Basic and is clearly explained in the technical documentation of the V9938: https://map.grauw.nl/resources/video/yamaha_v9938.pdf.

By PingPong

Enlighted (4137)

PingPong's picture

18-11-2022, 21:32

aoineko wrote:

Play with words if you want. The fact remains that this notion is absolutely not limited to Basic and is clearly explained in the technical documentation of the V9938: https://map.grauw.nl/resources/video/yamaha_v9938.pdf.

There is no need to play with words.
For the VDP the vram is laid out as a big screen of 256 (or 512) x (512/1024) pixels.
If you were right the vdp register they would have contained the page indication in the command or address registers.

By Frederik Dumarey

Supporter (10)

Frederik Dumarey's picture

19-11-2022, 17:43

Tried some functions with Fusion-C:

// Prepare vdp mode
  Screen(4);
  SetColors(15,4,4);
  Cls();

  // Don't use this in Graphic screen 3!
  // it changes R#2 bit 5 for pages concept, but R#2 is used for defining the base address of the name table!
  //SetDisplayPage(0);
  //SetActivePage(0);

  //Put a box on the screen
  FillVram(0x0000,0xFF,8); // pattern 0 = black box 8x8
  FillVram(0x2000,0xFF,8); // color table = white on white
  FillVram(0x1800,0,10); // name table = 10 times pattern 0
  WaitKey();

  // Test HMMM
  // tried to convert 0x1800 / 256 (pixel based) and copy pixels to memory, but does not work!
  //HMMM(0,0,0,10,8,8);
  //HMMM(0,24,0,25,1,1);

  Screen(0);
  Exit(0);

You can find c source here: https://github.com/FDumarey/MSX/blob/master/sc4pages.c
and .com compiled file here: https://github.com/FDumarey/MSX/blob/master/sc4pages.com

My first conclusions (also see comments in C file):
- Set page VDP register#2 use does not work in Graphic Screen 3 (since it is used for the pattern base address)
- HMMM VDP command is not going to do the right stuff since bitmap based VDP command

I hope Grauw can help me out:
- I can vpeek and vpoke to copy stuff in >16KB region, but since the Vpoke address parameter is limited to a 16-bit integer, I'm limited to 0xFFFF (64KB).
- How can I vpoke or maybe vram to vram (using the v9938 VDP commands) in the region 0x10000 to 0x1FFFF ?

By PingPong

Enlighted (4137)

PingPong's picture

19-11-2022, 19:00

1) HMMM (and every other vdp command) does not work on pattern modes.
2)you can vpoke the entire 17 bit area (128K), but you need to understand how things works because of compatibility with tms vdp.
The TMS vdp could only manage 16K of ram so you needed only 14 bits of address to manage. when you do a vpoke or vpeek operation you need to do this in two steps:
a) setup the vram ptr
b) output/input a byte

details of what is done in pratice with only 16K of addressing (the TMS old way):
a) set vram ptr.
output a byte to a port number #1, you need to write the low byte of address you need to vpoke or vpeek. in 'c'
output the remaining 6 bit of address to the same port bitwise oring this value if you need to perform a write operation, leaving unchanged for a read operation

int address = .....
outp (_PORT1_, (BYTE)address & 255);
outp (_PORT1_, (BYTE)(address & 63) | 64); // | because i need to write a value

now the (b) step, write or read the data byte
byte valuetopoke = .....
outp(_PORT2_, valuetopoke);

this is what happens on a TMS vdp.
However , because the V9938 had 17 bits (three bits more ) for the addressing, those extra bits are stored in an extra register (i do not remember the number, you can find this on V9938 documentations). Just because this register is like any other register you write this in the same way as other register, with the extra 3 bits to allow a 17 bit addressing.

the sequence to update a vdp register is as follow:

outp(_PORT1_, value of register you need to write);
outp(_PORT1_, 128 | number of register you need to write).

That said, the complete 17 bit addressing would be done in two steps:

a) set the extra bits registers with the bank of 16 K you need to write to:
int bank = 2; // write to third bank of 16 K value that is from address 32768 decimal.

outp(_PORT1_, bank);
outp(_PORT1_, | 128); // tell the vdp you need to write the register number ... , the 128 is bit wise or-ed to signal the vdp YOU WANT to WRITE an internal register not TO SET the VRAM PTR (!)

b) Set the usual 14 bits of a 16 VRAM address:

int writeflag = 1; // leave 0 for a read operation 1 means you want to write.

outp(_PORT1_, address & 255);
outp(_PORT1_, ((address >> 8) & 63) | writeflag);

Now you are ready to output the byte value.
outp (_PORT2_, bytevalue);

As you see, the vram access operation is kinda slow and complex, i remember there is a BIOS call that, given HL containing the 16 bit address and A containing the 17 bit could setup the VRAM Ptr as you need.

Just remember two things:
a) after you setup the vram ptr, next write operations or read operations automatically increment it, so if you are reading or writing consecutive block of bytes no need to execute another set vram ptr operation. Basically if you setup the VRAM ptr to 0x0002 and you output a byte this value is stored at 0x0002 and next bytes you output will go to 0x0003, 0x0004 etc. the same apply on read consecutive bytes.

b) there is a wrap around feature on the vram ptr: when the address ptr goes after the 16K address highest value, this wraps to 0 in all screen modes < GRAPHIC3. On GRAPHIC3 and higher modes the wrap arount occours (obviously) after you reached 0x1FFFF (the end of 128K)

Last thing: _PORT1_ is 0x99 _PORT2_ is 0x98 on almost all msx systems

By PingPong

Enlighted (4137)

PingPong's picture

19-11-2022, 19:18

if you are using Fusion_C from my outdated source i've found this:

void VpeekFirst( unsigned int address ) {

    if( Peek( SCRMOD ) >= 7 ) {
        VDPwriteNi( 14, (address >> 14) | (Peek( ACPAGE ) << 2) );
    }
    else {
        VDPwriteNi( 14, (address >> 14) | (Peek( ACPAGE ) << 1) );
    }
    OutPort( 0x99, (unsigned char)address );
    OutPort( 0x99, (unsigned char)(address >> 8) & 0x3F );
}

and

void VpokeFirst( unsigned int address ) {

    if( Peek( 0xFCAF ) >= 7 ) {
        VDPwriteNi( 14, (address >> 14) | (Peek( ACPAGE ) << 2) );
    }
    else {
        VDPwriteNi( 14, (address >> 14) | (Peek( ACPAGE ) << 1) );
    }
    OutPort( 0x99, (unsigned char)address );
    OutPort( 0x99, ((unsigned char)(address >> 8) & 0x7F) | 0x40 );
}

they do basically the same i've told you before, the extra 17-16-15th bit is stored in a z80 RAM location called ACPAGE, setting the vram ptr.
then a simple out on port2 (0x98) write or read the byte.
Notice the 0x40 value needed to tell to the vdp "I want to write a byte not read one"

a variant (not tested) that could suit your need maybe could be this:
(slow like a hell)

// address, full 16 bit address of vram ptr to set, bit17 = 0 first 64K, bit17 = 1 second 64K 

void VpokeFirst( unsigned int address, unsigned char bit17 ) {

	VDPwriteNi( 14, (address >> 8) || (bit17 << 3) );
    OutPort( 0x99, (unsigned char)address );
    OutPort( 0x99, ((unsigned char)(address >> 8) & 0x7F) | 0x40 );
}
Page 1/11
| 2 | 3 | 4 | 5 | 6