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