第三章 组合逻辑电路
一、SystemVerilog硬件描述语言基础
基于硬件描述语言的组合逻辑电路模块设计
- 更抽象的描述方式(硬件描述语言HDL) + CAD工具(电子设计自动化工具EDA) —>优化电路(自动化方法)
1.HDL的起源
- HDL:具有特殊结构能够对硬件逻辑电路的功能和时序进行描述的高级编程语言
- SystemVerilog HDL的特点: 具有并行特征,同一时刻执行多任务的能力 (一般软件程序设计语言: 串行)
- SystemVerilog程序 -> 硬件描述语言综合器 -> 硬件电路网表文件
2.综合与仿真
-
逻辑综合
RTL描述->翻译(EDA工具)->逻辑优化(去粗冗余逻辑)->实现与布局布线 -
仿真验证
编写一段HDL程序–测试程序
- 在特定时间将激励信号 送入 待测模块DUT的输入端口;
- 检查输出响应以判断模块功能是否正确
3.SystemVerilog HDL程序的基本结构
- 模块(基本建模单位):描述逻辑电路的功能、结构、外部接口
- 声明格式: module 模块名(端口1,端口2…);
- 端口:某模块与外界通信接口;
- 声明格式:input(输入)/output(输出)/inout(双向端口)【类型】 【位宽】 端口名1, 端口名2, …;
- 内部变量:模块内部各个子模块连接
//三要素:类型,位宽,名字。其中位宽可以缺省。
- 声明格式:内部信号类型 [位宽] 变量名1, 变量名2, …;
- 逻辑功能:明确模块行为和数据的流动(两种建模风格)
- 行为建模
描述输入输出之间的因果关系
1.基于持续赋值语句的建模
2.基于过程块语句的建模 - 结构建模
调用其他已经定义过的模块对整个电路的功能进行描述
-
程序模版
4.SystemVerilog HDL的语法要素
- 间隔符和注释
- 间隔符:空格符,tab键,换行符,换页符 提升可读性
- 注释:// /**/
- 标识符和关键字
- 标识符:取名所用的字符串,由英文字母,数字,$,下划线_组成,只能以英文字母或下划线开头
- 关键字 保留字,本身规定的特殊字符串,定义语言的结构,不能作为标识符使用
- 逻辑值
- 四种逻辑值:0,1,x或X(不确定值),z或Z(高阻态)
- 常量
- 整数型常量 //有负号按照有符号数补码处理
声明格式 : <+/-><位宽>’<进制><数值> - 实数型常量
- 字符型常量
- 数据类型
- 变量类型: logic(最常用,所定义信号的取值可以是0,1,x,z,其他的都是二态类型,仅能取0,1) bit byte shortint int
声明格式 :logic <位宽> 信号名1, 信号名2, …, 信号名n;
logic [15 : 0] addrbus, databus; //定义了两个(无符号)的16位向量信号
logic [15 : 0] signed addrbus; // 定义了两个(有符号)的16位向量信号
logic a, b; //定义了两个1位标量信号,相当于logic [0 : 0] a, b
logic [7 : 0] out, in;
assign out = in; //全选,将信号in赋予给信号out
assign out[7 : 4] = in[3 : 0]; //域选,将信号in的0-3位赋予信号out的4-7
assign out [3] = in [2 : 2]; //域选,将信号in的第2位赋予信号out的第3位
- 线网类型
wire,tri(可以用于定义多源驱动信号)
- 运算符
- 两个位数不同操作数进行位运算,位数少的零扩展,有符号的进行符号扩展
- <<逻辑左移 >>逻辑右移 <<<算术左移 (空余位用0填充)>>>算术右移(空余位用符号位填充)
假设:a = 5’b10100,n = 2,则
b = a << n; // a逻辑左移2位,最低位补0,结果为b = 5’b10000
b = a >> n; // a逻辑右移2位,最高位补0,结果为b = 5’b00101
b = a <<< n; // a算术左移2位,最低位补0,结果为b = 5’b10000
b = a >>> n; // a算术右移2位,最高位补符号位,结果为b = 5’b11101
- 关系运算(条件运算):关系成立?1:0;
- 拼接和复制
声明格式 :{ 信号1[n1 : m1],信号2[n2 : m2], …,信号n[nn : mn] }
必须操作确定位宽的数,{ n{A} }表示将A信号拼接n次
logic [1 : 0] B, C; // 假设B = 2’b00,C = 2’b11,
logic [3: 0] Y;
Y = {B, C}; // 正确,结果Y = 4’b0011
Y = {B[0], C[1], 2’b10}; // 正确,结果Y = 4’b0110,注意,常数的位宽不能缺省
Y = {B, 5}; // 错误,因为常数5的位宽不确定
Y = {2{C}}; // 正确,结果Y = 4’b1111
Y = {B[0], C[1], 2{B[1]}}; // 正确,结果Y = 4’b0100
二.基于SystemVerilog的数字逻辑电路建模方法
1.行为建模
1)基于持续赋值语句(assign)的建模
- 数据流建模
- 声明格式 :assign <#延迟量> 信号名 = 表达式 // <#延迟量>可以缺省
2)基于过程块语句(always或initial)的建模
- always_comb begin
过程赋值语句;//等号左边只能是变量类型
高级语言结构,如if…else, for等
end - 分支结构 必须考虑所有条件(完整分支)
if/else语句
if (condition_expr1) true_statement1;
else if (condition_expr2) true_statement2;
else if (condition_expr3) true_statement3;
. . .
else default_statement;
case语句
case (case_expr)
item_expr1: statement1;
item_expr2: statement2;
. . .
default: default_statement;
endcase
- 循环结构 for repeat while forever
2.结构化建模(层次化建模)
- 声明格式 :模块名 实例化名 (信号列表)
- 位置关联法:实例化子模块时,按照子模块定义时端口出现的顺序建立端口的连接关系
- 名称关联法:实例化子模块时,直接通过名称建立子模块端口的连接关系,不考虑其排列顺序
3.参数化建模(和#define很像)
- #(parameter WIDTH = 8)
- `define WIDTH 8
- generate 语句 动态生成代码
module andN #(parameter WIDTH = 4) (input logic [WIDTH – 1 : 0] a, output logic y);
genvar i;//必须通过定义循环变量
logic [WIDTH – 1 : 0] x;
generate
assign x[0] = a[0];
for (i = 1; i < WIDTH; i = i+1) begin : forloop
assign x[i] = a[i] & x[i - 1];
end //for循环必须加begin end,必须有名字
endgenerate
assign y = x[WIDTH - 1];
endmodule
三.基于SystemVerilog的测试程序
-
模板
module testbench_name(); // testbench为顶层模块,不会被其它模块例化,因此不需要任何端口// 信号定义
// 模块实例化
// 添加激励信号
// 显示输出结果(可以不添加任何显示打印语句,只生成波形图即可)
endmodule
`timescale 1ns/1ns // 预编译指令,定义时间单位和时间精度
module sillyfunction_tb ( ); // 测试程序没有输入/输出端口
logic a, b, c, y;
sillyfunction dut (.a(a), .b(b), .c( c ), .y(y)); // 实例化待测模块
initial begin // 给出激励信号
a = 0; b = 0; c = 0; #10;
c = 1; #10;
b = 1; c = 0; #10;
c = 1; #10;
a = 1; b = 0; c = 0; #10;
c = 1; #10;
b = 1; c = 0; #10;
c = 1; #50;
$ finish
end
initial begin // 输出结果,否则只产生波形
$ monitor ($ time, “a = %a, b = %b, c = %c, y = %y”, a, b, c, y);
end
endmodule
module siilyfunction(input logic a,b,c,output logic y);
assign y = ~b & ~c | a & ~b
endmodule
-
获取仿真时间:$time
-
显示信号值:$display、monitor//格式化打印
$display ( $ time, " a = %b b = %b c = %b y = %b", a, b, c, y);
-
结束/中断仿真:$finish、stop
$finish;
$finish(n);
$stop;
$stop(n);//n=1给出仿真时间 n=0不输出任何信息 -
文件输入:$readmemb、readmemh
$readmemb (“数据文件名”, 数组(存储器)名, <起始地址>, <结束地址>);
用空格或换行区分单个数据 ;用_提高可读性
@hex_addr 从改地址开始存储数据 -
文件输出:$fopen// 打开文件并返回值(0为打开失败)、fclose、fdisplay、fmonitor
$系统任务应用在仿真中
- 自动化测试预期结果和输出相应通过设计的程序比对,直接输出结果
总结:
- 测试程序 由 激励信号 待测模块 输出响应 组成 是不可综合的
- 为了便于复用和管理 通过文件施加激励
- 尽量采用 自动化比对
- 尽量使用 波形图 查找错误
- 行为仿真(前仿真) 可以发现很多问题,通过行为仿真不代表电路没有问题!
四.常见组合逻辑电路模块的设计
1.复用器
- 多输入单输出 记作: k:1复用器
2.译码器和编码器
- 译码器:n个输入m个输出 m<=2的n次方 输出只有一位有效
- 编码器:m个输入n个输出 m<=2的n次方 输入只有一位有效 (VALID位)
以上互为逆运算
3.算术电路
1)1位加法器
- 半加器(half-adder):两个输入a、b,两个输出s(求和结果)=a异或b、c(进位结果)=a&b。
- 全加器(full-adder):三个输入a、b、Cin,两个输出s(求和结果)=a异或b异或Cin、Cout(进位结果)=a&b +(a异或b)& Cin。
2)多位加法器( CPAs)
- 进位传播加法器
- 由两个n位输入,进位输入,产生:n位结果s,输出进位。
【1】行波进位加法器
- 所有进位构成的通路称为进位链(从低位向高位)实际延迟:(2n+1)t
【2】先行进位加法器
- 快速进位的加法器 把加法器分为若干块 每一块有进位时确定此块的输出进位
3)减法器
- 补码 减法器由加法器实现
4)比较器
- 相等比较器: 产生一个输出 表示是否相等
- 数值比较啊器:产生多个输出 表示关系
5)移位器和循环移位器
- 逻辑移位器:空出位补充0
- 算数移位器:左移相同 右移补符号位
- 循环移位器:循环移动数据
6)乘法器
7)算数逻辑单元 ALU
- 将多种算数运算或逻辑运算组合到一个单元模块中
- ALU是大多数计算机的核心
- 2的n次方种运算
五.逻辑阵列
- 逻辑门按照一定规则连接组成阵列,若门之间是可编程的,那么这个逻辑阵列可以执行任何功能
- 可编程逻辑阵列(PLA) 以与或形式实现两级组合逻辑 and阵列 or阵列 只能实现组合逻辑电路 m(与)*n(最小项输出)*p(或)位的pla
第四章 一.引言
第三章 第四章4.4. 4.6 第五章5.4 5.5
时序逻辑电路
- 时序逻辑电路 与 当前时刻的输入 之前时刻的输入 有关
- 时序逻辑电路内部具有记忆
- 一些基本概念: 1)状态 2)锁存器与触发器:用于存储1比特状态的模块 3)同步时序逻辑电路 (电路设计的90%以上)
时序逻辑电路的特征
- 按照一定的输入输出时序实现功能
- 电路内部具有短期记忆
- 输出输入之间有反馈回路