Add VHDL for DMA write channel
This commit is contained in:
		
							parent
							
								
									f58343fc0f
								
							
						
					
					
						commit
						5632ffc6b2
					
				|  | @ -207,7 +207,8 @@ architecture arch of dma_axi_master is | ||||||
|                                   limit: std_logic_vector(31 downto 12)) |                                   limit: std_logic_vector(31 downto 12)) | ||||||
|         return boolean |         return boolean | ||||||
|     is begin |     is begin | ||||||
|         return (unsigned(limit) /= 0) and (unsigned(addr) <= shift_left(unsigned(limit), 9) - transfer_size); |         return (unsigned(limit) /= 0) | ||||||
|  |                 and (unsigned(addr) <= shift_left(resize(unsigned(limit), 29), 9) - transfer_size); | ||||||
|     end function; |     end function; | ||||||
| 
 | 
 | ||||||
|     -- Calculate tha AXI address for a DMA transfer by adding the address offset from the client |     -- Calculate tha AXI address for a DMA transfer by adding the address offset from the client | ||||||
|  |  | ||||||
|  | @ -0,0 +1,250 @@ | ||||||
|  | -- | ||||||
|  | --  Management of DMA transfers from FPGA to memory. | ||||||
|  | -- | ||||||
|  | --  The AXI master MUST be configured for 16 beats per transfer. | ||||||
|  | -- | ||||||
|  | --  Joris van Rantwijk 2024 | ||||||
|  | -- | ||||||
|  | 
 | ||||||
|  | library ieee; | ||||||
|  | use ieee.std_logic_1164.all; | ||||||
|  | use ieee.numeric_std.all; | ||||||
|  | 
 | ||||||
|  | use work.puzzlefw_pkg.all; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | entity dma_write_channel is | ||||||
|  | 
 | ||||||
|  |     generic ( | ||||||
|  |         -- Size of the input data queue as 2-log of the number of words. | ||||||
|  |         queue_size_bits:    integer range 5 to 16 := 10 | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     port ( | ||||||
|  |         -- Main clock, active on rising edge. | ||||||
|  |         clk:                in  std_logic; | ||||||
|  | 
 | ||||||
|  |         -- Reset, active high, synchronous to main clock. | ||||||
|  |         reset:              in  std_logic; | ||||||
|  | 
 | ||||||
|  |         -- High to enable the channel, low to pause the channel. | ||||||
|  |         -- When channel_en is low, any ongoing transfer will be completed but | ||||||
|  |         -- no new transfer will be started. | ||||||
|  |         channel_en:         in  std_logic; | ||||||
|  | 
 | ||||||
|  |         -- High to initialize the channel. | ||||||
|  |         -- | ||||||
|  |         -- This resets the write pointer to the start of the buffer and deletes | ||||||
|  |         -- all data from the queue. | ||||||
|  |         -- | ||||||
|  |         -- This function must be used whenever the buffer address range is changed. | ||||||
|  |         -- This function must not be used while uncompleted DMA transfers | ||||||
|  |         -- are in progress. | ||||||
|  |         channel_init:       in  std_logic; | ||||||
|  | 
 | ||||||
|  |         -- Start and end address of the DMA buffer. | ||||||
|  |         -- Both addresses are relative to the DMA window base address. | ||||||
|  |         -- The write pointer wraps to the start address when it would | ||||||
|  |         -- have reached the end address. | ||||||
|  |         addr_start:         in  std_logic_vector(31 downto 7); | ||||||
|  |         addr_end:           in  std_logic_vector(31 downto 7); | ||||||
|  | 
 | ||||||
|  |         -- When the write pointer reaches the limit address, DMA transfers | ||||||
|  |         -- are paused until software updates the limit. | ||||||
|  |         addr_limit:         in  std_logic_vector(31 downto 7); | ||||||
|  | 
 | ||||||
|  |         -- An interrupt is triggered when the write pointer equals the | ||||||
|  |         -- interrupt address. | ||||||
|  |         addr_interrupt:     in  std_logic_vector(31 downto 7); | ||||||
|  | 
 | ||||||
|  |         -- Write pointer. | ||||||
|  |         addr_pointer:       out std_logic_vector(31 downto 7); | ||||||
|  | 
 | ||||||
|  |         -- High to enable interrupt on reaching a configured address. | ||||||
|  |         intr_en:            in  std_logic; | ||||||
|  | 
 | ||||||
|  |         -- Pulsed high to clear a previous interrupt condition. | ||||||
|  |         intr_clear:         in  std_logic; | ||||||
|  | 
 | ||||||
|  |         -- High if an enabled interrupt condition occurred and the interrupt | ||||||
|  |         -- has not been cleared yet. | ||||||
|  |         intr_out:           out std_logic; | ||||||
|  | 
 | ||||||
|  |         -- Input data stream to the channel. | ||||||
|  |         in_valid:           in  std_logic; | ||||||
|  |         in_ready:           out std_logic; | ||||||
|  |         in_data:            in  dma_data_type; | ||||||
|  | 
 | ||||||
|  |         -- Signals to AXI master. | ||||||
|  |         write_cmd_addr:     out dma_address_type; | ||||||
|  |         write_cmd_valid:    out std_logic; | ||||||
|  |         write_cmd_ready:    in  std_logic; | ||||||
|  |         write_data:         out dma_data_type; | ||||||
|  |         write_data_ready:   in  std_logic; | ||||||
|  |         write_finished:     in  std_logic | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  | end entity; | ||||||
|  | 
 | ||||||
|  | architecture arch of dma_write_channel is | ||||||
|  | 
 | ||||||
|  |     -- Number of beats per DMA transfer. | ||||||
|  |     -- The AXI master must use the same transfer size. | ||||||
|  |     -- Address alignments must match the transfer size. | ||||||
|  |     constant transfer_size: integer := 16; | ||||||
|  | 
 | ||||||
|  |     type state_type is (STATE_IDLE, STATE_START, STATE_FLOW); | ||||||
|  | 
 | ||||||
|  |     type regs_type is record | ||||||
|  |         cmd_valid:          std_logic; | ||||||
|  |         cmd_addr:           std_logic_vector(31 downto 7); | ||||||
|  |         addr_pointer:       std_logic_vector(31 downto 7); | ||||||
|  |         intr_out:           std_logic; | ||||||
|  |         state:              state_type; | ||||||
|  |         pending_beats:      unsigned(4 downto 0); | ||||||
|  |     end record; | ||||||
|  | 
 | ||||||
|  |     constant regs_init: regs_type := ( | ||||||
|  |         cmd_valid       => '0', | ||||||
|  |         cmd_addr        => (others => '0'), | ||||||
|  |         addr_pointer    => (others => '0'), | ||||||
|  |         intr_out        => '0', | ||||||
|  |         state           => STATE_IDLE, | ||||||
|  |         pending_beats   => (others => '0') | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     signal r: regs_type := regs_init; | ||||||
|  |     signal rnext: regs_type; | ||||||
|  | 
 | ||||||
|  |     signal s_fifo_reset:    std_logic; | ||||||
|  |     signal s_fifo_length:   unsigned(queue_size_bits - 1 downto 0); | ||||||
|  | 
 | ||||||
|  | begin | ||||||
|  | 
 | ||||||
|  |     -- | ||||||
|  |     -- Data FIFO. | ||||||
|  |     -- | ||||||
|  |     inst_fifo: entity work.simple_fifo | ||||||
|  |         generic map ( | ||||||
|  |             data_width          => 64, | ||||||
|  |             fifo_depth_bits     => queue_size_bits ) | ||||||
|  |         port map ( | ||||||
|  |             clk                 => clk, | ||||||
|  |             reset               => s_fifo_reset, | ||||||
|  |             in_valid            => in_valid, | ||||||
|  |             in_ready            => in_ready, | ||||||
|  |             in_data             => in_data, | ||||||
|  |             out_valid           => open, | ||||||
|  |             out_ready           => write_data_ready, | ||||||
|  |             out_data            => write_data, | ||||||
|  |             queue_length        => s_fifo_length );  | ||||||
|  | 
 | ||||||
|  |     -- Drive output ports. | ||||||
|  |     addr_pointer    <= r.addr_pointer; | ||||||
|  |     intr_out        <= r.intr_out; | ||||||
|  |     write_cmd_addr  <= r.cmd_addr & "0000"; | ||||||
|  |     write_cmd_valid <= r.cmd_valid; | ||||||
|  | 
 | ||||||
|  |     -- Drive reset signal to FIFO. | ||||||
|  |     s_fifo_reset    <= reset or channel_init; | ||||||
|  | 
 | ||||||
|  |     -- | ||||||
|  |     -- Combinatorial process. | ||||||
|  |     -- | ||||||
|  |     process (all) is | ||||||
|  |         variable v: regs_type; | ||||||
|  |     begin | ||||||
|  |         -- Load current register values. | ||||||
|  |         v := r; | ||||||
|  | 
 | ||||||
|  |         -- State machine. | ||||||
|  |         case r.state is | ||||||
|  | 
 | ||||||
|  |             when STATE_IDLE => | ||||||
|  |                 -- Issue a new transfer when possible. | ||||||
|  |                 -- Data for the whole transfer must be ready in the FIFO. | ||||||
|  |                 if (channel_en = '1') | ||||||
|  |                         and (s_fifo_length >= transfer_size) | ||||||
|  |                         and (r.cmd_addr /= addr_limit) then | ||||||
|  |                     v.cmd_valid := '1'; | ||||||
|  |                     v.state := STATE_START; | ||||||
|  |                     v.pending_beats := to_unsigned(transfer_size, v.pending_beats'length); | ||||||
|  |                 end if; | ||||||
|  | 
 | ||||||
|  |             when STATE_START => | ||||||
|  |                 -- Wait until start of transfer. | ||||||
|  |                 if write_cmd_ready = '1' then | ||||||
|  |                     v.cmd_valid := '0'; | ||||||
|  | 
 | ||||||
|  |                     -- Update command address. | ||||||
|  |                     v.cmd_addr := std_logic_vector(unsigned(r.cmd_addr) + 1); | ||||||
|  |                     if v.cmd_addr = addr_end then | ||||||
|  |                         -- Wrap at end of buffer. | ||||||
|  |                         v.cmd_addr := addr_start; | ||||||
|  |                     end if; | ||||||
|  | 
 | ||||||
|  |                     v.state := STATE_FLOW; | ||||||
|  |                 end if; | ||||||
|  | 
 | ||||||
|  |             when STATE_FLOW => | ||||||
|  |                 -- Wait until last beat. | ||||||
|  |                 if (write_data_ready = '1') and (r.pending_beats = 1) then | ||||||
|  |                     v.state := STATE_IDLE; | ||||||
|  |                 end if; | ||||||
|  | 
 | ||||||
|  |         end case; | ||||||
|  | 
 | ||||||
|  |         -- Count write beats to find end of transfer. | ||||||
|  |         if write_data_ready = '1' then | ||||||
|  |             v.pending_beats := r.pending_beats - 1; | ||||||
|  |         end if; | ||||||
|  | 
 | ||||||
|  |         -- Update pointer on write completion. | ||||||
|  |         if write_finished = '1' then | ||||||
|  |             v.addr_pointer := std_logic_vector(unsigned(r.addr_pointer) + 1); | ||||||
|  |             if v.addr_pointer = addr_end then | ||||||
|  |                 -- Wrap at end of buffer. | ||||||
|  |                 v.addr_pointer := addr_start; | ||||||
|  |             end if; | ||||||
|  |         end if; | ||||||
|  | 
 | ||||||
|  |         -- Clear interrupt. | ||||||
|  |         if intr_clear = '1' then | ||||||
|  |             v.intr_out := '0'; | ||||||
|  |         end if; | ||||||
|  | 
 | ||||||
|  |         -- Raise interrupt when pointer equals threshold. | ||||||
|  |         if (intr_en = '1') and (r.addr_pointer = addr_interrupt) then | ||||||
|  |             v.intr_out := '1'; | ||||||
|  |         end if; | ||||||
|  | 
 | ||||||
|  |         -- Initialize channel. | ||||||
|  |         if channel_init = '1' then | ||||||
|  |             v.cmd_valid := '0'; | ||||||
|  |             v.cmd_addr := addr_start; | ||||||
|  |             v.addr_pointer := addr_start; | ||||||
|  |             v.intr_out := '0'; | ||||||
|  |             v.state := STATE_IDLE; | ||||||
|  |         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; | ||||||
|  | @ -20,25 +20,29 @@ package puzzlefw_pkg is | ||||||
|     type dma_data_array is array(natural range <>) of dma_data_type; |     type dma_data_array is array(natural range <>) of dma_data_type; | ||||||
| 
 | 
 | ||||||
|     -- Register addresses. |     -- Register addresses. | ||||||
|     constant reg_addr_mask:     std_logic_vector(31 downto 0) := x"0010fffc"; |     constant reg_addr_mask:         std_logic_vector(31 downto 0) := x"0010fffc"; | ||||||
|     constant reg_info:          natural := 16#000000#; |     constant reg_info:              natural := 16#000000#; | ||||||
|     constant reg_irq_enable:    natural := 16#000010#; |     constant reg_irq_enable:        natural := 16#000010#; | ||||||
|     constant reg_dma_en:        natural := 16#000100#; |     constant reg_irq_pending:       natural := 16#000014#; | ||||||
|     constant reg_dma_status:    natural := 16#000104#; |     constant reg_dma_en:            natural := 16#000100#; | ||||||
|     constant reg_dma_clear:     natural := 16#000108#; |     constant reg_dma_status:        natural := 16#000104#; | ||||||
|     constant reg_rcnt:          natural := 16#000200#; |     constant reg_dma_clear:         natural := 16#000108#; | ||||||
|     constant reg_wcnt:          natural := 16#000204#; |     constant reg_acq_addr_start:    natural := 16#000200#; | ||||||
|     constant reg_start:         natural := 16#000208#; |     constant reg_acq_addr_end:      natural := 16#000204#; | ||||||
|     constant reg_test_irq:      natural := 16#000400#; |     constant reg_acq_addr_limit:    natural := 16#000208#; | ||||||
|     constant reg_test_led:      natural := 16#000404#; |     constant reg_acq_addr_intr:     natural := 16#00020c#; | ||||||
|     constant reg_dma_buf_addr:  natural := 16#100000#; |     constant reg_acq_addr_ptr:      natural := 16#000210#; | ||||||
|     constant reg_dma_buf_size:  natural := 16#100004#; |     constant reg_acq_channel_ctrl:  natural := 16#000214#; | ||||||
|  |     constant reg_acq_intr_ctrl:     natural := 16#000218#; | ||||||
|  |     constant reg_test_led:          natural := 16#000404#; | ||||||
|  |     constant reg_dma_buf_addr:      natural := 16#100000#; | ||||||
|  |     constant reg_dma_buf_size:      natural := 16#100004#; | ||||||
| 
 | 
 | ||||||
|     -- Firmware info word. |     -- Firmware info word. | ||||||
|     constant fw_api_version:    natural := 1; |     constant fw_api_version:        natural := 1; | ||||||
|     constant fw_version_major:  natural := 0; |     constant fw_version_major:      natural := 0; | ||||||
|     constant fw_version_minor:  natural := 2; |     constant fw_version_minor:      natural := 3; | ||||||
|     constant fw_info_word:      std_logic_vector(31 downto 0) := |     constant fw_info_word:          std_logic_vector(31 downto 0) := | ||||||
|         x"4a" |         x"4a" | ||||||
|         & std_logic_vector(to_unsigned(fw_api_version, 8)) |         & std_logic_vector(to_unsigned(fw_api_version, 8)) | ||||||
|         & std_logic_vector(to_unsigned(fw_version_major, 8)) |         & std_logic_vector(to_unsigned(fw_version_major, 8)) | ||||||
|  | @ -50,42 +54,54 @@ package puzzlefw_pkg is | ||||||
|     -- Control registers: read/write access by processor, output signals to FPGA. |     -- Control registers: read/write access by processor, output signals to FPGA. | ||||||
|     type registers_control is record |     type registers_control is record | ||||||
|         irq_enable:         std_logic; |         irq_enable:         std_logic; | ||||||
|         test_irq:           std_logic_vector(7 downto 0); |  | ||||||
|         test_led:           std_logic_vector(7 downto 0); |         test_led:           std_logic_vector(7 downto 0); | ||||||
|         dma_en:             std_logic; |         dma_en:             std_logic; | ||||||
|  |         acq_addr_start:     std_logic_vector(31 downto 7); | ||||||
|  |         acq_addr_end:       std_logic_vector(31 downto 7); | ||||||
|  |         acq_addr_limit:     std_logic_vector(31 downto 7); | ||||||
|  |         acq_addr_intr:      std_logic_vector(31 downto 7); | ||||||
|  |         acq_channel_en:     std_logic; | ||||||
|  |         acq_intr_en:        std_logic; | ||||||
|         dma_buf_addr:       std_logic_vector(31 downto 12); |         dma_buf_addr:       std_logic_vector(31 downto 12); | ||||||
|         dma_buf_size:       std_logic_vector(31 downto 12); |         dma_buf_size:       std_logic_vector(31 downto 12); | ||||||
|     end record; |     end record; | ||||||
| 
 | 
 | ||||||
|     -- Status registers: input signals from FPGA, read-only access by processor. |     -- Status registers: input signals from FPGA, read-only access by processor. | ||||||
|     type registers_status is record |     type registers_status is record | ||||||
|  |         irq_pending:        std_logic_vector(0 downto 0); | ||||||
|         dma_busy:           std_logic; |         dma_busy:           std_logic; | ||||||
|         dma_err_read:       std_logic; |         dma_err_read:       std_logic; | ||||||
|         dma_err_write:      std_logic; |         dma_err_write:      std_logic; | ||||||
|         dma_err_address:    std_logic; |         dma_err_address:    std_logic; | ||||||
|         dma_err_any:        std_logic; |         dma_err_any:        std_logic; | ||||||
|         rcnt:               unsigned(31 downto 0); |         acq_addr_ptr:       std_logic_vector(31 downto 7); | ||||||
|         wcnt:               unsigned(31 downto 0); |  | ||||||
|     end record; |     end record; | ||||||
| 
 | 
 | ||||||
|     -- Trigger registers: write-only access by processor, single-cycle pulse signals to FPGA. |     -- Trigger registers: write-only access by processor, single-cycle pulse signals to FPGA. | ||||||
|     type registers_trigger is record |     type registers_trigger is record | ||||||
|         dma_clear:          std_logic; |         dma_clear:          std_logic; | ||||||
|         start:              std_logic; |         acq_channel_init:   std_logic; | ||||||
|  |         acq_intr_clear:     std_logic; | ||||||
|     end record; |     end record; | ||||||
| 
 | 
 | ||||||
|     constant registers_control_init: registers_control := ( |     constant registers_control_init: registers_control := ( | ||||||
|         irq_enable      => '0', |         irq_enable      => '0', | ||||||
|         test_irq        => (others => '0'), |  | ||||||
|         test_led        => (others => '0'), |         test_led        => (others => '0'), | ||||||
|         dma_en          => '0', |         dma_en          => '0', | ||||||
|  |         acq_addr_start  => (others => '0'), | ||||||
|  |         acq_addr_end    => (others => '0'), | ||||||
|  |         acq_addr_limit  => (others => '0'), | ||||||
|  |         acq_addr_intr   => (others => '0'), | ||||||
|  |         acq_channel_en  => '0', | ||||||
|  |         acq_intr_en     => '0', | ||||||
|         dma_buf_addr    => (others => '0'), |         dma_buf_addr    => (others => '0'), | ||||||
|         dma_buf_size    => (others => '0') |         dma_buf_size    => (others => '0') | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     constant registers_trigger_init: registers_trigger := ( |     constant registers_trigger_init: registers_trigger := ( | ||||||
|         dma_clear       => '0', |         dma_clear       => '0', | ||||||
|         start           => '0' |         acq_channel_init => '0', | ||||||
|  |         acq_intr_clear  => '0' | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
| end package; | end package; | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
| 
 | 
 | ||||||
| library ieee; | library ieee; | ||||||
| use ieee.std_logic_1164.all; | use ieee.std_logic_1164.all; | ||||||
|  | use ieee.std_logic_misc.all; | ||||||
| use ieee.numeric_std.all; | use ieee.numeric_std.all; | ||||||
| 
 | 
 | ||||||
| library unisim; | library unisim; | ||||||
|  | @ -127,23 +128,24 @@ architecture arch of puzzlefw_top is | ||||||
|     signal s_axi_rvalid:    std_logic; |     signal s_axi_rvalid:    std_logic; | ||||||
|     signal s_axi_rready:    std_logic; |     signal s_axi_rready:    std_logic; | ||||||
| 
 | 
 | ||||||
|     signal s_irq:           std_logic_vector(7 downto 0); |     signal s_dma_interrupt: std_logic; | ||||||
|  |     signal s_irq_pending:   std_logic_vector(0 downto 0); | ||||||
|  |     signal s_irq_f2p:       std_logic_vector(7 downto 0); | ||||||
| 
 | 
 | ||||||
|     signal s_reg_control:   registers_control; |     signal s_reg_control:   registers_control; | ||||||
|     signal s_reg_status:    registers_status; |     signal s_reg_status:    registers_status; | ||||||
|     signal s_reg_trigger:   registers_trigger; |     signal s_reg_trigger:   registers_trigger; | ||||||
| 
 | 
 | ||||||
|     signal s_dma_read_cmd_addr:   dma_address_type; |     signal s_dma_write_cmd_addr:  dma_address_array(0 downto 0); | ||||||
|     signal s_dma_read_cmd_valid:  std_logic; |     signal s_dma_write_cmd_valid: std_logic_vector(0 downto 0); | ||||||
|     signal s_dma_read_cmd_ready:  std_logic; |     signal s_dma_write_cmd_ready: std_logic_vector(0 downto 0); | ||||||
|     signal s_dma_read_data:       dma_data_type; |     signal s_dma_write_data:      dma_data_array(0 downto 0); | ||||||
|     signal s_dma_read_data_valid: std_logic; |     signal s_dma_write_data_ready: std_logic_vector(0 downto 0); | ||||||
|     signal s_dma_write_cmd_addr:  dma_address_type; |     signal s_dma_write_finished:  std_logic_vector(0 downto 0); | ||||||
|     signal s_dma_write_cmd_valid: std_logic; | 
 | ||||||
|     signal s_dma_write_cmd_ready: std_logic; |     signal s_dma_in_valid:  std_logic; | ||||||
|     signal s_dma_write_data:      dma_data_type; |     signal s_dma_in_ready:  std_logic; | ||||||
|     signal s_dma_write_data_ready: std_logic; |     signal s_dma_in_data:   std_logic_vector(63 downto 0); | ||||||
|     signal s_dma_write_finished:  std_logic; |  | ||||||
| 
 | 
 | ||||||
|     signal r_test_prefetch: std_logic; |     signal r_test_prefetch: std_logic; | ||||||
|     signal r_test_raddr:    std_logic_vector(9 downto 0); |     signal r_test_raddr:    std_logic_vector(9 downto 0); | ||||||
|  | @ -153,8 +155,6 @@ architecture arch of puzzlefw_top is | ||||||
| 
 | 
 | ||||||
| begin | begin | ||||||
| 
 | 
 | ||||||
|     s_irq(7 downto 1) <= s_reg_control.test_irq(7 downto 1); |  | ||||||
|     s_irq(0) <= s_reg_control.test_irq(0) and s_reg_control.irq_enable; |  | ||||||
|     led_o(7 downto 2) <= s_reg_control.test_led(7 downto 2); |     led_o(7 downto 2) <= s_reg_control.test_led(7 downto 2); | ||||||
| 
 | 
 | ||||||
|     -- Differential clock input for ADC clock. |     -- Differential clock input for ADC clock. | ||||||
|  | @ -219,7 +219,7 @@ begin | ||||||
|             APB_M_0_pslverr(0)  => s_apb_pslverr, |             APB_M_0_pslverr(0)  => s_apb_pslverr, | ||||||
|             APB_M_0_pwdata      => s_apb_pwdata, |             APB_M_0_pwdata      => s_apb_pwdata, | ||||||
|             APB_M_0_pwrite      => s_apb_pwrite, |             APB_M_0_pwrite      => s_apb_pwrite, | ||||||
|             IRQ_F2P             => s_irq, |             IRQ_F2P             => s_irq_f2p, | ||||||
|             S_AXI_HP0_0_araddr  => s_axi_araddr, |             S_AXI_HP0_0_araddr  => s_axi_araddr, | ||||||
|             S_AXI_HP0_0_arburst => s_axi_arburst, |             S_AXI_HP0_0_arburst => s_axi_arburst, | ||||||
|             S_AXI_HP0_0_arcache => s_axi_arcache, |             S_AXI_HP0_0_arcache => s_axi_arcache, | ||||||
|  | @ -282,7 +282,7 @@ begin | ||||||
|     inst_axi_master: entity work.dma_axi_master |     inst_axi_master: entity work.dma_axi_master | ||||||
|         generic map ( |         generic map ( | ||||||
|             transfer_size       => 16, |             transfer_size       => 16, | ||||||
|             num_read_channels   => 1, |             num_read_channels   => 0, | ||||||
|             num_write_channels  => 1 ) |             num_write_channels  => 1 ) | ||||||
|         port map ( |         port map ( | ||||||
|             clk                 => clk_adc, |             clk                 => clk_adc, | ||||||
|  | @ -296,17 +296,17 @@ begin | ||||||
|             err_address         => s_reg_status.dma_err_address, |             err_address         => s_reg_status.dma_err_address, | ||||||
|             err_any             => s_reg_status.dma_err_any, |             err_any             => s_reg_status.dma_err_any, | ||||||
|             clear_errors        => s_reg_trigger.dma_clear, |             clear_errors        => s_reg_trigger.dma_clear, | ||||||
|             read_cmd_addr(0)    => s_dma_read_cmd_addr, |             read_cmd_addr       => (others => (others => '0')), | ||||||
|             read_cmd_valid(0)   => s_dma_read_cmd_valid, |             read_cmd_valid      => (others => '0'), | ||||||
|             read_cmd_ready(0)   => s_dma_read_cmd_ready, |             read_cmd_ready      => open, | ||||||
|             read_data(0)        => s_dma_read_data, |             read_data           => open, | ||||||
|             read_data_valid(0)  => s_dma_read_data_valid, |             read_data_valid     => open, | ||||||
|             write_cmd_addr(0)   => s_dma_write_cmd_addr, |             write_cmd_addr      => s_dma_write_cmd_addr, | ||||||
|             write_cmd_valid(0)  => s_dma_write_cmd_valid, |             write_cmd_valid     => s_dma_write_cmd_valid, | ||||||
|             write_cmd_ready(0)  => s_dma_write_cmd_ready, |             write_cmd_ready     => s_dma_write_cmd_ready, | ||||||
|             write_data(0)       => s_dma_write_data, |             write_data          => s_dma_write_data, | ||||||
|             write_data_ready(0) => s_dma_write_data_ready, |             write_data_ready    => s_dma_write_data_ready, | ||||||
|             write_finished(0)   => s_dma_write_finished, |             write_finished      => s_dma_write_finished, | ||||||
|             m_axi_awid          => s_axi_awid, |             m_axi_awid          => s_axi_awid, | ||||||
|             m_axi_awaddr        => s_axi_awaddr, |             m_axi_awaddr        => s_axi_awaddr, | ||||||
|             m_axi_awlen         => s_axi_awlen, |             m_axi_awlen         => s_axi_awlen, | ||||||
|  | @ -347,76 +347,47 @@ begin | ||||||
|             m_axi_rready        => s_axi_rready |             m_axi_rready        => s_axi_rready | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
| -- little test machine for DMA |     -- DMA Write Channel | ||||||
|     inst_mem: xpm_memory_sdpram |     inst_write_channel: entity work.dma_write_channel | ||||||
|         generic map ( |         generic map ( | ||||||
|             CLOCKING_MODE       => "common_clock", |             queue_size_bits     => 10 ) | ||||||
|             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 ( |         port map ( | ||||||
|             clka                => clk_adc, |             clk                 => clk_adc, | ||||||
|             clkb                => clk_adc, |             reset               => s_reset, | ||||||
|             rstb                => s_reset, |             channel_en          => s_reg_control.acq_channel_en, | ||||||
|             addra               => r_test_waddr, |             channel_init        => s_reg_trigger.acq_channel_init, | ||||||
|             addrb               => r_test_raddr, |             addr_start          => s_reg_control.acq_addr_start, | ||||||
|             dina                => s_dma_read_data, |             addr_end            => s_reg_control.acq_addr_end, | ||||||
|             doutb               => s_test_dout, |             addr_limit          => s_reg_control.acq_addr_limit, | ||||||
|             ena                 => s_dma_read_data_valid, |             addr_interrupt      => s_reg_control.acq_addr_intr, | ||||||
|             enb                 => s_test_ren, |             addr_pointer        => s_reg_status.acq_addr_ptr, | ||||||
|             wea                 => "1", |             intr_en             => s_reg_control.acq_intr_en, | ||||||
|             regceb              => '1', |             intr_clear          => s_reg_trigger.acq_intr_clear, | ||||||
|             injectdbiterra      => '0', |             intr_out            => s_dma_interrupt, | ||||||
|             injectsbiterra      => '0', |             in_valid            => s_dma_in_valid, | ||||||
|             sleep               => '0' ); |             in_ready            => s_dma_in_ready, | ||||||
|  |             in_data             => s_dma_in_data, | ||||||
|  |             write_cmd_addr      => s_dma_write_cmd_addr(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) ); | ||||||
| 
 | 
 | ||||||
|     s_dma_write_data <= not s_test_dout; |     -- Collect interrupt signals from peripherals and generate interrupt to PS. | ||||||
|     s_test_ren <= r_test_prefetch or s_dma_write_data_ready; |     s_irq_pending(0) <= s_dma_interrupt; | ||||||
|  |     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'); | ||||||
| 
 | 
 | ||||||
|  | -- little test machine for DMA | ||||||
|     process (clk_adc) is |     process (clk_adc) is | ||||||
|     begin |     begin | ||||||
|         if rising_edge(clk_adc) then |         if rising_edge(clk_adc) then | ||||||
|             r_test_prefetch <= '0'; |             s_dma_in_valid <= '1'; | ||||||
|             if s_dma_read_cmd_ready = '1' and s_dma_read_cmd_valid = '1' then |             if s_dma_in_ready = '1' then | ||||||
|                 if unsigned(s_dma_read_cmd_addr) < 1008 then |                 s_dma_in_data(15 downto 0) <= std_logic_vector(unsigned(s_dma_in_data(15 downto 0)) + 1); | ||||||
|                     s_dma_read_cmd_addr <= std_logic_vector(unsigned(s_dma_read_cmd_addr) + 16); |                 s_dma_in_data(63 downto 16) <= std_logic_vector(unsigned(s_dma_in_data(63 downto 16)) - 1); | ||||||
|                 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 if; |         end if; | ||||||
|     end process; |     end process; | ||||||
|  |  | ||||||
|  | @ -90,6 +90,7 @@ begin | ||||||
|             case to_integer(unsigned(apb_paddr and reg_addr_mask)) is |             case to_integer(unsigned(apb_paddr and reg_addr_mask)) is | ||||||
|                 when reg_info =>            v.prdata := fw_info_word; |                 when reg_info =>            v.prdata := fw_info_word; | ||||||
|                 when reg_irq_enable =>      v.prdata(0) := r.reg_control.irq_enable; |                 when reg_irq_enable =>      v.prdata(0) := r.reg_control.irq_enable; | ||||||
|  |                 when reg_irq_pending =>     v.prdata(0 downto 0) := reg_status.irq_pending; | ||||||
|                 when reg_dma_en =>          v.prdata(0) := r.reg_control.dma_en; |                 when reg_dma_en =>          v.prdata(0) := r.reg_control.dma_en; | ||||||
|                 when reg_dma_status  => |                 when reg_dma_status  => | ||||||
|                     v.prdata(0) := reg_status.dma_busy; |                     v.prdata(0) := reg_status.dma_busy; | ||||||
|  | @ -97,12 +98,16 @@ begin | ||||||
|                     v.prdata(2) := reg_status.dma_err_write; |                     v.prdata(2) := reg_status.dma_err_write; | ||||||
|                     v.prdata(3) := reg_status.dma_err_address; |                     v.prdata(3) := reg_status.dma_err_address; | ||||||
|                     v.prdata(4) := reg_status.dma_err_any; |                     v.prdata(4) := reg_status.dma_err_any; | ||||||
|                 when reg_rcnt =>            v.prdata := std_logic_vector(reg_status.rcnt); |                 when reg_acq_addr_start =>  v.prdata(31 downto 7) := r.reg_control.acq_addr_start; | ||||||
|                 when reg_wcnt =>            v.prdata := std_logic_vector(reg_status.wcnt); |                 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 7) := r.reg_control.acq_addr_intr; | ||||||
|  |                 when reg_acq_addr_ptr =>    v.prdata(31 downto 7) := reg_status.acq_addr_ptr; | ||||||
|  |                 when reg_acq_channel_ctrl => v.prdata(0) := r.reg_control.acq_channel_en; | ||||||
|  |                 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; | ||||||
|                 when reg_dma_buf_addr =>    v.prdata(31 downto 12) := r.reg_control.dma_buf_addr; |                 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 reg_dma_buf_size =>    v.prdata(31 downto 12) := r.reg_control.dma_buf_size; | ||||||
|                 when reg_test_irq =>        v.prdata(7 downto 0) := r.reg_control.test_irq; |  | ||||||
|                 when reg_test_led =>        v.prdata(7 downto 0) := r.reg_control.test_led; |  | ||||||
|                 when others =>              null; |                 when others =>              null; | ||||||
|             end case; |             end case; | ||||||
| 
 | 
 | ||||||
|  | @ -114,15 +119,23 @@ begin | ||||||
|                 when reg_irq_enable =>      v.reg_control.irq_enable := apb_pwdata(0); |                 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_en =>          v.reg_control.dma_en := apb_pwdata(0); | ||||||
|                 when reg_dma_clear =>       v.reg_trigger.dma_clear := apb_pwdata(0); |                 when reg_dma_clear =>       v.reg_trigger.dma_clear := apb_pwdata(0); | ||||||
|                 when reg_start =>           v.reg_trigger.start := 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 7); | ||||||
|  |                 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); | ||||||
|                 when reg_dma_buf_addr =>    v.reg_control.dma_buf_addr := apb_pwdata(31 downto 12); |                 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 reg_dma_buf_size =>    v.reg_control.dma_buf_size := apb_pwdata(31 downto 12); | ||||||
|                 when reg_test_irq =>        v.reg_control.test_irq := apb_pwdata(7 downto 0); |  | ||||||
|                 when reg_test_led =>        v.reg_control.test_led := apb_pwdata(7 downto 0); |  | ||||||
|                 when others =>              null; |                 when others =>              null; | ||||||
|             end case; |             end case; | ||||||
|         end if; |         end if; | ||||||
|          | 
 | ||||||
|         -- Synchronous reset. |         -- Synchronous reset. | ||||||
|         if reset = '1' then |         if reset = '1' then | ||||||
|             v := regs_init; |             v := regs_init; | ||||||
|  |  | ||||||
|  | @ -0,0 +1,208 @@ | ||||||
|  | -- | ||||||
|  | --  Simple FIFO with single clock. | ||||||
|  | -- | ||||||
|  | --  Joris van Rantwijk 2024 | ||||||
|  | -- | ||||||
|  | 
 | ||||||
|  | library ieee; | ||||||
|  | use ieee.std_logic_1164.all; | ||||||
|  | use ieee.numeric_std.all; | ||||||
|  | 
 | ||||||
|  | library xpm; | ||||||
|  | use xpm.vcomponents.all; | ||||||
|  | 
 | ||||||
|  | use work.puzzlefw_pkg.all; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | entity simple_fifo is | ||||||
|  | 
 | ||||||
|  |     generic ( | ||||||
|  |         -- Word width. | ||||||
|  |         data_width:         integer range 1 to 1024; | ||||||
|  | 
 | ||||||
|  |         -- Size of FIFO as 2-log of the number of words. | ||||||
|  |         fifo_depth_bits:    integer range 2 to 16 | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     port ( | ||||||
|  |         -- Main clock, active on rising edge. | ||||||
|  |         clk:                in  std_logic; | ||||||
|  | 
 | ||||||
|  |         -- Reset, active high, synchronous to main clock. | ||||||
|  |         -- After reset, the FIFO is empty. | ||||||
|  |         reset:              in  std_logic; | ||||||
|  | 
 | ||||||
|  |         -- Data input stream. | ||||||
|  |         in_valid:           in  std_logic; | ||||||
|  |         in_ready:           out std_logic; | ||||||
|  |         in_data:            in  std_logic_vector(data_width - 1 downto 0); | ||||||
|  | 
 | ||||||
|  |         -- Data output stream. | ||||||
|  |         out_valid:          out std_logic; | ||||||
|  |         out_ready:          in  std_logic; | ||||||
|  |         out_data:           out std_logic_vector(data_width - 1 downto 0); | ||||||
|  | 
 | ||||||
|  |         -- Number of words currently in the FIFO. | ||||||
|  |         -- This excludes the word currently expressed on "out_ready" when "out_valid" is high. | ||||||
|  |         queue_length:       out unsigned(fifo_depth_bits - 1 downto 0) | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  | end entity; | ||||||
|  | 
 | ||||||
|  | architecture arch of simple_fifo is | ||||||
|  | 
 | ||||||
|  |     type regs_type is record | ||||||
|  |         in_ready:       std_logic; | ||||||
|  |         out_valid:      std_logic; | ||||||
|  |         nonempty:       std_logic; | ||||||
|  |         waddr:          unsigned(fifo_depth_bits - 1 downto 0); | ||||||
|  |         raddr:          unsigned(fifo_depth_bits - 1 downto 0); | ||||||
|  |         qlen:           unsigned(fifo_depth_bits - 1 downto 0); | ||||||
|  |     end record; | ||||||
|  | 
 | ||||||
|  |     constant regs_init: regs_type := ( | ||||||
|  |         in_ready        => '0', | ||||||
|  |         out_valid       => '0', | ||||||
|  |         nonempty        => '0', | ||||||
|  |         waddr           => (others => '0'), | ||||||
|  |         raddr           => (others => '0'), | ||||||
|  |         qlen            => (others => '0') | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     signal r: regs_type := regs_init; | ||||||
|  |     signal rnext: regs_type; | ||||||
|  | 
 | ||||||
|  |     signal s_ram_wen:   std_logic; | ||||||
|  |     signal s_ram_ren:   std_logic; | ||||||
|  | 
 | ||||||
|  | begin | ||||||
|  | 
 | ||||||
|  |     -- | ||||||
|  |     -- Xilinx Simple Dual Port RAM. | ||||||
|  |     -- | ||||||
|  |     ram_inst: xpm_memory_sdpram | ||||||
|  |         generic map ( | ||||||
|  |             ADDR_WIDTH_A        => fifo_depth_bits, | ||||||
|  |             ADDR_WIDTH_B        => fifo_depth_bits, | ||||||
|  |             AUTO_SLEEP_TIME     => 0, | ||||||
|  |             BYTE_WRITE_WIDTH_A  => data_width, | ||||||
|  |             CASCADE_HEIGHT      => 0, | ||||||
|  |             CLOCKING_MODE       => "common_clock", | ||||||
|  |             ECC_MODE            => "no_ecc", | ||||||
|  |             MEMORY_INIT_FILE    => "none", | ||||||
|  |             MEMORY_INIT_PARAM   => "0", | ||||||
|  |             MEMORY_OPTIMIZATION => "true", | ||||||
|  |             MEMORY_PRIMITIVE    => "block", | ||||||
|  |             MEMORY_SIZE         => data_width * 2**fifo_depth_bits, | ||||||
|  |             MESSAGE_CONTROL     => 0, | ||||||
|  |             READ_DATA_WIDTH_B   => data_width, | ||||||
|  |             READ_LATENCY_B      => 1, | ||||||
|  |             READ_RESET_VALUE_B  => "0", | ||||||
|  |             RST_MODE_A          => "SYNC", | ||||||
|  |             RST_MODE_B          => "SYNC", | ||||||
|  |             SIM_ASSERT_CHK      => 0, | ||||||
|  |             USE_EMBEDDED_CONSTRAINT => 0, | ||||||
|  |             USE_MEM_INIT        => 0, | ||||||
|  |             WAKEUP_TIME         => "disable_sleep", | ||||||
|  |             WRITE_DATA_WIDTH_A  => data_width, | ||||||
|  |             WRITE_MODE_B        => "no_change" ) | ||||||
|  |         port map ( | ||||||
|  |             addra               => std_logic_vector(r.waddr), | ||||||
|  |             addrb               => std_logic_vector(r.raddr), | ||||||
|  |             clka                => clk, | ||||||
|  |             clkb                => clk, | ||||||
|  |             dbiterrb            => open, | ||||||
|  |             dina                => in_data, | ||||||
|  |             doutb               => out_data, | ||||||
|  |             ena                 => s_ram_wen, | ||||||
|  |             enb                 => s_ram_ren, | ||||||
|  |             injectdbiterra      => '0', | ||||||
|  |             injectsbiterra      => '0', | ||||||
|  |             regceb              => '1', | ||||||
|  |             rstb                => reset, | ||||||
|  |             sbiterrb            => open, | ||||||
|  |             sleep               => '0', | ||||||
|  |             wea                 => "1" ); | ||||||
|  | 
 | ||||||
|  |     -- | ||||||
|  |     -- Drive output ports. | ||||||
|  |     -- | ||||||
|  |     in_ready    <= r.in_ready; | ||||||
|  |     out_valid   <= r.out_valid; | ||||||
|  |     queue_length <= r.qlen; | ||||||
|  | 
 | ||||||
|  |     -- | ||||||
|  |     -- Drive control signals to RAM. | ||||||
|  |     -- | ||||||
|  |     s_ram_wen   <= in_valid and r.in_ready; | ||||||
|  |     s_ram_ren   <= r.nonempty and (out_ready or (not r.out_valid)); | ||||||
|  | 
 | ||||||
|  |     -- | ||||||
|  |     -- Combinatorial process. | ||||||
|  |     -- | ||||||
|  |     process (all) is | ||||||
|  |         variable v: regs_type; | ||||||
|  |     begin | ||||||
|  |         -- Load current register values. | ||||||
|  |         v := r; | ||||||
|  | 
 | ||||||
|  |         -- Update write pointer on write. | ||||||
|  |         if (in_valid = '1') and (r.in_ready = '1') then | ||||||
|  |             v.waddr := r.waddr + 1; | ||||||
|  |         end if; | ||||||
|  | 
 | ||||||
|  |         -- Update input ready status. | ||||||
|  |         -- Note this uses the NEW value of the write pointer. | ||||||
|  |         if v.waddr + 1 = r.raddr then | ||||||
|  |             v.in_ready := '0'; | ||||||
|  |         else | ||||||
|  |             v.in_ready := '1'; | ||||||
|  |         end if; | ||||||
|  | 
 | ||||||
|  |         -- On read from RAM, update read pointer. | ||||||
|  |         if (r.nonempty = '1') and (out_ready = '1' or r.out_valid = '0') then | ||||||
|  |             v.raddr := r.raddr + 1; | ||||||
|  |         end if; | ||||||
|  | 
 | ||||||
|  |         -- Determine whether output word is valid in the next cycle. | ||||||
|  |         if r.nonempty = '1' then | ||||||
|  |             -- Keep output word or load a new word during this cycle. | ||||||
|  |             v.out_valid := '1'; | ||||||
|  |         elsif out_ready = '1' then | ||||||
|  |             -- Consume output word without refreshing it. | ||||||
|  |             v.out_valid := '0'; | ||||||
|  |         end if; | ||||||
|  | 
 | ||||||
|  |         -- Determine whether RAM will contain data on the next cycle. | ||||||
|  |         -- Note this uses the NEW values of the read and write pointers. | ||||||
|  |         if v.waddr = v.raddr then | ||||||
|  |             v.nonempty := '0'; | ||||||
|  |         else | ||||||
|  |             v.nonempty := '1'; | ||||||
|  |         end if; | ||||||
|  | 
 | ||||||
|  |         -- Calculate queue length. | ||||||
|  |         -- Note this uses the NEW values of "waddr" and "raddr". | ||||||
|  |         v.qlen := v.waddr - v.raddr; | ||||||
|  | 
 | ||||||
|  |         -- 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; | ||||||
|  | @ -19,7 +19,9 @@ set_property target_language VHDL [current_project] | ||||||
| 
 | 
 | ||||||
| # Load VHDL files. | # Load VHDL files. | ||||||
| read_vhdl -vhdl2008 ../rtl/puzzlefw_pkg.vhd | read_vhdl -vhdl2008 ../rtl/puzzlefw_pkg.vhd | ||||||
|  | read_vhdl -vhdl2008 ../rtl/simple_fifo.vhd | ||||||
| read_vhdl -vhdl2008 ../rtl/dma_axi_master.vhd | read_vhdl -vhdl2008 ../rtl/dma_axi_master.vhd | ||||||
|  | read_vhdl -vhdl2008 ../rtl/dma_write_channel.vhd | ||||||
| read_vhdl -vhdl2008 ../rtl/registers.vhd | read_vhdl -vhdl2008 ../rtl/registers.vhd | ||||||
| read_vhdl -vhdl2008 ../rtl/puzzlefw_top.vhd | read_vhdl -vhdl2008 ../rtl/puzzlefw_top.vhd | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue