]> Joshua Wise's Git repositories - fpgaboy.git/blame - GBZ80Core.v
Fix RAM bugs with kludge. Fix CALL bug. CALL test case.
[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
4f9c2edf
JW
398 `EXEC_INC_PC;
399 end
400 3: begin
ef6fbe31
JW
401 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 1;
402 wdata <= registers[`REG_PCH];
403 wr <= 1;
404 end
4f9c2edf 405 4: begin
ef6fbe31
JW
406 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 2;
407 wdata <= registers[`REG_PCL];
408 wr <= 1;
409 end
ef6fbe31
JW
410 5: begin
411 `EXEC_NEWCYCLE; /* do NOT increment the PC */
412 end
413 endcase
414 end
634ce02c
JW
415 default:
416 $stop;
2f55f809
JW
417 endcase
418 state <= `STATE_WRITEBACK;
419 end
420 `STATE_WRITEBACK: begin
421 casex (opcode)
634ce02c
JW
422 `INSN_LD_reg_imm8:
423 case (cycle)
69ca9b5f
JW
424 0: cycle <= 1;
425 1: case (opcode[5:3])
634ce02c
JW
426 `INSN_reg_A: begin registers[`REG_A] <= rdata; cycle <= 0; end
427 `INSN_reg_B: begin registers[`REG_B] <= rdata; cycle <= 0; end
428 `INSN_reg_C: begin registers[`REG_C] <= rdata; cycle <= 0; end
429 `INSN_reg_D: begin registers[`REG_D] <= rdata; cycle <= 0; end
430 `INSN_reg_E: begin registers[`REG_E] <= rdata; cycle <= 0; end
431 `INSN_reg_H: begin registers[`REG_H] <= rdata; cycle <= 0; end
432 `INSN_reg_L: begin registers[`REG_L] <= rdata; cycle <= 0; end
433 `INSN_reg_dHL: cycle <= 2;
b85870e0 434 endcase
69ca9b5f 435 2: cycle <= 0;
634ce02c
JW
436 endcase
437 `INSN_HALT: begin
438 /* Nothing needs happen here. */
439 /* XXX Interrupts needed for HALT. */
440 end
441 `INSN_LD_HL_reg: begin
442 case (cycle)
69ca9b5f
JW
443 0: cycle <= 1;
444 1: cycle <= 0;
634ce02c
JW
445 endcase
446 end
447 `INSN_LD_reg_HL: begin
448 case (cycle)
449 0: cycle <= 1;
450 1: begin
451 case (opcode[5:3])
69ca9b5f
JW
452 `INSN_reg_A: registers[`REG_A] <= tmp;
453 `INSN_reg_B: registers[`REG_B] <= tmp;
454 `INSN_reg_C: registers[`REG_C] <= tmp;
455 `INSN_reg_D: registers[`REG_D] <= tmp;
456 `INSN_reg_E: registers[`REG_E] <= tmp;
457 `INSN_reg_H: registers[`REG_H] <= tmp;
458 `INSN_reg_L: registers[`REG_L] <= tmp;
634ce02c
JW
459 endcase
460 cycle <= 0;
461 end
462 endcase
463 end
464 `INSN_LD_reg_reg: begin
465 case (opcode[5:3])
69ca9b5f
JW
466 `INSN_reg_A: registers[`REG_A] <= tmp;
467 `INSN_reg_B: registers[`REG_B] <= tmp;
468 `INSN_reg_C: registers[`REG_C] <= tmp;
469 `INSN_reg_D: registers[`REG_D] <= tmp;
470 `INSN_reg_E: registers[`REG_E] <= tmp;
471 `INSN_reg_H: registers[`REG_H] <= tmp;
472 `INSN_reg_L: registers[`REG_L] <= tmp;
634ce02c
JW
473 endcase
474 end
475 `INSN_LD_reg_imm16: begin
476 case (cycle)
477 0: cycle <= 1;
478 1: begin
479 case (opcode[5:4])
480 `INSN_reg16_BC: registers[`REG_C] <= rdata;
481 `INSN_reg16_DE: registers[`REG_E] <= rdata;
482 `INSN_reg16_HL: registers[`REG_L] <= rdata;
483 `INSN_reg16_SP: registers[`REG_SPL] <= rdata;
484 endcase
485 cycle <= 2;
486 end
487 2: begin
488 case (opcode[5:4])
489 `INSN_reg16_BC: registers[`REG_B] <= rdata;
490 `INSN_reg16_DE: registers[`REG_D] <= rdata;
491 `INSN_reg16_HL: registers[`REG_H] <= rdata;
492 `INSN_reg16_SP: registers[`REG_SPH] <= rdata;
493 endcase
494 cycle <= 0;
495 end
496 endcase
497 end
498 `INSN_LD_SP_HL: begin
499 case (cycle)
500 0: begin
501 cycle <= 1;
502 registers[`REG_SPH] <= tmp;
503 end
504 1: begin
505 cycle <= 0;
506 registers[`REG_SPL] <= tmp;
507 end
508 endcase
509 end
97649fed
JW
510 `INSN_PUSH_reg: begin /* PUSH is 16 cycles! */
511 case (cycle)
512 0: begin
241c995c 513 {registers[`REG_SPH],registers[`REG_SPL]} <=
97649fed
JW
514 {registers[`REG_SPH],registers[`REG_SPL]} - 1;
515 cycle <= 1;
516 end
517 1: begin
241c995c 518 {registers[`REG_SPH],registers[`REG_SPL]} <=
97649fed
JW
519 {registers[`REG_SPH],registers[`REG_SPL]} - 1;
520 cycle <= 2;
521 end
522 2: cycle <= 3;
523 3: cycle <= 0;
524 endcase
525 end
526 `INSN_POP_reg: begin /* POP is 12 cycles! */
527 case (cycle)
528 0: begin
529 cycle <= 1;
241c995c 530 {registers[`REG_SPH],registers[`REG_SPL]} <=
97649fed
JW
531 {registers[`REG_SPH],registers[`REG_SPL]} + 1;
532 end
533 1: begin
534 case (opcode[5:4])
535 `INSN_stack_AF: registers[`REG_F] <= rdata;
536 `INSN_stack_BC: registers[`REG_C] <= rdata;
537 `INSN_stack_DE: registers[`REG_E] <= rdata;
538 `INSN_stack_HL: registers[`REG_L] <= rdata;
539 endcase
241c995c 540 {registers[`REG_SPH],registers[`REG_SPL]} <=
97649fed
JW
541 {registers[`REG_SPH],registers[`REG_SPL]} + 1;
542 cycle <= 2;
543 end
544 2: begin
545 case (opcode[5:4])
546 `INSN_stack_AF: registers[`REG_A] <= rdata;
547 `INSN_stack_BC: registers[`REG_B] <= rdata;
548 `INSN_stack_DE: registers[`REG_D] <= rdata;
549 `INSN_stack_HL: registers[`REG_H] <= rdata;
550 endcase
551 cycle <= 0;
552 end
553 endcase
00e30b4d
JW
554 end
555 `INSN_LDH_AC: begin
556 case (cycle)
557 0: cycle <= 1;
558 1: begin
559 cycle <= 0;
560 if (opcode[4])
561 registers[`REG_A] <= rdata;
562 end
563 endcase
564 end
fa136d63
JW
565 `INSN_LDx_AHL: begin
566 case (cycle)
567 0: cycle <= 1;
568 1: begin
569 cycle <= 0;
570 if (opcode[3])
571 registers[`REG_A] <= rdata;
572 {registers[`REG_H],registers[`REG_L]} <=
573 opcode[4] ? // if set, LDD, else LDI
574 ({registers[`REG_H],registers[`REG_L]} - 1) :
575 ({registers[`REG_H],registers[`REG_L]} + 1);
576 end
577 endcase
578 end
94522011
JW
579 `INSN_ALU8: begin
580 if ((opcode[2:0] == `INSN_reg_dHL) && (cycle == 0)) begin
581 /* Sit on our asses. */
582 cycle <= 1;
583 end else begin /* Actually do the computation! */
584 case (opcode[5:3])
585 `INSN_alu_ADD: begin
586 registers[`REG_A] <=
587 registers[`REG_A] + tmp;
588 registers[`REG_F] <=
589 { /* Z */ ((registers[`REG_A] + tmp) == 0) ? 1'b1 : 1'b0,
d3938806 590 /* N */ 1'b0,
94522011
JW
591 /* H */ (({1'b0,registers[`REG_A][3:0]} + {1'b0,tmp[3:0]}) >> 4 == 1) ? 1'b1 : 1'b0,
592 /* C */ (({1'b0,registers[`REG_A]} + {1'b0,tmp}) >> 8 == 1) ? 1'b1 : 1'b0,
593 registers[`REG_F][3:0]
594 };
595 end
6dbce0b5
JW
596 `INSN_alu_ADC: begin
597 registers[`REG_A] <=
598 registers[`REG_A] + tmp + {7'b0,registers[`REG_F][4]};
599 registers[`REG_F] <=
600 { /* Z */ ((registers[`REG_A] + tmp + {7'b0,registers[`REG_F][4]}) == 0) ? 1'b1 : 1'b0,
d3938806 601 /* N */ 1'b0,
6dbce0b5
JW
602 /* 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,
603 /* C */ (({1'b0,registers[`REG_A]} + {1'b0,tmp} + {8'b0,registers[`REG_F][4]}) >> 8 == 1) ? 1'b1 : 1'b0,
604 registers[`REG_F][3:0]
605 };
606 end
607 `INSN_alu_AND: begin
608 registers[`REG_A] <=
609 registers[`REG_A] & tmp;
610 registers[`REG_F] <=
611 { /* Z */ ((registers[`REG_A] & tmp) == 0) ? 1'b1 : 1'b0,
d3938806 612 3'b010,
6dbce0b5
JW
613 registers[`REG_F][3:0]
614 };
615 end
616 `INSN_alu_OR: begin
617 registers[`REG_A] <=
618 registers[`REG_A] | tmp;
619 registers[`REG_F] <=
620 { /* Z */ ((registers[`REG_A] | tmp) == 0) ? 1'b1 : 1'b0,
d3938806 621 3'b000,
6dbce0b5
JW
622 registers[`REG_F][3:0]
623 };
624 end
625 `INSN_alu_XOR: begin
626 registers[`REG_A] <=
627 registers[`REG_A] ^ tmp;
628 registers[`REG_F] <=
629 { /* Z */ ((registers[`REG_A] ^ tmp) == 0) ? 1'b1 : 1'b0,
d3938806 630 3'b000,
6dbce0b5
JW
631 registers[`REG_F][3:0]
632 };
633 end
94522011
JW
634 default:
635 $stop;
636 endcase
637 end
638 end
d3938806 639 `INSN_NOP: begin /* NOP! */ end
1e03e021
JW
640 `INSN_RST: begin
641 case (cycle)
642 0: cycle <= 1;
643 1: cycle <= 2;
69ca9b5f 644 2: cycle <= 3;
1e03e021
JW
645 3: begin
646 cycle <= 0;
647 {registers[`REG_SPH],registers[`REG_SPL]} <=
648 {registers[`REG_SPH],registers[`REG_SPL]}-2;
649 end
650 endcase
651 end
abae5818
JW
652 `INSN_RET: begin
653 case (cycle)
654 0: cycle <= 1;
655 1: begin
656 cycle <= 2;
657 registers[`REG_PCL] <= rdata;
658 end
659 2: begin
660 cycle <= 3;
661 registers[`REG_PCH] <= rdata;
662 end
663 3: begin
664 cycle <= 0;
665 {registers[`REG_SPH],registers[`REG_SPL]} <=
666 {registers[`REG_SPH],registers[`REG_SPL]} + 2;
667 if (opcode[4]) /* RETI */
668 ie <= 1;
669 end
670 endcase
671 end
ef6fbe31
JW
672 `INSN_CALL: begin
673 case (cycle)
674 0: cycle <= 1;
675 1: begin
676 cycle <= 2;
677 tmp <= rdata; // tmp contains newpcl
678 end
679 2: begin
680 cycle <= 3;
681 tmp2 <= rdata; // tmp2 contains newpch
682 end
683 3: begin
684 cycle <= 4;
ef6fbe31
JW
685 end
686 4: begin
687 cycle <= 5;
4f9c2edf 688 registers[`REG_PCH] <= tmp2;
ef6fbe31
JW
689 end
690 5: begin
691 {registers[`REG_SPH],registers[`REG_SPL]} <=
692 {registers[`REG_SPH],registers[`REG_SPL]} - 2;
4f9c2edf 693 registers[`REG_PCL] <= tmp;
ef6fbe31
JW
694 cycle <= 0;
695 end
696 endcase
697 end
698 default:
699 $stop;
2f55f809
JW
700 endcase
701 state <= `STATE_FETCH;
702 end
703 endcase
704endmodule
705
706`timescale 1ns / 1ps
ef6fbe31
JW
707module ROM(
708 input [15:0] address,
709 inout [7:0] data,
710 input wr, rd);
711
712 reg [7:0] rom [2047:0];
713 initial $readmemh("rom.hex", rom);
714
715 wire decode = address[15:13] == 0;
716 reg [7:0] odata;
717 wire idata = data;
718 assign data = (rd && decode) ? odata : 8'bzzzzzzzz;
719
4f9c2edf
JW
720 always @(posedge rd)
721 if (decode)
ef6fbe31 722 odata <= rom[address];
ef6fbe31
JW
723endmodule
724
725module InternalRAM(
726 input [15:0] address,
727 inout [7:0] data,
4f9c2edf 728 input clk,
ef6fbe31
JW
729 input wr, rd);
730
731 reg [7:0] ram [8191:0];
732
733 wire decode = (address >= 16'hC000) && (address < 16'hFE00);
734 reg [7:0] odata;
735 wire idata = data;
736 assign data = (rd && decode) ? odata : 8'bzzzzzzzz;
737
4f9c2edf
JW
738 reg [13:0] diq;
739 initial
740 for (diq = 0; diq < 8191; diq = diq + 1)
741 ram[diq] = 8'h43;
742
743 always @(negedge clk)
ef6fbe31
JW
744 begin
745 if (decode && rd)
4f9c2edf
JW
746 odata <= ram[address[12:0]];
747 if (decode && wr)
748 ram[address[12:0]] <= data;
ef6fbe31
JW
749 end
750endmodule
751
2f55f809
JW
752module TestBench();
753 reg clk = 0;
754 wire [15:0] addr;
755 wire [7:0] data;
756 wire wr, rd;
2f55f809 757
2f55f809
JW
758 always #10 clk <= ~clk;
759 GBZ80Core core(
760 .clk(clk),
761 .busaddress(addr),
762 .busdata(data),
763 .buswr(wr),
764 .busrd(rd));
ef6fbe31
JW
765
766 ROM rom(
767 .address(addr),
768 .data(data),
769 .wr(wr),
770 .rd(rd));
771
772 InternalRAM ram(
773 .address(addr),
774 .data(data),
4f9c2edf 775 .clk(clk),
ef6fbe31
JW
776 .wr(wr),
777 .rd(rd));
2f55f809 778endmodule
This page took 0.119151 seconds and 4 git commands to generate.