]> Joshua Wise's Git repositories - fpgaboy.git/blame_incremental - GBZ80Core.v
Yay. Fix retcc. Comparing against an x value - great idea, or greatest idea?
[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,`INSN_RETCC: 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 case (opcode[4:3]) // cycle 1 is skipped if we are not retcc
413 `INSN_cc_NZ: if (registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
414 `INSN_cc_Z: if (~registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
415 `INSN_cc_NC: if (registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
416 `INSN_cc_C: if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
417 endcase
418 rd <= 1;
419 address <= {registers[`REG_SPH],registers[`REG_SPL]};
420 end
421 2: begin
422 rd <= 1;
423 address <= {registers[`REG_SPH],registers[`REG_SPL]} + 1;
424 end
425 3: begin /* twiddle thumbs */ end
426 4: begin
427 `EXEC_NEWCYCLE;
428 // do NOT increment PC!
429 end
430 endcase
431 end
432 `INSN_CALL,`INSN_CALLCC: begin
433 case (cycle)
434 0: begin
435 `EXEC_INC_PC;
436 `EXEC_NEXTADDR_PCINC;
437 rd <= 1;
438 end
439 1: begin
440 `EXEC_INC_PC;
441 `EXEC_NEXTADDR_PCINC;
442 rd <= 1;
443 end
444 2: begin
445 `EXEC_INC_PC;
446 if (!opcode[0]) // i.e., is callcc
447 /* We need to check the condition code to bail out. */
448 case (opcode[4:3])
449 `INSN_cc_NZ: if (registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
450 `INSN_cc_Z: if (~registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
451 `INSN_cc_NC: if (registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
452 `INSN_cc_C: if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
453 endcase
454 end
455 3: begin
456 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 1;
457 wdata <= registers[`REG_PCH];
458 wr <= 1;
459 end
460 4: begin
461 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 2;
462 wdata <= registers[`REG_PCL];
463 wr <= 1;
464 end
465 5: begin
466 `EXEC_NEWCYCLE; /* do NOT increment the PC */
467 end
468 endcase
469 end
470 `INSN_JP_imm,`INSN_JPCC_imm: begin
471 case (cycle)
472 0: begin
473 `EXEC_INC_PC;
474 `EXEC_NEXTADDR_PCINC;
475 rd <= 1;
476 end
477 1: begin
478 `EXEC_INC_PC;
479 `EXEC_NEXTADDR_PCINC;
480 rd <= 1;
481 end
482 2: begin
483 `EXEC_INC_PC;
484 if (!opcode[0]) begin // i.e., JP cc,nn
485 /* We need to check the condition code to bail out. */
486 case (opcode[4:3])
487 `INSN_cc_NZ: if (registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
488 `INSN_cc_Z: if (~registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
489 `INSN_cc_NC: if (registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
490 `INSN_cc_C: if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
491 endcase
492 end
493 end
494 3: begin
495 `EXEC_NEWCYCLE;
496 end
497 endcase
498 end
499 `INSN_JP_HL: begin
500 `EXEC_NEWCYCLE;
501 end
502 `INSN_JR_imm,`INSN_JRCC_imm: begin
503 case (cycle)
504 0: begin
505 `EXEC_INC_PC;
506 `EXEC_NEXTADDR_PCINC;
507 rd <= 1;
508 end
509 1: begin
510 `EXEC_INC_PC;
511 if (opcode[5]) begin // i.e., JP cc,nn
512 /* We need to check the condition code to bail out. */
513 case (opcode[4:3])
514 `INSN_cc_NZ: if (registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
515 `INSN_cc_Z: if (~registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
516 `INSN_cc_NC: if (registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
517 `INSN_cc_C: if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
518 endcase
519 end
520 end
521 2: begin
522 `EXEC_NEWCYCLE;
523 end
524 endcase
525 end
526 default:
527 $stop;
528 endcase
529 state <= `STATE_WRITEBACK;
530 end
531 `STATE_WRITEBACK: begin
532 casex (opcode)
533 `INSN_LD_reg_imm8:
534 case (cycle)
535 0: begin end
536 1: case (opcode[5:3])
537 `INSN_reg_A: begin registers[`REG_A] <= rdata; end
538 `INSN_reg_B: begin registers[`REG_B] <= rdata; end
539 `INSN_reg_C: begin registers[`REG_C] <= rdata; end
540 `INSN_reg_D: begin registers[`REG_D] <= rdata; end
541 `INSN_reg_E: begin registers[`REG_E] <= rdata; end
542 `INSN_reg_H: begin registers[`REG_H] <= rdata; end
543 `INSN_reg_L: begin registers[`REG_L] <= rdata; end
544 `INSN_reg_dHL: begin /* Go off to cycle 2 */ end
545 endcase
546 2: begin end
547 endcase
548 `INSN_HALT: begin
549 /* Nothing needs happen here. */
550 /* XXX Interrupts needed for HALT. */
551 end
552 `INSN_LD_HL_reg: begin
553 /* Nothing of interest here */
554 end
555 `INSN_LD_reg_HL: begin
556 case (cycle)
557 0: begin end
558 1: begin
559 case (opcode[5:3])
560 `INSN_reg_A: registers[`REG_A] <= tmp;
561 `INSN_reg_B: registers[`REG_B] <= tmp;
562 `INSN_reg_C: registers[`REG_C] <= tmp;
563 `INSN_reg_D: registers[`REG_D] <= tmp;
564 `INSN_reg_E: registers[`REG_E] <= tmp;
565 `INSN_reg_H: registers[`REG_H] <= tmp;
566 `INSN_reg_L: registers[`REG_L] <= tmp;
567 endcase
568 end
569 endcase
570 end
571 `INSN_LD_reg_reg: begin
572 case (opcode[5:3])
573 `INSN_reg_A: registers[`REG_A] <= tmp;
574 `INSN_reg_B: registers[`REG_B] <= tmp;
575 `INSN_reg_C: registers[`REG_C] <= tmp;
576 `INSN_reg_D: registers[`REG_D] <= tmp;
577 `INSN_reg_E: registers[`REG_E] <= tmp;
578 `INSN_reg_H: registers[`REG_H] <= tmp;
579 `INSN_reg_L: registers[`REG_L] <= tmp;
580 endcase
581 end
582 `INSN_LD_reg_imm16: begin
583 case (cycle)
584 0: begin /* */ end
585 1: begin
586 case (opcode[5:4])
587 `INSN_reg16_BC: registers[`REG_C] <= rdata;
588 `INSN_reg16_DE: registers[`REG_E] <= rdata;
589 `INSN_reg16_HL: registers[`REG_L] <= rdata;
590 `INSN_reg16_SP: registers[`REG_SPL] <= rdata;
591 endcase
592 end
593 2: begin
594 case (opcode[5:4])
595 `INSN_reg16_BC: registers[`REG_B] <= rdata;
596 `INSN_reg16_DE: registers[`REG_D] <= rdata;
597 `INSN_reg16_HL: registers[`REG_H] <= rdata;
598 `INSN_reg16_SP: registers[`REG_SPH] <= rdata;
599 endcase
600 end
601 endcase
602 end
603 `INSN_LD_SP_HL: begin
604 case (cycle)
605 0: registers[`REG_SPH] <= tmp;
606 1: registers[`REG_SPL] <= tmp;
607 endcase
608 end
609 `INSN_PUSH_reg: begin /* PUSH is 16 cycles! */
610 case (cycle)
611 0: {registers[`REG_SPH],registers[`REG_SPL]} <=
612 {registers[`REG_SPH],registers[`REG_SPL]} - 1;
613 1: {registers[`REG_SPH],registers[`REG_SPL]} <=
614 {registers[`REG_SPH],registers[`REG_SPL]} - 1;
615 2: begin /* type F */ end
616 3: begin /* type F */ end
617 endcase
618 end
619 `INSN_POP_reg: begin /* POP is 12 cycles! */
620 case (cycle)
621 0: {registers[`REG_SPH],registers[`REG_SPL]} <=
622 {registers[`REG_SPH],registers[`REG_SPL]} + 1;
623 1: begin
624 case (opcode[5:4])
625 `INSN_stack_AF: registers[`REG_F] <= rdata;
626 `INSN_stack_BC: registers[`REG_C] <= rdata;
627 `INSN_stack_DE: registers[`REG_E] <= rdata;
628 `INSN_stack_HL: registers[`REG_L] <= rdata;
629 endcase
630 {registers[`REG_SPH],registers[`REG_SPL]} <=
631 {registers[`REG_SPH],registers[`REG_SPL]} + 1;
632 end
633 2: begin
634 case (opcode[5:4])
635 `INSN_stack_AF: registers[`REG_A] <= rdata;
636 `INSN_stack_BC: registers[`REG_B] <= rdata;
637 `INSN_stack_DE: registers[`REG_D] <= rdata;
638 `INSN_stack_HL: registers[`REG_H] <= rdata;
639 endcase
640 end
641 endcase
642 end
643 `INSN_LDH_AC: begin
644 case (cycle)
645 0: begin /* Type F */ end
646 1: if (opcode[4])
647 registers[`REG_A] <= rdata;
648 endcase
649 end
650 `INSN_LDx_AHL: begin
651 case (cycle)
652 0: begin /* Type F */ end
653 1: begin
654 if (opcode[3])
655 registers[`REG_A] <= rdata;
656 {registers[`REG_H],registers[`REG_L]} <=
657 opcode[4] ? // if set, LDD, else LDI
658 ({registers[`REG_H],registers[`REG_L]} - 1) :
659 ({registers[`REG_H],registers[`REG_L]} + 1);
660 end
661 endcase
662 end
663 `INSN_ALU8: begin
664 if ((opcode[2:0] == `INSN_reg_dHL) && (cycle == 0)) begin
665 /* Sit on our asses. */
666 end else begin /* Actually do the computation! */
667 case (opcode[5:3])
668 `INSN_alu_ADD: begin
669 registers[`REG_A] <=
670 registers[`REG_A] + tmp;
671 registers[`REG_F] <=
672 { /* Z */ ((registers[`REG_A] + tmp) == 0) ? 1'b1 : 1'b0,
673 /* N */ 1'b0,
674 /* H */ (({1'b0,registers[`REG_A][3:0]} + {1'b0,tmp[3:0]}) >> 4 == 1) ? 1'b1 : 1'b0,
675 /* C */ (({1'b0,registers[`REG_A]} + {1'b0,tmp}) >> 8 == 1) ? 1'b1 : 1'b0,
676 registers[`REG_F][3:0]
677 };
678 end
679 `INSN_alu_ADC: begin
680 registers[`REG_A] <=
681 registers[`REG_A] + tmp + {7'b0,registers[`REG_F][4]};
682 registers[`REG_F] <=
683 { /* Z */ ((registers[`REG_A] + tmp + {7'b0,registers[`REG_F][4]}) == 0) ? 1'b1 : 1'b0,
684 /* N */ 1'b0,
685 /* 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,
686 /* C */ (({1'b0,registers[`REG_A]} + {1'b0,tmp} + {8'b0,registers[`REG_F][4]}) >> 8 == 1) ? 1'b1 : 1'b0,
687 registers[`REG_F][3:0]
688 };
689 end
690 `INSN_alu_SUB: begin
691 registers[`REG_A] <=
692 registers[`REG_A] - tmp;
693 registers[`REG_F] <=
694 { /* Z */ ((registers[`REG_A] - tmp) == 0) ? 1'b1 : 1'b0,
695 /* N */ 1'b1,
696 /* H */ (({1'b0,registers[`REG_A][3:0]} - {1'b0,tmp[3:0]}) >> 4 == 1) ? 1'b1 : 1'b0,
697 /* C */ (({1'b0,registers[`REG_A]} - {1'b0,tmp}) >> 8 == 1) ? 1'b1 : 1'b0,
698 registers[`REG_F][3:0]
699 };
700 end
701 `INSN_alu_SBC: begin
702 registers[`REG_A] <=
703 registers[`REG_A] - (tmp + {7'b0,registers[`REG_F][4]});
704 registers[`REG_F] <=
705 { /* Z */ ((registers[`REG_A] - (tmp + {7'b0,registers[`REG_F][4]})) == 0) ? 1'b1 : 1'b0,
706 /* N */ 1'b1,
707 /* 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,
708 /* C */ (({1'b0,registers[`REG_A]} - ({1'b0,tmp} + {8'b0,registers[`REG_F][4]})) >> 8 == 1) ? 1'b1 : 1'b0,
709 registers[`REG_F][3:0]
710 };
711 end
712 `INSN_alu_AND: begin
713 registers[`REG_A] <=
714 registers[`REG_A] & tmp;
715 registers[`REG_F] <=
716 { /* Z */ ((registers[`REG_A] & tmp) == 0) ? 1'b1 : 1'b0,
717 3'b010,
718 registers[`REG_F][3:0]
719 };
720 end
721 `INSN_alu_OR: begin
722 registers[`REG_A] <=
723 registers[`REG_A] | tmp;
724 registers[`REG_F] <=
725 { /* Z */ ((registers[`REG_A] | tmp) == 0) ? 1'b1 : 1'b0,
726 3'b000,
727 registers[`REG_F][3:0]
728 };
729 end
730 `INSN_alu_XOR: begin
731 registers[`REG_A] <=
732 registers[`REG_A] ^ tmp;
733 registers[`REG_F] <=
734 { /* Z */ ((registers[`REG_A] ^ tmp) == 0) ? 1'b1 : 1'b0,
735 3'b000,
736 registers[`REG_F][3:0]
737 };
738 end
739 `INSN_alu_CP: begin
740 registers[`REG_F] <=
741 { /* Z */ ((registers[`REG_A] - tmp) == 0) ? 1'b1 : 1'b0,
742 /* N */ 1'b1,
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
748 default:
749 $stop;
750 endcase
751 end
752 end
753 `INSN_ALU_A: begin
754 case(opcode[5:3])
755 `INSN_alu_RLCA: begin
756 registers[`REG_A] <= {registers[`REG_A][6:0],registers[`REG_A][7]};
757 registers[`REG_F] <= {registers[`REG_F][7:5],registers[`REG_A][7],registers[`REG_F][3:0]};
758 end
759 `INSN_alu_RRCA: begin
760 registers[`REG_A] <= {registers[`REG_A][0],registers[`REG_A][7:1]};
761 registers[`REG_F] <= {registers[`REG_F][7:5],registers[`REG_A][0],registers[`REG_F][3:0]};
762 end
763 `INSN_alu_RLA: begin
764 registers[`REG_A] <= {registers[`REG_A][6:0],registers[`REG_F][4]};
765 registers[`REG_F] <= {registers[`REG_F][7:5],registers[`REG_A][7],registers[`REG_F][3:0]};
766 end
767 `INSN_alu_RRA: begin
768 registers[`REG_A] <= {registers[`REG_A][4],registers[`REG_A][7:1]};
769 registers[`REG_F] <= {registers[`REG_F][7:5],registers[`REG_A][0],registers[`REG_F][3:0]};
770 end
771 `INSN_alu_CPL: begin
772 registers[`REG_A] <= ~registers[`REG_A];
773 registers[`REG_F] <= {registers[`REG_F][7],1'b1,1'b1,registers[`REG_F][4:0]};
774 end
775 `INSN_alu_SCF: begin
776 registers[`REG_F] <= {registers[`REG_F][7:5],1,registers[`REG_F][3:0]};
777 end
778 `INSN_alu_CCF: begin
779 registers[`REG_F] <= {registers[`REG_F][7:5],~registers[`REG_F][4],registers[`REG_F][3:0]};
780 end
781 endcase
782 end
783 `INSN_NOP: begin /* NOP! */ end
784 `INSN_RST: begin
785 case (cycle)
786 0: begin /* type F */ end
787 1: begin /* type F */ end
788 2: begin /* type F */ end
789 3: {registers[`REG_SPH],registers[`REG_SPL]} <=
790 {registers[`REG_SPH],registers[`REG_SPL]}-2;
791 endcase
792 end
793 `INSN_RET,`INSN_RETCC: begin
794 case (cycle)
795 0: if (opcode[0]) // i.e., not RETCC
796 cycle <= 1; // Skip cycle 1; it gets incremented on the next round.
797 1: begin /* Nothing need happen here. */ end
798 2: registers[`REG_PCL] <= rdata;
799 3: registers[`REG_PCH] <= rdata;
800 4: begin
801 {registers[`REG_SPH],registers[`REG_SPL]} <=
802 {registers[`REG_SPH],registers[`REG_SPL]} + 2;
803 if (opcode[4] && (opcode != `INSN_RETCC)) /* RETI */
804 ie <= 1;
805 end
806 endcase
807 end
808 `INSN_CALL,`INSN_CALLCC: begin
809 case (cycle)
810 0: begin /* type F */ end
811 1: tmp <= rdata; // tmp contains newpcl
812 2: tmp2 <= rdata; // tmp2 contains newpch
813 3: begin /* type F */ end
814 4: registers[`REG_PCH] <= tmp2;
815 5: begin
816 {registers[`REG_SPH],registers[`REG_SPL]} <=
817 {registers[`REG_SPH],registers[`REG_SPL]} - 2;
818 registers[`REG_PCL] <= tmp;
819 end
820 endcase
821 end
822 `INSN_JP_imm,`INSN_JPCC_imm: begin
823 case (cycle)
824 0: begin /* type F */ end
825 1: tmp <= rdata; // tmp contains newpcl
826 2: tmp2 <= rdata; // tmp2 contains newpch
827 3: {registers[`REG_PCH],registers[`REG_PCL]} <=
828 {tmp2,tmp};
829 endcase
830 end
831 `INSN_JP_HL: begin
832 {registers[`REG_PCH],registers[`REG_PCL]} <=
833 {registers[`REG_H],registers[`REG_L]};
834 end
835 `INSN_JR_imm,`INSN_JRCC_imm: begin
836 case (cycle)
837 0: begin /* type F */ end
838 1: tmp <= rdata;
839 2: {registers[`REG_PCH],registers[`REG_PCL]} <=
840 {registers[`REG_PCH],registers[`REG_PCL]} +
841 {tmp[7]?8'hFF:8'h00,tmp};
842 endcase
843 end
844 default:
845 $stop;
846 endcase
847 state <= `STATE_FETCH;
848 end
849 endcase
850endmodule
This page took 0.037522 seconds and 4 git commands to generate.