timing.hh revision 14297:b4519e586f5e
15217Ssaidi@eecs.umich.edu/*
29428SAndreas.Sandberg@ARM.com * Copyright (c) 2012-2013,2015,2018 ARM Limited
39920Syasuko.eckert@amd.com * All rights reserved
49428SAndreas.Sandberg@ARM.com *
59428SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall
69428SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual
79428SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating
89428SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software
99428SAndreas.Sandberg@ARM.com * licensed hereunder.  You may use the software subject to the license
109428SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated
119428SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software,
129428SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form.
139428SAndreas.Sandberg@ARM.com *
149428SAndreas.Sandberg@ARM.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
155217Ssaidi@eecs.umich.edu * All rights reserved.
165217Ssaidi@eecs.umich.edu *
175217Ssaidi@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
185217Ssaidi@eecs.umich.edu * modification, are permitted provided that the following conditions are
195217Ssaidi@eecs.umich.edu * met: redistributions of source code must retain the above copyright
205217Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
215217Ssaidi@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
225217Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
235217Ssaidi@eecs.umich.edu * documentation and/or other materials provided with the distribution;
245217Ssaidi@eecs.umich.edu * neither the name of the copyright holders nor the names of its
255217Ssaidi@eecs.umich.edu * contributors may be used to endorse or promote products derived from
265217Ssaidi@eecs.umich.edu * this software without specific prior written permission.
275217Ssaidi@eecs.umich.edu *
285217Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
295217Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
305217Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
315217Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
325217Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
335217Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
345217Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
355217Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
365217Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
375217Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
385217Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
395217Ssaidi@eecs.umich.edu *
405217Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt
415217Ssaidi@eecs.umich.edu */
425217Ssaidi@eecs.umich.edu
435217Ssaidi@eecs.umich.edu#ifndef __CPU_SIMPLE_TIMING_HH__
445217Ssaidi@eecs.umich.edu#define __CPU_SIMPLE_TIMING_HH__
455217Ssaidi@eecs.umich.edu
466658Snate@binkert.org#include "cpu/simple/base.hh"
479441SAndreas.Sandberg@ARM.com#include "cpu/simple/exec_context.hh"
489441SAndreas.Sandberg@ARM.com#include "cpu/translation.hh"
495217Ssaidi@eecs.umich.edu#include "params/TimingSimpleCPU.hh"
508232Snate@binkert.org
519441SAndreas.Sandberg@ARM.comclass TimingSimpleCPU : public BaseSimpleCPU
525217Ssaidi@eecs.umich.edu{
535217Ssaidi@eecs.umich.edu  public:
545217Ssaidi@eecs.umich.edu
555217Ssaidi@eecs.umich.edu    TimingSimpleCPU(TimingSimpleCPUParams * params);
565217Ssaidi@eecs.umich.edu    virtual ~TimingSimpleCPU();
575217Ssaidi@eecs.umich.edu
585217Ssaidi@eecs.umich.edu    void init() override;
595217Ssaidi@eecs.umich.edu
605217Ssaidi@eecs.umich.edu  private:
615217Ssaidi@eecs.umich.edu
625217Ssaidi@eecs.umich.edu    /*
635217Ssaidi@eecs.umich.edu     * If an access needs to be broken into fragments, currently at most two,
645217Ssaidi@eecs.umich.edu     * the the following two classes are used as the sender state of the
655217Ssaidi@eecs.umich.edu     * packets so the CPU can keep track of everything. In the main packet
665217Ssaidi@eecs.umich.edu     * sender state, there's an array with a spot for each fragment. If a
675217Ssaidi@eecs.umich.edu     * fragment has already been accepted by the CPU, aka isn't waiting for
685217Ssaidi@eecs.umich.edu     * a retry, it's pointer is NULL. After each fragment has successfully
695217Ssaidi@eecs.umich.edu     * been processed, the "outstanding" counter is decremented. Once the
705217Ssaidi@eecs.umich.edu     * count is zero, the entire larger access is complete.
715217Ssaidi@eecs.umich.edu     */
725217Ssaidi@eecs.umich.edu    class SplitMainSenderState : public Packet::SenderState
735217Ssaidi@eecs.umich.edu    {
745217Ssaidi@eecs.umich.edu      public:
755217Ssaidi@eecs.umich.edu        int outstanding;
765217Ssaidi@eecs.umich.edu        PacketPtr fragments[2];
775217Ssaidi@eecs.umich.edu
785217Ssaidi@eecs.umich.edu        int
795217Ssaidi@eecs.umich.edu        getPendingFragment()
805217Ssaidi@eecs.umich.edu        {
815217Ssaidi@eecs.umich.edu            if (fragments[0]) {
825217Ssaidi@eecs.umich.edu                return 0;
839920Syasuko.eckert@amd.com            } else if (fragments[1]) {
849920Syasuko.eckert@amd.com                return 1;
859920Syasuko.eckert@amd.com            } else {
869920Syasuko.eckert@amd.com                return -1;
879920Syasuko.eckert@amd.com            }
889920Syasuko.eckert@amd.com        }
899920Syasuko.eckert@amd.com    };
909920Syasuko.eckert@amd.com
917720Sgblack@eecs.umich.edu    class SplitFragmentSenderState : public Packet::SenderState
927720Sgblack@eecs.umich.edu    {
935712Shsul@eecs.umich.edu      public:
945712Shsul@eecs.umich.edu        SplitFragmentSenderState(PacketPtr _bigPkt, int _index) :
955217Ssaidi@eecs.umich.edu            bigPkt(_bigPkt), index(_index)
965217Ssaidi@eecs.umich.edu        {}
975714Shsul@eecs.umich.edu        PacketPtr bigPkt;
985714Shsul@eecs.umich.edu        int index;
995714Shsul@eecs.umich.edu
1005714Shsul@eecs.umich.edu        void
1015714Shsul@eecs.umich.edu        clearFromParent()
1025714Shsul@eecs.umich.edu        {
1035714Shsul@eecs.umich.edu            SplitMainSenderState * main_send_state =
1045217Ssaidi@eecs.umich.edu                dynamic_cast<SplitMainSenderState *>(bigPkt->senderState);
1059428SAndreas.Sandberg@ARM.com            main_send_state->fragments[index] = NULL;
1069428SAndreas.Sandberg@ARM.com        }
1079428SAndreas.Sandberg@ARM.com    };
1089428SAndreas.Sandberg@ARM.com
1099428SAndreas.Sandberg@ARM.com    class FetchTranslation : public BaseTLB::Translation
1109428SAndreas.Sandberg@ARM.com    {
1119428SAndreas.Sandberg@ARM.com      protected:
1129428SAndreas.Sandberg@ARM.com        TimingSimpleCPU *cpu;
1139428SAndreas.Sandberg@ARM.com
1149428SAndreas.Sandberg@ARM.com      public:
1159428SAndreas.Sandberg@ARM.com        FetchTranslation(TimingSimpleCPU *_cpu)
1169428SAndreas.Sandberg@ARM.com            : cpu(_cpu)
1179428SAndreas.Sandberg@ARM.com        {}
1189428SAndreas.Sandberg@ARM.com
1199428SAndreas.Sandberg@ARM.com        void
1209428SAndreas.Sandberg@ARM.com        markDelayed()
1219428SAndreas.Sandberg@ARM.com        {
1229428SAndreas.Sandberg@ARM.com            assert(cpu->_status == BaseSimpleCPU::Running);
1239920Syasuko.eckert@amd.com            cpu->_status = ITBWaitResponse;
1249920Syasuko.eckert@amd.com        }
1259920Syasuko.eckert@amd.com
1269920Syasuko.eckert@amd.com        void
1279920Syasuko.eckert@amd.com        finish(const Fault &fault, const RequestPtr &req, ThreadContext *tc,
1289920Syasuko.eckert@amd.com               BaseTLB::Mode mode)
1299920Syasuko.eckert@amd.com        {
1309428SAndreas.Sandberg@ARM.com            cpu->sendFetch(fault, req, tc);
1319428SAndreas.Sandberg@ARM.com        }
1329428SAndreas.Sandberg@ARM.com    };
1339428SAndreas.Sandberg@ARM.com    FetchTranslation fetchTranslation;
1349428SAndreas.Sandberg@ARM.com
1359428SAndreas.Sandberg@ARM.com    void threadSnoop(PacketPtr pkt, ThreadID sender);
1369428SAndreas.Sandberg@ARM.com    void sendData(const RequestPtr &req,
1379428SAndreas.Sandberg@ARM.com                  uint8_t *data, uint64_t *res, bool read);
1389428SAndreas.Sandberg@ARM.com    void sendSplitData(const RequestPtr &req1, const RequestPtr &req2,
1399428SAndreas.Sandberg@ARM.com                       const RequestPtr &req,
1409428SAndreas.Sandberg@ARM.com                       uint8_t *data, bool read);
1419428SAndreas.Sandberg@ARM.com
1429428SAndreas.Sandberg@ARM.com    void translationFault(const Fault &fault);
1439428SAndreas.Sandberg@ARM.com
1449428SAndreas.Sandberg@ARM.com    PacketPtr buildPacket(const RequestPtr &req, bool read);
1459428SAndreas.Sandberg@ARM.com    void buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
1469428SAndreas.Sandberg@ARM.com            const RequestPtr &req1, const RequestPtr &req2,
1479428SAndreas.Sandberg@ARM.com            const RequestPtr &req,
1489428SAndreas.Sandberg@ARM.com            uint8_t *data, bool read);
1499428SAndreas.Sandberg@ARM.com
1509428SAndreas.Sandberg@ARM.com    bool handleReadPacket(PacketPtr pkt);
1519428SAndreas.Sandberg@ARM.com    // This function always implicitly uses dcache_pkt.
1529920Syasuko.eckert@amd.com    bool handleWritePacket();
1539920Syasuko.eckert@amd.com
1549920Syasuko.eckert@amd.com    /**
1559920Syasuko.eckert@amd.com     * A TimingCPUPort overrides the default behaviour of the
1569920Syasuko.eckert@amd.com     * recvTiming and recvRetry and implements events for the
1579920Syasuko.eckert@amd.com     * scheduling of handling of incoming packets in the following
1589920Syasuko.eckert@amd.com     * cycle.
1599428SAndreas.Sandberg@ARM.com     */
1609428SAndreas.Sandberg@ARM.com    class TimingCPUPort : public MasterPort
1619428SAndreas.Sandberg@ARM.com    {
1629428SAndreas.Sandberg@ARM.com      public:
1639428SAndreas.Sandberg@ARM.com
1649428SAndreas.Sandberg@ARM.com        TimingCPUPort(const std::string& _name, TimingSimpleCPU* _cpu)
1659441SAndreas.Sandberg@ARM.com            : MasterPort(_name, _cpu), cpu(_cpu),
1669441SAndreas.Sandberg@ARM.com              retryRespEvent([this]{ sendRetryResp(); }, name())
1679441SAndreas.Sandberg@ARM.com        { }
1689441SAndreas.Sandberg@ARM.com
1699441SAndreas.Sandberg@ARM.com      protected:
1709441SAndreas.Sandberg@ARM.com
1719441SAndreas.Sandberg@ARM.com        TimingSimpleCPU* cpu;
1729441SAndreas.Sandberg@ARM.com
1739441SAndreas.Sandberg@ARM.com        struct TickEvent : public Event
1749441SAndreas.Sandberg@ARM.com        {
1759441SAndreas.Sandberg@ARM.com            PacketPtr pkt;
1769441SAndreas.Sandberg@ARM.com            TimingSimpleCPU *cpu;
1779441SAndreas.Sandberg@ARM.com
1789441SAndreas.Sandberg@ARM.com            TickEvent(TimingSimpleCPU *_cpu) : pkt(NULL), cpu(_cpu) {}
1799441SAndreas.Sandberg@ARM.com            const char *description() const { return "Timing CPU tick"; }
1809441SAndreas.Sandberg@ARM.com            void schedule(PacketPtr _pkt, Tick t);
1819441SAndreas.Sandberg@ARM.com        };
1829441SAndreas.Sandberg@ARM.com
1839441SAndreas.Sandberg@ARM.com        EventFunctionWrapper retryRespEvent;
1849441SAndreas.Sandberg@ARM.com    };
1859441SAndreas.Sandberg@ARM.com
1869441SAndreas.Sandberg@ARM.com    class IcachePort : public TimingCPUPort
1879441SAndreas.Sandberg@ARM.com    {
1889441SAndreas.Sandberg@ARM.com      public:
1899441SAndreas.Sandberg@ARM.com
1909441SAndreas.Sandberg@ARM.com        IcachePort(TimingSimpleCPU *_cpu)
1919441SAndreas.Sandberg@ARM.com            : TimingCPUPort(_cpu->name() + ".icache_port", _cpu),
1929441SAndreas.Sandberg@ARM.com              tickEvent(_cpu)
1939441SAndreas.Sandberg@ARM.com        { }
1949441SAndreas.Sandberg@ARM.com
1959441SAndreas.Sandberg@ARM.com      protected:
1969441SAndreas.Sandberg@ARM.com
1979441SAndreas.Sandberg@ARM.com        virtual bool recvTimingResp(PacketPtr pkt);
1989441SAndreas.Sandberg@ARM.com
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    Port &getDataPort() override { return dcachePort; }
268
269    /** Return a reference to the instruction port. */
270    Port &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                         AtomicOpFunctorPtr 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 isCpuDrained() const {
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