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;
|
|
|
|
reg_status: in registers_status;
|
|
|
|
reg_trigger: out registers_trigger
|
|
|
|
);
|
|
|
|
|
|
|
|
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;
|
|
|
|
reg_trigger: registers_trigger;
|
|
|
|
end record;
|
|
|
|
|
|
|
|
constant regs_init: regs_type := (
|
|
|
|
pready => '0',
|
|
|
|
prdata => (others => '0'),
|
|
|
|
reg_control => registers_control_init,
|
|
|
|
reg_trigger => registers_trigger_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;
|
|
|
|
reg_trigger <= r.reg_trigger;
|
|
|
|
|
|
|
|
-- Combinatorial process.
|
|
|
|
process (all) is
|
|
|
|
variable v: regs_type;
|
|
|
|
begin
|
|
|
|
-- Load current register values.
|
|
|
|
v := r;
|
|
|
|
|
|
|
|
-- Clear single-cycle trigger pulses.
|
|
|
|
v.reg_trigger := registers_trigger_init;
|
|
|
|
|
|
|
|
-- 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-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;
|
|
|
|
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);
|
|
|
|
when reg_dma_clear => v.reg_trigger.dma_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);
|
|
|
|
v.reg_trigger.acq_channel_init := apb_pwdata(1);
|
|
|
|
when reg_acq_intr_ctrl =>
|
|
|
|
v.reg_control.acq_intr_en := apb_pwdata(0);
|
|
|
|
v.reg_trigger.acq_intr_clear := apb_pwdata(1);
|
|
|
|
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;
|