diff --git a/Asm65/OpDef.cs b/Asm65/OpDef.cs index 7a4bbf1..994fa43 100644 --- a/Asm65/OpDef.cs +++ b/Asm65/OpDef.cs @@ -518,6 +518,9 @@ namespace Asm65 { condBranchTakenFlags = curFlags; // Invoke the flag update delegate. newFlags = StatusFlagUpdater(curFlags, immVal, ref condBranchTakenFlags); + + // TODO(maybe): there are some constraints we can impose: if Z=1 then + // N=0, and if N=1 then Z=0. I'm not sure this is actually useful though. } private static StatusFlags FlagUpdater_NoChange(StatusFlags flags, int immVal, @@ -613,6 +616,40 @@ namespace Asm65 { } return flags; } + private static StatusFlags FlagUpdater_ROL(StatusFlags flags, int immVal, + ref StatusFlags condBranchTakenFlags) { + // this rotates the N flag into C, so set C=N + // if carry is one, set Z=0; otherwise set Z/N=indeterminate + // (if Z=1 we should set Z=C, but this seems rare and I don't entirely trust Z) + if (flags.C == 1) { + flags.C = flags.N; + flags.Z = 0; + flags.N = TriState16.INDETERMINATE; + } else { + flags.C = flags.N; + flags.Z = flags.N = TriState16.INDETERMINATE; + } + return flags; + } + private static StatusFlags FlagUpdater_ROR(StatusFlags flags, int immVal, + ref StatusFlags condBranchTakenFlags) { + // if carry is set, set Z=0 and N=1; + // if carry is clear, set N=0; + // if carry is clear and Z=1, everything is zero and no flags change + // (this seems unlikely, so I'm going to assume we've mis-read a flag and ignore this) + // otherwise, Z/N/C=indeterminate + if (flags.C == 1) { + flags.Z = 0; + flags.N = 1; + flags.C = TriState16.INDETERMINATE; + } else if (flags.C == 0) { + flags.N = 0; + flags.Z = flags.C = TriState16.INDETERMINATE; + } else { + flags.C = flags.Z = flags.N = TriState16.INDETERMINATE; + } + return flags; + } private static StatusFlags FlagUpdater_PLP(StatusFlags flags, int immVal, ref StatusFlags condBranchTakenFlags) { // All flags are unknown. The caller may be able to match with a previous @@ -1077,13 +1114,13 @@ namespace Asm65 { Mnemonic = OpName.ROL, Effect = FlowEffect.Cont, FlagsAffected = FlagsAffected_NZC, - StatusFlagUpdater = FlagUpdater_NZC + StatusFlagUpdater = FlagUpdater_ROL }; private static OpDef OpROR = new OpDef() { Mnemonic = OpName.ROR, Effect = FlowEffect.Cont, FlagsAffected = FlagsAffected_NZC, - StatusFlagUpdater = FlagUpdater_NZC + StatusFlagUpdater = FlagUpdater_ROR }; private static OpDef OpRTI = new OpDef() { Mnemonic = OpName.RTI, diff --git a/SourceGen/SGTestData/1003-flags-and-branches b/SourceGen/SGTestData/1003-flags-and-branches index 999e6e0..9aa96bf 100644 Binary files a/SourceGen/SGTestData/1003-flags-and-branches and b/SourceGen/SGTestData/1003-flags-and-branches differ diff --git a/SourceGen/SGTestData/Expected/1003-flags-and-branches_Merlin32.S b/SourceGen/SGTestData/Expected/1003-flags-and-branches_Merlin32.S index 6b6b58c..19262e2 100644 --- a/SourceGen/SGTestData/Expected/1003-flags-and-branches_Merlin32.S +++ b/SourceGen/SGTestData/Expected/1003-flags-and-branches_Merlin32.S @@ -191,40 +191,63 @@ L10DD ora #$80 dfb $00 dfb $db -L10E3 clc +L10E3 lda L10E3 + sec + ror A + bmi L10EC + + dfb $00 + dfb $dc + +L10EC clc + ror A + bpl L10F2 + + dfb $00 + dfb $dc + +L10F2 lda #$00 + sec + rol A + bne L10FA + + dfb $00 + dfb $dc + +L10FA clc php sec plp - bcc L10EB + bcc L1102 dfb $00 dfb $00 -L10EB rep #$20 +L1102 rep #$20 mx %01 sep #$10 - jsr L1106 + jsr L111D rep #$30 mx %00 - jsr L110C + jsr L1123 sep #$30 mx %11 - jsr L110C + jsr L1123 rep #$20 mx %01 sep #$10 - jsr L1106 + jsr L111D sep #$30 mx %11 rts mx %01 -L1106 lda #$1234 +L111D lda #$1234 ldx #$ff rts mx %11 -L110C lda #$ff +L1123 lda #$ff ldx #$ee ldy #$dd rts diff --git a/SourceGen/SGTestData/Expected/1003-flags-and-branches_cc65.S b/SourceGen/SGTestData/Expected/1003-flags-and-branches_cc65.S index 0cc6bec..815ca76 100644 --- a/SourceGen/SGTestData/Expected/1003-flags-and-branches_cc65.S +++ b/SourceGen/SGTestData/Expected/1003-flags-and-branches_cc65.S @@ -196,41 +196,64 @@ L10DD: ora #$80 .byte $00 .byte $db -L10E3: clc +L10E3: lda L10E3 + sec + ror A + bmi L10EC + + .byte $00 + .byte $dc + +L10EC: clc + ror A + bpl L10F2 + + .byte $00 + .byte $dc + +L10F2: lda #$00 + sec + rol A + bne L10FA + + .byte $00 + .byte $dc + +L10FA: clc php sec plp - bcc L10EB + bcc L1102 .byte $00 .byte $00 -L10EB: rep #$20 +L1102: rep #$20 .a16 sep #$10 - jsr L1106 + jsr L111D rep #$30 .i16 - jsr L110C + jsr L1123 sep #$30 .a8 .i8 - jsr L110C + jsr L1123 rep #$20 .a16 sep #$10 - jsr L1106 + jsr L111D sep #$30 .a8 rts .a16 -L1106: lda #$1234 +L111D: lda #$1234 ldx #$ff rts .a8 -L110C: lda #$ff +L1123: lda #$ff ldx #$ee ldy #$dd rts diff --git a/SourceGen/SGTestData/Expected/2008-address-changes_Merlin32.S b/SourceGen/SGTestData/Expected/2008-address-changes_Merlin32.S index bd58854..74e6322 100644 --- a/SourceGen/SGTestData/Expected/2008-address-changes_Merlin32.S +++ b/SourceGen/SGTestData/Expected/2008-address-changes_Merlin32.S @@ -82,7 +82,7 @@ L3100 dfb $02 fwd bit fwd lda ulabel lda ulabel+1 - lda $300e + lda ulabel+2 lda $300f lda L3100 beq L3182 diff --git a/SourceGen/SGTestData/Expected/2008-address-changes_cc65.S b/SourceGen/SGTestData/Expected/2008-address-changes_cc65.S index 57b2fef..5d92cb4 100644 --- a/SourceGen/SGTestData/Expected/2008-address-changes_cc65.S +++ b/SourceGen/SGTestData/Expected/2008-address-changes_cc65.S @@ -85,7 +85,7 @@ L3100: .byte $02 fwd: bit fwd lda ulabel lda ulabel+1 - lda $300e + lda ulabel+2 lda $300f lda L3100 beq L3182 diff --git a/SourceGen/SGTestData/Source/1003-flags-and-branches.S b/SourceGen/SGTestData/Source/1003-flags-and-branches.S index cfa5358..80513bc 100644 --- a/SourceGen/SGTestData/Source/1003-flags-and-branches.S +++ b/SourceGen/SGTestData/Source/1003-flags-and-branches.S @@ -176,6 +176,25 @@ ok_oraN0 brk $db ok_oraN1 +; check rol/ror +:foo lda :foo ;scramble N/V + sec + ror A ;rotates the carry into the hi bit (N) + bmi ok_ror1 + brk $dc +ok_ror1 + clc + ror A ;now try with carry clear + bpl ok_ror2 + brk $dc +ok_ror2 + lda #$00 ;set Z=1 + sec + rol A ;set Z=0 (could also set C=0) + bne ok_rol1 + brk $dc +ok_rol1 + ; simple php/plp pair test clc php