It is currently Thu Nov 23, 2017 11:57 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 80 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6  Next
Author Message
PostPosted: Mon Jul 24, 2017 10:28 pm 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 876
Location: Sweden
Yes and if it's a one player game you read bit 0 and bit 1 of $4016 as controller 1 data so that either standard or expansion controller can be used. If it's a two player game you also read bit 0 and bit 1 of $4017 as controller 2 data. This is what (most) commercial games do.
Only if you have a three or four player game you would treat bit 0 of $4016 and $4017 as separate data (as controller 1 and 2) from bit 1 (as controller 3 and 4). In that case you would also want to support the four score.

IMAGICA wrote:
I need to learn buffering first

The Nerdy Nights sound tutorial actually has a (graphic) buffering system that is worth studying.


Top
 Profile  
 
PostPosted: Wed Aug 02, 2017 1:51 pm 
Offline
User avatar

Joined: Thu Jul 13, 2017 5:17 pm
Posts: 35
Can you confirm if I'm reading bit 1?
Code:
 LDA #$01
  STA $4016
  LDA #$01
  STA $4016
  LDX #$08


Top
 Profile  
 
PostPosted: Wed Aug 02, 2017 3:58 pm 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 876
Location: Sweden
Not there. There you are writing to the $4016 output port, which is used by the controller as a command that it's time to send its current button data to the NES. It's called a latch or strobe for the controllers, and it gets you all controllers including the expansion port controllers.


Here is where you don't read bit 1:
Code:
  LDX #$08
ReadController1Loop:
  LDA $4016
  LSR A            ; bit0 -> Carry
  ROL buttons     ; bit0 <- Carry
  DEX
  BNE ReadController1Loop
 
  RTS

You shift bit 0 of $4016 into Carry (using LSR) and then rotate it out of Carry and into the RAM register "buttons" (using ROL). But you never touch bit 1 of $4016.

A simple way is to just add another set of LSR and ROL to get bit 1 into a temporary variable. Then you merge the two variables using OR.
Code:
  LDX #$08
ReadController1Loop:
  LDA $4016            ;get button data from bit 0 (con I) and bit 1 (con III)
  LSR A                ;shift button data from bit 0 into carry
  ROL buttons          ;rotate carry into a RAM register (con I buttons)
  LSR A                ;shift button data from bit 1 into carry
  ROL temp             ;rotate carry into a RAM register (con III buttons)
  DEX
  BNE ReadController1Loop

MergeControllers:
  LDA temp
  ORA buttons            ;OR con III with con I to merge them
  STA buttons

  RTS

And if your game is using two controllers you just repeat this code but use $4017 instead to get controller II and IV, and then merge them with each other the same way.



Edit: The easiest way to test if expansion port controllers (AKA controller III and IV) are working, is to test the game in an emulator like FCEUX and enable "Famicom 4-player Adapter" or similar. Then you just enable controller III in the emulator and see if it works with your game the same as controller I.


Top
 Profile  
 
PostPosted: Wed Aug 02, 2017 5:01 pm 
Offline
User avatar

Joined: Thu Jul 13, 2017 5:17 pm
Posts: 35
Thanks by the way what is the advantage of 8x16 sprites are? I willing to remake my sprites if it has advantages I need.


Top
 Profile  
 
PostPosted: Wed Aug 02, 2017 6:15 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5833
Location: Canada
IMAGICA wrote:
Thanks by the way what is the advantage of 8x16 sprites are? I willing to remake my sprites if it has advantages I need.

We had a recent thread on that topic:
https://forums.nesdev.com/viewtopic.php?f=2&t=16235

The advantage is really just that they're bigger. You can cover more screen with them, and use all 8K of the CHR tables rather than just one 4K side.

Conversely, the disadvantage is also that they're bigger. You'll end up with more wasted space at edges, and probably more overlap problems (i.e. 8 sprites per scanline issues).


Top
 Profile  
 
PostPosted: Sun Aug 20, 2017 9:35 pm 
Offline
User avatar

Joined: Thu Jul 13, 2017 5:17 pm
Posts: 35
I'm Still here. I'm now fixing the vblank issue of the game.
I'm also goin to post the code for anyone to find pout the v blank issue that Pokun gave the answer to.
Pokun wrote:
IMAGICA wrote:
2. I Don't want the All nmi approach. I want some of the rendering to go Outside Like text, boss AI and other stuff. I heard that It boggles down speed if your not careful.

Then just move out all your logic from the NMI and put it in your forever loop. Only keep the graphic updates (OAM, VRAM, $2000, $2001 and $2005 writes) in the NMI.

IMAGICA wrote:
3. It's a one player game. However, If I get to demaking smash bros., I'll need that info

You misunderstand me. If it's a one player game, you need to read both bit 0 and bit 1 of $4016 to your controller 1 data so that people can use both standard controllers and Famicom expansion port controllers. Nerdy Nights doesn't teach this but it's good practice to do it. Else people might not be able to use their arcade sticks and other controllers with your game.

IMAGICA wrote:
4. I found an article on stacks pha and pla. I just need to figure out where my buffer's going to go.

Your buffers goes into RAM wherever there is space. You are already buffering OAM and scroll in RAM. I like to keep my OAM buffer on RAM page 2 ($0200~$02FF), BG and palette buffers in page 3, and scroll and $2000/$2001 buffers in the zero page. The BG buffer can't be too big (there's not enough vblank time to draw the whole nametable), so you could also keep BG and palette buffers at the beginning of page 1. The stack starts in the other end of page 1 so unless you use a lot of stack there's no risk they will collide.


Attachments:
Kitsunetales.asm [26.46 KiB]
Downloaded 28 times
Top
 Profile  
 
PostPosted: Mon Aug 21, 2017 3:28 am 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 876
Location: Sweden
The https://wiki.nesdev.com/w/index.php/The_frame_and_NMIs explains how you can structure your code to keep graphic updates and game logic separate.

A few problems:

Code:
  lda #%00000001
  sta $4017 ;enable Square 1

I guess you meant $4015 here, that's where you enable/diable APU sound channels.

Code:
clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  STA $0200, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  LDA #$FE
  STA $0300, x
  INX
  BNE clrmem

I guess you meant to initialize $0200 to $FF, not $0300, since you are using $0200 as OAM buffer later in your code. You should do it like this:
Code:
clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  STA $0300, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  LDA #$FE
  STA $0200, x
  INX
  BNE clrmem

This makes sure all sprites are off screen at boot, hiding them.


Code:
Forever:

  JMP Forever     ;jump back to Forever, infinite loop

Here is your main loop, here you can put all logic (except sound which is better off in the NMI to avoid sound lag).

Mine look something like this:
Code:
main:
  jsr con_read       ;read controllers
  jsr logic          ;state machine with all game logic, like: input handlers, moving objects, collisions gravity etc

  lda #$01
  sta draw_flag           ;allow NMI to draw, prevents incomplete buffering
nmi_wait:
  lda nmi_end_flag
  beq nmi_wait            ;wait for NMI to finish, this limits logic to a fixed frame rate
  lda #$00
  sta nmi_end_flag        ;clear NMI completion flag
  jmp main

At the end of the main loop I wait for an NMI to finish. This makes sure there is only one NMI (graphic update) per main loop (game logic). Inside the NMI I only update graphics if the draw flag is set, otherwise I skip it. This prevents the NMI from drawing a frame if the main loop hasn't finished in time for the vblank. Also at the end of the NMI I set the NMI end flag so the main loop knows when it's time to start the next iteration.

In your NMI you first push A, X and Y to the stack so they don't mess with your logic, should an NMI happen in the middle of it. Then check for the draw flag, and skip updates if it's clear, then you fires off your OAM DMA (writing 0 to $2003 and $02 to $4014) to update sprites. After that you should do all your nametable and palette updates ($2006 and $2007) and finally scroll ($2005) and any PPU setting changes ($2000 and $2001).

After that you can do sound and anything else that you want to happen constantly at 60 Hz (or 50 Hz if PAL) without lag, but doesn't need to be in vblank (because vblank time might be up before your NMI handler has finished, that's why we put graphic updates first in the NMI).
And finally last thing before the RTI you have to pull A, X and Y from the stack again (in reverse order from that you pushed them in).

Just ask if there's something not clear enough.


Top
 Profile  
 
PostPosted: Sat Sep 02, 2017 1:27 pm 
Offline
User avatar

Joined: Thu Jul 13, 2017 5:17 pm
Posts: 35
Pokun wrote:
Code:
main:
  jsr con_read       ;read controllers
  jsr logic          ;state machine with all game logic, like: input handlers, moving objects, collisions gravity etc

  lda #$01
  sta draw_flag           ;allow NMI to draw, prevents incomplete buffering
nmi_wait:
  lda nmi_end_flag
  beq nmi_wait            ;wait for NMI to finish, this limits logic to a fixed frame rate
  lda #$00
  sta nmi_end_flag        ;clear NMI completion flag
  jmp main


how would
Code:
 lda nmi_end_flag
  beq nmi_wait           

work in this function?

second if I were to modify the mirroring at the end, woulden't I get an error?
Heard that's only possible with mmc3.


Top
 Profile  
 
PostPosted: Sat Sep 02, 2017 2:44 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19252
Location: NE Indiana, USA (NTSC)
The NMI handler interrupts the loop and sets the flag to a nonzero value.


Top
 Profile  
 
PostPosted: Sat Sep 02, 2017 7:20 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1832
Location: DIGDUG
Quote:
if I were to modify the mirroring at the end, woulden't I get an error?
Heard that's only possible with mmc3.


PPU Mirroring is hardwired into the PCB (by soldering a spot). It can't be changed except by a special mapper (such as MMC3).

Perhaps there is some other kind of mirroring you are talking about? Many of the CPU RAM addresses are mirrors of other addresses, for example.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Mon Sep 04, 2017 7:03 pm 
Offline
User avatar

Joined: Thu Jul 13, 2017 5:17 pm
Posts: 35
tepples wrote:
The NMI handler interrupts the loop and sets the flag to a nonzero value.

How would that happen?

My code is stuck.

I can't just expect it to do it.
what's the "special flag" stack I need to link to it?


Top
 Profile  
 
PostPosted: Mon Sep 04, 2017 7:39 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1832
Location: DIGDUG
If you look at the wiki page on PPU registers...

http://wiki.nesdev.com/w/index.php/PPU_registers

You will see, setting bit 7 on register $2000 will tell the PPU to generate an NMI signal at the end of every frame (at the start of vertical blanking).

With NMIs on, the code will automatically jump to the NMI code (wherever the NMI vector points to), and then once it sees an RTI, will return to the main code.

The NMI code is where you should update sprites, make changes to the background, and call the music subroutine.

Or, you could just flip a NMI_flag on, and immediately RTI. In this scenario, the main code would be looking for changes in the NMI_flag, before it does those things I mentioned (sprites, BG, music)

And read the controllers, maybe.

Edit - on a side note, NMIs are not affected by SEI and CLI, hence the "non maskable" in the name.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Tue Sep 19, 2017 9:31 am 
Offline
User avatar

Joined: Thu Jul 13, 2017 5:17 pm
Posts: 35
Here's something I've learned:
Never use a NMI that is used to render 8x8 sprites to render 8x16 sprites
Also don't mess with the vblank. I am learning x and y rendering values.


... how do you push x and y?
phx and phy?


Attachments:
Kitsunetales.asm [26.94 KiB]
Downloaded 13 times
Top
 Profile  
 
PostPosted: Tue Sep 19, 2017 10:13 am 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1832
Location: DIGDUG
PHY and PHX don't exist.

PHY = TYA PHA
PHX = TXA PHA

If you need to preserve A, first store A to a temporary variable...

STA temp
TYA
PHA
LDA temp

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
PostPosted: Wed Sep 20, 2017 10:44 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10118
Location: Rio de Janeiro - Brazil
dougeff wrote:
PHY and PHX don't exist.

They do exist in the 65C02 and 65816, but not in the 6502, which is the core the NES uses.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 80 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 8 guests


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 post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group