timing.hh revision 13954:2f400a5f2627
12SN/A/*
21762SN/A * Copyright (c) 2012-2013,2015,2018 ARM Limited
37534Ssteve.reinhardt@amd.com * All rights reserved
42SN/A *
52SN/A * The license below extends only to copyright in the software and shall
62SN/A * not be construed as granting a license to any other intellectual
72SN/A * property including but not limited to intellectual property relating
82SN/A * to a hardware implementation of the functionality of the software
92SN/A * licensed hereunder.  You may use the software subject to the license
102SN/A * terms below provided that you ensure that this notice is replicated
112SN/A * unmodified and in its entirety in all distributions of the software,
122SN/A * modified or unmodified, in source code or in binary form.
132SN/A *
142SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
152SN/A * All rights reserved.
162SN/A *
172SN/A * Redistribution and use in source and binary forms, with or without
182SN/A * modification, are permitted provided that the following conditions are
192SN/A * met: redistributions of source code must retain the above copyright
202SN/A * notice, this list of conditions and the following disclaimer;
212SN/A * redistributions in binary form must reproduce the above copyright
222SN/A * notice, this list of conditions and the following disclaimer in the
232SN/A * documentation and/or other materials provided with the distribution;
242SN/A * neither the name of the copyright holders nor the names of its
252SN/A * contributors may be used to endorse or promote products derived from
262SN/A * this software without specific prior written permission.
272SN/A *
282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292665Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
302665Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
312SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
322SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
332SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
342SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
352SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
362SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
372SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
392SN/A *
405491Sgblack@eecs.umich.edu * Authors: Steve Reinhardt
415491Sgblack@eecs.umich.edu */
422SN/A
435491Sgblack@eecs.umich.edu#ifndef __CPU_SIMPLE_TIMING_HH__
442SN/A#define __CPU_SIMPLE_TIMING_HH__
452SN/A
468737Skoansin.tan@gmail.com#include "cpu/simple/base.hh"
474762Snate@binkert.org#include "cpu/simple/exec_context.hh"
489342SAndreas.Sandberg@arm.com#include "cpu/translation.hh"
499356Snilay@cs.wisc.edu#include "params/TimingSimpleCPU.hh"
5056SN/A
512SN/Aclass TimingSimpleCPU : public BaseSimpleCPU
522797Sktlim@umich.edu{
532797Sktlim@umich.edu  public:
542609SN/A
559196SAndreas.Sandberg@arm.com    TimingSimpleCPU(TimingSimpleCPUParams * params);
562SN/A    virtual ~TimingSimpleCPU();
572SN/A
582SN/A    void init() override;
599196SAndreas.Sandberg@arm.com
609196SAndreas.Sandberg@arm.com  private:
619196SAndreas.Sandberg@arm.com
629196SAndreas.Sandberg@arm.com    /*
639196SAndreas.Sandberg@arm.com     * If an access needs to be broken into fragments, currently at most two,
649196SAndreas.Sandberg@arm.com     * the the following two classes are used as the sender state of the
659196SAndreas.Sandberg@arm.com     * packets so the CPU can keep track of everything. In the main packet
669196SAndreas.Sandberg@arm.com     * sender state, there's an array with a spot for each fragment. If a
679196SAndreas.Sandberg@arm.com     * fragment has already been accepted by the CPU, aka isn't waiting for
689196SAndreas.Sandberg@arm.com     * a retry, it's pointer is NULL. After each fragment has successfully
699196SAndreas.Sandberg@arm.com     * been processed, the "outstanding" counter is decremented. Once the
709196SAndreas.Sandberg@arm.com     * count is zero, the entire larger access is complete.
719196SAndreas.Sandberg@arm.com     */
729196SAndreas.Sandberg@arm.com    class SplitMainSenderState : public Packet::SenderState
739196SAndreas.Sandberg@arm.com    {
749196SAndreas.Sandberg@arm.com      public:
759196SAndreas.Sandberg@arm.com        int outstanding;
769342SAndreas.Sandberg@arm.com        PacketPtr fragments[2];
779196SAndreas.Sandberg@arm.com
789196SAndreas.Sandberg@arm.com        int
799196SAndreas.Sandberg@arm.com        getPendingFragment()
809196SAndreas.Sandberg@arm.com        {
819196SAndreas.Sandberg@arm.com            if (fragments[0]) {
829196SAndreas.Sandberg@arm.com                return 0;
839196SAndreas.Sandberg@arm.com            } else if (fragments[1]) {
842SN/A                return 1;
859342SAndreas.Sandberg@arm.com            } else {
862SN/A                return -1;
872SN/A            }
882SN/A        }
892SN/A    };
909196SAndreas.Sandberg@arm.com
912SN/A    class SplitFragmentSenderState : public Packet::SenderState
922SN/A    {
934762Snate@binkert.org      public:
949196SAndreas.Sandberg@arm.com        SplitFragmentSenderState(PacketPtr _bigPkt, int _index) :
954762Snate@binkert.org            bigPkt(_bigPkt), index(_index)
964762Snate@binkert.org        {}
972SN/A        PacketPtr bigPkt;
984762Snate@binkert.org        int index;
994762Snate@binkert.org
1004762Snate@binkert.org        void
1012SN/A        clearFromParent()
1022SN/A        {
1035034Smilesck@eecs.umich.edu            SplitMainSenderState * main_send_state =
1045034Smilesck@eecs.umich.edu                dynamic_cast<SplitMainSenderState *>(bigPkt->senderState);
1051553SN/A            main_send_state->fragments[index] = NULL;
106265SN/A        }
1077532Ssteve.reinhardt@amd.com    };
1087532Ssteve.reinhardt@amd.com
1097532Ssteve.reinhardt@amd.com    class FetchTranslation : public BaseTLB::Translation
1107532Ssteve.reinhardt@amd.com    {
1117532Ssteve.reinhardt@amd.com      protected:
1127532Ssteve.reinhardt@amd.com        TimingSimpleCPU *cpu;
113465SN/A
114465SN/A      public:
1157532Ssteve.reinhardt@amd.com        FetchTranslation(TimingSimpleCPU *_cpu)
1167532Ssteve.reinhardt@amd.com            : cpu(_cpu)
1177532Ssteve.reinhardt@amd.com        {}
1187532Ssteve.reinhardt@amd.com
1197532Ssteve.reinhardt@amd.com        void
1207532Ssteve.reinhardt@amd.com        markDelayed()
1217532Ssteve.reinhardt@amd.com        {
1227532Ssteve.reinhardt@amd.com            assert(cpu->_status == BaseSimpleCPU::Running);
1239196SAndreas.Sandberg@arm.com            cpu->_status = ITBWaitResponse;
1249196SAndreas.Sandberg@arm.com        }
1257532Ssteve.reinhardt@amd.com
1267532Ssteve.reinhardt@amd.com        void
1277532Ssteve.reinhardt@amd.com        finish(const Fault &fault, const RequestPtr &req, ThreadContext *tc,
1287532Ssteve.reinhardt@amd.com               BaseTLB::Mode mode)
1297532Ssteve.reinhardt@amd.com        {
1307532Ssteve.reinhardt@amd.com            cpu->sendFetch(fault, req, tc);
1317532Ssteve.reinhardt@amd.com        }
1327532Ssteve.reinhardt@amd.com    };
1337532Ssteve.reinhardt@amd.com    FetchTranslation fetchTranslation;
1347532Ssteve.reinhardt@amd.com
1359196SAndreas.Sandberg@arm.com    void threadSnoop(PacketPtr pkt, ThreadID sender);
1369196SAndreas.Sandberg@arm.com    void sendData(const RequestPtr &req,
1379196SAndreas.Sandberg@arm.com                  uint8_t *data, uint64_t *res, bool read);
1382SN/A    void sendSplitData(const RequestPtr &req1, const RequestPtr &req2,
1399196SAndreas.Sandberg@arm.com                       const RequestPtr &req,
1409196SAndreas.Sandberg@arm.com                       uint8_t *data, bool read);
1419196SAndreas.Sandberg@arm.com
1429196SAndreas.Sandberg@arm.com    void translationFault(const Fault &fault);
143330SN/A
1442SN/A    PacketPtr buildPacket(const RequestPtr &req, bool read);
1457532Ssteve.reinhardt@amd.com    void buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
1467532Ssteve.reinhardt@amd.com            const RequestPtr &req1, const RequestPtr &req2,
1477532Ssteve.reinhardt@amd.com            const RequestPtr &req,
1487823Ssteve.reinhardt@amd.com            uint8_t *data, bool read);
1497532Ssteve.reinhardt@amd.com
1507532Ssteve.reinhardt@amd.com    bool handleReadPacket(PacketPtr pkt);
1517492Ssteve.reinhardt@amd.com    // This function always implicitly uses dcache_pkt.
152330SN/A    bool handleWritePacket();
1539196SAndreas.Sandberg@arm.com
1549342SAndreas.Sandberg@arm.com    /**
1559342SAndreas.Sandberg@arm.com     * A TimingCPUPort overrides the default behaviour of the
1569342SAndreas.Sandberg@arm.com     * recvTiming and recvRetry and implements events for the
1579342SAndreas.Sandberg@arm.com     * scheduling of handling of incoming packets in the following
1589342SAndreas.Sandberg@arm.com     * cycle.
1599342SAndreas.Sandberg@arm.com     */
1609342SAndreas.Sandberg@arm.com    class TimingCPUPort : public MasterPort
1619196SAndreas.Sandberg@arm.com    {
1629196SAndreas.Sandberg@arm.com      public:
1639196SAndreas.Sandberg@arm.com
164938SN/A        TimingCPUPort(const std::string& _name, TimingSimpleCPU* _cpu)
1651031SN/A            : MasterPort(_name, _cpu), cpu(_cpu),
1661031SN/A              retryRespEvent([this]{ sendRetryResp(); }, name())
1671031SN/A        { }
1681031SN/A
1691031SN/A      protected:
1701031SN/A
1715314Sstever@gmail.com        TimingSimpleCPU* cpu;
1725314Sstever@gmail.com
1735315Sstever@gmail.com        struct TickEvent : public Event
1745314Sstever@gmail.com        {
1755314Sstever@gmail.com            PacketPtr pkt;
1765314Sstever@gmail.com            TimingSimpleCPU *cpu;
1772SN/A
1782SN/A            TickEvent(TimingSimpleCPU *_cpu) : pkt(NULL), cpu(_cpu) {}
1792SN/A            const char *description() const { return "Timing CPU tick"; }
180            void schedule(PacketPtr _pkt, Tick t);
181        };
182
183        EventFunctionWrapper retryRespEvent;
184    };
185
186    class IcachePort : public TimingCPUPort
187    {
188      public:
189
190        IcachePort(TimingSimpleCPU *_cpu)
191            : TimingCPUPort(_cpu->name() + ".icache_port", _cpu),
192              tickEvent(_cpu)
193        { }
194
195      protected:
196
197        virtual bool recvTimingResp(PacketPtr pkt);
198
199        virtual void recvReqRetry();
200
201        struct ITickEvent : public TickEvent
202        {
203
204            ITickEvent(TimingSimpleCPU *_cpu)
205                : TickEvent(_cpu) {}
206            void process();
207            const char *description() const { return "Timing CPU icache tick"; }
208        };
209
210        ITickEvent tickEvent;
211
212    };
213
214    class DcachePort : public TimingCPUPort
215    {
216      public:
217
218        DcachePort(TimingSimpleCPU *_cpu)
219            : TimingCPUPort(_cpu->name() + ".dcache_port", _cpu),
220              tickEvent(_cpu)
221        {
222           cacheBlockMask = ~(cpu->cacheLineSize() - 1);
223        }
224
225        Addr cacheBlockMask;
226      protected:
227
228        /** Snoop a coherence request, we need to check if this causes
229         * a wakeup event on a cpu that is monitoring an address
230         */
231        virtual void recvTimingSnoopReq(PacketPtr pkt);
232        virtual void recvFunctionalSnoop(PacketPtr pkt);
233
234        virtual bool recvTimingResp(PacketPtr pkt);
235
236        virtual void recvReqRetry();
237
238        virtual bool isSnooping() const {
239            return true;
240        }
241
242        struct DTickEvent : public TickEvent
243        {
244            DTickEvent(TimingSimpleCPU *_cpu)
245                : TickEvent(_cpu) {}
246            void process();
247            const char *description() const { return "Timing CPU dcache tick"; }
248        };
249
250        DTickEvent tickEvent;
251
252    };
253
254    void updateCycleCounts();
255
256    IcachePort icachePort;
257    DcachePort dcachePort;
258
259    PacketPtr ifetch_pkt;
260    PacketPtr dcache_pkt;
261
262    Cycles previousCycle;
263
264  protected:
265
266     /** Return a reference to the data port. */
267    MasterPort &getDataPort() override { return dcachePort; }
268
269    /** Return a reference to the instruction port. */
270    MasterPort &getInstPort() override { return icachePort; }
271
272  public:
273
274    DrainState drain() override;
275    void drainResume() override;
276
277    void switchOut() override;
278    void takeOverFrom(BaseCPU *oldCPU) override;
279
280    void verifyMemoryMode() const override;
281
282    void activateContext(ThreadID thread_num) override;
283    void suspendContext(ThreadID thread_num) override;
284
285    Fault initiateMemRead(Addr addr, unsigned size,
286            Request::Flags flags,
287            const std::vector<bool>& byteEnable =std::vector<bool>())
288        override;
289
290    Fault writeMem(uint8_t *data, unsigned size,
291                   Addr addr, Request::Flags flags, uint64_t *res,
292                   const std::vector<bool>& byteEnable = std::vector<bool>())
293        override;
294
295    Fault initiateMemAMO(Addr addr, unsigned size, Request::Flags flags,
296                         AtomicOpFunctor *amo_op) override;
297
298    void fetch();
299    void sendFetch(const Fault &fault,
300                   const RequestPtr &req, ThreadContext *tc);
301    void completeIfetch(PacketPtr );
302    void completeDataAccess(PacketPtr pkt);
303    void advanceInst(const Fault &fault);
304
305    /** This function is used by the page table walker to determine if it could
306     * translate the a pending request or if the underlying request has been
307     * squashed. This always returns false for the simple timing CPU as it never
308     * executes any instructions speculatively.
309     * @ return Is the current instruction squashed?
310     */
311    bool isSquashed() const { return false; }
312
313    /**
314     * Print state of address in memory system via PrintReq (for
315     * debugging).
316     */
317    void printAddr(Addr a);
318
319    /**
320     * Finish a DTB translation.
321     * @param state The DTB translation state.
322     */
323    void finishTranslation(WholeTranslationState *state);
324
325  private:
326
327    EventFunctionWrapper fetchEvent;
328
329    struct IprEvent : Event {
330        Packet *pkt;
331        TimingSimpleCPU *cpu;
332        IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t);
333        virtual void process();
334        virtual const char *description() const;
335    };
336
337    /**
338     * Check if a system is in a drained state.
339     *
340     * We need to drain if:
341     * <ul>
342     * <li>We are in the middle of a microcode sequence as some CPUs
343     *     (e.g., HW accelerated CPUs) can't be started in the middle
344     *     of a gem5 microcode sequence.
345     *
346     * <li>Stay at PC is true.
347     *
348     * <li>A fetch event is scheduled. Normally this would never be the
349     *     case with microPC() == 0, but right after a context is
350     *     activated it can happen.
351     * </ul>
352     */
353    bool isDrained() {
354        SimpleExecContext& t_info = *threadInfo[curThread];
355        SimpleThread* thread = t_info.thread;
356
357        return thread->microPC() == 0 && !t_info.stayAtPC &&
358               !fetchEvent.scheduled();
359    }
360
361    /**
362     * Try to complete a drain request.
363     *
364     * @returns true if the CPU is drained, false otherwise.
365     */
366    bool tryCompleteDrain();
367};
368
369#endif // __CPU_SIMPLE_TIMING_HH__
370