├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md └── src ├── cpu.rs └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "r6502" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "r6502" 3 | version = "0.1.0" 4 | authors = ["Raph Levien "] 5 | edition = "2021" 6 | description = "A cycle-accurate emulator for the 6502 microprocessor" 7 | license = "MIT OR Apache-2.0" 8 | keywords = ["6502", "emulator"] 9 | categories = ["emulators"] 10 | readme = "README.md" 11 | repository = "https://github.com/raphlinus/r6502" 12 | 13 | [dependencies] 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # R6502 2 | 3 | This is my take on emulation of the venerable 6502 microprocessor. Goals include: 4 | 5 | * High fidelity, cycle accurate emulation. 6 | * Reasonably small code size. 7 | * Reasonably good performance. 8 | * Easy to use as a component, integrating with I/O. 9 | 10 | It is likely this will grow into an Apple II emulator, very possibly running on a Raspberry Pi Pico, with bit-banged DVI video output (using [pico-dvi-rs]). 11 | 12 | One non-goal is to implement finer grained micro-architectural emulation; it would be difficult to achieve high performance. 13 | 14 | Internally, the implementation uses a form of microcode. There are up to seven micro-operations per instruction, each corresponding to one clock tick and thus one bus cycle. As in the original 6502, on each cycle there is either a read or write operation on the bus. The main method on the `Cpu` performs a clock tick. It is then up to the client to perform the bus operation, whether that's reading or writing to a simulated RAM or doing IO. 15 | 16 | It currently passes the [6502 functional tests]. A goal is to make it also pass the [Tom Harte test suite], which will require careful implementation of illegal instructions, and likely some other refinements. 17 | 18 | The current status is rough and unfinished. The core is probably reasonably stable, other than making it pass a more rigorous test suite and making it log less (which in turn precludes no_std), but things will move around to become better organized, and possibly to support emulation of more of the Apple II than just the CPU. 19 | 20 | To try it, run: 21 | 22 | ``` 23 | cargo run --release 6502_functional_test.bin > log.txt 24 | ``` 25 | 26 | This generates several gigabytes of log files. 27 | 28 | It is licensed under your choice of Apache 2 or MIT. 29 | 30 | [6502 functional tests]: https://github.com/Klaus2m5/6502_65C02_functional_tests 31 | [pico-dvi-rs]: https://github.com/DusterTheFirst/pico-dvi-rs 32 | [Tom Harte test suite]: https://github.com/TomHarte/ProcessorTests 33 | -------------------------------------------------------------------------------- /src/cpu.rs: -------------------------------------------------------------------------------- 1 | pub struct Cpu { 2 | // Processor registers 3 | pub a: u8, 4 | pub x: u8, 5 | pub y: u8, 6 | pub pc: u16, 7 | pub flags: u8, 8 | pub sp: u8, 9 | 10 | pub addr: u16, 11 | pub is_write: bool, 12 | pub data: u8, 13 | pub insn: u8, 14 | pub insn_cycle: u8, 15 | pub lo: u8, 16 | pub ptr: u8, 17 | 18 | // Other processor state 19 | pub cycle: usize, 20 | } 21 | 22 | #[repr(u8)] 23 | #[derive(Clone, Copy, Debug)] 24 | enum UcodeStep { 25 | Next, 26 | Fetch, 27 | // Immediate ALU ops 28 | OraImm, 29 | AndImm, 30 | EorImm, 31 | AdcImm, 32 | LdaImm, 33 | LdxImm, 34 | LdyImm, 35 | CpxImm, 36 | CpyImm, 37 | CmpImm, 38 | SbcImm, 39 | // Memory ALU ops 40 | Ora, 41 | And, 42 | Eor, 43 | Adc, 44 | Lda, 45 | Ldx, 46 | Ldy, 47 | Cmp, 48 | Cpx, 49 | Cpy, 50 | Bit, 51 | Sbc, 52 | // Memory RMW ops 53 | Rmw2, 54 | AslMem, 55 | RolMem, 56 | LsrMem, 57 | RorMem, 58 | IncMem, 59 | DecMem, 60 | // Single cycle ops 61 | AslA, 62 | RolA, 63 | LsrA, 64 | RorA, 65 | Clc, 66 | Sec, 67 | Cli, 68 | Sei, 69 | Cld, 70 | Sed, 71 | Clv, 72 | Txs, 73 | Tsx, 74 | Tax, 75 | Tay, 76 | Txa, 77 | Tya, 78 | // Addressing modes 79 | Abs1, 80 | Abs2, 81 | AbsX, 82 | AbsY, 83 | AbsIx, 84 | Zpg, 85 | ZpgX, 86 | ZpgY, 87 | Ind, 88 | IndY2, 89 | IndY3, 90 | XInd2, 91 | XInd4, 92 | OraIx, 93 | AndIx, 94 | EorIx, 95 | LdaIx, 96 | LdxIx, 97 | LdyIx, 98 | AdcIx, 99 | CmpIx, 100 | SbcIx, 101 | StaAbs, 102 | StxAbs, 103 | StyAbs, 104 | StaAbsIx, 105 | StaZpg, 106 | StxZpg, 107 | StyZpg, 108 | StaZpgX, 109 | StxZpgY, 110 | StyZpgX, 111 | StaXInd, 112 | Jmp, 113 | Bpl, 114 | Bmi, 115 | Bvc, 116 | Bvs, 117 | Bne, 118 | Beq, 119 | Bcc, 120 | Bcs, 121 | CondBr, 122 | Dex, 123 | Dey, 124 | Inx, 125 | Iny, 126 | // Stack ops 127 | Pha, 128 | Php, 129 | Pull1, 130 | Pull2, 131 | Plp, 132 | Jsr1, 133 | Jsr2, 134 | Brk1, 135 | Jsr3, 136 | Jsr4, 137 | Rts3, 138 | Rts4, 139 | Rts5, 140 | Rti3, 141 | Brk3, 142 | Brk4, 143 | Brk5, 144 | Brk6, 145 | Nyi, 146 | } 147 | 148 | use UcodeStep::*; 149 | 150 | const fn c1(s1: UcodeStep) -> [UcodeStep; 8] { 151 | [Fetch, s1, Next, Next, Next, Next, Next, Next] 152 | } 153 | 154 | const fn c2(s1: UcodeStep, s2: UcodeStep) -> [UcodeStep; 8] { 155 | [Fetch, s1, s2, Next, Next, Next, Next, Next] 156 | } 157 | 158 | const fn c3(s1: UcodeStep, s2: UcodeStep, s3: UcodeStep) -> [UcodeStep; 8] { 159 | [Fetch, s1, s2, s3, Next, Next, Next, Next] 160 | } 161 | 162 | const fn c4(s1: UcodeStep, s2: UcodeStep, s3: UcodeStep, s4: UcodeStep) -> [UcodeStep; 8] { 163 | [Fetch, s1, s2, s3, s4, Next, Next, Next] 164 | } 165 | 166 | const fn c5( 167 | s1: UcodeStep, 168 | s2: UcodeStep, 169 | s3: UcodeStep, 170 | s4: UcodeStep, 171 | s5: UcodeStep, 172 | ) -> [UcodeStep; 8] { 173 | [Fetch, s1, s2, s3, s4, s5, Next, Next] 174 | } 175 | 176 | const fn c6( 177 | s1: UcodeStep, 178 | s2: UcodeStep, 179 | s3: UcodeStep, 180 | s4: UcodeStep, 181 | s5: UcodeStep, 182 | s6: UcodeStep, 183 | ) -> [UcodeStep; 8] { 184 | [Fetch, s1, s2, s3, s4, s5, s6, Next] 185 | } 186 | 187 | const UCODE: [[UcodeStep; 8]; 256] = [ 188 | c6(Brk1, Jsr3, Brk3, Brk4, Brk5, Brk6), // 00 BRK 189 | c5(Zpg, XInd2, IndY2, XInd4, Ora), // 01 ORA X,ind 190 | c1(Nyi), // 02 191 | c1(Nyi), // 03 192 | c1(Nyi), // 04 193 | c2(Zpg, Ora), // 05 ORA zpg 194 | c4(Zpg, Rmw2, AslMem, Next), // 06 ASL zpg 195 | c1(Nyi), // 07 196 | c2(Php, Next), // 08 PHP 197 | c1(OraImm), // 09 ORA # 198 | c1(AslA), // 0a ASL A 199 | c1(Nyi), // 0b 200 | c1(Nyi), // 0c 201 | c3(Abs1, Abs2, Ora), // 0d ORA abs 202 | c5(Abs1, Abs2, Rmw2, AslMem, Next), // 0e ASL abs 203 | c1(Nyi), // 0f 204 | c3(Bpl, CondBr, Next), // 10 BPL rel 205 | c5(Zpg, IndY2, IndY3, OraIx, Ora), // 11 ORA ind,y 206 | c1(Nyi), // 12 207 | c1(Nyi), // 13 208 | c1(Nyi), // 14 209 | c3(Zpg, ZpgX, Ora), // 15 ORA zpg,X 210 | c5(Zpg, ZpgX, Rmw2, AslMem, Next), // 16 ASL zpg,X 211 | c1(Nyi), // 17 212 | c1(Clc), // 18 CLC 213 | c4(Abs1, AbsY, OraIx, Ora), // 19 ORA abs,Y 214 | c1(Nyi), // 1a 215 | c1(Nyi), // 1b 216 | c1(Nyi), // 1c 217 | c4(Abs1, AbsX, OraIx, Ora), // 1d ORA abs,X 218 | c6(Abs1, AbsX, AbsIx, Rmw2, AslMem, Next), // 1e ASL abs,X 219 | c1(Nyi), // 1f 220 | c5(Jsr1, Jsr2, Jsr3, Jsr4, Jmp), // 20 JSR 221 | c5(Zpg, XInd2, IndY2, XInd4, And), // 21 AND X,ind 222 | c1(Nyi), // 22 223 | c1(Nyi), // 23 224 | c2(Zpg, Bit), // 24 BIT zpg 225 | c2(Zpg, And), // 25 AND zpg 226 | c4(Zpg, Rmw2, RolMem, Next), // 26 ROL zpg 227 | c1(Nyi), // 27 228 | c3(Pull1, Pull2, Plp), // 28 PLP 229 | c1(AndImm), // 29 AND # 230 | c1(RolA), // 2a ROL A 231 | c1(Nyi), // 2b 232 | c3(Abs1, Abs2, Bit), // 2c BIT abs 233 | c3(Abs1, Abs2, And), // 2d AND abs 234 | c5(Abs1, Abs2, Rmw2, RolMem, Next), // 2e ROL abs 235 | c1(Nyi), // 2f 236 | c3(Bmi, CondBr, Next), // 30 BMI rel 237 | c5(Zpg, IndY2, IndY3, AndIx, And), // 31 AND ind,y 238 | c1(Nyi), // 32 239 | c1(Nyi), // 33 240 | c1(Nyi), // 34 241 | c3(Zpg, ZpgX, And), // 35 AND zpg,X 242 | c5(Zpg, ZpgX, Rmw2, RolMem, Next), // 36 ROL zpg,X 243 | c1(Nyi), // 37 244 | c1(Sec), // 38 SEC 245 | c4(Abs1, AbsY, AndIx, And), // 39 AND abs,Y 246 | c1(Nyi), // 3a 247 | c1(Nyi), // 3b 248 | c1(Nyi), // 3c 249 | c4(Abs1, AbsX, AndIx, And), // 3d AND abs,X 250 | c6(Abs1, AbsX, AbsIx, Rmw2, RolMem, Next), // 3e ROL abs,X 251 | c1(Nyi), // 3f 252 | c5(Pull1, Pull1, Rti3, Rts3, Jmp), // 40 RTI 253 | c5(Zpg, XInd2, IndY2, XInd4, Eor), // 41 EOR X,ind 254 | c1(Nyi), // 42 255 | c1(Nyi), // 43 256 | c1(Nyi), // 44 257 | c2(Zpg, Eor), // 45 EOR zpg 258 | c4(Zpg, Rmw2, LsrMem, Next), // 46 LSR zpg 259 | c1(Nyi), // 47 260 | c2(Pha, Next), // 48 PHA 261 | c1(EorImm), // 49 EOR # 262 | c1(LsrA), // 4a LSR A 263 | c1(Nyi), // 4b 264 | c2(Abs1, Jmp), // 4c JMP abs 265 | c3(Abs1, Abs2, Eor), // 4d EOR abs 266 | c5(Abs1, Abs2, Rmw2, LsrMem, Next), // 4e LSR abs 267 | c1(Nyi), // 4f 268 | c3(Bvc, CondBr, Next), // 50 BVC rel 269 | c5(Zpg, IndY2, IndY3, EorIx, Eor), // 51 EOR ind,y 270 | c1(Nyi), // 52 271 | c1(Nyi), // 53 272 | c1(Nyi), // 54 273 | c3(Zpg, ZpgX, Eor), // 55 EOR zpg,X 274 | c5(Zpg, ZpgX, Rmw2, LsrMem, Next), // 56 LSR zpg,X 275 | c1(Nyi), // 57 276 | c1(Cli), // 58 CLI 277 | c4(Abs1, AbsY, EorIx, Eor), // 59 EOR abs,Y 278 | c1(Nyi), // 5a 279 | c1(Nyi), // 5b 280 | c1(Nyi), // 5c 281 | c4(Abs1, AbsX, EorIx, Eor), // 5d EOR abs,X 282 | c6(Abs1, AbsX, AbsIx, Rmw2, LsrMem, Next), // 5e LSR abs,X 283 | c1(Nyi), // 5f 284 | c5(Pull1, Pull1, Rts3, Rts4, Rts5), // 60 RTS 285 | c5(Zpg, XInd2, IndY2, XInd4, Adc), // 61 ADC X,ind 286 | c1(Nyi), // 62 287 | c1(Nyi), // 63 288 | c1(Nyi), // 64 289 | c2(Zpg, Adc), // 65 ADC zpg 290 | c4(Zpg, Rmw2, RorMem, Next), // 66 ROR zpg 291 | c1(Nyi), // 67 292 | c3(Pull1, Pull2, Lda), // 68 PLA 293 | c1(AdcImm), // 69 ADC # 294 | c1(RorA), // 6a ROR A 295 | c1(Nyi), // 6b 296 | c4(Abs1, Abs2, Ind, Jmp), // 6c JMP ind 297 | c3(Abs1, Abs2, Adc), // 6d ADC abs 298 | c5(Abs1, Abs2, Rmw2, RorMem, Next), // 6e ROR abs 299 | c1(Nyi), // 6f 300 | c3(Bvs, CondBr, Next), // 70 BVS rel 301 | c5(Zpg, IndY2, IndY3, AdcIx, Adc), // 71 ADC ind,y 302 | c1(Nyi), // 72 303 | c1(Nyi), // 73 304 | c1(Nyi), // 74 305 | c3(Zpg, ZpgX, Adc), // 75 ADC zpg,X 306 | c5(Zpg, ZpgX, Rmw2, RorMem, Next), // 76 ROR zpg,X 307 | c1(Nyi), // 77 308 | c1(Sei), // 78 SEI 309 | c4(Abs1, AbsY, AdcIx, Adc), // 79 ADC abs,Y 310 | c1(Nyi), // 7a 311 | c1(Nyi), // 7b 312 | c1(Nyi), // 7c 313 | c4(Abs1, AbsX, AdcIx, Adc), // 7d ADC abs,X 314 | c6(Abs1, AbsX, AbsIx, Rmw2, RorMem, Next), // 7e ROR abs,X 315 | c1(Nyi), // 7f 316 | c1(Nyi), // 80 317 | c5(Zpg, XInd2, IndY2, StaXInd, Next), // 81 STA X,ind 318 | c1(Nyi), // 82 319 | c1(Nyi), // 83 320 | c2(StyZpg, Next), // 84 STY zpg 321 | c2(StaZpg, Next), // 85 STA zpg 322 | c2(StxZpg, Next), // 86 STX zpg 323 | c1(Nyi), // 87 324 | c1(Dey), // 88 DEY 325 | c1(Nyi), // 89 326 | c1(Txa), // 8a TXA 327 | c1(Nyi), // 8b 328 | c3(Abs1, StyAbs, Next), // 8c STY abs 329 | c3(Abs1, StaAbs, Next), // 8d STA abs 330 | c3(Abs1, StxAbs, Next), // 8e STX abs 331 | c1(Nyi), // 8f 332 | c3(Bcc, CondBr, Next), // 90 BCC rel 333 | c5(Zpg, IndY2, IndY3, StaAbsIx, Next), // 91 STA ind,Y 334 | c1(Nyi), // 92 335 | c1(Nyi), // 93 336 | c3(Zpg, StyZpgX, Next), // 94 STY zpg,X 337 | c3(Zpg, StaZpgX, Next), // 95 STA zpg,X 338 | c3(Zpg, StxZpgY, Next), // 96 STX zpg,Y 339 | c1(Nyi), // 97 340 | c1(Tya), // 98 TYA 341 | c4(Abs1, AbsY, StaAbsIx, Next), // 99 STA abs,Y 342 | c1(Txs), // 9a TXS 343 | c1(Nyi), // 9b 344 | c1(Nyi), // 9c 345 | c4(Abs1, AbsX, StaAbsIx, Next), // 9d STA abs,X 346 | c1(Nyi), // 9e 347 | c1(Nyi), // 9f 348 | c1(LdyImm), // a0 LDY # 349 | c5(Zpg, XInd2, IndY2, XInd4, Lda), // a1 LDA X,ind 350 | c1(LdxImm), // a2 LDX # 351 | c1(Nyi), // a3 352 | c2(Zpg, Ldy), // a4 LDY zpg 353 | c2(Zpg, Lda), // a5 LDA zpg 354 | c2(Zpg, Ldx), // a6 LDX zpg 355 | c1(Nyi), // a7 356 | c1(Tay), // a8 TAY 357 | c1(LdaImm), // a9 LDA # 358 | c1(Tax), // aa TAX 359 | c1(Nyi), // ab 360 | c3(Abs1, Abs2, Ldy), // ac LDY abs 361 | c3(Abs1, Abs2, Lda), // ad LDA abs 362 | c3(Abs1, Abs2, Ldx), // ae LDX abs 363 | c1(Nyi), // af 364 | c3(Bcs, CondBr, Next), // b0 BCS rel 365 | c5(Zpg, IndY2, IndY3, LdaIx, Lda), // b1 LDA ind,y 366 | c1(Nyi), // b2 367 | c1(Nyi), // b3 368 | c3(Zpg, ZpgX, Ldy), // b4 LDY zpg,X 369 | c3(Zpg, ZpgX, Lda), // b5 LDA zpg,X 370 | c3(Zpg, ZpgY, Ldx), // b6 LDX zpg,Y 371 | c1(Nyi), // b7 372 | c1(Clv), // b8 CLV 373 | c4(Abs1, AbsY, LdaIx, Lda), // b9 LDA abs,Y 374 | c1(Tsx), // ba TSX 375 | c1(Nyi), // bb 376 | c4(Abs1, AbsX, LdyIx, Ldy), // bc LDY abs,X 377 | c4(Abs1, AbsX, LdaIx, Lda), // bd LDA abs,X 378 | c4(Abs1, AbsY, LdxIx, Ldx), // be LDX abs,Y 379 | c1(Nyi), // bf 380 | c1(CpyImm), // c0 CPY # 381 | c5(Zpg, XInd2, IndY2, XInd4, Cmp), // c1 CMP X,ind 382 | c1(Nyi), // c2 383 | c1(Nyi), // c3 384 | c2(Zpg, Cpy), // c4 CPY zpg 385 | c2(Zpg, Cmp), // c5 CMP zpg 386 | c4(Zpg, Rmw2, DecMem, Next), // c6 DEC zpg 387 | c1(Nyi), // c7 388 | c1(Iny), // c8 INY 389 | c1(CmpImm), // c9 CMP # 390 | c1(Dex), // ca DEX 391 | c1(Nyi), // cb 392 | c3(Abs1, Abs2, Cpy), // cc CPY abs 393 | c3(Abs1, Abs2, Cmp), // cd CMP abs 394 | c5(Abs1, Abs2, Rmw2, DecMem, Next), // ce DEC abs 395 | c1(Nyi), // cf 396 | c3(Bne, CondBr, Next), // d0 BNE rel 397 | c5(Zpg, IndY2, IndY3, CmpIx, Cmp), // d1 CMP ind,y 398 | c1(Nyi), // d2 399 | c1(Nyi), // d3 400 | c1(Nyi), // d4 401 | c3(Zpg, ZpgX, Cmp), // d5 CMP zpg,X 402 | c5(Zpg, ZpgX, Rmw2, DecMem, Next), // d6 DEC zpg,X 403 | c1(Nyi), // d7 404 | c1(Cld), // d8 CLD 405 | c4(Abs1, AbsY, CmpIx, Cmp), // d9 CMP abs,Y 406 | c1(Nyi), // da 407 | c1(Nyi), // db 408 | c1(Nyi), // dc 409 | c4(Abs1, AbsX, CmpIx, Cmp), // dd CMP abs,X 410 | c6(Abs1, AbsX, AbsIx, Rmw2, DecMem, Next), // de DEC abs,X 411 | c1(Nyi), // df 412 | c1(CpxImm), // e0 CPX # 413 | c5(Zpg, XInd2, IndY2, XInd4, Sbc), // e1 SBC X,ind 414 | c1(Nyi), // e2 415 | c1(Nyi), // e3 416 | c2(Zpg, Cpx), // e4 CPX zpg 417 | c2(Zpg, Sbc), // e5 SBC zpg 418 | c4(Zpg, Rmw2, IncMem, Next), // e6 INC zpg 419 | c1(Nyi), // e7 420 | c1(Inx), // e8 INX 421 | c1(SbcImm), // e9 SBC # 422 | c1(Next), // ea NOP 423 | c1(Nyi), // eb 424 | c3(Abs1, Abs2, Cpx), // ec CPX abs 425 | c3(Abs1, Abs2, Sbc), // ed SBC abs 426 | c5(Abs1, Abs2, Rmw2, IncMem, Next), // ee INC abs 427 | c1(Nyi), // ef 428 | c3(Beq, CondBr, Next), // f0 BEQ rel 429 | c5(Zpg, IndY2, IndY3, SbcIx, Sbc), // f1 SBC ind,y 430 | c1(Nyi), // f2 431 | c1(Nyi), // f3 432 | c1(Nyi), // f4 433 | c3(Zpg, ZpgX, Sbc), // f5 SBC zpg,X 434 | c5(Zpg, ZpgX, Rmw2, IncMem, Next), // f6 INC zpg,X 435 | c1(Nyi), // f7 436 | c1(Sed), // f8 SED 437 | c4(Abs1, AbsY, SbcIx, Sbc), // f9 SBC abs,Y 438 | c1(Nyi), // fa 439 | c1(Nyi), // fb 440 | c1(Nyi), // fc 441 | c4(Abs1, AbsX, SbcIx, Sbc), // fd SBC abs,X 442 | c6(Abs1, AbsX, AbsIx, Rmw2, IncMem, Next), // fe INC abs,X 443 | c1(Nyi), // ff 444 | ]; 445 | 446 | pub trait Bus { 447 | fn read(&mut self, addr: u16) -> u8; 448 | 449 | fn write(&mut self, addr: u16, val: u8); 450 | } 451 | 452 | impl Cpu { 453 | pub fn new() -> Cpu { 454 | Cpu { 455 | a: 0, 456 | x: 0, 457 | y: 0, 458 | pc: 0, 459 | flags: 0x30, 460 | sp: 0, 461 | addr: 0, 462 | is_write: false, 463 | data: 0, 464 | insn: 0xea, 465 | insn_cycle: 0, 466 | lo: 0, 467 | ptr: 0, 468 | 469 | cycle: 0, 470 | } 471 | } 472 | 473 | pub fn print_state(&self) { 474 | println!( 475 | "a {:02x} x {:02x} y {:02x} s {:02x} p {:02x} pc {:04x}", 476 | self.a, self.x, self.y, self.sp, self.flags, self.pc 477 | ); 478 | } 479 | 480 | fn set_nz(&mut self, a: u8) { 481 | self.flags = (self.flags & 0x7d) | (a & 0x80) | if a == 0 { 2 } else { 0 }; 482 | } 483 | 484 | fn set_a_nz(&mut self, val: u8) { 485 | self.a = val; 486 | self.set_nz(val); 487 | } 488 | 489 | fn set_x_nz(&mut self, val: u8) { 490 | self.x = val; 491 | self.set_nz(val); 492 | } 493 | 494 | fn set_y_nz(&mut self, val: u8) { 495 | self.y = val; 496 | self.set_nz(val); 497 | } 498 | 499 | // Calculations 500 | 501 | fn asl(&mut self, val: u8) -> u8 { 502 | let c = (val & 0x80) >> 7; 503 | let new_val = val.wrapping_shl(1); 504 | self.flags = (self.flags & 0x7c) | (new_val & 0x80) | c | if new_val == 0 { 2 } else { 0 }; 505 | new_val 506 | } 507 | 508 | fn bit(&mut self, val: u8) { 509 | self.flags = (self.flags & 0x3d) | (val & 0xc0) | if val & self.a == 0 { 2 } else { 0 }; 510 | } 511 | 512 | fn rol(&mut self, val: u8) -> u8 { 513 | let c = (val & 0x80) >> 7; 514 | let new_val = val.wrapping_shl(1) | (self.flags & 1); 515 | self.flags = (self.flags & 0x7c) | (new_val & 0x80) | c | if new_val == 0 { 2 } else { 0 }; 516 | new_val 517 | } 518 | 519 | fn lsr(&mut self, val: u8) -> u8 { 520 | let c = val & 1; 521 | let new_val = val >> 1; 522 | self.flags = (self.flags & 0x7c) | (new_val & 0x80) | c | if new_val == 0 { 2 } else { 0 }; 523 | new_val 524 | } 525 | 526 | fn ror(&mut self, val: u8) -> u8 { 527 | let c = val & 1; 528 | let new_val = (val >> 1) | ((self.flags & 1) << 7); 529 | self.flags = (self.flags & 0x7c) | (new_val & 0x80) | c | if new_val == 0 { 2 } else { 0 }; 530 | new_val 531 | } 532 | 533 | fn adc(&mut self, val: u8) { 534 | if self.flags & 8 != 0 { 535 | // decimal mode 536 | let a = u16::from(self.a); 537 | let mut sum = a + u16::from(val) + u16::from(self.flags & 1); 538 | let z = if (sum & 0xff) == 0 { 2 } else { 0 }; 539 | let al = (self.a & 0xf) + (val & 0xf) + (self.flags & 1); 540 | if al >= 0xa { 541 | sum += u16::from(((al + 6) & 0xf) + 0x10); 542 | sum -= u16::from(al); 543 | } 544 | let n = (sum as u8) & 0x80; 545 | let v = (!(self.a ^ val) & (self.a ^ (sum as u8)) & 0x80) >> 1; 546 | let mut c = 0; 547 | if sum >= 0xa0 { 548 | sum += 0x60; 549 | c = 1; 550 | } 551 | self.flags = (self.flags & 0x3c) | n | v | z | c; 552 | //println!("decimal {:02x} + {:02x} = {:02x}", self.a, val, sum); 553 | self.a = sum as u8; 554 | } else { 555 | let a = u16::from(self.a); 556 | let sum = a + u16::from(val) + u16::from(self.flags & 1); 557 | let c = (sum >> 8) as u8; 558 | let sum = sum as u8; 559 | let v = (!(self.a ^ val) & (self.a ^ sum) & 0x80) >> 1; 560 | self.flags = (self.flags & 0x3c) | (sum & 0x80) | c | v | if sum == 0 { 2 } else { 0 }; 561 | self.a = sum; 562 | } 563 | } 564 | 565 | fn sbc(&mut self, val: u8) { 566 | if self.flags & 8 != 0 { 567 | // decimal mode 568 | let c_in = self.flags & 1; 569 | 570 | // set flags based on binary computation 571 | let sum = u16::from(self.a) + u16::from(!val) + u16::from(c_in); 572 | let c = (sum >> 8) as u8; 573 | let sum = sum as u8; 574 | let v = (!(self.a ^ !val) & (self.a ^ sum) & 0x80) >> 1; 575 | self.flags = (self.flags & 0x3c) | (sum & 0x80) | c | v | if sum == 0 { 2 } else { 0 }; 576 | 577 | // do decimal calculation (this follows decimal mode tutorial) 578 | let mut al = i16::from(self.a & 0xf) - i16::from(val & 0xf) + i16::from(c_in) - 1; 579 | if al < 0 { 580 | al = ((al - 6) & 0xf) - 0x10; 581 | } 582 | let mut a = i16::from(self.a & 0xf0) - i16::from(val & 0xf0) + al; 583 | if a < 0 { 584 | a -= 0x60; 585 | } 586 | self.a = a as u8; 587 | } else { 588 | self.adc(!val) 589 | } 590 | } 591 | 592 | fn cmp(&mut self, lhs: u8, rhs: u8) { 593 | let sum = u16::from(lhs) + u16::from(!rhs) + 1; 594 | let c = (sum >> 8) as u8; 595 | let sum = sum as u8; 596 | self.flags = (self.flags & 0x7c) | (sum & 0x80) | c | if sum == 0 { 2 } else { 0 }; 597 | } 598 | 599 | // new stuff 600 | 601 | // an adapter, which is probably going away 602 | pub fn do_bus(&mut self, bus: &mut dyn Bus) { 603 | if self.is_write { 604 | bus.write(self.addr, self.data); 605 | } else { 606 | self.data = bus.read(self.addr); 607 | } 608 | } 609 | 610 | pub fn cpu_clk_ucode(&mut self) { 611 | let insn_cycle = self.insn_cycle; 612 | self.insn_cycle += 1; 613 | let ucode = UCODE[self.insn as usize][insn_cycle as usize]; 614 | println!("{:x} {insn_cycle} {ucode:?}", self.insn); 615 | let (addr, is_write) = match ucode { 616 | Fetch => { 617 | self.insn = self.data; 618 | self.pc = self.pc.wrapping_add(1); 619 | (self.pc, false) 620 | } 621 | Next => { 622 | self.insn_cycle = 0; 623 | (self.pc, false) 624 | } 625 | AslA => { 626 | self.a = self.asl(self.a); 627 | self.insn_cycle = 0; 628 | (self.pc, false) 629 | } 630 | RolA => { 631 | self.a = self.rol(self.a); 632 | self.insn_cycle = 0; 633 | (self.pc, false) 634 | } 635 | LsrA => { 636 | self.a = self.lsr(self.a); 637 | self.insn_cycle = 0; 638 | (self.pc, false) 639 | } 640 | RorA => { 641 | self.a = self.ror(self.a); 642 | self.insn_cycle = 0; 643 | (self.pc, false) 644 | } 645 | Clc => { 646 | self.flags &= !0x01; 647 | self.insn_cycle = 0; 648 | (self.pc, false) 649 | } 650 | Sec => { 651 | self.flags |= 0x01; 652 | self.insn_cycle = 0; 653 | (self.pc, false) 654 | } 655 | Cli => { 656 | self.flags &= !0x04; 657 | self.insn_cycle = 0; 658 | (self.pc, false) 659 | } 660 | Sei => { 661 | self.flags |= 0x04; 662 | self.insn_cycle = 0; 663 | (self.pc, false) 664 | } 665 | Cld => { 666 | self.flags &= !0x08; 667 | self.insn_cycle = 0; 668 | (self.pc, false) 669 | } 670 | Sed => { 671 | self.flags |= 0x08; 672 | self.insn_cycle = 0; 673 | (self.pc, false) 674 | } 675 | Clv => { 676 | self.flags &= !0x40; 677 | self.insn_cycle = 0; 678 | (self.pc, false) 679 | } 680 | OraImm => { 681 | self.set_a_nz(self.a | self.data); 682 | self.pc = self.pc.wrapping_add(1); 683 | self.insn_cycle = 0; 684 | (self.pc, false) 685 | } 686 | AndImm => { 687 | self.set_a_nz(self.a & self.data); 688 | self.pc = self.pc.wrapping_add(1); 689 | self.insn_cycle = 0; 690 | (self.pc, false) 691 | } 692 | EorImm => { 693 | self.set_a_nz(self.a ^ self.data); 694 | self.pc = self.pc.wrapping_add(1); 695 | self.insn_cycle = 0; 696 | (self.pc, false) 697 | } 698 | AdcImm => { 699 | self.adc(self.data); 700 | self.pc = self.pc.wrapping_add(1); 701 | self.insn_cycle = 0; 702 | (self.pc, false) 703 | } 704 | LdaImm => { 705 | self.set_a_nz(self.data); 706 | self.pc = self.pc.wrapping_add(1); 707 | self.insn_cycle = 0; 708 | (self.pc, false) 709 | } 710 | LdxImm => { 711 | self.set_x_nz(self.data); 712 | self.pc = self.pc.wrapping_add(1); 713 | self.insn_cycle = 0; 714 | (self.pc, false) 715 | } 716 | LdyImm => { 717 | self.set_y_nz(self.data); 718 | self.pc = self.pc.wrapping_add(1); 719 | self.insn_cycle = 0; 720 | (self.pc, false) 721 | } 722 | CmpImm => { 723 | self.cmp(self.a, self.data); 724 | self.pc = self.pc.wrapping_add(1); 725 | self.insn_cycle = 0; 726 | (self.pc, false) 727 | } 728 | CpxImm => { 729 | self.cmp(self.x, self.data); 730 | self.pc = self.pc.wrapping_add(1); 731 | self.insn_cycle = 0; 732 | (self.pc, false) 733 | } 734 | CpyImm => { 735 | self.cmp(self.y, self.data); 736 | self.pc = self.pc.wrapping_add(1); 737 | self.insn_cycle = 0; 738 | (self.pc, false) 739 | } 740 | SbcImm => { 741 | self.sbc(self.data); 742 | self.pc = self.pc.wrapping_add(1); 743 | self.insn_cycle = 0; 744 | (self.pc, false) 745 | } 746 | Ora => { 747 | self.set_a_nz(self.a | self.data); 748 | self.insn_cycle = 0; 749 | (self.pc, false) 750 | } 751 | And => { 752 | self.set_a_nz(self.a & self.data); 753 | self.insn_cycle = 0; 754 | (self.pc, false) 755 | } 756 | Eor => { 757 | self.set_a_nz(self.a ^ self.data); 758 | self.insn_cycle = 0; 759 | (self.pc, false) 760 | } 761 | Adc => { 762 | self.adc(self.data); 763 | self.insn_cycle = 0; 764 | (self.pc, false) 765 | } 766 | Lda => { 767 | self.set_a_nz(self.data); 768 | self.insn_cycle = 0; 769 | (self.pc, false) 770 | } 771 | Ldx => { 772 | self.set_x_nz(self.data); 773 | self.insn_cycle = 0; 774 | (self.pc, false) 775 | } 776 | Ldy => { 777 | self.set_y_nz(self.data); 778 | self.insn_cycle = 0; 779 | (self.pc, false) 780 | } 781 | Cmp => { 782 | self.cmp(self.a, self.data); 783 | self.insn_cycle = 0; 784 | (self.pc, false) 785 | } 786 | Cpx => { 787 | self.cmp(self.x, self.data); 788 | self.insn_cycle = 0; 789 | (self.pc, false) 790 | } 791 | Cpy => { 792 | self.cmp(self.y, self.data); 793 | self.insn_cycle = 0; 794 | (self.pc, false) 795 | } 796 | Bit => { 797 | self.bit(self.data); 798 | self.insn_cycle = 0; 799 | (self.pc, false) 800 | } 801 | Sbc => { 802 | self.sbc(self.data); 803 | self.insn_cycle = 0; 804 | (self.pc, false) 805 | } 806 | Rmw2 => (self.addr, true), 807 | AslMem => { 808 | self.data = self.asl(self.data); 809 | (self.addr, true) 810 | } 811 | RolMem => { 812 | self.data = self.rol(self.data); 813 | (self.addr, true) 814 | } 815 | LsrMem => { 816 | self.data = self.lsr(self.data); 817 | (self.addr, true) 818 | } 819 | RorMem => { 820 | self.data = self.ror(self.data); 821 | (self.addr, true) 822 | } 823 | IncMem => { 824 | let val = self.data.wrapping_add(1); 825 | self.data = val; 826 | self.set_nz(val); 827 | (self.addr, true) 828 | } 829 | DecMem => { 830 | let val = self.data.wrapping_sub(1); 831 | self.data = val; 832 | self.set_nz(val); 833 | (self.addr, true) 834 | } 835 | Abs1 => { 836 | self.pc = self.pc.wrapping_add(1); 837 | self.lo = self.data; 838 | (self.pc, false) 839 | } 840 | Abs2 => { 841 | self.pc = self.pc.wrapping_add(1); 842 | let addr = ((self.data as u16) << 8) | (self.lo as u16); 843 | (addr, false) 844 | } 845 | Zpg => { 846 | self.pc = self.pc.wrapping_add(1); 847 | (self.data as u16, false) 848 | } 849 | AbsX => { 850 | self.pc = self.pc.wrapping_add(1); 851 | self.ptr = self.x; 852 | let lo = self.lo.wrapping_add(self.ptr); 853 | let addr = ((self.data as u16) << 8) | (lo as u16); 854 | (addr, false) 855 | } 856 | AbsY => { 857 | self.pc = self.pc.wrapping_add(1); 858 | self.ptr = self.y; 859 | let lo = self.lo.wrapping_add(self.ptr); 860 | let addr = ((self.data as u16) << 8) | (lo as u16); 861 | (addr, false) 862 | } 863 | AbsIx => { 864 | if self.lo.overflowing_add(self.ptr).1 { 865 | self.addr = self.addr.wrapping_add(0x100); 866 | } 867 | (self.addr, false) 868 | } 869 | ZpgX => { 870 | let addr = (self.addr as u8).wrapping_add(self.x) as u16; 871 | (addr, false) 872 | } 873 | ZpgY => { 874 | let addr = (self.addr as u8).wrapping_add(self.y) as u16; 875 | (addr, false) 876 | } 877 | OraIx => { 878 | if self.lo.overflowing_add(self.ptr).1 { 879 | let addr = self.addr.wrapping_add(0x100); 880 | (addr, false) 881 | } else { 882 | self.set_a_nz(self.a | self.data); 883 | self.insn_cycle = 0; 884 | (self.pc, false) 885 | } 886 | } 887 | AndIx => { 888 | if self.lo.overflowing_add(self.ptr).1 { 889 | let addr = self.addr.wrapping_add(0x100); 890 | (addr, false) 891 | } else { 892 | self.set_a_nz(self.a & self.data); 893 | self.insn_cycle = 0; 894 | (self.pc, false) 895 | } 896 | } 897 | EorIx => { 898 | if self.lo.overflowing_add(self.ptr).1 { 899 | let addr = self.addr.wrapping_add(0x100); 900 | (addr, false) 901 | } else { 902 | self.set_a_nz(self.a ^ self.data); 903 | self.insn_cycle = 0; 904 | (self.pc, false) 905 | } 906 | } 907 | LdaIx => { 908 | if self.lo.overflowing_add(self.ptr).1 { 909 | let addr = self.addr.wrapping_add(0x100); 910 | (addr, false) 911 | } else { 912 | self.set_a_nz(self.data); 913 | self.insn_cycle = 0; 914 | (self.pc, false) 915 | } 916 | } 917 | LdxIx => { 918 | if self.lo.overflowing_add(self.ptr).1 { 919 | let addr = self.addr.wrapping_add(0x100); 920 | (addr, false) 921 | } else { 922 | self.set_x_nz(self.data); 923 | self.insn_cycle = 0; 924 | (self.pc, false) 925 | } 926 | } 927 | LdyIx => { 928 | if self.lo.overflowing_add(self.ptr).1 { 929 | let addr = self.addr.wrapping_add(0x100); 930 | (addr, false) 931 | } else { 932 | self.set_y_nz(self.data); 933 | self.insn_cycle = 0; 934 | (self.pc, false) 935 | } 936 | } 937 | AdcIx => { 938 | if self.lo.overflowing_add(self.ptr).1 { 939 | let addr = self.addr.wrapping_add(0x100); 940 | (addr, false) 941 | } else { 942 | self.adc(self.data); 943 | self.insn_cycle = 0; 944 | (self.pc, false) 945 | } 946 | } 947 | CmpIx => { 948 | if self.lo.overflowing_add(self.ptr).1 { 949 | let addr = self.addr.wrapping_add(0x100); 950 | (addr, false) 951 | } else { 952 | self.cmp(self.a, self.data); 953 | self.insn_cycle = 0; 954 | (self.pc, false) 955 | } 956 | } 957 | SbcIx => { 958 | if self.lo.overflowing_add(self.ptr).1 { 959 | let addr = self.addr.wrapping_add(0x100); 960 | (addr, false) 961 | } else { 962 | self.sbc(self.data); 963 | self.insn_cycle = 0; 964 | (self.pc, false) 965 | } 966 | } 967 | IndY2 => { 968 | self.lo = self.data; 969 | let addr = (self.addr as u8).wrapping_add(1) as u16; 970 | (addr, false) 971 | } 972 | IndY3 => { 973 | let lo = self.lo.wrapping_add(self.y); 974 | self.ptr = self.y; 975 | let addr = ((self.data as u16) << 8) | (lo as u16); 976 | (addr, false) 977 | } 978 | XInd2 => { 979 | let addr = (self.addr as u8).wrapping_add(self.x) as u16; 980 | (addr, false) 981 | } 982 | XInd4 => { 983 | let addr = ((self.data as u16) << 8) | (self.lo as u16); 984 | (addr, false) 985 | } 986 | StaAbsIx => { 987 | if self.lo.overflowing_add(self.ptr).1 { 988 | self.addr = self.addr.wrapping_add(0x100); 989 | } 990 | self.data = self.a; 991 | (self.addr, true) 992 | } 993 | Ind => { 994 | self.lo = self.data; 995 | // increment lo byte only; no carry 996 | let lo = (self.addr as u8).wrapping_add(1); 997 | let addr = (self.addr & 0xff00) | lo as u16; 998 | (addr, false) 999 | } 1000 | StaZpg => { 1001 | self.pc = self.pc.wrapping_add(1); 1002 | let addr = self.data as u16; 1003 | self.data = self.a; 1004 | (addr, true) 1005 | } 1006 | StxZpg => { 1007 | self.pc = self.pc.wrapping_add(1); 1008 | let addr = self.data as u16; 1009 | self.data = self.x; 1010 | (addr, true) 1011 | } 1012 | StyZpg => { 1013 | self.pc = self.pc.wrapping_add(1); 1014 | let addr = self.data as u16; 1015 | self.data = self.y; 1016 | (addr, true) 1017 | } 1018 | StaZpgX => { 1019 | self.data = self.a; 1020 | let addr = (self.addr as u8).wrapping_add(self.x); 1021 | (addr as u16, true) 1022 | } 1023 | StxZpgY => { 1024 | self.data = self.x; 1025 | let addr = (self.addr as u8).wrapping_add(self.y); 1026 | (addr as u16, true) 1027 | } 1028 | StyZpgX => { 1029 | self.data = self.y; 1030 | let addr = (self.addr as u8).wrapping_add(self.x); 1031 | (addr as u16, true) 1032 | } 1033 | StaAbs => { 1034 | self.pc = self.pc.wrapping_add(1); 1035 | let addr = ((self.data as u16) << 8) | (self.lo as u16); 1036 | self.data = self.a; 1037 | (addr, true) 1038 | } 1039 | StxAbs => { 1040 | self.pc = self.pc.wrapping_add(1); 1041 | let addr = ((self.data as u16) << 8) | (self.lo as u16); 1042 | self.data = self.x; 1043 | (addr, true) 1044 | } 1045 | StyAbs => { 1046 | self.pc = self.pc.wrapping_add(1); 1047 | let addr = ((self.data as u16) << 8) | (self.lo as u16); 1048 | self.data = self.y; 1049 | (addr, true) 1050 | } 1051 | StaXInd => { 1052 | let addr = ((self.data as u16) << 8) | (self.lo as u16); 1053 | self.data = self.a; 1054 | (addr, true) 1055 | } 1056 | Txs => { 1057 | self.sp = self.x; 1058 | self.insn_cycle = 0; 1059 | (self.pc, false) 1060 | } 1061 | Tsx => { 1062 | self.set_x_nz(self.sp); 1063 | self.insn_cycle = 0; 1064 | (self.pc, false) 1065 | } 1066 | Tax => { 1067 | self.set_x_nz(self.a); 1068 | self.insn_cycle = 0; 1069 | (self.pc, false) 1070 | } 1071 | Tay => { 1072 | self.set_y_nz(self.a); 1073 | self.insn_cycle = 0; 1074 | (self.pc, false) 1075 | } 1076 | Txa => { 1077 | self.set_a_nz(self.x); 1078 | self.insn_cycle = 0; 1079 | (self.pc, false) 1080 | } 1081 | Tya => { 1082 | self.set_a_nz(self.y); 1083 | self.insn_cycle = 0; 1084 | (self.pc, false) 1085 | } 1086 | Jmp => { 1087 | self.pc = ((self.data as u16) << 8) | (self.lo as u16); 1088 | self.insn_cycle = 0; 1089 | (self.pc, false) 1090 | } 1091 | Bpl => self.cond_branch((self.flags & 0x80) == 0), 1092 | Bmi => self.cond_branch((self.flags & 0x80) != 0), 1093 | Bvc => self.cond_branch((self.flags & 0x40) == 0), 1094 | Bvs => self.cond_branch((self.flags & 0x40) != 0), 1095 | Bcc => self.cond_branch((self.flags & 0x01) == 0), 1096 | Bcs => self.cond_branch((self.flags & 0x01) != 0), 1097 | Bne => self.cond_branch((self.flags & 0x02) == 0), 1098 | Beq => self.cond_branch((self.flags & 0x02) != 0), 1099 | CondBr => { 1100 | let new_pc = self.pc.wrapping_add(self.lo as i8 as u16); 1101 | let nocarry_pc = (self.pc & 0xff00) | (new_pc & 0xff); 1102 | self.pc = new_pc; 1103 | if new_pc == nocarry_pc { 1104 | self.insn_cycle = 0; 1105 | } 1106 | (nocarry_pc, false) 1107 | } 1108 | Dex => { 1109 | let x = self.x.wrapping_sub(1); 1110 | self.set_x_nz(x); 1111 | self.insn_cycle = 0; 1112 | (self.pc, false) 1113 | } 1114 | Dey => { 1115 | let y = self.y.wrapping_sub(1); 1116 | self.set_y_nz(y); 1117 | self.insn_cycle = 0; 1118 | (self.pc, false) 1119 | } 1120 | Inx => { 1121 | let x = self.x.wrapping_add(1); 1122 | self.set_x_nz(x); 1123 | self.insn_cycle = 0; 1124 | (self.pc, false) 1125 | } 1126 | Iny => { 1127 | let y = self.y.wrapping_add(1); 1128 | self.set_y_nz(y); 1129 | self.insn_cycle = 0; 1130 | (self.pc, false) 1131 | } 1132 | Pha => { 1133 | self.data = self.a; 1134 | let addr = 0x100 | (self.sp as u16); 1135 | self.sp = self.sp.wrapping_sub(1); 1136 | (addr, true) 1137 | } 1138 | Php => { 1139 | self.data = self.flags; 1140 | let addr = 0x100 | (self.sp as u16); 1141 | self.sp = self.sp.wrapping_sub(1); 1142 | (addr, true) 1143 | } 1144 | Pull1 => { 1145 | let addr = 0x100 | (self.sp as u16); 1146 | self.sp = self.sp.wrapping_add(1); 1147 | (addr, false) 1148 | } 1149 | Pull2 => { 1150 | let addr = 0x100 | (self.sp as u16); 1151 | (addr, false) 1152 | } 1153 | Plp => { 1154 | self.flags = self.data | 0x30; 1155 | self.insn_cycle = 0; 1156 | (self.pc, false) 1157 | } 1158 | Jsr1 => { 1159 | self.pc = self.pc.wrapping_add(1); 1160 | self.lo = self.data; 1161 | let addr = 0x100 | (self.sp as u16); 1162 | (addr, false) 1163 | } 1164 | Jsr2 => { 1165 | self.data = (self.pc >> 8) as u8; 1166 | self.sp = self.sp.wrapping_sub(1); 1167 | (self.addr, true) 1168 | } 1169 | Jsr3 => { 1170 | self.data = self.pc as u8; 1171 | let addr = 0x100 | (self.sp as u16); 1172 | self.sp = self.sp.wrapping_sub(1); 1173 | (addr, true) 1174 | } 1175 | Jsr4 => (self.pc, false), 1176 | Rts3 => { 1177 | self.lo = self.data; 1178 | let addr = 0x100 | (self.sp as u16); 1179 | (addr, false) 1180 | } 1181 | Rts4 => { 1182 | self.pc = ((self.data as u16) << 8) | (self.lo as u16); 1183 | (self.pc, false) 1184 | } 1185 | Rts5 => { 1186 | self.pc = self.pc.wrapping_add(1); 1187 | self.insn_cycle = 0; 1188 | (self.pc, false) 1189 | } 1190 | Rti3 => { 1191 | self.flags = self.data; 1192 | let addr = 0x100 | (self.sp as u16); 1193 | self.sp = self.sp.wrapping_add(1); 1194 | (addr, false) 1195 | } 1196 | Brk1 => { 1197 | self.pc = self.pc.wrapping_add(1); 1198 | self.data = (self.pc >> 8) as u8; 1199 | let addr = 0x100 | (self.sp as u16); 1200 | self.sp = self.sp.wrapping_sub(1); 1201 | (addr, true) 1202 | } 1203 | Brk3 => { 1204 | self.data = self.flags; 1205 | let addr = 0x100 | (self.sp as u16); 1206 | self.sp = self.sp.wrapping_sub(1); 1207 | (addr, true) 1208 | } 1209 | Brk4 => (0xfffe, false), 1210 | Brk5 => { 1211 | self.lo = self.data; 1212 | (0xffff, false) 1213 | } 1214 | Brk6 => { 1215 | self.pc = ((self.data as u16) << 8) | (self.lo as u16); 1216 | self.flags |= 0x04; 1217 | self.insn_cycle = 0; 1218 | (self.pc, false) 1219 | } 1220 | _ => panic!("not yet implemented"), 1221 | }; 1222 | self.addr = addr; 1223 | self.is_write = is_write 1224 | } 1225 | 1226 | fn cond_branch(&mut self, cond: bool) -> (u16, bool) { 1227 | self.pc = self.pc.wrapping_add(1); 1228 | if cond { 1229 | self.lo = self.data; 1230 | } else { 1231 | self.insn_cycle = 0; 1232 | } 1233 | (self.pc, false) 1234 | } 1235 | } 1236 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::File; 3 | use std::io::Read; 4 | 5 | mod cpu; 6 | use cpu::{Bus, Cpu}; 7 | 8 | struct DebugBus { 9 | mem: [u8; 65536], 10 | } 11 | 12 | impl Bus for DebugBus { 13 | fn read(&mut self, addr: u16) -> u8 { 14 | let val = self.mem[addr as usize]; 15 | println!("rd {:04x} {:02x}", addr, val); 16 | val 17 | } 18 | 19 | fn write(&mut self, addr: u16, val: u8) { 20 | println!("wr {:04x} {:02x}", addr, val); 21 | self.mem[addr as usize] = val; 22 | } 23 | } 24 | 25 | fn main() { 26 | let args: Vec = env::args().collect(); 27 | if args.len() < 2 { 28 | println!("need bin arg"); 29 | return; 30 | } 31 | let mut f = File::open(&args[1]).expect("file not found"); 32 | let mut bin = Vec::new(); 33 | f.read_to_end(&mut bin).expect("read error"); 34 | println!("size = {}", bin.len()); 35 | let mut cpu = Cpu::new(); 36 | let mut debug_bus = DebugBus { 37 | mem: [0; 65536], 38 | }; 39 | debug_bus.mem.copy_from_slice(&bin); 40 | cpu.pc = 0x400; 41 | cpu.addr = 0x400; 42 | let mut last_insn_addr = 0; 43 | loop { 44 | cpu.do_bus(&mut debug_bus); 45 | cpu.print_state(); 46 | if cpu.insn_cycle == 1 { 47 | if cpu.addr == last_insn_addr { 48 | break; 49 | } 50 | last_insn_addr = cpu.addr; 51 | } 52 | cpu.cpu_clk_ucode(); 53 | } 54 | } 55 | --------------------------------------------------------------------------------