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