《计算机组成与CPU设计实验》2 组合逻辑(二)

本篇内容来源于中国大学mooc《计算机组成与CPU设计实验》 (江苏大学)中的课程视频、PPT等相关资料

本篇内容为《计算机组成与CPU设计实验》——译码器

参考视频:

计算机组成与CPU设计实验_江苏大学_中国大学MOOC(慕课) (icourse163.org)

编码转换

译码器

N个输入,gif.latex?2%5E%7BN%7D个输出。

只有一个输出有效(One-hot输出)。

例子:2-4译码器

ec46e650d3d84f6d84c4e000da52b3f1.png

 Verilog代码

module  decoder(
	input  [1:0]  A,
	output [3:0] Y
 ); 
 always_comb
 	begin
 		 case(A)
 		 	 00:Y = 4'b0001;
 			 01:Y = 4'b0010;
 			 10:Y = 4'b0100;
 			 11:Y = 4'b1000;
 		 default:Y = 4'bxxxx;
 		 endcase
 	end
endmodule

编码器

gif.latex?2%5E%7BN%7D个输入,N个输出,

只有一个输出有效(One-hot输出)。

例子:4-2优先级编码器

9f82a4a5f8a243d1af2c0b0357e9863e.png

4-2优先级译码器真值表

A3A2A1A0Y1Y0
XXXX00
1XXX11
01XX10
001X01
000100

  Verilog代码

使用 if语句优先级编码

module  PriorityEncoder(
	input  [3:0]  A,
	output [1:0] Y
 ); 

 always_comb
 	begin
 		 	 if(A[0])      Y = 2'b00;//是有优先级的,A[0]为1,就输出结果,不满足,依次按照优先级来
 			 else if(A[1]) Y = 2'b01;
 			 else if(A[2]) Y = 2'b10;
 			 else if(A[3]) Y = 2'b11;
 			 else          Y = 2'bxx;
 	end
endmodule

 使用casez或者casex优先级编码

module  PriorityEncoder(
	input  [3:0]  A,
	output [1:0] Y
 ); 

 always_comb
 	begin
 		 	case[A]
 			4'bxxx1: Y = 2'b00;//A中,不管1前面的前面是什么值都无所谓,前面的数值不参与比较
 			4'bxx10: Y = 2'b01;
 			4'bx100: Y = 2'b10;
            4'b1000: Y = 2'b11;
 			default: Y = 2'bxx;
 	end
endmodule

使用for循环语句优先级编码

只是用循环描述电路行为, 并非循环 “执行 ” 。

不是反复执行这个代码,只是告诉编译器,我是用一种循环的方式,描述这个电路。

module  PriorityEncoder(
	input  [3:0]  A,
	output [1:0] Y
 ); 
 always_comb
 	begin
        integer i;
        Y=0;
        for(i=0;i<8;i+1)
 		 	 if(A[i])      Y = i;
 	end
endmodule

编码转换

从一种码转换成另一种码。单纯用译码器或者编码器描述不合适。

 例子:

module Code_Translator (
    input[2:0] Code_In,
    output logic [2:0] Code__Out
);
    always_comb
        case (Code_In)
            3'b000: Code_out = 3'b101;
            3'b001: Code_Out = 3'b111;
            3'b010: Code_Out = 3'b001;
            3'b011: Code_out = 3'b000;
            3'b100: Code_Out = 3'b100;
            3'b101: Code_out = 3'b010;
            3'b110: Code_out = 3'b110;
            3'b111:Code_out = 3'b011;
            default: Code_Out = 3'bx;
        endcase
endmodule

编码转换例子:七段译码器

4位二进制数 → 七段数码显示器编码

2021062114051639.png

Verilog代码

module seg_dec(num,a_g);
input[3:0]           num;
output[6:0]          a_g;//a_g[6:0]->(a,b,c,d,e,f,g)
reg[6:0]             a_g;
always@(num)begin
    case(num)        //用case语句实现组合逻辑
    4'd0:begin a_g<=7'b111_1110;end
    4'd1:begin a_g<=7'b011_0000;end
    4'd2:begin a_g<=7'b110_1101;end
    4'd3:begin a_g<=7'b111_1100;end
    4'd4:begin a_g<=7'b011_0011;end
    4'd5:begin a_g<=7'b101_1011;end
    4'd6:begin a_g<=7'b101_1111;end
    4'd7:begin a_g<=7'b111_0000;end
    4'd8:begin a_g<=7'b111_1111;end
    4'd9:begin a_g<=7'b111_1011;end
    default:begin a_g<=7'b000_0001;end//num超出(0-9)时,用default统一处理,显示为中杠;
 
    endcase
 
end
endmodule

模块的参数和层次

 模块的参数定义使用parameter。可以很方便改变位宽。

 例子1:加法器

四位加法器 

311af40bfd7642a58c519a0b69234e81.png

Verilog描述 

module  ADDER(
	input  [3:0]  A,
	input  [3:0]  B,
	input CI,
	output [3:0] S,
	output CO
 ); 
assign {CO,S[3:0]}= A+B+CI;
 
endmodule

N位加法器(参数化设计)

Verilog描述  

module  ADDER
#parameter N=4
(
	input  [N-1:0]  A,
	input  [N-1:0]  B,
	input CI,
	output [N-1:0] S,
	output CO
 ); 
assign {CO,S[N-1:0]}= A+B+CI;
 
endmodule

例子2:三态缓冲器(参数化设计 )

N位输入Din,N位输出Dout 

58853b5948d34f678df73ce87d39a652.png

 Verilog描述  

module  TRIBUFFER
#parameter N=4
(
	input  [N-1:0]  Din,
	input  [N-1:0]  En,
	output [N-1:0]  Dout
 ); 
assign Dout = En? Din:{N{1'bz}};
 
endmodule

 模块的实例化和模块的层次

 模块的实例化,告诉工具,产生这个模块的电路 。

模块的层次化和参数化 ,有利于代码维护和重用

例子:八位的全加器

adder和buf模块已经在上面例子中定义。使用Verilog描述 top层电路,adder和buf模块实例化。

aa3dfb930bbe4096985c0e7bcd3b5b94.png

 Verilog描述

module  TOP
(
	input [7:0] x,
	input [7:0] y,
	input  cin,
	input  en,
	output  cout,
	output [7:0] out
 ); 
 wire [7:0] F;
 ADDER     adder(.A(x),.B(y),.CI(cin),.S(F),.CO(cout));//ADDER定义的模块名,adder,实例名。一个叫adder的ADDER模块。
 TRIBUFFER  buf(.Din(F),.En(en),.Dout(out));
endmodule

模块实例化的端口映射方式

 端口映射方式

 1、端口位置映射

实例化时的端口连接顺序必须与模块定义的顺序一致

4d3b0b45a1944aecb0277173487da5eb.png

 2、端口名称映射(推荐!!!)

可不按模块定义的端口顺序

75db585215b7423993e5fcdb5c20e567.png

 端口名称映射方式,允许未连接的 “悬空 ”端口(即不连接,空着)

两种表示方法:

  • 不写这个端口
  • 实例化时不声明,用空括号显式表示

注意:

应该连而未连的端口,因为从语法角度是没有错的,所以不会报错。需要注意,否则忘记连接会造成不易排查的错误

例子:端口S和En没有连接

7b63dcd4055e42baae4431f52886c53c.png

 Verilog描述 

module  TOP
(
	input [7:0] x,
	input [7:0] y,
	input  cin,
	input  en,
	output  cout,
	output [7:0] out
 ); 
 wire [7:0] F;
 ADDER     adder(.A(x),.B(y),.CI(cin),.CO(cout));//S没有写
 TRIBUFFER  buf(.Din(F),.En(),.Dout(out));//En端口使用()表示
endmodule

​

SystemVerilog简化的映射方法

因为名称多了,显得很罗嗦,所以简化

简化的名称映射方式

如果子模块的端口名称和上层模块的信号名称相同, 可以只写.name 

例子:

22da59b9f2e347f0a9025aa08360f600.png

  Verilog描述 

module  TOP
(
	input [7:0] A,
	input [7:0] B,
	input  CI,
	input  En,
	output  CO,
	output [7:0] Dout
 ); 
 wire [7:0] F;
 ADDER     adder(.A, .B, .CI, .CO, .S(F));
 TRIBUFFER  buf(.Din(F), .En, .Dout);
endmodule

 隐式名称映射方式:.*

连接所有名称相同的端口

注意:名称不同的端口必须显式连接,不能有悬空的端   

module  TOP
(
	input [7:0] A,
	input [7:0] B,
	input  CI,
	input  En,
	output  CO,
	output [7:0] Dout
 ); 
 wire [7:0] F;
 ADDER     adder(.*, .S(F));
 TRIBUFFER  buf(.Din(F), .*);
endmodule

//如果全部使用.*
ADDER     adder(.*); //编译报错,找不到.S同名的信号

模块实例化和修改子模块的参数

无需修改子模块,就可以改变参数值 

例子:使用带有参数子模块的全加器 

下面的电路为使用加法器和三态缓冲电路组成的N位全加器。

输入为N位的x,y。输出为N位 out。

使用参数的方法,写8位的全加器。(参数化的子模块在上面的例子中已定义)

78471d8d26224d9b97c66c6a3b485d2f.png

   Verilog描述 

module  TOP
(
	input [7:0] x,
	input [7:0] y,
	input  cin,
	input  en,
	output  cout,
	output [7:0] out
 ); 
 wire [7:0] F;
 ADDER  #(8)   adder(.A(x),.B(y),.CI(cin),.S(F),.CO(cout));
 TRIBUFFER #(8) buf(.Din(F),.En(en),.Dout(out));
endmodule

 多个参数的声明和映射

如果模块中出现不止一个参数,怎么定义?

模块定义 

例子: 

module  circuit
#(parameter M=8,
  parameter N=6
)
(
	input  [M-1:0]  A,
	output [N-1:0]  B
 ); 

......
 
endmodule

实例化的参数映射方式 

1、位置映射

 按照模块定义时参数声明的出现顺序

 circuit  #(8,6)  INST( ..... );

2、名称映射

 circuit  #(.N(8),.M(6))  INST( ..... );

有多个参数时,推荐使用名称映射

避坑指南

避免组合逻辑隐含锁存器

组合逻辑是没有存储特性的,要避免这种情况。(锁存器用在时序电路中) 

组合逻辑应该有完整的if-else

如果缺少else,会导致隐藏的锁存器。

例子:

if (condition) y = a;
//缺少else,在condition之外的情况,y的值保持不变,引入了一个锁存器

改正

if (condition) y = a;
else y = 'bx; //若对取值无要求,可赋值x
//综合工具就会知道,电路对else分支的取值是没有条件的,就不会生成锁存器

避免缺少else的情况,推荐使用always_comb

always_comb begin
    if (condition) y = a;
end
//缺少else,在condition之外的情况,y的值保持不变,引入了一个锁存器
//if else不完整,编译器会报错,提示always_comb块里面不是纯粹的组合逻辑。
//因为有隐藏的锁存器

ad186fc49a0e4ccbb1726e95de0694ab.png

 case语句要有default

case语句无有default,隐含锁存器

例子:

case (op)
    2'b00: y = a +  b;
    2'b01: y = a -  b;
    2'b10: y = a &  b;
    2'b11: y = a | b ;
//无default,其他默认条件的输出值保持不变,隐含锁存器
endcase

改正

case (op)
    2'b00: y = a +  b;
    2'b01: y = a -  b;
    2'b10: y = a &  b;
    2'b11: y = a | b ;
    default:y= 'bz;
endcase

推荐使用always_comb,编译器会检查case语句是否缺少default

组合逻辑的敏感列表应包含所有的输入 

不完整的敏感列表导致不可预料的综合结果

 例子:这个模块有四个输入abcd,一个输出y。但是下面的敏感列表中,缺少了一个输入d,会发生什么情况? 

c2c7db07467f407d948e7046d86d86a4.png

always @(a,b,c)  //缺少一个输入d
begin
    if (a)     y = 0;
    else if (b) y = 1;
    else if (c) y = 2;
    else if (d) y = 3;
end

综合出来的电路,不一定是组合逻辑,结果无法预测。 

组合逻辑推荐使用always_comb,always_comb里面没有敏感列表。

模块连接容易犯的错误 

例子:

353bc5f601dc4d76acdf98c172789b1b.png

 问题1:如果子模块之间的连线F,没有定义,会发生什么情况?

module  TOP
(
	input [7:0] x,
	input [7:0] y,
	input  cin,
	input  en,
	output  cout,
	output [7:0] out
 ); 
// wire [7:0] F;
 ADDER     adder(.A(x),.B(y),.CI(cin),.CO(cout));//S没有写
 TRIBUFFER  buf(.Din(F),.En(),.Dout(out));//En端口使用()表示
endmodule

​

 未声明信号的默认类型为wire型(标量,一位),但是不会默认为一个向量。

会出现,最低位发生变化,高位不变化。

Verilog-1995

未声明信号的默认类型为wire 型 (标量,一位)

容易造成难以发现的错误

//模块间的连接信号:
wire [7:0] F;
//没有声明,默认为标量
wire  F;

怎么避免未声明信号

Verilog-2001可关闭默认类型

关键字

`default_nettype none //关闭默认的线网类型wire
//之后有未声明的信号会报错
//`这个符号在esc下面


组合逻辑Verilog在线练习

练习网站:

牛客网-组合逻辑练习

042b3e9e48da4dcbbd2b7531e7e6adf0.png

66f727072f9f46fdbe4d2459a46b0084.png

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值