e5a7d35e16262ccfa113e892f147e39f9260adee
[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                                 /* XXX UNIMP */
134                         end
135                         `INSN_LD_HL_reg: begin
136                                 /* XXX UNIMP */
137                         end
138                         `INSN_LD_reg_HL: begin
139                                 /* XXX UNIMP */
140                         end
141                         `INSN_LD_reg_reg: begin
142                                 `EXEC_INC_PC;
143                                 `EXEC_NEWCYCLE;
144                                 case (opcode[2:0])
145                                 `INSN_reg_A:    begin tmp <= registers[`REG_A]; end
146                                 `INSN_reg_B:    begin tmp <= registers[`REG_B]; end
147                                 `INSN_reg_C:    begin tmp <= registers[`REG_C]; end
148                                 `INSN_reg_D:    begin tmp <= registers[`REG_D]; end
149                                 `INSN_reg_E:    begin tmp <= registers[`REG_E]; end
150                                 `INSN_reg_H:    begin tmp <= registers[`REG_H]; end
151                                 `INSN_reg_L:    begin tmp <= registers[`REG_L]; end
152                                 endcase
153                         end
154                         endcase
155                         state <= `STATE_WRITEBACK;
156                 end
157                 `STATE_WRITEBACK: begin
158                         casex (opcode)
159                                 `INSN_LD_reg_imm8:
160                                         case (cycle)
161                                         0: cycle <= 1;
162                                         1: case (opcode[5:3])
163                                                 `INSN_reg_A:    begin registers[`REG_A] <= rdata; cycle <= 0; end
164                                                 `INSN_reg_B:    begin registers[`REG_B] <= rdata; cycle <= 0; end
165                                                 `INSN_reg_C:    begin registers[`REG_C] <= rdata; cycle <= 0; end
166                                                 `INSN_reg_D:    begin registers[`REG_D] <= rdata; cycle <= 0; end
167                                                 `INSN_reg_E:    begin registers[`REG_E] <= rdata; cycle <= 0; end
168                                                 `INSN_reg_H:    begin registers[`REG_H] <= rdata; cycle <= 0; end
169                                                 `INSN_reg_L:    begin registers[`REG_L] <= rdata; cycle <= 0; end
170                                                 `INSN_reg_dHL:  cycle <= 2;
171                                                 endcase
172                                         2: cycle <= 0;
173                                         endcase
174                                 `INSN_HALT: begin
175                                         /* XXX UNIMP */
176                                 end
177                                 `INSN_LD_HL_reg: begin
178                                         /* XXX UNIMP */
179                                 end
180                                 `INSN_LD_reg_HL: begin
181                                         /* XXX UNIMP */
182                                 end
183                                 `INSN_LD_reg_reg: begin
184                                         case (opcode[5:3])
185                                         `INSN_reg_A:    begin registers[`REG_A] <= tmp; end
186                                         `INSN_reg_B:    begin registers[`REG_B] <= tmp; end
187                                         `INSN_reg_C:    begin registers[`REG_C] <= tmp; end
188                                         `INSN_reg_D:    begin registers[`REG_D] <= tmp; end
189                                         `INSN_reg_E:    begin registers[`REG_E] <= tmp; end
190                                         `INSN_reg_H:    begin registers[`REG_H] <= tmp; end
191                                         `INSN_reg_L:    begin registers[`REG_L] <= tmp; end
192                                         endcase
193                                 end
194                         endcase
195                         state <= `STATE_FETCH;
196                 end
197                 endcase
198 endmodule
199
200 `timescale 1ns / 1ps
201 module TestBench();
202         reg clk = 0;
203         wire [15:0] addr;
204         wire [7:0] data;
205         wire wr, rd;
206         reg [7:0] rom [2047:0];
207         
208         initial $readmemh("rom.hex", rom);
209         always #10 clk <= ~clk;
210         GBZ80Core core(
211                 .clk(clk),
212                 .busaddress(addr),
213                 .busdata(data),
214                 .buswr(wr),
215                 .busrd(rd));
216         assign data = rd ? rom[addr] : 8'bzzzzzzzz;
217 endmodule
This page took 0.022609 seconds and 2 git commands to generate.