Page 1 of 1

Problem with DMA_doVramFill

Posted: Tue Apr 21, 2020 1:33 pm
by tryphon
I have a problem with DMA_doVRamFill. My plane A starts at VRAM adress 0xC000 with :

Code: Select all

0xC000 : 2108 2108 2108 2108 2108 2108 2108 2108 2108 2108
(2108 means : tile 0x108 with palette 1, no priority, no flips) (If I'm not mistaken, VRAM is little-endian so it should be 08 21 inside).

I want to change those 2108 to 2142, so I do :

Code: Select all

DMA_doVRamFill(0xC000, 10, 0x42, 2);
But I get :

Code: Select all

0xC000 : 4242 2142 2142 2142 2142 2142 2142 2142 2142 2142


I know there's some problem with DMA operations that can miss the first operation. But I thought SGDK did take care of that. I'm using version 1.4 (maybe 1.34, not sure). Is it related ?

Also, do we agree that, if I want to change the 21 to 00, I'll have to do :

Code: Select all

DMA_doVRamFill(0xC001, 10, 0x42, 2);
?

Re: Problem with DMA_doVramFill

Posted: Tue Apr 21, 2020 7:39 pm
by Stef
In fact SGDK just take care about adjusting len but not the way data are written (and it should probably indeed) so currently you have to take care of that yourself. And unfortunately it's not really straightforward to handle that..

Re: Problem with DMA_doVramFill

Posted: Tue Apr 21, 2020 11:02 pm
by tryphon
OK, I think I understood the problem.

I looked in source code of DMA_doVRamFill. In fact, the "value" parameter needs to be u8.

Then, when sending the value to data port, you write :

Code: Select all

    *pw = value | (value << 8);
because the 1st word write sends the lower byte to adress, the upper byte to adjacent adress, then the upper byte to subsequent adresses.

But, unless I'm mistaken, it's impossible to fill, say, 4 adjacent cells with, for example, 0x1234 :

DMA_doVRamFill(0xC000, 4, 0x12, 2) will do :

Code: Select all

0xC000 : 1212 12.. 12.. 12..
then DMA_doVRamFill(0xC001, 4, 0x34, 2) will do :

Code: Select all

0xC000 : 3434 1234 1234 1234
The first cell will always be wrong and I'll have to fix it by hand.

So I modified the DMA_doVRamFill function by making value a u16, and sending value to *pw.
Now I can write :

Code: Select all

my_DMA_doVRamFill(0xC000, 4, 0x1234, 2);
my_DMA_doVRamFill(0xC000, 4, 0x3412, 2); // swap is needed
to fill my 4 cells.

Is it the right way to do it or am I missing something ?

Re: Problem with DMA_doVramFill

Posted: Wed Apr 22, 2020 7:41 am
by Stef
tryphon wrote:
Tue Apr 21, 2020 11:02 pm
OK, I think I understood the problem.

I looked in source code of DMA_doVRamFill. In fact, the "value" parameter needs to be u8.

Then, when sending the value to data port, you write :

Code: Select all

    *pw = value | (value << 8);
...
So I modified the DMA_doVRamFill function by making value a u16, and sending value to *pw.
Now I can write :

Code: Select all

my_DMA_doVRamFill(0xC000, 4, 0x1234, 2);
my_DMA_doVRamFill(0xC000, 4, 0x3412, 2); // swap is needed
to fill my 4 cells.

Is it the right way to do it or am I missing something ?
To fill word you indeed need to use step = 2 and do 2 DMA fill operations.
Why i'm using

Code: Select all

value | (value << 8)
is because you need to write a word and depending the destination address it will take the lower or upper byte.
Indeed what we do usually is just a final word write to fix the first wrong write done by DMA fill operation.

So in your case why not just writing a word filling method to make it even more clear:

Code: Select all

DMA_doVRamWordFill(0xC000, 4, 0x3412);
Which internally does 2 DMA fill operations and take care of fixing the first word ?

Re: Problem with DMA_doVramFill

Posted: Wed Apr 22, 2020 8:38 am
by tryphon
Because I sometimes do not need to write the upper byte :)

But I wrote a macro doing both write ;)

(I'm never sure when a function is inlined, so I guess macros are faster)

Re: Problem with DMA_doVramFill

Posted: Wed Apr 22, 2020 9:00 am
by Stef
If you use not too old SGDK with recent GCC (6.3) you can be confident about inlining. The LTO optimization does wonder, it even sometime push it a bit too much (making code size a bit large) but so you can safely use fonction for almost everything (as you can see i don't care too much with them in SGDK, sometime i can have up to 4 or 5 depth levels function).