通过模块之间的调用实现自顶向下的设计
练习十. 通过模块之间的调用实现自顶向下的设计目的:学习状态机的嵌套使用实现层次化、结构化设计。
现代硬件系统的设计过程与软件系统的开发相似,设计一个大规模的集成电路的往往由模块多层次的引用和组合构成。层次化、结构化的设计过程,能使复杂的系统容易控制和调试。 在Verilog HDL中,上层模块引用下层模块与C语言中程序调用有些类似,被引用的子模块在综合时作为其父模块的一部分被综合,形成相应的电路结构。在进行模块实例引用时,必须注意的是模块之间对应的端口,即子模块的端口与父模块的内部信号必须明确无误地一一对应,否则容易产生意想不到的后果。
下面给出的例子是设计中遇到的一个实例,其功能是将并行数据转化为串行数据送交外部电路编码,并将解码后得到的串行数据转化为并行数据交由CPU处理。显而易见,这实际上是两个独立的逻辑功能,分别设计为独立的模块,然后再合并为一个模块显得目的明确、层次清晰。
// ---------------- p_to_s.v ---------------------------------
module p_to_s(D_in,T0,data,SEND,ESC,ADD_100);
output D_in,T0; // D_in是串行输出,T0是移位时钟并给
// CPU中断,以确定何时给出下个数据。
input [7:0] data; //并行输入的数据。
input SEND,ESC,ADD_100; //SEND、ESC共同决定是否进行并到串
//的数据转化。ADD_100决定何时置数。
wire D_in,T0;
reg [7:0] DATA_Q,DATA_Q_buf;
assign T0 = ! (SEND & ESC); //形成移位时钟。.
assign D_in = DATA_Q[7]; //给出串行数据。
always @(posedge T0 or negedge ADD_100) //ADD_100下沿置数,T0上沿移位。
begin
if(!ADD_100)
DATA_Q = data;
else
begin
DATA_Q_buf = DATA_Q<<1; //DATA_Q_buf作为中介,以令综合器
DATA_Q = DATA_Q_buf; //能辨明。
end
end
endmodule
在p_to_s.v中,由于移位运算虽然可综合,但是不是简单的RTL级描述,直接用DATA_Q<=DATA_Q<<1的写法在综合时会令综合器产生误解。另外,在该设计中,由于时钟T0的频率较低,所以没有象以往那样采用低电平置数,而是采用ADD_100的下降沿置数。
//--------------------- s_to_p.v ---------------------------
module s_to_p(T1, data, D_out,DSC,TAKE,ADD_101);
output T1; //给CPU中断,以确定CPU何时取转化
//得到的并行数据。
output [7:0] data;
input D_out, DSC, TAKE, ADD_101; //D_out提供输入串行数据。DSC、TAKE
//共同决定何时取数。
wire [7:0] data;
wire T1,clk2;
reg [7:0] data_latch, data_latch_buf;
assign clk2 = DSC & TAKE ; //提供移位时钟。
assign T1 = !clk2;
assign data = (!ADD_101) ? data_latch : 8'bz;
always@(posedge clk2)
begin
data_latch_buf = data_latch << 1; //data_latch_buf作缓冲
data_latch = data_latch_buf; //,以令综合器能辩明。
data_latch[0] = D_out;
end
endmodule
将上面的两个模块合并起来的sys.v的源代码:
//------------------- sys.v ---------------------------
`include "./p_to_s.v"
`include "./s_to_p.v"
module sys(D_in,T0,T1, data, D_out,SEND,ESC,DSC,TAKE,ADD_100,ADD_101);
input D_out,SEND,ESC,DSC,TAKE,ADD_100,ADD_101;
inout [7:0] data;
output D_in,T0,T1;
p_to_s p_to_s(.D_in(D_in),.T0(T0),.data(data),
.SEND(SEND),.ESC(ESC),.ADD_100(ADD_100));
s_to_p s_to_p(.T1(T1),.data(data),.D_out(D_out),
.DSC(DSC),.TAKE(TAKE),.ADD_101(ADD_101));
endmodule
测试模块源代码:
//-------------Top test file for sys.v ------------------
`TImescale 1ns/100ps
`include "./sys.v"
module Top;
reg D_out,SEND,ESC,DSC,TAKE,ADD_100,ADD_101;
reg[7:0] data_buf;
wire [7:0] data;
wire clk2;
assign data = (ADD_101) ? data_buf : 8'bz;
//data在sys中是inout型变量,ADD_101
//控制data是作为输入还是进行输出。
assign clk2 =DSC && TAKE;
iniTIal
begin
SEND = 0;
ESC = 0;
DSC = 1;
TAKE = 1;
ADD_100 = 1;
ADD_101 = 1;
end
iniTIal
begin
data_buf = 8'b10000001;
#90 ADD_100 = 0;
#100 ADD_100 = 1;
end
always
begin
#50;
SEND = ~SEND;
ESC = ~ESC;
end
iniTIal
begin
#1500 ;
SEND = 0;
ESC = 0;
DSC = 1;
TAKE = 1;
ADD_100 = 1;
ADD_101 = 1;
D_out = 0;
#1150 ADD_101 = 0;
#100 ADD_101 =1;
#100 $stop;
end
always
begin
#50 ;
DSC = ~DSC;
TAKE = ~TAKE;
end
always @(negedge clk2) D_out = ~D_out;
sys sys(.D_in(D_in),.T0(T0),.T1(T1),.data(data),.D_out(D_out),
.ADD_101(ADD_101), .SEND(SEND),.ESC(ESC),.DSC(DSC),
.TAKE(TAKE),.ADD_100(ADD_100));
endmodule
仿真波形:[[wysiwyg_imageupload:255:]]
练习:设计一个序列发生器。要求根据输入的8位并行数据输出串行数据,如果输入数据在0—127之间则输出一位0,如果输入数据在128—255之间则输出一位1,同步时钟触发;并且和范例8的序列检测器搭接,形成一个封闭系统。编写测试模块,并给出仿真波形。
- 基于有限状态机在LIN总线开发中的应用(03-20)
- FPGA工程师:如何在FPGA中实现状态机?(03-01)
- 基于状态机的LCD多级菜单设计方案(06-25)
- 利用状态机的状态机实现层次结构化设计(02-11)
- 初学者对有限状态机(FSM)的设计的认识(02-11)
- ISE设计有关疑难问题与解决连载之综合warning解决办法(02-11)