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

Subversion Repositories cryptosorter

[/] [cryptosorter/] [trunk/] [memocodeDesignContest2008/] [xup/] [ExternalMemory/] [ExternalMemory.bsv] - Rev 3

Go to most recent revision | Compare with Previous | Blame | View Log

/*
Copyright (c) 2008 MIT

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.

Author: Kermin Fleming
*/

/*  This module serves as an abstraction layer for wrapping an external memory
    system.  In particular, it emulates a parametric number  of
    read and write virtual channels, sheilding the user module from the actual 
    details of the underlying memory system.  Thus, user modules may be 
    implemented targeting the same "External Memory" and then used in 
    systems with radically different memory subsystems. The module orders writes
    before reads. It is additionally parameterized by address width (Addr) 
    and data width.
*/ 


import Memocode08Types::*;
import Vector::*;
import FIFOF::*;
import Types::*;
import Interfaces::*;
import Parameters::*;
import DebugFlags::*;
import GetPut::*;

module mkExternalMemory#(PLBMaster plbmaster) (ExternalMemory);

  FIFOF#(Bit#(TAdd#(1,TLog#(ReadPortNum)))) readRespFIFO <- mkFIFOF();  
  FIFOF#(Bit#(TAdd#(1,TLog#(ReadPortNum)))) writeFIFO <- mkFIFOF();  

  Reg#(Bit#(TLog#(RecordsPerBlock))) readRespCount  <- mkReg(0);
  Reg#(Bit#(TLog#(RecordsPerBlock))) writeCount <- mkReg(0);
  Reg#(Bit#(TLog#(TAdd#(TAdd#(WritePortNum,ReadPortNum),1))))  outstandingCount <- mkReg(0);
  Reg#(Bit#(TLog#(TAdd#(WritePortNum,ReadPortNum))))  nextToSend <- mkReg(0);

  
  FIFOF#(Vector#(TAdd#(ReadPortNum, WritePortNum), Maybe#(PLBMasterCommand))) reqSnapshot <- mkSizedFIFOF(1);
  
  Vector#(ReadPortNum, RWire#(Addr)) readReqs <- replicateM(mkRWire);
  Vector#(WritePortNum, RWire#(Addr)) writeReqs <- replicateM(mkRWire);
    
  Vector#(ReadPortNum, Read) readInterfaces = newVector();
  Vector#(WritePortNum, Write) writeInterfaces = newVector();

 
  for(Integer i = 0; i < valueof(ReadPortNum); i = i + 1)
    begin
      readInterfaces[i] = 
        interface Read;
          // Should we go round robin?
          method Action readReq(Addr addr) if(reqSnapshot.notFull());
            debug(externalMemoryDebug,$display("ReadPort %d making ReadReq %h at %d", i, addr,$time));
            readReqs[i].wset(addr);                        
          endmethod

          // May want to use some buffering here.  Might help things out.
          method ActionValue#(Record) read() if(readRespFIFO.first() == 
                                                fromInteger(i));
            debug(externalMemoryDebug,$display("ReadPort %d making Read %d", i, readRespCount));
            if(readRespCount + 1 == 0)
              begin
                debug(externalMemoryDebug,$display("ReadPort %d Load Complete!", i));
                readRespFIFO.deq;
                readRespCount <= 0;
              end
            else
              begin
                readRespCount <= readRespCount + 1;
              end
            Record record <- plbmaster.wordOutput.get;
            return record;
          endmethod
        endinterface;                       
    end

  for(Integer i = 0; i < valueof(WritePortNum); i = i + 1)
    begin
      writeInterfaces[i] = 
        interface Write;
          // Should we go round robin?  SHould we delay as long as possible?
          method Action writeReq(Addr addr) if(reqSnapshot.notFull());
            debug(externalMemoryDebug,$display("WritePort %d making WriteReq %h", i, addr));
            writeReqs[i].wset(addr);
          endmethod

          // May want to use some buffering here.  Might help things out.
          method Action write(Record record) if(writeFIFO.first() == 
                                                fromInteger(i));
            if(writeCount + 1 == 0)
              begin
                debug(externalMemoryDebug,$display("WritePort %d Load Complete!", i));
                writeFIFO.deq;
                writeCount <= 0;
              end
            else
              begin
                writeCount <= writeCount + 1;
              end
            plbmaster.wordInput.put(record);
          endmethod
        endinterface;
                       
    end


  function checkMaybe(previous, maybeVal);
    if(maybeVal matches tagged Valid .data)
      begin
        return True;
      end
    else
      begin
        return previous;
      end
  endfunction
  
  function castStore(addrMaybe);
    if(addrMaybe matches tagged Valid .addr)
      begin 
        return tagged Valid StorePage(unpack(truncate(pack(addr))));    
      end
    else 
      begin
        return tagged Invalid; 
      end
  endfunction

  function castLoad(addrMaybe);
    if(addrMaybe matches tagged Valid .addr)
      begin 
        return tagged Valid LoadPage(unpack(truncate(pack(addr))));    
      end
    else 
      begin
        return tagged Invalid; 
      end
  endfunction

  function Maybe#(Addr) callwget(RWire#(Addr) rwire);
    return rwire.wget;
  endfunction

  rule processReqs;
    Bool shouldEnq = foldl(checkMaybe,False,append(map(callwget,writeReqs),map(callwget,readReqs)));
    if(shouldEnq)
      begin
        debug(externalMemoryDebug,$display("Processing Reqs at %d", $time));
        reqSnapshot.enq(append(map(castLoad, map(callwget,readReqs)),map(castStore,map(callwget,writeReqs))));        
      end
  endrule

  rule chooseReq;
    Maybe#(Bit#(TLog#(TAdd#(WritePortNum,ReadPortNum)))) sendTarget = tagged Invalid;
    for(Integer i = valueof(WritePortNum) + valueof(ReadPortNum) - 1; i >= 0; i = i - 1)
      begin
        if(reqSnapshot.first[i] matches tagged Valid .cmd &&& (fromInteger(i) >= nextToSend))
          begin
            sendTarget = tagged Valid fromInteger(i);
          end
      end   

    debug(externalMemoryDebug,$display("Sending Reqs, upto: %d, next index: %d", nextToSend, fromMaybe(-1,sendTarget)));

    if(sendTarget matches tagged Valid .index &&& reqSnapshot.first[index] matches tagged Valid .cmd)
      begin
        plbmaster.plbMasterCommandInput.put(cmd);
        if(cmd matches tagged LoadPage .addr)
          begin
            debug(externalMemoryDebug,$display("Issuing Load %d actual: %d", index, index));
            readRespFIFO.enq(truncate(index));                                
          end
        else 
          begin
            debug(externalMemoryDebug,$display("Issuing Store %d actual: %d", index, index-fromInteger(valueof(WritePortNum))));
            writeFIFO.enq(truncate(index-fromInteger(valueof(ReadPortNum))));                                
          end

        if(index >= fromInteger(valueof(WritePortNum)+ valueof(ReadPortNum) - 1)) 
          begin
            debug(externalMemoryDebug,$display("Req Q deq, due to last request"));
            reqSnapshot.deq;
            nextToSend <= 0;
          end 
        else
          begin
            nextToSend <= index + 1;
          end
      end 
    else 
      begin
        debug(externalMemoryDebug,$display("Req Q deq, due to no valid requests"));
        nextToSend <= 0;
        reqSnapshot.deq;
      end
     
  endrule


  // This is conservative...
  method Bool readsPending(); 
    return reqSnapshot.notEmpty || readRespFIFO.notEmpty;
  endmethod

  method Bool writesPending();
    return reqSnapshot.notEmpty || writeFIFO.notEmpty;
  endmethod

  interface  read = readInterfaces;
  interface  write = writeInterfaces;


endmodule





Go to most recent revision | 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.