diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eee4db0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.hex diff --git a/Allocators.bsv b/Allocators.bsv new file mode 100644 index 0000000..eb45e7e --- /dev/null +++ b/Allocators.bsv @@ -0,0 +1,396 @@ +/* ========================================================================= + * + * Filename: Allocators.bsv + * Date created: 05-20-2011 + * Last modified: 05-20-2011 + * Authors: Michael Papamichael + * + * Description: + * Implements allocators. + * + * ========================================================================= + */ + +`include "inc.v" +import Vector::*; +import Assert::*; +import NetworkTypes::*; +import Arbiters::*; +import ConfigReg::*; + +////////////////////////////////////////////////////////////////////////// +// Allocator Interface +// n is #requestors and m is #resources +interface Allocator#(type n, type m); + (* always_ready *) method ActionValue#( Vector#(n, Vector#(m, Bool)) ) allocate( Vector#(n, Vector#(m, Bool)) alloc_input); + //(* always_ready *) method Vector#(n, Vector#(m, Bool)) allocate( Vector#(n, Vector#(m, Bool)) alloc_input); + //(* always_ready *) method Action updatePipelinedAllocator( Vector#(n, Vector#(m, Bool)) alloc_input); + (* always_ready *) method Action next(); // used to advance allocator state for non-static allocators + //(* always_ready *) method Action updateAllocator( Vector#(n, Vector#(m, Bool)) alloc_input); +endinterface + +////////////////////////////////////////////////////////////////////////// +// Separable allocator - Input First +// Expects two vectors of external arbiters to reduce bluespec compilation times +module mkSepAllocIF#( Vector#(n, Arbiter#(m)) inputArbs, Vector#(m, Arbiter#(n)) outputArbs, Bool pipeline) + ( Allocator#(n, m) ); + String name = "mkSepAllocIF"; + + // Register used for pipelining option + Vector#(n, Vector#(m, Reg#(Bool))) inputArbGrants_reg; + for(Integer i=0; i6) use the allocator with External arbiters below +// This one becomes too slow to compile with Bluespec +module mkSepAllocIF_OldInternalArbiters( Allocator#(n, m) ); + String name = "mkSepAllocIF"; + + Vector#(n, Arbiter#(m)) inputArbs; + Vector#(m, Arbiter#(n)) outputArbs; + + //Instantiate Arbiters + for(Integer i=0; i + * + * Description: + * Testbench and synthesizable example for allocators. + * + * ========================================================================= + */ + +`include "inc.v" +import StmtFSM::*; // for testbench + +/////////////////////////////////////////////////// +// Testbench +typedef 5 NumRequestors; // n +typedef 5 NumResources; // m + +module mkSepAllocTest(Empty); + String name = "mkSepAllocIFTest"; + AllocatorSynth alloc <- mkSepAllocSynth(); + + Stmt test_seq = seq + action + Vector#(NumRequestors, Vector#(NumResources, Bool)) ai; + Vector#(NumRequestors, Vector#(NumResources, Bool)) ao; + //ai = unpack(2'b1_0); + //ai = unpack(4'b11_10); + //ai = unpack(12'b111_110_100_010); + //ai = unpack(12'b010_100_110_111); + ai = unpack(25'b01001_10001_11001_11101_11001); + alloc.next(); + ao = alloc.allocate(ai); + endaction + + action + Vector#(NumRequestors, Vector#(NumResources, Bool)) ai; + Vector#(NumRequestors, Vector#(NumResources, Bool)) ao; + //ai = unpack(2'b1_0); + //ai = unpack(4'b11_10); + //ai = unpack(12'b111_110_100_010); + //ai = unpack(12'b010_101_111_111); + ai = unpack(25'b01001_10001_11001_11101_11001); + ao = alloc.allocate(ai); + endaction + + //action Data_t test <- mf.deq(0); endaction + //mf.enq(1, 128'h11111111111111122222222222222222); + noAction; + noAction; + noAction; + noAction; + noAction; + noAction; + noAction; + noAction; + //while(True) noAction; + endseq; + + mkAutoFSM(test_seq); +endmodule + + +typedef Allocator#(NumRequestors, NumResources) AllocatorSynth; +typedef Arbiter#(NumResources) InputArb; +typedef Arbiter#(NumRequestors) OutputArb; + +typedef Vector#(NumRequestors, Arbiter#(NumResources)) InputArbs; +typedef Vector#(NumResources, Arbiter#(NumRequestors)) OutputArbs; + +interface InputArbiters; + interface Vector#(NumRequestors, Arbiter#(NumResources)) input_arbs; +endinterface + +interface OutputArbiters; + interface Vector#(NumResources, Arbiter#(NumRequestors)) output_arbs; +endinterface + +(* synthesize *) +//module mkInputArb#(Bit#(TLog#(NumResources)) startAt ) (InputArb); +module mkInputArb (InputArb); + InputArb ia <- mkRoundRobinArbiterStartAt(0); + //InputArb ia <- mkIterativeArbiter_fromEricStartAt(0); + return ia; +endmodule + +(* synthesize *) +//module mkOutputArb#(Bit#(TLog#(NumRequestors)) startAt) (OutputArb); +module mkOutputArb (OutputArb); + OutputArb oa <- mkRoundRobinArbiterStartAt(0); + //OutputArb oa <- mkIterativeArbiter_fromEricStartAt(0); + return oa; +endmodule + +(* synthesize *) +module mkInputArbiters(InputArbiters); + Vector#(NumRequestors, Arbiter#(NumResources)) ias; + for(Integer i=0; i + * + * Description: + * Implements static priority and round-robin arbiters. + * + * ========================================================================= + */ + +import Vector::*; +import Arbiter::*; + +///////////////////////////////////////////////////////////////////////// +// Encoder +function Maybe#(Bit#(m)) encoder( Vector#(n, Bool) vec ) + provisos(Log#(n, m)); + Maybe#(Bit#(m)) choice = Invalid; + //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority + for(Integer i=valueOf(n)-1; i >= 0; i=i-1) // I want the lowest to have highest priority + begin + if(vec[i]) begin + choice = Valid(fromInteger(i)); + end + end + return choice; +endfunction + + + +///////////////////////////////////////////////////////////////////////// +// Static Priority Arbiter +// Given a bitmask that has a some bits toggled, it produces a same size +// bitmask that only has the least-significant bit toggled. If no bits +// were originally toggled, then result is same as input. +function Maybe#(Vector#(n, Bool)) static_priority_arbiter_onehot_maybe( Vector#(n, Bool) vec ); + Vector#(n, Bool) selected = unpack(0); + Maybe#(Vector#(n, Bool)) result = Invalid; + //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority + for(Integer i=valueOf(n)-1; i >= 0; i=i-1) // I want the lowest to have highest priority + begin + if(vec[i]) begin + selected = unpack(0); + selected[i] = True; //Valid(fromInteger(i)); + result = tagged Valid selected; + end + end + return result; +endfunction + + +///////////////////////////////////////////////////////////////////////// +// Static Priority Arbiter +// Given a bitmask that has a few bits toggled, it produces a same size +// bitmask that only has the least-significant bit toggled. If no bits +// were originally toggled, then result is same as input. +function Vector#(n, Bool) static_priority_arbiter_onehot( Vector#(n, Bool) vec); + Vector#(n, Bool) selected = unpack(0); + //Maybe#(Bit#(m)) choice = Invalid; + //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority + for(Integer i=valueOf(n)-1; i >= 0; i=i-1) // I want the lowest to have highest priority + begin + if(vec[i]) begin + selected = unpack(0); + selected[i] = True; //Valid(fromInteger(i)); + end + end + return selected; +endfunction + + +///////////////////////////////////////////////////////////////////////// +// Static Priority Arbiter that starts at specific bit +// Given a bitmask that has a few bits toggled, it produces a same size +// bitmask that only has the least-significant bit toggled. If no bits +// were originally toggled, then result is same as input. +function Vector#(n, Bool) static_priority_arbiter_onehot_start_at( Vector#(n, Bool) vec, Integer startAt); + Vector#(n, Bool) selected = unpack(0); + //Maybe#(Bit#(m)) choice = Invalid; + //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority + Integer cur = startAt; + for(Integer i=valueOf(n)-1; i >= 0; i=i-1) // I want the lowest to have highest priority + begin + if(vec[cur%valueOf(n)]) begin + selected = unpack(0); + selected[cur%valueOf(n)] = True; //Valid(fromInteger(i)); + end + cur = cur+1; + end + return selected; +endfunction + + +//--------------------------------------------------------------------- +// Parameterizable n-way priority encoder. +// +// If the "en" signal de-asserted, the output will be 0. +// The input is a vector of booleans, with each Bool representing +// a requestor. The output is a vector of booleans of the same +// length. Up to only 1 bit can be asserted (or all bits are 0) +// at the output. The integer input "highest priority" indicates +// which requestor (corresponding to the input vector) gets the +// highest priority. +// Note: from Eric +//--------------------------------------------------------------------- + +function Vector#(n, Bool) priority_encoder_onehot( Integer highest_priority, Bool en, Vector#(n, Bool) vec ); + + Bool selected = False; + Vector#(n, Bool) choice = unpack(0); + + for(Integer i=highest_priority; i < valueOf(n); i=i+1) begin + if(vec[i] && !selected) begin + selected = True; + choice[i] = True; + end + end + + // wrap around + + for(Integer i=0; i < highest_priority; i=i+1) begin + if(vec[i] && !selected) begin + selected = True; + choice[i] = True; + end + end + + if(!en) choice = unpack(0); + return choice; +endfunction + + + +interface Arbiter#(type n); + (* always_ready *) method Vector#(n, Bool) select( Vector#(n, Bool) requests ); + (* always_ready *) method Action next(); +endinterface + +module mkStaticPriorityArbiter(Arbiter#(n)); + method Vector#(n, Bool) select( Vector#(n, Bool) requests ); + return static_priority_arbiter_onehot(requests); + endmethod + + method Action next(); + action noAction; endaction + endmethod + +endmodule + +module mkStaticPriorityArbiterStartAt#(Integer startAt) (Arbiter#(n)); + method Vector#(n, Bool) select( Vector#(n, Bool) requests ); + return static_priority_arbiter_onehot_start_at(requests, startAt); + endmethod + + method Action next(); + action noAction; endaction + endmethod +endmodule + + + + +//module mkRoundRobinArbiter(Arbiter#(n)); +// method ActionValue#(Vector#(n, Bool)) select( Vector#(n, Bool) requests ); +// return priority_arbiter_onehot(requests); +// endmethod +//endmodule + +// From Bill Dally, page 354 in Dally's book +(* noinline *) +function Tuple2#(Bool,Bool) gen_grant_carry(Bool c, Bool r, Bool p); + return tuple2(r && (c || p), !r && (c || p)); // grant and carry signals +endfunction + +////////////////////////////////////////////////////// +// Round-robin arbiter from Dally's book. Page 354 +module mkRoundRobinArbiter( Arbiter#(n) ); + + Reg#(Vector#(n, Bool)) token <- mkReg(unpack(1)); + + + + method Vector#(n, Bool) select( Vector#(n, Bool) requests ); + Vector#(n, Bool) granted_A = unpack(0); + Vector#(n, Bool) granted_B = unpack(0); + + ///////////////////////////////////////////////////////////////////// + // Replicated arbiters are used to avoid cyclical carry chain + // (see page 354, footnote 2 in Dally's book) + ///////////////////////////////////////////////////////////////////// + + // Arbiter 1 + Bool carry = False; + for(Integer i=0; i < valueOf(n); i=i+1) begin + let gc = gen_grant_carry(carry, requests[i], token[i]); + granted_A[i] = tpl_1(gc); + carry = tpl_2(gc); + end + + // Arbiter 2 (uses the carry from Arbiter 1) + for(Integer i=0; i < valueOf(n); i=i+1) begin + let gc = gen_grant_carry(carry, requests[i], token[i]); + granted_B[i] = tpl_1(gc); + carry = tpl_2(gc); + end + + Vector#(n, Bool) winner = unpack(0); + //Maybe#(Bit#(m)) winner = Invalid; + + for(Integer k=0; k < valueOf(n); k=k+1) begin + if(granted_A[k] || granted_B[k]) begin + winner = unpack(0); + winner[k] = True; + end + end + return winner; + endmethod + + method Action next(); + action + token <= rotate( token ); // WRONG -> this should get + endaction + endmethod + +endmodule + + +////////////////////////////////////////////////////// +// Round-robin arbiter from Dally's book. Page 354 +// Modified version to initialize with custom starting priority +module mkRoundRobinArbiterStartAt#(Integer startAt)( Arbiter#(n) ); + + Vector#(n, Bool) init_token = unpack(0); + init_token[startAt] = True; + Reg#(Vector#(n, Bool)) token <- mkReg(init_token); + + method Vector#(n, Bool) select( Vector#(n, Bool) requests ); + Vector#(n, Bool) granted_A = unpack(0); + Vector#(n, Bool) granted_B = unpack(0); + + ///////////////////////////////////////////////////////////////////// + // Replicated arbiters are used to avoid cyclical carry chain + // (see page 354, footnote 2 in Dally's book) + ///////////////////////////////////////////////////////////////////// + + // Arbiter 1 + Bool carry = False; + for(Integer i=0; i < valueOf(n); i=i+1) begin + let gc = gen_grant_carry(carry, requests[i], token[i]); + granted_A[i] = tpl_1(gc); + carry = tpl_2(gc); + end + + // Arbiter 2 (uses the carry from Arbiter 1) + for(Integer i=0; i < valueOf(n); i=i+1) begin + let gc = gen_grant_carry(carry, requests[i], token[i]); + granted_B[i] = tpl_1(gc); + carry = tpl_2(gc); + end + + Vector#(n, Bool) winner = unpack(0); + //Maybe#(Bit#(m)) winner = Invalid; + + for(Integer k=0; k < valueOf(n); k=k+1) begin + if(granted_A[k] || granted_B[k]) begin + winner = unpack(0); + winner[k] = True; + end + end + return winner; + endmethod + + method Action next(); + action + token <= rotate( token ); // WRONG -> this should get + endaction + endmethod + +endmodule + + + + +module mkIterativeArbiter_fromEric( Arbiter#(n) ); + + Reg#(Vector#(n, Bool)) token <- mkReg(unpack(1)); + + method Vector#(n, Bool) select( Vector#(n, Bool) requests ); + Vector#(n, Bool) granted = unpack(0); + + for(Integer i=0; i < valueOf(n); i=i+1) begin + let outcome = priority_encoder_onehot( i, token[i], requests ); + + for(Integer j=0; j < valueOf(n); j=j+1) begin + granted[j] = granted[j] || outcome[j]; + end + end + + Vector#(n, Bool) winner = unpack(0); + //Maybe#(Bit#(m)) winner = Invalid; + + for(Integer k=0; k < valueOf(n); k=k+1) begin + if(granted[k]) begin + winner = unpack(0); + winner[k] = True; + end + end + return winner; + endmethod + + method Action next(); + action + token <= rotate( token ); + endaction + endmethod + +endmodule + +module mkIterativeArbiter_fromEricStartAt#(Integer startAt) ( Arbiter#(n) ); + + //Reg#(Vector#(n, Bool)) token <- mkReg(unpack(1)); + Vector#(n, Bool) init_token = unpack(0); + init_token[startAt] = True; + Reg#(Vector#(n, Bool)) token <- mkReg(init_token); + + method Vector#(n, Bool) select( Vector#(n, Bool) requests ); + Vector#(n, Bool) granted = unpack(0); + + for(Integer i=0; i < valueOf(n); i=i+1) begin + let outcome = priority_encoder_onehot( i, token[i], requests ); + + for(Integer j=0; j < valueOf(n); j=j+1) begin + granted[j] = granted[j] || outcome[j]; + end + end + + Vector#(n, Bool) winner = unpack(0); + //Maybe#(Bit#(m)) winner = Invalid; + + for(Integer k=0; k < valueOf(n); k=k+1) begin + if(granted[k]) begin + winner = unpack(0); + winner[k] = True; + end + end + return winner; + endmethod + + method Action next(); + action + token <= rotate( token ); + endaction + endmethod + +endmodule + + + +//------ Testing ---------- + +(* synthesize *) +module mkTestArbiter8(Arbiter#(8)); + //Arbiter#(8) arb <- mkStaticPriorityArbiter(); + Arbiter#(8) arb <- mkStaticPriorityArbiterStartAt(2); + //Arbiter#(8) arb <- mkRoundRobinArbiter(); + //Arbiter#(8) arb <- mkRoundRobinArbiterStartAt(2); + //Arbiter#(8) arb <- mkIterativeArbiter_fromEric(); + return arb; + //method select = arb.select; + //method next = arb.next; +endmodule diff --git a/Aux.bsv b/Aux.bsv new file mode 100644 index 0000000..ffae9e1 --- /dev/null +++ b/Aux.bsv @@ -0,0 +1,119 @@ +/* ========================================================================= + * + * Filename: Router.bsv + * Date created: 06-19-2011 + * Last modified: 06-19-2011 + * Authors: Michael Papamichael + * + * Description: + * Collection of auxiliary functions and modules. + * + * ========================================================================= + */ + +`include "inc.v" +import Vector::*; +import NetworkTypes::*; + +/////////////////////////////////////////////////////////////////////////////////////////////// +// Auxiliary Functions: +// Most are compiled into separate modules (noinline) to reduce Bluespec compilation times. +/////////////////////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////// +// Priority Encoder +function Maybe#(Bit#(m)) priority_encoder( Vector#(n, Bool) vec ) + provisos(Log#(n, m)); + Maybe#(Bit#(m)) choice = Invalid; + //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority + for(Integer i=valueOf(n)-1; i >= 0; i=i-1) // I want the lowest to have highest priority + begin + if(vec[i]) begin + choice = Valid(fromInteger(i)); + end + end + return choice; +endfunction + +///////////////////////////////////////////////////////////////////////// +// Encoder +function Maybe#(Bit#(m)) encoder( Vector#(n, Bool) vec ) + provisos(Log#(n, m)); + Maybe#(Bit#(m)) choice = Invalid; + //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority + for(Integer i=valueOf(n)-1; i >= 0; i=i-1) // I want the lowest to have highest priority + begin + if(vec[i]) begin + choice = Valid(fromInteger(i)); + end + end + return choice; +endfunction + +// noninline version for OutPort +(* noinline *) +function Maybe#(OutPort_t) outport_encoder( Vector#(NumOutPorts, Bool) vec ); + return encoder(vec); + + //Maybe#(OutPort_t) choice = Invalid; + ////for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority + //for(Integer i=valueOf(NumOutPorts)-1; i >= 0; i=i-1) // I want the lowest to have highest priority + //begin + // if(vec[i]) begin + // choice = Valid(fromInteger(i)); + // end + //end + //return choice; +endfunction + +///////////////////////////////////////////////////////////////////////// +// Priority Selector +// Given a bitmask that has a few bits toggled, it produces a same size +// bitmask that only has the least-significant bit toggled. If not bit +// was originally toggled, then result is same as input. +function Vector#(n, Bool) priority_selector( Vector#(n, Bool) vec ); + Vector#(n, Bool) selected = unpack(0); + //Maybe#(Bit#(m)) choice = Invalid; + //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority + for(Integer i=valueOf(n)-1; i >= 0; i=i-1) // I want the lowest to have highest priority + begin + if(vec[i]) begin + selected = unpack(0); + selected[i] = True; //Valid(fromInteger(i)); + end + end + return selected; +endfunction + +////////////////////////////////////////////////////////////////////////////////////////////// +// Functions to prune and expand vectors by removing/adding an element at a specific index +function Vector#(m, element_type) pruneVector(Vector#(n, element_type) expanded_vec, Integer pruneIndex) + provisos (Add#(m,1,n)); + //Vector#(TSub#(NumOutPorts, 1), Bool) pruned_outs = unpack(0); + Vector#(m, element_type ) pruned_vec; + Integer p = 0; + for(Integer e=0; e + * + * Description: + * Dual-port memory that efficiently maps to BRAMs. (will infer RAMB18E/RAMB36E primitives) + * Bluespec BRAMCore package only infers RAMB36E primitives) + * Requires DPSRAM.v file. (see bottom) + * + */ + +// Sample instntiation +//interface BRAMTest4; +// interface DPSRAM#(Bit#(8), Bit#(4096)) bram_ifc; +//endinterface + +//(* synthesize *) +//module mkBRAMTest4( BRAMTest4 ); +// +// DPSRAM#(Bit#(8), Bit#(4096)) bram <- mkDPSRAM(); +// interface bram_ifc = bram; +// +//endmodule + +interface DPSRAM#(type index_t, type data_t); + method Action read(index_t idx_r); + method data_t value(); + method Action write(index_t idx_w, data_t din_w); + //method Action write( ) +endinterface + +import "BVI" DPSRAM = +module mkDPSRAM (DPSRAM#(index_t, data_t)) + provisos(Bits#(data_t, data_width_t), + Bits#(index_t, index_width_t), + Arith#(index_t), + Bounded#(index_t), + Literal#(index_t), + Eq#(index_t)); + + parameter WIDTH = valueof(data_width_t); + parameter ADDR_BITS = valueof(index_width_t); + + default_clock( clk ); + default_reset( rst_n ); + + schedule (read, value, write) CF (read, value, write); + /*schedule write CF read; + schedule write CF write; + schedule read CF read;*/ + + method read(IdxR) enable(Rd); + method DoutR value; + method write(IdxW, DinW) enable(We); +endmodule + + +/////////////////////////////////// +// DPSRAM Verilog module +/////////////////////////////////// + +//module DPSRAM ( +// Rd, +// IdxR, +// DoutR, +// +// We, +// IdxW, +// DinW, +// clk, +// rst_n +// ); +// +// // synthesis attribute BRAM_MAP of DPSRAM is "yes"; +// +// parameter WIDTH = 1; +// parameter ADDR_BITS = 9; +// parameter DEPTH = 1< + * + * Description: + * Dual-port memory with forwarding that efficiently maps to BRAMs. (will infer RAMB18E/RAMB36E primitives) + * Bluespec BRAMCore package only infers RAMB36E primitives) + * Requires DPSRAM_w_forwarding.v file. (see bottom) + * + */ + +// Sample instntiation +//(* synthesize *) +//module mkBRAMTest3( BRAMTest3 ); +// +// DPSRAM_w_forward#(Bit#(8), Bit#(4096)) bram <- mkDPSRAM_w_forward(); +// interface bram_ifc = bram; +// +//endmodule + +interface DPSRAM_w_forward#(type index_t, type data_t); + method Action read(index_t idx_r); + method data_t value(); + method Action write(index_t idx_w, data_t din_w); + //method Action write( ) +endinterface + + +import "BVI" DPSRAM_w_forward = +module mkDPSRAM_w_forward (DPSRAM_w_forward#(index_t, data_t)) + provisos(Bits#(data_t, data_width_t), + Bits#(index_t, index_width_t), + Arith#(index_t), + Bounded#(index_t), + Literal#(index_t), + Eq#(index_t)); + + parameter WIDTH = valueof(data_width_t); + parameter ADDR_BITS = valueof(index_width_t); + + default_clock( clk ); + default_reset( rst_n ); + + schedule (read, value, write) CF (read, value, write); + /*schedule write CF read; + schedule write CF write; + schedule read CF read;*/ + + method read(IdxR) enable(Rd); + method DoutR value; + method write(IdxW, DinW) enable(We); +endmodule + + +/////////////////////////////////////// +// DPSRAM_w_forwarding Verilog module +/////////////////////////////////////// + +//module DPSRAM_w_forward ( +// Rd, +// IdxR, +// DoutR, +// +// We, +// IdxW, +// DinW, +// clk, +// rst_n +// ); +// +// // synthesis attribute BRAM_MAP of dpsram_withforward is "yes"; +// +// parameter WIDTH = 1; +// parameter ADDR_BITS = 9; +// parameter DEPTH = 1< + * + * Description: + * Parameterized Input-Queued Router module. Used as building block for + * building larger networks. + * + * ========================================================================= + */ + +`include "inc.v" + +import FIFO::*; +//import FIFOF::*; +import Vector::*; +import RegFile::*; +import ConfigReg::*; +import Assert::*; + +import NetworkTypes::*; +import Aux::*; +import RF_16ports::*; +import RF_16portsLoad::*; +import RegFileMultiport::*; + +import FIFOLevel::*; +import MultiFIFOMem::*; +import RegFIFO::*; + +// Arbiters and Allocators used for scheduling +import Arbiters::*; +import Allocators::*; + +// Eventually maybe replace this with more efficient/alternative single queue implementation +typedef MultiFIFOMem#(Flit_t, 1, FlitBufferDepth) InputQueue; +(* synthesize *) +module mkInputQueue(InputQueue); + InputQueue inputQueue_ifc; + if ( `PIPELINE_LINKS ) begin // Add 1 cycle margin to FIFOs for credit that might be in transit + inputQueue_ifc <- mkMultiFIFOMem(False /*storeHeadsTailsInLUTRAM*/, 1 /* full_margin */ ); + end else begin + inputQueue_ifc <- mkMultiFIFOMem(False /*storeHeadsTailsInLUTRAM*/, 0 /* full_margin */ ); + end + return inputQueue_ifc; +endmodule + +typedef FIFOCountIfc#(OutPort_t, FlitBufferDepth) OutPortFIFO; +(* synthesize *) +module mkOutPortFIFO(OutPortFIFO); + //String fifo_name = strConcat( strConcat(integerToString(id1), " - "), integerToString(id2)); + //OutPortFIFO outPortFIFO_ifc <- mkRegFIFO_named(fifo_name, False); + OutPortFIFO outPortFIFO_ifc <- mkRegFIFO(False); + return outPortFIFO_ifc; +endmodule + +//typedef RF_16portsLoad#(RouterID_t, OutPort_t) RouteTableOld; +//typedef RegFileMultiport#(NumInPorts/*nr*/, 1/*nw*/, RouterID_t, OutPort_t) RouteTable; +//typedef RegFileMultiport#(NumInPorts/*nr*/, 1/*nw*/, UserPortID_t, OutPort_t) RouteTable; +typedef RegFileMultiport#(NumInPorts/*nr*/, 1/*nw*/, UserRecvPortID_t, OutPort_t) RouteTable; +module mkRouteTable#(String route_table_file) (RouteTable); + //RouteTable rt_ifc <- mkRF_16portsLoad(route_table_file); + RouteTable rt_ifc <- mkRegFileMultiportLoad(route_table_file); + return rt_ifc; +endmodule + +(* synthesize *) +module mkRouteTableSynth(RouteTable); + String route_table_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(4)), ".hex"); + //RouteTableOld rt_ifc <- mkRF_16portsLoad(route_table_file, False); + RouteTable rt_ifc <- mkRegFileMultiportLoad(route_table_file); + return rt_ifc; +endmodule + +//////////////////////////////////////////////// +// Router Module implementation +//////////////////////////////////////////////// +module mkIQRouter#(Integer id)(Router); + String name = "IQRouter"; + Bit#(8) errorCode = 0; + + Vector#(NumInPorts, InPort) inPort_ifaces; // in port interfaces +`ifdef EN_DBG + RouterCore router_core <- mkIQRouterCore(id); +`else + RouterCore router_core <- mkIQRouterCore(); +`endif + // Route Table + String route_table_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(id)), ".hex"); + //RF_16portsLoad#(RouterID_t, OutPort_t) routeTable <- mkRF_16portsLoad(route_table_file, /*binary*/False); + //RouteTable routeTable <- mkRouteTable(route_table_file, /*binary*/False); + RouteTable routeTable <- mkRouteTable(route_table_file); + + // for debugging + `ifdef EN_DBG + Reg#(Cycle_t) cycles <- mkConfigReg(0); + rule update_cycles(True); + cycles <= cycles + 1; + endrule + `endif + + // Define input interfaces + for(Integer i=0; i < valueOf(NumInPorts); i=i+1) begin + let ifc = + interface InPort + method Action putFlit(Maybe#(Flit_t) flit_in); + Maybe#(RoutedFlit_t) rt_flit = Invalid; + //`DBG_ID(("Receiving Flit on in_port %0d", i)); + if(isValid(flit_in)) begin + let fl_in = flit_in.Valid; + let out_p = routeTable.r[i].sub(fl_in.dst); + //let fl_in = tagged Valid Flit_t{is_tail:flit_in.Valid.is_tail, dst:flit_in.Valid.dst, out_p:out_p, vc:flit_in.Valid.vc, data:flit_in.Valid.data}; + rt_flit = tagged Valid RoutedFlit_t{flit:fl_in, out_port:out_p}; + `DBG_ID_CYCLES(("Incoming flit on port %0d - dest:%0d, vc:%0d, data:%x", i, fl_in.dst, fl_in.vc, fl_in.data )); + //rt_flit = tagged Valid RoutedFlit_t{ flit:Flit_t{is_tail:fl_in.is_tail, dst:fl_in.dst, out_p:out_p, vc:fl_in.vc, data:fl_in.data}, out_port:out_p}; + //if(i==0) begin + // //`DBG(("Cycle:%0d - Injected flit into router %0d - dest:%0d, tail:%0d, vc:%0d, data:%x", cycles, id, fl_in.dst, fl_in.is_tail, fl_in.vc, fl_in.data )); + // `DBG_ID_CYCLES(("Cycle:%0d - Injected flit - dest:%0d, data:%x", cycles, fl_in.dst, fl_in.data )); + //end else begin + // //`DBG(("Cycle:%0d - Router %0d received flit through in_port %0d - dest:%0d, tail:%0d, vc:%0d, data:%x", cycles, id, i, fl_in.dst, fl_in.is_tail, fl_in.vc, fl_in.data )); + // `DBG_ID(("Cycle:%0d - Received flit through in_port %0d - dest:%0d, data:%x", cycles, i, fl_in.dst, fl_in.data )); + //end + end + router_core.in_ports[i].putRoutedFlit(rt_flit); + endmethod + + // send credits upstream + method ActionValue#(Credit_t) getCredits; + let cr_out <- router_core.in_ports[i].getCredits(); + return cr_out; + endmethod + endinterface; + + inPort_ifaces[i] = ifc; + end + + interface in_ports = inPort_ifaces; + interface out_ports = router_core.out_ports; + //interface rt_info = rt_info_ifc; + +endmodule + + +module mkIQRouterSynth(Router); + let rt_synth <- mkIQRouter(4); + return rt_synth; +endmodule + + +//////////////////////////////////////////////// +// Router Module implementation +//////////////////////////////////////////////// +//module mkRouter#(RouterID_t id) (Router); +`ifdef EN_DBG +module mkIQRouterCore#(Integer id)(RouterCore); +`else +(* synthesize *) +module mkIQRouterCore(RouterCore); +`endif + + String name = "IQRouterCore"; + Bit#(8) errorCode = 0; + + // Vector of input and output port interfaces + Vector#(NumInPorts, RouterCoreInPort) inPort_ifaces; // in port interfaces + Vector#(NumOutPorts, OutPort) outPort_ifaces; // out port interfaces + + // Router Allocator + RouterAllocator routerAlloc <- mkSepRouterAllocator(`PIPELINE_ALLOCATOR /*pipeline*/); + + // Router State + Vector#(NumInPorts, InputQueue) flitBuffers <- replicateM(mkInputQueue()); + //Vector#(NumInPorts, RF_16ports#(VC_t, FlitBuffer_t) ) flitBuffers <- replicateM(mkRF_16ports()); + Vector#(NumInPorts, OutPortFIFO) outPortFIFOs; + Vector#(NumOutPorts, Reg#(Bit#(TLog#(TAdd#(FlitBufferDepth,1))))) credits; + //Vector#(NumOutPorts, Vector#(NumVCs, Reg#(Bool) )) credits; + + Vector#(NumInPorts, Wire#(Maybe#(Flit_t))) hasFlitsToSend_perIn <- replicateM(mkDWire(Invalid)); + Vector#(NumInPorts, Wire#(Maybe#(Flit_t))) flitsToSend_perIn <- replicateM(mkDWire(Invalid)); + // Used for multi-flit packets that use virtual links + //if(`USE_VIRTUAL_LINKS) begin + Vector#(NumOutPorts, Reg#(Bool) ) lockedVL; // locked virtual link + Vector#(NumOutPorts, Reg#(InPort_t) ) inPortVL; // holds current input for locked virtual channels + //end + + // Update wires + Vector#(NumOutPorts, Wire#(Bool) ) credits_set; // to handle incoming credits + Vector#(NumOutPorts, Wire#(Bool) ) credits_clear; // to clear credits due to outgoing flits + + // for debugging + `ifdef EN_DBG + Reg#(Cycle_t) cycles <- mkConfigReg(0); + rule update_cycles(True); cycles <= cycles + 1; endrule + `endif + + credits_set <- replicateM(mkDWire(False)); + credits_clear <- replicateM(mkDWire(False)); + credits <- replicateM(mkConfigReg(fromInteger(valueOf(FlitBufferDepth)))); // start with credits for all ouputs/VCs + outPortFIFOs <- replicateM(mkOutPortFIFO()); + // -- Initialization -- + /*for(Integer o=0; o 0) begin + + if(`USE_VIRTUAL_LINKS) begin + let is_locked = lockedVL[out_port]; + if( !is_locked || (is_locked && inPortVL[out_port] == fromInteger(i) ) ) begin + eligIO[i] = replicate(False); + eligIO[i][out_port] = True; + end + end else begin + eligIO[i][out_port] = True; + end + + end + end + // -- End Option 1 -- + + // -- Option 2: more scalable, but harder to read -- +// let build_eligIO_result = build_eligIO_and_other_alloc_structs(flitBuffers_notEmpty, outPortFIFOs_first, credit_values, lockedVL_values, inPortVL_values); +// eligIO = tpl_1(build_eligIO_result); +// activeVC_perIn = tpl_2(build_eligIO_result); +// activeVC_perOut = tpl_3(build_eligIO_result); + // -- End Option 2 -- + + // Perform allocation + Vector#(NumInPorts, Bool) activeInPorts = unpack(0); + //Vector#(NumInPorts, Vector#(NumOutPorts, Bool ) ) selectedIO = routerAlloc.allocate(eligIO); + Vector#(NumInPorts, Vector#(NumOutPorts, Wire#(Bool) ) ) selectedIO_s0; //= routerAlloc.allocate(eligIO); + Vector#(NumInPorts, Vector#(NumOutPorts, Reg#(Bool) ) ) selectedIO_reg; + Vector#(NumInPorts, Vector#(NumOutPorts, Bool ) ) selectedIO; // this is popuated depending on allocator pipeline options + + for(Integer i=0; i 0; // double check that credits still exist. Alternatively change margin in mkMultiFIFOMem + if (has_flits && has_credits) begin + activeInPorts[i] = True; + //InPort_t inp = fromInteger(i); + //activeIn_perOut[selectedOut.Valid] = tagged Valid inp; + activeIn_perOut[selectedOut.Valid] = tagged Valid fromInteger(i); + end + end + + end + end + + rule performAllocation(True); + let alloc_result <- routerAlloc.allocate(eligIO); + for(Integer i=0; i Router: %0d - dequeing from outPortFIFOs[%0d][%0d]", id, i, activeVC_perIn[i].Valid); + + //if(fl.out_p != out_port) begin + // `DBG_ID(("Outport mismatch! fl.out_p: %d does not match out_port %d", fl.out_p, out_port)); + //end + //activeVC_perOut[out_port] <= tagged Valid activeVC_perIn[i].Valid; + end + end + endrule + + +// ////////////////////////////////////////////////////////////////////////////////////////////// +// // Old MEMOCODE arbiter - performs static priority maximal matching +// // First mask out entries that don't have credits or are ineligible to be picked - Convert to function +// Vector#(NumVCs, Vector#(NumInPorts, Vector#(NumOutPorts, Bool ) ) ) eligVIO = unpack(0); //perOut_perVC_perIn; +// for(Integer i=0; i0) begin +// eligVIO[v][i][out_port] = True; +// end +// end +// end +// end +// +// +// +// // Arbitration - packaged main arbitration logic for each output in "noinline" function --> this reduces compilation times by 2 ORDERS OF MAGNITUDE! +// Tuple3#( Vector#(NumInPorts, Maybe#(VC_t)), /* activeVC_perIn */ +// Vector#(NumOutPorts, Maybe#(InPort_t)), /* activeIn_perOut */ +// Vector#(NumOutPorts, VC_t) /* activeVC_perOut */ +// ) arb_result; +// +// arb_result = arbitrateAll(eligVIO); +// activeVC_perIn = tpl_1(arb_result); +// activeIn_perOut = tpl_2(arb_result); +// activeVC_perOut = tpl_3(arb_result); +// +// Vector#(NumInPorts, Bool) activeInPorts = unpack(0); +// for(Integer i=0; i set +// if ( hasFlitsVIO_set[v][i][o] ) begin // something came in on an in_port --> set +// hasFlitsVIO[v][i][o] <= True; +// `DBG(("Marking incoming flit for out:%0d VC:%0d from in:%0d", o, v, i)); +// //end else if ( hasFlitsVIO_clear[v][i][o] && !hasFlitsVIO_set[v][i][o]) begin // something departed --> clear +// end else if ( hasFlitsVIO_clear[v][i][o] ) begin // something departed --> clear +// `DBG(("Clearing flit for out:%0d VC:%0d from in:%0d", o, v, i)); +// hasFlitsVIO[v][i][o] <= False; +// end +// end +// end +// end +// endrule + + // Rule to update credits. Credits get replenished from out_ports and are spent when sending flits. + (* fire_when_enabled *) + rule update_credits (True); // turn off credits for debugging + for(Integer o=0; o fromInteger(valueof(FlitBufferDepth))) begin + `DBG_ID_CYCLES(("Credit overflow at out_port %0d", o)); + end + end else if (!credits_set[o] && credits_clear[o]) begin // I only spent a credit + //credits[o][v] <= False; + credits[o] <= credits[o] - 1; + if(credits[o] == 0) begin + `DBG_ID_CYCLES(("Credit underflow at out_port %0d", o)); + end + end + end + //`DBG_DETAIL_ID(("credits:%b", readVReg(concat(credits)) )); // flatten the array to print + endrule + + + function Action printAllocMatrix(Vector#(n, Vector#(m, Bool)) am); + action + for(Integer i=0; i Router: %0d - enqueing to outPortFIFOs[%0d][%0d]", id, i, fl_in.vc); + if(i==0) begin + //`DBG(("Cycle:%0d - Injected flit into router %0d - dest:%0d, tail:%0d, vc:%0d, data:%x", cycles, id, fl_in.dst, fl_in.is_tail, fl_in.vc, fl_in.data )); + //`DBG(("Cycle:%0d - Injected flit - dest:%0d, vc:%0d, data:%x", cycles, fl_in.dst, fl_in.vc, fl_in.data )); + end else begin + //`DBG(("Cycle:%0d - Router %0d received flit through in_port %0d - dest:%0d, tail:%0d, vc:%0d, data:%x", cycles, id, i, fl_in.dst, fl_in.is_tail, fl_in.vc, fl_in.data )); + //`DBG(("Cycle:%0d - Received flit through in_port %0d - dest:%0d, vc:%0d, data:%x", cycles, i, fl_in.dst, fl_in.vc, fl_in.data )); + end + //`DBG(("Marking incoming flit for dst:%0d VC:%0d from in:%0d (isT:%0d)", fl_in.dst, fl_in.vc, i, /*fl_in.is_head,*/ fl_in.is_tail)); + //hasFlitsVIO_set[fl_in.vc][i][out_port] <= True; + end + endmethod + + // send credits upstream + method ActionValue#(Credit_t) getCredits; + Credit_t cr_out = Invalid; + if (activeInPorts[i]) begin + cr_out = tagged Valid 0; // VC is always 0 for input-queued router + end + return cr_out; + endmethod + endinterface; + + inPort_ifaces[i] = ifc; + end + + // Implement output interfaces + for(Integer o=0; o < valueOf(NumOutPorts); o=o+1) begin + let ifc = + interface OutPort + method ActionValue#(Maybe#(Flit_t)) getFlit(); + Maybe#(Flit_t) flitOut = Invalid; + if( isValid(activeIn_perOut[o]) ) begin // I have a flit to send + let active_in = activeIn_perOut[o].Valid; + //let active_vc = activeVC_perOut[o].Valid; + //if(!isValid(activeVC_perOut[o])) begin + // `DBG_ID(("active_vc is invalid!")); + //end + //let fb = flitBuffers[ active_in ].read_ports[o].read(active_vc); + //let fb <- flitBuffers[active_in].deq(active_vc); + //let fb <- flitsToSend_perIn[active_in]; + //outPortFIFOs[active_in][active_vc].deq(); + + //hasFlitsVIO_clear[active_vc][active_in][o] <= True; + //if(fb.is_tail) begin // If you see a tail unlock VL (also covers head/tail case) + // lockedVL[o][active_vc] <= False; + // //`DBG_DETAIL_ID(("UNLOCKED output %0d (was locked to in:%0d)", o, inPortVL[o][active_vc] )); + //end else begin // it's not a tail (i.e. head or in the middle of a packet), so lock the VL. + // lockedVL[o][active_vc] <= True; + // //`DBG_DETAIL_ID(("LOCKED output %0d locked to in:%0d, VC:%0d (flit %0d)", o, active_in, active_vc, fb.id )); + // inPortVL[o][active_vc] <= active_in; + //end + //flitOut = tagged Valid Flit_t{is_tail:fb.is_tail, dst:fb.dst, vc:active_vc, data:fb.data }; + //flitOut = flitsToSend_perIn[active_in]; + + `ifdef RESTRICT_UTURNS + // pruned version + // Generate pruned activeIn + dynamicAssert(active_in != fromInteger(o), "No U-turns allowed!"); + Vector#(NumInPorts, Bool) selectedInput = unpack(0); + selectedInput[active_in] = True; + let selectedInput_pruned = pruneVector(selectedInput, o); + let active_in_pruned = encoder(selectedInput_pruned); + let hasFlitsToSend_perIn_pruned = pruneVector(hasFlitsToSend_perIn, o); + flitOut = hasFlitsToSend_perIn_pruned[active_in_pruned.Valid]; + `else + //end else begin + // no pruning + flitOut = hasFlitsToSend_perIn[active_in]; + `endif + //end + + dynamicAssert(isValid(flitOut), "Output selected invalid flit!"); + //dynamicAssert(flitOut.Valid.vc == active_vc, "Flit VC and active VC do not match!"); + //if(flitOut.Valid.out_p != fromInteger(o)) begin + // `DBG_ID(("Flit out_port %d does not match actual out_port %d", flitOut.Valid.out_p, o)); + //end + + // clear credits + credits_clear[o] <= True; // VC is always 0 for input-queued router + + end + + return flitOut; + endmethod + + // receive credits from downstream routers + method Action putCredits(Credit_t cr_in); + `DBG_DETAIL_ID(("Receiving Credit on out_port %0d", o)); + // only mark here - perform update in rule + if(isValid(cr_in)) begin + //`DBG_DETAIL_ID(("Cycle: %0d: Received credit on out_port %0d for vc %0d", cycles, o, cr_in.Valid)); + `DBG_DETAIL(("Cycle: %0d: Received credit on out_port %0d for vc %0d", cycles, o, cr_in.Valid)); + credits_set[o] <= True; // VC is always 0 for input-queued router + end + endmethod + endinterface; + outPort_ifaces[o] = ifc; + end + + interface in_ports = inPort_ifaces; + interface out_ports = outPort_ifaces; + +endmodule + + + +/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// + + + +////////////////////////////////////////////////////////////// +// Old Arbitration Functions +////////////////////////////////////////////////////////////// + +//(* noinline *) +//function Maybe#(VC_t) pickVC( Vector#(NumVCs, Bool) eligVCs ); +// Maybe#(VC_t) sel_VC = Invalid; +// //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority +// for(Integer v=valueOf(NumVCs)-1; v >= 0; v=v-1) // I want the lowest to have highest priority +// begin +// if(eligVCs[v]) begin +// sel_VC = Valid(fromInteger(v)); +// end +// end +// return sel_VC; +//endfunction + +//(* noinline *) +//function Maybe#(InPort_t) pickIn( Vector#(NumInPorts, Bool) eligIns ); +// Maybe#(InPort_t) sel_In = Invalid; +// //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority +// for(Integer i=valueOf(NumInPorts)-1; i >= 0; i=i-1) // I want the lowest to have highest priority +// begin +// if(eligIns[i]) begin +// sel_In = Valid(fromInteger(i)); +// end +// end +// return sel_In; +//endfunction + +//(* noinline *) +//function Vector#(NumVCs, Vector#(NumInPorts, Bool )) maskOccupiedInputs(Vector#(NumVCs, Vector#(NumInPorts, Bool )) eligVI, Vector#(NumInPorts, Bool) freeInputs); +// for(Integer v=0; v + * + * Description: + * Parameterized Input-Queued Router module. Used as building block for + * building larger networks. Implements RouterSimple interface. + * + * ========================================================================= + */ + +`include "inc.v" + +import FIFO::*; +//import FIFOF::*; +import Vector::*; +import RegFile::*; +import ConfigReg::*; +import Assert::*; + +import NetworkTypes::*; +import Aux::*; +import RF_16ports::*; +import RF_16portsLoad::*; +import RegFileMultiport::*; + +import FIFOLevel::*; +import MultiFIFOMem::*; +import RegFIFO::*; + +// Arbiters and Allocators used for scheduling +import Arbiters::*; +import Allocators::*; + +// Eventually maybe replace this with more efficient/alternative single queue implementation +typedef MultiFIFOMem#(Flit_t, 1, FlitBufferDepth) InputQueue; +(* synthesize *) +module mkInputQueue(InputQueue); + InputQueue inputQueue_ifc; + if ( `PIPELINE_LINKS ) begin // Add 1 cycle margin to FIFOs for credit that might be in transit + inputQueue_ifc <- mkMultiFIFOMem(False /*storeHeadsTailsInLUTRAM*/, 1 /* full_margin */ ); + end else begin + inputQueue_ifc <- mkMultiFIFOMem(False /*storeHeadsTailsInLUTRAM*/, 0 /* full_margin */ ); + end + return inputQueue_ifc; +endmodule + +typedef FIFOCountIfc#(OutPort_t, FlitBufferDepth) OutPortFIFO; +(* synthesize *) +module mkOutPortFIFO(OutPortFIFO); + //String fifo_name = strConcat( strConcat(integerToString(id1), " - "), integerToString(id2)); + //OutPortFIFO outPortFIFO_ifc <- mkRegFIFO_named(fifo_name, False); + OutPortFIFO outPortFIFO_ifc <- mkRegFIFO(False); + return outPortFIFO_ifc; +endmodule + +//typedef RF_16portsLoad#(RouterID_t, OutPort_t) RouteTableOld; +//typedef RegFileMultiport#(NumInPorts/*nr*/, 1/*nw*/, RouterID_t, OutPort_t) RouteTable; +//typedef RegFileMultiport#(NumInPorts/*nr*/, 1/*nw*/, UserPortID_t, OutPort_t) RouteTable; +typedef RegFileMultiport#(NumInPorts/*nr*/, 1/*nw*/, UserRecvPortID_t, OutPort_t) RouteTable; +module mkRouteTable#(String route_table_file) (RouteTable); + //RouteTable rt_ifc <- mkRF_16portsLoad(route_table_file); + RouteTable rt_ifc <- mkRegFileMultiportLoad(route_table_file); + return rt_ifc; +endmodule + +(* synthesize *) +module mkRouteTableSynth(RouteTable); + String route_table_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(4)), ".hex"); + //RouteTableOld rt_ifc <- mkRF_16portsLoad(route_table_file, False); + RouteTable rt_ifc <- mkRegFileMultiportLoad(route_table_file); + return rt_ifc; +endmodule + +//////////////////////////////////////////////// +// Router Module implementation +//////////////////////////////////////////////// +module mkIQRouterSimple#(Integer id)(RouterSimple); + String name = "IQRouterSimple"; + Bit#(8) errorCode = 0; + + Vector#(NumInPorts, InPortSimple) inPort_ifaces; // in port interfaces +`ifdef EN_DBG + RouterCoreSimple router_core <- mkIQRouterCoreSimple(id); +`else + RouterCoreSimple router_core <- mkIQRouterCoreSimple(); +`endif + // Route Table + String route_table_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(id)), ".hex"); + //RF_16portsLoad#(RouterID_t, OutPort_t) routeTable <- mkRF_16portsLoad(route_table_file, /*binary*/False); + //RouteTable routeTable <- mkRouteTable(route_table_file, /*binary*/False); + RouteTable routeTable <- mkRouteTable(route_table_file); + + // for debugging + `ifdef EN_DBG + Reg#(Cycle_t) cycles <- mkConfigReg(0); + rule update_cycles(True); + cycles <= cycles + 1; + endrule + `endif + + // Define input interfaces + for(Integer i=0; i < valueOf(NumInPorts); i=i+1) begin + let ifc = + interface InPortSimple + method Action putFlit(Maybe#(Flit_t) flit_in); + Maybe#(RoutedFlit_t) rt_flit = Invalid; + //`DBG_ID(("Receiving Flit on in_port %0d", i)); + if(isValid(flit_in)) begin + let fl_in = flit_in.Valid; + let out_p = routeTable.r[i].sub(fl_in.dst); + //let fl_in = tagged Valid Flit_t{is_tail:flit_in.Valid.is_tail, dst:flit_in.Valid.dst, out_p:out_p, vc:flit_in.Valid.vc, data:flit_in.Valid.data}; + rt_flit = tagged Valid RoutedFlit_t{flit:fl_in, out_port:out_p}; + //rt_flit = tagged Valid RoutedFlit_t{ flit:Flit_t{is_tail:fl_in.is_tail, dst:fl_in.dst, out_p:out_p, vc:fl_in.vc, data:fl_in.data}, out_port:out_p}; + `DBG_ID_CYCLES(("Incoming flit on port %0d - dest:%0d, vc:%0d, data:%x", i, fl_in.dst, fl_in.vc, fl_in.data )); + end + router_core.in_ports[i].putRoutedFlit(rt_flit); + endmethod + + // send credits upstream + method ActionValue#(Vector#(NumVCs, Bool)) getNonFullVCs; + let cr_out <- router_core.in_ports[i].getNonFullVCs(); + return cr_out; + endmethod + + endinterface; + + inPort_ifaces[i] = ifc; + end + + interface in_ports = inPort_ifaces; + interface out_ports = router_core.out_ports; + //interface rt_info = rt_info_ifc; + +endmodule + + +module mkIQRouterSimpleSynth(RouterSimple); + let rt_synth <- mkIQRouterSimple(4); + return rt_synth; +endmodule + + +//////////////////////////////////////////////// +// Router Module implementation +//////////////////////////////////////////////// +//module mkRouter#(RouterID_t id) (Router); +`ifdef EN_DBG +module mkIQRouterCoreSimple#(Integer id)(RouterCoreSimple); +`else +(* synthesize *) +module mkIQRouterCoreSimple(RouterCoreSimple); +`endif + + String name = "IQRouterCoreSimple"; + Bit#(8) errorCode = 0; + + // Vector of input and output port interfaces + Vector#(NumInPorts, RouterCoreInPortSimple) inPort_ifaces; // in port interfaces + Vector#(NumOutPorts, OutPortSimple) outPort_ifaces; // out port interfaces + + // Router Allocator + RouterAllocator routerAlloc <- mkSepRouterAllocator(`PIPELINE_ALLOCATOR /*pipeline*/); + + // Router State + Vector#(NumInPorts, InputQueue) flitBuffers <- replicateM(mkInputQueue()); + //Vector#(NumInPorts, RF_16ports#(VC_t, FlitBuffer_t) ) flitBuffers <- replicateM(mkRF_16ports()); + Vector#(NumInPorts, OutPortFIFO) outPortFIFOs; + Vector#(NumOutPorts, Wire#(Bool)) simple_credits; + + Vector#(NumInPorts, Wire#(Maybe#(Flit_t))) hasFlitsToSend_perIn <- replicateM(mkDWire(Invalid)); + Vector#(NumInPorts, Wire#(Maybe#(Flit_t))) flitsToSend_perIn <- replicateM(mkDWire(Invalid)); + // Used for multi-flit packets that use virtual links + //if(`USE_VIRTUAL_LINKS) begin + Vector#(NumOutPorts, Reg#(Bool) ) lockedVL; // locked virtual link + Vector#(NumOutPorts, Reg#(InPort_t)) inPortVL; // holds current input for locked virtual channels + //end + + + // for debugging + `ifdef EN_DBG + Reg#(Cycle_t) cycles <- mkConfigReg(0); + rule update_cycles(True); cycles <= cycles + 1; endrule + `endif + + simple_credits <- replicateM(mkDWire(False)); // don't assume credits + outPortFIFOs <- replicateM(mkOutPortFIFO()); + + lockedVL <- replicateM(mkConfigReg(False)); + inPortVL <- replicateM(mkConfigReg(unpack(0))); + + // -- Initialization -- + /*for(Integer o=0; o Router: %0d - dequeing from outPortFIFOs[%0d][%0d]", id, i, activeVC_perIn[i].Valid); + + //if(fl.out_p != out_port) begin + // `DBG_ID(("Outport mismatch! fl.out_p: %d does not match out_port %d", fl.out_p, out_port)); + //end + //activeVC_perOut[out_port] <= tagged Valid activeVC_perIn[i].Valid; + end + end + endrule + + +// ////////////////////////////////////////////////////////////////////////////////////////////// +// // Old MEMOCODE arbiter - performs static priority maximal matching +// // First mask out entries that don't have credits or are ineligible to be picked - Convert to function +// Vector#(NumVCs, Vector#(NumInPorts, Vector#(NumOutPorts, Bool ) ) ) eligVIO = unpack(0); //perOut_perVC_perIn; +// for(Integer i=0; i0) begin +// eligVIO[v][i][out_port] = True; +// end +// end +// end +// end +// +// +// +// // Arbitration - packaged main arbitration logic for each output in "noinline" function --> this reduces compilation times by 2 ORDERS OF MAGNITUDE! +// Tuple3#( Vector#(NumInPorts, Maybe#(VC_t)), /* activeVC_perIn */ +// Vector#(NumOutPorts, Maybe#(InPort_t)), /* activeIn_perOut */ +// Vector#(NumOutPorts, VC_t) /* activeVC_perOut */ +// ) arb_result; +// +// arb_result = arbitrateAll(eligVIO); +// activeVC_perIn = tpl_1(arb_result); +// activeIn_perOut = tpl_2(arb_result); +// activeVC_perOut = tpl_3(arb_result); +// +// Vector#(NumInPorts, Bool) activeInPorts = unpack(0); +// for(Integer i=0; i set +// if ( hasFlitsVIO_set[v][i][o] ) begin // something came in on an in_port --> set +// hasFlitsVIO[v][i][o] <= True; +// `DBG(("Marking incoming flit for out:%0d VC:%0d from in:%0d", o, v, i)); +// //end else if ( hasFlitsVIO_clear[v][i][o] && !hasFlitsVIO_set[v][i][o]) begin // something departed --> clear +// end else if ( hasFlitsVIO_clear[v][i][o] ) begin // something departed --> clear +// `DBG(("Clearing flit for out:%0d VC:%0d from in:%0d", o, v, i)); +// hasFlitsVIO[v][i][o] <= False; +// end +// end +// end +// end +// endrule + + // Rule to update credits. Credits get replenished from out_ports and are spent when sending flits. +/* (* fire_when_enabled *) + rule update_credits (True); // turn off credits for debugging + for(Integer o=0; o fromInteger(valueof(FlitBufferDepth))) begin + `DBG_ID(("Credit overflow at out_port %0d", o)); + end + end else if (!credits_set[o] && credits_clear[o]) begin // I only spent a credit + //credits[o][v] <= False; + credits[o] <= credits[o] - 1; + if(credits[o] == 0) begin + `DBG_ID(("Credit underflow at out_port %0d", o)); + end + end + end + //`DBG_DETAIL_ID(("credits:%b", readVReg(concat(credits)) )); // flatten the array to print + endrule + */ + + + function Action printAllocMatrix(Vector#(n, Vector#(m, Bool)) am); + action + for(Integer i=0; i Router: %0d - enqueing to outPortFIFOs[%0d][%0d]", id, i, fl_in.vc); + //`DBG(("Marking incoming flit for dst:%0d VC:%0d from in:%0d (isT:%0d)", fl_in.dst, fl_in.vc, i, /*fl_in.is_head,*/ fl_in.is_tail)); + //hasFlitsVIO_set[fl_in.vc][i][out_port] <= True; + end + endmethod + + // send credits upstream + method ActionValue#(Vector#(NumVCs, Bool)) getNonFullVCs; + Vector#(NumVCs, Bool) ret = unpack(0); + let tmp = flitBuffers[i].notFull(); + ret[0] = tmp[0]; // VC is always 0 for input-queued router + return ret; + endmethod + endinterface; + + inPort_ifaces[i] = ifc; + end + + // Implement output interfaces + for(Integer o=0; o < valueOf(NumOutPorts); o=o+1) begin + let ifc = + interface OutPortSimple + method ActionValue#(Maybe#(Flit_t)) getFlit(); + Maybe#(Flit_t) flitOut = Invalid; + if( isValid(activeIn_perOut[o]) ) begin // I have a flit to send + let active_in = activeIn_perOut[o].Valid; + //let active_vc = activeVC_perOut[o].Valid; + //if(!isValid(activeVC_perOut[o])) begin + // `DBG_ID(("active_vc is invalid!")); + //end + //let fb = flitBuffers[ active_in ].read_ports[o].read(active_vc); + //let fb <- flitBuffers[active_in].deq(active_vc); + //let fb <- flitsToSend_perIn[active_in]; + //outPortFIFOs[active_in][active_vc].deq(); + + //hasFlitsVIO_clear[active_vc][active_in][o] <= True; + //if(fb.is_tail) begin // If you see a tail unlock VL (also covers head/tail case) + // lockedVL[o][active_vc] <= False; + // //`DBG_DETAIL_ID(("UNLOCKED output %0d (was locked to in:%0d)", o, inPortVL[o][active_vc] )); + //end else begin // it's not a tail (i.e. head or in the middle of a packet), so lock the VL. + // lockedVL[o][active_vc] <= True; + // //`DBG_DETAIL_ID(("LOCKED output %0d locked to in:%0d, VC:%0d (flit %0d)", o, active_in, active_vc, fb.id )); + // inPortVL[o][active_vc] <= active_in; + //end + //flitOut = tagged Valid Flit_t{is_tail:fb.is_tail, dst:fb.dst, vc:active_vc, data:fb.data }; + //flitOut = flitsToSend_perIn[active_in]; + + `ifdef RESTRICT_UTURNS + // pruned version + // Generate pruned activeIn + dynamicAssert(active_in != fromInteger(o), "No U-turns allowed!"); + Vector#(NumInPorts, Bool) selectedInput = unpack(0); + selectedInput[active_in] = True; + let selectedInput_pruned = pruneVector(selectedInput, o); + let active_in_pruned = encoder(selectedInput_pruned); + let hasFlitsToSend_perIn_pruned = pruneVector(hasFlitsToSend_perIn, o); + flitOut = hasFlitsToSend_perIn_pruned[active_in_pruned.Valid]; + `else + //end else begin + // no pruning + flitOut = hasFlitsToSend_perIn[active_in]; + `endif + //end + + dynamicAssert(isValid(flitOut), "Output selected invalid flit!"); + + if(`USE_VIRTUAL_LINKS) begin + if(flitOut.Valid.is_tail) begin // If you see a tail unlock VL (also covers head/tail case) + lockedVL[o] <= False; + `DBG_DETAIL_ID(("UNLOCKED output %0d (was locked to in:%0d)", o, inPortVL[o] )); + end else begin + lockedVL[o] <= True; + `DBG_DETAIL_ID(("LOCKED output %0d locked to in:%0d", o, active_in )); + inPortVL[o] <= active_in; + end + end + + //dynamicAssert(flitOut.Valid.vc == active_vc, "Flit VC and active VC do not match!"); + //if(flitOut.Valid.out_p != fromInteger(o)) begin + // `DBG_ID(("Flit out_port %d does not match actual out_port %d", flitOut.Valid.out_p, o)); + //end + + // clear credits + //credits_clear[o] <= True; // VC is always 0 for input-queued router + + end + + return flitOut; + endmethod + + // receive credits from downstream routers + method Action putNonFullVCs(Vector#(NumVCs, Bool) nonFullVCs); + `DBG_DETAIL_ID(("Receiving Credit on out_port %0d", o)); + simple_credits[o] <= nonFullVCs[0]; // VC is always 0 for input-queued router + `DBG_DETAIL(("Cycle: %0d: Non-full VCs for out_port %0d: %b", cycles, o, nonFullVCs)); + endmethod + + endinterface; + outPort_ifaces[o] = ifc; + end + + interface in_ports = inPort_ifaces; + interface out_ports = outPort_ifaces; + +endmodule + + + +/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// + + + +////////////////////////////////////////////////////////////// +// Old Arbitration Functions +////////////////////////////////////////////////////////////// + +//(* noinline *) +//function Maybe#(VC_t) pickVC( Vector#(NumVCs, Bool) eligVCs ); +// Maybe#(VC_t) sel_VC = Invalid; +// //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority +// for(Integer v=valueOf(NumVCs)-1; v >= 0; v=v-1) // I want the lowest to have highest priority +// begin +// if(eligVCs[v]) begin +// sel_VC = Valid(fromInteger(v)); +// end +// end +// return sel_VC; +//endfunction + +//(* noinline *) +//function Maybe#(InPort_t) pickIn( Vector#(NumInPorts, Bool) eligIns ); +// Maybe#(InPort_t) sel_In = Invalid; +// //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority +// for(Integer i=valueOf(NumInPorts)-1; i >= 0; i=i-1) // I want the lowest to have highest priority +// begin +// if(eligIns[i]) begin +// sel_In = Valid(fromInteger(i)); +// end +// end +// return sel_In; +//endfunction + +//(* noinline *) +//function Vector#(NumVCs, Vector#(NumInPorts, Bool )) maskOccupiedInputs(Vector#(NumVCs, Vector#(NumInPorts, Bool )) eligVI, Vector#(NumInPorts, Bool) freeInputs); +// for(Integer v=0; v 0, "Index width must be > 0" ); + + function Bit#(index_nt) incr(Bit#(index_nt) i); + return i+1; + endfunction + + function Bit#(index_nt) decr(Bit#(index_nt) i); + return i-1; + endfunction + + Reg#(Bool) full <- mkReg(False); + Reg#(Bool) almost_full <- mkReg(False); + Reg#(Bool) empty <- mkReg(True); + + + (* fire_when_enabled *) + rule work (True); + + if(isValid(w_clr.wget)) begin + head <= 0; + tail <= 0; + enq_cnt <= 0; + deq_cnt <= 0; + full <= False; + almost_full <= False; + empty <= True; + size_cnt <= 0; + end + + else begin + + if (isValid(w_deq.wget)) begin + head <= incr( head ); + deq_cnt <= deq_cnt + 1; + end + + if (isValid(w_enq.wget)) begin + let value = validValue(w_enq.wget); + mem.upd( tail, value ); + tail <= incr( tail ); + enq_cnt <= enq_cnt + 1; + end + + Bool nfull = full; + Bool nempty = empty; + Bool nalmost_full = almost_full; + let nsize = size_cnt; + + if(isValid(w_deq.wget) && isValid(w_enq.wget)) begin // queue remains same size, no change in status signals + nfull = full; + nempty = empty; + nalmost_full = almost_full; + end + else if(isValid(w_deq.wget)) begin + nfull = False; + nalmost_full = ( tail == head ); + nempty = ( incr( head ) == tail ); + nsize = size_cnt-1; + end + else if(isValid(w_enq.wget)) begin + nfull = ( incr(tail) == head ); + nalmost_full = ( (tail+2) == head ); + nempty = False; // if enqueuing, then definitely not empty + nsize = size_cnt+1; + end + + empty <= nempty; + full <= nfull; + almost_full <= nalmost_full || nfull; + size_cnt <= nsize; + + end + endrule + + continuousAssert( ! (empty && ( enq_cnt != deq_cnt ) ), "mismatched in enq/deq count" ); + + Bool logical_empty = (head == tail) && !full; // not synthesized + continuousAssert( empty == logical_empty, "error in empty signals" ); + + let pos = getStringPosition(name); + String pos_str = printPosition(pos); + + + method value_t first = mem.sub( head ); + method notFull = !full; + method notEmpty = !empty; + //method almostFull = almost_full; + + + method Action enq(value_t value) if (!full || !guarded); + w_enq.wset(value); + if(full) + $display("location of dfifo: ", pos_str); + dynamicAssert( !full, "ouch, enqueuing to full FIFO" ); + endmethod + + method Action deq() if (!empty || !guarded); + w_deq.wset(?); + if(empty) + $display("location of dfifo: ", pos_str); + dynamicAssert( !empty, "ouch, dequeueing from empty FIFO" ); + endmethod + + method Action clear(); + w_clr.wset(?); + endmethod + + method count() = size_cnt; + +endmodule + + +/////////////////////////////////////////////// +// LUT FIFO test +// +//typedef 32 FIFODepth; +//typedef Bit#(133) Data_t; +//typedef FIFOCountIfc#(Data_t, FIFODepth) LUTFIFOSynth; +// +//(* synthesize *) +//module mkLUTFIFOSynth(LUTFIFOSynth); +// LUTFIFOSynth f <- mkLUTFIFO(False); +// return f; +//endmodule +// diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..adbf2ca --- /dev/null +++ b/Makefile @@ -0,0 +1,287 @@ + +#========================================================================= +# +# Filename: Makefile +# Date created: 03-16-2011 +# Last modified: 04-07-2011 +# Authors: Michael Papamichael +# +# Description: +# Makefile for simulating and generating netlists. +# Based on Eric's makefile. +# +#========================================================================= + + +include makefile.def +include makefile.syn +include makefile.clean + +NPROCS:=$(shell grep -c ^processor /proc/cpuinfo) + +ifndef TARGET +%-bsim: + @make TARGET=$* $@ top=$(top) BSV_MACROS=$(BSV_MACROS) BUILD=$(BUILD) +%-vsim: + @make TARGET=$* $@ top=$(top) BSV_MACROS=$(BSV_MACROS) BUILD=$(BUILD) +%-run: + @make TARGET=$* $@ top=$(top) BSV_MACROS=$(BSV_MACROS) BUILD=$(BUILD) +%-xst: + @echo $* + @echo $@ + @echo $(top) + @make TARGET=$* $@ top=$(top) part=$(part) BSV_MACROS=$(BSV_MACROS) BUILD=$(BUILD) +%-dc: + @echo $* + @echo $@ + @echo $(top) + @make TARGET=$* $@ top=$(top) pdk=$(pdk) BSV_MACROS=$(BSV_MACROS) BUILD=$(BUILD) + +%-map: + @echo $* + @echo $@ + @echo $(top) + @make TARGET=$* $@ top=$(top) part=$(part) BSV_MACROS=$(BSV_MACROS) BUILD=$(BUILD) +%-bsc: + @echo $* + @echo $@ + @echo $(top) + @make TARGET=$* $@ top=$(top) BSV_MACROS=$(BSV_MACROS) BUILD=$(BUILD) +else + +########## BSIM PLUS COPRIMS ########### +#%-bsim: coprims $(call csrc, ./proj/$(TARGET)) +#ifndef top +# $(call bsim_compile, mk$*, $*.bsv); # bsv handles rest of dependencies +#else +# $(call bsim_compile, mk$(top), $(top).bsv); +#endif + +########## VSIM ########### +%-vsim: copy_vlog +ifndef top + scripts/bsvdeps . $*.bsv 1 > $*.dep + make -j $(NPROCS) -f makefile.bsc DEP=$*.dep GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + #make -j $(NPROCS) -f makefile.bsc DEP=$*.dep GLOBAL_FLAGS="$(GLOBAL_FLAGS)" BSV_MACROS='$(BSV_MACROS)' + #$(call vsim_compile, mk$*, $*.bsv); +else + scripts/bsvdeps . $*.bsv 1 > $*.dep + make -j $(NPROCS) -f makefile.bsc DEP=$*.dep GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + #$(call vsim_compile, $(top), $*.bsv); +endif + +########## VSIM ########### +%-run: copy_vlog +ifndef top + $(call vsim_compile, mk$*, $*.bsv); + $(call vcs_compile, mk$*); +else + $(call vsim_compile, $(top), $*.bsv); + $(call vcs_compile, $(top)); +endif + +########## XST ########### +%-xst: copy_vlog +ifndef top + # Parallel make + #scripts/bsvdeps . $*.bsv 1 > $*.dep + #make -j $(NPROCS) -f makefile.bsc DEP=$*.dep GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + #make -f makefile.bsc target TOP=$* GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + + # Serial make + $(call vsim_compile, mk$*, $*.bsv); + $(call xst_compile, mk$*, $(part)); +else + # Parallel make + #scripts/bsvdeps . $*.bsv 1 > $*.dep + #make -j $(NPROCS) -f makefile.bsc DEP=$*.dep GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + #make -f makefile.bsc target TARGET=$* TOP=$(top) GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + + # Serial make + $(call vsim_compile, $(top), $*.bsv); + $(call xst_compile, $(top), $(part)); +endif + +########## DC ########### +%-dc: copy_vlog +ifndef top + # Parallel make + #scripts/bsvdeps . $*.bsv 1 > $*.dep + #make -j $(NPROCS) -f makefile.bsc DEP=$*.dep GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + #make -f makefile.bsc target TOP=$* GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + + # Serial make + $(call vsim_compile, mk$*, $*.bsv); + $(call dc_compile, mk$*, $(pdk)); +else + # Parallel make + #scripts/bsvdeps . $*.bsv 1 > $*.dep + #make -j $(NPROCS) -f makefile.bsc DEP=$*.dep GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + #make -f makefile.bsc target TARGET=$* TOP=$(top) GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + + # Serial make + $(call vsim_compile, $(top), $*.bsv); + $(call dc_compile, $(top), $(pdk)); +endif + +########## MAP ########### +%-map: copy_vlog +ifndef top + # Parallel make + #scripts/bsvdeps . $*.bsv 1 > $*.dep + #make -j $(NPROCS) -f makefile.bsc DEP=$*.dep GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + #make -f makefile.bsc target TOP=$* GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + + # Serial make + $(call vsim_compile, mk$*, $*.bsv); + $(call map_compile, mk$*, $(part)); +else + # Parallel make + #scripts/bsvdeps . $*.bsv 1 > $*.dep + #make -j $(NPROCS) -f makefile.bsc DEP=$*.dep GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + #make -f makefile.bsc target TARGET=$* TOP=$(top) GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + + # Serial make + $(call vsim_compile, $(top), $*.bsv); + $(call map_compile, $(top), $(part)); +endif + + +########## BSC ########### +%-bsc: copy_vlog +ifndef top + # Parallel make + #scripts/bsvdeps . $*.bsv 1 > $*.dep + #make -j $(NPROCS) -f makefile.bsc DEP=$*.dep GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + #make -f makefile.bsc target TOP=$* GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + + # Serial make + $(call vsim_compile, mk$*, $*.bsv); +else + # Parallel make + #scripts/bsvdeps . $*.bsv 1 > $*.dep + #make -j $(NPROCS) -f makefile.bsc DEP=$*.dep GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + #make -f makefile.bsc target TARGET=$* TOP=$(top) GLOBAL_FLAGS="$(GLOBAL_FLAGS)" + + # Serial make + $(call vsim_compile, $(top), $*.bsv); +endif + + +endif + +sw: + g++ -o parse_conf parse_conf.cpp + g++ -o parse_traffic parse_traffic.cpp + +tmp: copy_vlog + $(call vsim_compile, mkInputVOQs, InputVOQs.bsv); + $(call xst_compile, mkInputVOQs); + +tmp2: copy_vlog + $(call vsim_compile, mkTestArbiter8, Arbiters.bsv); + $(call xst_compile, mkTestArbiter8); + +tmp3: copy_vlog + $(call vsim_compile, mkVOQRouter_multi_flit_bufs, VOQRouter_multi_flit_bufs.bsv); + $(call xst_compile, mkVOQRouter_multi_flit_bufs); + + +tmp4: copy_vlog + $(call vsim_compile, mkMultiFIFOMemTest, MultiFIFOMem.bsv); + $(call xst_compile, mkMultiFIFOMemTest); + +net: copy_vlog + $(call vsim_compile, mkNetwork, Network.bsv); + +net_xst: copy_vlog + $(call vsim_compile, mkNetwork, Network.bsv); + $(call xst_compile, mkNetwork); + +net_dc: copy_vlog + $(call vsim_compile, mkNetwork, Network.bsv); + $(call dc_compile, mkNetwork); + + +net_simple: copy_vlog + $(call vsim_compile, mkNetworkSimple, NetworkSimple.bsv); + +net_simple_xst: copy_vlog + $(call vsim_compile, mkNetworkSimple, NetworkSimple.bsv); + $(call xst_compile, mkNetworkSimple); + +net_simple_dc: copy_vlog + $(call vsim_compile, mkNetworkSimple, NetworkSimple.bsv); + $(call dc_compile, mkNetworkSimple); + + +mcr_tb: copy_vlog + $(call vsim_compile, mkMCRouter_tb, MCRouter_tb.bsv); + $(call vcs_compile, mkMCRouter_tb); + +mcr_xst: copy_vlog + $(call vsim_compile, mkMCRouter, MCRouter.bsv); + $(call xst_compile, mkMCRouter); + +mcn_tb: copy_vlog + $(call vsim_compile, mkMCNetwork_tb, MCNetwork_tb.bsv); + $(call vcs_compile, mkMCNetwork_tb); + +mcn_xst: copy_vlog + $(call vsim_compile, mkMCNetwork, MCNetwork.bsv); + $(call xst_compile, mkMCNetwork); + +mcn_xst_speed2: copy_vlog + $(call vsim_compile, mkMCNetwork, MCNetwork.bsv); + $(call xst_compile_speed2, mkMCNetwork); + +mcn_xst_speed3: copy_vlog + $(call vsim_compile, mkMCNetwork, MCNetwork.bsv); + $(call xst_compile_speed3, mkMCNetwork); + +mcn_xst_xupv5: copy_vlog + $(call vsim_compile, mkMCNetwork, MCNetwork.bsv); + $(call xst_compile_xupv5, mkMCNetwork); + +mcn_xst_xupv5_speed2: copy_vlog + $(call vsim_compile, mkMCNetwork, MCNetwork.bsv); + $(call xst_compile_xupv5_speed2, mkMCNetwork); + +mcn_xst_xupv5_speed3: copy_vlog + $(call vsim_compile, mkMCNetwork, MCNetwork.bsv); + $(call xst_compile_xupv5_speed2, mkMCNetwork); + +mcvn_xst: copy_vlog + $(call vsim_compile, mkMCVirtualNetwork, MCVirtualNetwork.bsv); + $(call xst_compile, mkMCVirtualNetwork); + +mcvn_xst_speed2: copy_vlog + $(call vsim_compile, mkMCVirtualNetwork, MCVirtualNetwork.bsv); + $(call xst_compile_speed2, mkMCVirtualNetwork); + +mcvn_xst_speed3: copy_vlog + $(call vsim_compile, mkMCVirtualNetwork, MCVirtualNetwork.bsv); + $(call xst_compile_speed3, mkMCVirtualNetwork); + +mcvn_xst_xupv5: copy_vlog + $(call vsim_compile, mkMCVirtualNetwork, MCVirtualNetwork.bsv); + $(call xst_compile_xupv5, mkMCVirtualNetwork); + +mcvn_xst_xupv5_speed2: copy_vlog + $(call vsim_compile, mkMCVirtualNetwork, MCVirtualNetwork.bsv); + $(call xst_compile_xupv5_speed2, mkMCVirtualNetwork); + +mcvn_xst_xupv5_speed3: copy_vlog + $(call vsim_compile, mkMCVirtualNetwork, MCVirtualNetwork.bsv); + $(call xst_compile_xupv5_speed3, mkMCVirtualNetwork); + + +mcvn_tb: copy_vlog + $(call vsim_compile, mkMCVirtualNetwork_tb, MCVirtualNetwork_tb.bsv); + $(call vcs_compile, mkMCVirtualNetwork_tb); + +mctraffic_tb: copy_vlog + $(call vsim_compile, mkMCTraffic_tb, MCTraffic_tb.bsv); + $(call vcs_compile, mkMCTraffic_tb); + + diff --git a/MultiFIFOMem.bsv b/MultiFIFOMem.bsv new file mode 100644 index 0000000..7f1bc0a --- /dev/null +++ b/MultiFIFOMem.bsv @@ -0,0 +1,495 @@ +/* ========================================================================= + * Filename: MultiFIFOMem.bsv + * Date created: 05-10-2011 + * Last modified: 05-10-2011 + * Authors: Michael Papamichael + * + * Description: + * This module implements multiple logical FIFOs hosted in a single LUTRAM + * memory. Only a single enqueue and dequeue operation are supported in each + * cycle. (enqueue and dequeue do not have to be to/from the same logical FIFO) + * Used as a building block for input queued routers. + * + * ========================================================================= + */ + +import Vector::*; +import RF_16ports::*; +import RF_1port::*; +import RegFile::*; +import ConfigReg::*; +import StmtFSM::*; // just for creating a test sequence +import Assert::*; + +`include "inc.v" + +// -- MultiFIFOMem Interface -- +//interface MultiFIFOMem#(Integer num_fifos, Integer fifo_depth, type fifo_data_t) +// method Action enq(Bit#(TLog#(num_fifos)) fifo_in, fifo_data_t data_in); // Enqueues flit into voq voq_enq +// method ActionValue#(fifo_data_t) deq(Bit#(TLog#(num_fifos) fifo_out); // Dequeues flit from voq voq_deq +// method Vector#(num_fifos, Bool) notEmpty(); // Used to query which voqs have flits +// method Vector#(num_fifos, Bool) notFull(); // Used to query which voqs are not full +//endinterface + +interface MultiFIFOMem#(type fifo_data_t, numeric type num_fifos, numeric type fifo_depth); + (* always_ready *) method Action enq(Bit#(TLog#(num_fifos)) fifo_in, fifo_data_t data_in); // Enqueues flit into voq voq_enq + (* always_ready *) method ActionValue#(fifo_data_t) deq(Bit#(TLog#(num_fifos)) fifo_out); // Dequeues flit from voq voq_deq + (* always_ready *) method Vector#(num_fifos, Bool) notEmpty(); // Used to query which voqs have flits + (* always_ready *) method Vector#(num_fifos, Bool) notFull(); // Used to query which voqs are not full +endinterface + +module mkMultiFIFOMem#( Bool storeHeadsTailsInLUTRAM, Integer full_margin) + ( MultiFIFOMem#(fifo_data_t, num_fifos, fifo_depth) ) + provisos( Bits#(fifo_data_t, fifo_data_width_t) ); + + staticAssert(full_margin < 4, "Full margin can only take values 0,1,2 or 3"); + //static_assert(full_margin < 3, "Full margin can only take values 0, 1 or 2"); + MultiFIFOMem#(fifo_data_t, num_fifos, fifo_depth) mf_ifc; + if (storeHeadsTailsInLUTRAM) begin + mf_ifc <- mkMultiFIFOMem_HeadTailsInLUTRAM(full_margin); + end else begin + mf_ifc <- mkMultiFIFOMem_HeadTailsInRegs(full_margin); + end + //MultiFIFOMemSynth mf <- mkMultiFIFOMemHeadTailsInLUTRAM(); + return mf_ifc; +endmodule + + +module mkMultiFIFOMem_HeadTailsInRegs#( Integer full_margin ) + (MultiFIFOMem#(fifo_data_t, num_fifos, fifo_depth)) + provisos( Bits#(fifo_data_t, fifo_data_width_t) ); + String name = "MultiFIFOMem"; + + //typedef Bit#(TLog#(num_fifos)) FIFOIdx_t; + //typedef Bit#(TLog#(fifo_depth)) FIFOPtr_t; // Pointer for individual queue + //typedef Bit#(TAdd#( TLog#(num_queues), TLog#(queue_depth) )) FIFOMemIdx_t; // Used to index fifoMem that hosts multiple queues + + // LUT RAM that stores multiple queues + //RF_16ports#( Bit#(TAdd#( TLog#(num_fifos), TLog#(fifo_depth) )) , fifo_data_t) fifoMem <- mkRF_16ports(); + //let hi = TMul#(num_fifos, fifo_depth); + //RegFile#( Bit#(TAdd#( TLog#(num_fifos), TLog#(fifo_depth) )) , fifo_data_t) fifoMem <- mkRegFile(0, fromInteger(valueOf(TMul#(num_fifos, fifo_depth))-1 )); + //RegFile#( Bit#(TAdd#( TLog#(num_fifos), TLog#(fifo_depth) )) , fifo_data_t) fifoMem <- mkRegFileFull(); + RF_1port#( Bit#(TAdd#( TLog#(num_fifos), TLog#(fifo_depth) )) , fifo_data_t) fifoMem <- mkRF_1port(); + Vector#(num_fifos, Reg#( Bit#(TLog#(fifo_depth)) )) heads <- replicateM(mkConfigReg(0)); + Vector#(num_fifos, Reg#( Bit#(TLog#(fifo_depth)) )) tails <- replicateM(mkConfigReg(0)); + Vector#(num_fifos, Reg#(Bool)) not_empty <- replicateM(mkConfigReg(False)); + Vector#(num_fifos, Reg#(Bool)) not_full <- replicateM(mkConfigReg(True)); + + // Wires to have enq and deq communicate to determine which queues are empty + Wire#(Maybe#( Bit#(TLog#(num_fifos)) )) wrFIFO <- mkDWire(Invalid); + Wire#(Maybe#( Bit#(TLog#(num_fifos)) )) rdFIFO <- mkDWire(Invalid); + + // Wires to update head tail pointers + Wire#(Bit#(TLog#(fifo_depth))) new_tail <- mkDWire(0); + Wire#(Bit#(TLog#(fifo_depth))) new_head <- mkDWire(0); + + // These "look-ahead" tail pointers are used to provide extra margin for full signal when pipelining. + // They reduce the effective size of each fifo. + Wire#(Bit#(TLog#(fifo_depth))) new_new_tail <- mkDWire(0); + Wire#(Bit#(TLog#(fifo_depth))) new_new_new_tail <- mkDWire(0); + Wire#(Bit#(TLog#(fifo_depth))) new_new_new_new_tail <- mkDWire(0); + + Wire#(Bit#(TLog#(fifo_depth))) cur_tail <- mkDWire(0); + Wire#(Bit#(TLog#(fifo_depth))) cur_head <- mkDWire(0); + //Wire#(QueuePtr_t) wrPtr <- mkDWire(0); + //Wire#(qPtr) rdPtr <- mkDWire(0); + + rule update_heads_tails(True); + // update tail + if(isValid(wrFIFO)) begin + tails[wrFIFO.Valid] <= new_tail; + end + // update head + if(isValid(rdFIFO)) begin + heads[rdFIFO.Valid] <= new_head; + end + + // update not_empty not_full + if(isValid(wrFIFO)) begin // somethine was enqueued + let fifo_in = wrFIFO.Valid; + if(!isValid(rdFIFO) || (isValid(rdFIFO) && fifo_in != rdFIFO.Valid)) begin // only need to update if a data wasn't dequeued from the same fifo + not_empty[fifo_in] <= True; + + if(full_margin == 0) begin // no margin, full actually corresponds to full signal + if(new_tail == heads[fifo_in]) begin // I enqueued and fifo became full + not_full[fifo_in] <= False; + `DBG_DETAIL(("Queue %d: Became FULL", fifo_in )); + end + end else if (full_margin == 1) begin // 1 cycle margin, full actually means that there is only 1 slot left + if(new_tail == heads[fifo_in] || new_new_tail == heads[fifo_in]) begin // I enqueued and fifo became full or almost full + not_full[fifo_in] <= False; + `DBG_DETAIL(("Queue %d: Became FULL", fifo_in )); + end + end else if (full_margin == 2) begin // 2 cycle margin, full actually means that there is only 2 slot left + if(new_tail == heads[fifo_in] || new_new_tail == heads[fifo_in] || new_new_new_tail == heads[fifo_in]) begin // I enqueued and fifo became full or almost full + not_full[fifo_in] <= False; + `DBG_DETAIL(("Queue %d: Became FULL", fifo_in )); + end + end else if (full_margin == 3) begin // 3 cycle margin, full actually means that there is only 2 slot left + if(new_tail == heads[fifo_in] || new_new_tail == heads[fifo_in] || new_new_new_tail == heads[fifo_in] || new_new_new_new_tail == heads[fifo_in]) begin // I enqueued and fifo became full or almost full + not_full[fifo_in] <= False; + `DBG_DETAIL(("Queue %d: Became FULL", fifo_in )); + end + end + end + end + + if(isValid(rdFIFO)) begin + let fifo_out = rdFIFO.Valid; + if(!isValid(wrFIFO) || (isValid(wrFIFO) && fifo_out != wrFIFO.Valid)) begin // only need to update if data wasn't enqueued to the same fifo + not_full[fifo_out] <= True; + if(new_head == tails[fifo_out]) begin // I just became empty + not_empty[fifo_out] <= False; + `DBG_DETAIL(("Queue %d: Became EMPTY", fifo_out )); + end + end + end + + endrule + + method Action enq(Bit#(TLog#(num_fifos)) fifo_in, fifo_data_t data_in); // Enqueues flit into fifo fifo_in + //dynamicAssert(fifo_in < fromInteger(valueOf(num_fifos)), "fifo_in >= num_fifos: Trying to index non-existent FIFO in MultiFIFOMem!"); + if(!not_full[fifo_in]) begin + `DBG(("2Enqueing to full FIFO - fifo_in:%d", fifo_in)); + `DBG(("Data dump of element that filled FIFO: %x", data_in)); + end + dynamicAssert(not_full[fifo_in], "Enqueing to full FIFO in MultiFIFOMem!"); + //let vcWrPtr = tails.read_ports[0].read(fl.vc); + let fifoWrPtr = tails[fifo_in]; + let enqAddr = {fifo_in, fifoWrPtr}; + `DBG_DETAIL(("Queue %d: Enqueueing %x", fifo_in, data_in )); + fifoMem.write(enqAddr, data_in); // Enqueue data + //fifoMem.upd(enqAddr, data_in); // Enqueue data + //tails.write(fl.vc, vcWrPtr+1); // Advance write pointer + let next_tail = fifoWrPtr+1; + let next_next_tail = next_tail + 1; + let next_next_next_tail = next_next_tail + 1; + cur_tail <= fifoWrPtr; + new_tail <= next_tail; + new_new_tail <= next_tail+1; + new_new_new_tail <= next_next_tail+1; + new_new_new_new_tail <= next_next_next_tail+1; + //tails[fifo_in] <= next_tail; // Advance write pointer + + // update wire used by deq + wrFIFO <= tagged Valid fifo_in; + + // update not_empty not_full + //if(!isValid(rdFIFO) || fifo_in != rdFIFO.Valid) begin // only need to update if a data wasn't dequeued from the same fifo + // not_empty[fifo_in] <= True; + // if(next_tail == heads[fifo_in]) begin // I enqueued and fifo became full + // not_full[fifo_in] <= False; + // `DBG_DETAIL(("Queue %d: Became FULL", fifo_in )); + // end + //end + + endmethod + + method ActionValue#(fifo_data_t) deq(Bit#(TLog#(num_fifos)) fifo_out); // Dequeues flit from fifo_out + //dynamicAssert(fifo_out < fromInteger(valueOf(num_fifos)), "fifo_in >= num_fifos: Trying to index non-existent FIFO in MultiFIFOMem!"); + dynamicAssert(not_empty[fifo_out], "Dequeing from empty FIFO in MultiFIFOMem!"); + //let vcRdPtr = heads.read_ports[0].read(vc); + let fifoRdPtr = heads[fifo_out]; + let deqAddr = {fifo_out, fifoRdPtr}; + //let data = fifoMem.read_ports[0].read(deqAddr); // Dequeue data + //let data = fifoMem.sub(deqAddr); // Dequeue data + let data = fifoMem.read(deqAddr); // Dequeue data + `DBG_DETAIL(("Queue %d: Dequeueing %x", fifo_out, data )); + //heads.write(fl.vc, vcRdPtr+1); // Advance read pointer + let next_head = fifoRdPtr+1; + cur_head <= fifoRdPtr; + new_head <= next_head; + //heads[fifo_out] <= next_head; // Advance read pointer + + // update wire used by enqFlit method + rdFIFO <= tagged Valid fifo_out; + + // update not_empty not_full + //if(!isValid(wrFIFO) || fifo_out != wrFIFO.Valid) begin // only need to update if data wasn't enqueued to the same fifo + // not_full[fifo_out] <= True; + // if(next_head == tails[fifo_out]) begin // I just became empty + // not_empty[fifo_out] <= False; + // `DBG_DETAIL(("Queue %d: Became EMPTY", fifo_out )); + // end + //end + + return data; + endmethod + + method Vector#(num_fifos, Bool) notEmpty(); // Used to query which queues have data (i.e. are not empty) + return readVReg(not_empty); + endmethod + + method Vector#(num_fifos, Bool) notFull(); // Used to query which queues have space (i.e. are not full) + return readVReg(not_full); + endmethod +endmodule + + + + +//////////////////////////////////////////////////////////// +// More parameterized version +module mkMultiFIFOMem_HeadTailsInLUTRAM#( Integer full_margin ) + (MultiFIFOMem#(fifo_data_t, num_fifos, fifo_depth)) + provisos( Bits#(fifo_data_t, fifo_data_width_t) ); + String name = "MultiFIFOMem"; + + //typedef Bit#(TLog#(num_fifos)) FIFOIdx_t; + //typedef Bit#(TLog#(fifo_depth)) FIFOPtr_t; // Pointer for individual queue + //typedef Bit#(TAdd#( TLog#(num_queues), TLog#(queue_depth) )) FIFOMemIdx_t; // Used to index fifoMem that hosts multiple queues + + // LUT RAM that stores multiple queues + //RF_16ports#( Bit#(TAdd#( TLog#(num_fifos), TLog#(fifo_depth) )) , fifo_data_t) fifoMem <- mkRF_16ports(); + //let hi = TMul#(num_fifos, fifo_depth); + //RegFile#( Bit#(TAdd#( TLog#(num_fifos), TLog#(fifo_depth) )) , fifo_data_t) fifoMem <- mkRegFile(0, fromInteger(valueOf(TMul#(num_fifos, fifo_depth))-1 )); + //RegFile#( Bit#(TAdd#( TLog#(num_fifos), TLog#(fifo_depth) )) , fifo_data_t) fifoMem <- mkRegFileFull(); + RF_1port#( Bit#(TAdd#( TLog#(num_fifos), TLog#(fifo_depth) )) , fifo_data_t) fifoMem <- mkRF_1port(); + + RF_16ports#( Bit#(TLog#(num_fifos)), Bit#(TLog#(fifo_depth)) ) heads <- mkRF_16ports(); + RF_16ports#( Bit#(TLog#(num_fifos)), Bit#(TLog#(fifo_depth)) ) tails <- mkRF_16ports(); + Vector#(num_fifos, Reg#(Bool)) not_empty <- replicateM(mkConfigReg(False)); + Vector#(num_fifos, Reg#(Bool)) not_full <- replicateM(mkConfigReg(True)); + + // Wires to have enq and deq communicate to determine which queues are empty + Wire#(Maybe#( Bit#(TLog#(num_fifos)) )) wrFIFO <- mkDWire(Invalid); + Wire#(Maybe#( Bit#(TLog#(num_fifos)) )) rdFIFO <- mkDWire(Invalid); + + // Wires to update head tail pointers + Wire#(Bit#(TLog#(fifo_depth))) new_tail <- mkDWire(0); + Wire#(Bit#(TLog#(fifo_depth))) new_head <- mkDWire(0); + + // These "look-ahead" tail pointers are used to provide extra margin for full signal when pipelining. + // They reduce the effective size of each fifo. + Wire#(Bit#(TLog#(fifo_depth))) new_new_tail <- mkDWire(0); + Wire#(Bit#(TLog#(fifo_depth))) new_new_new_tail <- mkDWire(0); + Wire#(Bit#(TLog#(fifo_depth))) new_new_new_new_tail <- mkDWire(0); + + Wire#(Bit#(TLog#(fifo_depth))) cur_tail <- mkDWire(0); + Wire#(Bit#(TLog#(fifo_depth))) cur_head <- mkDWire(0); + //Wire#(QueuePtr_t) wrPtr <- mkDWire(0); + //Wire#(qPtr) rdPtr <- mkDWire(0); + + rule update_heads_tails(True); + // update tail + if(isValid(wrFIFO)) begin + tails.write(wrFIFO.Valid, new_tail); + end + // update head + if(isValid(rdFIFO)) begin + heads.write(rdFIFO.Valid, new_head); + end + + // update not_empty not_full + if(isValid(wrFIFO)) begin + let fifo_in = wrFIFO.Valid; + if(!isValid(rdFIFO) || fifo_in != rdFIFO.Valid) begin // only need to update if a data wasn't dequeued from the same fifo + not_empty[fifo_in] <= True; + Bit#(TLog#(fifo_depth)) cur_head; + cur_head = heads.read_ports[0].read(fifo_in); + + if(full_margin == 0) begin // no margin, full actually corresponds to full signal + if(new_tail == cur_head) begin // I enqueued and fifo became full + not_full[fifo_in] <= False; + `DBG_DETAIL(("Queue %d: Became FULL", fifo_in )); + end + end else if (full_margin == 1) begin // 1 cycle margin, full actually means that there is only 1 slot left + if(new_tail == cur_head || new_new_tail == cur_head) begin // I enqueued and fifo became full or almost full + not_full[fifo_in] <= False; + `DBG_DETAIL(("Queue %d: Became FULL", fifo_in )); + end + end else if (full_margin == 2) begin // 2 cycle margin, full actually means that there is only 2 slot left + if(new_tail == cur_head || new_new_tail == cur_head || new_new_new_tail == cur_head) begin // I enqueued and fifo became full or almost full + not_full[fifo_in] <= False; + `DBG_DETAIL(("Queue %d: Became FULL", fifo_in )); + end + end else if (full_margin == 3) begin // 3 cycle margin, full actually means that there is only 2 slot left + if(new_tail == cur_head || new_new_tail == cur_head || new_new_new_tail == cur_head || new_new_new_new_tail == cur_head) begin // I enqueued and fifo became full or almost full + not_full[fifo_in] <= False; + `DBG_DETAIL(("Queue %d: Became FULL", fifo_in )); + end + end + end + end + + if(isValid(rdFIFO)) begin + let fifo_out = rdFIFO.Valid; + if(!isValid(wrFIFO) || fifo_out != wrFIFO.Valid) begin // only need to update if data wasn't enqueued to the same fifo + not_full[fifo_out] <= True; + Bit#(TLog#(fifo_depth)) cur_tail; + cur_tail = tails.read_ports[0].read(fifo_out); + if(new_head == cur_tail) begin // I just became empty + not_empty[fifo_out] <= False; + `DBG_DETAIL(("Queue %d: Became EMPTY", fifo_out )); + end + end + end + + endrule + + method Action enq(Bit#(TLog#(num_fifos)) fifo_in, fifo_data_t data_in); // Enqueues flit into fifo fifo_in + //dynamicAssert(fifo_in < fromInteger(valueOf(num_fifos)), "fifo_in >= num_fifos: Trying to index non-existent FIFO in MultiFIFOMem!"); + dynamicAssert(not_full[fifo_in], "Enqueing to full FIFO in MultiFIFOMem!"); + //let vcWrPtr = tails.read_ports[0].read(fl.vc); + + Bit#(TLog#(fifo_depth)) fifoWrPtr; + fifoWrPtr = tails.read_ports[1].read(fifo_in); + + let enqAddr = {fifo_in, fifoWrPtr}; + `DBG_DETAIL(("Queue %d: Enqueueing %x", fifo_in, data_in )); + fifoMem.write(enqAddr, data_in); // Enqueue data + //fifoMem.upd(enqAddr, data_in); // Enqueue data + //tails.write(fl.vc, vcWrPtr+1); // Advance write pointer + let next_tail = fifoWrPtr+1; + let next_next_tail = next_tail + 1; + let next_next_next_tail = next_next_tail + 1; + cur_tail <= fifoWrPtr; + new_tail <= next_tail; + new_new_tail <= next_tail+1; + new_new_new_tail <= next_next_tail+1; + new_new_new_new_tail <= next_next_next_tail+1; + //tails[fifo_in] <= next_tail; // Advance write pointer + + // update wire used by deq + wrFIFO <= tagged Valid fifo_in; + + // update not_empty not_full + //if(!isValid(rdFIFO) || fifo_in != rdFIFO.Valid) begin // only need to update if a data wasn't dequeued from the same fifo + // not_empty[fifo_in] <= True; + // if(next_tail == heads[fifo_in]) begin // I enqueued and fifo became full + // not_full[fifo_in] <= False; + // `DBG_DETAIL(("Queue %d: Became FULL", fifo_in )); + // end + //end + + endmethod + + method ActionValue#(fifo_data_t) deq(Bit#(TLog#(num_fifos)) fifo_out); // Dequeues flit from fifo_out + //dynamicAssert(fifo_out < fromInteger(valueOf(num_fifos)), "fifo_in >= num_fifos: Trying to index non-existent FIFO in MultiFIFOMem!"); + dynamicAssert(not_empty[fifo_out], "Dequeing from empty FIFO in MultiFIFOMem!"); + //let vcRdPtr = heads.read_ports[0].read(vc); + + Bit#(TLog#(fifo_depth)) fifoRdPtr; + fifoRdPtr = heads.read_ports[1].read(fifo_out); + + //let fifoRdPtr = heads[fifo_out]; + let deqAddr = {fifo_out, fifoRdPtr}; + //let data = fifoMem.read_ports[0].read(deqAddr); // Dequeue data + //let data = fifoMem.sub(deqAddr); // Dequeue data + let data = fifoMem.read(deqAddr); // Dequeue data + `DBG_DETAIL(("Queue %d: Dequeueing %x", fifo_out, data )); + //heads.write(fl.vc, vcRdPtr+1); // Advance read pointer + let next_head = fifoRdPtr+1; + cur_head <= fifoRdPtr; + new_head <= next_head; + //heads[fifo_out] <= next_head; // Advance read pointer + + // update wire used by enqFlit method + rdFIFO <= tagged Valid fifo_out; + + // update not_empty not_full + //if(!isValid(wrFIFO) || fifo_out != wrFIFO.Valid) begin // only need to update if data wasn't enqueued to the same fifo + // not_full[fifo_out] <= True; + // if(next_head == tails[fifo_out]) begin // I just became empty + // not_empty[fifo_out] <= False; + // `DBG_DETAIL(("Queue %d: Became EMPTY", fifo_out )); + // end + //end + + return data; + endmethod + + method Vector#(num_fifos, Bool) notEmpty(); // Used to query which queues have data (i.e. are not empty) + return readVReg(not_empty); + endmethod + + method Vector#(num_fifos, Bool) notFull(); // Used to query which queues have space (i.e. are not full) + return readVReg(not_full); + endmethod +endmodule + + + + + +////////////////////////////////////////////////////////// +// Example instance and Testbench + +//typedef 10 NumFIFOs; +//typedef 2 FIFODepth; +//typedef Bit#(128) Data_t; + +typedef 1 NumFIFOs; +typedef 4 FIFODepth; +typedef Bit#(128) Data_t; + +typedef MultiFIFOMem#(Data_t, NumFIFOs, FIFODepth) MultiFIFOMemSynth; + +(* synthesize *) +module mkMultiFIFOMemSynth(MultiFIFOMemSynth); + //MultiFIFOMemSynth mf <- mkMultiFIFOMem(True /*storeHeadsTailsInLUTRAM*/); + MultiFIFOMemSynth mf <- mkMultiFIFOMem(False /*storeHeadsTailsInLUTRAM*/, 0); + //MultiFIFOMemSynth mf <- mkMultiFIFOMemHeadTailsInLUTRAM(); + return mf; + + //----- Long form isntantiation ----- + //MultiFIFOMemSynth multi_fifos_ifc(); + //mkMultiFIFOMem multi_fifos(multi_fifos_ifc); + //return multi_fifos_ifc; + + //method enq = multi_fifos_ifc.enq; + //method deq = multi_fifos_ifc.deq; + //method notEmpty = multi_fifos_ifc.notEmpty; + //method notFull = multi_fifos_ifc.notFull; + +endmodule + +module mkMultiFIFOMemTest(Empty); + MultiFIFOMemSynth mf<- mkMultiFIFOMemSynth(); + + Stmt test_seq = seq + mf.enq(0, 128'h00000000000000000000000000000000); + mf.enq(0, 128'h00000000000000011111111111111111); + mf.enq(1, 128'h11111111111111100000000000000000); + mf.enq(0, 128'h00000000000000022222222222222222); + action Data_t test <- mf.deq(0); endaction + mf.enq(0, 128'h00000000000000033333333333333333); + mf.enq(1, 128'h11111111111111111111111111111111); + mf.enq(0, 128'h00000000000000044444444444444444); + action Data_t test <- mf.deq(0); endaction + mf.enq(1, 128'h11111111111111122222222222222222); + action Data_t test <- mf.deq(1); endaction + action Data_t test <- mf.deq(1); endaction + action Data_t test <- mf.deq(1); endaction + + noAction; +// // -- Test Error conditions -- +// mf.enq(9, 128'h00000000000000033333333333333333); +// mf.enq(9, 128'h00000000000000033333333333333333); +// mf.enq(9, 128'h00000000000000033333333333333333); +// mf.enq(9, 128'h00000000000000033333333333333333); +// // Enqueing to full fifo +// mf.enq(9, 128'h00000000000000033333333333333333); +// +// noAction; +// // Dequing from empty fifo +// action Data_t test <- mf.deq(5); endaction +// +// noAction; +// // Enqueing to non-existent fifo +// mf.enq(10, 128'h00000000000000033333333333333333); +// + + noAction; + noAction; + noAction; + noAction; + noAction; + noAction; + noAction; + //while(True) noAction; + endseq; + + mkAutoFSM(test_seq); +endmodule + diff --git a/Network.bsv b/Network.bsv new file mode 100644 index 0000000..918f033 --- /dev/null +++ b/Network.bsv @@ -0,0 +1,145 @@ +/* ========================================================================= + * + * Filename: Network.bsv + * Date created: 04-22-2011 + * Last modified: 11-28-2012 + * Authors: Michael Papamichael + * + * Description: + * Top-level module that instantinates and connects routers to implement + * the entire network. Exposes InPort/OutPort interfaces to hook up the nodes + * that will be connected to the network. + * + * ========================================================================= + */ + +`include "inc.v" + +import Assert::*; +import ConfigReg::*; +import Vector::*; +import BRAMFIFO::*; +import FIFOF::*; +//import Clocks::*; +import NetworkTypes::*; + +//`define USE_IQ_ROUTER BLA +`ifdef IDEAL +import NetworkIdeal::*; +`else + import NetworkGlue::*; + `ifdef USE_IQ_ROUTER + import IQRouter::*; + `else + import Router::*; + `endif +`endif + + +(* synthesize *) +module mkNetwork(Network); +`ifdef IDEAL + let net <- mkNetworkIdeal(); +`else + let net <- mkNetworkReal(); +`endif + return net; +endmodule + + +`ifndef IDEAL + +module mkNetworkReal(Network); + + String name = "Network "; + + // Vector of input and output interfaces to connect network clients + Vector#(NumUserSendPorts, InPort) send_ports_ifaces; + Vector#(NumUserRecvPorts, OutPort) recv_ports_ifaces; + Vector#(NumUserRecvPorts, RecvPortInfo) recv_ports_info_ifaces; + //Vector#(NumRouters, RouterInfo) router_info_ifaces; + + function get_rt( Integer i ); + `ifdef USE_IQ_ROUTER + return mkIQRouter(i); + `else + return mkRouter(i); + `endif + endfunction + + function get_port_info_ifc( Integer id ); + let recv_port_info_ifc = + interface RecvPortInfo + method UserRecvPortID_t getRecvPortID; + return fromInteger(id); + endmethod + endinterface; + return recv_port_info_ifc; + endfunction + +// function get_router_info_ifc( Integer id ); +// let router_info_ifc = +// interface RouterInfo +// method RouterID_t getRouterID; +// //method UserPortID_t getRouterID; +// return fromInteger(id); +// endmethod +// endinterface; +// return router_info_ifc; +// endfunction + + + + + // Declare router and traffic source interfaces + Vector#(NumRouters, Router) routers <- genWithM( get_rt ); + Vector#(NumLinks, ConnectPorts) links; + + ///////////////////////////////////////////////// + // Include the generated "links" file here + ///////////////////////////////////////////////// + // Make connections between routers + `include `NETWORK_LINKS_FILE + + //`include "conf_links.bsv" + //`include "net_configs/n1.txt.links.bsv" + + // TODO: Let gen_network.py create this + // Expose InPort and OutPort interfaces to be used by network clients + for(Integer r = 0; r< valueOf(NumRouters); r=r+1) begin + //send_ports_ifaces[r] = routers[r].in_ports[0]; + //recv_ports_ifaces[r] = routers[r].out_ports[0]; + //router_info_ifaces[r] = routers[r].rt_info; + //user_port_info_ifaces[r] = get_port_info_ifc(r); + //router_info_ifaces[r] = get_router_info_ifc(r); + end + + + // Count link utilization + //Reg#(Bit#(64)) cycle_count <- mkReg(0); + //Vector#(NumLinks, Reg#(Bit#(64))) link_util_counters <- replicatM(mkReg(0)); + /*for(Integer l = 0; l < valueOf(NumLinks); l=l+1) begin + if(links[l].saw_activity()) begin + link_util_counters[l] <= link_util_counters[l] + 1; + end + end*/ + + // rule printLinkUtil(`DUMP_LINK_UTIL); + // //cycle_count <= cycle_count + 1; + // for(Integer l = 0; l < valueOf(NumLinks); l=l+1) begin + // if(links[l].saw_activity()) begin + // $display("strace noc_link:%0d evt:saw_activity", l); + // end + // //link_util_counters[l] <= link_util_counters[l] + 1; + // end + // endrule + + + interface send_ports = send_ports_ifaces; + interface recv_ports = recv_ports_ifaces; + //interface router_info = router_info_ifaces; + interface recv_ports_info = recv_ports_info_ifaces; + +endmodule + +`endif diff --git a/NetworkExternalTypes.bsv b/NetworkExternalTypes.bsv new file mode 100644 index 0000000..5910e6e --- /dev/null +++ b/NetworkExternalTypes.bsv @@ -0,0 +1,119 @@ +/* ========================================================================= + * + * Filename: NetworkExternalTypes.bsv + * Date created: 04-23-2011 + * Last modified: 04-23-2011 + * Authors: Michael Papamichael + * + * Description: + * Types that are exposed for using the network within a bigger system. + * + * ========================================================================= + */ + +import Vector::*; +// Generic include +`include "inc.v" +/////////////////////////////////////////////////////////////////////////////////////////////// +// Set network and router parameters +// include *.conf.bsv file generated by running parse_conf on the network configuration file +/////////////////////////////////////////////////////////////////////////////////////////////// +//`define NETWORK_CONF_FILE "default_conf_parameters.bsv" +//`include `NETWORK_PARAMETERS_FILE +//`include "net_configs/n1.txt.conf.bsv" + +//////////////////////////////////////////////// +// Bluespec router and network types +//typedef `NUM_TOTAL_USER_PORTS NumTotalUserPorts; +typedef `NUM_USER_SEND_PORTS NumUserSendPorts; +typedef `NUM_USER_RECV_PORTS NumUserRecvPorts; +typedef `NUM_ROUTERS NumRouters; +typedef `NUM_IN_PORTS NumInPorts; +typedef `NUM_OUT_PORTS NumOutPorts; +typedef `CREDIT_DELAY CreditDelay; +typedef `NUM_VCS NumVCs; +typedef `NUM_LINKS NumLinks; +typedef `FLIT_DATA_WIDTH FlitDataWidth; +typedef `FLIT_BUFFER_DEPTH FlitBufferDepth; +typedef `NETWORK_CUT NetworkCut; // used by 'ideal' and 'xbar' +typedef `XBAR_LANES XbarLanes; +//typedef `ALLOC_TYPE SelectedAllocator; +//typedef `PIPELINE_ALLOCATOR PipelineAllocator; +//typedef `PIPELINE_LINKS PipelineLinks; + +function Integer getPipeLineStages(); + if(`PIPELINE_CORE && `PIPELINE_LINKS && `PIPELINE_ALLOCATOR) begin // 3 pipe stages + return 3; + end else if((`PIPELINE_CORE && `PIPELINE_LINKS) || (`PIPELINE_CORE && `PIPELINE_ALLOCATOR) || (`PIPELINE_ALLOCATOR && `PIPELINE_LINKS)) begin // 2 pipe stages + return 2; + //typedef 2 NumPipelineStages; + end else if (`PIPELINE_CORE || `PIPELINE_LINKS || `PIPELINE_ALLOCATOR) begin // 1 pipe stage + return 1; + //typedef 1 NumPipelineStages; + end else begin // no pipelining + //typedef 0 NumPipelineStages; + return 0; + end +endfunction + +// Derived parameters +//typedef Bit#(TLog#(NumTotalUserPorts)) UserPortID_t; +typedef Bit#(TLog#(NumUserSendPorts)) UserSendPortID_t; +typedef Bit#(TLog#(NumUserRecvPorts)) UserRecvPortID_t; +typedef Bit#(TLog#(NumRouters)) RouterID_t; +typedef Bit#(TLog#(TMax#(NumVCs, 2))) VC_t; // I want this to be at least 1 bit +typedef Bit#(FlitDataWidth) FlitData_t; + + +////////////////////////////////////////////////////// +// Flit and Credit Types +typedef struct{ + //Bool is_head; // turns out this was not needed + //Bool prio; // priority packet + Bool is_tail; // only required for multi-flit packets + //RouterID_t dst; + UserRecvPortID_t dst; + //OutPort_t out_p; // only for debugging + VC_t vc; + FlitData_t data; // payload of flit +} Flit_t + deriving(Bits, Eq); + +typedef Maybe#(VC_t) Credit_t; // credits carry VC to which they belong +typedef Vector#(NumVCs, Bool) CreditSimple_t; // bitmask indicating available VCs + +//////////////////////////////////////////////// +// InPort and OutPort interfaces +// - Uses credits +// Implemented by routers and traffic sources +//////////////////////////////////////////////// +interface InPort; + (* always_ready *) method Action putFlit(Maybe#(Flit_t) flit_in); + (* always_ready *) method ActionValue#(Credit_t) getCredits; +endinterface + +interface OutPort; + (* always_ready *) method ActionValue#(Maybe#(Flit_t)) getFlit(); + (* always_ready *) method Action putCredits(Credit_t cr_in); +endinterface + +//////////////////////////////////////////////// +// Simpler InPort and OutPort interfaces +// - Routers only exchange notFull signals, instead of credits +// Implemented by routers and traffic sources +//////////////////////////////////////////////// +interface InPortSimple; + (* always_ready *) method Action putFlit(Maybe#(Flit_t) flit_in); + (* always_ready *) method ActionValue#(Vector#(NumVCs, Bool)) getNonFullVCs; +endinterface + +interface OutPortSimple; + (* always_ready *) method ActionValue#(Maybe#(Flit_t)) getFlit(); + (* always_ready *) method Action putNonFullVCs(Vector#(NumVCs, Bool) nonFullVCs); +endinterface + +// Used by clients to obtain response address +interface RecvPortInfo; + //(* always_ready *) method RouterID_t getRouterID; + (* always_ready *) method UserRecvPortID_t getRecvPortID; +endinterface diff --git a/NetworkGlue.bsv b/NetworkGlue.bsv new file mode 100644 index 0000000..ed53846 --- /dev/null +++ b/NetworkGlue.bsv @@ -0,0 +1,146 @@ +/* ========================================================================= + * + * Filename: NetworkGlue.bsv + * Date created: 04-23-2011 + * Last modified: 04-23-2011 + * Authors: Michael Papamichael + * + * Description: + * Module to connect routers with other routers. + * + * ========================================================================= + */ + +import NetworkTypes::*; +import Router::*; +`include "inc.v" + +//////////////////////////////////////////////////////////////////////// +// ConnectPorts Interface +// Interface is only used to check activity for termination condition +//////////////////////////////////////////////////////////////////////// +interface ConnectPorts; + method Bool saw_activity(); +endinterface + +module mkConnectPorts#(Router r_out, Integer port_out, Router r_in, Integer port_in)(ConnectPorts); + ConnectPorts connectPorts_ifc; + if (`PIPELINE_LINKS) begin + connectPorts_ifc <- mkConnectPorts_wReg(r_out, port_out, r_in, port_in); + end else begin + connectPorts_ifc <- mkConnectPorts_noReg(r_out, port_out, r_in, port_in); + end + return connectPorts_ifc; +endmodule + + +module mkConnectPorts_noReg#(Router r_out, Integer port_out, Router r_in, Integer port_in)(ConnectPorts); + + PulseWire flits_activity <- mkPulseWire(); + PulseWire credits_activity <- mkPulseWireOR(); + + + (* fire_when_enabled *) + rule makeFlitLink(True); + let out_port_ifc = r_out.out_ports[port_out]; + let in_port_ifc = r_in.in_ports[port_in]; + let fl <- out_port_ifc.getFlit(); + in_port_ifc.putFlit(fl); // _ifc.put(r0_ifc.get); + if(isValid(fl)) begin + flits_activity.send(); + end + endrule + + (* fire_when_enabled *) + rule makeCreditLink(True); + let out_port_ifc = r_out.out_ports[port_out]; + let in_port_ifc = r_in.in_ports[port_in]; + let cr <- in_port_ifc.getCredits(); + out_port_ifc.putCredits(cr); + if(isValid(cr)) begin + credits_activity.send(); + end + endrule + + method Bool saw_activity(); + //return (flits_activity || credits_activity); + return (flits_activity); + endmethod +endmodule + + +// Only offers very minor frequency improvement +module mkConnectPorts_wReg#(Router r_out, Integer port_out, Router r_in, Integer port_in)(ConnectPorts); + + PulseWire flits_activity <- mkPulseWire(); + PulseWire credits_activity <- mkPulseWireOR(); + + Reg#(Credit_t) credit_reg <- mkReg(Invalid); + Reg#(Maybe#(Flit_t)) fl_reg <- mkReg(Invalid); + + + (* fire_when_enabled *) + rule makeFlitLink(True); + let out_port_ifc = r_out.out_ports[port_out]; + let in_port_ifc = r_in.in_ports[port_in]; + let fl <- out_port_ifc.getFlit(); + fl_reg <= fl; + in_port_ifc.putFlit(fl_reg); // _ifc.put(r0_ifc.get); + if(isValid(fl)) begin + flits_activity.send(); + end + endrule + + (* fire_when_enabled *) + rule makeCreditLink(True); + let out_port_ifc = r_out.out_ports[port_out]; + let in_port_ifc = r_in.in_ports[port_in]; + let cr <- in_port_ifc.getCredits(); + credit_reg <= cr; + out_port_ifc.putCredits(credit_reg); + if(isValid(cr)) begin + credits_activity.send(); + end + endrule + + method Bool saw_activity(); + //return (flits_activity || credits_activity); + return (flits_activity); + endmethod +endmodule + + + + +//////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////// +// Older Code +///////////////////////////////////////////////////// + + +//module connectPortsOld#(MCRouter r_out, Integer port_out, MCRouter r_in, Integer port_in)(Empty); +// +// (* fire_when_enabled *) +// rule makeFlitLink(True); +// let out_port_ifc = r_out.out_ports[port_out]; +// let in_port_ifc = r_in.in_ports[port_in]; +// let fl <- out_port_ifc.getFlit(); +// in_port_ifc.putFlit(fl); // _ifc.put(r0_ifc.get); +// endrule +// +// (* fire_when_enabled *) +// rule makeCreditLink(True); +// let out_port_ifc = r_out.out_ports[port_out]; +// let in_port_ifc = r_in.in_ports[port_in]; +// let cr <- in_port_ifc.getCredits(); +// out_port_ifc.putCredits(cr); +// //if (isValid(cr)) begin +// // `DBG_REF(("--------> Credits from in_port %0d to out_port %0d for vc %0d", port_in, port_out, cr.Valid)); +// //end +// //in_port_ifc.putFlit(out_port_ifc.getFlit()); // _ifc.put(r0_ifc.get); +// endrule +// +//endmodule + diff --git a/NetworkGlueSimple.bsv b/NetworkGlueSimple.bsv new file mode 100644 index 0000000..0f1e900 --- /dev/null +++ b/NetworkGlueSimple.bsv @@ -0,0 +1,145 @@ +/* ========================================================================= + * + * Filename: NetworkGlueSimple.bsv + * Date created: 09-18-2011 + * Last modified: 09-18-2011 + * Authors: Michael Papamichael + * + * Description: + * Module to connect routers with other routers. + * + * ========================================================================= + */ + +`include "inc.v" +import NetworkTypes::*; +//import RouterSimple::*; +import Vector::*; + +`ifdef USE_VOQ_ROUTER + import VOQRouterSimple::*; +`elsif USE_IQ_ROUTER + import IQRouterSimple::*; +`else + import RouterSimple::*; +`endif + + +//////////////////////////////////////////////////////////////////////// +// ConnectPorts Interface +// Interface is only used to check activity for termination condition +//////////////////////////////////////////////////////////////////////// +interface ConnectPorts; + method Bool saw_activity(); +endinterface + +module mkConnectPorts#(RouterSimple r_out, Integer port_out, RouterSimple r_in, Integer port_in)(ConnectPorts); + ConnectPorts connectPorts_ifc; + if (`PIPELINE_LINKS) begin + connectPorts_ifc <- mkConnectPorts_wReg(r_out, port_out, r_in, port_in); + end else begin + connectPorts_ifc <- mkConnectPorts_noReg(r_out, port_out, r_in, port_in); + end + return connectPorts_ifc; +endmodule + + +module mkConnectPorts_noReg#(RouterSimple r_out, Integer port_out, RouterSimple r_in, Integer port_in)(ConnectPorts); + + PulseWire flits_activity <- mkPulseWire(); + PulseWire credits_activity <- mkPulseWireOR(); + + + (* fire_when_enabled *) + rule makeFlitLink(True); + let out_port_ifc = r_out.out_ports[port_out]; + let in_port_ifc = r_in.in_ports[port_in]; + let fl <- out_port_ifc.getFlit(); + in_port_ifc.putFlit(fl); // _ifc.put(r0_ifc.get); + if(isValid(fl)) begin + flits_activity.send(); + end + endrule + + (* fire_when_enabled *) + rule makeCreditLink(True); + let out_port_ifc = r_out.out_ports[port_out]; + let in_port_ifc = r_in.in_ports[port_in]; + let cr <- in_port_ifc.getNonFullVCs(); + out_port_ifc.putNonFullVCs(cr); + endrule + + method Bool saw_activity(); + return (flits_activity); + endmethod +endmodule + + +// Only offers very minor frequency improvement +module mkConnectPorts_wReg#(RouterSimple r_out, Integer port_out, RouterSimple r_in, Integer port_in)(ConnectPorts); + + PulseWire flits_activity <- mkPulseWire(); + PulseWire credits_activity <- mkPulseWireOR(); + + Reg#(Vector#(NumVCs, Bool)) credit_reg <- mkReg(unpack(0)); + Reg#(Maybe#(Flit_t)) fl_reg <- mkReg(Invalid); + + + (* fire_when_enabled *) + rule makeFlitLink(True); + let out_port_ifc = r_out.out_ports[port_out]; + let in_port_ifc = r_in.in_ports[port_in]; + let fl <- out_port_ifc.getFlit(); + fl_reg <= fl; + in_port_ifc.putFlit(fl_reg); // _ifc.put(r0_ifc.get); + if(isValid(fl)) begin + flits_activity.send(); + end + endrule + + (* fire_when_enabled *) + rule makeCreditLink(True); + let out_port_ifc = r_out.out_ports[port_out]; + let in_port_ifc = r_in.in_ports[port_in]; + let cr <- in_port_ifc.getNonFullVCs(); + credit_reg <= cr; + out_port_ifc.putNonFullVCs(credit_reg); + endrule + + method Bool saw_activity(); + return (flits_activity); + endmethod +endmodule + +//////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////// +// Older Code +///////////////////////////////////////////////////// + + +//module connectPortsOld#(MCRouter r_out, Integer port_out, MCRouter r_in, Integer port_in)(Empty); +// +// (* fire_when_enabled *) +// rule makeFlitLink(True); +// let out_port_ifc = r_out.out_ports[port_out]; +// let in_port_ifc = r_in.in_ports[port_in]; +// let fl <- out_port_ifc.getFlit(); +// in_port_ifc.putFlit(fl); // _ifc.put(r0_ifc.get); +// endrule +// +// (* fire_when_enabled *) +// rule makeCreditLink(True); +// let out_port_ifc = r_out.out_ports[port_out]; +// let in_port_ifc = r_in.in_ports[port_in]; +// let cr <- in_port_ifc.getCredits(); +// out_port_ifc.putCredits(cr); +// //if (isValid(cr)) begin +// // `DBG_REF(("--------> Credits from in_port %0d to out_port %0d for vc %0d", port_in, port_out, cr.Valid)); +// //end +// //in_port_ifc.putFlit(out_port_ifc.getFlit()); // _ifc.put(r0_ifc.get); +// endrule +// +//endmodule + diff --git a/NetworkIdeal.bsv b/NetworkIdeal.bsv new file mode 100644 index 0000000..b1f088e --- /dev/null +++ b/NetworkIdeal.bsv @@ -0,0 +1,139 @@ +import Assert::*; +import ConfigReg::*; +import Vector::*; +import Count::*; +import FIFOF::*; +import PipelineFIFO::*; +import FIFOLevel::*; +import LUTFIFO::*; +import BRAMFIFO::*; +import Arbiters::*; +import GetPut::*; +import FIFOCountDeqBus::*; + + +`include "inc.v" + +import NetworkTypes::*; +import NetworkExternalTypes::*; + + +/* +module mkNetworkIdeal(Network); + + // Convention of outQs + // outQs [ output port ][ input port ] + + Vector#(NumRouters, Vector#(NumRouters, FIFOCountIfc#(Flit_t, FlitBufferDepth))) outQs; + Vector#(NumRouters, Count#(Bit#(TLog#(TAdd#(FlitBufferDepth,1))),1)) out_credits; + Vector#(NumRouters, Vector#(NumRouters, PulseWire)) send_credits; + Vector#(NumRouters, Reg#(Credit_t)) vc_type <- replicateM(mkReg(Invalid)); + Vector#(NumRouters, Arbiter#(NumRouters)) arbs <- replicateM(mkNetworkIdealArbiter); + + for(Integer i=0; i < valueOf(NumRouters); i=i+1) begin + Vector#(NumRouters, FIFOCountIfc#(Flit_t, FlitBufferDepth)) slice; + if(i < valueOf(NetworkCut)) begin + for(Integer k=0; k < valueOf(NumRouters); k=k+1) + slice[k] <- (k >= valueOf(NetworkCut)) ? mkNetworkIdealQueue : mkNetworkDummyQueue; + end + else begin + for(Integer k=0; k < valueOf(NumRouters); k=k+1) + slice[k] <- (k < valueOf(NetworkCut)) ? mkNetworkIdealQueue : mkNetworkDummyQueue; + end + outQs[i] = slice; + + out_credits[i] <- mkNetworkIdealCounter; + send_credits[i] <- replicateM(mkPulseWire); + end + + Vector#(NumRouters, InPort) send_ifaces; + Vector#(NumRouters, OutPort) recv_ifaces; + Vector#(NumRouters, RouterInfo) rt_ifaces; + + // Input Requests + + for(Integer i=0; i < valueOf(NumRouters); i=i+1) begin + let ifc = interface InPort + method Action putFlit(Maybe#(Flit_t) flit_in); + if(flit_in matches tagged Valid .flit) begin + let dst = flit.dst; + $display("[network] input port %0d -> output Q %0d", i, dst); + outQs[dst][i].enq(flit); + if(!isValid(vc_type[i])) + vc_type[i] <= Valid(flit.vc); + else dynamicAssert(flit.vc == validValue(vc_type[i]), "vc should be same coming in from same port"); + end + endmethod + method ActionValue#(Credit_t) getCredits; + Bool send = False; + for(Integer k=0; k < valueOf(NumRouters); k=k+1) begin + if(send_credits[k][i]) send = True; + end + if(send) begin + dynamicAssert(isValid(vc_type[i]), "error didnn't learn VC type yet..."); + return vc_type[i]; + end + else begin + return Invalid; + end + endmethod + endinterface; + send_ifaces[i] = ifc; + end + + // From outQs to output + + for(Integer i=0; i < valueOf(NumRouters); i=i+1) begin + + let ifc = interface OutPort + + method ActionValue#(Maybe#(Flit_t)) getFlit(); + actionvalue + Maybe#(Flit_t) flitOut = Invalid; + if(out_credits[i].value != 0) begin + Vector#(NumRouters, Bool) raises = unpack(0); + Maybe#(Bit#(TLog#(NumRouters))) msel = Invalid; + + for(Integer k=0; k < valueOf(NumRouters); k=k+1) begin + raises[k] = outQs[i][k].notEmpty; + end + + msel = mkNetworkIdealEncoder(arbs[i].select(raises)); + + if(msel matches tagged Valid .sel) begin + flitOut = Valid(outQs[i][sel].first); + outQs[i][sel].deq(); + out_credits[i].sub(1); + send_credits[i][sel].send(); + end + + end + return flitOut; + endactionvalue + endmethod + + method Action putCredits(Credit_t cr_in); + if(isValid(cr_in)) out_credits[i].add(1); + endmethod + + endinterface; + + recv_ifaces[i] = ifc; + end + + for(Integer i=0; i < valueOf(NumRouters); i=i+1) begin + let ifc = interface RouterInfo + method RouterID_t getRouterID(); + return fromInteger(i); + endmethod + endinterface; + + rt_ifaces[i] = ifc; + end + + interface send_ports = send_ifaces; + interface recv_ports = recv_ifaces; + interface router_info = rt_ifaces; + +endmodule +*/ diff --git a/NetworkSimple.bsv b/NetworkSimple.bsv new file mode 100644 index 0000000..02d8878 --- /dev/null +++ b/NetworkSimple.bsv @@ -0,0 +1,139 @@ +/* ========================================================================= + * + * Filename: NetworkSimple.bsv + * Date created: 09-19-2011 + * Last modified: 09-19-2011 + * Authors: Michael Papamichael + * + * Description: + * Top-level module that instantinates and connects routers to implement + * the entire network. Exposes InPort/OutPort interfaces to hook up the nodes + * that are will be connected to the network. + * + * ========================================================================= + */ + +`include "inc.v" + +import Assert::*; +import ConfigReg::*; +import Vector::*; +import BRAMFIFO::*; +import FIFOF::*; +//import Clocks::*; +import NetworkTypes::*; + +`ifdef IDEAL + import NetworkIdeal::*; +`else + import NetworkGlueSimple::*; + `ifdef USE_VOQ_ROUTER + import VOQRouterSimple::*; + `elsif USE_IQ_ROUTER + import IQRouterSimple::*; + `else + import RouterSimple::*; + `endif +`endif + + +(* synthesize *) +module mkNetworkSimple(NetworkSimple); +`ifdef IDEAL + let net <- mkNetworkIdealSimple(); +`else + let net <- mkNetworkRealSimple(); +`endif + return net; +endmodule + + +`ifndef IDEAL + +module mkNetworkRealSimple(NetworkSimple); + + String name = "Simple Network"; + + // Vector of input and output interfaces to connect network clients + Vector#(NumUserSendPorts, InPortSimple) send_ports_ifaces; + Vector#(NumUserRecvPorts, OutPortSimple) recv_ports_ifaces; + Vector#(NumUserRecvPorts, RecvPortInfo) recv_ports_info_ifaces; + //Vector#(NumRouters, RouterInfo) router_info_ifaces; + + function get_rt( Integer i ); + `ifdef USE_VOQ_ROUTER + return mkVOQRouterSimple(i); + `elsif USE_IQ_ROUTER + return mkIQRouterSimple(i); + `else + return mkRouterSimple(i); + `endif + endfunction + + function get_port_info_ifc( Integer id ); + let recv_port_info_ifc = + interface RecvPortInfo + method UserRecvPortID_t getRecvPortID; + return fromInteger(id); + endmethod + endinterface; + return recv_port_info_ifc; + endfunction + +// function get_router_info_ifc( Integer id ); +// let router_info_ifc = +// interface RouterInfo +// method RouterID_t getRouterID; +// //method UserPortID_t getRouterID; +// return fromInteger(id); +// endmethod +// endinterface; +// return router_info_ifc; +// endfunction + + + + // Declare router and traffic source interfaces + Vector#(NumRouters, RouterSimple) routers <- genWithM( get_rt ); + //Vector#(NumRouters, RouterSimple) routers; + Vector#(NumLinks, ConnectPorts) links; + + ///////////////////////////////////////////////// + // Include the generated "links" file here + ///////////////////////////////////////////////// + // Make connections between routers + `include `NETWORK_LINKS_FILE + + //`include "conf_links.bsv" + //`include "net_configs/n1.txt.links.bsv" + + // TODO: Let gen_network.py create this + // Expose InPort and OutPort interfaces to be used by network clients + for(Integer r = 0; r< valueOf(NumRouters); r=r+1) begin + //send_ports_ifaces[r] = routers[r].in_ports[0]; + //recv_ports_ifaces[r] = routers[r].out_ports[0]; + //router_info_ifaces[r] = routers[r].rt_info; + //user_port_info_ifaces[r] = get_port_info_ifc(r); + //router_info_ifaces[r] = get_router_info_ifc(r); + end + +// if(NumLinks > 0) begin +// rule printLinkUtil(`DUMP_LINK_UTIL); +// //cycle_count <= cycle_count + 1; +// for(Integer l = 0; l < valueOf(NumLinks); l=l+1) begin +// if(links[l].saw_activity()) begin +// $display("strace noc_link:%0d evt:saw_activity", l); +// end +// //link_util_counters[l] <= link_util_counters[l] + 1; +// end +// endrule +// end + + interface send_ports = send_ports_ifaces; + interface recv_ports = recv_ports_ifaces; + //interface router_info = router_info_ifaces; + interface recv_ports_info = recv_ports_info_ifaces; + +endmodule + +`endif diff --git a/NetworkSimpleTb.bsv b/NetworkSimpleTb.bsv new file mode 100644 index 0000000..f4766e4 --- /dev/null +++ b/NetworkSimpleTb.bsv @@ -0,0 +1,175 @@ +/* ========================================================================= + * + * Filename: NetworkSimpleTb.bsv + * Date created: 09-19-2012 + * Last modified: 09-22-2012 + * Authors: Michael Papamichael + * + * Description: + * Simple testbench for NetworkSimple. + * + * ========================================================================= + */ + +`include "inc.v" + +import Assert::*; +import ConfigReg::*; +import Vector::*; +import BRAMFIFO::*; +import FIFOF::*; +//import Clocks::*; +import NetworkTypes::*; + +//`ifdef USE_VOQ_ROUTER +// import VOQRouterSimple::*; +//`else +// import RouterSimple::*; +//`endif + +import NetworkGlueSimple::*; +import NetworkSimple::*; +import StmtFSM::*; // just for creating a test sequence +import FShow::*; + + +module mkNetworkSimpleTb(Empty); + String name = "NetworkSimpleTb "; + // instantiate network + NetworkSimple net <- mkNetworkSimple(); + + Reg#(Bit#(32)) cycle <- mkConfigReg(0); + + (* no_implicit_conditions *) + rule cycle_count(True); + $display("[cycle %08d] ----------------------------------------------- ", cycle); + //for(Integer r=0; r < valueOf(NumRouters); r=r+1) begin + // $write(" %0d", credits[r][0]); + //end + //$write("\n"); + cycle <= cycle + 1; + endrule + + // + (* fire_when_enabled *) + //rule printstats (cycle == fromInteger(valueOf(NumCyclesToTest))); + rule printstats (True); + Bit#(64) total_delay = unpack(0); + Bit#(64) total_pkt_cnt = unpack(0); + for(Integer r=0; r < valueOf(NumUserRecvPorts); r=r+1) begin + let fl <- net.recv_ports[r].getFlit(); + if(isValid(fl)) begin + $display("RecvPort:",r," Incoming Flit:",fshow(fl.Valid)); + end + + // don't provide credits to test backpressure! + //net.recv_ports[r].putNonFullVCs(unpack(0)); + + //$display("router %0d delay_sum %0d pkt_cnt %0d", r, delay_sum[r], pkt_cnt[r]); + //total_delay = total_delay + extend(delay_sum[r]); + //total_pkt_cnt = total_pkt_cnt + extend(pkt_cnt[r]); + end + + for(Integer s=0; s < valueOf(NumUserSendPorts); s=s+1) begin + let nonFullVCs <- net.send_ports[s].getNonFullVCs(); + if(!nonFullVCs[0]) begin // some port is full + $display("SendPort:",s," input buffer full!"); + end + + //$display("router %0d delay_sum %0d pkt_cnt %0d", r, delay_sum[r], pkt_cnt[r]); + //total_delay = total_delay + extend(delay_sum[r]); + //total_pkt_cnt = total_pkt_cnt + extend(pkt_cnt[r]); + end + + //$display("total_delay_sum %0d total_pkt_cnt %0d", total_delay, total_pkt_cnt); + endrule + + + + function Action sendFlit(UserSendPortID_t src, UserRecvPortID_t dst, Bool is_tail, VC_t vc, FlitData_t data); + action + Maybe#(Flit_t) fl = tagged Valid Flit_t{is_tail:is_tail, dst:dst, vc:vc, data:data}; + $display("SendPort ",src," is sending Flit: ",fshow(fl)); + net.send_ports[src].putFlit(fl); + + // Don't provide credits + //for(Integer r=0; r < valueOf(NumUserRecvPorts); r=r+1) begin + // net.recv_ports[r].putNonFullVCs(unpack(0)); + //end + + endaction + endfunction + + function Action noCredits(); + action + for(Integer r=0; r < valueOf(NumUserRecvPorts); r=r+1) begin + net.recv_ports[r].putNonFullVCs(unpack(0)); + end + endaction + endfunction + + rule provideCredits(True); + // provide credits + for(Integer r=0; r < valueOf(NumUserRecvPorts); r=r+1) begin + net.recv_ports[r].putNonFullVCs(unpack(1)); + end + endrule + + Stmt fsm = seq + action + //sendFlit(0,0,True,0,00000000); + //sendFlit(1,1,True,0,11000000); + //noCredits(); + //sendFlit(2,2,True,0,22000000); + //sendFlit(3,3,True,0,33000000); + //net.send_ports[0].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd0), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[1].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[2].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd2), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[3].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd3), vc:truncate(64'd0), data:unpack(0)} ); + $display("Pipeline Stages: %d", getPipeLineStages()); + endaction + action + sendFlit(0,1,True,0,01000000); + //sendFlit(2,9,True,0,29000000); + //net.send_ports[0].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[1].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[2].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[3].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + endaction + action + sendFlit(0,1,True,0,01000001); + //net.send_ports[0].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[1].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[2].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[3].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + endaction + action + sendFlit(0,1,True,0,01000002); + //net.send_ports[0].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[1].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[2].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[3].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + endaction + sendFlit(0,1,True,0,01000003); + sendFlit(0,1,True,0,01000004); + sendFlit(0,1,True,0,01000005); + sendFlit(0,1,True,0,01000006); + sendFlit(0,1,True,0,01000007); + //sendFlit(0,1,True,0,01000008); + //sendFlit(0,1,True,0,0); + //sendFlit(0,1,True,0,0); + //sendFlit(0,1,True,0,0); + //sendFlit(0,1,True,0,0); + //sendFlit(0,1,True,0,0); + repeat (50) + action + noAction; + endaction + noAction; + noAction; + + endseq; + + mkAutoFSM(fsm); + +endmodule diff --git a/NetworkTb.bsv b/NetworkTb.bsv new file mode 100644 index 0000000..b88aed2 --- /dev/null +++ b/NetworkTb.bsv @@ -0,0 +1,159 @@ +/* ========================================================================= + * + * Filename: NetworkTb.bsv + * Date created: 09-21-2012 + * Last modified: 09-21-2012 + * Authors: Michael Papamichael + * + * Description: + * Simple testbench for Network. + * + * ========================================================================= + */ + +import Assert::*; +import ConfigReg::*; +import Vector::*; +import BRAMFIFO::*; +import FIFOF::*; +//import Clocks::*; +import NetworkTypes::*; + +import Router::*; +import NetworkGlueSimple::*; +import Network::*; +import StmtFSM::*; // just for creating a test sequence +import FShow::*; + +`include "inc.v" + +module mkNetworkTb(Empty); + String name = "NetworkSimpleTb"; + // instantiate network + Network net <- mkNetwork(); + + Reg#(Bit#(32)) cycles <- mkConfigReg(0); + + (* no_implicit_conditions *) + rule cycle_count(True); + $display("[cycle %08d] ----------------------------------------------- ", cycles); + //for(Integer r=0; r < valueOf(NumRouters); r=r+1) begin + // $write(" %0d", credits[r][0]); + //end + //$write("\n"); + cycles <= cycles + 1; + endrule + + // + (* fire_when_enabled *) + //rule printstats (cycle == fromInteger(valueOf(NumCyclesToTest))); + rule printstats (True); + Bit#(64) total_delay = unpack(0); + Bit#(64) total_pkt_cnt = unpack(0); + for(Integer r=0; r < valueOf(NumUserRecvPorts); r=r+1) begin + let fl <- net.recv_ports[r].getFlit(); + if(isValid(fl)) begin + //$display("RecvPort:",r," Incoming Flit:",fshow(fl.Valid)); +// let tmp = $format("RecvPort:",r," Incoming Flit:",fshow(fl.Valid)); +// `DISP_CYCLES((tmp)); + `DISP_CYCLES(( $format("RecvPort:",r," Incoming Flit:",fshow(fl.Valid)) )); + //$display("RecvPort:",r," Incoming Flit:",fshow(fl.Valid)); + end + + // don't provide credits to test backpressure! + //net.recv_ports[r].putNonFullVCs(unpack(0)); + + //$display("router %0d delay_sum %0d pkt_cnt %0d", r, delay_sum[r], pkt_cnt[r]); + //total_delay = total_delay + extend(delay_sum[r]); + //total_pkt_cnt = total_pkt_cnt + extend(pkt_cnt[r]); + end + + // for(Integer s=0; s < valueOf(NumUserSendPorts); s=s+1) begin + // let nonFullVCs <- net.send_ports[s].getNonFullVCs(); + // if(!nonFullVCs[0]) begin // some port is full + // $display("SendPort:",s," input buffer full!"); + // end + + // //$display("router %0d delay_sum %0d pkt_cnt %0d", r, delay_sum[r], pkt_cnt[r]); + // //total_delay = total_delay + extend(delay_sum[r]); + // //total_pkt_cnt = total_pkt_cnt + extend(pkt_cnt[r]); + // end + + //$display("total_delay_sum %0d total_pkt_cnt %0d", total_delay, total_pkt_cnt); + endrule + + + function Action sendFlit(UserSendPortID_t src, UserRecvPortID_t dst, Bool is_tail, VC_t vc, FlitData_t data); + action + Maybe#(Flit_t) fl = tagged Valid Flit_t{is_tail:is_tail, dst:dst, vc:vc, data:data}; + //let tmp = $format("SendPort ",src," is sending Flit: ",fshow(fl)); + //`DISP_CYCLES((tmp)); + `DISP_CYCLES(( "SendPort ",src," is sending Flit: ",fshow(fl) )); + net.send_ports[src].putFlit(fl); + endaction + endfunction + + Stmt fsm = seq + action + sendFlit(0,0,True,0,'h00000000); + sendFlit(1,1,True,0,'h11000000); + sendFlit(2,2,True,0,'h22000000); + sendFlit(3,3,True,0,'h33000000); + //net.send_ports[0].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd0), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[1].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[2].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd2), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[3].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd3), vc:truncate(64'd0), data:unpack(0)} ); + endaction + action + sendFlit(0,1,True,0,'h01000000); + sendFlit(2,9,True,0,'h29000000); + //net.send_ports[0].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[1].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[2].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[3].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + endaction + action + sendFlit(0,1,True,0,'h01000001); + //net.send_ports[0].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[1].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[2].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[3].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + endaction + action + sendFlit(0,1,True,0,'h01000002); + //net.send_ports[0].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[1].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[2].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + //net.send_ports[3].putFlit( tagged Valid Flit_t{is_tail:True, dst:truncate(64'd1), vc:truncate(64'd0), data:unpack(0)} ); + endaction + + sendFlit(0,1,True,0,'h01000003); + sendFlit(0,1,True,0,'h01000004); + sendFlit(0,1,True,0,'h01000005); + sendFlit(0,1,True,0,'h01000006); + sendFlit(0,1,True,0,'h01000007); + sendFlit(0,1,True,0,'h01000008); + sendFlit(0,1,True,0,'h01000009); + sendFlit(0,1,True,0,'h01000010); + sendFlit(0,1,True,0,'h01000011); + sendFlit(0,1,True,0,'h01000012); + sendFlit(0,1,True,0,'h01000013); + sendFlit(0,1,True,0,'h01000014); + sendFlit(0,1,True,0,'h01000015); + //sendFlit(0,1,True,0,0); + //sendFlit(0,1,True,0,0); + //sendFlit(0,1,True,0,0); + //sendFlit(0,1,True,0,0); + //sendFlit(0,1,True,0,0); + repeat (50) + action + noAction; + endaction + noAction; + noAction; + + endseq; + + mkAutoFSM(fsm); + +endmodule diff --git a/NetworkTestHarness.bsv b/NetworkTestHarness.bsv new file mode 100644 index 0000000..53c90b3 --- /dev/null +++ b/NetworkTestHarness.bsv @@ -0,0 +1,270 @@ +/* ========================================================================= + * + * Filename: NetworkTestHarness.bsv + * Date created: 09-08-2011 + * Last modified: 09-16-2011 + * Authors: Michael Papamichael + * + * Description: + * Router test harness. Feeds traffic to network. + * + * ========================================================================= + */ + +import Assert::*; +import ConfigReg::*; +import Vector::*; +import BRAMFIFO::*; +import FIFOF::*; +//import Clocks::*; +import NetworkTypes::*; +import Network::*; +import RegFile::*; +import StmtFSM::*; // just for creating a test sequence + +`include "inc.v" + +//`define NPKTS 10 +//`define NFLITS 100000 +`define NCYCLES 1100000 +`define NWARMUP 100000 +`define TRACE_FILE_PREFIX "traffic" + +//typedef `NPKTS NumPktsToTest; +//typedef `NFLITS NumFlitsToTest; +typedef `NCYCLES NumCyclesToTest; +typedef `NWARMUP NumCyclesToWarm; +typedef NumCyclesToTest NumFlitsToTest; + +typedef Bit#(32) TimeStamp_t; // time-stamp + +interface NetworkTestHarness; + +endinterface + +typedef struct { + Bool is_head; // indicates head flit + Bool is_tail; // indicates tail flit - these flits are used to measure delay + Bit#(8) src; // Packet Source. (will be truncated to match RouterID_t) + Bit#(8) dst; // Packet Destination. (will be truncated to match RouterID_t) + Bit#(4) vc; // VC to use. (will be truncated to match VC_t) + TimeStamp_t ts; // Injection Time-stamp. (32-bits) + //Bit#(8) num_flits; // Number of flits in packet. (will be truncated to match FlitID_t) +} TraceEntry_t +deriving (Bits, Eq); + +//module mkTrafficDrivers#(Integer id)(Empty); +module mkNetworkTestHarness(Empty); + String name = "NetworkTestHarness"; + + // instantiate network + Network net <- mkNetwork(); + + Vector#(NumUserRecvPorts, Reg#( Bit#(64) )) pkt_cnt <- replicateM(mkConfigReg(0)); + Vector#(NumUserRecvPorts, Reg#( Bit#(64) )) delay_sum <- replicateM(mkConfigReg(0)); + + // credits + Vector#(NumUserSendPorts, Vector#(NumVCs, Reg#(Bit#(TLog#(TAdd#(FlitBufferDepth,1)))))) credits; + //Vector#(NumRouters, Vector#(NumVCs, Reg#(Bool) )) credits <- replicateM(mkReg(True)); // start with credits for all VCs. + Vector#(NumUserSendPorts, Vector#(NumVCs, Wire#(Bool))) credits_set; // <- replicateM(mkDWire(False)); + Vector#(NumUserSendPorts, Vector#(NumVCs, Wire#(Bool))) credits_clear; // <- replicateM(mkDWire(False)); + //Wire#(Bool) reset_stats <- mkDWire(False); + + for(Integer r = 0; r< valueOf(NumUserSendPorts); r=r+1) begin + credits[r] <- replicateM(mkConfigReg(fromInteger(valueOf(FlitBufferDepth)))); // start with credits for all ouputs/VCs + credits_set[r] <- replicateM(mkDWire(False)); + credits_clear[r] <- replicateM(mkDWire(False)); + end + + // Rule to update credits. Credits get replenished from out_ports and are spent when sending flits. + (* no_implicit_conditions *) + rule update_credits (True); // turn off credits for debugging + for(Integer r=0; r fromInteger(valueof(FlitBufferDepth))) begin + `DBG(("Credit overflow at router %0d VC %0d", r, v)); + end + end else if (!credits_set[r][v] && credits_clear[r][v]) begin // I only spent a credit + //credits[o][v] <= False; + credits[r][v] <= credits[r][v] - 1; + if(credits[r][v] == 0) begin + `DBG(("Credit underflow at router %0d VC %0d", r, v)); + end + end + end + end + //`DBG_DETAIL_ID(("credits:%b", readVReg(concat(credits)) )); // flatten the array to print + endrule + + function get_trace( Integer id ); + String traffic_file = strConcat( strConcat(`TRACE_FILE_PREFIX, integerToString(id)), ".rom"); + //$display("Loading router %d trace from %s", id, traffic_file); + return mkRegFileFullLoad(traffic_file); + //RegFile#(Bit#(TLog#(NumPktsToTest)), TraceEntry_t) traffic <- mkRegFileFullLoad(traffic_file); + //return traffic; + endfunction + + Vector#(NumUserSendPorts, RegFile#(Bit#(TLog#(NumFlitsToTest)), TraceEntry_t) ) traces <- genWithM( get_trace ); + Vector#(NumUserSendPorts, Reg#(Bit#(64)) ) cur_trace <- replicateM(mkConfigReg(0)); + + //for(i<=0; i < fromInteger(valueOf(NumFlitsToTest)); i<=i+1) seq + // String traffic_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(id)), ".rom"); + // RegFile#(Bit#(TLog#(NumPktsToTest)), TraceEntry_t) traffic <- mkRegFileFullLoad(traffic_file); + + //function Action send_flit() + //endfunction + Reg#(Bit#(64)) i <- mkReg(0); + //Reg#(Bit#(64)) r <- mkReg(0); + + Reg#(Bit#(32)) cycle <- mkConfigReg(0); + + (* no_implicit_conditions *) + rule cycle_count(True); + //$display("[cycle %08d] ----------------------------------------------- ", cycle); + //for(Integer r=0; r < valueOf(NumRouters); r=r+1) begin + // $write(" %0d", credits[r][0]); + //end + //$write("\n"); + cycle <= cycle + 1; + endrule + +// (* no_implicit_conditions *) +// rule monitor_warmup(True); +// if (cycle == fromInteger(valueOf(NumCyclesToWarm))) begin +// $display("Warmup done finished @ cycle %0d. Reseting stats.", cycle); +// reset_stats <= True; +// for(Integer r=0; r < valueOf(NumRouters); r=r+1) begin +// delay_sum[r] <= 0; +// pkt_cnt[r] <= 0; +// end +// end else begin +// endrule + + (* no_implicit_conditions *) + rule drain_flits(True); + for(Integer r=0; r < valueOf(NumUserRecvPorts); r=r+1) begin + let in_pckt <- net.recv_ports[r].getFlit(); + if(isValid(in_pckt)) begin // received a valid packet + let p = in_pckt.Valid; + net.recv_ports[r].putCredits( tagged Valid p.vc ); // send a credit back + end + + if (cycle == fromInteger(valueOf(NumCyclesToWarm))) begin + $display("Warmup done finished @ cycle %0d. Reseting stats.", cycle); + delay_sum[r] <= 0; + pkt_cnt[r] <= 0; + end else begin // only update stats if not resetting. + if(isValid(in_pckt)) begin // received a valid flit + let p = in_pckt.Valid; + if (p.is_tail) begin // valid flit is a tail + delay_sum[r] <= delay_sum[r] + extend(cycle-p.data); // data carries injection timestamp + pkt_cnt[r] <= pkt_cnt[r] + 1; + end + end + end + end + + // for(Integer r=0; r < valueOf(NumRouters); r=r+1) begin + // let in_pckt <- net.recv_ports[r].getFlit(); + // if(isValid(in_pckt)) begin // received a valid packet + // let p = in_pckt.Valid; + // net.recv_ports[r].putCredits( tagged Valid p.vc ); // send a credit back + // if(p.is_tail) begin // if this is a tail add it to the total delay. + // delay_sum[r] <= delay_sum[r] + extend(cycle-p.data); // data carries injection timestamp + // pkt_cnt[r] <= pkt_cnt[r] + 1; + // end + // end else begin + // net.recv_ports[r].putCredits( Invalid ); // send a credit back + // end + // end + endrule + + Stmt fsm = seq + // For each router + repeat( fromInteger(valueOf(NumCyclesToTest)) ) seq + //for(i<=0; i < fromInteger(valueOf(NumCyclesToTest)); i<=i+1) seq + //for(f<=0; f < fromInteger(valueOf(NumFlitsToTest)); f<=f+1) seq + //for(r<=0; r < fromInteger(valueOf(NumRouters)); r<=r+1) par + // Try to send a flit + action + for(Integer r=0; r < valueOf(NumUserSendPorts); r=r+1) begin + TraceEntry_t te = traces[r].sub(truncate(cur_trace[r])); + //$display("[%02d] curr_te: %x", r, te); + + // check for credits and check if cycle count has passed departure time! + if(credits[r][te.vc] > 0 && cycle >= te.ts) begin + + VC_t vc = truncate(te.vc); + net.send_ports[r].putFlit( tagged Valid Flit_t{is_tail:te.is_tail, dst:truncate(te.dst), vc:vc, data:te.ts} ); + credits_clear[r][vc] <= True; + + cur_trace[r] <= cur_trace[r] + 1; + //$display("Sending flit (t:%d) from %d to %d @ cycle %d (ts: %d)", te.is_tail, r, te.dst, cycle, te.ts); + //TrafficEntry_t te = traffic.sub(truncate(i)); + //send_trace(tr.ts, tr.src, tr.dst); + end else begin + net.send_ports[r].putFlit( Invalid ); + //if (cycle < te.ts) begin + // $display("Not ready to send flit yet (dep_time: %d, cur_time:%d)", te.ts, cycle); + //end + //if (credits[r][te.vc] == 0) begin + // $display("Out of credits (router: %d, VC: %d)", r, te.vc); + //end + end + + + end + endaction + //endpar + endseq + + endseq; + + rule handle_incoming_credits(True); + // keep track of credits + for(Integer r=0; r < valueOf(NumUserSendPorts); r=r+1) begin + let cr_in <- net.send_ports[r].getCredits(); + if(isValid(cr_in)) begin + credits_set[r][cr_in.Valid] <= True; + //$display("Cycle: %0d: Received credit at router %0d for vc %0d", cycle, r, cr_in.Valid); + end + end + endrule + + mkAutoFSM(fsm); + + + (* fire_when_enabled *) + rule printstats (cycle == fromInteger(valueOf(NumCyclesToTest))); + Bit#(64) total_delay = unpack(0); + Bit#(64) total_pkt_cnt = unpack(0); + for(Integer r=0; r < valueOf(NumUserRecvPorts); r=r+1) begin + $display("router %0d delay_sum %0d pkt_cnt %0d", r, delay_sum[r], pkt_cnt[r]); + total_delay = total_delay + extend(delay_sum[r]); + total_pkt_cnt = total_pkt_cnt + extend(pkt_cnt[r]); + end + $display("total_delay_sum %0d total_pkt_cnt %0d", total_delay, total_pkt_cnt); + endrule + + + + +// (* fire_when_enabled *) +// rule printstats (cycle == fromInteger(valueOf(NumCyclesToTest))); +// for(Integer r=0; r < valueOf(NumRouters); r=r+1) begin +// $display("router %0d delay_sum %0d pkt_cnt %0d", r, delay_sum[r], pkt_cnt[r]); +// //prstat(); +// end +// // for(Integer r=0; r < valueOf(NumRouters); i=i+1) begin +// // sinks[i].prstat(); +// // end +// endrule + +// method Action prstat(); +// $display("total_delay %0d\npkt_cnt %0d", delay_sum, pkt_cnt); +// endmethod + +endmodule diff --git a/NetworkTypes.bsv b/NetworkTypes.bsv new file mode 100644 index 0000000..fdd366d --- /dev/null +++ b/NetworkTypes.bsv @@ -0,0 +1,337 @@ +/* ========================================================================= + * + * Filename: MCInternalTypes.bsv + * Date created: 03-16-2011 + * Last modified: 04-06-2011 + * Authors: Michael Papamichael + * + * Description: + * Types used internally for Memocode network simulator. + * + * ========================================================================= + */ + +import Vector::*; +import FShow::*; +`include "NetworkExternalTypes.bsv" +//import MCExternalTypes::*; + +`include "inc.v" + +/////////////////////////////////////////////////////////////////////////////////////////////// +// Set network and router parameters +// include *.conf.bsv file generated by running parse_conf on the network configuration file +/////////////////////////////////////////////////////////////////////////////////////////////// + +//`include "conf_parameters.bsv" +//`include "net_configs/mesh_2x2.txt.conf.bsv" + +//////////////////////////////////////////////////////////////////// +// Type Definitions +//////////////////////////////////////////////////////////////////// +typedef enum{ SepIFRoundRobin, SepOFRoundRobin, SepIFStatic, SepOFStatic, Memocode } AllocType_t deriving(Bits, Eq); + +typedef Bit#(n) NumTypeParam#(numeric type n); +// Width of data field in each flit +//typedef 256 FlitDataWidth; +// Max number of flits per packet - check with Derek what the maximum number of flits is - reference uses uchar, i.e. 0-255 +typedef 256 MaxNumFlitsPerPacket; +// Max number of traffic entries +typedef 1024 MaxNumTrafficEntries; + +typedef 48 MaxCyclesLog; // Log of maximum number of cycles that can be counted +typedef 48 MaxNumPacketsLog; // Half of Log of maximum number of packets that each traffic generator can send + +// Derived parameters +typedef TSub#(CreditDelay, 1) CreditExtraDelay; + +typedef Bit#(TLog#(NumInPorts)) InPort_t; +typedef Bit#(TLog#(NumOutPorts)) OutPort_t; + +typedef Bit#(MaxCyclesLog) Cycle_t; +typedef Bit#(MaxNumPacketsLog) NumPackets_t; + +typedef struct{ + //Bool is_head; // turns out this was not needed + Bool is_tail; // only required for multi-flit packets + //RouterID_t dst; + UserRecvPortID_t dst; + //VC_t vc; // when flit is sitting in the flitbuffer the VC is implied + FlitData_t data; // payload of flit +} FlitBuffer_t + deriving(Bits, Eq); + +typedef struct{ + Flit_t flit; // flit + OutPort_t out_port; // out_port +} RoutedFlit_t + deriving(Bits, Eq); + + +//typedef struct{ +// //Bool is_head; // turns out this was not needed +// Bool is_tail; +// RouterID_t dst; +// VC_t vc; +// FlitData_t data; // payload of flit +// `ifdef EN_DBG_REF +// Bit#(256) id; // only used for validation +// `endif +//} Flit_t +// deriving(Bits, Eq); + +//////////////////////////////////////////////// +// InPort and OutPort interfaces +// Implemented by routers and traffic sources +//////////////////////////////////////////////// +//interface InPort; +// (* always_ready *) method Action putFlit(Maybe#(Flit_t) flit_in); +// (* always_ready *) method ActionValue#(Credit_t) getCredits; +//endinterface +// +//interface OutPort; +// (* always_ready *) method ActionValue#(Maybe#(Flit_t)) getFlit(); +// (* always_ready *) method Action putCredits(Credit_t cr_in); +//endinterface +// +//typedef Maybe#(VC_t) Credit_t; // credits carry VC to which they belong + +///////////////////////////////////////////////// +// Traffic Source Types +///////////////////////////////////////////////// +typedef Bit#(TLog#(MaxNumTrafficEntries)) TrafficEntryID_t; +typedef Bit#(TLog#(MaxNumFlitsPerPacket)) FlitID_t; +// Check with Derek what the maximum number of flits is - It is a uchar, i.e. 255 +typedef struct{ + RouterID_t dst; + VC_t vc; + FlitID_t num_flits; +} TrafficEntry_t + deriving(Bits, Eq); + + +////////////////////////////////////////////////// +// Command interface used by MicroBlaze +////////////////////////////////////////////////// + +// All possible commands that can be issued through MicroBlaze. +// Notes: Top module will need to maintain a counter that holds the current TrafficEntryID. This counter +// needs to get reset using the SetTrafficEntryCount command when starting to populate a new routers traffic entries. + +// Used to split cycle values in two halves when bringing in the results through Microblaze 32-bit interface +typedef TDiv#(MaxCyclesLog,2) HalfMaxCyclesLog; // Log of maximum number of cycles that can be counted +typedef TDiv#(MaxNumPacketsLog, 2) HalfMaxNumPacketsLog; // Half of Log of maximum number of packets that each traffic generator can send +typedef Bit#(HalfMaxCyclesLog) HalfCycle_t; +typedef Bit#(HalfMaxNumPacketsLog) HalfNumPackets_t; + +// Command to set current RouterID that will be configured +typedef struct{ + Bit#(8) rt_id; // Router ID. Will be truncated to match RouterID_t. +} SetRouterIDCmd_t + deriving (Bits, Eq); + +// Command for setting Route Table entries for currently selected router. +typedef struct{ + Bool endOfTable; // indicates that route table that was populated should now be committed to BRAM. + Bit#(8) dst; // Destination. Will be truncated to match RouterID_t. + Bit#(4) out_p; // Out Port. Will be truncated to match OutPort_t. +} RouteCmd_t + deriving (Bits, Eq); + +// Command for setting Traffic Source entries for currently selected router. +typedef struct{ + Bool endOfTraffic; // indicates end of traffic table for this source. You can commit to BRAM. + Bit#(8) dst; // Destination. Will be truncated to match RouterID_t. + Bit#(3) vc; // VC. Will be truncated to match VC_t. + Bit#(10) num_flits; // Number of flits in packet. Will be truncated to match FlitID_t. +} TrafficCmd_t + deriving (Bits, Eq); + +// Command for setting Maximum number of packets to be sent by the traffic source of the currently selected router. +// Since MicroBlaze goes through a narrow interface this requires two commands to separately set the high and low halves. +typedef struct{ + Bool is_lo; // indicates if this is the lower half of the value. + HalfNumPackets_t num_pcks_lo_hi; // carries low or high half of value. +} SetMaxPcksCmd_t + deriving (Bits, Eq); + +// Command for setting Maximum number of simulation cycles. +// Since MicroBlaze goes through a narrow interface this requires two commands to separately set the high and low halves. +typedef struct{ + Bool is_lo; + HalfCycle_t cycles_lo_hi; +} SetMaxCyclesCmd_t + deriving (Bits, Eq); + +// Command for setting the current traffic entry ID. Only used to set the traffic entry ID to 0, +// when starting to populate the traffic entries of a new router. +typedef struct{ + TrafficEntryID_t traf_id; // Value to set traffic entry ID to. +} SetTrafficIDCmd_t + deriving (Bits, Eq); + +// Command wrapper that can contain any of the above commands. This is what the MicroBlaze writes. +typedef union tagged{ + SetRouterIDCmd_t SetRtID_cmd; + RouteCmd_t Route_cmd; + TrafficCmd_t Traffic_cmd; + SetMaxPcksCmd_t MaxPcks_cmd; + SetMaxCyclesCmd_t MaxCycles_cmd; + SetTrafficIDCmd_t SetTrafID_cmd; + void InitDone_cmd; +} SetupCmd_t + deriving (Bits, Eq); + +// Results container. Used by MicroBlaze to read simulation results. +// Since MicroBlaze reads through a narrow interface two commands are require to separately read the high and low halves. +typedef struct{ + Bool reached_max_cycles; // indicates if experiment finished because maxCycles where reached + Bool is_lo; // indicates if this is the lower half of the value. + HalfCycle_t elapsed_cycles_lo_hi; // carries low or high half of value. +} Result_t + deriving (Bits, Eq); + + + +/////////////////////////////////////////////////// +// Data Structures for Virtual Router +/////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// Router state. Includes all state that a router stores and keeps track of, except for route tables. +// Route tables are handled separately, because they have to be initialized by MicroBlaze. +// Used to implement virtual router. +typedef struct{ + //Vector#(NumRouters, OutPort_t) routeTable; + Vector#(NumInPorts, Vector#(NumVCs, FlitBuffer_t)) flitBuffers; + Vector#(NumOutPorts, Vector#(NumVCs, Bool)) credits; + Vector#(NumVCs, Vector#(NumInPorts, Vector#(NumOutPorts, Bool))) hasFlitsVIO; + Vector#(NumOutPorts, Vector#(NumVCs, Bool )) lockedVL; + Vector#(NumOutPorts, Vector#(NumVCs, InPort_t)) inPortVL; +} RouterState_t + deriving (Bits, Eq); + +//////////////////////////////////////////////////////////////////////////////////// +// Incoming link state. Corresponds to flits and credits going into a router. +typedef struct{ + Vector#(NumInPorts, Maybe#(Flit_t)) in_flits; + Vector#(NumOutPorts, Credit_t) in_credits; +} RouterInLinks_t + deriving (Bits, Eq); + +//////////////////////////////////////////////////////////////////////////////////// +// Outgoing link state. Corresponds to flits and credits coming out of a router. +typedef struct{ + Vector#(NumOutPorts, Maybe#(Flit_t)) out_flits; + Vector#(NumInPorts, Credit_t) out_credits; +} RouterOutLinks_t + deriving (Bits, Eq); + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// Traffic source state. Includes all state that a traffic source stores and keeps track of. +// Used to implemente virtual traffic source. +typedef struct{ + //Vector#(NumRouters, OutPort_t) routeTable; + NumPackets_t packetsToSend; // total number of packets to send + TrafficEntryID_t lastTrafficEntryID; // to know when to wrap-around + NumPackets_t numSentPackets; // keep track of how many packets have been sent + TrafficEntry_t curTrafficEntry; // holds current traffic entry + //TrafficEntryID_t curTEindex; // current Traffic Entry index. + //FlitID_t cur_flits; // number of flits sent from this packet. + Vector#(NumVCs, Bool ) credits; // stores source credits + // Note: If I uncomment the (wrong) line below the compiler crashes with an internal error message. Send this to Bluespec so they can fix it. + //Vector#(NumVCs, Reg#(Bool) ) credits; +} TrafficSourceState_t + deriving (Bits, Eq); + + +typedef Bit#(TAdd#( TLog#(NumRouters), TLog#(MaxNumTrafficEntries) ) ) VirtualTrafficEntryID_t; +//typedef Bit#(TLog#(TMul#(NumRouters, MaxNumTrafficEntries))) VirtualTrafficEntryID_t; +//typedef struct{ +// RouterID_t src_id; // Traffic Source ID (one per router) +// TrafficEntryID_t traf_id; // Traffic Entry ID for the traffic table of the specified source +//} VirtualTrafficEntryID_t +// deriving (Bits, Eq, Bounded); + +interface Network; + interface Vector#(NumUserSendPorts, InPort) send_ports; + interface Vector#(NumUserRecvPorts, OutPort) recv_ports; + interface Vector#(NumUserRecvPorts, RecvPortInfo) recv_ports_info; // Used by clients for obtaining response address + //interface Vector#(NumRouters, RouterInfo) router_info; +endinterface + + +/////////////////////////////////////////////////////////////////////////// +// Router Interface +interface Router; + // Port Interfaces + interface Vector#(NumInPorts, InPort) in_ports; + interface Vector#(NumOutPorts, OutPort) out_ports; + // Used to query router info (e.g. ID) + //interface RouterInfo rt_info; + //method Action setRoutingEntry(RouterID_t dst, OutPort_t out_p); +endinterface + +/////////////////////////////////////////////////////////////////////////// +// RouterCore Interface +interface RouterCore; + interface Vector#(NumInPorts, RouterCoreInPort) in_ports; // Same as router in_ports, but also carry routing info + interface Vector#(NumOutPorts, OutPort) out_ports; + //interface Vector#(NumInPorts, Client#(RouterID_t, OutPort_t)) rt; +endinterface + +// InPort interface for RouterCore +interface RouterCoreInPort; + (* always_ready *) method Action putRoutedFlit(Maybe#(RoutedFlit_t) flit_in); + (* always_ready *) method ActionValue#(Credit_t) getCredits; +endinterface + + + +interface NetworkSimple; + interface Vector#(NumUserSendPorts, InPortSimple) send_ports; + interface Vector#(NumUserRecvPorts, OutPortSimple) recv_ports; + interface Vector#(NumUserRecvPorts, RecvPortInfo) recv_ports_info; // Used by clients for obtaining response address + //interface Vector#(NumRouters, RouterInfo) router_info; +endinterface + + +/////////////////////////////////////////////////////////////////////////// +// Router Interface +interface RouterSimple; + // Port Interfaces + interface Vector#(NumInPorts, InPortSimple) in_ports; + interface Vector#(NumOutPorts, OutPortSimple) out_ports; + // Used to query router info (e.g. ID) + //interface RouterInfo rt_info; + //method Action setRoutingEntry(RouterID_t dst, OutPort_t out_p); +endinterface + +/////////////////////////////////////////////////////////////////////////// +// RouterCore Interface +interface RouterCoreSimple; + interface Vector#(NumInPorts, RouterCoreInPortSimple) in_ports; // Same as router in_ports, but also carry routing info + interface Vector#(NumOutPorts, OutPortSimple) out_ports; + //interface Vector#(NumInPorts, Client#(RouterID_t, OutPort_t)) rt; +endinterface + +// InPort interface for RouterCore +interface RouterCoreInPortSimple; + (* always_ready *) method Action putRoutedFlit(Maybe#(RoutedFlit_t) flit_in); + (* always_ready *) method ActionValue#(Vector#(NumVCs, Bool)) getNonFullVCs; +endinterface + + + + +///////////////////////////////////////////////////////////////////////////////// +// Add some types to FShow typeclass for pretty printing + +instance FShow#(Flit_t); + function Fmt fshow (Flit_t fl); + return ($format("Flit [dst:%0d vc:%0d is_tail:%0d data:%x]", fl.dst, fl.vc, fl.is_tail, fl.data)); + //return ($format("Flit [dst:%0d\t vc:%0d\t is_tail:%0d\t data:%x]", fl.dst, fl.vc, fl.is_tail, fl.data)); + //return concatWith("Flit - is_tail:", fshow(""), fshow(fl.is_tail)); + //return concatWith("test"); + endfunction +endinstance diff --git a/NetworkXbar.bsv b/NetworkXbar.bsv new file mode 100644 index 0000000..28371f5 --- /dev/null +++ b/NetworkXbar.bsv @@ -0,0 +1,403 @@ +import Assert::*; +import ConfigReg::*; +import Vector::*; +import Count::*; +import FIFOF::*; +import PipelineFIFO::*; +import FIFOLevel::*; +import LUTFIFO::*; +import BRAMFIFO::*; +import Arbiters::*; +import GetPut::*; +import FIFOCountDeqBus::*; +import Strace::*; +import NetworkQueues::*; + + +`include "inc.v" + +import NetworkTypes::*; +import NetworkExternalTypes::*; +import Xbar::*; + + +module mkNetworkXbar(Network); + + XbarVerilog#(NumRouters, NumVCs, NetworkCut, FlitDataWidth, FlitBufferDepth) xbar <- mkXbarVerilog; + + Vector#(NumRouters, InPort) send_ifaces; + Vector#(NumRouters, OutPort) recv_ifaces; + Vector#(NumRouters, RouterInfo) rt_ifaces; + + Vector#(NumRouters, PulseWire) i_valid <- replicateM(mkPulseWire); + Vector#(NumRouters, PulseWire) i_prio <- replicateM(mkPulseWire); + Vector#(NumRouters, PulseWire) i_tail <- replicateM(mkPulseWire); + Vector#(NumRouters, RWire#(RouterID_t)) i_dst <- replicateM(mkRWire); + Vector#(NumRouters, RWire#(VC_t)) i_vc <- replicateM(mkRWire); + Vector#(NumRouters, RWire#(FlitData_t)) i_data <- replicateM(mkRWire); + + Vector#(NumRouters, PulseWire) o_cred_en <- replicateM(mkPulseWire); + + (* fire_when_enabled *) + rule putIface(True); + + Vector#(NumRouters, Bool) in_valid; + Vector#(NumRouters, Bool) in_prio; + Vector#(NumRouters, Bool) in_tail; + Vector#(NumRouters, RouterID_t) in_dst; + Vector#(NumRouters, VC_t) in_vc; + Vector#(NumRouters, FlitData_t) in_data; + + Vector#(NumRouters, Bool) out_cred_en; + + for(Integer i=0; i < valueOf(NumRouters); i=i+1) begin + in_valid[i] = i_valid[i]; + in_prio[i] = i_prio[i]; + in_tail[i] = i_tail[i]; + in_dst[i] = validValue(i_dst[i].wget); + in_vc[i] = validValue(i_vc[i].wget); + in_data[i] = validValue(i_data[i].wget); + + out_cred_en[i] = o_cred_en[i]; + end + + xbar.iports(in_valid, in_prio, in_tail, in_dst, in_vc, in_data); + xbar.o_cred(out_cred_en); + + endrule + + let o_valid = xbar.o_valid; + let o_prio = xbar.o_prio; + let o_tail = xbar.o_tail; + let o_dst = xbar.o_dst; + let o_vc = xbar.o_vc; + let o_data = xbar.o_data; + + let i_cred = xbar.i_cred; + let i_cred_valid = xbar.i_cred_valid; + + for(Integer i=0; i < valueOf(NumRouters); i=i+1) begin + let ifc = interface InPort + + method Action putFlit(Maybe#(Flit_t) flit_in); + if(flit_in matches tagged Valid .flit) begin + i_valid[i].send(); + if(flit.prio) i_prio[i].send(); + if(flit.is_tail) i_tail[i].send(); + i_dst[i].wset(flit.dst); + i_vc[i].wset(flit.vc); + i_data[i].wset(flit.data); + end + endmethod + + method ActionValue#(Credit_t) getCredits; + actionvalue + if(i_cred_valid[i]) return Valid(i_cred[i]); + else return Invalid; + endactionvalue + endmethod + + endinterface; + send_ifaces[i] = ifc; + end + + // From outQs to output + + for(Integer o=0; o < valueOf(NumRouters); o=o+1) begin + + let ifc = interface OutPort + + method ActionValue#(Maybe#(Flit_t)) getFlit(); + actionvalue + + Maybe#(Flit_t) flitOut = Invalid; + + if(o_valid[o]) begin + flitOut = Valid(Flit_t{ prio: o_prio[o], + is_tail: o_tail[o], + dst: o_dst[o], + vc: o_vc[o], + data: o_data[o] }); + end + + return flitOut; + endactionvalue + endmethod + + method Action putCredits(Credit_t cr_in); + if(isValid(cr_in)) begin + o_cred_en[o].send(); + end + endmethod + + endinterface; + + recv_ifaces[o] = ifc; + end + + for(Integer i=0; i < valueOf(NumRouters); i=i+1) begin + + let ifc = interface RouterInfo + method RouterID_t getRouterID(); + return fromInteger(i); + endmethod + endinterface; + + rt_ifaces[i] = ifc; + end + + interface send_ports = send_ifaces; + interface recv_ports = recv_ifaces; + interface router_info = rt_ifaces; + +endmodule + +/* +typedef struct { + Bool prio; + Flit_t flit; + Bit#(32) tag; +} TaggedFlit + deriving(Bits, Eq); + + +(* synthesize *) +module mkNetworkQueueWithDeqBus(FIFOCountDeqBus#(TaggedFlit, FlitBufferDepth, NumRouters)); + let q <- mkFIFOCountDeqBus(); + return q; +endmodule + +(* synthesize *) +module mkNetworkXbarQueue(FIFOCountIfc#(TaggedFlit, FlitBufferDepth)); + let q <- mkLUTFIFO(False); + return q; +endmodule + +(* synthesize *) +module mkNetworkDummyQueue(FIFOCountDeqBus#(TaggedFlit, FlitBufferDepth, NumRouters)); + interface FIFOCountIfc fifo; + method notEmpty = False; + method notFull = True; + endinterface + method deq_happened = False; +endmodule + +(* noinline *) +function Maybe#(Bit#(TLog#(TMul#(XbarLanes,NumRouters)))) mkNetworkXbarEncoder( Vector#(TMul#(XbarLanes,NumRouters), Bool) vec ); + Maybe#(Bit#(TLog#(TMul#(XbarLanes,NumRouters)))) choice = Invalid; + //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority + for(Integer i=valueOf(TMul#(XbarLanes,NumRouters))-1; i >= 0; i=i-1) // I want the lowest to have highest priority + begin + if(vec[i]) begin + choice = Valid(fromInteger(i)); + end + end + return choice; +endfunction + + +(* synthesize *) +module mkNetworkXbarArbiter( Arbiter#(TMul#(XbarLanes,NumRouters)) ); + let arb <- mkRoundRobinArbiter(); + rule alwaysToggle(True); + arb.next(); + endrule + method select = arb.select; + method next = noAction; +endmodule + +(* synthesize *) +module mkNetworkXbarCounter( Count#(Bit#(TLog#(TAdd#(FlitBufferDepth,1))),1) ); + let counter <- mkCount(valueOf(FlitBufferDepth)); + return counter; +endmodule + +interface XbarOutputQueue; + method Vector#(NumRouters, Bool) send_creds(); + interface Vector#(NumRouters, Put#(Flit_t)) send_ifaces; + interface OutPort recv_iface; +endinterface + + + + +module mkNetworkXbar(Network); + + Vector#(TMul#(XbarLanes,NumRouters), + FIFOCountDeqBus#(TaggedFlit, FlitBufferDepth, NumRouters)) inQs <- replicateM(mkNetworkQueueWithDeqBus); + + Vector#(TMul#(XbarLanes,NumRouters), + FIFOCountDeqBus#(TaggedFlit, FlitBufferDepth, NumRouters)) dummyQs <- replicateM(mkNetworkDummyQueue); + + Vector#(NumRouters, FIFOF#(TaggedFlit)) outQs <- replicateM(mkPipelineFIFO(False)); //mkNetworkXbarQueue); + Vector#(NumRouters, Arbiter#(TMul#(XbarLanes,NumRouters))) arbiters <- replicateM(mkNetworkXbarArbiter); + Vector#(NumRouters, + Count#(Bit#(TLog#(TAdd#(FlitBufferDepth,1))),1)) out_credits <- replicateM(mkNetworkXbarCounter); + Vector#(NumRouters, Reg#(Credit_t)) vc_type <- replicateM(mkReg(Invalid)); + + Vector#(NumRouters, Reg#(Bit#(32))) strace_tags; + for(Integer i=0; i < valueOf(NumRouters); i=i+1) + strace_tags[i] <- mkReg(fromInteger(i)*65536); + + Vector#(NumRouters, InPort) send_ifaces; + Vector#(NumRouters, OutPort) recv_ifaces; + Vector#(NumRouters, RouterInfo) rt_ifaces; + + rule stats(True); + for(Integer i=0; i < valueOf(NumRouters); i=i+1) begin + Bool raise=False; + for(Integer k=0; k < valueOf(XbarLanes); k=k+1) begin + if(inQs[i*valueOf(XbarLanes)+k].fifo.notEmpty) + raise = True; + end + if(raise) $display("strace time=%0d component=noc inst=0 evt=raises val=1", $time); + end + endrule + + for(Integer o=0; o < valueOf(NumRouters); o=o+1) begin + let arbiter = arbiters[o]; + rule moveToOutput(True); + arbiter.next(); + + Vector#(TMul#(XbarLanes,NumRouters), + FIFOCountDeqBus#(TaggedFlit, FlitBufferDepth, NumRouters)) validQs; + + for(Integer i=0; i < valueOf(NumRouters); i=i+1) begin + for(Integer k=0; k < valueOf(XbarLanes); k=k+1) begin + if(o < valueOf(NetworkCut)) begin + if(i >= valueOf(NetworkCut)) + validQs[i*valueOf(XbarLanes)+k] = inQs[i*valueOf(XbarLanes)+k]; + else + validQs[i*valueOf(XbarLanes)+k] = dummyQs[i*valueOf(XbarLanes)+k]; + end + else begin + if(i < valueOf(NetworkCut)) + validQs[i*valueOf(XbarLanes)+k] = inQs[i*valueOf(XbarLanes)+k]; + else + validQs[i*valueOf(XbarLanes)+k] = dummyQs[i*valueOf(XbarLanes)+k]; + end + end + end + + Vector#(TMul#(XbarLanes,NumRouters), Bool) raises = unpack(0); + for(Integer i=0; i < valueOf(TMul#(XbarLanes,NumRouters)); i=i+1) begin + let inQ = validQs[i].fifo; + raises[i] = inQ.notEmpty && (inQ.first.flit.dst == fromInteger(o)); + end + + let msel = mkNetworkXbarEncoder(arbiter.select(raises)); + if(msel matches tagged Valid .sel) begin + if(outQs[o].notFull) begin + let flitOut = validQs[sel].fifo.first; + outQs[o].enq(flitOut); + validQs[sel].deq[o].deq(); + $display("strace time=%0d component=noc inst=0 evt=grants val=1", $time); + end + else $display("strace time=%0d component=noc inst=0 evt=full val=1", $time); + end + endrule + end + + // Input Requests + + for(Integer i=0; i < valueOf(NumRouters); i=i+1) begin + let ifc = interface InPort + + method Action putFlit(Maybe#(Flit_t) flit_in); + if(flit_in matches tagged Valid .flit) begin + let dst = flit.dst; + Integer sel=i; + // sort by destination + for(Integer k=0; k < valueOf(XbarLanes); k=k+1) begin + Bit#(TLog#(XbarLanes)) tmp = truncate(dst); + if(tmp == fromInteger(k)) sel = i*valueOf(XbarLanes) + k; + end + + strace_tags[i]<=strace_tags[i]+1; + + inQs[sel].fifo.enq(TaggedFlit{flit:flit, tag:strace_tags[i], prio:flit.prio}); + //$display("[network] time=%0d input port %0d (sel:%0d) -> output Q %0d", $time, i, sel, dst); + strace_begin("noc", 0, "delay", strace_tags[i]); + strace("noc", 0, "num_packet"); + + // $display("[network] time=%0d input port %0d (sel:%0d) -> output Q %0d", $time, i, sel, dst); + if(!isValid(vc_type[i])) begin + vc_type[i] <= Valid(flit.vc); + // $display("[network] time=%0d setting input port %0d's vc to %0d", $time, i, flit.vc); + end + else dynamicAssert(flit.vc == validValue(vc_type[i]), "vc should be same coming in from same port"); + end + endmethod + + + method ActionValue#(Credit_t) getCredits; + Bool send = False; + for(Integer k=0; k < valueOf(XbarLanes); k=k+1) begin + if(inQs[i*valueOf(XbarLanes)+k].deq_happened) send = True; + end + if(send) begin + dynamicAssert(isValid(vc_type[i]), "error, didn't learn VC type yet"); + // $display("[network] time=%0d returning credit to input port %0d, vc:%0d", $time, i, validValue(vc_type[i])); + return vc_type[i]; + end + else begin + return Invalid; + end + endmethod + + endinterface; + send_ifaces[i] = ifc; + end + + // From outQs to output + + for(Integer o=0; o < valueOf(NumRouters); o=o+1) begin + + let ifc = interface OutPort + + method ActionValue#(Maybe#(Flit_t)) getFlit(); + actionvalue + Maybe#(Flit_t) flitOut = Invalid; + if((out_credits[o].value() != 0) && outQs[o].notEmpty) begin + flitOut = Valid(outQs[o].first.flit); + out_credits[o].sub(1); + outQs[o].deq(); + + if(outQs[o].first.prio) + strace_end("noc", 0, "prio_delay", outQs[o].first.tag); + else + strace_end("noc", 0, "delay", outQs[o].first.tag); + end + else if(outQs[o].notEmpty) begin + $display("strace time=%0d component=noc inst=0 evt=out_stall val=1", $time); + end + return flitOut; + endactionvalue + endmethod + + method Action putCredits(Credit_t cr_in); + if(isValid(cr_in)) out_credits[o].add(1); + endmethod + + endinterface; + + recv_ifaces[o] = ifc; + end + + for(Integer i=0; i < valueOf(NumRouters); i=i+1) begin + + let ifc = interface RouterInfo + method RouterID_t getRouterID(); + return fromInteger(i); + endmethod + endinterface; + + rt_ifaces[i] = ifc; + end + + interface send_ports = send_ifaces; + interface recv_ports = recv_ifaces; + interface router_info = rt_ifaces; + +endmodule +*/ diff --git a/Prims/.svn/entries b/Prims/.svn/entries new file mode 100644 index 0000000..693b1eb --- /dev/null +++ b/Prims/.svn/entries @@ -0,0 +1,878 @@ +10 + +dir +202 +file:///afs/ece.cmu.edu/usr/mpapamic/svnrepos/CONNECT/Prims +file:///afs/ece.cmu.edu/usr/mpapamic/svnrepos/CONNECT + + + +2013-10-08T08:08:43.999371Z +177 +mpapamic + + + + + + + + + + + + + + +4f13744c-6e46-11e0-9aa1-910fbbcf003f + +DPSRAM.v +file + + + + +2013-11-15T05:00:49.000000Z +5a9f9b09ba82d8c781acb932364e0b93 +2011-04-24T08:47:48.397130Z +1 +mpapamic + + + + + + + + + + + + + + + + + + + + + +1178 + +BypassWire.v +file + + + + +2013-11-15T05:00:49.000000Z +fd06f38184e853ca2f15d0f500cf438a +2011-04-24T08:47:48.397130Z +1 +mpapamic + + + + + + + + + + + + + + + + + + + + + +1397 + +QUAD_BRAM.v +file + + + + +2013-11-15T05:00:49.000000Z +2d9a851e09091410821a7cf87d0bef9a +2011-04-24T08:47:48.397130Z +1 +mpapamic + + + + + + + + + + + + + + + + + + + + + +5080 + +Xbar.v +file + + + + +2013-11-15T05:00:49.000000Z +8f2bf78dfce3ec47a94113355cb39ba1 +2012-03-07T00:40:35.529010Z +135 +mpapamic + + + + + + + + + + + + + + + + + + + + + +8958 + +RegFileLoadSyn.bsv +file + + + + +2013-11-15T05:00:49.000000Z +8722ec1ff2e0d6cf3a210c098b2a7345 +2013-10-07T22:45:26.614646Z +176 +mpapamic + + + + + + + + + + + + + + + + + + + + + +1064 + +ROM.v +file + + + + +2013-11-15T05:00:49.000000Z +8d151c3e45064a8860818979ae2486d8 +2011-04-24T08:47:48.397130Z +1 +mpapamic + + + + + + + + + + + + + + + + + + + + + +1021 + +PipelineFIFO.bsv +file + + + + +2013-11-15T05:00:49.000000Z +473da147548dbf118d74a1a74c3a9619 +2011-07-24T03:15:25.335199Z +41 +echung + + + + + + + + + + + + + + + + + + + + + +7892 + +DoubleBufferingRegFile_16ports.v +file + + + + +2013-11-15T05:00:49.000000Z +a44d47ad5e195374e113bd71bbee37d3 +2011-04-24T08:47:48.397130Z +1 +mpapamic + + + + + + + + + + + + + + + + + + + + + +9391 + +DPSRAM_w_forward.v +file + + + + +2013-11-15T05:00:49.000000Z +6f25ce35bf2aeb42ea4ea391fdefcbd3 +2011-04-24T08:47:48.397130Z +1 +mpapamic + + + + + + + + + + + + + + + + + + + + + +1165 + +RegFile_1port.v +file + + + + +2013-11-15T05:00:49.000000Z +1f6f8fac576f70272c92178bab2e25b0 +2012-11-30T16:41:36.113661Z +161 +mpapamic + + + + + + + + + + + + + + + + + + + + + +1641 + +BRAM1.v +file + + + + +2013-11-15T05:00:49.000000Z +7886b6aa9d789febb36a219a82fdf3f0 +2011-04-24T08:47:48.397130Z +1 +mpapamic + + + + + + + + + + + + + + + + + + + + + +2733 + +BRAM2.v +file + + + + +2013-11-15T05:00:49.000000Z +3c9c8a5226f07f3dc4da7d4235055b1d +2011-04-24T08:47:48.397130Z +1 +mpapamic + + + + + + + + + + + + + + + + + + + + + +4054 + +shift_8x64.v +file + + + + +2013-11-15T05:00:49.000000Z +936d35b7829f360a65e852da86c506f0 +2011-05-26T17:44:18.869078Z +20 +echung + + + + + + + + + + + + + + + + + + + + + +552 + +NetworkQueues.bsv +file + + + + +2013-11-15T05:00:49.000000Z +328542bf9fa4b93d1fab08d29d7ecbc9 +2012-03-07T00:40:35.529010Z +135 +mpapamic + + + + + + + + + + + + + + + + + + + + + +233 + +RegFileLoadSyn.v +file + + + + +2013-11-15T05:00:49.000000Z +105f42466afb9ab4a7d19e275b643d6f +2011-10-17T13:24:18.675271Z +108 +mpapamic + + + + + + + + + + + + + + + + + + + + + +973 + +RegFile_16ports_load.v +file + + + + +2013-11-15T05:00:49.000000Z +83661f24ea77d3405f5c138f25a6d7c8 +2011-04-25T15:51:08.516050Z +10 +mpapamic + + + + + + + + + + + + + + + + + + + + + +4297 + +shift_reg.v +file + + + + +2013-11-15T05:00:49.000000Z +5395afdd93b79994a7fb4b120f4bd87f +2011-04-24T08:47:48.397130Z +1 +mpapamic + + + + + + + + + + + + + + + + + + + + + +835 + +RegFile_16ports.v +file + + + + +2013-11-15T05:00:49.000000Z +be24c8392a84badc2a6d090a08039f0e +2011-05-16T23:27:52.686130Z +14 +mpapamic + + + + + + + + + + + + + + + + + + + + + +4120 + +RegFile.v +file + + + + +2013-11-15T05:00:49.000000Z +30fe694639cdc261b435005c9695a36b +2011-05-16T23:27:52.686130Z +14 +mpapamic + + + + + + + + + + + + + + + + + + + + + +4305 + +testbench_sample.v +file + + + + +2013-11-15T05:00:49.000000Z +5ea35ba118410fb4a3c77ee21d5f722d +2013-10-08T08:08:43.999371Z +177 +mpapamic + + + + + + + + + + + + + + + + + + + + + +4192 + +PriorityEncoder.v +file + + + + +2013-11-15T05:00:49.000000Z +ddb46d14126a670bb7ace8bde51648fc +2011-04-24T08:47:48.397130Z +1 +mpapamic + + + + + + + + + + + + + + + + + + + + + +431 + +Xbar.bsv +file + + + + +2013-11-15T05:00:49.000000Z +98abdd55626859d21c67a88c3f96a5d3 +2011-07-22T20:39:00.981758Z +40 +echung + + + + + + + + + + + + + + + + + + + + + +2142 + +RegFileMultiport.bsv +file + + + + +2013-11-15T05:00:49.000000Z +61194a7587f568aa0e4c00140410e664 +2011-06-16T16:56:24.069349Z +30 +mpapamic + + + + + + + + + + + + + + + + + + + + + +5237 + +SizedFIFO.v +file + + + + +2013-11-15T05:00:49.000000Z +956b0a57bc2278ae75f248685b95255d +2011-07-22T06:15:59.388368Z +39 +echung + + + + + + + + + + + + + + + + + + + + + +8807 + +testbench_sample_peek.v +file + + + + +2013-11-15T05:00:49.000000Z +aeff0ce1529abc8b5710f985b7c8d3a1 +2013-10-08T08:08:43.999371Z +177 +mpapamic + + + + + + + + + + + + + + + + + + + + + +4354 + diff --git a/Prims/.svn/text-base/BRAM1.v.svn-base b/Prims/.svn/text-base/BRAM1.v.svn-base new file mode 100644 index 0000000..5bddecf --- /dev/null +++ b/Prims/.svn/text-base/BRAM1.v.svn-base @@ -0,0 +1,85 @@ + +// Copyright (c) 2000-2009 Bluespec, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// $Revision: 17872 $ +// $Date: 2009-09-18 14:32:56 +0000 (Fri, 18 Sep 2009) $ + +`ifdef BSV_ASSIGNMENT_DELAY +`else + `define BSV_ASSIGNMENT_DELAY +`endif + +// Single-Ported BRAM +module BRAM1(CLK, + EN, + WE, + ADDR, + DI, + DO + ); + + // synopsys template + parameter PIPELINED = 0; + parameter ADDR_WIDTH = 1; + parameter DATA_WIDTH = 1; + parameter MEMSIZE = 1; + + + input CLK; + input EN; + input WE; + input [ADDR_WIDTH-1:0] ADDR; + input [DATA_WIDTH-1:0] DI; + output [DATA_WIDTH-1:0] DO; + + reg [DATA_WIDTH-1:0] RAM[0:MEMSIZE-1]; + reg [ADDR_WIDTH-1:0] ADDR_R; + reg [DATA_WIDTH-1:0] DO_R; + +`ifdef BSV_NO_INITIAL_BLOCKS +`else + // synopsys translate_off + integer i; + initial + begin : init_block + for (i = 0; i < MEMSIZE; i = i + 1) begin + RAM[i] = { ((DATA_WIDTH+1)/2) { 2'b10 } }; + end + ADDR_R = { ((ADDR_WIDTH+1)/2) { 2'b10 } }; + DO_R = { ((DATA_WIDTH+1)/2) { 2'b10 } }; + end + // synopsys translate_on +`endif // !`ifdef BSV_NO_INITIAL_BLOCKS + + always @(posedge CLK) begin + if (EN) begin + if (WE) + RAM[ADDR] <= `BSV_ASSIGNMENT_DELAY DI; + ADDR_R <= `BSV_ASSIGNMENT_DELAY ADDR; + end + DO_R <= `BSV_ASSIGNMENT_DELAY RAM[ADDR_R]; + end + + assign DO = (PIPELINED) ? DO_R : RAM[ADDR_R]; + +endmodule // BRAM1 + + diff --git a/Prims/.svn/text-base/BRAM2.v.svn-base b/Prims/.svn/text-base/BRAM2.v.svn-base new file mode 100644 index 0000000..17e2aff --- /dev/null +++ b/Prims/.svn/text-base/BRAM2.v.svn-base @@ -0,0 +1,132 @@ + +// Copyright (c) 2000-2009 Bluespec, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// $Revision: 17872 $ +// $Date: 2009-09-18 14:32:56 +0000 (Fri, 18 Sep 2009) $ + +`ifdef BSV_ASSIGNMENT_DELAY +`else + `define BSV_ASSIGNMENT_DELAY +`endif + +// Dual-Ported BRAM +module BRAM2(CLKA, + ENA, + WEA, + ADDRA, + DIA, + DOA, + CLKB, + ENB, + WEB, + ADDRB, + DIB, + DOB + ); + + // synopsys template + parameter PIPELINED = 0; + parameter ADDR_WIDTH = 1; + parameter DATA_WIDTH = 1; + parameter MEMSIZE = 1; + + input CLKA; + input ENA; + input WEA; + input [ADDR_WIDTH-1:0] ADDRA; + input [DATA_WIDTH-1:0] DIA; + output [DATA_WIDTH-1:0] DOA; + + input CLKB; + input ENB; + input WEB; + input [ADDR_WIDTH-1:0] ADDRB; + input [DATA_WIDTH-1:0] DIB; + output [DATA_WIDTH-1:0] DOB; + + reg [DATA_WIDTH-1:0] RAM[0:MEMSIZE-1] /* synthesis syn_ramstyle="no_rw_check" */ ; + reg [ADDR_WIDTH-1:0] ADDRA_R; + reg [ADDR_WIDTH-1:0] ADDRB_R; + reg [DATA_WIDTH-1:0] DOA_R; + reg [DATA_WIDTH-1:0] DOB_R; + + wire [DATA_WIDTH-1:0] DOA_noreg; + wire [DATA_WIDTH-1:0] DOB_noreg; + + wire [ADDR_WIDTH-1:0] ADDRA_muxed; + wire [ADDR_WIDTH-1:0] ADDRB_muxed; + + +`ifdef BSV_NO_INITIAL_BLOCKS +`else + // synopsys translate_off + integer i; + initial + begin : init_block + for (i = 0; i < MEMSIZE; i = i + 1) begin + RAM[i] = { ((DATA_WIDTH+1)/2) { 2'b10 } }; + end + ADDRA_R = { ((ADDR_WIDTH+1)/2) { 2'b10 } }; + ADDRB_R = { ((ADDR_WIDTH+1)/2) { 2'b10 } }; + DOA_R = { ((DATA_WIDTH+1)/2) { 2'b10 } }; + DOB_R = { ((DATA_WIDTH+1)/2) { 2'b10 } }; + end + // synopsys translate_on +`endif // !`ifdef BSV_NO_INITIAL_BLOCKS + + + always @(posedge CLKA) begin + ADDRA_R <= `BSV_ASSIGNMENT_DELAY ADDRA_muxed; + if (ENA) begin + if (WEA) + RAM[ADDRA_muxed] <= `BSV_ASSIGNMENT_DELAY DIA; + end + end + + always @(posedge CLKB) begin + ADDRB_R <= `BSV_ASSIGNMENT_DELAY ADDRB_muxed; + if (ENB) begin + if (WEB) + RAM[ADDRB_muxed] <= `BSV_ASSIGNMENT_DELAY DIB; + end + end + + + // ENA workaround for Synplify + assign ADDRA_muxed = (ENA) ? ADDRA : ADDRA_R; + assign ADDRB_muxed = (ENB) ? ADDRB : ADDRB_R; + + // Memory read + assign DOA_noreg = RAM[ADDRA_R]; + assign DOB_noreg = RAM[ADDRB_R]; + + // Pipeline + always @(posedge CLKA) + DOA_R <= DOA_noreg; + + always @(posedge CLKB) + DOB_R <= DOB_noreg; + + // Output drivers + assign DOA = (PIPELINED) ? DOA_R : DOA_noreg; + assign DOB = (PIPELINED) ? DOB_R : DOB_noreg; + +endmodule // BRAM2 diff --git a/Prims/.svn/text-base/BypassWire.v.svn-base b/Prims/.svn/text-base/BypassWire.v.svn-base new file mode 100644 index 0000000..8a7c134 --- /dev/null +++ b/Prims/.svn/text-base/BypassWire.v.svn-base @@ -0,0 +1,38 @@ + +// Copyright (c) 2000-2009 Bluespec, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// $Revision: 17872 $ +// $Date: 2009-09-18 14:32:56 +0000 (Fri, 18 Sep 2009) $ + + +module BypassWire(WGET, WVAL); + + // synopsys template + + parameter width = 1; + + input [width - 1 : 0] WVAL; + + output [width - 1 : 0] WGET; + + assign WGET = WVAL; + +endmodule diff --git a/Prims/.svn/text-base/DPSRAM.v.svn-base b/Prims/.svn/text-base/DPSRAM.v.svn-base new file mode 100644 index 0000000..d3b9931 --- /dev/null +++ b/Prims/.svn/text-base/DPSRAM.v.svn-base @@ -0,0 +1,65 @@ +module DPSRAM ( + Rd, + IdxR, + DoutR, + + We, + IdxW, + DinW, + clk, + rst_n + ); + + // synthesis attribute BRAM_MAP of DPSRAM is "yes"; + + parameter WIDTH = 1; + parameter ADDR_BITS = 9; + parameter DEPTH = 1< + * + * Description: + * 16-ported register file that maps to LUT RAM. Implements double-buffering + * internally. Automatically switches to other array when last address is + * written. + * + */ + +// Multi-ported Register File +module DoubleBufferedRegFile_16ports(CLK, rst_n, + ADDR_IN, D_IN, WE, + ADDR_1, D_OUT_1, + ADDR_2, D_OUT_2, + ADDR_3, D_OUT_3, + ADDR_4, D_OUT_4, + ADDR_5, D_OUT_5, + ADDR_6, D_OUT_6, + ADDR_7, D_OUT_7, + ADDR_8, D_OUT_8, + ADDR_9, D_OUT_9, + ADDR_10, D_OUT_10, + ADDR_11, D_OUT_11, + ADDR_12, D_OUT_12, + ADDR_13, D_OUT_13, + ADDR_14, D_OUT_14, + ADDR_15, D_OUT_15, + ADDR_16, D_OUT_16 + ); + + // synopsys template + parameter data_width = 208; + parameter addr_width = 8; + parameter depth = 1< hi) ) + $display( "Warning: RegFile: %m -- Address port 1 is out of bounds: %h", ADDR_1 ) ; + if (( ADDR_2 < lo ) || (ADDR_2 > hi) ) + $display( "Warning: RegFile: %m -- Address port 2 is out of bounds: %h", ADDR_2 ) ; + if (( ADDR_3 < lo ) || (ADDR_3 > hi) ) + $display( "Warning: RegFile: %m -- Address port 3 is out of bounds: %h", ADDR_3 ) ; + if (( ADDR_4 < lo ) || (ADDR_4 > hi) ) + $display( "Warning: RegFile: %m -- Address port 4 is out of bounds: %h", ADDR_4 ) ; + if (( ADDR_5 < lo ) || (ADDR_5 > hi) ) + $display( "Warning: RegFile: %m -- Address port 5 is out of bounds: %h", ADDR_5 ) ; + if ( WE && ( ADDR_IN < lo ) || (ADDR_IN > hi) ) + $display( "Warning: RegFile: %m -- Write Address port is out of bounds: %h", ADDR_IN ) ; + end + end + // synopsys translate_on + +endmodule + diff --git a/Prims/.svn/text-base/RegFileLoadSyn.bsv.svn-base b/Prims/.svn/text-base/RegFileLoadSyn.bsv.svn-base new file mode 100644 index 0000000..08467f4 --- /dev/null +++ b/Prims/.svn/text-base/RegFileLoadSyn.bsv.svn-base @@ -0,0 +1,38 @@ +import RegFile::*; + +module mkRegFileLoadSyn#(String filename)(RegFile#(index,data)) + provisos( Bounded#(index), + Bits#(index, a__), + Bits#(data, b__)); + RegFile#(index,data) rf; + if(genVerilog) begin + rf <- mkRegFileLoadSynVerilog(filename); + end + else begin + rf <- mkRegFileFullLoad(filename); + end + return rf; +endmodule + +import "BVI" RegFileLoadSyn = module mkRegFileLoadSynVerilog#(String filename)(RegFile#(index, data)); + + default_clock clk(CLK, (*unused*) clk_gate); + default_reset( RST_N ); + + parameter file = filename; + parameter addr_width = fromInteger(valueOf(SizeOf#(index))); + parameter data_width = fromInteger(valueOf(SizeOf#(data))); + parameter lo = 0; + parameter hi = fromInteger(valueOf(TExp#(SizeOf#(index))))-1; + parameter binary = 0; + + method D_OUT_1 sub(ADDR_1); + method upd(ADDR_IN, D_IN) enable(WE); + schedule (sub, upd) CF (sub, upd); + +endmodule + +module mkRfSynTest(RegFile#(Bit#(5), Bit#(64))); + let rf <- mkRegFileLoadSyn("zeros.hex"); + return rf; +endmodule diff --git a/Prims/.svn/text-base/RegFileLoadSyn.v.svn-base b/Prims/.svn/text-base/RegFileLoadSyn.v.svn-base new file mode 100644 index 0000000..3c6a12c --- /dev/null +++ b/Prims/.svn/text-base/RegFileLoadSyn.v.svn-base @@ -0,0 +1,38 @@ +module RegFileLoadSyn + (CLK, RST_N, + ADDR_IN, D_IN, WE, + ADDR_1, D_OUT_1 + ); + + parameter file = ""; + parameter addr_width = 1; + parameter data_width = 1; + parameter lo = 0; + parameter hi = 1; + parameter binary = 0; + + input CLK; + input RST_N; + input [addr_width - 1 : 0] ADDR_IN; + input [data_width - 1 : 0] D_IN; + input WE; + + input [addr_width - 1 : 0] ADDR_1; + output [data_width - 1 : 0] D_OUT_1; + + reg [data_width - 1 : 0] arr[lo:hi]; + + initial + begin : init_block + $readmemh(file, arr, lo, hi); + end + + always@(posedge CLK) + begin + if (WE && RST_N) + arr[ADDR_IN] <= D_IN; + end // always@ (posedge CLK) + + assign D_OUT_1 = arr[ADDR_1]; + +endmodule diff --git a/Prims/.svn/text-base/RegFileMultiport.bsv.svn-base b/Prims/.svn/text-base/RegFileMultiport.bsv.svn-base new file mode 100644 index 0000000..5018bb6 --- /dev/null +++ b/Prims/.svn/text-base/RegFileMultiport.bsv.svn-base @@ -0,0 +1,211 @@ +import RegFile::*; +import Vector::*; +import ConfigReg::*; +import RegFileLoadSyn::*; + +interface RegFileRead#(type addr, type data); + method data sub(addr a); +endinterface + +interface RegFileWrite#(type addr, type data); + method Action upd(addr a, data d); +endinterface + +interface RegFileMultiport#(numeric type nr, numeric type nw, type addr, type data); + interface Vector#(nr, RegFileRead#(addr,data)) r; + interface Vector#(nw, RegFileWrite#(addr,data)) w; +endinterface + +interface RegFile_1W_nR#(numeric type nr, type addr, type data); + interface RegFileWrite#(addr, data) w; + interface Vector#(nr, RegFileRead#(addr, data)) r; +endinterface + + +module mkRegFile_1W_nR(RegFile_1W_nR#(nr, addr, data)) + provisos(Bits#(addr, addr_nt), + Bits#(data, data_nt), + Bounded#(addr), + PrimIndex#(addr, a__) + ); + + Vector#(nr, RegFile#(addr, data)) banks <- replicateM(mkRegFileLoadSyn("zeros.hex")); + Vector#(nr, RegFileRead#(addr,data)) r_ifaces; + + for(Integer i=0; i < valueOf(nr); i=i+1) begin + let r_ifc = interface RegFileRead + method data sub(addr a); + return banks[i].sub(a); + endmethod + endinterface; + + r_ifaces[i] = r_ifc; + end + + interface RegFileWrite w; + method Action upd(addr a, data d); + for(Integer i=0; i < valueOf(nr); i=i+1) begin + banks[i].upd(a, d); + end + endmethod + endinterface + + interface r = r_ifaces; + +endmodule + + + + + +module mkRegFileMultiport(RegFileMultiport#(nr, nw, addr, data)) + provisos(Bits#(addr, addr_nt), + Bits#(data, data_nt), + Bounded#(addr), + PrimIndex#(addr, a__) + ); + + Vector#(nw, RegFile_1W_nR#(nr, addr, data)) banks <- replicateM(mkRegFile_1W_nR); + Vector#(TExp#(addr_nt), Reg#(Bit#(TLog#(nw)))) lvt <- replicateM(mkConfigRegU); + + Vector#(nw, RegFileWrite#(addr,data)) w_ifaces; + Vector#(nr, RegFileRead#(addr,data)) r_ifaces; + + for(Integer i=0; i < valueOf(nw); i=i+1) begin + let w_ifc = interface RegFileWrite + method Action upd(addr a, data d); + banks[i].w.upd(a, d); + lvt[a] <= fromInteger(i); + endmethod + endinterface; + w_ifaces[i] = w_ifc; + end + + for(Integer i=0; i < valueOf(nr); i=i+1) begin + let r_ifc = interface RegFileRead + method data sub(addr a); + let pick = lvt[a]; + return banks[pick].r[i].sub(a); + endmethod + endinterface; + r_ifaces[i] = r_ifc; + end + + interface w = w_ifaces; + interface r = r_ifaces; + +endmodule + + +module mkRegFileMultiportBrute(RegFileMultiport#(nr, nw, addr, data)) + provisos(Bits#(addr, addr_nt), + Bits#(data, data_nt), + Bounded#(addr), + PrimIndex#(addr, a__) + ); + + Vector#(TExp#(addr_nt), Reg#(data)) store <- replicateM(mkConfigRegU); + Vector#(nw, RegFileWrite#(addr,data)) w_ifaces; + Vector#(nr, RegFileRead#(addr,data)) r_ifaces; + + for(Integer i=0; i < valueOf(nw); i=i+1) begin + let w_ifc = interface RegFileWrite + method Action upd(addr a, data d); + store[a]<=d; + endmethod + endinterface; + w_ifaces[i] = w_ifc; + end + + for(Integer i=0; i < valueOf(nr); i=i+1) begin + let r_ifc = interface RegFileRead + method data sub(addr a); + return store[a]; + endmethod + endinterface; + r_ifaces[i] = r_ifc; + end + + interface w = w_ifaces; + interface r = r_ifaces; + +endmodule + + +//////////////////////////////////////////////////////// +// papamix: Added version that load init file + +module mkRegFile_1W_nR_Load#(String loadfile) + (RegFile_1W_nR#(nr, addr, data)) + provisos(Bits#(addr, addr_nt), + Bits#(data, data_nt), + Bounded#(addr), + PrimIndex#(addr, a__) + ); + + Vector#(nr, RegFile#(addr, data)) banks <- replicateM(mkRegFileLoadSyn(loadfile)); + Vector#(nr, RegFileRead#(addr,data)) r_ifaces; + + for(Integer i=0; i < valueOf(nr); i=i+1) begin + let r_ifc = interface RegFileRead + method data sub(addr a); + return banks[i].sub(a); + endmethod + endinterface; + + r_ifaces[i] = r_ifc; + end + + interface RegFileWrite w; + method Action upd(addr a, data d); + for(Integer i=0; i < valueOf(nr); i=i+1) begin + banks[i].upd(a, d); + end + endmethod + endinterface + + interface r = r_ifaces; + +endmodule + + +module mkRegFileMultiportLoad#(String loadfile) + (RegFileMultiport#(nr, nw, addr, data)) + provisos(Bits#(addr, addr_nt), + Bits#(data, data_nt), + Bounded#(addr), + PrimIndex#(addr, a__) + ); + + Vector#(nw, RegFile_1W_nR#(nr, addr, data)) banks <- replicateM(mkRegFile_1W_nR_Load(loadfile)); + Vector#(TExp#(addr_nt), Reg#(Bit#(TLog#(nw)))) lvt <- replicateM(mkConfigRegU); + + Vector#(nw, RegFileWrite#(addr,data)) w_ifaces; + Vector#(nr, RegFileRead#(addr,data)) r_ifaces; + + for(Integer i=0; i < valueOf(nw); i=i+1) begin + let w_ifc = interface RegFileWrite + method Action upd(addr a, data d); + banks[i].w.upd(a, d); + lvt[a] <= fromInteger(i); + endmethod + endinterface; + w_ifaces[i] = w_ifc; + end + + for(Integer i=0; i < valueOf(nr); i=i+1) begin + let r_ifc = interface RegFileRead + method data sub(addr a); + let pick = lvt[a]; + return banks[pick].r[i].sub(a); + endmethod + endinterface; + r_ifaces[i] = r_ifc; + end + + interface w = w_ifaces; + interface r = r_ifaces; + +endmodule + + diff --git a/Prims/.svn/text-base/RegFile_16ports.v.svn-base b/Prims/.svn/text-base/RegFile_16ports.v.svn-base new file mode 100644 index 0000000..a7d8f50 --- /dev/null +++ b/Prims/.svn/text-base/RegFile_16ports.v.svn-base @@ -0,0 +1,146 @@ +/* + * ========================================================================= + * + * Filename: RegFile_16ports.v + * Date created: 03-29-2011 + * Last modified: 03-29-2011 + * Authors: Michael Papamichael + * + * Description: + * 16-ported register file that maps to LUT RAM. + * + */ + +// Multi-ported Register File +module RegFile_16ports(CLK, rst_n, + ADDR_IN, D_IN, WE, + ADDR_1, D_OUT_1, + ADDR_2, D_OUT_2, + ADDR_3, D_OUT_3, + ADDR_4, D_OUT_4, + ADDR_5, D_OUT_5, + ADDR_6, D_OUT_6, + ADDR_7, D_OUT_7, + ADDR_8, D_OUT_8, + ADDR_9, D_OUT_9, + ADDR_10, D_OUT_10, + ADDR_11, D_OUT_11, + ADDR_12, D_OUT_12, + ADDR_13, D_OUT_13, + ADDR_14, D_OUT_14, + ADDR_15, D_OUT_15, + ADDR_16, D_OUT_16 + ); + + // synopsys template + parameter data_width = 1; + parameter addr_width = 1; + parameter depth = 1< + * + * Description: + * 16-ported register file that maps to LUT RAM. + * + */ + +// Multi-ported Register File +module RegFile_16ports_load(CLK, rst_n, + ADDR_IN, D_IN, WE, + ADDR_1, D_OUT_1, + ADDR_2, D_OUT_2, + ADDR_3, D_OUT_3, + ADDR_4, D_OUT_4, + ADDR_5, D_OUT_5, + ADDR_6, D_OUT_6, + ADDR_7, D_OUT_7, + ADDR_8, D_OUT_8, + ADDR_9, D_OUT_9, + ADDR_10, D_OUT_10, + ADDR_11, D_OUT_11, + ADDR_12, D_OUT_12, + ADDR_13, D_OUT_13, + ADDR_14, D_OUT_14, + ADDR_15, D_OUT_15, + ADDR_16, D_OUT_16 + ); + + // synopsys template + parameter data_width = 1; + parameter addr_width = 1; + parameter loadfile = ""; + parameter binary = 0; + //parameter lo = 0; + //parameter hi = 1; + parameter depth = 1<= 2) ? (p2depth2) : 0)]; + + reg [p1width - 1 : 0] D_OUT; + reg hasodata; + + wire [p3cntr_width-1:0] depthLess2 = p2depth2[p3cntr_width-1:0] ; + + wire [p3cntr_width-1 : 0] incr_tail; + wire [p3cntr_width-1 : 0] incr_head; + + assign incr_tail = tail + 1'b1 ; + assign incr_head = head + 1'b1 ; + + assign next_head = (head == depthLess2 ) ? {p3cntr_width{1'b0}} : incr_head ; + assign next_tail = (tail == depthLess2 ) ? {p3cntr_width{1'b0}} : incr_tail ; + + assign EMPTY_N = hasodata; + assign FULL_N = not_ring_full; + +`ifdef BSV_NO_INITIAL_BLOCKS +`else // not BSV_NO_INITIAL_BLOCKS + // synopsys translate_off + initial + begin : initial_block + integer i; + D_OUT = {((p1width + 1)/2){2'b10}} ; + + ring_empty = 1'b1; + not_ring_full = 1'b1; + hasodata = 1'b0; + head = {p3cntr_width {1'b0}} ; + tail = {p3cntr_width {1'b0}} ; + + for (i = 0; i <= p2depth2 && p2depth > 2; i = i + 1) + begin + arr[i] = D_OUT ; + end + end + // synopsys translate_on +`endif // BSV_NO_INITIAL_BLOCKS + + always @(posedge CLK /* or negedge RST_N */ ) + begin + if (!RST_N) + begin + head <= `BSV_ASSIGNMENT_DELAY {p3cntr_width {1'b0}} ; + tail <= `BSV_ASSIGNMENT_DELAY {p3cntr_width {1'b0}} ; + ring_empty <= `BSV_ASSIGNMENT_DELAY 1'b1; + not_ring_full <= `BSV_ASSIGNMENT_DELAY 1'b1; + hasodata <= `BSV_ASSIGNMENT_DELAY 1'b0; + + // Following section initializes the data registers which + // may be desired only in some situations. + // Uncomment to initialize array + /* + D_OUT <= `BSV_ASSIGNMENT_DELAY {p1width {1'b0}} ; + for (i = 0; i <= p2depth2 && p2depth > 2; i = i + 1) + begin + arr[i] <= `BSV_ASSIGNMENT_DELAY {p1width {1'b0}} ; + end + */ + end // if (RST_N == 0) + else + begin + + // Update arr[tail] once, since some FPGA synthesis tools are unable + // to infer good RAM placement when there are multiple separate + // writes of arr[tail] <= D_IN + if (!CLR && ENQ && ((DEQ && !ring_empty) || (!DEQ && hasodata && not_ring_full))) + begin + arr[tail] <= `BSV_ASSIGNMENT_DELAY D_IN; + end + + if (CLR) + begin + head <= `BSV_ASSIGNMENT_DELAY {p3cntr_width {1'b0}} ; + tail <= `BSV_ASSIGNMENT_DELAY {p3cntr_width {1'b0}} ; + ring_empty <= `BSV_ASSIGNMENT_DELAY 1'b1; + not_ring_full <= `BSV_ASSIGNMENT_DELAY 1'b1; + hasodata <= `BSV_ASSIGNMENT_DELAY 1'b0; + end // if (CLR) + + else if (DEQ && ENQ ) + begin + if (ring_empty) + begin + D_OUT <= `BSV_ASSIGNMENT_DELAY D_IN; + end + else + begin + // moved into combined write above + // arr[tail] <= `BSV_ASSIGNMENT_DELAY D_IN; + tail <= `BSV_ASSIGNMENT_DELAY next_tail; + D_OUT <= `BSV_ASSIGNMENT_DELAY arr[head]; + head <= `BSV_ASSIGNMENT_DELAY next_head; + end + end // if (DEQ && ENQ ) + + else if ( DEQ ) + begin + if (ring_empty) + begin + hasodata <= `BSV_ASSIGNMENT_DELAY 1'b0; + end + else + begin + D_OUT <= `BSV_ASSIGNMENT_DELAY arr[head]; + head <= `BSV_ASSIGNMENT_DELAY next_head; + not_ring_full <= `BSV_ASSIGNMENT_DELAY 1'b1; + ring_empty <= `BSV_ASSIGNMENT_DELAY next_head == tail ; + end + end // if ( DEQ ) + + else if (ENQ) + begin + if (! hasodata) + begin + D_OUT <= `BSV_ASSIGNMENT_DELAY D_IN; + hasodata <= `BSV_ASSIGNMENT_DELAY 1'b1; + end + else if ( not_ring_full ) // Drop this test to save redundant test + // but be warnned that with test fifo overflow causes loss of new data + // while without test fifo drops all but head entry! (pointer overflow) + begin + // moved into combined write above + // arr[tail] <= `BSV_ASSIGNMENT_DELAY D_IN; // drop the old element + tail <= `BSV_ASSIGNMENT_DELAY next_tail; + ring_empty <= `BSV_ASSIGNMENT_DELAY 1'b0; + not_ring_full <= `BSV_ASSIGNMENT_DELAY ! (next_tail == head) ; + end + end // if (ENQ) + end // else: !if(RST_N == 0) + + end // always @ (posedge CLK) + + // synopsys translate_off + always@(posedge CLK) + begin: error_checks + reg deqerror, enqerror ; + + deqerror = 0; + enqerror = 0; + if ( RST_N ) + begin + if ( ! EMPTY_N && DEQ ) + begin + deqerror = 1 ; + $display( "Warning: SizedFIFO: %m -- Dequeuing from empty fifo" ) ; + end + if ( ! FULL_N && ENQ && (!DEQ || guarded) ) + begin + enqerror = 1 ; + $display( "Warning: SizedFIFO: %m -- Enqueuing to a full fifo" ) ; + end + end + end // block: error_checks + // synopsys translate_on + + // synopsys translate_off + // Some assertions about parameter values + initial + begin : parameter_assertions + integer ok ; + ok = 1 ; + + if ( p2depth <= 2 ) + begin + ok = 0; + $display ( "ERROR SizedFIFO.v: depth parameter must be greater than 2" ) ; + end + + if ( p3cntr_width <= 0 ) + begin + ok = 0; + $display ( "ERROR SizedFIFO.v: width parameter must be greater than 0" ) ; + end + + if ( ok == 0 ) $finish ; + + end // initial begin + // synopsys translate_on + +endmodule diff --git a/Prims/.svn/text-base/Xbar.bsv.svn-base b/Prims/.svn/text-base/Xbar.bsv.svn-base new file mode 100644 index 0000000..00e0611 --- /dev/null +++ b/Prims/.svn/text-base/Xbar.bsv.svn-base @@ -0,0 +1,61 @@ +import Vector::*; +interface XbarVerilog#(numeric type n, + numeric type nvc, + numeric type cut, + numeric type dwidth, + numeric type buffer_depth); + + (* always_ready *) + method Action iports(Vector#(n, Bool) i_valid, + Vector#(n, Bool) i_prio, + Vector#(n, Bool) i_tail, + Vector#(n, Bit#(TLog#(n))) i_dst, + Vector#(n, Bit#(TLog#(nvc))) i_vc, + Vector#(n, Bit#(dwidth)) i_data); + + (* always_ready *) method Vector#(n, Bool) o_valid; + (* always_ready *) method Vector#(n, Bool) o_prio; + (* always_ready *) method Vector#(n, Bool) o_tail; + (* always_ready *) method Vector#(n, Bit#(TLog#(n))) o_dst; + (* always_ready *) method Vector#(n, Bit#(TLog#(nvc))) o_vc; + (* always_ready *) method Vector#(n, Bit#(dwidth)) o_data; + + (* always_ready *) method Vector#(n, Bit#(TLog#(nvc))) i_cred; + (* always_ready *) method Vector#(n, Bool) i_cred_valid; + (* always_ready *) method Action o_cred(Vector#(n, Bool) en); + +endinterface + +import "BVI" Xbar = module mkXbarVerilog(XbarVerilog#(n, nvc, cut, dwidth, buffer_depth)); + + default_clock clk(CLK, (*unused*) clk_gate); + + parameter N = fromInteger(valueOf(n)); + parameter NUM_VCS = fromInteger(valueOf(nvc)); + parameter CUT = fromInteger(valueOf(cut)); + parameter DATA = fromInteger(valueOf(dwidth)); + parameter BUFFER_DEPTH = fromInteger(valueOf(buffer_depth)); + + method iports(i_valid, i_prio, i_tail, i_dst, i_vc, i_data) enable((*inhigh*)True); + method o_valid o_valid; + method o_prio o_prio; + method o_tail o_tail; + method o_dst o_dst; + method o_vc o_vc; + method o_data o_data; + method i_cred i_cred; + method i_cred_valid i_cred_valid; + method o_cred(o_cred_en) enable((*inhigh*)True2); + + schedule (iports, o_valid, o_prio, o_tail, o_dst, o_vc, o_data, i_cred, i_cred_valid, o_cred) CF + (iports, o_valid, o_prio, o_tail, o_dst, o_vc, o_data, i_cred, i_cred_valid, o_cred); + +endmodule + +/* +(* synthesize *) +module mkXbarVerilogSynth(XbarVerilog#(4,2,1,32,16)); + let xbar <- mkXbarVerilog; + return xbar; +endmodule +*/ diff --git a/Prims/.svn/text-base/Xbar.v.svn-base b/Prims/.svn/text-base/Xbar.v.svn-base new file mode 100644 index 0000000..98e3871 --- /dev/null +++ b/Prims/.svn/text-base/Xbar.v.svn-base @@ -0,0 +1,355 @@ +`define clogb2(x) (\ + x <= 1 ? 0: \ + x <= 2 ? 1: \ + x <= 4 ? 2: \ + x <= 8 ? 3: \ + x <= 16 ? 4: \ + x <= 32 ? 5: \ + x <= 64 ? 6: \ + x <= 128 ? 7: \ + x <= 256 ? 8 : \ + x <= 512 ? 9 : \ + x <= 1024 ? 10 : \ + x <= 2048 ? 11 : \ + x <= 4096 ? 12 : \ + x <= 8192 ? 13 : \ + x <= 16384 ? 14 : -1) + +module XbarArbiter(CLK, RST_N, raises, grant, valid); + + parameter N=4; + + input CLK; + input RST_N; + input [N-1:0] raises; + output reg [N-1:0] grant; + output reg valid; + + function [1:0] gen_grant_carry; + input c, r, p; + begin + gen_grant_carry[1] = ~r & (c | p); + gen_grant_carry[0] = r & (c | p); + end + endfunction + + reg [N-1:0] token; + reg [N-1:0] granted_A; + reg [N-1:0] granted_B; + reg carry; + reg [1:0] gc; + + integer i; + + + always@(*) begin + valid = 1'b0; + grant = 0; + carry = 0; + granted_A = 0; + granted_B = 0; + + // Arbiter 1 + for(i=0; i < N; i=i+1) begin + gc = gen_grant_carry(carry, raises[i], token[i]); + granted_A[i] = gc[0]; + carry = gc[1]; + end + + // Arbiter 2 (uses the carry from Arbiter 1) + for(i=0; i < N; i=i+1) begin + gc = gen_grant_carry(carry, raises[i], token[i]); + granted_B[i] = gc[0]; + carry = gc[1]; + end + + for(i=0; i < N; i=i+1) begin + if(granted_A[i] | granted_B[i]) begin + grant = 0; + grant[i] = 1'b1; + valid = 1'b1; + end + end + end + + always@(posedge CLK) begin + if(RST_N) token <= {token[N-2:0], token[N-1]}; + else token <= 1; + end + +endmodule + + +module Xbar(CLK, RST_N, + i_valid, + i_prio, + i_tail, + i_dst, + i_vc, + i_data, + + o_valid, + o_prio, + o_tail, + o_dst, + o_vc, + o_data, + + i_cred, + i_cred_valid, + + o_cred_en + ); + + parameter N = 16; + parameter NUM_VCS = 2; + parameter CUT = 2; + parameter DATA = 32; + parameter BUFFER_DEPTH = 16; + + parameter LOG_N = `clogb2(N); + parameter VC = `clogb2(NUM_VCS); + parameter DST = `clogb2(N); + parameter FLIT_WIDTH = 1+1+DST+VC+DATA; + parameter CRED_WIDTH = `clogb2(BUFFER_DEPTH) + 1; + + input CLK, RST_N; + + // Input ports + input [N-1:0] i_valid; + input [N-1:0] i_prio; + input [N-1:0] i_tail; + input [N*DST-1:0] i_dst; + input [N*VC-1:0] i_vc; + input [N*DATA-1:0] i_data; + + wire [VC-1:0] i_vc_arr [N-1:0]; + + // Input queue front ports + wire [N-1:0] f_prio; + wire [N-1:0] f_tail; + wire [DST-1:0] f_dst [N-1:0]; + wire [VC-1:0] f_vc [N-1:0]; + wire [DATA-1:0] f_data [N-1:0]; + wire [N-1:0] f_elig; + + // Needed to play friendly with Icarus Verilog and Modelsim + wire [DST*N-1:0] f_dst_flat; + wire [VC*N-1:0] f_vc_flat; + wire [DATA*N-1:0] f_data_flat; + + // Output ports + output reg [N-1:0] o_valid; + output reg [N-1:0] o_prio; + output reg [N-1:0] o_tail; + output [N*DST-1:0] o_dst; + output [N*VC-1:0] o_vc; + output [N*DATA-1:0] o_data; + + reg [DST-1:0] o_dst_arr [N-1:0]; + reg [VC-1:0] o_vc_arr [N-1:0]; + reg [DATA-1:0] o_data_arr [N-1:0]; + + // Input credit + output [N*VC-1:0] i_cred; // just remembers the VC of 1st packet that arrives + output reg [N-1:0] i_cred_valid; // maybe bit + reg [VC-1:0] i_cred_arr [N-1:0]; + + // Output credit + input [N-1:0] o_cred_en; + + // Dequeue wires + wire [N-1:0] grants [N-1:0]; + wire [N-1:0] grant_valids; + reg [N-1:0] deq_en; + + reg [CRED_WIDTH-1:0] creds_left [N-1:0]; + + genvar i, o, k; + integer in,out; + + generate + for(o=0; o < N; o=o+1) begin: arbiters + wire [N-1:0] raises; + + for(k=0; k < N; k=k+1) begin: raisewires + assign raises[k] = (f_dst[k] == o) && f_elig[k]; + end + + XbarArbiter#(.N(N)) arbiter(.CLK(CLK), + .RST_N(RST_N), + .raises(raises), + .valid(grant_valids[o]), + .grant(grants[o])); // [(o+1)*LOG_N-1:o*LOG_N])); + + + + end + endgenerate + + + /* + // Stats + always@(negedge CLK) begin + if(RST_N) begin + for(in=0; in < N; in=in+1) begin + if(f_elig[in]) + $display("strace time=%0d component=noc inst=0 evt=raises val=1", $time); + + if(deq_en[in] != 0) + $display("strace time=%0d component=noc inst=0 evt=grants val=1", $time); + //$display("strace time=%0d component=noc inst=0 evt=full val=1", $time); + end + end + end + */ + + // Record the input VC + always@(posedge CLK) begin + if(RST_N) begin + for(in=0; in < N; in=in+1) begin + if(i_valid[in]) + i_cred_arr[in] <= i_vc_arr[in]; + end + end + else begin + for(in=0; in < N; in=in+1) begin + i_cred_arr[in]<='hx; + end + end + end + + for(i=0; i < N; i=i+1) begin: assign_arr + assign i_vc_arr[i] = i_vc[(i+1)*VC-1:i*VC]; + assign i_cred[(i+1)*VC-1:i*VC] = i_cred_arr[i]; + assign o_dst[(i+1)*DST-1:i*DST] = o_dst_arr[i]; + assign o_vc[(i+1)*VC-1:i*VC] = o_vc_arr[i]; + assign o_data[(i+1)*DATA-1:i*DATA] = o_data_arr[i]; + end + + // Enable deq + always@(*) begin + for(in=0; in < N; in=in+1) begin: deqwires + deq_en[in] = 1'b0; + i_cred_valid[in] = 1'b0; + + for(out=0; out < N; out=out+1) begin: outer + if(grant_valids[out] && (grants[out][in] == 1'b1) && (creds_left[out] != 0)) begin + deq_en[in] = 1'b1; + i_cred_valid[in] = 1'b1; + end + end + end + end + + // Needed to play friendly with Icarus Verilog + for(i=0; i < N; i=i+1) begin + assign f_dst_flat[(i+1)*DST-1:i*DST] = f_dst[i]; + assign f_vc_flat[(i+1)*VC-1:i*VC] = f_vc[i]; + assign f_data_flat[(i+1)*DATA-1:i*DATA] = f_data[i]; + end + + // Muxbar + for(i=0; i < N; i=i+1) begin: steerwires + always@(grant_valids[i] or grants[i] or creds_left[i] or f_prio or f_tail or f_dst_flat or f_vc_flat or f_data_flat) begin + o_valid[i] = 1'b0; + o_prio[i] = 'hx; + o_tail[i] = 'hx; + o_dst_arr[i] = 'hx; + o_vc_arr[i] = 'hx; + o_data_arr[i] = 'hx; + + for(in=0; in < N; in=in+1) begin: innersteer + if(grant_valids[i] && (grants[i][in] == 1'b1) && (creds_left[i] != 0)) begin + o_valid[i] = 1'b1; + o_prio[i] = f_prio[in]; + o_tail[i] = f_tail[in]; + o_dst_arr[i] = f_dst[in]; + o_vc_arr[i] = f_vc[in]; + o_data_arr[i] = f_data[in]; + end + end + end + end + + + /* + // Muxbar + always@(*) begin + for(out=0; out < N; out=out+1) begin: steerwires + o_valid[out] = 1'b0; + o_prio[out] = 'hx; + o_tail[out] = 'hx; + o_dst_arr[out] = 'hx; + o_vc_arr[out] = 'hx; + o_data_arr[out] = 'hx; + + for(in=0; in < N; in=in+1) begin: innersteer + if(grant_valids[out] && (grants[out][in] == 1'b1) && (creds_left[out] != 0)) begin + o_valid[out] = 1'b1; + o_prio[out] = f_prio[in]; + o_tail[out] = f_tail[in]; + o_dst_arr[out] = f_dst[in]; + o_vc_arr[out] = f_vc[in]; + o_data_arr[out] = f_data[in]; + end + end + end + end + */ + + // Transmit credits + for(o=0; o < N; o=o+1) begin: output_credits + always@(posedge CLK) begin + if(RST_N) begin + if((o_cred_en[o] == 1'b0) && (o_valid[o] == 1'b1)) + creds_left[o] <= creds_left[o] - 1; + else if((o_cred_en[o] == 1'b1) && (o_valid[o] == 1'b0)) + creds_left[o] <= creds_left[o] + 1; + end + else begin + creds_left[o] <= BUFFER_DEPTH; + end + end + end + + ///////////////////////// + // Input Queues + ///////////////////////// + + generate + for(i=0; i < N; i=i+1) begin: ififos +/* + SizedFIFO#(.p1width(FLIT_WIDTH), .p2depth(BUFFER_DEPTH), .p3cntr_width(`clogb2(BUFFER_DEPTH))) inQ + (.CLK(CLK), + .RST_N(RST_N), + .D_IN({i_prio[i], i_tail[i], i_dst[(i+1)*DST-1:i*DST], i_vc[(i+1)*VC-1:i*VC], i_data[(i+1)*DATA-1:i*DATA]}), + .ENQ(i_valid[i]), + .D_OUT({f_prio[i], f_tail[i], f_dst[i], f_vc[i], f_data[i]}), + .DEQ(deq_en[i]), + .EMPTY_N(f_elig[i]), + .FULL_N(), // unused + .CLR(1'b0) // unused + ); +*/ + mkNetworkXbarQ inQ(.CLK(CLK), .RST_N(RST_N), + .enq_sendData({i_prio[i], i_tail[i], i_dst[(i+1)*DST-1:i*DST], i_vc[(i+1)*VC-1:i*VC], i_data[(i+1)*DATA-1:i*DATA]}), + .EN_enq(i_valid[i]), + .RDY_enq(), + .EN_deq(deq_en[i]), + .RDY_deq(), + .first({f_prio[i], f_tail[i], f_dst[i], f_vc[i], f_data[i]}), + .RDY_first(), + .notFull(), + .RDY_notFull(), + .notEmpty(f_elig[i]), + .RDY_notEmpty(), + .count(), + .RDY_count(), + .EN_clear(1'b0), + .RDY_clear()); + + end + endgenerate + +endmodule diff --git a/Prims/.svn/text-base/shift_8x64.v.svn-base b/Prims/.svn/text-base/shift_8x64.v.svn-base new file mode 100644 index 0000000..f9faceb --- /dev/null +++ b/Prims/.svn/text-base/shift_8x64.v.svn-base @@ -0,0 +1,36 @@ +module shift_8x64_taps (clk, + shift, + sr_in, + sr_out, + sr_tap_one, + sr_tap_two, + sr_tap_three + ); + + input clk, shift; + + input [7:0] sr_in; + output [7:0] sr_tap_one, sr_tap_two, sr_tap_three, sr_out; + + reg [7:0] sr [63:0]; + integer n; + + always@(posedge clk) + begin + if (shift == 1'b1) + begin + for (n = 63; n>0; n = n-1) + begin + sr[n] <= sr[n-1]; + end + + sr[0] <= sr_in; + end + end + + assign sr_tap_one = sr[15]; + assign sr_tap_two = sr[31]; + assign sr_tap_three = sr[47]; + assign sr_out = sr[63]; + +endmodule diff --git a/Prims/.svn/text-base/shift_reg.v.svn-base b/Prims/.svn/text-base/shift_reg.v.svn-base new file mode 100644 index 0000000..13714c1 --- /dev/null +++ b/Prims/.svn/text-base/shift_reg.v.svn-base @@ -0,0 +1,52 @@ +module shift_reg (clk, + rst_n, + shift, + sr_in, + sr_out + ); + + parameter WIDTH = 64; + parameter STAGES = 16; + input clk, rst_n, shift; + + input [WIDTH-1:0] sr_in; + output [WIDTH-1:0] sr_out; + //output [7:0] sr_tap_one, sr_tap_two, sr_tap_three, sr_out; + + reg [WIDTH-1:0] sr [STAGES-1:0]; + integer n; + + // initialize + initial begin + for (n = 0; n0; n = n-1) + begin + sr[n] <= sr[n-1]; + end + + sr[0] <= sr_in; + end + //end + end + + assign sr_out = sr[STAGES-1]; + +endmodule diff --git a/Prims/.svn/text-base/testbench_sample.v.svn-base b/Prims/.svn/text-base/testbench_sample.v.svn-base new file mode 100644 index 0000000..9a6b016 --- /dev/null +++ b/Prims/.svn/text-base/testbench_sample.v.svn-base @@ -0,0 +1,151 @@ +/* ========================================================================= + * + * Filename: testbench_sample.v + * Date created: 05-28-2012 + * Last modified: 06-09-2012 + * Authors: Michael Papamichael + * + * Description: + * Minimal testbench sample for CONNECT networks + * + * ========================================================================= + */ + +`ifndef XST_SYNTH + +`timescale 1ns / 1ps + +`include "connect_parameters.v" + + +module CONNECT_testbench_sample(); + parameter HalfClkPeriod = 5; + localparam ClkPeriod = 2*HalfClkPeriod; + + // non-VC routers still reeserve 1 dummy bit for VC. + localparam vc_bits = (`NUM_VCS > 1) ? $clog2(`NUM_VCS) : 1; + localparam dest_bits = $clog2(`NUM_USER_RECV_PORTS); + localparam flit_port_width = 2 /*valid and tail bits*/+ `FLIT_DATA_WIDTH + dest_bits + vc_bits; + localparam credit_port_width = 1 + vc_bits; // 1 valid bit + localparam test_cycles = 20; + + reg Clk; + reg Rst_n; + + // input regs + reg send_flit [0:`NUM_USER_SEND_PORTS-1]; // enable sending flits + reg [flit_port_width-1:0] flit_in [0:`NUM_USER_SEND_PORTS-1]; // send port inputs + + reg send_credit [0:`NUM_USER_RECV_PORTS-1]; // enable sending credits + reg [credit_port_width-1:0] credit_in [0:`NUM_USER_RECV_PORTS-1]; //recv port credits + + // output wires + wire [credit_port_width-1:0] credit_out [0:`NUM_USER_SEND_PORTS-1]; + wire [flit_port_width-1:0] flit_out [0:`NUM_USER_RECV_PORTS-1]; + + reg [31:0] cycle; + integer i; + + // packet fields + reg is_valid; + reg is_tail; + reg [dest_bits-1:0] dest; + reg [vc_bits-1:0] vc; + reg [`FLIT_DATA_WIDTH-1:0] data; + + // Generate Clock + initial Clk = 0; + always #(HalfClkPeriod) Clk = ~Clk; + + // Run simulation + initial begin + cycle = 0; + for(i = 0; i < `NUM_USER_SEND_PORTS; i = i + 1) begin flit_in[i] = 0; send_flit[i] = 0; end + for(i = 0; i < `NUM_USER_RECV_PORTS; i = i + 1) begin credit_in[i] = 0; send_credit[i] = 0; end + + $display("---- Performing Reset ----"); + Rst_n = 0; // perform reset (active low) + #(5*ClkPeriod+HalfClkPeriod); + Rst_n = 1; + #(HalfClkPeriod); + + // send a 2-flit packet from send port 0 to receive port 1 + send_flit[0] = 1'b1; + dest = 1; + vc = 0; + data = 'ha; + flit_in[0] = {1'b1 /*valid*/, 1'b0 /*tail*/, dest, vc, data}; + $display("@%3d: Injecting flit %x into send port %0d", cycle, flit_in[0], 0); + + #(ClkPeriod); + // send 2nd flit of packet + send_flit[0] = 1'b1; + data = 'hb; + flit_in[0] = {1'b1 /*valid*/, 1'b1 /*tail*/, dest, vc, data}; + $display("@%3d: Injecting flit %x into send port %0d", cycle, flit_in[0], 0); + + #(ClkPeriod); + // stop sending flits + send_flit[0] = 1'b0; + flit_in[0] = 'b0; // valid bit + end + + + // Monitor arriving flits + always @ (posedge Clk) begin + cycle <= cycle + 1; + for(i = 0; i < `NUM_USER_RECV_PORTS; i = i + 1) begin + if(flit_out[i][flit_port_width-1]) begin // valid flit + $display("@%3d: Ejecting flit %x at receive port %0d", cycle, flit_out[i], i); + end + end + + // terminate simulation + if (cycle > test_cycles) begin + $finish(); + end + end + + // Add your code to handle flow control here (sending receiving credits) + + // Instantiate CONNECT network + mkNetwork dut + (.CLK(Clk) + ,.RST_N(Rst_n) + + ,.send_ports_0_putFlit_flit_in(flit_in[0]) + ,.EN_send_ports_0_putFlit(send_flit[0]) + + ,.EN_send_ports_0_getCredits(1'b1) // drain credits + ,.send_ports_0_getCredits(credit_out[0]) + + ,.send_ports_1_putFlit_flit_in(flit_in[1]) + ,.EN_send_ports_1_putFlit(send_flit[1]) + + ,.EN_send_ports_1_getCredits(1'b1) // drain credits + ,.send_ports_1_getCredits(credit_out[1]) + + // add rest of send ports here + // + + ,.EN_recv_ports_0_getFlit(1'b1) // drain flits + ,.recv_ports_0_getFlit(flit_out[0]) + + ,.recv_ports_0_putCredits_cr_in(credit_in[0]) + ,.EN_recv_ports_0_putCredits(send_credit[0]) + + ,.EN_recv_ports_1_getFlit(1'b1) // drain flits + ,.recv_ports_1_getFlit(flit_out[1]) + + ,.recv_ports_1_putCredits_cr_in(credit_in[1]) + ,.EN_recv_ports_1_putCredits(send_credit[1]) + + // add rest of receive ports here + // + + ); + + +endmodule + +`endif diff --git a/Prims/.svn/text-base/testbench_sample_peek.v.svn-base b/Prims/.svn/text-base/testbench_sample_peek.v.svn-base new file mode 100644 index 0000000..73fc13c --- /dev/null +++ b/Prims/.svn/text-base/testbench_sample_peek.v.svn-base @@ -0,0 +1,153 @@ +/* ========================================================================= + * + * Filename: testbench_sample.v + * Date created: 05-28-2012 + * Last modified: 11-30-2012 + * Authors: Michael Papamichael + * + * Description: + * Minimal testbench sample for CONNECT networks with Peek flow control + * + * ========================================================================= + */ + +`ifndef XST_SYNTH + +`timescale 1ns / 1ps + +`include "connect_parameters.v" + + +module CONNECT_testbench_sample_peek(); + parameter HalfClkPeriod = 5; + localparam ClkPeriod = 2*HalfClkPeriod; + + // non-VC routers still reeserve 1 dummy bit for VC. + localparam vc_bits = (`NUM_VCS > 1) ? $clog2(`NUM_VCS) : 1; + localparam dest_bits = $clog2(`NUM_USER_RECV_PORTS); + localparam flit_port_width = 2 /*valid and tail bits*/+ `FLIT_DATA_WIDTH + dest_bits + vc_bits; + //localparam credit_port_width = 1 + vc_bits; // 1 valid bit + localparam credit_port_width = `NUM_VCS; // 1 valid bit + localparam test_cycles = 20; + + reg Clk; + reg Rst_n; + + // input regs + reg send_flit [0:`NUM_USER_SEND_PORTS-1]; // enable sending flits + reg [flit_port_width-1:0] flit_in [0:`NUM_USER_SEND_PORTS-1]; // send port inputs + + reg send_credit [0:`NUM_USER_RECV_PORTS-1]; // enable sending credits + reg [credit_port_width-1:0] credit_in [0:`NUM_USER_RECV_PORTS-1]; //recv port credits + + // output wires + wire [credit_port_width-1:0] credit_out [0:`NUM_USER_SEND_PORTS-1]; + wire [flit_port_width-1:0] flit_out [0:`NUM_USER_RECV_PORTS-1]; + + reg [31:0] cycle; + integer i; + + // packet fields + reg is_valid; + reg is_tail; + reg [dest_bits-1:0] dest; + reg [vc_bits-1:0] vc; + reg [`FLIT_DATA_WIDTH-1:0] data; + + // Generate Clock + initial Clk = 0; + always #(HalfClkPeriod) Clk = ~Clk; + + // Run simulation + initial begin + cycle = 0; + for(i = 0; i < `NUM_USER_SEND_PORTS; i = i + 1) begin flit_in[i] = 0; send_flit[i] = 0; end + for(i = 0; i < `NUM_USER_RECV_PORTS; i = i + 1) begin credit_in[i] = 'b1; send_credit[i] = 'b1; end //constantly provide credits + + $display("---- Performing Reset ----"); + Rst_n = 0; // perform reset (active low) + #(5*ClkPeriod+HalfClkPeriod); + Rst_n = 1; + #(HalfClkPeriod); + + // send a 2-flit packet from send port 0 to receive port 1 + send_flit[0] = 1'b1; + dest = 1; + vc = 0; + data = 'ha; + flit_in[0] = {1'b1 /*valid*/, 1'b0 /*tail*/, dest, vc, data}; + $display("@%3d: Injecting flit %x into send port %0d", cycle, flit_in[0], 0); + + #(ClkPeriod); + // send 2nd flit of packet + send_flit[0] = 1'b1; + data = 'hb; + flit_in[0] = {1'b1 /*valid*/, 1'b1 /*tail*/, dest, vc, data}; + $display("@%3d: Injecting flit %x into send port %0d", cycle, flit_in[0], 0); + + #(ClkPeriod); + // stop sending flits + send_flit[0] = 1'b0; + flit_in[0] = 'b0; // valid bit + end + + + // Monitor arriving flits + always @ (posedge Clk) begin + cycle <= cycle + 1; + for(i = 0; i < `NUM_USER_RECV_PORTS; i = i + 1) begin + if(flit_out[i][flit_port_width-1]) begin // valid flit + $display("@%3d: Ejecting flit %x at receive port %0d", cycle, flit_out[i], i); + end + end + + // terminate simulation + if (cycle > test_cycles) begin + $finish(); + end + end + + // Add your code to handle flow control here (sending receiving credits) + + // Instantiate CONNECT network + mkNetworkSimple dut + (.CLK(Clk) + ,.RST_N(Rst_n) + + ,.send_ports_0_putFlit_flit_in(flit_in[0]) + ,.EN_send_ports_0_putFlit(send_flit[0]) + + ,.EN_send_ports_0_getNonFullVCs(1'b1) // drain credits + ,.send_ports_0_getNonFullVCs(credit_out[0]) + + ,.send_ports_1_putFlit_flit_in(flit_in[1]) + ,.EN_send_ports_1_putFlit(send_flit[1]) + + ,.EN_send_ports_1_getNonFullVCs(1'b1) // drain credits + ,.send_ports_1_getNonFullVCs(credit_out[1]) + + + // add rest of send ports here + // + + ,.EN_recv_ports_0_getFlit(1'b1) // drain flits + ,.recv_ports_0_getFlit(flit_out[0]) + + ,.recv_ports_0_putNonFullVCs_nonFullVCs(credit_in[0]) + ,.EN_recv_ports_0_putNonFullVCs(send_credit[0]) + + ,.EN_recv_ports_1_getFlit(1'b1) // drain flits + ,.recv_ports_1_getFlit(flit_out[1]) + + ,.recv_ports_1_putNonFullVCs_nonFullVCs(credit_in[1]) + ,.EN_recv_ports_1_putNonFullVCs(send_credit[1]) + + // add rest of receive ports here + // + + ); + + +endmodule + +`endif diff --git a/Prims/BRAM1.v b/Prims/BRAM1.v new file mode 100644 index 0000000..5bddecf --- /dev/null +++ b/Prims/BRAM1.v @@ -0,0 +1,85 @@ + +// Copyright (c) 2000-2009 Bluespec, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// $Revision: 17872 $ +// $Date: 2009-09-18 14:32:56 +0000 (Fri, 18 Sep 2009) $ + +`ifdef BSV_ASSIGNMENT_DELAY +`else + `define BSV_ASSIGNMENT_DELAY +`endif + +// Single-Ported BRAM +module BRAM1(CLK, + EN, + WE, + ADDR, + DI, + DO + ); + + // synopsys template + parameter PIPELINED = 0; + parameter ADDR_WIDTH = 1; + parameter DATA_WIDTH = 1; + parameter MEMSIZE = 1; + + + input CLK; + input EN; + input WE; + input [ADDR_WIDTH-1:0] ADDR; + input [DATA_WIDTH-1:0] DI; + output [DATA_WIDTH-1:0] DO; + + reg [DATA_WIDTH-1:0] RAM[0:MEMSIZE-1]; + reg [ADDR_WIDTH-1:0] ADDR_R; + reg [DATA_WIDTH-1:0] DO_R; + +`ifdef BSV_NO_INITIAL_BLOCKS +`else + // synopsys translate_off + integer i; + initial + begin : init_block + for (i = 0; i < MEMSIZE; i = i + 1) begin + RAM[i] = { ((DATA_WIDTH+1)/2) { 2'b10 } }; + end + ADDR_R = { ((ADDR_WIDTH+1)/2) { 2'b10 } }; + DO_R = { ((DATA_WIDTH+1)/2) { 2'b10 } }; + end + // synopsys translate_on +`endif // !`ifdef BSV_NO_INITIAL_BLOCKS + + always @(posedge CLK) begin + if (EN) begin + if (WE) + RAM[ADDR] <= `BSV_ASSIGNMENT_DELAY DI; + ADDR_R <= `BSV_ASSIGNMENT_DELAY ADDR; + end + DO_R <= `BSV_ASSIGNMENT_DELAY RAM[ADDR_R]; + end + + assign DO = (PIPELINED) ? DO_R : RAM[ADDR_R]; + +endmodule // BRAM1 + + diff --git a/Prims/BRAM2.v b/Prims/BRAM2.v new file mode 100644 index 0000000..17e2aff --- /dev/null +++ b/Prims/BRAM2.v @@ -0,0 +1,132 @@ + +// Copyright (c) 2000-2009 Bluespec, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// $Revision: 17872 $ +// $Date: 2009-09-18 14:32:56 +0000 (Fri, 18 Sep 2009) $ + +`ifdef BSV_ASSIGNMENT_DELAY +`else + `define BSV_ASSIGNMENT_DELAY +`endif + +// Dual-Ported BRAM +module BRAM2(CLKA, + ENA, + WEA, + ADDRA, + DIA, + DOA, + CLKB, + ENB, + WEB, + ADDRB, + DIB, + DOB + ); + + // synopsys template + parameter PIPELINED = 0; + parameter ADDR_WIDTH = 1; + parameter DATA_WIDTH = 1; + parameter MEMSIZE = 1; + + input CLKA; + input ENA; + input WEA; + input [ADDR_WIDTH-1:0] ADDRA; + input [DATA_WIDTH-1:0] DIA; + output [DATA_WIDTH-1:0] DOA; + + input CLKB; + input ENB; + input WEB; + input [ADDR_WIDTH-1:0] ADDRB; + input [DATA_WIDTH-1:0] DIB; + output [DATA_WIDTH-1:0] DOB; + + reg [DATA_WIDTH-1:0] RAM[0:MEMSIZE-1] /* synthesis syn_ramstyle="no_rw_check" */ ; + reg [ADDR_WIDTH-1:0] ADDRA_R; + reg [ADDR_WIDTH-1:0] ADDRB_R; + reg [DATA_WIDTH-1:0] DOA_R; + reg [DATA_WIDTH-1:0] DOB_R; + + wire [DATA_WIDTH-1:0] DOA_noreg; + wire [DATA_WIDTH-1:0] DOB_noreg; + + wire [ADDR_WIDTH-1:0] ADDRA_muxed; + wire [ADDR_WIDTH-1:0] ADDRB_muxed; + + +`ifdef BSV_NO_INITIAL_BLOCKS +`else + // synopsys translate_off + integer i; + initial + begin : init_block + for (i = 0; i < MEMSIZE; i = i + 1) begin + RAM[i] = { ((DATA_WIDTH+1)/2) { 2'b10 } }; + end + ADDRA_R = { ((ADDR_WIDTH+1)/2) { 2'b10 } }; + ADDRB_R = { ((ADDR_WIDTH+1)/2) { 2'b10 } }; + DOA_R = { ((DATA_WIDTH+1)/2) { 2'b10 } }; + DOB_R = { ((DATA_WIDTH+1)/2) { 2'b10 } }; + end + // synopsys translate_on +`endif // !`ifdef BSV_NO_INITIAL_BLOCKS + + + always @(posedge CLKA) begin + ADDRA_R <= `BSV_ASSIGNMENT_DELAY ADDRA_muxed; + if (ENA) begin + if (WEA) + RAM[ADDRA_muxed] <= `BSV_ASSIGNMENT_DELAY DIA; + end + end + + always @(posedge CLKB) begin + ADDRB_R <= `BSV_ASSIGNMENT_DELAY ADDRB_muxed; + if (ENB) begin + if (WEB) + RAM[ADDRB_muxed] <= `BSV_ASSIGNMENT_DELAY DIB; + end + end + + + // ENA workaround for Synplify + assign ADDRA_muxed = (ENA) ? ADDRA : ADDRA_R; + assign ADDRB_muxed = (ENB) ? ADDRB : ADDRB_R; + + // Memory read + assign DOA_noreg = RAM[ADDRA_R]; + assign DOB_noreg = RAM[ADDRB_R]; + + // Pipeline + always @(posedge CLKA) + DOA_R <= DOA_noreg; + + always @(posedge CLKB) + DOB_R <= DOB_noreg; + + // Output drivers + assign DOA = (PIPELINED) ? DOA_R : DOA_noreg; + assign DOB = (PIPELINED) ? DOB_R : DOB_noreg; + +endmodule // BRAM2 diff --git a/Prims/BypassWire.v b/Prims/BypassWire.v new file mode 100644 index 0000000..8a7c134 --- /dev/null +++ b/Prims/BypassWire.v @@ -0,0 +1,38 @@ + +// Copyright (c) 2000-2009 Bluespec, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// $Revision: 17872 $ +// $Date: 2009-09-18 14:32:56 +0000 (Fri, 18 Sep 2009) $ + + +module BypassWire(WGET, WVAL); + + // synopsys template + + parameter width = 1; + + input [width - 1 : 0] WVAL; + + output [width - 1 : 0] WGET; + + assign WGET = WVAL; + +endmodule diff --git a/Prims/DPSRAM.v b/Prims/DPSRAM.v new file mode 100644 index 0000000..d3b9931 --- /dev/null +++ b/Prims/DPSRAM.v @@ -0,0 +1,65 @@ +module DPSRAM ( + Rd, + IdxR, + DoutR, + + We, + IdxW, + DinW, + clk, + rst_n + ); + + // synthesis attribute BRAM_MAP of DPSRAM is "yes"; + + parameter WIDTH = 1; + parameter ADDR_BITS = 9; + parameter DEPTH = 1< + * + * Description: + * 16-ported register file that maps to LUT RAM. Implements double-buffering + * internally. Automatically switches to other array when last address is + * written. + * + */ + +// Multi-ported Register File +module DoubleBufferedRegFile_16ports(CLK, rst_n, + ADDR_IN, D_IN, WE, + ADDR_1, D_OUT_1, + ADDR_2, D_OUT_2, + ADDR_3, D_OUT_3, + ADDR_4, D_OUT_4, + ADDR_5, D_OUT_5, + ADDR_6, D_OUT_6, + ADDR_7, D_OUT_7, + ADDR_8, D_OUT_8, + ADDR_9, D_OUT_9, + ADDR_10, D_OUT_10, + ADDR_11, D_OUT_11, + ADDR_12, D_OUT_12, + ADDR_13, D_OUT_13, + ADDR_14, D_OUT_14, + ADDR_15, D_OUT_15, + ADDR_16, D_OUT_16 + ); + + // synopsys template + parameter data_width = 208; + parameter addr_width = 8; + parameter depth = 1< hi) ) + $display( "Warning: RegFile: %m -- Address port 1 is out of bounds: %h", ADDR_1 ) ; + if (( ADDR_2 < lo ) || (ADDR_2 > hi) ) + $display( "Warning: RegFile: %m -- Address port 2 is out of bounds: %h", ADDR_2 ) ; + if (( ADDR_3 < lo ) || (ADDR_3 > hi) ) + $display( "Warning: RegFile: %m -- Address port 3 is out of bounds: %h", ADDR_3 ) ; + if (( ADDR_4 < lo ) || (ADDR_4 > hi) ) + $display( "Warning: RegFile: %m -- Address port 4 is out of bounds: %h", ADDR_4 ) ; + if (( ADDR_5 < lo ) || (ADDR_5 > hi) ) + $display( "Warning: RegFile: %m -- Address port 5 is out of bounds: %h", ADDR_5 ) ; + if ( WE && ( ADDR_IN < lo ) || (ADDR_IN > hi) ) + $display( "Warning: RegFile: %m -- Write Address port is out of bounds: %h", ADDR_IN ) ; + end + end + // synopsys translate_on + +endmodule + diff --git a/Prims/RegFileLoadSyn.bsv b/Prims/RegFileLoadSyn.bsv new file mode 100644 index 0000000..08467f4 --- /dev/null +++ b/Prims/RegFileLoadSyn.bsv @@ -0,0 +1,38 @@ +import RegFile::*; + +module mkRegFileLoadSyn#(String filename)(RegFile#(index,data)) + provisos( Bounded#(index), + Bits#(index, a__), + Bits#(data, b__)); + RegFile#(index,data) rf; + if(genVerilog) begin + rf <- mkRegFileLoadSynVerilog(filename); + end + else begin + rf <- mkRegFileFullLoad(filename); + end + return rf; +endmodule + +import "BVI" RegFileLoadSyn = module mkRegFileLoadSynVerilog#(String filename)(RegFile#(index, data)); + + default_clock clk(CLK, (*unused*) clk_gate); + default_reset( RST_N ); + + parameter file = filename; + parameter addr_width = fromInteger(valueOf(SizeOf#(index))); + parameter data_width = fromInteger(valueOf(SizeOf#(data))); + parameter lo = 0; + parameter hi = fromInteger(valueOf(TExp#(SizeOf#(index))))-1; + parameter binary = 0; + + method D_OUT_1 sub(ADDR_1); + method upd(ADDR_IN, D_IN) enable(WE); + schedule (sub, upd) CF (sub, upd); + +endmodule + +module mkRfSynTest(RegFile#(Bit#(5), Bit#(64))); + let rf <- mkRegFileLoadSyn("zeros.hex"); + return rf; +endmodule diff --git a/Prims/RegFileLoadSyn.v b/Prims/RegFileLoadSyn.v new file mode 100644 index 0000000..3c6a12c --- /dev/null +++ b/Prims/RegFileLoadSyn.v @@ -0,0 +1,38 @@ +module RegFileLoadSyn + (CLK, RST_N, + ADDR_IN, D_IN, WE, + ADDR_1, D_OUT_1 + ); + + parameter file = ""; + parameter addr_width = 1; + parameter data_width = 1; + parameter lo = 0; + parameter hi = 1; + parameter binary = 0; + + input CLK; + input RST_N; + input [addr_width - 1 : 0] ADDR_IN; + input [data_width - 1 : 0] D_IN; + input WE; + + input [addr_width - 1 : 0] ADDR_1; + output [data_width - 1 : 0] D_OUT_1; + + reg [data_width - 1 : 0] arr[lo:hi]; + + initial + begin : init_block + $readmemh(file, arr, lo, hi); + end + + always@(posedge CLK) + begin + if (WE && RST_N) + arr[ADDR_IN] <= D_IN; + end // always@ (posedge CLK) + + assign D_OUT_1 = arr[ADDR_1]; + +endmodule diff --git a/Prims/RegFileMultiport.bsv b/Prims/RegFileMultiport.bsv new file mode 100644 index 0000000..5018bb6 --- /dev/null +++ b/Prims/RegFileMultiport.bsv @@ -0,0 +1,211 @@ +import RegFile::*; +import Vector::*; +import ConfigReg::*; +import RegFileLoadSyn::*; + +interface RegFileRead#(type addr, type data); + method data sub(addr a); +endinterface + +interface RegFileWrite#(type addr, type data); + method Action upd(addr a, data d); +endinterface + +interface RegFileMultiport#(numeric type nr, numeric type nw, type addr, type data); + interface Vector#(nr, RegFileRead#(addr,data)) r; + interface Vector#(nw, RegFileWrite#(addr,data)) w; +endinterface + +interface RegFile_1W_nR#(numeric type nr, type addr, type data); + interface RegFileWrite#(addr, data) w; + interface Vector#(nr, RegFileRead#(addr, data)) r; +endinterface + + +module mkRegFile_1W_nR(RegFile_1W_nR#(nr, addr, data)) + provisos(Bits#(addr, addr_nt), + Bits#(data, data_nt), + Bounded#(addr), + PrimIndex#(addr, a__) + ); + + Vector#(nr, RegFile#(addr, data)) banks <- replicateM(mkRegFileLoadSyn("zeros.hex")); + Vector#(nr, RegFileRead#(addr,data)) r_ifaces; + + for(Integer i=0; i < valueOf(nr); i=i+1) begin + let r_ifc = interface RegFileRead + method data sub(addr a); + return banks[i].sub(a); + endmethod + endinterface; + + r_ifaces[i] = r_ifc; + end + + interface RegFileWrite w; + method Action upd(addr a, data d); + for(Integer i=0; i < valueOf(nr); i=i+1) begin + banks[i].upd(a, d); + end + endmethod + endinterface + + interface r = r_ifaces; + +endmodule + + + + + +module mkRegFileMultiport(RegFileMultiport#(nr, nw, addr, data)) + provisos(Bits#(addr, addr_nt), + Bits#(data, data_nt), + Bounded#(addr), + PrimIndex#(addr, a__) + ); + + Vector#(nw, RegFile_1W_nR#(nr, addr, data)) banks <- replicateM(mkRegFile_1W_nR); + Vector#(TExp#(addr_nt), Reg#(Bit#(TLog#(nw)))) lvt <- replicateM(mkConfigRegU); + + Vector#(nw, RegFileWrite#(addr,data)) w_ifaces; + Vector#(nr, RegFileRead#(addr,data)) r_ifaces; + + for(Integer i=0; i < valueOf(nw); i=i+1) begin + let w_ifc = interface RegFileWrite + method Action upd(addr a, data d); + banks[i].w.upd(a, d); + lvt[a] <= fromInteger(i); + endmethod + endinterface; + w_ifaces[i] = w_ifc; + end + + for(Integer i=0; i < valueOf(nr); i=i+1) begin + let r_ifc = interface RegFileRead + method data sub(addr a); + let pick = lvt[a]; + return banks[pick].r[i].sub(a); + endmethod + endinterface; + r_ifaces[i] = r_ifc; + end + + interface w = w_ifaces; + interface r = r_ifaces; + +endmodule + + +module mkRegFileMultiportBrute(RegFileMultiport#(nr, nw, addr, data)) + provisos(Bits#(addr, addr_nt), + Bits#(data, data_nt), + Bounded#(addr), + PrimIndex#(addr, a__) + ); + + Vector#(TExp#(addr_nt), Reg#(data)) store <- replicateM(mkConfigRegU); + Vector#(nw, RegFileWrite#(addr,data)) w_ifaces; + Vector#(nr, RegFileRead#(addr,data)) r_ifaces; + + for(Integer i=0; i < valueOf(nw); i=i+1) begin + let w_ifc = interface RegFileWrite + method Action upd(addr a, data d); + store[a]<=d; + endmethod + endinterface; + w_ifaces[i] = w_ifc; + end + + for(Integer i=0; i < valueOf(nr); i=i+1) begin + let r_ifc = interface RegFileRead + method data sub(addr a); + return store[a]; + endmethod + endinterface; + r_ifaces[i] = r_ifc; + end + + interface w = w_ifaces; + interface r = r_ifaces; + +endmodule + + +//////////////////////////////////////////////////////// +// papamix: Added version that load init file + +module mkRegFile_1W_nR_Load#(String loadfile) + (RegFile_1W_nR#(nr, addr, data)) + provisos(Bits#(addr, addr_nt), + Bits#(data, data_nt), + Bounded#(addr), + PrimIndex#(addr, a__) + ); + + Vector#(nr, RegFile#(addr, data)) banks <- replicateM(mkRegFileLoadSyn(loadfile)); + Vector#(nr, RegFileRead#(addr,data)) r_ifaces; + + for(Integer i=0; i < valueOf(nr); i=i+1) begin + let r_ifc = interface RegFileRead + method data sub(addr a); + return banks[i].sub(a); + endmethod + endinterface; + + r_ifaces[i] = r_ifc; + end + + interface RegFileWrite w; + method Action upd(addr a, data d); + for(Integer i=0; i < valueOf(nr); i=i+1) begin + banks[i].upd(a, d); + end + endmethod + endinterface + + interface r = r_ifaces; + +endmodule + + +module mkRegFileMultiportLoad#(String loadfile) + (RegFileMultiport#(nr, nw, addr, data)) + provisos(Bits#(addr, addr_nt), + Bits#(data, data_nt), + Bounded#(addr), + PrimIndex#(addr, a__) + ); + + Vector#(nw, RegFile_1W_nR#(nr, addr, data)) banks <- replicateM(mkRegFile_1W_nR_Load(loadfile)); + Vector#(TExp#(addr_nt), Reg#(Bit#(TLog#(nw)))) lvt <- replicateM(mkConfigRegU); + + Vector#(nw, RegFileWrite#(addr,data)) w_ifaces; + Vector#(nr, RegFileRead#(addr,data)) r_ifaces; + + for(Integer i=0; i < valueOf(nw); i=i+1) begin + let w_ifc = interface RegFileWrite + method Action upd(addr a, data d); + banks[i].w.upd(a, d); + lvt[a] <= fromInteger(i); + endmethod + endinterface; + w_ifaces[i] = w_ifc; + end + + for(Integer i=0; i < valueOf(nr); i=i+1) begin + let r_ifc = interface RegFileRead + method data sub(addr a); + let pick = lvt[a]; + return banks[pick].r[i].sub(a); + endmethod + endinterface; + r_ifaces[i] = r_ifc; + end + + interface w = w_ifaces; + interface r = r_ifaces; + +endmodule + + diff --git a/Prims/RegFile_16ports.v b/Prims/RegFile_16ports.v new file mode 100644 index 0000000..a7d8f50 --- /dev/null +++ b/Prims/RegFile_16ports.v @@ -0,0 +1,146 @@ +/* + * ========================================================================= + * + * Filename: RegFile_16ports.v + * Date created: 03-29-2011 + * Last modified: 03-29-2011 + * Authors: Michael Papamichael + * + * Description: + * 16-ported register file that maps to LUT RAM. + * + */ + +// Multi-ported Register File +module RegFile_16ports(CLK, rst_n, + ADDR_IN, D_IN, WE, + ADDR_1, D_OUT_1, + ADDR_2, D_OUT_2, + ADDR_3, D_OUT_3, + ADDR_4, D_OUT_4, + ADDR_5, D_OUT_5, + ADDR_6, D_OUT_6, + ADDR_7, D_OUT_7, + ADDR_8, D_OUT_8, + ADDR_9, D_OUT_9, + ADDR_10, D_OUT_10, + ADDR_11, D_OUT_11, + ADDR_12, D_OUT_12, + ADDR_13, D_OUT_13, + ADDR_14, D_OUT_14, + ADDR_15, D_OUT_15, + ADDR_16, D_OUT_16 + ); + + // synopsys template + parameter data_width = 1; + parameter addr_width = 1; + parameter depth = 1< + * + * Description: + * 16-ported register file that maps to LUT RAM. + * + */ + +// Multi-ported Register File +module RegFile_16ports_load(CLK, rst_n, + ADDR_IN, D_IN, WE, + ADDR_1, D_OUT_1, + ADDR_2, D_OUT_2, + ADDR_3, D_OUT_3, + ADDR_4, D_OUT_4, + ADDR_5, D_OUT_5, + ADDR_6, D_OUT_6, + ADDR_7, D_OUT_7, + ADDR_8, D_OUT_8, + ADDR_9, D_OUT_9, + ADDR_10, D_OUT_10, + ADDR_11, D_OUT_11, + ADDR_12, D_OUT_12, + ADDR_13, D_OUT_13, + ADDR_14, D_OUT_14, + ADDR_15, D_OUT_15, + ADDR_16, D_OUT_16 + ); + + // synopsys template + parameter data_width = 1; + parameter addr_width = 1; + parameter loadfile = ""; + parameter binary = 0; + //parameter lo = 0; + //parameter hi = 1; + parameter depth = 1<= 2) ? (p2depth2) : 0)]; + + reg [p1width - 1 : 0] D_OUT; + reg hasodata; + + wire [p3cntr_width-1:0] depthLess2 = p2depth2[p3cntr_width-1:0] ; + + wire [p3cntr_width-1 : 0] incr_tail; + wire [p3cntr_width-1 : 0] incr_head; + + assign incr_tail = tail + 1'b1 ; + assign incr_head = head + 1'b1 ; + + assign next_head = (head == depthLess2 ) ? {p3cntr_width{1'b0}} : incr_head ; + assign next_tail = (tail == depthLess2 ) ? {p3cntr_width{1'b0}} : incr_tail ; + + assign EMPTY_N = hasodata; + assign FULL_N = not_ring_full; + +`ifdef BSV_NO_INITIAL_BLOCKS +`else // not BSV_NO_INITIAL_BLOCKS + // synopsys translate_off + initial + begin : initial_block + integer i; + D_OUT = {((p1width + 1)/2){2'b10}} ; + + ring_empty = 1'b1; + not_ring_full = 1'b1; + hasodata = 1'b0; + head = {p3cntr_width {1'b0}} ; + tail = {p3cntr_width {1'b0}} ; + + for (i = 0; i <= p2depth2 && p2depth > 2; i = i + 1) + begin + arr[i] = D_OUT ; + end + end + // synopsys translate_on +`endif // BSV_NO_INITIAL_BLOCKS + + always @(posedge CLK /* or negedge RST_N */ ) + begin + if (!RST_N) + begin + head <= `BSV_ASSIGNMENT_DELAY {p3cntr_width {1'b0}} ; + tail <= `BSV_ASSIGNMENT_DELAY {p3cntr_width {1'b0}} ; + ring_empty <= `BSV_ASSIGNMENT_DELAY 1'b1; + not_ring_full <= `BSV_ASSIGNMENT_DELAY 1'b1; + hasodata <= `BSV_ASSIGNMENT_DELAY 1'b0; + + // Following section initializes the data registers which + // may be desired only in some situations. + // Uncomment to initialize array + /* + D_OUT <= `BSV_ASSIGNMENT_DELAY {p1width {1'b0}} ; + for (i = 0; i <= p2depth2 && p2depth > 2; i = i + 1) + begin + arr[i] <= `BSV_ASSIGNMENT_DELAY {p1width {1'b0}} ; + end + */ + end // if (RST_N == 0) + else + begin + + // Update arr[tail] once, since some FPGA synthesis tools are unable + // to infer good RAM placement when there are multiple separate + // writes of arr[tail] <= D_IN + if (!CLR && ENQ && ((DEQ && !ring_empty) || (!DEQ && hasodata && not_ring_full))) + begin + arr[tail] <= `BSV_ASSIGNMENT_DELAY D_IN; + end + + if (CLR) + begin + head <= `BSV_ASSIGNMENT_DELAY {p3cntr_width {1'b0}} ; + tail <= `BSV_ASSIGNMENT_DELAY {p3cntr_width {1'b0}} ; + ring_empty <= `BSV_ASSIGNMENT_DELAY 1'b1; + not_ring_full <= `BSV_ASSIGNMENT_DELAY 1'b1; + hasodata <= `BSV_ASSIGNMENT_DELAY 1'b0; + end // if (CLR) + + else if (DEQ && ENQ ) + begin + if (ring_empty) + begin + D_OUT <= `BSV_ASSIGNMENT_DELAY D_IN; + end + else + begin + // moved into combined write above + // arr[tail] <= `BSV_ASSIGNMENT_DELAY D_IN; + tail <= `BSV_ASSIGNMENT_DELAY next_tail; + D_OUT <= `BSV_ASSIGNMENT_DELAY arr[head]; + head <= `BSV_ASSIGNMENT_DELAY next_head; + end + end // if (DEQ && ENQ ) + + else if ( DEQ ) + begin + if (ring_empty) + begin + hasodata <= `BSV_ASSIGNMENT_DELAY 1'b0; + end + else + begin + D_OUT <= `BSV_ASSIGNMENT_DELAY arr[head]; + head <= `BSV_ASSIGNMENT_DELAY next_head; + not_ring_full <= `BSV_ASSIGNMENT_DELAY 1'b1; + ring_empty <= `BSV_ASSIGNMENT_DELAY next_head == tail ; + end + end // if ( DEQ ) + + else if (ENQ) + begin + if (! hasodata) + begin + D_OUT <= `BSV_ASSIGNMENT_DELAY D_IN; + hasodata <= `BSV_ASSIGNMENT_DELAY 1'b1; + end + else if ( not_ring_full ) // Drop this test to save redundant test + // but be warnned that with test fifo overflow causes loss of new data + // while without test fifo drops all but head entry! (pointer overflow) + begin + // moved into combined write above + // arr[tail] <= `BSV_ASSIGNMENT_DELAY D_IN; // drop the old element + tail <= `BSV_ASSIGNMENT_DELAY next_tail; + ring_empty <= `BSV_ASSIGNMENT_DELAY 1'b0; + not_ring_full <= `BSV_ASSIGNMENT_DELAY ! (next_tail == head) ; + end + end // if (ENQ) + end // else: !if(RST_N == 0) + + end // always @ (posedge CLK) + + // synopsys translate_off + always@(posedge CLK) + begin: error_checks + reg deqerror, enqerror ; + + deqerror = 0; + enqerror = 0; + if ( RST_N ) + begin + if ( ! EMPTY_N && DEQ ) + begin + deqerror = 1 ; + $display( "Warning: SizedFIFO: %m -- Dequeuing from empty fifo" ) ; + end + if ( ! FULL_N && ENQ && (!DEQ || guarded) ) + begin + enqerror = 1 ; + $display( "Warning: SizedFIFO: %m -- Enqueuing to a full fifo" ) ; + end + end + end // block: error_checks + // synopsys translate_on + + // synopsys translate_off + // Some assertions about parameter values + initial + begin : parameter_assertions + integer ok ; + ok = 1 ; + + if ( p2depth <= 2 ) + begin + ok = 0; + $display ( "ERROR SizedFIFO.v: depth parameter must be greater than 2" ) ; + end + + if ( p3cntr_width <= 0 ) + begin + ok = 0; + $display ( "ERROR SizedFIFO.v: width parameter must be greater than 0" ) ; + end + + if ( ok == 0 ) $finish ; + + end // initial begin + // synopsys translate_on + +endmodule diff --git a/Prims/Xbar.bsv b/Prims/Xbar.bsv new file mode 100644 index 0000000..00e0611 --- /dev/null +++ b/Prims/Xbar.bsv @@ -0,0 +1,61 @@ +import Vector::*; +interface XbarVerilog#(numeric type n, + numeric type nvc, + numeric type cut, + numeric type dwidth, + numeric type buffer_depth); + + (* always_ready *) + method Action iports(Vector#(n, Bool) i_valid, + Vector#(n, Bool) i_prio, + Vector#(n, Bool) i_tail, + Vector#(n, Bit#(TLog#(n))) i_dst, + Vector#(n, Bit#(TLog#(nvc))) i_vc, + Vector#(n, Bit#(dwidth)) i_data); + + (* always_ready *) method Vector#(n, Bool) o_valid; + (* always_ready *) method Vector#(n, Bool) o_prio; + (* always_ready *) method Vector#(n, Bool) o_tail; + (* always_ready *) method Vector#(n, Bit#(TLog#(n))) o_dst; + (* always_ready *) method Vector#(n, Bit#(TLog#(nvc))) o_vc; + (* always_ready *) method Vector#(n, Bit#(dwidth)) o_data; + + (* always_ready *) method Vector#(n, Bit#(TLog#(nvc))) i_cred; + (* always_ready *) method Vector#(n, Bool) i_cred_valid; + (* always_ready *) method Action o_cred(Vector#(n, Bool) en); + +endinterface + +import "BVI" Xbar = module mkXbarVerilog(XbarVerilog#(n, nvc, cut, dwidth, buffer_depth)); + + default_clock clk(CLK, (*unused*) clk_gate); + + parameter N = fromInteger(valueOf(n)); + parameter NUM_VCS = fromInteger(valueOf(nvc)); + parameter CUT = fromInteger(valueOf(cut)); + parameter DATA = fromInteger(valueOf(dwidth)); + parameter BUFFER_DEPTH = fromInteger(valueOf(buffer_depth)); + + method iports(i_valid, i_prio, i_tail, i_dst, i_vc, i_data) enable((*inhigh*)True); + method o_valid o_valid; + method o_prio o_prio; + method o_tail o_tail; + method o_dst o_dst; + method o_vc o_vc; + method o_data o_data; + method i_cred i_cred; + method i_cred_valid i_cred_valid; + method o_cred(o_cred_en) enable((*inhigh*)True2); + + schedule (iports, o_valid, o_prio, o_tail, o_dst, o_vc, o_data, i_cred, i_cred_valid, o_cred) CF + (iports, o_valid, o_prio, o_tail, o_dst, o_vc, o_data, i_cred, i_cred_valid, o_cred); + +endmodule + +/* +(* synthesize *) +module mkXbarVerilogSynth(XbarVerilog#(4,2,1,32,16)); + let xbar <- mkXbarVerilog; + return xbar; +endmodule +*/ diff --git a/Prims/Xbar.v b/Prims/Xbar.v new file mode 100644 index 0000000..98e3871 --- /dev/null +++ b/Prims/Xbar.v @@ -0,0 +1,355 @@ +`define clogb2(x) (\ + x <= 1 ? 0: \ + x <= 2 ? 1: \ + x <= 4 ? 2: \ + x <= 8 ? 3: \ + x <= 16 ? 4: \ + x <= 32 ? 5: \ + x <= 64 ? 6: \ + x <= 128 ? 7: \ + x <= 256 ? 8 : \ + x <= 512 ? 9 : \ + x <= 1024 ? 10 : \ + x <= 2048 ? 11 : \ + x <= 4096 ? 12 : \ + x <= 8192 ? 13 : \ + x <= 16384 ? 14 : -1) + +module XbarArbiter(CLK, RST_N, raises, grant, valid); + + parameter N=4; + + input CLK; + input RST_N; + input [N-1:0] raises; + output reg [N-1:0] grant; + output reg valid; + + function [1:0] gen_grant_carry; + input c, r, p; + begin + gen_grant_carry[1] = ~r & (c | p); + gen_grant_carry[0] = r & (c | p); + end + endfunction + + reg [N-1:0] token; + reg [N-1:0] granted_A; + reg [N-1:0] granted_B; + reg carry; + reg [1:0] gc; + + integer i; + + + always@(*) begin + valid = 1'b0; + grant = 0; + carry = 0; + granted_A = 0; + granted_B = 0; + + // Arbiter 1 + for(i=0; i < N; i=i+1) begin + gc = gen_grant_carry(carry, raises[i], token[i]); + granted_A[i] = gc[0]; + carry = gc[1]; + end + + // Arbiter 2 (uses the carry from Arbiter 1) + for(i=0; i < N; i=i+1) begin + gc = gen_grant_carry(carry, raises[i], token[i]); + granted_B[i] = gc[0]; + carry = gc[1]; + end + + for(i=0; i < N; i=i+1) begin + if(granted_A[i] | granted_B[i]) begin + grant = 0; + grant[i] = 1'b1; + valid = 1'b1; + end + end + end + + always@(posedge CLK) begin + if(RST_N) token <= {token[N-2:0], token[N-1]}; + else token <= 1; + end + +endmodule + + +module Xbar(CLK, RST_N, + i_valid, + i_prio, + i_tail, + i_dst, + i_vc, + i_data, + + o_valid, + o_prio, + o_tail, + o_dst, + o_vc, + o_data, + + i_cred, + i_cred_valid, + + o_cred_en + ); + + parameter N = 16; + parameter NUM_VCS = 2; + parameter CUT = 2; + parameter DATA = 32; + parameter BUFFER_DEPTH = 16; + + parameter LOG_N = `clogb2(N); + parameter VC = `clogb2(NUM_VCS); + parameter DST = `clogb2(N); + parameter FLIT_WIDTH = 1+1+DST+VC+DATA; + parameter CRED_WIDTH = `clogb2(BUFFER_DEPTH) + 1; + + input CLK, RST_N; + + // Input ports + input [N-1:0] i_valid; + input [N-1:0] i_prio; + input [N-1:0] i_tail; + input [N*DST-1:0] i_dst; + input [N*VC-1:0] i_vc; + input [N*DATA-1:0] i_data; + + wire [VC-1:0] i_vc_arr [N-1:0]; + + // Input queue front ports + wire [N-1:0] f_prio; + wire [N-1:0] f_tail; + wire [DST-1:0] f_dst [N-1:0]; + wire [VC-1:0] f_vc [N-1:0]; + wire [DATA-1:0] f_data [N-1:0]; + wire [N-1:0] f_elig; + + // Needed to play friendly with Icarus Verilog and Modelsim + wire [DST*N-1:0] f_dst_flat; + wire [VC*N-1:0] f_vc_flat; + wire [DATA*N-1:0] f_data_flat; + + // Output ports + output reg [N-1:0] o_valid; + output reg [N-1:0] o_prio; + output reg [N-1:0] o_tail; + output [N*DST-1:0] o_dst; + output [N*VC-1:0] o_vc; + output [N*DATA-1:0] o_data; + + reg [DST-1:0] o_dst_arr [N-1:0]; + reg [VC-1:0] o_vc_arr [N-1:0]; + reg [DATA-1:0] o_data_arr [N-1:0]; + + // Input credit + output [N*VC-1:0] i_cred; // just remembers the VC of 1st packet that arrives + output reg [N-1:0] i_cred_valid; // maybe bit + reg [VC-1:0] i_cred_arr [N-1:0]; + + // Output credit + input [N-1:0] o_cred_en; + + // Dequeue wires + wire [N-1:0] grants [N-1:0]; + wire [N-1:0] grant_valids; + reg [N-1:0] deq_en; + + reg [CRED_WIDTH-1:0] creds_left [N-1:0]; + + genvar i, o, k; + integer in,out; + + generate + for(o=0; o < N; o=o+1) begin: arbiters + wire [N-1:0] raises; + + for(k=0; k < N; k=k+1) begin: raisewires + assign raises[k] = (f_dst[k] == o) && f_elig[k]; + end + + XbarArbiter#(.N(N)) arbiter(.CLK(CLK), + .RST_N(RST_N), + .raises(raises), + .valid(grant_valids[o]), + .grant(grants[o])); // [(o+1)*LOG_N-1:o*LOG_N])); + + + + end + endgenerate + + + /* + // Stats + always@(negedge CLK) begin + if(RST_N) begin + for(in=0; in < N; in=in+1) begin + if(f_elig[in]) + $display("strace time=%0d component=noc inst=0 evt=raises val=1", $time); + + if(deq_en[in] != 0) + $display("strace time=%0d component=noc inst=0 evt=grants val=1", $time); + //$display("strace time=%0d component=noc inst=0 evt=full val=1", $time); + end + end + end + */ + + // Record the input VC + always@(posedge CLK) begin + if(RST_N) begin + for(in=0; in < N; in=in+1) begin + if(i_valid[in]) + i_cred_arr[in] <= i_vc_arr[in]; + end + end + else begin + for(in=0; in < N; in=in+1) begin + i_cred_arr[in]<='hx; + end + end + end + + for(i=0; i < N; i=i+1) begin: assign_arr + assign i_vc_arr[i] = i_vc[(i+1)*VC-1:i*VC]; + assign i_cred[(i+1)*VC-1:i*VC] = i_cred_arr[i]; + assign o_dst[(i+1)*DST-1:i*DST] = o_dst_arr[i]; + assign o_vc[(i+1)*VC-1:i*VC] = o_vc_arr[i]; + assign o_data[(i+1)*DATA-1:i*DATA] = o_data_arr[i]; + end + + // Enable deq + always@(*) begin + for(in=0; in < N; in=in+1) begin: deqwires + deq_en[in] = 1'b0; + i_cred_valid[in] = 1'b0; + + for(out=0; out < N; out=out+1) begin: outer + if(grant_valids[out] && (grants[out][in] == 1'b1) && (creds_left[out] != 0)) begin + deq_en[in] = 1'b1; + i_cred_valid[in] = 1'b1; + end + end + end + end + + // Needed to play friendly with Icarus Verilog + for(i=0; i < N; i=i+1) begin + assign f_dst_flat[(i+1)*DST-1:i*DST] = f_dst[i]; + assign f_vc_flat[(i+1)*VC-1:i*VC] = f_vc[i]; + assign f_data_flat[(i+1)*DATA-1:i*DATA] = f_data[i]; + end + + // Muxbar + for(i=0; i < N; i=i+1) begin: steerwires + always@(grant_valids[i] or grants[i] or creds_left[i] or f_prio or f_tail or f_dst_flat or f_vc_flat or f_data_flat) begin + o_valid[i] = 1'b0; + o_prio[i] = 'hx; + o_tail[i] = 'hx; + o_dst_arr[i] = 'hx; + o_vc_arr[i] = 'hx; + o_data_arr[i] = 'hx; + + for(in=0; in < N; in=in+1) begin: innersteer + if(grant_valids[i] && (grants[i][in] == 1'b1) && (creds_left[i] != 0)) begin + o_valid[i] = 1'b1; + o_prio[i] = f_prio[in]; + o_tail[i] = f_tail[in]; + o_dst_arr[i] = f_dst[in]; + o_vc_arr[i] = f_vc[in]; + o_data_arr[i] = f_data[in]; + end + end + end + end + + + /* + // Muxbar + always@(*) begin + for(out=0; out < N; out=out+1) begin: steerwires + o_valid[out] = 1'b0; + o_prio[out] = 'hx; + o_tail[out] = 'hx; + o_dst_arr[out] = 'hx; + o_vc_arr[out] = 'hx; + o_data_arr[out] = 'hx; + + for(in=0; in < N; in=in+1) begin: innersteer + if(grant_valids[out] && (grants[out][in] == 1'b1) && (creds_left[out] != 0)) begin + o_valid[out] = 1'b1; + o_prio[out] = f_prio[in]; + o_tail[out] = f_tail[in]; + o_dst_arr[out] = f_dst[in]; + o_vc_arr[out] = f_vc[in]; + o_data_arr[out] = f_data[in]; + end + end + end + end + */ + + // Transmit credits + for(o=0; o < N; o=o+1) begin: output_credits + always@(posedge CLK) begin + if(RST_N) begin + if((o_cred_en[o] == 1'b0) && (o_valid[o] == 1'b1)) + creds_left[o] <= creds_left[o] - 1; + else if((o_cred_en[o] == 1'b1) && (o_valid[o] == 1'b0)) + creds_left[o] <= creds_left[o] + 1; + end + else begin + creds_left[o] <= BUFFER_DEPTH; + end + end + end + + ///////////////////////// + // Input Queues + ///////////////////////// + + generate + for(i=0; i < N; i=i+1) begin: ififos +/* + SizedFIFO#(.p1width(FLIT_WIDTH), .p2depth(BUFFER_DEPTH), .p3cntr_width(`clogb2(BUFFER_DEPTH))) inQ + (.CLK(CLK), + .RST_N(RST_N), + .D_IN({i_prio[i], i_tail[i], i_dst[(i+1)*DST-1:i*DST], i_vc[(i+1)*VC-1:i*VC], i_data[(i+1)*DATA-1:i*DATA]}), + .ENQ(i_valid[i]), + .D_OUT({f_prio[i], f_tail[i], f_dst[i], f_vc[i], f_data[i]}), + .DEQ(deq_en[i]), + .EMPTY_N(f_elig[i]), + .FULL_N(), // unused + .CLR(1'b0) // unused + ); +*/ + mkNetworkXbarQ inQ(.CLK(CLK), .RST_N(RST_N), + .enq_sendData({i_prio[i], i_tail[i], i_dst[(i+1)*DST-1:i*DST], i_vc[(i+1)*VC-1:i*VC], i_data[(i+1)*DATA-1:i*DATA]}), + .EN_enq(i_valid[i]), + .RDY_enq(), + .EN_deq(deq_en[i]), + .RDY_deq(), + .first({f_prio[i], f_tail[i], f_dst[i], f_vc[i], f_data[i]}), + .RDY_first(), + .notFull(), + .RDY_notFull(), + .notEmpty(f_elig[i]), + .RDY_notEmpty(), + .count(), + .RDY_count(), + .EN_clear(1'b0), + .RDY_clear()); + + end + endgenerate + +endmodule diff --git a/Prims/shift_8x64.v b/Prims/shift_8x64.v new file mode 100644 index 0000000..f9faceb --- /dev/null +++ b/Prims/shift_8x64.v @@ -0,0 +1,36 @@ +module shift_8x64_taps (clk, + shift, + sr_in, + sr_out, + sr_tap_one, + sr_tap_two, + sr_tap_three + ); + + input clk, shift; + + input [7:0] sr_in; + output [7:0] sr_tap_one, sr_tap_two, sr_tap_three, sr_out; + + reg [7:0] sr [63:0]; + integer n; + + always@(posedge clk) + begin + if (shift == 1'b1) + begin + for (n = 63; n>0; n = n-1) + begin + sr[n] <= sr[n-1]; + end + + sr[0] <= sr_in; + end + end + + assign sr_tap_one = sr[15]; + assign sr_tap_two = sr[31]; + assign sr_tap_three = sr[47]; + assign sr_out = sr[63]; + +endmodule diff --git a/Prims/shift_reg.v b/Prims/shift_reg.v new file mode 100644 index 0000000..13714c1 --- /dev/null +++ b/Prims/shift_reg.v @@ -0,0 +1,52 @@ +module shift_reg (clk, + rst_n, + shift, + sr_in, + sr_out + ); + + parameter WIDTH = 64; + parameter STAGES = 16; + input clk, rst_n, shift; + + input [WIDTH-1:0] sr_in; + output [WIDTH-1:0] sr_out; + //output [7:0] sr_tap_one, sr_tap_two, sr_tap_three, sr_out; + + reg [WIDTH-1:0] sr [STAGES-1:0]; + integer n; + + // initialize + initial begin + for (n = 0; n0; n = n-1) + begin + sr[n] <= sr[n-1]; + end + + sr[0] <= sr_in; + end + //end + end + + assign sr_out = sr[STAGES-1]; + +endmodule diff --git a/Prims/testbench_sample.v b/Prims/testbench_sample.v new file mode 100644 index 0000000..9a6b016 --- /dev/null +++ b/Prims/testbench_sample.v @@ -0,0 +1,151 @@ +/* ========================================================================= + * + * Filename: testbench_sample.v + * Date created: 05-28-2012 + * Last modified: 06-09-2012 + * Authors: Michael Papamichael + * + * Description: + * Minimal testbench sample for CONNECT networks + * + * ========================================================================= + */ + +`ifndef XST_SYNTH + +`timescale 1ns / 1ps + +`include "connect_parameters.v" + + +module CONNECT_testbench_sample(); + parameter HalfClkPeriod = 5; + localparam ClkPeriod = 2*HalfClkPeriod; + + // non-VC routers still reeserve 1 dummy bit for VC. + localparam vc_bits = (`NUM_VCS > 1) ? $clog2(`NUM_VCS) : 1; + localparam dest_bits = $clog2(`NUM_USER_RECV_PORTS); + localparam flit_port_width = 2 /*valid and tail bits*/+ `FLIT_DATA_WIDTH + dest_bits + vc_bits; + localparam credit_port_width = 1 + vc_bits; // 1 valid bit + localparam test_cycles = 20; + + reg Clk; + reg Rst_n; + + // input regs + reg send_flit [0:`NUM_USER_SEND_PORTS-1]; // enable sending flits + reg [flit_port_width-1:0] flit_in [0:`NUM_USER_SEND_PORTS-1]; // send port inputs + + reg send_credit [0:`NUM_USER_RECV_PORTS-1]; // enable sending credits + reg [credit_port_width-1:0] credit_in [0:`NUM_USER_RECV_PORTS-1]; //recv port credits + + // output wires + wire [credit_port_width-1:0] credit_out [0:`NUM_USER_SEND_PORTS-1]; + wire [flit_port_width-1:0] flit_out [0:`NUM_USER_RECV_PORTS-1]; + + reg [31:0] cycle; + integer i; + + // packet fields + reg is_valid; + reg is_tail; + reg [dest_bits-1:0] dest; + reg [vc_bits-1:0] vc; + reg [`FLIT_DATA_WIDTH-1:0] data; + + // Generate Clock + initial Clk = 0; + always #(HalfClkPeriod) Clk = ~Clk; + + // Run simulation + initial begin + cycle = 0; + for(i = 0; i < `NUM_USER_SEND_PORTS; i = i + 1) begin flit_in[i] = 0; send_flit[i] = 0; end + for(i = 0; i < `NUM_USER_RECV_PORTS; i = i + 1) begin credit_in[i] = 0; send_credit[i] = 0; end + + $display("---- Performing Reset ----"); + Rst_n = 0; // perform reset (active low) + #(5*ClkPeriod+HalfClkPeriod); + Rst_n = 1; + #(HalfClkPeriod); + + // send a 2-flit packet from send port 0 to receive port 1 + send_flit[0] = 1'b1; + dest = 1; + vc = 0; + data = 'ha; + flit_in[0] = {1'b1 /*valid*/, 1'b0 /*tail*/, dest, vc, data}; + $display("@%3d: Injecting flit %x into send port %0d", cycle, flit_in[0], 0); + + #(ClkPeriod); + // send 2nd flit of packet + send_flit[0] = 1'b1; + data = 'hb; + flit_in[0] = {1'b1 /*valid*/, 1'b1 /*tail*/, dest, vc, data}; + $display("@%3d: Injecting flit %x into send port %0d", cycle, flit_in[0], 0); + + #(ClkPeriod); + // stop sending flits + send_flit[0] = 1'b0; + flit_in[0] = 'b0; // valid bit + end + + + // Monitor arriving flits + always @ (posedge Clk) begin + cycle <= cycle + 1; + for(i = 0; i < `NUM_USER_RECV_PORTS; i = i + 1) begin + if(flit_out[i][flit_port_width-1]) begin // valid flit + $display("@%3d: Ejecting flit %x at receive port %0d", cycle, flit_out[i], i); + end + end + + // terminate simulation + if (cycle > test_cycles) begin + $finish(); + end + end + + // Add your code to handle flow control here (sending receiving credits) + + // Instantiate CONNECT network + mkNetwork dut + (.CLK(Clk) + ,.RST_N(Rst_n) + + ,.send_ports_0_putFlit_flit_in(flit_in[0]) + ,.EN_send_ports_0_putFlit(send_flit[0]) + + ,.EN_send_ports_0_getCredits(1'b1) // drain credits + ,.send_ports_0_getCredits(credit_out[0]) + + ,.send_ports_1_putFlit_flit_in(flit_in[1]) + ,.EN_send_ports_1_putFlit(send_flit[1]) + + ,.EN_send_ports_1_getCredits(1'b1) // drain credits + ,.send_ports_1_getCredits(credit_out[1]) + + // add rest of send ports here + // + + ,.EN_recv_ports_0_getFlit(1'b1) // drain flits + ,.recv_ports_0_getFlit(flit_out[0]) + + ,.recv_ports_0_putCredits_cr_in(credit_in[0]) + ,.EN_recv_ports_0_putCredits(send_credit[0]) + + ,.EN_recv_ports_1_getFlit(1'b1) // drain flits + ,.recv_ports_1_getFlit(flit_out[1]) + + ,.recv_ports_1_putCredits_cr_in(credit_in[1]) + ,.EN_recv_ports_1_putCredits(send_credit[1]) + + // add rest of receive ports here + // + + ); + + +endmodule + +`endif diff --git a/Prims/testbench_sample_peek.v b/Prims/testbench_sample_peek.v new file mode 100644 index 0000000..73fc13c --- /dev/null +++ b/Prims/testbench_sample_peek.v @@ -0,0 +1,153 @@ +/* ========================================================================= + * + * Filename: testbench_sample.v + * Date created: 05-28-2012 + * Last modified: 11-30-2012 + * Authors: Michael Papamichael + * + * Description: + * Minimal testbench sample for CONNECT networks with Peek flow control + * + * ========================================================================= + */ + +`ifndef XST_SYNTH + +`timescale 1ns / 1ps + +`include "connect_parameters.v" + + +module CONNECT_testbench_sample_peek(); + parameter HalfClkPeriod = 5; + localparam ClkPeriod = 2*HalfClkPeriod; + + // non-VC routers still reeserve 1 dummy bit for VC. + localparam vc_bits = (`NUM_VCS > 1) ? $clog2(`NUM_VCS) : 1; + localparam dest_bits = $clog2(`NUM_USER_RECV_PORTS); + localparam flit_port_width = 2 /*valid and tail bits*/+ `FLIT_DATA_WIDTH + dest_bits + vc_bits; + //localparam credit_port_width = 1 + vc_bits; // 1 valid bit + localparam credit_port_width = `NUM_VCS; // 1 valid bit + localparam test_cycles = 20; + + reg Clk; + reg Rst_n; + + // input regs + reg send_flit [0:`NUM_USER_SEND_PORTS-1]; // enable sending flits + reg [flit_port_width-1:0] flit_in [0:`NUM_USER_SEND_PORTS-1]; // send port inputs + + reg send_credit [0:`NUM_USER_RECV_PORTS-1]; // enable sending credits + reg [credit_port_width-1:0] credit_in [0:`NUM_USER_RECV_PORTS-1]; //recv port credits + + // output wires + wire [credit_port_width-1:0] credit_out [0:`NUM_USER_SEND_PORTS-1]; + wire [flit_port_width-1:0] flit_out [0:`NUM_USER_RECV_PORTS-1]; + + reg [31:0] cycle; + integer i; + + // packet fields + reg is_valid; + reg is_tail; + reg [dest_bits-1:0] dest; + reg [vc_bits-1:0] vc; + reg [`FLIT_DATA_WIDTH-1:0] data; + + // Generate Clock + initial Clk = 0; + always #(HalfClkPeriod) Clk = ~Clk; + + // Run simulation + initial begin + cycle = 0; + for(i = 0; i < `NUM_USER_SEND_PORTS; i = i + 1) begin flit_in[i] = 0; send_flit[i] = 0; end + for(i = 0; i < `NUM_USER_RECV_PORTS; i = i + 1) begin credit_in[i] = 'b1; send_credit[i] = 'b1; end //constantly provide credits + + $display("---- Performing Reset ----"); + Rst_n = 0; // perform reset (active low) + #(5*ClkPeriod+HalfClkPeriod); + Rst_n = 1; + #(HalfClkPeriod); + + // send a 2-flit packet from send port 0 to receive port 1 + send_flit[0] = 1'b1; + dest = 1; + vc = 0; + data = 'ha; + flit_in[0] = {1'b1 /*valid*/, 1'b0 /*tail*/, dest, vc, data}; + $display("@%3d: Injecting flit %x into send port %0d", cycle, flit_in[0], 0); + + #(ClkPeriod); + // send 2nd flit of packet + send_flit[0] = 1'b1; + data = 'hb; + flit_in[0] = {1'b1 /*valid*/, 1'b1 /*tail*/, dest, vc, data}; + $display("@%3d: Injecting flit %x into send port %0d", cycle, flit_in[0], 0); + + #(ClkPeriod); + // stop sending flits + send_flit[0] = 1'b0; + flit_in[0] = 'b0; // valid bit + end + + + // Monitor arriving flits + always @ (posedge Clk) begin + cycle <= cycle + 1; + for(i = 0; i < `NUM_USER_RECV_PORTS; i = i + 1) begin + if(flit_out[i][flit_port_width-1]) begin // valid flit + $display("@%3d: Ejecting flit %x at receive port %0d", cycle, flit_out[i], i); + end + end + + // terminate simulation + if (cycle > test_cycles) begin + $finish(); + end + end + + // Add your code to handle flow control here (sending receiving credits) + + // Instantiate CONNECT network + mkNetworkSimple dut + (.CLK(Clk) + ,.RST_N(Rst_n) + + ,.send_ports_0_putFlit_flit_in(flit_in[0]) + ,.EN_send_ports_0_putFlit(send_flit[0]) + + ,.EN_send_ports_0_getNonFullVCs(1'b1) // drain credits + ,.send_ports_0_getNonFullVCs(credit_out[0]) + + ,.send_ports_1_putFlit_flit_in(flit_in[1]) + ,.EN_send_ports_1_putFlit(send_flit[1]) + + ,.EN_send_ports_1_getNonFullVCs(1'b1) // drain credits + ,.send_ports_1_getNonFullVCs(credit_out[1]) + + + // add rest of send ports here + // + + ,.EN_recv_ports_0_getFlit(1'b1) // drain flits + ,.recv_ports_0_getFlit(flit_out[0]) + + ,.recv_ports_0_putNonFullVCs_nonFullVCs(credit_in[0]) + ,.EN_recv_ports_0_putNonFullVCs(send_credit[0]) + + ,.EN_recv_ports_1_getFlit(1'b1) // drain flits + ,.recv_ports_1_getFlit(flit_out[1]) + + ,.recv_ports_1_putNonFullVCs_nonFullVCs(credit_in[1]) + ,.EN_recv_ports_1_putNonFullVCs(send_credit[1]) + + // add rest of receive ports here + // + + ); + + +endmodule + +`endif diff --git a/README b/README new file mode 100644 index 0000000..1628548 --- /dev/null +++ b/README @@ -0,0 +1,175 @@ +/* ========================================================================= + * + * CONNECT - CONfigurable NEtwork Creation Tool + * Copyright (c) 2012 by Michael K. Papamichael, Carnegie Mellon University + * + * ========================================================================= + */ + +/////////////////////////////////// +//-------- General info ----------- + +CONNECT is a flexible RTL generator for fast, FPGA-friendly Networks-on-Chip. +This website serves as a front-end to CONNECT's network generation engine, which +is primarily based on Bluespec System Verilog. All networks generated through +CONNECT consist of fully synthesizable Verilog. + +CONNECT supports a variety of common network topologies, as well as custom +user-specified networks. A variety of network and router parameters, such as +router type, pipelining options, the number of virtual channels or allocator type, +allow the user to further customize the network and trade-off between resource +usage and performance. + +For license information please see the LICENSE file. + +////////////////////////////////////////////////// +//-------- Using the generated network ----------- + +All necessary files to implement a working network are located in this +directory. For networks with credit-based flow control the top module is +called "mkNetwork" and is located in the mkNetwork.v file. For networks with +peek flow control the top module is called mkNetworkSimple and is located in +the mkNetworkSimple.v file. Both the mkNetwork and mkNetworkSimple module +interfaces consist of a set of ports used for sending and receiving flits and +flow control information. + +The credit-based and peek-based networks share the same interface for sending and +receiving flits, but offer different flow-control interfaces, which are detailed +below. + +////////////////////////////////////////////////////////////////////////////////// +//-------- Data Send/Receive interface (mkNetwork and mkNetworkSimple) ----------- + +The mkNetwork credit-based interface consists of the following set of wires and buses for each port

: + + =================================== + ==== Send Port Wires and Buses ==== + =================================== + + - EN_send_ports_

_putFlit input wire: Assert when sending a flit to indicate + send_ports_P_putFlit_flit_in carries valid data. + - send_ports_

_putFlit_flit_in input bus, with the following fields: + + MSB LSB + ------------------------------------------------------------------------ + | | | | | | + ------------------------------------------------------------------------ + + Field Info: + : Indicates a valid flit. Set to 1 when sending a flit. + : Indicates this is a tail flit, i.e. the last flit of a packet. Should be + set to 1 for single-flit packets as they are also tail flits. + : Specifies the destination of the current flit. Populate with a valid + binary encoded router ID that corresponds to one of the routers in the network. + : For VC-based networks this field specifies the virtual channel to use and should be + populated with a valid VC, depending on the number of available virtual channels. + Lower VCs are prioritized over higher VCs. Networks that do not employ virtual + channels (Virtual-Output-Queued and Input-Queued) essentially behave as if they only + had a single virtual channel. As a result, for non-VC networks this field is 1-bit + wide and should be set to 0. + : User data field. Populate with data to be transfered. + + + //-------- Credit-based Flow Control Interface (mkNetwork) ----------- + - EN_send_ports_

_getCredits input wire: indicates sender is ready to receive a credit. + - send_ports_

_getCredits, output bus, with the following fields: + + MSB LSB + ----------------------------------- + | | | + ----------------------------------- + + Field Info: + : Indicates a valid credit. + : Indicates the virtual channel that the incoming credit is for. For non-VC networks + (VOQ and IQ) this field is 1-bit wide and should be set to 0. + + //-------- Peek-based Flow Control Interface (mkNetworkSimple) ----------- + - EN_send_ports_

_getNonFullVCs input wire: indicates sender is ready to receive a credit. + - send_ports_

_getNonFullVCs, output bus, that carries a bitmask indicating which VCs have available buffers space + (i.e. are non Full). MSB corresponds to the highest VC and LSB corresponds to the lowest VC. For non-VC networks + this signal is a single bit. + + + ====================================== + ==== Receive Port Wires and Buses ==== + ====================================== + + - EN_recv_ports_P_getFlit input wire: Assert when ready to receive an incoming flit. + - recv_ports_P_getFlit output bus, with the following fields: + + MSB LSB + ------------------------------------------------------------------------ + | | | | | | + ------------------------------------------------------------------------ + + Field Info: + : Indicates a valid flit. Check to see if received flit is valid. + : Indicates this is a tail flit, i.e. the last flit of a packet. Should be + set to 1 for single-flit packets as they are also tail flits. + : Specifies the destination of the received flit. + : Specifies the virtual channel of the received flit. Ignore for non-VC networks + : User data field. Contains the transferred data. + + //-------- Credit-based Flow Control Interface (mkNetwork) ----------- + - EN_recv_ports_P_putCredits input wire: indicates receiver is sending a credit. Assert when sending a credit. + - recv_ports_P_putCredits_cr_in, input bus, with the following fields: + + MSB LSB + ----------------------------------- + | | | + ----------------------------------- + + Field Info: + : Indicates a valid credit. + : Indicates the virtual channel that the outgoing credit is for. + + //-------- Peek-based Flow Control Interface (mkNetworkSimple) ----------- + - EN_recv_ports_

_putNonFullVCs input wire: indicates sender is ready to receive a credit. + - recv_ports_

_putNonFullVCs, input bus, which is a bitmask indicating which VCs have available buffers space + (i.e. are non Full). MSB corresponds to the highest VC and LSB corresponds to the lowest VC. For non-VC networks + this signal is a single bit. + + + ====================================================== + ==== Credit-based Flow Control - Credit Handling ==== + ====================================================== + + For CONNECT-generated networks that use credit-based flow control network clients + need to maintain and exchange flow control information (i.e. credits) with the + routers they are connected to. + + - Outgoing traffic (sending flits as a client) + Each client needs to maintain credit counters (one per VC) and a client + should only send a flit into the network if the corresponding credit counter + for the particular VC is non-zero. Credit counters should be initialized + according to the selected Flit Buffer Depth (e.g. for a Flit Buffer Depth of 7, + credit counters would need to be initialized to the value 7 after reset). Once + the flit is injected into the network the client needs to decrement the number + of available credits for the particular VC to keep track of remaining credits. + + - Incoming traffic (receiving flits as a client) + Each client needs to maintain incoming flit buffers (one per VC) to store the + flits it receives. These flit buffers need to be sized according to the + selected Flit Buffer Depth (e.g. for a Flit Buffer depth of 7, the depth of + the incoming flit buffers should be at least 7 entries deep). Each time the + client dequeues a flit from one of its incoming flit buffers, it needs to send + a credit for the corresponding VC to inform the router about the newly + available space. Routers initially assume that they have enough credits to + fill the client's incoming flit buffers. + + Note that if client is guaranteed to instantly consume every incoming flit, + then it does not need to maintain incoming flit buffers; however it still has + to provide a credit to the router for each incoming flit. + + + ============================ + ==== Peek Flow Control ==== + ============================ + + CONNECT-generated networks that use Peek flow control offer a simpler interface. + Instead of maintaing and exchanging credits, network clients simply need to + check if the buffer they intend to inject into is not full by checking the + send_ports_

_getNonFullVCs signal. In the case of VC-based networks they need to + check the specific bit that corresponds to the VC that the flit belongs to. + diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..477c1e7 --- /dev/null +++ b/README.txt @@ -0,0 +1,17 @@ +/* ========================================================================= + * + * Filename: README.txt + * Date created: 04-23-2011 + * Last modified: 04-23-2011 + * Authors: Michael Papamichael + * + * Description: + * Contains instructions on using CONNECT (CONfigurable NEtwork Creation Tool). + * Work in progress. + * + * ========================================================================= + */ + +//-------- Generating network RTL ----------- +Run the gen_network.py tool. Use the -h flag for further usage information. + diff --git a/RF_16ports.bsv b/RF_16ports.bsv new file mode 100644 index 0000000..0e81a3d --- /dev/null +++ b/RF_16ports.bsv @@ -0,0 +1,269 @@ +/* + * ========================================================================= + * + * Filename: RF_16ports.bsv + * Date created: 03-29-2011 + * Last modified: 03-29-2011 + * Authors: Michael Papamichael + * + * Description: + * 16-port register file that efficiently maps to LUT RAM. + * Unused ports should get pruned out by synthesis tool. + * Requires RegFile_16ports.v file. (see bottom) + * + */ + +import Vector::*; + +////////////////////////////////////////////////////////////////// +// 16-port register file implementation that maps to LUT RAM +////////////////////////////////////////////////////////////////// + +interface RegFileSingleReadPort#(type index_t, type data_t); + method data_t read(index_t idx_r); +endinterface + +interface RF_16ports#(type index_t, type data_t); + method Action write(index_t idx_w, data_t din_w); + interface Vector#(16, RegFileSingleReadPort#(index_t, data_t)) read_ports; +endinterface + +module mkRF_16ports (RF_16ports#(index_t, data_t)) + provisos(Bits#(data_t, data_width_t), + Bits#(index_t, index_width_t), + Arith#(index_t), + Bounded#(index_t), + Literal#(index_t), + Eq#(index_t)); + + Vector#(16, RegFileSingleReadPort#(index_t, data_t)) read_ports_ifaces; + RegFile_16ports#(index_t, data_t) reg_file <- mkRegFile_16ports(); + + + for (Integer i=0; i < 16; i=i+1) begin + let ifc = + interface RegFileSingleReadPort#(index_t) + method data_t read(index_t idx_r); + case(i) + 0: return reg_file.read_0(idx_r); + 1: return reg_file.read_1(idx_r); + 2: return reg_file.read_2(idx_r); + 3: return reg_file.read_3(idx_r); + 4: return reg_file.read_4(idx_r); + 5: return reg_file.read_5(idx_r); + 6: return reg_file.read_6(idx_r); + 7: return reg_file.read_7(idx_r); + 8: return reg_file.read_8(idx_r); + 9: return reg_file.read_9(idx_r); + 10: return reg_file.read_10(idx_r); + 11: return reg_file.read_11(idx_r); + 12: return reg_file.read_12(idx_r); + 13: return reg_file.read_13(idx_r); + 14: return reg_file.read_14(idx_r); + 15: return reg_file.read_15(idx_r); + endcase + endmethod + endinterface; + read_ports_ifaces[i] = ifc; + end + + interface read_ports = read_ports_ifaces; + + method Action write(index_t idx_w, data_t din_w); + reg_file.write(idx_w, din_w); + endmethod + +endmodule + +//////////////////////////////////////////////////////////////// + +interface RegFile_16ports#(type index_t, type data_t); + method Action write(index_t idx_w, data_t din_w); + method data_t read_0(index_t idx_r); + method data_t read_1(index_t idx_r); + method data_t read_2(index_t idx_r); + method data_t read_3(index_t idx_r); + method data_t read_4(index_t idx_r); + method data_t read_5(index_t idx_r); + method data_t read_6(index_t idx_r); + method data_t read_7(index_t idx_r); + method data_t read_8(index_t idx_r); + method data_t read_9(index_t idx_r); + method data_t read_10(index_t idx_r); + method data_t read_11(index_t idx_r); + method data_t read_12(index_t idx_r); + method data_t read_13(index_t idx_r); + method data_t read_14(index_t idx_r); + method data_t read_15(index_t idx_r); +endinterface + +import "BVI" RegFile_16ports = +module mkRegFile_16ports (RegFile_16ports#(index_t, data_t)) + provisos(Bits#(data_t, data_width_t), + Bits#(index_t, index_width_t), + Arith#(index_t), + Bounded#(index_t), + Literal#(index_t), + Eq#(index_t)); + + parameter data_width = valueof(data_width_t); + parameter addr_width = valueof(index_width_t); + + default_clock( CLK ); + default_reset( rst_n ); + + schedule (write, read_0, read_1, read_2, read_3, read_4, read_5, read_6, read_7, read_8, read_9, read_10, read_11, read_12, read_13, read_14, read_15) CF (write, read_0, read_1, read_2, read_3, read_4, read_5, read_6, read_7, read_8, read_9, read_10, read_11, read_12, read_13, read_14, read_15); + + method write(ADDR_IN, D_IN) enable(WE); + method D_OUT_1 read_0(ADDR_1 ); + method D_OUT_2 read_1(ADDR_2 ); + method D_OUT_3 read_2(ADDR_3 ); + method D_OUT_4 read_3(ADDR_4 ); + method D_OUT_5 read_4(ADDR_5 ); + method D_OUT_6 read_5(ADDR_6 ); + method D_OUT_7 read_6(ADDR_7 ); + method D_OUT_8 read_7(ADDR_8 ); + method D_OUT_9 read_8(ADDR_9 ); + method D_OUT_10 read_9(ADDR_10); + method D_OUT_11 read_10(ADDR_11); + method D_OUT_12 read_11(ADDR_12); + method D_OUT_13 read_12(ADDR_13); + method D_OUT_14 read_13(ADDR_14); + method D_OUT_15 read_14(ADDR_15); + method D_OUT_16 read_15(ADDR_16); + +endmodule + + +/////////////////////////////////// +// RegFile_16ports Verilog module +/////////////////////////////////// + +// Multi-ported Register File +//module RegFile_16ports(CLK, rst_n, +// ADDR_IN, D_IN, WE, +// ADDR_1, D_OUT_1, +// ADDR_2, D_OUT_2, +// ADDR_3, D_OUT_3, +// ADDR_4, D_OUT_4, +// ADDR_5, D_OUT_5, +// ADDR_6, D_OUT_6, +// ADDR_7, D_OUT_7, +// ADDR_8, D_OUT_8, +// ADDR_9, D_OUT_9, +// ADDR_10, D_OUT_10, +// ADDR_11, D_OUT_11, +// ADDR_12, D_OUT_12, +// ADDR_13, D_OUT_13, +// ADDR_14, D_OUT_14, +// ADDR_15, D_OUT_15, +// ADDR_16, D_OUT_16 +// ); +// +// // synopsys template +// parameter data_width = 1; +// parameter addr_width = 1; +// parameter depth = 1< + * + * Description: + * 16-port register file that efficiently maps to LUT RAM. + * Initial Contents can be loaded through file. + * Unused ports should get pruned out by synthesis tool. + * Requires RegFile_16ports.v file. (see bottom) + * + */ + +import Vector::*; + +////////////////////////////////////////////////////////////////// +// 16-port register file implementation that maps to LUT RAM +////////////////////////////////////////////////////////////////// + +interface RegFileSingleReadPort#(type index_t, type data_t); + method data_t read(index_t idx_r); +endinterface + +interface RF_16portsLoad#(type index_t, type data_t); + method Action write(index_t idx_w, data_t din_w); + interface Vector#(16, RegFileSingleReadPort#(index_t, data_t)) read_ports; +endinterface + +module mkRF_16portsLoad #(String loadfile, Bool binary) (RF_16portsLoad#(index_t, data_t)) + provisos(Bits#(data_t, data_width_t), + Bits#(index_t, index_width_t), + Arith#(index_t), + Bounded#(index_t), + Literal#(index_t), + Eq#(index_t)); + + Vector#(16, RegFileSingleReadPort#(index_t, data_t)) read_ports_ifaces; + RegFile_16portsLoad#(index_t, data_t) reg_file <- mkRegFile_16portsLoad(loadfile, binary); + + + for (Integer i=0; i < 16; i=i+1) begin + let ifc = + interface RegFileSingleReadPort#(index_t) + method data_t read(index_t idx_r); + case(i) + 0: return reg_file.read_0(idx_r); + 1: return reg_file.read_1(idx_r); + 2: return reg_file.read_2(idx_r); + 3: return reg_file.read_3(idx_r); + 4: return reg_file.read_4(idx_r); + 5: return reg_file.read_5(idx_r); + 6: return reg_file.read_6(idx_r); + 7: return reg_file.read_7(idx_r); + 8: return reg_file.read_8(idx_r); + 9: return reg_file.read_9(idx_r); + 10: return reg_file.read_10(idx_r); + 11: return reg_file.read_11(idx_r); + 12: return reg_file.read_12(idx_r); + 13: return reg_file.read_13(idx_r); + 14: return reg_file.read_14(idx_r); + 15: return reg_file.read_15(idx_r); + endcase + endmethod + endinterface; + read_ports_ifaces[i] = ifc; + end + + interface read_ports = read_ports_ifaces; + + method Action write(index_t idx_w, data_t din_w); + reg_file.write(idx_w, din_w); + endmethod + +endmodule + +//////////////////////////////////////////////////////////////// + +interface RegFile_16portsLoad#(type index_t, type data_t); + method Action write(index_t idx_w, data_t din_w); + method data_t read_0(index_t idx_r); + method data_t read_1(index_t idx_r); + method data_t read_2(index_t idx_r); + method data_t read_3(index_t idx_r); + method data_t read_4(index_t idx_r); + method data_t read_5(index_t idx_r); + method data_t read_6(index_t idx_r); + method data_t read_7(index_t idx_r); + method data_t read_8(index_t idx_r); + method data_t read_9(index_t idx_r); + method data_t read_10(index_t idx_r); + method data_t read_11(index_t idx_r); + method data_t read_12(index_t idx_r); + method data_t read_13(index_t idx_r); + method data_t read_14(index_t idx_r); + method data_t read_15(index_t idx_r); +endinterface + +import "BVI" RegFile_16ports_load = +module mkRegFile_16portsLoad #(String loadfile, Bool binary) (RegFile_16portsLoad#(index_t, data_t)) + provisos(Bits#(data_t, data_width_t), + Bits#(index_t, index_width_t), + Arith#(index_t), + Bounded#(index_t), + Literal#(index_t), + Eq#(index_t)); + + parameter data_width = valueof(data_width_t); + parameter addr_width = valueof(index_width_t); + parameter load_file = loadfile; + parameter binary = pack(binary); // convert to Bit#(1) + + default_clock( CLK ); + default_reset( rst_n ); + + schedule (write, read_0, read_1, read_2, read_3, read_4, read_5, read_6, read_7, read_8, read_9, read_10, read_11, read_12, read_13, read_14, read_15) CF (write, read_0, read_1, read_2, read_3, read_4, read_5, read_6, read_7, read_8, read_9, read_10, read_11, read_12, read_13, read_14, read_15); + + method write(ADDR_IN, D_IN) enable(WE); + method D_OUT_1 read_0(ADDR_1 ); + method D_OUT_2 read_1(ADDR_2 ); + method D_OUT_3 read_2(ADDR_3 ); + method D_OUT_4 read_3(ADDR_4 ); + method D_OUT_5 read_4(ADDR_5 ); + method D_OUT_6 read_5(ADDR_6 ); + method D_OUT_7 read_6(ADDR_7 ); + method D_OUT_8 read_7(ADDR_8 ); + method D_OUT_9 read_8(ADDR_9 ); + method D_OUT_10 read_9(ADDR_10); + method D_OUT_11 read_10(ADDR_11); + method D_OUT_12 read_11(ADDR_12); + method D_OUT_13 read_12(ADDR_13); + method D_OUT_14 read_13(ADDR_14); + method D_OUT_15 read_14(ADDR_15); + method D_OUT_16 read_15(ADDR_16); + +endmodule + + +/////////////////////////////////// +// RegFile_16ports Verilog module +/////////////////////////////////// + +// Multi-ported Register File +//module RegFile_16ports(CLK, rst_n, +// ADDR_IN, D_IN, WE, +// ADDR_1, D_OUT_1, +// ADDR_2, D_OUT_2, +// ADDR_3, D_OUT_3, +// ADDR_4, D_OUT_4, +// ADDR_5, D_OUT_5, +// ADDR_6, D_OUT_6, +// ADDR_7, D_OUT_7, +// ADDR_8, D_OUT_8, +// ADDR_9, D_OUT_9, +// ADDR_10, D_OUT_10, +// ADDR_11, D_OUT_11, +// ADDR_12, D_OUT_12, +// ADDR_13, D_OUT_13, +// ADDR_14, D_OUT_14, +// ADDR_15, D_OUT_15, +// ADDR_16, D_OUT_16 +// ); +// +// // synopsys template +// parameter data_width = 1; +// parameter addr_width = 1; +// parameter depth = 1< + * + * Description: + * Single-port register file that efficiently maps to LUT RAM. + * Requires RegFile_1port.v file. (see bottom) + * + */ + +import Vector::*; + +////////////////////////////////////////////////////////////////// +// Single-port register file implementation that maps to LUT RAM +////////////////////////////////////////////////////////////////// + +interface RF_1port#(type index_t, type data_t); + method Action write(index_t idx_w, data_t din_w); + method data_t read(index_t idx_r); +endinterface + +import "BVI" RegFile_1port = +module mkRF_1port (RF_1port#(index_t, data_t)) + provisos(Bits#(data_t, data_width_t), + Bits#(index_t, index_width_t), + Arith#(index_t), + Bounded#(index_t), + Literal#(index_t), + Eq#(index_t)); + + parameter data_width = valueof(data_width_t); + parameter addr_width = valueof(index_width_t); + + default_clock( CLK ); + default_reset( rst_n ); + + schedule (write, read) CF (write, read); + + method write(ADDR_IN, D_IN) enable(WE); + method D_OUT read(ADDR_OUT ); + +endmodule + + +/////////////////////////////////// +// RegFile_16ports Verilog module +/////////////////////////////////// + +// Multi-ported Register File +//module RegFile_1port(CLK, rst_n, +// ADDR_IN, D_IN, WE, +// ADDR_OUT, D_OUT +// ); +// +// // synopsys template +// parameter data_width = 1; +// parameter addr_width = 1; +// parameter depth = 1< 0, "Index width must be > 0" ); + + function Bit#(index_nt) incr(Bit#(index_nt) i); + return i+1; + endfunction + + function Bit#(index_nt) decr(Bit#(index_nt) i); + return i-1; + endfunction + + Reg#(Bool) full <- mkReg(False); + Reg#(Bool) almost_full <- mkReg(False); + Reg#(Bool) empty <- mkReg(True); + + + (* fire_when_enabled *) + rule work (True); + + if(isValid(w_clr.wget)) begin + head <= 0; + tail <= 0; + enq_cnt <= 0; + deq_cnt <= 0; + full <= False; + almost_full <= False; + empty <= True; + size_cnt <= 0; + end + + else begin + + if (isValid(w_deq.wget)) begin + head <= incr( head ); + deq_cnt <= deq_cnt + 1; + end + + if (isValid(w_enq.wget)) begin + let value = validValue(w_enq.wget); + //mem.upd( tail, value ); + mem[tail] <= value; + tail <= incr( tail ); + enq_cnt <= enq_cnt + 1; + end + + Bool nfull = full; + Bool nempty = empty; + Bool nalmost_full = almost_full; + let nsize = size_cnt; + + if(isValid(w_deq.wget) && isValid(w_enq.wget)) begin // queue remains same size, no change in status signals + nfull = full; + nempty = empty; + nalmost_full = almost_full; + end + else if(isValid(w_deq.wget)) begin + nfull = False; + nalmost_full = ( tail == head ); + nempty = ( incr( head ) == tail ); + nsize = size_cnt-1; + end + else if(isValid(w_enq.wget)) begin + nfull = ( incr(tail) == head ); + nalmost_full = ( (tail+2) == head ); + nempty = False; // if enqueuing, then definitely not empty + nsize = size_cnt+1; + end + + empty <= nempty; + full <= nfull; + almost_full <= nalmost_full || nfull; + size_cnt <= nsize; + + end + endrule + + continuousAssert( ! (empty && ( enq_cnt != deq_cnt ) ), "mismatched in enq/deq count" ); + + Bool logical_empty = (head == tail) && !full; // not synthesized + continuousAssert( empty == logical_empty, "error in empty signals" ); + + let pos = getStringPosition(name); + String pos_str = printPosition(pos); + + //method value_t first(); + // let rslt = mem[head]; + // return rslt; + //endmethod + + //method value_t first = mem.sub( head ); + method value_t first = mem[head]; + method notFull = !full; + method notEmpty = !empty; + //method almostFull = almost_full; + + + method Action enq(value_t value) if (!full || !guarded); + w_enq.wset(value); + if(full) + $display("location of dfifo: ", pos_str); + dynamicAssert( !full, "ouch, enqueuing to full FIFO" ); + endmethod + + method Action deq() if (!empty || !guarded); + w_deq.wset(?); + if(empty) + $display("location of dfifo: ", pos_str); + dynamicAssert( !empty, "ouch, dequeueing from empty FIFO" ); + endmethod + + method Action clear(); + w_clr.wset(?); + endmethod + + method count() = size_cnt; + +endmodule + + +/////////////////////////////////////////////// +// LUT FIFO test + +typedef 4 FIFODepth; +typedef Bit#(32) Data_t; +typedef FIFOCountIfc#(Data_t, FIFODepth) RegFIFOSynth; + +(* synthesize *) +module mkRegFIFOSynth(RegFIFOSynth); + RegFIFOSynth f <- mkRegFIFO(False); + return f; +endmodule + +/*typedef FIFOF#(Data_t) RegFIFOSynth2; +(* synthesize *) +module mkRegFIFOSynth2(RegFIFOSynth2); + RegFIFOSynth2 f <- mkUGSizedFIFOF(4); + return f; +endmodule +*/ + +/* +module mkSizedLUTRAMFIFOF#(NumTypeParam#(t_DEPTH) dummy) + // + //interface: + (FIFOF#(data_T)) + provisos + (Bits#(data_T, data_SZ)); + + LUTRAM#(Bit#(TLog#(t_DEPTH)), data_T) rs <- mkLUTRAMU(); + + COUNTER#(TLog#(t_DEPTH)) head <- mkLCounter(0); + COUNTER#(TLog#(t_DEPTH)) tail <- mkLCounter(0); + + Bool full = head.value() == (tail.value() + 1); + Bool empty = head.value() == tail.value(); + + //method Action enq(data_T d) if (!full); + method Action enq(data_T d); + + rs.upd(tail.value(), d); + tail.up(); + + endmethod + + //method data_T first() if (!empty); + method data_T first(); + + return rs.sub(head.value()); + + endmethod + + method Action deq(); + + head.up(); + + endmethod + + method Action clear(); + + tail.setC(0); + head.setC(0); + + endmethod + + method Bool notEmpty(); + return !empty; + endmethod + + method Bool notFull(); + return !full; + endmethod + +endmodule +*/ + diff --git a/Router.bsv b/Router.bsv new file mode 100644 index 0000000..84263c8 --- /dev/null +++ b/Router.bsv @@ -0,0 +1,866 @@ +/* ========================================================================= + * + * Filename: Router.bsv + * Date created: 04-23-2011 + * Last modified: 06-02-2011 + * Authors: Michael Papamichael + * + * Description: + * Parameterized Router module. Used as building block for building larger + * networks. + * + * ========================================================================= + */ + +`include "inc.v" + +import FIFO::*; +//import FIFOF::*; +import Vector::*; +import RegFile::*; +import ConfigReg::*; +import Assert::*; + +import NetworkTypes::*; +import Aux::*; +import RF_16ports::*; +import RF_16portsLoad::*; +import RegFileMultiport::*; + +import FIFOLevel::*; +import MultiFIFOMem::*; +import RegFIFO::*; + +// Arbiters and Allocators used for scheduling +import Arbiters::*; +import Allocators::*; + +typedef MultiFIFOMem#(Flit_t, NumVCs, FlitBufferDepth) InputVCQueues; +(* synthesize *) +module mkInputVCQueues(InputVCQueues); + InputVCQueues inputVCQueues_ifc <- mkMultiFIFOMem(False /*storeHeadsTailsInLUTRAM*/, 0 /* full_margin */ ); + return inputVCQueues_ifc; +endmodule + +typedef FIFOCountIfc#(OutPort_t, FlitBufferDepth) OutPortFIFO; +(* synthesize *) +module mkOutPortFIFO(OutPortFIFO); + //String fifo_name = strConcat( strConcat(integerToString(id1), " - "), integerToString(id2)); + //OutPortFIFO outPortFIFO_ifc <- mkRegFIFO_named(fifo_name, False); + OutPortFIFO outPortFIFO_ifc <- mkRegFIFO(False); + return outPortFIFO_ifc; +endmodule + +//typedef RF_16portsLoad#(RouterID_t, OutPort_t) RouteTableOld; +//typedef RegFileMultiport#(NumInPorts/*nr*/, 1/*nw*/, RouterID_t, OutPort_t) RouteTable; +//typedef RegFileMultiport#(NumInPorts/*nr*/, 1/*nw*/, UserPortID_t, OutPort_t) RouteTable; +typedef RegFileMultiport#(NumInPorts/*nr*/, 1/*nw*/, UserRecvPortID_t, OutPort_t) RouteTable; +module mkRouteTable#(String route_table_file) (RouteTable); + //RouteTable rt_ifc <- mkRF_16portsLoad(route_table_file); + RouteTable rt_ifc <- mkRegFileMultiportLoad(route_table_file); + return rt_ifc; +endmodule + +(* synthesize *) +module mkRouteTableSynth(RouteTable); + String route_table_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(4)), ".hex"); + //RouteTableOld rt_ifc <- mkRF_16portsLoad(route_table_file, False); + RouteTable rt_ifc <- mkRegFileMultiportLoad(route_table_file); + return rt_ifc; +endmodule + +//////////////////////////////////////////////// +// Router Module implementation +//////////////////////////////////////////////// +module mkRouter#(Integer id)(Router); + String name = "Router"; + Bit#(8) errorCode = 0; + + Vector#(NumInPorts, InPort) inPort_ifaces; // in port interfaces +`ifdef EN_DBG + RouterCore router_core <- mkRouterCore(id); +`else + RouterCore router_core <- mkRouterCore(); +`endif + // Route Table + String route_table_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(id)), ".hex"); + //String route_table_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(0)), ".hex"); + //RF_16portsLoad#(RouterID_t, OutPort_t) routeTable <- mkRF_16portsLoad(route_table_file, /*binary*/False); + //RouteTable routeTable <- mkRouteTable(route_table_file, /*binary*/False); + RouteTable routeTable <- mkRouteTable(route_table_file); + + // for debugging + `ifdef EN_DBG + Reg#(Cycle_t) cycles <- mkConfigReg(0); + rule update_cycles(True); + cycles <= cycles + 1; + endrule + `endif + + // Define input interfaces + for(Integer i=0; i < valueOf(NumInPorts); i=i+1) begin + let ifc = + interface InPort + method Action putFlit(Maybe#(Flit_t) flit_in); + Maybe#(RoutedFlit_t) rt_flit = Invalid; + //`DBG_ID(("Receiving Flit on in_port %0d", i)); + if(isValid(flit_in)) begin + let fl_in = flit_in.Valid; + let out_p = routeTable.r[i].sub(fl_in.dst); + //let fl_in = tagged Valid Flit_t{is_tail:flit_in.Valid.is_tail, dst:flit_in.Valid.dst, out_p:out_p, vc:flit_in.Valid.vc, data:flit_in.Valid.data}; + rt_flit = tagged Valid RoutedFlit_t{flit:fl_in, out_port:out_p}; + //rt_flit = tagged Valid RoutedFlit_t{ flit:Flit_t{is_tail:fl_in.is_tail, dst:fl_in.dst, out_p:out_p, vc:fl_in.vc, data:fl_in.data}, out_port:out_p}; + `DBG_ID_CYCLES(("Incoming flit on port %0d - dest:%0d, vc:%0d, data:%x", i, fl_in.dst, fl_in.vc, fl_in.data )); + //if(i==0) begin + // //`DBG(("Cycle:%0d - Injected flit into router %0d - dest:%0d, tail:%0d, vc:%0d, data:%x", cycles, id, fl_in.dst, fl_in.is_tail, fl_in.vc, fl_in.data )); + // `DBG_ID(("Cycle:%0d - Injected flit - dest:%0d, vc:%0d, data:%x", cycles, fl_in.dst, fl_in.vc, fl_in.data )); + //end else begin + // //`DBG(("Cycle:%0d - Router %0d received flit through in_port %0d - dest:%0d, tail:%0d, vc:%0d, data:%x", cycles, id, i, fl_in.dst, fl_in.is_tail, fl_in.vc, fl_in.data )); + // `DBG_ID(("Cycle:%0d - Received flit through in_port %0d - dest:%0d, vc:%0d, data:%x", cycles, i, fl_in.dst, fl_in.vc, fl_in.data )); + //end + end + router_core.in_ports[i].putRoutedFlit(rt_flit); + endmethod + + // send credits upstream + method ActionValue#(Credit_t) getCredits; + let cr_out <- router_core.in_ports[i].getCredits(); + return cr_out; + endmethod + endinterface; + + inPort_ifaces[i] = ifc; + end + + // Implement RouterInfo interface + //let rt_info_ifc = + // interface RouterInfo + // method RouterID_t getRouterID; + // return fromInteger(id); + // endmethod + // endinterface; + + interface in_ports = inPort_ifaces; + interface out_ports = router_core.out_ports; + //interface rt_info = rt_info_ifc; + +endmodule + + +module mkRouterSynth(Router); + let rt_synth <- mkRouter(4); + return rt_synth; +endmodule + + +// ////////////////////////////////////////////////////////////////////////////////////// +// // noinline functions to speed up Bluespec compilation +// // left-over code from old arbiter. not used anymore +// (* noinline *) +// function Tuple3#( +// Vector#(NumOutPorts, Bool ), /* eligIO_forIn */ +// Maybe#(VC_t), /* activeVC_perIn_forIn */ +// Vector#(NumOutPorts, VC_t) /* activeVC_perOut */ +// ) build_eligIO_and_other_alloc_structs_perIn ( +// Vector#(NumVCs, Bool) not_empty, +// Vector#(NumVCs, OutPort_t) outPortFIFOs_first_forIn, +// Vector#(NumOutPorts, Vector#(NumVCs, Bit#(TLog#(TAdd#(FlitBufferDepth,1))))) credits, +// Vector#(NumOutPorts, VC_t) activeVC_perOut, +// // only used if Virtual Links are enabled +// Vector#(NumOutPorts, Vector#(NumVCs, Bool )) lockedVL, +// Vector#(NumOutPorts, Vector#(NumVCs, InPort_t)) inPortVL, +// InPort_t cur_in +// ); +// +// Vector#(NumOutPorts, Bool ) eligIO_forIn = unpack(0); +// Maybe#(VC_t) activeVC_perIn_forIn = unpack(0); +// // Build eligIO and mark selected-active VC per Input (lowest VC has priority) +// for(Integer v=valueOf(NumVCs)-1; v>=0; v=v-1) begin // lowest VC has highest priority +// if(not_empty[v]) begin +// let out_port = outPortFIFOs_first_forIn[v]; +// +// if(`USE_VIRTUAL_LINKS) begin +// if(credits[out_port][v] > 0) begin +// let is_locked = lockedVL[out_port][v]; +// if( !is_locked || (is_locked && inPortVL[out_port][v] == cur_in ) ) begin +// activeVC_perIn_forIn = tagged Valid fromInteger(v); +// activeVC_perOut[out_port] = fromInteger(v); +// eligIO_forIn[out_port] = True; +// end +// end +// end else begin +// if(credits[out_port][v] > 0) begin +// activeVC_perIn_forIn = tagged Valid fromInteger(v); +// activeVC_perOut[out_port] = fromInteger(v); +// eligIO_forIn[out_port] = True; +// end +// end +// +// +// // if(credits[out_port][v] > 0) begin +// // activeVC_perIn_forIn = tagged Valid fromInteger(v); +// // activeVC_perOut[out_port] = fromInteger(v); +// // eligIO_forIn[out_port] = True; +// // end +// end +// end +// +// return tuple3(eligIO_forIn, activeVC_perIn_forIn, activeVC_perOut); +// endfunction +// +// (* noinline *) +// function Tuple3#( +// Vector#(NumInPorts, Vector#(NumOutPorts, Bool ) ), /* eligIO */ +// Vector#(NumInPorts, Maybe#(VC_t)), /* activeVC_perIn */ +// Vector#(NumOutPorts, VC_t) /* activeVC_perOut */ +// ) build_eligIO_and_other_alloc_structs ( +// Vector#(NumInPorts, Vector#(NumVCs, Bool) ) flitBuffers_notEmpty, +// Vector#(NumInPorts, Vector#(NumVCs, OutPort_t) ) outPortFIFOs_first, +// Vector#(NumOutPorts, Vector#(NumVCs, Bit#(TLog#(TAdd#(FlitBufferDepth,1))))) credits, +// // only used if Virtual Links are enabled +// Vector#(NumOutPorts, Vector#(NumVCs, Bool )) lockedVL, +// Vector#(NumOutPorts, Vector#(NumVCs, InPort_t)) inPortVL +// ); +// +// Vector#(NumInPorts, Vector#(NumOutPorts, Bool ) ) eligIO = unpack(0); +// Vector#(NumInPorts, Maybe#(VC_t)) activeVC_perIn = replicate(Invalid); // arbitration populates this +// Vector#(NumOutPorts, VC_t) activeVC_perOut = replicate(0); // This is only valid if activeIn_perOut is Valid - not Maybe type to avoid spending an extra bit +// +// // Build eligIO and mark selected-active VC per Input (lowest VC has priority) +// for(Integer i=0; i=0; v=v-1) begin // lowest VC has highest priority +// // if(not_empty[v]) begin +// // let out_port = outPortFIFOs_first[i][v]; +// // if(credits[out_port][v] > 0) begin +// // activeVC_perIn[i] = tagged Valid fromInteger(v); +// // activeVC_perOut[out_port] = fromInteger(v); +// // eligIO[i][out_port] = True; +// // end +// // end +// // end +// +// end +// +// return tuple3(eligIO, activeVC_perIn, activeVC_perOut); +// endfunction + + +//////////////////////////////////////////////// +// Router Module implementation +//////////////////////////////////////////////// +//module mkRouter#(RouterID_t id) (Router); +`ifdef EN_DBG +module mkRouterCore#(Integer id)(RouterCore); +`else +(* synthesize *) +module mkRouterCore(RouterCore); +`endif + + String name = "RouterCore"; + Bit#(8) errorCode = 0; + + // Vector of input and output port interfaces + Vector#(NumInPorts, RouterCoreInPort) inPort_ifaces; // in port interfaces + Vector#(NumOutPorts, OutPort) outPort_ifaces; // out port interfaces + + // Router Allocator + RouterAllocator routerAlloc <- mkSepRouterAllocator(`PIPELINE_ALLOCATOR /*pipeline*/); + + // Router State + Vector#(NumInPorts, InputVCQueues) flitBuffers <- replicateM(mkInputVCQueues()); + //Vector#(NumInPorts, RF_16ports#(VC_t, FlitBuffer_t) ) flitBuffers <- replicateM(mkRF_16ports()); + Vector#(NumInPorts, Vector#(NumVCs, OutPortFIFO)) outPortFIFOs; + Vector#(NumOutPorts, Vector#(NumVCs, Reg#(Bit#(TLog#(TAdd#(FlitBufferDepth,1)))))) credits; + //Vector#(NumOutPorts, Vector#(NumVCs, Reg#(Bool) )) credits; + + Vector#(NumInPorts, Wire#(Maybe#(Flit_t))) hasFlitsToSend_perIn <- replicateM(mkDWire(Invalid)); + Vector#(NumInPorts, Wire#(Maybe#(Flit_t))) flitsToSend_perIn <- replicateM(mkDWire(Invalid)); + // Used for multi-flit packets that use virtual links + //if(`USE_VIRTUAL_LINKS) begin + Vector#(NumOutPorts, Vector#(NumVCs, Reg#(Bool) )) lockedVL; // locked virtual link + Vector#(NumOutPorts, Vector#(NumVCs, Reg#(InPort_t))) inPortVL; // holds current input for locked virtual channels + //end + + // Update wires + Vector#(NumOutPorts, Vector#(NumVCs, Wire#(Bool) )) credits_set; // to handle incoming credits + Vector#(NumOutPorts, Vector#(NumVCs, Wire#(Bool) )) credits_clear; // to clear credits due to outgoing flits + + // for debugging + `ifdef EN_DBG + Reg#(Cycle_t) cycles <- mkConfigReg(0); + rule update_cycles(True); + cycles <= cycles + 1; + endrule + `endif + + + // -- Initialization -- + for(Integer o=0; o=0; v=v-1) begin // lowest VC has highest priority + outPortFIFOs_first[i][v] = outPortFIFOs[i][v].first(); + end + end + + Vector#(NumOutPorts, Vector#(NumVCs, Bit#(TLog#(TAdd#(FlitBufferDepth,1))))) credit_values; + Vector#(NumOutPorts, Vector#(NumVCs, Bool )) lockedVL_values; // locked virtual link + Vector#(NumOutPorts, Vector#(NumVCs, InPort_t)) inPortVL_values; // holds current input for locked virtual channels + for(Integer o=0; o=0; v=v-1) begin // lowest VC has highest priority + if(not_empty[v]) begin + //let out_port = outPortFIFOs[i][v].first(); + let out_port = outPortFIFOs_first[i][v]; + + if(`USE_VIRTUAL_LINKS) begin + if(credits[out_port][v] > 0) begin + let is_locked = lockedVL[out_port][v]; + if( !is_locked || (is_locked && inPortVL[out_port][v] == fromInteger(i) ) ) begin + activeVC_perIn_s0[i] = tagged Valid fromInteger(v); + //activeVC_perOut[out_port] = tagged Valid fromInteger(v); + //eligIO[i] = unpack(0); + eligIO[i] = replicate(False); + eligIO[i][out_port] = True; + end + end + end else begin + if(credits[out_port][v] > 0) begin + activeVC_perIn_s0[i] = tagged Valid fromInteger(v); + //activeVC_perOut[out_port] = tagged Valid fromInteger(v); + eligIO[i] = replicate(False); + eligIO[i][out_port] = True; + end + end + + end + end + end + // -- End Option 1 -- + + // -- Option 2: more scalable, but harder to read -- +// let build_eligIO_result = build_eligIO_and_other_alloc_structs(flitBuffers_notEmpty, outPortFIFOs_first, credit_values, lockedVL_values, inPortVL_values); +// eligIO = tpl_1(build_eligIO_result); +// activeVC_perIn = tpl_2(build_eligIO_result); +// activeVC_perOut = tpl_3(build_eligIO_result); + // -- End Option 2 -- + + // Perform allocation + Vector#(NumInPorts, Bool) activeInPorts = unpack(0); + //Vector#(NumInPorts, Vector#(NumOutPorts, Bool ) ) selectedIO = routerAlloc.allocate(eligIO); + Vector#(NumInPorts, Vector#(NumOutPorts, Wire#(Bool) ) ) selectedIO_s0; //= routerAlloc.allocate(eligIO); + Vector#(NumInPorts, Vector#(NumOutPorts, Reg#(Bool) ) ) selectedIO_reg; + Vector#(NumInPorts, Vector#(NumOutPorts, Bool ) ) selectedIO; // this is popuated depending on allocator pipeline options + + for(Integer i=0; i 0; // double check that credits still exist. Alternatively change margin in mkMultiFIFOMem + if (has_flits && has_credits) begin + activeInPorts[i] = True; + //InPort_t inp = fromInteger(i); + //activeIn_perOut[selectedOut.Valid] = tagged Valid inp; + activeIn_perOut[selectedOut.Valid] = tagged Valid fromInteger(i); + end + end + end + + end + end + + rule performAllocation(True); + let alloc_result <- routerAlloc.allocate(eligIO); + for(Integer i=0; i Router: %0d - dequeing from outPortFIFOs[%0d][%0d]", id, i, activeVC_perIn[i].Valid); + + //if(fl.out_p != out_port) begin + // `DBG_ID(("Outport mismatch! fl.out_p: %d does not match out_port %d", fl.out_p, out_port)); + //end + //activeVC_perOut[out_port] <= tagged Valid activeVC_perIn[i].Valid; + end + end + endrule + + +// ////////////////////////////////////////////////////////////////////////////////////////////// +// // Old MEMOCODE arbiter - performs static priority maximal matching +// // First mask out entries that don't have credits or are ineligible to be picked - Convert to function +// Vector#(NumVCs, Vector#(NumInPorts, Vector#(NumOutPorts, Bool ) ) ) eligVIO = unpack(0); //perOut_perVC_perIn; +// for(Integer i=0; i0) begin +// eligVIO[v][i][out_port] = True; +// end +// end +// end +// end +// +// +// +// // Arbitration - packaged main arbitration logic for each output in "noinline" function --> this reduces compilation times by 2 ORDERS OF MAGNITUDE! +// Tuple3#( Vector#(NumInPorts, Maybe#(VC_t)), /* activeVC_perIn */ +// Vector#(NumOutPorts, Maybe#(InPort_t)), /* activeIn_perOut */ +// Vector#(NumOutPorts, VC_t) /* activeVC_perOut */ +// ) arb_result; +// +// arb_result = arbitrateAll(eligVIO); +// activeVC_perIn = tpl_1(arb_result); +// activeIn_perOut = tpl_2(arb_result); +// activeVC_perOut = tpl_3(arb_result); +// +// Vector#(NumInPorts, Bool) activeInPorts = unpack(0); +// for(Integer i=0; i set +// if ( hasFlitsVIO_set[v][i][o] ) begin // something came in on an in_port --> set +// hasFlitsVIO[v][i][o] <= True; +// `DBG(("Marking incoming flit for out:%0d VC:%0d from in:%0d", o, v, i)); +// //end else if ( hasFlitsVIO_clear[v][i][o] && !hasFlitsVIO_set[v][i][o]) begin // something departed --> clear +// end else if ( hasFlitsVIO_clear[v][i][o] ) begin // something departed --> clear +// `DBG(("Clearing flit for out:%0d VC:%0d from in:%0d", o, v, i)); +// hasFlitsVIO[v][i][o] <= False; +// end +// end +// end +// end +// endrule + + // Rule to update credits. Credits get replenished from out_ports and are spent when sending flits. + (* fire_when_enabled *) + rule update_credits (True); // turn off credits for debugging + for(Integer o=0; o fromInteger(valueof(FlitBufferDepth))) begin + `DBG_ID_CYCLES(("Credit overflow at out_port %0d VC %0d", o, v)); + end + end else if (!credits_set[o][v] && credits_clear[o][v]) begin // I only spent a credit + //credits[o][v] <= False; + credits[o][v] <= credits[o][v] - 1; + if(credits[o][v] == 0) begin + `DBG_ID_CYCLES(("Credit underflow at out_port %0d VC %0d", o, v)); + end + end + end + end + //`DBG_DETAIL_ID(("credits:%b", readVReg(concat(credits)) )); // flatten the array to print + endrule + + +/* rule tmp (True); + for(Integer o=0; o < valueOf(NumOutPorts); o=o+1) begin + for(Integer v=0; v Router: %0d - enqueing to outPortFIFOs[%0d][%0d]", id, i, fl_in.vc); + if(i==0) begin + //`DBG(("Cycle:%0d - Injected flit into router %0d - dest:%0d, tail:%0d, vc:%0d, data:%x", cycles, id, fl_in.dst, fl_in.is_tail, fl_in.vc, fl_in.data )); + //`DBG(("Cycle:%0d - Injected flit - dest:%0d, vc:%0d, data:%x", cycles, fl_in.dst, fl_in.vc, fl_in.data )); + end else begin + //`DBG(("Cycle:%0d - Router %0d received flit through in_port %0d - dest:%0d, tail:%0d, vc:%0d, data:%x", cycles, id, i, fl_in.dst, fl_in.is_tail, fl_in.vc, fl_in.data )); + //`DBG(("Cycle:%0d - Received flit through in_port %0d - dest:%0d, vc:%0d, data:%x", cycles, i, fl_in.dst, fl_in.vc, fl_in.data )); + end + //`DBG(("Marking incoming flit for dst:%0d VC:%0d from in:%0d (isT:%0d)", fl_in.dst, fl_in.vc, i, /*fl_in.is_head,*/ fl_in.is_tail)); + //hasFlitsVIO_set[fl_in.vc][i][out_port] <= True; + end + endmethod + + // send credits upstream + method ActionValue#(Credit_t) getCredits; + Credit_t cr_out = Invalid; + if (activeInPorts[i]) begin + cr_out = activeVC_perIn[i]; + end + return cr_out; + endmethod + endinterface; + + inPort_ifaces[i] = ifc; + end + + // Implement output interfaces + for(Integer o=0; o < valueOf(NumOutPorts); o=o+1) begin + let ifc = + interface OutPort + method ActionValue#(Maybe#(Flit_t)) getFlit(); + Maybe#(Flit_t) flitOut = Invalid; + if( isValid(activeIn_perOut[o]) ) begin // I have a flit to send + let active_in = activeIn_perOut[o].Valid; + //let active_vc = activeVC_perOut[o].Valid; + if(!isValid(activeIn_perOut[o])) begin + `DBG_ID_CYCLES(("active_in is invalid!")); + end + //if(!isValid(activeVC_perOut[o])) begin + // `DBG_ID(("active_vc is invalid!")); + //end + //let fb = flitBuffers[ active_in ].read_ports[o].read(active_vc); + //let fb <- flitBuffers[active_in].deq(active_vc); + //let fb <- flitsToSend_perIn[active_in]; + //outPortFIFOs[active_in][active_vc].deq(); + + //hasFlitsVIO_clear[active_vc][active_in][o] <= True; + //if(fb.is_tail) begin // If you see a tail unlock VL (also covers head/tail case) + // lockedVL[o][active_vc] <= False; + // //`DBG_DETAIL_ID(("UNLOCKED output %0d (was locked to in:%0d)", o, inPortVL[o][active_vc] )); + //end else begin // it's not a tail (i.e. head or in the middle of a packet), so lock the VL. + // lockedVL[o][active_vc] <= True; + // //`DBG_DETAIL_ID(("LOCKED output %0d locked to in:%0d, VC:%0d (flit %0d)", o, active_in, active_vc, fb.id )); + // inPortVL[o][active_vc] <= active_in; + //end + //flitOut = tagged Valid Flit_t{is_tail:fb.is_tail, dst:fb.dst, vc:active_vc, data:fb.data }; + //flitOut = flitsToSend_perIn[active_in]; + + `ifdef RESTRICT_UTURNS + // pruned version + // Generate pruned activeIn + dynamicAssert(active_in != fromInteger(o), "No U-turns allowed!"); + Vector#(NumInPorts, Bool) selectedInput = unpack(0); + selectedInput[active_in] = True; + let selectedInput_pruned = pruneVector(selectedInput, o); + let active_in_pruned = encoder(selectedInput_pruned); + let hasFlitsToSend_perIn_pruned = pruneVector(hasFlitsToSend_perIn, o); + flitOut = hasFlitsToSend_perIn_pruned[active_in_pruned.Valid]; + `else + //end else begin + // no pruning + flitOut = hasFlitsToSend_perIn[active_in]; + `endif + //end + + dynamicAssert(isValid(flitOut), "Output selected invalid flit!"); + let active_vc = flitOut.Valid.vc; + //dynamicAssert(flitOut.Valid.vc == active_vc, "Flit VC and active VC do not match!"); + if(flitOut.Valid.vc != active_vc) begin + `DBG_ID_CYCLES(("Flit VC %d does not match active VC %d for output %d", flitOut.Valid.vc, active_vc, o)); + end + + //if(flitOut.Valid.out_p != fromInteger(o)) begin + // `DBG_ID(("Flit out_port %d does not match actual out_port %d", flitOut.Valid.out_p, o)); + //end + + dynamicAssert(isValid(flitOut), "Allocation selected input port with invalid flit!"); + if(`USE_VIRTUAL_LINKS) begin + if(flitOut.Valid.is_tail) begin // If you see a tail unlock VL (also covers head/tail case) + lockedVL[o][active_vc] <= False; + `DBG_DETAIL_ID(("UNLOCKED output %0d (was locked to in:%0d)", o, inPortVL[o][active_vc] )); + end else begin // it's not a tail (i.e. head or in the middle of a packet), so lock the VL. + lockedVL[o][active_vc] <= True; + `DBG_DETAIL_ID(("LOCKED output %0d locked to in:%0d, VC:%0d", o, active_in, active_vc )); + inPortVL[o][active_vc] <= active_in; + end + end + // clear credits + credits_clear[o][active_vc] <= True; + + end + + return flitOut; + endmethod + + // receive credits from downstream routers + method Action putCredits(Credit_t cr_in); + `DBG_DETAIL_ID(("Receiving Credit on out_port %0d", o)); + // only mark here - perform update in rule + if(isValid(cr_in)) begin + //`DBG_DETAIL_ID(("Cycle: %0d: Received credit on out_port %0d for vc %0d", cycles, o, cr_in.Valid)); + `DBG_DETAIL(("Cycle: %0d: Received credit on out_port %0d for vc %0d", cycles, o, cr_in.Valid)); + credits_set[o][cr_in.Valid] <= True; + end + endmethod + endinterface; + outPort_ifaces[o] = ifc; + end + + interface in_ports = inPort_ifaces; + interface out_ports = outPort_ifaces; + +endmodule + + + +/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// + + + +////////////////////////////////////////////////////////////// +// Old Arbitration Functions +////////////////////////////////////////////////////////////// + +//(* noinline *) +//function Maybe#(VC_t) pickVC( Vector#(NumVCs, Bool) eligVCs ); +// Maybe#(VC_t) sel_VC = Invalid; +// //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority +// for(Integer v=valueOf(NumVCs)-1; v >= 0; v=v-1) // I want the lowest to have highest priority +// begin +// if(eligVCs[v]) begin +// sel_VC = Valid(fromInteger(v)); +// end +// end +// return sel_VC; +//endfunction + +//(* noinline *) +//function Maybe#(InPort_t) pickIn( Vector#(NumInPorts, Bool) eligIns ); +// Maybe#(InPort_t) sel_In = Invalid; +// //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority +// for(Integer i=valueOf(NumInPorts)-1; i >= 0; i=i-1) // I want the lowest to have highest priority +// begin +// if(eligIns[i]) begin +// sel_In = Valid(fromInteger(i)); +// end +// end +// return sel_In; +//endfunction + +//(* noinline *) +//function Vector#(NumVCs, Vector#(NumInPorts, Bool )) maskOccupiedInputs(Vector#(NumVCs, Vector#(NumInPorts, Bool )) eligVI, Vector#(NumInPorts, Bool) freeInputs); +// for(Integer v=0; v + * + * Description: + * Parameterized Router module. Used as building block for building larger + * networks. Implements RouterSimple interface. + * + * ========================================================================= + */ + +`include "inc.v" + +import FIFO::*; +import FIFOF::*; +import Vector::*; +import RegFile::*; +import ConfigReg::*; +import Assert::*; + +import NetworkTypes::*; +import Aux::*; +import RF_16ports::*; +import RF_16portsLoad::*; +import RegFileMultiport::*; + +import FIFOLevel::*; +import MultiFIFOMem::*; +//import MultiFIFOMem_w_almost_full_empty::*; +import RegFIFO::*; + +// Arbiters and Allocators used for scheduling +import Arbiters::*; +import Allocators::*; + +typedef MultiFIFOMem#(Flit_t, NumVCs, FlitBufferDepth) InputVCQueues; +(* synthesize *) +module mkInputVCQueues(InputVCQueues); + InputVCQueues inputVCQueues_ifc; + // not needed because I double-check credits when pipelining. Enable if the credit-check is removed. + //inputVCQueues_ifc <- mkMultiFIFOMem(False /*storeHeadsTailsInLUTRAM*/, getPipeLineStages() /*full_margin*/); + if ( `PIPELINE_LINKS ) begin // Add 1 cycle margin to FIFOs for credit that might be in transit + inputVCQueues_ifc <- mkMultiFIFOMem(False /*storeHeadsTailsInLUTRAM*/, 1 /*full_margin*/); + end else begin + inputVCQueues_ifc <- mkMultiFIFOMem(False /*storeHeadsTailsInLUTRAM*/, 0 /*full_margin*/); + end + return inputVCQueues_ifc; +endmodule + +typedef FIFOCountIfc#(OutPort_t, FlitBufferDepth) OutPortFIFO; /* original code */ +//typedef FIFOF#(OutPort_t) OutPortFIFO; +(* synthesize *) +module mkOutPortFIFO(OutPortFIFO); + OutPortFIFO outPortFIFO_ifc <- mkRegFIFO(False); /* original code */ + //OutPortFIFO outPortFIFO_ifc <- mkGDepthParamFIFOF(False, False, FlitBufferDepth); + //OutPortFIFO outPortFIFO_ifc <- mkUGDepthParamFIFOF(fromInteger(valueOf(FlitBufferDepth))); + //OutPortFIFO outPortFIFO_ifc <- mkUGSizedFIFOF(valueOf(FlitBufferDepth)); + + //NumTypeParam#(FlitBufferDepth) fd = ?; + //OutPortFIFO outPortFIFO_ifc <- mkSizedLUTRAMFIFOF(fd); + return outPortFIFO_ifc; +endmodule + +//typedef RF_16portsLoad#(RouterID_t, OutPort_t) RouteTableOld; +typedef RegFileMultiport#(NumInPorts/*nr*/, 1/*nw*/, UserRecvPortID_t, OutPort_t) RouteTable; +module mkRouteTable#(String route_table_file) (RouteTable); + //RouteTable rt_ifc <- mkRF_16portsLoad(route_table_file); + RouteTable rt_ifc <- mkRegFileMultiportLoad(route_table_file); + return rt_ifc; +endmodule + +(* synthesize *) +module mkRouteTableSynth(RouteTable); + String route_table_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(0)), ".hex"); + //RouteTableOld rt_ifc <- mkRF_16portsLoad(route_table_file, False); + RouteTable rt_ifc <- mkRegFileMultiportLoad(route_table_file); + return rt_ifc; +endmodule + + + +//////////////////////////////////////////////// +// Router Module implementation +//////////////////////////////////////////////// +module mkRouterSimple#(Integer id)(RouterSimple); + String name = "RouterSimple"; + Bit#(8) errorCode = 0; + + Vector#(NumInPorts, InPortSimple) inPort_ifaces; // in port interfaces +`ifdef EN_DBG + RouterCoreSimple router_core <- mkRouterCoreSimple(id); +`else + RouterCoreSimple router_core <- mkRouterCoreSimple(); +`endif + // Route Table + String route_table_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(id)), ".hex"); + //String route_table_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(0)), ".hex"); + //RF_16portsLoad#(RouterID_t, OutPort_t) routeTable <- mkRF_16portsLoad(route_table_file, /*binary*/False); + //RouteTable routeTable <- mkRouteTable(route_table_file, /*binary*/False); + RouteTable routeTable <- mkRouteTable(route_table_file); + + // for debugging + `ifdef EN_DBG + Reg#(Cycle_t) cycles <- mkConfigReg(0); + rule update_cycles(True); + cycles <= cycles + 1; + endrule + `endif + + // Define input interfaces + for(Integer i=0; i < valueOf(NumInPorts); i=i+1) begin + let ifc = + interface InPortSimple + method Action putFlit(Maybe#(Flit_t) flit_in); + Maybe#(RoutedFlit_t) rt_flit = Invalid; + if(isValid(flit_in)) begin + //`DBG_ID(("Receiving Valid Flit on in_port %0d", i)); + let fl_in = flit_in.Valid; + let out_p = routeTable.r[i].sub(fl_in.dst); + //let fl_in = tagged Valid Flit_t{is_tail:flit_in.Valid.is_tail, dst:flit_in.Valid.dst, out_p:out_p, vc:flit_in.Valid.vc, data:flit_in.Valid.data}; + rt_flit = tagged Valid RoutedFlit_t{flit:fl_in, out_port:out_p}; + //rt_flit = tagged Valid RoutedFlit_t{ flit:Flit_t{is_tail:fl_in.is_tail, dst:fl_in.dst, out_p:out_p, vc:fl_in.vc, data:fl_in.data}, out_port:out_p}; + `DBG_ID_CYCLES(("Incoming flit on port %0d - dest:%0d, vc:%0d, data:%x", i, fl_in.dst, fl_in.vc, fl_in.data )); + if(i==0) begin + //`DBG(("Cycle:%0d - Injected flit into router %0d - dest:%0d, tail:%0d, vc:%0d, data:%x", cycles, id, fl_in.dst, fl_in.is_tail, fl_in.vc, fl_in.data )); + //`DBG_ID(("Cycle:%0d - Injected flit - dest:%0d, vc:%0d, data:%x", cycles, fl_in.dst, fl_in.vc, fl_in.data )); + end else begin + //`DBG(("Cycle:%0d - Router %0d received flit through in_port %0d - dest:%0d, tail:%0d, vc:%0d, data:%x", cycles, id, i, fl_in.dst, fl_in.is_tail, fl_in.vc, fl_in.data )); + //`DBG_ID(("Cycle:%0d - Received flit through in_port %0d - dest:%0d, vc:%0d, data:%x", cycles, i, fl_in.dst, fl_in.vc, fl_in.data )); + end + end + router_core.in_ports[i].putRoutedFlit(rt_flit); + endmethod + + // send credits upstream + method ActionValue#(Vector#(NumVCs, Bool)) getNonFullVCs; + let cr_out <- router_core.in_ports[i].getNonFullVCs(); + return cr_out; + endmethod + endinterface; + + inPort_ifaces[i] = ifc; + end + + // Implement RouterInfo interface + /*let rt_info_ifc = + interface RouterInfo + method RouterID_t getRouterID; + return fromInteger(id); + endmethod + endinterface;*/ + + interface in_ports = inPort_ifaces; + interface out_ports = router_core.out_ports; + //interface rt_info = rt_info_ifc; + +endmodule + + +module mkRouterSynthSimple(RouterSimple); + let rt_synth <- mkRouterSimple(4); + return rt_synth; +endmodule + + +// ////////////////////////////////////////////////////////////////////////////////////// +// // noinline functions to speed up Bluespec compilation +// (* noinline *) +// function Tuple3#( +// Vector#(NumOutPorts, Bool ), /* eligIO_forIn */ +// Maybe#(VC_t), /* activeVC_perIn_forIn */ +// Vector#(NumOutPorts, VC_t) /* activeVC_perOut */ +// ) build_eligIO_and_other_alloc_structs_perIn ( +// Vector#(NumVCs, Bool) not_empty, +// Vector#(NumVCs, OutPort_t) outPortFIFOs_first_forIn, +// Vector#(NumOutPorts, Vector#(NumVCs, Bit#(TLog#(TAdd#(FlitBufferDepth,1))))) credits, +// Vector#(NumOutPorts, VC_t) activeVC_perOut, +// // only used if Virtual Links are enabled +// Vector#(NumOutPorts, Vector#(NumVCs, Bool )) lockedVL, +// Vector#(NumOutPorts, Vector#(NumVCs, InPort_t)) inPortVL, +// InPort_t cur_in +// ); +// +// Vector#(NumOutPorts, Bool ) eligIO_forIn = unpack(0); +// Maybe#(VC_t) activeVC_perIn_forIn = unpack(0); +// // Build eligIO and mark selected-active VC per Input (lowest VC has priority) +// for(Integer v=valueOf(NumVCs)-1; v>=0; v=v-1) begin // lowest VC has highest priority +// if(not_empty[v]) begin +// let out_port = outPortFIFOs_first_forIn[v]; +// +// if(`USE_VIRTUAL_LINKS) begin +// if(credits[out_port][v] > 0) begin +// let is_locked = lockedVL[out_port][v]; +// if( !is_locked || (is_locked && inPortVL[out_port][v] == cur_in ) ) begin +// activeVC_perIn_forIn = tagged Valid fromInteger(v); +// activeVC_perOut[out_port] = fromInteger(v); +// eligIO_forIn[out_port] = True; +// end +// end +// end else begin +// if(credits[out_port][v] > 0) begin +// activeVC_perIn_forIn = tagged Valid fromInteger(v); +// activeVC_perOut[out_port] = fromInteger(v); +// eligIO_forIn[out_port] = True; +// end +// end +// +// +// // if(credits[out_port][v] > 0) begin +// // activeVC_perIn_forIn = tagged Valid fromInteger(v); +// // activeVC_perOut[out_port] = fromInteger(v); +// // eligIO_forIn[out_port] = True; +// // end +// end +// end +// +// return tuple3(eligIO_forIn, activeVC_perIn_forIn, activeVC_perOut); +// endfunction +// +// (* noinline *) +// function Tuple3#( +// Vector#(NumInPorts, Vector#(NumOutPorts, Bool ) ), /* eligIO */ +// Vector#(NumInPorts, Maybe#(VC_t)), /* activeVC_perIn */ +// Vector#(NumOutPorts, VC_t) /* activeVC_perOut */ +// ) build_eligIO_and_other_alloc_structs ( +// Vector#(NumInPorts, Vector#(NumVCs, Bool) ) flitBuffers_notEmpty, +// Vector#(NumInPorts, Vector#(NumVCs, OutPort_t) ) outPortFIFOs_first, +// Vector#(NumOutPorts, Vector#(NumVCs, Bit#(TLog#(TAdd#(FlitBufferDepth,1))))) credits, +// // only used if Virtual Links are enabled +// Vector#(NumOutPorts, Vector#(NumVCs, Bool )) lockedVL, +// Vector#(NumOutPorts, Vector#(NumVCs, InPort_t)) inPortVL +// ); +// +// Vector#(NumInPorts, Vector#(NumOutPorts, Bool ) ) eligIO = unpack(0); +// Vector#(NumInPorts, Maybe#(VC_t)) activeVC_perIn = replicate(Invalid); // arbitration populates this +// Vector#(NumOutPorts, VC_t) activeVC_perOut = replicate(0); // This is only valid if activeIn_perOut is Valid - not Maybe type to avoid spending an extra bit +// +// // Build eligIO and mark selected-active VC per Input (lowest VC has priority) +// for(Integer i=0; i=0; v=v-1) begin // lowest VC has highest priority +// // if(not_empty[v]) begin +// // let out_port = outPortFIFOs_first[i][v]; +// // if(credits[out_port][v] > 0) begin +// // activeVC_perIn[i] = tagged Valid fromInteger(v); +// // activeVC_perOut[out_port] = fromInteger(v); +// // eligIO[i][out_port] = True; +// // end +// // end +// // end +// +// end +// +// return tuple3(eligIO, activeVC_perIn, activeVC_perOut); +// endfunction + + +//////////////////////////////////////////////// +// Router Module implementation +//////////////////////////////////////////////// +//module mkRouter#(RouterID_t id) (Router); +`ifdef EN_DBG +module mkRouterCoreSimple#(Integer id)(RouterCoreSimple); +`else +(* synthesize *) +module mkRouterCoreSimple(RouterCoreSimple); +`endif + + String name = "RouterCoreSimple"; + Bit#(8) errorCode = 0; + + // Vector of input and output port interfaces + Vector#(NumInPorts, RouterCoreInPortSimple) inPort_ifaces; // in port interfaces + Vector#(NumOutPorts, OutPortSimple) outPort_ifaces; // out port interfaces + + // Router Allocator + RouterAllocator routerAlloc <- mkSepRouterAllocator(`PIPELINE_ALLOCATOR /*pipeline*/); + + // Router State + Vector#(NumInPorts, InputVCQueues) flitBuffers <- replicateM(mkInputVCQueues()); + //Vector#(NumInPorts, RF_16ports#(VC_t, FlitBuffer_t) ) flitBuffers <- replicateM(mkRF_16ports()); + Vector#(NumInPorts, Vector#(NumVCs, OutPortFIFO)) outPortFIFOs; + //Vector#(NumOutPorts, Vector#(NumVCs, Reg#(Bool))) simple_credits; + Vector#(NumOutPorts, Vector#(NumVCs, Wire#(Bool))) simple_credits; + + Vector#(NumInPorts, Wire#(Maybe#(Flit_t))) hasFlitsToSend_perIn <- replicateM(mkDWire(Invalid)); + Vector#(NumInPorts, Wire#(Maybe#(Flit_t))) flitsToSend_perIn <- replicateM(mkDWire(Invalid)); + // Used for multi-flit packets that use virtual links + //if(`USE_VIRTUAL_LINKS) begin + Vector#(NumOutPorts, Vector#(NumVCs, Reg#(Bool) )) lockedVL; // locked virtual link + Vector#(NumOutPorts, Vector#(NumVCs, Reg#(InPort_t))) inPortVL; // holds current input for locked virtual channels + //end + + + // for debugging + `ifdef EN_DBG + Reg#(Cycle_t) cycles <- mkConfigReg(0); + rule update_cycles(True); + cycles <= cycles + 1; + endrule + `endif + + // -- Initialization -- + for(Integer o=0; o=0; v=v-1) begin // lowest VC has highest priority + outPortFIFOs_first[i][v] = outPortFIFOs[i][v].first(); + end + end + + Vector#(NumOutPorts, Vector#(NumVCs, Bool)) credit_values; + // Virtual Link State + Vector#(NumOutPorts, Vector#(NumVCs, Bool )) lockedVL_values; // locked virtual link + Vector#(NumOutPorts, Vector#(NumVCs, InPort_t)) inPortVL_values; // holds current input for locked virtual channels + for(Integer o=0; o=0; v=v-1) begin // lowest VC has highest priority + if(not_empty[v]) begin + //let out_port = outPortFIFOs[i][v].first(); + let out_port = outPortFIFOs_first[i][v]; + + if(`USE_VIRTUAL_LINKS) begin + if(simple_credits[out_port][v]) begin + let is_locked = lockedVL[out_port][v]; + if( !is_locked || (is_locked && inPortVL[out_port][v] == fromInteger(i) ) ) begin + activeVC_perIn_s0[i] = tagged Valid fromInteger(v); + //activeVC_perOut[out_port] = tagged Valid fromInteger(v); + //eligIO[i] = unpack(0); + eligIO[i] = replicate(False); + eligIO[i][out_port] = True; + end + end + end else begin + if(simple_credits[out_port][v]) begin + activeVC_perIn_s0[i] = tagged Valid fromInteger(v); + //activeVC_perOut[out_port] = tagged Valid fromInteger(v); + eligIO[i] = replicate(False); + eligIO[i][out_port] = True; + end + end + + end + end + end + // -- End Option 1 -- + + // -- Option 2: more scalable, but harder to read -- +// let build_eligIO_result = build_eligIO_and_other_alloc_structs(flitBuffers_notEmpty, outPortFIFOs_first, credit_values, lockedVL_values, inPortVL_values); +// eligIO = tpl_1(build_eligIO_result); +// activeVC_perIn = tpl_2(build_eligIO_result); +// activeVC_perOut = tpl_3(build_eligIO_result); + // -- End Option 2 -- + + // Perform allocation + Vector#(NumInPorts, Bool) activeInPorts = unpack(0); + //Vector#(NumInPorts, Vector#(NumOutPorts, Bool ) ) selectedIO_s0 = routerAlloc.allocate(eligIO); + Vector#(NumInPorts, Vector#(NumOutPorts, Wire#(Bool) ) ) selectedIO_s0; //= routerAlloc.allocate(eligIO); + Vector#(NumInPorts, Vector#(NumOutPorts, Reg#(Bool) ) ) selectedIO_reg; + Vector#(NumInPorts, Vector#(NumOutPorts, Bool ) ) selectedIO; // this is popuated depending on allocator pipeline options + + for(Integer i=0; i0) begin +// eligVIO[v][i][out_port] = True; +// end +// end +// end +// end +// +// +// +// // Arbitration - packaged main arbitration logic for each output in "noinline" function --> this reduces compilation times by 2 ORDERS OF MAGNITUDE! +// Tuple3#( Vector#(NumInPorts, Maybe#(VC_t)), /* activeVC_perIn */ +// Vector#(NumOutPorts, Maybe#(InPort_t)), /* activeIn_perOut */ +// Vector#(NumOutPorts, VC_t) /* activeVC_perOut */ +// ) arb_result; +// +// arb_result = arbitrateAll(eligVIO); +// activeVC_perIn = tpl_1(arb_result); +// activeIn_perOut = tpl_2(arb_result); +// activeVC_perOut = tpl_3(arb_result); +// +// Vector#(NumInPorts, Bool) activeInPorts = unpack(0); +// for(Integer i=0; i set +// if ( hasFlitsVIO_set[v][i][o] ) begin // something came in on an in_port --> set +// hasFlitsVIO[v][i][o] <= True; +// `DBG(("Marking incoming flit for out:%0d VC:%0d from in:%0d", o, v, i)); +// //end else if ( hasFlitsVIO_clear[v][i][o] && !hasFlitsVIO_set[v][i][o]) begin // something departed --> clear +// end else if ( hasFlitsVIO_clear[v][i][o] ) begin // something departed --> clear +// `DBG(("Clearing flit for out:%0d VC:%0d from in:%0d", o, v, i)); +// hasFlitsVIO[v][i][o] <= False; +// end +// end +// end +// end +// endrule + + // Rule to update credits. Credits get replenished from out_ports and are spent when sending flits. +/* (* fire_when_enabled *) + rule update_credits (True); // turn off credits for debugging + for(Integer o=0; o fromInteger(valueof(FlitBufferDepth))) begin + `DBG_ID(("Credit overflow at out_port %0d VC %0d", o, v)); + end + end else if (!credits_set[o][v] && credits_clear[o][v]) begin // I only spent a credit + //credits[o][v] <= False; + credits[o][v] <= credits[o][v] - 1; + if(credits[o][v] == 0) begin + `DBG_ID(("Credit underflow at out_port %0d VC %0d", o, v)); + end + end + end + end + //`DBG_DETAIL_ID(("credits:%b", readVReg(concat(credits)) )); // flatten the array to print + endrule +*/ +/* + rule tmp (True); + for(Integer o=0; o < valueOf(NumOutPorts); o=o+1) begin + for(Integer v=0; v= 0; v=v-1) // I want the lowest to have highest priority +// begin +// if(eligVCs[v]) begin +// sel_VC = Valid(fromInteger(v)); +// end +// end +// return sel_VC; +//endfunction + +//(* noinline *) +//function Maybe#(InPort_t) pickIn( Vector#(NumInPorts, Bool) eligIns ); +// Maybe#(InPort_t) sel_In = Invalid; +// //for(Integer i=0; i < valueOf(n); i=i+1) // I want the highest to have highest priority +// for(Integer i=valueOf(NumInPorts)-1; i >= 0; i=i-1) // I want the lowest to have highest priority +// begin +// if(eligIns[i]) begin +// sel_In = Valid(fromInteger(i)); +// end +// end +// return sel_In; +//endfunction + +//(* noinline *) +//function Vector#(NumVCs, Vector#(NumInPorts, Bool )) maskOccupiedInputs(Vector#(NumVCs, Vector#(NumInPorts, Bool )) eligVI, Vector#(NumInPorts, Bool) freeInputs); +// for(Integer v=0; v + * + * Description: + * Router Testbench module. Also includes synthesizable template. + * + * ========================================================================= + */ + +`include "inc.v" +import Router::*; +import NetworkTypes::*; +import StmtFSM::*; // for testbench + +////////////////////////////////////////////////////////// +// VCRouter_multi_flit_bufs Testbench +(* synthesize *) +module mkRouterTb(Empty); + String name = "mkRouterTb"; + Reg#(Bit#(64)) cycles <- mkReg(0); + Reg#(Bit#(64)) total_cycles <- mkReg(20); + Router r <- mkRouter(4); + Integer test_cycles = 20; + + // Functions for sending flits/credits + function Action sendFlit(InPort inp, Maybe#(Flit_t) fl); + action inp.putFlit(fl); endaction + endfunction + + function Action sendCredits(OutPort outp, Credit_t cr); + action outp.putCredits(cr); endaction + endfunction + + function Action printFlit(Flit_t fl); + //$display("-->Flit {dst:%0d, vc:%0d, is_tail:%0d}", fl.dst, fl.vc, fl.is_tail); + $display("-->Flit {dst:%0d, vc:%0d}", fl.dst, fl.vc); + endfunction + + rule countCycle(True); + cycles<=cycles+1; + if(cycles >= total_cycles) $finish(0); + //$display("------------------------------------------------<%0d>",cycles); + endrule + + // Stmts for scanning flits and credits at out_ports/in_ports + Stmt scan_outports = seq + action + `BLUE; + $display("--------------------------- Start of cycle -------------------------------------<%0d>",cycles); + `WHITE; + for(Integer o=0; o < valueOf(NumOutPorts); o=o+1) begin + let fl <- r.out_ports[o].getFlit(); + if(isValid(fl)) begin + `DBG(("[%0d] Read Flit (data:%x) on out_port %0d", cycles, fl.Valid.data, o)); + //printFlit(fl.Valid); + end else begin + //`DBG(("[%0d] No Flit on out_port %d", cycles, o)); + end + end + endaction + endseq; + + Stmt scan_credits = seq + action + for(Integer i=0; i < valueOf(NumInPorts); i=i+1) begin + let cr <- r.in_ports[i].getCredits(); + if(isValid(cr)) begin + `DBG(("[%0d] Upstream credits from input %0d for VC:%0d", cycles, i, cr.Valid)); + end + end + endaction + endseq; + + Stmt scan_outputs = par + scan_outports; + scan_credits; + endpar; + + //////////////////////////////////////// + // Test sequence + + Stmt test_seq = seq + + par + //`DBG(("Sending Flits -------------------------------------<%0d>",cycles)); + sendFlit(r.in_ports[2], tagged Valid Flit_t{is_tail:True, data:32'hbbbbbbb0, dst:3, vc:1} ); + sendFlit(r.in_ports[3], tagged Valid Flit_t{is_tail:False, data:32'haaaaaaa0, dst:0, vc:1} ); + //sendFlit(mcr.in_ports[3], tagged Valid Flit_t{is_tail:False, dst:2, vc:0} ); + scan_outputs; + endpar + par + sendFlit(r.in_ports[0], tagged Valid Flit_t{is_tail:True, data:32'hccccccc0, dst:2, vc:1} ); + //sendFlit(r.in_ports[1], tagged Valid Flit_t{is_tail:True, data:0, dst:1, vc:1} ); + sendCredits(r.out_ports[3], tagged Valid fromInteger(1)); + //sendFlit(mcr.in_ports[3], tagged Valid Flit_t{is_tail:False, dst:2, vc:0} ); + scan_outputs; + endpar + par + sendFlit(r.in_ports[3], tagged Valid Flit_t{is_tail:False, data:32'haaaaaaa1, dst:0, vc:1} ); + sendFlit(r.in_ports[2], tagged Valid Flit_t{is_tail:True, data:32'hddddddd0, dst:3, vc:0} ); + scan_outputs; + sendCredits(r.out_ports[1], tagged Valid fromInteger(1)); + endpar + + par + sendFlit(r.in_ports[3], tagged Valid Flit_t{is_tail:True, data:32'haaaaaaa2, dst:0, vc:1} ); + scan_outputs; + endpar + + scan_outputs; + scan_outputs; + scan_outputs; + scan_outputs; + scan_outputs; + scan_outputs; + + +// noAction; + noAction; + //while(True) noAction; + endseq; + + +// Stmt test_seq = seq +// +// par +// `DBG(("Sending Flits -------------------------------------<%0d>",cycles)); +// sendFlit(r.in_ports[1], tagged Valid Flit_t{is_tail:True, data:0, dst:1, vc:1} ); +// //sendFlit(mcr.in_ports[3], tagged Valid Flit_t{is_tail:False, dst:2, vc:0} ); +// scan_outputs; +// endpar +// par +// `DBG(("Sending Flits -------------------------------------<%0d>",cycles)); +// sendFlit(r.in_ports[1], tagged Valid Flit_t{is_tail:True, data:0, dst:1, vc:1} ); +// sendCredits(r.out_ports[1], tagged Valid fromInteger(1)); +// //sendFlit(mcr.in_ports[3], tagged Valid Flit_t{is_tail:False, dst:2, vc:0} ); +// scan_outputs; +// endpar +// par +// sendCredits(r.out_ports[1], tagged Valid fromInteger(1)); +// endpar +// +// scan_outputs; +// $display("test %d", cycles); +// scan_outputs; +// $display("test %d", cycles); +// scan_outputs; +// $display("test %d", cycles); +// scan_outputs; +// $display("test %d", cycles); +// scan_outputs; +// +// noAction; +// noAction; +// noAction; +// noAction; +// noAction; +// noAction; +// noAction; +// noAction; +// noAction; +// noAction; +// noAction; +// //while(True) noAction; +// endseq; + + mkAutoFSM(test_seq); + +endmodule + +//////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////// +// Router for synthesis +// VCRouter_multi_flit_bufs for Synthesis test +(* synthesize *) +//module mkVCRouter_multi_flit_bufs_Synth(Router); +module mkRouterSynth(Router); + Router r_ifc <- mkRouter(0); + return r_ifc; +endmodule + + diff --git a/Strace.bsv b/Strace.bsv new file mode 100644 index 0000000..afeb401 --- /dev/null +++ b/Strace.bsv @@ -0,0 +1,35 @@ +function Action strace(String component, Bit#(32) inst, String evt); + action + $display("strace time=%0d component=%s inst=%0d evt=%s val=1", $time, component, inst, evt); + endaction +endfunction + +function Action strace_new_region(Bit#(32) id); + action + $display("strace time=%0d inst=%0d evt=new_region", $time, id); + endaction +endfunction + +function Action strace_add(String component, Bit#(32) inst, String evt, Bit#(32) val); + action + $display("strace time=%0d component=%s inst=%0d evt=%s val=%0d", $time, component, inst, evt, val); + endaction +endfunction + +function Action strace_begin(String component, Bit#(32) inst, String evt, Bit#(32) tag); + action + $display("strace time=%0d component=%s inst=%0d evt=%s tag=%0d begin=1", $time, component, inst, evt, tag); + endaction +endfunction + +function Action strace_end(String component, Bit#(32) inst, String evt, Bit#(32) tag); + action + $display("strace time=%0d component=%s inst=%0d evt=%s tag=%0d end=1", $time, component, inst, evt, tag); + endaction +endfunction + +function Action strace_cfg(String cfg, Bit#(32) value); + action + $display("strace cfg=%s val=%0d", cfg, value); + endaction +endfunction diff --git a/TrafficSource.bsv b/TrafficSource.bsv new file mode 100644 index 0000000..78172e5 --- /dev/null +++ b/TrafficSource.bsv @@ -0,0 +1,312 @@ +/* ========================================================================= + * + * Filename: TrafficSource.bsv + * Date created: 03-04-2012 + * Last modified: 03-05-2012 + * Authors: Michael Papamichael + * + * Description: + * Traffic Source used to inject packets into the network. + * + * ========================================================================= + */ + +import Assert::*; +import ConfigReg::*; +import FIFO::*; +import FIFOF::*; +import Vector::*; +import RegFile::*; +import LFSR::*; +import GetPut::*; +import FShow::*; + +import NetworkTypes::*; + +`include "inc.v" + +// Types +typedef Bit#(TLog#(256)) Load_t; +typedef Bit#(TLog#(512)) PktSize_t; + +//////////////////////////////// +// TrafficSource Interface +//////////////////////////////// +interface TrafficSource; + interface OutPort out_port; // this is connected with the injection port of a router + method Action setLoad(Load_t new_load); + method Action setMaxPktSize(PktSize_t new_max_pkt_size); + method Action set_enabled(Bool new_enabled); + method Action set_pkts_to_send(Bit#(64) new_pkts_to_send); + method Bool is_finished(); // return True if finished + interface Put#(Bool) setFixedPktSize; + //method Bool is_initDone(); + //method Action setTrafficEntryAndInit(TrafficEntryID_t tr_id, TrafficEntry_t tr, Bool init); + //method Action setPacketsToSend(HalfNumPackets_t num_pcks_lo_hi, Bool is_lo); +endinterface + + +//////////////////////////////////////////////// +// Traffic source implementation +//////////////////////////////////////////////// +(* synthesize *) +module mkTrafficSource#(UserRecvPortID_t id) (TrafficSource); + String name = "TrafficSource"; + Bit#(8) errorCode = 0; + + // State and wires + Reg#(Bool) enabled <- mkConfigReg(False); // only send packets if TrafficSource is enabled + Reg#(Bool) finished <- mkConfigReg(False); // only send packets if TrafficSource is enabled + Reg#(Bit#(64)) pkts_sent <- mkConfigReg(0); + + + Reg#(Load_t) load <- mkConfigReg(0); + Reg#(PktSize_t) max_pkt_size <- mkConfigReg(1); + Reg#(Bit#(64)) pkts_to_send <- mkConfigReg(0); + Reg#(Bool) fix_pkt_size <- mkConfigReg(True); // default behavior is to send fixed size packets of size max_pkt_size + + Reg#(PktSize_t) flits_left_to_send <- mkConfigReg(0); + Reg#(Flit_t) flit_of_curr_pkt <- mkConfigRegU(); + + + // LFSRs for load, packet size, destination and VC + LFSR#(Bit#(8)) load_lfsr <- mkLFSR_8; + LFSR#(Bit#(16)) pkt_size_lfsr <- mkLFSR_16; + LFSR#(Bit#(8)) dest_lfsr <- mkLFSR_8; + LFSR#(Bit#(8)) vc_lfsr <- mkLFSR_8; + + (* no_implicit_conditions *) + rule check_if_finished (True); + if(pkts_sent >= pkts_to_send) begin + finished <= True; + enabled <= False; + `DBG_ID(("Finished after sending %0d packets. Disabling traffic source.", pkts_sent)); + end + endrule + + (* no_implicit_conditions *) + rule advance_lfsrs (True);// advance LFSR + load_lfsr.next(); + pkt_size_lfsr.next(); + dest_lfsr.next(); + vc_lfsr.next(); + endrule + +// rule inject_traffic (enabled); +// if( truncate(load_lfsr.value) <= load ) begin // inject flit +// //if(truncate(dest_lfsr.value) > +// //UserRevcPort_t dest = truncate(dest_lfsr.value); +// UserRevcPort_t dest = dest_lfsr.value / NumUserRecvPorts; +// +// end +// load_lfsr.next(); // advance LFSR +// endrule + + Vector#(NumVCs, Reg#(Bit#(TLog#(TAdd#(FlitBufferDepth,1))))) credits <- replicateM(mkConfigReg(fromInteger(valueOf(FlitBufferDepth)))); + Vector#(NumVCs, Wire#(Bool)) credits_set <- replicateM(mkDWire(False)); + Vector#(NumVCs, Wire#(Bool)) credits_clear <- replicateM(mkDWire(False)); + //Wire#(Bool) reset_stats <- mkDWire(False); + + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // Rule to update credits. Credits get replenished from out_ports and are spent when sending flits. + (* no_implicit_conditions *) + rule update_credits (True); + for(Integer v=0; v fromInteger(valueof(FlitBufferDepth))) begin + `DBG_ID(("Credit overflow at VC %0d", v)); + end + end else if (!credits_set[v] && credits_clear[v]) begin // I only spent a credit + credits[v] <= credits[v]-1; + if(credits[v] == 0) begin + `DBG_ID(("Credit underflow at VC %0d", v)); + end + end + end + endrule + + // Rule for debugging + rule dbg (`EN_DBG_RULE); + if(errorCode != 0) begin // error + $display("Error (errorCode:%d)", errorCode); + $stop; + end + endrule + + + //////////////////////////////////////////////////// + // Interface Implementation + let ifc = + interface OutPort + method ActionValue#(Maybe#(Flit_t)) getFlit(); + let flit_to_send = Invalid; + // Only send flits if enabled + `DBG_ID(("load_lfsr value: %0d", load_lfsr.value)); + if( enabled ) begin + if( flits_left_to_send > 0 ) begin // in the middle of sending multi-flit packet + let fl = flit_of_curr_pkt; + if(flits_left_to_send == 1) begin // last flit + fl.is_tail = True; // set is_tail + pkts_sent <= pkts_sent + 1; + end + flit_to_send = tagged Valid fl; + flits_left_to_send <= flits_left_to_send - 1; + end else if( truncate(load_lfsr.value) <= load ) begin // inject flit + //if(truncate(dest_lfsr.value) > + //UserRevcPort_t dest = truncate(dest_lfsr.value); + // Note: very slight bias towards 0. To fix replace with "(dest_lfsr.value + fromInteger(valueOf(NumUserRecvPorts)) % fromInteger(valueOf(NumUserRecvPorts))) + UserRecvPortID_t dest = truncate(dest_lfsr.value % fromInteger(valueOf(NumUserRecvPorts))); + VC_t vc = truncate(vc_lfsr.value); + + // Define packet size + PktSize_t remaining_flits = max_pkt_size-1; // assumes fixed packet size, all packets have size max_pkt_size + if (!fix_pkt_size) begin // all packets have size max_pkt_size + remaining_flits = truncate(pkt_size_lfsr.value % extend(max_pkt_size)); + end + + // Set tail bit + let is_tail = False; // set is tail to False for multi-flit packets + if(remaining_flits == 0) begin // single-flit packet + is_tail = True; // set to true for single flit packets + pkts_sent <= pkts_sent + 1; + end + + // Prepare flit to send + flit_to_send = tagged Valid Flit_t{is_tail: is_tail, dst: dest, vc:vc, data:unpack(0)}; + flit_of_curr_pkt <= flit_to_send.Valid; // remember to generate rest of flits + flits_left_to_send <= remaining_flits; + + // Clear credit for this flit + credits_clear[vc] <= True; + + `DBG_ID(("Sending packet to %0d on VC %0d", dest, vc)); + end + end + return flit_to_send; + endmethod + + method Action putCredits(Credit_t cr_in); + if(isValid(cr_in)) begin + credits_set[cr_in.Valid] <= True; + end + endmethod + endinterface; + + interface out_port = ifc; + + interface setFixedPktSize = toPut(asReg(fix_pkt_size)); + + method Action setLoad(Load_t new_load); + `DBG_ID(("Setting load to %0d", new_load)); + load <= new_load; + endmethod + + method Action setMaxPktSize(PktSize_t new_max_pkt_size); + max_pkt_size <= new_max_pkt_size; + endmethod + + method Action set_enabled(new_enabled); + enabled <= new_enabled; + endmethod + + + method Action set_pkts_to_send(Bit#(64) new_pkts_to_send); + `DBG_ID(("Setting pkts_to_send to %0d", new_pkts_to_send)); + pkts_to_send <= new_pkts_to_send; + endmethod + + method Bool is_finished(); // return True if finished + return finished; + endmethod + +endmodule + + +//////////////////////////////////////////// +// Testbench - comment this line to disable +`define TRAFFIC_SOURCE_TB +`ifdef TRAFFIC_SOURCE_TB + +import StmtFSM::*; // for testbench + +//(* synthesize, scan_insert *) +(* synthesize *) +module mkTrafficSourceTb(Empty); + String name = "mkTrafficSourceTb"; + Reg#(Bit#(64)) cycles <- mkReg(0); + Reg#(Bit#(64)) total_cycles <- mkReg(20); + TrafficSource traffic_src <- mkTrafficSource(fromInteger(1)); + Integer test_cycles = 20; + + rule countCycles(True); + cycles<=cycles+1; + //if(cycles >= total_cycles) $finish(0); + $display("------------------------------------------------<%0d>",cycles); + endrule + + function Action printFlit(Flit_t fl); + //$display("-->Flit {dst:%0d, vc:%0d, is_tail:%0d}", fl.dst, fl.vc, fl.is_tail); + $display(" Flit {dst:%0d, vc:%0d is_tail:%0d}", fl.dst, fl.vc, fl.is_tail); + endfunction + + + Stmt scan_outport= seq + action + //`BLUE; + //$display("--------------------------- Start of cycle -------------------------------------<%0d>",cycles); + //`WHITE; + let fl <- traffic_src.out_port.getFlit(); + if(isValid(fl)) begin + //`DBG_CYCLES(("New Flit - dst:%0d\t vc:%0d\t is_tail:%0d\t data:%x", fl.Valid.dst, fl.Valid.vc, fl.Valid.is_tail, fl.Valid.data)); + `DBG_CYCLES(("New ", fshow(fl.Valid) )); + //printFlit(fl.Valid); + end else begin + //`DBG(("[%0d] No Flit on out_port %d", cycles, o)); + end + endaction + endseq; + + + Stmt test_seq = seq + noAction; + noAction; + traffic_src.set_pkts_to_send(fromInteger(16)); + traffic_src.setMaxPktSize(fromInteger(3)); + traffic_src.setFixedPktSize.put(False); + par + traffic_src.setLoad(fromInteger(128)); + traffic_src.set_enabled(True); + endpar + //let fl = traffic_src.out_port.getFlit(); + repeat(100) + scan_outport; + + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + //scan_outport; + noAction; + $finish(); + + endseq; + + mkAutoFSM(test_seq); + +endmodule + +`endif diff --git a/VOQRouterSimple.bsv b/VOQRouterSimple.bsv new file mode 100644 index 0000000..3d65506 --- /dev/null +++ b/VOQRouterSimple.bsv @@ -0,0 +1,518 @@ +/* ========================================================================= + * + * Filename: VOQRouterSimple.bsv + * Date created: 09-18-2012 + * Last modified: 09-18-2012 + * Authors: Michael Papamichael + * + * Description: + * Parameterized VOQ Router module. Used as building block for building larger + * networks. Implements RouterSimple interface + * + * ========================================================================= + */ + +`include "inc.v" + +import FIFO::*; +//import FIFOF::*; +import Vector::*; +import RegFile::*; +import ConfigReg::*; +import Assert::*; + +import NetworkTypes::*; +import Aux::*; +import RF_16ports::*; +import RF_16portsLoad::*; +import RegFileMultiport::*; + +import FIFOLevel::*; +import MultiFIFOMem::*; +import RegFIFO::*; + +// Arbiters and Allocators used for scheduling +import Arbiters::*; +import Allocators::*; + +// /////////////////////////////////////////////////////////////////////////// +// // Router Interface +// interface VOQRouterSimple; +// // Port Interfaces +// interface Vector#(NumInPorts, VOQInPortSimple) in_ports; +// interface Vector#(NumOutPorts, VOQOutPortSimple) out_ports; +// // Used to query router info (e.g. ID) +// //interface RouterInfo rt_info; +// //method Action setRoutingEntry(RouterID_t dst, OutPort_t out_p); +// endinterface +// +// //////////////////////////////////////////////// +// // Simpler InPort and OutPort interfaces +// // - Routers only exchange notFull signals, instead of credits +// // Implemented by routers and traffic sources +// //////////////////////////////////////////////// +// interface VOQInPortSimple; +// (* always_ready *) method Action putFlit(Maybe#(Flit_t) flit_in); +// (* always_ready *) method ActionValue#(Bool) getNonFull; +// endinterface +// +// interface VOQOutPortSimple; +// (* always_ready *) method ActionValue#(Maybe#(Flit_t)) getFlit(); +// (* always_ready *) method Action putNonFull(Bool putNonFull); +// endinterface +// +// +// /////////////////////////////////////////////////////////////////////////// +// // VOQRouterCoreSimple Interface +// interface VOQRouterCoreSimple; +// interface Vector#(NumInPorts, VOQRouterCoreInPortSimple) in_ports; // Same as router in_ports, but also carry routing info +// interface Vector#(NumOutPorts, VOQOutPortSimple) out_ports; +// //interface Vector#(NumInPorts, Client#(RouterID_t, OutPort_t)) rt; +// endinterface +// +// // InPort interface for RouterCore +// interface VOQRouterCoreInPortSimple; +// (* always_ready *) method Action putRoutedFlit(Maybe#(RoutedFlit_t) flit_in); +// (* always_ready *) method ActionValue#(Bool) getNonFull; +// endinterface + + +//typedef RF_16portsLoad#(RouterID_t, OutPort_t) RouteTableOld; +typedef RegFileMultiport#(NumInPorts/*nr*/, 1/*nw*/, UserRecvPortID_t, OutPort_t) RouteTable; +module mkRouteTable#(String route_table_file) (RouteTable); + //RouteTable rt_ifc <- mkRF_16portsLoad(route_table_file); + RouteTable rt_ifc <- mkRegFileMultiportLoad(route_table_file); + return rt_ifc; +endmodule + +(* synthesize *) +module mkRouteTableSynth(RouteTable); + String route_table_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(0)), ".hex"); + //RouteTableOld rt_ifc <- mkRF_16portsLoad(route_table_file, False); + RouteTable rt_ifc <- mkRegFileMultiportLoad(route_table_file); + return rt_ifc; +endmodule + +typedef MultiFIFOMem#(Flit_t, NumOutPorts, FlitBufferDepth) InputVOQueues; +(* synthesize *) +module mkInputVOQueues(InputVOQueues); + InputVOQueues inputVOQueues_ifc; + // not needed because I double-check credits when pipelining. Enable if the credit-check is removed. + //inputVOQueues_ifc <- mkMultiFIFOMem(False /*storeHeadsTailsInLUTRAM*/, getPipeLineStages() /*full_margin*/); + if ( `PIPELINE_LINKS ) begin // Add 1 cycle margin to FIFOs for credit that might be in transit + inputVOQueues_ifc <- mkMultiFIFOMem(False /*storeHeadsTailsInLUTRAM*/, 1 /*full_margin*/); + end else begin + inputVOQueues_ifc <- mkMultiFIFOMem(False /*storeHeadsTailsInLUTRAM*/, 0 /*full_margin*/); + end + return inputVOQueues_ifc; +endmodule + + +//////////////////////////////////////////////// +// VOQ Router Module implementation +//////////////////////////////////////////////// +//module mkRouter#(RouterID_t id) (Router); +`ifdef EN_DBG +module mkVOQRouterCoreSimple#(Integer id)(RouterCoreSimple); +`else +(* synthesize *) +module mkVOQRouterCoreSimple(RouterCoreSimple); +`endif + + String name = "VOQRouterCoreSimple"; + Bit#(8) errorCode = 0; + + // Vector of input and output port interfaces + Vector#(NumInPorts, RouterCoreInPortSimple) inPort_ifaces; // in port interfaces + Vector#(NumOutPorts, OutPortSimple) outPort_ifaces; // out port interfaces + + // Router Allocator + RouterAllocator routerAlloc <- mkSepRouterAllocator(`PIPELINE_ALLOCATOR /*pipeline*/); + + // Router State + Vector#(NumInPorts, InputVOQueues) flitVOQBuffers <- replicateM(mkInputVOQueues()); + //Vector#(NumOutPorts, Vector#(NumOutPorts, Reg#(Bit#(TLog#(TAdd#(FlitBufferDepth,1)))))) credits; + //Vector#(NumOutPorts, Reg#(Bool)) simple_credits; + Vector#(NumOutPorts, Wire#(Bool)) simple_credits; + + Vector#(NumInPorts, Wire#(Maybe#(Flit_t))) hasFlitsToSend_perIn <- replicateM(mkDWire(Invalid)); + Vector#(NumInPorts, Wire#(Maybe#(Flit_t))) flitsToSend_perIn <- replicateM(mkDWire(Invalid)); + // Used for multi-flit packets that use virtual links + + + Vector#(NumOutPorts, Reg#(Bool) ) lockedVL; // locked virtual link + Vector#(NumOutPorts, Reg#(InPort_t)) inPortVL; // holds current input for locked virtual channels + + // Update wires + //Vector#(NumOutPorts, Vector#(NumVCs, Wire#(Bool) )) credits_set; // to handle incoming credits + //Vector#(NumOutPorts, Vector#(NumVCs, Wire#(Bool) )) credits_clear; // to clear credits due to outgoing flits + + // for debugging + `ifdef EN_DBG + Reg#(Cycle_t) cycles <- mkConfigReg(0); + rule update_cycles(True); + cycles <= cycles + 1; + endrule + `endif + + // -- Initialization -- + //simple_credits <- replicateM(mkConfigReg(True)); // start with credits for all ouputs/VCs + simple_credits <- replicateM(mkDWire(False)); // don't assume credits + for(Integer o=0; o=0; v=v-1) begin // lowest VC has highest priority + outPortFIFOs_first[i][v] = outPortFIFOs[i][v].first(); + end*/ + end + + + // Build eligIO and mark selected-active VC per Input (lowest VC has priority) + // -- Option 1: cleaner, but less scalable -- is too slow when USE_VIRTUAL_LINKS is enabled + for(Integer i=0; i Router: %0d - enqueing to outPortFIFOs[%0d][%0d]", id, i, fl_in.vc); + //`DBG(("Marking incoming flit for dst:%0d VC:%0d from in:%0d (isT:%0d)", fl_in.dst, fl_in.vc, i, /*fl_in.is_head,*/ fl_in.is_tail)); + //hasFlitsVIO_set[fl_in.vc][i][out_port] <= True; + end + endmethod + + // send credits upstream + method ActionValue#(Vector#(NumVCs, Bool)) getNonFullVCs; + Vector#(NumVCs, Bool) ret = unpack(0); + let all_not_fulls = all(isTrue, flitVOQBuffers[i].notFull() ); // AND all not fulls + //return all_not_fulls; + if(all_not_fulls) begin + ret = unpack(1); + end + return ret; + //let not_fulls = flitVOQBuffers[i].notFull(); + //let all_not_fulls = fold(\& , not_fulls); // AND all not fulls + //let all_not_fulls = fold(\&, flitVOQBuffers[i].notFull()); // AND all not fulls + endmethod + endinterface; + + inPort_ifaces[i] = ifc; + end + + // Implement output interfaces + for(Integer o=0; o < valueOf(NumOutPorts); o=o+1) begin + let ifc = + interface OutPortSimple + method ActionValue#(Maybe#(Flit_t)) getFlit(); + Maybe#(Flit_t) flitOut = Invalid; + if( isValid(activeIn_perOut[o]) ) begin // I have a flit to send + let active_in = activeIn_perOut[o].Valid; + //let active_vc = activeVC_perOut[o].Valid; + if(!isValid(activeIn_perOut[o])) begin + `DBG_ID(("active_in is invalid!")); + end + flitOut = hasFlitsToSend_perIn[active_in]; + dynamicAssert(isValid(flitOut), "Allocation selected input port with invalid flit!"); + + if(`USE_VIRTUAL_LINKS) begin + if(flitOut.Valid.is_tail) begin // If you see a tail unlock VL (also covers head/tail case) + lockedVL[o] <= False; + `DBG_DETAIL_ID(("UNLOCKED output %0d (was locked to in:%0d)", o, inPortVL[o] )); + end else begin + lockedVL[o] <= True; + `DBG_DETAIL_ID(("LOCKED output %0d locked to in:%0d", o, active_in )); + inPortVL[o] <= active_in; + end + end + + end + + return flitOut; + endmethod + + // receive credits from downstream routers + method Action putNonFullVCs(Vector#(NumVCs, Bool) nonFullVCs); + //`DBG_DETAIL_ID(("Receiving Credit on out_port %0d", o)); + simple_credits[o] <= nonFullVCs[0]; + endmethod + endinterface; + outPort_ifaces[o] = ifc; + end + + interface in_ports = inPort_ifaces; + interface out_ports = outPort_ifaces; + +endmodule + +//////////////////////////////////////////////// +// Router Module implementation +//////////////////////////////////////////////// +module mkVOQRouterSimple#(Integer id)(RouterSimple); + String name = "VOQRouter"; + Bit#(8) errorCode = 0; + + Vector#(NumInPorts, InPortSimple) inPort_ifaces; // in port interfaces +`ifdef EN_DBG + RouterCoreSimple router_core <- mkVOQRouterCoreSimple(id); +`else + RouterCoreSimple router_core <- mkVOQRouterCoreSimple(); +`endif + // Route Table + String route_table_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(id)), ".hex"); + //String route_table_file = strConcat( strConcat(`NETWORK_ROUTING_FILE_PREFIX, integerToString(0)), ".hex"); + //RF_16portsLoad#(RouterID_t, OutPort_t) routeTable <- mkRF_16portsLoad(route_table_file, /*binary*/False); + //RouteTable routeTable <- mkRouteTable(route_table_file, /*binary*/False); + RouteTable routeTable <- mkRouteTable(route_table_file); + + // for debugging + `ifdef EN_DBG + Reg#(Cycle_t) cycles <- mkConfigReg(0); + `endif + + `ifdef EN_DBG + rule update_cycles(True); + cycles <= cycles + 1; + endrule + `endif + + // Define input interfaces + for(Integer i=0; i < valueOf(NumInPorts); i=i+1) begin + let ifc = + interface InPortSimple + method Action putFlit(Maybe#(Flit_t) flit_in); + Maybe#(RoutedFlit_t) rt_flit = Invalid; + //`DBG_ID(("Receiving Flit on in_port %0d", i)); + if(isValid(flit_in)) begin + let fl_in = flit_in.Valid; + let out_p = routeTable.r[i].sub(fl_in.dst); + //let fl_in = tagged Valid Flit_t{is_tail:flit_in.Valid.is_tail, dst:flit_in.Valid.dst, out_p:out_p, vc:flit_in.Valid.vc, data:flit_in.Valid.data}; + rt_flit = tagged Valid RoutedFlit_t{flit:fl_in, out_port:out_p}; + //rt_flit = tagged Valid RoutedFlit_t{ flit:Flit_t{is_tail:fl_in.is_tail, dst:fl_in.dst, out_p:out_p, vc:fl_in.vc, data:fl_in.data}, out_port:out_p}; + `DBG_ID_CYCLES(("Incoming flit on port %0d - dest:%0d, data:%x", i, fl_in.dst, fl_in.data )); + end + router_core.in_ports[i].putRoutedFlit(rt_flit); + endmethod + + // send credits upstream + method ActionValue#(Vector#(NumVCs, Bool)) getNonFullVCs; + let cr_out <- router_core.in_ports[i].getNonFullVCs(); + return cr_out; + endmethod + endinterface; + + inPort_ifaces[i] = ifc; + end + + // Implement RouterInfo interface + /*let rt_info_ifc = + interface RouterInfo + method RouterID_t getRouterID; + return fromInteger(id); + endmethod + endinterface;*/ + + interface in_ports = inPort_ifaces; + interface out_ports = router_core.out_ports; + //interface rt_info = rt_info_ifc; + +endmodule + + +module mkVOQRouterSynth(RouterSimple); + let rt_synth <- mkVOQRouterSimple(4); + return rt_synth; +endmodule + + diff --git a/gen_network.py b/gen_network.py new file mode 100755 index 0000000..ec0763f --- /dev/null +++ b/gen_network.py @@ -0,0 +1,2915 @@ +#!/usr/bin/env python +""" +SYNOPSIS + %prog [-h,--help] [-v,--verbose] [--version] + +DESCRIPTION + This script generates configuration files that are used by the network rtl and represent different topologies and network configurations. + In particular these files are generated: + - network_parameters.bsv : specifies network and router parameters. + - network_links.bsv : specifies how routers are connected (i.e. topology) + - network_routing_X.hex : specifies contents of router tables for router X (i.e. routing) + +EXAMPLES + %prog -t ring -n 4 -v 2 -d 8 -w 256 + +EXIT STATUS + Exit codes + +AUTHOR + Michael K. Papamichael + +LICENSE + Please contact the author for license information. + +VERSION + 0.6""" + +import sys, os, traceback, optparse +import math +import time +import re +import hashlib +#from pexpect import run, spawn + + +############################################### +## Opens and writes header to graphviz file +def prepare_graph_file(gv_filename, layout="invalid", custom_topology_info=None): + """ Opens graphviz file, writes header and returns file pointer""" + global options, args + try: dot = open(gv_filename, 'w'); + except IOError: print "Could not open file " + gv_filename; sys.exit(-1); + + # Write header + dot.write('digraph ' + options.topology + '_' + str(options.num_routers) + 'routers {\n'); + #dot.write(' layout = dot;\n'); + dot.write(' graph [outputorder=nodesfirst];\n') + #dot.write(' graph [center rankdir=LR];\n'); + #dot.write(' node [shape = circle fixedsize="true" width="0.6!" height="0.6!"]\n'); + #dot.write(' node [shape = circle width="0.6" height="0.6"]\n'); + #dot.write(' node [shape = circle penwidth="4.0" fillcolor="#336699" style="filled" color="#002060"]\n'); + + # Set node, edge and label styles + dot.write(' node [shape=circle width="0.75!" height="0.75!" penwidth="3.0" color="#385D8A" fillcolor="#4F81BD" style="filled" fontname="Arial" fontcolor="#FFFFFF"]\n'); + dot.write(' edge [penwidth="2.0" color="#002060" fontname="Arial"]\n'); + endpoint_node_style = 'node [shape=Mrecord style="rounded" width="0.25!" height="0.25!" penwidth="2.0" color="#E55400" fillcolor="#FF5D00" style="filled" fontname="Arial" fontcolor="#FFFFFF"]\n'; + #dot.write(' node [shape=box width="0.25!" height="0.25!" penwidth="2.0" color="#E55400" fillcolor="#FF5D00" style="filled" fontname="Arial" fontcolor="#FFFFFF"]\n'); + #dot.write(' edge [penwidth="2.0" color="#002060" fontname="Arial" dir="both"]\n'); + #dot.write(' edge [penwidth="2.0" color="#002060" fontname="Arial" labelfontsize="18"]\n'); + #dot.write(' node [shape = circle penwidth="3.0" fillcolor="#99b2cc" style="filled" color="#1f497d" fontcolor="#FFFFFF"]\n'); + #dot.write(' node [shape = circle penwidth="3.0" fillcolor="#336699" style="filled" color="#002060" fontcolor="#FFFFFF"]\n'); + + # For single switch topology only draw one router + if (options.topology == "single_switch"): + dot.write('node [label="R'+str(0)+'"] R'+str(0)+';\n'); + + if(options.graph_nodes): # Add endpoint nodes + dot.write(endpoint_node_style); + for r in range(options.num_routers): + dot.write('node [label="N'+str(r)+'"] N'+str(r)+';\n'); + + # For mesh and torus position nodes + elif (options.topology == "mesh" or options.topology == "torus"): # arrange nodes in a grid + rt_id = 0; + for c in range(options.routers_per_column): + for r in range(options.routers_per_row): + dot.write('\nnode [label="R'+str(rt_id)+'" pos="'+str(r*1.5)+','+str(c*1.5)+'!"] R'+str(rt_id)+'\n'); + rt_id = rt_id+1 + dot.write('\n'); + + if(options.graph_nodes): # Add endpoint nodes + dot.write(endpoint_node_style); + rt_id = 0; + for c in range(options.routers_per_column): + for r in range(options.routers_per_row): + dot.write('\nnode [label="N'+str(rt_id)+'" pos="'+str(r*1.5+0.75)+','+str(c*1.5+0.75)+'!"] N'+str(rt_id)+'\n'); + rt_id = rt_id+1 + + # For star reduce number of endpoint nodes by one + elif (options.topology == "star"): # arrange nodes in a tree + for r in range(options.num_routers): + dot.write('node [label="R'+str(r)+'"] R'+str(r)+';\n'); + if(options.graph_nodes): # Add endpoint nodes + dot.write(endpoint_node_style); + for r in range(options.num_routers-1): + dot.write('node [label="N'+str(r)+'"] N'+str(r)+';\n'); + + # For Fat Tree position nodes + elif (options.topology == "fat_tree"): # arrange nodes in a tree + num_stages = int(math.log(options.num_routers, 2)) - 1 # counts router stages + rts_in_stage = options.num_routers/2 + rt_id = 0; + for stage in range(num_stages): + if (stage < num_stages-1): # not the top stage + for sr in range(rts_in_stage): # subrouter in particular stage + dot.write('\nnode [label="R'+str(rt_id)+'" pos="'+str(sr*2)+','+str(stage*4)+'!"] R'+str(rt_id)+'\n'); + rt_id = rt_id+1 + else: # Last stage links + #dot.write(' node [shape=square width="1!" height="1!" penwidth="3.0" color="#385D8A" fillcolor="#4F81BD" style="filled" fontname="Arial" fontcolor="#FFFFFF"]\n'); + for sr in range(rts_in_stage/2): # subrouter in particular stage + dot.write('\nnode [label="R'+str(rt_id)+'" pos="'+str(1+sr*4)+','+str(stage*4)+'!"] R'+str(rt_id)+'\n'); + rt_id = rt_id+1 + dot.write('\n'); + + if(options.graph_nodes): # Add endpoint nodes + dot.write(endpoint_node_style); + stage = 0; # bottom stage + for sr in range(rts_in_stage): # subrouter in particular stage + dot.write('\nnode [label="N'+str(sr*2)+'" pos="'+str(sr*2-0.5)+','+str(-2)+'!"] N'+str(sr*2)+'\n'); + dot.write('\nnode [label="N'+str(sr*2+1)+'" pos="'+str(sr*2+0.5)+','+str(-2)+'!"] N'+str(sr*2+1)+'\n'); + #dot.write('node [label="N'+str(r)+'"] N'+str(r)+';\n'); + + # For Butterfly position nodes + elif (options.topology == "butterfly"): # arrange nodes in left-to-right stages + num_stages = int(math.log(options.num_routers, 2)) # counts router stages + rts_in_stage = options.num_routers/2 + rt_id = 0; + for stage in range(num_stages): + for sr in range(rts_in_stage): # subrouter in particular stage + #dot.write('\nnode [label="R'+str(rt_id)+'" pos="'+str(sr*2)+','+str(stage*4)+'!"] R'+str(rt_id)+'\n'); + dot.write('\nnode [label="R'+str(rt_id)+'" pos="'+str(stage*4)+','+str(sr*2)+'!"] R'+str(rt_id)+'\n'); + rt_id = rt_id+1 + dot.write('\n'); + + if(options.graph_nodes): # Add endpoint nodes + dot.write(endpoint_node_style); + stage = 0; # bottom stage + for sr in range(rts_in_stage): # subrouter in particular stage + # left nodes + #dot.write('\nnode [label="N'+str(sr*2)+'" pos="'+str(-2)+','+str(sr*2-0.5)+'!"] N'+str(sr*2)+'\n'); + #dot.write('\nnode [label="N'+str(sr*2+1)+'" pos="'+str(-2)+','+str(sr*2+0.5)+'!"] N'+str(sr*2+1)+'\n'); + dot.write('\nnode [label="N" pos="'+str(-2)+','+str(sr*2-0.5)+'!"] N'+str(sr*2+options.num_routers)+'\n'); + dot.write('\nnode [label="N" pos="'+str(-2)+','+str(sr*2+0.5)+'!"] N'+str(sr*2+1+options.num_routers)+'\n'); + # right nodes + #dot.write('\nnode [label="N'+str(sr*2+options.num_routers)+'" pos="'+str(num_stages*4-2)+','+str(sr*2-0.5)+'!"] N'+str(sr*2+options.num_routers)+'\n'); + #dot.write('\nnode [label="N'+str(sr*2+1+options.num_routers)+'" pos="'+str(num_stages*4-2)+','+str(sr*2+0.5)+'!"] N'+str(sr*2+1+options.num_routers)+'\n'); + dot.write('\nnode [label="N'+str(sr*2)+'" pos="'+str(num_stages*4-2)+','+str(sr*2-0.5)+'!"] N'+str(sr*2)+'\n'); + dot.write('\nnode [label="N'+str(sr*2+1)+'" pos="'+str(num_stages*4-2)+','+str(sr*2+0.5)+'!"] N'+str(sr*2+1)+'\n'); + #dot.write('node [label="N'+str(r)+'"] N'+str(r)+';\n'); + + # For Unidirectional single switch topology only draw one router + elif (options.topology == "uni_single_switch"): + dot.write('node [label="R'+str(0)+'"] R'+str(0)+';\n'); + + if(options.graph_nodes): # Add endpoint nodes + dot.write(endpoint_node_style); + for r in range(options.recv_endpoints): + dot.write('node [label="N'+str(r)+'"] N'+str(r)+';\n'); + for r in range(options.send_endpoints): + dot.write('node [label="N'+str(r+options.recv_endpoints)+'"] N'+str(r+options.recv_endpoints)+';\n'); + + + # For Unidirectional Tree position nodes + elif (options.topology == "uni_tree" or options.topology == "uni_tree_up" or options.topology == "uni_tree_down"): # arrange nodes in a tree + + build_down_tree = True; + if (options.topology == "uni_tree_down"): + build_down_tree = True; + elif (options.topology == "uni_tree_up"): + build_down_tree = False; + elif (options.uni_tree_inputs < options.uni_tree_outputs): + build_down_tree = True; + else: + build_down_tree = False; + + # assuming up tree + num_root_nodes = options.uni_tree_outputs + num_leaf_nodes = options.uni_tree_inputs + #if(options.uni_tree_inputs < options.uni_tree_outputs): # Build down tree + if(build_down_tree): # Build down tree + num_root_nodes = options.uni_tree_inputs + num_leaf_nodes = options.uni_tree_outputs + + num_stages = int(math.ceil(math.log(num_leaf_nodes, options.uni_tree_fanout))) - 1 # counts link stages + # Find first and last router id of last stage where nodes attach + final_stage_rt_first_id = 0 + for i in range(num_stages): + final_stage_rt_first_id += options.uni_tree_fanout**i + final_stage_rt_last_id = final_stage_rt_first_id * options.uni_tree_fanout + + cur_rt = 0; + rts_in_stage = 1; + last_stage_width = (1.0*options.uni_tree_fanout)**num_stages; # num_leaf_nodes/(1.0*options.uni_tree_fanout); + if(options.graph_nodes): # Make more space to add endpoint nodes + last_stage_width = (1.0*options.uni_tree_fanout)**(num_stages+1); # num_leaf_nodes/(1.0*options.uni_tree_fanout); + print "width", last_stage_width + for stage in range(num_stages+1): + gap = last_stage_width / (1.0*rts_in_stage) + offset = gap/2.0 + print "offset ", offset + for r in range(rts_in_stage): + dot.write('\nnode [label="R'+str(cur_rt)+'" pos="'+str(offset+gap*r*1.0)+','+str((-1)*stage*2)+'!"] R'+str(cur_rt)+'\n'); + cur_rt += 1; + rts_in_stage *= options.uni_tree_fanout; + + if(options.graph_nodes): # Add endpoint nodes + dot.write(endpoint_node_style); + + for stage in range(num_stages+1): + gap = 1.0; #last_stage_width / laste_) + offset = 0.5 + (last_stage_width - 1.0*num_root_nodes) / 2.0 + print "gap",gap,"offset",offset + if(stage == 0): # root + #if(options.uni_tree_inputs < options.uni_tree_outputs): # down tree has inputs at root + if(build_down_tree): # down tree has inputs at root + for i in range(options.uni_tree_inputs): + # Leave input ports anonymous + dot.write('\nnode [label="N'+ "" +'" pos="'+str(offset+gap*i*1.0)+','+str(2)+'!"] N'+str(i+options.uni_tree_outputs)+'\n'); + else: # up tree has outputs at root + for o in range(options.uni_tree_outputs): + dot.write('\nnode [label="N'+str(o)+'" pos="'+str(offset+gap*o*1.0)+','+str(2)+'!"] N'+str(o)+'\n'); + #dot.write('\nnode [label="R'+str(cur_rt)+'" pos="'+str(offset+gap*r*1.0)+','+str((-1)*stage*2)+'!"] R'+str(cur_rt)+'\n'); + + if(stage == num_stages): # last stage + gap = 1.0; #last_stage_width / (1.0*rts_in_stage) + offset = gap/2.0 + print "offset ", offset + #for r in range(rts_in_stage): + #if(options.uni_tree_inputs < options.uni_tree_outputs): # down tree has outputs at leafs + if(build_down_tree): # down tree has outputs at leafs + if(options.uni_tree_distribute_leaves): #distribute leaves + for o in range(options.uni_tree_outputs): + rt = get_uni_tree_distributed_rt(o, num_stages, options.uni_tree_fanout); + r_off = o/(options.uni_tree_fanout**(num_stages)); + dist = (rt*options.uni_tree_fanout+r_off); + #dot.write('\nnode [label="N'+ "" +'" pos="'+str(offset+jump*a*1.0+b*gap)+','+str(2)+'!"] N'+str(i+options.uni_tree_outputs)+'\n'); + dot.write('\nnode [label="N'+str(o)+'" pos="'+str(offset+dist*1.0*gap)+','+str((-1)*(stage+1)*2)+'!"] N'+str(o)+'\n'); + else: + for o in range(options.uni_tree_outputs): + dot.write('\nnode [label="N'+str(o)+'" pos="'+str(offset+gap*o*1.0)+','+str((-1)*(stage+1)*2)+'!"] N'+str(o)+'\n'); + #dot.write('\nnode [label="R'+str(cur_rt)+'" pos="'+str(offset+gap*r*1.0)+','+str((-1)*stage*2)+'!"] R'+str(cur_rt)+'\n'); + else: # up tree has inputs at leafs + if(options.uni_tree_distribute_leaves): #distribute leaves + for i in range(options.uni_tree_inputs): + rt = get_uni_tree_distributed_rt(i, num_stages, options.uni_tree_fanout); + r_off = i/(options.uni_tree_fanout**(num_stages)); + dist = (rt*options.uni_tree_fanout+r_off); + #dot.write('\nnode [label="N'+ "" +'" pos="'+str(offset+jump*a*1.0+b*gap)+','+str(2)+'!"] N'+str(i+options.uni_tree_outputs)+'\n'); + dot.write('\nnode [label="N'+ "" +'" pos="'+str(offset+dist*1.0*gap)+','+str((-1)*(stage+1)*2)+'!"] N'+str(i+options.uni_tree_outputs)+'\n'); + else: + for i in range(options.uni_tree_inputs): + dot.write('\nnode [label="N'+ "" +'" pos="'+str(offset+gap*i*1.0)+','+str((-1)*(stage+1)*2)+'!"] N'+str(i+options.uni_tree_outputs)+'\n'); + # use upper unused node IDs for the inputs ports + + # For custom topology consult topology_info + elif (options.topology == "custom"): + for r in range(options.num_routers): + dot.write('node [label="R'+str(r)+'"] R'+str(r)+';\n'); + + if(options.graph_nodes): # Add endpoint nodes + dot.write(endpoint_node_style); + #for r in range(options.num_routers): + for r in range( max( custom_topology_info['max_send_ports'], custom_topology_info['max_recv_ports']) ): + dot.write('node [label="N'+str(r)+'"] N'+str(r)+';\n'); + + # other topologies + else: + for r in range(options.num_routers): + dot.write('node [label="R'+str(r)+'"] R'+str(r)+';\n'); + + if(options.graph_nodes): # Add endpoint nodes + dot.write(endpoint_node_style); + for r in range(options.num_routers): + dot.write('node [label="N'+str(r)+'"] N'+str(r)+';\n'); + +# # Describe and rank nodes +# if (options.topology == "mesh" or options.topology == "torus"): # arrange nodes in a grid +# rt_id = 0; +# for c in range(options.routers_per_column): +# dot.write('{ node [shape=circle]\n'); +# for r in range(options.routers_per_row): +# dot.write(' R'+str(rt_id)); +# rt_id = rt_id+1 +# dot.write('\n}\n'); +# +# else: +# for r in range(options.num_routers): +# dot.write('node [label="R'+str(r)+'"] R'+str(r)+';\n'); + + if (options.graph_layout == "invalid"): # if user has not set this, set to specified layout + options.graph_layout = layout; + return dot + + +####################################### +## Single Switch +def gen_single_switch_links(links, dot_filename, dump_topology_filename): + """Generates links for single switch topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "circo"); + + # Expose user send/receive ports + for r in range(options.num_routers): + links.write('send_ports_ifaces['+str(r)+'] = routers['+str(0)+'].in_ports['+str(r)+'];\n') + links.write('recv_ports_ifaces['+str(r)+'] = routers['+str(0)+'].out_ports['+str(r)+'];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(r)+' -> R'+str(0)+':'+str(r)+'\n') + topo_dump.write('RecvPort '+str(r)+' -> R'+str(0)+':'+str(r)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('N'+str(r)+' -> R'+str(0)+' [ headlabel = "' + str(r) + '" ];\n') + dot.write('R'+str(0)+' -> N'+str(r)+' [ taillabel = "' + str(r) + '" ];\n') + #links.write('router_info_ifaces['+str(r)+'] = get_router_info_ifc('+str(r)+');\n') + links.write('recv_ports_info_ifaces['+str(r)+'] = get_port_info_ifc('+str(r)+');\n') + + link_id = 0; # this topology does not have any links + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id + +def gen_single_switch_routing(file_prefix, dump_routing_filename): + """Populates routing tables for single switch topology""" + global options, args + + # Dump routing file + if options.dump_routing_file: + try: route_dump = open(dump_routing_filename, 'w'); + except IOError: print "Could not open file " + dump_routing_filename; sys.exit(-1); + + link_id = -1; + # Just a single router + filename = options.output_dir + '/' + file_prefix + str(0) + '.hex' + try: rt = open(filename, 'w'); + except IOError: print "Could not open file " + filename; sys.exit(-1); + + for dst in range(options.num_routers): + out_port = dst + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(0)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(0)+': '+str(dst)+' -> '+str(out_port)+'\n'); + + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + + # Close routing dump file + if options.dump_routing_file: route_dump.close(); + if options.verbose and options.dump_routing_file: print 'Dumped routing file: ' + dump_routing_filename + + # Hack - set num_routers to actual number of routers + options.num_routers = 1; + + +####################################### +## Line +def gen_line_links(links, dot_filename, dump_topology_filename): + """Generates links for line topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + + # Generate graphviz .gv file + #if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "circo"); + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "dot"); + + # Expose user send/receive ports + for r in range(options.num_routers): + links.write('send_ports_ifaces['+str(r)+'] = routers['+str(r)+'].in_ports[0];\n') + links.write('recv_ports_ifaces['+str(r)+'] = routers['+str(r)+'].out_ports[0];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(r)+' -> R'+str(r)+':'+str(0)+'\n') + topo_dump.write('RecvPort '+str(r)+' -> R'+str(r)+':'+str(0)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('N'+str(r)+' -> R'+str(r)+' [ headlabel = "' + '0' + '" ];\n') + dot.write('R'+str(r)+' -> N'+str(r)+' [ taillabel = "' + '0' + '" ];\n') + #links.write('router_info_ifaces['+str(r)+'] = get_router_info_ifc('+str(r)+');\n') + links.write('recv_ports_info_ifaces['+str(r)+'] = get_port_info_ifc('+str(r)+');\n') + + link_id = -1; + # Connect in one direction using port 1 (right) + for r in range(options.num_routers-1): + link_id = link_id + 1; + next_router = (r+1)%options.num_routers; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(r)+'], 1, routers['+str(next_router)+'], 1);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(r)+':'+str(1)+' -> '+'R'+str(next_router)+':'+str(1)+'\n') + if options.gen_graph: dot.write('R'+str(r)+' -> R'+str(next_router)+' [ taillabel = "' + '1' + '", headlabel = "' + '1' + '" ];\n') + # Connect in the other direction using port 2 (left) + for r in range(1, options.num_routers): + link_id = link_id + 1; + prev_router = (r+options.num_routers-1)%options.num_routers; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(r)+'], 2, routers['+str(prev_router)+'], 2);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(r)+':'+str(2)+' -> '+'R'+str(prev_router)+':'+str(2)+'\n') + if options.gen_graph: dot.write('R'+str(r)+' -> R'+str(prev_router)+' [ taillabel = "' + '2' + '", headlabel = "' + '2' + '" ];\n') + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id + +def gen_line_routing(file_prefix, dump_routing_filename): + """Populates routing tables for line topology""" + global options, args + + # Dump routing file + if options.dump_routing_file: + try: route_dump = open(dump_routing_filename, 'w'); + except IOError: print "Could not open file " + dump_routing_filename; sys.exit(-1); + + link_id = -1; + for src in range(options.num_routers): + filename = options.output_dir + '/' + file_prefix + str(src) + '.hex' + try: rt = open(filename, 'w'); + except IOError: print "Could not open file " + filename; sys.exit(-1); + + for dst in range(options.num_routers): + if src == dst: # packet is destined to me, extract from router, i.e. out_port 0 + rt.write('%x\n' % (0) ); + #str.format( ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+'0' + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(0)+'\n'); + else: # packet is not for me, decide which way to send + diff = dst-src + dist = abs(diff) + if (diff >= 0): # Send to the right, i.e. using out_port 1 + out_port = 1 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + else: # Send to the left, i.e. using out_port 2 + out_port = 2 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + + # Close routing dump file + if options.dump_routing_file: route_dump.close(); + if options.verbose and options.dump_routing_file: print 'Dumped routing file: ' + dump_routing_filename + + +####################################### +## Ring +def gen_ring_links(links, dot_filename, dump_topology_filename): + """Generates links for ring topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "circo"); + + # Expose user send/receive ports + for r in range(options.num_routers): + links.write('send_ports_ifaces['+str(r)+'] = routers['+str(r)+'].in_ports[0];\n') + links.write('recv_ports_ifaces['+str(r)+'] = routers['+str(r)+'].out_ports[0];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(r)+' -> R'+str(r)+':'+str(0)+'\n') + topo_dump.write('RecvPort '+str(r)+' -> R'+str(r)+':'+str(0)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('N'+str(r)+' -> R'+str(r)+' [ headlabel = "' + '0' + '" ];\n') + dot.write('R'+str(r)+' -> N'+str(r)+' [ taillabel = "' + '0' + '" ];\n') + + #links.write('router_info_ifaces['+str(r)+'] = get_router_info_ifc('+str(r)+');\n') + links.write('recv_ports_info_ifaces['+str(r)+'] = get_port_info_ifc('+str(r)+');\n') + + link_id = -1; + for r in range(options.num_routers): + link_id = link_id + 1; + next_router = (r+1)%options.num_routers; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(r)+'], 1, routers['+str(next_router)+'], 1);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(r)+':'+str(1)+' -> '+'R'+str(next_router)+':'+str(1)+'\n') + if options.gen_graph: dot.write('R'+str(r)+' -> R'+str(next_router)+' [ taillabel = "' + '1' + '", headlabel = "' + '1' + '" ];\n') + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id + +def gen_ring_routing(file_prefix, dump_routing_filename): + """Populates routing tables for ring topology""" + global options, args + + # Dump routing file + if options.dump_routing_file: + try: route_dump = open(dump_routing_filename, 'w'); + except IOError: print "Could not open file " + dump_routing_filename; sys.exit(-1); + + link_id = -1; + for src in range(options.num_routers): + filename = options.output_dir + '/' + file_prefix + str(src) + '.hex' + try: + rt = open(filename, 'w') + except IOError: + print "Could not open file " + filename + sys.exit(-1) + + for dst in range(options.num_routers): + if src == dst: # packet is destined to me, extract from router, i.e. out_port 0 + rt.write('%x\n' % (0) ); + #str.format( ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+'0' + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(0)+'\n'); + else: # packet is not for me, send to next router, i.e. out_port 1 + #next_router = (src+1)%options.num_routers; + rt.write('%x\n' % (1) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+'1' + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(1)+'\n'); + + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + + # Close routing dump file + if options.dump_routing_file: route_dump.close(); + if options.verbose and options.dump_routing_file: print 'Dumped routing file: ' + dump_routing_filename + + +####################################### +## Double-Ring +def gen_double_ring_links(links, dot_filename, dump_topology_filename): + """Generates links for double-ring topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "circo"); + + # Expose user send/receive ports + for r in range(options.num_routers): + links.write('send_ports_ifaces['+str(r)+'] = routers['+str(r)+'].in_ports[0];\n') + links.write('recv_ports_ifaces['+str(r)+'] = routers['+str(r)+'].out_ports[0];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(r)+' -> R'+str(r)+':'+str(0)+'\n') + topo_dump.write('RecvPort '+str(r)+' -> R'+str(r)+':'+str(0)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('N'+str(r)+' -> R'+str(r)+' [ headlabel = "' + '0' + '" ];\n') + dot.write('R'+str(r)+' -> N'+str(r)+' [ taillabel = "' + '0' + '" ];\n') + #links.write('router_info_ifaces['+str(r)+'] = get_router_info_ifc('+str(r)+');\n') + links.write('recv_ports_info_ifaces['+str(r)+'] = get_port_info_ifc('+str(r)+');\n') + + link_id = -1; + # Connect in one direction using port 1 (clockwise) + for r in range(options.num_routers): + link_id = link_id + 1; + next_router = (r+1)%options.num_routers; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(r)+'], 1, routers['+str(next_router)+'], 1);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(r)+':'+str(1)+' -> '+'R'+str(next_router)+':'+str(1)+'\n') + if options.gen_graph: dot.write('R'+str(r)+' -> R'+str(next_router)+' [ taillabel = "' + '1' + '", headlabel = "' + '1' + '" ];\n') + # Connect in the other direction using port 2 (counter-clockwise) + for r in range(options.num_routers): + link_id = link_id + 1; + prev_router = (r+options.num_routers-1)%options.num_routers; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(r)+'], 2, routers['+str(prev_router)+'], 2);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(r)+':'+str(2)+' -> '+'R'+str(prev_router)+':'+str(2)+'\n') + if options.gen_graph: dot.write('R'+str(r)+' -> R'+str(prev_router)+' [ taillabel = "' + '2' + '", headlabel = "' + '2' + '" ];\n') + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id + +def gen_double_ring_routing(file_prefix, dump_routing_filename): + """Populates routing tables for double-ring topology""" + global options, args + + # Dump routing file + if options.dump_routing_file: + try: route_dump = open(dump_routing_filename, 'w'); + except IOError: print "Could not open file " + dump_routing_filename; sys.exit(-1); + + link_id = -1; + for src in range(options.num_routers): + filename = options.output_dir + '/' + file_prefix + str(src) + '.hex' + try: + rt = open(filename, 'w') + except IOError: + print "Could not open file " + filename + sys.exit(-1) + + for dst in range(options.num_routers): + if src == dst: # packet is destined to me, extract from router, i.e. out_port 0 + rt.write('%x\n' % (0) ); + #str.format( ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+'0' + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(0)+'\n'); + else: # packet is not for me, decide which way to send + diff = dst-src + dist = abs(diff) + if (diff >= 0 and dist <= options.num_routers/2) or (diff < 0 and dist > options.num_routers/2) : # Send clockwise, i.e. using out_port 1 + out_port = 1 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + else: # Send counter-clockwise, i.e. using out_port 1 + out_port = 2 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + + # Close routing dump file + if options.dump_routing_file: route_dump.close(); + if options.verbose and options.dump_routing_file: print 'Dumped routing file: ' + dump_routing_filename + +####################################### +## Star +def gen_star_links(links, dot_filename, dump_topology_filename): + """Generates links for star topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "circo"); # neato also works well for small networks + + # Expose user send/receive ports + for r in range(options.num_routers-1): + links.write('send_ports_ifaces['+str(r)+'] = routers['+str(r+1)+'].in_ports[0];\n') + links.write('recv_ports_ifaces['+str(r)+'] = routers['+str(r+1)+'].out_ports[0];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(r)+' -> R'+str(r+1)+':'+str(0)+'\n') + topo_dump.write('RecvPort '+str(r)+' -> R'+str(r+1)+':'+str(0)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('N'+str(r)+' -> R'+str(r+1)+' [ headlabel = "' + '0' + '" ];\n') + dot.write('R'+str(r+1)+' -> N'+str(r)+' [ taillabel = "' + '0' + '" ];\n') + #links.write('router_info_ifaces['+str(r)+'] = get_router_info_ifc('+str(r)+');\n') + links.write('recv_ports_info_ifaces['+str(r)+'] = get_port_info_ifc('+str(r)+');\n') + + link_id = -1; + # Connect central router (0) to sattelite routers. + for r in range(1, options.num_routers): + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(0)+'], ' + str(r-1) + ', routers['+str(r)+'], 1);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(0)+':'+str(r-1)+' -> '+'R'+str(r)+':'+str(1)+'\n') + if options.gen_graph: dot.write('R'+str(0)+' -> R'+str(r)+' [ taillabel = "' + str(r-1) + '", headlabel = "' + '1' + '" ];\n') + + # Connect sattelite routers to central router (0). + for r in range(1, options.num_routers): + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(r)+'], ' + str(1) + ', routers['+str(0)+'], ' + str(r-1)+ ');\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(r)+':'+str(1)+' -> '+'R'+str(0)+':'+str(r-1)+'\n') + if options.gen_graph: dot.write('R'+str(r)+' -> R'+str(0)+' [ taillabel = "' + str(1) + '", headlabel = "' + str(r-1) + '" ];\n') + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id + +def gen_star_routing(file_prefix, dump_routing_filename): + """Populates routing tables for star topology""" + global options, args + + # Dump routing file + if options.dump_routing_file: + try: route_dump = open(dump_routing_filename, 'w'); + except IOError: print "Could not open file " + dump_routing_filename; sys.exit(-1); + + link_id = -1; + for src in range(options.num_routers): + filename = options.output_dir + '/' + file_prefix + str(src) + '.hex' + try: + rt = open(filename, 'w') + except IOError: + print "Could not open file " + filename + sys.exit(-1) + + for dst in range(options.num_routers): + if (src == 0): # routing for central node + out_port = dst; # directly send to sattelite router + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + else: # routing for sattelite routers + if (src-1) == dst: # packet is destined to me, extract from router, i.e. out_port 0 + rt.write('%x\n' % (0) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+'0' + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(0)+'\n'); + else: + out_port = 1; # always send to central router + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + + # Close routing dump file + if options.dump_routing_file: route_dump.close(); + if options.verbose and options.dump_routing_file: print 'Dumped routing file: ' + dump_routing_filename + + +####################################### +## Mesh +def gen_mesh_links(links, dot_filename, dump_topology_filename): + """Generates mesh for mesh topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "neato"); + + # Expose user send/receive ports + for r in range(options.num_routers): + links.write('send_ports_ifaces['+str(r)+'] = routers['+str(r)+'].in_ports[0];\n') + links.write('recv_ports_ifaces['+str(r)+'] = routers['+str(r)+'].out_ports[0];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(r)+' -> R'+str(r)+':'+str(0)+'\n') + topo_dump.write('RecvPort '+str(r)+' -> R'+str(r)+':'+str(0)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('N'+str(r)+' -> R'+str(r)+' [ headlabel = "' + '0' + '" ];\n') + dot.write('R'+str(r)+' -> N'+str(r)+' [ taillabel = "' + '0' + '" ];\n') + #links.write('router_info_ifaces['+str(r)+'] = get_router_info_ifc('+str(r)+');\n') + links.write('recv_ports_info_ifaces['+str(r)+'] = get_port_info_ifc('+str(r)+');\n') + + link_id = -1; + # Connect in left direction using port 1 (left) + for r in range(1, options.routers_per_row): + for c in range(0, options.routers_per_column): + rt_id = c*options.routers_per_row + r; + link_id = link_id + 1; + left_router = c*options.routers_per_row + (r+options.routers_per_row-1)%options.routers_per_row; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(rt_id)+'], 1, routers['+str(left_router)+'], 1);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(rt_id)+':'+str(1)+' -> '+'R'+str(left_router)+':'+str(1)+'\n') + if options.gen_graph: dot.write('R'+str(rt_id)+' -> R'+str(left_router)+' [ taillabel = "' + '1' + '", headlabel = "' + '1' + '" ];\n') + + # Connect in up direction using port 2 (up) + for r in range(0, options.routers_per_row): + for c in range(1, options.routers_per_column): + rt_id = c*options.routers_per_row + r; + link_id = link_id + 1; + up_router = ((c+options.routers_per_column-1)%options.routers_per_column) * options.routers_per_row + r; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(rt_id)+'], 2, routers['+str(up_router)+'], 2);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(rt_id)+':'+str(2)+' -> '+'R'+str(up_router)+':'+str(2)+'\n') + if options.gen_graph: dot.write('R'+str(rt_id)+' -> R'+str(up_router)+' [ taillabel = "' + '2' + '", headlabel = "' + '2' + '" ];\n') + + # Connect in right direction using port 3 (right) + for r in range(0, options.routers_per_row-1): + for c in range(0, options.routers_per_column): + rt_id = c*options.routers_per_row + r; + link_id = link_id + 1; + right_router = c*options.routers_per_row + (r+options.routers_per_row+1)%options.routers_per_row; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(rt_id)+'], 3, routers['+str(right_router)+'], 3);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(rt_id)+':'+str(3)+' -> '+'R'+str(right_router)+':'+str(3)+'\n') + if options.gen_graph: dot.write('R'+str(rt_id)+' -> R'+str(right_router)+' [ taillabel = "' + '3' + '", headlabel = "' + '3' + '" ];\n') + + # Connect in down direction using port 4 (down) + for r in range(0, options.routers_per_row): + for c in range(0, options.routers_per_column-1): + rt_id = c*options.routers_per_row + r; + link_id = link_id + 1; + down_router = ((c+options.routers_per_column+1)%options.routers_per_column) * options.routers_per_row + r; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(rt_id)+'], 4, routers['+str(down_router)+'], 4);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(rt_id)+':'+str(4)+' -> '+'R'+str(down_router)+':'+str(4)+'\n') + if options.gen_graph: dot.write('R'+str(rt_id)+' -> R'+str(down_router)+' [ taillabel = "' + '4' + '", headlabel = "' + '4' + '" ];\n') + + # Expose the extra user ports + if(options.expose_unused_ports): + num_total_user_ports = options.num_routers + 2*options.routers_per_row + 2*options.routers_per_column; + for user_port in range(options.num_routers, num_total_user_ports): + tmp = find_dst_and_output_for_user_port(user_port) + rt = tmp[0] + out_port = tmp[1] + in_port = ((out_port+1) % 4) + 1 + r = rt%options.routers_per_row # row + c = rt/options.routers_per_row # column + r_offset = 0; c_offset = 0; + if (out_port == 1): r_offset = -1.25; + if (out_port == 2): c_offset = -1.25; + if (out_port == 3): r_offset = 1.25; + if (out_port == 4): c_offset = 1.25; + links.write('send_ports_ifaces['+str(user_port)+'] = routers['+str(rt)+'].in_ports['+str(in_port)+'];\n') + links.write('recv_ports_ifaces['+str(user_port)+'] = routers['+str(rt)+'].out_ports['+str(out_port)+'];\n') + + if options.dump_topology_file: + topo_dump.write('SendPort '+str(user_port)+' -> R'+str(rt)+':'+str(in_port)+'\n') + topo_dump.write('RecvPort '+str(user_port)+' -> R'+str(rt)+':'+str(out_port)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + #dot.write('\nnode [label="N'+str(user_port)+'"] N'+str(user_port)+'\n'); + dot.write('\nnode [label="N'+str(user_port)+'" pos="'+str(r*1.5+r_offset)+','+str(c*1.5+c_offset)+'!"] N'+str(user_port)+'\n'); + dot.write('N'+str(user_port)+' -> R'+str(rt)+' [ headlabel = "' + str(in_port) + '" ];\n') + dot.write('R'+str(rt)+' -> N'+str(user_port)+' [ taillabel = "' + str(out_port) + '" ];\n') + #links.write('router_info_ifaces['+str(user_port)+'] = get_router_info_ifc('+str(user_port)+');\n') + links.write('recv_ports_info_ifaces['+str(user_port)+'] = get_port_info_ifc('+str(user_port)+');\n') + + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id+1 + +def gen_mesh_routing(file_prefix, dump_routing_filename): + """Populates routing tables for mesh topology. XY routing: First move horizontally, then vertically.""" + global options, args + + # Dump routing file + if options.dump_routing_file: + try: route_dump = open(dump_routing_filename, 'w'); + except IOError: print "Could not open file " + dump_routing_filename; sys.exit(-1); + + link_id = -1; + + ## Typical mesh, does not expose extra ports + if(not options.expose_unused_ports): + for src in range(options.num_routers): + filename = options.output_dir + '/' + file_prefix + str(src) + '.hex' + try: + rt = open(filename, 'w') + except IOError: + print "Could not open file " + filename + sys.exit(-1) + + for dst in range(options.num_routers): + if src == dst: # packet is destined to me, extract from router, i.e. out_port 0 + rt.write('%x\n' % (0) ); + #str.format( ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+'0' + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(0)+'\n'); + else: # packet is not for me, decide which way to send + src_row = src / options.routers_per_row + src_col = src % options.routers_per_row + dst_row = dst / options.routers_per_row + dst_col = dst % options.routers_per_row + if(src_col != dst_col): # Need to send horizontally + diff = dst_col-src_col + dist = abs(diff) + if (diff >= 0): # Send to the right, i.e. using out_port 3 + out_port = 3 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + else: # Send to the left, i.e. using out_port 1 + out_port = 1 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + else: # Need to send vertically + diff = dst_row-src_row + dist = abs(diff) + if (diff >= 0): # Send down, i.e. using out_port 4 + out_port = 4 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + else: # Send up, i.e. using out_port 2 + out_port = 2 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + + ## Expose extra ports + else: + num_total_user_ports = options.num_routers + 2*options.routers_per_row + 2*options.routers_per_column; + for src in range(options.num_routers): + filename = options.output_dir + '/' + file_prefix + str(src) + '.hex' + try: + rt = open(filename, 'w') + except IOError: + print "Could not open file " + filename + sys.exit(-1) + + for user_port in range(num_total_user_ports): + tmp = find_dst_and_output_for_user_port(user_port) + dst = tmp[0] + if dst == src: # packet is destined to me, extract from router, i.e. out_port 0 + out_port = tmp[1] + rt.write('%x\n' % (out_port) ); + #str.format( ); + if options.verbose: print 'route:'+str(src)+'->'+str(user_port)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(user_port)+' -> '+str(out_port)+'\n'); + else: # packet is not for me, decide which way to send + src_row = src / options.routers_per_row + src_col = src % options.routers_per_row + dst_row = dst / options.routers_per_row + dst_col = dst % options.routers_per_row + if(src_col != dst_col): # Need to send horizontally + diff = dst_col-src_col + dist = abs(diff) + if (diff >= 0): # Send to the right, i.e. using out_port 3 + out_port = 3 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(user_port)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(user_port)+' -> '+str(out_port)+'\n'); + else: # Send to the left, i.e. using out_port 1 + out_port = 1 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(user_port)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(user_port)+' -> '+str(out_port)+'\n'); + else: # Need to send vertically + diff = dst_row-src_row + dist = abs(diff) + if (diff >= 0): # Send down, i.e. using out_port 4 + out_port = 4 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(user_port)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(user_port)+' -> '+str(out_port)+'\n'); + else: # Send up, i.e. using out_port 2 + out_port = 2 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(user_port)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(user_port)+' -> '+str(out_port)+'\n'); + + + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + +# helper function for mesh that exposes extra user ports +def find_dst_and_output_for_user_port(user_port): + if(user_port < options.num_routers): + return [user_port,0] + else: + cur_user_port = options.num_routers-1; + for cur_rt in range(options.num_routers): + is_left_side_router = cur_rt % options.routers_per_row == 0 + is_right_side_router = cur_rt % options.routers_per_row == options.routers_per_row-1 + is_top_side_router = cur_rt >= 0 and cur_rt < options.routers_per_row + is_bottom_side_router = cur_rt >= options.num_routers - options.routers_per_row and cur_rt < options.num_routers + + if(is_left_side_router): + cur_user_port = cur_user_port+1 + if(cur_user_port == user_port): + return [cur_rt,1] + + if(is_top_side_router): + cur_user_port = cur_user_port+1 + if(cur_user_port == user_port): + return [cur_rt,2] + + if(is_right_side_router): + cur_user_port = cur_user_port+1 + if(cur_user_port == user_port): + return [cur_rt,3] + + if(is_bottom_side_router): + cur_user_port = cur_user_port+1 + if(cur_user_port == user_port): + return [cur_rt,4] + + #is_corner_router = (cur_rt == 0 || cur_rt == options.routers_per_row-1 || cur_rt == options.num_routers - 1 || cur_rt == options.num_routers - 1 - options.routers_per_row) + #is_top_bottom_router = (cur_rt >= 0 && cur_rt < options.routers_per_row) || (cur_rt >= options.num_routers - options.routers_per_row && cur_rt < options.num_routers) + + #is_left_right_side_router = (cur_rt % options.routers_per_row == 0 || cur_rt % options.routers_per_row == options.routers_per_row-1); + #src_row = src / options.routers_per_row + #src_col = src % options.routers_per_row + #dst_row = dst / options.routers_per_row + #dst_col = dst % options.routers_per_row + + + + + +####################################### +## Torus +def gen_torus_links(links, dot_filename, dump_topology_filename): + """Generates mesh for torus topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "neato"); + + # Expose user send/receive ports + for r in range(options.num_routers): + links.write('send_ports_ifaces['+str(r)+'] = routers['+str(r)+'].in_ports[0];\n') + links.write('recv_ports_ifaces['+str(r)+'] = routers['+str(r)+'].out_ports[0];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(r)+' -> R'+str(r)+':'+str(0)+'\n') + topo_dump.write('RecvPort '+str(r)+' -> R'+str(r)+':'+str(0)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('N'+str(r)+' -> R'+str(r)+' [ headlabel = "' + '0' + '" ];\n') + dot.write('R'+str(r)+' -> N'+str(r)+' [ taillabel = "' + '0' + '" ];\n') + #links.write('router_info_ifaces['+str(r)+'] = get_router_info_ifc('+str(r)+');\n') + links.write('recv_ports_info_ifaces['+str(r)+'] = get_port_info_ifc('+str(r)+');\n') + + link_id = -1; + # Connect in left direction using port 1 (left) + for r in range(0, options.routers_per_row): + for c in range(0, options.routers_per_column): + rt_id = c*options.routers_per_row + r; + link_id = link_id + 1; + left_router = c*options.routers_per_row + (r+options.routers_per_row-1)%options.routers_per_row; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(rt_id)+'], 1, routers['+str(left_router)+'], 1);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(rt_id)+':'+str(1)+' -> '+'R'+str(left_router)+':'+str(1)+'\n') + if options.gen_graph: dot.write('R'+str(rt_id)+' -> R'+str(left_router)+' [ taillabel = "' + '1' + '", headlabel = "' + '1' + '" ];\n') + + # Connect in up direction using port 2 (up) + for r in range(0, options.routers_per_row): + for c in range(0, options.routers_per_column): + rt_id = c*options.routers_per_row + r; + link_id = link_id + 1; + up_router = ((c+options.routers_per_column-1)%options.routers_per_column) * options.routers_per_row + r; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(rt_id)+'], 2, routers['+str(up_router)+'], 2);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(rt_id)+':'+str(2)+' -> '+'R'+str(up_router)+':'+str(2)+'\n') + if options.gen_graph: dot.write('R'+str(rt_id)+' -> R'+str(up_router)+' [ taillabel = "' + '2' + '", headlabel = "' + '2' + '" ];\n') + + # Connect in right direction using port 3 (right) + for r in range(0, options.routers_per_row): + for c in range(0, options.routers_per_column): + rt_id = c*options.routers_per_row + r; + link_id = link_id + 1; + right_router = c*options.routers_per_row + (r+options.routers_per_row+1)%options.routers_per_row; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(rt_id)+'], 3, routers['+str(right_router)+'], 3);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(rt_id)+':'+str(3)+' -> '+'R'+str(right_router)+':'+str(3)+'\n') + if options.gen_graph: dot.write('R'+str(rt_id)+' -> R'+str(right_router)+' [ taillabel = "' + '3' + '", headlabel = "' + '3' + '" ];\n') + + # Connect in down direction using port 4 (down) + for r in range(0, options.routers_per_row): + for c in range(0, options.routers_per_column): + rt_id = c*options.routers_per_row + r; + link_id = link_id + 1; + down_router = ((c+options.routers_per_column+1)%options.routers_per_column) * options.routers_per_row + r; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(rt_id)+'], 4, routers['+str(down_router)+'], 4);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(rt_id)+':'+str(4)+' -> '+'R'+str(down_router)+':'+str(4)+'\n') + if options.gen_graph: dot.write('R'+str(rt_id)+' -> R'+str(down_router)+' [ taillabel = "' + '4' + '", headlabel = "' + '4' + '" ];\n') + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id + +def gen_torus_routing(file_prefix, dump_routing_filename): + """Populates routing tables for torus topology. XY routing: First move horizontally, then vertically.""" + global options, args + + # Dump routing file + if options.dump_routing_file: + try: route_dump = open(dump_routing_filename, 'w'); + except IOError: print "Could not open file " + dump_routing_filename; sys.exit(-1); + + link_id = -1; + for src in range(options.num_routers): + filename = options.output_dir + '/' + file_prefix + str(src) + '.hex' + try: + rt = open(filename, 'w') + except IOError: + print "Could not open file " + filename + sys.exit(-1) + + for dst in range(options.num_routers): + if src == dst: # packet is destined to me, extract from router, i.e. out_port 0 + rt.write('%x\n' % (0) ); + #str.format( ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+'0' + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(0)+'\n'); + else: # packet is not for me, decide which way to send + src_row = src / options.routers_per_row + src_col = src % options.routers_per_row + dst_row = dst / options.routers_per_row + dst_col = dst % options.routers_per_row + if(src_col != dst_col): # Need to send horizontally + diff = dst_col-src_col + dist = abs(diff) + if (diff >= 0 and dist <= options.routers_per_row/2) or (diff < 0 and dist > options.routers_per_row/2) : # Send to the right, i.e. using out_port 3 + out_port = 3 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + else: # Send to the left, i.e. using out_port 1 + out_port = 1 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + else: # Need to send vertically + diff = dst_row-src_row + dist = abs(diff) + if (diff >= 0 and dist <= options.routers_per_column/2) or (diff < 0 and dist > options.routers_per_column/2) : # Send down, i.e. using out_port 4 + out_port = 4 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + else: # Send up, i.e. using out_port 2 + out_port = 2 + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(out_port)+'\n'); + + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + + # Close routing dump file + if options.dump_routing_file: route_dump.close(); + if options.verbose and options.dump_routing_file: print 'Dumped routing file: ' + dump_routing_filename + + +####################################### +## Fully-connected +def gen_fully_connected_links(links, dot_filename, dump_topology_filename): + """Generates links for fully_connected topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "circo"); # neato also works well for small networks + + # Expose user send/receive ports + for r in range(options.num_routers): + links.write('send_ports_ifaces['+str(r)+'] = routers['+str(r)+'].in_ports[0];\n') + links.write('recv_ports_ifaces['+str(r)+'] = routers['+str(r)+'].out_ports[0];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(r)+' -> R'+str(r)+':'+str(0)+'\n') + topo_dump.write('RecvPort '+str(r)+' -> R'+str(r)+':'+str(0)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('N'+str(r)+' -> R'+str(r)+' [ headlabel = "' + '0' + '" ];\n') + dot.write('R'+str(r)+' -> N'+str(r)+' [ taillabel = "' + '0' + '" ];\n') + #links.write('router_info_ifaces['+str(r)+'] = get_router_info_ifc('+str(r)+');\n') + links.write('recv_ports_info_ifaces['+str(r)+'] = get_port_info_ifc('+str(r)+');\n') + + link_id = -1; + # Connect each router to all other routers. + for s in range(0, options.num_routers): + for d in range(0, options.num_routers): + if (s != d): # don't create a link to my self + if (s < d): + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(s)+'], ' + str(d) + ', routers['+str(d)+'], ' + str(s+1) + ');\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(s)+':'+str(d)+' -> '+'R'+str(d)+':'+str(s+1)+'\n') + if options.gen_graph: dot.write('R'+str(s)+' -> R'+str(d)+' [ taillabel = "' + str(d) + '", headlabel = "' + str(s+1) + '" ];\n') + else: + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(s)+'], ' + str(d+1) + ', routers['+str(d)+'], ' + str(s) + ');\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(s)+':'+str(d+1)+' -> '+'R'+str(d)+':'+str(s)+'\n') + if options.gen_graph: dot.write('R'+str(s)+' -> R'+str(d)+' [ taillabel = "' + str(d+1) + '", headlabel = "' + str(s) + '" ];\n') + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id + +def gen_fully_connected_routing(file_prefix, dump_routing_filename): + """Populates routing tables for fully_connected topology""" + global options, args + + # Dump routing file + if options.dump_routing_file: + try: route_dump = open(dump_routing_filename, 'w'); + except IOError: print "Could not open file " + dump_routing_filename; sys.exit(-1); + + link_id = -1; + for src in range(options.num_routers): + filename = options.output_dir + '/' + file_prefix + str(src) + '.hex' + try: + rt = open(filename, 'w') + except IOError: + print "Could not open file " + filename + sys.exit(-1) + + # All routers are a single hop away. Just pick proper output port. + for dst in range(0, options.num_routers): + if src == dst: # packet is destined to me, extract from router, i.e. out_port 0 + rt.write('%x\n' % (0) ); + #str.format( ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+'0' + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(0)+'\n'); + else: # packet is not for me, decide which way to send + if (src < dst): + rt.write('%x\n' % (dst) ) + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(dst) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(dst)+'\n'); + else: + rt.write('%x\n' % (dst+1) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(dst+1) + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(dst+1)+'\n'); + + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + + # Close routing dump file + if options.dump_routing_file: route_dump.close(); + if options.verbose and options.dump_routing_file: print 'Dumped routing file: ' + dump_routing_filename + + +####################################### +## Fat Tree +def gen_fat_tree_links(links, dot_filename, dump_topology_filename): + """Generates links for fat-tree topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "neato"); + + # Expose user send/receive ports (note: num_routers is a misnomer for this topology) + for r in range(options.num_routers): + links.write('send_ports_ifaces['+str(r)+'] = routers['+str(r/2)+'].in_ports['+str(r%2)+'];\n') + links.write('recv_ports_ifaces['+str(r)+'] = routers['+str(r/2)+'].out_ports['+str(r%2)+'];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(r)+' -> R'+str(r/2)+':'+str(r%2)+'\n') + topo_dump.write('RecvPort '+str(r)+' -> R'+str(r/2)+':'+str(r%2)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('N'+str(r)+' -> R'+str(r/2)+' [ headlabel = "' + str(r%2) + '" ];\n') + dot.write('R'+str(r/2)+' -> N'+str(r)+' [ taillabel = "' + str(r%2) + '" ];\n') + #links.write('router_info_ifaces['+str(r)+'] = get_router_info_ifc('+str(r)+');\n') + links.write('recv_ports_info_ifaces['+str(r)+'] = get_port_info_ifc('+str(r)+');\n') + + link_id = -1; + # Create links for each stage + num_stages = int(math.log(options.num_routers, 2)) - 2 # counts link stages + rts_in_stage = options.num_routers/2 + print 'num_stages =', num_stages + for stage in range(num_stages): + if (stage < num_stages-1): # not the top stage + for sr in range(rts_in_stage): # subrouter in particular stage + cur_rt = stage * rts_in_stage + sr + + #Check if this router belongs to the left or right subset + if( (cur_rt & (1< '+'R'+str(cur_rt+rts_in_stage)+':'+str(0)+'\n') + if options.gen_graph: dot.write('R'+str(cur_rt)+' -> R'+str(cur_rt+rts_in_stage)+' [ taillabel = "' + '2' + '", headlabel = "' + '0' + '" ];\n') + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(cur_rt)+'], 3, routers['+str(cur_rt+rts_in_stage+(1< '+'R'+str(cur_rt+rts_in_stage+(1< R'+str(cur_rt+rts_in_stage+(1< '+'R'+str(cur_rt)+':'+str(2)+'\n') + if options.gen_graph: dot.write('R'+str(cur_rt+rts_in_stage)+' -> R'+str(cur_rt)+' [ taillabel = "' + '0' + '", headlabel = "' + '2' + '" ];\n') + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(cur_rt+rts_in_stage+(1< '+'R'+str(cur_rt)+':'+str(3)+'\n') + if options.gen_graph: dot.write('R'+str(cur_rt+rts_in_stage+(1< R'+str(cur_rt)+' [ taillabel = "' + '0' + '", headlabel = "' + '3' + '" ];\n') + + else: # right subset, i.e. has stage-th bit set to 1 (connect to the left and above) + #Up links + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(cur_rt)+'], 2, routers['+str(cur_rt+rts_in_stage-(1< '+'R'+str(cur_rt+rts_in_stage-(1< R'+str(cur_rt+rts_in_stage-(1< '+'R'+str(cur_rt+rts_in_stage)+':'+str(1)+'\n') + if options.gen_graph: dot.write('R'+str(cur_rt)+' -> R'+str(cur_rt+rts_in_stage)+' [ taillabel = "' + '3' + '", headlabel = "' + '1' + '" ];\n') + + #Down links + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(cur_rt+rts_in_stage-(1< '+'R'+str(cur_rt)+':'+str(2)+'\n') + if options.gen_graph: dot.write('R'+str(cur_rt+rts_in_stage-(1< R'+str(cur_rt)+' [ taillabel = "' + '1' + '", headlabel = "' + '2' + '" ];\n') + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(cur_rt+rts_in_stage)+'], 1, routers['+str(cur_rt)+'], 3);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(cur_rt+rts_in_stage)+':'+str(1)+' -> '+'R'+str(cur_rt)+':'+str(3)+'\n') + if options.gen_graph: dot.write('R'+str(cur_rt+rts_in_stage)+' -> R'+str(cur_rt)+' [ taillabel = "' + '1' + '", headlabel = "' + '3' + '" ];\n') + + else: # Last stage links + links.write('//Last stage links\n') + last_stages = rts_in_stage/2; # Number of stages in last/top level + first_top_rt = num_stages * rts_in_stage; + top_rt_offset = 0; # rotate between top RTs + top_port_id = 0; #which port to connect to + for sr in range(rts_in_stage): + cur_rt = stage * rts_in_stage + sr + #Check if this router belongs to the left or right subset + #if( (cur_rt & (1< '+'R'+str(first_top_rt+top_rt_offset)+':'+str(top_port_id)+'\n') + if options.gen_graph: dot.write('R'+str(cur_rt)+' -> R'+str(first_top_rt+top_rt_offset)+' [ taillabel = "' + '2' + '", headlabel = "' + str(top_port_id) + '" ];\n') + #Down links + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(first_top_rt+top_rt_offset)+'], '+str(top_port_id)+', routers['+str(cur_rt)+'], 2);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(first_top_rt+top_rt_offset)+':'+str(top_port_id)+' -> '+'R'+str(cur_rt)+':'+str(2)+'\n') + if options.gen_graph: dot.write('R'+str(first_top_rt+top_rt_offset)+' -> R'+str(cur_rt)+' [ taillabel = "' + str(top_port_id) + '", headlabel = "' + '2' + '" ];\n') + top_rt_offset = (top_rt_offset + 1) % last_stages; + + #Up Links + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(cur_rt)+'], 3, routers['+str(first_top_rt+top_rt_offset)+'], '+str(top_port_id)+');\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(cur_rt)+':'+str(3)+' -> '+'R'+str(first_top_rt+top_rt_offset)+':'+str(top_port_id)+'\n') + if options.gen_graph: dot.write('R'+str(cur_rt)+' -> R'+str(first_top_rt+top_rt_offset)+' [ taillabel = "' + '3' + '", headlabel = "' + str(top_port_id) + '" ];\n') + #Down links + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(first_top_rt+top_rt_offset)+'], '+str(top_port_id)+', routers['+str(cur_rt)+'], 3);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(first_top_rt+top_rt_offset)+':'+str(top_port_id)+' -> '+'R'+str(cur_rt)+':'+str(3)+'\n') + if options.gen_graph: dot.write('R'+str(first_top_rt+top_rt_offset)+' -> R'+str(cur_rt)+' [ taillabel = "' + str(top_port_id) + '", headlabel = "' + '3' + '" ];\n') + top_rt_offset = (top_rt_offset + 1) % last_stages; + + if(top_rt_offset == 0): + top_port_id = top_port_id + 1; # connect to next port now + + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id+1 + +# TODO: fix this when you get restored file from ECE computing services. +# Correct version was somewhere between 2/11 and 2/14 +def gen_fat_tree_routing(file_prefix, dump_routing_filename): + """Populates routing tables for fat-tree topology""" + global options, args + + # Dump routing file + if options.dump_routing_file: + try: route_dump = open(dump_routing_filename, 'w'); + except IOError: print "Could not open file " + dump_routing_filename; sys.exit(-1); + + num_stages = int(math.log(options.num_routers, 2)) - 1 # counts router stages + rts_in_stage = options.num_routers/2 + print 'num_stages =', num_stages + for stage in range(num_stages): + if (stage < num_stages-1): # not the top stage + for sr in range(rts_in_stage): # subrouter in particular stage + cur_rt = stage * rts_in_stage + sr + print 'cur_rt ', cur_rt + filename = options.output_dir + '/' + file_prefix + str(cur_rt) + '.hex' + try: rt = open(filename, 'w'); + except IOError: print "Could not open file " + filename; sys.exit(-1); + + for dst in range(options.num_routers): + # Look at MS bits to determine up or down direction + if(dst>>stage+1 == sr>>stage): #go down + # Look at stage-th bit to determine left or right direction + if( dst & (1<<(stage)) == 0): # go left + rt.write('%x\n' % (0) ); + if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+'0' + if options.dump_routing_file: route_dump.write('R'+str(cur_rt)+': '+str(dst)+' -> '+str(0)+'\n'); + else: #go right + rt.write('%x\n' % (1) ); + if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+'1' + if options.dump_routing_file: route_dump.write('R'+str(cur_rt)+': '+str(dst)+' -> '+str(1)+'\n'); + else: #go up + # Look at stage-th bit to determine left or right direction + if( dst & (1<<(stage)) == 0): # go left + rt.write('%x\n' % (2) ); + if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+'2' + if options.dump_routing_file: route_dump.write('R'+str(cur_rt)+': '+str(dst)+' -> '+str(2)+'\n'); + else: #go right + rt.write('%x\n' % (3) ); + if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+'3' + if options.dump_routing_file: route_dump.write('R'+str(cur_rt)+': '+str(dst)+' -> '+str(3)+'\n'); + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + + else: # top stage - you can only go down from here + for sr in range(rts_in_stage/2): # subrouter in particular stage + cur_rt = stage * rts_in_stage + sr + print 'cur_rt ', cur_rt + filename = options.output_dir + '/' + file_prefix + str(cur_rt) + '.hex' + try: rt = open(filename, 'w'); + except IOError: print "Could not open file " + filename; sys.exit(-1); + + for dst in range(options.num_routers): + # Look at 2 MS bits to determine up or down direction + out_port = dst>>stage + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(cur_rt)+': '+str(dst)+' -> '+str(out_port)+'\n'); + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + # Hack - set num_routers to actual number of routers + actual_routers = (num_stages-1) * (options.num_routers/2) + (options.num_routers/4) # n-1 stages + last stage + options.num_routers = actual_routers; + + # Close routing dump file + if options.dump_routing_file: route_dump.close(); + if options.verbose and options.dump_routing_file: print 'Dumped routing file: ' + dump_routing_filename + +# for src in range(options.num_routers): +# filename = options.output_dir + '/' + file_prefix + str(src) + '.hex' +# try: rt = open(filename, 'w'); +# except IOError: print "Could not open file " + filename; sys.exit(-1); +# +# for dst in range(options.num_routers): +# if src == dst: # packet is destined to me, extract from router, i.e. out_port 0 +# rt.write('%x\n' % (0) ); +# #str.format( ); +# if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+'0' +# else: # packet is not for me, decide which way to send +# diff = dst-src +# dist = abs(diff) +# if (diff >= 0): # Send to the right, i.e. using out_port 1 +# out_port = 1 +# rt.write('%x\n' % (out_port) ); +# if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) +# else: # Send to the left, i.e. using out_port 2 +# out_port = 2 +# rt.write('%x\n' % (out_port) ); +# if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) +# +# rt.close(); +# if options.verbose: print 'Generated routing file: ' + filename + + + +####################################### +## Butterfly (2-ary n-fly) +def gen_butterfly_links(links, dot_filename, dump_topology_filename): + """Generates links for butterfly topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "neato"); + + # Calculate number of stages and routers per stage + num_stages = int(math.log(options.num_routers, 2)); # number of stages - log2(N) + rts_in_stage = options.num_routers/2; # switches per stage - N/2 + last_stage_offset = (num_stages-1)*rts_in_stage; + + # Expose user send/receive ports (note: num_routers is a misnomer for this topology) + for r in range(options.num_routers): + links.write('send_ports_ifaces['+str(r)+'] = routers['+str(r/2)+'].in_ports['+str(r%2)+'];\n') + links.write('recv_ports_ifaces['+str(r)+'] = routers['+str(last_stage_offset + r/2)+'].out_ports['+str(r%2)+'];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(r)+' -> R'+str(r/2)+':'+str(r%2)+'\n') + topo_dump.write('RecvPort '+str(r)+' -> R'+str(last_stage_offset + r/2)+':'+str(r%2)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('N'+str(r+options.num_routers)+' -> R'+str(r/2)+' [ headlabel = "' + str(r%2) + '" ];\n') + dot.write('R'+str(last_stage_offset + r/2)+' -> N'+str(r)+' [ taillabel = "' + str(r%2) + '" ];\n') + #links.write('router_info_ifaces['+str(r)+'] = get_router_info_ifc('+str(r)+');\n') + links.write('recv_ports_info_ifaces['+str(r)+'] = get_port_info_ifc('+str(r)+');\n') + + # Create links for each stage + link_id = -1; + print 'num_stages =', num_stages + link_stages = num_stages - 1; + for stage in range(link_stages): # first stage is the most-right one + for sr in range(rts_in_stage): # subrouter in particular stage + cur_rt = stage * rts_in_stage + sr + + rev_stage = link_stages - stage -1; # count in reverse to make things simpler + #Check if this router belongs to the top or bottom + if( (cur_rt & 1< '+'R'+str(cur_rt+rts_in_stage)+':'+str(0)+'\n') + if options.gen_graph: dot.write('R'+str(cur_rt)+' -> R'+str(cur_rt+rts_in_stage)+' [ taillabel = "' + '0' + '", headlabel = "' + '0' + '" ];\n') + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(cur_rt)+'], 1, routers['+str(cur_rt+rts_in_stage+(1< '+'R'+str(cur_rt+rts_in_stage+(1< R'+str(cur_rt+rts_in_stage+(1< R'+str(cur_rt)+' [ taillabel = "' + '0' + '", headlabel = "' + '2' + '" ];\n') + #link_id = link_id + 1; + #links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(cur_rt+rts_in_stage+(1< R'+str(cur_rt)+' [ taillabel = "' + '0' + '", headlabel = "' + '3' + '" ];\n') + + else: # bottom subset, (connect to the right and top right) + #Up links + link_id = link_id + 1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(cur_rt)+'], 0, routers['+str(cur_rt+rts_in_stage-(1< '+'R'+str(cur_rt+rts_in_stage-(1< R'+str(cur_rt+rts_in_stage-(1< '+'R'+str(cur_rt+rts_in_stage)+':'+str(1)+'\n') + if options.gen_graph: dot.write('R'+str(cur_rt)+' -> R'+str(cur_rt+rts_in_stage)+' [ taillabel = "' + '1' + '", headlabel = "' + '1' + '" ];\n') + + #Down links + #link_id = link_id + 1; + #links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(cur_rt+rts_in_stage-(1< R'+str(cur_rt)+' [ taillabel = "' + '1' + '", headlabel = "' + '2' + '" ];\n') + #link_id = link_id + 1; + #links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(cur_rt+rts_in_stage)+'], 1, routers['+str(cur_rt)+'], 3);\n') + #if options.gen_graph: dot.write('R'+str(cur_rt+rts_in_stage)+' -> R'+str(cur_rt)+' [ taillabel = "' + '1' + '", headlabel = "' + '3' + '" ];\n') + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id+1 + sys.exit(0) + +# fix this +def gen_butterfly_routing(file_prefix, dump_routing_filename): + """Populates routing tables for butterfly topology""" + global options, args + + # Dump routing file + if options.dump_routing_file: + try: route_dump = open(dump_routing_filename, 'w'); + except IOError: print "Could not open file " + dump_routing_filename; sys.exit(-1); + + # Calculate number of stages and routers per stage + num_stages = int(math.log(options.num_routers, 2)); # number of stages - log2(N) + rts_in_stage = options.num_routers/2; # switches per stage - N/2 + last_stage_offset = (num_stages-1)*rts_in_stage; + + print 'num_stages =', num_stages + for stage in range(num_stages): + for sr in range(rts_in_stage): # subrouter in particular stage + cur_rt = stage * rts_in_stage + sr + rev_stage = num_stages - stage -1; # count in reverse to make things simpler + print 'cur_rt ', cur_rt + filename = options.output_dir + '/' + file_prefix + str(cur_rt) + '.hex' + try: rt = open(filename, 'w'); + except IOError: print "Could not open file " + filename; sys.exit(-1); + + for dst in range(options.num_routers): + # Look at stage-th bit to determine left or right direction + if( dst & (1<<(rev_stage)) == 0): # go down + rt.write('%x\n' % (0) ); + if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+'0' + if options.dump_routing_file: route_dump.write('R'+str(cur_rt)+': '+str(dst)+' -> '+str(0)+'\n'); + else: #go up + rt.write('%x\n' % (1) ); + if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+'1' + if options.dump_routing_file: route_dump.write('R'+str(cur_rt)+': '+str(dst)+' -> '+str(1)+'\n'); + + ## Look at MS bits to determine up or down direction + #if(dst>>rev_stage+1 == sr>>rev_stage): #go down + # # Look at stage-th bit to determine left or right direction + # if( dst & (1<<(rev_stage)) == 0): # go left + # rt.write('%x\n' % (0) ); + # if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+'0' + # else: #go right + # rt.write('%x\n' % (1) ); + # if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+'1' + #else: #go up + # # Look at stage-th bit to determine left or right direction + # if( dst & (1<<(rev_stage)) == 0): # go left + # rt.write('%x\n' % (2) ); + # if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+'2' + # else: #go right + # rt.write('%x\n' % (3) ); + # if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+'3' + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + # Hack - set num_routers to actual number of routers + actual_routers = (num_stages) * (options.num_routers/2) # n stages, each n/2 routers + options.num_routers = actual_routers; + + # Close routing dump file + if options.dump_routing_file: route_dump.close(); + if options.verbose and options.dump_routing_file: print 'Dumped routing file: ' + dump_routing_filename + + +####################################### +## Unidirectional Single Switch +def gen_uni_single_switch_links(links, dot_filename, dump_topology_filename): + """Generates links for unidirectional single switch topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "circo"); + +# Expose user send/receive ports + for r in range(options.recv_endpoints): + links.write('recv_ports_ifaces['+str(r)+'] = routers['+str(0)+'].out_ports['+str(r)+'];\n') + links.write('recv_ports_info_ifaces['+str(r)+'] = get_port_info_ifc('+str(r)+');\n') + if options.dump_topology_file: + topo_dump.write('RecvPort '+str(r)+' -> R'+str(0)+':'+str(r)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('R'+str(0)+' -> N'+str(r)+' [ taillabel = "' + str(r) + '" ];\n') + + for r in range(options.send_endpoints): + links.write('send_ports_ifaces['+str(r)+'] = routers['+str(0)+'].in_ports['+str(r)+'];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(r)+' -> R'+str(0)+':'+str(r)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + #dot.write('N'+str(r+options.recv_endpoints)+' -> R'+str(0)+' [ headlabel = "' + str(r+options.recv_endpoints) + '" ];\n') + dot.write('N'+str(r+options.recv_endpoints)+' -> R'+str(0)+' [ headlabel = "' + str(r) + '" ];\n') + #links.write('router_info_ifaces['+str(r)+'] = get_router_info_ifc('+str(r)+');\n') + + link_id = 0; # this topology does not have any links + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id + +def gen_uni_single_switch_routing(file_prefix, dump_routing_filename): + """Populates routing tables for unidirectional single switch topology""" + return gen_single_switch_routing(file_prefix, dump_routing_filename); + + +####################################### +## Uni-directional Tree helper function +## Given an endpoint id, it returns the router id the node should be attached to. +## Note: you still need to add the router offset of the first router id of the last stage. + +def get_uni_tree_distributed_rt(node_id, num_stages, fanout): + i = 0; + rt = 0; + while(num_stages > 0): + rt += (node_id%fanout) * (fanout**(num_stages-1)) + node_id = node_id / fanout; + num_stages -= 1 + return rt; + +####################################### +## Uni-directional Tree + +# Wrappers for gen_uni_tree functions +def gen_uni_tree_up_links(links, dot_filename, dump_topology_filename): + return gen_uni_tree_links(links, dot_filename, dump_topology_filename); + +def gen_uni_tree_up_routing(file_prefix, dump_routing_filename): + return gen_uni_tree_routing(file_prefix, dump_routing_filename); + +def gen_uni_tree_down_links(links, dot_filename, dump_topology_filename): + return gen_uni_tree_links(links, dot_filename, dump_topology_filename); + +def gen_uni_tree_down_routing(file_prefix, dump_routing_filename): + return gen_uni_tree_routing(file_prefix, dump_routing_filename); + +def gen_uni_tree_links(links, dot_filename, dump_topology_filename): + """Generates links for uni-tree topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "neato"); + + num_root_nodes = 0; + num_leaf_nodes = 0; + + build_down_tree = True; + if (options.topology == "uni_tree_down"): + build_down_tree = True; + elif (options.topology == "uni_tree_up"): + build_down_tree = False; + elif (options.uni_tree_inputs < options.uni_tree_outputs): + build_down_tree = True; + else: + build_down_tree = False; + + #if(options.uni_tree_inputs < options.uni_tree_outputs): # Build down tree + if(build_down_tree): # Build down tree + num_root_nodes = options.uni_tree_inputs + num_leaf_nodes = options.uni_tree_outputs + num_stages = int(math.ceil(math.log(num_leaf_nodes, options.uni_tree_fanout))) - 1 # counts link stages + print "num_stages ",num_stages + # Expose user send/receive ports + for i in range(options.uni_tree_inputs): + links.write('send_ports_ifaces['+str(i)+'] = routers[0].in_ports['+str(i)+'];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(i)+' -> R'+str(0)+':'+str(i)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('N'+str(i+options.uni_tree_outputs)+' -> R'+str(0)+' [ headlabel = "' + str(i) + '" ];\n') + # Find first and last router id of last stage where nodes attach + final_stage_rt_first_id = 0 + for i in range(num_stages): + final_stage_rt_first_id += options.uni_tree_fanout**i + print "final_stage_rt_first_id ", final_stage_rt_first_id + final_stage_rt_last_id = final_stage_rt_first_id * options.uni_tree_fanout + print "final_stage_rt_first_id ", final_stage_rt_last_id + + + num_final_stage_rts = (final_stage_rt_last_id+1) - final_stage_rt_first_id; + if(options.uni_tree_distribute_leaves): + for recv_port_id in range(options.uni_tree_outputs): + o = final_stage_rt_first_id + get_uni_tree_distributed_rt(recv_port_id, num_stages, options.uni_tree_fanout); + p = recv_port_id/(options.uni_tree_fanout**num_stages) + links.write('recv_ports_ifaces['+str(recv_port_id)+'] = routers['+str(o)+'].out_ports['+str(p)+'];\n') + if options.dump_topology_file: + topo_dump.write('RecvPort '+str(recv_port_id)+' -> R'+str(0)+':'+str(p)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('R'+str(o)+' -> N'+str(recv_port_id)+' [ taillabel = "' + str(p) + '" ];\n') + links.write('recv_ports_info_ifaces['+str(recv_port_id)+'] = get_port_info_ifc('+str(recv_port_id)+');\n') + recv_port_id += 1; + else: + recv_port_id = 0; + for o in range(final_stage_rt_first_id, final_stage_rt_last_id+1): + for p in range(options.uni_tree_fanout): + if(recv_port_id < options.uni_tree_outputs): # Stop once you've created enough output ports, even if the tree has more outputs + links.write('recv_ports_ifaces['+str(recv_port_id)+'] = routers['+str(o)+'].out_ports['+str(p)+'];\n') + if options.dump_topology_file: + topo_dump.write('RecvPort '+str(recv_port_id)+' -> R'+str(0)+':'+str(p)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('R'+str(o)+' -> N'+str(recv_port_id)+' [ taillabel = "' + str(p) + '" ];\n') + links.write('recv_ports_info_ifaces['+str(recv_port_id)+'] = get_port_info_ifc('+str(recv_port_id)+');\n') + recv_port_id += 1; + + link_id = -1 + cur_rt = 0; + rts_in_stage = 1; + for stage in range(num_stages): + + for r in range(rts_in_stage): + for l in range(options.uni_tree_fanout): + link_id += 1; + dest_rt = options.uni_tree_fanout*cur_rt+l+1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(cur_rt)+'], '+str(l)+', routers['+str(dest_rt)+'], 0);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(cur_rt)+':'+str(l)+' -> '+'R'+str(dest_rt)+':'+str(0)+'\n') + if options.gen_graph: dot.write('R'+str(cur_rt)+' -> R'+str(dest_rt)+' [ taillabel = "' + str(l) + '", headlabel = "' + '0' + '" ];\n') + cur_rt += 1; + rts_in_stage *= options.uni_tree_fanout; + + + else: # build up tree + num_root_nodes = options.uni_tree_outputs + num_leaf_nodes = options.uni_tree_inputs + num_stages = int(math.ceil(math.log(num_leaf_nodes, options.uni_tree_fanout))) - 1 # counts link stages + print "num_stages ",num_stages + # Expose user send/receive ports + for o in range(options.uni_tree_outputs): + links.write('recv_ports_ifaces['+str(o)+'] = routers[0].out_ports['+str(o)+'];\n') + if options.dump_topology_file: + topo_dump.write('RecvPort '+str(o)+' -> R'+str(0)+':'+str(o)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('R'+str(0)+' -> N'+str(o)+' [ taillabel = "' + str(o) + '" ];\n') + links.write('recv_ports_info_ifaces['+str(o)+'] = get_port_info_ifc('+str(o)+');\n') + # Find first and last router id of last stage where nodes attach + final_stage_rt_first_id = 0 + for i in range(num_stages): + final_stage_rt_first_id += options.uni_tree_fanout**i + print "final_stage_rt_first_id ", final_stage_rt_first_id + final_stage_rt_last_id = final_stage_rt_first_id * options.uni_tree_fanout + print "final_stage_rt_first_id ", final_stage_rt_last_id + + + num_final_stage_rts = (final_stage_rt_last_id+1) - final_stage_rt_first_id; + if(options.uni_tree_distribute_leaves): + for send_port_id in range(options.uni_tree_inputs): + o = final_stage_rt_first_id + get_uni_tree_distributed_rt(send_port_id, num_stages, options.uni_tree_fanout); + p = send_port_id/(options.uni_tree_fanout**num_stages) + links.write('send_ports_ifaces['+str(send_port_id)+'] = routers['+str(o)+'].in_ports['+str(p)+'];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(send_port_id)+' -> R'+str(o)+':'+str(p)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('N'+str(send_port_id+options.uni_tree_outputs)+' -> R'+str(o)+' [ headlabel = "' + str(p) + '" ];\n') + send_port_id += 1; + else: + send_port_id = 0; + for o in range(final_stage_rt_first_id, final_stage_rt_last_id+1): + for p in range(options.uni_tree_fanout): + if(send_port_id < options.uni_tree_inputs): # Stop once you've created enough input ports, even if the tree has more outputs + links.write('send_ports_ifaces['+str(send_port_id)+'] = routers['+str(o)+'].in_ports['+str(p)+'];\n') + if options.dump_topology_file: + topo_dump.write('SendPort '+str(send_port_id)+' -> R'+str(o)+':'+str(p)+'\n') + if options.gen_graph and options.graph_nodes: # also include the endpoints + dot.write('N'+str(send_port_id+options.uni_tree_outputs)+' -> R'+str(o)+' [ headlabel = "' + str(p) + '" ];\n') + send_port_id += 1; + + link_id = -1 + cur_rt = 0; + rts_in_stage = 1; + for stage in range(num_stages): + for r in range(rts_in_stage): + for l in range(options.uni_tree_fanout): + link_id += 1; + src_rt = options.uni_tree_fanout*cur_rt+l+1; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(src_rt)+'], 0, routers['+str(cur_rt)+'], '+str(l)+');\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(src_rt)+':'+str(0)+' -> '+'R'+str(cur_rt)+':'+str(l)+'\n') + if options.gen_graph: dot.write('R'+str(src_rt)+' -> R'+str(cur_rt)+' [ taillabel = "' + '0' + '", headlabel = "' + str(l) + '" ];\n') + cur_rt += 1; + rts_in_stage *= options.uni_tree_fanout; + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id+1 + + +def gen_uni_tree_routing(file_prefix, dump_routing_filename): + """Populates routing tables for uni-tree topology""" + global options, args + + # Dump routing file + if options.dump_routing_file: + try: route_dump = open(dump_routing_filename, 'w'); + except IOError: print "Could not open file " + dump_routing_filename; sys.exit(-1); + + num_root_nodes = 0; + num_leaf_nodes = 0; + + build_down_tree = True; + if (options.topology == "uni_tree_down"): + build_down_tree = True; + elif (options.topology == "uni_tree_up"): + build_down_tree = False; + elif (options.uni_tree_inputs < options.uni_tree_outputs): + build_down_tree = True; + else: + build_down_tree = False; + + #if(options.uni_tree_inputs < options.uni_tree_outputs): # Build down tree + if(build_down_tree): # Build down tree + num_root_nodes = options.uni_tree_inputs + num_leaf_nodes = options.uni_tree_outputs + num_stages = int(math.ceil(math.log(num_leaf_nodes, options.uni_tree_fanout))) - 1 # counts link stages + print "num_stages ",num_stages + + cur_rt = 0; + rts_in_stage = 1; + for stage in range(num_stages+1): + for r in range(rts_in_stage): + filename = options.output_dir + '/' + file_prefix + str(cur_rt) + '.hex' + try: rt = open(filename, 'w'); + except IOError: print "Could not open file " + filename; sys.exit(-1); + + for dst in range(options.uni_tree_outputs): + if(options.uni_tree_distribute_leaves): #distribute leaves + out_port = dst / ( options.uni_tree_fanout**(stage) ) % options.uni_tree_fanout + else: + out_port = dst / ( options.uni_tree_fanout**(num_stages-stage) ) % options.uni_tree_fanout + rt.write('%x\n' % out_port ); + if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+ str(out_port) + if options.dump_routing_file: route_dump.write('R'+str(cur_rt)+': '+str(dst)+' -> '+str(out_port)+'\n'); + cur_rt += 1; + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + rts_in_stage *= options.uni_tree_fanout; + else: # Build up tree + num_root_nodes = options.uni_tree_outputs + num_leaf_nodes = options.uni_tree_inputs + num_stages = int(math.ceil(math.log(num_leaf_nodes, options.uni_tree_fanout))) - 1 # counts link stages + print "num_stages ",num_stages + + cur_rt = 0; + rts_in_stage = 1; + for stage in range(num_stages+1): + for r in range(rts_in_stage): + filename = options.output_dir + '/' + file_prefix + str(cur_rt) + '.hex' + try: rt = open(filename, 'w'); + except IOError: print "Could not open file " + filename; sys.exit(-1); + + if(stage == 0): # root router + for dst in range(options.uni_tree_outputs): + rt.write('%x\n' % dst ); + if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+ str(dst) + if options.dump_routing_file: route_dump.write('R'+str(cur_rt)+': '+str(dst)+' -> '+str(dst)+'\n'); + else: + for dst in range(options.uni_tree_outputs): + rt.write('%x\n' % 0 ); + if options.verbose: print 'route:'+str(cur_rt)+'->'+str(dst)+':'+ str(0) + if options.dump_routing_file: route_dump.write('R'+str(cur_rt)+': '+str(dst)+' -> '+str(0)+'\n'); + + cur_rt += 1; + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + rts_in_stage *= options.uni_tree_fanout; + + # Hack - set num_routers to actual number of routers + # Find number of routers + actual_routers = 0 + for i in range(num_stages+1): + actual_routers += options.uni_tree_fanout**i + options.num_routers = actual_routers; + + # Close routing dump file + if options.dump_routing_file: route_dump.close(); + if options.verbose and options.dump_routing_file: print 'Dumped routing file: ' + dump_routing_filename + + +####################################### +## xbar +def gen_xbar_links(links, dot_filename, dump_topology_filename): + """Generates links for xbar topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "circo"); + + link_id = -1; + for r in range(options.num_routers): + link_id = link_id + 1; + next_router = (r+1)%options.num_routers; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(r)+'], 1, routers['+str(next_router)+'], 1);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(r)+':'+str(1)+' -> '+'R'+str(next_router)+':'+str(1)+'\n') + if options.gen_graph: dot.write('R'+str(r)+' -> R'+str(next_router)+' [ taillabel = "' + '1' + '", headlabel = "' + '1' + '" ];\n') + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id + +def gen_xbar_routing(file_prefix, dump_routing_filename): + """Populates routing tables for xbar topology""" + global options, args + + # Dump routing file + if options.dump_routing_file: + try: route_dump = open(dump_routing_filename, 'w'); + except IOError: print "Could not open file " + dump_routing_filename; sys.exit(-1); + + for src in range(options.num_routers): + filename = options.output_dir + '/' + file_prefix + str(src) + '.hex' + try: + rt = open(filename, 'w') + except IOError: + print "Could not open file " + filename + sys.exit(-1) + + for dst in range(options.num_routers): + if src == dst: # packet is destined to me, extract from router, i.e. out_port 0 + rt.write('%x\n' % (0) ); + #str.format( ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+'0' + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(0)+'\n'); + else: # packet is not for me, send to next router, i.e. out_port 1 + #next_router = (src+1)%options.num_routers; + rt.write('%x\n' % (1) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+'1' + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(1)+'\n'); + + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + + # Close routing dump file + if options.dump_routing_file: route_dump.close(); + if options.verbose and options.dump_routing_file: print 'Dumped routing file: ' + dump_routing_filename + + +####################################### +## Ideal +def gen_ideal_links(links, dot_filename, dump_topology_filename): + """Generates links for ideal topology""" + global options, args + + # Dump topology file + if options.dump_topology_file: + try: topo_dump = open(dump_topology_filename, 'w'); + except IOError: print "Could not open file " + dump_topology_filename; sys.exit(-1); + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "circo"); + + link_id = -1; + for r in range(options.num_routers): + link_id = link_id + 1; + next_router = (r+1)%options.num_routers; + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+str(r)+'], 1, routers['+str(next_router)+'], 1);\n') + if options.dump_topology_file: topo_dump.write('RouterLink '+'R'+str(r)+':'+str(1)+' -> '+'R'+str(next_router)+':'+str(1)+'\n') + if options.gen_graph: dot.write('R'+str(r)+' -> R'+str(next_router)+' [ taillabel = "' + '1' + '", headlabel = "' + '1' + '" ];\n') + + # Close topology dump file + if options.dump_topology_file: topo_dump.close(); + if options.verbose and options.dump_topology_file: print 'Dumped topology file: ' + dump_topology_filename + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id + +def gen_ideal_routing(file_prefix, dump_routing_filename): + """Populates routing tables for ideal topology""" + global options, args + + # Dump routing file + if options.dump_routing_file: + try: route_dump = open(dump_routing_filename, 'w'); + except IOError: print "Could not open file " + dump_routing_filename; sys.exit(-1); + + link_id = -1; + for src in range(options.num_routers): + filename = options.output_dir + '/' + file_prefix + str(src) + '.hex' + try: + rt = open(filename, 'w') + except IOError: + print "Could not open file " + filename + sys.exit(-1) + + for dst in range(options.num_routers): + if src == dst: # packet is destined to me, extract from router, i.e. out_port 0 + rt.write('%x\n' % (0) ); + #str.format( ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+'0' + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(0)+'\n'); + else: # packet is not for me, send to next router, i.e. out_port 1 + #next_router = (src+1)%options.num_routers; + rt.write('%x\n' % (1) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+'1' + if options.dump_routing_file: route_dump.write('R'+str(src)+': '+str(dst)+' -> '+str(1)+'\n'); + + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + + # Close routing dump file + if options.dump_routing_file: route_dump.close(); + if options.verbose and options.dump_routing_file: print 'Dumped routing file: ' + dump_routing_filename + + +############################################################ +## parse_custom_topology +def parse_custom_topology(custom_topology_file, send_ports, recv_ports, router_links, topology_info): + """Parses custom topology file""" + global options, args + reverse_router_links = dict() + try: c_topology = open(options.custom_topology, 'r'); + except IOError: print "Could not open custom topology file " + options.custom_topology; sys.exit(-1); + + for i, l in enumerate(c_topology): + m = re.match('\s*$', l) # only whitespace until end of likne, i.e. empty line + if(m is not None): # whitespace + # skip whitespace + continue + m = re.match('\s*#', l) # comment + if(m is not None): # comment + #print 'Skipping comment on line', i + continue + #m = re.match('SendPort\s+(\d+)\s*->\s*R(\d+)\s*:\s*(\d+)', l) + m = re.match('\s*SendPort\s+(?P\d+)\s*->\s*R(?P\d+)\s*:\s*(?P\d+)', l) + if( m is not None ): + send_port = m.group('send_port'); + rt = m.group('rt'); + port = m.group('port'); + #if options.verbose: print 'Attaching Send Port %s to R%s:%s' % (m.group(1), m.group(2), m.group(3)) + if options.verbose: print 'Attaching Send Port %s to R%s:%s' % (send_port, rt, port) + #send_ports[m.group(1)] = [ m.group(2), m.group(3) ] + send_ports[send_port] = [rt, port] + #if options.verbose: print 'Attaching Send Port ',m.group(1),' to R',m.group(2),':',m.group(3) + + # Update topology info + if(topology_info['num_routers'] < (int(rt)+1)): topology_info['num_routers'] = int(rt)+1; # update total number of routers + if(topology_info['max_num_in_ports'] < (int(port)+1)): topology_info['max_num_in_ports'] = int(port)+1; # update max number of input ports + if(topology_info['max_send_ports'] < (int(send_port)+1)): topology_info['max_send_ports'] = int(send_port)+1; # update max number of send ports + continue + #m = re.match('\s*RecvPort\s+(\d+)\s*->\s*R(\d+)\s*:\s*(\d+)', l) + m = re.match('\s*RecvPort\s+(?P\d+)\s*->\s*R(?P\d+)\s*:\s*(?P\d+)', l) + if( m is not None ): + recv_port = m.group('recv_port'); + rt = m.group('rt'); + port = m.group('port'); + #if options.verbose: print 'Attaching Recv Port %s to R%s:%s' % (m.group(1), m.group(2), m.group(3)) + if options.verbose: print 'Attaching Recv Port %s to R%s:%s' % (recv_port, rt, port) + #recv_ports[m.group(1)] = [ m.group(2), m.group(3) ] + recv_ports[recv_port] = [rt, port] + + # Update topology info + if(topology_info['num_routers'] < (int(rt)+1)): topology_info['num_routers'] = int(rt)+1; # update total number of routers + if(topology_info['max_num_out_ports'] < (int(port)+1)): topology_info['max_num_out_ports'] = int(port)+1; # update max number of input ports + if(topology_info['max_recv_ports'] < (int(recv_port)+1)): topology_info['max_recv_ports'] = int(recv_port)+1; # update max number of send ports + continue + m = re.match('\s*SendRecvPort\s+(?P\d+)\s*->\s*R(?P\d+)\s*:\s*(?P\d+)', l) + if( m is not None ): + user_port = m.group('user_port'); + rt = m.group('rt'); + port = m.group('port'); + #if options.verbose: print 'Attaching Send Port %s to R%s:%s' % (m.group(1), m.group(2), m.group(3)) + if options.verbose: print 'Attaching Send Port %s to R%s:%s' % (user_port, rt, port) + send_ports[user_port] = [rt, port] + if options.verbose: print 'Attaching Recv Port %s to R%s:%s' % (user_port, rt, port) + recv_ports[user_port] = [rt, port] + #send_ports[m.group(1)] = [ m.group(2), m.group(3) ] + #if options.verbose: print 'Attaching Send Port ',m.group(1),' to R',m.group(2),':',m.group(3) + + # Update topology info + if(topology_info['num_routers'] < (int(rt)+1)): topology_info['num_routers'] = int(rt)+1; # update total number of routers + if(topology_info['max_num_in_ports'] < (int(port)+1)): topology_info['max_num_in_ports'] = int(port)+1; # update max number of input ports + if(topology_info['max_send_ports'] < (int(user_port)+1)): topology_info['max_send_ports'] = int(user_port)+1; # update max number of send ports + if(topology_info['max_recv_ports'] < (int(user_port)+1)): topology_info['max_recv_ports'] = int(user_port)+1; # update max number of send ports + continue + m = re.match('\s*RouterLink\s+R(?P\d+)\s*:\s*(?P\d+)\s*->\s*R(?P\d+)\s*:\s*(?P\d+)', l) + if( m is not None ): + src_rt = m.group('src_rt'); + src_port = m.group('src_port'); + dst_rt = m.group('dst_rt'); + dst_port = m.group('dst_port'); + #if options.verbose: print 'Connecting R%s:%s to R%s:%s' % (m.group(1), m.group(2), m.group(3), m.group(4)) + if options.verbose: print 'Connecting R%s:%s to R%s:%s' % (src_rt, src_port, dst_rt, dst_port) + if(src_rt not in router_links): router_links[src_rt] = dict(); + # check if connection already exists + if(src_port in router_links[src_rt]): # Overwriting connections + exist_dest = router_links[src_rt][src_port] + #print 'Warning: R%s:%s was already connected to R%s:%s, but will now be connected to R%s:R%s' % (m.group(1), m.group(2), exist_dest[0], exist_dest[1], m.group(3), m.group(4)) + print 'Warning: R%s:%s was already connected to R%s:%s, but will now be connected to R%s:R%s' % (src_rt, src_port, exist_dest[0], exist_dest[1], dst_rt, dst_port) + + # Add link + #router_links[m.group(1)][m.group(2)] = [ m.group(3), m.group(4) ] + router_links[src_rt][src_port] = [ dst_rt, dst_port ] + + # Update topology info + if(topology_info['num_routers'] < (int(src_rt)+1)): topology_info['num_routers'] = int(src_rt)+1; # update total number of routers + if(topology_info['num_routers'] < (int(dst_rt)+1)): topology_info['num_routers'] = int(dst_rt)+1; # update total number of routers + if(topology_info['max_num_out_ports'] < (int(src_port)+1)): topology_info['max_num_out_ports'] = int(src_port)+1; # update max number of input ports + if(topology_info['max_num_in_ports'] < (int(dst_port)+1)): topology_info['max_num_in_ports'] = int(dst_port)+1; # update max number of input ports + + # For sanity check + if(dst_rt not in reverse_router_links): reverse_router_links[dst_rt] = dict(); + reverse_router_links[dst_rt][dst_port] = [ src_rt, src_port ] + + continue + print 'Error parsing custom_topology_file (%s) at line %d: "%s"' % (custom_topology_file, i, l[:-1]) + sys.exit(-1); + + # Sanity checks + for r in range(topology_info['num_routers']): + if( ( str(r) not in router_links ) and ( str(r) not in reverse_router_links ) ): # A router that is unconnected + print 'Error: Missing topology info for router %d. Router IDs must be consecutive.' % (r) + sys.exit(-1); + + for s in range(topology_info['max_send_ports']): + if( str(s) not in send_ports ): # A non-existent send port + print 'Error: Missing topology info for send port %d. Send port IDs must be consecutive.' % (s) + sys.exit(-1); + + for r in range(topology_info['max_recv_ports']): + if( str(r) not in recv_ports ): # A non-existent recv port + print 'Error: Missing topology info for recv port %d. Recv port IDs must be consecutive.' % (r) + sys.exit(-1); + + if(int(topology_info['max_send_ports']) < 1): + print 'Error: No send ports! A network requires at least one send port.' + sys.exit(-1); + + if(int(topology_info['max_recv_ports']) < 1): + print 'Error: No receive ports! A network requires at least one receive port.' + sys.exit(-1); + + if options.verbose: print 'Total number of routers:', topology_info['num_routers'] + if options.verbose: print 'Max number of in ports:', topology_info['max_num_in_ports'] + if options.verbose: print 'Max number of out ports:', topology_info['max_num_out_ports'] + if options.verbose: print 'Max number of send ports:', topology_info['max_send_ports'] + if options.verbose: print 'Max number of recv ports:', topology_info['max_recv_ports'] + + + +############################################################ +## parse_custom_topology +def parse_custom_routing(custom_routing_file, topology_info): + """Parses custom routing file""" + global options, args + try: c_routing = open(custom_routing_file, 'r'); + except IOError: print "Could not open custom routing file " + options.custom_routing; sys.exit(-1); + + # Initialize routing tables + # routing = int(topology_info['num_routers']) * [int(topology_info['max_dests']) * [-1] ] # This does not work! Routing entries are aliases and overwrite each other + routing = [] + for r in range(int(topology_info['num_routers'])): + routing.insert(r, int(topology_info['max_dests']) * [-1] ) + + for i, l in enumerate(c_routing): + m = re.match('\s*$', l) # only whitespace until end of likne, i.e. empty line + if(m is not None): # whitespace + # skip whitespace + continue + m = re.match('\s*#', l) # comment + if(m is not None): # comment + #print 'Skipping comment on line', i + continue + #m = re.match('SendPort\s+(\d+)\s*->\s*R(\d+)\s*:\s*(\d+)', l) + m = re.match('\s*R(?P\d+)\s*:\s*(?P\d+)\s*->\s*(?P\d+)', l) + if( m is not None ): + rt = m.group('rt'); + dst = m.group('dst'); + port = m.group('port'); + if(int(rt) >= topology_info['num_routers']): print 'Routing entry for non-existent router %s at line %d: "%s"' % (rt, i, l[:-1]); sys.exit(-1) + if(int(dst) >= topology_info['max_dests']): print 'Routing entry for router %s has non-existent destination (%s) at line %d: "%s"' % (rt, dst, i, l[:-1]); sys.exit(-1) + if(int(port) >= topology_info['max_num_out_ports']): print 'Routing entry for router %s has non-existent out port (%s) at line %d: "%s"' % (rt, port, i, l[:-1]); sys.exit(-1) + + if( routing[int(rt)][int(dst)] != -1 ): print 'Warning: Overwriting previous routing entry (R%s:%s->%d) with new routing entry (R%s:%s->%s)' % ( rt, dst, routing[int(rt)][int(dst)], rt, dst, port) + #if options.verbose: print 'Attaching Send Port %s to R%s:%s' % (m.group(1), m.group(2), m.group(3)) + if options.verbose: print 'New routing entry for router %s: dst:%s -> out_port:%s' % (rt, dst, port) + routing[int(rt)][int(dst)] = int(port) + + continue + print 'Error parsing routing_topology_file (%s) at line %d: "%s"' % (routing_topology_file, i, l[:-1]) + sys.exit(-1); + + # Sanity check + for r in range(len(routing)): + for dst in range(len(routing[r])): + if(routing[r][dst] == -1): + print 'Warning: Router %d has undefined output port for packets with destination %d. Will use default output port (0).' % (r, dst) + routing[r][dst] = 0 + + return routing + +####################################### +## Custom +def gen_custom_links(send_ports, recv_ports, router_links, topology_info, links, dot_filename): + """Generates links for custom topology""" + global options, args + + # Generate graphviz .gv file + if options.gen_graph: dot = prepare_graph_file(dot_filename + ".gv", "circo", topology_info); + +# Expose user send/receive and info ports + for s, rp in send_ports.items(): + links.write('send_ports_ifaces['+s+'] = routers['+rp[0]+'].in_ports['+rp[1]+'];\n') + if options.graph_nodes: dot.write('N'+s+' -> R'+rp[0]+' [ headlabel = "' + rp[1] + '" ];\n') + for r, rp in recv_ports.items(): + links.write('recv_ports_ifaces['+r+'] = routers['+rp[0]+'].out_ports['+rp[1]+'];\n') + if options.graph_nodes: dot.write('R'+rp[0]+' -> N'+r+' [ taillabel = "' + rp[1] + '" ];\n') + links.write('recv_ports_info_ifaces['+r+'] = get_port_info_ifc('+r+');\n') + #for r in range(max(topology_info['max_send_ports'], topology_info['max_recv_ports'])): + #for r in range(options.num_routers): + # links.write('router_info_ifaces['+str(r)+'] = get_router_info_ifc('+str(r)+');\n') + + link_id = 0; + for src_rt in router_links.keys(): + for src_port in router_links[src_rt].keys(): + tmp = router_links[src_rt][src_port] + dst_rt = tmp[0] + dst_port = tmp[1] + links.write('links['+str(link_id)+'] <- mkConnectPorts(routers['+src_rt+'], '+src_port+', routers['+dst_rt+'], '+dst_port+');\n') + if options.gen_graph: dot.write('R'+src_rt+' -> R'+dst_rt+' [ taillabel = "' + src_port + '", headlabel = "' + dst_port + '" ];\n') + link_id = link_id + 1; + + # Close graphviz file + if options.gen_graph: dot.write('}\n'); dot.close(); + if options.verbose and options.gen_graph: print 'Generated graphviz file: ' + dot_filename + ".gv" + + return link_id + +def gen_custom_routing(routing, topology_info, file_prefix): + """Populates routing tables for custom topology""" + global options, args + for src in range(options.num_routers): + filename = options.output_dir + '/' + file_prefix + str(src) + '.hex' + try: rt = open(filename, 'w'); + except IOError: print "Could not open file " + filename; sys.exit(-1); + + for dst in range(int(topology_info['max_dests'])): + out_port = routing[src][dst] + rt.write('%x\n' % (out_port) ); + if options.verbose: print 'route:'+str(src)+'->'+str(dst)+':'+str(out_port) + + rt.close(); + if options.verbose: print 'Generated routing file: ' + filename + + + +############################################################ +## gen_net_parameters +def gen_net_parameters(num_user_send_ports, num_user_recv_ports, num_in_ports, num_out_ports, num_links, cut, filename = 'network_parameters.bsv'): + """Generates network parameters file""" + global options, args + filename = options.output_dir + '/' + filename + try: + parameters = open(filename, 'w') + except IOError: + print "Could not open file " + filename + sys.exit(-1) + + #parameters.write('`define NUM_TOTAL_USER_PORTS ' + str(num_total_user_ports) + '\n') + parameters.write('`define NUM_USER_SEND_PORTS ' + str(num_user_send_ports) + '\n') + parameters.write('`define NUM_USER_RECV_PORTS ' + str(num_user_recv_ports) + '\n') + parameters.write('`define NUM_ROUTERS ' + str(options.num_routers) + '\n') + parameters.write('`define NUM_IN_PORTS ' + str(num_in_ports) + '\n') + parameters.write('`define NUM_OUT_PORTS ' + str(num_out_ports) + '\n') + parameters.write('`define CREDIT_DELAY 1\n') + parameters.write('`define NUM_VCS ' + str(options.num_vcs) + '\n') + parameters.write('`define ALLOC_TYPE ' + str(options.alloc_type) + '\n') + parameters.write('`define USE_VIRTUAL_LINKS ' + str(options.use_virtual_links) + '\n') + parameters.write('`define FLIT_BUFFER_DEPTH ' + str(options.flit_buffer_depth) + '\n') + parameters.write('`define FLIT_DATA_WIDTH ' + str(options.flit_data_width) + '\n') + parameters.write('`define NUM_LINKS ' + str(num_links) + '\n') + parameters.write('`define NETWORK_CUT ' + str(cut) + '\n') + parameters.write('`define XBAR_LANES ' + str(options.xbar_lanes) + '\n') + if (options.router_type == "voq"): + parameters.write('`define USE_VOQ_ROUTER True\n') + elif (options.router_type == "iq"): + parameters.write('`define USE_IQ_ROUTER True\n') + if(options.dbg): + parameters.write('`define EN_DBG True\n') + if(options.dbg_detail): + parameters.write('`define EN_DBG True\n') + parameters.write('`define EN_DBG_DETAIL True\n') + + if(options.pipeline_core): + parameters.write('`define PIPELINE_CORE True\n') + else: + parameters.write('`define PIPELINE_CORE False\n') + if(options.pipeline_alloc): + parameters.write('`define PIPELINE_ALLOCATOR True\n') + else: + parameters.write('`define PIPELINE_ALLOCATOR False\n') + if(options.pipeline_links): + parameters.write('`define PIPELINE_LINKS True\n') + else: + parameters.write('`define PIPELINE_LINKS False\n') + + if options.verbose: print 'Generated parameters file: ' + filename + +############################################################ +## main +def main (): + # Default values for parameters + global options, args + #if (len(sys.argv) < 3): + # print "Error at least 2 args expected!"; + # exit(); + #for arg in sys.argv: + # print arg; + + if options.verbose: + print '================ Options ================' + options_dict = vars(options) + for o in options_dict: + print o,':',options_dict[o] + + #num_total_user_ports = options.num_routers + num_user_send_ports = options.num_routers + num_user_recv_ports = options.num_routers + max_num_in_ports = -1 + max_num_out_ports = -1 + num_links = -1 + + # Generated Files + network_parameters_file = '' + network_links_file = '' + network_routing_file_prefix = '' + + #### Derived options #### + if (options.voq_routers): + options.router_type = "voq"; + if (options.peek_flow_control): + options.flow_control_type = "peek"; + # Graph_nodes implies gen_graph + if (options.graph_nodes): + options.gen_graph = True; + + #### Global Checks for all topologies #### + if (options.router_type == "voq"): + if (not (options.flow_control_type == "peek")): + print 'Warning: VOQ routers require the use of "peek" flow control. Setting flow control to "peek".' + options.flow_control_type = True; + if (options.num_vcs > 1): + print 'Warning: VOQ routers do not support multiple Virtual Channels (VCs). Setting num_vcs to 1.' + options.num_vcs = 1; + + else: # VC-based routers + if (options.num_vcs == 1): + print 'Warning: VC-based routers require at least two Virtual Channels (VCs). Setting num_vcs to 2.' + options.num_vcs = 2; + + # Prefix for generated files (some topologies might add more fields to this - custom overrides this) + file_prefix = ''; + if(options.file_prefix == ''): + file_prefix = options.topology + '_' + str(options.num_routers) + 'RTs_' + str(options.num_vcs) + 'VCs_' + str(options.flit_buffer_depth) + 'BD_' + str(options.flit_data_width) + 'DW_' + str(options.alloc_type) + 'Alloc' + else: + file_prefix = options.file_prefix; + + #### single switch #### + if options.topology == 'single_switch': + # Set topology-specific parameters here + max_num_in_ports = options.num_routers + max_num_out_ports = options.num_routers + + #### line #### + elif options.topology == 'line': + # Set topology-specific parameters here + max_num_in_ports = 3 + max_num_out_ports = 3 + + #### ring #### + elif options.topology == 'ring': + # Set topology-specific parameters here + max_num_in_ports = 2 + max_num_out_ports = 2 + + elif options.topology == 'ideal': + max_num_in_ports = 2 + max_num_out_ports = 2 + + elif options.topology == 'xbar': + max_num_in_ports = 2 + max_num_out_ports = 2 + + #### double-ring #### + elif options.topology == 'double_ring': + # Set topology-specific parameters here + max_num_in_ports = 3 + max_num_out_ports = 3 + + #### star #### + elif options.topology == 'star': + # Check if star parameters are valid + if(options.num_routers > 16): + print 'Error:',options.topology, 'topology only supports up to 16 routers.' + sys.exit(1) + + num_user_send_ports = options.num_routers-1 + num_user_recv_ports = options.num_routers-1 + + # Set topology-specific parameters here + max_num_in_ports = options.num_routers-1 # central node is connected to num_routers-1 other routers, plus local port + max_num_out_ports = options.num_routers-1 # central node is connected to num_routers-1 other routers, plus local port + + #### mesh #### + elif options.topology == 'mesh': + # Check if mesh parameters are valid + # if num_routers is perfect square and routers_per_row, routers_per_column were not specified, set them here. + num_routers_sqrt = (int)( math.floor(math.sqrt(options.num_routers)) ) + num_routers_is_square = (options.num_routers == num_routers_sqrt**2) + if(num_routers_is_square and options.routers_per_row == -1 and options.routers_per_column == -1): + if options.verbose: print 'num_routers(%d) is perfect square; setting options.routers_per_row and options.routers_per_column to sqrt(num_routers) to build square mesh.' % (options.num_routers) + options.routers_per_row = num_routers_sqrt + options.routers_per_column = num_routers_sqrt + + if(options.routers_per_row * options.routers_per_column != options.num_routers): + print 'Error:',options.topology, 'topology requires that routers_per_row(%d) and routers_per_column(%d) are specified and that their product is equal to num_routers(%d).' % (options.routers_per_row, options.routers_per_column, options.num_routers) + sys.exit(1) + + # Set topology-specific parameters here + if(options.expose_unused_ports): + num_total_user_ports = options.num_routers + 2*options.routers_per_row + 2*options.routers_per_column; + num_user_send_ports = num_total_user_ports + num_user_recv_ports = num_total_user_ports + max_num_in_ports = 5 + max_num_out_ports = 5 + # Augment default prefix to include routers per row/column + if(options.file_prefix == ''): + file_prefix = file_prefix + '_' + str(options.routers_per_row) + 'RTsPerRow_' + str(options.routers_per_column) + 'RTsPerCol' + + + #### torus #### + elif options.topology == 'torus': + # Check if torus parameters are valid + # if num_routers is perfect square and routers_per_row, routers_per_column were not specified, set them here. + num_routers_sqrt = (int)( math.floor(math.sqrt(options.num_routers)) ) + num_routers_is_square = (options.num_routers == num_routers_sqrt**2) + if(num_routers_is_square and options.routers_per_row == -1 and options.routers_per_column == -1): + if options.verbose: print 'num_routers(%d) is perfect square; setting options.routers_per_row and options.routers_per_column to sqrt(num_routers) to build square torus.' % (options.num_routers) + options.routers_per_row = num_routers_sqrt + options.routers_per_column = num_routers_sqrt + + if(options.routers_per_row * options.routers_per_column != options.num_routers): + print 'Error:',options.topology, 'topology requires that routers_per_row(%d) and routers_per_column(%d) are specified and that their product is equal to num_routers(%d).' % (options.routers_per_row, options.routers_per_column, options.num_routers) + sys.exit(1) + + # Set topology-specific parameters here + max_num_in_ports = 5 + max_num_out_ports = 5 + # Augment default prefix to include routers per row/column + if(options.file_prefix == ''): + file_prefix = file_prefix + '_' + str(options.routers_per_row) + 'RTsPerRow_' + str(options.routers_per_column) + 'RTsPerCol' + + + #### fully-connected #### + elif options.topology == 'fully_connected': + # Check if fully-connected parameters are valid + if(options.num_routers > 16): + print 'Error:',options.topology, 'topology only supports up to 16 routers.' + sys.exit(1) + + # Set topology-specific parameters here + max_num_in_ports = options.num_routers # central node is connected to num_routers-1 other routers, plus local port + max_num_out_ports = options.num_routers # central node is connected to num_routers-1 other routers, plus local port + + #### fat tree #### + elif options.topology == 'fat_tree': + # Check if fat tree parameters are valid + num_is_power_of_two = options.num_routers != 0 and ((options.num_routers & (options.num_routers - 1)) == 0) + num_routers_sqrt = (int)( math.floor(math.sqrt(options.num_routers)) ) + num_routers_is_square = (options.num_routers == num_routers_sqrt**2) + if(not num_is_power_of_two): + print 'Error:',options.topology, 'topology requires that num_routers is a power of two.' + sys.exit(1) + + # Set topology-specific parameters here + max_num_in_ports = 4 # only fat tree based on 4x4 routers supported for now + max_num_out_ports = 4 # only fat tree based on 4x4 routers supported for now + + #### butterfly #### + elif options.topology == 'butterfly': + # Check if butterfly parameters are valid + num_is_power_of_two = options.num_routers != 0 and ((options.num_routers & (options.num_routers - 1)) == 0) + num_routers_sqrt = (int)( math.floor(math.sqrt(options.num_routers)) ) + num_routers_is_square = (options.num_routers == num_routers_sqrt**2) + if(not num_is_power_of_two): + print 'Error:',options.topology, 'topology requires that num_routers is a power of two.' + sys.exit(1) + + # Set topology-specific parameters here + max_num_in_ports = 2 # only 2-ary butterfly topology based on 2x2 routers supported for now + max_num_out_ports = 2 # only 2-ary butterfly topology based on 2x2 routers supported for now + + #### single switch #### + elif options.topology == 'uni_single_switch': + # Set topology-specific parameters here + max_num_in_ports = options.send_endpoints; + max_num_out_ports = options.recv_endpoints; + num_user_send_ports = options.uni_tree_inputs + num_user_recv_ports = options.uni_tree_outputs + + #### aggregation uni-directional tree #### + elif options.topology == 'uni_tree_up': + # Check if fat tree parameters are valid + + num_leaf_nodes = options.uni_tree_inputs; + if(num_leaf_nodes > 512): + print 'Error',options.topology, 'topology only supports up to 512 leaf nodes.' + sys.exit(1) + + if(options.uni_tree_fanout < 2): #automatically set fanout, default fan_out is 4 + if(num_leaf_nodes <= 4): + options.uni_tree_fanout = num_leaf_nodes + elif(num_leaf_nodes <= 16): + options.uni_tree_fanout = int(math.ceil(math.pow(num_leaf_nodes, 1.0/2.0))); + elif(num_leaf_nodes <= 256): + options.uni_tree_fanout = int(math.ceil(math.pow(num_leaf_nodes, 1.0/3.0))); + print 'Warning',options.topology, 'topology requires that uni_tree_fanout is at least two. Setting uni_tree_fanout to ', options.uni_tree_fanout + + # corner-case for very small uni_tree + if(options.uni_tree_inputs < options.uni_tree_fanout and options.uni_tree_outputs < options.uni_tree_fanout): + max_in_out = max(options.uni_tree_inputs, options.uni_tree_outputs); + print "Warning: uni_tree topology requires that uni_tree_fanout is not larger than both uni_tree_inputs and uni_tree_outpus.\n Setting uni_tree_fanout to (",max_in_out,")." + options.uni_tree_fanout = max_in_out; + + # Override file_prefix + if(options.file_prefix == ''): + file_prefix = options.topology + '_' + str(options.uni_tree_inputs) + 'INs_' + str(options.uni_tree_outputs) + 'OUTs_' + str(options.uni_tree_fanout) + 'FANOUT_' + str(options.num_vcs) + 'VCs_' + str(options.flit_buffer_depth) + 'BD_' + str(options.flit_data_width) + 'DW_' + str(options.alloc_type) + 'Alloc' + # Set topology-specific parameters here + num_user_send_ports = options.uni_tree_inputs + num_user_recv_ports = options.uni_tree_outputs + max_num_in_ports = options.uni_tree_fanout + max_num_out_ports = options.uni_tree_outputs + +# if(options.uni_tree_inputs < options.uni_tree_outputs): # Build down tree +# print 'Error',options.topology, 'topology requires that uni_tree_inputs >= uni_tree_outputs.' +# sys.exit(1) + + #### distribution uni-directional tree #### + elif options.topology == 'uni_tree_down': + # Check if fat tree parameters are valid + + num_leaf_nodes = options.uni_tree_inputs; + if(num_leaf_nodes > 512): + print 'Error',options.topology, 'topology only supports up to 512 leaf nodes.' + sys.exit(1) + + if(options.uni_tree_fanout < 2): #automatically set fanout, default fan_out is 4 + if(num_leaf_nodes <= 4): + options.uni_tree_fanout = num_leaf_nodes + elif(num_leaf_nodes <= 16): + options.uni_tree_fanout = int(math.ceil(math.pow(num_leaf_nodes, 1.0/2.0))); + elif(num_leaf_nodes <= 256): + options.uni_tree_fanout = int(math.ceil(math.pow(num_leaf_nodes, 1.0/3.0))); + print 'Warning',options.topology, 'topology requires that uni_tree_fanout is at least two. Setting uni_tree_fanout to ', options.uni_tree_fanout + + # corner-case for very small uni_tree + if(options.uni_tree_inputs < options.uni_tree_fanout and options.uni_tree_outputs < options.uni_tree_fanout): + max_in_out = max(options.uni_tree_inputs, options.uni_tree_outputs); + print "Warning: uni_tree topology requires that uni_tree_fanout is not larger than both uni_tree_inputs and uni_tree_outpus.\n Setting uni_tree_fanout to (",max_in_out,")." + options.uni_tree_fanout = max_in_out; + + # Override file_prefix + if(options.file_prefix == ''): + file_prefix = options.topology + '_' + str(options.uni_tree_inputs) + 'INs_' + str(options.uni_tree_outputs) + 'OUTs_' + str(options.uni_tree_fanout) + 'FANOUT_' + str(options.num_vcs) + 'VCs_' + str(options.flit_buffer_depth) + 'BD_' + str(options.flit_data_width) + 'DW_' + str(options.alloc_type) + 'Alloc' + # Set topology-specific parameters here + num_user_send_ports = options.uni_tree_inputs + num_user_recv_ports = options.uni_tree_outputs + max_num_in_ports = options.uni_tree_inputs + max_num_out_ports = options.uni_tree_fanout + +# if(options.uni_tree_inputs > options.uni_tree_outputs): # Build down tree +# print 'Error',options.topology, 'topology requires that uni_tree_inputs <= uni_tree_outputs.' +# sys.exit(1) + + #### uni-directional tree #### + elif options.topology == 'uni_tree': + # Check if fat tree parameters are valid + #if(not num_is_power_of_two): + # print 'Error:',options.topology, 'topology requires that num_routers is a power of two.' + # sys.exit(1) + + num_leaf_nodes = max(options.uni_tree_inputs, options.uni_tree_outputs); + if(num_leaf_nodes > 512): + print 'Error',options.topology, 'topology only supports up to 512 leaf nodes.' + sys.exit(1) + + if(options.uni_tree_fanout < 2): + if(num_leaf_nodes <= 8): + options.uni_tree_fanout = num_leaf_nodes + elif(num_leaf_nodes <= 64): + options.uni_tree_fanout = int(math.ceil(math.pow(num_leaf_nodes, 1.0/2.0))); + elif(num_leaf_nodes <= 512): + options.uni_tree_fanout = int(math.ceil(math.pow(num_leaf_nodes, 1.0/3.0))); + print 'Warning',options.topology, 'topology requires that uni_tree_fanout is at least two. Setting uni_tree_fanout to ', options.uni_tree_fanout + + # corner-case for very small uni_tree + if(options.uni_tree_inputs < options.uni_tree_fanout and options.uni_tree_outputs < options.uni_tree_fanout): + max_in_out = max(options.uni_tree_inputs, options.uni_tree_outputs); + print "Warning: uni_tree topology requires that uni_tree_fanout is not larger than both uni_tree_inputs and uni_tree_outpus.\n Setting uni_tree_fanout to (",max_in_out,")." + options.uni_tree_fanout = max_in_out; + + # Override file_prefix + if(options.file_prefix == ''): + file_prefix = options.topology + '_' + str(options.uni_tree_inputs) + 'INs_' + str(options.uni_tree_outputs) + 'OUTs_' + str(options.uni_tree_fanout) + 'FANOUT_' + str(options.num_vcs) + 'VCs_' + str(options.flit_buffer_depth) + 'BD_' + str(options.flit_data_width) + 'DW_' + str(options.alloc_type) + 'Alloc' + # Set topology-specific parameters here + num_user_send_ports = options.uni_tree_inputs + num_user_recv_ports = options.uni_tree_outputs + if(options.uni_tree_inputs < options.uni_tree_outputs): # Build down tree + max_num_in_ports = options.uni_tree_inputs + max_num_out_ports = options.uni_tree_fanout + #if(options.uni_tree_inputs < options.uni_tree_fanout): # corner-case for very small uni_tree + # print "WARNING: uni_tree topology requires that uni_tree_fanout is >= MIN(uni_tree_inputs, uni_tree_outpus).i + # \ Setting uni_tree_fanout to uni_tree_inputs (",options.uni_tree_inputs,")." + else: + max_num_in_ports = options.uni_tree_fanout + max_num_out_ports = options.uni_tree_outputs + + + #### Custom #### + elif options.topology == 'custom': + # Check if custom parameters are valid + if(options.custom_topology == "" or options.custom_routing == ""): + print "You must specify a custom topology and custom routing file using the --custom_topology and --custom_routing command-line options!"; sys.exit(-1); + + try: c_topology = open(options.custom_topology, 'r'); + except IOError: print "Could not open custom topology file " + options.custom_topology; sys.exit(-1); + try: c_routing = open(options.custom_routing, 'r'); + except IOError: print "Could not open custom routing file " + options.custom_routing; sys.exit(-1); + + # Generate a hash based on the custom topology and routing files + md5gen = hashlib.md5() + for l in c_topology: + md5gen.update(l); + for l in c_routing: + md5gen.update(l); + hash = md5gen.hexdigest(); + c_topology.close() + c_routing.close() + #print 'md5sum is :', hash + #sys.exit(-1); + + if(options.file_prefix == ''): + file_prefix = options.topology + hash + '_' + str(options.num_routers) + 'RTs_' + str(options.num_vcs) + 'VCs_' + str(options.flit_buffer_depth) + 'BD_' + str(options.flit_data_width) + 'DW_' + str(options.alloc_type) + 'Alloc' + + # Parse custom topology and routing files - might change options.num_routers + send_ports = dict(); recv_ports = dict(); router_links = dict(); # will get populated by parse_custom_topology + topology_info = {'num_routers':0, 'max_num_in_ports':0, 'max_num_out_ports':0, 'max_send_ports':0, 'max_recv_ports':0} + parse_custom_topology(options.custom_topology, send_ports, recv_ports, router_links, topology_info) + + # Set topology-specific parameters here + options.num_routers = topology_info['num_routers'] + max_num_in_ports = topology_info['max_num_in_ports'] + max_num_out_ports = topology_info['max_num_out_ports'] + num_user_send_ports = topology_info['max_send_ports'] + num_user_recv_ports = topology_info['max_recv_ports'] + #num_total_user_ports = max(topology_info['max_send_ports'], topology_info['max_recv_ports']) + #if options.verbose: print 'Total number of User ports (max of send/receive ports): %d' % (num_total_user_ports) + #if options.verbose: print 'Custom Topology Info: ', topology_info +# if options.verbose: print 'Custom topology info\n Number of routers: %d\n Max input ports per router: %d\n Max output ports per router: %d\n Number of user send ports: %d\n Number of user receive ports: %d\n' % (num_total_user_ports) + + topology_info['max_dests'] = topology_info['max_recv_ports'] + + routing = parse_custom_routing(options.custom_routing, topology_info) + + #sys.exit(-1); + + + #### unknown topology #### + else: + print 'Unknown topology', options.topology + sys.exit(1) + + # Check if other options are valid + if(options.expose_unused_ports and options.topology != 'mesh'): + print 'Warning: Ignoring option --expose_unused_ports, which is only supported for mesh topology' + #sys.exit(1) + + + # Generate configuration files + # Set configuration file names + network_parameters_file = file_prefix+'_parameters.bsv' + network_links_file = file_prefix+'_links.bsv' + network_routing_file_prefix = file_prefix+'_routing_' + + if options.verbose: print '\n================ Generating ' + options.topology + ' network ================' + generate_links_function = 'gen_'+options.topology+'_links' + generate_routing_function = 'gen_'+options.topology+'_routing' + + # Open links file + network_links_filename = options.output_dir + '/' + network_links_file + try: links = open(network_links_filename, 'w'); + except IOError: print "Could not open file " + network_links_filename; sys.exit(-1); + dot_filename = network_links_filename + dump_topology_filename = file_prefix+'.topology' + dump_routing_filename = file_prefix+'.routing' + + if(options.topology != "custom"): + num_links = eval(generate_links_function)(links, dot_filename, dump_topology_filename) + eval(generate_routing_function)(network_routing_file_prefix, dump_routing_filename) + else: + num_links = gen_custom_links(send_ports, recv_ports, router_links, topology_info, links, dot_filename); + gen_custom_routing(routing, topology_info, network_routing_file_prefix); + + links.close(); # close links file + if options.verbose: print 'Generated links file: ' + network_links_filename + + gen_net_parameters(num_user_send_ports, num_user_recv_ports, max_num_in_ports, max_num_out_ports, num_links, options.cut, network_parameters_file) + print 'Generated ' + options.topology + ' network configuration succesfully.' + + # Generate visulization of network graph + if options.gen_graph: + if (options.graph_layout == "invalid"): # if user or topology hasn't set this + options.graph_layout = "circo"; + command = 'dot -T'+options.graph_format + ' -K' + options.graph_layout + ' ' + options.output_dir + '/' + file_prefix+'_links.bsv.gv -o ' + options.output_dir + '/' + file_prefix+'.'+options.graph_format + os.system(command) + if options.verbose: print 'Generated network graph visuzalization file: ' + file_prefix+'.'+options.graph_format + + # Generate RTL and synthesize + if(options.gen_rtl): + xtra_flags = "" + if options.topology == 'ideal': + xtra_flags = "-D IDEAL=1 " + if options.topology == 'xbar': + xtra_flags = "-D XBAR=1 -D XBAR_LANES="+str(options.xbar_lanes) + " " + + user_flags = 'USER_FLAGS=\'' + xtra_flags + '-D NETWORK_PARAMETERS_FILE="\\"' + network_parameters_file + '"\\" -D NETWORK_LINKS_FILE="\\"' + network_links_file + '"\\" -D NETWORK_ROUTING_FILE_PREFIX="\\"' + network_routing_file_prefix +'"\\"\'' + command = 'make net ' + user_flags + if (options.flow_control_type == "peek"): + command = 'make net_simple ' + user_flags + + print 'Compiling Bluespec to Verilog' + if options.verbose: print 'Executing command: ' + command + os.system(command); + + if(options.run_xst): + user_flags = 'USER_FLAGS=\'-D NETWORK_PARAMETERS_FILE="\\"' + network_parameters_file + '"\\" -D NETWORK_LINKS_FILE="\\"' + network_links_file + '"\\" -D NETWORK_ROUTING_FILE_PREFIX="\\"' + network_routing_file_prefix +'"\\"\'' + command = 'make net_xst ' + user_flags + + if (options.flow_control_type == "peek"): + command = 'make net_simple_xst ' + user_flags + + print 'Compiling Bluespec to Verilog and running Xilinx XST for synthesis' + if options.verbose: print 'Executing command: ' + command + os.system(command); + + + if(options.run_dc): + user_flags = 'USER_FLAGS=\'-D NETWORK_PARAMETERS_FILE="\\"' + network_parameters_file + '"\\" -D NETWORK_LINKS_FILE="\\"' + network_links_file + '"\\" -D NETWORK_ROUTING_FILE_PREFIX="\\"' + network_routing_file_prefix +'"\\"\'' + command = 'make net_dc ' + user_flags + + if (options.flow_control_type == "peek"): + command = 'make net_simple_dc ' + user_flags + + print 'Compiling Bluespec to Verilog and running Synopsys DC for synthesis' + if options.verbose: print 'Executing command: ' + command + os.system(command); + + + if(options.sendmail != ''): + #command = 'echo "\n~H From:CONECT \n\nBody of message" | mail -s "CONECT subject" '+options.sendmail + #command = 'echo "Body of message" | mail -s "CONECT subject" -a "From: CONECT " '+options.sendmail + #command = 'echo "Body of message" | mail -r "CONECT" -R "papamix@cs.cmu.edu" -s "CONECT subject" '+options.sendmail + command = 'echo "Body of message" | mail -r "CONECT" -s "CONECT subject" -S replyto=papamix@cs.cmu.edu '+options.sendmail + #command = 'echo "Body of message" | mail -r "CONECT" -s "CONECT subject" -S from="CONECT " '+options.sendmail + #command = 'echo "Body of message" | mail -r "CONECT" -s "CONECT subject" '+options.sendmail+' -- -f papamix@cs.cmu.edu' + os.system(command); + + +if __name__ == '__main__': + try: + start_time = time.time() + #terminal_columns = os.popen('stty size', 'r').read().split()[1]; # hack to get terminal columns if not available from 'COLUMNS' environment variable + #parser = optparse.OptionParser(formatter=optparse.TitledHelpFormatter( width = int( os.environ.get('COLUMNS', terminal_columns) ) ), usage=globals()['__doc__'], version='0.6') + parser = optparse.OptionParser(formatter=optparse.TitledHelpFormatter(), usage=globals()['__doc__'], version='0.6') + #parser = optparse.OptionParser(formatter=optparse.IndentedHelpFormatter( width = int( os.environ.get('COLUMNS', terminal_columns) ) ), usage=globals()['__doc__'], version='0.4') + parser.add_option ('--verbose', action='store_true', default=False, help='verbose output'); + parser.add_option ('-t', '--topology', action='store', type="string", default='ring', + help='specifies topology (can take values "single_switch", "line", "ring", "double_ring", "star", "mesh", "torus", "fat_tree", "butterfly", "fully_connected", "uni_single_switch", "uni_tree", uni_tree_up", "uni_tree_down", "custom", "ideal", "xbar")'); + parser.add_option ('--sendmail', action='store', type="string", default='', help='Send email notification when done') + parser.add_option ('-n', '--num_routers', action='store', type="int", default=4, help='Specifies number of endpoint routers'); + parser.add_option ('--send_endpoints', action='store', type="int", default=4, help='Specifies number of send endpoints for uni-directional topologies'); + parser.add_option ('--recv_endpoints', action='store', type="int", default=4, help='Specifies number of receive endpoints for uni-directional topologies'); + parser.add_option ('-r', '--routers_per_row', action='store', type="int", default=-1, + help='specifies number of routers in each row (only used for mesh and torus)'); + parser.add_option ('-c', '--routers_per_column', action='store', type="int", default=-1, + help='specifies number of routers in each column (only used for mesh and torus)'); + parser.add_option ('-v', '--num_vcs', action='store', type="int", default=2, help='specifies number of virtual channels'); + parser.add_option ('-a', '--alloc_type', action='store', type="string", default='SepIFRoundRobin', + help='specifies type of allocator (can take values "SepIFRoundRobin", "SepOFRoundRobin", "SepIFStatic", "SepOFStatic", "Memocode")'); + parser.add_option ('--use_virtual_links', action='store_true', default=False, help='Enables locking of virtual links (VC+OutPort) in the presence of multi-flit packets.'); + # parser.add_option ('-a', '--alloc_type', action='store', type="string", default='sep_if_', help='specifies type of allocator (can take values:\n"sep_if_rr" (Separable Input-First Round-Robin Allocator),\n"sep_of_rr" (Separable Output-First Round-Robin Allocator),\n"sep_if_st" (Separable Input-First Static Allocator),\n"sep_of_st" (Separable Output-First Static Allocator),\n"memocode" (Exhaustive maximal allocator used in memocode design contest)') + parser.add_option ('-d', '--flit_buffer_depth', action='store', type="int", default=4, help='specifies depth of flit buffers'); + parser.add_option ('-s', '--sink_buffer_depth', action='store', type="int", default=-1, + help='specifies depth of buffers at receiving endpoints. If not specified flit_buffer_depth is assumed.'); + parser.add_option ('-w', '--flit_data_width', action='store', type="int", default=256, help='specifies flit data width'); + parser.add_option ('-i', '--cut', action='store', type="int", default=0, help='specifies the cut in an ideal or xbar network'); + parser.add_option ('-p', '--file_prefix', action='store', type="string", default='', help='override default file prefix'); + parser.add_option ('-l', '--xbar_lanes', action='store', type="int", default=1, help="specifies number of lanes in Xbar network"); + parser.add_option ('-o', '--output_dir', action='store', type="string", default='.', help='specifies output directory (default is ./)'); + parser.add_option ('-g', '--gen_rtl', action='store_true', default=False, help='invokes bsc compiler to generate rtl'); + parser.add_option ('-x', '--run_xst', action='store_true', default=False, help='generates rtl and invokes xst for synthesis'); + parser.add_option ('--run_dc', action='store_true', default=False, help='generates rtl and invokes Synopsys DC for synthesis'); + parser.add_option ('--expose_unused_ports', action='store_true', default=False, help='Exposes unused user ports for Mesh topology.'); + parser.add_option ('--flow_control_type', action='store', type="string", default='credit', + help='specifies flow control type, Credit-based or Peek (can take values "credit", "peek")'); + parser.add_option ('--peek_flow_control', action='store_true', default=False, help='Uses simpler peek flow control interface instead of credit-based interface.'); + parser.add_option ('--router_type', action='store', type="string", default='vc', + help='specifies router type, Virtual-Channel-based, Virtual-Output-Queued or Input-Queued (can take values "vc", "voq", "iq")'); + parser.add_option ('--voq_routers', action='store_true', default=False, help='Use Virtual-Output-Queued (VOQ) routers instead of Virtual-Channel (VC) routers.'); + parser.add_option ('--uni_tree_inputs', action='store', type="int", default=4, help='Number of tree input ports.'); + parser.add_option ('--uni_tree_outputs', action='store', type="int", default=64, help='Number of tree input ports.'); + parser.add_option ('--uni_tree_fanout', action='store', type="int", default=0, help='Fan-out of each tree router (will be calculated automatically if set to 0).'); + parser.add_option ('--uni_tree_distribute_leaves', action='store_true', default=False, help='Distributes the leaf nodes to the available routers, when the tree does not perfectly fit the available leaf nodes.'); + parser.add_option ('--pipeline_core', action='store_true', default=False, help='Pipelines router core.'); + parser.add_option ('--pipeline_alloc', action='store_true', default=False, help='Pipelines router allocator.'); + parser.add_option ('--pipeline_links', action='store_true', default=False, help='Pipelines flit and credit links.'); + parser.add_option ('--concentration_factor', action='store', type="int", default=1, + help='specifies number of user ports per endpoint router (not implemented yet)'); + parser.add_option ('--custom_topology', action='store', type="string", default="", help='specifies custom topology file.'); + parser.add_option ('--custom_routing', action='store', type="string", default="", help='specifies custom routing file.'); + parser.add_option ('--dump_topology_file', action='store_true', default=False, help='dumps the topology spec file for the generated network.'); + parser.add_option ('--dump_routing_file', action='store_true', default=False, help='dumps the routing spec file for the generated network.'); + parser.add_option ('--dbg', action='store_true', default=False, help='Enables debug messages in generated rtl.'); + parser.add_option ('--dbg_detail', action='store_true', default=False, help='Enables more detailed debug messages in generated rtl.'); + parser.add_option ('--gen_graph', action='store_true', default=False, help='Visualizes network graph using graphviz.'); + parser.add_option ('--graph_nodes', action='store_true', default=False, help='Also includes endpoint nodes in generated graph.'); + parser.add_option ('--graph_format', action='store', type="string", default="svg", help='Specifies output format for graphviz (e.g., png, jpg or svg)'); + parser.add_option ('--graph_layout', action='store', type="string", default="invalid", help='Specifies graphviz layout engine (e.g., dot, neato, circle)'); + # Future parameters + # Pick between different allocation schemes (e.g. matrix allocators, wavefront allocators, etc) + # choose implementation details (e.g. BRAM/LUT RAM, etc) + + (options, args) = parser.parse_args() + if (len(sys.argv) < 2): + parser.print_help(); #parser.error ('missing argument') + sys.exit(0) + main() + if options.verbose: print 'Done in', (time.time() - start_time), 'seconds' + sys.exit(0) + except KeyboardInterrupt, e: # Ctrl-C + raise e + except SystemExit, e: # sys.exit() + raise e + except Exception, e: + print 'ERROR, UNEXPECTED EXCEPTION' + print str(e) + traceback.print_exc() + os._exit(1) + diff --git a/inc.v b/inc.v new file mode 100644 index 0000000..d1b0a81 --- /dev/null +++ b/inc.v @@ -0,0 +1,249 @@ +/* ========================================================================= + * + * Filename: inc.v + * Date created: 03-18-2011 + * Last modified: 04-05-2011 + * Authors: Michael Papamichael + * + * Description: + * Generic include file for all modules + * + * ========================================================================= + */ + +///////////////////////////////////////////////////////////////////////// +// Set default configuration files. Override these in makefile. +//`define NETWORK_PARAMETERS_FILE "test_parameters.bsv" +`ifndef NETWORK_PARAMETERS_FILE + `define NETWORK_PARAMETERS_FILE "sample_mesh_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "mesh_4RTs_2VCs_4BD_128DW_2RTsPerRow_2RTsPerCol_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "ring_4RTs_2VCs_4BD_128DW_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "mesh_9RTs_2VCs_4BD_128DW_3RTsPerRow_3RTsPerCol_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "mesh_9RTs_2VCs_4BD_128DW_SepOfStaticAlloc_3RTsPerRow_3RTsPerCol_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "mesh_9RTs_2VCs_4BD_128DW_SepOFStaticAlloc_3RTsPerRow_3RTsPerCol_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "mesh_9RTs_2VCs_8BD_32DW_SepIFRoundRobinAlloc_3RTsPerRow_3RTsPerCol_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "test_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "double_ring_32RTs_2VCs_8BD_32DW_SepOFRoundRobinAlloc_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "mesh_16RTs_4VCs_8BD_32DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "mesh_16RTs_4VCs_8BD_64DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "mesh_16RTs_4VCs_8BD_128DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "fully_connected_8RTs_2VCs_8BD_32DW_SepOFRoundRobinAlloc_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "mesh_16RTs_2VCs_8BD_32DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "ring_64RTs_4VCs_4BD_128DW_SepOFRoundRobinAlloc_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "torus_16RTs_2VCs_16BD_64DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "fat_tree_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "double_ring_16RTs_4VCs_8BD_32DW_SepOFRoundRobinAlloc_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "fully_connected_16RTs_2VCs_8BD_32DW_SepOFRoundRobinAlloc_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "fully_connected_10RTs_4VCs_8BD_32DW_SepOFRoundRobinAlloc_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "mesh_16RTs_8VCs_8BD_32DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "mesh_16RTs_2VCs_8BD_32DW_SepIFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "high_radix_special_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "uni_tree_4INs_64OUTs_8FANOUT_1VCs_4BD_128DW_SepIFRoundRobinAlloc_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "uni_tree_4INs_64OUTs_8FANOUT_1VCs_4BD_128DW_SepIFRoundRobinAlloc_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "uni_tree_4INs_16OUTs_4FANOUT_1VCs_4BD_128DW_SepIFRoundRobinAlloc_parameters.bsv" + //`define NETWORK_PARAMETERS_FILE "uni_tree_4INs_64OUTs_8FANOUT_1VCs_4BD_128DW_SepIFRoundRobinAlloc_parameters.bsv" +`endif +`ifndef NETWORK_LINKS_FILE + `define NETWORK_LINKS_FILE "sample_mesh_links.bsv" + //`define NETWORK_LINKS_FILE "mesh_9RTs_2VCs_4BD_128DW_SepOfStaticAlloc_3RTsPerRow_3RTsPerCol_links.bsv" + //`define NETWORK_LINKS_FILE "mesh_16RTs_2VCs_8BD_64DW_SepOfStaticAllocAlloc_4RTsPerRow_4RTsPerCol_links.bsv" + //`define NETWORK_LINKS_FILE "mesh_9RTs_2VCs_8BD_32DW_SepIFRoundRobinAlloc_3RTsPerRow_3RTsPerCol_links.bsv" + //`define NETWORK_LINKS_FILE "double_ring_32RTs_2VCs_8BD_32DW_SepOFRoundRobinAlloc_links.bsv" + //`define NETWORK_LINKS_FILE "mesh_16RTs_4VCs_8BD_32DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_links.bsv" + //`define NETWORK_LINKS_FILE "mesh_16RTs_4VCs_8BD_64DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_links.bsv" + //`define NETWORK_LINKS_FILE "mesh_16RTs_4VCs_8BD_128DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_links.bsv" + //`define NETWORK_LINKS_FILE "fully_connected_8RTs_2VCs_8BD_32DW_SepOFRoundRobinAlloc_links.bsv" + //`define NETWORK_LINKS_FILE "mesh_16RTs_2VCs_8BD_32DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_links.bsv" + //`define NETWORK_LINKS_FILE "ring_64RTs_4VCs_4BD_128DW_SepOFRoundRobinAlloc_links.bsv" + //`define NETWORK_LINKS_FILE "torus_16RTs_2VCs_16BD_64DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_links.bsv" + //`define NETWORK_LINKS_FILE "fat_tree_links.bsv" + //`define NETWORK_LINKS_FILE "double_ring_16RTs_4VCs_8BD_32DW_SepOFRoundRobinAlloc_links.bsv" + //`define NETWORK_LINKS_FILE "fully_connected_16RTs_2VCs_8BD_32DW_SepOFRoundRobinAlloc_links.bsv" + //`define NETWORK_LINKS_FILE "fully_connected_10RTs_4VCs_8BD_32DW_SepOFRoundRobinAlloc_links.bsv" + //`define NETWORK_LINKS_FILE "mesh_16RTs_8VCs_8BD_32DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_links.bsv" + //`define NETWORK_LINKS_FILE "mesh_16RTs_2VCs_8BD_32DW_SepIFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_links.bsv" + //`define NETWORK_LINKS_FILE "high_radix_special_links.bsv" + //`define NETWORK_LINKS_FILE "uni_tree_4INs_16OUTs_4FANOUT_2VCs_4BD_128DW_SepIFRoundRobinAlloc_links.bsv" + //`define NETWORK_LINKS_FILE "uni_tree_4INs_64OUTs_8FANOUT_1VCs_4BD_128DW_SepIFRoundRobinAlloc_links.bsv" + //`define NETWORK_LINKS_FILE "uni_tree_4INs_16OUTs_4FANOUT_1VCs_4BD_128DW_SepIFRoundRobinAlloc_links.bsv" + //`define NETWORK_LINKS_FILE "uni_tree_4INs_64OUTs_8FANOUT_1VCs_4BD_128DW_SepIFRoundRobinAlloc_links.bsv" + +`endif +`ifndef NETWORK_ROUTING_FILE_PREFIX + `define NETWORK_ROUTING_FILE_PREFIX "sample_mesh_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "mesh_4RTs_2VCs_4BD_128DW_2RTsPerRow_2RTsPerCol_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "ring_4RTs_2VCs_4BD_128DW_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "mesh_16RTs_2VCs_8BD_64DW_SepOfStaticAllocAlloc_4RTsPerRow_4RTsPerCol_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "mesh_9RTs_2VCs_4BD_128DW_3RTsPerRow_3RTsPerCol_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "mesh_9RTs_2VCs_8BD_32DW_SepIFRoundRobinAlloc_3RTsPerRow_3RTsPerCol_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "mesh_64RTs_2VCs_1BD_256DW_SepIFRoundRobinAlloc_8RTsPerRow_8RTsPerCol_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "double_ring_32RTs_2VCs_8BD_32DW_SepOFRoundRobinAlloc_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "mesh_16RTs_4VCs_8BD_32DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "mesh_16RTs_4VCs_8BD_64DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "mesh_16RTs_4VCs_8BD_128DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "fully_connected_8RTs_2VCs_8BD_32DW_SepOFRoundRobinAlloc_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "mesh_16RTs_2VCs_8BD_32DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "ring_64RTs_4VCs_4BD_128DW_SepOFRoundRobinAlloc_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "torus_16RTs_2VCs_16BD_64DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "fat_tree_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "double_ring_16RTs_4VCs_8BD_32DW_SepOFRoundRobinAlloc_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "fully_connected_16RTs_2VCs_8BD_32DW_SepOFRoundRobinAlloc_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "fully_connected_10RTs_4VCs_8BD_32DW_SepOFRoundRobinAlloc_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "mesh_16RTs_8VCs_8BD_32DW_SepOFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "mesh_16RTs_2VCs_8BD_32DW_SepIFRoundRobinAlloc_4RTsPerRow_4RTsPerCol_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "high_radix_special_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "uni_tree_4INs_16OUTs_4FANOUT_2VCs_4BD_128DW_SepIFRoundRobinAlloc_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "uni_tree_4INs_64OUTs_8FANOUT_1VCs_4BD_128DW_SepIFRoundRobinAlloc_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "uni_tree_4INs_16OUTs_4FANOUT_1VCs_4BD_128DW_SepIFRoundRobinAlloc_routing_" + //`define NETWORK_ROUTING_FILE_PREFIX "uni_tree_4INs_64OUTs_8FANOUT_1VCs_4BD_128DW_SepIFRoundRobinAlloc_routing_" +`endif + +`include `NETWORK_PARAMETERS_FILE + +// Set default parameters +`ifndef NUM_ROUTERS + `define NUM_ROUTERS 16 +`endif +`ifndef NUM_IN_PORTS + `define NUM_IN_PORTS 5 +`endif +`ifndef NUM_OUT_PORTS + `define NUM_OUT_PORTS 5 +`endif +`ifndef CREDIT_DELAY + `define CREDIT_DELAY 1 +`endif +`ifndef NUM_VCS + `define NUM_VCS 2 +`endif +`ifndef FLIT_BUFFER_DEPTH 8 + `define FLIT_BUFFER_DEPTH 8 +`endif +`ifndef FLIT_DATA_WIDTH + `define FLIT_DATA_WIDTH 32 +`endif +`ifndef NUM_LINKS + `define NUM_LINKS 48 +`endif +`ifndef IDEAL_NETWORK_CUT + `define IDEAL_NETWORK_CUT 0 +`endif +`ifndef ALLOC_TYPE + `define ALLOC_TYPE SepOFRoundRobin +`endif +`ifndef USE_VIRTUAL_LINKS + `define USE_VIRTUAL_LINKS False +`endif +`ifndef DUMP_LINK_UTIL + `define DUMP_LINK_UTIL True +`endif +`ifndef PIPELINE_ALLOCATOR + `define PIPELINE_ALLOCATOR False +`endif +`ifndef PIPELINE_CORE + `define PIPELINE_CORE False +`endif +`ifndef PIPELINE_LINKS + `define PIPELINE_LINKS False +`endif + +//`define USE_VOQ_ROUTER True +//`define USE_IQ_ROUTER True + +//`ifndef RESTRICT_UTURNS +// `define RESTRICT_UTURNS False +//`endif + +// Enables debugging messages +//`define EN_DBG True // comment this out to disable common debugging messages + +// Enables more detailed debugging messages +//`define EN_DBG_DETAIL True // comment this out to disable common debugging messages + +// If enabled will produce messages that match software reference design. +// Make sure this is commented out when synthesizing design. +//`define EN_DBG_REF True // controls if debugging messages that compare to reference design are printed + +// Colors +`define NO_COLORS 1 +`ifdef NO_COLORS + `define WHITE $write("") + `define RED $write("") + `define BLUE $write("") + `define BROWN $write("") + `define GREEN $write("") +`else + `define WHITE $write("%c[0m",27) + //`define WHITE_INL  + `define RED $write("%c[1;31m",27) + `define BLUE $write("%c[1;34m",27) + `define BROWN $write("%c[4;33m",27) + `define GREEN $write("%c[1;32m",27) +`endif + +// Debugging stuff +`ifdef EN_DBG + //`define EN_DBG_RULE True + // Note: Do not use parentheses inside DBG messages. They cause conflicts with the macro definition + //`define DBG(_str) $write("%c[1;31m[ %15s ] %c[0m",27,name,27);$display _str + `define DBG(_str) `RED;$write("%s",name);`WHITE;$write(" : ");$display _str + //`define DBG_ID(_str) $write("%c[1;31m[ %d:",27,id); $write(name," ] %c[0m",27);$display _str + `define DBG_ID(_str) `RED;$write("%s",name);`BLUE;$write("(%0d)",id);`WHITE;$write(" : ");$display _str + //`define DBG_CYCLES(_str) $write("%c[1;31m[ %15s ] %c[1;34m@ %4d %c[0m:",27,name,27,cycles,27);$display _str + `define DBG_CYCLES(_str) `RED;$write("%s",name);`GREEN;$write(" @ %04d", cycles);`WHITE;$write(" : ");$display _str + //`define DBG_ID_CYCLES(_str) $write("%c[1;31m[ %d:",27,id);$write(name," ] %c[0m",27);$write("%c[1;34m @ %d ",27,cycles);$write("%c[0m :",27);$display _str + `define DBG_ID_CYCLES(_str) `RED;$write("%s",name);`BLUE;$write("(%0d)",id);`GREEN;$write(" @ %04d", cycles);`WHITE;$write(" : ");$display _str + `define DBG_NONAME(_str) $display _str +`else + //`define EN_DBG_RULE False + `define DBG(_str) $write("") + `define DBG_ID(_str) $write("") + `define DBG_CYCLES(_str) $write("") + `define DBG_ID_CYCLES(_str) $write("") + `define DBG_NONAME(_str) $write("") +`endif + +`ifdef EN_DBG_DETAIL + `define EN_DBG_RULE True + // Note: Do not use parentheses inside DBG_DETAIL messages. They cause conflicts with the macro definition + //`define DBG_DETAIL(_str) $write("%c[1;31m[ %15s ] %c[0m",27,name,27); $display _str + `define DBG_DETAIL(_str) `RED;$write("%20s",name);`WHITE;$write(" : ");$display _str + //`define DBG_DETAIL_ID(_str) $write("%c[1;31m[ %d:",27,id); $write(name," ] %c[0m",27);$display _str + `define DBG_DETAIL_ID(_str) `RED;$write("%20s(%d)",name,id);`WHITE;$write(" : ");$display _str +`else + `define EN_DBG_RULE False + `define DBG_DETAIL(_str) $write("") + `define DBG_DETAIL_ID(_str) $write("") +`endif + +`ifdef EN_DBG_REF + // used to print out messags that match reference design + `define DBG_REF(_str) $display _str +`else + `define DBG_REF(_str) $write("") +`endif + +// Fancy display versions +`define DISP(_str) `RED;$write("%s",name);`WHITE;$write(" : ");$display _str +`define DISP_ID(_str) `RED;$write("%s",name);`BLUE;$write("(%0d)",id);`WHITE;$write(" : ");$display _str +`define DISP_CYCLES(_str) `RED;$write("%s",name);`GREEN;$write(" @ %04d", cycles);`WHITE;$write(" : ");$display _str +`define DISP_ID_CYCLES(_str) `RED;$write("%s",name);`BLUE;$write("(%0d)",id);`GREEN;$write(" @ %04d", cycles);`WHITE;$write(" : ");$display _str +`define DISP_NONAME(_str) $display _str + +//`ifndef BLA +//`define BLA +//function Action dbg_cycles(Fmt msg); +// action +// let tmp = $format(msg); +// `DISP_CYCLES((tmp)); +// endaction +//endfunction +//`endif + +//////////////////// older stuff /////////////////////////////// +// -- Older debugging defines -- +//`define EN_DBG True +//`define DBG $write("%c[1;31m[ %15s ] %c[0m",27,name,27) +//`define DBG_id $write("%c[1;31m[ %d:",27,id); $write(name," ] %c[0m",27) +//`define DBG if(!False) begin noAction; end else begin + diff --git a/makefile.bsc b/makefile.bsc new file mode 100644 index 0000000..9452b9c --- /dev/null +++ b/makefile.bsc @@ -0,0 +1,12 @@ +-include $(DEP) + +SRC_PATH=$(shell find . -name "$(TARGET).bsv") + +%.bo: %.bsv + #bsc $(BSV_MACROS) $(GLOBAL_FLAGS) -u $< + bsc $(GLOBAL_FLAGS) -u $< + +#target: +target: + #bsc -u -verilog $(BSV_MACROS) $(GLOBAL_FLAGS) -g mk$(TOP) $(SRC_PATH) + bsc -u -verilog $(GLOBAL_FLAGS) -g $(TOP) $(SRC_PATH) diff --git a/makefile.clean b/makefile.clean new file mode 100644 index 0000000..2e3cc43 --- /dev/null +++ b/makefile.clean @@ -0,0 +1,21 @@ +clean: + @echo "Cleaning..." + rm -rf ./obj/* + rm -rf ./build/* + rm -f *.o *.so + find . -name "*.sched" -exec rm -rf {} \; + find . -name "*.o" -exec rm -rf {} \; + find . -name "*.bo" -exec rm -rf {} \; + find . -name "*.bi" -exec rm -rf {} \; + find . -name "*.ba" -exec rm -rf {} \; + +swclean: + find . -name "*.o" -exec rm -rf {} \; + +clean_xst: + rm -rf $(XST_DIR)/* + +clean_vcs: + rm -rf $(VCS_DIR)/* + +clobber: clean clean_xst clean_vcs diff --git a/makefile.def b/makefile.def new file mode 100644 index 0000000..6bb06fe --- /dev/null +++ b/makefile.def @@ -0,0 +1,160 @@ +####### Bluespec defs ######## +BSC = bsc +SCRATCH = ~/scratch/mpapamic/ +VLOG = build +XST_DIR = ${SCRATCH}/xst_runs +DC_DIR = ${SCRATCH}/dc_runs +#XST_DIR = /scratch/mpapamic/xst_runs +#XST_DIR = /home/mpapamic/xst_runs +#SYN_DIR = /scratch/mpapamic/synplify_runs +SYN_DIR = /home/mpapamic/synplify_runs +VCS_DIR = ${SCRATCH}/vcs_runs +#VCS_DIR = ./vcs_runs +#VCS_DIR = /scratch/mpapamic/vcs_runs +OBJDIR = ./obj +IMPORT_DIRS = $(shell find . -name ".svn" -prune -o -name "build" -prune -o -type d -exec echo -ne "{}:" \;) +ALLDIRS = $(shell find . -name ".svn" -prune -o -name "*.c*" -exec dirname {} \; | uniq) +IMPORT = $(OBJDIR):${BLUESPEC_HOME}/lib/Prelude:${BLUESPEC_HOME}/lib/Libraries:$(IMPORT_DIRS)+ +# With this set of options I was able to compile the largest design. (16x16, 8VCs). Make sure you run on machines with 16GB memory. 16x16 8VCs requires 11.4GB of RAM. +#GLOBAL_FLAGS = -opt-undetermined-vals -unspecified-to 0 -resource-simple -Xc++ -O0 -u -simdir $(OBJDIR) -bdir $(OBJDIR) -p $(IMPORT) -check-assert -vdir $(VLOG) +RTS -K3072M -H8192M -RTS -v95 -no-warn-action-shadowing +# Erics flags +GLOBAL_FLAGS = -relax-method-earliness -opt-undetermined-vals -unspecified-to X -resource-simple -Xc++ -O0 -u -simdir $(OBJDIR) -bdir $(OBJDIR) -p $(IMPORT) -check-assert -vdir $(VLOG) +RTS -K3072M -H8192M -RTS -v95 -no-warn-action-shadowing +#GLOBAL_FLAGS = -opt-undetermined-vals -unspecified-to X -scheduler-effort 1 -resource-simple -Xc++ -O0 -u -simdir $(OBJDIR) -bdir $(OBJDIR) -p $(IMPORT) -check-assert -vdir $(VLOG) +RTS -K3072M -H8192M -RTS -v95 -no-warn-action-shadowing +#GLOBAL_FLAGS = -unspecified-to X -scheduler-effort 1 -Xc++ -O0 -u -simdir $(OBJDIR) -bdir $(OBJDIR) -p $(IMPORT) -check-assert -vdir $(VLOG) +RTS -K1024M -RTS -v95 -no-warn-action-shadowing +#GLOBAL_FLAGS = -unspecified-to X -scheduler-effort 1 -Xc++ -O0 -u -simdir $(OBJDIR) -bdir $(OBJDIR) -p $(IMPORT) -check-assert -vdir $(VLOG) +RTS -K500000000 -RTS -v95 -no-warn-action-shadowing +#GLOBAL_FLAGS = -unspecified-to X -scheduler-effort 1 -Xc++ -O0 -Xc++ -fPIC -u -simdir $(OBJDIR) -bdir $(OBJDIR) -p $(IMPORT) -check-assert -vdir $(VLOG) +RTS -K500000000 -RTS -v95 -no-warn-action-shadowing +#GLOBAL_FLAGS = -unspecified-to X -steps-warn-interval 1000 -v -show-stats -scheduler-effort 0 -Xc++ -O0 -u -simdir $(OBJDIR) -bdir $(OBJDIR) -p $(IMPORT) -check-assert -vdir $(VLOG) +RTS -K500000000 -RTS -v95 -no-warn-action-shadowing +BSC_vsim = bsc $(GLOBAL_FLAGS) -verilog -steps 10000000 +#BSC_vsim = bsc $(GLOBAL_FLAGS) -verilog -g +BSC_bsim = bsc $(GLOBAL_FLAGS) -show-schedule -D __NOSYNTH__=1 -sim +RTS -K50000000 -RTS -steps 10000000 -g +timestamp = `date +%F_%H%M` +fixed_timestamp := $(shell date +%F_%H%M) +logdir = logs + +####### GCC defs ######## +GCC = gcc +G++ = g++ +OPTS = -Wall -O3 -funroll-loops -DNS_STANDALONE -DLOG_RESULTS +INCL = -I./cfg/ \ + -I./swlib/ \ + -I./swlib/hashlib \ + -I./swlib/easy_opt \ + -I./swlib/timing \ + -I./rtl/Stats \ + -I./rtl/Coprims \ + -I./sw/Netsim \ + -I./sw/Netsim/testing \ + -I./sw/Dramsim + +####### Functions ######## + +define vsim_compile +@echo Compiling $(strip $(1)) from file $(2) into simulatable Verilog +@mkdir -p ${OBJDIR} +@${BSC_vsim} ${GLOBAL_FLAGS} ${USER_FLAGS} -g ${1} ${2} +endef + +#define vsim_compile_dbg_ref +#@echo Compiling $(strip $(1)) from file $(2) into simulatable Verilog +#@${BSC_vsim} -D EN_DBG_REF ${GLOBAL_FLAGS} -g ${1} ${2} +#endef +# +#define vsim_compile_dbg_ref +#@echo Compiling $(strip $(1)) from file $(2) into simulatable Verilog +#@${BSC_vsim} -D EN_DBG_REF ${GLOBAL_FLAGS} -g ${1} ${2} +#endef + +define bsim_compile +@echo Compiling $(strip $(1)) from file $(2) into .o file +rm -f $(OBJDIR)/schedule.o $(OBJDIR)/mk*.o $(OBJDIR)/$(strip $(1)).o +@${BSC_bsim} ${1} ${2} +@touch $(OBJDIR)/non.o +@${BSC} -sim ${GLOBAL_FLAGS} ${USER_FLAGS} -o ${1} -e ${1} $(OBJDIR)/*.ba $(OBJDIR)/*.o +endef + +define xst_compile +@echo Compiling for xst +mkdir -p ${XST_DIR}/$(strip $(1))_${fixed_timestamp} +cp -r ${VLOG}/* ${XST_DIR}/$(strip $(1))_${fixed_timestamp} +./scripts/compile_xst.sh ${XST_DIR}/$(strip $(1))_${fixed_timestamp} $(strip $(1)) $(2) +@echo Finished synthesis in directory: ${XST_DIR}/$(strip $(1))_${fixed_timestamp} +./scripts/getSynthStats.sh ${XST_DIR}/$(strip $(1))_${fixed_timestamp} +endef + +define map_compile +@echo Compiling for xst +mkdir -p ${XST_DIR}/$(strip $(1))_${fixed_timestamp} +cp -r ${VLOG}/* ${XST_DIR}/$(strip $(1))_${fixed_timestamp} +./scripts/compile_xst.sh ${XST_DIR}/$(strip $(1))_${fixed_timestamp} $(strip $(1)) $(2) +@echo Finished synthesis in directory: ${XST_DIR}/$(strip $(1))_${fixed_timestamp} +@echo Running MAP to extract detailed resource usage stats +./scripts/getMapStats.sh ${XST_DIR}/$(strip $(1))_${fixed_timestamp} $(strip $(1)) $(2) +./scripts/getSynthStats.sh ${XST_DIR}/$(strip $(1))_${fixed_timestamp} +endef + +define dc_compile +@echo Compiling with Synopsys DC +mkdir -p ${DC_DIR}/$(strip $(1))_${fixed_timestamp} +cp -r ${VLOG}/* ${DC_DIR}/$(strip $(1))_${fixed_timestamp} +./scripts/synth_dc.sh ${DC_DIR}/$(strip $(1))_${fixed_timestamp} $(strip $(1)) $(2) +@echo Finished synthesis in directory: ${DC_DIR}/$(strip $(1))_${fixed_timestamp} +#./scripts/getSynthStats.sh ${DC_DIR}/$(strip $(1))_${fixed_timestamp} +endef + +# define xst_compile_speed2 +# @echo Compiling for xst +# mkdir -p ${XST_DIR}/$(strip $(1))_${timestamp} +# cp -r ${VLOG}/* ${XST_DIR}/$(strip $(1))_${timestamp} +# ./scripts/compile_xst_speed2.sh ${XST_DIR}/$(strip $(1))_${timestamp} $(strip $(1)) +# endef +# +# define xst_compile_speed3 +# @echo Compiling for xst +# mkdir -p ${XST_DIR}/$(strip $(1))_${timestamp} +# cp -r ${VLOG}/* ${XST_DIR}/$(strip $(1))_${timestamp} +# ./scripts/compile_xst_speed3.sh ${XST_DIR}/$(strip $(1))_${timestamp} $(strip $(1)) +# endef +# +# define xst_compile_xupv5 +# @echo Compiling for xst +# mkdir -p ${XST_DIR}_xupv5/$(strip $(1))_${timestamp} +# cp -r ${VLOG}/* ${XST_DIR}_xupv5/$(strip $(1))_${timestamp} +# ./scripts/compile_xst_xupv5.sh ${XST_DIR}_xupv5/$(strip $(1))_${timestamp} $(strip $(1)) +# endef +# +# define xst_compile_xupv5_speed2 +# @echo Compiling for xst +# mkdir -p ${XST_DIR}_xupv5/$(strip $(1))_${timestamp} +# cp -r ${VLOG}/* ${XST_DIR}_xupv5/$(strip $(1))_${timestamp} +# ./scripts/compile_xst_xupv5_speed2.sh ${XST_DIR}_xupv5/$(strip $(1))_${timestamp} $(strip $(1)) +# endef +# +# define xst_compile_xupv5_speed3 +# @echo Compiling for xst +# mkdir -p ${XST_DIR}_xupv5/$(strip $(1))_${timestamp} +# cp -r ${VLOG}/* ${XST_DIR}_xupv5/$(strip $(1))_${timestamp} +# ./scripts/compile_xst_xupv5_speed3.sh ${XST_DIR}_xupv5/$(strip $(1))_${timestamp} $(strip $(1)) +# endef + +define vcs_compile +@echo Compiling for vcs +mkdir -p ${VCS_DIR}/$(strip $(1))_${timestamp} +cp -r ${VLOG}/* ${VCS_DIR}/$(strip $(1))_${timestamp} +./scripts/compile_vcs.sh ${VCS_DIR}/$(strip $(1))_${timestamp} $(strip $(1)) +#./scripts/dovcs.sh ${VCS_DIR}/$(strip $(1))_${timestamp} $(strip $(1)) +endef + +define csrc +buildrepo \ +$(patsubst %.c,$(OBJDIR)/%.o,$(shell find ${1} -maxdepth 1 -name "*.c")) \ +$(patsubst %.cpp,$(OBJDIR)/%.o,$(shell find ${1} -maxdepth 1 -name "*.cpp")) +endef + +#$(shell find ${1} -maxdepth 1 -name "*.c" -exec sh -c "echo {} | sed 's/\.c/.o/g'" \;) \ +#$(patsubst %.cpp,$(OBJDIR)/%.o,$(shell find ${1} -maxdepth 1 -name "*.cpp" -exec sh -c "echo {} | sed 's/\.cpp/.o/g'" \;)) + +#GLOBAL_FLAGS = -verbose -u -unspecified-to X -O -show-schedule -vdir verilog +#GLOBAL_FLAGS = -u -vdir verilog -check-assert -verbose -show-stats -inline-simple +#GLOBAL_FLAGS = -u -vdir verilog -unspecified-to X -check-assert -verbose -opt-undetermined-vals +# -scheduler-effort 0 +# -one-module-per-file diff --git a/makefile.syn b/makefile.syn new file mode 100644 index 0000000..1b97233 --- /dev/null +++ b/makefile.syn @@ -0,0 +1,81 @@ +tb: prims + $(call bsim_compile, mkCoramSimTb, ./rtl/Microbench/CoramTb.bsv); + +pwr: + $(call vsim_compile, top, ./rtl/PwrTest/Testbench.bsv) + +peakpwr: + $(call vsim_compile, mkPeakPower, ./rtl/PeakPower/PeakPower.bsv) + +peakpwr_tb: + $(call bsim_compile, mkPeakPower, ./rtl/PeakPower/PeakPower.bsv) + +#$(call vcs_compile, top) + +memtb: $(OBJS) + $(call bsim_compile, mkMemoryTb, ./rtl/Microbench/MemoryTb.bsv); + +tort1: $(OBJS) + $(call bsim_compile, mkMemTort1, ./rtl/Microbench/MemTort1.bsv); + +mm: $(OBJS) + $(call bsim_compile, mkMM, ./rtl/MM/MM.bsv); + +gemmtop: copy_vlog + $(call vsim_compile, mkPeGroup, ./rtl/GEMM/GemmTop.bsv) + ./fix_madds.sh + +gemm: copy_vlog + $(call vsim_compile, mkGemmPE_dsp4, ./rtl/GEMM/GemmPE.bsv) + ./fix_madds.sh + +madd: + $(call vsim_compile, mkMadd, ./rtl/GEMM/Madd.bsv) + +gemm_tb: copy_vlog + $(call vsim_compile, mkGemmTb, ./rtl/GEMM/GemmTb.bsv) + +gemm_bsim: $(OBJS) + $(call bsim_compile, mkGemmTb, ./rtl/GEMM/GemmTb.bsv) + +gemmpwr: + $(call vsim_compile, mkGemmPower, ./rtl/GEMM/GemmPower.bsv) + ./fix_madds.sh + +gemmpwr_vcs: $(OBJS) copy_vlog + $(call vsim_compile, mkGemmPower, ./rtl/GEMM/GemmPower.bsv) + ./fix_madds.sh + $(call vcs_compile, mkGemmPower) + +gemmpwr_bsim: $(OBJS) + $(call bsim_compile, mkGemmPower, ./rtl/GEMM/GemmPower.bsv) + +fptb: copy_vlog + $(call vsim_compile, mkFpTb2, ./rtl/GEMM/Madd.bsv) + $(call vcs_compile, mkFpTb2) + +spmv: $(OBJS) + $(call bsim_compile, mkSPMV, ./rtl/SpMV/SpMV.bsv); + +dma: $(OBJS) + $(call bsim_compile, mkDmaTb, ./rtl/Microbench/DmaTb.bsv); + +copy_prims: + cp ./rtl/Prims/*.v ./build + +copy_vlog: + mkdir -p build + cp ./Prims/*.v ./build + #cp ./lib/*.v ./build + #cp *.data ./build + - cp ./*routing_*.hex ./build + - cp ./*.rom ./build + #cp ./net_configs/*.data ./build + +copy_init_files: + cp *.data ./build + + + #rm -f ./build/main.v + #cp ./rtl/Prims/*.v ./build + #find ./rtl/Prims -name "*.v" -exec cp {} ./build \; diff --git a/sample_mesh_links.bsv b/sample_mesh_links.bsv new file mode 100644 index 0000000..78be7d0 --- /dev/null +++ b/sample_mesh_links.bsv @@ -0,0 +1,96 @@ +send_ports_ifaces[0] = routers[0].in_ports[0]; +recv_ports_ifaces[0] = routers[0].out_ports[0]; +recv_ports_info_ifaces[0] = get_port_info_ifc(0); +send_ports_ifaces[1] = routers[1].in_ports[0]; +recv_ports_ifaces[1] = routers[1].out_ports[0]; +recv_ports_info_ifaces[1] = get_port_info_ifc(1); +send_ports_ifaces[2] = routers[2].in_ports[0]; +recv_ports_ifaces[2] = routers[2].out_ports[0]; +recv_ports_info_ifaces[2] = get_port_info_ifc(2); +send_ports_ifaces[3] = routers[3].in_ports[0]; +recv_ports_ifaces[3] = routers[3].out_ports[0]; +recv_ports_info_ifaces[3] = get_port_info_ifc(3); +send_ports_ifaces[4] = routers[4].in_ports[0]; +recv_ports_ifaces[4] = routers[4].out_ports[0]; +recv_ports_info_ifaces[4] = get_port_info_ifc(4); +send_ports_ifaces[5] = routers[5].in_ports[0]; +recv_ports_ifaces[5] = routers[5].out_ports[0]; +recv_ports_info_ifaces[5] = get_port_info_ifc(5); +send_ports_ifaces[6] = routers[6].in_ports[0]; +recv_ports_ifaces[6] = routers[6].out_ports[0]; +recv_ports_info_ifaces[6] = get_port_info_ifc(6); +send_ports_ifaces[7] = routers[7].in_ports[0]; +recv_ports_ifaces[7] = routers[7].out_ports[0]; +recv_ports_info_ifaces[7] = get_port_info_ifc(7); +send_ports_ifaces[8] = routers[8].in_ports[0]; +recv_ports_ifaces[8] = routers[8].out_ports[0]; +recv_ports_info_ifaces[8] = get_port_info_ifc(8); +send_ports_ifaces[9] = routers[9].in_ports[0]; +recv_ports_ifaces[9] = routers[9].out_ports[0]; +recv_ports_info_ifaces[9] = get_port_info_ifc(9); +send_ports_ifaces[10] = routers[10].in_ports[0]; +recv_ports_ifaces[10] = routers[10].out_ports[0]; +recv_ports_info_ifaces[10] = get_port_info_ifc(10); +send_ports_ifaces[11] = routers[11].in_ports[0]; +recv_ports_ifaces[11] = routers[11].out_ports[0]; +recv_ports_info_ifaces[11] = get_port_info_ifc(11); +send_ports_ifaces[12] = routers[12].in_ports[0]; +recv_ports_ifaces[12] = routers[12].out_ports[0]; +recv_ports_info_ifaces[12] = get_port_info_ifc(12); +send_ports_ifaces[13] = routers[13].in_ports[0]; +recv_ports_ifaces[13] = routers[13].out_ports[0]; +recv_ports_info_ifaces[13] = get_port_info_ifc(13); +send_ports_ifaces[14] = routers[14].in_ports[0]; +recv_ports_ifaces[14] = routers[14].out_ports[0]; +recv_ports_info_ifaces[14] = get_port_info_ifc(14); +send_ports_ifaces[15] = routers[15].in_ports[0]; +recv_ports_ifaces[15] = routers[15].out_ports[0]; +recv_ports_info_ifaces[15] = get_port_info_ifc(15); +links[0] <- mkConnectPorts(routers[1], 1, routers[0], 1); +links[1] <- mkConnectPorts(routers[5], 1, routers[4], 1); +links[2] <- mkConnectPorts(routers[9], 1, routers[8], 1); +links[3] <- mkConnectPorts(routers[13], 1, routers[12], 1); +links[4] <- mkConnectPorts(routers[2], 1, routers[1], 1); +links[5] <- mkConnectPorts(routers[6], 1, routers[5], 1); +links[6] <- mkConnectPorts(routers[10], 1, routers[9], 1); +links[7] <- mkConnectPorts(routers[14], 1, routers[13], 1); +links[8] <- mkConnectPorts(routers[3], 1, routers[2], 1); +links[9] <- mkConnectPorts(routers[7], 1, routers[6], 1); +links[10] <- mkConnectPorts(routers[11], 1, routers[10], 1); +links[11] <- mkConnectPorts(routers[15], 1, routers[14], 1); +links[12] <- mkConnectPorts(routers[4], 2, routers[0], 2); +links[13] <- mkConnectPorts(routers[8], 2, routers[4], 2); +links[14] <- mkConnectPorts(routers[12], 2, routers[8], 2); +links[15] <- mkConnectPorts(routers[5], 2, routers[1], 2); +links[16] <- mkConnectPorts(routers[9], 2, routers[5], 2); +links[17] <- mkConnectPorts(routers[13], 2, routers[9], 2); +links[18] <- mkConnectPorts(routers[6], 2, routers[2], 2); +links[19] <- mkConnectPorts(routers[10], 2, routers[6], 2); +links[20] <- mkConnectPorts(routers[14], 2, routers[10], 2); +links[21] <- mkConnectPorts(routers[7], 2, routers[3], 2); +links[22] <- mkConnectPorts(routers[11], 2, routers[7], 2); +links[23] <- mkConnectPorts(routers[15], 2, routers[11], 2); +links[24] <- mkConnectPorts(routers[0], 3, routers[1], 3); +links[25] <- mkConnectPorts(routers[4], 3, routers[5], 3); +links[26] <- mkConnectPorts(routers[8], 3, routers[9], 3); +links[27] <- mkConnectPorts(routers[12], 3, routers[13], 3); +links[28] <- mkConnectPorts(routers[1], 3, routers[2], 3); +links[29] <- mkConnectPorts(routers[5], 3, routers[6], 3); +links[30] <- mkConnectPorts(routers[9], 3, routers[10], 3); +links[31] <- mkConnectPorts(routers[13], 3, routers[14], 3); +links[32] <- mkConnectPorts(routers[2], 3, routers[3], 3); +links[33] <- mkConnectPorts(routers[6], 3, routers[7], 3); +links[34] <- mkConnectPorts(routers[10], 3, routers[11], 3); +links[35] <- mkConnectPorts(routers[14], 3, routers[15], 3); +links[36] <- mkConnectPorts(routers[0], 4, routers[4], 4); +links[37] <- mkConnectPorts(routers[4], 4, routers[8], 4); +links[38] <- mkConnectPorts(routers[8], 4, routers[12], 4); +links[39] <- mkConnectPorts(routers[1], 4, routers[5], 4); +links[40] <- mkConnectPorts(routers[5], 4, routers[9], 4); +links[41] <- mkConnectPorts(routers[9], 4, routers[13], 4); +links[42] <- mkConnectPorts(routers[2], 4, routers[6], 4); +links[43] <- mkConnectPorts(routers[6], 4, routers[10], 4); +links[44] <- mkConnectPorts(routers[10], 4, routers[14], 4); +links[45] <- mkConnectPorts(routers[3], 4, routers[7], 4); +links[46] <- mkConnectPorts(routers[7], 4, routers[11], 4); +links[47] <- mkConnectPorts(routers[11], 4, routers[15], 4); diff --git a/sample_mesh_parameters.bsv b/sample_mesh_parameters.bsv new file mode 100644 index 0000000..c9c68b8 --- /dev/null +++ b/sample_mesh_parameters.bsv @@ -0,0 +1,19 @@ +//`define USE_VOQ_ROUTER DEF +`define USE_IQ_ROUTER DEF +`define NUM_USER_SEND_PORTS 16 +`define NUM_USER_RECV_PORTS 16 +`define NUM_ROUTERS 16 +`define NUM_IN_PORTS 5 +`define NUM_OUT_PORTS 5 +`define CREDIT_DELAY 1 +`define NUM_VCS 2 +`define ALLOC_TYPE SepIFRoundRobin +`define USE_VIRTUAL_LINKS False +`define FLIT_BUFFER_DEPTH 8 +`define FLIT_DATA_WIDTH 32 +`define NUM_LINKS 48 +`define NETWORK_CUT 0 +`define XBAR_LANES 1 +`define PIPELINE_CORE False +`define PIPELINE_ALLOCATOR False +`define PIPELINE_LINKS False diff --git a/version b/version new file mode 100644 index 0000000..8f897c8 --- /dev/null +++ b/version @@ -0,0 +1 @@ +202