misc: Delete the now unnecessary create methods.
[gem5.git] / src / arch / arm / fastmodel / iris / thread_context.cc
1 /*
2 * Copyright (c) 2020 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright 2019 Google, Inc.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions are
18 * met: redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer;
20 * redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution;
23 * neither the name of the copyright holders nor the names of its
24 * contributors may be used to endorse or promote products derived from
25 * this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include "arch/arm/fastmodel/iris/thread_context.hh"
41
42 #include <utility>
43
44 #include "arch/arm/system.hh"
45 #include "arch/arm/utility.hh"
46 #include "iris/detail/IrisCppAdapter.h"
47 #include "iris/detail/IrisObjects.h"
48 #include "mem/se_translating_port_proxy.hh"
49 #include "mem/translating_port_proxy.hh"
50 #include "sim/pseudo_inst.hh"
51
52 namespace Iris
53 {
54
55 void
56 ThreadContext::initFromIrisInstance(const ResourceMap &resources)
57 {
58 bool enabled = false;
59 call().perInstanceExecution_getState(_instId, enabled);
60 _status = enabled ? Active : Suspended;
61
62 suspend();
63
64 call().memory_getMemorySpaces(_instId, memorySpaces);
65 call().memory_getUsefulAddressTranslations(_instId, translations);
66
67 typedef ThreadContext Self;
68 iris::EventSourceInfo evSrcInfo;
69
70 client.registerEventCallback<Self, &Self::breakpointHit>(
71 this, "ec_IRIS_BREAKPOINT_HIT",
72 "Handle hitting a breakpoint", "Iris::ThreadContext");
73 call().event_getEventSource(_instId, evSrcInfo, "IRIS_BREAKPOINT_HIT");
74 call().eventStream_create(_instId, breakpointEventStreamId,
75 evSrcInfo.evSrcId, client.getInstId());
76
77 for (auto it = bps.begin(); it != bps.end(); it++)
78 installBp(it);
79
80 client.registerEventCallback<Self, &Self::semihostingEvent>(
81 this, "ec_IRIS_SEMIHOSTING_CALL_EXTENSION",
82 "Handle a semihosting call", "Iris::ThreadContext");
83 call().event_getEventSource(_instId, evSrcInfo,
84 "IRIS_SEMIHOSTING_CALL_EXTENSION");
85 call().eventStream_create(_instId, semihostingEventStreamId,
86 evSrcInfo.evSrcId, client.getInstId(),
87 // Set all arguments to their defaults, except syncEc which is
88 // changed to true.
89 nullptr, "", false, 0, nullptr, false, false, true);
90 }
91
92 iris::ResourceId
93 ThreadContext::extractResourceId(
94 const ResourceMap &resources, const std::string &name)
95 {
96 return resources.at(name).rscId;
97 }
98
99 void
100 ThreadContext::extractResourceMap(
101 ResourceIds &ids, const ResourceMap &resources,
102 const IdxNameMap &idx_names)
103 {
104 for (const auto &idx_name: idx_names) {
105 int idx = idx_name.first;
106 const std::string &name = idx_name.second;
107
108 if (idx >= ids.size())
109 ids.resize(idx + 1, iris::IRIS_UINT64_MAX);
110
111 ids[idx] = extractResourceId(resources, name);
112 }
113 }
114
115 void
116 ThreadContext::maintainStepping()
117 {
118 Tick now = 0;
119
120 while (true) {
121 if (comInstEventQueue.empty()) {
122 // Set to 0 to deactivate stepping.
123 call().step_setup(_instId, 0, "instruction");
124 break;
125 }
126
127 Tick next = comInstEventQueue.nextTick();
128 if (!now)
129 now = getCurrentInstCount();
130
131 if (next <= now) {
132 comInstEventQueue.serviceEvents(now);
133 // Start over now that comInstEventQueue has likely changed.
134 continue;
135 }
136
137 // Set to the number of instructions still to step through.
138 Tick remaining = next - now;
139 call().step_setup(_instId, remaining, "instruction");
140 break;
141 }
142 }
143
144 ThreadContext::BpInfoIt
145 ThreadContext::getOrAllocBp(Addr pc)
146 {
147 auto pc_it = bps.find(pc);
148
149 if (pc_it != bps.end())
150 return pc_it;
151
152 auto res = bps.emplace(std::make_pair(pc, new BpInfo(pc)));
153 panic_if(!res.second, "Inserting breakpoint failed.");
154 return res.first;
155 }
156
157 void
158 ThreadContext::installBp(BpInfoIt it)
159 {
160 Addr pc = it->second->pc;
161 const auto &space_ids = getBpSpaceIds();
162 for (auto sid: space_ids) {
163 BpId id;
164 call().breakpoint_set_code(_instId, id, pc, sid, 0, true);
165 it->second->ids.push_back(id);
166 }
167 }
168
169 void
170 ThreadContext::uninstallBp(BpInfoIt it)
171 {
172 for (auto id: it->second->ids)
173 call().breakpoint_delete(_instId, id);
174 it->second->clearIds();
175 }
176
177 void
178 ThreadContext::delBp(BpInfoIt it)
179 {
180 panic_if(!it->second->empty(),
181 "BP info still had events associated with it.");
182
183 if (it->second->validIds())
184 uninstallBp(it);
185
186 bps.erase(it);
187 }
188
189 iris::IrisErrorCode
190 ThreadContext::instanceRegistryChanged(
191 uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
192 uint64_t sInstId, bool syncEc, std::string &error_message_out)
193 {
194 const std::string &event = fields.at("EVENT").getString();
195 const iris::InstanceId id = fields.at("INST_ID").getU64();
196 const std::string &name = fields.at("INST_NAME").getString();
197
198 if (name != "component." + _irisPath)
199 return iris::E_ok;
200
201 if (event == "added")
202 _instId = id;
203 else if (event == "removed")
204 _instId = iris::IRIS_UINT64_MAX;
205 else
206 panic("Unrecognized event type %s", event);
207
208 return iris::E_ok;
209 }
210
211 iris::IrisErrorCode
212 ThreadContext::phaseInitLeave(
213 uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
214 uint64_t sInstId, bool syncEc, std::string &error_message_out)
215 {
216 std::vector<iris::ResourceInfo> resources;
217 call().resource_getList(_instId, resources);
218
219 std::map<iris::ResourceId, const iris::ResourceInfo *>
220 idToResource;
221 for (const auto &resource: resources) {
222 idToResource[resource.rscId] = &resource;
223 }
224 ResourceMap resourceMap;
225 for (const auto &resource: resources) {
226 std::string name = resource.name;
227 iris::ResourceId parentId = resource.parentRscId;
228 while (parentId != iris::IRIS_UINT64_MAX) {
229 const auto *parent = idToResource[parentId];
230 name = parent->name + "." + name;
231 parentId = parent->parentRscId;
232 }
233 resourceMap[name] = resource;
234 }
235
236 initFromIrisInstance(resourceMap);
237
238 return iris::E_ok;
239 }
240
241 iris::IrisErrorCode
242 ThreadContext::simulationTimeEvent(
243 uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
244 uint64_t sInstId, bool syncEc, std::string &error_message_out)
245 {
246 if (fields.at("RUNNING").getAsBool()) {
247 // If this is just simulation time starting up, don't do anything.
248 return iris::E_ok;
249 }
250
251 // If simulation time has stopped for any reason, IRIS helpfully clears
252 // all stepping counters and we need to set them back. We might also need
253 // to service events based on the current number of executed instructions.
254 maintainStepping();
255
256 // Restart simulation time to make sure things progress once we give
257 // control back.
258 call().simulationTime_run(iris::IrisInstIdSimulationEngine);
259
260 return iris::E_ok;
261 }
262
263 iris::IrisErrorCode
264 ThreadContext::breakpointHit(
265 uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
266 uint64_t sInstId, bool syncEc, std::string &error_message_out)
267 {
268 Addr pc = fields.at("PC").getU64();
269
270 auto it = getOrAllocBp(pc);
271
272 std::shared_ptr<BpInfo::EventList> events = it->second->events;
273 auto e_it = events->begin();
274 while (e_it != events->end()) {
275 PCEvent *e = *e_it;
276 // Advance e_it here since e might remove itself from the list.
277 e_it++;
278 e->process(this);
279 }
280
281 return iris::E_ok;
282 }
283
284 iris::IrisErrorCode
285 ThreadContext::semihostingEvent(
286 uint64_t esId, const iris::IrisValueMap &fields, uint64_t time,
287 uint64_t sInstId, bool syncEc, std::string &error_message_out)
288 {
289 if (ArmSystem::callSemihosting(this, true)) {
290 // Stop execution in case an exit of the sim loop was scheduled. We
291 // don't want to keep executing instructions in the mean time.
292 call().perInstanceExecution_setState(_instId, false);
293
294 // Schedule an event to resume execution right after any exit has
295 // had a chance to happen.
296 if (!enableAfterPseudoEvent->scheduled())
297 getCpuPtr()->schedule(enableAfterPseudoEvent, curTick());
298
299 call().semihosting_return(_instId, readIntReg(0));
300 } else {
301 call().semihosting_notImplemented(_instId);
302 }
303 return iris::E_ok;
304 }
305
306 ThreadContext::ThreadContext(
307 BaseCPU *cpu, int id, System *system, ::BaseMMU *mmu,
308 BaseISA *isa, iris::IrisConnectionInterface *iris_if,
309 const std::string &iris_path) :
310 _cpu(cpu), _threadId(id), _system(system), _mmu(mmu), _isa(isa),
311 _irisPath(iris_path), vecRegs(ArmISA::NumVecRegs),
312 vecPredRegs(ArmISA::NumVecPredRegs),
313 comInstEventQueue("instruction-based event queue"),
314 client(iris_if, "client." + iris_path)
315 {
316 iris::InstanceInfo info;
317 auto ret_code = noThrow().instanceRegistry_getInstanceInfoByName(
318 info, "component." + iris_path);
319 if (ret_code == iris::E_ok) {
320 // The iris instance registry already new about this path.
321 _instId = info.instId;
322 } else {
323 // This path doesn't (yet) exist. Set the ID to something invalid.
324 _instId = iris::IRIS_UINT64_MAX;
325 }
326
327 typedef ThreadContext Self;
328 iris::EventSourceInfo evSrcInfo;
329
330 client.registerEventCallback<Self, &Self::instanceRegistryChanged>(
331 this, "ec_IRIS_INSTANCE_REGISTRY_CHANGED",
332 "Install the iris instance ID", "Iris::ThreadContext");
333 call().event_getEventSource(iris::IrisInstIdGlobalInstance, evSrcInfo,
334 "IRIS_INSTANCE_REGISTRY_CHANGED");
335 regEventStreamId = iris::IRIS_UINT64_MAX;
336 static const std::vector<std::string> fields =
337 { "EVENT", "INST_ID", "INST_NAME" };
338 call().eventStream_create(iris::IrisInstIdGlobalInstance, regEventStreamId,
339 evSrcInfo.evSrcId, client.getInstId(), &fields);
340
341 client.registerEventCallback<Self, &Self::phaseInitLeave>(
342 this, "ec_IRIS_SIM_PHASE_INIT_LEAVE",
343 "Initialize register contexts", "Iris::ThreadContext");
344 call().event_getEventSource(iris::IrisInstIdSimulationEngine, evSrcInfo,
345 "IRIS_SIM_PHASE_INIT_LEAVE");
346 initEventStreamId = iris::IRIS_UINT64_MAX;
347 call().eventStream_create(
348 iris::IrisInstIdSimulationEngine, initEventStreamId,
349 evSrcInfo.evSrcId, client.getInstId());
350
351 client.registerEventCallback<Self, &Self::simulationTimeEvent>(
352 this, "ec_IRIS_SIMULATION_TIME_EVENT",
353 "Handle simulation time stopping for breakpoints or stepping",
354 "Iris::ThreadContext");
355 call().event_getEventSource(iris::IrisInstIdSimulationEngine, evSrcInfo,
356 "IRIS_SIMULATION_TIME_EVENT");
357 timeEventStreamId = iris::IRIS_UINT64_MAX;
358 call().eventStream_create(
359 iris::IrisInstIdSimulationEngine, timeEventStreamId,
360 evSrcInfo.evSrcId, client.getInstId());
361
362 breakpointEventStreamId = iris::IRIS_UINT64_MAX;
363 semihostingEventStreamId = iris::IRIS_UINT64_MAX;
364
365 auto enable_lambda = [this]{
366 call().perInstanceExecution_setState(_instId, true);
367 };
368 enableAfterPseudoEvent = new EventFunctionWrapper(
369 enable_lambda, "resume after pseudo inst",
370 false, Event::Sim_Exit_Pri + 1);
371 }
372
373 ThreadContext::~ThreadContext()
374 {
375 call().eventStream_destroy(
376 iris::IrisInstIdSimulationEngine, initEventStreamId);
377 initEventStreamId = iris::IRIS_UINT64_MAX;
378 client.unregisterEventCallback("ec_IRIS_SIM_PHASE_INIT_LEAVE");
379
380 call().eventStream_destroy(
381 iris::IrisInstIdGlobalInstance, regEventStreamId);
382 regEventStreamId = iris::IRIS_UINT64_MAX;
383 client.unregisterEventCallback("ec_IRIS_INSTANCE_REGISTRY_CHANGED");
384
385 call().eventStream_destroy(
386 iris::IrisInstIdGlobalInstance, timeEventStreamId);
387 timeEventStreamId = iris::IRIS_UINT64_MAX;
388 client.unregisterEventCallback("ec_IRIS_SIMULATION_TIME_EVENT");
389
390 if (enableAfterPseudoEvent->scheduled())
391 getCpuPtr()->deschedule(enableAfterPseudoEvent);
392 delete enableAfterPseudoEvent;
393 }
394
395 bool
396 ThreadContext::schedule(PCEvent *e)
397 {
398 auto it = getOrAllocBp(e->pc());
399 it->second->events->push_back(e);
400
401 if (_instId != iris::IRIS_UINT64_MAX && !it->second->validIds())
402 installBp(it);
403
404 return true;
405 }
406
407 bool
408 ThreadContext::remove(PCEvent *e)
409 {
410 auto it = getOrAllocBp(e->pc());
411 it->second->events->remove(e);
412
413 if (it->second->empty())
414 delBp(it);
415
416 return true;
417 }
418
419 bool
420 ThreadContext::translateAddress(Addr &paddr, iris::MemorySpaceId p_space,
421 Addr vaddr, iris::MemorySpaceId v_space)
422 {
423 iris::MemoryAddressTranslationResult result;
424 auto ret = noThrow().memory_translateAddress(
425 _instId, result, v_space, vaddr, p_space);
426
427 if (ret != iris::E_ok) {
428 // Check if there was a legal translation between these two spaces.
429 // If so, something else went wrong.
430 for (auto &trans: translations)
431 if (trans.inSpaceId == v_space && trans.outSpaceId == p_space)
432 return false;
433
434 panic("No legal translation IRIS address translation found.");
435 }
436
437 if (result.address.empty())
438 return false;
439
440 if (result.address.size() > 1) {
441 warn("Multiple mappings for address %#x.", vaddr);
442 return false;
443 }
444
445 paddr = result.address[0];
446 return true;
447 }
448
449 void
450 ThreadContext::scheduleInstCountEvent(Event *event, Tick count)
451 {
452 Tick now = getCurrentInstCount();
453 comInstEventQueue.schedule(event, count);
454 if (count <= now)
455 call().simulationTime_stop(iris::IrisInstIdSimulationEngine);
456 else
457 maintainStepping();
458 }
459
460 void
461 ThreadContext::descheduleInstCountEvent(Event *event)
462 {
463 comInstEventQueue.deschedule(event);
464 maintainStepping();
465 }
466
467 Tick
468 ThreadContext::getCurrentInstCount()
469 {
470 uint64_t count;
471 auto ret = call().step_getStepCounterValue(_instId, count, "instruction");
472 panic_if(ret != iris::E_ok, "Failed to get instruction count.");
473 return count;
474 }
475
476 void
477 ThreadContext::initMemProxies(::ThreadContext *tc)
478 {
479 if (FullSystem) {
480 assert(!physProxy && !virtProxy);
481 physProxy.reset(new PortProxy(_cpu->getSendFunctional(),
482 _cpu->cacheLineSize()));
483 virtProxy.reset(new TranslatingPortProxy(tc));
484 } else {
485 assert(!virtProxy);
486 virtProxy.reset(new SETranslatingPortProxy(this,
487 SETranslatingPortProxy::NextPage));
488 }
489 }
490
491 ThreadContext::Status
492 ThreadContext::status() const
493 {
494 return _status;
495 }
496
497 void
498 ThreadContext::setStatus(Status new_status)
499 {
500 if (enableAfterPseudoEvent->scheduled())
501 getCpuPtr()->deschedule(enableAfterPseudoEvent);
502 if (new_status == Active) {
503 if (_status != Active)
504 call().perInstanceExecution_setState(_instId, true);
505 } else {
506 if (_status == Active)
507 call().perInstanceExecution_setState(_instId, false);
508 }
509 _status = new_status;
510 }
511
512 ArmISA::PCState
513 ThreadContext::pcState() const
514 {
515 ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
516 ArmISA::PCState pc;
517
518 pc.thumb(cpsr.t);
519 pc.nextThumb(pc.thumb());
520 pc.jazelle(cpsr.j);
521 pc.nextJazelle(cpsr.j);
522 pc.aarch64(!cpsr.width);
523 pc.nextAArch64(!cpsr.width);
524 pc.illegalExec(false);
525 pc.itstate(ArmISA::itState(cpsr));
526 pc.nextItstate(0);
527
528 iris::ResourceReadResult result;
529 call().resource_read(_instId, result, pcRscId);
530 Addr addr = result.data.at(0);
531 if (cpsr.width && cpsr.t)
532 addr = addr & ~0x1;
533 pc.set(addr);
534
535 return pc;
536 }
537 void
538 ThreadContext::pcState(const ArmISA::PCState &val)
539 {
540 Addr pc = val.pc();
541
542 ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
543 if (cpsr.width && cpsr.t)
544 pc = pc | 0x1;
545
546 iris::ResourceWriteResult result;
547 call().resource_write(_instId, result, pcRscId, pc);
548 }
549
550 Addr
551 ThreadContext::instAddr() const
552 {
553 return pcState().instAddr();
554 }
555
556 Addr
557 ThreadContext::nextInstAddr() const
558 {
559 return pcState().nextInstAddr();
560 }
561
562 RegVal
563 ThreadContext::readMiscRegNoEffect(RegIndex misc_reg) const
564 {
565 iris::ResourceReadResult result;
566 call().resource_read(_instId, result, miscRegIds.at(misc_reg));
567 return result.data.at(0);
568 }
569
570 void
571 ThreadContext::setMiscRegNoEffect(RegIndex misc_reg, const RegVal val)
572 {
573 iris::ResourceWriteResult result;
574 call().resource_write(_instId, result, miscRegIds.at(misc_reg), val);
575 }
576
577 RegVal
578 ThreadContext::readIntReg(RegIndex reg_idx) const
579 {
580 ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
581
582 iris::ResourceReadResult result;
583 if (cpsr.width)
584 call().resource_read(_instId, result, intReg32Ids.at(reg_idx));
585 else
586 call().resource_read(_instId, result, intReg64Ids.at(reg_idx));
587 return result.data.at(0);
588 }
589
590 void
591 ThreadContext::setIntReg(RegIndex reg_idx, RegVal val)
592 {
593 ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
594
595 iris::ResourceWriteResult result;
596 if (cpsr.width)
597 call().resource_write(_instId, result, intReg32Ids.at(reg_idx), val);
598 else
599 call().resource_write(_instId, result, intReg64Ids.at(reg_idx), val);
600 }
601
602 /*
603 * The 64 bit version of registers gives us a pre-flattened view of the reg
604 * file, no matter what mode we're in or if we're currently 32 or 64 bit.
605 */
606 RegVal
607 ThreadContext::readIntRegFlat(RegIndex idx) const
608 {
609 if (idx >= flattenedIntIds.size())
610 return 0;
611 iris::ResourceId res_id = flattenedIntIds.at(idx);
612 if (res_id == iris::IRIS_UINT64_MAX)
613 return 0;
614 iris::ResourceReadResult result;
615 call().resource_read(_instId, result, res_id);
616 return result.data.at(0);
617 }
618
619 void
620 ThreadContext::setIntRegFlat(RegIndex idx, uint64_t val)
621 {
622 iris::ResourceId res_id =
623 (idx >= flattenedIntIds.size()) ? iris::IRIS_UINT64_MAX :
624 flattenedIntIds.at(idx);
625 panic_if(res_id == iris::IRIS_UINT64_MAX,
626 "Int reg %d is not supported by fast model.", idx);
627 iris::ResourceWriteResult result;
628 call().resource_write(_instId, result, flattenedIntIds.at(idx), val);
629 }
630
631 RegVal
632 ThreadContext::readCCRegFlat(RegIndex idx) const
633 {
634 if (idx >= ccRegIds.size())
635 return 0;
636 iris::ResourceReadResult result;
637 call().resource_read(_instId, result, ccRegIds.at(idx));
638 return result.data.at(0);
639 }
640
641 void
642 ThreadContext::setCCRegFlat(RegIndex idx, RegVal val)
643 {
644 panic_if(idx >= ccRegIds.size(),
645 "CC reg %d is not supported by fast model.", idx);
646 iris::ResourceWriteResult result;
647 call().resource_write(_instId, result, ccRegIds.at(idx), val);
648 }
649
650 const ArmISA::VecRegContainer &
651 ThreadContext::readVecReg(const RegId &reg_id) const
652 {
653 const RegIndex idx = reg_id.index();
654 ArmISA::VecRegContainer &reg = vecRegs.at(idx);
655 reg.zero();
656
657 // Ignore accesses to registers which aren't architected. gem5 defines a
658 // few extra registers which it uses internally in the implementation of
659 // some instructions.
660 if (idx >= vecRegIds.size())
661 return reg;
662
663 iris::ResourceReadResult result;
664 call().resource_read(_instId, result, vecRegIds.at(idx));
665 size_t data_size = result.data.size() * (sizeof(*result.data.data()));
666 size_t size = std::min(data_size, reg.size());
667 memcpy(reg.raw_ptr<void>(), (void *)result.data.data(), size);
668
669 return reg;
670 }
671
672 const ArmISA::VecRegContainer &
673 ThreadContext::readVecRegFlat(RegIndex idx) const
674 {
675 return readVecReg(RegId(VecRegClass, idx));
676 }
677
678 const ArmISA::VecPredRegContainer &
679 ThreadContext::readVecPredReg(const RegId &reg_id) const
680 {
681 RegIndex idx = reg_id.index();
682
683 ArmISA::VecPredRegContainer &reg = vecPredRegs.at(idx);
684 reg.reset();
685
686 if (idx >= vecPredRegIds.size())
687 return reg;
688
689 iris::ResourceReadResult result;
690 call().resource_read(_instId, result, vecPredRegIds.at(idx));
691
692 size_t offset = 0;
693 size_t num_bits = reg.NUM_BITS;
694 uint8_t *bytes = (uint8_t *)result.data.data();
695 while (num_bits > 8) {
696 reg.set_bits(offset, 8, *bytes);
697 offset += 8;
698 num_bits -= 8;
699 bytes++;
700 }
701 if (num_bits)
702 reg.set_bits(offset, num_bits, *bytes);
703
704 return reg;
705 }
706
707 const ArmISA::VecPredRegContainer &
708 ThreadContext::readVecPredRegFlat(RegIndex idx) const
709 {
710 return readVecPredReg(RegId(VecPredRegClass, idx));
711 }
712
713 } // namespace Iris