9using namespace Tempest;
17 region.emplace_back(Region(0x1000,0x80000000));
21 for(
auto& rgn:region) {
22 if(rgn.status==S_Allocated && rgn.real!=
nullptr) {
29void Mem32::implSetCallbackR(Type t, std::function<
void(
void*, uint32_t)> fn,
size_t elt) {
31 m.read = std::move(fn);
32 m.elementSize = uint32_t(elt);
35void Mem32::implSetCallbackW(Type t, std::function<
void(
void*, uint32_t)> fn,
size_t elt) {
37 m.write = std::move(fn);
38 m.elementSize = uint32_t(elt);
42 if(
auto rgn = implAllocAt(address,size)) {
46 rgn->comment = comment;
49 throw std::bad_alloc();
53 if(
auto rgn = implAlloc(size)) {
57 rgn->comment = comment;
60 throw std::bad_alloc();
64 if(
auto rgn = implAllocAt(address,size)) {
68 rgn->status = S_Callback;
71 throw std::bad_alloc();
75 if(
auto rgn = implAllocAt(address,size)) {
76 rgn->real = std::calloc(rgn->size,1);
77 if(rgn->real==
nullptr) {
82 rgn->status = S_Allocated;
83 rgn->comment = comment;
86 throw std::bad_alloc();
90 if(
auto rgn = implAlloc(size)) {
91 rgn->real = std::calloc(rgn->size,1);
92 if(rgn->real==
nullptr) {
96 rgn->status = S_Allocated;
97 rgn->comment = comment;
104 if(
auto rgn = implAlloc(size)) {
106 rgn->status = S_Callback;
107 rgn->comment = comment;
116 for(
size_t i=0; i<region.size(); ++i) {
117 if(region[i].address!=address)
119 std::free(region[i].real);
120 region[i].real =
nullptr;
121 region[i].status = S_Unused;
125 Log::e(
"mem_free: heap block wan't allocated by script: ",
reinterpret_cast<void*
>(uint64_t(address)));
129 auto r = translate(address);
131 Log::e(
"deref: address translation failure: ",
reinterpret_cast<void*
>(uint64_t(address)));
134 if(r->address+r->size < address+size) {
135 Log::e(
"deref: memmory block is too small: ",
reinterpret_cast<void*
>(uint64_t(address)),
" ", size);
139 memSyncRead(rgn.type, rgn, address, size);
140 address -= rgn.address;
141 return reinterpret_cast<uint8_t*
>(rgn.real)+address;
145 auto rgn = translate(address);
147 Log::e(
"deref: address translation failure: ",
reinterpret_cast<void*
>(uint64_t(address)));
150 if(rgn->address+rgn->size < address+size) {
151 Log::e(
"deref: memmory block is too small: ",
reinterpret_cast<void*
>(uint64_t(address)),
" ", size);
154 if(rgn->status==S_Callback) {
155 Log::e(
"deref: unable to deref callback-memory: ",
reinterpret_cast<void*
>(uint64_t(address)));
159 address -= rgn->address;
160 return reinterpret_cast<uint8_t*
>(rgn->real)+address;
164 auto r = translate(address);
166 Log::e(
"deref: address translation failure: ",
reinterpret_cast<void*
>(uint64_t(address)));
171 const ptr32_t dAddr = address - rgn.address;
172 const uint32_t size = rgn.size - dAddr;
173 memSyncRead(rgn.type, rgn, address, size);
174 return {
reinterpret_cast<uint8_t*
>(rgn.real)+dAddr, size};
177void Mem32::compactage() {
178 for(
size_t i=0; i+1<region.size(); ) {
179 auto& a = region[i+0];
180 auto& b = region[i+1];
181 if(a.status==S_Unused && a.status==b.status && a.address+a.size==b.address) {
184 region.erase(region.begin()+ptrdiff_t(i+1));
192 auto rgn = translate(address);
194 Log::e(
"mem_writeint: address translation failure: ",
reinterpret_cast<void*
>(uint64_t(address)));
198 memSyncRead(rgn->type, *rgn, address, 4);
199 const ptr32_t dAddr = address-rgn->address;
200 auto ptr =
reinterpret_cast<uint8_t*
>(rgn->real)+dAddr;
201 std::memcpy(ptr,&v,4);
202 memSyncWrite(rgn->type, *rgn, address, 4);
206 const auto r = translate(address);
208 Log::e(
"mem_readint: address translation failure: ",
reinterpret_cast<void*
>(uint64_t(address)));
213 const ptr32_t dAddr = address-rgn.address;
214 memSyncRead(rgn.type, rgn, address, 4);
216 auto ptr =
reinterpret_cast<uint8_t*
>(rgn.real)+dAddr;
218 std::memcpy(&ret,ptr,4);
223 auto s = translate(psrc);
224 auto d = translate(pdst);
225 if(s==
nullptr || s->status==S_Unused) {
226 Log::e(
"mem_copybytes: address translation failure: ",
reinterpret_cast<void*
>(uint64_t(psrc)));
229 if(d==
nullptr || d->status==S_Unused) {
230 Log::e(
"mem_copybytes: address translation failure: ",
reinterpret_cast<void*
>(uint64_t(pdst)));
236 size_t sOff = psrc - src.address;
237 size_t dOff = pdst - dst.address;
239 if(src.size<sOff+size) {
240 Log::e(
"mem_copybytes: copy-size exceed source block size: ", size);
241 sz = std::min(src.size-sOff,sz);
243 if(dst.size<dOff+size) {
244 Log::e(
"mem_copybytes: copy-size exceed destination block size: ", size);
245 sz = std::min(dst.size-dOff,sz);
247 memSyncRead(src.type, src,
ptr32_t(src.address+sOff), uint32_t(sz));
248 memSyncRead(dst.type, dst,
ptr32_t(dst.address+dOff), uint32_t(sz));
249 std::memcpy(
reinterpret_cast<uint8_t*
>(dst.real)+dOff,
250 reinterpret_cast<uint8_t*
>(src.real)+sOff,
252 memSyncWrite(dst.type, dst,
ptr32_t(dst.address+dOff), uint32_t(sz));
255Mem32::Region* Mem32::implAlloc(uint32_t size) {
258 for(
size_t i=0; i<region.size(); ++i) {
259 if(region[i].status!=S_Unused)
261 const uint32_t off = region[i].address %
memAlign;
262 if(region[i].size<size+off)
264 if(size!=region[i].size) {
268 region.insert(region.begin()+ptrdiff_t(i+1),p2);
270 region[i].size = size;
279 if(implRealloc(address,size))
282 auto next = implAlloc(size);
286 auto src = translate(address);
289 Log::e(
"realloc: address translation failure: ",
reinterpret_cast<void*
>(uint64_t(address)));
295 auto ret = next->address;
296 next->status = S_Allocated;
299 next->type = src->type;
300 next->real = std::realloc(src->real, next->size);
301 next->comment = src->comment;
303 std::memset(
reinterpret_cast<uint8_t*
>(next->real)+src->size, 0, size-src->size);
306 src->status = S_Unused;
309 next->real = std::calloc(next->size, 1);
315Mem32::Region* Mem32::implAllocAt(ptr32_t address, uint32_t size) {
316 for(
size_t i=0; i<region.size(); ++i) {
317 auto& rgn = region[i];
320 if(!(rgn.address<=address && address+size<=rgn.address+rgn.size))
327 if(rgn.status!=S_Unused) {
328 Log::e(
"DMA: failed to pin a ",size,
" bytes of memory: block is in use");
333 address = region[i].address;
335 if(region[i].address<address) {
336 uint32_t off = (address-region[i].address);
340 region.insert(region.begin()+ptrdiff_t(i+1),p2);
341 region[i].size = off;
344 if(size!=region[i].size) {
348 region.insert(region.begin()+ptrdiff_t(i+1),p2);
356bool Mem32::implRealloc(ptr32_t address, uint32_t nsize) {
360 for(
size_t i=0; i<region.size(); ++i) {
361 auto& rgn = region[i];
362 if(rgn.address!=address)
369 auto next = std::realloc(rgn.real, nsize);
373 Region frgn(address+nsize, rgn.size-nsize);
375 region.insert(region.begin() + intptr_t(i + 1), frgn);
379 if(i+1==region.size())
382 auto& rgn1 = region[i+1];
383 if(rgn1.status==S_Unused && rgn.size + rgn1.size>=nsize) {
384 auto next = std::realloc(rgn.real, nsize);
387 std::memset(
reinterpret_cast<uint8_t*
>(next)+rgn.size, 0, nsize-rgn.size);
388 rgn1.address += (nsize-rgn.size);
389 rgn1.size -= (nsize-rgn.size);
402Mem32::Region* Mem32::implTranslate(ptr32_t address) {
404 for(
auto& rgn:region) {
405 if(rgn.address<=address && address<rgn.address+rgn.size && rgn.status!=S_Unused)
411Mem32::Region* Mem32::translate(ptr32_t address) {
415 auto ret = implTranslate(address);
420 if(rgn.status!=S_Callback)
423 if(rgn.real==
nullptr) {
424 rgn.real = std::calloc(rgn.size, 1);
425 if(rgn.real==
nullptr)
426 throw std::bad_alloc();
431void Mem32::memSyncRead(Type type,
const Region& rgn, ptr32_t address, uint32_t size) {
434 auto m = memMap.find(type);
435 if(m==memMap.end()) {
436 throw std::logic_error(
"DMA: callback is not provided for callback memory!");
438 memSyncRead(m->second, rgn, address, size);
441void Mem32::memSyncRead(Callback& cb,
const Region& rgn, ptr32_t address, uint32_t size) {
442 address -= rgn.address;
444 const uint32_t begin = address/cb.elementSize;
445 const uint32_t end = (address+size+cb.elementSize-1)/cb.elementSize;
447 auto ptr =
reinterpret_cast<uint8_t*
>(rgn.real);
448 for(
size_t i=begin; i<end; ++i) {
449 cb.read(ptr+i*cb.elementSize, uint32_t(i));
453void Mem32::memSyncWrite(Type type,
const Region& rgn, ptr32_t address, uint32_t size) {
456 auto m = memMap.find(type);
457 if(m==memMap.end()) {
458 Log::e(
"memSyncWrite: unable to write to mapped memory: ",
reinterpret_cast<void*
>(uint64_t(address)));
461 memSyncWrite(m->second, rgn, address, size);
464void Mem32::memSyncWrite(Callback& cb,
const Region& rgn, ptr32_t address, uint32_t size) {
466 Log::e(
"memSyncWrite: unable to write to mapped memory: ",
reinterpret_cast<void*
>(uint64_t(address)));
470 address -= rgn.address;
471 const uint32_t begin = address/cb.elementSize;
472 const uint32_t end = (address+size+cb.elementSize-1)/cb.elementSize;
474 auto ptr =
reinterpret_cast<uint8_t*
>(rgn.real);
475 for(
size_t i=begin; i<end; ++i) {
476 cb.write(ptr+i*cb.elementSize, uint32_t(i));
Compatibility::ptr32_t ptr32_t
int32_t readInt(ptr32_t address)
void * derefv(ptr32_t address, uint32_t size)
ptr32_t alloc(uint32_t size, const char *comment=nullptr)
ptr32_t realloc(ptr32_t address, uint32_t size)
ptr32_t pin(void *mem, ptr32_t address, uint32_t size, const char *comment=nullptr)
static constexpr uint32_t memAlign
void copyBytes(ptr32_t src, ptr32_t dst, uint32_t size)
auto deref(ptr32_t address) -> std::tuple< void *, uint32_t >
void writeInt(ptr32_t address, int32_t v)