blob: ba38c6585632799cfc535bfa013c416f90695607 [file] [log] [blame]
/*
* Copyright (c) 2021-2022 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.
*/
machine(MachineType:MiscNode, "CHI Misc Node for handling and distrbuting DVM operations") :
// Additional pipeline latency modeling for the different request types
// When defined, these are applied after the initial tag array read and
// sending necessary snoops.
Cycles snp_latency := 0; // Applied before handling any snoop
Cycles snp_inv_latency := 0; // Additional latency for invalidating snoops
// Request TBE allocation latency
Cycles allocation_latency := 0;
// Enqueue latencies for outgoing messages
// NOTE: should remove this and only use parameters above?
Cycles request_latency := 1;
Cycles response_latency := 1;
Cycles sched_response_latency := 1;
Cycles snoop_latency := 1;
Cycles data_latency := 1;
// Recycle latency on resource stalls
Cycles stall_recycle_lat := 1;
// Number of entries in the TBE tables
int number_of_DVM_TBEs;
int number_of_non_sync_TBEs;
// wait for the final tag update to complete before deallocating TBE and
// going to final stable state
bool dealloc_wait_for_tag := "False";
// Width of the data channel. Data transfer are split in multiple messages
// at the protocol level when this is less than the cache line size.
int data_channel_size;
// Combine Comp+DBIDResp responses for DvmOp(Non-sync)
// CHI-D and later only!
bool early_nonsync_comp;
// additional latency for the WU Comp response
Cycles comp_wu_latency := 0;
// Additional latency for sending RetryAck
Cycles retry_ack_latency := 0;
// Additional latency for sending PCrdGrant
Cycles crd_grant_latency := 0;
// Additional latency for retrying a request
Cycles retry_req_latency := 0;
// stall new requests to destinations with a pending retry
bool throttle_req_on_retry := "True";
// Message Queues
// Interface to the network
// Note vnet_type is used by Garnet only. "response" type is assumed to
// have data, so use it for data channels and "none" for the rest.
// network="To" for outbound queue; network="From" for inbound
// virtual networks: 0=request, 1=snoop, 2=response, 3=data
MessageBuffer * reqOut, network="To", virtual_network="0", vnet_type="none";
MessageBuffer * snpOut, network="To", virtual_network="1", vnet_type="none";
MessageBuffer * rspOut, network="To", virtual_network="2", vnet_type="none";
MessageBuffer * datOut, network="To", virtual_network="3", vnet_type="response";
MessageBuffer * reqIn, network="From", virtual_network="0", vnet_type="none";
MessageBuffer * snpIn, network="From", virtual_network="1", vnet_type="none";
MessageBuffer * rspIn, network="From", virtual_network="2", vnet_type="none";
MessageBuffer * datIn, network="From", virtual_network="3", vnet_type="response";
// Mandatory queue for receiving requests from the sequencer
MessageBuffer * mandatoryQueue;
// Internal queue for trigger events
MessageBuffer * triggerQueue;
// Internal queue for retry trigger events
MessageBuffer * retryTriggerQueue;
// Internal queue for scheduled response messages
MessageBuffer * schedRspTriggerQueue;
// Internal queue for accepted requests
MessageBuffer * reqRdy;
// Internal queue for accepted snoops
MessageBuffer * snpRdy;
{
////////////////////////////////////////////////////////////////////////////
// States
////////////////////////////////////////////////////////////////////////////
// Should only involve states relevant to TLBI or Sync operations
state_declaration(State, default="MiscNode_State_null") {
Unallocated, AccessPermission:Invalid, desc="TBE is not associated with a DVM op";
DvmSync_Partial, AccessPermission:Invalid, desc="DvmSync which is waiting for extra data";
DvmSync_ReadyToDist, AccessPermission:Invalid, desc="DvmSync which has all data, ready to distribute to other cores";
DvmSync_Distributing, AccessPermission:Invalid, desc="DvmSync which is distributing snoops to the rest of the cores";
DvmSync_Waiting, AccessPermission:Invalid, desc="DvmSync which is waiting for snoop responses to come back";
DvmNonSync_Partial, AccessPermission:Invalid, desc="DVM non-sync waiting for extra data from initiator";
DvmNonSync_ReadyToDist, AccessPermission:Invalid, desc="DVM non-sync with all data, ready to distribute to other cores";
DvmNonSync_Distributing, AccessPermission:Invalid, desc="DVM non-sync distributing snoops to the rest of the cores";
DvmNonSync_Waiting, AccessPermission:Invalid, desc="DVM non-sync waiting for snoop responses to come back";
DvmOp_Complete, AccessPermission:Invalid, desc="A completed DVM op";
// Null state for debugging
null, AccessPermission:Invalid, desc="Null state";
}
////////////////////////////////////////////////////////////////////////////
// Events
////////////////////////////////////////////////////////////////////////////
enumeration(Event) {
// Events triggered by incoming requests. Allocate TBE and move
// request or snoop to the ready queue
AllocRequest, desc="Allocates a TBE for a request. Triggers a retry if table is full";
AllocRequestWithCredit, desc="Allocates a TBE for a request. Always succeeds. Used when a client is retrying after being denied.";
SnpResp_I;
NCBWrData;
// Retry handling
SendRetryAck, desc="Send RetryAck";
SendPCrdGrant, desc="Send PCrdGrant";
DoRetry, desc="Resend the current pending request";
DvmTlbi_Initiate, desc="Initiate a DVM TLBI on the provided TBE";
DvmSync_Initiate, desc="Initiate a DVM Sync on the provided TBE";
DvmSendNextMessage_P1, desc="Trigger a SnpDvmOp_P1 message based on the TBE type";
DvmSendNextMessage_P2, desc="Trigger a SnpDvmOp_P2 message based on the TBE type";
DvmFinishDistributing, desc="Move the TBE out of the Distributing state into Waiting";
DvmFinishWaiting, desc="Move the TBE out of the Waiting state and complete it";
DvmUpdatePendingOps, desc="Update which operation is currently distributing";
// This is triggered once a transaction doesn't have
// any queued action and is not expecting responses/data. The transaction
// is finalized and the next stable state is stored in the cache/directory
// See the processNextState and makeFinalState functions
Final;
null;
}
////////////////////////////////////////////////////////////////////////////
// Data structures
////////////////////////////////////////////////////////////////////////////
// Cache block size
int blockSize, default="RubySystem::getBlockSizeBytes()";
// Helper class for tracking expected response and data messages
structure(ExpectedMap, external ="yes") {
void clear(int dataChunks);
void addExpectedRespType(CHIResponseType);
void addExpectedDataType(CHIDataType);
void setExpectedCount(int val);
void addExpectedCount(int val);
bool hasExpected();
bool hasReceivedResp();
bool hasReceivedData();
int expected();
int received();
bool receiveResp(CHIResponseType);
bool receiveData(CHIDataType);
bool receivedDataType(CHIDataType);
bool receivedRespType(CHIResponseType);
}
// Tracks a pending retry
structure(RetryQueueEntry) {
Addr txnId, desc="Transaction ID";
MachineID retryDest, desc="Retry destination";
bool isNonSync, desc="Is a NonSync operation";
}
// Queue for event triggers. Used to specify a list of actions that need
// to be performed across multiple transitions.
// This class is also used to track pending retries
structure(TriggerQueue, external ="yes") {
Event front();
Event back();
bool frontNB();
bool backNB();
bool empty();
void push(Event);
void pushNB(Event);
void pushFront(Event);
void pushFrontNB(Event);
void pop();
}
// TBE fields
structure(TBE, desc="Transaction buffer entry definition") {
Tick timestamp, desc="Time this entry was allocated. Affects order of trigger events";
int storSlot, desc="Slot in the storage tracker occupied by this entry";
// Transaction info mostly extracted from the request message
Addr txnId, desc="Unique Transaction ID";
CHIRequestType reqType, desc="Request type that initiated this transaction";
bool isNonSync, desc="Is a non-sync DVM operation";
MachineID requestor, desc="Requestor ID";
// Transaction state information
State state, desc="SLICC line state";
NetDest notSentTargets, desc="Set of MachineIDs we haven't snooped yet";
NetDest pendingTargets, desc="Set of MachineIDs that were snooped, but haven't responded";
NetDest receivedTargets, desc="Set of MachineIDs that have responded to snoops";
// Helper structures to track expected events and additional transient
// state info
// List of actions to be performed while on a transient state
// See the processNextState function for details
TriggerQueue actions, template="<MiscNode_Event>", desc="List of actions";
Event pendAction, desc="Current pending action";
Tick delayNextAction, desc="Delay next action until given tick";
State finalState, desc="Final state; set when pendAction==Final";
// List of expected responses and data. Checks the type of data against the
// expected ones for debugging purposes
// See the processNextState function for details
ExpectedMap expected_req_resp, template="<CHIResponseType,CHIDataType>";
ExpectedMap expected_snp_resp, template="<CHIResponseType,CHIDataType>";
bool waiting_on_other_txns, desc="Is waiting for other transactions to update before finishing.";
CHIResponseType slicchack1; // fix compiler not including headers
CHIDataType slicchack2; // fix compiler not including headers
// Tracks pending scheduled responses
int sched_responses;
bool block_on_sched_responses;
// This TBE stalled a message and thus we need to call wakeUpBuffers
// at some point
bool wakeup_pending_req;
bool wakeup_pending_snp;
bool wakeup_pending_tgr;
}
// TBE table definition
structure(MN_TBETable, external ="yes") {
TBE lookup(Addr);
void allocate(Addr);
void deallocate(Addr);
bool isPresent(Addr);
TBE chooseNewDistributor();
}
structure(TBEStorage, external ="yes") {
int size();
int capacity();
int reserved();
int slotsAvailable();
bool areNSlotsAvailable(int n);
void incrementReserved();
void decrementReserved();
int addEntryToNewSlot();
void removeEntryFromSlot(int slot);
}
structure(MN_TBEStorage, external ="yes") {
int size();
int capacity();
int reserved();
int slotsAvailable(int partition);
bool areNSlotsAvailable(int n, int partition);
void incrementReserved(int partition);
void decrementReserved(int partition);
int addEntryToNewSlot(int partition);
void removeEntryFromSlot(int slot, int partition);
// Which operation to retry depends on the current available storage.
// If there's a NonSync op waiting for PCrdGrant and the Nonsync reserved space is free,
// the NonSync takes priority.
// => Make the MN_TBEStorage responsible for calculating this.
void emplaceRetryEntry(RetryQueueEntry ret);
bool hasPossibleRetry();
RetryQueueEntry popNextRetryEntry();
}
// Definitions of the TBE tables
// TBE table for DVM requests
MN_TBETable dvmTBEs, constructor="m_number_of_DVM_TBEs";
TBEStorage nonSyncTBEs, constructor="this, m_number_of_non_sync_TBEs";
TBEStorage genericTBEs, constructor="this, (m_number_of_DVM_TBEs - m_number_of_non_sync_TBEs)";
MN_TBEStorage storDvmTBEs, template="<MiscNode_RetryQueueEntry>", constructor="this, {m_genericTBEs_ptr, m_nonSyncTBEs_ptr}";
// txnId of the current TBE which is distributing snoops
// NOTE - this is a safety measure for making sure we don't
// tell the same person to start snooping twice.
// Don't rely on it, if someone stops distributing and no-one starts
// this variable will not be updated.
Addr currentDistributor, default="0";
bool hasCurrentDistributor, default="false";
bool needsToCheckPendingOps, default="false";
// Pending RetryAck/PCrdGrant
structure(RetryTriggerMsg, interface="Message") {
Addr txnId;
Event event;
MachineID retryDest;
bool functionalRead(Packet *pkt) { return false; }
bool functionalRead(Packet *pkt, WriteMask &mask) { return false; }
bool functionalWrite(Packet *pkt) { return false; }
}
// Pending transaction actions (generated by TBE:actions)
structure(TriggerMsg, interface="Message") {
Addr txnId;
bool from_hazard; // this actions was generate during a snoop hazard
bool functionalRead(Packet *pkt) { return false; }
bool functionalRead(Packet *pkt, WriteMask &mask) { return false; }
bool functionalWrite(Packet *pkt) { return false; }
}
////////////////////////////////////////////////////////////////////////////
// Input/output port definitions
////////////////////////////////////////////////////////////////////////////
include "CHI-dvm-misc-node-ports.sm";
// CHI-dvm-misc-node-ports.sm also includes CHI-dvm-misc-node-funcs.sm
////////////////////////////////////////////////////////////////////////////
// Actions and transitions
////////////////////////////////////////////////////////////////////////////
include "CHI-dvm-misc-node-actions.sm";
include "CHI-dvm-misc-node-transitions.sm";
}