三态门
如果同学直接按照前面讲的的方式去实现 SRAM 控制器,会遇到这样的一个问题:读和写都需要经过同样的信号 sram_data
来传输数据,这怎么实现呢?如果实现错误,就会导致读取的数据一直是错误的。
在一些接口协议中,比如这里的 SRAM 等等,为了节省引脚数量,都出现了同一个信号在不同的时间传输不同方向的数据的现象。因此,为了防止两端设备同时输出,设备在不输出信号时需要设置高阻态。在 SystemVerilog 代码中,我们通常会将三态门 signal_io
拆分成三个信号:signal_i
、signal_o
和 signal_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_comb
和 sram_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
最后更新:
2024年9月8日
作者: