1 /*
2 Copyright (C) 1998-2000 T. Scott Dattalo
3
4 This file is part of the libgpsim library of gpsim
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, see
18 <http://www.gnu.org/licenses/lgpl-2.1.html>.
19 */
20
21 #ifndef SRC_GPSIM_TIME_H_
22 #define SRC_GPSIM_TIME_H_
23
24 #include "exports.h"
25 #include "breakpoints.h"
26
27 //---------------------------------------------------------
28 // Cycle Counter
29 //
30 // The cycle counter class is used to coordinate the timing
31 // between the different peripherals within a processor and
32 // in some cases, the timing between several simulated processors
33 // and modules.
34 //
35 // The smallest quantum of simulated time is called a 'cycle'.
36 // The simuluation engine increments a 'Cycle Counter' at quantum
37 // simulation step. Simulation objects that wished to be notified
38 // at a specific instance in time can set a cycle counter break
39 // point that will get invoked whenever the cycle counter reaches
40 // that instance.
41
42
43
44 //------------------------------------------------------------
45 //
46 // Cycle counter breakpoint list
47 //
48 // This is a friend class to the Cycle Counter class. Its purpose
49 // is to maintain a doubly linked list of cycle counter break
50 // points.
51
52 class Cycle_Counter_breakpoint_list {
53 public:
54 Cycle_Counter_breakpoint_list();
55
56 Cycle_Counter_breakpoint_list *getNext();
57 Cycle_Counter_breakpoint_list *getPrev();
58 void clear();
59 void invoke();
60
61 // This is the value compared to the cycle counter.
62 guint64 break_value;
63
64 // True when this break is active.
65 bool bActive = false;
66
67 // The breakpoint_number is a number uniquely identifying this
68 // cycle counter break point. Note, this number is used only
69 // when the break point was assigned by a user
70
71 unsigned int breakpoint_number = 0;
72
73 // If non-null, the TriggerObject will point to an object that will get invoked
74 // when the breakpoint is encountered.
75
76 TriggerObject *f = nullptr;
77
78 // Doubly-linked list mechanics..
79 // (these will be made private eventually)
80 Cycle_Counter_breakpoint_list *next = nullptr;
81 Cycle_Counter_breakpoint_list *prev = nullptr;
82 };
83
84
85 class Cycle_Counter {
86 public:
87 #define BREAK_ARRAY_SIZE 4
88 #define BREAK_ARRAY_MASK (BREAK_ARRAY_SIZE -1)
89
90 Cycle_Counter();
91 ~Cycle_Counter();
92
93 void preset(guint64 new_value); // not used currently.
94
95 /*
96 increment - This inline member function is called once or
97 twice for every simulated instruction. Its purpose is to
98 increment the cycle counter using roll over arithmetic.
99 If there's a breakpoint set on the new value of the cycle
100 counter then the simulation is either stopped or a callback
101 function is invoked. In either case, the break point is
102 cleared.
103 */
104
increment()105 inline void increment()
106 {
107 // This has been changed so the cycle counter (value)
108 // is incremented after processing breakpoints
109
110 // Increment the current cycle then check if
111 // we have a break point set here
112 if (value == break_on_this) {
113 breakpoint();
114 }
115
116 value++;
117 // Note that it's really inefficient to trace every cycle increment.
118 // Instead, we implicitly trace the increments with the instruction traces.
119 }
120
121 /*
122 advance the Cycle Counter by more than one instruction quantum.
123 This is almost identical to the increment() function except that
124 we allow the counter to be advanced by an arbitrary amount.
125 They're separated only for efficiency reasons. This one runs slower.
126 */
advance(guint64 step)127 inline void advance(guint64 step)
128 {
129 while (step--) {
130 if (value == break_on_this) {
131 breakpoint();
132 }
133 }
134
135 value++;
136 }
137
138 // Return the current cycle counter value
get()139 guint64 get()
140 {
141 return value;
142 }
143
144 // Return the cycle counter for some time off in the future:
145 guint64 get(double future_time_from_now);
146
147 bool set_break(guint64 future_cycle,
148 TriggerObject *f = nullptr, unsigned int abp = MAX_BREAKPOINTS);
149 bool set_break_delta(guint64 future_cycle,
150 TriggerObject *f = nullptr, unsigned int abp = MAX_BREAKPOINTS);
151 bool reassign_break(guint64 old_cycle, guint64 future_cycle, TriggerObject *f = nullptr);
152 void clear_current_break(TriggerObject *f = nullptr);
153 void dump_breakpoints();
154
155 void clear_break(guint64 at_cycle);
156 void clear_break(TriggerObject *f);
157 void set_instruction_cps(guint64 cps);
instruction_cps()158 double instruction_cps()
159 {
160 return m_instruction_cps;
161 }
seconds_per_cycle()162 double seconds_per_cycle()
163 {
164 return m_seconds_per_cycle;
165 }
166
167 // Largest cycle counter value
168
169 static const guint64 END_OF_TIME = 0xFFFFFFFFFFFFFFFFULL;
170
171
172 bool reassigned = false; // Set true when a break point is reassigned (or deleted)
173
174 Cycle_Counter_breakpoint_list
175 active, // Head of the active breakpoint linked list
176 inactive; // Head of the inactive one.
177
178 bool bSynchronous = false; // a flag that's true when the time per counter tick is constant
179
180 private:
181 // The number of instruction cycles that correspond to one second
182 double m_instruction_cps;
183 double m_seconds_per_cycle;
184
185 guint64 value = 0; // Current value of the cycle counter.
186 guint64 break_on_this; // If there's a pending cycle break point, then it'll be this
187
188 /*
189 breakpoint
190 when the member function "increment()" encounters a break point,
191 breakpoint() is called.
192 */
193
194 void breakpoint();
195 };
196
197
198 #if defined(IN_MODULE) && defined(_WIN32)
199 // we are in a module: don't access cycles object directly!
200 LIBGPSIM_EXPORT Cycle_Counter &get_cycles();
201 #else
202 // we are in gpsim: use of get_cycles() is recommended,
203 // even if cycles object can be accessed directly.
204 extern Cycle_Counter cycles;
205
get_cycles()206 inline Cycle_Counter &get_cycles()
207 {
208 return cycles;
209 }
210 #endif
211
212
213
214 /// The stopwatch object is used to keep track of the amount of
215 /// time between events. It can be controlled either through the
216 /// class API or through its attributes
217 class StopWatch : public TriggerObject {
218 public:
219 StopWatch();
220 ~StopWatch();
221
222 guint64 get();
223 double get_time();
224
225 void set_enable(bool);
226 void set_direction(bool);
227 void set_rollover(guint64);
228 void set_value(guint64);
229
230 void set_break(bool);
231
232 void update();
233
234 virtual void callback();
235 virtual void callback_print();
236
237 private:
238 Integer *value;
239 Integer *rollover;
240 Boolean *enable;
241 Boolean *direction;
242
243 bool count_dir;
244
245 guint64 offset = 0;
246 guint64 break_cycle = 0;
247 };
248
249
250 extern StopWatch *stop_watch;
251
252
253 #endif
254