├── .gitignore ├── LICENSE.md ├── README.md ├── csim ├── cr_engine │ ├── cr_engine.h │ ├── cwnd_cr_engine.cc │ └── cwnd_cr_engine.h ├── dd_engine │ ├── dd_engine.cc │ └── dd_engine.h ├── fifo │ ├── fifo1w.cc │ ├── fifo1w.h │ ├── fifo2w.cc │ ├── fifo2w.h │ ├── fifo4w.cc │ └── fifo4w.h ├── main.cc ├── receiver │ ├── nreno_receiver.h │ ├── receiver.cc │ ├── receiver.h │ ├── sliding_window.cc │ └── sliding_window.h ├── tonic.cc ├── tonic.h └── utils │ ├── util.cc │ └── util.h ├── include ├── clogb2.vh ├── flow_state_defaults.vh ├── sim.vh └── system_params.vh ├── settings.sh ├── src ├── bitmap_ops │ ├── cnt_wnd │ │ ├── cnt_block.v │ │ ├── cnt_set.v │ │ └── cnt_wnd.v │ └── ff_wnd │ │ ├── ff_block.v │ │ ├── ff_set.v │ │ └── ff_wnd.v ├── context_store │ ├── 2w2r │ │ └── cntxt_store_2w2r.v │ └── 4w4r │ │ └── cntxt_store_4w4r.v ├── cr_engine │ ├── common │ │ └── event_processors │ │ │ └── cr_enqueue │ │ │ └── cr_enqueue.v │ └── cwnd │ │ ├── cr_core.v │ │ ├── cr_engine.v │ │ └── event_processors │ │ └── cr_transmit │ │ └── cr_transmit.v ├── dd_engine │ ├── dd_core.v │ ├── dd_engine.v │ └── event_processors │ │ ├── dd_dequeue_prop │ │ └── dd_dequeue_prop.v │ │ ├── dd_incoming │ │ ├── dd_incoming_0.v │ │ └── dd_incoming_1.v │ │ ├── dd_next │ │ └── dd_next.v │ │ └── dd_timeout │ │ └── dd_timeout.v ├── fifos │ ├── fifo_1w │ │ └── fifo_1w.v │ ├── fifo_2w │ │ └── fifo_2w.v │ ├── fifo_3w │ │ └── fifo_3w.v │ └── fifo_4w │ │ └── fifo_4w.v ├── ram │ ├── ram_2p_wrapper.v │ ├── ram_2w2r.v │ ├── ram_2w4r.v │ └── ram_4w4r.v ├── tonic.v └── user_defined_logic │ ├── nreno_1 │ ├── include │ │ └── user_constants.vh │ ├── user_defined_incoming.v │ └── user_defined_timeout.v │ ├── nreno_2 │ ├── include │ │ └── user_constants.vh │ ├── user_defined_incoming.v │ └── user_defined_timeout.v │ ├── reno │ ├── include │ │ └── user_constants.vh │ ├── user_defined_incoming.v │ └── user_defined_timeout.v │ └── sack │ ├── include │ └── user_constants.vh │ ├── user_defined_incoming.v │ └── user_defined_timeout.v ├── tb ├── config │ └── tonic │ │ ├── tonic_nreno_1.yaml │ │ ├── tonic_nreno_2.yaml │ │ ├── tonic_reno.yaml │ │ └── tonic_sack.yaml └── sim │ ├── common │ └── sim_receiver │ │ ├── ack_prio_queue.c │ │ ├── ack_prio_queue.h │ │ ├── constants.h │ │ ├── receiver_resp.h │ │ ├── sim.flist │ │ ├── sim_receiver.c │ │ ├── sim_receiver.tab │ │ ├── sim_receiver.v │ │ ├── sliding_window.c │ │ └── sliding_window.h │ ├── sim.flist │ └── tonic │ ├── cr_flists │ ├── cwnd.flist │ ├── rate.flist │ └── token.flist │ ├── nreno_1 │ ├── receiver_resp.c │ └── sim.flist │ ├── nreno_2 │ ├── receiver_resp.c │ └── sim.flist │ ├── reno │ ├── receiver_resp.c │ └── sim.flist │ ├── sack │ ├── receiver_resp.c │ └── sim.flist │ ├── sim.flist │ └── sim_top.v └── tools ├── lib ├── commonlib.py ├── config.py ├── dbglib.py ├── simlib.py └── testlib.py ├── libconfig.py └── runtest /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | build/ 3 | tools/*.pyc 4 | tools/lib/*.pyc 5 | tb/sim/tonic/sim_top_debug.v 6 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Princeton University 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tonic 2 | 3 | Tonic is a programmable hardware architecture for the transport logic, i.e., reliable data delivery and congestion control. All the design files in this repository are available for use under the 3-clause BSD License. 4 | 5 | 6 | 7 | ## Code Structure 8 | 9 | - **src/** - source files 10 | - **tonic.v** (Tonic's top-level) 11 | - **dd_engine/** (Data Delivery Engine) 12 | - **cr_engine/** (Credit Engine) 13 | - **user_defined_logic/** 14 | - Other components used by the engines (e.g., RAM, bitmap operations, etc.) 15 | - **include/** system-wide constants 16 | - **tb/** - testbench files 17 | - **config/** (.yaml files for configuring simulations and test parameters) 18 | - **sim/** (simulation files for Tonic, including a mock receiver in C) 19 | - **tools/** (scripts for running simulations and tests) 20 | - **build/** - temporary build files. The output of the build and simulation goes in this directory. 21 | - **csim/** - Tonic's cycle-accurate simulator in C++. 22 | 23 | **Note:** Some directories are empty as they are being ported into the new infrastructre. 24 | 25 | ---- 26 | ## Setting up the Environment 27 | 28 | Before running any scripts, make sure to setup the environment variables by running 29 | 30 | ``` 31 | source settings.sh 32 | ``` 33 | 34 | ---- 35 | ## Running Simulation and Other Tests 36 | 37 | All the simulations and tests are executed through the `tools/runtest` script. 38 | 39 | ``` 40 | ./tools/runtest --type [sim|unit|system] \ 41 | --config path_of_config_file_from_config_root.yaml \ 42 | [--debug] 43 | ``` 44 | 45 | **Notes:** 46 | - The `system` and `unit` options are not included yet and therefore cannot be used for now. 47 | - The `sim` option simulates the module that is designated in the config file using the initial parameters specified in the same file. Currently, we have simulation files for `tonic`, for which you can specify a protocol and initial parameters. See below for more information on the format of the configuration file. 48 | - Note that *path_of_the_config_file_from_config_root.yaml* is **not** the full path to the config file. It is the path to the file starting from `tb/config`. 49 | - The `debug` option is used to send a flag to simulation files to print debugging information. Please see `tb/sim/dd_engine/sim_top.v` for an example. 50 | 51 | ### The Configuration File 52 | 53 | Configuration files are in YAML format. Here is the basic structure of a configuration file. 54 | 55 | ``` 56 | module_name: 57 | params: 58 | module_specific_param1: val1 59 | module_specific_param2: val2 60 | ... 61 | specs: 62 | sim_cycles: val 63 | 64 | # sim_specific_params 65 | sim_specific_param1: val1 66 | sim_specific_param2: val2 67 | ... 68 | ``` 69 | 70 | **Notes** 71 | - `module_name` is, in most cases, the name of the top-level module for the test. Exception are top-level modules such as `tonic` and ``dd_engine`` that include one or more of the programmable modules (i.e., `user_defined_incoming` and `user_defined_timeout`). In those cases, `module_name` should be `top_level_module/protocol_name`. For instance, to test `tonic` with `reno`, the `module_name` should be `tonic/reno`. 72 | - All the relevant simulations and test files for `module_name` (except for the source files) should be in `tb/test_type/module_name`, where `test_type` is either of `sim`, `unit`, and `system`. 73 | - `params` is for specifying module-specific parameters. For `tonic`, these are `init_wnd_size` and `init_rtx_timer_amnt`. As another example, if one were to write a unit test for the `fifo` module used in Tonic, these paramters could include its depth and width. 74 | - `specs` are parameters used for customizing the simulation: 75 | - `sim_cycles` specifies how many cycles to run the test for and should be specified in all configuration files. 76 | - For end-to-end simulations for `tonic`, the following options are required (See `tb/config/` for examples). 77 | `active_flow_cnt`, `receiver`, `loss_prob` (represented in X in thousands), and `rtt` are only used for end-to-end simulations for `tonic`. 78 | ``` 79 | active_flow_cnt: val (total number of flows to simulate) 80 | receiver: True/False (whether the simulations requires a mock receiver) 81 | loss_prob: X (the resulting loss probability will be X/1000) 82 | rtt: val (in nanoseconds) 83 | cr_type: val (type of the credit engine, 0 -> cwnd, 1 -> rate, 2 -> tokens) 84 | ... 85 | ``` 86 | - For top-level modules such as `tonic` and ``dd_engine`` that include one or more of the programmable modules, the following simulation variables should be specified as well: 87 | ``` 88 | user_context_w: val (number of bits used for protocol-specific state) 89 | init_user_context: val (in hex, the initial value for protocol-specific state) 90 | send_dd_context: 0 or 1 (whether to send protocol-specific state to cr engine. 0 for all cwnd-based protocols) 91 | ``` 92 | ---- 93 | ## Other Notes 94 | 95 | ### Credit Engines 96 | The current version of the code does not include the implementation of the rate-based and grant-based credit engine. Thus, as of now, only protocols that use congestion window as means of handling credit can be simulated. 97 | 98 | ### Adding your Own Protocol 99 | 100 | The current version of the code includes four example protocols in `src/user_defined_logic/`, all some variant of TCP: Reno, two different implementations of New Reno one based on [RFC 6582](https://tools.ietf.org/html/rfc6582), and an implementation of selective acknowledgment based on [RFC 6675](https://tools.ietf.org/html/rfc6675). To add your own protocol `proto`, create `user_defined_logic/proto` folder and implement `user_defined_incomig.v` and `user_defined_timeout.v`, following the input/output interface of the examples. Then create `tb/sim/tonic/proto` and follow the example in `tb/sim/tonic` to add protocol specific receiver behavior and simulation files. 101 | 102 | -------------------------------------------------------------------------------- /csim/cr_engine/cr_engine.h: -------------------------------------------------------------------------------- 1 | #ifndef CR_ENGINE__H 2 | #define CR_ENGINE__H 3 | 4 | #include "system_defs.h" 5 | 6 | class CREngine{ 7 | public: 8 | 9 | // Inputs 10 | 11 | uint8_t clk; 12 | uint8_t rst_n; 13 | 14 | uint32_t enq_fid_in; 15 | uint32_t enq_seq_in; 16 | uint32_t enq_seq_tx_id_in; 17 | 18 | uint32_t dd_cntxt_in; 19 | 20 | uint32_t incoming_fid_in; 21 | PktType pkt_type_in; 22 | PktData pkt_data_in; 23 | 24 | uint32_t timeout_fid_in; 25 | 26 | uint8_t tx_val; 27 | 28 | // Outputs 29 | uint32_t next_seq_fid_out; 30 | uint32_t next_seq_out; 31 | uint8_t next_seq_tx_id_out; 32 | 33 | uint32_t dp_fid_out; 34 | uint32_t cr_cntxt_out; 35 | 36 | virtual void eval() = 0; 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /csim/cr_engine/cwnd_cr_engine.cc: -------------------------------------------------------------------------------- 1 | #include "cwnd_cr_engine.h" 2 | 3 | #include 4 | 5 | CwndCREngine::CwndCREngine(uint32_t flow_cnt){ 6 | this->flow_cnt = flow_cnt; 7 | none_elem = FLOW_ID_NONE; 8 | tx_fifo = new Fifo2W(flow_cnt, &none_elem); 9 | 10 | queue_w_data_0 = new uint32_t(FLOW_ID_NONE); 11 | queue_w_data_1 = new uint32_t(FLOW_ID_NONE); 12 | 13 | for (uint32_t i = 0; i < flow_cnt; i++){ 14 | 15 | // init ram 16 | Context* flow_cntxt = new Context(); 17 | ram[i + 1] = flow_cntxt; 18 | } 19 | 20 | Context* flow_cntxt = new Context(); 21 | ram[FLOW_ID_NONE] = flow_cntxt; 22 | 23 | // other inits 24 | incoming_fid_in = FLOW_ID_NONE; 25 | enq_fid_in = FLOW_ID_NONE; 26 | 27 | } 28 | 29 | void CwndCREngine::eval(){ 30 | // Fifo 31 | tx_fifo->clk = clk; 32 | tx_fifo->rst_n = rst_n; 33 | 34 | uint8_t tx_fifo_w_val_0, tx_fifo_w_val_1; 35 | tx_fifo_w_val_0 = *queue_w_data_0 != FLOW_ID_NONE; 36 | tx_fifo_w_val_1 = *queue_w_data_1 != FLOW_ID_NONE; 37 | 38 | tx_fifo->w_val_0 = tx_fifo_w_val_0; 39 | tx_fifo->w_data_0 = queue_w_data_0; 40 | tx_fifo->w_val_1 = tx_fifo_w_val_1; 41 | tx_fifo->w_data_1 = queue_w_data_1; 42 | tx_fifo->r_val = tx_val; 43 | 44 | tx_fifo->eval(); 45 | 46 | //// CR Core 47 | 48 | // Positive edge of clock 49 | if (prev_clk == 0 && 50 | clk == 1){ 51 | if (!rst_n){ 52 | 53 | // Fifo 54 | queue_w_data_0 = new uint32_t(FLOW_ID_NONE); 55 | queue_w_data_1 = new uint32_t(FLOW_ID_NONE); 56 | 57 | // Ps 58 | enq_fid_p = FLOW_ID_NONE; 59 | tx_fid_p = FLOW_ID_NONE; 60 | 61 | enq_seq_p = FLOW_SEQ_NONE; 62 | // Ls 63 | enq_fid_l = FLOW_ID_NONE; 64 | tx_fid_l = FLOW_ID_NONE; 65 | 66 | enq_seq_l = FLOW_SEQ_NONE; 67 | } 68 | else{ 69 | // Fifo 70 | queue_w_data_0 = new uint32_t(tx_enq_fid1); 71 | queue_w_data_1 = new uint32_t(tx_enq_fid2); 72 | 73 | // Ps 74 | enq_fid_p = enq_fid_l; 75 | tx_fid_p = tx_fid_l; 76 | 77 | enq_seq_p = enq_seq_l; 78 | 79 | // Ls 80 | enq_fid_l = enq_fid_in; 81 | tx_fid_l = tx_fid_in; 82 | 83 | enq_seq_l = enq_seq_in; 84 | } 85 | 86 | ////////// Look up P contexts //////////// 87 | Context *enq_cntxt_p, *tx_cntxt_p; 88 | 89 | enq_cntxt_p = ram[enq_fid_p]; 90 | tx_cntxt_p = ram[tx_fid_p]; 91 | 92 | if (DEBUG){ 93 | 94 | cout << "enq_fid_in: " << enq_fid_in << endl; 95 | cout << "tx_fid_in: " << tx_fid_in << endl; 96 | cout << "--------------------------" << endl; 97 | 98 | cout << "enq_fid_p: " << enq_fid_p << endl; 99 | cout << "enq_cntxt_p: " << endl << *enq_cntxt_p << endl; 100 | cout << "--------------------------" << endl; 101 | 102 | cout << "tx_fid_p: " << tx_fid_p << endl; 103 | cout << "tx_cntxt_p: " << endl << *tx_cntxt_p << endl; 104 | cout << "--------------------------" << endl; 105 | 106 | } 107 | //////// Process events ////////// 108 | 109 | //// Enq 110 | enq_cntxt_p->pkt_queue.push(enq_seq_p); 111 | 112 | //// 113 | next_seq_out = FLOW_SEQ_NONE; 114 | next_seq_fid_out = tx_fid_p; 115 | next_seq_tx_id_out = 0; 116 | 117 | if (tx_fid_p != FLOW_ID_NONE) { 118 | next_seq_out = tx_cntxt_p->pkt_queue.front(); 119 | tx_cntxt_p->pkt_queue.pop(); 120 | } 121 | 122 | ///////////// Merge ////////////// 123 | 124 | // ready_to_tx and output 125 | 126 | tx_enq_fid1 = FLOW_ID_NONE; 127 | tx_enq_fid2 = FLOW_ID_NONE; 128 | 129 | 130 | tx_cntxt_p->ready_to_tx = !tx_cntxt_p->pkt_queue.empty(); 131 | if (tx_cntxt_p->ready_to_tx) tx_enq_fid2 = tx_fid_p; 132 | if (tx_fid_p != enq_fid_p && 133 | enq_cntxt_p->pkt_queue.size() == 1){ 134 | enq_cntxt_p->ready_to_tx = true; 135 | tx_enq_fid1 = enq_fid_p; 136 | } 137 | 138 | 139 | dp_fid_out = tx_fid_p; 140 | cr_cntxt_out = 0; 141 | 142 | // Print updated contexts 143 | if (DEBUG){ 144 | cout << "enq_fid_p: " << enq_fid_p << endl; 145 | cout << "updated enq_cntxt_p: " << endl << *enq_cntxt_p << endl; 146 | cout << "--------------------------" << endl; 147 | 148 | cout << "tx_fid_p: " << tx_fid_p << endl; 149 | cout << "updated tx_cntxt_p: " << endl << *tx_cntxt_p << endl; 150 | cout << "--------------------------" << endl; 151 | } 152 | 153 | } 154 | 155 | prev_clk = clk; 156 | 157 | 158 | // Apply Changes 159 | 160 | uint32_t* tx_fid_tmp_ptr = (uint32_t*)(tx_fifo->r_data); 161 | uint32_t tx_fid_tmp = *tx_fid_tmp_ptr; 162 | tx_fid_in = tx_val ? tx_fid_tmp : FLOW_ID_NONE; 163 | // FIXME:delete next_fid_in_ptr; 164 | } 165 | 166 | ostream & operator << (ostream &out, const CwndCREngine::Context &c) 167 | { 168 | out << "ready to tx: " << c.ready_to_tx << endl 169 | << "pkt queue head: " << (c.pkt_queue.empty() ? FLOW_SEQ_NONE : c.pkt_queue.front()) << endl 170 | << "pkt queue size: " << c.pkt_queue.size() << endl; 171 | 172 | 173 | return out; 174 | } 175 | 176 | 177 | -------------------------------------------------------------------------------- /csim/cr_engine/cwnd_cr_engine.h: -------------------------------------------------------------------------------- 1 | #ifndef CWND_CR_ENGINE__H 2 | #define CWND_CR_ENGINE__H 3 | 4 | #include "cr_engine.h" 5 | #include "../fifo/fifo2w.h" 6 | 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | class CwndCREngine : public CREngine { 13 | public: 14 | CwndCREngine(uint32_t); 15 | 16 | void eval(); 17 | 18 | struct Context{ 19 | bool ready_to_tx; 20 | queue pkt_queue; 21 | 22 | friend ostream & operator << (ostream &out, const CwndCREngine::Context &c); 23 | }; 24 | 25 | private: 26 | uint32_t flow_cnt = 0; 27 | map ram; 28 | Fifo2W* tx_fifo; 29 | uint32_t none_elem = FLOW_ID_NONE; 30 | 31 | uint8_t prev_clk = 0; 32 | 33 | uint32_t *queue_w_data_0; 34 | uint32_t *queue_w_data_1; 35 | 36 | uint32_t tx_fid_in = FLOW_ID_NONE; 37 | 38 | uint32_t enq_fid_p = FLOW_ID_NONE; 39 | uint32_t tx_fid_p = FLOW_ID_NONE; 40 | uint32_t enq_seq_p = FLOW_SEQ_NONE; 41 | 42 | uint32_t enq_fid_l = FLOW_ID_NONE; 43 | uint32_t tx_fid_l = FLOW_ID_NONE; 44 | uint32_t enq_seq_l = FLOW_SEQ_NONE; 45 | 46 | uint32_t tx_enq_fid1 = FLOW_ID_NONE; 47 | uint32_t tx_enq_fid2 = FLOW_ID_NONE; 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /csim/dd_engine/dd_engine.h: -------------------------------------------------------------------------------- 1 | #ifndef DD_ENGINE__H 2 | #define DD_ENGINE__H 3 | 4 | #include "system_defs.h" 5 | #include "../fifo/fifo4w.h" 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | class DDEngine{ 12 | public: 13 | 14 | // Inputs 15 | 16 | uint8_t clk; 17 | uint8_t rst_n; 18 | 19 | uint32_t dp_fid_in; 20 | uint32_t cr_cntxt_in; 21 | 22 | uint32_t incoming_fid_in; 23 | PktType pkt_type_in; 24 | PktData pkt_data_in; 25 | 26 | // Outputs 27 | 28 | uint32_t next_seq_fid_out; 29 | uint32_t next_seq_out; 30 | uint8_t next_seq_tx_id_out; 31 | 32 | uint8_t timeout_val_out; 33 | uint32_t timeout_fid_out; 34 | 35 | uint32_t dd_cntxt_out; 36 | 37 | DDEngine(uint32_t); 38 | void eval(); 39 | 40 | struct Context1{ 41 | uint32_t next_new; 42 | uint32_t wnd_start; 43 | set acked_wnd; 44 | uint32_t wnd_size; 45 | 46 | friend ostream & operator << (ostream &out, const DDEngine::Context1 &c); 47 | }; 48 | 49 | struct Context2{ 50 | set rtx_wnd; 51 | uint8_t idle; 52 | uint8_t back_pressure; 53 | uint32_t pkt_queue_size; 54 | uint32_t rtx_exptime; 55 | uint8_t active_rtx_timer; 56 | uint32_t rtx_timer_amnt; 57 | void * user_cntxt; 58 | 59 | friend ostream & operator << (ostream &out, const DDEngine::Context2 &c); 60 | }; 61 | 62 | struct NewRenoContext{ 63 | uint32_t prev_hgst_ack; 64 | bool in_recovery; 65 | uint32_t recover; 66 | bool in_timeout; 67 | uint32_t wnd_inc_cntr; 68 | uint32_t ss_thresh; 69 | uint32_t dup_acks; 70 | }; 71 | 72 | private: 73 | uint32_t flow_cnt = 0; 74 | map ram1; 75 | map ram2; 76 | Fifo4W* non_idle; 77 | uint32_t none_elem = FLOW_ID_NONE; 78 | 79 | uint8_t prev_clk = 0; 80 | 81 | uint32_t *next_enq_fid1_q; 82 | uint32_t *next_enq_fid2_q; 83 | uint32_t *next_enq_fid3_q; 84 | uint32_t *next_enq_fid4_q; 85 | 86 | uint32_t cack_in = FLOW_SEQ_NONE; 87 | uint32_t sack_in = FLOW_SEQ_NONE; 88 | uint32_t sack_tx_id_in = 0; 89 | 90 | uint32_t next_fid_in = FLOW_ID_NONE; 91 | uint32_t inc0_fid_in = FLOW_ID_NONE; 92 | uint32_t inc1_fid_in = FLOW_ID_NONE; 93 | uint32_t timeout_fid_in = FLOW_ID_NONE; 94 | 95 | uint32_t inc1_cack = FLOW_SEQ_NONE; 96 | uint32_t inc1_sack = FLOW_SEQ_NONE; 97 | uint32_t inc1_sack_tx_id = 0; 98 | 99 | uint32_t inc1_new_c_acks_cnt = 0; 100 | uint8_t inc1_valid_sack = 0; 101 | uint32_t inc1_old_wnd_start = 0; 102 | PktType inc1_pkt_type = NONE_PKT; 103 | 104 | uint32_t next_fid_p = FLOW_ID_NONE; 105 | uint32_t inc0_fid_p = FLOW_ID_NONE; 106 | uint32_t inc1_fid_p = FLOW_ID_NONE; 107 | uint32_t timeout_fid_p = FLOW_ID_NONE; 108 | uint32_t dp_fid_p = FLOW_ID_NONE; 109 | 110 | uint32_t cack_p = FLOW_SEQ_NONE; 111 | uint32_t sack_p = FLOW_SEQ_NONE; 112 | uint32_t sack_tx_id_p = 0; 113 | PktType pkt_type_p = NONE_PKT; 114 | 115 | uint32_t next_fid_l = FLOW_ID_NONE; 116 | uint32_t inc0_fid_l = FLOW_ID_NONE; 117 | uint32_t inc1_fid_l = FLOW_ID_NONE; 118 | uint32_t timeout_fid_l = FLOW_ID_NONE; 119 | uint32_t dp_fid_l = FLOW_ID_NONE; 120 | 121 | uint32_t cack_l = FLOW_SEQ_NONE; 122 | uint32_t sack_l = FLOW_SEQ_NONE; 123 | uint32_t sack_tx_id_l = 0; 124 | PktType pkt_type_l = NONE_PKT; 125 | 126 | uint64_t global_time = 0; 127 | 128 | uint32_t next_enq_fid1 = FLOW_ID_NONE; 129 | uint32_t next_enq_fid2 = FLOW_ID_NONE; 130 | uint32_t next_enq_fid3 = FLOW_ID_NONE; 131 | uint32_t next_enq_fid4 = FLOW_ID_NONE; 132 | 133 | uint32_t inc0_new_c_acks_cnt = 0; 134 | uint8_t inc0_valid_sack = 0; 135 | uint32_t inc0_old_wnd_start = 0; 136 | 137 | bool inc1_reset_rtx_timer = false; 138 | 139 | }; 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /csim/fifo/fifo1w.cc: -------------------------------------------------------------------------------- 1 | #include "fifo1w.h" 2 | 3 | Fifo1W::Fifo1W(int max_size, void* none_elem){ 4 | this->max_size = max_size; 5 | this->none_elem = none_elem; 6 | }; 7 | 8 | void Fifo1W::eval (){ 9 | 10 | // Positive Edge of the Clock 11 | if (prev_clk == 0 && 12 | clk == 1){ 13 | if (r_val && !elems.empty()) elems.pop(); 14 | if (w_val && elems.size() < max_size && 15 | !(elems.empty() && r_val)) elems.push(w_data); 16 | 17 | } 18 | 19 | prev_clk = clk; 20 | 21 | bool empty_queue = elems.empty(); 22 | if (empty_queue && w_val) r_data = w_data; 23 | else if (empty_queue) r_data = none_elem; 24 | else r_data = elems.front(); 25 | 26 | full = elems.size() >= max_size; 27 | data_avail = !empty_queue || (empty_queue & w_val); 28 | } 29 | -------------------------------------------------------------------------------- /csim/fifo/fifo1w.h: -------------------------------------------------------------------------------- 1 | #ifndef FIFO1W_H 2 | #define FIFO1W_H 3 | 4 | #include 5 | #include "system_defs.h" 6 | 7 | using namespace std; 8 | 9 | class Fifo1W{ 10 | public: 11 | // Inputs 12 | 13 | uint8_t clk; 14 | uint8_t rst_n; 15 | 16 | uint8_t w_val; 17 | void* w_data; 18 | 19 | uint8_t r_val; 20 | 21 | // Outputs 22 | 23 | void* r_data; 24 | uint32_t size; 25 | uint8_t full; 26 | uint8_t data_avail; 27 | 28 | Fifo1W(int, void*); 29 | 30 | void eval(); 31 | 32 | private: 33 | queue elems; 34 | uint32_t max_size; 35 | void* none_elem; 36 | 37 | // clock 38 | uint8_t prev_clk; 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /csim/fifo/fifo2w.cc: -------------------------------------------------------------------------------- 1 | #include "fifo2w.h" 2 | 3 | #include 4 | using namespace std; 5 | 6 | Fifo2W::Fifo2W(int max_size, void* none_elem){ 7 | this->max_size = max_size; 8 | this->none_elem = none_elem; 9 | }; 10 | 11 | void Fifo2W::eval (){ 12 | 13 | uint8_t srtd_w_val_0, srtd_w_val_1; 14 | void *srtd_w_data_0, *srtd_w_data_1; 15 | 16 | srtd_w_val_0 = w_val_0 || w_val_1; 17 | srtd_w_val_1 = w_val_0 && w_val_1; 18 | 19 | srtd_w_data_0 = w_val_0 ? w_data_0 : w_data_1; 20 | srtd_w_data_1 = w_data_1; 21 | 22 | bool was_empty = elems.empty(); 23 | // Positive Edge of the Clock 24 | if (prev_clk == 0 && 25 | clk == 1){ 26 | if (rst_n){ 27 | if (DEBUG){ 28 | cout << (int)srtd_w_val_0 << " " << *(uint32_t*)srtd_w_data_0 << endl; 29 | cout << (int)srtd_w_val_1 << " " << *(uint32_t*)srtd_w_data_1 << endl; 30 | } 31 | bool was_empty = elems.empty(); 32 | if (r_val && !elems.empty()) elems.pop(); 33 | if (srtd_w_val_0 && elems.size() < max_size && 34 | !(was_empty && r_val)) elems.push(srtd_w_data_0); 35 | 36 | if (srtd_w_val_1 && elems.size() < max_size) elems.push(srtd_w_data_1); 37 | } 38 | } 39 | 40 | prev_clk = clk; 41 | 42 | bool empty_queue = elems.empty(); 43 | if (was_empty && srtd_w_val_0) r_data = srtd_w_data_0; 44 | else if (empty_queue) r_data = none_elem; 45 | else r_data = elems.front(); 46 | 47 | size = elems.size(); 48 | full = elems.size() >= max_size; 49 | data_avail = !empty_queue || (empty_queue & srtd_w_val_0); 50 | } 51 | 52 | void Fifo2W::init_enq(void* elem){ 53 | elems.push(elem); 54 | } 55 | -------------------------------------------------------------------------------- /csim/fifo/fifo2w.h: -------------------------------------------------------------------------------- 1 | #ifndef FIFO2W_H 2 | #define FIFO2W_H 3 | 4 | #include 5 | #include "system_defs.h" 6 | 7 | using namespace std; 8 | 9 | class Fifo2W{ 10 | public: 11 | // Inputs 12 | 13 | uint8_t clk; 14 | uint8_t rst_n; 15 | 16 | uint8_t w_val_0; 17 | void* w_data_0; 18 | 19 | uint8_t w_val_1; 20 | void* w_data_1; 21 | 22 | uint8_t r_val; 23 | 24 | // Outputs 25 | 26 | void* r_data; 27 | uint32_t size; 28 | uint8_t full; 29 | uint8_t data_avail; 30 | 31 | Fifo2W(int, void*); 32 | 33 | void eval(); 34 | void init_enq(void*); 35 | 36 | private: 37 | queue elems; 38 | uint32_t max_size; 39 | void* none_elem; 40 | 41 | // clock 42 | uint8_t prev_clk; 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /csim/fifo/fifo4w.cc: -------------------------------------------------------------------------------- 1 | #include "fifo4w.h" 2 | 3 | #include 4 | using namespace std; 5 | 6 | Fifo4W::Fifo4W(int max_size, void* none_elem){ 7 | this->max_size = max_size; 8 | this->none_elem = none_elem; 9 | }; 10 | 11 | void Fifo4W::eval (){ 12 | 13 | uint8_t srtd_w_val_0, srtd_w_val_1, srtd_w_val_2, srtd_w_val_3; 14 | void *srtd_w_data_0, *srtd_w_data_1, *srtd_w_data_2, *srtd_w_data_3; 15 | 16 | srtd_w_val_0 = w_val_0 || w_val_1 || w_val_2 || w_val_3; 17 | 18 | srtd_w_val_1 = ((w_val_0 && w_val_1) || (w_val_0 && w_val_2) | 19 | (w_val_0 && w_val_3) || (w_val_1 && w_val_2) | 20 | (w_val_1 && w_val_3) || (w_val_2 && w_val_3)); 21 | srtd_w_val_2 = ((w_val_0 && w_val_1 && w_val_2) || (w_val_0 && w_val_1 && w_val_3) | 22 | (w_val_0 && w_val_2 && w_val_3) || (w_val_1 && w_val_2 && w_val_3)); 23 | srtd_w_val_3 = (w_val_0 && w_val_1 && w_val_2 && w_val_3); 24 | 25 | srtd_w_data_0 = w_val_0 ? w_data_0 : 26 | w_val_1 ? w_data_1 : 27 | w_val_2 ? w_data_2 : 28 | w_data_3; 29 | 30 | srtd_w_data_1 = (w_val_1 && w_val_0) ? w_data_1: 31 | (w_val_2 && (w_val_1 || w_val_0)) ? w_data_2: w_data_3; 32 | 33 | srtd_w_data_2 = (w_val_0 && w_val_1 && w_val_2) ? w_data_2: w_data_3; 34 | 35 | srtd_w_data_3 = w_data_3; 36 | 37 | bool was_empty = elems.empty(); 38 | // Positive Edge of the Clock 39 | if (prev_clk == 0 && 40 | clk == 1){ 41 | if (rst_n){ 42 | if (DEBUG){ 43 | cout << (int)srtd_w_val_0 << " " << *(uint32_t*)srtd_w_data_0 << endl; 44 | cout << (int)srtd_w_val_1 << " " << *(uint32_t*)srtd_w_data_1 << endl; 45 | cout << (int)srtd_w_val_2 << " " << *(uint32_t*)srtd_w_data_2 << endl; 46 | cout << (int)srtd_w_val_3 << " " << *(uint32_t*)srtd_w_data_3 << endl; 47 | } 48 | bool was_empty = elems.empty(); 49 | if (r_val && !elems.empty()) elems.pop(); 50 | if (srtd_w_val_0 && elems.size() < max_size && 51 | !(was_empty && r_val)) elems.push(srtd_w_data_0); 52 | 53 | if (srtd_w_val_1 && elems.size() < max_size) elems.push(srtd_w_data_1); 54 | if (srtd_w_val_2 && elems.size() < max_size) elems.push(srtd_w_data_2); 55 | if (srtd_w_val_3 && elems.size() < max_size) elems.push(srtd_w_data_3); 56 | } 57 | } 58 | 59 | prev_clk = clk; 60 | 61 | bool empty_queue = elems.empty(); 62 | if (was_empty && srtd_w_val_0) r_data = srtd_w_data_0; 63 | else if (empty_queue) r_data = none_elem; 64 | else r_data = elems.front(); 65 | 66 | size = elems.size(); 67 | full = elems.size() >= max_size; 68 | data_avail = !empty_queue || (empty_queue & srtd_w_val_0); 69 | } 70 | 71 | void Fifo4W::init_enq(void* elem){ 72 | elems.push(elem); 73 | } 74 | -------------------------------------------------------------------------------- /csim/fifo/fifo4w.h: -------------------------------------------------------------------------------- 1 | #ifndef FIFO4W_H 2 | #define FIFO4W_H 3 | 4 | #include 5 | #include "system_defs.h" 6 | 7 | using namespace std; 8 | 9 | class Fifo4W{ 10 | public: 11 | // Inputs 12 | 13 | uint8_t clk; 14 | uint8_t rst_n; 15 | 16 | uint8_t w_val_0; 17 | void* w_data_0; 18 | 19 | uint8_t w_val_1; 20 | void* w_data_1; 21 | 22 | uint8_t w_val_2; 23 | void* w_data_2; 24 | 25 | uint8_t w_val_3; 26 | void* w_data_3; 27 | 28 | uint8_t r_val; 29 | 30 | // Outputs 31 | 32 | void* r_data; 33 | uint32_t size; 34 | uint8_t full; 35 | uint8_t data_avail; 36 | 37 | Fifo4W(int, void*); 38 | 39 | void eval(); 40 | void init_enq(void*); 41 | 42 | private: 43 | queue elems; 44 | uint32_t max_size; 45 | void* none_elem; 46 | 47 | // clock 48 | uint8_t prev_clk; 49 | }; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /csim/main.cc: -------------------------------------------------------------------------------- 1 | #include "system_defs.h" 2 | #include "tonic.h" 3 | #include "receiver/nreno_receiver.h" 4 | #include "cr_engine/cwnd_cr_engine.h" 5 | #include "dd_engine/dd_engine.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define NDEBUG 14 | #include 15 | 16 | using namespace std; 17 | 18 | const uint32_t REF_FLOW_ID_NONE = 1023; 19 | 20 | class TonicTestBench{ 21 | public: 22 | 23 | TonicTestBench(uint32_t flow_cnt, 24 | uint32_t loss_cnt_in_1000, 25 | uint32_t rtt, 26 | uint32_t sim_cycles){ 27 | this->flow_cnt = flow_cnt; 28 | this->sim_cycles = sim_cycles; 29 | 30 | CREngine* cr_engine = new CwndCREngine(flow_cnt); 31 | DDEngine* dd_engine = new DDEngine(flow_cnt); 32 | 33 | tonic = new Tonic(dd_engine, cr_engine); 34 | 35 | receiver = new NewRenoReceiver(flow_cnt, 36 | loss_cnt_in_1000, 37 | rtt); 38 | 39 | src_fname = "refs/" + to_string(loss_cnt_in_1000) + "/src.txt"; 40 | sink_fname = "refs/" + to_string(loss_cnt_in_1000) + "/sink.txt"; 41 | } 42 | 43 | 44 | void run(){ 45 | reset(); 46 | tonic->link_avail = 1; 47 | 48 | ReceiverResp resp; 49 | 50 | // open refs 51 | ifstream src_file(src_fname); 52 | ifstream sink_file(sink_fname); 53 | 54 | for (int i = 0; i < sim_cycles; i++){ 55 | if (PRINT_TRACE){ 56 | cout << "####################################" << endl; 57 | cout << "Time " << i << endl; 58 | print_input(); 59 | } 60 | 61 | // check input with ref 62 | uint32_t ref_incoming_fid; 63 | uint32_t ref_pkt_type_int; 64 | string ref_pkt_data_str; 65 | 66 | src_file >> ref_incoming_fid >> ref_pkt_type_int >> ref_pkt_data_str; 67 | 68 | if (PRINT_TRACE){ 69 | cout << "ref in " << ref_incoming_fid << " " << ref_pkt_type_int << " " << 70 | stoi(ref_pkt_data_str.substr(0, 32), nullptr, 2) << endl; 71 | } 72 | 73 | if (ref_incoming_fid != REF_FLOW_ID_NONE){ 74 | assert(ref_incoming_fid == tonic->incoming_fid_in); 75 | 76 | // convert pkt_type 77 | PktType ref_pkt_type = ref_pkt_type_int < 4 ? ref_pkt_types[ref_pkt_type_int] : NONE_PKT; 78 | 79 | assert(ref_pkt_type == tonic->pkt_type_in); 80 | 81 | if (ref_pkt_type == CACK_PKT){ 82 | string cack_str = ref_pkt_data_str.substr(0, 32); 83 | assert(stoi(cack_str, nullptr, 2) == tonic->pkt_data_in.cack_pkt.cack); 84 | } 85 | } 86 | else{ 87 | assert(tonic->incoming_fid_in == FLOW_ID_NONE); 88 | } 89 | 90 | // calculate tonic output 91 | tick(); 92 | 93 | if (PRINT_TRACE){ 94 | print_output(); 95 | } 96 | 97 | // check output with ref 98 | uint32_t ref_next_val; 99 | uint32_t ref_next_seq_fid_out; 100 | uint32_t ref_next_seq_out; 101 | uint32_t ref_next_seq_tx_id_out; 102 | 103 | sink_file >> ref_next_val >> ref_next_seq_fid_out >> ref_next_seq_out >> ref_next_seq_tx_id_out; 104 | 105 | if (PRINT_TRACE){ 106 | cout << "ref out " << ref_next_seq_fid_out << " " << ref_next_seq_out << endl; 107 | } 108 | 109 | assert(ref_next_val == tonic->next_val); 110 | if (ref_next_val){ 111 | assert(ref_next_seq_fid_out == tonic->next_seq_fid_out); 112 | assert(ref_next_seq_out == tonic->next_seq_out); 113 | } 114 | 115 | receiver->tick_clk(); 116 | if (tonic->next_val){ 117 | receiver->receive(tonic->next_seq_fid_out, 118 | tonic->next_seq_out, 119 | tonic->next_seq_tx_id_out); 120 | } 121 | 122 | receiver->transmit(resp); 123 | tonic->incoming_fid_in = resp.fid; 124 | tonic->pkt_type_in = resp.pkt_type; 125 | tonic->pkt_data_in = resp.pkt_data; 126 | 127 | } 128 | 129 | src_file.close(); 130 | sink_file.close(); 131 | } 132 | 133 | private: 134 | Tonic* tonic; 135 | Receiver* receiver; 136 | 137 | uint32_t flow_cnt; 138 | uint32_t sim_cycles; 139 | 140 | PktType ref_pkt_types[4] = {SACK_PKT, PULL_PKT, NACK_PKT, CACK_PKT}; 141 | 142 | string src_fname, sink_fname; 143 | 144 | void reset(){ 145 | tonic->rst_n = 0; 146 | tonic->incoming_fid_in = FLOW_ID_NONE; 147 | tonic->pkt_type_in = NONE_PKT; 148 | tick(); 149 | tonic->rst_n = 1; 150 | } 151 | 152 | void tick(){ 153 | tonic->clk = 0; 154 | tonic->eval(); 155 | 156 | tonic->clk = 1; 157 | tonic->eval(); 158 | } 159 | 160 | string pkt_type_str(PktType type){ 161 | string res = type == SACK_PKT ? "SACK" : 162 | type == PULL_PKT ? "PULL" : 163 | type == NACK_PKT ? "NACK" : 164 | type == CACK_PKT ? "CACK" : 165 | type == NONE_PKT ? "NONE" : 166 | "UDEF"; 167 | return res; 168 | } 169 | 170 | string pkt_data_str(PktType type, PktData data){ 171 | stringstream ss; 172 | if (type == CACK_PKT){ 173 | ss << data.cack_pkt.cack; 174 | } 175 | return ss.str(); 176 | } 177 | 178 | void print_input(){ 179 | cout << "pkt in " << tonic->incoming_fid_in << " " 180 | << pkt_type_str(tonic->pkt_type_in) << " " 181 | << pkt_data_str(tonic->pkt_type_in, 182 | tonic->pkt_data_in) << endl; 183 | } 184 | 185 | void print_output(){ 186 | if (tonic->next_val){ 187 | cout << "pkt out " << tonic->next_seq_fid_out << " " << 188 | tonic->next_seq_out << " " << 189 | (int)tonic->next_seq_tx_id_out << endl; 190 | } 191 | else{ 192 | cout << "pkt out NONE" << endl; 193 | } 194 | } 195 | 196 | }; 197 | 198 | int main(){ 199 | srand(123456789); 200 | uint32_t flow_cnt = 4; 201 | uint32_t rtt = 30; 202 | uint32_t loss_cnt_in_1000 = 300; 203 | uint32_t sim_cycles = 100000; 204 | 205 | TonicTestBench tb(flow_cnt, 206 | loss_cnt_in_1000, 207 | rtt, 208 | sim_cycles); 209 | tb.run(); 210 | 211 | return 0; 212 | } 213 | -------------------------------------------------------------------------------- /csim/receiver/nreno_receiver.h: -------------------------------------------------------------------------------- 1 | #ifndef NEW_RENO_RECEIVER__H 2 | #define NEW_RENO_RECEIVER__H 3 | 4 | #include "receiver.h" 5 | #include 6 | 7 | using namespace std; 8 | 9 | class NewRenoReceiver: public Receiver{ 10 | public: 11 | NewRenoReceiver(uint32_t flow_cnt, 12 | uint32_t loss_cnt_in_1000, 13 | uint32_t rtt) : Receiver(flow_cnt, 14 | loss_cnt_in_1000, 15 | rtt){} 16 | 17 | void receiver_resp(uint32_t fid, uint32_t cack, 18 | uint32_t sack, uint8_t sack_tx_id, 19 | ReceiverResp& resp){ 20 | resp.fid = fid; 21 | resp.pkt_type = CACK_PKT; 22 | resp.pkt_data.cack_pkt.cack = cack; 23 | } 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /csim/receiver/receiver.cc: -------------------------------------------------------------------------------- 1 | #include "receiver.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | Receiver::Receiver(uint32_t flow_cnt, 9 | uint32_t loss_cnt_in_1000, 10 | uint32_t rtt){ 11 | this->flow_cnt = flow_cnt; 12 | rcvd = new SlidingWindow[flow_cnt]; 13 | loss_prob = loss_cnt_in_1000 / 1000.0; 14 | this->rtt = rtt; 15 | time_in_ns = 0; 16 | } 17 | 18 | void Receiver::tick_clk(){ 19 | time_in_ns += CYCLE_IN_NS; 20 | } 21 | 22 | void Receiver::transmit(ReceiverResp& resp) { 23 | resp.fid = FLOW_ID_NONE; 24 | resp.pkt_type = NONE_PKT; 25 | 26 | 27 | if (!ack_queue.empty()){ 28 | AckQueueElement ack = ack_queue.top(); 29 | if (ack.rcvd_time <= time_in_ns){ 30 | receiver_resp(ack.fid, 31 | ack.cumulative_ack, 32 | ack.selective_ack, ack.sack_tx_id, resp); 33 | ack_queue.pop(); 34 | } 35 | } 36 | 37 | if (DEBUG){ 38 | cout << time_in_ns << " transmitted " << resp.fid << " " << 39 | resp.pkt_data.cack_pkt.cack << endl; 40 | } 41 | } 42 | 43 | 44 | void Receiver::receive(uint32_t next_seq_fid, 45 | uint32_t next_seq, 46 | uint8_t next_seq_tx_id) { 47 | 48 | if (DEBUG){ 49 | cout << time_in_ns << " received " << next_seq_fid << " " << 50 | next_seq << " " << endl; 51 | } 52 | if (next_seq_fid > 0 && 53 | next_seq_fid <= flow_cnt){ 54 | double r = (double)rand() / (double)RAND_MAX; 55 | if (r > loss_prob){ 56 | rcvd[next_seq_fid-1].ack(next_seq); 57 | 58 | AckQueueElement new_ack; 59 | new_ack.fid = next_seq_fid; 60 | new_ack.cumulative_ack = rcvd[next_seq_fid-1].get_cack(); 61 | new_ack.selective_ack = next_seq; 62 | new_ack.sack_tx_id = next_seq_tx_id; 63 | new_ack.rcvd_time = time_in_ns + rtt; 64 | ack_queue.push(new_ack); 65 | } 66 | else{ 67 | if (PRINT_TRACE){ 68 | cout << "dropped " << next_seq_fid << " " << next_seq << endl; 69 | } 70 | } 71 | } 72 | else{ 73 | } 74 | 75 | } 76 | 77 | -------------------------------------------------------------------------------- /csim/receiver/receiver.h: -------------------------------------------------------------------------------- 1 | #ifndef RECEIVER_H 2 | #define RECEIVER_H 3 | 4 | #include 5 | #include "system_defs.h" 6 | #include "sliding_window.h" 7 | 8 | using namespace std; 9 | 10 | struct ReceiverResp{ 11 | uint32_t fid; 12 | PktType pkt_type; 13 | PktData pkt_data; 14 | }; 15 | 16 | class Receiver{ 17 | public: 18 | Receiver(uint32_t, uint32_t, uint32_t); 19 | 20 | void tick_clk(); 21 | 22 | 23 | void transmit(ReceiverResp&); 24 | void receive(uint32_t, uint32_t, uint8_t); 25 | virtual void receiver_resp(uint32_t, uint32_t, 26 | uint32_t, uint8_t, ReceiverResp&) = 0; 27 | 28 | 29 | private: 30 | struct AckQueueElement { 31 | uint32_t fid; 32 | uint32_t cumulative_ack; 33 | uint32_t selective_ack; 34 | uint8_t sack_tx_id; 35 | uint64_t rcvd_time; 36 | 37 | bool operator<(const AckQueueElement& rhs) const{ 38 | return rcvd_time > rhs.rcvd_time; 39 | } 40 | }; 41 | 42 | uint32_t flow_cnt; 43 | float loss_prob; 44 | uint32_t rtt; 45 | 46 | uint64_t time_in_ns; 47 | 48 | priority_queue ack_queue; 49 | 50 | SlidingWindow* rcvd; 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /csim/receiver/sliding_window.cc: -------------------------------------------------------------------------------- 1 | #include "sliding_window.h" 2 | #include "../utils/util.h" 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | SlidingWindow::SlidingWindow(){ 9 | head = 0; 10 | } 11 | 12 | void SlidingWindow::ack(uint32_t ack_seq){ 13 | if (ack_seq < head) return; 14 | 15 | elems.insert(ack_seq); 16 | set::iterator it = elems.begin(); 17 | 18 | while(*it == head && it != elems.end()){ 19 | head++; 20 | it++; 21 | } 22 | elems.erase(elems.begin(), it); 23 | } 24 | 25 | uint32_t SlidingWindow::get_cack(){ 26 | return head; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /csim/receiver/sliding_window.h: -------------------------------------------------------------------------------- 1 | #ifndef SLIDING_WINDOW__H 2 | #define SLIDING_WINDOW__H 3 | 4 | #include 5 | #include "system_defs.h" 6 | 7 | using namespace std; 8 | 9 | class SlidingWindow{ 10 | public: 11 | SlidingWindow(); 12 | 13 | void ack(uint32_t); 14 | uint32_t get_cack(); 15 | 16 | private: 17 | set elems; 18 | uint32_t head; 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /csim/tonic.cc: -------------------------------------------------------------------------------- 1 | #include "tonic.h" 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | Tonic::Tonic(DDEngine* dd_engine, CREngine* cr_engine){ 8 | this->dd_engine = dd_engine; 9 | this->cr_engine = cr_engine; 10 | 11 | OutQElem* none_elem = new OutQElem(); 12 | none_elem->fid = FLOW_ID_NONE; 13 | outq = new Fifo1W(OUTQ_MAX_SIZE, none_elem); 14 | } 15 | 16 | void Tonic::eval(){ 17 | 18 | // DD Engine 19 | dd_engine->clk = clk; 20 | dd_engine->rst_n = rst_n; 21 | 22 | dd_engine->dp_fid_in = dd_dp_fid; 23 | dd_engine->cr_cntxt_in = dd_cr_cntxt; 24 | 25 | uint32_t dd_incoming_fid = (pkt_type_in == SACK_PKT || 26 | pkt_type_in == CACK_PKT || 27 | pkt_type_in == NACK_PKT) ? incoming_fid_in : FLOW_ID_NONE; 28 | 29 | dd_engine->incoming_fid_in = dd_incoming_fid; 30 | dd_engine->pkt_type_in = pkt_type_in; 31 | dd_engine->pkt_data_in = pkt_data_in; 32 | 33 | dd_engine->eval(); 34 | 35 | 36 | // CR Engine 37 | cr_engine->clk = clk; 38 | cr_engine->rst_n = rst_n; 39 | 40 | cr_engine->enq_fid_in = cr_enq_fid; 41 | cr_engine->enq_seq_in = cr_enq_seq; 42 | cr_engine->enq_seq_tx_id_in = cr_enq_seq_tx_id; 43 | 44 | cr_engine->dd_cntxt_in = cr_dd_cntxt; 45 | 46 | uint32_t cr_incoming_fid = (pkt_type_in == PULL_PKT) ? incoming_fid_in : FLOW_ID_NONE; 47 | cr_engine->incoming_fid_in = cr_incoming_fid; 48 | cr_engine->pkt_type_in = pkt_type_in; 49 | cr_engine->pkt_data_in = pkt_data_in; 50 | 51 | uint32_t timeout_fid = cr_timeout_val ? cr_timeout_fid : FLOW_ID_NONE; 52 | cr_engine->timeout_fid_in = timeout_fid; 53 | 54 | cr_engine->tx_val = tx_val; 55 | 56 | cr_engine->eval(); 57 | 58 | // Fifo 59 | 60 | outq->clk = clk; 61 | outq->rst_n = rst_n; 62 | 63 | uint8_t outq_w_val = tonic_next_seq_fid != FLOW_ID_NONE; 64 | outq->w_val = outq_w_val; 65 | 66 | if (outq_w_val){ 67 | OutQElem* outq_w_data = new OutQElem(); 68 | outq_w_data->fid = tonic_next_seq_fid; 69 | outq_w_data->seq = tonic_next_seq; 70 | outq_w_data->tx_id = tonic_next_seq_tx_id; 71 | 72 | outq->w_data = outq_w_data; 73 | } 74 | else{ 75 | outq->w_data = 0; 76 | } 77 | 78 | outq->r_val = link_avail; 79 | 80 | outq->eval(); 81 | 82 | // Clock Positive Edge 83 | if (prev_clk == 0 && 84 | clk == 1) { 85 | if (!rst_n){ 86 | 87 | // Enq Fid 88 | enq_fid_0 = FLOW_ID_NONE; 89 | enq_fid_1 = FLOW_ID_NONE; 90 | enq_fid_2 = FLOW_ID_NONE; 91 | enq_fid_3 = FLOW_ID_NONE; 92 | cr_enq_fid = FLOW_ID_NONE; 93 | 94 | // Enq Seq 95 | enq_seq_0 = FLOW_SEQ_NONE; 96 | enq_seq_1 = FLOW_SEQ_NONE; 97 | enq_seq_2 = FLOW_SEQ_NONE; 98 | enq_seq_3 = FLOW_SEQ_NONE; 99 | cr_enq_seq = FLOW_SEQ_NONE; 100 | 101 | // TX ID 102 | enq_seq_tx_id_0 = 0; 103 | enq_seq_tx_id_1 = 0; 104 | enq_seq_tx_id_2 = 0; 105 | enq_seq_tx_id_3 = 0; 106 | cr_enq_seq_tx_id = 0; 107 | 108 | // Timeout Val 109 | timeout_val_0 = 0; 110 | timeout_val_1 = 0; 111 | timeout_val_2 = 0; 112 | timeout_val_3 = 0; 113 | cr_timeout_val = 0; 114 | 115 | // Timeout FID 116 | timeout_fid_0 = 0; 117 | timeout_fid_1 = 0; 118 | timeout_fid_2 = 0; 119 | timeout_fid_3 = 0; 120 | cr_timeout_fid = 0; 121 | 122 | // DD Context 123 | dd_cntxt_0 = 0; 124 | dd_cntxt_1 = 0; 125 | dd_cntxt_2 = 0; 126 | dd_cntxt_3 = 0; 127 | cr_dd_cntxt = 0; 128 | 129 | // DP FID 130 | dp_fid_0 = FLOW_ID_NONE; 131 | dp_fid_1 = FLOW_ID_NONE; 132 | dp_fid_2 = FLOW_ID_NONE; 133 | dp_fid_3 = FLOW_ID_NONE; 134 | dd_dp_fid = FLOW_ID_NONE; 135 | 136 | // CR Context 137 | cr_cntxt_0 = FLOW_ID_NONE; 138 | cr_cntxt_1 = FLOW_ID_NONE; 139 | cr_cntxt_2 = FLOW_ID_NONE; 140 | cr_cntxt_3 = FLOW_ID_NONE; 141 | dd_cr_cntxt = FLOW_ID_NONE; 142 | 143 | } 144 | else{ 145 | 146 | // Enq fid 147 | cr_enq_fid = enq_fid_3; 148 | enq_fid_3 = enq_fid_2; 149 | enq_fid_2 = enq_fid_1; 150 | enq_fid_1 = enq_fid_0; 151 | enq_fid_0 = dd_next_seq_fid; 152 | 153 | // Enq Seq 154 | cr_enq_seq = enq_seq_3; 155 | enq_seq_3 = enq_seq_2; 156 | enq_seq_2 = enq_seq_1; 157 | enq_seq_1 = enq_seq_0; 158 | enq_seq_0 = dd_next_seq; 159 | 160 | // TX ID 161 | cr_enq_seq_tx_id = enq_seq_tx_id_3; 162 | enq_seq_tx_id_3 = enq_seq_tx_id_2; 163 | enq_seq_tx_id_2 = enq_seq_tx_id_1; 164 | enq_seq_tx_id_1 = enq_seq_tx_id_0; 165 | enq_seq_tx_id_0 = dd_next_seq_tx_id; 166 | 167 | // Timeout Val 168 | cr_timeout_val = timeout_val_3; 169 | timeout_val_3 = timeout_val_2; 170 | timeout_val_2 = timeout_val_1; 171 | timeout_val_1 = timeout_val_0; 172 | timeout_val_0 = dd_timeout_val; 173 | 174 | // Timeout Fid 175 | cr_timeout_fid = timeout_fid_3; 176 | timeout_fid_3 = timeout_fid_2; 177 | timeout_fid_2 = timeout_fid_1; 178 | timeout_fid_1 = timeout_fid_0; 179 | timeout_fid_0 = dd_timeout_fid; 180 | 181 | // DD Context 182 | cr_dd_cntxt = dd_cntxt_3; 183 | dd_cntxt_3 = dd_cntxt_2; 184 | dd_cntxt_2 = dd_cntxt_1; 185 | dd_cntxt_1 = dd_cntxt_0; 186 | dd_cntxt_0 = dd_cntxt; 187 | 188 | // DP FID 189 | dd_dp_fid = dp_fid_3; 190 | dp_fid_3 = dp_fid_2; 191 | dp_fid_2 = dp_fid_1; 192 | dp_fid_1 = dp_fid_0; 193 | dp_fid_0 = cr_dp_fid; 194 | 195 | // CR Context 196 | dd_cr_cntxt = cr_cntxt_3; 197 | cr_cntxt_3 = cr_cntxt_2; 198 | cr_cntxt_2 = cr_cntxt_1; 199 | cr_cntxt_1 = cr_cntxt_0; 200 | cr_cntxt_0 = cr_cntxt; 201 | 202 | } 203 | 204 | if (DEBUG){ 205 | cout << "enq fid chain: " << enq_fid_0 << " " << enq_fid_1 << " " 206 | << enq_fid_2 << " " << enq_fid_3 << " " 207 | << cr_enq_fid << " " << endl; 208 | 209 | cout << "dp fid chain: " << dp_fid_0 << " " << dp_fid_1 << " " 210 | << dp_fid_2 << " " << dp_fid_3 << " " 211 | << dd_dp_fid << " " << endl; 212 | 213 | } 214 | } 215 | 216 | prev_clk = clk; 217 | 218 | //// Apply Changes 219 | 220 | // DD Engine 221 | dd_next_seq = dd_engine->next_seq_out; 222 | dd_next_seq_tx_id = dd_engine->next_seq_tx_id_out; 223 | dd_next_seq_fid = dd_engine->next_seq_fid_out; 224 | 225 | dd_timeout_val = dd_engine->timeout_val_out; 226 | dd_timeout_fid = dd_engine->timeout_fid_out; 227 | 228 | dd_cntxt = dd_engine->dd_cntxt_out; 229 | 230 | // CR Engine 231 | tonic_next_seq = cr_engine->next_seq_out; 232 | tonic_next_seq_tx_id = cr_engine->next_seq_tx_id_out; 233 | tonic_next_seq_fid = cr_engine->next_seq_fid_out; 234 | 235 | cr_dp_fid = cr_engine->dp_fid_out; 236 | cr_cntxt = cr_engine->cr_cntxt_out; 237 | 238 | // Fifo 239 | tx_val = outq->size < OUTQ_THRESH; 240 | OutQElem* outq_r_data = (struct OutQElem*) outq->r_data; 241 | 242 | next_seq_fid_out = outq_r_data->fid; 243 | next_seq_out = outq_r_data->seq; 244 | next_seq_tx_id_out = outq_r_data->tx_id; 245 | 246 | // TODO: delete the element? 247 | 248 | next_val = next_seq_fid_out != FLOW_ID_NONE; 249 | }; 250 | -------------------------------------------------------------------------------- /csim/tonic.h: -------------------------------------------------------------------------------- 1 | #ifndef TONIC_H 2 | #define TONIC_H 3 | 4 | #include "system_defs.h" 5 | #include "dd_engine/dd_engine.h" 6 | #include "cr_engine/cr_engine.h" 7 | #include "fifo/fifo1w.h" 8 | 9 | class Tonic{ 10 | public: 11 | 12 | // Inputs 13 | 14 | uint8_t clk; 15 | uint8_t rst_n; 16 | 17 | uint32_t incoming_fid_in; 18 | PktType pkt_type_in; 19 | PktData pkt_data_in; 20 | 21 | uint8_t link_avail; 22 | 23 | // Outputs 24 | uint8_t next_val; 25 | uint32_t next_seq_fid_out; 26 | uint32_t next_seq_out; 27 | uint8_t next_seq_tx_id_out; 28 | 29 | 30 | Tonic(DDEngine*, CREngine*); 31 | 32 | void eval(); 33 | 34 | private: 35 | 36 | // Engines 37 | DDEngine* dd_engine; 38 | CREngine* cr_engine; 39 | 40 | // Outgoing Queue 41 | Fifo1W* outq; 42 | 43 | // fifo elements 44 | struct OutQElem{ 45 | uint32_t fid; 46 | uint32_t seq; 47 | uint8_t tx_id; 48 | }; 49 | 50 | // clock 51 | uint32_t prev_clk; 52 | 53 | // DD Output 54 | uint32_t dd_next_seq; 55 | uint8_t dd_next_seq_tx_id; 56 | uint32_t dd_next_seq_fid; 57 | 58 | uint8_t dd_timeout_val; 59 | uint32_t dd_timeout_fid; 60 | 61 | uint32_t dd_cntxt; 62 | 63 | // CR Output 64 | uint32_t tonic_next_seq; 65 | uint8_t tonic_next_seq_tx_id; 66 | uint32_t tonic_next_seq_fid; 67 | 68 | uint32_t cr_dp_fid; 69 | uint32_t cr_cntxt; 70 | 71 | // CR Input 72 | uint8_t tx_val; 73 | 74 | // Registers 75 | 76 | // DD to CR 77 | uint32_t enq_fid_0; 78 | uint32_t enq_fid_1; 79 | uint32_t enq_fid_2; 80 | uint32_t enq_fid_3; 81 | uint32_t cr_enq_fid; 82 | 83 | uint32_t enq_seq_0; 84 | uint32_t enq_seq_1; 85 | uint32_t enq_seq_2; 86 | uint32_t enq_seq_3; 87 | uint32_t cr_enq_seq; 88 | 89 | uint8_t enq_seq_tx_id_0; 90 | uint8_t enq_seq_tx_id_1; 91 | uint8_t enq_seq_tx_id_2; 92 | uint8_t enq_seq_tx_id_3; 93 | uint8_t cr_enq_seq_tx_id; 94 | 95 | uint8_t timeout_val_0; 96 | uint8_t timeout_val_1; 97 | uint8_t timeout_val_2; 98 | uint8_t timeout_val_3; 99 | uint8_t cr_timeout_val; 100 | 101 | uint32_t timeout_fid_0; 102 | uint32_t timeout_fid_1; 103 | uint32_t timeout_fid_2; 104 | uint32_t timeout_fid_3; 105 | uint32_t cr_timeout_fid; 106 | 107 | uint32_t dd_cntxt_0; 108 | uint32_t dd_cntxt_1; 109 | uint32_t dd_cntxt_2; 110 | uint32_t dd_cntxt_3; 111 | uint32_t cr_dd_cntxt; 112 | 113 | // CR to DD 114 | 115 | uint32_t dp_fid_0; 116 | uint32_t dp_fid_1; 117 | uint32_t dp_fid_2; 118 | uint32_t dp_fid_3; 119 | uint32_t dd_dp_fid; 120 | 121 | uint32_t cr_cntxt_0; 122 | uint32_t cr_cntxt_1; 123 | uint32_t cr_cntxt_2; 124 | uint32_t cr_cntxt_3; 125 | uint32_t dd_cr_cntxt; 126 | }; 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /csim/utils/util.cc: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | #include 4 | 5 | string set_str(const set* s){ 6 | stringstream ss; 7 | ss << "{"; 8 | for (set::iterator it = s->begin(); 9 | it != s->end(); 10 | it++){ 11 | ss << *it << ", "; 12 | } 13 | ss << "}"; 14 | return ss.str(); 15 | } 16 | -------------------------------------------------------------------------------- /csim/utils/util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | string set_str(const set*); 11 | #endif 12 | -------------------------------------------------------------------------------- /include/clogb2.vh: -------------------------------------------------------------------------------- 1 | function integer clogb2; 2 | input integer val; 3 | begin 4 | clogb2 = 1; 5 | for (val = val/2; val > 1; val = val/2) begin 6 | clogb2 = clogb2 + 1; 7 | end 8 | end 9 | endfunction 10 | -------------------------------------------------------------------------------- /include/flow_state_defaults.vh: -------------------------------------------------------------------------------- 1 | `define RST_NEXT_NEW {`FLOW_SEQ_NUM_W{1'b0}} 2 | `define RST_WND_START {`FLOW_SEQ_NUM_W{1'b0}} 3 | `define RST_WND_START_IND {`FLOW_WIN_IND_W{1'b0}} 4 | `define RST_IDLE 1'b0 5 | `define RST_ACKED_WND {`FLOW_WIN_SIZE{1'b0}} 6 | `define RST_TX_CNT_WND {(`FLOW_WIN_SIZE * `TX_CNT_W){1'b0}} 7 | `define RST_RTX_WND {`FLOW_WIN_SIZE{1'b0}} 8 | `define RST_BACK_PRESSURE 1'b0 9 | `define RST_ACTIVE_RTX_TIMER 1'b0 10 | `define RST_WND_MASK {{(`FLOW_WIN_SIZE-`RST_WND_SIZE){1'b0}}, {`RST_WND_SIZE{1'b1}}} 11 | `define RST_RTX_EXPTIME {`TIME_W{1'b1}} 12 | 13 | `define RST_PKT_QUEUE {(`MAX_PKT_QUEUE_SIZE * `FLOW_SEQ_NUM_W){1'b0}} 14 | `define RST_TX_ID_QUEUE {(`MAX_PKT_QUEUE_SIZE * `TX_CNT_W){1'b0}} 15 | `define RST_PKT_QUEUE_HEAD {`PKT_QUEUE_IND_W{1'b0}} 16 | `define RST_PKT_QUEUE_TAIL {`PKT_QUEUE_IND_W{1'b0}} 17 | `define RST_PKT_QUEUE_SIZE {`PKT_QUEUE_IND_W{1'b0}} 18 | `define RST_LAST_CRED_UPDATE {`TIME_W{1'b0}} 19 | 20 | `define RST_READY_TO_TX 1'b0 21 | `define RST_TX_SIZE {{(`TX_SIZE_W - 10){1'b0}}, 10'd1000} 22 | 23 | `define RST_EX_CREDIT (`RST_TX_SIZE * `MAX_PKT_QUEUE_SIZE) 24 | `define RST_LAST_PULL_CNTR {`PULL_CNTR_W{1'b0}} 25 | `define RST_TIMEOUT_CRED `RST_EX_CREDIT 26 | `define RST_CRED_CAP `CRED_CAP 27 | 28 | -------------------------------------------------------------------------------- /include/sim.vh: -------------------------------------------------------------------------------- 1 | `define VCS_SIMULATION 2 | -------------------------------------------------------------------------------- /include/system_params.vh: -------------------------------------------------------------------------------- 1 | // CR_TYPE 2 | `define CR_TYPE_CWND 0 3 | `define CR_TYPE_RATE 1 4 | `define CR_TYPE_GRANT 2 5 | 6 | // Cross-Engine Context 7 | `define DD_CONTEXT_W (`RATE_W) 8 | `define DD_CONTEXT_NONE {`DD_CONTEXT_W{1'b1}} 9 | `define CR_CONTEXT_W 1 10 | 11 | //FLOW 12 | `define FLOW_ID_W `MAX_FLOW_CNT_WIDTH 13 | 14 | `define FLOW_SEQ_NUM_W 32 // should be power of two 15 | `define FLOW_SEQ_NONE {`FLOW_SEQ_NUM_W{1'h1}} 16 | `define FLOW_ID_NONE {`FLOW_ID_W{1'b1}} 17 | 18 | `define MAX_FLOW_CNT 1024 // should be power of two 19 | `define MAX_FLOW_CNT_WIDTH (clogb2(`MAX_FLOW_CNT)) 20 | 21 | // WINDOW 22 | `define FLOW_WIN_SIZE 8'd128 23 | `define MAX_FLOW_WIN_SIZE 8'd120 24 | `define FLOW_WIN_SIZE_W (clogb2(`FLOW_WIN_SIZE+8'd1) + 8'd1) 25 | `define FLOW_WIN_IND_W `FLOW_WIN_SIZE_W 26 | `define FLOW_WIN_MOD {`FLOW_WIN_SIZE_W{1'b1}} 27 | 28 | 29 | // Packet Queues 30 | 31 | `define MAX_PKT_QUEUE_SIZE 16 // should be power of two 32 | `define MAX_QUEUE_BITS (`MAX_PKT_QUEUE_SIZE * `FLOW_SEQ_NUM_W) 33 | `define MAX_TX_ID_BITS (`MAX_PKT_QUEUE_SIZE * `TX_CNT_W) 34 | `define PKT_QUEUE_IND_W (clogb2(`MAX_PKT_QUEUE_SIZE)) 35 | `define PKT_QUEUE_START_THRESH (`MAX_PKT_QUEUE_SIZE - 6) 36 | `define PKT_QUEUE_STOP_THRESH (`MAX_PKT_QUEUE_SIZE - 5) 37 | 38 | // Timers 39 | `define TIMER_W 32 40 | `define CRED_TIMER_W 32 41 | 42 | // Time 43 | `define TX_SIZE_W 11 44 | 45 | 46 | // Time, Rate, and Credit 47 | 48 | `define TIME_W 32 49 | 50 | `define RATE_W 18 51 | `define BASE_RATE 1562500 52 | `define LOW_RATE_THRESH 215 53 | `define MAX_RATE (100000000000 / `BASE_RATE) 54 | 55 | `define CYC_1_START_IND `RATE_W - 1 56 | `define CYC_1_END_IND `RATE_W - 9 57 | 58 | `define CYC_8_START_IND `CYC_1_END_IND - 1 59 | `define CYC_8_END_IND `CYC_1_END_IND - 3 60 | 61 | `define CYC_64_START_IND `CYC_8_END_IND - 1 62 | `define CYC_64_END_IND `CYC_8_END_IND - 3 63 | 64 | `define CYC_512_START_IND `CYC_64_END_IND - 1 65 | `define CYC_512_END_IND `CYC_64_END_IND - 3 66 | 67 | `define CRED_W 32 68 | 69 | // Credit Cap 70 | 71 | `define CRED_CAP {`CRED_W{1'b1}} 72 | 73 | 74 | // Pkt Types and Data 75 | 76 | `define PKT_TYPE_W 4 77 | `define PKT_DATA_W 100 78 | 79 | `define SACK_PKT {`PKT_TYPE_W{1'b0}} 80 | `define PULL_PKT {{(`PKT_TYPE_W-1){1'b0}}, 1'd1} 81 | `define NACK_PKT {{(`PKT_TYPE_W-2){1'b0}}, 2'd2} 82 | `define CACK_PKT {{(`PKT_TYPE_W-2){1'b0}}, 2'd3} 83 | `define CNP_PKT {{(`PKT_TYPE_W-1){1'b0}}, 3'd4} 84 | `define NONE_PKT {`PKT_TYPE_W{1'b1}} 85 | 86 | // Grants 87 | 88 | `define SEND_CNTR_W `FLOW_SEQ_NUM_W 89 | `define PULL_CNTR_W `SEND_CNTR_W 90 | `define REM_PULL_PKT_W 16 91 | `define MAX_REM_PULL_PKT_CNT {`REM_PULL_PKT_W{1'b1}} 92 | 93 | 94 | // TX_CNT 95 | 96 | `define TX_CNT_W 2 97 | `define MAX_TX_CNT {`TX_CNT_W{1'b1}} 98 | `define TX_CNT_WIN_SIZE (`FLOW_WIN_SIZE * `TX_CNT_W) 99 | 100 | // Other 101 | `define FLAG_W 1 102 | 103 | // OUTQ 104 | `define OUTQ_W (`FLOW_ID_W + `FLOW_SEQ_NUM_W + `TX_CNT_W) 105 | `define OUTQ_MAX_SIZE 16 //power of two 106 | `define OUTQ_SIZE_W (clogb2(`OUTQ_MAX_SIZE)) 107 | `define OUTQ_THRESH 10 108 | -------------------------------------------------------------------------------- /settings.sh: -------------------------------------------------------------------------------- 1 | export TONIC_HOME=$PWD 2 | export TONIC_TB_CFG_PATH=$TONIC_HOME/tb/config 3 | export TONIC_TOOLS=$TONIC_HOME/tools 4 | # 5 | export PATH=$PATH:$TONIC_TOOLS 6 | export PYTHONPATH=$PYTHONPATH:$TONIC_TOOLS/lib 7 | -------------------------------------------------------------------------------- /src/bitmap_ops/cnt_wnd/cnt_block.v: -------------------------------------------------------------------------------- 1 | // Note: 2 | // BLOCK_WIDTH must be power of 2 3 | module cnt_block #( 4 | parameter BLOCK_WIDTH = 2, 5 | parameter BLOCK_IND_WIDTH = 10, 6 | parameter BLOCK_LEVEL = -1, 7 | parameter BLOCK_WIDTH_LOG = clogb2(BLOCK_WIDTH) 8 | )( 9 | input [BLOCK_IND_WIDTH*BLOCK_WIDTH-1:0] cnts_in, 10 | 11 | output [BLOCK_IND_WIDTH+BLOCK_WIDTH_LOG-1:0] cnt_out 12 | ); 13 | 14 | generate 15 | if (BLOCK_WIDTH == 2) begin 16 | assign cnt_out = {{BLOCK_WIDTH_LOG{1'b0}}, cnts_in[BLOCK_IND_WIDTH * BLOCK_WIDTH - 1 -: BLOCK_IND_WIDTH]} + 17 | {{BLOCK_WIDTH_LOG{1'b0}}, cnts_in[BLOCK_IND_WIDTH-1:0]}; 18 | end 19 | else begin 20 | assign cnt_out = {(BLOCK_IND_WIDTH+BLOCK_WIDTH_LOG){1'b0}}; 21 | end 22 | endgenerate 23 | 24 | 25 | function integer clogb2; 26 | input integer val; 27 | begin 28 | clogb2 = 1; 29 | for (val = val/2; val > 1; val = val/2) begin 30 | clogb2 = clogb2 + 1; 31 | end 32 | end 33 | endfunction 34 | 35 | endmodule 36 | -------------------------------------------------------------------------------- /src/bitmap_ops/cnt_wnd/cnt_set.v: -------------------------------------------------------------------------------- 1 | module cnt_set #( 2 | parameter VECT_WIDTH = 64, 3 | parameter VECT_IND_WIDTH = 4, 4 | parameter BLOCK_WIDTH = 2 5 | )( 6 | input [VECT_WIDTH-1:0] vect_in, 7 | 8 | output [VECT_IND_WIDTH-1:0] cnt_out 9 | ); 10 | 11 | localparam BLOCK_DEPTH = clog(VECT_WIDTH, BLOCK_WIDTH); 12 | localparam BLOCK_WIDTH_LOG = clog(BLOCK_WIDTH, 2); 13 | 14 | wire [VECT_WIDTH-1:0] cnt_level[BLOCK_DEPTH:0]; 15 | 16 | 17 | assign cnt_out = cnt_level[BLOCK_DEPTH][VECT_IND_WIDTH-1:0]; 18 | 19 | genvar ii, jj; 20 | 21 | 22 | generate begin 23 | for (ii = 0; ii < BLOCK_DEPTH; ii = ii + 1) begin: level_gen 24 | if (ii == 0) begin 25 | assign cnt_level[ii] = vect_in; 26 | end 27 | 28 | // wire [VECT_WIDTH/pow(BLOCK_WIDTH,ii)-1:0] val_out_prev_level; 29 | for (jj = 0; jj < pow(BLOCK_WIDTH, BLOCK_DEPTH-ii-1); jj = jj + 1) begin: block_gen 30 | cnt_block # ( 31 | .BLOCK_WIDTH (BLOCK_WIDTH ), 32 | .BLOCK_IND_WIDTH (ii + 1 ), 33 | .BLOCK_LEVEL (ii ) 34 | ) cnt_block ( 35 | .cnts_in (cnt_level[ii][(jj+1)*(BLOCK_WIDTH*(ii+1))-1 :jj*BLOCK_WIDTH*(ii+1)]), 36 | .cnt_out (cnt_level[ii+1][(jj+1)*(ii+1+BLOCK_WIDTH_LOG)-1:jj*(ii+1+BLOCK_WIDTH_LOG)]) 37 | ); 38 | end 39 | end 40 | end 41 | endgenerate 42 | 43 | function integer clog; 44 | input integer val; 45 | input integer base; 46 | begin 47 | clog = 1; 48 | for (val = val/base; val > 1; val = val/base) begin 49 | clog = clog + 1; 50 | end 51 | end 52 | endfunction 53 | 54 | 55 | function integer pow; 56 | input integer base; 57 | input integer val; 58 | begin 59 | pow = 1; 60 | for (val = val; val > 0; val = val - 1) begin 61 | pow = pow*base; 62 | end 63 | end 64 | endfunction 65 | 66 | 67 | endmodule 68 | -------------------------------------------------------------------------------- /src/bitmap_ops/cnt_wnd/cnt_wnd.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module cnt_wnd # ( 4 | parameter VECT_WIDTH = -1, 5 | parameter VECT_IND_WIDTH = -1, 6 | parameter BLOCK_WIDTH = 2 7 | ) ( 8 | input [VECT_WIDTH-1:0] vect_in, 9 | input select_set_in, 10 | 11 | output [VECT_IND_WIDTH-1:0] cnt_out 12 | ); 13 | 14 | wire [VECT_WIDTH-1:0] vect_wnd_set_bits; 15 | 16 | genvar ii; 17 | 18 | generate 19 | for (ii = 0; ii < VECT_WIDTH; ii = ii + 1) begin: vect_wnd_set_bits_gen 20 | assign vect_wnd_set_bits[ii] = (vect_in[ii] == select_set_in); 21 | end 22 | endgenerate 23 | 24 | 25 | cnt_set #( 26 | .VECT_WIDTH (VECT_WIDTH ), 27 | .VECT_IND_WIDTH (VECT_IND_WIDTH ), 28 | .BLOCK_WIDTH (BLOCK_WIDTH ) 29 | ) cnt_set ( 30 | .vect_in (vect_wnd_set_bits ), 31 | .cnt_out (cnt_out ) 32 | ); 33 | 34 | endmodule 35 | -------------------------------------------------------------------------------- /src/bitmap_ops/ff_wnd/ff_block.v: -------------------------------------------------------------------------------- 1 | // Description: 2 | // Input: Multiple {val, ind} pairs, where several pairs can be valid 3 | // Output: least significant valid pair 4 | // Note: 5 | // BLOCK_WIDTH must be power of 2 6 | module ff_block #( 7 | parameter BLOCK_WIDTH = 4, 8 | parameter BLOCK_IND_WIDTH = 10, 9 | parameter BLOCK_LEVEL = -1 10 | )( 11 | input [BLOCK_WIDTH-1:0] ind_val_in, 12 | input [BLOCK_IND_WIDTH*BLOCK_WIDTH-1:0] ind_flat_in, 13 | 14 | output val_out, 15 | output [BLOCK_IND_WIDTH-1:0] ind_out 16 | ); 17 | 18 | localparam INPUT_DIR_NUM_WIDTH = clogb2(BLOCK_WIDTH); 19 | localparam INPUT_DIR_SHIFT = clogb2(BLOCK_WIDTH)*BLOCK_LEVEL; 20 | 21 | wire [BLOCK_WIDTH-1:0] single_valid_bus; 22 | wire [BLOCK_IND_WIDTH-1:0] selected_ind; 23 | wire [BLOCK_IND_WIDTH-1:0] ind_matr[BLOCK_WIDTH-1:0]; 24 | wire [INPUT_DIR_NUM_WIDTH-1:0] selected_direction; 25 | wire [BLOCK_WIDTH-1:0] ind_in_revert_matrix[BLOCK_IND_WIDTH-1:0]; 26 | wire [INPUT_DIR_NUM_WIDTH-1:0] direction_matrix[BLOCK_WIDTH-1:0]; 27 | wire [BLOCK_WIDTH-1:0] direction_matrix_inv[INPUT_DIR_NUM_WIDTH-1:0]; 28 | 29 | genvar ii, jj; 30 | 31 | assign val_out = |ind_val_in; 32 | 33 | //assign ind_out = (selected_direction << INPUT_DIR_SHIFT) + selected_ind; 34 | assign ind_out = (selected_direction << INPUT_DIR_SHIFT) + selected_ind; 35 | 36 | 37 | // Vector with at most one valid bit set 38 | generate begin 39 | for (ii = 0; ii < BLOCK_WIDTH; ii = ii + 1) begin: single_valid_bus_gen 40 | if (ii == 0) begin 41 | assign single_valid_bus[ii] = ind_val_in[ii]; 42 | end 43 | else begin 44 | assign single_valid_bus[ii] = ~(|ind_val_in[ii-1:0]) & ind_val_in[ii]; 45 | end 46 | end 47 | end 48 | endgenerate 49 | 50 | 51 | // Parallel OR input indexes masked by a vector with at most one valid bit set 52 | generate begin 53 | for (ii = 0; ii < BLOCK_WIDTH; ii = ii + 1) begin: ind_matr_gen 54 | assign ind_matr[ii] = ind_flat_in[(ii+1)*BLOCK_IND_WIDTH-1:ii*BLOCK_IND_WIDTH]; 55 | end 56 | 57 | 58 | for (ii = 0; ii < BLOCK_IND_WIDTH; ii = ii + 1) begin: selected_ind_gen 59 | for (jj = 0; jj < BLOCK_WIDTH; jj = jj + 1) begin: ind_in_revert_gen 60 | assign ind_in_revert_matrix[ii][jj] = ind_matr[jj][ii] & single_valid_bus[jj]; 61 | end 62 | assign selected_ind[ii] = |ind_in_revert_matrix[ii]; 63 | end 64 | end 65 | endgenerate 66 | 67 | // Get Input Direction number curresponding to a set bit in single_valid_bus 68 | generate begin 69 | for (ii = 0; ii < BLOCK_WIDTH; ii = ii + 1) begin: direction_matrix_gen 70 | wire [31:0] tmp_index = ii; 71 | assign direction_matrix[ii] = tmp_index[INPUT_DIR_NUM_WIDTH-1:0]; 72 | end 73 | 74 | for (ii = 0; ii < INPUT_DIR_NUM_WIDTH; ii = ii + 1) begin: selected_direction_gen 75 | for (jj = 0; jj < BLOCK_WIDTH; jj = jj + 1) begin: direction_matrix_gen 76 | assign direction_matrix_inv[ii][jj] = direction_matrix[jj][ii] & single_valid_bus[jj]; 77 | end 78 | assign selected_direction[ii] = |direction_matrix_inv[ii]; 79 | end 80 | end 81 | endgenerate 82 | 83 | // clogb2 function 84 | `include "clogb2.vh" 85 | 86 | endmodule 87 | -------------------------------------------------------------------------------- /src/bitmap_ops/ff_wnd/ff_set.v: -------------------------------------------------------------------------------- 1 | 2 | module ff_set #( 3 | parameter VECT_WIDTH = 64, 4 | parameter VECT_IND_WIDTH = 4, 5 | parameter BLOCK_WIDTH = 2 6 | )( 7 | input [VECT_WIDTH-1:0] vect_in, 8 | 9 | output val_out, 10 | output [VECT_IND_WIDTH-1:0] ind_out 11 | ); 12 | 13 | localparam BLOCK_DEPTH = clog(VECT_WIDTH, BLOCK_WIDTH); 14 | localparam IND_VAL_ARR_SIZE = VECT_WIDTH * (BLOCK_DEPTH + 1); 15 | localparam FLAT_ARR_ITEM_WIDTH = VECT_WIDTH * VECT_IND_WIDTH; 16 | localparam IND_FLAT_ARR_SIZE = FLAT_ARR_ITEM_WIDTH * (BLOCK_DEPTH + 1); 17 | 18 | wire [IND_VAL_ARR_SIZE-1:0] ind_val_level; 19 | wire [IND_FLAT_ARR_SIZE-1:0] ind_flat_level; 20 | 21 | assign val_out = ind_val_level[BLOCK_DEPTH * VECT_WIDTH]; 22 | 23 | assign ind_out = ind_flat_level[BLOCK_DEPTH * FLAT_ARR_ITEM_WIDTH + VECT_IND_WIDTH - 1 -: VECT_IND_WIDTH]; 24 | 25 | genvar ii, jj; 26 | 27 | generate begin 28 | for (ii = 0; ii < BLOCK_DEPTH; ii = ii + 1) begin: level_gen 29 | if (ii == 0) begin 30 | assign ind_val_level[(ii + 1) * VECT_WIDTH - 1 -: VECT_WIDTH] = vect_in; 31 | 32 | // Generate flat level 0 indexes 33 | for (jj = 0; jj < VECT_WIDTH; jj = jj + 1) begin: ind_flat_level_gen 34 | assign ind_flat_level[(jj+1)*VECT_IND_WIDTH-1:jj*VECT_IND_WIDTH] = {VECT_IND_WIDTH{1'b0}}; 35 | end 36 | end 37 | 38 | 39 | for (jj = 0; jj < num_blks(VECT_WIDTH, ii, BLOCK_WIDTH); jj = jj + 1) begin: block_gen 40 | ff_block # ( 41 | .BLOCK_WIDTH (BLOCK_WIDTH ), 42 | .BLOCK_IND_WIDTH (VECT_IND_WIDTH ), 43 | .BLOCK_LEVEL (ii ) 44 | ) ff_block ( 45 | .ind_val_in (ind_val_level[(ii * VECT_WIDTH) + (jj+1)*BLOCK_WIDTH-1: (ii * VECT_WIDTH) + jj*BLOCK_WIDTH]), 46 | .ind_flat_in(ind_flat_level[(ii * FLAT_ARR_ITEM_WIDTH) + (jj+1)*VECT_IND_WIDTH*BLOCK_WIDTH-1: (ii * FLAT_ARR_ITEM_WIDTH) + jj*VECT_IND_WIDTH*BLOCK_WIDTH]), 47 | .val_out(ind_val_level[(ii+1) * VECT_WIDTH + jj]), 48 | .ind_out(ind_flat_level[((ii+1) * FLAT_ARR_ITEM_WIDTH) + (jj+1)*VECT_IND_WIDTH-1: 49 | ((ii+1) * FLAT_ARR_ITEM_WIDTH) + jj*VECT_IND_WIDTH]) 50 | ); 51 | end 52 | assign ind_val_level[(ii + 1) * VECT_WIDTH + VECT_WIDTH - 1 : (ii + 1) * VECT_WIDTH + num_blks(VECT_WIDTH, ii, BLOCK_WIDTH)] = {(VECT_WIDTH - num_blks(VECT_WIDTH, ii, BLOCK_WIDTH)){1'b0}}; 53 | assign ind_flat_level[(ii + 1) * FLAT_ARR_ITEM_WIDTH + FLAT_ARR_ITEM_WIDTH - 1 : (ii + 1) * FLAT_ARR_ITEM_WIDTH + (num_blks(VECT_WIDTH, ii, BLOCK_WIDTH))*VECT_IND_WIDTH] = {(VECT_IND_WIDTH * (VECT_WIDTH - num_blks(VECT_WIDTH, ii, BLOCK_WIDTH))){1'b0}}; 54 | 55 | end 56 | end 57 | endgenerate 58 | 59 | function integer clog; 60 | input integer val; 61 | input integer base; 62 | begin 63 | clog = 1; 64 | for (val = val/base; val > 1; val = val/base) begin 65 | clog = clog + 1; 66 | end 67 | end 68 | endfunction 69 | 70 | 71 | function integer pow; 72 | input integer base; 73 | input integer val; 74 | begin 75 | pow = 1; 76 | for (val = val; val > 0; val = val - 1) begin 77 | pow = pow*base; 78 | end 79 | end 80 | endfunction 81 | 82 | function integer num_blks; 83 | input integer w; 84 | input integer i; 85 | input integer bw; 86 | begin 87 | num_blks = pow(bw, i + 1) > w ? 1 : w/pow(bw, i + 1); 88 | end 89 | endfunction 90 | 91 | endmodule 92 | -------------------------------------------------------------------------------- /src/bitmap_ops/ff_wnd/ff_wnd.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module ff_wnd # ( 4 | parameter VECT_WIDTH = -1, 5 | parameter VECT_IND_WIDTH = -1, 6 | parameter BLOCK_WIDTH = 2 7 | ) ( 8 | input [VECT_WIDTH-1:0] vect_in, 9 | input select_set_in, 10 | input [VECT_IND_WIDTH-1:0] head_in, 11 | 12 | output val_out, 13 | output [VECT_IND_WIDTH-1:0] ind_out 14 | ); 15 | 16 | wire [VECT_WIDTH-1:0] vect_wnd_set_bits_1; 17 | wire val_out_1; 18 | wire [VECT_IND_WIDTH-1:0] ind_out_1; 19 | 20 | wire [VECT_WIDTH-1:0] vect_wnd_set_bits_2; 21 | wire val_out_2; 22 | wire [VECT_IND_WIDTH-1:0] ind_out_2; 23 | 24 | genvar ii; 25 | 26 | generate 27 | for (ii = 0; ii < VECT_WIDTH; ii = ii + 1) begin: vect_wnd_set_bits_gen 28 | assign vect_wnd_set_bits_1[ii] = (vect_in[ii] == select_set_in) & 29 | (ii >= head_in); 30 | 31 | 32 | assign vect_wnd_set_bits_2[ii] = (vect_in[ii] == select_set_in); 33 | end 34 | endgenerate 35 | 36 | 37 | ff_set #( 38 | .VECT_WIDTH (VECT_WIDTH ), 39 | .VECT_IND_WIDTH (VECT_IND_WIDTH ), 40 | .BLOCK_WIDTH (BLOCK_WIDTH ) 41 | ) sfs1 ( 42 | .vect_in (vect_wnd_set_bits_1 ), 43 | .val_out (val_out_1 ), 44 | .ind_out (ind_out_1 ) 45 | ); 46 | 47 | ff_set #( 48 | .VECT_WIDTH (VECT_WIDTH ), 49 | .VECT_IND_WIDTH (VECT_IND_WIDTH ), 50 | .BLOCK_WIDTH (BLOCK_WIDTH ) 51 | ) sfs2 ( 52 | .vect_in (vect_wnd_set_bits_2 ), 53 | .val_out (val_out_2 ), 54 | .ind_out (ind_out_2 ) 55 | ); 56 | 57 | assign val_out = val_out_1 | val_out_2; 58 | assign ind_out = val_out_1 ? ind_out_1 : ind_out_2; 59 | 60 | endmodule 61 | -------------------------------------------------------------------------------- /src/cr_engine/common/event_processors/cr_enqueue/cr_enqueue.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module cr_enqueue ( 4 | //// Inputs 5 | 6 | input [`FLOW_SEQ_NUM_W-1:0] enq_seq, 7 | input [`TX_CNT_W-1:0] enq_seq_tx_id, 8 | 9 | // context 10 | input [`MAX_QUEUE_BITS-1:0] pkt_queue_in, 11 | input [`MAX_TX_ID_BITS-1:0] tx_id_queue_in, 12 | input [`PKT_QUEUE_IND_W-1:0] pkt_queue_tail_in, 13 | input [`PKT_QUEUE_IND_W-1:0] pkt_queue_size_in, 14 | 15 | //// Outputs 16 | output [`MAX_QUEUE_BITS-1:0] pkt_queue_out, 17 | output [`MAX_TX_ID_BITS-1:0] tx_id_queue_out, 18 | output [`PKT_QUEUE_IND_W-1:0] pkt_queue_tail_out, 19 | output [`PKT_QUEUE_IND_W-1:0] pkt_queue_size_out 20 | ); 21 | 22 | 23 | // pkt_queue 24 | genvar i; 25 | 26 | generate 27 | for (i = 0; i < `MAX_PKT_QUEUE_SIZE; i = i + 1) begin: gen_pkt_queue 28 | assign pkt_queue_out[(i + 1) * `FLOW_SEQ_NUM_W - 1 -: `FLOW_SEQ_NUM_W] = (i == pkt_queue_tail_in) ? enq_seq : 29 | pkt_queue_in[(i + 1) * `FLOW_SEQ_NUM_W - 1 -: `FLOW_SEQ_NUM_W]; 30 | end 31 | endgenerate 32 | 33 | // tx_id_queue 34 | generate 35 | for (i = 0; i < `MAX_PKT_QUEUE_SIZE; i = i + 1) begin: gen_tx_id_queue 36 | assign tx_id_queue_out[(i + 1) * `TX_CNT_W - 1 -: `TX_CNT_W] = (i == pkt_queue_tail_in) ? enq_seq_tx_id : 37 | tx_id_queue_in[(i + 1) * `TX_CNT_W - 1 -: `TX_CNT_W]; 38 | end 39 | endgenerate 40 | 41 | 42 | // pkt_queue_tail 43 | wire [`PKT_QUEUE_IND_W:0] next_tail; 44 | assign next_tail = pkt_queue_tail_in + {{(`PKT_QUEUE_IND_W-1){1'b0}}, 1'b1}; 45 | 46 | assign pkt_queue_tail_out = (enq_seq == `FLOW_SEQ_NONE) ? pkt_queue_tail_in : next_tail[`PKT_QUEUE_IND_W-1:0]; 47 | 48 | // pkt_queue_size 49 | assign pkt_queue_size_out = (enq_seq == `FLOW_SEQ_NONE) ? pkt_queue_size_in : (pkt_queue_size_in + {{(`PKT_QUEUE_IND_W-1){1'b0}}, 1'b1}); 50 | 51 | // clogb2 function 52 | `include "clogb2.vh" 53 | endmodule 54 | -------------------------------------------------------------------------------- /src/cr_engine/cwnd/cr_engine.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module cr_engine ( 4 | input clk, 5 | input rst_n, 6 | // Inputs 7 | input [`FLOW_ID_W-1:0] enq_fid_in, 8 | input [`FLOW_SEQ_NUM_W-1:0] enq_seq_in, 9 | input [`TX_CNT_W-1:0] enq_seq_tx_id_in, 10 | 11 | input [`DD_CONTEXT_W-1:0] dd_cntxt_in, 12 | 13 | input [`FLOW_ID_W-1:0] incoming_fid_in, 14 | input [`PKT_TYPE_W-1:0] pkt_type_in, 15 | input [`PKT_DATA_W-1:0] pkt_data_in, 16 | 17 | input [`FLOW_ID_W-1:0] timeout_fid_in, 18 | 19 | input tx_val, 20 | // Outputs 21 | 22 | output [`FLOW_ID_W-1:0] dp_fid_out, 23 | 24 | output [`FLOW_ID_W-1:0] next_seq_fid_out, 25 | output [`FLOW_SEQ_NUM_W-1:0] next_seq_out, 26 | output [`TX_CNT_W-1:0] next_seq_tx_id_out, 27 | 28 | output [`CR_CONTEXT_W-1:0] cr_cntxt_out 29 | ); 30 | 31 | wire [`FLOW_ID_W-1:0] tx_fid_in; 32 | 33 | //////// Credit Engine ////////////////// 34 | 35 | // transport engine outputs 36 | wire [`FLOW_ID_W-1:0] tx_enq_fid1; 37 | wire [`FLOW_ID_W-1:0] tx_enq_fid2; 38 | 39 | assign cr_cntxt_out = {`CR_CONTEXT_W{1'b0}}; 40 | 41 | cr_core core (.clk (clk ), 42 | .rst_n (rst_n ), 43 | .enq_fid_in (enq_fid_in ), 44 | .enq_seq_in (enq_seq_in ), 45 | .enq_seq_tx_id_in (enq_seq_tx_id_in ), 46 | .tx_fid_in (tx_fid_in ), 47 | 48 | .tx_enq_fid1 (tx_enq_fid1 ), 49 | .tx_enq_fid2 (tx_enq_fid2 ), 50 | .next_seq (next_seq_out ), 51 | .next_seq_tx_id (next_seq_tx_id_out ), 52 | .next_seq_fid (next_seq_fid_out ), 53 | .dp_fid (dp_fid_out )); 54 | 55 | 56 | //////// TX Fifo /////////////////////// 57 | 58 | // fifo inputs 59 | wire tx_fifo_w_val_0; 60 | wire tx_fifo_w_val_1; 61 | 62 | reg [`FLOW_ID_W - 1:0] queue_w_data_0; 63 | reg [`FLOW_ID_W - 1:0] queue_w_data_1; 64 | 65 | wire [`FLOW_ID_W:0] ni_fifo_size; 66 | wire ni_fifo_full; 67 | wire ni_fifo_data_avail; 68 | 69 | wire [`FLOW_ID_W - 1:0] tx_fid_tmp; 70 | 71 | 72 | assign tx_fifo_w_val_0 = queue_w_data_0 != `FLOW_ID_NONE; 73 | assign tx_fifo_w_val_1 = queue_w_data_1 != `FLOW_ID_NONE; 74 | 75 | always @(posedge clk) begin 76 | if (~rst_n) begin 77 | queue_w_data_0 <= `FLOW_ID_NONE; 78 | queue_w_data_1 <= `FLOW_ID_NONE; 79 | end 80 | else begin 81 | queue_w_data_0 <= tx_enq_fid1; 82 | queue_w_data_1 <= tx_enq_fid2; 83 | end 84 | end 85 | 86 | assign tx_fid_in = tx_val ? tx_fid_tmp : `FLOW_ID_NONE; 87 | 88 | fifo_2w #(.FIFO_WIDTH (`FLOW_ID_W ), 89 | .FIFO_DEPTH (`MAX_FLOW_CNT )) 90 | tx_fifo(.clk (clk ), 91 | .rst_n (rst_n ), 92 | 93 | .w_val_0 (tx_fifo_w_val_0 ), 94 | .w_data_0 (queue_w_data_0 ), 95 | 96 | .w_val_1 (tx_fifo_w_val_1 ), 97 | .w_data_1 (queue_w_data_1 ), 98 | 99 | .r_val (tx_val ), 100 | .r_data (tx_fid_tmp ), 101 | 102 | .size (ni_fifo_size ), 103 | .full (ni_fifo_full ), 104 | .data_avail (ni_fifo_data_avail )); 105 | 106 | 107 | // clogb2 function 108 | `include "clogb2.vh" 109 | endmodule 110 | -------------------------------------------------------------------------------- /src/cr_engine/cwnd/event_processors/cr_transmit/cr_transmit.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module cr_transmit ( 4 | //// Inputs 5 | // context 6 | input [`MAX_QUEUE_BITS-1:0] pkt_queue, 7 | input [`MAX_TX_ID_BITS-1:0] tx_id_queue, 8 | input [`PKT_QUEUE_IND_W-1:0] pkt_queue_head_in, 9 | input [`PKT_QUEUE_IND_W-1:0] pkt_queue_size_in, 10 | 11 | //// Outputs 12 | output [`PKT_QUEUE_IND_W-1:0] pkt_queue_head_out, 13 | output [`PKT_QUEUE_IND_W-1:0] pkt_queue_size_out, 14 | 15 | output [`FLOW_SEQ_NUM_W-1:0] next_seq_out, 16 | output [`TX_CNT_W-1:0] next_seq_tx_id_out 17 | ); 18 | 19 | localparam FLOW_SEQ_NUM_LOG = clogb2(`FLOW_SEQ_NUM_W); 20 | localparam TX_ID_LOG = clogb2(`TX_CNT_W); 21 | 22 | // pkt_queue_head_out 23 | wire [`PKT_QUEUE_IND_W:0] head_out; 24 | assign head_out = pkt_queue_head_in + {{(`PKT_QUEUE_IND_W-1){1'b0}}, 1'b1}; 25 | assign pkt_queue_head_out = head_out[`PKT_QUEUE_IND_W-1:0]; 26 | 27 | // pkt_queue_size_out 28 | assign pkt_queue_size_out = pkt_queue_size_in - {{(`PKT_QUEUE_IND_W-1){1'b0}}, 1'b1}; 29 | 30 | // next_seq_out 31 | wire [`PKT_QUEUE_IND_W + FLOW_SEQ_NUM_LOG - 1: 0] head_ind; 32 | assign head_ind = {pkt_queue_head_in, {FLOW_SEQ_NUM_LOG{1'b1}}}; 33 | assign next_seq_out = pkt_queue[head_ind -: `FLOW_SEQ_NUM_W]; 34 | 35 | // next_seq_tx_id_out 36 | wire [`PKT_QUEUE_IND_W + TX_ID_LOG - 1: 0] tx_id_head_ind; 37 | assign tx_id_head_ind = {pkt_queue_head_in, {TX_ID_LOG{1'b1}}}; 38 | assign next_seq_tx_id_out = tx_id_queue[tx_id_head_ind -: `TX_CNT_W]; 39 | 40 | // clogb2 function 41 | `include "clogb2.vh" 42 | 43 | endmodule 44 | -------------------------------------------------------------------------------- /src/dd_engine/dd_engine.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module dd_engine ( 4 | input clk, 5 | input rst_n, 6 | 7 | // inputs 8 | input [`FLOW_ID_W-1:0] dp_fid_in, 9 | input [`CR_CONTEXT_W-1:0] cr_cntxt_in, 10 | 11 | input [`FLOW_ID_W-1:0] incoming_fid_in, 12 | input [`PKT_TYPE_W-1:0] pkt_type_in, 13 | input [`PKT_DATA_W-1:0] pkt_data_in, 14 | 15 | // outputs 16 | output [`FLOW_SEQ_NUM_W-1:0] next_seq_out, 17 | output [`TX_CNT_W-1:0] next_seq_tx_id_out, 18 | output [`FLOW_ID_W-1:0] next_seq_fid_out, 19 | 20 | output [`FLAG_W-1:0] timeout_val_out, 21 | output [`FLOW_ID_W-1:0] timeout_fid_out, 22 | 23 | output [`DD_CONTEXT_W-1:0] dd_cntxt_out 24 | ); 25 | 26 | //********************************************************************************* 27 | // Wires and Regs 28 | //********************************************************************************* 29 | 30 | // Non-idle Fifo 31 | 32 | wire [`FLOW_ID_W-1:0] next_fid_in; 33 | 34 | reg [`FLOW_ID_W-1:0] next_enq_fid1_q; 35 | reg [`FLOW_ID_W-1:0] next_enq_fid2_q; 36 | reg [`FLOW_ID_W-1:0] next_enq_fid3_q; 37 | reg [`FLOW_ID_W-1:0] next_enq_fid4_q; 38 | 39 | wire w_val_fid1; 40 | wire w_val_fid2; 41 | wire w_val_fid3; 42 | wire w_val_fid4; 43 | 44 | wire r_val_next_fid; 45 | wire [`FLOW_ID_W - 1:0] r_data; 46 | wire [`FLOW_ID_W:0] ni_fifo_size; 47 | wire ni_fifo_full; 48 | wire ni_fifo_data_avail; 49 | 50 | // transport engine wires 51 | 52 | wire [`FLOW_ID_W-1:0] next_enq_fid1; 53 | wire [`FLOW_ID_W-1:0] next_enq_fid2; 54 | wire [`FLOW_ID_W-1:0] next_enq_fid3; 55 | wire [`FLOW_ID_W-1:0] next_enq_fid4; 56 | 57 | 58 | //********************************************************************************* 59 | // Logic - Queues 60 | //********************************************************************************* 61 | 62 | // non-idle 63 | 64 | always @(posedge clk) begin 65 | if (~rst_n) begin 66 | next_enq_fid1_q <= `FLOW_ID_NONE; 67 | next_enq_fid2_q <= `FLOW_ID_NONE; 68 | next_enq_fid3_q <= `FLOW_ID_NONE; 69 | next_enq_fid4_q <= `FLOW_ID_NONE; 70 | end 71 | else begin 72 | next_enq_fid1_q <= next_enq_fid1; 73 | next_enq_fid2_q <= next_enq_fid2; 74 | next_enq_fid3_q <= next_enq_fid3; 75 | next_enq_fid4_q <= next_enq_fid4; 76 | end 77 | end 78 | 79 | assign w_val_fid1 = next_enq_fid1_q != `FLOW_ID_NONE; 80 | assign w_val_fid2 = next_enq_fid2_q != `FLOW_ID_NONE; 81 | assign w_val_fid3 = next_enq_fid3_q != `FLOW_ID_NONE; 82 | assign w_val_fid4 = next_enq_fid4_q != `FLOW_ID_NONE; 83 | 84 | assign r_val_next_fid = 1'b1; 85 | 86 | fifo_4w #(.FIFO_WIDTH (`FLOW_ID_W), 87 | .FIFO_DEPTH (`MAX_FLOW_CNT)) non_idle_fifo (.clk (clk ), 88 | .rst_n (rst_n ), 89 | .w_val_0 (w_val_fid1 ), 90 | .w_data_0 (next_enq_fid1_q ), 91 | .w_val_1 (w_val_fid2 ), 92 | .w_data_1 (next_enq_fid2_q ), 93 | .w_val_2 (w_val_fid3 ), 94 | .w_data_2 (next_enq_fid3_q ), 95 | .w_val_3 (w_val_fid4 ), 96 | .w_data_3 (next_enq_fid4_q ), 97 | .r_val (r_val_next_fid ), 98 | .r_data (r_data ), 99 | .full (ni_fifo_full ), 100 | .size (ni_fifo_size ), 101 | .data_avail (ni_fifo_data_avail )); 102 | 103 | 104 | //********************************************************************************* 105 | // Logic - Transport Engine 106 | //********************************************************************************* 107 | 108 | assign next_fid_in = r_val_next_fid ? r_data : `FLOW_ID_NONE; 109 | 110 | dd_core core (.clk (clk ), 111 | .rst_n (rst_n ), 112 | .next_fid_in (next_fid_in ), 113 | 114 | .dp_fid_in (dp_fid_in ), 115 | .cr_cntxt_in (cr_cntxt_in ), 116 | 117 | .incoming_fid_in (incoming_fid_in ), 118 | .pkt_type_in (pkt_type_in ), 119 | .pkt_data_in (pkt_data_in ), 120 | 121 | .next_seq_out (next_seq_out ), 122 | .next_seq_tx_id_out (next_seq_tx_id_out ), 123 | .next_seq_fid_out (next_seq_fid_out ), 124 | 125 | .timeout_val_out (timeout_val_out ), 126 | .timeout_fid_out (timeout_fid_out ), 127 | .dd_cntxt_out (dd_cntxt_out ), 128 | 129 | .next_enq_fid1 (next_enq_fid1 ), 130 | .next_enq_fid2 (next_enq_fid2 ), 131 | .next_enq_fid3 (next_enq_fid3 ), 132 | .next_enq_fid4 (next_enq_fid4 ) 133 | ); 134 | 135 | // clogb2 function 136 | `include "clogb2.vh" 137 | 138 | endmodule 139 | -------------------------------------------------------------------------------- /src/dd_engine/event_processors/dd_dequeue_prop/dd_dequeue_prop.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module dd_dequeue_prop ( 4 | // Inputs 5 | input [`PKT_QUEUE_IND_W-1:0] pkt_queue_size_in, 6 | input [`FLAG_W-1:0] back_pressure_in, 7 | 8 | // Outputs 9 | output [`PKT_QUEUE_IND_W-1:0] pkt_queue_size_out, 10 | output [`FLAG_W-1:0] back_pressure_out, 11 | output [`FLAG_W-1:0] activated_by_dp 12 | ); 13 | 14 | assign pkt_queue_size_out = pkt_queue_size_in - {{(`PKT_QUEUE_IND_W-1){1'b0}}, 1'b1}; 15 | 16 | assign back_pressure_out = ~(back_pressure_in & pkt_queue_size_out < `PKT_QUEUE_START_THRESH) & back_pressure_in; 17 | assign activated_by_dp = back_pressure_in & pkt_queue_size_out < `PKT_QUEUE_START_THRESH; 18 | 19 | // clogb2 function 20 | `include "clogb2.vh" 21 | 22 | endmodule 23 | -------------------------------------------------------------------------------- /src/dd_engine/event_processors/dd_incoming/dd_incoming_0.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module dd_incoming_0 ( 4 | //// input interface 5 | input [`PKT_TYPE_W-1:0] pkt_type_in, 6 | input [`FLOW_SEQ_NUM_W-1:0] cumulative_ack_in, 7 | input [`FLOW_SEQ_NUM_W-1:0] selective_ack_in, 8 | input [`TX_CNT_W-1:0] sack_tx_id_in, 9 | 10 | // context 11 | input [`FLOW_WIN_SIZE-1:0] acked_wnd_in, 12 | input [`FLOW_WIN_IND_W-1:0] wnd_start_ind_in, 13 | input [`FLOW_SEQ_NUM_W-1:0] wnd_start_in, 14 | input [`FLOW_WIN_SIZE_W-1:0] wnd_size_in, 15 | 16 | //// output interface 17 | 18 | output [`FLAG_W-1:0] valid_selective_ack, 19 | output [`FLOW_WIN_IND_W-1:0] new_c_acks_cnt, 20 | 21 | // context 22 | 23 | output [`FLOW_WIN_SIZE-1:0] acked_wnd_out, 24 | output [`FLOW_WIN_IND_W-1:0] wnd_start_ind_out, 25 | output [`FLOW_SEQ_NUM_W-1:0] wnd_start_out 26 | ); 27 | 28 | localparam R_FLOW_WIN_IND_W = `FLOW_WIN_IND_W - 1; 29 | 30 | //********************************************************************************* 31 | // Wires and Regs 32 | //********************************************************************************* 33 | 34 | wire [`FLOW_SEQ_NUM_W-1:0] selective_ack_ind_tmp; 35 | wire [`FLOW_WIN_IND_W-2:0] selective_ack_ind; 36 | 37 | wire [`FLOW_WIN_IND_W-1:0] end_of_wnd_ind_tmp; 38 | wire [`FLOW_WIN_IND_W-1:0] end_of_wnd_ind; 39 | 40 | // window 41 | wire [`FLOW_WIN_SIZE-1:0] wnd_mask; 42 | wire wnd_range_val_1; 43 | wire [`FLOW_WIN_IND_W-1:0] wnd_range_start_1; 44 | wire [`FLOW_WIN_IND_W-1:0] wnd_range_end_1; 45 | 46 | wire wnd_range_val_2; 47 | wire [`FLOW_WIN_IND_W-1:0] wnd_range_start_2; 48 | wire [`FLOW_WIN_IND_W-1:0] wnd_range_end_2; 49 | 50 | // newly-acked 51 | wire [`FLOW_WIN_SIZE-1:0] nwack_wnd_mask; 52 | wire [`FLOW_WIN_SIZE-1:0] nwack_wnd; 53 | 54 | wire nwack_wnd_range_val_1; 55 | wire [`FLOW_WIN_IND_W-1:0] nwack_wnd_range_start_1; 56 | wire [`FLOW_WIN_IND_W-1:0] nwack_wnd_range_end_1; 57 | 58 | wire nwack_wnd_range_val_2; 59 | wire [`FLOW_WIN_IND_W-1:0] nwack_wnd_range_start_2; 60 | wire [`FLOW_WIN_IND_W-1:0] nwack_wnd_range_end_2; 61 | 62 | //********************************************************************************* 63 | // Logic 64 | //********************************************************************************* 65 | 66 | assign end_of_wnd_ind_tmp = wnd_start_ind_out + wnd_size_in; 67 | assign end_of_wnd_ind = {1'b0, end_of_wnd_ind_tmp[R_FLOW_WIN_IND_W-1:0]}; 68 | 69 | // wnd start output 70 | assign wnd_start_out = (cumulative_ack_in > wnd_start_in) ? cumulative_ack_in : wnd_start_in; 71 | 72 | wire [`FLOW_SEQ_NUM_W-1:0] wnd_start_ind_out_tmp; 73 | assign wnd_start_ind_out_tmp = wnd_start_ind_in + wnd_start_out - wnd_start_in; 74 | assign wnd_start_ind_out = {1'b0, wnd_start_ind_out_tmp[R_FLOW_WIN_IND_W-1:0]}; 75 | 76 | // wnd mask 77 | assign wnd_range_val_1 = 1'b1; 78 | assign wnd_range_start_1 = wnd_start_ind_out; 79 | assign wnd_range_end_1 = (end_of_wnd_ind >= wnd_start_ind_out) ? end_of_wnd_ind : `FLOW_WIN_SIZE; 80 | 81 | assign wnd_range_val_2 = end_of_wnd_ind < wnd_start_ind_out; 82 | assign wnd_range_start_2 = {(R_FLOW_WIN_IND_W+1){1'b0}}; 83 | assign wnd_range_end_2 = end_of_wnd_ind; 84 | 85 | // acks 86 | assign selective_ack_ind_tmp = selective_ack_in - wnd_start_in + wnd_start_ind_in; 87 | assign selective_ack_ind = selective_ack_ind_tmp[R_FLOW_WIN_IND_W-1:0]; 88 | 89 | assign valid_selective_ack = ~acked_wnd_in[selective_ack_ind] & 90 | selective_ack_in > wnd_start_out & 91 | (selective_ack_in < wnd_start_out + wnd_size_in); 92 | 93 | genvar i; 94 | 95 | // mask for new window 96 | generate 97 | for (i = 0; i < `FLOW_WIN_SIZE; i = i + 1) begin: gen_wnd_mask 98 | assign wnd_mask[i] = (wnd_range_val_1 & (i >= wnd_range_start_1) & (i < wnd_range_end_1)) | 99 | (wnd_range_val_2 & (i >= wnd_range_start_2) & (i < wnd_range_end_2)) ; 100 | end 101 | endgenerate 102 | 103 | // update acked_wnd 104 | generate 105 | for (i = 0; i < `FLOW_WIN_SIZE; i = i + 1) begin: gen_ack 106 | assign acked_wnd_out[i] = wnd_mask[i] & ~nwack_wnd_mask[i] & 107 | (((i == selective_ack_ind) & valid_selective_ack) ? 1'b1 : acked_wnd_in[i]); 108 | end 109 | endgenerate 110 | 111 | // newly-acked ranges 112 | assign nwack_wnd_range_val_1 = 1'b1; 113 | assign nwack_wnd_range_start_1 = wnd_start_ind_in; 114 | assign nwack_wnd_range_end_1 = (wnd_start_ind_out >= wnd_start_ind_in) ? wnd_start_ind_out : `FLOW_WIN_SIZE; 115 | 116 | assign nwack_wnd_range_val_2 = wnd_start_ind_out < wnd_start_ind_in; 117 | assign nwack_wnd_range_start_2 = {(R_FLOW_WIN_IND_W+1){1'b0}}; 118 | assign nwack_wnd_range_end_2 = wnd_start_ind_out; 119 | 120 | // nwack_wnd_mask 121 | generate 122 | for (i = 0; i < `FLOW_WIN_SIZE; i = i + 1) begin: gen_nwack_wnd_mask 123 | assign nwack_wnd_mask[i] = (nwack_wnd_range_val_1 & (i >= nwack_wnd_range_start_1) & (i < nwack_wnd_range_end_1)) | 124 | (nwack_wnd_range_val_2 & (i >= nwack_wnd_range_start_2) & (i < nwack_wnd_range_end_2)); 125 | end 126 | endgenerate 127 | 128 | 129 | // nwack_wnd 130 | generate 131 | for (i = 0; i < `FLOW_WIN_SIZE; i = i + 1) begin: gen_nwack_wnd 132 | assign nwack_wnd[i] = ~acked_wnd_in[i] & nwack_wnd_mask[i]; 133 | end 134 | endgenerate 135 | 136 | // count new acks 137 | cnt_wnd #( 138 | .VECT_WIDTH (`FLOW_WIN_SIZE ), 139 | .VECT_IND_WIDTH (`FLOW_WIN_IND_W ) 140 | ) 141 | cnt_wnd ( 142 | .vect_in (nwack_wnd ), 143 | .select_set_in (1'b1 ), 144 | .cnt_out (new_c_acks_cnt ) 145 | ); 146 | 147 | // clogb2 function 148 | `include "clogb2.vh" 149 | endmodule 150 | -------------------------------------------------------------------------------- /src/dd_engine/event_processors/dd_incoming/dd_incoming_1.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module dd_incoming_1 ( 4 | // input 5 | input [`PKT_TYPE_W-1:0] pkt_type_in, 6 | input [`PKT_DATA_W-1:0] pkt_data_in, 7 | input [`FLOW_SEQ_NUM_W-1:0] cumulative_ack_in, 8 | input [`FLOW_SEQ_NUM_W-1:0] selective_ack_in, 9 | input [`TX_CNT_W-1:0] sack_tx_id_in, 10 | 11 | input [`TIME_W-1:0] now, 12 | 13 | input [`FLAG_W-1:0] valid_selective_ack, 14 | input [`FLOW_WIN_IND_W-1:0] new_c_acks_cnt, 15 | input [`FLOW_SEQ_NUM_W-1:0] old_wnd_start_in, 16 | 17 | input [`FLOW_WIN_SIZE-1:0] acked_wnd_in, 18 | input [`FLOW_WIN_SIZE-1:0] rtx_wnd_in, 19 | input [`TX_CNT_WIN_SIZE-1:0] tx_cnt_wnd_in, 20 | input [`FLOW_WIN_IND_W-1:0] wnd_start_ind_in, 21 | input [`FLOW_SEQ_NUM_W-1:0] wnd_start_in, 22 | input [`FLOW_WIN_SIZE_W-1:0] wnd_size_in, 23 | input [`FLOW_SEQ_NUM_W-1:0] next_new_in, 24 | input [`TIMER_W-1:0] rtx_timer_amnt_in, 25 | input [`FLOW_SEQ_NUM_W-1:0] total_tx_cnt_in, 26 | input [`USER_CONTEXT_W-1:0] user_cntxt_in, 27 | 28 | // output 29 | output [`FLOW_WIN_SIZE-1:0] rtx_wnd_out, 30 | output [`FLOW_WIN_SIZE_W-1:0] wnd_size_out, 31 | output [`FLAG_W-1:0] reset_rtx_timer, 32 | output [`TIMER_W-1:0] rtx_timer_amnt_out, 33 | output [`USER_CONTEXT_W-1:0] user_cntxt_out 34 | ); 35 | 36 | localparam R_FLOW_WIN_IND_W = `FLOW_WIN_IND_W - 1; 37 | 38 | //********************************************************************************* 39 | // Wires and Regs 40 | //********************************************************************************* 41 | 42 | wire mark_rtx; 43 | 44 | wire [`FLOW_SEQ_NUM_W-1:0] rtx_start_ind_tmp; 45 | wire [`FLOW_WIN_IND_W-1:0] rtx_start_ind; 46 | 47 | wire [`FLOW_SEQ_NUM_W-1:0] rtx_end_ind_tmp; 48 | wire [`FLOW_WIN_IND_W-1:0] rtx_end_ind; 49 | 50 | wire rtx_range_val_1; 51 | wire [`FLOW_WIN_IND_W-1:0] rtx_range_start_1; 52 | wire [`FLOW_WIN_IND_W-1:0] rtx_range_end_1; 53 | 54 | wire rtx_range_val_2; 55 | wire [`FLOW_WIN_IND_W-1:0] rtx_range_start_2; 56 | wire [`FLOW_WIN_IND_W-1:0] rtx_range_end_2; 57 | 58 | wire [`FLOW_SEQ_NUM_W-1:0] rtx_start; 59 | wire [`FLOW_SEQ_NUM_W-1:0] rtx_end; 60 | 61 | //********************************************************************************* 62 | // Logic 63 | //********************************************************************************* 64 | 65 | user_defined_incoming ud_inc (.pkt_type_in (pkt_type_in ), 66 | .pkt_data_in (pkt_data_in ), 67 | .cumulative_ack_in (cumulative_ack_in ), 68 | .selective_ack_in (selective_ack_in ), 69 | .sack_tx_id_in (sack_tx_id_in ), 70 | .now (now ), 71 | 72 | .valid_selective_ack (valid_selective_ack ), 73 | .new_c_acks_cnt (new_c_acks_cnt ), 74 | .old_wnd_start_in (old_wnd_start_in ), 75 | 76 | .acked_wnd_in (acked_wnd_in ), 77 | .rtx_wnd_in (rtx_wnd_in ), 78 | .tx_cnt_wnd_in (tx_cnt_wnd_in ), 79 | .wnd_start_in (wnd_start_in ), 80 | .wnd_size_in (wnd_size_in ), 81 | .next_new_in (next_new_in ), 82 | .rtx_timer_amnt_in (rtx_timer_amnt_in ), 83 | .total_tx_cnt_in (total_tx_cnt_in ), 84 | .user_cntxt_in (user_cntxt_in ), 85 | 86 | .mark_rtx (mark_rtx ), 87 | .rtx_start (rtx_start ), 88 | .rtx_end (rtx_end ), 89 | .wnd_size_out (wnd_size_out ), 90 | .reset_rtx_timer (reset_rtx_timer ), 91 | .rtx_timer_amnt_out (rtx_timer_amnt_out ), 92 | .user_cntxt_out (user_cntxt_out )); 93 | // rtx_wnd 94 | assign rtx_start_ind_tmp = rtx_start - wnd_start_in + wnd_start_ind_in; 95 | assign rtx_start_ind = {1'b0, rtx_start_ind_tmp[R_FLOW_WIN_IND_W-1:0]}; 96 | 97 | assign rtx_end_ind_tmp = rtx_end - wnd_start_in + wnd_start_ind_in; 98 | assign rtx_end_ind = {1'b0, rtx_end_ind_tmp[R_FLOW_WIN_IND_W-1:0]}; 99 | 100 | assign rtx_range_val_1 = 1'b1; 101 | assign rtx_range_start_1 = rtx_start_ind; 102 | assign rtx_range_end_1 = (rtx_end_ind >= rtx_start_ind) ? rtx_end_ind : `FLOW_WIN_SIZE; 103 | 104 | assign rtx_range_val_2 = rtx_end_ind < rtx_start_ind; 105 | assign rtx_range_start_2 = {(R_FLOW_WIN_IND_W+1){1'b0}}; 106 | assign rtx_range_end_2 = rtx_end_ind; 107 | 108 | genvar i; 109 | 110 | generate 111 | for (i = 0; i < `FLOW_WIN_SIZE; i = i + 1) begin: gen_rtx 112 | assign rtx_wnd_out[i] = ~acked_wnd_in[i] & 113 | ((mark_rtx & 114 | ((rtx_range_val_1 & i >= rtx_range_start_1 & i < rtx_range_end_1) | 115 | (rtx_range_val_2 & i >= rtx_range_start_2 & i < rtx_range_end_2))) 116 | ? 1'b1 : rtx_wnd_in[i]); 117 | end 118 | endgenerate 119 | 120 | // clogb2 function 121 | `include "clogb2.vh" 122 | endmodule 123 | -------------------------------------------------------------------------------- /src/dd_engine/event_processors/dd_next/dd_next.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module dd_next ( 4 | //// input interface 5 | 6 | // context 7 | input [`FLOW_WIN_SIZE-1:0] rtx_wnd_in, 8 | input [`TX_CNT_WIN_SIZE-1:0] tx_cnt_wnd_in, 9 | input [`FLOW_SEQ_NUM_W-1:0] next_new_in, 10 | input [`FLOW_WIN_IND_W-1:0] wnd_start_ind_in, 11 | input [`FLOW_SEQ_NUM_W-1:0] wnd_start_in, 12 | input [`FLOW_WIN_SIZE_W-1:0] wnd_size_in, 13 | input [`PKT_QUEUE_IND_W-1:0] pkt_queue_size_in, 14 | input [`FLOW_SEQ_NUM_W-1:0] total_tx_cnt_in, 15 | 16 | // output interface 17 | output [`FLOW_WIN_SIZE-1:0] rtx_wnd_out, 18 | output [`TX_CNT_WIN_SIZE-1:0] tx_cnt_wnd_out, 19 | output [`FLOW_SEQ_NUM_W-1:0] next_new_out, 20 | output [`PKT_QUEUE_IND_W-1:0] pkt_queue_size_out, 21 | output [`FLAG_W-1:0] back_pressure_out, 22 | output [`FLOW_SEQ_NUM_W-1:0] total_tx_cnt_out, 23 | 24 | output reg [`FLOW_SEQ_NUM_W-1:0] next_seq_out, 25 | output [`TX_CNT_W-1:0] next_seq_tx_id_out, 26 | output reg [`FLOW_WIN_IND_W-1:0] next_seq_ind_out 27 | ); 28 | 29 | //********************************************************************************* 30 | // Wires and Regs 31 | //********************************************************************************* 32 | 33 | wire [`FLOW_WIN_SIZE-1:0] wnd_mask; 34 | 35 | wire wnd_range_val_1; 36 | wire [`FLOW_WIN_IND_W-1:0] wnd_range_start_1; 37 | wire [`FLOW_WIN_IND_W-1:0] wnd_range_end_1; 38 | 39 | wire wnd_range_val_2; 40 | wire [`FLOW_WIN_IND_W-1:0] wnd_range_start_2; 41 | wire [`FLOW_WIN_IND_W-1:0] wnd_range_end_2; 42 | 43 | wire [`FLOW_WIN_SIZE-1:0] masked_rtx_wnd; 44 | wire [`FLOW_WIN_IND_W-1:0] first_rtx_ind; 45 | wire rtx_exists; 46 | 47 | reg [`FLOW_WIN_IND_W-1:0] tmp_next_seq_out; 48 | 49 | wire [`FLOW_WIN_IND_W-1:0] end_of_wnd_ind_tmp; 50 | wire [`FLOW_WIN_IND_W-1:0] end_of_wnd_ind; 51 | 52 | wire [`FLOW_SEQ_NUM_W-1:0] next_new_ind_tmp; 53 | wire [`FLOW_WIN_IND_W-1:0] next_new_ind; 54 | 55 | //********************************************************************************* 56 | // Logic 57 | //********************************************************************************* 58 | 59 | localparam R_FLOW_IND_W = `FLOW_WIN_IND_W-1; 60 | 61 | wire [`FLOW_SEQ_NUM_W-1:0] padded_wnd_size_in; 62 | assign padded_wnd_size_in = {{(`FLOW_SEQ_NUM_W - `FLOW_WIN_SIZE_W){1'b0}}, wnd_size_in}; 63 | 64 | // next new ind 65 | assign next_new_ind_tmp = next_new_in - wnd_start_in + wnd_start_ind_in; 66 | assign next_new_ind = {1'b0, next_new_ind_tmp[R_FLOW_IND_W-1:0]}; 67 | 68 | 69 | assign end_of_wnd_ind_tmp = wnd_start_ind_in + wnd_size_in; 70 | assign end_of_wnd_ind = {1'b0, end_of_wnd_ind_tmp[R_FLOW_IND_W-1:0]}; 71 | 72 | //// mask window 73 | assign end_of_wnd_ind_tmp = wnd_start_ind_in + wnd_size_in; 74 | assign end_of_wnd_ind = {1'b0, end_of_wnd_ind_tmp[R_FLOW_IND_W-1:0]}; 75 | 76 | // wnd mask 77 | assign wnd_range_val_1 = 1'b1; 78 | assign wnd_range_start_1 = wnd_start_ind_in; 79 | assign wnd_range_end_1 = (end_of_wnd_ind >= wnd_start_ind_in) ? end_of_wnd_ind : `FLOW_WIN_SIZE; 80 | 81 | assign wnd_range_val_2 = end_of_wnd_ind < wnd_start_ind_in; 82 | assign wnd_range_start_2 = {(R_FLOW_IND_W+1){1'b0}}; 83 | assign wnd_range_end_2 = end_of_wnd_ind; 84 | 85 | genvar i; 86 | 87 | // create mask 88 | generate 89 | for (i = 0; i < `FLOW_WIN_SIZE; i = i + 1) begin: gen_wnd_mask 90 | assign wnd_mask[i] = (wnd_range_val_1 & (i >= wnd_range_start_1) & (i < wnd_range_end_1)) | 91 | (wnd_range_val_2 & (i >= wnd_range_start_2) & (i < wnd_range_end_2)) ; 92 | end 93 | endgenerate 94 | 95 | 96 | // mask rtx_wnd 97 | generate 98 | for (i = 0; i < `FLOW_WIN_SIZE; i = i + 1) begin: gen_masekd_rtx_wnd 99 | assign masked_rtx_wnd[i] = rtx_wnd_in[i] & wnd_mask[i]; 100 | end 101 | endgenerate 102 | 103 | // tx cnt wnd 104 | generate 105 | for (i = 0; i < `FLOW_WIN_SIZE; i = i + 1) begin: gen_tx_cnt_wnd 106 | assign tx_cnt_wnd_out[((i + 1) * `TX_CNT_W) - 1 -: `TX_CNT_W] = 107 | (i == next_seq_ind_out & rtx_exists & 108 | tx_cnt_wnd_in[((i + 1)*`TX_CNT_W)-1-:`TX_CNT_W]< `MAX_TX_CNT) ? tx_cnt_wnd_in[((i + 1) * `TX_CNT_W) - 1 -: `TX_CNT_W] + {{(`TX_CNT_W - 1){1'b0}}, 1'b1}: 109 | (i == next_seq_ind_out & !rtx_exists) ? {`TX_CNT_W{1'b0}} 110 | : tx_cnt_wnd_in[((i + 1) * `TX_CNT_W) - 1 -: `TX_CNT_W]; 111 | end 112 | endgenerate 113 | 114 | // find first to retransmit 115 | ff_wnd #( 116 | .VECT_WIDTH (`FLOW_WIN_SIZE ), 117 | .VECT_IND_WIDTH (`FLOW_WIN_IND_W ), 118 | .BLOCK_WIDTH (4 ) 119 | ) 120 | find_first ( 121 | .vect_in (masked_rtx_wnd ), 122 | .select_set_in (1'b1 ), 123 | .head_in (wnd_start_ind_in ), 124 | .val_out (rtx_exists ), 125 | .ind_out (first_rtx_ind ) 126 | ); 127 | 128 | 129 | // update rtx_wnd if there is anything to retransmit 130 | generate 131 | for (i = 0; i < `FLOW_WIN_SIZE; i = i + 1) begin: gen_rtx_wnd 132 | assign rtx_wnd_out[i] = (rtx_exists & (i == first_rtx_ind)) ? 1'b0 : masked_rtx_wnd[i]; 133 | end 134 | endgenerate 135 | 136 | // Decide what next sequence number should be: 137 | // if there is anything to retransmit, then retransmit 138 | // else if you have more new to send, send new 139 | // else output None 140 | always @(*) begin 141 | if (rtx_exists) begin 142 | tmp_next_seq_out = `FLOW_WIN_SIZE + first_rtx_ind - wnd_start_ind_in; 143 | next_seq_out = {{(`FLOW_SEQ_NUM_W - R_FLOW_IND_W){1'b0}}, tmp_next_seq_out[R_FLOW_IND_W-1:0]} + wnd_start_in; 144 | end 145 | else if (next_new_in < wnd_start_in + padded_wnd_size_in) begin 146 | next_seq_out = next_new_in; 147 | end 148 | else begin 149 | next_seq_out = `FLOW_SEQ_NONE; 150 | end 151 | end 152 | 153 | always @(*) begin 154 | if (rtx_exists) begin 155 | next_seq_ind_out = first_rtx_ind; 156 | end 157 | else if (next_new_in < wnd_start_in + padded_wnd_size_in) begin 158 | next_seq_ind_out = next_new_ind; 159 | end 160 | else begin 161 | next_seq_ind_out = end_of_wnd_ind; 162 | end 163 | end 164 | 165 | assign next_seq_tx_id_out = tx_cnt_wnd_out[(next_seq_ind_out + 1) * `TX_CNT_W - 1 -: `TX_CNT_W]; 166 | 167 | //// Update Context 168 | wire [`FLOW_SEQ_NUM_W-1:0] end_wnd_seq; 169 | assign end_wnd_seq = wnd_start_in + padded_wnd_size_in; 170 | 171 | assign next_new_out = next_new_in + ((~rtx_exists) & (next_new_in < end_wnd_seq) ? 1 : 0); 172 | 173 | // pkt_queue_size_out 174 | assign pkt_queue_size_out = pkt_queue_size_in + {{(`PKT_QUEUE_IND_W - 1){1'b0}}, 1'b1}; 175 | 176 | // back_pressure 177 | assign back_pressure_out = pkt_queue_size_out >= `PKT_QUEUE_STOP_THRESH; 178 | 179 | assign total_tx_cnt_out = next_seq_out == `FLOW_SEQ_NONE ? total_tx_cnt_in : total_tx_cnt_in + 1; 180 | // clogb2 function 181 | `include "clogb2.vh" 182 | 183 | endmodule 184 | -------------------------------------------------------------------------------- /src/dd_engine/event_processors/dd_timeout/dd_timeout.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module dd_timeout ( 4 | //// input 5 | input timeout_expired, 6 | input [`TIME_W-1:0] now, 7 | input [`FLOW_WIN_SIZE-1:0] rtx_wnd_in, 8 | input [`FLOW_WIN_SIZE-1:0] acked_wnd_in, 9 | input [`TX_CNT_WIN_SIZE-1:0] tx_cnt_wnd_in, 10 | input [`FLOW_SEQ_NUM_W-1:0] next_new_in, 11 | input [`FLOW_WIN_IND_W-1:0] wnd_start_ind_in, 12 | input [`FLOW_SEQ_NUM_W-1:0] wnd_start_in, 13 | input [`FLOW_WIN_SIZE_W-1:0] wnd_size_in, 14 | input [`TIMER_W-1:0] rtx_timer_amnt_in, 15 | input [`FLOW_SEQ_NUM_W-1:0] total_tx_cnt_in, 16 | input [`USER_CONTEXT_W-1:0] user_cntxt_in, 17 | 18 | //// output 19 | 20 | output [`FLOW_WIN_SIZE-1:0] rtx_wnd_out, 21 | output [`FLOW_WIN_SIZE_W-1:0] wnd_size_out, 22 | output [`TIMER_W-1:0] rtx_timer_amnt_out, 23 | output [`USER_CONTEXT_W-1:0] user_cntxt_out 24 | ); 25 | 26 | 27 | localparam R_FLOW_WIN_IND_W = `FLOW_WIN_IND_W - 1; 28 | 29 | //********************************************************************************* 30 | // Wires and Regs 31 | //********************************************************************************* 32 | 33 | wire mark_rtx; 34 | wire [`FLOW_SEQ_NUM_W-1:0] rtx_start_ind_tmp; 35 | wire [`FLOW_WIN_IND_W-1:0] rtx_start_ind; 36 | wire [`FLOW_SEQ_NUM_W-1:0] rtx_end_ind_tmp; 37 | wire [`FLOW_WIN_IND_W-1:0] rtx_end_ind; 38 | 39 | wire rtx_range_val_1; 40 | wire [`FLOW_WIN_IND_W-1:0] rtx_range_start_1; 41 | wire [`FLOW_WIN_IND_W-1:0] rtx_range_end_1; 42 | 43 | wire rtx_range_val_2; 44 | wire [`FLOW_WIN_IND_W-1:0] rtx_range_start_2; 45 | wire [`FLOW_WIN_IND_W-1:0] rtx_range_end_2; 46 | 47 | wire [`FLOW_SEQ_NUM_W-1:0] rtx_start; 48 | wire [`FLOW_SEQ_NUM_W-1:0] rtx_end; 49 | 50 | //********************************************************************************* 51 | // Logic 52 | //********************************************************************************* 53 | 54 | user_defined_timeout ud_to ( 55 | .timeout_expired (timeout_expired ), 56 | .now (now ), 57 | .acked_wnd_in (acked_wnd_in ), 58 | .rtx_wnd_in (rtx_wnd_in ), 59 | .tx_cnt_wnd_in (tx_cnt_wnd_in ), 60 | .wnd_start_in (wnd_start_in ), 61 | .wnd_size_in (wnd_size_in ), 62 | .next_new_in (next_new_in ), 63 | .rtx_timer_amnt_in (rtx_timer_amnt_in ), 64 | .total_tx_cnt_in (total_tx_cnt_in ), 65 | .user_cntxt_in (user_cntxt_in ), 66 | 67 | .mark_rtx (mark_rtx ), 68 | .rtx_start (rtx_start ), 69 | .rtx_end (rtx_end ), 70 | .wnd_size_out (wnd_size_out ), 71 | .rtx_timer_amnt_out (rtx_timer_amnt_out ), 72 | .user_cntxt_out (user_cntxt_out )); 73 | 74 | // rtx_wnd 75 | assign rtx_start_ind_tmp = rtx_start - wnd_start_in + wnd_start_ind_in; 76 | assign rtx_start_ind = {1'b0, rtx_start_ind_tmp[R_FLOW_WIN_IND_W-1:0]}; 77 | 78 | assign rtx_end_ind_tmp = rtx_end - wnd_start_in + wnd_start_ind_in; 79 | assign rtx_end_ind = {1'b0, rtx_end_ind_tmp[R_FLOW_WIN_IND_W-1:0]}; 80 | 81 | assign rtx_range_val_1 = 1'b1; 82 | assign rtx_range_start_1 = rtx_start_ind; 83 | assign rtx_range_end_1 = (rtx_end_ind >= rtx_start_ind) ? rtx_end_ind : `FLOW_WIN_SIZE; 84 | 85 | assign rtx_range_val_2 = rtx_end_ind < rtx_start_ind; 86 | assign rtx_range_start_2 = {(R_FLOW_WIN_IND_W + 1){1'b0}}; 87 | assign rtx_range_end_2 = rtx_end_ind; 88 | 89 | //// Update rtx_wnd with packets decided as lost 90 | genvar i; 91 | 92 | // update rtx_wnd 93 | generate 94 | for (i = 0; i < `FLOW_WIN_SIZE; i = i + 1) begin: gen_rtx 95 | assign rtx_wnd_out[i] = (~acked_wnd_in[i]) & ((mark_rtx & 96 | ((rtx_range_val_1 & i >= rtx_range_start_1 & i < rtx_range_end_1) | 97 | (rtx_range_val_2 & i >= rtx_range_start_2 & i < rtx_range_end_2))) 98 | ? 1'b1 : rtx_wnd_in[i]); 99 | end 100 | endgenerate 101 | 102 | // clogb2 function 103 | `include "clogb2.vh" 104 | 105 | endmodule 106 | -------------------------------------------------------------------------------- /src/fifos/fifo_1w/fifo_1w.v: -------------------------------------------------------------------------------- 1 | // Description: 2 | // FIFO with first-word fall-through parameter 3 | 4 | module fifo_1w # ( 5 | parameter FIFO_WIDTH = 0, 6 | parameter FIFO_DEPTH = 0, 7 | parameter CNT_WIDTH = (clogb2(FIFO_DEPTH) + 1) 8 | ) ( 9 | input clk, 10 | input rst_n, 11 | 12 | input w_val, 13 | input [FIFO_WIDTH-1:0] w_data, 14 | 15 | input r_val, 16 | output [FIFO_WIDTH-1:0] r_data, 17 | 18 | output [CNT_WIDTH-1:0] size, 19 | output reg full, 20 | output wire data_avail 21 | ); 22 | 23 | localparam PTR_WIDTH = clogb2(FIFO_DEPTH); 24 | localparam ELEM_NONE = {FIFO_WIDTH{1'b1}}; 25 | 26 | //----------------------------------------------------------------------------- 27 | // Internal Signals 28 | 29 | reg [FIFO_WIDTH-1:0] fifo [FIFO_DEPTH-1:0]; 30 | reg [PTR_WIDTH-1:0] head_ptr; 31 | reg [PTR_WIDTH-1:0] tail_ptr; 32 | reg [CNT_WIDTH-1:0] used_cnt; 33 | reg empty; 34 | 35 | wire [PTR_WIDTH:0] head_ptr_next; 36 | wire [PTR_WIDTH:0] tail_ptr_next; 37 | wire [CNT_WIDTH:0] used_cnt_next; 38 | wire [CNT_WIDTH:0] used_cnt_tmp; 39 | 40 | wire srtd_w_val_0; 41 | wire [FIFO_WIDTH-1:0] srtd_w_data_0; 42 | 43 | wire added_cnt; 44 | //----------------------------------------------------------------------------- 45 | // Combinational Logic 46 | 47 | assign srtd_w_val_0 = w_val & used_cnt < FIFO_DEPTH-1; 48 | 49 | assign srtd_w_data_0 = w_data; 50 | 51 | assign added_cnt = srtd_w_val_0; 52 | 53 | assign head_ptr_next = head_ptr + {{PTR_WIDTH-1{1'b0}}, 1'b1}; 54 | assign tail_ptr_next = tail_ptr + {{PTR_WIDTH-1{1'b0}}, added_cnt}; 55 | 56 | assign used_cnt_tmp = used_cnt + {{CNT_WIDTH-1{1'b0}}, added_cnt}; 57 | assign used_cnt_next = ((used_cnt_tmp == {(CNT_WIDTH+1){1'b0}}) & r_val) ? {(CNT_WIDTH+1){1'b0}} : used_cnt_tmp - {{CNT_WIDTH{1'b0}}, r_val}; 58 | 59 | assign r_data = empty & srtd_w_val_0 ? srtd_w_data_0 : 60 | empty & ~srtd_w_val_0 ? ELEM_NONE : fifo[head_ptr]; 61 | 62 | assign data_avail = (empty & srtd_w_val_0) | ~empty; 63 | assign size = used_cnt; 64 | //----------------------------------------------------------------------------- 65 | // Sequential Logic 66 | always @(posedge clk) begin 67 | if (~rst_n) begin 68 | head_ptr <= {PTR_WIDTH{1'b0}}; 69 | end 70 | else begin 71 | head_ptr <= ((~empty & r_val) | (empty & srtd_w_val_0 & r_val))? head_ptr_next[PTR_WIDTH-1:0] : head_ptr; 72 | end 73 | end 74 | 75 | 76 | always @(posedge clk) begin 77 | if (~rst_n) begin 78 | tail_ptr <= {PTR_WIDTH{1'b0}}; 79 | end 80 | else begin 81 | tail_ptr <= full ? tail_ptr : tail_ptr_next[PTR_WIDTH-1:0]; 82 | end 83 | end 84 | 85 | 86 | always @(posedge clk) begin 87 | if (~rst_n) begin 88 | used_cnt <= {CNT_WIDTH{1'b0}}; 89 | end 90 | else begin 91 | used_cnt <= used_cnt_next >= FIFO_DEPTH - 1 ? FIFO_DEPTH - 1 : used_cnt_next; 92 | end 93 | end 94 | 95 | always @(posedge clk) begin 96 | if (~rst_n) begin 97 | empty <= 1'b1; 98 | full <= 1'b0; 99 | end 100 | else begin 101 | empty <= used_cnt_next == 0 ? 1'b1 : 1'b0; 102 | full <= used_cnt_next >= (FIFO_DEPTH-1) ? 1'b1 : 1'b0; 103 | end 104 | end 105 | 106 | 107 | generate begin 108 | genvar ii; 109 | for (ii = 0; ii < FIFO_DEPTH; ii = ii + 1) begin: fifo_gen 110 | always @(posedge clk) begin 111 | if (~rst_n) begin 112 | fifo[ii] <= ELEM_NONE; 113 | end 114 | else begin 115 | fifo[ii] <= srtd_w_val_0 & (ii == tail_ptr) ? srtd_w_data_0 : fifo[ii]; 116 | end 117 | end 118 | end 119 | end 120 | endgenerate 121 | 122 | // clogb2 function 123 | `include "clogb2.vh" 124 | 125 | endmodule 126 | -------------------------------------------------------------------------------- /src/fifos/fifo_2w/fifo_2w.v: -------------------------------------------------------------------------------- 1 | // Description: 2 | // FIFO with first-word fall-through parameter 3 | 4 | module fifo_2w # ( 5 | parameter FIFO_WIDTH = 0, 6 | parameter FIFO_DEPTH = 0, 7 | parameter CNT_WIDTH = (clogb2(FIFO_DEPTH) + 1) 8 | ) ( 9 | input clk, 10 | input rst_n, 11 | 12 | input w_val_0, 13 | input [FIFO_WIDTH-1:0] w_data_0, 14 | 15 | input w_val_1, 16 | input [FIFO_WIDTH-1:0] w_data_1, 17 | 18 | input r_val, 19 | output [FIFO_WIDTH-1:0] r_data, 20 | 21 | output [CNT_WIDTH-1:0] size, 22 | output reg full, 23 | output wire data_avail 24 | ); 25 | 26 | localparam PTR_WIDTH = clogb2(FIFO_DEPTH); 27 | localparam ELEM_NONE = {FIFO_WIDTH{1'b1}}; 28 | 29 | //----------------------------------------------------------------------------- 30 | // Internal Signals 31 | 32 | reg [FIFO_WIDTH-1:0] fifo [FIFO_DEPTH-1:0]; 33 | reg [PTR_WIDTH-1:0] head_ptr; 34 | reg [PTR_WIDTH-1:0] tail_ptr; 35 | reg [CNT_WIDTH-1:0] used_cnt; 36 | reg empty; 37 | 38 | wire [PTR_WIDTH:0] head_ptr_next; 39 | wire [PTR_WIDTH:0] tail_ptr_next; 40 | wire [CNT_WIDTH:0] used_cnt_next; 41 | wire [CNT_WIDTH:0] used_cnt_tmp; 42 | 43 | wire srtd_w_val_0; 44 | wire [FIFO_WIDTH-1:0] srtd_w_data_0; 45 | 46 | wire srtd_w_val_1; 47 | wire [FIFO_WIDTH-1:0] srtd_w_data_1; 48 | 49 | wire [PTR_WIDTH-1:0] w_ind_1; 50 | wire [PTR_WIDTH:0] w_ind_tmp_1; 51 | 52 | wire [2:0] added_cnt; 53 | //----------------------------------------------------------------------------- 54 | // Combinational Logic 55 | 56 | assign srtd_w_val_0 = (w_val_0 | w_val_1) & (used_cnt < FIFO_DEPTH-1); 57 | assign srtd_w_val_1 = (w_val_0 & w_val_1) & (used_cnt < FIFO_DEPTH-2); 58 | 59 | assign srtd_w_data_0 = w_val_0 ? w_data_0 : w_data_1; 60 | assign srtd_w_data_1 = w_data_1; 61 | 62 | assign added_cnt = srtd_w_val_1 ? 3'b010 : 63 | srtd_w_val_0 ? 3'b001 : 3'b000; 64 | 65 | assign head_ptr_next = head_ptr + {{PTR_WIDTH-1{1'b0}}, 1'b1}; 66 | assign tail_ptr_next = tail_ptr + {{(PTR_WIDTH-2){1'b0}}, added_cnt}; 67 | 68 | assign used_cnt_tmp = used_cnt + {{(CNT_WIDTH-2){1'b0}}, added_cnt}; 69 | assign used_cnt_next = ((used_cnt_tmp == {(CNT_WIDTH+1){1'b0}}) & r_val) ? {(CNT_WIDTH+1){1'b0}} : used_cnt_tmp - {{CNT_WIDTH{1'b0}}, r_val}; 70 | 71 | assign r_data = empty & srtd_w_val_0 ? srtd_w_data_0 : 72 | empty & ~srtd_w_val_0 ? ELEM_NONE : fifo[head_ptr]; 73 | 74 | assign data_avail = (empty & srtd_w_val_0) | ~empty; 75 | 76 | assign w_ind_tmp_1 = tail_ptr + {{PTR_WIDTH-1{1'b0}}, 1'b1}; 77 | 78 | assign w_ind_1 = w_ind_tmp_1[PTR_WIDTH-1:0]; 79 | 80 | assign size = used_cnt; 81 | //----------------------------------------------------------------------------- 82 | // Sequential Logic 83 | always @(posedge clk) begin 84 | if (~rst_n) begin 85 | head_ptr <= {PTR_WIDTH{1'b0}}; 86 | end 87 | else begin 88 | head_ptr <= ((~empty & r_val) | (empty & srtd_w_val_0 & r_val))? head_ptr_next[PTR_WIDTH-1:0] : head_ptr; 89 | end 90 | end 91 | 92 | 93 | always @(posedge clk) begin 94 | if (~rst_n) begin 95 | tail_ptr <= {PTR_WIDTH{1'b0}}; 96 | end 97 | else begin 98 | tail_ptr <= full ? tail_ptr : tail_ptr_next[PTR_WIDTH-1:0]; 99 | end 100 | end 101 | 102 | 103 | always @(posedge clk) begin 104 | if (~rst_n) begin 105 | used_cnt <= {(PTR_WIDTH+1){1'b0}}; 106 | end 107 | else begin 108 | used_cnt <= used_cnt_next >= FIFO_DEPTH - 1 ? FIFO_DEPTH - 1 : used_cnt_next; 109 | end 110 | end 111 | 112 | always @(posedge clk) begin 113 | if (~rst_n) begin 114 | empty <= 1'b1; 115 | full <= 1'b0; 116 | end 117 | else begin 118 | empty <= used_cnt_next == 0 ? 1'b1 : 1'b0; 119 | full <= used_cnt_next >= (FIFO_DEPTH-1) ? 1'b1 : 1'b0; 120 | end 121 | end 122 | 123 | 124 | generate begin 125 | genvar ii; 126 | for (ii = 0; ii < FIFO_DEPTH; ii = ii + 1) begin: fifo_gen 127 | always @(posedge clk) begin 128 | if (~rst_n) begin 129 | fifo[ii] <= ELEM_NONE; 130 | end 131 | else begin 132 | fifo[ii] <= srtd_w_val_0 & (ii == tail_ptr) ? srtd_w_data_0 : 133 | srtd_w_val_1 & (ii == w_ind_1) ? srtd_w_data_1 : fifo[ii]; 134 | end 135 | end 136 | end 137 | end 138 | endgenerate 139 | 140 | // clogb2 function 141 | `include "clogb2.vh" 142 | 143 | endmodule 144 | -------------------------------------------------------------------------------- /src/fifos/fifo_3w/fifo_3w.v: -------------------------------------------------------------------------------- 1 | // Description: 2 | // FIFO with first-word fall-through parameter 3 | 4 | module fifo_3w # ( 5 | parameter FIFO_WIDTH = 0, 6 | parameter FIFO_DEPTH = 0, 7 | parameter CNT_WIDTH = (clogb2(FIFO_DEPTH) + 1) 8 | ) ( 9 | input clk, 10 | input rst_n, 11 | 12 | input w_val_0, 13 | input [FIFO_WIDTH-1:0] w_data_0, 14 | 15 | input w_val_1, 16 | input [FIFO_WIDTH-1:0] w_data_1, 17 | 18 | input w_val_2, 19 | input [FIFO_WIDTH-1:0] w_data_2, 20 | 21 | input r_val, 22 | output [FIFO_WIDTH-1:0] r_data, 23 | 24 | output [CNT_WIDTH-1:0] size, 25 | output reg full, 26 | output wire data_avail 27 | ); 28 | 29 | localparam PTR_WIDTH = clogb2(FIFO_DEPTH); 30 | localparam ELEM_NONE = {FIFO_WIDTH{1'b1}}; 31 | 32 | //----------------------------------------------------------------------------- 33 | // Internal Signals 34 | 35 | reg [FIFO_WIDTH-1:0] fifo [FIFO_DEPTH-1:0]; 36 | reg [PTR_WIDTH-1:0] head_ptr; 37 | reg [PTR_WIDTH-1:0] tail_ptr; 38 | reg [CNT_WIDTH-1:0] used_cnt; 39 | reg empty; 40 | 41 | wire [PTR_WIDTH:0] head_ptr_next; 42 | wire [PTR_WIDTH:0] tail_ptr_next; 43 | wire [CNT_WIDTH:0] used_cnt_next; 44 | wire [CNT_WIDTH:0] used_cnt_tmp; 45 | 46 | wire srtd_w_val_0; 47 | wire [FIFO_WIDTH-1:0] srtd_w_data_0; 48 | 49 | wire srtd_w_val_1; 50 | wire [FIFO_WIDTH-1:0] srtd_w_data_1; 51 | 52 | wire srtd_w_val_2; 53 | wire [FIFO_WIDTH-1:0] srtd_w_data_2; 54 | 55 | wire [PTR_WIDTH-1:0] w_ind_1, w_ind_2; 56 | wire [PTR_WIDTH:0] w_ind_tmp_1, w_ind_tmp_2; 57 | 58 | wire [2:0] added_cnt; 59 | //----------------------------------------------------------------------------- 60 | // Combinational Logic 61 | 62 | assign srtd_w_val_0 = (w_val_0 | w_val_1 | w_val_2) & (used_cnt < FIFO_DEPTH-1); 63 | assign srtd_w_val_1 = ((w_val_0 & w_val_1) | (w_val_0 & w_val_2) | 64 | (w_val_1 & w_val_2)) & (used_cnt < FIFO_DEPTH-2); 65 | assign srtd_w_val_2 = (w_val_0 & w_val_1 & w_val_2) & (used_cnt < FIFO_DEPTH-3); 66 | 67 | assign srtd_w_data_0 = w_val_0 ? w_data_0 : 68 | w_val_1 ? w_data_1 : w_data_2; 69 | 70 | assign srtd_w_data_1 = (w_val_1 & w_val_0) ? w_data_1: w_data_2; 71 | 72 | assign srtd_w_data_2 = w_data_2; 73 | 74 | assign added_cnt = srtd_w_val_2 ? 3'b011 : 75 | srtd_w_val_1 ? 3'b010 : 76 | srtd_w_val_0 ? 3'b001 : 3'b000; 77 | 78 | assign head_ptr_next = head_ptr + {{PTR_WIDTH-1{1'b0}}, 1'b1}; 79 | assign tail_ptr_next = tail_ptr + {{(PTR_WIDTH-2){1'b0}}, added_cnt}; 80 | 81 | assign used_cnt_tmp = used_cnt + {{(CNT_WIDTH-2){1'b0}}, added_cnt}; 82 | assign used_cnt_next = ((used_cnt_tmp == {(CNT_WIDTH+1){1'b0}}) & r_val) ? {(CNT_WIDTH+1){1'b0}} : used_cnt_tmp - {{CNT_WIDTH{1'b0}}, r_val}; 83 | 84 | assign r_data = empty & srtd_w_val_0 ? srtd_w_data_0 : 85 | empty & ~srtd_w_val_0 ? ELEM_NONE : fifo[head_ptr]; 86 | 87 | assign data_avail = (empty & srtd_w_val_0) | ~empty; 88 | 89 | assign w_ind_tmp_1 = tail_ptr + {{PTR_WIDTH-1{1'b0}}, 1'b1}; 90 | assign w_ind_tmp_2 = tail_ptr + {{PTR_WIDTH-2{1'b0}}, 2'b10}; 91 | 92 | assign w_ind_1 = w_ind_tmp_1[PTR_WIDTH-1:0]; 93 | assign w_ind_2 = w_ind_tmp_2[PTR_WIDTH-1:0]; 94 | 95 | assign size = used_cnt; 96 | //----------------------------------------------------------------------------- 97 | // Sequential Logic 98 | always @(posedge clk) begin 99 | if (~rst_n) begin 100 | head_ptr <= {PTR_WIDTH{1'b0}}; 101 | end 102 | else begin 103 | head_ptr <= ((~empty & r_val) | (empty & srtd_w_val_0 & r_val))? head_ptr_next[PTR_WIDTH-1:0] : head_ptr; 104 | end 105 | end 106 | 107 | 108 | always @(posedge clk) begin 109 | if (~rst_n) begin 110 | tail_ptr <= {PTR_WIDTH{1'b0}}; 111 | end 112 | else begin 113 | tail_ptr <= full ? tail_ptr : tail_ptr_next[PTR_WIDTH-1:0]; 114 | end 115 | end 116 | 117 | 118 | always @(posedge clk) begin 119 | if (~rst_n) begin 120 | used_cnt <= {CNT_WIDTH{1'b0}}; 121 | end 122 | else begin 123 | used_cnt <= used_cnt_next >= FIFO_DEPTH - 1 ? FIFO_DEPTH - 1 : used_cnt_next; 124 | end 125 | end 126 | 127 | always @(posedge clk) begin 128 | if (~rst_n) begin 129 | empty <= 1'b1; 130 | full <= 1'b0; 131 | end 132 | else begin 133 | empty <= used_cnt_next == 0 ? 1'b1 : 1'b0; 134 | full <= used_cnt_next >= (FIFO_DEPTH-1) ? 1'b1 : 1'b0; 135 | end 136 | end 137 | 138 | 139 | generate begin 140 | genvar ii; 141 | for (ii = 0; ii < FIFO_DEPTH; ii = ii + 1) begin: fifo_gen 142 | always @(posedge clk) begin 143 | if (~rst_n) begin 144 | fifo[ii] <= ELEM_NONE; 145 | end 146 | else begin 147 | fifo[ii] <= srtd_w_val_0 & (ii == tail_ptr) ? srtd_w_data_0 : 148 | srtd_w_val_1 & (ii == w_ind_1) ? srtd_w_data_1 : 149 | srtd_w_val_2 & (ii == w_ind_2) ? srtd_w_data_2 : fifo[ii]; 150 | end 151 | end 152 | end 153 | end 154 | endgenerate 155 | 156 | // clogb2 function 157 | `include "clogb2.vh" 158 | 159 | endmodule 160 | -------------------------------------------------------------------------------- /src/fifos/fifo_4w/fifo_4w.v: -------------------------------------------------------------------------------- 1 | // Description: 2 | // FIFO with first-word fall-through parameter 3 | 4 | module fifo_4w # ( 5 | parameter FIFO_WIDTH = 0, 6 | parameter FIFO_DEPTH = 0, 7 | parameter CNT_WIDTH = (clogb2(FIFO_DEPTH) + 1) 8 | ) ( 9 | input clk, 10 | input rst_n, 11 | 12 | input w_val_0, 13 | input [FIFO_WIDTH-1:0] w_data_0, 14 | 15 | input w_val_1, 16 | input [FIFO_WIDTH-1:0] w_data_1, 17 | 18 | input w_val_2, 19 | input [FIFO_WIDTH-1:0] w_data_2, 20 | 21 | input w_val_3, 22 | input [FIFO_WIDTH-1:0] w_data_3, 23 | 24 | input r_val, 25 | output [FIFO_WIDTH-1:0] r_data, 26 | 27 | output [CNT_WIDTH-1:0] size, 28 | output reg full, 29 | output wire data_avail 30 | ); 31 | 32 | localparam PTR_WIDTH = clogb2(FIFO_DEPTH); 33 | localparam ELEM_NONE = {FIFO_WIDTH{1'b1}}; 34 | 35 | //----------------------------------------------------------------------------- 36 | // Internal Signals 37 | 38 | reg [FIFO_WIDTH-1:0] fifo [FIFO_DEPTH-1:0]; 39 | reg [PTR_WIDTH-1:0] head_ptr; 40 | reg [PTR_WIDTH-1:0] tail_ptr; 41 | reg [CNT_WIDTH-1:0] used_cnt; 42 | reg empty; 43 | 44 | wire [PTR_WIDTH:0] head_ptr_next; 45 | wire [PTR_WIDTH:0] tail_ptr_next; 46 | wire [CNT_WIDTH:0] used_cnt_next; 47 | wire [CNT_WIDTH:0] used_cnt_tmp; 48 | 49 | wire srtd_w_val_0; 50 | wire [FIFO_WIDTH-1:0] srtd_w_data_0; 51 | 52 | wire srtd_w_val_1; 53 | wire [FIFO_WIDTH-1:0] srtd_w_data_1; 54 | 55 | wire srtd_w_val_2; 56 | wire [FIFO_WIDTH-1:0] srtd_w_data_2; 57 | 58 | wire srtd_w_val_3; 59 | wire [FIFO_WIDTH-1:0] srtd_w_data_3; 60 | 61 | wire [PTR_WIDTH-1:0] w_ind_1, w_ind_2, w_ind_3; 62 | wire [PTR_WIDTH:0] w_ind_tmp_1, w_ind_tmp_2, w_ind_tmp_3; 63 | 64 | wire [2:0] added_cnt; 65 | //----------------------------------------------------------------------------- 66 | // Combinational Logic 67 | 68 | assign srtd_w_val_0 = (w_val_0 | w_val_1 | w_val_2 | w_val_3) & (used_cnt < FIFO_DEPTH-1); 69 | assign srtd_w_val_1 = ((w_val_0 & w_val_1) | (w_val_0 & w_val_2) | 70 | (w_val_0 & w_val_3) | (w_val_1 & w_val_2) | 71 | (w_val_1 & w_val_3) | (w_val_2 & w_val_3)) & (used_cnt < FIFO_DEPTH-2); 72 | assign srtd_w_val_2 = ((w_val_0 & w_val_1 & w_val_2) | (w_val_0 & w_val_1 & w_val_3) | 73 | (w_val_0 & w_val_2 & w_val_3) | (w_val_1 & w_val_2 & w_val_3)) & (used_cnt < FIFO_DEPTH-3); 74 | assign srtd_w_val_3 = (w_val_0 & w_val_1 & w_val_2 & w_val_3) & (used_cnt < FIFO_DEPTH-4); 75 | 76 | assign srtd_w_data_0 = w_val_0 ? w_data_0 : 77 | w_val_1 ? w_data_1 : 78 | w_val_2 ? w_data_2 : 79 | w_data_3; 80 | 81 | assign srtd_w_data_1 = (w_val_1 & w_val_0) ? w_data_1: 82 | (w_val_2 & (w_val_1 | w_val_0)) ? w_data_2: w_data_3; 83 | 84 | assign srtd_w_data_2 = (w_val_0 & w_val_1 & w_val_2) ? w_data_2: w_data_3; 85 | 86 | assign srtd_w_data_3 = w_data_3; 87 | 88 | assign added_cnt = srtd_w_val_3 ? 3'b100 : 89 | srtd_w_val_2 ? 3'b011 : 90 | srtd_w_val_1 ? 3'b010 : 91 | srtd_w_val_0 ? 3'b001 : 3'b000; 92 | 93 | assign head_ptr_next = head_ptr + {{PTR_WIDTH-1{1'b0}}, 1'b1}; 94 | assign tail_ptr_next = tail_ptr + {{(PTR_WIDTH-2){1'b0}}, added_cnt}; 95 | 96 | assign used_cnt_tmp = used_cnt + {{(CNT_WIDTH-2){1'b0}}, added_cnt}; 97 | assign used_cnt_next = ((used_cnt_tmp == {(CNT_WIDTH+1){1'b0}}) & r_val) ? {(CNT_WIDTH+1){1'b0}} : used_cnt_tmp - {{CNT_WIDTH{1'b0}}, r_val}; 98 | 99 | assign r_data = empty & srtd_w_val_0 ? srtd_w_data_0 : 100 | empty & ~srtd_w_val_0 ? ELEM_NONE : fifo[head_ptr]; 101 | 102 | assign data_avail = (empty & srtd_w_val_0) | ~empty; 103 | 104 | assign w_ind_tmp_1 = tail_ptr + {{PTR_WIDTH-1{1'b0}}, 1'b1}; 105 | assign w_ind_tmp_2 = tail_ptr + {{PTR_WIDTH-2{1'b0}}, 2'b10}; 106 | assign w_ind_tmp_3 = tail_ptr + {{PTR_WIDTH-2{1'b0}}, 2'b11}; 107 | 108 | assign w_ind_1 = w_ind_tmp_1[PTR_WIDTH-1:0]; 109 | assign w_ind_2 = w_ind_tmp_2[PTR_WIDTH-1:0]; 110 | assign w_ind_3 = w_ind_tmp_3[PTR_WIDTH-1:0]; 111 | 112 | assign size = used_cnt; 113 | //----------------------------------------------------------------------------- 114 | // Sequential Logic 115 | always @(posedge clk) begin 116 | if (~rst_n) begin 117 | head_ptr <= {PTR_WIDTH{1'b0}}; 118 | end 119 | else begin 120 | head_ptr <= ((~empty & r_val) | (empty & srtd_w_val_0 & r_val))? head_ptr_next[PTR_WIDTH-1:0] : head_ptr; 121 | end 122 | end 123 | 124 | 125 | always @(posedge clk) begin 126 | if (~rst_n) begin 127 | tail_ptr <= {PTR_WIDTH{1'b0}}; 128 | end 129 | else begin 130 | tail_ptr <= full ? tail_ptr : tail_ptr_next[PTR_WIDTH-1:0]; 131 | end 132 | end 133 | 134 | 135 | always @(posedge clk) begin 136 | if (~rst_n) begin 137 | used_cnt <= {CNT_WIDTH{1'b0}}; 138 | end 139 | else begin 140 | used_cnt <= used_cnt_next >= FIFO_DEPTH - 1 ? FIFO_DEPTH - 1 : used_cnt_next; 141 | end 142 | end 143 | 144 | always @(posedge clk) begin 145 | if (~rst_n) begin 146 | empty <= 1'b1; 147 | full <= 1'b0; 148 | end 149 | else begin 150 | empty <= used_cnt_next == 0 ? 1'b1 : 1'b0; 151 | full <= used_cnt_next >= (FIFO_DEPTH-1) ? 1'b1 : 1'b0; 152 | end 153 | end 154 | 155 | 156 | generate begin 157 | genvar ii; 158 | for (ii = 0; ii < FIFO_DEPTH; ii = ii + 1) begin: fifo_gen 159 | always @(posedge clk) begin 160 | if (~rst_n) begin 161 | fifo[ii] <= ELEM_NONE; 162 | end 163 | else begin 164 | fifo[ii] <= srtd_w_val_0 & (ii == tail_ptr) ? srtd_w_data_0 : 165 | srtd_w_val_1 & (ii == w_ind_1) ? srtd_w_data_1 : 166 | srtd_w_val_2 & (ii == w_ind_2) ? srtd_w_data_2 : 167 | srtd_w_val_3 & (ii == w_ind_3) ? srtd_w_data_3 : fifo[ii]; 168 | end 169 | end 170 | end 171 | end 172 | endgenerate 173 | 174 | // clogb2 function 175 | `include "clogb2.vh" 176 | 177 | endmodule 178 | -------------------------------------------------------------------------------- /src/ram/ram_2p_wrapper.v: -------------------------------------------------------------------------------- 1 | // Description: 2 | // Model for Vivado True Dual Port Memory 3 | // Doesn't give any guarantees for compliance with Vivado's memory behavior 4 | // Notes: 5 | // - clka and clkb must be the same 6 | // - no data forwarding between read and write ports 7 | // - no assumption about write ordering in case of address collision 8 | // - 1 cycle read latency 9 | 10 | `timescale 1ns/1ns 11 | 12 | module ram_2p_wrapper #( 13 | parameter RAM_TYPE = -1, 14 | parameter RAM_DEPTH = -1, 15 | parameter RAM_ADDR_WIDTH = -1, 16 | parameter RAM_DATA_WIDTH = -1 17 | )( 18 | input rst_n, 19 | input clka, 20 | input ena, 21 | input wea, 22 | input [RAM_ADDR_WIDTH-1:0] addra, 23 | input [RAM_DATA_WIDTH-1:0] dina, 24 | output [RAM_DATA_WIDTH-1:0] douta, 25 | input clkb, 26 | input enb, 27 | input web, 28 | input [RAM_ADDR_WIDTH-1:0] addrb, 29 | input [RAM_DATA_WIDTH-1:0] dinb, 30 | output [RAM_DATA_WIDTH-1:0] doutb 31 | ); 32 | `ifdef VCS_SIMULATION 33 | 34 | reg [RAM_DATA_WIDTH-1:0] mem [RAM_DEPTH-1:0]; 35 | reg [RAM_DATA_WIDTH-1:0] douta_f; 36 | reg [RAM_DATA_WIDTH-1:0] doutb_f; 37 | 38 | genvar ii; 39 | 40 | assign douta = douta_f; 41 | assign doutb = doutb_f; 42 | 43 | generate 44 | for (ii = 0; ii < RAM_DEPTH; ii = ii + 1) begin: mem_gen 45 | always @(posedge clka) begin 46 | if (~rst_n) begin 47 | mem[ii] <= {RAM_DATA_WIDTH{1'b0}}; 48 | end 49 | else begin 50 | mem[ii] <= ena & wea & (ii == addra) ? dina : 51 | enb & web & (ii == addrb) ? dinb : mem[ii]; 52 | end 53 | end 54 | end 55 | endgenerate 56 | 57 | always @(posedge clka) begin 58 | douta_f <= ena & ~wea ? mem[addra] : {RAM_DATA_WIDTH{1'bx}}; 59 | doutb_f <= enb & ~web ? mem[addrb] : {RAM_DATA_WIDTH{1'bx}}; 60 | end 61 | 62 | `else // VCS_SIMULATION 63 | 64 | // Vivado IP 65 | generate 66 | if (RAM_TYPE == 0) begin 67 | ram_2p_type_0 ram_2p ( 68 | .clka (clka ), 69 | .ena (ena ), 70 | .wea (wea ), 71 | .addra (addra ), 72 | .dina (dina ), 73 | .douta (douta ), 74 | .clkb (clkb ), 75 | .enb (enb ), 76 | .web (web ), 77 | .addrb (addrb ), 78 | .dinb (dinb ), 79 | .doutb (doutb ) 80 | ); 81 | end 82 | else if (RAM_TYPE == 1) begin 83 | ram_2p_type_1 ram_2p ( 84 | .clka (clka ), 85 | .ena (ena ), 86 | .wea (wea ), 87 | .addra (addra ), 88 | .dina (dina ), 89 | .douta (douta ), 90 | .clkb (clkb ), 91 | .enb (enb ), 92 | .web (web ), 93 | .addrb (addrb ), 94 | .dinb (dinb ), 95 | .doutb (doutb ) 96 | ); 97 | end 98 | else if (RAM_TYPE == 2) begin 99 | ram_2p_type_2 ram_2p ( 100 | .clka (clka ), 101 | .ena (ena ), 102 | .wea (wea ), 103 | .addra (addra ), 104 | .dina (dina ), 105 | .douta (douta ), 106 | .clkb (clkb ), 107 | .enb (enb ), 108 | .web (web ), 109 | .addrb (addrb ), 110 | .dinb (dinb ), 111 | .doutb (doutb ) 112 | ); 113 | end 114 | else if (RAM_TYPE == 3) begin 115 | ram_2p_type_3 ram_2p ( 116 | .clka (clka ), 117 | .ena (ena ), 118 | .wea (wea ), 119 | .addra (addra ), 120 | .dina (dina ), 121 | .douta (douta ), 122 | .clkb (clkb ), 123 | .enb (enb ), 124 | .web (web ), 125 | .addrb (addrb ), 126 | .dinb (dinb ), 127 | .doutb (doutb ) 128 | ); 129 | end 130 | else if (RAM_TYPE == 4) begin 131 | ram_2p_type_4 ram_2p ( 132 | .clka (clka ), 133 | .ena (ena ), 134 | .wea (wea ), 135 | .addra (addra ), 136 | .dina (dina ), 137 | .douta (douta ), 138 | .clkb (clkb ), 139 | .enb (enb ), 140 | .web (web ), 141 | .addrb (addrb ), 142 | .dinb (dinb ), 143 | .doutb (doutb ) 144 | ); 145 | end 146 | else if (RAM_TYPE == 5) begin 147 | ram_2p_type_5 ram_2p ( 148 | .clka (clka ), 149 | .ena (ena ), 150 | .wea (wea ), 151 | .addra (addra ), 152 | .dina (dina ), 153 | .douta (douta ), 154 | .clkb (clkb ), 155 | .enb (enb ), 156 | .web (web ), 157 | .addrb (addrb ), 158 | .dinb (dinb ), 159 | .doutb (doutb ) 160 | ); 161 | end 162 | else if (RAM_TYPE == 6) begin 163 | ram_2p_type_6 ram_2p ( 164 | .clka (clka ), 165 | .ena (ena ), 166 | .wea (wea ), 167 | .addra (addra ), 168 | .dina (dina ), 169 | .douta (douta ), 170 | .clkb (clkb ), 171 | .enb (enb ), 172 | .web (web ), 173 | .addrb (addrb ), 174 | .dinb (dinb ), 175 | .doutb (doutb ) 176 | ); 177 | end 178 | 179 | endgenerate 180 | 181 | `endif // VCS_SIMULATION 182 | 183 | 184 | //----------------------------------------------------------- 185 | // Functions 186 | //----------------------------------------------------------- 187 | 188 | // clogb2 function 189 | `include "clogb2.vh" 190 | 191 | endmodule 192 | -------------------------------------------------------------------------------- /src/ram/ram_2w2r.v: -------------------------------------------------------------------------------- 1 | // Description: 2 | // In case of conflicting R/W to the same address returns data from a write 3 | // Doesn't guarantee any ordering between two writes to the same address 4 | 5 | `timescale 1ns/1ns 6 | 7 | module ram_2w2r #( 8 | parameter RAM_TYPE = -1, 9 | parameter RAM_DEPTH = -1, 10 | parameter RAM_ADDR_WIDTH = -1, 11 | parameter RAM_DATA_WIDTH = -1 12 | ) ( 13 | input clk, 14 | input rst_n, 15 | 16 | input r0_val, 17 | input [RAM_ADDR_WIDTH-1:0] r0_addr, 18 | output [RAM_DATA_WIDTH-1:0] r0_data, 19 | 20 | input r1_val, 21 | input [RAM_ADDR_WIDTH-1:0] r1_addr, 22 | output [RAM_DATA_WIDTH-1:0] r1_data, 23 | 24 | input w0_val, 25 | input [RAM_ADDR_WIDTH-1:0] w0_addr, 26 | input [RAM_DATA_WIDTH-1:0] w0_data, 27 | 28 | input w1_val, 29 | input [RAM_ADDR_WIDTH-1:0] w1_addr, 30 | input [RAM_DATA_WIDTH-1:0] w1_data 31 | ); 32 | // MRB - most recent bank storage for every address 33 | reg [RAM_DEPTH-1:0] mrb; 34 | reg r0_mrb_f; 35 | reg r1_mrb_f; 36 | 37 | wire r0_mrb; 38 | wire r1_mrb; 39 | wire w0_bank; 40 | wire w1_bank; 41 | 42 | wire b0_ena; 43 | wire b0_wea; 44 | wire [RAM_ADDR_WIDTH-1:0] b0_addra; 45 | wire [RAM_DATA_WIDTH-1:0] b0_dina; 46 | wire [RAM_DATA_WIDTH-1:0] b0_douta; 47 | wire b0_enb; 48 | wire b0_web; 49 | wire [RAM_ADDR_WIDTH-1:0] b0_addrb; 50 | wire [RAM_DATA_WIDTH-1:0] b0_dinb; 51 | wire [RAM_DATA_WIDTH-1:0] b0_doutb; 52 | wire b1_ena; 53 | wire b1_wea; 54 | wire [RAM_ADDR_WIDTH-1:0] b1_addra; 55 | wire [RAM_DATA_WIDTH-1:0] b1_dina; 56 | wire [RAM_DATA_WIDTH-1:0] b1_douta; 57 | wire b1_enb; 58 | wire b1_web; 59 | wire [RAM_ADDR_WIDTH-1:0] b1_addrb; 60 | wire [RAM_DATA_WIDTH-1:0] b1_dinb; 61 | wire [RAM_DATA_WIDTH-1:0] b1_doutb; 62 | 63 | genvar ii; 64 | 65 | //----------------------------------------------------------- 66 | // Logic 67 | //----------------------------------------------------------- 68 | assign r0_mrb = mrb[r0_addr]; 69 | assign r1_mrb = mrb[r1_addr]; 70 | // write data to bank 1 only if there is a read from bank 0 71 | assign w0_bank = r0_val & ~r0_mrb; 72 | assign w1_bank = r1_val & ~r1_mrb; 73 | 74 | // Bank 0 Port a 75 | assign b0_ena = (r0_val & ~r0_mrb) | (w0_val & ~w0_bank); 76 | assign b0_wea = w0_val & ~w0_bank; 77 | assign b0_addra = (r0_val & ~r0_mrb) ? r0_addr : w0_addr; 78 | assign b0_dina = w0_data; 79 | // Bank 0 Port b 80 | assign b0_enb = (r1_val & ~r1_mrb) | (w1_val & ~w1_bank); 81 | assign b0_web = w1_val & ~w1_bank; 82 | assign b0_addrb = (r1_val & ~r1_mrb) ? r1_addr : w1_addr; 83 | assign b0_dinb = w1_data; 84 | 85 | // Bank 1 Port a 86 | assign b1_ena = (r0_val & r0_mrb) | (w0_val & w0_bank); 87 | assign b1_wea = w0_val & w0_bank; 88 | assign b1_addra = (r0_val & r0_mrb) ? r0_addr : w0_addr; 89 | assign b1_dina = w0_data; 90 | // Bank 1 Port b 91 | assign b1_enb = (r1_val & r1_mrb) | (w1_val & w1_bank); 92 | assign b1_web = w1_val & w1_bank; 93 | assign b1_addrb = (r1_val & r1_mrb) ? r1_addr : w1_addr; 94 | assign b1_dinb = w1_data; 95 | 96 | assign r0_data = ~r0_mrb_f ? b0_douta : b1_douta; 97 | assign r1_data = ~r1_mrb_f ? b0_doutb : b1_doutb; 98 | 99 | generate 100 | for (ii = 0; ii < RAM_DEPTH; ii = ii + 1) begin: mrb_gen 101 | always @(posedge clk) begin 102 | if (~rst_n) begin 103 | mrb[ii] <= 1'b0; 104 | end 105 | else begin 106 | // TODO: change to parallel logic 107 | mrb[ii] <= w0_val & (ii == w0_addr) ? w0_bank : 108 | w1_val & (ii == w1_addr) ? w1_bank : mrb[ii]; 109 | end 110 | end 111 | end 112 | endgenerate 113 | 114 | always @(posedge clk) begin 115 | r0_mrb_f <= r0_mrb; 116 | r1_mrb_f <= r1_mrb; 117 | end 118 | 119 | 120 | ram_2p_wrapper #( 121 | .RAM_TYPE (RAM_TYPE ), 122 | .RAM_DEPTH (RAM_DEPTH ), 123 | .RAM_ADDR_WIDTH (RAM_ADDR_WIDTH ), 124 | .RAM_DATA_WIDTH (RAM_DATA_WIDTH ) 125 | ) bank0 ( 126 | .rst_n (rst_n ), 127 | .clka (clk ), 128 | .ena (b0_ena ), 129 | .wea (b0_wea ), 130 | .addra (b0_addra ), 131 | .dina (b0_dina ), 132 | .douta (b0_douta ), 133 | .clkb (clk ), 134 | .enb (b0_enb ), 135 | .web (b0_web ), 136 | .addrb (b0_addrb ), 137 | .dinb (b0_dinb ), 138 | .doutb (b0_doutb ) 139 | ); 140 | 141 | ram_2p_wrapper #( 142 | .RAM_TYPE (RAM_TYPE ), 143 | .RAM_DEPTH (RAM_DEPTH ), 144 | .RAM_ADDR_WIDTH (RAM_ADDR_WIDTH ), 145 | .RAM_DATA_WIDTH (RAM_DATA_WIDTH ) 146 | ) bank1 ( 147 | .rst_n (rst_n ), 148 | .clka (clk ), 149 | .ena (b1_ena ), 150 | .wea (b1_wea ), 151 | .addra (b1_addra ), 152 | .dina (b1_dina ), 153 | .douta (b1_douta ), 154 | .clkb (clk ), 155 | .enb (b1_enb ), 156 | .web (b1_web ), 157 | .addrb (b1_addrb ), 158 | .dinb (b1_dinb ), 159 | .doutb (b1_doutb ) 160 | ); 161 | 162 | //----------------------------------------------------------- 163 | // Checker 164 | //----------------------------------------------------------- 165 | `ifdef RAM_CHECKER 166 | 167 | // No more than one write to the same address 168 | always @(posedge clk) begin 169 | if (w0_val & w1_val & (w0_addr == w1_addr)) begin 170 | $display("ERROR Checker: %m: two write to address 0x%h in the same cycle @%t. No particular ordering between writes is guaranteed", w0_addr, $time); 171 | $stop; 172 | end 173 | end 174 | 175 | `endif 176 | 177 | endmodule 178 | -------------------------------------------------------------------------------- /src/ram/ram_2w4r.v: -------------------------------------------------------------------------------- 1 | // Description: 2 | // 2 write / 4 read port memory 3 | // Made out of two 2w/2r memory 4 | 5 | `timescale 1ns/1ns 6 | 7 | module ram_2w4r #( 8 | parameter RAM_TYPE = -1, 9 | parameter RAM_DEPTH = -1, 10 | parameter RAM_ADDR_WIDTH = -1, 11 | parameter RAM_DATA_WIDTH = -1 12 | )( 13 | input clk, 14 | input rst_n, 15 | 16 | input r0_val, 17 | input [RAM_ADDR_WIDTH-1:0] r0_addr, 18 | output [RAM_DATA_WIDTH-1:0] r0_data, 19 | 20 | input r1_val, 21 | input [RAM_ADDR_WIDTH-1:0] r1_addr, 22 | output [RAM_DATA_WIDTH-1:0] r1_data, 23 | 24 | input r2_val, 25 | input [RAM_ADDR_WIDTH-1:0] r2_addr, 26 | output [RAM_DATA_WIDTH-1:0] r2_data, 27 | 28 | input r3_val, 29 | input [RAM_ADDR_WIDTH-1:0] r3_addr, 30 | output [RAM_DATA_WIDTH-1:0] r3_data, 31 | 32 | input w0_val, 33 | input [RAM_ADDR_WIDTH-1:0] w0_addr, 34 | input [RAM_DATA_WIDTH-1:0] w0_data, 35 | 36 | input w1_val, 37 | input [RAM_ADDR_WIDTH-1:0] w1_addr, 38 | input [RAM_DATA_WIDTH-1:0] w1_data 39 | ); 40 | 41 | ram_2w2r #( 42 | .RAM_TYPE (RAM_TYPE ), 43 | .RAM_DEPTH (RAM_DEPTH ), 44 | .RAM_ADDR_WIDTH (RAM_ADDR_WIDTH ), 45 | .RAM_DATA_WIDTH (RAM_DATA_WIDTH ) 46 | ) mem0 ( 47 | .clk (clk ), 48 | .rst_n (rst_n ), 49 | .r0_val (r0_val ), 50 | .r0_addr (r0_addr ), 51 | .r0_data (r0_data ), 52 | .r1_val (r1_val ), 53 | .r1_addr (r1_addr ), 54 | .r1_data (r1_data ), 55 | .w0_val (w0_val ), 56 | .w0_addr (w0_addr ), 57 | .w0_data (w0_data ), 58 | .w1_val (w1_val ), 59 | .w1_addr (w1_addr ), 60 | .w1_data (w1_data ) 61 | ); 62 | 63 | ram_2w2r #( 64 | .RAM_TYPE (RAM_TYPE ), 65 | .RAM_DEPTH (RAM_DEPTH ), 66 | .RAM_ADDR_WIDTH (RAM_ADDR_WIDTH ), 67 | .RAM_DATA_WIDTH (RAM_DATA_WIDTH ) 68 | ) mem1 ( 69 | .clk (clk ), 70 | .rst_n (rst_n ), 71 | .r0_val (r2_val ), 72 | .r0_addr (r2_addr ), 73 | .r0_data (r2_data ), 74 | .r1_val (r3_val ), 75 | .r1_addr (r3_addr ), 76 | .r1_data (r3_data ), 77 | .w0_val (w0_val ), 78 | .w0_addr (w0_addr ), 79 | .w0_data (w0_data ), 80 | .w1_val (w1_val ), 81 | .w1_addr (w1_addr ), 82 | .w1_data (w1_data ) 83 | ); 84 | 85 | endmodule 86 | -------------------------------------------------------------------------------- /src/user_defined_logic/nreno_1/include/user_constants.vh: -------------------------------------------------------------------------------- 1 | `define SEND_DD_CONTEXT 1'b0 2 | `define USER_CONTEXT_W 98 3 | 4 | `define DUP_ACKS_THRESH {{(`FLOW_WIN_SIZE_W-2){1'b0}}, 2'd3} 5 | `define MAX_DUP_ACKS {{(`FLOW_WIN_SIZE_W-4){1'b0}}, 4'd10} 6 | -------------------------------------------------------------------------------- /src/user_defined_logic/nreno_1/user_defined_timeout.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module user_defined_timeout ( 4 | // input 5 | input timeout_expired, 6 | input [`TIME_W-1:0] now, 7 | input [`FLOW_WIN_SIZE-1:0] acked_wnd_in, 8 | input [`FLOW_WIN_SIZE-1:0] rtx_wnd_in, 9 | input [`TX_CNT_WIN_SIZE-1:0] tx_cnt_wnd_in, 10 | input [`FLOW_SEQ_NUM_W-1:0] wnd_start_in, 11 | input [`FLOW_WIN_SIZE_W-1:0] wnd_size_in, 12 | input [`FLOW_SEQ_NUM_W-1:0] next_new_in, 13 | input [`TIMER_W-1:0] rtx_timer_amnt_in, 14 | input [`FLOW_SEQ_NUM_W-1:0] total_tx_cnt_in, 15 | input [`USER_CONTEXT_W-1:0] user_cntxt_in, 16 | 17 | // output 18 | output [`FLAG_W-1:0] mark_rtx, 19 | output [`FLOW_SEQ_NUM_W-1:0] rtx_start, 20 | output [`FLOW_SEQ_NUM_W-1:0] rtx_end, 21 | output [`FLOW_WIN_SIZE_W-1:0] wnd_size_out, 22 | output [`TIMER_W-1:0] rtx_timer_amnt_out, 23 | output [`USER_CONTEXT_W-1:0] user_cntxt_out 24 | ); 25 | 26 | //********************************************************************************* 27 | // Wires and Regs 28 | //********************************************************************************* 29 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_two; 30 | 31 | // user context 32 | wire [`FLOW_WIN_SIZE_W-1:0] dup_acks_in; 33 | wire [`FLOW_WIN_SIZE_W-1:0] ss_thresh_in; 34 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_in; 35 | wire [`FLAG_W-1:0] in_timeout_in; 36 | wire [`FLOW_SEQ_NUM_W-1:0] recover_in; 37 | wire [`FLAG_W-1:0] in_recovery_in; 38 | wire [`FLOW_SEQ_NUM_W-1:0] prev_hgst_ack_in; 39 | wire [`FLOW_WIN_SIZE_W-1:0] cwnd_in; 40 | 41 | wire [`FLOW_WIN_SIZE_W-1:0] dup_acks_out; 42 | wire [`FLOW_WIN_SIZE_W-1:0] ss_thresh_out; 43 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_out; 44 | wire [`FLAG_W-1:0] in_timeout_out; 45 | wire [`FLOW_SEQ_NUM_W-1:0] recover_out; 46 | wire [`FLAG_W-1:0] in_recovery_out; 47 | wire [`FLOW_SEQ_NUM_W-1:0] prev_hgst_ack_out; 48 | wire [`FLOW_WIN_SIZE_W-1:0] cwnd_out; 49 | 50 | 51 | //********************************************************************************* 52 | // Logic 53 | //********************************************************************************* 54 | assign {prev_hgst_ack_in, in_recovery_in, recover_in, 55 | in_timeout_in, wnd_inc_cntr_in, ss_thresh_in, 56 | dup_acks_in, cwnd_in} = user_cntxt_in; 57 | 58 | assign user_cntxt_out = timeout_expired ? {prev_hgst_ack_out, in_recovery_out, recover_out, 59 | in_timeout_out, wnd_inc_cntr_out, ss_thresh_out, 60 | dup_acks_out, cwnd_out} : user_cntxt_in; 61 | 62 | assign wnd_two = {{(`FLOW_WIN_SIZE_W-2){1'b0}}, {2'd2}}; 63 | 64 | assign mark_rtx = timeout_expired; // Is derived from user's policy 65 | assign rtx_start = wnd_start_in; 66 | assign rtx_end = wnd_start_in + 1; 67 | 68 | assign wnd_size_out = timeout_expired ? {{(`FLOW_WIN_SIZE_W-1){1'b0}}, 1'b1} : wnd_size_in; 69 | assign rtx_timer_amnt_out = rtx_timer_amnt_in; 70 | assign dup_acks_out = {`FLOW_WIN_SIZE_W{1'b0}}; 71 | assign ss_thresh_out = wnd_size_in > wnd_two ? {1'b0, wnd_size_in[`FLOW_WIN_SIZE_W-1:1]} : wnd_two; 72 | assign wnd_inc_cntr_out = {`FLOW_WIN_SIZE_W{1'b0}}; 73 | assign in_timeout_out = 1'b1; 74 | assign recover_out = next_new_in - 1; 75 | assign in_recovery_out = in_recovery_in; 76 | assign prev_hgst_ack_out = prev_hgst_ack_in; 77 | 78 | // clogb2 function 79 | `include "clogb2.vh" 80 | 81 | endmodule 82 | -------------------------------------------------------------------------------- /src/user_defined_logic/nreno_2/include/user_constants.vh: -------------------------------------------------------------------------------- 1 | `define SEND_DD_CONTEXT 1'b0 2 | `define USER_CONTEXT_W 90 3 | 4 | `define DUP_ACKS_THRESH {{(`FLOW_WIN_SIZE_W-2){1'b0}}, 2'd3} 5 | `define MAX_DUP_ACKS {{(`FLOW_WIN_SIZE_W-4){1'b0}}, 4'd10} 6 | -------------------------------------------------------------------------------- /src/user_defined_logic/nreno_2/user_defined_incoming.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | `include "user_constants.vh" 4 | 5 | module user_defined_incoming ( 6 | // input 7 | input [`PKT_TYPE_W-1:0] pkt_type_in, 8 | input [`PKT_DATA_W-1:0] pkt_data_in, 9 | input [`FLOW_SEQ_NUM_W-1:0] cumulative_ack_in, 10 | input [`FLOW_SEQ_NUM_W-1:0] selective_ack_in, 11 | input [`TX_CNT_W-1:0] sack_tx_id_in, 12 | 13 | input [`TIME_W-1:0] now, 14 | input [`FLAG_W-1:0] valid_selective_ack, 15 | input [`FLOW_WIN_IND_W-1:0] new_c_acks_cnt, 16 | input [`FLOW_SEQ_NUM_W-1:0] old_wnd_start_in, 17 | 18 | input [`FLOW_WIN_SIZE-1:0] acked_wnd_in, 19 | input [`FLOW_WIN_SIZE-1:0] rtx_wnd_in, 20 | input [`TX_CNT_WIN_SIZE-1:0] tx_cnt_wnd_in, 21 | input [`FLOW_SEQ_NUM_W-1:0] wnd_start_in, 22 | input [`FLOW_WIN_SIZE_W-1:0] wnd_size_in, 23 | input [`FLOW_SEQ_NUM_W-1:0] next_new_in, 24 | input [`TIMER_W-1:0] rtx_timer_amnt_in, 25 | input [`FLOW_SEQ_NUM_W-1:0] total_tx_cnt_in, 26 | input [`USER_CONTEXT_W-1:0] user_cntxt_in, 27 | 28 | // output 29 | output [`FLAG_W-1:0] mark_rtx, 30 | output [`FLOW_SEQ_NUM_W-1:0] rtx_start, 31 | output [`FLOW_SEQ_NUM_W-1:0] rtx_end, 32 | output [`FLOW_WIN_SIZE_W-1:0] wnd_size_out, 33 | output [`FLAG_W-1:0] reset_rtx_timer, 34 | output [`TIMER_W-1:0] rtx_timer_amnt_out, 35 | output [`USER_CONTEXT_W-1:0] user_cntxt_out 36 | ); 37 | 38 | // wires and regs 39 | wire is_new_ack; 40 | wire is_dup_ack; 41 | wire full_ack; 42 | wire partial_ack; 43 | wire do_fast_rtx; 44 | 45 | reg [`FLOW_WIN_SIZE_W-1:0] wnd_size_out_tmp; 46 | reg [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_out_tmp; 47 | wire [`FLOW_WIN_SIZE_W-1:0] half_ss_thresh; 48 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_min_dups; 49 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_plus_one; 50 | 51 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_zero; 52 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_one; 53 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_two; 54 | 55 | // user-defined context 56 | 57 | wire [`FLOW_WIN_SIZE_W-1:0] dup_acks_in; 58 | wire [`FLOW_WIN_SIZE_W-1:0] ss_thresh_in; 59 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_in; 60 | wire [`FLAG_W-1:0] in_timeout_in; 61 | wire [`FLOW_SEQ_NUM_W-1:0] recover_in; 62 | wire [`FLAG_W-1:0] in_recovery_in; 63 | wire [`FLOW_SEQ_NUM_W-1:0] prev_hgst_ack_in; 64 | 65 | wire [`FLOW_WIN_SIZE_W-1:0] dup_acks_out; 66 | wire [`FLOW_WIN_SIZE_W-1:0] ss_thresh_out; 67 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_out; 68 | wire [`FLAG_W-1:0] in_timeout_out; 69 | wire [`FLOW_SEQ_NUM_W-1:0] recover_out; 70 | wire [`FLAG_W-1:0] in_recovery_out; 71 | wire [`FLOW_SEQ_NUM_W-1:0] prev_hgst_ack_out; 72 | 73 | //------------------------------------------------------------------------ 74 | // Combinational logic 75 | 76 | assign {prev_hgst_ack_in, in_recovery_in, recover_in, 77 | in_timeout_in, wnd_inc_cntr_in, ss_thresh_in, 78 | dup_acks_in} = user_cntxt_in; 79 | 80 | assign user_cntxt_out = {prev_hgst_ack_out, in_recovery_out, recover_out, 81 | in_timeout_out, wnd_inc_cntr_out, ss_thresh_out, 82 | dup_acks_out}; 83 | 84 | // constant window sizes 85 | assign wnd_zero = {`FLOW_WIN_SIZE_W{1'b0}}; 86 | assign wnd_one = {{(`FLOW_WIN_SIZE_W-1){1'b0}}, {1'b1}}; 87 | assign wnd_two = {{(`FLOW_WIN_SIZE_W-2){1'b0}}, {2'd2}}; 88 | 89 | // rtx 90 | assign mark_rtx = do_fast_rtx | partial_ack; 91 | 92 | assign rtx_start = wnd_start_in; 93 | assign rtx_end = wnd_start_in + 1; 94 | 95 | // other state variables 96 | assign is_dup_ack = old_wnd_start_in == cumulative_ack_in; 97 | assign is_new_ack = wnd_start_in > old_wnd_start_in; 98 | assign dup_acks_out = is_new_ack ? wnd_zero: 99 | is_dup_ack ? dup_acks_in + wnd_one : dup_acks_in; 100 | 101 | assign do_fast_rtx = dup_acks_out == `DUP_ACKS_THRESH & 102 | ((cumulative_ack_in > recover_in) | 103 | (wnd_size_in > wnd_one & 104 | cumulative_ack_in - prev_hgst_ack_in <= 4)); 105 | 106 | assign recover_out = do_fast_rtx ? next_new_in - 1: recover_in; 107 | 108 | assign ss_thresh_out = do_fast_rtx ? half_ss_thresh : ss_thresh_in; 109 | 110 | assign full_ack = is_new_ack & cumulative_ack_in > recover_in; 111 | assign partial_ack = is_new_ack & cumulative_ack_in <= recover_in; 112 | 113 | assign in_recovery_out = (in_recovery_in & cumulative_ack_in <= recover_in) | 114 | (do_fast_rtx); 115 | 116 | assign prev_hgst_ack_out = is_new_ack ? old_wnd_start_in : prev_hgst_ack_in; 117 | 118 | assign wnd_size_out = wnd_size_out_tmp >= `MAX_FLOW_WIN_SIZE ? `MAX_FLOW_WIN_SIZE : wnd_size_out_tmp; 119 | assign wnd_inc_cntr_out = wnd_inc_cntr_out_tmp; 120 | assign rtx_timer_amnt_out = rtx_timer_amnt_in; 121 | assign reset_rtx_timer = ~in_recovery_out; 122 | assign in_timeout_out = (~full_ack) & in_timeout_in; 123 | 124 | assign half_ss_thresh = wnd_size_in > wnd_two ? {1'b0, wnd_size_in[`FLOW_WIN_SIZE_W-1:1]} : wnd_two; 125 | assign wnd_min_dups = wnd_size_in - dup_acks_in; 126 | assign wnd_plus_one = wnd_size_in + wnd_one; 127 | 128 | // wnd size tmp 129 | always @(*) begin 130 | if (in_recovery_in & ~in_timeout_in) begin 131 | if (full_ack) begin 132 | wnd_size_out_tmp = ss_thresh_in; 133 | end 134 | else if (partial_ack) begin 135 | wnd_size_out_tmp = wnd_size_in + wnd_start_in - old_wnd_start_in + wnd_one; 136 | end 137 | else if (is_dup_ack) begin 138 | wnd_size_out_tmp = wnd_plus_one; 139 | end 140 | else begin 141 | wnd_size_out_tmp = wnd_size_in; 142 | end 143 | end 144 | else if (is_new_ack) begin 145 | if (wnd_size_in < ss_thresh_in) begin 146 | wnd_size_out_tmp = wnd_min_dups + wnd_one; 147 | end 148 | else begin 149 | wnd_size_out_tmp = wnd_min_dups + (wnd_inc_cntr_in == wnd_size_in ? wnd_one : wnd_zero); 150 | end 151 | end 152 | else if (is_dup_ack) begin 153 | wnd_size_out_tmp = wnd_plus_one; 154 | end 155 | else begin 156 | wnd_size_out_tmp = wnd_size_in; 157 | end 158 | end 159 | 160 | // wnd inc cntr tmp 161 | always @(*) begin 162 | if (in_recovery_out & ~in_timeout_in) begin 163 | wnd_inc_cntr_out_tmp = wnd_zero; 164 | end 165 | else if (is_new_ack & wnd_size_in >= ss_thresh_in) begin 166 | wnd_inc_cntr_out_tmp = wnd_inc_cntr_in == wnd_size_in ? wnd_zero : wnd_inc_cntr_in + wnd_one; 167 | end 168 | else begin 169 | wnd_inc_cntr_out_tmp = wnd_inc_cntr_in; 170 | end 171 | end 172 | 173 | // clogb2 function 174 | `include "clogb2.vh" 175 | 176 | endmodule 177 | -------------------------------------------------------------------------------- /src/user_defined_logic/nreno_2/user_defined_timeout.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module user_defined_timeout ( 4 | // input 5 | input timeout_expired, 6 | input [`TIME_W-1:0] now, 7 | input [`FLOW_WIN_SIZE-1:0] acked_wnd_in, 8 | input [`FLOW_WIN_SIZE-1:0] rtx_wnd_in, 9 | input [`TX_CNT_WIN_SIZE-1:0] tx_cnt_wnd_in, 10 | input [`FLOW_SEQ_NUM_W-1:0] wnd_start_in, 11 | input [`FLOW_WIN_SIZE_W-1:0] wnd_size_in, 12 | input [`FLOW_SEQ_NUM_W-1:0] next_new_in, 13 | input [`TIMER_W-1:0] rtx_timer_amnt_in, 14 | input [`FLOW_SEQ_NUM_W-1:0] total_tx_cnt_in, 15 | input [`USER_CONTEXT_W-1:0] user_cntxt_in, 16 | 17 | // output 18 | output [`FLAG_W-1:0] mark_rtx, 19 | output [`FLOW_SEQ_NUM_W-1:0] rtx_start, 20 | output [`FLOW_SEQ_NUM_W-1:0] rtx_end, 21 | output [`FLOW_WIN_SIZE_W-1:0] wnd_size_out, 22 | output [`TIMER_W-1:0] rtx_timer_amnt_out, 23 | output [`USER_CONTEXT_W-1:0] user_cntxt_out 24 | ); 25 | 26 | //********************************************************************************* 27 | // Wires and Regs 28 | //********************************************************************************* 29 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_two; 30 | 31 | // user context 32 | wire [`FLOW_WIN_SIZE_W-1:0] dup_acks_in; 33 | wire [`FLOW_WIN_SIZE_W-1:0] ss_thresh_in; 34 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_in; 35 | wire [`FLAG_W-1:0] in_timeout_in; 36 | wire [`FLOW_SEQ_NUM_W-1:0] recover_in; 37 | wire [`FLAG_W-1:0] in_recovery_in; 38 | wire [`FLOW_SEQ_NUM_W-1:0] prev_hgst_ack_in; 39 | 40 | wire [`FLOW_WIN_SIZE_W-1:0] dup_acks_out; 41 | wire [`FLOW_WIN_SIZE_W-1:0] ss_thresh_out; 42 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_out; 43 | wire [`FLAG_W-1:0] in_timeout_out; 44 | wire [`FLOW_SEQ_NUM_W-1:0] recover_out; 45 | wire [`FLAG_W-1:0] in_recovery_out; 46 | wire [`FLOW_SEQ_NUM_W-1:0] prev_hgst_ack_out; 47 | 48 | 49 | //********************************************************************************* 50 | // Logic 51 | //********************************************************************************* 52 | assign {prev_hgst_ack_in, in_recovery_in, recover_in, 53 | in_timeout_in, wnd_inc_cntr_in, ss_thresh_in, 54 | dup_acks_in} = user_cntxt_in; 55 | 56 | assign user_cntxt_out = timeout_expired ? {prev_hgst_ack_out, in_recovery_out, recover_out, 57 | in_timeout_out, wnd_inc_cntr_out, ss_thresh_out, 58 | dup_acks_out} : user_cntxt_in; 59 | 60 | assign wnd_two = {{(`FLOW_WIN_SIZE_W-2){1'b0}}, {2'd2}}; 61 | 62 | assign mark_rtx = timeout_expired; // Is derived from user's policy 63 | assign rtx_start = wnd_start_in; 64 | assign rtx_end = wnd_start_in + 1; 65 | 66 | assign wnd_size_out = timeout_expired ? {{(`FLOW_WIN_SIZE_W-1){1'b0}}, 1'b1} : wnd_size_in; 67 | assign rtx_timer_amnt_out = rtx_timer_amnt_in; 68 | assign dup_acks_out = {`FLOW_WIN_SIZE_W{1'b0}}; 69 | assign ss_thresh_out = wnd_size_in > wnd_two ? {1'b0, wnd_size_in[`FLOW_WIN_SIZE_W-1:1]} : wnd_two; 70 | assign wnd_inc_cntr_out = {`FLOW_WIN_SIZE_W{1'b0}}; 71 | assign in_timeout_out = 1'b1; 72 | assign recover_out = next_new_in - 1; 73 | assign in_recovery_out = in_recovery_in; 74 | assign prev_hgst_ack_out = prev_hgst_ack_in; 75 | 76 | // clogb2 function 77 | `include "clogb2.vh" 78 | 79 | endmodule 80 | -------------------------------------------------------------------------------- /src/user_defined_logic/reno/include/user_constants.vh: -------------------------------------------------------------------------------- 1 | `define SEND_DD_CONTEXT 1'b0 2 | `define USER_CONTEXT_W (`FLAG_W + 3 * `FLOW_WIN_SIZE_W) 3 | 4 | `define DUP_ACKS_THRESH {{(`FLOW_WIN_SIZE_W-2){1'b0}}, 2'd3} 5 | `define MAX_DUP_ACKS {{(`FLOW_WIN_SIZE_W-4){1'b0}}, 4'd10} 6 | -------------------------------------------------------------------------------- /src/user_defined_logic/reno/user_defined_incoming.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | `include "user_constants.vh" 4 | 5 | module user_defined_incoming ( 6 | // input 7 | input [`PKT_TYPE_W-1:0] pkt_type_in, 8 | input [`PKT_DATA_W-1:0] pkt_data_in, 9 | input [`FLOW_SEQ_NUM_W-1:0] cumulative_ack_in, 10 | input [`FLOW_SEQ_NUM_W-1:0] selective_ack_in, 11 | input [`TX_CNT_W-1:0] sack_tx_id_in, 12 | 13 | input [`TIME_W-1:0] now, 14 | input [`FLAG_W-1:0] valid_selective_ack, 15 | input [`FLOW_WIN_IND_W-1:0] new_c_acks_cnt, 16 | input [`FLOW_SEQ_NUM_W-1:0] old_wnd_start_in, 17 | 18 | input [`FLOW_WIN_SIZE-1:0] acked_wnd_in, 19 | input [`FLOW_WIN_SIZE-1:0] rtx_wnd_in, 20 | input [`TX_CNT_WIN_SIZE-1:0] tx_cnt_wnd_in, 21 | input [`FLOW_SEQ_NUM_W-1:0] wnd_start_in, 22 | input [`FLOW_WIN_SIZE_W-1:0] wnd_size_in, 23 | input [`FLOW_SEQ_NUM_W-1:0] next_new_in, 24 | input [`TIMER_W-1:0] rtx_timer_amnt_in, 25 | input [`FLOW_SEQ_NUM_W-1:0] total_tx_cnt_in, 26 | input [`USER_CONTEXT_W-1:0] user_cntxt_in, 27 | 28 | // output 29 | output [`FLAG_W-1:0] mark_rtx, 30 | output [`FLOW_SEQ_NUM_W-1:0] rtx_start, 31 | output [`FLOW_SEQ_NUM_W-1:0] rtx_end, 32 | output [`FLOW_WIN_SIZE_W-1:0] wnd_size_out, 33 | output [`FLAG_W-1:0] reset_rtx_timer, 34 | output [`TIMER_W-1:0] rtx_timer_amnt_out, 35 | output [`USER_CONTEXT_W-1:0] user_cntxt_out 36 | ); 37 | 38 | // wires and regs 39 | wire is_new_ack; 40 | wire is_dup_ack; 41 | 42 | reg [`FLOW_WIN_SIZE_W-1:0] wnd_size_out_tmp; 43 | reg [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_out_tmp; 44 | wire [`FLOW_WIN_SIZE_W-1:0] half_ss_thresh; 45 | 46 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_zero; 47 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_one; 48 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_two; 49 | 50 | // user-defined context 51 | 52 | wire [`FLOW_WIN_SIZE_W-1:0] dup_acks_in; 53 | wire [`FLOW_WIN_SIZE_W-1:0] ss_thresh_in; 54 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_in; 55 | wire [`FLAG_W-1:0] in_timeout_in; 56 | 57 | wire [`FLOW_WIN_SIZE_W-1:0] dup_acks_out; 58 | wire [`FLOW_WIN_SIZE_W-1:0] ss_thresh_out; 59 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_out; 60 | wire [`FLAG_W-1:0] in_timeout_out; 61 | 62 | //------------------------------------------------------------------------ 63 | // Combinational logic 64 | 65 | assign {in_timeout_in, wnd_inc_cntr_in, ss_thresh_in, 66 | dup_acks_in} = user_cntxt_in; 67 | 68 | assign user_cntxt_out = {in_timeout_out, wnd_inc_cntr_out, ss_thresh_out, 69 | dup_acks_out}; 70 | 71 | assign wnd_zero = {`FLOW_WIN_SIZE_W{1'b0}}; 72 | assign wnd_one = {{(`FLOW_WIN_SIZE_W-1){1'b0}}, {1'b1}}; 73 | assign wnd_two = {{(`FLOW_WIN_SIZE_W-2){1'b0}}, {2'd2}}; 74 | 75 | assign is_dup_ack = old_wnd_start_in == cumulative_ack_in; 76 | assign is_new_ack = wnd_start_in > old_wnd_start_in; 77 | assign dup_acks_out = is_new_ack ? wnd_zero: 78 | is_dup_ack ? dup_acks_in + wnd_one : dup_acks_in; 79 | 80 | // rtx 81 | assign mark_rtx = ~in_timeout_in & dup_acks_out == `DUP_ACKS_THRESH; 82 | assign rtx_start = wnd_start_in; 83 | assign rtx_end = wnd_start_in + 1; 84 | 85 | assign wnd_size_out = wnd_size_out_tmp >= `MAX_FLOW_WIN_SIZE ? `MAX_FLOW_WIN_SIZE : wnd_size_out_tmp; 86 | assign wnd_inc_cntr_out = wnd_inc_cntr_out_tmp; 87 | assign rtx_timer_amnt_out = rtx_timer_amnt_in; 88 | assign reset_rtx_timer = is_new_ack; 89 | assign in_timeout_out = (~is_new_ack) & in_timeout_in; 90 | 91 | assign half_ss_thresh = wnd_size_in > wnd_two ? {1'b0, wnd_size_in[`FLOW_WIN_SIZE_W-1:1]} : wnd_two; 92 | assign ss_thresh_out = ~in_timeout_in & dup_acks_out == `DUP_ACKS_THRESH ? half_ss_thresh : ss_thresh_in; 93 | 94 | // wnd size tmp 95 | always @(*) begin 96 | if (is_new_ack) begin 97 | if (~in_timeout_in & dup_acks_in > 0 & dup_acks_in < `DUP_ACKS_THRESH) begin 98 | wnd_size_out_tmp = wnd_size_in - dup_acks_in; 99 | end 100 | else if(~in_timeout_in & dup_acks_in >= `DUP_ACKS_THRESH) begin 101 | wnd_size_out_tmp = ss_thresh_in; 102 | end 103 | else if(wnd_size_in < ss_thresh_in) begin 104 | wnd_size_out_tmp = wnd_size_in + wnd_one; 105 | end 106 | else begin 107 | wnd_size_out_tmp = wnd_inc_cntr_in == wnd_size_in ? wnd_size_in + wnd_one : wnd_size_in; 108 | end 109 | end 110 | else if (~in_timeout_in & is_dup_ack & 111 | dup_acks_out < `MAX_DUP_ACKS) begin 112 | wnd_size_out_tmp = wnd_size_in + wnd_one; 113 | end 114 | else begin 115 | wnd_size_out_tmp = wnd_size_in; 116 | end 117 | end 118 | 119 | // wnd inc cntr tmp 120 | always @(*) begin 121 | if (is_new_ack) begin 122 | wnd_inc_cntr_out_tmp = wnd_inc_cntr_in == wnd_size_in ? wnd_zero : wnd_inc_cntr_in + wnd_one; 123 | end 124 | else if (~in_timeout_in & is_dup_ack) begin 125 | wnd_inc_cntr_out_tmp = (dup_acks_out >= `DUP_ACKS_THRESH) ? wnd_zero : wnd_inc_cntr_in; 126 | end 127 | else begin 128 | wnd_inc_cntr_out_tmp = wnd_inc_cntr_in; 129 | end 130 | end 131 | 132 | // clogb2 function 133 | `include "clogb2.vh" 134 | 135 | endmodule 136 | -------------------------------------------------------------------------------- /src/user_defined_logic/reno/user_defined_timeout.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module user_defined_timeout ( 4 | // input 5 | input timeout_expired, 6 | input [`TIME_W-1:0] now, 7 | input [`FLOW_WIN_SIZE-1:0] acked_wnd_in, 8 | input [`FLOW_WIN_SIZE-1:0] rtx_wnd_in, 9 | input [`TX_CNT_WIN_SIZE-1:0] tx_cnt_wnd_in, 10 | input [`FLOW_SEQ_NUM_W-1:0] wnd_start_in, 11 | input [`FLOW_WIN_SIZE_W-1:0] wnd_size_in, 12 | input [`FLOW_SEQ_NUM_W-1:0] next_new_in, 13 | input [`TIMER_W-1:0] rtx_timer_amnt_in, 14 | input [`FLOW_SEQ_NUM_W-1:0] total_tx_cnt_in, 15 | input [`USER_CONTEXT_W-1:0] user_cntxt_in, 16 | 17 | // output 18 | output [`FLAG_W-1:0] mark_rtx, 19 | output [`FLOW_SEQ_NUM_W-1:0] rtx_start, 20 | output [`FLOW_SEQ_NUM_W-1:0] rtx_end, 21 | output [`FLOW_WIN_SIZE_W-1:0] wnd_size_out, 22 | output [`TIMER_W-1:0] rtx_timer_amnt_out, 23 | output [`USER_CONTEXT_W-1:0] user_cntxt_out 24 | ); 25 | 26 | //********************************************************************************* 27 | // Wires and Regs 28 | //********************************************************************************* 29 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_two; 30 | 31 | // user context 32 | wire [`FLOW_WIN_SIZE_W-1:0] dup_acks_in; 33 | wire [`FLOW_WIN_SIZE_W-1:0] ss_thresh_in; 34 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_in; 35 | wire [`FLAG_W-1:0] in_timeout_in; 36 | 37 | wire [`FLOW_WIN_SIZE_W-1:0] dup_acks_out; 38 | wire [`FLOW_WIN_SIZE_W-1:0] ss_thresh_out; 39 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_out; 40 | wire [`FLAG_W-1:0] in_timeout_out; 41 | 42 | 43 | //********************************************************************************* 44 | // Logic 45 | //********************************************************************************* 46 | assign {in_timeout_in, wnd_inc_cntr_in, 47 | ss_thresh_in, dup_acks_in} = user_cntxt_in; 48 | 49 | assign user_cntxt_out = timeout_expired ? {in_timeout_out, wnd_inc_cntr_out, 50 | ss_thresh_out, dup_acks_out} : user_cntxt_in; 51 | 52 | 53 | assign wnd_two = {{(`FLOW_WIN_SIZE_W-2){1'b0}}, {2'd2}}; 54 | 55 | assign mark_rtx = 1'b1; // Is derived from user's policy 56 | assign rtx_start = wnd_start_in; 57 | assign rtx_end = wnd_start_in + 1; 58 | 59 | assign wnd_size_out = timeout_expired ? {{(`FLOW_WIN_SIZE_W-1){1'b0}}, 1'b1} : timeout_expired; 60 | assign rtx_timer_amnt_out = rtx_timer_amnt_in; 61 | assign dup_acks_out = {`FLOW_WIN_SIZE_W{1'b0}}; 62 | assign ss_thresh_out = wnd_size_in > wnd_two ? {1'b0, wnd_size_in[`FLOW_WIN_SIZE_W-1:1]} : wnd_two; 63 | assign wnd_inc_cntr_out = {`FLOW_WIN_SIZE_W{1'b0}}; 64 | assign in_timeout_out = 1'b1; 65 | 66 | // clogb2 function 67 | `include "clogb2.vh" 68 | 69 | endmodule 70 | -------------------------------------------------------------------------------- /src/user_defined_logic/sack/include/user_constants.vh: -------------------------------------------------------------------------------- 1 | `define SEND_DD_CONTEXT 1'b0 2 | `define USER_CONTEXT_W (2 * `FLAG_W + 3 * `FLOW_SEQ_NUM_W + 6 * `FLOW_WIN_SIZE_W) 3 | 4 | `define DUP_ACKS_THRESH 3 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/user_defined_logic/sack/user_defined_timeout.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ns 2 | 3 | module user_defined_timeout ( 4 | // input 5 | input timeout_expired, 6 | input [`TIME_W-1:0] now, 7 | input [`FLOW_WIN_SIZE-1:0] acked_wnd_in, 8 | input [`FLOW_WIN_SIZE-1:0] rtx_wnd_in, 9 | input [`TX_CNT_WIN_SIZE-1:0] tx_cnt_wnd_in, 10 | input [`FLOW_SEQ_NUM_W-1:0] wnd_start_in, 11 | input [`FLOW_WIN_SIZE_W-1:0] wnd_size_in, 12 | input [`FLOW_SEQ_NUM_W-1:0] next_new_in, 13 | input [`TIMER_W-1:0] rtx_timer_amnt_in, 14 | input [`FLOW_SEQ_NUM_W-1:0] total_tx_cnt_in, 15 | input [`USER_CONTEXT_W-1:0] user_cntxt_in, 16 | 17 | // output 18 | output [`FLAG_W-1:0] mark_rtx, 19 | output [`FLOW_SEQ_NUM_W-1:0] rtx_start, 20 | output [`FLOW_SEQ_NUM_W-1:0] rtx_end, 21 | output [`FLOW_WIN_SIZE_W-1:0] wnd_size_out, 22 | output [`TIMER_W-1:0] rtx_timer_amnt_out, 23 | output [`USER_CONTEXT_W-1:0] user_cntxt_out 24 | ); 25 | 26 | //********************************************************************************* 27 | // Wires and Regs 28 | //********************************************************************************* 29 | // user context 30 | wire [`FLOW_WIN_SIZE_W-1:0] cwnd_in; 31 | wire [`FLOW_WIN_SIZE_W-1:0] ss_thresh_in; 32 | wire [`FLOW_WIN_SIZE_W-1:0] sacked_in; 33 | wire [`FLOW_WIN_SIZE_W-1:0] dup_acks_in; 34 | wire [`FLOW_WIN_SIZE_W-1:0] sacked_gt_min_in; 35 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_in; 36 | wire [`FLOW_SEQ_NUM_W-1:0] min_sack_in; 37 | wire [`FLOW_SEQ_NUM_W-1:0] last_marked_sack_in; 38 | wire [`FLOW_SEQ_NUM_W-1:0] recover_in; 39 | wire [`FLAG_W-1:0] in_recovery_in; 40 | wire [`FLAG_W-1:0] in_timeout_in; 41 | 42 | wire [`FLOW_WIN_SIZE_W-1:0] cwnd_out; 43 | wire [`FLOW_WIN_SIZE_W-1:0] ss_thresh_out; 44 | wire [`FLOW_WIN_SIZE_W-1:0] sacked_out; 45 | wire [`FLOW_WIN_SIZE_W-1:0] dup_acks_out; 46 | wire [`FLOW_WIN_SIZE_W-1:0] sacked_gt_min_out; 47 | wire [`FLOW_WIN_SIZE_W-1:0] wnd_inc_cntr_out; 48 | wire [`FLOW_SEQ_NUM_W-1:0] min_sack_out; 49 | wire [`FLOW_SEQ_NUM_W-1:0] last_marked_sack_out; 50 | wire [`FLOW_SEQ_NUM_W-1:0] recover_out; 51 | wire [`FLAG_W-1:0] in_recovery_out; 52 | wire [`FLAG_W-1:0] in_timeout_out; 53 | 54 | //********************************************************************************* 55 | // Logic 56 | //********************************************************************************* 57 | assign user_cntxt_out = {in_timeout_out, in_recovery_out, recover_out, 58 | last_marked_sack_out, min_sack_out, wnd_inc_cntr_out, 59 | sacked_gt_min_out, dup_acks_out, sacked_out, 60 | ss_thresh_out, cwnd_out}; 61 | 62 | assign {in_timeout_in, in_recovery_in, recover_in, 63 | last_marked_sack_in, min_sack_in, wnd_inc_cntr_in, 64 | sacked_gt_min_in, dup_acks_in, sacked_in, 65 | ss_thresh_in, cwnd_in} = user_cntxt_in; 66 | 67 | assign wnd_zero = {`FLOW_WIN_SIZE_W{1'b0}}; 68 | assign wnd_two = {{(`FLOW_WIN_SIZE_W-2){1'b0}}, {2'd2}}; 69 | 70 | assign mark_rtx = 1'b1; // Is derived from user's policy 71 | 72 | assign wnd_size_out = wnd_size_in; 73 | assign rtx_timer_amnt_out = rtx_timer_amnt_in; 74 | 75 | assign rtx_start = wnd_start_in; 76 | assign rtx_end = next_new_in; 77 | 78 | assign cwnd_out = cwnd_in; 79 | assign ss_thresh_out = wnd_size_in > wnd_two ? {1'b0, wnd_size_in[`FLOW_WIN_SIZE_W-1:1]} : wnd_two; 80 | assign sacked_out = sacked_in; 81 | assign dup_acks_out = wnd_zero; 82 | assign sacked_gt_min_out = wnd_zero; 83 | assign wnd_inc_cntr_out = wnd_zero; 84 | assign min_sack_out = `FLOW_SEQ_NONE; 85 | assign last_marked_sack_out = last_marked_sack_in; 86 | assign recover_out = next_new_in - 1; 87 | assign in_recovery_out = 1'b0; 88 | assign in_timeout_out = 1'b1; 89 | 90 | // clogb2 function 91 | `include "clogb2.vh" 92 | 93 | endmodule 94 | -------------------------------------------------------------------------------- /tb/config/tonic/tonic_nreno_1.yaml: -------------------------------------------------------------------------------- 1 | # unit_name 2 | # model parameters 3 | # : 4 | # model specifications 5 | # param - val 6 | tonic/nreno_1: 7 | params: 8 | init_wnd_size : 10 9 | init_rtx_timer_amnt : 2000 10 | 11 | specs: 12 | user_context_w : 98 13 | init_user_context : 0x3c000a 14 | send_dd_context : 0 15 | 16 | cr_type : 0 17 | 18 | sim_cycles : 100 19 | active_flow_cnt : 4 20 | rtt : 20 21 | loss_prob : 300 22 | receiver : True 23 | -------------------------------------------------------------------------------- /tb/config/tonic/tonic_nreno_2.yaml: -------------------------------------------------------------------------------- 1 | # unit_name 2 | # model parameters 3 | # : 4 | # model specifications 5 | # param - val 6 | tonic/nreno_2: 7 | params: 8 | init_wnd_size : 10 9 | init_rtx_timer_amnt : 2000 10 | 11 | specs: 12 | user_context_w : 90 13 | init_user_context : 0x3c00 14 | send_dd_context : 0 15 | 16 | cr_type : 0 17 | 18 | sim_cycles : 10 19 | active_flow_cnt : 4 20 | rtt : 20 21 | loss_prob : 300 22 | receiver : True 23 | -------------------------------------------------------------------------------- /tb/config/tonic/tonic_reno.yaml: -------------------------------------------------------------------------------- 1 | # unit_name 2 | # model parameters 3 | # : 4 | # model specifications 5 | # param - val 6 | tonic/reno: 7 | params: 8 | init_wnd_size : 10 9 | init_rtx_timer_amnt : 2000 10 | 11 | specs: 12 | user_context_w : 25 13 | init_user_context : 0 14 | send_dd_context : 0 15 | 16 | cr_type : 0 17 | 18 | sim_cycles : 100 19 | active_flow_cnt : 4 20 | rtt : 20 21 | loss_prob : 300 22 | receiver : True 23 | -------------------------------------------------------------------------------- /tb/config/tonic/tonic_sack.yaml: -------------------------------------------------------------------------------- 1 | # unit_name 2 | # model parameters 3 | # : 4 | # model specifications 5 | # param - val 6 | tonic/sack: 7 | params: 8 | init_wnd_size : 10 9 | init_rtx_timer_amnt : 2000 10 | 11 | specs: 12 | user_context_w : 146 13 | init_user_context : 0 14 | send_dd_context : 0 15 | 16 | cr_type : 0 17 | 18 | sim_cycles : 10 19 | active_flow_cnt : 4 20 | rtt : 20 21 | loss_prob : 300 22 | receiver : True 23 | -------------------------------------------------------------------------------- /tb/sim/common/sim_receiver/ack_prio_queue.c: -------------------------------------------------------------------------------- 1 | #include "ack_prio_queue.h" 2 | #include 3 | #include 4 | 5 | void prioInit(struct AckPrioQueue* q){ 6 | q->cnt = 0; 7 | q->head = 0; 8 | } 9 | 10 | int prioSize(struct AckPrioQueue* q){ 11 | return q->cnt; 12 | } 13 | 14 | bool prioIsEmpty (struct AckPrioQueue* q){ 15 | return (q->cnt == 0); 16 | } 17 | 18 | bool prioIsFull (struct AckPrioQueue* q){ 19 | return (q->cnt == MAX_QUEUE_SIZE); 20 | } 21 | 22 | struct AckQueueElement prioHead(struct AckPrioQueue* q){ 23 | if (prioIsEmpty(q)){ 24 | struct AckQueueElement tmp; 25 | return tmp; 26 | } 27 | else { 28 | return q->elems[q->head]; 29 | } 30 | } 31 | 32 | struct AckQueueElement prioDequeue(struct AckPrioQueue* q){ 33 | if (prioIsEmpty(q)){ 34 | struct AckQueueElement tmp; 35 | return tmp; 36 | } 37 | else{ 38 | int prev_head = q->head; 39 | q->head = (q->head + 1) % MAX_QUEUE_SIZE; 40 | q->cnt--; 41 | return q->elems[prev_head]; 42 | } 43 | } 44 | 45 | void prioEnqueue(struct AckPrioQueue* q, struct AckQueueElement a){ 46 | if (!prioIsFull(q)){ 47 | int i; 48 | int found_ind = (q->head + q->cnt) % MAX_QUEUE_SIZE; 49 | if (a.rcvd_time < q->elems[q->head].rcvd_time){ 50 | int new_head = (q->head - 1 + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE; 51 | q->elems[new_head] = a; 52 | q->head = new_head; 53 | q->cnt++; 54 | } 55 | else{ 56 | for (i = 0; i < q->cnt; i++){ 57 | int rcvd_time1 = q->elems[(q->head + i) % MAX_QUEUE_SIZE].rcvd_time; 58 | int rcvd_time2 = q->elems[(q->head + i + 1) % MAX_QUEUE_SIZE].rcvd_time; 59 | if (a.rcvd_time >= rcvd_time1 && a.rcvd_time < rcvd_time2){ 60 | found_ind = i + 1; 61 | break; 62 | } 63 | } 64 | if (found_ind != (q->head + q->cnt) % MAX_QUEUE_SIZE){ 65 | for (i = 0; i < found_ind; i++){ 66 | q->elems[(q->head + i - 1 + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE] = 67 | q->elems[(q->head + i) % MAX_QUEUE_SIZE]; 68 | } 69 | q->elems[(q->head + found_ind - 1 + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE] = a; 70 | q->head = (q->head - 1 + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE; 71 | } 72 | else if(q->elems[(found_ind - 1 + MAX_QUEUE_SIZE)% MAX_QUEUE_SIZE].rcvd_time > 73 | a.rcvd_time){ 74 | q->elems[found_ind] = q->elems[(found_ind - 1 + MAX_QUEUE_SIZE)% MAX_QUEUE_SIZE]; 75 | q->elems[(found_ind - 1 + MAX_QUEUE_SIZE)% MAX_QUEUE_SIZE] = a; 76 | } 77 | else{ 78 | q->elems[found_ind] = a; 79 | } 80 | q->cnt++; 81 | } 82 | } 83 | } 84 | 85 | void prioPrint(struct AckPrioQueue* q){ 86 | int i; 87 | printf("Ack queue: "); 88 | for (i = 0; i < q->cnt; i++){ 89 | struct AckQueueElement tmp = q->elems[(q->head + i) % MAX_QUEUE_SIZE]; 90 | printf("%d %d %d %d,", tmp.fid, tmp.cumulative_ack, tmp.selective_ack, tmp.rcvd_time); 91 | } 92 | printf("\n"); 93 | } 94 | -------------------------------------------------------------------------------- /tb/sim/common/sim_receiver/ack_prio_queue.h: -------------------------------------------------------------------------------- 1 | #ifndef ACK_PRIO_QUEUE__H_ 2 | #define ACK_PRIO_QUEUE__H_ 3 | 4 | #include "constants.h" 5 | 6 | struct AckQueueElement { 7 | unsigned int fid; 8 | unsigned int cumulative_ack; 9 | unsigned int selective_ack; 10 | unsigned int sack_tx_id; 11 | unsigned int rcvd_time; 12 | }; 13 | 14 | struct AckPrioQueue { 15 | struct AckQueueElement elems[MAX_QUEUE_SIZE]; 16 | int head; 17 | int cnt; 18 | }; 19 | 20 | void prioInit(struct AckPrioQueue*); 21 | int prioSize(struct AckPrioQueue*); 22 | bool prioIsEmpty (struct AckPrioQueue*); 23 | bool prioIsFull (struct AckPrioQueue*); 24 | struct AckQueueElement prioHead(struct AckPrioQueue*); 25 | struct AckQueueElement prioDequeue(struct AckPrioQueue*); 26 | void prioEnqueue(struct AckPrioQueue*, struct AckQueueElement); 27 | void prioPrint(struct AckPrioQueue*); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /tb/sim/common/sim_receiver/constants.h: -------------------------------------------------------------------------------- 1 | #ifndef CONSTANTS_H 2 | #define CONSTANTS_H 3 | 4 | typedef int bool; 5 | #define true 1 6 | #define false 0 7 | 8 | #define CYCLE_IN_NS 10 9 | 10 | #define PKT_DATA_W 100 11 | #define FLOW_ID_NONE 0xFFFF 12 | #define MAX_FLOW_CNT 1024 13 | #define MAX_FLOW_ID (1 << 16) 14 | #define FLOW_SEQ_NUM_NONE 0xFFFFFFFF 15 | #define MAX_QUEUE_SIZE 2000 16 | #define FLOW_WIN_SIZE 1024 17 | 18 | #define NONE_PKT 0xFFFF 19 | #define SACK_PKT 0 20 | #define PULL_PKT 1 21 | #define NACK_PKT 2 22 | #define CACK_PKT 3 23 | 24 | 25 | #define NEXT_SEQ_PATH "sim_top.sim_receiver.next_seq_in" 26 | #define NEXT_SEQ_TX_ID_PATH "sim_top.sim_receiver.next_seq_tx_id_in" 27 | #define NEXT_SEQ_FID_PATH "sim_top.sim_receiver.next_seq_fid_in" 28 | 29 | #define RESP_FID_PATH "sim_top.sim_receiver.read_resp_fid" 30 | #define RESP_PKT_TYPE_PATH "sim_top.sim_receiver.read_resp_pkt_type" 31 | #define RESP_PKT_DATA_PATH "sim_top.sim_receiver.read_resp_pkt_data" 32 | 33 | #define LOSS_PATH "sim_top.sim_receiver.LINK_LOSS_PROB" 34 | #define RTT_PATH "sim_top.sim_receiver.LINK_RTT" 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /tb/sim/common/sim_receiver/receiver_resp.h: -------------------------------------------------------------------------------- 1 | #include "constants.h" 2 | 3 | struct ReceiverResp{ 4 | int fid; 5 | unsigned int pkt_type; 6 | char pkt_data[PKT_DATA_W]; 7 | }; 8 | 9 | void receiver_resp(int, int, 10 | int, int, 11 | struct ReceiverResp*); 12 | -------------------------------------------------------------------------------- /tb/sim/common/sim_receiver/sim.flist: -------------------------------------------------------------------------------- 1 | ##################################### 2 | # test bench C files 3 | ##################################### 4 | $TONIC_HOME/tb/sim/common/sim_receiver/sim_receiver.c 5 | $TONIC_HOME/tb/sim/common/sim_receiver/ack_prio_queue.c 6 | $TONIC_HOME/tb/sim/common/sim_receiver/sliding_window.c 7 | 8 | ##################################### 9 | # Design Files 10 | ##################################### 11 | $TONIC_HOME/tb/sim/common/sim_receiver/sim_receiver.v 12 | -------------------------------------------------------------------------------- /tb/sim/common/sim_receiver/sim_receiver.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "vpi_user.h" 4 | 5 | #include "constants.h" 6 | #include "ack_prio_queue.h" 7 | #include "sliding_window.h" 8 | 9 | #include "receiver_resp.h" 10 | 11 | double LOSS_PROB = 1; 12 | double RTT_IN_NS = 0; 13 | 14 | long long int time_in_ns = 0; 15 | 16 | struct AckPrioQueue ackQueue; 17 | 18 | struct SlidingWindow rcvd[MAX_FLOW_CNT]; 19 | 20 | 21 | void init(void){ 22 | vpiHandle loss_handle = vpi_handle_by_name(LOSS_PATH, NULL); 23 | s_vpi_value loss_val = {vpiIntVal}; 24 | vpi_get_value(loss_handle, &loss_val); 25 | LOSS_PROB = loss_val.value.integer / 1000.0; 26 | 27 | vpiHandle rtt_handle = vpi_handle_by_name(RTT_PATH, NULL); 28 | s_vpi_value rtt_val = {vpiIntVal}; 29 | vpi_get_value(rtt_handle, &rtt_val); 30 | RTT_IN_NS = rtt_val.value.integer; 31 | 32 | srand(123456789); 33 | } 34 | 35 | void send_clk(void){ 36 | time_in_ns += CYCLE_IN_NS; 37 | } 38 | 39 | void read_inputs(void) { 40 | // vpi_printf("-------------\n"); 41 | 42 | 43 | struct ReceiverResp resp; 44 | resp.fid = FLOW_ID_NONE; 45 | resp.pkt_type = NONE_PKT; 46 | sprintf(resp.pkt_data, "%0*d", PKT_DATA_W, 0); 47 | 48 | 49 | if (!prioIsEmpty(&ackQueue)){ 50 | struct AckQueueElement ack = prioHead(&ackQueue); 51 | 52 | if (ack.rcvd_time <= time_in_ns){ 53 | receiver_resp(ack.fid, 54 | ack.cumulative_ack, 55 | ack.selective_ack, ack.sack_tx_id, &resp); 56 | prioDequeue(&ackQueue); 57 | } 58 | } 59 | 60 | vpiHandle resp_fid_handle = vpi_handle_by_name(RESP_FID_PATH, NULL); 61 | s_vpi_value resp_fid_val = {vpiIntVal, resp.fid}; 62 | vpi_put_value(resp_fid_handle, &resp_fid_val, NULL, vpiNoDelay); 63 | 64 | vpiHandle resp_pkt_type_handle = vpi_handle_by_name(RESP_PKT_TYPE_PATH, NULL); 65 | s_vpi_value resp_pkt_type_val = {vpiIntVal, resp.pkt_type}; 66 | vpi_put_value(resp_pkt_type_handle, &resp_pkt_type_val, NULL, vpiNoDelay); 67 | 68 | vpiHandle resp_pkt_data_handle = vpi_handle_by_name(RESP_PKT_DATA_PATH, NULL); 69 | s_vpi_value resp_pkt_data_val = {vpiBinStrVal, resp.pkt_data}; 70 | vpi_put_value(resp_pkt_data_handle, &resp_pkt_data_val, NULL, vpiNoDelay); 71 | } 72 | 73 | 74 | void write_outputs(void) { 75 | vpiHandle next_seq_handle = vpi_handle_by_name(NEXT_SEQ_PATH, NULL); 76 | s_vpi_value next_seq_val = {vpiIntVal}; 77 | vpi_get_value(next_seq_handle, &next_seq_val); 78 | int next_seq = next_seq_val.value.integer; 79 | 80 | vpiHandle next_seq_tx_id_handle = vpi_handle_by_name(NEXT_SEQ_TX_ID_PATH, NULL); 81 | s_vpi_value next_seq_tx_id_val = {vpiIntVal}; 82 | vpi_get_value(next_seq_tx_id_handle, &next_seq_tx_id_val); 83 | int next_seq_tx_id = next_seq_tx_id_val.value.integer; 84 | 85 | vpiHandle next_seq_fid_handle = vpi_handle_by_name(NEXT_SEQ_FID_PATH, NULL); 86 | s_vpi_value next_seq_fid_val = {vpiIntVal}; 87 | vpi_get_value(next_seq_fid_handle, &next_seq_fid_val); 88 | int next_seq_fid = next_seq_fid_val.value.integer; 89 | 90 | if (next_seq_fid > 0 && 91 | next_seq_fid < MAX_FLOW_CNT - 1){ 92 | double r = (double)rand() / (double)RAND_MAX; 93 | if (r > LOSS_PROB){ 94 | SWAck(&rcvd[next_seq_fid], next_seq); 95 | 96 | struct AckQueueElement new_ack; 97 | new_ack.fid = next_seq_fid; 98 | new_ack.cumulative_ack = SWGetCumulativeAck(&rcvd[next_seq_fid]); 99 | new_ack.selective_ack = next_seq; 100 | new_ack.sack_tx_id = next_seq_tx_id; 101 | new_ack.rcvd_time = time_in_ns + RTT_IN_NS; 102 | prioEnqueue(&ackQueue, new_ack); 103 | /*vpi_printf("enqueued %d %d %d %d\n", new_ack.fid, 104 | new_ack.cumulative_ack, 105 | new_ack.selective_ack, 106 | new_ack.sack_tx_id); 107 | */ 108 | } 109 | else{ 110 | vpi_printf("dropped %d %d\n", next_seq_fid, next_seq); 111 | } 112 | } 113 | else{ 114 | } 115 | 116 | } 117 | 118 | /******** register vpi calls ***********/ 119 | 120 | void registerReadInputsSystfs() { 121 | s_vpi_systf_data task_data_s; 122 | p_vpi_systf_data task_data_p = &task_data_s; 123 | task_data_p->type = vpiSysTask; 124 | task_data_p->tfname = "$read_inputs"; 125 | task_data_p->calltf = read_inputs; 126 | task_data_p->compiletf = 0; 127 | 128 | vpi_register_systf(task_data_p); 129 | } 130 | 131 | void registerWriteOutputsSystfs() { 132 | s_vpi_systf_data task_data_s; 133 | p_vpi_systf_data task_data_p = &task_data_s; 134 | task_data_p->type = vpiSysTask; 135 | task_data_p->tfname = "$write_outputs"; 136 | task_data_p->calltf = write_outputs; 137 | task_data_p->compiletf = 0; 138 | 139 | vpi_register_systf(task_data_p); 140 | } 141 | 142 | void registerInitSystfs() { 143 | s_vpi_systf_data task_data_s; 144 | p_vpi_systf_data task_data_p = &task_data_s; 145 | task_data_p->type = vpiSysTask; 146 | task_data_p->tfname = "$init_vpi"; 147 | task_data_p->calltf = init; 148 | task_data_p->compiletf = 0; 149 | 150 | vpi_register_systf(task_data_p); 151 | } 152 | 153 | void registerSendClkSystfs() { 154 | s_vpi_systf_data task_data_s; 155 | p_vpi_systf_data task_data_p = &task_data_s; 156 | task_data_p->type = vpiSysTask; 157 | task_data_p->tfname = "$send_clk"; 158 | task_data_p->calltf = send_clk; 159 | task_data_p->compiletf = 0; 160 | 161 | vpi_register_systf(task_data_p); 162 | } 163 | 164 | -------------------------------------------------------------------------------- /tb/sim/common/sim_receiver/sim_receiver.tab: -------------------------------------------------------------------------------- 1 | $read_inputs call=read_inputs 2 | $write_outputs call=write_outputs 3 | $init call=init 4 | $send_clk call=send_clk 5 | -------------------------------------------------------------------------------- /tb/sim/common/sim_receiver/sim_receiver.v: -------------------------------------------------------------------------------- 1 | module sim_receiver #(parameter RTT = -1, 2 | parameter LOSS_PROB = -1)( 3 | 4 | input clk, 5 | input rst_n, 6 | 7 | input [`FLOW_SEQ_NUM_W-1:0] next_seq_in, 8 | input [`TX_CNT_W-1:0] next_seq_tx_id_in, 9 | input [`FLOW_ID_W-1:0] next_seq_fid_in, 10 | 11 | output reg [`FLOW_ID_W-1:0] resp_fid, 12 | output reg [`PKT_TYPE_W-1:0] resp_pkt_type, 13 | output reg [`PKT_DATA_W-1:0] resp_pkt_data 14 | ); 15 | 16 | localparam LINK_RTT = RTT; 17 | localparam LINK_LOSS_PROB = LOSS_PROB; 18 | 19 | reg [`FLOW_ID_W-1:0] read_resp_fid; 20 | reg [`PKT_TYPE_W-1:0] read_resp_pkt_type; 21 | reg [`PKT_DATA_W-1:0] read_resp_pkt_data; 22 | 23 | initial begin 24 | read_resp_fid = `FLOW_ID_NONE; 25 | read_resp_pkt_type = `NONE_PKT; 26 | read_resp_pkt_data = {`PKT_DATA_W{1'b0}}; 27 | end 28 | 29 | initial begin 30 | $init; 31 | end 32 | 33 | always @(posedge clk) begin 34 | $send_clk; 35 | end 36 | 37 | always @(posedge clk) begin 38 | if (rst_n) begin 39 | resp_fid <= read_resp_fid; 40 | resp_pkt_type <= read_resp_pkt_type; 41 | resp_pkt_data <= read_resp_pkt_data; 42 | end 43 | else begin 44 | resp_fid <= `FLOW_ID_NONE; 45 | resp_pkt_type <= `NONE_PKT; 46 | resp_pkt_data <= {`PKT_DATA_W{1'b0}}; 47 | end 48 | end 49 | 50 | always @(posedge clk) begin 51 | if (rst_n) begin 52 | $read_inputs; 53 | end 54 | end 55 | 56 | always @(posedge clk) begin 57 | if (rst_n) begin 58 | $write_outputs; 59 | end 60 | end 61 | 62 | `include "clogb2.vh" 63 | endmodule 64 | -------------------------------------------------------------------------------- /tb/sim/common/sim_receiver/sliding_window.c: -------------------------------------------------------------------------------- 1 | #include "sliding_window.h" 2 | #include "constants.h" 3 | 4 | void SWInit(struct SlidingWindow* sw){ 5 | sw->head = 0; 6 | sw->head_seq = 0; 7 | } 8 | 9 | void SWAck(struct SlidingWindow* sw, int ack_seq){ 10 | int ack_rel = ack_seq - sw->head_seq; 11 | if (ack_rel < 0 || ack_rel >= FLOW_WIN_SIZE) return; 12 | int ack = (sw->head + ack_rel) % FLOW_WIN_SIZE; 13 | sw->elems[ack] = 1; 14 | int i; 15 | int did_break = false; 16 | for (i = 0; i < FLOW_WIN_SIZE; i++){ 17 | int ind = (sw->head + i) % FLOW_WIN_SIZE; 18 | if (sw->elems[ind]){ 19 | sw->elems[ind] = 0; 20 | } 21 | else{ 22 | did_break = true; 23 | break; 24 | } 25 | } 26 | 27 | if (did_break){ 28 | sw->head = (sw->head + i) % FLOW_WIN_SIZE; 29 | sw->head_seq += i; 30 | } 31 | else{ 32 | sw->head_seq += FLOW_WIN_SIZE; 33 | } 34 | } 35 | 36 | int SWGetCumulativeAck(struct SlidingWindow* sw){ 37 | return sw->head_seq; 38 | } 39 | 40 | void SWPrint(struct SlidingWindow* sw){ 41 | int i; 42 | for (i = 0; i < FLOW_WIN_SIZE; i++){ 43 | printf("%d:%d, ", sw->head_seq + i, 44 | sw->elems[(sw->head + i) % FLOW_WIN_SIZE]); 45 | } 46 | printf("\n"); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /tb/sim/common/sim_receiver/sliding_window.h: -------------------------------------------------------------------------------- 1 | #ifndef SLIDING_WINDOW__H 2 | #define SLIDING_WINDOW__H 3 | 4 | #include "constants.h" 5 | 6 | struct SlidingWindow{ 7 | int elems[FLOW_WIN_SIZE]; 8 | int head; 9 | int head_seq; 10 | }; 11 | 12 | void SWInit(struct SlidingWindow*); 13 | void SWAck(struct SlidingWindow*, int); 14 | int SWGetCumulativeAck(struct SlidingWindow*); 15 | void SWPrint(struct SlidingWindow*); 16 | #endif 17 | -------------------------------------------------------------------------------- /tb/sim/sim.flist: -------------------------------------------------------------------------------- 1 | ##################################### 2 | ## Include Search Paths 3 | ###################################### 4 | +incdir+$TONIC_HOME/include/ 5 | -------------------------------------------------------------------------------- /tb/sim/tonic/cr_flists/cwnd.flist: -------------------------------------------------------------------------------- 1 | ## Engine and Core 2 | 3 | $TONIC_HOME/src/cr_engine/cwnd/cr_engine.v 4 | $TONIC_HOME/src/cr_engine/cwnd/cr_core.v 5 | 6 | ## Fifos 7 | $TONIC_HOME/src/fifos/fifo_2w/fifo_2w.v 8 | 9 | ## event processors 10 | 11 | $TONIC_HOME/src/cr_engine/common/event_processors/cr_enqueue/cr_enqueue.v 12 | $TONIC_HOME/src/cr_engine/cwnd/event_processors/cr_transmit/cr_transmit.v 13 | 14 | ## context store 15 | 16 | $TONIC_HOME/src/context_store/2w2r/cntxt_store_2w2r.v 17 | -------------------------------------------------------------------------------- /tb/sim/tonic/cr_flists/rate.flist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minmit/tonic/c156930bc665af1a89954bad9f00ca903a154a7e/tb/sim/tonic/cr_flists/rate.flist -------------------------------------------------------------------------------- /tb/sim/tonic/cr_flists/token.flist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/minmit/tonic/c156930bc665af1a89954bad9f00ca903a154a7e/tb/sim/tonic/cr_flists/token.flist -------------------------------------------------------------------------------- /tb/sim/tonic/nreno_1/receiver_resp.c: -------------------------------------------------------------------------------- 1 | #include "receiver_resp.h" 2 | #include "vpi_user.h" 3 | 4 | #include 5 | 6 | int INT_BUFF_SIZE = 32; 7 | 8 | char* int2bin(int a, char* buffer) { 9 | int i; 10 | for (i = INT_BUFF_SIZE-1; i >= 0; i--) { 11 | if (a % 2) buffer[i] = '1'; 12 | else buffer[i] = '0'; 13 | 14 | a /= 2; 15 | } 16 | return buffer; 17 | } 18 | 19 | void receiver_resp(int fid, int cumulative_ack, 20 | int selective_ack, int sack_tx_id, 21 | struct ReceiverResp* resp){ 22 | 23 | resp->fid = fid; 24 | resp->pkt_type = CACK_PKT; 25 | 26 | resp->pkt_data[100] = '\0'; 27 | int ind_in_data = 0; 28 | int2bin(cumulative_ack, resp->pkt_data + ind_in_data); 29 | ind_in_data += INT_BUFF_SIZE; 30 | 31 | sprintf(resp->pkt_data + ind_in_data, "%0*d", PKT_DATA_W - ind_in_data, 0); 32 | } 33 | -------------------------------------------------------------------------------- /tb/sim/tonic/nreno_1/sim.flist: -------------------------------------------------------------------------------- 1 | ##################################### 2 | ## Include Search Paths 3 | ###################################### 4 | +incdir+$TONIC_HOME/src/user_defined_logic/nreno_1/include 5 | 6 | ##################################### 7 | # test bench C files 8 | ##################################### 9 | $TONIC_HOME/tb/sim/tonic/nreno_1/receiver_resp.c 10 | 11 | ##################################### 12 | # Design Files 13 | ##################################### 14 | 15 | $TONIC_HOME/src/user_defined_logic/nreno_1/user_defined_incoming.v 16 | $TONIC_HOME/src/user_defined_logic/nreno_1/user_defined_timeout.v 17 | 18 | -f $TONIC_HOME/tb/sim/tonic/cr_flists/cwnd.flist 19 | -------------------------------------------------------------------------------- /tb/sim/tonic/nreno_2/receiver_resp.c: -------------------------------------------------------------------------------- 1 | #include "receiver_resp.h" 2 | #include "vpi_user.h" 3 | 4 | #include 5 | 6 | int INT_BUFF_SIZE = 32; 7 | 8 | char* int2bin(int a, char* buffer) { 9 | int i; 10 | for (i = INT_BUFF_SIZE-1; i >= 0; i--) { 11 | if (a % 2) buffer[i] = '1'; 12 | else buffer[i] = '0'; 13 | 14 | a /= 2; 15 | } 16 | return buffer; 17 | } 18 | 19 | void receiver_resp(int fid, int cumulative_ack, 20 | int selective_ack, int sack_tx_id, 21 | struct ReceiverResp* resp){ 22 | 23 | resp->fid = fid; 24 | resp->pkt_type = CACK_PKT; 25 | 26 | resp->pkt_data[100] = '\0'; 27 | int ind_in_data = 0; 28 | int2bin(cumulative_ack, resp->pkt_data + ind_in_data); 29 | ind_in_data += INT_BUFF_SIZE; 30 | 31 | sprintf(resp->pkt_data + ind_in_data, "%0*d", PKT_DATA_W - ind_in_data, 0); 32 | } 33 | -------------------------------------------------------------------------------- /tb/sim/tonic/nreno_2/sim.flist: -------------------------------------------------------------------------------- 1 | ##################################### 2 | ## Include Search Paths 3 | ###################################### 4 | +incdir+$TONIC_HOME/src/user_defined_logic/nreno_2/include 5 | 6 | ##################################### 7 | # test bench C files 8 | ##################################### 9 | $TONIC_HOME/tb/sim/tonic/nreno_2/receiver_resp.c 10 | 11 | ##################################### 12 | # Design Files 13 | ##################################### 14 | 15 | $TONIC_HOME/src/user_defined_logic/nreno_2/user_defined_incoming.v 16 | $TONIC_HOME/src/user_defined_logic/nreno_2/user_defined_timeout.v 17 | 18 | -f $TONIC_HOME/tb/sim/tonic/cr_flists/cwnd.flist 19 | -------------------------------------------------------------------------------- /tb/sim/tonic/reno/receiver_resp.c: -------------------------------------------------------------------------------- 1 | #include "receiver_resp.h" 2 | #include "vpi_user.h" 3 | 4 | #include 5 | 6 | int INT_BUFF_SIZE = 32; 7 | 8 | char* int2bin(int a, char* buffer) { 9 | int i; 10 | for (i = INT_BUFF_SIZE-1; i >= 0; i--) { 11 | if (a % 2) buffer[i] = '1'; 12 | else buffer[i] = '0'; 13 | 14 | a /= 2; 15 | } 16 | return buffer; 17 | } 18 | 19 | void receiver_resp(int fid, int cumulative_ack, 20 | int selective_ack, int sack_tx_id, 21 | struct ReceiverResp* resp){ 22 | 23 | resp->fid = fid; 24 | resp->pkt_type = CACK_PKT; 25 | 26 | resp->pkt_data[100] = '\0'; 27 | int ind_in_data = 0; 28 | int2bin(cumulative_ack, resp->pkt_data + ind_in_data); 29 | ind_in_data += INT_BUFF_SIZE; 30 | 31 | sprintf(resp->pkt_data + ind_in_data, "%0*d", PKT_DATA_W - ind_in_data, 0); 32 | } 33 | -------------------------------------------------------------------------------- /tb/sim/tonic/reno/sim.flist: -------------------------------------------------------------------------------- 1 | ##################################### 2 | ## Include Search Paths 3 | ###################################### 4 | +incdir+$TONIC_HOME/src/user_defined_logic/reno/include 5 | 6 | ##################################### 7 | # test bench C files 8 | ##################################### 9 | $TONIC_HOME/tb/sim/tonic/reno/receiver_resp.c 10 | 11 | ##################################### 12 | # Design Files 13 | ##################################### 14 | 15 | $TONIC_HOME/src/user_defined_logic/reno/user_defined_incoming.v 16 | $TONIC_HOME/src/user_defined_logic/reno/user_defined_timeout.v 17 | 18 | -f $TONIC_HOME/tb/sim/tonic/cr_flists/cwnd.flist 19 | -------------------------------------------------------------------------------- /tb/sim/tonic/sack/receiver_resp.c: -------------------------------------------------------------------------------- 1 | #include "receiver_resp.h" 2 | #include "vpi_user.h" 3 | 4 | #include 5 | 6 | int INT_BUFF_SIZE = 32; 7 | 8 | char* int2bin(int a, char* buffer) { 9 | int i; 10 | for (i = INT_BUFF_SIZE-1; i >= 0; i--) { 11 | if (a % 2) buffer[i] = '1'; 12 | else buffer[i] = '0'; 13 | 14 | a /= 2; 15 | } 16 | return buffer; 17 | } 18 | 19 | void receiver_resp(int fid, int cumulative_ack, 20 | int selective_ack, int sack_tx_id, 21 | struct ReceiverResp* resp){ 22 | 23 | resp->fid = fid; 24 | resp->pkt_type = CACK_PKT; 25 | 26 | resp->pkt_data[100] = '\0'; 27 | int ind_in_data = 0; 28 | int2bin(cumulative_ack, resp->pkt_data + ind_in_data); 29 | ind_in_data += INT_BUFF_SIZE; 30 | 31 | sprintf(resp->pkt_data + ind_in_data, "%0*d", PKT_DATA_W - ind_in_data, 0); 32 | } 33 | -------------------------------------------------------------------------------- /tb/sim/tonic/sack/sim.flist: -------------------------------------------------------------------------------- 1 | ##################################### 2 | ## Include Search Paths 3 | ###################################### 4 | +incdir+$TONIC_HOME/src/user_defined_logic/sack/include 5 | 6 | ##################################### 7 | # test bench C files 8 | ##################################### 9 | $TONIC_HOME/tb/sim/tonic/sack/receiver_resp.c 10 | 11 | ##################################### 12 | # Design Files 13 | ##################################### 14 | 15 | $TONIC_HOME/src/user_defined_logic/sack/user_defined_incoming.v 16 | $TONIC_HOME/src/user_defined_logic/sack/user_defined_timeout.v 17 | 18 | -f $TONIC_HOME/tb/sim/tonic/cr_flists/cwnd.flist 19 | -------------------------------------------------------------------------------- /tb/sim/tonic/sim.flist: -------------------------------------------------------------------------------- 1 | ##################################### 2 | ## Include Search Paths 3 | ###################################### 4 | 5 | ##################################### 6 | # test bench files 7 | ##################################### 8 | $TONIC_HOME/tb/sim/tonic/sim_top.v 9 | 10 | ##################################### 11 | # Design Files 12 | ##################################### 13 | 14 | $TONIC_HOME/src/tonic.v 15 | 16 | ## dd_engine 17 | 18 | $TONIC_HOME/src/dd_engine/dd_engine.v 19 | 20 | $TONIC_HOME/src/dd_engine/dd_core.v 21 | 22 | $TONIC_HOME/src/dd_engine/event_processors/dd_incoming/dd_incoming_0.v 23 | $TONIC_HOME/src/dd_engine/event_processors/dd_incoming/dd_incoming_1.v 24 | $TONIC_HOME/src/dd_engine/event_processors/dd_timeout/dd_timeout.v 25 | 26 | $TONIC_HOME/src/dd_engine/event_processors/dd_next/dd_next.v 27 | $TONIC_HOME/src/dd_engine/event_processors/dd_dequeue_prop/dd_dequeue_prop.v 28 | 29 | ## bitmap_ops 30 | 31 | $TONIC_HOME/src/bitmap_ops/ff_wnd/ff_wnd.v 32 | $TONIC_HOME/src/bitmap_ops/ff_wnd/ff_block.v 33 | $TONIC_HOME/src/bitmap_ops/ff_wnd/ff_set.v 34 | 35 | $TONIC_HOME/src/bitmap_ops/cnt_wnd/cnt_wnd.v 36 | $TONIC_HOME/src/bitmap_ops/cnt_wnd/cnt_block.v 37 | $TONIC_HOME/src/bitmap_ops/cnt_wnd/cnt_set.v 38 | 39 | ## Fifos 40 | 41 | $TONIC_HOME/src/fifos/fifo_4w/fifo_4w.v 42 | $TONIC_HOME/src/fifos/fifo_1w/fifo_1w.v 43 | 44 | ## context store 45 | 46 | $TONIC_HOME/src/context_store/4w4r/cntxt_store_4w4r.v 47 | 48 | ## RAM 49 | $TONIC_HOME/src/ram/ram_4w4r.v 50 | $TONIC_HOME/src/ram/ram_2w4r.v 51 | $TONIC_HOME/src/ram/ram_2w2r.v 52 | $TONIC_HOME/src/ram/ram_2p_wrapper.v 53 | 54 | -------------------------------------------------------------------------------- /tools/lib/commonlib.py: -------------------------------------------------------------------------------- 1 | import re, os, subprocess, shlex 2 | import dbglib as dbg 3 | 4 | def launchSlurmJob(job_name, cmd, slurm_dep_l, flog_path): 5 | slurm_file = job_name + ".slurm" 6 | fp = open(slurm_file, "w") 7 | fp.write("#!/bin/sh\n") 8 | fp.write("#SBATCH -N 1\n") 9 | fp.write("#SBATCH -c 8\n") 10 | fp.write("#SBATCH --mem=65536\n") 11 | fp.write("#SBATCH -t 24:00:00\n") 12 | fp.write("#SBATCH -J %s\n\n" % job_name) 13 | fp.write("%s > %s" % (cmd, flog_path)) 14 | fp.close() 15 | 16 | os.chmod(slurm_file, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) 17 | 18 | retry_limit = 128 19 | 20 | if len(slurm_dep_l) > 0: 21 | opt_dep = "--dependency=afterok:" + ':'.join([str(job_id) for job_id in slurm_dep_l]) 22 | else: 23 | opt_dep = '' 24 | 25 | slurm_cmd = "sbatch %s %s" % (opt_dep, slurm_file) 26 | dbg.print_info("Slurm command: %s" % slurm_cmd) 27 | proc = subprocess.Popen(shlex.split(slurm_cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE) 28 | out, err = proc.communicate() 29 | retry_cnt = 1 30 | while proc.returncode != 0: 31 | if retry_cnt > retry_limit: 32 | dbg.print_error("Failed to submit command %s through slurm" % cmd) 33 | return None 34 | else: 35 | dbg.print_info("Slurm submission failed. Retrying in 30 seconds...") 36 | time.sleep(30) 37 | dbg.print_info("Submitting slurm job") 38 | proc = subprocess.Popen(shlex.split(slurm_cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE) 39 | out, err = proc.communicate() 40 | 41 | # Get job ID 42 | match = re.match("Submitted batch job (\d+)\n", out) 43 | if match != None: 44 | job_id = int(match.group(1)) 45 | dbg.print_info("Submitted batch job %d" % job_id) 46 | return job_id 47 | else: 48 | dbg.print_error("Can't find submitted job id!") 49 | return None 50 | 51 | # Nonblocking 52 | # Returns process ID 53 | def launchJob(job_name, cmd, use_slurm, slurm_dep_l, flog): 54 | if use_slurm: 55 | pid = launchSlurmJob(job_name, cmd, slurm_dep_l, flog) 56 | else: 57 | pid = subprocess.Popen(shlex.split(cmd), stdout=flog, stderr=flog) 58 | 59 | return pid 60 | 61 | def strInFile(fpath, str_l): 62 | try: 63 | f = open(fpath, 'r') 64 | fdata = f.read() 65 | f.close() 66 | except IOError: 67 | dbg.print_error("Can't open file: %s" % fpath) 68 | return False 69 | 70 | # File was opened and read 71 | for s in str_l: 72 | m = re.search(s, fdata) 73 | if m == None: 74 | return False 75 | 76 | return True -------------------------------------------------------------------------------- /tools/lib/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | TONIC_HOME = os.environ["TONIC_HOME"] 4 | BUILD_DIR = os.path.join(TONIC_HOME, "build") 5 | TB_DIR = os.path.join(TONIC_HOME, "tb") 6 | TB_CONFIG_DIR = os.path.join(TB_DIR, "config") 7 | TB_UNIT_DIR = os.path.join(TB_DIR, "unit") 8 | TB_SYSTEM_DIR = os.path.join(TB_DIR, "system") 9 | TB_SIM_DIR = os.path.join(TB_DIR, "sim") 10 | VPI_RECEIVER_DIR = os.path.join(TB_DIR, "sim", "common", "sim_receiver") 11 | -------------------------------------------------------------------------------- /tools/lib/dbglib.py: -------------------------------------------------------------------------------- 1 | import sys, inspect 2 | 3 | LOG_LEVEL_ERROR = 0 4 | LOG_LEVEL_WARNING = 1 5 | LOG_LEVEL_ALL = 2 6 | 7 | LOG_LEVEL = LOG_LEVEL_ALL 8 | DEBUG = True 9 | DEFAULT_LOG_STREAM = sys.stdout 10 | 11 | class clr: 12 | RED = '\033[91m' 13 | GREEN = '\033[92m' 14 | YELLOW = '\033[93m' 15 | BLUE = '\033[94m' 16 | CYAN = '\033[96m' 17 | RST_CLR = '\033[0m' 18 | 19 | def getFuncLine(): 20 | # stack: [0] - current, [1] - print_* function, [2] - program 21 | frame_record = inspect.stack()[2] 22 | frame = frame_record[0] 23 | info = inspect.getframeinfo(frame) 24 | fname_short = info.filename.split('/')[-1] 25 | retval = "%s:%3d" % (fname_short, info.lineno) 26 | return retval 27 | 28 | def print_debug(msg, fstream=DEFAULT_LOG_STREAM): 29 | if DEBUG: 30 | msg_print = clr.CYAN + "[DEBUG] " + getFuncLine() + clr.RST_CLR + ": " + msg.strip() 31 | print >> fstream, msg_print 32 | 33 | def print_info(msg, fstream=DEFAULT_LOG_STREAM): 34 | if LOG_LEVEL >= LOG_LEVEL_ALL: 35 | msg_print = clr.BLUE + "[INFO] " + getFuncLine() + clr.RST_CLR + ": " + msg.strip() 36 | print >> fstream, msg_print 37 | 38 | def print_warning(msg, fstream=DEFAULT_LOG_STREAM): 39 | if LOG_LEVEL >= LOG_LEVEL_WARNING: 40 | msg_print = clr.YELLOW + "[WARN] " + getFuncLine() + clr.RST_CLR + ": " + msg.strip() 41 | print >> fstream, msg_print 42 | 43 | def print_error(msg, fstream=DEFAULT_LOG_STREAM): 44 | if LOG_LEVEL >= LOG_LEVEL_ERROR: 45 | msg_print = clr.RED + "[ERROR] " + getFuncLine() + clr.RST_CLR + ": " + msg.strip() 46 | print >> fstream, msg_print 47 | 48 | def print_success(msg, fstream=DEFAULT_LOG_STREAM): 49 | if LOG_LEVEL >= LOG_LEVEL_ALL: 50 | msg_print = clr.GREEN + "[PASS] " + getFuncLine() + clr.RST_CLR + ": " + msg.strip() 51 | print >> fstream, msg_print 52 | -------------------------------------------------------------------------------- /tools/lib/simlib.py: -------------------------------------------------------------------------------- 1 | import os, subprocess, re 2 | # Local modules 3 | import commonlib as common 4 | import config as cfg 5 | import dbglib as dbg 6 | 7 | def genSimDefs(tb_name, param_d, spec_d): 8 | def_s = "" 9 | for param in param_d: 10 | d = " +define+%s_%s=%s" % (tb_name.upper(), param.upper(), str(param_d[param])) 11 | def_s += d 12 | 13 | for spec in spec_d: 14 | d = " +define+%s=%s" % (spec.upper(), str(spec_d[spec])) 15 | def_s += d 16 | 17 | if dbg.DEBUG: 18 | def_s += "+define+DEBUG" 19 | 20 | return def_s 21 | 22 | def buildSim(tb_name, tb_dir, tb_name_l, 23 | param_d, spec_d, build_dir, flog): 24 | sim_tool = "vcs" 25 | build_opt = "-full64 +v2k -debug_all +lint=all,noVCDE -timescale=1ps/1ps" 26 | 27 | ## flists 28 | common_flist_path = os.path.join(tb_dir, "sim.flist") 29 | 30 | other_flist_path = tb_dir 31 | all_other_flists = '' 32 | for name in tb_name_l: 33 | other_flist_path = os.path.join(other_flist_path, name) 34 | all_other_flists += '-f %s ' % os.path.join(other_flist_path, "sim.flist") 35 | 36 | ## other 37 | sim_def = genSimDefs(tb_name_l[0], param_d, spec_d) 38 | 39 | build_cmd = "%s %s -f %s %s %s" % (sim_tool, build_opt, common_flist_path, 40 | all_other_flists, sim_def) 41 | 42 | prev_dir = os.getcwd() 43 | os.chdir(build_dir) 44 | # TODO: change for Slurm 45 | flog.write("*"*40 + '\n') 46 | flog.write("Build command:\n") 47 | flog.write("*"*40 + '\n') 48 | flog.write(build_cmd + '\n') 49 | flog.write("*"*40 + '\n') 50 | flog.write("\n\n") 51 | flog.flush() 52 | proc = common.launchJob(None, build_cmd, False, [], flog) 53 | proc.wait() 54 | os.chdir(prev_dir) 55 | 56 | return proc.returncode 57 | 58 | def buildSimWithVPI(tb_name, tb_dir, tb_name_l, 59 | param_d, spec_d, build_dir, flog): 60 | sim_tool = "vcs" 61 | build_opt = "-full64 +v2k +vpi -debug_all +lint=all,noVCDE -timescale=1ps/1ps" 62 | 63 | ## flists 64 | common_flist_path = os.path.join(tb_dir, "sim.flist") 65 | 66 | other_flist_path = tb_dir 67 | all_other_flists = '' 68 | for name in tb_name_l: 69 | other_flist_path = os.path.join(other_flist_path, name) 70 | all_other_flists += '-f %s ' % os.path.join(other_flist_path, "sim.flist") 71 | 72 | vpi_flist_path = os.path.join(cfg.VPI_RECEIVER_DIR, "sim.flist") 73 | 74 | ## CFLAGS 75 | cflags = "-CFLAGS " 76 | cflags += '"-I%s" ' % cfg.VPI_RECEIVER_DIR 77 | #cflags += '"-I%s/amd64/lib" ' % os.environ['VCS_HOME'] 78 | 79 | ## other 80 | sim_def = genSimDefs(tb_name_l[0], param_d, spec_d) 81 | tab_path = os.path.join(cfg.VPI_RECEIVER_DIR, "sim_receiver.tab") 82 | 83 | 84 | 85 | build_cmd = "%s %s -P %s -f %s %s -f %s %s %s" % (sim_tool, build_opt, tab_path, common_flist_path, 86 | all_other_flists, vpi_flist_path, sim_def, cflags) 87 | 88 | prev_dir = os.getcwd() 89 | os.chdir(build_dir) 90 | # TODO: change for Slurm 91 | flog.write("*"*40 + '\n') 92 | flog.write("Build command:\n") 93 | flog.write("*"*40 + '\n') 94 | flog.write(build_cmd + '\n') 95 | flog.write("*"*40 + '\n') 96 | flog.write("\n\n") 97 | flog.flush() 98 | proc = common.launchJob(None, build_cmd, False, [], flog) 99 | proc.wait() 100 | os.chdir(prev_dir) 101 | 102 | return proc.returncode 103 | 104 | def runSim(tb_name, build_dir, flog): 105 | prev_dir = os.getcwd() 106 | os.chdir(build_dir) 107 | proc = subprocess.Popen("./simv", stdout=flog, stderr=flog) 108 | proc.wait() 109 | 110 | os.chdir(prev_dir) 111 | 112 | def isTestPassed(log_path): 113 | flog = open(log_path, 'r') 114 | log_data = flog.read() 115 | flog.close() 116 | 117 | m = re.search("PASSED", log_data) 118 | if m == None: 119 | return False 120 | else: 121 | return True 122 | -------------------------------------------------------------------------------- /tools/lib/testlib.py: -------------------------------------------------------------------------------- 1 | import os, yaml, shlex, sys 2 | import subprocess as subp 3 | # User Modules 4 | import config as cfg 5 | import dbglib as dbg 6 | import simlib as sim 7 | 8 | 9 | class Test(object): 10 | def __init__(self, name, tb_dir, config_d): 11 | self.name = name 12 | self.tb_dir = tb_dir 13 | self.config_d = config_d 14 | self.build_dir = os.path.join(cfg.BUILD_DIR, name) 15 | self.CreateBuildDir() 16 | self.use_slurm = False 17 | self.buildsim_log = os.path.join(self.build_dir, "buildsim.log") 18 | self.runsim_log = os.path.join(self.build_dir, "runsim.log") 19 | 20 | rest, n = os.path.split(self.name) 21 | self.tb_name_l = [n] 22 | while len(rest) > 0: 23 | rest, n = os.path.split(rest) 24 | self.tb_name_l.append(n) 25 | 26 | self.tb_name_l.reverse() 27 | 28 | # Create build folder if it doesn't exist 29 | def CreateBuildDir(self): 30 | if not os.path.exists(self.build_dir): 31 | dbg.print_info("Creating build folder: %s" % self.build_dir) 32 | os.makedirs(self.build_dir) 33 | 34 | def GetName(self): 35 | return self.name 36 | 37 | def GetParams(self): 38 | return self.config_d['params'] 39 | 40 | def GetSpecs(self): 41 | return self.config_d['specs'] 42 | 43 | def Run(self): 44 | # Build simulation model 45 | dbg.print_info("Building simulation model for '%s'" % self.name) 46 | flog = open(self.buildsim_log, 'w') 47 | rv = sim.buildSim(self.name, self.tb_dir, self.tb_name_l, 48 | self.GetParams(), self.GetSpecs(), self.build_dir, flog) 49 | flog.close() 50 | if rv != 0: 51 | dbg.print_error("Failed to build a simulation model for '%s'" % self.name) 52 | dbg.print_error("Check log: %s" % self.buildsim_log) 53 | return 1 54 | 55 | # Run Simulation 56 | dbg.print_info("Running simulation for '%s'" % self.name) 57 | flog = open(self.runsim_log, 'w') 58 | sim.runSim(self.name, self.build_dir, flog) 59 | flog.close() 60 | 61 | # Check if test passed 62 | if sim.isTestPassed(self.runsim_log): 63 | dbg.print_success("Test for '%s' passed" % self.name) 64 | else: 65 | dbg.print_error("Test for '%s' failed" % self.name) 66 | 67 | return 0 68 | 69 | 70 | class UnitTest(Test): 71 | def __init__(self, name, tb_dir, config_d): 72 | super(UnitTest, self).__init__(name, tb_dir, config_d) 73 | self.gen_ss_log = os.path.join(self.build_dir, "gen_ss.log") 74 | 75 | def genSrcSnk(self): 76 | gen_ss_path = os.path.join(cfg.TB_UNIT_DIR, self.name, "gen_ss.py") 77 | gen_ss_opt = "" 78 | param_d = self.GetParams() 79 | for param_name in param_d: 80 | gen_ss_opt += " --%s %d" % (param_name, param_d[param_name]) 81 | 82 | spec_d = self.GetSpecs() 83 | for spec_name in spec_d: 84 | gen_ss_opt += " --%s %d" % (spec_name, spec_d[spec_name]) 85 | 86 | if dbg.DEBUG: 87 | gen_ss_opt += " --debug" 88 | 89 | gen_ss_cmd = gen_ss_path + gen_ss_opt 90 | #TODO: change for slurm 91 | flog = open(self.gen_ss_log, 'w') 92 | proc = subp.Popen(shlex.split(gen_ss_cmd), stdout=flog, stderr=flog) 93 | proc.wait() 94 | flog.close() 95 | return proc.returncode 96 | 97 | def Run(self): 98 | # Generate src/snk files 99 | dbg.print_info("Generating SRC/SNK files for '%s'" % self.name) 100 | rv = self.genSrcSnk() 101 | if rv != 0: 102 | dbg.print_error("Failed to generate SRC/SNK files for '%s'" % self.name) 103 | dbg.print_error("Check log: %s" % self.gen_ss_log) 104 | return 1 105 | 106 | super(UnitTest, self).Run() 107 | 108 | class SystemTest(Test): 109 | def __init__(self, name, tb_dir, config_d): 110 | super(SystemTest, self).__init__(name, tb_dir, config_d) 111 | 112 | class Sim(Test): 113 | def __init__(self, name, tb_dir, config_d): 114 | super(Sim, self).__init__(name, tb_dir, config_d) 115 | 116 | def NeedsReceiver(self): 117 | return ('receiver' in self.config_d['specs'] 118 | and self.config_d['specs']['receiver']) 119 | 120 | def Run(self): 121 | # Build simulation model 122 | dbg.print_info("Building simulation model for '%s'" % self.name) 123 | flog = open(self.buildsim_log, 'w') 124 | 125 | if self.NeedsReceiver(): 126 | rv = sim.buildSimWithVPI(self.name, self.tb_dir, self.tb_name_l, 127 | self.GetParams(), self.GetSpecs(), 128 | self.build_dir, flog) 129 | else: 130 | rv = sim.buildSim(self.name, self.tb_dir, self.tb_name_l, 131 | self.GetParams(), self.GetSpecs(), 132 | self.build_dir, flog) 133 | 134 | flog.close() 135 | if rv != 0: 136 | dbg.print_error("Failed to build a simulation model for '%s'" % self.name) 137 | dbg.print_error("Check log: %s" % self.buildsim_log) 138 | return 1 139 | 140 | # Run Simulation 141 | dbg.print_info("Running simulation for '%s'" % self.name) 142 | flog = open(self.runsim_log, 'w') 143 | sim.runSim(self.name, self.build_dir, flog) 144 | flog.close() 145 | 146 | # Check if test passed 147 | dbg.print_success("Simulation for '%s' finished" % self.name) 148 | 149 | return 0 150 | 151 | def readTestConfig(cfg_name): 152 | cfg_path = os.path.join(cfg.TB_CONFIG_DIR, cfg_name) 153 | with open(cfg_path, 'r') as ymlfile: 154 | run_cfg = yaml.load(ymlfile) 155 | 156 | return run_cfg 157 | -------------------------------------------------------------------------------- /tools/libconfig.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | 3 | def insertLibPath(): 4 | script_dir = os.path.dirname(os.path.realpath(__file__)) 5 | lib_dir = os.path.join(script_dir, "./lib") 6 | sys.path.insert(0, lib_dir) 7 | 8 | insertLibPath() -------------------------------------------------------------------------------- /tools/runtest: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.7 2 | 3 | from argparse import ArgumentParser 4 | import sys 5 | # User Modules 6 | from libconfig import * 7 | import testlib as test 8 | import dbglib as dbg 9 | import config as cfg 10 | 11 | def main(): 12 | parser = ArgumentParser() 13 | parser._action_groups.pop() 14 | required = parser.add_argument_group('Required Arguments') 15 | required.add_argument("--type", dest="type", required=True, type=str, choices=["sim", "unit", "system"], help="Test type") 16 | required.add_argument("--config", dest="config", required=True, type=str, metavar="", help="YAML configuration file name") 17 | 18 | parser.add_argument("--debug", dest="debug", action='store_true', help="Enable debugging messages") 19 | args = parser.parse_args() 20 | 21 | # Read Test Configuration 22 | run_cfg = test.readTestConfig(args.config) 23 | 24 | if args.type == "sim": 25 | test_class = test.Sim 26 | tb_dir = cfg.TB_SIM_DIR 27 | 28 | elif args.type == "unit": 29 | print "Not implemented in this version" 30 | sys.exit(0) 31 | 32 | elif args.type == "system": 33 | print "Not implemented in this version" 34 | sys.exit(0) 35 | 36 | dbg.DEBUG = args.debug 37 | 38 | # Run tests for every design in configuration file 39 | for design_name in run_cfg.keys(): 40 | dbg.print_info("="*80) 41 | dbg.print_info("%s: '%s'" % (args.type, design_name)) 42 | dbg.print_info("="*80) 43 | test_inst = test_class(design_name, tb_dir, run_cfg[design_name]) 44 | res_code = test_inst.Run() 45 | sys.exit(res_code) 46 | 47 | if __name__ == "__main__": 48 | main() 49 | --------------------------------------------------------------------------------