OpenCores
URL https://opencores.org/ocsvn/potato/potato/trunk

Subversion Repositories potato

[/] [potato/] [trunk/] [src/] [pp_control_unit.vhd] - Rev 21

Go to most recent revision | Compare with Previous | Blame | View Log

-- The Potato Processor - A simple processor for FPGAs
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
-- Report bugs and issues on <http://opencores.org/project,potato,bugtracker>
 
library ieee;
use ieee.std_logic_1164.all;
 
use work.pp_constants.all;
use work.pp_csr.all;
use work.pp_types.all;
use work.pp_utilities.all;
 
--! @brief Unit decoding instructions and setting control signals apropriately.
entity pp_control_unit is
	port(
		-- Inputs, indices correspond to instruction word indices:
		opcode  : in std_logic_vector( 4 downto 0);
		funct3  : in std_logic_vector( 2 downto 0);
		funct7  : in std_logic_vector( 6 downto 0);
		funct12 : in std_logic_vectoR(11 downto 0);
 
		-- Control signals:
		rd_write            : out std_logic;
		branch              : out branch_type;
 
		-- Exception signals:
		decode_exception       : out std_logic;
		decode_exception_cause : out std_logic_vector(4 downto 0);
 
		-- Control register signals:
		csr_write : out csr_write_mode;
		csr_imm   : out std_logic; --! Indicating an immediate variant of the csrr* instructions.
 
		-- Sources of operands to the ALU:
		alu_x_src, alu_y_src : out alu_operand_source;
 
		-- ALU operation:
		alu_op : out alu_operation;
 
		-- Memory transaction parameters:
		mem_op   : out memory_operation_type;
		mem_size : out memory_operation_size
	);
end entity pp_control_unit;
 
architecture behaviour of pp_control_unit is
	signal exception       : std_logic;
	signal exception_cause : std_logic_vector(4 downto 0);
	signal alu_op_temp     : alu_operation;
begin
 
	csr_imm <= funct3(2);
	alu_op <= alu_op_temp;
 
	decode_exception <= exception or to_std_logic(alu_op_temp = ALU_INVALID);
	decode_exception_cause <= exception_cause when alu_op_temp /= ALU_INVALID
		else CSR_CAUSE_INVALID_INSTR;
 
	alu_control: entity work.pp_alu_control_unit
		port map(
			opcode => opcode,
			funct3 => funct3,
			funct7 => funct7,
			alu_x_src => alu_x_src,
			alu_y_src => alu_y_src,
			alu_op => alu_op_temp
		);
 
	decode_ctrl: process(opcode, funct3, funct12)
	begin
		case opcode is
			when b"01101" => -- Load upper immediate
				rd_write <= '1';
				exception <= '0';
				exception_cause <= CSR_CAUSE_NONE;
				branch <= BRANCH_NONE;
			when b"00101" => -- Add upper immediate to PC
				rd_write <= '1';
				exception <= '0';
				exception_cause <= CSR_CAUSE_NONE;
				branch <= BRANCH_NONE;
			when b"11011" => -- Jump and link
				rd_write <= '1';
				exception <= '0';
				exception_cause <= CSR_CAUSE_NONE;
				branch <= BRANCH_JUMP;
			when b"11001" => -- Jump and link register
				rd_write <= '1';
				exception <= '0';
				exception_cause <= CSR_CAUSE_NONE;
				branch <= BRANCH_JUMP_INDIRECT;
			when b"11000" => -- Branch operations
				rd_write <= '0';
				exception <= '0';
				exception_cause <= CSR_CAUSE_NONE;
				branch <= BRANCH_CONDITIONAL;
			when b"00000" => -- Load instructions
				rd_write <= '1';
				exception <= '0';
				exception_cause <= CSR_CAUSE_NONE;
				branch <= BRANCH_NONE;
			when b"01000" => -- Store instructions
				rd_write <= '0';
				exception <= '0';
				exception_cause <= CSR_CAUSE_NONE;
				branch <= BRANCH_NONE;
			when b"00100" => -- Register-immediate operations
				rd_write <= '1';
				exception <= '0';
				exception_cause <= CSR_CAUSE_NONE;
				branch <= BRANCH_NONE;
			when b"01100" => -- Register-register operations
				rd_write <= '1';
				exception <= '0';
				exception_cause <= CSR_CAUSE_NONE;
				branch <= BRANCH_NONE;
			when b"00011" => -- Fence instructions, ignored
				rd_write <= '0';
				exception <= '0';
				exception_cause <= CSR_CAUSE_NONE;
				branch <= BRANCH_NONE;
			when b"11100" => -- System instructions
				if funct3 = b"000" then
					rd_write <= '0';
 
					if funct12 = x"000" then
						exception <= '1';
						exception_cause <= CSR_CAUSE_SYSCALL;
						branch <= BRANCH_NONE;
					elsif funct12 = x"001" then
						exception <= '1';
						exception_cause <= CSR_CAUSE_BREAKPOINT;
						branch <= BRANCH_NONE;
					elsif funct12 = x"800" then
						exception <= '0';
						exception_cause <= CSR_CAUSE_NONE;
						branch <= BRANCH_SRET;
					else
						exception <= '1';
						exception_cause <= CSR_CAUSE_INVALID_INSTR;
						branch <= BRANCH_NONE;
					end if;
				else
					rd_write <= '1';
					exception <= '0';
					exception_cause <= CSR_CAUSE_NONE;
					branch <= BRANCH_NONE;
				end if;
			when others =>
				rd_write <= '0';
				exception <= '1';
				exception_cause <= CSR_CAUSE_INVALID_INSTR;
				branch <= BRANCH_NONE;
		end case;
	end process decode_ctrl;
 
	decode_csr: process(opcode, funct3)
	begin
		if opcode = b"11100" then
			case funct3 is
				when b"001" | b"101" => -- csrrw/i
					csr_write <= CSR_WRITE_REPLACE;
				when b"010" | b"110" => -- csrrs/i
					csr_write <= CSR_WRITE_SET;
				when b"011" | b"111" => -- csrrc/i
					csr_write <= CSR_WRITE_CLEAR;
				when others =>
					csr_write <= CSR_WRITE_NONE;
			end case;
		else
			csr_write <= CSR_WRITE_NONE;
		end if;
	end process decode_csr;
 
	decode_mem: process(opcode, funct3)
	begin
		case opcode is
			when b"00000" => -- Load instructions
				case funct3 is
					when b"000" => -- lw
						mem_size <= MEMOP_SIZE_BYTE;
						mem_op <= MEMOP_TYPE_LOAD;
					when b"001" => -- lh
						mem_size <= MEMOP_SIZE_HALFWORD;
						mem_op <= MEMOP_TYPE_LOAD;
					when b"010" | b"110" => -- lw
						mem_size <= MEMOP_SIZE_WORD;
						mem_op <= MEMOP_TYPE_LOAD;
					when b"100" => -- lbu
						mem_size <= MEMOP_SIZE_BYTE;
						mem_op <= MEMOP_TYPE_LOAD_UNSIGNED;
					when b"101" => -- lhu
						mem_size <= MEMOP_SIZE_HALFWORD;
						mem_op <= MEMOP_TYPE_LOAD_UNSIGNED;
					when others => -- FIXME: Treat others as lw.
						mem_size <= MEMOP_SIZE_WORD;
						mem_op <= MEMOP_TYPE_INVALID;
				end case;
			when b"01000" => -- Store instructions
				case funct3 is
					when b"000" =>
						mem_op <= MEMOP_TYPE_STORE;
						mem_size <= MEMOP_SIZE_BYTE;
					when b"001" =>
						mem_op <= MEMOP_TYPE_STORE;
						mem_size <= MEMOP_SIZE_HALFWORD;
					when b"010" =>
						mem_op <= MEMOP_TYPE_STORE;
						mem_size <= MEMOP_SIZE_WORD;
					when others =>
						mem_op <= MEMOP_TYPE_INVALID;
						mem_size <= MEMOP_SIZE_WORD;
				end case;
			when others =>
				mem_op <= MEMOP_TYPE_NONE;
				mem_size <= MEMOP_SIZE_WORD;
		end case;
	end process decode_mem;
 
end architecture behaviour;
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.