library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity hdmicap_v1_0_S00_AXI is generic ( -- Users to add parameters here -- User parameters ends -- Do not modify the parameters beyond this line -- Width of S_AXI data bus C_S_AXI_DATA_WIDTH : integer := 32; -- Width of S_AXI address bus C_S_AXI_ADDR_WIDTH : integer := 7 ); port ( -- Users to add ports here s_hdmi_clk : in std_logic; s_hdmi_lane : in std_logic_vector (5 downto 0); s_hdmi_pll_locked : in std_logic; s_hdmi_pll_psen : out std_logic; s_hdmi_pll_ps_inc : out std_logic; s_hdmi_pll_ps_done : in std_logic; s_hdmi_hsync : out std_logic; s_hdmi_vsync : out std_logic; s_hdmi_de : out std_logic; s_hdmi_out_we : out std_logic; s_hdmi_out_last : out std_logic; s_hdmi_out_valid : out std_logic; s_hdmi_in_ready : in std_logic; s_hdmi_tkeep : out std_logic_vector(3 downto 0); s_hdmi_out_data : out std_logic_vector(31 downto 0); s_hdmi_pixel_clock : out std_logic; s_hdmi_irq : out std_logic; -- User ports ends -- Do not modify the ports beyond this line -- Global Clock Signal S_AXI_ACLK : in std_logic; -- Global Reset Signal. This Signal is Active LOW S_AXI_ARESETN : in std_logic; -- Write address (issued by master, acceped by Slave) S_AXI_AWADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0); -- Write channel Protection type. This signal indicates the -- privilege and security level of the transaction, and whether -- the transaction is a data access or an instruction access. S_AXI_AWPROT : in std_logic_vector(2 downto 0); -- Write address valid. This signal indicates that the master signaling -- valid write address and control information. S_AXI_AWVALID : in std_logic; -- Write address ready. This signal indicates that the slave is ready -- to accept an address and associated control signals. S_AXI_AWREADY : out std_logic; -- Write data (issued by master, acceped by Slave) S_AXI_WDATA : in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0); -- Write strobes. This signal indicates which byte lanes hold -- valid data. There is one write strobe bit for each eight -- bits of the write data bus. S_AXI_WSTRB : in std_logic_vector((C_S_AXI_DATA_WIDTH/8)-1 downto 0); -- Write valid. This signal indicates that valid write -- data and strobes are available. S_AXI_WVALID : in std_logic; -- Write ready. This signal indicates that the slave -- can accept the write data. S_AXI_WREADY : out std_logic; -- Write response. This signal indicates the status -- of the write transaction. S_AXI_BRESP : out std_logic_vector(1 downto 0); -- Write response valid. This signal indicates that the channel -- is signaling a valid write response. S_AXI_BVALID : out std_logic; -- Response ready. This signal indicates that the master -- can accept a write response. S_AXI_BREADY : in std_logic; -- Read address (issued by master, acceped by Slave) S_AXI_ARADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0); -- Protection type. This signal indicates the privilege -- and security level of the transaction, and whether the -- transaction is a data access or an instruction access. S_AXI_ARPROT : in std_logic_vector(2 downto 0); -- Read address valid. This signal indicates that the channel -- is signaling valid read address and control information. S_AXI_ARVALID : in std_logic; -- Read address ready. This signal indicates that the slave is -- ready to accept an address and associated control signals. S_AXI_ARREADY : out std_logic; -- Read data (issued by slave) S_AXI_RDATA : out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0); -- Read response. This signal indicates the status of the -- read transfer. S_AXI_RRESP : out std_logic_vector(1 downto 0); -- Read valid. This signal indicates that the channel is -- signaling the required read data. S_AXI_RVALID : out std_logic; -- Read ready. This signal indicates that the master can -- accept the read data and response information. S_AXI_RREADY : in std_logic ); end hdmicap_v1_0_S00_AXI; architecture arch_imp of hdmicap_v1_0_S00_AXI is component fifo_generator_0 is port ( rst : in std_logic; wr_clk : in std_logic; rd_clk : in std_logic; din : in std_logic_vector(31 downto 0); wr_en : in std_logic; rd_en : in std_logic; dout : out std_logic_vector(31 downto 0); full : out std_logic; empty : out std_logic ); end component fifo_generator_0; signal pixel_fifo_reset :std_logic; signal axi_fifo_read_select : std_logic; signal axi_fifo_read_select_reg : std_logic; signal ss_hdmi_out_data : std_logic_vector(31 downto 0); signal pixel_fifo_axi_side : std_logic_vector(31 downto 0); signal pixel_fifo_empty : std_logic; signal pixel_fifo_full : std_logic; signal s_hdmi_out_last_sig : std_logic; -- AXI4LITE signals signal axi_awaddr : std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0); signal axi_awready : std_logic; signal axi_wready : std_logic; signal axi_bresp : std_logic_vector(1 downto 0); signal axi_bvalid : std_logic; signal axi_araddr : std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0); signal axi_arready : std_logic; signal axi_rdata : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0); signal axi_rresp : std_logic_vector(1 downto 0); signal axi_rvalid : std_logic; -- Example-specific design signals -- local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH -- ADDR_LSB is used for addressing 32/64 bit registers/memories -- ADDR_LSB = 2 for 32 bits (n downto 2) -- ADDR_LSB = 3 for 64 bits (n downto 3) constant ADDR_LSB : integer := (C_S_AXI_DATA_WIDTH/32)+ 1; constant OPT_MEM_ADDR_BITS : integer := 4; ------------------------------------------------ ---- Signals for user logic register space example -------------------------------------------------- signal hdmi_clk_counter :std_logic_vector(31 downto 0); signal hdmi_lane :std_logic_vector(3 downto 0); signal hdmi_reset :std_logic; signal s_hdmi_pll_ps_ctr : std_logic_vector(7 downto 0); signal s_hdmi_pll_ps_target : std_logic_vector(7 downto 0); signal s_hdmi_pll_ps_pending : std_logic; signal lane_shifter : std_logic_vector((3 * 12) - 1 downto 0); signal lane_sample : std_logic_vector((3 * 10) - 1 downto 0); signal dlane_sample : std_logic_vector((3 * 10) - 1 downto 0); signal lane_sample_old : std_logic_vector((3 * 10) - 1 downto 0); signal s_pixel_clk : std_logic; signal s_pixel_clk_high : std_logic_vector(1 downto 0); signal ctr_vert_total : std_logic_vector(12 downto 0); signal meas_vert_total : std_logic_vector(12 downto 0); signal ctr_vert_sync : std_logic_vector(12 downto 0); signal meas_vert_sync : std_logic_vector(12 downto 0); signal ctr_vert_fp : std_logic_vector(12 downto 0); signal meas_vert_fp : std_logic_vector(12 downto 0); signal ctr_vert_bp : std_logic_vector(12 downto 0); signal meas_vert_bp : std_logic_vector(12 downto 0); signal ctr_horz_total : std_logic_vector(12 downto 0); signal meas_horz_total : std_logic_vector(12 downto 0); signal ctr_horz_sync : std_logic_vector(12 downto 0); signal meas_horz_sync : std_logic_vector(12 downto 0); signal ctr_horz_fp : std_logic_vector(12 downto 0); signal meas_horz_fp : std_logic_vector(12 downto 0); signal ctr_horz_bp : std_logic_vector(12 downto 0); signal meas_horz_bp : std_logic_vector(12 downto 0); signal meas_horz_data_sample_line : std_logic_vector(12 downto 0); signal meas_vsync_h_pos : std_logic_vector(12 downto 0); signal ctr_pixels_in_frame : std_logic_vector(25 downto 0); signal meas_pixels_in_frame : std_logic_vector(25 downto 0); signal ctr_data_clocks_in_frame : std_logic_vector(25 downto 0); signal meas_data_clocks_in_frame : std_logic_vector(25 downto 0); signal ctr_data_clocks_in_line : std_logic_vector(25 downto 0); signal ctr_data_clocks_in_vb : std_logic_vector(25 downto 0); signal meas_data_clocks_in_vb : std_logic_vector(25 downto 0); signal ctr_control_clocks_in_frame : std_logic_vector(25 downto 0); signal meas_control_clocks_in_frame : std_logic_vector(25 downto 0); signal ctr_control_clocks_in_line : std_logic_vector(25 downto 0); signal ctr_control_clocks_in_vb : std_logic_vector(25 downto 0); signal meas_control_clocks_in_vb : std_logic_vector(25 downto 0); signal ctr_hdmi_perr_control_pre_preamble : std_logic_vector(12 downto 0); signal meas_hdmi_perr_control_pre_preamble : std_logic_vector(12 downto 0); signal ctr_hdmi_control_pre_preamble : std_logic_vector(2 downto 0); signal ctr_vsyncs : std_logic_vector(15 downto 0); signal meas_vsync_stamp : std_logic_vector(15 downto 0); signal hold_measurement_updates : std_logic; signal hold_measurement_updates_px : std_logic; signal ctr_escapes : std_logic_vector((32 * 3) - 1 downto 0); -- for each of the 3 channels signal meas_escapes : std_logic_vector((32 * 3) -1 downto 0); signal clear_escapes_tog : std_logic; signal clear_escapes_sen : std_logic; signal timestamp_escapes_captured : std_logic_vector(31 downto 0); signal c : std_logic_vector(5 downto 0); signal hsync : std_logic; signal vsync : std_logic; signal hsync_old : std_logic; signal vsync_old : std_logic; signal is_back : std_logic; signal is_back_v : std_logic; signal hsync_active_level : std_logic; signal vsync_active_level : std_logic; signal soft_reset_tog : std_logic; signal soft_reset_sen_px : std_logic; constant IRQ_SOURCE_TRIG_COMPLETED : integer := 0; constant IRQ_SOURCE_PLL_LOCK_CHANGE : integer := 1; signal a_irq_sources_tog : std_logic_vector(1 downto 0); signal a_irq_sources_sen : std_logic_vector(1 downto 0); signal a_irq_sources_status : std_logic_vector(1 downto 0); constant DM_CONTROL : std_logic_vector := "000"; constant DM_VIDEO : std_logic_vector := "001"; constant DM_DATA : std_logic_vector := "010"; constant DM_PRE_GUARD1 : std_logic_vector := "011"; constant DM_PRE_GUARD2 : std_logic_vector := "100"; constant DM_POST_DATA_GUARD2 : std_logic_vector := "101"; signal tmds_decode_mode : std_logic_vector(2 downto 0); signal control_preamble_count : std_logic_vector(3 downto 0); signal control_pattern_seen : std_logic; -- [ delayed nad (1) ] [ cc (2) ] [ dout 8 ] constant lane_state_width : integer := 11; signal lane_state : std_logic_vector((3 * lane_state_width) - 1 downto 0); signal dlane_state : std_logic_vector((3 * lane_state_width) - 1 downto 0); signal sync_ctr : std_logic_vector(2 downto 0); -- b3..b1 = 0..4 pair sample, b0 = 1=offset shift inside pair signal sync_offset : std_logic_vector(3 downto 0); signal sync_offset_axi : std_logic_vector(3 downto 0); signal sync_offset_manual : std_logic; signal sync_offset_changed_tog : std_logic; signal sync_offset_changed_sen : std_logic; signal capture_only_raw : std_logic; signal capture_only_data : std_logic; signal capture_continuous : std_logic; signal pixel_fifo_empty_axi : std_logic; signal since_last_sync : std_logic_vector(15 downto 0); signal coding_sync_ctr : std_logic_vector(31 downto 0); signal terc4 : std_logic_vector(11 downto 0); signal terc4_illegal : std_logic; signal ctr_terc4_illegals_in_frame : std_logic_vector(15 downto 0); signal meas_terc4_illegals_in_frame : std_logic_vector(15 downto 0); signal data_header : std_logic_vector(31 downto 0); signal ctr_packet : std_logic_vector(5 downto 0); signal ctr_axi_clocks : std_logic_vector(15 downto 0); signal shifter_pixel_ctr_samples : std_logic_vector((4 * 32) -1 downto 0); signal hdmi_clk_counter_start : std_logic_vector(31 downto 0); signal guard_ch1_133 : std_logic; signal guard_ch2_2cc : std_logic; signal slv_reg_rden : std_logic; signal slv_reg_wren : std_logic; signal reg_data_out :std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0); signal byte_index : integer; signal armed_tog : std_logic; signal armed_sen : std_logic; signal s_hdmi_in_ready_axi : std_logic; signal armed: std_logic; signal triggered : std_logic; signal filtered_trigger : std_logic; signal completed : std_logic; signal showed_last : std_logic; signal dma_length_px : std_logic_vector(31 downto 0); signal dma_ctr_px : std_logic_vector(31 downto 0); signal dma_ctr_used : std_logic_vector(31 downto 0); signal dma_ctr_read_from_fifo : std_logic_vector(31 downto 0); signal clear_irq_tog : std_logic; signal clear_irq_sen : std_logic; signal irq : std_logic; signal s_hdmi_pll_locked_old : std_logic; begin streamfifo : component fifo_generator_0 port map ( rst => pixel_fifo_reset, wr_clk => s_pixel_clk, rd_clk => S_AXI_ACLK, din => ss_hdmi_out_data, wr_en => filtered_trigger, rd_en => s_hdmi_in_ready, --axi_fifo_read_select_reg, dout => s_hdmi_out_data, -- pixel_fifo_axi_side, full => pixel_fifo_full, empty => pixel_fifo_empty ); -- I/O Connections assignments S_AXI_AWREADY <= axi_awready; S_AXI_WREADY <= axi_wready; S_AXI_BRESP <= axi_bresp; S_AXI_BVALID <= axi_bvalid; S_AXI_ARREADY <= axi_arready; S_AXI_RDATA <= axi_rdata; S_AXI_RRESP <= axi_rresp; S_AXI_RVALID <= axi_rvalid; -- Implement axi_awready generation -- axi_awready is asserted for one S_AXI_ACLK clock cycle when both -- S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is -- de-asserted when reset is low. s_hdmi_tkeep <= "1111"; s_hdmi_out_valid <= not pixel_fifo_empty; s_hdmi_out_last <= s_hdmi_out_last_sig; process (S_AXI_ACLK) begin if rising_edge(S_AXI_ACLK) then if S_AXI_ARESETN = '0' then axi_awready <= '0'; else if (axi_awready = '0' and S_AXI_AWVALID = '1' and S_AXI_WVALID = '1') then -- slave is ready to accept write address when -- there is a valid write address and write data -- on the write address and data bus. This design -- expects no outstanding transactions. axi_awready <= '1'; else axi_awready <= '0'; end if; end if; end if; end process; -- Implement axi_awaddr latching -- This process is used to latch the address when both -- S_AXI_AWVALID and S_AXI_WVALID are valid. process (S_AXI_ACLK) begin if rising_edge(S_AXI_ACLK) then if S_AXI_ARESETN = '0' then axi_awaddr <= (others => '0'); else if (axi_awready = '0' and S_AXI_AWVALID = '1' and S_AXI_WVALID = '1') then -- Write Address latching axi_awaddr <= S_AXI_AWADDR; end if; end if; end if; end process; -- Implement axi_wready generation -- axi_wready is asserted for one S_AXI_ACLK clock cycle when both -- S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is -- de-asserted when reset is low. process (S_AXI_ACLK) begin if rising_edge(S_AXI_ACLK) then if S_AXI_ARESETN = '0' then axi_wready <= '0'; else if (axi_wready = '0' and S_AXI_WVALID = '1' and S_AXI_AWVALID = '1') then -- slave is ready to accept write data when -- there is a valid write address and write data -- on the write address and data bus. This design -- expects no outstanding transactions. axi_wready <= '1'; else axi_wready <= '0'; end if; end if; end if; end process; -- Implement memory mapped register select and write logic generation -- The write data is accepted and written to memory mapped registers when -- axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to -- select byte enables of slave registers while writing. -- These registers are cleared when reset (active low) is applied. -- Slave register write enable is asserted when valid address and data are available -- and the slave is ready to accept the write address and write data. slv_reg_wren <= axi_wready and S_AXI_WVALID and axi_awready and S_AXI_AWVALID ; process (S_AXI_ACLK) variable loc_addr :std_logic_vector(OPT_MEM_ADDR_BITS downto 0); begin if rising_edge(S_AXI_ACLK) then if S_AXI_ARESETN = '0' then s_hdmi_pll_psen <= '0'; s_hdmi_pll_ps_inc <= '0'; s_hdmi_pll_ps_ctr <= (others => '0'); s_hdmi_pll_ps_target <= (others => '0'); s_hdmi_pll_ps_pending <= '0'; armed_tog <= '0'; soft_reset_tog <= '0'; clear_irq_tog <= '0'; capture_only_raw <= '0'; showed_last <= '0'; dma_length_px <= (others => '0'); hold_measurement_updates <= '0'; dma_ctr_read_from_fifo <= (others => '0'); else loc_addr := axi_awaddr(ADDR_LSB + OPT_MEM_ADDR_BITS downto ADDR_LSB); if (slv_reg_wren = '1') then case loc_addr is when b"00000" => if (S_AXI_WSTRB(0) = '1') then s_hdmi_pll_ps_target <= S_AXI_WDATA(7 downto 0); end if; -- start full data capture next vsync when b"00001" => if (S_AXI_WSTRB(0) = '1') then if S_AXI_WDATA(1) = '1' then sync_offset_axi <= S_AXI_WDATA(7 downto 4); sync_offset_manual <= S_AXI_WDATA(3); sync_offset_changed_tog <= not sync_offset_changed_tog; end if; if S_AXI_WDATA(0) = '1' then showed_last <= '0'; armed_tog <= not armed_tog; dma_ctr_used <= dma_length_px; dma_ctr_read_from_fifo <= (others => '0'); end if; end if; when b"00010" => if (S_AXI_WSTRB(0) = '1') then capture_only_data <= S_AXI_WDATA(6); -- only capture data content capture_continuous <= S_AXI_WDATA(5); -- 0 = begin and end on vsync, 1 = begin anywhere pixel_fifo_reset <= S_AXI_WDATA(4); capture_only_raw <= S_AXI_WDATA(3); if S_AXI_WDATA(2) = '1' then soft_reset_tog <= not soft_reset_tog; end if; vsync_active_level <= S_AXI_WDATA(1); hsync_active_level <= S_AXI_WDATA(0); end if; when b"00011" => if (S_AXI_WSTRB(0) = '1') then -- inform async sources they are cleared clear_irq_tog <= not clear_irq_tog; a_irq_sources_status <= (others => '0'); irq <= '0'; end if; when b"00100" => if (S_AXI_WSTRB(0) = '1') then dma_length_px <= S_AXI_WDATA; end if; when b"00101" => if (S_AXI_WSTRB(0) = '1') then if S_AXI_WDATA(0) = '1' then -- transfers escapes counters into meas and clears escape counters clear_escapes_tog <= not clear_escapes_tog; end if; end if; when b"00110" => if (S_AXI_WSTRB(0) = '1') then hold_measurement_updates <= S_AXI_WDATA(0); end if; when others => end case; end if; -- dma completion signal... in AXI clock domain pixel_fifo_empty_axi <= pixel_fifo_empty; s_hdmi_in_ready_axi <= s_hdmi_in_ready; if s_hdmi_in_ready_axi = '1' and pixel_fifo_empty_axi = '0' then dma_ctr_read_from_fifo <= std_logic_vector(unsigned(dma_ctr_read_from_fifo) + 1); if dma_ctr_used /= "00000000000000000000000000000000" then dma_ctr_used <= std_logic_vector(unsigned(dma_ctr_used) - 1); end if; end if; s_hdmi_out_last_sig <= '0'; if dma_ctr_used = "00000000000000000000000000000001" or completed = '1' then s_hdmi_out_last_sig <= '1'; end if; -- can't do this on pixel clock domain as no clock when unlocked s_hdmi_pll_locked_old <= s_hdmi_pll_locked; if (s_hdmi_pll_locked /= s_hdmi_pll_locked_old) then a_irq_sources_tog(IRQ_SOURCE_PLL_LOCK_CHANGE) <= not a_irq_sources_tog(IRQ_SOURCE_PLL_LOCK_CHANGE); end if; -- async irq management a_irq_sources_sen <= a_irq_sources_tog; for n in 0 to 1 loop if a_irq_sources_sen(n) /= a_irq_sources_tog(n) then a_irq_sources_status(n) <= '1'; irq <= '1'; end if; end loop; -- he is a 1-clock strobe s_hdmi_pll_psen <= '0'; if s_hdmi_pll_ps_target /= s_hdmi_pll_ps_ctr then if s_hdmi_pll_ps_pending = '0' then s_hdmi_pll_psen <= '1'; s_hdmi_pll_ps_pending <= '1'; if s_hdmi_pll_ps_target < s_hdmi_pll_ps_ctr then s_hdmi_pll_ps_inc <= '0'; else s_hdmi_pll_ps_inc <= '1'; end if; end if; if s_hdmi_pll_ps_pending = '1' and s_hdmi_pll_ps_done = '1' then if s_hdmi_pll_ps_target < s_hdmi_pll_ps_ctr then s_hdmi_pll_ps_ctr <= std_logic_vector(unsigned(s_hdmi_pll_ps_ctr) - 1); else s_hdmi_pll_ps_ctr <= std_logic_vector(unsigned(s_hdmi_pll_ps_ctr) + 1); end if; s_hdmi_pll_ps_pending <= '0'; end if; end if; end if; dlane_sample <= lane_sample; dlane_state <= lane_state; end if; end process; -- Implement write response logic generation -- The write response and response valid signals are asserted by the slave -- when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. -- This marks the acceptance of address and indicates the status of -- write transaction. process (S_AXI_ACLK) begin if rising_edge(S_AXI_ACLK) then if S_AXI_ARESETN = '0' then axi_bvalid <= '0'; axi_bresp <= "00"; --need to work more on the responses else if (axi_awready = '1' and S_AXI_AWVALID = '1' and axi_wready = '1' and S_AXI_WVALID = '1' and axi_bvalid = '0' ) then axi_bvalid <= '1'; axi_bresp <= "00"; elsif (S_AXI_BREADY = '1' and axi_bvalid = '1') then --check if bready is asserted while bvalid is high) axi_bvalid <= '0'; -- (there is a possibility that bready is always asserted high) end if; end if; end if; end process; -- Implement axi_arready generation -- axi_arready is asserted for one S_AXI_ACLK clock cycle when -- S_AXI_ARVALID is asserted. axi_awready is -- de-asserted when reset (active low) is asserted. -- The read address is also latched when S_AXI_ARVALID is -- asserted. axi_araddr is reset to zero on reset assertion. process (S_AXI_ACLK) begin if rising_edge(S_AXI_ACLK) then if S_AXI_ARESETN = '0' then axi_arready <= '0'; axi_araddr <= (others => '1'); else if (axi_arready = '0' and S_AXI_ARVALID = '1') then -- indicates that the slave has acceped the valid read address axi_arready <= '1'; -- Read Address latching axi_araddr <= S_AXI_ARADDR; else axi_arready <= '0'; end if; end if; end if; end process; -- Implement axi_arvalid generation -- axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both -- S_AXI_ARVALID and axi_arready are asserted. The slave registers -- data are available on the axi_rdata bus at this instance. The -- assertion of axi_rvalid marks the validity of read data on the -- bus and axi_rresp indicates the status of read transaction.axi_rvalid -- is deasserted on reset (active low). axi_rresp and axi_rdata are -- cleared to zero on reset (active low). process (S_AXI_ACLK) begin if rising_edge(S_AXI_ACLK) then if S_AXI_ARESETN = '0' then axi_rvalid <= '0'; axi_rresp <= "00"; else if (axi_arready = '1' and S_AXI_ARVALID = '1' and axi_rvalid = '0') then -- Valid read data is available at the read data bus axi_rvalid <= '1'; axi_rresp <= "00"; -- 'OKAY' response elsif (axi_rvalid = '1' and S_AXI_RREADY = '1') then -- Read data is accepted by the master axi_rvalid <= '0'; end if; end if; end if; end process; -- simulate the serdes at 10 x pixel rate (no serdes on zynq7z20) -- 270MHz at 576p process (s_hdmi_clk) begin if rising_edge(s_hdmi_clk) then if hdmi_reset = '0' or s_hdmi_pll_locked = '0' then sync_ctr <= (others => '0'); s_pixel_clk <= '0'; else if (sync_ctr = "100") then sync_ctr <= "000"; else sync_ctr <= std_logic_vector(unsigned(sync_ctr) + 1); end if; -- first level shifter needs to hold 12 bits so we can select the 10 we want -- n1 -> b11 -> b9 -> b7 -> b5 -> b3 -> b1 -> -- n0 -> b10 -> b8 -> b6 -> b4 -> b2 -> b0 -> for n in 0 to 2 loop for m in 0 to 4 loop lane_shifter((n * 12) + (m * 2) + 1) <= lane_shifter((n * 12) + (m * 2) + 3); lane_shifter((n * 12) + (m * 2)) <= lane_shifter((n * 12) + (m * 2) + 2); -- lane_shifter((n * 12) + (m * 2) + 3) <= lane_shifter((n * 12) + (m * 2) + 1); -- lane_shifter((n * 12) + (m * 2) + 2) <= lane_shifter((n * 12) + (m * 2) + 0); end loop; lane_shifter((n * 12) + 11) <= s_hdmi_lane(n + 3); lane_shifter((n * 12) + 10) <= s_hdmi_lane(n); -- lane_shifter((n * 12) + 1) <= s_hdmi_lane(n + 3); -- lane_shifter((n * 12) + 0) <= s_hdmi_lane(n); end loop; -- sample the tmds 10-bit data at the sync point -- because they come in pairs due to needing DDR clock, the LSB -- of the sync offset selects whether to offset by one bit inside the pairs -- -- also synthesize the locked pixel clock with 50% duty if (sync_ctr = sync_offset(3 downto 1)) then if (sync_offset(0) = '0') then lane_sample(9 downto 0) <= lane_shifter(9 downto 0); lane_sample(19 downto 10) <= lane_shifter(21 downto 12); lane_sample(29 downto 20) <= lane_shifter(33 downto 24); else lane_sample(9 downto 0) <= lane_shifter(10 downto 1); lane_sample(19 downto 10) <= lane_shifter(22 downto 13); lane_sample(29 downto 20) <= lane_shifter(34 downto 25); end if; lane_sample_old <= lane_sample; s_pixel_clk <= '1'; s_pixel_clk_high <= "10"; end if; if s_pixel_clk = '1' then if s_pixel_clk_high = "00" then s_pixel_clk <= '0'; else s_pixel_clk_high <= std_logic_vector(unsigned(s_pixel_clk_high) - 1); end if; end if; end if; hdmi_reset <= S_AXI_ARESETN; end if; end process; process(s_pixel_clk, completed, irq, hsync, vsync) begin s_hdmi_pixel_clock <= s_pixel_clk; s_hdmi_irq <= irq; s_hdmi_hsync <= hsync; s_hdmi_vsync <= vsync; end process; -- everything else can happen at the pixel rate -- 27MHz at 576p process (s_pixel_clk) variable o : std_logic_vector(11 downto 0); variable d : std_logic_vector(8 downto 0); variable hsync_now : std_logic; variable vsync_now : std_logic; variable bump_esc : std_logic; begin if rising_edge(s_pixel_clk) then soft_reset_sen_px <= soft_reset_tog; if hdmi_reset = '0' or (soft_reset_sen_px /= soft_reset_tog) then since_last_sync <= (others => '0'); sync_offset <= (others => '0'); coding_sync_ctr <= (others => '0'); hdmi_clk_counter <= (others => '0'); is_back <= '0'; is_back_v <= '0'; triggered <= '0'; completed <= '0'; armed_sen <= '0'; armed <= '0'; meas_horz_total <= (others => '0'); meas_horz_sync <= (others => '0'); meas_horz_fp <= (others => '0'); meas_horz_bp <= (others => '0'); meas_vert_total <= (others => '0'); meas_vert_sync <= (others => '0'); meas_vert_fp <= (others => '0'); meas_vert_bp <= (others => '0'); ctr_pixels_in_frame <= (others => '0'); ctr_data_clocks_in_line <= (others => '0'); ctr_data_clocks_in_frame <= (others => '0'); tmds_decode_mode <= DM_CONTROL; control_preamble_count <= (others => '0'); ctr_hdmi_control_pre_preamble <= (others => '0'); ctr_hdmi_perr_control_pre_preamble <= (others => '0'); hsync <= '0'; vsync <= '0'; c <= (others => '0'); guard_ch1_133 <= '0'; guard_ch2_2cc <= '0'; else ctr_pixels_in_frame <= std_logic_vector(unsigned(ctr_pixels_in_frame) + 1); hdmi_clk_counter <= std_logic_vector(unsigned (hdmi_clk_counter) + 1); -- perform all the possible interpretations -- EVERY OUTPUT IS REGISTERED control_pattern_seen <= '0'; guard_ch1_133 <= '0'; guard_ch2_2cc <= '0'; clear_escapes_sen <= clear_escapes_tog; if clear_escapes_sen /= clear_escapes_tog then timestamp_escapes_captured <= hdmi_clk_counter; end if; filtered_trigger <= (triggered and (not capture_only_data)) or (capture_only_data and completed and (not showed_last)); -- control coding for n in 0 to 2 loop bump_esc := '0'; case lane_sample((n * 10) + 9 downto (n * 10) + 0) is when "1011001100" => -- video guard band ch0/2 if n = 2 then guard_ch2_2cc <= '1'; end if; bump_esc := '1'; when "0100110011" => -- video ch1, or data island guard band ch 1/2 if n = 1 then guard_ch1_133 <= '1'; end if; bump_esc := '1'; when "1101010100" => c((n * 2) + 1 downto (n * 2)) <= "00"; control_pattern_seen <= '1'; bump_esc := '1'; when "0010101011" => -- yes c((n * 2) + 1 downto (n * 2)) <= "01"; control_pattern_seen <= '1'; bump_esc := '1'; when "0101010100" => c((n * 2) + 1 downto (n * 2)) <= "10"; control_pattern_seen <= '1'; bump_esc := '1'; when "1010101011" => -- yes c((n * 2) + 1 downto (n * 2)) <= "11"; control_pattern_seen <= '1'; bump_esc := '1'; when others => end case; if clear_escapes_sen = clear_escapes_tog then if bump_esc = '1' then ctr_escapes((n * 32) + 31 downto (n * 32)) <= std_logic_vector(unsigned (ctr_escapes((n * 32) + 31 downto (n * 32))) + 1); end if; else meas_escapes((n * 32) + 31 downto (n * 32)) <= ctr_escapes((n * 32) + 31 downto (n * 32)); ctr_escapes((n * 32) + 31 downto (n * 32)) <= (others => '0'); end if; -- TERC4 (data island) coding terc4_illegal <= '0'; case lane_sample((n * 10) + 9 downto (n * 10) + 0) is when "1010011100" => terc4((n * 4) + 3 downto (n * 4)) <= "0000"; when "1001100011" => terc4((n * 4) + 3 downto (n * 4)) <= "0001"; when "1011100100" => terc4((n * 4) + 3 downto (n * 4)) <= "0010"; when "1011100010" => terc4((n * 4) + 3 downto (n * 4)) <= "0011"; when "0101110001" => terc4((n * 4) + 3 downto (n * 4)) <= "0100"; when "0100011110" => terc4((n * 4) + 3 downto (n * 4)) <= "0101"; when "0110001110" => terc4((n * 4) + 3 downto (n * 4)) <= "0110"; when "0100111100" => terc4((n * 4) + 3 downto (n * 4)) <= "0111"; when "1011001100" => terc4((n * 4) + 3 downto (n * 4)) <= "1000"; when "0100111001" => terc4((n * 4) + 3 downto (n * 4)) <= "1001"; when "0110011100" => terc4((n * 4) + 3 downto (n * 4)) <= "1010"; when "1011000110" => terc4((n * 4) + 3 downto (n * 4)) <= "1011"; when "1010001110" => terc4((n * 4) + 3 downto (n * 4)) <= "1100"; when "1001110001" => terc4((n * 4) + 3 downto (n * 4)) <= "1101"; when "0101100011" => terc4((n * 4) + 3 downto (n * 4)) <= "1110"; when "1011000011" => terc4((n * 4) + 3 downto (n * 4)) <= "1111"; when others => terc4_illegal <= '1'; end case; -- video coding -- data one sample delayed from _old, d is not registered here if lane_sample_old((n * 10) + 9) = '1' then d := lane_sample_old((n * 10) + 8 downto (n * 10)) xor "011111111"; else d := lane_sample_old((n * 10) + 8 downto (n * 10)); end if; if tmds_decode_mode /= DM_VIDEO and (tmds_decode_mode /= DM_PRE_GUARD2 or guard_ch2_2cc /= '1') then o := ( 9 => vsync, 8 => hsync, others => '0'); elsif lane_sample_old((n * 10) + 8) = '1' then o := ( 9 => vsync, 8 => hsync, 7 => d(7) XOR d(6), 6 => d(6) XOR d(5), 5 => d(5) XOR d(4), 4 => d(4) XOR d(3), 3 => d(3) XOR d(2), 2 => d(2) XOR d(1), 1 => d(1) XOR d(0), 0 => d(0), others => '0'); else o := ( 9 => vsync, 8 => hsync, 7 => d(7) XNOR d(6), 6 => d(6) XNOR d(5), 5 => d(5) XNOR d(4), 4 => d(4) XNOR d(3), 3 => d(3) XNOR d(2), 2 => d(2) XNOR d(1), 1 => d(1) XNOR d(0), 0 => d(0), others => '0'); end if; lane_state((n * lane_state_width) + 10 downto n * lane_state_width) <= o(10 downto 0); end loop; -- by default, issue the raw 10-bit data ss_hdmi_out_data <= ( 31 => '1', 30 => '0', -- raw 10-bit data 29 => lane_sample(29), 28 => lane_sample(28), 27 => lane_sample(27), 26 => lane_sample(26), 25 => lane_sample(25), 24 => lane_sample(24), 23 => lane_sample(23), 22 => lane_sample(22), 21 => lane_sample(21), 20 => lane_sample(20), 19 => lane_sample(19), 18 => lane_sample(18), 17 => lane_sample(17), 16 => lane_sample(16), 15 => lane_sample(15), 14 => lane_sample(14), 13 => lane_sample(13), 12 => lane_sample(12), 11 => lane_sample(11), 10 => lane_sample(10), 9 => lane_sample(9), 8 => lane_sample(8), 7 => lane_sample(7), 6 => lane_sample(6), 5 => lane_sample(5), 4 => lane_sample(4), 3 => lane_sample(3), 2 => lane_sample(2), 1 => lane_sample(1), 0 => lane_sample(0), others => '0' ); -- process the registered information from the previous clock s_hdmi_de <= '0'; case tmds_decode_mode is when DM_CONTROL => ctr_control_clocks_in_frame <= std_logic_vector(unsigned(ctr_control_clocks_in_frame) + 1); ctr_control_clocks_in_line <= std_logic_vector(unsigned(ctr_control_clocks_in_line) + 1); if c(5 downto 2) = "0001" or c(5 downto 2) = "0101" then -- video or data if control_preamble_count = "0111" then -- he sends exactly 8 to warn us tmds_decode_mode <= DM_PRE_GUARD1; -- then he will send 2 x guard band ctr_hdmi_control_pre_preamble <= (others => '0'); if ctr_hdmi_control_pre_preamble < "100" then ctr_hdmi_perr_control_pre_preamble <= std_logic_vector(unsigned(ctr_hdmi_perr_control_pre_preamble)); end if; control_preamble_count <= (others => '0'); else control_preamble_count <= std_logic_vector(unsigned(control_preamble_count) + 1); end if; else if (ctr_hdmi_control_pre_preamble /= "111") then ctr_hdmi_control_pre_preamble <= std_logic_vector(unsigned(ctr_hdmi_control_pre_preamble) + 1); end if; control_preamble_count <= (others => '0'); end if; hsync <= c(0); vsync <= c(1); if guard_ch1_133 = '1' then -- data or video guard tmds_decode_mode <= DM_PRE_GUARD2; hsync <= terc4(0); vsync <= terc4(1); end if; when DM_VIDEO => -- no postamble on video he just starts sending ctrl data when done if control_pattern_seen = '1' then tmds_decode_mode <= DM_CONTROL; hsync <= c(0); vsync <= c(1); else s_hdmi_de <= '1'; -- override the output to be the decoded RGB data if capture_only_raw = '0' then ss_hdmi_out_data <= ( 31 => '1', -- decoded data (A) 30 => '1', -- 29 => '1', -- rgba pixel data 28 => '1', 27 => '1', 26 => '1', 25 => '1', 24 => '1', 23 => lane_state(7), -- B 22 => lane_state(6), 21 => lane_state(5), 20 => lane_state(4), 19 => lane_state(3), 18 => lane_state(2), 17 => lane_state(1), 16 => lane_state(0), 15 => lane_state(18), -- G 14 => lane_state(17), 13 => lane_state(16), 12 => lane_state(15), 11 => lane_state(14), 10 => lane_state(13), 9 => lane_state(12), 8 => lane_state(11), 7 => lane_state(29), -- R 6 => lane_state(28), 5 => lane_state(27), 4 => lane_state(26), 3 => lane_state(25), 2 => lane_state(24), 1 => lane_state(23), 0 => lane_state(22), others => '0'); end if; end if; when DM_DATA => -- 2 clock postamble on data on ch1 + 2 only (ch0 has TERC4 syncs) -- override the output to be the decoded RGB data if capture_only_raw = '0' then ss_hdmi_out_data <= ( 31 => '1', -- decoded data 30 => '1', 29 => '1', 28 => '1', 27 => '1', 26 => '1', 25 => '1', 24 => '0', -- data island 23 => terc4(11), 22 => terc4(10), 21 => terc4(9), 20 => terc4(8), 15 => terc4(7), 14 => terc4(6), 13 => terc4(5), 12 => terc4(4), 7 => terc4(3), 6 => terc4(2), 5 => terc4(1), 4 => terc4(0), others => '0'); end if; ctr_packet <= std_logic_vector(unsigned(ctr_packet) + 1); filtered_trigger <= triggered; if terc4_illegal = '1' and ctr_terc4_illegals_in_frame /= "1111111111111111" then ctr_terc4_illegals_in_frame <= std_logic_vector(unsigned(ctr_terc4_illegals_in_frame) + 1); end if; ctr_data_clocks_in_frame <= std_logic_vector(unsigned(ctr_data_clocks_in_frame) + 1); ctr_data_clocks_in_line <= std_logic_vector(unsigned(ctr_data_clocks_in_line) + 1); if guard_ch1_133 = '1' then --postamble tmds_decode_mode <= DM_POST_DATA_GUARD2; end if; if control_pattern_seen = '1' then tmds_decode_mode <= DM_CONTROL; end if; hsync <= terc4(0); vsync <= terc4(1); when DM_PRE_GUARD1 => if guard_ch2_2cc = '0' then -- data hsync <= terc4(0); vsync <= terc4(1); end if; -- video guard has no sync info since imples both syncs OFF tmds_decode_mode <= DM_PRE_GUARD2; when DM_PRE_GUARD2 => if guard_ch2_2cc = '1' then --video tmds_decode_mode <= DM_VIDEO; else tmds_decode_mode <= DM_DATA; hsync <= terc4(0); vsync <= terc4(1); end if; when DM_POST_DATA_GUARD2 => tmds_decode_mode <= DM_CONTROL; hsync <= terc4(0); vsync <= terc4(1); when others => tmds_decode_mode <= DM_CONTROL; end case; hsync_old <= hsync; vsync_old <= vsync; hold_measurement_updates_px <= hold_measurement_updates; -- frame capture management s_hdmi_out_we <= filtered_trigger; armed_sen <= armed_tog; if armed_sen /= armed_tog then completed <= '0'; dma_ctr_px <= (others => '0'); if capture_continuous = '1' then armed <= '0'; -- armed is never high during continuous capture triggered <= '1'; else armed <= '1'; -- ie, set triggered at next vsync triggered <= '0'; end if; end if; if filtered_trigger = '1' then dma_ctr_px <= std_logic_vector(unsigned(dma_ctr_px) + 1); end if; -- continuous capture ends when we do the set amount if capture_continuous = '1' and dma_ctr_px = dma_length_px and triggered = '1' then a_irq_sources_tog(IRQ_SOURCE_TRIG_COMPLETED) <= not a_irq_sources_tog(IRQ_SOURCE_TRIG_COMPLETED); completed <= '1'; triggered <= '0'; end if; -- H counters ctr_horz_total <= std_logic_vector(unsigned(ctr_horz_total) + 1); if (hsync = hsync_active_level) then ctr_horz_sync <= std_logic_vector(unsigned(ctr_horz_sync) + 1); end if; -- no hsync, no active video if (hsync /= hsync_active_level and tmds_decode_mode /= DM_VIDEO) then if is_back = '0' then -- no active seen yet -> bp (left margin) ctr_horz_bp <= std_logic_vector(unsigned(ctr_horz_bp) + 1); else -- active seen -> fp (right margin) ctr_horz_fp <= std_logic_vector(unsigned(ctr_horz_fp) + 1); end if; end if; if tmds_decode_mode = DM_VIDEO then is_back <= '1'; -- line has seen any active video is_back_v <= '1'; -- frame has ever seen any active video end if; -- per-line processing (done at point hsync starts) if (hsync = hsync_active_level and hsync_old /= hsync_active_level) then -- hsync begins ctr_horz_total <= (others => '0'); ctr_horz_bp <= (others => '0'); ctr_horz_fp <= (others => '0'); ctr_horz_sync <= (others => '0'); ctr_data_clocks_in_line <= (others => '0'); ctr_control_clocks_in_line <= (others => '0'); -- only store info for lines with active video (or fp/bp will be wrong) if hold_measurement_updates_px = '0' and is_back = '1' then meas_horz_total <= ctr_horz_total; meas_horz_sync <= ctr_horz_sync; meas_horz_fp <= ctr_horz_fp; meas_horz_bp <= ctr_horz_bp; meas_horz_data_sample_line <= ctr_vert_total; else -- vertical blanking ctr_data_clocks_in_vb <= std_logic_vector(unsigned(ctr_data_clocks_in_line) + unsigned(ctr_data_clocks_in_vb)); ctr_control_clocks_in_vb <= std_logic_vector(unsigned(ctr_control_clocks_in_line) + unsigned(ctr_control_clocks_in_vb)); end if; is_back <= '0'; ctr_vert_total <= std_logic_vector(unsigned(ctr_vert_total) + 1); if (vsync = vsync_active_level) then ctr_vert_sync <= std_logic_vector(unsigned(ctr_vert_sync) + 1); end if; -- no vsync, no active video on this line if vsync /= vsync_active_level and is_back = '0' then if is_back_v = '0' then -- no active lines seen yet -> bp (top margin) ctr_vert_bp <= std_logic_vector(unsigned(ctr_vert_bp) + 1); else -- active has been seen this field -> fp (bottom margin) ctr_vert_fp <= std_logic_vector(unsigned(ctr_vert_fp) + 1); end if; end if; end if; -- per field processing if (vsync = vsync_active_level and vsync_old /= vsync_active_level) then -- vsync begins ctr_vsyncs <= std_logic_vector(unsigned(ctr_vsyncs) + 1); ctr_vert_total <= (others => '0'); ctr_vert_bp <= (others => '0'); ctr_vert_fp <= (others => '0'); ctr_vert_sync <= (others => '0'); ctr_pixels_in_frame <= (others => '0'); ctr_data_clocks_in_frame <= (others => '0'); ctr_data_clocks_in_vb <= (others => '0'); ctr_control_clocks_in_frame <= (others => '0'); ctr_control_clocks_in_vb <= (others => '0'); ctr_terc4_illegals_in_frame <= (others => '0'); if hold_measurement_updates_px = '0' then meas_vert_total <= ctr_vert_total; meas_vert_sync <= ctr_vert_sync; meas_vert_fp <= ctr_vert_fp; meas_vert_bp <= ctr_vert_bp; meas_pixels_in_frame <= ctr_pixels_in_frame; meas_data_clocks_in_frame <= ctr_data_clocks_in_frame; meas_data_clocks_in_vb <= ctr_data_clocks_in_vb; meas_control_clocks_in_frame <= ctr_control_clocks_in_frame; meas_control_clocks_in_vb <= ctr_control_clocks_in_vb; meas_vsync_stamp <= ctr_vsyncs; meas_vsync_h_pos <= ctr_horz_total; meas_hdmi_perr_control_pre_preamble <= ctr_hdmi_perr_control_pre_preamble; meas_terc4_illegals_in_frame <= ctr_terc4_illegals_in_frame; end if; is_back_v <= '0'; if capture_continuous = '0' then -- stop and start on a vsync triggered <= armed; armed <= '0'; completed <= triggered; -- high for one vsync... if triggered = '1' then a_irq_sources_tog(IRQ_SOURCE_TRIG_COMPLETED) <= not a_irq_sources_tog(IRQ_SOURCE_TRIG_COMPLETED); end if; end if; end if; -- notification of clear IRQ from AXI domain -- clear_irq_sen <= clear_irq_tog; -- if clear_irq_sen /= clear_irq_tog then -- -- end if; -- auto bit slip if sync_offset_manual = '1' then sync_offset <= sync_offset_axi; sync_offset_changed_sen <= sync_offset_changed_tog; if sync_offset_changed_tog /= sync_offset_changed_sen then coding_sync_ctr <= (others => '0'); else if control_pattern_seen = '1' then coding_sync_ctr <= std_logic_vector(unsigned(coding_sync_ctr) + 1); end if; end if; else if control_pattern_seen = '1' then -- sync seen since_last_sync <= (others => '0'); coding_sync_ctr <= std_logic_vector(unsigned(coding_sync_ctr) + 1); else if since_last_sync = "1111111111111111" then if sync_offset = "1001" then sync_offset <= "0000"; else sync_offset <= std_logic_vector(unsigned(sync_offset) + 1); end if; end if; since_last_sync <= std_logic_vector(unsigned(since_last_sync) + 1); end if; end if; end if; -- reset end if; -- clock edge end process; -- Implement memory mapped register select and read logic generation -- Slave register read enable is asserted when valid address is available -- and the slave is ready to accept the read address. slv_reg_rden <= axi_arready and S_AXI_ARVALID and (not axi_rvalid) ; process (axi_araddr, S_AXI_ARESETN, slv_reg_rden, s_hdmi_pll_locked, sync_offset, lane_sample, hdmi_clk_counter, s_hdmi_pll_ps_ctr, s_hdmi_pll_ps_target, coding_sync_ctr, meas_vert_sync, meas_vert_total, meas_horz_sync, meas_horz_total, meas_vert_fp, meas_vert_bp, meas_horz_fp, meas_horz_bp, triggered, armed, dlane_sample, dlane_state, shifter_pixel_ctr_samples, irq, c, meas_data_clocks_in_frame, meas_data_clocks_in_vb, meas_control_clocks_in_frame, meas_control_clocks_in_vb, meas_pixels_in_frame, a_irq_sources_status, dma_ctr_read_from_fifo) variable loc_addr :std_logic_vector(OPT_MEM_ADDR_BITS downto 0); begin -- Address decoding for reading registers loc_addr := axi_araddr(ADDR_LSB + OPT_MEM_ADDR_BITS downto ADDR_LSB); axi_fifo_read_select <= '0'; case loc_addr is when b"00000" => if (s_hdmi_pll_locked = '0') then reg_data_out <= (others => '0'); else reg_data_out <= hdmi_clk_counter; end if; when b"00001" => if (s_hdmi_pll_locked = '0') then reg_data_out <= (others => '0'); else reg_data_out <= ( 31 => s_hdmi_pll_ps_ctr(7), 30 => s_hdmi_pll_ps_ctr(6), 29 => s_hdmi_pll_ps_ctr(5), 28 => s_hdmi_pll_ps_ctr(4), 27 => s_hdmi_pll_ps_ctr(3), 26 => s_hdmi_pll_ps_ctr(2), 25 => s_hdmi_pll_ps_ctr(1), 24 => s_hdmi_pll_ps_ctr(0), 23 => s_hdmi_pll_ps_target(7), 22 => s_hdmi_pll_ps_target(6), 21 => s_hdmi_pll_ps_target(5), 20 => s_hdmi_pll_ps_target(4), 19 => s_hdmi_pll_ps_target(3), 18 => s_hdmi_pll_ps_target(2), 17 => s_hdmi_pll_ps_target(1), 16 => s_hdmi_pll_ps_target(0), 15 => sync_offset(3), 14 => sync_offset(2), 13 => sync_offset(1), 12 => sync_offset(0), 7 => c(5), 6 => c(4), 5 => c(3), 4 => c(2), 2 => tmds_decode_mode(2), 1 => tmds_decode_mode(1), 0 => tmds_decode_mode(0), others => '0'); end if; when b"00010" => reg_data_out <= (31 => s_hdmi_pll_locked, 30 => irq, 29 => a_irq_sources_status(IRQ_SOURCE_PLL_LOCK_CHANGE), 28 => a_irq_sources_status(IRQ_SOURCE_TRIG_COMPLETED), 27 => pixel_fifo_full, 26 => pixel_fifo_empty, 25 => triggered, 24 => armed, 17 => vsync, 16 => hsync, 9 => dlane_sample(9), 8 => dlane_sample(8), 7 => dlane_sample(7), 6 => dlane_sample(6), 5 => dlane_sample(5), 4 => dlane_sample(4), 3 => dlane_sample(3), 2 => dlane_sample(2), 1 => dlane_sample(1), 0 => dlane_sample(0), others => '0'); when b"00011" => reg_data_out <= coding_sync_ctr; when b"00100" => reg_data_out <= (28 => meas_vert_total(12), 27 => meas_vert_total(11), 26 => meas_vert_total(10), 25 => meas_vert_total(9), 24 => meas_vert_total(8), 23 => meas_vert_total(7), 22 => meas_vert_total(6), 21 => meas_vert_total(5), 20 => meas_vert_total(4), 19 => meas_vert_total(3), 18 => meas_vert_total(2), 17 => meas_vert_total(1), 16 => meas_vert_total(0), 12 => meas_vert_sync(12), 11 => meas_vert_sync(11), 10 => meas_vert_sync(10), 9 => meas_vert_sync(9), 8 => meas_vert_sync(8), 7 => meas_vert_sync(7), 6 => meas_vert_sync(6), 5 => meas_vert_sync(5), 4 => meas_vert_sync(4), 3 => meas_vert_sync(3), 2 => meas_vert_sync(2), 1 => meas_vert_sync(1), 0 => meas_vert_sync(0), others => '0'); when b"00101" => reg_data_out <= (28 => meas_vert_fp(12), 27 => meas_vert_fp(11), 26 => meas_vert_fp(10), 25 => meas_vert_fp(9), 24 => meas_vert_fp(8), 23 => meas_vert_fp(7), 22 => meas_vert_fp(6), 21 => meas_vert_fp(5), 20 => meas_vert_fp(4), 19 => meas_vert_fp(3), 18 => meas_vert_fp(2), 17 => meas_vert_fp(1), 16 => meas_vert_fp(0), 12 => meas_vert_bp(12), 11 => meas_vert_bp(11), 10 => meas_vert_bp(10), 9 => meas_vert_bp(9), 8 => meas_vert_bp(8), 7 => meas_vert_bp(7), 6 => meas_vert_bp(6), 5 => meas_vert_bp(5), 4 => meas_vert_bp(4), 3 => meas_vert_bp(3), 2 => meas_vert_bp(2), 1 => meas_vert_bp(1), 0 => meas_vert_bp(0), others => '0'); when b"00110" => reg_data_out <= (28 => meas_horz_total(12), 27 => meas_horz_total(11), 26 => meas_horz_total(10), 25 => meas_horz_total(9), 24 => meas_horz_total(8), 23 => meas_horz_total(7), 22 => meas_horz_total(6), 21 => meas_horz_total(5), 20 => meas_horz_total(4), 19 => meas_horz_total(3), 18 => meas_horz_total(2), 17 => meas_horz_total(1), 16 => meas_horz_total(0), 12 => meas_horz_sync(12), 11 => meas_horz_sync(11), 10 => meas_horz_sync(10), 9 => meas_horz_sync(9), 8 => meas_horz_sync(8), 7 => meas_horz_sync(7), 6 => meas_horz_sync(6), 5 => meas_horz_sync(5), 4 => meas_horz_sync(4), 3 => meas_horz_sync(3), 2 => meas_horz_sync(2), 1 => meas_horz_sync(1), 0 => meas_horz_sync(0), others => '0'); when b"00111" => reg_data_out <= (28 => meas_horz_fp(12), 27 => meas_horz_fp(11), 26 => meas_horz_fp(10), 25 => meas_horz_fp(9), 24 => meas_horz_fp(8), 23 => meas_horz_fp(7), 22 => meas_horz_fp(6), 21 => meas_horz_fp(5), 20 => meas_horz_fp(4), 19 => meas_horz_fp(3), 18 => meas_horz_fp(2), 17 => meas_horz_fp(1), 16 => meas_horz_fp(0), 12 => meas_horz_bp(12), 11 => meas_horz_bp(11), 10 => meas_horz_bp(10), 9 => meas_horz_bp(9), 8 => meas_horz_bp(8), 7 => meas_horz_bp(7), 6 => meas_horz_bp(6), 5 => meas_horz_bp(5), 4 => meas_horz_bp(4), 3 => meas_horz_bp(3), 2 => meas_horz_bp(2), 1 => meas_horz_bp(1), 0 => meas_horz_bp(0), others => '0'); when b"01000" => reg_data_out <= ( 25 => meas_data_clocks_in_vb(25), 24 => meas_data_clocks_in_vb(24), 23 => meas_data_clocks_in_vb(23), 22 => meas_data_clocks_in_vb(22), 21 => meas_data_clocks_in_vb(21), 20 => meas_data_clocks_in_vb(20), 19 => meas_data_clocks_in_vb(19), 18 => meas_data_clocks_in_vb(18), 17 => meas_data_clocks_in_vb(17), 16 => meas_data_clocks_in_vb(16), 15 => meas_data_clocks_in_vb(15), 14 => meas_data_clocks_in_vb(14), 13 => meas_data_clocks_in_vb(13), 12 => meas_data_clocks_in_vb(12), 11 => meas_data_clocks_in_vb(11), 10 => meas_data_clocks_in_vb(10), 9 => meas_data_clocks_in_vb(9), 8 => meas_data_clocks_in_vb(8), 7 => meas_data_clocks_in_vb(7), 6 => meas_data_clocks_in_vb(6), 5 => meas_data_clocks_in_vb(5), 4 => meas_data_clocks_in_vb(4), 3 => meas_data_clocks_in_vb(3), 2 => meas_data_clocks_in_vb(2), 1 => meas_data_clocks_in_vb(1), 0 => meas_data_clocks_in_vb(0), others => '0'); when b"01001" => reg_data_out <= ( 25 => meas_pixels_in_frame(25), 24 => meas_pixels_in_frame(24), 23 => meas_pixels_in_frame(23), 22 => meas_pixels_in_frame(22), 21 => meas_pixels_in_frame(21), 20 => meas_pixels_in_frame(20), 19 => meas_pixels_in_frame(19), 18 => meas_pixels_in_frame(18), 17 => meas_pixels_in_frame(17), 16 => meas_pixels_in_frame(16), 15 => meas_pixels_in_frame(15), 14 => meas_pixels_in_frame(14), 13 => meas_pixels_in_frame(13), 12 => meas_pixels_in_frame(12), 11 => meas_pixels_in_frame(11), 10 => meas_pixels_in_frame(10), 9 => meas_pixels_in_frame(9), 8 => meas_pixels_in_frame(8), 7 => meas_pixels_in_frame(7), 6 => meas_pixels_in_frame(6), 5 => meas_pixels_in_frame(5), 4 => meas_pixels_in_frame(4), 3 => meas_pixels_in_frame(3), 2 => meas_pixels_in_frame(2), 1 => meas_pixels_in_frame(1), 0 => meas_pixels_in_frame(0), others => '0'); when b"01010" => reg_data_out <= ( 25 => meas_data_clocks_in_frame(25), 24 => meas_data_clocks_in_frame(24), 23 => meas_data_clocks_in_frame(23), 22 => meas_data_clocks_in_frame(22), 21 => meas_data_clocks_in_frame(21), 20 => meas_data_clocks_in_frame(20), 19 => meas_data_clocks_in_frame(19), 18 => meas_data_clocks_in_frame(18), 17 => meas_data_clocks_in_frame(17), 16 => meas_data_clocks_in_frame(16), 15 => meas_data_clocks_in_frame(15), 14 => meas_data_clocks_in_frame(14), 13 => meas_data_clocks_in_frame(13), 12 => meas_data_clocks_in_frame(12), 11 => meas_data_clocks_in_frame(11), 10 => meas_data_clocks_in_frame(10), 9 => meas_data_clocks_in_frame(9), 8 => meas_data_clocks_in_frame(8), 7 => meas_data_clocks_in_frame(7), 6 => meas_data_clocks_in_frame(6), 5 => meas_data_clocks_in_frame(5), 4 => meas_data_clocks_in_frame(4), 3 => meas_data_clocks_in_frame(3), 2 => meas_data_clocks_in_frame(2), 1 => meas_data_clocks_in_frame(1), 0 => meas_data_clocks_in_frame(0), others => '0'); -- last 4 clock samples when b"01011" => reg_data_out <= pixel_fifo_axi_side; axi_fifo_read_select <= '1'; -- these sample the number of pixel clocks coming in the last 4 fixed period -- from this we can know the pixel clock rate and estimate stability when b"01100" => reg_data_out <= shifter_pixel_ctr_samples(31 downto 0); when b"01101" => reg_data_out <= shifter_pixel_ctr_samples(63 downto 32); when b"01110" => reg_data_out <= shifter_pixel_ctr_samples(95 downto 64); when b"01111" => reg_data_out <= shifter_pixel_ctr_samples(127 downto 96); when b"10000" => reg_data_out <= timestamp_escapes_captured; -- these are aimed at detecting badly connected channels, -- ie only one polarity connected / driven,,, the stats for -- escapes on that channel should become wrong when b"10001" => -- escapes on ch0 reg_data_out <= meas_escapes(31 downto 0); when b"10010" => -- escapes on ch1 reg_data_out <= meas_escapes(63 downto 32); when b"10011" => -- escapes on ch2 reg_data_out <= meas_escapes(95 downto 64); when b"10100" => -- detect data freshness reg_data_out <= ( 31 => meas_vsync_stamp(15), -- frame # the vertical measurements were taken on 30 => meas_vsync_stamp(14), 29 => meas_vsync_stamp(13), 28 => meas_vsync_stamp(12), 27 => meas_vsync_stamp(11), 26 => meas_vsync_stamp(10), 25 => meas_vsync_stamp(9), 24 => meas_vsync_stamp(8), 23 => meas_vsync_stamp(7), 22 => meas_vsync_stamp(6), 21 => meas_vsync_stamp(5), 20 => meas_vsync_stamp(4), 19 => meas_vsync_stamp(3), 18 => meas_vsync_stamp(2), 17 => meas_vsync_stamp(1), 16 => meas_vsync_stamp(0), 12 => meas_horz_data_sample_line(12), -- line # the horizontal measurements were taken on 11 => meas_horz_data_sample_line(11), 10 => meas_horz_data_sample_line(10), 9 => meas_horz_data_sample_line(9), 8 => meas_horz_data_sample_line(8), 7 => meas_horz_data_sample_line(7), 6 => meas_horz_data_sample_line(6), 5 => meas_horz_data_sample_line(5), 4 => meas_horz_data_sample_line(4), 3 => meas_horz_data_sample_line(3), 2 => meas_horz_data_sample_line(2), 1 => meas_horz_data_sample_line(1), 0 => meas_horz_data_sample_line(0), others => '0'); when b"10101" => reg_data_out <= ( 25 => meas_control_clocks_in_frame(25), 24 => meas_control_clocks_in_frame(24), 23 => meas_control_clocks_in_frame(23), 22 => meas_control_clocks_in_frame(22), 21 => meas_control_clocks_in_frame(21), 20 => meas_control_clocks_in_frame(20), 19 => meas_control_clocks_in_frame(19), 18 => meas_control_clocks_in_frame(18), 17 => meas_control_clocks_in_frame(17), 16 => meas_control_clocks_in_frame(16), 15 => meas_control_clocks_in_frame(15), 14 => meas_control_clocks_in_frame(14), 13 => meas_control_clocks_in_frame(13), 12 => meas_control_clocks_in_frame(12), 11 => meas_control_clocks_in_frame(11), 10 => meas_control_clocks_in_frame(10), 9 => meas_control_clocks_in_frame(9), 8 => meas_control_clocks_in_frame(8), 7 => meas_control_clocks_in_frame(7), 6 => meas_control_clocks_in_frame(6), 5 => meas_control_clocks_in_frame(5), 4 => meas_control_clocks_in_frame(4), 3 => meas_control_clocks_in_frame(3), 2 => meas_control_clocks_in_frame(2), 1 => meas_control_clocks_in_frame(1), 0 => meas_control_clocks_in_frame(0), others => '0'); when b"10110" => reg_data_out <= ( 25 => meas_control_clocks_in_vb(25), 24 => meas_control_clocks_in_vb(24), 23 => meas_control_clocks_in_vb(23), 22 => meas_control_clocks_in_vb(22), 21 => meas_control_clocks_in_vb(21), 20 => meas_control_clocks_in_vb(20), 19 => meas_control_clocks_in_vb(19), 18 => meas_control_clocks_in_vb(18), 17 => meas_control_clocks_in_vb(17), 16 => meas_control_clocks_in_vb(16), 15 => meas_control_clocks_in_vb(15), 14 => meas_control_clocks_in_vb(14), 13 => meas_control_clocks_in_vb(13), 12 => meas_control_clocks_in_vb(12), 11 => meas_control_clocks_in_vb(11), 10 => meas_control_clocks_in_vb(10), 9 => meas_control_clocks_in_vb(9), 8 => meas_control_clocks_in_vb(8), 7 => meas_control_clocks_in_vb(7), 6 => meas_control_clocks_in_vb(6), 5 => meas_control_clocks_in_vb(5), 4 => meas_control_clocks_in_vb(4), 3 => meas_control_clocks_in_vb(3), 2 => meas_control_clocks_in_vb(2), 1 => meas_control_clocks_in_vb(1), 0 => meas_control_clocks_in_vb(0), others => '0'); when b"10111" => -- where the VSYNC appears in terms of h pixels reg_data_out <= ( 31 => meas_terc4_illegals_in_frame(15), -- illegal terc4 codes this frame 30 => meas_terc4_illegals_in_frame(14), 29 => meas_terc4_illegals_in_frame(13), 28 => meas_terc4_illegals_in_frame(12), 27 => meas_terc4_illegals_in_frame(11), 26 => meas_terc4_illegals_in_frame(10), 25 => meas_terc4_illegals_in_frame(9), 24 => meas_terc4_illegals_in_frame(8), 23 => meas_terc4_illegals_in_frame(7), 22 => meas_terc4_illegals_in_frame(6), 21 => meas_terc4_illegals_in_frame(5), 20 => meas_terc4_illegals_in_frame(4), 19 => meas_terc4_illegals_in_frame(3), 18 => meas_terc4_illegals_in_frame(2), 17 => meas_terc4_illegals_in_frame(1), 16 => meas_terc4_illegals_in_frame(0), 12 => meas_vsync_h_pos(12), 11 => meas_vsync_h_pos(11), 10 => meas_vsync_h_pos(10), 9 => meas_vsync_h_pos(9), 8 => meas_vsync_h_pos(8), 7 => meas_vsync_h_pos(7), 6 => meas_vsync_h_pos(6), 5 => meas_vsync_h_pos(5), 4 => meas_vsync_h_pos(4), 3 => meas_vsync_h_pos(3), 2 => meas_vsync_h_pos(2), 1 => meas_vsync_h_pos(1), 0 => meas_vsync_h_pos(0), others => '0'); when b"11000" => -- must be 4 non-preamble control cycles before preamble reg_data_out <= ( 12 => meas_hdmi_perr_control_pre_preamble(12), 11 => meas_hdmi_perr_control_pre_preamble(11), 10 => meas_hdmi_perr_control_pre_preamble(10), 9 => meas_hdmi_perr_control_pre_preamble(9), 8 => meas_hdmi_perr_control_pre_preamble(8), 7 => meas_hdmi_perr_control_pre_preamble(7), 6 => meas_hdmi_perr_control_pre_preamble(6), 5 => meas_hdmi_perr_control_pre_preamble(5), 4 => meas_hdmi_perr_control_pre_preamble(4), 3 => meas_hdmi_perr_control_pre_preamble(3), 2 => meas_hdmi_perr_control_pre_preamble(2), 1 => meas_hdmi_perr_control_pre_preamble(1), 0 => meas_hdmi_perr_control_pre_preamble(0), others => '0'); when b"11001" => -- words actually read from fifo by DMA reg_data_out <= dma_ctr_read_from_fifo(31 downto 0); when b"11010" => -- words actually read from fifo by DMA reg_data_out <= dma_ctr_used; when others => reg_data_out <= (others => '1'); end case; end process; -- Output register or memory read data process( S_AXI_ACLK ) is begin if (rising_edge (S_AXI_ACLK)) then if ( S_AXI_ARESETN = '0' ) then axi_rdata <= (others => '0'); else -- sample the pixel clock counter every 64K AXI clocks (655us @ 100MHz, shifter replaced 2.4ms) -- AXI clock shouldn't be spread-spectrum for this axi_fifo_read_select_reg <= '0'; ctr_axi_clocks <= std_logic_vector(unsigned(ctr_axi_clocks) + 1); if (ctr_axi_clocks = "1111111111111111") then for n in 0 to 2 loop shifter_pixel_ctr_samples(((n + 1) * 32) + 31 downto ((n + 1) * 32)) <= shifter_pixel_ctr_samples((n * 32) + 31 downto (n * 32)); end loop; shifter_pixel_ctr_samples(31 downto 0) <= std_logic_vector( unsigned(hdmi_clk_counter) - unsigned(hdmi_clk_counter_start)); hdmi_clk_counter_start <= hdmi_clk_counter; end if; if (slv_reg_rden = '1') then axi_fifo_read_select_reg <= axi_fifo_read_select; -- When there is a valid read address (S_AXI_ARVALID) with -- acceptance of read address by the slave (axi_arready), -- output the read dada -- Read address mux axi_rdata <= reg_data_out; -- register read data end if; end if; end if; end process; -- Add user logic here -- User logic ends end arch_imp;