/*
 * 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(Directory, "Network_test Directory")
    : MessageBuffer * requestToDir, network="From", virtual_network="0",
            ordered="false", vnet_type = "request";
      MessageBuffer * forwardToDir, network="From", virtual_network="1",
            ordered="false", vnet_type = "forward";
      MessageBuffer * responseToDir, network="From", virtual_network="2",
            ordered="false", 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";
  }

  // ** OBJECTS **
  State getState(Address addr) {
    return State:I;
  }

  void setState(Address addr, State state) {

  }

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

  void setAccessPermission(Address addr, State state) {
  }

  DataBlock getDataBlock(Address addr), return_by_ref="yes" {
    error("Network Test does not support get data block.");
  }

  // ** IN_PORTS **

  in_port(requestQueue_in, RequestMsg, requestToDir) {
    if (requestQueue_in.isReady()) {
      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()) {
      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()) {
      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();
  }

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

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

  // TRANSITIONS

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

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