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.
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
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.
I am not 100% sure that the "in a,(c)" would work though haha. But it's worth a try
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).
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.
Yeah actually I would recommend LDIRVM as well!
Hi all,
Thanks for all the advice! I've tried to implement all of the tips it and it still works 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
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
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.
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?
LoL that page is a great page. I learned a lot from the site owner
(yes, during vblank you can use otir and unrolled otir)
... 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)