---------------------------------------------------------------------------------- -- Company: Weber State University -- Engineer: Fon Brown -- -- Create Date: 20:37:50 11/22/2013 -- Design Name: Simplified mips -- Module Name: cpu - Behavioral -- -- Description: Module to implement a simplified MIPs processor in VHDL -- -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity cpu is Port (clk : in STD_LOGIC; reset : in STD_LOGIC; inst_address : out STD_LOGIC_VECTOR (31 downto 0); inst_in : in STD_LOGIC_VECTOR (31 downto 0); data_address : out STD_LOGIC_VECTOR (31 downto 0); data_out : out STD_LOGIC_VECTOR (31 downto 0); data_in : in STD_LOGIC_VECTOR (31 downto 0); data_write_enable : out STD_LOGIC); end cpu; architecture Behavioral of cpu is -- types type pc_select is (pc_next, pc_jump, pc_branch, pc_jreg); type alu_op is (alu_add, alu_sub, alu_and, alu_or); type reg_file_type is array (0 to 31) of unsigned(31 downto 0); -- register file signal reg_file: reg_file_type; -- Fetch Stage signal F_PC: unsigned(31 downto 0); -- Decode Stage signal D_pc_select: pc_select; -- controls next PC signal D_PC: unsigned (31 downto 0); -- address of subsequent instruction signal D_IR: unsigned (31 downto 0); -- instruction register signal D_S: unsigned (31 downto 0); -- register contents for Rs signal D_T: unsigned (31 downto 0); -- register contents for Rt signal D_Imm: unsigned (31 downto 0); -- Sign Extended immediate operand signal D_Op2: unsigned (31 downto 0); -- Second operand for ALU (with D_S) signal D_alu_op: alu_op; -- alu operation for this instruction signal D_Rs: unsigned (4 downto 0); -- address of register S signal D_Rt: unsigned (4 downto 0); -- address of register T signal D_Rd: unsigned (4 downto 0); -- address of register to write back signal D_stall_for_S: boolean; -- using register S - stall if not ready signal D_stall_for_T: boolean; -- using register T - stall if not ready signal D_stall: boolean; -- data dependency detected signal D_write_reg: boolean; -- write back will occur signal D_write_mem: boolean; -- store (write to memory) will occur signal D_read_mem: boolean; -- read from memory will occur -- Execute Stage signal E_Op1: unsigned (31 downto 0); -- First operand for ALU signal E_Op2: unsigned (31 downto 0); -- Second operand for ALU (with D_S) signal E_alu_op: alu_op; -- alu operation for this instruction signal E_Result: unsigned (31 downto 0); -- Second operand for ALU (with D_S) signal E_T: unsigned (31 downto 0); -- register contents for (for store) signal E_Rd: unsigned (4 downto 0); -- address of register to write back signal E_write_reg: boolean; -- write back will occur signal E_write_mem: boolean; -- store (write to memory) will occur signal E_read_mem: boolean; -- read from memory will occur -- Memory Stage signal M_Result: unsigned (31 downto 0); -- ALU Result signal M_T: unsigned (31 downto 0); -- register contents for (for store) signal M_Rd: unsigned (4 downto 0); -- address of register to write back signal M_write_reg: boolean; -- write back will occur signal M_write_mem: boolean; -- store (write to memory) will occur signal M_read_mem: boolean; -- read from memory will occur -- Write Back Stage signal W_D: unsigned (31 downto 0); -- Second operand for ALU (with D_S) signal W_Rd: unsigned (4 downto 0); -- address of register to write back signal W_write_reg: boolean; -- write back will occur begin -- Fetch Stage inst_address <= std_logic_vector(F_PC); process (clk, reset) begin if reset = '1' then F_PC <= X"00000000"; -- start executing instructions at address 0 D_PC <= X"00000004"; -- normally P_PC + 4 D_IR <= X"00000000"; -- instruction register elsif rising_edge(clk) and not D_stall then D_IR <= X"00000000"; -- no-op instruction in case of jump/branch D_PC <= F_PC + 4; -- pc transferred to decode stage for branch & jump case D_pc_select is when pc_next => F_PC <= F_PC+4; D_IR <= unsigned(inst_in); when pc_jump => F_PC <= D_PC(31 downto 28) & D_IR(25 downto 0) & "00"; when pc_branch => F_PC <= D_PC + (D_imm(29 downto 0) & "00"); when pc_jreg => F_PC <= D_T; end case; end if; end process; -- Decode Stage D_Rs <= D_IR(25 downto 21); D_Rt <= D_IR(20 downto 16); D_S <= X"00000000" when D_Rs = "00000" else -- register 0 is always 0 W_D when D_Rs = W_Rd and W_write_reg else -- write-through reg_file(to_integer(D_Rs)); -- register S D_T <= X"00000000" when D_Rt = "00000" else -- register 0 is always 0 W_D when D_Rt = W_Rd and W_write_reg else -- write-through reg_file(to_integer(D_Rt)); -- register T D_imm <= unsigned(resize(signed(D_IR(15 downto 0)), 32)); -- sign extend process (D_IR, D_S, D_T, D_Imm) begin D_Op2 <= D_imm; -- assume I format (or J) D_Rd <= D_IR(20 downto 16); -- assume I format (or J) D_pc_select <= pc_next; -- assume no jump D_alu_op <= alu_add; -- assume alu op is add D_write_reg <= false; D_write_mem <= false; D_read_mem <= false; D_stall_for_S <= true; -- indicates dependency on S will stall the processor D_stall_for_T <= false; -- indicates dependency on T will stall the processor case D_IR(31 downto 26) is when "000010" => D_pc_select <= pc_jump; D_stall_for_S <= false; -- j when "000100" => D_stall_for_T <= true; if D_S = D_T then D_pc_select <= pc_branch; end if; -- beq when "000101" => D_stall_for_T <= true; if D_S /= D_T then D_pc_select <= pc_branch; end if; -- bne when "001000" => D_write_reg <= true; D_alu_op <= alu_add; -- addi when "001100" => D_write_reg <= true; D_alu_op <= alu_and; -- andi when "001101" => D_write_reg <= true; D_alu_op <= alu_or; -- ori when "100011" => D_write_reg <= true; D_read_mem <= true; -- lw when "101011" => D_write_mem <= true; D_stall_for_T <= true; -- sw when "000000" => D_Op2 <= D_T; -- R format, use Rt for source D_Rd <= D_IR(15 downto 11); -- R format, use Rd for dest D_write_reg <= true; D_stall_for_T <= true; case D_IR(5 downto 0) is when "001000" => D_pc_select <= pc_jreg; -- jr when "100000" => D_alu_op <= alu_add; -- sub when "100010" => D_alu_op <= alu_sub; -- sub when "100100" => D_alu_op <= alu_and; -- and when "100101" => D_alu_op <= alu_or; -- or when others => null; end case; when others => D_stall_for_S <= false; end case; end process; D_stall <= (D_stall_for_S and E_write_reg and D_Rs = E_Rd) OR (D_stall_for_S and M_write_reg and D_Rs = M_Rd) OR (D_stall_for_T and E_write_reg and D_Rt = E_Rd) OR (D_stall_for_T and M_write_reg and D_Rt = M_Rd); process (clk, reset) begin if reset = '1' then E_read_mem <= false; E_write_mem <= false; E_write_reg <= false; elsif rising_edge(clk) then E_T <= D_T; -- for store instruction E_Op1 <= D_S; E_Op2 <= D_Op2; E_Rd <= D_Rd; E_alu_op <= D_alu_op; if D_stall then E_read_mem <= false; E_write_mem <= false; E_write_reg <= false; else E_read_mem <= D_read_mem; E_write_mem <= D_write_mem; E_write_reg <= D_write_reg and D_Rd /= "00000"; end if; end if; end process; -- Execute Stage E_result <= E_Op1 + E_Op2 when E_alu_op = alu_add else -- add E_Op1 - E_Op2 when E_alu_op = alu_sub else -- subtract E_Op1 and E_Op2 when E_alu_op = alu_and else -- and E_Op1 or E_Op2; -- or process (clk, reset) begin if reset = '1' then M_read_mem <= false; M_write_mem <= false; M_write_reg <= false; elsif rising_edge(clk) then M_read_mem <= E_read_mem; M_write_mem <= E_write_mem; M_write_reg <= E_write_reg; M_T <= E_T; -- for store instruction M_result <= E_result; M_Rd <= E_Rd; end if; end process; -- Memory Stage data_out <= std_logic_vector(M_T); data_address <= std_logic_vector(M_result); data_write_enable <= '1' when M_write_mem else '0'; process (clk, reset) begin if reset = '1' then W_write_reg <= false; elsif rising_edge(clk) then W_write_reg <= M_write_reg; W_Rd <= M_Rd; if M_read_mem then W_D <= unsigned(data_in); else W_D <= M_result; end if; end if; end process; -- write back stage process (clk) begin if rising_edge(clk) and W_write_reg then reg_file(to_integer(W_Rd)) <= W_D; end if; end process; end Behavioral;