library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; use IEEE.std_logic_arith.all; use usefuls.all; entity Bus2Periph is generic ( bus_width : natural := 8; periph_width : natural range (bus_width + 1) to natural'high := 16); port ( clk : in std_logic; transaction : in std_logic; data_in : in std_logic_vector(bus_width-1 downto 0); data_out : out std_logic_vector(bus_width-1 downto 0); dir : in std_logic; -- write register => '1', read register => '0' cs : in std_logic; -- chip select done : out std_logic; -- complete write / valid output periph_in : in std_logic_vector(periph_width-1 downto 0); periph_out : out std_logic_vector(periph_width-1 downto 0); periph_dir : out std_logic; -- write register => '1', read register => '0' periph_cs : out std_logic; -- chip select periph_done : in std_logic); -- complete write / valid output end Bus2Periph; architecture Behavioral of Bus2Periph is constant times : integer := (periph_width + bus_width - 1) / bus_width; constant count_required_bits : integer := log2_ceil(times); signal data : std_logic_vector((bus_width * times) - 1 downto 0); signal rw_count : std_logic_vector(count_required_bits-1 downto 0); type state_type is (POR, IDLE, READ_FROM_Periph, WRITE_TO_Bus, WAIT_DONE_WRITE_TO_Bus, READ_FROM_Bus, WAIT_DONE_READ_FROM_Bus, WRITE_TO_Periph); signal current_state : state_type := POR; signal cs_buf : std_logic; signal done_buf : std_logic; signal data_in_buf : std_logic_vector(bus_width-1 downto 0); signal periph_cs_buf : std_logic; begin process(clk) begin if clk'event and clk = '1' then if current_state /= POR and transaction = '0' then current_state <= IDLE; else case current_state is when POR => current_state <= IDLE; when IDLE => if cs_buf = '0' and cs = '1' then if dir = '0' then current_state <= READ_FROM_Periph; else current_state <= READ_FROM_Bus; end if; else null; end if; when READ_FROM_Periph => if periph_cs_buf = '1' and periph_done = '1' then current_state <= WRITE_TO_Bus; else null; end if; when WRITE_TO_Bus => current_state <= WAIT_DONE_WRITE_TO_Bus; when WAIT_DONE_WRITE_TO_Bus => if cs_buf = '1' and cs = '0' and rw_count /= conv_std_logic_vector(times, count_required_bits) then current_state <= WRITE_TO_Bus; else null; end if; when READ_FROM_Bus => current_state <= WAIT_DONE_READ_FROM_Bus; when WAIT_DONE_READ_FROM_Bus => if rw_count = conv_std_logic_vector(times, count_required_bits) then current_state <= WRITE_TO_Periph; elsif cs_buf = '0' and cs = '1' then current_state <= READ_FROM_Bus; else null; end if; when WRITE_TO_Periph => null; end case; end if; end if; end process; process(clk) begin if clk'event and clk = '1' then cs_buf <= cs; end if; end process; process(clk) begin if clk'event and clk = '1' then if current_state = WRITE_TO_Bus or current_state = READ_FROM_Bus then rw_count <= rw_count + 1; elsif current_state = IDLE then rw_count <= conv_std_logic_vector(0, count_required_bits); else null; end if; end if; end process; process(clk) begin if clk'event and clk = '1' then if cs_buf = '0' and cs = '1' then data_in_buf <= data_in; else null; end if; end if; end process; process(clk) begin if clk'event and clk = '1' then if current_state = IDLE then data <= (others => '0'); elsif current_state = READ_FROM_Periph then data(periph_width - 1 downto 0) <= periph_in; elsif current_state = READ_FROM_Bus then data <= data(bus_width * (times - 1) - 1 downto 0) & data_in_buf; elsif current_state = WAIT_DONE_WRITE_TO_Bus then if cs_buf = '1' and cs = '0' then data <= data(bus_width * (times - 1) - 1 downto 0) & conv_std_logic_vector(0, bus_width); else null; end if; else null; end if; end if; end process; process(clk) begin if clk'event and clk = '1' then if current_state = READ_FROM_Periph or current_state = WRITE_TO_Periph then periph_cs_buf <= '1'; else periph_cs_buf <= '0'; end if; end if; end process; periph_cs <= periph_cs_buf; process(clk) begin if clk'event and clk = '1' then case current_state is when WAIT_DONE_WRITE_TO_Bus => if cs /= '0' then done_buf <= '1'; else done_buf <= '0'; end if; when WAIT_DONE_READ_FROM_Bus => if cs_buf = '1' and cs = '1' and rw_count /= conv_std_logic_vector(times, count_required_bits) then done_buf <= '1'; else done_buf <= '0'; end if; when WRITE_TO_Periph => if periph_done = '1' then done_buf <= '1'; else null; end if; when others => done_buf <= '0'; end case; end if; end process; data_out <= data((bus_width * times - 1) downto (bus_width * (times - 1))) when current_state = WAIT_DONE_WRITE_TO_Bus and cs = '1' else (others => 'Z'); done <= done_buf when cs = '1' else 'Z'; periph_out <= data(periph_width - 1 downto 0) when (current_state = WRITE_TO_Periph) else (others => 'Z'); periph_dir <= '0' when (current_state = READ_FROM_Periph) else '1' when (current_state = WRITE_TO_Periph) else 'Z'; end Behavioral;