redpitaya-puzzlefw/fpga/rtl/puzzlefw_top.vhd

441 lines
18 KiB
VHDL

--
-- Top-level FPGA design for Red Pitaya PuzzleFW firmware.
--
-- Joris van Rantwijk 2024
--
library ieee;
use ieee.std_logic_1164.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 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; -- ADC data
adc_clk_i: in std_logic_vector(1 downto 0); -- ADC clock 1=pos, 0=neg
adc_clk_o: out std_logic_vector(1 downto 0); -- optional clock output for ADC
adc_cdcs_o: out std_logic; -- ADC clock duty cycle stabilizer
dac_dat_o: out std_logic_vector(13 downto 0); -- DAC data
dac_wrt_o: out std_logic; -- DAC write control
dac_sel_o: out std_logic; -- DAC channel select
dac_clk_o: out std_logic; -- DAC clock
dac_rst_o: out std_logic; -- DAC reset
dac_pwm_o: out std_logic_vector(3 downto 0); -- PWM DAC
exp_p_io: inout std_logic_vector(7 downto 0); -- extension I/O pos
exp_n_io: inout std_logic_vector(7 downto 0); -- extension I/O neg
led_o: inout std_logic_vector(7 downto 0) -- LEDs
);
end puzzlefw_top;
architecture arch of puzzlefw_top is
-- Main 125 MHz clock, derived from ADC clock input port.
signal clk_adc: std_logic;
-- Auxiliary clock from FCLK0.
signal clk_fclk: std_logic;
-- Main reset signal, derived from FCLK_RESET0, active high, synchronous to clk_adc.
signal s_reset: std_logic;
signal s_adc_clk_ibuf: std_logic;
signal r_fclk_cnt: unsigned(26 downto 0);
signal r_fclk_led: std_logic;
signal r_adcclk_cnt: unsigned(26 downto 0);
signal r_adcclk_led: std_logic;
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;
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;
signal s_irq: std_logic_vector(7 downto 0);
signal s_reg_control: registers_control;
signal s_reg_status: registers_status;
signal s_reg_trigger: registers_trigger;
signal s_dma_read_cmd_addr: dma_address_type;
signal s_dma_read_cmd_valid: std_logic;
signal s_dma_read_cmd_ready: std_logic;
signal s_dma_read_data: dma_data_type;
signal s_dma_read_data_valid: std_logic;
signal s_dma_write_cmd_addr: dma_address_type;
signal s_dma_write_cmd_valid: std_logic;
signal s_dma_write_cmd_ready: std_logic;
signal s_dma_write_data: dma_data_type;
signal s_dma_write_data_ready: std_logic;
signal s_dma_write_finished: std_logic;
signal r_test_prefetch: std_logic;
signal r_test_raddr: std_logic_vector(9 downto 0);
signal r_test_waddr: std_logic_vector(9 downto 0);
signal s_test_dout: std_logic_vector(63 downto 0);
signal s_test_ren: std_logic;
begin
s_irq <= s_reg_control.test_irq;
led_o(7 downto 2) <= s_reg_control.test_led(7 downto 2);
-- Differential clock input for ADC clock.
inst_ibuf_adc_clk: IBUFDS
port map (
O => s_adc_clk_ibuf,
I => adc_clk_i(1),
IB => adc_clk_i(0)
);
-- Clock buffer for ADC clock.
inst_bufg_adc_clk: BUFG
port map (
I => s_adc_clk_ibuf,
O => clk_adc
);
inst_obuf_led0: OBUF
port map (
I => r_fclk_led,
O => led_o(0)
);
inst_obuf_led1: OBUF
port map (
I => r_adcclk_led,
O => led_o(1)
);
-- ARM/PS block design.
inst_blockdesign: entity work.puzzlefw_wrapper
port map (
sys_clk => clk_adc,
ps_fclk => clk_fclk,
peripheral_reset_0(0) => s_reset,
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,
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,
IRQ_F2P => s_irq,
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
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,
reg_trigger => s_reg_trigger
);
-- AXI master.
inst_axi_master: entity work.dma_axi_master
generic map (
transfer_size => 16,
num_read_channels => 1,
num_write_channels => 1 )
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_trigger.dma_clear,
read_cmd_addr(0) => s_dma_read_cmd_addr,
read_cmd_valid(0) => s_dma_read_cmd_valid,
read_cmd_ready(0) => s_dma_read_cmd_ready,
read_data(0) => s_dma_read_data,
read_data_valid(0) => s_dma_read_data_valid,
write_cmd_addr(0) => s_dma_write_cmd_addr,
write_cmd_valid(0) => s_dma_write_cmd_valid,
write_cmd_ready(0) => s_dma_write_cmd_ready,
write_data(0) => s_dma_write_data,
write_data_ready(0) => s_dma_write_data_ready,
write_finished(0) => 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
);
-- little test machine for DMA
inst_mem: xpm_memory_sdpram
generic map (
CLOCKING_MODE => "common_clock",
MEMORY_PRIMITIVE => "block",
MEMORY_SIZE => 1024 * 64,
ADDR_WIDTH_A => 10,
ADDR_WIDTH_B => 10,
WRITE_DATA_WIDTH_A => 64,
BYTE_WRITE_WIDTH_A => 64,
READ_DATA_WIDTH_B => 64,
READ_LATENCY_B => 1 )
port map (
clka => clk_adc,
clkb => clk_adc,
rstb => s_reset,
addra => r_test_waddr,
addrb => r_test_raddr,
dina => s_dma_read_data,
doutb => s_test_dout,
ena => s_dma_read_data_valid,
enb => s_test_ren,
wea => "1",
regceb => '1',
injectdbiterra => '0',
injectsbiterra => '0',
sleep => '0' );
s_dma_write_data <= not s_test_dout;
s_test_ren <= r_test_prefetch or s_dma_write_data_ready;
process (clk_adc) is
begin
if rising_edge(clk_adc) then
r_test_prefetch <= '0';
if s_dma_read_cmd_ready = '1' and s_dma_read_cmd_valid = '1' then
if unsigned(s_dma_read_cmd_addr) < 1008 then
s_dma_read_cmd_addr <= std_logic_vector(unsigned(s_dma_read_cmd_addr) + 16);
else
s_dma_read_cmd_valid <= '0';
end if;
end if;
if s_dma_read_data_valid = '1' then
s_reg_status.rcnt <= s_reg_status.rcnt + 1;
r_test_waddr <= std_logic_vector(unsigned(r_test_waddr) + 1);
if unsigned(r_test_waddr) = 1023 then
s_dma_write_cmd_valid <= '1';
r_test_prefetch <= '1';
end if;
end if;
if s_dma_write_cmd_ready = '1' and s_dma_write_cmd_valid = '1' then
if unsigned(s_dma_write_cmd_addr) < 1008 then
s_dma_write_cmd_addr <= std_logic_vector(unsigned(s_dma_write_cmd_addr) + 16);
else
s_dma_write_cmd_valid <= '0';
end if;
end if;
if (r_test_prefetch = '1') or (s_dma_write_data_ready = '1') then
r_test_raddr <= std_logic_vector(unsigned(r_test_raddr) + 1);
end if;
if s_dma_write_finished = '1' then
s_reg_status.wcnt <= s_reg_status.wcnt + 1;
end if;
if s_reg_trigger.start = '1' then
r_test_waddr <= (others => '0');
r_test_raddr <= (others => '0');
s_dma_read_cmd_addr <= (others => '0');
s_dma_write_cmd_addr <= (others => '0');
s_dma_read_cmd_valid <= '1';
s_dma_write_cmd_valid <= '0';
end if;
end if;
end process;
-- END test
process (clk_fclk) is
begin
if rising_edge(clk_fclk) then
r_fclk_cnt <= r_fclk_cnt + 1;
r_fclk_led <= r_fclk_cnt(r_fclk_cnt'high);
end if;
end process;
process (clk_adc) is
begin
if rising_edge(clk_adc) then
r_adcclk_cnt <= r_adcclk_cnt + 1;
r_adcclk_led <= r_adcclk_cnt(r_adcclk_cnt'high);
end if;
end process;
end architecture;