diff options
Diffstat (limited to 'store/works/life/computer-organization-experiment/cpu.vhdl')
-rw-r--r-- | store/works/life/computer-organization-experiment/cpu.vhdl | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/store/works/life/computer-organization-experiment/cpu.vhdl b/store/works/life/computer-organization-experiment/cpu.vhdl new file mode 100644 index 0000000..7ca6d9e --- /dev/null +++ b/store/works/life/computer-organization-experiment/cpu.vhdl @@ -0,0 +1,476 @@ +library ieee; +use ieee.std_logic_1164.all; + +package cru is + subtype word is std_logic_vector(31 downto 0); + constant clock_time : time := 10 ns; +end package; + +library ieee; +use ieee.std_logic_1164.all; +use work.cru.all; + +entity generic_clock is + generic(delay, interval: time); + port(CLK: out std_logic); +end entity; + +architecture Behavioral of generic_clock is + signal V : std_logic := '1'; +begin + l: process is + begin + CLK <= '0'; + wait for delay; + loop + CLK <= V; + V <= not V; + wait for interval; + end loop; + end process; +end architecture; + +library ieee; +use ieee.std_logic_1164.all; +use work.cru.all; + +entity reg is + port ( + CLK: in std_logic; -- Rising edge -> Read; Falling edge -> Write. + WRITE: in std_logic; -- If 1 then at falling edge of clock, W will be written. + W_DATA: in word; -- The data to write. + R_DATA: out word -- The data to read. + ); +end entity; + +architecture Behavioral of reg is + signal V: word := X"00000000"; +begin + process(CLK) + begin + if rising_edge(CLK) then + R_DATA <= V; + end if; + if falling_edge(CLK) and WRITE = '1' then + V <= W_DATA; + end if; + end process; +end architecture; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.cru.all; + +entity register_file is + port ( + CLK: in std_logic; + WRITE: in std_logic; + R1, R2, W: in std_logic_vector(4 downto 0); + WD: in std_logic_vector(31 downto 0); + RD1, RD2: out std_logic_vector(31 downto 0) + ); +end entity; + +architecture Behavioral of register_file is + type reg_file_type is array (0 to 31) of word; + signal reg_file: reg_file_type := (others => X"00000000"); +begin + process (CLK) + begin + if rising_edge(CLK) then + RD1 <= reg_file(to_integer(unsigned(R1))); + RD2 <= reg_file(to_integer(unsigned(R2))); + end if; + if falling_edge(CLK) and WRITE = '1' then + reg_file(to_integer(unsigned(W))) <= WD; + end if; + end process; +end architecture; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.std_logic_unsigned.all; +use work.cru.all; + +entity alu is + port ( + A, B: in std_logic_vector(31 downto 0); + ALUC: in std_logic_vector(3 downto 0); + S: out std_logic_vector(31 downto 0); + Z: out std_logic + ); +end entity; + +architecture Behavioral of alu is +begin + S <= A + B when ALUC(2 downto 0) ?= B"000" + else A - B when ALUC(2 downto 0) ?= B"010" + else A and B when ALUC(2 downto 0) ?= B"100" + else A or B when ALUC(2 downto 0) ?= B"101" + else A xor B when ALUC(2 downto 0) ?= B"110" + else std_logic_vector(signed(A) sll 16) and X"FFFF0000" when ALUC(2 downto 0) ?= B"110" + else std_logic_vector(signed(A) sll to_integer(unsigned(B))) when ALUC ?= B"0011" + else std_logic_vector(signed(A) srl to_integer(unsigned(B))) when ALUC ?= B"1011" + else std_logic_vector(signed(A) sra to_integer(unsigned(B))) when ALUC ?= B"1111"; + Z <= S ?= X"00000000" after 10 ps; +end architecture; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.cru.all; + +entity ram is + port( + CLK: in std_logic; + R_DATA: out word; + W_DATA: in word; + ADDR: in word; + READ: in std_logic; + WRITE: in std_logic + ); +end entity; + +architecture Behavioral of ram is + type memory_type is array (0 to 16#30#) of word; + signal memory: memory_type := ( +/* + X"3c010000", + X"34240080", + X"20050004", + X"0c000018", + X"ac820000", + X"8c890000", + X"01244022", + X"20050003", + X"20a5ffff", + X"34a8ffff", + X"39085555", + X"2009ffff", + X"312affff", + X"01493025", + X"01494026", + X"01463824", + X"10a00001", + X"08000008", + X"2005ffff", + X"000543c0", + X"00084400", + X"00084403", + X"000843c2", + X"08000017", + X"00004020", + X"8c890000", + X"20840004", + X"01094020", + X"20a5ffff", + X"14a0fffb", + X"00081000", + X"03e00008", + X"000000A3", + X"00000027", + X"00000079", + X"00000115", +*/ + X"3C010000", + X"3421004C", + X"8C240000", + X"20210004", + X"8C250000", + X"20210004", + X"0C000009", + X"AC230000", + X"08000008", + X"20020010", + X"00001820", + X"30A60001", + X"10060001", + X"00641820", + X"00042040", + X"00052842", + X"2042FFFF", + X"1440FFF9", + X"03e00008", + X"0000C9AE", + X"0000F6E5", + others => (others => '0') + ); +begin + l: process(CLK) is + begin + if rising_edge(CLK) and READ = '1' then + r_data <= memory(to_integer(unsigned(ADDR)) / 4); + end if; + if falling_edge(CLK) and WRITE = '1' then + memory(to_integer(unsigned(ADDR)) / 4) <= w_data; + end if; + end process; +end architecture; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.std_logic_unsigned.all; +use work.cru.all; + +entity cpu is +end entity; + +architecture Behavioral of cpu is + signal pc_clk: std_logic := '0'; + signal reg_clk: std_logic := '0'; + signal mem_clk: std_logic := '0'; + + signal pc: word := X"00000000"; + signal pc_to_write: word; + + signal ins: word; + + signal mem_addr: word; + signal mem_r_data: word; + signal mem_w_data: word; + signal mem_read: std_logic := '0'; + signal mem_write: std_logic := '0'; + + signal WRITE_REG: std_logic := '0'; + signal R1: std_logic_vector(4 downto 0) := B"00000"; + signal R2: std_logic_vector(4 downto 0) := B"00000"; + signal W: std_logic_vector(4 downto 0) := B"00000"; + signal WD: std_logic_vector(31 downto 0) := X"00000000"; + signal RD1: std_logic_vector(31 downto 0) := X"00000000"; + signal RD2: std_logic_vector(31 downto 0) := X"00000000"; + + signal A: std_logic_vector(31 downto 0) := X"00000000"; + signal B: std_logic_vector(31 downto 0) := X"00000000"; + signal ALUC: std_logic_vector(3 downto 0) := B"0000"; + signal S: std_logic_vector(31 downto 0); + signal Z: std_logic; +begin + pc_clock: entity work.generic_clock + generic map (delay => 1 ps, interval => clock_time) + port map (CLK => pc_clk); + + mem_clock: entity work.generic_clock + generic map (delay => 1 ns, interval => clock_time / 2) + port map (CLK => mem_clk); + + reg_clock: entity work.generic_clock + generic map (delay => 2 ns, interval => clock_time) + port map (CLK => reg_clk); + + pc_reg: entity work.reg + port map ( + CLK => pc_clk, + WRITE => '1', + R_DATA => pc, + W_DATA => pc_to_write + ); + + reg_file: entity work.register_file + port map( + CLK => reg_clk, + WRITE => WRITE_REG, + R1 => R1, + R2 => R2, + W => W, + WD => WD, + RD1 => RD1, + RD2 => RD2 + ); + + alu: entity work.alu + port map( + A => A, + B => B, + ALUC => ALUC, + S => S, + Z => Z + ); + + ram: entity work.ram + port map ( + CLK => mem_clk, + r_data => mem_r_data, + w_data => mem_w_data, + addr => mem_addr, + READ => mem_read, + WRITE => mem_write + ); + + logic: process is + begin + wait until rising_edge(pc_clk); + + wait for 100 ps; + + mem_read <= '1'; + mem_addr <= pc; + pc_to_write <= pc + 4; + + wait for 1 ns; + + ins <= mem_r_data; + + wait for 100 ps; + + if ins(31 downto 27) = B"00001" then -- j / jal, not read reg + R1 <= (others => '0'); + R2 <= (others => '0'); + elsif ins(31 downto 26) = B"000000" then + if ins(5) = '1' then + R1 <= ins(25 downto 21); + R2 <= ins(20 downto 16); + elsif ins(3) = '0' then + R1 <= ins(20 downto 16); + R2 <= (others => '0'); + else + R1 <= ins(25 downto 21); + R2 <= (others => '0'); + end if; + else + if ins(31) = '1' then + R1 <= ins(25 downto 21); + R2 <= ins(20 downto 16); + elsif ins(29 downto 26) = B"1111" then + R1 <= (others => '0'); + R2 <= (others => '0'); + elsif ins(29) = '1' then + R1 <= ins(25 downto 21); + R2 <= (others => '0'); + else + R1 <= ins(25 downto 21); + R2 <= ins(20 downto 16); + end if; + end if; + + wait for 1 ns; + + if ins(31 downto 27) = B"00001" then -- j / jal, not read reg + + ALUC <= B"0011"; + A <= (25 downto 0 => ins(25 downto 0), others => '0'); + B <= X"00000002"; + elsif ins(31 downto 26) = B"000000" then + if ins(5) = '1' then + ALUC <= ins(3 downto 0); + A <= RD1; + B <= RD2; + elsif ins(3) = '0' then + ALUC(3 downto 2) <= ins(1 downto 0); + ALUC(1 downto 0) <= B"11"; + A <= RD1; + B <= (4 downto 0 => ins(10 downto 6), others => '0'); + else + ALUC <= (others => '0'); + A <= (others => '0'); + B <= (others => '0'); + end if; + else + if ins(31) = '1' then + ALUC <= B"0000"; + A <= RD1; + B <= (15 downto 0 => ins(15 downto 0), others => '0' ); + elsif ins(29 downto 26) = B"1111" then + ALUC <= (others => '0'); + A <= (others => '0'); + B <= (others => '0'); + elsif ins(29) = '1' then + ALUC <= ins(29 downto 26); + A <= RD1; + B(15 downto 0) <= ins(15 downto 0); + if ins(15) = '0' then + B(31 downto 16) <= X"0000"; + else + B(31 downto 16) <= X"FFFF"; + end if; + else + ALUC <= B"0010"; + A <= RD1; + B <= RD2; + end if; + end if; + + wait for 100 ps; + + if ins(31 downto 27) = B"00001" then -- j / jal, not read reg + if ins(26) = '1' then -- jal + W <= B"11111"; + WD <= pc + 4; + WRITE_REG <= '1'; + else + WRITE_REG <= '0'; + end if; + pc_to_write <= S; + elsif ins(31 downto 26) = B"000000" then + if ins(5) = '1' then + WRITE_REG <= '1'; + W <= ins(15 downto 11); + WD <= S; + elsif ins(3) = '0' then + WRITE_REG <= '1'; + W <= ins(15 downto 11); + WD <= S; + else + WRITE_REG <= '0'; + pc_to_write <= RD1; + end if; + else + if ins(31) = '1' then + if ins(29) = '1' then + R2 <= ins(20 downto 16); + mem_write <= '1'; + mem_addr <= S; + mem_w_data <= RD2; + + wait until falling_edge(mem_clk); + + wait for 100 ps; + + mem_write <= '0'; + + else + W <= ins(20 downto 16); + mem_read <= '1'; + mem_addr <= S; + + wait until rising_edge(mem_clk); + + wait for 100 ps; + + WD <= mem_r_data; + WRITE_REG <= '1'; + end if; + elsif ins(29 downto 26) = B"1111" then + WRITE_REG <= '1'; + W <= ins(20 downto 16); + WD(31 downto 16) <= ins(15 downto 0); + elsif ins(29) = '1' then + WRITE_REG <= '1'; + W <= ins(20 downto 16); + WD <= S; + else + WRITE_REG <= '0'; + if Z = '1' xor ins(26) = '1' then + pc_to_write <= pc_to_write + to_integer(signed(ins(15 downto 0)) * 4); + end if; + end if; + end if; + end process; +end architecture; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.std_logic_unsigned.all; +use work.cru.all; + +entity cpu_test_bench is +end entity; + +architecture Behavioral of cpu_test_bench is + signal CLK: std_logic; +begin + cpu : entity work.cpu; +end architecture; |