promach
Advanced Member level 4
I am working on Spidergon Networks-on-Chips verilog code implementation
Please see Spidergon NoC introduction
I am having two problems (I am a bit stucked) with spidergon_node.v and spidergon_top.v respectively.
1) In spidergon_node.v , how should I code the virtual_channels[] such that 'flit_data_input' is assigned to available virtual_channels[] ?
2) In spidergon_top.v , how do I code the verilog such that I could connect 'flit_data_input' and 'flit_data_output' according to the following spidergon architecture ?
spidergon_top.v
spidergon_node.v
router.v
arbiter.v
Please see Spidergon NoC introduction
I am having two problems (I am a bit stucked) with spidergon_node.v and spidergon_top.v respectively.
1) In spidergon_node.v , how should I code the virtual_channels[] such that 'flit_data_input' is assigned to available virtual_channels[] ?
Code:
.flit_data_input(flit_data_input[][]),
.flit_data_output(flit_data_output[][])
2) In spidergon_top.v , how do I code the verilog such that I could connect 'flit_data_input' and 'flit_data_output' according to the following spidergon architecture ?
spidergon_top.v
Code Verilog - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 // [url]https://www.reddit.com/r/algorithms/comments/au94ak/spidergon_networksonchips/[/url] module spidergon_top #(parameter NUM_OF_NODES=32, NODE_BUFFER_WIDTH=4, NUM_OF_VIRTUAL_CHANNELS=2, FLIT_DATA_WIDTH=16 ) (clk, reset, data_input, data_output); // the most significant two bits are to indicate head and/or tail flits, // followed by dest_node and flit_data_payload // See [url]https://www.lisnoc.org/packets.html[/url] // 01 = head_flit , 00 = data_flit (body_flit), 10 = tail_flit, 11 = flit_without_data_payload localparam HEAD_TAIL = 2; localparam DEST_NODE_WIDTH = $clog2(NUM_OF_NODES); localparam FLIT_TOTAL_WIDTH = HEAD_TAIL+FLIT_DATA_WIDTH; localparam NUM_OF_PORTS = 3; // clockwise, anti-clockwise, across input clk, reset; input [FLIT_TOTAL_WIDTH-1:0] data_input; output signed [FLIT_DATA_WIDTH-1:0] data_output; wire [FLIT_TOTAL_WIDTH-1:0] flit_data_input [NUM_OF_NODES-1:0][NUM_OF_PORTS-1:0]; wire [FLIT_TOTAL_WIDTH-1:0] flit_data_output [NUM_OF_NODES-1:0][NUM_OF_PORTS-1:0]; // data entrance and exit for the NoC assign flit_data_input[0][0] = data_input; assign data_output = flit_data_output[NUM_OF_NODES-1][NUM_OF_PORTS-1][0 +: FLIT_DATA_WIDTH]; localparam STOP = 3; localparam ACROSS = 2; localparam CLOCKWISE = 1; localparam ANTI_CLOCKWISE = 0; generate // generates all the nodes of spidergon as well as the connecting edges between nodes genvar node_num; for(node_num = 0; node_num < NUM_OF_NODES; node_num = node_num + 1) begin spidergon_node node #( NUM_OF_NODES, node_num, NODE_BUFFER_WIDTH, NUM_OF_VIRTUAL_CHANNELS, FLIT_DATA_WIDTH ) ( .clk(clk), .reset(reset), .flit_data_input(flit_data_input[][]), .flit_data_output(flit_data_output[][]) ); end endgenerate endmodule
spidergon_node.v
Code Verilog - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 // a single node within the Spidergon module spidergon_node #(parameter NUM_OF_NODES=32, NODE_IDENTIFIER=0, NODE_BUFFER_WIDTH=4, NUM_OF_VIRTUAL_CHANNELS=2, FLIT_DATA_WIDTH=16 ) (clk, reset, flit_data_input, flit_data_output); localparam STOP = 3; localparam ACROSS = 2; localparam CLOCKWISE = 1; localparam ANTI_CLOCKWISE = 0; // the most significant two bits are to indicate head and/or tail flits, // followed by dest_node and flit_data_payload // See [url]https://www.lisnoc.org/packets.html[/url] // 01 = head_flit , 00 = data_flit (body_flit), 10 = tail_flit, 11 = flit_without_data_payload localparam HEAD_TAIL = 2; localparam DEST_NODE_WIDTH = $clog2(NUM_OF_NODES); localparam FLIT_TOTAL_WIDTH = HEAD_TAIL+FLIT_DATA_WIDTH; localparam NUM_OF_PORTS = 3; // clockwise, anti-clockwise, across localparam BIDIRECTIONAL_PER_PORT = 2; // two-way data traffic input clk, reset; input [FLIT_TOTAL_WIDTH-1:0] flit_data_input [NUM_OF_PORTS-1:0]; output reg [FLIT_TOTAL_WIDTH-1:0] flit_data_output [NUM_OF_PORTS-1:0]; reg signed [NODE_BUFFER_WIDTH-1:0] virtual_channels [NUM_OF_VIRTUAL_CHANNELS-1:0][NUM_OF_PORTS-1:0]; // requests for the input data (from one of the 3 input ports) // to be routed to destination node (via one of the 3 output ports) // this 'req' is not a one-hot vector: reg [vc_num] req [out_port]; // multiple input data streams from different virtual channels could compete for the same output port reg [NUM_OF_VIRTUAL_CHANNELS-1:0] req [NUM_OF_PORTS-1:0]; reg [NUM_OF_VIRTUAL_CHANNELS-1:0] req_previous [NUM_OF_PORTS-1:0]; // note that 'grant' is one-hot vector, // when asserted, it means the corresponding 'req' is approved/granted // and only a single priority line is serviced (granted) at any given clock cycle wire [NUM_OF_VIRTUAL_CHANNELS-1:0] grant [NUM_OF_PORTS-1:0]; wire [NUM_OF_VIRTUAL_CHANNELS-1:0] grant_previous [NUM_OF_PORTS-1:0]; localparam DIRECTION_WIDTH = 2; wire [DIRECTION_WIDTH-1:0] direction [NUM_OF_PORTS-1:0]; // stop, clockwise, anti-clockwise, across wire [DEST_NODE_WIDTH-1:0] dest_node [NUM_OF_PORTS-1:0]; genvar port_num; genvar vc_num; generate for(port_num=0; port_num<NUM_OF_PORTS; port_num=port_num+1) begin for(vc_num=0; vc_num<NUM_OF_VIRTUAL_CHANNELS; vc_num=vc_num+1) begin always @(posedge clk) begin if(reset) virtual_channels[port_num][vc_num] <= 0; else begin virtual_channels[port_num][vc_num] <= 0; if() virtual_channels[dest_node][vc_num] <= flit_data_input[port_num]; else virtual_channels[dest_node][vc_num] <= 0; end end always @(posedge clk) begin if(reset) req_previous[port_num][vc_num] <= 0; else req_previous[port_num][vc_num] <= req[port_num][vc_num]; end always @(posedge clk) begin if(reset) req[direction[port_num]][vc_num] <= 0; else begin // check the flit header to determine the flit nature case(flit_data_input[port_num][(FLIT_TOTAL_WIDTH-1) -: HEAD_TAIL]) begin // body_flit // to keep 'req' stable before the arrival of tail_flit 'b00 : req[direction[port_num]][vc_num] <= req_previous[direction[port_num]][vc_num]; // tail_flit 'b01 : req[direction[port_num]][vc_num] <= 0; // head_flit 'b10 : req[direction[port_num]][vc_num] <= 1; // flit_without_data_payload 'b11 : req[direction[port_num]][vc_num] <= 1; default : req[direction[port_num]][vc_num] <= 0; end end end end // virtual channel (VC) buffers round-robin arbitration arbiter rr_arb #(NUM_OF_VIRTUAL_CHANNELS) (.req(req[port_num]), .grant(grant[port_num]), .base(base[port_num])); always @(posedge clk) begin if(reset) grant_previous[port_num] <= 0; else grant_previous[port_num] <= grant[port_num]; end always @(posedge clk) begin // starts round-robin arbiter with priority #1 getting prioritized first if(reset) base[port_num] <= 1; // 'base' is a one-hot signal // which rotates upon 'req' is granted (and tail_flit had arrived), // and wraps around upon reaching MSB else if((grant_previous[port_num] != grant[port_num]) && (req[port_num] == 0)) base[port_num] <= (base[port_num][NUM_OF_VIRTUAL_CHANNELS-1]) ? 1 : (base[port_num] << 1); end assign dest_node[port_num] = flit_data_input[port_num][(FLIT_DATA_WIDTH-1) +: DEST_NODE_WIDTH]; // path routing computation block for each input ports router rt ( .clk(clk), .reset(reset), .dest_node(dest_node[port_num]), .current_node(NODE_IDENTIFIER), .direction(direction[port_num]) ); always @(posedge clk) begin if(reset) flit_data_output[NUM_OF_PORTS-1:0] <= 0; else begin // for Spidergon NoC functional verification and testing flit_data_output[direction[port_num]] <= virtual_channels[direction[port_num]][grant]; // user-defined module (arithmetic operations) within each Spidergon node /*multiply mty #() (.clk(clk), .reset(reset), .in_valid(in_valid), .out_valid(out_valid), .in_A(in_A), .in_B(in_B), .out_C(out_C));*/ end end end endgenerate endmodule
router.v
Code Verilog - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 // shortest path routing algorithm of Spidergon module router #(parameter NUM_OF_NODES = 32) (clk, reset, dest_node, current_node, direction) localparam DIRECTION_WIDTH = 2; localparam STOP = 3; localparam ACROSS = 2; localparam CLOCKWISE = 1; localparam ANTI_CLOCKWISE = 0; input clk, reset; input [$clog2(NUM_OF_NODES)-1:0] dest_node, current_node; output reg [DIRECTION_WIDTH-1:0] direction; // stop, clockwise, anti-clockwise, across // RelAd = ((dest-current) mod (NUM_OF_NODES)) * 4 // [url]https://en.wikipedia.org/wiki/Modulo_operation#Performance_issues[/url] // x % 2^n == x < 0 ? x | ~(2^n - 1) : x & (2^n - 1) wire signed [$clog2(NUM_OF_NODES)-1:0] diff; wire [$clog2(NUM_OF_NODES)-1:0] RelAd; assign diff = dest_node - current_node; assign RelAd = (diff < 0) ? (diff | ~(NUM_OF_NODES-1)) | (diff & (NUM_OF_NODES-1)); localparam SHIFT_BY_TWO = 2; // multiply by four localparam NUM_OF_NODES_TIMES_THREE = 3*NUM_OF_NODES; localparam NUM_OF_NODES_TIMES_FOUR = 4*NUM_OF_NODES; always @(posedge clk) begin if(reset) direction <= STOP; else begin // [url]https://www.verificationguide.com/p/systemverilog-constraint-inside.html[/url] case(RelAd << SHIFT_BY_TWO) inside begin 0 : direction <= STOP; [NUM_OF_NODES:1] : direction <= CLOCKWISE; [NUM_OF_NODES_TIMES_FOUR:NUM_OF_NODES_TIMES_THREE] : direction <= ANTI_CLOCKWISE; default : direction <= ACROSS; end end end endmodule
arbiter.v
Code Verilog - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 // Credit: [url]https://github.com/thomasrussellmurphy/stx_cookbook/blob/master/arbitration/arbiter.v[/url] // Copyright 2007 Altera Corporation. All rights reserved. // Altera products are protected under numerous U.S. and foreign patents, // maskwork rights, copyrights and other intellectual property laws. // // This reference design file, and your use thereof, is subject to and governed // by the terms and conditions of the applicable Altera Reference Design // License Agreement (either as signed by you or found at [url]www.altera.com[/url]). By // using this reference design file, you indicate your acceptance of such terms // and conditions between you and Altera Corporation. In the event that you do // not agree with such terms and conditions, you may not use the reference // design file and please promptly destroy any copies you have made. // // This reference design file is being provided on an "as-is" basis and as an // accommodation and therefore all warranties, representations or guarantees of // any kind (whether express, implied or statutory) including, without // limitation, warranties of merchantability, non-infringement, or fitness for // a particular purpose, are specifically disclaimed. By making this reference // design file available, Altera expressly does not recommend, suggest or // require that this reference design file be used in combination with any // other product not provided by Altera. ///////////////////////////////////////////////////////////////////////////// // baeckler - 02-13-2007 // // 'base' is a one hot signal indicating the first request // that should be considered for a grant. Followed by higher // indexed requests, then wrapping around. // // [url]https://www.reddit.com/r/FPGA/comments/axutbt/understanding_a_simple_roundrobin_arbiter_verilog/[/url] module arbiter ( req, grant, base ); parameter WIDTH = 16; input [WIDTH-1:0] req; output [WIDTH-1:0] grant; input [WIDTH-1:0] base; wire [2*WIDTH-1:0] double_req = {req,req}; wire [2*WIDTH-1:0] double_grant = double_req & ~(double_req-base); assign grant = double_grant[WIDTH-1:0] | double_grant[2*WIDTH-1:WIDTH]; endmodule