| /* | |
| * 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, desc=""; | |
| NCBWrData, desc=""; | |
| // 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, desc=""; | |
| null, desc=""; | |
| } | |
| //////////////////////////////////////////////////////////////////////////// | |
| // 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"; | |
| } |