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