summaryrefslogtreecommitdiff
path: root/src/systemc/ext/tlm_utils/tlm_quantumkeeper.h
blob: bad46ad117adf57aadf7d223ef564280693718a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*****************************************************************************

  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
  more contributor license agreements.  See the NOTICE file distributed
  with this work for additional information regarding copyright ownership.
  Accellera licenses this file to you under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with the
  License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  implied.  See the License for the specific language governing
  permissions and limitations under the License.

 *****************************************************************************/

#ifndef __SYSTEMC_EXT_TLM_UTILS_TLM_QUANTUMKEEPER_H__
#define __SYSTEMC_EXT_TLM_UTILS_TLM_QUANTUMKEEPER_H__

#include <tlm>

namespace tlm_utils
{

// tlm_quantumkeeper class
//
// The tlm_quantumkeeper class is used to keep track of the local time in
// an initiator (how much it has run ahead of the SystemC time), to
// synchronize with SystemC time etc.
class tlm_quantumkeeper
{
  public:
    //
    // Static setters/getters for the global quantum value.
    //
    // The global quantum is the maximum time an initiator can run ahead of
    // SystemC time. All initiators will synchronize on timing points that are
    // multiples of the global quantum value.
    //
    static void
    set_global_quantum(const sc_core::sc_time &t)
    {
        tlm::tlm_global_quantum::instance().set(t);
    }

    static const sc_core::sc_time &
    get_global_quantum()
    {
        return tlm::tlm_global_quantum::instance().get();
    }

  public:
    tlm_quantumkeeper() : m_next_sync_point(sc_core::SC_ZERO_TIME),
                          m_local_time(sc_core::SC_ZERO_TIME)
    {}

    virtual ~tlm_quantumkeeper() {}

    // Increment the local time (the time the initiator is ahead of the
    // systemC time) After incrementing the local time an initiator should
    // check (with the need_sync method) if a sync is required.
    virtual void inc(const sc_core::sc_time &t) { m_local_time += t; }

    // Sets the local time (the time the initiator is ahead of the
    // systemC time) After changing the local time an initiator should
    // check (with the need_sync method) if a sync is required.
    virtual void set(const sc_core::sc_time &t) { m_local_time = t; }

    // Checks if a sync to systemC is required for this initiator. This will
    // be the case if the local time becomes greater than the local (current)
    // quantum value for this initiator.
    virtual bool
    need_sync() const
    {
        return sc_core::sc_time_stamp() + m_local_time >= m_next_sync_point;
    }

    // Synchronize to systemC. This call will do a wait for the time the
    // initiator was running ahead of systemC time and reset the
    // tlm_quantumkeeper.
    virtual void
    sync()
    {
        sc_core::wait(m_local_time);
        reset();
    }

    // Non-virtual convenience method to set the local time and sync only if
    // needed
    void
    set_and_sync(const sc_core::sc_time &t)
    {
        set(t);
        if (need_sync())
            sync();
    }

    // Resets the local time to SC_ZERO_TIME and computes the value of the
    // next local quantum. This method should be called by an initiator after
    // a wait because of a synchronization request by a target (TLM_ACCEPTED,
    // or TLM_UPDATED).
    virtual void
    reset()
    {
        m_local_time = sc_core::SC_ZERO_TIME;
        m_next_sync_point = sc_core::sc_time_stamp() + compute_local_quantum();
    }

    // Helper function to get the current systemC time, taken the local time
    // into account. The current systemC time is calculated as the time
    // returned by sc_time_stamp incremeneted with the time the initiator is
    // running ahead.
    virtual sc_core::sc_time
    get_current_time() const
    {
        return sc_core::sc_time_stamp() + m_local_time;
    }

    // Helper functions to get the time the initiator is running ahead of
    // systenC (local time). This time should be passed to a target in the
    // nb_transport call
    virtual sc_core::sc_time
    get_local_time() const
    {
        return m_local_time;
    }

  protected:
    // Calculate the next local quantum for this initiator.
    //
    // The method can be overloaded in a derived object if an initiator wants
    // to use another local quantum. This derived object should also take the
    // global quantum into account. It's local quantum should not be set to a
    // value that is larger than the quantum returned by the
    // compute_local_quantum of the tlm_global_quantum singleton.
    virtual sc_core::sc_time
    compute_local_quantum()
    {
        return tlm::tlm_global_quantum::instance().compute_local_quantum();
    }

  protected:
    sc_core::sc_time m_next_sync_point;
    sc_core::sc_time m_local_time;
};

} // namespace tlm_utils

#endif /* __SYSTEMC_EXT_TLM_UTILS_TLM_QUANTUMKEEPER_H__ */