It is currently Wed Nov 22, 2017 10:39 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 1386 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6, 7, 8 ... 93  Next
Author Message
 Post subject:
PostPosted: Mon Apr 04, 2011 12:55 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19251
Location: NE Indiana, USA (NTSC)
Most of the time, bad opcode means either A. you forgot the RTS at the end of a subroutine, B. you messed up a bankswitch, or C. you did RTS on a messed-up stack.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 04, 2011 1:10 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 803
Location: cypress, texas
tepples wrote:
Most of the time, bad opcode means either A. you forgot the RTS at the end of a subroutine, B. you messed up a bankswitch, or C. you did RTS on a messed-up stack.

tepples, thanks! :D I guess it was kind of A. I put your code in the middle of a subroutine. So it had the first part of the first subroutine missing an RTS at the end.... like
Code:
[subroutineA...[subroutineB...rts]...rts]
[/quote]


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 07, 2011 11:56 am 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 803
Location: cypress, texas
Code:
      draw_sprite:
        ; t0-t2 are temporary zero page locations holding
        ; the address of a particular sprite layout and the
        ; number of sprites left to draw
        lda sprite_layouts_lo, x
        sta t0
        lda sprite_layouts_hi, x
        sta t0+1
        lda sprite_layouts_count, x
        sta t2
        ldy #0
        ; oamIndex is a variable tracking how far you've written
        ; into shadow OAM (customarily at $0200-$02FF)
        ldx oamIndex
      @loop:
        ; If you have the address of an array in a zero page pointer,
        ; you use the (d),y addressing mode and increase Y to go
        ; to the next byte.
        lda (t0), y
        iny
        ;ect. start
        sta sprite+4;+oamIndex
       
        inx
        inc oamIndex
        ;end ect.       
        dec t2
        bne @loop
        stx oamIndex
        rts
       


This is what I have so far. :oops: My brain doesn't work right now, but I want to make progress. My code always draws the sprite with just one tile; how do i increase the size? I used
Code:
sta sprite+oamIndex
but that didnt help. And also, is that code possible... like for me, it is hard to understand why "sta sprite+aVariable" would work...? Found my assembly textbook from college and read the entire first chapter and going to finish the second chapter by today. It is really fun reading it! :)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 07, 2011 5:36 pm 
Offline
Formerly 65024U

Joined: Sat Mar 27, 2010 12:57 pm
Posts: 2257
Nope, that code isn't possible. You have to store a sprite next to/below in the next sprite address.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 07, 2011 7:24 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 803
Location: cypress, texas
Thank you 3gengames! :D


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 11, 2011 3:45 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 803
Location: cypress, texas
I think I've found the problem... put tepples' code inside the code that runs before the
Code:
cli
.

Inside the NES 101 Tutorial the only code that runs after cli is the endless loop transfering control to the vblank interrupt, i think. Where do you think tepples' code should go? I'm asking beccause my skill with rearanging others' code is very poor; guess i could keep try ing though.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 13, 2011 6:44 am 
Offline

Joined: Sun May 14, 2006 10:26 am
Posts: 48
Location: Norway
The code tepples posted is a subroutine. You can place it wherever you want (of course not in the middle of some other code). Was this what you meant, or do you mean where to place the actual calls (jsr) to the routine?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 14, 2011 8:47 am 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 803
Location: cypress, texas
Jaffe wrote:
The code tepples posted is a subroutine.
Yes, thank you; I agree. :)

Jaffe wrote:
You can place it wherever you want (of course not in the middle of some other code). Was this what you meant, or do you mean where to place the actual calls (jsr) to the routine?
Well, i think i ment both... My first problem was that I placed it in the middle of some other code. I've moved the

Code:
; Background data
bg:
.incbin "charSelect1.nam"
; Attribute table
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00,$F0,$F0,$F0,$F0,$F0,$F0,$F0,$F0
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$0F,$0F,$0F,$0F,$0F,$0F,$0F,$0F
;sprite data
hero_frame1:
.db aY,    $80, $00, aX, aY,    $81, $00, aX+8
.db aY+8,  $90, $00, aX, aY+8,  $91, $00, aX+8
.db aY+16, $a0, $00, aX, aY+16, $a1, $00, aX+8
.db aY+24, $b0, $00, aX, aY+24, $b1, $00, aX+8
hero_frame2:
.db aY,    $80, $00, aX, aY,    $81, $00, aX+8
.db aY+8,  $90, $00, aX, aY+8,  $91, $00, aX+8
.db aY+16, $a0, $00, aX, aY+16, $a1, $00, aX+8
.db aY+24, $b0, $00, aX, aY+24, $b1, $00, aX+8
hero_frame3:
.db aY,    $80, $00, aX, aY,    $81, $00, aX+8
.db aY+8,  $90, $00, aX, aY+8,  $91, $00, aX+8
.db aY+16, $a0, $00, aX, aY+16, $a1, $00, aX+8
.db aY+24, $b0, $00, aX, aY+24, $b1, $00, aX+8
hero_frame4:
.db aY,    $80, $00, aX, aY,    $81, $00, aX+8
.db aY+8,  $90, $00, aX, aY+8,  $91, $00, aX+8
.db aY+16, $a0, $00, aX, aY+16, $a1, $00, aX+8
.db aY+24, $b0, $00, aX, aY+24, $b1, $00, aX+8
;Operator < produces the low byte of an address
sprite_layouts_lo:
.db <hero_frame1, <hero_frame2, <hero_frame3, <hero_frame4
;Operator > produces the high byte of an address
sprite_layouts_hi:
.db >hero_frame1, >hero_frame2, >hero_frame3, >hero_frame4
;Number of hardware sprites in each layout
sprite_layouts_count:
.db 8, 8, 8, 8

that part underneath the background and attribute data code at the end... that was obvious to me; after i did it. :oops: but, it's ok to make a mistake and then learn from that. : )

Jaffe wrote:
...or do you mean where to place the actual calls (jsr) to the routine?
After many ideas and hours of reading I have decided to place the jsr in my vblank code because vblank is the period where you write to the sprite memory, right?

Thank you Jaffe for helping me! :)

This code has not worked for me, yet... now, it draws the first sprite in the correct spot on the screen; but only the first sprite. :? Back to my assembly book.
3
edit: forgot to post my code

Code:
      draw_sprite:
        ...
        ldx oamIndex
      @loop:
        ; If you have the address of an array in a zero page pointer,
        ; you use the (d),y addressing mode and increase Y to go
        ; to the next byte.
        lda (t0), y
        iny

        ;ect. start
        sta sprite, x
        inx
        ;end ect.  THIS IS THE END OF MY CODE.

        dec t2
        bne @loop
        stx oamIndex
        rts


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 14, 2011 4:52 pm 
Offline

Joined: Sun May 14, 2006 10:26 am
Posts: 48
Location: Norway
I have a bit of a hard time getting an overview of your code. Could you post it in its entirety?

The subroutine should not be called during vblank time, at least not before all PPU updates are done. You'll want the subroutine to store sprite data in a page of RAM, and let the contents of this page be copied into OAM by a DMA transfer during vblank (from reading this thread it seems you did this before?) That way you can use all of the non-vblank time to do complex calculations etc. to compute what objects are to be shown in the next frame, where they should be placed, etc. Then when vblank comes, you'll have the sprite data ready to be copied into OAM.

I assume your game has some kind of a main loop that just runs over and over? This is usually where you'd like to place your call to the routine, but that requires that you have some way of controlling how often the loop runs. You could also place it at the end of your vblank code, after you're sure that all code accessing the PPU has run. If you just want to show one object now as a test, you can just as well call it once before your code enters the main infinite loop.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 15, 2011 7:07 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 803
Location: cypress, texas
Jaffe wrote:
I have a bit of a hard time getting an overview of your code. Could you post it in its entirety?


It's not really my code yet; it is really the code of Michael Martin in the NES 101 Tutorial and the code of tepples in his post on page 4, i think, of this thread.

Code:
   ; Transfer control to the VBLANK routines.
loop:   jmp loop

;80 81       
;90 91       
;a0 a1       
;b0 b1   
;        .db aY, $80, $00, aX, aY, $81, $00, aX+8,
;          aY+8, $90, $00, aX, aY+8, $91, $00, aX+8,
;          aY+16, $a0, $00, aX, aY+16, $a1, $00, aX+8,
;         aY+24, $b0, $00, aX, aY+24, $b1, $00, aX+8
              
       
      draw_sprite:
        ; t0-t2 are temporary zero page locations holding
        ; the address of a particular sprite layout and the
        ; number of sprites left to draw
        lda sprite_layouts_lo, x
        sta t0
        lda sprite_layouts_hi, x
        sta t0+1
        lda sprite_layouts_count, x
        sta t2
        ldy #0
        ; oamIndex is a variable tracking how far you've written
        ; into shadow OAM (customarily at $0200-$02FF)
        ldx oamIndex
      @loop:
        ; If you have the address of an array in a zero page pointer,
        ; you use the (d),y addressing mode and increase Y to go
        ; to the next byte.
        lda (t0), y
        iny
        ;ect. start
        sta sprite, x
        inx
        ;end ect.       
        dec t2
        bne @loop
        stx oamIndex
        rts
       
      



Yes, I remember doing that from before in this thread. Right now, my file for vblank looks like:

Code:
jsr scroll_screen
jsr update_sprite
jsr react_to_input
rti

scroll_screen:
        ldx #$00                ; Reset VRAM
        stx $2006
        stx $2006

        ldx scroll                ; Do we need to scroll at all?
        beq no_scroll
        dex
        stx scroll
        lda #$00
        sta $2005                ; Write 0 for Horiz. Scroll value
        stx $2005                ; Write the value of 'scroll' for Vert. Scroll value
               
no_scroll:
        rts
 
update_sprite:
        ldx #3
      jsr draw_sprite
      
      lda #>sprite
        sta $4014 ;OAM_DMA register ; Jam page $200-$2FF into SPR-RAM
                      ;takes 513 cycles.
                
       
react_to_input:
        lda #$01        ; strobe joypad
        sta $4016
        lda #$00
        sta $4016

        lda $4016        ; Is the A button down?
        and #1
      beq @b
      jsr low_c
@b:      lda $4016      ;Is the B button down?
      and #1
      beq not_dn
      jsr high_c
not_dn: rts                                ; Ignore left and right, we don't use 'em

low_c:
        pha
        lda #$84
        sta $4000
        lda #$AA
        sta $4002
        lda #$09
        sta $4003
        pla
        rts

high_c:
        pha
        lda #$86
        sta $4000   ;audio
        lda #$69
        sta $4002
        lda #$08
        sta $4003
        pla
        rts


Jaffe wrote:
That way you can use all of the non-vblank time to do complex calculations etc. to compute what objects are to be shown in the next frame, where they should be placed, etc. Then when vblank comes, you'll have the sprite data ready to be copied into OAM.
So the first thing in vblank should be the copying of page 2 to OAM? And then is it right to do all the updating of page 2 after vblank ends? At vblank we are suspossed to make our changes known to OAM first and writes to page 2 are for between Vblank times. That's what im learning right now, thank you. :)

tokumaru wrote:
The start of VBlank is an important event, so it makes sense to interrupt whatever the PPU is doing so that the full duration of VBlank can be used for VRAM updates.
What is VRAM? :?

Jaffe wrote:
If you just want to show one object now as a test, you can just as well call it once before your code enters the main infinite loop.
Ok, thanks! :) I changed it, but have the poblem again... it's only drawing the first of the 8 sprite object/meta-sprite. It's in the right place though and it's the right sprite.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Apr 15, 2011 10:14 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19251
Location: NE Indiana, USA (NTSC)
Yes, you can update the CPU's copy of OAM outside of vblank. In fact, you're supposed to.

VRAM is any RAM mapped into PPU $0000-$2FFF. It includes CIRAM, the memory inside the NES used for nametables, and CHR RAM, the memory inside the cartridge used for pattern tables. Some cartridges have CHR ROM instead of CHR RAM; for these, the only VRAM is CIRAM.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Apr 16, 2011 7:57 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10118
Location: Rio de Janeiro - Brazil
Are you using the exact code you pasted here? You know it's incomplete, right? The sprite drawing routine is not copying all the bytes it's supposed to from the meta-sprite definitions, and it's not adding the coordinates to the object's coordinates either. That routine was provided as an example, not as something you can copy & paste.

I advise you start writing your own code, or at least read all the code you use very carefully so that you know exactly what it's doing. Making Frankenstein programs (copying blocks of code from different sources) is a terrible way to learn, because you have no idea of what is actually going on in the program and are only hoping that it will somehow work.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 20, 2011 10:52 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 803
Location: cypress, texas
tepples wrote:
Yes, you can update the CPU's copy of OAM outside of vblank. In fact, you're supposed to.
Thank you. :) Would testing the input be ok for during vblank? No, testing the input hasn't anything to do with VRAM... right?

tepples wrote:
VRAM is any RAM mapped into PPU $0000-$2FFF. It includes CIRAM, the memory inside the NES used for nametables, and CHR RAM, the memory inside the cartridge used for pattern tables. Some cartridges have CHR ROM instead of CHR RAM; for these, the only VRAM is CIRAM.
Thanks! :)

tokumaru wrote:
Are you using the exact code you pasted here? You know it's incomplete, right? The sprite drawing routine is not copying all the bytes it's supposed to from the meta-sprite definitions, and it's not adding the coordinates to the object's coordinates either. That routine was provided as an example, not as something you can copy & paste.

I advise you start writing your own code, or at least read all the code you use very carefully so that you know exactly what it's doing. Making Frankenstein programs (copying blocks of code from different sources) is a terrible way to learn, because you have no idea of what is actually going on in the program and are only hoping that it will somehow work.
Yes ok, you are right on all points. Thank you for your help. :) God really helped me with it and so it kind of works now! :D The code... it's able to print out the entire meta-sprite now using tepples' code and my code! Now i'm trying to figure out how to move it with the control pad... and I think maybe calling
Code:
ldx #3
jsr draw_sprite

after each input-check would work... but how should I try this?
Here's code that appplies to this question. :)

Code:
        lda #%00011110
        sta $2001

   ;matthew's init
   
   
   cli
;----------------------------END OF RESET----------------------------------
   ; Transfer control to the VBLANK routines.
           ldx #3
      jsr draw_sprite

loop:   jmp loop

;80 81       
;90 91       
;a0 a1       
;b0 b1   
;        .db aY, $80, $00, aX, aY, $81, $00, aX+8,
;          aY+8, $90, $00, aX, aY+8, $91, $00, aX+8,
;          aY+16, $a0, $00, aX, aY+16, $a1, $00, aX+8,
;         aY+24, $b0, $00, aX, aY+24, $b1, $00, aX+8
              
       
      draw_sprite:
        ; t0-t2 are temporary zero page locations holding
        ; the address of a particular sprite layout and the

Would jsr draw_sprite be ok to include inside of the loop: jmp loop?
Is that the only place I can put it? :? (Because the rest of the file is subroutines and then data.) I'm missing knowlege about a way to organize my code with files. :? I remember reading some post by tokumaru that's about organizing code with different files... will search for that tomorrow. Good night. :)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 21, 2011 9:34 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10118
Location: Rio de Janeiro - Brazil
unregistered wrote:
Would jsr draw_sprite be ok to include inside of the loop: jmp loop?

It depends. There are 3 common ways to organize your frame logic in NES programs in order to make sure it will run 60 times per second (as it should):

1. Put the game logic after VRAM-related operations in your NMI. The NMI routine is automatically called at the start of VBlank, and once the VRAM updates are finished, you are free to do other kinds of operations. Since the NES runs at 60fps, there are 60 VBlanks in a second, so your game logic will also run at 60 Hz. Many commercial games do this, including SMB and Final Fantasy. There are some problems with this method though, which make lag frames (these happen when the frame logic takes longer than a frame to complete) difficult to manage. SMB suffers from this when there are too many enemies on screen (apparently the status bar "jumps" and the music slows down). Most tutorials appear to use this.

Code:
Loop:
   jmp Loop

NMI:
   ;DO PPU UPDATES HERE;

   ;RUN THE GAME LOGIC HERE;

   rti


2. Use the NMI just for signaling the start of VBlank, and both the frame logic and the VRAM-updating in the main thread (the "loop: jmp loop" part). This is very similar to the above, only the order of the updates is different. Here we update the frame logic first and then we wait for VBlank (by checking a flag which is modified by the NMI when VBlank starts) before performing all VRAM updates. This technique suffers from the same lag frame problems. AFAIK, no commercial games did it like this.

Code:
Loop:
   ;RUN THE GAME LOGIC HERE;

   ;WAIT FOR THE NMI;

   ;DO PPU UPDATES HERE;

   jmp Loop

NMI:
   ;INDICATE THE START OF VBLANK;

   rti


3. Separate your main thread from your NMI thread and run them in parallel. This is my favorite, because it allows for safe handling of lag frames. When the NMI fires, it can detect if the frame logic is complete or not, so it's able to detect lag frames and make sura that status bars, the music and other things still work even though the frame logic isn't finished. AFAIK, most commercial games use this.

Code:
Loop:
   ;RUN THE GAME LOGIC HERE;

   ;WAIT FOR THE PPU UPDATES TO COMPLETE;

   jmp Loop

NMI:
   ;DO PPU UPDATES HERE;

   rti


So, to answer your question more directly: If you just place the sprite-drawing call in the main loop without any other modifications, that routine will be called 100's of times in a frame, because there isn't any sort of timing control in there. In your case, the simplest fix would probably be to place that call right after the controller is checked and the player's coordinates are changed. Since it appears you are building this from a tutorial, it would be better to stick to the first solution I explained in this post. Just keep in mind that there are other options, and that you might want to take a look at them once your games become more complex and need more "robust" timing.

Quote:
I remember reading some post by tokumaru that's about organizing code with different files...

How you organize your files doesn't make any difference in the program... Separating files and using includes is something that's supposed to help you keep track of what's where and make your code more easily maintainable, but in the end the assemble still sees all the code as if it were in a single huge file. What matters for NES programs is the order in which things are processed, which doesn't necessarily match the order in which they are written.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 21, 2011 9:55 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19251
Location: NE Indiana, USA (NTSC)
tokumaru wrote:
2. Use the NMI just for signaling the start of VBlank, and both the frame logic and the VRAM-updating in the main thread (the "loop: jmp loop" part). [...] AFAIK, no commercial games did it like this.

Don't Squaresoft games such as Final Fantasy do it this way?

I'll have to see if Nintendulator and NESICIDE can measure /NMI-to-RTI time.


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

All times are UTC - 7 hours


Who is online

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