better algorithm to load bytes

This commit is contained in:
2026-03-27 18:59:36 -06:00
parent c6c63d6391
commit 3d80b690c4
9 changed files with 135 additions and 89 deletions

View File

@@ -111,21 +111,7 @@ namespace spider {
* Immediate Addressing Mode
*/
void CPU::imm() {
switch(_size) {
case 0b00:
_alu->_u8 = _reel->readU8(RI);
break;
case 0b01:
_alu->_u16 = _reel->readU16(RI);
break;
case 0b10:
_alu->_u32 = _reel->readU32(RI);
break;
case 0b11:
_alu->_u64 = _reel->readU64(RI);
break;
}
_reel->loadRegister(RI, _size, _alu);
_opers[0] = _alu;
_post = &CPU::imp;
RI += 1 << _size;
@@ -134,51 +120,28 @@ namespace spider {
/**
* Absolute Addressing Mode
*/
void CPU::abs() { // TODO cache ptr size
u8 dat_size = 1 << _size;
u8 ptr_size = 1 << getFlag(CPU::FLAG_MEMORY_MODE);
u64 ptr = 0;
void CPU::abs() {
// Load the actual ptr into the ALU
u8 mm = u8(getFlag(CPU::FLAG_MEMORY_MODE));
_reel->loadRegister(RI, mm, _alu);
RI += 1 << mm;
if(ptr_size + dat_size > _ram->size()) return; // TODO: avoid overflow
switch(ptr_size) {
case 1:
ptr = _reel->readU8(RI);
break;
case 2:
ptr = _reel->readU16(RI);
break;
case 4:
ptr = _reel->readU32(RI);
break;
case 8:
ptr = _reel->readU64(RI);
break;
}
switch(_size) {
case 0b00:
spider::loadLE(&_alu->_u8, &(*_ram)[ptr]);
break;
case 0b01:
spider::loadLE(&_alu->_u16, &(*_ram)[ptr]);
break;
case 0b10:
spider::loadLE(&_alu->_u32, &(*_ram)[ptr]);
break;
case 0b11:
spider::loadLE(&_alu->_u64, &(*_ram)[ptr]);
break;
}
RI += dat_size;
// read the memory from RAM
_store = _alu->_u64;
_ram->loadRegister(_store, _size, _alu);
_post = &CPU::psw;
}
/**
* Register Addressing Mode
*/
void CPU::reg() {
void CPU::reg() { // NOT FINISHED
// Two consecutive registers can be declared
// Shift if the top part will become .reg too
u8 sh = (_addrm & 0b11000 == 0b11000) * 4;
// store no-op
_post = &CPU::imp;
}
/**

View File

@@ -1,5 +1,9 @@
#include "RAM.hpp"
#include <spider/runtime/cpu/Register.hpp>
#include <spider/runtime/memory/Types.hpp>
#include <cstring>
namespace spider {
@@ -72,6 +76,11 @@ namespace spider {
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) {

View File

@@ -43,6 +43,8 @@ namespace spider {
u8 at(u64 i) const;
void loadRegister(u64 i, u8 size_code, register_t* r);
public:
void resize(u64 new_size);

View File

@@ -118,8 +118,8 @@ namespace spider {
std::memcpy(bytes, &n, sizeof(T));
#endif
#if SPIDER_LITTLE_ENDIAN
T tmp = byteswap(n);
std::memcpy(bytes, &tmp, sizeof(T));
n = byteswap(n);
std::memcpy(bytes, &n, sizeof(T));
#endif
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
for (size_t i = 0; i < sizeof(T); ++i) {
@@ -151,9 +151,8 @@ namespace spider {
std::memcpy(n, bytes, sizeof(T));
#endif
#if SPIDER_LITTLE_ENDIAN
T tmp;
std::memcpy(&tmp, bytes, sizeof(T));
*n = byteswap(tmp);
std::memcpy(&n, bytes, sizeof(T));
*n = byteswap(n);
#endif
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
using U = std::make_unsigned_t<T>;
@@ -185,8 +184,8 @@ namespace spider {
inline void storeLE(T n, u8* bytes) {
static_assert(std::is_trivially_copyable<T>::value);
#if SPIDER_BIG_ENDIAN
T tmp = byteswap(n);
std::memcpy(bytes, &tmp, sizeof(T));
n = byteswap(n);
std::memcpy(bytes, &n, sizeof(T));
#endif
#if SPIDER_LITTLE_ENDIAN
std::memcpy(bytes, &n, sizeof(T));
@@ -218,9 +217,8 @@ namespace spider {
inline void loadLE(T* n, const u8* bytes) {
static_assert(std::is_trivially_copyable<T>::value);
#if SPIDER_BIG_ENDIAN
T tmp;
std::memcpy(&tmp, bytes, sizeof(T));
*n = byteswap(tmp);
std::memcpy(&n, bytes, sizeof(T));
*n = byteswap(n);
#endif
#if SPIDER_LITTLE_ENDIAN
std::memcpy(n, bytes, sizeof(T));
@@ -249,5 +247,80 @@ namespace spider {
*n = bit_cast<f64>(tmp);
}
// ADVANCED Load Little Endian //
/**
* Loads LE bytes into a type.
* Also considers that the array may end, actually.
*/
template<typename T>
inline void loadPartialLE(T* n, const u8* bytes, isize length) {
*n = 0;
length = std::min(sizeof(T), length);
#if SPIDER_BIG_ENDIAN
std::memcpy(n, bytes, length);
*n = byteswap(n);
#endif
#if SPIDER_LITTLE_ENDIAN
std::memcpy(n, bytes, length);
#endif
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
using U = std::make_unsigned_t<T>;
U result = 0;
for (size_t i = 0; i < length; ++i) {
result |= static_cast<U>(bytes[i]) << (i * 8);
}
*n = static_cast<T>(result);
#endif
}
template<>
inline void loadPartialLE<f32>(f32* n, const u8* bytes, isize length) {
u32 tmp;
loadLE(&tmp, bytes);
*n = bit_cast<f32>(tmp);
}
template<>
inline void loadPartialLE<f64>(f64* n, const u8* bytes, isize length) {
u64 tmp;
loadLE(&tmp, bytes);
*n = bit_cast<f64>(tmp);
}
inline void loadRegisterU8(register_t* r, const u8* bytes, isize length) {
loadPartialLE(&r->_u8, bytes, length);
}
inline void loadRegisterU16(register_t* r, const u8* bytes, isize length) {
loadPartialLE(&r->_u16, bytes, length);
}
inline void loadRegisterU32(register_t* r, const u8* bytes, isize length) {
loadPartialLE(&r->_u32, bytes, length);
}
inline void loadRegisterU64(register_t* r, const u8* bytes, isize length) {
loadPartialLE(&r->_u64, bytes, length);
}
using _regload = void (*)(register_t* r, const u8* bytes, isize length);
inline _regload loadRegister[] = {
&loadRegisterU8, &loadRegisterU16,
&loadRegisterU32, &loadRegisterU64
};
// MISCs
inline void loadPartialBytes(const u8* from, isize fromOffset, isize fromLength, u8* to, isize toLength) {
size_t safeOffset = std::min(fromOffset, fromLength);
from += safeOffset;
fromLength -= safeOffset;
size_t writable = std::min(fromLength, toLength);
std::copy(from, from + writable, to);
std::fill(to + writable, to + toLength, 0);
}
}

View File

@@ -55,6 +55,8 @@ namespace spider {
*/
virtual void readRange(u64 ip, u8* out, u64 length) = 0;
virtual void loadRegister(u64 ip, u8 size_code, register_t* r) = 0;
/**
* Current size of the instructions.
*/

View File

@@ -179,6 +179,12 @@ namespace spider {
}
}
void InstrReelDyn::loadRegister(u64 ip, u8 size_code, register_t* r) {
u8 bytes[8];
readRange(ip, bytes, 1 << size_code);
spider::loadRegister[size_code](r, bytes, 8);
}
/**
* Current size of the instructions.
*/

View File

@@ -85,6 +85,8 @@ namespace spider {
*/
virtual void readRange(u64 ip, u8* out, u64 length) override;
virtual void loadRegister(u64 ip, u8 size_code, register_t* r) override;
/**
* Current size of the instructions.
*/

View File

@@ -47,49 +47,36 @@ namespace spider {
// Instruction abstraction //
u8 InstrReelFixed::readU8(u64 ip) {
// guard against access
if(ip + 1 > _size) return 0;
// send byte
return _mem[ip];
u8 dat;
spider::loadPartialLE(&dat, _mem + ip, _size);
return dat;
}
u16 InstrReelFixed::readU16(u64 ip) {
// guard against access
if(ip + 2 > _size) return 0;
// build a 16-bit big endian number
u16 dat;
spider::loadLE(&dat, _mem + ip);
spider::loadPartialLE(&dat, _mem + ip, _size);
return dat;
}
u32 InstrReelFixed::readU32(u64 ip) {
// guard against access
if(ip + 4 > _size) return 0;
// build a 32-bit big endian number
u32 dat;
spider::loadLE(&dat, _mem + ip);
spider::loadPartialLE(&dat, _mem + ip, _size);
return dat;
}
u64 InstrReelFixed::readU64(u64 ip) {
// guard against access
if(ip + 8 > _size) return 0;
// build a 64-bit big endian number
u64 dat;
spider::loadLE(&dat, _mem + ip);
spider::loadPartialLE(&dat, _mem + ip, _size);
return dat;
}
void InstrReelFixed::readRange(u64 ip, u8* out, u64 length) {
if(ip + length > _size) {
std::memset(out, 0, length);
return;
spider::loadPartialBytes(_mem, isize(ip), _size, out, length);
}
std::memcpy(out, _mem + ip, length);
void InstrReelFixed::loadRegister(u64 ip, u8 size_code, register_t* r) {
ip = std::min(ip, _size);
spider::loadRegister[size_code](r, _mem + ip, _size - ip);
}
u64 InstrReelFixed::size() {

View File

@@ -70,6 +70,8 @@ namespace spider {
*/
virtual void readRange(u64 ip, u8* out, u64 length) override;
virtual void loadRegister(u64 ip, u8 size_code, register_t* r) override;
/**
* Current size of the instructions.
*/