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