LD reg, imm16 and LD SP,HL
[fpgaboy.git] / GBZ80Core.v
CommitLineData
2f55f809
JW
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
b85870e0
JW
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
634ce02c
JW
29`define INSN_LD_reg_imm16 8'b00xx0001
30`define INSN_LD_SP_HL 8'b11111001
b85870e0
JW
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
634ce02c
JW
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
2f55f809
JW
43module 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
b85870e0
JW
61 reg [7:0] tmp; /* Generic temporary reg. */
62
2f55f809
JW
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;
b85870e0 98 newcycle <= 0;
2f55f809
JW
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;
2f55f809
JW
119 rd <= 1;
120 end
121 1: begin
122 `EXEC_INC_PC;
b85870e0 123 if (opcode[5:3] == `INSN_reg_dHL) begin
2f55f809
JW
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
b85870e0 137 `INSN_HALT: begin
f2e04715
JW
138 `EXEC_NEWCYCLE;
139 /* XXX Interrupts needed for HALT. */
b85870e0
JW
140 end
141 `INSN_LD_HL_reg: begin
f2e04715
JW
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
b85870e0
JW
161 end
162 `INSN_LD_reg_HL: begin
f2e04715
JW
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
b85870e0
JW
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
634ce02c
JW
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;
2f55f809
JW
218 endcase
219 state <= `STATE_WRITEBACK;
220 end
221 `STATE_WRITEBACK: begin
222 casex (opcode)
634ce02c
JW
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;
b85870e0 235 endcase
634ce02c
JW
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
2f55f809
JW
311 endcase
312 state <= `STATE_FETCH;
313 end
314 endcase
315endmodule
316
317`timescale 1ns / 1ps
318module 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;
334endmodule
This page took 0.047984 seconds and 4 git commands to generate.