-- Simple single cycle implementation of a CPU -- -- Subset of 32 bits PowerPC architecture. -- -- Supported instructions: -- -- add rD,rA,rB library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; entity simple_cpu is port ( clk : in std_logic; -- Main clock rst : in std_logic; -- Reset -- Interface to instruction memory (combinatory) -- for now, a 8 bits address 32 bits data interface -- that supports up to 256 instructions imem_addr : out std_logic_vector(7 downto 0); imem_data : in std_logic_vector(31 downto 0) ); end simple_cpu; architecture behaviour of simple_cpu is signal pc : std_logic_vector(7 downto 0); signal next_pc : std_logic_vector(7 downto 0); signal insn : std_logic_vector(31 downto 0); signal rA : std_logic_vector(4 downto 0); signal rB : std_logic_vector(4 downto 0); signal rD : std_logic_vector(4 downto 0); signal rWr : std_logic; type regfile_type is array(0 to 31) of std_logic_vector(31 downto 0); signal regfile : regfile_type; type right_ttype is (RIGHT_ZERO, RIGHT_SIMM, RIGHT_UIMM, RIGHT_IMM_UP, RIGHT_REG); signal right_type : right_ttype; signal left_sp_zero : std_logic; type alu_op_type is (ALU_NONE, ALU_ADD); signal alu_op : alu_op_type; signal alu_out : std_logic_vector(31 downto 0); signal alu_left : std_logic_vector(31 downto 0); signal alu_right : std_logic_vector(31 downto 0); type reg_src_type is (SRC_NONE, SRC_ALU); signal reg_src : reg_src_type; begin -- Program counter: simple adder for now pc_step : process(clk,rst) begin if rst = '1' then pc <= (others => '1'); elsif rising_edge(clk) then pc <= next_pc; insn <= imem_data; end if; end process; next_pc <= (others => '0') when rst = '1' else pc + 1; imem_addr <= next_pc; -- Register file write handling registers : process(clk) begin if rst = '1' then regfile <= (others => (others => '0')); elsif rising_edge(clk) and rWr = '1' then -- XX case and handle NONE ? assert on NONE & rWr ? if reg_src = SRC_ALU then regfile(conv_integer(rD)) <= alu_out; end if; end if; end process; -- ALU left and right member alu_args: process(clk, left_sp_zero, right_type) begin case right_type is when RIGHT_ZERO => alu_right <= (others => '0'); when RIGHT_SIMM => alu_right(15 downto 0) <= insn(15 downto 0); if (insn(15) = '1') then alu_right(31 downto 16) <= (others => '1'); else alu_right(31 downto 16) <= (others => '0'); end if; when RIGHT_UIMM => alu_right(15 downto 0) <= insn(15 downto 0); alu_right(31 downto 16) <= (others => '0'); when RIGHT_IMM_UP => -- no need to split sign extend from -- unsigned on 32 bits impl. alu_right(31 downto 16) <= insn(15 downto 0); alu_right(15 downto 0) <= (others => '0'); when RIGHT_REG => alu_right <= regfile(conv_integer(rB)); end case; if left_sp_zero = '1' and rA = "00000" then alu_left <= (others => '0'); else alu_left <= regfile(conv_integer(rA)); end if; end process; -- ALU ops alu : process(clk, alu_op, alu_left, alu_right) begin case alu_op is when ALU_NONE => alu_out <= (others => '0'); when ALU_ADD => alu_out <= alu_left + alu_right; end case; end process; -- Instruction decoding & Control logic rD <= insn(25 downto 21); rA <= insn(20 downto 16); rB <= insn(15 downto 11); decoder : process(clk, insn) begin rWr <= '0'; alu_op <= ALU_NONE; reg_src <= SRC_NONE; right_type <= RIGHT_ZERO; left_sp_zero <= '0'; case insn(31 downto 26) is when "001110" => -- 0xe is addi rWr <= '1'; alu_op <= ALU_ADD; reg_src <= SRC_ALU; right_type <= RIGHT_SIMM; left_sp_zero <= '1'; when "011111" => -- 0x1f extended opcodes -- addx (TODO: test 2 missing bits) if insn(9 downto 1) = "100001010" then rWr <= '1'; alu_op <= ALU_ADD; reg_src <= SRC_ALU; right_type <= RIGHT_REG; left_sp_zero <= '0'; end if; end case; end process; end behaviour;