EM•Script — EM™ Reimagined
Welcome (back) to EM [ˈɛm ] – a programming environment which targets resource-constrained embedded systems. To flatten its learning curve and drive broader use, we've now reimagined EM within the boundaries of the TypeScript language – leading us to EM•Script.
What and why
1 — Refresh my memory of EM ...
Since its inception in 2010, the focus of the EM Programming Language has remained constant – producing "tiny code for tiny chips" where every byte of memory and μJoule of energy matters when deploying low-cost, low-power embedded systems.
Having supported more than twenty 8/16/32-bit MCUs from a dozen silicon vendors, the EM language promises a higher-level programming paradigm coupled with a higher-level of runtime performance when compared with legacy C/C++ code targeting these MCUs.
As important, just a handful of EM programmers have developed thousands of EM modules re-used across a broad range of high-volume (yet proprietary) IoT applications. In late 2023, The EM Foundation – a 501(c)(3) non-profit – announced an openly available EM-SDK.
2 — So why did you create EM•Script
Promoting the EM SDK through blog posts in early 2024 elicited a mixed bag of reactions – from "cool, good luck" to "sorry, try again" . Despite evidence quantifying EM's performance advantage over C/C++, a new (and unknown !!) language does raise the acceptance bar.
Needless to say, the effort required to support a handful of developers pales in comparison to promoting, sustaining, and evolving an open-source EM language for the broad community of embedded programmers. This realization then led to a radical change of course.
Zig•EM – announced here in 3Q24 – attacked the issue head-on by nominally grafting the novel concepts and constructs of EM onto another programming language.
A hidden gem
First released in early 2016, Zig also offers a "higher-level programming with higher-levels of performance" value proposition when compared with C/C++. Zig regularly earns high-marks when held up against other modern system programming languages like Go and Rust – both already targeting embedded MCUs.
But unlike the competition, Zig offers an inherent simplicity and transparency reminiscent of classic C – the incumbant system programming language which some argue Zig could supplant. At the same time, Zig challenges many entrenched programming practices and demands that we "think differently" from the outset.
Speaking now from personal experience: While not the easiest language to master, the Ziggit forum stands apart for how it welcomes, nutures, and encourages new members of the Zig programming community.
Compared with other system programming languages, however, Zig very much remains a work in progress: a stable 1.0 release still lies years away; and language server support within popular development environments like VS Code remains skeletal.
Some lessons learned from the Zig•EM experience:
● embedding EM within another programming language can afford re-use of the latter's infrastructure
● a language combo need not compromise runtime performance [time, space, power] versus legacy EM
● while code performance remains a top priority, the quality of the coding experience can't lag far behind
... which finally brings us to EM•Script – same approach, different language !!
3 — What makes TypeScript an ideal host
TypeScript – younger than EM, in fact – now claims a perennial spot amongst the five most widely used programming languages.(1) The language also enjoys first-class support within VS Code – an environment written in TypeScript and used by a vast majority of developers.
- see the Stack Overflow Developer Survey
EM•Script does in fact leverage many of the language services and compiler APIs delivered as part of TypeScript. As important, the latter's robust type-system enables us to capture "the essence of EM" without leaving the confines of the TypeScript language.
But maybe the strongest reason for choosing TypeScript comes down to this paradox:
*NOBODY* regards TypeScript as a suitable language for programming resource-constrained MCUs !!
Opportunities abound.... Unlike other modern programming languages that have "branched out" to target embedded MCUs [MicroPython, TinyGo, and others], TypeScript has never had a bridge into the world of low-cost, low-power embedded systems – until now, of course !!
Show and tell
4 — Show me some EM•Script source code
Well, you can't call yourself a programming language if you can't do this:
em.examples.basic/Ex01_HelloP | |
---|---|
And to dispel any doubts, let's view the corresponding .em.ts
source file inside VS Code using our special EM•Script extension – which will flatten your learning curve by using core TypeScript language services such as syntax highlighting, hover help, and intellisense.
For a more realistic and compelling example, consider this "low-level" EM•Script module which implements a bit-banged UART transmitter using a GPIO pin and a hardware counter:
em.utils/SoftUart
code shown here in fact remains 100% portable across any MCU offering these sorts of hardware capabilities.
5 — How does EM•Script optimize target firmware
While sourced as TypeScript, an efficient implementation of the put
function defined at line 23 of em.utils/SoftUart
ultimately requires object code targeting the MCU instruction-set. To that end, EM•Script could simply translate .em.ts
files into corresponding C++ sources.
Bear with us – we've purposely omitted the most critical phase of the EM•Script program build-flow !!
Starting with a "top-level" program source file (eg, Ex01_HelloP.em.ts
), the translator follows its import
chain and generates a main.cpp
program – adding other translated files through #include
directives and implementing the special em$run
function seen here within main
.
Like EM before it, the EM•Script build flow can leverage any compiler suite which supports the C++14 standard. And who knows, maybe EM•Script will someday support other target programming languages as well – including Zig.
With a self-contained main.cpp
as its sole input, the downstream compiler can aggressively apply stock optimization techniques(1) to the whole program – yielding a smaller, more efficient main.out
image. But the real power of EM•Script lies in what happens upstream:
- constant folding, function inlining, dead-code elimination, etc
The EM•Script program build-flow inserts a novel configuration step between initial translation and downstream compilation – enabling a world of application-centric optimizations often missed when building legacy C/C++ programs.
Besides generating C++ code for each .em.ts
source file, EM•Script invokes an extended TypeScript→JavaScript transpiler which yields corresponding .em.js
modules – all combined into a single main.js
program executed at build-time on your host PC.
Our configuration phase in fact serves as a staging area where the whole program comes together for a "dry-run", so to speak. By implementing special functions(1)inside namespace
em$meta
, each module can actively participate in the configuration process at build-time:
em$configure
,em$construct
,em$generate
, etc
● by binding values to EM•Script $config
parameters published by other modules
● by pre-initializing static constants and variables used internally by the module
● by wiring one module to another via the $proxy
– $delegate
design pattern
● by forcibly including / excluding individual modules from downstream compilation
● by generating fragments of specialized C/C++ code which main.cpp
will incorporate
As such, EM•Script serves as its own meta-language used for build-time meta-programming .
With boundless resources on your host PC – and with all of Node.js available to the main.js
meta-program – opportunities abound for individual modules to encapsulate application-centric logic that ultimately shapes program images targeting resource-constrained MCUs.
For those with deep[er] knowledge of TypeScript ...
Embedding the original EM language within the confines of TypeScript can sometimes become a delicate balancing act. To ensure we don't mask critical concepts and constructs which lie at the heart of EM, we'll sometimes must compromise on certain "best practices" embraced by modern TypeScript developers.(1)
- use of
namespace
andvar
, for example
Rest assured, we'll identify and rationalize these "pragmatic exceptions" as we learn more about embedded programming using the EM•Script language. In reality, the majority of targeted EM•Script users – embedded developers coming from C – will have little/no prior experience with TypeScript.
Next steps
6 — Can I start exploring the EM•Script environment
Absolutely – the Setup section of this site will help you get started with our EM•Script SDK. Once you've provisioned a compatible(1)host PC, you can cross-compile target applications using EM•Script – either from the command-line or else within the VS Code environment.
- Windows, Linux, or MacOS
While not required, we strongly encourage you to purchase a low-cost MCU development board currently supported by the SDK. Nothing beats the joy of blinking those LEDs !!
If you'd prefer to just "look around", check out the other sections of this site – which we'll continue to populate going forward. You can also browse the set of target Packages delivered with the latest EM•Script SDK. And for those wanting OSS, endulge yourself at GitHub.
7 — Tell me more about the longer-term roadmap for EM•Script
After a one-year detour – which led us to EM•Script via Zig•EM – we can finally continue down the path originally charted by the EM programming language:
support a broad(er) range of embedded MCUs and document how to create an em$distro
offer lightweight connectivity frameworks built upon standard / proprietary wireless protocols
explore the impact of tenfold code-size reductions on novel MCU architectures based on RISC-V
showcase EM•Script through application development projects sponsored by The EM Foundation
EM•Script – The embedded language for embedded programming
Happy coding !!!