port.hh revision 13845:60939226a345
1/*
2 * Copyright (c) 2011-2012,2015,2017 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2002-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Ron Dreslinski
41 *          Andreas Hansson
42 *          William Wang
43 */
44
45/**
46 * @file
47 * Port Object Declaration.
48 */
49
50#ifndef __MEM_PORT_HH__
51#define __MEM_PORT_HH__
52
53#include "base/addr_range.hh"
54#include "mem/backdoor.hh"
55#include "mem/packet.hh"
56#include "sim/port.hh"
57
58class MemObject;
59
60/** Forward declaration */
61class BaseSlavePort;
62
63/**
64 * A BaseMasterPort is a protocol-agnostic master port, responsible
65 * only for the structural connection to a slave port. The final
66 * master port that inherits from the base class must override the
67 * bind member function for the specific slave port class.
68 */
69class BaseMasterPort : public Port
70{
71
72  protected:
73
74    BaseSlavePort* _baseSlavePort;
75
76    BaseMasterPort(const std::string& name, PortID id=InvalidPortID);
77    virtual ~BaseMasterPort();
78
79  public:
80
81    BaseSlavePort& getSlavePort() const;
82
83};
84
85/**
86 * A BaseSlavePort is a protocol-agnostic slave port, responsible
87 * only for the structural connection to a master port.
88 */
89class BaseSlavePort : public Port
90{
91
92  protected:
93
94    BaseMasterPort* _baseMasterPort;
95
96    BaseSlavePort(const std::string& name, PortID id=InvalidPortID);
97    virtual ~BaseSlavePort();
98
99  public:
100
101    BaseMasterPort& getMasterPort() const;
102
103};
104
105/** Forward declaration */
106class SlavePort;
107
108/**
109 * A MasterPort is a specialisation of a BaseMasterPort, which
110 * implements the default protocol for the three different level of
111 * transport functions. In addition to the basic functionality of
112 * sending packets, it also has functions to receive range changes or
113 * determine if the port is snooping or not.
114 */
115class MasterPort : public BaseMasterPort
116{
117
118    friend class SlavePort;
119
120  private:
121
122    SlavePort* _slavePort;
123
124  protected:
125
126    MemObject& owner;
127
128  public:
129
130    MasterPort(const std::string& name, MemObject* _owner,
131               PortID id=InvalidPortID);
132    virtual ~MasterPort();
133
134    /**
135     * Bind this master port to a slave port. This also does the
136     * mirror action and binds the slave port to the master port.
137     */
138    void bind(Port &peer) override;
139
140    /**
141     * Unbind this master port and the associated slave port.
142     */
143    void unbind() override;
144
145    /**
146     * Send an atomic request packet, where the data is moved and the
147     * state is updated in zero time, without interleaving with other
148     * memory accesses.
149     *
150     * @param pkt Packet to send.
151     *
152     * @return Estimated latency of access.
153     */
154    Tick sendAtomic(PacketPtr pkt);
155
156    /**
157     * Send an atomic request packet like above, but also request a backdoor
158     * to the data being accessed.
159     *
160     * @param pkt Packet to send.
161     * @param backdoor Can be set to a back door pointer by the target to let
162     *        caller have direct access to the requested data.
163     *
164     * @return Estimated latency of access.
165     */
166    Tick sendAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor);
167
168    /**
169     * Send a functional request packet, where the data is instantly
170     * updated everywhere in the memory system, without affecting the
171     * current state of any block or moving the block.
172     *
173     * @param pkt Packet to send.
174     */
175    void sendFunctional(PacketPtr pkt);
176
177    /**
178     * Attempt to send a timing request to the slave port by calling
179     * its corresponding receive function. If the send does not
180     * succeed, as indicated by the return value, then the sender must
181     * wait for a recvReqRetry at which point it can re-issue a
182     * sendTimingReq.
183     *
184     * @param pkt Packet to send.
185     *
186     * @return If the send was succesful or not.
187    */
188    bool sendTimingReq(PacketPtr pkt);
189
190    /**
191     * Check if the slave can handle a timing request.
192     *
193     * If the send cannot be handled at the moment, as indicated by
194     * the return value, then the sender will receive a recvReqRetry
195     * at which point it can re-issue a sendTimingReq.
196     *
197     * @param pkt Packet to send.
198     *
199     * @return If the send was succesful or not.
200     */
201    bool tryTiming(PacketPtr pkt) const;
202
203    /**
204     * Attempt to send a timing snoop response packet to the slave
205     * port by calling its corresponding receive function. If the send
206     * does not succeed, as indicated by the return value, then the
207     * sender must wait for a recvRetrySnoop at which point it can
208     * re-issue a sendTimingSnoopResp.
209     *
210     * @param pkt Packet to send.
211     */
212    bool sendTimingSnoopResp(PacketPtr pkt);
213
214    /**
215     * Send a retry to the slave port that previously attempted a
216     * sendTimingResp to this master port and failed. Note that this
217     * is virtual so that the "fake" snoop response port in the
218     * coherent crossbar can override the behaviour.
219     */
220    virtual void sendRetryResp();
221
222    /**
223     * Determine if this master port is snooping or not. The default
224     * implementation returns false and thus tells the neighbour we
225     * are not snooping. Any master port that wants to receive snoop
226     * requests (e.g. a cache connected to a bus) has to override this
227     * function.
228     *
229     * @return true if the port should be considered a snooper
230     */
231    virtual bool isSnooping() const { return false; }
232
233    /**
234     * Get the address ranges of the connected slave port.
235     */
236    AddrRangeList getAddrRanges() const;
237
238    /** Inject a PrintReq for the given address to print the state of
239     * that address throughout the memory system.  For debugging.
240     */
241    void printAddr(Addr a);
242
243  protected:
244
245    /**
246     * Receive an atomic snoop request packet from the slave port.
247     */
248    virtual Tick recvAtomicSnoop(PacketPtr pkt)
249    {
250        panic("%s was not expecting an atomic snoop request\n", name());
251        return 0;
252    }
253
254    /**
255     * Receive a functional snoop request packet from the slave port.
256     */
257    virtual void recvFunctionalSnoop(PacketPtr pkt)
258    {
259        panic("%s was not expecting a functional snoop request\n", name());
260    }
261
262    /**
263     * Receive a timing response from the slave port.
264     */
265    virtual bool recvTimingResp(PacketPtr pkt) = 0;
266
267    /**
268     * Receive a timing snoop request from the slave port.
269     */
270    virtual void recvTimingSnoopReq(PacketPtr pkt)
271    {
272        panic("%s was not expecting a timing snoop request\n", name());
273    }
274
275    /**
276     * Called by the slave port if sendTimingReq was called on this
277     * master port (causing recvTimingReq to be called on the slave
278     * port) and was unsuccesful.
279     */
280    virtual void recvReqRetry() = 0;
281
282    /**
283     * Called by the slave port if sendTimingSnoopResp was called on this
284     * master port (causing recvTimingSnoopResp to be called on the slave
285     * port) and was unsuccesful.
286     */
287    virtual void recvRetrySnoopResp()
288    {
289        panic("%s was not expecting a snoop retry\n", name());
290    }
291
292    /**
293     * Called to receive an address range change from the peer slave
294     * port. The default implementation ignores the change and does
295     * nothing. Override this function in a derived class if the owner
296     * needs to be aware of the address ranges, e.g. in an
297     * interconnect component like a bus.
298     */
299    virtual void recvRangeChange() { }
300};
301
302/**
303 * A SlavePort is a specialisation of a port. In addition to the
304 * basic functionality of sending packets to its master peer, it also
305 * has functions specific to a slave, e.g. to send range changes
306 * and get the address ranges that the port responds to.
307 */
308class SlavePort : public BaseSlavePort
309{
310
311    friend class MasterPort;
312
313  private:
314
315    MasterPort* _masterPort;
316    bool defaultBackdoorWarned;
317
318  protected:
319
320    MemObject& owner;
321
322  public:
323
324    SlavePort(const std::string& name, MemObject* _owner,
325              PortID id=InvalidPortID);
326    virtual ~SlavePort();
327
328    /**
329     * Send an atomic snoop request packet, where the data is moved
330     * and the state is updated in zero time, without interleaving
331     * with other memory accesses.
332     *
333     * @param pkt Snoop packet to send.
334     *
335     * @return Estimated latency of access.
336     */
337    Tick sendAtomicSnoop(PacketPtr pkt);
338
339    /**
340     * Send a functional snoop request packet, where the data is
341     * instantly updated everywhere in the memory system, without
342     * affecting the current state of any block or moving the block.
343     *
344     * @param pkt Snoop packet to send.
345     */
346    void sendFunctionalSnoop(PacketPtr pkt);
347
348    /**
349     * Attempt to send a timing response to the master port by calling
350     * its corresponding receive function. If the send does not
351     * succeed, as indicated by the return value, then the sender must
352     * wait for a recvRespRetry at which point it can re-issue a
353     * sendTimingResp.
354     *
355     * @param pkt Packet to send.
356     *
357     * @return If the send was succesful or not.
358    */
359    bool sendTimingResp(PacketPtr pkt);
360
361    /**
362     * Attempt to send a timing snoop request packet to the master port
363     * by calling its corresponding receive function. Snoop requests
364     * always succeed and hence no return value is needed.
365     *
366     * @param pkt Packet to send.
367     */
368    void sendTimingSnoopReq(PacketPtr pkt);
369
370    /**
371     * Send a retry to the master port that previously attempted a
372     * sendTimingReq to this slave port and failed.
373     */
374    void sendRetryReq();
375
376    /**
377     * Send a retry to the master port that previously attempted a
378     * sendTimingSnoopResp to this slave port and failed.
379     */
380    void sendRetrySnoopResp();
381
382    /**
383     * Find out if the peer master port is snooping or not.
384     *
385     * @return true if the peer master port is snooping
386     */
387    bool isSnooping() const { return _masterPort->isSnooping(); }
388
389    /**
390     * Called by the owner to send a range change
391     */
392    void sendRangeChange() const {
393        if (!_masterPort)
394            fatal("%s cannot sendRangeChange() without master port", name());
395        _masterPort->recvRangeChange();
396    }
397
398    /**
399     * Get a list of the non-overlapping address ranges the owner is
400     * responsible for. All slave ports must override this function
401     * and return a populated list with at least one item.
402     *
403     * @return a list of ranges responded to
404     */
405    virtual AddrRangeList getAddrRanges() const = 0;
406
407    /**
408     * We let the master port do the work, so these don't do anything.
409     */
410    void unbind() override {}
411    void bind(Port &peer) override {}
412
413  protected:
414
415    /**
416     * Called by the master port to unbind. Should never be called
417     * directly.
418     */
419    void slaveUnbind();
420
421    /**
422     * Called by the master port to bind. Should never be called
423     * directly.
424     */
425    void slaveBind(MasterPort& master_port);
426
427    /**
428     * Receive an atomic request packet from the master port.
429     */
430    virtual Tick recvAtomic(PacketPtr pkt) = 0;
431
432    /**
433     * Receive an atomic request packet from the master port, and optionally
434     * provide a backdoor to the data being accessed.
435     */
436    virtual Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr &backdoor);
437
438    /**
439     * Receive a functional request packet from the master port.
440     */
441    virtual void recvFunctional(PacketPtr pkt) = 0;
442
443    /**
444     * Receive a timing request from the master port.
445     */
446    virtual bool recvTimingReq(PacketPtr pkt) = 0;
447
448    /**
449     * Availability request from the master port.
450     */
451    virtual bool tryTiming(PacketPtr pkt) {
452        panic("%s was not expecting a %s\n", name(), __func__);
453    }
454
455    /**
456     * Receive a timing snoop response from the master port.
457     */
458    virtual bool recvTimingSnoopResp(PacketPtr pkt)
459    {
460        panic("%s was not expecting a timing snoop response\n", name());
461    }
462
463    /**
464     * Called by the master port if sendTimingResp was called on this
465     * slave port (causing recvTimingResp to be called on the master
466     * port) and was unsuccesful.
467     */
468    virtual void recvRespRetry() = 0;
469
470};
471
472#endif //__MEM_PORT_HH__
473