Free42 Web

created July 8th, 2025 • 4m reading time • 5 views

After getting my DM42 a few years ago, I wanted a RPN calculator to use on my computer and found that Free42, the same software used by the DM42, is also available as a desktop application. It worked really well for everything I needed to do, but whenever I didn’t have access to my computer, like when in school (personal devices were banned) or if I was using somebody else’s computer, I really missed having access to a quality RPN calculator.

I thought it would be cool if Free42 could be ported to run on a website, but just never got around to trying to make it. Until now, go ahead try it (hopefully it loaded). The full version also has support for save states, loading and exporting programs, and changing settings.

How it Works

The Free42 project is split into two components, the core library that handles simulating the actual HP42S, and the shells which provide a graphical front end to the core library for different platforms (GTK, Windows, MacOS, iPhone, and Android).

My plan was to compile the core library to Web Assembly and write a new front end with web technologies (HTML / Javascript). Web Assembly (WASM) is a instruction language that can be executed with near-native performance in web applications, and using the Emscripten compiler toolchain, the C code of the core library can be compiled to WASM.

The Glue

Due to how the core library was written it made more sense to write a small layer above it to make the interface between the Javascript and C++ simpler. Once the WASM library is loaded, it is supplied with a list of callbacks for many of the events the core library calls, like for refreshing the screen or playing a tone.

For example the core library calls shell_blitter to refresh the screen. Here my interface library repackages the pixel bitset as a Javascript Uint8Array and passes it to the blit callback function.

void shell_blitter(const char *bits, int bytes_per_line, int x, int y,
                   int width, int height) {
  auto total_bytes = height * bytes_per_line;

  auto view = typed_memory_view(total_bytes, (const uint8_t *)bits);
  auto data = val::global("Uint8Array").new_(view);

  callbacks.call<void>("blit", data);
}

The interface library also exposes function to be called from Javascript, like exporting a program. The core library only lets you export programs to a file, but by patching the core library I was able to make the export_hp42s public. Using libc’s fmemopen function, I was able to pass the file descriptor of a memory buffer to the serialization routine.

Technically the core does support writing to a memory buffer without accessing the private function, but for that you would need to enable the IPHONE feature flag. Probably should have just done that, but whatever…

val export_program() {
  if (current_prgm == -1)
    return val::undefined();

  auto size = core_program_size(current_prgm) + 3;
  auto buffer = malloc(size);

  gfile = fmemopen(buffer, size, "wb");
  if (gfile == nullptr)
    return val::undefined();

  export_hp42s(current_prgm);
  fclose(gfile);

  auto view = typed_memory_view(size, (uint8_t *)buffer);
  return val::global("Uint8Array").new_(view);
}

Compiling for the Web

As someone who very rarely works with C++ code, every time I do, its a bit of a battle with the build system. By copying from one of the existing Makefiles, I was able to get my interface library compiling with clang, but although the emscripten compiler (emcc) is supposed to be a drop in replacement for clang, I had some issues building the project due the its dependency on the Intel® Decimal Floating-Point Math Library. It took me way to long to figure this out, but by patching its build script to pretend that emcc is the same as gcc, it worked.

--- a/IntelRDFPMathLib20U1/LIBRARY/makefile.iml_head
+++ b/IntelRDFPMathLib20U1/LIBRARY/makefile.iml_head
@@ -519,6 +519,9 @@
     else
         __TMP   := $(strip $(subst /, ,$(firstword $(CC))))
         CC_NAME := $(word $(words $(__TMP)), $(__TMP))
+        ifeq ($(CC_NAME),emcc)
+            CC_NAME := gcc
+        endif
     endif
 endif

The Front End

Screenshot of the web interface

For the front end, I opted to keep things simple, using minimal CSS or custom styling. I was originally just using plain Javascript, but I wanted to get nice tab completion with all the classes I was making, so I switched to Typescript. But I didn’t really want to handle keeping the internal state in sync with the UI manually, so I then switched to Svelte.

Svelte was an improvement over plain TS, but getting everything connected still ended up being pretty messy. For example the state select box needs to show an entry for every state, but the states are stored in the browser’s IndexedDB through Emscripten’s IDBFS virtual filesystem. This is because Free42 naively only supports loading states from the filesystem. So in order for the following reactive component to work, states needs to be a globally defined store that gets refreshed from the virtual filesystem whenever anything changes.

<select multiple bind:value={selected}>
    {#each $states as state}
        <option value={state}>{state}</option>
    {/each}
</select>

Future Plans

This project already took a little longer than expected, so I decided not implement the full planed functionality since I don’t personally use the printer, alternative skins, or care that much about memory leaks (I think I would have to put free calls in the Javascript?). But I might get around to adding those features in the future, depending on if I actually end up using this.