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
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;