]> Joshua Wise's Git repositories - fpgaboy.git/blob - GBZ80Core.v
0cdefa546c112fb204503bc5e17a6848e9136639
[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
37 `define INSN_reg_A              3'b111
38 `define INSN_reg_B              3'b000
39 `define INSN_reg_C              3'b001
40 `define INSN_reg_D              3'b010
41 `define INSN_reg_E              3'b011
42 `define INSN_reg_H              3'b100
43 `define INSN_reg_L              3'b101
44 `define INSN_reg_dHL    3'b110
45 `define INSN_reg16_BC   2'b00
46 `define INSN_reg16_DE   2'b01
47 `define INSN_reg16_HL   2'b10
48 `define INSN_reg16_SP   2'b11
49 `define INSN_stack_AF   2'b11
50 `define INSN_stack_BC   2'b00
51 `define INSN_stack_DE   2'b01
52 `define INSN_stack_HL   2'b10
53 `define INSN_alu_ADD            3'b000
54 `define INSN_alu_ADC            3'b001
55 `define INSN_alu_SUB            3'b010
56 `define INSN_alu_SBC            3'b011
57 `define INSN_alu_AND            3'b100
58 `define INSN_alu_XOR            3'b101
59 `define INSN_alu_OR             3'b110
60 `define INSN_alu_CP             3'b111          // Oh lawd, is dat some CP?
61
62 module GBZ80Core(
63         input clk,
64         output reg [15:0] busaddress,   /* BUS_* is latched on STATE_FETCH. */
65         inout [7:0] busdata,
66         output reg buswr, output reg busrd);
67         
68         reg [1:0] state = 0;                                    /* State within this bus cycle (see STATE_*). */
69         reg [2:0] cycle = 0;                                    /* Cycle for instructions. */
70         
71         reg [7:0] registers[11:0];
72         
73         reg [15:0] address;                             /* Address for the next bus operation. */
74         
75         reg [7:0] opcode;                               /* Opcode from the current machine cycle. */
76         
77         reg [7:0] rdata, wdata;         /* Read data from this bus cycle, or write data for the next. */
78         reg rd = 1, wr = 0, newcycle = 1;
79         
80         reg [7:0] tmp;                                  /* Generic temporary reg. */
81         
82         reg [7:0] buswdata;
83         assign busdata = buswr ? buswdata : 8'bzzzzzzzz;
84         
85         initial begin
86                 registers[ 0] <= 0;
87                 registers[ 1] <= 0;
88                 registers[ 2] <= 0;
89                 registers[ 3] <= 0;
90                 registers[ 4] <= 0;
91                 registers[ 5] <= 0;
92                 registers[ 6] <= 0;
93                 registers[ 7] <= 0;
94                 registers[ 8] <= 0;
95                 registers[ 9] <= 0;
96                 registers[10] <= 0;
97                 registers[11] <= 0;
98         end
99
100         always @(posedge clk)
101                 case (state)
102                 `STATE_FETCH: begin
103                         if (wr)
104                                 buswdata <= wdata;
105                         if (newcycle)
106                                 busaddress <= {registers[`REG_PCH], registers[`REG_PCL]};
107                         else
108                                 busaddress <= address;
109                         buswr <= wr;
110                         busrd <= rd;
111                         state <= `STATE_DECODE;
112                 end
113                 `STATE_DECODE: begin
114                         if (newcycle) begin
115                                 opcode <= busdata;
116                                 rdata <= busdata;
117                                 newcycle <= 0;
118                                 cycle <= 0;
119                         end else
120                                 if (rd) rdata <= busdata;
121                         buswr <= 0;
122                         busrd <= 0;
123                         wr <= 0;
124                         rd <= 0;
125                         address <= 16'bxxxxxxxxxxxxxxxx;        // Make it obvious if something of type has happened.
126                         wdata <= 8'bxxxxxxxx;
127                         state <= `STATE_EXECUTE;
128                 end
129                 `STATE_EXECUTE: begin
130 `define EXEC_INC_PC \
131         {registers[`REG_PCH], registers[`REG_PCL]} <= {registers[`REG_PCH], registers[`REG_PCL]} + 1
132 `define EXEC_NEXTADDR_PCINC \
133         address <= {registers[`REG_PCH], registers[`REG_PCL]} + 1
134 `define EXEC_NEWCYCLE \
135         newcycle <= 1; rd <= 1; wr <= 0
136                         casex (opcode)
137                         `INSN_LD_reg_imm8: begin
138                                 case (cycle)
139                                 0:      begin
140                                                 `EXEC_INC_PC;
141                                                 `EXEC_NEXTADDR_PCINC;
142                                                 rd <= 1;
143                                         end
144                                 1: begin
145                                                 `EXEC_INC_PC;
146                                                 if (opcode[5:3] == `INSN_reg_dHL) begin
147                                                         address <= {registers[`REG_H], registers[`REG_L]};
148                                                         wdata <= rdata;
149                                                         rd <= 0;
150                                                         wr <= 1;
151                                                 end else begin
152                                                         `EXEC_NEWCYCLE;
153                                                 end
154                                         end
155                                 2: begin
156                                                 `EXEC_NEWCYCLE;
157                                         end
158                                 endcase
159                         end
160                         `INSN_HALT: begin
161                                 `EXEC_NEWCYCLE;
162                                 /* XXX Interrupts needed for HALT. */
163                         end
164                         `INSN_LD_HL_reg: begin
165                                 case (cycle)
166                                 0:      begin
167                                                 case (opcode[2:0])
168                                                 `INSN_reg_A:    begin wdata <= registers[`REG_A]; end
169                                                 `INSN_reg_B:    begin wdata <= registers[`REG_B]; end
170                                                 `INSN_reg_C:    begin wdata <= registers[`REG_C]; end
171                                                 `INSN_reg_D:    begin wdata <= registers[`REG_D]; end
172                                                 `INSN_reg_E:    begin wdata <= registers[`REG_E]; end
173                                                 `INSN_reg_H:    begin wdata <= registers[`REG_H]; end
174                                                 `INSN_reg_L:    begin wdata <= registers[`REG_L]; end
175                                                 endcase
176                                                 address <= {registers[`REG_H], registers[`REG_L]};
177                                                 wr <= 1; rd <= 0;
178                                         end
179                                 1:      begin
180                                                 `EXEC_INC_PC;
181                                                 `EXEC_NEWCYCLE;
182                                         end
183                                 endcase
184                         end
185                         `INSN_LD_reg_HL: begin
186                                 case(cycle)
187                                 0: begin
188                                                 address <= {registers[`REG_H], registers[`REG_L]};
189                                                 rd <= 1;
190                                         end
191                                 1: begin
192                                                 tmp <= rdata;
193                                                 `EXEC_INC_PC;
194                                                 `EXEC_NEWCYCLE;
195                                         end
196                                 endcase
197                         end
198                         `INSN_LD_reg_reg: begin
199                                 `EXEC_INC_PC;
200                                 `EXEC_NEWCYCLE;
201                                 case (opcode[2:0])
202                                 `INSN_reg_A:    begin tmp <= registers[`REG_A]; end
203                                 `INSN_reg_B:    begin tmp <= registers[`REG_B]; end
204                                 `INSN_reg_C:    begin tmp <= registers[`REG_C]; end
205                                 `INSN_reg_D:    begin tmp <= registers[`REG_D]; end
206                                 `INSN_reg_E:    begin tmp <= registers[`REG_E]; end
207                                 `INSN_reg_H:    begin tmp <= registers[`REG_H]; end
208                                 `INSN_reg_L:    begin tmp <= registers[`REG_L]; end
209                                 endcase
210                         end
211                         `INSN_LD_reg_imm16: begin
212                                 `EXEC_INC_PC;
213                                 case (cycle)
214                                 0:      begin
215                                                 `EXEC_NEXTADDR_PCINC;
216                                                 rd <= 1;
217                                         end
218                                 1:      begin
219                                                 `EXEC_NEXTADDR_PCINC;
220                                                 rd <= 1;
221                                         end
222                                 2: begin `EXEC_NEWCYCLE; end
223                                 endcase
224                         end
225                         `INSN_LD_SP_HL: begin
226                                 case (cycle)
227                                 0:      begin
228                                                 tmp <= registers[`REG_H];
229                                         end
230                                 1:      begin
231                                                 `EXEC_NEWCYCLE;
232                                                 `EXEC_INC_PC;
233                                                 tmp <= registers[`REG_L];
234                                         end
235                                 endcase
236                         end
237                         `INSN_PUSH_reg: begin   /* PUSH is 16 cycles! */
238                                 case (cycle)
239                                 0: begin
240                                                 wr <= 1;
241                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
242                                                 case (opcode[5:4])
243                                                 `INSN_stack_AF: wdata <= registers[`REG_A];
244                                                 `INSN_stack_BC: wdata <= registers[`REG_B];
245                                                 `INSN_stack_DE: wdata <= registers[`REG_D];
246                                                 `INSN_stack_HL: wdata <= registers[`REG_H];
247                                                 endcase
248                                         end
249                                 1: begin
250                                                 wr <= 1;
251                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
252                                                 case (opcode[5:4])
253                                                 `INSN_stack_AF: wdata <= registers[`REG_F];
254                                                 `INSN_stack_BC: wdata <= registers[`REG_C];
255                                                 `INSN_stack_DE: wdata <= registers[`REG_E];
256                                                 `INSN_stack_HL: wdata <= registers[`REG_L];
257                                                 endcase
258                                         end
259                                 2:      begin /* TWIDDLE OUR FUCKING THUMBS! */ end
260                                 3: begin
261                                                 `EXEC_NEWCYCLE;
262                                                 `EXEC_INC_PC;
263                                         end
264                                 endcase
265                         end
266                         `INSN_POP_reg: begin    /* POP is 12 cycles! */
267                                 case (cycle)
268                                 0: begin
269                                                 rd <= 1;
270                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]};
271                                         end
272                                 1: begin
273                                                 rd <= 1;
274                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]};
275                                         end
276                                 2: begin
277                                                 `EXEC_NEWCYCLE;
278                                                 `EXEC_INC_PC;
279                                         end
280                                 endcase
281                         end
282                         `INSN_LDH_AC: begin
283                                 case (cycle)
284                                 0:      begin
285                                                 address <= {8'hFF,registers[`REG_C]};
286                                                 if (opcode[4]) begin    // LD A,(C)
287                                                         rd <= 1;
288                                                 end else begin
289                                                         wr <= 1;
290                                                         wdata <= registers[`REG_A];
291                                                 end
292                                         end
293                                 1: begin
294                                                 `EXEC_NEWCYCLE;
295                                                 `EXEC_INC_PC;
296                                         end
297                                 endcase
298                         end
299                         `INSN_LDx_AHL: begin
300                                 case (cycle)
301                                 0: begin
302                                                 address <= {registers[`REG_H],registers[`REG_L]};
303                                                 if (opcode[3]) begin    // LDx A, (HL)
304                                                         rd <= 1;
305                                                 end else begin
306                                                         wr <= 1;
307                                                         wdata <= registers[`REG_A];
308                                                 end
309                                         end
310                                 1:      begin
311                                                 `EXEC_NEWCYCLE;
312                                                 `EXEC_INC_PC;
313                                         end
314                                 endcase
315                         end
316                         `INSN_ALU8: begin
317                                 if ((opcode[2:0] == `INSN_reg_dHL) && (cycle == 0)) begin
318                                         // fffffffff fuck your shit, read from (HL) :(
319                                         rd <= 1;
320                                         address <= {registers[`REG_H], registers[`REG_L]};
321                                 end else begin
322                                         `EXEC_NEWCYCLE;
323                                         `EXEC_INC_PC;
324                                         case (opcode[2:0])
325                                         `INSN_reg_A:    begin tmp <= registers[`REG_A]; end
326                                         `INSN_reg_B:    begin tmp <= registers[`REG_B]; end
327                                         `INSN_reg_C:    begin tmp <= registers[`REG_C]; end
328                                         `INSN_reg_D:    begin tmp <= registers[`REG_D]; end
329                                         `INSN_reg_E:    begin tmp <= registers[`REG_E]; end
330                                         `INSN_reg_H:    begin tmp <= registers[`REG_H]; end
331                                         `INSN_reg_L:    begin tmp <= registers[`REG_L]; end
332                                         `INSN_reg_dHL:  begin tmp <= rdata; end
333                                         endcase
334                                 end
335                         end
336                         default:
337                                 $stop;
338                         endcase
339                         state <= `STATE_WRITEBACK;
340                 end
341                 `STATE_WRITEBACK: begin
342                         casex (opcode)
343                         `INSN_LD_reg_imm8:
344                                 case (cycle)
345                                 0: cycle <= 1;
346                                 1: case (opcode[5:3])
347                                         `INSN_reg_A:    begin registers[`REG_A] <= rdata; cycle <= 0; end
348                                         `INSN_reg_B:    begin registers[`REG_B] <= rdata; cycle <= 0; end
349                                         `INSN_reg_C:    begin registers[`REG_C] <= rdata; cycle <= 0; end
350                                         `INSN_reg_D:    begin registers[`REG_D] <= rdata; cycle <= 0; end
351                                         `INSN_reg_E:    begin registers[`REG_E] <= rdata; cycle <= 0; end
352                                         `INSN_reg_H:    begin registers[`REG_H] <= rdata; cycle <= 0; end
353                                         `INSN_reg_L:    begin registers[`REG_L] <= rdata; cycle <= 0; end
354                                         `INSN_reg_dHL:  cycle <= 2;
355                                         endcase
356                                 2: cycle <= 0;
357                                 endcase
358                         `INSN_HALT: begin
359                                 /* Nothing needs happen here. */
360                                 /* XXX Interrupts needed for HALT. */
361                         end
362                         `INSN_LD_HL_reg: begin
363                                 case (cycle)
364                                 0: cycle <= 1;
365                                 1: cycle <= 0;
366                                 endcase
367                         end
368                         `INSN_LD_reg_HL: begin
369                                 case (cycle)
370                                 0:      cycle <= 1;
371                                 1:      begin
372                                                 case (opcode[5:3])
373                                                 `INSN_reg_A:    begin registers[`REG_A] <= tmp; end
374                                                 `INSN_reg_B:    begin registers[`REG_B] <= tmp; end
375                                                 `INSN_reg_C:    begin registers[`REG_C] <= tmp; end
376                                                 `INSN_reg_D:    begin registers[`REG_D] <= tmp; end
377                                                 `INSN_reg_E:    begin registers[`REG_E] <= tmp; end
378                                                 `INSN_reg_H:    begin registers[`REG_H] <= tmp; end
379                                                 `INSN_reg_L:    begin registers[`REG_L] <= tmp; end
380                                                 endcase
381                                                 cycle <= 0;
382                                         end
383                                 endcase
384                         end
385                         `INSN_LD_reg_reg: begin
386                                 case (opcode[5:3])
387                                 `INSN_reg_A:    begin registers[`REG_A] <= tmp; end
388                                 `INSN_reg_B:    begin registers[`REG_B] <= tmp; end
389                                 `INSN_reg_C:    begin registers[`REG_C] <= tmp; end
390                                 `INSN_reg_D:    begin registers[`REG_D] <= tmp; end
391                                 `INSN_reg_E:    begin registers[`REG_E] <= tmp; end
392                                 `INSN_reg_H:    begin registers[`REG_H] <= tmp; end
393                                 `INSN_reg_L:    begin registers[`REG_L] <= tmp; end
394                                 endcase
395                         end
396                         `INSN_LD_reg_imm16: begin
397                                 case (cycle)
398                                 0:      cycle <= 1;
399                                 1:      begin
400                                                 case (opcode[5:4])
401                                                 `INSN_reg16_BC: registers[`REG_C] <= rdata;
402                                                 `INSN_reg16_DE: registers[`REG_E] <= rdata;
403                                                 `INSN_reg16_HL: registers[`REG_L] <= rdata;
404                                                 `INSN_reg16_SP: registers[`REG_SPL] <= rdata;
405                                                 endcase
406                                                 cycle <= 2;
407                                         end
408                                 2: begin
409                                                 case (opcode[5:4])
410                                                 `INSN_reg16_BC: registers[`REG_B] <= rdata;
411                                                 `INSN_reg16_DE: registers[`REG_D] <= rdata;
412                                                 `INSN_reg16_HL: registers[`REG_H] <= rdata;
413                                                 `INSN_reg16_SP: registers[`REG_SPH] <= rdata;
414                                                 endcase
415                                                 cycle <= 0;
416                                         end
417                                 endcase
418                         end
419                         `INSN_LD_SP_HL: begin
420                                 case (cycle)
421                                 0: begin
422                                                 cycle <= 1;
423                                                 registers[`REG_SPH] <= tmp;
424                                         end
425                                 1: begin
426                                                 cycle <= 0;
427                                                 registers[`REG_SPL] <= tmp;
428                                         end
429                                 endcase
430                         end
431                         `INSN_PUSH_reg: begin   /* PUSH is 16 cycles! */
432                                 case (cycle)
433                                 0: begin
434                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
435                                                         {registers[`REG_SPH],registers[`REG_SPL]} - 1;
436                                                 cycle <= 1;
437                                         end
438                                 1:      begin
439                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
440                                                         {registers[`REG_SPH],registers[`REG_SPL]} - 1;
441                                                 cycle <= 2;
442                                         end
443                                 2:      cycle <= 3;
444                                 3:      cycle <= 0;
445                                 endcase
446                         end
447                         `INSN_POP_reg: begin    /* POP is 12 cycles! */
448                                 case (cycle)
449                                 0:      begin
450                                                 cycle <= 1;
451                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
452                                                         {registers[`REG_SPH],registers[`REG_SPL]} + 1;
453                                         end
454                                 1:      begin
455                                                 case (opcode[5:4])
456                                                 `INSN_stack_AF: registers[`REG_F] <= rdata;
457                                                 `INSN_stack_BC: registers[`REG_C] <= rdata;
458                                                 `INSN_stack_DE: registers[`REG_E] <= rdata;
459                                                 `INSN_stack_HL: registers[`REG_L] <= rdata;
460                                                 endcase
461                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
462                                                         {registers[`REG_SPH],registers[`REG_SPL]} + 1;
463                                                 cycle <= 2;
464                                         end
465                                 2:      begin
466                                                 case (opcode[5:4])
467                                                 `INSN_stack_AF: registers[`REG_A] <= rdata;
468                                                 `INSN_stack_BC: registers[`REG_B] <= rdata;
469                                                 `INSN_stack_DE: registers[`REG_D] <= rdata;
470                                                 `INSN_stack_HL: registers[`REG_H] <= rdata;
471                                                 endcase
472                                                 cycle <= 0;
473                                         end
474                                 endcase
475                         end
476                         `INSN_LDH_AC: begin
477                                 case (cycle)
478                                 0:      cycle <= 1;
479                                 1: begin
480                                                 cycle <= 0;
481                                                 if (opcode[4])
482                                                         registers[`REG_A] <= rdata;
483                                         end
484                                 endcase
485                         end
486                         `INSN_LDx_AHL: begin
487                                 case (cycle)
488                                 0:      cycle <= 1;
489                                 1:      begin
490                                                 cycle <= 0;
491                                                 if (opcode[3])
492                                                         registers[`REG_A] <= rdata;
493                                                 {registers[`REG_H],registers[`REG_L]} <=
494                                                         opcode[4] ? // if set, LDD, else LDI
495                                                         ({registers[`REG_H],registers[`REG_L]} - 1) :
496                                                         ({registers[`REG_H],registers[`REG_L]} + 1);
497                                         end
498                                 endcase
499                         end
500                         `INSN_ALU8: begin
501                                 if ((opcode[2:0] == `INSN_reg_dHL) && (cycle == 0)) begin
502                                         /* Sit on our asses. */
503                                         cycle <= 1;
504                                 end else begin          /* Actually do the computation! */
505                                         case (opcode[5:3])
506                                         `INSN_alu_ADD: begin
507                                                 registers[`REG_A] <=
508                                                         registers[`REG_A] + tmp;
509                                                 registers[`REG_F] <=
510                                                         { /* Z */ ((registers[`REG_A] + tmp) == 0) ? 1'b1 : 1'b0,
511                                                           /* N */ 0,
512                                                           /* H */ (({1'b0,registers[`REG_A][3:0]} + {1'b0,tmp[3:0]}) >> 4 == 1) ? 1'b1 : 1'b0,
513                                                           /* C */ (({1'b0,registers[`REG_A]} + {1'b0,tmp}) >> 8 == 1) ? 1'b1 : 1'b0,
514                                                           registers[`REG_F][3:0]
515                                                         };
516                                         end
517                                         default:
518                                                 $stop;
519                                         endcase
520                                 end
521                         end
522                         endcase
523                         state <= `STATE_FETCH;
524                 end
525                 endcase
526 endmodule
527
528 `timescale 1ns / 1ps
529 module TestBench();
530         reg clk = 0;
531         wire [15:0] addr;
532         wire [7:0] data;
533         wire wr, rd;
534         reg [7:0] rom [2047:0];
535         
536         initial $readmemh("rom.hex", rom);
537         always #10 clk <= ~clk;
538         GBZ80Core core(
539                 .clk(clk),
540                 .busaddress(addr),
541                 .busdata(data),
542                 .buswr(wr),
543                 .busrd(rd));
544         assign data = rd ? rom[addr] : 8'bzzzzzzzz;
545 endmodule
This page took 0.104769 seconds and 2 git commands to generate.