写代码:
下面的myhdl代码写了一个模块top,里面有两个计数器:cnt1从0计到9,当cnt1=9时,cnt2从0计到4。
from myhdl import *
@block
def top(cnt1, cnt2, clk, rst_n):
"""
this is an example of counter
"""
@always_seq(clk.posedge, reset=rst_n)
def counter1():
if cnt1 == 9:
cnt1.next = 0
else:
cnt1.next = cnt1 + 1
@always(clk.posedge, rst_n.negedge)
def counter2():
if rst_n == 0:
cnt2.next = 5
elif cnt1 == 9:
if cnt2 == 4:
cnt2.next = 0
else:
cnt2.next = cnt2 + 1
return counter1, counter2
从上面的代码可以看到其实与verilog非常接近,只是复位和时钟在python装饰器always和always_seq里实现了。另一个特殊点是,给一个信号赋值需要用xxx.next,这样就描述了DFF的功能,赋的值下一个时钟生效。
转Verilog:
我们用下面的方法来把myhdl转成verilog:
def convert():
cnt1 = Signal(intbv(0,0,16))
cnt2 = Signal(intbv(0,0,8))
clk = Signal(bool(0))
rst_n = ResetSignal(0, active=0, isasync=True)
dut = top(cnt1, cnt2, clk, rst_n)
dut.convert(hdl='verilog')
convert()
直接上效果,不解释了,大家自己看:
// File: top.v
// Generated by MyHDL 0.11
// Date: Sat Feb 26 21:29:06 2022
`timescale 1ns/10ps
module top (
cnt1,
cnt2,
clk,
rst_n
);
// this is an example of counter
output [3:0] cnt1;
reg [3:0] cnt1;
output [2:0] cnt2;
reg [2:0] cnt2;
input clk;
input rst_n;
always @(posedge clk, negedge rst_n) begin: TOP_COUNTER1
if (rst_n == 0) begin
cnt1 <= 0;
end
else begin
if ((cnt1 == 9)) begin
cnt1 <= 0;
end
else begin
cnt1 <= (cnt1 + 1);
end
end
end
always @(posedge clk, negedge rst_n) begin: TOP_COUNTER2
if ((rst_n == 0)) begin
cnt2 <= 5;
end
else if ((cnt1 == 9)) begin
if ((cnt2 == 4)) begin
cnt2 <= 0;
end
else begin
cnt2 <= (cnt2 + 1);
end
end
end
endmodule
写验证环境,仿真:
from random import randrange
def testbench():
cnt1 = Signal(intbv(0,0,16))
cnt2 = Signal(intbv(0,0,8))
clk = Signal(bool(0))
rst_n = ResetSignal(0, active=0, isasync=True)
dut = top(cnt1, cnt2, clk, rst_n)
@always(delay(10))
def clkgen():
clk.next = not clk
@instance
def rstgen():
yield delay(15)
rst_n.next = 1
return dut, clkgen, rstgen
def simulate(timesteps):
tb = traceSignals(testbench)
sim = Simulation(tb)
sim.run(timesteps)
simulate(2000)
与Verilog的验证环境没有太大区别,实例化、编写时钟、复位等激励,设置dump波形,仿真时间等。
看波形:
运行后目录下产生testbench.vcd。用Verdi打开如下图: