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;

示意图如下:

Verilog 中 inout 端口的使用与测试-冯金伟博客园

VCS生成的Schematic:

Verilog 中 inout 端口的使用与测试-冯金伟博客园

测试波形:

Verilog 中 inout 端口的使用与测试-冯金伟博客园

结论

本文实现了对inout端口的读写。