Verilog 用户定义原语
标准 Verilog 原语,例如 nand
和 not
可能并不总是容易或足以表示复杂的逻辑。称为 UDP 的新原始元素 或用户定义的原语 可以定义为对组合逻辑或顺序逻辑进行建模。
所有 UDP 都只有一个输出,可以是 0、1 或 X,而不是 Z(不支持)。任何具有值 Z 的输入都将被视为 X。
Verilog UDP 符号
Verilog 用户定义的原语可以写在与 module 相同的级别 定义,但从不在 module
之间 和 endmodule
.它们可以有多个输入端口,但始终只有一个输出端口,双向端口无效。所有端口信号都必须是标量,这意味着它们必须是 1 位宽。
硬件行为被描述为原语 状态表,列出了 table
中不同可能的输入组合及其对应的输出 和 endtable
.输入输出信号的值用以下符号表示。
符号 | 评论 |
---|---|
0 | 逻辑 0 |
1 | 逻辑1 |
x | 未知,可为逻辑0或1。可用作顺序UDP的输入/输出或当前状态 |
? | 逻辑 0、1 或 x。不能输出任何UDP |
- | 无变化,仅允许在 UDP 的输出中 |
ab | 从 a 到 b 的值变化,其中 a 或 b 为 0、1 或 x |
* | 同??,表示输入值有任何变化 |
r | 同 01 -> 输入上升沿 |
f | 与 10 相同 -> 输入下降沿 |
p | 输入的潜在上升沿; 0->1、0->x 或 x->1 |
n | 输入的潜在下降沿; 1->0, x->0, 1->x |
组合 UDP 示例
// Output should always be the first signal in port list
primitive mux (out, sel, a, b);
output out;
input sel, a, b;
table
// sel a b out
0 1 ? : 1;
0 0 ? : 0;
1 ? 0 : 0;
1 ? 1 : 1;
x 0 0 : 0;
x 1 1 : 1;
endtable
endprimitive
?
表示信号可以是 0、1 或 x,与决定最终输出无关。
下面显示的是一个测试平台模块,它实例化了 UDP 并向其应用输入刺激。
module tb;
reg sel, a, b;
reg [2:0] dly;
wire out;
integer i;
// Instantiate the UDP - note that UDPs cannot
// be instantiated with port name connection
mux u_mux ( out, sel, a, b);
initial begin
a <= 0;
b <= 0;
$monitor("[T=%0t] a=%0b b=%0b sel=%0b out=%0b", $time, a, b, sel, out);
// Drive a, b, and sel after different random delays
for (i = 0; i < 10; i = i + 1) begin
dly = $random;
#(dly) a <= $random;
dly = $random;
#(dly) b <= $random;
dly = $random;
#(dly) sel <= $random;
end
end
endmodule
<无脚本> 模拟日志xcelium> run [T=0] a=0 b=0 sel=x out=0 [T=4] a=1 b=0 sel=x out=x [T=5] a=1 b=1 sel=x out=1 [T=10] a=1 b=1 sel=1 out=1 [T=15] a=0 b=1 sel=1 out=1 [T=28] a=0 b=0 sel=1 out=0 [T=33] a=0 b=0 sel=0 out=0 [T=38] a=1 b=0 sel=0 out=1 [T=40] a=1 b=1 sel=0 out=1 [T=51] a=1 b=1 sel=1 out=1 [T=54] a=0 b=0 sel=1 out=0 [T=62] a=1 b=0 sel=1 out=0 [T=67] a=1 b=1 sel=1 out=1 [T=72] a=0 b=1 sel=1 out=1 [T=80] a=0 b=1 sel=0 out=0 [T=84] a=0 b=0 sel=0 out=0 [T=85] a=1 b=0 sel=0 out=1 xmsim: *W,RNQUIE: Simulation is complete.
顺序 UDP 示例
顺序逻辑可以是电平敏感或边沿敏感,因此有两种顺序 UDP。输出端口也应该声明为 reg
在 UDP 定义中键入,并且可以选择在 initial
中初始化 声明。
顺序 UDP 在输入和输出字段之间有一个附加字段,由 :
分隔 代表当前状态。
级别敏感的 UDPs
primitive d_latch (q, clk, d);
output q;
input clk, d;
reg q;
table
// clk d q q+
1 1 : ? : 1;
1 0 : ? : 0;
0 ? : ? : -;
endtable
endprimitive
在上表中,连字符 -
表的最后一行表示 q+ 的值没有变化。
module tb;
reg clk, d;
reg [1:0] dly;
wire q;
integer i;
d_latch u_latch (q, clk, d);
always #10 clk = ~clk;
initial begin
clk = 0;
$monitor ("[T=%0t] clk=%0b d=%0b q=%0b", $time, clk, d, q);
#10; // To see the effect of X
for (i = 0; i < 50; i = i+1) begin
dly = $random;
#(dly) d <= $random;
end
#20 $finish;
end
endmodule
<无脚本> 模拟日志xcelium> run [T=0] clk=0 d=x q=x [T=10] clk=1 d=1 q=1 [T=13] clk=1 d=0 q=0 [T=14] clk=1 d=1 q=1 [T=17] clk=1 d=0 q=0 [T=20] clk=0 d=1 q=0 [T=28] clk=0 d=0 q=0 [T=30] clk=1 d=1 q=1 [T=38] clk=1 d=0 q=0 [T=39] clk=1 d=1 q=1 [T=40] clk=0 d=1 q=1 [T=42] clk=0 d=0 q=1 [T=47] clk=0 d=1 q=1 [T=50] clk=1 d=0 q=0 [T=55] clk=1 d=1 q=1 [T=59] clk=1 d=0 q=0 [T=60] clk=0 d=0 q=0 [T=61] clk=0 d=1 q=0 [T=64] clk=0 d=0 q=0 [T=67] clk=0 d=1 q=0 [T=70] clk=1 d=0 q=0 [T=73] clk=1 d=1 q=1 [T=74] clk=1 d=0 q=0 [T=77] clk=1 d=1 q=1 [T=79] clk=1 d=0 q=0 [T=80] clk=0 d=0 q=0 [T=84] clk=0 d=1 q=0 [T=86] clk=0 d=0 q=0 [T=87] clk=0 d=1 q=0 [T=90] clk=1 d=1 q=1 [T=91] clk=1 d=0 q=0 [T=100] clk=0 d=0 q=0 [T=110] clk=1 d=0 q=0 Simulation complete via $finish(1) at time 111 NS + 0
边缘敏感的 UDPs
在下面显示的示例中,D 触发器被建模为 Verilog 用户定义的原语。请注意,时钟的上升沿由 01
指定 或 0?
primitive d_flop (q, clk, d);
output q;
input clk, d;
reg q;
table
// clk d q q+
// obtain output on rising edge of clk
(01) 0 : ? : 0;
(01) 1 : ? : 1;
(0?) 1 : 1 : 1;
(0?) 0 : 0 : 0;
// ignore negative edge of clk
(?0) ? : ? : -;
// ignore data changes on steady clk
? (??): ? : -;
endtable
endprimitive
在测试台中,UDP被实例化并在随机时钟数后使用随机d输入值驱动。
module tb;
reg clk, d;
reg [1:0] dly;
wire q;
integer i;
d_flop u_flop (q, clk, d);
always #10 clk = ~clk;
initial begin
clk = 0;
$monitor ("[T=%0t] clk=%0b d=%0b q=%0b", $time, clk, d, q);
#10; // To see the effect of X
for (i = 0; i < 20; i = i+1) begin
dly = $random;
repeat(dly) @(posedge clk);
d <= $random;
end
#20 $finish;
end
endmodule
从图中可以看出,输出 q 在 1 个时钟延迟后跟随输入 d,这是 D 触发器所期望的行为。
<无脚本> 模拟日志xcelium> run [T=0] clk=0 d=x q=x [T=10] clk=1 d=1 q=x [T=20] clk=0 d=1 q=x [T=30] clk=1 d=1 q=1 [T=40] clk=0 d=1 q=1 [T=50] clk=1 d=1 q=1 [T=60] clk=0 d=1 q=1 [T=70] clk=1 d=0 q=1 [T=80] clk=0 d=0 q=1 [T=90] clk=1 d=1 q=0 [T=100] clk=0 d=1 q=0 [T=110] clk=1 d=1 q=1 [T=120] clk=0 d=1 q=1 [T=130] clk=1 d=1 q=1 [T=140] clk=0 d=1 q=1 [T=150] clk=1 d=0 q=1 [T=160] clk=0 d=0 q=1 [T=170] clk=1 d=0 q=0 [T=180] clk=0 d=0 q=0 [T=190] clk=1 d=0 q=0 [T=200] clk=0 d=0 q=0 [T=210] clk=1 d=1 q=0 [T=220] clk=0 d=1 q=0 [T=230] clk=1 d=1 q=1 [T=240] clk=0 d=1 q=1 [T=250] clk=1 d=1 q=1 [T=260] clk=0 d=1 q=1 [T=270] clk=1 d=1 q=1 [T=280] clk=0 d=1 q=1 [T=290] clk=1 d=1 q=1 [T=300] clk=0 d=1 q=1 [T=310] clk=1 d=1 q=1 [T=320] clk=0 d=1 q=1 [T=330] clk=1 d=1 q=1 [T=340] clk=0 d=1 q=1 [T=350] clk=1 d=1 q=1 [T=360] clk=0 d=1 q=1 [T=370] clk=1 d=0 q=1 [T=380] clk=0 d=0 q=1 [T=390] clk=1 d=0 q=0 [T=400] clk=0 d=0 q=0 [T=410] clk=1 d=1 q=0 [T=420] clk=0 d=1 q=0 [T=430] clk=1 d=1 q=1 [T=440] clk=0 d=1 q=1 [T=450] clk=1 d=1 q=1 [T=460] clk=0 d=1 q=1 [T=470] clk=1 d=1 q=1 [T=480] clk=0 d=1 q=1 Simulation complete via $finish(1) at time 490 NS + 0
Verilog