aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJacob Bramley <jacob.bramley@arm.com>2020-10-30 18:25:43 +0000
committerJacob Bramley <jacob.bramley@arm.com>2020-11-05 14:34:47 +0000
commitc4ef66e95e71f13cb4f1d2983d401fe49bdcc0a7 (patch)
tree7d1be638b0813c5a1358f528626046411567a339 /src
parentf73036bad9bdb8c853d783c7f94be1f298cb508d (diff)
downloadvixl-c4ef66e95e71f13cb4f1d2983d401fe49bdcc0a7.tar.gz
Make the stack size configurable.
Also fix the implementation of stack guards, and make these configurable too. Change-Id: Ic62ee326ed725616322ca8fa26d38b9a089d5043
Diffstat (limited to 'src')
-rw-r--r--src/aarch64/logic-aarch64.cc160
-rw-r--r--src/aarch64/simulator-aarch64.cc205
-rw-r--r--src/aarch64/simulator-aarch64.h382
3 files changed, 398 insertions, 349 deletions
diff --git a/src/aarch64/logic-aarch64.cc b/src/aarch64/logic-aarch64.cc
index 821c1db9..cb82f715 100644
--- a/src/aarch64/logic-aarch64.cc
+++ b/src/aarch64/logic-aarch64.cc
@@ -170,7 +170,7 @@ SimFloat16 Simulator::UFixedToFloat16(uint64_t src,
void Simulator::ld1(VectorFormat vform, LogicVRegister dst, uint64_t addr) {
dst.ClearForWrite(vform);
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
- dst.ReadUintFromMem(vform, i, addr);
+ LoadLane(dst, vform, i, addr);
addr += LaneSizeInBytesFromFormat(vform);
}
}
@@ -180,7 +180,7 @@ void Simulator::ld1(VectorFormat vform,
LogicVRegister dst,
int index,
uint64_t addr) {
- dst.ReadUintFromMem(vform, index, addr);
+ LoadLane(dst, vform, index, addr);
}
@@ -189,13 +189,13 @@ void Simulator::ld1r(VectorFormat vform,
LogicVRegister dst,
uint64_t addr,
bool is_signed) {
- unsigned unpack_size = LaneSizeInBitsFromFormat(unpack_vform);
+ unsigned unpack_size = LaneSizeInBytesFromFormat(unpack_vform);
dst.ClearForWrite(vform);
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
if (is_signed) {
- dst.ReadIntFromMem(vform, unpack_size, i, addr);
+ LoadIntToLane(dst, vform, unpack_size, i, addr);
} else {
- dst.ReadUintFromMem(vform, unpack_size, i, addr);
+ LoadUintToLane(dst, vform, unpack_size, i, addr);
}
}
}
@@ -215,8 +215,8 @@ void Simulator::ld2(VectorFormat vform,
int esize = LaneSizeInBytesFromFormat(vform);
uint64_t addr2 = addr1 + esize;
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
- dst1.ReadUintFromMem(vform, i, addr1);
- dst2.ReadUintFromMem(vform, i, addr2);
+ LoadLane(dst1, vform, i, addr1);
+ LoadLane(dst2, vform, i, addr2);
addr1 += 2 * esize;
addr2 += 2 * esize;
}
@@ -231,8 +231,8 @@ void Simulator::ld2(VectorFormat vform,
dst1.ClearForWrite(vform);
dst2.ClearForWrite(vform);
uint64_t addr2 = addr1 + LaneSizeInBytesFromFormat(vform);
- dst1.ReadUintFromMem(vform, index, addr1);
- dst2.ReadUintFromMem(vform, index, addr2);
+ LoadLane(dst1, vform, index, addr1);
+ LoadLane(dst2, vform, index, addr2);
}
@@ -244,8 +244,8 @@ void Simulator::ld2r(VectorFormat vform,
dst2.ClearForWrite(vform);
uint64_t addr2 = addr + LaneSizeInBytesFromFormat(vform);
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
- dst1.ReadUintFromMem(vform, i, addr);
- dst2.ReadUintFromMem(vform, i, addr2);
+ LoadLane(dst1, vform, i, addr);
+ LoadLane(dst2, vform, i, addr2);
}
}
@@ -262,9 +262,9 @@ void Simulator::ld3(VectorFormat vform,
uint64_t addr2 = addr1 + esize;
uint64_t addr3 = addr2 + esize;
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
- dst1.ReadUintFromMem(vform, i, addr1);
- dst2.ReadUintFromMem(vform, i, addr2);
- dst3.ReadUintFromMem(vform, i, addr3);
+ LoadLane(dst1, vform, i, addr1);
+ LoadLane(dst2, vform, i, addr2);
+ LoadLane(dst3, vform, i, addr3);
addr1 += 3 * esize;
addr2 += 3 * esize;
addr3 += 3 * esize;
@@ -283,9 +283,9 @@ void Simulator::ld3(VectorFormat vform,
dst3.ClearForWrite(vform);
uint64_t addr2 = addr1 + LaneSizeInBytesFromFormat(vform);
uint64_t addr3 = addr2 + LaneSizeInBytesFromFormat(vform);
- dst1.ReadUintFromMem(vform, index, addr1);
- dst2.ReadUintFromMem(vform, index, addr2);
- dst3.ReadUintFromMem(vform, index, addr3);
+ LoadLane(dst1, vform, index, addr1);
+ LoadLane(dst2, vform, index, addr2);
+ LoadLane(dst3, vform, index, addr3);
}
@@ -300,9 +300,9 @@ void Simulator::ld3r(VectorFormat vform,
uint64_t addr2 = addr + LaneSizeInBytesFromFormat(vform);
uint64_t addr3 = addr2 + LaneSizeInBytesFromFormat(vform);
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
- dst1.ReadUintFromMem(vform, i, addr);
- dst2.ReadUintFromMem(vform, i, addr2);
- dst3.ReadUintFromMem(vform, i, addr3);
+ LoadLane(dst1, vform, i, addr);
+ LoadLane(dst2, vform, i, addr2);
+ LoadLane(dst3, vform, i, addr3);
}
}
@@ -322,10 +322,10 @@ void Simulator::ld4(VectorFormat vform,
uint64_t addr3 = addr2 + esize;
uint64_t addr4 = addr3 + esize;
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
- dst1.ReadUintFromMem(vform, i, addr1);
- dst2.ReadUintFromMem(vform, i, addr2);
- dst3.ReadUintFromMem(vform, i, addr3);
- dst4.ReadUintFromMem(vform, i, addr4);
+ LoadLane(dst1, vform, i, addr1);
+ LoadLane(dst2, vform, i, addr2);
+ LoadLane(dst3, vform, i, addr3);
+ LoadLane(dst4, vform, i, addr4);
addr1 += 4 * esize;
addr2 += 4 * esize;
addr3 += 4 * esize;
@@ -348,10 +348,10 @@ void Simulator::ld4(VectorFormat vform,
uint64_t addr2 = addr1 + LaneSizeInBytesFromFormat(vform);
uint64_t addr3 = addr2 + LaneSizeInBytesFromFormat(vform);
uint64_t addr4 = addr3 + LaneSizeInBytesFromFormat(vform);
- dst1.ReadUintFromMem(vform, index, addr1);
- dst2.ReadUintFromMem(vform, index, addr2);
- dst3.ReadUintFromMem(vform, index, addr3);
- dst4.ReadUintFromMem(vform, index, addr4);
+ LoadLane(dst1, vform, index, addr1);
+ LoadLane(dst2, vform, index, addr2);
+ LoadLane(dst3, vform, index, addr3);
+ LoadLane(dst4, vform, index, addr4);
}
@@ -369,17 +369,17 @@ void Simulator::ld4r(VectorFormat vform,
uint64_t addr3 = addr2 + LaneSizeInBytesFromFormat(vform);
uint64_t addr4 = addr3 + LaneSizeInBytesFromFormat(vform);
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
- dst1.ReadUintFromMem(vform, i, addr);
- dst2.ReadUintFromMem(vform, i, addr2);
- dst3.ReadUintFromMem(vform, i, addr3);
- dst4.ReadUintFromMem(vform, i, addr4);
+ LoadLane(dst1, vform, i, addr);
+ LoadLane(dst2, vform, i, addr2);
+ LoadLane(dst3, vform, i, addr3);
+ LoadLane(dst4, vform, i, addr4);
}
}
void Simulator::st1(VectorFormat vform, LogicVRegister src, uint64_t addr) {
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
- src.WriteUintToMem(vform, i, addr);
+ StoreLane(src, vform, i, addr);
addr += LaneSizeInBytesFromFormat(vform);
}
}
@@ -389,19 +389,19 @@ void Simulator::st1(VectorFormat vform,
LogicVRegister src,
int index,
uint64_t addr) {
- src.WriteUintToMem(vform, index, addr);
+ StoreLane(src, vform, index, addr);
}
void Simulator::st2(VectorFormat vform,
- LogicVRegister dst,
- LogicVRegister dst2,
+ LogicVRegister src,
+ LogicVRegister src2,
uint64_t addr) {
int esize = LaneSizeInBytesFromFormat(vform);
uint64_t addr2 = addr + esize;
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
- dst.WriteUintToMem(vform, i, addr);
- dst2.WriteUintToMem(vform, i, addr2);
+ StoreLane(src, vform, i, addr);
+ StoreLane(src2, vform, i, addr2);
addr += 2 * esize;
addr2 += 2 * esize;
}
@@ -409,28 +409,28 @@ void Simulator::st2(VectorFormat vform,
void Simulator::st2(VectorFormat vform,
- LogicVRegister dst,
- LogicVRegister dst2,
+ LogicVRegister src,
+ LogicVRegister src2,
int index,
uint64_t addr) {
int esize = LaneSizeInBytesFromFormat(vform);
- dst.WriteUintToMem(vform, index, addr);
- dst2.WriteUintToMem(vform, index, addr + 1 * esize);
+ StoreLane(src, vform, index, addr);
+ StoreLane(src2, vform, index, addr + 1 * esize);
}
void Simulator::st3(VectorFormat vform,
- LogicVRegister dst,
- LogicVRegister dst2,
- LogicVRegister dst3,
+ LogicVRegister src,
+ LogicVRegister src2,
+ LogicVRegister src3,
uint64_t addr) {
int esize = LaneSizeInBytesFromFormat(vform);
uint64_t addr2 = addr + esize;
uint64_t addr3 = addr2 + esize;
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
- dst.WriteUintToMem(vform, i, addr);
- dst2.WriteUintToMem(vform, i, addr2);
- dst3.WriteUintToMem(vform, i, addr3);
+ StoreLane(src, vform, i, addr);
+ StoreLane(src2, vform, i, addr2);
+ StoreLane(src3, vform, i, addr3);
addr += 3 * esize;
addr2 += 3 * esize;
addr3 += 3 * esize;
@@ -439,33 +439,33 @@ void Simulator::st3(VectorFormat vform,
void Simulator::st3(VectorFormat vform,
- LogicVRegister dst,
- LogicVRegister dst2,
- LogicVRegister dst3,
+ LogicVRegister src,
+ LogicVRegister src2,
+ LogicVRegister src3,
int index,
uint64_t addr) {
int esize = LaneSizeInBytesFromFormat(vform);
- dst.WriteUintToMem(vform, index, addr);
- dst2.WriteUintToMem(vform, index, addr + 1 * esize);
- dst3.WriteUintToMem(vform, index, addr + 2 * esize);
+ StoreLane(src, vform, index, addr);
+ StoreLane(src2, vform, index, addr + 1 * esize);
+ StoreLane(src3, vform, index, addr + 2 * esize);
}
void Simulator::st4(VectorFormat vform,
- LogicVRegister dst,
- LogicVRegister dst2,
- LogicVRegister dst3,
- LogicVRegister dst4,
+ LogicVRegister src,
+ LogicVRegister src2,
+ LogicVRegister src3,
+ LogicVRegister src4,
uint64_t addr) {
int esize = LaneSizeInBytesFromFormat(vform);
uint64_t addr2 = addr + esize;
uint64_t addr3 = addr2 + esize;
uint64_t addr4 = addr3 + esize;
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
- dst.WriteUintToMem(vform, i, addr);
- dst2.WriteUintToMem(vform, i, addr2);
- dst3.WriteUintToMem(vform, i, addr3);
- dst4.WriteUintToMem(vform, i, addr4);
+ StoreLane(src, vform, i, addr);
+ StoreLane(src2, vform, i, addr2);
+ StoreLane(src3, vform, i, addr3);
+ StoreLane(src4, vform, i, addr4);
addr += 4 * esize;
addr2 += 4 * esize;
addr3 += 4 * esize;
@@ -475,17 +475,17 @@ void Simulator::st4(VectorFormat vform,
void Simulator::st4(VectorFormat vform,
- LogicVRegister dst,
- LogicVRegister dst2,
- LogicVRegister dst3,
- LogicVRegister dst4,
+ LogicVRegister src,
+ LogicVRegister src2,
+ LogicVRegister src3,
+ LogicVRegister src4,
int index,
uint64_t addr) {
int esize = LaneSizeInBytesFromFormat(vform);
- dst.WriteUintToMem(vform, index, addr);
- dst2.WriteUintToMem(vform, index, addr + 1 * esize);
- dst3.WriteUintToMem(vform, index, addr + 2 * esize);
- dst4.WriteUintToMem(vform, index, addr + 3 * esize);
+ StoreLane(src, vform, index, addr);
+ StoreLane(src2, vform, index, addr + 1 * esize);
+ StoreLane(src3, vform, index, addr + 2 * esize);
+ StoreLane(src4, vform, index, addr + 3 * esize);
}
@@ -7019,7 +7019,7 @@ void Simulator::SVEStructuredStoreHelper(VectorFormat vform,
for (int r = 0; r < reg_count; r++) {
uint64_t element_address = addr.GetElementAddress(i, r);
- zt[r].WriteUintToMem(unpack_vform, i << unpack_shift, element_address);
+ StoreLane(zt[r], unpack_vform, i << unpack_shift, element_address);
}
}
@@ -7068,9 +7068,6 @@ void Simulator::SVEStructuredLoadHelper(VectorFormat vform,
ReadVRegister(zt_codes[3]),
};
- VectorFormat unpack_vform =
- SVEFormatFromLaneSizeInBytesLog2(msize_in_bytes_log2);
-
for (int i = 0; i < LaneCountFromFormat(vform); i++) {
for (int r = 0; r < reg_count; r++) {
uint64_t element_address = addr.GetElementAddress(i, r);
@@ -7081,16 +7078,9 @@ void Simulator::SVEStructuredLoadHelper(VectorFormat vform,
}
if (is_signed) {
- zt[r].ReadIntFromMem(vform,
- LaneSizeInBitsFromFormat(unpack_vform),
- i,
- element_address);
-
+ LoadIntToLane(zt[r], vform, msize_in_bytes, i, element_address);
} else {
- zt[r].ReadUintFromMem(vform,
- LaneSizeInBitsFromFormat(unpack_vform),
- i,
- element_address);
+ LoadUintToLane(zt[r], vform, msize_in_bytes, i, element_address);
}
}
}
@@ -7216,7 +7206,7 @@ void Simulator::SVEFaultTolerantLoadHelper(VectorFormat vform,
// First-faulting loads always load the first active element, regardless
// of FFR. The result will be discarded if its FFR lane is inactive, but
// it could still generate a fault.
- value = Memory::Read(msize_in_bytes, element_address);
+ value = MemReadUint(msize_in_bytes, element_address);
// All subsequent elements have non-fault semantics.
type = kSVENonFaultLoad;
@@ -7228,7 +7218,7 @@ void Simulator::SVEFaultTolerantLoadHelper(VectorFormat vform,
bool can_read = (i < fake_fault_at_lane) &&
CanReadMemory(element_address, msize_in_bytes);
if (can_read) {
- value = Memory::Read(msize_in_bytes, element_address);
+ value = MemReadUint(msize_in_bytes, element_address);
} else {
// Propagate the fault to the end of FFR.
for (int j = i; j < LaneCountFromFormat(vform); j++) {
diff --git a/src/aarch64/simulator-aarch64.cc b/src/aarch64/simulator-aarch64.cc
index 692a0596..cd5a2d6c 100644
--- a/src/aarch64/simulator-aarch64.cc
+++ b/src/aarch64/simulator-aarch64.cc
@@ -67,8 +67,10 @@ SimSystemRegister SimSystemRegister::DefaultValueFor(SystemRegister id) {
}
-Simulator::Simulator(Decoder* decoder, FILE* stream)
- : movprfx_(NULL), cpu_features_auditor_(decoder, CPUFeatures::All()) {
+Simulator::Simulator(Decoder* decoder, FILE* stream, SimStack::Allocated stack)
+ : memory_(std::move(stack)),
+ movprfx_(NULL),
+ cpu_features_auditor_(decoder, CPUFeatures::All()) {
// Ensure that shift operations act as the simulator expects.
VIXL_ASSERT((static_cast<int32_t>(-1) >> 1) == -1);
VIXL_ASSERT((static_cast<uint32_t>(-1) >> 1) == 0x7fffffff);
@@ -101,18 +103,6 @@ Simulator::Simulator(Decoder* decoder, FILE* stream)
ResetState();
- // Allocate and set up the simulator stack.
- stack_ = new byte[stack_size_];
- stack_limit_ = stack_ + stack_protection_size_;
- // Configure the starting stack pointer.
- // - Find the top of the stack.
- byte* tos = stack_ + stack_size_;
- // - There's a protection region at both ends of the stack.
- tos -= stack_protection_size_;
- // - The stack pointer must be 16-byte aligned.
- tos = AlignDown(tos, 16);
- WriteSp(tos);
-
// Print a warning about exclusive-access instructions, but only the first
// time they are encountered. This warning can be silenced using
// SilenceExclusiveAccessWarning().
@@ -192,6 +182,8 @@ void Simulator::ResetState() {
ResetVRegisters();
ResetPRegisters();
+ WriteSp(memory_.GetStack().GetBase());
+
pc_ = NULL;
pc_modified_ = false;
@@ -221,7 +213,6 @@ void Simulator::SetVectorLengthInBits(unsigned vector_length) {
}
Simulator::~Simulator() {
- delete[] stack_;
// The decoder may outlive the simulator.
decoder_->RemoveVisitor(print_disasm_);
delete print_disasm_;
@@ -1272,7 +1263,7 @@ uint16_t Simulator::PrintPartialAccess(uint16_t access_mask,
const char* sep = "";
for (int i = struct_element_count - 1; i >= 0; i--) {
int offset = lane_size_in_bytes * i;
- uint64_t nibble = Memory::Read(lane_size_in_bytes, address + offset);
+ uint64_t nibble = MemReadUint(lane_size_in_bytes, address + offset);
fprintf(stream_, "%s%0*" PRIx64, sep, lane_size_in_nibbles, nibble);
sep = "'";
}
@@ -2015,7 +2006,7 @@ void Simulator::LoadAcquireRCpcUnscaledOffsetHelper(const Instruction* instr) {
VIXL_ALIGNMENT_EXCEPTION();
}
- WriteRegister<T1>(rt, static_cast<T1>(Memory::Read<T2>(address)));
+ WriteRegister<T1>(rt, static_cast<T1>(MemRead<T2>(address)));
// Approximate load-acquire by issuing a full barrier after the load.
__sync_synchronize();
@@ -2045,7 +2036,7 @@ void Simulator::StoreReleaseUnscaledOffsetHelper(const Instruction* instr) {
// Approximate store-release by issuing a full barrier after the load.
__sync_synchronize();
- Memory::Write<T>(address, ReadRegister<T>(rt));
+ MemWrite<T>(address, ReadRegister<T>(rt));
LogWrite(rt, GetPrintRegisterFormat(element_size), address);
}
@@ -2132,7 +2123,7 @@ void Simulator::VisitLoadStorePAC(const Instruction* instr) {
// Verify that the calculated address is available to the host.
VIXL_ASSERT(address == addr_ptr);
- WriteXRegister(dst, Memory::Read<uint64_t>(addr_ptr), NoRegLog);
+ WriteXRegister(dst, MemRead<uint64_t>(addr_ptr), NoRegLog);
unsigned access_size = 1 << 3;
LogRead(dst, GetPrintRegisterFormatForSize(access_size), addr_ptr);
}
@@ -2160,92 +2151,92 @@ void Simulator::LoadStoreHelper(const Instruction* instr,
LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreMask));
switch (op) {
case LDRB_w:
- WriteWRegister(srcdst, Memory::Read<uint8_t>(address), NoRegLog);
+ WriteWRegister(srcdst, MemRead<uint8_t>(address), NoRegLog);
extend_to_size = kWRegSizeInBytes;
break;
case LDRH_w:
- WriteWRegister(srcdst, Memory::Read<uint16_t>(address), NoRegLog);
+ WriteWRegister(srcdst, MemRead<uint16_t>(address), NoRegLog);
extend_to_size = kWRegSizeInBytes;
break;
case LDR_w:
- WriteWRegister(srcdst, Memory::Read<uint32_t>(address), NoRegLog);
+ WriteWRegister(srcdst, MemRead<uint32_t>(address), NoRegLog);
extend_to_size = kWRegSizeInBytes;
break;
case LDR_x:
- WriteXRegister(srcdst, Memory::Read<uint64_t>(address), NoRegLog);
+ WriteXRegister(srcdst, MemRead<uint64_t>(address), NoRegLog);
extend_to_size = kXRegSizeInBytes;
break;
case LDRSB_w:
- WriteWRegister(srcdst, Memory::Read<int8_t>(address), NoRegLog);
+ WriteWRegister(srcdst, MemRead<int8_t>(address), NoRegLog);
extend_to_size = kWRegSizeInBytes;
break;
case LDRSH_w:
- WriteWRegister(srcdst, Memory::Read<int16_t>(address), NoRegLog);
+ WriteWRegister(srcdst, MemRead<int16_t>(address), NoRegLog);
extend_to_size = kWRegSizeInBytes;
break;
case LDRSB_x:
- WriteXRegister(srcdst, Memory::Read<int8_t>(address), NoRegLog);
+ WriteXRegister(srcdst, MemRead<int8_t>(address), NoRegLog);
extend_to_size = kXRegSizeInBytes;
break;
case LDRSH_x:
- WriteXRegister(srcdst, Memory::Read<int16_t>(address), NoRegLog);
+ WriteXRegister(srcdst, MemRead<int16_t>(address), NoRegLog);
extend_to_size = kXRegSizeInBytes;
break;
case LDRSW_x:
- WriteXRegister(srcdst, Memory::Read<int32_t>(address), NoRegLog);
+ WriteXRegister(srcdst, MemRead<int32_t>(address), NoRegLog);
extend_to_size = kXRegSizeInBytes;
break;
case LDR_b:
- WriteBRegister(srcdst, Memory::Read<uint8_t>(address), NoRegLog);
+ WriteBRegister(srcdst, MemRead<uint8_t>(address), NoRegLog);
rt_is_vreg = true;
break;
case LDR_h:
- WriteHRegister(srcdst, Memory::Read<uint16_t>(address), NoRegLog);
+ WriteHRegister(srcdst, MemRead<uint16_t>(address), NoRegLog);
rt_is_vreg = true;
break;
case LDR_s:
- WriteSRegister(srcdst, Memory::Read<float>(address), NoRegLog);
+ WriteSRegister(srcdst, MemRead<float>(address), NoRegLog);
rt_is_vreg = true;
break;
case LDR_d:
- WriteDRegister(srcdst, Memory::Read<double>(address), NoRegLog);
+ WriteDRegister(srcdst, MemRead<double>(address), NoRegLog);
rt_is_vreg = true;
break;
case LDR_q:
- WriteQRegister(srcdst, Memory::Read<qreg_t>(address), NoRegLog);
+ WriteQRegister(srcdst, MemRead<qreg_t>(address), NoRegLog);
rt_is_vreg = true;
break;
case STRB_w:
- Memory::Write<uint8_t>(address, ReadWRegister(srcdst));
+ MemWrite<uint8_t>(address, ReadWRegister(srcdst));
break;
case STRH_w:
- Memory::Write<uint16_t>(address, ReadWRegister(srcdst));
+ MemWrite<uint16_t>(address, ReadWRegister(srcdst));
break;
case STR_w:
- Memory::Write<uint32_t>(address, ReadWRegister(srcdst));
+ MemWrite<uint32_t>(address, ReadWRegister(srcdst));
break;
case STR_x:
- Memory::Write<uint64_t>(address, ReadXRegister(srcdst));
+ MemWrite<uint64_t>(address, ReadXRegister(srcdst));
break;
case STR_b:
- Memory::Write<uint8_t>(address, ReadBRegister(srcdst));
+ MemWrite<uint8_t>(address, ReadBRegister(srcdst));
rt_is_vreg = true;
break;
case STR_h:
- Memory::Write<uint16_t>(address, ReadHRegisterBits(srcdst));
+ MemWrite<uint16_t>(address, ReadHRegisterBits(srcdst));
rt_is_vreg = true;
break;
case STR_s:
- Memory::Write<float>(address, ReadSRegister(srcdst));
+ MemWrite<float>(address, ReadSRegister(srcdst));
rt_is_vreg = true;
break;
case STR_d:
- Memory::Write<double>(address, ReadDRegister(srcdst));
+ MemWrite<double>(address, ReadDRegister(srcdst));
rt_is_vreg = true;
break;
case STR_q:
- Memory::Write<qreg_t>(address, ReadQRegister(srcdst));
+ MemWrite<qreg_t>(address, ReadQRegister(srcdst));
rt_is_vreg = true;
break;
@@ -2326,64 +2317,64 @@ void Simulator::LoadStorePairHelper(const Instruction* instr,
// Use NoRegLog to suppress the register trace (LOG_REGS, LOG_FP_REGS). We
// will print a more detailed log.
case LDP_w: {
- WriteWRegister(rt, Memory::Read<uint32_t>(address), NoRegLog);
- WriteWRegister(rt2, Memory::Read<uint32_t>(address2), NoRegLog);
+ WriteWRegister(rt, MemRead<uint32_t>(address), NoRegLog);
+ WriteWRegister(rt2, MemRead<uint32_t>(address2), NoRegLog);
break;
}
case LDP_s: {
- WriteSRegister(rt, Memory::Read<float>(address), NoRegLog);
- WriteSRegister(rt2, Memory::Read<float>(address2), NoRegLog);
+ WriteSRegister(rt, MemRead<float>(address), NoRegLog);
+ WriteSRegister(rt2, MemRead<float>(address2), NoRegLog);
rt_is_vreg = true;
break;
}
case LDP_x: {
- WriteXRegister(rt, Memory::Read<uint64_t>(address), NoRegLog);
- WriteXRegister(rt2, Memory::Read<uint64_t>(address2), NoRegLog);
+ WriteXRegister(rt, MemRead<uint64_t>(address), NoRegLog);
+ WriteXRegister(rt2, MemRead<uint64_t>(address2), NoRegLog);
break;
}
case LDP_d: {
- WriteDRegister(rt, Memory::Read<double>(address), NoRegLog);
- WriteDRegister(rt2, Memory::Read<double>(address2), NoRegLog);
+ WriteDRegister(rt, MemRead<double>(address), NoRegLog);
+ WriteDRegister(rt2, MemRead<double>(address2), NoRegLog);
rt_is_vreg = true;
break;
}
case LDP_q: {
- WriteQRegister(rt, Memory::Read<qreg_t>(address), NoRegLog);
- WriteQRegister(rt2, Memory::Read<qreg_t>(address2), NoRegLog);
+ WriteQRegister(rt, MemRead<qreg_t>(address), NoRegLog);
+ WriteQRegister(rt2, MemRead<qreg_t>(address2), NoRegLog);
rt_is_vreg = true;
break;
}
case LDPSW_x: {
- WriteXRegister(rt, Memory::Read<int32_t>(address), NoRegLog);
- WriteXRegister(rt2, Memory::Read<int32_t>(address2), NoRegLog);
+ WriteXRegister(rt, MemRead<int32_t>(address), NoRegLog);
+ WriteXRegister(rt2, MemRead<int32_t>(address2), NoRegLog);
sign_extend = true;
break;
}
case STP_w: {
- Memory::Write<uint32_t>(address, ReadWRegister(rt));
- Memory::Write<uint32_t>(address2, ReadWRegister(rt2));
+ MemWrite<uint32_t>(address, ReadWRegister(rt));
+ MemWrite<uint32_t>(address2, ReadWRegister(rt2));
break;
}
case STP_s: {
- Memory::Write<float>(address, ReadSRegister(rt));
- Memory::Write<float>(address2, ReadSRegister(rt2));
+ MemWrite<float>(address, ReadSRegister(rt));
+ MemWrite<float>(address2, ReadSRegister(rt2));
rt_is_vreg = true;
break;
}
case STP_x: {
- Memory::Write<uint64_t>(address, ReadXRegister(rt));
- Memory::Write<uint64_t>(address2, ReadXRegister(rt2));
+ MemWrite<uint64_t>(address, ReadXRegister(rt));
+ MemWrite<uint64_t>(address2, ReadXRegister(rt2));
break;
}
case STP_d: {
- Memory::Write<double>(address, ReadDRegister(rt));
- Memory::Write<double>(address2, ReadDRegister(rt2));
+ MemWrite<double>(address, ReadDRegister(rt));
+ MemWrite<double>(address2, ReadDRegister(rt2));
rt_is_vreg = true;
break;
}
case STP_q: {
- Memory::Write<qreg_t>(address, ReadQRegister(rt));
- Memory::Write<qreg_t>(address2, ReadQRegister(rt2));
+ MemWrite<qreg_t>(address, ReadQRegister(rt));
+ MemWrite<qreg_t>(address2, ReadQRegister(rt2));
rt_is_vreg = true;
break;
}
@@ -2443,7 +2434,7 @@ void Simulator::CompareAndSwapHelper(const Instruction* instr) {
// associated with that location, even if the compare subsequently fails.
local_monitor_.Clear();
- T data = Memory::Read<T>(address);
+ T data = MemRead<T>(address);
if (is_acquire) {
// Approximate load-acquire by issuing a full barrier after the load.
__sync_synchronize();
@@ -2454,7 +2445,7 @@ void Simulator::CompareAndSwapHelper(const Instruction* instr) {
// Approximate store-release by issuing a full barrier before the store.
__sync_synchronize();
}
- Memory::Write<T>(address, newvalue);
+ MemWrite<T>(address, newvalue);
LogWrite(rt, GetPrintRegisterFormatForSize(element_size), address);
}
WriteRegister<T>(rs, data, NoRegLog);
@@ -2490,8 +2481,8 @@ void Simulator::CompareAndSwapPairHelper(const Instruction* instr) {
// associated with that location, even if the compare subsequently fails.
local_monitor_.Clear();
- T data_low = Memory::Read<T>(address);
- T data_high = Memory::Read<T>(address2);
+ T data_low = MemRead<T>(address);
+ T data_high = MemRead<T>(address2);
if (is_acquire) {
// Approximate load-acquire by issuing a full barrier after the load.
@@ -2506,8 +2497,8 @@ void Simulator::CompareAndSwapPairHelper(const Instruction* instr) {
__sync_synchronize();
}
- Memory::Write<T>(address, newvalue_low);
- Memory::Write<T>(address2, newvalue_high);
+ MemWrite<T>(address, newvalue_low);
+ MemWrite<T>(address2, newvalue_high);
}
WriteRegister<T>(rs + 1, data_high, NoRegLog);
@@ -2675,43 +2666,43 @@ void Simulator::VisitLoadStoreExclusive(const Instruction* instr) {
case LDAXRB_w:
case LDARB_w:
case LDLARB:
- WriteWRegister(rt, Memory::Read<uint8_t>(address), NoRegLog);
+ WriteWRegister(rt, MemRead<uint8_t>(address), NoRegLog);
reg_size = kWRegSizeInBytes;
break;
case LDXRH_w:
case LDAXRH_w:
case LDARH_w:
case LDLARH:
- WriteWRegister(rt, Memory::Read<uint16_t>(address), NoRegLog);
+ WriteWRegister(rt, MemRead<uint16_t>(address), NoRegLog);
reg_size = kWRegSizeInBytes;
break;
case LDXR_w:
case LDAXR_w:
case LDAR_w:
case LDLAR_w:
- WriteWRegister(rt, Memory::Read<uint32_t>(address), NoRegLog);
+ WriteWRegister(rt, MemRead<uint32_t>(address), NoRegLog);
reg_size = kWRegSizeInBytes;
break;
case LDXR_x:
case LDAXR_x:
case LDAR_x:
case LDLAR_x:
- WriteXRegister(rt, Memory::Read<uint64_t>(address), NoRegLog);
+ WriteXRegister(rt, MemRead<uint64_t>(address), NoRegLog);
reg_size = kXRegSizeInBytes;
break;
case LDXP_w:
case LDAXP_w:
- WriteWRegister(rt, Memory::Read<uint32_t>(address), NoRegLog);
+ WriteWRegister(rt, MemRead<uint32_t>(address), NoRegLog);
WriteWRegister(rt2,
- Memory::Read<uint32_t>(address + element_size),
+ MemRead<uint32_t>(address + element_size),
NoRegLog);
reg_size = kWRegSizeInBytes;
break;
case LDXP_x:
case LDAXP_x:
- WriteXRegister(rt, Memory::Read<uint64_t>(address), NoRegLog);
+ WriteXRegister(rt, MemRead<uint64_t>(address), NoRegLog);
WriteXRegister(rt2,
- Memory::Read<uint64_t>(address + element_size),
+ MemRead<uint64_t>(address + element_size),
NoRegLog);
reg_size = kXRegSizeInBytes;
break;
@@ -2755,37 +2746,35 @@ void Simulator::VisitLoadStoreExclusive(const Instruction* instr) {
case STLXRB_w:
case STLRB_w:
case STLLRB:
- Memory::Write<uint8_t>(address, ReadWRegister(rt));
+ MemWrite<uint8_t>(address, ReadWRegister(rt));
break;
case STXRH_w:
case STLXRH_w:
case STLRH_w:
case STLLRH:
- Memory::Write<uint16_t>(address, ReadWRegister(rt));
+ MemWrite<uint16_t>(address, ReadWRegister(rt));
break;
case STXR_w:
case STLXR_w:
case STLR_w:
case STLLR_w:
- Memory::Write<uint32_t>(address, ReadWRegister(rt));
+ MemWrite<uint32_t>(address, ReadWRegister(rt));
break;
case STXR_x:
case STLXR_x:
case STLR_x:
case STLLR_x:
- Memory::Write<uint64_t>(address, ReadXRegister(rt));
+ MemWrite<uint64_t>(address, ReadXRegister(rt));
break;
case STXP_w:
case STLXP_w:
- Memory::Write<uint32_t>(address, ReadWRegister(rt));
- Memory::Write<uint32_t>(address + element_size,
- ReadWRegister(rt2));
+ MemWrite<uint32_t>(address, ReadWRegister(rt));
+ MemWrite<uint32_t>(address + element_size, ReadWRegister(rt2));
break;
case STXP_x:
case STLXP_x:
- Memory::Write<uint64_t>(address, ReadXRegister(rt));
- Memory::Write<uint64_t>(address + element_size,
- ReadXRegister(rt2));
+ MemWrite<uint64_t>(address, ReadXRegister(rt));
+ MemWrite<uint64_t>(address + element_size, ReadXRegister(rt2));
break;
default:
VIXL_UNREACHABLE();
@@ -2818,7 +2807,7 @@ void Simulator::AtomicMemorySimpleHelper(const Instruction* instr) {
T value = ReadRegister<T>(rs);
- T data = Memory::Read<T>(address);
+ T data = MemRead<T>(address);
if (is_acquire) {
// Approximate load-acquire by issuing a full barrier after the load.
@@ -2859,7 +2848,7 @@ void Simulator::AtomicMemorySimpleHelper(const Instruction* instr) {
__sync_synchronize();
}
- Memory::Write<T>(address, result);
+ MemWrite<T>(address, result);
WriteRegister<T>(rt, data, NoRegLog);
PrintRegisterFormat format = GetPrintRegisterFormatForSize(element_size);
@@ -2881,7 +2870,7 @@ void Simulator::AtomicMemorySwapHelper(const Instruction* instr) {
CheckIsValidUnalignedAtomicAccess(rn, address, element_size);
- T data = Memory::Read<T>(address);
+ T data = MemRead<T>(address);
if (is_acquire) {
// Approximate load-acquire by issuing a full barrier after the load.
__sync_synchronize();
@@ -2891,7 +2880,7 @@ void Simulator::AtomicMemorySwapHelper(const Instruction* instr) {
// Approximate store-release by issuing a full barrier before the store.
__sync_synchronize();
}
- Memory::Write<T>(address, ReadRegister<T>(rs));
+ MemWrite<T>(address, ReadRegister<T>(rs));
WriteRegister<T>(rt, data);
@@ -2910,7 +2899,7 @@ void Simulator::LoadAcquireRCpcHelper(const Instruction* instr) {
CheckIsValidUnalignedAtomicAccess(rn, address, element_size);
- WriteRegister<T>(rt, Memory::Read<T>(address));
+ WriteRegister<T>(rt, MemRead<T>(address));
// Approximate load-acquire by issuing a full barrier after the load.
__sync_synchronize();
@@ -3031,27 +3020,27 @@ void Simulator::VisitLoadLiteral(const Instruction* instr) {
// Use NoRegLog to suppress the register trace (LOG_REGS, LOG_VREGS), then
// print a more detailed log.
case LDR_w_lit:
- WriteWRegister(rt, Memory::Read<uint32_t>(address), NoRegLog);
+ WriteWRegister(rt, MemRead<uint32_t>(address), NoRegLog);
LogRead(rt, kPrintWReg, address);
break;
case LDR_x_lit:
- WriteXRegister(rt, Memory::Read<uint64_t>(address), NoRegLog);
+ WriteXRegister(rt, MemRead<uint64_t>(address), NoRegLog);
LogRead(rt, kPrintXReg, address);
break;
case LDR_s_lit:
- WriteSRegister(rt, Memory::Read<float>(address), NoRegLog);
+ WriteSRegister(rt, MemRead<float>(address), NoRegLog);
LogVRead(rt, kPrintSRegFP, address);
break;
case LDR_d_lit:
- WriteDRegister(rt, Memory::Read<double>(address), NoRegLog);
+ WriteDRegister(rt, MemRead<double>(address), NoRegLog);
LogVRead(rt, kPrintDRegFP, address);
break;
case LDR_q_lit:
- WriteQRegister(rt, Memory::Read<qreg_t>(address), NoRegLog);
+ WriteQRegister(rt, MemRead<qreg_t>(address), NoRegLog);
LogVRead(rt, kPrintReg1Q, address);
break;
case LDRSW_x_lit:
- WriteXRegister(rt, Memory::Read<int32_t>(address), NoRegLog);
+ WriteXRegister(rt, MemRead<int32_t>(address), NoRegLog);
LogExtendingRead(rt, kPrintXReg, kWRegSizeInBytes, address);
break;
@@ -4439,7 +4428,7 @@ void Simulator::SysOp_W(int op, int64_t val) {
case CIVAC: {
// Perform a dummy memory access to ensure that we have read access
// to the specified address.
- volatile uint8_t y = Memory::Read<uint8_t>(val);
+ volatile uint8_t y = MemRead<uint8_t>(val);
USE(y);
// TODO: Implement "case ZVA:".
break;
@@ -9739,7 +9728,7 @@ void Simulator::VisitSVELoadPredicateRegister(const Instruction* instr) {
uint64_t multiplier = ExtractSignedBitfield64(8, 0, imm9);
uint64_t address = ReadXRegister(instr->GetRn()) + multiplier * pl;
for (int i = 0; i < pl; i++) {
- pt.Insert(i, Memory::Read<uint8_t>(address + i));
+ pt.Insert(i, MemRead<uint8_t>(address + i));
}
LogPRead(instr->GetPt(), address);
break;
@@ -9759,7 +9748,7 @@ void Simulator::VisitSVELoadVectorRegister(const Instruction* instr) {
uint64_t multiplier = ExtractSignedBitfield64(8, 0, imm9);
uint64_t address = ReadXRegister(instr->GetRn()) + multiplier * vl;
for (int i = 0; i < vl; i++) {
- zt.Insert(i, Memory::Read<uint8_t>(address + i));
+ zt.Insert(i, MemRead<uint8_t>(address + i));
}
LogZRead(instr->GetRt(), address);
break;
@@ -10694,7 +10683,7 @@ void Simulator::VisitSVEStorePredicateRegister(const Instruction* instr) {
uint64_t multiplier = ExtractSignedBitfield64(8, 0, imm9);
uint64_t address = ReadXRegister(instr->GetRn()) + multiplier * pl;
for (int i = 0; i < pl; i++) {
- Memory::Write(address + i, pt.GetLane<uint8_t>(i));
+ MemWrite(address + i, pt.GetLane<uint8_t>(i));
}
LogPWrite(instr->GetPt(), address);
break;
@@ -10714,7 +10703,7 @@ void Simulator::VisitSVEStoreVectorRegister(const Instruction* instr) {
uint64_t multiplier = ExtractSignedBitfield64(8, 0, imm9);
uint64_t address = ReadXRegister(instr->GetRn()) + multiplier * vl;
for (int i = 0; i < vl; i++) {
- Memory::Write(address + i, zt.GetLane<uint8_t>(i));
+ MemWrite(address + i, zt.GetLane<uint8_t>(i));
}
LogZWrite(instr->GetRt(), address);
break;
@@ -11878,11 +11867,11 @@ void Simulator::DoRuntimeCall(const Instruction* instr) {
// The appropriate `Simulator::SimulateRuntimeCall()` wrapper and the function
// to call are passed inlined in the assembly.
uintptr_t call_wrapper_address =
- Memory::Read<uintptr_t>(instr + kRuntimeCallWrapperOffset);
+ MemRead<uintptr_t>(instr + kRuntimeCallWrapperOffset);
uintptr_t function_address =
- Memory::Read<uintptr_t>(instr + kRuntimeCallFunctionOffset);
+ MemRead<uintptr_t>(instr + kRuntimeCallFunctionOffset);
RuntimeCallType call_type = static_cast<RuntimeCallType>(
- Memory::Read<uint32_t>(instr + kRuntimeCallTypeOffset));
+ MemRead<uint32_t>(instr + kRuntimeCallTypeOffset));
auto runtime_call_wrapper =
reinterpret_cast<void (*)(Simulator*, uintptr_t)>(call_wrapper_address);
@@ -11917,7 +11906,7 @@ void Simulator::DoConfigureCPUFeatures(const Instruction* instr) {
// Read the kNone-terminated list of features.
CPUFeatures parameters;
while (true) {
- ElementType feature = Memory::Read<ElementType>(instr + offset);
+ ElementType feature = MemRead<ElementType>(instr + offset);
offset += element_size;
if (feature == static_cast<ElementType>(CPUFeatures::kNone)) break;
parameters.Combine(static_cast<CPUFeatures::Feature>(feature));
diff --git a/src/aarch64/simulator-aarch64.h b/src/aarch64/simulator-aarch64.h
index 1e7d3079..f8bc2754 100644
--- a/src/aarch64/simulator-aarch64.h
+++ b/src/aarch64/simulator-aarch64.h
@@ -27,6 +27,7 @@
#ifndef VIXL_AARCH64_SIMULATOR_AARCH64_H_
#define VIXL_AARCH64_SIMULATOR_AARCH64_H_
+#include <memory>
#include <vector>
#include "../globals-vixl.h"
@@ -54,11 +55,112 @@
namespace vixl {
namespace aarch64 {
+class SimStack {
+ public:
+ SimStack() {}
+ explicit SimStack(size_t size) : usable_size_(size) {}
+
+ // Guard against accesses above the stack base. This could occur, for example,
+ // if the first simulated function tries to read stack arguments that haven't
+ // been properly initialised in the Simulator's stack.
+ void SetBaseGuardSize(size_t size) { base_guard_size_ = size; }
+
+ // Guard against stack overflows. The size should be large enough to detect
+ // the largest stride made (by `MacroAssembler::Claim()` or equivalent) whilst
+ // initialising stack objects.
+ void SetLimitGuardSize(size_t size) { limit_guard_size_ = size; }
+
+ // The minimum usable size of the stack.
+ // Equal to "stack base" - "stack limit", in AAPCS64 terminology.
+ void SetUsableSize(size_t size) { usable_size_ = size; }
+
+ // Set the minimum alignment for the stack parameters.
+ void AlignToBytesLog2(int align_log2) { align_log2_ = align_log2; }
+
+ class Allocated {
+ public:
+ // Using AAPCS64 terminology, highest addresses at the top:
+ //
+ // data_.get() + alloc_size ->
+ // |
+ // | Base guard
+ // GetBase() -> | |
+ // | |
+ // | | AAPCS64-legal
+ // | Usable stack | values of 'sp'.
+ // | |
+ // | |
+ // GetLimit() -> |
+ // | Limit guard
+ // data_.get() -> |
+ //
+ // The Simulator detects (and forbids) accesses to either guard region.
+
+ char* GetBase() const { return base_; }
+ char* GetLimit() const { return limit_; }
+
+ template <typename T>
+ bool IsAccessInGuardRegion(const T* base, size_t size) const {
+ VIXL_ASSERT(size > 0);
+ // Inclusive bounds.
+ const char* start = reinterpret_cast<const char*>(base);
+ const char* end = start + size - 1;
+ const char* data_start = data_.get();
+ const char* data_end = data_start + alloc_size_ - 1;
+ bool in_base_guard = (start <= data_end) && (end >= base_);
+ bool in_limit_guard = (start <= limit_) && (end >= data_start);
+ return in_base_guard || in_limit_guard;
+ }
+
+ private:
+ std::unique_ptr<char[]> data_;
+ char* limit_;
+ char* base_;
+ size_t alloc_size_;
+
+ friend class SimStack;
+ };
+
+ // Allocate the stack, locking the parameters.
+ Allocated Allocate() {
+ size_t align_to = 1 << align_log2_;
+ size_t l = AlignUp(limit_guard_size_, align_to);
+ size_t u = AlignUp(usable_size_, align_to);
+ size_t b = AlignUp(base_guard_size_, align_to);
+ size_t size = l + u + b;
+
+ Allocated a;
+ size_t alloc_size = (align_to - 1) + size;
+ a.data_ = std::make_unique<char[]>(alloc_size);
+ void* data = a.data_.get();
+ auto data_aligned =
+ reinterpret_cast<char*>(std::align(align_to, size, data, alloc_size));
+ a.limit_ = data_aligned + l - 1;
+ a.base_ = data_aligned + l + u;
+ a.alloc_size_ = alloc_size;
+ return a;
+ }
+
+ private:
+ size_t base_guard_size_ = 256;
+ size_t limit_guard_size_ = 4 * 1024;
+ size_t usable_size_ = 8 * 1024;
+ size_t align_log2_ = 4;
+
+ static const size_t kDefaultBaseGuardSize = 256;
+ static const size_t kDefaultLimitGuardSize = 4 * 1024;
+ static const size_t kDefaultUsableSize = 8 * 1024;
+};
+
// Representation of memory, with typed getters and setters for access.
class Memory {
public:
+ explicit Memory(SimStack::Allocated stack) : stack_(std::move(stack)) {}
+
+ const SimStack::Allocated& GetStack() { return stack_; }
+
template <typename T>
- static T AddressUntag(T address) {
+ T AddressUntag(T address) const {
// Cast the address using a C-style cast. A reinterpret_cast would be
// appropriate, but it can't cast one integral type to another.
uint64_t bits = (uint64_t)address;
@@ -66,18 +168,35 @@ class Memory {
}
template <typename T, typename A>
- static T Read(A address) {
+ T Read(A address) const {
T value;
address = AddressUntag(address);
- VIXL_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
- (sizeof(value) == 4) || (sizeof(value) == 8) ||
- (sizeof(value) == 16));
- memcpy(&value, reinterpret_cast<const char*>(address), sizeof(value));
+ VIXL_STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
+ (sizeof(value) == 4) || (sizeof(value) == 8) ||
+ (sizeof(value) == 16));
+ auto base = reinterpret_cast<const char*>(address);
+ if (stack_.IsAccessInGuardRegion(base, sizeof(value))) {
+ VIXL_ABORT_WITH_MSG("Attempt to read from stack guard region");
+ }
+ memcpy(&value, base, sizeof(value));
return value;
}
+ template <typename T, typename A>
+ void Write(A address, T value) const {
+ address = AddressUntag(address);
+ VIXL_STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
+ (sizeof(value) == 4) || (sizeof(value) == 8) ||
+ (sizeof(value) == 16));
+ auto base = reinterpret_cast<char*>(address);
+ if (stack_.IsAccessInGuardRegion(base, sizeof(value))) {
+ VIXL_ABORT_WITH_MSG("Attempt to write to stack guard region");
+ }
+ memcpy(base, &value, sizeof(value));
+ }
+
template <typename A>
- static uint64_t Read(int size_in_bytes, A address) {
+ uint64_t ReadUint(int size_in_bytes, A address) const {
switch (size_in_bytes) {
case 1:
return Read<uint8_t>(address);
@@ -92,14 +211,39 @@ class Memory {
return 0;
}
- template <typename T, typename A>
- static void Write(A address, T value) {
- address = AddressUntag(address);
- VIXL_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
- (sizeof(value) == 4) || (sizeof(value) == 8) ||
- (sizeof(value) == 16));
- memcpy(reinterpret_cast<char*>(address), &value, sizeof(value));
+ template <typename A>
+ int64_t ReadInt(int size_in_bytes, A address) const {
+ switch (size_in_bytes) {
+ case 1:
+ return Read<int8_t>(address);
+ case 2:
+ return Read<int16_t>(address);
+ case 4:
+ return Read<int32_t>(address);
+ case 8:
+ return Read<int64_t>(address);
+ }
+ VIXL_UNREACHABLE();
+ return 0;
+ }
+
+ template <typename A>
+ void Write(int size_in_bytes, A address, uint64_t value) const {
+ switch (size_in_bytes) {
+ case 1:
+ return Write(address, static_cast<uint8_t>(value));
+ case 2:
+ return Write(address, static_cast<uint16_t>(value));
+ case 4:
+ return Write(address, static_cast<uint32_t>(value));
+ case 8:
+ return Write(address, value);
+ }
+ VIXL_UNREACHABLE();
}
+
+ private:
+ SimStack::Allocated stack_;
};
// Represent a register (r0-r31, v0-v31, z0-z31, p0-p15).
@@ -478,136 +622,6 @@ class LogicVRegister {
}
}
- void ReadIntFromMem(VectorFormat vform,
- unsigned msize_in_bits,
- int index,
- uint64_t addr) const {
- if (IsSVEFormat(vform)) register_.NotifyAccessAsZ();
- int64_t value;
- switch (msize_in_bits) {
- case 8:
- value = Memory::Read<int8_t>(addr);
- break;
- case 16:
- value = Memory::Read<int16_t>(addr);
- break;
- case 32:
- value = Memory::Read<int32_t>(addr);
- break;
- case 64:
- value = Memory::Read<int64_t>(addr);
- break;
- default:
- VIXL_UNREACHABLE();
- return;
- }
-
- unsigned esize_in_bits = LaneSizeInBitsFromFormat(vform);
- VIXL_ASSERT(esize_in_bits >= msize_in_bits);
- switch (esize_in_bits) {
- case 8:
- register_.Insert(index, static_cast<int8_t>(value));
- break;
- case 16:
- register_.Insert(index, static_cast<int16_t>(value));
- break;
- case 32:
- register_.Insert(index, static_cast<int32_t>(value));
- break;
- case 64:
- register_.Insert(index, static_cast<int64_t>(value));
- break;
- default:
- VIXL_UNREACHABLE();
- return;
- }
- }
-
- void ReadUintFromMem(VectorFormat vform,
- unsigned msize_in_bits,
- int index,
- uint64_t addr) const {
- if (IsSVEFormat(vform)) register_.NotifyAccessAsZ();
- uint64_t value;
- switch (msize_in_bits) {
- case 8:
- value = Memory::Read<uint8_t>(addr);
- break;
- case 16:
- value = Memory::Read<uint16_t>(addr);
- break;
- case 32:
- value = Memory::Read<uint32_t>(addr);
- break;
- case 64:
- value = Memory::Read<uint64_t>(addr);
- break;
- default:
- VIXL_UNREACHABLE();
- return;
- }
-
- unsigned esize_in_bits = LaneSizeInBitsFromFormat(vform);
- VIXL_ASSERT(esize_in_bits >= msize_in_bits);
- switch (esize_in_bits) {
- case 8:
- register_.Insert(index, static_cast<uint8_t>(value));
- break;
- case 16:
- register_.Insert(index, static_cast<uint16_t>(value));
- break;
- case 32:
- register_.Insert(index, static_cast<uint32_t>(value));
- break;
- case 64:
- register_.Insert(index, static_cast<uint64_t>(value));
- break;
- default:
- VIXL_UNREACHABLE();
- return;
- }
- }
-
- void ReadUintFromMem(VectorFormat vform, int index, uint64_t addr) const {
- if (IsSVEFormat(vform)) register_.NotifyAccessAsZ();
- switch (LaneSizeInBitsFromFormat(vform)) {
- case 8:
- register_.Insert(index, Memory::Read<uint8_t>(addr));
- break;
- case 16:
- register_.Insert(index, Memory::Read<uint16_t>(addr));
- break;
- case 32:
- register_.Insert(index, Memory::Read<uint32_t>(addr));
- break;
- case 64:
- register_.Insert(index, Memory::Read<uint64_t>(addr));
- break;
- default:
- VIXL_UNREACHABLE();
- return;
- }
- }
-
- void WriteUintToMem(VectorFormat vform, int index, uint64_t addr) const {
- if (IsSVEFormat(vform)) register_.NotifyAccessAsZ();
- uint64_t value = Uint(vform, index);
- switch (LaneSizeInBitsFromFormat(vform)) {
- case 8:
- Memory::Write(addr, static_cast<uint8_t>(value));
- break;
- case 16:
- Memory::Write(addr, static_cast<uint16_t>(value));
- break;
- case 32:
- Memory::Write(addr, static_cast<uint32_t>(value));
- break;
- case 64:
- Memory::Write(addr, value);
- break;
- }
- }
-
template <typename T>
T Float(int index) const {
return register_.GetLane<T>(index);
@@ -1005,7 +1019,9 @@ class SimExclusiveGlobalMonitor {
class Simulator : public DecoderVisitor {
public:
- explicit Simulator(Decoder* decoder, FILE* stream = stdout);
+ explicit Simulator(Decoder* decoder,
+ FILE* stream = stdout,
+ SimStack::Allocated stack = SimStack().Allocate());
~Simulator();
void ResetState();
@@ -1083,7 +1099,7 @@ class Simulator : public DecoderVisitor {
void WritePc(const Instruction* new_pc,
BranchLogMode log_mode = LogBranches) {
if (log_mode == LogBranches) LogTakenBranch(new_pc);
- pc_ = Memory::AddressUntag(new_pc);
+ pc_ = memory_.AddressUntag(new_pc);
pc_modified_ = true;
}
VIXL_DEPRECATED("WritePc", void set_pc(const Instruction* new_pc)) {
@@ -1689,6 +1705,63 @@ class Simulator : public DecoderVisitor {
}
}
+ template <typename T, typename A>
+ T MemRead(A address) const {
+ return memory_.Read<T>(address);
+ }
+
+ template <typename T, typename A>
+ void MemWrite(A address, T value) const {
+ return memory_.Write(address, value);
+ }
+
+ template <typename A>
+ uint64_t MemReadUint(int size_in_bytes, A address) const {
+ return memory_.ReadUint(size_in_bytes, address);
+ }
+
+ template <typename A>
+ int64_t MemReadInt(int size_in_bytes, A address) const {
+ return memory_.ReadInt(size_in_bytes, address);
+ }
+
+ template <typename A>
+ void MemWrite(int size_in_bytes, A address, uint64_t value) const {
+ return memory_.Write(size_in_bytes, address, value);
+ }
+
+ void LoadLane(LogicVRegister dst,
+ VectorFormat vform,
+ int index,
+ uint64_t addr) const {
+ unsigned msize_in_bytes = LaneSizeInBytesFromFormat(vform);
+ LoadUintToLane(dst, vform, msize_in_bytes, index, addr);
+ }
+
+ void LoadUintToLane(LogicVRegister dst,
+ VectorFormat vform,
+ unsigned msize_in_bytes,
+ int index,
+ uint64_t addr) const {
+ dst.SetUint(vform, index, MemReadUint(msize_in_bytes, addr));
+ }
+
+ void LoadIntToLane(LogicVRegister dst,
+ VectorFormat vform,
+ unsigned msize_in_bytes,
+ int index,
+ uint64_t addr) const {
+ dst.SetInt(vform, index, MemReadInt(msize_in_bytes, addr));
+ }
+
+ void StoreLane(const LogicVRegister& src,
+ VectorFormat vform,
+ int index,
+ uint64_t addr) const {
+ unsigned msize_in_bytes = LaneSizeInBytesFromFormat(vform);
+ MemWrite(msize_in_bytes, addr, src.Uint(vform, index));
+ }
+
uint64_t ComputeMemOperandAddress(const MemOperand& mem_op) const;
template <typename T>
@@ -1697,7 +1770,7 @@ class Simulator : public DecoderVisitor {
return ReadCPURegister<T>(operand.GetCPURegister());
} else {
VIXL_ASSERT(operand.IsMemOperand());
- return Memory::Read<T>(ComputeMemOperandAddress(operand.GetMemOperand()));
+ return MemRead<T>(ComputeMemOperandAddress(operand.GetMemOperand()));
}
}
@@ -1718,7 +1791,7 @@ class Simulator : public DecoderVisitor {
WriteCPURegister(operand.GetCPURegister(), raw, log_mode);
} else {
VIXL_ASSERT(operand.IsMemOperand());
- Memory::Write(ComputeMemOperandAddress(operand.GetMemOperand()), value);
+ MemWrite(ComputeMemOperandAddress(operand.GetMemOperand()), value);
}
}
@@ -4502,14 +4575,11 @@ class Simulator : public DecoderVisitor {
static const uint32_t kConditionFlagsMask = 0xf0000000;
- // Stack
- byte* stack_;
- static const int stack_protection_size_ = 256;
- // 8 KB stack.
- // TODO: Make this configurable, or automatically allocate space as it runs
- // out (like the OS would try to do).
- static const int stack_size_ = 8 * 1024 + 2 * stack_protection_size_;
- byte* stack_limit_;
+ Memory memory_;
+
+ static const size_t kDefaultStackGuardStartSize = 0;
+ static const size_t kDefaultStackGuardEndSize = 4 * 1024;
+ static const size_t kDefaultStackUsableSize = 8 * 1024;
Decoder* decoder_;
// Indicates if the pc has been modified by the instruction and should not be