Verilog中的module可以看成一个具有输入输出端口的黑盒子,该黑盒子有输入和输出接口(信号),通过把输入在盒子中执行某些操作来实现某项功能。(类似于C语言中的函数)

图1 模块示意图
图1 所示的顶层模块(top_module)结构用Verilog语言可描述为:
module top_module(
input a,
input b,
output out
);
.......
endmodule
同理,图1 所示的次级模块(mod_a)结构用Verilog语言可描述为:
module top_module(
input in1,
input in2,
output out
);
.......
endmodule
注意事项:每个模应单独块处于一个.v文件中,模块名即为文件名(规范代码!)
模块的输入输出端口都可看出模块的信号,若不写信号类型则默认为wire类型信号!
// 以下这两个语句本质是一直的
input a;
input wire a;
除了wire型信号,还有reg型信号,具体详见1.4节!
如图1所示,top_module的两个输入端口连接到次级模块(mod_a)的输入端口,那如何在top_module模块模块中使用mod_a模块的功能呢?这就需要通过模块实例化,可以把top_module看成C语言中的主函数,次级模块mod_a看成普通函数,这样就可以在主函数中调用其他函数来完成相应的功能!
在top_module中实例化mod_a的方式为:
模块实例化语法: 模块名 实例名(定义连接port的信号);
module top_module(
input a,
input b,
output out
);
mod_a instance2 (.in1(a), .in2(b), .out(out));
endmodule
always块可构建 组合逻辑块 和 时序逻辑块,复杂的逻辑操作都需要处于该逻辑块中,如if、case、for等
(1) 组合逻辑块
module top_module();
always @(*) begin
....
end
endmodule
(1) 时序逻辑电路
module top_module();
always @(posedge clk) begin
....
end
endmodule
generate主要结合for循环使用,主要用途有:
(1) 操作向量
module top_module(input [7:0] in, output [7:0] out);
genvar i; // genvar i; 也可以定义在generate内部
generate
for(i=0; i<8; i++) begin: bit
assign out[i]=^in[8-1:i];
end
endgenerate
endmodule
(2) 模块重复多次实例化
module top_module(
input a,
input b,
output out
);
genvar i;
generate
for(i=0; i<8; i++) begin: gen_mod_a // gen_mod_a 为每个begin_end的结构的名称
mod_a instance2 (.in1(a), .in2(b), .out(out));
end
endgenerate
endmodule
initial块可以理解为一个初始化块,在initial的起始位置的语句在0时刻即开始执行,之后如果遇到延时,则延时之后执行接下来的语句。
初始块是不可综合的,因此不能将其转化为带有数字元素的硬件原理图。因此初始块除了在仿真中使用外,并没有太大的作用。
如:在仿真文件中初始化各种参数:
initial
begin
sys_clk = 1'b1;
sys_rst_n = 1'b0;
#50
sys_rst_n = 1'b1;
end
注意:
若需要在RTL代码中初始化参数,需要用always块,用initial块会导致错误!
如下所示,在RTL代码中初始化存储器的方式为:
reg [255:0]char_data[4:0];
always@(posedge clk)
begin
char_data[0] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char_data[1] <= 256'h0000000000000000000000000000000000000000000000000000000000000000;
char_data[2] <= 256'h0000000000000000000000200000000000000000002000000008000010000000;
char_data[3] <= 256'h000000000000000000000038000000000000020000380000000600001C000000;
char_data[4] <= 256'h02000000000100000000003E0000000000000700003E0000000780001F000000;
end
Verilog 中赋值方式有三种: 连续赋值、阻塞赋值、非阻塞赋值
assign x = y;
// 组合块
always @(*) begin
out1 = a ;
a = b ;
out2 = a ;
end
// 时序块
always @(posedge clk) begin
out1 <= a ;
a <= b ;
out2 <= a ;
end
(1)用途: 标识符用于定义常数、变量、信号、端口、参数名、模块名等。
(2)组成: 字母、数字、$、下划线任意组合而成
(3)注意事项:
Verilog中有4中逻辑值:0、1、x、z
注意:这里的z、x是不区分大小写的(X、Z也可)
(1) 逻辑运算符:&&(与)、==(相等)、||(或)、!=(不等)
(2) 按位运算符: &、|、~、^、~&、~^、~|
(3) 归约运算符: &、|、~、^、&、~^、~|
&a [3:0] // AND:a[3]&a[2]&a[1]&a [0]相当于(a[3:0]== 4'hf)
|b [3:0] // OR: b[3]|b[2]|b[1]|b [0]相当于(b[3:0]!= 4'h0)
^c [2:0] // XOR:c[2]^c[1]^c[0]
与C语言类似,常量主要有:整数型、实数型和字符串型三种
(1) 正数: 直接写 10 表示位宽为32bit的十进制整数(系统默认)
(2) 负数: -10需要用二进制补码表示,多了一位符号位(1 1010)
(3) 用科学计数法表示:12.345e3 表示 12345
[换算成二进制数后的位宽]'[数制符号][与数制对应的值]
(1) 二进制(b): 8'b1000_1100
(2) 十六进制(h): 8'h8c
(3) 八进制(o): 8'o214
(4) 十进制(d): 8'140
注意事项:
(1) 每个字符由1个8位的ASCII码值表示,即需要1byte存储空间
(2) 如:“Hello world” 字符串由11个ASCII符号构成,需要11byte存储空间
Verilog中注释主要有行注释(//)和块注释(/* .... */)两种,表示方法与C语言一致!
// 行注释
/*
块注释
*/
Verilog中的变量主要有两种: wire和reg
(1) 线网型(wire): 表示电路间的物理连接,wire定义的变量也可看成信号端口
(2) 当两个wire信号被连续赋值时,在逻辑块中会被映射成真实的物理连线,此时这两个信号端口的变化是同步的!
wire a;
wire b;
assign b = a; // 表示a与b之间生成实际的物理连线
(1) 寄存器型(reg): 表示一个抽象的数据存储单元
(2) reg 具有对某一时间点状态进行保持的功能
(1) 在always、initial语句中被赋值的变量(赋值号左边的变量)都是reg型变量
(2) 在assign语句中被赋值的变量,为wire型变量
(1) 参数是一种常量,通常出现在module内部,常被用于定义状态、数据位宽等
parameter STATE = 1'b0;
(2) 只作用于声明的那个文件,且可以被灵活改变!
(3) 局部参数localparam,只在本模块中使用
localparam STATE= 1'b1’;
(4) 参数的名称一般为大写,以区分其他变量
vector(向量),是一组信号的集合,可视为位宽超过1bit 的 wire 信号。
(1) 定义方式:
格式:input/output wire/reg [upper:lower] vector_name
//输入输出型
input [7:0] a,b,
output reg [7:0] out
// 模块中间向量
wire [7:0] c, e;
reg [7:0] d;
多路选择器应用:实现一个 256 选 1 选择器,sel 信号作为选择信号,当 sel = 0 时选择 in[3:0],sel = 1 时选择 in[7:4],以此类推。
module top_module (
input [1023:0] in,
input [7:0] sel,
output [3:0] out
);
assign out = {in[sel*4+3], in[sel*4+2], in[sel*4+1], in[sel*4+0]};
// assign out = in[sel*4 +: 4];
// assign out = in[sel*4+3 -: 4];
endmodule
参考文章:HDLBits:在线学习 Verilog (十三 · Problem 60-64) - 知乎 (zhihu.com)
(1) 与C语言相同,Verilog也有三元表达式:
condition ? if_true : if_false
当条件为真,表达式值为if_true ,否则表达式值为if_false。
(2) 应用
(sel ? b : a) // 一个二选一MUX,通过sel的值选择a或者b
always @(posedge clk) // 一个T触发器
q <= toggle ? ~q : q;
assign out = ena ? q : 1'bz; // 三态缓冲器
(3) 参考文章: HDLBits:在线学习Verilog(八 · Problem 35-39) - 知乎 (zhihu.com)
(1) 最常用的形式:(优势:输出的所有可能都写到,不存在未知电平输出!)
if(<条件表达式 1>)
语句或语句块 1;
else if(<条件表达式 2>)
语句或语句块 2;
………
else
语句或语句块 n;
(2) 不建议使用if-else嵌套,会存在优先级问题,导致逻辑混乱,
(3) 所有if-else语句都应写成(1)的形式!
(4) 根据条件表达式依次比较,存在优先级!
(1) 书写形式:
case(<控制表达式>)
<分支语句 1> : 语句块 1;
<分支语句 2> : 语句块 2;
<分支语句 3> : 语句块 3;
………
<分支语句 n> : 语句块 n;
default : 语句块 n+1;
endcase
比较<控制表达式>与<分支语句n>的取值相等则执行对应语句,否则执行default后语句!
(2) 执行完某一分支语句后立即跳出case语句结构,终止case语句执行。
(3) <分支语句n>的取值必须互不相同!
(4) 以encase结束case语句块
(5) 各分支语句间不存在优先级!
(6) 具体应用: 用case语句搭建多路选择器,(以9选1多路选择器为例)
module top_module(
input [15:0] a, b, c, d, e, f, g, h, i,
input [3:0] sel,
output [15:0] out );
always @(*) begin
case(sel)
4'h0:begin out = a; end
4'h1:begin out = b; end
4'h2:begin out = c; end
4'h3:begin out = d; end
4'h4:begin out = e; end
4'h5:begin out = f; end
4'h6:begin out = g; end
4'h7:begin out = h; end
4'h8:begin out = i; end
default: out = 16'hffff;
endcase
end
endmodule
(1) 书写形式:
integer i;
always @(*) begin
for(i=0; i<n; i++) begin: for_name
<循环语句>
end
end
用一对花括号加逗号组成“{ , }”拼接运算符,逗号隔开的数据按顺序拼接成新数据!
wire [1:0] a;
wire [3:0] b;
wire [5:0] c;
wire [11:0] d = {a, b, c}
在左边拼接实现右移,右边拼接实现左移!
always @(posedge clk) begin
if(rst_n == 1'b0)
out <= 4'b0;
else
out <= {in, out[3:1]}; // 右移
end
语法: {重复次数{vector}}
{3{a}} = {a, a, a}
{3'd5, {2{3'd6}}} // 9'b101_110_110.
移位运算符用于将左边操作数左移或右移指定的位数!移位后空闲位用0填充。
如: 4‘b1101 << 3 结果为:4‘b1000
如: 4‘b1101 >> 3 结果为:4‘b0001


代码实现:
module add1 (
input a,
input b,
input cin,
output sum,
output cout
);
assign sum = a^b^cin;
assign cout = (a&b) | (a&cin) | (b&cin);
endmodule

16进制全加器如上图所示,它可由上节中16个二进制全加器组合而成。
用Verilog实现16进制全加器代码为:
module add16 (
input [15:0] a,
input [15:0] b,
input cin,
output [15:0] sum,
output cout
);
wire [16:0] Add_cin;
assign Add_cin[0] = cin; // 上图中第一个二进制加法器进位输入为0 assign Add_cin[0] = 1b'0;
// 用 generate 进行模块多次实例化
// generate 应用范围:对矢量(vector)多个位重复操作,模块重复实例化
genvar i;
generate
for(i=0; i<16; i++) begin: gen_add16 // gen_add16 为每个begin_end的结构,仿真器会通过他来标识生成结构,gen_add16[0],gen_add16[1]....
add1 Add16(.a(a[i]), .b(b[i]), .cin(Add_cin[i]), .sum(sum[i]), .cout(Add_cin[i+1]));
end
endgenerate
assign cout = Add_cin[16];
endmodule
module counter
// 参数传递
#(
parameter COUNT_MAX = 25'd24_999_999,
parameter STATE = 1'b0 // 多个参数用逗号隔开
)
(
input wire sys_clk,
output reg led_out
);
// 代码主体
endmodule
// 参数传递
#(
.COUNT_NUM( 25'd24_999_999), // 传入参数
.STATE(1'b0)
)
counter1_init // 实例化模块的名称位置
(
.sys_clk (sys_clk),
.led_out(led_out)
);
参考资料:
[1] 野火《FPGA Verilog开发实战指南》:[野火]FPGA Verilog开发实战指南——基于Altera EP4CE10 征途Pro开发板 — [野火]FPGA Verilog开发实战指南——基于Altera EP4CE10 征途Pro开发板 文档 (embedfire.com)
https://doc.embedfire.com/fpga/altera/ep4ce10_pro/zh/latest/index.html
[2] HDLBits中文导学:HDLBits 中文导学 - 知乎 (zhihu.com)
我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He
所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择
在Ruby类中,我重写了三个方法,并且在每个方法中,我基本上做同样的事情:classExampleClassdefconfirmation_required?is_allowed&&superenddefpostpone_email_change?is_allowed&&superenddefreconfirmation_required?is_allowed&&superendend有更简洁的语法吗?如何缩短代码? 最佳答案 如何使用别名?classExampleClassdefconfirmation_required?is_a
可能已经问过了,但我找不到它。这里有2个常见的情况(对我来说,在编程Rails时......)用ruby编写是令人沮丧的:"astring".match(/abc(.+)abc/)[1]在这种情况下,我得到一个错误,因为字符串不匹配,因此在nil上调用[]运算符。我想找到的是比以下内容更好的替代方法:temp="astring".match(/abc(.+)abc/);temp.nil??nil:temp[1]简而言之,如果不匹配,则简单地返回nil而不会出错第二种情况是这样的:var=something.very.long.and.tedious.to.writevar=some
我正在学习Ruby的基础知识(刚刚开始),我遇到了Hash.[]method.它被引入a=["foo",1,"bar",2]=>["foo",1,"bar",2]Hash[*a]=>{"foo"=>1,"bar"=>2}稍加思索,我发现Hash[*a]等同于Hash.[](*a)或Hash.[]*一个。我的问题是为什么会这样。是什么让您将*a放在方括号内,是否有某种规则可以在何时何地使用“it”?编辑:我的措辞似乎造成了一些困惑。我不是在问数组扩展。我明白了。我的问题基本上是:如果[]是方法名称,为什么可以将参数放在括号内?这看起来几乎——但不完全是——就像说如果你有一个方法Foo.d
1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,
Ⅰ软件测试基础一、软件测试基础理论1、软件测试的必要性所有的产品或者服务上线都需要测试2、测试的发展过程3、什么是软件测试找bug,发现缺陷4、测试的定义使用人工或自动的手段来运行或者测试某个系统的过程。目的在于检测它是否满足规定的需求。弄清预期结果和实际结果的差别。5、测试的目的以最小的人力、物力和时间找出软件中潜在的错误和缺陷6、测试的原则28原则:20%的主要功能要重点测(eg:支付宝的支付功能,其他功能都是次要的)80%的错误存在于20%的代码中7、测试标准8、测试的基本要求功能测试性能测试安全性测试兼容性测试易用性测试外观界面测试可靠性测试二、质量模型衡量一个优秀软件的维度①功能性功
作为新的阿里云用户,您可以50免费试用多种优惠,价值高达1,700美元(或8,500美元)。这将让您了解和体验阿里云平台上提供的一系列产品和服务。如果您以个人身份注册免费试用,您将获得价值1,700美元的优惠。但是,如果您是注册公司,您可以选择企业免费试用,提交基本信息通过企业实名注册验证,即可开始价值$8,500的免费试用!本教程介绍了如何设置您的帐户并使用您的免费试用版。关于免费试用在我们开始此试用之前,您还必须遵守以下条款和条件才能访问您的免费试用:只有在一年内创建的账户才有资格获得阿里云免费试用。通过此免费试用优惠,用户可以免费试用免费试用活动页面上列出的每种产品一次。如果您有多个帐
ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear
我正在尝试使用ruby编写一个双线程客户端,一个线程从套接字读取数据并将其打印出来,另一个线程读取本地数据并将其发送到远程服务器。我发现的问题是Ruby似乎无法捕获线程内的错误,这是一个示例:#!/usr/bin/rubyThread.new{loop{$stdout.puts"hi"abc.putsefsleep1}}loop{sleep1}显然,如果我在线程外键入abc.putsef,代码将永远不会运行,因为Ruby将报告“undefinedvariableabc”。但是,如果它在一个线程内,则没有错误报告。我的问题是,如何让Ruby捕获这样的错误?或者至少,报告线程中的错误?