题解 | #非整数倍数据位宽转换24to128#
非整数倍数据位宽转换24to128
https://www.nowcoder.com/practice/6312169e30a645bba5d832c7313c64cc
`timescale 1ns/1ns module width_24to128( input clk , input rst_n , input valid_in , input [23:0] data_in , output reg valid_out , output reg [127:0] data_out , output reg [127:0] data_reg // output reg [3:0] cnt ); //============================================== // 这道题,注意: // 1) 非整数倍的位宽转换,要防止非整数倍的那一个数据丢数据位置。 // 因此,应当采用更大位宽的数组将需要获取的数据全部都缓存,然后再根据需要输出。 // 2) 寻找非整数倍的位宽要求,对于输入数据位宽,在拼接操作出现循环状态时候,所需要的拼接次数。 // 根据输入的特点,多个24bit的数据转换为128bit的数据, // 假设有一个位宽很大的数据buffer存放输入的24bit数据,则每轮存储情况如下: // ① 24×5+8,新输入6个24bit,余最后一个数据的后16bit,输出 buf[143:16] // ② 算上上次余下的16bit,16+24×4+16,新输入5个24bit,余下最后一数据的后8bit,输出 buf[135:8] // ③ 同理,8+5×24,新输入5个24bit,余下0bit,输出[127:0] // ④ 上一轮数据无剩余bit,也就是buf清空,状态和 ① 一样。 // ...................... // 综上所述,也就是说,经过三轮的输出,24bit的拼接状态会出现循环。 // 统计以上三轮的输入,一共是输入了 6+5+5=16 个24bit数据,由此可以以16次输入为一轮,计数0-15,这个刚好可以用4bit的寄存器,循环覆盖计数 //============================================== reg [3:0] cnt; always @(posedge clk or negedge rst_n) begin if(~rst_n) cnt <= 4'd0; else cnt <= valid_in? cnt+1'd1 : cnt; end // width: 16×24=384 // buffer reg [383:0] data_buf; always @(posedge clk or negedge rst_n) begin if(~rst_n) data_buf <= 384'h0; else data_buf <= valid_in? {data_buf[359:0], data_in} : data_buf; end // valid_out always @(posedge clk or negedge rst_n) begin if(~rst_n) valid_out <= 1'b0; else begin if(cnt==4'd5 || cnt==4'd10 || cnt==4'd15) valid_out <= 1'b1; else valid_out <= 1'b0; end end // data_out always @(*) begin if(~rst_n) data_out = 'h0; else begin if(cnt==4'd6) data_out = data_buf[143:16]; else if(cnt==4'd11) data_out = data_buf[135:8]; else if(cnt==4'd0) data_out = data_buf[127:0]; else data_out = data_out; end end endmodule
testbench
`timescale 1ns/1ns module tb; reg clk; reg rst_n; reg [23:0] data_in; reg valid_in; wire valid_out; wire [127:0] data_out; wire [3:0] cnt; // wire [127:0] data_reg; wire [383:0] q; always#5 clk = ~clk; initial begin clk = 1'b1; rst_n = 1'b0; data_in = 'b0; valid_in = 1'b0; #10; rst_n = 1'b1; #20; valid_in = 1'b1; data_in = 24'ha0a1a2; #10; data_in = 24'hb2b1b0; #10; data_in = 24'hc2c1c0; #10; data_in = 24'hd2d1d0; #10; data_in = 24'he2e1e0; #10; data_in = 24'hf2f1f0; #10; valid_in = 1'b1; #40; valid_in = 1'b1; #10; data_in = 24'ha2a1a0; #10; data_in = 24'hb2b1b0; #10; data_in = 24'hc2c1c0; #10; data_in = 24'hd2d1d0; #10; data_in = 24'he2e1e0; #40; $finish(); end width_24to128 ins ( .clk (clk), .rst_n (rst_n), .valid_in (valid_in), .data_in (data_in), .valid_out (valid_out), .data_out (data_out), // .data_reg (data_reg), .cnt (cnt), .q (q) ); endmodule