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