前言
MCDF,全名多通道数据整形器(Multiple channels data formatter),他的功能是对多个channel的输入数据包,经由arbiter根据各个通道优先级仲裁,选定通道,并将数据交给formatter打包,一并输出的器件。每个channel的状态由一个32位的读写控制寄存器和一个32位的只读状态寄存器决定。
一、slave_fifo功能解析与实现步骤
slave端完成了一个外部数据输入的接受和认证,并将它们有序存放进FIFO中的功能,对来自arbiter的某些信号a2sx_ack_i做处理,arbiter从slave取完数据后,返回一个应答信号使得slave可以被再次读取。
二、slave_fifo.v
代码如下:
module slave_fifo (
//雷打不动的时钟与复位
input clk_i, // Clock input
input rstn_i, // low level effective
//外部输入的channnel数据32位
input [31:0] chx_data_i, // Data input ---->From outside
//从arbiter to slave的读ack???
input a2sx_ack_i, // Read ack ---->From Arbiter
//通道使能
input slvx_en_i, // Write enable To Registers ---->To Register
//由外部而来,valid拉高,32位的数据写入才有效
input chx_valid_i, // Data is valid From outside ---->From Outside
//slave通道输出数据,送往FIFOx???
output reg [31:0] slvx_data_o, // Data Output ---->To Arbiter
//数据边界,即距离FIFO满还有多少
output [5:0] margin_o, // Data margin ---->To Registers
//输出的ready,表明当前通道是否准备好接收数据,和FIFO的空满状态有关,满则ready拉低
output reg chx_ready_o, // Ready to accept data ---->To outside
//salve的输出数据的valid,表明输出数据的有效性
output reg slvx_val_o, // read acknowledge Keep to handshake with Arbiter ----> To Arbiter
//slave的输出请求???
output reg slvx_req_o
);
//------------------------------Internal variables-------------------//
reg [5:0] wr_pointer_r;//FIFO的写指针
reg [5:0] rd_pointer_r;//FIFO的读指针
reg [31:0] mem [0:31]; //FIFO 32bits width and 32 deepth
//-----------------------------Variable assignments------------------//
wire full_s, empty_s, rd_en_s ;//定义了fifo满信号,空信号与读使能信号
wire [5:0] data_cnt_s;//计算FIFO余量
assign full_s = ({~wr_pointer_r[5],wr_pointer_r[4:0]}==rd_pointer_r);//满标志位用读写指针最高位相反,其余各位保持一致表示,这是fifo的一个特点
assign empty_s = (wr_pointer_r == rd_pointer_r);//空标志位用读指针与写指针相同表示
assign data_cnt_s = (6'd32 - (wr_pointer_r - rd_pointer_r));//fifo空状态能存6'd32个数据,减去写指针与读指针的差值,得到当前余量,这说明写指针是大于读指针的,fifo的一个特点就是只有两个指针,所以不能像存储器那样任意访问存储位置,只能先写再读
assign margin_o = data_cnt_s;//把余量大小输出
assign rd_en_s = a2sx_ack_i;//arbiter to slave的ack来了之后,说明可以开始读使能了???
//-----------Code Start---------------------------------------------//
//下列always块都是并行触发
//如果FIFO没满并且通道使能,那么ready拉高,可以接收数据
always @ (*) //ready signal
begin
if (!full_s && slvx_en_i) chx_ready_o = 1'b1;//If FIFO is not full and also enabled it is ready to accept data
else chx_ready_o = 1'b0;
end
//复位信号
always @ (*) //reset signal
begin
if (!rstn_i) slvx_req_o = 1'b0;//清零复位
else if (!empty_s) slvx_req_o = 1'b1;//如果fifo非空,slave输出请求置1,可以输出数据
else slvx_req_o = 1'b0;
end
//write pointer increment
//写指针逻辑
always @ (posedge clk_i or negedge rstn_i)//敏感事件是每次时钟的上升沿或复位信号下降沿
begin : WRITE_POINTER
if (!rstn_i) begin
wr_pointer_r <= 6'b0000;//写指针复位
end else
if (chx_valid_i && chx_ready_o) begin//输入数据有效且当前通道可以接受
wr_pointer_r <= wr_pointer_r + 6'b0001;//每进行一次操作后指针地址加一
end
end
//read pointer increment
//读指针逻辑
always @ (posedge clk_i or negedge rstn_i)
//敏感事件是每次时钟的上升沿或复位信号下降沿
begin : READ_POINTER
if (!rstn_i) begin
rd_pointer_r <= 6'b0000;//
end else
if (rd_en_s && (!empty_s)) begin//读信号使能且FIFO非空
rd_pointer_r <= rd_pointer_r + 6'b0001;//每进行一次操作后指针地址加一
end
end
//data output is vaild
//数据输出valid
always @ (posedge clk_i or negedge rstn_i)
//敏感事件是每次时钟的上升沿或复位信号下降沿
begin
if (!rstn_i) slvx_val_o <= 1'b0;//slave的valid输出复位
else if (rd_en_s && (!empty_s))//读信号使能且FIFO非空
slvx_val_o <= 1'b1;//slave的valid输出置1,输出数据主动方认为有效
else slvx_val_o <= 1'b0;//否则无效
end
// Memory Read Block
//读FIFO逻辑
always @ (posedge clk_i )
//敏感事件仅取决于时钟上升沿
begin : READ_DATA
if (rstn_i && rd_en_s && (!empty_s)) begin//没按下复位,读信号使能且FIFO非空
slvx_data_o <= mem[rd_pointer_r[4:0]];//slave端的数据输出从mem数组中取出读指针地址对应的32位数据,这里mem数据就是FIFO
end
end
// Memory Write Block
//写FIFO逻辑
always @ (posedge clk_i)
//敏感事件仅取决于时钟上升沿
begin : MEM_WRITE
if (rstn_i && chx_valid_i && chx_ready_o && slvx_en_i) begin//没复位,通道输入数据主动方认为有效,通道准备好,slave使能
mem[wr_pointer_r[4:0]] <= chx_data_i;//把外部输入数据写入FIFO对应写指针的地址内
end
end
endmodule
//slave端完成了一个外部数据输入的接受和认证,并将它们有序存放进FIFO中的功能,对来自arbiter的某些信号a2sx_ack_i做处理,arbiter从slave取完数据后,返回一个应答信号使得slave可以被再次读取