718 lines
29 KiB
VHDL
718 lines
29 KiB
VHDL
--
|
|
-- Top-level FPGA design for Red Pitaya PuzzleFW firmware,
|
|
-- variant for 4 input channels.
|
|
--
|
|
-- Joris van Rantwijk 2024
|
|
--
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.std_logic_misc.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
library unisim;
|
|
use unisim.vcomponents.all;
|
|
|
|
library xpm;
|
|
use xpm.vcomponents.all;
|
|
|
|
use work.puzzlefw_pkg.all;
|
|
|
|
|
|
entity puzzlefw_top_4ch is
|
|
|
|
port (
|
|
-- Ports directly connected to ARM/PS.
|
|
DDR_0_addr: inout std_logic_vector(14 downto 0);
|
|
DDR_0_ba: inout std_logic_vector(2 downto 0);
|
|
DDR_0_cas_n: inout std_logic;
|
|
DDR_0_ck_n: inout std_logic;
|
|
DDR_0_ck_p: inout std_logic;
|
|
DDR_0_cke: inout std_logic;
|
|
DDR_0_cs_n: inout std_logic;
|
|
DDR_0_dm: inout std_logic_vector(3 downto 0);
|
|
DDR_0_dq: inout std_logic_vector(31 downto 0);
|
|
DDR_0_dqs_n: inout std_logic_vector(3 downto 0);
|
|
DDR_0_dqs_p: inout std_logic_vector(3 downto 0);
|
|
DDR_0_odt: inout std_logic;
|
|
DDR_0_ras_n: inout std_logic;
|
|
DDR_0_reset_n: inout std_logic;
|
|
DDR_0_we_n: inout std_logic;
|
|
FIXED_IO_0_ddr_vrn: inout std_logic;
|
|
FIXED_IO_0_ddr_vrp: inout std_logic;
|
|
FIXED_IO_0_mio: inout std_logic_vector(53 downto 0);
|
|
FIXED_IO_0_ps_clk: inout std_logic;
|
|
FIXED_IO_0_ps_porb: inout std_logic;
|
|
FIXED_IO_0_ps_srstb: inout std_logic;
|
|
|
|
-- Ports controlled by FPGA.
|
|
adc_dat_i: in adc_data_input_type_4ch; -- ADC data
|
|
adc_clk_i: in adc_clock_input_type_4ch; -- ADC clock 1=pos, 0=neg
|
|
spi_csa_o: out std_logic; -- SPI interface to ADC
|
|
spi_csb_o: out std_logic;
|
|
spi_clk_o: out std_logic;
|
|
spi_mosi_o: out std_logic;
|
|
dac_pwm_o: out std_logic_vector(3 downto 0); -- PWM DAC
|
|
exp_p_io: inout std_logic_vector(10 downto 0); -- extension I/O pos
|
|
exp_n_io: inout std_logic_vector(10 downto 0); -- extension I/O neg
|
|
led_o: out std_logic_vector(7 downto 0) -- LEDs
|
|
);
|
|
|
|
end puzzlefw_top_4ch;
|
|
|
|
architecture arch of puzzlefw_top_4ch is
|
|
|
|
-- Main 125 MHz clock, derived from ADC A clock input port.
|
|
signal clk_adc: std_logic;
|
|
|
|
-- Auxiliary clock from FCLK0.
|
|
signal clk_fclk200: std_logic;
|
|
|
|
-- Reset signals.
|
|
signal s_ext_reset_n: std_logic; -- reset signal from GPIO, active low
|
|
signal s_pll_reset: std_logic; -- reset signal for PLL
|
|
signal s_pll_locked: std_logic; -- PLL locked status
|
|
signal s_reset: std_logic; -- main reset, synchronized to clk_adc
|
|
signal r_reset_done: std_logic; -- reset status report via GPIO
|
|
|
|
-- Internal clock signals.
|
|
signal s_adc_clk_ibuf: std_logic_vector(1 downto 0);
|
|
signal clk_adc_capture: std_logic_vector(1 downto 0);
|
|
signal s_pll_clkfbout: std_logic;
|
|
signal s_pll_clkfbin: std_logic;
|
|
signal s_pll_clkout: std_logic;
|
|
|
|
-- Blinking LED.
|
|
signal r_adcclk_cnt: unsigned(25 downto 0);
|
|
signal r_adcclk_led: std_logic;
|
|
|
|
-- Internal GPIO and SPI signals from PS.
|
|
signal s_gpio_in: std_logic_vector(23 downto 0);
|
|
signal s_gpio_out: std_logic_vector(23 downto 0);
|
|
signal s_spi_sclk_o: std_logic;
|
|
signal s_spi_sclk_t: std_logic;
|
|
signal s_spi_mosi_o: std_logic;
|
|
signal s_spi_mosi_t: std_logic;
|
|
signal s_spi_ss_o: std_logic_vector(1 downto 0);
|
|
signal s_spi_ss_t: std_logic;
|
|
|
|
-- APB bus for register access.
|
|
signal s_apb_paddr: std_logic_vector(31 downto 0);
|
|
signal s_apb_penable: std_logic;
|
|
signal s_apb_prdata: std_logic_vector(31 downto 0);
|
|
signal s_apb_pready: std_logic;
|
|
signal s_apb_psel: std_logic;
|
|
signal s_apb_pslverr: std_logic;
|
|
signal s_apb_pwdata: std_logic_vector(31 downto 0);
|
|
signal s_apb_pwrite: std_logic;
|
|
|
|
-- AXI bus for DMA.
|
|
signal s_axi_awid: std_logic_vector(5 downto 0);
|
|
signal s_axi_awaddr: std_logic_vector(31 downto 0);
|
|
signal s_axi_awlen: std_logic_vector(3 downto 0);
|
|
signal s_axi_awsize: std_logic_vector(2 downto 0);
|
|
signal s_axi_awburst: std_logic_vector(1 downto 0);
|
|
signal s_axi_awlock: std_logic_vector(1 downto 0);
|
|
signal s_axi_awcache: std_logic_vector(3 downto 0);
|
|
signal s_axi_awprot: std_logic_vector(2 downto 0);
|
|
signal s_axi_awqos: std_logic_vector(3 downto 0);
|
|
signal s_axi_awvalid: std_logic;
|
|
signal s_axi_awready: std_logic;
|
|
signal s_axi_wid: std_logic_vector(5 downto 0);
|
|
signal s_axi_wdata: std_logic_vector(63 downto 0);
|
|
signal s_axi_wstrb: std_logic_vector(7 downto 0);
|
|
signal s_axi_wlast: std_logic;
|
|
signal s_axi_wvalid: std_logic;
|
|
signal s_axi_wready: std_logic;
|
|
signal s_axi_bid: std_logic_vector(5 downto 0);
|
|
signal s_axi_bresp: std_logic_vector(1 downto 0);
|
|
signal s_axi_bvalid: std_logic;
|
|
signal s_axi_bready: std_logic;
|
|
signal s_axi_arid: std_logic_vector(5 downto 0);
|
|
signal s_axi_araddr: std_logic_vector(31 downto 0);
|
|
signal s_axi_arlen: std_logic_vector(3 downto 0);
|
|
signal s_axi_arsize: std_logic_vector(2 downto 0);
|
|
signal s_axi_arburst: std_logic_vector(1 downto 0);
|
|
signal s_axi_arlock: std_logic_vector(1 downto 0);
|
|
signal s_axi_arcache: std_logic_vector(3 downto 0);
|
|
signal s_axi_arprot: std_logic_vector(2 downto 0);
|
|
signal s_axi_arqos: std_logic_vector(3 downto 0);
|
|
signal s_axi_arvalid: std_logic;
|
|
signal s_axi_arready: std_logic;
|
|
signal s_axi_rid: std_logic_vector(5 downto 0);
|
|
signal s_axi_rdata: std_logic_vector(63 downto 0);
|
|
signal s_axi_rresp: std_logic_vector(1 downto 0);
|
|
signal s_axi_rlast: std_logic;
|
|
signal s_axi_rvalid: std_logic;
|
|
signal s_axi_rready: std_logic;
|
|
|
|
-- Interrupts.
|
|
signal s_irq_pending: std_logic_vector(1 downto 0);
|
|
signal s_irq_f2p: std_logic_vector(7 downto 0);
|
|
|
|
-- Registers.
|
|
signal s_reg_control: registers_control;
|
|
signal s_reg_status: registers_status;
|
|
|
|
-- DMA write channel control.
|
|
signal s_dma_write_cmd_addr: dma_address_array(0 to 1);
|
|
signal s_dma_write_cmd_length: dma_burst_length_array(0 to 1);
|
|
signal s_dma_write_cmd_valid: std_logic_vector(1 downto 0);
|
|
signal s_dma_write_cmd_ready: std_logic_vector(1 downto 0);
|
|
signal s_dma_write_data: dma_data_array(0 to 1);
|
|
signal s_dma_write_data_ready: std_logic_vector(1 downto 0);
|
|
signal s_dma_write_finished: std_logic_vector(1 downto 0);
|
|
|
|
signal s_acq_dma_valid: std_logic;
|
|
signal s_acq_dma_ready: std_logic;
|
|
signal s_acq_dma_empty: std_logic;
|
|
signal s_acq_dma_data: dma_data_type;
|
|
|
|
signal s_tt_dma_valid: std_logic;
|
|
signal s_tt_dma_ready: std_logic;
|
|
signal s_tt_dma_empty: std_logic;
|
|
signal s_tt_dma_data: dma_data_type;
|
|
|
|
signal s_timestamp: std_logic_vector(timestamp_bits - 1 downto 0);
|
|
signal s_adc_data: adc_data_array(0 to 3);
|
|
signal s_adc_sample: adc_data_array(0 to 3);
|
|
signal s_dig_in: std_logic_vector(3 downto 0);
|
|
signal s_dig_sync: std_logic_vector(3 downto 0);
|
|
signal s_dig_deglitch: std_logic_vector(3 downto 0);
|
|
signal s_dig_sample: std_logic_vector(3 downto 0);
|
|
|
|
begin
|
|
|
|
-- Global FPGA reset.
|
|
-- GPIO(0) = '0' to reset.
|
|
s_ext_reset_n <= s_gpio_out(0);
|
|
|
|
-- GPIO inputs to the PS.
|
|
-- GPIO(1) = '0' while in reset, '1' when reset released.
|
|
s_gpio_in(1) <= r_reset_done;
|
|
s_gpio_in(0) <= '0';
|
|
s_gpio_in(23 downto 2) <= (others => '0');
|
|
|
|
-- Drive LEDs.
|
|
led_o(0) <= r_adcclk_led; -- blinking LED, 1 Hz
|
|
led_o(1) <= s_reg_control.acquisition_en; -- acquisition enabled
|
|
led_o(2) <= s_reg_status.trig_waiting; -- waiting for trigger
|
|
led_o(3) <= or_reduce(s_reg_control.timetagger_en); -- timetagger enabled
|
|
led_o(7 downto 4) <= s_reg_control.led_state(7 downto 4);
|
|
|
|
-- Drive safe levels to unused DAC pins.
|
|
dac_pwm_o <= (others => 'Z');
|
|
|
|
-- Use extension I/O pins as inputs only.
|
|
exp_p_io <= (others => 'Z');
|
|
exp_n_io <= (others => 'Z');
|
|
|
|
-- Drive SPI bus.
|
|
inst_obuf_spi_clk: OBUFT
|
|
port map (
|
|
I => s_spi_sclk_o,
|
|
T => s_spi_sclk_t,
|
|
O => spi_clk_o );
|
|
|
|
inst_obuf_spi_mosi: OBUFT
|
|
port map (
|
|
I => s_spi_mosi_o,
|
|
T => s_spi_mosi_t,
|
|
O => spi_mosi_o );
|
|
|
|
inst_obuf_spi_csa: OBUFT
|
|
port map (
|
|
I => s_spi_ss_o(0),
|
|
T => s_spi_ss_t,
|
|
O => spi_csa_o );
|
|
|
|
inst_obuf_spi_csb: OBUFT
|
|
port map (
|
|
I => s_spi_ss_o(1),
|
|
T => s_spi_ss_t,
|
|
O => spi_csb_o );
|
|
|
|
-- Handle clock input and data input for each ADC.
|
|
gen_adcin: for i in 0 to 1 generate
|
|
|
|
-- Differential clock input for ADC clock.
|
|
inst_ibuf_adc_clk: IBUFDS
|
|
port map (
|
|
O => s_adc_clk_ibuf(i),
|
|
I => adc_clk_i(i)(1),
|
|
IB => adc_clk_i(i)(0) );
|
|
|
|
-- Clock buffer for ADC clock.
|
|
-- BUFR is faster (lower propagation delay) than BUFG.
|
|
inst_bufg_adc_clk: BUFR
|
|
port map (
|
|
I => s_adc_clk_ibuf(i),
|
|
O => clk_adc_capture(i),
|
|
CE => '1',
|
|
CLR => '0' );
|
|
|
|
end generate;
|
|
|
|
-- PLL for 125 MHz clock.
|
|
-- Input clock comes from ADC A.
|
|
-- Output clock drives most of the FPGA design.
|
|
inst_pll: PLLE2_BASE
|
|
generic map (
|
|
BANDWIDTH => "OPTIMIZED",
|
|
CLKFBOUT_MULT => 8,
|
|
CLKFBOUT_PHASE => 0.0,
|
|
CLKIN1_PERIOD => 8.0,
|
|
CLKOUT0_DIVIDE => 8,
|
|
CLKOUT0_DUTY_CYCLE => 0.5,
|
|
CLKOUT0_PHASE => 0.0,
|
|
DIVCLK_DIVIDE => 1,
|
|
STARTUP_WAIT => "FALSE" )
|
|
port map (
|
|
CLKOUT0 => s_pll_clkout,
|
|
CLKFBOUT => s_pll_clkfbout,
|
|
LOCKED => s_pll_locked,
|
|
CLKIN1 => s_adc_clk_ibuf(0),
|
|
PWRDWN => '0',
|
|
RST => s_pll_reset,
|
|
CLKFBIN => s_pll_clkfbin );
|
|
|
|
-- Reset PLL when external reset is applied.
|
|
s_pll_reset <= not s_ext_reset_n;
|
|
|
|
-- Clock buffers for PLL.
|
|
inst_bufg_pll_clkfb: BUFG
|
|
port map (
|
|
I => s_pll_clkfbout,
|
|
O => s_pll_clkfbin );
|
|
|
|
inst_bufg_pll_clkout: BUFG
|
|
port map (
|
|
I => s_pll_clkout,
|
|
O => clk_adc );
|
|
|
|
-- Since the design uses IDELAY, it must contain an IDELAYCTRL instance.
|
|
inst_idelayctrl: IDELAYCTRL
|
|
port map (
|
|
RDY => open,
|
|
REFCLK => clk_fclk200,
|
|
RST => s_pll_reset );
|
|
|
|
-- ARM/PS block design.
|
|
inst_blockdesign: entity work.puzzlefw_wrapper
|
|
port map (
|
|
sys_clk => clk_adc,
|
|
ps_fclk => clk_fclk200,
|
|
peripheral_reset_0(0) => s_reset,
|
|
ext_reset_in_0 => s_ext_reset_n,
|
|
dcm_locked_0 => s_pll_locked,
|
|
DDR_0_addr => DDR_0_addr,
|
|
DDR_0_ba => DDR_0_ba,
|
|
DDR_0_cas_n => DDR_0_cas_n,
|
|
DDR_0_ck_n => DDR_0_ck_n,
|
|
DDR_0_ck_p => DDR_0_ck_p,
|
|
DDR_0_cke => DDR_0_cke,
|
|
DDR_0_cs_n => DDR_0_cs_n,
|
|
DDR_0_dm => DDR_0_dm,
|
|
DDR_0_dq => DDR_0_dq,
|
|
DDR_0_dqs_n => DDR_0_dqs_n,
|
|
DDR_0_dqs_p => DDR_0_dqs_p,
|
|
DDR_0_odt => DDR_0_odt,
|
|
DDR_0_ras_n => DDR_0_ras_n,
|
|
DDR_0_reset_n => DDR_0_reset_n,
|
|
DDR_0_we_n => DDR_0_we_n,
|
|
FIXED_IO_0_ddr_vrn => FIXED_IO_0_ddr_vrn,
|
|
FIXED_IO_0_ddr_vrp => FIXED_IO_0_ddr_vrp,
|
|
FIXED_IO_0_mio => FIXED_IO_0_mio,
|
|
FIXED_IO_0_ps_clk => FIXED_IO_0_ps_clk,
|
|
FIXED_IO_0_ps_porb => FIXED_IO_0_ps_porb,
|
|
FIXED_IO_0_ps_srstb => FIXED_IO_0_ps_srstb,
|
|
GPIO_I_0 => s_gpio_in,
|
|
GPIO_O_0 => s_gpio_out,
|
|
SPI0_MOSI_O_0 => s_spi_mosi_o,
|
|
SPI0_MOSI_T_0 => s_spi_mosi_t,
|
|
SPI0_SCLK_O_0 => s_spi_sclk_o,
|
|
SPI0_SCLK_T_0 => s_spi_sclk_t,
|
|
SPI0_SS1_O_0 => s_spi_ss_o(1),
|
|
SPI0_SS_O_0 => s_spi_ss_o(0),
|
|
SPI0_SS_T_0 => s_spi_ss_t,
|
|
IRQ_F2P => s_irq_f2p,
|
|
APB_M_0_paddr => s_apb_paddr,
|
|
APB_M_0_penable => s_apb_penable,
|
|
APB_M_0_prdata => s_apb_prdata,
|
|
APB_M_0_pready(0) => s_apb_pready,
|
|
APB_M_0_psel(0) => s_apb_psel,
|
|
APB_M_0_pslverr(0) => s_apb_pslverr,
|
|
APB_M_0_pwdata => s_apb_pwdata,
|
|
APB_M_0_pwrite => s_apb_pwrite,
|
|
S_AXI_HP0_0_araddr => s_axi_araddr,
|
|
S_AXI_HP0_0_arburst => s_axi_arburst,
|
|
S_AXI_HP0_0_arcache => s_axi_arcache,
|
|
S_AXI_HP0_0_arid => s_axi_arid,
|
|
S_AXI_HP0_0_arlen => s_axi_arlen,
|
|
S_AXI_HP0_0_arlock => s_axi_arlock,
|
|
S_AXI_HP0_0_arprot => s_axi_arprot,
|
|
S_AXI_HP0_0_arqos => s_axi_arqos,
|
|
S_AXI_HP0_0_arready => s_axi_arready,
|
|
S_AXI_HP0_0_arsize => s_axi_arsize,
|
|
S_AXI_HP0_0_arvalid => s_axi_arvalid,
|
|
S_AXI_HP0_0_awaddr => s_axi_awaddr,
|
|
S_AXI_HP0_0_awburst => s_axi_awburst,
|
|
S_AXI_HP0_0_awcache => s_axi_awcache,
|
|
S_AXI_HP0_0_awid => s_axi_awid,
|
|
S_AXI_HP0_0_awlen => s_axi_awlen,
|
|
S_AXI_HP0_0_awlock => s_axi_awlock,
|
|
S_AXI_HP0_0_awprot => s_axi_awprot,
|
|
S_AXI_HP0_0_awqos => s_axi_awqos,
|
|
S_AXI_HP0_0_awready => s_axi_awready,
|
|
S_AXI_HP0_0_awsize => s_axi_awsize,
|
|
S_AXI_HP0_0_awvalid => s_axi_awvalid,
|
|
S_AXI_HP0_0_bid => s_axi_bid,
|
|
S_AXI_HP0_0_bready => s_axi_bready,
|
|
S_AXI_HP0_0_bresp => s_axi_bresp,
|
|
S_AXI_HP0_0_bvalid => s_axi_bvalid,
|
|
S_AXI_HP0_0_rdata => s_axi_rdata,
|
|
S_AXI_HP0_0_rid => s_axi_rid,
|
|
S_AXI_HP0_0_rlast => s_axi_rlast,
|
|
S_AXI_HP0_0_rready => s_axi_rready,
|
|
S_AXI_HP0_0_rresp => s_axi_rresp,
|
|
S_AXI_HP0_0_rvalid => s_axi_rvalid,
|
|
S_AXI_HP0_0_wdata => s_axi_wdata,
|
|
S_AXI_HP0_0_wid => s_axi_wid,
|
|
S_AXI_HP0_0_wlast => s_axi_wlast,
|
|
S_AXI_HP0_0_wready => s_axi_wready,
|
|
S_AXI_HP0_0_wstrb => s_axi_wstrb,
|
|
S_AXI_HP0_0_wvalid => s_axi_wvalid
|
|
);
|
|
|
|
-- Memory-mapped registers.
|
|
inst_registers: entity work.registers
|
|
generic map (
|
|
num_acq_channels => 4 )
|
|
port map (
|
|
clk => clk_adc,
|
|
reset => s_reset,
|
|
apb_psel => s_apb_psel,
|
|
apb_penable => s_apb_penable,
|
|
apb_pwrite => s_apb_pwrite,
|
|
apb_paddr => s_apb_paddr,
|
|
apb_pwdata => s_apb_pwdata,
|
|
apb_pready => s_apb_pready,
|
|
apb_pslverr => s_apb_pslverr,
|
|
apb_prdata => s_apb_prdata,
|
|
reg_control => s_reg_control,
|
|
reg_status => s_reg_status
|
|
);
|
|
|
|
-- AXI master.
|
|
inst_axi_master: entity work.dma_axi_master
|
|
generic map (
|
|
num_read_channels => 0,
|
|
num_write_channels => 2 )
|
|
port map (
|
|
clk => clk_adc,
|
|
reset => s_reset,
|
|
dma_en => s_reg_control.dma_en,
|
|
dma_busy => s_reg_status.dma_busy,
|
|
window_base_addr => s_reg_control.dma_buf_addr,
|
|
window_size => s_reg_control.dma_buf_size,
|
|
err_read => s_reg_status.dma_err_read,
|
|
err_write => s_reg_status.dma_err_write,
|
|
err_address => s_reg_status.dma_err_address,
|
|
err_any => s_reg_status.dma_err_any,
|
|
clear_errors => s_reg_control.dma_clear,
|
|
read_cmd_addr => (others => (others => '0')),
|
|
read_cmd_length => (others => (others => '0')),
|
|
read_cmd_valid => (others => '0'),
|
|
read_cmd_ready => open,
|
|
read_data => open,
|
|
read_data_valid => open,
|
|
write_cmd_addr => s_dma_write_cmd_addr,
|
|
write_cmd_length => s_dma_write_cmd_length,
|
|
write_cmd_valid => s_dma_write_cmd_valid,
|
|
write_cmd_ready => s_dma_write_cmd_ready,
|
|
write_data => s_dma_write_data,
|
|
write_data_ready => s_dma_write_data_ready,
|
|
write_finished => s_dma_write_finished,
|
|
m_axi_awid => s_axi_awid,
|
|
m_axi_awaddr => s_axi_awaddr,
|
|
m_axi_awlen => s_axi_awlen,
|
|
m_axi_awsize => s_axi_awsize,
|
|
m_axi_awburst => s_axi_awburst,
|
|
m_axi_awlock => s_axi_awlock,
|
|
m_axi_awcache => s_axi_awcache,
|
|
m_axi_awprot => s_axi_awprot,
|
|
m_axi_awqos => s_axi_awqos,
|
|
m_axi_awvalid => s_axi_awvalid,
|
|
m_axi_awready => s_axi_awready,
|
|
m_axi_wid => s_axi_wid,
|
|
m_axi_wdata => s_axi_wdata,
|
|
m_axi_wstrb => s_axi_wstrb,
|
|
m_axi_wlast => s_axi_wlast,
|
|
m_axi_wvalid => s_axi_wvalid,
|
|
m_axi_wready => s_axi_wready,
|
|
m_axi_bid => s_axi_bid,
|
|
m_axi_bresp => s_axi_bresp,
|
|
m_axi_bvalid => s_axi_bvalid,
|
|
m_axi_bready => s_axi_bready,
|
|
m_axi_arid => s_axi_arid,
|
|
m_axi_araddr => s_axi_araddr,
|
|
m_axi_arlen => s_axi_arlen,
|
|
m_axi_arsize => s_axi_arsize,
|
|
m_axi_arburst => s_axi_arburst,
|
|
m_axi_arlock => s_axi_arlock,
|
|
m_axi_arcache => s_axi_arcache,
|
|
m_axi_arprot => s_axi_arprot,
|
|
m_axi_arqos => s_axi_arqos,
|
|
m_axi_arvalid => s_axi_arvalid,
|
|
m_axi_arready => s_axi_arready,
|
|
m_axi_rid => s_axi_rid,
|
|
m_axi_rdata => s_axi_rdata,
|
|
m_axi_rresp => s_axi_rresp,
|
|
m_axi_rlast => s_axi_rlast,
|
|
m_axi_rvalid => s_axi_rvalid,
|
|
m_axi_rready => s_axi_rready
|
|
);
|
|
|
|
-- DMA write channel for analog acquisition
|
|
inst_acq_dma: entity work.dma_write_channel
|
|
generic map (
|
|
transfer_size_bits => 4,
|
|
queue_size_bits => 14,
|
|
idle_timeout => 256 )
|
|
port map (
|
|
clk => clk_adc,
|
|
reset => s_reset,
|
|
channel_en => s_reg_control.acq_dma_en,
|
|
channel_busy => s_reg_status.acq_dma_busy,
|
|
channel_init => s_reg_control.acq_dma_init,
|
|
addr_start => s_reg_control.acq_addr_start,
|
|
addr_end => s_reg_control.acq_addr_end,
|
|
addr_limit => s_reg_control.acq_addr_limit,
|
|
addr_interrupt => s_reg_control.acq_addr_intr,
|
|
addr_pointer => s_reg_status.acq_addr_ptr,
|
|
intr_en => s_reg_control.acq_intr_en,
|
|
intr_clear => s_reg_control.acq_intr_clear,
|
|
intr_out => s_irq_pending(0),
|
|
in_valid => s_acq_dma_valid,
|
|
in_ready => s_acq_dma_ready,
|
|
in_empty => s_acq_dma_empty,
|
|
in_data => s_acq_dma_data,
|
|
write_cmd_addr => s_dma_write_cmd_addr(0),
|
|
write_cmd_length => s_dma_write_cmd_length(0),
|
|
write_cmd_valid => s_dma_write_cmd_valid(0),
|
|
write_cmd_ready => s_dma_write_cmd_ready(0),
|
|
write_data => s_dma_write_data(0),
|
|
write_data_ready => s_dma_write_data_ready(0),
|
|
write_finished => s_dma_write_finished(0) );
|
|
|
|
-- DMA write channel for time tagger
|
|
inst_tt_dma: entity work.dma_write_channel
|
|
generic map (
|
|
transfer_size_bits => 4,
|
|
queue_size_bits => 12,
|
|
idle_timeout => 256 )
|
|
port map (
|
|
clk => clk_adc,
|
|
reset => s_reset,
|
|
channel_en => s_reg_control.tt_dma_en,
|
|
channel_busy => s_reg_status.tt_dma_busy,
|
|
channel_init => s_reg_control.tt_dma_init,
|
|
addr_start => s_reg_control.tt_addr_start,
|
|
addr_end => s_reg_control.tt_addr_end,
|
|
addr_limit => s_reg_control.tt_addr_limit,
|
|
addr_interrupt => s_reg_control.tt_addr_intr,
|
|
addr_pointer => s_reg_status.tt_addr_ptr,
|
|
intr_en => s_reg_control.tt_intr_en,
|
|
intr_clear => s_reg_control.tt_intr_clear,
|
|
intr_out => s_irq_pending(1),
|
|
in_valid => s_tt_dma_valid,
|
|
in_ready => s_tt_dma_ready,
|
|
in_empty => s_tt_dma_empty,
|
|
in_data => s_tt_dma_data,
|
|
write_cmd_addr => s_dma_write_cmd_addr(1),
|
|
write_cmd_length => s_dma_write_cmd_length(1),
|
|
write_cmd_valid => s_dma_write_cmd_valid(1),
|
|
write_cmd_ready => s_dma_write_cmd_ready(1),
|
|
write_data => s_dma_write_data(1),
|
|
write_data_ready => s_dma_write_data_ready(1),
|
|
write_finished => s_dma_write_finished(1) );
|
|
|
|
-- Timestamp generator.
|
|
inst_timestamp_gen: entity work.timestamp_gen
|
|
port map (
|
|
clk => clk_adc,
|
|
reset => s_reset,
|
|
clear => s_reg_control.timestamp_clear,
|
|
timestamp => s_timestamp );
|
|
|
|
s_reg_status.timestamp <= s_timestamp;
|
|
|
|
-- Capture ADC data.
|
|
-- ADC A handles channels 0 and 1.
|
|
-- ADC B handles channels 2 and 3.
|
|
-- Each channel receives one 14-bit sample per clock cycle.
|
|
-- The 14 bits are transferred through 7 DDR signals.
|
|
gen_adc_capture: for i in 0 to 3 generate
|
|
inst_adc_capture: entity work.adc_capture_ddr
|
|
port map (
|
|
clk_capture => clk_adc_capture(i / 2),
|
|
clk_intermediate => clk_adc_capture(0),
|
|
clk_handoff => clk_adc,
|
|
in_data => adc_dat_i(i),
|
|
out_data => s_adc_data(i) );
|
|
end generate;
|
|
|
|
-- Optionally generate simulated ADC samples.
|
|
gen_adc_sample_stream: for i in 0 to 1 generate
|
|
inst_adc_sample_stream: entity work.adc_sample_stream
|
|
port map (
|
|
clk => clk_adc,
|
|
reset => s_reset,
|
|
simulate => s_reg_control.simulate_adc,
|
|
in_data => s_adc_data(2*i to 2*i+1),
|
|
out_data => s_adc_sample(2*i to 2*i+1) );
|
|
end generate;
|
|
|
|
-- Monitor range of ADC samples.
|
|
inst_monitor_gen: for i in 0 to 3 generate
|
|
inst_range_monitor: entity work.adc_range_monitor
|
|
generic map (
|
|
signed_data => false )
|
|
port map (
|
|
clk => clk_adc,
|
|
reset => s_reset,
|
|
clear => s_reg_control.adc_range_clear,
|
|
in_data => s_adc_sample(i),
|
|
min_value => s_reg_status.adc_min_value(i),
|
|
max_value => s_reg_status.adc_max_value(i) );
|
|
end generate;
|
|
|
|
-- Monitor current ADC sample value.
|
|
s_reg_status.adc_sample <= s_adc_sample;
|
|
|
|
-- Analog acquisition data chain.
|
|
inst_acquisition_chain: entity work.acquisition_chain
|
|
generic map (
|
|
num_channels => 4 )
|
|
port map (
|
|
clk => clk_adc,
|
|
reset => s_reset,
|
|
acquisition_en => s_reg_control.acquisition_en,
|
|
trigger_delay => s_reg_control.trigger_delay,
|
|
record_length => s_reg_control.record_length,
|
|
decimation_factor => s_reg_control.decimation_factor,
|
|
averaging => s_reg_control.averaging_en,
|
|
shift_steps => s_reg_control.shift_steps,
|
|
ch4_mode => s_reg_control.ch4_mode,
|
|
trig_auto_en => s_reg_control.trig_auto_en,
|
|
trig_ext_en => s_reg_control.trig_ext_en,
|
|
trig_ext_once => s_reg_control.trig_ext_once,
|
|
trig_force => s_reg_control.trig_force,
|
|
trig_ext_select => s_reg_control.trig_ext_select,
|
|
trig_ext_falling => s_reg_control.trig_ext_falling,
|
|
timestamp_in => s_timestamp,
|
|
adc_data_in => s_adc_sample,
|
|
trig_ext_in => s_dig_sample,
|
|
trig_waiting => s_reg_status.trig_waiting,
|
|
trig_detected => s_reg_status.trig_detected,
|
|
out_valid => s_acq_dma_valid,
|
|
out_ready => s_acq_dma_ready,
|
|
out_empty => s_acq_dma_empty,
|
|
out_data => s_acq_dma_data );
|
|
|
|
-- Capture digital inputs.
|
|
s_dig_in(0) <= exp_p_io(0);
|
|
s_dig_in(1) <= exp_n_io(0);
|
|
s_dig_in(2) <= exp_p_io(1);
|
|
s_dig_in(3) <= exp_n_io(1);
|
|
|
|
inst_dig_capture_gen: for i in 0 to 3 generate
|
|
|
|
-- Use IDDR to capture digital input.
|
|
-- The IDDR is used in pipeline mode; this inserts a secondary flip-flop
|
|
-- in the data path which helps to suppress metastability.
|
|
inst_dig_iddr: IDDR
|
|
generic map (
|
|
DDR_CLK_EDGE => "SAME_EDGE_PIPELINED" )
|
|
port map (
|
|
Q1 => s_dig_sync(i),
|
|
Q2 => open,
|
|
C => clk_adc,
|
|
CE => '1',
|
|
D => s_dig_in(i),
|
|
R => '0',
|
|
S => '0' );
|
|
|
|
-- Deglitch filter.
|
|
inst_dig_deglitch: entity work.deglitch
|
|
generic map (
|
|
deglitch_cycles => 4 )
|
|
port map (
|
|
clk => clk_adc,
|
|
din => s_dig_sync(i),
|
|
dout => s_dig_deglitch(i) );
|
|
|
|
end generate;
|
|
|
|
-- Optionally generate simulated digital signals.
|
|
process (clk_adc) is
|
|
begin
|
|
if rising_edge(clk_adc) then
|
|
if s_reg_control.dig_simulate = '1' then
|
|
s_dig_sample <= s_reg_control.dig_sim_state;
|
|
else
|
|
s_dig_sample <= s_dig_deglitch;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- Monitor digital signal state.
|
|
s_reg_status.dig_sample <= s_dig_sample;
|
|
|
|
-- Time tagger.
|
|
inst_timetagger: entity work.timetagger
|
|
port map (
|
|
clk => clk_adc,
|
|
reset => s_reset,
|
|
channel_en => s_reg_control.timetagger_en,
|
|
marker => s_reg_control.timetagger_mark,
|
|
timestamp_in => s_timestamp,
|
|
dig_sample => s_dig_sample,
|
|
out_valid => s_tt_dma_valid,
|
|
out_ready => s_tt_dma_ready,
|
|
out_empty => s_tt_dma_empty,
|
|
out_data => s_tt_dma_data );
|
|
|
|
-- Collect interrupt signals from peripherals and generate interrupt to PS.
|
|
s_reg_status.irq_pending <= s_irq_pending;
|
|
s_irq_f2p(0) <= s_reg_control.irq_enable and or_reduce(s_irq_pending);
|
|
s_irq_f2p(7 downto 1) <= (others => '0');
|
|
|
|
-- Report reset status via GPIO.
|
|
process (clk_adc, s_ext_reset_n) is
|
|
begin
|
|
if s_ext_reset_n = '0' then
|
|
r_reset_done <= '0';
|
|
elsif rising_edge(clk_adc) then
|
|
r_reset_done <= not s_reset;
|
|
end if;
|
|
end process;
|
|
|
|
-- Blinking LED, 1 Hz.
|
|
process (clk_adc) is
|
|
begin
|
|
if rising_edge(clk_adc) then
|
|
if s_reset = '1' then
|
|
r_adcclk_cnt <= (others => '0');
|
|
r_adcclk_led <= '0';
|
|
elsif r_adcclk_cnt = 62499999 then
|
|
r_adcclk_cnt <= (others => '0');
|
|
r_adcclk_led <= not r_adcclk_led;
|
|
else
|
|
r_adcclk_cnt <= r_adcclk_cnt + 1;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
end architecture;
|