+493
-139
src/Cpu.zig
+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
+1
src/tests/cpu.zig
+8
-8
src/tests/cpu/alu.zig
+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
+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
+
}