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
+779 -149
Diff #1
+260 -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 + 0x20 => self.jsr(pins), // JSR abs 130 + 0x21 => if (self.zpXInd(pins)) |_| self._and(pins, v), // AND (zp,X) 131 + 0x24 => if (self.zp(pins)) |_| self.bit(pins), // BIT zp 132 + 0x25 => if (self.zp(pins)) |_| self._and(pins, v), // AND zp 133 + 0x26 => if (self.zp(pins)) |_| self.rol(pins, .mem), // ROL zp 134 + 0x29 => if (self.imm(pins)) |_| self._and(pins, v), // AND # 135 + 0x2a => if (self.imm(pins)) |_| self.rol(pins, .acc), // ROL A 136 + 0x2c => if (self.abs(pins)) |_| self.bit(pins), // BIT abs 137 + 0x2d => if (self.abs(pins)) |_| self._and(pins, v), // AND abs 138 + 0x2e => if (self.abs(pins)) |_| self.rol(pins, .mem), // ROL abs 139 + 140 + 0x30 => if (self.imm(pins)) |_| self.branch(pins, self.status.negative), // BMI 141 + 0x31 => if (self.zpIndY(pins)) |_| self._and(pins, v), // AND (zp),Y 142 + 0x35 => if (self.zpOff(pins, self.x)) |_| self._and(pins, v), // AND zp,X 143 + 0x36 => if (self.zpOff(pins, self.x)) |_| self.rol(pins, .mem), // ROL zp,X 142 144 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 145 + 0x39 => if (self.absOff(pins, self.y)) |_| self._and(pins, v), // AND abs,Y 146 + 0x3d => if (self.absOff(pins, self.x)) |_| self._and(pins, v), // AND abs,X 147 + 0x3e => if (self.absOff(pins, self.x)) |_| self.rol(pins, .mem), // ROL abs,X 146 148 147 149 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 150 + 0x41 => if (self.zpXInd(pins)) |_| self.eor(pins, v), // EOR (zp,X) 151 + 0x45 => if (self.zp(pins)) |_| self.eor(pins, v), // EOR zp 152 + 0x46 => if (self.zp(pins)) |_| self.lsr(pins, .mem), // LSR zp 153 + 0x49 => if (self.imm(pins)) |_| self.eor(pins, v), // EOR # 154 + 0x4a => if (self.imm(pins)) |_| self.lsr(pins, .acc), // LSR A 155 + 0x4c => self.jmp(pins), // JMP abs 156 + 0x4d => if (self.abs(pins)) |_| self.eor(pins, v), // EOR abs 157 + 0x4e => if (self.abs(pins)) |_| self.lsr(pins, .mem), // LSR abs 158 + 159 + 0x50 => if (self.imm(pins)) |_| self.branch(pins, !self.status.overflow), // BVC 160 + 0x51 => if (self.zpIndY(pins)) |_| self.eor(pins, v), // EOR (zp),Y 161 + 0x55 => if (self.zpOff(pins, self.x)) |_| self.eor(pins, v), // EOR zp,X 162 + 0x56 => if (self.zpOff(pins, self.x)) |_| self.lsr(pins, .mem), // LSR zp,X 160 163 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 164 + 0x59 => if (self.absOff(pins, self.y)) |_| self.eor(pins, v), // EOR abs,Y 165 + 0x5d => if (self.absOff(pins, self.x)) |_| self.eor(pins, v), // EOR abs,X 166 + 0x5e => if (self.absOff(pins, self.x)) |_| self.lsr(pins, .mem), // LSR abs,X 167 + 168 + 0x60 => self.rts(pins), // RTS 169 + 0x61 => if (self.zpXInd(pins)) |_| self.adc(pins, v), // ADC (zp,X) 170 + 0x65 => if (self.zp(pins)) |_| self.adc(pins, v), // ADC zp 171 + 0x66 => if (self.zp(pins)) |_| self.ror(pins, .mem), // ROR zp 172 + 0x69 => if (self.imm(pins)) |_| self.adc(pins, v), // ADC # 173 + 0x6a => if (self.imm(pins)) |_| self.ror(pins, .acc), // ROR A 174 + 0x6c => self.jmpInd(pins), // JMP (ind) 175 + 0x6d => if (self.abs(pins)) |_| self.adc(pins, v), // ADC abs 176 + 0x6e => if (self.abs(pins)) |_| self.ror(pins, .mem), // ROR abs 177 + 178 + 0x70 => if (self.imm(pins)) |_| self.branch(pins, self.status.overflow), // BVS 179 + 0x71 => if (self.zpIndY(pins)) |_| self.adc(pins, v), // ADC (zp),Y 180 + 0x75 => if (self.zpOff(pins, self.x)) |_| self.adc(pins, v), // ADC zp,X 181 + 0x76 => if (self.zpOff(pins, self.x)) |_| self.ror(pins, .mem), // ROR zp,X 177 182 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 183 + 0x79 => if (self.absOff(pins, self.y)) |_| self.adc(pins, v), // ADC abs,Y 184 + 0x7d => if (self.absOff(pins, self.x)) |_| self.adc(pins, v), // ADC abs,X 185 + 0x7e => if (self.absOff(pins, self.x)) |_| self.ror(pins, .mem), // ROR abs,X 186 + 187 + 0x81 => if (self.zpXInd(pins)) |_| self.st(pins, self.y), // STA (zp,X) 188 + 0x84 => if (self.zp(pins)) |_| self.st(pins, self.y), // STY zp 189 + 0x85 => if (self.zp(pins)) |_| self.st(pins, self.a), // STA zp 190 + 0x86 => if (self.zp(pins)) |_| self.st(pins, self.x), // STX zp 191 + 0x88 => if (self.imm(pins)) |_| self.dexy(pins, &self.y), // DEY 192 + 0x8a => if (self.imm(pins)) |_| self.ld(pins, &self.a, self.x), // TXA 193 + 0x8c => if (self.abs(pins)) |_| self.st(pins, self.y), // STY abs 194 + 0x8d => if (self.abs(pins)) |_| self.st(pins, self.a), // STA abs 195 + 0x8e => if (self.abs(pins)) |_| self.st(pins, self.x), // STX abs 196 + 197 + 0x90 => if (self.imm(pins)) |_| self.branch(pins, !self.status.carry), // BCC 198 + 0x91 => if (self.zpIndY(pins)) |_| self.ld(pins, &self.a, v), // STA (zp),Y 199 + 0x94 => if (self.zpOff(pins, self.x)) |_| self.st(pins, self.y), // STY zp,X 200 + 0x95 => if (self.zpOff(pins, self.x)) |_| self.st(pins, self.a), // STA zp,X 201 + 0x96 => if (self.zpOff(pins, self.y)) |_| self.st(pins, self.x), // STX zp,Y 202 + 0x99 => if (self.absOff(pins, self.y)) |_| self.st(pins, self.a), // STA abs,Y 203 + 0x9a => if (self.imm(pins)) |_| self.ld(pins, &self.sp, self.x), // TXS 204 + 0x9c => if (self.absOff(pins, self.x)) |_| self.st(pins, self.y), // STY abs,X 205 + 0x9d => if (self.absOff(pins, self.x)) |_| self.st(pins, self.a), // STA abs,X 206 + 0x9e => if (self.absOff(pins, self.y)) |_| self.st(pins, self.x), // STX abs,Y 207 + 208 + 0xa0 => if (self.imm(pins)) |_| self.ld(pins, &self.y, v), // LDY # 209 + 0xa1 => if (self.zpXInd(pins)) |_| self.ld(pins, &self.y, v), // LDA (zp,X) 210 + 0xa2 => if (self.imm(pins)) |_| self.ld(pins, &self.x, v), // LDX # 211 + 0xa4 => if (self.zp(pins)) |_| self.ld(pins, &self.y, v), // LDY zp 212 + 0xa5 => if (self.zp(pins)) |_| self.ld(pins, &self.a, v), // LDA zp 213 + 0xa6 => if (self.zp(pins)) |_| self.ld(pins, &self.x, v), // LDX zp 214 + 0xa8 => if (self.imm(pins)) |_| self.ld(pins, &self.y, self.a), // TAY 215 + 0xa9 => if (self.imm(pins)) |_| self.ld(pins, &self.a, v), // LDA # 216 + 0xaa => if (self.imm(pins)) |_| self.ld(pins, &self.x, self.a), // TAX 217 + 0xac => if (self.abs(pins)) |_| self.ld(pins, &self.y, v), // LDY abs 218 + 0xad => if (self.abs(pins)) |_| self.ld(pins, &self.a, v), // LDA abs 219 + 0xae => if (self.abs(pins)) |_| self.ld(pins, &self.x, v), // LDX abs 220 + 221 + 0xb0 => if (self.imm(pins)) |_| self.branch(pins, self.status.carry), // BCS 222 + 0xb1 => if (self.zpIndY(pins)) |_| self.ld(pins, &self.a, v), // LDA (zp),Y 223 + 0xb4 => if (self.zpOff(pins, self.x)) |_| self.ld(pins, &self.y, v), // LDY zp,X 224 + 0xb5 => if (self.zpOff(pins, self.x)) |_| self.ld(pins, &self.a, v), // LDA zp,X 225 + 0xb6 => if (self.zpOff(pins, self.y)) |_| self.ld(pins, &self.x, v), // LDX zp,Y 221 226 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 227 + 0xb9 => if (self.absOff(pins, self.y)) |_| self.ld(pins, &self.a, v), // LDA abs,Y 228 + 0xba => if (self.imm(pins)) |_| self.ld(pins, &self.x, self.sp), // TSX 229 + 0xbc => if (self.absOff(pins, self.x)) |_| self.ld(pins, &self.y, v), // LDY abs,X 230 + 0xbd => if (self.absOff(pins, self.x)) |_| self.ld(pins, &self.a, v), // LDA abs,X 231 + 0xbe => if (self.absOff(pins, self.y)) |_| self.ld(pins, &self.x, v), // LDX abs,Y 232 + 233 + 0xc0 => if (self.imm(pins)) |_| self.cmp(pins, self.y), // CPY # 234 + 0xc1 => if (self.zpXInd(pins)) |_| self.cmp(pins, self.a), // CMP (zp,X) 235 + 0xc4 => if (self.zp(pins)) |_| self.cmp(pins, self.y), // CPY zp 236 + 0xc5 => if (self.zp(pins)) |_| self.cmp(pins, self.a), // CMP zp 237 + 0xc6 => if (self.zp(pins)) |c| self.dec(pins, c), // DEC zp 238 + 0xc8 => if (self.imm(pins)) |_| self.inxy(pins, &self.y), // INY 239 + 0xc9 => if (self.imm(pins)) |_| self.cmp(pins, self.a), // CMP # 240 + 0xca => if (self.imm(pins)) |_| self.dexy(pins, &self.x), // DEY 241 + 0xcc => if (self.abs(pins)) |_| self.cmp(pins, self.y), // CPY abs 242 + 0xcd => if (self.abs(pins)) |_| self.cmp(pins, self.a), // CMP abs 243 + 0xce => if (self.abs(pins)) |c| self.dec(pins, c), // DEC abs 244 + 245 + 0xd0 => if (self.imm(pins)) |_| self.branch(pins, !self.status.zero), // BNE 246 + 0xd1 => if (self.zpIndY(pins)) |_| self.cmp(pins, self.a), // CMP (zp),Y 247 + 0xd5 => if (self.zpOff(pins, self.x)) |_| self.cmp(pins, self.a), // CMP zp,X 248 + 0xd6 => if (self.zpOff(pins, self.x)) |c| self.dec(pins, c), // DEC zp,X 229 249 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 250 + 0xd9 => if (self.absOff(pins, self.y)) |_| self.cmp(pins, self.a), // CMP abs,Y 251 + 0xdd => if (self.absOff(pins, self.x)) |_| self.cmp(pins, self.a), // CMP abs,X 252 + 0xde => if (self.absOff(pins, self.x)) |c| self.dec(pins, c), // DEC abs,X 253 + 254 + 0xe0 => if (self.imm(pins)) |_| self.cmp(pins, self.x), // CPX # 255 + 0xe1 => if (self.zpXInd(pins)) |_| self.sbc(pins, v), // SBC (zp,X) 256 + 0xe4 => if (self.zp(pins)) |_| self.cmp(pins, self.x), // CPX zp 257 + 0xe5 => if (self.zp(pins)) |_| self.sbc(pins, v), // SBC zp 258 + 0xe6 => if (self.zp(pins)) |c| self.inc(pins, c), // INC zp 259 + 0xe8 => if (self.imm(pins)) |_| self.inxy(pins, &self.x), // INX 260 + 0xe9 => if (self.imm(pins)) |_| self.sbc(pins, v), // SBC # 261 + 0xea => if (self.imm(pins)) |_| self.fetch(pins), // NOP 262 + 0xec => if (self.abs(pins)) |_| self.cmp(pins, self.x), // CPX abs 263 + 0xed => if (self.abs(pins)) |_| self.sbc(pins, v), // SBC abs 264 + 0xee => if (self.abs(pins)) |c| self.inc(pins, c), // INC abs 265 + 266 + 0xf0 => if (self.imm(pins)) |_| self.branch(pins, self.status.zero), // BEQ 267 + 0xf1 => if (self.zpIndY(pins)) |_| self.sbc(pins, v), // SBC (zp),Y 268 + 0xf5 => if (self.zpOff(pins, self.x)) |_| self.sbc(pins, v), // SBC zp,X 269 + 0xf6 => if (self.zpOff(pins, self.x)) |c| self.inc(pins, c), // INC zp,X 234 270 0xf8 => self.set(pins, .decimal, true), // SED 271 + 0xf9 => if (self.absOff(pins, self.y)) |_| self.sbc(pins, v), // SBC abs,Y 272 + 0xfd => if (self.absOff(pins, self.x)) |_| self.sbc(pins, v), // SBC abs,X 273 + 0xfe => if (self.absOff(pins, self.x)) |c| self.inc(pins, c), // INC abs,X 235 274 236 - else => log.err("UNHANDLED OP={X}", .{self.opcode}), 275 + else => { 276 + log.err("UNHANDLED OP={X}", .{self.opcode}); 277 + self.fetch(pins); 278 + }, 237 279 } 238 280 } 239 281 240 - inline fn imm(self: *Cpu, pins: *zesty.Pins) bool { 282 + inline fn imm(self: *Cpu, pins: *zesty.Pins) ?u3 { 241 283 switch (self.cycle) { 242 284 0 => { 243 285 self.pc +%= 1; 244 286 pins.cpu_addr = self.pc; 245 287 }, 246 - else => return true, 288 + else => return self.cycle - 1, 247 289 } 248 - return false; 290 + return null; 249 291 } 250 - inline fn zp(self: *Cpu, pins: *zesty.Pins) bool { 292 + inline fn zp(self: *Cpu, pins: *zesty.Pins) ?u3 { 251 293 switch (self.cycle) { 252 294 0 => { 253 295 self.pc +%= 1; ··· 257 299 self.hilo = .{ .lo = pins.cpu_data }; 258 300 pins.cpu_addr = self.hilo.addr(); 259 301 }, 260 - else => return true, 302 + else => return self.cycle - 2, 261 303 } 262 - return false; 304 + return null; 263 305 } 264 - inline fn zpOff(self: *Cpu, pins: *zesty.Pins, v: u8) bool { 306 + inline fn zpOff(self: *Cpu, pins: *zesty.Pins, v: u8) ?u3 { 265 307 switch (self.cycle) { 266 308 0 => { 267 309 self.pc +%= 1; ··· 275 317 self.hilo.lo +%= v; 276 318 pins.cpu_addr = self.hilo.addr(); 277 319 }, 278 - else => return true, 320 + else => return self.cycle - 3, 279 321 } 280 - return false; 322 + return null; 281 323 } 282 - inline fn abs(self: *Cpu, pins: *zesty.Pins) bool { 324 + inline fn abs(self: *Cpu, pins: *zesty.Pins) ?u3 { 283 325 switch (self.cycle) { 284 326 0 => { 285 327 self.pc +%= 1; ··· 294 336 self.hilo.hi = pins.cpu_data; 295 337 pins.cpu_addr = self.hilo.addr(); 296 338 }, 297 - else => return true, 339 + else => return self.cycle - 3, 298 340 } 299 - return false; 341 + return null; 300 342 } 301 - inline fn absOff(self: *Cpu, pins: *zesty.Pins, v: u8) bool { 343 + inline fn absOff(self: *Cpu, pins: *zesty.Pins, v: u8) ?u3 { 302 344 switch (self.cycle) { 303 345 0 => { 304 346 self.pc +%= 1; ··· 317 359 3 => { 318 360 pins.cpu_addr = self.hilo.addr(); 319 361 }, 320 - else => return true, 362 + else => return self.cycle - 4, 321 363 } 322 - return false; 364 + return null; 323 365 } 324 - inline fn zpXInd(self: *Cpu, pins: *zesty.Pins) bool { 366 + inline fn zpXInd(self: *Cpu, pins: *zesty.Pins) ?u3 { 325 367 switch (self.cycle) { 326 368 0 => { 327 369 self.pc +%= 1; ··· 344 386 self.hilo.hi = pins.cpu_data; 345 387 pins.cpu_addr = self.hilo.addr(); 346 388 }, 347 - else => return true, 389 + else => return self.cycle - 5, 348 390 } 349 - return false; 391 + return null; 350 392 } 351 - inline fn zpIndY(self: *Cpu, pins: *zesty.Pins) bool { 393 + inline fn zpIndY(self: *Cpu, pins: *zesty.Pins) ?u3 { 352 394 switch (self.cycle) { 353 395 0 => { 354 396 self.pc +%= 1; ··· 367 409 4 => { 368 410 pins.cpu_addr = self.hilo.addr(); 369 411 }, 370 - else => return true, 412 + else => return self.cycle - 5, 371 413 } 372 - return false; 414 + return null; 373 415 } 374 416 375 417 inline fn fetch(self: *Cpu, pins: *zesty.Pins) void { ··· 483 525 self.setNZ(v); 484 526 self.fetch(pins); 485 527 } 486 - inline fn dec(self: *Cpu, pins: *zesty.Pins, v: *u8) void { 528 + inline fn adc(self: *Cpu, pins: *zesty.Pins, v: u8) void { 529 + var result, var carry = @addWithOverflow(self.a, @intFromBool(self.status.carry)); 530 + // TODO: implement optional support for decimal mode 531 + result, carry = @addWithOverflow(result, v); 532 + 533 + self.status.carry = carry > 0; 534 + self.setNZ(result); 535 + // Overflow bit is set if both inputs have the same sign, 536 + // and the output has a different sign 537 + self.status.overflow = ~(self.a ^ v) & (self.a ^ result) & 0x80 > 0; 538 + self.a = result; 539 + self.fetch(pins); 540 + } 541 + inline fn sbc(self: *Cpu, pins: *zesty.Pins, v: u8) void { 542 + self.adc(pins, ~v); 543 + } 544 + inline fn cmp(self: *Cpu, pins: *zesty.Pins, v: u8) void { 545 + // a CMP is basically a SBC in disguise 546 + const result, const carry = @addWithOverflow(v, ~pins.cpu_data +% 1); 547 + self.status.carry = carry > 0; 548 + self.setNZ(result); 549 + self.fetch(pins); 550 + } 551 + inline fn inxy(self: *Cpu, pins: *zesty.Pins, v: *u8) void { 552 + v.* +%= 1; 553 + self.setNZ(v.*); 554 + self.fetch(pins); 555 + } 556 + 557 + inline fn dexy(self: *Cpu, pins: *zesty.Pins, v: *u8) void { 487 558 v.* -%= 1; 488 559 self.setNZ(v.*); 489 560 self.fetch(pins); 490 561 } 562 + inline fn inc(self: *Cpu, pins: *zesty.Pins, c: u3) void { 563 + switch (c) { 564 + 0 => { 565 + // Dummy write? (Not sure why the processor does this) 566 + self.hilo = .{ .lo = pins.cpu_data }; 567 + pins.cpu_rw = .write; 568 + }, 569 + 1 => { 570 + self.hilo.lo +%= 1; 571 + self.setNZ(self.hilo.lo); 572 + pins.cpu_data = self.hilo.lo; 573 + pins.cpu_rw = .write; 574 + }, 575 + else => self.fetch(pins), 576 + } 577 + } 578 + inline fn dec(self: *Cpu, pins: *zesty.Pins, c: u3) void { 579 + switch (c) { 580 + 0 => { 581 + // Dummy write? (Not sure why the processor does this) 582 + self.hilo = .{ .lo = pins.cpu_data }; 583 + pins.cpu_rw = .write; 584 + }, 585 + 1 => { 586 + self.hilo.lo -%= 1; 587 + self.setNZ(self.hilo.lo); 588 + pins.cpu_data = self.hilo.lo; 589 + pins.cpu_rw = .write; 590 + }, 591 + else => self.fetch(pins), 592 + } 593 + } 594 + inline fn bit(self: *Cpu, pins: *zesty.Pins) void { 595 + const status: Status = .from(pins.cpu_data); 596 + self.status.negative = status.negative; 597 + self.status.overflow = status.overflow; 598 + self.status.zero = (self.a & pins.cpu_data) == 0; 599 + self.fetch(pins); 600 + } 491 601 492 602 //------------------------------------------------------ 493 603 // Opcodes: Control flow ··· 511 621 pins.cpu_data, 512 622 true, 513 623 ); 514 - pins.cpu_addr = self.pc; 624 + pins.cpu_addr = pc; 515 625 if (!page_crossed) self.fetchAt(pins, pc); 516 626 }, 517 627 else => self.fetchAt(pins, self.hilo.addr()), ··· 697 807 inline fn offsetWithPageFaultBehavior( 698 808 self: *Addr, 699 809 v: u8, 700 - signed: bool, 810 + comptime signed: bool, 701 811 ) struct { u16, bool } { 702 - self.lo, const page_crossed = if (!signed and v < 0x80) 703 - @addWithOverflow(self.lo, v) 704 - else 812 + const is_negative = signed and v >= 0x80; 813 + self.lo, const page_crossed = if (is_negative) 705 814 // v should NEVER be lower than 0x80, but saturate down to 0 to be safe 706 - @subWithOverflow(self.lo, v -| 0x80); 815 + @subWithOverflow(self.lo, v - 0x80) 816 + else 817 + @addWithOverflow(self.lo, v); 707 818 708 819 // If we haven't crossed the page boundary, skip over the next cycle. 709 - defer self.hi +%= page_crossed; 820 + defer { 821 + if (is_negative) 822 + self.hi -%= page_crossed 823 + else 824 + self.hi +%= page_crossed; 825 + } 710 826 return .{ self.addr(), page_crossed > 0 }; 711 827 } 712 828 };
+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 + }
+145 -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 + jmp, 113 + jsr, 114 + rts, 115 + 116 + nop, 117 + 93 118 fn encode(op: Opcode, opr: Operand) ?u8 { 94 119 return switch (op) { 95 120 .brk => switch (opr) { ··· 180 205 .indirect_indexed => 0x51, 181 206 else => null, 182 207 }, 208 + .adc => switch (opr) { 209 + .zeropage => 0x65, 210 + .zeropage_x => 0x75, 211 + .absolute => 0x6d, 212 + .absolute_x => 0x7d, 213 + .absolute_y => 0x79, 214 + .immediate => 0x69, 215 + .indexed_indirect => 0x61, 216 + .indirect_indexed => 0x71, 217 + else => null, 218 + }, 219 + .sbc => switch (opr) { 220 + .zeropage => 0xe5, 221 + .zeropage_x => 0xf5, 222 + .absolute => 0xed, 223 + .absolute_x => 0xfd, 224 + .absolute_y => 0xf9, 225 + .immediate => 0xe9, 226 + .indexed_indirect => 0xe1, 227 + .indirect_indexed => 0xf1, 228 + else => null, 229 + }, 183 230 .asl => switch (opr) { 184 231 .zeropage => 0x06, 185 232 .zeropage_x => 0x16, ··· 212 259 .implied => 0x6a, 213 260 else => null, 214 261 }, 262 + .inc => switch (opr) { 263 + .zeropage => 0xe6, 264 + .zeropage_x => 0xf6, 265 + .absolute => 0xee, 266 + .absolute_x => 0xfe, 267 + else => null, 268 + }, 269 + .dec => switch (opr) { 270 + .zeropage => 0xc6, 271 + .zeropage_x => 0xd6, 272 + .absolute => 0xce, 273 + .absolute_x => 0xde, 274 + else => null, 275 + }, 276 + .inx => switch (opr) { 277 + .implied => 0xe8, 278 + else => null, 279 + }, 280 + .dex => switch (opr) { 281 + .implied => 0xca, 282 + else => null, 283 + }, 284 + .iny => switch (opr) { 285 + .implied => 0xc8, 286 + else => null, 287 + }, 288 + .dey => switch (opr) { 289 + .implied => 0x88, 290 + else => null, 291 + }, 292 + .cmp => switch (opr) { 293 + .zeropage => 0xc5, 294 + .zeropage_x => 0xd5, 295 + .absolute => 0xcd, 296 + .absolute_x => 0xdd, 297 + .absolute_y => 0xd9, 298 + .immediate => 0xc9, 299 + .indexed_indirect => 0xc1, 300 + .indirect_indexed => 0xd1, 301 + else => null, 302 + }, 303 + .cpx => switch (opr) { 304 + .immediate => 0xe0, 305 + .zeropage => 0xe4, 306 + .absolute => 0xec, 307 + else => null, 308 + }, 309 + .cpy => switch (opr) { 310 + .immediate => 0xc0, 311 + .zeropage => 0xc4, 312 + .absolute => 0xcc, 313 + else => null, 314 + }, 315 + .bit => switch (opr) { 316 + .zeropage => 0x24, 317 + .absolute => 0x2c, 318 + else => null, 319 + }, 215 320 .clc => switch (opr) { 216 321 .implied => 0x18, 217 322 else => null, ··· 240 345 .implied => 0xf8, 241 346 else => null, 242 347 }, 348 + 349 + .bpl => switch (opr) { 350 + .immediate => 0x10, 351 + else => null, 352 + }, 353 + .bmi => switch (opr) { 354 + .immediate => 0x30, 355 + else => null, 356 + }, 357 + .bvc => switch (opr) { 358 + .immediate => 0x50, 359 + else => null, 360 + }, 361 + .bvs => switch (opr) { 362 + .immediate => 0x70, 363 + else => null, 364 + }, 365 + .bcc => switch (opr) { 366 + .immediate => 0x90, 367 + else => null, 368 + }, 369 + .bcs => switch (opr) { 370 + .immediate => 0xb0, 371 + else => null, 372 + }, 373 + .bne => switch (opr) { 374 + .immediate => 0xd0, 375 + else => null, 376 + }, 377 + .beq => switch (opr) { 378 + .immediate => 0xf0, 379 + else => null, 380 + }, 381 + .nop => switch (opr) { 382 + .implied => 0xea, 383 + else => null, 384 + }, 243 385 }; 244 386 } 245 387 };
+95 -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 #%11000000 125 + \\bmi #5 126 + \\ 127 + \\lda #0 128 + \\beq #$87 129 + \\ 130 + \\bit $8004 131 + \\bvs #2 132 + \\brk 133 + \\nop 134 + ), 135 + }, 136 + } }); 137 + 138 + cpu.run(&z); // SEC 139 + try std.testing.expectEqual(0x8001, z.cpu.pc); 140 + try std.testing.expect(z.cpu.status.carry); 141 + cpu.run(&z); // BCS 142 + try std.testing.expectEqual(0x8007, z.cpu.pc); 143 + // LDA #80 should be skipped here. 144 + try std.testing.expect(!z.cpu.status.negative); 145 + 146 + cpu.run(&z); // LDA #0 147 + try std.testing.expectEqual(0x8009, z.cpu.pc); 148 + try std.testing.expect(z.cpu.status.zero); 149 + cpu.run(&z); // BEQ (jump backwards) 150 + try std.testing.expectEqual(0x8003, z.cpu.pc); 151 + 152 + cpu.run(&z); // LDA #%11000000 153 + try std.testing.expectEqual(0xa9, z.cpu.opcode); 154 + try std.testing.expectEqual(0x8005, z.cpu.pc); 155 + try std.testing.expect(z.cpu.status.negative); 156 + 157 + // TODO: investigate why the CPU run helper doesn't stop after branching 158 + z.stepCpu(); // BMI 159 + z.stepCpu(); // BMI 160 + z.stepCpu(); // BMI 161 + try std.testing.expectEqual(0x800c, z.cpu.pc); 162 + }

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