Add UCF for the z80 core
[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
97649fed
JW
31`define INSN_PUSH_reg 8'b11xx0101
32`define INSN_POP_reg 8'b11xx0001
b85870e0
JW
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
634ce02c
JW
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
97649fed
JW
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
2f55f809
JW
49module 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
b85870e0
JW
67 reg [7:0] tmp; /* Generic temporary reg. */
68
2f55f809
JW
69 reg [7:0] buswdata;
70 assign busdata = buswr ? buswdata : 8'bzzzzzzzz;
71
72 initial begin
241c995c
JW
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;
2f55f809
JW
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;
b85870e0 104 newcycle <= 0;
2f55f809
JW
105 cycle <= 0;
106 end else
107 if (rd) rdata <= busdata;
108 buswr <= 0;
109 busrd <= 0;
97649fed
JW
110 wr <= 0;
111 rd <= 0;
112 address <= 16'bxxxxxxxxxxxxxxxx; // Make it obvious if something of type has happened.
113 wdata <= 8'bxxxxxxxx;
2f55f809
JW
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;
2f55f809
JW
129 rd <= 1;
130 end
131 1: begin
132 `EXEC_INC_PC;
b85870e0 133 if (opcode[5:3] == `INSN_reg_dHL) begin
2f55f809
JW
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
b85870e0 147 `INSN_HALT: begin
f2e04715
JW
148 `EXEC_NEWCYCLE;
149 /* XXX Interrupts needed for HALT. */
b85870e0
JW
150 end
151 `INSN_LD_HL_reg: begin
f2e04715
JW
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
b85870e0
JW
171 end
172 `INSN_LD_reg_HL: begin
f2e04715
JW
173 case(cycle)
174 0: begin
175 address <= {registers[`REG_H], registers[`REG_L]};
97649fed 176 rd <= 1;
f2e04715
JW
177 end
178 1: begin
179 tmp <= rdata;
180 `EXEC_INC_PC;
181 `EXEC_NEWCYCLE;
182 end
183 endcase
b85870e0
JW
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
634ce02c
JW
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
634ce02c
JW
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
97649fed
JW
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
634ce02c
JW
269 default:
270 $stop;
2f55f809
JW
271 endcase
272 state <= `STATE_WRITEBACK;
273 end
274 `STATE_WRITEBACK: begin
275 casex (opcode)
634ce02c
JW
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;
b85870e0 288 endcase
634ce02c
JW
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
97649fed
JW
364 `INSN_PUSH_reg: begin /* PUSH is 16 cycles! */
365 case (cycle)
366 0: begin
241c995c 367 {registers[`REG_SPH],registers[`REG_SPL]} <=
97649fed
JW
368 {registers[`REG_SPH],registers[`REG_SPL]} - 1;
369 cycle <= 1;
370 end
371 1: begin
241c995c 372 {registers[`REG_SPH],registers[`REG_SPL]} <=
97649fed
JW
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;
241c995c 384 {registers[`REG_SPH],registers[`REG_SPL]} <=
97649fed
JW
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
241c995c 394 {registers[`REG_SPH],registers[`REG_SPL]} <=
97649fed
JW
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
2f55f809
JW
409 endcase
410 state <= `STATE_FETCH;
411 end
412 endcase
413endmodule
414
415`timescale 1ns / 1ps
416module 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;
432endmodule
This page took 0.058943 seconds and 4 git commands to generate.