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