-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathagc_simulator.c
279 lines (245 loc) · 7.65 KB
/
agc_simulator.c
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/*
* agc_simulator.c
*
* Created on: Dec 2, 2008
* Author: MZ211D
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "yaAGC.h"
#include "agc_cli.h"
#include "agc_engine.h"
#include "agc_symtab.h"
#include "agc_debug.h"
#include "agc_debugger.h"
#include "agc_simulator.h"
/** Declare the singleton Simulator object instance */
static Simulator_t Simulator;
static int SimInitializeEngine(void)
{
int result = 0;
/* Initialize the simulation */
if (!Simulator.Options->debug_dsky)
{
if (Simulator.Options->resume == NULL)
{
if (Simulator.Options->cfg)
{
if (CmOrLm)
{
result = agc_engine_init (&Simulator.State,
Simulator.Options->core, "CM.core", 0);
}
else
{
result = agc_engine_init (&Simulator.State,
Simulator.Options->core, "LM.core", 0);
}
}
else
{
result = agc_engine_init (&Simulator.State,
Simulator.Options->core,"core", 0);
}
}
else
{
result = agc_engine_init (&Simulator.State,
Simulator.Options->core, Simulator.Options->resume, 1);
}
/* Check AGC Engine Init Result and display proper message */
switch (result)
{
case 0:
break; /* All is OK */
case 1:
printf ("Specified core-rope image file not found.\n");
break;
case 2:
printf ("Core-rope image larger than core memory.\n");
break;
case 3:
printf ("Core-rope image file must have even size.\n");
break;
case 5:
printf ("Core-rope image file read error.\n");
break;
default:
printf ("Initialization implementation error.\n");
break;
}
}
return (result);
}
/**
This function executes one cycle of the AGC engine. This is
a wrapper function to eliminate showing the passing of the
current engine state. */
static void SimExecuteEngine()
{
agc_engine (&Simulator.State);
}
/**
Initialize the AGC Simulator; this means setting up the debugger, AGC
engine and initializing the simulator time parameters.
*/
int SimInitialize(Options_t* Options)
{
int result = 0;
/* Without Options we can't Run */
if (!Options) return(6);
/* Set the basic simulator variables */
Simulator.Options = Options;
Simulator.DebugRules = DebugRules;
Simulator.DumpInterval = Options->dump_time * sysconf (_SC_CLK_TCK);
/* Set legacy Option variables */
Portnum = Options->port;
DebugDsky = Options->debug_dsky;
DebugDeda = Options->debug_deda;
DedaQuiet = Options->deda_quiet;
Simulator.DumpInterval = Simulator.DumpInterval;
SocketInterlaceReload = Options->interlace;
/* If we are not in quiet mode display the version info */
if (!Options->quiet) DbgDisplayVersion();
/* Initialize the AGC Engine */
result = SimInitializeEngine();
/* Initialize the Debugger if running with debug mode */
if(Options->debug) DbgInitialize(Options,&(Simulator.State));
// if (Options->cdu_log)
// {
// extern FILE *CduLog;
// CduLog = fopen (Options->cdu_log, "w");
// }
/* Initialize realtime and cycle counters */
Simulator.RealTimeOffset = times (&Simulator.DummyTime); // The starting time of the program.
Simulator.NextCoreDump = Simulator.RealTimeOffset + Simulator.DumpInterval;
SimSetCycleCount(SIM_CYCLECOUNT_AGC); // Num. of AGC cycles so far.
Simulator.RealTimeOffset -= (Simulator.CycleCount + AGC_PER_SECOND / 2) / AGC_PER_SECOND;
Simulator.LastRealTime = ~0UL;
return (result | Options->version);
}
/**
This function adjusts the Simulator Cycle Count. Either based on the number
of AGC Cycles or incremented during Sim cycles. This functions uses a
mode switch to determine how to set or adjust the Cycle Counter
*/
void SimSetCycleCount(int Mode)
{
switch(Mode)
{
case SIM_CYCLECOUNT_AGC:
Simulator.CycleCount = sysconf (_SC_CLK_TCK) * Simulator.State.CycleCounter;
break;
case SIM_CYCLECOUNT_INC:
Simulator.CycleCount += sysconf (_SC_CLK_TCK);
break;
}
}
/**
This function puts the simulator in a sleep state to reduce
CPU usage on the PC.
*/
static void SimSleep(void)
{
#ifdef WIN32
Sleep (10);
#else
struct timespec req, rem;
req.tv_sec = 0;
req.tv_nsec = 10000000;
nanosleep (&req, &rem);
#endif
}
/**
This function manages the AGC periodic core dumping of the
AGC state machine.
*/
static void SimManageCoreDump(void)
{
/* Check to see if the next core dump should be made */
if (Simulator.RealTime >= Simulator.NextCoreDump)
{
/* Use either specific core dump name (from cfg) or generic */
if (Simulator.Options->cfg)
{
if (CmOrLm) MakeCoreDump (&Simulator.State, "CM.core");
else MakeCoreDump (&Simulator.State, "LM.core");
}
else MakeCoreDump (&Simulator.State, "core");
/* Set the next CoreDump Time based on DumpInterval time */
Simulator.NextCoreDump = Simulator.RealTime + Simulator.DumpInterval;
}
}
/**
* This function is a helper to allow the debugger to update the realtime
*/
void SimUpdateTime(void)
{
Simulator.RealTimeOffset +=
((Simulator.RealTime = times (&Simulator.DummyTime)) - Simulator.LastRealTime);
Simulator.LastRealTime = Simulator.RealTime;
}
/**
This function manages the Simulator time to achieve the
average 11.7 microsecond per opcode execution
*/
static void SimManageTime(void)
{
Simulator.RealTime = times (&Simulator.DummyTime);
if (Simulator.RealTime != Simulator.LastRealTime)
{
/* Make a routine core dump */
SimManageCoreDump();
// Need to recalculate the number of AGC cycles we're supposed to
// have executed. Notice the trick of multiplying both CycleCount
// and DesiredCycles by CLK_TCK, to avoid a long long division by CLK_TCK.
// This not only reduces overhead, but actually makes the calculation
// more exact. A bit tricky to understand at first glance, though.
Simulator.LastRealTime = Simulator.RealTime;
//DesiredCycles = ((RealTime - RealTimeOffset) * AGC_PER_SECOND) / CLK_TCK;
//DesiredCycles = (RealTime - RealTimeOffset) * AGC_PER_SECOND;
// The calculation is done in the following funky way because if done as in
// the line above, the right-hand side will be done in 32-bit arithmetic
// on a 32-bit CPU, while the left-hand side is 64-bit, and so the calculation
// will overflow and fail after 4 minutes of operation. Done the following
// way, the calculation will always be 64-bit. Making AGC_PER_SECOND a ULL
// constant in agc_engine.h would fix it, but the Orbiter folk wouldn't
// be able to compile it.
Simulator.DesiredCycles = Simulator.RealTime;
Simulator.DesiredCycles -= Simulator.RealTimeOffset;
Simulator.DesiredCycles *= AGC_PER_SECOND;
}
else SimSleep();
}
/**
Execute the simulated CPU. Expecting to ACCURATELY cycle the simulation every
11.7 microseconds within Linux (or Win32) is a bit too much, I think.
(Not that it's really critical, as long as it looks right from the
user's standpoint.) So I do a trick: I just execute the simulation
often enough to keep up with real-time on the average. AGC time is
measured as the number of machine cycles divided by AGC_PER_SECOND,
while real-time is measured using the times() function. What this mains
is that AGC_PER_SECOND AGC cycles are executed every CLK_TCK clock ticks.
The timing is thus rather rough-and-ready (i.e., I'm sure it can be improved
a lot). It's good enough for me, for NOW, but I'd be happy to take suggestions
for how to improve it in a reasonably portable way.*/
void SimExecute(void)
{
while(1)
{
/* Manage the Simulated Time */
SimManageTime();
while (Simulator.CycleCount < Simulator.DesiredCycles)
{
/* If debugging is enabled run the debugger */
if (Simulator.Options->debug && DbgExecute()) continue;
/* Execute a cyle of the AGC engine */
SimExecuteEngine();
/* Adjust the CycleCount */
SimSetCycleCount(SIM_CYCLECOUNT_INC);
}
}
}