I'm trying to implement a synchronous up-down counter in verilog with the following rules:
- Counter only changes on rising edge of clock
- When reset=1, count goes to 00, normal operation when reset=0
- counting is enabled when en=1 and disabled when en=0 counts up when dir=0 counts down when dir=1
- counting does NOT wrap. When counting down, does NOT go from 00 to 11 (i.e. stays at 00). When counting up, does NOT go from 11 to 00 (i.e. stays at 11)
So far my code is:
module counter
(
input clock,
input reset,
input en,
input dir,
output reg [1:0] count
);
always @ (posedge clock) begin
if (reset==1'b1 || en==1'b0) begin
count=2'b0;
end
else if(en==1 && dir==0) begin //up count when dir=0
count <= count+1;
end
else begin //down count when dir=1
count <=count-1;
end
end
endmodule
This does everything except for the counting wraps. How would I make it not wrap?
Testbench below(comments say what the code should be doing)
`timescale 1 ns / 1 ns // Time for each step, time precision
`define CLOCK_PERIOD 10
module main;
reg clock; // Free running clock
reg reset; // Input - reset
reg en; // Input - enable counting
reg dir; // Input - direction (0=up)
wire [1:0] count; // Output - Counter output
// Instantiate module
counter u1( clock, reset, en, dir, count );
initial // Done once at start up
begin
$display( "Up/Down Counter (no wrap)" );
$dumpfile( "dump.vcd" );
$dumpvars;
// Set initial values for inputs, asset reset
clock = 0;
reset = 1;
en = 0;
dir = 0;
// Turn off reset after one clock
#(`CLOCK_PERIOD * 1)
reset = 0;
// Wait for a while to make sure it does not count
#(`CLOCK_PERIOD * 2)
// Assert enable, should count up to 3 and stop
en = 1;
#(`CLOCK_PERIOD * 5)
// Make sure does not count if we now deassert enable
en = 0;
#(`CLOCK_PERIOD * 2)
// Set dir=1 but en=0, so should not change
dir = 1;
#(`CLOCK_PERIOD * 2)
// Now enable, should count down and stop at 0
en = 1;
// Count back down, check if reset is ignored if not asserted
// at a clock edge
dir=1;
#7
reset = 1;
#6
reset = 0;
#(`CLOCK_PERIOD * 5)
reset = 0;
// Leave time to stabilize
#(`CLOCK_PERIOD * 4)
$finish;
end
else count = 2'b0;
? You want it to do a reset ifen
is low? Where is your logic to comparecount
to the min/max? \$\endgroup\$else count = 2'b0
was a silly mistake (I was trying to have that be theen
condition). Yes, I want to reset whenen
is low (edited code should now reflect that). I think the logic to comparecount
is one of my issues. I'm not sure even where to start to have my counter stop after one iteration... \$\endgroup\$en
would go to zero, since that's the easiest. \$\endgroup\$