微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 硬件工程师文库 > 通过模块之间的调用实现自顶向下的设计

通过模块之间的调用实现自顶向下的设计

时间:02-11 来源:网络整理 点击:

练习十. 通过模块之间的调用实现自顶向下的设计目的:学习状态机的嵌套使用实现层次化、结构化设计。
现代硬件系统的设计过程与软件系统的开发相似,设计一个大规模的集成电路的往往由模块多层次的引用和组合构成。层次化、结构化的设计过程,能使复杂的系统容易控制和调试。 在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的序列检测器搭接,形成一个封闭系统。编写测试模块,并给出仿真波形。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top