forked from xcore/tool_axe
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Core.h
357 lines (300 loc) · 9.15 KB
/
Core.h
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
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
// Copyright (c) 2011-2012, Richard Osborne, All rights reserved
// This software is freely distributable under a derivative of the
// University of Illinois/NCSA Open Source License posted in
// LICENSE.txt and at <http://github.xcore.com/>
#ifndef _Core_h_
#define _Core_h_
#include "Config.h"
#include <iterator>
#include <cstring>
#include "Resource.h"
#include "Thread.h"
#include "Port.h"
#include "Instruction.h"
#include "BitManip.h"
#include <string>
#include <climits>
class Lock;
class Synchroniser;
class Chanend;
class ChanEndpoint;
class ClockBlock;
class Port;
class Timer;
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
class Node;
enum ProcessorState {
PS_RAM_BASE = 0x00b,
PS_VECTOR_BASE = 0x10b
};
class Core {
public:
enum {
RUN_JIT_ADDR_OFFSET = 2,
INTERPRET_ONE_ADDR_OFFSET = 3,
ILLEGAL_PC_THREAD_ADDR_OFFSET = 4
};
enum {
INVALIDATE_NONE,
INVALIDATE_CURRENT,
INVALIDATE_CURRENT_AND_PREVIOUS
};
private:
typedef int executionFrequency_t;
static const executionFrequency_t MIN_EXECUTION_FREQUENCY = INT_MIN;
executionFrequency_t *executionFrequency;
uint32_t * memoryOffset;
unsigned char *invalidationInfoOffset;
// The opcode cache is bigger than the memory size. We place an ILLEGAL_PC
// pseudo instruction just past the end of memory. This saves
// us from having to check for illegal pc values when incrementing the pc from
// the previous instruction. Addition pseudo instructions come after this and
// are use for communicating illegal states.
OPCODE_TYPE *opcode;
Operands *operands;
public:
const uint32_t ramSizeLog2;
const uint32_t ram_base;
const uint32_t ramBaseMultiple;
private:
Thread * const thread;
Synchroniser * const sync;
Lock * const lock;
Chanend * const chanend;
Timer * const timer;
ClockBlock * const clkBlk;
Port ** const port;
unsigned *portNum;
Resource ***resource;
unsigned *resourceNum;
static bool allocatable[LAST_STD_RES_TYPE + 1];
uint32_t * const memory;
unsigned coreNumber;
Node *parent;
std::string codeReference;
OPCODE_TYPE decodeOpcode;
bool hasMatchingNodeID(ResourceID ID);
void invalidateWordSlowPath(uint32_t address);
void invalidateSlowPath(uint32_t shiftedAddress);
private:
unsigned char *invalidationInfo;
uint32_t getRamSizeShorts() const { return 1 << (ramSizeLog2 - 1); }
public:
uint32_t vector_base;
uint32_t syscallAddress;
uint32_t exceptionAddress;
Core(uint32_t RamSize, uint32_t RamBase);
~Core();
void clearOpcode(uint32_t pc);
void setOpcode(uint32_t pc, OPCODE_TYPE opc, unsigned size);
void setOpcode(uint32_t pc, OPCODE_TYPE opc, Operands &ops, unsigned size);
const Operands &getOperands(uint32_t pc) const { return operands[pc]; }
const OPCODE_TYPE *getOpcodeArray() const { return opcode; }
bool setSyscallAddress(uint32_t value);
bool setExceptionAddress(uint32_t value);
void initCache(OPCODE_TYPE decode, OPCODE_TYPE illegalPC,
OPCODE_TYPE illegalPCThread, OPCODE_TYPE runJit,
OPCODE_TYPE interpretOne);
void resetCaches();
void runJIT(uint32_t jitPc);
uint32_t getRamSize() const { return 1 << ramSizeLog2; }
bool updateExecutionFrequencyFromStub(uint32_t shiftedAddress) {
const executionFrequency_t threshold = 128;
if (++executionFrequency[shiftedAddress] > threshold) {
return true;
}
return false;
}
void updateExecutionFrequency(uint32_t shiftedAddress) {
if (updateExecutionFrequencyFromStub(shiftedAddress))
runJIT(shiftedAddress);
}
uint32_t targetPc(unsigned pc) const
{
return ram_base + (pc << 1);
}
uint32_t virtualAddress(uint32_t address) const
{
return address + ram_base;
}
uint32_t physicalAddress(uint32_t address) const
{
return address - ram_base;
}
bool isValidAddress(uint32_t address) const
{
return (address >> ramSizeLog2) == ramBaseMultiple;
}
bool isValidPc(uint32_t address) const {
return address < getRamSizeShorts();
}
uint32_t toPc(uint32_t address) const {
return (address - ram_base) >> 1;
}
uint32_t fromPc(uint32_t pc) const {
return (pc << 1) + ram_base;
}
private:
uint8_t *mem() {
return reinterpret_cast<uint8_t*>(memory);
}
const uint8_t *mem() const {
return reinterpret_cast<uint8_t*>(memory);
}
uint8_t *memOffset() {
return reinterpret_cast<uint8_t*>(memoryOffset);
}
const uint8_t *memOffset() const {
return reinterpret_cast<uint8_t*>(memoryOffset);
}
public:
uint32_t loadWord(uint32_t address) const
{
if (HOST_LITTLE_ENDIAN) {
return *reinterpret_cast<const uint32_t*>((memOffset() + address));
} else {
return
bswap32(*reinterpret_cast<const uint32_t*>((memOffset() + address)));
}
}
int16_t loadShort(uint32_t address) const
{
return loadByte(address) | loadByte(address + 1) << 8;
}
uint8_t loadByte(uint32_t address) const
{
return memOffset()[address];
}
bool invalidateWordCheck(uint32_t address) {
uint16_t info;
std::memcpy(&info, &invalidationInfoOffset[address >> 1], sizeof(info));
if (info == (INVALIDATE_NONE | (INVALIDATE_NONE << 8)))
return false;
return true;
}
bool invalidateWord(uint32_t address) {
if (!invalidateWordCheck(address))
return false;
invalidateWordSlowPath(address >> 1);
return true;
}
bool invalidateShortCheck(uint32_t address) {
if (invalidationInfoOffset[address >> 1] == INVALIDATE_NONE)
return false;
return true;
}
bool invalidateShort(uint32_t address) {
if (!invalidateShortCheck(address))
return false;
invalidateSlowPath(address >> 1);
return true;
}
bool invalidateByteCheck(uint32_t address) {
if (invalidationInfoOffset[address >> 1] == INVALIDATE_NONE)
return false;
return true;
}
bool invalidateByte(uint32_t address) {
if (!invalidateByteCheck(address))
return false;
invalidateSlowPath(address >> 1);
return true;
}
uint8_t &byte(uint32_t address)
{
return memOffset()[address];
}
void storeWord(uint32_t value, uint32_t address)
{
if (HOST_LITTLE_ENDIAN) {
*reinterpret_cast<uint32_t*>((memOffset() + address)) = value;
} else {
*reinterpret_cast<uint32_t*>((memOffset() + address)) = bswap32(value);
}
}
void storeShort(int16_t value, uint32_t address)
{
memOffset()[address] = static_cast<uint8_t>(value);
memOffset()[address + 1] = static_cast<uint8_t>(value >> 8);
}
void storeByte(uint8_t value, uint32_t address)
{
memOffset()[address] = value;
}
void writeMemory(uint32_t address, void *src, size_t size);
Resource *allocResource(Thread ¤t, ResourceType type);
Thread *allocThread(Thread ¤t)
{
return static_cast<Thread*>(allocResource(current, RES_TYPE_THREAD));
}
const Port *getPortByID(ResourceID ID) const;
/// Returns the resource associated with the resource ID or NULL if the
/// the resource ID is invalid.
Resource *getResourceByID(ResourceID ID);
const Resource *getResourceByID(ResourceID ID) const;
bool getLocalChanendDest(ResourceID ID, ChanEndpoint *&result);
ChanEndpoint *getChanendDest(ResourceID ID);
unsigned getRunJitAddr() const {
return (getRamSizeShorts() - 1) + RUN_JIT_ADDR_OFFSET;
}
unsigned getInterpretOneAddr() const {
return (getRamSizeShorts() - 1) + INTERPRET_ONE_ADDR_OFFSET;
}
unsigned getIllegalPCThreadAddr() const {
return (getRamSizeShorts() - 1) + ILLEGAL_PC_THREAD_ADDR_OFFSET;
}
void finalize();
void updateIDs();
/// Set the parent of the current core. updateIDs() must be called to update
/// The core IDs and the channel end resource IDs.
void setParent(Node *n) {
parent = n;
}
void setCoreNumber(unsigned value) { coreNumber = value; }
unsigned getCoreNumber() const { return coreNumber; }
uint32_t getCoreID() const;
const Node *getParent() const { return parent; }
Node *getParent() { return parent; }
void dumpPaused() const;
Thread &getThread(unsigned num) { return thread[num]; }
const Thread &getThread(unsigned num) const { return thread[num]; }
void setCodeReference(const std::string &value) { codeReference = value; }
const std::string &getCodeReference() const { return codeReference; }
std::string getCoreName() const;
class port_iterator {
Core *core;
unsigned width;
unsigned num;
public:
port_iterator(Core *c, unsigned w, unsigned n) :
core(c), width(w), num(n) {}
const port_iterator &operator++() {
++num;
if (num >= core->portNum[width]) {
num = 0;
do {
++width;
} while (width != 33 && num >= core->portNum[width]);
}
return *this;
}
port_iterator operator++(int) {
port_iterator it(*this);
++(*this);
return it;
}
bool operator==(const port_iterator &other) {
return other.width == width &&
other.num == num;
}
bool operator!=(const port_iterator &other) {
return !(*this == other);
}
Port *operator*() {
return &core->port[width][num];
}
};
port_iterator port_begin() { return port_iterator(this, 1, 0); }
port_iterator port_end() { return port_iterator(this, 33, 0); }
};
#endif // _Core_h_