Tips on best coding practices?

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

User avatar
pubby
Posts: 583
Joined: Thu Mar 31, 2016 11:15 am

Re: Tips on best coding practices?

Post by pubby »

Nowadays people put controller reads immediately after sprite DMA in order to prevent a glitch related to DPCM sounds. See: https://wiki.nesdev.com/w/index.php/Con ... ng_OAM_DMA

You don't have to understand what those words mean in order to use it. Just copy/paste the code from the wiki into your NMI subroutine.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Tips on best coding practices?

Post by tokumaru »

pubby wrote:Nowadays people put controller reads immediately after sprite DMA in order to prevent a glitch related to DPCM sounds. See: https://wiki.nesdev.com/w/index.php/Con ... ng_OAM_DMA
That could present a problem if done in the NMI and the logic in a lag frame samples different controller states. You can easily solve that if you just copy the controller state to a secondary variable to be used for game logic at the beginning of the game loop though.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Tips on best coding practices?

Post by rainwarrior »

pubby wrote:Nowadays people put controller reads immediately after sprite DMA in order to prevent a glitch related to DPCM sounds. See: https://wiki.nesdev.com/w/index.php/Con ... ng_OAM_DMA

You don't have to understand what those words mean in order to use it. Just copy/paste the code from the wiki into your NMI subroutine.
It's a valid way to prevent the DPCM glitch but it's not always appropriate to read your controller in the NMI. (ilag frames leading to inconsistent state throughout the update, missed button presses, etc.)

Edit: tokumaru already covered it.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Tips on best coding practices?

Post by tokumaru »

I said you could easily solve the problem using a secondary variable but I didn't really spend much time thinking about all the implications of that. Missed button presses could happen either way I suppose. Is there anything else that could go wrong in that case?
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Tips on best coding practices?

Post by tepples »

tokumaru wrote:
pubby wrote:Nowadays people put controller reads immediately after sprite DMA in order to prevent a glitch related to DPCM sounds.
That could present a problem if done in the NMI and the logic in a lag frame samples different controller states. You can easily solve that if you just copy the controller state to a secondary variable to be used for game logic at the beginning of the game loop though.
Or by reading input only after DMA to OAM. In lag frames, the flag for "display list is ready" won't be set.
User avatar
JWinslow23
Posts: 30
Joined: Mon Apr 24, 2017 5:52 am
Location: West Allis, WI

Re: Tips on best coding practices?

Post by JWinslow23 »

Sumez wrote:Absolutely. You can easily store all 8 button states on a single NES controller in a single byte, with each bit indicating wether the button is pressed. I also do comparisons with the previous NMI to see if a button was just pressed to trigger events on button pulses (such as attacking or jumping), and store those in a separate byte.
Yes, I do do this.

Code: Select all

ReadJoypad:
  LDA <ButtonsHeldNow
  STA <ButtonsHeldLastFrame ; Store ButtonsHeldNow into ButtonsHeldLastFrame
  LDA #$01
  STA $4016             ; Continuously reload the buttons
  STA <ButtonsHeldNow   ; Initialize ButtonsHeldNow
  LSR A
  STA $4016             ; Stop reloading; ready to read controller
JoypadLoop:
  LDA $4016
  LSR A                 ; Store button state into carry
  ROL <ButtonsHeldNow   ; Rotate carry into ButtonsHeldNow
  BCC JoypadLoop        ; Carry will be 1 once all buttons are read
                        ; So jump back if carry is 0
  RTS                   ; Return
tokumaru wrote:stuff that does things in places
Did that, and it works. Thanks!
pubby wrote:Nowadays people put controller reads immediately after sprite DMA in order to prevent a glitch related to DPCM sounds. See: https://wiki.nesdev.com/w/index.php/Con ... ng_OAM_DMA

You don't have to understand what those words mean in order to use it. Just copy/paste the code from the wiki into your NMI subroutine.
As I don't use DPCM sounds (yet; I might possibly have a title scream or something), I'm just not going to bother with that. Besides, my controller routine will only read the first controller (this will be a one player game), and it also stores the last button held, so I'm not sure what that does to the cycles.
User avatar
JWinslow23
Posts: 30
Joined: Mon Apr 24, 2017 5:52 am
Location: West Allis, WI

Re: Tips on best coding practices?

Post by JWinslow23 »

Bump.

Right now, I want to be able to add scrolling to this game. I'm a bit confused by the docs over at the NESDev Wiki, I'm not exactly sure what to do. How do I actually make the background scroll? I'll be scrolling horizontally, and the background repeats, if that helps.
User avatar
Bregalad
Posts: 8056
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Tips on best coding practices?

Post by Bregalad »

JWinslow23 wrote:Bump.

Right now, I want to be able to add scrolling to this game. I'm a bit confused by the docs over at the NESDev Wiki, I'm not exactly sure what to do. How do I actually make the background scroll? I'll be scrolling horizontally, and the background repeats, if that helps.
The scrolling pages on the wiki are currently being reworked, currently they are a bit messed up. They'll be fixed in the near future.

As how to make a repeating BG scroll it's extremely simple, you use the $2000 and $2005 registers to do that.
User avatar
JWinslow23
Posts: 30
Joined: Mon Apr 24, 2017 5:52 am
Location: West Allis, WI

Re: Tips on best coding practices?

Post by JWinslow23 »

Bregalad wrote:
JWinslow23 wrote:Bump.

Right now, I want to be able to add scrolling to this game. I'm a bit confused by the docs over at the NESDev Wiki, I'm not exactly sure what to do. How do I actually make the background scroll? I'll be scrolling horizontally, and the background repeats, if that helps.
The scrolling pages on the wiki are currently being reworked, currently they are a bit messed up. They'll be fixed in the near future.

As how to make a repeating BG scroll it's extremely simple, you use the $2000 and $2005 registers to do that.
...use them how? That's my question. :P OK, I've made the screen "scroll" horizontally, but it seems that the background has also been shifted up 2 rows (when my ScrollX is always 0). What do I do to remedy this? Here is my code that handles scrolling (with .inesmir 0 as the mode):

Code: Select all

  DEC <ScrollY
  BIT $2002
  LDA <ScrollY
  STA $2005
  LDA #$00
  STA $2005
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Tips on best coding practices?

Post by tokumaru »

You appear to have switched X and Y there... The first $2005 write sets the horizontal scroll (X) while the second write sets the vertical scroll (Y).

Note that depending on the NT mirroring you're using, the total background size will be either 256x480 pixels (horizontal mirroring) or 512x240 pixels (vertical mirroring), meaning that one of the scroll values can't be represented in just 8 bits (8 bits can only go up to 255, but you need to go up to 479 or 511). For this reason, in addition to writing to $2005, you need to update the "9th bit" of the scroll values using register $2000 (the lower 2 bits).

If the background is supposed to be the same 256x480 or 512x240 area over and over, simply changing the scroll registers will do, but if you want to display a larger background, such as a level in SMB, you'll need to progressively update the name tables each vblank in coordination with the scroll changes.
User avatar
JWinslow23
Posts: 30
Joined: Mon Apr 24, 2017 5:52 am
Location: West Allis, WI

Re: Tips on best coding practices?

Post by JWinslow23 »

tokumaru wrote:You appear to have switched X and Y there... The first $2005 write sets the horizontal scroll (X) while the second write sets the vertical scroll (Y).

Note that depending on the NT mirroring you're using, the total background size will be either 256x480 pixels (horizontal mirroring) or 512x240 pixels (vertical mirroring), meaning that one of the scroll values can't be represented in just 8 bits (8 bits can only go up to 255, but you need to go up to 479 or 511). For this reason, in addition to writing to $2005, you need to update the "9th bit" of the scroll values using register $2000 (the lower 2 bits).

If the background is supposed to be the same 256x480 or 512x240 area over and over, simply changing the scroll registers will do, but if you want to display a larger background, such as a level in SMB, you'll need to progressively update the name tables each vblank in coordination with the scroll changes.
Well, the writes are how they're supposed to be. I gotta be less stupid in variable naming, that should be ScrollX (horizontal scrolling) :P . And the background will simply be repeating, as in my original two games. The problem here is, there seem to be two blank rows of background appearing now that weren't there earlier. I've "fixed" it by setting the scroll y to always equal $F0, but I'm sure there's a better way.

What I have now seems to work for my purposes, but to do this "correctly", how would I change $2000? I'm trying this:

Code: Select all

  LDA <ScrollX
  BEQ NoWrap
  LDA $2000
  EOR #%00000001
  STA $2000
NoWrap:
This is supposed to toggle the X>256 bit of $2000 every time the scroll x is 0, but this is causing the sprite to render incorrectly. How would I fix this?
Last edited by JWinslow23 on Tue Apr 25, 2017 6:18 am, edited 1 time in total.
User avatar
Bregalad
Posts: 8056
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Tips on best coding practices?

Post by Bregalad »

JWinslow23 wrote: The problem here is, there seem to be two blank rows of background appearing now that weren't there earlier. I've "fixed" it by setting the scroll y to always equal $F0, but I'm sure there's a better way.
You should explain your problem better. $f0 is a "negative" vertical scroll value and you should avoid it as it will show attribute table data as name table data. This should make 16 glitchy lines at the top of the screen, although 8 will be hidden by overscan so 8 will show.

If you need to move the screen down by 16 pixels, use the value $e0 instead.
User avatar
JWinslow23
Posts: 30
Joined: Mon Apr 24, 2017 5:52 am
Location: West Allis, WI

Re: Tips on best coding practices?

Post by JWinslow23 »

Bregalad wrote:
JWinslow23 wrote: The problem here is, there seem to be two blank rows of background appearing now that weren't there earlier. I've "fixed" it by setting the scroll y to always equal $F0, but I'm sure there's a better way.
You should explain your problem better. $f0 is a "negative" vertical scroll value and you should avoid it as it will show attribute table data as name table data. This should make 16 glitchy lines at the top of the screen, although 8 will be hidden by overscan so 8 will show.

If you need to move the screen down by 16 pixels, use the value $e0 instead.
Not working. The screen is blank if I use $E0 for some reason.

The thing is, I'm thinking $00 should work and show the whole screen, but even in NTSC mode, there seem to be blank rows on the bottom that don't show up without the scrolling code. This is confusing to me. :?
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Tips on best coding practices?

Post by tepples »

If Y=224 ($E0) blanks the screen, then you probably have the cartridge set to 256x480 (aka vertical arrangement or horizontal mirroring), and it's reading the wrong nametable. Try setting bit 1 of the value you write to $2000, that is, ORing it with the value $02.


EDIT: corrected brain fart
User avatar
Bregalad
Posts: 8056
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Tips on best coding practices?

Post by Bregalad »

tepples wrote:If Y=224 ($E0) blanks the screen, then you probably have the cartridge set to 256x480 (aka vertical arrangement or horizontal mirroring), and it's reading the wrong nametable. Try setting bit 1 of the value you write to $2001, that is, ORing it with the value $02.
$2000 not $2001. That or simply use vertical mirroring / horizontal arrangement.
Post Reply