Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions target/sim/src/vip_cheshire_soc.sv
Original file line number Diff line number Diff line change
Expand Up @@ -1069,9 +1069,9 @@ module vip_cheshire_soc_tristate import cheshire_pkg::*; (
);

// I2C
bufif1 (i2c_sda_i, i2c_sda, ~i2c_sda_en);
assign i2c_sda_i = i2c_sda;
bufif1 (i2c_sda, i2c_sda_o, i2c_sda_en);
bufif1 (i2c_scl_i, i2c_scl, ~i2c_scl_en);
assign i2c_scl_i = i2c_scl;
bufif1 (i2c_scl, i2c_scl_o, i2c_scl_en);
pullup (i2c_sda);
pullup (i2c_scl);
Expand Down
54 changes: 54 additions & 0 deletions target/sim/test/I2C_RESOLVED_INPUTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# I2C resolved inputs in the simulation VIP

The I2C input buffers used `~i2c_*_en` as their enable.
When the DUT drove either line low, its corresponding input became high impedance.
The controller therefore could not observe the actual resolved bus value.

Sample both I2C inputs continuously. Preserve the open-drain output buffers,
pullups, and all SPI input/output buffers.

The finite test instantiates the real `vip_cheshire_soc_tristate` module.
It sweeps all 16 combinations of DUT and peer low/release controls for SDA/SCL.
It also checks released inputs and unchanged SPI input gating.
The test contains no EEPROM model.

Official base: `6c6dd5e834347f72c7be31cd6c41021ec293c5b9`.
VCS W-2024.09-SP1 compiled both versions. The same 78-check input produced
16 input mismatches on the original and zero on the patch.
The original ended with the expected failure. The patch finished normally at 250 ns.
Both used a 1 us HDL deadline and a 60-second wall-clock limit.

## Reproduction

The isolated test extracts the complete real tristate module without edits.
A small package supplies only the SPI chip-select port width for elaboration.
It does not model any I2C behavior or replace the DUT.
From the repository root with VCS on PATH:

```bash
ROOT=$PWD
mkdir test-i2c-inputs
cd test-i2c-inputs
cat > package.sv <<'SV'
package cheshire_pkg;
localparam int unsigned SpihNumCs = 2;
endpackage
SV
sed -n '/^module vip_cheshire_soc_tristate/,$p' \
"$ROOT/target/sim/src/vip_cheshire_soc.sv" > vip_tristate.sv
timeout 120 vcs -full64 -sverilog -timescale=1ns/1ps package.sv \
vip_tristate.sv "$ROOT/target/sim/test/tb_i2c_resolved_inputs.sv" \
-top tb_i2c_resolved_inputs -o simv -l compile.log
timeout 60 ./simv -l run.log
```

For the original comparison, extract the module from the stated official base.
Use a separate output directory and the identical test and package.
The patched log must contain one `I2C_PIN_DONE checks=78 errors=0`, a normal
`$finish`, and no mismatch, fatal, or timeout. The original must report exactly
16 mismatches and the failure marker. A process exit code alone is insufficient.

This is a four-state simulation-wrapper test. It does not verify the full
I2C controller, EEPROM protocol, or SoC. No synthesizable RTL changes.

AI assistance: OpenAI Codex assisted the patch, test, and validation.
57 changes: 57 additions & 0 deletions target/sim/test/tb_i2c_resolved_inputs.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2026 CheshireAra contributors.
// SPDX-License-Identifier: Apache-2.0
`timescale 1ns/1ps
module tb_i2c_resolved_inputs;
tri sda, scl, sck;
tri [1:0] csb;
tri [3:0] sd;
wire sda_i, scl_i;
wire [3:0] sd_i;
logic sda_en = 0, scl_en = 0;
logic peer_sda_low = 0, peer_scl_low = 0;
logic [3:0] sd_en = 0;
logic [3:0] sd_o = 0;
int checks = 0, errors = 0;
assign sda = peer_sda_low ? 1'b0 : 1'bz;
assign scl = peer_scl_low ? 1'b0 : 1'bz;
vip_cheshire_soc_tristate dut (
.i2c_sda_i(sda_i), .i2c_sda_o(1'b0), .i2c_sda_en(sda_en),
.i2c_scl_i(scl_i), .i2c_scl_o(1'b0), .i2c_scl_en(scl_en),
.i2c_sda(sda), .i2c_scl(scl),
.spih_sck_o(1'b0), .spih_sck_en(1'b0), .spih_sck(sck),
.spih_csb_o(2'b00), .spih_csb_en(2'b00), .spih_csb(csb),
.spih_sd_o(sd_o), .spih_sd_en(sd_en), .spih_sd_i(sd_i), .spih_sd(sd)
);
task automatic check_bit(input string label, input logic got, want);
checks++;
if (got !== want) begin
errors++;
$display("PIN_MISMATCH %s got=%b want=%b",label,got,want);
end
endtask
initial begin
for (int state_id=0; state_id<16; state_id++) begin
{sda_en,scl_en,peer_sda_low,peer_scl_low}=4'(state_id);
#10;
check_bit("SDA wire",sda,!(sda_en || peer_sda_low));
check_bit("SDA input",sda_i,!(sda_en || peer_sda_low));
check_bit("SCL wire",scl,!(scl_en || peer_scl_low));
check_bit("SCL input",scl_i,!(scl_en || peer_scl_low));
end
sda_en=0; scl_en=0; peer_sda_low=0; peer_scl_low=0;
#10;
check_bit("SDA release",sda_i,1'b1);
check_bit("SCL release",scl_i,1'b1);
for (int pin=0;pin<4;pin++) begin
sd_o=0; sd_en=4'(1<<pin); #10;
check_bit("SPI driven output",sd[pin],1'b0);
check_bit("SPI input gate",sd_i[pin],1'bz);
sd_en=0; #10;
check_bit("SPI released input",sd_i[pin],1'b1);
end
$display("I2C_PIN_DONE checks=%0d errors=%0d",checks,errors);
if (errors) $fatal(1,"I2C_PIN_FAILURE");
$finish;
end
initial begin #1000; $fatal(1,"I2C_PIN_TIMEOUT"); end
endmodule