--controller for the LC-2 --Based on 8051 controller by Tony Givargis --Created by: --Eric Frohnhoefer --Ron Feliciano library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_arith.all; use IEEE.std_logic_unsigned.all; entity FSM is port(clk: in std_logic; rst: in std_logic; IR: in std_logic_vector(15 downto 0); CC: in std_logic_vector(2 downto 0); --NZP Bits PC_ld: out std_logic; PC_mux: out std_logic_vector(1 downto 0); IR_ld: out std_logic; MAR_mux: out std_logic_vector(1 downto 0); MAR_gate: out std_logic; DR_addr: out std_logic_vector(2 downto 0); DR_enable: out std_logic; SR1_addr: out std_logic_vector(2 downto 0); SR2_addr: out std_logic_vector(2 downto 0); SR2_mux: out std_logic; ALU_sel: out std_logic_vector(1 downto 0); CC_ld: out std_logic; MDR_ld: out std_logic; MAR_ld: out std_logic; PC_gate: out std_logic; ALU_gate: out std_logic; MDR_gate: out std_logic; MDR_mux : out std_logic; MIO_enable: out std_logic; Read_Write: out std_logic; PC_clear: out std_logic; MDR_clear: out std_logic; MAR_clear: out std_logic; IR_clear: out std_logic; CC_clear: out std_logic ); end FSM; architecture FSM_arch of FSM is type CPU_STATE_TYPE is (CS_0, CS_1, CS_2, CS_3); type EXE_STATE_TYPE is (ES_0, ES_1, ES_2, ES_3, ES_4, ES_5, ES_6, ES_7); signal cpu_state : CPU_STATE_TYPE; signal execute_state : EXE_STATE_TYPE; constant ADD : std_logic_vector(3 downto 0) := "0001"; constant ANDR : std_logic_vector(3 downto 0) := "0101"; constant BR : std_logic_vector(3 downto 0) := "0000"; constant JSR : std_logic_vector(3 downto 0) := "0100"; constant JSRR : std_logic_vector(3 downto 0) := "1100"; constant LD : std_logic_vector(3 downto 0) := "0010"; constant LDI : std_logic_vector(3 downto 0) := "1010"; constant LDR : std_logic_vector(3 downto 0) := "0110"; constant LEA : std_logic_vector(3 downto 0) := "1110"; constant NOTR : std_logic_vector(3 downto 0) := "1001"; constant RET : std_logic_vector(3 downto 0) := "1101"; constant RTI : std_logic_vector(3 downto 0) := "1000"; constant ST : std_logic_vector(3 downto 0) := "0011"; constant STI : std_logic_vector(3 downto 0) := "1011"; constant STR : std_logic_vector(3 downto 0) := "0111"; constant TRAP : std_logic_vector(3 downto 0) := "1111"; begin state_machine : process (rst, clk) variable TRAPVECTOR : std_logic_vector (7 downto 0); variable OPCODE : std_logic_vector (3 downto 0); variable PGOFFSET : std_logic_vector (8 downto 0); variable SR1 : std_logic_vector (2 downto 0); variable SR2 : std_logic_vector (2 downto 0); variable DR : std_logic_vector (2 downto 0); variable Imm : std_logic; variable Imm_v :std_logic_vector(4 downto 0); variable link : std_logic; begin if (rst = '1') then cpu_state <= CS_0; execute_state <= ES_0; elsif (clk'event and clk='1') then case cpu_state is --------------------------------------------------------------------- --reset the controller --------------------------------------------------------------------- when CS_0 => case execute_state is when ES_0 => PC_clear <= '1'; IR_clear <= '1'; MDR_clear <= '1'; MAR_clear <= '1'; ALU_gate <= '0'; PC_gate <= '0'; MAR_gate<='0'; MDR_gate<='0'; DR_addr<="000"; SR1_addr<="000"; SR2_addr<="000"; execute_state <= ES_1; when ES_1 => PC_clear <= '0'; IR_clear <= '0'; MDR_clear <= '0'; MAR_clear <= '0'; execute_state <= ES_2; when ES_2 => MIO_enable <= '0'; MAR_ld <= '0'; IR_ld <= '0'; MDR_ld <= '0'; CC_ld <= '0'; PC_ld <= '0'; execute_state <= ES_3; when ES_3 => execute_state <= ES_4; when ES_4 => execute_state <= ES_5; when ES_5 => cpu_state <= CS_1; execute_state <= ES_0; when others => null; end case; --------------------------------------------------------------------- --handle the interrupts --------------------------------------------------------------------- when CS_1 => cpu_state <= CS_2; execute_state <= ES_0; --------------------------------------------------------------------- --process instruction (get opcodes) --------------------------------------------------------------------- when CS_2=> case execute_state is when ES_0 => PC_gate <= '1'; MAR_ld <= '1'; execute_state <= ES_1; when ES_1 => PC_gate <= '0'; --upkeep MAR_ld <= '0'; --upkeep Read_Write <= '1'; MIO_enable <= '1'; MDR_mux <= '0'; execute_state <= ES_2; when ES_2 => MDR_ld <= '1'; MIO_enable <= '0'; execute_state <= ES_3; when ES_3 => MDR_ld <= '0'; --upkeep MDR_gate <= '1'; IR_ld <= '1'; PC_mux <= "00"; PC_ld <= '1'; execute_state <= ES_4; when ES_4 => IR_ld <= '0'; --upkeep PC_ld <= '0'; --upkeep MDR_gate <= '0'; --upkeep(clear the bus) execute_state <= ES_5; when ES_5 => OPCODE := IR(15 downto 12); SR1 := IR(8 downto 6); SR2 := IR(2 downto 0); DR := IR(11 downto 9); Imm := IR(5); Imm_v := IR(4 downto 0); PGOFFSET := IR(8 downto 0); TRAPVECTOR :=IR(7 downto 0); link := IR(11); cpu_state <= CS_3; execute_state <= ES_0; when others => null; end case; --------------------------------------------------------------------- --execute instructions --------------------------------------------------------------------- when CS_3=> case OPCODE is --------------------------------------------------------------------- --finished when ADD => --DR <- SR1+SR2 case execute_state is when ES_0 => SR1_addr <= SR1; if (Imm = '0') then SR2_addr <= SR2; SR2_mux <= '1'; elsif (Imm = '1') then SR2_mux <= '0'; --load intermediate value end if; ALU_sel <= "00"; execute_state <= ES_1; when ES_1 => ALU_gate <= '1'; --Place sum on the data bus CC_ld <= '1'; execute_state <= ES_2; when ES_2 => execute_state <= ES_3; when ES_3 => DR_addr <= DR; DR_enable <= '1'; --write sum to destination register execute_state <= ES_4; when ES_4 => CC_ld <= '0'; ALU_gate <= '0'; --upkeep(clear the bus) DR_enable <= '0'; --upkeep execute_state <= ES_5; when ES_5 => cpu_state <= CS_1; execute_state <= ES_0; when others => null; end case; --------------------------------------------------------------------- --finished when ANDR => case execute_state is when ES_0 => SR1_addr <= SR1; if (Imm = '0') then SR2_addr <= SR2; SR2_mux <= '1'; elsif (Imm = '1') then SR2_mux <= '0'; --load intermediate value end if; ALU_sel <= "01"; execute_state <= ES_1; when ES_1 => ALU_gate <= '1'; execute_state <= ES_2; when ES_2 => execute_state <= ES_3; when ES_3 => CC_ld <= '1'; --store nzp bit DR_addr <= DR; DR_enable <= '1'; --write sum to destination register execute_state <= ES_4; when ES_4 => ALU_gate <= '0'; CC_ld <= '0'; --upkeep DR_enable <= '0'; --upkeep execute_state <= ES_5; when ES_5 => cpu_state <= CS_1; execute_state <= ES_0; when others => null; end case; --------------------------------------------------------------------- --finished when NOTR => case execute_state is when ES_0 => SR1_addr <= SR1; execute_state <= ES_1; when ES_1 => ALU_sel <="11"; execute_state <= ES_2; when ES_2 => ALU_gate <= '1'; execute_state <= ES_3; when ES_3 => CC_ld <= '1'; --store nzp bit DR_addr <= DR; DR_enable <= '1'; execute_state <= ES_4; when ES_4 => ALU_gate <= '0'; CC_ld <= '0'; DR_enable <= '0'; execute_state <= ES_5; when ES_5 => execute_state <= ES_0; cpu_state <= CS_1; when others => null; end case; --------------------------------------------------------------------- -- finished when LD => case execute_state is when ES_0 => MAR_mux <= "00"; MAR_gate <= '1'; -- open MAR gate MAR_ld <= '1'; execute_state <= ES_1; when ES_1 => MAR_ld <= '0'; Read_Write <= '1'; MIO_enable <= '1'; MDR_mux <= '0'; MAR_gate <= '0'; -- close MAR gate again on next clock execute_state <= ES_2; when ES_2 => MIO_enable <= '0'; MDR_ld <= '1'; execute_state <= ES_3; when ES_3 => MDR_ld <= '0'; MDR_gate <= '1'; DR_addr <= DR; DR_enable <= '1'; CC_ld <= '1'; execute_state <= ES_4; when ES_4 => MDR_gate <= '0'; CC_ld <= '0'; DR_enable <='0'; execute_state <= ES_5; when ES_5 => execute_state <= ES_0; cpu_state <= CS_1; when others => null; end case; --------------------------------------------------------------------- -- Finished when LDI => case execute_state is when ES_0 => MAR_mux <= "00"; MAR_gate <= '1'; MAR_ld <= '1'; execute_state <= ES_1; when ES_1 => MAR_ld <= '0'; MAR_gate <= '0'; Read_Write <= '1'; MIO_enable <= '1'; execute_state <= ES_2; when ES_2 => MDR_mux <= '0'; MDR_ld <= '1'; MIO_enable <= '0'; execute_state <= ES_3; when ES_3 => MDR_ld <= '0'; MDR_gate <= '1'; MAR_ld <= '1'; execute_state <= ES_4; when ES_4 => MAR_ld <= '0'; MDR_gate <= '0'; Read_Write <= '1'; MIO_enable <= '1'; execute_state <= ES_5; when ES_5 => MIO_enable <= '0'; MDR_ld <= '1'; MDR_mux <= '0'; execute_state <= ES_6; when ES_6 => MDR_ld <= '0'; MDR_gate <= '1'; DR_addr <= DR; DR_enable <= '1'; CC_ld <= '1'; execute_state <= ES_7; when ES_7 => MDR_gate <= '0'; DR_enable <= '0'; CC_ld <= '0'; execute_state <= ES_0; cpu_state <= CS_1; when others => null; end case; --------------------------------------------------------------------- --finished when LEA => case execute_state is when ES_0 => MAR_mux <= "00"; MAR_gate <= '1'; execute_state <= ES_1; when ES_1 => DR_addr <= DR; DR_enable <= '1'; CC_ld <= '1'; execute_state <= ES_2; when ES_2 => MAR_gate <= '0'; DR_enable <= '0'; CC_ld <= '0'; execute_state <= ES_3; when ES_3 => execute_state <= ES_4; when ES_4 => execute_state <= ES_5; when ES_5 => execute_state <= ES_0; cpu_state <= CS_1; when others => null; end case; --------------------------------------------------------------------- --finished --need to add NZP when LDR => case execute_state is when ES_0 => SR1_addr <= SR1; execute_state <= ES_1; when ES_1 => MAR_mux <= "01"; MAR_gate <= '1'; MAR_ld <= '1'; execute_state <= ES_2; when ES_2 => MAR_ld <= '0'; MAR_gate <= '0'; MIO_enable <= '1'; Read_Write <= '1'; execute_state <= ES_3; when ES_3 => MDR_mux <= '0'; MDR_ld <= '1'; MIO_enable <= '0'; execute_state <= ES_4; when ES_4 => MDR_ld <= '0'; MDR_gate <= '1'; DR_addr <= DR; DR_enable <= '1'; CC_ld <= '1'; execute_state <= ES_5; when ES_5 => DR_enable <= '0'; CC_ld <= '0'; MDR_gate <= '0'; execute_state <= ES_0; cpu_state <= CS_1; when others => null; end case; --------------------------------------------------------------------- when ST => case execute_state is when ES_0 => MAR_mux <= "00"; MAR_gate <= '1'; MAR_ld <= '1'; SR1_addr <= DR; ALU_sel <= "10"; execute_state <= ES_1; when ES_1 => MAR_ld <= '0'; MAR_gate <= '0'; ALU_gate <='1'; MDR_mux <= '1'; MDR_ld <= '1'; execute_state <= ES_2; when ES_2 => ALU_gate <= '0'; MDR_ld <= '0'; Read_Write <= '0'; MIO_enable <= '1'; execute_state <= ES_3; when ES_3 => MIO_enable <= '0'; execute_state <= ES_4; when ES_4 => execute_state <= ES_5; when ES_5 => execute_state <= ES_0; cpu_state <= CS_1; when others => null; end case; --------------------------------------------------------------------- when STR => case execute_state is when ES_0 => SR1_addr <= SR1; ALU_sel <= "10"; execute_state <= ES_1; when ES_1 => MAR_mux <= "01"; MAR_gate <= '1'; MAR_ld <= '1'; execute_state <= ES_2; when ES_2 => MAR_gate <='0'; MAR_ld <='0'; SR1_addr <= DR; ALU_sel <= "10"; execute_state <= ES_3; when ES_3 => ALU_gate <= '1'; MDR_mux <= '1'; MDR_ld <= '1'; execute_state <= ES_4; when ES_4 => MDR_ld <= '0'; ALU_gate <= '0'; MIO_enable <= '1'; Read_Write <= '0'; execute_state <= ES_5; when ES_5 => MIO_enable <= '0'; execute_state <= ES_0; cpu_state <= CS_1; when others => null; end case; --------------------------------------------------------------------- when STI => case execute_state is when ES_0 => MAR_mux <="00"; MAR_ld <= '1'; MAR_gate <= '1'; execute_state <= ES_1; when ES_1 => MAR_ld <= '0'; MAR_gate <= '0'; MIO_enable <= '1'; Read_Write <= '1'; execute_state <= ES_2; when ES_2 => MDR_mux <= '0'; MDR_ld <= '1'; MIO_enable <= '0'; execute_state <= ES_3; when ES_3 => MDR_gate <= '1'; MAR_ld <= '1'; SR1_addr <= DR; ALU_sel <= "10"; execute_state <= ES_4; when ES_4 => MDR_gate <= '0'; MAR_ld <= '0'; ALU_gate <= '1'; MDR_mux <= '1'; MDR_ld <= '1'; execute_state <= ES_5; when ES_5 => ALU_gate <= '0'; MDR_ld <= '0'; Read_Write <= '0'; MIO_enable <= '1'; execute_State <= ES_6; when ES_6 => MIO_enable <= '0'; execute_state <= ES_0; cpu_state <= CS_1; when others => null; end case; --------------------------------------------------------------------- when JSR => case execute_state is when ES_0 => if (link = '1') then PC_gate <= '1'; DR_addr <= "111"; Dr_enable <= '1'; PC_mux <= "11"; PC_ld <= '1'; elsif (link = '0') then PC_mux <= "11"; PC_ld <= '1'; end if; execute_state <= ES_1; when ES_1 => if (link = '1') then PC_gate <= '0'; DR_enable <= '0'; PC_ld <= '0'; elsif (link <= '0') then PC_ld <= '0'; end if; execute_state <= ES_2; when ES_2 => execute_state <= ES_3; when ES_3 => execute_state <= ES_4; when ES_4 => execute_state <= ES_5; when ES_5 => execute_state <= ES_0; cpu_state <= CS_1; when others => null; end case; --------------------------------------------------------------------- when JSRR => case execute_state is when ES_0 => SR1_addr <= SR1; execute_state <= ES_1; when ES_1 => if (link = '1') then PC_gate <= '1'; DR_addr <= "111"; DR_enable <= '1'; elsif (link <= '0') then MAR_mux <= "01"; MAR_gate <= '1'; PC_mux <= "01"; PC_ld <= '1'; end if; execute_state <= ES_2; when ES_2 => if (link = '1') then DR_enable <= '0'; PC_gate <= '0'; MAR_mux <= "01"; MAR_gate <= '1'; PC_mux <= "01"; PC_ld <= '1'; elsif (link = '0') then PC_ld <= '0'; MAR_gate <= '0'; end if; execute_state <= ES_3; when ES_3 => if (link <= '1') then MAR_gate <= '0'; PC_ld <= '0'; end if; execute_state <= ES_4; when ES_4 => execute_state <= ES_5; when ES_5 => execute_state <= ES_0; cpu_state <= CS_1; when others => null; end case; --------------------------------------------------------------------- when RET => case execute_state is when ES_0 => SR1_addr <= "111"; ALU_sel <= "10"; execute_state <= ES_1; when ES_1 => ALU_gate <= '1'; PC_mux <= "01"; PC_ld <= '1'; execute_state <= ES_2; when ES_2 => ALU_gate <= '0'; PC_ld <= '0'; execute_state <= ES_3; when ES_3 => execute_state <= ES_4; when ES_4 => execute_state <= ES_5; when ES_5 => execute_state <= ES_0; cpu_state <= CS_1; when others => null; end case; --------------------------------------------------------------------- when BR => case execute_state is when ES_0 => if (((IR(11) and CC(2)) or (IR(10) and CC(1)) or (IR(9) and CC(0))) = '1') then PC_mux <= "11"; PC_ld <= '1'; else execute_state <= ES_0; cpu_state <= CS_1; end if; execute_state <= ES_1; when ES_1 => PC_ld <= '0'; execute_state <= ES_2; when ES_2 => execute_state <= ES_3; when ES_3 => execute_state <= ES_4; when ES_4 => execute_state <= ES_5; when ES_5 => execute_state <= ES_0; cpu_state <= CS_1; when others => null; end case; --------------------------------------------------------------------- when TRAP => case execute_state is when ES_0 => PC_gate <= '1'; DR_addr <= "111"; DR_enable <= '1'; execute_state <= ES_1; when ES_1 => PC_gate <= '0'; DR_enable <= '0'; MAR_mux <= "10"; MAR_gate <= '1'; MAR_ld <= '1'; execute_state <= ES_2; when ES_2 => MAR_gate <= '0'; MAR_ld <= '0'; Read_Write <= '1'; MIO_enable <= '1'; execute_state <= ES_3; when ES_3 => MIO_enable <= '0'; MDR_mux <= '0'; MDR_ld <= '1'; execute_state <= ES_4; when ES_4 => MDR_ld <= '0'; MDR_gate <= '1'; PC_ld <= '1'; PC_mux <= "01"; execute_state <= ES_5; when ES_5 => PC_ld <= '0'; MDR_gate <= '0'; if(TRAPVECTOR = "00100101") then execute_state <= ES_5; else execute_state <= ES_0; cpu_state <= CS_1; end if; when others => null; end case; when others => null; end case; when others => null; end case; end if; end process state_machine; end FSM_arch;