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