Skip to article

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
endmodule
Expected 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
PASS

4'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 of a and b.

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.