单双字节转换
简单说明
axis_8to16_pack 用于把字节流两两拼包,低字节先进 tdata[7:0],高字节后进 tdata[15:8]。当最后只有一个字节时,通过 tkeep=2'b01 表示只有低字节有效。
axis_16to8_unpack 则反向拆包,根据 tkeep 判断哪些 byte 有效,按低字节、高字节顺序输出。两个模块都严格使用 valid && ready 作为数据传输条件,避免出现丢字节、重复字节和边界错位问题。
1. axis_8to16_pack:8bit 字节流打包成 16bit AXIS
功能:每接收两个 8bit byte,拼成一个 16bit 输出;如果最后只剩 1 byte,则 tkeep=2'b01。
module axis_8to16_pack (
input wire clk_i, // 时钟
input wire rst_i, // 高有效同步复位
input wire s_valid_i, // 8bit输入valid
output wire s_ready_o, // 8bit输入ready
input wire [7:0] s_data_i, // 8bit输入数据
input wire s_last_i, // 8bit输入last
output reg m_valid_o, // 16bit输出valid
input wire m_ready_i, // 16bit输出ready
output reg [15:0] m_data_o, // 16bit输出数据
output reg [1:0] m_keep_o, // 16bit输出keep
output reg m_last_o // 16bit输出last
);
localparam [2:0] ST_IDLE = 3'b001; // 等待低字节
localparam [2:0] ST_HAVE = 3'b010; // 已缓存低字节
localparam [2:0] ST_OUT = 3'b100; // 等待输出握手
reg [2:0] state_r; // 当前状态
reg [2:0] state_next; // 下一状态
reg [7:0] byte0_r; // 低字节缓存
wire s_fire_w; // 输入握手
wire m_fire_w; // 输出握手
assign s_fire_w = s_valid_i && s_ready_o;
assign m_fire_w = m_valid_o && m_ready_i;
assign s_ready_o = (state_r == ST_IDLE) || (state_r == ST_HAVE);
//==================================================
// state register
//==================================================
always @(posedge clk_i) begin
if (rst_i) begin
state_r <= ST_IDLE;
end
else begin
state_r <= state_next;
end
end
//==================================================
// next state logic
//==================================================
always @(*) begin
state_next = state_r;
case (state_r)
ST_IDLE: begin
if (s_fire_w && s_last_i) begin
state_next = ST_OUT;
end
else if (s_fire_w) begin
state_next = ST_HAVE;
end
end
ST_HAVE: begin
if (s_fire_w) begin
state_next = ST_OUT;
end
end
ST_OUT: begin
if (m_fire_w) begin
state_next = ST_IDLE;
end
end
default: begin
state_next = ST_IDLE;
end
endcase
end
//==================================================
// output and data logic
//==================================================
always @(posedge clk_i) begin
if (rst_i) begin
byte0_r <= 8'd0;
m_valid_o <= 1'b0;
m_data_o <= 16'd0;
m_keep_o <= 2'b00;
m_last_o <= 1'b0;
end
else begin
case (state_r)
ST_IDLE: begin
m_valid_o <= 1'b0;
m_data_o <= 16'd0;
m_keep_o <= 2'b00;
m_last_o <= 1'b0;
if (s_fire_w && s_last_i) begin
m_valid_o <= 1'b1;
m_data_o <= {8'd0, s_data_i};
m_keep_o <= 2'b01;
m_last_o <= 1'b1;
end
else if (s_fire_w) begin
byte0_r <= s_data_i;
end
end
ST_HAVE: begin
if (s_fire_w) begin
m_valid_o <= 1'b1;
m_data_o <= {s_data_i, byte0_r};
m_keep_o <= 2'b11;
m_last_o <= s_last_i;
end
end
ST_OUT: begin
if (m_fire_w) begin
m_valid_o <= 1'b0;
m_data_o <= 16'd0;
m_keep_o <= 2'b00;
m_last_o <= 1'b0;
end
end
default: begin
byte0_r <= 8'd0;
m_valid_o <= 1'b0;
m_data_o <= 16'd0;
m_keep_o <= 2'b00;
m_last_o <= 1'b0;
end
endcase
end
end
endmodule
2. axis_16to8_unpack:16bit AXIS 拆成 8bit 字节流
功能:根据 tkeep 判断有效字节数,低字节先输出,高字节后输出。
module axis_16to8_unpack (
input wire clk_i, // 时钟
input wire rst_i, // 高有效同步复位
input wire s_valid_i, // 16bit输入valid
output wire s_ready_o, // 16bit输入ready
input wire [15:0] s_data_i, // 16bit输入数据
input wire [1:0] s_keep_i, // 16bit输入keep
input wire s_last_i, // 16bit输入last
output reg m_valid_o, // 8bit输出valid
input wire m_ready_i, // 8bit输出ready
output reg [7:0] m_data_o, // 8bit输出数据
output reg m_last_o // 8bit输出last
);
localparam [2:0] ST_IDLE = 3'b001; // 等待16bit输入
localparam [2:0] ST_LOW = 3'b010; // 输出低字节
localparam [2:0] ST_HIGH = 3'b100; // 输出高字节
reg [2:0] state_r; // 当前状态
reg [2:0] state_next; // 下一状态
reg [7:0] low_byte_r; // 低字节缓存
reg [7:0] high_byte_r; // 高字节缓存
reg high_valid_r; // 高字节有效
reg last_r; // last缓存
wire s_fire_w; // 输入握手
wire m_fire_w; // 输出握手
assign s_fire_w = s_valid_i && s_ready_o;
assign m_fire_w = m_valid_o && m_ready_i;
assign s_ready_o = (state_r == ST_IDLE);
//==================================================
// state register
//==================================================
always @(posedge clk_i) begin
if (rst_i) begin
state_r <= ST_IDLE;
end
else begin
state_r <= state_next;
end
end
//==================================================
// next state logic
//==================================================
always @(*) begin
state_next = state_r;
case (state_r)
ST_IDLE: begin
if (s_fire_w && s_keep_i[0]) begin
state_next = ST_LOW;
end
else if (s_fire_w && s_keep_i[1]) begin
state_next = ST_HIGH;
end
end
ST_LOW: begin
if (m_fire_w && high_valid_r) begin
state_next = ST_HIGH;
end
else if (m_fire_w) begin
state_next = ST_IDLE;
end
end
ST_HIGH: begin
if (m_fire_w) begin
state_next = ST_IDLE;
end
end
default: begin
state_next = ST_IDLE;
end
endcase
end
//==================================================
// output and data logic
//==================================================
always @(posedge clk_i) begin
if (rst_i) begin
low_byte_r <= 8'd0;
high_byte_r <= 8'd0;
high_valid_r <= 1'b0;
last_r <= 1'b0;
m_valid_o <= 1'b0;
m_data_o <= 8'd0;
m_last_o <= 1'b0;
end
else begin
case (state_r)
ST_IDLE: begin
m_valid_o <= 1'b0;
m_data_o <= 8'd0;
m_last_o <= 1'b0;
if (s_fire_w) begin
low_byte_r <= s_data_i[7:0];
high_byte_r <= s_data_i[15:8];
high_valid_r <= s_keep_i[1];
last_r <= s_last_i;
end
end
ST_LOW: begin
m_valid_o <= 1'b1;
m_data_o <= low_byte_r;
m_last_o <= last_r && !high_valid_r;
if (m_fire_w) begin
m_valid_o <= 1'b0;
end
end
ST_HIGH: begin
m_valid_o <= 1'b1;
m_data_o <= high_byte_r;
m_last_o <= last_r;
if (m_fire_w) begin
high_valid_r <= 1'b0;
m_valid_o <= 1'b0;
m_last_o <= 1'b0;
end
end
default: begin
low_byte_r <= 8'd0;
high_byte_r <= 8'd0;
high_valid_r <= 1'b0;
last_r <= 1'b0;
m_valid_o <= 1'b0;
m_data_o <= 8'd0;
m_last_o <= 1'b0;
end
endcase
end
end
endmodule

浙公网安备 33010602011771号