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