redpitaya-puzzlefw/fpga/rtl/registers.vhd

240 lines
12 KiB
VHDL

--
-- 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;
reg_status: in registers_status
);
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'),
reg_control => registers_control_init
);
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.
v.reg_control.dma_clear := '0';
v.reg_control.timestamp_clear := '0';
v.reg_control.acq_dma_init := '0';
v.reg_control.acq_intr_clear := '0';
v.reg_control.trig_force := '0';
v.reg_control.adc_range_clear := '0';
v.reg_control.tt_dma_init := '0';
v.reg_control.tt_intr_clear := '0';
v.reg_control.timetagger_mark := '0';
-- 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;
when reg_irq_pending => v.prdata(1 downto 0) := reg_status.irq_pending;
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;
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);
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;
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_dma_ctrl => v.prdata(0) := r.reg_control.acq_dma_en;
when reg_acq_intr_ctrl => v.prdata(0) := r.reg_control.acq_intr_en;
when reg_acq_dma_status => v.prdata(0) := reg_status.acq_dma_busy;
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;
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);
when reg_tt_addr_start => v.prdata(31 downto 7) := r.reg_control.tt_addr_start;
when reg_tt_addr_end => v.prdata(31 downto 7) := r.reg_control.tt_addr_end;
when reg_tt_addr_limit => v.prdata(31 downto 7) := r.reg_control.tt_addr_limit;
when reg_tt_addr_intr => v.prdata(31 downto 3) := r.reg_control.tt_addr_intr;
when reg_tt_addr_ptr => v.prdata(31 downto 3) := reg_status.tt_addr_ptr;
when reg_tt_dma_ctrl => v.prdata(0) := r.reg_control.tt_dma_en;
when reg_tt_intr_ctrl => v.prdata(0) := r.reg_control.tt_intr_en;
when reg_tt_dma_status => v.prdata(0) := reg_status.tt_dma_busy;
when reg_timetagger_en => v.prdata(7 downto 0) := r.reg_control.timetagger_en;
when reg_dig_simulate =>
v.prdata(8) := r.reg_control.dig_simulate;
v.prdata(3 downto 0) := r.reg_control.dig_sim_state;
when reg_dig_sample => v.prdata(3 downto 0) := reg_status.dig_sample;
when reg_led_state => v.prdata(7 downto 0) := r.reg_control.led_state;
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);
when reg_dma_clear => v.reg_control.dma_clear := apb_pwdata(0);
when reg_timestamp_clear => v.reg_control.timestamp_clear := apb_pwdata(0);
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);
when reg_acq_addr_intr => v.reg_control.acq_addr_intr := apb_pwdata(31 downto 3);
when reg_acq_dma_ctrl =>
v.reg_control.acq_dma_en := apb_pwdata(0);
v.reg_control.acq_dma_init := apb_pwdata(1);
when reg_acq_intr_ctrl =>
v.reg_control.acq_intr_en := apb_pwdata(0);
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);
when reg_adc_range_clear => v.reg_control.adc_range_clear := apb_pwdata(0);
when reg_tt_addr_start => v.reg_control.tt_addr_start := apb_pwdata(31 downto 7);
when reg_tt_addr_end => v.reg_control.tt_addr_end := apb_pwdata(31 downto 7);
when reg_tt_addr_limit => v.reg_control.tt_addr_limit := apb_pwdata(31 downto 7);
when reg_tt_addr_intr => v.reg_control.tt_addr_intr := apb_pwdata(31 downto 3);
when reg_tt_dma_ctrl =>
v.reg_control.tt_dma_en := apb_pwdata(0);
v.reg_control.tt_dma_init := apb_pwdata(1);
when reg_tt_intr_ctrl =>
v.reg_control.tt_intr_en := apb_pwdata(0);
v.reg_control.tt_intr_clear := apb_pwdata(1);
when reg_timetagger_en => v.reg_control.timetagger_en := apb_pwdata(7 downto 0);
when reg_timetagger_mark => v.reg_control.timetagger_mark := apb_pwdata(0);
when reg_dig_simulate =>
v.reg_control.dig_simulate := apb_pwdata(8);
v.reg_control.dig_sim_state := apb_pwdata(3 downto 0);
when reg_led_state => v.reg_control.led_state := apb_pwdata(7 downto 0);
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;
-- 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;