常用网站:
定义一个模块
module name(varible, ...); // 定义一个模块
// 模块逻辑
endmodule // 模块结束
输入标识符:input
,输出标识符:output
module name(
input a,b,
output c,d
);
赋值语句
assign x = y;
与、或、非、异或、同或
assign out = !in; // 非门,C语言写法
assign out = ~in;
assign out = a & b; // 与门
assign out = a | b; // 或门
assign out = a ^ b; // 异或门
assign out = !(a ^ b); // 同或门
线网型信号:wire
,一般用来表示中间信号
wire a, b, c;
向量:将一组相关的信号用一个向量名称统一命名的方式
wire [7:0] w; // 表示一个8bit的向量信号w
向量拼接:{}
,用于将向量进行拼接
d[2:0] = {a[0], b[1], c[1]}; // 表示d向量的第一位是a[0],第二位是b[1],第三位是c[1]
表示自定义
bit
的写法:n'bxxx..xxx
:表示共有n位,每位为x,其中b
表示的是binary
复制算子:取连续值的情况
{5{1'b1}} // 5'b11111
{2{a,b,c}} // The same as {a,b,c,a,b,c}
{3'd5, {2{3'd6}}} // 9'b101_110_110
模块调用:父模块调用子模块
module top_module( // 父模块
input a,
input b,
output out
);
mod_a mymod( // 调用子模块 mymod为子模块实例化名称
.in1 (a), // 端口对应
.in2 (b),
.out (out));
endmodule
module mod_a ( // 子模块
input in1,
input in2,
output out
);
assign out = in1 & in2;
endmodule
always
块语法格式
always@()
,与assign
语句等效
assign
语句只能对一个信号进行赋值,always
块内可对多个信号进行赋值assign
语句中被赋值信号为wire
类型,always
块内被赋值信号需定义为reg
类型always
块内支持更加丰富的语法,如使用if…else..、case
等适合实现交复杂的组合逻辑module my (input a, input b, output reg out);
always@(a, b) out = a & b;
endmodule
always@(posedge clk || negedge clk)
x = y;
),该赋值方式只能用在过程块(如always@(*)
)内x <= y;
),该赋值方式只能用在过程块内(如always@(posedge clk)
)在设计
Verilog
模块时,请遵循以下原则:
- 在组合逻辑的always块内采用阻塞赋值
- 时序逻辑的always块内采用非阻塞赋值
if...else
:控制语句,if
语句用于过程块内部,其对应的电路是二选一的选择器
// 在`assign`中
assign out = (condition) ? x : y;
// 在`always`中
always@(*)
begin
if (condition) out = x;
else if (condition) out = y;
else out = z;
end
case
:条件语句
case (condition):
a:
b:
c:
endcase
debug
:调试,$display
, $strobe
, $monitor
,使用$finish
去结束这个仿真。
initial
:从仿真0开始执行,在整个仿真过程中只执行一次;如果一个模块中包含了多个initial
,则这些initial
块从仿真0时刻开始并发执行,且每个块执行是各自独立的,一本在块中使用begin
和end
定义范围域
initial
begin
//;
end
暂时先学这么多,等后面有不懂的再回头看。
来看看verilator
官方给的与C++
交互的例子
mkdir test_our
cd test_our
cat >our.v <<'EOF'
module our; # 定义一个module
initial # 定义一个initial块
begin # initial块的开始
$display("Hello World"); # debug输出Hello World
$finish; # debug完成
end # initial块的结束
endmodule # our模块的结束
EOF
cat >sim_main.cpp <<'EOF'
#include "Vour.h" # our.v被verilator编译成Vour.h
#include "verilated.h" # verialtor官方库
int main(int argc, char** argv, char** env) {
VerilatedContext* contextp = new VerilatedContext; # verilator上下文指针
contextp->commandArgs(argc, argv); # 检查参数
Vour* top = new Vour{contextp}; # 实例化our模块
while (!contextp->gotFinish()) { # 一直到contextp仿真完成才退出
top->eval(); # 更新电路状态
}
delete top;
delete contextp;
return 0;
}
EOF
编译
verilator -Wall --cc --exe --build sim_main.cpp our.v
-Wall
:让verilator
执行强类型警告--cc
:得到C++
输出--exe
:和wrapper
文件一起,为了创建一个可执行文件--build
:让verilator
能让自己执行运行程序
./obj_dir/Vour
Hello World
- our.v:2: Verilog $finish
处理器内部一般有一个PC寄存器,其中存储指令地址,正常运行过程中,PC的值会随时间增加,同时从指令寄存器中取出相应地址的指令,因此,在此实现处理器的取指令电路,包含两部分:PC模块、指令存储器
module pc_reg(
input wire clk,
input wire rst,
output reg[5:0] pc,
output reg ce
);
always@(posedge clk) begin
if (rst == 1'b1) begin
ce <= 1'b0; // 复位信号有效时,指令存储器使能信号无效
end else begin
ce <= 1'b1
end
end
always@(posedge clk) begin
if (ce === 1'b0) begin
pc <= 6'h00 // 指令存储器使能信号无效的时候,PC保持为0
end else begin:
pc <= pc + 1'b1 // 指令存储器使能信号有效的时候,PC在每个时钟+1
end
end
endmodule