]> Joshua Wise's Git repositories - fpgaboy.git/blame - GBZ80Core.v
Test interrupts. They work!
[fpgaboy.git] / GBZ80Core.v
CommitLineData
2f55f809
JW
1`define REG_A 0
2`define REG_B 1
3`define REG_C 2
4`define REG_D 3
5`define REG_E 4
6`define REG_F 5
7`define REG_H 6
8`define REG_L 7
9`define REG_SPH 8
10`define REG_SPL 9
11`define REG_PCH 10
12`define REG_PCL 11
13
14`define FLAG_Z 8'b10000000
15`define FLAG_N 8'b01000000
16`define FLAG_H 8'b00100000
17`define FLAG_C 8'b00010000
18
19`define STATE_FETCH 2'h0
20`define STATE_DECODE 2'h1
21`define STATE_EXECUTE 2'h2
22`define STATE_WRITEBACK 2'h3
23
24`define INSN_LD_reg_imm8 8'b00xxx110
b85870e0
JW
25`define INSN_HALT 8'b01110110
26`define INSN_LD_HL_reg 8'b01110xxx
27`define INSN_LD_reg_HL 8'b01xxx110
28`define INSN_LD_reg_reg 8'b01xxxxxx
634ce02c
JW
29`define INSN_LD_reg_imm16 8'b00xx0001
30`define INSN_LD_SP_HL 8'b11111001
97649fed 31`define INSN_PUSH_reg 8'b11xx0101
00e30b4d
JW
32`define INSN_POP_reg 8'b11xx0001
33`define INSN_LDH_AC 8'b111x0010 // Either LDH A,(C) or LDH (C),A
fa136d63 34`define INSN_LDx_AHL 8'b001xx010 // LDD/LDI A,(HL) / (HL),A
94522011 35`define INSN_ALU8 8'b10xxxxxx // 10 xxx yyy
d3938806 36`define INSN_NOP 8'b00000000
1e03e021 37`define INSN_RST 8'b11xxx111
abae5818 38`define INSN_RET 8'b110x1001 // 1 = RETI, 0 = RET
611e4a90 39`define INSN_RETCC 8'b110xx000
ef6fbe31 40`define INSN_CALL 8'b11001101
6b4e2828 41`define INSN_CALLCC 8'b110xx100 // Not that call/cc.
a85b19a7
JW
42`define INSN_JP_imm 8'b11000011
43`define INSN_JPCC_imm 8'b110xx010
a00483d0 44`define INSN_ALU_A 8'b00xxx111
6b4e2828 45`define INSN_JP_HL 8'b11101001
722e486a
JW
46`define INSN_JR_imm 8'b00011000
47`define INSN_JRCC_imm 8'b001xx000
dadf7990 48`define INSN_INCDEC16 8'b00xxx011
f8db6448
JW
49`define INSN_VOP_INTR 8'b11111100 // 0xFC is grabbed by the fetch if there is an interrupt pending.
50`define INSN_DI 8'b11110011
51`define INSN_EI 8'b11111011
a85b19a7
JW
52
53`define INSN_cc_NZ 2'b00
54`define INSN_cc_Z 2'b01
55`define INSN_cc_NC 2'b10
56`define INSN_cc_C 2'b11
fa136d63 57
b85870e0
JW
58`define INSN_reg_A 3'b111
59`define INSN_reg_B 3'b000
60`define INSN_reg_C 3'b001
61`define INSN_reg_D 3'b010
62`define INSN_reg_E 3'b011
63`define INSN_reg_H 3'b100
64`define INSN_reg_L 3'b101
65`define INSN_reg_dHL 3'b110
634ce02c
JW
66`define INSN_reg16_BC 2'b00
67`define INSN_reg16_DE 2'b01
68`define INSN_reg16_HL 2'b10
69`define INSN_reg16_SP 2'b11
97649fed
JW
70`define INSN_stack_AF 2'b11
71`define INSN_stack_BC 2'b00
72`define INSN_stack_DE 2'b01
73`define INSN_stack_HL 2'b10
94522011
JW
74`define INSN_alu_ADD 3'b000
75`define INSN_alu_ADC 3'b001
76`define INSN_alu_SUB 3'b010
77`define INSN_alu_SBC 3'b011
78`define INSN_alu_AND 3'b100
79`define INSN_alu_XOR 3'b101
80`define INSN_alu_OR 3'b110
81`define INSN_alu_CP 3'b111 // Oh lawd, is dat some CP?
a00483d0
JW
82`define INSN_alu_RLCA 3'b000
83`define INSN_alu_RRCA 3'b001
84`define INSN_alu_RLA 3'b010
85`define INSN_alu_RRA 3'b011
86`define INSN_alu_DAA 3'b100
87`define INSN_alu_CPL 3'b101
88`define INSN_alu_SCF 3'b110
89`define INSN_alu_CCF 3'b111
94522011 90
2f55f809
JW
91module GBZ80Core(
92 input clk,
62940da0 93 output reg [15:0] busaddress = 0, /* BUS_* is latched on STATE_FETCH. */
2f55f809 94 inout [7:0] busdata,
f8db6448
JW
95 output reg buswr = 0, output reg busrd = 0,
96 input irq, input [7:0] jaddr);
2f55f809
JW
97
98 reg [1:0] state = 0; /* State within this bus cycle (see STATE_*). */
99 reg [2:0] cycle = 0; /* Cycle for instructions. */
100
101 reg [7:0] registers[11:0];
102
103 reg [15:0] address; /* Address for the next bus operation. */
104
105 reg [7:0] opcode; /* Opcode from the current machine cycle. */
106
107 reg [7:0] rdata, wdata; /* Read data from this bus cycle, or write data for the next. */
108 reg rd = 1, wr = 0, newcycle = 1;
109
ef6fbe31 110 reg [7:0] tmp, tmp2; /* Generic temporary regs. */
b85870e0 111
2f55f809
JW
112 reg [7:0] buswdata;
113 assign busdata = buswr ? buswdata : 8'bzzzzzzzz;
114
f8db6448 115 reg ie = 0, iedelay = 0;
abae5818 116
2f55f809 117 initial begin
241c995c
JW
118 registers[ 0] <= 0;
119 registers[ 1] <= 0;
120 registers[ 2] <= 0;
121 registers[ 3] <= 0;
122 registers[ 4] <= 0;
123 registers[ 5] <= 0;
124 registers[ 6] <= 0;
125 registers[ 7] <= 0;
126 registers[ 8] <= 0;
127 registers[ 9] <= 0;
128 registers[10] <= 0;
129 registers[11] <= 0;
2e642f1f
JW
130 ie <= 0;
131 rd <= 1;
132 wr <= 0;
133 newcycle <= 1;
134 state <= 0;
135 cycle <= 0;
f8db6448
JW
136 busrd <= 0;
137 buswr <= 0;
138 busaddress <= 0;
139 iedelay <= 0;
2f55f809
JW
140 end
141
142 always @(posedge clk)
143 case (state)
144 `STATE_FETCH: begin
2e642f1f 145 if (newcycle) begin
2f55f809 146 busaddress <= {registers[`REG_PCH], registers[`REG_PCL]};
2e642f1f
JW
147 buswr <= 0;
148 busrd <= 1;
149 end else begin
2f55f809 150 busaddress <= address;
2e642f1f
JW
151 buswr <= wr;
152 busrd <= rd;
153 if (wr)
154 buswdata <= wdata;
155 end
2f55f809
JW
156 state <= `STATE_DECODE;
157 end
158 `STATE_DECODE: begin
159 if (newcycle) begin
f8db6448
JW
160 if (ie && irq)
161 opcode <= `INSN_VOP_INTR;
162 else
163 opcode <= busdata;
2f55f809 164 rdata <= busdata;
b85870e0 165 newcycle <= 0;
2f55f809 166 cycle <= 0;
2e642f1f 167 end else begin
2f55f809 168 if (rd) rdata <= busdata;
2e642f1f
JW
169 cycle <= cycle + 1;
170 end
f8db6448
JW
171 if (iedelay) begin
172 ie <= 1;
173 iedelay <= 0;
174 end
2f55f809
JW
175 buswr <= 0;
176 busrd <= 0;
97649fed
JW
177 wr <= 0;
178 rd <= 0;
179 address <= 16'bxxxxxxxxxxxxxxxx; // Make it obvious if something of type has happened.
180 wdata <= 8'bxxxxxxxx;
2f55f809
JW
181 state <= `STATE_EXECUTE;
182 end
183 `STATE_EXECUTE: begin
184`define EXEC_INC_PC \
185 {registers[`REG_PCH], registers[`REG_PCL]} <= {registers[`REG_PCH], registers[`REG_PCL]} + 1
186`define EXEC_NEXTADDR_PCINC \
187 address <= {registers[`REG_PCH], registers[`REG_PCL]} + 1
188`define EXEC_NEWCYCLE \
189 newcycle <= 1; rd <= 1; wr <= 0
190 casex (opcode)
191 `INSN_LD_reg_imm8: begin
192 case (cycle)
193 0: begin
194 `EXEC_INC_PC;
195 `EXEC_NEXTADDR_PCINC;
2f55f809
JW
196 rd <= 1;
197 end
69ca9b5f 198 1: begin
2f55f809 199 `EXEC_INC_PC;
b85870e0 200 if (opcode[5:3] == `INSN_reg_dHL) begin
2f55f809
JW
201 address <= {registers[`REG_H], registers[`REG_L]};
202 wdata <= rdata;
203 rd <= 0;
204 wr <= 1;
205 end else begin
206 `EXEC_NEWCYCLE;
207 end
208 end
69ca9b5f 209 2: begin
2f55f809
JW
210 `EXEC_NEWCYCLE;
211 end
212 endcase
213 end
b85870e0 214 `INSN_HALT: begin
f2e04715
JW
215 `EXEC_NEWCYCLE;
216 /* XXX Interrupts needed for HALT. */
b85870e0
JW
217 end
218 `INSN_LD_HL_reg: begin
f2e04715
JW
219 case (cycle)
220 0: begin
221 case (opcode[2:0])
69ca9b5f
JW
222 `INSN_reg_A: wdata <= registers[`REG_A];
223 `INSN_reg_B: wdata <= registers[`REG_B];
224 `INSN_reg_C: wdata <= registers[`REG_C];
225 `INSN_reg_D: wdata <= registers[`REG_D];
226 `INSN_reg_E: wdata <= registers[`REG_E];
227 `INSN_reg_H: wdata <= registers[`REG_H];
228 `INSN_reg_L: wdata <= registers[`REG_L];
f2e04715
JW
229 endcase
230 address <= {registers[`REG_H], registers[`REG_L]};
231 wr <= 1; rd <= 0;
232 end
233 1: begin
234 `EXEC_INC_PC;
235 `EXEC_NEWCYCLE;
236 end
237 endcase
b85870e0
JW
238 end
239 `INSN_LD_reg_HL: begin
f2e04715 240 case(cycle)
69ca9b5f 241 0: begin
f2e04715 242 address <= {registers[`REG_H], registers[`REG_L]};
97649fed 243 rd <= 1;
f2e04715 244 end
69ca9b5f 245 1: begin
f2e04715
JW
246 tmp <= rdata;
247 `EXEC_INC_PC;
248 `EXEC_NEWCYCLE;
249 end
250 endcase
b85870e0
JW
251 end
252 `INSN_LD_reg_reg: begin
253 `EXEC_INC_PC;
254 `EXEC_NEWCYCLE;
255 case (opcode[2:0])
69ca9b5f
JW
256 `INSN_reg_A: tmp <= registers[`REG_A];
257 `INSN_reg_B: tmp <= registers[`REG_B];
258 `INSN_reg_C: tmp <= registers[`REG_C];
259 `INSN_reg_D: tmp <= registers[`REG_D];
260 `INSN_reg_E: tmp <= registers[`REG_E];
261 `INSN_reg_H: tmp <= registers[`REG_H];
262 `INSN_reg_L: tmp <= registers[`REG_L];
b85870e0
JW
263 endcase
264 end
634ce02c
JW
265 `INSN_LD_reg_imm16: begin
266 `EXEC_INC_PC;
267 case (cycle)
268 0: begin
269 `EXEC_NEXTADDR_PCINC;
270 rd <= 1;
271 end
272 1: begin
273 `EXEC_NEXTADDR_PCINC;
274 rd <= 1;
275 end
276 2: begin `EXEC_NEWCYCLE; end
277 endcase
278 end
279 `INSN_LD_SP_HL: begin
280 case (cycle)
281 0: begin
634ce02c
JW
282 tmp <= registers[`REG_H];
283 end
284 1: begin
285 `EXEC_NEWCYCLE;
286 `EXEC_INC_PC;
287 tmp <= registers[`REG_L];
288 end
289 endcase
290 end
97649fed
JW
291 `INSN_PUSH_reg: begin /* PUSH is 16 cycles! */
292 case (cycle)
69ca9b5f 293 0: begin
97649fed
JW
294 wr <= 1;
295 address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
296 case (opcode[5:4])
297 `INSN_stack_AF: wdata <= registers[`REG_A];
298 `INSN_stack_BC: wdata <= registers[`REG_B];
299 `INSN_stack_DE: wdata <= registers[`REG_D];
300 `INSN_stack_HL: wdata <= registers[`REG_H];
301 endcase
302 end
69ca9b5f 303 1: begin
97649fed
JW
304 wr <= 1;
305 address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
306 case (opcode[5:4])
307 `INSN_stack_AF: wdata <= registers[`REG_F];
308 `INSN_stack_BC: wdata <= registers[`REG_C];
309 `INSN_stack_DE: wdata <= registers[`REG_E];
310 `INSN_stack_HL: wdata <= registers[`REG_L];
311 endcase
312 end
20204e79 313 2: begin /* Twiddle thumbs. */ end
69ca9b5f 314 3: begin
97649fed
JW
315 `EXEC_NEWCYCLE;
316 `EXEC_INC_PC;
317 end
318 endcase
319 end
320 `INSN_POP_reg: begin /* POP is 12 cycles! */
321 case (cycle)
69ca9b5f 322 0: begin
97649fed
JW
323 rd <= 1;
324 address <= {registers[`REG_SPH],registers[`REG_SPL]};
325 end
69ca9b5f 326 1: begin
97649fed
JW
327 rd <= 1;
328 address <= {registers[`REG_SPH],registers[`REG_SPL]};
329 end
69ca9b5f 330 2: begin
97649fed
JW
331 `EXEC_NEWCYCLE;
332 `EXEC_INC_PC;
333 end
334 endcase
335 end
00e30b4d
JW
336 `INSN_LDH_AC: begin
337 case (cycle)
338 0: begin
339 address <= {8'hFF,registers[`REG_C]};
340 if (opcode[4]) begin // LD A,(C)
341 rd <= 1;
342 end else begin
343 wr <= 1;
fa136d63 344 wdata <= registers[`REG_A];
00e30b4d
JW
345 end
346 end
69ca9b5f 347 1: begin
00e30b4d
JW
348 `EXEC_NEWCYCLE;
349 `EXEC_INC_PC;
350 end
351 endcase
352 end
fa136d63
JW
353 `INSN_LDx_AHL: begin
354 case (cycle)
69ca9b5f 355 0: begin
fa136d63
JW
356 address <= {registers[`REG_H],registers[`REG_L]};
357 if (opcode[3]) begin // LDx A, (HL)
358 rd <= 1;
359 end else begin
360 wr <= 1;
361 wdata <= registers[`REG_A];
362 end
363 end
364 1: begin
365 `EXEC_NEWCYCLE;
366 `EXEC_INC_PC;
367 end
368 endcase
369 end
94522011
JW
370 `INSN_ALU8: begin
371 if ((opcode[2:0] == `INSN_reg_dHL) && (cycle == 0)) begin
372 // fffffffff fuck your shit, read from (HL) :(
373 rd <= 1;
374 address <= {registers[`REG_H], registers[`REG_L]};
375 end else begin
376 `EXEC_NEWCYCLE;
377 `EXEC_INC_PC;
378 case (opcode[2:0])
69ca9b5f
JW
379 `INSN_reg_A: tmp <= registers[`REG_A];
380 `INSN_reg_B: tmp <= registers[`REG_B];
381 `INSN_reg_C: tmp <= registers[`REG_C];
382 `INSN_reg_D: tmp <= registers[`REG_D];
383 `INSN_reg_E: tmp <= registers[`REG_E];
384 `INSN_reg_H: tmp <= registers[`REG_H];
385 `INSN_reg_L: tmp <= registers[`REG_L];
386 `INSN_reg_dHL: tmp <= rdata;
94522011
JW
387 endcase
388 end
389 end
a00483d0
JW
390 `INSN_ALU_A: begin
391 `EXEC_NEWCYCLE;
392 `EXEC_INC_PC;
393 end
d3938806
JW
394 `INSN_NOP: begin
395 `EXEC_NEWCYCLE;
396 `EXEC_INC_PC;
397 end
1e03e021
JW
398 `INSN_RST: begin
399 case (cycle)
abae5818 400 0: begin
69ca9b5f 401 `EXEC_INC_PC; // This goes FIRST in RST
abae5818 402 end
69ca9b5f 403 1: begin
1e03e021
JW
404 wr <= 1;
405 address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
406 wdata <= registers[`REG_PCH];
407 end
69ca9b5f 408 2: begin
1e03e021
JW
409 wr <= 1;
410 address <= {registers[`REG_SPH],registers[`REG_SPL]}-2;
411 wdata <= registers[`REG_PCL];
412 end
69ca9b5f 413 3: begin
1e03e021
JW
414 `EXEC_NEWCYCLE;
415 {registers[`REG_PCH],registers[`REG_PCL]} <=
416 {10'b0,opcode[5:3],3'b0};
417 end
418 endcase
419 end
f26748f7 420 `INSN_RET,`INSN_RETCC: begin
abae5818
JW
421 case (cycle)
422 0: begin
423 rd <= 1;
424 address <= {registers[`REG_SPH],registers[`REG_SPL]};
425 end
611e4a90 426 1: begin // SPECIAL CASE: cycle does NOT increase linearly with ret!
dadf7990
JW
427 `EXEC_INC_PC; // cycle 1 is skipped if we are not retcc
428 case (opcode[4:3])
611e4a90
JW
429 `INSN_cc_NZ: if (registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
430 `INSN_cc_Z: if (~registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
431 `INSN_cc_NC: if (registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
432 `INSN_cc_C: if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
433 endcase
434 rd <= 1;
435 address <= {registers[`REG_SPH],registers[`REG_SPL]};
436 end
437 2: begin
abae5818
JW
438 rd <= 1;
439 address <= {registers[`REG_SPH],registers[`REG_SPL]} + 1;
440 end
611e4a90
JW
441 3: begin /* twiddle thumbs */ end
442 4: begin
abae5818
JW
443 `EXEC_NEWCYCLE;
444 // do NOT increment PC!
445 end
446 endcase
447 end
6b4e2828 448 `INSN_CALL,`INSN_CALLCC: begin
ef6fbe31
JW
449 case (cycle)
450 0: begin
451 `EXEC_INC_PC;
452 `EXEC_NEXTADDR_PCINC;
453 rd <= 1;
454 end
455 1: begin
456 `EXEC_INC_PC;
457 `EXEC_NEXTADDR_PCINC;
458 rd <= 1;
459 end
460 2: begin
4f9c2edf 461 `EXEC_INC_PC;
6b4e2828
JW
462 if (!opcode[0]) // i.e., is callcc
463 /* We need to check the condition code to bail out. */
464 case (opcode[4:3])
465 `INSN_cc_NZ: if (registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
466 `INSN_cc_Z: if (~registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
467 `INSN_cc_NC: if (registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
468 `INSN_cc_C: if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
469 endcase
4f9c2edf
JW
470 end
471 3: begin
ef6fbe31
JW
472 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 1;
473 wdata <= registers[`REG_PCH];
474 wr <= 1;
475 end
4f9c2edf 476 4: begin
ef6fbe31
JW
477 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 2;
478 wdata <= registers[`REG_PCL];
479 wr <= 1;
480 end
ef6fbe31
JW
481 5: begin
482 `EXEC_NEWCYCLE; /* do NOT increment the PC */
483 end
484 endcase
485 end
a85b19a7
JW
486 `INSN_JP_imm,`INSN_JPCC_imm: begin
487 case (cycle)
488 0: begin
489 `EXEC_INC_PC;
490 `EXEC_NEXTADDR_PCINC;
491 rd <= 1;
492 end
493 1: begin
494 `EXEC_INC_PC;
495 `EXEC_NEXTADDR_PCINC;
496 rd <= 1;
497 end
498 2: begin
a00483d0 499 `EXEC_INC_PC;
a85b19a7
JW
500 if (!opcode[0]) begin // i.e., JP cc,nn
501 /* We need to check the condition code to bail out. */
502 case (opcode[4:3])
503 `INSN_cc_NZ: if (registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
a00483d0 504 `INSN_cc_Z: if (~registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
a85b19a7 505 `INSN_cc_NC: if (registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
a00483d0 506 `INSN_cc_C: if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
a85b19a7
JW
507 endcase
508 end
509 end
510 3: begin
511 `EXEC_NEWCYCLE;
512 end
513 endcase
514 end
6b4e2828
JW
515 `INSN_JP_HL: begin
516 `EXEC_NEWCYCLE;
517 end
722e486a
JW
518 `INSN_JR_imm,`INSN_JRCC_imm: begin
519 case (cycle)
520 0: begin
521 `EXEC_INC_PC;
522 `EXEC_NEXTADDR_PCINC;
523 rd <= 1;
524 end
525 1: begin
526 `EXEC_INC_PC;
527 if (opcode[5]) begin // i.e., JP cc,nn
528 /* We need to check the condition code to bail out. */
529 case (opcode[4:3])
530 `INSN_cc_NZ: if (registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
531 `INSN_cc_Z: if (~registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
532 `INSN_cc_NC: if (registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
533 `INSN_cc_C: if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
534 endcase
535 end
536 end
537 2: begin
538 `EXEC_NEWCYCLE;
539 end
540 endcase
541 end
dadf7990
JW
542 `INSN_INCDEC16: begin
543 case (cycle)
544 0: begin
545 case (opcode[5:4])
546 `INSN_reg16_BC: begin
547 tmp <= registers[`REG_B];
548 tmp2 <= registers[`REG_C];
549 end
550 `INSN_reg16_DE: begin
551 tmp <= registers[`REG_D];
552 tmp2 <= registers[`REG_E];
553 end
554 `INSN_reg16_HL: begin
555 tmp <= registers[`REG_H];
556 tmp2 <= registers[`REG_L];
557 end
558 `INSN_reg16_SP: begin
559 tmp <= registers[`REG_SPH];
560 tmp2 <= registers[`REG_SPL];
561 end
562 endcase
563 end
564 1: begin
565 `EXEC_INC_PC;
566 `EXEC_NEWCYCLE;
567 end
568 endcase
569 end
f8db6448
JW
570 `INSN_VOP_INTR: begin
571 case (cycle)
572 0: begin
573 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 1;
574 wdata <= registers[`REG_PCH];
575 wr <= 1;
576 end
577 1: begin
578 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 2;
579 wdata <= registers[`REG_PCL];
580 wr <= 1;
581 end
582 2: begin
583 `EXEC_NEWCYCLE;
584 end
585 endcase
586 end
587 `INSN_DI: begin
588 `EXEC_NEWCYCLE;
589 `EXEC_INC_PC;
590 end
591 `INSN_EI: begin
592 `EXEC_NEWCYCLE;
593 `EXEC_INC_PC;
594 end
634ce02c
JW
595 default:
596 $stop;
2f55f809
JW
597 endcase
598 state <= `STATE_WRITEBACK;
599 end
600 `STATE_WRITEBACK: begin
601 casex (opcode)
634ce02c
JW
602 `INSN_LD_reg_imm8:
603 case (cycle)
2e642f1f 604 0: begin end
69ca9b5f 605 1: case (opcode[5:3])
2e642f1f
JW
606 `INSN_reg_A: begin registers[`REG_A] <= rdata; end
607 `INSN_reg_B: begin registers[`REG_B] <= rdata; end
608 `INSN_reg_C: begin registers[`REG_C] <= rdata; end
609 `INSN_reg_D: begin registers[`REG_D] <= rdata; end
610 `INSN_reg_E: begin registers[`REG_E] <= rdata; end
611 `INSN_reg_H: begin registers[`REG_H] <= rdata; end
612 `INSN_reg_L: begin registers[`REG_L] <= rdata; end
613 `INSN_reg_dHL: begin /* Go off to cycle 2 */ end
b85870e0 614 endcase
2e642f1f 615 2: begin end
634ce02c
JW
616 endcase
617 `INSN_HALT: begin
618 /* Nothing needs happen here. */
619 /* XXX Interrupts needed for HALT. */
620 end
621 `INSN_LD_HL_reg: begin
2e642f1f 622 /* Nothing of interest here */
634ce02c
JW
623 end
624 `INSN_LD_reg_HL: begin
625 case (cycle)
2e642f1f 626 0: begin end
634ce02c
JW
627 1: begin
628 case (opcode[5:3])
69ca9b5f
JW
629 `INSN_reg_A: registers[`REG_A] <= tmp;
630 `INSN_reg_B: registers[`REG_B] <= tmp;
631 `INSN_reg_C: registers[`REG_C] <= tmp;
632 `INSN_reg_D: registers[`REG_D] <= tmp;
633 `INSN_reg_E: registers[`REG_E] <= tmp;
634 `INSN_reg_H: registers[`REG_H] <= tmp;
635 `INSN_reg_L: registers[`REG_L] <= tmp;
634ce02c 636 endcase
634ce02c
JW
637 end
638 endcase
639 end
640 `INSN_LD_reg_reg: begin
641 case (opcode[5:3])
69ca9b5f
JW
642 `INSN_reg_A: registers[`REG_A] <= tmp;
643 `INSN_reg_B: registers[`REG_B] <= tmp;
644 `INSN_reg_C: registers[`REG_C] <= tmp;
645 `INSN_reg_D: registers[`REG_D] <= tmp;
646 `INSN_reg_E: registers[`REG_E] <= tmp;
647 `INSN_reg_H: registers[`REG_H] <= tmp;
648 `INSN_reg_L: registers[`REG_L] <= tmp;
634ce02c
JW
649 endcase
650 end
651 `INSN_LD_reg_imm16: begin
652 case (cycle)
2e642f1f 653 0: begin /* */ end
634ce02c
JW
654 1: begin
655 case (opcode[5:4])
656 `INSN_reg16_BC: registers[`REG_C] <= rdata;
657 `INSN_reg16_DE: registers[`REG_E] <= rdata;
658 `INSN_reg16_HL: registers[`REG_L] <= rdata;
659 `INSN_reg16_SP: registers[`REG_SPL] <= rdata;
660 endcase
634ce02c
JW
661 end
662 2: begin
663 case (opcode[5:4])
664 `INSN_reg16_BC: registers[`REG_B] <= rdata;
665 `INSN_reg16_DE: registers[`REG_D] <= rdata;
666 `INSN_reg16_HL: registers[`REG_H] <= rdata;
667 `INSN_reg16_SP: registers[`REG_SPH] <= rdata;
668 endcase
634ce02c
JW
669 end
670 endcase
671 end
672 `INSN_LD_SP_HL: begin
673 case (cycle)
2e642f1f
JW
674 0: registers[`REG_SPH] <= tmp;
675 1: registers[`REG_SPL] <= tmp;
634ce02c
JW
676 endcase
677 end
97649fed
JW
678 `INSN_PUSH_reg: begin /* PUSH is 16 cycles! */
679 case (cycle)
2e642f1f
JW
680 0: {registers[`REG_SPH],registers[`REG_SPL]} <=
681 {registers[`REG_SPH],registers[`REG_SPL]} - 1;
682 1: {registers[`REG_SPH],registers[`REG_SPL]} <=
683 {registers[`REG_SPH],registers[`REG_SPL]} - 1;
684 2: begin /* type F */ end
685 3: begin /* type F */ end
97649fed
JW
686 endcase
687 end
688 `INSN_POP_reg: begin /* POP is 12 cycles! */
689 case (cycle)
2e642f1f
JW
690 0: {registers[`REG_SPH],registers[`REG_SPL]} <=
691 {registers[`REG_SPH],registers[`REG_SPL]} + 1;
97649fed
JW
692 1: begin
693 case (opcode[5:4])
694 `INSN_stack_AF: registers[`REG_F] <= rdata;
695 `INSN_stack_BC: registers[`REG_C] <= rdata;
696 `INSN_stack_DE: registers[`REG_E] <= rdata;
697 `INSN_stack_HL: registers[`REG_L] <= rdata;
698 endcase
241c995c 699 {registers[`REG_SPH],registers[`REG_SPL]} <=
97649fed 700 {registers[`REG_SPH],registers[`REG_SPL]} + 1;
97649fed
JW
701 end
702 2: begin
703 case (opcode[5:4])
704 `INSN_stack_AF: registers[`REG_A] <= rdata;
705 `INSN_stack_BC: registers[`REG_B] <= rdata;
706 `INSN_stack_DE: registers[`REG_D] <= rdata;
707 `INSN_stack_HL: registers[`REG_H] <= rdata;
708 endcase
97649fed
JW
709 end
710 endcase
00e30b4d
JW
711 end
712 `INSN_LDH_AC: begin
713 case (cycle)
2e642f1f
JW
714 0: begin /* Type F */ end
715 1: if (opcode[4])
716 registers[`REG_A] <= rdata;
00e30b4d
JW
717 endcase
718 end
fa136d63
JW
719 `INSN_LDx_AHL: begin
720 case (cycle)
2e642f1f 721 0: begin /* Type F */ end
fa136d63 722 1: begin
fa136d63
JW
723 if (opcode[3])
724 registers[`REG_A] <= rdata;
725 {registers[`REG_H],registers[`REG_L]} <=
726 opcode[4] ? // if set, LDD, else LDI
727 ({registers[`REG_H],registers[`REG_L]} - 1) :
728 ({registers[`REG_H],registers[`REG_L]} + 1);
729 end
730 endcase
731 end
94522011
JW
732 `INSN_ALU8: begin
733 if ((opcode[2:0] == `INSN_reg_dHL) && (cycle == 0)) begin
734 /* Sit on our asses. */
94522011
JW
735 end else begin /* Actually do the computation! */
736 case (opcode[5:3])
737 `INSN_alu_ADD: begin
738 registers[`REG_A] <=
739 registers[`REG_A] + tmp;
740 registers[`REG_F] <=
741 { /* Z */ ((registers[`REG_A] + tmp) == 0) ? 1'b1 : 1'b0,
d3938806 742 /* N */ 1'b0,
94522011
JW
743 /* H */ (({1'b0,registers[`REG_A][3:0]} + {1'b0,tmp[3:0]}) >> 4 == 1) ? 1'b1 : 1'b0,
744 /* C */ (({1'b0,registers[`REG_A]} + {1'b0,tmp}) >> 8 == 1) ? 1'b1 : 1'b0,
745 registers[`REG_F][3:0]
746 };
747 end
6dbce0b5
JW
748 `INSN_alu_ADC: begin
749 registers[`REG_A] <=
750 registers[`REG_A] + tmp + {7'b0,registers[`REG_F][4]};
751 registers[`REG_F] <=
752 { /* Z */ ((registers[`REG_A] + tmp + {7'b0,registers[`REG_F][4]}) == 0) ? 1'b1 : 1'b0,
d3938806 753 /* N */ 1'b0,
6dbce0b5
JW
754 /* H */ (({1'b0,registers[`REG_A][3:0]} + {1'b0,tmp[3:0]} + {4'b0,registers[`REG_F][4]}) >> 4 == 1) ? 1'b1 : 1'b0,
755 /* C */ (({1'b0,registers[`REG_A]} + {1'b0,tmp} + {8'b0,registers[`REG_F][4]}) >> 8 == 1) ? 1'b1 : 1'b0,
756 registers[`REG_F][3:0]
757 };
758 end
a00483d0
JW
759 `INSN_alu_SUB: begin
760 registers[`REG_A] <=
761 registers[`REG_A] - tmp;
762 registers[`REG_F] <=
763 { /* Z */ ((registers[`REG_A] - tmp) == 0) ? 1'b1 : 1'b0,
764 /* N */ 1'b1,
765 /* H */ (({1'b0,registers[`REG_A][3:0]} - {1'b0,tmp[3:0]}) >> 4 == 1) ? 1'b1 : 1'b0,
766 /* C */ (({1'b0,registers[`REG_A]} - {1'b0,tmp}) >> 8 == 1) ? 1'b1 : 1'b0,
767 registers[`REG_F][3:0]
768 };
769 end
770 `INSN_alu_SBC: begin
771 registers[`REG_A] <=
772 registers[`REG_A] - (tmp + {7'b0,registers[`REG_F][4]});
773 registers[`REG_F] <=
774 { /* Z */ ((registers[`REG_A] - (tmp + {7'b0,registers[`REG_F][4]})) == 0) ? 1'b1 : 1'b0,
775 /* N */ 1'b1,
776 /* H */ (({1'b0,registers[`REG_A][3:0]} - ({1'b0,tmp[3:0]} + {4'b0,registers[`REG_F][4]})) >> 4 == 1) ? 1'b1 : 1'b0,
777 /* C */ (({1'b0,registers[`REG_A]} - ({1'b0,tmp} + {8'b0,registers[`REG_F][4]})) >> 8 == 1) ? 1'b1 : 1'b0,
778 registers[`REG_F][3:0]
779 };
780 end
6dbce0b5
JW
781 `INSN_alu_AND: begin
782 registers[`REG_A] <=
783 registers[`REG_A] & tmp;
784 registers[`REG_F] <=
785 { /* Z */ ((registers[`REG_A] & tmp) == 0) ? 1'b1 : 1'b0,
d3938806 786 3'b010,
6dbce0b5
JW
787 registers[`REG_F][3:0]
788 };
789 end
790 `INSN_alu_OR: begin
791 registers[`REG_A] <=
792 registers[`REG_A] | tmp;
793 registers[`REG_F] <=
794 { /* Z */ ((registers[`REG_A] | tmp) == 0) ? 1'b1 : 1'b0,
d3938806 795 3'b000,
6dbce0b5
JW
796 registers[`REG_F][3:0]
797 };
798 end
799 `INSN_alu_XOR: begin
800 registers[`REG_A] <=
801 registers[`REG_A] ^ tmp;
802 registers[`REG_F] <=
803 { /* Z */ ((registers[`REG_A] ^ tmp) == 0) ? 1'b1 : 1'b0,
d3938806 804 3'b000,
6dbce0b5
JW
805 registers[`REG_F][3:0]
806 };
807 end
a00483d0
JW
808 `INSN_alu_CP: begin
809 registers[`REG_F] <=
810 { /* Z */ ((registers[`REG_A] - tmp) == 0) ? 1'b1 : 1'b0,
811 /* N */ 1'b1,
812 /* H */ (({1'b0,registers[`REG_A][3:0]} - {1'b0,tmp[3:0]}) >> 4 == 1) ? 1'b1 : 1'b0,
813 /* C */ (({1'b0,registers[`REG_A]} - {1'b0,tmp}) >> 8 == 1) ? 1'b1 : 1'b0,
814 registers[`REG_F][3:0]
815 };
816 end
94522011
JW
817 default:
818 $stop;
819 endcase
820 end
821 end
a00483d0
JW
822 `INSN_ALU_A: begin
823 case(opcode[5:3])
824 `INSN_alu_RLCA: begin
825 registers[`REG_A] <= {registers[`REG_A][6:0],registers[`REG_A][7]};
826 registers[`REG_F] <= {registers[`REG_F][7:5],registers[`REG_A][7],registers[`REG_F][3:0]};
827 end
828 `INSN_alu_RRCA: begin
829 registers[`REG_A] <= {registers[`REG_A][0],registers[`REG_A][7:1]};
830 registers[`REG_F] <= {registers[`REG_F][7:5],registers[`REG_A][0],registers[`REG_F][3:0]};
831 end
832 `INSN_alu_RLA: begin
833 registers[`REG_A] <= {registers[`REG_A][6:0],registers[`REG_F][4]};
834 registers[`REG_F] <= {registers[`REG_F][7:5],registers[`REG_A][7],registers[`REG_F][3:0]};
835 end
836 `INSN_alu_RRA: begin
837 registers[`REG_A] <= {registers[`REG_A][4],registers[`REG_A][7:1]};
838 registers[`REG_F] <= {registers[`REG_F][7:5],registers[`REG_A][0],registers[`REG_F][3:0]};
839 end
840 `INSN_alu_CPL: begin
841 registers[`REG_A] <= ~registers[`REG_A];
842 registers[`REG_F] <= {registers[`REG_F][7],1'b1,1'b1,registers[`REG_F][4:0]};
843 end
844 `INSN_alu_SCF: begin
845 registers[`REG_F] <= {registers[`REG_F][7:5],1,registers[`REG_F][3:0]};
846 end
847 `INSN_alu_CCF: begin
848 registers[`REG_F] <= {registers[`REG_F][7:5],~registers[`REG_F][4],registers[`REG_F][3:0]};
849 end
850 endcase
851 end
d3938806 852 `INSN_NOP: begin /* NOP! */ end
1e03e021
JW
853 `INSN_RST: begin
854 case (cycle)
2e642f1f
JW
855 0: begin /* type F */ end
856 1: begin /* type F */ end
857 2: begin /* type F */ end
858 3: {registers[`REG_SPH],registers[`REG_SPL]} <=
859 {registers[`REG_SPH],registers[`REG_SPL]}-2;
1e03e021
JW
860 endcase
861 end
611e4a90 862 `INSN_RET,`INSN_RETCC: begin
abae5818 863 case (cycle)
f26748f7 864 0: if (opcode[0]) // i.e., not RETCC
611e4a90
JW
865 cycle <= 1; // Skip cycle 1; it gets incremented on the next round.
866 1: begin /* Nothing need happen here. */ end
867 2: registers[`REG_PCL] <= rdata;
868 3: registers[`REG_PCH] <= rdata;
869 4: begin
abae5818
JW
870 {registers[`REG_SPH],registers[`REG_SPL]} <=
871 {registers[`REG_SPH],registers[`REG_SPL]} + 2;
dadf7990 872 if (opcode[4] && opcode[0]) /* RETI */
abae5818
JW
873 ie <= 1;
874 end
875 endcase
876 end
6b4e2828 877 `INSN_CALL,`INSN_CALLCC: begin
ef6fbe31 878 case (cycle)
2e642f1f
JW
879 0: begin /* type F */ end
880 1: tmp <= rdata; // tmp contains newpcl
881 2: tmp2 <= rdata; // tmp2 contains newpch
882 3: begin /* type F */ end
883 4: registers[`REG_PCH] <= tmp2;
ef6fbe31
JW
884 5: begin
885 {registers[`REG_SPH],registers[`REG_SPL]} <=
886 {registers[`REG_SPH],registers[`REG_SPL]} - 2;
4f9c2edf 887 registers[`REG_PCL] <= tmp;
ef6fbe31
JW
888 end
889 endcase
890 end
a85b19a7
JW
891 `INSN_JP_imm,`INSN_JPCC_imm: begin
892 case (cycle)
893 0: begin /* type F */ end
894 1: tmp <= rdata; // tmp contains newpcl
895 2: tmp2 <= rdata; // tmp2 contains newpch
896 3: {registers[`REG_PCH],registers[`REG_PCL]} <=
897 {tmp2,tmp};
898 endcase
899 end
6b4e2828
JW
900 `INSN_JP_HL: begin
901 {registers[`REG_PCH],registers[`REG_PCL]} <=
902 {registers[`REG_H],registers[`REG_L]};
903 end
722e486a
JW
904 `INSN_JR_imm,`INSN_JRCC_imm: begin
905 case (cycle)
906 0: begin /* type F */ end
907 1: tmp <= rdata;
908 2: {registers[`REG_PCH],registers[`REG_PCL]} <=
909 {registers[`REG_PCH],registers[`REG_PCL]} +
910 {tmp[7]?8'hFF:8'h00,tmp};
911 endcase
912 end
dadf7990
JW
913 `INSN_INCDEC16: begin
914 case (cycle)
915 0: {tmp,tmp2} <= {tmp,tmp2} +
916 (opcode[3] ? 16'hFFFF : 16'h0001);
917 1: begin
918 case (opcode[5:4])
919 `INSN_reg16_BC: begin
920 registers[`REG_B] <= tmp;
921 registers[`REG_C] <= tmp2;
922 end
923 `INSN_reg16_DE: begin
924 registers[`REG_D] <= tmp;
925 registers[`REG_E] <= tmp2;
926 end
927 `INSN_reg16_HL: begin
928 registers[`REG_H] <= tmp;
929 registers[`REG_L] <= tmp2;
930 end
931 `INSN_reg16_SP: begin
932 registers[`REG_SPH] <= tmp;
933 registers[`REG_SPL] <= tmp2;
934 end
935 endcase
936 end
937 endcase
938 end
f8db6448
JW
939 `INSN_VOP_INTR: begin
940 case (cycle)
941 0: begin end
942 1: {registers[`REG_SPH],registers[`REG_SPL]}
943 <= {registers[`REG_SPH],registers[`REG_SPL]} - 2;
944 2: begin
945 ie <= 0;
946 {registers[`REG_PCH],registers[`REG_PCL]} <=
947 {8'b0,jaddr};
948 end
949 endcase
950 end
951 `INSN_DI: ie <= 0;
952 `INSN_EI: iedelay <= 1;
ef6fbe31
JW
953 default:
954 $stop;
2f55f809
JW
955 endcase
956 state <= `STATE_FETCH;
957 end
958 endcase
959endmodule
This page took 0.131547 seconds and 4 git commands to generate.