inout 端口的使用
第一次遇到inout
端口的使用,是在大三的时候,课程要求写一个通过 I2C 读取EEPROM的电路。当时连抄带蒙实现了功能,助教略略检查了一下就过关了。现在导师给了个小任务,给一个存储芯片写SPI接口,这又涉及到inout
端口的使用了。不必奇怪,SPI的Master的确不需要用inout
,但现在做的事写SPI的Slave,目标存储器用了inout
。
稍稍百度一下可以知道,inout
需要一个三态门,一个实现方法是(当然还有其它方法):
assign data_io=read?mem_tmp:8'bzzzzzzzz;
读取时,往mem_tmp
送数据,接收输入时,直接从inout
端口取数据,类似于:
mem_tmp <= memory[addr];
这是被读取端。
如何进行测试
也许是我没认真看其它网友的博客,我根据自己的理解理了理对inout
端口的Testbench的编写。
首先,Testbench没有端口,也就没有inout
类型的信号/变量可以用,读取数据需要wire
类型的信号,写入数据需要reg
类型的信号,也就是说需要两个信号来测试inout
端口。
举个例子,一个16-Byte随机存取存储器:
`timescale 1ns/1ps
module ram_16x8bit(
input clk,
input [7:0] addr,
input read,
inout [7:0] data_io
);
reg [7:0] memory[0:15];
reg [7:0] mem_tmp;
assign data_io=read?mem_tmp:8'bzzzzzzzz;
initial begin
$readmemh("mem.txt", memory);
end
always@(posedge clk) begin
if(read) mem_tmp <= memory[addr];
else memory[addr] <= data_io;
end
endmodule // 16Byte ram
它的Testbench可以是:
`timescale 1ns/1ps
module test;
reg clk;
reg [7:0] addr;
reg read;
wire [7:0] data_wire;
reg [7:0] data_reg;
assign data_wire = read?8'hzz:data_reg;
initial begin
$dumpfile("wave.vcd");
$dumpvars(0,test);
clk = 1'b1;
forever begin
#5 clk = ~clk;
end
end
integer i;
initial begin
// Read Test
#10;
i = 0;
while(i<=15) begin
#10;
read = 1'b1;
addr = i;
i = i + 1;
end
//Write Test
i = 0;
while(i<=15) begin
#10;
read = 1'b0;
addr = i;
data_reg = 15 - i;
i = i + 1;
end
i = 0;
while(i<=15) begin
#10;
read = 1'b1;
addr = i;
i = i + 1;
end
#10 $finish;
end
ram_16x8bit test_ram(
.clk(clk),
.addr(addr),
.read(read),
.data_io(data_wire)
);
endmodule
对inout
端口的处理:
assign data_wire = read?8'hzz:data_reg;
示意图如下:
VCS生成的Schematic:
测试波形:
结论
本文实现了对inout
端口的读写。