From 55291edc559a08316555d2da6b46a8b4a63c3d44 Mon Sep 17 00:00:00 2001
From: Grzegorz Daniluk <grzegorz.daniluk@cern.ch>
Date: Thu, 28 Jul 2016 15:03:11 +0200
Subject: [PATCH] wrsw_nic: bw throttling, no throttling yet

---
 modules/wrsw_nic/Manifest.py            |   1 +
 modules/wrsw_nic/nic_bw_throttling.vhd  | 204 ++++++++++++++++++++++++
 modules/wrsw_nic/nic_rx_fsm.vhd         |  36 ++++-
 modules/wrsw_nic/nic_wbgen2_pkg.vhd     |  24 +--
 modules/wrsw_nic/nic_wishbone_slave.vhd |  16 +-
 modules/wrsw_nic/wr_nic.wb              |  26 +++
 modules/wrsw_nic/wrsw_nic.vhd           |   7 +
 modules/wrsw_nic/xwrsw_nic.vhd          |   8 +
 top/bare_top/scb_top_bare.vhd           |   2 +
 top/bare_top/wrsw_components_pkg.vhd    |   2 +
 top/bare_top/wrsw_top_pkg.vhd           |   2 +
 11 files changed, 316 insertions(+), 12 deletions(-)
 create mode 100644 modules/wrsw_nic/nic_bw_throttling.vhd

diff --git a/modules/wrsw_nic/Manifest.py b/modules/wrsw_nic/Manifest.py
index b9d124c1..6aeab1db 100644
--- a/modules/wrsw_nic/Manifest.py
+++ b/modules/wrsw_nic/Manifest.py
@@ -6,6 +6,7 @@ files  = [  "nic_constants_pkg.vhd" ,
 						"nic_tx_fsm.vhd" ,
 						"nic_buffer.vhd" ,
 						"nic_elastic_buffer.vhd",
+                                                "nic_bw_throttling.vhd",
 						"nic_wbgen2_pkg.vhd",
 						"xwrsw_nic.vhd",
 						"wrsw_nic.vhd"];
diff --git a/modules/wrsw_nic/nic_bw_throttling.vhd b/modules/wrsw_nic/nic_bw_throttling.vhd
new file mode 100644
index 00000000..3ca233ee
--- /dev/null
+++ b/modules/wrsw_nic/nic_bw_throttling.vhd
@@ -0,0 +1,204 @@
+library IEEE;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+use work.wr_fabric_pkg.all;
+--use work.gencores_pkg.all;
+
+entity nic_bw_throttling is
+  generic (
+    g_true_random : boolean := false);
+  port (
+    clk_sys_i   : in  std_logic;
+    rst_n_i     : in  std_logic;
+
+    pps_p_i     : in std_logic;
+    pps_valid_i : in std_logic;
+
+    snk_i   : in  t_wrf_sink_in;
+    snk_o   : out t_wrf_sink_out;
+    src_o   : out t_wrf_source_out;
+    src_i   : in  t_wrf_source_in;
+
+    bw_o    : out std_logic_vector(31 downto 0);
+    rnd_o   : out std_logic_vector(31 downto 0));
+end nic_bw_throttling;
+
+architecture behav of nic_bw_throttling is
+
+  signal bw_cnt : unsigned(31 downto 0);
+  signal bw_reg : unsigned(31 downto 0);
+  signal is_data : std_logic;
+
+  signal drop_frame : std_logic;
+  type t_fwd_fsm is (WAIT_FRAME, FLUSH, PASS, DROP);
+  signal state_fwd : t_fwd_fsm;
+  signal wrf_reg : t_wrf_sink_in;
+
+  signal ring_out : std_logic_vector(31 downto 0);
+  signal rnd_reg  : std_logic_vector(31 downto 0);
+  --attribute keep : string;
+  --attribute keep of ring_out : signal is "true";
+  --attribute keep_hierarchy : string;
+  --attribute keep_hierarchy of behav : architecture is "true";
+  attribute S : string;
+  attribute S of ring_out : signal is "true";
+
+  constant c_LFSR_START : std_logic_vector := x"A5A5";
+begin
+
+  -------------------------------------------------
+  --          Random number generation           --
+  -------------------------------------------------
+  GEN_RND: if g_true_random generate
+    -- based on Generalized Ring Oscillator
+    ring_out(0) <= ring_out(31) xnor ring_out(0) xnor ring_out(1);
+    GEN_RND: for I in 1 to 30 generate
+      ring_out(I) <= ring_out(I-1) xor ring_out(I) xor ring_out(I+1);
+    end generate;
+    ring_out(31) <= ring_out(30) xor ring_out(31) xor ring_out(0);
+
+    --GEN_ANTI_META: for J in 0 to 31 generate
+    --  SYNC_FFS: gc_sync_ffs
+    --    port map (
+    --      clk_i    => clk_sys_i,
+    --      rst_n_i  => rst_n_i,
+    --      data_i   => ring_out(J),
+    --      synced_o => rnd_reg(J));
+    --end generate;
+    process(clk_sys_i)
+    begin
+      if rising_edge(clk_sys_i) then
+        if rst_n_i = '0' then
+          rnd_reg <= (others=>'0');
+        else
+          rnd_reg <= ring_out;
+        end if;
+      end if;
+    end process;
+  end generate;
+
+  GEN_PSEUDO_RND: if not g_true_random generate
+    -- based on LSFR x^16 + x^15 + x^13 + x^4 + 1
+    process(clk_sys_i)
+    begin
+      if rising_edge(clk_sys_i) then
+        if rst_n_i = '0' then
+          rnd_reg(31 downto 0) <= (others=>'0');
+          rnd_reg(15 downto 0) <= c_LFSR_START;
+        else
+          rnd_reg(0) <= rnd_reg(15) xor rnd_reg(14) xor rnd_reg(12) xor rnd_reg(3);
+          rnd_reg(15 downto 1) <= rnd_reg(14 downto 0);
+        end if;
+      end if;
+    end process;
+
+  end generate;
+
+  rnd_o <= rnd_reg;
+
+  -------------------------------------------------
+  --        Forwarding or dropping frames        --
+  -------------------------------------------------
+  drop_frame <= '0';
+
+  process(clk_sys_i)
+  begin
+    if rising_edge(clk_sys_i) then
+      if rst_n_i = '0' then
+        state_fwd <= WAIT_FRAME;
+        wrf_reg <= c_dummy_snk_in;
+
+        snk_o <= c_dummy_src_in;
+        src_o <= c_dummy_snk_in;
+      else
+        case state_fwd is
+          when WAIT_FRAME =>
+            snk_o.ack   <= '0';
+            snk_o.err   <= '0';
+            snk_o.rty   <= '0';
+            src_o       <= c_dummy_snk_in;
+            if (snk_i.cyc='1' and snk_i.stb='1') then
+              -- new frame is transmitted
+              snk_o.stall <= '1';
+              wrf_reg <= snk_i;
+
+              if (drop_frame = '0') then
+                state_fwd <= FLUSH;
+              elsif (drop_frame = '1') then
+                state_fwd <= DROP;
+              end if;
+            else
+              snk_o.stall <= '0';
+            end if;
+
+          when FLUSH =>
+            -- flush wrf_reg stored on stall or in WAIT_FRAME
+            snk_o <= src_i;
+            if (src_i.stall = '0') then
+              src_o     <= wrf_reg;
+              state_fwd <= PASS;
+            end if;
+
+          when PASS =>
+            snk_o <= src_i;
+            if (src_i.stall = '0') then
+              src_o <= snk_i;
+            else
+              wrf_reg   <= snk_i;
+              state_fwd <= FLUSH;
+            end if;
+
+          when DROP =>
+            -- ack everything from SNK, pass nothing to SRC
+            snk_o.stall <= '0';
+            snk_o.err   <= '0';
+            snk_o.rty   <= '0';
+            src_o       <= c_dummy_snk_in;
+            if (snk_i.stb='1') then
+              snk_o.ack <= '1';
+            else
+              snk_o.ack <= '0';
+            end if;
+
+            if (snk_i.cyc='0' and snk_i.stb='0') then
+              state_fwd <= WAIT_FRAME;
+            end if;
+        end case;
+      end if;
+    end if;
+  end process;
+
+
+  -------------------------------------------------
+  -- Calculating bandwidth actually going to ARM --
+  -------------------------------------------------
+
+  is_data <= '1' when (snk_i.adr=c_WRF_DATA and snk_i.cyc='1' and snk_i.stb='1') else
+             '0';
+
+  process(clk_sys_i)
+  begin
+    if rising_edge(clk_sys_i) then
+      if rst_n_i = '0' or pps_valid_i = '0' then
+        bw_cnt <= (others=>'0');
+        bw_reg <= (others=>'0');
+      elsif pps_p_i = '1' then
+        bw_reg <= bw_cnt;
+        bw_cnt <= (others=>'0');
+      elsif is_data = '1' then
+        -- we count incoming bytes here
+        if snk_i.sel(0) = '1' then
+          -- 16bits carry valid data
+          bw_cnt <= bw_cnt + 2;
+        elsif snk_i.sel(0) = '0' then
+          -- only 8bits carry valid data
+          bw_cnt <= bw_cnt + 1;
+        end if;
+      end if;
+    end if;
+  end process;
+  
+  bw_o <= std_logic_vector(bw_reg);
+
+end behav;
diff --git a/modules/wrsw_nic/nic_rx_fsm.vhd b/modules/wrsw_nic/nic_rx_fsm.vhd
index 6db617cc..a8bc4667 100644
--- a/modules/wrsw_nic/nic_rx_fsm.vhd
+++ b/modules/wrsw_nic/nic_rx_fsm.vhd
@@ -57,6 +57,8 @@ entity nic_rx_fsm is
         clk_sys_i : in std_logic;
         rst_n_i   : in std_logic;
 
+        pps_p_i     : in std_logic;
+        pps_valid_i : in std_logic;
 -------------------------------------------------------------------------------
 -- WRF sink
 -------------------------------------------------------------------------------
@@ -121,6 +123,20 @@ architecture behavioral of NIC_RX_FSM is
       dreq_i    : in  std_logic);
   end component;
 
+  component nic_bw_throttling
+    port (
+      clk_sys_i   : in  std_logic;
+      rst_n_i     : in  std_logic;
+      pps_p_i     : in std_logic;
+      pps_valid_i : in std_logic;
+      snk_i   : in  t_wrf_sink_in;
+      snk_o   : out t_wrf_sink_out;
+      src_o   : out t_wrf_source_out;
+      src_i   : in  t_wrf_source_in;
+      bw_o    : out std_logic_vector(31 downto 0);
+      rnd_o   : out std_logic_vector(31 downto 0));
+  end component;
+
 
   type t_rx_fsm_state is (RX_DISABLED, RX_WAIT_SOF, RX_REQUEST_DESCRIPTOR, RX_DATA, RX_UPDATE_DESC, RX_MEM_RESYNC, RX_MEM_FLUSH);
 
@@ -147,17 +163,33 @@ architecture behavioral of NIC_RX_FSM is
 
   signal fab_in     : t_ep_internal_fabric;
   signal fab_dreq   : std_logic;
+
+  signal bw_src_out : t_wrf_source_out;
+  signal bw_src_in  : t_wrf_source_in;
   
 begin
 
+  U_Throttling: nic_bw_throttling
+    port map (
+      clk_sys_i   => clk_sys_i,
+      rst_n_i     => rst_n_i,
+      pps_p_i     => pps_p_i,
+      pps_valid_i => pps_valid_i,
+      snk_i       => snk_i,
+      snk_o       => snk_o,
+      src_o       => bw_src_out,
+      src_i       => bw_src_in,
+      bw_o        => regs_o.bw_i,
+      rnd_o       => regs_o.rnd_i);
+
   U_Buffer : nic_elastic_buffer
     generic map (
       g_depth => 64)
     port map (
       clk_sys_i => clk_sys_i,
       rst_n_i   => rst_n_i,
-      snk_i     => snk_i,
-      snk_o     => snk_o,
+      snk_i     => bw_src_out, --snk_i,
+      snk_o     => bw_src_in,  --snk_o,
       fab_o     => fab_in,
       dreq_i    => fab_dreq);
 
diff --git a/modules/wrsw_nic/nic_wbgen2_pkg.vhd b/modules/wrsw_nic/nic_wbgen2_pkg.vhd
index d0bb3b3b..f4ab2e05 100644
--- a/modules/wrsw_nic/nic_wbgen2_pkg.vhd
+++ b/modules/wrsw_nic/nic_wbgen2_pkg.vhd
@@ -3,7 +3,7 @@
 ---------------------------------------------------------------------------------------
 -- File           : nic_wbgen2_pkg.vhd
 -- Author         : auto-generated by wbgen2 from wr_nic.wb
--- Created        : Fri Jul  3 16:18:39 2015
+-- Created        : Thu Jul 28 10:18:55 2016
 -- Standard       : VHDL'87
 ---------------------------------------------------------------------------------------
 -- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wr_nic.wb
@@ -27,6 +27,8 @@ package nic_wbgen2_pkg is
     sr_tx_error_i                            : std_logic;
     sr_cur_tx_desc_i                         : std_logic_vector(2 downto 0);
     sr_cur_rx_desc_i                         : std_logic_vector(2 downto 0);
+    bw_i                                     : std_logic_vector(31 downto 0);
+    rnd_i                                    : std_logic_vector(31 downto 0);
     end record;
   
   constant c_nic_in_registers_init_value: t_nic_in_registers := (
@@ -35,7 +37,9 @@ package nic_wbgen2_pkg is
     sr_tx_done_i => '0',
     sr_tx_error_i => '0',
     sr_cur_tx_desc_i => (others => '0'),
-    sr_cur_rx_desc_i => (others => '0')
+    sr_cur_rx_desc_i => (others => '0'),
+    bw_i => (others => '0'),
+    rnd_i => (others => '0')
     );
     
     -- Output registers (WB slave -> user design)
@@ -71,20 +75,20 @@ end package;
 package body nic_wbgen2_pkg is
 function f_x_to_zero (x:std_logic) return std_logic is
 begin
-if(x = 'X' or x = 'U') then
-return '0';
+if x = '1' then
+return '1';
 else
-return x;
-end if; 
+return '0';
+end if;
 end function;
 function f_x_to_zero (x:std_logic_vector) return std_logic_vector is
 variable tmp: std_logic_vector(x'length-1 downto 0);
 begin
 for i in 0 to x'length-1 loop
-if(x(i) = 'X' or x(i) = 'U') then
-tmp(i):= '0';
+if x(i) = '1' then
+tmp(i):= '1';
 else
-tmp(i):=x(i);
+tmp(i):= '0';
 end if; 
 end loop; 
 return tmp;
@@ -98,6 +102,8 @@ tmp.sr_tx_done_i := f_x_to_zero(left.sr_tx_done_i) or f_x_to_zero(right.sr_tx_do
 tmp.sr_tx_error_i := f_x_to_zero(left.sr_tx_error_i) or f_x_to_zero(right.sr_tx_error_i);
 tmp.sr_cur_tx_desc_i := f_x_to_zero(left.sr_cur_tx_desc_i) or f_x_to_zero(right.sr_cur_tx_desc_i);
 tmp.sr_cur_rx_desc_i := f_x_to_zero(left.sr_cur_rx_desc_i) or f_x_to_zero(right.sr_cur_rx_desc_i);
+tmp.bw_i := f_x_to_zero(left.bw_i) or f_x_to_zero(right.bw_i);
+tmp.rnd_i := f_x_to_zero(left.rnd_i) or f_x_to_zero(right.rnd_i);
 return tmp;
 end function;
 end package body;
diff --git a/modules/wrsw_nic/nic_wishbone_slave.vhd b/modules/wrsw_nic/nic_wishbone_slave.vhd
index b0e64f19..1702ae62 100644
--- a/modules/wrsw_nic/nic_wishbone_slave.vhd
+++ b/modules/wrsw_nic/nic_wishbone_slave.vhd
@@ -3,7 +3,7 @@
 ---------------------------------------------------------------------------------------
 -- File           : nic_wishbone_slave.vhd
 -- Author         : auto-generated by wbgen2 from wr_nic.wb
--- Created        : Fri Jul  3 16:18:39 2015
+-- Created        : Thu Jul 28 10:18:55 2016
 -- Standard       : VHDL'87
 ---------------------------------------------------------------------------------------
 -- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE wr_nic.wb
@@ -223,6 +223,18 @@ begin
               rddata_reg(31) <= 'X';
               ack_sreg(0) <= '1';
               ack_in_progress <= '1';
+            when "0010" => 
+              if (wb_we_i = '1') then
+              end if;
+              rddata_reg(31 downto 0) <= regs_i.bw_i;
+              ack_sreg(0) <= '1';
+              ack_in_progress <= '1';
+            when "0011" => 
+              if (wb_we_i = '1') then
+              end if;
+              rddata_reg(31 downto 0) <= regs_i.rnd_i;
+              ack_sreg(0) <= '1';
+              ack_in_progress <= '1';
             when "1000" => 
               if (wb_we_i = '1') then
                 eic_idr_write_int <= '1';
@@ -460,6 +472,8 @@ begin
   regs_o.sr_tx_error_o <= wrdata_reg(3);
 -- Current TX descriptor
 -- Current RX descriptor
+-- Bytes-per-second
+-- 32-bit random number for throttling
 -- extra code for reg/fifo/mem: TX descriptors mem
 -- RAM block instantiation for memory: TX descriptors mem
   nic_dtx_raminst : wbgen2_dpssram
diff --git a/modules/wrsw_nic/wr_nic.wb b/modules/wrsw_nic/wr_nic.wb
index 6c63d874..e50197ab 100644
--- a/modules/wrsw_nic/wr_nic.wb
+++ b/modules/wrsw_nic/wr_nic.wb
@@ -152,6 +152,32 @@ top = peripheral {
 			};
    };
 
+   reg {
+      name = "NIC Bandwidth Register";
+      prefix = "BW";
+      field {
+        name = "Bytes-per-second";
+        type = SLV;
+        size = 32;
+        access_bus = READ_ONLY;
+        access_dev = WRITE_ONLY;
+        load = LOAD_EXT;
+      };
+   };
+
+   reg {
+      name = "NIC Random Register";
+      prefix = "RND";
+      field {
+        name = "32-bit random number for throttling";
+        type = SLV;
+        size = 32;
+        access_bus = READ_ONLY;
+        access_dev = WRITE_ONLY;
+        load = LOAD_EXT;
+      };
+   };
+
 	 irq {
       name = "Receive Complete";
       prefix = "rcomp";
diff --git a/modules/wrsw_nic/wrsw_nic.vhd b/modules/wrsw_nic/wrsw_nic.vhd
index b0147c03..2e933ccd 100644
--- a/modules/wrsw_nic/wrsw_nic.vhd
+++ b/modules/wrsw_nic/wrsw_nic.vhd
@@ -54,6 +54,9 @@ entity wrsw_nic is
     clk_sys_i : in std_logic;
     rst_n_i   : in std_logic;
 
+    pps_p_i     : in std_logic;
+    pps_valid_i : in std_logic;
+
 -------------------------------------------------------------------------------
 -- Pipelined Wishbone interface
 -------------------------------------------------------------------------------
@@ -120,6 +123,8 @@ architecture rtl of wrsw_nic is
     port (
       clk_sys_i           : in  std_logic;
       rst_n_i             : in  std_logic;
+      pps_p_i             : in std_logic;
+      pps_valid_i         : in std_logic;
       snk_i               : in  t_wrf_sink_in;
       snk_o               : out t_wrf_sink_out;
       src_i               : in  t_wrf_source_in;
@@ -154,6 +159,8 @@ begin
     port map (
       clk_sys_i           => clk_sys_i,
       rst_n_i             => rst_n_i,
+      pps_p_i             => pps_p_i,
+      pps_valid_i         => pps_valid_i,
       snk_i               => snk_in,
       snk_o               => snk_out,
       src_i               => src_in,
diff --git a/modules/wrsw_nic/xwrsw_nic.vhd b/modules/wrsw_nic/xwrsw_nic.vhd
index 3202eff9..aa186cfa 100644
--- a/modules/wrsw_nic/xwrsw_nic.vhd
+++ b/modules/wrsw_nic/xwrsw_nic.vhd
@@ -67,6 +67,9 @@ entity xwrsw_nic is
   port (
     clk_sys_i : in std_logic;
     rst_n_i   : in std_logic;
+    
+    pps_p_i     : in std_logic;
+    pps_valid_i : in std_logic;
 
 -------------------------------------------------------------------------------
 -- WRF sink
@@ -138,6 +141,8 @@ architecture rtl of xwrsw_nic is
     port (
       clk_sys_i             : in  std_logic;
       rst_n_i               : in  std_logic;
+      pps_p_i               : in std_logic;
+      pps_valid_i           : in std_logic;
       snk_i                 : in  t_wrf_sink_in;
       snk_o                 : out t_wrf_sink_out;
       regs_i                : in  t_nic_out_registers;
@@ -488,6 +493,9 @@ begin  -- rtl
       clk_sys_i => clk_sys_i,
       rst_n_i   => nic_reset_n,
 
+      pps_p_i     => pps_p_i,
+      pps_valid_i => pps_valid_i,
+
       snk_i => snk_i,
       snk_o => snk_o,
 
diff --git a/top/bare_top/scb_top_bare.vhd b/top/bare_top/scb_top_bare.vhd
index e76a9201..28cc247a 100644
--- a/top/bare_top/scb_top_bare.vhd
+++ b/top/bare_top/scb_top_bare.vhd
@@ -607,6 +607,8 @@ begin
       port map (
         clk_sys_i           => clk_sys,
         rst_n_i             => rst_n_sys,
+        pps_p_i             => pps_csync,
+        pps_valid_i         => pps_valid,
         snk_i               => endpoint_snk_in(c_NUM_PORTS),
         snk_o               => endpoint_snk_out(c_NUM_PORTS),
         src_i               => endpoint_src_in(c_NUM_PORTS),
diff --git a/top/bare_top/wrsw_components_pkg.vhd b/top/bare_top/wrsw_components_pkg.vhd
index 68c4c65d..60185f05 100644
--- a/top/bare_top/wrsw_components_pkg.vhd
+++ b/top/bare_top/wrsw_components_pkg.vhd
@@ -184,6 +184,8 @@ package wrsw_components_pkg is
     port (
       clk_sys_i           : in  std_logic;
       rst_n_i             : in  std_logic;
+      pps_p_i             : in std_logic;
+      pps_valid_i         : in std_logic;
       snk_i               : in  t_wrf_sink_in;
       snk_o               : out t_wrf_sink_out;
       src_i               : in  t_wrf_source_in;
diff --git a/top/bare_top/wrsw_top_pkg.vhd b/top/bare_top/wrsw_top_pkg.vhd
index 32f0e1b2..6be38d30 100644
--- a/top/bare_top/wrsw_top_pkg.vhd
+++ b/top/bare_top/wrsw_top_pkg.vhd
@@ -184,6 +184,8 @@ package wrsw_top_pkg is
     port (
       clk_sys_i           : in  std_logic;
       rst_n_i             : in  std_logic;
+      pps_p_i             : in std_logic;
+      pps_valid_i         : in std_logic;
       snk_i               : in  t_wrf_sink_in;
       snk_o               : out t_wrf_sink_out;
       src_i               : in  t_wrf_source_in;
-- 
GitLab