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