Menu

Verilog Concatenation and Replication: The {} Operators

How to glue signals together with {} and copy a pattern N times with {N{...}} - the indispensable Verilog operators for building wider buses out of pieces.

This page includes runnable editors - edit, run, and see output instantly.

Two Tiny Operators That Earn Their Keep

Verilog has two {} shapes:

  1. Concatenation - {a, b, c} - glues multiple signals into one wider one.
  2. Replication - {N{pattern}} - copies a pattern N times.

You'll use both constantly. Every time a bus needs to be split, joined, padded, or sign-extended, one of these two operators is the answer.

Concatenation: {a, b, c}

The simplest case: stack two signals into one:

Reading left-to-right: a is the high half, b is the low half. The first operand inside {} is the most significant. The width of the result is the sum of operand widths.

You can concatenate any number of operands:

wire [31:0] word = {byte3, byte2, byte1, byte0};

And the operands can be different widths:

wire [11:0] frame = {start_bit, data_byte, parity, stop_bit};
//                    1 bit      8 bits     1 bit   2 bits  = 12

A common rule: all operands of a concatenation must have an explicit width. Unsized literals (1 instead of 1'b1) cause errors because the parser doesn't know how many bits to allocate. Always write 1'b0, 1'b1, 4'd0, never bare 0 or 1 inside {}.

Concatenation on the Left Side

Concatenation on the LHS of an assignment splits a wide signal back into its parts:

That's the canonical adder-with-carry pattern. {carry_out, sum_bits} is a single 9-bit destination on the left of the assignment, and the bits get distributed: top bit to carry_out, low 8 to sum_bits.

LHS concatenation works in assign and in procedural blocks:

always @(posedge clk) begin
    {high_byte, low_byte} <= incoming_word;
end

Replication: {N{pattern}}

The replication operator copies a pattern a fixed number of times. The shape is {N{pattern}} - a count, then the pattern in its own pair of braces:

N has to be a constant - the compiler needs to know the result width at elaboration. The pattern can be a literal, a parameter, or any expression whose width is known.

Don't forget the inner braces. {8 1'b1} is a syntax error; {8{1'b1}} is correct. The outer {} is the operator; the inner {...} wraps the pattern being replicated.

Combining Both: Sign and Zero Extension

The two operators compose naturally to build wider values:

The { {8{a_negative[7]}}, a_negative } is the standard sign-extension pattern. Read it as: replicate the sign bit eight times, then append the original 8 bits. Net result: 16-bit two's-complement representation of the same number.

For unsigned widening, you can rely on the assignment - Verilog zero-extends automatically when the destination is wider:

wire [15:0] zext_auto = a_unsigned;   // works, top 8 bits are 0

But signed extension never happens implicitly unless both operand and destination are declared signed. The explicit replication idiom is safer.

Useful Patterns

Building a Mask of N Ones

parameter N = 5;
wire [31:0] mask = { {32-N{1'b0}}, {N{1'b1}} };
// e.g. with N=5, mask = 32'h0000_001F

Reversing a Vector

Verilog doesn't have a built-in reverse, but you can write one inline with concatenation:

wire [3:0] forward  = 4'b1010;
wire [3:0] reversed = {forward[0], forward[1], forward[2], forward[3]};
// reversed = 4'b0101

For wider vectors, a generate loop or a function is cleaner.

Packing Flags Into a Status Byte

wire [7:0] status = {
    error_flag,    // [7]
    overflow,      // [6]
    underflow,     // [5]
    ready,         // [4]
    busy,          // [3]
    1'b0,          // [2] reserved
    1'b0,          // [1] reserved
    valid          // [0]
};

The 1-bit reserved slots have explicit widths - never bare 0 inside {}.

Common Mistakes

Unsized literals inside {}. {a, 0} is a syntax error or a 32-bit-wide zero. Always size: {a, 1'b0}.

Forgetting inner braces in replication. {8 1'b1} doesn't parse; {8{1'b1}} does.

Confusing the order. {a, b} puts a on the high side and b on the low. Reverse your assumption and you'll get an inverted byte order somewhere.

Replicating zero times. {0{...}} is illegal in standard Verilog. SystemVerilog allows it (and produces a zero-width result). Plain Verilog will reject it.

What Comes Next

You've now seen every Verilog operator. The next chapter switches gears and dives into structure - how modules connect to each other, the rules for ports, and the syntax for instantiating sub-modules to build larger designs.

Frequently Asked Questions

How do you concatenate signals in Verilog?

Use curly braces: {a, b, c} produces a single wide vector by glueing the operands left-to-right. The MSB of a becomes the MSB of the result; the LSB of c becomes the LSB. The width of the result is the sum of operand widths. Concatenation works on both the right side of an assignment (to build a value) and the left side (to split a value).

What does {N{pattern}} mean in Verilog?

It's the replication operator: it produces N copies of pattern concatenated together. {8{1'b1}} is an 8-bit all-ones value (8'hFF). {4{2'b10}} is the 8-bit value 8'b10101010. Replication is how you zero-extend, sign-extend, or build any repeating bit pattern without writing it out by hand.

How do you sign-extend a signal in Verilog?

Use replication to repeat the sign bit: { {24{a[7]}}, a } extends an 8-bit a to 32 bits by replicating bit 7 (the sign bit) 24 times and then appending the original. For unsigned zero-extension, replicate 1'b0 or just let the assignment do it implicitly when the destination is wider.

Can you use concatenation on the left side of an assignment?

Yes - it's how you assign multiple targets from one wide source. {carry, sum} = a + b; puts the result of the addition into carry (the high bit) and sum (the rest) in one statement. Each target keeps its width; the parser distributes the bits of the right side accordingly.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED