blob: 95cfd192a7cccf5ad830a798c266d98f26e3c809 [file]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "mpact/sim/util/memory/flat_memory.h"
#include <cstdint>
#include <functional>
#include "absl/base/macros.h"
#include "absl/numeric/bits.h"
namespace mpact {
namespace sim {
namespace util {
void FlatMemory::Load(uint64_t address, DataBuffer *db, Instruction *inst,
ReferenceCount *context) {
ABSL_HARDENING_ASSERT(address >= base_);
uint64_t offset = (address - base_) << shift_;
ABSL_HARDENING_ASSERT(offset + db->size<uint8_t>() <= size_);
uint8_t *ptr = &memory_buffer_[offset];
db->CopyFrom(ptr);
if (nullptr != inst) {
if (db->latency() > 0) {
// If the context is non-null, need to IncRef it before storing it in the
// lambda.
if (context != nullptr) context->IncRef();
inst->state()->function_delay_line()->Add(db->latency(),
[inst, context]() {
inst->Execute(context);
if (context != nullptr)
context->DecRef();
});
} else {
inst->Execute(context);
}
}
}
void FlatMemory::Load(DataBuffer *address_db, DataBuffer *mask_db, int el_size,
DataBuffer *db, Instruction *inst,
ReferenceCount *context) {
int max = mask_db->size<bool>();
switch (el_size) {
case 1:
LoadData<uint8_t>(address_db, mask_db, max, db);
break;
case 2:
LoadData<uint16_t>(address_db, mask_db, max, db);
break;
case 4:
LoadData<uint32_t>(address_db, mask_db, max, db);
break;
case 8:
LoadData<uint64_t>(address_db, mask_db, max, db);
break;
default:
// Error if the default case is hit.
ABSL_HARDENING_ASSERT(false);
break;
}
if (nullptr != inst) {
if (db->latency() > 0) {
// If the context is non-null, need to IncRef it before storing it in the
// lambda.
if (context != nullptr) context->IncRef();
inst->state()->function_delay_line()->Add(db->latency(),
[inst, context]() {
inst->Execute(context);
if (context != nullptr)
context->DecRef();
});
} else {
inst->Execute(context);
}
}
}
void FlatMemory::Store(uint64_t address, DataBuffer *db) {
ABSL_HARDENING_ASSERT(address >= base_);
uint64_t offset = (address - base_) << shift_;
ABSL_HARDENING_ASSERT(offset + db->size<uint8_t>() <= size_);
uint8_t *ptr = &memory_buffer_[offset];
db->CopyTo(ptr);
}
void FlatMemory::Store(DataBuffer *address_db, DataBuffer *mask_db, int el_size,
DataBuffer *db) {
int max = mask_db->size<bool>();
switch (el_size) {
case 1:
StoreData<uint8_t>(address_db, mask_db, max, db);
break;
case 2:
StoreData<uint16_t>(address_db, mask_db, max, db);
break;
case 4:
StoreData<uint32_t>(address_db, mask_db, max, db);
break;
case 8:
StoreData<uint64_t>(address_db, mask_db, max, db);
break;
default:
// Error if the default case is hit.
ABSL_HARDENING_ASSERT(false);
break;
}
}
FlatMemory::FlatMemory(int64_t memory_size_in_units, uint64_t base_address,
uint32_t addressable_unit_size, uint8_t fill)
: size_(memory_size_in_units * addressable_unit_size),
base_(base_address),
memory_buffer_(nullptr) {
ABSL_HARDENING_ASSERT(absl::has_single_bit(addressable_unit_size));
shift_ = absl::countr_zero(addressable_unit_size);
memory_buffer_ = new uint8_t[size_];
if (nullptr == memory_buffer_) {
size_ = 0;
}
memset(memory_buffer_, fill, size_);
}
FlatMemory::~FlatMemory() { delete[] memory_buffer_; }
} // namespace util
} // namespace sim
} // namespace mpact