练习十-通过模块实例调用实现大型系统的设计

练习十-通过模块实例调用实现大型系统的设计

      • 1,任务目的
      • 2,RTL代码,两个独立的模块和一个接口模块
        • 2.1,P_S模块RTL
        • 2.2,S_P模块的RTL
        • 2.3,sys的接口模块实现
      • 3,带有数据流的原理框图,以及vivado生成的RTL框图
        • 3.1,带有数据流的原理框图
        • 3.2,vivado生成的原理框图
      • 4,顶层模块
      • 5,测试输出波形正确

1,任务目的

(1)学习和掌握状态机的嵌套和模块实例的连接方法;
(2)了解大型系统设计的层次化、结构化解决办法的技术基础;
(3)学习数据总线在模块设计中的应用和控制,掌握复杂接口模块设计的基本技术;
(4)学习和掌握用工程概念来编写较完整的测试模块,做到接近真实的完整测试。

现代硬件系统的设计过程与软件系统的开发相似,设计一个大规模的集成电路,往往由模块经多层次引用和组合构成。层次化、结构化的设计过程,能使复杂的系统变得容易控制和调试。
在Verilog模块设计中,上层模块引用下层模块,这与C语言中的程序调用有些类似,被引用的子模块在综合时作为其父模块的一部分被综合,形成相应的电路结构。在进行模块实例引用时,必须注意的是模块之间对应的端口,即子模块的端口与父模块的内部信号必须明确无误地一一对应,否则容易产生意想不到的后果。
本文省去了编码部分以及与计算机的接口,只留下CPU数据总线作为并行数据的出入通道。这实际上是两个独立的逻辑功能模块:
一个是并行数据流转换为串行位流;
一个是将该串行位流又转换为并行数据。
分别设计成两个独立的模块,然后再合并为一个模块,共享同一条数据总线和时钟。

注意:
假设从并行数据总线上输入到模块的数据其到达的时间,有一定的随机性,测试模块如何来表达这些问题,如何设计出能保证可靠接收和发送的接口是需要有经验的。

2,RTL代码,两个独立的模块和一个接口模块

2.1,P_S模块RTL
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/11/23 11:28:54
// Design Name: 
// Module Name: P_S
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

//	模块功能:
//	把在nGet_AD_data负跳变沿时刻后能维持约3个时钟周期
//	的并行字节数据取入模块,在时钟节拍下转换为字节的
//	位流,并产生相应字节位流的有效信号

`define		YES 1
`define		NO	0
module	P_S(
Dbit_out, link_S_out, data, 
nGet_AD_data, clk
);
input	clk;				// 主时钟节拍
input	nGet_AD_data;		// 负电平有效时取并行数据控制信号线
input	[7:0]	data;		//	并行输入的数据端口
output	Dbit_out;			//	串行位流的输出

output	link_S_out;			//	允许串行位流输出的控制信号
reg		link_S_out;			//	串行位流输出的控制信号寄存器

reg		[3:0]	state;		//	状态变量寄存器
reg		[7:0]	data_buf;	//	并行数据缓存器
reg		d_buf;				//	位缓存器
reg		finish_flag;		//	字节处理结束标志

assign	Dbit_out = (link_S_out) ? d_buf : 0;	// 给出串行数据

always@(posedge clk or negedge nGet_AD_data)	
// nGet_AD_data 下降沿置数,寄存器清零,clk上跳沿送出位流
	if(!nGet_AD_data)	begin
		finish_flag		<= 0;
		state			<= 9;		//	延迟两个状态:9、10
		link_S_out		<= `NO;
		d_buf			<= 0;
		data_buf		<= 0;
		end
	else	
		case(state)
			9:	begin
				data_buf	<= data;
				state		<= 10;
				link_S_out	<= `NO;
				end
			10:	begin
				data_buf	<= data;
				state		<= 0;
				link_S_out	<= `NO;
				end
			0:	begin
				d_buf		<= data_buf[7];
				state		<= 1;
				link_S_out	<= `YES;
				end
			1:	begin
				d_buf		<= data_buf[6];
				state		<= 2;
				end
			2:	begin
				d_buf		<= data_buf[5];
				state		<= 3;
				end
			3:	begin
				d_buf		<= data_buf[4];
				state		<= 4;
				end
			4:	begin
				d_buf		<= data_buf[3];
				state		<= 5;
				end
			5:	begin
				d_buf		<= data_buf[2];
				state		<= 6;
				end
			6:	begin
				d_buf		<= data_buf[1];
				state		<= 7;
				end
			7:	begin
				d_buf		<= data_buf[0];
				state		<= 8;
				end
			8:	begin
				state		<= 4'b1111;	// do nothing state
				link_S_out	<= `NO;

				finish_flag	<= 1;
				end
			default:	begin
				state		<= 4'b1111;	// do nothing state
				link_S_out	<= `NO;

				end
		endcase
		
endmodule
2.2,S_P模块的RTL
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/11/23 11:30:36
// Design Name: 
// Module Name: S_P
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

//	S_P.v
//	模块功能:把在位流有效信号控制下的字节位流读入模块,在时钟节拍控制下
//	转换为并行的字节数据,输出到并行数据口

`define	YES		1
`define	NO		0
module	S_P(
data,		Dbit_in,
Dbit_ena,	clk
);
output	[7:0]		data;	// 并行数据输出口
input	Dbit_in,	clk;	//	字节位流输入口
input	Dbit_ena;			// 字节位流使能输入口

reg		[7:0]	data_buf;
reg		[3:0]	state;		//	状态变量寄存器
reg				p_out_link;	//	并行输出控制寄存器

assign	data = (p_out_link == `YES) ? data_buf : 8'bz;

always@(negedge clk)
	if(Dbit_ena)
		case(state)
		0:	begin
			p_out_link	<= `NO;
			
			data_buf[7]	<= Dbit_in;
			state		<= 1;
			end
			
		1:	begin
			data_buf[6]	<= Dbit_in;
			state		<= 2;
			end
		
		2:	begin
			data_buf[5]	<= Dbit_in;
			state		<= 3;
			end
			
		3:	begin
			data_buf[4]	<= Dbit_in;
			state		<= 4;
			end
		
		4:	begin
			data_buf[3]	<= Dbit_in;
			state		<= 5;
			end
		
		5:	begin
			data_buf[2]	<= Dbit_in;
			state		<= 6;
			end
		
		6:	begin
			data_buf[1]	<= Dbit_in;
			state		<= 7;
			end
		
		7:	begin
			data_buf[0]	<= Dbit_in;
			state		<= 8;
			end
			
		8:	begin
			p_out_link	<= `YES;
			state		<= 4'b1111;
			end
			
		default:
			state		<= 0;
			
		endcase
		
	else	begin
		p_out_link	<= `YES;
		state		<= 0;
		end
	
endmodule

2.3,sys的接口模块实现
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/11/23 11:31:42
// Design Name: 
// Module Name: sys
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


//	模块的功能:把两个独立的逻辑模块(P_S和S_P)合并到一个可综合的模块中,
//	共用一条并行总线,配合有关信号,分别进行输入/输出

//	模块的目的:学习如何把两个单向输入/输出的实例模块,连接在一起,共享一条总线
//	本模块是完全可综合模块,已经通过综合和布线后仿真

module	sys(databus, use_p_in_bus, Dbit_out,
Dbit_ena, nGet_AD_data, clk);
input	nGet_AD_data;	//	取并行数据的控制信号
input	use_p_in_bus;	//	并行总线用于输入数据的控制信号
input	clk;			//	主时钟

inout	[7:0]	databus;	// 双向并行数据总线
output	Dbit_out;		//	字节位流输出
output	Dbit_ena;		//	字节位流输出使能

wire	clk;
wire	nGet_AD_data;
wire	Dbit_out;
wire	Dbit_ena;
wire	[7:0]	data;

assign	databus = (!use_p_in_bus) ? data : 8'bzzzz_zzzz;

//	端口例化
P_S m0(
.Dbit_out		(Dbit_out		),
.link_S_out		(Dbit_ena		),
.data			(databus		),
.nGet_AD_data	(nGet_AD_data	),
.clk			(clk			)
);

S_P	m1(
.data			(data			),
.Dbit_in		(Dbit_out		),
.Dbit_ena		(Dbit_ena		),
.clk			(clk			)
);

endmodule

3,带有数据流的原理框图,以及vivado生成的RTL框图

3.1,带有数据流的原理框图

3.2,vivado生成的原理框图

练习十-通过模块实例调用实现大型系统的设计_第1张图片

4,顶层模块

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/11/23 11:32:23
// Design Name: 
// Module Name: top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

//	模块的功能:对合并在一起的可综合的sys模块进行测试验证。
//	其测试信号尽可能地与实际情况一致,用随机数系统任务对数
//	据的到来和时钟沿的抖动都进行了模拟仿真。本模块无任何工程
//	价值,只有学习价值。
module	top;
reg				clk;
reg		[7:0]	data_buf;
reg				nGet_AD_data;
reg				D_Pin_ena;	//	并行数据输入sys模块的使能信号寄存器

wire	[7:0]	data;
wire			clk2;
wire			Dbit_ena;

assign			data = (D_Pin_ena) ? data_buf : 8'bz;

initial		begin
	clk 			 = 0;
	nGet_AD_data	 = 1;				// 	置取数据控制信号初始值为高电平
	data_buf		 = 8'b1001_1001;	//	假设数据缓存器的初始值,可用于模拟并行数据的变化
	D_Pin_ena		 = 0;
end

initial		begin
	repeat(100)
	begin
		#(100 * 14 + {$random}%23) 	nGet_AD_data = 0;	// 取并行数据开始
		#(112 + {$random}%12)		nGet_AD_data = 1;	// 保持一定时间低电平后恢复高电平
		#({$random}%50)				D_Pin_ena	 = 1;	// 并行数据输入sys模块的使能信号有效
		#(100 * 3 + {$random}%5)	D_Pin_ena	 = 0;	// 保持三个时钟周期后让出总线
		#333						data_buf	 = data_buf + 1;	// 假设数据变化,可为下次取得不同的数据
		#(100*11 + {$random}%1000);
	end
end

always	#(50 + $random%2)	clk = ~clk;		// 主时钟的产生

sys	ms(
.databus		(data			),
.use_p_in_bus	(D_Pin_ena		),
.Dbit_out		(Dbit_out		),
.Dbit_ena		(Dbit_ena		),
.nGet_AD_data	(nGet_AD_data	),
.clk			(clk			)
);

endmodule

5,测试输出波形正确

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