It is currently Thu Oct 19, 2017 12:24 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 55 posts ]  Go to page Previous  1, 2, 3, 4  Next
Author Message
PostPosted: Wed Dec 30, 2015 1:50 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19099
Location: NE Indiana, USA (NTSC)
Friendly_Noob wrote:
GetInput2 is a loop checking $4016 8 times, because there are 8 buttons. Then depending on if the button is pressed or not 00000000 or 00000001 is ANDed with 00000011 ($03) so it's 00000000 or 00000001 again?

When you read controller port $4016 or $4017, bit 0 represents whether a button is pressed on the plug-in controller (NES) or hardwired controller (Famicom), bit 1 represents whether the corresponding button is pressed on the expansion controller (Famicom), and bits 7-2 are unrelated to button presses. A 4-player game for Famicom will treat bit 0 and bit 1 separately by shifting each into carry (lsr a) and then shifting it out into that player's variable:
Code:
lda $4016
lsr a
rol player1_buttons
lsr a
rol player2_buttons


But for a 1- or 2-player game, you usually want to have each button on the Famicom expansion controller do the same thing as the corresponding button on the hardwired controller.

Quote:
Also, why should I store oldbutton?

To detect the difference between pressing a button and holding a button:
Code:
lda oldbutton  ; A = buttons pressed last frame
eor #$FF       ; A = buttons NOT pressed last frame
and button     ; A = buttons pressed this frame but not last frame
sta newbutton


Here's another tip: If you prefill button with $01, you don't need to use Y as the loop counter. Carry after rotating a bit into place will be clear until the 1 bit gets rotated out, and you can use this change in carry to detect the end of the loop. The code used in my games is similar to the last snippet on Gamepad code, reproduced here:
Code:
JOYPAD1 = $4016
JOYPAD2 = $4017

.zeropage
buttons1: .res 1
buttons2: .res 1

.code
readjoy:
  lda #$01
  sta JOYPAD1
  sta buttons2  ; player 2's buttons double as a ring counter
  lsr a         ; now A is 0
  sta JOYPAD1
@loop:
  lda JOYPAD1
  and #$03      ; ignore bits other than controller
  cmp #$01      ; Set carry if and only if nonzero
  rol buttons1  ; Carry -> bit0; bit 7 -> Carry
  lda JOYPAD2   ; Repeat
  and #$03
  cmp #$01
  rol buttons2  ; Carry -> bit0; bit 7 -> Carry
  bcc @loop     ; Loop is done when the last bit of $01 is shifted out
  rts


Top
 Profile  
 
PostPosted: Wed Dec 30, 2015 2:24 pm 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10057
Location: Rio de Janeiro - Brazil
Friendly_Noob wrote:
Also, why should I store oldbutton?

Like memblers and tepples said, so that you can compare the new buttons against the old ones and tell which ones have been pressed or released since last time. Some actions, such as jumping, shooting, or moving a cursor, are normally only triggered when the button is pressed, not when it's held down. Moving left and right, on the other hand, normally happens when the respective buttons are held down. Since there are these two types of actions, its customary for games to keep one variable containing the bits directly read from the controller, and another containing only the new buttons.


Top
 Profile  
 
PostPosted: Fri Nov 25, 2016 1:25 am 
Offline

Joined: Mon Dec 14, 2015 2:58 am
Posts: 20
Here's my question after almost a year of absence. In this loop I don't want to mess with any of the sprite's attributes like position on the screen, it's just to
store tile numbers in the right places to form a 16x16 metasprite. How do I make a loop that stores a value every 4 memory locations? I did something like this, but 4xINY doesn't seem to be a smart solution.
Code:
sprite1: .db $00,$00,$10,$11


Code:
LoadFrame:
  LDX #$00
  LDY #$00
LoadFrameLoop:
  LDA sprite1, x
  STA $201, y
  INX
  INY
  INY
  INY
  INY
  CPX #$04
  BNE LoadFrameLoop


Top
 Profile  
 
PostPosted: Fri Nov 25, 2016 2:01 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5718
Location: Canada
A small burst of INX or INY instructions is a common thing to do on the 6502. 3 or 4 in a row is usually better than something like TYA / CLC / ADC #4 / TAY.

If speed is more important than size you can also unroll the loop:
Code:
; original:
;   15 bytes
;   (3 * 24) + 23 = 95 cycles
:
   lda sprite1, x
   sta $201, y
   inx
   iny
   iny
   iny
   iny
   cpx #4
   bne :-

; unrolled loop:
;   6 * 4 = 24 bytes
;   4 * 9 = 36 cycles
.repeat 4, I
   lda sprite1+I
   sta $201+(i*4), y
.endrepeat


Top
 Profile  
 
PostPosted: Fri Nov 25, 2016 2:09 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
I wouldn't bother with a loop in this case, assuming you have the extra space for the code (it's not much), and the cycle savings are worth it (factor of about 3, I'd think). All the addresses are calculable at assemble-time, so I'd just do this:

Code:
sprite1: .db $00,$00,$10,$11

LoadFrame:
  lda sprite1
  sta $0201
  lda sprite1+1
  sta $0201+4
  lda sprite1+2
  sta $0201+8
  lda sprite1+3
  sta $0201+12

If you need this code to be a bit more dynamic, such as handling multiple entries (e.g. sprite2, sprite3, etc.) then the situation becomes a bit more complicated but not too bad. Use a combination of a 16-bit pointer in ZP and indirect indexed addressing:

Code:
spriteptr = $00               ; Change this to whatever ZP location is available: your problem not mine! :P

sprite1: .db $00,$00,$10,$11
sprite2: .db $20,$20,$30,$31  ; I just made up this data
sprite3: .db $40,$40,$50,$51  ; I just made up this data

  lda #.LOBYTE(sprite2)
  sta spriteptr
  lda #.HIBYTE(sprite2)
  sta spriteptr+1
  jsr LoadFrame
  ...
  ...

LoadFrame:
  ldy #0
  lda (spriteptr),y
  sta $0201
  iny
  lda (spriteptr),y
  sta $0201+4
  iny
  lda (spriteptr),y
  sta $0201+8
  iny
  lda (spriteptr),y
  sta $0201+12
  rts

You get the idea, I hope.

Edit: rainwarrior beat me to it using a .repeat loop that unrolls the existing loop + keeps the use of Y indexing. Also, sorry for all the edits -- it's post-US-Thanksgiving and I'm in a kind of "OMG I ate too much, gonna burst" state where my brain is all over the place (what else is new).


Top
 Profile  
 
PostPosted: Sat Nov 26, 2016 4:18 am 
Offline

Joined: Mon Dec 14, 2015 2:58 am
Posts: 20
Does .repeat work on NESASM3? Maybe it's time to move to ca65.


Top
 Profile  
 
PostPosted: Sat Nov 26, 2016 5:05 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
Friendly_Noob wrote:
Does .repeat work on NESASM3? Maybe it's time to move to ca65.

nesasm 3.x assembler directives are fully documented (any user of an assembler should refer to and read their assembler documentation as needed ;-) ). The short answer is no it doesn't, but it does support macros, so you could "repeat generation of code" very easily with a macro + repeated use of the macro.

I really don't think something like .repeat is reason to change assemblers, but that's my own opinion. And if you *had* to switch assemblers for simple projects, asm6 might be a better choice (the directive there is REPT/ENDR; here's a random copy of the documentation), as there isn't as much setup/complication involved compared to ca65/ld65.


Top
 Profile  
 
PostPosted: Sat Nov 26, 2016 10:39 am 
Offline

Joined: Wed Jul 30, 2008 12:03 am
Posts: 32
or something in between
use an LUT

Code:
 ldx #03
loop
 ldy ytable,x
 lda sprite1,x
 sta $201,y
 dex
 bpl loop

ytable
 $00
 $04
 $08
 $0C


Top
 Profile  
 
PostPosted: Sat Nov 26, 2016 12:27 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5718
Location: Canada
koitsu wrote:
Friendly_Noob wrote:
Does .repeat work on NESASM3? Maybe it's time to move to ca65.

I really don't think something like .repeat is reason to change assemblers, but that's my own opinion.

I think NESASM silently failing to generate valid code when you overflow a bank is a good reason to change assemblers. :P The repeat directive is just one of a hundred advantages.


Top
 Profile  
 
PostPosted: Sat Nov 26, 2016 6:54 pm 
Offline

Joined: Thu Aug 28, 2008 1:17 am
Posts: 591
rainwarrior wrote:
koitsu wrote:
Friendly_Noob wrote:
Does .repeat work on NESASM3? Maybe it's time to move to ca65.

I really don't think something like .repeat is reason to change assemblers, but that's my own opinion.

I think NESASM silently failing to generate valid code when you overflow a bank is a good reason to change assemblers. :P The repeat directive is just one of a hundred advantages.

Failing to generate code or failing to provide a warning? Was this not fixed with updated versions of nesasm? If not, why not? The source is pretty easy to modify (I added some stuff at one point).

_________________
__________________________
http://pcedev.wordpress.com


Top
 Profile  
 
PostPosted: Sat Nov 26, 2016 8:47 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19099
Location: NE Indiana, USA (NTSC)
"Silently" implied lack of a warning to me. Which forks fix this?


Top
 Profile  
 
PostPosted: Sun Dec 04, 2016 12:39 pm 
Offline

Joined: Mon Dec 14, 2015 2:58 am
Posts: 20
That's my loop after moving to ASM6. For some reason all the sprites loaded are tiles $00, or $00, $00, $00, $11 when I put INY in a different place (after STA $201 + i for example)
Code:
LoadYacaFrontFrame1:
  LDA  #%01000000
  STA  $206
  LDA  #%00000000
  STA  $202
  STA  $20A
  STA  $20E
  LDY  #$00
  i=0
  REPT 4
  LDA yacafront1, y
  STA $201 + i
  DB i
  i=i+4
  INY
  ENDR
  RTS

yacafront1:
  .db $00,$00,$10,$11


Top
 Profile  
 
PostPosted: Sun Dec 04, 2016 1:12 pm 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10057
Location: Rio de Janeiro - Brazil
Why do you have a DB in the middle of your code? The CPU will try to execute those bytes as if they were instructions, and things will very likely derail from there.


Top
 Profile  
 
PostPosted: Sun Dec 04, 2016 1:24 pm 
Offline

Joined: Mon Dec 14, 2015 2:58 am
Posts: 20
It's not in the actual code, I just wanted you to know how yacafront1 looks like.


Top
 Profile  
 
PostPosted: Sun Dec 04, 2016 6:03 pm 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10057
Location: Rio de Janeiro - Brazil
Not that, I'm taking about the DB i inside the REPT block. You're inserting bytes $00, $04, $08 and $0c in the middle of the program, that the CPU will try to execute.


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 6 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