Jump to content

Photo

Just started with assembly programming, Playfield generation difficulties

programming debug help atari 2600 newbie Playfields tutorial Bytes

5 replies to this topic

#1 George Washingtoad OFFLINE  

George Washingtoad

    Star Raider

  • 51 posts
  • Location:North Carolina

Posted Mon Feb 11, 2019 7:47 PM

Hey there everyone, I just started learning to program the Atari 2600 in Assembly recently and I think that I have learned a great deal. However, I seem to have hit a road block. Initially, when I first started programming playfields and backgrounds, I plugged the values in line by line like this:

.fctbNone{ color:#e0e0e0; }
.fctbStyle0{ color:#adff2f;font-style:oblique; }
.fctbStyle3{ color:#ffd700; }
.fctbStyle5{ color:#ee82ee; }
.fctbStyle4{ color:#00bfff; }
.fctbStyle2{ color:#ffa500; }
.fctbStyle1{ color:#00ffff;font-weight:bold; }
.fctbStyle1Style3{ color:#00ffff;font-weight:bold; }
.fctbStyle2Style3{ color:#ffa500; }
.fctbStyle6{ color:#ff6347; }
.fctbStyle0Style6{ color:#adff2f;font-style:oblique; }; < GAME TITLE >
; < AUTOR >

    processor 6502
    include "vcs.h"
    include "macro.h"
        
;---------- LABELS ----------
;----------------------------

    SEG
    ORG $F000

Reset


; Initialize TIA/RAM
; ------------------
                LDX #0
                LDA #0
                    
Clear           STA 0,X
                INX
                BNE Clear
        
        
; Initialize Labels
; -----------------
 COMPILE_VERSION = NTSC
 NTSC =#1
    LDA #%00000001
     STA $82
     LDA #$BC
     STA COLUPF
     LDA $82
     STA CTRLPF
                        
        
; Start Game
; ----------
StartOfFrame    LDA #0
                STA VBLANK

                LDA #2
                STA VSYNC

                ; VSYNC Signal
                STA WSYNC
                STA WSYNC
                STA WSYNC

                LDA #0
                STA VSYNC           

                ; Vertical Blank
                LDX #0
                
VerticalBlank   STA WSYNC
                INX
                CPX #37
                BNE VerticalBlank

                ; Scanlines
                LDX #0
IDIOT 
                    INX
                    LDA #$C4
                    STA COLUBK
                    STA WSYNC
                    CPX #40
                    BNE IDIOT
                    
                          LDA #$C4
                    STA COLUPF
                    LDA #$0
                    STA COLUBK 
                    LDA #%11111111
                    STA PF0
                    STA PF1
                    LDA #%10111111
                    STA PF2
                    
MORAL 
                    INX
                    LDA #$CA
 STA COLUBK
                    STA WSYNC
                    CPX #42
                    BNE MORAL
                    
                    LDA #%11100000
                    STA PF0
                    LDA #%11001111
                    STA PF1
                    LDA #%00011111
                    STA PF2
CORAL 
                    INX
                    LDA #$CA
 STA COLUBK
                    STA WSYNC
                    CPX #44
                    BNE CORAL   
                    
                    LDA #%11000000
                    STA PF0
                    LDA #%10000111
                    STA PF1
                    LDA #%00001111
                    STA PF2
NORAL 
                    INX
                    LDA #$CA
 STA COLUBK
                    STA WSYNC
                    CPX #46
                    BNE NORAL  
 
                    LDA #%10000000
                    STA PF0
                    LDA #%00000011
                    STA PF1
                    LDA #%00000111
                    STA PF2
STEVE 
                    INX
                    LDA #$CA
 STA COLUBK
                    STA WSYNC
                    CPX #48
                    BNE STEVE  
 
                    LDA #%00000000
                    STA PF0
                    LDA #%00000001
                    STA PF1
                    LDA #%00000011
                    STA PF2
PTEVE 
                    INX
                    LDA #$CA
 STA COLUBK
                    STA WSYNC
                    CPX #50
                    BNE PTEVE    
  
               
                    
                    LDA #0
                    STA PF0
                    STA PF1
                    STA PF2
BIGB                
 INX
 LDA #$CA
 STA COLUBK

 STA WSYNC
 CPX #110       
 BNE BIGB
 
BIGBB                
 INX
 LDA #$2E
 STA COLUBK

 STA WSYNC
 CPX #130       
 BNE BIGBB 

BIGBBB                
 INX
 LDA #$2C
 STA COLUBK

 STA WSYNC
 CPX #150       
 BNE BIGBBB 
                    
                    
FED                
 INX
 LDA #$0
 STA COLUBK

 STA WSYNC
 CPX #192       
    BNE FED
                    

EndScreen       LDA #%01000010
                STA VBLANK

                ; Overscan
                LDX #0

Overscan        STA WSYNC
                INX
                CPX #30
                BNE Overscan

                ; Next Frame
                ; ----------
                JMP StartOfFrame

                ORG $FFFA
                .word Reset
                .word Reset
                .word Reset

            END

Thanks all!

 

But while I was continuing in the tutorials, I found that my original methodology isnt really going to work (or will it? please let me know!) especially working with a great deal of sprites and backgrounds. So,  I have found that most people tend to do play fields more like this:

.fctbNone{ color:#e0e0e0; }
.fctbStyle0{ color:#adff2f;font-style:oblique; }
.fctbStyle3{ color:#ffd700; }
.fctbStyle5{ color:#ee82ee; }
.fctbStyle4{ color:#00bfff; }
.fctbStyle2{ color:#ffa500; }
.fctbStyle1{ color:#00ffff;font-weight:bold; }
.fctbStyle1Style3{ color:#00ffff;font-weight:bold; }
.fctbStyle2Style3{ color:#ffa500; }
.fctbStyle6{ color:#ff6347; }
.fctbStyle0Style6{ color:#adff2f;font-style:oblique; }; < GAME TITLE >
; < AUTOR >

    processor 6502
    include "vcs.h"
    include "macro.h"
        
;---------- LABELS ----------
;----------------------------

    SEG
    ORG $F000

Reset


; Initialize TIA/RAM
; ------------------
                LDX #0
                LDA #0
                    
Clear           STA 0,X
                INX
                BNE Clear
        
        
; Initialize Labels
; -----------------
 COMPILE_VERSION = NTSC
 NTSC =#1
    LDA #%00000001
     STA $82
     LDA #$BC
     STA COLUPF
     LDA $82
     STA CTRLPF
                        
PFG0
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
PFG1
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
PFG2
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
 .byte %10101010
; Start Game
; ----------
StartOfFrame    LDA #0
                STA VBLANK

                LDA #2
                STA VSYNC

                ; VSYNC Signal
                STA WSYNC
                STA WSYNC
                STA WSYNC

                LDA #0
                STA VSYNC           

                ; Vertical Blank
                LDX #0
                
VerticalBlank   STA WSYNC
                INX
                CPX #37
                BNE VerticalBlank

                ; Scanlines
                LDX #0

                    
;THIS AREA IS ENCLOSED FOR THE PASTEING
LDY #0
Woah
 LDA PFG0,X
 STA PF0
 LDA PFG1,X
 STA PF1
 LDA PFG2,X
 STA PF2
 INX

 STA WSYNC
 cpx #190
 bne Woah
;FINISH AREA
                    
                    
                    LDA %00000000
                    STA PF0
                    STA PF1
                    STA PF2
FED                
 INX
 LDA #$0
 STA COLUBK

 STA WSYNC
 CPX #192       
    BNE FED
                    

EndScreen       LDA #%01000010
                STA VBLANK

                ; Overscan
                LDX #0

Overscan        STA WSYNC
                INX
                CPX #30
                BNE Overscan

                ; Next Frame
                ; ----------
                JMP StartOfFrame

                ORG $FFFA
                .word Reset
                .word Reset
                .word Reset

            END

So once I tested this I found that I only got some of the playfield filled, the other parts are random. why is this? Can it be fixed?

 

  



#2 George Washingtoad OFFLINE  

George Washingtoad

    Star Raider

  • Topic Starter
  • 51 posts
  • Location:North Carolina

Posted Mon Feb 11, 2019 7:48 PM

Disregard the parts on the top about the different colors, thats just from my IDE.



#3 JeffJetton OFFLINE  

JeffJetton

    Space Invader

  • 22 posts
  • Location:Nashville, TN

Posted Tue Feb 12, 2019 2:35 PM

Hi George,

 

Your set of data for PFG0 is only 48 bytes long. PFG1 and PFG2 are both 49 bytes. Your X register, on the other hand, is holding values ranging from 0 to 190. Since you're using X as an offset to the base address of each of your sets of playfield data, it eventually "overshoots the runway", causing your LDA to start loading the values of your actual program instructions and using those values to set the playfield.

 

For example, once X reaches 49 (beyond the end of your PFG0 data), the LDA PFG0,X instruction actually loads A with the first byte of PFG1. When X gets to 98, it moves beyond PFG1 and reads the first byte of PFG2. And by the time X hits 147, you're now loading in the value of that LDA that comes after your data, at the "StartOfFrame" label. (It happens to have a value of $A9, by the way).

 

Of course, your LDA PFG1,X and LDA PFG2,X instructions are doing the same thing, only they start farther down in your data and therefore wind up reading more of your program instructions.

 

If you used each byte of playfield data for four consecutive scanlines, that would fix your problem.

Woah

 LDA PFG0,X
 STA PF0
 LDA PFG1,X
 STA PF1
 LDA PFG2,X
 STA PF2
 INX

 STA WSYNC
 STA WSYNC
 STA WSYNC
 STA WSYNC
 cpx #47
 bne Woah

;FINISH AREA
                    
                    
                    LDA %00000000
                    STA PF0
                    STA PF1
                    STA PF2
FED                
 INX
 LDA #$0
 STA COLUBK

 STA WSYNC
 CPX #48
 BNE FED       

Alternatively, you could store your offset in memory somewhere instead of in X. You'll still use X to keep track of which scanline you were on, but you'd only INC your offset variable every 4 scanlines.


Edited by JeffJetton, Tue Feb 12, 2019 2:39 PM.


#4 SpiceWare ONLINE  

SpiceWare

    Draconian

  • 12,699 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Tue Feb 12, 2019 2:45 PM

You might find my tutorial useful.



#5 JeffJetton OFFLINE  

JeffJetton

    Space Invader

  • 22 posts
  • Location:Nashville, TN

Posted Tue Feb 12, 2019 3:05 PM

Oh, and there are a few other things you might want to think about (and bear in mind that I'm no expert here either):

 

  • Yes you absolutely should check out the above-mentioned tutorial. :thumbsup:
  • Your playfield data is sandwiched in-between your initialization code and the beginning of your kernel (your "frame" loop). I don't see that you're skipping over it with a jmp or anything, which means all that data is getting executed as if they were instructions! It just so happens that %10101010 (or $AA) is the TAX opcode. So your program starts out by transferring A to X 146 times in a row. :-o (In fact, you could actually replace some or all of your .byte %10101010 lines with an equivalent number of TAX instructions and your program would run exactly the same.)
  • You could skip the data with a jmp StartOfFrame, but it's probably more common to simply define your data at the end of your program, right before that final ORG $FFFA. And yes, unlike many (most?) structured programming languages, here it's perfectly legal to reference data that you don't "define" until later in your program.
  • Another thing that's different from programming languages you may be used to is that it's usually better to count down to zero in all your loops rather than counting up to your target value. CPX is really just subtracting X from A and not storing the result anywhere. BNE merely tests to see if the last math operation resulted in a zero and branches if it didn't. By using a DEX instead of an INX, your final decrement to zero will trigger the desired no-branch condition. That eliminates the need for the compare instruction, saving two bytes and two processor cycles per iteration. For example...
                ; Vertical Blank
                LDX #37
VerticalBlank   STA WSYNC
                DEX
                BNE VerticalBlank

Edited by JeffJetton, Tue Feb 12, 2019 3:16 PM.


#6 George Washingtoad OFFLINE  

George Washingtoad

    Star Raider

  • Topic Starter
  • 51 posts
  • Location:North Carolina

Posted Tue Feb 12, 2019 6:45 PM

Thanks a lot for the advice everybody! That makes a lot more sense now!







Also tagged with one or more of these keywords: programming, debug, help, atari 2600, newbie, Playfields, tutorial, Bytes

0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users