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