Search code examples
verilog

Shifting LED from first LED


main.v

    `timescale 1ns / 1ps

module main(
    input reset,
    input clk, //50MHz
    output [6:0] led
    );
    reg [26:0] counter;
    reg trigger;
    reg [6:0] temp;
    initial begin
        temp <= 7'b0000001;
    end

    always @ (posedge clk, posedge reset) begin
        if (reset == 1'b1) begin
            temp <= 7'b0000001;
        end

        else begin
            counter <= counter + 1;
        end
    end

    always @ (counter) begin
        if (counter == 26'd50000000)begin //1Hz
            trigger <= ~trigger;
            counter <= 26'd0;
        end

    end

    always @ (trigger) begin
        temp <= (temp == 7'b1000000) ? 7'b0000001 :
                (temp == 7'b0000001) ? 7'b0000010 :
                (temp == 7'b0000010) ? 7'b0000100 :
                (temp == 7'b0000100) ? 7'b0001000 :
                (temp == 7'b0001000) ? 7'b0010000 :
                (temp == 7'b0010000) ? 7'b0100000 :
                (temp == 7'b0100000) ? 7'b1000000 : 7'b0000000;

    end
    assign led = temp; 
endmodule

The LED doesn't move. It stays on the first LED forever. Is it the trigger that didn't work or did I misunderstand the counter?

This is the working code. I don't know why I have to use if statement, but it works.

`timescale 1ns / 1ps

module main(
    input reset,
    input clk, //50MHz
    output [6:0] led
    );
    reg [26:0] counter;
    reg trigger;
    reg [6:0] temp;

    always @ (posedge clk, posedge reset) begin
        if (reset == 1'b1) begin
            counter <= 'b0;
            trigger <= 'b0;
        end
        else begin
           if (counter == 26'd50000000)begin //1Hz
              trigger <= ~trigger;
              counter <= 26'd0;
           end
           else begin
              counter <= counter + 1;
           end
        end
    end

    always @ (posedge trigger, posedge reset) begin
            if (reset == 1'b1) begin
                temp <= 7'd0;
            end
            else begin

            if (temp == 7'b1000000) begin
                temp = 7'b0000001;
            end

            else if (temp == 7'b0000001) begin
                temp = 7'b0000010;
            end

            else if (temp == 7'b0000010) begin
                temp = 7'b0000100;
            end

            else if (temp == 7'b0000100) begin
                temp = 7'b0001000;
            end

            else if (temp == 7'b0001000) begin
                temp = 7'b0010000;
            end                        

            else if (temp == 7'b0010000) begin
                temp = 7'b0100000;
            end

            else if (temp == 7'b0100000) begin
                temp = 7'b1000000;
            end                        

            else begin
                temp = 7'b0000001;
            end
            trigger <= 'b0;
            end
        end
    assign led = temp; 
endmodule

Solution

  • The general structure for a a flip flop for an FPGA is to use an initial to set default values, or for ASIC use an async reset.

    Looking at the code exert:

    initial begin
        temp <= 7'b0000001;
    end
    
    always @ (posedge clk, posedge reset) begin
        if (reset == 1'b1) begin
            temp <= 7'b0000001;
        end
    
        else begin
            counter <= counter + 1;
        end
    end
    

    We have temp assigned a value in an async reset and an initial, while counter never get initialised. The more standard approach for creating a flip_flop with an async reset:

    always @ (posedge clk, posedge reset) begin
        if (reset == 1'b1) begin
            counter <= 'b0;
        end
        else begin
            counter <= counter + 1;
        end
    end
    

    Part 2

    The next section of code is:

    always @ (counter) begin
        if (counter == 26'd50000000)begin //1Hz
            trigger <= ~trigger;
            counter <= 26'd0;
        end
    end
    

    This has a manual sensitivity list which triggers on counter, It is best practise to use an automatic sensitivity list with always @*. This is also a combinatorial block so it should use blocking assignments (=).

    In verilog a variable should not be assigned a value from multiple blocks, as counter is here. The exception is using initial blocks for default values.

    Combinatorial blocks do not hold state, and this block only changes value on a particular count. implying trigger would hold its value, this will imply a latch. Accidentally implied latches can cause a lot of problems as is a bigger topic, than can be discussed here.

    Consider doing this instead:

    always @ (posedge clk, posedge reset) begin
        if (reset == 1'b1) begin
            counter <= 'b0;
            trigger <= 'b0;
        end
        else begin
           if (counter == 26'd50000000)begin //1Hz
              trigger <= ~trigger;
              counter <= 26'd0;
           end
           else begin
              counter <= counter + 1;
           end
        end
    end
    

    Part 3

    Your last section of code is again a manual sensitivity list:

     always @ (trigger) begin
    

    This is not edge triggered so is a combinatorial section. A combinatorial loop is where the output is a function of itself. temp = some function of temp.

    It looks like you really wanted to make this a flip-flop which updates on the positive edge of trigger:

    update I have also just noticed that you used a less than or equals, which will not work in this situation as you have the largest number first.

    always @ (posedge trigger, posedge reset) begin
        if (reset == 1'b1) begin
            temp <= 'b0;
        end
        else begin
        temp <= (temp == 7'b1000000) ? 7'b0000001 : // <= changed to  ==
                (temp <= 7'b0000001) ? 7'b0000010 :
                (temp <= 7'b0000010) ? 7'b0000100 :
                (temp <= 7'b0000100) ? 7'b0001000 :
                (temp <= 7'b0001000) ? 7'b0010000 :
                (temp <= 7'b0010000) ? 7'b0100000 :
                (temp <= 7'b0100000) ? 7'b1000000 : 7'b0000000;
        end
    end