-MCDF源码
mcdt框图
slave_fifo
接收外部的数据,在合适的时间,将数据发送给仲裁器
module slave_fifo (
input clk_i, // Clock input
input rstn_i, // Reset signal
input [31:0] chx_data_i, // Data input ---->From outside
input a2sx_ack_i, // Read ack ---->From Arbiter
input chx_valid_i, // Data is valid From outside ---->From Outside
output reg [31:0] slvx_data_o, // Data Output ---->To Arbiter
output [5:0] slvx_margin_o, // Data margin ---->To Outside
output reg chx_ready_o, // Ready to accept data ---->To outside
output reg slvx_val_o, // Output data is valid ---->To Arbiter
output reg slvx_req_o // Request to send data ---->To Arbiter
);
//------------------------------Internal variables-------------------//
reg [5:0] wr_pointer_r;
reg [5:0] rd_pointer_r;
reg [31:0] mem [0:31]; //FIFO 32bits width and 32 deepth
//-----------------------------Variable assignments------------------//
wire full_s, empty_s, rd_en_s ;
wire [5:0] data_cnt_s;
assign full_s = ({~wr_pointer_r[5],wr_pointer_r[4:0]}==rd_pointer_r);
assign empty_s = (wr_pointer_r == rd_pointer_r);
assign data_cnt_s = (6'd32 - (wr_pointer_r - rd_pointer_r));
assign slvx_margin_o = data_cnt_s;
assign rd_en_s = a2sx_ack_i;
//-----------Code Start---------------------------------------------//
always @ (*) //ready signal
begin
if (!full_s) chx_ready_o = 1'b1; //If FIFO is not full then 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; //If FIFO is not empty then it is ready to send data
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
rd_pointer_r <= rd_pointer_r + 6'b0001;
end
end
//data output is vaild
always @ (posedge clk_i or negedge rstn_i)
begin
if (!rstn_i) slvx_val_o <= 1'b0;
else if (rd_en_s && (!empty_s))
slvx_val_o <= 1'b1;
else slvx_val_o <= 1'b0;
end
// Memory Read Block
always @ (posedge clk_i )
begin : READ_DATA
if (rstn_i && rd_en_s && (!empty_s)) begin
slvx_data_o <= mem[rd_pointer_r[4:0]];
end
end
// Memory Write Block
always @ (posedge clk_i)
begin : MEM_WRITE
if (rstn_i && chx_valid_i && chx_ready_o) begin
mem[wr_pointer_r[4:0]] <= chx_data_i;
end
end
endmodule
接口说明
input clk_i, 时钟输入
input rstn_i, 复位输入
input [31:0] chx_data_i, 外部数据输入
input a2sx_ack_i, 从仲裁器(Arbiter)获得的应答
input chx_valid_i, 外部输入的数据有效信号
output reg [31:0] slvx_data_o, 输出到仲裁器的数据
output [5:0] slvx_margin_o, 输出到外部剩余可写数据位数
output reg chx_ready_o, 输出到外部的准备信号
output reg slvx_val_o, 输出到仲裁器的数据有效信号
output reg slvx_req_o 输出到仲裁器的数据器请求发送信号
当fifo中数据不满,chx_ready_o准备接受数据信号拉高;当fifo不空,请求发送数据信号拉高。
当外部数据有效并且fifo不满,时钟上升沿地址指针加1.
当仲裁器返回应答,并且fifo非空,读指针加1.
信号说明
1、FIFO写满与读空
写满:写指针最高位取反等于读指针
读空:写指针与读指针相等
assign full_s = ({~wr_pointer_r[5],wr_pointer_r[4:0]}==rd_pointer_r);
assign empty_s = (wr_pointer_r == rd_pointer_r);
2、slvx_margin_o剩余可写数据位数
assign data_cnt_s = (6'd32 - (wr_pointer_r - rd_pointer_r));
assign slvx_margin_o = data_cnt_s;
3、数据读写
读要求仲裁器的应答信号和非空信号
写要求外都数据有效和准备写信号
// Memory Read Block
always @ (posedge clk_i )
begin : READ_DATA
if (rstn_i && rd_en_s && (!empty_s)) begin
slvx_data_o <= mem[rd_pointer_r[4:0]];
end
end
// Memory Write Block
always @ (posedge clk_i)
begin : MEM_WRITE
if (rstn_i && chx_valid_i && chx_ready_o) begin
mem[wr_pointer_r[4:0]] <= chx_data_i;
end
end
arbiter
与各个slave_fifo通讯并且判优。
module arbiter(
input clk_i,
input rstn_i,
//connect with slave port
input [31:0] slv0_data_i,
input [31:0] slv1_data_i,
input [31:0] slv2_data_i,
input slv0_req_i,
input slv1_req_i,
input slv2_req_i,
input slv0_val_i,
input slv1_val_i,
input slv2_val_i,
output a2s0_ack_o,
output a2s1_ack_o,
output a2s2_ack_o,
//Output of MCDT
output data_val_o,
output [1:0] arb_id_o,
output [31:0] arb_data_o
);
reg data_val_r;
reg [1:0] arb_id_r;
reg [31:0] arb_data_r;
reg [2:0] c_state;
reg [2:0] n_state;
//--------------------------------use FSM to implete simple Round Robin Arbiter
parameter IDLE = 3'b000,
GRANT0 = 3'b001,
GRANT1 = 3'b010,
GRANT2 = 3'b100;
always @ (posedge clk_i or negedge rstn_i)
begin
if (!rstn_i) c_state <= IDLE;
else c_state <= n_state;
end
always @ (*)
begin
if (!rstn_i) n_state = IDLE; //default priority slv0 > slv1 > slv2
else
case (c_state)
IDLE : if (slv0_req_i) n_state = GRANT0;
else if (slv1_req_i) n_state = GRANT1;
else if (slv2_req_i) n_state = GRANT2;
else n_state = IDLE;
GRANT0 : if (slv1_req_i) n_state = GRANT1;
else if (slv2_req_i) n_state = GRANT2;
else if (slv0_req_i) n_state = GRANT0;
else n_state = IDLE;
GRANT1 : if (slv2_req_i) n_state = GRANT2;
else if (slv0_req_i) n_state = GRANT0;
else if (slv1_req_i) n_state = GRANT1;
else n_state = IDLE;
GRANT2 : if (slv0_req_i) n_state = GRANT0;
else if (slv1_req_i) n_state = GRANT1;
else if (slv2_req_i) n_state = GRANT2;
else n_state = IDLE;
default : n_state = IDLE;
endcase
end
assign {a2s2_ack_o,a2s1_ack_o,a2s0_ack_o} = c_state;
// please check only one valid at a time @@ zhangshi
always @ (*)
begin
if (!rstn_i) begin
data_val_r = 1'b0;
arb_id_r = 2'b11;
arb_data_r = 32'hffff_ffff;
end
else
case ({slv2_val_i,slv1_val_i,slv0_val_i})
3'b001 : begin
data_val_r = slv0_val_i;
arb_id_r = 2'b00;
arb_data_r = slv0_data_i;
end
3'b010 : begin
data_val_r = slv1_val_i;
arb_id_r = 2'b01;
arb_data_r = slv1_data_i;
end
3'b100 : begin
data_val_r = slv2_val_i;
arb_id_r = 2'b10;
arb_data_r = slv2_data_i;
end
default : begin
data_val_r = 1'b0;
arb_id_r = 2'b11;
arb_data_r = 32'hffff_ffff;
end
endcase
end
assign data_val_o = data_val_r;
assign arb_data_o = arb_data_r;
assign arb_id_o = arb_id_r;
endmodule
接口说明:
input [31:0] slv0_data_i, 数据输入
input slv0_req_i 数据请求输入
input slv0_val_i, 数据有效是输入
output a2s0_ack_o, 应答信号输出
这样的接口输出有三组
output data_val_o, 数据有效输出
output [1:0] arb_id_o, 通道ID输出
output [31:0] arb_data_o 数据输出
实现方式:根据fifo的数据输出请求信号选择对应的状态,对应状态用独热码形式作为应答信号输出给fifo进行读数据;根据数据有效信号判断通道ID并且进行读取。