Preparation for building instructions
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
|
// Absolute Types
|
||||||
using u8 = std::uint8_t;
|
using u8 = std::uint8_t;
|
||||||
using u16 = std::uint16_t;
|
using u16 = std::uint16_t;
|
||||||
using u32 = std::uint32_t;
|
using u32 = std::uint32_t;
|
||||||
@@ -25,6 +26,9 @@ namespace spider {
|
|||||||
static_assert(sizeof(f32) == 4, "The f32 type must be exactly 4 bytes.");
|
static_assert(sizeof(f32) == 4, "The f32 type must be exactly 4 bytes.");
|
||||||
static_assert(sizeof(f64) == 8, "The f64 type must be exactly 8 bytes.");
|
static_assert(sizeof(f64) == 8, "The f64 type must be exactly 8 bytes.");
|
||||||
|
|
||||||
|
// Utility types
|
||||||
|
using isize = std::size_t;
|
||||||
|
|
||||||
// Utility imports
|
// Utility imports
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::deque;
|
using std::deque;
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ namespace spider {
|
|||||||
R2{}, R3{}, R4{}, R5{},
|
R2{}, R3{}, R4{}, R5{},
|
||||||
R6{}, R7{}, R8{}, R9{},
|
R6{}, R7{}, R8{}, R9{},
|
||||||
RF{}, RI{}, RS{}, RZ{},
|
RF{}, RI{}, RS{}, RZ{},
|
||||||
RE{}, RN{}, RV{}, RM{}
|
RE{}, RN{}, RV{}, RM{},
|
||||||
|
ALU0{}, ALU1{}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
CPU::~CPU() {}
|
CPU::~CPU() {}
|
||||||
|
|||||||
@@ -1,16 +1,64 @@
|
|||||||
#include "InstrReel.hpp"
|
#include "InstrReel.hpp"
|
||||||
|
|
||||||
|
#include <spider/runtime/cpu/CPU.hpp>
|
||||||
|
|
||||||
|
#include <spider/runtime/memory/Types.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
InstrReel::InstrReel() {}
|
// Public Interface //
|
||||||
|
|
||||||
|
InstrReel::InstrReel() : _mem(nullptr), _size(0), _offset(0), _total_size(0) {}
|
||||||
|
|
||||||
InstrReel::~InstrReel() {}
|
InstrReel::~InstrReel() {}
|
||||||
|
|
||||||
u16 InstrReel::instrAt(u64 ip) const {}
|
// Instruction abstraction //
|
||||||
|
|
||||||
u8 InstrReel::dataAt(u64 ip) const {}
|
u8 InstrReel::atU8(u64 ip) {
|
||||||
|
// guard against access
|
||||||
|
u64 ip_p = ip - _offset;
|
||||||
|
if(ip_p + 1 > _size) return 0;
|
||||||
|
|
||||||
u8 InstrReel::feedNext(CPU& cpu) {}
|
// send byte
|
||||||
|
return _mem[ip];
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 InstrReel::atU16(u64 ip) {
|
||||||
|
// guard against access
|
||||||
|
u64 ip_p = ip - _offset;
|
||||||
|
if(ip_p + 2 > _size) return 0;
|
||||||
|
|
||||||
|
// build a 16-bit big endian number
|
||||||
|
u16 dat;
|
||||||
|
spider::loadLE(&dat, _mem + ip_p);
|
||||||
|
return dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 InstrReel::atU32(u64 ip) {
|
||||||
|
// guard against access
|
||||||
|
u64 ip_p = ip - _offset;
|
||||||
|
if(ip_p + 4 > _size) return 0;
|
||||||
|
|
||||||
|
// build a 32-bit big endian number
|
||||||
|
u32 dat;
|
||||||
|
spider::loadLE(&dat, _mem + ip_p);
|
||||||
|
return dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 InstrReel::atU64(u64 ip) {
|
||||||
|
// guard against access
|
||||||
|
u64 ip_p = ip - _offset;
|
||||||
|
if(ip_p + 8 > _size) return 0;
|
||||||
|
|
||||||
|
// build a 64-bit big endian number
|
||||||
|
u64 dat;
|
||||||
|
spider::loadLE(&dat, _mem + ip_p);
|
||||||
|
return dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 InstrReel::size() {
|
||||||
|
return _total_size;
|
||||||
|
}
|
||||||
|
|
||||||
// Static Utils //
|
// Static Utils //
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <spider/SpiderRuntime.hpp>
|
#include <spider/SpiderRuntime.hpp>
|
||||||
|
#include <spider/runtime/memory/ByteArray.hpp>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
@@ -8,43 +9,57 @@ namespace spider {
|
|||||||
* Implements an instruction reel.
|
* Implements an instruction reel.
|
||||||
*/
|
*/
|
||||||
class InstrReel {
|
class InstrReel {
|
||||||
private:
|
protected: // Current accessing range //
|
||||||
|
|
||||||
|
u8* _mem;
|
||||||
|
isize _size;
|
||||||
|
isize _offset;
|
||||||
|
isize _total_size;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
InstrReel();
|
InstrReel();
|
||||||
|
|
||||||
~InstrReel();
|
virtual ~InstrReel();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the two-byte instruction at the
|
|
||||||
* specific byte location.
|
|
||||||
*/
|
|
||||||
u16 instrAt(u64 ip) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a byte of data at
|
* Obtains a byte of data at
|
||||||
* the specific location.
|
* the specific location.
|
||||||
|
* Reindexing may occur, continous access
|
||||||
|
* may incurr in less penalties.
|
||||||
*/
|
*/
|
||||||
u8 dataAt(u64 ip) const;
|
virtual u8 atU8(u64 ip);
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the data, and then
|
* Obtains a byte of data at
|
||||||
* feeds the instruction into the
|
* the specific location.
|
||||||
* CPU.
|
* Reindexing may occur, continous access
|
||||||
*
|
* may incurr in less penalties.
|
||||||
* Returns how many steps it should
|
|
||||||
* move after.
|
|
||||||
*/
|
*/
|
||||||
u8 feedNext(CPU& cpu);
|
virtual u16 atU16(u64 ip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains a byte of data at
|
||||||
|
* the specific location.
|
||||||
|
* Reindexing may occur, continous access
|
||||||
|
* may incurr in less penalties.
|
||||||
|
*/
|
||||||
|
virtual u32 atU32(u64 ip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains a byte of data at
|
||||||
|
* the specific location.
|
||||||
|
* Reindexing may occur, continous access
|
||||||
|
* may incurr in less penalties.
|
||||||
|
*/
|
||||||
|
virtual u64 atU64(u64 ip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current size of the instructions.
|
||||||
|
*/
|
||||||
|
virtual u64 size();
|
||||||
|
|
||||||
public: // Static Utils //
|
public: // Static Utils //
|
||||||
|
|
||||||
|
|||||||
192
src/spider/runtime/cpu/InstrReelDyn.cpp
Normal file
192
src/spider/runtime/cpu/InstrReelDyn.cpp
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
#include "InstrReelDyn.hpp"
|
||||||
|
|
||||||
|
#include <spider/runtime/memory/Types.hpp>
|
||||||
|
|
||||||
|
namespace spider {
|
||||||
|
|
||||||
|
InstrReelDyn::InstrReelDyn(u64 length) : _use_count(0), _block_index(0) {
|
||||||
|
_total_size = length;
|
||||||
|
growToFit(length > 0 ? length - 1 : 0);
|
||||||
|
selectBlock(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
InstrReelDyn::InstrReelDyn(const u8* data, u64 length) {}
|
||||||
|
|
||||||
|
InstrReelDyn::InstrReelDyn(const InstrReelDyn& copy) : _use_count(copy._use_count), _block_index(copy._block_index), _blocks(copy._blocks) {
|
||||||
|
if (_block_index < _blocks.size()) selectBlock(_block_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
InstrReelDyn::InstrReelDyn(InstrReelDyn&& move) noexcept : _use_count(move._use_count), _block_index(move._block_index), _blocks(std::move(move._blocks)) {
|
||||||
|
if (_block_index < _blocks.size()) selectBlock(_block_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
InstrReelDyn::~InstrReelDyn() {
|
||||||
|
// .. //
|
||||||
|
}
|
||||||
|
|
||||||
|
InstrReelDyn& InstrReelDyn::operator=(const InstrReelDyn& copy) {
|
||||||
|
_use_count = copy._use_count;
|
||||||
|
_block_index = copy._block_index;
|
||||||
|
_blocks = copy._blocks;
|
||||||
|
if (_block_index < _blocks.size()) selectBlock(_block_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
InstrReelDyn& InstrReelDyn::operator=(InstrReelDyn&& move) noexcept {
|
||||||
|
_use_count = move._use_count;
|
||||||
|
_block_index = move._block_index;
|
||||||
|
_blocks = std::move(move._blocks);
|
||||||
|
if (_block_index < _blocks.size()) selectBlock(_block_index);
|
||||||
|
|
||||||
|
move._use_count = 0;
|
||||||
|
move._block_index = 0;
|
||||||
|
move._mem = nullptr;
|
||||||
|
move._offset = 0;
|
||||||
|
move._size = 0;
|
||||||
|
move._total_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstrReelDyn::growToFit(isize index) {
|
||||||
|
while (_blocks.size() < (index + 1)) {
|
||||||
|
_blocks.emplace_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isize InstrReelDyn::selectIndex(u64 ip) {
|
||||||
|
return ip / 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstrReelDyn::ReelBlock* InstrReelDyn::selectBlock(isize index) {
|
||||||
|
// Update base class cache
|
||||||
|
auto ptr = &_blocks[index];
|
||||||
|
_offset = index * 256;
|
||||||
|
_mem = ptr->data;
|
||||||
|
_size = 256;
|
||||||
|
_block_index = index;
|
||||||
|
|
||||||
|
//_blocks[block_idx].access_count++;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 InstrReelDyn::atU8(u64 ip) {
|
||||||
|
isize j = selectIndex(ip);
|
||||||
|
if (j >= _blocks.size()) return 0;
|
||||||
|
if (j != _block_index) {
|
||||||
|
this->selectBlock(j);
|
||||||
|
}
|
||||||
|
return _mem[ip - _offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 InstrReelDyn::atU16(u64 ip) {
|
||||||
|
isize j0 = selectIndex(ip);
|
||||||
|
isize j1 = selectIndex(ip + 1);
|
||||||
|
if (j1 >= _blocks.size()) return 0;
|
||||||
|
if (j0 == j1 && j0 != _block_index) {
|
||||||
|
selectBlock(j0);
|
||||||
|
}
|
||||||
|
if (j0 == j1 && j0 == _block_index) {
|
||||||
|
u16 dat;
|
||||||
|
spider::loadLE(&dat, _mem);
|
||||||
|
return dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
// general case, first part
|
||||||
|
u16 dat = 0;
|
||||||
|
const u8 size = sizeof(u16);
|
||||||
|
|
||||||
|
// select first block and offset
|
||||||
|
selectBlock(j0);
|
||||||
|
u8 rem = ip % 256;
|
||||||
|
|
||||||
|
for (u8 n = 0; n < size; n++) {
|
||||||
|
dat |= _mem[rem++] << (n * 8);
|
||||||
|
ip++;
|
||||||
|
if (!rem) selectBlock(++j0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 InstrReelDyn::atU32(u64 ip) {
|
||||||
|
isize j0 = selectIndex(ip);
|
||||||
|
isize j1 = selectIndex(ip + 3);
|
||||||
|
if (j1 >= _blocks.size()) return 0;
|
||||||
|
if (j0 == j1 && j0 != _block_index) {
|
||||||
|
selectBlock(j0);
|
||||||
|
}
|
||||||
|
if (j0 == j1 && j0 == _block_index) {
|
||||||
|
u32 dat;
|
||||||
|
spider::loadLE(&dat, _mem);
|
||||||
|
return dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
// general case, first part
|
||||||
|
u32 dat = 0;
|
||||||
|
const u8 size = sizeof(u32);
|
||||||
|
|
||||||
|
// select first block and offset
|
||||||
|
selectBlock(j0);
|
||||||
|
u8 rem = ip % 256;
|
||||||
|
|
||||||
|
for (u8 n = 0; n < size; n++) {
|
||||||
|
dat |= _mem[rem++] << (n * 8);
|
||||||
|
ip++;
|
||||||
|
if (!rem) selectBlock(++j0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 InstrReelDyn::atU64(u64 ip) {
|
||||||
|
isize j0 = selectIndex(ip);
|
||||||
|
isize j1 = selectIndex(ip + 3);
|
||||||
|
if (j1 >= _blocks.size()) return 0;
|
||||||
|
if (j0 == j1 && j0 != _block_index) {
|
||||||
|
selectBlock(j0);
|
||||||
|
}
|
||||||
|
if (j0 == j1 && j0 == _block_index) {
|
||||||
|
u64 dat;
|
||||||
|
spider::loadLE(&dat, _mem);
|
||||||
|
return dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
// general case, first part
|
||||||
|
u64 dat = 0;
|
||||||
|
const u8 size = sizeof(u64);
|
||||||
|
|
||||||
|
// select first block and offset
|
||||||
|
selectBlock(j0);
|
||||||
|
u8 rem = ip % 256;
|
||||||
|
|
||||||
|
for (u8 n = 0; n < size; n++) {
|
||||||
|
dat |= _mem[rem++] << (n * 8);
|
||||||
|
ip++;
|
||||||
|
if (!rem) selectBlock(++j0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstrReelDyn::at(u64 ip, u8 dat) {}
|
||||||
|
|
||||||
|
void InstrReelDyn::at(u64 ip, u16 dat) {}
|
||||||
|
|
||||||
|
void InstrReelDyn::at(u64 ip, u32 dat) {}
|
||||||
|
|
||||||
|
void InstrReelDyn::at(u64 ip, u64 dat) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends instruction at location.
|
||||||
|
*/
|
||||||
|
void InstrReelDyn::append(u64 ip, u16 bc) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends instruction at the end.
|
||||||
|
*/
|
||||||
|
void InstrReelDyn::append(u16 bc) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes instruction at location.
|
||||||
|
*/
|
||||||
|
void InstrReelDyn::remove(u64 ip) {}
|
||||||
|
|
||||||
|
}
|
||||||
110
src/spider/runtime/cpu/InstrReelDyn.hpp
Normal file
110
src/spider/runtime/cpu/InstrReelDyn.hpp
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spider/runtime/cpu/InstrReel.hpp>
|
||||||
|
|
||||||
|
namespace spider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements an instruction reel.
|
||||||
|
*/
|
||||||
|
class InstrReelDyn : public InstrReel {
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct ReelBlock {
|
||||||
|
u8 data[256] = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
u64 _use_count;
|
||||||
|
isize _block_index;
|
||||||
|
std::deque<ReelBlock> _blocks;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
InstrReelDyn(u64 length);
|
||||||
|
|
||||||
|
InstrReelDyn(const u8* data, u64 length);
|
||||||
|
|
||||||
|
InstrReelDyn(const InstrReelDyn& copy);
|
||||||
|
|
||||||
|
InstrReelDyn(InstrReelDyn&& move) noexcept;
|
||||||
|
|
||||||
|
virtual ~InstrReelDyn();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
InstrReelDyn& operator=(const InstrReelDyn& copy);
|
||||||
|
|
||||||
|
InstrReelDyn& operator=(InstrReelDyn&& move) noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
isize selectIndex(u64 ip);
|
||||||
|
|
||||||
|
void growToFit(isize index);
|
||||||
|
|
||||||
|
ReelBlock* selectBlock(isize index);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains a byte of data at
|
||||||
|
* the specific location.
|
||||||
|
* Reindexing may occur, continous access
|
||||||
|
* may incurr in less penalties.
|
||||||
|
*/
|
||||||
|
virtual u8 atU8(u64 ip) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains a byte of data at
|
||||||
|
* the specific location.
|
||||||
|
* Reindexing may occur, continous access
|
||||||
|
* may incurr in less penalties.
|
||||||
|
*/
|
||||||
|
virtual u16 atU16(u64 ip) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains a byte of data at
|
||||||
|
* the specific location.
|
||||||
|
* Reindexing may occur, continous access
|
||||||
|
* may incurr in less penalties.
|
||||||
|
*/
|
||||||
|
virtual u32 atU32(u64 ip) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains a byte of data at
|
||||||
|
* the specific location.
|
||||||
|
* Reindexing may occur, continous access
|
||||||
|
* may incurr in less penalties.
|
||||||
|
*/
|
||||||
|
virtual u64 atU64(u64 ip) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void at(u64 ip, u8 dat);
|
||||||
|
|
||||||
|
void at(u64 ip, u16 dat);
|
||||||
|
|
||||||
|
void at(u64 ip, u32 dat);
|
||||||
|
|
||||||
|
void at(u64 ip, u64 dat);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends instruction at location.
|
||||||
|
*/
|
||||||
|
void append(u64 ip, u16 bc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends instruction at the end.
|
||||||
|
*/
|
||||||
|
void append(u16 bc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes instruction at location.
|
||||||
|
*/
|
||||||
|
void remove(u64 ip);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
0
src/spider/runtime/cpu/InstrReelFile.hpp
Normal file
0
src/spider/runtime/cpu/InstrReelFile.hpp
Normal file
149
src/spider/runtime/cpu/InstrReelFixed.cpp
Normal file
149
src/spider/runtime/cpu/InstrReelFixed.cpp
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
#include "InstrReelFixed.hpp"
|
||||||
|
|
||||||
|
#include <spider/runtime/memory/Types.hpp>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace spider {
|
||||||
|
|
||||||
|
// Constructors & Destructors //
|
||||||
|
|
||||||
|
InstrReelFixed::InstrReelFixed(u64 length) {
|
||||||
|
this->_offset = 0;
|
||||||
|
this->_size = length;
|
||||||
|
this->_total_size = length;
|
||||||
|
|
||||||
|
if (_size > 0) {
|
||||||
|
_mem = new u8[_size];
|
||||||
|
std::memset(_mem, 0, _size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InstrReelFixed::InstrReelFixed(const u8* data, u64 length) {
|
||||||
|
this->_offset = 0;
|
||||||
|
this->_size = length;
|
||||||
|
this->_total_size = length;
|
||||||
|
|
||||||
|
if (_size > 0) {
|
||||||
|
_mem = new u8[_size];
|
||||||
|
std::copy(data, data + _size, _mem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InstrReelFixed::InstrReelFixed(const InstrReelFixed& other) {
|
||||||
|
_offset = other._offset;
|
||||||
|
_size = other._size;
|
||||||
|
_total_size = other._total_size;
|
||||||
|
_mem = new u8[_size];
|
||||||
|
std::copy(other._mem, other._mem + _size, _mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
InstrReelFixed::InstrReelFixed(InstrReelFixed&& other) noexcept {
|
||||||
|
_mem = other._mem;
|
||||||
|
_offset = other._offset;
|
||||||
|
_size = other._size;
|
||||||
|
_total_size = other._total_size;
|
||||||
|
|
||||||
|
other._mem = nullptr;
|
||||||
|
other._offset = 0;
|
||||||
|
other._size = 0;
|
||||||
|
other._total_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstrReelFixed::~InstrReelFixed() {
|
||||||
|
delete[] _mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign Operators //
|
||||||
|
|
||||||
|
InstrReelFixed& InstrReelFixed::operator=(const InstrReelFixed& 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;
|
||||||
|
_offset = other._offset;
|
||||||
|
_size = other._size;
|
||||||
|
_total_size = other._total_size;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstrReelFixed& InstrReelFixed::operator=(InstrReelFixed&& other) noexcept {
|
||||||
|
if (this == &other) return *this; // lock self
|
||||||
|
|
||||||
|
delete[] _mem;
|
||||||
|
|
||||||
|
_mem = other._mem; // steal
|
||||||
|
_offset = other._offset;
|
||||||
|
_size = other._size;
|
||||||
|
_total_size = other._total_size;
|
||||||
|
|
||||||
|
other._mem = nullptr; // leave as husk
|
||||||
|
other._offset = 0;
|
||||||
|
other._size = 0;
|
||||||
|
other._total_size = 0;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Misc //
|
||||||
|
|
||||||
|
void InstrReelFixed::at(u64 ip, u8 dat) {
|
||||||
|
if(ip + 1 > _size) return;
|
||||||
|
_mem[ip] = dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstrReelFixed::at(u64 ip, u16 dat) {
|
||||||
|
if(ip + 2 > _size) return;
|
||||||
|
spider::storeLE(dat, _mem + ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstrReelFixed::at(u64 ip, u32 dat) {
|
||||||
|
if(ip + 4 > _size) return;
|
||||||
|
spider::storeLE(dat, _mem + ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstrReelFixed::at(u64 ip, u64 dat) {
|
||||||
|
if(ip + 8 > _size) return;
|
||||||
|
spider::storeLE(dat, _mem + ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstrReelFixed::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;
|
||||||
|
_total_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;
|
||||||
|
_total_size = new_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
43
src/spider/runtime/cpu/InstrReelFixed.hpp
Normal file
43
src/spider/runtime/cpu/InstrReelFixed.hpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spider/runtime/cpu/InstrReel.hpp>
|
||||||
|
|
||||||
|
namespace spider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements an instruction reel.
|
||||||
|
*/
|
||||||
|
class InstrReelFixed : public InstrReel {
|
||||||
|
public:
|
||||||
|
|
||||||
|
InstrReelFixed(u64 length);
|
||||||
|
|
||||||
|
InstrReelFixed(const u8* data, u64 length);
|
||||||
|
|
||||||
|
InstrReelFixed(const InstrReelFixed& copy);
|
||||||
|
|
||||||
|
InstrReelFixed(InstrReelFixed&& move) noexcept;
|
||||||
|
|
||||||
|
virtual ~InstrReelFixed();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
InstrReelFixed& operator=(const InstrReelFixed& copy);
|
||||||
|
|
||||||
|
InstrReelFixed& operator=(InstrReelFixed&& move) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void at(u64 ip, u8 dat);
|
||||||
|
|
||||||
|
void at(u64 ip, u16 dat);
|
||||||
|
|
||||||
|
void at(u64 ip, u32 dat);
|
||||||
|
|
||||||
|
void at(u64 ip, u64 dat);
|
||||||
|
|
||||||
|
void resize(u64 new_size);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,33 +2,45 @@
|
|||||||
|
|
||||||
#include <spider/runtime/Runtime.hpp>
|
#include <spider/runtime/Runtime.hpp>
|
||||||
#include <spider/runtime/util/Terminal.hpp>
|
#include <spider/runtime/util/Terminal.hpp>
|
||||||
|
#include <spider/runtime/native/distro.hpp>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <format>
|
||||||
|
#include <thread>
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
void drawHead(Terminal& t) {
|
void drawHead(Terminal& t) {
|
||||||
t.move(1, 1)
|
t.move(1, 1)
|
||||||
.style(Terminal::RESET)
|
.style(Terminal::FG_YELLOW)
|
||||||
.print(" Spider Runtime Live Debug ")
|
.print(" Spider Runtime Live Debug ")
|
||||||
.style(Terminal::RESET).print(" | ")
|
.style(Terminal::RESET).print(" | ")
|
||||||
.style(Terminal::FG_CYAN).print(" Sintek Analytics @ 2026 ")
|
.style(Terminal::FG_B_CYAN).print(" Sintek Analytics @ 2026 ")
|
||||||
.style(Terminal::RESET).print(" | ")
|
.style(Terminal::RESET).print(" | ")
|
||||||
.style(Terminal::FG_B_BLACK).print("Press ESC to exit")
|
.style(Terminal::FG_B_BLACK).print("Press ESC to exit")
|
||||||
.style(Terminal::FG_BLACK)
|
.style(Terminal::FG_BLACK)
|
||||||
.style(Terminal::BG_YELLOW)
|
.style(Terminal::BG_YELLOW)
|
||||||
.move(3, 1).print(" || __ ||").print(" ")
|
.move(3, 1).print(" // __ \\\\").print(" ") // 27
|
||||||
.move(4, 1).print(" \\\\( )//").print(" SPIDER v0.1 ")
|
.move(4, 1).print(" \\\\( )//").print(" SPIDER v0.1 ")
|
||||||
.move(5, 1).print(" //()\\\\ ").print(" alpha ")
|
.move(5, 1).print(" //()\\\\ ").print(" alpha ")
|
||||||
.move(6, 1).print(" || || ").print(" ")
|
.move(6, 1).print(" \\\\ // ").print(" ")
|
||||||
|
.style(Terminal::RESET)
|
||||||
|
.style(Terminal::FG_B_BLACK) // 4x8 for the menu
|
||||||
|
.move(3, 28).print("[ STEP ]")
|
||||||
|
.move(4, 28).print("[ STOP ]")
|
||||||
|
.move(5, 28).print("[ RUN ]")
|
||||||
|
.move(6, 28).print("[ MENU ]")
|
||||||
.style(Terminal::RESET)
|
.style(Terminal::RESET)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawCPUTempl(Terminal& t, CPU& cpu) {
|
void drawCPUTempl(Terminal& t, CPU& cpu) {
|
||||||
i32 r = 7, c = 1;
|
i32 r = 8, c = 1;
|
||||||
t.drawBox(r, c, 35, 18, "CPU");
|
i32 w = 35, h = 31;
|
||||||
|
t.drawBox(r, c, w, h, "CPU");
|
||||||
|
|
||||||
const std::string regs[] = {
|
const std::string regs[] = {
|
||||||
"RA", "RB", "RC", "RD",
|
"RA", "RB", "RC", "RD",
|
||||||
@@ -36,47 +48,335 @@ namespace spider {
|
|||||||
"R2", "R3", "R4", "R5",
|
"R2", "R3", "R4", "R5",
|
||||||
"R6", "R7", "R8", "R9",
|
"R6", "R7", "R8", "R9",
|
||||||
"RF", "RI", "RS", "RZ",
|
"RF", "RI", "RS", "RZ",
|
||||||
"RE", "RN", "RV", "RM"
|
"RE", "RN", "RV", "RM",
|
||||||
|
"ALU0", "ALU1"
|
||||||
|
};
|
||||||
|
const std::string alt[] = {
|
||||||
|
Terminal::FG_WHITE,
|
||||||
|
Terminal::FG_B_BLACK,
|
||||||
};
|
};
|
||||||
|
|
||||||
r++;
|
r++;
|
||||||
c++;
|
c++;
|
||||||
|
|
||||||
|
t.move(r++, c);
|
||||||
|
t.style(Terminal::FG_B_YELLOW);
|
||||||
|
t.print_center(w - 2, "GP Registers");
|
||||||
|
t.style(Terminal::RESET);
|
||||||
for (i32 i = 0; i < 8; i++) {
|
for (i32 i = 0; i < 8; i++) {
|
||||||
|
t.style(alt[i & 1]);
|
||||||
t.move(r + i * 2, c);
|
t.move(r + i * 2, c);
|
||||||
t.print(regs[i * 2]);
|
t.print(regs[i * 2]);
|
||||||
t.move(r + i * 2, c + 17);
|
t.move(r + i * 2, c + 17);
|
||||||
t.print(regs[i * 2 + 1]);
|
t.print(regs[i * 2 + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.move(r += 16, c);
|
||||||
|
t.style(Terminal::FG_B_CYAN);
|
||||||
|
t.print_center(w - 2, "System Registers");
|
||||||
|
t.style(Terminal::RESET);
|
||||||
|
r++;
|
||||||
|
for (i32 j = 0, i = 8; i < 12; j++, i++) {
|
||||||
|
t.style(alt[j & 1]);
|
||||||
|
t.move(r + j * 2, c);
|
||||||
|
t.print(regs[i * 2]);
|
||||||
|
t.move(r + j * 2, c + 17);
|
||||||
|
t.print(regs[i * 2 + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
t.move(r += 8, c);
|
||||||
|
t.style(Terminal::FG_GREEN);
|
||||||
|
t.print_center(w - 2, "Extra Registers");
|
||||||
|
t.style(Terminal::RESET);
|
||||||
|
r++;
|
||||||
|
for (i32 j = 0, i = 12; i < 13; j++, i++) {
|
||||||
|
t.style(alt[j & 1]);
|
||||||
|
t.move(r + j * 2, c);
|
||||||
|
t.print(regs[i * 2]);
|
||||||
|
t.move(r + j * 2, c + 17);
|
||||||
|
t.print(regs[i * 2 + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
t.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void printU64Hex(u64 n) {
|
||||||
|
std::ios state(nullptr);
|
||||||
|
state.copyfmt(std::cout);
|
||||||
|
std::cout
|
||||||
|
<< std::hex
|
||||||
|
<< std::uppercase
|
||||||
|
<< std::setfill('0')
|
||||||
|
<< std::setw(16)
|
||||||
|
<< n;
|
||||||
|
std::cout.copyfmt(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawCPU(Terminal& t, CPU& cpu) {
|
||||||
|
i32 r = 8, c = 1;
|
||||||
|
|
||||||
|
const register_t* regs[] = {
|
||||||
|
&cpu.RA, &cpu.RB, &cpu.RC, &cpu.RD,
|
||||||
|
&cpu.RX, &cpu.RY, &cpu.R0, &cpu.R1,
|
||||||
|
&cpu.R2, &cpu.R3, &cpu.R4, &cpu.R5,
|
||||||
|
&cpu.R6, &cpu.R7, &cpu.R8, &cpu.R9,
|
||||||
|
//&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ,
|
||||||
|
//&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM,
|
||||||
|
&cpu.ALU0, &cpu.ALU1
|
||||||
|
};
|
||||||
|
const u64* sys_regs[] = {
|
||||||
|
&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ,
|
||||||
|
&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM,
|
||||||
|
};
|
||||||
|
const std::string alt[] = {
|
||||||
|
Terminal::FG_WHITE,
|
||||||
|
Terminal::FG_B_BLACK,
|
||||||
|
};
|
||||||
|
|
||||||
|
r++;
|
||||||
|
c++;
|
||||||
|
t.move(r++, c);
|
||||||
|
t.style(Terminal::RESET);
|
||||||
|
r++;
|
||||||
|
for (i32 i = 0; i < 8; i++) {
|
||||||
|
t.style(alt[i & 1]);
|
||||||
|
t.move(r + i * 2, c);
|
||||||
|
printU64Hex(regs[i * 2]->_u64);
|
||||||
|
t.move(r + i * 2, c + 17);
|
||||||
|
printU64Hex(regs[i * 2 + 1]->_u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
t.move(r += 16, c);
|
||||||
|
r++;
|
||||||
|
for (i32 j = 0, i = 8; i < 12; j++, i++) {
|
||||||
|
t.style(alt[j & 1]);
|
||||||
|
t.move(r + j * 2, c);
|
||||||
|
printU64Hex(*sys_regs[i * 2]);
|
||||||
|
t.move(r + j * 2, c + 17);
|
||||||
|
printU64Hex(*sys_regs[i * 2 + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
t.move(r += 8, c);
|
||||||
|
r++;
|
||||||
|
for (i32 j = 0; j < 1; j++) {
|
||||||
|
t.style(alt[j & 1]);
|
||||||
|
t.move(r + j * 2, c);
|
||||||
|
printU64Hex(regs[16 + j * 2]->_u64);
|
||||||
|
t.move(r + j * 2, c + 17);
|
||||||
|
printU64Hex(regs[16 + j * 2 + 1]->_u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
t.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 addressWidth(isize ramSize) {
|
||||||
|
if (ramSize == 0) return 1;
|
||||||
|
isize maxAddr = ramSize - 1;
|
||||||
|
i32 digits = 0;
|
||||||
|
// Shift by increments of 4 (one hex nibble)
|
||||||
|
// We use a do-while to ensure at least 1 digit is returned for small RAMs
|
||||||
|
do {
|
||||||
|
digits++;
|
||||||
|
maxAddr >>= 4;
|
||||||
|
} while (maxAddr > 0);
|
||||||
|
|
||||||
|
return digits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a vertical scrollbar
|
||||||
|
* @param x The column where the bar should be placed (usually box_x + width - 1)
|
||||||
|
* @param y The starting row of the track (usually box_y + 1)
|
||||||
|
* @param trackHeight The internal height of the box (box_height - 2)
|
||||||
|
* @param progress The current progress
|
||||||
|
* @param total The total
|
||||||
|
*/
|
||||||
|
void drawScrollThumb(Terminal& term, i32 x, i32 y, i32 trackHeight, isize progress, isize total) {
|
||||||
|
if (total == 0 || trackHeight <= 0) return;
|
||||||
|
|
||||||
|
// 1. Draw the background track (Light Shade: ░)
|
||||||
|
term.style(Terminal::FG_B_BLACK); // Dim the track
|
||||||
|
for (int i = 0; i < trackHeight; ++i) {
|
||||||
|
term.move(y + i, x).print("░");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Calculate Thumb Position
|
||||||
|
// Cap progress to total to avoid overflow
|
||||||
|
if (progress > total) progress = total;
|
||||||
|
|
||||||
|
// Calculate ratio (0.0 to 1.0)
|
||||||
|
f64 ratio = f64(progress) / f64(total);
|
||||||
|
|
||||||
|
// Map to track coordinates
|
||||||
|
i32 thumbOffset = i32(ratio * (trackHeight - 1));
|
||||||
|
|
||||||
|
// 3. Draw the Thumb (Full Block: █)
|
||||||
|
term.move(y + thumbOffset, x);
|
||||||
|
term.style(Terminal::FG_WHITE).print("█");
|
||||||
|
term.style(Terminal::RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a hex dump of memory within a styled terminal box.
|
||||||
|
* @param term Reference to your Terminal instance
|
||||||
|
* @param ram The RAM
|
||||||
|
* @param scrollPos The starting address to display
|
||||||
|
* @param x Starting column
|
||||||
|
* @param y Starting row
|
||||||
|
* @param width Width of the box
|
||||||
|
* @param height Height of the box
|
||||||
|
*/
|
||||||
|
void drawRAM(Terminal& term, RAM& ram, u64 scrollPos) {
|
||||||
|
// 1. Draw the container box
|
||||||
|
i32 y = 3;
|
||||||
|
i32 height = 36;
|
||||||
|
|
||||||
|
// 2. Configuration for the hex layout
|
||||||
|
int addrWidth = addressWidth(ram.size());
|
||||||
|
int bytesPerRow = 8;
|
||||||
|
int displayRows = height - 2; // Subtract top/bottom borders
|
||||||
|
i32 width = (2 + 2 + 16 + 7 + 3 + 8 + 4) + addrWidth;
|
||||||
|
i32 x = 37;
|
||||||
|
|
||||||
|
// create box
|
||||||
|
term.drawBox(y, x, width, height, "RAM");
|
||||||
|
drawScrollThumb(term, x + width - 2, y + 1, height - 2, scrollPos, ram.size());
|
||||||
|
|
||||||
|
// Ensure scrollPos is within bounds and aligned
|
||||||
|
if (scrollPos < 0) scrollPos = 0;
|
||||||
|
if (scrollPos > ram.size()) scrollPos = ram.size();
|
||||||
|
|
||||||
|
for (int i = 0; i < displayRows; ++i) {
|
||||||
|
isize currentRowAddr = scrollPos + (i * bytesPerRow);
|
||||||
|
|
||||||
|
// address lock
|
||||||
|
if (currentRowAddr >= ram.size()) {
|
||||||
|
term.move(y + 1 + i, x + 1);
|
||||||
|
term.print(std::string(width - 3, ' '));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ssaddr;
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
// setup ss
|
||||||
|
ssaddr << std::setfill('0') << std::uppercase << std::hex;
|
||||||
|
ss << std::setfill('0') << std::uppercase << std::hex;
|
||||||
|
|
||||||
|
// address
|
||||||
|
ssaddr << std::setw(addrWidth) << currentRowAddr << " ";
|
||||||
|
|
||||||
|
// Hex Bytes
|
||||||
|
std::string asciiPart = "";
|
||||||
|
for (int j = 0; j < bytesPerRow; ++j) {
|
||||||
|
isize targetAddr = currentRowAddr + j;
|
||||||
|
if (targetAddr >= ram.size()) {
|
||||||
|
ss << ""; // Padding for end of memory
|
||||||
|
asciiPart += "";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 byte = ram[targetAddr];
|
||||||
|
ss << std::setfill('0') << std::setw(2) << std::hex << (u32)byte << " ";
|
||||||
|
asciiPart += (std::isprint(byte) ? (char)byte : '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Combine and Print ---
|
||||||
|
term.move(y + 1 + i, x + 2); // Move inside the box
|
||||||
|
term.style(Terminal::FG_B_CYAN).print(ssaddr.str()); // Hex part in Cyan
|
||||||
|
term.style(Terminal::FG_WHITE).print(ss.str());
|
||||||
|
term.style(Terminal::FG_B_YELLOW).print(" | ");
|
||||||
|
term.style(Terminal::FG_WHITE).print(asciiPart); // ASCII part in White
|
||||||
|
}
|
||||||
|
|
||||||
|
term.style(Terminal::RESET);
|
||||||
|
term.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getTimestamp() {
|
||||||
|
std::time_t t = std::time(nullptr);
|
||||||
|
std::tm lt;
|
||||||
|
#if defined(SPIDER_OS_WINDOWS)
|
||||||
|
localtime_s(<, &t);
|
||||||
|
#endif
|
||||||
|
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
||||||
|
localtime_r(&t, <);
|
||||||
|
#endif
|
||||||
|
return std::format("{:02}:{:02}:{:02} {:02}/{:02}/{}",
|
||||||
|
lt.tm_hour, lt.tm_min, lt.tm_sec,
|
||||||
|
lt.tm_mday, lt.tm_mon + 1, lt.tm_year + 1900);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawTime(Terminal& t) {
|
||||||
|
//auto now = std::chrono::system_clock::now();
|
||||||
|
//auto now_l = std::chrono::current_zone()->to_local(now);
|
||||||
|
//auto now_s = std::chrono::floor<std::chrono::seconds>(now_l);
|
||||||
|
//std::string time_str = std::format("{:%H:%M:%S}", now_s); // Format: HH:mm:ss
|
||||||
|
//std::string date_str = std::format("{:%d/%m/%Y}", now_s); // Format: dd/MM/YYYY
|
||||||
|
|
||||||
|
t.move(1, 76);
|
||||||
|
t.style(Terminal::RESET);
|
||||||
|
t.print(" | ").style(Terminal::FG_GREEN).print(getTimestamp());
|
||||||
|
}
|
||||||
|
|
||||||
|
void redraw(Terminal& t, Runtime& r, u64 scroll) {
|
||||||
|
// draw CPU, RAM
|
||||||
|
drawCPU(t, r.cpu);
|
||||||
|
drawRAM(t, r.ram, scroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
int liveDebugMain() {
|
int liveDebugMain() {
|
||||||
Terminal t;
|
Terminal t;
|
||||||
Runtime runtime(1024);
|
Runtime runtime(1024);
|
||||||
|
|
||||||
|
bool running = true, update = true;
|
||||||
|
u64 ramScroll = 0;
|
||||||
|
u8 key = Terminal::UNKNOWN;
|
||||||
|
|
||||||
t.println("Starting Spider live debug...");
|
t.println("Starting Spider live debug...");
|
||||||
t.altbuff(true).cursor(false);
|
t.altbuff(true).cursor(false);
|
||||||
|
|
||||||
|
drawTime(t);
|
||||||
drawHead(t);
|
drawHead(t);
|
||||||
drawCPUTempl(t, runtime.cpu);
|
drawCPUTempl(t, runtime.cpu);
|
||||||
|
|
||||||
bool running = true;
|
// delay for time
|
||||||
int c = 1;
|
auto last_exec = std::chrono::steady_clock::now();
|
||||||
|
auto delay = std::chrono::milliseconds(1000);
|
||||||
|
|
||||||
while (running) {
|
while (running) {
|
||||||
|
// draw time
|
||||||
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
if (now - last_exec >= delay) {
|
||||||
|
drawTime(t);
|
||||||
|
last_exec = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// redraw something if it updated
|
||||||
|
if (update) {
|
||||||
|
redraw(t, runtime, ramScroll);
|
||||||
|
update = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle Input
|
// Handle Input
|
||||||
u8 k = t.getKey();
|
key = t.getKeyNb();
|
||||||
switch (k) {
|
switch (key) {
|
||||||
case Terminal::ESC:
|
case Terminal::ESC:
|
||||||
running = false;
|
running = false;
|
||||||
break;
|
break;
|
||||||
|
case Terminal::UP:
|
||||||
|
if (ramScroll >= 16) ramScroll -= 16;
|
||||||
|
update = true;
|
||||||
|
break;
|
||||||
|
case Terminal::DOWN:
|
||||||
|
if (runtime.ram.size() >= 16 && ramScroll <= runtime.ram.size() - 16) ramScroll += 16;
|
||||||
|
update = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
t.move(5, c++);
|
|
||||||
t.print("A");
|
|
||||||
t.flush();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
t.altbuff(false).println("Stopped Spider live debug.").flush();
|
t.altbuff(false).println("Stopped Spider live debug.").flush();
|
||||||
|
|||||||
74
src/spider/runtime/memory/ByteArray.cpp
Normal file
74
src/spider/runtime/memory/ByteArray.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "ByteArray.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace spider {
|
||||||
|
|
||||||
|
ByteArray::ByteArray(isize length) : _mem(nullptr), _size(length) {
|
||||||
|
if (_size > 0) {
|
||||||
|
_mem = new u8[_size];
|
||||||
|
std::memset(_mem, 0, _size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArray::ByteArray(const ByteArray& other) : _mem(new u8[other._size]), _size(other._size) {
|
||||||
|
std::copy(other._mem, other._mem + _size, _mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArray::ByteArray(ByteArray&& other) noexcept : _mem(other._mem), _size(other._size) {
|
||||||
|
other._mem = nullptr;
|
||||||
|
other._size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArray::~ByteArray() {
|
||||||
|
delete[] _mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArray& ByteArray::operator=(const ByteArray& 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArray& ByteArray::operator=(ByteArray&& 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8& ByteArray::operator[](isize index) {
|
||||||
|
return _mem[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 ByteArray::operator[](isize index) const {
|
||||||
|
return _mem[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* ByteArray::data() {
|
||||||
|
return _mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8* ByteArray::data() const {
|
||||||
|
return _mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
isize ByteArray::size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
49
src/spider/runtime/memory/ByteArray.hpp
Normal file
49
src/spider/runtime/memory/ByteArray.hpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spider/runtime/common.hpp>
|
||||||
|
|
||||||
|
namespace spider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A general purpose byte array
|
||||||
|
* with RAII semantics.
|
||||||
|
*/
|
||||||
|
class ByteArray {
|
||||||
|
private:
|
||||||
|
|
||||||
|
u8* _mem;
|
||||||
|
isize _size;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ByteArray(isize length);
|
||||||
|
|
||||||
|
ByteArray(const ByteArray& other);
|
||||||
|
|
||||||
|
ByteArray(ByteArray&& other) noexcept;
|
||||||
|
|
||||||
|
~ByteArray();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ByteArray& operator=(const ByteArray& other);
|
||||||
|
|
||||||
|
ByteArray& operator=(ByteArray&& other) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
u8& operator[](isize index);
|
||||||
|
|
||||||
|
u8 operator[](isize index) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
u8* data();
|
||||||
|
|
||||||
|
const u8* data() const;
|
||||||
|
|
||||||
|
isize size() const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -111,4 +111,20 @@ namespace spider {
|
|||||||
return _size;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,16 @@ namespace spider {
|
|||||||
|
|
||||||
u64 size() const;
|
u64 size() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
u8* begin();
|
||||||
|
|
||||||
|
u8* end();
|
||||||
|
|
||||||
|
const u8* begin() const;
|
||||||
|
|
||||||
|
const u8* end() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
248
src/spider/runtime/memory/Types.hpp
Normal file
248
src/spider/runtime/memory/Types.hpp
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spider/runtime/common.hpp>
|
||||||
|
#include <spider/runtime/native/machine.hpp>
|
||||||
|
|
||||||
|
#if __cplusplus >= 202002L
|
||||||
|
#include <bit>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SPIDER_COMPILER_MSVC)
|
||||||
|
#include <cstdlib>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace spider {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file contains cross platform type juggling.
|
||||||
|
* Optimized for each case.
|
||||||
|
*
|
||||||
|
* General assumtions is that unsigned and signed
|
||||||
|
* integers are the exact same bit representation.
|
||||||
|
*
|
||||||
|
* Floats to and from integers is the focus when
|
||||||
|
* juggling.
|
||||||
|
*
|
||||||
|
* Additionally, provides help selecting a specific
|
||||||
|
* type from raw bytes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Utilities //
|
||||||
|
|
||||||
|
#if __cplusplus >= 202002L
|
||||||
|
using std::bit_cast;
|
||||||
|
#else
|
||||||
|
template<typename To, typename From>
|
||||||
|
inline To bit_cast(const From& src) {
|
||||||
|
static_assert(sizeof(To) == sizeof(From), "bit_cast size mismatch");
|
||||||
|
To dst;
|
||||||
|
std::memcpy(&dst, &src, sizeof(To));
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline T byteswap(T v) {
|
||||||
|
static_assert(std::is_integral<T>::value, "byteswap requires integral type");
|
||||||
|
|
||||||
|
using U = std::make_unsigned_t<T>;
|
||||||
|
U u = static_cast<U>(v);
|
||||||
|
|
||||||
|
if constexpr (sizeof(T) == 1) {
|
||||||
|
return v;
|
||||||
|
} else if constexpr (sizeof(T) == 2) {
|
||||||
|
|
||||||
|
#if defined(SPIDER_COMPILER_MSVC)
|
||||||
|
u = _byteswap_ushort(u);
|
||||||
|
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
||||||
|
u = __builtin_bswap16(u);
|
||||||
|
#else
|
||||||
|
u = (u >> 8) | (u << 8);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} else if constexpr (sizeof(T) == 4) {
|
||||||
|
|
||||||
|
#if defined(SPIDER_COMPILER_MSVC)
|
||||||
|
u = _byteswap_ulong(u);
|
||||||
|
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
||||||
|
u = __builtin_bswap32(u);
|
||||||
|
#else
|
||||||
|
u =
|
||||||
|
((u & 0x000000FFu) << 24) |
|
||||||
|
((u & 0x0000FF00u) << 8) |
|
||||||
|
((u & 0x00FF0000u) >> 8) |
|
||||||
|
((u & 0xFF000000u) >> 24);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} else if constexpr (sizeof(T) == 8) {
|
||||||
|
|
||||||
|
#if defined(SPIDER_COMPILER_MSVC)
|
||||||
|
u = _byteswap_uint64(u);
|
||||||
|
#elif defined(SPIDER_COMPILER_GCC_LIKE)
|
||||||
|
u = __builtin_bswap64(u);
|
||||||
|
#else
|
||||||
|
u =
|
||||||
|
((u & 0x00000000000000FFull) << 56) |
|
||||||
|
((u & 0x000000000000FF00ull) << 40) |
|
||||||
|
((u & 0x0000000000FF0000ull) << 24) |
|
||||||
|
((u & 0x00000000FF000000ull) << 8) |
|
||||||
|
((u & 0x000000FF00000000ull) >> 8) |
|
||||||
|
((u & 0x0000FF0000000000ull) >> 24) |
|
||||||
|
((u & 0x00FF000000000000ull) >> 40) |
|
||||||
|
((u & 0xFF00000000000000ull) >> 56);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Generic fallback (rare: non 1/2/4/8-byte types)
|
||||||
|
U result = 0;
|
||||||
|
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||||
|
result |= ((u >> (i * 8)) & 0xFF) << ((sizeof(T) - 1 - i) * 8);
|
||||||
|
}
|
||||||
|
u = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<T>(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store Big Endian //
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void storeBE(T n, u8* bytes) {
|
||||||
|
static_assert(std::is_trivially_copyable<T>::value);
|
||||||
|
#if SPIDER_BIG_ENDIAN
|
||||||
|
std::memcpy(bytes, &n, sizeof(T));
|
||||||
|
#endif
|
||||||
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
|
T tmp = byteswap(n);
|
||||||
|
std::memcpy(bytes, &tmp, sizeof(T));
|
||||||
|
#endif
|
||||||
|
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
||||||
|
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||||
|
bytes[i] = static_cast<u8>(
|
||||||
|
(static_cast<std::make_unsigned_t<T>>(n) >> ((sizeof(T) - 1 - i) * 8)) & 0xFF
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void storeBE<f32>(f32 n, u8* bytes) {
|
||||||
|
u32 tmp = bit_cast<u32>(n);
|
||||||
|
storeBE(tmp, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void storeBE<f64>(f64 n, u8* bytes) {
|
||||||
|
u64 tmp = bit_cast<u64>(n);
|
||||||
|
storeBE(tmp, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Big Endian //
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void loadBE(T* n, const u8* bytes) {
|
||||||
|
static_assert(std::is_trivially_copyable<T>::value);
|
||||||
|
#if SPIDER_BIG_ENDIAN
|
||||||
|
std::memcpy(n, bytes, sizeof(T));
|
||||||
|
#endif
|
||||||
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
|
T tmp;
|
||||||
|
std::memcpy(&tmp, bytes, sizeof(T));
|
||||||
|
*n = bswap(tmp);
|
||||||
|
#endif
|
||||||
|
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
||||||
|
using U = std::make_unsigned_t<T>;
|
||||||
|
U result = 0;
|
||||||
|
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||||
|
result |= static_cast<U>(bytes[i]) << ((sizeof(T) - 1 - i) * 8);
|
||||||
|
}
|
||||||
|
*n = static_cast<T>(result);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void loadBE<f32>(f32* n, const u8* bytes) {
|
||||||
|
u32 tmp;
|
||||||
|
loadBE(&tmp, bytes);
|
||||||
|
*n = bit_cast<f32>(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void loadBE<f64>(f64* n, const u8* bytes) {
|
||||||
|
u64 tmp;
|
||||||
|
loadBE(&tmp, bytes);
|
||||||
|
*n = bit_cast<f64>(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store Little Endian //
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
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));
|
||||||
|
#endif
|
||||||
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
|
std::memcpy(bytes, &n, sizeof(T));
|
||||||
|
#endif
|
||||||
|
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
||||||
|
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||||
|
bytes[i] = static_cast<u8>(
|
||||||
|
(static_cast<std::make_unsigned_t<T>>(n) >> (i * 8)) & 0xFF
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void storeLE<f32>(f32 n, u8* bytes) {
|
||||||
|
u32 tmp = bit_cast<u32>(n);
|
||||||
|
storeLE(tmp, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void storeLE<f64>(f64 n, u8* bytes) {
|
||||||
|
u64 tmp = bit_cast<u64>(n);
|
||||||
|
storeLE(tmp, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Little Endian //
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void loadLE(T* n, const u8* bytes) {
|
||||||
|
static_assert(std::is_trivially_copyable<T>::value);
|
||||||
|
#if SPIDER_BIG_ENDIAN
|
||||||
|
std::memcpy(n, bytes, sizeof(T));
|
||||||
|
#endif
|
||||||
|
#if SPIDER_LITTLE_ENDIAN
|
||||||
|
T tmp;
|
||||||
|
std::memcpy(&tmp, bytes, sizeof(T));
|
||||||
|
*n = bswap(tmp);
|
||||||
|
#endif
|
||||||
|
#if !SPIDER_BIG_ENDIAN && !SPIDER_LITTLE_ENDIAN
|
||||||
|
using U = std::make_unsigned_t<T>;
|
||||||
|
U result = 0;
|
||||||
|
for (size_t i = 0; i < sizeof(T); ++i) {
|
||||||
|
result |= static_cast<U>(bytes[i]) << (i * 8);
|
||||||
|
}
|
||||||
|
*n = static_cast<T>(result);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void loadLE<f32>(f32* n, const u8* bytes) {
|
||||||
|
u32 tmp;
|
||||||
|
loadLE(&tmp, bytes);
|
||||||
|
*n = bit_cast<f32>(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline void loadLE<f64>(f64* n, const u8* bytes) {
|
||||||
|
u64 tmp;
|
||||||
|
loadLE(&tmp, bytes);
|
||||||
|
*n = bit_cast<f64>(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -58,7 +58,6 @@
|
|||||||
// (not used now) //
|
// (not used now) //
|
||||||
// ========================================================== //
|
// ========================================================== //
|
||||||
|
|
||||||
|
|
||||||
// Find out what compiler the user is using
|
// Find out what compiler the user is using
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
#define SPIDER_COMPILER_CLANG
|
#define SPIDER_COMPILER_CLANG
|
||||||
|
|||||||
@@ -17,10 +17,45 @@
|
|||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
|
// Style //
|
||||||
|
const char* Terminal::RESET = "\033[0m";
|
||||||
|
const char* Terminal::BOLD = "\033[1m";
|
||||||
|
const char* Terminal::ITALIC = "\033[3m";
|
||||||
|
const char* Terminal::FAINT = "\033[2m";
|
||||||
|
const char* Terminal::STRIKE = "\033[9m";
|
||||||
|
|
||||||
|
// Foreground //
|
||||||
|
const char* Terminal::FG_BLACK = "\033[30m"; const char* Terminal::FG_B_BLACK = "\033[90m";
|
||||||
|
const char* Terminal::FG_RED = "\033[31m"; const char* Terminal::FG_B_RED = "\033[91m";
|
||||||
|
const char* Terminal::FG_GREEN = "\033[32m"; const char* Terminal::FG_B_GREEN = "\033[92m";
|
||||||
|
const char* Terminal::FG_YELLOW = "\033[33m"; const char* Terminal::FG_B_YELLOW = "\033[93m";
|
||||||
|
const char* Terminal::FG_BLUE = "\033[34m"; const char* Terminal::FG_B_BLUE = "\033[94m";
|
||||||
|
const char* Terminal::FG_MAGENTA = "\033[35m"; const char* Terminal::FG_B_MAGENTA = "\033[95m";
|
||||||
|
const char* Terminal::FG_CYAN = "\033[36m"; const char* Terminal::FG_B_CYAN = "\033[96m";
|
||||||
|
const char* Terminal::FG_WHITE = "\033[37m"; const char* Terminal::FG_B_WHITE = "\033[97m";
|
||||||
|
|
||||||
|
// Background //
|
||||||
|
const char* Terminal::BG_BLACK = "\033[40m"; const char* Terminal::BG_B_BLACK = "\033[100m";
|
||||||
|
const char* Terminal::BG_RED = "\033[41m"; const char* Terminal::BG_B_RED = "\033[101m";
|
||||||
|
const char* Terminal::BG_GREEN = "\033[42m"; const char* Terminal::BG_B_GREEN = "\033[102m";
|
||||||
|
const char* Terminal::BG_YELLOW = "\033[43m"; const char* Terminal::BG_B_YELLOW = "\033[103m";
|
||||||
|
const char* Terminal::BG_BLUE = "\033[44m"; const char* Terminal::BG_B_BLUE = "\033[104m";
|
||||||
|
const char* Terminal::BG_MAGENTA = "\033[45m"; const char* Terminal::BG_B_MAGENTA = "\033[105m";
|
||||||
|
const char* Terminal::BG_CYAN = "\033[46m"; const char* Terminal::BG_B_CYAN = "\033[106m";
|
||||||
|
const char* Terminal::BG_WHITE = "\033[47m"; const char* Terminal::BG_B_WHITE = "\033[107m";
|
||||||
|
|
||||||
Terminal::Terminal() {
|
Terminal::Terminal() {
|
||||||
#if defined(SPIDER_OS_WINDOWS)
|
#if defined(SPIDER_OS_WINDOWS)
|
||||||
|
// Enable UTF-8
|
||||||
SetConsoleOutputCP(CP_UTF8);
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
SetConsoleCP(CP_UTF8);
|
SetConsoleCP(CP_UTF8);
|
||||||
|
|
||||||
|
// enable vtp
|
||||||
|
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
DWORD dwMode = 0;
|
||||||
|
GetConsoleMode(hOut, &dwMode);
|
||||||
|
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
SetConsoleMode(hOut, dwMode);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +172,7 @@ namespace spider {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<i32, i32> Terminal::size() {
|
std::pair<i32, i32> Terminal::getSize() {
|
||||||
std::pair<i32, i32> pair;
|
std::pair<i32, i32> pair;
|
||||||
#if defined(SPIDER_OS_WINDOWS)
|
#if defined(SPIDER_OS_WINDOWS)
|
||||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
@@ -171,6 +206,7 @@ namespace spider {
|
|||||||
case 80: return Terminal::DOWN;
|
case 80: return Terminal::DOWN;
|
||||||
case 75: return Terminal::LEFT;
|
case 75: return Terminal::LEFT;
|
||||||
case 77: return Terminal::RIGHT;
|
case 77: return Terminal::RIGHT;
|
||||||
|
default: return Terminal::UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ch == 13) return Terminal::ENTER;
|
if (ch == 13) return Terminal::ENTER;
|
||||||
@@ -185,24 +221,54 @@ namespace spider {
|
|||||||
newt.c_lflag &= ~(ICANON | ECHO);
|
newt.c_lflag &= ~(ICANON | ECHO);
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
||||||
|
|
||||||
u8 chd = Terminal::UNKNOWN;
|
u8 result = Terminal::UNKNOWN;
|
||||||
i32 ch = getchar();
|
int ch = getchar();
|
||||||
if (ch == 27) { // ESC sequence
|
|
||||||
|
if (ch == 27) { // Potential Escape Sequence
|
||||||
|
// Use a small timeout or check if more chars are in buffer
|
||||||
|
// to distinguish between 'Esc' key and 'Arrow' sequence
|
||||||
|
// Another Win for the Win API
|
||||||
|
struct timeval tv = { 0, 10000 }; // 10ms wait
|
||||||
|
fd_set fds;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(STDIN_FILENO, &fds);
|
||||||
|
|
||||||
|
if (select(1, &fds, NULL, NULL, &tv) > 0) {
|
||||||
if (getchar() == '[') {
|
if (getchar() == '[') {
|
||||||
switch (getchar()) {
|
switch (getchar()) {
|
||||||
case 'A': chd = Terminal::UP; break;
|
case 'A': result = Terminal::UP; break;
|
||||||
case 'B': chd = Terminal::DOWN; break;
|
case 'B': result = Terminal::DOWN; break;
|
||||||
case 'D': chd = Terminal::LEFT; break;
|
case 'D': result = Terminal::LEFT; break;
|
||||||
case 'C': chd = Terminal::RIGHT; break;
|
case 'C': result = Terminal::RIGHT; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
result = Terminal::ESC;
|
||||||
}
|
}
|
||||||
else if (ch == 10) chd = Terminal::ENTER;
|
} else if (ch == 10) result = Terminal::ENTER;
|
||||||
else if (ch == 127) chd = Terminal::BACKSPACE;
|
else if (ch == 127) result = Terminal::BACKSPACE;
|
||||||
|
else result = (u8)ch;
|
||||||
|
|
||||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||||
|
return result;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
return chd;
|
u8 Terminal::getKeyNb() {
|
||||||
|
#if defined(SPIDER_OS_WINDOWS)
|
||||||
|
if (_kbhit()) return getKey();
|
||||||
|
return Terminal::UNKNOWN;
|
||||||
|
#endif
|
||||||
|
#if defined(SPIDER_OS_LINUX) || defined(SPIDER_OS_MACOS)
|
||||||
|
struct timeval tv = { 0, 0 };
|
||||||
|
fd_set fds;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(STDIN_FILENO, &fds);
|
||||||
|
// select() returns > 0 if there is data to read
|
||||||
|
if (select(1, &fds, NULL, NULL, &tv) > 0) {
|
||||||
|
return getKey();
|
||||||
|
}
|
||||||
|
return Terminal::UNKNOWN;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,43 +5,48 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <limits>
|
#include <sstream>
|
||||||
|
|
||||||
namespace spider {
|
namespace spider {
|
||||||
|
|
||||||
class Terminal {
|
class Terminal {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// --- Constants ---
|
static const char* RESET;
|
||||||
static constexpr const char* RESET = "\033[0m";
|
static const char* BOLD;
|
||||||
static constexpr const char* FG_BLACK = "\033[30m"; static constexpr const char* FG_B_BLACK = "\033[90m";
|
static const char* ITALIC;
|
||||||
static constexpr const char* FG_RED = "\033[31m"; static constexpr const char* FG_B_RED = "\033[91m";
|
static const char* FAINT;
|
||||||
static constexpr const char* FG_GREEN = "\033[32m"; static constexpr const char* FG_B_GREEN = "\033[92m";
|
static const char* STRIKE;
|
||||||
static constexpr const char* FG_YELLOW = "\033[33m"; static constexpr const char* FG_B_YELLOW = "\033[93m";
|
|
||||||
static constexpr const char* FG_BLUE = "\033[34m"; static constexpr const char* FG_B_BLUE = "\033[94m";
|
|
||||||
static constexpr const char* FG_MAGENTA = "\033[35m"; static constexpr const char* FG_B_MAGENTA = "\033[95m";
|
|
||||||
static constexpr const char* FG_CYAN = "\033[36m"; static constexpr const char* FG_B_CYAN = "\033[96m";
|
|
||||||
static constexpr const char* FG_WHITE = "\033[37m"; static constexpr const char* FG_B_WHITE = "\033[97m";
|
|
||||||
|
|
||||||
static constexpr const char* BG_BLACK = "\033[40m"; static constexpr const char* BG_B_BLACK = "\033[100m";
|
static const char* FG_BLACK; static const char* FG_B_BLACK;
|
||||||
static constexpr const char* BG_RED = "\033[41m"; static constexpr const char* BG_B_RED = "\033[101m";
|
static const char* FG_RED; static const char* FG_B_RED;
|
||||||
static constexpr const char* BG_GREEN = "\033[42m"; static constexpr const char* BG_B_GREEN = "\033[102m";
|
static const char* FG_GREEN; static const char* FG_B_GREEN;
|
||||||
static constexpr const char* BG_YELLOW = "\033[43m"; static constexpr const char* BG_B_YELLOW = "\033[103m";
|
static const char* FG_YELLOW; static const char* FG_B_YELLOW;
|
||||||
static constexpr const char* BG_BLUE = "\033[44m"; static constexpr const char* BG_B_BLUE = "\033[104m";
|
static const char* FG_BLUE; static const char* FG_B_BLUE;
|
||||||
static constexpr const char* BG_MAGENTA = "\033[45m"; static constexpr const char* BG_B_MAGENTA = "\033[105m";
|
static const char* FG_MAGENTA; static const char* FG_B_MAGENTA;
|
||||||
static constexpr const char* BG_CYAN = "\033[46m"; static constexpr const char* BG_B_CYAN = "\033[106m";
|
static const char* FG_CYAN; static const char* FG_B_CYAN;
|
||||||
static constexpr const char* BG_WHITE = "\033[47m"; static constexpr const char* BG_B_WHITE = "\033[107m";
|
static const char* FG_WHITE; static const char* FG_B_WHITE;
|
||||||
|
|
||||||
|
static const char* BG_BLACK; static const char* BG_B_BLACK;
|
||||||
|
static const char* BG_RED; static const char* BG_B_RED;
|
||||||
|
static const char* BG_GREEN; static const char* BG_B_GREEN;
|
||||||
|
static const char* BG_YELLOW; static const char* BG_B_YELLOW;
|
||||||
|
static const char* BG_BLUE; static const char* BG_B_BLUE;
|
||||||
|
static const char* BG_MAGENTA; static const char* BG_B_MAGENTA;
|
||||||
|
static const char* BG_CYAN; static const char* BG_B_CYAN;
|
||||||
|
static const char* BG_WHITE; static const char* BG_B_WHITE;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static constexpr const u8 UP = 0x1;
|
// Key Definitions (ASCII OK) //
|
||||||
static constexpr const u8 DOWN = 0x2;
|
static constexpr const u8 UP = 0x80;
|
||||||
static constexpr const u8 LEFT = 0x3;
|
static constexpr const u8 DOWN = 0x81;
|
||||||
static constexpr const u8 RIGHT = 0x4;
|
static constexpr const u8 LEFT = 0x82;
|
||||||
static constexpr const u8 ENTER = 0x5;
|
static constexpr const u8 RIGHT = 0x83;
|
||||||
static constexpr const u8 ESC = 0x6;
|
static constexpr const u8 ENTER = 0x84;
|
||||||
static constexpr const u8 BACKSPACE = 0x7;
|
static constexpr const u8 ESC = 0x85;
|
||||||
static constexpr const u8 UNKNOWN = 0x8;
|
static constexpr const u8 BACKSPACE = 0x86;
|
||||||
|
static constexpr const u8 UNKNOWN = 0xFF;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -119,7 +124,12 @@ namespace spider {
|
|||||||
|
|
||||||
u8 getKey();
|
u8 getKey();
|
||||||
|
|
||||||
std::pair<i32, i32> size();
|
/**
|
||||||
|
* Get key non blocking
|
||||||
|
*/
|
||||||
|
u8 getKeyNb();
|
||||||
|
|
||||||
|
std::pair<i32, i32> getSize();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -135,6 +145,26 @@ namespace spider {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Terminal& print_center(i32 width, const T& msg) {
|
||||||
|
// to string
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << msg;
|
||||||
|
std::string s = oss.str();
|
||||||
|
|
||||||
|
// then print
|
||||||
|
if (s.length() >= size(width)) {
|
||||||
|
std::cout << s;
|
||||||
|
} else {
|
||||||
|
i32 total_padding = width - s.length();
|
||||||
|
i32 left_padding = total_padding / 2;
|
||||||
|
std::cout << std::string(left_padding, ' ');
|
||||||
|
std::cout << s;
|
||||||
|
std::cout << std::string(total_padding - left_padding, ' ');
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Terminal& read(T& var) {
|
Terminal& read(T& var) {
|
||||||
std::cin >> var;
|
std::cin >> var;
|
||||||
|
|||||||
Reference in New Issue
Block a user