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