# The game itself (boring)

I made a sorta-proof-of-concept game for the original Game Boy in Nim (with the 
help of GBDK/SDCC as the compiler), with custom assembly bootstrapping and 
minimal dependency on GBDK libraries.

<https://github.com/ZoomTen/pocket-clicker>

Basically, it's a very simple (and very boring) Cookie Clicker clone; nothing 
much at the moment.

## …but why?

I've been using Nim for a few months now and I've really enjoyed it. 
Personally, Nim's highlight for me is how I can make applications and scripts 
that are performant yet easy to read and write.

It advertises itself mainly as a "systems programming language" (though IMO it 
doesn't necessarily _need_ to be), and that much is proven with projects to 
program [Arduino](https://github.com/dinau/nimOnAVR), 
[ESP32](https://github.com/elcritch/nesper) devices, and even the existence of 
@exelotl's [Natu](https://github.com/exelotl/natu) toolkit for creating Game 
Boy Advance games along with [successful 
projects](https://www.goodboygalaxy.com/) made with it.

The latter of which made me think if it was even possible to do with the 
original Game Boy—that would be really funny, I thought. The mere existence of 
a C compiler for Game Boy proved to be enough to try.

This is actually my second attempt at doing such a thing—my first used a lot of 
bindings to GBDK and remained careful not to use things that require managed 
memory like Nim strings and seqs: <https://github.com/ZoomTen/nim-gb-test>

## but how?

I started out this project trying to compile some standard Nim (that is, your 
basic Hello World) with SDCC to see what kind of stuff I needed to work around, 
using things like `-d:danger`, `-d:useMalloc`, and `--checks:off`. In lieu of 
the Makefile I previously used, I decided to use Nim's tasks instead.

Seeing how `os:any` seems to be recommended over `os:standalone`, I tried 
adding that. Unfortunately, I quickly realized that there's still a major 
difference between `os:any` and `os:standalone` at the moment, namely the 
former assumes in its `system` module that a standardized output device even 
exists for the architecture (FILE*, stderr, stdout). I _could_ spoof the 
incompatible calls out in my custom `nimbase.h`, but C macro substitution could 
only do so much, and I eventually hit a roadblock (specifically, I couldn't 
patch out `nimDestroyAndDispose` yet). So I switched back to the tried and 
tested `os:standalone`.

With a few calls to `fwrite` and such spoofed out to 0, [it 
compiled](https://gist.githubusercontent.com/ZoomTen/d34915d1664763f9ff2dbafdd02c0345/raw/ec05bfd7e47eb5da1e984662cb66f39b2457fbce/gbnimtest2.zip).
 Overriding `echo` with a call to GBDK's `printf` (and of course converting the 
Nim string to a `cstring`) made it display the text. But what was more 
surprising though, was the fact that _even_ seqs, objects, and `repr`-ing them 
[worked 
too](https://gist.githubusercontent.com/ZoomTen/d34915d1664763f9ff2dbafdd02c0345/raw/ec05bfd7e47eb5da1e984662cb66f39b2457fbce/image.png).

That discovery motivated me to go further with the idea. Here I faced another 
problem of not being able to specify the C compiler invocation template. To get 
around it, I had to use NimScript. Since I couldn't exactly use the `.exe` and 
`.options.always` parameters to use the current Nim binary with the correct 
arguments, the NimScript needed to be executed directly as if it was a standard 
shell script (which is the point, isn't it?)

There were some more problems I encountered that I eventually worked around, 
such as SDCC crashing with "unbalanced stack" errors with certain parts of 
Nim's C codegen, and the `.uint8` / `'u8` litter needed for _performant_ ASM 
codegen and type satisfaction.

The end result of all that, however, is a program written (mostly) in Nim, its 
compilation controlled with Nim, and I gained a level of control over the 
output slightly higher than what stock GBDK would grant me (thanks to being 
able to compile my ASM code in the same build process).

* * *

Ultimately I think this endeavor proved to me even more that Nim really _can_ 
be described as a "systems language", even if some elbow grease is needed to 
make it work on exotic architectures. Standing on the shoulders of giants 
turned out to be a very good idea :)

Reply via email to