blob: 591a06f11da8022826d6efe79ca83fe5b562b6db [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>gem5</title>
<!-- SITE FAVICON -->
<link rel="shortcut icon" type="image/gif" href="/assets/img/gem5ColorVert.gif"/>
<link rel="canonical" href="http://localhost:4000/cache-declarations/">
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,700,800,600' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Muli:400,300' rel='stylesheet' type='text/css'>
<!-- FAVICON -->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<!-- BOOTSTRAP -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<!-- CUSTOM CSS -->
<link rel="stylesheet" href="/css/main.css">
</head>
<body>
<nav class="navbar navbar-expand-md navbar-light bg-light">
<a class="navbar-brand" href="/">
<img src="/assets/img/gem5ColorLong.gif" alt="gem5" height=45px>
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavDropdown">
<ul class="navbar-nav ml-auto">
<li class="nav-item ">
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item dropdown ">
<a class="nav-link dropdown-toggle" href="/about" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
About
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<a class="dropdown-item" href="/about">About</a>
<a class="dropdown-item" href="/publications">Publications</a>
<a class="dropdown-item" href="/governance">Governance</a>
</div>
</li>
<li class="nav-item dropdown active">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Documentation
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<!-- Pull navigation from _data/documentation.yml -->
<a class="dropdown-item" href="/introduction">Introduction</a>
<a class="dropdown-item" href="/building">Getting Started</a>
<a class="dropdown-item" href="/environment">Modifying/Extending</a>
<a class="dropdown-item" href="/MSIintro">Modeling Cache Coherence with Ruby</a>
</div>
</li>
<li class="nav-item ">
<a class="nav-link" href="/contributing">Contributing</a>
</li>
<li class="nav-item ">
<a class="nav-link" href="/search">Search</a>
</li>
</ul>
</div>
</nav>
<main>
<div class="sidenav-top">
<img src="/assets/img/gem5ColorLong.gif" height="80">
<div class="search">
<form action="/search" method="get">
<!-- <label for="search-box"><i class="fa fa-search"></i></label> -->
<input type="text" name="query">
<button type="submit" name="submit"><i class="fa fa-search"></i></button>
</form>
</div>
</div>
<div class="sidenav">
<!-- Pull navigation from _data/documentation.yml -->
<a class="item" href="/introduction" role="button" aria-expanded="false" aria-controls="collapseExample">
Introduction
</a>
<div class="collapse " id="introdution">
</div>
<a class="item" data-toggle="collapse" href="#pt1" role="button" aria-expanded="false" aria-controls="collapseExample">
Getting Started
</a>
<div class="collapse " id="pt1">
<a class="subitem " href="/building">Building gem5</a>
<a class="subitem " href="/simple_config">Creating a simple configuration script</a>
<a class="subitem " href="/cache_config">Adding cache to configuration script</a>
<a class="subitem " href="/gem5_stats">Understanding gem5 statistics and output</a>
<a class="subitem " href="/example_configs">Using the default configuration scripts</a>
</div>
<a class="item" data-toggle="collapse" href="#pt2" role="button" aria-expanded="false" aria-controls="collapseExample">
Modifying/Extending
</a>
<div class="collapse " id="pt2">
<a class="subitem " href="/environment">Setting up your development environment</a>
<a class="subitem " href="/helloobject">Creating a very simple SimObject</a>
<a class="subitem " href="/debugging">Debugging gem5</a>
<a class="subitem " href="/events">Event-driven programming</a>
<a class="subitem " href="/parameters">Adding parameters to SimObjects and more events</a>
<a class="subitem " href="/memoryobject">Creating SimObjects in the memory system</a>
<a class="subitem " href="/simplecache">Creating a simple cache object</a>
</div>
<a class="item" data-toggle="collapse" href="#pt3" role="button" aria-expanded="false" aria-controls="collapseExample">
Modeling Cache Coherence with Ruby
</a>
<div class="collapse show" id="pt3">
<a class="subitem " href="/MSIintro">Introduction to Ruby</a>
<a class="subitem " href="/cache-intro">MSI example cache protocol</a>
<a class="subitem active" href="/cache-declarations">Declaring a state machine</a>
<a class="subitem " href="/cache-in-ports">In port code blocks</a>
<a class="subitem " href="/cache-actions">Action code blocks</a>
<a class="subitem " href="/cache-transitions">Transition code blocks</a>
<a class="subitem " href="/directory">MSI Directory implementation</a>
<a class="subitem " href="/MSIbuilding">Compiling a SLICC protocol</a>
<a class="subitem " href="/configuration">Configuring a simple Ruby system</a>
<a class="subitem " href="/running">Running the simple Ruby system</a>
<a class="subitem " href="/MSIdebugging">Debugging SLICC Protocols</a>
<a class="subitem " href="/simple-MI_example">Configuring for a standard protocol</a>
</div>
</div>
<div class="container" id="doc-container">
<!-- <h1>Declaring a state machine</h1> -->
<dl>
<dt>authors</dt>
<dd>Jason Lowe-Power</dd>
</dl>
<h1 id="declaring-a-state-machine">Declaring a state machine</h1>
<p>Let’s start on our first state machine file! First, we will create the
L1 cache controller for our MSI protocol.</p>
<p>Create a file called <code class="highlighter-rouge">MSI-cache.sm</code> and the following code declares the
state machine.</p>
<p>``` {.sourceCode .c++}
machine(MachineType:L1Cache, “MSI cache”)
: <parameters>
{
<All state="" machine="" code="">
}</All></parameters></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
The first thing you'll notice about the state machine code is that is
looks very C++-like. The state machine file is like creating a C++
object in a header file, if you included all of the code there as well.
When in doubt, C++ syntax with *probably* work in SLICC. However, there
are many cases where C++ syntax is incorrect syntax for SLICC as well as
cases where SLICC extends the syntax.
With `MachineType:L1Cache`, we are naming this state machine `L1Cache`.
SLICC will generate many different objects for us from the state machine
using that name. For instance, once this file is compiled, there will be
a new SimObject: `L1Cache_Controller` that is the cache controller. Also
included in this declaration is a description of this state machine:
"MSI cache".
There are many cases in SLICC where you must include a description to go
along with the variable. The reason for this is that SLICC was
originally designed to just describe, not implement, coherence
protocols. Today, these extra descriptions serve two purposes. First,
they act as comments on what the author intended each variable, or
state, or event, to be used for. Second, many of them are still exported
into HTML when building the HTML tables for the SLICC protocol. Thus,
while browsing the HTML table, you can see the more detailed comments
from the author of the protocol. It is important to be clear with these
descriptions since coherence protocols can get quite complicated.
State machine parameters
------------------------
Proceeding the `machine()` declaration is a colon, after which all of
the parameters to the state machine are declared. These parameters are
directly exported to the SimObject that is generated by the state
machine.
For our MSI L1 cache, we have the following parameters:
``` {.sourceCode .c++}
machine(MachineType:L1Cache, "MSI cache")
: Sequencer *sequencer;
CacheMemory *cacheMemory;
bool send_evictions;
&lt;Message buffer declarations&gt;
{
}
</code></pre></div></div>
<p>First, we have a <code class="highlighter-rouge">Sequencer</code>. This is a special class that is
implemented in Ruby to interface with the rest of gem5. The Sequencer is
a gem5 <code class="highlighter-rouge">MemObject</code> with a slave port so it can accept memory requests
from other objects. The sequencer accepts requests from a CPU (or other
master port) and converts the gem5 the packet into a <code class="highlighter-rouge">RubyRequest</code>.
Finally, the <code class="highlighter-rouge">RubyRequest</code> is pushed onto the <code class="highlighter-rouge">mandatoryQueue</code> of the
state machine. We will revisit the <code class="highlighter-rouge">mandatoryQueue</code> in
in port section &lt;MSI-in-ports-section&gt;.</p>
<p>Next, there is a <code class="highlighter-rouge">CacheMemory</code> object. This is what holds the cache data
(i.e., cache entries). The exact implementation, size, etc. is
configurable at runtime.</p>
<p>Finally, we can specify any other parameters we would like, similar to a
general <code class="highlighter-rouge">SimObject</code>. In this case, we have a boolean variable
<code class="highlighter-rouge">send_evictions</code>. This is used for out-of-order core models to notify
the load-store queue if an address is evicted after a load to squash a
load if it is speculative.</p>
<p>Next, also in the parameter block (i.e., before the first open bracket),
we need to declare all of the message buffers that this state machine
will use. Message buffers are the interface between the state machine
and the Ruby network. Messages are sent and received via the message
buffers. Thus, for each virtual channel in our protocol we need a
separate message buffer.</p>
<p>The MSI protocol needs three different virtual networks. Virtual
networks are needed to prevent deadlock (e.g., it is bad if a response
gets stuck behind a stalled request). In this protocol, the highest
priority is responses (virtual network 2), followed by forwarded
requests (virtual network 1), then requests have the lowest priority
(virtual network 0). See Sorin et al. for details on why these three
virtual networks are needed.</p>
<p>The following code declares all of the needed message buffers.</p>
<dl>
<dt>``` {.sourceCode .c++}</dt>
<dt>machine(MachineType:L1Cache, “MSI cache”)</dt>
<dd>Sequencer *sequencer;
CacheMemory *cacheMemory;
bool send_evictions;
<p>MessageBuffer * requestToDir, network=”To”, virtual_network=”0”, vnet_type=”request”;
MessageBuffer * responseToDirOrSibling, network=”To”, virtual_network=”2”, vnet_type=”response”;</p>
<p>MessageBuffer * forwardFromDir, network=”From”, virtual_network=”1”, vnet_type=”forward”;
MessageBuffer * responseFromDirOrSibling, network=”From”, virtual_network=”2”, vnet_type=”response”;</p>
<p>MessageBuffer * mandatoryQueue;</p>
</dd>
</dl>
<p>{</p>
<p>}</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
We have five different message buffers: two "To", two "From", and one
special message buffer. The "To" message buffers are similar to slave
ports in gem5. These are the message buffers that this controller uses
to send messages to other controllers in the system. The "From" message
buffers are like slave ports. This controller receives messages on
"From" buffers from other controllers in the system.
We have two different "To" buffers, one for low priority requests, and
one for high priority responses. The priority for the networks are not
inherent. The priority is based on the order that other controllers look
at the message buffers. It is a good idea to number the virtual networks
so that higher numbers mean higher priority, but the virtual network
number is ignored by Ruby except that messages on network 2 can only go
to other message buffers on network 2 (i.e., messages can't jump from
one network to another).
Similarly, there is two different ways this cache can receive messages,
either as a forwarded request from the directory (e.g., another cache
requests a writable block and we have a readable copy) or as a response
to a request this controller made. The response is higher priority than
the forwarded requests.
Finally, there is a special message buffer, the `mandatoryQueue`. This
message buffer is used by the `Sequencer` to convert gem5 packets into
Ruby requests. Unlike the other message buffers, `mandatoryQueue` does
not connect to the Ruby network. Note: the name of this message buffer
is hard-coded and must be exactly "mandatoryQueue".
As previously mentioned, this parameter block is converted into the
SimObject description file. Any parameters you put in this block will be
SimObject parameters that are accessible from the Python configuration
files. If you look at the generated file L1Cache\_Controller.py, it will
look very familiar. Note: This is a generated file and you should never
modify generated files directly!
``` {.sourceCode .python}
from m5.params import *
from m5.SimObject import SimObject
from Controller import RubyController
class L1Cache_Controller(RubyController):
type = 'L1Cache_Controller'
cxx_header = 'mem/protocol/L1Cache_Controller.hh'
sequencer = Param.RubySequencer("")
cacheMemory = Param.RubyCache("")
send_evictions = Param.Bool("")
requestToDir = Param.MessageBuffer("")
responseToDirOrSibling = Param.MessageBuffer("")
forwardFromDir = Param.MessageBuffer("")
responseFromDirOrSibling = Param.MessageBuffer("")
mandatoryQueue = Param.MessageBuffer("")
</code></pre></div></div>
<h2 id="state-declarations">State declarations</h2>
<p>The next part of the state machine is the state declaration. Here, we
are going to declare all of the stable and transient states for the
state machine. We will follow the naming convention in Sorin et al. For
instance, the transient state “IM_AD” corresponds to moving from
Invalid to Modified waiting on acks and data. These states come directly
from the left column of Table 8.3 in Sorin et al.</p>
<p>``` {.sourceCode .c++}
state_declaration(State, desc=”Cache states”) {
I, AccessPermission:Invalid,
desc=”Not present/Invalid”;</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// States moving out of I
IS_D, AccessPermission:Invalid,
desc="Invalid, moving to S, waiting for data";
IM_AD, AccessPermission:Invalid,
desc="Invalid, moving to M, waiting for acks and data";
IM_A, AccessPermission:Busy,
desc="Invalid, moving to M, waiting for acks";
S, AccessPermission:Read_Only,
desc="Shared. Read-only, other caches may have the block";
// States moving out of S
SM_AD, AccessPermission:Read_Only,
desc="Shared, moving to M, waiting for acks and 'data'";
SM_A, AccessPermission:Read_Only,
desc="Shared, moving to M, waiting for acks";
M, AccessPermission:Read_Write,
desc="Modified. Read &amp; write permissions. Owner of block";
// States moving to Invalid
MI_A, AccessPermission:Busy,
desc="Was modified, moving to I, waiting for put ack";
SI_A, AccessPermission:Busy,
desc="Was shared, moving to I, waiting for put ack";
II_A, AccessPermission:Invalid,
desc="Sent valid data before receiving put ack. "Waiting for put ack."; } ```
</code></pre></div></div>
<p>Each state has an associated access permission: “Invalid”, “NotPresent”,
“Busy”, “Read_Only”, or “Read_Write”. The access permission is used
for <em>functional</em> accesses to the cache. Functional accesses are
debug-like accesses when the simulator wants to read or update the data
immediately. One example of this is reading in files in SE mode which
are directly loaded into memory.</p>
<p>For functional accesses all caches are checked to see if they have a
corresponding block with matching address. For functional reads, <em>all</em>
of the blocks with a matching address that have read-only or read-write
permission are accessed (they should all have the same data). For
functional writes, all blocks are updated with new data if they have
busy, read-only, or read-write permission.</p>
<h2 id="event-declarations">Event declarations</h2>
<p>Next, we need to declare all of the events that are triggered by
incoming messages for this cache controller. These events come directly
from the first row in Table 8.3 in Sorin et al.</p>
<p>``` {.sourceCode .c++}
enumeration(Event, desc=”Cache events”) {
// From the processor/sequencer/mandatory queue
Load, desc=”Load from processor”;
Store, desc=”Store from processor”;</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Internal event (only triggered from processor requests)
Replacement, desc="Triggered when block is chosen as victim";
// Forwarded request from other cache via dir on the forward network
FwdGetS, desc="Directory sent us a request to satisfy GetS. We must have the block in M to respond to this.";
FwdGetM, desc="Directory sent us a request to satisfy GetM. We must have the block in M to respond to this.";
Inv, desc="Invalidate from the directory.";
PutAck, desc="Response from directory after we issue a put. This must be on the fwd network to avoid deadlock.";
// Responses from directory
DataDirNoAcks, desc="Data from directory (acks = 0)";
DataDirAcks, desc="Data from directory (acks &gt; 0)";
// Responses from other caches
DataOwner, desc="Data from owner";
InvAck, desc="Invalidation ack from other cache after Inv";
// Special event to simplify implementation
LastInvAck, desc="Triggered after the last ack is received"; } ```
</code></pre></div></div>
<h2 id="user-defined-structures">User-defined structures</h2>
<p>Next, we need to define some structures that we will use in other places
in this controller. The first one we will define is <code class="highlighter-rouge">Entry</code>. This is the
structure that is stored in the <code class="highlighter-rouge">CacheMemory</code>. It only needs to contain
data and a state, but it may contain any other data you want. Note: The
state that this structure is storing is the <code class="highlighter-rouge">State</code> type that was
defined above, not a hardcoded state type.</p>
<p>You can find the abstract version of this class (<code class="highlighter-rouge">AbstractCacheEntry</code>)
in <code class="highlighter-rouge">src/mem/ruby/slicc_interface/AbstractCacheEntry.hh</code>. If you want to
use any of the member functions of <code class="highlighter-rouge">AbstractCacheEntry</code>, you need to
declare them here (this isn’t used in this protocol).</p>
<p>``` {.sourceCode .c++}
structure(Entry, desc=”Cache entry”, interface=”AbstractCacheEntry”) {
State CacheState, desc=”cache state”;
DataBlock DataBlk, desc=”Data in the block”;
}</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
Another structure we will need is a TBE. TBE is the "transaction buffer
entry". This stores information needed during transient states. This is
*like* an MSHR. It functions as an MSHR in this protocol, but the entry
is also allocated for other uses. In this protocol, it will store the
state (usually needed), data (also usually needed), and the number of
acks that this block is currently waiting for. The `AcksOutstanding` is
used for the transitions where other controllers send acks instead of
the data.
``` {.sourceCode .c++}
structure(TBE, desc="Entry for transient requests") {
State TBEState, desc="State of block";
DataBlock DataBlk, desc="Data for the block. Needed for MI_A";
int AcksOutstanding, default=0, desc="Number of acks left to receive.";
}
</code></pre></div></div>
<p>Next, we need a place to store all of the TBEs. This is an externally
defined class; it is defined in C++ outside of SLICC. Therefore, we need
to declare that we are going to use it, and also declare any of the
functions that we will call on it. You can find the code for the
<code class="highlighter-rouge">TBETable</code> in src/mem/ruby/structures/TBETable.hh. It is templatized on
the TBE structure defined above, which gets a little confusing, as we
will see.</p>
<p>``` {.sourceCode .c++}
structure(TBETable, external=”yes”) {
TBE lookup(Addr);
void allocate(Addr);
void deallocate(Addr);
bool isPresent(Addr);
}</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
The `external="yes"` tells SLICC to not look for the definition of this
structure. This is similar to declaring a variable `extern` in C/C++.
Other declarations and definitions required
-------------------------------------------
Finally, we are going to go through some boilerplate of declaring
variables, declaring functions in `AbstractController` that we will use
in this controller, and defining abstract functions in
`AbstractController`.
First, we need to have a variable that stores a TBE table. We have to do
this in SLICC because it is not until this time that we know the true
type of the TBE table since the TBE type was defined above. This is some
particularly tricky (or nasty) code to get SLICC to generate the right
C++ code. The difficulty is that we want templatize `TBETable` based on
the `TBE` type above. The key is that SLICC mangles the names of all
types declared in the machine with the machine's name. For instance,
`TBE` is actually L1Cache\_TBE in C++.
We also want to pass a parameter to the constructor of the `TBETable`.
This is a parameter that is actually part of the `AbstractController`,
thus we need to use the C++ name for the variable since it doesn't have
a SLICC name.
``` {.sourceCode .c++}
TBETable TBEs, template="&lt;L1Cache_TBE&gt;", constructor="m_number_of_TBEs";
</code></pre></div></div>
<p>If you can understand the above code, then you are an official SLICC
ninja!</p>
<p>Next, any functions that are part of AbstractController need to be
declared, if we are going to use them in the rest of the file. In this
case, we are only going to use <code class="highlighter-rouge">clockEdge()</code></p>
<p>``` {.sourceCode .c++}
Tick clockEdge();</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
There are a few other functions we're going to use in actions. These
functions are used in actions to set and unset implicit variables
available in action code-blocks. Action code blocks will be explained in
detail in the action section \&lt;MSI-actions-section\&gt;. These may be
needed when a transition has many actions.
``` {.sourceCode .c++}
void set_cache_entry(AbstractCacheEntry a);
void unset_cache_entry();
void set_tbe(TBE b);
void unset_tbe();
</code></pre></div></div>
<p>Another useful function is <code class="highlighter-rouge">mapAddressToMachine</code>. This allows us to
change the address mappings for banked directories or caches at runtime
so we don’t have to hardcode them in the SLICC file.</p>
<p>``` {.sourceCode .c++}
MachineID mapAddressToMachine(Addr addr, MachineType mtype);</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
Finally, you can also add any functions you may want to use in the file
and implement them here. For instance, it is convenient to access cache
blocks by address with a single function. Again, in this function there
is some SLICC trickery. We need to access "by pointer" since the cache
block is something that we need to be mutable later ("by reference"
would have been a better name). The cast is also necessary since we
defined a specific `Entry` type in the file, but the `CacheMemory` holds
the abstract type.
``` {.sourceCode .c++}
// Convenience function to look up the cache entry.
// Needs a pointer so it will be a reference and can be updated in actions
Entry getCacheEntry(Addr address), return_by_pointer="yes" {
return static_cast(Entry, "pointer", cacheMemory.lookup(address));
}
</code></pre></div></div>
<p>The next set of boilerplate code rarely changes between different
protocols. There’s a set of functions that are pure-virtual in
<code class="highlighter-rouge">AbstractController</code> that we must implement.</p>
<dl>
<dt><code class="highlighter-rouge">getState</code></dt>
<dd>Given a TBE, cache entry, and address return the state of the block.
This is called on the block to decide which transition to execute
when an event is triggered. Usually, you return the state in the TBE
or cache entry, whichever is valid.</dd>
<dt><code class="highlighter-rouge">setState</code></dt>
<dd>Given a TBE, cache entry, and address make sure the state is set
correctly on the block. This is called at the end of the transition
to set the final state on the block.</dd>
<dt><code class="highlighter-rouge">getAccessPermission</code></dt>
<dd>Get the access permission of a block. This is used during functional
access to decide whether or not to functionally access the block. It
is similar to <code class="highlighter-rouge">getState</code>, get the information from the TBE if valid,
cache entry, if valid, or the block is not present.</dd>
<dt><code class="highlighter-rouge">setAccessPermission</code></dt>
<dd>Like <code class="highlighter-rouge">getAccessPermission</code>, but sets the permission.</dd>
<dt><code class="highlighter-rouge">functionalRead</code></dt>
<dd>Functionally read the data. It is possible the TBE has more
up-to-date information, so check that first. Note: testAndRead/Write
defined in src/mem/ruby/slicc_interface/Util.hh</dd>
<dt><code class="highlighter-rouge">functionalWrite</code></dt>
<dd>Functionally write the data. Similarly, you may need to update the
data in both the TBE and the cache entry.</dd>
</dl>
<p>``` {.sourceCode .c++}
State getState(TBE tbe, Entry cache_entry, Addr addr) {
// The TBE state will override the state in cache memory, if valid
if (is_valid(tbe)) { return tbe.TBEState; }
// Next, if the cache entry is valid, it holds the state
else if (is_valid(cache_entry)) { return cache_entry.CacheState; }
// If the block isn’t present, then it’s state must be I.
else { return State:I; }
}</p>
<p>void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
if (is_valid(tbe)) { tbe.TBEState := state; }
if (is_valid(cache_entry)) { cache_entry.CacheState := state; }
}</p>
<p>AccessPermission getAccessPermission(Addr addr) {
TBE tbe := TBEs[addr];
if(is_valid(tbe)) {
return L1Cache_State_to_permission(tbe.TBEState);
}</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Entry cache_entry := getCacheEntry(addr);
if(is_valid(cache_entry)) {
return L1Cache_State_to_permission(cache_entry.CacheState);
}
return AccessPermission:NotPresent; }
</code></pre></div></div>
<p>void setAccessPermission(Entry cache_entry, Addr addr, State state) {
if (is_valid(cache_entry)) {
cache_entry.changePermission(L1Cache_State_to_permission(state));
}
}</p>
<p>void functionalRead(Addr addr, Packet *pkt) {
TBE tbe := TBEs[addr];
if(is_valid(tbe)) {
testAndRead(addr, tbe.DataBlk, pkt);
} else {
testAndRead(addr, getCacheEntry(addr).DataBlk, pkt);
}
}</p>
<p>int functionalWrite(Addr addr, Packet *pkt) {
int num_functional_writes := 0;</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>TBE tbe := TBEs[addr];
if(is_valid(tbe)) {
num_functional_writes := num_functional_writes +
testAndWrite(addr, tbe.DataBlk, pkt);
return num_functional_writes;
}
num_functional_writes := num_functional_writes +
testAndWrite(addr, getCacheEntry(addr).DataBlk, pkt);
return num_functional_writes; } ```
</code></pre></div></div>
</div>
</main>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
<script>
// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};
function scrollFunction() {
if (document.body.scrollTop > 100 || document.documentElement.scrollTop > 20) {
document.getElementById("myBtn").style.display = "block";
} else {
document.getElementById("myBtn").style.display = "none";
}
}
// When the user clicks on the button, scroll to the top of the document
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
}
</script>
</body>
<footer class="page-footer">
<div class="container">
<div class="row">
<div class="col-12 col-sm-4">
<p><a href="/about">About</a></p>
<p><a href="/publications">Publications</a></p>
<p><a href="/contributing">Contributing</a></p>
</div><br>
<div class="col-12 col-sm-4">
<p><a href="/gettingstarted">Documentation</a></p>
<p><a href="#">Source</a></p>
</div><br>
<div class="col-12 col-sm-4">
<p><a href="/help">Help</a></p>
<p><a href="/search">Search</a></p>
<p><a href="#">Mailing Lists</a></p>
</div>
</div>
</div>
</footer>
</html>