text: /*
   * Copyright (c) 2013-2014 ARM Limited
   * All rights reserved
   *
   * The license below extends only to copyright in the software and shall
   * not be construed as granting a license to any other intellectual
   * property including but not limited to intellectual property relating
   * to a hardware implementation of the functionality of the software
   * licensed hereunder.  You may use the software subject to the license
   * terms below provided that you ensure that this notice is replicated
   * unmodified and in its entirety in all distributions of the software,
   * modified or unmodified, in source code or in binary form.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are
   * met: redistributions of source code must retain the above copyright
   * notice, this list of conditions and the following disclaimer;
   * redistributions in binary form must reproduce the above copyright
   * notice, this list of conditions and the following disclaimer in the
   * documentation and/or other materials provided with the distribution;
   * neither the name of the copyright holders nor the names of its
   * contributors may be used to endorse or promote products derived from
   * this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * Authors: Andrew Bardsley
   */
  
  /**
   * @file
   *
   *  Fetch1 is responsible for fetching "lines" from memory and passing
   *  them to Fetch2
   */
  
  #ifndef __CPU_MINOR_FETCH1_HH__
  #define __CPU_MINOR_FETCH1_HH__
  
  #include "cpu/minor/buffers.hh"
  #include "cpu/minor/cpu.hh"
  #include "cpu/minor/pipe_data.hh"
  #include "cpu/base.hh"
  #include "mem/packet.hh"
  
  namespace Minor
  {
  
  /** A stage responsible for fetching "lines" from memory and passing
   *  them to Fetch2 */
  class Fetch1 : public Named
  {
    protected:
      /** Exposable fetch port */
      class IcachePort : public MinorCPU::MinorCPUPort
      {
        protected:
          /** My owner */
          Fetch1 &fetch;
  
        public:
          IcachePort(std::string name, Fetch1 &fetch_, MinorCPU &cpu) :
              MinorCPU::MinorCPUPort(name, cpu), fetch(fetch_)
          { }
  
        protected:
          bool recvTimingResp(PacketPtr pkt)
          { return fetch.recvTimingResp(pkt); }
  
          void recvReqRetry() { fetch.recvReqRetry(); }
      };
  
      /** Memory access queuing.
       *
       *  A request can be submitted by pushing it onto the requests queue after
       *  issuing an ITLB lookup (state becomes InTranslation) with a
       *  FetchSenderState senderState containing the current lineSeqNum and
       *  stream/predictionSeqNum.
       *
       *  Translated packets (state becomes Translation) are then passed to the
       *  memory system and the transfers queue (state becomes RequestIssuing).
       *  Retries are handled by leaving the packet on the requests queue and
       *  changing the state to IcacheNeedsRetry).
       *
       *  Responses from the memory system alter the request object (state
       *  become Complete).  Responses can be picked up from the head of the
       *  transfers queue to pass on to Fetch2. */
  
      /** Structure to hold SenderState info through
       *  translation and memory accesses. */
      class FetchRequest :
          public BaseTLB::Translation, /* For TLB lookups */
          public Packet::SenderState /* For packing into a Packet */
      {
        protected:
          /** Owning fetch unit */
          Fetch1 &fetch;
  
        public:
          /** Progress of this request through address translation and
           *  memory */
          enum FetchRequestState
          {
              NotIssued, /* Just been made */
              InTranslation, /* Issued to ITLB, must wait for reqply */
              Translated, /* Translation complete */
              RequestIssuing, /* Issued to memory, must wait for response */
              Complete /* Complete.  Either a fault, or a fetched line */
          };
  
          FetchRequestState state;
  
          /** Identity of the line that this request will generate */
          InstId id;
  
          /** FetchRequests carry packets while they're in the requests and
           * transfers responses queues.  When a Packet returns from the memory
           * system, its request needs to have its packet updated as this may
           * have changed in flight */
          PacketPtr packet;
  
          /** The underlying request that this fetch represents */
          Request request;
  
          /** PC to fixup with line address */
          TheISA::PCState pc;
  
          /** Fill in a fault if one happens during fetch, check this by
           *  picking apart the response packet */
          Fault fault;
  
          /** Make a packet to use with the memory transaction */
          void makePacket();
  
          /** Report interface */
          void reportData(std::ostream &os) const;
  
          /** Is this line out of date with the current stream/prediction
           *  sequence and can it be discarded without orphaning in flight
           *  TLB lookups/memory accesses? */
          bool isDiscardable() const;
  
          /** Is this a complete read line or fault */
          bool isComplete() const { return state == Complete; }
  
        protected:
          /** BaseTLB::Translation interface */
  
          /** Interface for ITLB responses.  We can handle delay, so don't
           *  do anything */
          void markDelayed() { }
  
          /** Interface for ITLB responses.  Populates self and then passes
           *  the request on to the ports' handleTLBResponse member
           *  function */
          void finish(const Fault &fault_, RequestPtr request_,
                      ThreadContext *tc, BaseTLB::Mode mode);
  
        public:
          FetchRequest(Fetch1 &fetch_, InstId id_, TheISA::PCState pc_) :
              SenderState(),
              fetch(fetch_),
              state(NotIssued),
              id(id_),
              packet(NULL),
              request(),
              pc(pc_),
              fault(NoFault)
          { }
  
          ~FetchRequest();
      };
  
      typedef FetchRequest *FetchRequestPtr;
  
    protected:
      /** Construction-assigned data members */
  
      /** Pointer back to the containing CPU */
      MinorCPU &cpu;
  
      /** Input port carrying branch requests from Execute */
      Latch<BranchData>::Output inp;
      /** Output port carrying read lines to Fetch2 */
      Latch<ForwardLineData>::Input out;
      /** Input port carrying branch predictions from Fetch2 */
      Latch<BranchData>::Output prediction;
  
      /** Interface to reserve space in the next stage */
      Reservable &nextStageReserve;
  
      /** IcachePort to pass to the CPU.  Fetch1 is the only module that uses
       *  it. */
      IcachePort icachePort;
  
      /** Line snap size in bytes.  All fetches clip to make their ends not
       *  extend beyond this limit.  Setting this to the machine L1 cache line
       *  length will result in fetches never crossing line boundaries. */
      unsigned int lineSnap;
  
      /** Maximum fetch width in bytes.  Setting this (and lineSnap) to the
       *  machine L1 cache line length will result in fetches of whole cache
       *  lines.  Setting this to sizeof(MachInst) will result it fetches of
       *  single instructions (except near the end of lineSnap lines) */
      unsigned int maxLineWidth;
  
      /** Maximum number of fetches allowed in flight (in queues or memory) */
      unsigned int fetchLimit;
  
    protected:
      /** Cycle-by-cycle state */
  
      /** State of memory access for head instruction fetch */
      enum FetchState
      {
          FetchHalted, /* Not fetching, waiting to be woken by transition
              to FetchWaitingForPC.  The PC is not valid in this state */
          FetchWaitingForPC, /* Not fetching, waiting for stream change.
              This doesn't stop issued fetches from being returned and
              processed or for branches to change the state to Running. */
          FetchRunning /* Try to fetch, when possible */
      };
  
      /** Stage cycle-by-cycle state */
  
      FetchState state;
  
      /** Fetch PC value. This is updated by branches from Execute, branch
       *  prediction targets from Fetch2 and by incrementing it as we fetch
       *  lines subsequent to those two sources. */
      TheISA::PCState pc;
  
      /** Stream sequence number.  This changes on request from Execute and is
       *  used to tag instructions by the fetch stream to which they belong.
       *  Execute originates new prediction sequence numbers. */
      InstSeqNum streamSeqNum;
  
      /** Prediction sequence number.  This changes when requests from Execute
       *  or Fetch2 ask for a change of fetch address and is used to tag lines
       *  by the prediction to which they belong.  Fetch2 originates
       *  prediction sequence numbers. */
      InstSeqNum predictionSeqNum;
  
      /** Blocked indication for report */
      bool blocked;
  
      /** State of memory access for head instruction fetch */
      enum IcacheState
      {
          IcacheRunning, /* Default. Step icache queues when possible */
          IcacheNeedsRetry /* Request rejected, will be asked to retry */
      };
  
      typedef Queue<FetchRequestPtr,
          ReportTraitsPtrAdaptor<FetchRequestPtr>,
          NoBubbleTraits<FetchRequestPtr> >
          FetchQueue;
  
      /** Queue of address translated requests from Fetch1 */
      FetchQueue requests;
  
      /** Queue of in-memory system requests and responses */
      FetchQueue transfers;
  
      /** Retry state of icache_port */
      IcacheState icacheState;
  
      /** Sequence number for line fetch used for ordering lines to flush */
      InstSeqNum lineSeqNum;
  
      /** Count of the number fetches which have left the transfers queue
       *  and are in the 'wild' in the memory system.  Try not to rely on
       *  this value, it's better to code without knowledge of the number
       *  of outstanding accesses */
      unsigned int numFetchesInMemorySystem;
      /** Number of requests inside the ITLB rather than in the queues.
       *  All requests so located *must* have reserved space in the
       *  transfers queue */
      unsigned int numFetchesInITLB;
  
    protected:
      friend std::ostream &operator <<(std::ostream &os,
          Fetch1::FetchState state);
  
      /** Start fetching from a new address. */
      void changeStream(const BranchData &branch);
  
      /** Update streamSeqNum and predictionSeqNum from the given branch (and
       *  assume these have changed and discard (on delivery) all lines in
       *  flight) */
      void updateExpectedSeqNums(const BranchData &branch);
  
      /** Convert a response to a ForwardLineData */
      void processResponse(FetchRequestPtr response,
          ForwardLineData &line);
  
      friend std::ostream &operator <<(std::ostream &os,
          IcacheState state);
  
      /** Insert a line fetch into the requests.  This can be a partial
       *  line request where the given address has a non-0 offset into a
       *  line. */
      void fetchLine();
  
      /** Try and issue a fetch for a translated request at the
       *  head of the requests queue.  Also tries to move the request
       *  between queues */
      void tryToSendToTransfers(FetchRequestPtr request);
  
      /** Try to send (or resend) a memory request's next/only packet to
       *  the memory system.  Returns true if the fetch was successfully
       *  sent to memory */
      bool tryToSend(FetchRequestPtr request);
  
      /** Move a request between queues */
      void moveFromRequestsToTransfers(FetchRequestPtr request);
  
      /** Step requests along between requests and transfers queues */
      void stepQueues();
  
      /** Pop a request from the given queue and correctly deallocate and
       *  discard it. */
      void popAndDiscard(FetchQueue &queue);
  
      /** Handle pushing a TLB response onto the right queue */
      void handleTLBResponse(FetchRequestPtr response);
  
      /** Returns the total number of queue occupancy, in-ITLB and
       *  in-memory system fetches */
      unsigned int numInFlightFetches();
  
      /** Print the appropriate MinorLine line for a fetch response */
      void minorTraceResponseLine(const std::string &name,
          FetchRequestPtr response) const;
  
      /** Memory interface */
      virtual bool recvTimingResp(PacketPtr pkt);
      virtual void recvReqRetry();
  
    public:
      Fetch1(const std::string &name_,
          MinorCPU &cpu_,
          MinorCPUParams &params,
          Latch<BranchData>::Output inp_,
          Latch<ForwardLineData>::Input out_,
          Latch<BranchData>::Output prediction_,
          Reservable &next_stage_input_buffer);
  
    public:
      /** Returns the IcachePort owned by this Fetch1 */
      MinorCPU::MinorCPUPort &getIcachePort() { return icachePort; }
  
      /** Pass on input/buffer data to the output if you can */
      void evaluate();
  
      void minorTrace() const;
  
      /** Is this stage drained?  For Fetch1, draining is initiated by
       *  Execute signalling a branch with the reason HaltFetch */
      bool isDrained();
  };
  
  }
  
  #endif /* __CPU_MINOR_FETCH1_HH__ */
  