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