Naismith Avai
Naismith Avai

Reputation: 9

When I try to check two inputs in one always block I am getting inferred latch warning and my code runs inconsistently in Verilog

I try to design simple circuit, I have two push buttons as an input and 8 leds as an output, whenever I press one of them I want to shift the bits to the left and the last bit will be also set to 1, if other push button is pressed the bits will be shift to right. Here is my code.

module project1(leds, pushbutton1, pushbutton2);

output reg [7:0] leds;
input pushbutton1, pushbutton2 ;

reg pb1, pb2;

always @(pushbutton1 or pushbutton2)
    begin   
        pb1<=pushbutton1;
        pb2<=pushbutton2;

        if ((pb1==1)&&(pb2==0))
                    leds<=(leds<<1)+1;
        else if ((pb1==0)&&(pb1==1))
                    leds<=(leds>>1);
        else if (((pb1==0)&&(pb2==0)) ||((pb1==1)&&(pb2==1)))
             leds<=leds;
    end


initial begin
    leds = 8'h00;
end

endmodule

I have read many pages and I guess there will be bouncing problem. To solve it I tried to use posedge

always @(posedge pushbutton1 or posedge pushbutton2)

but in this case I get an error message "Error (10200): Verilog HDL Conditional Statement error at myfirstproject.v(14): cannot match operand(s) in the condition to the corresponding edges in the enclosing event control of the always construct"

When I tried to implement just one push button I had no problem and the below code worked well

module project1(leds, pushbutton1);

output reg [7:0] leds;
input pushbutton1;

always @(posedge pushbutton1)
begin
   if (leds==8'hFF)
        leds<=8'h00;
   else
       leds<=(leds<<1)+1;
end
 initial begin
   leds=8'h00;
 end
endmodule

I think If-else statements cover all possible conditions but it doesn't work. How can I check two inputs at the same time in one always block? I know it is not possible to change the value of any variable that is defined in different always block but is there any way to implement it by using two or more different always block like

always @(posedge pushbutton1)
..........

always @(posedge pushbutton2)
.........

Also I tried to use the system clock to trigger the button change like that, but still doesn't work

module project1 (leds, pushbutton1, pushbutton2, clk);

output reg [7:0] leds;
input clk, pushbutton1, pushbutton2 ;


always @(posedge clk)
    begin   
        if (pushbutton1==1 && pushbutton2==0)
            begin   
                if (leds==8'h00)
                    leds<=8'h01;
                else if (leds==8'hff)
                    leds<=8'h00;
                else 
                    leds<= (leds<<1)+1;
            end
        if (pushbutton1==0 && pushbutton2==1)
            begin
                if ((leds==8'h00) ||(leds==8'h01))
                    leds<= 8'h00;
                else 
                    leds<=(leds>>1);
            end
        else
            leds<=leds;
            
    end

initial begin
    leds = 8'h00;
end

endmodule

Upvotes: 0

Views: 571

Answers (2)

Naismith Avai
Naismith Avai

Reputation: 9

I have solved the problem by using FSM. I also want to share some info that I have learned when I tried to solve the problem. Push buttons of FPGA DE-0 Nano have Schmitt Triggered debounced circuit and they are active low. The circuit is sequential circuit so we don't need to write all cases in case block.

module clock_ex (leds, pb1, pb2, clk);

input clk;
input pb1, pb2;
output reg [7:0] leds;
reg [1:0] state;
wire [1:0] buttons;
assign buttons={~pb1,~pb2};

always @(posedge clk)
begin
    case (state)
    2'b00:
            begin
                case(buttons)
                    2'b01:
                            begin   
                                state<=2'b01;
                                leds<={leds[6:0],1'b1};
                            end
                    2'b10:
                            begin
                                state<=2'b10;
                                leds<={1'b0,leds[7:1]};
                            end
                endcase
            end
    2'b01:
            begin
                if (buttons==2'b00)
                    state<=2'b00;
            end
    2'b10:
            begin
                if (buttons==2'b00)
                    state<=2'b00;
            end
endcase
end 
initial
    begin
    leds=8'b111;
    state=2'b00;
    end
    
endmodule  

Upvotes: 0

m4j0rt0m
m4j0rt0m

Reputation: 354

You might want to include some debouncing logic, as well as some synchronizers in order to avoid metastability problems. I took this from a project of mine, this should solve the problem:

localparam NUM_SYNC   = 3;
localparam DEBOUNCE   = 16;
localparam DBNC_WDTH  = $clog2(DEBOUNCE + 1);

integer i;
reg [NUM_SYNC-1:0]  button_a_sync;
reg [NUM_SYNC-1:0]  button_b_sync;
reg [DBNC_WDTH-1:0] debounce_counter;
wire                button_pushed, button_released;

//..debouncing fsm
reg button_state;
localparam IDLE = 0;
localparam ACTION = 0;

//..control signals to use:
reg shift_right;
reg shift_left;

/* synchronizers */
always @ (posedge clk_i, negedge arstn_i) begin
  if(~arstn_i) begin
    for(i=0; i<NUM_SYNC; i=i+1) begin
      button_a_sync[i] <= 1'b0;
      button_b_sync[i] <= 1'b0;
    end
  end
  else begin
    for(i=0; i<NUM_SYNC; i=i+1) begin
      if(i==0) begin
        button_a_sync[i] <= button_a_i;
        button_b_sync[i] <= button_b_i;
      end
      else begin
        button_a_sync[i] <= button_a_sync[i-1];
        button_b_sync[i] <= button_b_sync[i-1];
      end
    end
  end
end

/* button change */
assign button_pushed   = button_a_sync[NUM_SYNC-1] | button_b_sync[NUM_SYNC-1];
assign button_released = ~button_pushed;

/* button state control */
always @ (posedge clk_i, negedge arstn_i) begin
  if(~arstn_i) begin
    shift_right      <= 0;
    shift_left       <= 0;
    debounce_counter <= 0;
    button_state     <= IDLE;
  end
  else begin
    case(button_state)
      IDLE: begin
        if(button_pushed) begin //..a button has been pushed
          if(debounce_counter == DEBOUNCE) begin
            shift_right       <= button_a_sync[NUM_SYNC-1];
            shift_left        <= button_b_sync[NUM_SYNC-1];
            debounce_counter  <= 0;
            button_state      <= ACTION;
          end
          else
            debounce_counter  <= debounce_counter + 1;
        end
        else
          debounce_counter  <= 0;
      end
      ACTION: begin
        shift_right <= 0;
        shift_left  <= 0;
        if(button_released) begin //..the buttons are released
          if(debounce_counter == DEBOUNCE) begin
            debounce_counter  <= 0;
            button_state      <= IDLE;
          end
          else
            debounce_counter  <= debounce_counter + 1;
        end
        else
          debounce_counter <= 0;
      end
    endcase
  end
end

//..shift logic
always @ (posedge clk_i, negedge arstn_i) begin
  if(~arstn_i)
    leds <= 0;
  else begin
    case({shift_left, shift_right})
      2'b01: begin //..shift right
        leds[7]   <= 1'b1;
        leds[6:0] <= leds[7:1];
      end
      2'b10: begin //..shift left
        leds[0]   <= 1'b1;
        leds[7:1] <= leds[6:0];
      end
      default: begin //..don't do anything
        leds <= leds;
      end
    endcase
  end
end

Upvotes: 0

Related Questions