generated from riscv-software-src/template-riscv-code
-
Notifications
You must be signed in to change notification settings - Fork 67
/
Copy pathInst.hpp
350 lines (306 loc) · 13.7 KB
/
Inst.hpp
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
// <Inst.h> -*- C++ -*-
#pragma once
#include "sparta/memory/AddressTypes.hpp"
#include "sparta/resources/Scoreboard.hpp"
#include "sparta/resources/Queue.hpp"
#include "sparta/pairs/SpartaKeyPairs.hpp"
#include "sparta/simulation/State.hpp"
#include "sparta/utils/SpartaSharedPointer.hpp"
#include "sparta/utils/SpartaSharedPointerAllocator.hpp"
#include "mavis/OpcodeInfo.h"
#include "stf-inc/stf_inst_reader.hpp"
#include "InstArchInfo.hpp"
#include "CoreTypes.hpp"
#include "MiscUtils.hpp"
#include <cstdlib>
#include <ostream>
#include <map>
#include <variant>
namespace olympia
{
/*!
* \class Inst
* \brief Example instruction that flows through the example/CoreModel
*/
// Forward declaration of the Pair Definition class is must as we are friending it.
class InstPairDef;
class Inst {
public:
class RenameData
{
public:
// A register consists of its value and its register file.
struct Reg {
uint32_t val = 0;
core_types::RegFile rf = core_types::RegFile::RF_INVALID;
mavis::InstMetaData::OperandFieldID field_id = mavis::InstMetaData::OperandFieldID::NONE;
bool is_x0 = false;
};
using RegList = std::vector<Reg>;
void setOriginalDestination(const Reg & destination){
original_dest_ = destination;
}
void setDestination(const Reg & destination){
dest_ = destination;
}
void setDataReg(const Reg & data_reg){
data_reg_ = data_reg;
}
void setSource(const Reg & source){
src_.emplace_back(source);
}
const RegList & getSourceList() const {
return src_;
}
const Reg & getOriginalDestination() const {
return original_dest_;
}
const Reg & getDestination() const {
return dest_;
}
const Reg & getDataReg() const {
return data_reg_;
}
private:
Reg original_dest_;
Reg dest_;
RegList src_;
Reg data_reg_;
};
// Used by Mavis
using PtrType = sparta::SpartaSharedPointer<Inst>;
// The modeler needs to alias a type called
// "SpartaPairDefinitionType" to the Pair Definition class of
// itself
using SpartaPairDefinitionType = InstPairDef;
enum class Status : std::uint16_t{
FETCHED = 0,
__FIRST = FETCHED,
DECODED,
RENAMED,
DISPATCHED,
SCHEDULED,
COMPLETED,
RETIRED,
FLUSHED,
__LAST
};
/*!
* \brief Construct an Instruction
* \param opcode_info Mavis Opcode information
* \param inst_arch_info Pointer to the static data of instruction
* \param clk Core clock
*
* Called by Mavis when an opcode is decoded to a particular
* instruction.
*/
Inst(const mavis::OpcodeInfo::PtrType& opcode_info,
const InstArchInfo::PtrType & inst_arch_info,
const sparta::Clock * clk);
// This is needed by Mavis as an optimization. Try NOT to
// implement it and let the compiler do it for us for speed.
Inst(const Inst& other) = default;
const Status & getStatus() const {
return status_state_;
}
bool getCompletedStatus() const {
return getStatus() == olympia::Inst::Status::COMPLETED;
}
bool getFlushedStatus() const {
return getStatus() == olympia::Inst::Status::FLUSHED;
}
void setStatus(Status status) {
sparta_assert(status_state_ != status,
"Status being set twice to the same value: "
<< status << " " << *this);
sparta_assert(status > status_state_,
"Cannot go backwards in status. Current: "
<< status_state_ << " New: " << status << *this);
status_state_ = status;
if(getStatus() == Status::COMPLETED) {
if(ev_retire_ != 0) {
ev_retire_->schedule();
}
}
}
InstArchInfo::TargetUnit getUnit() const {
return inst_arch_info_->getTargetUnit();
}
InstArchInfo::TargetPipe getPipe() const {
return inst_arch_info_->getTargetPipe();
}
// ROB handling -- mark this instruction as the oldest in the machine
void setOldest(bool oldest, sparta::Scheduleable * rob_retire_event) {
ev_retire_ = rob_retire_event;
is_oldest_ = oldest;
}
bool isMarkedOldest() const { return is_oldest_; }
// Rewind iterator used for going back in program simulation after flushes
template<typename T>
void setRewindIterator(T iter) { rewind_iter_ = iter; }
template<typename T>
T getRewindIterator() const { return std::get<T>(rewind_iter_); }
// Set the instructions unique ID. This ID in constantly
// incremented and does not repeat. The same instruction in a
// trace can have different unique IDs (due to flushing)
void setUniqueID(uint64_t uid) { unique_id_ = uid; }
uint64_t getUniqueID() const { return unique_id_; }
// Set the instruction's Program ID. This ID is specific to
// an instruction's retire pointer. The same instruction in a
// trace will have the same program ID (as compared to
// UniqueID).
void setProgramID(uint64_t prog_id) { program_id_ = prog_id; }
uint64_t getProgramID() const { return program_id_; }
// Set the instruction's PC
void setPC(sparta::memory::addr_t inst_pc) { inst_pc_ = inst_pc; }
sparta::memory::addr_t getPC() const { return inst_pc_; }
// Set the instruction's target PC (branch target or load/store target)
void setTargetVAddr(sparta::memory::addr_t target_vaddr) { target_vaddr_ = target_vaddr; }
sparta::memory::addr_t getTargetVAddr() const { return target_vaddr_; }
// Branch instruction was taken (always set for JAL/JALR)
void setTakenBranch(bool taken) { is_taken_branch_ = taken; }
// TBD -- add branch prediction
void setSpeculative(bool spec) { is_speculative_ = spec; }
// Opcode information
std::string getMnemonic() const { return opcode_info_->getMnemonic(); }
std::string getDisasm() const { return opcode_info_->dasmString(); }
uint32_t getOpCode() const { return static_cast<uint32_t>(opcode_info_->getOpcode()); }
// Operand information
using OpInfoList = mavis::DecodedInstructionInfo::OpInfoList;
const OpInfoList& getSourceOpInfoList() const { return opcode_info_->getSourceOpInfoList(); }
const OpInfoList& getDestOpInfoList() const { return opcode_info_->getDestOpInfoList(); }
// Static instruction information
bool isStoreInst() const { return is_store_; }
bool isLoadStoreInst() const {return inst_arch_info_->isLoadStore(); }
uint32_t getExecuteTime() const { return inst_arch_info_->getExecutionTime(); }
uint64_t getRAdr() const { return target_vaddr_ | 0x8000000; } // faked
bool isSpeculative() const { return is_speculative_; }
bool isTransfer() const { return is_transfer_; }
bool isTakenBranch() const { return is_taken_branch_; }
bool isBranch() const { return is_branch_; }
bool isCondBranch() const { return is_condbranch_; }
bool isCall() const { return is_call_; }
bool isReturn() const { return is_return_; }
// Rename information
core_types::RegisterBitMask & getSrcRegisterBitMask(const core_types::RegFile rf) {
return src_reg_bit_masks_[rf];
}
core_types::RegisterBitMask & getDestRegisterBitMask(const core_types::RegFile rf) {
return dest_reg_bit_masks_[rf];
}
core_types::RegisterBitMask & getDataRegisterBitMask(const core_types::RegFile rf) {
return store_data_mask_[rf];
}
const core_types::RegisterBitMask & getSrcRegisterBitMask(const core_types::RegFile rf) const {
return src_reg_bit_masks_[rf];
}
const core_types::RegisterBitMask & getDestRegisterBitMask(const core_types::RegFile rf) const {
return dest_reg_bit_masks_[rf];
}
const core_types::RegisterBitMask & getDataRegisterBitMask(const core_types::RegFile rf) const {
return store_data_mask_[rf];
}
RenameData & getRenameData() {
return rename_data;
}
const RenameData & getRenameData() const{
return rename_data;
}
private:
mavis::OpcodeInfo::PtrType opcode_info_;
InstArchInfo::PtrType inst_arch_info_;
sparta::memory::addr_t inst_pc_ = 0; // Instruction's PC
sparta::memory::addr_t target_vaddr_ = 0; // Instruction's Target PC (for branches, loads/stores)
bool is_oldest_ = false;
uint64_t unique_id_ = 0; // Supplied by Fetch
uint64_t program_id_ = 0; // Supplied by a trace Reader or execution backend
bool is_speculative_ = false; // Is this instruction soon to be flushed?
const bool is_store_;
const bool is_transfer_; // Is this a transfer instruction (F2I/I2F)
const bool is_branch_;
const bool is_condbranch_;
const bool is_call_;
const bool is_return_;
bool is_taken_branch_ = false;
sparta::Scheduleable * ev_retire_ = nullptr;
Status status_state_;
using JSONIterator = uint64_t;
using RewindIterator = std::variant<stf::STFInstReader::iterator, JSONIterator>;
RewindIterator rewind_iter_;
// Rename information
using RegisterBitMaskArray = std::array<core_types::RegisterBitMask, core_types::RegFile::N_REGFILES>;
RegisterBitMaskArray src_reg_bit_masks_;
RegisterBitMaskArray dest_reg_bit_masks_;
RegisterBitMaskArray store_data_mask_;
RenameData rename_data;
};
using InstPtr = Inst::PtrType;
using InstQueue = sparta::Queue<InstPtr>;
inline std::ostream & operator<<(std::ostream & os, const Inst::Status & status) {
switch(status) {
case Inst::Status::FETCHED:
os << "FETCHED";
break;
case Inst::Status::DECODED:
os << "DECODED";
break;
case Inst::Status::RENAMED:
os << "RENAMED";
break;
case Inst::Status::DISPATCHED:
os << "DISPATCHED";
break;
case Inst::Status::SCHEDULED:
os << "SCHEDULED";
break;
case Inst::Status::COMPLETED:
os << "COMPLETED";
break;
case Inst::Status::RETIRED:
os << "RETIRED";
break;
case Inst::Status::FLUSHED:
os << "FLUSHED";
break;
case Inst::Status::__LAST:
throw sparta::SpartaException("__LAST cannot be a valid enum state.");
}
return os;
}
inline std::ostream & operator<<(std::ostream & os, const Inst & inst) {
os << "uid: " << inst.getUniqueID()
<< " " << std::setw(10) << inst.getStatus()
<< " " << std::hex << inst.getPC() << std::dec
<< " pid: " << inst.getProgramID() << " '" << inst.getDisasm() << "' ";
return os;
}
inline std::ostream & operator<<(std::ostream & os, const InstPtr & inst) {
os << *inst;
return os;
}
/*!
* \class InstPairDef
* \brief Pair Definition class of the Example instruction that flows through the example/CoreModel
*/
// This is the definition of the PairDefinition class of Inst.
// This PairDefinition class could be named anything but it needs to
// inherit publicly from sparta::PairDefinition templatized on the actual class Inst.
class InstPairDef : public sparta::PairDefinition<Inst>{
public:
// The SPARTA_ADDPAIRs APIs must be called during the construction of the PairDefinition class
InstPairDef() : PairDefinition<Inst>(){
SPARTA_INVOKE_PAIRS(Inst);
}
SPARTA_REGISTER_PAIRS(SPARTA_ADDPAIR("DID", &Inst::getUniqueID),
SPARTA_ADDPAIR("uid", &Inst::getUniqueID),
SPARTA_ADDPAIR("mnemonic", &Inst::getMnemonic),
SPARTA_ADDPAIR("complete", &Inst::getCompletedStatus),
SPARTA_ADDPAIR("unit", &Inst::getUnit),
SPARTA_ADDPAIR("latency", &Inst::getExecuteTime),
SPARTA_ADDPAIR("raddr", &Inst::getRAdr, std::ios::hex),
SPARTA_ADDPAIR("tgt_vaddr", &Inst::getTargetVAddr, std::ios::hex))
};
// Instruction allocators
using InstAllocator = sparta::SpartaSharedPointerAllocator<Inst>;
using InstArchInfoAllocator = sparta::SpartaSharedPointerAllocator<InstArchInfo>;
}