13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!

设计可综合状态机的指导原则

  • 1,组合逻辑电路设计
    • 1.1,8位带进位端的加法器模块设计
      • 1.1.1,RTL代码设计
      • 1.1.2,tb测试信号
      • 1.1.3,生成原理图
      • 1.1.4,SIM输出波形
    • 1.2,指令译码模块设计
      • 1.2.1,RTL代码设计
      • 1.2.2,tb测试代码
      • 1.2.3,生成原理图
      • 1.2.4,SIM输出波形
    • 1.3,利用 task 和 电平敏感的 always 块设计经比较后重组信号的组合逻辑
      • 1.3.1,RTL代码设计
      • 1.3.2,tb测试代码
      • 1.3.3,生成原理图
      • 1.3.4,SIM输出波形
    • 1.4,比较器模块设计
      • 1.4.1,RTL代码设计
      • 1.4.2,tb测试代码
      • 1.4.3,生成原理图
      • 1.4.4,SIM输出波形
    • 1.5,3-8译码器模块设计
      • 1.5.1,RTL代码设计
      • 1.5.2,tb测试代码
      • 1.5.3,生成原理图
      • 1.5.4,SIM输出波形
    • 1.6,8-3编码器模块设计
      • 1.6.1.1,RTL代码设计,编码器方案1
      • 1.6.1.2,tb测试代码
      • 1.6.1.3,生成原理图
      • 1.6.1.4,SIM输出波形
      • 1.6.2.1,RTL代码设计,编码器方案2
      • 1.6.2.2,tb测试代码
      • 1.6.2.3,生成原理图
      • 1.6.2.4,SIM输出波形
      • 1.6.3.1,RTL代码设计,编码器方案3
      • 1.6.3.2,tb测试代码
      • 1.6.3.3,生成原理图
      • 1.6.3.4,SIM输出波形
    • 1.7,多路器模块设计
      • 1.7.1.1,RTL代码设计,设计方案1
      • 1.7.1.2,tb测试代码
      • 1.7.1.3,生成原理图
      • 1.7.1.4,SIM输出波形
      • 1.7.2.1,RTL代码设计,设计方案2
      • 1.7.2.2,tb测试代码
      • 1.7.2.3,生成原理图
      • 1.7.2.4,SIM输出波形
      • 1.7.3.1,RTL代码模块设计,设计方案3
      • 1.7.3.2,tb测试代码
      • 1.7.3.3,生成原理图
      • 1.7.3.4,SIM输出波形图
    • 1.8,奇偶校验位生成器模块设计
      • 1.8.1,RTL代码设计
      • 1.8.2,tb测试代码
      • 1.8.3,生成原理图
      • 1.8.4,SIM输出波形
    • 1.9,三态输出驱动器模块设计
      • 1.9.1.1,RTL代码设计,设计方案1
      • 1.9.1.2,tb测试代码
      • 1.9.1.3,生成原理图
      • 1.9.1.4,SIM输出波形
      • 1.9.2.1,RTL代码设计,设计方案2
      • 1.9.2.2,tb测试代码
      • 1.9.2.3,生成原理图
      • 1.9.2.4,SIM输出波形
    • 1.10,三态双向驱动器模块设计
      • 1.10.1,RTL代码设计
      • 1.10.2,tb测试代码
      • 1.10.3,生成原理图
      • 1.10.4,SIM输出波形
  • 2,时序逻辑电路设计
    • 2.1,触发器设计
      • 2.1.1,RTL代码设计
      • 2.1.2,tb测试代码
      • 2.1.3,生成原理图
      • 2.1.4,SIM输出波形
    • 2.2,电平敏感型锁存器设计
      • 2.2.1.1,RTL代码设计,方案1
      • 2.2.1.2,tb测试代码
      • 2.2.1.3,生成原理图
      • 2.2.1.4,SIM输出波形图
      • 2.2.2.1,RTL代码设计,方案2
      • 2.2.2.2,tb测试代码
      • 2.2.2.3,生成原理图
      • 2.2.2.4,SIM输出波形图
      • 2.2.3.1,RTL代码设计,方案3
      • 2.2.3.2,tb测试代码
      • 2.2.3.3,生成原理图
      • 2.2.3.4,SIM输出波形图
    • 2.3,移位寄存器设计
      • 2.3.1,RTL代码设计
      • 2.3.2,tb测试代码
      • 2.3.3,生成原理图
      • 2.3.4,SIM输出波形
    • 2.4,8位计数器设计
      • 2.4.1.1,RTL代码设计,方案1
      • 2.4.1.2,tb测试代码
      • 2.4.1.3,生成原理图
      • 2.4.1.4,SIM输出波形
      • 2.4.2.1,RTL代码设计,方案2
      • 2.4.2.2,tb测试代码
      • 2.4.2.3,生成原理图
      • 2.4.2.4,SIM输出波形
  • 3,状态机的置位和复位
    • 3.1,状态机的异步置位与复位
      • 3.1.1,带异步高电平有效的置/复位端的D触发器,RTL设计
      • 3.1.2,tb测试信号
      • 3.1.3,生成原理图
      • 3.1.4,SIM输出波形图
    • 3.2,状态机的同步置位与复位
      • 3.2.1,同步的具有高电平有效的置位/复位端的D触发器,RTL设计
      • 3.2.2,tb测试信号
      • 3.2.3,生成原理图
      • 3.2.4,SIM输出波形
  • 4,编码风格的总结

一、注意:

1,大多数FPGA内部的触发器数目相当多,又加上独热码状态机的译码逻辑最为简单,所以在设计采用FPGA实现的状态机时,往往采用独热码状态机(即每个状态只有一个寄存器置位的状态机)。
2,设计异步状态机。如果设计要求必须有不同的时钟触发的状态机,采用方法:
(1)编写另一个模块,在那个模块内使用另一个时钟;
(2)用实例引用的方法在另一个模块中把它们连接起来。
(3)为使设计比较简单、调试比较容易,应该尽量使这两个状态机的时钟有一定的关系;例如甲模块的时钟是乙模块时钟同步计数器的输出。
3,千万不要使用综合工具来设计异步状态机。因为目前大多数综合工具在对异步状态机进行逻辑优化时会胡乱地简化逻辑,使综合后的异步状态机不能正常工作。

二、综合的一般原则:

1,综合之前一定要进行仿真,这是因为仿真会暴露逻辑错误。如果不做仿真,没有发现的逻辑错误会进入综合器,使综合的结果产生同样的逻辑错误。
2,每一次布局布线之后都要进行仿真,在器件编程或流片之前要做最后的仿真。
3,用Verilog HDL描述的异步状态机是不能综合的,因此应该避免用综合器来设计;如果一定要设计异步状态机,则可用电路图输入的方法来设计。
4,如果要为电平敏感的锁存器建模,使用连续赋值语句是最简单的方法。

三、语言指导原则:

1,always块:
(1)每个always块只能有一个事件控制“@(event-expression)”,而且要紧跟在always关键字的后面。
(2)always块可以表示时序逻辑或者组合逻辑;但不建议使用always块既表示电平敏感的透明锁存器又同时表示组合逻辑,虽然always块这样使用不会有语法错误,但是这容易产生电路功能的错误和多余电平敏感的透明锁存器。
(3)带有posedge或negedge关键字的事件表达式表示沿触发的时序逻辑,没有posedge或negedge关键字的表示组合逻辑或电平敏感的锁存器,或者两种都表示。
(4)每个表示时序always块只能由一个时钟跳变沿触发,置位或复位最好也由该时钟跳变沿触发。
(5)每个在always块中赋值的信号都必须定义成reg型或整型。
整型变量默认是32位,使用Verilog操作符可对其进行二进制求补的算术运算。综合器还支持整型变量的范围说明,这样就允许产生不是32位的整型量。句法结构是:integer [ : ]。
(6)always块中应该避免组合反馈回路。
每次执行always块时,在生成组合逻辑的always块中赋值的所有信号必须有明确的值;否则,需要设计者在设计中加入电平敏感的锁存器来保持赋值前的最后一个值。只有这样,综合器才能正常生成电路,如果不这样做,综合器会发出警告,提示设计中插入了锁存器。如果在设计中存在综合器认为不是电平敏感锁存器的组合回路时,综合器会发出错误信息(例如在设计异步状态机时)。

四、对上述原则的简化解释:

用always块设计纯组合逻辑电路时,在生成组合逻辑的always块中参与赋值的所有信号都必须有明确的值,即在赋值表达式右端参与赋值的信号都必须在always@(敏感电平列表)中列出。如果赋值表达式右端参与赋值的信号没在always@(敏感电平列表)中列出,这就会形成一个透明的锁存器。但是,该信号的变化不会立刻显现出来,而必须等到敏感电平列表中某个信号变化时,它的作用才会显现出来,也就是相当于存在着一个透明锁存器,即把该信号的变化暂存起来,待敏感电平列表中某个信号变化再起作用,纯组合逻辑不可能做到这一点。
这样,综合后所得的电路已经不是纯组合逻辑电路了,这时综合器又会发出警告,提示设计中插入了锁存器。

1,组合逻辑电路设计

1.1,8位带进位端的加法器模块设计

1.1.1,RTL代码设计

//	1,8位带进位端的加法器的设计实例
module	adder_8(
input	[7:0]	a,
input	[7:0]	b,
input			cin,

output	[7:0]	sum,
output			cout
);

assign	{cout, sum} = a + b +cin;
endmodule

1.1.2,tb测试信号

//	测试信号, tb

module	tb_adder_8;
reg		[7:0]	a;
reg		[7:0]	b;
reg				cin;

wire	[7:0]	sum;
wire			cout;

adder_8		u1_adder_8(
.a				(a			),
.b				(b			),
.cin			(cin		),
.sum			(sum		),
.cout			(cout		)
);

initial		begin
#60;
a	= 8'b0000_1111;
b	= 8'b0001_0000;
cin = 1'b1;

#100
a	= 8'b1010_1010;
b	= 8'b0101_0101;
cin	= 1'b1;
end

endmodule

1.1.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第1张图片

1.1.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第2张图片

1.2,指令译码模块设计

1.2.1,RTL代码设计

//	2,指令译码电路的设计实例(利用电平敏感的always块来设计组合逻辑)
//	操作码的定义
`define		plus		3'd0
`define		minus		3'd1
`define		band		3'd2
`define		bor			3'd3
`define		unegate		3'd4

module	alu(
input		[7:0]		a,
input		[7:0]		b,
input		[2:0]		opcode,

output	reg	[7:0]		out
);

//	用电平敏感的always块描述组合逻辑
always@(opcode or a or b)		begin
	case(opcode)
		// 算术运算
		`plus:		out = a + b;
		`minus:		out = a - b;
		//	位运算
		`band:		out	= a & b;
		`bor:		out	= a | b;
		//	单目运算
		`unegate:	out = ~a;
		
		default:	out	= 8'hx;
	endcase
end

endmodule

1.2.2,tb测试代码

//	2,
module	tb_alu;
reg		[7:0]		a;
reg		[7:0]		b;
reg		[2:0]		opcode;

wire	[7:0]		out;

initial		begin
#60;
opcode	= 3'd0;

#10;
opcode	= 3'd1;

#10;
opcode	= 3'd2;

#20;

#10;
opcode	= 3'd3;

#10;
opcode	= 3'd4;

#10;
opcode	= 3'd6;

end


initial		begin
#60;
a	= 8'b0000_1111;
b	= 8'b0001_0000;

#40;
a	= 8'b1010_1010;
b	= 8'b0101_0101;

#100
$stop;
end

alu		u1_alu(
.a				(a			),
.b				(b			),
.opcode			(opcode		),
.out			(out		)
);

endmodule

1.2.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第3张图片

1.2.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第4张图片

1.3,利用 task 和 电平敏感的 always 块设计经比较后重组信号的组合逻辑

1.3.1,RTL代码设计

//	3,利用 task 和电平敏感的 always 块设计经比较后重组信号的组合逻辑
module	sort4(ra, rb, rc, rd, a, b, c, d);
parameter		t	= 3;

input		[3:0]	a;
input		[3:0]	b;
input		[3:0]	c;
input		[3:0]	d;

output	reg	[t:0]	ra;
output	reg	[t:0]	rb;
output	reg	[t:0]	rc;
output	reg	[t:0]	rd;

always@(a or b or c or d)	begin:local
//	用电平敏感的 always 块描述组合逻辑
reg			[t:0]	va, vb, vc, vd;
{va, vb, vc, vd} = {a, b, c, d};

sort2(va, vc);      //    实现交换,第一个是小指,第二个是大值。
sort2(vb, vd);      //    实现交换,第一个是小指,第二个是大值。
sort2(va, vb);      //    实现交换,第一个是小指,第二个是大值。
sort2(vc, vd);      //    实现交换,第一个是小指,第二个是大值。
sort2(vb, vc);      //    实现交换,第一个是小指,第二个是大值。

{ra, rb, rc, rd} = {va, vb, vc, vd};    //  按照:从小到大     输出。

end

task	sort2;             //  调用任务,如果满足条件,
inout	[t:0]	x, y;      //  则按照最终得到,小、大值,返回! 
reg		[t:0]	tmp;

if(x > y)	begin
	tmp		= x;
	x		= y;
	y		= tmp;
end

endtask

endmodule

1.3.2,tb测试代码

//	3,
module tb_sort4;
parameter		t = 3;

reg		[3:0]	a;
reg		[3:0]	b;
reg		[3:0]	c;
reg		[3:0]	d;

wire	[t:0]	ra;
wire	[t:0]	rb;
wire	[t:0]	rc;
wire	[t:0]	rd;

initial		begin
a = 0; b = 0; c = 0; d = 0;

repeat(5)	begin
#100
	a = {$random} % 15;
	b = {$random} % 15;
	c = {$random} % 15;
	d = {$random} % 15;
end

#700;
$stop;

end

sort4		u1_sort4(
.a			(a		),
.b			(b		),
.c			(c		),
.d			(d		),

.ra			(ra		),
.rb			(rb		),
.rc			(rc		),
.rd			(rd		)
);

endmodule

1.3.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第5张图片

1.3.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第6张图片

1.4,比较器模块设计

1.4.1,RTL代码设计

//	4,比较器的设计实例(利用赋值语句设计组合逻辑)
module		compare(equal, a, b);
parameter					size = 4;
input		[size-1 : 0]	a, b;
output						equal;

assign		equal	= (a == b) ? 1 : 0; 

endmodule

1.4.2,tb测试代码

//	4
//	测试信号
module	tb_compare;
parameter			size = 4;
reg		[size-1:0]	a, b;
wire				equal;

initial		begin
a = 4'd0; b = 4'd0;

repeat(5)		begin
#20;
a = {$random} % 15;
b = {$random} % 15;
end

#700;
$stop;
end

compare		u1_compare(
.a			(a		),
.b			(b		),
.equal		(equal	)
);

endmodule

1.4.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第7张图片

1.4.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第8张图片

1.5,3-8译码器模块设计

1.5.1,RTL代码设计

//	5,3-8译码器设计实例(利用赋值语句设计组合逻辑)
module		decoder(out, in);
input	[2:0]	in;
output	[7:0]	out;

assign		out = 1'b1 << in;
//	把最低位的 1 左移 in(根据从 in 口输入的值)位,并赋予 out.
endmodule

1.5.2,tb测试代码

//	5,
module	tb_decoder;
reg		[2:0]		in;
wire	[7:0]		out;

initial		begin
in	= 3'd0;

repeat(8)	begin
#100;
in	= {$random}%8;
end 

#400;
$stop;
end

decoder		u1_decoder(
.in			(in			),
.out		(out		)
);

endmodule

1.5.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第9张图片

1.5.4,SIM输出波形

在这里插入图片描述

1.6,8-3编码器模块设计

1.6.1.1,RTL代码设计,编码器方案1

//	6,8-3编码器的设计实例,(1)
module	encoder1(none_on, out, in);
input		[7:0]	in;

output	reg			none_on;
output	reg	[2:0]	out;

always@(in)		begin:local		// 此处 begin-end 块必须有一模块名,因为块中定义了局部变量
	integer			i;
	out		= 0;
	none_on	= 1;
	
	/*	返回输入信号 in 的 8位 中,为 1 的最高位数 */
	for(i=0; i<8; i=i+1)	begin		// 取最高位是1,先有效
		if(in[i])	begin
			out			= i;
			none_on		= 0;
		end
	end
end

endmodule

1.6.1.2,tb测试代码

//	6,
module	tb_encoder1;
reg		[7:0]		in;		//	编码器

wire	[2:0]		out;
wire				none_on;

initial		begin
in		= 8'b0000_0000;

#100;
in		= 8'b0000_0001;
#100;
in		= 8'b0000_0010;
#100;
in		= 8'b0000_0100;
#100;
in		= 8'b0000_1000;

#200;
in		= 8'b0001_0000;
#100;
in		= 8'b0010_0000;
#100;
in		= 8'b0100_0000;
#100;
in		= 8'b1000_0000;

#200;
in		= 8'b1010_0000;
#100;
in		= 8'b0001_0100;

#200;
$stop;

end

encoder1	u1_encoder1(
.in			(in			),
.out		(out		),
.none_on	(none_on	)
);

endmodule

1.6.1.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第10张图片

1.6.1.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第11张图片

1.6.2.1,RTL代码设计,编码器方案2

//	编码器设计方案,(2)
module	encoder2(none_on, out2, out1, out0, h, g, f, e, d, c, b, a);
input			h, g, f, e, d, c, b, a;
output			none_on, out2, out1, out0;
wire	[3:0]	outvec;

assign	outvec = h ? 4'b0111 : g ? 4'b0110 : f ? 4'b0101 :
				e ? 4'b0100 : d ? 4'b0011 : c ? 4'b0010 :
				b ? 4'b0001 : a ? 4'b0000 : 4'b1000;

assign	none_on = outvec[3];
assign	out2	= outvec[2];
assign	out1	= outvec[1];
assign	out0	= outvec[0];

endmodule

1.6.2.2,tb测试代码

//	6,(2)
module	tb_encoder2;
reg			h;		//	7	
reg			g;		//	6
reg			f;		//	5
reg			e;		//	4
reg			d;		//	3
reg			c;		//	2
reg			b;		//	1
reg			a;		//	0

wire		none_on;
wire		out2;
wire		out1;
wire		out0;

initial		begin
			//	0		
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};

#20;		//	7
{h, g, f, e, d, c, b, a} = {1'b1, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};

#20;		//	6
{h, g, f, e, d, c, b, a} = {1'b0, 1'b1, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};

#20;		//	5
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b1, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};

#20;		//	4
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b1, 1'b0, 1'b0, 1'b0, 1'b0};

#20;		//	3
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b0, 1'b1, 1'b0, 1'b0, 1'b0};

#20;		//	2
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b1, 1'b0, 1'b0};

#20;		//	1
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b1, 1'b0};

#20;		//	0
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b1};

#200;		//	0
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};

#20;		//	5
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b1, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};

#300;
$stop;
end

encoder2	u1_encoder2(
.h			(h			),
.g			(g			),
.f			(f			),
.e			(e			),
.d			(d			),
.c			(c			),
.b			(b			),
.a			(a			),

.none_on	(none_on	),
.out2		(out2		),
.out1		(out1		),
.out0		(out0		)
);

endmodule

1.6.2.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第12张图片

1.6.2.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第13张图片

1.6.3.1,RTL代码设计,编码器方案3

//	编码器设计方案,(3)
module		encoder3(none_on, out2, out1, out0, h, g, f, e, d, c, b, a);
input		h, g, f, e, d, c, b, a;
output		out2, out1, out0;
output		none_on;

reg		[3:0]	outvec;

assign		{none_on, out2, out1, out0} = outvec;

always@(a or b or c or d or e or f or g or h)		begin
	if(h)			outvec	= 4'b0111;
	else if(g)		outvec	= 4'b0110;
	else if(f)		outvec	= 4'b0101;
	else if(e)		outvec	= 4'b0100;

	else if(d)		outvec	= 4'b0011;	
	else if(c)		outvec	= 4'b0010;
	else if(b)		outvec	= 4'b0001;
	else if(a)		outvec	= 4'b0000;

	else			outvec	= 4'b1000;
end

endmodule

1.6.3.2,tb测试代码

//
module tb_encoder3;
reg			h;		//	7	
reg			g;		//	6
reg			f;		//	5
reg			e;		//	4
reg			d;		//	3
reg			c;		//	2
reg			b;		//	1
reg			a;		//	0

wire		none_on;
wire		out2;
wire		out1;
wire		out0;

initial		begin
			//	0		
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};

#20;		//	7
{h, g, f, e, d, c, b, a} = {1'b1, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};

#20;		//	6
{h, g, f, e, d, c, b, a} = {1'b0, 1'b1, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};

#20;		//	5
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b1, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};

#20;		//	4
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b1, 1'b0, 1'b0, 1'b0, 1'b0};

#20;		//	3
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b0, 1'b1, 1'b0, 1'b0, 1'b0};

#20;		//	2
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b1, 1'b0, 1'b0};

#20;		//	1
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b1, 1'b0};

#20;		//	0
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b1};

#200;		//	0
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};

#20;		//	5
{h, g, f, e, d, c, b, a} = {1'b0, 1'b0, 1'b1, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0};

#300;
$stop;
end

encoder3	u1_encoder3(
.h			(h			),
.g			(g			),
.f			(f			),
.e			(e			),
.d			(d			),
.c			(c			),
.b			(b			),
.a			(a			),

.none_on	(none_on	),
.out2		(out2		),
.out1		(out1		),
.out0		(out0		)
);

endmodule

1.6.3.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第14张图片

1.6.3.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第15张图片

1.7,多路器模块设计

1.7.1.1,RTL代码设计,设计方案1

使用连续赋值、case语句 或 if-else语句 可以生成多路器电路。
如果条件语句(case 或 if-else)中分支条件是互斥的话,综合器
能自动地生成并行的路由器。

//	7,多路器的设计实例,(1)
module		emux1(out, a, b, sel);
input		a, b, sel;
output		out;

assign		out	= sel ? a : b;

endmodule

1.7.1.2,tb测试代码

//	7
module	tb_emux1;
reg				a;
reg				b;
reg				sel;

wire			out;

initial		begin
a = 1'b0;	b = 1'b0;	sel	= 1'b0;

repeat(5)	begin
#100
	sel	= {$random}	% 2;
	a	= {$random} % 2;
	b	= {$random} % 2;	
end

#700;
$stop;
end

emux1	u1_emux1(
.a				(a			),
.b				(b			),
.sel			(sel		),

.out			(out		)
);

endmodule

1.7.1.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第16张图片

1.7.1.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第17张图片

1.7.2.1,RTL代码设计,设计方案2

//	多路器设计方案,(2)
module		mux2(out, a, b, sel);
input			a, b, sel;
output	reg		out;
//	用电平触发的 always 块来设计多路器的组合逻辑

always@(a or b or sel)	begin
/*	检查输入信号 sel 的值,如是 1,输出 out 是 a;如是 0,输出 out 是 b.*/
	case(sel)
		1'b1:		out = a;
		1'b0:		out	= b;
		default:	out = 'bx;
	endcase
end
endmodule

1.7.2.2,tb测试代码

//	7,(2)
module		tb_mux2;
reg				a;
reg				b;
reg				sel;

wire			out;

initial		begin
a = 1'b0;	b = 1'b0;	sel	= 1'b0;

repeat(5)	begin
#100
	sel	= {$random}	% 2;
	a	= {$random} % 2;
	b	= {$random} % 2;	
end

#700;
$stop;
end

mux2	u1_mux2(
.a				(a			),
.b				(b			),
.sel			(sel		),

.out			(out		)
);

endmodule

1.7.2.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第18张图片

1.7.2.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第19张图片

1.7.3.1,RTL代码模块设计,设计方案3

//	多路器设计方案,(3)
module	mux3(out, a, b, sel);
input			a, b, sel;
output	reg		out;

always@(a or b or sel)	begin
	if(sel)
		out	= a;
	else
		out	= b;
end

endmodule

1.7.3.2,tb测试代码

//	7,(2)
module		tb_mux3;
reg				a;
reg				b;
reg				sel;

wire			out;

initial		begin
a = 1'b0;	b = 1'b0;	sel	= 1'b0;

repeat(5)	begin
#100
	sel	= {$random}	% 2;
	a	= {$random} % 2;
	b	= {$random} % 2;	
end

#700;
$stop;
end

mux3	u1_mux3(
.a				(a			),
.b				(b			),
.sel			(sel		),

.out			(out		)
);

endmodule

1.7.3.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第20张图片

1.7.3.4,SIM输出波形图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第21张图片

1.8,奇偶校验位生成器模块设计

1.8.1,RTL代码设计

//	8,奇偶校验位生成器设计实例
module	parity(even_numbits, odd_numbits, input_bus);
input	[7:0]	input_bus;
output	even_numbits, odd_numbits;

assign	odd_numbits 	= ^input_bus;
assign	even_numbits	= ~odd_numbits;

endmodule

1.8.2,tb测试代码

//	8
module		tb_parity;
reg		[7:0]	input_bus;

wire			even_numbits;
wire			odd_numbits;

initial		begin
input_bus		= 8'd0;

repeat(8)	begin
#100;
input_bus		= {$random} % 8;
end

#400;
input_bus		= 8'd0;

end

parity		u1_parity(
.input_bus			(input_bus		),

.even_numbits		(even_numbits	),
.odd_numbits		(odd_numbits	)
);
endmodule

1.8.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第22张图片

1.8.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第23张图片

1.9,三态输出驱动器模块设计

1.9.1.1,RTL代码设计,设计方案1

//	9,三态输出驱动器设计实例(用连续赋值语句建立三态门模型)
//	三态输出驱动器设计方案,(1)
module		trist1(out, in, enable);
input		in, enable;
output		out;

assign		out	= enable ? in : 'bz;

endmodule

1.9.1.2,tb测试代码

//	9,(1)
module		tb_trist1;
reg			in;
reg			enable;
wire		out;

initial		begin
enable	= 1'b0;				in	= 1'b0;	

repeat(8)	begin
#100;
enable	= {$random} % 2;	in	= {$random} % 2;
end

#400;
enable	= {$random} % 2;	in	= {$random} % 2;
end

trist1		u1_trist1(
.in					(in				),
.enable				(enable			),

.out				(out			)
);

endmodule

1.9.1.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第24张图片

1.9.1.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第25张图片

1.9.2.1,RTL代码设计,设计方案2

//	三态输出驱动器设计方案,(2)
module		trist2(out, in, enable);
input		in, enable;
output		out;

//	bufif1 是一个Verilog门级原语(primitive)
bufif1 mybuf1(out, in, enable);

endmodule

1.9.2.2,tb测试代码

//	9,(2)
module		tb_trist2;
reg			in;
reg			enable;
wire		out;

initial		begin
enable	= 1'b0;				in	= 1'b0;	

repeat(8)	begin
#100;
enable	= {$random} % 2;	in	= {$random} % 2;
end

#400;
enable	= {$random} % 2;	in	= {$random} % 2;
end

trist2		u1_trist2(
.in					(in				),
.enable				(enable			),

.out				(out			)
);

endmodule

1.9.2.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第26张图片

1.9.2.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第27张图片

1.10,三态双向驱动器模块设计

1.10.1,RTL代码设计

//	10,三态双向驱动器设计实例
module		bidir(tri_inout, out, in, en, b);
input		en,	in, b;

output		out;
inout		tri_inout;

assign		tri_inout	= en ? in : 'bz;
assign		out			= tri_inout ^ b;

endmodule

1.10.2,tb测试代码

//	10
module		tb_bidir;
reg			en;
reg			in;
reg			b;

wire		tri_inout;
wire		out;

initial		begin
en	= 1'b0;		in	= 1'b0;		b = 1'b0;

repeat(8)	begin
#100;
en	= {$random}%2;	in = {$random}%2;	b = {$random}%2;
end

#400;
$stop;
end

bidir		u1_bidir(
.en			(en				),
.in			(in				),
.b			(b				),

.tri_inout	(tri_inout		),
.out		(out		)
);

endmodule

1.10.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第28张图片

1.10.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第29张图片

2,时序逻辑电路设计

2.1,触发器设计

2.1.1,RTL代码设计

//	11,触发器设计实例
module		dff(q, data, clk);
input			clk, data;
output	reg		q;

always@(posedge clk)		begin
	q	<= data;
end

endmodule

2.1.2,tb测试代码

//	11,时序逻辑
module	tb_dff;
reg		clk;
reg		data;
wire	q;

//	clk
always	#5	clk = ~clk;

initial		begin
clk		= 1'b0;
end

//	
initial		begin
data	= 1'b0;

forever	begin
#10;
data	= {$random} % 2;
end

end

dff		u1_dff(
.clk		(clk		),
.data		(data		),

.q			(q			)
);

endmodule

2.1.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第30张图片

2.1.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第31张图片

2.2,电平敏感型锁存器设计

2.2.1.1,RTL代码设计,方案1

//	12,电平敏感型锁存器设计实例,(1)
module	latch1(q, data, clk);

input		clk, data;
output		q;

assign		q	= clk ? data : q;

endmodule

2.2.1.2,tb测试代码

//
//	12
module	tb_latch1;
reg			clk;
reg			data;

wire		q;

initial		begin
clk		= 1'b1;
data	= 1'b0;

forever		begin
#10
clk		= ~clk;
data	= {$random} % 2;
end

end

latch1		u1_latch1(
.clk			(clk		),
.data			(data		),

.q				(q			)
);

endmodule

2.2.1.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第32张图片

2.2.1.4,SIM输出波形图

在这里插入图片描述

2.2.2.1,RTL代码设计,方案2

//	13,带置位和复位端的电平敏感型锁存器设计实例,(2)
module	latch2(q, data, clk, set, reset);
input		clk, data, set, reset;
output		q;

assign		q = reset ? 0 : (set ? 1 : (clk ? data : q));

endmodule

2.2.2.2,tb测试代码

//
//	13,
module	tb_latch2;
reg			clk;	//	
reg			reset;	//	
reg			set;	//	
reg			data;	//	

wire		q;		//	

initial		begin
clk		= 1'b1;
reset	= 1'b1;
set		= 1'b1;
data	= 1'b0;

forever		begin
#10
clk		= ~clk;
reset	= {$random} % 2;
set		= {$random} % 2;
data	= {$random} % 2;
end

end

latch2		u1_latch2(
.clk			(clk		),
.reset			(reset		),
.set			(set		),
.data			(data		),

.q				(q			)
);

endmodule

2.2.2.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第33张图片

2.2.2.4,SIM输出波形图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第34张图片

2.2.3.1,RTL代码设计,方案3

//	14,电平敏感型锁存器设计实例,(3)
module	latch3(q, data, clk);
input			clk, data;
output	reg		q;

always@(clk or data)		begin
	if(clk)
		q		<= data;
end

endmodule

2.2.3.2,tb测试代码

//
//	14
module		tb_latch3;
reg				clk;
reg				data;

wire			q;

initial		begin
clk		= 1'b1;
data	= 1'b0;

forever		begin
#10
clk		= ~clk;
data	= {$random} % 2;
end

end

latch3		u1_latch3(
.clk			(clk			),
.data			(data			),

.q				(q				)
);

endmodule

2.2.3.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第35张图片

2.2.3.4,SIM输出波形图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第36张图片
注意:
的综合器会产生一警告信息,告诉你产生了一个电平敏感型锁存器,因为我们设计的就是一个电平敏感型锁存器,所以不用管这个警告信息。

2.3,移位寄存器设计

2.3.1,RTL代码设计


//	15,移位寄存器设计实例
module		shifter(din, clk, i_rst, dout);
input				clk, i_rst, din;
output	reg	[7:0]	dout;

always@(posedge clk)		begin
	if(i_rst)					//	清零
		dout	<= 8'b0;
	else	begin
		dout	<= dout	<< 1;	//	左移一位
		dout[0]	<= din;			//	把输入信号放入寄存器的最低位
		end
end

endmodule

2.3.2,tb测试代码

//	tb,测试信号
module		tb_shifter;
reg				clk;
reg				i_rst;
reg				din;

wire	[7:0]	dout;

initial		begin
i_rst	= 1'b1;
#5;
i_rst	= 1'b0;
end

initial		begin
clk		= 1'b1;
din		= 1'b0;

forever	begin
#10;
clk		= ~clk;
din		= {$random} % 2;
end

end

shifter		u1_shifter(
.clk			(clk			),
.i_rst			(i_rst			),
.din			(din			),

.dout			(dout			)
);

endmodule

2.3.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第37张图片

2.3.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第38张图片

2.4,8位计数器设计

2.4.1.1,RTL代码设计,方案1

//	16,8位计数器设计实例,(1)
module	counter1(out, cout, data, load, cin, clk);
input				clk, cin, load;
input		[7:0]	data;

output	reg	[7:0]	out;
output				cout;

always@(posedge clk)		begin
	if(load)
		out		<= data;
	else
		out		<= out + cin;
end

assign	cout	= (& out) & cin;
//	只有当 out[7:0] 的所有各位都是1, 并且进位 cin 也是1时才能产生进位 cout。

endmodule

2.4.1.2,tb测试代码

//	16,(1)
//	测试代码
module		tb_counter1;
reg					clk;
reg					cin;
reg					load;
reg		[7:0]		data;

wire	[7:0]		out;
wire				cout;

always	#10		clk	= ~clk;

initial		begin
clk		= 1'b1;		
load	= 1'b0;		//	不置数

#10;
load	= 1'b1;		//	置数

#20;
load	= 1'b0;		//	不置数
end

//	输入数据
initial		begin	//	顺序执行块
data	= 8'b0000_0000;
cin		= 1'b1;

#40;
data	= 8'b0000_0001;
cin		= 1'b1;

//	repeat(256)		begin
//	#20;
//	data	= 8'b0000_0001 + 1'b1;
//	end

#5400;
data	= 8'b0000_0000;
cin		= 1'b0;
end

counter1	u1_counter1(
.clk				(clk			),
.cin				(cin			),
.load				(load			),
.data				(data			),

.out				(out			),
.cout				(cout			)
);

endmodule

2.4.1.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第39张图片

2.4.1.4,SIM输出波形

(1)全局看进位
13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第40张图片
(2)拉进看进位
13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第41张图片

2.4.2.1,RTL代码设计,方案2

//	17,8位计数器设计实例,(2)
module	counter2(out, cout, data, load, cin, clk);
input				load, cin, clk;
input		[7:0]	data;

output	reg	[7:0]	out;
output	reg			cout;

reg			[7:0]	preout;

//	创建 8位 寄存器
always@(posedge clk)		begin
	out		<= preout;
end

/*	计算计数器和进位的下一个状态。注意:为提高性能不希望加载影响到进位。 */
always@(out or data or load or cin)		begin
	{cout, preout}	= out + cin;
	
	if(load)
		preout		= data;

end

endmodule

2.4.2.2,tb测试代码

//	17,(2)
//	测试代码
module		tb_counter2;
reg				clk;
reg				cin;
reg				load;
reg		[7:0]	data;

wire	[7:0]	out;
wire			cout;			

initial		begin
load	= 1'b0;				//	不置位
data	= 8'b0000_0000;
cin		= 1'b1;

#40;
load	= 1'b1;				//	置位
data	= 8'b0000_0001;
//	cin		= 1'b1;

#20;						//	不置位
load	= 1'b0;

#6000;						//	置位
load	= 1'b1;
data	= 8'b1000_0000;
cin		= 1'b0;
end

always	#10		clk = ~clk;
initial		begin
clk		= 1'b1;
end

counter2		u1_counter2(
.clk				(clk			),
.cin				(cin			),
.load				(load			),
.data				(data			),

.out				(out			),
.cout				(cout			)
);

endmodule

2.4.2.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第42张图片

2.4.2.4,SIM输出波形

(1)全局,看进位、置位;
13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第43张图片
(2)拉进,看进位、置位;
13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第44张图片

3,状态机的置位和复位

3.1,状态机的异步置位与复位

3.1.1,带异步高电平有效的置/复位端的D触发器,RTL设计

//	13.6.1	状态机的异步置位与复位是用 always 块和事件控制实现的。
//			带异步高电平有效的 置/复位端 的 D触发器实例
module		dff1(q, qb, d, clk, set, reset);
input			clk, d, set, reset;
output	reg		q, qb;
//	声明 q 和 qb 为 reg类型,因为它需要在 always 块内赋值

always@(posedge clk or posedge set or posedge reset)	begin
	if(reset)	begin
		q	<= 0;
		qb	<= 1;
		end
	else	
		if(set)		begin
			q	<= 1;
			qb	<= 0;
			end
		else	begin
			q	<= d;
			qb	<= ~d;
			end
end

endmodule

3.1.2,tb测试信号

//	18,异步
module		tb_dff1;
reg					clk;
reg					reset;
reg					set;
reg					d;

wire				q;
wire				qb;

initial		begin
reset		= 1'b0;		//	no vld.
set			= 1'b0;
d			= 1'b0;

#10;
reset		= 1'b1;		//	vld.
set			= 1'b0;
d			= 1'b1;

#20;
reset		= 1'b1;		//	vld	
set			= 1'b1;
d			= 1'b0;

#40;
reset		= 1'b0;
set			= 1'b1;
d			= 1'b0;

#400;					//	no vld.
reset		= 1'b0;
set			= 1'b0;
d			= 1'd1;

#20;
d			= 1'd0;

#20;
d			= 1'd1;

#20;
d			= 1'd0;
end

always		#10		clk = ~clk;
initial		begin
clk			= 1'b1;
end

dff1		u1_dff1(
.clk			(clk			),
.reset			(reset			),
.set			(set			),
.d				(d				),

.q				(q				),
.qb				(qb				)
);

endmodule

3.1.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第45张图片

3.1.4,SIM输出波形图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第46张图片

3.2,状态机的同步置位与复位

3.2.1,同步的具有高电平有效的置位/复位端的D触发器,RTL设计

//	13.6.2	状态机的同步置位与复位
//	同步的具有高电平有效的 置位/复位 的 D触发器
module	dff2(q, qb, d, clk, set, reset);
input			clk, d, set, reset;
output	reg		q, qb;

always@(posedge clk)		begin
	if(reset)	begin
		q	<= 0;
		qb	<= 1;
		end
	else	begin
		if(set)		begin
			q	<= 1;
			qb	<= 0;
			end
		else	begin
			q	<= d;
			qb	<= ~d;
			end
		end
end

endmodule

3.2.2,tb测试信号

//	19,同步
module		tb_dff2;
reg				clk;
reg				reset;
reg				set;
reg				d;

wire				q;
wire				qb;

initial		begin
reset		= 1'b0;		
set			= 1'b0;
d			= 1'b0;		// 	vld.

#10;
reset		= 1'b1;		//	vld.
set			= 1'b0;
d			= 1'b1;

#20;
reset		= 1'b1;		//	vld,
set			= 1'b1;
d			= 1'b0;

#40;
reset		= 1'b0;
set			= 1'b1;		//	vld.
d			= 1'b0;

#400;					
reset		= 1'b0;
set			= 1'b0;
d			= 1'd1;		//	vld.

#20;
d			= 1'd0;		//	vld.

#20;
d			= 1'd1;		//	vld.

#20;
d			= 1'd0;		//	vld.
end

always		#10		clk = ~clk;
initial		begin
clk			= 1'b1;
end

dff2		u1_dff2(
.clk			(clk			),
.reset			(reset			),
.set			(set			),
.d				(d				),

.q				(q				),
.qb				(qb				)
);
endmodule

3.2.3,生成原理图

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第47张图片

3.2.4,SIM输出波形

13-设计可综合状态机的指导原则,本文对于Verilog设计方法学至关重要!_第48张图片

4,编码风格的总结

本文阐述了什么样的风格的Verilog模块是可以综合成电路结构的,以及综合的一般原则。此外,对于一般的综合工具而言,可以借助于工具自动综合成电路结构的Verilog模块风格非常有限,如1.1节的组合逻辑和3.2节同步状态机的标准写法。

注意:
当系统比较复杂时,需要通过仔细的分析,把一个具体系统分解为数据流和控制流。构思哪些部分用组合逻辑,哪些部分的资源可以共享而不影响系统的性能,需要设置哪些开关逻辑来控制数据的流动,需要一个或几个同步有限状态机来正确有序地控制这些开关逻辑,以便有效地利用有限的硬件资源,才能编写出真正有价值的RTL级源代码,从而综合出有实用价值的高性能的数字逻辑电路系统。

因此,认真学习并掌握数字电路基础和计算机体系结构这两门学科的真谛是Verilog数字系统设计的基础。

你可能感兴趣的:(Verilog数字系统设计教程,fpga开发,Verilog前端设计)