Search code examples
verilogmicroprocessors

two clock ring counter with verilog


I'm trying to write a roll shift/ ring counter that takes two switches as the clocks in verilog.

My code is as follows:

module roll(CLK1, CLK2, LEDS);
input CLK1;
input CLK2;
output [3:0] LEDS;
reg [3:0] LEDS;


initial 
begin
LEDS = 4'b0001;
end


always@(posedge CLK1 or posedge CLK2)
begin
if(CLK1)
begin

         LEDS[3]<=LEDS[2];
         LEDS[2]<=LEDS[1];
      LEDS[1]<=LEDS[0];
         LEDS[0]<=LEDS[3];
end

// Roll Right
if(CLK2)
begin
         LEDS[3]<=LEDS[0];
         LEDS[2]<=LEDS[3];
         LEDS[1]<=LEDS[2];
         LEDS[0]<=LEDS[1];

 end
end
endmodule

I tried using two always blocks, but then figured out that I cannot do that. and when I have the posedge CLK2 in the always statement, the leds on my FPGA all stay on.


Solution

  • Remember Verilog is not a programming language it is a hardware description language.

    And when coding for synthesis, you will only be successful if you write code that can be instantiated with actual gates. So writing an always block with sensitivity to edges of two different signals can't be synthesized unless the response to one of the two signals has the effect of a RESET or PRESET operation.

    Your code also logically doesn't do what it seems you want to. Consider what your code says will happen if there is a rising edge on CLK2 when CLK1 is already high (or vice versa). Your lights will roll left and then immediately roll right gain, resulting in no change.

    A more usual approach would be to have a clock running much faster than the UP and DOWN inputs are expected to change, and use that to drive the logic. For example

    module roller(input clk, input rst, input UP, input DOWN, output reg LEDS[3:0]);
    
    reg UP1, DOWN1;
    
    always @(posedge clk or posedge rst)
    if (rst) begin
        LEDS[3:0] <= 4'b0001;
    end 
    else
    begin
        UP1 <= UP;
        DOWN1 <= DOWN;
        if (UP & ~UP1) begin
             LEDS[3:0] <= {LEDS[2:0], LEDS[3]};
        end
        else if (DOWN & ~DOWN1) begin
             LEDS[3:0] <= {LEDS[0], LEDS[3:1]};
        end
    end
    endmodule;
    

    Notice that this gives priority to UP. If both UP and DOWN are asserted, the pattern will roll "up" rather than down. If you want a different behavior, you'd have to modify the code to achieve it.