-- synthesis VHDL_INPUT_VERSION VHDL_2008 library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.std_logic_misc.all; use work.sim_switcher_pkg.all; entity sim_switcher_top is generic ( -- General parameters SYSFREQ : integer := 25_000_000; -- System clock frequency INSIM : std_logic := '0'; -- In Simulation flag: 0 - real work (default), 1 - simulation -- I2C parameters I2C_SLAVE_ADDR : std_logic_vector(6 downto 0) := "1010111" -- Address of I2C slave, dafault 0x57 ); port ( -- Clock and reset clk25_i : in std_logic; clk125_i : in std_logic; rstn_i : in std_logic; -- User LED led_o : out std_logic; -- Power Good signals pg_10v_i : in std_logic; pg_25v_i : in std_logic; pg_33v_i : in std_logic; -- CPU reset signals cpu_rst_reqn_i : in std_logic; cpu_trstn_o : out std_logic; cpu_jtag_rstn_o : out std_logic; -- FPGA interrupt to CPU fpga_int_o : out std_logic; -- FPGA_INTn_V18, PIN_F12, active high -- I2C slave interface i2c_scl_io : inout std_logic; i2c_sda_io : inout std_logic; -- SIM board CONF bits sb_conf_i : in std_logic_vector(2 downto 0); -- SIM signals sim_detect_i : in std_logic_vector(7 downto 0); sim_pwron_o : out std_logic_vector(7 downto 0); sim_rst_o : out std_logic_vector(7 downto 0); sim_clk_o : out std_logic_vector(7 downto 0); sim_data_io : inout std_logic_vector(7 downto 0); -- Virtual SIM data IO signals vsim_data_io : inout std_logic_vector(3 downto 0); -- Modem signals for SIM cards mod_detect_o : out std_logic_vector(3 downto 0); mod_wake_host_i : in std_logic_vector(3 downto 0); mod_simpwr_i : in std_logic_vector(7 downto 0); mod_simrst_i : in std_logic_vector(7 downto 0); mod_clk_i : in std_logic_vector(7 downto 0); mod_data_io : inout std_logic_vector(7 downto 0); -- Modem LEDs mod_led_o : out std_logic_vector(7 downto 0); -- Modem manage signals mod_pwr_o : out std_logic_vector(7 downto 0); -- Modem power on signals mod_rstn_o : out std_logic_vector(7 downto 5); -- PCIe reset signal mod_pciehstwake_i : in std_logic_vector(7 downto 5); -- PCIe wake host signal -- Expansion card GPIO signals exp_card_io : inout std_logic_vector(5 downto 0); -- FAN power on signals fan_o : out std_logic_vector(1 downto 0); -- I2C slave interface FPGA-MCU (BitBang by MCU) i2c_mcuscl_io : inout std_logic; i2c_mcusda_io : inout std_logic; -- POE IN add-in card poe_in_vpres : in std_logic; -- Voltage present at card power output poe_in_enn : out std_logic; -- PD enable signal (active low) poe_in_t2p : in std_logic_vector(1 downto 0); -- PSE connected signal -- POE OUT add-in card signals pse_rst : out std_logic; -- PSE reset pse_vpwr_enn : out std_logic; -- PSE enable (active low) pse_i2c_scl_io : inout std_logic; -- PSE I2C SCL signal pse_i2c_sda_io : inout std_logic; -- PSE I2C SDA signal pse_intn : in std_logic; -- PSE interrupt (active low) pse_vpwr_pg : in std_logic -- PSE power good signal ); end entity sim_switcher_top; architecture rtl of sim_switcher_top is component debounce is generic ( WAIT_CYCLES : integer := 5 ); port ( signal_in : in std_logic; signal_out : out std_logic; clk : in std_logic ); end component; constant FLASHES : natural := 5; -- Number of LED flashes on boot constant CPU_RST_DURATION : natural := 100_000_000; -- 25_000_000 = 1sec constant PON_RST_DURATION : natural := 10; -- 25_000_000 = 1sec constant PON_CPU_DELAY_DURATION : natural := 75_000_000; -- 25_000_000 = 1sec constant SB_CONF_UPDATE_INTERVAL : natural := 25_000_000; -- 25_000_000 = 1sec constant DEBOUNCING_WAIT_CYCLES : natural := 3; -- Number of debouncing wait cycles constant REPI2C_DEBOUNCING_WAIT_CYCLES : natural := 3; -- Number of debouncing wait cycles constant EXPIO_DEBOUNCING_WAIT_CYCLES : natural := 25; -- Number of debouncing wait cycles constant I2C_CLK : natural := 400_000; -- speed the i2c bus (scl) will run at in Hz constant I2C_MAX_WAIT : natural := 2_500_000; -- 25_000_000 = 1sec constant PSE_I2C_ADDR : std_logic_vector(6 downto 0) := "0100000"; -- 0x20 constant PSE_REG_NUM : natural := 8; constant PSE_POLL_INTERVAL : natural := 25_000_000; -- 25_000_000 = 1sec signal s_clk_i : std_logic; -- clock buffer signal s_rstn_i : std_logic; -- reset signal signal s_rst_i : std_logic; -- reset signal -- Signals to detect CPU reset request falling edge signal s_cpu_rst_reqn : std_logic; signal s_cpu_rst_reqn_prev : std_logic; signal s_cpu_trst_dir_o : std_logic := '1'; signal s_rst_cntr_start : std_logic; -- CPU delay signal signal s_cpu_delay : std_logic := '1'; signal s_led_o : std_logic := '1'; -- I2C slave parallel interface signal i2c_read_req : std_logic := '0'; signal i2c_data_to_master : std_logic_vector(7 downto 0) := (others => '0'); signal i2c_data_valid : std_logic := '0'; signal i2c_data_from_master : std_logic_vector(7 downto 0) := (others => '0'); -- I2C slave state machine type i2c_fsm_t is (ready, receive_byte, wait_while_sent); signal i2c_slv_state : i2c_fsm_t := ready; signal reg_sim_pwr : std_logic_vector(15 downto 0); signal reg_sim_det : std_logic_vector(15 downto 0); signal s_reg_to_write : std_logic_vector(7 downto 0); -- SIM data signals signal s_sim_data_i, sdb_sim_data_i, sdb_sim_data_prev, s_sim_data_o: std_logic_vector(15 downto 0); -- Modem data signals signal s_mod_data_i, sdb_mod_data_i, sw_mod_data_i, sw_mod_data_prev, s_mod_data_o, sw_mod_data_o: std_logic_vector(7 downto 0); -- SIM board CONF bits register signal reg_sim_board_conf : std_logic_vector(2 downto 0); -- SIM switch IRQs for repeater state machine reset upon SIM change signal reg_sim_change_irq : std_logic_vector(15 downto 0) := (others => '0'); -- Modem LED register signal reg_mod_led : std_logic_vector(7 downto 0); -- Modem power register signal reg_mod_pwr : std_logic_vector(7 downto 0); -- PCI-e signals signal reg_pcie_rstn : std_logic_vector(7 downto 5); signal reg_pcie_waken : std_logic_vector(7 downto 5); -- M.2 modem wake host register signal reg_mod_hstwake : std_logic_vector(3 downto 0); -- FAN control register signal reg_fan_ctl : std_logic_vector(1 downto 0); -- PSE registers signal reg_pse_status : std_logic_vector(1 downto 0); signal reg_pse_ctl : std_logic_vector(1 downto 0); -- POE PD registers signal reg_poepd_status : std_logic_vector(2 downto 0); signal reg_poepd_ctl : std_logic; -- Expansion card IO tri-state control signal reg_expio_line : std_logic_vector(5 downto 0); signal reg_expio_output : std_logic_vector(5 downto 0); signal reg_expio_dir : std_logic_vector(5 downto 0); signal reg_expio_intdirh2l : std_logic_vector(5 downto 0); signal reg_expio_intdirl2h : std_logic_vector(5 downto 0); signal reg_expio_intstatus : std_logic_vector(5 downto 0); signal s_exp_card_i : std_logic_vector(5 downto 0); signal s_dbexp_card_i : std_logic_vector(5 downto 0); signal s_dbexp_card_prev : std_logic_vector(5 downto 0); signal s_expio_intl2h : std_logic_vector(5 downto 0); signal s_expio_inth2l : std_logic_vector(5 downto 0); -- Interrupt related signals signal reg_int_reason : std_logic_vector(7 downto 0); signal s_int_reason_gpio : std_logic; signal s_int_reason_reset : std_logic; signal s_int_reason_reset_ack : std_logic; signal s_int_expio_reset : std_logic; signal s_int_expio_reset_ack : std_logic; signal s_fpga_int_o : std_logic; signal sdb_pse_intn : std_logic; signal sdb_pse_intn_prev : std_logic; -- State machine signals and types type state_t is (idle, mod_to_sim, sim_to_mod); type arr_state_t is array (natural range <>) of state_t; signal state: arr_state_t(0 to 7); -- SIM-MODEM switching register signal reg_sim_modemnum: arr_modnum_t(0 to 7); -- PSE regs and control signals type arr_regs_t is array (natural range <>) of std_logic_vector(7 downto 0); signal pse_regs_to_read, pse_regs_value: arr_regs_t(0 to PSE_REG_NUM-1); type i2c_pse_fsm_t is (ready, i2c_trn_start, i2c_trn_main, i2c_trn_final_word_wait, i2c_wr_wait, i2c_rd_wait, wait_ack); signal i2c_state : i2c_pse_fsm_t := ready; signal s_i2c_data_wr : std_logic_vector(7 downto 0); signal s_i2c_data_rd : std_logic_vector(7 downto 0); signal s_i2c_txn_start : std_logic; signal s_i2c_rw_flag : std_logic; signal s_i2c_busy_flag : std_logic; signal i2c_busy_prev : std_logic; signal i2c_core_start : std_logic; signal i2c_core_busy : std_logic; signal i2c_wr_done : std_logic; signal reg_i2c_trn_dir : std_logic; signal wait_i2c_start : std_logic; signal pse_i2c_write_reg : std_logic; signal pse_i2c_write_ack : std_logic; signal pse_i2c_addr_wrtn : std_logic; signal pse_i2c_wr_reg_num : std_logic_vector(7 downto 0); signal pse_i2c_wr_reg_val : std_logic_vector(7 downto 0); begin -- Interrupt output routing fpga_int_o <= s_fpga_int_o; -- Currently unused SIM data lines for VirtualSIM s_sim_data_i(15 downto 8) <= (others => '1'); sdb_sim_data_i(15 downto 8) <= (others => '1'); -- Fill SIM detect register reg_sim_det(7 downto 0) <= sim_detect_i; reg_sim_det(15 downto 8) <= (others => '0'); -- Drive modem LEDs and Power mod_led_o <= reg_mod_led; mod_pwr_o <= reg_mod_pwr; -- Drive PCI-e RSTn and WAKEn signals mod_rstn_o <= reg_pcie_rstn; reg_pcie_waken <= mod_pciehstwake_i; -- Drive M.2 wake host signals reg_mod_hstwake <= mod_wake_host_i; -- Drive FAN control signals fan_o <= reg_fan_ctl; -- POE PD init reg_poepd_status(2) <= poe_in_vpres; reg_poepd_status(1 downto 0) <= poe_in_t2p(1 downto 0); poe_in_enn <= reg_poepd_ctl; ---------------------- -- Working with PSE -- ---------------------- -- PSE init pse_rst <= reg_pse_ctl(0); pse_vpwr_enn <= reg_pse_ctl(1); reg_pse_status(1) <= not pse_intn; reg_pse_status(0) <= pse_vpwr_pg; -- Connect PSE I2C bus to main I2C bus inst_i2c_master: i2c_master generic map ( input_clk => SYSFREQ, bus_clk => I2C_CLK ) port map ( clk => clk25_i, reset_n => s_rstn_i, ena => s_i2c_txn_start, addr => PSE_I2C_ADDR, rw => s_i2c_rw_flag, data_wr => s_i2c_data_wr, busy => s_i2c_busy_flag, data_rd => s_i2c_data_rd, ack_error => open, sda => pse_i2c_sda_io, scl => pse_i2c_scl_io, scl_invert => '0' ); -- PSE register addresses pse_regs_to_read <= ( 0 => x"0C", -- RO 1 => x"0D", -- RO 2 => x"0E", -- RO 3 => x"0F", -- RO 4 => x"10", -- RO 5 => x"12", -- R/W 6 => x"13", -- R/W 7 => x"14" -- R/W ); -- PSE read trigger process pse_readtrig_proc: process(clk25_i, s_rstn_i, wait_i2c_start, i2c_core_busy, pse_i2c_write_reg) is variable wait_cnt : natural := 0; begin if (s_rstn_i = '0') then i2c_core_start <= '0'; wait_i2c_start <= '0'; reg_i2c_trn_dir <= '1'; pse_i2c_write_ack <= '0'; elsif (rising_edge(clk25_i)) then -- Clear write ack flag if pse_i2c_write_reg has been cleared if (pse_i2c_write_reg = '0') then pse_i2c_write_ack <= '0'; end if; -- Main PSE I2C core control process if (wait_i2c_start = '1') then -- Wait until PSE I2C core goes to busy state if wait_i2c_start is set if (i2c_core_busy = '1') then wait_i2c_start <= '0'; end if; elsif (i2c_core_busy = '0') then -- If PSE I2C core is not busy - check for required operation and proceed if (i2c_core_start = '1') then i2c_core_start <= '0'; elsif (pse_i2c_write_reg = '1') then wait_cnt := 0; wait_i2c_start <= '1'; pse_i2c_write_ack <= '1'; reg_i2c_trn_dir <= '0'; -- I2C write op i2c_core_start <= '1'; elsif (wait_cnt > PSE_POLL_INTERVAL) then wait_cnt := 0; wait_i2c_start <= '1'; reg_i2c_trn_dir <= '1'; -- I2C read op i2c_core_start <= '1'; end if; wait_cnt := wait_cnt + 1; end if; end if; end process; -- PSE I2C interaction process pse_i2c_proc: process (clk25_i, s_rstn_i) variable reg_num_rd : natural := 0; begin if (s_rstn_i = '0') then pse_regs_value <= ( 0 => x"00", 1 => x"00", 2 => x"00", 3 => x"00", 4 => x"00", 5 => x"00", 6 => x"00", 7 => x"00" ); i2c_state <= ready; i2c_core_busy <= '0'; i2c_busy_prev <= '0'; i2c_wr_done <= '0'; reg_num_rd := 0; elsif (rising_edge(clk25_i)) then case i2c_state is when ready => if (i2c_core_start = '1') then i2c_state <= i2c_trn_start; i2c_core_busy <= '1'; reg_num_rd := 0; i2c_busy_prev <= '0'; end if; when i2c_trn_start => s_i2c_txn_start <= '1'; -- Initiate the transaction s_i2c_rw_flag <= '0'; -- First byte is always write case reg_i2c_trn_dir is when '0' => -- write s_i2c_data_wr <= pse_i2c_wr_reg_num; -- Place reg number to I2C master core pse_i2c_addr_wrtn <= '0'; when '1' => -- read s_i2c_data_wr <= pse_regs_to_read(reg_num_rd); -- Place reg number to I2C master core end case; i2c_busy_prev <= s_i2c_busy_flag; i2c_wr_done <= '0'; i2c_state <= i2c_trn_main; when i2c_trn_main => i2c_busy_prev <= s_i2c_busy_flag; -- Capture the value of the previous i2c busy signal if (i2c_busy_prev = '0' and s_i2c_busy_flag = '1') then -- I2C busy just went high case reg_i2c_trn_dir is -- Switches to the needed transaction direction when '0' => -- When write - continue to write if (pse_i2c_addr_wrtn = '0') then -- Keep writing if there's still data in the RAM pse_i2c_addr_wrtn <= '1'; s_i2c_data_wr <= pse_i2c_wr_reg_val; -- Prepare register value to write else -- Else - finish the transaction i2c_state <= i2c_trn_final_word_wait; s_i2c_txn_start <= '0'; end if; when '1' => -- When read if (i2c_wr_done = '0') then -- Change the transaction from Write to Read after writing the first byte s_i2c_rw_flag <= '1'; -- Switch to read i2c_state <= i2c_wr_wait; else i2c_wr_done <= '0'; s_i2c_txn_start <= '0'; -- Stop core after reading 1 byte i2c_state <= i2c_rd_wait; end if; when others => i2c_state <= ready; end case; end if; when i2c_trn_final_word_wait => if (i2c_busy_prev = '1' and s_i2c_busy_flag = '0') then -- I2C became free i2c_state <= wait_ack; end if; when i2c_wr_wait => if (s_i2c_busy_flag = '0') then -- Indicates data read in last command is ready i2c_state <= i2c_trn_main; -- Transaction complete, go to next state in design i2c_wr_done <= '1'; i2c_busy_prev <= s_i2c_busy_flag; end if; when i2c_rd_wait => if (s_i2c_busy_flag = '0') then -- Indicates data read in last command is ready pse_regs_value(reg_num_rd) <= s_i2c_data_rd; -- Store received byte reg_num_rd := reg_num_rd + 1; if (reg_num_rd = PSE_REG_NUM) then -- All regs are 1 byte length i2c_state <= wait_ack; -- Transaction complete, go to next state in design else i2c_state <= i2c_trn_start; -- Transaction complete, go to next state in design end if; end if; when wait_ack => i2c_core_busy <= '0'; i2c_busy_prev <= '0'; if (i2c_core_start = '0') then i2c_state <= ready; end if; when others => i2c_state <= ready; end case; end if; end process pse_i2c_proc; ------------------------------------ -- Working woth expansion card IO -- ------------------------------------ -- Expansion card IO control gen_expio_dbnc: for i in 0 to 5 generate s_exp_card_i(i) <= exp_card_io(i); reg_expio_line(i) <= s_dbexp_card_i(i); exp_card_io(i) <= '0' when reg_expio_output(i) = '0' and reg_expio_dir(i) = '1' else '1' when reg_expio_output(i) = '1' and reg_expio_dir(i) = '1' else 'Z'; expio_debounce : debounce generic map ( WAIT_CYCLES => EXPIO_DEBOUNCING_WAIT_CYCLES ) port map ( clk => clk25_i, signal_in => s_exp_card_i(i), signal_out => s_dbexp_card_i(i) ); end generate gen_expio_dbnc; pseint_debounce : debounce generic map ( WAIT_CYCLES => DEBOUNCING_WAIT_CYCLES ) port map ( clk => clk25_i, signal_in => pse_intn, signal_out => sdb_pse_intn ); -------------------------- -- Interrupt generation -- -------------------------- reg_expio_intstatus <= s_expio_intl2h or s_expio_inth2l; int_gen_proc: process(clk25_i, s_rstn_i, sdb_pse_intn, sdb_pse_intn_prev, s_int_expio_reset, s_expio_intl2h, s_expio_inth2l, reg_expio_intdirl2h, reg_expio_intdirh2l, s_dbexp_card_i, s_dbexp_card_prev) is begin if s_rstn_i = '0' then s_fpga_int_o <= '0'; s_expio_intl2h <= (others => '0'); s_expio_inth2l <= (others => '0'); reg_int_reason <= (others => '0'); elsif (rising_edge(clk25_i)) then s_dbexp_card_prev <= s_dbexp_card_i; sdb_pse_intn_prev <= sdb_pse_intn; -- Catch IO line transitions for interrupt generating for i in 0 to 5 loop -- Generate Low-to-High IO transition interrupt if (reg_expio_intdirl2h(i) = '1' and s_dbexp_card_prev(i) = '0' and s_dbexp_card_i(i) = '1') then s_expio_intl2h(i) <= '1'; end if; -- Generate High-to-Low IO transition interrupt if (reg_expio_intdirh2l(i) = '1' and s_dbexp_card_prev(i) = '1' and s_dbexp_card_i(i) = '0') then s_expio_inth2l(i) <= '1'; end if; end loop; -- Write the interrupt reason is IO bit reg_int_reason(0) <= OR_REDUCE(s_expio_intl2h) or OR_REDUCE(s_expio_inth2l); -- Write interrupt reason is PSE bit if (sdb_pse_intn_prev = '1' and sdb_pse_intn = '0') then reg_int_reason(1) <= '1'; end if; if (s_int_expio_reset = '1') then s_expio_intl2h <= (others => '0'); s_expio_inth2l <= (others => '0'); s_int_expio_reset_ack <= '1'; else s_int_expio_reset_ack <= '0'; end if; if (s_int_reason_reset = '1') then reg_int_reason <= (others => '0'); s_int_reason_reset_ack <= '1'; else s_int_reason_reset_ack <= '0'; end if; s_fpga_int_o <= OR_REDUCE(s_expio_intl2h) or OR_REDUCE(s_expio_inth2l) or not sdb_pse_intn; end if; end process; ---------------------------------- -- Power-On FPGA IP-cores reset -- ---------------------------------- pon_rst_proc: process(clk25_i) is variable wait_cnt : natural := 0; begin if (rising_edge(clk25_i)) then if (wait_cnt > PON_RST_DURATION) then s_rstn_i <= '1'; else wait_cnt := wait_cnt + 1; s_rstn_i <= '0'; end if; end if; end process; s_rst_i <= not s_rstn_i; ----------------------- -- Startup LED blink -- ----------------------- led_o <= s_led_o; led_blink_proc: process(clk25_i) is variable wait_cnt : natural := 0; variable flash_cnt : natural := 0; begin if (rising_edge(clk25_i)) then if (wait_cnt > SYSFREQ/4) then if (flash_cnt <= (FLASHES-1)*2) then wait_cnt := 0; s_led_o <= not s_led_o; flash_cnt := flash_cnt + 1; end if; end if; if (flash_cnt <= FLASHES*2) then wait_cnt := wait_cnt + 1; end if; end if; end process; ------------------------------ -- Power-On CPU start delay -- ------------------------------ pon_cpu_start_proc: process(clk25_i) is variable wait_cnt : natural := 0; begin if (rising_edge(clk25_i)) then if (wait_cnt > PON_CPU_DELAY_DURATION) then s_cpu_delay <= '1'; else wait_cnt := wait_cnt + 1; s_cpu_delay <= '0'; end if; end if; end process; ------------------------------------- -- Reset generator per CPU request -- ------------------------------------- s_cpu_rst_reqn <= cpu_rst_reqn_i; cpu_trstn_o <= '0' when s_cpu_trst_dir_o = '0' or s_cpu_delay = '0' else 'Z'; --pg_10v_i and pg_25v_i and pg_33v_i; --cpu_trstn_o <= pg_10v_i and pg_25v_i and pg_33v_i; cpu_jtag_rstn_o <= '0' when s_cpu_trst_dir_o = '0' or s_cpu_delay = '0' else 'Z'; cpu_rst_gen_proc: process(clk25_i, s_rstn_i, cpu_rst_reqn_i) is variable wait_cnt : natural := CPU_RST_DURATION; begin if s_rstn_i = '0' then wait_cnt := 0; s_rst_cntr_start <= '0'; s_cpu_rst_reqn_prev <= cpu_rst_reqn_i; elsif rising_edge(clk25_i) then s_cpu_rst_reqn_prev <= s_cpu_rst_reqn; -- Capture value of RESET_REQn for further edge detection -- Check for start if s_rst_cntr_start = '1' then if (wait_cnt >= CPU_RST_DURATION) then s_cpu_trst_dir_o <= '1'; s_rst_cntr_start <= '0'; else wait_cnt := wait_cnt + 1; s_cpu_trst_dir_o <= '0'; end if; else if (s_cpu_rst_reqn_prev = '1' and s_cpu_rst_reqn = '0') then wait_cnt := 0; s_rst_cntr_start <= '1'; end if; end if; end if; end process; --------------------------- -- SIM board CONF update -- --------------------------- sb_conf_upd_proc: process(clk25_i, s_rstn_i, sb_conf_i) is variable wait_cnt : natural := 0; begin if s_rstn_i = '0' then wait_cnt := 0; reg_sim_board_conf <= sb_conf_i; elsif (rising_edge(clk25_i)) then if (wait_cnt > SB_CONF_UPDATE_INTERVAL) then wait_cnt := 0; reg_sim_board_conf <= sb_conf_i; else wait_cnt := wait_cnt + 1; end if; end if; end process; -------------------------------- -- I2C slave interface to CPU -- -------------------------------- inst_i2c_slave: i2c_slave generic map ( SLAVE_ADDR => I2C_SLAVE_ADDR ) port map( scl => i2c_scl_io, sda => i2c_sda_io, clk => clk25_i, rst => s_rst_i, read_req => i2c_read_req, data_to_master => i2c_data_to_master, data_valid => i2c_data_valid, data_from_master => i2c_data_from_master ); i2c_slv_process : process (clk25_i, s_rstn_i) variable wait_cnt : natural := 0; begin if (s_rstn_i = '0') then i2c_data_to_master <= (others => '0'); wait_cnt := 0; -- SIM attach reset assigment: default is 1-to-1 SIM to MODEM connection reg_sim_modemnum <= ( 0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5, 6 => 6, 7 => 7 ); -- SIM change IRQ register reset reg_sim_change_irq <= (others => '0'); -- Turn on all SIM cards reg_sim_pwr(7 downto 0) <= (others => '1'); -- Real SIMs power is on reg_sim_pwr(15 downto 8) <= (others => '0'); -- Virtual SIMs power is "off" reg_mod_led <= (others => '0'); -- Modem LEDs are not lit reg_mod_pwr <= (others => '0'); -- Modem power is off reg_pcie_rstn <= (others => '1'); -- PCIe RSTn is not active reg_fan_ctl <= (others => '0'); -- FANs are off reg_pse_ctl <= (others => '0'); -- POE out is on reg_poepd_ctl <= '0'; -- POE PD enabled reg_expio_output <= (others => '1'); -- All Expansion card IOs in HighZ at start reg_expio_dir <= (others => '0'); -- All Expansion card IOs direction is IN reg_expio_intdirh2l <= (others => '0'); -- Expansion card GPIO default line interrupt generation for High-to-Low transition is off reg_expio_intdirl2h <= (others => '0'); -- Expansion card GPIO default line interrupt generation for Low-to-High transition is off pse_i2c_write_reg <= '0'; elsif (rising_edge(clk25_i)) then if (s_int_expio_reset_ack = '1') then s_int_expio_reset <= '0'; end if; if (s_int_reason_reset_ack = '1') then s_int_reason_reset <= '0'; end if; case i2c_slv_state is when ready => wait_cnt := 0; -- Reset pse_i2c_write_reg trigger if PSE I2C core has ACKed the write operation if (pse_i2c_write_ack = '1') then pse_i2c_write_reg <= '0'; end if; i2c_data_to_master <= (others => '0'); if (i2c_data_valid = '1') then -- master sent a register addr byte -- Save register address for later use in write procedure s_reg_to_write <= i2c_data_from_master; case i2c_data_from_master is when x"10" => -- Read ID byte i2c_data_to_master <= x"18"; i2c_slv_state <= wait_while_sent; when x"11" => -- Read SW Version byte (v1.0=0x18 MBCr1, v1.1=0x19 MBSr1, v2.0=0x28 MBSr2) i2c_data_to_master <= x"28"; i2c_slv_state <= wait_while_sent; when x"12" => -- Read SIM board model regiser i2c_data_to_master <= "00000" & reg_sim_board_conf; i2c_slv_state <= wait_while_sent; when x"15" => -- Read interrupt reason register (autocleared on read) i2c_data_to_master <= reg_int_reason; s_int_reason_reset <= '1'; -- Clear reg on read i2c_slv_state <= wait_while_sent; when x"20" => -- Read SIM1 modem register i2c_data_to_master <= "0000" & std_logic_vector(to_unsigned(reg_sim_modemnum(0),4)); i2c_slv_state <= wait_while_sent; when x"21" => -- Read SIM2 modem register i2c_data_to_master <= "0000" & std_logic_vector(to_unsigned(reg_sim_modemnum(1),4)); i2c_slv_state <= wait_while_sent; when x"22" => -- Read SIM3 modem register i2c_data_to_master <= "0000" & std_logic_vector(to_unsigned(reg_sim_modemnum(2),4)); i2c_slv_state <= wait_while_sent; when x"23" => -- Read SIM4 modem register i2c_data_to_master <= "0000" & std_logic_vector(to_unsigned(reg_sim_modemnum(3),4)); i2c_slv_state <= wait_while_sent; when x"24" => -- Read SIM5 modem register i2c_data_to_master <= "0000" & std_logic_vector(to_unsigned(reg_sim_modemnum(4),4)); i2c_slv_state <= wait_while_sent; when x"25" => -- Read SIM6 modem register i2c_data_to_master <= "0000" & std_logic_vector(to_unsigned(reg_sim_modemnum(5),4)); i2c_slv_state <= wait_while_sent; when x"26" => -- Read SIM7 modem register i2c_data_to_master <= "0000" & std_logic_vector(to_unsigned(reg_sim_modemnum(6),4)); i2c_slv_state <= wait_while_sent; when x"27" => -- Read SIM8 modem register i2c_data_to_master <= "0000" & std_logic_vector(to_unsigned(reg_sim_modemnum(7),4)); i2c_slv_state <= wait_while_sent; when x"35" => -- Read M.2 modem wake host register i2c_data_to_master <= "0000"®_mod_hstwake(3 downto 0); i2c_slv_state <= wait_while_sent; when x"36" => -- Read modem LED register i2c_data_to_master <= reg_mod_led(7 downto 0); i2c_slv_state <= wait_while_sent; when x"37" => -- Read modem power register i2c_data_to_master <= reg_mod_pwr(7 downto 0); i2c_slv_state <= wait_while_sent; when x"38" => -- Read PCIe RSTn register i2c_data_to_master <= reg_pcie_rstn(7 downto 5)&"00000"; i2c_slv_state <= wait_while_sent; when x"39" => -- Read PCIe WAKEn register i2c_data_to_master <= reg_pcie_waken(7 downto 5)&"00000"; i2c_slv_state <= wait_while_sent; when x"3A" => -- Read SIM detect register (LSB) i2c_data_to_master <= reg_sim_det(7 downto 0); i2c_slv_state <= wait_while_sent; -- when x"3B" => -- Read SIM detect register (MSB) -- i2c_data_to_master <= reg_sim_det(15 downto 8); -- i2c_slv_state <= wait_while_sent; when x"3C" => -- Read SIM power register (LSB) i2c_data_to_master <= reg_sim_pwr(7 downto 0); i2c_slv_state <= wait_while_sent; -- when x"3D" => -- Read SIM power register (MSB) -- i2c_data_to_master <= reg_sim_pwr(15 downto 8); -- i2c_slv_state <= wait_while_sent; when x"41" => -- Read Expansion card IO lines i2c_data_to_master <= "00" & reg_expio_line; i2c_slv_state <= wait_while_sent; when x"42" => -- Read Expansion card output value register i2c_data_to_master <= "00" & reg_expio_output; i2c_slv_state <= wait_while_sent; when x"43" => -- Read Expansion card direction (0 - IN, 1 - OUT) register i2c_data_to_master <= "00" & reg_expio_dir; i2c_slv_state <= wait_while_sent; when x"44" => -- Read Expansion card GPIO interrupt generation for High-to-Low transition register i2c_data_to_master <= "00" & reg_expio_intdirh2l; i2c_slv_state <= wait_while_sent; when x"45" => -- Read Expansion card GPIO interrupt generation for Low-to-High transition register i2c_data_to_master <= "00" & reg_expio_intdirl2h; i2c_slv_state <= wait_while_sent; when x"46" => -- Read Expansion card GPIO interrupt status register (autocleared on read) i2c_data_to_master <= "00" & reg_expio_intstatus; s_int_expio_reset <= '1'; -- Clear reg on read i2c_slv_state <= wait_while_sent; when x"51" => -- Read FAN control regiser i2c_data_to_master <= "000000" & reg_fan_ctl; i2c_slv_state <= wait_while_sent; when x"52" => -- Read POE OUT status register i2c_data_to_master <= "000000" & reg_pse_status; i2c_slv_state <= wait_while_sent; when x"53" => -- Read POE OUT control register i2c_data_to_master <= "000000" & reg_pse_ctl; i2c_slv_state <= wait_while_sent; when x"54" => -- Read POE IN status register i2c_data_to_master <= "00000" & reg_poepd_status; i2c_slv_state <= wait_while_sent; when x"55" => -- Read POE IN control register i2c_data_to_master <= "0000000" & reg_poepd_ctl; i2c_slv_state <= wait_while_sent; when x"60" => -- Read PSE register "Port 1 Status" 0x0C i2c_data_to_master <= pse_regs_value(0); i2c_slv_state <= wait_while_sent; when x"61" => -- Read PSE register "Port 2 Status" 0x0D i2c_data_to_master <= pse_regs_value(1); i2c_slv_state <= wait_while_sent; when x"62" => -- Read PSE register "Port 3 Status" 0x0E i2c_data_to_master <= pse_regs_value(2); i2c_slv_state <= wait_while_sent; when x"63" => -- Read PSE register "Port 4 Status" 0x0F i2c_data_to_master <= pse_regs_value(3); i2c_slv_state <= wait_while_sent; when x"64" => -- Read PSE register "Power Status" 0x10 i2c_data_to_master <= pse_regs_value(4); i2c_slv_state <= wait_while_sent; when x"65" => -- Read PSE register "Operating Mode" 0x12, 00 Off, 01 Manual, 10 Semi-Auto, 11 Auto i2c_data_to_master <= pse_regs_value(5); i2c_slv_state <= wait_while_sent; when x"66" => -- Read PSE register "Disconnect Enable" 0x13 i2c_data_to_master <= pse_regs_value(6); i2c_slv_state <= wait_while_sent; when x"67" => -- Read PSE register "Detect/Class Enable" 0x14 i2c_data_to_master <= pse_regs_value(7); i2c_slv_state <= wait_while_sent; when x"A0" => -- Write SIM1 modem register i2c_slv_state <= receive_byte; when x"A1" => -- Write SIM2 modem register i2c_slv_state <= receive_byte; when x"A2" => -- Write SIM3 modem register i2c_slv_state <= receive_byte; when x"A3" => -- Write SIM4 modem register i2c_slv_state <= receive_byte; when x"A4" => -- Write SIM5 modem register i2c_slv_state <= receive_byte; when x"A5" => -- Write SIM6 modem register i2c_slv_state <= receive_byte; when x"A6" => -- Write SIM7 modem register i2c_slv_state <= receive_byte; when x"A7" => -- Write SIM8 modem register i2c_slv_state <= receive_byte; when x"B6" => -- Write modem LED register i2c_slv_state <= receive_byte; when x"B7" => -- Write modem power register i2c_slv_state <= receive_byte; when x"B8" => -- Write PCIe RSTn register i2c_slv_state <= receive_byte; when x"BC" => -- Write SIMs power register (LSB) i2c_slv_state <= receive_byte; -- when x"BD" => -- Write SIMs power register (MSB) -- i2c_slv_state <= receive_byte; when x"C2" => -- Write Expansion card output register i2c_slv_state <= receive_byte; when x"C3" => -- Write Expansion card direction register i2c_slv_state <= receive_byte; when x"C4" => -- Write Expansion card GPIO interrupt generation for High-to-Low transition register i2c_slv_state <= receive_byte; when x"C5" => -- Write Expansion card GPIO interrupt generation for Low-to-High transition register i2c_slv_state <= receive_byte; when x"D1" => -- Write FAN control regiser i2c_slv_state <= receive_byte; when x"D3" => -- Write POE OUT control register i2c_slv_state <= receive_byte; when x"D5" => -- Write POE IN control register i2c_slv_state <= receive_byte; when x"E5" => -- Write PSE register "Operating Mode" 0x12 i2c_slv_state <= receive_byte; when x"E6" => -- Write PSE register "Disconnect Enable" 0x13 i2c_slv_state <= receive_byte; when x"E7" => -- Write PSE register "Detect/Class Enable" 0x14 i2c_slv_state <= receive_byte; when others => i2c_slv_state <= ready; end case; end if; when receive_byte => if (i2c_data_valid = '1') then case s_reg_to_write is when x"A0" => -- Write SIM1 modem register reg_sim_modemnum(0) <= to_integer(unsigned(i2c_data_from_master(3 downto 0))); when x"A1" => -- Write SIM2 modem register reg_sim_modemnum(1) <= to_integer(unsigned(i2c_data_from_master(3 downto 0))); when x"A2" => -- Write SIM3 modem register reg_sim_modemnum(2) <= to_integer(unsigned(i2c_data_from_master(3 downto 0))); when x"A3" => -- Write SIM4 modem register reg_sim_modemnum(3) <= to_integer(unsigned(i2c_data_from_master(3 downto 0))); when x"A4" => -- Write SIM5 modem register reg_sim_modemnum(4) <= to_integer(unsigned(i2c_data_from_master(3 downto 0))); when x"A5" => -- Write SIM6 modem register reg_sim_modemnum(5) <= to_integer(unsigned(i2c_data_from_master(3 downto 0))); when x"A6" => -- Write SIM7 modem register reg_sim_modemnum(6) <= to_integer(unsigned(i2c_data_from_master(3 downto 0))); when x"A7" => -- Write SIM8 modem register reg_sim_modemnum(7) <= to_integer(unsigned(i2c_data_from_master(3 downto 0))); when x"B6" => -- Write modem LED register reg_mod_led(7 downto 0) <= i2c_data_from_master(7 downto 0); when x"B7" => -- Write modem power register reg_mod_pwr(7 downto 0) <= i2c_data_from_master(7 downto 0); when x"B8" => -- Write PCIe RSTn register reg_pcie_rstn(7 downto 5) <= i2c_data_from_master(7 downto 5); when x"BC" => -- Write SIMs power register (LSB) reg_sim_pwr(7 downto 0) <= i2c_data_from_master(7 downto 0); -- when x"BD" => -- Write SIMs power register (MSB) -- reg_sim_pwr(15 downto 8) <= i2c_data_from_master(7 downto 0); when x"C2" => -- Write Expansion card output register reg_expio_output <= i2c_data_from_master(5 downto 0); when x"C3" => -- Write Expansion card direction register reg_expio_dir <= i2c_data_from_master(5 downto 0); when x"C4" => -- Write Expansion card GPIO interrupt generation for High-to-Low transition register reg_expio_intdirh2l <= i2c_data_from_master(5 downto 0); when x"C5" => -- Write Expansion card GPIO interrupt generation for Low-to-High transition register reg_expio_intdirl2h <= i2c_data_from_master(5 downto 0); when x"D1" => -- Write FAN control regiser reg_fan_ctl(1 downto 0) <= i2c_data_from_master(1 downto 0); when x"D3" => -- Write POE OUT control register reg_pse_ctl(1 downto 0) <= i2c_data_from_master(1 downto 0); when x"D5" => -- Write POE IN control register reg_poepd_ctl <= i2c_data_from_master(0); when x"E5" => -- Write PSE register "Operating Mode" 0x12 pse_i2c_wr_reg_val <= i2c_data_from_master(7 downto 0); pse_i2c_wr_reg_num <= x"12"; pse_i2c_write_reg <= '1'; when x"E6" => -- Write PSE register "Disconnect Enable" 0x13 pse_i2c_wr_reg_val <= i2c_data_from_master(7 downto 0); pse_i2c_wr_reg_num <= x"13"; pse_i2c_write_reg <= '1'; when x"E7" => -- Write PSE register "Detect/Class Enable" 0x14 pse_i2c_wr_reg_val <= i2c_data_from_master(7 downto 0); pse_i2c_wr_reg_num <= x"14"; pse_i2c_write_reg <= '1'; when others => null; end case; i2c_slv_state <= ready; else -- Wait timer to prevent freeze in waiting state if (wait_cnt > I2C_MAX_WAIT) then i2c_slv_state <= ready; else wait_cnt := wait_cnt + 1; end if; end if; when wait_while_sent => if (i2c_read_req = '1') then i2c_slv_state <= ready; else -- Wait timer to prevent freeze in waiting state if (wait_cnt > I2C_MAX_WAIT) then i2c_slv_state <= ready; else wait_cnt := wait_cnt + 1; end if; end if; when others => i2c_slv_state <= ready; end case; end if; end process i2c_slv_process; -------------------------- --- SIM card switching --- -------------------------- -- Power on SIM card according to the reg_sim_pwr register sim_pwron_o <= reg_sim_pwr(7 downto 0); -- Bidir sinals routing gen_datalines: for i in 0 to 7 generate s_sim_data_i(i) <= sim_data_io(i); sim_data_io(i) <= '0' when s_sim_data_o(i) = '0' else 'Z'; s_mod_data_i(i) <= mod_data_io(i); mod_data_io(i) <= '0' when s_mod_data_o(i) = '0' else 'Z'; -- Debounce data lines mod_dat_i_debounce : debounce generic map ( WAIT_CYCLES => DEBOUNCING_WAIT_CYCLES ) port map ( clk => clk25_i, signal_in => s_mod_data_i(i), signal_out => sdb_mod_data_i(i) ); sim_dat_i_debounce : debounce generic map ( WAIT_CYCLES => DEBOUNCING_WAIT_CYCLES ) port map ( clk => clk25_i, signal_in => s_sim_data_i(i), signal_out => sdb_sim_data_i(i) ); end generate gen_datalines; -- Actual SIM/MODEM signal muxing sim_muxing : sim_mux port map ( reg_sim_modemnum => reg_sim_modemnum, sim_rst_o => sim_rst_o, mod_simrst_i => mod_simrst_i, sim_clk_o => sim_clk_o, mod_clk_i => mod_clk_i, mod_detect_o => mod_detect_o, sim_detect_i => sim_detect_i, sw_mod_data_i => sw_mod_data_i, -- For switched tri-state buffer there are input and output part of mod_data_i => sdb_mod_data_i, -- the lines which are switched transparently, thus ports mod_data_o => s_mod_data_o, -- sw_mod_data_i is actual output and sw_mod_data_o is sw_mod_data_o => sw_mod_data_o -- actual input. Please, don't be confused by conflicting name. ); ------------------ -- SIM repeater -- ------------------ sim_rptr_proc: process(clk25_i, s_rstn_i, sdb_sim_data_i, sdb_sim_data_prev, sw_mod_data_i, sw_mod_data_prev, reg_sim_change_irq) is begin if s_rstn_i = '0' then s_sim_data_o <= (others => '1'); sw_mod_data_o <= (others => '1'); sdb_sim_data_prev <= sdb_sim_data_i; sw_mod_data_prev <= sw_mod_data_i; state <= (others => idle); elsif (rising_edge(clk25_i)) then sdb_sim_data_prev <= sdb_sim_data_i; sw_mod_data_prev <= sw_mod_data_i; for i in 0 to 7 loop case state(i) is when idle => if (sw_mod_data_prev(i) = '1' and sw_mod_data_i(i) = '0') then s_sim_data_o(i) <= '0'; state(i) <= mod_to_sim; elsif (sdb_sim_data_prev(i) = '1' and sdb_sim_data_i(i) = '0') then sw_mod_data_o(i) <= '0'; state(i) <= sim_to_mod; end if; when mod_to_sim => if ((sw_mod_data_prev(i) = '0' and sw_mod_data_i(i) = '1') or reg_sim_change_irq(i) = '1') then s_sim_data_o(i) <= '1'; state(i) <= idle; end if; when sim_to_mod => if ((sdb_sim_data_prev(i) = '0' and sdb_sim_data_i(i) = '1') or reg_sim_change_irq(i) = '1') then sw_mod_data_o(i) <= '1'; state(i) <= idle; end if; end case; end loop; end if; end process; end architecture rtl;