add blog posts in HTML format
This commit is contained in:
442
blog-esp32.html
Normal file
442
blog-esp32.html
Normal file
@@ -0,0 +1,442 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Running Spider on ESP32 — Diego López</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400&family=Syne:wght@400;700;800&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg: #0a0a0a;
|
||||
--surface: #111111;
|
||||
--border: #1f1f1f;
|
||||
--accent: #00e5a0;
|
||||
--accent2: #ff6b35;
|
||||
--text: #e8e8e8;
|
||||
--muted: #666;
|
||||
--code-bg: #0d1117;
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font-family: 'Syne', sans-serif;
|
||||
line-height: 1.7;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* ── Header ── */
|
||||
header {
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding: 2rem 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
header::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -60px; left: -60px;
|
||||
width: 300px; height: 300px;
|
||||
background: radial-gradient(circle, rgba(0,229,160,0.08) 0%, transparent 70%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.header-inner {
|
||||
max-width: 860px;
|
||||
margin: 0 auto;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
.tag {
|
||||
font-family: 'Space Mono', monospace;
|
||||
font-size: 0.7rem;
|
||||
color: var(--accent);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.15em;
|
||||
border: 1px solid var(--accent);
|
||||
padding: 0.2rem 0.6rem;
|
||||
display: inline-block;
|
||||
margin-bottom: 1.2rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(2rem, 5vw, 3.2rem);
|
||||
font-weight: 800;
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.02em;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
h1 span {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.meta {
|
||||
font-family: 'Space Mono', monospace;
|
||||
font-size: 0.75rem;
|
||||
color: var(--muted);
|
||||
margin-top: 1.2rem;
|
||||
}
|
||||
|
||||
/* ── Main content ── */
|
||||
main {
|
||||
max-width: 860px;
|
||||
margin: 0 auto;
|
||||
padding: 3rem 2rem 6rem;
|
||||
}
|
||||
|
||||
/* ── Diagram box ── */
|
||||
.diagram {
|
||||
background: var(--code-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-left: 3px solid var(--accent);
|
||||
padding: 1.5rem 2rem;
|
||||
font-family: 'Space Mono', monospace;
|
||||
font-size: 0.82rem;
|
||||
color: #8b949e;
|
||||
line-height: 2;
|
||||
margin: 2rem 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.diagram .hl { color: var(--accent); }
|
||||
.diagram .hl2 { color: var(--accent2); }
|
||||
|
||||
/* ── Section heading ── */
|
||||
.step {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 1.5rem;
|
||||
margin: 3rem 0 1rem;
|
||||
}
|
||||
|
||||
.step-num {
|
||||
font-family: 'Space Mono', monospace;
|
||||
font-size: 0.7rem;
|
||||
color: var(--accent);
|
||||
border: 1px solid var(--accent);
|
||||
padding: 0.3rem 0.5rem;
|
||||
white-space: nowrap;
|
||||
margin-top: 0.3rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.step h2 {
|
||||
font-size: 1.4rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #b0b0b0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* ── Code block ── */
|
||||
pre {
|
||||
background: var(--code-bg);
|
||||
border: 1px solid var(--border);
|
||||
padding: 1.4rem 1.6rem;
|
||||
font-family: 'Space Mono', monospace;
|
||||
font-size: 0.78rem;
|
||||
line-height: 1.8;
|
||||
overflow-x: auto;
|
||||
margin: 1.2rem 0;
|
||||
color: #8b949e;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
pre .kw { color: #ff7b72; }
|
||||
pre .str { color: #a5d6ff; }
|
||||
pre .cmt { color: #3d4f5a; font-style: italic; }
|
||||
pre .val { color: var(--accent); }
|
||||
pre .flag { color: var(--accent2); }
|
||||
|
||||
/* ── Flags table ── */
|
||||
.flag-grid {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: 0;
|
||||
margin: 1.5rem 0;
|
||||
border: 1px solid var(--border);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.flag-grid .flag-name {
|
||||
font-family: 'Space Mono', monospace;
|
||||
font-size: 0.78rem;
|
||||
color: var(--accent2);
|
||||
padding: 0.7rem 1rem;
|
||||
background: var(--code-bg);
|
||||
border-bottom: 1px solid var(--border);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.flag-grid .flag-desc {
|
||||
font-size: 0.85rem;
|
||||
color: #b0b0b0;
|
||||
padding: 0.7rem 1rem;
|
||||
background: var(--surface);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.flag-grid .flag-name:last-of-type,
|
||||
.flag-grid .flag-desc:last-of-type {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* ── Result banner ── */
|
||||
.result {
|
||||
border: 1px solid var(--accent);
|
||||
background: rgba(0,229,160,0.04);
|
||||
padding: 1.5rem 2rem;
|
||||
margin: 3rem 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.result::before {
|
||||
content: 'CONFIRMED OUTPUT';
|
||||
font-family: 'Space Mono', monospace;
|
||||
font-size: 0.65rem;
|
||||
color: var(--accent);
|
||||
letter-spacing: 0.15em;
|
||||
position: absolute;
|
||||
top: -0.55rem;
|
||||
left: 1.5rem;
|
||||
background: var(--bg);
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.result pre {
|
||||
border: none;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.result pre .ok { color: var(--accent); }
|
||||
|
||||
/* ── Note ── */
|
||||
.note {
|
||||
border-left: 2px solid var(--accent2);
|
||||
padding: 0.8rem 1.2rem;
|
||||
background: rgba(255,107,53,0.04);
|
||||
margin: 1.5rem 0;
|
||||
font-size: 0.88rem;
|
||||
color: #b0b0b0;
|
||||
}
|
||||
|
||||
.note strong { color: var(--accent2); }
|
||||
|
||||
/* ── Footer ── */
|
||||
footer {
|
||||
border-top: 1px solid var(--border);
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
font-family: 'Space Mono', monospace;
|
||||
font-size: 0.7rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* ── Animations ── */
|
||||
@keyframes fadeUp {
|
||||
from { opacity: 0; transform: translateY(16px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
header, main > * {
|
||||
animation: fadeUp 0.5s ease both;
|
||||
}
|
||||
|
||||
main > *:nth-child(1) { animation-delay: 0.05s; }
|
||||
main > *:nth-child(2) { animation-delay: 0.10s; }
|
||||
main > *:nth-child(3) { animation-delay: 0.15s; }
|
||||
main > *:nth-child(4) { animation-delay: 0.20s; }
|
||||
main > *:nth-child(5) { animation-delay: 0.25s; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="header-inner">
|
||||
<div class="tag">Spider Lang · Internship 2026</div>
|
||||
<h1>Running Spider<br>on <span>ESP32</span></h1>
|
||||
<p style="color:#888; max-width:560px; margin-top:0.8rem;">
|
||||
How the Spider Runtime was cross-compiled for the Xtensa architecture
|
||||
and flashed onto physical hardware using ESP-IDF.
|
||||
</p>
|
||||
<div class="meta">Diego Alberto López · Build System · April 2026</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
|
||||
<!-- Overview diagram -->
|
||||
<div class="diagram">
|
||||
<span class="hl">script.spider</span>
|
||||
↓ Spider Compiler
|
||||
<span class="hl">bytecode.spd</span> <span style="color:#3d4f5a">← Spider's own format, not x86, not Xtensa</span>
|
||||
|
||||
<span class="hl">Spider Runtime (C++)</span>
|
||||
↓ xtensa-esp-elf-g++ <span style="color:#3d4f5a">← ESP-IDF toolchain</span>
|
||||
<span class="hl2">spider_esp32.bin</span>
|
||||
↓ esptool.py
|
||||
<span class="hl">ESP32 flash memory</span> <span style="color:#3d4f5a">← Runtime lives here permanently</span>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Spider's bytecode is a neutral format that belongs to no specific processor.
|
||||
The toolchain's job is not to convert bytecode — it compiles the
|
||||
C++ source of the Runtime itself into Xtensa machine code.
|
||||
Once flashed, the Runtime lives in the ESP32's flash memory and
|
||||
interprets Spider bytecode at runtime.
|
||||
</p>
|
||||
|
||||
<!-- Step 1 -->
|
||||
<div class="step">
|
||||
<div class="step-num">01</div>
|
||||
<h2>Prerequisites</h2>
|
||||
</div>
|
||||
|
||||
<p>Install ESP-IDF v5.x and add the Xtensa toolchain to your PATH:</p>
|
||||
|
||||
<pre><span class="cmt"># Add to ~/.bashrc to make it permanent</span>
|
||||
<span class="kw">export</span> PATH=<span class="str">$PATH:/c/Espressif/tools/xtensa-esp-elf/esp-14.2.0_20251107/xtensa-esp-elf/bin</span></pre>
|
||||
|
||||
<!-- Step 2 -->
|
||||
<div class="step">
|
||||
<div class="step-num">02</div>
|
||||
<h2>Compile flags for ESP32</h2>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The Runtime uses compile-time platform detection via <code style="font-family:'Space Mono',monospace;color:var(--accent);font-size:0.85em">distro_mcu.hpp</code>.
|
||||
These flags tell it which hardware it is targeting:
|
||||
</p>
|
||||
|
||||
<div class="flag-grid">
|
||||
<div class="flag-name">-DESP32</div>
|
||||
<div class="flag-desc">Activates ESP32 detection in distro_mcu.hpp</div>
|
||||
<div class="flag-name">-DSPIDER_DISTRO_MICRO</div>
|
||||
<div class="flag-desc">Enables microcontroller mode (reduced memory footprint)</div>
|
||||
<div class="flag-name">-DSPIDER_OS_NONE</div>
|
||||
<div class="flag-desc">Declares bare-metal environment, no OS</div>
|
||||
<div class="flag-name">-mlongcalls</div>
|
||||
<div class="flag-desc">Required for Xtensa's memory layout and call distances</div>
|
||||
<div class="flag-name">-fno-exceptions -fno-rtti</div>
|
||||
<div class="flag-desc">Disable C++ features unavailable on bare-metal</div>
|
||||
<div class="flag-name">-O0</div>
|
||||
<div class="flag-desc">No optimizations — faster compilation during development</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3 -->
|
||||
<div class="step">
|
||||
<div class="step-num">03</div>
|
||||
<h2>Build with ESP-IDF (CMake)</h2>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The bare-metal Makefile approach caused boot loops because the ESP32 bootloader
|
||||
expects a specific binary format. The correct approach is to use ESP-IDF's
|
||||
CMake build system, which generates the bootloader, partition table, and app
|
||||
binary automatically.
|
||||
</p>
|
||||
|
||||
<pre><span class="cmt"># From spider-micro-buildtools/esp32/idf_project/</span>
|
||||
idf.py set-target esp32
|
||||
idf.py build
|
||||
idf.py -p COM6 flash monitor</pre>
|
||||
|
||||
<p>The CMakeLists.txt registers the Spider Runtime source files as a component:</p>
|
||||
|
||||
<pre><span class="kw">set</span>(SPIDER_RUNTIME_SRC
|
||||
<span class="str">"${CMAKE_CURRENT_SOURCE_DIR}/../../../../spider-runtime/src"</span>
|
||||
)
|
||||
|
||||
<span class="kw">idf_component_register</span>(
|
||||
SRCS
|
||||
<span class="str">"main.cpp"</span>
|
||||
<span class="str">"${SPIDER_RUNTIME_SRC}/spider/runtime/Runtime.cpp"</span>
|
||||
<span class="str">"${SPIDER_RUNTIME_SRC}/spider/runtime/cpu/CPU.cpp"</span>
|
||||
<span class="cmt">... (all Runtime source files)</span>
|
||||
PRIV_INCLUDE_DIRS <span class="str">"${SPIDER_RUNTIME_SRC}"</span>
|
||||
)</pre>
|
||||
|
||||
<div class="note">
|
||||
<strong>Note:</strong> Relative paths using <code style="font-family:'Space Mono',monospace;font-size:0.85em">CMAKE_CURRENT_SOURCE_DIR</code>
|
||||
are used to avoid exposing personal directory structure in the repository.
|
||||
</div>
|
||||
|
||||
<!-- Step 4 -->
|
||||
<div class="step">
|
||||
<div class="step-num">04</div>
|
||||
<h2>app_main — The ESP32 entry point</h2>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
ESP-IDF requires <code style="font-family:'Space Mono',monospace;color:var(--accent);font-size:0.85em">app_main()</code>
|
||||
instead of the standard <code style="font-family:'Space Mono',monospace;color:var(--accent);font-size:0.85em">main()</code>.
|
||||
The Spider Runtime is initialized here with a fixed amount of RAM:
|
||||
</p>
|
||||
|
||||
<pre><span class="kw">#include</span> <span class="str">"esp_log.h"</span>
|
||||
<span class="kw">#include</span> <span class="str"><spider/runtime/Runtime.hpp></span>
|
||||
|
||||
<span class="kw">static const char*</span> TAG = <span class="str">"Spider"</span>;
|
||||
|
||||
<span class="kw">extern "C" void</span> app_main(<span class="kw">void</span>) {
|
||||
ESP_LOGI(TAG, <span class="str">"Spider Runtime starting..."</span>);
|
||||
spider::Runtime runtime(<span class="val">32</span> * <span class="val">1024</span>); <span class="cmt">// 32 KB RAM</span>
|
||||
ESP_LOGI(TAG, <span class="str">"Spider Runtime initialized!"</span>);
|
||||
ESP_LOGI(TAG, <span class="str">"RAM size: 32KB"</span>);
|
||||
<span class="kw">while</span>(<span class="val">1</span>) { vTaskDelay(pdMS_TO_TICKS(<span class="val">1000</span>)); }
|
||||
}</pre>
|
||||
|
||||
<!-- Confirmed output -->
|
||||
<div class="result">
|
||||
<pre>
|
||||
<span class="ok">I (274) Spider: Spider Runtime starting...</span>
|
||||
<span class="ok">I (274) Spider: Spider Runtime initialized!</span>
|
||||
<span class="ok">I (274) Spider: RAM size: 32KB</span>
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<!-- Repo structure -->
|
||||
<div class="step">
|
||||
<div class="step-num">05</div>
|
||||
<h2>Repository structure</h2>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The build tools live in <code style="font-family:'Space Mono',monospace;color:var(--accent);font-size:0.85em">spider-micro-buildtools</code>,
|
||||
separate from the Runtime source. Both repos must be cloned at the same level:
|
||||
</p>
|
||||
|
||||
<div class="diagram">
|
||||
<span class="hl">Internship/</span>
|
||||
├── <span class="hl">spider-runtime/</span> <span style="color:#3d4f5a">← Runtime C++ source</span>
|
||||
└── <span class="hl2">spider-micro-buildtools/</span>
|
||||
└── esp32/
|
||||
├── Makefile <span style="color:#3d4f5a">← bare-metal reference build</span>
|
||||
├── gen_makefile.py
|
||||
├── main_esp32.cpp
|
||||
├── README.md
|
||||
└── <span class="hl2">idf_project/</span> <span style="color:#3d4f5a">← ESP-IDF project (use this)</span>
|
||||
├── CMakeLists.txt
|
||||
└── main/
|
||||
├── CMakeLists.txt
|
||||
└── main.cpp
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
Spider Lang Internship 2026 · Diego Alberto López
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
551
blog-instrucciones.html
Normal file
551
blog-instrucciones.html
Normal file
@@ -0,0 +1,551 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Implementing Spider VM Instructions — Diego López</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,400;0,600;1,400&family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,700;1,9..144,300&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg: #faf8f4;
|
||||
--surface: #f2ede4;
|
||||
--border: #ddd8ce;
|
||||
--accent: #c44b2b;
|
||||
--accent2: #2563a8;
|
||||
--text: #1a1714;
|
||||
--muted: #8a8278;
|
||||
--code-bg: #1c1917;
|
||||
--code-text: #d4cfca;
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font-family: 'Fraunces', serif;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
/* ── Header ── */
|
||||
header {
|
||||
background: var(--text);
|
||||
color: var(--bg);
|
||||
padding: 4rem 2rem 3rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
header::after {
|
||||
content: '0x068→0x079';
|
||||
position: absolute;
|
||||
bottom: -1.5rem;
|
||||
right: 2rem;
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
font-size: 6rem;
|
||||
color: rgba(255,255,255,0.04);
|
||||
line-height: 1;
|
||||
pointer-events: none;
|
||||
letter-spacing: -0.05em;
|
||||
}
|
||||
|
||||
.header-inner {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.tag {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
font-size: 0.7rem;
|
||||
color: var(--accent);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.15em;
|
||||
margin-bottom: 1.5rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(2.2rem, 5vw, 3.5rem);
|
||||
font-weight: 700;
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.02em;
|
||||
margin-bottom: 1.2rem;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
color: rgba(250,248,244,0.65);
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.meta {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
font-size: 0.7rem;
|
||||
color: rgba(250,248,244,0.4);
|
||||
margin-top: 2rem;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
/* ── Main ── */
|
||||
main {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 4rem 2rem 6rem;
|
||||
}
|
||||
|
||||
section {
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.6rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.01em;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 2px solid var(--border);
|
||||
}
|
||||
|
||||
h2 span {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
font-size: 0.8rem;
|
||||
color: var(--accent);
|
||||
font-style: normal;
|
||||
vertical-align: middle;
|
||||
margin-left: 0.8rem;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #3d3830;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* ── Instruction table ── */
|
||||
.instr-group {
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
.group-label {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
font-size: 0.68rem;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.12em;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.instr-list {
|
||||
border: 1px solid var(--border);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.instr-row {
|
||||
display: grid;
|
||||
grid-template-columns: 6rem 5rem 1fr;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.instr-row:last-child { border-bottom: none; }
|
||||
|
||||
.instr-row:hover { background: var(--surface); }
|
||||
|
||||
.instr-op {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
font-size: 0.75rem;
|
||||
color: var(--accent);
|
||||
padding: 0.65rem 1rem;
|
||||
background: var(--surface);
|
||||
border-right: 1px solid var(--border);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.instr-name {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
padding: 0.65rem 1rem;
|
||||
border-right: 1px solid var(--border);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.instr-desc {
|
||||
font-size: 0.85rem;
|
||||
padding: 0.65rem 1rem;
|
||||
color: #5a5248;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* ── Code block ── */
|
||||
pre {
|
||||
background: var(--code-bg);
|
||||
color: var(--code-text);
|
||||
padding: 1.4rem 1.6rem;
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
font-size: 0.78rem;
|
||||
line-height: 1.85;
|
||||
overflow-x: auto;
|
||||
margin: 1.2rem 0;
|
||||
}
|
||||
|
||||
pre .kw { color: #e06c75; }
|
||||
pre .fn { color: #61afef; }
|
||||
pre .cmt { color: #4d4540; font-style: italic; }
|
||||
pre .val { color: #98c379; }
|
||||
pre .type { color: #e5c07b; }
|
||||
|
||||
/* ── Pattern box ── */
|
||||
.pattern {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-left: 3px solid var(--accent2);
|
||||
padding: 1.2rem 1.5rem;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
.pattern-label {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
font-size: 0.65rem;
|
||||
color: var(--accent2);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.12em;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.pattern pre {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
color: #3d3830;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
.pattern pre .fn { color: var(--accent2); }
|
||||
.pattern pre .cmt { color: var(--muted); }
|
||||
|
||||
/* ── Test results ── */
|
||||
.test-results {
|
||||
background: var(--code-bg);
|
||||
padding: 1.5rem 2rem;
|
||||
margin: 2rem 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.test-results::before {
|
||||
content: 'TEST OUTPUT — 15/15 PASS';
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
font-size: 0.65rem;
|
||||
color: #4ade80;
|
||||
letter-spacing: 0.12em;
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.test-line {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
font-size: 0.78rem;
|
||||
line-height: 1.9;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.test-line .pass { color: #4ade80; }
|
||||
.test-line .section { color: #e5c07b; margin-top: 0.5rem; display: block; }
|
||||
|
||||
/* ── Note ── */
|
||||
.note {
|
||||
border: 1px solid var(--border);
|
||||
padding: 1rem 1.4rem;
|
||||
margin: 1.5rem 0;
|
||||
font-size: 0.88rem;
|
||||
color: #5a5248;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.note strong { color: var(--text); font-style: normal; }
|
||||
|
||||
/* ── Footer ── */
|
||||
footer {
|
||||
background: var(--text);
|
||||
color: rgba(250,248,244,0.4);
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
font-size: 0.7rem;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
/* ── Animations ── */
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(12px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
section {
|
||||
animation: fadeIn 0.6s ease both;
|
||||
}
|
||||
|
||||
section:nth-child(1) { animation-delay: 0.05s; }
|
||||
section:nth-child(2) { animation-delay: 0.12s; }
|
||||
section:nth-child(3) { animation-delay: 0.19s; }
|
||||
section:nth-child(4) { animation-delay: 0.26s; }
|
||||
section:nth-child(5) { animation-delay: 0.33s; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="header-inner">
|
||||
<span class="tag">Spider VM · Instruction Set Implementation · 2026</span>
|
||||
<h1>Implementing<br>Spider VM Instructions</h1>
|
||||
<p class="subtitle">Cast conversions, trigonometric and exponential functions for the Spider Virtual Machine — opcodes 0x068 through 0x079.</p>
|
||||
<div class="meta">Diego Alberto López · spider-runtime · April 2026</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
|
||||
<!-- Context -->
|
||||
<section>
|
||||
<h2>Context <span>background</span></h2>
|
||||
<p>
|
||||
The Spider VM instruction set is organized in a 9-bit opcode space (512 slots),
|
||||
divided among team members. My assigned range covers 15 instructions:
|
||||
two type cast conversions and thirteen math functions.
|
||||
</p>
|
||||
<p>
|
||||
Instructions are defined in <code style="font-family:'IBM Plex Mono',monospace;font-size:0.9em;color:var(--accent)">Instr_060-07F.cpp</code>,
|
||||
which already contained the previous range (0x060–0x067) implemented by another team member.
|
||||
My work begins at 0x068.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- Instruction list -->
|
||||
<section>
|
||||
<h2>Assigned Instructions <span>0x068 → 0x079</span></h2>
|
||||
|
||||
<div class="instr-group">
|
||||
<div class="group-label">Cast Conversions</div>
|
||||
<div class="instr-list">
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x068</div>
|
||||
<div class="instr-name">D2I</div>
|
||||
<div class="instr-desc">Double (f64) → Integer (i32), truncates toward zero</div>
|
||||
</div>
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x069</div>
|
||||
<div class="instr-name">D2L</div>
|
||||
<div class="instr-desc">Double (f64) → Long (i64), truncates toward zero</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="instr-group">
|
||||
<div class="group-label">Trigonometric</div>
|
||||
<div class="instr-list">
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x06C</div>
|
||||
<div class="instr-name">SIN</div>
|
||||
<div class="instr-desc">Sine — sin(Dst) → Dst</div>
|
||||
</div>
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x06D</div>
|
||||
<div class="instr-name">COS</div>
|
||||
<div class="instr-desc">Cosine — cos(Dst) → Dst</div>
|
||||
</div>
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x06E</div>
|
||||
<div class="instr-name">TAN</div>
|
||||
<div class="instr-desc">Tangent — tan(Dst) → Dst</div>
|
||||
</div>
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x06F</div>
|
||||
<div class="instr-name">ASIN</div>
|
||||
<div class="instr-desc">Arc sine — asin(Dst) → Dst</div>
|
||||
</div>
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x070</div>
|
||||
<div class="instr-name">ACOS</div>
|
||||
<div class="instr-desc">Arc cosine — acos(Dst) → Dst</div>
|
||||
</div>
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x071</div>
|
||||
<div class="instr-name">ATAN</div>
|
||||
<div class="instr-desc">Arc tangent — atan(Dst) → Dst</div>
|
||||
</div>
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x072</div>
|
||||
<div class="instr-name">ATAN2</div>
|
||||
<div class="instr-desc">Arc tangent 2-argument — atan2(Dst, Src) → Dst</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="instr-group">
|
||||
<div class="group-label">Exponential</div>
|
||||
<div class="instr-list">
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x074</div>
|
||||
<div class="instr-name">EXP</div>
|
||||
<div class="instr-desc">Natural exponential — eˣ → Dst</div>
|
||||
</div>
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x075</div>
|
||||
<div class="instr-name">LOG</div>
|
||||
<div class="instr-desc">Natural logarithm — ln(Dst) → Dst</div>
|
||||
</div>
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x076</div>
|
||||
<div class="instr-name">LOGAB</div>
|
||||
<div class="instr-desc">Logarithm base A of B — log_Src(Dst) → Dst</div>
|
||||
</div>
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x077</div>
|
||||
<div class="instr-name">POW</div>
|
||||
<div class="instr-desc">Power — Dst^Src → Dst</div>
|
||||
</div>
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x078</div>
|
||||
<div class="instr-name">SQRT</div>
|
||||
<div class="instr-desc">Square root — √Dst → Dst</div>
|
||||
</div>
|
||||
<div class="instr-row">
|
||||
<div class="instr-op">0x079</div>
|
||||
<div class="instr-name">ROOT</div>
|
||||
<div class="instr-desc">General root — Dst^(1/Src) → Dst</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Implementation pattern -->
|
||||
<section>
|
||||
<h2>Implementation Pattern <span>how it works</span></h2>
|
||||
|
||||
<p>
|
||||
Every instruction in the Spider VM follows the same three-step pattern:
|
||||
fetch the operand(s), perform the operation, and call the post-execution hook.
|
||||
</p>
|
||||
|
||||
<div class="pattern">
|
||||
<div class="pattern-label">Single-operand pattern</div>
|
||||
<pre><span class="fn">fetchOperDst</span>(); <span class="cmt">// points _dst to the destination register</span>
|
||||
_dst->_f64 = std::<span class="fn">sin</span>(_dst->_f64);
|
||||
(this->*_post)(); <span class="cmt">// post-execution hook (write-back if needed)</span></pre>
|
||||
</div>
|
||||
|
||||
<div class="pattern">
|
||||
<div class="pattern-label">Two-operand pattern (ATAN2, LOGAB, POW, ROOT)</div>
|
||||
<pre><span class="fn">fetchOperDst</span>(); <span class="cmt">// _dst ← destination</span>
|
||||
<span class="fn">fetchOperSrc</span>(); <span class="cmt">// _src ← source</span>
|
||||
_dst->_f64 = std::<span class="fn">atan2</span>(_dst->_f64, _src->_f64);
|
||||
(this->*_post)();</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The <code style="font-family:'IBM Plex Mono',monospace;font-size:0.9em;color:var(--accent)">register_t</code> union
|
||||
allows each register to be read as any type (<code style="font-family:'IBM Plex Mono',monospace;font-size:0.85em">_f64</code>,
|
||||
<code style="font-family:'IBM Plex Mono',monospace;font-size:0.85em">_u32</code>,
|
||||
<code style="font-family:'IBM Plex Mono',monospace;font-size:0.85em">_u64</code>, etc.)
|
||||
without casting overhead. The type modifier in the instruction header determines
|
||||
which field is active.
|
||||
</p>
|
||||
|
||||
<p>Notable special cases:</p>
|
||||
<p>
|
||||
<strong>LOGAB</strong> uses the change-of-base formula:
|
||||
log<sub>a</sub>(b) = ln(b) / ln(a), where Dst is b and Src is a.
|
||||
</p>
|
||||
<p>
|
||||
<strong>ROOT</strong> uses the identity: ⁿ√x = x^(1/n),
|
||||
implemented as <code style="font-family:'IBM Plex Mono',monospace;font-size:0.85em">std::pow(dst, 1.0 / src)</code>.
|
||||
</p>
|
||||
|
||||
<p>The full implementation in C++20:</p>
|
||||
|
||||
<pre><span class="kw">void</span> <span class="type">CPU</span>::<span class="fn">D2I</span>() {
|
||||
<span class="fn">fetchOperDst</span>();
|
||||
_dst->_u32 = <span class="kw">static_cast</span><<span class="type">u32</span>>(_dst->_f64);
|
||||
(this->*_post)();
|
||||
}
|
||||
|
||||
<span class="kw">void</span> <span class="type">CPU</span>::<span class="fn">SIN</span>() {
|
||||
<span class="fn">fetchOperDst</span>();
|
||||
_dst->_f64 = std::<span class="fn">sin</span>(_dst->_f64);
|
||||
(this->*_post)();
|
||||
}
|
||||
|
||||
<span class="kw">void</span> <span class="type">CPU</span>::<span class="fn">LOGAB</span>() {
|
||||
<span class="fn">fetchOperDst</span>();
|
||||
<span class="fn">fetchOperSrc</span>();
|
||||
_dst->_f64 = std::<span class="fn">log</span>(_dst->_f64) / std::<span class="fn">log</span>(_src->_f64);
|
||||
(this->*_post)();
|
||||
}
|
||||
|
||||
<span class="kw">void</span> <span class="type">CPU</span>::<span class="fn">ROOT</span>() {
|
||||
<span class="fn">fetchOperDst</span>();
|
||||
<span class="fn">fetchOperSrc</span>();
|
||||
_dst->_f64 = std::<span class="fn">pow</span>(_dst->_f64, <span class="val">1.0</span> / _src->_f64);
|
||||
(this->*_post)();
|
||||
}</pre>
|
||||
</section>
|
||||
|
||||
<!-- Testing -->
|
||||
<section>
|
||||
<h2>Verification <span>test results</span></h2>
|
||||
|
||||
<p>
|
||||
A test program was written to call each instruction directly on the CPU
|
||||
and verify the output against mathematically known values.
|
||||
Since <code style="font-family:'IBM Plex Mono',monospace;font-size:0.9em;color:var(--accent)">fetchInstr()</code>
|
||||
and <code style="font-family:'IBM Plex Mono',monospace;font-size:0.9em;color:var(--accent)">execute()</code>
|
||||
are not yet implemented in the Runtime, operands are set manually before each call.
|
||||
</p>
|
||||
|
||||
<div class="test-results">
|
||||
<div class="test-line">
|
||||
<span class="section">-- Cast Instructions --</span>
|
||||
<span class="pass">[PASS]</span> D2I (3.9 -> 3) = 3 (expected 3)<br>
|
||||
<span class="pass">[PASS]</span> D2L (1e12) = 1e+12 (expected 1e+12)
|
||||
<span class="section">-- Trigonometric Instructions --</span>
|
||||
<span class="pass">[PASS]</span> SIN(pi/2) = 1 (expected 1)<br>
|
||||
<span class="pass">[PASS]</span> COS(0) = 1 (expected 1)<br>
|
||||
<span class="pass">[PASS]</span> TAN(pi/4) = 1 (expected 1)<br>
|
||||
<span class="pass">[PASS]</span> ASIN(1.0) = 1.5708 (expected 1.5708)<br>
|
||||
<span class="pass">[PASS]</span> ACOS(1.0) = 0 (expected 0)<br>
|
||||
<span class="pass">[PASS]</span> ATAN(1.0) = 0.785398 (expected 0.785398)<br>
|
||||
<span class="pass">[PASS]</span> ATAN2(1,1) = 0.785398 (expected 0.785398)
|
||||
<span class="section">-- Exponential Instructions --</span>
|
||||
<span class="pass">[PASS]</span> EXP(1) = 2.71828 (expected 2.71828)<br>
|
||||
<span class="pass">[PASS]</span> LOG(e) = 1 (expected 1)<br>
|
||||
<span class="pass">[PASS]</span> LOGAB(100,10) = 2 (expected 2)<br>
|
||||
<span class="pass">[PASS]</span> POW(2,10) = 1024 (expected 1024)<br>
|
||||
<span class="pass">[PASS]</span> SQRT(9) = 3 (expected 3)<br>
|
||||
<span class="pass">[PASS]</span> ROOT(27,3) = 3 (expected 3)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="note">
|
||||
<strong>Note on testing approach:</strong> The test program uses stub implementations
|
||||
of <code style="font-family:'IBM Plex Mono',monospace;font-size:0.85em">fetchOperDst()</code>,
|
||||
<code style="font-family:'IBM Plex Mono',monospace;font-size:0.85em">fetchOperSrc()</code>,
|
||||
and <code style="font-family:'IBM Plex Mono',monospace;font-size:0.85em">imp()</code>
|
||||
as no-ops, and sets <code style="font-family:'IBM Plex Mono',monospace;font-size:0.85em">_dst</code> and
|
||||
<code style="font-family:'IBM Plex Mono',monospace;font-size:0.85em">_src</code> manually.
|
||||
This isolates the instruction logic completely from the unimplemented CPU dispatch system.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
Spider Lang Internship 2026 · Diego Alberto López
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user