Page 1 of 2
write to vram - in c problems
Posted: Sun Mar 23, 2014 8:48 pm
by DrDementia
I have question about writing to vram where my nametable is (0x2000). I'm exploring shiru's neslib and programming in c.
I want to update the vram and I tried various methods, here's some code for you guys
Code: Select all
ppu_waitnmi();
ppu_off();
vram_write((unsigned char*)array16,address,16);
ppu_on_all();
If I write 16 bytes to vram I get a graphic glitch. I can write 15 bytes or less without the glitch though with this method.
Not sure if it's a timing or speed issue. maybe I'm trying to do things improperly(bad code).
I really want to change multiple spots in vram then render. what's the right way to do this?
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 5:42 am
by rainwarrior
When you say you get a glitch, do you mean you get a bit of black at the top of the screen and the image is shifted down? What is the glitch?
The vblank period after NMI is a very short time, and it is really difficult to do very much at all in C code during this time. The NMI handler in shiru's library is probably already doing a bunch of things (uploading sprites, etc.) and should have a special way of uploading nametable data during vblank. So, after it's done all that, there's probably not much time left for you to do any manual uploads of your own.
You should only need to turn the PPU off and on manually when you are going to turn rendering off for a long time to do a lot of PPU uploading, like if you're setting up the whole screen at once.
Edit: I think what you need to use is the "set_vram_update" function, which you should do before ppu_waitnmi(), and your update will automatically be applied during the ppu_waitnmi() call.
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 8:59 am
by DrDementia
thanks for the help.
The glitch seems to fill the whole screen with garbage for a frame. here's some more code to show what's happening.
http://pastie.org/8964484
you should be able to compile that. it's a minimal example of what I was trying to do. I'll look at "set_vram_update" maybe that will work. I did notice you could use it during rendering, but it said "number of transferred bytes is limited by vblank time"
the other vram functions "works only when rendering is turned off" according to shiru, which is why I was turning the ppu off/on.
I'm probably trying to do things in a weird way.
edit: added "delay(20);" to the loop so you could see the glitch easier. and attached the compiled .nes for anyone to test.
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 12:01 pm
by rainwarrior
Oh, that's interesting. The glitch frame you are seeing is that occasionally for 1 frame you're using the wrong CHR pattern page for your nametables.
This is controlled by
bit 4 of the register at $2000. Once every several frames your code is writing $80 instead of $90 to this register, which causes it to select the $0000 CHR page for backgrounds instead of the $1000 page you want.
I don't know how this is being triggered, or why it doesn't happen every frame. The code is a LDA #$80, STA $2000, which I can't find in the neslib.s source
found here. Maybe shiru can answer your question.
However, the code you have written is still a problem. You should only turn the PPU off when you need to take rendering down for multiple frames so you can place a lot of data into the PPU. For an update that happens every frame,
do not turn the PPU off, just push the data through with set_vram_update. You should be able to push at least 32 bytes per frame through there, if not more (I don't use shiru's neslib, so I can't tell you its performance limits).
Edit: oh, didn't see your comment about delay(), I was going by your pastebin source. That explains why it's not every frame at least. I expect the offending write to $2000 is in ppu_on_all, but I also think you are probably using an out of date neslib? Try using the one at shiru's page instead.
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 1:20 pm
by DrDementia
first I'm using the neslib.s from his
examples
ppu_on_all is defined as
Code: Select all
;void __fastcall__ ppu_on_all(void);
_ppu_on_all:
lda <PPU_MASK_VAR
ora #%00011000
ppu_onoff:
sta <PPU_MASK_VAR
sta PPU_MASK
lda #$80
sta PPU_CTRL
jsr _ppu_waitnmi
lda #$00
sta PPU_ADDR
sta PPU_ADDR
lda <PPU_CTRL_VAR
sta PPU_CTRL
rts
I thought the chr banks may be getting switched. not sure why that is.
I agree my code is not the best, I'm struggling to find the best time/way to try and update the vram.
I experimented with the set_vram_update() function. and successfully wrote 16 bytes to the vram each frame with no glitches.
I need to test more. I want to update different spots of the name table(say 16 bytes for 8 different rows). That's 128 total bytes and 8 different calls to set_vram_update. What's the best way to get that done?
any better c libraries to use? or did you write your own library. I think I read you code in c.
:edit think I found the answer about libraries in another thread, and coltrane src
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 1:40 pm
by rainwarrior
I think you need to redownload the examples, this is what ppu_on_all looks like when I just downloaded it now:
Code: Select all
_ppu_on_all:
lda <PPU_MASK_VAR
ora #%00011000
ppu_onoff:
sta <PPU_MASK_VAR
sta PPU_MASK
jsr _ppu_waitnmi
lda #$00
sta PPU_ADDR
sta PPU_ADDR
lda <PPU_CTRL_VAR
sta PPU_CTRL
rts
The problem with the old code that you seem to have is that writes #$80 to $2000 instead of the stuff that's stored in PPU_CTRL_VAR, forcing both sprites and nametable to use the $0000 page until the next frame's NMI. To me this looks like a bug that shiru has since corrected.
I've used cc65 a bit, and did prepare my own libraries work working with it. I don't have a tutorial or much in the way of examples to show. I've so far released one project publicly with full source, but I think you'll have an easier time with shiru's libs than trying to figure out my stuff. If you want to look, it's here:
http://rainwarrior.ca/music/coltrane_src.zip
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 2:17 pm
by DrDementia
you were absolutely right about me using old libs. from june 2013. I got the new one from jan 2014. Then compiled the code from earlier, and still same behavior. I'm a beginner in 6502 so debugging is tough.
going to put a BP on 0x2000 and try to figure it out.
attached new compiled code incase anyone wants to take a look. no delay this try, compiled just as the pastie
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 2:21 pm
by rainwarrior
Just set bit 4 of the PPU_CTRL_VAR.
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 2:57 pm
by DrDementia
according to the wiki page you linked to bit 4 controls "Background pattern table address (0: $0000; 1: $1000)"
so couldn't I just use bank_bg(0); ? Can't seem to get that to work.
here's what that does.
Code: Select all
;void __fastcall__ bank_bg(unsigned char n);
_bank_bg:
and #$01
asl a
asl a
asl a
asl a
sta <TEMP
lda <PPU_CTRL_VAR
and #%11101111
ora <TEMP
sta <PPU_CTRL_VAR
rts
edit: weird, what it does is : for a frame it thinks where I write the bytes to is the beginning of the nametable. or something ??? watching the nametable viewer in fceux shows this. not sure what it's doing.
edit2:
might be a bug in vram_write ??? if I comment that line out nothing strange happens. but it seems where I write to it thinks is the beginning of the NT or bank address??? and starting there that gets shown on screen. You can see it in the example I attached
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 4:35 pm
by tepples
A little strong. Turning off rendering frees up the first 100 CPU cycles on the prerender scanline. I'd have said
you usually don't need to.
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 6:43 pm
by rainwarrior
You want bank_bg(1), your background tiles are at $1000.
I recommended not turning the PPU off because it is of no help when using this library, and turning the PPU back on here is not consequence free (especially since it seems to force scroll to 0,0 for the frame it is called on?). If you want to do advanced things by turning the PPU off, you're not going to be doing it with the library functions.
Actually, I'm surprised shiru didn't move the write to $2001 into the NMI instead; if ppu_on_all is called in the middle of the screen you're going to get a half rendered frame (with incorrect background scroll to boot), I think...
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 6:58 pm
by Movax12
rainwarrior wrote:I recommended not turning the PPU off ...turning the PPU back on here is not consequence free
I understood that forcing render off during vblank was a trick to gain a bit more time to write to VRAM. I turn it off almost immediately in NMI and don't turn it on until all PPU writes are done. Can you verify there are consequences? I'll change my code if there is a downside.
EDIT: Correction: "..don't turn it
off until.." fixed.
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 7:10 pm
by rainwarrior
I'm referring specifically to the consequences of shiru's routine ppu_on_all, and only that. If you call it every frame you're going to get a visual problem.
If disabling rendering during vblank gives a performance boost I'd like to read more about it, actually, but I think it's a bit off topic in this thread. (I can't seem to find information about this on the wiki.)
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 8:32 pm
by tokumaru
rainwarrior wrote:If disabling rendering during vblank gives a performance boost I'd like to read more about it
There's no performance boost, you just get a little extra time for PPU memory accesses because the PPU itself won't be accessing memory during the pre-render scanline when rendering is off. Personally, I prefer to not disable rendering, but I wouldn't think twice about doing if I needed a few more dozen cycles of VBlank time.
Re: write to vram - in c problems
Posted: Mon Mar 24, 2014 9:23 pm
by rainwarrior
Oh, so it's not really any different than the regular technique of keeping rendering off at the top of the screen, only where you happen to be turning back on? Okay. (Anyhow, sorry for the hijack.)