cache module
This commit is contained in:
85
rtl/data_cache/async_fifo.v
Normal file
85
rtl/data_cache/async_fifo.v
Normal file
@@ -0,0 +1,85 @@
|
||||
module async_fifo #(
|
||||
parameter DATA_WIDTH = 8,
|
||||
parameter FIFO_DEPTH = 16
|
||||
)(
|
||||
input wr_clk,
|
||||
input wr_rst_n,
|
||||
input wr_en,
|
||||
input [DATA_WIDTH-1:0] wr_data,
|
||||
output full,
|
||||
|
||||
input rd_clk,
|
||||
input rd_rst_n,
|
||||
input rd_en,
|
||||
output [DATA_WIDTH-1:0] rd_data,
|
||||
output empty
|
||||
);
|
||||
|
||||
reg [DATA_WIDTH-1:0] mem [FIFO_DEPTH -1 : 0];
|
||||
reg [$clog2(FIFO_DEPTH) : 0] wr_ptr, rd_ptr;
|
||||
|
||||
integer i;
|
||||
always@(posedge wr_clk or negedge wr_rst_n) begin
|
||||
if(!wr_rst_n) begin
|
||||
wr_ptr <= 'd0;
|
||||
for(i=0;i<FIFO_DEPTH;i=i+1) begin
|
||||
mem[i] <= 'd0;
|
||||
end
|
||||
end else if(wr_en && !full) begin
|
||||
mem[wr_ptr[$clog2(FIFO_DEPTH)-1:0]] <= wr_data;
|
||||
wr_ptr <= wr_ptr + 1'b1;
|
||||
end else begin
|
||||
wr_ptr <= wr_ptr;
|
||||
end
|
||||
end
|
||||
|
||||
always@(posedge rd_clk or negedge rd_rst_n) begin
|
||||
if(!rd_rst_n) begin
|
||||
rd_ptr <= 'd0;
|
||||
end else if(rd_en && !empty) begin
|
||||
rd_ptr <= rd_ptr + 1'b1;
|
||||
end else begin
|
||||
rd_ptr <= rd_ptr;
|
||||
end
|
||||
end
|
||||
|
||||
wire [$clog2(FIFO_DEPTH):0] wr_ptr_g , rd_ptr_g;
|
||||
|
||||
assign wr_ptr_g = wr_ptr ^(wr_ptr >>1);
|
||||
assign rd_ptr_g = rd_ptr ^(rd_ptr >>1);
|
||||
|
||||
reg [$clog2(FIFO_DEPTH):0] wr_ptr_gr , wr_ptr_grr;
|
||||
reg [$clog2(FIFO_DEPTH):0] rd_ptr_gr , rd_ptr_grr;
|
||||
|
||||
always@(posedge rd_clk or negedge rd_rst_n) begin
|
||||
if(!rd_rst_n) begin
|
||||
wr_ptr_gr <= 0;
|
||||
wr_ptr_grr <=0;
|
||||
end else begin
|
||||
wr_ptr_gr <= wr_ptr_g;
|
||||
wr_ptr_grr <= wr_ptr_gr;
|
||||
end
|
||||
end
|
||||
|
||||
always@(posedge wr_clk or negedge wr_rst_n) begin
|
||||
if(!wr_rst_n) begin
|
||||
rd_ptr_gr <= 0;
|
||||
rd_ptr_grr <=0;
|
||||
end else begin
|
||||
rd_ptr_gr <= rd_ptr_g;
|
||||
rd_ptr_grr <= rd_ptr_gr;
|
||||
end
|
||||
end
|
||||
|
||||
assign rd_data = mem[rd_ptr[$clog2(FIFO_DEPTH)-1:0]];
|
||||
|
||||
|
||||
assign full = ((wr_ptr_g[$clog2(FIFO_DEPTH)] !=
|
||||
rd_ptr_grr[$clog2(FIFO_DEPTH)]) && (wr_ptr_g[$clog2(FIFO_DEPTH)-1] !=
|
||||
rd_ptr_grr[$clog2(FIFO_DEPTH)]-1) && (wr_ptr_g[$clog2(FIFO_DEPTH)-2:0] ==
|
||||
rd_ptr_grr[$clog2(FIFO_DEPTH)-2 : 0])) ? 1:0;
|
||||
|
||||
assign empty = (rd_ptr_g[$clog2(FIFO_DEPTH) : 0] ==
|
||||
wr_ptr_grr[$clog2(FIFO_DEPTH) :0]) ? 1:0;
|
||||
|
||||
endmodule
|
196
rtl/data_cache/axi_write_ctrl.v
Normal file
196
rtl/data_cache/axi_write_ctrl.v
Normal file
@@ -0,0 +1,196 @@
|
||||
module axi_write_ctrl #(
|
||||
parameter AXI_ID_W = 8, // AXI ID位宽
|
||||
parameter AXI_ADDR_W = 32, // AXI地址位宽
|
||||
parameter AXI_DATA_W = 256, // AXI数据位宽
|
||||
parameter AXI_STRB_W = AXI_DATA_W / 8 // 字节选通位宽(256bit对应32字节)
|
||||
) (
|
||||
input wire clk, // 系统时钟
|
||||
input wire rst_n, // 异步复位,低有效
|
||||
|
||||
// 控制与数据输入
|
||||
input wire start_en, // 写事务启动使能
|
||||
input wire [AXI_ADDR_W-1:0] sram_base_addr, // SRAM基地址
|
||||
input wire [AXI_DATA_W-1:0] fifo_rd_data, // FIFO读数据
|
||||
input wire fifo_empty, // FIFO空标志
|
||||
output reg fifo_rd_en, // FIFO读使能
|
||||
|
||||
// AXI AW通道
|
||||
output reg [AXI_ID_W-1:0] axi_m_awid, // 写地址ID
|
||||
output reg [AXI_ADDR_W-1:0] axi_m_awaddr, // 写地址
|
||||
output reg [3:0] axi_m_awlen, // 突发长度(0表示1个数据)
|
||||
output reg [2:0] axi_m_awsize, // 数据宽度(5对应32字节)
|
||||
output reg [1:0] axi_m_awburst, // 突发类型(0表示增量)
|
||||
output reg axi_m_awlock, // 锁定信号(0表示普通访问)
|
||||
output reg [4:0] axi_m_awcache, // 缓存属性(0表示非缓存)
|
||||
output reg [2:0] axi_m_awprot, // 保护属性(0表示普通)
|
||||
output reg [4:0] axi_m_awqos, // QoS优先级(0表示默认)
|
||||
output reg axi_m_awvalid, // 写地址有效
|
||||
input wire axi_m_awready, // 写地址就绪
|
||||
|
||||
// AXI W通道
|
||||
output reg [AXI_ID_W-1:0] axi_m_wid, // 写数据ID
|
||||
output reg [AXI_DATA_W-1:0] axi_m_wdata, // 写数据
|
||||
output reg [AXI_STRB_W-1:0] axi_m_wstrb, // 字节选通(全1表示所有字节有效)
|
||||
output reg axi_m_wlast, // 突发结束标志
|
||||
output reg axi_m_wvalid, // 写数据有效
|
||||
input wire axi_m_wready, // 写数据就绪
|
||||
|
||||
// AXI B通道
|
||||
input wire [AXI_ID_W-1:0] axi_m_bid, // 写响应ID
|
||||
input wire [1:0] axi_m_bresp, // 写响应(0表示OKAY)
|
||||
input wire axi_m_bvalid, // 写响应有效
|
||||
output reg axi_m_bready, // 写响应就绪
|
||||
|
||||
// 状态输出
|
||||
output reg axi_busy, // AXI写事务忙
|
||||
output reg axi_done // AXI写事务完成
|
||||
);
|
||||
|
||||
// 内部信号定义
|
||||
reg [AXI_ADDR_W-1:0] curr_addr; // 当前写地址(基于基地址递增)
|
||||
reg [1:0] axi_state; // AXI状态机状态寄存器
|
||||
|
||||
// 状态定义
|
||||
localparam AXI_IDLE = 2'd0; // 空闲状态
|
||||
localparam AXI_AW = 2'd1; // 地址通道传输状态
|
||||
localparam AXI_W = 2'd2; // 数据通道传输状态
|
||||
localparam AXI_B = 2'd3; // 响应通道传输状态
|
||||
|
||||
// 1. AXI状态机时序逻辑
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
axi_state <= AXI_IDLE;
|
||||
curr_addr <= {AXI_ADDR_W{1'b0}};
|
||||
axi_busy <= 1'b0;
|
||||
axi_done <= 1'b0;
|
||||
end else begin
|
||||
axi_done <= 1'b0; // 单周期有效
|
||||
case (axi_state)
|
||||
AXI_IDLE: begin
|
||||
axi_busy <= 1'b0;
|
||||
// 启动条件: 使能信号有效且FIFO非空
|
||||
if (start_en && !fifo_empty) begin
|
||||
axi_state <= AXI_AW;
|
||||
axi_busy <= 1'b1;
|
||||
// 初始化当前地址为基地址(首次)或保持上次地址(连续传输)
|
||||
curr_addr <= (curr_addr == {AXI_ADDR_W{1'b0}}) ? sram_base_addr : curr_addr;
|
||||
end
|
||||
end
|
||||
|
||||
AXI_AW: begin
|
||||
// 地址通道握手完成,进入数据通道
|
||||
if (axi_m_awvalid && axi_m_awready) begin
|
||||
axi_state <= AXI_W;
|
||||
// 预计算下一次地址(当前地址 + 数据宽度字节数)
|
||||
curr_addr <= curr_addr + (AXI_DATA_W / 8);
|
||||
end
|
||||
end
|
||||
|
||||
AXI_W: begin
|
||||
// 数据通道握手完成,进入响应通道
|
||||
if (axi_m_wvalid && axi_m_wready) begin
|
||||
axi_state <= AXI_B;
|
||||
end
|
||||
end
|
||||
|
||||
AXI_B: begin
|
||||
// 响应通道握手完成,事务结束
|
||||
if (axi_m_bvalid && axi_m_bready) begin
|
||||
axi_state <= AXI_IDLE;
|
||||
axi_done <= 1'b1; // 标记事务完成
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// 2. AXI AW通道信号生成逻辑
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
axi_m_awid <= {AXI_ID_W{1'b0}};
|
||||
axi_m_awaddr <= {AXI_ADDR_W{1'b0}};
|
||||
axi_m_awlen <= 4'd0;
|
||||
axi_m_awsize <= 3'd5; // 5对应32字节(2^5 = 32)
|
||||
axi_m_awburst <= 2'd0; // 0表示INCR(增量)突发
|
||||
axi_m_awlock <= 1'b0;
|
||||
axi_m_awcache <= 5'd0; // 非缓存、非缓冲
|
||||
axi_m_awprot <= 3'd0; // 普通非特权数据访问
|
||||
axi_m_awqos <= 5'd0; // 默认QoS级别
|
||||
axi_m_awvalid <= 1'b0;
|
||||
end else begin
|
||||
case (axi_state)
|
||||
AXI_AW: begin
|
||||
axi_m_awid <= 8'd0; // 固定ID为0
|
||||
axi_m_awaddr <= curr_addr; // 当前地址
|
||||
axi_m_awlen <= 4'd0; // 突发长度为1(0+1)
|
||||
axi_m_awsize <= 3'd5; // 保持32字节宽度
|
||||
axi_m_awburst <= 2'd0; // 保持增量突发
|
||||
axi_m_awvalid <= 1'b1; // 地址有效
|
||||
end
|
||||
default: begin
|
||||
axi_m_awvalid <= 1'b0; // 非地址状态时无效
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// 3. AXI W通道信号生成逻辑
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
axi_m_wid <= {AXI_ID_W{1'b0}};
|
||||
axi_m_wdata <= {AXI_DATA_W{1'b0}};
|
||||
axi_m_wstrb <= {AXI_STRB_W{1'b1}}; // 所有字节有效
|
||||
axi_m_wlast <= 1'b1; // 单拍突发,始终为1
|
||||
axi_m_wvalid <= 1'b0;
|
||||
fifo_rd_en <= 1'b0;
|
||||
end else begin
|
||||
case (axi_state)
|
||||
AXI_AW: begin
|
||||
// 地址握手完成前预读FIFO
|
||||
if (axi_m_awready) begin
|
||||
fifo_rd_en <= 1'b1; // 读取FIFO数据
|
||||
axi_m_wid <= 8'd0; // 与AW通道ID保持一致
|
||||
axi_m_wdata <= fifo_rd_data; // 锁存FIFO数据
|
||||
axi_m_wvalid <= 1'b1; // 数据有效
|
||||
end else begin
|
||||
fifo_rd_en <= 1'b0;
|
||||
axi_m_wvalid <= 1'b0;
|
||||
end
|
||||
end
|
||||
AXI_W: begin
|
||||
fifo_rd_en <= 1'b0; // 停止读FIFO
|
||||
// 数据握手完成后失效
|
||||
if (axi_m_wready) begin
|
||||
axi_m_wvalid <= 1'b0;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
fifo_rd_en <= 1'b0;
|
||||
axi_m_wvalid <= 1'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// 4. AXI B通道信号生成逻辑
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
axi_m_bready <= 1'b0;
|
||||
end else begin
|
||||
case (axi_state)
|
||||
AXI_B: begin
|
||||
axi_m_bready <= 1'b1; // 准备接收响应
|
||||
// 响应握手完成后失效
|
||||
if (axi_m_bvalid) begin
|
||||
axi_m_bready <= 1'b0;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
axi_m_bready <= 1'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
109
rtl/data_cache/data_assemble.v
Normal file
109
rtl/data_cache/data_assemble.v
Normal file
@@ -0,0 +1,109 @@
|
||||
module data_assemble #(
|
||||
parameter PIXEL_WIDTH = 8, // 单通道像素位宽
|
||||
parameter GRAY_PIXEL_CNT = 32, // Gray模式:32个8bit→256bit
|
||||
parameter RGB_PIXEL_CNT = 8 // RGB模式:8个32bit(24bit数据+8bit补零)→256bit
|
||||
) (
|
||||
input wire clk,
|
||||
input wire rst_n,
|
||||
input wire en, // 拼接使能
|
||||
input wire input_pixel_type, // 0=Gray,1=RGB
|
||||
input wire [PIXEL_WIDTH-1:0] ir_ch0, // CH0数据
|
||||
input wire [PIXEL_WIDTH-1:0] ir_ch1, // CH1数据
|
||||
input wire [PIXEL_WIDTH-1:0] ir_ch2, // CH2数据
|
||||
input wire pixel_valid, // 像素有效
|
||||
output reg done, // 拼接完成(256bit就绪)
|
||||
output reg [255:0] assembled_data // 拼接后256bit数据
|
||||
);
|
||||
|
||||
// 内部信号
|
||||
reg [4:0] gray_cnt; // Gray模式计数器(0~31)
|
||||
reg [2:0] rgb_cnt; // RGB模式计数器(0~7)
|
||||
reg [255:0] data_reg; // 拼接数据寄存器
|
||||
reg sync_out,sync_out_r;
|
||||
|
||||
|
||||
// 拼接计数器复位逻辑
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
gray_cnt <= 5'd0;
|
||||
rgb_cnt <= 3'd0;
|
||||
end else if (!en) begin
|
||||
gray_cnt <= 5'd0;
|
||||
rgb_cnt <= 3'd0;
|
||||
end else if (pixel_valid) begin
|
||||
case (input_pixel_type)
|
||||
1'b0: begin // Gray模式
|
||||
gray_cnt <= (gray_cnt == GRAY_PIXEL_CNT ) ? 5'd0 : gray_cnt + 5'd1;
|
||||
end
|
||||
1'b1: begin // RGB模式
|
||||
rgb_cnt <= (rgb_cnt == RGB_PIXEL_CNT ) ? 3'd0 : rgb_cnt + 3'd1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// 数据拼接逻辑
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
data_reg <= 256'd0;
|
||||
assembled_data <= 256'd0;
|
||||
sync_out <= 'd0;
|
||||
sync_out_r <= 'd0;
|
||||
end else if (!en) begin
|
||||
sync_out <= 'd0;
|
||||
data_reg <= 256'd0;
|
||||
assembled_data <= 256'd0;
|
||||
done <= 'd0;
|
||||
end else if (pixel_valid) begin
|
||||
|
||||
case (input_pixel_type)
|
||||
1'b0: begin // Gray模式:32x8bit→256bit(高位到低位拼接)
|
||||
data_reg[(GRAY_PIXEL_CNT -1- gray_cnt) * PIXEL_WIDTH +: PIXEL_WIDTH] <= ir_ch0;
|
||||
// 计数器满:拼接完成,锁存数据
|
||||
if (gray_cnt == GRAY_PIXEL_CNT -1 ) begin
|
||||
sync_out = 1'd1;
|
||||
//data_reg <= 256'd0; // 复位寄存器,准备下一轮
|
||||
end
|
||||
end
|
||||
1'b1: begin // RGB模式:8x32bit→256bit(32bit=8bit补零+CH2+CH1+CH0)
|
||||
reg [31:0] rgb_pixel;
|
||||
rgb_pixel = {8'd0, ir_ch2, ir_ch1, ir_ch0}; // 补零+三通道数据
|
||||
data_reg[(RGB_PIXEL_CNT - 1 - rgb_cnt) * 32 +: 32] <= rgb_pixel;
|
||||
// 计数器满:拼接完成,锁存数据
|
||||
if (gray_cnt == GRAY_PIXEL_CNT -1 ) begin
|
||||
sync_out = 1'd1;
|
||||
//data_reg <= 256'd0; // 复位寄存器,准备下一轮
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
sync_out_r <= 'd0;
|
||||
end else begin
|
||||
sync_out_r <= sync_out;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
assembled_data <= 'd0;
|
||||
done <= 'd0;
|
||||
end else if (sync_out_r) begin
|
||||
assembled_data <= data_reg;
|
||||
done <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (done == 1'b1) begin
|
||||
done <= 'd0;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
470
rtl/data_cache/data_cache.v
Normal file
470
rtl/data_cache/data_cache.v
Normal file
@@ -0,0 +1,470 @@
|
||||
module data_cache #(
|
||||
// 异步FIFO参数(IR→系统时钟域)
|
||||
parameter ASYNC_FIFO_DEPTH = 1024, // 异步FIFO深度
|
||||
parameter ASYNC_FIFO_DATA_W = 27, // 27bit=1(ir_valid)+1(ir_vs)+1(ir_hs)+8(ch0)+8(ch1)+8(ch2)
|
||||
// 同步FIFO参数(系统时钟域,256bit数据缓存)
|
||||
parameter SYNC_FIFO_DEPTH = 2048, // 同步FIFO深度(适配256x256图像)
|
||||
parameter SYNC_FIFO_DATA_W = 256, // 同步FIFO数据位宽(AXI写数据位宽)
|
||||
// 直方图RAM参数(1x256,每个通道1个)
|
||||
parameter HIST_RAM_DEPTH = 256, // 直方图RAM深度(0~255,对应8bit像素值)
|
||||
parameter HIST_RAM_DATA_W = 1, // 直方图RAM数据位宽(1bit:存在标记)
|
||||
// AXI参数
|
||||
parameter AXI_ID_W = 8, // AXI AW/W ID位宽
|
||||
parameter AXI_ADDR_W = 32, // AXI地址位宽
|
||||
parameter AXI_DATA_W = 256, // AXI数据位宽(与SYNC_FIFO_DATA_W一致)
|
||||
parameter AXI_STRB_W = AXI_DATA_W / 8 // AXI WSTRB位宽(32bit)
|
||||
) (
|
||||
// -------------------------- Common 端口 --------------------------
|
||||
input wire clk, // 系统时钟(AXI/控制逻辑时钟)
|
||||
input wire rst_n, // 系统复位(低有效,同步clk)
|
||||
// -------------------------- 配置信号端口 --------------------------
|
||||
input wire ipa_en, // IPA总使能
|
||||
input wire update_src_trig, // 更新原始图像触发(高有效)
|
||||
input wire input_pixel_type, // 输入像素类型:0=Gray,1=RGB
|
||||
input wire [15:0] src_pixel_height, // 原始图像高度
|
||||
input wire [15:0] src_pixel_width, // 原始图像宽度
|
||||
input wire [15:0] histogram_low_num, // 直方图低位数(计算min用)
|
||||
input wire [15:0] histogram_high_num, // 直方图高位数(计算max用)
|
||||
output reg src_image_cache_done, // 原始图像缓存完成(高有效)
|
||||
// -------------------------- 连接Windowed模块端口 --------------------------
|
||||
output reg [7:0] dwidth_conv_min_ch0, // CH0归一化min值
|
||||
output reg [7:0] dwidth_conv_max_ch0, // CH0归一化max值
|
||||
output reg [7:0] dwidth_conv_min_ch1, // CH1归一化min值
|
||||
output reg [7:0] dwidth_conv_max_ch1, // CH1归一化max值
|
||||
output reg [7:0] dwidth_conv_min_ch2, // CH2归一化min值
|
||||
output reg [7:0] dwidth_conv_max_ch2, // CH2归一化max值
|
||||
// -------------------------- IR图像输入端口(IR时钟域) --------------------------
|
||||
input wire ir_clk, // IR像素同步时钟
|
||||
input wire ir_valid, // IR像素有效信号
|
||||
input wire ir_vs, // IR垂直同步(帧起始)
|
||||
input wire ir_hs, // IR水平同步(行起始)
|
||||
input wire [7:0] ir_ch0, // IR CH0数据(Gray时有效)
|
||||
input wire [7:0] ir_ch1, // IR CH1数据(RGB时有效)
|
||||
input wire [7:0] ir_ch2, // IR CH2数据(RGB时有效)
|
||||
// -------------------------- AXI写总线端口(系统时钟域) --------------------------
|
||||
output reg [AXI_ID_W-1:0] axi_m_awid, // AXI AW通道ID
|
||||
output reg [AXI_ADDR_W-1:0] axi_m_awaddr, // AXI AW通道地址(SRAM起始地址)
|
||||
output reg [3:0] axi_m_awlen, // AXI AW通道突发长度(0=1拍)
|
||||
output reg [2:0] axi_m_awsize, // AXI AW通道数据宽度(5=32字节=256bit)
|
||||
output reg [1:0] axi_m_awburst, // AXI AW通道突发类型(0=INCR)
|
||||
output reg axi_m_awlock, // AXI AW通道锁定(0=普通)
|
||||
output reg [3:0] axi_m_awcache, // AXI AW通道缓存属性(0=非缓存)
|
||||
output reg [2:0] axi_m_awprot, // AXI AW通道保护属性(0=普通)
|
||||
output reg [3:0] axi_m_awqos, // AXI AW通道QoS(0=默认)
|
||||
output reg axi_m_awvalid, // AXI AW通道有效
|
||||
input wire axi_m_awready, // AXI AW通道就绪
|
||||
output reg [AXI_ID_W-1:0] axi_m_wid, // AXI W通道ID(与AW一致)
|
||||
output reg [AXI_DATA_W-1:0] axi_m_wdata, // AXI W通道数据(256bit)
|
||||
output reg [AXI_STRB_W-1:0] axi_m_wstrb, // AXI W通道字节使能(全1=有效)
|
||||
output reg axi_m_wlast, // AXI W通道突发结束标记
|
||||
output reg axi_m_wvalid, // AXI W通道有效
|
||||
input wire axi_m_wready, // AXI W通道就绪
|
||||
input wire [AXI_ID_W-1:0] axi_m_bid, // AXI B通道ID
|
||||
input wire [1:0] axi_m_bresp, // AXI B通道响应(0=OKAY)
|
||||
input wire axi_m_bvalid, // AXI B通道有效
|
||||
output reg axi_m_bready // AXI B通道就绪
|
||||
);
|
||||
|
||||
// -------------------------- 内部信号定义 --------------------------
|
||||
// 1. 复位同步(跨时钟域复位处理)
|
||||
wire rst_n_ir; // IR时钟域同步后的复位
|
||||
wire rst_n_sys; // 系统时钟域同步后的复位
|
||||
|
||||
// 2. 异步FIFO信号(IR→系统时钟域)
|
||||
wire async_fifo_wr_en; // 异步FIFO写使能(IR时钟域)
|
||||
wire [ASYNC_FIFO_DATA_W-1:0] async_fifo_wr_data; // 异步FIFO写数据(IR时钟域)
|
||||
wire async_fifo_full; // 异步FIFO满(IR时钟域)
|
||||
wire async_fifo_rd_en; // 异步FIFO读使能(系统时钟域)
|
||||
wire [ASYNC_FIFO_DATA_W-1:0] async_fifo_rd_data; // 异步FIFO读数据(系统时钟域)
|
||||
wire async_fifo_empty; // 异步FIFO空(系统时钟域)
|
||||
|
||||
// 3. 跨域后像素信号(系统时钟域)
|
||||
wire ir_valid_sys; // 跨域后像素有效
|
||||
wire ir_vs_sys; // 跨域后帧起始
|
||||
wire ir_hs_sys; // 跨域后行起始
|
||||
wire [7:0] ir_ch0_sys; // 跨域后CH0数据
|
||||
wire [7:0] ir_ch1_sys; // 跨域后CH1数据
|
||||
wire [7:0] ir_ch2_sys; // 跨域后CH2数据
|
||||
reg flag;
|
||||
|
||||
// 4. 直方图控制信号
|
||||
wire hist_rst; // 直方图RAM复位(帧起始/更新触发)
|
||||
wire hist_wr_en_ch0; // CH0直方图写使能
|
||||
wire [7:0] hist_wr_addr_ch0; // CH0直方图写地址(像素值)
|
||||
wire hist_wr_en_ch1; // CH1直方图写使能
|
||||
wire [7:0] hist_wr_addr_ch1; // CH1直方图写地址(像素值)
|
||||
wire hist_wr_en_ch2; // CH2直方图写使能
|
||||
wire [7:0] hist_wr_addr_ch2; // CH2直方图写地址(像素值)
|
||||
reg hist_calc_en; // 直方图min/max计算使能(帧结束后)
|
||||
wire hist_calc_done; // 直方图min/max计算完成
|
||||
|
||||
// 5. 数据拼接信号
|
||||
wire assemble_en; // 数据拼接使能
|
||||
wire assemble_done; // 数据拼接完成(256bit就绪)
|
||||
wire [255:0] assemble_data; // 拼接后256bit数据
|
||||
|
||||
// 6. 同步FIFO信号(系统时钟域)
|
||||
wire sync_fifo_wr_en; // 同步FIFO写使能
|
||||
wire [255:0] sync_fifo_wr_data;// 同步FIFO写数据(拼接后256bit)
|
||||
wire sync_fifo_full; // 同步FIFO满
|
||||
wire sync_fifo_rd_en; // 同步FIFO读使能
|
||||
wire [255:0] sync_fifo_rd_data;// 同步FIFO读数据
|
||||
wire sync_fifo_empty; // 同步FIFO空
|
||||
|
||||
// 7. 帧计数与状态信号
|
||||
reg [15:0] col_cnt; // 列计数器(像素宽度计数)
|
||||
reg [15:0] row_cnt; // 行计数器(像素高度计数)
|
||||
reg frame_active; // 帧活跃标记(IR_VS后到帧结束)
|
||||
reg axi_write_busy; // AXI写事务忙标记
|
||||
wire axi_write_done; // 来自 axi_write_ctrl 的写完成标志
|
||||
|
||||
// 8. 状态机定义
|
||||
// typedef enum logic [2:0] {
|
||||
// S_IDLE, // 空闲(等待IPA使能)
|
||||
// S_WAIT_VS, // 等待帧起始(IR_VS)
|
||||
// S_RECEIVE_DATA, // 接收像素数据(写直方图+拼接)
|
||||
// S_WRITE_FIFO, // 拼接完成写同步FIFO
|
||||
// S_WAIT_AXI, // 等待AXI写完成
|
||||
// S_FRAME_DONE // 帧缓存完成(置位src_image_cache_done)
|
||||
// } data_cache_state_t;
|
||||
|
||||
localparam [3:0] S_IDLE = 3'b000;
|
||||
localparam [3:0] S_WAIT_VS = 3'b001;
|
||||
localparam [3:0] S_RECEIVE_DATA = 3'b010;
|
||||
localparam [3:0] S_WRITE_FIFO = 3'b011;
|
||||
localparam [3:0] S_WAIT_AXI = 3'b100;
|
||||
localparam [3:0] S_FRAME_DONE = 3'b101;
|
||||
|
||||
reg [2:0] curr_state;
|
||||
reg [2:0] next_state;
|
||||
|
||||
|
||||
// -------------------------- 子模块实例化 --------------------------
|
||||
// 1. 复位同步(确保跨时钟域复位稳定)
|
||||
rst_sync #(
|
||||
.SYNC_STAGE(2) // 2级同步
|
||||
) u_rst_sync_ir (
|
||||
.clk(ir_clk),
|
||||
.rst_n_in(rst_n),
|
||||
.rst_n_out(rst_n_ir)
|
||||
);
|
||||
|
||||
rst_sync #(
|
||||
.SYNC_STAGE(2)
|
||||
) u_rst_sync_sys (
|
||||
.clk(clk),
|
||||
.rst_n_in(rst_n),
|
||||
.rst_n_out(rst_n_sys)
|
||||
);
|
||||
|
||||
// 2. 异步FIFO(IR时钟域→系统时钟域,传输像素数据+控制信号)
|
||||
async_fifo #(
|
||||
.FIFO_DEPTH(ASYNC_FIFO_DEPTH),
|
||||
.DATA_WIDTH(ASYNC_FIFO_DATA_W)
|
||||
) u_async_fifo (
|
||||
// 写端口(IR时钟域)
|
||||
.wr_clk(ir_clk),
|
||||
.wr_rst_n(rst_n_ir),
|
||||
.wr_en(async_fifo_wr_en),
|
||||
.wr_data(async_fifo_wr_data),
|
||||
.full(async_fifo_full),
|
||||
// 读端口(系统时钟域)
|
||||
.rd_clk(clk),
|
||||
.rd_rst_n(rst_n_sys),
|
||||
.rd_en(async_fifo_rd_en),
|
||||
.rd_data(async_fifo_rd_data),
|
||||
.empty(async_fifo_empty)
|
||||
);
|
||||
|
||||
// 3. 直方图控制模块(统计CH0/CH1/CH2直方图,计算min/max)
|
||||
histogram_ctrl #(
|
||||
.HIST_RAM_DEPTH(HIST_RAM_DEPTH),
|
||||
.HIST_RAM_DATA_W(HIST_RAM_DATA_W)
|
||||
) u_histogram_ctrl (
|
||||
.clk(clk),
|
||||
.rst_n(rst_n_sys),
|
||||
.hist_rst(hist_rst),
|
||||
.input_pixel_type(input_pixel_type),
|
||||
.hist_wr_en_ch0(hist_wr_en_ch0),
|
||||
.hist_wr_addr_ch0(hist_wr_addr_ch0),
|
||||
.hist_wr_en_ch1(hist_wr_en_ch1),
|
||||
.hist_wr_addr_ch1(hist_wr_addr_ch1),
|
||||
.hist_wr_en_ch2(hist_wr_en_ch2),
|
||||
.hist_wr_addr_ch2(hist_wr_addr_ch2),
|
||||
.histogram_low_num(histogram_low_num),
|
||||
.histogram_high_num(histogram_high_num),
|
||||
.calc_en(hist_calc_en),
|
||||
.calc_done(hist_calc_done),
|
||||
.dwidth_conv_min_ch0(dwidth_conv_min_ch0),
|
||||
.dwidth_conv_max_ch0(dwidth_conv_max_ch0),
|
||||
.dwidth_conv_min_ch1(dwidth_conv_min_ch1),
|
||||
.dwidth_conv_max_ch1(dwidth_conv_max_ch1),
|
||||
.dwidth_conv_min_ch2(dwidth_conv_min_ch2),
|
||||
.dwidth_conv_max_ch2(dwidth_conv_max_ch2)
|
||||
);
|
||||
|
||||
// 4. 数据拼接模块(Gray:32x8bit→256bit;RGB:8x32bit→256bit)
|
||||
data_assemble #(
|
||||
.PIXEL_WIDTH(8), // 单通道像素位宽
|
||||
.GRAY_PIXEL_CNT(32), // Gray模式拼接像素数(32x8bit=256bit)
|
||||
.RGB_PIXEL_CNT(8) // RGB模式拼接像素数(8x32bit=256bit)
|
||||
) u_data_assemble (
|
||||
.clk(clk),
|
||||
.rst_n(rst_n_sys),
|
||||
.en(assemble_en),
|
||||
.input_pixel_type(input_pixel_type),
|
||||
.ir_ch0(ir_ch0_sys),
|
||||
.ir_ch1(ir_ch1_sys),
|
||||
.ir_ch2(ir_ch2_sys),
|
||||
.pixel_valid(async_fifo_rd_data[26]),
|
||||
.done(assemble_done),
|
||||
.assembled_data(assemble_data)
|
||||
);
|
||||
|
||||
// 5. 同步FIFO(缓存拼接后的256bit数据,适配AXI写速度)
|
||||
sync_fifo #(
|
||||
.FIFO_DEPTH(SYNC_FIFO_DEPTH),
|
||||
.DATA_WIDTH(SYNC_FIFO_DATA_W)
|
||||
) u_sync_fifo (
|
||||
.clk(clk),
|
||||
.rst_n(rst_n_sys),
|
||||
.wr_en(sync_fifo_wr_en),
|
||||
.wr_data(sync_fifo_wr_data),
|
||||
.full(sync_fifo_full),
|
||||
.rd_en(sync_fifo_rd_en),
|
||||
.rd_data(sync_fifo_rd_data),
|
||||
.empty(sync_fifo_empty)
|
||||
);
|
||||
|
||||
// 6. AXI写控制模块(从同步FIFO读数据,发起AXI写事务)
|
||||
axi_write_ctrl #(
|
||||
.AXI_ID_W(AXI_ID_W),
|
||||
.AXI_ADDR_W(AXI_ADDR_W),
|
||||
.AXI_DATA_W(AXI_DATA_W),
|
||||
.AXI_STRB_W(AXI_STRB_W)
|
||||
) u_axi_write_ctrl (
|
||||
.clk(clk),
|
||||
.rst_n(rst_n_sys),
|
||||
.start_en(!sync_fifo_empty && !axi_write_busy), // FIFO非空且AXI空闲时启动
|
||||
.sram_base_addr(32'h0000_0000), // SRAM基地址(可配置)
|
||||
.fifo_rd_data(sync_fifo_rd_data),
|
||||
.fifo_empty(sync_fifo_empty),
|
||||
.fifo_rd_en(sync_fifo_rd_en),
|
||||
.axi_m_awid(axi_m_awid),
|
||||
.axi_m_awaddr(axi_m_awaddr),
|
||||
.axi_m_awlen(axi_m_awlen),
|
||||
.axi_m_awsize(axi_m_awsize),
|
||||
.axi_m_awburst(axi_m_awburst),
|
||||
.axi_m_awlock(axi_m_awlock),
|
||||
.axi_m_awcache(axi_m_awcache),
|
||||
.axi_m_awprot(axi_m_awprot),
|
||||
.axi_m_awqos(axi_m_awqos),
|
||||
.axi_m_awvalid(axi_m_awvalid),
|
||||
.axi_m_awready(axi_m_awready),
|
||||
.axi_m_wid(axi_m_wid),
|
||||
.axi_m_wdata(axi_m_wdata),
|
||||
.axi_m_wstrb(axi_m_wstrb),
|
||||
.axi_m_wlast(axi_m_wlast),
|
||||
.axi_m_wvalid(axi_m_wvalid),
|
||||
.axi_m_wready(axi_m_wready),
|
||||
.axi_m_bid(axi_m_bid),
|
||||
.axi_m_bresp(axi_m_bresp),
|
||||
.axi_m_bvalid(axi_m_bvalid),
|
||||
.axi_m_bready(axi_m_bready),
|
||||
.axi_busy(axi_write_busy),
|
||||
.axi_done(axi_write_done)
|
||||
);
|
||||
|
||||
|
||||
// -------------------------- 核心逻辑实现 --------------------------
|
||||
// assign flag = (col_cnt == src_pixel_width-1'd1);
|
||||
assign axi_write_done = (axi_m_bvalid && axi_m_bready);
|
||||
// 1. 异步FIFO写控制(IR时钟域)
|
||||
assign async_fifo_wr_data = {ir_valid, ir_vs, ir_hs, ir_ch2, ir_ch1, ir_ch0};
|
||||
assign async_fifo_wr_en = ir_valid && !async_fifo_full && ipa_en; // 像素有效且FIFO未满
|
||||
|
||||
// 2. 异步FIFO读控制(系统时钟域)
|
||||
assign async_fifo_rd_en = !async_fifo_empty &&
|
||||
(curr_state == S_WAIT_VS || frame_active) && !flag; // 帧活跃且FIFO非空
|
||||
|
||||
// 3. 跨域后信号解析(系统时钟域)
|
||||
assign ir_valid_sys = async_fifo_rd_data[26] && !flag; // [26] = ir_valid
|
||||
assign ir_vs_sys = async_fifo_rd_data[25]; // [25] = ir_vs
|
||||
assign ir_hs_sys = async_fifo_rd_data[24]; // [24] = ir_hs
|
||||
assign ir_ch2_sys = async_fifo_rd_data[23:16];// [23:16] = ir_ch2
|
||||
assign ir_ch1_sys = async_fifo_rd_data[15:8]; // [15:8] = ir_ch1
|
||||
assign ir_ch0_sys = async_fifo_rd_data[7:0]; // [7:0] = ir_ch0
|
||||
|
||||
// 4. 直方图写控制(系统时钟域)
|
||||
assign hist_rst = update_src_trig || ir_vs_sys; // 更新触发或帧起始时复位直方图
|
||||
assign hist_wr_en_ch0 = ir_valid_sys && frame_active; // CH0始终写(Gray/RGB均有效)
|
||||
assign hist_wr_addr_ch0 = ir_ch0_sys;
|
||||
assign hist_wr_en_ch1 = ir_valid_sys && frame_active && (input_pixel_type == 1'b1); // RGB时写CH1
|
||||
assign hist_wr_addr_ch1 = ir_ch1_sys;
|
||||
assign hist_wr_en_ch2 = ir_valid_sys && frame_active && (input_pixel_type == 1'b1); // RGB时写CH2
|
||||
assign hist_wr_addr_ch2 = ir_ch2_sys;
|
||||
//assign hist_calc_en = (row_cnt == src_pixel_height-1'd1) && (col_cnt == src_pixel_width-1'd1); // 帧结束后计算min/max
|
||||
|
||||
// 5. 数据拼接使能控制
|
||||
assign assemble_en = frame_active && ir_valid_sys && !ir_vs_sys;
|
||||
|
||||
// 6. 同步FIFO写控制
|
||||
assign sync_fifo_wr_en = assemble_done && !sync_fifo_full;
|
||||
assign sync_fifo_wr_data = assemble_data;
|
||||
|
||||
// 7. 帧计数逻辑 - 修复frame_active激活(关键:不依赖frame_active读FIFO)
|
||||
always @(posedge clk or negedge rst_n_sys) begin
|
||||
if (!rst_n_sys) begin
|
||||
col_cnt <= 16'd0;
|
||||
row_cnt <= 16'd0;
|
||||
frame_active <= 1'b0;
|
||||
end else if (update_src_trig) begin
|
||||
col_cnt <= 16'd0;
|
||||
row_cnt <= 16'd0;
|
||||
frame_active <= 1'b0;
|
||||
end else if (ir_vs_sys && curr_state == S_WAIT_VS) begin
|
||||
// WAIT_VS状态下,ir_vs_sys=1 → 激活frame_active
|
||||
col_cnt <= 16'd0;
|
||||
row_cnt <= 16'd0;
|
||||
frame_active <= 1'b1;
|
||||
end else if (curr_state == S_RECEIVE_DATA) begin
|
||||
// RECEIVE_DATA状态下保持frame_active=1,直到帧结束
|
||||
frame_active <= 1'b1;
|
||||
if (ir_valid_sys && !ir_vs_sys) begin
|
||||
col_cnt <= col_cnt + 16'd1;
|
||||
if (col_cnt == src_pixel_width - 16'd1) begin
|
||||
col_cnt <= 16'd0;
|
||||
row_cnt <= row_cnt + 16'd1;
|
||||
if (row_cnt == src_pixel_height - 16'd1) begin
|
||||
frame_active <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
frame_active <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// 8. 状态机时序逻辑
|
||||
always @(posedge clk or negedge rst_n_sys) begin
|
||||
if (!rst_n_sys) begin
|
||||
curr_state <= S_IDLE;
|
||||
end else begin
|
||||
curr_state <= next_state;
|
||||
end
|
||||
end
|
||||
|
||||
// 9. 状态机组合逻辑(状态转移)
|
||||
always @(*) begin
|
||||
next_state = curr_state;
|
||||
case (curr_state)
|
||||
S_IDLE: begin
|
||||
// 等待IPA使能
|
||||
if (ipa_en && !update_src_trig) begin
|
||||
next_state = S_WAIT_VS;
|
||||
end
|
||||
end
|
||||
S_WAIT_VS: begin
|
||||
// 等待帧起始(IR_VS)
|
||||
if (ir_vs_sys) begin
|
||||
next_state = S_RECEIVE_DATA;
|
||||
end else if (update_src_trig) begin
|
||||
next_state = S_IDLE;
|
||||
end
|
||||
end
|
||||
S_RECEIVE_DATA: begin
|
||||
// 接收数据:直到帧结束(行/列计数满)
|
||||
if ((row_cnt == src_pixel_height-1'd1) && (col_cnt == src_pixel_width-1'd1)) begin
|
||||
next_state = S_WRITE_FIFO;
|
||||
end else if (update_src_trig) begin
|
||||
next_state = S_IDLE;
|
||||
end
|
||||
end
|
||||
S_WRITE_FIFO: begin
|
||||
// 条件1:同步FIFO已空(数据已全部读出到AXI控制器),但AXI仍在忙碌 → 等待AXI完成
|
||||
if (sync_fifo_empty && axi_write_busy) begin
|
||||
next_state = S_WAIT_AXI;
|
||||
end
|
||||
// 条件2:同步FIFO已空,且AXI已完成所有写操作 → 直接进入帧完成
|
||||
else if (sync_fifo_empty && !axi_write_busy) begin
|
||||
next_state = S_FRAME_DONE;
|
||||
end
|
||||
// 条件3:收到更新触发 → 强制回到IDLE
|
||||
else if (update_src_trig) begin
|
||||
next_state = S_IDLE;
|
||||
end
|
||||
end
|
||||
S_WAIT_AXI: begin
|
||||
// AXI写完成后进入帧完成状态
|
||||
if (axi_write_done) begin
|
||||
next_state = S_FRAME_DONE;
|
||||
end
|
||||
// 收到更新触发 → 强制回到IDLE
|
||||
else if (update_src_trig) begin
|
||||
next_state = S_IDLE;
|
||||
end
|
||||
end
|
||||
S_FRAME_DONE: begin
|
||||
// 帧完成:保持1拍后回到等待VS(支持连续帧)
|
||||
if (src_image_cache_done) begin
|
||||
next_state = S_WAIT_VS;
|
||||
end else begin
|
||||
next_state = S_FRAME_DONE;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// 10. 状态机输出逻辑(控制各模块行为)
|
||||
always @(posedge clk or negedge rst_n_sys) begin
|
||||
if (!rst_n_sys) begin
|
||||
src_image_cache_done <= 1'b0;
|
||||
end else begin
|
||||
src_image_cache_done <= 1'b0;
|
||||
case (curr_state)
|
||||
S_FRAME_DONE: begin
|
||||
// 帧完成:置位缓存完成信号,并等待直方图计算完成
|
||||
src_image_cache_done <= hist_calc_done;
|
||||
end
|
||||
default: begin
|
||||
src_image_cache_done <= 1'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk or negedge rst_n_sys) begin
|
||||
if (!rst_n_sys) begin
|
||||
hist_calc_en <= 'd0;
|
||||
end else begin
|
||||
hist_calc_en <= (row_cnt == src_pixel_height-1'd1) && (col_cnt == src_pixel_width-1'd1);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
// always @(posedge clk or negedge rst_n_sys) begin
|
||||
// if (!rst_n_sys) begin
|
||||
// assemble_en <= 'd0;
|
||||
// end else begin
|
||||
// assemble_en <= frame_active && ir_valid_sys && !ir_vs_sys;
|
||||
// end
|
||||
|
||||
// end
|
||||
reg [1:0] flag_cnt;
|
||||
always @(posedge clk or negedge rst_n_sys) begin
|
||||
if (!rst_n_sys) begin
|
||||
flag <= 'd0;
|
||||
flag_cnt <='d0;
|
||||
end else if (flag == 1'b1)begin
|
||||
flag_cnt <= flag_cnt + 1'b1;
|
||||
if (flag_cnt == 2'd2) begin
|
||||
flag <= 'd0;
|
||||
flag_cnt <='d0;
|
||||
end
|
||||
end else if (col_cnt == src_pixel_width-1'd1) begin
|
||||
flag <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
231
rtl/data_cache/histogram_ctrl.v
Normal file
231
rtl/data_cache/histogram_ctrl.v
Normal file
@@ -0,0 +1,231 @@
|
||||
module histogram_ctrl #(
|
||||
parameter HIST_RAM_DEPTH = 256,
|
||||
parameter HIST_RAM_DATA_W = 1
|
||||
) (
|
||||
input wire clk,
|
||||
input wire rst_n,
|
||||
input wire hist_rst, // 直方图复位
|
||||
input wire input_pixel_type, // 0=Gray,1=RGB
|
||||
input wire hist_wr_en_ch0, // CH0写使能
|
||||
input wire [7:0] hist_wr_addr_ch0, // CH0写地址(像素值0~255)
|
||||
input wire hist_wr_en_ch1, // CH1写使能
|
||||
input wire [7:0] hist_wr_addr_ch1, // CH1写地址
|
||||
input wire hist_wr_en_ch2, // CH2写使能
|
||||
input wire [7:0] hist_wr_addr_ch2, // CH2写地址
|
||||
input wire [15:0] histogram_low_num, // 低位数(计算min)
|
||||
input wire [15:0] histogram_high_num,// 高位数(计算max)
|
||||
input wire calc_en, // 计算使能
|
||||
output reg calc_done, // 计算完成
|
||||
output reg [7:0] dwidth_conv_min_ch0,
|
||||
output reg [7:0] dwidth_conv_max_ch0,
|
||||
output reg [7:0] dwidth_conv_min_ch1,
|
||||
output reg [7:0] dwidth_conv_max_ch1,
|
||||
output reg [7:0] dwidth_conv_min_ch2,
|
||||
output reg [7:0] dwidth_conv_max_ch2
|
||||
);
|
||||
|
||||
// 内部信号
|
||||
reg [HIST_RAM_DATA_W-1:0] hist_ram_ch0 [HIST_RAM_DEPTH-1:0]; // CH0直方图RAM
|
||||
reg [HIST_RAM_DATA_W-1:0] hist_ram_ch1 [HIST_RAM_DEPTH-1:0]; // CH1直方图RAM
|
||||
reg [HIST_RAM_DATA_W-1:0] hist_ram_ch2 [HIST_RAM_DEPTH-1:0]; // CH2直方图RAM
|
||||
reg [7:0] calc_addr; // 遍历地址(0~255)
|
||||
reg [15:0] low_cnt_ch0; // CH0低位数计数器
|
||||
reg [15:0] high_cnt_ch0; // CH0高位数计数器
|
||||
reg [15:0] low_cnt_ch1; // CH1低位数计数器
|
||||
reg [15:0] high_cnt_ch1; // CH1高位数计数器
|
||||
reg [15:0] low_cnt_ch2; // CH2低位数计数器
|
||||
reg [15:0] high_cnt_ch2; // CH2高位数计数器
|
||||
reg calc_active; // 计算活跃标记
|
||||
|
||||
// 状态定义
|
||||
|
||||
localparam [1:0] S_HIST_IDLE = 2'b00;
|
||||
localparam [1:0] S_HIST_CLEAR = 2'b01;
|
||||
localparam [1:0] S_HIST_WRITE = 2'b10;
|
||||
localparam [1:0] S_HIST_CALC = 2'b11;
|
||||
|
||||
reg [1:0] curr_hist_state;
|
||||
reg [1:0] next_hist_state;
|
||||
|
||||
// 1. 状态机时序逻辑
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
curr_hist_state <= S_HIST_IDLE;
|
||||
end else begin
|
||||
curr_hist_state <= next_hist_state;
|
||||
end
|
||||
end
|
||||
|
||||
// 2. 状态机组合逻辑
|
||||
always @(*) begin
|
||||
next_hist_state = curr_hist_state;
|
||||
case (curr_hist_state)
|
||||
S_HIST_IDLE: begin
|
||||
if (hist_rst) begin
|
||||
next_hist_state = S_HIST_CLEAR;
|
||||
end else if (hist_wr_en_ch0 || hist_wr_en_ch1 || hist_wr_en_ch2) begin
|
||||
next_hist_state = S_HIST_WRITE;
|
||||
end else if (calc_en) begin
|
||||
next_hist_state = S_HIST_CALC;
|
||||
end
|
||||
end
|
||||
S_HIST_CLEAR: begin
|
||||
if (calc_addr == HIST_RAM_DEPTH - 1) begin
|
||||
next_hist_state = S_HIST_IDLE;
|
||||
end
|
||||
end
|
||||
S_HIST_WRITE: begin
|
||||
if (hist_rst) begin
|
||||
next_hist_state = S_HIST_CLEAR;
|
||||
end else if (calc_en) begin
|
||||
next_hist_state = S_HIST_CALC;
|
||||
end
|
||||
end
|
||||
S_HIST_CALC: begin
|
||||
if (calc_addr == HIST_RAM_DEPTH - 1) begin
|
||||
next_hist_state = S_HIST_IDLE;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// 3. 直方图RAM复位/写逻辑
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
// 复位所有RAM
|
||||
integer i;
|
||||
for (i = 0; i < HIST_RAM_DEPTH; i = i+1) begin
|
||||
hist_ram_ch0[i] <= 1'b0;
|
||||
hist_ram_ch1[i] <= 1'b0;
|
||||
hist_ram_ch2[i] <= 1'b0;
|
||||
end
|
||||
calc_addr <= 8'd0;
|
||||
end else begin
|
||||
case (curr_hist_state)
|
||||
S_HIST_CLEAR: begin
|
||||
// 清空RAM(地址递增)
|
||||
hist_ram_ch0[calc_addr] <= 1'b0;
|
||||
hist_ram_ch1[calc_addr] <= 1'b0;
|
||||
hist_ram_ch2[calc_addr] <= 1'b0;
|
||||
calc_addr <= calc_addr + 8'd1;
|
||||
end
|
||||
S_HIST_WRITE: begin
|
||||
// CH0写(始终有效)
|
||||
if (hist_wr_en_ch0) begin
|
||||
hist_ram_ch0[hist_wr_addr_ch0] <= 1'b1; // 标记像素值存在
|
||||
end
|
||||
// CH1/CH2写(仅RGB模式有效)
|
||||
if (hist_wr_en_ch1 && (input_pixel_type == 1'b1)) begin
|
||||
hist_ram_ch1[hist_wr_addr_ch1] <= 1'b1;
|
||||
end
|
||||
if (hist_wr_en_ch2 && (input_pixel_type == 1'b1)) begin
|
||||
hist_ram_ch2[hist_wr_addr_ch2] <= 1'b1;
|
||||
end
|
||||
calc_addr <= 8'd0;
|
||||
end
|
||||
S_HIST_CALC: begin
|
||||
// 遍历地址递增
|
||||
calc_addr <= calc_addr + 8'd1;
|
||||
end
|
||||
default: begin
|
||||
calc_addr <= 8'd0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// 4. 修复后的直方图min/max计算逻辑(关键修复点)
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
low_cnt_ch0 <= 16'd0;
|
||||
high_cnt_ch0 <= 16'd0;
|
||||
low_cnt_ch1 <= 16'd0;
|
||||
high_cnt_ch1 <= 16'd0;
|
||||
low_cnt_ch2 <= 16'd0;
|
||||
high_cnt_ch2 <= 16'd0;
|
||||
dwidth_conv_min_ch0 <= 8'd0;
|
||||
dwidth_conv_max_ch0 <= 8'd255;
|
||||
dwidth_conv_min_ch1 <= 8'd0;
|
||||
dwidth_conv_max_ch1 <= 8'd255;
|
||||
dwidth_conv_min_ch2 <= 8'd0;
|
||||
dwidth_conv_max_ch2 <= 8'd255;
|
||||
calc_done <= 1'b0;
|
||||
calc_active <= 1'b0;
|
||||
end else begin
|
||||
calc_done <= 1'b0;
|
||||
case (curr_hist_state)
|
||||
S_HIST_CALC: begin
|
||||
calc_active <= 1'b1;
|
||||
// -------------------------- 关键修复1:计算开始时强制清零计数器 --------------------------
|
||||
if (calc_addr == 8'd0) begin // 遍历地址为0时(计算起始),清零所有计数器
|
||||
low_cnt_ch0 <= 16'd0;
|
||||
high_cnt_ch0 <= 16'd0;
|
||||
low_cnt_ch1 <= 16'd0;
|
||||
high_cnt_ch1 <= 16'd0;
|
||||
low_cnt_ch2 <= 16'd0;
|
||||
high_cnt_ch2 <= 16'd0;
|
||||
end
|
||||
|
||||
// -------------------------- CH0计算 --------------------------
|
||||
// min:0→255遍历,找第histogram_low_num个1
|
||||
if (low_cnt_ch0 < histogram_low_num && hist_ram_ch0[calc_addr] == 1'b1) begin
|
||||
low_cnt_ch0 <= low_cnt_ch0 + 16'd1;
|
||||
if (low_cnt_ch0 == histogram_low_num - 16'd1) begin
|
||||
dwidth_conv_min_ch0 <= calc_addr;
|
||||
end
|
||||
end
|
||||
// max:255→0遍历,找第histogram_high_num个1
|
||||
if (high_cnt_ch0 < histogram_high_num && hist_ram_ch0[255 - calc_addr] == 1'b1) begin
|
||||
high_cnt_ch0 <= high_cnt_ch0 + 16'd1;
|
||||
if (high_cnt_ch0 == histogram_high_num - 16'd1) begin
|
||||
dwidth_conv_max_ch0 <= 255 - calc_addr;
|
||||
end
|
||||
end
|
||||
|
||||
// -------------------------- CH1计算(仅RGB模式) --------------------------
|
||||
if (input_pixel_type == 1'b1) begin
|
||||
if (low_cnt_ch1 < histogram_low_num && hist_ram_ch1[calc_addr] == 1'b1) begin
|
||||
low_cnt_ch1 <= low_cnt_ch1 + 16'd1;
|
||||
if (low_cnt_ch1 == histogram_low_num - 16'd1) begin
|
||||
dwidth_conv_min_ch1 <= calc_addr;
|
||||
end
|
||||
end
|
||||
if (high_cnt_ch1 < histogram_high_num && hist_ram_ch1[255 - calc_addr] == 1'b1) begin
|
||||
high_cnt_ch1 <= high_cnt_ch1 + 16'd1;
|
||||
if (high_cnt_ch1 == histogram_high_num - 16'd1) begin
|
||||
dwidth_conv_max_ch1 <= 255 - calc_addr;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// -------------------------- CH2计算(仅RGB模式) --------------------------
|
||||
if (input_pixel_type == 1'b1) begin
|
||||
if (low_cnt_ch2 < histogram_low_num && hist_ram_ch2[calc_addr] == 1'b1) begin
|
||||
low_cnt_ch2 <= low_cnt_ch2 + 16'd1;
|
||||
if (low_cnt_ch2 == histogram_low_num - 16'd1) begin
|
||||
dwidth_conv_min_ch2 <= calc_addr;
|
||||
end
|
||||
end
|
||||
if (high_cnt_ch2 < histogram_high_num && hist_ram_ch2[255 - calc_addr] == 1'b1) begin
|
||||
high_cnt_ch2 <= high_cnt_ch2 + 16'd1;
|
||||
if (high_cnt_ch2 == histogram_high_num - 16'd1) begin
|
||||
dwidth_conv_max_ch2 <= 255 - calc_addr;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// -------------------------- 遍历结束:置位完成信号 --------------------------
|
||||
if (calc_addr == HIST_RAM_DEPTH - 1) begin
|
||||
calc_done <= 1'b1;
|
||||
calc_active <= 1'b0;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
calc_active <= 1'b0;
|
||||
calc_done <= 1'b0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
27
rtl/data_cache/rst_sync.v
Normal file
27
rtl/data_cache/rst_sync.v
Normal file
@@ -0,0 +1,27 @@
|
||||
module rst_sync #(
|
||||
parameter SYNC_STAGE = 2 // 同步级数(推荐2级)
|
||||
) (
|
||||
input wire clk,
|
||||
input wire rst_n_in,
|
||||
output reg rst_n_out
|
||||
);
|
||||
|
||||
reg [SYNC_STAGE-1:0] rst_sync_reg;
|
||||
|
||||
always @(posedge clk or negedge rst_n_in) begin
|
||||
if (!rst_n_in) begin
|
||||
rst_sync_reg <= {SYNC_STAGE{1'b0}};
|
||||
end else begin
|
||||
rst_sync_reg <= {rst_sync_reg[SYNC_STAGE-2:0], 1'b1};
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk or negedge rst_n_in) begin
|
||||
if (!rst_n_in) begin
|
||||
rst_n_out <= 1'b0;
|
||||
end else begin
|
||||
rst_n_out <= rst_sync_reg[SYNC_STAGE-1];
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
73
rtl/data_cache/sync_fifo.v
Normal file
73
rtl/data_cache/sync_fifo.v
Normal file
@@ -0,0 +1,73 @@
|
||||
module sync_fifo #(
|
||||
parameter DATA_WIDTH = 8,
|
||||
parameter FIFO_DEPTH = 16
|
||||
)(
|
||||
input clk,
|
||||
input rst_n,
|
||||
input wr_en,
|
||||
input [DATA_WIDTH-1:0] wr_data,
|
||||
output full,
|
||||
input rd_en,
|
||||
output [DATA_WIDTH-1:0] rd_data,
|
||||
output empty
|
||||
);
|
||||
localparam ADDR_WIDTH = $clog2(FIFO_DEPTH);
|
||||
reg [DATA_WIDTH-1:0] mem [0 : FIFO_DEPTH -1];
|
||||
reg [ADDR_WIDTH : 0] wr_ptr, rd_ptr;
|
||||
wire [ADDR_WIDTH -1:0] wr_addr ,rd_addr;
|
||||
|
||||
assign wr_addr = wr_ptr[ADDR_WIDTH -1:0];
|
||||
assign rd_addr = rd_ptr[ADDR_WIDTH -1:0];
|
||||
|
||||
always@(posedge clk or negedge rst_n) begin
|
||||
if(!rst_n) begin
|
||||
wr_ptr <= 'd0;
|
||||
end else if(wr_en && !full) begin
|
||||
wr_ptr <= wr_ptr + 1'b1;
|
||||
end else begin
|
||||
wr_ptr <= wr_ptr;
|
||||
end
|
||||
end
|
||||
|
||||
always@(posedge clk or negedge rst_n) begin
|
||||
if(!rst_n) begin
|
||||
rd_ptr <= 'd0;
|
||||
end else if(rd_en && !empty) begin
|
||||
rd_ptr <= rd_ptr + 1'b1;
|
||||
end else begin
|
||||
rd_ptr <= rd_ptr;
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
integer i;
|
||||
always@(posedge clk or negedge rst_n) begin
|
||||
if(!rst_n) begin
|
||||
for(i=0;i<FIFO_DEPTH;i=i+1) begin
|
||||
mem[i] <= 'd0;
|
||||
end
|
||||
end else if(wr_en && !full) begin
|
||||
mem[wr_addr] <= wr_data;
|
||||
end else begin
|
||||
mem[wr_addr] <= mem[wr_addr];
|
||||
end
|
||||
end
|
||||
|
||||
// always@(posedge clk or negedge rst_n) begin
|
||||
// if(!rst_n) begin
|
||||
// rd_data <= 'd0;
|
||||
// end else if(rd_en && !empty) begin
|
||||
// rd_data <= mem[rd_addr];
|
||||
// end else begin
|
||||
// rd_data <= rd_data;
|
||||
// end
|
||||
// end
|
||||
|
||||
assign rd_data = mem[rd_addr];
|
||||
|
||||
|
||||
assign full = ((wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]) &&
|
||||
(wr_ptr[ADDR_WIDTH -1:0] == rd_ptr[ADDR_WIDTH -1:0])) ? 1:0;
|
||||
assign empty = (wr_ptr == rd_ptr) ? 1:0;
|
||||
|
||||
endmodule
|
Reference in New Issue
Block a user