Operators and Expressions
Concatenation and Replication in Verilog
How {a, b} joins bit vectors into a wider one, how {n{bits}} repeats a pattern, and the {carry, sum} idiom for splitting a wider arithmetic result.
3 min read · Updated
Curly braces { } join two or more bit vectors, most-significant operand first, into one wider vector. {a, b} is a single expression whose width is the sum of a's and b's widths — not addition of their values, concatenation of their bits. Hardware it becomes: almost always wiring, not gates — concatenation and replication describe which existing signal connects to which position of a wider bus, the same way naming a bus [7:0] is a labeling choice, not a computation.
Concatenation works on either side of an assignment. On the right, {hi, lo} builds a wider value out of narrower pieces. On the left, {cout, sum} = a + b does the reverse: it splits a wider result straight into separate named pieces in one assignment, which is the standard idiom for capturing a carry-out alongside a sum.
Replication repeats a pattern a fixed number of times: {n{pattern}} is pattern written out n times and concatenated together. {4{1'b1}} is a compact way to write 4'b1111 — most useful when the repeat count is a parameter rather than a literal you could just type out.
Predict before running
Before running it, predict the 5-bit result of 4'hF + 4'h1 split via {cout, sum}, and what {hi, lo} produces from two 4-bit halves.
module add_with_carry (
input wire [3:0] a,
input wire [3:0] b,
output wire [3:0] sum,
output wire cout
);
assign {cout, sum} = a + b;
endmodule
module tb;
reg [3:0] a, b;
wire [3:0] sum;
wire cout;
reg [3:0] hi, lo;
add_with_carry u_add (.a(a), .b(b), .sum(sum), .cout(cout));
initial begin
a = 4'hF;
b = 4'h1;
#1;
$display("a=%h b=%h {cout,sum}=%b cout=%b sum=%h", a, b, {cout, sum}, cout, sum);
a = 4'h3;
b = 4'h2;
#1;
$display("a=%h b=%h {cout,sum}=%b cout=%b sum=%h", a, b, {cout, sum}, cout, sum);
hi = 4'hA;
lo = 4'hB;
$display("byte = {hi,lo} = %h", {hi, lo});
$display("replication {4{1'b1}} = %b", {4{1'b1}});
$display("replication {2{2'b01}} = %b", {2{2'b01}});
$display("PASS");
$finish;
end
endmoduleExpected output — reveal after you predict
a=f b=1 {cout,sum}=10000 cout=1 sum=0
a=3 b=2 {cout,sum}=00101 cout=0 sum=5
byte = {hi,lo} = ab
replication {4{1'b1}} = 1111
replication {2{2'b01}} = 0101
PASS4'hF + 4'h1 is 15 + 1 = 16, which needs 5 bits (5'b10000); {cout, sum} captures exactly that: cout=1, sum=0000. The second addition (3 + 2 = 5) fits in 4 bits, so cout=0 and sum holds the full result. {hi, lo} places hi in the upper nibble and lo in the lower one, matching write order left to right. {2{2'b01}} repeats the 2-bit pattern 01 twice, producing 0101 — not the value 01 doubled arithmetically.
Common mistakes
- Reversing the order inside
{ }. Concatenation is positional:{hi, lo}and{lo, hi}produce different values even though both operands are identical. - Forgetting a size on every operand inside a replication or a self-determined concatenation. An operand with no declared width (an unsized literal like plain
1) inside{ }is a compile error in most tools — concatenation needs every piece's width to be known. - Reaching for concatenation to do arithmetic.
{a, b}places bits side by side; it does not add, subtract, or otherwise combine the values ofaandb.
Sources and verification
Example provenance: SkillLift Labs authored the example for this tutorial. tests/scripts/tutorial-verified-examples.test.ts extracts the complete marked example from this Markdown file, compiles it in Verilog-2005 mode with Icarus Verilog, runs it, and requires the simulator output to match the Expected output block exactly. The same test also carries an independent, code-owned semantic oracle, and exercises the article-to-runner source-splitting path. Automation verifies those stated properties; human technical review for indexing remains a separate gate.