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