OpenCores
URL https://opencores.org/ocsvn/cryptosorter/cryptosorter/trunk

Subversion Repositories cryptosorter

[/] [cryptosorter/] [trunk/] [memocodeDesignContest2008/] [sort/] [BRAMLevelFIFOAdders/] [BRAMVLevelFIFO.bsv] - Rev 6

Compare with Previous | Blame | View Log

//----------------------------------------------------------------------//
// The MIT License 
// 
// Copyright (c) 2008 Alfred Man Cheuk Ng, mcn02@mit.edu 
// 
// Permission is hereby granted, free of charge, to any person 
// obtaining a copy of this software and associated documentation 
// files (the "Software"), to deal in the Software without 
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//----------------------------------------------------------------------//

//////////////////////////////////////////////////////////////////////////
// Summary
//
// This file describes the implementation of VLevelFIFO which time multiplex
// a single memory instance with one write port and one read port between
// multiple logical fifos. The implementation is parameteric in the following
// ways: 1) the number of logical fifos, 2) the size of each logical fifo,
// 3) the data type stored in the fifo      
//////////////////////////////////////////////////////////////////////////

// import standard library
import DReg::*;
import FIFO::*;
import RegFile::*;
import StmtFSM::*;
import Vector::*;

// import self-made library
import BRAM::*;
import EHRReg::*;
import VLevelFIFO::*;

`define Debug False

// try to update the new value of vec[idx] to f(vec[idx]) 
function Vector#(sz,a) parUpdate (Vector#(sz,a) vec, Bit#(isz) idx, 
                                  function a f (a val));
   Vector#(sz,a) new_vec = newVector();
   for (Integer i = 0; i < valueOf(sz); i = i + 1)
      begin
         if (idx == fromInteger(i))
            new_vec[i] = f(vec[i]);
         else
            new_vec[i] = vec[i];
      end
   return new_vec;
endfunction
   
function Bit#(a) decrBy(Bit#(a) snd, Bit#(a) fst);
   return fst - snd;
endfunction
 
// implementation of VLevelFIFO with BRAM
module mkBRAMVLevelFIFO (VLevelFIFO#(no_fifo, fifo_sz, data_t))
   provisos (Bits#(data_t,data_sz),
             Add#(TLog#(no_fifo),TLog#(fifo_sz),bram_idx_sz));   

   // instantiate an unguarded 1 cycle latency bram (i.e. the read response will only valid for 1 cycle)  
   UGBRAM#(Bit#(bram_idx_sz), data_t)           ugbram <- mkBypassUGBRAM_Full();
   
   RegFile#(Bit#(TLog#(no_fifo)),Bit#(TLog#(fifo_sz)))  head <- mkRegFileFull();
   RegFile#(Bit#(TLog#(no_fifo)),Bit#(TLog#(fifo_sz)))  tail <- mkRegFileFull();
   Reg#(Bit#(TLog#(no_fifo))) i <- mkReg(0);
   Reg#(Bool) finishInit <- mkReg(False);
   
   EHRReg#(2,Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))))  usedReg;
   usedReg <- mkEHRReg(replicate(0));  
   EHRReg#(2,Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))))  freeReg;
   freeReg <- mkEHRReg(replicate(fromInteger(valueOf(fifo_sz))));

   Wire#(Maybe#(Bit#(TLog#(no_fifo))))  enqIdx <- mkDWire(tagged Invalid);
   Wire#(data_t)                        enqVal <- mkDWire(?);
   Reg#(Maybe#(Bit#(TLog#(no_fifo))))   lastEnqIdx <- mkDReg(tagged Invalid);     
   
   Wire#(Maybe#(Bit#(TLog#(no_fifo))))  deqIdx <- mkDWire(tagged Invalid);
   Reg#(Maybe#(Bit#(TLog#(no_fifo))))   lastDeqIdx <- mkDReg(tagged Invalid);     

   Wire#(Maybe#(Bit#(TLog#(no_fifo))))  firstIdx <- mkDWire(tagged Invalid);
   
   Wire#(Maybe#(Bit#(TLog#(no_fifo))))  decrFreeIdx <- mkDWire(tagged Invalid);
   Wire#(Bit#(TLog#(TAdd#(fifo_sz,1)))) decrFreeAmnt <- mkDWire(?);
      
   let enqIdxVal         = fromMaybe(0,enqIdx);
   let deqIdxVal         = fromMaybe(0,deqIdx);
   let firstIdxVal       = fromMaybe(0,firstIdx);
   let decrFreeIdxVal    = fromMaybe(0,decrFreeIdx);
   let deqIdxNEQFirstIdx = deqIdxVal != firstIdxVal;  
   let readResp          = ugbram.read_resp();
     
   // start the initialization processor
   rule initialization(!finishInit);
      head.upd(i,0);
      tail.upd(i,0);
      i <= i + 1;
      if (i == fromInteger(valueOf(no_fifo)-1))
         finishInit <= True;
   endrule   
   
   rule processEnq(finishInit && isValid(enqIdx));
      let tailVal = tail.sub(enqIdxVal);
      tail.upd(enqIdxVal, (tailVal + 1));
      ugbram.write({enqIdxVal,tailVal},enqVal);
      lastEnqIdx <= enqIdx;
      
      if(`Debug) $display("%m enq data %d to fifo %d with tailVal %d",enqVal,enqIdxVal,tailVal);
   endrule
    
   // last cycle someone enq, we update the usedReg this cycle (conservative
   rule updateUsedReg (isValid(lastEnqIdx));
      let idx = fromMaybe(?,lastEnqIdx);
      usedReg[0] <= parUpdate(usedReg[0], idx, \+ (1));

      if(`Debug) $display("%m updateUsedReg idx %d old val %d new val %d",idx,usedReg[0][idx], usedReg[1][idx]);
   endrule  
      
   // last cycle someone deq, we update the freeReg this cycle (conservative)
   rule updateFreeReg (isValid(lastDeqIdx));
      let idx = fromMaybe(?,lastDeqIdx);
      freeReg[0] <= parUpdate(freeReg[0], idx, \+ (1));

      if(`Debug) $display("%m updateFreeReg idx %d old val %d new val %d",idx,freeReg[0][idx], freeReg[1][idx]);
   endrule  
   
   rule processDeq(finishInit && isValid(deqIdx));
      let headVal = head.sub(deqIdxVal);
      head.upd(deqIdxVal, (headVal + 1));     
      usedReg[1] <= parUpdate(usedReg[1], deqIdxVal, decrBy(1));
      lastDeqIdx <= deqIdx;

      if(`Debug) $display("%m deq fifo %d",deqIdxVal);
   endrule
   
   rule processFirstReq(finishInit && isValid(firstIdx));
      let headVal = head.sub(firstIdxVal);
      ugbram.read_req({firstIdxVal,headVal});
//       if (deqIdxNEQFirstIdx || !isValid(deqIdx))
//          begin
//             ugbram.read_req({firstIdxVal,headVal});
            
//             if(`Debug) $display("%m first read idx %d headVal %d",firstIdxVal,headVal);
//          end
//       else // the fifo is dequeued at that cycle, we should read the next head
//          begin
//             ugbram.read_req({firstIdxVal,headVal+1});
            
//             if(`Debug) $display("%m first read idx %d headVal+1 %d",firstIdxVal,headVal+1);
//          end
   endrule
           
   rule processDecrFree(finishInit && isValid(decrFreeIdx));             
      freeReg[1] <= parUpdate(freeReg[1], decrFreeIdxVal, decrBy(decrFreeAmnt));
      
      if(`Debug) $display("%m decrFree fifo %d by %d",decrFreeIdxVal,decrFreeAmnt);
   endrule

   // enq is unguarded here, we expect the user to check it before they enq
   method Action enq(Bit#(TLog#(no_fifo)) idx, data_t data) if (finishInit);
      enqIdx <= tagged Valid idx;
      enqVal <= data;      
   endmethod
   
   // deq is unguarded here, we expect the user to check it before they deq
   method Action deq(Bit#(TLog#(no_fifo)) idx)  if (finishInit);
      deqIdx <= tagged Valid idx;    
   endmethod
   
   method Action firstReq(Bit#(TLog#(no_fifo)) idx)  if (finishInit);
      firstIdx <= tagged Valid idx;
   endmethod
   
   // first is unguarded here, we expecte the user to check it before they call first
   method data_t firstResp()  if (finishInit);
      return readResp;
   endmethod
   
   method Action clear()  if (finishInit);
      noAction;
   endmethod
   
   // return the usage of each fifo at the beginning of the cycle
   method Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))) used()  if (finishInit);
      return usedReg[0];
   endmethod
   
   // return enq credit token available for each fifo
   method Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))) free()  if (finishInit);
      return freeReg[0];
   endmethod
   
   // get credit token to enq fifo idx in the future
   // this method is unguarded (i.e. user need to call method free 
   // and check for token availability before calling this action)
   method Action decrFree(Bit#(TLog#(no_fifo)) idx, Bit#(TLog#(TAdd#(fifo_sz,1))) amnt)  if (finishInit);
      decrFreeIdx  <= tagged Valid idx;
      decrFreeAmnt <= amnt; 
   endmethod
   
endmodule
 
// implementation of VLevelFIFO with BRAM decrFree is always treated as deq one token
module mkDecrOneBRAMVLevelFIFO (VLevelFIFO#(no_fifo, fifo_sz, data_t))
   provisos (Bits#(data_t,data_sz),
             Add#(TLog#(no_fifo),TLog#(fifo_sz),bram_idx_sz));   

   // instantiate an unguarded 1 cycle latency bram (i.e. the read response will only valid for 1 cycle)  
   UGBRAM#(Bit#(bram_idx_sz), data_t)           ugbram <- mkBypassUGBRAM_Full();
   
   RegFile#(Bit#(TLog#(no_fifo)),Bit#(TLog#(fifo_sz)))  head <- mkRegFileFull();
   RegFile#(Bit#(TLog#(no_fifo)),Bit#(TLog#(fifo_sz)))  tail <- mkRegFileFull();
   Reg#(Bit#(TLog#(no_fifo))) i <- mkReg(0);
   Reg#(Bool) finishInit <- mkReg(False);
   
   Reg#(Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))))  usedReg <- mkReg(replicate(0));
   
   Reg#(Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))))  freeReg <- mkReg(replicate(fromInteger(valueOf(fifo_sz))));
   
   Wire#(Maybe#(Bit#(TLog#(no_fifo)))) enqIdx <- mkDWire(tagged Invalid);
   Wire#(data_t)                       enqVal <- mkDWire(?);
   
   Wire#(Maybe#(Bit#(TLog#(no_fifo)))) deqIdx <- mkDWire(tagged Invalid);

   Wire#(Maybe#(Bit#(TLog#(no_fifo)))) firstIdx <- mkDWire(tagged Invalid);
   
   Wire#(Maybe#(Bit#(TLog#(no_fifo)))) decrFreeIdx <- mkDWire(tagged Invalid);
      
   let enqIdxVal         = fromMaybe(0,enqIdx);
   let deqIdxVal         = fromMaybe(0,deqIdx);
   let firstIdxVal       = fromMaybe(0,firstIdx);
   let decrFreeIdxVal    = fromMaybe(0,decrFreeIdx);
   let deqIdxNEQFirstIdx = deqIdxVal != firstIdxVal;  
   let readResp          = ugbram.read_resp();
     
   // start the initialization processor
   rule initialization(!finishInit);
      head.upd(i,0);
      tail.upd(i,0);
      i <= i + 1;
      if (i == fromInteger(valueOf(no_fifo)-1))
         finishInit <= True;
   endrule
   
   rule updateUsedReg(finishInit && (isValid(enqIdx) || isValid(deqIdx)));
      Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))) newUsedReg = newVector();
      for (Integer i = 0; i < valueOf(no_fifo); i = i + 1)
         begin
            Bit#(TLog#(no_fifo)) iVal = fromInteger(i);
            let checkEnqIdx = enqIdxVal == iVal;
            let checkDeqIdx = deqIdxVal == iVal;
            if (isValid(enqIdx) && checkEnqIdx && !(isValid(deqIdx) && checkDeqIdx))
               newUsedReg[i] = usedReg[i] + 1;
            else
               if (isValid(deqIdx) && checkDeqIdx && !(isValid(enqIdx) && checkEnqIdx))
                  newUsedReg[i] = usedReg[i] - 1;
               else
                  newUsedReg[i] = usedReg[i];
         end
      usedReg <= newUsedReg;

      if(`Debug) $display("%m updateUsedReg");
   endrule
   
   rule updateFreeReg(finishInit && (isValid(decrFreeIdx) || isValid(deqIdx)));
      Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))) newFreeReg = newVector();
      for (Integer i = 0; i < valueOf(no_fifo); i = i + 1)
         begin
            Bit#(TLog#(no_fifo)) iVal = fromInteger(i);
            let checkDecrFreeIdx      = decrFreeIdxVal == iVal;
            let checkDeqIdx           = deqIdxVal == iVal;
            if (isValid(decrFreeIdx) && checkDecrFreeIdx && !(isValid(deqIdx) && checkDeqIdx))
               newFreeReg[i] = freeReg[i] - 1;
            else
               if (isValid(deqIdx) && checkDeqIdx && !(isValid(decrFreeIdx) && checkDecrFreeIdx))
                  newFreeReg[i] = freeReg[i] + 1;               
               else
                  newFreeReg[i] = freeReg[i];               
         end
      freeReg <= newFreeReg;

      if(`Debug) $display("%m updateFreeReg");
   endrule
   
   rule processEnq(finishInit && isValid(enqIdx));
      let tailVal = tail.sub(enqIdxVal);
      tail.upd(enqIdxVal, (tailVal + 1));
      ugbram.write({enqIdxVal,tailVal},enqVal);

      if(`Debug) $display("%m enq data %d to fifo %d with tailVal %d",enqVal,enqIdxVal,tailVal);
   endrule
   
   rule processFirstReq(finishInit && isValid(firstIdx));
      let headVal = head.sub(firstIdxVal);
      ugbram.read_req({firstIdxVal,headVal});
      
//       if (deqIdxNEQFirstIdx || !isValid(deqIdx))
//          begin
//             ugbram.read_req({firstIdxVal,headVal});
//             if(`Debug) $display("%m first read idx %d headVal %d",firstIdxVal,headVal);
//          end
//       else // the fifo is dequeued at that cycle, we should read the next head
//          begin
//             ugbram.read_req({firstIdxVal,headVal+1});
//             if(`Debug) $display("%m first read idx %d headVal+1 %d",firstIdxVal,headVal+1);
//          end
   endrule

   rule processDeq(finishInit && isValid(deqIdx));
      let headVal = head.sub(deqIdxVal);
      head.upd(deqIdxVal, (headVal + 1));      
   endrule
   
   // enq is unguarded here, we expect the user to check it before they enq
   method Action enq(Bit#(TLog#(no_fifo)) idx, data_t data) if (finishInit);
      enqIdx <= tagged Valid idx;
      enqVal <= data;      
   endmethod
   
   // deq is unguarded here, we expect the user to check it before they deq
   method Action deq(Bit#(TLog#(no_fifo)) idx)  if (finishInit);
      deqIdx <= tagged Valid idx;
      
      if(`Debug) $display("%m deq fifo %d",idx);
   endmethod
   
   method Action firstReq(Bit#(TLog#(no_fifo)) idx)  if (finishInit);
      firstIdx <= tagged Valid idx;
   endmethod
   
   // first is unguarded here, we expecte the user to check it before they call first
   method data_t firstResp()  if (finishInit);
      return readResp;
   endmethod
   
   method Action clear()  if (finishInit);
      noAction;
   endmethod
   
   // return the usage of each fifo at the beginning of the cycle
   method Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))) used()  if (finishInit);
      return usedReg;
   endmethod
   
   // return enq credit token available for each fifo
   method Vector#(no_fifo,Bit#(TLog#(TAdd#(fifo_sz,1)))) free()  if (finishInit);
      return freeReg;
   endmethod
   
   // get credit token to enq fifo idx in the future
   // this method is unguarded (i.e. user need to call method free 
   // and check for token availability before calling this action)
   method Action decrFree(Bit#(TLog#(no_fifo)) idx, Bit#(TLog#(TAdd#(fifo_sz,1))) amnt)  if (finishInit);
      decrFreeIdx <= tagged Valid idx;
   endmethod
   
endmodule

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.