---------------------------------------------------------------------------- -- icsp.vhd -- ICSP Low Level Interface -- Version 1.0 -- -- Copyright (C) 2015-2017 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; library unisim; use unisim.VCOMPONENTS.ALL; library unimacro; use unimacro.VCOMPONENTS.ALL; use work.vivado_pkg.ALL; -- Vivado Attributes use work.icsp_pkg.ALL; -- ICSP commands entity icsp is port ( mchp_clk : in std_logic; -- base clock smpl_clk : in std_logic; -- sample clock (50ns) -- icsp_clk_t : out std_logic := '1'; -- icsp clock tristate icsp_clk_o : out std_logic; -- icsp clock out -- icsp_dat_t : out std_logic := '1'; -- icsp data tristate icsp_dat_o : out std_logic; -- icsp data out icsp_dat_i : in std_logic; -- icsp data in -- icsp_sel : out std_logic_vector (15 downto 0) := x"0000"; -- data_out : in icsp_value_t; data_in : out icsp_value_t; -- command : in icsp_cmd_t; valid : in std_logic; ready : out std_logic ); end entity icsp; architecture RTL of icsp is signal icsp_in : std_logic; signal icsp_clk_en : std_logic; function is_zero_f(vec : std_logic_vector) return boolean is begin for I in vec'low to vec'high loop if vec(I) then return false; end if; end loop; return true; end is_zero_f; function pad_f(vec : std_logic_vector; size : natural) return std_logic_vector is variable val : std_logic_vector(size-1 downto 0) := (others => '0'); begin val(vec'high downto vec'low) := vec; return val; end pad_f; begin icsp_clk_o <= mchp_clk and icsp_clk_en; -------------------------------------------------------------------- -- Noise Filter -------------------------------------------------------------------- icsp_in_proc : process (smpl_clk) variable last_v : std_logic; variable shift_v : std_logic_vector(3 downto 0) := (others => '0'); variable clean_v : std_logic; begin if falling_edge(smpl_clk) then -- pulse <= '0'; shift_v := shift_v(shift_v'high-1 downto 0) & icsp_dat_i; /* clean_v := '1' when (shift_v(0) and shift_v(1) and shift_v(2)) or (shift_v(0) and shift_v(1) and shift_v(3)) or (shift_v(0) and shift_v(2) and shift_v(3)) or (shift_v(1) and shift_v(2) and shift_v(3)) else '0'; */ clean_v := '1' when (shift_v(0) and shift_v(1)) or (shift_v(0) and shift_v(2)) or (shift_v(1) and shift_v(2)) else '0'; -- clean <= clean_v; if not last_v and mchp_clk then -- pulse <= '1'; icsp_in <= clean_v; end if; last_v := mchp_clk; end if; end process; -------------------------------------------------------------------- -- State Machine -------------------------------------------------------------------- command_proc : process (mchp_clk) type cmd_state is (idle_s, word_s, read_s, delay_s); variable state_v : cmd_state := idle_s; variable count_v : integer range -2 to 33; variable shift_v : natural range 0 to 31; variable value_v : std_logic_vector(31 downto 0); begin if rising_edge(mchp_clk) then case state_v is when idle_s => -- icsp_dat_o <= '1'; if valid then case command is when ICSP_CMD_NOP => state_v := idle_s; when ICSP_CMD_LVP => -- enter LVP mode state_v := word_s; value_v := ICSP_LVP_KEY; count_v := 33; when ICSP_CMD_W4 => -- write 4bit data state_v := word_s; value_v := pad_f(data_out, 32); count_v := 4; when ICSP_CMD_W6 => -- write 6bit data state_v := word_s; value_v := pad_f(data_out, 32); count_v := 6; when ICSP_CMD_W8 => -- write 8bit state_v := word_s; value_v := pad_f(data_out, 32); count_v := 8; when ICSP_CMD_W16 => -- write 16bit state_v := word_s; value_v := pad_f(data_out, 32); count_v := 16; when ICSP_CMD_R16 => -- read 16bit state_v := read_s; value_v := (others => '0'); count_v := 16; shift_v := 16; icsp_dat_t <= '1'; icsp_dat_o <= '1'; when ICSP_CMD_ML => -- set nMCLR low state_v := idle_s; icsp_clk_t <= '0'; icsp_dat_t <= '0'; when ICSP_CMD_MH => -- set nMCLR high state_v := idle_s; icsp_clk_t <= '0'; icsp_dat_t <= '0'; when ICSP_CMD_MZ => -- tristate nMCLR state_v := idle_s; icsp_clk_t <= '1'; icsp_dat_t <= '1'; icsp_dat_o <= '1'; when ICSP_CMD_SEL => -- select interface state_v := idle_s; icsp_sel <= data_out(15 downto 0); when ICSP_CMD_DLY => -- delay clk cycles state_v := delay_s; value_v := pad_f(data_out, 32); when others => state_v := idle_s; end case; end if; when word_s => if count_v = 0 then icsp_clk_en <= '0'; icsp_dat_t <= '0'; icsp_dat_o <= '0'; -- favor stop condition? state_v := idle_s; else icsp_clk_en <= '1'; icsp_dat_t <= '0'; icsp_dat_o <= value_v(0); value_v := "0" & value_v(value_v'high downto 1); end if; count_v := count_v - 1; when read_s => value_v := icsp_in & value_v(value_v'high downto 1); icsp_clk_en <= '1' when count_v > 0 else '0'; if count_v = -1 then value_v := std_logic_vector( shift_right(unsigned(value_v), shift_v)); data_in <= value_v(15 downto 0); state_v := idle_s; elsif count_v = 0 then icsp_dat_t <= '0'; icsp_dat_o <= '0'; end if; count_v := count_v - 1; when delay_s => if is_zero_f(value_v) then state_v := idle_s; else value_v := std_logic_vector( unsigned(value_v) - "1"); end if; end case; ready <= '1' when state_v = idle_s else '0'; end if; end process; end RTL;