Repository navigation
Expand file tree
/
Copy pathline_buffer.v
More file actions
169 lines (153 loc) · 6.76 KB
/
Copy pathline_buffer.v
File metadata and controls
169 lines (153 loc) · 6.76 KB
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
`timescale 1ns / 1ps
module line_buffer #(
parameter H_PIXEL = 1024,
parameter DATA_WIDTH = 8
)(
input clk,
input rst_n,
input data_in_valid,
input [DATA_WIDTH-1:0] data_in,
input frame_vsync,
output reg window_valid,
output reg [DATA_WIDTH-1:0] win_data_00, win_data_01, win_data_02,
output reg [DATA_WIDTH-1:0] win_data_10, win_data_11, win_data_12,
output reg [DATA_WIDTH-1:0] win_data_20, win_data_21, win_data_22
);
// =========================================================================
// 1. 帧起始检测
// =========================================================================
reg vsync_d1;
wire frame_start = frame_vsync & ~vsync_d1;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) vsync_d1 <= 1'b0;
else vsync_d1 <= frame_vsync;
end
// =========================================================================
// 2. RAM 读写地址控制 (读比写晚 1 拍)
// =========================================================================
reg [9:0] wr_addr;
reg [9:0] rd_addr;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
wr_addr <= 10'd0;
rd_addr <= 10'd0;
end else if (frame_start) begin
wr_addr <= 10'd0;
rd_addr <= 10'd0;
end else if (data_in_valid) begin
wr_addr <= (wr_addr == H_PIXEL - 1) ? 10'd0 : wr_addr + 1'b1;
rd_addr <= wr_addr;
end
end
// =========================================================================
// 3. 双口 RAM 例化 (提取行缓存)
// =========================================================================
wire [DATA_WIDTH-1:0] rd_data_0;
wire [DATA_WIDTH-1:0] rd_data_1;
line_ram_640x8 u_line_ram_0 (
.clka (clk), .cea (data_in_valid), .addra (wr_addr), .dia (data_in),
.clkb (clk), .ceb (data_in_valid), .addrb (rd_addr), .oceb (1'b1),
.dob (rd_data_0), .rstb (~rst_n)
);
line_ram_640x8_1 u_line_ram_1 (
.clka (clk), .cea (data_in_valid), .addra (wr_addr), .dia (rd_data_0),
.clkb (clk), .ceb (data_in_valid), .addrb (rd_addr), .oceb (1'b1),
.dob (rd_data_1), .rstb (~rst_n)
);
// =========================================================================
// 4. 数据与 Valid 信号延迟链
// =========================================================================
reg [DATA_WIDTH-1:0] data_in_d1, data_in_d2;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_in_d1 <= 0; data_in_d2 <= 0;
end else begin
data_in_d1 <= data_in; data_in_d2 <= data_in_d1;
end
end
reg valid_d1, valid_d2, valid_d3;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
valid_d1 <= 1'b0; valid_d2 <= 1'b0; valid_d3 <= 1'b0;
end else begin
valid_d1 <= data_in_valid;
valid_d2 <= valid_d1;
valid_d3 <= valid_d2;
end
end
// =========================================================================
// 5. 3x3 窗口移位寄存器
// =========================================================================
reg [DATA_WIDTH-1:0] row0 [0:2];
reg [DATA_WIDTH-1:0] row1 [0:2];
reg [DATA_WIDTH-1:0] row2 [0:2];
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
row0[0] <= 0; row0[1] <= 0; row0[2] <= 0;
row1[0] <= 0; row1[1] <= 0; row1[2] <= 0;
row2[0] <= 0; row2[1] <= 0; row2[2] <= 0;
end else if (valid_d2) begin
row0[0] <= row0[1]; row0[1] <= row0[2];
row1[0] <= row1[1]; row1[1] <= row1[2];
row2[0] <= row2[1]; row2[1] <= row2[2];
row0[2] <= rd_data_1;
row1[2] <= rd_data_0;
row2[2] <= data_in_d2;
end
end
// =========================================================================
// ★ 修正版:对齐时序的边界处理
// =========================================================================
// 1. 基于输入像素的原始坐标
reg [10:0] x_cnt_in, y_cnt_in;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
x_cnt_in <= 0; y_cnt_in <= 0;
end else if (data_in_valid) begin
if (x_cnt_in == H_PIXEL - 1) begin
x_cnt_in <= 0; y_cnt_in <= y_cnt_in + 1;
end else begin
x_cnt_in <= x_cnt_in + 1;
end
end else if (frame_vsync) begin
x_cnt_in <= 0; y_cnt_in <= 0;
end
end
// 2. 将坐标延迟 3 拍,与输出的 win_data 严格对齐
reg [10:0] x_cnt_d1, x_cnt_d2, x_cnt_d3;
reg [10:0] y_cnt_d1, y_cnt_d2, y_cnt_d3;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
x_cnt_d1 <= 0; x_cnt_d2 <= 0; x_cnt_d3 <= 0;
y_cnt_d1 <= 0; y_cnt_d2 <= 0; y_cnt_d3 <= 0;
end else begin
x_cnt_d1 <= x_cnt_in; x_cnt_d2 <= x_cnt_d1; x_cnt_d3 <= x_cnt_d2;
y_cnt_d1 <= y_cnt_in; y_cnt_d2 <= y_cnt_d1; y_cnt_d3 <= y_cnt_d2;
end
end
// 3. 判断是否处于无效边界(使用对齐后的坐标)
wire border_invalid = (y_cnt_d3 < 2) || (x_cnt_d3 < 2);
// 4. 窗口数据输出
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
window_valid <= 1'b0;
win_data_00 <= 0; win_data_01 <= 0; win_data_02 <= 0;
win_data_10 <= 0; win_data_11 <= 0; win_data_12 <= 0;
win_data_20 <= 0; win_data_21 <= 0; win_data_22 <= 0;
end else begin
// 时序严格保持一致,保护视频流不断流
window_valid <= valid_d3;
if (border_invalid) begin
// 强制清 0,消灭边界假数据
win_data_00 <= 8'h00; win_data_01 <= 8'h00; win_data_02 <= 8'h00;
win_data_10 <= 8'h00; win_data_11 <= 8'h00; win_data_12 <= 8'h00;
win_data_20 <= 8'h00; win_data_21 <= 8'h00; win_data_22 <= 8'h00;
end else begin
// 正常区域,输出真实窗口数据
win_data_00 <= row0[0]; win_data_01 <= row0[1]; win_data_02 <= row0[2];
win_data_10 <= row1[0]; win_data_11 <= row1[1]; win_data_12 <= row1[2];
win_data_20 <= row2[0]; win_data_21 <= row2[1]; win_data_22 <= row2[2];
end
end
end
endmodule