跳转至

三态门

如果同学直接按照前面讲的的方式去实现 SRAM 控制器,会遇到这样的一个问题:读和写都需要经过同样的信号 sram_data 来传输数据,这怎么实现呢?如果实现错误,就会导致读取的数据一直是错误的。

在一些接口协议中,比如这里的 SRAM 等等,为了节省引脚数量,都出现了同一个信号在不同的时间传输不同方向的数据的现象。因此,为了防止两端设备同时输出,设备在不输出信号时需要设置高阻态。在 SystemVerilog 代码中,我们通常会将三态门 signal_io 拆分成三个信号:signal_isignal_osignal_t,分别表示输入、输出和高阻态。对应的代码如下:

module tri_state_logic (
    inout signal_io
);

    wire signal_i;
    wire signal_o;
    wire signal_t;

    assign signal_io = signal_t ? 1'bz : signal_o;
    assign signal_i = signal_io;

endmodule

这样实现以后,内部就可以很方便地处理三态逻辑了。需要输出时,设置 signal_t=0,把 signal_o 设置为想要输出的值;需要输入时,设置 signal_t=1,从 signal_i 获取输入数据。

以 SRAM 为例,对于 sram_data 来说,需要按照如下的方式来处理:

module sram_controller (
    inout [31:0] sram_data
);

    wire [31:0] sram_data_i_comb;
    reg [31:0] sram_data_o_comb;
    reg sram_data_t_comb;

    assign sram_data = sram_data_t_comb ? 32'bz : sram_data_o_comb;
    assign sram_data_i_comb = sram_data;

    always_comb begin
        sram_data_t_comb = 1'b0;
        sram_data_o_comb = 32'b0;

        // ...
    end
endmodule

sram_data_t_comb=1 的时候,表示进入高阻态,此时对应的是读操作,读取的数据在 sram_data_i_comb 信号;当 sram_data_t_comb=0 的时候,进入输出状态,此时对应的是写操作。对于 SRAM 控制器来说,只需要在相应的状态下,设置 sram_data_t_comb 即可。

上面的 sram_data_o_combsram_data_t_comb 也可以改成用寄存器来实现,结合状态机,可以按照下面的思路实现:

module sram_controller (
    inout [31:0] sram_data
);

    wire [31:0] sram_data_i_comb;
    reg [31:0] sram_data_o_reg;
    reg sram_data_t_reg;

    assign sram_data = sram_data_t_reg ? 32'bz : sram_data_o_reg;
    assign sram_data_i_comb = sram_data;

    always_ff @ (posedge clock) begin
        if (reset) begin
            // high-Z when reset
            sram_data_t_reg <= 1'b1;
            sram_data_o_reg <= 32'b0;
            // ...
        end else begin
            // ...
            if (STB_I && CYC_I && state == STATE_IDLE) begin
                if (WE_I) begin
                    // write
                    sram_data_t_reg <= 1'b0;
                    sram_data_o_reg <= DAT_I;
                    state <= STATE_WRITE;
                end else begin
                    // read
                    sram_data_t_reg <= 1'b1;
                    state <= STATE_READ;
                end
            end
        end
    end
endmodule

最后更新: 2023年11月5日
作者:Jiajie Chen