VLSI Interview Questions and Answers – Part 2

Question 11: D-Flip-Flop with Enable (Power Optimized)

Add an enable signal to a D-Flip-Flop. How would you optimize the design for power?

There are three common ways to add an enable signal, but only one is truly power-efficient.

  1. Gating the Input: Place a MUX before the D-input of the flop. If `enable` is high, the MUX passes the new data. If `enable` is low, it feeds the flop’s own output back to its input. The flop still sees a clock edge every cycle, consuming switching power.
  2. Gating the Output: Place a tri-state buffer or MUX on the output. This is generally not done as it doesn’t stop the internal flop from switching and consuming power.
  3. Gating the Clock (Power Optimized): This is the best method for power optimization. The clock signal itself is turned off when the enable signal is low. This prevents the flip-flop from toggling at all, saving significant dynamic power.

However, simple clock gating with an AND gate is dangerous as it can create glitches. The industry-standard solution is to use an Integrated Clock Gating (ICG) Cell. An ICG cell is essentially a latch-based, glitch-free AND gate that ensures the gated clock output is always clean.

Power-Optimized Enable using ICG Cell

ICG Cell

DFF
Clock
Enable
gated_clk

Question 12: Detecting a Previously Seen Number

A 4-bit number arrives every clock cycle. Design a circuit that raises an output signal `high` if the number seen in the current cycle has already appeared in a previous cycle (since the last reset).

This is a classic use case for a direct-mapped lookup table. Since the input is 4 bits, there are only 24 = 16 possible values (0 to 15).

Architecture:

  1. Create a 16-bit register or a small memory (16×1 bit), let’s call it seen_table. Initialize all bits to 0 at reset.
  2. Each bit in this table corresponds to one of the possible input numbers. For example, `seen_table[0]` corresponds to the number `4’b0000`, `seen_table[5]` to `4’b0101`, and so on.
  3. In any given cycle:
    • Use the incoming 4-bit number as an index into the seen_table.
    • Check: Read the value at that index. If the bit is already `1`, it means we have seen this number before. Set the output `seen_before` to high.
    • Update: After the check, write a `1` to that index in the table to mark the current number as “seen” for future cycles.

module seen_detector (
    input  logic clk, reset,
    input  logic [3:0] data_in,
    output logic       seen_before
);
    reg [15:0] seen_table;

    // Check logic is combinational
    assign seen_before = seen_table[data_in];

    // Update logic is sequential
    always_ff @(posedge clk or posedge reset) begin
        if (reset) begin
            seen_table <= 16'b0;
        end else begin
            // Set the bit corresponding to the current data
            seen_table[data_in] <= 1'b1;
        end
    end
endmodule
            

Question 13: STA Path Adjustments

For the circuit below, how would you adjust the delay elements `dly1`, `dly2`, and `dly3` to fix a) a setup violation and b) a hold violation at input B of flip-flop FF2?

FF1
FF2
dly3
dly1
dly2
A
B
O
clk

In this standard timing path, FF1 is the launch flop and FF2 is the capture flop.

  • dly1 affects the launch clock path.
  • dly2 affects the capture clock path.
  • dly3 affects the data path.

a) Fixing a Setup Violation

A setup violation means the data at B is arriving too late. To fix this, we need to make the data arrive earlier relative to the capture clock. We can:

  • Decrease dly3: This speeds up the data path directly.
  • Increase dly2: This delays the capture clock, giving the data more time to arrive and stabilize.
  • Decrease dly1: This makes the launch clock arrive earlier, starting the data’s journey sooner.

b) Fixing a Hold Violation

A hold violation means the data at B is changing too soon after the clock edge, before FF2 can reliably capture it. To fix this, we need to make the data path slower relative to the capture clock. We can:

  • Increase dly3: This slows down the data path, making it stable for longer after the clock edge. This is the most common fix.
  • Decrease dly2: This makes the capture clock arrive earlier, effectively “outrunning” the fast data change.
  • Increase dly1: This delays the launch clock, making the data start its journey later.

Question 14: RTL for a SIPO Register

Write a Verilog RTL module for an 8-bit SIPO (Serial-In, Parallel-Out) shift register.

A SIPO register shifts in one bit at a time and makes all the bits available simultaneously on a parallel output. The most common implementation is a simple shift register. The original code in the PDF was flawed; here is the corrected, standard implementation.


module sipo_8bit (
    input  logic       clk,
    input  logic       reset,
    input  logic       serial_in,
    output logic [7:0] parallel_out
);

    // Internal register to hold the shifted data
    logic [7:0] shift_reg;

    always_ff @(posedge clk or posedge reset) begin
        if (reset) begin
            shift_reg <= 8'b0;
        end else begin
            // Concatenate new input bit with the top 7 bits
            // This shifts the register to the right
            shift_reg <= {shift_reg[6:0], serial_in};
        end
    end

    // Continuously assign the register value to the output
    assign parallel_out = shift_reg;

endmodule
            

Operation: On each rising clock edge, the `serial_in` bit is placed into the least significant bit (LSB) position of the register, and all other bits are shifted one position to the left (towards the MSB). The entire 8-bit value of the internal register is continuously available at `parallel_out`.

Question 15: Resolving a CDC Pulse Synchronization Issue

Given the timing diagram below where a narrow pulse on `data` crosses from `clkA` domain to `clkB` domain, how do you resolve the CDC issue? Assume nothing about the relationship between `clkA` and `clkB`.

clkB
data

A narrow pulse is extremely difficult to synchronize. A standard two-flop synchronizer will likely miss it entirely if the pulse is not active during a rising edge of `clkB`. Even if it is captured, it could be metastable.

The standard solution is to convert the pulse into a level-sensitive signal that can be safely synchronized. A toggle-flop synchronizer is ideal for this.

Architecture:

  1. Source Domain (`clkA`): Use the incoming pulse to toggle a flip-flop. This converts the one-cycle pulse into a level change that will persist until the next pulse arrives.
  2. CDC Path: Synchronize this toggling signal using a standard two-flop synchronizer into the `clkB` domain.
  3. Destination Domain (`clkB`): Detect the change in the synchronized level. An XOR gate comparing the synchronized signal with its one-cycle-delayed version will generate a single-cycle pulse in the `clkB` domain every time the level changes.

This method reliably transfers the pulse event across the domain, though it introduces a constraint: a new pulse cannot be sent until the previous one has been acknowledged by the destination, to prevent missing a toggle.

Question 16: RTL for a D-Latch

Write the Verilog RTL for a D-type latch.

A D-latch is a level-sensitive memory element. It is transparent when its enable signal is high (output follows input) and opaque when the enable is low (output holds its last value). Latches are inferred in Verilog when combinational logic has incomplete specification (e.g., an `if` without an `else`, or a `case` without a `default`).

Here is the RTL for a simple active-high D-latch with an asynchronous reset.


module d_latch (
    input  logic d,       // Data input
    input  logic en,      // Enable (level-sensitive)
    input  logic rst_n,   // Asynchronous active-low reset
    output logic q        // Output
);

    always_latch begin
        if (!rst_n) begin
            q <= 1'b0;
        end else if (en) begin
            q <= d; // Transparent: output follows input
        end
        // When en is low, q holds its value, creating the latch.
    end

endmodule
            

While useful in specific applications, latches are often avoided in synchronous designs because their timing analysis is more complex than for edge-triggered flip-flops.

Question 17: Synthesis of Incomplete Sensitivity List

What will the following code synthesize to? always @(!a) if (b) d=a;

This code has multiple issues that highlight bad RTL coding practices.

  1. Sensitivity List: The sensitivity list `always @(!a)` is nonsensical for synthesis. Synthesis tools create hardware based on logic structure, not arbitrary event triggers. The tool will likely ignore `!a` and interpret the block as combinational, issuing a warning that the sensitivity list is incomplete. The correct way to specify a combinational block is with `always @*` or `always_comb`.
  2. Incomplete Specification: The `if (b)` statement has no corresponding `else` clause. This means the code does not specify what the value of `d` should be when `b` is false. To prevent this ambiguity, a synthesis tool will infer a latch to hold the previous value of `d`.

Synthesis Result: The code will synthesize to a latch. The input to the latch will be `a`, and the enable for the latch will be `b`. This is almost certainly not the designer’s intent and can lead to major timing problems. A linter would flag this as a critical warning.

Question 18: Synthesis of Incomplete Sequential Logic

What will the following code synthesize to? always @(posedge clk) if (reset) q <= 0;

This is a sequential block that only specifies behavior when `reset` is high. It does not define what `q` should do when `reset` is low. In a sequential (`always_ff` or `always @(posedge clk)`) block, if a signal is not assigned a value under all conditions, it is inferred to hold its previous value.

Synthesis Result: The synthesizer will create a D-flip-flop where the output `q` is fed back to its own D-input, effectively holding its value forever once `reset` goes low. The `reset` signal acts as a synchronous load enable for the value `0`.

The hardware will be a D-flip-flop with a MUX at its input. The MUX selects `1’b0` when `reset` is high, and selects the flop’s own output `q` when `reset` is low.

DFF
MUX
D
q
1’b0
10
reset

Question 19: Safely Gating a Clock

How do you safely gate a clock to save power, and what are the risks of doing it incorrectly?

Clock gating is a technique used to turn off the clock to parts of a design to reduce dynamic power consumption. However, doing it naively is dangerous.

The Risk of Incorrect Gating: Using a simple AND or OR gate to combine a clock and a control signal is unsafe. If the control signal changes while the clock is high, it can create a glitch or a shortened pulse on the gated clock output. This glitch can cause downstream flops to either miss a clock edge or capture data incorrectly, leading to functional failure.

The Safe Solution: Integrated Clock Gating (ICG) Cell

The industry-standard method is to use a library-provided Integrated Clock Gating (ICG) cell. An ICG cell is essentially a latch-based, glitch-free circuit.

How it works:

  1. It contains a level-sensitive latch that holds the enable signal.
  2. The latch is transparent only when the clock is low. This ensures that the enable signal can only change its state when the clock is inactive.
  3. When the clock goes high, the latch becomes opaque, holding the enable value stable for the entire duration of the clock pulse.
  4. An AND gate then combines the stable latch output with the original clock.

This guarantees that the gated clock output is always a full, clean pulse without any glitches.

Question 20: Fixing Timing Violations from RTL

How can you fix a setup violation from RTL code only? Can you also fix a hold violation from RTL?

Fixing Setup Violations in RTL

A setup violation means the data signal is arriving too late at a flip-flop’s input relative to the clock edge. This is caused by a long combinational logic path between registers. From RTL, you can:

  • Pipelining: This is the most common and effective method. You break the long combinational path into two or more smaller, faster paths by adding registers in between. This increases latency but allows for a higher clock frequency. For example, changing `out = a + b + c;` to `temp <= a + b;` and `out <= temp + c;` in subsequent cycles.
  • Logic Restructuring: Rewrite the logic to be more efficient. For example, changing a long `if-else-if` chain (which synthesizes to a slow priority encoder) to a `case` statement (which synthesizes to a faster parallel MUX).
  • FSM State Encoding: For Finite State Machines, changing the state encoding can help. A binary encoding is dense but can have complex next-state logic. A one-hot or gray encoding can simplify the next-state logic, reducing the delay and helping fix setup violations.

Fixing Hold Violations in RTL

Generally, no. A hold violation means the data signal is changing too soon after the clock edge, before the flip-flop has had time to reliably capture it. This is usually caused by a data path that is *too fast* relative to the clock path.

Hold violations are considered a physical design issue, not a logical one. They are fixed during the Place & Route stage by the backend team, who add delay to the data path by inserting buffers or using longer wire routes. It is not something an RTL designer can or should try to fix by changing the Verilog code.

Leave a Reply

Your email address will not be published. Required fields are marked *