mirror of
https://github.com/lupyuen/lupyuen.github.io.git
synced 2025-01-13 09:08:30 +08:00
1092 lines
No EOL
59 KiB
HTML
1092 lines
No EOL
59 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="generator" content="rustdoc">
|
||
<title>QuickJS JavaScript Engine on a Real-Time Operating System (Apache NuttX RTOS)</title>
|
||
|
||
|
||
<!-- Begin scripts/articles/*-header.html: Article Header for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
<meta property="og:title"
|
||
content="QuickJS JavaScript Engine on a Real-Time Operating System (Apache NuttX RTOS)"
|
||
data-rh="true">
|
||
<meta property="og:description"
|
||
content="Can we run QuickJS JavaScript Engine on Apache NuttX RTOS? And Blink the LED on Ox64 BL808 RISC-V SBC... In 4 lines of JavaScript? Let’s do it!"
|
||
data-rh="true">
|
||
<meta name="description"
|
||
content="Can we run QuickJS JavaScript Engine on Apache NuttX RTOS? And Blink the LED on Ox64 BL808 RISC-V SBC... In 4 lines of JavaScript? Let’s do it!">
|
||
<meta property="og:image"
|
||
content="https://lupyuen.github.io/images/quickjs-title.png">
|
||
<meta property="og:type"
|
||
content="article" data-rh="true">
|
||
<link rel="canonical"
|
||
href="https://lupyuen.org/articles/quickjs.html" />
|
||
<!-- End scripts/articles/*-header.html -->
|
||
<!-- Begin scripts/rustdoc-header.html: Header for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
<link rel="alternate" type="application/rss+xml" title="RSS Feed for lupyuen" href="/rss.xml" />
|
||
<link rel="stylesheet" type="text/css" href="../normalize.css">
|
||
<link rel="stylesheet" type="text/css" href="../rustdoc.css" id="mainThemeStyle">
|
||
<link rel="stylesheet" type="text/css" href="../dark.css">
|
||
<link rel="stylesheet" type="text/css" href="../light.css" id="themeStyle">
|
||
<link rel="stylesheet" type="text/css" href="../prism.css">
|
||
<script src="../storage.js"></script><noscript>
|
||
<link rel="stylesheet" href="../noscript.css"></noscript>
|
||
<link rel="shortcut icon" href="../favicon.ico">
|
||
<style type="text/css">
|
||
#crate-search {
|
||
background-image: url("../down-arrow.svg");
|
||
}
|
||
</style>
|
||
<!-- End scripts/rustdoc-header.html -->
|
||
|
||
|
||
</head>
|
||
<body class="rustdoc">
|
||
<!--[if lte IE 8]>
|
||
<div class="warning">
|
||
This old browser is unsupported and will most likely display funky
|
||
things.
|
||
</div>
|
||
<![endif]-->
|
||
|
||
|
||
<!-- Begin scripts/rustdoc-before.html: Pre-HTML for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
|
||
<!-- Begin Theme Picker -->
|
||
<div class="theme-picker" style="left: 0"><button id="theme-picker" aria-label="Pick another theme!"><img src="../brush.svg"
|
||
width="18" alt="Pick another theme!"></button>
|
||
<div id="theme-choices"></div>
|
||
</div>
|
||
<!-- Theme Picker -->
|
||
|
||
<!-- End scripts/rustdoc-before.html -->
|
||
|
||
|
||
<h1 class="title">QuickJS JavaScript Engine on a Real-Time Operating System (Apache NuttX RTOS)</h1>
|
||
<nav id="rustdoc"><ul>
|
||
<li><a href="#quickjs-on-nuttx-emulator" title="QuickJS on NuttX Emulator">1 QuickJS on NuttX Emulator</a><ul></ul></li>
|
||
<li><a href="#build-quickjs-for-nuttx" title="Build QuickJS for NuttX">2 Build QuickJS for NuttX</a><ul></ul></li>
|
||
<li><a href="#nuttx-stack-is-full-of-quickjs" title="NuttX Stack is Full of QuickJS">3 NuttX Stack is Full of QuickJS</a><ul></ul></li>
|
||
<li><a href="#add-ioctl-to-quickjs" title="Add ioctl() to QuickJS">4 Add ioctl() to QuickJS</a><ul></ul></li>
|
||
<li><a href="#quickjs-blinks-the-led-on-ox64-sbc" title="QuickJS Blinks the LED on Ox64 SBC">5 QuickJS Blinks the LED on Ox64 SBC</a><ul></ul></li>
|
||
<li><a href="#how-small-is-quickjs" title="How Small is QuickJS">6 How Small is QuickJS</a><ul></ul></li>
|
||
<li><a href="#simulate-the-led-on-ox64-emulator" title="Simulate the LED on Ox64 Emulator">7 Simulate the LED on Ox64 Emulator</a><ul></ul></li>
|
||
<li><a href="#whats-next" title="What’s Next">8 What’s Next</a><ul></ul></li>
|
||
<li><a href="#appendix-build-quickjs-for-nuttx" title="Appendix: Build QuickJS for NuttX">9 Appendix: Build QuickJS for NuttX</a><ul></ul></li>
|
||
<li><a href="#appendix-build-nuttx-for-qemu" title="Appendix: Build NuttX for QEMU">10 Appendix: Build NuttX for QEMU</a><ul></ul></li>
|
||
<li><a href="#appendix-build-nuttx-for-ox64" title="Appendix: Build NuttX for Ox64">11 Appendix: Build NuttX for Ox64</a><ul></ul></li></ul></nav><p>📝 <em>18 Feb 2024</em></p>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-title.webp" alt="QuickJS JavaScript Engine on a Real-Time Operating System (Apache NuttX RTOS)" /></p>
|
||
<p><a href="https://lupyuen.github.io/nuttx-tinyemu/quickjs/"><em>(Try the Online Demo)</em></a></p>
|
||
<p><a href="https://youtu.be/AFDVceqQNRs"><em>(Watch the Demo on YouTube)</em></a></p>
|
||
<p><a href="https://github.com/bellard/quickjs"><strong>QuickJS</strong></a> is a small <strong>JavaScript Engine</strong> that supports <a href="https://bellard.org/quickjs/quickjs.html#os-module"><strong>POSIX Functions</strong></a>.</p>
|
||
<p><a href="https://nuttx.apache.org/docs/latest/index.html"><strong>Apache NuttX RTOS</strong></a> is a tiny <strong>Real-Time Operating System</strong> (for all kinds of devices) that’s compatible with POSIX.</p>
|
||
<p><em>Can we run QuickJS on NuttX? And Blink the LED in 4 lines of JavaScript?</em></p>
|
||
<div class="example-wrap"><pre class="language-javascript"><code>// Blink the NuttX LED, on then off
|
||
const ULEDIOC_SETALL = 0x1d03;
|
||
const fd = os.open("/dev/userleds", os.O_WRONLY);
|
||
os.ioctl(fd, ULEDIOC_SETALL, 1);
|
||
os.ioctl(fd, ULEDIOC_SETALL, 0);</code></pre></div>
|
||
<p>Let’s do it! In this article we…</p>
|
||
<ul>
|
||
<li>
|
||
<p>Run QuickJS on <strong>Ox64 BL808 RISC-V SBC</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Blink the LED by adding the <strong>ioctl() function</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Reconfigure the <strong>NuttX App Stack</strong> (because it’s too tiny)</p>
|
||
</li>
|
||
<li>
|
||
<p>Analyse the <strong>Memory Footprint</strong> of QuickJS (Code + Data + Heap Size)</p>
|
||
</li>
|
||
<li>
|
||
<p>Test QuickJS in the Web Browser with <strong>NuttX Emulator</strong> (and a Simulated LED)</p>
|
||
</li>
|
||
</ul>
|
||
<p>QuickJS is perfect for Iterative, Interactive Experiments on NuttX! We go hands-on (fingers too)…</p>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-title2.png" alt="QuickJS JavaScript Engine in Ox64 NuttX Emulator" /></p>
|
||
<h1 id="quickjs-on-nuttx-emulator"><a class="doc-anchor" href="#quickjs-on-nuttx-emulator">§</a>1 QuickJS on NuttX Emulator</h1>
|
||
<p>Click here to try <strong>QuickJS JavaScript Engine</strong> in NuttX Emulator (pic above)…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/nuttx-tinyemu/quickjs"><strong>QuickJS on Ox64 NuttX Emulator</strong></a></p>
|
||
<p><a href="https://youtu.be/AFDVceqQNRs">(Watch the <strong>Demo on YouTube</strong>)</a></p>
|
||
</li>
|
||
</ul>
|
||
<p>Now we do some Finger Exercises (sorry <strong>copy-pasta won’t work</strong> in the Emulator)</p>
|
||
<ol>
|
||
<li>
|
||
<p>To start QuickJS: Enter this at the <strong>NSH Prompt</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>qjs</code></pre></div></li>
|
||
<li>
|
||
<p>At the QuickJS Prompt: We define the <strong>NuttX LED Command</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-javascript"><code>ULEDIOC_SETALL = 0x1d03</code></pre></div>
|
||
<p><a href="https://lupyuen.github.io/articles/nim#blink-an-led">(About <strong>ULEDIOC_SETALL</strong>)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Next we open the <strong>NuttX LED Device</strong> (write-only)…</p>
|
||
<div class="example-wrap"><pre class="language-javascript"><code>fd = os.open("/dev/userleds", os.O_WRONLY)</code></pre></div></li>
|
||
<li>
|
||
<p>Watch what happens when we <strong>Flip On the LED</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-javascript"><code>os.ioctl(fd, ULEDIOC_SETALL, 1)</code></pre></div>
|
||
<p><strong>GPIO 29</strong> turns Green! (Pic above)</p>
|
||
</li>
|
||
<li>
|
||
<p>When we <strong>Flip Off the LED</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-javascript"><code>os.ioctl(fd, ULEDIOC_SETALL, 0)</code></pre></div>
|
||
<p><strong>GPIO 29</strong> goes back to Normal!</p>
|
||
</li>
|
||
<li>
|
||
<p>Our Demo does this…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>NuttShell (NSH) NuttX-12.4.0-RC0
|
||
nsh> qjs
|
||
QuickJS - Type "\h" for help
|
||
|
||
## Define the NuttX LED Command
|
||
qjs > ULEDIOC_SETALL = 0x1d03
|
||
7427
|
||
|
||
## Open the NuttX LED Device (write-only)
|
||
qjs > fd = os.open("/dev/userleds", os.O_WRONLY)
|
||
3
|
||
|
||
## Flip LED On: GPIO 29 turns Green
|
||
qjs > os.ioctl(fd, ULEDIOC_SETALL, 1)
|
||
|
||
## Flip LED Off: GPIO 29 goes back to normal
|
||
qjs > os.ioctl(fd, ULEDIOC_SETALL, 0)</code></pre></div>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx#quickjs-blinks-the-led-on-ox64-emulator">(See the <strong>Complete Log</strong>)</a></p>
|
||
<p><a href="https://youtu.be/AFDVceqQNRs">(Watch the <strong>Demo on YouTube</strong>)</a></p>
|
||
</li>
|
||
</ol>
|
||
<p><em>Erm our fingers are hurting?</em></p>
|
||
<p>Try this <strong>Non-Interactive JavaScript</strong> with QuickJS…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>nsh> qjs --std /system/bin/blink.js</code></pre></div>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/blink.js">(See the <strong>Blinky JavaScript</strong>)</a></p>
|
||
<p><a href="https://bellard.org/quickjs/quickjs.html#qjs-interpreter">(Option “<strong><code>--std</code></strong>” will import the <strong>POSIX Functions</strong>)</a></p>
|
||
<p><em>Wow… A Blinky in JavaScript?</em></p>
|
||
<p>Yep we flipped this <a href="https://github.com/lupyuen/quickjs-nuttx#quickjs-calls-nuttx-led-driver"><strong>NuttX Blinky App</strong></a> from C to <strong>Interactive JavaScript</strong>!</p>
|
||
<p><em>Does it work on Real Hardware?</em></p>
|
||
<p>The exact same QuickJS blinks a Real LED on <a href="https://www.hackster.io/lupyuen/8-risc-v-sbc-on-a-real-time-operating-system-ox64-nuttx-474358"><strong>Ox64 BL808 SBC</strong></a>, based on 64-bit RISC-V. (We’ll come back to this)</p>
|
||
<p>How did we make this happen? Read on to find out…</p>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-expect.png" alt="Auto-Test QuickJS with Expect Scripting" /></p>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/qemu.exp"><em>Auto-Test QuickJS with Expect Scripting</em></a></p>
|
||
<h1 id="build-quickjs-for-nuttx"><a class="doc-anchor" href="#build-quickjs-for-nuttx">§</a>2 Build QuickJS for NuttX</h1>
|
||
<p><em>QuickJS compiles OK for NuttX?</em></p>
|
||
<p>Mostly. QuickJS compiles for NuttX <strong>with no code changes</strong>…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/quickjs#appendix-build-quickjs-for-nuttx"><strong>“Build QuickJS for NuttX”</strong></a></li>
|
||
</ul>
|
||
<p>Then we hit some <strong>Missing Functions</strong>…</p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>POSIX Functions:</strong> <em>popen, pclose, pipe2, symlink, …</em></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Dynamic Linking:</strong> <em>dlopen, dlsym, dlclose</em></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Math Functions:</strong> <em>pow, floor, trunc, …</em></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Atomic Functions:</strong> <em>atomic_fetch_add_2, atomic_fetch_or_1, …</em></p>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx#fix-the-missing-functions">(See the <strong>Missing Functions</strong>)</a></p>
|
||
</li>
|
||
</ol>
|
||
<p><em>Can we fill in the missing functions?</em></p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>POSIX Functions:</strong> The typical POSIX Functions are OK. The special ones are probably available if we tweak the <strong>Build Options</strong> for NuttX.</p>
|
||
<p>For now, we stick with the Basic NuttX Config and stub out the <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/stub.c#L10-L14"><strong>Advanced POSIX Functions</strong></a>.</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Dynamic Linking:</strong> We won’t support Dynamic Linking for NuttX. We <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/stub.c#L3-L5"><strong>stubbed the missing functions</strong></a>.</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Math Functions:</strong> We linked them with GCC Option “<strong><code>-lm</code></strong>”. The last few stragglers: We <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/stub.c#L7-L9"><strong>stubbed the functions</strong></a>.</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Atomic Functions:</strong> We filled in the <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/arch_atomic.c#L32-L743"><strong>Missing Atomic Functions</strong></a>.</p>
|
||
<p><a href="https://github.com/apache/nuttx/issues/10642">(About <strong>NuttX Atomic Functions</strong>)</a></p>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/quickjs.c#L67-L73">(We might <strong>Disable Atomic Functions</strong>)</a></p>
|
||
</li>
|
||
</ol>
|
||
<p>After these fixes, QuickJS builds OK for NuttX!</p>
|
||
<p><a href="https://lupyuen.github.io/articles/quickjs#appendix-build-quickjs-for-nuttx">(How to build <strong>QuickJS for NuttX</strong>)</a></p>
|
||
<p><em>That’s plenty of stubbing. Will it break QuickJS?</em></p>
|
||
<p>Thankfully we have <strong>Automated Testing</strong> with an Expect Script (pic above): <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/qemu.exp">qemu.exp</a></p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>#!/usr/bin/expect
|
||
## Expect Script for Testing QuickJS with QEMU Emulator
|
||
|
||
## For every 1 character sent, wait 0.001 milliseconds
|
||
set send_slow {1 0.001}
|
||
|
||
## Start NuttX on QEMU Emulator
|
||
## Remove `-bios none` for newer versions of NuttX
|
||
spawn qemu-system-riscv64 \
|
||
-semihosting \
|
||
-M virt,aclint=on \
|
||
-cpu rv64 \
|
||
-bios none \
|
||
-kernel nuttx \
|
||
-nographic
|
||
|
||
## Wait for the prompt and enter this command
|
||
expect "nsh> "
|
||
send -s "qjs -e console.log(123) \r"
|
||
|
||
## Check the response...
|
||
expect {
|
||
## If we see this message, exit normally
|
||
"nsh>" { exit 0 }
|
||
|
||
## If timeout, exit with an error
|
||
timeout { exit 1 }
|
||
}</code></pre></div>
|
||
<p>Before the Auto-Test, we solve the Auto-Crash…</p>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-stack.webp" alt="Loopy Stack Trace probably means Stack Full" /></p>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx/blob/0aafbb7572d4d0a1f7ac48d0b6a5ac0ba8374cfc/nuttx/qemu.log#L5385-L5478"><em>Loopy Stack Trace probably means Stack Full</em></a></p>
|
||
<h1 id="nuttx-stack-is-full-of-quickjs"><a class="doc-anchor" href="#nuttx-stack-is-full-of-quickjs">§</a>3 NuttX Stack is Full of QuickJS</h1>
|
||
<p><em>QuickJS builds OK for NuttX. Does it run?</em></p>
|
||
<p>Sorry nope! QuickJS ran into <a href="https://github.com/lupyuen/quickjs-nuttx#quickjs-crashes-on-nuttx"><strong>Bizarre Crashes</strong></a> on NuttX (with looping Stack Traces, pic above)…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx#atom-sentinel-becomes-0xffff_ffff"><strong>Strange Pointers</strong></a> (<code>0xFFFF_FFFF</code>) while reading the JavaScript Atoms</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx#unexpected-character-in-quickjs"><strong>Unexpected Characters</strong></a> (<code>0xFF</code>) appeared in our JavaScript Strings</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx#malloc-problems-in-nuttx"><strong>Malloc was Erasing</strong></a> our JavaScript Strings</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx#heap-errors-and-stdio-weirdness"><strong>Heap Memory</strong></a> got weirdly corrupted (even <strong>printf()</strong> failed)</p>
|
||
</li>
|
||
</ul>
|
||
<p>After plenty of headscratching troubleshooting, this <a href="https://github.com/lupyuen/quickjs-nuttx#nuttx-stack-is-full-of-quickjs"><strong>Vital Clue</strong></a> suddenly pops up…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code>riscv_exception: EXCEPTION: Load page fault. MCAUSE: 000000000000000d, EPC: 00000000c0006d52, MTVAL: ffffffffffffffff
|
||
PID GRP PRI POLICY TYPE NPX STATE EVENT STACKBASE SIZE USED FILLED COMMAND
|
||
0x802002b0 2048 2040 99.6%! irq
|
||
0 0 0 FIFO Kthread - Ready 0x80206010 3056 1856 60.7% Idle_Task
|
||
1 1 100 RR Kthread - Waiting Semaphore 0x8020a050 1968 704 35.7% lpwork 0x802015f0 0x80201618
|
||
2 2 100 RR Task - Waiting Semaphore 0xc0202040 3008 744 24.7% /system/bin/init
|
||
3 3 100 RR Task - Running 0xc0202050 1968 1968 100.0%! qjs }¼uq¦ü®²äÅ</code></pre></div>
|
||
<p>The last line shows that the <strong>QuickJS Stack</strong> (2 KB) is <strong>100% Full</strong>! (With the Command Line incorrigibly corrupted)</p>
|
||
<p>We follow these steps to <a href="https://github.com/lupyuen/nuttx-star64#increase-stack-size"><strong>increase the App Stack Size</strong></a>…</p>
|
||
<ol>
|
||
<li>
|
||
<p>Enter “<strong><code>make menuconfig</code></strong>”</p>
|
||
</li>
|
||
<li>
|
||
<p>Select <em>“Library Routines > Program Execution Options”</em></p>
|
||
</li>
|
||
<li>
|
||
<p>Set <em>“Default task_spawn Stack Size”</em> to <strong>65536</strong></p>
|
||
<p>(That’s 64 KB)</p>
|
||
</li>
|
||
<li>
|
||
<p>Select <em>“Library Routines > Thread Local Storage (TLS)”</em></p>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx#fix-quickjs-interactive-mode-on-nuttx">(Why we set <strong>Thread Local Storage</strong>)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Set <em>“Maximum Stack Size (Log2)”</em> to <strong>16</strong></p>
|
||
<p>(Because 2^16 = 64 KB)</p>
|
||
</li>
|
||
</ol>
|
||
<p>Which becomes this in our <strong>NuttX Build Config</strong>: <a href="https://github.com/lupyuen2/wip-nuttx/commit/904b95534298378d64b99c1f9e649f8bc27a8048#diff-fa4b30efe1c5e19ba2fdd2216528406d85fa89bf3d2d0e5161794191c1566078">ox64/nsh/defconfig</a></p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Upsize the App Stack to 64 KB
|
||
CONFIG_POSIX_SPAWN_DEFAULT_STACKSIZE=65536
|
||
CONFIG_TLS_LOG2_MAXSTACK=16</code></pre></div>
|
||
<p>QuickJS crashes no more!</p>
|
||
<p><strong>Lesson Learnt:</strong> If the NuttX Stack Dump loops forever, we’re probably <strong>Out Of Stack Space</strong>.</p>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-posix.png" alt="POSIX Functions in QuickJS" /></p>
|
||
<p><a href="https://bellard.org/quickjs/quickjs.html#os-module"><em>POSIX Functions in QuickJS</em></a></p>
|
||
<h1 id="add-ioctl-to-quickjs"><a class="doc-anchor" href="#add-ioctl-to-quickjs">§</a>4 Add ioctl() to QuickJS</h1>
|
||
<p><em>ioctl() doesn’t appear in the QuickJS Docs? (Pic above)</em></p>
|
||
<div class="example-wrap"><pre class="language-javascript"><code>// Flip On the NuttX LED
|
||
const ULEDIOC_SETALL = 0x1d03;
|
||
const fd = os.open("/dev/userleds", os.O_WRONLY);
|
||
os.ioctl(fd, ULEDIOC_SETALL, 1);</code></pre></div>
|
||
<p>That’s because we added <strong>ioctl()</strong> to QuickJS: <a href="https://github.com/lupyuen/quickjs-nuttx/commit/91aaf4257992c08b01590f0d61fa37a386933a4b#diff-95fe784bea3e0fbdf30ba834b1a74b538090f4d70f4f8770ef397ef68ec37aa3">quickjs-libc.c</a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>// List of JavaScript Functions in `os` Module
|
||
static const JSCFunctionListEntry js_os_funcs[] = {
|
||
...
|
||
// Declare our ioctl() function...
|
||
JS_CFUNC_DEF(
|
||
"ioctl", // Function Name
|
||
3, // Parameters
|
||
js_os_ioctl // Implemented here
|
||
),
|
||
};
|
||
|
||
// Define our ioctl() function
|
||
static JSValue js_os_ioctl(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
||
int fd, req; // ioctl() File Descriptor and Request Number
|
||
int64_t arg, ret; // ioctl() Parameter and Return Value
|
||
BOOL is_bigint; // True if we're using BigInt
|
||
|
||
// First Arg is ioctl() File Descriptor (int32)
|
||
if (JS_ToInt32(ctx, &fd, argv[0]))
|
||
return JS_EXCEPTION;
|
||
|
||
// Second Arg is ioctl() Request Number (int32)
|
||
if (JS_ToInt32(ctx, &req, argv[1]))
|
||
return JS_EXCEPTION;
|
||
|
||
// Third Arg is ioctl() Parameter (int64)
|
||
// TODO: What if it's int32? What about passing a Pointer to a C Struct?
|
||
is_bigint = JS_IsBigInt(ctx, argv[2]);
|
||
if (JS_ToInt64Ext(ctx, &arg, argv[2]))
|
||
return JS_EXCEPTION;
|
||
|
||
// Call NuttX ioctl()
|
||
ret = ioctl(fd, req, arg);
|
||
if (ret == -1)
|
||
ret = -errno;
|
||
|
||
// Return the Result as BigInt or Normal Integer
|
||
if (is_bigint)
|
||
return JS_NewBigInt64(ctx, ret);
|
||
else
|
||
return JS_NewInt64(ctx, ret);
|
||
}</code></pre></div>
|
||
<p>After adding this code to QuickJS, <strong>ioctl()</strong> comes to life…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>NuttShell (NSH) NuttX-12.4.0-RC0
|
||
nsh> qjs
|
||
QuickJS - Type "\h" for help
|
||
|
||
qjs > os.ioctl
|
||
function ioctl()
|
||
|
||
qjs > os.ioctl(1,2,3)
|
||
-25
|
||
|
||
qjs > os.ioctl(100,2,3)
|
||
-9</code></pre></div>
|
||
<p>We test <strong>ioctl()</strong> on real hardware…</p>
|
||
<p><img src="https://lupyuen.github.io/images/nim-wiring.webp" alt="Connect an LED to Ox64 SBC at GPIO 29, Pin 21" /></p>
|
||
<h1 id="quickjs-blinks-the-led-on-ox64-sbc"><a class="doc-anchor" href="#quickjs-blinks-the-led-on-ox64-sbc">§</a>5 QuickJS Blinks the LED on Ox64 SBC</h1>
|
||
<p><em>We added ioctl() to QuickJS. Does it work?</em></p>
|
||
<p>We test <strong>ioctl()</strong> on a Real Device with a Real LED: <strong>Ox64 BL808 RISC-V SBC</strong>. Right after these tweaks…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/commit/8f75f3744f3964bd3ed0596421a93e59fb39cdd8"><strong>Add the GPIO Driver</strong></a> for Ox64 BL808</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/commit/4f3996959132ca0d35874b7be3eef89d6bf7f351"><strong>Add the LED Driver</strong></a> for Ox64 BL808</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/commit/904b95534298378d64b99c1f9e649f8bc27a8048"><strong>Increase the App Stack Size</strong></a> from 2 KB to 64 KB</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/commit/28453790d06c0282b85e5df98624f8fa1c0b2226"><strong>Increase the RAM Disk Region</strong></a> from 16 MB to 40 MB</p>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx#add-led-driver-to-nuttx-ox64-bl808-sbc">(Why we enlarge the <strong>RAM Disk Region</strong>)</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx-apps/commit/66f1389c8d17eecdc5ef7baa62d13435bd053ee3"><strong>Patch the <code>leds</code> app</strong></a> for testing LED Driver</p>
|
||
<p>(Because <strong>task_create()</strong> is missing from Kernel Mode)</p>
|
||
</li>
|
||
</ul>
|
||
<p>Follow these steps to download (or build) <strong>NuttX and QuickJS</strong>…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/quickjs#appendix-build-nuttx-for-ox64"><strong>“Build NuttX for Ox64”</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/quickjs#appendix-build-quickjs-for-nuttx"><strong>“Build QuickJS for NuttX Ox64”</strong></a></p>
|
||
</li>
|
||
</ul>
|
||
<p>Connect an LED to Ox64 SBC at <strong>GPIO 29, Pin 21</strong> (pic above)…</p>
|
||
<div><table><thead><tr><th style="text-align: left">Connect</th><th style="text-align: left">To</th><th style="text-align: left">Wire</th></tr></thead><tbody>
|
||
<tr><td style="text-align: left"><strong>Ox64 Pin 21</strong> <br><em>(GPIO 29)</em></td><td style="text-align: left"><strong>Resistor</strong> <br><em>(47 Ohm)</em></td><td style="text-align: left">Red</td></tr>
|
||
<tr><td style="text-align: left"><strong>Resistor</strong> <br><em>(47 Ohm)</em></td><td style="text-align: left"><strong>LED +</strong> <br><em>(Curved Edge)</em></td><td style="text-align: left">Breadboard</td></tr>
|
||
<tr><td style="text-align: left"><strong>LED -</strong> <br><em>(Flat Edge)</em></td><td style="text-align: left"><strong>Ox64 Pin 23</strong> <br><em>(GND)</em></td><td style="text-align: left">Black</td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<p><a href="https://wiki.pine64.org/wiki/File:Ox64_pinout.png">(See the <strong>Ox64 Pinout</strong>)</a></p>
|
||
<p>(Resistor is <strong>47 Ohm</strong>, yellow-purple-black-gold, almost Karma Chameleon)</p>
|
||
<p>Boot NuttX on Ox64. Enter these commands…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>NuttShell (NSH) NuttX-12.4.0-RC0
|
||
nsh> qjs
|
||
QuickJS - Type "\h" for help
|
||
|
||
## Define the NuttX LED Command
|
||
qjs > ULEDIOC_SETALL = 0x1d03
|
||
7427
|
||
|
||
## Open the NuttX LED Device (write-only)
|
||
qjs > fd = os.open("/dev/userleds", os.O_WRONLY)
|
||
3
|
||
|
||
## Flip LED to On
|
||
qjs > os.ioctl(fd, ULEDIOC_SETALL, 1)
|
||
bl808_gpiowrite: regaddr=0x20000938, set=0x1000000
|
||
0
|
||
|
||
## Flip LED to Off
|
||
qjs > os.ioctl(fd, ULEDIOC_SETALL, 0)
|
||
bl808_gpiowrite: regaddr=0x20000938, clear=0x1000000
|
||
0</code></pre></div>
|
||
<p><a href="https://gist.github.com/lupyuen/aeb74f047dc81be08e812458232ef92f#file-nuttx-quickjs-ox64-log-L165-L247">(Or run the <strong>Blinky JavaScript</strong>)</a></p>
|
||
<p>Yep <strong>ioctl()</strong> works great on a Real Device, with a Real LED!</p>
|
||
<p><a href="https://youtu.be/jv29M16CFJQ">(Watch the <strong>Demo on YouTube</strong>)</a></p>
|
||
<p><a href="https://gist.github.com/lupyuen/aeb74f047dc81be08e812458232ef92f#file-nuttx-quickjs-ox64-log-L112-L247">(See the <strong>NuttX Log</strong>)</a></p>
|
||
<p><img src="https://lupyuen.github.io/images/nim-blink2.webp" alt="Apache NuttX RTOS on Ox64 BL808 RISC-V SBC: QuickJS blinks our LED" /></p>
|
||
<p><em>If we don’t have an Ox64 SBC?</em></p>
|
||
<p>No worries, the exact same steps will work for <strong>QEMU Emulator</strong> (64-bit RISC-V)…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/commit/1037eda906f11aef44f7670f8cc5a1c1d2141911"><strong>Add the LED Driver</strong></a> for QEMU</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/commit/3b662696aff4b89e2b873a6b75d0006860fc9f7b"><strong>Increase the App Stack Size</strong></a> from 2 KB to 64 KB</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx-apps/commit/45dbe5ce07239e7ca7dcb50cb0e55da151052429"><strong>Patch the <code>leds</code> app</strong></a> for testing LED Driver</p>
|
||
</li>
|
||
</ul>
|
||
<p>When we download (or build) <strong>NuttX and QuickJS</strong>…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/quickjs#appendix-build-nuttx-for-qemu"><strong>“Build NuttX for QEMU”</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/quickjs#appendix-build-quickjs-for-nuttx"><strong>“Build QuickJS for NuttX QEMU”</strong></a></p>
|
||
</li>
|
||
</ul>
|
||
<p>QuickJS blinks a <strong>Simulated LED</strong> on NuttX QEMU…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Start NuttX on QEMU
|
||
## Remove `-bios none` for newer versions of NuttX
|
||
$ qemu-system-riscv64 -semihosting -M virt,aclint=on -cpu rv64 -bios none -kernel nuttx -nographic
|
||
|
||
## Run our Blinky JavaScript with QuickJS
|
||
NuttShell (NSH) NuttX-12.4.0-RC0
|
||
nsh> qjs --std /system/bin/blink.js
|
||
led=0, val=1
|
||
led=0, val=0
|
||
led=0, val=1</code></pre></div>
|
||
<p>To Exit QEMU: Press <strong><code>Ctrl-A</code></strong> then <strong><code>x</code></strong></p>
|
||
<p><a href="https://gist.github.com/lupyuen/a3d2a491112eaf5810edc1fa355606db">(See the <strong>Complete Log</strong>)</a></p>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-text.webp" alt="QuickJS Code Size rendered with linkermapviz" /></p>
|
||
<p><a href="https://lupyuen.github.io/nuttx-tinyemu/quickjs/linkermap"><em>QuickJS Code Size rendered with linkermapviz</em></a></p>
|
||
<h1 id="how-small-is-quickjs"><a class="doc-anchor" href="#how-small-is-quickjs">§</a>6 How Small is QuickJS</h1>
|
||
<p><em>Will QuickJS run on all kinds of NuttX Devices?</em></p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>$ riscv64-unknown-elf-size apps/bin/qjs
|
||
text data bss dec
|
||
554847 260 94 555201</code></pre></div>
|
||
<p>Probably not ALL devices? JavaScript needs <strong>a fair bit of RAM</strong> to run comfortably.</p>
|
||
<p><em>What’s the Memory Footprint like?</em></p>
|
||
<p>We ran <a href="https://github.com/PromyLOPh/linkermapviz"><strong>linkermapviz</strong></a> on the <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/qjs-riscv.map"><strong>QuickJS Linker Map</strong></a> for NuttX QEMU…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Visualise the QuickJS Linker Map for NuttX QEMU.
|
||
## Produces linkermap.html: https://github.com/lupyuen/nuttx-tinyemu/blob/main/docs/quickjs/linkermap.html
|
||
|
||
git clone https://github.com/PromyLOPh/linkermapviz
|
||
cd linkermapviz
|
||
pip3 install .
|
||
linkermapviz < quickjs-nuttx/nuttx/qjs-riscv.map</code></pre></div>
|
||
<p>Which produces the <a href="https://lupyuen.github.io/nuttx-tinyemu/quickjs/linkermap"><strong>Visualised Linker Map</strong></a> for QuickJS. (Pics above and below)</p>
|
||
<p>Here are the sizes of QuickJS and its options…</p>
|
||
<div><table><thead><tr><th style="text-align: left">Size of Code + Data (Read-Only)</th><th style="text-align: center"></th></tr></thead><tbody>
|
||
<tr><td style="text-align: left">QuickJS with All The Toppings</td><td style="text-align: center"><strong>554 KB</strong></td></tr>
|
||
<tr><td style="text-align: left">Without REPL</td><td style="text-align: center"><strong>538 KB</strong></td></tr>
|
||
<tr><td style="text-align: left">Without BigInt</td><td style="text-align: center"><strong>522 KB</strong></td></tr>
|
||
<tr><td style="text-align: left">Without BigInt, REPL</td><td style="text-align: center"><strong>506 KB</strong></td></tr>
|
||
</tbody></table>
|
||
</div><span style="font-size:90%">
|
||
<p><a href="https://bellard.org/quickjs/quickjs.html#Quick-start">(<strong>REPL</strong> is for Interactive Commands)</a></p>
|
||
<p><a href="https://bellard.org/quickjs/quickjs.html#BigInt_002c-BigFloat_002c-BigDecimal">(<strong>BigInt</strong> is for Big Numbers and Calculator)</a></p>
|
||
</span>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-data.jpg" alt="QuickJS Data Size" /></p>
|
||
<p><em>What about Heap Memory Size?</em></p>
|
||
<p>Based on the NuttX Logs with <a href="https://github.com/lupyuen2/wip-nuttx/blob/master/Kconfig#L963-L988"><strong>Heap Logging Enabled</strong></a>: <em>“Build Setup > Debug Options > Enable Debug Features > Memory Manager Debug Features > Info Output”</em></p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx/blob/d2dbef1afef26ae4cc76719d7cac3740da5f3387/nuttx/qemu.log#L74-L2905"><strong>Heap Log: Without REPL</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx/blob/38e004e6eb643932f6957e03828ad25242cf803a/nuttx/qemu.log#L74-L18308"><strong>Heap Log: With REPL</strong></a></p>
|
||
<p><a href="https://lupyuen.github.io/articles/quickjs#appendix-build-quickjs-for-nuttx">(<strong>REPL</strong> runs extra <strong>JavaScript Bytecode</strong>)</a></p>
|
||
</li>
|
||
</ul>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-sheet.webp" alt="Computing the QuickJS Heap Usage with a Spreadsheet" /></p>
|
||
<p>We compute the <strong>Heap Usage</strong> with a Spreadsheet (pic above)…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://docs.google.com/spreadsheets/d/1EpdktueHxfAR4VR80d1XSZRwdO2UvNGf_sPetHHzAGQ/edit?usp=sharing"><strong>Heap Usage: Without REPL</strong> (Google Sheets)</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://docs.google.com/spreadsheets/d/1g0-O2qdgjwNfSIxfayNzpUN8mmMyWFmRf2dMyQ9a8JI/edit?usp=sharing"><strong>Heap Usage: With REPL</strong> (Google Sheets)</a></p>
|
||
</li>
|
||
</ul>
|
||
<p>(<strong>“Free Size”</strong> might be inaccurate because it uses <strong>VLOOKUP</strong> for Top-Down Lookup, though we actually need Down-Top Lookup)</p>
|
||
<p>And we derive the <strong>QuickJS Heap Usage</strong> (pic below)…</p>
|
||
<div><table><thead><tr><th style="text-align: left">Max Heap Usage</th><th style="text-align: center"></th></tr></thead><tbody>
|
||
<tr><td style="text-align: left">QuickJS without REPL</td><td style="text-align: center"><strong>276 KB</strong></td></tr>
|
||
<tr><td style="text-align: left">QuickJS with REPL</td><td style="text-align: center"><strong>371 KB</strong></td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-heap.jpg" alt="QuickJS Heap Usage" /></p>
|
||
<p>Which totals <strong>782 KB</strong> for Barebones QuickJS. And a whopping <strong>925 KB</strong> for Turducken QuickJS. (Nearly 1 MB for Code + Data + Heap!)</p>
|
||
<p>For newer <strong>Upsized NuttX Gadgets</strong> that are <strong>Extra Roomy</strong> (and Vroomy), there’s a high chance that we can run QuickJS…</p>
|
||
<p>And experiment with all kinds of <strong>NuttX Drivers</strong> via ioctl(). The Interactive JavaScript Way!</p>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-size.png" alt="QEMU vs Ox64 QuickJS: 4 MB vs 22 MB" /></p>
|
||
<p><em>QEMU vs Ox64 QuickJS: Any diff? (Pic above)</em></p>
|
||
<p>QuickJS for NuttX QEMU is more Memory-Efficient because it uses <a href="https://github.com/lupyuen/quickjs-nuttx#full-linking-for-nuttx-apps"><strong>Full Linking</strong></a>.</p>
|
||
<p>(Instead of ELF Loader patching the <a href="https://lupyuen.github.io/articles/app#inside-a-nuttx-app"><strong>Relocatable Symbols</strong></a> at runtime)</p>
|
||
<p>Ox64 QuickJS was slower and <strong>multi-deca-mega-chonky</strong>: 22 MB! So we switched to <a href="https://github.com/lupyuen/quickjs-nuttx#switch-ox64-quickjs-to-full-linking"><strong>QuickJS with Full Linking</strong></a>, QuickJS is now 4 MB on Ox64. (Similar to QEMU)</p>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx#full-linking-for-nuttx-apps">(About <strong>NuttX Full Linking</strong>)</a></p>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-title.webp" alt="QuickJS JavaScript Engine to Apache NuttX RTOS" /></p>
|
||
<p><a href="https://youtu.be/AFDVceqQNRs"><em>Watch the Demo on YouTube</em></a></p>
|
||
<h1 id="simulate-the-led-on-ox64-emulator"><a class="doc-anchor" href="#simulate-the-led-on-ox64-emulator">§</a>7 Simulate the LED on Ox64 Emulator</h1>
|
||
<p><em>NuttX Emulator blinks a Simulated LED…</em></p>
|
||
<p><em>How does it work? (Pic above, lower right)</em></p>
|
||
<p>We modded <a href="https://lupyuen.github.io/articles/tinyemu3"><strong>NuttX Emulator</strong></a> (in WebAssembly) to…</p>
|
||
<ol>
|
||
<li>
|
||
<p>Watch for updates to <a href="https://lupyuen.github.io/articles/nim#led-driver-for-ox64"><strong>GPIO Registers</strong></a></p>
|
||
<p>(Like <code>0x2000_0938</code> for GPIO 29)</p>
|
||
</li>
|
||
<li>
|
||
<p>Notify our <a href="https://github.com/lupyuen/nuttx-tinyemu/blob/main/docs/quickjs/term.js#L487-L497"><strong>Web Browser JavaScript</strong></a> of any updates</p>
|
||
<p>(Like <em>{“nuttxemu”:{“gpio29”:1}}</em>)</p>
|
||
</li>
|
||
<li>
|
||
<p>And our Web Browser JavaScript <a href="https://github.com/lupyuen/nuttx-tinyemu/blob/main/docs/quickjs/term.js#L497-L507"><strong>Flips the Simulated LED</strong></a></p>
|
||
<p>(On or Off)</p>
|
||
</li>
|
||
</ol>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-led.jpg" alt="Simulate the LED on Ox64 Emulator" /></p>
|
||
<p>Here’s our <a href="https://lupyuen.github.io/articles/tinyemu3"><strong>NuttX Emulator</strong></a> (WebAssembly) intercepting all <strong>Writes to GPIO 29</strong>: <a href="https://github.com/lupyuen/ox64-tinyemu/blob/main/riscv_cpu.c#L486-L553">riscv_cpu.c</a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>// WebAssembly called by TinyEmu to emulate
|
||
// Writes to RISC-V Addresses
|
||
int target_write_slow(...) {
|
||
...
|
||
// Intercept Writes to Memory-Mapped I/O
|
||
switch(paddr) {
|
||
|
||
// If we're writing to BL808 GPIO 29 (0x2000_0938)...
|
||
case 0x20000938: {
|
||
// Send an Emulator Notification to the Console:
|
||
// {"nuttxemu":{"gpio29":1}}
|
||
|
||
// Check if the Output Bit is Off or On
|
||
#define reg_gpio_xx_o 24
|
||
const char b =
|
||
((val & (1 << reg_gpio_xx_o)) == 0)
|
||
? '0' : '1';
|
||
|
||
// Send the Notification to Console
|
||
char notify[] = "{\"nuttxemu\":{\"gpio29\":0}}\r\n";
|
||
notify[strlen(notify) - 5] = b;
|
||
print_console(NULL, notify, strlen(notify));
|
||
}</code></pre></div>
|
||
<p>Which sends a Notification to the Web Browser (JavaScript), saying that the <strong>GPIO Output has changed</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-json"><code>{"nuttxemu":
|
||
{"gpio29": 1}
|
||
}</code></pre></div>
|
||
<p>Our Web Browser (JavaScript) receives the Notification and <strong>Flips the Simulated LED</strong>: <a href="https://github.com/lupyuen/nuttx-tinyemu/blob/main/docs/quickjs/term.js#L487-L507">term.js</a></p>
|
||
<div class="example-wrap"><pre class="language-javascript"><code>// JavaScript called by our WebAssembly
|
||
// to print something to Console
|
||
Term.prototype.write = function(str) {
|
||
|
||
// If this is a Notification JSON from Emulator WebAssembly:
|
||
// {"nuttxemu":{"gpio29":1}}
|
||
if (str.indexOf(`{"nuttxemu":`) == 0) {
|
||
|
||
// Get the GPIO Number and GPIO Value from JSON
|
||
const notify = JSON.parse(str).nuttxemu; // {gpio29:1}
|
||
const gpio = Object.keys(notify)[0]; // "gpio29"
|
||
const val = notify[gpio]; // 0 or 1
|
||
|
||
// Render the GPIO in HTML:
|
||
// <td id="gpio29" class="gpio_on">GPIO29</td>
|
||
document.getElementById("status").style.width = document.getElementById("term_wrap").style.width; // Space out the GPIO Status
|
||
const gpio_status = document.getElementById(gpio);
|
||
gpio_status.style.display = "block";
|
||
|
||
// GPIO Off or On
|
||
gpio_status.className = (val == 0)
|
||
? "gpio_off" // Normal CSS Style
|
||
: "gpio_on"; // Green CSS Style
|
||
return; // Don't show in Console Output
|
||
}</code></pre></div>
|
||
<p><a href="https://github.com/lupyuen/nuttx-tinyemu/blob/main/docs/quickjs/index.html#L21-L29">(<strong>status</strong> and <strong>gpio29</strong> are in HTML)</a></p>
|
||
<p><a href="https://github.com/lupyuen/nuttx-tinyemu/blob/main/docs/quickjs/style.css#L106-L117">(<strong>gpio_off</strong> and <strong>gpio_on</strong> are in CSS)</a></p>
|
||
<p><strong>Emulator Notifications</strong> won’t appear in the Emulator Console Output. (Because we suppressed them)</p>
|
||
<p>We’ll see the Notifications in the <strong>JavaScript Console</strong>. (Pic below)</p>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-notify.png" alt="Notifications from NuttX Emulator appear in JavaScript Console" /></p>
|
||
<h1 id="whats-next"><a class="doc-anchor" href="#whats-next">§</a>8 What’s Next</h1>
|
||
<p>Thanks to the <a href="https://github.com/bellard/quickjs"><strong>QuickJS Team</strong></a>, we have a fun new way to Experiment Interactively with NuttX Gadgets!</p>
|
||
<ul>
|
||
<li>
|
||
<p>We ran QuickJS on <strong>Ox64 BL808 RISC-V SBC</strong> and <strong>NuttX Emulator</strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Blinking the LED works great after we added the <strong>ioctl() function</strong></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Memory Footprint</strong> of QuickJS might reach 1 MB (if we’re using all the features)</p>
|
||
</li>
|
||
<li>
|
||
<p>How will you use <strong>QuickJS on NuttX</strong>? Lemme know!</p>
|
||
</li>
|
||
</ul>
|
||
<p>Many Thanks to my <a href="https://lupyuen.github.io/articles/sponsor"><strong>GitHub Sponsors</strong></a> (and the awesome NuttX Community) for supporting my work! This article wouldn’t have been possible without your support.</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/sponsor"><strong>Sponsor me a coffee</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://news.ycombinator.com/item?id=39414388"><strong>Discuss this article on Hacker News</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://forum.pine64.org/showthread.php?tid=19083"><strong>Discuss this article on Pine64 Forum</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://bbs.bouffalolab.com/d/283-article-quickjs-javascript-on-a-real-time-operating-system-ox64-nuttx"><strong>Discuss this article on Bouffalo Lab Forum</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/nuttx-ox64"><strong>My Current Project: “Apache NuttX RTOS for Ox64 BL808”</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/nuttx-star64"><strong>My Other Project: “NuttX for Star64 JH7110”</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/pinephone-nuttx"><strong>Older Project: “NuttX for PinePhone”</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io"><strong>Check out my articles</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/rss.xml"><strong>RSS Feed</strong></a></p>
|
||
</li>
|
||
</ul>
|
||
<p><em>Got a question, comment or suggestion? Create an Issue or submit a Pull Request here…</em></p>
|
||
<p><a href="https://github.com/lupyuen/lupyuen.github.io/blob/master/src/quickjs.md"><strong>lupyuen.github.io/src/quickjs.md</strong></a></p>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-expect.png" alt="Auto-Test QuickJS with Expect Scripting" /></p>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/qemu.exp"><em>Auto-Test QuickJS with Expect Scripting</em></a></p>
|
||
<h1 id="appendix-build-quickjs-for-nuttx"><a class="doc-anchor" href="#appendix-build-quickjs-for-nuttx">§</a>9 Appendix: Build QuickJS for NuttX</h1>
|
||
<p>Before building QuickJS: Build NuttX for <strong>QEMU or Ox64</strong>…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/quickjs#appendix-build-nuttx-for-qemu"><strong>Build NuttX for QEMU</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/quickjs#appendix-build-nuttx-for-ox64"><strong>Build NuttX for Ox64</strong></a></p>
|
||
</li>
|
||
</ul>
|
||
<p>(Or download the NuttX and QuickJS Binaries from these links)</p>
|
||
<p>Then follow these steps to build <strong>QuickJS for NuttX</strong> (QEMU or Ox64)…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Download and build QuickJS for NuttX
|
||
git clone https://github.com/lupyuen/quickjs-nuttx
|
||
cd quickjs-nutttx/nuttx
|
||
./build.sh</code></pre></div>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/build.sh">(See the <strong>Build Script</strong>)</a></p>
|
||
<p>Remember to…</p>
|
||
<ul>
|
||
<li>
|
||
<p>Set the <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/build.sh#L4-L8"><strong>Toolchain Path</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p>Select <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/build.sh#L8-L14"><strong>QuickJS for NuttX QEMU</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p>Or <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/build.sh#L14-L25"><strong>QuickJS for NuttX Ox64</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p>Do <a href="https://github.com/lupyuen/quickjs-nuttx#switch-ox64-quickjs-to-full-linking"><strong>Full Linking</strong></a> for Smaller Ox64 Binaries</p>
|
||
</li>
|
||
</ul>
|
||
<p><em>How did we figure out the steps to build QuickJS for NuttX?</em></p>
|
||
<p>We ran “<strong><code>make</code> <code>--trace</code></strong>” to observe the <strong>QuickJS Build</strong>: <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/make.log">make.log</a></p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Build QuickJS for Debian x64 and observe the build
|
||
$ make --trace
|
||
|
||
## Build qjs.o
|
||
gcc \
|
||
-g \
|
||
-Wall \
|
||
-MMD \
|
||
-MF .obj/qjs.o.d \
|
||
-Wno-array-bounds \
|
||
-Wno-format-truncation \
|
||
-fwrapv \
|
||
-D_GNU_SOURCE \
|
||
-DCONFIG_VERSION=\"2024-01-13\" \
|
||
-DCONFIG_BIGNUM \
|
||
-O2 \
|
||
-c \
|
||
-o .obj/qjs.o \
|
||
qjs.c
|
||
|
||
## Omitted: Build a bunch of other binaries
|
||
...
|
||
## Link them together
|
||
gcc \
|
||
-g \
|
||
-rdynamic \
|
||
-o qjs \
|
||
.obj/qjs.o \
|
||
.obj/repl.o \
|
||
.obj/quickjs.o \
|
||
.obj/libregexp.o \
|
||
.obj/libunicode.o \
|
||
.obj/cutils.o \
|
||
.obj/quickjs-libc.o \
|
||
.obj/libbf.o \
|
||
.obj/qjscalc.o \
|
||
-lm \
|
||
-ldl \
|
||
-lpthread</code></pre></div>
|
||
<p>And we know that NuttX builds <a href="https://github.com/lupyuen/tcc-riscv32-wasm#how-nuttx-build-links-a-nuttx-app"><strong>NuttX Apps</strong></a> like this…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Build NuttX Apps for QEMU and observe the build
|
||
$ cd ../apps
|
||
$ make --trace import
|
||
|
||
## Compile hello app
|
||
## For riscv-none-elf-gcc: "-march=rv64imafdc_zicsr_zifencei"
|
||
## For riscv64-unknown-elf-gcc: "-march=rv64imafdc"
|
||
riscv-none-elf-gcc \
|
||
-c \
|
||
-fno-common \
|
||
-Wall \
|
||
-Wstrict-prototypes \
|
||
-Wshadow \
|
||
-Wundef \
|
||
-Wno-attributes \
|
||
-Wno-unknown-pragmas \
|
||
-Wno-psabi \
|
||
-fno-common \
|
||
-pipe \
|
||
-Os \
|
||
-fno-strict-aliasing \
|
||
-fomit-frame-pointer \
|
||
-ffunction-sections \
|
||
-fdata-sections \
|
||
-g \
|
||
-mcmodel=medany \
|
||
-march=rv64imafdc_zicsr_zifencei \
|
||
-mabi=lp64d \
|
||
-isystem apps/import/include \
|
||
-isystem apps/import/include \
|
||
-D__NuttX__ \
|
||
-I "apps/include" \
|
||
hello_main.c \
|
||
-o hello_main.c.workspaces.bookworm.apps.examples.hello.o
|
||
|
||
## Link hello app
|
||
## For riscv-none-elf-ld: "rv64imafdc_zicsr/lp64d"
|
||
## For riscv64-unknown-elf-ld: "rv64imafdc/lp64d
|
||
riscv-none-elf-ld \
|
||
--oformat elf64-littleriscv \
|
||
-e _start \
|
||
-Bstatic \
|
||
-Tapps/import/scripts/gnu-elf.ld \
|
||
-Lapps/import/libs \
|
||
-L "xpack-riscv-none-elf-gcc-13.2.0-2/lib/gcc/riscv-none-elf/13.2.0/rv64imafdc_zicsr/lp64d" \
|
||
apps/import/startup/crt0.o \
|
||
hello_main.c.workspaces.bookworm.apps.examples.hello.o \
|
||
--start-group \
|
||
-lmm \
|
||
-lc \
|
||
-lproxies \
|
||
-lgcc apps/libapps.a \
|
||
xpack-riscv-none-elf-gcc-13.2.0-2/lib/gcc/riscv-none-elf/13.2.0/rv64imafdc_zicsr/lp64d/libgcc.a \
|
||
--end-group \
|
||
-o apps/bin/hello</code></pre></div>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/build.sh#L19-L25">(<strong>Ox64 Build</strong> is a little different)</a></p>
|
||
<p>Thus we…</p>
|
||
<ul>
|
||
<li>
|
||
<p>Combine everything above into our <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/build.sh"><strong>QuickJS Build Script</strong></a></p>
|
||
<p>(Later we’ll merge into the NuttX Makefiles)</p>
|
||
</li>
|
||
<li>
|
||
<p>Add an <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/qemu.exp"><strong>Expect Script</strong></a> for auto-testing QuickJS on QEMU</p>
|
||
<p>(Pic above)</p>
|
||
</li>
|
||
</ul>
|
||
<p>Everything builds OK without changing any code in QuickJS! Though we <a href="https://lupyuen.github.io/articles/quickjs#build-quickjs-for-nuttx"><strong>stubbed out some functions</strong></a> because NuttX works a little differently.</p>
|
||
<p><em>repl.c and qjscalc.c are missing?</em></p>
|
||
<p>They’re generated by the <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/make.log#L28-L32"><strong>QuickJS Compiler</strong></a>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Compile the REPL from JavaScript to C
|
||
./qjsc -c -o repl.c -m repl.js
|
||
|
||
## Compile the BigNum Calculator from JavaScript to C
|
||
./qjsc -fbignum -c -o qjscalc.c qjscalc.js</code></pre></div>
|
||
<p>So we <strong>borrow the output</strong> from another QuickJS Build (Debian x64) and add to NuttX…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/repl.c"><strong>nuttx/repl.c</strong></a>: Interactive-Mode REPL for QuickJS</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/qjscalc.c"><strong>nuttx/qjscalc.c</strong></a>: BigNum Calculator for QuickJS</p>
|
||
</li>
|
||
</ul>
|
||
<p><em>What’s inside repl.c and qjscalc.c?</em></p>
|
||
<p>They contain plenty of <a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/repl.c"><strong>JavaScript Bytecode</strong></a> for REPL and BigNum Calculator. Brilliant!</p>
|
||
<div class="example-wrap"><pre class="language-c"><code>/* File generated automatically by the QuickJS compiler. */
|
||
#include <inttypes.h>
|
||
const uint32_t qjsc_repl_size = 16280;
|
||
const uint8_t qjsc_repl[16280] = {
|
||
0x02, 0xa5, 0x03, 0x0e, 0x72, 0x65, 0x70, 0x6c,
|
||
0x2e, 0x6a, 0x73, 0x06, 0x73, 0x74, 0x64, 0x04, ...</code></pre></div>
|
||
<p>That’s why REPL and BigNum will require more Heap Memory, to execute the extra JavaScript Bytecode.</p>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-qemu.png" alt="QuickJS on NuttX QEMU" /></p>
|
||
<p><a href="https://gist.github.com/lupyuen/a3d2a491112eaf5810edc1fa355606db"><em>QuickJS on NuttX QEMU</em></a></p>
|
||
<h1 id="appendix-build-nuttx-for-qemu"><a class="doc-anchor" href="#appendix-build-nuttx-for-qemu">§</a>10 Appendix: Build NuttX for QEMU</h1>
|
||
<p>In this article, we compiled a Work-In-Progress Version of <strong>Apache NuttX RTOS for QEMU RISC-V (64-bit Kernel Mode)</strong> that has these updates…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/commit/1037eda906f11aef44f7670f8cc5a1c1d2141911"><strong>Add the LED Driver</strong></a> for QEMU</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/commit/3b662696aff4b89e2b873a6b75d0006860fc9f7b"><strong>Increase the App Stack Size</strong></a> from 2 KB to 64 KB</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx-apps/commit/45dbe5ce07239e7ca7dcb50cb0e55da151052429"><strong>Patch the <code>leds</code> app</strong></a> for testing LED Driver</p>
|
||
</li>
|
||
</ul>
|
||
<p>We may download the <a href="https://github.com/lupyuen2/wip-nuttx/releases/tag/qemuled-1"><strong>NuttX Binaries for QEMU</strong></a>…</p>
|
||
<ol>
|
||
<li>
|
||
<p>Download the NuttX Kernel: <a href="https://github.com/lupyuen2/wip-nuttx/releases/download/qemuled-1/nuttx"><strong><code>nuttx</code></strong></a></p>
|
||
<p>Copy to <strong><code>$HOME/nuttx/</code></strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Download the NuttX Apps: <a href="https://github.com/lupyuen2/wip-nuttx/releases/download/qemuled-1/apps-bin.zip"><strong><code>apps-bin.zip</code></strong></a></p>
|
||
<p>Unzip and copy the files inside (not the folder) into <strong><code>$HOME/apps/bin/</code></strong></p>
|
||
<p>(We should see <strong><code>$HOME/apps/bin/qjs</code></strong> and <strong><code>blink.js</code></strong>)</p>
|
||
</li>
|
||
<li>
|
||
<p>Then run…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>$ cd $HOME/nuttx/
|
||
$ qemu-system-riscv64 \
|
||
-semihosting \
|
||
-M virt,aclint=on \
|
||
-cpu rv64 \
|
||
-bios none \
|
||
-kernel nuttx \
|
||
-nographic</code></pre></div>
|
||
<p>(Remove <strong><code>-bios none</code></strong> for newer versions of NuttX)</p>
|
||
<p><a href="https://gist.github.com/lupyuen/a3d2a491112eaf5810edc1fa355606db">(See the <strong>NuttX Log</strong>)</a></p>
|
||
</li>
|
||
</ol>
|
||
<p>Or if we prefer to <strong>build NuttX ourselves</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Download the WIP NuttX Source Code
|
||
git clone \
|
||
--branch qemuled \
|
||
https://github.com/lupyuen2/wip-nuttx \
|
||
nuttx
|
||
git clone \
|
||
--branch qemuled \
|
||
https://github.com/lupyuen2/wip-nuttx-apps \
|
||
apps
|
||
|
||
## Configure NuttX for QEMU RISC-V (64-bit Kernel Mode)
|
||
cd nuttx
|
||
tools/configure.sh rv-virt:knsh64
|
||
|
||
## Build NuttX
|
||
make
|
||
|
||
## Dump the disassembly to nuttx.S
|
||
riscv64-unknown-elf-objdump \
|
||
--syms --source --reloc --demangle --line-numbers --wide \
|
||
--debugging \
|
||
nuttx \
|
||
>nuttx.S \
|
||
2>&1
|
||
|
||
## Build the Apps Filesystem
|
||
make -j 8 export
|
||
pushd ../apps
|
||
./tools/mkimport.sh -z -x ../nuttx/nuttx-export-*.tar.gz
|
||
make -j 8 import
|
||
popd</code></pre></div>
|
||
<p><a href="https://lupyuen.github.io/articles/release#build-nuttx-for-star64">(Remember to install the <strong>Build Prerequisites and Toolchain</strong>)</a></p>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/releases/tag/qemuled-1">(See the <strong>Build Script</strong>)</a></p>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/releases/tag/qemuled-1">(See the <strong>Build Outputs</strong>)</a></p>
|
||
<p>This produces the NuttX ELF Image <strong><code>nuttx</code></strong> that we’ll boot on QEMU RISC-V Emulator in a while.</p>
|
||
<p>But first: We build <strong>QuickJS for QEMU</strong>, which will produce <code>qjs</code> and <code>blink.sh</code> in the <code>apps/bin</code> folder…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/quickjs#appendix-build-quickjs-for-nuttx"><strong>“Build QuickJS for NuttX QEMU”</strong></a></li>
|
||
</ul>
|
||
<p>Now we boot <strong><code>nuttx</code></strong> on QEMU RISC-V Emulator…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Start the QEMU RISC-V Emulator (64-bit) with NuttX RTOS
|
||
qemu-system-riscv64 \
|
||
-semihosting \
|
||
-M virt,aclint=on \
|
||
-cpu rv64 \
|
||
-bios none \
|
||
-kernel nuttx \
|
||
-nographic</code></pre></div>
|
||
<p>(Remove <strong><code>-bios none</code></strong> for newer versions of NuttX)</p>
|
||
<p>At the NuttX Prompt, enter…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>qjs --std /system/bin/blink.js</code></pre></div>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/blink.js">(See the <strong>Blinky JavaScript</strong>)</a></p>
|
||
<p>QuickJS runs our Blinky JavaScript and blinks a <strong>Simulated LED</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>## Remove `-bios none` for newer versions of NuttX
|
||
$ qemu-system-riscv64 -semihosting -M virt,aclint=on -cpu rv64 -bios none -kernel nuttx -nographic
|
||
|
||
NuttShell (NSH) NuttX-12.4.0-RC0
|
||
nsh> qjs --std /system/bin/blink.js
|
||
led=0, val=1
|
||
led=0, val=0
|
||
led=0, val=1</code></pre></div>
|
||
<p><a href="https://gist.github.com/lupyuen/a3d2a491112eaf5810edc1fa355606db">(See the <strong>Complete Log</strong>)</a></p>
|
||
<p>To Exit QEMU: Press <strong><code>Ctrl-A</code></strong> then <strong><code>x</code></strong></p>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-title2.png" alt="QuickJS on NuttX Ox64" /></p>
|
||
<p><a href="https://gist.github.com/lupyuen/f879aa3378aa1b0170a1d3ea2b0b9d67"><em>QuickJS on NuttX Ox64</em></a></p>
|
||
<h1 id="appendix-build-nuttx-for-ox64"><a class="doc-anchor" href="#appendix-build-nuttx-for-ox64">§</a>11 Appendix: Build NuttX for Ox64</h1>
|
||
<p>In this article, we compiled a Work-In-Progress Version of <strong>Apache NuttX RTOS for Ox64</strong> that has these updates…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/commit/8f75f3744f3964bd3ed0596421a93e59fb39cdd8"><strong>Add the GPIO Driver</strong></a> for Ox64 BL808</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/commit/4f3996959132ca0d35874b7be3eef89d6bf7f351"><strong>Add the LED Driver</strong></a> for Ox64 BL808</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/commit/904b95534298378d64b99c1f9e649f8bc27a8048"><strong>Increase the App Stack Size</strong></a> from 2 KB to 64 KB</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/commit/28453790d06c0282b85e5df98624f8fa1c0b2226"><strong>Increase the RAM Disk Region</strong></a> from 16 MB to 40 MB</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx-apps/commit/66f1389c8d17eecdc5ef7baa62d13435bd053ee3"><strong>Patch the <code>leds</code> app</strong></a> for testing LED Driver</p>
|
||
</li>
|
||
</ul>
|
||
<p>We may download the <a href="https://github.com/lupyuen2/wip-nuttx/releases/tag/gpio2-1"><strong>NuttX Binaries for Ox64</strong></a>…</p>
|
||
<ol>
|
||
<li>
|
||
<p>Download the NuttX Image: <a href="https://github.com/lupyuen2/wip-nuttx/releases/download/gpio2-1/Image"><strong><code>Image</code></strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p>Prepare a <strong>Linux microSD</strong> for Ox64 as described <a href="https://lupyuen.github.io/articles/ox64"><strong>in the previous article</strong></a>.</p>
|
||
<p><a href="https://lupyuen.github.io/articles/ox64#flash-opensbi-and-u-boot">(Remember to flash <strong>OpenSBI and U-Boot Bootloader</strong>)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Copy the <strong><code>Image</code></strong> file (from above) and overwrite the <strong><code>Image</code></strong> in the Linux microSD…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Overwrite the Linux Image
|
||
## on Ox64 microSD
|
||
cp Image \
|
||
"/Volumes/NO NAME/Image"
|
||
diskutil unmountDisk /dev/disk2</code></pre></div></li>
|
||
<li>
|
||
<p>Insert the <a href="https://lupyuen.github.io/images/ox64-sd.jpg"><strong>microSD into Ox64</strong></a> and power up Ox64.</p>
|
||
</li>
|
||
<li>
|
||
<p>Ox64 boots <a href="https://lupyuen.github.io/articles/sbi"><strong>OpenSBI</strong></a>, which starts <a href="https://lupyuen.github.io/articles/linux#u-boot-bootloader-for-star64"><strong>U-Boot Bootloader</strong></a>, which starts <strong>NuttX Kernel</strong> and the NuttX Shell (NSH).</p>
|
||
</li>
|
||
<li>
|
||
<p>At the NuttX Prompt, enter…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>qjs --std /system/bin/blink.js</code></pre></div>
|
||
<p><a href="https://github.com/lupyuen/quickjs-nuttx/blob/master/nuttx/blink.js">(See the <strong>Blinky JavaScript</strong>)</a></p>
|
||
</li>
|
||
<li>
|
||
<p>QuickJS executes our Blinky JavaScript and blinks our <strong>LED on GPIO 29</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code>NuttShell (NSH) NuttX-12.4.0-RC0
|
||
nsh> qjs --std /system/bin/blink.js
|
||
|
||
bl808_gpiowrite: regaddr=0x20000938, set=0x1000000
|
||
bl808_gpiowrite: regaddr=0x20000938, clear=0x1000000
|
||
bl808_gpiowrite: regaddr=0x20000938, set=0x1000000
|
||
bl808_gpiowrite: regaddr=0x20000938, clear=0x1000000</code></pre></div>
|
||
<p><a href="https://gist.github.com/lupyuen/aeb74f047dc81be08e812458232ef92f#file-nuttx-quickjs-ox64-log-L112-L247">(See the <strong>Complete Log</strong>)</a></p>
|
||
</li>
|
||
</ol>
|
||
<p>Or if we prefer to <strong>build NuttX ourselves</strong>…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Download the WIP NuttX Source Code
|
||
git clone \
|
||
--branch gpio2 \
|
||
https://github.com/lupyuen2/wip-nuttx \
|
||
nuttx
|
||
git clone \
|
||
--branch gpio2 \
|
||
https://github.com/lupyuen2/wip-nuttx-apps \
|
||
apps
|
||
|
||
## Configure NuttX for Ox64 BL808 RISC-V SBC
|
||
cd nuttx
|
||
tools/configure.sh ox64:nsh
|
||
|
||
## Build NuttX
|
||
make
|
||
|
||
## Export the NuttX Kernel
|
||
## to `nuttx.bin`
|
||
riscv64-unknown-elf-objcopy \
|
||
-O binary \
|
||
nuttx \
|
||
nuttx.bin
|
||
|
||
## Dump the disassembly to nuttx.S
|
||
riscv64-unknown-elf-objdump \
|
||
--syms --source --reloc --demangle --line-numbers --wide \
|
||
--debugging \
|
||
nuttx \
|
||
>nuttx.S \
|
||
2>&1
|
||
|
||
## Dump the hello_nim disassembly to hello_nim.S
|
||
riscv64-unknown-elf-objdump \
|
||
--syms --source --reloc --demangle --line-numbers --wide \
|
||
--debugging \
|
||
../apps/bin/hello_nim \
|
||
>hello_nim.S \
|
||
2>&1</code></pre></div>
|
||
<p><a href="https://lupyuen.github.io/articles/release#build-nuttx-for-star64">(Remember to install the <strong>Build Prerequisites and Toolchain</strong>)</a></p>
|
||
<p>We build the <strong>NuttX Apps Filesystem</strong> that contains NuttX Shell and NuttX Apps…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Build the Apps Filesystem
|
||
make -j 8 export
|
||
pushd ../apps
|
||
./tools/mkimport.sh -z -x ../nuttx/nuttx-export-*.tar.gz
|
||
make -j 8 import
|
||
popd</code></pre></div>
|
||
<p>Next we build <strong>QuickJS for Ox64</strong>, which will produce <code>qjs</code> and <code>blink.sh</code> in the <code>apps/bin</code> folder…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/quickjs#appendix-build-quickjs-for-nuttx"><strong>“Build QuickJS for NuttX Ox64”</strong></a></li>
|
||
</ul>
|
||
<p>We bundle QuickJS into the <strong>Initial RAM Disk</strong> and append it to the NuttX Image…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Generate the Initial RAM Disk `initrd`
|
||
## in ROMFS Filesystem Format
|
||
## from the Apps Filesystem `../apps/bin`
|
||
## and label it `NuttXBootVol`
|
||
genromfs \
|
||
-f initrd \
|
||
-d ../apps/bin \
|
||
-V "NuttXBootVol"
|
||
|
||
## Prepare a Padding with 64 KB of zeroes
|
||
head -c 65536 /dev/zero >/tmp/nuttx.pad
|
||
|
||
## Append Padding and Initial RAM Disk to NuttX Kernel
|
||
cat nuttx.bin /tmp/nuttx.pad initrd \
|
||
>Image</code></pre></div>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/releases/tag/gpio2-1">(See the <strong>Build Script</strong>)</a></p>
|
||
<p><a href="https://github.com/lupyuen2/wip-nuttx/releases/tag/gpio2-1">(See the <strong>Build Outputs</strong>)</a></p>
|
||
<p>This produces the NuttX Image for Ox64: <strong><code>Image</code></strong></p>
|
||
<p>Follow the <a href="https://lupyuen.github.io/articles/quickjs#appendix-build-nuttx-for-ox64"><strong>earlier instructions</strong></a> to copy <strong><code>Image</code></strong> to a Linux microSD, boot it on Ox64 and run QuickJS. (Pic below)</p>
|
||
<p><a href="https://youtu.be/jv29M16CFJQ">(Watch the <strong>Demo on YouTube</strong>)</a></p>
|
||
<p><a href="https://gist.github.com/lupyuen/aeb74f047dc81be08e812458232ef92f#file-nuttx-quickjs-ox64-log-L112-L247">(See the <strong>NuttX Log</strong>)</a></p>
|
||
<p><em>What about the NuttX Image for Ox64 Emulator? (Pic above)</em></p>
|
||
<p>The exact same Build Outputs from above, we copied to the <a href="https://github.com/lupyuen/nuttx-tinyemu/tree/main/docs/quickjs"><strong>NuttX Emulator for Ox64</strong></a>.</p>
|
||
<p><img src="https://lupyuen.github.io/images/quickjs-ox64.webp" alt="QuickJS blinks an LED on Ox64 BL808 SBC" /></p>
|
||
<p><a href="https://youtu.be/jv29M16CFJQ"><em>QuickJS blinks an LED on Ox64 BL808 SBC</em></a></p>
|
||
|
||
|
||
<!-- Begin scripts/rustdoc-after.html: Post-HTML for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
|
||
<!-- Begin Theme Picker and Prism Theme -->
|
||
<script src="../theme.js"></script>
|
||
<script src="../prism.js"></script>
|
||
<!-- Theme Picker and Prism Theme -->
|
||
|
||
<!-- End scripts/rustdoc-after.html -->
|
||
|
||
|
||
</body>
|
||
</html> |