cache module

This commit is contained in:
Core_kingdom
2025-08-26 16:53:22 +08:00
commit 79dee10db1
124 changed files with 13283 additions and 0 deletions

View 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

View 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

View File

@@ -0,0 +1,109 @@
module data_assemble #(
parameter PIXEL_WIDTH = 8, // 单通道像素位宽
parameter GRAY_PIXEL_CNT = 32, // Gray模式32个8bit256bit
parameter RGB_PIXEL_CNT = 8 // RGB模式8个32bit24bit数据+8bit补零256bit
) (
input wire clk,
input wire rst_n,
input wire en, // 拼接使能
input wire input_pixel_type, // 0=Gray1=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模式32x8bit256bit高位到低位拼接
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模式8x32bit256bit32bit=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
View 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=Gray1=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通道QoS0=默认
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. 异步FIFOIR时钟域系统时钟域传输像素数据+控制信号
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:32x8bit256bitRGB:8x32bit256bit
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

View 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=Gray1=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计算 --------------------------
// min0→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
// max255→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
View 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

View 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