Search code examples
verilog

Verilog state machine based on switch inputs and button presses


I'm running into some problems implementing a synthesizeable state machine to output the results from several lower-level modules I've already implemented. As far as I can tell, the structure I have so far wants nested always blocks, but that can't be done in Verilog. I'm not sure how to circumvent this problem.

Here is my state machine so far:

module project3_fall2013_statemachine(CLOCK_50, KEY, SW, LED);

input CLOCK_50;
input [1:0] KEY;
input [3:0] SW;
output[7:0] LED;
reg [3:0] A, B;
reg [7:0] OUTPUT = 8'b00000000;
wire [7:0] XOR_OUTPUT, ROTATE_OUTPUT, ADD_OUTPUT, SUB_OUTPUT, NEGATE_OUTPUT,         CUM_OUTPUT, MULT_UNSIGNED_OUTPUT;
reg [4:0] STATE = BASE;


xor_my_id XOR_ID_MODULE(A, B, XOR_OUTPUT);
rotate_a_b ROTATE_MODULE(A, B, ROTATE_OUTPUT);
add_a_b ADD_MODULE(A, B, ADD_OUTPUT);
subtract_a_b SUB_MODULE(A, B, SUB_OUTPUT);
negate_a NEGATE_MODULE(A, B, NEGATE_OUTPUT);
add_a_b CUM_MODULE(OUTPUT, A, CUM_OUTPUT);
mult_unsigned MULT_UNSIGNED_MODULE(A, B, MULT_UNSIGNED_OUTPUT);

initial begin

parameter BASE = 5'b00001, XOR_0 = 5'b00010, ROTATE_0 = 5'b00011, ADD_0 = 5'b00100, SUB_0 = 5'b00101,
         NEGATE_0 = 5'b00110, CUM_0 = 5'b00111, MULT_UNSIGNED_0 = 5'b01000,
      MULT_SIGNED_0 = 5'b01001, XOR_1 = 5'b01010, ROTATE_1 = 5'b01011, ADD_1 = 5'b01100, SUB_1 = 5'b01101,
         NEGATE_1 = 5'b01110, CUM_1 = 5'b01111, MULT_UNSIGNED_1 = 5'b10000, MULT_UNSIGNED_2 = 5'b10001, MULT_UNSIGNED_3 = 5'b10010,
         MULT_UNSIGNED_4 = 5'b10011, MULT_UNSIGNED_5 = 5'b10100;
         
case(STATE) 
BASE: begin
    always@ (posedge KEY[1]) begin
        case(SW) 
            4'b0000: STATE = XOR_0;
            4'b0001: STATE = ROTATE_0;
            4'b0010: STATE = ADD_0;
            4'b0011: STATE = SUB_0;
            4'b0100: STATE = NEGATE_0;
            4'b0101: STATE = CUM_0;
            4'b0110: STATE = MULT_UNSIGNED_0;
        endcase
    end
end

XOR_0: begin
    always @ (posedge KEY[1]) begin
        A = SW;
        LED = {4'b0000, A};
        STATE = XOR_1;  
    end
    
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
end
    
XOR_1: begin
    always @ (posedge KEY[1]) begin
        B = SW;
        OUTPUT = XOR_OUTPUT;
        LED = OUTPUT;
        STATE = BASE;
    end
    
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
end
ROTATE_0: begin
    always @ (posedge KEY[1]) begin
        A = SW;
        LED = {4'b0000, A};
        STATE = ROTATE_1;
    end
    
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
end
ROTATE_1: begin
    always @ (posedge KEY[1]) begin
        B = SW;
        OUTPUT = ROTATE_OUTPUT;
        LED = OUTPUT;
        STATE = BASE;
    end
    
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
end
ADD_0: begin
    always @ (posedge KEY[1]) begin
        A = SW;
        LED = {4'b0000, A};
        STATE = ADD_1;
    end
    
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
end
ADD_1: begin
    always @ (posedge KEY[1]) begin
        B = SW;
        OUTPUT = ADD_OUTPUT;
        LED = OUTPUT;
        STATE = BASE;
    end
    
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
end
SUB_0: begin
    always @ (posedge KEY[1]) begin
        A = SW;
        LED = {4'b0000, A};
        STATE = SUB_1;
    end
    
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
end
SUB_1: begin
    always @ (posedge KEY[1]) begin
        B = SW;
        OUTPUT = SUB_OUTPUT;
        LED = OUTPUT;
        STATE = BASE;
    end
    
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
end
NEGATE_0: begin
    always @ (posedge KEY[1]) begin
        A = SW;
        LED = {4'b0000, A};
        STATE = NEGATE_1;
    end
    
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
end
NEGATE_1: begin
        OUTPUT = NEGATE_OUTPUT;
        LED = OUTPUT;
        STATE = BASE;
        end
CUM_0:begin
    always @ (posedge KEY[1]) begin
        A = SW;
        LED = {4'b0000, A};
        STATE = CUM_1;
    end
    
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
end
CUM_1: begin
        OUTPUT = CUM_OUTPUT;
        LED = OUTPUT;
        STATE = BASE;
        end
MULT_UNSIGNED_0: begin
    always @ (posedge KEY[1]) begin
        A = SW;
        LED = {4'b0000, B};
        STATE = MULT_UNSIGNED_1;
    end
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
    end
MULT_UNSIGNED_1: begin
    always @ (posedge KEY[1]) begin
        B = SW;
        LED = {A, B};
        STATE = MULT_UNSIGNED_2;
    end
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
    end
MULT_UNSIGNED_2:begin 

    OUTPUT = {8{A[0]}} & B;
    LED = OUTPUT;
    always @ (posedge KEY[1]) begin
        STATE = MULT_UNSIGNED_3;
    end
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
    end
MULT_UNSIGNED_3: begin
    OUTPUT = OUTPUT + ({8{A[1]}} & B) << 1);
    LED = OUTPUT;
    always @ (posedge KEY[1]) begin
        STATE = MULT_UNSIGNED_4;
    end
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
    end
MULT_UNSIGNED_4: begin
    OUTPUT = OUTPUT + ({8{A[2]}} & B) << 2);
    LED = OUTPUT;
    always @ (posedge KEY[1]) begin
        STATE = MULT_UNSIGNED_5;
    end
    always @ (posedge KEY[0]) begin
        CASE = BASE;
    end
    end
MULT_UNSIGNED_5: begin
    OUTPUT = MULT_UNSIGNED_OUTPUT;
    LED = OUTPUT;
    STATE = BASE;
    end
    
    :STATE = STATE;
endcase

end

endmodule

The state machine operates by receiving 4 bit inputs via SW, and is driven by KEY[1]. KEY[0] is a reset to the BASE case. The case statement within BASE shows the states chosen by a particular input by SW. Each state then has at least one following state that does not depend on SW, but is still driven by KEY[1] presses. I really just want to output the correct 8-bit output generated by the correct module, determined by user input.

thanks for any help!

UPDATED:

    module project3_fall2013_statemachine(CLOCK_50, RESET, ENABLE, SW, LED);

input CLOCK_50;
input RESET, ENABLE;
input [3:0] SW;
output reg [7:0]  LED;
reg [3:0] A, B;
reg [7:0] OUTPUT = 8'b00000000;
wire [7:0] XOR_OUTPUT, ROTATE_OUTPUT, ADD_OUTPUT, SUB_OUTPUT, NEGATE_OUTPUT, CUM_OUTPUT, MULT_UNSIGNED_OUTPUT;
reg [4:0] STATE = BASE;


xor_my_id XOR_ID_MODULE(A, B, XOR_OUTPUT);
rotate_a_b ROTATE_MODULE(A, B, ROTATE_OUTPUT);
add_a_b ADD_MODULE(A, B, ADD_OUTPUT);
subtract_a_b SUB_MODULE(A, B, SUB_OUTPUT);
negate_a NEGATE_MODULE(A, NEGATE_OUTPUT);
add_a_b CUM_MODULE(OUTPUT, A, CUM_OUTPUT);
mult_unsigned MULT_UNSIGNED_MODULE(A, B, MULT_UNSIGNED_OUTPUT);



parameter BASE = 5'b00001, XOR_0 = 5'b00010, ROTATE_0 = 5'b00011, ADD_0 = 5'b00100, SUB_0 = 5'b00101,
             NEGATE_0 = 5'b00110, CUM_0 = 5'b00111, MULT_UNSIGNED_0 = 5'b01000,
          MULT_SIGNED_0 = 5'b01001, XOR_1 = 5'b01010, ROTATE_1 = 5'b01011, ADD_1 = 5'b01100, SUB_1 = 5'b01101,
             NEGATE_1 = 5'b01110, CUM_1 = 5'b01111, MULT_UNSIGNED_1 = 5'b10000, MULT_UNSIGNED_2 = 5'b10001, MULT_UNSIGNED_3 = 5'b10010,
             MULT_UNSIGNED_4 = 5'b10011, MULT_UNSIGNED_5 = 5'b10100;

always@ (posedge ENABLE or negedge RESET) begin

if(!RESET)begin
    STATE <= BASE;
end

else if(ENABLE) begin
case(STATE) 
    BASE: begin
            LED = {8'b00000000};
            case(SW) 
                4'b0000: STATE <= XOR_0;
                4'b0001: STATE <= ROTATE_0;
                4'b0010: STATE <= ADD_0;
                4'b0011: STATE <= SUB_0;
                4'b0100: STATE <= NEGATE_0;
                4'b0101: STATE <= CUM_0;
                4'b0110: STATE <= MULT_UNSIGNED_0;
            endcase
    end

    XOR_0: begin
            A <= SW;
            LED <= {4'b0000, A};
            STATE <= XOR_1; 
    end
        
    XOR_1: begin
            B <= SW;
            OUTPUT <= XOR_OUTPUT;
            LED <= OUTPUT;
            STATE <= BASE;
    end
    ROTATE_0: begin
            A <= SW;
            LED <= {4'b0000, A};
            STATE <= ROTATE_1;
    end
    ROTATE_1: begin
            B <= SW;
            OUTPUT <= ROTATE_OUTPUT;
            LED <= OUTPUT;
            STATE <= BASE;
    end
    ADD_0: begin
            A <= SW;
            LED <= {4'b0000, A};
            STATE <= ADD_1;
    end
    ADD_1: begin
            B <= SW;
            OUTPUT <= ADD_OUTPUT;
            LED <= OUTPUT;
            STATE <= BASE;
    end
    SUB_0: begin
            A <= SW;
            LED <= {4'b0000, A};
            STATE <= SUB_1;
    end
    SUB_1: begin
            B <= SW;
            OUTPUT <= SUB_OUTPUT;
            LED <= OUTPUT;
            STATE <= BASE;
    end
    NEGATE_0: begin
            A <= SW;
            LED <= {4'b0000, A};
            STATE <= NEGATE_1;
    end
    NEGATE_1: begin
            OUTPUT <= NEGATE_OUTPUT;
            LED <= OUTPUT;
            STATE <= BASE;
            end
    CUM_0:begin
            A <= SW;
            LED <= {4'b0000, A};
            STATE <= CUM_1;
    end
    CUM_1: begin
            OUTPUT <= CUM_OUTPUT;
            LED <= OUTPUT;
            STATE <= BASE;
            end
    MULT_UNSIGNED_0: begin
            A <= SW;
            LED <= {4'b0000, B};
            STATE <= MULT_UNSIGNED_1;
        end
    MULT_UNSIGNED_1: begin
            B <= SW;
            LED <= {A, B};
            STATE <= MULT_UNSIGNED_2;
        end
    MULT_UNSIGNED_2:begin 
    
        OUTPUT <= {8{A[0]}} & B;
        LED <= OUTPUT;
        STATE <= MULT_UNSIGNED_3;
        end
    MULT_UNSIGNED_3: begin
        OUTPUT <= OUTPUT + ({8{A[1]}} & B) << 1;
        LED <= OUTPUT;
        STATE <= MULT_UNSIGNED_4;
        end
    MULT_UNSIGNED_4: begin
        OUTPUT <= OUTPUT + ({8{A[2]}} & B) << 2;
        LED <= OUTPUT;
        STATE <= MULT_UNSIGNED_5;
        end
    MULT_UNSIGNED_5: begin
        OUTPUT <= MULT_UNSIGNED_OUTPUT;
        LED <= OUTPUT;
        STATE <= BASE;
        end
        
        default:STATE <= STATE;
endcase
en

    d
    else begin
    STATE = STATE;
    end
    end
    
    
    endmodule

ROTATE MODULE: should rotate to the left, unless the number is negative, in which case rotate to the right. now working

module rotate_a_b(a,b,out);
  
input [3:0]  a;
input [3:0]  b;
output [7:0] out;
wire [11:0] a_rotated;
wire [11:0] out_uncropped;

assign a_rotated = {a, a, a}; // maximum magnitude of rotation is 8
assign out_uncropped = {4'b0000, (a_rotated << b[2:0])};
assign out = out_uncropped[11:8];

endmodule

Solution

  • If you think you need nested always blocks then you are likely not thinking about hardware design, while RTL gives some abstraction from the electronic components it has to be written in such away that represent possible hardware behaviour.

    always @* represents a combinatorial block.
    always @(posdege clk) represents sequential logic, where the outputs are driven by flip-flops.

    always blocks tell the simulator when to trigger the block for simulation, as everything is happening at once, it is all parallel. The simulator could not know when to schedule code not contained in these blocks.

    You need to have always @(posedge KEY[0] and always @(posedge KEY[1] which each contain the case statement. If they are not to do anything for a particular case then hold or Zero the current values. You can have a default: case as a catch all for those unspecified.

    Update Regarding the rotate function you should be able to take the MSB to indicate if negative. Use >>> to preserve sign bits. you might need to declare the reg/wires assigned or add $signed function

    reg signed [msb:0] data_in;
    
    always @(posedge clk) begin
      if (data_in[msb] == 1'b0) begin
        data_out <= data_in <<< 1;
      end
      else begin
        data_out <= data_in >>> 1;
      end
    end
    // or use $signed(data_in) >>> 1;