Assembly experiment: bouncing block

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

By Grauw

Ascended (10016)

Grauw's picture

11-05-2021, 15:38

thegeps wrote:

To modify your values in RAM you can address them easily in this way:

     Ld hl,RAMSAT  ;point to sprite0 byte (y coord)
     Ld (hl),whatever value you need

     Ld hl,RAMSAT+1 ; sprite0 x coord
     Ld hl,RAMSAT+4 ; sprite1 y coord

And if your RAMSAT is 256 aligned you can do this faster:

Ramsat:     equ 0c000h

     Ld hl,ramsat ;set this address as start point (sprite0 y coord)
     Ld (hl),your value
     Ld l,1  ;sprite0 x coord
     Ld (hl),your value
     Ld l,4  ;sprite1 y coord
     Ld (hl),your value
     Ld l,5  ;sprite1 x coord
     Ld (hl),your value

Or using ix / iy with offset instead of hl, which is convenient and no need to align (e.g. ld (ix + 4),20). A tad slower but it’s not so important, the big gain comes from combining the individual VRAM writes.

By santiontanon

Paragon (1453)

santiontanon's picture

11-05-2021, 15:43

In this particular example, it's an extreme case, as you have 4 sprites locked in the same x, y, and hence it would require 4 memory writes to update x or y. But what I was saying in general is the same idea as what @thegeps is explaining.

What I would do in your particular case would be like this: for your first two writes, if "x" is the byte after "y+1" in your memory layout, you can just do this (assuming this is running in vblank, otherwise, it'll be too fast for the VDP):

    ld hl,y+1
    outi
    outi

Also, if you just want to "skip" a byte in VRAM. If I don't remember wrong, you can just "read" and that will also auto-increment the VDP address pointer. Someone would have to verify this, but I think that if you want to write the x, y of 4 sprites in your case, you can just do:

    ld e,4
label:
    ld hl,y+1
    outi
    outi
    in a,(c)
    in a,(c)
    dec e
    jr nz, label

I am not 100% sure that the "in a,(c)" would work though haha. But it's worth a try Wink

Also, again! All of these things will make the code very fast, and the VDP has some restrictions about how fast can you transfer data to it (in MSX1). These restrictions are lifted during vblank, when you can send data as fast as you want. If you are not sending data during vblank, then you might need to insert "nops" in between the instructions to slow the CPU down.

By Grauw

Ascended (10016)

Grauw's picture

11-05-2021, 15:49

santiontanon wrote:

I am not 100% sure that the "in a,(c)" would work though haha. But it's worth a try Wink

Yes it does but it’s too fast. VRAM access on the MSX1 VDP must be 29 cycles apart, maybe more if you use this in trick to skip bytes. I wouldn’t use that, I would use thegeps’ approach where you output the entire table separately, and which includes sufficient wait (outi + jp combo in Sprite_to_vram = 29 cycles).

By ToriHino

Paladin (721)

ToriHino's picture

11-05-2021, 16:05

I tend to use the solution of thegeps as well, always just to a complete update of all the attributes (at least for the number of sprites you use)in one go.
And if you don't really really need the highest performance, you can just do a LDIRVM BIOS call. The overall overhead is really not that big and it even works on those exceptional machines that don't have the VDP at port 98.
I often also put it as a first in my interrupt routine, after that start updating things again for the next refresh cycle.

By Grauw

Ascended (10016)

Grauw's picture

11-05-2021, 16:59

Yeah actually I would recommend LDIRVM as well!

By Pbk71

Expert (101)

Pbk71's picture

11-05-2021, 17:02

Hi all,

Thanks for all the advice! I've tried to implement all of the tips it and it still works Wink My code has got a lot smaller now and this rewriting of my code really teaches me a lot, I'm very happy with that! I wonder if it can even optimized more by now Smile

I made a RAMbuffer for the sprite attributes where I change the coordinates with IX . Also removed the LDIRVM calls. I use OUTI not only to update the coordinates of the sprites, but also to write the sprite patterns to VRAM at the start of the program. Is this risky as this is not done just after a VBLANK? Seems to work...

See the latest version here: https://msxpen.com/codes/-M_QvFKS12zddrvsWsAU

By Grauw

Ascended (10016)

Grauw's picture

11-05-2021, 17:06

As long as you ensure that all I/O to port 98H (VRAM access) is 29 cycles apart, including their own cycle cost, it does not matter when you do them. During blanking, this time restriction is reduced.

By Pbk71

Expert (101)

Pbk71's picture

11-05-2021, 17:17

Ok, so I can change this...

spriteattr_to_vram:
		      outi				; write byte to VRAM
              jp nz,spriteattr_to_vram

to this...

		      otir				; write bytes to VRAM

...because it is just after a VBLANK?
Or use 16 times OUTI as you describe on this page?

By thegeps

Paladin (854)

thegeps's picture

11-05-2021, 17:48

LoL that page is a great page. I learned a lot from the site owner Wink

(yes, during vblank you can use otir and unrolled otir)

By thegeps

Paladin (854)

thegeps's picture

11-05-2021, 17:52

ToriHino wrote:

... if you don't really really need the highest performance, you can just do a LDIRVM BIOS call. The overall overhead is really not that big and it even works on those exceptional machines that don't have the VDP at port 98...

that can be easily fixed by:

     ld a,(6)
     ld c,a

in this way c will have the right vdp data port number (obviously if you didn.t get rid of bios)

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