140 lines
3.0 KiB
C++
140 lines
3.0 KiB
C++
#include "RAM.hpp"
|
|
|
|
#include <spider/runtime/cpu/Register.hpp>
|
|
|
|
#include <spider/runtime/memory/Types.hpp>
|
|
|
|
#include <cstring>
|
|
|
|
namespace spider {
|
|
|
|
// Constructors & Destructors //
|
|
|
|
RAM::RAM(u64 length) : _mem(nullptr), _size(length), _oob(0) {
|
|
if (_size > 0) {
|
|
_mem = new u8[_size];
|
|
std::memset(_mem, 0, _size);
|
|
}
|
|
}
|
|
|
|
RAM::RAM(const RAM& other) : _size(other._size), _oob(0) {
|
|
_mem = new u8[_size];
|
|
std::copy(other._mem, other._mem + _size, _mem);
|
|
}
|
|
|
|
RAM::RAM(RAM&& other) noexcept : _mem(other._mem), _size(other._size), _oob(0) {
|
|
other._mem = nullptr;
|
|
other._size = 0;
|
|
}
|
|
|
|
RAM::~RAM() {
|
|
delete[] _mem;
|
|
}
|
|
|
|
// Assign Operators //
|
|
|
|
RAM& RAM::operator=(const RAM& other) {
|
|
if (this == &other) return *this; // lock self
|
|
|
|
u8* new_mem = new u8[other._size];
|
|
std::copy(other._mem, other._mem + other._size, new_mem);
|
|
|
|
delete[] _mem;
|
|
_mem = new_mem;
|
|
_size = other._size;
|
|
|
|
return *this;
|
|
}
|
|
|
|
RAM& RAM::operator=(RAM&& other) noexcept {
|
|
if (this == &other) return *this; // lock self
|
|
|
|
delete[] _mem;
|
|
|
|
_mem = other._mem; // time to steal!
|
|
_size = other._size;
|
|
|
|
other._mem = nullptr; // leave as a husk
|
|
other._size = 0;
|
|
|
|
return *this;
|
|
}
|
|
|
|
// Unsafe Access //
|
|
|
|
u8& RAM::operator[](u64 i) { return _mem[i]; }
|
|
|
|
u8 RAM::operator[](u64 i) const { return _mem[i]; }
|
|
|
|
// Managed Access //
|
|
|
|
u8& RAM::at(u64 i) {
|
|
return (i < _size) ? _mem[i] : _oob;
|
|
}
|
|
|
|
u8 RAM::at(u64 i) const {
|
|
return (i < _size) ? _mem[i] : _oob;
|
|
}
|
|
|
|
void RAM::loadRegister(u64 i, u8 size_code, register_t* r) {
|
|
i = std::min(i, _size);
|
|
spider::loadRegister[size_code](r, _mem + i, _size - i);
|
|
}
|
|
|
|
// Misc //
|
|
|
|
void RAM::resize(u64 new_size) {
|
|
// Special case 1
|
|
if (new_size == _size) return;
|
|
|
|
// Special case 2
|
|
if (new_size == 0) {
|
|
delete[] _mem;
|
|
_mem = nullptr;
|
|
_size = 0;
|
|
return;
|
|
}
|
|
|
|
// 1. Allocate the new block
|
|
u8* new_mem = new u8[new_size];
|
|
|
|
// 2. Zero-initialize
|
|
std::memset(new_mem, 0, new_size);
|
|
|
|
// 3. Preserve data
|
|
// If shrinking, copy 'new_size' bytes. If growing, copy 'old_size' bytes.
|
|
u64 bytes_to_copy = (new_size < _size) ? new_size : _size;
|
|
|
|
// 3.1 Previous size could be zero, where _mem would be null
|
|
if (_mem != nullptr) {
|
|
std::copy(_mem, _mem + bytes_to_copy, new_mem);
|
|
}
|
|
|
|
// 4. Swap and Clean up
|
|
delete[] _mem;
|
|
_mem = new_mem;
|
|
_size = new_size;
|
|
}
|
|
|
|
u64 RAM::size() const {
|
|
return _size;
|
|
}
|
|
|
|
u8* RAM::begin() {
|
|
return this->_mem;
|
|
}
|
|
|
|
u8* RAM::end() {
|
|
return this->_mem + this->_size;
|
|
}
|
|
|
|
const u8* RAM::begin() const {
|
|
return this->_mem;
|
|
}
|
|
|
|
const u8* RAM::end() const {
|
|
return this->_mem + this->_size;
|
|
}
|
|
|
|
}
|