├── docs ├── 2xb.png ├── crossbar.png ├── ring-node.png ├── vc-fifo.png ├── flit-to-packet.png ├── packet-to-flit.png ├── ring-network.png └── flit-to-packet-pipe-stages.png ├── README.md ├── TestBenchVcFifo.bsv ├── TestBenchP2F.bsv ├── Cntr.bsv ├── IndexPool.bsv ├── VcFifo.bsv ├── PacketFifo.bsv ├── RingForFpga.bsv ├── Ring.bsv ├── CommonTypes.bsv ├── project.bld ├── xupv5.ucf ├── TestBenchRing.bsv ├── PacketToFlit.bsv ├── Ehr.bsv ├── TestBenchRingNode.bsv ├── TestBenchF2P.bsv ├── TestBenchXbr.bsv ├── RingNode.bsv ├── Arbiter.bsv ├── CrossBar.bsv ├── FlitToPacket.bsv ├── Fifo.bsv └── LICENSE /docs/2xb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimi-michael/Ring-NoC/HEAD/docs/2xb.png -------------------------------------------------------------------------------- /docs/crossbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimi-michael/Ring-NoC/HEAD/docs/crossbar.png -------------------------------------------------------------------------------- /docs/ring-node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimi-michael/Ring-NoC/HEAD/docs/ring-node.png -------------------------------------------------------------------------------- /docs/vc-fifo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimi-michael/Ring-NoC/HEAD/docs/vc-fifo.png -------------------------------------------------------------------------------- /docs/flit-to-packet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimi-michael/Ring-NoC/HEAD/docs/flit-to-packet.png -------------------------------------------------------------------------------- /docs/packet-to-flit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimi-michael/Ring-NoC/HEAD/docs/packet-to-flit.png -------------------------------------------------------------------------------- /docs/ring-network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimi-michael/Ring-NoC/HEAD/docs/ring-network.png -------------------------------------------------------------------------------- /docs/flit-to-packet-pipe-stages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kimi-michael/Ring-NoC/HEAD/docs/flit-to-packet-pipe-stages.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Ring-NoC 2 | ======== 3 | 4 | a scaleable ring topology network on chip (NoC) implemented in BSV 5 | 6 | for more details check the wiki page: 7 | https://github.com/kimi-michael/Ring-NoC/wiki/Ring-NoC-project-description 8 | -------------------------------------------------------------------------------- /TestBenchVcFifo.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | import FShow::*; 5 | import CommonTypes::*; 6 | import VcFifo::*; 7 | 8 | typedef enum {Start, Test, End} TestPhase deriving (Bits, Eq); 9 | 10 | (* synthesize *) 11 | module mkVcFifoTestBench(); 12 | 13 | Integer maxCyclesToRun = 20; 14 | Integer nodeId = 1; 15 | 16 | Reg#(Bit#(32)) cycle <- mkReg(0); 17 | Reg#(TestPhase)testPhase <- mkReg(Start); 18 | Reg#(Bit#(4)) testStage <- mkReg(0); 19 | VcFifo#(4, 32, 2) p2f <- mkVcFifo; 20 | /////////////////////////////////////////////////////////////////// 21 | rule timeout if (cycle > fromInteger(maxCyclesToRun)); 22 | $display("Timeout termination cycle count %d", cycle); 23 | $finish(); 24 | endrule 25 | 26 | rule clockCount; 27 | $display("\n== cycle %03d ==", cycle); 28 | cycle <= cycle + 1; 29 | endrule 30 | ////////////////////////////////////////////////////////////////// 31 | rule start(testPhase == Start); 32 | $display("Start tests:"); 33 | testPhase <= Test; 34 | endrule 35 | 36 | Reg#(Bit#(1)) vcId <- mkReg(0); 37 | 38 | rule test_enq(testPhase == Test); 39 | Flit_t#(4, 32, 2) f = Flit_t{src:1 , 40 | dest: 3, 41 | fltId: 1, 42 | pktId: 2, 43 | vcId: vcId, 44 | data: 'hdeadbeaf + cycle}; 45 | $display("enq flit:: ", fshow(f)); 46 | p2f.put(f); 47 | vcId <= vcId + 1; 48 | endrule 49 | 50 | rule test_deq(testPhase == Test && cycle > 5); 51 | let f <- p2f.get(); 52 | $display("deq flit:: ", fshow(f)); 53 | endrule 54 | endmodule 55 | 56 | -------------------------------------------------------------------------------- /TestBenchP2F.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | import CommonTypes::*; 5 | import PacketToFlit::*; 6 | 7 | typedef enum {Start, P2F, End} TestPhase deriving (Bits, Eq); 8 | 9 | (* synthesize *) 10 | module mkP2FTestBench(); 11 | 12 | Integer maxCyclesToRun = 20; 13 | Integer nodeId = 1; 14 | 15 | Reg#(Bit#(32)) cycle <- mkReg(0); 16 | Reg#(TestPhase)testPhase <- mkReg(Start); 17 | Reg#(Bit#(4)) testStage <- mkReg(0); 18 | PacketToFlit#(4, 32, 2) p2f <- mkPacketToFlit(nodeId); 19 | /////////////////////////////////////////////////////////////////// 20 | rule timeout if (cycle > fromInteger(maxCyclesToRun)); 21 | $display("Timeout termination cycle count %d", cycle); 22 | $finish(); 23 | endrule 24 | 25 | rule clockCount; 26 | $display("== cycle %03d ==", cycle); 27 | cycle <= cycle + 1; 28 | endrule 29 | ////////////////////////////////////////////////////////////////// 30 | rule start(testPhase == Start); 31 | $display("Start tests:"); 32 | testPhase <= P2F; 33 | endrule 34 | 35 | rule testP2F_enq(testPhase == P2F); 36 | Packet#(4) p = Packet{peer: 1, msg: ?/*'h0123456789abcdef*/}; 37 | p.msg = 'hffffeeeeddddccccbbbbaaaa9999888877776666555544443333222211110000 + extend(cycle); 38 | $display("enq pkt:: dest: %b, msg: %h", p.peer, p.msg); 39 | p2f.enq(p); 40 | testStage <= 1; 41 | endrule 42 | 43 | rule testP2F_deq(testPhase == P2F ); 44 | let f = p2f.first(); 45 | $display("deq flit:: src:%d dst:%d fid:%d pid:%d vid:%d data:%h", 46 | f.src, f.dest, f.fltId, f.pktId, f.vcId, f.data); 47 | p2f.deq(); 48 | endrule 49 | endmodule 50 | 51 | -------------------------------------------------------------------------------- /Cntr.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | // Implemens a cyclic bounded counter, when it reaches it's maximal value 5 | // it will automaticaly wrap to 0 6 | interface Cntr#(type t); 7 | // returns current value of a counter 8 | method t getCount(); 9 | // increments counter to next value 10 | method Action increment(); 11 | method Action decrement(); 12 | endinterface 13 | 14 | module mkCntr#(parameter Integer maxVaule) (Cntr#(t)) 15 | provisos(Bits#(t, tSz), Arith#(t), Eq#(t)); 16 | 17 | Reg#(t) counter <- mkReg(0); 18 | 19 | PulseWire increment_called <- mkPulseWire(); 20 | PulseWire decrement_called <- mkPulseWire(); 21 | 22 | rule count; 23 | Bool isCounterWrapAround = (counter == fromInteger(maxVaule)); 24 | Bool isCounterZero = (counter == 0); 25 | 26 | if (increment_called && !decrement_called) begin 27 | if (isCounterWrapAround) begin 28 | counter <= 0; 29 | //$display("@%4t cnt: wrap around to 0", $time); 30 | end 31 | else begin 32 | counter <= counter + 1; 33 | //$display("@%4t cnt: increment current value of %3d", $time, counter); 34 | end 35 | end 36 | else if (!increment_called && decrement_called) begin 37 | if (isCounterZero) 38 | counter <= 0; 39 | else 40 | counter <= counter - 1; 41 | end 42 | else begin // both inc/dec or none of them been called 43 | counter <= counter; 44 | end 45 | endrule 46 | 47 | method t getCount = counter; 48 | 49 | method Action decrement(); 50 | decrement_called.send(); 51 | endmethod 52 | 53 | method Action increment(); 54 | increment_called.send(); 55 | endmethod 56 | 57 | endmodule 58 | 59 | // (* synthesize *) 60 | // module mkCntr_Synth(Cntr#(Bit#(4))); 61 | // let c <- mkCntr(10); 62 | // return c; 63 | // endmodule 64 | -------------------------------------------------------------------------------- /IndexPool.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | //This module implements a pool of indexs. It starts when all entries are 5 | // ready to be allocated. Each time user may request to get one index 6 | // at a time until all indexes are allocated. 7 | // When user "finishes using an index" he should return that index to 8 | // the allocator (for future allocation) 9 | // 10 | import Fifo::*; 11 | 12 | interface Allocator#(numeric type n, type t); 13 | method t freeIndex(); 14 | method Action nextFree(); 15 | method Action deallocate(t index); 16 | method Bool notEmpty(); 17 | method Bool notFull(); 18 | method Bool isNotInitializing(); 19 | endinterface 20 | 21 | module mkIndexAllocator(Allocator#(n, t)) provisos (Bits#(t, tSz), Eq#(t), Arith#(t)); 22 | 23 | Fifo#(n,t) indexFifo <- mkCFFifo; 24 | 25 | Reg#(Bool) isInitDone <- mkReg(False); 26 | Reg#(t) ii <- mkReg(0); 27 | 28 | Integer depth = valueOf(n); 29 | 30 | //init the pool in first "n" # of cycles" 31 | rule initializePool if ( !isInitDone ); 32 | //$display("@%4t alc: initialize element #%02d", $time, ii); 33 | indexFifo.enq(ii); 34 | if (ii == fromInteger(depth-1)) 35 | isInitDone <= True; 36 | ii <= ii + 1; 37 | endrule 38 | 39 | method t freeIndex() if (isInitDone); 40 | return indexFifo.first; 41 | endmethod 42 | 43 | method Action nextFree() if (isInitDone); 44 | //$display("@%4t alc: calulate next after %d", $time, indexFifo.first); 45 | indexFifo.deq; 46 | endmethod 47 | 48 | method Action deallocate(t index) if (isInitDone); 49 | //$display("@%4t alc: deallocate index %3d", $time, index); 50 | indexFifo.enq(index); 51 | endmethod 52 | 53 | method Bool notEmpty = !indexFifo.notFull; 54 | 55 | method Bool notFull = !indexFifo.notEmpty; 56 | 57 | method Bool isNotInitializing = isInitDone; 58 | 59 | endmodule 60 | -------------------------------------------------------------------------------- /VcFifo.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | import CommonTypes::*; 5 | import Fifo::*; 6 | import FShow::*; 7 | import Arbiter::*; 8 | 9 | interface VcFifo#(numeric type nofNodes, 10 | numeric type fltSz, 11 | numeric type numVC); 12 | //put a flit into vc fifo 13 | method Action put(Flit_t#(nofNodes, fltSz, numVC) flit); 14 | 15 | //remove the topmost flit out of vc fifo 16 | method ActionValue#(Flit_t#(nofNodes, fltSz, numVC)) get(); 17 | endinterface 18 | 19 | module mkVcFifo(VcFifo#(nofNodes, fltSz, numVC)) 20 | provisos(Log#(numVC, numVCSz)); 21 | 22 | Integer nofVCs = valueOf(numVC); 23 | 24 | //vc fifos array - one fifo for each vc 25 | Fifo#(NofFlitsInPacket_t#(fltSz), 26 | Flit_t#(nofNodes, fltSz, numVC)) vcFifoArr[nofVCs]; 27 | 28 | //init loop to create all fifos 29 | for (Integer i = 0; i < nofVCs; i = i+ 1) begin 30 | vcFifoArr[i]<-mkCFFifo; 31 | end 32 | 33 | Bool isFixed = False; 34 | Arbiter_IFC#(numVC) arbiter <- mkArbiter(isFixed); 35 | 36 | 37 | ///////////////////////////////////////////////////////////////////// 38 | /// rules 39 | ///////////////////////////////////////////////////////////////////// 40 | for (Integer i=0; i < nofVCs; i = i + 1) begin 41 | //every non empty fifo bids the arbiter 42 | rule bid if ( vcFifoArr[i].notEmpty() ); 43 | arbiter.clients[i].request(); 44 | endrule 45 | end 46 | 47 | //////////////////////////////////////////////////////////////////// 48 | // interface methods implementation 49 | 50 | method Action put(Flit_t#(nofNodes, fltSz, numVC) flit); 51 | // $display("@%4t vcf: put fifoIdx:%1d ", 52 | // $time, flit.vcId /*,fshow(flit)*/); 53 | vcFifoArr[flit.vcId].enq(flit); 54 | endmethod 55 | 56 | method ActionValue#(Flit_t#(nofNodes, fltSz, numVC)) get(); 57 | //deque from current non empty fifo 58 | let winFifoId = arbiter.grant_id; 59 | // $display("@%4t vcf: get fifoIdx:%1d ", 60 | // $time, winFifoId /*,fshow(flit)*/); 61 | let res = vcFifoArr[winFifoId].first; 62 | vcFifoArr[winFifoId].deq; 63 | return res; 64 | endmethod 65 | 66 | endmodule 67 | 68 | 69 | // (* synthesize *) 70 | // module mkVcFifo_Synth(VcFifo#(4,32,4)); 71 | // let _u <- mkVcFifo; 72 | // return _u; 73 | // endmodule 74 | -------------------------------------------------------------------------------- /PacketFifo.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | import Fifo::*; 5 | import RWire::*; 6 | import FShow::*; 7 | 8 | ////////////////////////////////////////////////////////////////////// 9 | // module implementation ///////////////////////////////////////////// 10 | // 11 | // if timeOut > 0 each ready packed will be stored in the fifo for 12 | // timeOut clocks. After that if the client didn't fetched the data 13 | // it will be released. 14 | // if timeOut is 0 the data will never be released. 15 | // 16 | module mkPacketFifo#(parameter Integer timeOut) 17 | (Fifo#(size, t)) provisos (Bits#(t, tSz), FShow#(t)); 18 | 19 | Fifo#(size, t) fifo <- mkPipelineFifo; 20 | 21 | Reg#(int) ageCount <- mkReg(fromInteger(timeOut)); 22 | Wire#(Bool) resetAgeFromClear <- mkDWire(False); 23 | Wire#(Bool) resetAgeFromDeq <- mkDWire(False); 24 | 25 | Wire#(Bool) deqCommand <- mkDWire(False); 26 | Wire#(Bool) ageThresholdReached <- mkDWire(False); 27 | 28 | rule doDeque if (ageThresholdReached || deqCommand); 29 | if ( ageThresholdReached && !deqCommand) 30 | $display("@%4t pkf: age threshold reached, throw ", $time, fshow(fifo.first)); 31 | else if (!ageThresholdReached && deqCommand) 32 | $display("@%4t pkf: deque command, dequing pkt ", $time, fshow(fifo.first)); 33 | else 34 | $display("@%4t pkf: deque from age and command ", $time, fshow(fifo.first)); 35 | fifo.deq(); 36 | endrule 37 | 38 | if (timeOut > 0) begin 39 | 40 | // assert age threshold reached signal when deq haven't been called 41 | // during the last TIMEOUT number of cycles 42 | rule ageThreshold if (ageCount == fromInteger(timeOut)); 43 | ageThresholdReached <= True; 44 | endrule 45 | 46 | // control of the age counter 47 | rule ageControl if (fifo.notEmpty); 48 | if (resetAgeFromClear || resetAgeFromDeq || ageThresholdReached ) 49 | ageCount <= 0; 50 | else 51 | ageCount <= ageCount + 1; 52 | endrule 53 | 54 | end 55 | 56 | method Bool notFull = fifo.notFull; 57 | 58 | method Bool notEmpty = fifo.notEmpty; 59 | 60 | method t first = fifo.first; 61 | 62 | method Action deq; 63 | deqCommand <= True; 64 | if (timeOut > 0) 65 | resetAgeFromDeq <= True; 66 | endmethod 67 | 68 | method Action enq(t x); 69 | fifo.enq(x); 70 | endmethod 71 | 72 | method Action clear; 73 | fifo.clear; 74 | if (timeOut > 0) 75 | resetAgeFromClear <= True; 76 | endmethod 77 | 78 | endmodule 79 | -------------------------------------------------------------------------------- /RingForFpga.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | package RingForFpga; 5 | 6 | import CommonTypes::*; 7 | import RingNode::*; 8 | import Ring::*; 9 | 10 | ////////////////////////////////////////////////////////////////////// 11 | // define synthesizeable interface & module to be tested on FPGA 12 | ////////////////////////////////////////////////////////////////////// 13 | interface RingWith4Nodes; // define ring with 4 nodes ifc 14 | method Action enq0(Packet#(4) packet); 15 | method Packet#(4) first0(); 16 | method Action deq0(); 17 | 18 | method Action enq1(Packet#(4) packet); 19 | method Packet#(4) first1(); 20 | method Action deq1(); 21 | 22 | method Action enq2(Packet#(4) packet); 23 | method Packet#(4) first2(); 24 | method Action deq2(); 25 | 26 | method Action enq3(Packet#(4) packet); 27 | method Packet#(4) first3(); 28 | method Action deq3(); 29 | endinterface 30 | 31 | 32 | // implement ring with 4 node. Flit size is 8, number of VCs is 2 33 | module mkRingWith4Nodes(RingWith4Nodes); 34 | 35 | Integer iNofNodes = 4; 36 | 37 | RingNode#(4, 8, 2) nodeVector[4]; 38 | for (Integer i = 0; i < iNofNodes; i = i+ 1) begin 39 | nodeVector[i]<-mkRingNode(i); // create all ring nodes 40 | end 41 | 42 | // connect all nodes to form a ring /////////////////////////////// 43 | for (Integer i = 0; i < iNofNodes; i = i+ 1) begin 44 | 45 | let curNode = nodeVector[i]; 46 | let nextNode = nodeVector[(i+1)%iNofNodes]; 47 | 48 | rule putFlitToNext; 49 | let flit <-curNode.getUp(); 50 | nextNode.putDn(flit); 51 | endrule 52 | 53 | rule getFlitFromNext; 54 | let flit <-nextNode.getDn(); 55 | curNode.putUp(flit); 56 | endrule 57 | end 58 | 59 | // implement all the methods 60 | method Action enq0(Packet#(4) packet); 61 | nodeVector[0].enq(packet); 62 | endmethod 63 | method Packet#(4) first0 = nodeVector[0].first; 64 | method Action deq0 = nodeVector[0].deq; 65 | 66 | method Action enq1(Packet#(4) packet); 67 | nodeVector[1].enq(packet); 68 | endmethod 69 | method Packet#(4) first1 = nodeVector[1].first; 70 | method Action deq1 = nodeVector[1].deq; 71 | 72 | method Action enq2(Packet#(4) packet); 73 | nodeVector[2].enq(packet); 74 | endmethod 75 | method Packet#(4) first2 = nodeVector[2].first; 76 | method Action deq2 = nodeVector[2].deq; 77 | 78 | method Action enq3(Packet#(4) packet); 79 | nodeVector[3].enq(packet); 80 | endmethod 81 | method Packet#(4) first3 = nodeVector[3].first; 82 | method Action deq3 = nodeVector[3].deq; 83 | 84 | endmodule 85 | 86 | // now synthesize the synthesizable module :) 87 | (* synthesize *) 88 | module mkRingWith4Nodes_Synth(RingWith4Nodes); 89 | let _u <- mkRingWith4Nodes(); 90 | return _u; 91 | endmodule 92 | 93 | endpackage 94 | -------------------------------------------------------------------------------- /Ring.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | package Ring; 5 | 6 | import Vector::*; 7 | import FShow::*; 8 | import CommonTypes::*; 9 | import RingNode::*; 10 | 11 | ////////////////////////////////////////////////////////////////////// 12 | // IMPORTANT NOTE: 13 | // The following types: 14 | // PayloadSz 15 | // Payload 16 | // Packet 17 | // were moved to CommonTypes.bsv file. Otherwise they cause a circular 18 | // dependancy as explaned below: 19 | // 1. RingNode should include Ring to know these types hence 20 | // RingNode->Ring 21 | // 2. Ring should include RingNode cause it instantiates RingNodes to 22 | // form a ring :) thus: Ring->RingNode 23 | // Now 1 and 2 form a circular include depandancy 24 | // 25 | ////////////////////////////////////////////////////////////////////// 26 | 27 | typedef 32 FlitSize_t; // size of a flit, have to satisfy the equation 28 | // (packet_size % flit_size == 0) 29 | typedef 4 NumberOfVCs_t; // number of virtual channels in a system 30 | 31 | ////////////////////////////////////////////////////////////////////// 32 | /// Ring interface. The parameter is the type used to specify node IDs. 33 | ////////////////////////////////////////////////////////////////////// 34 | interface Ring#(numeric type nofNodes); 35 | 36 | // get a specific endpoint in the ring. 37 | method RingNode#(nofNodes, FlitSize_t, NumberOfVCs_t) 38 | getNode(Bit#(TLog#(nofNodes)) idx); 39 | 40 | endinterface 41 | 42 | ////////////////////////////////////////////////////////////////////// 43 | /// module implementation 44 | ////////////////////////////////////////////////////////////////////// 45 | module mkRing(Ring#(nofNodes)); 46 | 47 | Integer iNofNodes = valueOf(nofNodes); 48 | 49 | RingNode#(nofNodes, FlitSize_t, NumberOfVCs_t) nodeVector[valueOf(nofNodes)]; 50 | for (Integer i = 0; i < iNofNodes; i = i+ 1) begin 51 | nodeVector[i]<-mkRingNode(i); // create all ring nodes 52 | end 53 | 54 | // connect all nodes to form a ring /////////////////////////////// 55 | for (Integer i = 0; i < iNofNodes; i = i+ 1) begin 56 | 57 | let curNode = nodeVector[i]; 58 | let nextNode = nodeVector[(i+1)%iNofNodes]; 59 | 60 | rule putFlitToNext; 61 | let flit <- curNode.getUp(); 62 | $display("@%4t rn%1d: sending flit to Up-Ring ... ", 63 | $time, i, fshow(flit)); 64 | nextNode.putDn(flit); 65 | endrule 66 | 67 | rule getFlitFromNext; 68 | let flit <- nextNode.getDn(); 69 | $display("@%4t rn%1d: getting flit from Up-Ring ... ", 70 | $time, i, fshow(flit)); 71 | curNode.putUp(flit); 72 | endrule 73 | end 74 | 75 | ////////////////////////////////////////////////////////////////////// 76 | method RingNode#(nofNodes, FlitSize_t, NumberOfVCs_t) 77 | getNode(Bit#(TLog#(nofNodes)) idx); 78 | return nodeVector[idx]; 79 | endmethod 80 | 81 | endmodule 82 | 83 | 84 | endpackage 85 | -------------------------------------------------------------------------------- /CommonTypes.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | /** 5 | * Define all common types that are being used in this project 6 | */ 7 | import FShow::*;// for being able to "pretty print" types defined below 8 | 9 | ////////////////////////////////////////////////////////////////////// 10 | // Important note: 11 | // Type definitions from Ring.bsv appears here to remove inclusion 12 | // of Ring.bsv from all other modules which eventually cause cyrcular 13 | // dependancy 14 | ////////////////////////////////////////////////////////////////////// 15 | 16 | typedef 256 PayloadSz; // data size received by the node from a client. 17 | typedef Bit#(PayloadSz) Payload; 18 | 19 | typedef struct { // data packet received from the client (user) 20 | Bit#(TLog#(nodeNum)) peer; // destination Id of the receiving node 21 | Payload msg; // data itself to be send to a peer 22 | } Packet#(type nodeNum) deriving(Bits, Eq); 23 | 24 | 25 | ////////////////////////////////////////////////////////////////////// 26 | // other typedefs 27 | ////////////////////////////////////////////////////////////////////// 28 | 29 | //number of flits in a packet 30 | typedef TDiv#(PayloadSz, fltSz) 31 | NofFlitsInPacket_t#(numeric type fltSz); 32 | 33 | // size of packet id field in bits 34 | typedef 4 PacketIdSize_t; 35 | 36 | // represent packet id 37 | typedef Bit#(PacketIdSize_t) PacketId_t; 38 | 39 | // holds flit's data 40 | typedef Bit#(fltSz) FlitPayload_t#(numeric type fltSz); 41 | 42 | // represent flit's id, calc size of flit id field in bits from 43 | // proveded types 44 | typedef Bit#(TLog#(TDiv#(PayloadSz, fltSz))) 45 | FlitId_t#(numeric type fltSz); 46 | 47 | // address of a node on a ring 48 | typedef Bit#(TLog#(nofNodes)) 49 | Address_t#(numeric type nofNodes); 50 | 51 | // represend a VC type of a flit 52 | typedef Bit#(TLog#(numVC)) 53 | VcId_t#(numeric type numVC); 54 | 55 | // a header of tagged flit 56 | typedef struct{ 57 | Address_t#(nofNodes) src; //flit's sender address 58 | Address_t#(nofNodes) dest; //flit's destination address 59 | FlitId_t#(fltSz) fltId;//flit's id 60 | PacketId_t pktId;//source packet id 61 | VcId_t#(numVC) vcId; //VC of a flit 62 | FlitPayload_t#(fltSz) data; //flit's data 63 | } Flit_t#(numeric type nofNodes, 64 | numeric type fltSz, 65 | numeric type numVC) deriving (Bits, Eq); 66 | 67 | 68 | ////////////////////////////////////////////////////////////////////// 69 | // define show methods for common types for easy printing... 70 | instance FShow#(Flit_t#(nofNodes, flitSz, numVC)) ; 71 | function Fmt fshow ( Flit_t#(nofNodes, flitSz, numVC) f); 72 | return $format("" 73 | ,f.src, f.dest, f.fltId, f.pktId, f.vcId, f.data); 74 | endfunction 75 | endinstance 76 | 77 | instance FShow#(Packet#(nodeNum)) ; 78 | function Fmt fshow ( Packet#(nodeNum) p); 79 | return $format("", p.peer, p.msg); 80 | endfunction 81 | endinstance 82 | 83 | -------------------------------------------------------------------------------- /project.bld: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | default-targets: dut_tb_ring 3 | bsc-compile-options: -aggressive-conditions -keep-fires -u 4 | bsc-link-options: -keep-fires 5 | 6 | [common] 7 | hide-target 8 | bsv-source-directories: . 9 | verilog-directory: build_verilog 10 | binary-directory: build_bin 11 | simulation-directory: build_sim 12 | info-directory: build_info 13 | altera-directory: build_quartus 14 | xilinx-directory: build_xilinx 15 | log-directory: build_logs 16 | bsc-compile-options: -sched-dot -show-schedule 17 | build-for: bluesim 18 | 19 | [dut_tb_ring] 20 | extends-target: common 21 | exe-file: dut_tb_ring.bin 22 | top-module: mkRingTestBench 23 | top-file: ./TestBenchRing.bsv 24 | 25 | [dut_tb_ringnode] 26 | extends-target: common 27 | exe-file: dut_tb_ringnode.bin 28 | top-module: mkRingNodeTestBench 29 | top-file: ./TestBenchRingNode.bsv 30 | 31 | [dut_tb_f2p] 32 | extends-target: common 33 | exe-file: dut_tb_f2p.bin 34 | top-module: mkF2PTestBench 35 | top-file: ./TestBenchF2P.bsv 36 | 37 | [dut_tb_p2f] 38 | extends-target: common 39 | exe-file: dut_tb_p2f.bin 40 | top-module: mkP2FTestBench 41 | top-file: ./TestBenchP2F.bsv 42 | 43 | [dut_tb_vcfifo] 44 | extends-target: common 45 | exe-file: dut_tb_vcfifo.bin 46 | top-module: mkVcFifoTestBench 47 | top-file: ./TestBenchVcFifo.bsv 48 | 49 | [dut_tb_xbr] 50 | extends-target: common 51 | exe-file: dut_tb_xbr.bin 52 | top-module: mkCrossBarTestBench 53 | top-file: ./TestBenchXbr.bsv 54 | 55 | ########################## 56 | # generate verilog code: # 57 | ########################## 58 | 59 | [vlog_dut_ring] 60 | extends-target: common 61 | build-for: verilog 62 | top-module: mkRingWith4Nodes_Synth 63 | top-file: RingForFpga.bsv 64 | 65 | [vlog_dut_tb_xbr] 66 | extends-target: common 67 | build-for: verilog 68 | top-module: mkCrossBarTestBench 69 | top-file: TestBenchXbr.bsv 70 | 71 | [vlog_dut_tb_vcfifo] 72 | extends-target: common 73 | build-for: verilog 74 | top-module: mkVcFifoTestBench 75 | top-file: TestBenchVcFifo.bsv 76 | 77 | [vlog_dut_tb_p2f] 78 | extends-target: common 79 | build-for: verilog 80 | top-module: mkP2FTestBench 81 | top-file: TestBenchP2F.bsv 82 | 83 | [vlog_dut_tb_f2p] 84 | extends-target: common 85 | build-for: verilog 86 | top-module: mkF2PTestBench 87 | top-file: TestBenchF2P.bsv 88 | 89 | ################## 90 | # build for fpga # 91 | ################## 92 | [fpga] 93 | top-module: mkRingWith4Nodes_Synth 94 | extends-target: common 95 | scemi-tb 96 | build-for: xupv5 97 | xilinx-map-options: -detail -u 98 | exe-file: tb 99 | xilinx-ucf-file: ./xupv5.ucf 100 | top-file: ./RingForFpga.bsv 101 | -------------------------------------------------------------------------------- /xupv5.ucf: -------------------------------------------------------------------------------- 1 | #NET CLK_27MHZ_FPGA LOC="AG18"; # Bank 4, Vcco=3.3V, No DCI 2 | #NET CLK_33MHZ_FPGA LOC="AH17"; # Bank 4, Vcco=3.3V, No DCI 3 | #NET CLK_FPGA_N LOC="K19"; # Bank 3, Vcco=2.5V, No DCI 4 | #NET CLK_FPGA_P LOC="L19"; # Bank 3, Vcco=2.5V, No DCI 5 | 6 | # Bank 4, Vcco=3.3V, No DCI 7 | NET "CLK" LOC = AH15; //100MHz clock 8 | 9 | 10 | #NET FPGA_CPU_RESET_B LOC="E9"; # Bank 20, Vcco=3.3V, DCI using 49.9 ohm 11 | #NET RST_N LOC="E9"; # Bank 20, Vcco=3.3V, DCI using 49.9 ohm 12 | 13 | #NET GPIO_LED_0 LOC="H18"; # Bank 3, Vcco=2.5V, No DCI 14 | #NET GPIO_LED_1 LOC="L18"; # Bank 3, Vcco=2.5V, No DCI 15 | #NET GPIO_LED_2 LOC="G15"; # Bank 3, Vcco=2.5V, No DCI 16 | #NET GPIO_LED_3 LOC="AD26"; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors 17 | #NET GPIO_LED_4 LOC="G16"; # Bank 3, Vcco=2.5V, No DCI 18 | #NET GPIO_LED_5 LOC="AD25"; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors 19 | #NET GPIO_LED_6 LOC="AD24"; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors 20 | #NET GPIO_LED_7 LOC="AE24"; # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors 21 | #NET GPIO_LED_C LOC="E8"; # Bank 20, Vcco=3.3V, DCI using 49.9 ohm resistors 22 | #NET GPIO_LED_E LOC="AG23"; # Bank 2, Vcco=3.3V 23 | #NET GPIO_LED_N LOC="AF13"; # Bank 2, Vcco=3.3V 24 | #NET GPIO_LED_S LOC="AG12"; # Bank 2, Vcco=3.3V 25 | #NET GPIO_LED_W LOC="AF23"; # Bank 2, Vcco=3.3V 26 | 27 | # Bank 3, Vcco=2.5V, No DCI 28 | # Bank 3, Vcco=2.5V, No DCI 29 | #NET "leds_pins_LED[1]" LOC = L18; 30 | # Bank 3, Vcco=2.5V, No DCI 31 | #NET "leds_pins_LED[2]" LOC = G15; 32 | # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors 33 | #NET "leds_pins_LED[3]" LOC = AD26; 34 | # Bank 3, Vcco=2.5V, No DCI 35 | #NET "leds_pins_LED[4]" LOC = G16; 36 | # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors 37 | #NET "leds_pins_LED[5]" LOC = AD25; 38 | # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors 39 | #NET "leds_pins_LED[6]" LOC = AD24; 40 | # Bank 21, Vcco=1.8V, DCI using 49.9 ohm resistors 41 | #NET "leds_pins_LED[7]" LOC = AE24; 42 | # Bank 20, Vcco=3.3V, DCI using 49.9 ohm resistors 43 | #NET "leds_pins_LED[8]" LOC = E8; 44 | # Bank 2, Vcco=3.3V 45 | #NET "leds_pins_LED[9]" LOC = AG23; 46 | # Bank 2, Vcco=3.3V 47 | #NET "leds_pins_LED[10]" LOC = AF13; 48 | # Bank 2, Vcco=3.3V 49 | #NET "leds_pins_LED[11]" LOC = AG12; 50 | # Bank 2, Vcco=3.3V 51 | #NET "leds_pins_LED[12]" LOC = AF23; 52 | 53 | 54 | #NET GPIO_SW_C LOC="AJ6"; # Bank 18, Vcco=3.3V, No DCI 55 | #NET GPIO_SW_E LOC="AK7"; # Bank 18, Vcco=3.3V, No DCI 56 | #NET GPIO_SW_N LOC="U8"; # Bank 18, Vcco=3.3V, No DCI 57 | #NET GPIO_SW_S LOC="V8"; # Bank 18, Vcco=3.3V, No DCI 58 | #NET GPIO_SW_W LOC="AJ7"; # Bank 18, Vcco=3.3V, No DCI 59 | 60 | 61 | 62 | NET "RST_N" LOC = E9; 63 | #NET "leds_pins_LED[0]" LOC = H18; 64 | 65 | 66 | NET "CLK" IOSTANDARD = LVCMOS33; 67 | NET "RST_N" IOSTANDARD = LVCMOS33; 68 | #NET "leds_pins_LED[3]" IOSTANDARD = LVDCI_18; 69 | #NET "leds_pins_LED[4]" IOSTANDARD = LVCMOS25; 70 | #NET "leds_pins_LED[5]" IOSTANDARD = LVDCI_18; 71 | #NET "leds_pins_LED[6]" IOSTANDARD = LVDCI_18; 72 | #NET "leds_pins_LED[7]" IOSTANDARD = LVDCI_18; 73 | #NET "leds_pins_LED[8]" IOSTANDARD = LVDCI_33; 74 | #NET "leds_pins_LED[9]" IOSTANDARD = LVCMOS33; 75 | #NET "leds_pins_LED[10]" IOSTANDARD = LVCMOS33; 76 | #NET "leds_pins_LED[11]" IOSTANDARD = LVCMOS33; 77 | #NET "leds_pins_LED[12]" IOSTANDARD = LVCMOS33; 78 | NET "RST_N" PULLUP; 79 | 80 | 81 | #NET "RST_N" DRIVE = 12; 82 | #NET "RST_N" SLEW = SLOW; 83 | 84 | 85 | #NET "uart_pins_serial_tx" LOC = AG20; 86 | 87 | 88 | 89 | #NET "uart_pins_serial_tx" IOSTANDARD = LVCMOS33; 90 | 91 | 92 | #NET "uart_pins_serial_tx" DRIVE = 12; 93 | #NET "uart_pins_serial_tx" SLEW = SLOW; 94 | 95 | # PlanAhead Generated physical constraints 96 | 97 | #NET "uart_pins_serial_rx" LOC = AG15; 98 | 99 | # PlanAhead Generated IO constraints 100 | 101 | # NET "uart_pins_serial_rx" IOSTANDARD = LVCMOS33; 102 | -------------------------------------------------------------------------------- /TestBenchRing.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | import Ring::*; 5 | import RingNode::*; 6 | import CommonTypes::*; 7 | import StmtFSM::*; 8 | import FShow::*; 9 | import Fifo::*; 10 | import Vector::*; 11 | 12 | typedef 4 NofNodes_t; // num of nodes in a ring 13 | typedef 4 NofPackets_t; // num of packets to be sent in this test 14 | 15 | // helps to get unique payload for each packet 16 | function Payload getNextPayload(Payload p); 17 | Bit#(256) incr = 256'h00000008_00000008_00000008_00000008_00000008_00000008_00000008_00000008; 18 | return (p + incr); 19 | endfunction 20 | 21 | // convert from integer to address type 22 | function Address_t#(NofNodes_t) addressFromInteger (Integer a); 23 | Address_t#(NofNodes_t) c = fromInteger(a) ; 24 | return(c); 25 | endfunction 26 | 27 | (* synthesize *) 28 | module mkRingTestBench(); 29 | 30 | Bit#(TLog#(NofNodes_t)) nodeId = 1; // source node that send all packets 31 | Integer maxCyclesToRun = 200; 32 | Integer numberOfNodes = valueOf(NofNodes_t); 33 | 34 | Ring#(NofNodes_t) ring <- mkRing(); 35 | 36 | // fifos that immitates ring nodes, we will test each recieved 37 | // packet in a j's ring node with packet in j's fifo 38 | Vector#(NofNodes_t, Fifo#(NofPackets_t, Packet#(NofNodes_t))) 39 | sentPacketFifos <- replicateM(mkPipelineFifo); 40 | 41 | // holds all destination addresses that we gonna send in this test 42 | Vector#(NofNodes_t, Address_t#(NofNodes_t)) destinations = genWith(addressFromInteger); 43 | // override the destinations if needed 44 | // destinations[0] = 3; 45 | // destinations[1] = 0; 46 | // destinations[2] = 3; 47 | // destinations[3] = 1; 48 | 49 | Reg#(int) cycle <- mkReg(1); 50 | Reg#(Packet#(NofNodes_t)) packet <- mkReg(Packet{peer: 1, 51 | msg: 256'h00000007_00000006_00000005_00000004_00000003_00000002_00000001_00000000}); 52 | Reg#(int) i0 <- mkReg(0); 53 | 54 | //////////////////////////////////////////////////////////////////////////////// 55 | /// sequences 56 | //////////////////////////////////////////////////////////////////////////////// 57 | 58 | // put a packet(s) into 0'th ring node. put the same packet into sentPacketFifos 59 | // for verification 60 | Stmt enqSeq = 61 | seq 62 | while ( i0 < fromInteger(valueOf(NofPackets_t)) ) action 63 | Packet#(NofNodes_t) p = Packet{peer: destinations[i0], 64 | msg : getNextPayload(packet.msg)}; 65 | $display("@%4t tst: enq packet ... ", $time, fshow(p)); 66 | sentPacketFifos[p.peer].enq(p); //put pkt into a dest fifo for test 67 | ring.getNode(nodeId).enq(p); //put pkt into src node (to be transmitted to dest node) 68 | packet <= p; 69 | i0 <= i0+1; 70 | endaction 71 | endseq; 72 | 73 | FSM enqFSM <- mkFSM(enqSeq); 74 | 75 | //////////////////////////////////////////////////////////////////////////////// 76 | /// rules 77 | //////////////////////////////////////////////////////////////////////////////// 78 | 79 | for (Integer i=0; i fromInteger(maxCyclesToRun)); 111 | $display("Timeout termination cycle count %d", cycle); 112 | $finish(); 113 | endrule 114 | 115 | rule clockCount; 116 | $display("== cycle %03d @%3t ==", cycle, $time); 117 | cycle <= cycle + 1; 118 | endrule 119 | 120 | endmodule 121 | -------------------------------------------------------------------------------- /PacketToFlit.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | /** 5 | * Implements all moduel related to PacketToFlit module 6 | */ 7 | import FShow::*; 8 | import CommonTypes::*; 9 | import Fifo::*; //for pipleind n-elemenst fifos 10 | import SpecialFIFOs::*; //for pipelined standard fifos (1-elements) 11 | import FIFOF::*; 12 | import Vector::*; 13 | import Cntr::*; 14 | 15 | ////////////////////////////////////////////////////////////////////// 16 | ////////////////////////////////////////////////////////////////////// 17 | ////////////////////////////////////////////////////////////////////// 18 | 19 | interface PacketToFlit#(numeric type nofNodes, 20 | numeric type fltSz, 21 | numeric type numVC); 22 | // put the packet into the unit, will be invoked by clinet 23 | method Action enq(Packet#(nofNodes) packet); 24 | // read a topmost flit of a unit, will invoked by VCFiFo 25 | method Flit_t#(nofNodes, fltSz, numVC) first(); 26 | // remove the topmost flit and put the next one (if any) instead 27 | method Action deq(); 28 | // true if the unit has any flits in it 29 | method Bool notEmpty(); 30 | // true if the unit can accept more packets from a client 31 | method Bool notFull(); 32 | endinterface 33 | 34 | module mkPacketToFlit#(parameter Integer nodeId) 35 | (PacketToFlit#(nofNodes, fltSz, numVC)); 36 | 37 | //some ints i'm using here 38 | Integer flitFifoSize = valueOf(NofFlitsInPacket_t#(fltSz)); 39 | Integer pktCountLim = valueOf(TSub#(TExp#(PacketIdSize_t), 1)); 40 | Integer fltCountLim = flitFifoSize - 1; 41 | Integer vcCountLim = valueOf(numVC) - 1; 42 | 43 | //fifos 44 | FIFOF#(Packet#(nofNodes)) packetFifo <- mkPipelineFIFOF; 45 | Fifo#(NofFlitsInPacket_t#(fltSz), 46 | Flit_t#(nofNodes, fltSz, numVC)) flitFifo <- mkPipelineFifo; 47 | //counters 48 | Cntr#(PacketId_t) pktCount <- mkCntr(pktCountLim); 49 | Cntr#(FlitId_t#(fltSz)) fltCount <- mkCntr(fltCountLim); 50 | Cntr#(VcId_t#(numVC)) vcCount <- mkCntr(vcCountLim); 51 | 52 | /****************************************************************** 53 | * This rule is activezed when we have a packet in a packetFifo. 54 | * Then every cycle we will enque a flit out of the arrived packet 55 | * into the flitFifo 56 | *****************************************************************/ 57 | rule enqFlit if (packetFifo.notEmpty && flitFifo.notFull); 58 | 59 | Flit_t#(nofNodes, fltSz, numVC) flit = ?; 60 | Bit#(PayloadSz) packet = pack(packetFifo.first.msg); 61 | FlitPayload_t#(fltSz) flitsArr[flitFifoSize]; 62 | 63 | //split the packet vector into vector of flits 64 | for( Integer i = 0; i < flitFifoSize; i = i + 1 ) begin 65 | flitsArr[i] = packet[ (i+1)*valueOf(fltSz) - 1 : i*valueOf(fltSz)]; 66 | end 67 | 68 | //update flit's fields 69 | flit.src = fromInteger(nodeId); 70 | flit.dest = packetFifo.first.peer; 71 | flit.fltId = fltCount.getCount; 72 | flit.pktId = pktCount.getCount; 73 | flit.vcId = vcCount.getCount; 74 | flit.data = flitsArr[fltCount.getCount]; //choose the appropriate flit 75 | 76 | // $display("@%4t p2f: enq flit ", $time, fshow(flit)); 77 | 78 | flitFifo.enq(flit); 79 | 80 | //it's a last flit of a pkt 81 | if (fltCount.getCount == fromInteger(fltCountLim)) begin 82 | pktCount.increment; 83 | vcCount.increment; 84 | packetFifo.deq; 85 | end 86 | fltCount.increment; 87 | 88 | endrule 89 | 90 | /////////////////////////////////////////////////////////////////// 91 | /// methods implementation 92 | /////////////////////////////////////////////////////////////////// 93 | method Action enq(Packet#(nofNodes) packet) if (packetFifo.notFull); 94 | // $display("@%4t p2f: enq packet ", $time, fshow(packet)); 95 | packetFifo.enq(packet); 96 | endmethod 97 | 98 | method Action deq() if (flitFifo.notEmpty); 99 | // $display("@%4t p2f: deq flit ", $time, fshow(flitFifo.first)); 100 | flitFifo.deq; 101 | endmethod 102 | 103 | method Flit_t#(nofNodes,fltSz,numVC) first = flitFifo.first; 104 | 105 | method Bool notEmpty = flitFifo.notEmpty; 106 | 107 | method Bool notFull = packetFifo.notFull; 108 | 109 | 110 | 111 | endmodule 112 | -------------------------------------------------------------------------------- /Ehr.bsv: -------------------------------------------------------------------------------- 1 | // Ehr.bsv 2 | // 3 | // The functional design is all Nirav's (ndave@mit.edu) fault. 4 | // Forward complaints/commentary in that direction. Myron 5 | // (mdk@mit.edu) added probes to it for proper scheduling 6 | // 7 | // The iterative design is all Myron's fault, since he thought 8 | // an alternative approach would help him understand what was 9 | // eventually revealed to be a bug in the bluespec compiler! 10 | // 11 | // The two implementations (mkEhr and mkEhrF) are functionally 12 | // identical. 13 | // 14 | // NOTE: THIS IS VERY IMPORTANT!!! 15 | // 16 | // Neither of these two modules (mkEhr or mkEhrF) should be used 17 | // without being enclosed immediately in a synthesize boundry. 18 | // This is due to bug in the Bluespec compiler which really 19 | // screws things up. Finding this out was painful. Avoid the 20 | // pain and follow this warning --myron 21 | // 22 | // Second point: These two Ehr implementations are close to what 23 | // Dan Rosenband outlined in his thesis. What they lack is 24 | // scheduling constraints between read/write pairs. That is to 25 | // say that read_1 and write_1 are conflict free whereas they 26 | // should be FORCED to schedule read_1 < write_1 ... 27 | 28 | import Vector ::*; 29 | import RWire ::*; 30 | import Probe ::*; 31 | 32 | typedef Vector#(n_sz, Reg#(alpha)) Ehr#(type n_sz, type alpha); 33 | 34 | // mkVirtualReg adds one level of ephemeralness to 'base'. 'state' 35 | // is the concrete interface underlying the virtual register (the 36 | // register itself). With state and base as input, mkVirtualReg 37 | // connects them with Rwires and probes so as to enforce the proper 38 | // rule scheduling and behavior: 39 | // ... < read_n < write_n < read_n+1 < write_n+1 < ... 40 | 41 | module mkVirtualReg#(Reg#(alpha) state, Reg#(alpha) base) 42 | (Tuple2#(Reg#(alpha), Reg#(alpha))) provisos(Bits#(alpha,asz)); 43 | 44 | // enforce ordering and data forewarding using wires and probes 45 | RWire#(alpha) w <- mkRWire(); 46 | Probe#(alpha) probe <- mkProbe; 47 | 48 | Reg#(alpha) i0 = interface Reg 49 | method _read(); 50 | return base._read(); 51 | endmethod 52 | method Action _write(x); 53 | w.wset(x); 54 | probe <= base._read(); 55 | endmethod 56 | endinterface; 57 | 58 | Reg#(alpha) i1 = interface Reg 59 | method _read() = fromMaybe(base._read, w.wget()); 60 | method _write(x) = noAction; // never used 61 | endinterface; 62 | 63 | return (tuple2(i0,i1)); 64 | 65 | endmodule 66 | 67 | // Creates an Ehr module by layering virtual registers 68 | // .idx[i] holds read_i and write_i methods. reg.read_n 69 | // is expressec as reg[n]._read(); 70 | 71 | module mkEhrF#(alpha init)(Ehr#(n,alpha)) provisos(Bits#(alpha, asz), 72 | Add#(li, 1, n)); 73 | 74 | Reg#(alpha) r <- mkReg(init); 75 | 76 | Vector#(n,Reg#(alpha)) vidx = newVector(); 77 | 78 | // 'old' is a placeholder which also ensures that the last-written value 79 | // won't get dropped since r and old are both the initial register during 80 | // the first iteration of the 'for' loop. 81 | Reg #(alpha) old = r; 82 | Tuple2#(Reg#(alpha),Reg#(alpha)) tinf; 83 | 84 | // make interfaces 85 | for(Integer i = 0; i < valueOf(n); i = i + 1) 86 | begin 87 | tinf <- mkVirtualReg(r,old); 88 | vidx[i] = tinf.fst(); 89 | old = tinf.snd(); 90 | end 91 | 92 | rule do_stuff(True); 93 | r <= tinf.snd._read(); 94 | endrule 95 | 96 | return vidx; 97 | 98 | endmodule 99 | 100 | /*********************************************************************/ 101 | // alternate implementation, not quite as cool as the functional 102 | // version by Nirav, but less code and possibly easier to understand 103 | /*********************************************************************/ 104 | 105 | module mkEhr#(alpha init) (Ehr#(n,alpha)) provisos(Bits#(alpha, asz), 106 | Add#(li, 1, n)); 107 | 108 | Reg#(alpha) r <- mkReg(init); 109 | Vector#(n, RWire#(alpha)) wires <- replicateM(mkRWire); 110 | Vector#(n, RWire#(alpha)) probes <- replicateM(mkRWire); 111 | Vector#(n, Reg#(alpha)) vidx = newVector(); 112 | Vector#(n, alpha) chain = newVector(); 113 | 114 | for(Integer i = 0; i < valueOf(n); i = i + 1) 115 | begin 116 | if(i==0) chain[i] = r; 117 | else chain[i] = fromMaybe(chain[i-1], wires[i-1].wget()); 118 | end 119 | 120 | for(Integer j = 0; j < valueOf(n); j = j + 1) 121 | begin 122 | vidx[j] = interface Reg 123 | method _read(); 124 | return chain[j]; 125 | endmethod 126 | method Action _write(x); 127 | wires[j].wset(x); 128 | probes[j].wset(chain[j]); 129 | endmethod 130 | endinterface; 131 | end 132 | 133 | 134 | (*fire_when_enabled, no_implicit_conditions *) 135 | rule do_stuff(True); 136 | r <= fromMaybe(chain[valueOf(li)], wires[valueOf(li)].wget()); 137 | endrule 138 | 139 | return vidx; 140 | 141 | endmodule 142 | 143 | interface Ehr2BSV#(type t); 144 | interface Reg#(t) r1; 145 | interface Reg#(t) r2; 146 | endinterface 147 | 148 | (* synthesize *) 149 | module mkEhr2BSV (Ehr2BSV#(Bit#(32))); 150 | Ehr#(2,Bit#(32)) ehr <- mkEhr(0); 151 | interface r1 = ehr[0]; 152 | interface r2 = ehr[1]; 153 | endmodule -------------------------------------------------------------------------------- /TestBenchRingNode.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | import RingNode::*; 5 | import CommonTypes::*; 6 | import StmtFSM::*; 7 | import FShow::*; 8 | import Vector::*; 9 | 10 | //////////////////////////////////////////////////////////////////////////////// 11 | /// types 12 | //////////////////////////////////////////////////////////////////////////////// 13 | 14 | typedef 32 FlitSize_t; 15 | typedef 4 NumberOfVCs_t; 16 | typedef 4 NofNodes_t; 17 | 18 | //////////////////////////////////////////////////////////////////////////////// 19 | /// helper functions 20 | //////////////////////////////////////////////////////////////////////////////// 21 | 22 | // helps to generate unique packet payload by incrementing a given's packet 23 | // payload 24 | function Packet#(NofNodes_t) generateNextPacket(Packet#(NofNodes_t) p); 25 | Bit#(256) incr = 256'h00000008_00000008_00000008_00000008_00000008_00000008_00000008_00000008; 26 | Bit#(256) msg = p.msg; 27 | p.msg = msg + incr; 28 | return p; 29 | endfunction 30 | 31 | // same a above but for flit's payload 32 | function Flit_t#(NofNodes_t, FlitSize_t, NumberOfVCs_t) 33 | generateNextFlit(Flit_t#(NofNodes_t, FlitSize_t, NumberOfVCs_t) flit, 34 | Address_t#(NofNodes_t) address ); 35 | flit.data = flit.data + 'h8; 36 | flit.dest = address; 37 | return flit; 38 | endfunction 39 | 40 | // convert integer to address type 41 | function Address_t#(NofNodes_t) addressFromInteger (Integer a); 42 | Address_t#(NofNodes_t) c = fromInteger(a) ; 43 | return(c); 44 | endfunction 45 | 46 | //////////////////////////////////////////////////////////////////////////////// 47 | /// module 48 | //////////////////////////////////////////////////////////////////////////////// 49 | 50 | (* synthesize *) 51 | module mkRingNodeTestBench(); 52 | Integer nodeId = 0; 53 | Integer maxCyclesToRun = 40; 54 | 55 | 56 | RingNode#(NofNodes_t, FlitSize_t, NumberOfVCs_t) node <- mkRingNode(nodeId); 57 | 58 | 59 | Reg#(int) cycle <- mkReg(1); 60 | Reg#(Packet#(NofNodes_t)) packet <- mkReg(Packet{peer: 1, 61 | msg: 256'h00000007_00000006_00000005_00000004_00000003_00000002_00000001_00000000}); 62 | Reg#(Flit_t#(NofNodes_t, FlitSize_t, NumberOfVCs_t)) flit <- mkReg(Flit_t{src: fromInteger(nodeId) , 63 | dest: 0, 64 | fltId: 1, 65 | pktId: 2, 66 | vcId: 0, 67 | data: 'hdeadbeaf}); 68 | Vector#(NofNodes_t, Address_t#(NofNodes_t)) destinations = genWith(addressFromInteger); 69 | 70 | Reg#(int) i0 <- mkReg(0); 71 | 72 | ////////////////////////////////////////////////////////////////////// 73 | // sequences 74 | ////////////////////////////////////////////////////////////////////// 75 | Stmt clientEnqSeq = 76 | seq 77 | action 78 | $display("@%4t tst: client port enq packet ", $time, fshow(packet)); 79 | node.enq(packet); 80 | packet <= generateNextPacket(packet); 81 | endaction 82 | // await(node.notFull); 83 | // action 84 | // Packet#(NofNodes_t) p = Packet{peer:2, msg:packet.msg}; 85 | // $display("@%4t tst: client port enq packet ", $time, fshow(p)); 86 | // node.enq(p); 87 | // packet <= generateNextPacket(p); 88 | // endaction 89 | endseq; 90 | 91 | Stmt upEnqSeq = 92 | seq 93 | while( i0 < fromInteger(valueOf(NofNodes_t)) ) action 94 | $display("@%4t tst: dn port put packet ", $time, fshow(flit), " i0: %2d", i0); 95 | node.putDn(flit); 96 | flit <= generateNextFlit(flit, destinations[i0]); 97 | i0 <= i0 + 1; 98 | endaction 99 | endseq; 100 | 101 | Stmt clientDrainSeq = 102 | seq 103 | while (True) action 104 | await (node.notEmpty); 105 | action 106 | $display("@%4t tst: client port deq packet ", 107 | $time, fshow(node.first)); 108 | node.deq(); 109 | endaction 110 | endaction 111 | endseq; 112 | 113 | Stmt upDrainSeq = 114 | seq 115 | while (True) action 116 | let flit <- node.getUp; 117 | $display("@%4t tst: up port get packet ", $time, fshow(flit)); 118 | endaction 119 | endseq; 120 | 121 | Stmt downDrainSeq = 122 | seq 123 | while (True) action 124 | let flit <- node.getDn; 125 | $display("@%4t tst: dn port get packet ", $time, fshow(flit)); 126 | endaction 127 | endseq; 128 | 129 | FSM clientPortEnqFSM <- mkFSM(clientEnqSeq); 130 | FSM upPortEnqFSM <- mkFSM(upEnqSeq); 131 | FSM clientDrainFSM <- mkFSM(clientDrainSeq); 132 | FSM upDrainFSM <- mkFSM(upDrainSeq); 133 | FSM downDrainFSM <- mkFSM(downDrainSeq); 134 | 135 | ////////////////////////////////////////////////////////////////////// 136 | // rules: 137 | ////////////////////////////////////////////////////////////////////// 138 | 139 | rule timeout if (cycle > fromInteger(maxCyclesToRun)); 140 | $display("Timeout termination cycle count %d", cycle); 141 | $finish(); 142 | endrule 143 | 144 | rule clockCount; 145 | $display("== cycle %03d @%3t ==", cycle, $time); 146 | cycle <= cycle + 1; 147 | endrule 148 | 149 | rule startTest if (cycle == 1); 150 | clientPortEnqFSM.start; 151 | //upPortEnqFSM.start; 152 | clientDrainFSM.start; 153 | upDrainFSM.start; 154 | downDrainFSM.start; 155 | for ( Integer i=0; i fromInteger(maxCyclesToRun)); 156 | $display("Timeout termination cycle count %d", cycle); 157 | $finish(); 158 | endrule 159 | 160 | rule clockCount; 161 | $display("== cycle %03d @%3t ==", cycle, $time); 162 | cycle <= cycle + 1; 163 | endrule 164 | 165 | ////////////////////////////////////////////////////////////////// 166 | rule deque if ( cycle == 70 ); 167 | $display("@%4t tst: popped data ", $time, fshow(dut.first())); 168 | dut.deq(); 169 | endrule 170 | 171 | endmodule 172 | -------------------------------------------------------------------------------- /TestBenchXbr.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | 5 | import CommonTypes::*; 6 | import CrossBar::*; 7 | import Vector::*; //for replication method 8 | import FShow::*; //for show method 9 | 10 | typedef enum {Start, Test, End} TestPhase_t deriving (Bits, Eq); 11 | typedef 6 NofNodes_t; 12 | 13 | (* synthesize *) 14 | module mkCrossBarTestBench(); 15 | 16 | Integer maxCyclesToRun = 50; 17 | Integer nodeId = 1; 18 | 19 | 20 | Reg#(Bit#(32)) cycle <- mkReg(0); 21 | Reg#(TestPhase_t)testPhase <- mkReg(Start); 22 | Reg#(Bit#(4)) testStage <- mkReg(0); 23 | TwoCrossBar#(int) twoXb <- mkTwoCrossBar(0); 24 | ThreeCrossBar#(NofNodes_t, int) fxb <- mkRingNodeCrossBar(nodeId); 25 | 26 | /////////////////////////////////////////////////////////////////// 27 | rule timeout if (cycle > fromInteger(maxCyclesToRun)); 28 | $display("Timeout termination cycle count %d", cycle); 29 | $finish(); 30 | endrule 31 | 32 | rule clockCount; 33 | $display("\n== cycle %03d", cycle); 34 | cycle <= cycle + 1; 35 | endrule 36 | 37 | ////////////////////////////////////////////////////////////////// 38 | rule start(testPhase == Start); 39 | $display("Start tests:"); 40 | testPhase <= Test; 41 | endrule 42 | 43 | ////////////////////////////////////////////////////////////////// 44 | Reg#(Direction_t) dir0 <- mkReg(Up); 45 | Reg#(Direction_t) dir1 <- mkReg(Down); 46 | Reg#(int) data0 <- mkReg('d100); 47 | Reg#(int) data1 <- mkReg('d200); 48 | Reg#(Bool) drainEnable <- mkReg(False); 49 | 50 | ////////////////////////////////////////////////////////////////// 51 | rule test_rout_to_distinct_ports(testPhase == Test && cycle < 10); 52 | RoutPath_t p0 = RoutPath_t{level: replicate(dir0)}; 53 | RoutPath_t p1 = RoutPath_t{level: replicate(dir1)}; 54 | 55 | RoutRequest_t#(int) r0 = RoutRequest_t{path:p0, data:data0}; 56 | RoutRequest_t#(int) r1 = RoutRequest_t{path:p1, data:data1}; 57 | $display("put r0 ",fshow(r0)); 58 | $display(" r1 ",fshow(r1)); 59 | twoXb.putPortUp(r0); 60 | twoXb.putPortDn(r1); 61 | 62 | data0 <= data0 + 1; 63 | data1 <= data1 + 1; 64 | //swtich directions: 65 | bit d0 = pack(dir0); dir0 <= unpack(~d0); 66 | bit d1 = pack(dir1); dir1 <= unpack(~d1); 67 | 68 | drainEnable <= True; 69 | endrule 70 | 71 | ////////////////////////////////////////////////////////////////// 72 | rule test_rout_to_same_port_up(testPhase == Test && 73 | cycle >= 10 && 74 | cycle < 20 ); 75 | RoutPath_t path = RoutPath_t{level:replicate(Down)}; 76 | RoutRequest_t#(int) r = RoutRequest_t{path:path, data:data0}; 77 | $display("put up ", fshow(r)); 78 | twoXb.putPortUp(r); 79 | data0 <= data0 + 1; 80 | endrule 81 | 82 | rule test_rout_to_same_port_dn(testPhase == Test && 83 | cycle >= 10 && 84 | cycle < 20 ); 85 | RoutPath_t path = RoutPath_t{level:replicate(Down)}; 86 | RoutRequest_t#(int) r = RoutRequest_t{path:path, data:data1}; 87 | $display("put dn ", fshow(r)); 88 | twoXb.putPortDn(r); 89 | data1 <= data1 + 1; 90 | endrule 91 | 92 | ////////////////////////////////////////////////////////////////// 93 | rule test_one_port_at_a_time(testPhase == Test && 94 | cycle >= 20 && cycle < 30); 95 | RoutPath_t path = RoutPath_t{level:replicate(Up)}; 96 | RoutRequest_t#(int) r = RoutRequest_t{path:path, data:data0}; 97 | $display("put up ", fshow(r)); 98 | twoXb.putPortDn(r); 99 | data0 <= data0 + 1; 100 | endrule 101 | 102 | ////////////////////////////////////////////////////////////////// 103 | rule drainOutPortUp if( drainEnable ); 104 | let up <- twoXb.getPortUp; 105 | $display("drain out port Up: ", fshow(up)); 106 | endrule 107 | 108 | rule drainOutPortDn if( drainEnable ); 109 | let dn <- twoXb.getPortDn; 110 | $display("drain out port Dn: ", fshow(dn)); 111 | endrule 112 | 113 | /////////////////////////////////////////////////////////////////// 114 | // BELOW WRITTEN TEST FOR FULL-CORSSBAR MODULE 115 | 116 | /** 117 | * create address vector v of these values: nodeId={0,1,6} 118 | * each time put v[i] to port i and verify that every time 119 | * we get the correct same data in each output port 120 | * */ 121 | Vector#(3, Reg#(Address_t#(NofNodes_t))) destAddr 122 | <- replicateM(mkRegU()); 123 | 124 | Vector#(3, Reg#(int)) data <- replicateM(mkReg(fromInteger(0))); 125 | 126 | rule initRegisters if (cycle == 1); 127 | destAddr[0] <= fromInteger(0); 128 | destAddr[1] <= fromInteger(1); 129 | destAddr[2] <= fromInteger(2); 130 | data[0] <= 'd000; 131 | data[1] <= 'd100; 132 | data[2] <= 'd200; 133 | endrule 134 | 135 | rule routeToDistinctPorts if (cycle >= 40 && cycle < 50 ); 136 | $display("putPort0: addr ", destAddr[0], ", data", data[0]); 137 | $display("putPort1: addr ", destAddr[1], ", data", data[1]); 138 | $display("putPort2: addr ", destAddr[2], ", data", data[2]); 139 | //put the vector elements ot all ports in fxb 140 | fxb.putPort0(destAddr[0], data[0]); 141 | fxb.putPort1(destAddr[1], data[1]); 142 | fxb.putPort2(destAddr[2], data[2]); 143 | //rotate vectors down 144 | destAddr[0] <= destAddr[1]; 145 | destAddr[1] <= destAddr[2]; 146 | destAddr[2] <= destAddr[0]; 147 | data[0] <= data[1] + 1; 148 | data[1] <= data[2] + 1; 149 | data[2] <= data[0] + 1; 150 | endrule 151 | 152 | // drain the ouput ports of fxb module //////////////////////////// 153 | rule drainFxbOutputUp; 154 | $display("OutputUp : ", fxb.getPortUp); 155 | endrule 156 | 157 | rule drainFxbOutputDn; 158 | $display("OutputDn : ", fxb.getPortDn); 159 | endrule 160 | 161 | rule drainFxbOutputSelf; 162 | $display("OutputSelf: ", fxb.getPortSelf); 163 | endrule 164 | 165 | endmodule 166 | 167 | -------------------------------------------------------------------------------- /RingNode.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | import FShow::*; 5 | import CommonTypes::*; 6 | 7 | import PacketToFlit::*; 8 | import VcFifo::*; 9 | import CrossBar::*; 10 | import FlitToPacket::*; 11 | 12 | /////////////////////////////////////////////////////////////////////////////// 13 | // Important note: all following types should be power of 2 otherwise 14 | // synth tool fails :( 15 | 16 | // number of packets assembled in flit-to-packet sub module 17 | typedef 8 NofAssembeldPackets_t; 18 | 19 | // size of a PACKET_FIFO that stores the assembled packets ready to be fetched 20 | // by client 21 | typedef 4 NofWaitingPkts_t; 22 | 23 | // after DropTimeout_t cycles a packet will be dropped from PACKET_FIFO if it 24 | // wasn't fetched by user. 25 | typedef 16 DropTimeout_t; 26 | 27 | //////////////////////////////////////////////////////////////////////////////// 28 | // This interface defines a ring node's functionality as seen by the client. 29 | // Up ring direction denotes the direction of increasing nodeIds (0,1,2..N-1) 30 | // Donw ring direction is opposite to Up ring i.e. decresing nodeId (...,2,1,0) 31 | // 32 | // IMPORTANT NOTE: 33 | // Original interface didn't define how ring node communicate with peer ring 34 | // nodes. Thus we have to add interface methods to define the communication 35 | // of ring node with upper and lower ring nodes. 36 | //////////////////////////////////////////////////////////////////////////////// 37 | interface RingNode#(numeric type nofNodes, 38 | numeric type fltSz, 39 | numeric type numVC); 40 | 41 | // send a payload to node destination 42 | method Action enq(Packet#(nofNodes) packet); 43 | 44 | // read the first incoming message 45 | method Packet#(nofNodes) first(); 46 | 47 | // dequeue the first incoming message 48 | method Action deq(); 49 | 50 | // get the endpoint's ID 51 | method Bit#(TLog#(nofNodes)) nodeID(); 52 | 53 | //ADDED methods for communicating with upper & lower ring node 54 | 55 | // enque flit arriving from upper ring node 56 | method Action putUp(Flit_t#(nofNodes, fltSz, numVC) flit); 57 | 58 | // enque flit arriving from lower ring node 59 | method Action putDn(Flit_t#(nofNodes, fltSz, numVC) flit); 60 | 61 | // deque flit from upper ring node 62 | method ActionValue#(Flit_t#(nofNodes, fltSz, numVC)) getUp(); 63 | 64 | // deque flit from lower ring node 65 | method ActionValue#(Flit_t#(nofNodes, fltSz, numVC)) getDn(); 66 | 67 | method Bool notEmpty(); 68 | method Bool notFull(); 69 | 70 | endinterface 71 | 72 | 73 | //////////////////////////////////////////////////////////////////////////////// 74 | // RingNode implementing module: 75 | // nodeId parameter is used to specify node's IDs. 76 | //////////////////////////////////////////////////////////////////////////////// 77 | module mkRingNode#(parameter Integer nodeId) (RingNode#(nofNodes, fltSz, numVC)) 78 | provisos(Mul#(TDiv#(PayloadSz, fltSz), fltSz, PayloadSz)); 79 | 80 | Integer dropTimeout = valueOf(DropTimeout_t); 81 | 82 | ////////////////////////////////////////////////////////////////////// 83 | // instantiation of internal modules: 84 | ////////////////////////////////////////////////////////////////////// 85 | PacketToFlit#(nofNodes, fltSz, numVC) packetToFlit <- mkPacketToFlit(nodeId); 86 | // flits from client 87 | VcFifo#(nofNodes, fltSz, numVC) clientVcFifo <- mkVcFifo; 88 | // flits from upper ring node 89 | VcFifo#(nofNodes, fltSz, numVC) upRingVcFifo <- mkVcFifo; 90 | // flits from lower ring node 91 | VcFifo#(nofNodes, fltSz, numVC) downRingVcFifo <- mkVcFifo; 92 | 93 | ThreeCrossBar#(nofNodes, Flit_t#(nofNodes, fltSz, numVC)) crossbar 94 | <- mkRingNodeCrossBar(nodeId); 95 | 96 | FlitToPacket#(nofNodes, fltSz, numVC, NofAssembeldPackets_t, 97 | NofWaitingPkts_t) flitToPacket <- mkFlitToPacket(dropTimeout); 98 | 99 | ////////////////////////////////////////////////////////////////////// 100 | // rules: 101 | ////////////////////////////////////////////////////////////////////// 102 | rule fromPacket2FlitToVCFifo; 103 | let flit = packetToFlit.first; 104 | $display("@%4t rn%1d: packetToFlit -> clientVcFifo ", 105 | $time, nodeId, fshow(flit)); 106 | packetToFlit.deq(); 107 | clientVcFifo.put(flit); 108 | endrule 109 | 110 | (* fire_when_enabled *) 111 | rule fromClientVCFifoToCrossbar; 112 | let flit <- clientVcFifo.get(); 113 | $display("@%4t rn%1d: clientVcFifo -> crossbar ", 114 | $time, nodeId, fshow(flit)); 115 | crossbar.putPort1(flit.dest, flit); 116 | endrule 117 | 118 | (* fire_when_enabled *) 119 | rule fromUpVCFifoToCrossbar; 120 | let flit <- upRingVcFifo.get(); 121 | $display("@%4t rn%1d: upRingVcFifo -> crossbar ", 122 | $time, nodeId, fshow(flit)); 123 | crossbar.putPort0(flit.dest, flit); 124 | endrule 125 | 126 | (* fire_when_enabled *) 127 | rule fromDownVCFifoToCrossbar; 128 | let flit <- downRingVcFifo.get(); 129 | $display("@%4t rn%1d: downRingVcFifo -> crossbar ", 130 | $time, nodeId, fshow(flit)); 131 | crossbar.putPort2(flit.dest, flit); 132 | endrule 133 | 134 | rule fromCrossbarToFlitToPacket; 135 | let flit <- crossbar.getPortSelf(); 136 | $display("@%4t rn%1d: crossbar -> flitToPacket ", 137 | $time, nodeId, fshow(flit)); 138 | flitToPacket.enq(flit); 139 | endrule 140 | 141 | ////////////////////////////////////////////////////////////////////// 142 | // methods: 143 | ////////////////////////////////////////////////////////////////////// 144 | 145 | method Action enq(Packet#(nofNodes) packet); 146 | $display("@%4t rn%1d: enq packet ", 147 | $time, nodeId, fshow(packet)); 148 | packetToFlit.enq(packet); 149 | endmethod 150 | 151 | // read the first incoming message 152 | method Packet#(nofNodes) first = flitToPacket.first; 153 | 154 | // dequeue the first incoming message 155 | method Action deq(); 156 | $display("@%4t rn%1d: deq packet ", 157 | $time, nodeId, fshow(flitToPacket.first)); 158 | flitToPacket.deq(); 159 | endmethod 160 | 161 | // get the endpoint's ID 162 | method Bit#(TLog#(nofNodes)) nodeID(); 163 | return pack(nodeID); 164 | endmethod 165 | 166 | method Action putUp(Flit_t#(nofNodes, fltSz, numVC) flit); 167 | $display("@%4t rn%1d: putUp flit ", 168 | $time, nodeId, fshow(flit)); 169 | upRingVcFifo.put(flit); 170 | endmethod 171 | 172 | method Action putDn(Flit_t#(nofNodes, fltSz, numVC) flit); 173 | $display("@%4t rn%1d: enqDn flit ", 174 | $time, nodeId, fshow(flit)); 175 | downRingVcFifo.put(flit); 176 | endmethod 177 | 178 | // deque flit from upper ring node 179 | method ActionValue#(Flit_t#(nofNodes, fltSz, numVC)) getUp(); 180 | let flit <- crossbar.getPortUp(); 181 | return flit; 182 | endmethod 183 | 184 | // deque flit from lower ring node 185 | method ActionValue#(Flit_t#(nofNodes, fltSz, numVC)) getDn(); 186 | let flit <- crossbar.getPortDn(); 187 | return flit; 188 | endmethod 189 | 190 | method Bool notEmpty = flitToPacket.notEmpty; 191 | method Bool notFull = packetToFlit.notFull; 192 | 193 | endmodule 194 | 195 | // (* synthesize *) 196 | // module mkRingNode_Synth(RingNode#(4,32,2)); 197 | // let _u <- mkRingNode(1); 198 | // return _u; 199 | // endmodule 200 | -------------------------------------------------------------------------------- /Arbiter.bsv: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2007--2009 Bluespec, Inc. All rights reserved. 2 | // $Revision: 20163 $ 3 | // $Date: 2010-04-12 18:29:20 +0000 (Mon, 12 Apr 2010) $ 4 | 5 | package Arbiter; 6 | 7 | import Vector::*; 8 | import BUtils::*; 9 | import Connectable::*; 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | /// 13 | //////////////////////////////////////////////////////////////////////////////// 14 | 15 | interface ArbiterClient_IFC; 16 | method Action request(); 17 | method Action lock(); 18 | method Bool grant(); 19 | endinterface 20 | 21 | interface ArbiterRequest_IFC; 22 | method Bool request(); 23 | method Bool lock(); 24 | method Action grant(); 25 | endinterface 26 | 27 | interface Arbiter_IFC#(numeric type count); 28 | interface Vector#(count, ArbiterClient_IFC) clients; 29 | method Bit#(TLog#(count)) grant_id; 30 | endinterface 31 | 32 | //////////////////////////////////////////////////////////////////////////////// 33 | /// A fair round robin arbiter with changing priorities. If the value of "fixed" 34 | /// is True, the current grant is locked and not updated again until 35 | /// "fixed" goes False; 36 | //////////////////////////////////////////////////////////////////////////////// 37 | 38 | module mkArbiter#(Bool fixed) (Arbiter_IFC#(count)); 39 | 40 | let icount = valueOf(count); 41 | 42 | // Initially, priority is given to client 0 43 | Vector#(count, Bool) init_value = replicate(False); 44 | init_value[0] = True; 45 | Reg#(Vector#(count, Bool)) priority_vector <- mkReg(init_value); 46 | 47 | 48 | Wire#(Vector#(count, Bool)) grant_vector <- mkBypassWire; 49 | Wire#(Bit#(TLog#(count))) grant_id_wire <- mkBypassWire; 50 | Vector#(count, PulseWire) request_vector <- replicateM(mkPulseWire); 51 | 52 | rule every (True); 53 | 54 | // calculate the grant_vector 55 | Vector#(count, Bool) zow = replicate(False); 56 | Vector#(count, Bool) grant_vector_local = replicate(False); 57 | Bit#(TLog#(count)) grant_id_local = 0; 58 | 59 | Bool found = True; 60 | 61 | for (Integer x = 0; x < (2 * icount); x = x + 1) 62 | 63 | begin 64 | 65 | Integer y = (x % icount); 66 | 67 | if (priority_vector[y]) found = False; 68 | 69 | let a_request = request_vector[y]; 70 | zow[y] = a_request; 71 | 72 | if (!found && a_request) 73 | begin 74 | grant_vector_local[y] = True; 75 | grant_id_local = fromInteger(y); 76 | found = True; 77 | end 78 | end 79 | 80 | // Update the RWire 81 | grant_vector <= grant_vector_local; 82 | grant_id_wire <= grant_id_local; 83 | 84 | // If a grant was given, update the priority vector so that 85 | // client now has lowest priority. 86 | if (any(isTrue,grant_vector_local) && !fixed) 87 | begin 88 | // $display("(%5d) Updating priorities", $time); 89 | priority_vector <= rotateR(grant_vector_local); 90 | end 91 | 92 | 93 | // $display("(%5d) priority vector: %4b", $time, priority_vector); 94 | // $display("(%5d) request vector: %4b", $time, zow); 95 | // $display("(%5d) Grant vector: %4b", $time, grant_vector_local); 96 | 97 | endrule 98 | 99 | // Now create the vector of interfaces 100 | Vector#(count, ArbiterClient_IFC) client_vector = newVector; 101 | 102 | for (Integer x = 0; x < icount; x = x + 1) 103 | 104 | client_vector[x] = (interface ArbiterClient_IFC 105 | 106 | method Action request(); 107 | request_vector[x].send(); 108 | endmethod 109 | 110 | method Action lock(); 111 | dummyAction; 112 | endmethod 113 | 114 | method grant (); 115 | return grant_vector[x]; 116 | endmethod 117 | endinterface); 118 | 119 | interface clients = client_vector; 120 | method grant_id = grant_id_wire; 121 | endmodule 122 | 123 | //////////////////////////////////////////////////////////////////////////////// 124 | /// This one gives the current owner priority (i.e. they can hold as long as 125 | /// they keep requesting it. 126 | //////////////////////////////////////////////////////////////////////////////// 127 | 128 | module mkStickyArbiter (Arbiter_IFC#(count)); 129 | 130 | let icount = valueOf(count); 131 | 132 | // Initially, priority is given to client 0 133 | Vector#(count, Bool) all_false = replicate(False); 134 | Vector#(count, Bool) init_value = replicate(False); 135 | init_value[0] = True; 136 | Reg#(Vector#(count, Bool)) priority_vector <- mkReg(init_value); 137 | 138 | 139 | Wire#(Vector#(count, Bool)) grant_vector <- mkBypassWire; 140 | Reg#(Vector#(count, Bool)) grant_vector_prev <- mkReg(all_false); 141 | Wire#(Bit#(TLog#(count))) grant_id_wire <- mkBypassWire; 142 | Vector#(count, PulseWire) request_vector <- replicateM(mkPulseWire); 143 | 144 | function Bool getValue(PulseWire ifc); 145 | return ifc._read; 146 | endfunction 147 | 148 | rule every (True); 149 | 150 | let current_requests = map(getValue, request_vector); 151 | let owner_request = (pack(grant_vector_prev) & pack(current_requests)) != 0; 152 | 153 | // calculate the grant_vector 154 | Vector#(count, Bool) zow = all_false; 155 | Vector#(count, Bool) grant_vector_local = all_false; 156 | Bit#(TLog#(count)) grant_id_local = 0; 157 | 158 | if (owner_request) 159 | grant_vector_local = grant_vector_prev; 160 | else 161 | begin 162 | 163 | Bool found = True; 164 | 165 | for (Integer x = 0; x < (2 * icount); x = x + 1) 166 | 167 | begin 168 | 169 | Integer y = (x % icount); 170 | 171 | if (priority_vector[y]) found = False; 172 | 173 | let a_request = request_vector[y]; 174 | zow[y] = a_request; 175 | 176 | if (!found && a_request) 177 | begin 178 | grant_vector_local[y] = True; 179 | grant_id_local = fromInteger(y); 180 | found = True; 181 | end 182 | end 183 | end 184 | 185 | 186 | // Update the RWire 187 | grant_vector <= grant_vector_local; 188 | grant_vector_prev <= grant_vector_local; 189 | grant_id_wire <= grant_id_local; 190 | 191 | // If a new grant was given, update the priority vector so that 192 | // client now has lowest priority. 193 | if (any(isTrue, grant_vector_local) && !owner_request) 194 | 195 | priority_vector <= rotateR(grant_vector_local); 196 | /* -----\/----- EXCLUDED -----\/----- 197 | 198 | $display(" priority vector %4b", priority_vector, $time); 199 | $display(" request vector %4b", zow, $time); 200 | $display(" Grant vector %4b", grant_vector_local, $time); 201 | $display("Grant vector prev %4b", grant_vector_prev, $time); 202 | -----/\----- EXCLUDED -----/\----- */ 203 | 204 | endrule 205 | 206 | // Now create the vector of interfaces 207 | Vector#(count, ArbiterClient_IFC) client_vector = newVector; 208 | 209 | for (Integer x = 0; x < icount; x = x + 1) 210 | 211 | client_vector[x] = (interface ArbiterClient_IFC 212 | 213 | method Action request(); 214 | request_vector[x].send(); 215 | endmethod 216 | 217 | method Action lock(); 218 | 219 | endmethod 220 | 221 | method grant (); 222 | return grant_vector_prev[x]; 223 | endmethod 224 | endinterface); 225 | 226 | interface clients = client_vector; 227 | method grant_id = grant_id_wire; 228 | endmodule 229 | 230 | module mkHoldArbiter (Arbiter_IFC#(count)); 231 | 232 | let icount = valueOf(count); 233 | 234 | // Initially, priority is given to client 0 235 | Vector#(count, Bool) init_value = replicate(False); 236 | init_value[0] = True; 237 | Reg#(Vector#(count, Bool)) priority_vector <- mkReg(init_value); 238 | 239 | 240 | 241 | Wire#(Vector#(count, Bool)) grant_vector <- mkBypassWire; 242 | Wire#(Bit#(TLog#(count))) grant_id_wire <- mkBypassWire; 243 | Vector#(count, PulseWire) request_vector <- replicateM(mkPulseWire); 244 | 245 | rule every (True); 246 | 247 | // calculate the grant_vector 248 | Vector#(count, Bool) zow = replicate(False); 249 | Vector#(count, Bool) grant_vector_local = replicate(False); 250 | Bit#(TLog#(count)) grant_id_local = 0; 251 | 252 | Bool found = True; 253 | 254 | for (Integer x = 0; x < (2 * icount); x = x + 1) 255 | 256 | begin 257 | 258 | Integer y = (x % icount); 259 | 260 | if (priority_vector[y]) found = False; 261 | 262 | let a_request = request_vector[y]; 263 | zow[y] = a_request; 264 | 265 | if (!found && a_request) 266 | begin 267 | grant_vector_local[y] = True; 268 | grant_id_local = fromInteger(y); 269 | found = True; 270 | end 271 | end 272 | 273 | // Update the RWire 274 | grant_vector <= grant_vector_local; 275 | grant_id_wire <= grant_id_local; 276 | 277 | // If a grant was given, update the priority vector so that 278 | // client now has lowest priority. 279 | if (any(isTrue,grant_vector_local)) 280 | begin 281 | priority_vector <= rotateR(grant_vector_local); 282 | grant_vector <= grant_vector_local; 283 | end 284 | else 285 | begin 286 | grant_vector <= grant_vector; // hold previous values 287 | end 288 | 289 | // $display(" priority vector %4b", priority_vector, $time); 290 | // $display(" request vector %4b", zow, $time); 291 | // $display(" Grant vector %4b", grant_vector_local, $time); 292 | 293 | endrule 294 | 295 | // Now create the vector of interfaces 296 | Vector#(count, ArbiterClient_IFC) client_vector = newVector; 297 | 298 | for (Integer x = 0; x < icount; x = x + 1) 299 | 300 | client_vector[x] = (interface ArbiterClient_IFC 301 | 302 | method Action request(); 303 | request_vector[x].send(); 304 | endmethod 305 | 306 | method Action lock(); 307 | dummyAction; 308 | endmethod 309 | 310 | method grant (); 311 | return grant_vector[x]; 312 | endmethod 313 | endinterface); 314 | 315 | interface clients = client_vector; 316 | method grant_id = grant_id_wire; 317 | endmodule 318 | 319 | function Bool isTrue(Bool value); 320 | return value; 321 | endfunction 322 | 323 | instance Connectable#(ArbiterClient_IFC, ArbiterRequest_IFC); 324 | module mkConnection#(ArbiterClient_IFC client, ArbiterRequest_IFC request) (Empty); 325 | 326 | rule send_grant (client.grant); 327 | request.grant(); 328 | endrule 329 | 330 | rule send_request (request.request); 331 | client.request(); 332 | endrule 333 | 334 | rule send_lock (request.lock); 335 | client.lock(); 336 | endrule 337 | endmodule 338 | endinstance 339 | 340 | //////////////////////////////////////////////////////////////////////////////// 341 | /// 342 | //////////////////////////////////////////////////////////////////////////////// 343 | 344 | typeclass Arbitable#(type a); 345 | module mkArbiterRequest#(a ifc) (ArbiterRequest_IFC); 346 | endtypeclass 347 | 348 | //////////////////////////////////////////////////////////////////////////////// 349 | /// 350 | //////////////////////////////////////////////////////////////////////////////// 351 | 352 | endpackage 353 | -------------------------------------------------------------------------------- /CrossBar.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | import CommonTypes::*; 5 | import FIFOF::*; 6 | import SpecialFIFOs::*; //for pipe-lined standard fifos (1-elements) 7 | import RWire::*; 8 | import Vector::*; 9 | import FShow::*; 10 | 11 | typedef enum {Up, Down} Direction_t deriving ( Bits, Eq ); 12 | typedef enum {UpPort, DownPort, SelfPort} Port_t deriving ( Bits, Eq ); 13 | 14 | typedef struct { 15 | Vector#(2, Direction_t) level; /* each 2Xbar mux will use it's 16 | level direction*/ 17 | } RoutPath_t deriving( Bits, Eq ); 18 | 19 | typedef struct { 20 | RoutPath_t path; 21 | t data; 22 | } RoutRequest_t#(type t) deriving ( Bits, Eq ); 23 | 24 | ////////////////////////////////////////////////////////////////////// 25 | // override of the representation methods: 26 | instance FShow#(Direction_t); 27 | function Fmt fshow (Direction_t d); 28 | case (d) 29 | Up: return fshow("Up"); 30 | Down: return fshow("Dn"); 31 | endcase 32 | endfunction 33 | endinstance 34 | 35 | instance FShow#(RoutPath_t); 36 | function Fmt fshow (RoutPath_t path); 37 | return $format("<", fshow(path.level[0]), 38 | ",", fshow(path.level[1]), ">"); 39 | endfunction 40 | endinstance 41 | 42 | instance FShow#(RoutRequest_t#(t)) provisos (Bits#(t, tSz), FShow#(t)); 43 | function Fmt fshow (RoutRequest_t#(t) req); 44 | return $format("<", fshow(req.path), 45 | ",", fshow(req.data),">"); 46 | endfunction 47 | endinstance 48 | 49 | //////////////////////////////////////////////////////////////////////////////// 50 | // Defines interface to 2 ports full crossbar. Ports named 'Up' and 'Dn' (Down) 51 | //////////////////////////////////////////////////////////////////////////////// 52 | interface TwoCrossBar#(type t); 53 | method Action putPortUp(RoutRequest_t#(t) req); 54 | method Action putPortDn(RoutRequest_t#(t) req); 55 | method ActionValue#(RoutRequest_t#(t)) getPortUp; 56 | method ActionValue#(RoutRequest_t#(t)) getPortDn; 57 | endinterface 58 | 59 | 60 | //////////////////////////////////////////////////////////////////////////////// 61 | // Full crossbar router with 2 input ports and 2 output ports. 62 | // l (stands for level) is a parameter that tells the mux at what sate it's 63 | // instantiated i.e. using this module one may implement N-to-N full crossbar 64 | // module using N routing stages (or levels) 65 | //////////////////////////////////////////////////////////////////////////////// 66 | module mkTwoCrossBar#(parameter Integer l) 67 | (TwoCrossBar#(t)) provisos(Bits#(t, tSz)); 68 | 69 | //staging flops of route requests when arrive/leaving the unit 70 | FIFOF#(RoutRequest_t#(t)) outPortUp <- mkPipelineFIFOF; 71 | FIFOF#(RoutRequest_t#(t)) outPortDn <- mkPipelineFIFOF; 72 | FIFOF#(RoutRequest_t#(t)) inPortUp <- mkPipelineFIFOF; 73 | FIFOF#(RoutRequest_t#(t)) inPortDn <- mkPipelineFIFOF; 74 | 75 | RWire#(RoutRequest_t#(t)) wireInUpReq <- mkRWire(); 76 | RWire#(RoutRequest_t#(t)) wireInDnReq <- mkRWire(); 77 | 78 | // will be used to implement RR conflict resolution 79 | Reg#(Direction_t) portSelect <- mkReg(Up); 80 | 81 | rule processInPortUp if(inPortUp.notEmpty); 82 | wireInUpReq.wset(inPortUp.first); 83 | endrule 84 | 85 | rule processInPortDn if(inPortDn.notEmpty); 86 | wireInDnReq.wset(inPortDn.first); 87 | endrule 88 | 89 | //Do the RR selection when both requests are targeted to same 90 | // output port 91 | rule portSelectControl if (isValid(wireInDnReq.wget()) && 92 | isValid(wireInUpReq.wget()) ); 93 | Direction_t inUpDirection = validValue(wireInUpReq.wget()).path.level[l]; 94 | Direction_t inDnDirection = validValue(wireInDnReq.wget()).path.level[l]; 95 | if(inUpDirection == inDnDirection) begin//select next port 96 | bit select = pack(portSelect); 97 | portSelect <= unpack(~select); 98 | end 99 | endrule 100 | 101 | // process the request from both input ports 102 | rule processRequests; 103 | case (tuple2 (wireInUpReq.wget(), wireInDnReq.wget())) matches 104 | {tagged Invalid ,tagged Invalid }: 105 | noAction; 106 | {tagged Valid .u,tagged Invalid }: 107 | begin 108 | if( u.path.level[l] == Up ) outPortUp.enq(u); 109 | else outPortDn.enq(u); 110 | inPortUp.deq; 111 | end 112 | {tagged Invalid ,tagged Valid .d}: 113 | begin 114 | if( d.path.level[l] == Up ) outPortUp.enq(d); 115 | else outPortDn.enq(d); 116 | inPortDn.deq; 117 | end 118 | {tagged Valid .u,tagged Valid .d}: 119 | begin 120 | case(tuple2(u.path.level[l], 121 | d.path.level[l])) matches 122 | {tagged Up, tagged Up }: 123 | begin 124 | if(portSelect==Up) begin 125 | outPortUp.enq(u); 126 | inPortUp.deq; 127 | //d req is stalled 128 | end 129 | else begin//portSelect==Down 130 | outPortUp.enq(d); 131 | inPortDn.deq; 132 | //u req is stalled 133 | end 134 | end 135 | {tagged Up, tagged Down}: 136 | begin 137 | outPortUp.enq(u); 138 | outPortDn.enq(d); 139 | inPortUp.deq; 140 | inPortDn.deq; 141 | end 142 | {tagged Down, tagged Up }: 143 | begin 144 | outPortUp.enq(d); 145 | outPortDn.enq(u); 146 | inPortUp.deq; 147 | inPortDn.deq; 148 | end 149 | {tagged Down, tagged Down}: 150 | begin 151 | if(portSelect==Up) begin 152 | outPortDn.enq(u); 153 | inPortUp.deq; 154 | end 155 | else begin//portSelect==Down 156 | outPortDn.enq(d); 157 | inPortDn.deq; 158 | end 159 | end 160 | endcase 161 | end 162 | endcase 163 | endrule 164 | 165 | 166 | method Action putPortUp(RoutRequest_t#(t) req); 167 | inPortUp.enq(req); 168 | endmethod 169 | 170 | method Action putPortDn(RoutRequest_t#(t) req); 171 | inPortDn.enq(req); 172 | endmethod 173 | 174 | method ActionValue#(RoutRequest_t#(t)) getPortUp; 175 | let res = outPortUp.first; 176 | outPortUp.deq; 177 | return res; 178 | endmethod 179 | 180 | method ActionValue#(RoutRequest_t#(t)) getPortDn; 181 | let res = outPortDn.first; 182 | outPortDn.deq; 183 | return res; 184 | endmethod 185 | 186 | endmodule 187 | 188 | 189 | //////////////////////////////////////////////////////////////////////////////// 190 | // Implements the routing table that decides where to route the 191 | // current packed based on give-nodeId and the destinationId (filed 192 | // in the flit). 193 | // The whole idea in this module is that it should be optimized 194 | // by synt' tool into a look-up table 195 | //////////////////////////////////////////////////////////////////////////////// 196 | interface RoutingTable#(numeric type nofNodes); 197 | method RoutPath_t getRoutPath(Address_t#(nofNodes) dest); 198 | endinterface 199 | 200 | 201 | module mkRoutingTable#(parameter Integer nodeId) 202 | (RoutingTable#(nofNodes)); 203 | 204 | Integer n = valueOf(nofNodes); 205 | Integer n_h = ( n%2==1 ) ? n/2 : (n-1)/2; 206 | 207 | Vector#(nofNodes, Port_t) routeTbl = replicate(SelfPort); 208 | 209 | Integer idx = 1; 210 | for( Integer i = 0 ; i < n/2; i = i + 1, idx = idx + 1 ) 211 | routeTbl[idx] = UpPort; 212 | for( Integer i = 0 ; i < n_h; i = i + 1, idx = idx + 1 ) 213 | routeTbl[idx] = DownPort; 214 | 215 | routeTbl = rotateBy( routeTbl, fromInteger(nodeId) ); 216 | 217 | method RoutPath_t getRoutPath(Address_t#(nofNodes) dest); 218 | RoutPath_t path = ?; 219 | case( routeTbl[dest] ) 220 | UpPort : begin 221 | path.level[0] = Up; 222 | path.level[1] = Up; 223 | end 224 | DownPort : begin 225 | path.level[0] = Up; 226 | path.level[1] = Down; 227 | end 228 | SelfPort : begin 229 | path.level[0] = Down; 230 | path.level[1] = Up; 231 | end 232 | endcase 233 | return path; 234 | endmethod 235 | endmodule 236 | 237 | //////////////////////////////////////////////////////////////////////////////// 238 | // This is a full cross bar (fxb) routing module that can rout any 239 | // data (payload) from any of its input ports (0,1,2) to any of its 240 | // output ports (Up, Dn, Self). Routing is based on the destination 241 | // address (appears explicitly in the put method) and the address 242 | // of a given node (where this module is instantiated) 243 | //////////////////////////////////////////////////////////////////////////////// 244 | interface ThreeCrossBar#(numeric type nofNodes, type t); 245 | method Action putPort0(Address_t#(nofNodes) destAddr, t data); 246 | method Action putPort1(Address_t#(nofNodes) destAddr, t data); 247 | method Action putPort2(Address_t#(nofNodes) destAddr, t data); 248 | method ActionValue#(t) getPortUp; 249 | method ActionValue#(t) getPortDn; 250 | method ActionValue#(t) getPortSelf; 251 | endinterface 252 | 253 | module mkRingNodeCrossBar#(parameter Integer nodeId) 254 | (ThreeCrossBar#(nofNodes, t)) provisos(Bits#(t, tSz), 255 | FShow#(t)); 256 | 257 | //instantiate routing table: 258 | RoutingTable#(nofNodes) routingTbl <- mkRoutingTable(nodeId); 259 | 260 | //instantiate a grid of 4 2xb routing modules: 261 | TwoCrossBar#(t) level0Up <- mkTwoCrossBar(0); 262 | TwoCrossBar#(t) level0Dn <- mkTwoCrossBar(0); 263 | TwoCrossBar#(t) level1Up <- mkTwoCrossBar(1); 264 | TwoCrossBar#(t) level1Dn <- mkTwoCrossBar(1); 265 | 266 | rule rowUpToRowUp; //from level0-up out up to level1-up input up 267 | let data <- level0Up.getPortUp; 268 | level1Up.putPortUp(data); 269 | endrule 270 | 271 | rule rowUpToRowDn; //from level0-up out dn to level1-dn input up 272 | let data <- level0Up.getPortDn; 273 | level1Dn.putPortUp(data); 274 | endrule 275 | 276 | rule rowDnToRowUp; 277 | let data <- level0Dn.getPortUp; 278 | level1Up.putPortDn(data); 279 | endrule 280 | 281 | rule rowDnToRowDn; 282 | let data <- level0Dn.getPortDn; 283 | level1Dn.putPortDn(data); 284 | endrule 285 | 286 | /*This checker verifies there is no packet routed to down port 287 | * of level1-down crossbar */ 288 | rule fatal; 289 | let data <- level1Dn.getPortDn; 290 | $display("Error @%t in %m assertion fail level1Dn.PortDn", 291 | " isn't empty [", data, "] as expected"); 292 | $finish; 293 | endrule 294 | 295 | method Action putPort0(Address_t#(nofNodes) destAddr, t data); 296 | let path = routingTbl.getRoutPath(destAddr); 297 | RoutRequest_t#(t) req = RoutRequest_t{path:path, data: data}; 298 | level0Up.putPortUp(req); 299 | //$display("putPort0: ", fshow(req)); 300 | endmethod 301 | 302 | method Action putPort1(Address_t#(nofNodes) destAddr, t data); 303 | let path = routingTbl.getRoutPath(destAddr); 304 | RoutRequest_t#(t) req = RoutRequest_t{path:path, data: data}; 305 | level0Up.putPortDn(req); 306 | //$display("putPort1: ", fshow(req)); 307 | endmethod 308 | 309 | method Action putPort2(Address_t#(nofNodes) destAddr, t data); 310 | let path = routingTbl.getRoutPath(destAddr); 311 | RoutRequest_t#(t) req = RoutRequest_t{path:path, data: data}; 312 | level0Dn.putPortUp(req); 313 | //$display("putPort2: ", fshow(req)); 314 | endmethod 315 | 316 | method ActionValue#(t) getPortUp; 317 | let res <- level1Up.getPortUp; 318 | return res.data; 319 | endmethod 320 | 321 | method ActionValue#(t) getPortDn; 322 | let res <- level1Up.getPortDn; 323 | return res.data; 324 | endmethod 325 | 326 | method ActionValue#(t) getPortSelf; 327 | let res <- level1Dn.getPortUp; 328 | return res.data; 329 | endmethod 330 | 331 | endmodule 332 | 333 | // (* synthesize *) 334 | // module mkTwoCrossBar_Synth(TwoCrossBar#(Bit#(4))); 335 | // let _c <- mkTwoCrossBar(1); 336 | // return _c; 337 | // endmodule 338 | 339 | // (* synthesize *) 340 | // module mkCrossBar_Synth(ThreeCrossBar#(4, Flit_t#(4, 32, 4))); 341 | // let _d <- mkRingNodeCrossBar(1); 342 | // return _d; 343 | // endmodule 344 | -------------------------------------------------------------------------------- /FlitToPacket.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Michael Kimi 3 | */ 4 | import Ehr::*; 5 | import FIFOF::*; 6 | import CommonTypes::*; 7 | import Vector::*; 8 | import Cntr::*; 9 | import IndexPool::*; 10 | import BRAM::*; 11 | import Fifo::*; 12 | import PacketFifo::*; 13 | import FShow::*; 14 | 15 | ////////////////////////////////////////////////////////////////////// 16 | // interface definition ////////////////////////////////////////////// 17 | // 18 | // nofAssemblPkts: defines the number of packets that may be 19 | // assembled concurrently from arriving flits. 20 | // nofWaitingPkts: define the number of ready packets to be fetched 21 | // by client 22 | interface FlitToPacket#(numeric type nofNodes, 23 | numeric type fltSz, 24 | numeric type numVC, 25 | numeric type nofAssemblPkts, 26 | numeric type nofWaitingPkts); 27 | //enq flit into the flit to packet unit 28 | method Action enq(Flit_t#(nofNodes, fltSz, numVC) flit); 29 | //deq an assembled packet from the unit 30 | method Action deq(); 31 | //return the assembled packet 32 | method Packet#(nofNodes) first(); 33 | //return true if unit isn't empty and has a ready packet for a client 34 | method Bool notEmpty(); 35 | //return true if unit isn't full and can accept a flit 36 | method Bool notFull(); 37 | //report all configuration parameters, for debug 38 | method Action reportConfiguration(); 39 | //return true if the unit finished its internal initialization 40 | method Bool isNotInitializing(); 41 | 42 | method Action reportStatus(); 43 | 44 | endinterface 45 | 46 | ////////////////////////////////////////////////////////////////////// 47 | // internal type definitions ///////////////////////////////////////// 48 | 49 | typedef Bit#(TLog#(depth)) 50 | RamIndex_t#(numeric type depth); //for ram's indexing 51 | 52 | typedef struct { 53 | Address_t#(nofNodes) src; //indexing field 54 | PacketId_t pktId; //indexing field 55 | } CamEntry_t#(numeric type nofNodes) deriving (Bits, Eq); 56 | 57 | typedef struct { 58 | Flit_t#(nofNodes, fltSz, numVC) flit; //arrived flit 59 | Bool isAllocated; //true if flit is in the cam 60 | RamIndex_t#(depth) rowIdx; //valid if isAllocated==True 61 | FlitId_t#(fltSz) flitCnt; //count arrived flits 62 | } Forward_t#(numeric type nofNodes, 63 | numeric type numVC, 64 | numeric type fltSz, 65 | numeric type depth) deriving (Bits, Eq); 66 | 67 | ////////////////////////////////////////////////////////////////////// 68 | // define show methods for common types for easy printing... 69 | instance FShow#(Forward_t#(nofNodes, numVC, flitSz, depth)) ; 70 | function Fmt fshow (Forward_t#(nofNodes, numVC, flitSz, depth) fw); 71 | return ($format("")); 76 | endfunction 77 | endinstance 78 | 79 | 80 | 81 | ////////////////////////////////////////////////////////////////////// 82 | // helper functions ////////////////////////////////////////////////// 83 | 84 | // creates a write request into the ram structure from forwarded data 85 | function BRAMRequest#(RamIndex_t#(depth), // address type 86 | FlitPayload_t#(fltSz)) // data type 87 | makeWriteRequest(Forward_t#(nofNodes, numVC, fltSz, depth) fw); 88 | return BRAMRequest{write: True, 89 | responseOnWrite: False, 90 | address: fw.rowIdx, 91 | datain: fw.flit.data}; 92 | endfunction 93 | 94 | // creates a read request from the ram structure from forwarded data 95 | function BRAMRequest#(RamIndex_t#(depth), 96 | FlitPayload_t#(fltSz)) 97 | makeReadRequest(Forward_t#(nofNodes, numVC, fltSz, depth) fw); 98 | return BRAMRequest{write: False, 99 | responseOnWrite: True, 100 | address: fw.rowIdx, 101 | datain: ?}; 102 | endfunction 103 | 104 | // return a payload type from vector of flits 105 | function Payload toPayload(Vector#(nofFlitsInPacket, FlitPayload_t#(fltSz)) flits) 106 | provisos (Mul#(nofFlitsInPacket, fltSz, PayloadSz)); 107 | Bit#(PayloadSz) packet = pack(flits); 108 | return unpack(packet); 109 | endfunction 110 | 111 | function Bool isMatching(Flit_t#(nofNodes, fltSz, numVC) flit, 112 | CamEntry_t#(nofNodes) entry); 113 | return (flit.src == entry.src) && (flit.pktId == entry.pktId); 114 | endfunction 115 | 116 | //////////////////////////////////////////////////////////////////////////////// 117 | // Module implementation 118 | // 119 | // Implements Flit to packed assembled module. Flits may arrive into 120 | // this module from multiple sources. all flits are being assembled into 121 | // a packed. when a packed is ready it may be fetched. In case no one fetched 122 | // the packet during `dropTimeout` number of cycles the assembled packet will 123 | // be dropped silently 124 | //////////////////////////////////////////////////////////////////////////////// 125 | module mkFlitToPacket#(parameter Integer dropTimeout) 126 | (FlitToPacket#(nofNodes, fltSz, numVC, nofAssemblPkts, nofWaitingPkts)) 127 | provisos(Mul#(TDiv#(PayloadSz, fltSz), fltSz, PayloadSz)); //TODO check why BSC screams w/o this dummy proviso? 128 | 129 | Integer flitCountLim = valueOf(NofFlitsInPacket_t#(fltSz))-1; 130 | 131 | //CAM that store packet's allocated row for flits that are being assembled 132 | Vector#(nofAssemblPkts, Ehr#(2, CamEntry_t#(nofNodes))) cam 133 | <- replicateM( mkEhr( CamEntry_t{src:?, pktId:?})); 134 | 135 | // stores a valid bit for each entry in a CAM 136 | Vector#(nofAssemblPkts, Ehr#(2, Bool)) validEntry 137 | <- replicateM(mkEhr(False)); 138 | 139 | //counters that counts arrived flits in assembled packets 140 | Vector#(nofAssemblPkts, Cntr#(FlitId_t#(fltSz))) flitsCounter 141 | <- replicateM( mkCntr(flitCountLim) ); 142 | 143 | 144 | //flopping stage FIFOs (registers) 145 | FIFOF#(Flit_t#(nofNodes, fltSz, numVC)) stage1 <- mkFIFOF; 146 | FIFOF#(Forward_t#(nofNodes, numVC, fltSz, nofAssemblPkts)) stage2 <- mkFIFOF; 147 | FIFOF#(Flit_t#(nofNodes, fltSz, numVC)) stage3 <- mkFIFOF; 148 | 149 | //packet FIFO, to store assembled packets for client 150 | Fifo#(nofWaitingPkts, Packet#(nofNodes)) packetFifo 151 | <- mkPacketFifo(dropTimeout); 152 | 153 | //track free ram entries 154 | Allocator#(nofAssemblPkts, RamIndex_t#(nofAssemblPkts)) indexPool 155 | <- mkIndexAllocator; 156 | 157 | //create RAM structure to hold all flits data (of assembled packet) 158 | Integer nofBRAMs = valueOf(NofFlitsInPacket_t#(fltSz))-1; 159 | 160 | BRAM_Configure cfg = defaultValue;//BRAM config obj 161 | cfg.memorySize = valueOf(nofAssemblPkts); // set memory size 162 | 163 | BRAM1Port#(RamIndex_t#(nofAssemblPkts), 164 | FlitPayload_t#(fltSz)) ramArr[nofBRAMs]; 165 | for (Integer i=0; i a write the flit into pre-allocated entry in ram 231 | //2. last flit of a packet -> a read from all rams and write to packetFifo 232 | // b dealloc entry from cam (set valid==False) 233 | // c dealloc entry from ram 234 | //3. some flit of a packet arrived => write to appropriate RAM 235 | 236 | if (isAllocated == False) begin //1. 237 | //1st flit will always be written to a free row at ram 0 238 | ramArr[0].portA.request.put(makeWriteRequest(fwEntry)); 239 | cam[rowIdx][0] <= CamEntry_t{src: flit.src, // update the cam 240 | pktId: flit.pktId}; 241 | validEntry[rowIdx][0] <= True; // set entry valid 242 | 243 | formatStr = $format("FRST FLIT OF PKT. write flit to ram 0 row", 244 | rowIdx, " ", fshow(flit)); 245 | 246 | end 247 | else if (isAllocated && (ramIdx == fromInteger(flitCountLim))) begin //2. 248 | for (Integer i=0; i < nofBRAMs; i=i+1) begin // generate reads from all rams 249 | ramArr[i].portA.request.put(makeReadRequest(fwEntry)); 250 | end 251 | indexPool.deallocate(rowIdx); // de allocate row 252 | validEntry[ramIdx][1] <= False; // invalidate the entry in CAM 253 | stage3.enq(flit); // enable next processing stage 254 | 255 | formatStr = $format("LAST FLIT OF PKT. reading from all rams and de alloc row ", 256 | rowIdx, fshow(flit)); 257 | 258 | end 259 | else begin //3. 260 | ramArr[ramIdx].portA.request.put(makeWriteRequest(fwEntry)); 261 | 262 | formatStr = $format("SOME FLIT OF PKT. write flit to ram ", ramIdx, " row ", 263 | rowIdx, " ", fshow(flit)); 264 | end 265 | 266 | // $display("@%4t f2p: stg2 ", $time, formatStr); 267 | endrule 268 | 269 | // receive read data from all rams and assemble them into a single 270 | // packet. Then write this packet to packetFifo 271 | rule cycle3WriteToPackeFifo if (stage3.notEmpty); 272 | let flit = stage3.first; 273 | 274 | Vector#(NofFlitsInPacket_t#(fltSz), FlitPayload_t#(fltSz)) 275 | flitsData = newVector; 276 | 277 | for (Integer i=0; i < nofBRAMs; i=i+1) begin // put flits read flits 278 | flitsData[i] <- ramArr[i].portA.response.get(); 279 | end 280 | //put the last piece directly from stage3 FIFO (it isn't written into rams) 281 | flitsData[nofBRAMs] = flit.data; 282 | 283 | Packet#(nofNodes) packet = Packet{peer: flit.dest, 284 | msg: toPayload(flitsData)}; 285 | 286 | // $display("@%4t f2p: stg3 assembled ", $time, fshow(packet)); 287 | 288 | packetFifo.enq(packet); 289 | 290 | stage3.deq; 291 | endrule 292 | 293 | 294 | //////////////////////////////////////////////////////////////////////////////// 295 | /// implementation of interface's methods: 296 | //////////////////////////////////////////////////////////////////////////////// 297 | 298 | method Action enq(Flit_t#(nofNodes, fltSz, numVC) flit) 299 | if (indexPool.isNotInitializing); 300 | 301 | // $display("@%4t f2p: stg0 staging ", $time, fshow(flit)); 302 | stage1.enq(flit); 303 | endmethod 304 | 305 | method Action deq = packetFifo.deq; 306 | 307 | method Packet#(nofNodes) first = packetFifo.first; 308 | 309 | method Bool notEmpty = packetFifo.notEmpty; 310 | 311 | method Bool notFull = !indexPool.notFull; 312 | 313 | method Action reportConfiguration(); 314 | $display("From Interface:"); 315 | $display(" Number of Nodes = %3d", valueOf(nofNodes)); 316 | $display(" Flit Size = %3d", valueOf(fltSz)); 317 | $display(" Number of VCs = %3d", valueOf(numVC)); 318 | $display(" # Assembled pkts= %3d", valueOf(nofAssemblPkts)); 319 | $display(" # Waiting pkts = %3d", valueOf(nofWaitingPkts)); 320 | $display("Internal:"); 321 | $display(" Flit Cout Limit = %3d", flitCountLim); 322 | $display(" Timeout = %3d", dropTimeout); 323 | $display(" Number of RAMs = %3d", nofBRAMs); 324 | endmethod 325 | 326 | method Action reportStatus(); 327 | $display("Flit2Packet status:"); 328 | $display(" IdxALC notEmpty = %b, notFull = %b, notInit = %b", indexPool.notEmpty, indexPool.notFull, indexPool.isNotInitializing); 329 | $display(" PktFFO notEmpty = %b, notFull = %b", packetFifo.notEmpty, packetFifo.notFull); 330 | $display(" stage1 notEmpty = %b, notFull = %b", stage1.notEmpty, stage1.notFull); 331 | $display(" stage2 notEmpty = %b, notFull = %b", stage2.notEmpty, stage2.notFull); 332 | $display(" stage3 notEmpty = %b, notFull = %b", stage3.notEmpty, stage3.notFull); 333 | 334 | endmethod 335 | 336 | method Bool isNotInitializing = indexPool.isNotInitializing; 337 | 338 | endmodule 339 | 340 | -------------------------------------------------------------------------------- /Fifo.bsv: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright (C) 2012 4 | 5 | Arvind 6 | Muralidaran Vijayaraghavan 7 | 8 | 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: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 11 | 12 | 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. 13 | 14 | */ 15 | 16 | 17 | /* 18 | This file contains many FIFO implementations 19 | 1) Conflict Free FIFO with 2 elements 20 | 2) Pipeline FIFO with 1 element 21 | 3) Bypass FIFO with 1 element 22 | 4) Conflict Free FIFO with n elements (ptr based implementation) 23 | 5) Pipeline FIFO with n elements (ptr based implementation) 24 | 6) Searchable n-element FIFO has an extra search method added to the n-element FIFOs 25 | a) Searchable conflict-free n-element FIFO 26 | b) Searchable pipelined n-element FIFO 27 | 28 | Clear always happens after enq and deq (but before canonicalize when applicable) 29 | All these FIFOs have been tested with various pipelines. In particular n-element FIFO can be put in place of the respective 2-element or 1-element FIFO 30 | 31 | */ 32 | 33 | import Ehr::*; 34 | import Vector::*; 35 | 36 | interface Fifo#(numeric type n, type t); 37 | method Bool notFull; 38 | method Action enq(t x); 39 | method Bool notEmpty; 40 | method Action deq; 41 | method t first; 42 | method Action clear; 43 | endinterface 44 | 45 | /* 46 | // This Fifo2 <- mkCFFifo generates a two element FIFO where enq and deq are conflict free 47 | // {notEmpty, first} < deq < clear < canon 48 | // notFull < enq < clear < canon 49 | // deq conflict free with enq 50 | module mkCFFifo(Fifo#(2, t)) provisos(Bits#(t, tSz)); 51 | Ehr#(3, t) da <- mkEhr(?); 52 | Ehr#(3, Bool) va <- mkEhr(False); 53 | Ehr#(3, t) db <- mkEhr(?); 54 | Ehr#(3, Bool) vb <- mkEhr(False); 55 | 56 | rule canon if(vb[2] && !va[2]); 57 | da[2] <= db[2]; 58 | va[2] <= True; 59 | vb[2] <= False; 60 | endrule 61 | 62 | method Bool notFull = !vb[0]; 63 | 64 | method Action enq(t x) if(!vb[0]); 65 | db[0] <= x; 66 | vb[0] <= True; 67 | endmethod 68 | 69 | method Bool notEmpty = va[0]; 70 | 71 | method Action deq if (va[0]); 72 | va[0] <= False; 73 | endmethod 74 | 75 | method t first if(va[0]); 76 | return da[0]; 77 | endmethod 78 | 79 | method Action clear; 80 | vb[1] <= False; 81 | va[1] <= False; 82 | endmethod 83 | endmodule 84 | */ 85 | 86 | /* 87 | // This generates a one element FIFO where deq < enq 88 | // {notEmpty, first} < deq < notFull < enq < clear 89 | module mkPipelineFifo(Fifo#(1, t)) provisos(Bits#(t, tSz)); 90 | Reg#(t) data <- mkRegU; 91 | Ehr#(3, Bool) full <- mkEhr(False); 92 | 93 | method Bool notFull = !full[1]; 94 | 95 | method Action enq(t x) if(!full[1]); 96 | data <= x; 97 | full[1] <= True; 98 | endmethod 99 | 100 | method Bool notEmpty = full[0]; 101 | 102 | method Action deq if(full[0]); 103 | full[0] <= False; 104 | endmethod 105 | 106 | method t first if(full[0]); 107 | return data; 108 | endmethod 109 | 110 | method Action clear; 111 | full[2] <= False; 112 | endmethod 113 | endmodule 114 | */ 115 | 116 | // A bypass FIFO implementation 117 | // notFull < enq < {notEmpty, first} < deq < clear 118 | module mkBypassFifo(Fifo#(1, t)) provisos(Bits#(t, tSz)); 119 | Ehr#(2, t) data <- mkEhr(?); 120 | Ehr#(3, Bool) full <- mkEhr(False); 121 | 122 | method Bool notFull = !full[0]; 123 | 124 | method Action enq(t x) if(!full[0]); 125 | data[0] <= x; 126 | full[0] <= True; 127 | endmethod 128 | 129 | method Bool notEmpty = full[1]; 130 | 131 | method Action deq if(full[1]); 132 | full[1] <= False; 133 | endmethod 134 | 135 | method t first if(full[1]); 136 | return data[1]; 137 | endmethod 138 | 139 | method Action clear; 140 | full[2] <= False; 141 | endmethod 142 | endmodule 143 | 144 | // (* synthesize *) 145 | // module mkBypassFifo_Synth(Fifo#(1, int)); 146 | // let _f <- mkBypassFifo; 147 | // return _f; 148 | // endmodule 149 | 150 | ////////////////////////////////////////////////////////////////////// 151 | 152 | // A Conflict free implementation of n element FIFO 153 | // {notEmpty, first} < deq < clear < canonicalize 154 | // notFull < enq < clear < canonicalize 155 | // deq conflict free with enq 156 | // canonicalize has no effect after clear anyway 157 | 158 | module mkCFFifo(Fifo#(n, t)) provisos(Bits#(t, tSz), 159 | Add#(n, 1, n1), 160 | Log#(n1, sz), 161 | Add#(sz, 1, sz1)); 162 | Integer ni = valueOf(n); 163 | Bit#(sz1) nb = fromInteger(ni); 164 | Bit#(sz1) n2 = 2*nb; 165 | Vector#(n, Reg#(t)) data <- replicateM(mkRegU); 166 | Ehr#(3, Bit#(sz1)) enqP <- mkEhr(0); 167 | Ehr#(3, Bit#(sz1)) deqP <- mkEhr(0); 168 | Ehr#(3, Bool) enqEn <- mkEhr(True); 169 | Ehr#(3, Bool) deqEn <- mkEhr(False); 170 | Ehr#(2, t) tempData <- mkEhr(?); 171 | Ehr#(2, Maybe#(Bit#(sz1))) tempEnqP <- mkEhr(Invalid); 172 | 173 | rule canonicalize; 174 | Bit#(sz1) cnt = enqP[2] >= deqP[2]? enqP[2] - deqP[2]: 175 | (enqP[2]%nb + nb) - deqP[2]%nb; 176 | if(!enqEn[2] && cnt != nb) enqEn[2] <= True; 177 | if(!deqEn[2] && cnt != 0) deqEn[2] <= True; 178 | 179 | if(isValid(tempEnqP[1])) 180 | begin 181 | data[validValue(tempEnqP[1])] <= tempData[1]; 182 | tempEnqP[1] <= Invalid; 183 | end 184 | endrule 185 | 186 | method Bool notFull = enqEn[0]; 187 | 188 | method Action enq(t x) if(enqEn[0]); 189 | tempData[0] <= x; 190 | tempEnqP[0] <= Valid (enqP[0]%nb); 191 | enqP[0] <= (enqP[0] + 1)%n2; 192 | enqEn[0] <= False; 193 | endmethod 194 | 195 | method Bool notEmpty = deqEn[0]; 196 | 197 | method Action deq if(deqEn[0]); 198 | deqP[0] <= (deqP[0] + 1)%n2; 199 | deqEn[0] <= False; 200 | endmethod 201 | 202 | method t first if(deqEn[0]); 203 | return data[deqP[0]%nb]; 204 | endmethod 205 | 206 | method Action clear; 207 | enqP[1] <= 0; 208 | deqP[1] <= 0; 209 | enqEn[1] <= True; 210 | deqEn[1] <= False; 211 | endmethod 212 | endmodule 213 | 214 | // (* synthesize *) 215 | // module mkCFFifo_Synth(Fifo#(4, int)); 216 | // let _f <- mkCFFifo; 217 | // return _f; 218 | // endmodule 219 | 220 | ////////////////////////////////////////////////////////////////////// 221 | 222 | 223 | // A pipelined implementation of n element FIFO 224 | // {notEmpty, first} < deq < notFull < enq < clear 225 | 226 | module mkPipelineFifo(Fifo#(n, t)) provisos(Bits#(t, tSz), 227 | Add#(n, 1, n1), 228 | Log#(n1, sz), 229 | Add#(sz, 1, sz1)); 230 | Integer ni = valueOf(n); 231 | Bit#(sz1) nb = fromInteger(ni); 232 | Bit#(sz1) n2 = 2*nb; 233 | Vector#(n, Reg#(t)) data <- replicateM(mkRegU); 234 | Ehr#(3, Bit#(sz1)) enqP <- mkEhr(0); 235 | Ehr#(2, Bit#(sz1)) deqP <- mkEhr(0); 236 | 237 | Bit#(sz1) cnt0 = enqP[0] >= deqP[0]? enqP[0] - deqP[0]: 238 | (enqP[0]%nb + nb) - deqP[0]%nb; 239 | Bit#(sz1) cnt1 = enqP[0] >= deqP[1]? enqP[0] - deqP[1]: 240 | (enqP[0]%nb + nb) - deqP[1]%nb; 241 | 242 | method Bool notFull = cnt1 < nb; 243 | 244 | method Action enq(t x) if(cnt1 < nb); 245 | enqP[0] <= (enqP[0] + 1)%n2; 246 | data[enqP[0]%nb] <= x; 247 | endmethod 248 | 249 | method Bool notEmpty = cnt0 != 0; 250 | 251 | method Action deq if(cnt0 != 0); 252 | deqP[0] <= (deqP[0] + 1)%n2; 253 | endmethod 254 | 255 | method t first if(cnt0 != 0); 256 | return data[deqP[0]%nb]; 257 | endmethod 258 | 259 | method Action clear; 260 | enqP[2] <= 0; 261 | deqP[1] <= 0; 262 | endmethod 263 | endmodule 264 | 265 | // (* synthesize *) 266 | // module mkPipelineFifo_Synth(Fifo#(4, int)); 267 | // let _f <- mkPipelineFifo; 268 | // return _f; 269 | // endmodule 270 | 271 | 272 | 273 | 274 | ////////////////////////////////////////////////////////////////////// 275 | // Searchable FIFO has an extra search method 276 | ////////////////////////////////////////////////////////////////////// 277 | interface SFifo#(numeric type n, type t, type st); 278 | method Bool notFull; 279 | method Action enq(t x); 280 | method Bool notEmpty; 281 | method Action deq; 282 | method Bool search(st s); 283 | method t first; 284 | method Action clear; 285 | endinterface 286 | 287 | // search is conflict-free with {enq, deq, first, notFull, notEmpty} 288 | // search < clear < canonicalize 289 | module mkCFSFifo#(function Bool isFound(t v, st k)) 290 | (SFifo#(n, t, st)) 291 | provisos(Bits#(t, tSz), 292 | Add#(n, 1, n1), 293 | Log#(n1, sz), 294 | Add#(sz, 1, sz1)); 295 | Integer ni = valueOf(n); 296 | Bit#(sz1) nb = fromInteger(ni); 297 | Bit#(sz1) n2 = 2*nb; 298 | Vector#(n, Reg#(t)) data <- replicateM(mkRegU); 299 | Ehr#(3, Bit#(sz1)) enqP <- mkEhr(0); 300 | Ehr#(3, Bit#(sz1)) deqP <- mkEhr(0); 301 | Ehr#(3, Bool) enqEn <- mkEhr(True); 302 | Ehr#(3, Bool) deqEn <- mkEhr(False); 303 | Ehr#(2, t) tempData <- mkEhr(?); 304 | Ehr#(2, Maybe#(Bit#(sz1))) tempEnqP <- mkEhr(Invalid); 305 | Ehr#(2, Maybe#(Bit#(sz1))) tempDeqP <- mkEhr(Invalid); 306 | 307 | Bit#(sz1) cnt0 = enqP[0] >= deqP[0]? enqP[0] - deqP[0]: 308 | (enqP[0]%nb + nb) - deqP[0]%nb; 309 | Bit#(sz1) cnt2 = enqP[2] >= deqP[2]? enqP[2] - deqP[2]: 310 | (enqP[2]%nb + nb) - deqP[2]%nb; 311 | rule canonicalize; 312 | if(!enqEn[2] && cnt2 != nb) enqEn[2] <= True; 313 | if(!deqEn[2] && cnt2 != 0) deqEn[2] <= True; 314 | 315 | if(isValid(tempEnqP[1])) 316 | begin 317 | data[validValue(tempEnqP[1])] <= tempData[1]; 318 | tempEnqP[1] <= Invalid; 319 | end 320 | 321 | if(isValid(tempDeqP[1])) 322 | begin 323 | deqP[0] <= validValue(tempDeqP[1]); 324 | tempDeqP[1] <= Invalid; 325 | end 326 | endrule 327 | 328 | method Bool notFull = enqEn[0]; 329 | 330 | method Action enq(t x) if(enqEn[0]); 331 | tempData[0] <= x; 332 | tempEnqP[0] <= Valid (enqP[0]%nb); 333 | enqP[0] <= (enqP[0] + 1)%n2; 334 | enqEn[0] <= False; 335 | endmethod 336 | 337 | method Bool notEmpty = deqEn[0]; 338 | 339 | method Action deq if(deqEn[0]); 340 | tempDeqP[0] <= Valid ((deqP[0] + 1)%n2); 341 | deqEn[0] <= False; 342 | endmethod 343 | 344 | method t first if(deqEn[0]); 345 | return data[deqP[0]%nb]; 346 | endmethod 347 | 348 | method Bool search(st s); 349 | Bool ret = False; 350 | for(Bit#(sz1) i = 0; i < nb; i = i + 1) 351 | begin 352 | let ptr = (deqP[0] + i)%nb; 353 | if(isFound(data[ptr], s) && i < cnt0) 354 | ret = True; 355 | end 356 | return ret; 357 | endmethod 358 | 359 | method Action clear; 360 | enqP[1] <= 0; 361 | deqP[1] <= 0; 362 | enqEn[1] <= True; 363 | deqEn[1] <= False; 364 | endmethod 365 | endmodule 366 | 367 | // {notEmpty, first} < deq < search 368 | // search CF {enq, notFull} 369 | // search < clear 370 | module mkPipelineSFifo#(function Bool isFound(t v, st k))(SFifo#(n, t, st)) provisos(Bits#(t, tSz), Add#(n, 1, n1), Log#(n1, sz), Add#(sz, 1, sz1), Bits#(st, stz)); 371 | Integer ni = valueOf(n); 372 | Bit#(sz1) nb = fromInteger(ni); 373 | Bit#(sz1) n2 = 2*nb; 374 | Vector#(n, Reg#(t)) data <- replicateM(mkRegU); 375 | Ehr#(3, Bit#(sz1)) enqP <- mkEhr(0); 376 | Ehr#(2, Bit#(sz1)) deqP <- mkEhr(0); 377 | 378 | Bit#(sz1) cnt0 = enqP[0] >= deqP[0]? enqP[0] - deqP[0]: 379 | (enqP[0]%nb + nb) - deqP[0]%nb; 380 | Bit#(sz1) cnt1 = enqP[0] >= deqP[1]? enqP[0] - deqP[1]: 381 | (enqP[0]%nb + nb) - deqP[1]%nb; 382 | 383 | method Bool notFull = cnt1 < nb; 384 | 385 | method Action enq(t x) if(cnt1 < nb); 386 | enqP[0] <= (enqP[0] + 1)%n2; 387 | data[enqP[0]%nb] <= x; 388 | endmethod 389 | 390 | method Bool notEmpty = cnt0 != 0; 391 | 392 | method Action deq if(cnt0 != 0); 393 | deqP[0] <= (deqP[0] + 1)%n2; 394 | endmethod 395 | 396 | method t first if(cnt0 != 0); 397 | return data[deqP[0]%nb]; 398 | endmethod 399 | 400 | method Bool search(st s); 401 | Bool ret = False; 402 | for(Bit#(sz1) i = 0; i < nb; i = i + 1) 403 | begin 404 | let ptr = (deqP[1] + i)%nb; 405 | if(isFound(data[ptr], s) && i < cnt1) 406 | ret = True; 407 | end 408 | return ret; 409 | endmethod 410 | 411 | method Action clear; 412 | enqP[2] <= 0; 413 | deqP[1] <= 0; 414 | endmethod 415 | endmodule 416 | 417 | // Searchable Count FIFO has an extra search method which returns the count of the number of elements found 418 | interface SCountFifo#(numeric type n, type t, type st); 419 | method Bool notFull; 420 | method Action enq(t x); 421 | method Bool notEmpty; 422 | method Action deq; 423 | method Bit#(TLog#(TAdd#(n, 1))) search(st s); 424 | method t first; 425 | method Action clear; 426 | endinterface 427 | 428 | // search is conflict-free with {enq, deq, first, notFull, notEmpty} 429 | // search < clear < canonicalize 430 | module mkCFSCountFifo#(function Bool isFound(t v, st k))(SCountFifo#(n, t, st)) provisos(Bits#(t, tSz), Add#(n, 1, n1), Log#(n1, sz), Add#(sz, 1, sz1)); 431 | Integer ni = valueOf(n); 432 | Bit#(sz1) nb = fromInteger(ni); 433 | Bit#(sz1) n2 = 2*nb; 434 | Vector#(n, Reg#(t)) data <- replicateM(mkRegU); 435 | Ehr#(3, Bit#(sz1)) enqP <- mkEhr(0); 436 | Ehr#(3, Bit#(sz1)) deqP <- mkEhr(0); 437 | Ehr#(3, Bool) enqEn <- mkEhr(True); 438 | Ehr#(3, Bool) deqEn <- mkEhr(False); 439 | Ehr#(2, t) tempData <- mkEhr(?); 440 | Ehr#(2, Maybe#(Bit#(sz1))) tempEnqP <- mkEhr(Invalid); 441 | Ehr#(2, Maybe#(Bit#(sz1))) tempDeqP <- mkEhr(Invalid); 442 | 443 | Bit#(sz1) cnt0 = enqP[0] >= deqP[0]? enqP[0] - deqP[0]: 444 | (enqP[0]%nb + nb) - deqP[0]%nb; 445 | Bit#(sz1) cnt2 = enqP[2] >= deqP[2]? enqP[2] - deqP[2]: 446 | (enqP[2]%nb + nb) - deqP[2]%nb; 447 | rule canonicalize; 448 | if(!enqEn[2] && cnt2 != nb) enqEn[2] <= True; 449 | if(!deqEn[2] && cnt2 != 0) deqEn[2] <= True; 450 | 451 | if(isValid(tempEnqP[1])) 452 | begin 453 | data[validValue(tempEnqP[1])] <= tempData[1]; 454 | tempEnqP[1] <= Invalid; 455 | end 456 | 457 | if(isValid(tempDeqP[1])) 458 | begin 459 | deqP[0] <= validValue(tempDeqP[1]); 460 | tempDeqP[1] <= Invalid; 461 | end 462 | endrule 463 | 464 | method Bool notFull = enqEn[0]; 465 | 466 | method Action enq(t x) if(enqEn[0]); 467 | tempData[0] <= x; 468 | tempEnqP[0] <= Valid (enqP[0]%nb); 469 | enqP[0] <= (enqP[0] + 1)%n2; 470 | enqEn[0] <= False; 471 | endmethod 472 | 473 | method Bool notEmpty = deqEn[0]; 474 | 475 | method Action deq if(deqEn[0]); 476 | tempDeqP[0] <= Valid ((deqP[0] + 1)%n2); 477 | deqEn[0] <= False; 478 | endmethod 479 | 480 | method t first if(deqEn[0]); 481 | return data[deqP[0]%nb]; 482 | endmethod 483 | 484 | method Bit#(TLog#(TAdd#(n, 1))) search(st s); 485 | Bit#(TLog#(TAdd#(n, 1))) ret = 0; 486 | for(Bit#(sz1) i = 0; i < nb; i = i + 1) 487 | begin 488 | let ptr = (deqP[0] + i)%nb; 489 | if(isFound(data[ptr], s) && i < cnt0) 490 | ret = ret + 1; 491 | end 492 | return ret; 493 | endmethod 494 | 495 | method Action clear; 496 | enqP[1] <= 0; 497 | deqP[1] <= 0; 498 | enqEn[1] <= True; 499 | deqEn[1] <= False; 500 | endmethod 501 | endmodule 502 | 503 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | --------------------------------------------------------------------------------