library IEEE; use IEEE.std_logic_1164.all; entity Controller is port( Clock : in std_logic; -- CLK input port Reset : in std_logic; -- Reset input to go back to state S0 Opcode : in std_logic_vector(1 downto 0); --Opcode input to determine what insturction to be executed Hit : in std_logic; -- Hit input would give signal when the cache is hit LDPC : out std_logic; -- LDPC output would give signal to the PC_Register when to load the PC ImSel : out std_logic; -- ImSel output would give signal to the Quad 2x1 MUX to select either D1 or D0 LDAcc : out std_logic; -- LDAcc output would give signal to the Accumulator when to load the accumulator Func : out std_logic_vector(2 downto 0); --See Assignment #2 for meaning of Func bits. Cond : in std_logic_vector(1 downto 0) --Cond(0) is '1' when ALU input A = zero ('1' means A = x0). --Cond(1) is '1' when ALU result is zero. ); end Controller; architecture arch1 of Controller is type stateType is (S0, S1, S2, S3); -- S0 is the first state, depending on the Reset input, it would either stay in state S0 or check if cache is hi -- If cache is hit in state S0 then depending on the opcode, output the LDPC, LDAcc, ImSel, Func(1) and Func(0) accordingly -- If cache is missed in state S0, then go to state S3 -- S1 comes after the machine does the output logic for the state S0, S1 would does certain outputs and move registers from ALU to Acc. After that it goes back to state S0 -- S2 comes if the Cond(1) is 0, and it does certain outputs and increment PC. After that it goes back to state S0 -- S3 would check if cache hit or not, if not then stay in S3. If hit, it does the same output logic as in state S0 signal state: stateType := S0; begin NextStateLogic: process (Clock, Reset) is begin if (Reset = '1') then state <= S0; elsif (Clock'event and Clock = '1') then case state is when S0 => if (Hit = '1') then if (Opcode = "00") then state <= S1; -- LoadAccImmediate instruction. elsif (Opcode = "01") then state <= S1; -- AddAccImmediate instruction. elsif (Opcode = "10") then state <= S0; -- Branch on Acc zero instruction elsif (Opcode = "11") then -- Decrement and Branch if Zero if(Cond(1) = '0') then state <= S2; else state <= S1; end if; else state <= S0; -- goto S0 if unknown Opcode. end if; else state <= S3; -- go to state S3 if the cache is missed in state S0 end if; when S1 => state <= S0; -- PC will be incremented moving from S1 to S0 (for several instructions). when S2 => state <= S0; -- PC will be loaded with immediate at end of phase 2 of dbnz. when S3 => -- When the cache is hit in state S3, do the following according to the Opcode if (Hit = '1') then if (Opcode = "00") then state <= S1; -- LoadAccImmediate instruction. elsif (Opcode = "01") then state <= S1; -- AddAccImmediate instruction. elsif (Opcode = "10") then state <= S0; -- Branch on Acc zero instruction elsif (Opcode = "11") then -- Decrement and Branch if Zero if(Cond(1) = '0') then state <= S2; -- result not zero so take branch. else state <= S1; -- result zero so not taken. end if; else state <= S0; -- goto S0 if unknown Opcode. end if; else state <= S3; -- If cache is missed, stay in state S3 end if; end case; end if; end process NextStateLogic; OutputLogic: process(state, Opcode, Cond, Hit) is begin if (Hit = '1') then -- If chache is hit case state is when S0 => if (Opcode = "00") then -- a LoadAccImmediate instruction. LDPC <= '0'; LDAcc <= '1'; ImSel <= '1'; Func(1) <= '0'; Func(0) <= '0'; elsif (Opcode = "01") then -- an AddAccImmediate instruction. LDPC <= '0'; LDAcc <= '1'; ImSel <= '1'; Func(1) <= '1'; Func(0) <= '0'; elsif (Opcode = "10" AND Cond(0) = '0') then -- a BranchZero not taken. LDPC <= '1'; LDAcc <= '0'; ImSel <= '0'; Func(1) <= '0'; Func(0) <= '1'; elsif (Opcode = "10" AND Cond(0) = '1') then -- a BranchZero taken. LDPC <= '1'; LDAcc <= '0'; ImSel <= '1'; Func(1) <= '0'; Func(0) <= '0'; elsif (Opcode = "11") then -- we tell ALU to decrement it's A input, and we latch it into Acc. LDPC <= '0'; LDAcc <= '1'; ImSel <= 'x'; Func(1) <= '1'; Func(0) <= '1'; end if; when S1 => -- As this state ends, we increment the PC using Func="01" and latch it. LDPC <= '1'; LDAcc <= '0'; ImSel <= '0'; Func(1) <= '0'; Func(0) <= '1'; when S2 => -- As this state ends, we branch the PC using Func="00" and latch it. LDPC <= '1'; LDAcc <= '0'; ImSel <= '1'; Func(1) <= '0'; Func(0) <= '0'; when S3 => -- If chache is hit in state S3, output the followings according to the Opcode if (Opcode = "00") then -- a LoadAccImmediate instruction. LDPC <= '0'; LDAcc <= '1'; ImSel <= '1'; Func(1) <= '0'; Func(0) <= '0'; elsif (Opcode = "01") then -- an AddAccImmediate instruction. LDPC <= '0'; LDAcc <= '1'; ImSel <= '1'; Func(1) <= '1'; Func(0) <= '0'; elsif (Opcode = "10" AND Cond(0) = '0') then -- a BranchZero not taken. LDPC <= '1'; LDAcc <= '0'; ImSel <= '0'; Func(1) <= '0'; Func(0) <= '1'; elsif (Opcode = "10" AND Cond(0) = '1') then -- a BranchZero taken. LDPC <= '1'; LDAcc <= '0'; ImSel <= '1'; Func(1) <= '0'; Func(0) <= '0'; elsif (Opcode = "11") then -- we tell ALU to decrement it's A input, and we latch it into Acc. LDPC <= '0'; LDAcc <= '1'; ImSel <= 'x'; Func(1) <= '1'; Func(0) <= '1'; end if; end case; else -- If chache is missed, then DO NOT load PC or Accumulator LDPC <= '0'; LDAcc <= '0'; ImSel <= 'x'; Func(1) <= 'x'; Func(0) <= 'x'; end if; Func(2) <= '0'; end process OutputLogic; end arch1;