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

cpu: finish ALU impl #1

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/3lyo7elkecv22
+768 -149
Diff #0
+256 -144
src/Cpu.zig
··· 109 109 const v = pins.cpu_data; 110 110 switch (self.opcode) { 111 111 0x00 => self.brk(pins), // BRK 112 - 113 - 0x01 => if (self.zpXInd(pins)) self.ora(pins, v), // ORA (zp,X) 114 - 0x05 => if (self.zp(pins)) self.ora(pins, v), // ORA zp 115 - 0x06 => if (self.zp(pins)) self.asl(pins, .mem), // ASL zp 116 - 0x09 => if (self.imm(pins)) self.ora(pins, v), // ORA # 117 - 0x0a => if (self.imm(pins)) self.asl(pins, .acc), // ASL A 118 - 0x0d => if (self.abs(pins)) self.ora(pins, v), // ORA abs 119 - 0x0e => if (self.abs(pins)) self.asl(pins, .mem), // ASL abs 120 - 121 - 0x10 => if (self.imm(pins)) self.branch(pins, !self.status.negative), // BPL 122 - 0x11 => if (self.zpIndY(pins)) self.ora(pins, v), // ORA (zp),Y 123 - 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 112 + 0x01 => if (self.zpXInd(pins)) |_| self.ora(pins, v), // ORA (zp,X) 113 + 0x05 => if (self.zp(pins)) |_| self.ora(pins, v), // ORA zp 114 + 0x06 => if (self.zp(pins)) |_| self.asl(pins, .mem), // ASL zp 115 + 0x09 => if (self.imm(pins)) |_| self.ora(pins, v), // ORA # 116 + 0x0a => if (self.imm(pins)) |_| self.asl(pins, .acc), // ASL A 117 + 0x0d => if (self.abs(pins)) |_| self.ora(pins, v), // ORA abs 118 + 0x0e => if (self.abs(pins)) |_| self.asl(pins, .mem), // ASL abs 119 + 120 + 0x10 => if (self.imm(pins)) |_| self.branch(pins, !self.status.negative), // BPL 121 + 0x11 => if (self.zpIndY(pins)) |_| self.ora(pins, v), // ORA (zp),Y 122 + 0x15 => if (self.zpOff(pins, self.x)) |_| self.ora(pins, v), // ORA zp,X 123 + 0x16 => if (self.zpOff(pins, self.x)) |_| self.asl(pins, .mem), // ASL zp,X 125 124 0x18 => self.set(pins, .carry, false), // CLC 126 - 0x19 => if (self.absOff(pins, self.y)) self.ora(pins, v), // ORA abs,Y 127 - 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 129 - 130 - 0x21 => if (self.zpXInd(pins)) self._and(pins, v), // AND (zp,X) 131 - 0x25 => if (self.zp(pins)) self._and(pins, v), // AND zp 132 - 0x26 => if (self.zp(pins)) self.rol(pins, .mem), // ROL zp 133 - 0x29 => if (self.imm(pins)) self._and(pins, v), // AND # 134 - 0x2a => if (self.imm(pins)) self.rol(pins, .acc), // ROL A 135 - 0x2d => if (self.abs(pins)) self._and(pins, v), // AND abs 136 - 0x2e => if (self.abs(pins)) self.rol(pins, .mem), // ROL abs 137 - 138 - 0x30 => if (self.imm(pins)) self.branch(pins, self.status.negative), // BMI 139 - 0x31 => if (self.zpIndY(pins)) self._and(pins, v), // AND (zp),Y 140 - 0x35 => if (self.zpOff(pins, self.x)) self._and(pins, v), // AND zp,X 141 - 0x36 => if (self.zpOff(pins, self.x)) self.rol(pins, .mem), // ROL zp,X 125 + 0x19 => if (self.absOff(pins, self.y)) |_| self.ora(pins, v), // ORA abs,Y 126 + 0x1d => if (self.absOff(pins, self.x)) |_| self.ora(pins, v), // ORA abs,X 127 + 0x1e => if (self.absOff(pins, self.x)) |_| self.asl(pins, .mem), // ASL abs,X 128 + 129 + 0x21 => if (self.zpXInd(pins)) |_| self._and(pins, v), // AND (zp,X) 130 + 0x24 => if (self.zp(pins)) |_| self.bit(pins), // BIT zp 131 + 0x25 => if (self.zp(pins)) |_| self._and(pins, v), // AND zp 132 + 0x26 => if (self.zp(pins)) |_| self.rol(pins, .mem), // ROL zp 133 + 0x29 => if (self.imm(pins)) |_| self._and(pins, v), // AND # 134 + 0x2a => if (self.imm(pins)) |_| self.rol(pins, .acc), // ROL A 135 + 0x2c => if (self.abs(pins)) |_| self.bit(pins), // BIT abs 136 + 0x2d => if (self.abs(pins)) |_| self._and(pins, v), // AND abs 137 + 0x2e => if (self.abs(pins)) |_| self.rol(pins, .mem), // ROL abs 138 + 139 + 0x30 => if (self.imm(pins)) |_| self.branch(pins, self.status.negative), // BMI 140 + 0x31 => if (self.zpIndY(pins)) |_| self._and(pins, v), // AND (zp),Y 141 + 0x35 => if (self.zpOff(pins, self.x)) |_| self._and(pins, v), // AND zp,X 142 + 0x36 => if (self.zpOff(pins, self.x)) |_| self.rol(pins, .mem), // ROL zp,X 142 143 0x38 => self.set(pins, .carry, true), // SEC 143 - 0x39 => if (self.absOff(pins, self.y)) self._and(pins, v), // AND abs,Y 144 - 0x3d => if (self.absOff(pins, self.x)) self._and(pins, v), // AND abs,X 145 - 0x3e => if (self.absOff(pins, self.x)) self.rol(pins, .mem), // ROL abs,X 144 + 0x39 => if (self.absOff(pins, self.y)) |_| self._and(pins, v), // AND abs,Y 145 + 0x3d => if (self.absOff(pins, self.x)) |_| self._and(pins, v), // AND abs,X 146 + 0x3e => if (self.absOff(pins, self.x)) |_| self.rol(pins, .mem), // ROL abs,X 146 147 147 148 0x40 => self.rti(pins), // RTI 148 - 0x41 => if (self.zpXInd(pins)) self.eor(pins, v), // EOR (zp,X) 149 - 0x45 => if (self.zp(pins)) self.eor(pins, v), // EOR zp 150 - 0x46 => if (self.zp(pins)) self.lsr(pins, .mem), // LSR zp 151 - 0x49 => if (self.imm(pins)) self.eor(pins, v), // EOR # 152 - 0x4a => if (self.imm(pins)) self.lsr(pins, .acc), // LSR A 153 - 0x4d => if (self.abs(pins)) self.eor(pins, v), // EOR abs 154 - 0x4e => if (self.abs(pins)) self.lsr(pins, .mem), // LSR abs 155 - 156 - 0x50 => if (self.imm(pins)) self.branch(pins, !self.status.overflow), // BVC 157 - 0x51 => if (self.zpIndY(pins)) self.eor(pins, v), // EOR (zp),Y 158 - 0x55 => if (self.zpOff(pins, self.x)) self.eor(pins, v), // EOR zp,X 159 - 0x56 => if (self.zpOff(pins, self.x)) self.lsr(pins, .mem), // LSR zp,X 149 + 0x41 => if (self.zpXInd(pins)) |_| self.eor(pins, v), // EOR (zp,X) 150 + 0x45 => if (self.zp(pins)) |_| self.eor(pins, v), // EOR zp 151 + 0x46 => if (self.zp(pins)) |_| self.lsr(pins, .mem), // LSR zp 152 + 0x49 => if (self.imm(pins)) |_| self.eor(pins, v), // EOR # 153 + 0x4a => if (self.imm(pins)) |_| self.lsr(pins, .acc), // LSR A 154 + 0x4d => if (self.abs(pins)) |_| self.eor(pins, v), // EOR abs 155 + 0x4e => if (self.abs(pins)) |_| self.lsr(pins, .mem), // LSR abs 156 + 157 + 0x50 => if (self.imm(pins)) |_| self.branch(pins, !self.status.overflow), // BVC 158 + 0x51 => if (self.zpIndY(pins)) |_| self.eor(pins, v), // EOR (zp),Y 159 + 0x55 => if (self.zpOff(pins, self.x)) |_| self.eor(pins, v), // EOR zp,X 160 + 0x56 => if (self.zpOff(pins, self.x)) |_| self.lsr(pins, .mem), // LSR zp,X 160 161 0x58 => self.set(pins, .irq_disabled, false), // CLI 161 - 0x59 => if (self.absOff(pins, self.y)) self.eor(pins, v), // EOR abs,Y 162 - 0x5d => if (self.absOff(pins, self.x)) self.eor(pins, v), // EOR abs,X 163 - 0x5e => if (self.absOff(pins, self.x)) self.lsr(pins, .mem), // LSR abs,X 164 - 165 - // 0x61 => if (self.zpXInd(pins)) self.adc(pins, v), // ADC (zp,X) 166 - // 0x65 => if (self.zp(pins)) self.adc(pins, v), // ADC zp 167 - 0x66 => if (self.zp(pins)) self.ror(pins, .mem), // ROR zp 168 - // 0x69 => if (self.imm(pins)) self.adc(pins, v), // ADC # 169 - 0x6a => if (self.imm(pins)) self.ror(pins, .acc), // ROR A 170 - // 0x6d => if (self.abs(pins)) self.adc(pins, v), // ADC abs 171 - 0x6e => if (self.abs(pins)) self.ror(pins, .mem), // ROR abs 172 - 173 - 0x70 => if (self.imm(pins)) self.branch(pins, self.status.overflow), // BVS 174 - // 0x71 => if (self.zpIndY(pins)) self.adc(pins, v), // ADC (zp),Y 175 - // 0x75 => if (self.zpOff(pins, self.x)) self.adc(pins, v), // ADC zp,X 176 - 0x76 => if (self.zpOff(pins, self.x)) self.ror(pins, .mem), // ROR zp,X 162 + 0x59 => if (self.absOff(pins, self.y)) |_| self.eor(pins, v), // EOR abs,Y 163 + 0x5d => if (self.absOff(pins, self.x)) |_| self.eor(pins, v), // EOR abs,X 164 + 0x5e => if (self.absOff(pins, self.x)) |_| self.lsr(pins, .mem), // LSR abs,X 165 + 166 + 0x61 => if (self.zpXInd(pins)) |_| self.adc(pins, v), // ADC (zp,X) 167 + 0x65 => if (self.zp(pins)) |_| self.adc(pins, v), // ADC zp 168 + 0x66 => if (self.zp(pins)) |_| self.ror(pins, .mem), // ROR zp 169 + 0x69 => if (self.imm(pins)) |_| self.adc(pins, v), // ADC # 170 + 0x6a => if (self.imm(pins)) |_| self.ror(pins, .acc), // ROR A 171 + 0x6d => if (self.abs(pins)) |_| self.adc(pins, v), // ADC abs 172 + 0x6e => if (self.abs(pins)) |_| self.ror(pins, .mem), // ROR abs 173 + 174 + 0x70 => if (self.imm(pins)) |_| self.branch(pins, self.status.overflow), // BVS 175 + 0x71 => if (self.zpIndY(pins)) |_| self.adc(pins, v), // ADC (zp),Y 176 + 0x75 => if (self.zpOff(pins, self.x)) |_| self.adc(pins, v), // ADC zp,X 177 + 0x76 => if (self.zpOff(pins, self.x)) |_| self.ror(pins, .mem), // ROR zp,X 177 178 0x78 => self.set(pins, .irq_disabled, true), // SEI 178 - // 0x79 => if (self.absOff(pins, self.y)) self.adc(pins, v), // ADC abs,Y 179 - // 0x7d => if (self.absOff(pins, self.x)) self.adc(pins, v), // ADC abs,X 180 - 0x7e => if (self.absOff(pins, self.x)) self.ror(pins, .mem), // ROR abs,X 181 - 182 - 0x81 => if (self.zpXInd(pins)) self.st(pins, self.y), // STA (zp,X) 183 - 0x84 => if (self.zp(pins)) self.st(pins, self.y), // STY zp 184 - 0x85 => if (self.zp(pins)) self.st(pins, self.a), // STA zp 185 - 0x86 => if (self.zp(pins)) self.st(pins, self.x), // STX zp 186 - 0x88 => if (self.imm(pins)) self.dec(pins, &self.y), // DEY 187 - 0x8a => if (self.imm(pins)) self.ld(pins, &self.a, self.x), // TXA 188 - 0x8c => if (self.abs(pins)) self.st(pins, self.y), // STY abs 189 - 0x8d => if (self.abs(pins)) self.st(pins, self.a), // STA abs 190 - 0x8e => if (self.abs(pins)) self.st(pins, self.x), // STX abs 191 - 192 - 0x90 => if (self.imm(pins)) self.branch(pins, !self.status.carry), // BCC 193 - 0x91 => if (self.zpIndY(pins)) self.ld(pins, &self.a, v), // STA (zp),Y 194 - 0x94 => if (self.zpOff(pins, self.x)) self.st(pins, self.y), // STY zp,X 195 - 0x95 => if (self.zpOff(pins, self.x)) self.st(pins, self.a), // STA zp,X 196 - 0x96 => if (self.zpOff(pins, self.y)) self.st(pins, self.x), // STX zp,Y 197 - 0x99 => if (self.absOff(pins, self.y)) self.st(pins, self.a), // STA abs,Y 198 - 0x9a => if (self.imm(pins)) self.ld(pins, &self.sp, self.x), // TXS 199 - 0x9c => if (self.absOff(pins, self.x)) self.st(pins, self.y), // STY abs,X 200 - 0x9d => if (self.absOff(pins, self.x)) self.st(pins, self.a), // STA abs,X 201 - 0x9e => if (self.absOff(pins, self.y)) self.st(pins, self.x), // STX abs,Y 202 - 203 - 0xa0 => if (self.imm(pins)) self.ld(pins, &self.y, v), // LDY # 204 - 0xa1 => if (self.zpXInd(pins)) self.ld(pins, &self.y, v), // LDA (zp,X) 205 - 0xa2 => if (self.imm(pins)) self.ld(pins, &self.x, v), // LDX # 206 - 0xa4 => if (self.zp(pins)) self.ld(pins, &self.y, v), // LDY zp 207 - 0xa5 => if (self.zp(pins)) self.ld(pins, &self.a, v), // LDA zp 208 - 0xa6 => if (self.zp(pins)) self.ld(pins, &self.x, v), // LDX zp 209 - 0xa8 => if (self.imm(pins)) self.ld(pins, &self.y, self.a), // TAY 210 - 0xa9 => if (self.imm(pins)) self.ld(pins, &self.a, v), // LDA # 211 - 0xaa => if (self.imm(pins)) self.ld(pins, &self.x, self.a), // TAX 212 - 0xac => if (self.abs(pins)) self.ld(pins, &self.y, v), // LDY abs 213 - 0xad => if (self.abs(pins)) self.ld(pins, &self.a, v), // LDA abs 214 - 0xae => if (self.abs(pins)) self.ld(pins, &self.x, v), // LDX abs 215 - 216 - 0xb0 => if (self.imm(pins)) self.branch(pins, self.status.carry), // BCS 217 - 0xb1 => if (self.zpIndY(pins)) self.ld(pins, &self.a, v), // LDA (zp),Y 218 - 0xb4 => if (self.zpOff(pins, self.x)) self.ld(pins, &self.y, v), // LDY zp,X 219 - 0xb5 => if (self.zpOff(pins, self.x)) self.ld(pins, &self.a, v), // LDA zp,X 220 - 0xb6 => if (self.zpOff(pins, self.y)) self.ld(pins, &self.x, v), // LDX zp,Y 179 + 0x79 => if (self.absOff(pins, self.y)) |_| self.adc(pins, v), // ADC abs,Y 180 + 0x7d => if (self.absOff(pins, self.x)) |_| self.adc(pins, v), // ADC abs,X 181 + 0x7e => if (self.absOff(pins, self.x)) |_| self.ror(pins, .mem), // ROR abs,X 182 + 183 + 0x81 => if (self.zpXInd(pins)) |_| self.st(pins, self.y), // STA (zp,X) 184 + 0x84 => if (self.zp(pins)) |_| self.st(pins, self.y), // STY zp 185 + 0x85 => if (self.zp(pins)) |_| self.st(pins, self.a), // STA zp 186 + 0x86 => if (self.zp(pins)) |_| self.st(pins, self.x), // STX zp 187 + 0x88 => if (self.imm(pins)) |_| self.dexy(pins, &self.y), // DEY 188 + 0x8a => if (self.imm(pins)) |_| self.ld(pins, &self.a, self.x), // TXA 189 + 0x8c => if (self.abs(pins)) |_| self.st(pins, self.y), // STY abs 190 + 0x8d => if (self.abs(pins)) |_| self.st(pins, self.a), // STA abs 191 + 0x8e => if (self.abs(pins)) |_| self.st(pins, self.x), // STX abs 192 + 193 + 0x90 => if (self.imm(pins)) |_| self.branch(pins, !self.status.carry), // BCC 194 + 0x91 => if (self.zpIndY(pins)) |_| self.ld(pins, &self.a, v), // STA (zp),Y 195 + 0x94 => if (self.zpOff(pins, self.x)) |_| self.st(pins, self.y), // STY zp,X 196 + 0x95 => if (self.zpOff(pins, self.x)) |_| self.st(pins, self.a), // STA zp,X 197 + 0x96 => if (self.zpOff(pins, self.y)) |_| self.st(pins, self.x), // STX zp,Y 198 + 0x99 => if (self.absOff(pins, self.y)) |_| self.st(pins, self.a), // STA abs,Y 199 + 0x9a => if (self.imm(pins)) |_| self.ld(pins, &self.sp, self.x), // TXS 200 + 0x9c => if (self.absOff(pins, self.x)) |_| self.st(pins, self.y), // STY abs,X 201 + 0x9d => if (self.absOff(pins, self.x)) |_| self.st(pins, self.a), // STA abs,X 202 + 0x9e => if (self.absOff(pins, self.y)) |_| self.st(pins, self.x), // STX abs,Y 203 + 204 + 0xa0 => if (self.imm(pins)) |_| self.ld(pins, &self.y, v), // LDY # 205 + 0xa1 => if (self.zpXInd(pins)) |_| self.ld(pins, &self.y, v), // LDA (zp,X) 206 + 0xa2 => if (self.imm(pins)) |_| self.ld(pins, &self.x, v), // LDX # 207 + 0xa4 => if (self.zp(pins)) |_| self.ld(pins, &self.y, v), // LDY zp 208 + 0xa5 => if (self.zp(pins)) |_| self.ld(pins, &self.a, v), // LDA zp 209 + 0xa6 => if (self.zp(pins)) |_| self.ld(pins, &self.x, v), // LDX zp 210 + 0xa8 => if (self.imm(pins)) |_| self.ld(pins, &self.y, self.a), // TAY 211 + 0xa9 => if (self.imm(pins)) |_| self.ld(pins, &self.a, v), // LDA # 212 + 0xaa => if (self.imm(pins)) |_| self.ld(pins, &self.x, self.a), // TAX 213 + 0xac => if (self.abs(pins)) |_| self.ld(pins, &self.y, v), // LDY abs 214 + 0xad => if (self.abs(pins)) |_| self.ld(pins, &self.a, v), // LDA abs 215 + 0xae => if (self.abs(pins)) |_| self.ld(pins, &self.x, v), // LDX abs 216 + 217 + 0xb0 => if (self.imm(pins)) |_| self.branch(pins, self.status.carry), // BCS 218 + 0xb1 => if (self.zpIndY(pins)) |_| self.ld(pins, &self.a, v), // LDA (zp),Y 219 + 0xb4 => if (self.zpOff(pins, self.x)) |_| self.ld(pins, &self.y, v), // LDY zp,X 220 + 0xb5 => if (self.zpOff(pins, self.x)) |_| self.ld(pins, &self.a, v), // LDA zp,X 221 + 0xb6 => if (self.zpOff(pins, self.y)) |_| self.ld(pins, &self.x, v), // LDX zp,Y 221 222 0xb8 => self.set(pins, .overflow, true), // SEV 222 - 0xb9 => if (self.absOff(pins, self.y)) self.ld(pins, &self.a, v), // LDA abs,Y 223 - 0xba => if (self.imm(pins)) self.ld(pins, &self.x, self.sp), // TSX 224 - 0xbc => if (self.absOff(pins, self.x)) self.ld(pins, &self.y, v), // LDY abs,X 225 - 0xbd => if (self.absOff(pins, self.x)) self.ld(pins, &self.a, v), // LDA abs,X 226 - 0xbe => if (self.absOff(pins, self.y)) self.ld(pins, &self.x, v), // LDX abs,Y 227 - 228 - 0xd0 => if (self.imm(pins)) self.branch(pins, !self.status.zero), // BNE 223 + 0xb9 => if (self.absOff(pins, self.y)) |_| self.ld(pins, &self.a, v), // LDA abs,Y 224 + 0xba => if (self.imm(pins)) |_| self.ld(pins, &self.x, self.sp), // TSX 225 + 0xbc => if (self.absOff(pins, self.x)) |_| self.ld(pins, &self.y, v), // LDY abs,X 226 + 0xbd => if (self.absOff(pins, self.x)) |_| self.ld(pins, &self.a, v), // LDA abs,X 227 + 0xbe => if (self.absOff(pins, self.y)) |_| self.ld(pins, &self.x, v), // LDX abs,Y 228 + 229 + 0xc0 => if (self.imm(pins)) |_| self.cmp(pins, self.y), // CPY # 230 + 0xc1 => if (self.zpXInd(pins)) |_| self.cmp(pins, self.a), // CMP (zp,X) 231 + 0xc4 => if (self.zp(pins)) |_| self.cmp(pins, self.y), // CPY zp 232 + 0xc5 => if (self.zp(pins)) |_| self.cmp(pins, self.a), // CMP zp 233 + 0xc6 => if (self.zp(pins)) |c| self.dec(pins, c), // DEC zp 234 + 0xc8 => if (self.imm(pins)) |_| self.inxy(pins, &self.y), // INY 235 + 0xc9 => if (self.imm(pins)) |_| self.cmp(pins, self.a), // CMP # 236 + 0xca => if (self.imm(pins)) |_| self.dexy(pins, &self.x), // DEY 237 + 0xcc => if (self.abs(pins)) |_| self.cmp(pins, self.y), // CPY abs 238 + 0xcd => if (self.abs(pins)) |_| self.cmp(pins, self.a), // CMP abs 239 + 0xce => if (self.abs(pins)) |c| self.dec(pins, c), // DEC abs 240 + 241 + 0xd0 => if (self.imm(pins)) |_| self.branch(pins, !self.status.zero), // BNE 242 + 0xd1 => if (self.zpIndY(pins)) |_| self.cmp(pins, self.a), // CMP (zp),Y 243 + 0xd5 => if (self.zpOff(pins, self.x)) |_| self.cmp(pins, self.a), // CMP zp,X 244 + 0xd6 => if (self.zpOff(pins, self.x)) |c| self.dec(pins, c), // DEC zp,X 229 245 0xd8 => self.set(pins, .decimal, false), // CLD 230 - 231 - 0xea => if (self.imm(pins)) self.fetch(pins), // NOP 232 - 233 - 0xf0 => if (self.imm(pins)) self.branch(pins, self.status.zero), // BEQ 246 + 0xd9 => if (self.absOff(pins, self.y)) |_| self.cmp(pins, self.a), // CMP abs,Y 247 + 0xdd => if (self.absOff(pins, self.x)) |_| self.cmp(pins, self.a), // CMP abs,X 248 + 0xde => if (self.absOff(pins, self.x)) |c| self.dec(pins, c), // DEC abs,X 249 + 250 + 0xe0 => if (self.imm(pins)) |_| self.cmp(pins, self.x), // CPX # 251 + 0xe1 => if (self.zpXInd(pins)) |_| self.sbc(pins, v), // SBC (zp,X) 252 + 0xe4 => if (self.zp(pins)) |_| self.cmp(pins, self.x), // CPX zp 253 + 0xe5 => if (self.zp(pins)) |_| self.sbc(pins, v), // SBC zp 254 + 0xe6 => if (self.zp(pins)) |c| self.inc(pins, c), // INC zp 255 + 0xe8 => if (self.imm(pins)) |_| self.inxy(pins, &self.x), // INX 256 + 0xe9 => if (self.imm(pins)) |_| self.sbc(pins, v), // SBC # 257 + 0xea => if (self.imm(pins)) |_| self.fetch(pins), // NOP 258 + 0xec => if (self.abs(pins)) |_| self.cmp(pins, self.x), // CPX abs 259 + 0xed => if (self.abs(pins)) |_| self.sbc(pins, v), // SBC abs 260 + 0xee => if (self.abs(pins)) |c| self.inc(pins, c), // INC abs 261 + 262 + 0xf0 => if (self.imm(pins)) |_| self.branch(pins, self.status.zero), // BEQ 263 + 0xf1 => if (self.zpIndY(pins)) |_| self.sbc(pins, v), // SBC (zp),Y 264 + 0xf5 => if (self.zpOff(pins, self.x)) |_| self.sbc(pins, v), // SBC zp,X 265 + 0xf6 => if (self.zpOff(pins, self.x)) |c| self.inc(pins, c), // INC zp,X 234 266 0xf8 => self.set(pins, .decimal, true), // SED 267 + 0xf9 => if (self.absOff(pins, self.y)) |_| self.sbc(pins, v), // SBC abs,Y 268 + 0xfd => if (self.absOff(pins, self.x)) |_| self.sbc(pins, v), // SBC abs,X 269 + 0xfe => if (self.absOff(pins, self.x)) |c| self.inc(pins, c), // INC abs,X 235 270 236 - else => log.err("UNHANDLED OP={X}", .{self.opcode}), 271 + else => { 272 + log.err("UNHANDLED OP={X}", .{self.opcode}); 273 + self.fetch(pins); 274 + }, 237 275 } 238 276 } 239 277 240 - inline fn imm(self: *Cpu, pins: *zesty.Pins) bool { 278 + inline fn imm(self: *Cpu, pins: *zesty.Pins) ?u3 { 241 279 switch (self.cycle) { 242 280 0 => { 243 281 self.pc +%= 1; 244 282 pins.cpu_addr = self.pc; 245 283 }, 246 - else => return true, 284 + else => return self.cycle - 1, 247 285 } 248 - return false; 286 + return null; 249 287 } 250 - inline fn zp(self: *Cpu, pins: *zesty.Pins) bool { 288 + inline fn zp(self: *Cpu, pins: *zesty.Pins) ?u3 { 251 289 switch (self.cycle) { 252 290 0 => { 253 291 self.pc +%= 1; ··· 257 295 self.hilo = .{ .lo = pins.cpu_data }; 258 296 pins.cpu_addr = self.hilo.addr(); 259 297 }, 260 - else => return true, 298 + else => return self.cycle - 2, 261 299 } 262 - return false; 300 + return null; 263 301 } 264 - inline fn zpOff(self: *Cpu, pins: *zesty.Pins, v: u8) bool { 302 + inline fn zpOff(self: *Cpu, pins: *zesty.Pins, v: u8) ?u3 { 265 303 switch (self.cycle) { 266 304 0 => { 267 305 self.pc +%= 1; ··· 275 313 self.hilo.lo +%= v; 276 314 pins.cpu_addr = self.hilo.addr(); 277 315 }, 278 - else => return true, 316 + else => return self.cycle - 3, 279 317 } 280 - return false; 318 + return null; 281 319 } 282 - inline fn abs(self: *Cpu, pins: *zesty.Pins) bool { 320 + inline fn abs(self: *Cpu, pins: *zesty.Pins) ?u3 { 283 321 switch (self.cycle) { 284 322 0 => { 285 323 self.pc +%= 1; ··· 294 332 self.hilo.hi = pins.cpu_data; 295 333 pins.cpu_addr = self.hilo.addr(); 296 334 }, 297 - else => return true, 335 + else => return self.cycle - 3, 298 336 } 299 - return false; 337 + return null; 300 338 } 301 - inline fn absOff(self: *Cpu, pins: *zesty.Pins, v: u8) bool { 339 + inline fn absOff(self: *Cpu, pins: *zesty.Pins, v: u8) ?u3 { 302 340 switch (self.cycle) { 303 341 0 => { 304 342 self.pc +%= 1; ··· 317 355 3 => { 318 356 pins.cpu_addr = self.hilo.addr(); 319 357 }, 320 - else => return true, 358 + else => return self.cycle - 4, 321 359 } 322 - return false; 360 + return null; 323 361 } 324 - inline fn zpXInd(self: *Cpu, pins: *zesty.Pins) bool { 362 + inline fn zpXInd(self: *Cpu, pins: *zesty.Pins) ?u3 { 325 363 switch (self.cycle) { 326 364 0 => { 327 365 self.pc +%= 1; ··· 344 382 self.hilo.hi = pins.cpu_data; 345 383 pins.cpu_addr = self.hilo.addr(); 346 384 }, 347 - else => return true, 385 + else => return self.cycle - 5, 348 386 } 349 - return false; 387 + return null; 350 388 } 351 - inline fn zpIndY(self: *Cpu, pins: *zesty.Pins) bool { 389 + inline fn zpIndY(self: *Cpu, pins: *zesty.Pins) ?u3 { 352 390 switch (self.cycle) { 353 391 0 => { 354 392 self.pc +%= 1; ··· 367 405 4 => { 368 406 pins.cpu_addr = self.hilo.addr(); 369 407 }, 370 - else => return true, 408 + else => return self.cycle - 5, 371 409 } 372 - return false; 410 + return null; 373 411 } 374 412 375 413 inline fn fetch(self: *Cpu, pins: *zesty.Pins) void { ··· 483 521 self.setNZ(v); 484 522 self.fetch(pins); 485 523 } 486 - inline fn dec(self: *Cpu, pins: *zesty.Pins, v: *u8) void { 524 + inline fn adc(self: *Cpu, pins: *zesty.Pins, v: u8) void { 525 + var result, var carry = @addWithOverflow(self.a, @intFromBool(self.status.carry)); 526 + // TODO: implement optional support for decimal mode 527 + result, carry = @addWithOverflow(result, v); 528 + 529 + self.status.carry = carry > 0; 530 + self.setNZ(result); 531 + // Overflow bit is set if both inputs have the same sign, 532 + // and the output has a different sign 533 + self.status.overflow = ~(self.a ^ v) & (self.a ^ result) & 0x80 > 0; 534 + self.a = result; 535 + self.fetch(pins); 536 + } 537 + inline fn sbc(self: *Cpu, pins: *zesty.Pins, v: u8) void { 538 + self.adc(pins, ~v); 539 + } 540 + inline fn cmp(self: *Cpu, pins: *zesty.Pins, v: u8) void { 541 + // a CMP is basically a SBC in disguise 542 + const result, const carry = @addWithOverflow(v, ~pins.cpu_data +% 1); 543 + self.status.carry = carry > 0; 544 + self.setNZ(result); 545 + self.fetch(pins); 546 + } 547 + inline fn inxy(self: *Cpu, pins: *zesty.Pins, v: *u8) void { 548 + v.* +%= 1; 549 + self.setNZ(v.*); 550 + self.fetch(pins); 551 + } 552 + 553 + inline fn dexy(self: *Cpu, pins: *zesty.Pins, v: *u8) void { 487 554 v.* -%= 1; 488 555 self.setNZ(v.*); 489 556 self.fetch(pins); 490 557 } 558 + inline fn inc(self: *Cpu, pins: *zesty.Pins, c: u3) void { 559 + switch (c) { 560 + 0 => { 561 + // Dummy write? (Not sure why the processor does this) 562 + self.hilo = .{ .lo = pins.cpu_data }; 563 + pins.cpu_rw = .write; 564 + }, 565 + 1 => { 566 + self.hilo.lo +%= 1; 567 + self.setNZ(self.hilo.lo); 568 + pins.cpu_data = self.hilo.lo; 569 + pins.cpu_rw = .write; 570 + }, 571 + else => self.fetch(pins), 572 + } 573 + } 574 + inline fn dec(self: *Cpu, pins: *zesty.Pins, c: u3) void { 575 + switch (c) { 576 + 0 => { 577 + // Dummy write? (Not sure why the processor does this) 578 + self.hilo = .{ .lo = pins.cpu_data }; 579 + pins.cpu_rw = .write; 580 + }, 581 + 1 => { 582 + self.hilo.lo -%= 1; 583 + self.setNZ(self.hilo.lo); 584 + pins.cpu_data = self.hilo.lo; 585 + pins.cpu_rw = .write; 586 + }, 587 + else => self.fetch(pins), 588 + } 589 + } 590 + inline fn bit(self: *Cpu, pins: *zesty.Pins) void { 591 + const status: Status = .from(pins.cpu_data); 592 + self.status.negative = status.negative; 593 + self.status.overflow = status.overflow; 594 + self.status.zero = (self.a & pins.cpu_data) == 0; 595 + self.fetch(pins); 596 + } 491 597 492 598 //------------------------------------------------------ 493 599 // Opcodes: Control flow ··· 511 617 pins.cpu_data, 512 618 true, 513 619 ); 514 - pins.cpu_addr = self.pc; 620 + pins.cpu_addr = pc; 515 621 if (!page_crossed) self.fetchAt(pins, pc); 516 622 }, 517 623 else => self.fetchAt(pins, self.hilo.addr()), ··· 697 803 inline fn offsetWithPageFaultBehavior( 698 804 self: *Addr, 699 805 v: u8, 700 - signed: bool, 806 + comptime signed: bool, 701 807 ) struct { u16, bool } { 702 - self.lo, const page_crossed = if (!signed and v < 0x80) 703 - @addWithOverflow(self.lo, v) 704 - else 808 + const is_negative = signed and v >= 0x80; 809 + self.lo, const page_crossed = if (is_negative) 705 810 // v should NEVER be lower than 0x80, but saturate down to 0 to be safe 706 - @subWithOverflow(self.lo, v -| 0x80); 811 + @subWithOverflow(self.lo, v - 0x80) 812 + else 813 + @addWithOverflow(self.lo, v); 707 814 708 815 // If we haven't crossed the page boundary, skip over the next cycle. 709 - defer self.hi +%= page_crossed; 816 + defer { 817 + if (is_negative) 818 + self.hi -%= page_crossed 819 + else 820 + self.hi +%= page_crossed; 821 + } 710 822 return .{ self.addr(), page_crossed > 0 }; 711 823 } 712 824 };
+279
src/tests/cpu/alu.zig
··· 131 131 try std.testing.expect(!z.cpu.status.zero); 132 132 try std.testing.expect(z.cpu.status.carry); 133 133 } 134 + 135 + test "ADC" { 136 + var z = cpu.testZes(.{ 137 + .rom = &.{ 138 + .{ 139 + 0x8000, cpu.assemble( 140 + \\LDA #%10000101 141 + \\SEC 142 + \\ADC #%10000101 143 + ), 144 + }, 145 + }, 146 + }); 147 + cpu.run(&z); // Setup A register 148 + cpu.run(&z); // Set carry 149 + cpu.run(&z); // Perform addition 150 + 151 + try std.testing.expectEqual(0x8005, z.cpu.pc); 152 + try std.testing.expectEqual(0b00001011, z.cpu.a); 153 + try std.testing.expect(!z.cpu.status.negative); 154 + try std.testing.expect(!z.cpu.status.zero); 155 + try std.testing.expect(z.cpu.status.carry); 156 + try std.testing.expect(z.cpu.status.overflow); 157 + } 158 + 159 + test "SBC" { 160 + var z = cpu.testZes(.{ 161 + .rom = &.{ 162 + .{ 163 + 0x8000, cpu.assemble( 164 + \\LDA #%10000101 165 + \\SEC 166 + \\SBC #%01111010 167 + ), 168 + }, 169 + }, 170 + }); 171 + cpu.run(&z); // Setup A register 172 + cpu.run(&z); // Set carry 173 + cpu.run(&z); // Perform addition 174 + 175 + try std.testing.expectEqual(0x8005, z.cpu.pc); 176 + try std.testing.expectEqual(0b00001011, z.cpu.a); 177 + try std.testing.expect(!z.cpu.status.negative); 178 + try std.testing.expect(!z.cpu.status.zero); 179 + try std.testing.expect(z.cpu.status.carry); 180 + try std.testing.expect(z.cpu.status.overflow); 181 + } 182 + 183 + test "DEC" { 184 + var z = cpu.testZes(.{ 185 + .ram = &.{ 186 + .{ 0x42, &.{0x69} }, 187 + }, 188 + .rom = &.{ 189 + .{ 190 + 0x8000, cpu.assemble( 191 + \\DEC <$42 192 + ), 193 + }, 194 + }, 195 + }); 196 + cpu.run(&z); 197 + try std.testing.expectEqual(0x8002, z.cpu.pc); 198 + try std.testing.expectEqual(0x68, z.ram[0x42]); 199 + try std.testing.expect(!z.cpu.status.negative); 200 + try std.testing.expect(!z.cpu.status.zero); 201 + } 202 + 203 + test "DEX" { 204 + var z = cpu.testZes(.{ 205 + .rom = &.{ 206 + .{ 207 + 0x8000, cpu.assemble( 208 + \\DEX 209 + ), 210 + }, 211 + }, 212 + }); 213 + cpu.run(&z); 214 + try std.testing.expectEqual(0x8002, z.cpu.pc); 215 + try std.testing.expectEqual(0b11111111, z.cpu.x); 216 + try std.testing.expect(z.cpu.status.negative); 217 + try std.testing.expect(!z.cpu.status.zero); 218 + } 219 + 220 + test "DEY" { 221 + var z = cpu.testZes(.{ 222 + .rom = &.{ 223 + .{ 224 + 0x8000, cpu.assemble( 225 + \\DEY 226 + ), 227 + }, 228 + }, 229 + }); 230 + cpu.run(&z); 231 + try std.testing.expectEqual(0x8002, z.cpu.pc); 232 + try std.testing.expectEqual(0b11111111, z.cpu.y); 233 + try std.testing.expect(z.cpu.status.negative); 234 + try std.testing.expect(!z.cpu.status.zero); 235 + } 236 + 237 + test "INC" { 238 + var z = cpu.testZes(.{ 239 + .ram = &.{ 240 + .{ 0x42, &.{0x69} }, 241 + }, 242 + .rom = &.{ 243 + .{ 244 + 0x8000, cpu.assemble( 245 + \\INC <$42 246 + ), 247 + }, 248 + }, 249 + }); 250 + cpu.run(&z); 251 + try std.testing.expectEqual(0x8002, z.cpu.pc); 252 + try std.testing.expectEqual(0x6a, z.ram[0x42]); 253 + try std.testing.expect(!z.cpu.status.negative); 254 + try std.testing.expect(!z.cpu.status.zero); 255 + } 256 + 257 + test "INX" { 258 + var z = cpu.testZes(.{ 259 + .rom = &.{ 260 + .{ 261 + 0x8000, cpu.assemble( 262 + \\INX 263 + ), 264 + }, 265 + }, 266 + }); 267 + cpu.run(&z); 268 + try std.testing.expectEqual(0x8002, z.cpu.pc); 269 + try std.testing.expectEqual(0b00000001, z.cpu.x); 270 + try std.testing.expect(!z.cpu.status.negative); 271 + try std.testing.expect(!z.cpu.status.zero); 272 + } 273 + 274 + test "INY" { 275 + var z = cpu.testZes(.{ 276 + .rom = &.{ 277 + .{ 278 + 0x8000, cpu.assemble( 279 + \\INY 280 + ), 281 + }, 282 + }, 283 + }); 284 + cpu.run(&z); 285 + try std.testing.expectEqual(0x8002, z.cpu.pc); 286 + try std.testing.expectEqual(0b00000001, z.cpu.y); 287 + try std.testing.expect(!z.cpu.status.negative); 288 + try std.testing.expect(!z.cpu.status.zero); 289 + } 290 + 291 + test "CMP" { 292 + var z = cpu.testZes(.{ 293 + .rom = &.{ 294 + .{ 295 + 0x8000, cpu.assemble( 296 + \\LDA #$dd 297 + \\CMP #$42 298 + \\CMP #$dd 299 + \\CMP #$ee 300 + ), 301 + }, 302 + }, 303 + }); 304 + cpu.run(&z); 305 + 306 + cpu.run(&z); 307 + try std.testing.expectEqual(0x8004, z.cpu.pc); 308 + try std.testing.expect(z.cpu.status.negative); 309 + try std.testing.expect(!z.cpu.status.zero); 310 + try std.testing.expect(z.cpu.status.carry); 311 + 312 + cpu.run(&z); 313 + try std.testing.expectEqual(0x8006, z.cpu.pc); 314 + try std.testing.expect(!z.cpu.status.negative); 315 + try std.testing.expect(z.cpu.status.zero); 316 + try std.testing.expect(z.cpu.status.carry); 317 + 318 + cpu.run(&z); 319 + try std.testing.expectEqual(0x8008, z.cpu.pc); 320 + try std.testing.expect(z.cpu.status.negative); 321 + try std.testing.expect(!z.cpu.status.zero); 322 + try std.testing.expect(!z.cpu.status.carry); 323 + } 324 + 325 + test "CPX" { 326 + var z = cpu.testZes(.{ 327 + .rom = &.{ 328 + .{ 329 + 0x8000, cpu.assemble( 330 + \\LDX #$dd 331 + \\CPX #$42 332 + \\CPX #$dd 333 + \\CPX #$ee 334 + ), 335 + }, 336 + }, 337 + }); 338 + cpu.run(&z); 339 + 340 + cpu.run(&z); 341 + try std.testing.expectEqual(0x8004, z.cpu.pc); 342 + try std.testing.expect(z.cpu.status.negative); 343 + try std.testing.expect(!z.cpu.status.zero); 344 + try std.testing.expect(z.cpu.status.carry); 345 + 346 + cpu.run(&z); 347 + try std.testing.expectEqual(0x8006, z.cpu.pc); 348 + try std.testing.expect(!z.cpu.status.negative); 349 + try std.testing.expect(z.cpu.status.zero); 350 + try std.testing.expect(z.cpu.status.carry); 351 + 352 + cpu.run(&z); 353 + try std.testing.expectEqual(0x8008, z.cpu.pc); 354 + try std.testing.expect(z.cpu.status.negative); 355 + try std.testing.expect(!z.cpu.status.zero); 356 + try std.testing.expect(!z.cpu.status.carry); 357 + } 358 + test "CPY" { 359 + var z = cpu.testZes(.{ 360 + .rom = &.{ 361 + .{ 362 + 0x8000, cpu.assemble( 363 + \\LDY #$dd 364 + \\CPY #$42 365 + \\CPY #$dd 366 + \\CPY #$ee 367 + ), 368 + }, 369 + }, 370 + }); 371 + cpu.run(&z); 372 + 373 + cpu.run(&z); 374 + try std.testing.expectEqual(0x8004, z.cpu.pc); 375 + try std.testing.expect(z.cpu.status.negative); 376 + try std.testing.expect(!z.cpu.status.zero); 377 + try std.testing.expect(z.cpu.status.carry); 378 + 379 + cpu.run(&z); 380 + try std.testing.expectEqual(0x8006, z.cpu.pc); 381 + try std.testing.expect(!z.cpu.status.negative); 382 + try std.testing.expect(z.cpu.status.zero); 383 + try std.testing.expect(z.cpu.status.carry); 384 + 385 + cpu.run(&z); 386 + try std.testing.expectEqual(0x8008, z.cpu.pc); 387 + try std.testing.expect(z.cpu.status.negative); 388 + try std.testing.expect(!z.cpu.status.zero); 389 + try std.testing.expect(!z.cpu.status.carry); 390 + } 391 + test "BIT" { 392 + var z = cpu.testZes(.{ 393 + .ram = &.{ 394 + .{ 0x42, &.{0b11000000} }, 395 + }, 396 + .rom = &.{ 397 + .{ 398 + 0x8000, cpu.assemble( 399 + \\LDA #%00000101 400 + \\BIT <$42 401 + ), 402 + }, 403 + }, 404 + }); 405 + cpu.run(&z); 406 + 407 + cpu.run(&z); 408 + try std.testing.expectEqual(0x8004, z.cpu.pc); 409 + try std.testing.expect(z.cpu.status.negative); 410 + try std.testing.expect(z.cpu.status.overflow); 411 + try std.testing.expect(z.cpu.status.zero); 412 + }
+142 -3
src/tests/cpu/assembler.zig
··· 50 50 51 51 pub fn assembleComptime(comptime in: []const u8) []const u8 { 52 52 // Heuristically defined 53 - @setEvalBranchQuota(in.len * 100); 53 + @setEvalBranchQuota(in.len * 500); 54 54 55 55 return comptime v: { 56 56 var count_w: std.Io.Writer.Discarding = .init(&.{}); 57 - assemble(in, &count_w.writer) catch |err| std.debug.panic("error: {}", .{err}); 58 - 57 + assemble(in, &count_w.writer) catch |err| @compileError(std.fmt.comptimePrint("error: {}", .{err})); 59 58 var buf: [count_w.fullCount()]u8 = undefined; 60 59 var w: std.Io.Writer = .fixed(&buf); 61 60 assemble(in, &w) catch unreachable; ··· 77 76 ora, 78 77 @"and", 79 78 eor, 79 + adc, 80 + sbc, 80 81 asl, 81 82 lsr, 82 83 rol, 83 84 ror, 85 + inc, 86 + dec, 87 + inx, 88 + dex, 89 + iny, 90 + dey, 91 + cmp, 92 + cpx, 93 + cpy, 94 + bit, 84 95 85 96 clc, 86 97 sec, ··· 90 101 cld, 91 102 sed, 92 103 104 + bpl, 105 + bmi, 106 + bvc, 107 + bvs, 108 + bcc, 109 + bcs, 110 + bne, 111 + beq, 112 + 113 + nop, 114 + 93 115 fn encode(op: Opcode, opr: Operand) ?u8 { 94 116 return switch (op) { 95 117 .brk => switch (opr) { ··· 180 202 .indirect_indexed => 0x51, 181 203 else => null, 182 204 }, 205 + .adc => switch (opr) { 206 + .zeropage => 0x65, 207 + .zeropage_x => 0x75, 208 + .absolute => 0x6d, 209 + .absolute_x => 0x7d, 210 + .absolute_y => 0x79, 211 + .immediate => 0x69, 212 + .indexed_indirect => 0x61, 213 + .indirect_indexed => 0x71, 214 + else => null, 215 + }, 216 + .sbc => switch (opr) { 217 + .zeropage => 0xe5, 218 + .zeropage_x => 0xf5, 219 + .absolute => 0xed, 220 + .absolute_x => 0xfd, 221 + .absolute_y => 0xf9, 222 + .immediate => 0xe9, 223 + .indexed_indirect => 0xe1, 224 + .indirect_indexed => 0xf1, 225 + else => null, 226 + }, 183 227 .asl => switch (opr) { 184 228 .zeropage => 0x06, 185 229 .zeropage_x => 0x16, ··· 212 256 .implied => 0x6a, 213 257 else => null, 214 258 }, 259 + .inc => switch (opr) { 260 + .zeropage => 0xe6, 261 + .zeropage_x => 0xf6, 262 + .absolute => 0xee, 263 + .absolute_x => 0xfe, 264 + else => null, 265 + }, 266 + .dec => switch (opr) { 267 + .zeropage => 0xc6, 268 + .zeropage_x => 0xd6, 269 + .absolute => 0xce, 270 + .absolute_x => 0xde, 271 + else => null, 272 + }, 273 + .inx => switch (opr) { 274 + .implied => 0xe8, 275 + else => null, 276 + }, 277 + .dex => switch (opr) { 278 + .implied => 0xca, 279 + else => null, 280 + }, 281 + .iny => switch (opr) { 282 + .implied => 0xc8, 283 + else => null, 284 + }, 285 + .dey => switch (opr) { 286 + .implied => 0x88, 287 + else => null, 288 + }, 289 + .cmp => switch (opr) { 290 + .zeropage => 0xc5, 291 + .zeropage_x => 0xd5, 292 + .absolute => 0xcd, 293 + .absolute_x => 0xdd, 294 + .absolute_y => 0xd9, 295 + .immediate => 0xc9, 296 + .indexed_indirect => 0xc1, 297 + .indirect_indexed => 0xd1, 298 + else => null, 299 + }, 300 + .cpx => switch (opr) { 301 + .immediate => 0xe0, 302 + .zeropage => 0xe4, 303 + .absolute => 0xec, 304 + else => null, 305 + }, 306 + .cpy => switch (opr) { 307 + .immediate => 0xc0, 308 + .zeropage => 0xc4, 309 + .absolute => 0xcc, 310 + else => null, 311 + }, 312 + .bit => switch (opr) { 313 + .zeropage => 0x24, 314 + .absolute => 0x2c, 315 + else => null, 316 + }, 215 317 .clc => switch (opr) { 216 318 .implied => 0x18, 217 319 else => null, ··· 240 342 .implied => 0xf8, 241 343 else => null, 242 344 }, 345 + 346 + .bpl => switch (opr) { 347 + .immediate => 0x10, 348 + else => null, 349 + }, 350 + .bmi => switch (opr) { 351 + .immediate => 0x30, 352 + else => null, 353 + }, 354 + .bvc => switch (opr) { 355 + .immediate => 0x50, 356 + else => null, 357 + }, 358 + .bvs => switch (opr) { 359 + .immediate => 0x70, 360 + else => null, 361 + }, 362 + .bcc => switch (opr) { 363 + .immediate => 0x90, 364 + else => null, 365 + }, 366 + .bcs => switch (opr) { 367 + .immediate => 0xb0, 368 + else => null, 369 + }, 370 + .bne => switch (opr) { 371 + .immediate => 0xd0, 372 + else => null, 373 + }, 374 + .beq => switch (opr) { 375 + .immediate => 0xf0, 376 + else => null, 377 + }, 378 + .nop => switch (opr) { 379 + .implied => 0xea, 380 + else => null, 381 + }, 243 382 }; 244 383 } 245 384 };
+91 -2
src/tests/cpu/control_flow.zig
··· 15 15 try std.testing.expectEqual(0x69, z.pins.cpu_data); 16 16 } 17 17 18 - test "BRK and RTI" { 18 + test "BRK" { 19 19 var z = cpu.testZes(.{ 20 20 // Set a recognizable IRQ offset 21 21 .irq = 0x8964, 22 22 .rom = &.{ 23 - .{ 0x8000, cpu.assemble("brk") }, // BRK 23 + .{ 0x8000, cpu.assemble("brk") }, 24 24 }, 25 25 }); 26 26 ··· 67 67 try std.testing.expectEqual(0x00, z.ram[0x1fc]); 68 68 try std.testing.expectEqual(status, z.ram[0x1fb]); 69 69 } 70 + 71 + test "set and clear" { 72 + // TODO: Test CLV as well 73 + var z = cpu.testZes(.{ .rom = &.{ 74 + .{ 75 + 0x8000, cpu.assemble( 76 + \\sec 77 + \\cli 78 + \\sed 79 + \\clc 80 + \\sei 81 + \\cld 82 + ), 83 + }, 84 + } }); 85 + 86 + // Initial state 87 + try std.testing.expect(!z.cpu.status.carry); 88 + try std.testing.expect(z.cpu.status.irq_disabled); 89 + try std.testing.expect(!z.cpu.status.decimal); 90 + 91 + cpu.run(&z); // SEC 92 + try std.testing.expectEqual(0x8001, z.cpu.pc); 93 + try std.testing.expect(z.cpu.status.carry); 94 + 95 + cpu.run(&z); // CLI 96 + try std.testing.expectEqual(0x8002, z.cpu.pc); 97 + try std.testing.expect(!z.cpu.status.irq_disabled); 98 + 99 + cpu.run(&z); // SED 100 + try std.testing.expectEqual(0x8003, z.cpu.pc); 101 + try std.testing.expect(z.cpu.status.decimal); 102 + 103 + cpu.run(&z); // CLC 104 + try std.testing.expectEqual(0x8004, z.cpu.pc); 105 + try std.testing.expect(!z.cpu.status.carry); 106 + 107 + cpu.run(&z); // SEI 108 + try std.testing.expectEqual(0x8005, z.cpu.pc); 109 + try std.testing.expect(z.cpu.status.irq_disabled); 110 + 111 + cpu.run(&z); // CLD 112 + try std.testing.expectEqual(0x8006, z.cpu.pc); 113 + try std.testing.expect(!z.cpu.status.decimal); 114 + } 115 + 116 + test "branches" { 117 + // TODO: Test overflow as well 118 + var z = cpu.testZes(.{ .rom = &.{ 119 + .{ 120 + 0x8000, cpu.assemble( 121 + \\sec 122 + \\bcs #5 123 + \\ 124 + \\lda #$80 125 + \\bmi #5 126 + \\ 127 + \\lda #0 128 + \\beq #$87 129 + \\nop 130 + ), 131 + }, 132 + } }); 133 + 134 + cpu.run(&z); // SEC 135 + try std.testing.expectEqual(0x8001, z.cpu.pc); 136 + try std.testing.expect(z.cpu.status.carry); 137 + cpu.run(&z); // BCS 138 + try std.testing.expectEqual(0x8007, z.cpu.pc); 139 + // LDA #80 should be skipped here. 140 + try std.testing.expect(!z.cpu.status.negative); 141 + 142 + cpu.run(&z); // LDA #0 143 + try std.testing.expectEqual(0x8009, z.cpu.pc); 144 + try std.testing.expect(z.cpu.status.zero); 145 + cpu.run(&z); // BEQ (jump backwards) 146 + try std.testing.expectEqual(0x8003, z.cpu.pc); 147 + 148 + cpu.run(&z); // LDA #$80 149 + try std.testing.expectEqual(0xa9, z.cpu.opcode); 150 + try std.testing.expectEqual(0x8005, z.cpu.pc); 151 + try std.testing.expect(z.cpu.status.negative); 152 + 153 + // TODO: investigate why the CPU run helper doesn't stop after branching 154 + z.stepCpu(); // BMI 155 + z.stepCpu(); // BMI 156 + z.stepCpu(); // BMI 157 + try std.testing.expectEqual(0x800c, z.cpu.pc); 158 + }

History

2 rounds 0 comments
sign up or login to add to the discussion
1 commit
expand
cpu: finish ALU impl
expand 0 comments
pull request successfully merged
pluie.me submitted #0
1 commit
expand
cpu: finish ALU impl
expand 0 comments