OpenCores
URL https://opencores.org/ocsvn/ccsds_rxtxsoc/ccsds_rxtxsoc/trunk

Subversion Repositories ccsds_rxtxsoc

[/] [ccsds_rxtxsoc/] [trunk/] [ccsds_tx_framer.vhd] - Rev 2

Compare with Previous | Blame | View Log

-------------------------------
---- Project: EurySPACE CCSDS RX/TX with wishbone interface
---- Design Name: ccsds_tx_framer
---- Version: 1.0.0
---- Description:
---- Implementation of standard CCSDS 132.0-B-2
-------------------------------
---- Author(s):
---- Guillaume REMBERT
-------------------------------
---- Licence:
---- MIT
-------------------------------
---- Changes list:
---- 2016/02/27: initial release
---- 2016/10/20: rework
---- 2016/10/24: multiple footers generation to ensure higher speed than input max data rate (CCSDS_TX_FRAMER_DATA_BUS_SIZE*CLK_FREQ bits/sec)
---- 2016/10/31: ressources optimization
---- 2016/11/03: add only idle data insertion
-------------------------------
--TODO: trailer as option
--HEADER (6 up to 70 bytes) / before data / f(idle)
--TRANSFER FRAME DATA FIELD => Variable
--TRAILER (2 up to 6 bytes) / after data / f(data, header)
 
-- libraries used
library ieee;
use ieee.std_logic_1164.all;
 
--=============================================================================
-- Entity declaration for ccsds_tx / unitary tx framer inputs and outputs
--=============================================================================
entity ccsds_tx_framer is
  generic(
    constant CCSDS_TX_FRAMER_DATA_BUS_SIZE: integer; -- in bits
    constant CCSDS_TX_FRAMER_DATA_LENGTH: integer; -- in Bytes
    constant CCSDS_TX_FRAMER_FOOTER_LENGTH: integer; -- in Bytes
    constant CCSDS_TX_FRAMER_HEADER_LENGTH: integer; -- in Bytes
    constant CCSDS_TX_FRAMER_PARALLELISM_MAX_RATIO: integer := 16 -- activated max framer parallelism speed ratio / 1 = full speed / 2 = wishbone bus non-pipelined write max speed / ... / CCSDS_TX_FRAMER_DATA_BUS_SIZE = external serial data
  );
  port(
    -- inputs
    clk_i: in std_logic;
    dat_i: in std_logic_vector(CCSDS_TX_FRAMER_DATA_BUS_SIZE-1 downto 0);
    dat_val_i: in std_logic;
    rst_i: in std_logic;
    -- outputs
    dat_o: out std_logic_vector((CCSDS_TX_FRAMER_HEADER_LENGTH+CCSDS_TX_FRAMER_FOOTER_LENGTH+CCSDS_TX_FRAMER_DATA_LENGTH)*8-1 downto 0);
    dat_nxt_o: out std_logic;
    dat_val_o: out std_logic;
    idl_o: out std_logic
  );
end ccsds_tx_framer;
 
--=============================================================================
-- architecture declaration / internal components and connections
--=============================================================================
architecture structure of ccsds_tx_framer is
  component ccsds_tx_header is
    generic(
      constant CCSDS_TX_HEADER_LENGTH: integer
    );
    port(
      clk_i: in std_logic;
      idl_i: in std_logic;
      nxt_i: in std_logic;
      rst_i: in std_logic;
      dat_o: out std_logic_vector(CCSDS_TX_HEADER_LENGTH*8-1 downto 0);
      dat_val_o: out std_logic
    );
  end component;
  component ccsds_tx_footer is
    generic(
      constant CCSDS_TX_FOOTER_DATA_LENGTH : integer;
      constant CCSDS_TX_FOOTER_LENGTH: integer
    );
    port(
      clk_i: in std_logic;
      rst_i: in std_logic;
      nxt_i: in std_logic;
      bus_o: out std_logic;
      dat_i: in std_logic_vector(CCSDS_TX_FOOTER_DATA_LENGTH*8-1 downto 0);
      dat_o: out std_logic_vector((CCSDS_TX_FOOTER_LENGTH+CCSDS_TX_FOOTER_DATA_LENGTH)*8-1 downto 0);
      dat_val_o: out std_logic
    );
  end component;
 
-- internal constants
  constant CCSDS_TX_FRAMER_FOOTER_NUMBER : integer := CCSDS_TX_FRAMER_DATA_BUS_SIZE*((CCSDS_TX_FRAMER_HEADER_LENGTH+CCSDS_TX_FRAMER_DATA_LENGTH+CCSDS_TX_FRAMER_FOOTER_LENGTH)*8+1)/(CCSDS_TX_FRAMER_DATA_LENGTH*8*CCSDS_TX_FRAMER_PARALLELISM_MAX_RATIO)+1; -- 8*(HEAD+DATA+FOOT+1) clks / crc ; BUS bits / parallelism * clk ; DATA*8 bits / footer
  constant CCSDS_TX_FRAMER_OID_PATTERN: std_logic_vector(CCSDS_TX_FRAMER_DATA_LENGTH*8-1 downto 0) := (others => '1'); -- Only Idle Data Pattern transmitted (jam payload for frame stuffing)
 
-- internal variable signals 
  type frame_array is array (CCSDS_TX_FRAMER_FOOTER_NUMBER-1 downto 0) of std_logic_vector((CCSDS_TX_FRAMER_FOOTER_LENGTH+CCSDS_TX_FRAMER_DATA_LENGTH+CCSDS_TX_FRAMER_HEADER_LENGTH)*8-1 downto 0);
  signal wire_header_data: std_logic_vector(CCSDS_TX_FRAMER_HEADER_LENGTH*8-1 downto 0);
  signal wire_footer_data_o: frame_array;
  signal wire_header_data_valid: std_logic;
  signal wire_footer_data_valid: std_logic_vector(CCSDS_TX_FRAMER_FOOTER_NUMBER-1 downto 0);
  signal wire_header_next: std_logic := '0';
  signal wire_header_idle: std_logic := '0';
  signal wire_footer_next: std_logic_vector(CCSDS_TX_FRAMER_FOOTER_NUMBER-1 downto 0) := (others => '0');
  signal wire_footer_busy: std_logic_vector(CCSDS_TX_FRAMER_FOOTER_NUMBER-1 downto 0);
 
  signal reg_next_frame: std_logic_vector(CCSDS_TX_FRAMER_DATA_LENGTH*8-CCSDS_TX_FRAMER_DATA_BUS_SIZE-1 downto 0);
  signal reg_current_frame: std_logic_vector((CCSDS_TX_FRAMER_DATA_LENGTH)*8-1 downto 0);
  signal reg_processing_frame: std_logic_vector((CCSDS_TX_FRAMER_DATA_LENGTH+CCSDS_TX_FRAMER_HEADER_LENGTH)*8-1 downto 0);
  signal next_processing_frame_pointer : integer range 0 to CCSDS_TX_FRAMER_FOOTER_NUMBER-1 := 0;
 
-- components instanciation and mapping
  begin
  tx_header_0: ccsds_tx_header
    generic map(
      CCSDS_TX_HEADER_LENGTH => CCSDS_TX_FRAMER_HEADER_LENGTH
    )
    port map(
      clk_i => clk_i,
      idl_i => wire_header_idle,
      nxt_i => wire_header_next,
      rst_i => rst_i,
      dat_o => wire_header_data,
      dat_val_o => wire_header_data_valid
    );
 
  FOOTERGEN:
    for i in 0 to CCSDS_TX_FRAMER_FOOTER_NUMBER-1 generate
      tx_footer_x : ccsds_tx_footer
      generic map(
        CCSDS_TX_FOOTER_DATA_LENGTH => CCSDS_TX_FRAMER_DATA_LENGTH+CCSDS_TX_FRAMER_HEADER_LENGTH,
        CCSDS_TX_FOOTER_LENGTH => CCSDS_TX_FRAMER_FOOTER_LENGTH
      )
      port map(
        clk_i => clk_i,
        rst_i => rst_i,
        nxt_i => wire_footer_next(i),
        bus_o => wire_footer_busy(i),
        dat_i => reg_processing_frame,
        dat_o => wire_footer_data_o(i),
        dat_val_o => wire_footer_data_valid(i)
      );
    end generate FOOTERGEN;
 
-- presynthesis checks
    CHKFRAMERP0 : if ((CCSDS_TX_FRAMER_DATA_LENGTH*8) mod CCSDS_TX_FRAMER_DATA_BUS_SIZE /= 0) generate
      process
      begin
        report "ERROR: FRAMER DATA LENGTH SHOULD BE A MULTIPLE OF FRAMER DATA BUS SIZE" severity failure;
        wait;
      end process;
    end generate CHKFRAMERP0;
    CHKFRAMERP1 : if ((CCSDS_TX_FRAMER_DATA_LENGTH) = 0) generate
      process
      begin
        report "ERROR: FRAMER DATA LENGTH CANNOT BE 0" severity failure;
        wait;
      end process;
    end generate CHKFRAMERP1;
    CHKFRAMERP2 : if ((CCSDS_TX_FRAMER_PARALLELISM_MAX_RATIO) = 0) generate
      process
      begin
        report "ERROR: PARALLELISM MAX RATIO CANNOT BE 0" severity failure;
        wait;
      end process;
    end generate CHKFRAMERP2;
 
-- internal processing
 
    --=============================================================================
    -- Begin of frameroutputp
    -- Generate valid frame output on footer data_valid signal
    --=============================================================================
    -- read: rst_i, wire_footer_data, wire_footer_data_valid
    -- write: dat_o, dat_val_o
    -- r/w: next_valid_frame_pointer
    FRAMEROUTPUTP: process (clk_i)
    variable next_valid_frame_pointer : integer range 0 to CCSDS_TX_FRAMER_FOOTER_NUMBER-1 := 0;
    begin
      -- on each clock rising edge
      if rising_edge(clk_i) then
        -- reset signal received
        if (rst_i = '1') then
          next_valid_frame_pointer := 0;
          dat_o <= (others => '0');
          dat_val_o <= '0';
        -- generating valid frames output
        else
          dat_o <= wire_footer_data_o(next_valid_frame_pointer);
          if (wire_footer_data_valid(next_valid_frame_pointer) = '1') then
            dat_val_o <= '1';
            if (next_valid_frame_pointer < (CCSDS_TX_FRAMER_FOOTER_NUMBER-1)) then
              next_valid_frame_pointer := (next_valid_frame_pointer + 1);
            else
              next_valid_frame_pointer := 0;
            end if;
          else
            dat_o <= (others => '0');
            dat_val_o <= '0';
          end if;
        end if;
      end if;
    end process;
    --=============================================================================
    -- Begin of framerprocessp
    -- Start footer computation on valid header signal
    --=============================================================================
    -- read: wire_header_data, wire_header_data_valid
    -- write: next_processing_frame_pointer, reg_processing_frame, wire_footer_next
    -- r/w: 
    FRAMERPROCESSP: process (clk_i)
    variable reg_next_processing_frame: std_logic_vector((CCSDS_TX_FRAMER_DATA_LENGTH)*8-1 downto 0);
    begin
      -- on each clock rising edge
      if rising_edge(clk_i) then
        -- reset signal received
        if (rst_i = '1') then
          next_processing_frame_pointer <= 0;
          wire_footer_next <= (others => '0');
        else
          if(wire_header_data_valid = '1') then
            reg_processing_frame((CCSDS_TX_FRAMER_DATA_LENGTH+CCSDS_TX_FRAMER_HEADER_LENGTH)*8-1 downto CCSDS_TX_FRAMER_DATA_LENGTH*8) <= wire_header_data;
            -- idle data to be used
            if (wire_header_data(10 downto 0) = "11111111110") then
              reg_processing_frame(CCSDS_TX_FRAMER_DATA_LENGTH*8-1 downto 0) <= CCSDS_TX_FRAMER_OID_PATTERN;
              reg_next_processing_frame := reg_current_frame;
            -- current data to be used
            else
              -- continuous data flow header is one clk in advance
              if (CCSDS_TX_FRAMER_DATA_LENGTH*8 = CCSDS_TX_FRAMER_DATA_BUS_SIZE) and (CCSDS_TX_FRAMER_PARALLELISM_MAX_RATIO = 1) then
                reg_processing_frame(CCSDS_TX_FRAMER_DATA_LENGTH*8-1 downto 0) <= reg_next_processing_frame;
                reg_next_processing_frame := reg_current_frame;
              -- header is synchronous with data
              else
                reg_processing_frame(CCSDS_TX_FRAMER_DATA_LENGTH*8-1 downto 0) <= reg_current_frame;
              end if;
            end if;
            wire_footer_next(next_processing_frame_pointer) <= '1';
            if (next_processing_frame_pointer = CCSDS_TX_FRAMER_FOOTER_NUMBER-1) then
              next_processing_frame_pointer <= 0;
            else
              next_processing_frame_pointer <= (next_processing_frame_pointer + 1);
            end if;
          end if;
          if (next_processing_frame_pointer = 0) then
            wire_footer_next(CCSDS_TX_FRAMER_FOOTER_NUMBER-1) <= '0';
          else
            wire_footer_next(next_processing_frame_pointer-1) <= '0';
          end if;
        end if;
      end if;
    end process;
    --=============================================================================
    -- Begin of framergeneratep
    -- Generate next_frame, start next header generation
    --=============================================================================
    -- read: dat_val_i, rst_i
    -- write: wire_header_next, reg_current_frame, reg_next_frame, dat_nxt_o, idl_o
    -- r/w: 
    FRAMERGENERATEP: process (clk_i)
    variable next_frame_write_pos: integer range 0 to (CCSDS_TX_FRAMER_DATA_LENGTH*8/CCSDS_TX_FRAMER_DATA_BUS_SIZE)-1 := (CCSDS_TX_FRAMER_DATA_LENGTH*8/CCSDS_TX_FRAMER_DATA_BUS_SIZE)-1;
    variable frame_output_counter: integer range 0 to (CCSDS_TX_FRAMER_DATA_LENGTH*CCSDS_TX_FRAMER_PARALLELISM_MAX_RATIO*8/CCSDS_TX_FRAMER_DATA_BUS_SIZE)-1 := 0;
    variable current_frame_ready: std_logic := '0';
    begin
      -- on each clock rising edge
      if rising_edge(clk_i) then
        -- reset signal received
        if (rst_i = '1') then
          current_frame_ready := '0';
          wire_header_next <= '0';
          next_frame_write_pos := (CCSDS_TX_FRAMER_DATA_LENGTH*8/CCSDS_TX_FRAMER_DATA_BUS_SIZE)-1;
          frame_output_counter := 0;
          idl_o <= '0';
          dat_nxt_o <= '0';
        else
          -- valid data is presented
          if (dat_val_i = '1') then
            -- next frame is full
            if (next_frame_write_pos = 0) then
              reg_current_frame(CCSDS_TX_FRAMER_DATA_BUS_SIZE-1 downto 0) <= dat_i;
              reg_current_frame(CCSDS_TX_FRAMER_DATA_LENGTH*8-1 downto CCSDS_TX_FRAMER_DATA_BUS_SIZE) <= reg_next_frame;
              -- time to start frame computation
              if (frame_output_counter = 0) then
                -- CRC is ready to compute
                if (wire_footer_busy(next_processing_frame_pointer) = '0') then
                  frame_output_counter := (CCSDS_TX_FRAMER_DATA_LENGTH*8*CCSDS_TX_FRAMER_PARALLELISM_MAX_RATIO/CCSDS_TX_FRAMER_DATA_BUS_SIZE)-1;
                  wire_header_next <= '1';
                  wire_header_idle <= '0';
                  idl_o <= '0';
                -- source data rate overflow / stop buffer output
                else
                  dat_nxt_o <= '0';
                end if;
              else
                frame_output_counter := frame_output_counter - 1;
                -- signal a frame ready for computation
                if (current_frame_ready = '0') then
                  wire_header_next <= '0';
                  current_frame_ready := '1';
                -- source data rate overflow
                else
                  dat_nxt_o <= '0';
                end if;
              end if;
              next_frame_write_pos := CCSDS_TX_FRAMER_DATA_LENGTH*8/CCSDS_TX_FRAMER_DATA_BUS_SIZE-1;
            else
              -- filling next frame
              reg_next_frame(next_frame_write_pos*CCSDS_TX_FRAMER_DATA_BUS_SIZE-1 downto (next_frame_write_pos-1)*CCSDS_TX_FRAMER_DATA_BUS_SIZE) <= dat_i;
              next_frame_write_pos := next_frame_write_pos-1;
              -- time to start frame computation
              if (frame_output_counter = 0) then
                -- CRC is ready to compute
                if (wire_footer_busy(next_processing_frame_pointer) = '0') then
                  dat_nxt_o <= '1';
                  frame_output_counter := (CCSDS_TX_FRAMER_DATA_LENGTH*CCSDS_TX_FRAMER_PARALLELISM_MAX_RATIO*8/CCSDS_TX_FRAMER_DATA_BUS_SIZE)-1;
                  -- no frame is ready / inserting idle data
                  if (current_frame_ready = '0') then
                    wire_header_next <= '1';
                    wire_header_idle <= '1';
                    idl_o <= '1';
                  -- a frame is ready
                  else
                    wire_header_next <= '1';
                    wire_header_idle <= '0';
                    current_frame_ready := '0';
                    idl_o <= '0';
                  end if;
                else
                  dat_nxt_o <= '0';
                end if;
              else
                -- stop data before overflow
                if (next_frame_write_pos = 1) and (current_frame_ready = '1') then
                  dat_nxt_o <= '0';
                end if;
                frame_output_counter := frame_output_counter - 1;
                wire_header_next <= '0';
              end if;
            end if;
          -- no valid data
          else
            -- time to start frame computation
            if (frame_output_counter = 0) then
              -- CRC is ready to compute
              if (wire_footer_busy(next_processing_frame_pointer) = '0') then
                dat_nxt_o <= '1';
                frame_output_counter := (CCSDS_TX_FRAMER_DATA_LENGTH*CCSDS_TX_FRAMER_PARALLELISM_MAX_RATIO*8/CCSDS_TX_FRAMER_DATA_BUS_SIZE)-1;
                if (current_frame_ready = '0') then
                  wire_header_next <= '1';
                  wire_header_idle <= '1';
                  idl_o <= '1';
                else
                  wire_header_next <= '1';
                  wire_header_idle <= '0';
                  current_frame_ready := '0';
                  idl_o <= '0';
                end if;
              end if;
            else
              wire_header_next <= '0';
              frame_output_counter := frame_output_counter - 1;
            end if;
          end if;
        end if;
      end if;
    end process;
end structure;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.