Re: [stella] behold, i am become shiva, destroyer of kernals!

Subject: Re: [stella] behold, i am become shiva, destroyer of kernals!
From: "Andrew Davie" <atari2600@xxxxxxxxxxxxx>
Date: Thu, 11 Mar 2004 23:51:36 +1100
    ;we have a hit - if ball is positioned
    ; on left side, it goes right. On right,
    ; it goes left.
    cmp ballXposition+1
    bcc BallHitPlayerOnRight

The clc above, and in similar code, is totally superfluous.  Remove it.
The comparison sets or clears the carry, and also N and Z flags.  The
previous state of these is lost/ignored.

There are many low/high byte additions and declarations like this...

SLOW_GRAV_LO_BYTE = #%11110101
SLOW_GRAV_HI_BYTE = #%11111111

    lda slowP1YSpeed
    sta slowP1YSpeed
    lda slowP1YSpeed+1
    sta slowP1YSpeed+1

It's easier (for a human) to just use a 16-bit value and let the assembler
calculate the high/low bytes.

SLOW_GRAV = -2.5 * 256            ; easy way to visualise 8.8 format... use
decimal as you think of it, mult by 256 to get actual 8.8 format

    lda slowP1YSpeed
    adc #<SLOW_GRAV            ; LOW byte of constant
    sta slowP1YSpeed
    lda slowP1YSpeed+1
    adc #>SLOW_GRAV            ; HIGH byte of constant
    sta slowP1YSpeed+1

The advantages of the above are...

1) You only have to change the value in one location
2) You NEVER have to hand-calculate the HI/LO values or think about them in
3) You can easily change from 8.8 format to any other format by changing the
*256 constant in such declarations

This code is a bit dangerous...

    lda p0score ;accumulator = score
    asl ;accumulator = score * 2
    asl ;accumulator = score * 4
    adc p0score  ;accumulator = (score * 4) + score = score * 5
    adc #<Score0Graphic-1 ;add in the low byte of the graphic location
    sta pointerP0Score
    ;lda #>Score0Graphic ;grab the hight byte of the graphic location
    ;sta pointerP0Score+1

In particular, it's initialising the high and low byte of a 16-bit pointer w
ith different values.  Specifically, it puts the low byte of address-1 (plus
score * 5) into the low byte, and the high byte is elsewhere initialised to
the high byte of Score0Graphic.  If I'm reading this right, assume p0score =
0, then this would initialise (pointerP0Score) to point to 255 bytes PAST
the start of Score0Graphic.


Score0Graphic is at $F800
p0score is 0

    lda p0score    ; a = 0
    adc p0score    ; a = 0
    adc #<Score0Graphic-1  ; a = $FF   (we added FF)
    sta pointerP0Score  ; now $FF

so assuming the high byte was initialised to the high byte of the base
address of Score0Graphic table, (PointerP0Score) would then be $F8FF -- 
pointing nowhere near where I think this code is TRYING to point.  Exactly a
page off, actually.

This could be a problem in other sections of the code, but it sure looks
like a problem here and for the P1 pointer, just below that.

In several places in the code, you're using $2D to waste cycles (with a
store, etc).
Use the SLEEP macro.  Code like this...

    sta $2D ... or
   dec $2d; wait 5 cycles

should be replaced by

    SLEEP 3    ... or
    SLEEP 10

The meaning is clearer, and it's easier to make systemwide changes (eg: use
of illegal opcodes or not).  Finally, the dec may have unforseen effects,
and the SLEEP is guaranteed to have NO effect on hardware OR flags (for
illegal opcode version).  For the legal opcode version, it only affects

By the way, there was some interesting posts a few years back on
"efficiently wasting time" which gave the least number of bytes necessary to
waste a particular number of cycles.  Worth a read.

I find the mix of UPPERCASE and lowercase op-codes quite inelegant... eg:

;divide by 32 for the count, then multiply by 8 for the offset...





(actual code, by the way!).  It would be nice to stick to one or the other,
preferably lowercase :)


Archives (includes files) at
Unsub & more at

Current Thread