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
dustmop
Posts: 136
Joined: Wed Oct 16, 2013 7:55 am

Re: Corrupt File?

Post by dustmop » Tue Mar 21, 2017 9:58 am

As mentioned earlier, shifts are used to combine what the hardware gives you (a single bit per read) into one byte. This byte represents the entire controller state, using a single bit for each button on the controller (conveniently, the NES controller has 8 buttons).

Shown below are typically the values for each button (depending upon how controller reading is performed, they may be backwards if reading is done in reverse):

Code: Select all

RIGHT_BUTTON = $01
LEFT_BUTTON = $02
DOWN_BUTTON = $04
UP_BUTTON = $08
START_BUTTON = $10
SELECT_BUTTON = $20
B_BUTTON = $40
A_BUTTON = $80
As an example, here's what happens if the player is holding LEFT, START, A and B:

Code: Select all

%1101_0010 = $d2
 || |   |
 || |   +-------- LEFT_BUTTON = $02
 || +------------ START_BUTTON = $10
 |+-------------- B_BUTTON = $40
 +--------------- A_BUTTON = $80
Using AND is a way to strip out a single bit at a time, to see if the corresponding button is currently being pressed.

For the previous example, here's what happens when that value is AND'd with the value for RIGHT_BUTTON, which is not currently being pressed:

Code: Select all

%1101_0010 = $d2
   AND
%0000_0001 = $01 (RIGHT_BUTTON)
----------
%0000_0000
The result is zero, because RIGHT is not being pressed. If instead, the value was AND'd with the value for B_BUTTON:

Code: Select all

%1101_0010 = $d2
   AND
%0100_0000 = $40 (B_BUTTON)
----------
%0100_0000
The result is $40, which is non-zero, because B *is* being pressed.

Whether the result is zero or non-zero is useful, because then we can use BEQ or BNE to jump to another piece of code.

User avatar
tokumaru
Posts: 11711
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Corrupt File?

Post by tokumaru » Tue Mar 21, 2017 10:00 am

Maybe it'll help if I rewrite this part:

Code: Select all

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

Code: Select all

;A, B, Select, Start, Up, Down, Left, Right
right = %00000001
left = %00000010
down = %00000100
up = %00001000
start = %00010000
select = %00100000
a_button = %01000000
b_button = %10000000
Looking at these numbers in binary, you can clearly see that they are masks used to isolate individual bits in a byte. By ANDing them with the byte that contains the states of all buttons you can isolate any bit you're interested in checking. AND is a bitwise operation that only results in 1 if both bits are 1, so the result will be 0 when the button is not pressed, and not 0 when it's pressed.
DementedPurple wrote: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.
Errr... Nestopia is not crazy, if it says your file is corrupted, your file is not a valid NES ROM. FCEUX might be doing something behind the scenes to make it work, but this is something you should definitely be looking into. What's the exact byte size of the file?

adam_smasher
Posts: 271
Joined: Sun Mar 27, 2011 10:49 am
Location: Seattle

Re: Corrupt File?

Post by adam_smasher » Tue Mar 21, 2017 10:41 am

DementedPurple wrote:And how would I get the other bit? Do you load a memory address and the use "AND other memory location"
Yes, this. Operations on the 6502 generally use what's in the accumulator as an implicit argument and as the implicit destination. So, for example, AND #$10 will perform a bitwise AND with whatever is in the accumulator and the constant number $10 (that's 10 in hexadecimal, a.k.a. 16 in decimal) and finally put the result in the accumulator. By "bitwise", I mean the rightmost bit of the accumulator will get AND'd with the rightmost bit of the number $10 to form the rightmost bit of the result.

User avatar
dougeff
Posts: 2691
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: Corrupt File?

Post by dougeff » Tue Mar 21, 2017 11:16 am

Oh crap, did I get the button order wrong?

It should be...
b_button = %01000000 = $40
a_button = %10000000 = $80

Not...
a_button = %01000000
b_button = %10000000

Right?

Dustmop corrected me, tokumaru copied incorrectly from me.
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 » Tue Mar 21, 2017 11:45 am

Okay, I think I get it, it's a way to see if two buttons are pressed. But I have one final question. How come when I run FARIDS edited code, I get a screen filled with the first sprite. I knew I would see the first sprite, but I expected to only see it in the middle of the screen. Is it a bug?

User avatar
dustmop
Posts: 136
Joined: Wed Oct 16, 2013 7:55 am

Re: Corrupt File?

Post by dustmop » Tue Mar 21, 2017 11:56 am

There's no way to know what's wrong with your modified code unless you post code. i, personally, am not psychic.

DementedPurple
Posts: 318
Joined: Mon Jan 30, 2017 5:20 pm
Location: Colorado USA

Re: Corrupt File?

Post by DementedPurple » Tue Mar 21, 2017 12:00 pm

This is the glitched code

Code: Select all

There were a lot of mistakes in your code, I fixed some of them in a way that it works as you want :

Code:
;----------------------------------------------------------------
; constants
;----------------------------------------------------------------

PRG_COUNT = 1 ;1 = 16KB, 2 = 32KB
MIRRORING = %0001 ;%0000 = horizontal, %0001 = vertical, %1000 = four-screen

;----------------------------------------------------------------
; variables
;----------------------------------------------------------------

   .enum $0000

   ;NOTE: declare variables using the DSB and DSW directives, like this:

   ;MyVariable0 .dsb 1
   ;MyVariable1 .dsb 3

   .ende

   ;NOTE: you can also split the variable declarations into individual pages, like this:

   ;.enum $0100
   ;.ende

   ;.enum $0200
   ;.ende

;----------------------------------------------------------------
; iNES header
;----------------------------------------------------------------

   .db "NES", $1a ;identification of the iNES header
   .db $01 ;number of 16KB PRG-ROM pages
   .db $01 ;number of 8KB CHR-ROM pages
   .db $00|$01 ;mapper 0 and mirroring
   .dsb 9, $00 ;clear the remaining bytes

;----------------------------------------------------------------
; program bank(s)
;----------------------------------------------------------------

   .base $10000-(PRG_COUNT*$4000)

Reset:
   LDA #$3F
   STA $2006
   LDA #$00
   STA $2006

LDA #$3F
STA $2007
LDA #$30
STA $2007
LDA #$3F
STA $2007
LDA #$3F
STA $2007

LDY #%10001001
STY $2000
LDX #%00011110
STX $2001

LDX #128
STX $0000
STX $0001

Wait:

LDA #1
STA $4016
LDA #0
STA $4016

;Check A
   LDA $4016

;Check B
   LDA $4016

;Check Select
   LDA $4016

;Check Start
   LDA $4016

;Check Up
   LDA $4016
   AND #%00000001
   CMP #%00000001
   BEQ UP

;Check Down
   LDA $4016
   AND #%00000001
   CMP #%00000001
   BEQ DOWN

;Check Left
   LDA $4016
   AND #%00000001
   CMP #%00000001
   BEQ LEFT

;Check Right
   LDA $4016
   AND #%00000001
   CMP #%00000001
   BEQ RIGHT
JMP Wait

UP:
LDX $0001
INX
STX $0001
JMP Wait
DOWN:
LDX $0001
DEX
STX $0001
JMP Wait
LEFT:
LDX $0000
DEX
STX $0000
JMP Wait
RIGHT:
LDY $0000
INY
STY $0000
JMP Wait

NMI:

   LDY #$00
   STY $2003

   LDY $0001
   STY $2004
   LDY #0
   STY $2004
   STY $2004
   LDY $0000
   STY $2004

RTI
   
IRQ:

   ;NOTE: IRQ code goes here
RTI
;----------------------------------------------------------------
; interrupt vectors
;----------------------------------------------------------------

   .org $fffa

   .dw NMI
   .dw Reset
   .dw IRQ

;----------------------------------------------------------------
; CHR-ROM bank
;----------------------------------------------------------------

   .incbin "Graphics.chr"

User avatar
tokumaru
Posts: 11711
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Corrupt File?

Post by tokumaru » Tue Mar 21, 2017 12:17 pm

You never initialized the name tables, so if an emulator initializes them with zeroes you're gonna get the first tile repeated over and over. If you want a blank background you have to include a blank tile in your tileset and write the index of that tile to the entire name table being displayed. Never count on anything being initialized automatically, always clear everything yourself. And please, add the PPU warm up loop in your reset code before using the PPU.

DementedPurple
Posts: 318
Joined: Mon Jan 30, 2017 5:20 pm
Location: Colorado USA

Re: Corrupt File?

Post by DementedPurple » Tue Mar 21, 2017 12:45 pm

Another question. Can you use multiple AND commands like this:

Code: Select all

LDA Controller
CMP #1
AND #2
AND #4
BEQ Example

User avatar
tokumaru
Posts: 11711
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Corrupt File?

Post by tokumaru » Tue Mar 21, 2017 12:52 pm

You can, but each AND will act upon the result of the previous operation, which is probably not what you want. If you want to use multiple masks at once you can do this:

Code: Select all

AND #(1|2|4)
The symbol "|" performs a bitwise OR during assembly, to combine the separate masks into one.

For example, if you want to both START and A to perform the same action, such as start a game, you can do something like this:

Code: Select all

LDA PressedButtons
AND #(MASK_START|MASK_A)
BNE StartGame

User avatar
FARID
Posts: 489
Joined: Wed Apr 07, 2010 1:14 am
Location: Iran
Contact:

Re: Corrupt File?

Post by FARID » Tue Mar 21, 2017 11:59 pm

DementedPurple wrote:Another question. Can you use multiple AND commands like this:

Code: Select all

LDA Controller
CMP #1
AND #2
AND #4
BEQ Example
No that will not work as you want.
You must read joypad port ($4016) eight times, in order to find out the status of all buttons.
With each read of $4016 the state of only one button is revealed in this order : A B Select Start Up Down Left Right
When you read $4016 a value is loaded into reg A, right?
That value is in this format : #%xxxxxxxj
But the only bit related to joypad buttons is bit0 (j)
bit0 can have two possible values : it can be either 0 or 1, right?
If it is 0 then it shows that the button was not pressed.
If it is 1 then it shows that the button was pressed.
So we have to separate bit0 from other bits (bit1 ~ bit7), because other bits are related to other things which we don't care, they can be any random value
That is why we have to use AND opcode
We AND reg A value with #%00000001, so all of the bits from bit1 ~ bit7 are set to 0, but bit0 keeps it's own value (it means if it was 0 it will be 0, if it was 1 it will be 1)
Then we can use CMP opcode to check the value of bit0 and do the desired action according to it's state

Analyze this to find out what is going on :

Code: Select all

;Check A:
LDA Controller
AND #%00000001
CMP #%00000000
BEQ A_was_not_pressed
CMP #%00000001
BEQ A_was_pressed

;Check B:
LDA Controller
AND #%00000001
CMP #%00000000
BEQ B_was_not_pressed
CMP #%00000001
BEQ B_was_pressed

.
.
.

;Check Right:
LDA Controller
AND #%00000001
CMP #%00000000
BEQ Right_was_not_pressed
CMP #%00000001
BEQ Right_was_pressed
Once you understand what is going on you can use more optimized codes to read joypad

unregistered
Posts: 1071
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: Corrupt File?

Post by unregistered » Thu Mar 23, 2017 10:17 am

After creating this line in my input asm file my easiness with the button byte increased dramaticly! :) :mrgreen: Hope it can help you too. :)

Code: Select all

;abetudlr
Since select and start both begin with 's' I chose the second letter of both of them... that way there are 8 different letters each representing its bit! :mrgreen:

User avatar
tokumaru
Posts: 11711
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Corrupt File?

Post by tokumaru » Thu Mar 23, 2017 10:21 am

But you don't need to remember the bit order at all if you simply define 8 symbols to use as masks.

unregistered
Posts: 1071
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: Corrupt File?

Post by unregistered » Thu Mar 23, 2017 10:38 am

tokumaru wrote:But you don't need to remember the bit order at all if you simply define 8 symbols to use as masks.
But it really helps me because I can open the trace file (created by FCEUX 2.2.2) with notepad and find "A:41 X:08" and it instantly goes to the first time I pressed a. It's very easy to check controller usage that way! :) :mrgreen:

edit: I'll make that easier to understand later today. : )

unregistered
Posts: 1071
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Re: Corrupt File?

Post by unregistered » Thu Mar 23, 2017 9:51 pm

unregistered wrote:
tokumaru wrote:But you don't need to remember the bit order at all if you simply define 8 symbols to use as masks.
But it really helps me because I can open the trace file (created by FCEUX 2.2.2) with notepad and find "A:41 X:08" and it instantly goes to the first time I pressed a. It's very easy to check controller usage that way! :) :mrgreen:

edit: I'll make that easier to understand later today. : )
So in our read controller routine is a loop somewhat like this:

Code: Select all

ldx #08
-loop lda $4016
      and #03
      Cmp #01
      rol currentControllerButtons
      Dex
      BNE -loop     
That's its heart. I think I found something like that in Michael Martin's NES 101 Tutorial. Anyways, when making a trace log file in FCEUX 2.2.2. ...the Trace Logger screen appears and I have checked
* Log state of registers
* Log Frames count
* Log emulator messages
* Log Processor status flags
* Log breakpoint hits
* Use Stack Pointer for code tabbing (nesting visualization)
* To the left from disassembly
I click Log to File. Then reset your game because that causes it to start at frame 0. A frame is one cycle through vblank interrupt (NMI) and after the rti it loops once through my main loop. Then it waits for the next vblank to start. Frame 0 ends, frame 1 begins, the i flag is set and frame 1's vblank begins. Causing it to start at 0 decreases the file size.

Move to point in your game where you want to start logging... have to go to sleep will finish tomorrow night.

Post Reply