I am working on a finite state machine that is written in Verilog and being simulated in ModelSim. This FSM is for implementation of a SISC processor. In this implementation, we are using arithmetic and branch instructions. Below is the control module in question:
module ctrl (clk, rst_f, opcode, mm, stat, rf_we, alu_op, wb_sel, pc_sel, pc_write, pc_rst, br_sel, rb_sel, ir_load);
input clk, rst_f;
input[3:0] stat, mm, opcode;
output rf_we, wb_sel, pc_sel, pc_write, pc_rst, br_sel, rb_sel, ir_load;
output [1:0] alu_op;
reg rf_we, wb_sel, pc_sel, pc_write, pc_rst, br_sel, rb_sel, ir_load;
reg [1:0] alu_op;
// states
parameter start0 = 0, start1 = 1, fetch = 2, decode = 3, execute = 4, mem = 5, writeback = 6;
// opcodes
parameter NOOP = 0, LOD = 1, STR = 2, SWP = 3, BRA = 4, BRR = 5, BNE = 6, BNR = 7, ALU_OP = 8, HLT=15;
// addressing modes
parameter am_imm = 8;
// state registers
reg [2:0] present_state, next_state;
reg [3:0] branchTest;
initial
present_state = start0;
always @(posedge clk or negedge rst_f)
begin
if(!rst_f)
next_state = 1;
present_state = next_state;
end
always @(mm or stat)
begin
branchTest = mm & stat;
end
always @(present_state or next_state)
begin
case (present_state)
0: //Startup
next_state = start1;
1: //Reset state - cycle setup step
begin
wb_sel = 0;
rf_we = 0;
alu_op[0] = 0;
alu_op[1] = 0;
pc_sel = 0;
pc_write = 0;
pc_rst = 1;
br_sel = 0;
rb_sel = 0;
ir_load = 0;
next_state = fetch;
end
2: //fetch step - This will be retrieve instruction from memory
begin
pc_write = 0;
pc_rst = 0;
ir_load = 1;
pc_write = 1;
wb_sel = 0;
rf_we = 0;
alu_op[0] = 0;
alu_op[1] = 0;
br_sel = 0;
rb_sel = 0;
pc_sel = 0;
next_state = decode;
end
3: //decode step - Interpret instruction and decide what signals to turn on
begin
pc_write = 0;
ir_load = 0;
case (opcode)
NOOP: next_state = execute;
LOD: next_state = execute;//Code for load instructions
STR: next_state = execute;//Code for store instructions
SWP: next_state = execute;//Code for swap instruction
BRA: begin if(branchTest != 0) //Code for branch if equal instruction
begin
br_sel = 0;
pc_sel = 1;
pc_write = 1;
next_state = fetch;
end
else
next_state = execute;
end
BRR: begin if(branchTest != 0) //Code for branch if equal relative instruction
begin
br_sel = 1;
pc_sel = 1;
pc_write = 1;
next_state = fetch;
end
else
next_state = execute;
end
BNE: begin if(branchTest == 0) //Code for branch if not equal instruction
begin
br_sel = 0;
pc_sel = 1;
pc_write = 1;
next_state = fetch;
end
else
next_state = execute;
end
BNR: begin if(branchTest == 0) //Code for branch if not equal relative instruction
begin
br_sel = 1;
pc_sel = 1;
pc_write = 1;
next_state = fetch;
end
else
next_state = execute;
end
ALU_OP: begin
next_state = execute;
end
endcase
end
4: //execute step
begin
if(opcode != ALU_OP)
begin
alu_op[1] = 1;
end
else
begin
alu_op[1] = 0;
alu_op[0] = mm[3];
end
next_state = mem;
end
5: //memory step
begin
next_state = writeback;
end
6: //writeback step
begin
if(opcode == ALU_OP)
begin
rf_we = 1;
end
next_state = fetch;
end
endcase
end
// Halt on HLT instruction
always @ (opcode)
begin
if (opcode == HLT)
begin
#5 $display ("Halt."); //Delay 5 ns so $monitor will print the halt instruction
$stop;
end
end
endmodule
The arithmetic functions work as expected. However, when the branch instructions are executed, the change in outputs seem to be delayed by many cycles. I have a monitor statement in another module that is outputting the various values from the simulation. The pertinent part of output is as follows:
# R1:00000001 R2:00000002 R3:00000002 R4:00000002 R5:ff000019 IR:80331002 PC:001b ir_load:0 pc_write:0 br_addr: 4125 IM:7100fffd br_sel:0 pc_sel:0 OP-CODE:8 mm:0000 bTest:0000 alu_op:00 rf_we:0 write_data:00000002 state:4 next:5 (STAT: 0000)
# R1:00000001 R2:00000002 R3:00000002 R4:00000002 R5:ff000019 IR:80331002 PC:001b ir_load:0 pc_write:0 br_addr: 4125 IM:7100fffd br_sel:0 pc_sel:0 OP-CODE:8 mm:0000 bTest:0000 alu_op:00 rf_we:0 write_data:00000001 state:5 next:6 (STAT: 0000)
# R1:00000001 R2:00000002 R3:00000002 R4:00000002 R5:ff000019 IR:80331002 PC:001b ir_load:0 pc_write:0 br_addr: 4125 IM:7100fffd br_sel:0 pc_sel:0 OP-CODE:8 mm:0000 bTest:0000 alu_op:00 rf_we:1 write_data:00000001 state:6 next:2 (STAT: 0000)
# R1:00000001 R2:00000002 R3:00000001 R4:00000002 R5:ff000019 IR:80331002 PC:001b ir_load:1 pc_write:1 br_addr: 4125 IM:7100fffd br_sel:0 pc_sel:0 OP-CODE:8 mm:0000 bTest:0000 alu_op:00 rf_we:0 write_data:00000001 state:2 next:3 (STAT: 0000)
**# R1:00000001 R2:00000002 R3:00000001 R4:00000002 R5:ff000019 IR:7100fffd PC:001c ir_load:0 pc_write:0 br_addr: 25 IM:60000016 br_sel:0 pc_sel:0 OP-CODE:7 mm:0001 bTest:0000 alu_op:00 rf_we:0 write_data:00000001 state:3 next:4 (STAT: 0000)
# R1:00000001 R2:00000002 R3:00000001 R4:00000002 R5:ff000019 IR:7100fffd PC:001c ir_load:0 pc_write:0 br_addr: 25 IM:60000016 br_sel:0 pc_sel:0 OP-CODE:7 mm:0001 bTest:0000 alu_op:10 rf_we:0 write_data:00000000 state:4 next:5 (STAT: 0000)
# R1:00000001 R2:00000002 R3:00000001 R4:00000002 R5:ff000019 IR:7100fffd PC:001c ir_load:0 pc_write:0 br_addr: 25 IM:60000016 br_sel:0 pc_sel:0 OP-CODE:7 mm:0001 bTest:0000 alu_op:10 rf_we:0 write_data:00000000 state:5 next:6 (STAT: 0000)
# R1:00000001 R2:00000002 R3:00000001 R4:00000002 R5:ff000019 IR:7100fffd PC:001c ir_load:0 pc_write:0 br_addr: 25 IM:60000016 br_sel:0 pc_sel:0 OP-CODE:7 mm:0001 bTest:0000 alu_op:10 rf_we:0 write_data:00000000 state:6 next:2 (STAT: 0000)
# R1:00000001 R2:00000002 R3:00000001 R4:00000002 R5:ff000019 IR:7100fffd PC:001c ir_load:1 pc_write:1 br_addr: 25 IM:60000016 br_sel:0 pc_sel:0 OP-CODE:7 mm:0001 bTest:0000 alu_op:00 rf_we:0 write_data:00000000 state:2 next:3 (STAT: 0000)
# R1:00000001 R2:00000002 R3:00000001 R4:00000002 R5:ff000019 IR:60000016 PC:001d ir_load:0 pc_write:1 br_addr: 22 IM:f0000000 br_sel:1 pc_sel:1 OP-CODE:6 mm:0000 bTest:0000 alu_op:00 rf_we:0 write_data:00000000 state:3 next:2 (STAT: 0000)
# R1:00000001 R2:00000002 R3:00000001 R4:00000002 R5:ff000019 IR:60000016 PC:0016 ir_load:1 pc_write:1 br_addr: 44 IM:8822ffff br_sel:0 pc_sel:0 OP-CODE:6 mm:0000 bTest:0000 alu_op:00 rf_we:0 write_data:00000000 state:2 next:3 (STAT: 0000)
# R1:00000001 R2:00000002 R3:00000001 R4:00000002 R5:ff000019 IR:8822ffff PC:0017 ir_load:0 pc_write:1 br_addr: 22 IM:51000005 br_sel:0 pc_sel:1 OP-CODE:8 mm:1000 bTest:0000 alu_op:00 rf_we:0 write_data:00000000 state:3 next:2 (STAT: 0000)**
# R1:00000001 R2:00000002 R3:00000001 R4:00000002 R5:ff000019 IR:8822ffff PC:0016 ir_load:1 pc_write:1 br_addr: 21 IM:8822ffff br_sel:0 pc_sel:0 OP-CODE:8 mm:1000 bTest:0000 alu_op:00 rf_we:0 write_data:00000000 state:2 next:3 (STAT: 0000)
# R1:00000001 R2:00000002 R3:00000001 R4:00000002 R5:ff000019 IR:8822ffff PC:0017 ir_load:0 pc_write:0 br_addr: 22 IM:51000005 br_sel:0 pc_sel:0 OP-CODE:8 mm:1000 bTest:0000 alu_op:00 rf_we:0 write_data:00000000 state:3 next:4 (STAT: 0000)
In the lines marked with ** in the output, there are two commands (OPCODE) being used: 7 and 6. OPCODE 7 comes before OPCODE 6 in the output provided, and when OPCODE 7 is run, given the conditions it was passed, should change the state of the output, return to the FETCH step and branch the program counter (PC). However, it seems to evaluate to a different condition, instead move onto EXECUTE, and finish out the cycle. On the OPCODE 6, which should always evaluate true and branch, it indeed branches as I would expect. However, on the next OPCODE after 6, it seems to also produce a branch result, though it is not a branch instruction. Given the nature of the instructions being passed, I think it is only a fluke that it was going to branch to the same place regardless, so it doesn't totally mess up the instructions (both OPCODE 7 and 6 branch to the same place).
What I am surmising is - the OPCODE 7 did indeed test true for the branch, but instead of setting all its variables during the current cycle and moving to FETCH, it goes through all the steps and waits until the FSM goes back to FETCH and then changes (this creates the return FETCH seen during OPCODE 6). Since the following OPCODE is also a branch, it also generates its conditions, but not until the FSM returns to FETCH. During the next instruction, it executes the branch criteria from OPCODE 6, but fortunately returns to itself and then continues on its merry way.
So my question is am I barking up the wrong tree or am I not setting my outputs and next state properly in the if statements that are in DECODE state of my FSM?
I have a passing familiarity with HDLs, and have worked with VHDL before, but this is my first go at Verilog. This question is a bit long winded, so if any clarification is needed, please feel free to ask.