]> Joshua Wise's Git repositories - fpgaboy.git/blob - GBZ80Core.v
fa9ed0bef538de32f697ae5cd7a64e505cb843c4
[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_reg_A              3'b111
32 `define INSN_reg_B              3'b000
33 `define INSN_reg_C              3'b001
34 `define INSN_reg_D              3'b010
35 `define INSN_reg_E              3'b011
36 `define INSN_reg_H              3'b100
37 `define INSN_reg_L              3'b101
38 `define INSN_reg_dHL    3'b110
39 `define INSN_reg16_BC   2'b00
40 `define INSN_reg16_DE   2'b01
41 `define INSN_reg16_HL   2'b10
42 `define INSN_reg16_SP   2'b11
43 module GBZ80Core(
44         input clk,
45         output reg [15:0] busaddress,   /* BUS_* is latched on STATE_FETCH. */
46         inout [7:0] busdata,
47         output reg buswr, output reg busrd);
48         
49         reg [1:0] state = 0;                                    /* State within this bus cycle (see STATE_*). */
50         reg [2:0] cycle = 0;                                    /* Cycle for instructions. */
51         
52         reg [7:0] registers[11:0];
53         
54         reg [15:0] address;                             /* Address for the next bus operation. */
55         
56         reg [7:0] opcode;                               /* Opcode from the current machine cycle. */
57         
58         reg [7:0] rdata, wdata;         /* Read data from this bus cycle, or write data for the next. */
59         reg rd = 1, wr = 0, newcycle = 1;
60         
61         reg [7:0] tmp;                                  /* Generic temporary reg. */
62         
63         reg [7:0] buswdata;
64         assign busdata = buswr ? buswdata : 8'bzzzzzzzz;
65         
66         initial begin
67                 registers[ 0] = 0;
68                 registers[ 1] = 0;
69                 registers[ 2] = 0;
70                 registers[ 3] = 0;
71                 registers[ 4] = 0;
72                 registers[ 5] = 0;
73                 registers[ 6] = 0;
74                 registers[ 7] = 0;
75                 registers[ 8] = 0;
76                 registers[ 9] = 0;
77                 registers[10] = 0;
78                 registers[11] = 0;
79         end
80
81         always @(posedge clk)
82                 case (state)
83                 `STATE_FETCH: begin
84                         if (wr)
85                                 buswdata <= wdata;
86                         if (newcycle)
87                                 busaddress <= {registers[`REG_PCH], registers[`REG_PCL]};
88                         else
89                                 busaddress <= address;
90                         buswr <= wr;
91                         busrd <= rd;
92                         state <= `STATE_DECODE;
93                 end
94                 `STATE_DECODE: begin
95                         if (newcycle) begin
96                                 opcode <= busdata;
97                                 rdata <= busdata;
98                                 newcycle <= 0;
99                                 cycle <= 0;
100                         end else
101                                 if (rd) rdata <= busdata;
102                         buswr <= 0;
103                         busrd <= 0;
104                         state <= `STATE_EXECUTE;
105                 end
106                 `STATE_EXECUTE: begin
107 `define EXEC_INC_PC \
108         {registers[`REG_PCH], registers[`REG_PCL]} <= {registers[`REG_PCH], registers[`REG_PCL]} + 1
109 `define EXEC_NEXTADDR_PCINC \
110         address <= {registers[`REG_PCH], registers[`REG_PCL]} + 1
111 `define EXEC_NEWCYCLE \
112         newcycle <= 1; rd <= 1; wr <= 0
113                         casex (opcode)
114                         `INSN_LD_reg_imm8: begin
115                                 case (cycle)
116                                 0:      begin
117                                                 `EXEC_INC_PC;
118                                                 `EXEC_NEXTADDR_PCINC;
119                                                 rd <= 1;
120                                         end
121                                 1: begin
122                                                 `EXEC_INC_PC;
123                                                 if (opcode[5:3] == `INSN_reg_dHL) begin
124                                                         address <= {registers[`REG_H], registers[`REG_L]};
125                                                         wdata <= rdata;
126                                                         rd <= 0;
127                                                         wr <= 1;
128                                                 end else begin
129                                                         `EXEC_NEWCYCLE;
130                                                 end
131                                         end
132                                 2: begin
133                                                 `EXEC_NEWCYCLE;
134                                         end
135                                 endcase
136                         end
137                         `INSN_HALT: begin
138                                 `EXEC_NEWCYCLE;
139                                 /* XXX Interrupts needed for HALT. */
140                         end
141                         `INSN_LD_HL_reg: begin
142                                 case (cycle)
143                                 0:      begin
144                                                 case (opcode[2:0])
145                                                 `INSN_reg_A:    begin wdata <= registers[`REG_A]; end
146                                                 `INSN_reg_B:    begin wdata <= registers[`REG_B]; end
147                                                 `INSN_reg_C:    begin wdata <= registers[`REG_C]; end
148                                                 `INSN_reg_D:    begin wdata <= registers[`REG_D]; end
149                                                 `INSN_reg_E:    begin wdata <= registers[`REG_E]; end
150                                                 `INSN_reg_H:    begin wdata <= registers[`REG_H]; end
151                                                 `INSN_reg_L:    begin wdata <= registers[`REG_L]; end
152                                                 endcase
153                                                 address <= {registers[`REG_H], registers[`REG_L]};
154                                                 wr <= 1; rd <= 0;
155                                         end
156                                 1:      begin
157                                                 `EXEC_INC_PC;
158                                                 `EXEC_NEWCYCLE;
159                                         end
160                                 endcase
161                         end
162                         `INSN_LD_reg_HL: begin
163                                 case(cycle)
164                                 0: begin
165                                                 address <= {registers[`REG_H], registers[`REG_L]};
166                                                 wr <= 0; rd <= 1;
167                                         end
168                                 1: begin
169                                                 tmp <= rdata;
170                                                 `EXEC_INC_PC;
171                                                 `EXEC_NEWCYCLE;
172                                         end
173                                 endcase
174                         end
175                         `INSN_LD_reg_reg: begin
176                                 `EXEC_INC_PC;
177                                 `EXEC_NEWCYCLE;
178                                 case (opcode[2:0])
179                                 `INSN_reg_A:    begin tmp <= registers[`REG_A]; end
180                                 `INSN_reg_B:    begin tmp <= registers[`REG_B]; end
181                                 `INSN_reg_C:    begin tmp <= registers[`REG_C]; end
182                                 `INSN_reg_D:    begin tmp <= registers[`REG_D]; end
183                                 `INSN_reg_E:    begin tmp <= registers[`REG_E]; end
184                                 `INSN_reg_H:    begin tmp <= registers[`REG_H]; end
185                                 `INSN_reg_L:    begin tmp <= registers[`REG_L]; end
186                                 endcase
187                         end
188                         `INSN_LD_reg_imm16: begin
189                                 `EXEC_INC_PC;
190                                 case (cycle)
191                                 0:      begin
192                                                 `EXEC_NEXTADDR_PCINC;
193                                                 rd <= 1;
194                                         end
195                                 1:      begin
196                                                 `EXEC_NEXTADDR_PCINC;
197                                                 rd <= 1;
198                                         end
199                                 2: begin `EXEC_NEWCYCLE; end
200                                 endcase
201                         end
202                         `INSN_LD_SP_HL: begin
203                                 case (cycle)
204                                 0:      begin
205                                                 rd <= 0;
206                                                 address <= 16'bxxxxxxxxxxxxxxxx;
207                                                 tmp <= registers[`REG_H];
208                                         end
209                                 1:      begin
210                                                 `EXEC_NEWCYCLE;
211                                                 `EXEC_INC_PC;
212                                                 tmp <= registers[`REG_L];
213                                         end
214                                 endcase
215                         end
216                         default:
217                                 $stop;
218                         endcase
219                         state <= `STATE_WRITEBACK;
220                 end
221                 `STATE_WRITEBACK: begin
222                         casex (opcode)
223                         `INSN_LD_reg_imm8:
224                                 case (cycle)
225                                 0: cycle <= 1;
226                                 1: case (opcode[5:3])
227                                         `INSN_reg_A:    begin registers[`REG_A] <= rdata; cycle <= 0; end
228                                         `INSN_reg_B:    begin registers[`REG_B] <= rdata; cycle <= 0; end
229                                         `INSN_reg_C:    begin registers[`REG_C] <= rdata; cycle <= 0; end
230                                         `INSN_reg_D:    begin registers[`REG_D] <= rdata; cycle <= 0; end
231                                         `INSN_reg_E:    begin registers[`REG_E] <= rdata; cycle <= 0; end
232                                         `INSN_reg_H:    begin registers[`REG_H] <= rdata; cycle <= 0; end
233                                         `INSN_reg_L:    begin registers[`REG_L] <= rdata; cycle <= 0; end
234                                         `INSN_reg_dHL:  cycle <= 2;
235                                         endcase
236                                 2: cycle <= 0;
237                                 endcase
238                         `INSN_HALT: begin
239                                 /* Nothing needs happen here. */
240                                 /* XXX Interrupts needed for HALT. */
241                         end
242                         `INSN_LD_HL_reg: begin
243                                 case (cycle)
244                                 0: cycle <= 1;
245                                 1: cycle <= 0;
246                                 endcase
247                         end
248                         `INSN_LD_reg_HL: begin
249                                 case (cycle)
250                                 0:      cycle <= 1;
251                                 1:      begin
252                                                 case (opcode[5:3])
253                                                 `INSN_reg_A:    begin registers[`REG_A] <= tmp; end
254                                                 `INSN_reg_B:    begin registers[`REG_B] <= tmp; end
255                                                 `INSN_reg_C:    begin registers[`REG_C] <= tmp; end
256                                                 `INSN_reg_D:    begin registers[`REG_D] <= tmp; end
257                                                 `INSN_reg_E:    begin registers[`REG_E] <= tmp; end
258                                                 `INSN_reg_H:    begin registers[`REG_H] <= tmp; end
259                                                 `INSN_reg_L:    begin registers[`REG_L] <= tmp; end
260                                                 endcase
261                                                 cycle <= 0;
262                                         end
263                                 endcase
264                         end
265                         `INSN_LD_reg_reg: begin
266                                 case (opcode[5:3])
267                                 `INSN_reg_A:    begin registers[`REG_A] <= tmp; end
268                                 `INSN_reg_B:    begin registers[`REG_B] <= tmp; end
269                                 `INSN_reg_C:    begin registers[`REG_C] <= tmp; end
270                                 `INSN_reg_D:    begin registers[`REG_D] <= tmp; end
271                                 `INSN_reg_E:    begin registers[`REG_E] <= tmp; end
272                                 `INSN_reg_H:    begin registers[`REG_H] <= tmp; end
273                                 `INSN_reg_L:    begin registers[`REG_L] <= tmp; end
274                                 endcase
275                         end
276                         `INSN_LD_reg_imm16: begin
277                                 case (cycle)
278                                 0:      cycle <= 1;
279                                 1:      begin
280                                                 case (opcode[5:4])
281                                                 `INSN_reg16_BC: registers[`REG_C] <= rdata;
282                                                 `INSN_reg16_DE: registers[`REG_E] <= rdata;
283                                                 `INSN_reg16_HL: registers[`REG_L] <= rdata;
284                                                 `INSN_reg16_SP: registers[`REG_SPL] <= rdata;
285                                                 endcase
286                                                 cycle <= 2;
287                                         end
288                                 2: begin
289                                                 case (opcode[5:4])
290                                                 `INSN_reg16_BC: registers[`REG_B] <= rdata;
291                                                 `INSN_reg16_DE: registers[`REG_D] <= rdata;
292                                                 `INSN_reg16_HL: registers[`REG_H] <= rdata;
293                                                 `INSN_reg16_SP: registers[`REG_SPH] <= rdata;
294                                                 endcase
295                                                 cycle <= 0;
296                                         end
297                                 endcase
298                         end
299                         `INSN_LD_SP_HL: begin
300                                 case (cycle)
301                                 0: begin
302                                                 cycle <= 1;
303                                                 registers[`REG_SPH] <= tmp;
304                                         end
305                                 1: begin
306                                                 cycle <= 0;
307                                                 registers[`REG_SPL] <= tmp;
308                                         end
309                                 endcase
310                         end
311                         endcase
312                         state <= `STATE_FETCH;
313                 end
314                 endcase
315 endmodule
316
317 `timescale 1ns / 1ps
318 module TestBench();
319         reg clk = 0;
320         wire [15:0] addr;
321         wire [7:0] data;
322         wire wr, rd;
323         reg [7:0] rom [2047:0];
324         
325         initial $readmemh("rom.hex", rom);
326         always #10 clk <= ~clk;
327         GBZ80Core core(
328                 .clk(clk),
329                 .busaddress(addr),
330                 .busdata(data),
331                 .buswr(wr),
332                 .busrd(rd));
333         assign data = rd ? rom[addr] : 8'bzzzzzzzz;
334 endmodule
This page took 0.03334 seconds and 2 git commands to generate.