From 9cbf12551e97539c0b265f0c7f9ba80fa4273a65 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Sun, 25 Oct 2015 12:12:35 +0800 Subject: initial commit --- hdmicap_v1_0_S00_AXI.vhd | 1790 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1790 insertions(+) create mode 100755 hdmicap_v1_0_S00_AXI.vhd (limited to 'hdmicap_v1_0_S00_AXI.vhd') diff --git a/hdmicap_v1_0_S00_AXI.vhd b/hdmicap_v1_0_S00_AXI.vhd new file mode 100755 index 0000000..6857ea6 --- /dev/null +++ b/hdmicap_v1_0_S00_AXI.vhd @@ -0,0 +1,1790 @@ +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; -- cgit v1.2.3