Zesty - a pin-accurate, cycle-accurate NES emulator written in Zig

cpu: all undocumented opcodes #4

merged opened by pluie.me targeting main from pluie/jj-tpnmozqyuktv
Labels

None yet.

Participants 1
AT URI
at://did:plc:e4f33w5yt2m54tq6vsagpwiu/sh.tangled.repo.pull/3lypmb2opee22
+549 -147
Diff #0
+493 -139
src/Cpu.zig
··· 106 106 107 107 // log.err("BOBER={x}", .{self.opcode}); 108 108 109 + @setEvalBranchQuota(2000); 109 110 const v = pins.cpu_data; 110 111 switch (self.opcode) { 111 112 0x00 => self.brk(pins), // BRK 112 113 0x01 => if (self.zpXInd(pins)) |_| self.ora(pins, v), // ORA (zp,X) 114 + 0x02 => if (self.imp(pins)) |_| self.hlt(pins), // *HLT 115 + 0x03 => if (self.zpXInd(pins)) |c| self.slo(pins, c), // *SLO (zp,X) 116 + 0x04 => if (self.zp(pins)) |_| self.fetch(pins), // *NOP zp 113 117 0x05 => if (self.zp(pins)) |_| self.ora(pins, v), // ORA zp 114 - 0x06 => if (self.zp(pins)) |_| self.asl(pins, .mem), // ASL zp 118 + 0x06 => if (self.zp(pins)) |c| self.asl(pins, c), // ASL zp 119 + 0x07 => if (self.zp(pins)) |c| self.slo(pins, c), // *SLO zp 115 120 0x08 => self.php(pins), // PHP 116 121 0x09 => if (self.imm(pins)) |_| self.ora(pins, v), // ORA # 117 - 0x0a => if (self.imm(pins)) |_| self.asl(pins, .acc), // ASL A 122 + 0x0a => if (self.imp(pins)) |_| self.asla(pins), // ASL A 123 + 0x0b => if (self.imm(pins)) |_| self.anc(pins), // *ANC # 124 + 0x0c => if (self.abs(pins)) |_| self.fetch(pins), // *NOP abs 118 125 0x0d => if (self.abs(pins)) |_| self.ora(pins, v), // ORA abs 119 - 0x0e => if (self.abs(pins)) |_| self.asl(pins, .mem), // ASL abs 126 + 0x0e => if (self.abs(pins)) |c| self.asl(pins, c), // ASL abs 127 + 0x0f => if (self.abs(pins)) |c| self.slo(pins, c), // *SLO abs 120 128 121 - 0x10 => if (self.imm(pins)) |_| self.branch(pins, !self.status.negative), // BPL 129 + 0x10 => if (self.imm(pins)) |_| self.branch(pins, !self.status.negative), // BPL # 122 130 0x11 => if (self.zpIndY(pins)) |_| self.ora(pins, v), // ORA (zp),Y 131 + 0x12 => if (self.imp(pins)) |_| self.hlt(pins), // *HLT 132 + 0x13 => if (self.zpIndY(pins)) |c| self.slo(pins, c), // *SLO (zp),Y 133 + 0x14 => if (self.zpOff(pins, self.x)) |_| self.fetch(pins), // *NOP zp,X 123 134 0x15 => if (self.zpOff(pins, self.x)) |_| self.ora(pins, v), // ORA zp,X 124 - 0x16 => if (self.zpOff(pins, self.x)) |_| self.asl(pins, .mem), // ASL zp,X 125 - 0x18 => self.set(pins, .carry, false), // CLC 135 + 0x16 => if (self.zpOff(pins, self.x)) |c| self.asl(pins, c), // ASL zp,X 136 + 0x17 => if (self.zpOff(pins, self.x)) |c| self.slo(pins, c), // *SLO zp,X 137 + 0x18 => if (self.imp(pins)) |_| self.set(pins, .carry, false), // CLC 126 138 0x19 => if (self.absOff(pins, self.y)) |_| self.ora(pins, v), // ORA abs,Y 139 + 0x1a => if (self.imp(pins)) |_| self.fetch(pins), // *NOP 140 + 0x1b => if (self.absOff(pins, self.y)) |c| self.slo(pins, c), // *SLO abs,Y 141 + 0x1c => if (self.absOff(pins, self.x)) |_| self.fetch(pins), // *NOP abs,X 127 142 0x1d => if (self.absOff(pins, self.x)) |_| self.ora(pins, v), // ORA abs,X 128 - 0x1e => if (self.absOff(pins, self.x)) |_| self.asl(pins, .mem), // ASL abs,X 143 + 0x1e => if (self.absOff(pins, self.x)) |c| self.asl(pins, c), // ASL abs,X 144 + 0x1f => if (self.absOff(pins, self.x)) |c| self.slo(pins, c), // *SLO abs,X 129 145 130 146 0x20 => self.jsr(pins), // JSR abs 131 147 0x21 => if (self.zpXInd(pins)) |_| self._and(pins, v), // AND (zp,X) 148 + 0x22 => if (self.imp(pins)) |_| self.hlt(pins), // *HLT 149 + 0x23 => if (self.zpXInd(pins)) |c| self.rla(pins, c), // *RLA (zp,X) 132 150 0x24 => if (self.zp(pins)) |_| self.bit(pins), // BIT zp 133 151 0x25 => if (self.zp(pins)) |_| self._and(pins, v), // AND zp 134 - 0x26 => if (self.zp(pins)) |_| self.rol(pins, .mem), // ROL zp 152 + 0x26 => if (self.zp(pins)) |c| self.rol(pins, c), // ROL zp 153 + 0x27 => if (self.zp(pins)) |c| self.rla(pins, c), // *RLA zp 135 154 0x28 => self.plp(pins), // PLP 136 155 0x29 => if (self.imm(pins)) |_| self._and(pins, v), // AND # 137 - 0x2a => if (self.imm(pins)) |_| self.rol(pins, .acc), // ROL A 156 + 0x2a => if (self.imp(pins)) |_| self.rola(pins), // ROL A 157 + 0x2b => if (self.imm(pins)) |_| self.anc(pins), // *ANC # 138 158 0x2c => if (self.abs(pins)) |_| self.bit(pins), // BIT abs 139 159 0x2d => if (self.abs(pins)) |_| self._and(pins, v), // AND abs 140 - 0x2e => if (self.abs(pins)) |_| self.rol(pins, .mem), // ROL abs 160 + 0x2e => if (self.abs(pins)) |c| self.rol(pins, c), // ROL abs 161 + 0x2f => if (self.abs(pins)) |c| self.rla(pins, c), // *RLA abs 141 162 142 - 0x30 => if (self.imm(pins)) |_| self.branch(pins, self.status.negative), // BMI 163 + 0x30 => if (self.imm(pins)) |_| self.branch(pins, self.status.negative), // BMI # 143 164 0x31 => if (self.zpIndY(pins)) |_| self._and(pins, v), // AND (zp),Y 165 + 0x32 => if (self.imp(pins)) |_| self.hlt(pins), // *HLT 166 + 0x33 => if (self.zpIndY(pins)) |c| self.rla(pins, c), // *RLA (zp),Y 167 + 0x34 => if (self.zpOff(pins, self.x)) |_| self.fetch(pins), // *NOP zp,X 144 168 0x35 => if (self.zpOff(pins, self.x)) |_| self._and(pins, v), // AND zp,X 145 - 0x36 => if (self.zpOff(pins, self.x)) |_| self.rol(pins, .mem), // ROL zp,X 146 - 0x38 => self.set(pins, .carry, true), // SEC 169 + 0x36 => if (self.zpOff(pins, self.x)) |c| self.rol(pins, c), // ROL zp,X 170 + 0x37 => if (self.zpOff(pins, self.x)) |c| self.rla(pins, c), // *RLA zp,X 171 + 0x38 => if (self.imp(pins)) |_| self.set(pins, .carry, true), // SEC 147 172 0x39 => if (self.absOff(pins, self.y)) |_| self._and(pins, v), // AND abs,Y 173 + 0x3a => if (self.imp(pins)) |_| self.fetch(pins), // *NOP 174 + 0x3b => if (self.absOff(pins, self.y)) |c| self.rla(pins, c), // *RLA abs,Y 175 + 0x3c => if (self.absOff(pins, self.x)) |_| self.fetch(pins), // *NOP abs,X 148 176 0x3d => if (self.absOff(pins, self.x)) |_| self._and(pins, v), // AND abs,X 149 - 0x3e => if (self.absOff(pins, self.x)) |_| self.rol(pins, .mem), // ROL abs,X 177 + 0x3e => if (self.absOff(pins, self.x)) |c| self.rol(pins, c), // ROL abs,X 178 + 0x3f => if (self.absOff(pins, self.x)) |c| self.rla(pins, c), // *RLA abs,X 150 179 151 180 0x40 => self.rti(pins), // RTI 152 181 0x41 => if (self.zpXInd(pins)) |_| self.eor(pins, v), // EOR (zp,X) 182 + 0x42 => if (self.imp(pins)) |_| self.hlt(pins), // *HLT 183 + 0x43 => if (self.zpXInd(pins)) |c| self.sre(pins, c), // *SRE (zp,X) 184 + 0x44 => if (self.zp(pins)) |_| self.fetch(pins), // *NOP zp 153 185 0x45 => if (self.zp(pins)) |_| self.eor(pins, v), // EOR zp 154 - 0x46 => if (self.zp(pins)) |_| self.lsr(pins, .mem), // LSR zp 186 + 0x46 => if (self.zp(pins)) |c| self.lsr(pins, c), // LSR zp 187 + 0x47 => if (self.zp(pins)) |c| self.sre(pins, c), // *SRE zp 155 188 0x48 => self.pha(pins), // PHA 156 189 0x49 => if (self.imm(pins)) |_| self.eor(pins, v), // EOR # 157 - 0x4a => if (self.imm(pins)) |_| self.lsr(pins, .acc), // LSR A 190 + 0x4a => if (self.imp(pins)) |_| self.lsra(pins), // LSR A 191 + 0x4b => if (self.imm(pins)) |_| self.alr(pins), // *ALR # 158 192 0x4c => self.jmp(pins), // JMP abs 159 193 0x4d => if (self.abs(pins)) |_| self.eor(pins, v), // EOR abs 160 - 0x4e => if (self.abs(pins)) |_| self.lsr(pins, .mem), // LSR abs 194 + 0x4e => if (self.abs(pins)) |c| self.lsr(pins, c), // LSR abs 195 + 0x4f => if (self.abs(pins)) |c| self.sre(pins, c), // *SRE abs 161 196 162 - 0x50 => if (self.imm(pins)) |_| self.branch(pins, !self.status.overflow), // BVC 197 + 0x50 => if (self.imp(pins)) |_| self.branch(pins, !self.status.overflow), // BVC # 163 198 0x51 => if (self.zpIndY(pins)) |_| self.eor(pins, v), // EOR (zp),Y 199 + 0x52 => if (self.imp(pins)) |_| self.hlt(pins), // *HLT 200 + 0x53 => if (self.zpIndY(pins)) |c| self.sre(pins, c), // *SRE (zp),Y 201 + 0x54 => if (self.zpOff(pins, self.x)) |_| self.fetch(pins), // *NOP zp,X 164 202 0x55 => if (self.zpOff(pins, self.x)) |_| self.eor(pins, v), // EOR zp,X 165 - 0x56 => if (self.zpOff(pins, self.x)) |_| self.lsr(pins, .mem), // LSR zp,X 166 - 0x58 => self.set(pins, .irq_disabled, false), // CLI 203 + 0x56 => if (self.zpOff(pins, self.x)) |c| self.lsr(pins, c), // LSR zp,X 204 + 0x57 => if (self.zpOff(pins, self.x)) |c| self.sre(pins, c), // *SRE zp,X 205 + 0x58 => if (self.imp(pins)) |_| self.set(pins, .irq_disabled, false), // CLI 167 206 0x59 => if (self.absOff(pins, self.y)) |_| self.eor(pins, v), // EOR abs,Y 207 + 0x5a => if (self.imp(pins)) |_| self.fetch(pins), // *NOP 208 + 0x5b => if (self.absOff(pins, self.y)) |c| self.sre(pins, c), // *SRE abs,Y 209 + 0x5c => if (self.absOff(pins, self.x)) |_| self.fetch(pins), // *NOP abs,X 168 210 0x5d => if (self.absOff(pins, self.x)) |_| self.eor(pins, v), // EOR abs,X 169 - 0x5e => if (self.absOff(pins, self.x)) |_| self.lsr(pins, .mem), // LSR abs,X 211 + 0x5e => if (self.absOff(pins, self.x)) |c| self.lsr(pins, c), // LSR abs,X 212 + 0x5f => if (self.absOff(pins, self.x)) |c| self.sre(pins, c), // *SRE abs,X 170 213 171 214 0x60 => self.rts(pins), // RTS 172 215 0x61 => if (self.zpXInd(pins)) |_| self.adc(pins, v), // ADC (zp,X) 216 + 0x62 => if (self.imp(pins)) |_| self.hlt(pins), // *HLT 217 + 0x63 => if (self.zpXInd(pins)) |c| self.rra(pins, c), // *RRA (zp,X) 218 + 0x64 => if (self.zp(pins)) |_| self.fetch(pins), // *NOP zp 173 219 0x65 => if (self.zp(pins)) |_| self.adc(pins, v), // ADC zp 174 - 0x66 => if (self.zp(pins)) |_| self.ror(pins, .mem), // ROR zp 220 + 0x66 => if (self.zp(pins)) |c| self.ror(pins, c), // ROR zp 221 + 0x67 => if (self.zp(pins)) |c| self.rra(pins, c), // *RRA zp 175 222 0x68 => self.pla(pins), // PLA 176 223 0x69 => if (self.imm(pins)) |_| self.adc(pins, v), // ADC # 177 - 0x6a => if (self.imm(pins)) |_| self.ror(pins, .acc), // ROR A 224 + 0x6a => if (self.imp(pins)) |_| self.rora(pins), // ROR A 225 + 0x6b => if (self.imm(pins)) |_| self.arr(pins), // *ARR # 178 226 0x6c => self.jmpInd(pins), // JMP (ind) 179 227 0x6d => if (self.abs(pins)) |_| self.adc(pins, v), // ADC abs 180 - 0x6e => if (self.abs(pins)) |_| self.ror(pins, .mem), // ROR abs 228 + 0x6e => if (self.abs(pins)) |c| self.ror(pins, c), // ROR abs 229 + 0x6f => if (self.abs(pins)) |c| self.rra(pins, c), // *RRA abs 181 230 182 - 0x70 => if (self.imm(pins)) |_| self.branch(pins, self.status.overflow), // BVS 231 + 0x70 => if (self.imm(pins)) |_| self.branch(pins, self.status.overflow), // BVS # 183 232 0x71 => if (self.zpIndY(pins)) |_| self.adc(pins, v), // ADC (zp),Y 233 + 0x72 => if (self.imp(pins)) |_| self.hlt(pins), // *HLT 234 + 0x73 => if (self.zpIndY(pins)) |c| self.rra(pins, c), // *RRA (zp),Y 235 + 0x74 => if (self.zpOff(pins, self.x)) |_| self.fetch(pins), // *NOP zp,X 184 236 0x75 => if (self.zpOff(pins, self.x)) |_| self.adc(pins, v), // ADC zp,X 185 - 0x76 => if (self.zpOff(pins, self.x)) |_| self.ror(pins, .mem), // ROR zp,X 186 - 0x78 => self.set(pins, .irq_disabled, true), // SEI 237 + 0x76 => if (self.zpOff(pins, self.x)) |c| self.ror(pins, c), // ROR zp,X 238 + 0x77 => if (self.zpOff(pins, self.x)) |c| self.rra(pins, c), // *RRA zp,X 239 + 0x78 => if (self.imp(pins)) |_| self.set(pins, .irq_disabled, true), // SEI 187 240 0x79 => if (self.absOff(pins, self.y)) |_| self.adc(pins, v), // ADC abs,Y 241 + 0x7a => if (self.imp(pins)) |_| self.fetch(pins), // *NOP 242 + 0x7b => if (self.absOff(pins, self.y)) |c| self.rra(pins, c), // *RRA abs,Y 243 + 0x7c => if (self.absOff(pins, self.x)) |_| self.fetch(pins), // *NOP abs,X 188 244 0x7d => if (self.absOff(pins, self.x)) |_| self.adc(pins, v), // ADC abs,X 189 - 0x7e => if (self.absOff(pins, self.x)) |_| self.ror(pins, .mem), // ROR abs,X 245 + 0x7e => if (self.absOff(pins, self.x)) |c| self.ror(pins, c), // ROR abs,X 246 + 0x7f => if (self.absOff(pins, self.x)) |c| self.rra(pins, c), // *RRA abs,X 190 247 248 + 0x80 => if (self.imm(pins)) |_| self.fetch(pins), // *NOP imm 191 249 0x81 => if (self.zpXInd(pins)) |_| self.st(pins, self.y), // STA (zp,X) 250 + 0x82 => if (self.imm(pins)) |_| self.fetch(pins), // *NOP imm 251 + 0x83 => if (self.zpXInd(pins)) |c| self.sax(pins, c), // *SAX (zp,X) 192 252 0x84 => if (self.zp(pins)) |_| self.st(pins, self.y), // STY zp 193 253 0x85 => if (self.zp(pins)) |_| self.st(pins, self.a), // STA zp 194 254 0x86 => if (self.zp(pins)) |_| self.st(pins, self.x), // STX zp 195 - 0x88 => if (self.imm(pins)) |_| self.dexy(pins, &self.y), // DEY 196 - 0x8a => if (self.imm(pins)) |_| self.ld(pins, &self.a, self.x), // TXA 255 + 0x87 => if (self.zp(pins)) |c| self.sax(pins, c), // *SAX zp 256 + 0x88 => if (self.imp(pins)) |_| self.dexy(pins, &self.y), // DEY 257 + 0x89 => if (self.imm(pins)) |_| self.fetch(pins), // *NOP imm 258 + 0x8a => if (self.imp(pins)) |_| self.ld(pins, &self.a, self.x), // TXA 259 + 0x8b => if (self.imm(pins)) |_| self.ane(pins), // *ANE # 197 260 0x8c => if (self.abs(pins)) |_| self.st(pins, self.y), // STY abs 198 261 0x8d => if (self.abs(pins)) |_| self.st(pins, self.a), // STA abs 199 262 0x8e => if (self.abs(pins)) |_| self.st(pins, self.x), // STX abs 263 + 0x8f => if (self.abs(pins)) |c| self.sax(pins, c), // *SAX abs 200 264 201 - 0x90 => if (self.imm(pins)) |_| self.branch(pins, !self.status.carry), // BCC 265 + 0x90 => if (self.imm(pins)) |_| self.branch(pins, !self.status.carry), // BCC # 202 266 0x91 => if (self.zpIndY(pins)) |_| self.ld(pins, &self.a, v), // STA (zp),Y 267 + 0x92 => if (self.imp(pins)) |_| self.hlt(pins), // *HLT 268 + 0x93 => if (self.zpIndY(pins)) |c| self.a11(pins, self.a & self.x, c), // *SHA (zp,Y) 203 269 0x94 => if (self.zpOff(pins, self.x)) |_| self.st(pins, self.y), // STY zp,X 204 270 0x95 => if (self.zpOff(pins, self.x)) |_| self.st(pins, self.a), // STA zp,X 205 271 0x96 => if (self.zpOff(pins, self.y)) |_| self.st(pins, self.x), // STX zp,Y 272 + 0x97 => if (self.zpOff(pins, self.y)) |c| self.sax(pins, c), // *SAX zp,Y 206 273 0x99 => if (self.absOff(pins, self.y)) |_| self.st(pins, self.a), // STA abs,Y 207 - 0x9a => if (self.imm(pins)) |_| self.ld(pins, &self.sp, self.x), // TXS 208 - 0x9c => if (self.absOff(pins, self.x)) |_| self.st(pins, self.y), // STY abs,X 274 + 0x9a => if (self.imp(pins)) |_| self.ld(pins, &self.sp, self.x), // TXS 275 + 0x9b => if (self.absOff(pins, self.y)) |c| self.tas(pins, c), // *TAS abs,Y 276 + 0x9c => if (self.absOff(pins, self.x)) |c| self.a11(pins, self.y, c), // *SHY abs,X 209 277 0x9d => if (self.absOff(pins, self.x)) |_| self.st(pins, self.a), // STA abs,X 210 - 0x9e => if (self.absOff(pins, self.y)) |_| self.st(pins, self.x), // STX abs,Y 278 + 0x9e => if (self.absOff(pins, self.y)) |c| self.a11(pins, self.x, c), // *SHX abs,Y 279 + 0x9f => if (self.absOff(pins, self.y)) |c| self.a11(pins, self.a & self.x, c), // *SHA abs,Y 211 280 212 281 0xa0 => if (self.imm(pins)) |_| self.ld(pins, &self.y, v), // LDY # 213 282 0xa1 => if (self.zpXInd(pins)) |_| self.ld(pins, &self.y, v), // LDA (zp,X) 214 283 0xa2 => if (self.imm(pins)) |_| self.ld(pins, &self.x, v), // LDX # 284 + 0xa3 => if (self.zpXInd(pins)) |c| self.dcp(pins, c), // *DCP (zp,X) 215 285 0xa4 => if (self.zp(pins)) |_| self.ld(pins, &self.y, v), // LDY zp 216 286 0xa5 => if (self.zp(pins)) |_| self.ld(pins, &self.a, v), // LDA zp 217 287 0xa6 => if (self.zp(pins)) |_| self.ld(pins, &self.x, v), // LDX zp 218 - 0xa8 => if (self.imm(pins)) |_| self.ld(pins, &self.y, self.a), // TAY 288 + 0xa7 => if (self.zp(pins)) |c| self.dcp(pins, c), // *DCP zp 289 + 0xa8 => if (self.imp(pins)) |_| self.ld(pins, &self.y, self.a), // TAY 219 290 0xa9 => if (self.imm(pins)) |_| self.ld(pins, &self.a, v), // LDA # 220 - 0xaa => if (self.imm(pins)) |_| self.ld(pins, &self.x, self.a), // TAX 291 + 0xaa => if (self.imp(pins)) |_| self.ld(pins, &self.x, self.a), // TAX 292 + 0xab => if (self.imm(pins)) |_| self.lxa(pins), // *LXA # 221 293 0xac => if (self.abs(pins)) |_| self.ld(pins, &self.y, v), // LDY abs 222 294 0xad => if (self.abs(pins)) |_| self.ld(pins, &self.a, v), // LDA abs 223 295 0xae => if (self.abs(pins)) |_| self.ld(pins, &self.x, v), // LDX abs 296 + 0xaf => if (self.abs(pins)) |c| self.dcp(pins, c), // *DCP abs 224 297 225 - 0xb0 => if (self.imm(pins)) |_| self.branch(pins, self.status.carry), // BCS 298 + 0xb0 => if (self.imm(pins)) |_| self.branch(pins, self.status.carry), // BCS # 226 299 0xb1 => if (self.zpIndY(pins)) |_| self.ld(pins, &self.a, v), // LDA (zp),Y 300 + 0xb2 => if (self.imp(pins)) |_| self.hlt(pins), // *HLT 301 + 0xb3 => if (self.zpIndY(pins)) |c| self.dcp(pins, c), // *DCP (zp),Y 227 302 0xb4 => if (self.zpOff(pins, self.x)) |_| self.ld(pins, &self.y, v), // LDY zp,X 228 303 0xb5 => if (self.zpOff(pins, self.x)) |_| self.ld(pins, &self.a, v), // LDA zp,X 229 304 0xb6 => if (self.zpOff(pins, self.y)) |_| self.ld(pins, &self.x, v), // LDX zp,Y 230 - 0xb8 => self.set(pins, .overflow, true), // SEV 305 + 0xb7 => if (self.zpOff(pins, self.y)) |c| self.dcp(pins, c), // *DCP zp,Y 306 + 0xb8 => if (self.imp(pins)) |_| self.set(pins, .overflow, true), // SEV 231 307 0xb9 => if (self.absOff(pins, self.y)) |_| self.ld(pins, &self.a, v), // LDA abs,Y 232 - 0xba => if (self.imm(pins)) |_| self.ld(pins, &self.x, self.sp), // TSX 308 + 0xba => if (self.imp(pins)) |_| self.ld(pins, &self.x, self.sp), // TSX 309 + 0xbb => if (self.absOff(pins, self.y)) |_| self.las(pins), // *LAS abs,Y 233 310 0xbc => if (self.absOff(pins, self.x)) |_| self.ld(pins, &self.y, v), // LDY abs,X 234 311 0xbd => if (self.absOff(pins, self.x)) |_| self.ld(pins, &self.a, v), // LDA abs,X 235 312 0xbe => if (self.absOff(pins, self.y)) |_| self.ld(pins, &self.x, v), // LDX abs,Y 313 + 0xbf => if (self.absOff(pins, self.y)) |c| self.dcp(pins, c), // *DCP abs,Y 236 314 237 315 0xc0 => if (self.imm(pins)) |_| self.cmp(pins, self.y), // CPY # 238 316 0xc1 => if (self.zpXInd(pins)) |_| self.cmp(pins, self.a), // CMP (zp,X) 317 + 0xc2 => if (self.imm(pins)) |_| self.fetch(pins), // *NOP imm 318 + 0xc3 => if (self.zpXInd(pins)) |c| self.dcp(pins, c), // *DCP (zp,X) 239 319 0xc4 => if (self.zp(pins)) |_| self.cmp(pins, self.y), // CPY zp 240 320 0xc5 => if (self.zp(pins)) |_| self.cmp(pins, self.a), // CMP zp 241 321 0xc6 => if (self.zp(pins)) |c| self.dec(pins, c), // DEC zp 242 - 0xc8 => if (self.imm(pins)) |_| self.inxy(pins, &self.y), // INY 322 + 0xc7 => if (self.zp(pins)) |c| self.dcp(pins, c), // *DCP zp 323 + 0xc8 => if (self.imp(pins)) |_| self.inxy(pins, &self.y), // INY 243 324 0xc9 => if (self.imm(pins)) |_| self.cmp(pins, self.a), // CMP # 244 - 0xca => if (self.imm(pins)) |_| self.dexy(pins, &self.x), // DEY 325 + 0xca => if (self.imp(pins)) |_| self.dexy(pins, &self.x), // DEX 245 326 0xcc => if (self.abs(pins)) |_| self.cmp(pins, self.y), // CPY abs 327 + 0xcb => if (self.imm(pins)) |_| self.las(pins), // *SBX # 246 328 0xcd => if (self.abs(pins)) |_| self.cmp(pins, self.a), // CMP abs 247 329 0xce => if (self.abs(pins)) |c| self.dec(pins, c), // DEC abs 330 + 0xcf => if (self.abs(pins)) |c| self.dcp(pins, c), // *DCP abs 248 331 249 - 0xd0 => if (self.imm(pins)) |_| self.branch(pins, !self.status.zero), // BNE 332 + 0xd0 => if (self.imm(pins)) |_| self.branch(pins, !self.status.zero), // BNE # 250 333 0xd1 => if (self.zpIndY(pins)) |_| self.cmp(pins, self.a), // CMP (zp),Y 334 + 0xd2 => if (self.imp(pins)) |_| self.hlt(pins), // *HLT 335 + 0xd3 => if (self.zpIndY(pins)) |c| self.dcp(pins, c), // *DCP (zp),Y 336 + 0xd4 => if (self.zpOff(pins, self.x)) |_| self.fetch(pins), // *NOP zp,X 251 337 0xd5 => if (self.zpOff(pins, self.x)) |_| self.cmp(pins, self.a), // CMP zp,X 252 338 0xd6 => if (self.zpOff(pins, self.x)) |c| self.dec(pins, c), // DEC zp,X 253 - 0xd8 => self.set(pins, .decimal, false), // CLD 339 + 0xd7 => if (self.zpOff(pins, self.x)) |c| self.dcp(pins, c), // *DCP zp,X 340 + 0xd8 => if (self.imp(pins)) |_| self.set(pins, .decimal, false), // CLD 254 341 0xd9 => if (self.absOff(pins, self.y)) |_| self.cmp(pins, self.a), // CMP abs,Y 342 + 0xda => if (self.imp(pins)) |_| self.fetch(pins), // *NOP 343 + 0xdb => if (self.absOff(pins, self.y)) |c| self.dcp(pins, c), // *DCP abs,Y 344 + 0xdc => if (self.absOff(pins, self.x)) |_| self.fetch(pins), // *NOP abs,X 255 345 0xdd => if (self.absOff(pins, self.x)) |_| self.cmp(pins, self.a), // CMP abs,X 256 346 0xde => if (self.absOff(pins, self.x)) |c| self.dec(pins, c), // DEC abs,X 347 + 0xdf => if (self.absOff(pins, self.x)) |c| self.dcp(pins, c), // *DCP abs,X 257 348 258 349 0xe0 => if (self.imm(pins)) |_| self.cmp(pins, self.x), // CPX # 259 350 0xe1 => if (self.zpXInd(pins)) |_| self.sbc(pins, v), // SBC (zp,X) 351 + 0xe2 => if (self.imm(pins)) |_| self.fetch(pins), // *NOP imm 352 + 0xe3 => if (self.zpXInd(pins)) |c| self.isc(pins, c), // *ISC (zp,X) 260 353 0xe4 => if (self.zp(pins)) |_| self.cmp(pins, self.x), // CPX zp 261 354 0xe5 => if (self.zp(pins)) |_| self.sbc(pins, v), // SBC zp 262 355 0xe6 => if (self.zp(pins)) |c| self.inc(pins, c), // INC zp 263 - 0xe8 => if (self.imm(pins)) |_| self.inxy(pins, &self.x), // INX 356 + 0xe7 => if (self.zp(pins)) |c| self.isc(pins, c), // *ISC zp 357 + 0xe8 => if (self.imp(pins)) |_| self.inxy(pins, &self.x), // INX 264 358 0xe9 => if (self.imm(pins)) |_| self.sbc(pins, v), // SBC # 265 - 0xea => if (self.imm(pins)) |_| self.fetch(pins), // NOP 359 + 0xea => if (self.imp(pins)) |_| self.fetch(pins), // NOP 360 + 0xeb => if (self.imm(pins)) |_| self.sbc(pins, v), // *SBC # 266 361 0xec => if (self.abs(pins)) |_| self.cmp(pins, self.x), // CPX abs 267 362 0xed => if (self.abs(pins)) |_| self.sbc(pins, v), // SBC abs 268 363 0xee => if (self.abs(pins)) |c| self.inc(pins, c), // INC abs 364 + 0xef => if (self.abs(pins)) |c| self.isc(pins, c), // *ISC abs 269 365 270 - 0xf0 => if (self.imm(pins)) |_| self.branch(pins, self.status.zero), // BEQ 366 + 0xf0 => if (self.imm(pins)) |_| self.branch(pins, self.status.zero), // BEQ # 271 367 0xf1 => if (self.zpIndY(pins)) |_| self.sbc(pins, v), // SBC (zp),Y 368 + 0xf2 => if (self.imp(pins)) |_| self.hlt(pins), // *HLT 369 + 0xf3 => if (self.zpIndY(pins)) |c| self.isc(pins, c), // *ISC (zp),Y 370 + 0xf4 => if (self.zpOff(pins, self.x)) |_| self.fetch(pins), // *NOP zp,X 272 371 0xf5 => if (self.zpOff(pins, self.x)) |_| self.sbc(pins, v), // SBC zp,X 273 372 0xf6 => if (self.zpOff(pins, self.x)) |c| self.inc(pins, c), // INC zp,X 274 - 0xf8 => self.set(pins, .decimal, true), // SED 373 + 0xf7 => if (self.zpOff(pins, self.x)) |c| self.isc(pins, c), // *ISC zp,X 374 + 0xf8 => if (self.imp(pins)) |_| self.set(pins, .decimal, true), // SED 275 375 0xf9 => if (self.absOff(pins, self.y)) |_| self.sbc(pins, v), // SBC abs,Y 376 + 0xfa => if (self.imp(pins)) |_| self.fetch(pins), // *NOP 377 + 0xfb => if (self.absOff(pins, self.y)) |c| self.isc(pins, c), // *ISC abs,Y 378 + 0xfc => if (self.absOff(pins, self.x)) |_| self.fetch(pins), // *NOP abs,X 276 379 0xfd => if (self.absOff(pins, self.x)) |_| self.sbc(pins, v), // SBC abs,X 277 380 0xfe => if (self.absOff(pins, self.x)) |c| self.inc(pins, c), // INC abs,X 381 + 0xff => if (self.absOff(pins, self.x)) |c| self.isc(pins, c), // *ISC abs,X 278 382 279 - else => { 280 - log.err("UNHANDLED OP={X}", .{self.opcode}); 281 - self.fetch(pins); 282 - }, 383 + else => unreachable, 283 384 } 284 385 } 285 386 387 + inline fn imp(self: *Cpu, pins: *zesty.Pins) ?u3 { 388 + switch (self.cycle) { 389 + 0 => { 390 + pins.cpu_addr = self.pc; 391 + }, 392 + else => return self.cycle - 1, 393 + } 394 + return null; 395 + } 286 396 inline fn imm(self: *Cpu, pins: *zesty.Pins) ?u3 { 287 397 switch (self.cycle) { 288 398 0 => { ··· 433 543 434 544 inline fn ld(self: *Cpu, pins: *zesty.Pins, to: *u8, from: u8) void { 435 545 to.* = from; 436 - self.setNZ(to.*); 546 + self.status.setNZ(to.*); 437 547 self.fetch(pins); 438 548 } 439 549 inline fn st(self: *Cpu, pins: *zesty.Pins, from: u8) void { ··· 486 596 } 487 597 inline fn pla(self: *Cpu, pins: *zesty.Pins) void { 488 598 self.a = self.pull(pins) orelse return; 489 - self.setNZ(self.a); 599 + self.status.setNZ(self.a); 490 600 } 491 601 inline fn plp(self: *Cpu, pins: *zesty.Pins) void { 492 602 const status: Status = .from(self.pull(pins) orelse return); ··· 504 614 //------------------------------------------------------ 505 615 // Opcodes: Arithmetic 506 616 507 - const Dst = enum { acc, mem }; 617 + inline fn _adc(a: u8, b: u8, status: *Status) u8 { 618 + var result, var carry = @addWithOverflow(a, @intFromBool(status.carry)); 619 + // TODO: implement optional support for decimal mode 620 + result, carry = @addWithOverflow(result, b); 621 + 622 + status.carry = carry > 0; 623 + status.setNZ(result); 624 + // Overflow bit is set if both inputs have the same sign, 625 + // and the output has a different sign 626 + status.overflow = ~(a ^ b) & (a ^ result) & 0x80 > 0; 627 + return result; 628 + } 629 + inline fn _sbc(a: u8, b: u8, status: *Status) u8 { 630 + return _adc(a, ~b, status); 631 + } 632 + inline fn _cmp(a: u8, b: u8, status: *Status) u8 { 633 + // a CMP is basically a SBC in disguise 634 + const result, const carry = @addWithOverflow(a, ~b +% 1); 635 + status.carry = carry > 0; 636 + status.setNZ(result); 637 + return result; 638 + } 639 + 640 + inline fn _asl(a: u8, comptime rotate: bool, status: *Status) u8 { 641 + var v, const carry = @shlWithOverflow(a, 1); 642 + if (rotate) v |= @intFromBool(status.carry); 643 + status.carry = carry > 0; 644 + status.setNZ(v); 645 + return v; 646 + } 647 + inline fn _lsr(a: u8, comptime rotate: bool, status: *Status) u8 { 648 + // There's no @shrWithOverflow :( 649 + var v = a >> 1; 650 + if (rotate and status.carry) v |= 0x80; 651 + status.carry = a & 1 > 0; 652 + status.setNZ(v); 653 + return v; 654 + } 655 + 508 656 inline fn ora(self: *Cpu, pins: *zesty.Pins, v: u8) void { 509 657 self.a |= v; 510 - self.setNZ(self.a); 658 + self.status.setNZ(self.a); 511 659 self.fetch(pins); 512 660 } 513 661 inline fn _and(self: *Cpu, pins: *zesty.Pins, v: u8) void { 514 662 self.a &= v; 515 - self.setNZ(self.a); 663 + self.status.setNZ(self.a); 516 664 self.fetch(pins); 517 665 } 518 666 inline fn eor(self: *Cpu, pins: *zesty.Pins, v: u8) void { 519 667 self.a ^= v; 520 - self.setNZ(self.a); 668 + self.status.setNZ(self.a); 521 669 self.fetch(pins); 522 670 } 523 - inline fn asl(self: *Cpu, pins: *zesty.Pins, comptime dst: Dst) void { 524 - const v, self.status.carry = switch (dst) { 525 - .acc => v: { 526 - self.a, const carry = @shlWithOverflow(self.a, 1); 527 - break :v .{ self.a, carry > 0 }; 528 - }, 529 - .mem => v: { 530 - pins.cpu_data, const carry = @shlWithOverflow(pins.cpu_data, 1); 671 + inline fn asl(self: *Cpu, pins: *zesty.Pins, c: u3) void { 672 + switch (c) { 673 + 0 => { 674 + pins.cpu_data = _asl(pins.cpu_data, false, &self.status); 531 675 pins.cpu_rw = .write; 532 - break :v .{ pins.cpu_data, carry > 0 }; 533 676 }, 534 - }; 535 - self.setNZ(v); 536 - self.fetch(pins); 677 + else => self.fetch(pins), 678 + } 537 679 } 538 - inline fn lsr(self: *Cpu, pins: *zesty.Pins, comptime dst: Dst) void { 539 - // There's no @shrWithOverflow :( 540 - const v, self.status.carry = switch (dst) { 541 - .acc => v: { 542 - const carry = self.a & 0b1; 543 - self.a >>= 1; 544 - break :v .{ self.a, carry > 0 }; 545 - }, 546 - .mem => v: { 547 - const carry = pins.cpu_data & 0b1; 548 - pins.cpu_data >>= 1; 680 + inline fn rol(self: *Cpu, pins: *zesty.Pins, c: u3) void { 681 + switch (c) { 682 + 0 => { 683 + pins.cpu_data = _asl(pins.cpu_data, true, &self.status); 549 684 pins.cpu_rw = .write; 550 - break :v .{ pins.cpu_data, carry > 0 }; 551 685 }, 552 - }; 553 - 554 - self.setNZ(v); 555 - self.fetch(pins); 686 + else => self.fetch(pins), 687 + } 556 688 } 557 - inline fn rol(self: *Cpu, pins: *zesty.Pins, comptime dst: Dst) void { 558 - const v, self.status.carry = switch (dst) { 559 - .acc => v: { 560 - self.a, const carry = @shlWithOverflow(self.a, 1); 561 - self.a |= @intFromBool(self.status.carry); 562 - break :v .{ self.a, carry > 0 }; 563 - }, 564 - .mem => v: { 565 - pins.cpu_data, const carry = @shlWithOverflow(pins.cpu_data, 1); 566 - pins.cpu_data |= @intFromBool(self.status.carry); 689 + inline fn lsr(self: *Cpu, pins: *zesty.Pins, c: u3) void { 690 + switch (c) { 691 + 0 => { 692 + pins.cpu_data = _lsr(pins.cpu_data, false, &self.status); 693 + self.status.setNZ(pins.cpu_data); 567 694 pins.cpu_rw = .write; 568 - break :v .{ pins.cpu_data, carry > 0 }; 569 695 }, 570 - }; 571 - 572 - self.setNZ(v); 573 - self.fetch(pins); 696 + else => self.fetch(pins), 697 + } 574 698 } 575 - inline fn ror(self: *Cpu, pins: *zesty.Pins, comptime dst: Dst) void { 576 - const v, self.status.carry = switch (dst) { 577 - .acc => v: { 578 - const carry = self.a & 1; 579 - self.a >>= 1; 580 - if (self.status.carry) self.a |= 0b1000_0000; 581 - break :v .{ self.a, carry > 0 }; 582 - }, 583 - .mem => v: { 584 - const carry = pins.cpu_data & 1; 585 - pins.cpu_data >>= 1; 586 - if (self.status.carry) pins.cpu_data |= 0b1000_0000; 699 + inline fn ror(self: *Cpu, pins: *zesty.Pins, c: u3) void { 700 + switch (c) { 701 + 0 => { 702 + pins.cpu_data = _lsr(pins.cpu_data, true, &self.status); 703 + self.status.setNZ(pins.cpu_data); 587 704 pins.cpu_rw = .write; 588 - break :v .{ pins.cpu_data, carry > 0 }; 589 705 }, 590 - }; 591 - 592 - self.setNZ(v); 706 + else => self.fetch(pins), 707 + } 708 + } 709 + inline fn asla(self: *Cpu, pins: *zesty.Pins) void { 710 + self.a = _asl(self.a, false, &self.status); 711 + self.status.setNZ(self.a); 712 + self.fetch(pins); 713 + } 714 + inline fn rola(self: *Cpu, pins: *zesty.Pins) void { 715 + self.a = _asl(self.a, true, &self.status); 716 + self.status.setNZ(self.a); 717 + self.fetch(pins); 718 + } 719 + inline fn lsra(self: *Cpu, pins: *zesty.Pins) void { 720 + self.a = _lsr(self.a, false, &self.status); 721 + self.status.setNZ(self.a); 722 + self.fetch(pins); 723 + } 724 + inline fn rora(self: *Cpu, pins: *zesty.Pins) void { 725 + self.a = _lsr(self.a, true, &self.status); 726 + self.status.setNZ(self.a); 593 727 self.fetch(pins); 594 728 } 595 729 inline fn adc(self: *Cpu, pins: *zesty.Pins, v: u8) void { 596 - var result, var carry = @addWithOverflow(self.a, @intFromBool(self.status.carry)); 597 - // TODO: implement optional support for decimal mode 598 - result, carry = @addWithOverflow(result, v); 599 - 600 - self.status.carry = carry > 0; 601 - self.setNZ(result); 602 - // Overflow bit is set if both inputs have the same sign, 603 - // and the output has a different sign 604 - self.status.overflow = ~(self.a ^ v) & (self.a ^ result) & 0x80 > 0; 605 - self.a = result; 730 + self.a = _adc(self.a, v, &self.status); 606 731 self.fetch(pins); 607 732 } 608 733 inline fn sbc(self: *Cpu, pins: *zesty.Pins, v: u8) void { 609 - self.adc(pins, ~v); 734 + self.a = _sbc(self.a, v, &self.status); 735 + self.fetch(pins); 610 736 } 611 737 inline fn cmp(self: *Cpu, pins: *zesty.Pins, v: u8) void { 612 - // a CMP is basically a SBC in disguise 613 - const result, const carry = @addWithOverflow(v, ~pins.cpu_data +% 1); 614 - self.status.carry = carry > 0; 615 - self.setNZ(result); 738 + _ = _cmp(v, pins.cpu_data, &self.status); 616 739 self.fetch(pins); 617 740 } 618 741 inline fn inxy(self: *Cpu, pins: *zesty.Pins, v: *u8) void { 619 742 v.* +%= 1; 620 - self.setNZ(v.*); 743 + self.status.setNZ(v.*); 621 744 self.fetch(pins); 622 745 } 623 746 624 747 inline fn dexy(self: *Cpu, pins: *zesty.Pins, v: *u8) void { 625 748 v.* -%= 1; 626 - self.setNZ(v.*); 749 + self.status.setNZ(v.*); 627 750 self.fetch(pins); 628 751 } 629 752 inline fn inc(self: *Cpu, pins: *zesty.Pins, c: u3) void { ··· 635 758 }, 636 759 1 => { 637 760 self.hilo.lo +%= 1; 638 - self.setNZ(self.hilo.lo); 761 + self.status.setNZ(self.hilo.lo); 639 762 pins.cpu_data = self.hilo.lo; 640 763 pins.cpu_rw = .write; 641 764 }, ··· 651 774 }, 652 775 1 => { 653 776 self.hilo.lo -%= 1; 654 - self.setNZ(self.hilo.lo); 777 + self.status.setNZ(self.hilo.lo); 655 778 pins.cpu_data = self.hilo.lo; 656 779 pins.cpu_rw = .write; 657 780 }, ··· 938 1061 } 939 1062 940 1063 //------------------------------------------------------ 941 - // Helpers 1064 + // Opcodes: Undocumented 1065 + 1066 + /// This seems like the most common "magic" value for ANE and LXA. 1067 + /// I genuinely hope nobody depends on this. 1068 + /// You shouldn't, anyway, since on real hardware 1069 + /// this apparently changes depending on temperature?? 1070 + const undocumented_magic: u8 = 0xee; 1071 + 1072 + /// HLT (halt) 1073 + inline fn hlt(self: *Cpu, pins: *zesty.Pins) void { 1074 + // Stuck 1075 + pins.cpu_addr = 0xffff; 1076 + pins.cpu_data = 0xff; 1077 + self.cycle -= 1; 1078 + } 1079 + /// ALR (AND + LSR) 1080 + inline fn alr(self: *Cpu, pins: *zesty.Pins) void { 1081 + self.a &= pins.cpu_data; 1082 + self.a = _lsr(self.a, false, &self.status); 1083 + self.fetch(pins); 1084 + } 1085 + /// ANC (AND, set C) 1086 + inline fn anc(self: *Cpu, pins: *zesty.Pins) void { 1087 + self.a &= pins.cpu_data; 1088 + self.status.carry = self.a >= 0x80; 1089 + self.status.setNZ(self.a); 1090 + self.fetch(pins); 1091 + } 1092 + /// ANE/XAA, aka The One Unstable Opcode 1093 + /// See https://www.nesdev.org/wiki/Visual6502wiki/6502_Opcode_8B_(XAA,_ANE) 1094 + inline fn ane(self: *Cpu, pins: *zesty.Pins) void { 1095 + self.a = (self.a | undocumented_magic) & self.x & pins.cpu_data; 1096 + self.status.setNZ(self.a); 1097 + self.fetch(pins); 1098 + } 1099 + /// ARR (AND + ROR) 1100 + inline fn arr(self: *Cpu, pins: *zesty.Pins) void { 1101 + // The behavior of these flags is cursed AF. 1102 + // Kudos to https://github.com/floooh/chips for expressing 1103 + // this in emulator-friendly form 1104 + self.a >>= 1; 1105 + if (self.status.carry) self.a |= 0x80; 1106 + self.status.setNZ(self.a); 1107 + 1108 + if (self.a & 0x40 > 0) { 1109 + self.status.overflow = true; 1110 + self.status.carry = true; 1111 + } 1112 + if (self.a & 0x20 > 0) { 1113 + self.status.overflow = !self.status.overflow; 1114 + } 1115 + self.fetch(pins); 1116 + } 1117 + /// DCP (DEC + CMP) 1118 + inline fn dcp(self: *Cpu, pins: *zesty.Pins, c: u3) void { 1119 + switch (c) { 1120 + 0 => { 1121 + // Dummy write 1122 + self.hilo = .{ .lo = pins.cpu_data }; 1123 + pins.cpu_rw = .write; 1124 + }, 1125 + 1 => { 1126 + self.hilo.lo -%= 1; 1127 + pins.cpu_data = self.hilo.lo; 1128 + pins.cpu_rw = .write; 1129 + _ = _cmp(self.a, pins.cpu_data, &self.status); 1130 + }, 1131 + else => self.fetch(pins), 1132 + } 1133 + } 1134 + /// ISC (INC + SBC) 1135 + inline fn isc(self: *Cpu, pins: *zesty.Pins, c: u3) void { 1136 + switch (c) { 1137 + 0 => { 1138 + // Dummy write 1139 + self.hilo = .{ .lo = pins.cpu_data }; 1140 + pins.cpu_rw = .write; 1141 + }, 1142 + 1 => { 1143 + self.hilo.lo +%= 1; 1144 + pins.cpu_data = self.hilo.lo; 1145 + pins.cpu_rw = .write; 1146 + self.a = _sbc(self.a, self.hilo.lo, &self.status); 1147 + }, 1148 + else => self.fetch(pins), 1149 + } 1150 + } 1151 + /// LAS (LDA + TSX) 1152 + inline fn las(self: *Cpu, pins: *zesty.Pins) void { 1153 + self.sp &= pins.cpu_data; 1154 + self.a = self.sp; 1155 + self.x = self.sp; 1156 + self.status.setNZ(self.a); 1157 + self.fetch(pins); 1158 + } 1159 + /// LAX (LDA + LDX) 1160 + inline fn lax(self: *Cpu, pins: *zesty.Pins) void { 1161 + self.a = pins.cpu_data; 1162 + self.x = pins.cpu_data; 1163 + self.status.setNZ(self.a); 1164 + self.fetch(pins); 1165 + } 1166 + /// LXA (LAX immediate) 1167 + /// Highly magical. See ANE 1168 + inline fn lxa(self: *Cpu, pins: *zesty.Pins) void { 1169 + self.a = (self.a | undocumented_magic) & pins.cpu_data; 1170 + self.x = self.a; 1171 + self.status.setNZ(self.a); 1172 + self.fetch(pins); 1173 + } 1174 + /// RLA (ROL + AND) 1175 + inline fn rla(self: *Cpu, pins: *zesty.Pins, c: u3) void { 1176 + switch (c) { 1177 + 0 => { 1178 + // Dummy write 1179 + self.hilo = .{ .lo = pins.cpu_data }; 1180 + pins.cpu_rw = .write; 1181 + }, 1182 + 1 => { 1183 + pins.cpu_data = self.hilo.lo; 1184 + 1185 + pins.cpu_data, const carry = @shlWithOverflow(pins.cpu_data, 1); 1186 + pins.cpu_data |= @intFromBool(self.status.carry); 1187 + pins.cpu_rw = .write; 1188 + 1189 + self.a &= self.hilo.lo; 1190 + self.status.setNZ(self.a); 1191 + self.status.carry = carry > 0; 1192 + }, 1193 + else => self.fetch(pins), 1194 + } 1195 + } 1196 + /// RRA (ROR + AND) 1197 + inline fn rra(self: *Cpu, pins: *zesty.Pins, c: u3) void { 1198 + switch (c) { 1199 + 0 => { 1200 + // Dummy write 1201 + self.hilo = .{ .lo = pins.cpu_data }; 1202 + pins.cpu_rw = .write; 1203 + }, 1204 + 1 => { 1205 + pins.cpu_data = self.hilo.lo; 1206 + 1207 + self.status.carry = pins.cpu_data & 1 > 0; 1208 + pins.cpu_data >>= 1; 1209 + if (self.status.carry) pins.cpu_data |= 0b1000_0000; 1210 + pins.cpu_rw = .write; 1211 + 1212 + self.a &= pins.cpu_data; 1213 + self.status.setNZ(self.a); 1214 + }, 1215 + else => self.fetch(pins), 1216 + } 1217 + } 1218 + /// SAX 1219 + inline fn sax(self: *Cpu, pins: *zesty.Pins, c: u3) void { 1220 + switch (c) { 1221 + 0 => { 1222 + pins.cpu_data = self.a & self.x; 1223 + pins.cpu_rw = .write; 1224 + }, 1225 + else => self.fetch(pins), 1226 + } 1227 + } 1228 + /// SBX (CMP, DEX) 1229 + inline fn sbx(self: *Cpu, pins: *zesty.Pins) void { 1230 + self.x = _cmp(self.x & self.a, pins.cpu_data, &self.status); 1231 + self.fetch(pins); 1232 + } 1233 + /// SHA, SHX, SHY (A11) 1234 + /// Even though the high byte may be dropped on real 6502 CPUs, 1235 + /// here I choose to add them unconditionally. 1236 + inline fn a11(self: *Cpu, pins: *zesty.Pins, v: u8, c: u3) void { 1237 + switch (c) { 1238 + 0 => { 1239 + const pc: Addr = .from(self.pc); 1240 + pins.cpu_data = v & (pc.hi +% 1); 1241 + pins.cpu_rw = .write; 1242 + }, 1243 + else => self.fetch(pins), 1244 + } 1245 + } 1246 + /// SLO (ASL + ORA) 1247 + inline fn slo(self: *Cpu, pins: *zesty.Pins, c: u3) void { 1248 + switch (c) { 1249 + 0 => { 1250 + self.hilo.lo = pins.cpu_data; 1251 + pins.cpu_rw = .write; 1252 + }, 1253 + 1 => { 1254 + pins.cpu_data = _asl(self.hilo.lo, false, &self.status); 1255 + self.a |= pins.cpu_data; 1256 + self.status.setNZ(self.a); 1257 + pins.cpu_rw = .write; 1258 + }, 1259 + else => self.fetch(pins), 1260 + } 1261 + } 1262 + /// SRE (LSR + EOR) 1263 + inline fn sre(self: *Cpu, pins: *zesty.Pins, c: u3) void { 1264 + switch (c) { 1265 + 0 => { 1266 + self.hilo.lo = pins.cpu_data; 1267 + pins.cpu_rw = .write; 1268 + }, 1269 + 1 => { 1270 + pins.cpu_data = _lsr(self.hilo.lo, false, &self.status); 1271 + self.a ^= pins.cpu_data; 1272 + self.status.setNZ(self.a); 1273 + pins.cpu_rw = .write; 1274 + }, 1275 + else => self.fetch(pins), 1276 + } 1277 + } 1278 + /// TAS 1279 + /// Unstable. See A11 1280 + inline fn tas(self: *Cpu, pins: *zesty.Pins, c: u3) void { 1281 + switch (c) { 1282 + 0 => { 1283 + const pc: Addr = .from(self.pc); 1284 + const v = self.a & self.x; 942 1285 943 - inline fn setNZ(self: *Cpu, v: u8) void { 944 - self.status.zero = v == 0; 945 - self.status.negative = v >= 0x80; 1286 + self.sp = v; 1287 + pins.cpu_data = v & (pc.hi +% 1); 1288 + pins.cpu_rw = .write; 1289 + }, 1290 + else => self.fetch(pins), 1291 + } 946 1292 } 947 1293 1294 + //------------------------------------------------------ 1295 + // Helpers 1296 + 948 1297 pub const Status = packed struct(u8) { 949 1298 carry: bool = false, 950 1299 zero: bool = false, ··· 966 1315 return @bitCast(v); 967 1316 } 968 1317 1318 + inline fn setNZ(self: *Status, v: u8) void { 1319 + self.zero = v == 0; 1320 + self.negative = v >= 0x80; 1321 + } 1322 + 969 1323 pub fn format( 970 1324 self: Status, 971 1325 writer: *std.Io.Writer,
+1
src/tests/cpu.zig
··· 10 10 _ = @import("cpu/alu.zig"); 11 11 _ = @import("cpu/control_flow.zig"); 12 12 _ = @import("cpu/stack.zig"); 13 + _ = @import("cpu/undocumented.zig"); 13 14 } 14 15 15 16 //------------------------------------------------------
+8 -8
src/tests/cpu/alu.zig
··· 64 64 } }); 65 65 cpu.run(&z); // Setup A register 66 66 cpu.run(&z); 67 - try std.testing.expectEqual(0x8004, z.cpu.pc); 67 + try std.testing.expectEqual(0x8003, z.cpu.pc); 68 68 try std.testing.expectEqual(0b00001010, z.cpu.a); 69 69 try std.testing.expect(!z.cpu.status.negative); 70 70 try std.testing.expect(!z.cpu.status.zero); ··· 81 81 } }); 82 82 cpu.run(&z); // Setup A register 83 83 cpu.run(&z); 84 - try std.testing.expectEqual(0x8004, z.cpu.pc); 84 + try std.testing.expectEqual(0x8003, z.cpu.pc); 85 85 try std.testing.expectEqual(0b01000010, z.cpu.a); 86 86 try std.testing.expect(!z.cpu.status.negative); 87 87 try std.testing.expect(!z.cpu.status.zero); ··· 103 103 cpu.run(&z); // Set carry 104 104 cpu.run(&z); 105 105 106 - try std.testing.expectEqual(0x8005, z.cpu.pc); 106 + try std.testing.expectEqual(0x8004, z.cpu.pc); 107 107 try std.testing.expectEqual(0b00001011, z.cpu.a); 108 108 try std.testing.expect(!z.cpu.status.negative); 109 109 try std.testing.expect(!z.cpu.status.zero); ··· 125 125 cpu.run(&z); // Set carry 126 126 cpu.run(&z); 127 127 128 - try std.testing.expectEqual(0x8005, z.cpu.pc); 128 + try std.testing.expectEqual(0x8004, z.cpu.pc); 129 129 try std.testing.expectEqual(0b11000010, z.cpu.a); 130 130 try std.testing.expect(z.cpu.status.negative); 131 131 try std.testing.expect(!z.cpu.status.zero); ··· 211 211 }, 212 212 }); 213 213 cpu.run(&z); 214 - try std.testing.expectEqual(0x8002, z.cpu.pc); 214 + try std.testing.expectEqual(0x8001, z.cpu.pc); 215 215 try std.testing.expectEqual(0b11111111, z.cpu.x); 216 216 try std.testing.expect(z.cpu.status.negative); 217 217 try std.testing.expect(!z.cpu.status.zero); ··· 228 228 }, 229 229 }); 230 230 cpu.run(&z); 231 - try std.testing.expectEqual(0x8002, z.cpu.pc); 231 + try std.testing.expectEqual(0x8001, z.cpu.pc); 232 232 try std.testing.expectEqual(0b11111111, z.cpu.y); 233 233 try std.testing.expect(z.cpu.status.negative); 234 234 try std.testing.expect(!z.cpu.status.zero); ··· 265 265 }, 266 266 }); 267 267 cpu.run(&z); 268 - try std.testing.expectEqual(0x8002, z.cpu.pc); 268 + try std.testing.expectEqual(0x8001, z.cpu.pc); 269 269 try std.testing.expectEqual(0b00000001, z.cpu.x); 270 270 try std.testing.expect(!z.cpu.status.negative); 271 271 try std.testing.expect(!z.cpu.status.zero); ··· 282 282 }, 283 283 }); 284 284 cpu.run(&z); 285 - try std.testing.expectEqual(0x8002, z.cpu.pc); 285 + try std.testing.expectEqual(0x8001, z.cpu.pc); 286 286 try std.testing.expectEqual(0b00000001, z.cpu.y); 287 287 try std.testing.expect(!z.cpu.status.negative); 288 288 try std.testing.expect(!z.cpu.status.zero);
+47
src/tests/cpu/undocumented.zig
··· 1 + //! Tests about undocumented opcodes. 2 + const std = @import("std"); 3 + const cpu = @import("../cpu.zig"); 4 + 5 + test "HLT" { 6 + // These opcodes all kill the CPU. 7 + const ops = [_]u8{ 8 + 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, // 9 + 0x62, 0x72, 0x92, 0xb2, 0xd2, 0xf2, 10 + }; 11 + 12 + for (ops) |op| { 13 + var z = cpu.testZes(.{ 14 + .init_cpu = false, 15 + .rom = &.{ 16 + .{ 0x8000, &.{op} }, 17 + }, 18 + }); 19 + while (!z.cpu.sync) z.stepCpu(); // Boot cycle 20 + 21 + z.stepCpu(); // First cycle is fine 22 + 23 + for (0..3) |_| { 24 + z.stepCpu(); // Stuck! 25 + try std.testing.expectEqual(0xffff, z.pins.cpu_addr); 26 + } 27 + } 28 + } 29 + 30 + test "NOPs" { 31 + var z = cpu.testZes(.{ 32 + .init_cpu = false, 33 + .rom = &.{ 34 + .{ 35 + 0x8000, &.{ 36 + 0x1a, 0x3a, 0x5a, 0x7a, 0xda, 0xfa, // implied 37 + 0x80, 0x82, 0x89, 0xc2, 0xe2, // immediate 38 + 0x04, 0x44, 0x64, // zp 39 + 0x14, 0x34, 0x54, 0x74, 0xd4, 0xf4, // zp,X 40 + 0x0c, // abs 41 + 0x1c, 0x3c, 0x5c, 0x7c, 0xdc, 0xfc, // abs,X 42 + }, 43 + }, 44 + }, 45 + }); 46 + while (!z.cpu.status.brk) z.stepCpu(); 47 + }

History

1 round 0 comments
sign up or login to add to the discussion
pluie.me submitted #0
1 commit
expand
cpu: all undocumented opcodes
expand 0 comments
pull request successfully merged