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