├── .gitattributes
├── README.md
├── report
├── Project报告.pdf
└── README.md
├── screenshot
├── black-wins.jpg
├── draw.jpg
├── game-running.jpg
└── white-wins.jpg
└── src
├── clock
└── clk_divider.v
├── data
├── gobang_datapath.v
└── testbench
│ └── gobang_datapath_tb.v
├── display
├── display_pics.v
├── vga_display.v
└── vga_sync.v
├── gobang_top.v
├── input
├── ps2_input.v
├── ps2_scan.v
└── testbench
│ └── ps2_scan_tb.v
├── logic
├── gobang_logic.v
├── gobang_patterns.v
├── gobang_strategy.v
├── score_calculator.v
└── win_checker.v
└── random
└── random_generator.v
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.v linguist-language=verilog
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Verilog-Gobang-Game-with-AI
2 | This is my project for the course "Logic and Computer Design Fundamentals"(LCDF, course instructor: SQS) in Zhejiang University.
3 |
4 | It is a gobang game for one or two players which can be played using the Kintex-7 FPGA Board, a VGA monitor and a PS/2 keyboard. The players can play with each other or play with AI or watch the game between two AI. A greedy strategy is used to implement the AI of the game.
5 |
6 | If you are intrested, you can read my project report (in Chinese) for more details.
7 |
8 |
9 |
10 | ^ The game is running.
11 |
12 |
13 |
14 | ^ Black wins the game
15 |
16 |
17 |
18 | ^ White wins the game
19 |
20 |
21 |
22 | ^ It's a draw
23 |
--------------------------------------------------------------------------------
/report/Project报告.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsreaper/verilog-gobang-game-with-ai/82478150edce899de7589b3bbcb7e759f8f89cab/report/Project报告.pdf
--------------------------------------------------------------------------------
/report/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsreaper/verilog-gobang-game-with-ai/82478150edce899de7589b3bbcb7e759f8f89cab/report/README.md
--------------------------------------------------------------------------------
/screenshot/black-wins.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsreaper/verilog-gobang-game-with-ai/82478150edce899de7589b3bbcb7e759f8f89cab/screenshot/black-wins.jpg
--------------------------------------------------------------------------------
/screenshot/draw.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsreaper/verilog-gobang-game-with-ai/82478150edce899de7589b3bbcb7e759f8f89cab/screenshot/draw.jpg
--------------------------------------------------------------------------------
/screenshot/game-running.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsreaper/verilog-gobang-game-with-ai/82478150edce899de7589b3bbcb7e759f8f89cab/screenshot/game-running.jpg
--------------------------------------------------------------------------------
/screenshot/white-wins.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsreaper/verilog-gobang-game-with-ai/82478150edce899de7589b3bbcb7e759f8f89cab/screenshot/white-wins.jpg
--------------------------------------------------------------------------------
/src/clock/clk_divider.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //------------------------------------------------------------------------------
4 | // Clock division module
5 | //------------------------------------------------------------------------------
6 | module clk_divider(
7 | input wire clk, // Clock
8 | input wire rst, // Reset
9 | output reg [31:0] clk_div // Division result
10 | );
11 |
12 | always @ (posedge clk or negedge rst)
13 | if (!rst)
14 | clk_div <= 32'b0;
15 | else
16 | clk_div <= clk_div + 1;
17 |
18 | endmodule
19 |
--------------------------------------------------------------------------------
/src/data/gobang_datapath.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //------------------------------------------------------------------------------
4 | // Stores the data of the chessboard
5 | //------------------------------------------------------------------------------
6 | module gobang_datapath(
7 | input wire clk, // Clock
8 | input wire rst, // Reset
9 | input wire clr, // Clear
10 |
11 | input wire write, // Enable-write signal
12 | input wire [3:0] write_i, // The position to write information
13 | input wire [3:0] write_j,
14 | input wire write_color, // The color to write in
15 |
16 | input wire [3:0] logic_i, // Row needed by logic
17 | input wire [3:0] display_i, // Row needed by display
18 | input wire [3:0] consider_i, // Row considered by strategy/checker
19 | input wire [3:0] consider_j, // Column considered by s/c
20 |
21 | output wire [14:0] logic_row, // Row information for logic
22 | output wire [14:0] display_black, // Row information for display
23 | output wire [14:0] display_white,
24 | output reg [8:0] black_i, // Row information for s/c
25 | output reg [8:0] black_j, // Column information for s/c
26 | output reg [8:0] black_ij, // Main diagonal information for s/c
27 | output reg [8:0] black_ji, // Counter diagonal information for s/c
28 | output reg [8:0] white_i,
29 | output reg [8:0] white_j,
30 | output reg [8:0] white_ij,
31 | output reg [8:0] white_ji
32 | );
33 |
34 | // Side parameters
35 | localparam BLACK = 1'b0,
36 | WHITE = 1'b1;
37 |
38 | // Chessboard parameters
39 | localparam BOARD_SIZE = 15;
40 |
41 | // RAMs, store the information of the black/white chess
42 | reg [14:0] board_black [14:0];
43 | reg [14:0] board_white [14:0];
44 |
45 | // Helper registers to fetch information from RAM
46 | integer i, j;
47 | reg [14:0] row_4b, row_3b, row_2b, row_1b, row0b,
48 | row1b, row2b, row3b, row4b;
49 | reg [14:0] row_4w, row_3w, row_2w, row_1w, row0w,
50 | row1w, row2w, row3w, row4w;
51 |
52 | // Generate the output
53 | assign logic_row = board_black[logic_i] | board_white[logic_i];
54 | assign display_black = board_black[display_i];
55 | assign display_white = board_white[display_i];
56 |
57 | always @ (negedge clk or negedge rst) begin
58 | if (!rst || clr) begin
59 | board_black[0] <= 15'b0;
60 | board_black[1] <= 15'b0;
61 | board_black[2] <= 15'b0;
62 | board_black[3] <= 15'b0;
63 | board_black[4] <= 15'b0;
64 | board_black[5] <= 15'b0;
65 | board_black[6] <= 15'b0;
66 | board_black[7] <= 15'b0;
67 | board_black[8] <= 15'b0;
68 | board_black[9] <= 15'b0;
69 | board_black[10] <= 15'b0;
70 | board_black[11] <= 15'b0;
71 | board_black[12] <= 15'b0;
72 | board_black[13] <= 15'b0;
73 | board_black[14] <= 15'b0;
74 |
75 | board_white[0] <= 15'b0;
76 | board_white[1] <= 15'b0;
77 | board_white[2] <= 15'b0;
78 | board_white[3] <= 15'b0;
79 | board_white[4] <= 15'b0;
80 | board_white[5] <= 15'b0;
81 | board_white[6] <= 15'b0;
82 | board_white[7] <= 15'b0;
83 | board_white[8] <= 15'b0;
84 | board_white[9] <= 15'b0;
85 | board_white[10] <= 15'b0;
86 | board_white[11] <= 15'b0;
87 | board_white[12] <= 15'b0;
88 | board_white[13] <= 15'b0;
89 | board_white[14] <= 15'b0;
90 | end
91 | else if (write)
92 | if (write_color == BLACK)
93 | board_black[write_i] <= board_black[write_i] |
94 | (15'b1 << write_j);
95 | else
96 | board_white[write_i] <= board_white[write_i] |
97 | (15'b1 << write_j);
98 | end
99 |
100 | always @ (*) begin
101 | i = consider_i;
102 | j = consider_j;
103 |
104 | // Fetch the data of the rows from i-4 to i+4
105 | if (i - 4 >= 0) begin
106 | row_4b = board_black[i - 4];
107 | row_4w = board_white[i - 4];
108 | end
109 | else begin
110 | row_4b = 15'b0;
111 | row_4w = 15'b0;
112 | end
113 |
114 | if (i - 3 >= 0) begin
115 | row_3b = board_black[i - 3];
116 | row_3w = board_white[i - 3];
117 | end
118 | else begin
119 | row_3b = 15'b0;
120 | row_3w = 15'b0;
121 | end
122 |
123 | if (i - 2 >= 0) begin
124 | row_2b = board_black[i - 2];
125 | row_2w = board_white[i - 2];
126 | end
127 | else begin
128 | row_2b = 15'b0;
129 | row_2w = 15'b0;
130 | end
131 |
132 | if (i - 1 >= 0) begin
133 | row_1b = board_black[i - 1];
134 | row_1w = board_white[i - 1];
135 | end
136 | else begin
137 | row_1b = 15'b0;
138 | row_1w = 15'b0;
139 | end
140 |
141 | if (i >= 0 && i < BOARD_SIZE) begin
142 | row0b = board_black[i];
143 | row0w = board_white[i];
144 | end
145 | else begin
146 | row0b = 15'b0;
147 | row0w = 15'b0;
148 | end
149 |
150 | if (i + 1 < BOARD_SIZE) begin
151 | row1b = board_black[i + 1];
152 | row1w = board_white[i + 1];
153 | end
154 | else begin
155 | row1b = 15'b0;
156 | row1w = 15'b0;
157 | end
158 |
159 | if (i + 2 < BOARD_SIZE) begin
160 | row2b = board_black[i + 2];
161 | row2w = board_white[i + 2];
162 | end
163 | else begin
164 | row2b = 15'b0;
165 | row2w = 15'b0;
166 | end
167 |
168 | if (i + 3 < BOARD_SIZE) begin
169 | row3b = board_black[i + 3];
170 | row3w = board_white[i + 3];
171 | end
172 | else begin
173 | row3b = 15'b0;
174 | row3w = 15'b0;
175 | end
176 |
177 | if (i + 4 < BOARD_SIZE) begin
178 | row4b = board_black[i + 4];
179 | row4w = board_white[i + 4];
180 | end
181 | else begin
182 | row4b = 15'b0;
183 | row4w = 15'b0;
184 | end
185 |
186 | // Write the data of each grid to the output
187 | if (j - 4 >= 0) begin
188 | black_i[0] = row0b[j - 4];
189 | white_i[0] = row0w[j - 4];
190 | black_ij[0] = row_4b[j - 4];
191 | white_ij[0] = row_4w[j - 4];
192 | black_ji[0] = row4b[j - 4];
193 | white_ji[0] = row4w[j - 4];
194 | end
195 | else begin
196 | black_i[0] = 1'b0;
197 | white_i[0] = 1'b0;
198 | black_ij[0] = 1'b0;
199 | white_ij[0] = 1'b0;
200 | black_ji[0] = 1'b0;
201 | white_ji[0] = 1'b0;
202 | end
203 |
204 | if (j - 3 >= 0) begin
205 | black_i[1] = row0b[j - 3];
206 | white_i[1] = row0w[j - 3];
207 | black_ij[1] = row_3b[j - 3];
208 | white_ij[1] = row_3w[j - 3];
209 | black_ji[1] = row3b[j - 3];
210 | white_ji[1] = row3w[j - 3];
211 | end
212 | else begin
213 | black_i[1] = 1'b0;
214 | white_i[1] = 1'b0;
215 | black_ij[1] = 1'b0;
216 | white_ij[1] = 1'b0;
217 | black_ji[1] = 1'b0;
218 | white_ji[1] = 1'b0;
219 | end
220 |
221 | if (j - 2 >= 0) begin
222 | black_i[2] = row0b[j - 2];
223 | white_i[2] = row0w[j - 2];
224 | black_ij[2] = row_2b[j - 2];
225 | white_ij[2] = row_2w[j - 2];
226 | black_ji[2] = row2b[j - 2];
227 | white_ji[2] = row2w[j - 2];
228 | end
229 | else begin
230 | black_i[2] = 1'b0;
231 | white_i[2] = 1'b0;
232 | black_ij[2] = 1'b0;
233 | white_ij[2] = 1'b0;
234 | black_ji[2] = 1'b0;
235 | white_ji[2] = 1'b0;
236 | end
237 |
238 | if (j - 1 >= 0) begin
239 | black_i[3] = row0b[j - 1];
240 | white_i[3] = row0w[j - 1];
241 | black_ij[3] = row_1b[j - 1];
242 | white_ij[3] = row_1w[j - 1];
243 | black_ji[3] = row1b[j - 1];
244 | white_ji[3] = row1w[j - 1];
245 | end
246 | else begin
247 | black_i[3] = 1'b0;
248 | white_i[3] = 1'b0;
249 | black_ij[3] = 1'b0;
250 | white_ij[3] = 1'b0;
251 | black_ji[3] = 1'b0;
252 | white_ji[3] = 1'b0;
253 | end
254 |
255 | if (j >= 0 && j < BOARD_SIZE) begin
256 | black_i[4] = row0b[j];
257 | white_i[4] = row0w[j];
258 | black_ij[4] = row0b[j];
259 | white_ij[4] = row0w[j];
260 | black_ji[4] = row0b[j];
261 | white_ji[4] = row0w[j];
262 |
263 | black_j[0] = row_4b[j];
264 | black_j[1] = row_3b[j];
265 | black_j[2] = row_2b[j];
266 | black_j[3] = row_1b[j];
267 | black_j[4] = row0b[j];
268 | black_j[5] = row1b[j];
269 | black_j[6] = row2b[j];
270 | black_j[7] = row3b[j];
271 | black_j[8] = row4b[j];
272 | white_j[0] = row_4w[j];
273 | white_j[1] = row_3w[j];
274 | white_j[2] = row_2w[j];
275 | white_j[3] = row_1w[j];
276 | white_j[4] = row0w[j];
277 | white_j[5] = row1w[j];
278 | white_j[6] = row2w[j];
279 | white_j[7] = row3w[j];
280 | white_j[8] = row4w[j];
281 | end
282 | else begin
283 | black_i[4] = 1'b0;
284 | white_i[4] = 1'b0;
285 | black_ij[4] = 1'b0;
286 | white_ij[4] = 1'b0;
287 | black_ji[4] = 1'b0;
288 | white_ji[4] = 1'b0;
289 |
290 | black_j[0] = 1'b0;
291 | black_j[1] = 1'b0;
292 | black_j[2] = 1'b0;
293 | black_j[3] = 1'b0;
294 | black_j[4] = 1'b0;
295 | black_j[5] = 1'b0;
296 | black_j[6] = 1'b0;
297 | black_j[7] = 1'b0;
298 | black_j[8] = 1'b0;
299 | white_j[0] = 1'b0;
300 | white_j[1] = 1'b0;
301 | white_j[2] = 1'b0;
302 | white_j[3] = 1'b0;
303 | white_j[4] = 1'b0;
304 | white_j[5] = 1'b0;
305 | white_j[6] = 1'b0;
306 | white_j[7] = 1'b0;
307 | white_j[8] = 1'b0;
308 | end
309 |
310 | if (j + 1 < BOARD_SIZE) begin
311 | black_i[5] = row0b[j + 1];
312 | white_i[5] = row0w[j + 1];
313 | black_ij[5] = row1b[j + 1];
314 | white_ij[5] = row1w[j + 1];
315 | black_ji[5] = row_1b[j + 1];
316 | white_ji[5] = row_1w[j + 1];
317 | end
318 | else begin
319 | black_i[5] = 1'b0;
320 | white_i[5] = 1'b0;
321 | black_ij[5] = 1'b0;
322 | white_ij[5] = 1'b0;
323 | black_ji[5] = 1'b0;
324 | white_ji[5] = 1'b0;
325 | end
326 |
327 | if (j + 2 < BOARD_SIZE) begin
328 | black_i[6] = row0b[j + 2];
329 | white_i[6] = row0w[j + 2];
330 | black_ij[6] = row2b[j + 2];
331 | white_ij[6] = row2w[j + 2];
332 | black_ji[6] = row_2b[j + 2];
333 | white_ji[6] = row_2w[j + 2];
334 | end
335 | else begin
336 | black_i[6] = 1'b0;
337 | white_i[6] = 1'b0;
338 | black_ij[6] = 1'b0;
339 | white_ij[6] = 1'b0;
340 | black_ji[6] = 1'b0;
341 | white_ji[6] = 1'b0;
342 | end
343 |
344 | if (j + 3 < BOARD_SIZE) begin
345 | black_i[7] = row0b[j + 3];
346 | white_i[7] = row0w[j + 3];
347 | black_ij[7] = row3b[j + 3];
348 | white_ij[7] = row3w[j + 3];
349 | black_ji[7] = row_3b[j + 3];
350 | white_ji[7] = row_3w[j + 3];
351 | end
352 | else begin
353 | black_i[7] = 1'b0;
354 | white_i[7] = 1'b0;
355 | black_ij[7] = 1'b0;
356 | white_ij[7] = 1'b0;
357 | black_ji[7] = 1'b0;
358 | white_ji[7] = 1'b0;
359 | end
360 |
361 | if (j + 4 < BOARD_SIZE) begin
362 | black_i[8] = row0b[j + 4];
363 | white_i[8] = row0w[j + 4];
364 | black_ij[8] = row4b[j + 4];
365 | white_ij[8] = row4w[j + 4];
366 | black_ji[8] = row_4b[j + 4];
367 | white_ji[8] = row_4w[j + 4];
368 | end
369 | else begin
370 | black_i[8] = 1'b0;
371 | white_i[8] = 1'b0;
372 | black_ij[8] = 1'b0;
373 | white_ij[8] = 1'b0;
374 | black_ji[8] = 1'b0;
375 | white_ji[8] = 1'b0;
376 | end
377 | end
378 |
379 | endmodule
380 |
--------------------------------------------------------------------------------
/src/data/testbench/gobang_datapath_tb.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | module gobang_datapath_tb;
4 |
5 | // Inputs
6 | reg clk;
7 | reg rst;
8 | reg clr;
9 | reg write;
10 | reg [3:0] write_x;
11 | reg [3:0] write_y;
12 | reg write_color;
13 | reg [3:0] get_x;
14 | reg [3:0] get_y;
15 |
16 | // Outputs
17 | wire [8:0] black_x;
18 | wire [8:0] black_y;
19 | wire [8:0] black_xy;
20 | wire [8:0] black_yx;
21 | wire [8:0] white_x;
22 | wire [8:0] white_y;
23 | wire [8:0] white_xy;
24 | wire [8:0] white_yx;
25 | wire [224:0] black_data;
26 | wire [224:0] white_data;
27 |
28 | // Instantiate the Unit Under Test (UUT)
29 | gobang_datapath uut (
30 | .clk(clk),
31 | .rst(rst),
32 | .clr(clr),
33 | .write(write),
34 | .write_x(write_x),
35 | .write_y(write_y),
36 | .write_color(write_color),
37 | .get_x(get_x),
38 | .get_y(get_y),
39 | .black_x(black_x),
40 | .black_y(black_y),
41 | .black_xy(black_xy),
42 | .black_yx(black_yx),
43 | .white_x(white_x),
44 | .white_y(white_y),
45 | .white_xy(white_xy),
46 | .white_yx(white_yx),
47 | .black_data(black_data),
48 | .white_data(white_data)
49 | );
50 |
51 | initial begin
52 | clk = 0;
53 | rst = 1;
54 | write = 0;
55 | write_x = 0;
56 | write_y = 0;
57 | write_color = 0;
58 | get_x = 1;
59 | get_y = 1;
60 | #70;
61 |
62 | rst = 0;
63 | write = 1;
64 | write_x = 1;
65 | write_y = 1;
66 | write_color = 0;
67 | #50;
68 |
69 | write = 0;
70 | #50;
71 |
72 | write = 1;
73 | write_x = 2;
74 | write_y = 1;
75 | write_color = 1;
76 | #50;
77 |
78 | write = 0;
79 | end
80 |
81 | always begin
82 | #50;
83 | clk = ~clk;
84 | end
85 |
86 | endmodule
87 |
88 |
--------------------------------------------------------------------------------
/src/display/vga_display.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //------------------------------------------------------------------------------
4 | // Display the color for each pixel
5 | //------------------------------------------------------------------------------
6 | module vga_display(
7 | input wire clk, // Clock (25MHz)
8 | input wire rst, // Reset
9 |
10 | input wire [3:0] cursor_i, // Cursor position
11 | input wire [3:0] cursor_j,
12 | input wire black_is_player, // If black is not AI
13 | input wire white_is_player, // If white is not AI
14 | input wire crt_player, // Current player
15 | input wire game_running, // If the game is running
16 | input wire [1:0] winner, // Who wins the game
17 |
18 | input wire [14:0] display_black, // Row information for display
19 | input wire [14:0] display_white,
20 |
21 | output wire [3:0] display_i, // Row needed by display
22 | output wire sync_h, // VGA horizontal sync
23 | output wire sync_v, // VGA vertical sync
24 | output wire [3:0] r, // VGA red component
25 | output wire [3:0] g, // VGA green component
26 | output wire [3:0] b // VGA blue component
27 | );
28 |
29 | // Side parameters
30 | localparam BLACK = 1'b0,
31 | WHITE = 1'b1;
32 |
33 | // Chessboard display parameters
34 | localparam BOARD_SIZE = 15,
35 | GRID_SIZE = 23,
36 | GRID_X_BEGIN = 148,
37 | GRID_X_END = 492,
38 | GRID_Y_BEGIN = 68,
39 | GRID_Y_END = 412;
40 |
41 | // Side information display parameters
42 | localparam SIDE_BLACK_X_BEGIN = 545,
43 | SIDE_BLACK_X_END = 616,
44 | SIDE_BLACK_Y_BEGIN = 182,
45 | SIDE_BLACK_Y_END = 200,
46 | SIDE_WHITE_X_BEGIN = 545,
47 | SIDE_WHITE_X_END = 616,
48 | SIDE_WHITE_Y_BEGIN = 278,
49 | SIDE_WHITE_Y_END = 296;
50 |
51 | // Current player pointer display parameters
52 | localparam CRT_BLACK_X_BEGIN = 510,
53 | CRT_BLACK_X_END = 541,
54 | CRT_BLACK_Y_BEGIN = 185,
55 | CRT_BLACK_Y_END = 198,
56 | CRT_WHITE_X_BEGIN = 510,
57 | CRT_WHITE_X_END = 541,
58 | CRT_WHITE_Y_BEGIN = 281,
59 | CRT_WHITE_Y_END = 294;
60 |
61 | // Title display parameters
62 | localparam TITLE_X_BEGIN = 0,
63 | TITLE_X_END = 140,
64 | TITLE_Y_BEGIN = 62,
65 | TITLE_Y_END = 418;
66 |
67 | // Instruction display parameters
68 | localparam INS_X_BEGIN = 145,
69 | INS_X_END = 494,
70 | INS_Y_BEGIN = 424,
71 | INS_Y_END = 467;
72 |
73 | // Result display parameters
74 | localparam RES_X_BEGIN = 187,
75 | RES_X_END = 452,
76 | RES_Y_BEGIN = 20,
77 | RES_Y_END = 47;
78 |
79 | // Author info display parameters
80 | localparam AUTHOR_X_BEGIN = 510,
81 | AUTHOR_X_END = 634,
82 | AUTHOR_Y_BEGIN = 455,
83 | AUTHOR_Y_END = 476;
84 |
85 |
86 |
87 | // Current display color
88 | reg [11:0] rgb;
89 | assign r = video_on ? rgb[11:8] : 4'b0;
90 | assign g = video_on ? rgb[7:4] : 4'b0;
91 | assign b = video_on ? rgb[3:0] : 4'b0;
92 |
93 | // VGA control signal generator
94 | wire video_on;
95 | wire [9:0] x, y;
96 | vga_sync
97 | sync(
98 | .clk(clk),
99 | .rst(rst),
100 | .sync_h(sync_h),
101 | .sync_v(sync_v),
102 | .video_on(video_on),
103 | .x(x),
104 | .y(y)
105 | );
106 |
107 | // Chessboard display registers
108 | reg [3:0] row, col;
109 | integer delta_x, delta_y;
110 | assign display_i = row < BOARD_SIZE ? row : 4'b0;
111 |
112 | // Patterns needed to be displayed
113 | wire [22:0] chess_piece_data;
114 | pic_chess_piece chess_piece(x >= GRID_X_BEGIN && x <= GRID_X_END &&
115 | y >= GRID_Y_BEGIN && y <= GRID_Y_END,
116 | delta_y + GRID_SIZE/2, chess_piece_data);
117 |
118 | wire [71:0] black_player_data, black_ai_data,
119 | white_player_data, white_ai_data;
120 | pic_side_player black_player(x >= SIDE_BLACK_X_BEGIN &&
121 | x <= SIDE_BLACK_X_END &&
122 | y >= SIDE_BLACK_Y_BEGIN &&
123 | y <= SIDE_BLACK_Y_END,
124 | y - SIDE_BLACK_Y_BEGIN, black_player_data),
125 | white_player(x >= SIDE_WHITE_X_BEGIN &&
126 | x <= SIDE_WHITE_X_END &&
127 | y >= SIDE_WHITE_Y_BEGIN &&
128 | y <= SIDE_WHITE_Y_END,
129 | y - SIDE_WHITE_Y_BEGIN, white_player_data);
130 | pic_side_ai black_ai(x >= SIDE_BLACK_X_BEGIN && x <= SIDE_BLACK_X_END &&
131 | y >= SIDE_BLACK_Y_BEGIN && y <= SIDE_BLACK_Y_END,
132 | y - SIDE_BLACK_Y_BEGIN, black_ai_data),
133 | white_ai(x >= SIDE_WHITE_X_BEGIN && x <= SIDE_WHITE_X_END &&
134 | y >= SIDE_WHITE_Y_BEGIN && y <= SIDE_WHITE_Y_END,
135 | y - SIDE_WHITE_Y_BEGIN, white_ai_data);
136 |
137 | wire [31:0] black_ptr_data, white_ptr_data;
138 | pic_crt_ptr black_ptr(x >= CRT_BLACK_X_BEGIN && x <= CRT_BLACK_X_END &&
139 | y >= CRT_BLACK_Y_BEGIN && y <= CRT_BLACK_Y_END,
140 | y - CRT_BLACK_Y_BEGIN, black_ptr_data),
141 | white_ptr(x >= CRT_WHITE_X_BEGIN && x <= CRT_WHITE_X_END &&
142 | y >= CRT_WHITE_Y_BEGIN && y <= CRT_WHITE_Y_END,
143 | y - CRT_WHITE_Y_BEGIN, white_ptr_data);
144 |
145 | wire [140:0] title_data;
146 | pic_title title(x >= TITLE_X_BEGIN && x <= TITLE_X_END &&
147 | y >= TITLE_Y_BEGIN && y <= TITLE_Y_END,
148 | y - TITLE_Y_BEGIN, title_data);
149 |
150 | wire [349:0] ins_start_data, ins_player_data, ins_ai_data;
151 | pic_ins_start ins_start(x >= INS_X_BEGIN && x <= INS_X_END &&
152 | y >= INS_Y_BEGIN && y <= INS_Y_END,
153 | y - INS_Y_BEGIN, ins_start_data);
154 | pic_ins_player ins_player(x >= INS_X_BEGIN && x <= INS_X_END &&
155 | y >= INS_Y_BEGIN && y <= INS_Y_END,
156 | y - INS_Y_BEGIN, ins_player_data);
157 | pic_ins_ai ins_ai(x >= INS_X_BEGIN && x <= INS_X_END &&
158 | y >= INS_Y_BEGIN && y <= INS_Y_END,
159 | y - INS_Y_BEGIN, ins_ai_data);
160 |
161 | wire [265:0] black_wins_data, white_wins_data, res_draw_data;
162 | pic_black_wins black_wins(x >= RES_X_BEGIN && x <= RES_X_END &&
163 | y >= RES_Y_BEGIN && y <= RES_Y_END,
164 | y - RES_Y_BEGIN, black_wins_data);
165 | pic_white_wins white_wins(x >= RES_X_BEGIN && x <= RES_X_END &&
166 | y >= RES_Y_BEGIN && y <= RES_Y_END,
167 | y - RES_Y_BEGIN, white_wins_data);
168 | pic_res_draw res_draw(x >= RES_X_BEGIN && x <= RES_X_END &&
169 | y >= RES_Y_BEGIN && y <= RES_Y_END,
170 | y - RES_Y_BEGIN, res_draw_data);
171 |
172 | wire [124:0] author_info_data;
173 | pic_author_info author_info(x >= AUTHOR_X_BEGIN && x <= AUTHOR_X_END &&
174 | y >= AUTHOR_Y_BEGIN && y <= AUTHOR_Y_END,
175 | y - AUTHOR_Y_BEGIN, author_info_data);
176 |
177 | // Calculate the current row and column
178 | always @ (x or y) begin
179 | if (y >= GRID_Y_BEGIN &&
180 | y < GRID_Y_BEGIN + GRID_SIZE)
181 | row = 4'b0000;
182 | else if (y >= GRID_Y_BEGIN + GRID_SIZE &&
183 | y < GRID_Y_BEGIN + GRID_SIZE*2)
184 | row = 4'b0001;
185 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*2 &&
186 | y < GRID_Y_BEGIN + GRID_SIZE*3)
187 | row = 4'b0010;
188 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*3 &&
189 | y < GRID_Y_BEGIN + GRID_SIZE*4)
190 | row = 4'b0011;
191 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*4 &&
192 | y < GRID_Y_BEGIN + GRID_SIZE*5)
193 | row = 4'b0100;
194 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*5 &&
195 | y < GRID_Y_BEGIN + GRID_SIZE*6)
196 | row = 4'b0101;
197 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*6 &&
198 | y < GRID_Y_BEGIN + GRID_SIZE*7)
199 | row = 4'b0110;
200 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*7 &&
201 | y < GRID_Y_BEGIN + GRID_SIZE*8)
202 | row = 4'b0111;
203 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*8 &&
204 | y < GRID_Y_BEGIN + GRID_SIZE*9)
205 | row = 4'b1000;
206 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*9 &&
207 | y < GRID_Y_BEGIN + GRID_SIZE*10)
208 | row = 4'b1001;
209 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*10 &&
210 | y < GRID_Y_BEGIN + GRID_SIZE*11)
211 | row = 4'b1010;
212 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*11 &&
213 | y < GRID_Y_BEGIN + GRID_SIZE*12)
214 | row = 4'b1011;
215 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*12 &&
216 | y < GRID_Y_BEGIN + GRID_SIZE*13)
217 | row = 4'b1100;
218 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*13 &&
219 | y < GRID_Y_BEGIN + GRID_SIZE*14)
220 | row = 4'b1101;
221 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*14 &&
222 | y < GRID_Y_BEGIN + GRID_SIZE*15)
223 | row = 4'b1110;
224 | else
225 | row = 4'b1111;
226 |
227 | if (x >= GRID_X_BEGIN &&
228 | x < GRID_X_BEGIN + GRID_SIZE)
229 | col = 4'b0000;
230 | else if (x >= GRID_X_BEGIN + GRID_SIZE &&
231 | x < GRID_X_BEGIN + GRID_SIZE*2)
232 | col = 4'b0001;
233 | else if (x >= GRID_X_BEGIN + GRID_SIZE*2 &&
234 | x < GRID_X_BEGIN + GRID_SIZE*3)
235 | col = 4'b0010;
236 | else if (x >= GRID_X_BEGIN + GRID_SIZE*3 &&
237 | x < GRID_X_BEGIN + GRID_SIZE*4)
238 | col = 4'b0011;
239 | else if (x >= GRID_X_BEGIN + GRID_SIZE*4 &&
240 | x < GRID_X_BEGIN + GRID_SIZE*5)
241 | col = 4'b0100;
242 | else if (x >= GRID_X_BEGIN + GRID_SIZE*5 &&
243 | x < GRID_X_BEGIN + GRID_SIZE*6)
244 | col = 4'b0101;
245 | else if (x >= GRID_X_BEGIN + GRID_SIZE*6 &&
246 | x < GRID_X_BEGIN + GRID_SIZE*7)
247 | col = 4'b0110;
248 | else if (x >= GRID_X_BEGIN + GRID_SIZE*7 &&
249 | x < GRID_X_BEGIN + GRID_SIZE*8)
250 | col = 4'b0111;
251 | else if (x >= GRID_X_BEGIN + GRID_SIZE*8 &&
252 | x < GRID_X_BEGIN + GRID_SIZE*9)
253 | col = 4'b1000;
254 | else if (x >= GRID_X_BEGIN + GRID_SIZE*9 &&
255 | x < GRID_X_BEGIN + GRID_SIZE*10)
256 | col = 4'b1001;
257 | else if (x >= GRID_X_BEGIN + GRID_SIZE*10 &&
258 | x < GRID_X_BEGIN + GRID_SIZE*11)
259 | col = 4'b1010;
260 | else if (x >= GRID_X_BEGIN + GRID_SIZE*11 &&
261 | x < GRID_X_BEGIN + GRID_SIZE*12)
262 | col = 4'b1011;
263 | else if (x >= GRID_X_BEGIN + GRID_SIZE*12 &&
264 | x < GRID_X_BEGIN + GRID_SIZE*13)
265 | col = 4'b1100;
266 | else if (x >= GRID_X_BEGIN + GRID_SIZE*13 &&
267 | x < GRID_X_BEGIN + GRID_SIZE*14)
268 | col = 4'b1101;
269 | else if (x >= GRID_X_BEGIN + GRID_SIZE*14 &&
270 | x < GRID_X_BEGIN + GRID_SIZE*15)
271 | col = 4'b1110;
272 | else
273 | col = 4'b1111;
274 |
275 | delta_x = GRID_X_BEGIN + col*GRID_SIZE + GRID_SIZE/2 - x;
276 | delta_y = GRID_Y_BEGIN + row*GRID_SIZE + GRID_SIZE/2 - y;
277 | end
278 |
279 | // Calculate the color
280 | always @ (posedge clk) begin
281 | if (x >= GRID_X_BEGIN && x <= GRID_X_END &&
282 | y >= GRID_Y_BEGIN && y <= GRID_Y_END) begin
283 | // Draw the chessboard
284 | if (display_black[col] &&
285 | chess_piece_data[delta_x + GRID_SIZE/2])
286 | // Draw a black chess
287 | rgb <= 12'h000;
288 | else if (display_white[col] &&
289 | chess_piece_data[delta_x + GRID_SIZE/2])
290 | // Draw a white chess
291 | rgb <= 12'hfff;
292 | else if (row == cursor_i && col == cursor_j &&
293 | (delta_x == GRID_SIZE/2 || delta_x == -(GRID_SIZE/2) ||
294 | delta_y == GRID_SIZE/2 || delta_y == -(GRID_SIZE/2)))
295 | // Draw a red square as a cursor
296 | rgb <= 12'hf00;
297 | else if (delta_x == 0 || delta_y == 0)
298 | // Draw the light border of a grid
299 | rgb <= 12'hda6;
300 | else if (delta_x == 1 || delta_y == 1)
301 | // Draw the dark border of a grid
302 | rgb <= 12'h751;
303 | else
304 | rgb <= 12'hc81;
305 | end
306 | else if (x >= CRT_BLACK_X_BEGIN && x <= CRT_BLACK_X_END &&
307 | y >= CRT_BLACK_Y_BEGIN && y <= CRT_BLACK_Y_END) begin
308 | // Draw the current player pointer for black side
309 | rgb <= game_running && crt_player == BLACK &&
310 | black_ptr_data[CRT_BLACK_X_END - x] ? 12'h000 : 12'hc81;
311 | end
312 | else if (x >= CRT_WHITE_X_BEGIN && x <= CRT_WHITE_X_END &&
313 | y >= CRT_WHITE_Y_BEGIN && y <= CRT_WHITE_Y_END) begin
314 | // Draw the current player pointer for white side
315 | rgb <= game_running && crt_player == WHITE &&
316 | white_ptr_data[CRT_WHITE_X_END - x] ? 12'hfff : 12'hc81;
317 | end
318 | else if (x >= SIDE_BLACK_X_BEGIN && x <= SIDE_BLACK_X_END &&
319 | y >= SIDE_BLACK_Y_BEGIN && y <= SIDE_BLACK_Y_END) begin
320 | // Draw who plays the black side
321 | if (black_is_player)
322 | rgb <= black_player_data[SIDE_BLACK_X_END - x] ?
323 | 12'h000 : 12'hc81;
324 | else
325 | rgb <= black_ai_data[SIDE_BLACK_X_END - x] ? 12'h000 : 12'hc81;
326 | end
327 | else if (x >= SIDE_WHITE_X_BEGIN && x <= SIDE_WHITE_X_END &&
328 | y >= SIDE_WHITE_Y_BEGIN && y <= SIDE_WHITE_Y_END) begin
329 | // Draw who plays the white side
330 | if (white_is_player)
331 | rgb <= white_player_data[SIDE_WHITE_X_END - x] ?
332 | 12'hfff : 12'hc81;
333 | else
334 | rgb <= white_ai_data[SIDE_WHITE_X_END - x] ? 12'hfff : 12'hc81;
335 | end
336 | else if (x >= INS_X_BEGIN && x <= INS_X_END &&
337 | y >= INS_Y_BEGIN && y <= INS_Y_END) begin
338 | // Draw instructions
339 | if (!game_running)
340 | rgb <= ins_start_data[INS_X_END - x] ? 12'h000 : 12'hc81;
341 | else if ((black_is_player && crt_player == BLACK) ||
342 | (white_is_player && crt_player == WHITE))
343 | rgb <= ins_player_data[INS_X_END - x] ? 12'h000 : 12'hc81;
344 | else
345 | rgb <= ins_ai_data[INS_X_END - x] ? 12'h000 : 12'hc81;
346 | end
347 | else if (x >= RES_X_BEGIN && x <= RES_X_END &&
348 | y >= RES_Y_BEGIN && y <= RES_Y_END) begin
349 | // Draw the result
350 | case (winner)
351 | 2'b00: rgb <= 12'hc81;
352 | 2'b01: rgb <= black_wins_data[RES_X_END - x] ? 12'h000 : 12'hc81;
353 | 2'b10: rgb <= white_wins_data[RES_X_END - x] ? 12'hfff : 12'hc81;
354 | 2'b11: rgb <= res_draw_data[RES_X_END - x] ? 12'hfff : 12'hc81;
355 | endcase
356 | end
357 | else if (x >= TITLE_X_BEGIN && x <= TITLE_X_END &&
358 | y >= TITLE_Y_BEGIN && y <= TITLE_Y_END) begin
359 | // Draw the title
360 | rgb <= title_data[TITLE_X_END - x] ? 12'hfff : 12'hc81;
361 | end
362 | else if (x >= AUTHOR_X_BEGIN && x <= AUTHOR_X_END &&
363 | y >= AUTHOR_Y_BEGIN && y <= AUTHOR_Y_END) begin
364 | // Draw the author info
365 | rgb <= author_info_data[AUTHOR_X_END - x] ? 12'h000 : 12'hc81;
366 | end
367 | else
368 | // Draw the background
369 | rgb <= 12'hc81;
370 | end
371 |
372 | endmodule
373 |
--------------------------------------------------------------------------------
/src/display/vga_sync.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //------------------------------------------------------------------------------
4 | // Generate the VGA control signal
5 | //------------------------------------------------------------------------------
6 | module vga_sync(
7 | input wire clk, // Clock (25MHz)
8 | input wire rst, // Reset
9 | output wire sync_h, // VGA horizontal sync
10 | output wire sync_v, // VGA vertical sync
11 | output wire video_on, // True when in the display area
12 | output reg [9:0] x, // X coordinate
13 | output reg [9:0] y // Y coordinate
14 | );
15 |
16 | assign sync_h = ~(x > 655 && x < 752);
17 | assign sync_v = ~(y > 489 && y < 492);
18 | assign video_on = (x < 640 && y < 480);
19 |
20 | always @ (posedge clk or negedge rst) begin
21 | if (!rst) begin
22 | x <= 0;
23 | y <= 0;
24 | end
25 | else begin
26 | if (x == 799)
27 | x <= 0;
28 | else
29 | x <= x + 1'b1;
30 | if (y == 524)
31 | y <= 0;
32 | else if (x == 799)
33 | y <= y + 1'b1;
34 | end
35 | end
36 |
37 | endmodule
38 |
--------------------------------------------------------------------------------
/src/gobang_top.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //------------------------------------------------------------------------------
4 | // Top module
5 | //------------------------------------------------------------------------------
6 | module gobang_top(
7 | input wire clk, // Clock (100MHz)
8 | input wire rst, // Reset button, 0 = pressed, 1 = released
9 | input wire ps2_clk, // PS2 clock
10 | input wire ps2_data, // PS2 data
11 | output wire sync_h, // VGA horizontal sync
12 | output wire sync_v, // VGA vertical sync
13 | output wire [3:0] r, // VGA red component
14 | output wire [3:0] g, // VGA green component
15 | output wire [3:0] b, // VGA blue component
16 | output wire buz // Arduino buzzer
17 | );
18 |
19 | wire [3:0] consider_i, consider_j, cursor_i, cursor_j;
20 | wire data_clr, data_write;
21 | wire black_is_player, white_is_player, crt_player, game_running;
22 | wire [1:0] winner;
23 |
24 | wire [8:0] black_i, black_j, black_ij, black_ji,
25 | white_i, white_j, white_ij, white_ji;
26 | wire [14:0] logic_row, display_black, display_white;
27 |
28 | wire key_up, key_down, key_left, key_right, key_ok, key_switch;
29 |
30 | wire [3:0] display_i;
31 |
32 | wire [31:0] rand_num;
33 | wire [31:0] clk_div;
34 |
35 | // Turn off the arduino buzzer
36 | assign buz = 1'b1;
37 |
38 | gobang_logic
39 | game_logic(
40 | .clk_slow(clk_div[16]),
41 | .clk_fast(clk_div[6]),
42 | .rst(rst),
43 | .random(rand_num[0]),
44 | .key_up(key_up),
45 | .key_down(key_down),
46 | .key_left(key_left),
47 | .key_right(key_right),
48 | .key_ok(key_ok),
49 | .key_switch(key_switch),
50 | .black_i(black_i),
51 | .black_j(black_j),
52 | .black_ij(black_ij),
53 | .black_ji(black_ji),
54 | .white_i(white_i),
55 | .white_j(white_j),
56 | .white_ij(white_ij),
57 | .white_ji(white_ji),
58 | .chess_row(logic_row),
59 | .consider_i(consider_i),
60 | .consider_j(consider_j),
61 | .data_clr(data_clr),
62 | .data_write(data_write),
63 | .cursor_i(cursor_i),
64 | .cursor_j(cursor_j),
65 | .black_is_player(black_is_player),
66 | .white_is_player(white_is_player),
67 | .crt_player(crt_player),
68 | .game_running(game_running),
69 | .winner(winner)
70 | );
71 |
72 | gobang_datapath
73 | data(
74 | .clk(clk_div[16]),
75 | .rst(rst),
76 | .clr(data_clr),
77 | .write(data_write),
78 | .write_i(cursor_i),
79 | .write_j(cursor_j),
80 | .write_color(crt_player),
81 | .logic_i(cursor_i),
82 | .display_i(display_i),
83 | .consider_i(consider_i),
84 | .consider_j(consider_j),
85 | .logic_row(logic_row),
86 | .display_black(display_black),
87 | .display_white(display_white),
88 | .black_i(black_i),
89 | .black_j(black_j),
90 | .black_ij(black_ij),
91 | .black_ji(black_ji),
92 | .white_i(white_i),
93 | .white_j(white_j),
94 | .white_ij(white_ij),
95 | .white_ji(white_ji)
96 | );
97 |
98 | ps2_input
99 | keyboard(
100 | .clk_slow(clk_div[16]),
101 | .clk_fast(clk_div[6]),
102 | .rst(rst),
103 | .ps2_clk(ps2_clk),
104 | .ps2_data(ps2_data),
105 | .key_up(key_up),
106 | .key_down(key_down),
107 | .key_left(key_left),
108 | .key_right(key_right),
109 | .key_ok(key_ok),
110 | .key_switch(key_switch)
111 | );
112 |
113 | vga_display
114 | display(
115 | .clk(clk_div[1]),
116 | .rst(rst),
117 | .cursor_i(cursor_i),
118 | .cursor_j(cursor_j),
119 | .black_is_player(black_is_player),
120 | .white_is_player(white_is_player),
121 | .crt_player(crt_player),
122 | .game_running(game_running),
123 | .winner(winner),
124 | .display_black(display_black),
125 | .display_white(display_white),
126 | .display_i(display_i),
127 | .sync_h(sync_h),
128 | .sync_v(sync_v),
129 | .r(r),
130 | .g(g),
131 | .b(b)
132 | );
133 |
134 | random_generator
135 | rand(
136 | .clk(clk_div[6]),
137 | .rst(rst),
138 | .load(key_ok),
139 | .seed(clk_div),
140 | .rand_num(rand_num)
141 | );
142 |
143 | clk_divider
144 | divider(
145 | .clk(clk),
146 | .rst(rst),
147 | .clk_div(clk_div)
148 | );
149 |
150 | endmodule
151 |
--------------------------------------------------------------------------------
/src/input/ps2_input.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //------------------------------------------------------------------------------
4 | // Dealing with the input data of the PS2 keyboard
5 | //------------------------------------------------------------------------------
6 | module ps2_input(
7 | input wire clk_slow, // Slower clock for this module
8 | input wire clk_fast, // Faster clock for the PS2 scanner
9 | input wire rst, // Reset
10 | input wire ps2_clk, // PS2 clock
11 | input wire ps2_data, // PS2 data
12 |
13 | output wire key_up, // If UP key is pressed
14 | output wire key_down, // If DOWN key is pressed
15 | output wire key_left, // If LEFT key is pressed
16 | output wire key_right, // If RIGHT key is pressed
17 | output wire key_ok, // If OK key is pressed
18 | output wire key_switch // If SWITCH key is pressed
19 | );
20 |
21 | wire [8:0] crt_data; // Input data of the PS2 keyboard
22 |
23 | // Key state recorders
24 | reg [1:0] key_up_state, key_down_state, key_left_state,
25 | key_right_state, key_ok_state, key_switch_state;
26 | // Only becomes true at the posedge of each key
27 | assign key_up = key_up_state[0] & ~key_up_state[1];
28 | assign key_down = key_down_state[0] & ~key_down_state[1];
29 | assign key_left = key_left_state[0] & ~key_left_state[1];
30 | assign key_right = key_right_state[0] & ~key_right_state[1];
31 | assign key_ok = key_ok_state[0] & ~key_ok_state[1];
32 | assign key_switch = key_switch_state[0] & ~key_switch_state[1];
33 |
34 | // PS2 keyboard scanner
35 | ps2_scan
36 | scanner(
37 | .clk(clk_fast),
38 | .rst(rst),
39 | .ps2_clk(ps2_clk),
40 | .ps2_data(ps2_data),
41 | .crt_data(crt_data)
42 | );
43 |
44 | always @ (posedge clk_slow or negedge rst)
45 | if (!rst) begin
46 | key_up_state <= 2'b0;
47 | key_down_state <= 2'b0;
48 | key_left_state <= 2'b0;
49 | key_right_state <= 2'b0;
50 | key_ok_state <= 2'b0;
51 | key_switch_state <= 2'b0;
52 | end
53 | else begin
54 | // Record the key state
55 | key_up_state <= {key_up_state[0], crt_data == 9'h175};
56 | key_down_state <= {key_down_state[0], crt_data == 9'h172};
57 | key_left_state <= {key_left_state[0], crt_data == 9'h16b};
58 | key_right_state <= {key_right_state[0], crt_data == 9'h174};
59 | key_ok_state <= {key_ok_state[0], crt_data == 9'h029};
60 | key_switch_state <= {key_switch_state[0], crt_data == 9'h014};
61 | end
62 |
63 | endmodule
64 |
--------------------------------------------------------------------------------
/src/input/ps2_scan.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //------------------------------------------------------------------------------
4 | // PS2 keyboard scanner
5 | //------------------------------------------------------------------------------
6 | module ps2_scan(
7 | input wire clk, // Clock
8 | input wire rst, // Reset
9 | input wire ps2_clk, // PS2 clock
10 | input wire ps2_data, // PS2 data
11 |
12 | output reg [8:0] crt_data // Input data of the keyboard
13 | );
14 |
15 | reg [1:0] ps2_clk_state; // PS2 clock recorder
16 | wire ps2_clk_neg; // True at the negedge of the PS2 clock
17 | assign ps2_clk_neg = ~ps2_clk_state[0] & ps2_clk_state[1];
18 |
19 | // Registers for data reading
20 | reg [3:0] read_state;
21 | reg [7:0] read_data;
22 |
23 | // Registers for special signals
24 | reg is_f0, is_e0;
25 |
26 | // Record the PS2 clock
27 | always @ (posedge clk or negedge rst)
28 | if (!rst)
29 | ps2_clk_state <= 2'b0;
30 | else
31 | ps2_clk_state <= {ps2_clk_state[0], ps2_clk};
32 |
33 | always @ (posedge clk or negedge rst) begin
34 | if (!rst) begin
35 | read_state <= 4'b0;
36 | read_data <= 8'b0;
37 |
38 | is_f0 <= 1'b0;
39 | is_e0 <= 1'b0;
40 | crt_data <= 9'b0;
41 | end
42 | else if (ps2_clk_neg) begin
43 | // Reads in the data
44 | if (read_state > 4'b1001)
45 | read_state <= 4'b0;
46 | else begin
47 | if (read_state > 4'b0 && read_state < 4'b1001)
48 | read_data[read_state - 1] <= ps2_data;
49 | read_state <= read_state + 1'b1;
50 | end
51 | end
52 | else if (read_state == 4'b1010 && |read_data) begin
53 | if (read_data == 8'hf0)
54 | is_f0 <= 1'b1;
55 | else if (read_data == 8'he0)
56 | is_e0 <= 1'b1;
57 | else
58 | if (is_f0) begin
59 | // A key is released
60 | is_f0 <= 1'b0;
61 | is_e0 <= 1'b0;
62 | crt_data <= 9'b0;
63 | end
64 | else if (is_e0) begin
65 | is_e0 <= 1'b0;
66 | crt_data <= {1'b1, read_data};
67 | end
68 | else
69 | crt_data <= {1'b0, read_data};
70 |
71 | read_data <= 8'b0;
72 | end
73 | end
74 |
75 | endmodule
76 |
--------------------------------------------------------------------------------
/src/input/testbench/ps2_scan_tb.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | module ps2_scan_tb;
4 |
5 | // Inputs
6 | reg clk;
7 | reg rst;
8 | reg ps2_clk;
9 | reg ps2_data;
10 |
11 | // Outputs
12 | wire [8:0] crt_data;
13 |
14 | // Instantiate the Unit Under Test (UUT)
15 | ps2_scan uut (
16 | .clk(clk),
17 | .rst(rst),
18 | .ps2_clk(ps2_clk),
19 | .ps2_data(ps2_data),
20 | .crt_data(crt_data)
21 | );
22 |
23 | reg [3:0] i;
24 |
25 | localparam [7:0] SPACE = 8'h29, UP = 8'h75;
26 | localparam [7:0] E0 = 8'he0, F0 = 8'hf0;
27 |
28 | initial begin
29 | clk = 0;
30 | rst = 1;
31 | ps2_clk = 1;
32 | ps2_data = 0;
33 | #50;
34 |
35 | rst = 0;
36 | #30;
37 |
38 | rst = 1;
39 | #30;
40 |
41 | // space
42 | for (i=0;i<11;i=i+1) begin
43 | ps2_clk = 1;
44 | if (i > 0 && i < 9)
45 | ps2_data = SPACE[i-1];
46 | #30;
47 |
48 | ps2_clk = 0;
49 | #30;
50 | end
51 |
52 | ps2_clk = 1;
53 | #30;
54 |
55 | // e0
56 | for (i=0;i<11;i=i+1) begin
57 | ps2_clk = 1;
58 | if (i > 0 && i < 9)
59 | ps2_data = E0[i-1];
60 | #30;
61 |
62 | ps2_clk = 0;
63 | #30;
64 | end
65 |
66 | ps2_clk = 1;
67 | #30;
68 |
69 | // up
70 | for (i=0;i<11;i=i+1) begin
71 | ps2_clk = 1;
72 | if (i > 0 && i < 9)
73 | ps2_data = UP[i-1];
74 | #30;
75 |
76 | ps2_clk = 0;
77 | #30;
78 | end
79 |
80 | ps2_clk = 1;
81 | #30;
82 |
83 | // f0
84 | for (i=0;i<11;i=i+1) begin
85 | ps2_clk = 1;
86 | if (i > 0 && i < 9)
87 | ps2_data = F0[i-1];
88 | #30;
89 |
90 | ps2_clk = 0;
91 | #30;
92 | end
93 |
94 | ps2_clk = 1;
95 | #30;
96 |
97 | // space
98 | for (i=0;i<11;i=i+1) begin
99 | ps2_clk = 1;
100 | if (i > 0 && i < 9)
101 | ps2_data = SPACE[i-1];
102 | #30;
103 |
104 | ps2_clk = 0;
105 | #30;
106 | end
107 |
108 | ps2_clk = 1;
109 | #30;
110 | end
111 |
112 | always begin
113 | #5;
114 | clk = ~clk;
115 | end
116 |
117 | endmodule
118 |
119 |
--------------------------------------------------------------------------------
/src/logic/gobang_logic.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //------------------------------------------------------------------------------
4 | // The logic part of the gobang game
5 | //------------------------------------------------------------------------------
6 | module gobang_logic(
7 | input wire clk_slow, // Slower clock for main FSM
8 | input wire clk_fast, // Faster clock for strategy and checker
9 | input wire rst, // Reset
10 | input wire random, // Random signal
11 |
12 | input wire key_up, // If UP key is pressed
13 | input wire key_down, // If DOWN key is pressed
14 | input wire key_left, // If LEFT key is pressed
15 | input wire key_right, // If RIGHT key is pressed
16 | input wire key_ok, // If OK key is pressed
17 | input wire key_switch, // If SWITCH key is pressed
18 |
19 | input wire [8:0] black_i, // Row information for strategy/checker
20 | input wire [8:0] black_j, // Column information for s/c
21 | input wire [8:0] black_ij, // Main diagonal information for s/c
22 | input wire [8:0] black_ji, // Counter diagonal information for s/c
23 | input wire [8:0] white_i,
24 | input wire [8:0] white_j,
25 | input wire [8:0] white_ij,
26 | input wire [8:0] white_ji,
27 | input wire [14:0] chess_row, // Row information for main logic
28 |
29 | output wire [3:0] consider_i, // The row s/c is considering
30 | output wire [3:0] consider_j, // The column s/c is considering
31 |
32 | output reg data_clr, // Clear the datapath
33 | output reg data_write, // Writing-enable signal of the datapath
34 |
35 | output reg [3:0] cursor_i, // Row of the cursor
36 | output reg [3:0] cursor_j, // Column of the cursor
37 | output reg black_is_player, // If black is not AI
38 | output reg white_is_player, // If white is not AI
39 | output reg crt_player, // Current player
40 | output reg game_running, // If the game is running
41 | output reg [1:0] winner // Who wins the game
42 | );
43 |
44 | // Side parameters
45 | localparam BLACK = 1'b0,
46 | WHITE = 1'b1;
47 |
48 | // Chessboard parameters
49 | localparam BOARD_SIZE = 15;
50 |
51 | // State parameters
52 | localparam STATE_IDLE = 3'b000,
53 | STATE_MOVE = 3'b001,
54 | STATE_WAIT = 3'b010,
55 | STATE_DECIDE = 3'b011,
56 | STATE_PUT_CHESS = 3'b100,
57 | STATE_PUT_END = 3'b101,
58 | STATE_CHECK = 3'b110,
59 | STATE_GAME_END = 3'b111;
60 |
61 | // Lasting time for STATE_WAIT
62 | localparam WAIT_TIME = 400;
63 |
64 | reg [2:0] state; // Current game state
65 | reg [8:0] wait_count;
66 | reg [7:0] move_count; // How many moves have been played
67 |
68 | // A simple strategy for the game
69 | reg strategy_clr, strategy_active;
70 | wire [3:0] strategy_i, strategy_j;
71 | wire [12:0] black_best_score;
72 | wire [3:0] black_best_i, black_best_j;
73 | wire [12:0] white_best_score;
74 | wire [3:0] white_best_i, white_best_j;
75 | gobang_strategy
76 | strategy(
77 | .clk(clk_fast),
78 | .rst(rst),
79 | .clr(strategy_clr),
80 | .active(strategy_active),
81 | .random(random),
82 | .black_i(black_i),
83 | .black_j(black_j),
84 | .black_ij(black_ij),
85 | .black_ji(black_ji),
86 | .white_i(white_i),
87 | .white_j(white_j),
88 | .white_ij(white_ij),
89 | .white_ji(white_ji),
90 | .get_i(strategy_i),
91 | .get_j(strategy_j),
92 | .black_best_score(black_best_score),
93 | .black_best_i(black_best_i),
94 | .black_best_j(black_best_j),
95 | .white_best_score(white_best_score),
96 | .white_best_i(white_best_i),
97 | .white_best_j(white_best_j)
98 | );
99 |
100 | // A checker to check if someone wins the game
101 | reg win_clr, win_active;
102 | wire [3:0] win_i, win_j;
103 | wire is_win;
104 | win_checker
105 | checker(
106 | .clk(clk_fast),
107 | .rst(rst),
108 | .clr(win_clr),
109 | .active(win_active),
110 | .black_i(black_i),
111 | .black_j(black_j),
112 | .black_ij(black_ij),
113 | .black_ji(black_ji),
114 | .white_i(white_i),
115 | .white_j(white_j),
116 | .white_ij(white_ij),
117 | .white_ji(white_ji),
118 | .get_i(win_i),
119 | .get_j(win_j),
120 | .is_win(is_win)
121 | );
122 |
123 | // The strategy and the checker uses the same port to get information,
124 | // but they will not use it at the same time
125 | assign consider_i = strategy_i | win_i;
126 | assign consider_j = strategy_j | win_j;
127 |
128 | // Main FSM of the game
129 | always @ (posedge clk_slow or negedge rst) begin
130 | if (!rst) begin
131 | cursor_i <= BOARD_SIZE;
132 | cursor_j <= BOARD_SIZE;
133 | {white_is_player, black_is_player} <= 2'b01;
134 | crt_player <= BLACK;
135 | game_running <= 1'b0;
136 | winner <= 2'b00;
137 |
138 | state <= STATE_IDLE;
139 | move_count <= 8'b0;
140 | data_clr <= 1'b0;
141 | data_write <= 1'b0;
142 | strategy_clr <= 1'b0;
143 | strategy_active <= 1'b0;
144 | win_clr <= 1'b0;
145 | win_active <= 1'b0;
146 | end
147 | else begin
148 | case (state)
149 | STATE_IDLE:
150 | if (key_ok) begin
151 | // Press OK key to start the game
152 | cursor_i <= BOARD_SIZE/2;
153 | cursor_j <= BOARD_SIZE/2;
154 | crt_player <= BLACK;
155 | game_running <= 1'b1;
156 | winner <= 2'b00;
157 |
158 | state <= STATE_MOVE;
159 | move_count <= 8'b0;
160 | data_clr <= 1'b1;
161 | strategy_clr <= 1'b1;
162 | win_clr <= 1'b1;
163 | end
164 | else if (key_switch)
165 | // Switch player
166 | {white_is_player, black_is_player} <=
167 | {white_is_player, black_is_player} + 2'b1;
168 | else
169 | state <= STATE_IDLE;
170 |
171 | STATE_MOVE: begin
172 | data_clr <= 1'b0;
173 | strategy_clr <= 1'b0;
174 | win_clr <= 1'b0;
175 |
176 | if ((crt_player == BLACK && black_is_player) ||
177 | (crt_player == WHITE && white_is_player)) begin
178 | // Player's move
179 |
180 | // Move the cursor
181 | if (key_up && cursor_i > 0)
182 | cursor_i <= cursor_i - 1'b1;
183 | else if (key_down && cursor_i < BOARD_SIZE - 1)
184 | cursor_i <= cursor_i + 1'b1;
185 | if (key_left && cursor_j > 0)
186 | cursor_j <= cursor_j - 1'b1;
187 | else if (key_right && cursor_j < BOARD_SIZE - 1)
188 | cursor_j <= cursor_j + 1'b1;
189 |
190 | if (key_ok)
191 | // Press OK key to put the chess
192 | state <= STATE_PUT_CHESS;
193 | end
194 | else begin
195 | // CPU's move
196 | strategy_active <= 1'b1;
197 | state <= STATE_WAIT;
198 | wait_count <= 0;
199 | end
200 | end
201 |
202 | STATE_WAIT:
203 | // Wait for a while, otherwise the CPU will deicide too fast
204 | if (wait_count >= WAIT_TIME)
205 | state <= STATE_DECIDE;
206 | else
207 | wait_count <= wait_count + 1'b1;
208 |
209 | STATE_DECIDE: begin
210 | // Compare the best possible score for my side and the opposite,
211 | // and choose the best position
212 | strategy_active <= 1'b0;
213 | if (black_best_score > white_best_score ||
214 | (black_best_score == white_best_score &&
215 | crt_player == BLACK)) begin
216 | cursor_i <= black_best_i;
217 | cursor_j <= black_best_j;
218 | end
219 | else begin
220 | cursor_i <= white_best_i;
221 | cursor_j <= white_best_j;
222 | end
223 |
224 | state <= STATE_PUT_CHESS;
225 | end
226 |
227 | STATE_PUT_CHESS:
228 | // Check if the position is occupied. If not, put the chess
229 | if (!chess_row[cursor_j]) begin
230 | move_count <= move_count + 8'b1;
231 | data_write <= 1'b1;
232 | state <= STATE_PUT_END;
233 | end
234 | else
235 | state <= STATE_MOVE;
236 |
237 | STATE_PUT_END: begin
238 | data_write <= 1'b0;
239 | win_active <= 1'b1;
240 | state <= STATE_CHECK;
241 | end
242 |
243 | STATE_CHECK: begin
244 | // Check if someone wins the game or there is a draw
245 | win_active <= 1'b0;
246 | if (is_win || move_count == BOARD_SIZE * BOARD_SIZE)
247 | state <= STATE_GAME_END;
248 | else begin
249 | crt_player <= ~crt_player;
250 | state <= STATE_MOVE;
251 | end
252 | end
253 |
254 | STATE_GAME_END: begin
255 | if (is_win)
256 | // Someone wins the game
257 | winner <= 2'b01 << crt_player;
258 | else
259 | // There is a draw
260 | winner <= 2'b11;
261 |
262 | state <= STATE_IDLE;
263 | game_running <= 1'b0;
264 | end
265 |
266 | endcase
267 | end
268 | end
269 |
270 | endmodule
271 |
--------------------------------------------------------------------------------
/src/logic/gobang_patterns.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 | //------------------------------------------------------------------------------
3 | // _ = empty | * = my chess | o = opponent's chess
4 | //------------------------------------------------------------------------------
5 |
6 | //------------------------------------------------------------------------------
7 | // Recognize *****
8 | //------------------------------------------------------------------------------
9 | module pattern_five(
10 | input wire [8:0] my,
11 | output reg ret
12 | );
13 |
14 | always @ (*)
15 | if ((my[0] && my[1] && my[2] && my[3] && my[4]) ||
16 | (my[1] && my[2] && my[3] && my[4] && my[5]) ||
17 | (my[2] && my[3] && my[4] && my[5] && my[6]) ||
18 | (my[3] && my[4] && my[5] && my[6] && my[7]) ||
19 | (my[4] && my[5] && my[6] && my[7] && my[8]))
20 | ret = 1'b1;
21 | else
22 | ret = 1'b0;
23 |
24 | endmodule
25 |
26 | //------------------------------------------------------------------------------
27 | // Recognize _****_
28 | //------------------------------------------------------------------------------
29 | module pattern_four(
30 | input wire [8:0] my,
31 | input wire [8:0] op,
32 | output reg ret
33 | );
34 |
35 | wire [8:0] empty;
36 | assign empty = ~(my | op);
37 |
38 | always @ (*)
39 | if ((empty[0] && my[1] && my[2] && my[3] && my[4] && empty[5]) ||
40 | (empty[1] && my[2] && my[3] && my[4] && my[5] && empty[6]) ||
41 | (empty[2] && my[3] && my[4] && my[5] && my[6] && empty[7]) ||
42 | (empty[3] && my[4] && my[5] && my[6] && my[7] && empty[8]))
43 | ret = 1'b1;
44 | else
45 | ret = 1'b0;
46 |
47 | endmodule
48 |
49 | //------------------------------------------------------------------------------
50 | // Recognize o****_ | _****o | *_*** | ***_* | **_**
51 | //------------------------------------------------------------------------------
52 | module pattern_ffour(
53 | input wire [8:0] my,
54 | input wire [8:0] op,
55 | output reg ret
56 | );
57 |
58 | wire [8:0] empty;
59 | assign empty = ~(my | op);
60 |
61 | always @ (*)
62 | if ((op[0] && my[1] && my[2] && my[3] && my[4] && empty[5]) ||
63 | (op[1] && my[2] && my[3] && my[4] && my[5] && empty[6]) ||
64 | (op[2] && my[3] && my[4] && my[5] && my[6] && empty[7]) ||
65 | (op[3] && my[4] && my[5] && my[6] && my[7] && empty[8]) ||
66 | (empty[0] && my[1] && my[2] && my[3] && my[4] && op[5]) ||
67 | (empty[1] && my[2] && my[3] && my[4] && my[5] && op[6]) ||
68 | (empty[2] && my[3] && my[4] && my[5] && my[6] && op[7]) ||
69 | (empty[3] && my[4] && my[5] && my[6] && my[7] && op[8]) ||
70 | (my[0] && empty[1] && my[2] && my[3] && my[4]) ||
71 | (my[1] && empty[2] && my[3] && my[4] && my[5]) ||
72 | (my[2] && empty[3] && my[4] && my[5] && my[6]) ||
73 | (my[3] && empty[4] && my[5] && my[6] && my[7]) ||
74 | (my[4] && empty[5] && my[6] && my[7] && my[8]) ||
75 | (my[0] && my[1] && my[2] && empty[3] && my[4]) ||
76 | (my[1] && my[2] && my[3] && empty[4] && my[5]) ||
77 | (my[2] && my[3] && my[4] && empty[5] && my[6]) ||
78 | (my[3] && my[4] && my[5] && empty[6] && my[7]) ||
79 | (my[4] && my[5] && my[6] && empty[7] && my[8]) ||
80 | (my[0] && my[1] && empty[2] && my[3] && my[4]) ||
81 | (my[1] && my[2] && empty[3] && my[4] && my[5]) ||
82 | (my[2] && my[3] && empty[4] && my[5] && my[6]) ||
83 | (my[3] && my[4] && empty[5] && my[6] && my[7]) ||
84 | (my[4] && my[5] && empty[6] && my[7] && my[8]))
85 | ret = 1'b1;
86 | else
87 | ret = 1'b0;
88 |
89 | endmodule
90 |
91 | //------------------------------------------------------------------------------
92 | // Recognize _***_ | _**_*_ | _*_**_
93 | //------------------------------------------------------------------------------
94 | module pattern_three(
95 | input wire [8:0] my,
96 | input wire [8:0] op,
97 | output reg ret
98 | );
99 |
100 | wire [8:0] empty;
101 | assign empty = ~(my | op);
102 |
103 | always @ (*)
104 | if ((empty[0] && my[1] && my[2] && my[3] && empty[4]) ||
105 | (empty[1] && my[2] && my[3] && my[4] && empty[5]) ||
106 | (empty[2] && my[3] && my[4] && my[5] && empty[6]) ||
107 | (empty[3] && my[4] && my[5] && my[6] && empty[7]) ||
108 | (empty[4] && my[5] && my[6] && my[7] && empty[8]) ||
109 | (empty[0] && my[1] && my[2] && empty[3] && my[4] && empty[5]) ||
110 | (empty[1] && my[2] && my[3] && empty[4] && my[5] && empty[6]) ||
111 | (empty[2] && my[3] && my[4] && empty[5] && my[6] && empty[7]) ||
112 | (empty[3] && my[4] && my[5] && empty[6] && my[7] && empty[8]) ||
113 | (empty[0] && my[1] && empty[2] && my[3] && my[4] && empty[5]) ||
114 | (empty[1] && my[2] && empty[3] && my[4] && my[5] && empty[6]) ||
115 | (empty[2] && my[3] && empty[4] && my[5] && my[6] && empty[7]) ||
116 | (empty[3] && my[4] && empty[5] && my[6] && my[7] && empty[8]))
117 | ret = 1'b1;
118 | else
119 | ret = 1'b0;
120 |
121 | endmodule
122 |
123 | //------------------------------------------------------------------------------
124 | // Recognize o_*** | ***_o
125 | //------------------------------------------------------------------------------
126 | module pattern_fthree(
127 | input wire [8:0] my,
128 | input wire [8:0] op,
129 | output reg ret
130 | );
131 |
132 | wire [8:0] empty;
133 | assign empty = ~(my | op);
134 |
135 | always @ (*)
136 | if ((op[0] && empty[1] && my[2] && my[3] && my[4]) ||
137 | (op[1] && empty[2] && my[3] && my[4] && my[5]) ||
138 | (op[2] && empty[3] && my[4] && my[5] && my[6]) ||
139 | (op[3] && empty[4] && my[5] && my[6] && my[7]) ||
140 | (op[4] && empty[5] && my[6] && my[7] && my[8]) ||
141 | (my[0] && my[1] && my[2] && empty[3] && op[4]) ||
142 | (my[1] && my[2] && my[3] && empty[4] && op[5]) ||
143 | (my[2] && my[3] && my[4] && empty[5] && op[6]) ||
144 | (my[3] && my[4] && my[5] && empty[6] && op[7]) ||
145 | (my[4] && my[5] && my[6] && empty[7] && op[8]))
146 | ret = 1'b1;
147 | else
148 | ret = 1'b0;
149 |
150 | endmodule
151 |
152 | //------------------------------------------------------------------------------
153 | // Recognize _**_ | _*_*_
154 | //------------------------------------------------------------------------------
155 | module pattern_two(
156 | input wire [8:0] my,
157 | input wire [8:0] op,
158 | output reg ret
159 | );
160 |
161 | wire [8:0] empty;
162 | assign empty = ~(my | op);
163 |
164 | always @ (*)
165 | if ((empty[0] && my[1] && my[2] && empty[3]) ||
166 | (empty[1] && my[2] && my[3] && empty[4]) ||
167 | (empty[2] && my[3] && my[4] && empty[5]) ||
168 | (empty[3] && my[4] && my[5] && empty[6]) ||
169 | (empty[4] && my[5] && my[6] && empty[7]) ||
170 | (empty[5] && my[6] && my[7] && empty[8]) ||
171 | (empty[0] && my[1] && empty[2] && my[3] && empty[4]) ||
172 | (empty[1] && my[2] && empty[3] && my[4] && empty[5]) ||
173 | (empty[2] && my[3] && empty[4] && my[5] && empty[6]) ||
174 | (empty[3] && my[4] && empty[5] && my[6] && empty[7]) ||
175 | (empty[4] && my[5] && empty[6] && my[7] && empty[8]))
176 | ret = 1'b1;
177 | else
178 | ret = 1'b0;
179 |
180 | endmodule
181 |
182 | //------------------------------------------------------------------------------
183 | // Recognize o***_ | _***o
184 | //------------------------------------------------------------------------------
185 | module pattern_sthree(
186 | input wire [8:0] my,
187 | input wire [8:0] op,
188 | output reg ret
189 | );
190 |
191 | wire [8:0] empty;
192 | assign empty = ~(my | op);
193 |
194 | always @ (*)
195 | if ((op[0] && my[1] && my[2] && my[3] && empty[4]) ||
196 | (op[1] && my[2] && my[3] && my[4] && empty[5]) ||
197 | (op[2] && my[3] && my[4] && my[5] && empty[6]) ||
198 | (op[3] && my[4] && my[5] && my[6] && empty[7]) ||
199 | (op[4] && my[5] && my[6] && my[7] && empty[8]) ||
200 | (empty[0] && my[1] && my[2] && my[3] && op[4]) ||
201 | (empty[1] && my[2] && my[3] && my[4] && op[5]) ||
202 | (empty[2] && my[3] && my[4] && my[5] && op[6]) ||
203 | (empty[3] && my[4] && my[5] && my[6] && op[7]) ||
204 | (empty[4] && my[5] && my[6] && my[7] && op[8]))
205 | ret = 1'b1;
206 | else
207 | ret = 1'b0;
208 |
209 | endmodule
210 |
211 | //------------------------------------------------------------------------------
212 | // Recognize o_** | **_o
213 | //------------------------------------------------------------------------------
214 | module pattern_ftwo(
215 | input wire [8:0] my,
216 | input wire [8:0] op,
217 | output reg ret
218 | );
219 |
220 | wire [8:0] empty;
221 | assign empty = ~(my | op);
222 |
223 | always @ (*)
224 | if ((op[0] && empty[1] && my[2] && my[3]) ||
225 | (op[1] && empty[2] && my[3] && my[4]) ||
226 | (op[2] && empty[3] && my[4] && my[5]) ||
227 | (op[3] && empty[4] && my[5] && my[6]) ||
228 | (op[4] && empty[5] && my[6] && my[7]) ||
229 | (op[5] && empty[6] && my[7] && my[8]) ||
230 | (my[0] && my[1] && empty[2] && op[3]) ||
231 | (my[1] && my[2] && empty[3] && op[4]) ||
232 | (my[2] && my[3] && empty[4] && op[5]) ||
233 | (my[3] && my[4] && empty[5] && op[6]) ||
234 | (my[4] && my[5] && empty[6] && op[7]) ||
235 | (my[5] && my[6] && empty[7] && op[8]))
236 | ret = 1'b1;
237 | else
238 | ret = 1'b0;
239 |
240 | endmodule
241 |
242 | //------------------------------------------------------------------------------
243 | // Recognize o**_ | _**o
244 | //------------------------------------------------------------------------------
245 | module pattern_stwo(
246 | input wire [8:0] my,
247 | input wire [8:0] op,
248 | output reg ret
249 | );
250 |
251 | wire [8:0] empty;
252 | assign empty = ~(my | op);
253 |
254 | always @ (*)
255 | if ((op[0] && my[1] && my[2] && empty[3]) ||
256 | (op[1] && my[2] && my[3] && empty[4]) ||
257 | (op[2] && my[3] && my[4] && empty[5]) ||
258 | (op[3] && my[4] && my[5] && empty[6]) ||
259 | (op[4] && my[5] && my[6] && empty[7]) ||
260 | (op[5] && my[6] && my[7] && empty[8]) ||
261 | (empty[0] && my[1] && my[2] && op[3]) ||
262 | (empty[1] && my[2] && my[3] && op[4]) ||
263 | (empty[2] && my[3] && my[4] && op[5]) ||
264 | (empty[3] && my[4] && my[5] && op[6]) ||
265 | (empty[4] && my[5] && my[6] && op[7]) ||
266 | (empty[5] && my[6] && my[7] && op[8]))
267 | ret = 1'b1;
268 | else
269 | ret = 1'b0;
270 |
271 | endmodule
272 |
--------------------------------------------------------------------------------
/src/logic/gobang_strategy.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //------------------------------------------------------------------------------
4 | // A simple strategy for the gobang game.
5 | //------------------------------------------------------------------------------
6 | module gobang_strategy(
7 | input wire clk, // Clock
8 | input wire rst, // Reset
9 | input wire clr, // Clear
10 | input wire active, // Active signal
11 | input wire random, // Random signal
12 |
13 | input wire [8:0] black_i, // Row information
14 | input wire [8:0] black_j, // Column information
15 | input wire [8:0] black_ij, // Main diagonal information
16 | input wire [8:0] black_ji, // Counter diagonal information
17 | input wire [8:0] white_i,
18 | input wire [8:0] white_j,
19 | input wire [8:0] white_ij,
20 | input wire [8:0] white_ji,
21 |
22 | output reg [3:0] get_i, // Current row considered
23 | output reg [3:0] get_j, // Current column considered
24 |
25 | output reg [12:0] black_best_score, // Best possible score
26 | output reg [3:0] black_best_i, // Best row
27 | output reg [3:0] black_best_j, // Best column
28 | output reg [12:0] white_best_score,
29 | output reg [3:0] white_best_i,
30 | output reg [3:0] white_best_j
31 | );
32 |
33 | // Chessboard parameters
34 | localparam BOARD_SIZE = 15;
35 |
36 | // State parameters
37 | localparam STATE_IDLE = 1'b0,
38 | STATE_WORKING = 1'b1;
39 |
40 | reg state; // Current state
41 |
42 | // Scores of the four directions
43 | wire [12:0] black_score_i, black_score_j, black_score_ij, black_score_ji;
44 | wire [12:0] white_score_i, white_score_j, white_score_ij, white_score_ji;
45 |
46 | // Total scores
47 | wire [12:0] black_score, white_score;
48 | assign black_score = black_score_i + black_score_j +
49 | black_score_ij + black_score_ji;
50 | assign white_score = white_score_i + white_score_j +
51 | white_score_ij + white_score_ji;
52 |
53 | // Score calculators
54 | score_calculator
55 | calc_black_i(
56 | .my(black_i),
57 | .op(white_i),
58 | .score(black_score_i)
59 | ),
60 | calc_black_j(
61 | .my(black_j),
62 | .op(white_j),
63 | .score(black_score_j)
64 | ),
65 | calc_black_ij(
66 | .my(black_ij),
67 | .op(white_ij),
68 | .score(black_score_ij)
69 | ),
70 | calc_black_ji(
71 | .my(black_ji),
72 | .op(white_ji),
73 | .score(black_score_ji)
74 | ),
75 | calc_white_i(
76 | .my(white_i),
77 | .op(black_i),
78 | .score(white_score_i)
79 | ),
80 | calc_white_j(
81 | .my(white_j),
82 | .op(black_j),
83 | .score(white_score_j)
84 | ),
85 | calc_white_ij(
86 | .my(white_ij),
87 | .op(black_ij),
88 | .score(white_score_ij)
89 | ),
90 | calc_white_ji(
91 | .my(white_ji),
92 | .op(black_ji),
93 | .score(white_score_ji)
94 | );
95 |
96 | // FSM of the strategy
97 | // Every time the active signal comes, the strategy will run once
98 | always @ (posedge clk or negedge rst) begin
99 | if (!rst || clr) begin
100 | get_i <= 4'b0;
101 | get_j <= 4'b0;
102 | black_best_score <= 0;
103 | black_best_i <= BOARD_SIZE / 2;
104 | black_best_j <= BOARD_SIZE / 2;
105 | white_best_score <= 0;
106 | white_best_i <= BOARD_SIZE / 2;
107 | white_best_j <= BOARD_SIZE / 2;
108 |
109 | state <= STATE_IDLE;
110 | end
111 | else if (!active && state == STATE_IDLE)
112 | state <= STATE_WORKING;
113 | else if (active && state == STATE_WORKING) begin
114 | // Calculate the best positions
115 | if ((get_i == 4'b0 && get_j == 4'b0) ||
116 | black_score > black_best_score ||
117 | (black_score == black_best_score && random)) begin
118 | black_best_score <= black_score;
119 | black_best_i <= get_i;
120 | black_best_j <= get_j;
121 | end
122 | if ((get_i == 4'b0 && get_j == 4'b0) ||
123 | white_score > white_best_score ||
124 | (white_score == white_best_score && random)) begin
125 | white_best_score <= white_score;
126 | white_best_i <= get_i;
127 | white_best_j <= get_j;
128 | end
129 |
130 | // Move to the next position
131 | if (get_j == BOARD_SIZE - 1) begin
132 | if (get_i == BOARD_SIZE - 1) begin
133 | get_i <= 4'b0;
134 | get_j <= 4'b0;
135 | state <= STATE_IDLE;
136 | end
137 | else begin
138 | get_i <= get_i + 1'b1;
139 | get_j <= 4'b0;
140 | end
141 | end
142 | else
143 | get_j <= get_j + 1'b1;
144 | end
145 | end
146 |
147 | endmodule
148 |
--------------------------------------------------------------------------------
/src/logic/score_calculator.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //------------------------------------------------------------------------------
4 | // Calculate the score of a given pattern
5 | //------------------------------------------------------------------------------
6 | module score_calculator(
7 | input wire [8:0] my, // Pattern of my side
8 | input wire [8:0] op, // Pattern of the opposite side
9 | output reg [12:0] score // The score of the given pattern
10 | );
11 |
12 | wire [8:0] my_next;
13 | assign my_next = my | 9'b000010000;
14 |
15 | wire score2, score4, score5, score8, score15,
16 | score40, score70, score300, score2000;
17 |
18 | // Pattern recognizers
19 | pattern_stwo pattern2(my_next, op, score2);
20 | pattern_ftwo pattern4(my_next, op, score4);
21 | pattern_sthree pattern5(my_next, op, score5);
22 | pattern_two pattern8(my_next, op, score8);
23 | pattern_fthree pattern15(my_next, op, score15);
24 | pattern_three pattern40(my_next, op, score40);
25 | pattern_ffour pattern70(my_next, op, score70);
26 | pattern_four pattern300(my_next, op, score300);
27 | pattern_five pattern2000(my_next, score2000);
28 |
29 | always @ (*)
30 | if (my[4] || op[4])
31 | // Invalid pattern
32 | score = 0;
33 | else if (score2000)
34 | score = 2000;
35 | else if (score300)
36 | score = 300;
37 | else if (score70)
38 | score = 70;
39 | else if (score40)
40 | score = 40;
41 | else if (score15)
42 | score = 15;
43 | else if (score8)
44 | score = 8;
45 | else if (score5)
46 | score = 5;
47 | else if (score4)
48 | score = 4;
49 | else if (score2)
50 | score = 2;
51 | else
52 | score = 1;
53 |
54 | endmodule
55 |
--------------------------------------------------------------------------------
/src/logic/win_checker.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //------------------------------------------------------------------------------
4 | // Checker to check if someone wins the game
5 | //------------------------------------------------------------------------------
6 | module win_checker(
7 | input wire clk, // Clock
8 | input wire rst, // Reset
9 | input wire clr, // Clear
10 | input wire active, // Active signal
11 |
12 | input wire [8:0] black_i, // Row information
13 | input wire [8:0] black_j, // Column information
14 | input wire [8:0] black_ij, // Main diagonal information
15 | input wire [8:0] black_ji, // Counter diagonal information
16 | input wire [8:0] white_i,
17 | input wire [8:0] white_j,
18 | input wire [8:0] white_ij,
19 | input wire [8:0] white_ji,
20 |
21 | output reg [3:0] get_i, // Current row considered
22 | output reg [3:0] get_j, // Current column considered
23 | output reg is_win // If someone wins the game
24 | );
25 |
26 | // Chessboard parameters
27 | localparam BOARD_SIZE = 15;
28 |
29 | // State parameters
30 | localparam STATE_IDLE = 1'b0,
31 | STATE_WORKING = 1'b1;
32 |
33 | reg state; // Current state
34 |
35 | // Pattern recognizers
36 | wire b0, b1, b2, b3, w0, w1, w2, w3;
37 | pattern_five pattern_b0(black_i, b0),
38 | pattern_b1(black_j, b1),
39 | pattern_b2(black_ij, b2),
40 | pattern_b3(black_ji, b3),
41 | pattern_w0(white_i, w0),
42 | pattern_w1(white_j, w1),
43 | pattern_w2(white_ij, w2),
44 | pattern_w3(white_ji, w3);
45 |
46 | // FSM of the checker
47 | // Every time the active signal comes, the checker will run once
48 | always @ (posedge clk or negedge rst) begin
49 | if (!rst || clr) begin
50 | get_i <= 4'b0;
51 | get_j <= 4'b0;
52 | is_win <= 0;
53 |
54 | state <= STATE_IDLE;
55 | end
56 | else if (!active && state == STATE_IDLE)
57 | state <= STATE_WORKING;
58 | else if (active && state == STATE_WORKING) begin
59 | // Check if someone wins the game
60 | if (get_i == 4'b0 && get_j == 4'b0)
61 | is_win <= b0 | b1 | b2 | b3 | w0 | w1 | w2 | w3;
62 | else
63 | is_win <= is_win | b0 | b1 | b2 | b3 | w0 | w1 | w2 | w3;
64 |
65 | // Move to the next position
66 | if (get_j == BOARD_SIZE - 1) begin
67 | if (get_i == BOARD_SIZE - 1) begin
68 | get_i <= 4'b0;
69 | get_j <= 4'b0;
70 | state <= STATE_IDLE;
71 | end
72 | else begin
73 | get_i <= get_i + 1'b1;
74 | get_j <= 4'b0;
75 | end
76 | end
77 | else
78 | get_j <= get_j + 1'b1;
79 | end
80 | end
81 |
82 | endmodule
83 |
--------------------------------------------------------------------------------
/src/random/random_generator.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 |
3 | //------------------------------------------------------------------------------
4 | // Generate a random number
5 | //------------------------------------------------------------------------------
6 | module random_generator(
7 | input wire clk, // Clock
8 | input wire rst, // Reset
9 | input wire load, // Load signal
10 | input wire [31:0] seed, // Random seed
11 | output reg [31:0] rand_num // A random number
12 | );
13 |
14 | always @ (posedge clk or negedge rst)
15 | if (!rst)
16 | rand_num <= 32'b0;
17 | else if (load)
18 | // Load the random seed
19 | rand_num <= seed;
20 | else
21 | rand_num <= {rand_num[30:0],
22 | rand_num[31] ^ rand_num[29] ^ rand_num[28] ^
23 | rand_num[27] ^ rand_num[23] ^ rand_num[20] ^
24 | rand_num[19] ^ rand_num[17] ^ rand_num[15] ^
25 | rand_num[14] ^ rand_num[12] ^ rand_num[11] ^
26 | rand_num[9] ^ rand_num[4] ^ rand_num[3] ^
27 | rand_num[2]};
28 |
29 | endmodule
30 |
--------------------------------------------------------------------------------