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

Subversion Repositories c16

[/] [c16/] [trunk/] [vhdl/] [alu8.vhd] - Rev 31

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

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
 
--  Uncomment the following lines to use the declarations that are
--  provided for instantiating Xilinx primitive components.
--library UNISIM;
--use UNISIM.VComponents.all;
 
use work.cpu_pack.ALL;
 
entity alu8 is
	PORT(	CLK_I : in   std_logic;
			T2    : in   std_logic;
			CLR   : in   std_logic;
			CE    : in   std_logic;
 
			ALU_OP : in  std_logic_vector( 4 downto 0);
			XX     : in  std_logic_vector(15 downto 0);
			YY     : in  std_logic_vector(15 downto 0);
 
			ZZ     : out std_logic_vector(15 downto 0)
		);
end alu8;
 
architecture Behavioral of alu8 is
 
 
	function sh_mask(Y    : unsigned(3 downto 0);
					 YMAX : unsigned(3 downto 0);
	                 LR   : std_logic;
	                 FILL : std_logic;
					 X    : std_logic) return std_logic is
 
	begin
		if (YMAX >= Y) then									-- Y small
			if (LR = '1') then		return	X;			-- LSL
			else					return	FILL;		-- LSR
			end if;
		else												-- Y big
			if (LR = '1') then		return	FILL;		-- LSL
			else					return	X;			-- ASR/LSR
			end if;
		end if;
	end;
 
	function b8(A : std_logic) return std_logic_vector is
	begin
		return A & A & A & A & A & A & A & A;
	end;
 
	function b16(A : std_logic) return std_logic_vector is
	begin
		return b8(A) & b8(A);
	end;
 
	function aoxn(A : std_logic_vector(3 downto 0)) return std_logic is
	begin
		case A is
			-- and
			when "0000" =>	return '0';
			when "0001" =>	return '0';
			when "0010" =>	return '0';
			when "0011" =>	return '1';
			-- or
			when "0100" =>	return '0';
			when "0101" =>	return '1';
			when "0110" =>	return '1';
			when "0111" =>	return '1';
			-- xor
			when "1000" =>	return '0';
			when "1001" =>	return '1';
			when "1010" =>	return '1';
			when "1011" =>	return '0';
			-- not Y
			when "1100" =>	return '1';
			when "1101" =>	return '0';
			when "1110" =>	return '1';
			when others =>	return '0';
		end case;
	end;
 
	signal MD_OR     : std_logic_vector(15 downto 0);		-- Multiplicator/Divisor
	signal PROD_REM  : std_logic_vector(31 downto 0);
	signal MD_OP     : std_logic;						-- operation D/M, S/U
	signal QP_NEG    : std_logic;						-- product / quotient negative
	signal RM_NEG    : std_logic;						-- remainder negative
 
begin
 
	alumux: process(ALU_OP, MD_OP, XX, YY, QP_NEG, RM_NEG, PROD_REM)
 
		variable MASKED_X : std_logic_vector(15 downto 0);
		variable SCNT     : unsigned(3 downto 0);
		variable SFILL    : std_logic;
		variable ROL1     : std_logic_vector(15 downto 0);
		variable ROL2     : std_logic_vector(15 downto 0);
		variable ROL4     : std_logic_vector(15 downto 0);
		variable ROL8     : std_logic_vector(15 downto 0);
		variable X_GE_Y	  : std_logic;	-- signed   X >=  Y
		variable X_HS_Y	  : std_logic;	-- unsigned X >=  Y
		variable X_HSGE_Y : std_logic;	-- any      X >=  Y
		variable X_EQ_Y	  : std_logic;	-- signed   X ==  Y
		variable X_CMP_Y  : std_logic;
 
	begin
		MASKED_X := XX and b16(ALU_OP(0));
		SFILL    := ALU_OP(0) and XX(15);
 
		if (ALU_OP(1) = '1') then	-- LSL
			SCNT := UNSIGNED(YY(3 downto 0));
		else						-- LSR / ASR
			SCNT := "0000" - UNSIGNED(YY(3 downto 0));
		end if;
 
		if (SCNT(0) = '0') then	ROL1 := XX;
		else					ROL1 := XX(14 downto 0) & XX(15);
		end if;
 
		if (SCNT(1) = '0') then	ROL2 := ROL1;
		else					ROL2 := ROL1(13 downto 0) & ROL1(15 downto 14);
		end if;
 
		if (SCNT(2) = '0') then	ROL4 := ROL2;
		else					ROL4 := ROL2(11 downto 0) & ROL2(15 downto 12);
		end if;
 
		if (SCNT(3) = '0') then	ROL8 := ROL4;
		else					ROL8 := ROL4(7 downto 0) & ROL4(15 downto 8);
		end if;
 
		if (XX = YY) then		X_EQ_Y := '1';
		else					X_EQ_Y := '0';
		end if;
 
		if (UNSIGNED(XX) >= UNSIGNED(YY)) then		X_HSGE_Y := '1';
		else										X_HSGE_Y := '0';
		end if;
 
		if (XX(15) /= YY(15)) then		-- different sign/high bit
			X_HS_Y := XX(15);		-- X ia bigger iff high bit set
			X_GE_Y := YY(15);		-- X is bigger iff Y negative
		else							-- same sign/high bit: GE == HS
			X_HS_Y := X_HSGE_Y;
			X_GE_Y := X_HSGE_Y;
		end if;
 
		case ALU_OP is
			when	ALU_X_HS_Y	=>	X_CMP_Y :=      X_HS_Y;
			when	ALU_X_LO_Y	=>	X_CMP_Y := not  X_HS_Y;
			when	ALU_X_HI_Y	=>	X_CMP_Y :=      X_HS_Y and not X_EQ_Y;
			when	ALU_X_LS_Y	=>	X_CMP_Y := not (X_HS_Y and not X_EQ_Y);
			when	ALU_X_GE_Y	=>	X_CMP_Y :=      X_GE_Y;
			when	ALU_X_LT_Y	=>	X_CMP_Y := not  X_GE_Y;
			when	ALU_X_GT_Y	=>	X_CMP_Y :=      X_GE_Y and not X_EQ_Y;
			when	ALU_X_LE_Y	=>	X_CMP_Y := not (X_GE_Y and not X_EQ_Y);
			when	ALU_X_EQ_Y	=>	X_CMP_Y :=      X_EQ_Y;
			when	others		=>	X_CMP_Y := not  X_EQ_Y;
		end case;
 
		ZZ <= X"0000";
 
		case ALU_OP is
			when	ALU_X_HS_Y | ALU_X_LO_Y | ALU_X_HI_Y | ALU_X_LS_Y |
					ALU_X_GE_Y | ALU_X_LT_Y | ALU_X_GT_Y | ALU_X_LE_Y |
					ALU_X_EQ_Y | ALU_X_NE_Y =>
				ZZ  <= b16(X_CMP_Y);
 
			when 	ALU_NEG_Y |	ALU_X_SUB_Y =>
				ZZ  <= MASKED_X - YY;
 
			when	ALU_MOVE_Y | ALU_X_ADD_Y =>
				ZZ  <= MASKED_X + YY;
 
			when 	ALU_X_AND_Y | ALU_X_OR_Y  | ALU_X_XOR_Y | ALU_NOT_Y =>
				for i in 0 to 15 loop
					ZZ(i) <= aoxn(ALU_OP(1 downto 0) & XX(i) & YY(i));
				end loop;
 
			when	ALU_X_LSR_Y | ALU_X_ASR_Y | ALU_X_LSL_Y =>
				for i in 0 to 15 loop
					ZZ(i) <= sh_mask(SCNT, CONV_UNSIGNED(i, 4),
									 ALU_OP(1), SFILL, ROL8(i));
				end loop;
 
			when	ALU_X_MIX_Y =>
					ZZ(15 downto 8) <= YY(7 downto 0);
					ZZ( 7 downto 0) <= XX(7 downto 0);
 
			when	ALU_MUL_IU | ALU_MUL_IS |
					ALU_DIV_IU | ALU_DIV_IS | ALU_MD_STP =>	-- mult/div ini/step
					ZZ <= PROD_REM(15 downto 0);
 
			when	ALU_MD_FIN =>	-- mult/div
				if (QP_NEG = '0') then	ZZ <= PROD_REM(15 downto 0);
				else					ZZ <= X"0000" - PROD_REM(15 downto 0);
				end if;
 
			when	others =>	-- modulo
				if (RM_NEG = '0') then	ZZ <= PROD_REM(31 downto 16);
				else					ZZ <= X"0000" - PROD_REM(31 downto 16);
				end if;
		end case;
	end process;
 
	muldiv: process(CLK_I)
 
		variable POS_YY : std_logic_vector(15 downto 0);
		variable POS_XX : std_logic_vector(15 downto 0);
		variable DIFF   : std_logic_vector(16 downto 0);
		variable SUM    : std_logic_vector(16 downto 0);
 
	begin
		if (rising_edge(CLK_I)) then
			if (T2 = '1') then
				if (CLR = '1') then
					PROD_REM <= X"00000000";	-- product/remainder
					MD_OR    <= X"0000";		-- multiplicator/divisor
					MD_OP    <= '0';			-- mult(0)/div(1)
					QP_NEG   <= '0';			-- quotient/product negative
					RM_NEG   <= '0';			-- remainder negative
				elsif (CE = '1') then
					SUM  := ('0' & PROD_REM(31 downto 16)) + ('0' & MD_OR);
					DIFF := ('0' & PROD_REM(30 downto 15)) - ('0' & MD_OR);
 
					if (XX(15) = '0') then	POS_XX := XX;
					else					POS_XX := X"0000" - XX;
					end if;
 
					if (YY(15) = '0') then	POS_YY := YY;
					else					POS_YY := X"0000" - YY;
					end if;
 
					case  ALU_OP is
						when	ALU_MUL_IU | ALU_MUL_IS | ALU_DIV_IU | ALU_DIV_IS =>
							MD_OP    <= ALU_OP(1);		-- div / mult
							MD_OR    <= POS_YY;		-- multiplicator/divisor
							QP_NEG   <= ALU_OP(0) and (XX(15) xor YY(15));
							RM_NEG   <= ALU_OP(0) and  XX(15);
							PROD_REM <= X"0000" & POS_XX;
 
						when	ALU_MD_STP =>
							if (MD_OP = '0') then		-- multiplication step
 
								PROD_REM(15 downto 0) <= PROD_REM(16 downto 1);
								if (PROD_REM(0) = '0') then
										PROD_REM(31 downto 15) <=
										'0' & PROD_REM(31 downto 16);
								else
									PROD_REM(31 downto 15) <= SUM;
								end if;
							else						-- division step
								if (DIFF(16) = '1') then	-- carry: small remainder
									PROD_REM(31 downto 16) <= PROD_REM(30 downto 15);
								else
									PROD_REM(31 downto 16) <= DIFF(15 downto 0);
								end if;
 
								PROD_REM(15 downto 1) <= PROD_REM(14 downto 0);
								PROD_REM(0) <= not DIFF(16);
							end if;
 
						when	others =>
					end case;
				end if;
			end if;
		end if;
	end process;
 
end Behavioral;
 

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.