1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20#ifndef __SYSTEMC_EXT_TLM_UTILS_TLM_QUANTUMKEEPER_H__
21#define __SYSTEMC_EXT_TLM_UTILS_TLM_QUANTUMKEEPER_H__
22
23#include "../core/sc_time.hh"
24
25namespace tlm_utils
26{
27
28// tlm_quantumkeeper class
29//
30// The tlm_quantumkeeper class is used to keep track of the local time in
31// an initiator (how much it has run ahead of the SystemC time), to
32// synchronize with SystemC time etc.
33class tlm_quantumkeeper
34{
35  public:
36    //
37    // Static setters/getters for the global quantum value.
38    //
39    // The global quantum is the maximum time an initiator can run ahead of
40    // SystemC time. All initiators will synchronize on timing points that are
41    // multiples of the global quantum value.
42    //
43    static void
44    set_global_quantum(const sc_core::sc_time &t)
45    {
46        tlm::tlm_global_quantum::instance().set(t);
47    }
48
49    static const sc_core::sc_time &
50    get_global_quantum()
51    {
52        return tlm::tlm_global_quantum::instance().get();
53    }
54
55  public:
56    tlm_quantumkeeper() : m_next_sync_point(sc_core::SC_ZERO_TIME),
57                          m_local_time(sc_core::SC_ZERO_TIME)
58    {}
59
60    virtual ~tlm_quantumkeeper() {}
61
62    // Increment the local time (the time the initiator is ahead of the
63    // systemC time) After incrementing the local time an initiator should
64    // check (with the need_sync method) if a sync is required.
65    virtual void inc(const sc_core::sc_time &t) { m_local_time += t; }
66
67    // Sets the local time (the time the initiator is ahead of the
68    // systemC time) After changing the local time an initiator should
69    // check (with the need_sync method) if a sync is required.
70    virtual void set(const sc_core::sc_time &t) { m_local_time = t; }
71
72    // Checks if a sync to systemC is required for this initiator. This will
73    // be the case if the local time becomes greater than the local (current)
74    // quantum value for this initiator.
75    virtual bool
76    need_sync() const
77    {
78        return sc_core::sc_time_stamp() + m_local_time >= m_next_sync_point;
79    }
80
81    // Synchronize to systemC. This call will do a wait for the time the
82    // initiator was running ahead of systemC time and reset the
83    // tlm_quantumkeeper.
84    virtual void
85    sync()
86    {
87        sc_core::wait(m_local_time);
88        reset();
89    }
90
91    // Non-virtual convenience method to set the local time and sync only if
92    // needed
93    void
94    set_and_sync(const sc_core::sc_time &t)
95    {
96        set(t);
97        if (need_sync())
98            sync();
99    }
100
101    // Resets the local time to SC_ZERO_TIME and computes the value of the
102    // next local quantum. This method should be called by an initiator after
103    // a wait because of a synchronization request by a target (TLM_ACCEPTED,
104    // or TLM_UPDATED).
105    virtual void
106    reset()
107    {
108        m_local_time = sc_core::SC_ZERO_TIME;
109        m_next_sync_point = sc_core::sc_time_stamp() + compute_local_quantum();
110    }
111
112    // Helper function to get the current systemC time, taken the local time
113    // into account. The current systemC time is calculated as the time
114    // returned by sc_time_stamp incremeneted with the time the initiator is
115    // running ahead.
116    virtual sc_core::sc_time
117    get_current_time() const
118    {
119        return sc_core::sc_time_stamp() + m_local_time;
120    }
121
122    // Helper functions to get the time the initiator is running ahead of
123    // systenC (local time). This time should be passed to a target in the
124    // nb_transport call
125    virtual sc_core::sc_time
126    get_local_time() const
127    {
128        return m_local_time;
129    }
130
131  protected:
132    // Calculate the next local quantum for this initiator.
133    //
134    // The method can be overloaded in a derived object if an initiator wants
135    // to use another local quantum. This derived object should also take the
136    // global quantum into account. It's local quantum should not be set to a
137    // value that is larger than the quantum returned by the
138    // compute_local_quantum of the tlm_global_quantum singleton.
139    virtual sc_core::sc_time
140    compute_local_quantum()
141    {
142        return tlm::tlm_global_quantum::instance().compute_local_quantum();
143    }
144
145  protected:
146    sc_core::sc_time m_next_sync_point;
147    sc_core::sc_time m_local_time;
148};
149
150} // namespace tlm_utils
151
152#endif /* __SYSTEMC_EXT_TLM_UTILS_TLM_QUANTUMKEEPER_H__ */
153