/*
 * Copyright (c) 2009 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * 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: Brad Beckmann
 *          Tushar Krishna
 */


machine(MachineType:Directory, "Garnet_standalone Directory")
    : MessageBuffer * requestToDir, network="From", virtual_network="0",
            vnet_type = "request";
      MessageBuffer * forwardToDir, network="From", virtual_network="1",
            vnet_type = "forward";
      MessageBuffer * responseToDir, network="From", virtual_network="2",
            vnet_type = "response";
{
  // STATES
  state_declaration(State, desc="Directory states", default="Directory_State_I") {
    // Base states
    I, AccessPermission:Invalid, desc="Invalid";
  }

  // Events
  enumeration(Event, desc="Directory events") {
    // processor requests
    Receive_Request, desc="Receive Message";
    Receive_Forward, desc="Receive Message";
    Receive_Response, desc="Receive Message";
  }

  // TYPES
  // DirectoryEntry
  structure(Entry, desc="...", interface="AbstractEntry") {
    State DirectoryState,          desc="Directory state";
    DataBlock DataBlk,             desc="data for the block";
  }

  // ** FUNCTIONS **
  Tick clockEdge();

  State getState(Addr addr) {
    return State:I;
  }

  void setState(Addr addr, State state) {

  }

  AccessPermission getAccessPermission(Addr addr) {
    return AccessPermission:NotPresent;
  }

  void setAccessPermission(Addr addr, State state) {
  }

  void functionalRead(Addr addr, Packet *pkt) {
    error("Garnet_standalone does not support functional read.");
  }

  int functionalWrite(Addr addr, Packet *pkt) {
    error("Garnet_standalone does not support functional write.");
  }

  // ** IN_PORTS **

  in_port(requestQueue_in, RequestMsg, requestToDir) {
    if (requestQueue_in.isReady(clockEdge())) {
      peek(requestQueue_in, RequestMsg) {
        if (in_msg.Type == CoherenceRequestType:MSG) {
          trigger(Event:Receive_Request, in_msg.addr);
        } else {
          error("Invalid message");
        }
      }
    }
  }
  in_port(forwardQueue_in, RequestMsg, forwardToDir) {
    if (forwardQueue_in.isReady(clockEdge())) {
      peek(forwardQueue_in, RequestMsg) {
        if (in_msg.Type == CoherenceRequestType:MSG) {
          trigger(Event:Receive_Forward, in_msg.addr);
        } else {
          error("Invalid message");
        }
      }
    }
  }
  in_port(responseQueue_in, RequestMsg, responseToDir) {
    if (responseQueue_in.isReady(clockEdge())) {
      peek(responseQueue_in, RequestMsg) {
        if (in_msg.Type == CoherenceRequestType:MSG) {
          trigger(Event:Receive_Response, in_msg.addr);
        } else {
          error("Invalid message");
        }
      }
    }
  }

  // Actions

  action(i_popIncomingRequestQueue, "i", desc="Pop incoming request queue") {
    requestQueue_in.dequeue(clockEdge());
  }

  action(f_popIncomingForwardQueue, "f", desc="Pop incoming forward queue") {
    forwardQueue_in.dequeue(clockEdge());
  }

  action(r_popIncomingResponseQueue, "r", desc="Pop incoming response queue") {
    responseQueue_in.dequeue(clockEdge());
  }

  // TRANSITIONS

  // The directory simply drops the received packets.
  // The goal of Garnet_standalone is only to track network stats.

  transition(I, Receive_Request) {
    i_popIncomingRequestQueue;
  }
  transition(I, Receive_Forward) {
    f_popIncomingForwardQueue;
  }
  transition(I, Receive_Response) {
    r_popIncomingResponseQueue;
  }
}