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