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