aboutsummaryrefslogtreecommitdiff
path: root/src/statemachine.sv
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/statemachine.sv246
1 files changed, 246 insertions, 0 deletions
diff --git a/src/statemachine.sv b/src/statemachine.sv
new file mode 100644
index 0000000..1a5beb1
--- /dev/null
+++ b/src/statemachine.sv
@@ -0,0 +1,246 @@
+`define STATE_RESET 3'b000
+`define STATE_HALT 3'b001
+`define STATE_IF 3'b010
+`define STATE_DECODE 3'b011
+`define STATE_EXEC 3'b100
+`define STATE_MEM 3'b101
+`define STATE_WRITEBACK 3'b110
+
+module statemachine(clk, reset, opcode, op, pc_reset, pc_load, pc_sel, ir_load,
+ addr_sel, mem_cmd, reg_w_sel, reg_a_sel, reg_b_sel, write,
+ loada, loadb, loadc, loads, loadm, asel, bsel, csel, vsel,
+ halt);
+ input clk, reset;
+ input [1:0] op;
+ input [2:0] opcode;
+ output reg pc_reset, pc_load, ir_load, addr_sel, write, loada, loadb,
+ loadc, loads, loadm, asel, bsel, csel, halt;
+ output reg [1:0] pc_sel, mem_cmd;
+ output reg [2:0] reg_w_sel, reg_a_sel, reg_b_sel;
+ output reg [3:0] vsel;
+
+ reg [3:0] state;
+
+ always_comb begin
+ {pc_reset, pc_load, pc_sel, ir_load, addr_sel, mem_cmd,
+ reg_w_sel, reg_a_sel, reg_b_sel, write, loada, loadb,
+ loadc, loads, loadm, asel, bsel, csel, vsel, halt}
+ = 31'b0;
+
+ casex ({state, opcode, op})
+ /* Reset state. */
+ {`STATE_RESET, 5'bxxx_xx}:
+ {pc_reset, pc_load, addr_sel, mem_cmd}
+ = 5'b111_10;
+
+ /* Instruction fetch. */
+ {`STATE_IF, 5'bxxx_xx}:
+ {pc_load, ir_load, addr_sel, mem_cmd} = 5'b111_10;
+
+ /* MOV immediate to register. */
+ {`STATE_DECODE, 5'b110_10}:
+ {addr_sel, mem_cmd, reg_w_sel, write, vsel}
+ = 11'b1_10_100_1_0100;
+
+ /* MOV register to register. */
+ {`STATE_DECODE, 5'b110_00}:
+ {reg_b_sel, loadb} = 4'b001_1;
+ {`STATE_EXEC, 5'b110_00}:
+ {loadc, asel} = 2'b11;
+ {`STATE_WRITEBACK, 5'b110_00}:
+ {addr_sel, mem_cmd, reg_w_sel, write, vsel}
+ = 11'b1_10_010_1_0001;
+
+ /* General ALU operations. */
+ {`STATE_DECODE, 5'b101_xx}:
+ {reg_a_sel, reg_b_sel, loada, loadb} = 8'b100_001_11;
+
+ /* ADD. */
+ {`STATE_EXEC, 5'b101_00}:
+ loadc = 1'b1;
+ {`STATE_WRITEBACK, 5'b101_00}:
+ {addr_sel, mem_cmd, reg_w_sel, write, vsel}
+ = 11'b1_10_010_1_0001;
+
+ /* CMP. */
+ {`STATE_EXEC, 5'b101_01}:
+ {addr_sel, mem_cmd, loads} = 4'b1_10_1;
+
+ /* AND. */
+ {`STATE_EXEC, 5'b101_10}:
+ loadc = 1'b1;
+ {`STATE_WRITEBACK, 5'b101_10}:
+ {addr_sel, mem_cmd, reg_w_sel, write, vsel}
+ = 11'b1_10_010_1_0001;
+
+ /* MVN. */
+ {`STATE_EXEC, 5'b101_11}:
+ loadc = 1'b1;
+ {`STATE_WRITEBACK, 5'b101_11}:
+ {addr_sel, mem_cmd, reg_w_sel, write, vsel}
+ = 11'b1_10_010_1_0001;
+
+ /* LDR. */
+ {`STATE_DECODE, 5'b011_xx}:
+ {reg_a_sel, loada} = 4'b100_1;
+ {`STATE_EXEC, 5'b011_xx}:
+ {loadm, bsel} = 2'b11;
+ {`STATE_MEM, 5'b011_xx}:
+ mem_cmd = 2'b10;
+ {`STATE_WRITEBACK, 5'b011_xx}:
+ {addr_sel, mem_cmd, reg_w_sel, write, vsel}
+ = 11'b1_10_010_1_0010;
+
+ /* STR. */
+ {`STATE_DECODE, 5'b100_xx}:
+ {reg_a_sel, reg_b_sel, csel, loada, loadc}
+ = 9'b100_010_111;
+ {`STATE_EXEC, 5'b100_xx}:
+ {loadm, bsel} = 2'b11;
+ {`STATE_MEM, 5'b100_xx}:
+ mem_cmd = 2'b01;
+ {`STATE_WRITEBACK, 5'b100_xx}:
+ {addr_sel, mem_cmd} = 3'b1_10;
+
+ /* B, BEQ, BNE, BLT, BLE. */
+ {`STATE_DECODE, 5'b001_xx}:
+ {pc_load, pc_sel} = 3'b1_01;
+ {`STATE_EXEC, 5'b001_xx}:
+ {addr_sel, mem_cmd} = 3'b1_10;
+
+ /* BL. */
+ {`STATE_DECODE, 5'b010_11}:
+ {pc_load, pc_sel, reg_w_sel, write, vsel}
+ = 11'b1_11_100_1_1000;
+ {`STATE_EXEC, 5'b010_11}:
+ {addr_sel, mem_cmd} = 3'b1_10;
+
+ /* BX, BLX. */
+ {`STATE_DECODE, 5'b010_xx}:
+ {reg_b_sel, loadc, csel} = 5'b010_11;
+
+ /* BX. */
+ {`STATE_EXEC, 5'b010_00}:
+ {pc_load, pc_sel} = 3'b1_10;
+ {`STATE_WRITEBACK, 5'b010_00}:
+ {addr_sel, mem_cmd} = 3'b1_10;
+
+ /* BLX. */
+ {`STATE_EXEC, 5'b010_10}:
+ {pc_load, pc_sel, reg_w_sel, write, vsel}
+ = 11'b1_10_100_1_1000;
+ {`STATE_WRITEBACK, 5'b010_10}:
+ {addr_sel, mem_cmd}
+ = 3'b1_10;
+
+ {`STATE_HALT, 5'bxxx_xx}:
+ halt = 1'b1;
+
+ default: begin end
+ endcase
+ end
+
+ always_ff @(posedge clk) casex ({reset, state, opcode, op})
+ /* Reset. */
+ 10'b1_xxxx_xxx_xx:
+ state <= `STATE_RESET;
+ {1'b0, `STATE_RESET, 5'bxxx_xx}:
+ state <= `STATE_IF;
+
+ /* Beginning of instruction cycle. */
+ {1'b0, `STATE_IF, 5'bxxx_xx}:
+ state <= `STATE_DECODE;
+
+ /* HALT. */
+ {1'b0, `STATE_DECODE, 5'b111_xx}:
+ state <= `STATE_HALT;
+ {1'b0, `STATE_HALT, 5'bxxx_xx}:
+ state <= `STATE_HALT;
+
+ /* MOV immediate to register. */
+ {1'b0, `STATE_DECODE, 5'b110_10}:
+ state <= `STATE_IF;
+
+ /* MOV register to register. */
+ {1'b0, `STATE_DECODE, 5'b110_00}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b110_00}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b110_00}:
+ state <= `STATE_IF;
+
+ /* ADD. */
+ {1'b0, `STATE_DECODE, 5'b101_00}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b101_00}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b101_00}:
+ state <= `STATE_IF;
+
+ /* CMP. */
+ {1'b0, `STATE_DECODE, 5'b101_01}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b101_01}:
+ state <= `STATE_IF;
+
+ /* AND. */
+ {1'b0, `STATE_DECODE, 5'b101_10}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b101_10}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b101_10}:
+ state <= `STATE_IF;
+
+ /* MVN. */
+ {1'b0, `STATE_DECODE, 5'b101_11}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b101_11}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b101_11}:
+ state <= `STATE_IF;
+
+ /* LDR. */
+ {1'b0, `STATE_DECODE, 5'b011_xx}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b011_xx}:
+ state <= `STATE_MEM;
+ {1'b0, `STATE_MEM, 5'b011_xx}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b011_xx}:
+ state <= `STATE_IF;
+
+ /* STR. */
+ {1'b0, `STATE_DECODE, 5'b100_xx}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b100_xx}:
+ state <= `STATE_MEM;
+ {1'b0, `STATE_MEM, 5'b100_xx}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b100_xx}:
+ state <= `STATE_IF;
+
+ /* B, BEQ, BNE, BLT, BLE. */
+ {1'b0, `STATE_DECODE, 5'b001_xx}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b001_xx}:
+ state <= `STATE_IF;
+
+ /* BL. */
+ {1'b0, `STATE_DECODE, 5'b010_11}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b010_11}:
+ state <= `STATE_IF;
+
+ /* BX, BLX. */
+ {1'b0, `STATE_DECODE, 5'b010_xx}:
+ state <= `STATE_EXEC;
+ {1'b0, `STATE_EXEC, 5'b010_xx}:
+ state <= `STATE_WRITEBACK;
+ {1'b0, `STATE_WRITEBACK, 5'b010_xx}:
+ state <= `STATE_IF;
+
+ /* Should not happen. Otherwise, an error occurred. */
+ default:
+ state <= `STATE_RESET;
+ endcase
+endmodule: statemachine