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