Porting Arduboy Games to the WASM-4

I was just thinking one could perhaps pretty easily port the Arduboy2 library to something like WASM-4… (either straight, or as a slight patch of the project for resolution, etc)… so someone just drops in their Arduboy source, recompiles, and then you have a modern web or native runtime for your game (no slow emulation, etc)…

And if someone then wanted to expand the game further (4 colors, more RAM, larger screen) that would also be a choice.

Since C/C++ is already one of the supported targets you could get started pretty fast with just a Arduboy2 lib that ripped out the hardware pieces and replaced them with a little glue for the buttons/VRAM.

Anyone interesting in this?

1 Like

I made a really rough pass at the idea, but Mystic Balloons is 95% working. A few notes:

  • Integer overflow in C++ is undefined (and AVR != WASM), so that led to some weird behavior with buffer offsets in sprite rendering that took a hot minute to track down.
  • I had to swap out the Arduboy frame stuff for update at 60FPS (so this might not work for all games, esp if they need a variable refresh rate)
  • Lots of hacks to the library to strip/comment out all the Arduino hardware bits
  • After that I only had to touch Arduboy::display and Arduboy2Core::buttonsState() to wire in the WASM4 “hardware”… I just paint the screen in monochrome in the middle of the 160x160 that Wasm4 has to offer.
  • I just stubbed out EEPROM, but you’d really want to wire it to the 1024 bytes of “hard disk” space that WASM gives you.
  • Tight loops that wait on input wouldn’t be supported, but thankfully Balloons seems to have none of those.
  • All the assembly stuff has to be replaced with raw C code… so that would mean reimplementing the C version of Image+Mask used by so many games.

For the curious, the WASM-4 cartridge is 27kb (of their 64kb limit).


fantastic work done! you can use the ESPboy fork of the Arduboy2 library where all asm code has been replaced by C code

Great idea… that might be easier than going back thru years of history to find the original code. :slight_smile:

Great work!

Ouch … I know a few people (including myself) rely on overflow and underflow. I know its not good practice but on a small device like the Arduboy it can shave off bytes of code.

Personally I have made a game that slowly increases the frame rate to increase the speed of the game. Are you saying that you can specify any frame rate (60 was just an example) but not change it at runtime?

Fixing the bugs wouldn’t increase space used… It should be possible to have source that would compile on either Arduboy or WASM-4 just based on a few compiler defines with 99% the exact same source.

The problem is that C “upgrades” ints when it can… on Arduino you don’t notice because there is nothing to upgrade to, it’s 8-bit… upgrading would waste tons of space… so they are truncated to the exact byte size… but on WASM you get 32-bit ints by default so something like:

uint16_close_to_overflow + 256

…will NOT overflow… it’ll just go right past the int16 boundary so you have to instead write:

uint16_t(int16_close_to_overflow + 256)

Typecasting it back to 16-bits, so the compiler knows it needs to clamp it. This behavior is simply implied on the Arduboy hardware so you get it for free.

Are you saying that you can specify any frame rate (60 was just an example)

You’re hard-wired to 60 with WASM-4. And on the web there are also reasons 60 is best since that’s what the animation frame built in stuff is designed for. Native I imagine if you hacked the source you’d have more choices, but out of the box everything must run at 60. So effects like speeding up to slowing down back on frame rate are impossible.

Right, of course.

Oh … that’s interesting. I guess for those games that run at 45 or 30 fps, you could waste a frame or every third one to achieve the result.

Only signed integer overflow though, and only until C++20.

Though if you’re talking about the bug I think you’re talking about, it’s probably due to Arduboy using a 16-bit int and the target platform using a 32-bit int, which isn’t actually to do with how integer overflow being undefined because it happens even when both systems are using two’s complement.

Though this bug was fixed in more recent versions of Arduboy2.

Would SpritesB not suffice?

Also of course on WASM-4 you have none of the OLED hardware features… though quite a few of them could be trivially emulated with software (like invert, brightness, etc)… I was just playing around here. Not sure how useful this is for anyone. :slight_smile:

Only signed integer overflow though, and only until C++20.

These were signed integers, but thanks for the clarification. :slight_smile: Glad to see they’re going to fix that.

it’s probably due to Arduboy using a 16-bit int and the target platform using a 32-bit int

Well I’m using the correct int16_t type, (which works properly if you typecast the result)… I was told it has to do with C++ policy on upgrading integers… so I’m confused between that an undefined. :slight_smile: It’s something for sure. :slight_smile: Could be it’s well defined and just super annoying.

Would SpritesB not suffice?

Ha, possibly!!! Forgot about that.

1 Like

I make a point of mentioning ‘signed’ integers simply because the same doesn’t apply to unsigned arithmetic - unsigned arithmetic is always performed modulo a power of two, so it’s well defined.

C++20 was introduced last year, so for C++20 compliant compilers it’s already ‘fixed’. (The number isn’t a version number, it’s the last two digits of the year date, hence C++98, C++03, C++11, C++14, C++17, C++20.)

Yes, arithmetic is always performed on int or larger, so anything smaller than int is promoted. (The full set of rules can be found here.)

If you’re talking about the bug I think you’re talking about - that particular line in Sprites which has since been fixed - then the problem is nothing to do with overflow being undefined.

Signed arithmetic overflow being undefined means that ‘legally’ speaking ‘anything’ can happen when two signed integers are added together and the result would be larger than the type can handle. (I think the only reason it’s ‘undefined’ is because C used it to support one’s complement arithmetic, and then C++ copied that rule, but I’m not certain.)

In practice what actually happens is that the compiler uses two’s complement and thus overflow behaves as in two’s complement overflow. But that’s not what causes the issue in Sprites.

The issue in the case of the code in Sprites is that when the arithmetic is done with 32-bit arithmetic there’s extra bits worth of information that causes the pointer to vastly overshoot its destination (i.e. a buffer overflow bug).

It went unnoticed for so long because those extra bits are discarded when using 16-bit arithmetic. The solution is, as you’ve discovered, to either cast to a 16-bit integer or to mask away the excess bits.

You wouldn’t be the first, and you probably won’t be the last.

(There’s a good reason I know so much about this particular bug.)

Ah yes, a different architecture would be likely to hit things like that. :slight_smile:

1 Like

const size_t index = static_cast<uint16_t>(ofs + WIDTH);

Indeed, I was using my older fork… didn’t think it would matter that much for testing purposes, how very mistaken I was. :slight_smile:

1 Like

Now I just need a cool name for the library “Abw4lib” sounds pretty dull…

Is there any sub-forum here for posts of ports?

I wish I had some more control over the “by Josh Goebel” in the link… I’m not trying to misrepresent anything… perhaps itch.io isn’t the best place to do this long term? If anyone wants to test… or if anyone is interested in porting their own games… reach out… I think I almost have things in a clean enough place to share the library.

1 Like

Not sure what the terms are for itch.io if they have any rules over posting others games or not. This is pretty cool!

Just change the title to ‘Mystic Balloons - TEAM a.r.g. ported’ … and it will append your name to become ‘Mystic Balloons - TEAM a.r.g. ported by Josh Goebel’

1 Like

Looks pretty awesome recompiled for 160x80 as well. :wink: (same aspect ratio)