fastmodel: Fix hierachical Iris component names.
[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, ::BaseTLB *dtb, ::BaseTLB *itb,
308 iris::IrisConnectionInterface *iris_if, const std::string &iris_path) :
309 _cpu(cpu), _threadId(id), _system(system), _dtb(dtb), _itb(itb),
310 _irisPath(iris_path), vecRegs(ArmISA::NumVecRegs),
311 vecPredRegs(ArmISA::NumVecPredRegs),
312 comInstEventQueue("instruction-based event queue"),
313 client(iris_if, "client." + iris_path)
314 {
315 iris::InstanceInfo info;
316 auto ret_code = noThrow().instanceRegistry_getInstanceInfoByName(
317 info, "component." + iris_path);
318 if (ret_code == iris::E_ok) {
319 // The iris instance registry already new about this path.
320 _instId = info.instId;
321 } else {
322 // This path doesn't (yet) exist. Set the ID to something invalid.
323 _instId = iris::IRIS_UINT64_MAX;
324 }
325
326 typedef ThreadContext Self;
327 iris::EventSourceInfo evSrcInfo;
328
329 client.registerEventCallback<Self, &Self::instanceRegistryChanged>(
330 this, "ec_IRIS_INSTANCE_REGISTRY_CHANGED",
331 "Install the iris instance ID", "Iris::ThreadContext");
332 call().event_getEventSource(iris::IrisInstIdGlobalInstance, evSrcInfo,
333 "IRIS_INSTANCE_REGISTRY_CHANGED");
334 regEventStreamId = iris::IRIS_UINT64_MAX;
335 static const std::vector<std::string> fields =
336 { "EVENT", "INST_ID", "INST_NAME" };
337 call().eventStream_create(iris::IrisInstIdGlobalInstance, regEventStreamId,
338 evSrcInfo.evSrcId, client.getInstId(), &fields);
339
340 client.registerEventCallback<Self, &Self::phaseInitLeave>(
341 this, "ec_IRIS_SIM_PHASE_INIT_LEAVE",
342 "Initialize register contexts", "Iris::ThreadContext");
343 call().event_getEventSource(iris::IrisInstIdSimulationEngine, evSrcInfo,
344 "IRIS_SIM_PHASE_INIT_LEAVE");
345 initEventStreamId = iris::IRIS_UINT64_MAX;
346 call().eventStream_create(
347 iris::IrisInstIdSimulationEngine, initEventStreamId,
348 evSrcInfo.evSrcId, client.getInstId());
349
350 client.registerEventCallback<Self, &Self::simulationTimeEvent>(
351 this, "ec_IRIS_SIMULATION_TIME_EVENT",
352 "Handle simulation time stopping for breakpoints or stepping",
353 "Iris::ThreadContext");
354 call().event_getEventSource(iris::IrisInstIdSimulationEngine, evSrcInfo,
355 "IRIS_SIMULATION_TIME_EVENT");
356 timeEventStreamId = iris::IRIS_UINT64_MAX;
357 call().eventStream_create(
358 iris::IrisInstIdSimulationEngine, timeEventStreamId,
359 evSrcInfo.evSrcId, client.getInstId());
360
361 breakpointEventStreamId = iris::IRIS_UINT64_MAX;
362 semihostingEventStreamId = iris::IRIS_UINT64_MAX;
363
364 auto enable_lambda = [this]{
365 call().perInstanceExecution_setState(_instId, true);
366 };
367 enableAfterPseudoEvent = new EventFunctionWrapper(
368 enable_lambda, "resume after pseudo inst",
369 false, Event::Sim_Exit_Pri + 1);
370 }
371
372 ThreadContext::~ThreadContext()
373 {
374 call().eventStream_destroy(
375 iris::IrisInstIdSimulationEngine, initEventStreamId);
376 initEventStreamId = iris::IRIS_UINT64_MAX;
377 client.unregisterEventCallback("ec_IRIS_SIM_PHASE_INIT_LEAVE");
378
379 call().eventStream_destroy(
380 iris::IrisInstIdGlobalInstance, regEventStreamId);
381 regEventStreamId = iris::IRIS_UINT64_MAX;
382 client.unregisterEventCallback("ec_IRIS_INSTANCE_REGISTRY_CHANGED");
383
384 call().eventStream_destroy(
385 iris::IrisInstIdGlobalInstance, timeEventStreamId);
386 timeEventStreamId = iris::IRIS_UINT64_MAX;
387 client.unregisterEventCallback("ec_IRIS_SIMULATION_TIME_EVENT");
388
389 if (enableAfterPseudoEvent->scheduled())
390 getCpuPtr()->deschedule(enableAfterPseudoEvent);
391 delete enableAfterPseudoEvent;
392 }
393
394 bool
395 ThreadContext::schedule(PCEvent *e)
396 {
397 auto it = getOrAllocBp(e->pc());
398 it->second->events->push_back(e);
399
400 if (_instId != iris::IRIS_UINT64_MAX && !it->second->validIds())
401 installBp(it);
402
403 return true;
404 }
405
406 bool
407 ThreadContext::remove(PCEvent *e)
408 {
409 auto it = getOrAllocBp(e->pc());
410 it->second->events->remove(e);
411
412 if (it->second->empty())
413 delBp(it);
414
415 return true;
416 }
417
418 bool
419 ThreadContext::translateAddress(Addr &paddr, iris::MemorySpaceId p_space,
420 Addr vaddr, iris::MemorySpaceId v_space)
421 {
422 iris::MemoryAddressTranslationResult result;
423 auto ret = noThrow().memory_translateAddress(
424 _instId, result, v_space, vaddr, p_space);
425
426 if (ret != iris::E_ok) {
427 // Check if there was a legal translation between these two spaces.
428 // If so, something else went wrong.
429 for (auto &trans: translations)
430 if (trans.inSpaceId == v_space && trans.outSpaceId == p_space)
431 return false;
432
433 panic("No legal translation IRIS address translation found.");
434 }
435
436 if (result.address.empty())
437 return false;
438
439 if (result.address.size() > 1) {
440 warn("Multiple mappings for address %#x.", vaddr);
441 return false;
442 }
443
444 paddr = result.address[0];
445 return true;
446 }
447
448 void
449 ThreadContext::scheduleInstCountEvent(Event *event, Tick count)
450 {
451 Tick now = getCurrentInstCount();
452 comInstEventQueue.schedule(event, count);
453 if (count <= now)
454 call().simulationTime_stop(iris::IrisInstIdSimulationEngine);
455 else
456 maintainStepping();
457 }
458
459 void
460 ThreadContext::descheduleInstCountEvent(Event *event)
461 {
462 comInstEventQueue.deschedule(event);
463 maintainStepping();
464 }
465
466 Tick
467 ThreadContext::getCurrentInstCount()
468 {
469 uint64_t count;
470 auto ret = call().step_getStepCounterValue(_instId, count, "instruction");
471 panic_if(ret != iris::E_ok, "Failed to get instruction count.");
472 return count;
473 }
474
475 void
476 ThreadContext::initMemProxies(::ThreadContext *tc)
477 {
478 if (FullSystem) {
479 assert(!physProxy && !virtProxy);
480 physProxy.reset(new PortProxy(_cpu->getSendFunctional(),
481 _cpu->cacheLineSize()));
482 virtProxy.reset(new TranslatingPortProxy(tc));
483 } else {
484 assert(!virtProxy);
485 virtProxy.reset(new SETranslatingPortProxy(this,
486 SETranslatingPortProxy::NextPage));
487 }
488 }
489
490 ThreadContext::Status
491 ThreadContext::status() const
492 {
493 return _status;
494 }
495
496 void
497 ThreadContext::setStatus(Status new_status)
498 {
499 if (enableAfterPseudoEvent->scheduled())
500 getCpuPtr()->deschedule(enableAfterPseudoEvent);
501 if (new_status == Active) {
502 if (_status != Active)
503 call().perInstanceExecution_setState(_instId, true);
504 } else {
505 if (_status == Active)
506 call().perInstanceExecution_setState(_instId, false);
507 }
508 _status = new_status;
509 }
510
511 ArmISA::PCState
512 ThreadContext::pcState() const
513 {
514 ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
515 ArmISA::PCState pc;
516
517 pc.thumb(cpsr.t);
518 pc.nextThumb(pc.thumb());
519 pc.jazelle(cpsr.j);
520 pc.nextJazelle(cpsr.j);
521 pc.aarch64(!cpsr.width);
522 pc.nextAArch64(!cpsr.width);
523 pc.illegalExec(false);
524 pc.itstate(ArmISA::itState(cpsr));
525 pc.nextItstate(0);
526
527 iris::ResourceReadResult result;
528 call().resource_read(_instId, result, pcRscId);
529 Addr addr = result.data.at(0);
530 if (cpsr.width && cpsr.t)
531 addr = addr & ~0x1;
532 pc.set(addr);
533
534 return pc;
535 }
536 void
537 ThreadContext::pcState(const ArmISA::PCState &val)
538 {
539 Addr pc = val.pc();
540
541 ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
542 if (cpsr.width && cpsr.t)
543 pc = pc | 0x1;
544
545 iris::ResourceWriteResult result;
546 call().resource_write(_instId, result, pcRscId, pc);
547 }
548
549 Addr
550 ThreadContext::instAddr() const
551 {
552 return pcState().instAddr();
553 }
554
555 Addr
556 ThreadContext::nextInstAddr() const
557 {
558 return pcState().nextInstAddr();
559 }
560
561 RegVal
562 ThreadContext::readMiscRegNoEffect(RegIndex misc_reg) const
563 {
564 iris::ResourceReadResult result;
565 call().resource_read(_instId, result, miscRegIds.at(misc_reg));
566 return result.data.at(0);
567 }
568
569 void
570 ThreadContext::setMiscRegNoEffect(RegIndex misc_reg, const RegVal val)
571 {
572 iris::ResourceWriteResult result;
573 call().resource_write(_instId, result, miscRegIds.at(misc_reg), val);
574 }
575
576 RegVal
577 ThreadContext::readIntReg(RegIndex reg_idx) const
578 {
579 ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
580
581 iris::ResourceReadResult result;
582 if (cpsr.width)
583 call().resource_read(_instId, result, intReg32Ids.at(reg_idx));
584 else
585 call().resource_read(_instId, result, intReg64Ids.at(reg_idx));
586 return result.data.at(0);
587 }
588
589 void
590 ThreadContext::setIntReg(RegIndex reg_idx, RegVal val)
591 {
592 ArmISA::CPSR cpsr = readMiscRegNoEffect(ArmISA::MISCREG_CPSR);
593
594 iris::ResourceWriteResult result;
595 if (cpsr.width)
596 call().resource_write(_instId, result, intReg32Ids.at(reg_idx), val);
597 else
598 call().resource_write(_instId, result, intReg64Ids.at(reg_idx), val);
599 }
600
601 /*
602 * The 64 bit version of registers gives us a pre-flattened view of the reg
603 * file, no matter what mode we're in or if we're currently 32 or 64 bit.
604 */
605 RegVal
606 ThreadContext::readIntRegFlat(RegIndex idx) const
607 {
608 if (idx >= flattenedIntIds.size())
609 return 0;
610 iris::ResourceId res_id = flattenedIntIds.at(idx);
611 if (res_id == iris::IRIS_UINT64_MAX)
612 return 0;
613 iris::ResourceReadResult result;
614 call().resource_read(_instId, result, res_id);
615 return result.data.at(0);
616 }
617
618 void
619 ThreadContext::setIntRegFlat(RegIndex idx, uint64_t val)
620 {
621 iris::ResourceId res_id =
622 (idx >= flattenedIntIds.size()) ? iris::IRIS_UINT64_MAX :
623 flattenedIntIds.at(idx);
624 panic_if(res_id == iris::IRIS_UINT64_MAX,
625 "Int reg %d is not supported by fast model.", idx);
626 iris::ResourceWriteResult result;
627 call().resource_write(_instId, result, flattenedIntIds.at(idx), val);
628 }
629
630 RegVal
631 ThreadContext::readCCRegFlat(RegIndex idx) const
632 {
633 if (idx >= ccRegIds.size())
634 return 0;
635 iris::ResourceReadResult result;
636 call().resource_read(_instId, result, ccRegIds.at(idx));
637 return result.data.at(0);
638 }
639
640 void
641 ThreadContext::setCCRegFlat(RegIndex idx, RegVal val)
642 {
643 panic_if(idx >= ccRegIds.size(),
644 "CC reg %d is not supported by fast model.", idx);
645 iris::ResourceWriteResult result;
646 call().resource_write(_instId, result, ccRegIds.at(idx), val);
647 }
648
649 const ArmISA::VecRegContainer &
650 ThreadContext::readVecReg(const RegId &reg_id) const
651 {
652 const RegIndex idx = reg_id.index();
653 ArmISA::VecRegContainer &reg = vecRegs.at(idx);
654 reg.zero();
655
656 // Ignore accesses to registers which aren't architected. gem5 defines a
657 // few extra registers which it uses internally in the implementation of
658 // some instructions.
659 if (idx >= vecRegIds.size())
660 return reg;
661
662 iris::ResourceReadResult result;
663 call().resource_read(_instId, result, vecRegIds.at(idx));
664 size_t data_size = result.data.size() * (sizeof(*result.data.data()));
665 size_t size = std::min(data_size, reg.size());
666 memcpy(reg.raw_ptr<void>(), (void *)result.data.data(), size);
667
668 return reg;
669 }
670
671 const ArmISA::VecRegContainer &
672 ThreadContext::readVecRegFlat(RegIndex idx) const
673 {
674 return readVecReg(RegId(VecRegClass, idx));
675 }
676
677 const ArmISA::VecPredRegContainer &
678 ThreadContext::readVecPredReg(const RegId &reg_id) const
679 {
680 RegIndex idx = reg_id.index();
681
682 ArmISA::VecPredRegContainer &reg = vecPredRegs.at(idx);
683 reg.reset();
684
685 if (idx >= vecPredRegIds.size())
686 return reg;
687
688 iris::ResourceReadResult result;
689 call().resource_read(_instId, result, vecPredRegIds.at(idx));
690
691 size_t offset = 0;
692 size_t num_bits = reg.NUM_BITS;
693 uint8_t *bytes = (uint8_t *)result.data.data();
694 while (num_bits > 8) {
695 reg.set_bits(offset, 8, *bytes);
696 offset += 8;
697 num_bits -= 8;
698 bytes++;
699 }
700 if (num_bits)
701 reg.set_bits(offset, num_bits, *bytes);
702
703 return reg;
704 }
705
706 const ArmISA::VecPredRegContainer &
707 ThreadContext::readVecPredRegFlat(RegIndex idx) const
708 {
709 return readVecPredReg(RegId(VecPredRegClass, idx));
710 }
711
712 } // namespace Iris