宋桓公

inout仿真终极方案

0
阅读(3860)

   仿真inout确实是个麻烦事,同一个端口,既要写TestBeach输入激励信号,又要观察输出的响应信号。但是往往,就看到了自己 的输入激励,而看不到响应信号,今天就通过一个例子,提出一个简单的仿真方案。
   首先,建模部分如下:

 1:  module inout_test
 2: (
 3:  input CLK,
 4:  input RSTn,
 5:  
 6:  inout [31:0] pci_ad
 7: );
 8:  
 9:  parameter read_ad = 1'b0;
 10:  parameter write_ad = 1'b1;
 11:  
 12:  reg pci_ad_oe;
 13:  reg [31:0]pci_dat_out;
 14:  assign pci_ad = pci_ad_oe ? pci_dat_out : 32'bZ; 
 15:  
 16:  reg [3:0]i;
 17:  always @(posedge CLK or negedge RSTn)
 18:  if(!RSTn)
 19:  begin
 20:  i <= 4'd0;
 21:  pci_ad_oe <= read_ad;
 22:  pci_dat_out <= 32'd0;
 23:  end
 24:  else
 25:  case(i)
 26:  0:
 27:  begin
 28:  pci_ad_oe <= read_ad;
 29:  i <= i + 1'b1;
 30:  end
 31:  1:
 32:  begin
 33:  i <= i + 1'b1;
 34:  end
 35:  2:
 36:  begin
 37:  i <= i + 1'b1;
 38:  end
 39:  //------
 40:  3:
 41:  begin
 42:  pci_ad_oe <= write_ad;
 43:  pci_dat_out <= 32'd33;
 44:  i <= i + 1'b1;
 45:  end
 46:  4:
 47:  begin
 48:  pci_dat_out <= 32'd44;
 49:  i <= i + 1'b1;
 50:  end
 51:  5:
 52:  begin
 53:  pci_dat_out <= 32'd55;
 54:  i <= i + 1'b1;
 55:  end
 56:  6:
 57:  begin
 58:  pci_dat_out <= 32'd66;
 59:  end
 60:  
 61:  endcase
 62:  
 63: endmodule


观察程序:inout [31:0] pci_ad;  pci_ad声明为inout变量。
而是关键实现输入输出的语句是:
assign pci_ad = pci_ad_oe ? pci_dat_out : 32'bZ;

当变量 pci_ad_oe == 1 时,pci_ad作为输出端口,将pci_dat_out的值输出,
此时控制pci_dat_out就能控制pci_ad的输出。

当 pci_ad_oe == 0 时,pci_ad作为输入端口,此时pci_dat_out对端口不再
产生影响,能影响pci_ad的只能是外部的激励(输入信号)。

接着看程序,步骤0,1,2,(即当i为0,1,2)时pci_ad作为输入端口,
接收外部的激励信号;步骤3,4,5,6时,pci_ad作为输出端口,输出
响应信号。

 

建模部分完毕,接着编写TestBeach:

 1: `timescale 1 ps/ 1 ps
 2: module inout_test_vlg_tst();
 3:  
 4: reg CLK;
 5: reg RSTn;
 6: reg [31:0] treg_pci_ad;
 7:  
 8: wire [31:0]  pci_ad;
 9:  
 10: assign pci_ad = treg_pci_ad;
 11:  
 12: inout_test i1 (
 13:  .CLK(CLK),
 14:  .RSTn(RSTn),
 15:  .pci_ad(pci_ad)
 16: );
 17:  
 18: initial                                                
 19: begin 
 20:  RSTn = 0; #10 RSTn = 1;
 21:  CLK = 1; forever #5 CLK = ~CLK;
 22: end 
 23:  
 24:  reg [3:0]Ti;
 25:  always @(posedge CLK or negedge RSTn)
 26:  if(!RSTn)
 27:  begin
 28:  Ti <= 4'd0;
 29:  end
 30:  else
 31:  case(Ti)
 32:  0:
 33:  begin
 34:  treg_pci_ad <= 32'd1;
 35:  Ti <= Ti + 1'b1;
 36:  end
 37:  1:
 38:  begin
 39:  treg_pci_ad <= 32'd2;
 40:  Ti <= Ti + 1'b1;
 41:  end
 42:  2:
 43:  begin
 44:  treg_pci_ad <= 32'd3;
 45:  Ti <= Ti + 1'b1;
 46:  end
 47:  3:
 48:  begin
 49:  treg_pci_ad <= 32'd4;
 50:  Ti <= Ti + 1'b1;
 51:  end
 52:  4:
 53:  begin
 54:  treg_pci_ad <= 32'd5;
 55:  Ti <= Ti + 1'b1;
 56:  end
 57:  5:
 58:  begin
 59:  treg_pci_ad <= 32'd6;
 60:  Ti <= Ti + 1'b1;
 61:  end
 62:  6:
 63:  begin
 64:  treg_pci_ad <= 32'd7;
 65:  end
 66:  
 67:  endcase
 68:  
 69: endmodule

首先,说明在建模完成之后,我喜欢自动生成TestBeach,这样的好处是他会根据你的建模程序,
自动生成变量声明,正好和你的建模一一对应,而不用自己一个个声明。当然主体测试程序还是
得自己编写。具体步骤方法如下图所示:

image_thumb[33]

 

接着看,TestBeach的具体内容:

assign pci_ad = treg_pci_ad;这句也自动生成的,每当你声明了一个inout端口,他就会自动生成
一个变量,这个变量的命名方法就是在你的inout变量名字前加一个“treg_”前缀。这个变量的作用
就是让你模拟激励信号的。也就是说,inout的输入信号就靠他了。
   
    回头看看建模部分,有步骤i(0~6),共7个,同样在TestBeach有步骤Ti(0~6)共7个,且

他们是 一一对应的,不理解这个对应关系不要紧,我想把仿真图调出来给您瞧瞧:

image_thumb[17]

   没错他们在时钟上是一一对应的。我们记得在建模时,步骤0,1,2,总线是作为输入状态的,此时
   可观察激励信号,步骤3,4,5,6是输出时刻,观察响应信号。

   而在,TestBeach中Ti的7个步骤全部是输入激励信号。于是我们猜测,在步骤0,1,2时,我们看到是
   激励信号,也就是treg_pci_ad的值——分别是0,1,2。而步骤3,4,5,6时treg_pci_ad的值不再起
   作用,我们看到的应该是响应信号pci_dat_out的值33,44,55,66。是不是这样呢,我们继续看仿真
   图:

image_thumb[35]

   我们发现,激励值是看到了,没错是1,2,3,但是pci_ad_oe拉高之后,我们只能看到一堆XX,而看不
到响应信号的值,这就是我们之前说所说的:“看到了自己的输入激励,而看不到响应信号”,了解到这个
问题之后,要解决这个问题其实不难,只要在建模里加上两句话即可:

output [31:0] Tout_pci_ad,//用于观察总线的输出信号

assign Tout_pci_ad = pci_ad_oe ? pci_dat_out : 32'bZ;

也就是新增一个输出,信号Tout_pci_ad专门用于观察pci_ad的输出响应值,由于新增了引脚输出,编译后,
别忘了从新生成TestBeach(温馨提示:在此之前,请另存TestBeach的主体控制代码,免得被从新写,呵呵!)
这样的话输入输出就能看啦:

image_thumb[37]

总结:原本的是inout端口,仅仅能作为输入端口,观察激励信号,想观察输出的响应的,需另外加上Tout_输出
信号专门用于观察输出信号。

需要修改后完整程序的话,留下邮箱,我发给您。

 

 技术讨论欢迎加群~~电子技术协会   362584474