added editable byte code

This commit is contained in:
2026-06-14 23:27:11 -06:00
parent 86fa139c9c
commit bfcd91e6fb
16 changed files with 619 additions and 22 deletions
+2
View File
@@ -1,2 +1,4 @@
/.vscode/
/makevars.mak
/bin
/out
+4 -1
View File
@@ -1,3 +1,6 @@
bin/spider/DrawVM.o: src/spider/DrawVM.cpp src/spider/LiveDebug.hpp
bin/spider/DrawVM.o: src/spider/DrawVM.cpp src/spider/LiveDebug.hpp \
src/spider/RamContent.hpp src/spider/ByteCodeContent.hpp
src/spider/DrawVM.cpp:
src/spider/LiveDebug.hpp:
src/spider/RamContent.hpp:
src/spider/ByteCodeContent.hpp:
Binary file not shown.
+4 -1
View File
@@ -1,3 +1,6 @@
bin/spider/LiveDebug.o: src/spider/LiveDebug.cpp src/spider/LiveDebug.hpp
bin/spider/LiveDebug.o: src/spider/LiveDebug.cpp src/spider/LiveDebug.hpp \
src/spider/RamContent.hpp src/spider/ByteCodeContent.hpp
src/spider/LiveDebug.cpp:
src/spider/LiveDebug.hpp:
src/spider/RamContent.hpp:
src/spider/ByteCodeContent.hpp:
Binary file not shown.
+2 -2
View File
@@ -25,11 +25,11 @@ CFLAGS := -std=c++20 -O2 \
-Wsign-conversion -Wnull-dereference -Wdouble-promotion \
-Wformat=2 -Wimplicit-fallthrough -Wsuggest-override \
-Wextra-semi -Wduplicated-cond -Wduplicated-branches \
-Wlogical-op -Wuseless-cast
-Wlogical-op -Wuseless-cast -Wno-unused-parameter
LFLAGS := -std=c++20 -static -static-libstdc++ -static-libgcc \
-Wl,--fatal-warnings -Wl,--warn-common
LIBDIRS := -L"$(PATH_DESKTOPLIB)/out" -L"$(PATH_SPIDER_RUNTIME)/out"
LIB := -ldesktoplib #-lspider-runtime
LIB := -ldesktoplib -lspider-runtime
INC := -I"$(PATH_DESKTOPLIB)/src" -I"$(PATH_SPIDER_RUNTIME)/src" -I./src/
#---------------------------------------------------------------------------------
BIN
View File
Binary file not shown.
+71
View File
@@ -0,0 +1,71 @@
#include "ByteCodeContent.hpp"
#include "LiveDebug.hpp"
#include <cmath>
namespace spider {
ByteCodeContent::ByteCodeContent() : input(1), ipX(0), ipY(0) {}
ByteCodeContent::~ByteCodeContent() {}
// Content must report how tall it wants to be
int ByteCodeContent::getTotalHeight() const {
return int(std::ceil(float(reel.size() + 1) / 16.f));
}
// Render only the rows between startRow and endRow
// relativeY is where the Content starts drawing in terminal space
void ByteCodeContent::render(Terminal& t, pos screenPos, pos viewport, std::pair<int, int> rows) const {
const u64 reel_size = reel.size();
char ascii[16];
for (int row = rows.first; row < rows.second; ++row) {
// Set terminal cursor position for the start of this row
t << pos(screenPos.x + 1, screenPos.y + (row - rows.first));
// Group 8 Bytes
for(int block = 0; block < 2; block++) {
for (int col = 0; col < 8; ++col) {
u64 offset = u64(row * 16 + col + block * 8);
u32 offX = u32(block * 8 + col);
int ascii_index = col + block * 8;
// Is currently selected thing?
bool selected = offX == ipX && u32(row) == ipY && menuSelected && mainMenuID == 0x13;
if(selected) t << backg::B_GREEN << color::BLACK;
// Is input currently enabled?
if(input.getCharCount() && selected) {
// draw this instead!
u8 byte = u8(input.getValue());
drawU8(byte);
ascii[ascii_index] = (byte >= 32 && byte <= 126) ? static_cast<char>(byte) : '.';
} else if (offset < reel_size) {
u8 byte = reel.readU8(offset);
drawU8(byte);
ascii[ascii_index] = (byte >= 32 && byte <= 126) ? static_cast<char>(byte) : '.';
} else {
t << " ";
ascii[ascii_index] = ' ';
}
t << style::RESET << color::WHITE;
t << ' ';
}
if(block == 0) t << " ";
}
t << color::B_BLACK;
t << "| ";
t << color::WHITE;
// --- ASCII Output Loop ---
for (int i = 0; i < 16; ++i) {
t << ascii[i];
if (i == 7) t << ' ';
}
}
}
}
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#include <spider/runtime/Runtime.hpp>
#include <desktoplib/terminal/ui/Content.hpp>
#include <spider/ByteInput.hpp>
namespace spider {
using namespace ckitty::terminal;
/**
* Draws a specific part of the RAM.
*/
class ByteCodeContent : public Content {
public:
ByteInput input;
u64 ipX, ipY;
public:
ByteCodeContent();
virtual ~ByteCodeContent();
public:
// Content must report how tall it wants to be
virtual int getTotalHeight() const override;
// Render only the rows between startRow and endRow
// relativeY is where the Content starts drawing in terminal space
virtual void render(Terminal& t, pos screenPos, pos viewport, std::pair<int, int> rows) const override;
};
}
+49
View File
@@ -0,0 +1,49 @@
#include "ByteInput.hpp"
#include <cctype>
namespace spider {
ByteInput::ByteInput(u64 bytes)
: max_bytes(bytes), max_chars(max_bytes * 2),
current_char_count(0), accumulated_value(0) {
}
u8 ByteInput::hexCharToInt(char ch) const {
if (ch >= '0' && ch <= '9') return u8(ch - '0');
if (ch >= 'a' && ch <= 'f') return u8(ch - 'a' + 10);
if (ch >= 'A' && ch <= 'F') return u8(ch - 'A' + 10);
return 0;
}
bool ByteInput::accept(char ch) {
if (current_char_count >= max_chars || !std::isxdigit(int(ch))) {
return false;
}
// Shift left by 4 bits (1 hex nibble) and inject the new digit
accumulated_value = (accumulated_value << 4) | hexCharToInt(ch);
current_char_count++;
return true;
}
u64 ByteInput::getValue() const {
if (current_char_count == 0) {
return 0;
}
// Pad remaining digits with zeros since entry started at MSB
std::size_t remaining_chars = max_chars - current_char_count;
return accumulated_value << (remaining_chars * 4);
}
void ByteInput::cancel() {
current_char_count = 0;
accumulated_value = 0;
}
bool ByteInput::isComplete() const { return current_char_count == max_chars; }
std::size_t ByteInput::getCharCount() const { return current_char_count; }
}
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#include <spider/runtime/Runtime.hpp>
#include <cstddef>
#include <cstdint>
namespace spider {
class ByteInput {
private:
u64 max_bytes;
u64 max_chars;
u64 current_char_count;
u64 accumulated_value;
// Helper to convert a single hex char to its integer value
public:
/**
* @brief Construct a new Byte Input object.
* @param bytes The number of bytes to accept (capped at 8 to prevent uint64_t overflow).
*/
explicit ByteInput(u64 bytes);
private:
u8 hexCharToInt(char ch) const;
public:
/**
* @brief Accepts a character if it is a valid hex digit and capacity remains.
* @param ch The character to process.
* @return true if accepted, false if invalid or full.
*/
bool accept(char ch);
/**
* @brief Get the numeric value of the current input.
* @return std::uint64_t The value, padded with trailing zeros if incomplete.
*/
u64 getValue() const;
/**
* @brief Resets the input buffer and index.
*/
void cancel();
// Inline getters for quick state checking
bool isComplete() const;
u64 getCharCount() const;
};
}
+107 -15
View File
@@ -7,17 +7,81 @@
namespace spider {
const char hex_chars[] = {
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'A', 'B',
'C', 'D', 'E', 'F',
};
void drawU64(u64 n) {
const char chars[] = {
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'A', 'B',
'C', 'D', 'E', 'F',
};
Terminal& t = *term;
for (int i = 15; i >= 0; --i) {
u64 m = n >> (i * 4);
t << chars[m & 0xF];
t << hex_chars[m & 0xF];
}
}
void drawU8(u8 n) {
Terminal& t = *term;
t << hex_chars[(n >> 4) & 0xF];
t << hex_chars[ n & 0xF];
}
void drawValue(register_t r) {
//u64: 18446744073709551615 | u64: 18446744073709551615//
}
void clearValue() {
}
void drawCPUValues() {
Terminal& t = *term;
CPU& cpu = runtime.cpu;
i32 c = 1, r = 8;
c++;
r += 3;
const color alt[] = {
color::WHITE,
color::B_BLACK,
};
t << style::RESET;
for (i32 i = 0; i < 8; i++) {
t << alt[i & 1];
t << pos(c, r + i * 2);
drawU64(cpu.GPR[i * 2]._u64);
t << pos(c + 17, r + i * 2);
drawU64(cpu.GPR[i * 2 + 1]._u64);
}
r += 17;
// "RF", "RI", "RS", "RZ",
// "RE", "RN", "RV", "RM",
const u64* sr[] = {
&cpu.RF, &cpu.RI, &cpu.RS, &cpu.RZ,
&cpu.RE, &cpu.RN, &cpu.RV, &cpu.RM,
};
t << style::RESET;
for (i32 i = 0; i < 4; i++) {
t << alt[i & 1];
t << pos(c, r + i * 2);
drawU64(*sr[i * 2]);
t << pos(c + 17, r + i * 2);
drawU64(*sr[i * 2 + 1]);
}
r += 9;
const register_t* cr[] = { &cpu.ALU0, &cpu.ALU1 };
t << style::RESET;
for (i32 i = 0; i < 1; i++) {
t << alt[i & 1];
t << pos(c, r + i * 2);
drawU64(cr[i * 2]->_u64);
t << pos(c + 17, r + i * 2);
drawU64(cr[i * 2 + 1]->_u64);
}
}
@@ -96,12 +160,19 @@ namespace spider {
t.flush();
}
void drawRAMValues() {
if(updateRAM) {
updateRAM = false;
ram_scroll->render(*term);
}
}
void drawRAMFace() {
Terminal& t = *term;
// FF FF FF FF FF FF FF FF | XXXX XXXX #//
i32 c = 37, r = 8;
i32 w = 40, h = 31;
i32 c = ram_scroll->position.x - 1, r = ram_scroll->position.y - 1;
i32 w = ram_scroll->width + 2, h = ram_scroll->height + 2;
Box myBox({ c, r }, w, h, " RAM ");
myBox.charset = BoxSet::DOUBLE;
myBox.borderFg = color::RED;
@@ -109,12 +180,19 @@ namespace spider {
t << myBox;
}
void drawByteCodeValues() {
if(updateReel) {
updateReel = false;
reel_scroll->render(*term);
}
}
void drawByteCodeFace() {
Terminal& t = *term;
// FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | XXXXXXXX XXXXXXXX #//
// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ........ ........ #//
i32 c = 78, r = 8;
i32 w = 71, h = 31;
i32 c = reel_scroll->position.x - 1, r = reel_scroll->position.y - 1;
i32 w = reel_scroll->width + 2, h = reel_scroll->height + 2;
Box myBox({ c, r }, w, h, " Byte Code ");
myBox.charset = BoxSet::DOUBLE;
myBox.borderFg = color::GREEN;
@@ -136,6 +214,20 @@ namespace spider {
lt.tm_mday, lt.tm_mon + 1, lt.tm_year + 1900);
}
void drawPanel() {
Terminal& t = *term;
t
<< pos(46, 3) << color::B_YELLOW << cyclesRan
;
}
void drawValues() {
drawPanel();
drawCPUValues();
drawRAMValues();
drawByteCodeValues();
}
void drawFaceplate() {
Terminal& t = *term;
t
@@ -164,7 +256,7 @@ namespace spider {
drawCPUFace();
drawRAMFace();
drawByteCodeFace();
t << pos(101, 1) << color::YELLOW;
t << pos(104, 1) << color::YELLOW;
for(int i = 0; i < 47; i++) t << "";
t << "";
for(int i = 0; i < 5; i++) {
@@ -182,7 +274,7 @@ namespace spider {
<< pos(29, 6) << color::B_BLACK << "[ MENU ]"
<< pos(4, 8) << color::CYAN << " CPU "
<< pos(40, 8) << color::RED << " RAM "
<< pos(81, 8) << color::GREEN << " Byte Code "
<< pos(82, 8) << color::GREEN << " Byte Code "
;
switch(mainMenuID) {
case 0x1: // step
@@ -208,7 +300,7 @@ namespace spider {
else t << "> RAM <";
break;
case 0x13: // instr
t << pos(81, 8) << color::GREEN << style::BOLD;
t << pos(82, 8) << color::GREEN << style::BOLD;
if(menuSelected) t << "[ Byte Code ]";
else t << "> Byte Code <";
break;
+144 -3
View File
@@ -1,18 +1,30 @@
#include "LiveDebug.hpp"
#include <thread>
#include <cctype>
namespace spider {
// Resources //
Runtime runtime;
InstrReelDyn reel(256);
Terminal* term;
MenuMap* mainmenu;
RamContent* ram_content;
InnerScroll* ram_scroll;
ByteCodeContent reel_content;
InnerScroll* reel_scroll;
bool running;
int mainMenuID = 1;
int intrMenuID = 1;
bool menuSelected = false;
bool updateRAM = true;
bool updateReel = true;
int selCPUReg = 0;
int selRamPos = 0;
int selInstrPos = 0;
@@ -30,6 +42,7 @@ namespace spider {
.fill(backg::BLACK)
;
drawFaceplate();
drawValues();
}
// Live Actions //
@@ -49,6 +62,12 @@ namespace spider {
// Setup & Loop //
void setup() {
runtime.ram.resize(1024);
runtime.hookReel(&reel);
ram_content = new RamContent(&runtime.ram);
ram_scroll = new InnerScroll(pos(38, 9), 39, 29, *ram_content);
reel_scroll = new InnerScroll(pos(80, 9), 71, 29, reel_content);
clearAll();
mainmenu = new MenuMap(3, 5);
mainmenu->setWrap(true, false);
@@ -63,6 +82,26 @@ namespace spider {
mainmenu->fill(2, 4, 1, 3, 0x13);
}
/**
* Performs an action according to the
* currently selected action on the panel.
* AKA: STEP, RUN, STOP, MENU
*/
void panelAction() {
switch(mainMenuID) {
case 1: // STEP
//runtime.step();
cyclesRan++;
break;
case 2: // RUN
break;
case 3: // STOP
break;
case 4: // MENU
break; // TODO: DO THIS
}
}
void mainMenuCtrls(int k) {
switch(k) {
case key::UP:
@@ -77,6 +116,27 @@ namespace spider {
case key::RIGHT:
mainmenu->moveRight();
break;
case key::ENTER:
// This is a panel action
if(mainMenuID < 0x10) {
panelAction();
break;
}
// starting action, asap as it's
// selected. Usually just update
// the menu so it comes alive.
menuSelected = mainMenuID;
switch(mainMenuID) {
case 0x11:
break;
case 0x12:
updateRAM = true;
break;
case 0x13:
updateReel = true;
break;
}
break;
default:
return;
}
@@ -84,6 +144,77 @@ namespace spider {
mainMenuID = r.id;
}
void selMenuCtrls(int k) {
switch(mainMenuID) {
case 0x11: // CPU
break;
case 0x12: // RAM
if(k == key::UP) {
ram_scroll->scroll(-1);
updateRAM = true;
}
if(k == key::DOWN) {
ram_scroll->scroll(1);
updateRAM = true;
}
if(k == 'q') updateRAM = true;
break;
case 0x13: // INSTR
if(k == key::UP) {
reel_scroll->scroll(-1);
reel_content.ipY = u64(reel_scroll->rowY);
reel_content.input.cancel();
updateReel = true;
}
if(k == key::DOWN) {
reel_scroll->scroll(1);
reel_content.ipY = u64(reel_scroll->rowY);
reel_content.input.cancel();
updateReel = true;
}
if(k == key::LEFT) {
reel_content.ipX = (reel_content.ipX - 1) % 16;
reel_content.input.cancel();
updateReel = true;
}
if(k == key::RIGHT) {
reel_content.ipX = (reel_content.ipX + 1) % 16;
reel_content.input.cancel();
updateReel = true;
}
if(std::isxdigit(k)) {
// Input enable.
// Clamp if outside of range.
u64 maxIP = reel.size();
u64 ip = std::min<u64>(reel_content.ipX + reel_content.ipY * 16, maxIP);
reel_content.ipX = ip % 16;
reel_content.ipY = ip / 16;
auto& t = *term;
t << pos(0, 0) << ip << ", " << maxIP;
reel_content.input.accept(char(k));
updateReel = true;
}
if(k == key::ENTER || reel_content.input.isComplete()) {
// Input enable.
// Clamp if outside of range.
u64 maxIP = reel.size();
u64 ip = std::min<u64>(reel_content.ipX + reel_content.ipY * 16, maxIP);
reel_content.ipX = ip % 16;
reel_content.ipY = ip / 16;
u8 byte = u8(reel_content.input.getValue());
reel.write(ip, &byte, 1);
reel_content.input.cancel();
updateReel = true;
}
if(k == 'q') updateReel = true;
break;
}
if(k == 'q') {
menuSelected = false;
drawMainMenuSel();
}
}
void loop() {
// time @79
Terminal& t = *term;
@@ -95,11 +226,21 @@ namespace spider {
running = false;
return;
}
mainMenuCtrls(k);
drawMainMenuSel();
// if nothing selected, draw the main menu
// selection AND handle input
if(!menuSelected) {
mainMenuCtrls(k);
drawMainMenuSel();
} else { // inner, selected menu
selMenuCtrls(k);
}
drawValues();
// Favour the thread doing other stuff
if(!runVM) { // IF the vm is not continously running
if(runVM) { // IF the vm is not continously running
std::this_thread::yield();
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
+28
View File
@@ -1,21 +1,43 @@
#pragma once
#include <spider/runtime/Runtime.hpp>
#include <spider/runtime/reel/InstrReelDyn.hpp>
#include <desktoplib/terminal/Terminal.hpp>
#include <desktoplib/terminal/ui/Box.hpp>
#include <desktoplib/terminal/ui/MenuMap.hpp>
#include <desktoplib/terminal/ui/Content.hpp>
#include <desktoplib/terminal/ui/InnerScroll.hpp>
#include "RamContent.hpp"
#include "ByteCodeContent.hpp"
namespace spider {
using namespace ckitty::terminal;
// Virtual Machine
extern Runtime runtime;
extern InstrReelDyn reel;
// Resources //
extern Terminal* term;
extern MenuMap* mainmenu;
extern RamContent* ram_content;
extern InnerScroll* ram_scroll;
extern ByteCodeContent reel_content;
extern InnerScroll* reel_scroll;
extern bool running;
extern int mainMenuID;
extern bool menuSelected;
extern bool updateRAM;
extern bool updateReel;
extern u64 cyclesRan;
extern bool runVM;
// UI Actions //
@@ -23,8 +45,14 @@ namespace spider {
void drawFaceplate();
void drawValues();
void drawMainMenuSel();
void drawU64(u64 n);
void drawU8(u8 n);
std::string getTime();
// Live Actions //
+76
View File
@@ -0,0 +1,76 @@
#include "RamContent.hpp"
#include "LiveDebug.hpp"
#include <cmath>
namespace spider {
RamContent::RamContent(RAM* _ram) : ram(_ram) {}
RamContent::~RamContent() {}
// Content must report how tall it wants to be
int RamContent::getTotalHeight() const {
return int(std::ceil(float(ram->size()) / 8.f));
}
// Render only the rows between startRow and endRow
// relativeY is where the Content starts drawing in terminal space
void RamContent::render(Terminal& t, pos screenPos, pos viewport, std::pair<int, int> rows) const {
// FF FF FF FF FF FF FF FF | XXXX XXXX #//
const u64 ram_size = ram->size();
char ascii[8];
for (int row = rows.first; row < rows.second; ++row) {
// Set terminal cursor position for the start of this row
t << pos(screenPos.x + 1, screenPos.y + (row - rows.first));
// Is this the selected column?
if(ram_scroll->rowY == row && menuSelected && mainMenuID == 0x12) {
t << backg::RED << color::WHITE;
} else {
t << style::RESET << color::WHITE;
}
// --- Group 1: First 4 bytes ---
for (int col = 0; col < 4; ++col) {
u64 offset = static_cast<u64>(row * 8 + col);
if (offset < ram_size) {
u8 byte = ram->at(offset);
drawU8(byte);
ascii[col] = (byte >= 32 && byte <= 126) ? static_cast<char>(byte) : '.';
} else {
t << " ";
ascii[col] = ' ';
}
t << ' ';
}
t << ' ';
// --- Group 2: Next 4 bytes ---
for (int col = 4; col < 8; ++col) {
u64 offset = static_cast<u64>(row * 8 + col);
if (offset < ram_size) {
u8 byte = ram->at(offset);
drawU8(byte);
ascii[col] = (byte >= 32 && byte <= 126) ? static_cast<char>(byte) : '.';
} else {
t << " ";
ascii[col] = ' ';
}
t << " ";
}
t << color::B_BLACK;
t << "| ";
t << color::WHITE;
// --- ASCII Output Loop ---
for (int i = 0; i < 8; ++i) {
t << ascii[i];
if (i == 3) t << ' ';
}
}
}
}
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#include <spider/runtime/memory/RAM.hpp>
#include <desktoplib/terminal/ui/Content.hpp>
namespace spider {
using namespace ckitty::terminal;
/**
* Draws a specific part of the RAM.
*/
class RamContent : public Content {
public:
RAM* ram;
public:
RamContent(RAM* _ram);
virtual ~RamContent();
public:
// Content must report how tall it wants to be
virtual int getTotalHeight() const override;
// Render only the rows between startRow and endRow
// relativeY is where the Content starts drawing in terminal space
virtual void render(Terminal& t, pos screenPos, pos viewport, std::pair<int, int> rows) const override;
};
}