[stella] First attempt at Atari 2600 programming

Subject: [stella] First attempt at Atari 2600 programming
From: Tennessee Carmel-Veilleux <veilleux@xxxxxxxxx>
Date: Mon, 15 Jun 1998 07:34:27 -0400
Hello,

        Last night, I made my first attempt at modifying a playfield
graphics program for the 2600. I added a cascading sound and changed the
input parameters to display more than just plain blue when the joystick
is moved. The source was Erik Mooney's playfield graphics demo, and I
had quite a few problems writing it... You will see in the source that
when I tried to make the sound routine change the sound every scanline,
during scanline scanning, the machine (in my case PCAE
on a P233) became excessively slow. My best guess is that the routines
takes too many clocks, but I don't think it exceeds the 76 I can use per
scanline. How odd. Also, I had some problems with 6502 programming as I
tried to save some cycles because I'm used to the 80x86 assembler, which
is quite different (although the 6502 is easier to code).

I would like to hear comments on the small code I added, even thought it
might be crappy...

    Regards,
--
Tennessee Carmel-Veilleux (Coordonator of Digital Meltdown)
veilleux@xxxxxxxxx (www.ameth.org/~veilleux)
ICQ ID : 8604827
||*|| This message was written in Canada / Ce message a été écrit au
Canada

;--------------------------------------
; My first attempt at writing atari code
; Modification of Erik Mooney's color stripes example
; Mods : -Plays a continuous stream of sound
;        -When you move the joystick, the color of the background
;         is equal to the joystick position bits
;---------------------------------------

;How to Draw a Playfield II, by Erik Mooney (emooney@xxxxxxxxxxxxxxxx)
;Heavily indebted to Nick S. Bensema's "How to Draw a Playfield" (thanks!)
;I removed most of Nick's comments.. refer to the original for more
;complete documentation.

        processor 6502
        include vcs.h


    org $F000           ;"processor 6502" was moved into vcs2600.h

Score0  = $80    ;RAM locations
Score1  = $81
Sndfrq  = $82 ;Sound frequency
Oldtim  = $83 ;OLD intim
Framecount = $84 ;Frame count

Joystick0  = $90

Start

    SEI  ; Disable interrupts, if there are any.
    CLD  ; Clear BCD math bit.
    LDX  #$FF
    TXS  ; Set stack to top of RAM.

    LDA #0  ;Zero everything except VSYNC.
B1  STA 0,X
    DEX
    BNE B1

    STA Framecount
; At this point in the code we would set up things like the data
; direction registers for the joysticks and such.

    JSR  GameInit

MainLoop
    JSR  VerticalBlank ;Execute the vertical blank.
    JSR  CheckSwitches ;Check console switches.
    JSR  GameCalc      ;Do calculations during Vblank
    JSR  DrawScreen    ;Draw the screen
    JSR  OverScan      ;Do more calculations during overscan
    JMP  MainLoop      ;Continue forever.

VerticalBlank          ;Beginning of the frame - at the end of overscan.
    LDA  #2            ;VBLANK was set at the beginning of overscan.
    STA  WSYNC
    STA  WSYNC
    STA  WSYNC
    STA  VSYNC ;Begin vertical sync.
    STA  WSYNC ; First line of VSYNC
    STA  WSYNC ; Second line of VSYNC.

; Atari says we have to have 37 scanlines of VBLANK time.  Since
; each scanline uses 76 cycles, that makes 37*76=2888 cycles.
; We must also subtract the five cycles it will take to set the
; timer, and the three cycles it will take to STA WSYNC to the next
; line.  Plus the checking loop is only accurate to six cycles, making
; a total of fourteen cycles we have to waste.  2888-14=2876.
;
; We almost always use TIM64T for this, since the math just won't
; work out with the other intervals.  2880/64=44.something.  It
; doesn't matter what that something is, we have to round DOWN.

    LDA #44        ;Set timer to activate during the last line of VBLANK.
    STA TIM64T
;
; Now we can end the VSYNC period.
;
    LDA #0
    STA  WSYNC ; Third line of VSYNC.
    STA  VSYNC ; Writing zero to VSYNC ends vertical sync period.
    RTS

CheckSwitches
    LDA #0          ;Clear collision latches
    STA CXCLR       ;In a real game, we'd probably check the collision
                    ;registers before clearing them.
    LDA SWCHA       ;Read joystick 0
    STA Joystick0   ;Store for later use
    RTS

GameCalc
    LDA #0
    STA COLUBK  ;Background will be black.

    LDA Joystick0  ;Load the joystick switches
    AND #$F0    ;Only care about top four bits, which is joystick 0
    CMP #$F0    ;If top four=1111, stick centered, don't change
                ;---------------------
                ; The AND $F0 is also very useful at getting only the color
                ; high nibble needed by the COLUBK register
    BEQ NoStick ; If no stick movement, branch
    ; LDA #$88  ; 
    STA COLUBK  ; Otherwise use the reminescent value in A to set background
                ;---------------------
NoStick


    LDA #$55    ;Alternate pixels: 01010101 = $55
    STA PF0
    STA PF2     ;Store alternating bit pattern to the playfield registers
    ASL         ;Because PF1 displays in the opposite bit order from PF0
    STA PF1     ;and PF2, we need 10101010 instead of 01010101.
    LDA #1
;    STA CTRLPF  ;Let's reflect the playfield just cause we feel like it =)
    RTS

;To refresh your memory:
;    PF0  |     PF1       |      PF2
;  4 5 6 7|7 6 5 4 3 2 1 0|0 1 2 3 4 5 6 7
;This pattern is the left half of the screen; it's then either repeated
;or reflected depending on bit 0 of CTRLPF.  For a playfield that doesn't
;repeat or reflect, you'd have to alter the playfield registers in the
;middle of each scanline.

DrawScreen
    LDA INTIM
    BNE DrawScreen ;Loops until the timer is done - that means we're
                   ;somewhere in the last line of vertical blank.
    STA WSYNC      ;End the current scanline - the last line of VBLANK.
    STA VBLANK     ;End the VBLANK period.  The TIA will display stuff
                   ;starting with the next scanline.  We do have 23 cycles
                   ;of horizontal blank before it displays anything.

    ;--My sound routine---
    INC Framecount
    LDX Framecount

    PHA ; Save old TIMer state
    TXA ; Transfer line value in A 
    AND #$1F ; Get a 0-31 (5 bits) value for divider from y line 
    STA AUDF0 ; Set frequency divider
    AND #$0F ; Get a 0-15 (4 bits) value for volume from y line
    STA AUDV0 ; Set audio volume
    LDA #$04 ; Pur 4 into A
    STA AUDC0 ; Set audio control to 0 (divide by 1)
    PLA ; Load old timer into A

    ;-------------------


    LDY #0       ;We're going to use Y to count scanlines.

;Everything is already set, so let's just count scanlines.
;We're at the beginning of WBLANK of the first TV line right here.
ScanLoop
    
    ;------------------
    ; ***** Problem here... If you comment out the previoud block
    ; of sound code, and use this one instead, the machine is rendered
    ; Extremely slow. Anybody would know why ?
    ;------------------
    ;STY Sndfrq ; Story Y line value in Sndfrq
    ;LDX Sndfrq ; load y line value in X

    ;STA Oldtim ; Save old TIMer state
    ;TXA ; Transfer line value in A 
    ;AND #$1F ; Get a 0-31 (5 bits) value for divider from y line 
    ;STA AUDF0 ; Set frequency divider
    ;AND #$0F ; Get a 0-15 (4 bits) value for volume from y line
    ;STA AUDV0 ; Set audio volume
    ;LDA #$04 ; Pur 4 into A
    ;STA AUDC0 ; Set audio control to 0 (divide by 1)
    ;LDA Oldtim ; Load old timer into A
    ;-------------------


    STY COLUPF     ;Keep changing the playfield color every line for some
                   ;neat-looking stripes.

NoChange
    STA WSYNC      ;Wait for end of scanline
    INY

    BNE ScanLoop   ;Count scanlines.
    RTS

OverScan        ;We've got 30 scanlines to kill.
    LDX #30     ;In a real game, we'd probably be doing calculations here,
KillLines       ;possibly using the timer again to tell us when overscan
    STA WSYNC   ;is done instead of counting the scanlines.
    DEX
    BNE KillLines
    RTS

GameInit    ;Usually called to start a new game.. we're not using it yet.
    LDA #0  ;Just example code to show what could be done here.
    STA Score0
    STA Score1
    RTS

;Starting positions for PC
    org $FFFC
    .word Start
    .word Start

Attachment: Mypfg.bin
Description: Binary data

Current Thread