Skip to content

Commit ca7d7dd

Browse files
authored
Merge pull request #122 from rumbledethumps/master
fix w65c02 BBRx/BBSx timing
2 parents afc3314 + f2b6715 commit ca7d7dd

3 files changed

Lines changed: 82 additions & 72 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
## What's New
22

3+
* **12-Aug-2026**: fixed BBRx/BBSx timing and bus behaviour in w65c02.h. These
4+
instructions are all reads on the W65C02S — the decoder used to emit a dummy
5+
write-back of the zero page value — and their length varies with the branch:
6+
5 cycles not taken, 6 taken, 7 taken across a page boundary, instead of a flat
7+
6. Verified against the SingleStepTests/65x02 "wdc65c02" v1 vectors; the older
8+
ProcessorTests set that the original decode followed predates the July 2024
9+
correction.
10+
311
* **11-Jan-2025**: writing data back to floppy is now supported in the CPC emulation
412
(see: https://github.com/floooh/chips/issues/104 and https://github.com/floooh/chips/pull/105),
513
note though that the floppy emulation in the CPC is still very rough. Many thanks to @karlvr for the PR!

chips/w65c02.h

Lines changed: 69 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,11 @@
4848
is supported; the "unused" opcodes behave as the guaranteed NOPs of their
4949
documented length.
5050
51-
The instruction timing is verified cycle-by-cycle against the SingleStepTests
52-
"wdc65c02" test vectors (every opcode except WAI and STP, which halt the CPU
53-
and cannot be single-stepped), and the instruction behaviour against Klaus
54-
Dormann's 65C02 extended opcodes functional test.
51+
The instruction timing is verified cycle-by-cycle against the
52+
SingleStepTests/65x02 "wdc65c02" (v1) test vectors (every opcode except WAI
53+
and STP, which halt the CPU and cannot be single-stepped), and the
54+
instruction behaviour against Klaus Dormann's 65C02 extended opcodes
55+
functional test.
5556
5657
To initialize the emulator, fill out a w65c02_desc_t structure with
5758
initialization parameters and then call w65c02_init().
@@ -733,11 +734,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
733734
/* BBR0 */
734735
case (0x0F<<3)|0: _SA(c->PC++);break;
735736
case (0x0F<<3)|1: c->AD=_GD();_SA(c->AD);break;
736-
case (0x0F<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
737+
case (0x0F<<3)|2: c->AD=_GD();_SA(_GA());break;
737738
case (0x0F<<3)|3: c->AD=(c->AD>>0)&1;_SA(c->PC++);break;
738-
case (0x0F<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0==(uint8_t)c->AD){c->PC=_t;}}break;
739-
case (0x0F<<3)|5: _FETCH();break;
740-
case (0x0F<<3)|6: assert(false);break;
739+
case (0x0F<<3)|4: if(0==(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
740+
case (0x0F<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
741+
case (0x0F<<3)|6: c->PC=c->AD;_FETCH();break;
741742
case (0x0F<<3)|7: assert(false);break;
742743
/* BPL */
743744
case (0x10<<3)|0: _SA(c->PC++);break;
@@ -877,11 +878,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
877878
/* BBR1 */
878879
case (0x1F<<3)|0: _SA(c->PC++);break;
879880
case (0x1F<<3)|1: c->AD=_GD();_SA(c->AD);break;
880-
case (0x1F<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
881+
case (0x1F<<3)|2: c->AD=_GD();_SA(_GA());break;
881882
case (0x1F<<3)|3: c->AD=(c->AD>>1)&1;_SA(c->PC++);break;
882-
case (0x1F<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0==(uint8_t)c->AD){c->PC=_t;}}break;
883-
case (0x1F<<3)|5: _FETCH();break;
884-
case (0x1F<<3)|6: assert(false);break;
883+
case (0x1F<<3)|4: if(0==(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
884+
case (0x1F<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
885+
case (0x1F<<3)|6: c->PC=c->AD;_FETCH();break;
885886
case (0x1F<<3)|7: assert(false);break;
886887
/* JSR */
887888
case (0x20<<3)|0: _SA(c->PC++);break;
@@ -1021,11 +1022,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
10211022
/* BBR2 */
10221023
case (0x2F<<3)|0: _SA(c->PC++);break;
10231024
case (0x2F<<3)|1: c->AD=_GD();_SA(c->AD);break;
1024-
case (0x2F<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
1025+
case (0x2F<<3)|2: c->AD=_GD();_SA(_GA());break;
10251026
case (0x2F<<3)|3: c->AD=(c->AD>>2)&1;_SA(c->PC++);break;
1026-
case (0x2F<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0==(uint8_t)c->AD){c->PC=_t;}}break;
1027-
case (0x2F<<3)|5: _FETCH();break;
1028-
case (0x2F<<3)|6: assert(false);break;
1027+
case (0x2F<<3)|4: if(0==(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
1028+
case (0x2F<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
1029+
case (0x2F<<3)|6: c->PC=c->AD;_FETCH();break;
10291030
case (0x2F<<3)|7: assert(false);break;
10301031
/* BMI */
10311032
case (0x30<<3)|0: _SA(c->PC++);break;
@@ -1165,11 +1166,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
11651166
/* BBR3 */
11661167
case (0x3F<<3)|0: _SA(c->PC++);break;
11671168
case (0x3F<<3)|1: c->AD=_GD();_SA(c->AD);break;
1168-
case (0x3F<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
1169+
case (0x3F<<3)|2: c->AD=_GD();_SA(_GA());break;
11691170
case (0x3F<<3)|3: c->AD=(c->AD>>3)&1;_SA(c->PC++);break;
1170-
case (0x3F<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0==(uint8_t)c->AD){c->PC=_t;}}break;
1171-
case (0x3F<<3)|5: _FETCH();break;
1172-
case (0x3F<<3)|6: assert(false);break;
1171+
case (0x3F<<3)|4: if(0==(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
1172+
case (0x3F<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
1173+
case (0x3F<<3)|6: c->PC=c->AD;_FETCH();break;
11731174
case (0x3F<<3)|7: assert(false);break;
11741175
/* RTI */
11751176
case (0x40<<3)|0: _SA(c->PC);break;
@@ -1309,11 +1310,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
13091310
/* BBR4 */
13101311
case (0x4F<<3)|0: _SA(c->PC++);break;
13111312
case (0x4F<<3)|1: c->AD=_GD();_SA(c->AD);break;
1312-
case (0x4F<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
1313+
case (0x4F<<3)|2: c->AD=_GD();_SA(_GA());break;
13131314
case (0x4F<<3)|3: c->AD=(c->AD>>4)&1;_SA(c->PC++);break;
1314-
case (0x4F<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0==(uint8_t)c->AD){c->PC=_t;}}break;
1315-
case (0x4F<<3)|5: _FETCH();break;
1316-
case (0x4F<<3)|6: assert(false);break;
1315+
case (0x4F<<3)|4: if(0==(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
1316+
case (0x4F<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
1317+
case (0x4F<<3)|6: c->PC=c->AD;_FETCH();break;
13171318
case (0x4F<<3)|7: assert(false);break;
13181319
/* BVC */
13191320
case (0x50<<3)|0: _SA(c->PC++);break;
@@ -1453,11 +1454,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
14531454
/* BBR5 */
14541455
case (0x5F<<3)|0: _SA(c->PC++);break;
14551456
case (0x5F<<3)|1: c->AD=_GD();_SA(c->AD);break;
1456-
case (0x5F<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
1457+
case (0x5F<<3)|2: c->AD=_GD();_SA(_GA());break;
14571458
case (0x5F<<3)|3: c->AD=(c->AD>>5)&1;_SA(c->PC++);break;
1458-
case (0x5F<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0==(uint8_t)c->AD){c->PC=_t;}}break;
1459-
case (0x5F<<3)|5: _FETCH();break;
1460-
case (0x5F<<3)|6: assert(false);break;
1459+
case (0x5F<<3)|4: if(0==(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
1460+
case (0x5F<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
1461+
case (0x5F<<3)|6: c->PC=c->AD;_FETCH();break;
14611462
case (0x5F<<3)|7: assert(false);break;
14621463
/* RTS */
14631464
case (0x60<<3)|0: _SA(c->PC);break;
@@ -1597,11 +1598,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
15971598
/* BBR6 */
15981599
case (0x6F<<3)|0: _SA(c->PC++);break;
15991600
case (0x6F<<3)|1: c->AD=_GD();_SA(c->AD);break;
1600-
case (0x6F<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
1601+
case (0x6F<<3)|2: c->AD=_GD();_SA(_GA());break;
16011602
case (0x6F<<3)|3: c->AD=(c->AD>>6)&1;_SA(c->PC++);break;
1602-
case (0x6F<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0==(uint8_t)c->AD){c->PC=_t;}}break;
1603-
case (0x6F<<3)|5: _FETCH();break;
1604-
case (0x6F<<3)|6: assert(false);break;
1603+
case (0x6F<<3)|4: if(0==(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
1604+
case (0x6F<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
1605+
case (0x6F<<3)|6: c->PC=c->AD;_FETCH();break;
16051606
case (0x6F<<3)|7: assert(false);break;
16061607
/* BVS */
16071608
case (0x70<<3)|0: _SA(c->PC++);break;
@@ -1741,11 +1742,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
17411742
/* BBR7 */
17421743
case (0x7F<<3)|0: _SA(c->PC++);break;
17431744
case (0x7F<<3)|1: c->AD=_GD();_SA(c->AD);break;
1744-
case (0x7F<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
1745+
case (0x7F<<3)|2: c->AD=_GD();_SA(_GA());break;
17451746
case (0x7F<<3)|3: c->AD=(c->AD>>7)&1;_SA(c->PC++);break;
1746-
case (0x7F<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0==(uint8_t)c->AD){c->PC=_t;}}break;
1747-
case (0x7F<<3)|5: _FETCH();break;
1748-
case (0x7F<<3)|6: assert(false);break;
1747+
case (0x7F<<3)|4: if(0==(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
1748+
case (0x7F<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
1749+
case (0x7F<<3)|6: c->PC=c->AD;_FETCH();break;
17491750
case (0x7F<<3)|7: assert(false);break;
17501751
/* BRA */
17511752
case (0x80<<3)|0: _SA(c->PC++);break;
@@ -1885,11 +1886,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
18851886
/* BBS0 */
18861887
case (0x8F<<3)|0: _SA(c->PC++);break;
18871888
case (0x8F<<3)|1: c->AD=_GD();_SA(c->AD);break;
1888-
case (0x8F<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
1889+
case (0x8F<<3)|2: c->AD=_GD();_SA(_GA());break;
18891890
case (0x8F<<3)|3: c->AD=(c->AD>>0)&1;_SA(c->PC++);break;
1890-
case (0x8F<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0!=(uint8_t)c->AD){c->PC=_t;}}break;
1891-
case (0x8F<<3)|5: _FETCH();break;
1892-
case (0x8F<<3)|6: assert(false);break;
1891+
case (0x8F<<3)|4: if(0!=(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
1892+
case (0x8F<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
1893+
case (0x8F<<3)|6: c->PC=c->AD;_FETCH();break;
18931894
case (0x8F<<3)|7: assert(false);break;
18941895
/* BCC */
18951896
case (0x90<<3)|0: _SA(c->PC++);break;
@@ -2029,11 +2030,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
20292030
/* BBS1 */
20302031
case (0x9F<<3)|0: _SA(c->PC++);break;
20312032
case (0x9F<<3)|1: c->AD=_GD();_SA(c->AD);break;
2032-
case (0x9F<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
2033+
case (0x9F<<3)|2: c->AD=_GD();_SA(_GA());break;
20332034
case (0x9F<<3)|3: c->AD=(c->AD>>1)&1;_SA(c->PC++);break;
2034-
case (0x9F<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0!=(uint8_t)c->AD){c->PC=_t;}}break;
2035-
case (0x9F<<3)|5: _FETCH();break;
2036-
case (0x9F<<3)|6: assert(false);break;
2035+
case (0x9F<<3)|4: if(0!=(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
2036+
case (0x9F<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
2037+
case (0x9F<<3)|6: c->PC=c->AD;_FETCH();break;
20372038
case (0x9F<<3)|7: assert(false);break;
20382039
/* LDY */
20392040
case (0xA0<<3)|0: _SA(c->PC++);break;
@@ -2173,11 +2174,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
21732174
/* BBS2 */
21742175
case (0xAF<<3)|0: _SA(c->PC++);break;
21752176
case (0xAF<<3)|1: c->AD=_GD();_SA(c->AD);break;
2176-
case (0xAF<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
2177+
case (0xAF<<3)|2: c->AD=_GD();_SA(_GA());break;
21772178
case (0xAF<<3)|3: c->AD=(c->AD>>2)&1;_SA(c->PC++);break;
2178-
case (0xAF<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0!=(uint8_t)c->AD){c->PC=_t;}}break;
2179-
case (0xAF<<3)|5: _FETCH();break;
2180-
case (0xAF<<3)|6: assert(false);break;
2179+
case (0xAF<<3)|4: if(0!=(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
2180+
case (0xAF<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
2181+
case (0xAF<<3)|6: c->PC=c->AD;_FETCH();break;
21812182
case (0xAF<<3)|7: assert(false);break;
21822183
/* BCS */
21832184
case (0xB0<<3)|0: _SA(c->PC++);break;
@@ -2317,11 +2318,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
23172318
/* BBS3 */
23182319
case (0xBF<<3)|0: _SA(c->PC++);break;
23192320
case (0xBF<<3)|1: c->AD=_GD();_SA(c->AD);break;
2320-
case (0xBF<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
2321+
case (0xBF<<3)|2: c->AD=_GD();_SA(_GA());break;
23212322
case (0xBF<<3)|3: c->AD=(c->AD>>3)&1;_SA(c->PC++);break;
2322-
case (0xBF<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0!=(uint8_t)c->AD){c->PC=_t;}}break;
2323-
case (0xBF<<3)|5: _FETCH();break;
2324-
case (0xBF<<3)|6: assert(false);break;
2323+
case (0xBF<<3)|4: if(0!=(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
2324+
case (0xBF<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
2325+
case (0xBF<<3)|6: c->PC=c->AD;_FETCH();break;
23252326
case (0xBF<<3)|7: assert(false);break;
23262327
/* CPY */
23272328
case (0xC0<<3)|0: _SA(c->PC++);break;
@@ -2461,11 +2462,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
24612462
/* BBS4 */
24622463
case (0xCF<<3)|0: _SA(c->PC++);break;
24632464
case (0xCF<<3)|1: c->AD=_GD();_SA(c->AD);break;
2464-
case (0xCF<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
2465+
case (0xCF<<3)|2: c->AD=_GD();_SA(_GA());break;
24652466
case (0xCF<<3)|3: c->AD=(c->AD>>4)&1;_SA(c->PC++);break;
2466-
case (0xCF<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0!=(uint8_t)c->AD){c->PC=_t;}}break;
2467-
case (0xCF<<3)|5: _FETCH();break;
2468-
case (0xCF<<3)|6: assert(false);break;
2467+
case (0xCF<<3)|4: if(0!=(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
2468+
case (0xCF<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
2469+
case (0xCF<<3)|6: c->PC=c->AD;_FETCH();break;
24692470
case (0xCF<<3)|7: assert(false);break;
24702471
/* BNE */
24712472
case (0xD0<<3)|0: _SA(c->PC++);break;
@@ -2605,11 +2606,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
26052606
/* BBS5 */
26062607
case (0xDF<<3)|0: _SA(c->PC++);break;
26072608
case (0xDF<<3)|1: c->AD=_GD();_SA(c->AD);break;
2608-
case (0xDF<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
2609+
case (0xDF<<3)|2: c->AD=_GD();_SA(_GA());break;
26092610
case (0xDF<<3)|3: c->AD=(c->AD>>5)&1;_SA(c->PC++);break;
2610-
case (0xDF<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0!=(uint8_t)c->AD){c->PC=_t;}}break;
2611-
case (0xDF<<3)|5: _FETCH();break;
2612-
case (0xDF<<3)|6: assert(false);break;
2611+
case (0xDF<<3)|4: if(0!=(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
2612+
case (0xDF<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
2613+
case (0xDF<<3)|6: c->PC=c->AD;_FETCH();break;
26132614
case (0xDF<<3)|7: assert(false);break;
26142615
/* CPX */
26152616
case (0xE0<<3)|0: _SA(c->PC++);break;
@@ -2749,11 +2750,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
27492750
/* BBS6 */
27502751
case (0xEF<<3)|0: _SA(c->PC++);break;
27512752
case (0xEF<<3)|1: c->AD=_GD();_SA(c->AD);break;
2752-
case (0xEF<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
2753+
case (0xEF<<3)|2: c->AD=_GD();_SA(_GA());break;
27532754
case (0xEF<<3)|3: c->AD=(c->AD>>6)&1;_SA(c->PC++);break;
2754-
case (0xEF<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0!=(uint8_t)c->AD){c->PC=_t;}}break;
2755-
case (0xEF<<3)|5: _FETCH();break;
2756-
case (0xEF<<3)|6: assert(false);break;
2755+
case (0xEF<<3)|4: if(0!=(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
2756+
case (0xEF<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
2757+
case (0xEF<<3)|6: c->PC=c->AD;_FETCH();break;
27572758
case (0xEF<<3)|7: assert(false);break;
27582759
/* BEQ */
27592760
case (0xF0<<3)|0: _SA(c->PC++);break;
@@ -2893,11 +2894,11 @@ uint64_t w65c02_tick(w65c02_t* c, uint64_t pins) {
28932894
/* BBS7 */
28942895
case (0xFF<<3)|0: _SA(c->PC++);break;
28952896
case (0xFF<<3)|1: c->AD=_GD();_SA(c->AD);break;
2896-
case (0xFF<<3)|2: c->AD=_GD();_SD(c->AD);_WR();break;
2897+
case (0xFF<<3)|2: c->AD=_GD();_SA(_GA());break;
28972898
case (0xFF<<3)|3: c->AD=(c->AD>>7)&1;_SA(c->PC++);break;
2898-
case (0xFF<<3)|4: {uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(0!=(uint8_t)c->AD){c->PC=_t;}}break;
2899-
case (0xFF<<3)|5: _FETCH();break;
2900-
case (0xFF<<3)|6: assert(false);break;
2899+
case (0xFF<<3)|4: if(0!=(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}break;
2900+
case (0xFF<<3)|5: if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}break;
2901+
case (0xFF<<3)|6: c->PC=c->AD;_FETCH();break;
29012902
case (0xFF<<3)|7: assert(false);break;
29022903
// %>
29032904
default: _W65C02_UNREACHABLE;

codegen/w65c02_gen.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,17 +242,18 @@ def i_bra(o):
242242
o.t('_SA((c->PC&0xFF00)|(c->AD&0x00FF));if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;c->irq_pip>>=1;c->nmi_pip>>=1;_FETCH();};')
243243
o.t('c->PC=c->AD;')
244244

245-
# BBRx/BBSx: flat 6 cycles (RMW-style zp read + always-present branch cycle)
245+
# BBRx/BBSx: all reads, 5 cycles not taken / 6 taken / 7 taken across a page
246246
def bbr(bit): return _bitbr(bit, taken='0==') # branch if bit clear
247247
def bbs(bit): return _bitbr(bit, taken='0!=') # branch if bit set
248248
def _bitbr(bit, taken):
249249
def i(o):
250250
o.t('_SA(c->PC++);') # fetch zp addr
251251
o.t('c->AD=_GD();_SA(c->AD);') # read zp value
252-
o.t('c->AD=_GD();_SD(c->AD);_WR();') # dummy write-back; AD=zp value
252+
o.t('c->AD=_GD();_SA(_GA());') # re-read, address held
253253
o.t('c->AD=(c->AD>>%d)&1;_SA(c->PC++);' % bit) # AD=selected bit; fetch rel
254-
o.t('{uint16_t _t=c->PC+(int8_t)_GD();_SA((c->PC&0xFF00)|(_t&0x00FF));if(%s(uint8_t)c->AD){c->PC=_t;}}' % taken)
255-
o.t('')
254+
o.t('if(%s(uint8_t)c->AD){c->AD=c->PC+(int8_t)_GD();_SA(c->PC);}else{_FETCH();}' % taken)
255+
o.t('if((c->AD&0xFF00)==(c->PC&0xFF00)){c->PC=c->AD;_FETCH();}else{_SA(c->PC);}')
256+
o.t('c->PC=c->AD;')
256257
return i
257258

258259
# jumps

0 commit comments

Comments
 (0)