1/*
2 * Copyright (c) 2017 Jason Lowe-Power
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Jason Lowe-Power
29 */
30
31#ifndef __LEARNING_GEM5_PART2_SIMPLE_MEMOBJ_HH__
32#define __LEARNING_GEM5_PART2_SIMPLE_MEMOBJ_HH__
33
34#include "mem/port.hh"
35#include "params/SimpleMemobj.hh"
36#include "sim/sim_object.hh"
37
38/**
39 * A very simple memory object. Current implementation doesn't even cache
40 * anything it just forwards requests and responses.
41 * This memobj is fully blocking (not non-blocking). Only a single request can
42 * be outstanding at a time.
43 */
44class SimpleMemobj : public SimObject
45{
46  private:
47
48    /**
49     * Port on the CPU-side that receives requests.
50     * Mostly just forwards requests to the owner.
51     * Part of a vector of ports. One for each CPU port (e.g., data, inst)
52     */
53    class CPUSidePort : public SlavePort
54    {
55      private:
56        /// The object that owns this object (SimpleMemobj)
57        SimpleMemobj *owner;
58
59        /// True if the port needs to send a retry req.
60        bool needRetry;
61
62        /// If we tried to send a packet and it was blocked, store it here
63        PacketPtr blockedPacket;
64
65      public:
66        /**
67         * Constructor. Just calls the superclass constructor.
68         */
69        CPUSidePort(const std::string& name, SimpleMemobj *owner) :
70            SlavePort(name, owner), owner(owner), needRetry(false),
71            blockedPacket(nullptr)
72        { }
73
74        /**
75         * Send a packet across this port. This is called by the owner and
76         * all of the flow control is hanled in this function.
77         *
78         * @param packet to send.
79         */
80        void sendPacket(PacketPtr pkt);
81
82        /**
83         * Get a list of the non-overlapping address ranges the owner is
84         * responsible for. All slave ports must override this function
85         * and return a populated list with at least one item.
86         *
87         * @return a list of ranges responded to
88         */
89        AddrRangeList getAddrRanges() const override;
90
91        /**
92         * Send a retry to the peer port only if it is needed. This is called
93         * from the SimpleMemobj whenever it is unblocked.
94         */
95        void trySendRetry();
96
97      protected:
98        /**
99         * Receive an atomic request packet from the master port.
100         * No need to implement in this simple memobj.
101         */
102        Tick recvAtomic(PacketPtr pkt) override
103        { panic("recvAtomic unimpl."); }
104
105        /**
106         * Receive a functional request packet from the master port.
107         * Performs a "debug" access updating/reading the data in place.
108         *
109         * @param packet the requestor sent.
110         */
111        void recvFunctional(PacketPtr pkt) override;
112
113        /**
114         * Receive a timing request from the master port.
115         *
116         * @param the packet that the requestor sent
117         * @return whether this object can consume the packet. If false, we
118         *         will call sendRetry() when we can try to receive this
119         *         request again.
120         */
121        bool recvTimingReq(PacketPtr pkt) override;
122
123        /**
124         * Called by the master port if sendTimingResp was called on this
125         * slave port (causing recvTimingResp to be called on the master
126         * port) and was unsuccesful.
127         */
128        void recvRespRetry() override;
129    };
130
131    /**
132     * Port on the memory-side that receives responses.
133     * Mostly just forwards requests to the owner
134     */
135    class MemSidePort : public MasterPort
136    {
137      private:
138        /// The object that owns this object (SimpleMemobj)
139        SimpleMemobj *owner;
140
141        /// If we tried to send a packet and it was blocked, store it here
142        PacketPtr blockedPacket;
143
144      public:
145        /**
146         * Constructor. Just calls the superclass constructor.
147         */
148        MemSidePort(const std::string& name, SimpleMemobj *owner) :
149            MasterPort(name, owner), owner(owner), blockedPacket(nullptr)
150        { }
151
152        /**
153         * Send a packet across this port. This is called by the owner and
154         * all of the flow control is hanled in this function.
155         *
156         * @param packet to send.
157         */
158        void sendPacket(PacketPtr pkt);
159
160      protected:
161        /**
162         * Receive a timing response from the slave port.
163         */
164        bool recvTimingResp(PacketPtr pkt) override;
165
166        /**
167         * Called by the slave port if sendTimingReq was called on this
168         * master port (causing recvTimingReq to be called on the slave
169         * port) and was unsuccesful.
170         */
171        void recvReqRetry() override;
172
173        /**
174         * Called to receive an address range change from the peer slave
175         * port. The default implementation ignores the change and does
176         * nothing. Override this function in a derived class if the owner
177         * needs to be aware of the address ranges, e.g. in an
178         * interconnect component like a bus.
179         */
180        void recvRangeChange() override;
181    };
182
183    /**
184     * Handle the request from the CPU side
185     *
186     * @param requesting packet
187     * @return true if we can handle the request this cycle, false if the
188     *         requestor needs to retry later
189     */
190    bool handleRequest(PacketPtr pkt);
191
192    /**
193     * Handle the respone from the memory side
194     *
195     * @param responding packet
196     * @return true if we can handle the response this cycle, false if the
197     *         responder needs to retry later
198     */
199    bool handleResponse(PacketPtr pkt);
200
201    /**
202     * Handle a packet functionally. Update the data on a write and get the
203     * data on a read.
204     *
205     * @param packet to functionally handle
206     */
207    void handleFunctional(PacketPtr pkt);
208
209    /**
210     * Return the address ranges this memobj is responsible for. Just use the
211     * same as the next upper level of the hierarchy.
212     *
213     * @return the address ranges this memobj is responsible for
214     */
215    AddrRangeList getAddrRanges() const;
216
217    /**
218     * Tell the CPU side to ask for our memory ranges.
219     */
220    void sendRangeChange();
221
222    /// Instantiation of the CPU-side ports
223    CPUSidePort instPort;
224    CPUSidePort dataPort;
225
226    /// Instantiation of the memory-side port
227    MemSidePort memPort;
228
229    /// True if this is currently blocked waiting for a response.
230    bool blocked;
231
232  public:
233
234    /** constructor
235     */
236    SimpleMemobj(SimpleMemobjParams *params);
237
238    /**
239     * Get a port with a given name and index. This is used at
240     * binding time and returns a reference to a protocol-agnostic
241     * port.
242     *
243     * @param if_name Port name
244     * @param idx Index in the case of a VectorPort
245     *
246     * @return A reference to the given port
247     */
248    Port &getPort(const std::string &if_name,
249                  PortID idx=InvalidPortID) override;
250};
251
252
253#endif // __LEARNING_GEM5_PART2_SIMPLE_MEMOBJ_HH__
254