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
endmodulePASS 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 PASSEvery cycle is checked against an independent reference, so the final
PASSmeans the adder, the enable gate, and the synchronous clear all behaved. Note thataccwraps 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 endmodulePASS 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
PASSWith 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
clris high), or the sumacc + din(ifenis high). If none of those hold, the register holds its value — this implicit hold is what makesena true enable rather than a free-running add. Because every assignment uses the non-blocking operator<=inside analways @(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. Keepingclrseparate fromrst_nlets 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 ifpriority 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 LabRun it in the LabOpen this design in the free in-browser simulator — edit, compile and see the waveform/log instantly.
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 Hi! Ask me about courses, fees, batches or discounts. ×ChipXpert AssistantAsk about courses, fees, batches and centres