Bugfix for SCF
[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                         `INSN_LD_reg_imm8: begin
195                                 case (cycle)
196                                 0:      begin
197                                                 `EXEC_INC_PC;
198                                                 `EXEC_NEXTADDR_PCINC;
199                                                 rd <= 1;
200                                         end
201                                 1:      begin
202                                                 `EXEC_INC_PC;
203                                                 if (opcode[5:3] == `INSN_reg_dHL) begin
204                                                         address <= {registers[`REG_H], registers[`REG_L]};
205                                                         wdata <= rdata;
206                                                         rd <= 0;
207                                                         wr <= 1;
208                                                 end else begin
209                                                         `EXEC_NEWCYCLE;
210                                                 end
211                                         end
212                                 2:      begin
213                                                 `EXEC_NEWCYCLE;
214                                         end
215                                 endcase
216                         end
217                         `INSN_HALT: begin
218                                 `EXEC_NEWCYCLE;
219                                 /* XXX Interrupts needed for HALT. */
220                         end
221                         `INSN_LD_HL_reg: begin
222                                 case (cycle)
223                                 0:      begin
224                                                 case (opcode[2:0])
225                                                 `INSN_reg_A:    wdata <= registers[`REG_A];
226                                                 `INSN_reg_B:    wdata <= registers[`REG_B];
227                                                 `INSN_reg_C:    wdata <= registers[`REG_C];
228                                                 `INSN_reg_D:    wdata <= registers[`REG_D];
229                                                 `INSN_reg_E:    wdata <= registers[`REG_E];
230                                                 `INSN_reg_H:    wdata <= registers[`REG_H];
231                                                 `INSN_reg_L:    wdata <= registers[`REG_L];
232                                                 endcase
233                                                 address <= {registers[`REG_H], registers[`REG_L]};
234                                                 wr <= 1; rd <= 0;
235                                         end
236                                 1:      begin
237                                                 `EXEC_INC_PC;
238                                                 `EXEC_NEWCYCLE;
239                                         end
240                                 endcase
241                         end
242                         `INSN_LD_reg_HL: begin
243                                 case(cycle)
244                                 0:      begin
245                                                 address <= {registers[`REG_H], registers[`REG_L]};
246                                                 rd <= 1;
247                                         end
248                                 1:      begin
249                                                 tmp <= rdata;
250                                                 `EXEC_INC_PC;
251                                                 `EXEC_NEWCYCLE;
252                                         end
253                                 endcase
254                         end
255                         `INSN_LD_reg_reg: begin
256                                 `EXEC_INC_PC;
257                                 `EXEC_NEWCYCLE;
258                                 case (opcode[2:0])
259                                 `INSN_reg_A:    tmp <= registers[`REG_A];
260                                 `INSN_reg_B:    tmp <= registers[`REG_B];
261                                 `INSN_reg_C:    tmp <= registers[`REG_C];
262                                 `INSN_reg_D:    tmp <= registers[`REG_D];
263                                 `INSN_reg_E:    tmp <= registers[`REG_E];
264                                 `INSN_reg_H:    tmp <= registers[`REG_H];
265                                 `INSN_reg_L:    tmp <= registers[`REG_L];
266                                 endcase
267                         end
268                         `INSN_LD_reg_imm16: begin
269                                 `EXEC_INC_PC;
270                                 case (cycle)
271                                 0:      begin
272                                                 `EXEC_NEXTADDR_PCINC;
273                                                 rd <= 1;
274                                         end
275                                 1:      begin
276                                                 `EXEC_NEXTADDR_PCINC;
277                                                 rd <= 1;
278                                         end
279                                 2: begin `EXEC_NEWCYCLE; end
280                                 endcase
281                         end
282                         `INSN_LD_SP_HL: begin
283                                 case (cycle)
284                                 0:      begin
285                                                 tmp <= registers[`REG_H];
286                                         end
287                                 1:      begin
288                                                 `EXEC_NEWCYCLE;
289                                                 `EXEC_INC_PC;
290                                                 tmp <= registers[`REG_L];
291                                         end
292                                 endcase
293                         end
294                         `INSN_PUSH_reg: begin   /* PUSH is 16 cycles! */
295                                 case (cycle)
296                                 0:      begin
297                                                 wr <= 1;
298                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
299                                                 case (opcode[5:4])
300                                                 `INSN_stack_AF: wdata <= registers[`REG_A];
301                                                 `INSN_stack_BC: wdata <= registers[`REG_B];
302                                                 `INSN_stack_DE: wdata <= registers[`REG_D];
303                                                 `INSN_stack_HL: wdata <= registers[`REG_H];
304                                                 endcase
305                                         end
306                                 1:      begin
307                                                 wr <= 1;
308                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]}-2;
309                                                 case (opcode[5:4])
310                                                 `INSN_stack_AF: wdata <= registers[`REG_F];
311                                                 `INSN_stack_BC: wdata <= registers[`REG_C];
312                                                 `INSN_stack_DE: wdata <= registers[`REG_E];
313                                                 `INSN_stack_HL: wdata <= registers[`REG_L];
314                                                 endcase
315                                         end
316                                 2:      begin /* Twiddle thumbs. */ end
317                                 3:      begin
318                                                 `EXEC_NEWCYCLE;
319                                                 `EXEC_INC_PC;
320                                         end
321                                 endcase
322                         end
323                         `INSN_POP_reg: begin    /* POP is 12 cycles! */
324                                 case (cycle)
325                                 0:      begin
326                                                 rd <= 1;
327                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]};
328                                         end
329                                 1:      begin
330                                                 rd <= 1;
331                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]} + 1;
332                                         end
333                                 2:      begin
334                                                 `EXEC_NEWCYCLE;
335                                                 `EXEC_INC_PC;
336                                         end
337                                 endcase
338                         end
339                         `INSN_LDH_AC: begin
340                                 case (cycle)
341                                 0:      begin
342                                                 address <= {8'hFF,registers[`REG_C]};
343                                                 if (opcode[4]) begin    // LD A,(C)
344                                                         rd <= 1;
345                                                 end else begin
346                                                         wr <= 1;
347                                                         wdata <= registers[`REG_A];
348                                                 end
349                                         end
350                                 1:      begin
351                                                 `EXEC_NEWCYCLE;
352                                                 `EXEC_INC_PC;
353                                         end
354                                 endcase
355                         end
356                         `INSN_LDx_AHL: begin
357                                 case (cycle)
358                                 0:      begin
359                                                 address <= {registers[`REG_H],registers[`REG_L]};
360                                                 if (opcode[3]) begin    // LDx A, (HL)
361                                                         rd <= 1;
362                                                 end else begin
363                                                         wr <= 1;
364                                                         wdata <= registers[`REG_A];
365                                                 end
366                                         end
367                                 1:      begin
368                                                 `EXEC_NEWCYCLE;
369                                                 `EXEC_INC_PC;
370                                         end
371                                 endcase
372                         end
373                         `INSN_ALU8: begin
374                                 if ((opcode[2:0] == `INSN_reg_dHL) && (cycle == 0)) begin
375                                         // fffffffff fuck your shit, read from (HL) :(
376                                         rd <= 1;
377                                         address <= {registers[`REG_H], registers[`REG_L]};
378                                 end else begin
379                                         `EXEC_NEWCYCLE;
380                                         `EXEC_INC_PC;
381                                         case (opcode[2:0])
382                                         `INSN_reg_A:    tmp <= registers[`REG_A];
383                                         `INSN_reg_B:    tmp <= registers[`REG_B];
384                                         `INSN_reg_C:    tmp <= registers[`REG_C];
385                                         `INSN_reg_D:    tmp <= registers[`REG_D];
386                                         `INSN_reg_E:    tmp <= registers[`REG_E];
387                                         `INSN_reg_H:    tmp <= registers[`REG_H];
388                                         `INSN_reg_L:    tmp <= registers[`REG_L];
389                                         `INSN_reg_dHL:  tmp <= rdata;
390                                         endcase
391                                 end
392                         end
393                         `INSN_ALU_A: begin
394                                 `EXEC_NEWCYCLE;
395                                 `EXEC_INC_PC;
396                         end
397                         `INSN_NOP: begin
398                                 `EXEC_NEWCYCLE;
399                                 `EXEC_INC_PC;
400                         end
401                         `INSN_RST: begin
402                                 case (cycle)
403                                 0:      begin
404                                                 `EXEC_INC_PC;           // This goes FIRST in RST
405                                         end
406                                 1:      begin
407                                                 wr <= 1;
408                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
409                                                 wdata <= registers[`REG_PCH];
410                                         end
411                                 2:      begin
412                                                 wr <= 1;
413                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]}-2;
414                                                 wdata <= registers[`REG_PCL];
415                                         end
416                                 3:      begin
417                                                 `EXEC_NEWCYCLE;
418                                                 {registers[`REG_PCH],registers[`REG_PCL]} <=
419                                                         {10'b0,opcode[5:3],3'b0};
420                                         end
421                                 endcase
422                         end
423                         `INSN_RET,`INSN_RETCC: begin
424                                 case (cycle)
425                                 0:      begin
426                                                 rd <= 1;
427                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]};
428                                         end
429                                 1:      begin   // SPECIAL CASE: cycle does NOT increase linearly with ret!
430                                                 `EXEC_INC_PC;   // cycle 1 is skipped if we are not retcc
431                                                 case (opcode[4:3])
432                                                 `INSN_cc_NZ:    if (registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
433                                                 `INSN_cc_Z:             if (~registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
434                                                 `INSN_cc_NC:    if (registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
435                                                 `INSN_cc_C:             if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
436                                                 endcase
437                                                 rd <= 1;
438                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]};
439                                         end
440                                 2:      begin
441                                                 rd <= 1;
442                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]} + 1;
443                                         end
444                                 3:      begin /* twiddle thumbs */ end
445                                 4:      begin
446                                                 `EXEC_NEWCYCLE;
447                                                 // do NOT increment PC!
448                                         end
449                                 endcase
450                         end
451                         `INSN_CALL,`INSN_CALLCC: begin
452                                 case (cycle)
453                                 0:      begin
454                                                 `EXEC_INC_PC;
455                                                 `EXEC_NEXTADDR_PCINC;
456                                                 rd <= 1;
457                                         end
458                                 1:      begin
459                                                 `EXEC_INC_PC;
460                                                 `EXEC_NEXTADDR_PCINC;
461                                                 rd <= 1;
462                                         end
463                                 2:      begin
464                                                 `EXEC_INC_PC;
465                                                 if (!opcode[0]) // i.e., is callcc
466                                                         /* We need to check the condition code to bail out. */
467                                                         case (opcode[4:3])
468                                                         `INSN_cc_NZ:    if (registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
469                                                         `INSN_cc_Z:             if (~registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
470                                                         `INSN_cc_NC:    if (registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
471                                                         `INSN_cc_C:             if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
472                                                         endcase
473                                         end
474                                 3:      begin
475                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 1;
476                                                 wdata <= registers[`REG_PCH];
477                                                 wr <= 1;
478                                         end
479                                 4:      begin
480                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 2;
481                                                 wdata <= registers[`REG_PCL];
482                                                 wr <= 1;
483                                         end
484                                 5:      begin
485                                                 `EXEC_NEWCYCLE; /* do NOT increment the PC */
486                                         end
487                                 endcase
488                         end
489                         `INSN_JP_imm,`INSN_JPCC_imm: begin
490                                 case (cycle)
491                                 0:      begin
492                                                 `EXEC_INC_PC;
493                                                 `EXEC_NEXTADDR_PCINC;
494                                                 rd <= 1;
495                                         end
496                                 1:      begin
497                                                 `EXEC_INC_PC;
498                                                 `EXEC_NEXTADDR_PCINC;
499                                                 rd <= 1;
500                                         end
501                                 2:      begin
502                                                 `EXEC_INC_PC;
503                                                 if (!opcode[0]) begin   // i.e., JP cc,nn
504                                                         /* We need to check the condition code to bail out. */
505                                                         case (opcode[4:3])
506                                                         `INSN_cc_NZ:    if (registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
507                                                         `INSN_cc_Z:             if (~registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
508                                                         `INSN_cc_NC:    if (registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
509                                                         `INSN_cc_C:             if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
510                                                         endcase
511                                                 end
512                                         end
513                                 3:      begin
514                                                 `EXEC_NEWCYCLE;
515                                         end
516                                 endcase
517                         end
518                         `INSN_JP_HL: begin
519                                 `EXEC_NEWCYCLE;
520                         end
521                         `INSN_JR_imm,`INSN_JRCC_imm: begin
522                                 case (cycle)
523                                 0:      begin
524                                                 `EXEC_INC_PC;
525                                                 `EXEC_NEXTADDR_PCINC;
526                                                 rd <= 1;
527                                         end
528                                 1: begin
529                                                 `EXEC_INC_PC;
530                                                 if (opcode[5]) begin    // i.e., JP cc,nn
531                                                         /* We need to check the condition code to bail out. */
532                                                         case (opcode[4:3])
533                                                         `INSN_cc_NZ:    if (registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
534                                                         `INSN_cc_Z:             if (~registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end
535                                                         `INSN_cc_NC:    if (registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
536                                                         `INSN_cc_C:             if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end
537                                                         endcase
538                                                 end
539                                         end
540                                 2:      begin
541                                                 `EXEC_NEWCYCLE;
542                                         end
543                                 endcase
544                         end
545                         `INSN_INCDEC16: begin
546                                 case (cycle)
547                                 0: begin
548                                                 case (opcode[5:4])
549                                                 `INSN_reg16_BC: begin
550                                                         tmp <= registers[`REG_B];
551                                                         tmp2 <= registers[`REG_C];
552                                                 end
553                                                 `INSN_reg16_DE: begin
554                                                         tmp <= registers[`REG_D];
555                                                         tmp2 <= registers[`REG_E];
556                                                 end
557                                                 `INSN_reg16_HL: begin
558                                                         tmp <= registers[`REG_H];
559                                                         tmp2 <= registers[`REG_L];
560                                                 end
561                                                 `INSN_reg16_SP: begin
562                                                         tmp <= registers[`REG_SPH];
563                                                         tmp2 <= registers[`REG_SPL];
564                                                 end
565                                                 endcase
566                                         end
567                                 1: begin
568                                                 `EXEC_INC_PC;
569                                                 `EXEC_NEWCYCLE;
570                                         end
571                                 endcase
572                         end
573                         `INSN_VOP_INTR: begin
574                                 case (cycle)
575                                 0:      begin
576                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 1;
577                                                 wdata <= registers[`REG_PCH];
578                                                 wr <= 1;
579                                         end
580                                 1:      begin
581                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 2;
582                                                 wdata <= registers[`REG_PCL];
583                                                 wr <= 1;
584                                         end
585                                 2:      begin
586                                                 `EXEC_NEWCYCLE;
587                                         end
588                                 endcase
589                         end
590                         `INSN_DI: begin
591                                 `EXEC_NEWCYCLE;
592                                 `EXEC_INC_PC;
593                         end
594                         `INSN_EI: begin
595                                 `EXEC_NEWCYCLE;
596                                 `EXEC_INC_PC;
597                         end
598                         default:
599                                 $stop;
600                         endcase
601                         state <= `STATE_WRITEBACK;
602                 end
603                 `STATE_WRITEBACK: begin
604                         casex (opcode)
605                         `INSN_LD_reg_imm8:
606                                 case (cycle)
607                                 0:      begin end
608                                 1:      case (opcode[5:3])
609                                         `INSN_reg_A:    begin registers[`REG_A] <= rdata; end
610                                         `INSN_reg_B:    begin registers[`REG_B] <= rdata; end
611                                         `INSN_reg_C:    begin registers[`REG_C] <= rdata; end
612                                         `INSN_reg_D:    begin registers[`REG_D] <= rdata; end
613                                         `INSN_reg_E:    begin registers[`REG_E] <= rdata; end
614                                         `INSN_reg_H:    begin registers[`REG_H] <= rdata; end
615                                         `INSN_reg_L:    begin registers[`REG_L] <= rdata; end
616                                         `INSN_reg_dHL:  begin /* Go off to cycle 2 */ end
617                                         endcase
618                                 2:      begin end
619                                 endcase
620                         `INSN_HALT: begin
621                                 /* Nothing needs happen here. */
622                                 /* XXX Interrupts needed for HALT. */
623                         end
624                         `INSN_LD_HL_reg: begin
625                                 /* Nothing of interest here */
626                         end
627                         `INSN_LD_reg_HL: begin
628                                 case (cycle)
629                                 0:      begin end
630                                 1:      begin
631                                                 case (opcode[5:3])
632                                                 `INSN_reg_A:    registers[`REG_A] <= tmp;
633                                                 `INSN_reg_B:    registers[`REG_B] <= tmp;
634                                                 `INSN_reg_C:    registers[`REG_C] <= tmp;
635                                                 `INSN_reg_D:    registers[`REG_D] <= tmp;
636                                                 `INSN_reg_E:    registers[`REG_E] <= tmp;
637                                                 `INSN_reg_H:    registers[`REG_H] <= tmp;
638                                                 `INSN_reg_L:    registers[`REG_L] <= tmp;
639                                                 endcase
640                                         end
641                                 endcase
642                         end
643                         `INSN_LD_reg_reg: begin
644                                 case (opcode[5:3])
645                                 `INSN_reg_A:    registers[`REG_A] <= tmp;
646                                 `INSN_reg_B:    registers[`REG_B] <= tmp;
647                                 `INSN_reg_C:    registers[`REG_C] <= tmp;
648                                 `INSN_reg_D:    registers[`REG_D] <= tmp;
649                                 `INSN_reg_E:    registers[`REG_E] <= tmp;
650                                 `INSN_reg_H:    registers[`REG_H] <= tmp;
651                                 `INSN_reg_L:    registers[`REG_L] <= tmp;
652                                 endcase
653                         end
654                         `INSN_LD_reg_imm16: begin
655                                 case (cycle)
656                                 0:      begin /* */ end
657                                 1:      begin
658                                                 case (opcode[5:4])
659                                                 `INSN_reg16_BC: registers[`REG_C] <= rdata;
660                                                 `INSN_reg16_DE: registers[`REG_E] <= rdata;
661                                                 `INSN_reg16_HL: registers[`REG_L] <= rdata;
662                                                 `INSN_reg16_SP: registers[`REG_SPL] <= rdata;
663                                                 endcase
664                                         end
665                                 2: begin
666                                                 case (opcode[5:4])
667                                                 `INSN_reg16_BC: registers[`REG_B] <= rdata;
668                                                 `INSN_reg16_DE: registers[`REG_D] <= rdata;
669                                                 `INSN_reg16_HL: registers[`REG_H] <= rdata;
670                                                 `INSN_reg16_SP: registers[`REG_SPH] <= rdata;
671                                                 endcase
672                                         end
673                                 endcase
674                         end
675                         `INSN_LD_SP_HL: begin
676                                 case (cycle)
677                                 0:      registers[`REG_SPH] <= tmp;
678                                 1: registers[`REG_SPL] <= tmp;
679                                 endcase
680                         end
681                         `INSN_PUSH_reg: begin   /* PUSH is 16 cycles! */
682                                 case (cycle)
683                                 0:      begin /* type F */ end
684                                 1:      begin /* type F */ end
685                                 2:      begin /* type F */ end
686                                 3:      {registers[`REG_SPH],registers[`REG_SPL]} <=
687                                                 {registers[`REG_SPH],registers[`REG_SPL]} - 2;
688                                 endcase
689                         end
690                         `INSN_POP_reg: begin    /* POP is 12 cycles! */
691                                 case (cycle)
692                                 0:      begin end
693                                 1:      begin
694                                                 case (opcode[5:4])
695                                                 `INSN_stack_AF: registers[`REG_F] <= rdata;
696                                                 `INSN_stack_BC: registers[`REG_C] <= rdata;
697                                                 `INSN_stack_DE: registers[`REG_E] <= rdata;
698                                                 `INSN_stack_HL: registers[`REG_L] <= rdata;
699                                                 endcase
700                                         end
701                                 2:      begin
702                                                 case (opcode[5:4])
703                                                 `INSN_stack_AF: registers[`REG_A] <= rdata;
704                                                 `INSN_stack_BC: registers[`REG_B] <= rdata;
705                                                 `INSN_stack_DE: registers[`REG_D] <= rdata;
706                                                 `INSN_stack_HL: registers[`REG_H] <= rdata;
707                                                 endcase
708                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
709                                                         {registers[`REG_SPH],registers[`REG_SPL]} + 2;
710                                         end
711                                 endcase
712                         end
713                         `INSN_LDH_AC: begin
714                                 case (cycle)
715                                 0:      begin /* Type F */ end
716                                 1:      if (opcode[4])
717                                                 registers[`REG_A] <= rdata;
718                                 endcase
719                         end
720                         `INSN_LDx_AHL: begin
721                                 case (cycle)
722                                 0:      begin /* Type F */ end
723                                 1:      begin
724                                                 if (opcode[3])
725                                                         registers[`REG_A] <= rdata;
726                                                 {registers[`REG_H],registers[`REG_L]} <=
727                                                         opcode[4] ? // if set, LDD, else LDI
728                                                         ({registers[`REG_H],registers[`REG_L]} - 1) :
729                                                         ({registers[`REG_H],registers[`REG_L]} + 1);
730                                         end
731                                 endcase
732                         end
733                         `INSN_ALU8: begin
734                                 if ((opcode[2:0] == `INSN_reg_dHL) && (cycle == 0)) begin
735                                         /* Sit on our asses. */
736                                 end else begin          /* Actually do the computation! */
737                                         case (opcode[5:3])
738                                         `INSN_alu_ADD: begin
739                                                 registers[`REG_A] <=
740                                                         registers[`REG_A] + tmp;
741                                                 registers[`REG_F] <=
742                                                         { /* Z */ ((registers[`REG_A] + tmp) == 0) ? 1'b1 : 1'b0,
743                                                           /* N */ 1'b0,
744                                                           /* H */ (({1'b0,registers[`REG_A][3:0]} + {1'b0,tmp[3:0]}) >> 4 == 1) ? 1'b1 : 1'b0,
745                                                           /* C */ (({1'b0,registers[`REG_A]} + {1'b0,tmp}) >> 8 == 1) ? 1'b1 : 1'b0,
746                                                           registers[`REG_F][3:0]
747                                                         };
748                                         end
749                                         `INSN_alu_ADC: begin
750                                                 registers[`REG_A] <=
751                                                         registers[`REG_A] + tmp + {7'b0,registers[`REG_F][4]};
752                                                 registers[`REG_F] <=
753                                                         { /* Z */ ((registers[`REG_A] + tmp + {7'b0,registers[`REG_F][4]}) == 0) ? 1'b1 : 1'b0,
754                                                           /* N */ 1'b0,
755                                                           /* 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,
756                                                           /* C */ (({1'b0,registers[`REG_A]} + {1'b0,tmp} + {8'b0,registers[`REG_F][4]}) >> 8 == 1) ? 1'b1 : 1'b0,
757                                                           registers[`REG_F][3:0]
758                                                         };
759                                         end
760                                         `INSN_alu_SUB: begin
761                                                 registers[`REG_A] <=
762                                                         registers[`REG_A] - tmp;
763                                                 registers[`REG_F] <=
764                                                         { /* Z */ ((registers[`REG_A] - tmp) == 0) ? 1'b1 : 1'b0,
765                                                           /* N */ 1'b1,
766                                                           /* H */ (({1'b0,registers[`REG_A][3:0]} - {1'b0,tmp[3:0]}) >> 4 == 1) ? 1'b1 : 1'b0,
767                                                           /* C */ (({1'b0,registers[`REG_A]} - {1'b0,tmp}) >> 8 == 1) ? 1'b1 : 1'b0,
768                                                           registers[`REG_F][3:0]
769                                                         };
770                                         end
771                                         `INSN_alu_SBC: begin
772                                                 registers[`REG_A] <=
773                                                         registers[`REG_A] - (tmp + {7'b0,registers[`REG_F][4]});
774                                                 registers[`REG_F] <=
775                                                         { /* Z */ ((registers[`REG_A] - (tmp + {7'b0,registers[`REG_F][4]})) == 0) ? 1'b1 : 1'b0,
776                                                           /* N */ 1'b1,
777                                                           /* 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,
778                                                           /* C */ (({1'b0,registers[`REG_A]} - ({1'b0,tmp} + {8'b0,registers[`REG_F][4]})) >> 8 == 1) ? 1'b1 : 1'b0,
779                                                           registers[`REG_F][3:0]
780                                                         };
781                                         end
782                                         `INSN_alu_AND: begin
783                                                 registers[`REG_A] <=
784                                                         registers[`REG_A] & tmp;
785                                                 registers[`REG_F] <=
786                                                         { /* Z */ ((registers[`REG_A] & tmp) == 0) ? 1'b1 : 1'b0,
787                                                           3'b010,
788                                                           registers[`REG_F][3:0]
789                                                         };
790                                         end
791                                         `INSN_alu_OR: begin
792                                                 registers[`REG_A] <=
793                                                         registers[`REG_A] | tmp;
794                                                 registers[`REG_F] <=
795                                                         { /* Z */ ((registers[`REG_A] | tmp) == 0) ? 1'b1 : 1'b0,
796                                                           3'b000,
797                                                           registers[`REG_F][3:0]
798                                                         };
799                                         end
800                                         `INSN_alu_XOR: begin
801                                                 registers[`REG_A] <=
802                                                         registers[`REG_A] ^ tmp;
803                                                 registers[`REG_F] <=
804                                                         { /* Z */ ((registers[`REG_A] ^ tmp) == 0) ? 1'b1 : 1'b0,
805                                                           3'b000,
806                                                           registers[`REG_F][3:0]
807                                                         };
808                                         end
809                                         `INSN_alu_CP: begin
810                                                 registers[`REG_F] <=
811                                                         { /* Z */ ((registers[`REG_A] - tmp) == 0) ? 1'b1 : 1'b0,
812                                                           /* N */ 1'b1,
813                                                           /* H */ (({1'b0,registers[`REG_A][3:0]} - {1'b0,tmp[3:0]}) >> 4 == 1) ? 1'b1 : 1'b0,
814                                                           /* C */ (({1'b0,registers[`REG_A]} - {1'b0,tmp}) >> 8 == 1) ? 1'b1 : 1'b0,
815                                                           registers[`REG_F][3:0]
816                                                         };
817                                         end
818                                         default:
819                                                 $stop;
820                                         endcase
821                                 end
822                         end
823                         `INSN_ALU_A: begin
824                                 case(opcode[5:3])
825                                 `INSN_alu_RLCA: begin
826                                         registers[`REG_A] <= {registers[`REG_A][6:0],registers[`REG_A][7]};
827                                         registers[`REG_F] <= {registers[`REG_F][7:5],registers[`REG_A][7],registers[`REG_F][3:0]};
828                                 end
829                                 `INSN_alu_RRCA: begin
830                                         registers[`REG_A] <= {registers[`REG_A][0],registers[`REG_A][7:1]};
831                                         registers[`REG_F] <= {registers[`REG_F][7:5],registers[`REG_A][0],registers[`REG_F][3:0]};
832                                 end
833                                 `INSN_alu_RLA: begin
834                                         registers[`REG_A] <= {registers[`REG_A][6:0],registers[`REG_F][4]};
835                                         registers[`REG_F] <= {registers[`REG_F][7:5],registers[`REG_A][7],registers[`REG_F][3:0]};
836                                 end
837                                 `INSN_alu_RRA: begin
838                                         registers[`REG_A] <= {registers[`REG_A][4],registers[`REG_A][7:1]};
839                                         registers[`REG_F] <= {registers[`REG_F][7:5],registers[`REG_A][0],registers[`REG_F][3:0]};
840                                 end
841                                 `INSN_alu_CPL: begin
842                                         registers[`REG_A] <= ~registers[`REG_A];
843                                         registers[`REG_F] <= {registers[`REG_F][7],1'b1,1'b1,registers[`REG_F][4:0]};
844                                 end
845                                 `INSN_alu_SCF: begin
846                                         registers[`REG_F] <= {registers[`REG_F][7:5],1'b1,registers[`REG_F][3:0]};
847                                 end
848                                 `INSN_alu_CCF: begin
849                                         registers[`REG_F] <= {registers[`REG_F][7:5],~registers[`REG_F][4],registers[`REG_F][3:0]};
850                                 end
851                                 endcase
852                         end
853                         `INSN_NOP: begin /* NOP! */ end
854                         `INSN_RST: begin
855                                 case (cycle)
856                                 0:      begin /* type F */ end
857                                 1:      begin /* type F */ end
858                                 2:      begin /* type F */ end
859                                 3:      {registers[`REG_SPH],registers[`REG_SPL]} <=
860                                                 {registers[`REG_SPH],registers[`REG_SPL]}-2;
861                                 endcase
862                         end
863                         `INSN_RET,`INSN_RETCC: begin
864                                 case (cycle)
865                                 0:      if (opcode[0])  // i.e., not RETCC
866                                                 cycle <= 1;     // Skip cycle 1; it gets incremented on the next round.
867                                 1: begin /* Nothing need happen here. */ end
868                                 2:      registers[`REG_PCL] <= rdata;
869                                 3:      registers[`REG_PCH] <= rdata;
870                                 4:      begin
871                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
872                                                         {registers[`REG_SPH],registers[`REG_SPL]} + 2;
873                                                 if (opcode[4] && opcode[0])     /* RETI */
874                                                         ie <= 1;
875                                         end
876                                 endcase
877                         end
878                         `INSN_CALL,`INSN_CALLCC: begin
879                                 case (cycle)
880                                 0:      begin /* type F */ end
881                                 1:      tmp <= rdata;   // tmp contains newpcl
882                                 2:      tmp2 <= rdata;  // tmp2 contains newpch
883                                 3:      begin /* type F */ end
884                                 4:      registers[`REG_PCH] <= tmp2;
885                                 5: begin
886                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
887                                                         {registers[`REG_SPH],registers[`REG_SPL]} - 2;
888                                                 registers[`REG_PCL] <= tmp;
889                                         end
890                                 endcase
891                         end
892                         `INSN_JP_imm,`INSN_JPCC_imm: begin
893                                 case (cycle)
894                                 0:      begin /* type F */ end
895                                 1:      tmp <= rdata;   // tmp contains newpcl
896                                 2:      tmp2 <= rdata;  // tmp2 contains newpch
897                                 3:      {registers[`REG_PCH],registers[`REG_PCL]} <=
898                                                 {tmp2,tmp};
899                                 endcase
900                         end
901                         `INSN_JP_HL: begin
902                                 {registers[`REG_PCH],registers[`REG_PCL]} <=
903                                         {registers[`REG_H],registers[`REG_L]};
904                         end
905                         `INSN_JR_imm,`INSN_JRCC_imm: begin
906                                 case (cycle)
907                                 0:      begin /* type F */ end
908                                 1:      tmp <= rdata;
909                                 2: {registers[`REG_PCH],registers[`REG_PCL]} <=
910                                                 {registers[`REG_PCH],registers[`REG_PCL]} +
911                                                 {tmp[7]?8'hFF:8'h00,tmp};
912                                 endcase
913                         end
914                         `INSN_INCDEC16: begin
915                                 case (cycle)
916                                 0:      {tmp,tmp2} <= {tmp,tmp2} +
917                                                 (opcode[3] ? 16'hFFFF : 16'h0001);
918                                 1: begin
919                                                 case (opcode[5:4])
920                                                 `INSN_reg16_BC: begin
921                                                         registers[`REG_B] <= tmp;
922                                                         registers[`REG_C] <= tmp2;
923                                                 end
924                                                 `INSN_reg16_DE: begin
925                                                         registers[`REG_D] <= tmp;
926                                                         registers[`REG_E] <= tmp2;
927                                                 end
928                                                 `INSN_reg16_HL: begin
929                                                         registers[`REG_H] <= tmp;
930                                                         registers[`REG_L] <= tmp2;
931                                                 end
932                                                 `INSN_reg16_SP: begin
933                                                         registers[`REG_SPH] <= tmp;
934                                                         registers[`REG_SPL] <= tmp2;
935                                                 end
936                                                 endcase
937                                         end
938                                 endcase
939                         end
940                         `INSN_VOP_INTR: begin
941                                 case (cycle)
942                                 0:      begin end
943                                 1:      begin end
944                                 2:      begin
945                                                 ie <= 0;
946                                                 {registers[`REG_PCH],registers[`REG_PCL]} <=
947                                                         {8'b0,jaddr};
948                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
949                                                         {registers[`REG_SPH],registers[`REG_SPL]} - 2;
950                                         end
951                                 endcase
952                         end
953                         `INSN_DI: ie <= 0;
954                         `INSN_EI: iedelay <= 1;
955                         default:
956                                 $stop;
957                         endcase
958                         state <= `STATE_FETCH;
959                 end
960                 endcase
961 endmodule
This page took 0.19919 seconds and 4 git commands to generate.