What You'll Learn
Elevator Pitch: How to Describe Your Project
In 60 seconds, you should be able to explain your I2C project to a hiring manager. Practice this:
Your Pitch:
"I designed and verified a SystemVerilog I2C master controller with a 6-state FSM, addressing clock synchronization, open-drain simulation, and collision detection. The testbench includes 10 comprehensive test cases covering protocol fundamentals, edge cases, and error scenarios. I also modeled a slave responder to validate bidirectional communication—the design is fully self-contained and ready for EDA Playground simulation with Synopsys VCS."
Why This Works:
- Scope is clear: Master + slave, 6 states, 10 tests—concrete numbers impress.
- Technical depth: FSM, open-drain, collision detection—shows you understand protocol nuances.
- Verification mindset: Testbench, test cases, edge cases—you think like a verification engineer.
- Production-ready: Synopsys VCS, EDA Playground—you've thought about deployment.
Core Interview Questions
Here are the most common I2C questions you'll face, with model answers:
Q1: What is I2C and why is it important?
I2C (Inter-Integrated Circuit) is a synchronous, two-wire serial protocol with only SCL (clock) and SDA (data) lines. It's important because it's low-cost (only 2 wires), scalable (supports multiple masters and slaves via open-drain architecture), and widely used in embedded systems, sensors, and ASIC/FPGA testing. The open-drain design enables wired-AND arbitration, allowing multiple devices to safely share the bus.
Q2: Explain the START and STOP conditions. Why is the sequence important?
START: Master pulls SDA LOW while SCL is HIGH. This unique transition wakes all slaves and signals the start of a transaction. STOP: Master releases SDA to HIGH while SCL is HIGH. This signals end of transaction and releases the bus. The sequence is critical because any other transition could be misinterpreted—if both SCL and SDA fell simultaneously, a slave might not recognize it as a START condition.
Q3: What is the purpose of ACK/NACK, and how is it signaled?
ACK (acknowledge): Receiver pulls SDA LOW during the 9th clock pulse, confirming it received the byte and is ready for more. NACK (no acknowledge): Receiver releases SDA (leaves it HIGH during bit 9), signaling it cannot accept more data. In write transactions, only the slave can ACK/NACK; in read transactions, the master sends ACK/NACK after receiving each byte to control data flow.
Q4: How do you model pull-up resistors in simulation?
I use a wired-AND model with continuous assignments:
assign scl_in = (scl_out==0) ? 0 : 1; This mimics the open-drain behavior without simulating RC charging curves. The line is LOW if ANY device pulls it; otherwise, pull-ups bring it HIGH. For timing-critical designs, I can add slew-rate modeling with a ramp function, but for functional verification, the binary model is sufficient and simulation is much faster.Q5: Explain clock stretching. When and why does it occur?
Clock stretching happens when a slave holds SCL LOW (scl_out=0) indefinitely. The slave does this when it needs processing time before the next bit (e.g., reading from slow EEPROM). The master must wait until SCL is released before proceeding. In my design, I implemented this with a
wait(scl_stable==1) condition that tolerates indefinite delays. This is critical for real-world multi-slave systems where devices have varying speeds.Q6: What is 7-bit vs. 10-bit addressing?
7-bit addressing: First byte contains 7 address bits [7:1] + 1 R/W bit [0]. Supports 128 addresses (0x00–0x7F). 10-bit addressing: First byte is special: 5 bits [7:3]=11110, 2 address bits [1:0], R/W bit [0]. Next byte contains remaining 8 address bits. Supports 1024 addresses. My design implements 7-bit addressing, which is by far the most common in modern embedded systems.
Q7: How did you detect and handle collisions?
In my design, I monitor SDA while the master releases it (sda_out=1). If SDA_IN reads as 0 despite release, another device is pulling it—this is a collision. I set
error=1 to flag it. In multi-master arbitration, the master that loses arbitration (its data differs from the bus) should stop driving and monitor bus activity. For this design, I focused on detection; full arbitration (master backing off) would require state machine extensions.Deep Dive Topics
Multi-Master Arbitration
If two masters drive simultaneously, I2C arbitration ensures exactly one wins:
- Each master sends its address/data bit (sda_out)
- Master samples the bus (sda_in)
- If sda_out ≠ sda_in: Master lost arbitration; it should stop driving and listen
- If sda_out = sda_in: Master won; continue normally
To implement this in SystemVerilog:
// Arbitration during TX_DATA state
always @(posedge scl_rising) begin
if (state == TX_DATA) begin
// We sent a bit; check if it matches the bus
if (sda_out == 1'b0 && sda_in == 1'b1) begin
// We pulled LOW, but bus is HIGH → LOST arbitration
arbitration_lost <= 1'b1;
// Stop driving; switch to monitoring mode
sda_out <= 1'b1;
scl_out <= 1'b1;
end
end
end
Interview Talking Point:
"Multi-master arbitration is elegant because it's asynchronous—no central arbiter needed. The bus itself enforces fairness. Masters with the highest priority naturally win because they drive bits first."
Timing Verification
Real silicon must meet strict timing constraints. Key parameters:
| Parameter | Standard (100 kHz) | Fast (400 kHz) | Impact |
|---|---|---|---|
| tLOW (SCL low time) | 4.7 µs | 1.3 µs | Slave must release SCL in this time |
| tHIGH (SCL high time) | 4.0 µs | 0.6 µs | Master must not pull SCL too fast |
| tSU:DAT (data setup) | 250 ns | 100 ns | SDA must be stable before SCL rise |
| tHD:DAT (data hold) | 300 ns | 300 ns | SDA must stay stable after SCL fall |
To verify timing in simulation:
// Monitor setup time
always @(posedge scl_rising) begin
if (sda_changed_since_scl_fall < 250ns) begin
$warning("Setup time violation: t_SU:DAT = %t",
$time - sda_change_time);
end
end
Common Interview Pitfalls
Avoid these mistakes when discussing your project:
Mistake 1: "I just ran the simulator and got passing tests."
Better Answer: "I designed 10 focused test cases with explicit pass/fail criteria. Each test targets a specific protocol requirement—START condition timing, ACK generation, collision detection. I also reviewed waveforms to verify setup/hold times and edge transitions."
Better Answer: "I designed 10 focused test cases with explicit pass/fail criteria. Each test targets a specific protocol requirement—START condition timing, ACK generation, collision detection. I also reviewed waveforms to verify setup/hold times and edge transitions."
Mistake 2: "My testbench has no slave model; I just checked the outputs."
Better Answer: "I implemented a slave responder to generate ACK bits and simulate clock stretching. This lets me validate the full I2C transaction from both sides—master and slave negotiation."
Better Answer: "I implemented a slave responder to generate ACK bits and simulate clock stretching. This lets me validate the full I2C transaction from both sides—master and slave negotiation."
Mistake 3: "I don't know if my design would work at 400 kHz; I only tested at 100 kHz."
Better Answer: "I parameterized the clock divider (CLK_DIV_100K, CLK_DIV_400K) and tested both speeds. At 400 kHz, timing margins are tighter, so I paid special attention to setup/hold violations."
Better Answer: "I parameterized the clock divider (CLK_DIV_100K, CLK_DIV_400K) and tested both speeds. At 400 kHz, timing margins are tighter, so I paid special attention to setup/hold violations."
Mistake 4: "I didn't think about what happens if two masters collide."
Better Answer: "I implemented collision detection by monitoring SDA changes while releasing it. If the bus doesn't match my output, I set error=1. A full multi-master system would add arbitration logic to back off gracefully."
Better Answer: "I implemented collision detection by monitoring SDA changes while releasing it. If the bus doesn't match my output, I set error=1. A full multi-master system would add arbitration logic to back off gracefully."
Scaling to UVM
Your class-based testbench is a great foundation. Upgrading to UVM adds structure:
// UVM Testbench Skeleton
class i2c_master_test extends uvm_test;
`uvm_component_utils(i2c_master_test)
i2c_env env;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = i2c_env::type_id::create("env", this);
endfunction
virtual task run_phase(uvm_phase phase);
super.run_phase(phase);
phase.raise_objection(this);
// Send sequences (start, write, stop)
repeat(10) env.driver.write_byte(8'hA5);
phase.drop_objection(this);
endtask
endclass
UVM Benefits Over Class-Based TB
| Feature | Class-Based TB | UVM |
|---|---|---|
| Reusability | Good—components are modular | Excellent—UVM base classes standardize structure |
| Sequence Library | Manual; ad-hoc | Built-in; combinatorial mixing |
| Scoreboarding | Hand-coded per project | UVM Subscriber pattern + TLM |
| Coverage Integration | Via SystemVerilog events | Unified via UVM factory |
| Learning Curve | Fast (days) | Steep (weeks) |
Interview Strategy:
"My current testbench is class-based and functional. I understand UVM and could migrate it if the project requires large-scale regression or multi-site validation. For this scope (10 test cases, single DUT), the simpler approach was appropriate."
Performance Optimization
Synthesis Optimizations
Goal: Reduce area/power while meeting timing at target frequency.
- FSM Encoding: One-hot (few gates) vs. binary (compact) vs. gray (glitch-free transitions)
- Clock Divider: Use shift register (synthesizes well) instead of counter for certain ratios
- Synchronizers: Double-flop is minimal; 3+ flops only if metastability risk is severe
// One-hot FSM (synthesizes to smaller mux tree)
typedef enum logic [5:0] {
IDLE = 6'b000001,
START_COND = 6'b000010,
TX_DATA = 6'b000100,
RX_DATA = 6'b001000,
ACK_BIT = 6'b010000,
STOP_COND = 6'b100000
} state_t;
state_t state, next_state;
always @(posedge clk or negedge rst_n) begin
if (~rst_n) state <= IDLE;
else state <= next_state;
end
Verification Optimizations
- Constraint random testing: Beyond hand-coded cases, generate random address/data
- Coverage-driven verification: Identify untested code paths and generate targeted tests
- Formal verification: Prove properties (e.g., "start_cond_req always leads to START condition within N cycles")
// Simple property-based check (SVA)
property start_condition_generated;
start_cond_req |=> ##[1:100] (scl_stable && ~sda_stable);
endproperty
assert property (start_condition_generated)
else $error("START never generated");
Series Recap & Next Steps
What We Built
- Part 1: I2C protocol fundamentals—START, STOP, ACK/NACK, addressing, timing.
- Part 2: 6-state FSM master controller with edge detection and clock generation.
- Part 3: Slave responder with address matching, ACK generation, and pull-up simulation.
- Part 4: Comprehensive testbench with 10 test cases and systematic debugging.
- Part 5: Interview prep, advanced topics, UVM scaling, and optimization strategies.
Next Steps for Your Portfolio
- Verify on EDA Playground: Upload design.sv and testbench.sv to edaplayground.com and confirm "ALL TESTS PASSED"
- Add to LinkedIn: Post a 2-3 sentence summary with the link. Tag VLSI/verification communities.
- Document on GitHub: Upload your project with a comprehensive README explaining each module and test.
- Interview Talking Points: Practice your elevator pitch. Prepare waveform screenshots showing START/STOP/ACK.
- Expand the Project: Add multi-master arbitration, formal property checks, or UVM testbench upgrade.
Series Navigation:
Part 1: Protocol Fundamentals →
Part 2: Master Controller FSM →
Part 3: Slave Responder & Pull-up Logic →
Part 4: Testbench Design & Test Cases →
Part 5: Interview Prep & Optimization (You are here)
🎉 Series Complete! 🎉
Thank you for reading. Now go build, simulate, and ace that interview!
Part 1: Protocol Fundamentals →
Part 2: Master Controller FSM →
Part 3: Slave Responder & Pull-up Logic →
Part 4: Testbench Design & Test Cases →
Part 5: Interview Prep & Optimization (You are here)
🎉 Series Complete! 🎉
Thank you for reading. Now go build, simulate, and ace that interview!

Comments
Post a Comment