Verilog位宽操作技巧----拼接与截位

在FPGA开发中,经常可能会涉及到位宽截取;比如一个信号定义一个信号A[15:0],在实际使用的时候有时候只需要截取高8位,那么就是A[15:8],或者截取低8位A[7:0]。这是一种最常见的使用场景,对于一个入门级的FPGA工程师都没什么问题。这篇文章主要介绍几种与位宽操作实用但又稍微冷门的几个场景。

一、复制拼接

    拼接的意思是将几个短位宽的数据拼接成更大位宽的数据。比如:A = 4'h5  B = 4'hA ; 将A与 B 拼接在一起就是{A,B} = 8'h5A。这是最常见的拼接操作,但是如果我们需要将A和B重复拼接32次呢?如果重复敲32个{A,B}是不是显得有点蠢。Verilog也考虑到这一场景,给出了一个复制拼接的用法,具体如下:

C = {32{A,B}} ;
等效为
C= {{A,B},{A,B},......,{A,B}} //共32次

两层拼接符,内层拼接符外面的数字代表复制的次数;将{A,B}作为一个整体,重复拼接32次;

如果将32定义为一个parameter,这样代码更直观、更利于维护。需注意的是:这里的复制的次数一定得是常量,不可以是变量reg / wire ;
 

parameter    copy_num  = 8'd32 ;

assign C = {copy_num{A,B}};

二、移位拼接

    移位拼接是一种作为移位寄存器 经常使用方法;

   假设需求如下,要从输入的串行序列中寻找固定的编码段4‘b1011,那么就需要将串行的数据转并行,最直接的实现方法可能是:

always@(posedge clk)begin
    A[0] <= Din ;
    A[1] <= A[0] ;
    A[2] <= A[1] ;
    A[3] <= A[2] ;
end

这样写自然也没什么问题,做边沿检测或者跨时钟域处理,只需要缓存个2~3clk的时候我也倾向直接这么用,

但是当这个移位寄存器的位宽太大的时候,比如超过10 或者更大,这么写就显得代码臃肿,这时候有没有更好的选择呢?

当然,移位拼接就是更好的选择:

向左移位
always@(posedge clk)begin
    A[3:0] <= {A[2:0],Din};
end
向右移位
always@(posedge clk)begin
    A[3:0] <= {Din,A[3:1]};
end

三、位截取

按照IEEE Verilog的标准,向量的位宽截取分为 按位截取(bit-select) 和 按块截取(part-select)

按位截取可能是大多数人更常用的一种方式,这里不多赘述;

A[15:0]
截取高8位:
B = A[15:8]

这里重点说一下Part-Select这种模式,如上图所示:

也就是说,part-select这种模式有两个关键表达式:base_expr 和 width_expr ; 一个关键的操作符 +: 或 -:

base_expr简单来说就是基地址,width_expr是宽度;通过“+:” 或 “-: ” 来控制方向;

其中,基地址可以是变量,但宽度一定是正整数常量

由于part-select的这种特征,对于长位宽信号,拆分为多个小位宽信号就非常友好,比如:

// part-select实现
reg [255:0]  A;
//现需要将A拆分成 16 个 16bit的信号,我们可以这样做
reg [15:0] B[15:0] ;
integer i;
for(i=0;i<=15;i<=i+1)begin
    assign B[i] = A[i*16 +: 16] ; 
end

如果是传统的方法,那将会是这样:

// part-select实现
reg [255:0]  A;
//现需要将A拆分成 16 个 16bit的信号,我们可以这样做
reg [15:0] B[15:0] ;

assign B[0] = A[15:0] ;
assign B[1] = A[31:16] ; 
assign B[2] = A[47:32] ; 
....
assign B[15] = A[255:240] ;  

两种方法一对比,从代码的书写量、可读性、可维护性各方面,高下立判。

而且两种方法实现的电路是一模一样,并不会说用这种“投机取巧”的方法,就会增加电路实现的负担。

Verilog拼接是指在Verilog HDL中将多个信号或变量连接在一起形成一个更大的信号或变量的操作拼接操作使用“{ }”符号来表示,其中括号内的信号或变量按照顺序连接在一起。拼接操作可以用于连接向量、数组、结构体等不同类型的信号或变量。通过拼接操作,可以方便地将多个信号或变量组合在一起,以满足特定的设计需求。例如,下面是一个使用Verilog拼接操作的例子: ```verilog module Example_Concatenation(input \[3:0\] a, input \[3:0\] b, output \[7:0\] c); assign c = {a, b}; endmodule ``` 在上述例子中,输入信号a和b都是4向量,输出信号c是8向量。通过拼接操作`{a, b}`,将输入信号a和b连接在一起形成输出信号c。因此,当输入信号a为`0101`,输入信号b为`0011`时,输出信号c将为`01010011`。\[1\] 需要注意的是,拼接操作要求被连接的信号或变量的数必须满足拼接后的数要求,否则会导致编译错误。此外,拼接操作还可以用于连接不同类型的信号或变量,但需要保证类型兼容性。\[2\] 总之,Verilog拼接是一种在Verilog HDL中将多个信号或变量连接在一起形成一个更大的信号或变量的操作,通过使用`{ }`符号进行拼接。这种操作可以方便地组合多个信号或变量,以满足特定的设计需求。 #### 引用[.reference_title] - *1* *2* [(118)Verilog[拼接运算设计]](https://blog.csdn.net/m0_46498597/article/details/129658898)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [verilog基础运算——拼接运算、全加器、阻塞非阻塞、D触发器、移寄存器、8-3编码器、3-8解码器等](https://blog.csdn.net/H19981118/article/details/115317794)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值