Files
lopez-repo/blog-instrucciones.html

552 lines
17 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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 &nbsp;·&nbsp; spider-runtime &nbsp;·&nbsp; 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 (0x0600x067) 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>&lt;<span class="type">u32</span>&gt;(_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 &nbsp;·&nbsp; Diego Alberto López
</footer>
</body>
</html>