Verdi波形查看transaction
除了以下两个选项以外,
+UVM_TR_RECORD
+UVM_LOG_RECORD
还需要声明+UVM_VERDI_TRACE选项
+UVM_VERDI_TRACE=UVM_AWARE+RAL+TLM+MSG+HIER+PRINT
否则使用的是VC的环境抓取,而不是Verdi环境。(Verdi Transaction debug)
门控时钟
时钟门控如果仅仅使用一个与门操作,则在复位毛刺出现以后,导致时钟毛刺,导致时序错误。
为了解决复位毛刺,引入锁存器、寄存器的方案。不管引入何种方案,都会引入额外的竞争冒险。
因此需要额外考虑建立保持时间的满足。
https://zhuanlan.zhihu.com/p/139363948
寄存器相比锁存器,建立保持时间更容易满足,但是额外引入了一个单元增大了面积,加之锁存器往往采用cell工艺库实现,不存在skew问题,建立保持时间容易得到满足。因而广泛采用的是锁存器。
时钟门控也可以使用rtl直接编写,但是我觉得还是用库更安全。
时钟切换
时钟切换也有一套自己的逻辑。如果直接切换是不对的。如果有工艺库,我觉得还是用工艺库吧。
引入以下链接,其实写的并不清晰,重要信息和逻辑性缺乏,难以理解。
https://mp.weixin.qq.com/s/uGpon0hVjSiLSQV3zrFSjA
但是以下信息是明确的:
如果直接使用简单粗暴的代码进行时钟切换:
assign outclock = select? clk1: clk0;
这种写法是肯定会产生毛刺的,这对整个芯片系统是很危险的,很容易进入亚稳态的情况,系统很容易bug。(本质上还是select的问题,select要是往后移动一些,在两个时钟都为高的情况下切换,就可以的)
所以设计时钟切换也有它的一套复杂逻辑。
vcs的ucli
ucli是vcs自有的一些库,用于在tcl环境下调用,也遵守tcl语法。典型的fsdbDumpVars等命令,从灵活性考虑,也使用ucli更为方便。
对于函数调用部分,有一些限制,但是也许有用。
在init的代码处调试
在以下代码直接执行后,static 的function F应该是自动执行了一次。
module mod1;
class C;
static int I=F();
static function int F();
logic log1;
begin
log1 = 1;
$display("%m log1=%0b",log1);
$display("In function F");
F = 10;
end
endfunction
endclass
endmodule
而使用ucli,可以添加断点,然后执行:
先进入init部分
./simv -ucli=init
进入后,先添加断点。C为函数类名,F为静态方法。
init%stop -in \C::F
然后执行一个0时间,则调到该类的静态方法处停止
init%run 0
再执行一个0时间,则执行了该静态方法,然后退出到ucli
init%run 0
ucli%
使用调用,仍可再次触发
ucli% \C::F
内部调用函数
对于以下代码,不使用-R选项编译和运行,而是单独分开,先编译。
program P1;
integer i=1;
class c;
task prg_tsk_int(int n1 = 10);
$display("prg_tsk_int n1 = %0d",n1);
endtask
function int prg_func_int(int n2 = 12);
$display("prg_func_int n2 = %0d",n2);
return 1;
endfunction
endclass
c c1=new();
initial begin
#2
c1.prg_tsk_int(i);
c1.prg_func_int(i);
end
endprogram
运行的时候,使用以下:
simv -ucli
运行到initial里面
run 1
调用函数
call {c1.prg_tsk_int(100)}
根据以上:
通过使用call调用一些function修改class的值,然后再触发sequence,达到不同sequence的效果。
斐波那契LFSR和伽罗瓦LFSR
LFSR(线性反馈移位寄存器),它的作用是产生伪随机数。伪随机数的用处是可以在编码和解码的时候使用。
在PCIe的差分系统中,数据流中出现重复的序列后,导致较强的EMI干扰(电磁干扰,Electromagnetic Interference,EMI),进行扰码随机化后,EMI的噪声会减弱。(频谱被展宽)
PCIe 内部存在扰码器。扰码器需要初始值相同,才能在发送端和接收端通信。因此PCIe 设备使用COM字符,使得发送端和接收端都能识别,对初始值进行设定。
由于LFSR在每个周期都会进行更新,因此需要暂停的时候需要进行处理。在PCIe中,数据流添加了SKIP字符,该字符是不需要进行扰码和解扰处理的,因此这些字符出现时,LFSR将进入暂停状态。
多项式和生成序列
从视频中截取:
https://www.bilibili.com/video/BV1k94y1x7Bu/?spm_id_from=333.337.search-card.all.click&vd_source=0b160b3f23f010d84a4c31e761257ea4
线性移位寄存器,本质是寄存器,使用线性(异或操作)和移位,实现寄存器的随机性。
对生成序列产生影响的位置叫抽头。
在以下4级LFSR中,C4=C1=C0=1,右边的C1和C0做异或操作,移动到C4的位置。
在多项式右上角的标号,应该仅仅是一个标号,而不是一个次方的意义,只是表示哪些地方应该做异或操作,然后将异或结果移动到哪里。
斐波那契和伽瓦罗
● 斐波那契是多个触发器的输出通过异或逻辑,控制一个触发器的输入(多项式和生成序列中的例子)。
● 伽瓦罗是一个触发器的输出通过异或逻辑,控制多个触发器的串行输入。
伽罗瓦LFSR具有更高的速度,因为两个触发器之间只有一个异或门。斐波那契LFSR在首尾两个寄存器之间有多个异或门,组合逻辑延时更大,因为为了满足建立保持时间的要求,其频率更小(周期更大),速度更慢。
斐波那契
https://zhuanlan.zhihu.com/p/620450000
以三级LFSR,反馈函数为: 为例
从左到右依次递减编号:
从左到右依次递增编号:
伽瓦罗
https://zhuanlan.zhihu.com/p/620450000
以三级LFSR,反馈函数为: 为例:
从左到右依次递减编号:
从左到右依次递增编号:
CRC8 CCITT算法
伽瓦罗,多项式为X^8 +X^2+X+1
PCIe的扰码电路
工作波形: