Jump to content
IGNORED

Just started with assembly programming, Playfield generation difficulties


Recommended Posts

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 $F000Reset; 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 #0IDIOT                     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 PF2CORAL                     INX                    LDA #$CA STA COLUBK                    STA WSYNC                    CPX #44                    BNE CORAL                                           LDA #%11000000                    STA PF0                    LDA #%10000111                    STA PF1                    LDA #%00001111                    STA PF2NORAL                     INX                    LDA #$CA STA COLUBK                    STA WSYNC                    CPX #46                    BNE NORAL                       LDA #%10000000                    STA PF0                    LDA #%00000011                    STA PF1                    LDA #%00000111                    STA PF2STEVE                     INX                    LDA #$CA STA COLUBK                    STA WSYNC                    CPX #48                    BNE STEVE                       LDA #%00000000                    STA PF0                    LDA #%00000001                    STA PF1                    LDA #%00000011                    STA PF2PTEVE                     INX                    LDA #$CA STA COLUBK                    STA WSYNC                    CPX #50                    BNE PTEVE                                                             LDA #0                    STA PF0                    STA PF1                    STA PF2BIGB                 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 #0Overscan        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 $F000Reset; 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 %10101010PFG1 .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 %10101010PFG2 .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 PASTEINGLDY #0Woah 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 PF2FED                 INX LDA #$0 STA COLUBK STA WSYNC CPX #192           BNE FED                    EndScreen       LDA #%01000010                STA VBLANK                ; Overscan                LDX #0Overscan        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?

 

 

Link to comment
Share on other sites

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
Link to comment
Share on other sites

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
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...