Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
joshop opened this issue Apr 1, 2022 · 0 comments
Open

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

joshop opened this issue Apr 1, 2022 · 0 comments

Comments

@joshop
Copy link

joshop commented Apr 1, 2022

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant