2024-08-02 21:47:58 +02:00
|
|
|
--
|
|
|
|
-- Memory-mapped registers for Red Pitaya PuzzleFW firmware.
|
|
|
|
--
|
|
|
|
-- Joris van Rantwijk 2024
|
|
|
|
--
|
|
|
|
|
|
|
|
library ieee;
|
|
|
|
use ieee.std_logic_1164.all;
|
|
|
|
use ieee.numeric_std.all;
|
|
|
|
|
|
|
|
use work.puzzlefw_pkg.all;
|
|
|
|
|
|
|
|
|
|
|
|
entity registers is
|
|
|
|
|
|
|
|
port (
|
|
|
|
-- Main clock, active on rising edge.
|
|
|
|
clk: in std_logic;
|
|
|
|
|
|
|
|
-- Reset, active high, synchronous to main clock.
|
|
|
|
reset: in std_logic;
|
|
|
|
|
|
|
|
-- APB bus interface.
|
|
|
|
apb_psel: in std_logic;
|
|
|
|
apb_penable: in std_logic;
|
|
|
|
apb_pwrite: in std_logic;
|
|
|
|
apb_paddr: in std_logic_vector(31 downto 0);
|
|
|
|
apb_pwdata: in std_logic_vector(31 downto 0);
|
|
|
|
apb_pready: out std_logic;
|
|
|
|
apb_pslverr: out std_logic;
|
|
|
|
apb_prdata: out std_logic_vector(31 downto 0);
|
|
|
|
|
|
|
|
-- FPGA interface.
|
|
|
|
reg_control: out registers_control;
|
2024-08-26 12:52:35 +02:00
|
|
|
reg_status: in registers_status
|
2024-08-02 21:47:58 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
end entity;
|
|
|
|
|
|
|
|
architecture arch of registers is
|
|
|
|
|
|
|
|
type regs_type is record
|
|
|
|
pready: std_logic;
|
|
|
|
prdata: std_logic_vector(31 downto 0);
|
|
|
|
reg_control: registers_control;
|
|
|
|
end record;
|
|
|
|
|
|
|
|
constant regs_init: regs_type := (
|
|
|
|
pready => '0',
|
|
|
|
prdata => (others => '0'),
|
2024-08-26 12:52:35 +02:00
|
|
|
reg_control => registers_control_init
|
2024-08-02 21:47:58 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
signal r: regs_type := regs_init;
|
|
|
|
signal rnext: regs_type;
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
|
|
|
-- Drive output signals.
|
|
|
|
apb_pready <= r.pready;
|
|
|
|
apb_pslverr <= '0'; -- never signal errors
|
|
|
|
apb_prdata <= r.prdata;
|
|
|
|
reg_control <= r.reg_control;
|
|
|
|
|
|
|
|
-- Combinatorial process.
|
|
|
|
process (all) is
|
|
|
|
variable v: regs_type;
|
|
|
|
begin
|
|
|
|
-- Load current register values.
|
|
|
|
v := r;
|
|
|
|
|
|
|
|
-- Clear single-cycle trigger pulses.
|
2024-08-26 12:52:35 +02:00
|
|
|
v.reg_control.dma_clear := '0';
|
|
|
|
v.reg_control.timestamp_clear := '0';
|
|
|
|
v.reg_control.acq_channel_init := '0';
|
|
|
|
v.reg_control.acq_intr_clear := '0';
|
|
|
|
v.reg_control.trig_force := '0';
|
2024-08-26 23:11:16 +02:00
|
|
|
v.reg_control.adc_range_clear := '0';
|
2024-08-02 21:47:58 +02:00
|
|
|
|
|
|
|
-- Respond to each APB access on the next clock cycle (no wait states).
|
|
|
|
v.pready := apb_psel and (not apb_penable);
|
|
|
|
|
|
|
|
-- Handle APB read transfer.
|
|
|
|
if apb_psel = '1' and apb_penable = '0' and apb_pwrite = '0' then
|
|
|
|
|
|
|
|
-- Initialize result to all-zero bits.
|
|
|
|
v.prdata := (others => '0');
|
|
|
|
|
|
|
|
-- Determine read result as function of address.
|
|
|
|
case to_integer(unsigned(apb_paddr and reg_addr_mask)) is
|
|
|
|
when reg_info => v.prdata := fw_info_word;
|
|
|
|
when reg_irq_enable => v.prdata(0) := r.reg_control.irq_enable;
|
2024-08-09 20:16:53 +02:00
|
|
|
when reg_irq_pending => v.prdata(0 downto 0) := reg_status.irq_pending;
|
2024-08-02 21:47:58 +02:00
|
|
|
when reg_dma_en => v.prdata(0) := r.reg_control.dma_en;
|
|
|
|
when reg_dma_status =>
|
|
|
|
v.prdata(0) := reg_status.dma_busy;
|
|
|
|
v.prdata(1) := reg_status.dma_err_read;
|
|
|
|
v.prdata(2) := reg_status.dma_err_write;
|
|
|
|
v.prdata(3) := reg_status.dma_err_address;
|
|
|
|
v.prdata(4) := reg_status.dma_err_any;
|
2024-08-26 12:52:35 +02:00
|
|
|
when reg_timestamp_lo => v.prdata := reg_status.timestamp(31 downto 0);
|
|
|
|
when reg_timestamp_hi => v.prdata(15 downto 0) := reg_status.timestamp(47 downto 32);
|
2024-08-09 20:16:53 +02:00
|
|
|
when reg_acq_addr_start => v.prdata(31 downto 7) := r.reg_control.acq_addr_start;
|
|
|
|
when reg_acq_addr_end => v.prdata(31 downto 7) := r.reg_control.acq_addr_end;
|
|
|
|
when reg_acq_addr_limit => v.prdata(31 downto 7) := r.reg_control.acq_addr_limit;
|
2024-08-24 23:04:35 +02:00
|
|
|
when reg_acq_addr_intr => v.prdata(31 downto 3) := r.reg_control.acq_addr_intr;
|
|
|
|
when reg_acq_addr_ptr => v.prdata(31 downto 3) := reg_status.acq_addr_ptr;
|
|
|
|
when reg_acq_channel_ctrl =>
|
|
|
|
v.prdata(0) := r.reg_control.acq_channel_en;
|
|
|
|
v.prdata(8) := reg_status.acq_channel_busy;
|
2024-08-09 20:16:53 +02:00
|
|
|
when reg_acq_intr_ctrl => v.prdata(0) := r.reg_control.acq_intr_en;
|
2024-08-26 12:52:35 +02:00
|
|
|
when reg_acquisition_en => v.prdata(0) := r.reg_control.acquisition_en;
|
|
|
|
when reg_record_length => v.prdata(15 downto 0) := r.reg_control.record_length;
|
|
|
|
when reg_decimation_factor => v.prdata(17 downto 0) := r.reg_control.decimation_factor;
|
|
|
|
when reg_shift_steps => v.prdata(3 downto 0) := r.reg_control.shift_steps;
|
|
|
|
when reg_averaging_en => v.prdata(0) := r.reg_control.averaging_en;
|
|
|
|
when reg_ch4_mode => v.prdata(0) := r.reg_control.ch4_mode;
|
|
|
|
when reg_simulate_adc => v.prdata(0) := r.reg_control.simulate_adc;
|
|
|
|
when reg_trigger_mode =>
|
|
|
|
v.prdata(0) := r.reg_control.trig_auto_en;
|
|
|
|
v.prdata(1) := r.reg_control.trig_ext_en;
|
|
|
|
v.prdata(5 downto 4) := r.reg_control.trig_ext_select;
|
|
|
|
v.prdata(7) := r.reg_control.trig_ext_falling;
|
|
|
|
when reg_trigger_delay => v.prdata(15 downto 0) := r.reg_control.trigger_delay;
|
|
|
|
when reg_trigger_status => v.prdata(0) := reg_status.trig_waiting;
|
2024-08-26 23:11:16 +02:00
|
|
|
when reg_adc_sample =>
|
|
|
|
v.prdata(adc_data_bits - 1 downto 0) := reg_status.adc_sample(0);
|
|
|
|
v.prdata(adc_data_bits + 15 downto 16) := reg_status.adc_sample(1);
|
|
|
|
when reg_adc23_sample =>
|
|
|
|
v.prdata(adc_data_bits - 1 downto 0) := reg_status.adc_sample(2);
|
|
|
|
v.prdata(adc_data_bits + 15 downto 16) := reg_status.adc_sample(3);
|
|
|
|
when reg_adc0_minmax =>
|
|
|
|
v.prdata(adc_data_bits - 1 downto 0) := reg_status.adc_min_value(0);
|
|
|
|
v.prdata(adc_data_bits + 15 downto 16) := reg_status.adc_max_value(0);
|
|
|
|
when reg_adc1_minmax =>
|
|
|
|
v.prdata(adc_data_bits - 1 downto 0) := reg_status.adc_min_value(1);
|
|
|
|
v.prdata(adc_data_bits + 15 downto 16) := reg_status.adc_max_value(1);
|
|
|
|
when reg_adc2_minmax =>
|
|
|
|
v.prdata(adc_data_bits - 1 downto 0) := reg_status.adc_min_value(2);
|
|
|
|
v.prdata(adc_data_bits + 15 downto 16) := reg_status.adc_max_value(2);
|
|
|
|
when reg_adc3_minmax =>
|
|
|
|
v.prdata(adc_data_bits - 1 downto 0) := reg_status.adc_min_value(3);
|
|
|
|
v.prdata(adc_data_bits + 15 downto 16) := reg_status.adc_max_value(3);
|
2024-08-09 20:16:53 +02:00
|
|
|
when reg_test_led => v.prdata(7 downto 0) := r.reg_control.test_led;
|
2024-08-24 23:04:35 +02:00
|
|
|
when reg_test_divider => v.prdata(15 downto 0) := r.reg_control.test_divider;
|
2024-08-02 21:47:58 +02:00
|
|
|
when reg_dma_buf_addr => v.prdata(31 downto 12) := r.reg_control.dma_buf_addr;
|
|
|
|
when reg_dma_buf_size => v.prdata(31 downto 12) := r.reg_control.dma_buf_size;
|
|
|
|
when others => null;
|
|
|
|
end case;
|
|
|
|
|
|
|
|
end if;
|
|
|
|
|
|
|
|
-- Handle APB write transfer.
|
|
|
|
if apb_psel = '1' and apb_penable = '0' and apb_pwrite = '1' then
|
|
|
|
case to_integer(unsigned(apb_paddr and reg_addr_mask)) is
|
|
|
|
when reg_irq_enable => v.reg_control.irq_enable := apb_pwdata(0);
|
|
|
|
when reg_dma_en => v.reg_control.dma_en := apb_pwdata(0);
|
2024-08-26 12:52:35 +02:00
|
|
|
when reg_dma_clear => v.reg_control.dma_clear := apb_pwdata(0);
|
|
|
|
when reg_timestamp_clear => v.reg_control.timestamp_clear := apb_pwdata(0);
|
2024-08-09 20:16:53 +02:00
|
|
|
when reg_acq_addr_start => v.reg_control.acq_addr_start := apb_pwdata(31 downto 7);
|
|
|
|
when reg_acq_addr_end => v.reg_control.acq_addr_end := apb_pwdata(31 downto 7);
|
|
|
|
when reg_acq_addr_limit => v.reg_control.acq_addr_limit := apb_pwdata(31 downto 7);
|
2024-08-24 23:04:35 +02:00
|
|
|
when reg_acq_addr_intr => v.reg_control.acq_addr_intr := apb_pwdata(31 downto 3);
|
2024-08-09 20:16:53 +02:00
|
|
|
when reg_acq_channel_ctrl =>
|
|
|
|
v.reg_control.acq_channel_en := apb_pwdata(0);
|
2024-08-26 12:52:35 +02:00
|
|
|
v.reg_control.acq_channel_init := apb_pwdata(1);
|
2024-08-09 20:16:53 +02:00
|
|
|
when reg_acq_intr_ctrl =>
|
|
|
|
v.reg_control.acq_intr_en := apb_pwdata(0);
|
2024-08-26 12:52:35 +02:00
|
|
|
v.reg_control.acq_intr_clear := apb_pwdata(1);
|
|
|
|
when reg_acquisition_en => v.reg_control.acquisition_en := apb_pwdata(0);
|
|
|
|
when reg_record_length => v.reg_control.record_length := apb_pwdata(15 downto 0);
|
|
|
|
when reg_decimation_factor => v.reg_control.decimation_factor := apb_pwdata(17 downto 0);
|
|
|
|
when reg_shift_steps => v.reg_control.shift_steps := apb_pwdata(3 downto 0);
|
|
|
|
when reg_averaging_en => v.reg_control.averaging_en := apb_pwdata(0);
|
|
|
|
when reg_ch4_mode => v.reg_control.ch4_mode := apb_pwdata(0);
|
|
|
|
when reg_simulate_adc => v.reg_control.simulate_adc := apb_pwdata(0);
|
|
|
|
when reg_trigger_mode =>
|
|
|
|
v.reg_control.trig_auto_en := apb_pwdata(0);
|
|
|
|
v.reg_control.trig_ext_en := apb_pwdata(1);
|
|
|
|
v.reg_control.trig_ext_select := apb_pwdata(5 downto 4);
|
|
|
|
v.reg_control.trig_ext_falling := apb_pwdata(7);
|
|
|
|
v.reg_control.trig_force := apb_pwdata(8);
|
|
|
|
when reg_trigger_delay => v.reg_control.trigger_delay := apb_pwdata(15 downto 0);
|
2024-08-26 23:11:16 +02:00
|
|
|
when reg_adc_range_clear => v.reg_control.adc_range_clear := apb_pwdata(0);
|
2024-08-09 20:16:53 +02:00
|
|
|
when reg_test_led => v.reg_control.test_led := apb_pwdata(7 downto 0);
|
2024-08-24 23:04:35 +02:00
|
|
|
when reg_test_divider => v.reg_control.test_divider := apb_pwdata(15 downto 0);
|
2024-08-02 21:47:58 +02:00
|
|
|
when reg_dma_buf_addr => v.reg_control.dma_buf_addr := apb_pwdata(31 downto 12);
|
|
|
|
when reg_dma_buf_size => v.reg_control.dma_buf_size := apb_pwdata(31 downto 12);
|
|
|
|
when others => null;
|
|
|
|
end case;
|
|
|
|
end if;
|
2024-08-09 20:16:53 +02:00
|
|
|
|
2024-08-02 21:47:58 +02:00
|
|
|
-- Synchronous reset.
|
|
|
|
if reset = '1' then
|
|
|
|
v := regs_init;
|
|
|
|
end if;
|
|
|
|
|
|
|
|
-- Drive new register values to synchronous process.
|
|
|
|
rnext <= v;
|
|
|
|
|
|
|
|
end process;
|
|
|
|
|
|
|
|
-- Synchronous process.
|
|
|
|
process (clk) is
|
|
|
|
begin
|
|
|
|
if rising_edge(clk) then
|
|
|
|
r <= rnext;
|
|
|
|
end if;
|
|
|
|
end process;
|
|
|
|
|
|
|
|
end architecture;
|