`timescale 1ns/1ns
module test_dm ;
reg clk=0,rst =0,bus_wr=0 ;
reg [1:0] bus_addr =0;
reg [31:0] bus_din=0;
wire [31:0] bus_dout ;
wire [71:0] m_cmd;
wire m_valid;
reg m_ready=0 ;
reg [7:0]s_sts ;
reg s_valid=0;
wire s_ready;
reg error=0;
wire rstn ;
task wr_reg ;
input [1:0]addr;
input [31:0] value;
begin
bus_din = value ;
bus_addr = addr ;
@(posedge clk);bus_wr = 0;
@(posedge clk);bus_wr = 1;
@(posedge clk);bus_wr = 0;
end
endtask
always #5 clk = ~clk ;
initial begin
rst =1;
#20 ; rst =0;
#20;
wr_reg( 0 ,0 );
wr_reg (1, 250);
wr_reg (2, 7);
end
dm_ctlr #(16) DM_CNTLR(
.clk( clk ),
.rst( rst ),
.bus_wr( bus_wr ),
.bus_addr(bus_addr ),
.bus_din(bus_din ),
.bus_dout(bus_dout ) ,
.m_cmd( m_cmd ),
.m_valid(m_valid ) ,
.m_ready(1 ) ,
// .m_ready( m_ready ) ,
.s_sts( s_sts ),
.s_valid( s_valid ),
.s_ready(s_ready ),
.error(error ) ,
.rstn(rstn )
);
endmodule
/*
datamover_ctlr #(16) DM_CNTLR(
.clk( clk ),
.rst( rst ),
.bus_wr( bus_wr ),
.bus_addr(bus_addr ),
.bus_din(bus_din ),
.bus_dout(bus_dout ) ,
.m_cmd( m_cmd ),
.m_valid(m_valid ) ,
.m_ready( m_ready ) ,
.s_sts( s_sts ),
.s_valid( s_valid ),
.s_ready(s_ready ),
.error(error ) ,
.rstn(rstn )
);
*/
module dm_ctlr #(
parameter MAX_BYTES_IN_CMD = 4096
)(
input clk,
input rst,
input bus_wr,
input [1:0] bus_addr,
input [31:0] bus_din,
output reg [31:0]bus_dout ,
output reg [71:0] m_cmd=0 ,
output reg m_valid ,
input m_ready ,
input [7:0]s_sts,
input s_valid,
output reg s_ready,
input error ,
output reg rstn
);
reg local_rst ;
always @ (posedge clk)
local_rst <= ( rst == 1) ||(rstn == 0 );
reg [31:0] addr ,len ;
reg need_eof,incr,en ;
reg [7:0] st ;
reg [31:0] cur_addr , remain_len ;
always@(posedge clk)
if (bus_wr)
case (bus_addr)
0: addr <= bus_din ;
1: len <= bus_din ;
2: begin en <= bus_din[0]; incr<=bus_din[1]; need_eof<=bus_din[2]; end
endcase
always@(posedge clk)
rstn <= ~( (bus_wr==1 ) && (bus_addr[1:0]==3) && (bus_din[0]==1)) ;
always@(posedge clk ) s_ready<= 1;//s_valid ;
reg [8:0 ] last_sts ;
always@(posedge clk )
if (s_ready&s_valid)
last_sts <= {error,s_sts[7:0]} ;
reg [31:0] cntr ;
always@*
case (bus_addr)
0 : bus_dout <= last_sts ;
1 : bus_dout <= cntr ;
default bus_dout<='hx ;
endcase
always @ (posedge clk )
if ((en==0)||(local_rst==1)) cntr <=0;else
if (st==11) cntr<=1+cntr ;
always @ (posedge clk) m_cmd[23]<= incr;
always @ (posedge clk)
case (st)
10,11 :m_cmd[31]<=(1==need_eof) ;
default m_cmd[31]<=0;
endcase
always @* m_cmd[71:64] <=0 ;
always @* m_cmd[31:24] <=0 ;
always @ (posedge clk)
case (st)
3,10: m_cmd[63:32] = cur_addr ;
endcase
always @ (posedge clk)
case (st)
3:m_cmd[22:0] = MAX_BYTES_IN_CMD ;
10:m_cmd[22:0] = remain_len ;
endcase
always @ (posedge clk)
case (st)
3,10 : m_valid<=1;
4,11 : if (m_ready) m_valid <=0;
default m_valid<=0;
endcase
always @ (posedge clk)
case (st)
3:begin cur_addr<=cur_addr+MAX_BYTES_IN_CMD; remain_len<=remain_len-MAX_BYTES_IN_CMD;end
1:begin cur_addr <= addr; remain_len<=len ;end
endcase
always @ (posedge clk)
if (local_rst) st<=0;else
case ( st )
0 : if ( en ) st<=1;
1 : st<=2; //保存寄存器
2 : if (remain_len > MAX_BYTES_IN_CMD ) st<=3 ; else st<=10;// 分支检测是否是最后一个命令
3 : st<=4; // 设置valid // 更新计数器
4 : if (m_ready) st<=2; // 检查ready
//处理最后一个命令
10: st<=11;//设置valid
11: st<=11; //if (m_ready) st<=0; //检查ready
default st<=0;
endcase
endmodule