nesdev.parodius.com Forum Index nesdev.parodius.com
NES Development and Strangulation Records message boards
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

nametable questions
Goto page Previous  1, 2
 
Post new topic   Reply to topic    nesdev.parodius.com Forum Index -> Newbie Help Center
View previous topic :: View next topic  
Author Message
bbbirddd



Joined: 08 Jan 2009
Posts: 21
Location: New Hampshire, US

PostPosted: Fri Jan 09, 2009 8:56 am    Post subject: Reply with quote

Confused this works but i still get the flicker. hmmm
Back to top
View user's profile Send private message Visit poster's website
Celius



Joined: 05 Jun 2005
Posts: 1875
Location: Minneapolis, Minnesota, United States

PostPosted: Fri Jan 09, 2009 10:07 am    Post subject: Reply with quote

Oh, try just remove "lda #3 sta $4014" really quick and see if the flickering continues then. If it doesn't, that means that sprite DMA, which I'm pretty sure takes 513 cycles to execute, and then the extra ~1950 to execute the other update code would combine to equal an amount that would cause a spill out of Vblank.
Back to top
View user's profile Send private message Visit poster's website
bbbirddd



Joined: 08 Jan 2009
Posts: 21
Location: New Hampshire, US

PostPosted: Fri Jan 09, 2009 11:29 am    Post subject: Reply with quote

Ok cool, that does prevent the flickering. So I guess I actually don't really need a sprite on screen for the rom I'm trying to make (sort of a live visual type deal), but I am wondering, how do I draw an entire screen full of background tiles instead of just a few rows. I'm already working with 128 bits (?) of background information for only a few lines and isn't there a limit when I'm doing this:

Code:
   lda #$20
   sta $2006                ; $2020-$23C0 = name table 0 (32x25 tiles)
   sta $2006

   ldx #$00
loadNames:                  ; load background name table (bkg12.map)
   lda ourMap, x
   inx
   sta $2007               ; $2007 = PPU memory data
   cpx #4*32
   bne loadNames
Back to top
View user's profile Send private message Visit poster's website
Celius



Joined: 05 Jun 2005
Posts: 1875
Location: Minneapolis, Minnesota, United States

PostPosted: Fri Jan 09, 2009 4:06 pm    Post subject: Reply with quote

If you have a 1k (1024 bytes) name table arrangement in a file (Like your files, just for the whole name table), in order to load it you have to use indirect addressing. So you'd put the address of the start of the background data file into say $50 and $51, where $50 contains the low byte and $51 contains the high byte of the address. Then you start with Y = 0, and you do "lda ($50),y sta $2007" and "iny" in a loop until y wraps back to 0, at which point you add 1 to $51. And you'll loop 3 more times after that. You basically copy 4 256 byte sections to the name table. But if you do this, you're going to want to shut off the screen entirely for a frame or so, because this is probably not going to fit into 2200 cycles (in fact, that's impossible for that to happen).
Back to top
View user's profile Send private message Visit poster's website
bbbirddd



Joined: 08 Jan 2009
Posts: 21
Location: New Hampshire, US

PostPosted: Sun Jan 11, 2009 9:41 am    Post subject: Reply with quote

Thanks again Celius. This has been really helpful. But this all leads me to a question. Isn't it better to perform as few operations during an interrupt as possible? I understand that what I am doing at the moment is taking less than 2200 cycles and therefore will complete without flickering during a VBlank, but wouldn't it generally be better to keep as much out of the VBlank routine as possible? In your last response you suggested that I could not redraw a whole background image within 2200 cycles, and therefore would need to turn the screen off and on around that code. If I do this, should I take all that controller stuff out of the VBlank routine and put it back in my Infinite loop?
Back to top
View user's profile Send private message Visit poster's website
tepples



Joined: 19 Sep 2004
Posts: 4887
Location: USA

PostPosted: Sun Jan 11, 2009 12:53 pm    Post subject: Reply with quote

You can keep the controller reading code in the NMI handler, as long as you do it after you turn rendering back on at PPUMASK. In fact, Super Mario Bros. does virtually everything in its NMI handler.
Back to top
View user's profile Send private message Visit poster's website AIM Address
bbbirddd



Joined: 08 Jan 2009
Posts: 21
Location: New Hampshire, US

PostPosted: Sun Jan 11, 2009 2:00 pm    Post subject: Reply with quote

so what does one generally put in the infinite loop? anything?
Back to top
View user's profile Send private message Visit poster's website
Bregalad



Joined: 12 Nov 2004
Posts: 3640
Location: Jongny, VD, Switzerland

PostPosted: Sun Jan 11, 2009 2:27 pm    Post subject: Reply with quote

I don't put an infinite loop. The closer I have a game loop, but it's not intinite because it breaks on game over or level beaten condiitons.

SMB have an infinite loop tough.
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Disch



Joined: 10 Nov 2004
Posts: 1445

PostPosted: Sun Jan 11, 2009 2:28 pm    Post subject: Reply with quote

Seperating the infinite loop from the NMI is unimportant in simple programs, but to handle slowdown effectively, it can be useful to keep them each doing seperate jobs. The approach I'd use would be something like this:

In Infinite loop:
---------------------
1) Update joypad data
2) Do game logic (collision detection, AI, etc)
3) Draw sprites and stuff to shadow OAM
4) Prepare an organized list of PPU writes in a buffer so that you can quickly dump stuff to $2007 next vblank.
5) Set a "can draw" flag
6) Set a "waiting for VBl" flag
7) Wait for "waiting for VBl" flag to clear
8) Repeat from step 1


In NMI:
---------------------
1) Set up CPU cycle based IRQ if needed for raster effects (if mapper 069 or something -- probably not applicable most of the time).
2) Do Sprite DMA (only if "can draw" flag is set)
3) Scan the prepared drawing buffer and do all desired $2007 writes (step 4 in infinite loop) -- (only if "can draw" flag is set)
4) Clear the "can draw" flag to indicate drawing is done
5) Set scroll
6) Set up PPU based IRQ if needed for raster effects (if mapper 004 or something)
7) Just to music routine to keep music/sound effects playing
8) Clear "waiting for vbl" flag
9) RTI



This setup keeps the logic and drawing code seperated so that if NMI interrupts your game logic, you can still do necessary raster effects like splitting the screen, as well as keep music playing without disrupting game logic.

Also the "can draw" flag prevents your NMI handler from drawing half-completed stuff if the NMI happens in the middle of your preparation.

So this setup gracefully handles slowdown and stuff without causing weird graphical glitches.


EDIT:

it dawns on me that you can use the "waiting for vblank" flag as the "can draw" flag -- so you only need one flag. *shrug*
Back to top
View user's profile Send private message
bbbirddd



Joined: 08 Jan 2009
Posts: 21
Location: New Hampshire, US

PostPosted: Sun Jan 11, 2009 2:49 pm    Post subject: Reply with quote

wow, thanks for the great explanations. i'm still a bit hung up on indirect addressing. I understand how the actual addressing works I think, but how do I store my background data in a specific location to access by indirect addressing? For example, I have this included in my code at the moment, how do I store it in a specific location?

Code:
ourMap2:.db  1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0
      .db 17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0
      .db  0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2
      .db  0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18
      .db  1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0
      .db 17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0
      .db  0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2
      .db  0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18
      .db  1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0
      .db 17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0
      .db  0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2
      .db  0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18
      .db  1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0
      .db 17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0
      .db  0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2
      .db  0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18
      .db  1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0
      .db 17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0
      .db  0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2
      .db  0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18
      .db  1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0
      .db 17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0
      .db  0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2
      .db  0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18
      .db  1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0
      .db 17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0
      .db  0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2
      .db  0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18
      .db  1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0
      .db 17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0,17,18, 0, 0


Is this table ready to be stored somewhere/accesses? Or do I need to save this info in some other way? Again, I'm a beginner, so sorry if this is pretty simple.
Back to top
View user's profile Send private message Visit poster's website
Disch



Joined: 10 Nov 2004
Posts: 1445

PostPosted: Sun Jan 11, 2009 3:20 pm    Post subject: Reply with quote

Your data should be immediately accessable via the ourMap2 label. What you need to do is copy the address this label represents (aka create a "pointer" to the label) and put that pointer somewhere in zero page memory. From there you can use indirect addressing on that pointer.

I don't know the NESASM syntax for it (assuming that's what you're using -- I haven't really been paying attention), but here's how you'd do that in ca65:

Code:

; assuming 'ptr' is a 2-byte variable in zero page

lda #<ourMap2   ; put low byte of ourMap2 address in A
sta ptr         ;  write as low byte of our pointer

lda #>ourMap2   ; get high byte
sta ptr+1       ;  write as high byte of pointer

ldy #0          ; zero Y for indexing
lda (ptr),Y     ; do an indirect read from the address our pointer points to
                ;  plus Y.  Since ptr points to 'ourMap2', and since Y=0, this
                ;  will read from ourMap2+0

                ; you can increase Y to go to the next byte, then increase ptr+1 once
                ;  Y wraps to point to the next 256-byte block


iirc, nesasm code for this is probably something like:

Code:

lda #LO(ourMap2)
sta <ptr

lda #HI(ourMap2)
sta <ptr+1

ldy #0
lda [ptr],Y
Back to top
View user's profile Send private message
bbbirddd



Joined: 08 Jan 2009
Posts: 21
Location: New Hampshire, US

PostPosted: Sun Jan 11, 2009 8:32 pm    Post subject: Reply with quote

Again, I understand the explanation but I am in fact using NESASM and can't seem to get this to work. Does anyone know how to handle this in NESASM? Thanks for all the help
Back to top
View user's profile Send private message Visit poster's website
Banshaku



Joined: 24 Jun 2008
Posts: 892
Location: Tokyo, Japan

PostPosted: Mon Jan 12, 2009 2:35 am    Post subject: Reply with quote

I didn't follow the thread completely but the proper syntax for nesasm is:

Code:

   lda #LOW(ourMap2)
   sta ptr
   lda #HIGH(ourMap2)
   sta ptr + 1
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    nesdev.parodius.com Forum Index -> Newbie Help Center All times are GMT - 7 Hours
Goto page Previous  1, 2
Page 2 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group