Skip to content

Compiler assuming C clear when it isn't? #135

@joshop

Description

@joshop

Millfork has been great for developing my homebrew NES game, and so far it's been totally stable, but either I messed something up or the compiler is getting a bit overeager with an optimization. In my collision detection routine, I have this code:

level_idx = (lo(player_x >> 4) & $1f) | (word(player_y & $f0) << 1)
if (hi(vel_x) & $80 == 0) {
    level_idx += 1
}
if (solidity[level_shadow[level_idx]] || (player_y & $0f != 0 && solidity[level_shadow[level_idx+32]])) {
    k += 1
}

Using optimization level 8 (same thing happens with 4), I get this assembly:

; 
;line:89:main.mfk
;               level_idx = (lo(player_x >> 4) & $1f) | (word(player_y & $f0) << 1)
    LDA player_x
    STA __reg
    LDA player_x + 1
    LSR
    ROR __reg
    LSR
    ROR __reg
    LSR
    LDA __reg
    ROR
    ALR #$3E
    STA __reg
    TXA
    PHA
    LDA __reg
    PHA
    LDA player_y
    AND #$F0
    PHA
    ROL
    ROL
    AND #1
    STA __reg + 1
    PLA
    ASL
    STA __reg
    PLA
    ORA __reg
    STA main$level_idx
    PLA
    ORA __reg + 1
    STA main$level_idx + 1
; 
;line:90:main.mfk
;               if (hi(vel_x) & $80 == 0) {
    BIT vel_x + 1
    BMI .fi__00221
; 
;line:91:main.mfk
;                   level_idx += 1
    INC main$level_idx
    BNE .in__00220
    INC main$level_idx + 1
.in__00220:
; 
;line:90:main.mfk
;               if (hi(vel_x) & $80 == 0) {
.fi__00221:
; 
;line:93:main.mfk
;               if (solidity[level_shadow[level_idx]] || (player_y & $0f != 0 && solidity[level_shadow[level_idx+32]])) {
    LDY main$level_idx
    LDA main$level_idx + 1
    ADC #3 ; THIS IS WHERE THE BUG IS
    STA __reg + 1
    STX __reg
    LDA (__reg), Y
    TAY
    LDA solidity.array, Y
    BNE .or__00223
    LDA player_y
    AND #$F
    BEQ .fi__00222
    LDY main$level_idx
    LDA main$level_idx + 1
    CLC
    ADC #3
    STA __reg + 1
    LDA #$20
    STA __reg
    LDA (__reg), Y
    TAY
    LDA solidity.array, Y
    BEQ .fi__00222
.or__00223:
; 
;line:94:main.mfk
;                   k += 1
    INX
; 
;line:93:main.mfk
;               if (solidity[level_shadow[level_idx]] || (player_y & $0f != 0 && solidity[level_shadow[level_idx+32]])) {
.fi__00222:

level_shadow is located at $0300, so the address computation optimization makes sense, but that ADC is causing a bug when carry is set from the most recent ASL. When I add a CLC explicitly, or use optimization level 2, the bug disappears. Did I forget something or did the optimizer?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions