---------------------------------------------------------------------------- -- reg_icsp.vhd -- AXI3 Lite 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; library unisim; use unisim.VCOMPONENTS.ALL; use work.axi3ml_pkg.ALL; -- AXI3 Lite Master use work.helper_pkg.ALL; -- Helpers use work.reg_array_pkg.ALL; -- Register Array use work.vivado_pkg.ALL; -- Vivado Attributes entity reg_icsp is port ( s_axi_aclk : in std_logic; s_axi_areset_n : in std_logic; -- s_axi_ro : out axi3ml_read_in_r; s_axi_ri : in axi3ml_read_out_r; s_axi_wo : out axi3ml_write_in_r; s_axi_wi : in axi3ml_write_out_r; -- icsp_clk_in : in std_logic; -- icsp_enable : 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 reg_icsp; architecture RTL of reg_icsp is attribute KEEP_HIERARCHY of RTL : architecture is "TRUE"; -- s_axi_aclk domain signal axi_icsp_go : std_logic := '0'; signal axi_icsp_done : std_logic; signal axi_icsp_active : std_logic; signal reg_ab_in : std_logic_vector (116 downto 0); signal reg_ba_out : std_logic_vector (31 downto 0); alias axi_icsp_en : std_logic is reg_ab_in(116); alias axi_icsp_write : std_logic is reg_ab_in(115); alias axi_icsp_ctrl : std_logic is reg_ab_in(114); alias axi_icsp_ecad : std_logic_vector (1 downto 0) is reg_ab_in(113 downto 112); alias axi_icsp_ecbd : std_logic_vector (1 downto 0) is reg_ab_in(111 downto 110); alias axi_icsp_odir : std_logic is reg_ab_in(109); alias axi_icsp_idir : std_logic is reg_ab_in(108); alias axi_icsp_cdir : std_logic is reg_ab_in(107); alias axi_icsp_opos : std_logic_vector (4 downto 0) is reg_ab_in(106 downto 102); alias axi_icsp_ipos : std_logic_vector (4 downto 0) is reg_ab_in(101 downto 97); alias axi_icsp_cpos : std_logic_vector (3 downto 0) is reg_ab_in(96 downto 93); alias axi_icsp_dlen : std_logic_vector (4 downto 0) is reg_ab_in(92 downto 88); alias axi_icsp_clen : std_logic_vector (3 downto 0) is reg_ab_in(87 downto 84); alias axi_icsp_cmd : std_logic_vector (3 downto 0) is reg_ab_in(83 downto 80); alias axi_icsp_cdly : std_logic_vector (15 downto 0) is reg_ab_in(79 downto 64); alias axi_icsp_ddly : std_logic_vector (15 downto 0) is reg_ab_in(63 downto 48); alias axi_icsp_cseq : std_logic_vector (15 downto 0) is reg_ab_in(47 downto 32); alias axi_icsp_data : std_logic_vector (31 downto 0) is reg_ab_in(31 downto 0); alias axi_icsp_din : std_logic_vector (31 downto 0) is reg_ab_in(31 downto 0); alias axi_icsp_dout : std_logic_vector (31 downto 0) is reg_ba_out(31 downto 0); -- icsp_clk_in domain signal icsp_go : std_logic; signal icsp_done : std_logic := '0'; signal icsp_active : std_logic; signal icsp_action : std_logic; signal icsp_action_occ : std_logic; signal icsp_latch : std_logic; signal reg_ab_out : std_logic_vector (116 downto 0); signal reg_ba_in : std_logic_vector (31 downto 0); alias icsp_en : std_logic is reg_ab_out(116); alias icsp_write : std_logic is reg_ab_out(115); alias icsp_ctrl : std_logic is reg_ab_out(114); alias icsp_ecad : std_logic_vector (1 downto 0) is reg_ab_out(113 downto 112); alias icsp_ecbd : std_logic_vector (1 downto 0) is reg_ab_out(111 downto 110); alias icsp_odir : std_logic is reg_ab_out(109); alias icsp_idir : std_logic is reg_ab_out(108); alias icsp_cdir : std_logic is reg_ab_out(107); alias icsp_opos : std_logic_vector (4 downto 0) is reg_ab_out(106 downto 102); alias icsp_ipos : std_logic_vector (4 downto 0) is reg_ab_out(101 downto 97); alias icsp_cpos : std_logic_vector (3 downto 0) is reg_ab_out(96 downto 93); alias icsp_dlen : std_logic_vector (4 downto 0) is reg_ab_out(92 downto 88); alias icsp_clen : std_logic_vector (3 downto 0) is reg_ab_out(87 downto 84); alias icsp_cmd : std_logic_vector (3 downto 0) is reg_ab_out(83 downto 80); alias icsp_cdly : std_logic_vector (15 downto 0) is reg_ab_out(79 downto 64); alias icsp_ddly : std_logic_vector (15 downto 0) is reg_ab_out(63 downto 48); alias icsp_cseq : std_logic_vector (15 downto 0) is reg_ab_out(47 downto 32); alias icsp_data : std_logic_vector (31 downto 0) is reg_ab_out(31 downto 0); alias icsp_din : std_logic_vector (31 downto 0) is reg_ab_out(31 downto 0); alias icsp_dout : std_logic_vector (31 downto 0) is reg_ba_in(31 downto 0); begin icsp_enable <= icsp_en; /* debug(0) <= icsp_clk_in; debug(1) <= icsp_action; debug(2) <= icsp_addr(0); debug(3) <= icsp_write; */ pp_reg_sync_inst : entity work.pp_reg_sync generic map ( AB_WIDTH => 117, BA_WIDTH => 32 ) port map ( clk_a => s_axi_aclk, ping_a => axi_icsp_go, -- in, toggle pong_a => axi_icsp_done, -- out, toggle active => axi_icsp_active, -- out -- reg_ab_in => reg_ab_in, reg_ba_out => reg_ba_out, -- clk_b => icsp_clk_in, ping_b => icsp_go, -- out, toggle pong_b => icsp_done, -- in, toggle action => icsp_action, -- out -- reg_ba_in => reg_ba_in, reg_ab_out => reg_ab_out ); icsp_inst : entity work.icsp port map ( icsp_clk_in => icsp_clk_in, -- icsp_action => icsp_action_occ, icsp_active => icsp_active, -- icsp_write => icsp_write, icsp_ctrl => icsp_ctrl, icsp_cmd => icsp_cmd, -- icsp_clen => icsp_clen, icsp_dlen => icsp_dlen, -- icsp_cpos => icsp_cpos, icsp_opos => icsp_opos, icsp_ipos => icsp_ipos, -- icsp_cdir => icsp_cdir, icsp_odir => icsp_odir, icsp_idir => icsp_idir, -- icsp_ecbd => icsp_ecbd, icsp_ecad => icsp_ecad, -- icsp_cdly => icsp_cdly, icsp_ddly => icsp_ddly, -- icsp_cseq => icsp_cseq, icsp_din => icsp_din, -- icsp_dout => icsp_dout, icsp_latch => icsp_latch, -- icsp_clk_o => icsp_clk_o, icsp_clk_t => icsp_clk_t, -- icsp_dat_i => icsp_dat_i, icsp_dat_o => icsp_dat_o, icsp_dat_t => icsp_dat_t, -- debug => debug ); -------------------------------------------------------------------- -- One Clock Cycle Trigger on Action -------------------------------------------------------------------- action_proc : process (icsp_clk_in, icsp_action) variable icsp_action_v : std_logic := '0'; begin if rising_edge(icsp_clk_in) then icsp_action_occ <= '0'; if icsp_action = '1' and icsp_action_v = '0' then icsp_action_occ <= '1'; end if; icsp_action_v := icsp_action; end if; end process; -------------------------------------------------------------------- -- Falling Edge on Active ends Action -------------------------------------------------------------------- done_proc : process (icsp_clk_in, icsp_latch) variable icsp_active_v : std_logic := '0'; begin if rising_edge(icsp_clk_in) then if icsp_active = '0' and icsp_active_v = '1' then icsp_done <= icsp_go; -- turn around end if; icsp_active_v := icsp_active; end if; end process; -------------------------------------------------------------------- -- AXI Read/Write -------------------------------------------------------------------- reg_rwseq_proc : process ( s_axi_aclk, s_axi_areset_n, s_axi_ri, s_axi_wi ) variable index_v : integer := 0; variable addr_v : std_logic_vector (31 downto 0) := (others => '0'); variable arready_v : std_logic := '0'; variable rvalid_v : std_logic := '0'; variable awready_v : std_logic := '0'; variable wready_v : std_logic := '0'; variable bvalid_v : std_logic := '0'; variable rdata_v : std_logic_vector (31 downto 0); variable rresp_v : std_logic_vector (1 downto 0) := "00"; variable wdata_v : std_logic_vector (31 downto 0); variable wstrb_v : std_logic_vector (3 downto 0); variable bresp_v : std_logic_vector (1 downto 0) := "00"; type rw_state is ( idle_s, r_addr_s, r_icsp_s, r_data_s, w_addr_s, w_data_s, w_icsp_s, w_resp_s); variable state : rw_state := idle_s; variable reg_v : reg32_a(0 to 3) := (others => (others => '0')); begin if rising_edge(s_axi_aclk) then if s_axi_areset_n = '0' then addr_v := (others => '0'); arready_v := '0'; rvalid_v := '0'; awready_v := '0'; wready_v := '0'; bvalid_v := '0'; rdata_v := (others => '0'); wdata_v := (others => '0'); wstrb_v := (others => '0'); state := idle_s; else case state is when idle_s => rvalid_v := '0'; bvalid_v := '0'; if s_axi_ri.arvalid = '1' then -- address _is_ valid state := r_addr_s; elsif s_axi_wi.awvalid = '1' then -- address _is_ valid state := w_addr_s; end if; -- ARVALID ---> RVALID Master -- \ /` \ -- \, / \, -- ARREADY RREADY Slave when r_addr_s => addr_v := s_axi_ri.araddr; arready_v := '1'; -- ready for transfer axi_icsp_write <= '0'; axi_icsp_go <= not axi_icsp_go; -- toggle trigger state := r_icsp_s; when r_icsp_s => -- wait for icsp arready_v := '0'; -- done with addr if axi_icsp_active = '0' then reg_v(0) := axi_icsp_dout; state := r_data_s; end if; when r_data_s => -- deliver data rdata_v := reg_v(index_v); rresp_v := "00"; if s_axi_ri.rready = '1' then -- master ready rvalid_v := '1'; -- data is valid state := idle_s; end if; -- AWVALID ---> WVALID _ BREADY Master -- \ --__ /` \ --__ /` -- \, /--__ \, --_ / -- AWREADY -> WREADY ---> BVALID Slave when w_addr_s => addr_v := s_axi_wi.awaddr; awready_v := '1'; -- ready for transfer state := w_data_s; when w_data_s => awready_v := '0'; -- done with addr wready_v := '1'; -- ready for data if s_axi_wi.wvalid = '1' then -- data transfer wdata_v := s_axi_wi.wdata; wstrb_v := s_axi_wi.wstrb; update(reg_v(index_v), wdata_v, wstrb_v); bresp_v := "00"; -- transfer OK axi_icsp_write <= '1'; axi_icsp_din <= reg_v(0); axi_icsp_go <= not axi_icsp_go; state := w_icsp_s; end if; when w_icsp_s => -- wait for icsp wready_v := '0'; -- done with write if axi_icsp_active = '0' then state := w_resp_s; end if; when w_resp_s => if s_axi_wi.bready = '1' then -- master ready bvalid_v := '1'; -- response valid state := idle_s; end if; end case; end if; end if; index_v := to_integer(unsigned(addr_v(3 downto 0))) / 4; s_axi_ro.arready <= arready_v; s_axi_ro.rvalid <= rvalid_v; s_axi_wo.awready <= awready_v; s_axi_wo.wready <= wready_v; s_axi_wo.bvalid <= bvalid_v; s_axi_ro.rdata <= rdata_v; s_axi_ro.rresp <= rresp_v; s_axi_wo.bresp <= bresp_v; axi_icsp_ctrl <= '0' when index_v = 0 else '1'; axi_icsp_en <= reg_v(1)(31); axi_icsp_dlen <= reg_v(1)(28 downto 24); axi_icsp_clen <= reg_v(1)(23 downto 20); axi_icsp_cmd <= reg_v(1)(19 downto 16); axi_icsp_cseq <= reg_v(1)(15 downto 0); axi_icsp_cdly <= reg_v(2)(31 downto 16); axi_icsp_ddly <= reg_v(2)(15 downto 0); axi_icsp_ecad <= reg_v(3)(29 downto 28); axi_icsp_ecbd <= reg_v(3)(25 downto 24); axi_icsp_cdir <= reg_v(3)(23); axi_icsp_cpos <= reg_v(3)(19 downto 16); axi_icsp_idir <= reg_v(3)(15); axi_icsp_ipos <= reg_v(3)(12 downto 8); axi_icsp_odir <= reg_v(3)(7); axi_icsp_opos <= reg_v(3)(4 downto 0); end process; end RTL;