It is currently Wed Jun 28, 2017 12:14 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 46 posts ]  Go to page Previous  1, 2, 3, 4  Next
Author Message
 Post subject: Re: Corrupt File?
PostPosted: Mon Mar 20, 2017 11:16 am 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1601
Location: DIGDUG
Further on why Japanese expansion controllers listed separately...from the wiki...

https://wiki.nesdev.com/w/index.php/Standard_controller

Famicom $4016:
76543210
---- ----
oooo oMFD
|||| ||||
|||| |||+- Player 1 serial controller data
|||| ||+-- If connected to expansion port (and available), player 3 serial controller data (0 otherwise)
|||| |+--- Microphone in controller 2 on traditional Famicom, 0 on AV Famicom
++++-+---- Open bus

Information only comes in 1 bit at a time, each time the port is read. 8 reads for 8 buttons.

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


Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Mon Mar 20, 2017 11:47 am 
Offline

Joined: Mon Jan 30, 2017 5:20 pm
Posts: 262
Location: Colorado USA
Could you explain why you shift bits and push the accumulator to the stack? I don't know much about shifting bits and pushing and pulling the stack. I know how to count in binary. Is that what shifting bits is? Just a glorified increment? Isn't the stack what remembers the address of the command It's executing?


Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Mon Mar 20, 2017 12:19 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 18536
Location: NE Indiana, USA (NTSC)
Bit shifts are used here to combine multiple reads from a serial port into one byte.


Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Mon Mar 20, 2017 12:38 pm 
Offline
User avatar

Joined: Wed Oct 16, 2013 7:55 am
Posts: 115
A bit shift is different from an increment. It moves all bits left or right, which in binary is equivalent to multiplying or dividing by 2.

For example:
0000_0100 is 4
when shifted left once it becomes
0000_1000 which is 8
but when shifted right once becomes
0000_0010 which is 2

The controller hardware only yields a single bit at a time, so shifts are used here to pack all the bits together into a single byte.


Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Mon Mar 20, 2017 12:52 pm 
Offline

Joined: Mon Jan 30, 2017 5:20 pm
Posts: 262
Location: Colorado USA
Okay, I understand bit shifting. what about pushing and pulling from the stack? Why do we need that in reading the controllers?


Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Mon Mar 20, 2017 2:00 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 18536
Location: NE Indiana, USA (NTSC)
Here's what the code snippet marked "SMB3" is doing:

Read the controller state into $00.
Load $00 and save it on the stack.
Read the controller state into $00 again.
Load the value saved on the stack, which is the first controller state.
Compare it to the value in $00, which is the second controller state.

It's trying to read the controller twice, compare the results, and accept the result only if the two reads match. This avoids a bug in the 2A03 CPU, used in the Famicom, NTSC NES, and RGB systems, that causes misreads during DPCM playback.

In general, reading the controllers need not involve the stack. The routine in the file I linked, pads.s, reads the controllers to $0000 and $0001 and saves the first read to $0002 and $0003 instead of the stack.

But the use of the stack to save a temporary value is a common idiom in assembly language programming. We can only speculate why the stack was used instead of a variable on zero page in this particular instance. One possibility is saving code size, as PHA and PLA are one byte shorter than STA to zero page or LDA from zero page. Another is overwriting fewer local variables so as not to disturb variables in use by the caller.


Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Mon Mar 20, 2017 2:04 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 9758
Location: Rio de Janeiro - Brazil
DementedPurple wrote:
Okay, I understand bit shifting. what about pushing and pulling from the stack? Why do we need that in reading the controllers?

Just to be clear, you don't need to use the stack to read the controllers, it's just that one specific implementation used it. Everything in programming can be done a thousand different ways.

Anyway, that routine is just saving a copy of the button states to the stack, so it can read the controllers again (which overwrites the variable) and compare both values. There's a glitch in the NES that sometimes corrupts controller reads when DPCM samples are playing, so one solution to avoid that problem is to read the controller repeatedly until 2 consecutive reads match.

You can use PHA and PLA to store things in the stack temporarily, but you have to be careful to always execute the same number of PHAs and PLAs, otherwise the program can easily crash due to stack overflows or underflows.


Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Mon Mar 20, 2017 3:10 pm 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 593
Location: Sweden
DementedPurple wrote:
And maybe teach me how to make a variable?

Variables are actually just definitions (labels) of RAM registers so you could use the = or .equ directive in ASM6 like:
Code:
var0 = $0000  ;general purpose variable
var1 = $0001
;...

But that would make it not possible to insert new variables in between the ones you wrote earlier. So assemblers has directives that automatically increments an internal counter of the assembler for definition purposes. In ASM6 it's the .dsb (define storage byte) and .dsw (define storage word) directives together with .enum (enumerate) and .ende (end enumerate).

Example RAM map:
Code:
  .enum $0000 ;$0000-$00FF (Zero Page)
var0 .dsb 1  ;general purpose variable
var1 .dsb 1
pointer0 .dsb 2  ;general purpose pointer
frame_count .dsb 1 ;frame counter
con_stat .dsb 2 ;controller button states
p1_x .dsb 1 ;player 1 X-coordinate
p1_y .dsb 1 ;player 1 Y-coordinate
p1_rest .dsb 1 ;player 1 lives
p1_score .dsb 1 ;player 1 score
;...
  .ende

  .enum $0100 ;$0100-$01FF (hardware stack)
;Reserved for the stack.
  .ende

  .enum $0200 ;$0200-$02FF (shadow OAM)
shadow_oam .dsb 256
  .ende

  .enum $0300 ;$0300-$07FF
array0 .dsb 16
array1 .dsb 32
;...
  .ende

Here var0 will be defined as $0000 and var1 will be $0001. The number after the .dsb directive is how many bytes you reserve for the label. I used two byte for con_stat, that way you can have controller I button states in con_stat+0 and controller II button states in con_stat+1. Zero Page should only be used for often accessed variables and for your pointers (as they require the ZP). Bigger things like arrays may be put in later pages so they don't take up too much of your Zero Page space. Page 1 is used by the hardware stack, but you can use part of it if you run out of RAM and don't use a ton of stack. The stack builds from $01FF and down, so use the first part of this page for variables in that case. Page 2 is usually used for shadow OAM, it's not necessary to use this page, but you have to use one whole RAM page for that if you are going to use OAM DMA, so you might as well use page 2 since that's what everyone does. Commercial games as well as homebrew normally uses it.
Dividing the RAM in pages like this you must of course make sure that your variables doesn't spill out of the page and into the next one.

I think you can make RAM definitions about anywhere in the source file (I'm not sure), but it makes sense to put them in the beginning like in the templates.


Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Mon Mar 20, 2017 4:27 pm 
Offline

Joined: Mon Jan 30, 2017 5:20 pm
Posts: 262
Location: Colorado USA
With dougeffs example, how would I jump to a certain location when a button is pressed?


Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Mon Mar 20, 2017 7:05 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1601
Location: DIGDUG
I do something like this...

Code:
enum $000

joypad1:   .db 0
joypad1_last_frame:   .db 0

.ende

;A, B, Select, Start, Up, Down, Left, Right
right = $01
left = $02
down = $04
up = $08
start = $10
select = $20
b_button = $40
a_button = $80

Edit, fixed wrong button order.
(in NMI, after all PPU / Sprite / Scrolling stuff)

Code:
   LDA joypad1
   STA joypad1_last_frame ; save the last frame's buttons
ReadController:
   LDX #$01
   STX $4016
   DEX
   STX $4016
   LDX #$08
ControllerLoop:
   LDA $4016
   LSR
   ROL joypad1
   DEX
   BNE ControllerLoop
;new buttons now stored in joypad1 RAM address


(if you want to do something, anytime B is pressed, even if held)

Code:
   LDA joypad1   
   AND #b_button   ;check if b press
   BEQ b_exit
   JSR Whatever_B_Does
b_exit:
   LDA joypad1   
   AND #a_button   ;check if a press
   BEQ a_exit
   JSR Whatever_A_Does
a_exit:


;etc, on down the line

(if you want to do something, only on NEW B presses...)

Code:
   LDA joypad1_last_frame
   AND #b_button   ;check if b still held from last frame
   BNE b_exit
   LDA joypad1   
   AND #b_button   ;check if new b press
   BEQ b_exit
   JSR Whatever_B_Does
b_exit:
   ;check some other button now



the AND here does a bit mask...removing all the other buttons from the Accumulator, so that we are only concerned with just that bit. If the result is zero (because the button is not pressed) it will set the z flag, and we can BEQ / BNE away from the subroutine.

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


Last edited by dougeff on Tue Mar 21, 2017 11:21 am, edited 2 times in total.

Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Tue Mar 21, 2017 9:27 am 
Offline

Joined: Mon Jan 30, 2017 5:20 pm
Posts: 262
Location: Colorado USA
What does the AND command do? How would I change DougEFFs example to work with other buttons? I would think that the AND command is a logic command. How do you and a bit? I don't know what that means.


Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Tue Mar 21, 2017 9:29 am 
Online

Joined: Sun Mar 27, 2011 10:49 am
Posts: 153
A bit can be 0 or 1.

0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1

Hopefully it should be obvious why.


Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Tue Mar 21, 2017 9:34 am 
Offline

Joined: Mon Jan 30, 2017 5:20 pm
Posts: 262
Location: Colorado USA
But why is it needed to read controllers?


Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Tue Mar 21, 2017 9:38 am 
Offline

Joined: Mon Jan 30, 2017 5:20 pm
Posts: 262
Location: Colorado USA
And how would I get the other bit? Do you load a memory address and the use "AND other memory location"


Top
 Profile  
 
 Post subject: Re: Corrupt File?
PostPosted: Tue Mar 21, 2017 9:51 am 
Offline

Joined: Mon Jan 30, 2017 5:20 pm
Posts: 262
Location: Colorado USA
I've figured out that the reason I was having a corrupt file was not the ROM, but rather the emulator. I got a corrupt file in Nestopia, but when I loaded it into Fceux, It worked just fine.


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 7 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