07-23-2018 05:56 AM - edited 07-23-2018 06:03 AM
Hello everyone,
I am working on a design implemented on a Nexys4ddr (Artix-7 XC7A100T), using Vivado 2015.4. This design includes a microprocessor and peripherals, both using a non-standard I2C interface with 4 unidirectional ports instead of 2 bidirectional ports. The interface of my top module allows the connexion of external I2C peripherals with standard interface (with bidirectional ports). The conversion between inout ports and input/outputs is realized using a "tri-state-like" design. The attached schematic shows what is done in the RTL description.
The I2C Ext periph is outside of the FPGA, the rest is inside. I have two such structures, one for an external slave, the other for an external slave. In the RTL code (System Verilog) I do something like this :
assign io_scl_s = (w_scl_s == 1'b1) ? 1'bz : 1'b0; assign io_sda_s = (w_sda_s == 1'b1) ? 1'bz : 1'b0; assign io_scl_m = (w_scl_m == 1'b1) ? 1'bz : 1'b0; assign io_sda_m = (w_sda_m == 1'b1) ? 1'bz : 1'b0;
The instanciation of my microprocessor (which includes the i2C Master module) is like this :
mcu MCU ( ... // I2C Slave toward an external master .i_i2cs_scl (io_scl_s), .i_i2cs_sda (io_sda_s), .o_i2cs_scl (w_scl_s), .o_i2cs_sda (w_sda_s), // I2C Master toward an external slave .i_i2cm_scl (io_scl_m), .i_i2cm_sda (io_sda_m), .o_i2cm_scl (w_scl_m), .o_i2cm_sda (w_sda_m), ... );
In simulation i realized i have a lot of signal being on 'hZ' value, which i don't like since it spawns 'hX' values on the outputs of logic gates. I tried to force a value on them in my testbench using a process like this one :
process_comb begin if(rw_io_scl_m_w === 1'bz || rw_io_scl_m_w === 1'bx) begin rw_io_scl_m <= 1'b1; end if(rw_io_sda_m_w === 1'bz || rw_io_sda_m_w === 1'bx) begin rw_io_sda_m <= 1'b1; end if(rw_io_scl_s_w === 1'bz || rw_io_scl_s_w === 1'bx) begin rw_io_scl_s <= 1'b1; end if(rw_io_sda_s_w === 1'bz || rw_io_sda_s_w === 1'bx) begin rw_io_sda_s <= 1'b1; end end assign rw_io_scl_s_w = rw_io_scl_s; assign rw_io_sda_s_w = rw_io_sda_s; assign rw_io_scl_m_w = rw_io_scl_m; assign rw_io_sda_m_w = rw_io_sda_m;
But this seems to only have half efficiency, since i do not have 'hZ' values anymore, but there are a lot of 'hX' on the 4 inout ports, as well as on the 'i_sda_m' port (which results from an AND operation with a 'hX' from 'io_sda_s').
Weird thing is that the rising edges of the signals are ok, but the rest is 'hX'. Thus i tried to clock the process with an high speed clock to be sure it is activated often enough, but this doesn't seem to help.
My theory is that when i read in my testbench an 'hX' or an 'hZ' from the design and that i force the '1'b1' value on it, since there is still 'hX' or 'hZ' on it the simulation tool gives me an 'hX' cause it can't decide the value. If this is indeed the case, then i'm screwed.
So I would like to know if you have any advices that could help me solve this situation.
07-23-2018 06:45 PM
The simple solution is to "pull up" the open-drain I/O signals. In Verilog the built-in pullup function does this. So for each I/O signal (bi-directional I2C pins of the FPGA) you implement a pullup in the test bench like
pullup (io_scl_s);
pullup (io_sda_s);
etc.
Then instead of Hi-Z, these pins take a weak '1' when not driven. This emulates the actual board hardware which requires an actual resistor pulling up each of the I2C signals.
07-23-2018 06:45 PM
The simple solution is to "pull up" the open-drain I/O signals. In Verilog the built-in pullup function does this. So for each I/O signal (bi-directional I2C pins of the FPGA) you implement a pullup in the test bench like
pullup (io_scl_s);
pullup (io_sda_s);
etc.
Then instead of Hi-Z, these pins take a weak '1' when not driven. This emulates the actual board hardware which requires an actual resistor pulling up each of the I2C signals.
07-23-2018 07:04 PM
07-24-2018 05:42 AM
Thank you a lot for your answers, it seems like this solved my problem. In Modelsim the values are displayed on dotted lines for the io on which i applied the pullup primitive, which means it is assigned to a weak '1' if i understood correctly.
Most important point is that there is no more 'X' or 'Z' in my design, since i guess the weak '1' got "absorbed" when it went through a logic gate (i have AND gates in which these signals go through).
I managed to have almost the same behaviour by doing this :
always_comb begin if(rw_io_scl_m_w === 1'bz) begin rw_io_scl_m <= 1'b1; end else begin rw_io_scl_m <= 1'bz; end if(rw_io_sda_m_w === 1'bz) begin rw_io_sda_m <= 1'b1; end else begin rw_io_sda_m <= 1'bz; end if(rw_io_scl_s_w === 1'bz) begin rw_io_scl_s <= 1'b1; end else begin rw_io_scl_s <= 1'bz; end if(rw_io_sda_s_w === 1'bz) begin rw_io_sda_s <= 1'b1; end else begin rw_io_sda_s <= 1'bz; end end
In this case the 'X' and 'Z' values were still present in the design but only for infinitesimal periods of time and only on vertical edges (corresponding to the delay during which the triggering condition of the process is enabled and the moment where the assignment to '1' operates i suppose).
Thank you again for your help, and have a nice day !