本文为RTL乒乓运算模块设计的子模块设计。
该模块可借鉴使用APB到标准握手桥模块,即APB2standard_handshake_bridge 设计
区别在于APB接口的pslverr由寄存器模块给出,此处只根据pwrite作分选
接口如下
Group | Signal | Direction | Width(bits) | Description |
---|---|---|---|---|
APB_intf | prstn | input | 1 | 异步低复位 |
pclk | input | 1 | 时钟,为36MHZ | |
paddr | input | 32 | APB地址,用于对pingpong_ave_reg内寄存器片选 | |
psel | input | 1 | APB选通,用于对pingpong_ave_reg选通 | |
penable | input | 1 | ||
pwrite | input | 1 | 高写低读 | |
pwdata | input | 32 | 写入数据 | |
prdata | output | 32 | 读出数据 | |
pready | output | 1 | ||
pslverr | output | 1 | 传输是否错误 | |
pingpong_ave_intf | waddr | output | 32 | 写地址 |
wdata | output | 32 | 写数据 | |
wr_en | output | 1 | 写使能 | |
wready | input | 1 | 写准备 | |
wslverr | input | 1 | 写错误,当地址错误或写入只读寄存器时该信号拉高 | |
raddr | output | 32 | 读地址 | |
rdata | input | 32 | 读数据 | |
rdata_val | input | 32 | 读数据有效 | |
rd_en | output | 1 | 读使能 | |
rready | input | 1 | 读准备 | |
rslverr | input | 1 | 读错误,当地址错误或不可读寄存器时该信号拉高 |
module apb2pingpong_ave_reg_intf(
input prstn,
input pclk,
//APB interface
input [31:0] paddr,
input pwrite,
input psel,
input penable,
input [31:0] pwdata,
output [31:0] prdata,
output pready,
output pslverr,
//pingpong_ave_reg interface
output [31:0] waddr,
output [31:0] wdata,
output wr_en,
input wready,
input wslverr,
output [31:0] raddr,
input [31:0] rdata,
input rdata_val,
output rd_en,
input rready,
input rslverr
);
assign wr_en = pwrite && psel && penable;
assign waddr = paddr;
assign raddr = paddr;
assign wdata = pwdata;
assign pready = (pwrite)? wready:rdata_val;
assign prdata = rdata;
assign rd_en = (!pwrite) && psel && !rdata_val;
assign pslverr = (pwrite)? wslverr:rslverr;
endmodule
该模块主要是解析AXIS串行输入的ODF数据,根据协议内容解析、校验。
同时根据外部控制信号对AXIS输入进行屏蔽,防止透传变量被新的ODF覆盖
根据读指令,对待平均数据串行读出。
● 基于AXIS接口串行输入ODF协议包,时钟aclk为150MHZ
● 对ODF协议解析,若校验和通过,寄存协议包中各变量
● 可控制AXIS接口屏蔽,防止新的ODF进入
Group | Signal | Direction | Width(bits) | Description |
---|---|---|---|---|
AXIS_intf | aclk | input | 1 | AXIS时钟 |
arstn | input | 1 | AXIS低电平异步复位 | |
tdata_ODF | input | 32 | AXIS数据 | |
tvalid_ODF | input | 1 | tdata有效 | |
tlast_ODF | input | 1 | 指示最后一个tdata | |
tready_ODF | output | 1 | tvalid握手信号 | |
ODF analysis output | ||||
frame_length | output | 16 | 数据包长度 | |
frame_counter | output | 32 | 数据帧计数 | |
arrive_time | output | 32 | 到达时间 | |
alpha | output | 16 | 透传变量α | |
beta | output | 16 | 透传变量β | |
gamma | output | 16 | 透传变量γ | |
lambda | output | 16 | 透传变量λ | |
Sample_A_fixed_type | output | 8 | 变量A修订数据类型 | |
Sample_B_fixed_type | output | 8 | 变量B修订数据类型 | |
Sample_C_fixed_type | output | 8 | 变量C修订数据类型 | |
Sample_D_fixed_type | output | 8 | 变量D修订数据类型 | |
rdata_Sample_A_FIFO | output | 16 | 串行输出待平均变量A | |
rdata_val_Sample_A_FIFO | output | 1 | 串行输出待平均变量A有效 | |
rdata_Sample_B_FIFO | output | 16 | 串行输出待平均变量B | |
rdata_val_Sample_B_FIFO | output | 1 | 串行输出待平均变量B有效 | |
rdata_Sample_C_FIFO | output | 16 | 串行输出待平均变量C | |
rdata_val_Sample_C_FIFO | output | 1 | 串行输出待平均变量C有效 | |
rdata_Sample_D_FIFO | output | 16 | 串行输出待平均变量D | |
rdata_val_Sample_D_FIFO | output | 1 | 串行输出待平均变量D有效 | |
ODF_analysis_done | output | 1 | 一包ODF解析完毕标志 | |
ODF analysis control | ||||
rd_en_Sample_A_FIFO | input | 1 | 待平均变量A读出标志 | |
rd_en_Sample_B_FIFO | input | 1 | 待平均变量B读出标志 | |
rd_en_Sample_C_FIFO | input | 1 | 待平均变量C读出标志 | |
rd_en_Sample_D_FIFO | input | 1 | 待平均变量D读出标志 | |
ODF_block_en | input | 1 | ODF协议包阻塞标志 |
由于校验和在ODF最后一项,所以当ODF通过AXIS输入之后,先解析其中的变量,待平均数据ABCD则直接写入FIFO,解析的同时计算校验和。
最后如果校验和成功则ODF_analysis_done拉高一拍。若校验失败,则将FIFO复位,ODF_analysis_done不拉高
状态机如下
由于我们根据协议解析ODF,所以必须用到一个计数器ODF_cnt标注当前tdata传输的是ODF的第几项,同时可以借助该计数器将上述状态机实现。
注意ODF_cnt==10+2a时,check_suim_correct和rst_fifo不可同时变化,合成一张图则如下
module ODF_analysis(
input arstn,
input aclk,
//AXIS interface
input [31:0] tdata_ODF,
input tvalid_ODF,
input tlast_ODF,
output tready_ODF,
//ODF analysis output
output reg [15:0] frame_length,
output reg [15:0] frame_counter,
output reg [31:0] arrive_time,
output reg [15:0] alpha,
output reg [15:0] beta,
output reg [15:0] gamma,
output reg [15:0] lambda,
output reg [7:0] sample_A_fixed_type,
output reg [7:0] sample_B_fixed_type,
output reg [7:0] sample_C_fixed_type,
output reg [7:0] sample_D_fixed_type,
output [7:0] rdata_sample_A_FIFO,
output rdata_val_sample_A_FIFO,
output [7:0] rdata_sample_B_FIFO,
output rdata_val_sample_B_FIFO,
output [7:0] rdata_sample_C_FIFO,
output rdata_val_sample_C_FIFO,
output [7:0] rdata_sample_D_FIFO,
output rdata_val_sample_D_FIFO,
output ODF_analysis_done,
//ODF analysis control
input rd_en_sample_A_FIFO,
input rd_en_sample_B_FIFO,
input rd_en_sample_C_FIFO,
input rd_en_sample_D_FIFO,
input ODF_block_en
);
wire axis_handshake_done;
wire [15:0] frame_length_plus_3;
reg [15:0] ODF_cnt;
wire ODF_cnt_larger_1;
reg [7:0] check_sum;
wire check_sum_time;
wire check_sum_correct;
wire rst_fifo;
wire [15:0] sample_data_length_tmp;
wire [15:0] sample_data_length;
wire frame_head_time;
wire ODF_analysis_time;
reg [7:0] wdata_sample_A_FIFO;
reg wr_en_sample_A_FIFO;
reg [7:0] wdata_sample_B_FIFO;
reg wr_en_sample_B_FIFO;
reg [7:0] wdata_sample_C_FIFO;
reg wr_en_sample_C_FIFO;
reg [7:0] wdata_sample_D_FIFO;
reg wr_en_sample_D_FIFO;
assign axis_handshake_done = tvalid_ODF && tready_ODF;
assign frame_length_plus_3 = frame_length + 16'd3;
/*
--------------------------------------------
ODF analysis done is equivalent to check sum correct
--------------------------------------------
*/
assign check_sum_time = (ODF_cnt == frame_length_plus_3) && axis_handshake_done;
assign check_sum_correct = check_sum_time && (check_sum == tdata_ODF);
assign ODF_analysis_done = check_sum_correct;
/*
--------------------------------------------
length of sample data
--------------------------------------------
*/
assign sample_data_length_tmp = frame_length - 16'd7;
assign sample_data_length = {1'd0,sample_data_length_tmp[15:1]};
/*
--------------------------------------------
ODF_cnt > 1 && ODF_cnt < frame_length + 3
--------------------------------------------
*/
assign frame_head_time = (tdata_ODF == 16'hABCD_1234) && axis_handshake_done;
assign ODF_cnt_larger_1 = |(ODF_cnt[15:1]);
assign ODF_analysis_time = ODF_cnt_larger_1 && ODF_cnt < frame_length_plus_3 && axis_handshake_done;
/*
--------------------------------------------
check sum failed then reset sample fifos
--------------------------------------------
*/
assign rst_fifo = ~(check_sum_time && (check_sum != tdata_ODF));
/*
--------------------------------------------
ODF_cnt logic
--------------------------------------------
*/
always@(posedge aclk or negedge arstn) begin
if(!arstn)
ODF_cnt <= 16'd1;
else if(frame_head_time || ODF_analysis_time)
ODF_cnt <= ODF_cnt + 16'd1;
else if(check_sum_time)
ODF_cnt <= 16'd1;
end
/*
--------------------------------------------
ODF analysis logic
--------------------------------------------
*/
always@(posedge aclk or negedge arstn) begin
if(!arstn) begin
frame_length <= 16'hFFFF_FFFF;
frame_counter <= 16'h0;
arrive_time <= 32'd0;
alpha <= 16'd0;
beta <= 16'd0;
gamma <= 16'd0;
lambda <= 16'd0;
sample_A_fixed_type <= 8'd0;
sample_B_fixed_type <= 8'd0;
sample_C_fixed_type <= 8'd0;
sample_D_fixed_type <= 8'd0;
wdata_sample_A_FIFO <= 8'd0;
wr_en_sample_A_FIFO <= 1'd0;
wdata_sample_B_FIFO <= 8'd0;
wr_en_sample_B_FIFO <= 1'd0;
wdata_sample_C_FIFO <= 8'd0;
wr_en_sample_C_FIFO <= 1'd0;
wdata_sample_D_FIFO <= 8'd0;
wr_en_sample_D_FIFO <= 1'd0;
end
else if(ODF_cnt == 16'd2 && axis_handshake_done)
frame_length <= tdata_ODF[15:0];
else if(ODF_cnt == 16'd3 && axis_handshake_done)
frame_counter <= tdata_ODF[15:0];
else if(ODF_cnt == 16'd4 && axis_handshake_done)
arrive_time <= tdata_ODF;
else if(ODF_cnt == 16'd5 && axis_handshake_done) begin
alpha <= tdata_ODF[15:0];
beta <= tdata_ODF[31:16];
end
else if(ODF_cnt == 16'd6 && axis_handshake_done) begin
gamma <= tdata_ODF[15:0];
lambda <= tdata_ODF[31:16];
end
else if(ODF_cnt == 16'd7 && axis_handshake_done) begin
sample_A_fixed_type <= tdata_ODF[7:0];
sample_B_fixed_type <= tdata_ODF[15:8];
sample_C_fixed_type <= tdata_ODF[23:16];
sample_D_fixed_type <= tdata_ODF[31:24];
end
else if(ODF_cnt >= 16'd7 && ODF_cnt <= sample_data_length + 16'd7 && axis_handshake_done) begin
wdata_sample_A_FIFO <= tdata_ODF[15:0];
wr_en_sample_A_FIFO <= 1'b1;
wdata_sample_B_FIFO <= tdata_ODF[31:16];
wr_en_sample_B_FIFO <= 1'b1;
end
else if(ODF_cnt >= sample_data_length + 16'd8 && ODF_cnt <= frame_length && axis_handshake_done) begin
wdata_sample_C_FIFO <= tdata_ODF[15:0];
wr_en_sample_C_FIFO <= 1'b1;
wdata_sample_D_FIFO <= tdata_ODF[31:16];
wr_en_sample_D_FIFO <= 1'b1;
end
end
/*
--------------------------------------------
check_sum logic
--------------------------------------------
*/
always@(posedge aclk or negedge arstn) begin
if(!arstn)
check_sum <= 8'd0;
else if(ODF_analysis_time)
check_sum <= tdata_ODF[7:0];
else if(check_sum_time)
check_sum <= 8'd0;
end
/*
--------------------------------------------
sample data FIFO
if check sum failed, reset fifo.
make sure clks of resetting fifo smaller than 7 according to ODF frame protocol
--------------------------------------------
*/
async_fifo#(
.ASYNC_FIFO_WDEPTH (64 ), //写深度,即FIFO大小 ASYNC_FIFO_SIZE=(WDATA_WIDTH × ASYNC_FIFO_WDEPTH) bit
.WDATA_WIDTH (8 ),
.RDATA_WIDTH (8 ),
.PROG_WDEPTH (64 )
)U_SAMPLE_A_FIFO(
.rstn (arstn && rst_fifo ),
.wclk (aclk ),
.wr_en (wr_en_sample_A_FIFO ),
.wdata (wdata_sample_A_FIFO ),
.rclk (aclk ),
.rd_en (rd_en_sample_A_FIFO ),
.rdata (rdata_sample_A_FIFO ),
.valid (rdata_val_sample_A_FIFO ),
.full ( ),
.pfull ( ),
.empty ( )
);
async_fifo#(
.ASYNC_FIFO_WDEPTH (64 ), //写深度,即FIFO大小 ASYNC_FIFO_SIZE=(WDATA_WIDTH × ASYNC_FIFO_WDEPTH) bit
.WDATA_WIDTH (8 ),
.RDATA_WIDTH (8 ),
.PROG_WDEPTH (64 )
)U_SAMPLE_B_FIFO(
.rstn (arstn && rst_fifo ),
.wclk (aclk ),
.wr_en (wr_en_sample_B_FIFO ),
.wdata (wdata_sample_B_FIFO ),
.rclk (aclk ),
.rd_en (rd_en_sample_B_FIFO ),
.rdata (rdata_sample_B_FIFO ),
.valid (rdata_val_sample_B_FIFO ),
.full ( ),
.pfull ( ),
.empty ( )
);
async_fifo#(
.ASYNC_FIFO_WDEPTH (64 ), //写深度,即FIFO大小 ASYNC_FIFO_SIZE=(WDATA_WIDTH × ASYNC_FIFO_WDEPTH) bit
.WDATA_WIDTH (8 ),
.RDATA_WIDTH (8 ),
.PROG_WDEPTH (64 )
)U_SAMPLE_C_FIFO(
.rstn (arstn && rst_fifo ),
.wclk (aclk ),
.wr_en (wr_en_sample_C_FIFO ),
.wdata (wdata_sample_C_FIFO ),
.rclk (aclk ),
.rd_en (rd_en_sample_C_FIFO ),
.rdata (rdata_sample_C_FIFO ),
.valid (rdata_val_sample_C_FIFO ),
.full ( ),
.pfull ( ),
.empty ( )
);
async_fifo#(
.ASYNC_FIFO_WDEPTH (64 ), //写深度,即FIFO大小 ASYNC_FIFO_SIZE=(WDATA_WIDTH × ASYNC_FIFO_WDEPTH) bit
.WDATA_WIDTH (8 ),
.RDATA_WIDTH (8 ),
.PROG_WDEPTH (64 )
)U_SAMPLE_D_FIFO(
.rstn (arstn && rst_fifo ),
.wclk (aclk ),
.wr_en (wr_en_sample_D_FIFO ),
.wdata (wdata_sample_D_FIFO ),
.rclk (aclk ),
.rd_en (rd_en_sample_D_FIFO ),
.rdata (rdata_sample_D_FIFO ),
.valid (rdata_val_sample_D_FIFO ),
.full ( ),
.pfull ( ),
.empty ( )
);
endmodule
在平均计算完毕后,根据ADF协议打包并通过AXIS输出
● 待平均计算完毕后生成ADF协议包,时钟aclk为150MHZ
● 正确计算校验和
● 按照AXIS接口协议串行打包输出
Group | Signal | Direction | Width(bits) | Description |
---|---|---|---|---|
AXIS_intf | aclk | input | 1 | AXIS时钟 |
arstn | input | 1 | AXIS低电平异步复位 | |
tdata_ADF | output | 32 | AXIS数据 | |
tvalid_ADF | output | 1 | tdata有效 | |
tlast_ADF | output | 1 | 指示最后一个tdata | |
tready_ADF | input | 1 | tvalid握手信号 | |
ADF generate input | ||||
frame_length | input | 16 | 数据包长度 | |
frame_counter | input | 32 | 数据帧计数 | |
arrive_time | input | 32 | 到达时间 | |
alpha | input | 16 | 透传变量α | |
beta | input | 16 | 透传变量β | |
gamma | input | 16 | 透传变量γ | |
lambda | input | 16 | 透传变量λ | |
Sample_A_fixed_type | input | 8 | 变量A修订数据类型 | |
Sample_B_fixed_type | input | 8 | 变量B修订数据类型 | |
Sample_C_fixed_type | input | 8 | 变量C修订数据类型 | |
Sample_D_fixed_type | input | 8 | 变量D修订数据类型 | |
sample_A_ave | input | 16 | 变量A加权平均结果 | |
sample_B_ave | input | 16 | 变量A加权平均结果 | |
sample_C_ave | input | 16 | 变量A加权平均结果 | |
sample_D_ave | input | 16 | 变量A加权平均结果 | |
ADF generate control | ||||
ave_done | input | 1 | 加权平均完成标志 | |
ADF_gen_done | output | 1 | ADF打包完成标志 |
思路和状态机类似,按照协议,先帧头握手、再frame length握手,一直到最后。但要注意的是图中校验和check_sum是每握手成功后算一次校验和,所以最终tdata_ADF与正确的校验和在时序上是对齐的,所以就需要一个组合逻辑在ADF_cnt非14时为数据,等于14时为check_sum。
module ADF_gen(
input arstn,
input aclk,
//AXIS interface
output [31:0] tdata_ADF,
output tvalid_ADF,
output tlast_ADF,
input tready_ADF,
//ADF generate input
input [15:0] frame_length,
input [15:0] frame_counter,
input [31:0] arrive_time,
input [15:0] alpha,
input [15:0] beta,
input [15:0] gamma,
input [15:0] lambda,
input [7:0] sample_A_fixed_type,
input [7:0] sample_B_fixed_type,
input [7:0] sample_C_fixed_type,
input [7:0] sample_D_fixed_type,
input [31:0] sample_A_ave,
input [31:0] sample_B_ave,
input [31:0] sample_C_ave,
input [31:0] sample_D_ave,
input ave_done,
output ADF_gen_done
);
reg [14:0] ADF_cnt;
reg [31:0] tdata_ADF_body;
reg [7:0] check_sum;
wire sum_time;
wire axis_handshake_done;
assign tdata_ADF = (ADF_cnt[14])?{24'd0,check_sum}:tdata_ADF_body;
assign tlast_ADF = ADF_cnt[14] && tvalid_ADF;
assign sum_time = |(ADF_cnt[13:2]);
assign axis_handshake_done = tvalid_ADF && tready_ADF;
assign ADF_gen_done = ADF_cnt[14] && axis_handshake_done;
/*
----------------------------
ADF cnt logic
start at ave_done and move one bit after axis handshake
----------------------------
*/
always@(posedge aclk or negedge arstn) begin
if(!arstn)
ADF_cnt <= 15'd1;
else if(ave_done)
ADF_cnt <= 15'd1;
else if(axis_handshake_done)
ADF_cnt <= ADF_cnt << 1;
end
/*
----------------------------
tdata_ADF_body logic
update data after axis handshake
ADF package without checksum
----------------------------
*/
always@(posedge aclk or negedge arstn) begin
if(!arstn)
tdata_ADF_body <= 32'd0;
else if(ave_done)
tdata_ADF_body <= 32'hA5A5_B6B6;
else if(ADF_cnt[1] && axis_handshake_done)
tdata_ADF_body <= {16'd0,frame_length};
else if(ADF_cnt[2] && axis_handshake_done)
tdata_ADF_body <= {16'd0,frame_counter};
else if(ADF_cnt[3] && axis_handshake_done)
tdata_ADF_body <= arrive_time;
else if(ADF_cnt[4] && axis_handshake_done)
tdata_ADF_body <= {beta,alpha};
else if(ADF_cnt[5] && axis_handshake_done)
tdata_ADF_body <= {lambda,gamma};
else if(ADF_cnt[6] && axis_handshake_done)
tdata_ADF_body <= {sample_D_fixed_type,sample_C_fixed_type,sample_B_fixed_type,sample_A_fixed_type};
else if(ADF_cnt[7] && axis_handshake_done)
tdata_ADF_body <= sample_A_ave;
else if(ADF_cnt[8] && axis_handshake_done)
tdata_ADF_body <= sample_B_ave;
else if(ADF_cnt[9] && axis_handshake_done)
tdata_ADF_body <= sample_C_ave;
else if(ADF_cnt[10] && axis_handshake_done)
tdata_ADF_body <= sample_D_ave;
else if(ADF_cnt[11] && axis_handshake_done)
tdata_ADF_body <= 32'h0;
end
/*
----------------------------
checksum logic
update checksum after axis handshake
check sum adds during index 2-13 of ADF protocol
----------------------------
*/
always@(posedge aclk or negedge arstn) begin
if(!arstn)
check_sum <= 8'd0;
else if(sum_time)
check_sum <= check_sum + tdata_ODF[7:0];
else if(ADF_gen_done)
check_sum <= 8'd0;
end
endmodule
寄存器接口模块,完成寄存器配置和读取。同时校准数据RAM控制也在该模块下
● 基于标准握手接口,可实现寄存器的读写操作。工作时钟pclk为36MHZ
● 根据工作状态更新状态寄存器,注意跨时钟域问题
● 将部分指令寄存器输出到其他模块,以进行控制
Group | Signal | Direction | Width(bits) | Description | |
---|---|---|---|---|---|
pclk | input | 1 | 工作时钟,应为36MHz | ||
prstn | input | 1 | 异步低电平复位 | ||
standard handshake intf | waddr | input | 32 | 写地址 | |
wdata | input | 32 | 写数据 | ||
wr_en | input | 1 | 写使能 | ||
wready | output | 1 | 写准备 | ||
wslverr | output | 1 | 写错误,当地址错误或写入只读寄存器时该信号拉高 | ||
raddr | input | 32 | 读地址 | ||
rdata | output | 32 | 读数据 | ||
rdata_val | output | 32 | 读数据有效 | ||
rd_en | input | 1 | 读使能 | ||
rready | output | 1 | 读准备 | ||
rslverr | output | 1 | 读错误,当地址错误或不可读寄存器时该信号拉高 | ||
PA_ENABLE register intf | pa_enable | output | 1 | Control whether pingpong_ave is enabled | |
pa_work_mode | output | 2 | 2'b00: Stop Operation Mode;2'b01:Carrying Fixed Data Mode;2'b10:Solo Operation Mode | ||
PA_WEIGHT register intf | pa_weight_k1 | output | 16 | weight value for average calculation | |
pa_weight_k2 | output | 16 | weight value for average calculation | ||
... | output | 16 | weight value for average calculation | ||
pa_weight_k10 | output | 16 | weight value for average calculation | ||
PA_ODF_MODE register intf | pa_ODF_block_mode | output | 2 | Indicates the masking mode of the ODF. 2'd0 indicates that an ODF is acquired and then masking begins until a packet of ADF is output. 2'd1 indicates that ODF is never blocked. In this case, the register of the transparent transmission variable is required, which will take more resources. 2'd3 indicates selection of masking mode of ODF depends on the relationship of size of MUL_ADF_PIPELINE_STAGES_NUM_THRESHOLD and MUL_ADF_PIPELINE_STAGES_NUM in PA_MUL_STAGES | |
ODF_analysis_done | input | 1 | To calculate number of ODF already received | ||
pa_ODF_time_out | output | 2 | Clk periods of waiting for ODF coming | ||
PA_ADF_MODE | ADF_gen_done | input | 1 | To calculate number of ADF already made | |
PA_MUL_STAGES | sample_data_length | input | 8 | Number of sample data to be equilibrated in the last ODF. | |
PA_SAMPLE_A_FIX_RAM | |||||
PA_SAMPLE_B_FIX_RAM | |||||
PA_SAMPLE_C_FIX_RAM | |||||
PA_SAMPLE_C_FIX_RAM |