Select Git revision
generateStationStreams.sh
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
reorder_sequencer.vhd 11.75 KiB
-------------------------------------------------------------------------------
--
-- Copyright (C) 2011
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Purpose: Providing address and control signals for external memory realizing a
-- reordering of the data. Based on alternating read and writes.
--
--
-- Description: The values of generic g_reorder_seq determine the rhythm of the
-- sequencer. The sequencer is based on the use of a dualpage memory.
-- While data is written in page 0, page 1 is read. The state machine
-- alternated between reads and writes: read periods and write periods.
-- The number of accesses in a read and wrte period is determined by the
-- values of the generic.
-- The generics are interpreted as addresses in the sosi clock-domain. If the
-- datarate and/or the datawidth of the memory interface is higher than the
-- sosi domain than the g_data_w_ratio generic can be used to specify the
-- that ratio. An example:
--
-- SOSI DOMAIN MEMORY DOMAIN (DDR3)
-- Datawidth 64 bits 256 bits
-- Clockrate 200 MHz 200 MHz
--
-- The g_data_w_ratio should be 4 to facilitate this transition
-- The meaning of the other generics is explained her:
--
-- - wr_chunksize is the number of samples that are written during a write access.
-- A write access always consists of 1 access.
-- - rd_chunksize is the number of samples that are read during a read access.
-- - rd_nof_chunks is the number of read accesses performed during a read period
-- - rd_interval defines the number of blocks in between two consecutive reads.
-- - gapsize is the address space to be skipped in between two consecutive write or
-- read periods. Gapsize can be used to create byte-alignment in the memory.
-- - nof_blocks determines the number of write and read periods before the page
-- swap takes place.
--
-- The example shows the following configuration:
--
-- wr_chunksize : POSITIVE := 8
-- rd_chunksize : POSITIVE := 4;
-- rd_nof_chunks : POSITIVE := 2;
-- rd_interval : POSITIVE := 2;
-- gapsize : NATURAL := 0;
-- nof_blocks : POSITIVE := 5;
-- WR RD
-- -------- --------
-- |0 | |0,0 | rd_chunksize
-- wr_chunksize | | --------
-- | | |2,1 |
-- -------- --------
-- gapsize | | | |
-- -------- --------
-- |1 | |1,1 |
-- | | --------
-- | | |4,0 |
-- -------- --------
-- | | | |
-- -------- --------
-- |2 | |0,1 |
-- | | --------
-- | | |3,0 |
-- -------- --------
-- | | | |
-- -------- --------
-- |3 | |2,0 |
-- | | --------
-- | | |4,1 |
-- -------- --------
-- | | | |
-- -------- --------
-- |4 | |1,0 |
-- | | --------
-- | | |3,1 |
-- -------- --------
-- | | | |
-- -------- --------
-- page 0 page 1
--
-- The index in the write page indicate the write period(0-4)
-- The first index in the read page indicates the read period(0-4)
-- The second index in the read page indicates the chunknumber(0-1)
-- One can see the influence of rd_interval = 2in the fact there is a gap
-- of 2 blocks in between two consecutive chunks that ar read. The first
-- chunck (0,0) is read from the block 0. The second chunk (0,1) is read
-- from block 2. The third chunk (1,0) is read from block 4.
--
-- Remarks: If the g_data_w_ratio is used, be sure that the generics wr_chunksize,
-- rd_chunksize, rd_nof_chunks and gapsize are divisible by g_data_w_ratio.
LIBRARY IEEE, common_lib;
USE IEEE.STD_LOGIC_1164.ALL;
USE common_lib.common_pkg.ALL;
USE common_lib.common_mem_pkg.ALL;
USE work.reorder_pkg.ALL;
ENTITY reorder_sequencer IS
GENERIC (
g_reorder_seq : t_reorder_seq := c_reorder_seq;
g_data_w_ratio : POSITIVE := 1 -- (256/256) Ratio between datawidth of the memory controller and SOSI domain
); -- Used to determine the width of counters.
PORT (
-- Clocks and reset
dp_rst : IN STD_LOGIC; -- reset synchronous with st_clk
dp_clk : IN STD_LOGIC; -- other clock domain clock
en_evt : OUT STD_LOGIC;
wr_not_rd : OUT STD_LOGIC;
address : OUT STD_LOGIC_VECTOR;
burstsize : OUT STD_LOGIC_VECTOR;
done : IN STD_LOGIC
);
END reorder_sequencer;
ARCHITECTURE rtl OF reorder_sequencer IS
-- Rescale to memory addressing
CONSTANT c_wr_chunksize : POSITIVE := g_reorder_seq.wr_chunksize/g_data_w_ratio;
CONSTANT c_rd_chunksize : POSITIVE := g_reorder_seq.rd_chunksize/g_data_w_ratio;
CONSTANT c_gapsize : NATURAL := g_reorder_seq.gapsize/g_data_w_ratio;
CONSTANT c_blocksize : POSITIVE := c_wr_chunksize + c_gapsize;
CONSTANT c_page_size : POSITIVE := c_blocksize * g_reorder_seq.nof_blocks;
CONSTANT c_mem_size : POSITIVE := 2*c_page_size;
CONSTANT c_rd_block_increment : POSITIVE := c_blocksize * g_reorder_seq.rd_interval;
TYPE state_type is (s_idle, s_write, s_first_write, s_wait_wr, s_read, s_wait_rd);
TYPE reg_type IS RECORD
rd_page_offset : NATURAL;
wr_page_offset : NATURAL;
ddr3_en : STD_LOGIC;
wr_not_rd : STD_LOGIC;
rd_block_offset : NATURAL;
rd_chunks_offset : NATURAL;
wr_block_offset : NATURAL;
switch_cnt : NATURAL RANGE 0 TO g_reorder_seq.rd_nof_chunks; -- Counter that counts the write and read accesses to determine the switch between read and write phase.
page_cnt : NATURAL RANGE 0 TO g_reorder_seq.nof_blocks; -- Counter that counts the number of write accesses to determine the page-swap.
first_write : STD_LOGIC;
start_addr : NATURAL RANGE 0 TO c_mem_size-1;
burstsize : NATURAL RANGE 0 TO sel_a_b(c_wr_chunksize > c_rd_chunksize, c_wr_chunksize, c_rd_chunksize);
state : state_type; -- The state machine.
END RECORD;
SIGNAL r, rin : reg_type;
BEGIN
---------------------------------------------------------------
-- CHECK IF PROVIDED GENERICS ARE ALLOWED.
---------------------------------------------------------------
ASSERT NOT(g_reorder_seq.wr_chunksize /= (g_reorder_seq.rd_nof_chunks*g_reorder_seq.rd_chunksize) AND rising_edge(dp_clk)) REPORT "Total write configuration is different from total read configuration!!!" SEVERITY FAILURE;
p_comb : PROCESS(r, dp_rst, done)
VARIABLE v : reg_type;
BEGIN
v := r;
v.ddr3_en := '0';
CASE r.state IS
WHEN s_idle =>
IF(done = '1') THEN
v.first_write := '1';
v.state := s_first_write;
END IF;
WHEN s_first_write =>
v.wr_not_rd := '1';
v.ddr3_en := '1';
v.start_addr := r.wr_page_offset + r.wr_block_offset;
v.burstsize := c_wr_chunksize;
v.state := s_wait_wr;
WHEN s_write =>
IF(done = '1') THEN
v.wr_not_rd := '1';
v.ddr3_en := '1';
v.start_addr := r.wr_page_offset + r.wr_block_offset;
v.burstsize := c_wr_chunksize;
v.state := s_wait_wr;
END IF;
WHEN s_wait_wr =>
v.wr_block_offset := r.wr_block_offset + c_blocksize;
v.page_cnt := r.page_cnt + 1;
v.switch_cnt := 0;
v.state := s_read;
WHEN s_read =>
IF(done = '1') THEN
v.wr_not_rd := '0';
IF( r.first_write = '0') THEN
v.ddr3_en := '1';
END IF;
v.start_addr := r.rd_page_offset + r.rd_block_offset + r.rd_chunks_offset;
v.burstsize := c_rd_chunksize;
v.switch_cnt := r.switch_cnt + 1;
v.state := s_wait_rd;
END IF;
WHEN s_wait_rd =>
v.rd_block_offset := r.rd_block_offset + c_rd_block_increment;
IF(r.rd_block_offset + c_rd_block_increment >= c_page_size) THEN
v.rd_chunks_offset := r.rd_chunks_offset + c_rd_chunksize;
v.rd_block_offset := r.rd_block_offset + c_rd_block_increment - c_page_size;
END IF;
IF(r.switch_cnt = g_reorder_seq.rd_nof_chunks) THEN
v.switch_cnt := 0;
v.state := s_write;
IF(r.page_cnt = g_reorder_seq.nof_blocks) THEN
v.rd_page_offset := r.wr_page_offset;
v.wr_page_offset := r.rd_page_offset;
v.page_cnt := 0;
v.first_write := '0';
v.rd_block_offset := 0;
v.rd_chunks_offset := 0;
v.wr_block_offset := 0;
END IF;
ELSE
v.state := s_read;
END IF;
WHEN OTHERS =>
v.state := s_idle;
END CASE;
IF(dp_rst = '1') THEN
v.rd_page_offset := c_page_size;
v.wr_page_offset := 0;
v.page_cnt := 0;
v.switch_cnt := 0;
v.ddr3_en := '0';
v.wr_not_rd := '0';
v.wr_block_offset := 0;
v.rd_block_offset := 0;
v.rd_chunks_offset := 0;
v.start_addr := 0;
v.burstsize := 0;
v.first_write := '1';
v.state := s_idle;
END IF;
rin <= v;
END PROCESS;
p_regs : PROCESS(dp_clk)
BEGIN
IF RISING_EDGE(dp_clk) THEN
r <= rin;
END IF;
END PROCESS;
en_evt <= r.ddr3_en;
wr_not_rd <= r.wr_not_rd;
address <= TO_UVEC(r.start_addr, address'LENGTH);
burstsize <= TO_UVEC(r.burstsize, burstsize'LENGTH);
END rtl;