Sunil.B
Sunil.B

Reputation: 27

Trying to design an 8-bit reloadable down counter

Task: Designing a 8-bit downcounter which takes an initial input value and start the downcount, and when count becomes 8'b0000_0000, it should automatically set to input value.

Ex: If given input is 8'b10010100, counter should start counting down, when value reaches 8'00000000, it should automatically reset to 8'b10010100, and again start downcount repeatedly. For this had written a modified D flip flop using behavioral method, which works as follows: When ld=0, output of d-flip flop q=d1 and q_bar=~d1 and when ld=1, q=d2 and q_bar=~d2 Here d2 stores the initial input values, and ld is being used as switch, i.e. when q=8'b00000000, ld=1 and sets counter output q=d2 and next cycle, ld=0 and takes d1 value.

Modified D-flip flop

module modified_d_flip_flop(q,q_bar,d1,d2,clk,ld
    );
    input d1,d2,clk,ld;
    output q,q_bar;
    reg q,q_bar;
    always @(posedge clk)
        begin
                if(ld==0)
                begin
                q<=d1;
                q_bar<=~d1;
                end
            else if(ld==1)
                begin
                q<=d2;
                q_bar<=~d2;
                end
            else
                begin
                q<=q;
                q_bar<=q_bar;
                end
            end
    endmodule

Down Counter:

module down_counter(
    input [7:0] d,
    input clk,
    input ld,
    output [7:0] q,
    output [7:0] q_bar
    );      
    modified_d_flip_flop m_dff1 (.q(q[0]), .q_bar(q_bar[0]), .d1(q_bar[0]), .d2(d[0]), .clk(clk), .ld(ld));
    modified_d_flip_flop m_dff2 (.q(q[1]), .q_bar(q_bar[1]), .d1(q_bar[1]), .d2(d[1]), .clk(q[0]), .ld(ld));
    modified_d_flip_flop m_dff3 (.q(q[2]), .q_bar(q_bar[2]), .d1(q_bar[2]), .d2(d[2]), .clk(q[1]), .ld(ld));
    modified_d_flip_flop m_dff4 (.q(q[3]), .q_bar(q_bar[3]), .d1(q_bar[3]), .d2(d[3]), .clk(q[2]), .ld(ld));
    modified_d_flip_flop m_dff5 (.q(q[4]), .q_bar(q_bar[4]), .d1(q_bar[4]), .d2(d[4]), .clk(q[3]), .ld(ld));
    modified_d_flip_flop m_dff6 (.q(q[5]), .q_bar(q_bar[5]), .d1(q_bar[5]), .d2(d[5]), .clk(q[4]), .ld(ld));
    modified_d_flip_flop m_dff7 (.q(q[6]), .q_bar(q_bar[6]), .d1(q_bar[6]), .d2(d[6]), .clk(q[5]), .ld(ld));
     modified_d_flip_flop m_dff8 (.q(q[7]), .q_bar(q_bar[7]), .d1(q_bar[7]), .d2(d[7]), .clk(q[6]), .ld(ld));
    endmodule

Down counter Test Bench

 module down_counter_tb;

    reg [7:0] d;
    reg clk;
    reg ld;

    wire [7:0] q;
    wire [7:0] q_bar;

    down_counter uut (
        .d(d), 
        .clk(clk),
        .ld(ld),
        .q(q), 
        .q_bar(q_bar)
    );
        always #5 clk = ~clk;
    initial begin
        clk = 1;
        ld = 1;
        d = 8'b00000111;
        end
    initial begin
        #20 ld = 0;
        #20 ld = 1;
        #30 ld = 0;
     end
     endmodule

Issue: If initial input i.e. d2=8'b11111111, then i am getting the downcounter it works properly for the above code, But if i give some thing like d2=8'10010011, then counter starts from 011, 010, 001 and 111, 110, 101, ........ it counts only the number of high bits from lsb + 1, if 0 is encountered next values till msb becomes x.

enter image description here

enter image description here

enter image description here

ld function too is not working as expected, when ld=0 instead of reset counter to initial input, it stops counter and starts it once ld=0.

Upvotes: 1

Views: 187

Answers (2)

Sunil.B
Sunil.B

Reputation: 27

Thanks @toolic

You code surely gave me an idea. Modified it a little to solve my issue

I am trying to design a frequency divider for my project for that i needed this downcounter.

ld - Use was to make the counter reset to my expected value when ld=0 and again make ld=1 next cycle to start the downcount and again when downcounter value became 0, make ld=0 to reset the counter to expected value. This had to go on forever.

In your testbench we have to set it many times. I just wanted to give one initial value and i wanted it to run forever.

I modified your code, to get my desired result. I removed ld and added, initial q = 0

Down Counter

module down_counter( 
 input [7:0] d,
 input clk,
 output reg [7:0] q
);
 
 initial q = 0;
 
 always @(posedge clk)
    begin
    if (q == 0)
        begin
        q <= d;
        end
    else 
        begin
        q <= q-1;
        end
    end
endmodule

Testbench:

module down_counter_tb;

// Inputs
reg [7:0] d;
reg clk;

// Outputs
wire [7:0] q;

// Instantiate the Unit Under Test (UUT)
down_counter uut (
    .d(d), 
    .clk(clk), 
    .q(q)
);

always #5 clk=~clk;

initial begin
    // Initialize Inputs
    d = 8'b00000100;
    clk = 1;

end
  
endmodule

Waveform: Its automatically sets to 4 again and again when it becomes 0

Upvotes: -1

toolic
toolic

Reputation: 61977

Your code is too hard to debug because you are not designing at the proper level of abstraction. You should always use the highest level of abstraction to make the design easier to understand. Instead of designing an individual flip-flop then trying to connect them together, just design a simple counter.

With all those module instance connections, you may have a simple connection bug.

Another potential issue is a simulation race condition. Every flip-flop uses a different clock signal.

Here is a common way to design a synchronous counter. It uses the same clock for all flops of the counter:

module down_counter (
    input [7:0] d,
    input clk,
    input ld,
    output reg [7:0] q
);      

always @(posedge clk) begin
    if (ld || (q == 0)) begin
        q <= d;
    end else begin
        q <= q - 1;
    end
end
endmodule

module down_counter_tb;
    reg [7:0] d;
    reg clk;
    reg ld;
    wire [7:0] q;

    down_counter uut (
        .d(d), 
        .clk(clk),
        .ld(ld),
        .q(q)
    );

    always #5 clk = ~clk;

    initial begin
        clk = 1;
        ld  = 1;
        d   = 7;

        repeat (2) @(posedge clk);
        ld <= 0;

        repeat (15) @(posedge clk);
        ld <= 0;
        d  <= 8'b1001_0011;
        repeat (1) @(posedge clk);
        ld <= 0;

        repeat (500) @(posedge clk);
        $finish;
    end
endmodule

By using nonblocking assignments (<=) and driving the inputs on @(posedge clk) in the testbench (as is done in the design), we also avoid race conditions in the testbench.

You didn't provide a thorough description of the ld signal. The code I showed loads the counter with the 8-bit input data (d) when ld=1. When ld=0, the counter counts down. When it reaches 0, the counter is automatically reloaded with d.

Upvotes: 1

Related Questions