------------------------------------------------------------------------- -- Project: JCPU, a portable 8-bit RISC CPU written in VHDL -- This file: system test using Xilinx ML-402 -- Copyright (C) 2007 J. Ahrensfeld -- This library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License as published by the Free Software Foundation; either -- version 2.1 of the License, or (at your option) any later version. -- This library is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- Lesser General Public License for more details. -- You should have received a copy of the GNU Lesser General Public -- License along with this library; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- For questions and ideas, please contact the author at jens@jayfield.org ----------------------------------------------------------------------- LIBRARY ieee; use IEEE.STD_LOGIC_1164.ALL; USE ieee.numeric_std.ALL; use std.textio.all; -- Imports the standard textio package. Library UNISIM; use UNISIM.vcomponents.all; library work; use work.mips_types.all; --use work.fifo_ctrl_pkg.all; use work.sdram_config.all; use work.sdram_types.all; ENTITY mips_sys IS GENERIC ( sys_freq : integer := 100E6; ddr_phaseshift : integer := 0; ddr_frequency_hz : integer := 100E6 ); PORT ( sys_rst_n_in : in std_logic; sys_clk_in : in std_logic; -- Buttons and LEDs sys_btn : in unsigned(4 downto 0); sys_dip : in unsigned(7 downto 0); sys_led : out unsigned(8 downto 0); -- UART sys_rx : in std_logic; sys_tx : out std_logic; -- LCD sys_lcd_d : inout unsigned(3 downto 0); sys_lcd_e : out std_logic; sys_lcd_rs : out std_logic; sys_lcd_rw : out std_logic; -- DDR SDRAM sys_sdr_clk_p : out std_logic; -- ddr_sdram_clock sys_sdr_clk_n : out std_logic; -- /ddr_sdram_clock sys_sdr_cke_q : out std_logic; -- clock enable sys_sdr_cs_qn : out std_logic; -- /chip select sys_sdr_ras_qn : out std_logic; -- /ras sys_sdr_cas_qn : out std_logic; -- /cas sys_sdr_we_qn : out std_logic; -- /write enable sys_sdr_dm_q : out unsigned(DDR_DM_WIDTH-1 downto 0); -- data mask bits, set to "00" sys_sdr_dqs_q : inout unsigned(DDR_DQS_WIDTH-1 downto 0); -- data strobe, only for write sys_sdr_ba_q : out unsigned(DDR_BANK_WIDTH-1 downto 0); -- bank select sys_sdr_a_q : out unsigned(DDR_ADDR_WIDTH-1 downto 0); -- address bus sys_sdr_data : inout unsigned(DDR_DATA_WIDTH-1 downto 0); -- bidir data bus sys_sdr_clk_fb : in std_logic; -- VGA -- sys_vga_red : out unsigned(7 downto 0); -- sys_vga_green : out unsigned(7 downto 0); -- sys_vga_blue : out unsigned(7 downto 0); -- sys_vga_blank_n : out std_logic; -- sys_vga_sync_n : out std_logic; -- sys_vga_hsync : out std_logic; -- sys_vga_vsync : out std_logic; -- sys_vga_clk : out std_logic; sys_error : out unsigned(1 downto 0) -- indicates Errors ); -- attribute BUFFER_TYPE : string; -- attribute BUFFER_TYPE of sys_clk_in : signal is "BUFG"; -- attribute BUFFER_TYPE of sys_sdr_dcm_clk_fb : signal is "BUFG"; END mips_sys; ARCHITECTURE behavior OF mips_sys IS COMPONENT mips_top Port ( rst : in STD_LOGIC; clk : in STD_LOGIC; int : in unsigned(5 downto 0); mem_valid : in STD_LOGIC; mem_rdy : in STD_LOGIC; mem_re : out STD_LOGIC; mem_en : out STD_LOGIC; mem_we : out unsigned(3 downto 0); mem_din : in word_t; mem_dout : out word_t; mem_addr : out word_t ); END COMPONENT; signal int : unsigned(5 downto 0); signal mem_din : word_t; signal mem_dout : word_t; signal mem_addr : word_t; signal mem_re : std_logic; signal mem_en : std_logic; signal mem_we : unsigned(3 downto 0); signal mem_valid : std_logic; signal mem_rdy : std_logic; COMPONENT rom Port ( clk : in STD_LOGIC; ce : in STD_LOGIC; addr : in word_t; dout : out word_t ); END COMPONENT; signal rom_data : word_t; COMPONENT ram PORT ( clk : in STD_LOGIC; ce : in STD_LOGIC; we : in unsigned(3 downto 0); addr : in unsigned(31 downto 0); din : in unsigned(31 downto 0); dout : out unsigned(31 downto 0) ); END COMPONENT; signal ram_data : word_t; COMPONENT lcd_port PORT ( rst : in std_logic; clk : in std_logic; we : in std_logic; din : in unsigned(7 downto 0); dout : out unsigned(7 downto 0); lcd_d : inout unsigned(3 downto 0); lcd_e : out std_logic; lcd_rs : out std_logic; lcd_rw : out std_logic ); END COMPONENT; COMPONENT uart_tx Port ( data_in : in std_logic_vector(7 downto 0); write_buffer : in std_logic; reset_buffer : in std_logic; en_16_x_baud : in std_logic; serial_out : out std_logic; buffer_full : out std_logic; buffer_half_full : out std_logic; clk : in std_logic ); END COMPONENT; COMPONENT uart_rx Port ( serial_in : in std_logic; data_out : out std_logic_vector(7 downto 0); read_buffer : in std_logic; reset_buffer : in std_logic; en_16_x_baud : in std_logic; buffer_data_present : out std_logic; buffer_full : out std_logic; buffer_half_full : out std_logic; clk : in std_logic ); END COMPONENT; signal rst : std_logic; signal rst_in : std_logic; signal started_up : std_logic := '1'; signal clk : std_logic; signal led_reg : unsigned(7 downto 0); signal cpu_lcd_out_reg, cpu_lcd_in_reg, reg_uart_tx: unsigned(7 downto 0); signal cpu_lcd_we : std_logic; signal err_led_reg : unsigned(1 downto 0); signal btn_ps2_reg : unsigned(7 downto 0); -- Signals to form an timer generating an interrupt every microsecond subtype tick_usec_t is natural range 0 to 99; signal tick_usec : tick_usec_t; signal cnt_usec : word_t; signal cnt_sec : word_t; signal cnt_usec_preset : word_t; signal cnt_sec_preset : word_t; signal cnt_usec_en : std_logic; signal cnt_usec_we : std_logic; signal cnt_sec_en : std_logic; signal cnt_sec_we : std_logic; -- Signals for UART connections signal baud_count : unsigned(7 downto 0); signal en_16_x_baud : std_logic; signal reg_we_uart_tx : std_logic; signal tx_full : std_logic; signal tx_half_full : std_logic; signal reg_re_uart_rx : std_logic; signal reg_uart_rx : std_logic_vector(7 downto 0); signal rx_data_present : std_logic; signal rx_full : std_logic; signal rx_half_full : std_logic; signal uart_status_port : unsigned(7 downto 0); signal reg_uart_ctrl : unsigned(7 downto 0); signal reg_uart_baud : unsigned(7 downto 0); -- DDR SDRAM constant BURST_LEN : natural := 2; signal sdr_addr : user_addr_t; signal sdr_busy_q : std_logic; signal sdr_udata_in : unsigned(SDR_DATA_WIDTH-1 downto 0); signal sdr_udata_out_q : unsigned(SDR_DATA_WIDTH-1 downto 0); signal sdr_udata_vld_q : std_logic; signal sdr_be : unsigned(SDR_DM_WIDTH-1 downto 0) := "00000000"; signal sdr_read : std_logic; signal sdr_en : std_logic; signal reg_data : word_t; signal reg_data_vld : std_logic; signal reg_en : std_logic; signal rom_en : std_logic; signal rom_data_vld : std_logic; signal ram_en : std_logic; signal ram_data_vld : std_logic; signal sdram_en : std_logic; signal sd_counter : word_t; signal mem_re_r : std_logic; signal mem_we_r : unsigned(3 downto 0); signal mem_dout_r : word_t; signal mem_addr_r : word_t; -- attribute rom_style: string; -- attribute rom_style of cmd_fifo_dout: signal is "DISTRIBUTED"; -- attribute rom_style of cpu_cpu_write_fifo_dout: signal is "DISTRIBUTED"; -- attribute rom_style of cpu_read_fifo_dout: signal is "DISTRIBUTED"; BEGIN int <= "0000" & rx_data_present & btn_ps2_reg(4); rst_in <= not (started_up and sys_rst_n_in); en_mux: process(clk) begin if rising_edge(clk) then if rst = '1' then sdram_en <= '0'; else reg_en <= '0'; rom_en <= '0'; ram_en <= '0'; -- sdram_en <= '0'; if mem_en = '1' then mem_re_r <= mem_re; mem_we_r <= mem_we; mem_dout_r <= mem_dout; mem_addr_r <= mem_addr; if mem_addr(31 downto 28) = X"A" then reg_en <= '1'; elsif (mem_addr(31 downto 28) = X"B" and mem_addr(15) = '0') then rom_en <= '1'; elsif (mem_addr(31 downto 28) = X"B" and mem_addr(15) = '1') then ram_en <= '1'; elsif (mem_addr(31 downto 28) = X"8" or mem_addr(30) = '1') then sdram_en <= '1'; end if; elsif sdr_busy_q = '0' then sdram_en <= '0'; end if; end if; end if; end process; sdr_addr <= mem_addr_r(24 downto 2) & "0"; sdr_udata_in <= mem_dout_r & mem_dout_r; sdr_be <= mem_we_r & mem_we_r; sdr_read <= '1'; sdr_en <= sdram_en and not sdr_busy_q; ------------------------------------------------------------------ led_out: process(rst, clk) begin if rst = '1' then sys_led <= (others => '0'); sys_error <= (others => '0'); elsif rising_edge(clk) then sys_led <= not mem_rdy & led_reg; sys_error <= err_led_reg; end if; end process; ------------------------------------------------------------------ btn_ps2_register: process(clk) begin if rising_edge(clk) then btn_ps2_reg <= "000" & unsigned(sys_btn); end if; end process; proc_sd_counter: process(clk) begin if rising_edge(clk) then if rst = '1' then sd_counter <= (others => '0'); elsif sdr_udata_vld_q = '1' then sd_counter <= sd_counter + 1; end if; end if; end process; mem_valid <= sdr_udata_vld_q or reg_data_vld or rom_data_vld or ram_data_vld; mem_din <= reg_data when reg_data_vld = '1' else rom_data when rom_data_vld = '1' else ram_data when ram_data_vld = '1' else sdr_udata_out_q(mem_din'left downto mem_din'right); ------------------------------------------------------------------ inst_rom: rom PORT MAP ( clk => clk, ce => rom_en, addr => mem_addr_r, dout => rom_data ); inst_ram: ram PORT MAP ( clk => clk, ce => ram_en, we => mem_we_r, addr => mem_addr_r, din => mem_dout_r, dout => ram_data ); ram_read: process(clk) begin if rising_edge(clk) then ram_data_vld <= '0'; if ram_en = '1' and mem_re_r = '1' then ram_data_vld <= '1'; end if; end if; end process; rom_read: process(clk) begin if rising_edge(clk) then rom_data_vld <= '0'; if rom_en = '1' and mem_re_r = '1' then rom_data_vld <= '1'; end if; end if; end process; registers_read: process(clk) begin if rising_edge(clk) then reg_data_vld <= '0'; reg_re_uart_rx <= '0'; if reg_en = '1' and mem_re_r = '1' then reg_data_vld <= '1'; reg_data <= (others => '0'); case mem_addr_r(5 downto 2) is when "0000" => null; when "0001" => reg_re_uart_rx <= mem_re_r; reg_data(7 downto 0) <= unsigned(reg_uart_rx); when "0010" => reg_data(7 downto 0) <= uart_status_port; reg_data(15 downto 8) <= reg_uart_baud; reg_data(23 downto 16) <= btn_ps2_reg; reg_data(31 downto 24) <= cpu_lcd_in_reg; when "0100" => reg_data <= cnt_usec; when "0101" => reg_data <= cnt_sec; when others => null; end case; end if; end if; end process; ------------------------------------------------------------------ registers_write: process(clk) begin if rising_edge(clk) then cpu_lcd_we <= '0'; reg_we_uart_tx <= '0'; cnt_usec_we <= '0'; cnt_sec_we <= '0'; if rst = '1' then led_reg <= (others => '0'); err_led_reg <= (others => '0'); cpu_lcd_out_reg <= (others => '0'); reg_uart_baud <= to_unsigned(53, 8); reg_uart_ctrl <= to_unsigned(0, 8); elsif reg_en = '1' then case mem_addr_r(5 downto 2) is when "0000" => if mem_we_r(0) = '1' then led_reg(7 downto 0) <= mem_dout_r(7 downto 0); end if; if mem_we_r(3) = '1' then err_led_reg <= mem_dout_r(31 downto 30); end if; when "0001" => if mem_we_r(0) = '1' then reg_we_uart_tx <= '1'; reg_uart_tx <= mem_dout_r(7 downto 0); end if; when "0010" => if mem_we_r(0) = '1' then reg_uart_ctrl <= mem_dout_r(7 downto 0); end if; if mem_we_r(1) = '1' then reg_uart_baud <= mem_dout_r(15 downto 8); end if; if mem_we_r(3) = '1' then cpu_lcd_we <= '1'; cpu_lcd_out_reg <= mem_dout_r(31 downto 24); end if; when "0100" => if mem_we_r(3) = '1' then cnt_usec_we <= '1'; cnt_usec_preset <= mem_dout_r; end if; when "0101" => if mem_we_r(3) = '1' then cnt_sec_we <= '1'; cnt_sec_preset <= mem_dout_r; end if; when others => null; end case; end if; end if; end process; ------------------------------------------------------------------ mem_rdy <= not sdr_busy_q; ------------------------------------------------------------------ inst_mips_top: mips_top PORT MAP ( rst => rst, clk => clk, int => int, mem_valid => mem_valid, mem_rdy => mem_rdy, mem_en => mem_en, mem_re => mem_re, mem_we => mem_we, mem_din => mem_din, mem_dout => mem_dout, mem_addr => mem_addr ); inst_lcd_port: lcd_port PORT MAP ( rst => rst, clk => clk, we => cpu_lcd_we, din => cpu_lcd_out_reg, dout => cpu_lcd_in_reg, lcd_d => sys_lcd_d, lcd_e => sys_lcd_e, lcd_rs => sys_lcd_rs, lcd_rw => sys_lcd_rw ); inst_uart_tx: uart_tx port map ( data_in => std_logic_vector(reg_uart_tx), write_buffer => reg_we_uart_tx, reset_buffer => rst, en_16_x_baud => en_16_x_baud, serial_out => sys_tx, buffer_full => tx_full, buffer_half_full => tx_half_full, clk => clk ); inst_uart_rx: uart_rx port map ( serial_in => sys_rx, data_out => reg_uart_rx, read_buffer => reg_re_uart_rx, reset_buffer => rst, en_16_x_baud => en_16_x_baud, buffer_data_present => rx_data_present, buffer_full => rx_full, buffer_half_full => rx_half_full, clk => clk ); uart_status_port <= (7 downto 5 => '0') & rx_data_present & rx_full & rx_half_full & tx_full & tx_half_full; tick_usec_timer: process(clk) begin if clk'event and clk='1' then cnt_usec_en <= '0'; if rst = '1' then tick_usec <= 0; cnt_usec_en <= '0'; elsif tick_usec = tick_usec_t'high then tick_usec <= 0; cnt_usec_en <= '1'; else tick_usec <= tick_usec + 1; end if; end if; end process; cnt_usec_timer: process(clk) begin if clk'event and clk='1' then cnt_sec_en <= '0'; if rst = '1' then cnt_usec <= (others => '0'); cnt_sec_en <= '0'; elsif cnt_usec_we = '1' then cnt_usec <= cnt_usec_preset; elsif cnt_usec_en = '1' then if cnt_usec = to_unsigned(1E6 - 1, word_t'length) then cnt_usec <= (others => '0'); cnt_sec_en <= '1'; else cnt_usec <= cnt_usec + 1; end if; end if; end if; end process; cnt_sec_timer: process(clk) begin if clk'event and clk='1' then if rst = '1' then cnt_sec <= (others => '0'); elsif cnt_sec_we = '1' then cnt_sec <= cnt_sec_preset; elsif cnt_sec_en = '1' then cnt_sec <= cnt_sec + 1; end if; end if; end process; baud_timer: process(clk) begin if clk'event and clk='1' then if rst = '1' then baud_count <= (others => '0'); elsif baud_count = reg_uart_baud then baud_count <= (others => '0'); en_16_x_baud <= '1'; else baud_count <= baud_count + 1; en_16_x_baud <= '0'; end if; end if; end process; -- DDR SDRAM Controller Core inst_sdram_ctrl_frontend : entity work.sdram_ctrl_frontend Generic map ( BL => BURST_LEN, read_phaseshift => ddr_phaseshift, f_sysclk => ddr_frequency_hz, fifo_depth => 4 ) Port map ( sys_rst_in => rst_in, sys_clk_in => sys_clk_in, sys_rst_out => rst, sys_clk_out => clk, sys_clk_fb => sys_sdr_clk_fb, busy => sdr_busy_q, en => sdr_en, r_wn => mem_re_r, be => sdr_be, addr => sdr_addr, din => sdr_udata_in, dout => sdr_udata_out_q, dout_re => sdr_read, dout_vld => sdr_udata_vld_q, -- SDRAM signals sd_clk_p => sys_sdr_clk_p, sd_clk_n => sys_sdr_clk_n, sd_cke => sys_sdr_cke_q, sd_cs_n => sys_sdr_cs_qn, sd_cas_n => sys_sdr_cas_qn, sd_ras_n => sys_sdr_ras_qn, sd_we_n => sys_sdr_we_qn, sd_addr => sys_sdr_a_q, sd_ba => sys_sdr_ba_q, sd_dm => sys_sdr_dm_q, sd_dqs => sys_sdr_dqs_q, sd_data => sys_sdr_data ); STARTUP_VIRTEX4_inst : STARTUP_VIRTEX4 port map ( EOS => started_up, -- End of Startup 1-bit output CLK => open, -- Clock input for start-up sequence GSR => '0', -- Global Set/Reset input (GSR cannot be used for the port name) GTS => '0', -- Global 3-state input (GTS cannot be used for the port name) USRCCLKO => '0', -- USRCCLKO 1-bit input USRCCLKTS => '0', -- USRCCLKTS 1-bit input USRDONEO => '0', -- USRDONEO 1-bit input USRDONETS => '0' -- USRDONETS 1-bit input ); ------------------------------------------------------------------ END;