-
Notifications
You must be signed in to change notification settings - Fork 0
/
find_intersection_vert.v
305 lines (225 loc) · 10.4 KB
/
find_intersection_vert.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
`timescale 1ns/1ns
module find_wall_intersection_vert
(
input signed [12:0] playerX, playerY, // player's current X and Y position
input [9:0] alpha_X, // angle of ray currently being cast in fixed point format
input [9:0] alpha_Y, // alpha_X is the left of the decimal point, alpha_Y is the right
input clock, // On board clock, 50 MHz for the DE1_SoC
input resetn, // active-low, resets the FSM and clears the datapath registers
input begin_calc, // begins calculation of wall intersection
output signed [12:0] wallX, wallY, // calculated wall X and Y for this ray
output wall_found, // high if wall is found, low if not
output maze_bounds_reached, // high if the ray reached maze bounds without intersecting with the grid
output end_calc // calculation has ended, whether wall found or not
);
// tells the datapath to reset values in preparation for calculation
wire reset_datapath;
// tells the datapath to calculate the first intersection of the ray with the grid, cycle 0
wire find_first_intersection_0;
// tells the datapath to calculate the first intersection of the ray with the grid, cycle 1
wire find_first_intersection_1;
// tells the datapath to calculate the X and Y offset to find new intersections of the ray with the grid, cycle 0
wire find_offset_0;
// tells the datapath to calculate the X and Y offset to find new intersections of the ray with the grid, cycle 1
wire find_offset_1;
// tells the datapath to find the next intersection of the ray with the grid
wire find_next_intersection;
// tells the datapath to convert an X, Y intersection to a grid coordinate
wire convert_to_grid_coords;
// tells the datapath to check whether a wall exists at this grid coordinate by communicating with the grid register
wire check_for_wall_0, check_for_wall_1;
// if either reached_wall or reached_maze_bounds, start at the beginning and wait for begin_calc again
wire reached_wall, reached_maze_bounds;
// tell the FSM that wall checking or bounds checking is complete, and to transition states as required
wire end_wall_checking, end_bounds_checking;
// ------------------------------------ outputs to higher-level module --------------------------------------
// wall_found is always reached_wall, if no wall is reached then end_calc is high but wall_found is 0
assign wall_found = reached_wall;
assign maze_bounds_reached = reached_maze_bounds;
// high for one cycle when either wall is reached or bounds are reached
assign end_calc = reached_wall || reached_maze_bounds;
// this is the same control module in find_intersection_horiz.v
control_find_intersection FSM(
.clock(clock),
.resetn(resetn),
// -------------------------------- inputs that affect FSM state -------------------------------------
.begin_calc(begin_calc),
// if either reached_wall or reached_maze_bounds, go back to beginning
.reached_wall(reached_wall),
.reached_maze_bounds(reached_maze_bounds),
.end_bounds_checking(end_bounds_checking),
.end_wall_checking(end_wall_checking),
// ------------------------------------ outputs to the datapath --------------------------------------
.reset_datapath(reset_datapath),
.find_first_intersection_0(find_first_intersection_0),
.find_first_intersection_1(find_first_intersection_1),
.find_offset_0(find_offset_0),
.find_offset_1(find_offset_1),
.find_next_intersection(find_next_intersection),
.convert_to_grid_coords(convert_to_grid_coords),
.check_for_wall_0(check_for_wall_0),
.check_for_wall_1(check_for_wall_1)
);
datapath_find_intersection_vert position_manip(
.clock(clock),
.resetn(resetn),
// ------------------------------------ control signals from FSM --------------------------------------
.reset_datapath(reset_datapath),
.find_first_intersection_0(find_first_intersection_0),
.find_first_intersection_1(find_first_intersection_1),
.find_offset_0(find_offset_0),
.find_offset_1(find_offset_1),
.find_next_intersection(find_next_intersection),
.convert_to_grid_coords(convert_to_grid_coords),
.check_for_wall_0(check_for_wall_0),
.check_for_wall_1(check_for_wall_1),
// ------------------------------------ data input and output --------------------------------------
.playerX(playerX),
.playerY(playerY),
.alpha_X(alpha_X),
.alpha_Y(alpha_Y),
// when reached_wall is high, currentX = wallX, currentY = wallY
.currentX(wallX),
.currentY(wallY),
// ----------------------------------------- outputs to FSM -----------------------------------------
// ------------------- inform the FSM if a wall or maze bounds have been reached ----------------------------
.reached_wall(reached_wall),
.reached_maze_bounds(reached_maze_bounds),
.end_bounds_checking(end_bounds_checking),
.end_wall_checking(end_wall_checking)
);
endmodule
module datapath_find_intersection_vert (input clock, resetn,
reset_datapath, find_first_intersection_0, find_first_intersection_1,
find_offset_0, find_offset_1, find_next_intersection,
convert_to_grid_coords, check_for_wall_0, check_for_wall_1,
input signed [12:0] playerX, playerY,
input signed [9:0] alpha_X, input signed [9:0] alpha_Y,
output reg signed [12:0] currentX, currentY,
output reg reached_wall, reached_maze_bounds, end_wall_checking, end_bounds_checking);
// B_x, B_y are the coordinates of the first intersection
// X_a, Y_a are the offsets used to calculate the next intersection
// C_x, C_y is the current X and Y of the ray
reg signed [20:0] B_x, B_y, X_a, Y_a, C_x, C_y;
// S_FIND_NEXT sets currentX and currentY to the first intersection for the first iteration, and checks offset
// intersections after
reg checked_first_intersection;
// ---------------------------------------- sin, cos, tan LUTs --------------------------------------------------
// sin, cos, tan LUTs take fixed points as inputs and give fixed points as outputs
wire signed [9:0] tan_alpha_X;
wire signed [17:0] tan_alpha_Y;
tan_LUT lookup_TAN_value(.angleX(alpha_X),.angleY(alpha_Y),.ratioX(tan_alpha_X),.ratioY(tan_alpha_Y));
// ------------------------------------ Fixed point multiplications -----------------------------------------------
wire signed [20:0] ray_proj_Y;
int_fixed_point_mult_int multiplier_line_eq (
// performs fixed point multiplication: ray_proj_Y = (playerX - B_x) * tan(alpha)
.int_in(playerX - B_x),
.fixed_X(tan_alpha_X),
.fixed_Y(tan_alpha_Y),
.int_out(ray_proj_Y)
);
wire signed [20:0] offset_proj_Y;
int_fixed_point_mult_int multiplier_offset (
// performs fixed point multiplication: offset_proj_Y = -X_a * tan(alpha)
.int_in(-X_a),
.fixed_X(tan_alpha_X),
.fixed_Y(tan_alpha_Y),
.int_out(offset_proj_Y)
);
// ----------------------------------- communication with grid RAM block ------------------------------------------
// 12-bit grid address to address 4096 possible grid locations (0-63, 0-63)
reg [11:0] grid_address;
// high if a wall exists at this grid, else low
wire grid_out;
// how do we create a .mif file to initialize RAM block with level data?
//ram4096x1 grid();
// temporary solution is a lookup table that returns level data
grid2D level_data(.grid_address(grid_address),.grid_out(grid_out));
// ---------------------------------------- datapath output table ------------------------------------------------
always @(posedge clock)
begin
if (!resetn) begin
B_x <= 12'b0;
B_y <= 12'b0;
X_a <= 12'b0;
Y_a <= 12'b0;
C_x <= 12'b0;
C_y <= 12'b0;
end
else begin
if (reset_datapath) begin
checked_first_intersection <= 1'b0;
reached_wall <= 1'b0;
reached_maze_bounds <= 1'b0;
end_wall_checking <= 1'b0;
end_bounds_checking <= 1'b0;
end
if (find_first_intersection_0) begin
if (alpha_X >= 90 && alpha_X < 270) // ray facing left
B_x <= (playerX / 64) * 64 - 1; // subtract 1 to make B part of the grid block to the left of the grid line
else if ((alpha_X >= 270 && alpha_X < 360) || (alpha_X >= 0 && alpha_X < 90)) // ray facing right
B_x <= (playerX / 64) * 64 + 64; // add 64 to make B_x the X position of the next grid block
end
if (find_first_intersection_1) begin
// find B_y by line equation, look above for calculation of ray_proj_Y
// must check if these generated B_x and B_y are out of bounds
B_y <= playerY + ray_proj_Y;
end
if (find_offset_0) begin
if (alpha_X >= 90 && alpha_X < 270) // ray facing left
X_a <= -64;
else if ((alpha_X >= 270 && alpha_X < 360) || (alpha_X >= 0 && alpha_X < 90)) // ray facing right
X_a <= 64;
end
if (find_offset_1)
Y_a <= offset_proj_Y; // slope equation, look above for calculation of offset_proj_Y
if (find_next_intersection) begin
// reset these in preparation for checking for bounds and then wall
end_wall_checking <= 1'b0;
end_bounds_checking <= 1'b0;
// set next intersection to first intersection in the first iteration so that it is also checked for a wall
if (!checked_first_intersection) begin
C_x <= B_x;
C_y <= B_y;
checked_first_intersection <= 1'b1;
end else begin
// add the offset to current coordinate to find next coordinate
C_x <= C_x + X_a;
C_y <= C_y + Y_a;
end
end
if (convert_to_grid_coords) begin
// first check if C_x and C_y are out of bounds. if out of bounds, quit here and go back to S_WAIT
if (C_x >= 4096 || C_y >= 4096 || C_x <= 0 || C_y <= 0)
reached_maze_bounds <= 1'b1;
else
grid_address <= 64 * (C_y / 64) + (C_x / 64); // flatten a 2D grid address into a 1D address
// we're done checking bounds, update the FSM
end_bounds_checking <= 1'b1;
end
if (check_for_wall_0) begin
// by this state, the RAM should have responded with the data at the grid_address
reached_wall <= grid_out;
end
if (check_for_wall_1) begin
// we're done checking for a wall, update the FSM
end_wall_checking <= 1'b1;
end
end
end
// ------------------------------------------- output registers --------------------------------------------------
always @(posedge clock)
begin
if (!resetn)
currentX <= 0;
else
currentX <= C_x; // C_x is registered to keep it stable for 1 clock cycle
end
always @(posedge clock)
begin
if (!resetn)
currentY <= 0;
else
currentY <= C_y; // C_y is registered to keep it stable for 1 clock cycle
end
endmodule