This final part covers advanced design topics including clock domain crossing, reset strategies, pipelining, memory design, low-power techniques, DFT, and formal verification. These questions target senior and staff-level design roles.
A 250 MHz clock has a period of 4 ns. A 1 ms output requires counting 250,000 clock cycles (1,000,000 ns / 4 ns = 250,000). For a 50% duty cycle, the counter toggles the output every 125,000 cycles. The counter must be wide enough to hold 124,999 — an 18-bit counter (2^17 = 131,072) suffices.
module clk_div_250m_to_1ms (
input clk_250m, rst_n,
output reg out_1ms
);
reg [17:0] count;
parameter MAX = 125000 - 1;
always @(posedge clk_250m or negedge rst_n) begin
if (!rst_n) begin
count <= 0;
out_1ms <= 0;
end else if (count == MAX) begin
count <= 0;
out_1ms <= ~out_1ms;
end else begin
count <= count + 1;
end
end
endmodule
An enable signal that stays active for 250,000 clock cycles requires a counter that counts from 0 to 249,999. The enable output is asserted while the counter is within the counting range. This is commonly used for timing generation, state machine sequencing, or as a strobe for periodic operations. An 18-bit counter (2^18 = 262,144) is sufficient.
module enable_250k (
input clk, rst_n,
output reg enable
);
reg [17:0] count;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
count <= 0;
enable <= 0;
end else if (count < 250000 - 1) begin
count <= count + 1;
enable <= 1;
end else begin
enable <= 0;
end
end
endmodule
This enable signal pulses high for 250,000 consecutive cycles then goes low. Combined with a clock divider (Q31), it can create complex timing sequences for system-level control.
An up/down counter can increment or decrement based on a direction control signal. Parallel load allows initializing the counter to a specific value. This is a fundamental building block in timer modules, address generators, and control logic.
module updown_counter #(parameter N = 8) (
input clk, rst_n, up, down, load,
input [N-1:0] d,
output reg [N-1:0] count
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) count <= 0;
else if (load) count <= d;
else if (up && !down) count <= count + 1;
else if (down && !up) count <= count - 1;
end
endmodule
A Mod-N counter counts from 0 to N-1 and then wraps back to 0. The modulus is parameterized, making it reusable for different divide-by-N applications. The counter resets when it reaches the terminal count (N-1).
module mod_n_counter #(parameter N = 10) (
input clk, rst_n, en,
output reg [$clog2(N)-1:0] count,
output reg tc
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin count <= 0; tc <= 0; end
else if (en) begin
if (count == N-1) begin count <= 0; tc <= 1; end
else begin count <= count + 1; tc <= 0; end
end else tc <= 0;
end
endmodule
A D flip-flop can be constructed from a 2x1 multiplexer with feedback. The mux selects between the input D (when clk=1) and the current output Q (when clk=0), creating an edge-triggered behavior. This is a classic interview question testing understanding of sequential element construction from combinational logic.
module dff_mux (
input clk, d,
output reg q
);
wire mux_out;
assign mux_out = clk ? d : q;
always @(*) q = mux_out;
endmodule
A more practical positive-edge-triggered DFF uses two cascaded mux-based latches (master-slave): the master is transparent when clk=0, the slave when clk=1. The rising edge captures the value because the slave latches the master's output exactly at the clock edge.
A 250 MHz clock has a period of 4 ns. 1 kHz = 1 ms period = 250,000 clock cycles. For 75% duty cycle, the output is high for 75% of 250,000 = 187,500 cycles and low for the remaining 62,500 cycles. This complements the 25% duty cycle design (Q40), showing how the same counter structure can produce different output waveforms.
module clk_div_75pct (
input clk_250m, rst_n,
output reg out_1k
);
reg [17:0] count;
parameter PERIOD = 250000 - 1;
parameter HIGH = 187500 - 1;
always @(posedge clk_250m or negedge rst_n) begin
if (!rst_n) begin count <= 0; out_1k <= 0; end
else begin
if (count == PERIOD) count <= 0;
else count <= count + 1;
out_1k <= (count <= HIGH);
end
end
endmodule
A PWM generator produces a variable-duty-cycle output by comparing a counter with a threshold value. When the counter is less than the threshold, the output is high; otherwise low. The counter resets at the period boundary.
module pwm_gen #(parameter N = 8) (
input clk, rst_n,
input [N-1:0] duty,
output reg pwm_out
);
reg [N-1:0] count;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin count <= 0; pwm_out <= 0; end
else begin
count <= count + 1;
pwm_out <= (count < duty);
end
end
endmodule
A sequence detector asserts an output when the pattern "1011" is detected. In a Mealy machine, the output is asserted during the last bit of the sequence, allowing immediate response. Overlapping sequences are handled — after detecting "1011", the last "11" can start a new match.
module seq_1011 (
input clk, rst_n, din,
output reg detected
);
reg [1:0] state;
localparam S0 = 0, S1 = 1, S2 = 2, S3 = 3;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin state <= S0; detected <= 0; end
else begin
detected <= 0;
case (state)
S0: if (din) state <= S1;
S1: if (!din) state <= S2; else state <= S1;
S2: if (din) state <= S3; else state <= S0;
S3: begin
if (din) begin state <= S1; detected <= 1; end
else state <= S2;
end
endcase
end
end
endmodule
A T flip-flop toggles its output when T=1 and holds when T=0. Using a 2x1 mux, the mux selects between the current output Q (when T=0) and the inverted output ~Q (when T=1). This demonstrates how sequential elements with different behavior can be constructed from the same mux-based building block.
module tff_mux (
input clk, t,
output reg q
);
wire mux_out;
assign mux_out = t ? ~q : q;
always @(posedge clk) q = mux_out;
endmodule
A 250 MHz clock has a period of 4 ns. 1 kHz = 1 ms period = 250,000 clock cycles. For 25% duty cycle, the output is high for 25% of 250,000 = 62,500 cycles and low for the remaining 187,500 cycles. A counter tracks the total period, and the output is asserted during the first 62,500 counts.
module clk_div_25pct (
input clk_250m, rst_n,
output reg out_1k
);
reg [17:0] count;
parameter PERIOD = 250000 - 1;
parameter HIGH = 62500 - 1;
always @(posedge clk_250m or negedge rst_n) begin
if (!rst_n) begin count <= 0; out_1k <= 0; end
else begin
if (count == PERIOD) count <= 0;
else count <= count + 1;
out_1k <= (count <= HIGH);
end
end
endmodule
Counter, FSM, sequential logic, and clock dividers are the backbone of every digital design interview. Practice these patterns — clock dividers, counters with load/enable, FSMs for sequence detection and control, shift registers, and mux-based flip-flop construction — to build fluency for any design role.