Corrupt File?

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: Corrupt File?

Post by dougeff »

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
DementedPurple
Posts: 318
Joined: Mon Jan 30, 2017 5:20 pm
Location: Colorado USA

Re: Corrupt File?

Post by DementedPurple »

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?
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Corrupt File?

Post by tepples »

Bit shifts are used here to combine multiple reads from a serial port into one byte.
User avatar
dustmop
Posts: 136
Joined: Wed Oct 16, 2013 7:55 am

Re: Corrupt File?

Post by dustmop »

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.
DementedPurple
Posts: 318
Joined: Mon Jan 30, 2017 5:20 pm
Location: Colorado USA

Re: Corrupt File?

Post by DementedPurple »

Okay, I understand bit shifting. what about pushing and pulling from the stack? Why do we need that in reading the controllers?
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Corrupt File?

Post by tepples »

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.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Corrupt File?

Post by tokumaru »

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.
Pokun
Posts: 2681
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Corrupt File?

Post by Pokun »

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: Select all

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: Select all

  .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.
DementedPurple
Posts: 318
Joined: Mon Jan 30, 2017 5:20 pm
Location: Colorado USA

Re: Corrupt File?

Post by DementedPurple »

With dougeffs example, how would I jump to a certain location when a button is pressed?
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: Corrupt File?

Post by dougeff »

I do something like this...

Code: Select all

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: Select all

	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: Select all

	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: Select all

	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.
Last edited by dougeff on Tue Mar 21, 2017 11:21 am, edited 2 times in total.
nesdoug.com -- blog/tutorial on programming for the NES
DementedPurple
Posts: 318
Joined: Mon Jan 30, 2017 5:20 pm
Location: Colorado USA

Re: Corrupt File?

Post by DementedPurple »

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.
adam_smasher
Posts: 271
Joined: Sun Mar 27, 2011 10:49 am
Location: Victoria, BC

Re: Corrupt File?

Post by adam_smasher »

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.
DementedPurple
Posts: 318
Joined: Mon Jan 30, 2017 5:20 pm
Location: Colorado USA

Re: Corrupt File?

Post by DementedPurple »

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

Re: Corrupt File?

Post by DementedPurple »

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

Re: Corrupt File?

Post by DementedPurple »

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.
Post Reply