题解 | #非整数倍数据位宽转换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

全部评论
data_out肯定需要寄存器打拍输出,这里用的wire既不符合题意,也不符合实际业务场景;valid_out在不判断下一拍data_in的valid_in是否有效的时候,就提前拉高,没有充分考虑valid可能不连续的场景,如果在UT中多随机几次,肯定报错
点赞 回复 分享
发布于 05-04 15:25 上海

相关推荐

点赞 评论 收藏
分享
评论
2
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务