---------------------------------------------------------------------------- -- icsp.vhd -- ICSP Interface -- Version 1.0 -- -- Copyright (C) 2023 H.Poetzl -- -- This program is free software: you can redistribute it and/or -- modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation, either version -- 2 of the License, or (at your option) any later version. -- ---------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.ALL; use IEEE.numeric_std.ALL; use work.vivado_pkg.ALL; -- Vivado Attributes entity icsp is port ( icsp_clk_in : in std_logic; -- icsp_action : in std_logic; icsp_active : out std_logic; -- icsp_write : in std_logic; icsp_ctrl : in std_logic; icsp_cmd : in std_logic_vector (3 downto 0); -- icsp_clen : in std_logic_vector (3 downto 0); icsp_dlen : in std_logic_vector (4 downto 0); -- icsp_cpos : in std_logic_vector (3 downto 0); icsp_opos : in std_logic_vector (4 downto 0); icsp_ipos : in std_logic_vector (4 downto 0); -- icsp_cdir : in std_logic; icsp_odir : in std_logic; icsp_idir : in std_logic; -- icsp_ecbd : in std_logic_vector (1 downto 0); icsp_ecad : in std_logic_vector (1 downto 0); -- icsp_cdly : in std_logic_vector (15 downto 0); icsp_ddly : in std_logic_vector (15 downto 0); -- icsp_cseq : in std_logic_vector (15 downto 0); icsp_din : in std_logic_vector (31 downto 0); -- icsp_dout : out std_logic_vector (31 downto 0); icsp_latch : out std_logic; -- icsp_clk_o : out std_logic; icsp_clk_t : out std_logic; -- icsp_dat_i : in std_logic; icsp_dat_o : out std_logic; icsp_dat_t : out std_logic; -- debug : out std_logic_vector (3 downto 0) ); end entity icsp; architecture RTL of icsp is attribute KEEP_HIERARCHY of RTL : architecture is "TRUE"; signal icsp_dat : std_logic := '0'; signal icsp_tri : std_logic := '0'; signal clk_gate : std_logic := '0'; signal clear_valin : std_logic := '0'; signal sample_valin : std_logic := '0'; begin -------------------------------------------------------------------- -- ICSP Sequence Action -------------------------------------------------------------------- action_proc : process (icsp_clk_in) type cmd_state is (idle_s, ctrl_s, cseq_s, cdly_s, clkb_s, data_s, clka_s, ddly_s, wait_s); variable state_v : cmd_state := idle_s; variable snext_v : cmd_state; variable count_v : integer range -2 to 31; variable value_v : unsigned(31 downto 0); variable wait_v : integer range 0 to 65535; procedure valso ( variable val_v : inout unsigned (31 downto 0); signal shift_dir : in std_logic; signal bit_pos : in std_logic_vector; signal bit_out : out std_logic) is variable bit_pos_v : integer range 0 to 31 := to_integer(unsigned(bit_pos)); begin bit_out <= val_v(bit_pos_v); if shift_dir = '0' then val_v := "0" & val_v(31 downto 1); else val_v := val_v(30 downto 0) & "0"; end if; end procedure; begin if rising_edge(icsp_clk_in) then icsp_latch <= '0'; clear_valin <= '0'; sample_valin <= '0'; clk_gate <= '1' when state_v = cseq_s or state_v = clkb_s or state_v = clka_s or state_v = data_s else '0'; -- actions for current state case state_v is when idle_s => null; when ctrl_s => null; when cseq_s => valso(value_v, icsp_cdir, icsp_cpos, icsp_dat); count_v := count_v - 1; when cdly_s => wait_v := wait_v - 1; when clkb_s => icsp_dat <= '0'; count_v := count_v - 1; when data_s => sample_valin <= '1'; valso(value_v, icsp_odir, icsp_opos, icsp_dat); count_v := count_v - 1; when clka_s => icsp_dat <= '0'; count_v := count_v - 1; when ddly_s => wait_v := wait_v - 1; when wait_s => value_v := value_v - "1"; end case; -- state transitions case state_v is when idle_s => if icsp_action = '1' then if icsp_ctrl = '1' then snext_v := ctrl_s; elsif icsp_cmd = "0000" then snext_v := wait_s; else snext_v := cseq_s; end if; end if; when ctrl_s => snext_v := idle_s; when cseq_s => if count_v < 0 then snext_v := cdly_s; end if; when cdly_s => if wait_v = 0 then snext_v := clkb_s; end if; when clkb_s => if count_v = 0 then snext_v := data_s; end if; when data_s => if count_v < 0 then snext_v := clka_s; end if; when clka_s => if count_v = 0 then snext_v := ddly_s; end if; when ddly_s => if wait_v = 0 then snext_v := idle_s; end if; when wait_s => if value_v = x"FFFFFFFF" then snext_v := idle_s; end if; end case; if snext_v = cseq_s and icsp_cmd(0) = '0' then snext_v := cdly_s; -- skip cmd sequence end if; if snext_v = cdly_s and icsp_cmd(1) = '0' then snext_v := clkb_s; -- skip cmd delay end if; if snext_v = clkb_s and ( icsp_ecbd = "00" or icsp_cmd(2) = '0' ) then snext_v := data_s; -- skip before data end if; if snext_v = data_s and icsp_cmd(2) = '0' then snext_v := clka_s; -- skip data sequence end if; if snext_v = clka_s and ( icsp_ecad = "00" or icsp_cmd(2) = '0' ) then snext_v := ddly_s; -- skip after data end if; if snext_v = ddly_s and icsp_cmd(3) = '0' then snext_v := idle_s; -- skip data delay end if; -- next state preparations if state_v /= snext_v then case snext_v is when idle_s => null; when ctrl_s => null; when cseq_s => value_v := x"0000" & unsigned(icsp_cseq); count_v := to_integer(unsigned(icsp_clen)); when cdly_s => wait_v := to_integer(unsigned(icsp_cdly)); when clkb_s => count_v := to_integer(unsigned(icsp_ecbd)); when data_s => clear_valin <= '1'; value_v := unsigned(icsp_din); count_v := to_integer(unsigned(icsp_dlen)); when clka_s => count_v := to_integer(unsigned(icsp_ecad)); when ddly_s => wait_v := to_integer(unsigned(icsp_ddly)); when wait_s => value_v := x"00" & unsigned(icsp_din(23 downto 0)); end case; end if; icsp_active <= '0' when state_v = idle_s else '1'; icsp_tri <= '1' when ( state_v = data_s or state_v = clkb_s or state_v = clka_s ) and icsp_write = '0' else '0'; debug(2 downto 0) <= "000" when state_v = idle_s else "001" when state_v = ctrl_s else "010" when state_v = cseq_s else "011" when state_v = cdly_s else "100" when state_v = data_s and icsp_write = '0' else "101" when state_v = data_s and icsp_write = '1' else "110" when state_v = ddly_s else "111" when state_v = wait_s else "111"; state_v := snext_v; end if; debug(3) <= icsp_tri; end process; sample_proc : process (icsp_clk_in) variable valin_v : unsigned(31 downto 0); procedure valsi ( variable val_v : inout unsigned (31 downto 0); signal shift_dir : in std_logic; signal bit_pos : in std_logic_vector; signal bit_in : in std_logic) is variable bit_pos_v : integer range 0 to 31 := to_integer(unsigned(bit_pos)); begin if shift_dir = '1' then val_v := "0" & val_v(31 downto 1); else val_v := val_v(30 downto 0) & "0"; end if; val_v(bit_pos_v) := bit_in; end procedure; begin if falling_edge(icsp_clk_in) then if clear_valin = '1' then valin_v := (others => '0'); elsif sample_valin = '1' then valsi(valin_v, icsp_idir, icsp_ipos, icsp_dat_i); end if; end if; icsp_dout <= std_logic_vector(valin_v); end process; icsp_clk_t <= '0'; icsp_clk_o <= icsp_clk_in when clk_gate else '0'; icsp_dat_t <= icsp_tri; icsp_dat_o <= icsp_dat; end RTL;