单双字节转换

简单说明

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

posted @ 2026-07-03 11:02  Oppenic  阅读(8)  评论(0)    收藏  举报