Accumulator in Verilog: Register-Plus-Adder with Clear and Enable

An accumulator is one of the most reused building blocks in digital design: a register that keeps adding incoming data to its own stored value. It is the heart of every FIR filter tap, DSP MAC unit, running-sum counter, and averaging circuit. This page gives you clean, synthesizable accumulator verilog code — a register fed by an adder, gated by an enable, and cleared synchronously — together with a self-checking testbench that tracks a reference running sum and asserts the output every cycle.

We then extend the idea to a multiply-accumulate (MAC) unit, where each cycle computes acc <= acc + a×b. Both examples are parameterized by width, use only Verilog-2005 constructs, and simulate deterministically.

Parameterized accumulator with synchronous clear and enable

The design is deliberately tiny: on each rising clock edge, an active-low reset or a synchronous clr zeroes the register, otherwise en decides whether din is added into acc. The testbench drives the sequence 10, 20, 30, 5, maintains an independent reference sum, asserts after every edge, exercises clr, then accumulates again.

// Accumulator: register + adder with synchronous clear and enable
module accumulator #(parameter W=8)(
  input clk, rst_n, clr, en,
  input [W-1:0] din,
  output reg [W-1:0] acc
);
  always @(posedge clk) begin
    if (!rst_n)      acc <= {W{1'b0}};
    else if (clr)    acc <= {W{1'b0}};
    else if (en)     acc <= acc + din;
  end
endmodule

module tb;
  reg clk, rst_n, clr, en;
  reg [7:0] din;
  wire [7:0] acc;
  reg [7:0] ref_sum;
  integer errors;

  accumulator #(.W(8)) dut(.clk(clk), .rst_n(rst_n), .clr(clr), .en(en), .din(din), .acc(acc));

  always #5 clk = ~clk;

  // apply one input value for one cycle with en=1, update reference, check
  task step(input [7:0] v);
    begin
      din = v; en = 1'b1; clr = 1'b0;
      @(posedge clk);
      ref_sum = ref_sum + v;   // reference running sum
      #1;                      // let acc settle after clock edge
      if (acc !== ref_sum) begin
        errors = errors + 1;
        $display("MISMATCH: din=%0d acc=%0d expected=%0d", v, acc, ref_sum);
      end else
        $display("PASS cycle: din=%0d acc=%0d", v, acc);
    end
  endtask

  initial begin
    clk = 0; rst_n = 0; clr = 0; en = 0; din = 0; ref_sum = 0; errors = 0;
    @(posedge clk); #1 rst_n = 1;          // release reset
    if (acc !== 8'd0) begin errors=errors+1; $display("MISMATCH: reset acc=%0d",acc); end
    else $display("PASS reset: acc=0");

    step(8'd10);
    step(8'd20);
    step(8'd30);
    step(8'd5);                             // running sum now 65

    // exercise synchronous clear
    en = 0; clr = 1; @(posedge clk); ref_sum = 0; #1;
    if (acc !== 8'd0) begin errors=errors+1; $display("MISMATCH: clr acc=%0d",acc); end
    else $display("PASS clear: acc=0");

    step(8'd7);                             // accumulate again after clear

    if (errors == 0) $display("PASS");
    else $display("FAIL: %0d errors", errors);
    $finish;
  end
endmodule
PASS reset: acc=0
PASS cycle: din=10 acc=10
PASS cycle: din=20 acc=30
PASS cycle: din=30 acc=60
PASS cycle: din=5 acc=65
PASS clear: acc=0
PASS cycle: din=7 acc=7
PASS

Every cycle is checked against an independent reference, so the final PASS means the adder, the enable gate, and the synchronous clear all behaved. Note that acc wraps modulo 2W — with W=8 the stored value is always masked to 8 bits.

Variant: multiply-accumulate (MAC) unit

Swap the adder's second operand for a product and you have a MAC: acc <= acc + a*b. The accumulator is made wider than the product so partial sums do not overflow early. This is the exact datapath inside DSP slices and FIR filters.

// Multiply-accumulate (MAC): acc <= acc + a*b, synchronous clear/enable
module mac #(parameter W=4, ACCW=16)(
  input clk, rst_n, clr, en,
  input [W-1:0] a, b,
  output reg [ACCW-1:0] acc
);
  always @(posedge clk) begin
    if (!rst_n)   acc <= {ACCW{1'b0}};
    else if (clr) acc <= {ACCW{1'b0}};
    else if (en)  acc <= acc + a*b;   // product widened into ACCW accumulator
  end
endmodule

module tb;
  reg clk, rst_n, clr, en;
  reg [3:0] a, b;
  wire [15:0] acc;
  reg [15:0] ref_sum;
  integer errors;

  mac #(.W(4), .ACCW(16)) dut(.clk(clk),.rst_n(rst_n),.clr(clr),.en(en),.a(a),.b(b),.acc(acc));

  always #5 clk = ~clk;

  task mstep(input [3:0] av, input [3:0] bv);
    begin
      a = av; b = bv; en = 1'b1; clr = 1'b0;
      @(posedge clk);
      ref_sum = ref_sum + av*bv;
      #1;
      if (acc !== ref_sum) begin
        errors = errors + 1;
        $display("MISMATCH: %0d*%0d acc=%0d expected=%0d", av, bv, acc, ref_sum);
      end else
        $display("PASS MAC: %0d*%0d -> acc=%0d", av, bv, acc);
    end
  endtask

  initial begin
    clk=0; rst_n=0; clr=0; en=0; a=0; b=0; ref_sum=0; errors=0;
    @(posedge clk); #1 rst_n=1;
    mstep(4'd3, 4'd4);   // +12
    mstep(4'd7, 4'd2);   // +14 -> 26
    mstep(4'd15, 4'd15); // +225 -> 251
    en=0; clr=1; @(posedge clk); ref_sum=0; #1;
    if (acc !== 16'd0) begin errors=errors+1; $display("MISMATCH: clr acc=%0d",acc); end
    else $display("PASS clear: acc=0");
    mstep(4'd5, 4'd5);   // +25
    if (errors==0) $display("PASS"); else $display("FAIL: %0d errors", errors);
    $finish;
  end
endmodule
PASS MAC: 3*4 -> acc=12
PASS MAC: 7*2 -> acc=26
PASS MAC: 15*15 -> acc=251
PASS clear: acc=0
PASS MAC: 5*5 -> acc=25
PASS

With 4-bit operands the maximum single product is 15×15 = 225, and a 16-bit accumulator holds many such terms before wrapping — the width choice is the designer's job, not the tool's.

How the accumulator works

The circuit is a single register with a combinational adder in front of it. On each rising edge the register loads one of three things, in strict priority: zero (if reset is asserted), zero (if the synchronous clear clr is high), or the sum acc + din (if en is high). If none of those hold, the register holds its value — this implicit hold is what makes en a true enable rather than a free-running add. Because every assignment uses the non-blocking operator <= inside an always @(posedge clk) block, the whole thing infers edge-triggered flip-flops with no latches.

Synchronous vs. asynchronous clear

Here both reset and clear are synchronous: they only take effect on a clock edge because they are tested inside the clocked block with no edge in the sensitivity list. If you wanted an asynchronous reset you would write always @(posedge clk or negedge rst_n) instead. Synchronous clears are generally preferred in FPGA and ASIC flows because they map cleanly onto the flip-flop's own synchronous reset/clear port and avoid reset-recovery timing issues. Keeping clr separate from rst_n lets you re-zero the running sum mid-operation (for example, between filter frames) without a full chip reset.

Overflow and width planning

An accumulator adds without bound, so overflow is the first thing to reason about. In the W=8 design the sum is truncated to 8 bits and wraps modulo 256 — after 10+20+30+5 = 65 it is fine, but a long input stream will roll over. The MAC variant shows the fix: make the accumulator wider than its inputs. To hold the sum of N products of W-bit numbers without overflow you need roughly 2×W + ⌈log2N⌉ bits. Deciding that width is a conscious design choice; synthesis will not grow the register for you.

Synthesis notes

This code synthesizes to one adder plus W flip-flops (plus a W-bit multiplier for the MAC). The priority chain reset > clr > en > hold becomes a small multiplexer on the register's data input. On FPGAs the MAC will usually be absorbed into a dedicated DSP block. One common mistake is mixing blocking (=) and non-blocking (<=) assignments in the clocked block — always use non-blocking for sequential logic so simulation matches hardware.

Interview angle

Expect to be asked to distinguish an accumulator from a counter (a counter adds a constant 1; an accumulator adds a data input), to add an enable without creating a latch, and to explain where the extra accumulator width in a MAC comes from. A sharp follow-up is "what happens if two of your control signals are asserted together?" — the answer is that the if/else if priority resolves it deterministically, with reset winning over clear and clear winning over enable. Being able to state that priority order from the code is exactly what interviewers look for.

Have questions about this topic?
Share your question in comments or talk to our mentor team for batch guidance.
▶ Try it in the ChipXpert Lab

Open this design in the free in-browser simulator — edit, compile and see the waveform/log instantly.

Run it in the Lab

Learn Verilog with mentors, labs and placement support

This free series is maintained by the ChipXpert training team in Hyderabad & Bengaluru. Go deeper with instructor-led courses on real EDA tools.

Explore VLSI Courses
Next batch starts 18th November 2026
Start your VLSI career with ChipXpert

Live online and classroom batches in Hyderabad & Bengaluru. Fill in your details and a counsellor will call you back.

  • Real EDA tools in your browser: industry-standard EDAReal EDA tools in your browser
  • Recorded sessions on the elearn portalRecorded sessions
  • Placement assistance: resume, mock interviewsPlacement assistance
  • Merit scholarship up to 60% · EMI optionsScholarship up to 60%
Hi! Ask me about courses, fees, batches or discounts. ×
BENGALURU
HYDERABAD