1206 lines
42 KiB
VHDL
1206 lines
42 KiB
VHDL
-- 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;
|