diff --git a/Hardware/components/datapath.vhd b/Hardware/components/datapath.vhd new file mode 100644 index 0000000000000000000000000000000000000000..290ccffa16126af4fb467fe2709ba49054dcd98d --- /dev/null +++ b/Hardware/components/datapath.vhd @@ -0,0 +1,271 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity datapath is + port ( + -------------------------------------------------- + -- external processor signals -------------------- + -------------------------------------------------- + + clock : in std_logic; + nR : in std_logic; + + -------------------------------------------------- + -- internal processor signals -------------------- + -------------------------------------------------- + + omnibus : inout std_logic_vector(15 downto 0); + + -- signals that are required by the register file + AX : in std_logic_vector(3 downto 0); + AY : in std_logic_vector(3 downto 0); + eAX15 : in std_logic; + regNWE : in std_logic; + + -- signals that are required by the ALU + opCoALU : in std_logic_vector(4 downto 0); + carry : inout std_logic; + imm4 : in std_logic_vector(3 downto 0); + DX : inout std_logic_vector(15 downto 0); + DY : inout std_logic_vector(15 downto 0); + + -- signals that are required by the C register + eC : in std_logic; + + -- signals that are required by buffers + eBuffDX : in std_logic; + eBuffALU : in std_logic + ); +end datapath; + +architecture arcDatapath of datapath is + type tyRF is array (15 downto 0) of std_logic_vector(15 downto 0); + + -- output signals of the AX15 logic: + -- from AX15 to ALU + signal outAX15 : std_logic_vector(3 downto 0); + + -- output singals of the ALU: + -- from ALU to ALU buffer or C register + signal outALU : std_logic_vector(15 downto 0); + signal outC : std_logic; +begin + AX15 : process (eAX15, AX) is + begin + if eAX15 = '1' then + outAX15 <= (others => '1'); + else + outAX15 <= AX; + end if; + end process AX15; + + registerFile : process (clock) is + variable RF : tyRF; + begin + if rising_edge(clock) then + if regNWE = '0' then + RF(to_integer(unsigned(outAX15))) := omnibus; + else + DX <= RF(to_integer(unsigned(outAX15))); + DY <= RF(to_integer(unsigned(AY))); + end if; + end if; + end process registerFile; + + ALU : process (opCoALU, imm4, DX, DY) is + -- auxiliary variable + variable vectorHelper : std_logic_vector(15 downto 0); + begin + -- reset auxiliary variable + vectorHelper := (others => '0'); + case opCoALU is + -- DY + when "00000" => + outALU <= DY; + + -- DX + DY + when "00001" => + outALU <= std_logic_vector(signed(DX) + signed(DY)); + + -- DX + DY + carry, carry update + when "00010" => + vectorHelper(0) := carry; + if (to_integer(signed(DX)) + to_integer(signed(DY)) + to_integer(signed(vectorHelper)) > 32767) then + outC <= '1'; + outALU <= std_logic_vector(to_signed(to_integer(signed(DX)) + + to_integer(signed(DY)) + + to_integer(signed(vectorHelper)) - 32767,16)); + else + outC <= '0'; + outALU <= std_logic_vector(signed(DX) + signed(DY) + signed(vectorHelper)); + end if; + + -- DX - DY + when "00011" => + outALU <= std_logic_vector(signed(DX)-signed(DY)); + + -- DX and DY + when "00100" => + outALU <= DX and DY; + + -- DX or DY + when "00101" => + outALU <= DX or DY; + + -- DX xor DY + when "00110" => + outALU <= DX xor DY; + + -- not DX + when "00111" => + outALU <= not DX; + + -- arithmetic shift left: DX << DY <3:0> + when "01000" => + outALU <= std_logic_vector(shift_left(signed(DX), to_integer(unsigned(DY(3 downto 0))))); + + -- logical shift right: DX >>> DY <3:0> + when "01001" => + outALU <= std_logic_vector(shift_right(unsigned(DX), to_integer(unsigned(DY(3 downto 0))))); + + -- DX >> DY <3:0> + when "01010" => + outALU <= std_logic_vector(shift_right(signed(DX), to_integer(unsigned(DY(3 downto 0))))); + + -- undefined + when "01011" => + outALU <= "UUUUUUUUUUUUUUUU"; + + -- DX << 1, outC: DX[15] + when "01100" => + outC <= DX(15); + outALU <= std_logic_vector(shift_left(signed(DX), 1)); + + -- DX >>> 1, outC: DX[0] + when "01101" => + outC <= DX(0); + outALU <= std_logic_vector(shift_right(unsigned(DX), 1)); + + -- DX >> 1, outC: DX[0] + when "01110" => + outC <= DX(0); + outALU <= std_logic_vector(shift_right(signed(DX), 1)); + + -- undefined + when "01111" => + outALU <= "UUUUUUUUUUUUUUUU"; + + -- DX, outC: (DX == DY) + when "10000" => + outALU <= DX; + if DX = DY then + outC <= '1'; + else + outC <= '0'; + end if; + + -- DX, outC: (DX != DY) + when "10001" => + outALU <= DX; + if DX = DY then + outC <= '0'; + else + outC <= '1'; + end if; + + -- DX, outC: (DX > DY) + when "10010" => + outALU <= DX; + if DX > DY then + outC <= '1'; + else + outC <= '0'; + end if; + + -- DX, outC: (DX < DY) + when "10011" => + outALU <= DX; + if DX < DY then + outC <= '1'; + else + outC <= '0'; + end if; + + -- IMM4 + when "10100" => + vectorHelper(3 downto 0) := imm4; + outALU <= vectorHelper; + + -- DX + IMM4 + when "10101" => + vectorHelper(3 downto 0) := imm4; + outALU <= std_logic_vector(signed(DX) + signed(vectorHelper)); + + -- DX - IMM4 + when "10110" => + vectorHelper(3 downto 0) := imm4; + outALU <= std_logic_vector(signed(DX) - signed(vectorHelper)); + + -- DX and IMM4 + when "10111" => + vectorHelper(3 downto 0) := imm4; + outALU <= DX and vectorHelper; + + -- DX << IMM4 + when "11000" => + outALU <= std_logic_vector(shift_left(signed(DX), to_integer(unsigned(imm4)))); + + -- DX >>> IMM4 + when "11001" => + outALU <= std_logic_vector(shift_right(unsigned(DX), to_integer(unsigned(imm4)))); + + -- set bit IMM4 in DX + when "11010" => + vectorHelper := DX; + vectorHelper(to_integer(unsigned(imm4))) := '1'; + outALU <= vectorHelper; + + -- clear bit IMM4 in DX + when "11011" => + vectorHelper := DX; + vectorHelper(to_integer(unsigned(imm4))) := '0'; + outALU <= vectorHelper; + + -- 111** = undefined + when others => + outALU <= "UUUUUUUUUUUUUUUU"; + end case; + end process ALU; + + buffALU : process (outALU, eBuffALU) is + begin + if eBuffALU = '1' then + omnibus <= outALU; + else + omnibus <= (others => 'Z'); + end if; + end process buffALU; + + buffDX : process (DX, eBuffDX) is + begin + if eBuffDX = '1' then + omnibus <= DX; + else + omnibus <= (others => 'Z'); + end if; + end process buffDX; + + C : process (clock, nR) is + begin + if nR = '0' then + carry <= '0'; + else + if rising_edge(clock) then + if eC = '1' then + carry <= outC; + end if; + end if; + end if; + end process C; +end arcDatapath; \ No newline at end of file