+256
-144
src/Cpu.zig
+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
+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
+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
+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
+
}