-
使用|data和data!=0 的区别
-
|data写法简单,但是漏写| 的可能,测试仿真器会检查data==1'b1
-
data!=0写法繁琐,但是辨识度高, 推荐使用
-
-
多个分之判断的代码改写(组合逻辑,时序逻辑,function 里面均可以使用)
如何理解这种设计呢, 类似在if 条件的一个判断分之下,加了一级的mux逻辑。
建议使用下面这种写法
if(exp_a)begin if(exp_b) begin end else begin end end else begin end
if(exp_a)begin data_out <= (exp_b)? xxx :xxx; end else begin end
使用下面分片的代码块,起层次关系更加明确;
防止如下问题的出现:
条件1 和 条件2 的先后优先级/ 有重叠区域 等问题。
代码出现问题很难分析
代码理解困难
代码看起来比较冗余
if(exp_a && exp_b)begin // 条件1 end else if(exp_a && (~exp_b))begin//条件2 end else if(~exp_a)begin // 条件3 end
-
Function 的使用
function automitic [msb:lsb] function_name;
input [xx:0] port_a;
input [xx:0] port_b;
logic [msb:lsb] temp_data;
logic flag;
begin
temp_data='d0;
flag=1'b0
if(xxx)begin
if(port_a ... port_b )
temp_data = xxx;
end else begin
temp_data=xxx;
end
function_name ={ temp_data,flag };
end
endfunction
-
-
在逻辑中,function 和always@(*)功能差不多,function 实现简单
-
-
Mux 是先使用还是后使用
-
对于入口数据,先mux后再使用
-
对于出口数据,先处理完成一路后与另外一路mux
-
-
Generate for的使用
genvar i; // gen many modules generate for(i=0;i<xxx;i=i+1)begin: GEN_XXX_PROC xxx_module u_xxx_modele( .port1(xxx[i]), .port2(xxx[i]), .port3(xxx[i]), .port4(xxx[i]), ); end endgenerate // gen many same logic generate for(i=0;i<xxx;i=i+1)begin: GEN_XXX_PROC always@(posedge clk)begin if(!rst_n)begin xxx[i] <= 'd0; end else begin if(....) xxx[i]<=xxx; else (...) xxx[i]<=xxx; end end end endgenerate
-
Generate if的使用
generate
if( xxx==<constant_expression>))begin:gen_exp0
end else begin:gen_exp_1
end
endgenerate
-
Generate case的使用
generate
case( xxx==<constant_expression>))begin
exp0:begin end
exp1:begin end
exp2:begin end
default:begin end
end
endgenerate
Generate if和generate case是针
对paramerter的值
做判断的
-
Integer 的使用
integer i;
//例化多个always块
for (i=0;i<xxx;i=i+1)begin
always@(*)begin
data[i] =xxx;
end
end
// 一个always 块内嵌入for loop
always@(posedge clk)begin
if(!rst_n)begin
....
end
else begin
....
else if(xxx)begin
for(i=0;i<xxx;i=i+1)begin
data[i] <=data[i+1]
end
end
end
end
-
状态机的使用
// gen cur_sts logic always@(posedge clk)begin if(!rst_n) cur_sts<=IDLE; else cur_sts<=nxt_sts; end // gen nxt_sts logic always@(*)begin case(cur_sts) IDLE:begin if(...) nxt_sts=xxx; else nxt_sts=xxx; end ...:begin end default: nex_sts=IDLE; endcase end //gen main process logic always@(posedge clk )begin if(!rst) out_data<='d0; else begin case(cur_sts) IDLE:begin if(...) out_data<=xxx; else out_data<=xxx; end ....:begin end default:out_data<='d0; endcase end end
-
Verilog part_select的使用
data[base_ptr+:length] == data[(base_Ptr+length-1'b1):base_ptr]
data[base_ptr-:length] == data[base_ptr:(base_ptr+1'b1-length)]
//example
//1。 -----------for big_endian-----------
data[0+:8] == data[7:0]
data[7-:8] == data[7:0]
//1。 -----------for little_endian-----------
data[0+:8] == data[0:7]
data[7-:8] == data[0:7]
-
字节序的高位对齐和低位对齐,大端(网络字节序)和小端大端字节序有利于硬件数据拼接处理,数据接左移后即可继续处理;大端字节序符合人类的阅读顺序;软件实现简单;硬件可以使用function实现字节序的颠倒
function automatic [63:0] bytes_rvs; input data_in[63:0]; logic [63:0] data_tmp; integer i; begin data_tmp ='d0; for (inti=0;i<8;i=i+1)begin data_tmp[(i*8)+:8] <= data_in[((7-i)*8)+:8]; end bytes_rvs = data_tmp; end endfunction
-
大端又叫网络字节序,既网络发送的高位数据最终存储在内存低地址位置
-
小端是数据发送的高位会存在内存高位地址,低位存在内存低位地址
-
一个always 只控制一个信号在一个always 内操作2个信号,若2者存在关联关系:例如epp_fin和mer_fin,如果使用if else来写,存在epp_fin 拉高后mer_fin需要采集的信号被忽略。mer_fin 会在下一包eop才拉高,造成丢包问题。解决方法: 在一个always 内控制多个信号,若2者存在一个时钟同时拉高的可能,先判断是否同时拉高,在分别判断。 或者写2组if else 条件分别处理每一个信号。
-