Hacker News new | past | comments | ask | show | jobs | submit login
Gameboy hello world (feeb.dog)
188 points by luu on Oct 14, 2017 | hide | past | web | favorite | 22 comments

I don't know whether OP is the author of this code, but if they are, or if anyone is keen to use it as a template, there's a small but important quirk of the Game Boy hardware this doesn't take into account: when the Game Boy's screen is rendering (i.e. almost all the time), the CPU doesn't have access to VRAM.

In this case, I guess this demo works (if it does, I haven't tested it on my flash cart) because the amount of data transferred to VRAM is small and the timing of things happens to line up so that it all gets sent at the right time, but for anything more complicated you can't rely on that.

There's two ways around this: either turn the screen off before copying your tile and map data over (and you can only safely turn the screen off when it's not rendering, too) or set up a system to blast as much data as possible into VRAM as quickly as possible when a frame is finished drawing.

To test if the screen is off, either spin until bits 0 and 1 of $FF41 == 01 or set up a interrupt handler that'll get fired on vblank.

OP, if you did write this code (or if the author reads this, or if anyone else is interested), feel free to hit me up with any questions. My primary side project is a GB game, and I'd love to talk shop.

(author) thanks so much for the comments. i vaguely knew about this but i serendipitously didn't run into it. how does lack of vram access manifest? do vram writes silently fail?

this is precisely the sort of quirk i wanted to cover in this template so i appreciate hearing about it.

Yeah, writes are ignored, and reads return garbage (no idea what).

I recommend using the BGB emulator - you can configure it to crash into a debugger whenever it detects an invalid VRAM access. Plus the debugger is insanely useful.

and the screen is blanked i suppose. that would allow pritive pwm. has that been used? i would imagine that allows some nice fade effects or enhanced bit-depth in the brightness, as is done eg. on c64.

Adding to what wk_end has said - many emulators (VBA included) will just write to the VRAM without complaining, so you won't even catch the bug unless you try it on a flash cart or in BGB (I'll second that recommendation).

For your demo checking $FF41 should be sufficient, unless you're writing a lot of data you'll usually have enough time in one vblank period. You could wait for $FF41 == 01 and then copy all the data, or check it each iteration of the loop (less efficient but will never fail). I've seen actual games do it both ways (decent amount of disassembly/ROM hacking experience).

Very cool. Something I really love about assembly programming is that there's no black magic between me and the hardware. I can know exactly what every bit of every instruction means by looking at the instruction set documentation, and I can look at the computer architecture documentation to know exactly how to access each device.

Also, the "API"'s you have to learn are incredibly simple compared to learning API's for every framework and protocol in high-level programming. If devices are memory-mapped, than all I'll ever need to know is load and store. I just need to look at the registers that are available for each I/O device, what their addresses are, and what the bits represent in them. From there I access them all the same way: load and store. Couldn't possibly get any easier than just moving things around between registers and memory.

Compare that to high level development like web development, where you need an understanding of HTTP on top of one of infinite different web backends, written in different languages, all using different libraries with different naming conventions and different programming paradigms, plus knowledge of HTML, CSS, possibly another smorgasbord of frameworks, plus knowledge of decent security practices, databases, operations, and the list goes on.

It's obviously apples to oranges though, and I can produce a lot more real-world value doing web development than I can doing assembly programming, at least just as one person. My point is that I really like the simplicity and straightforwardness of writing assembly, at least in the few very short times I've done it. Maybe large assembly projects have all the same challenges as high-level development or worse.

I love low-level, assembly-level programming. The big problem is, we're largely past the era of it.

All but the most simplest embedded systems are complex enough to require some pre-developed library or abstraction layer to stand between a single tinkerer and the hardware. Otherwise it would take you an eternity just to stand up a "Hello World!" The cost of a Linux-capable SoC is low enough that you can buy one for $5 in the form of the Pi Zero. If a system complex enough to run Linux only costs $5 to sell, and probably even less to make, what incentive is there anymore to produce hardware that's simple enough to work with directly at the assembly layer?

The last holdouts are extremely power-efficient embedded systems. And even then you can do those with C.

I'm an old fart who can remember the "good ol' days" just as well, and I still program the SNES as a hobby. But really, that's all it'll ever be anymore; a hobby for legacy systems. There's no reason anymore to even skip C, when architectures have been so fine-tuned for code written with C.

You would be surprised how much it is used still in embedded dev. Picking an embedded board that can, with low level coding, just run your target software is generally far cheaper and power friendly than something more powerful. On millions of devices being produced every cent counts and on wearable devices every hour battery life counts.

For instance, in our case and the case I know best, we could use a full 32 bit ARM arch in our hardware but we do not; we retarget a very simple microcontroller with a few kilobytes of memory for this because it is far cheaper and far less power hungry. Result is that we have to use asm or C with quite a high % of asm. We decided to use only asm because it makes the audits easier too. Because of this work I got to meet many manufacturers and these components are in a lot of appliances and are often coded in asm.

I don't fully agree that we're "past" it.

It's definitely out of fashion, but when something complicated breaks, where is the "adult" you call to figure it out? :)

I do 100% agree that commercial systems / enterprise / game dev is past the low level era, but the knowledge of the area is anything but obsolete for the reason I mentioned before.

I like learning about these legacy systems precisely because we are past them. They are no longer being extended. What I learn about e.g. 6502 today will be 100% applicable 10 years from now. I don't have that confidence with modern systems.

That is what I like about it too. The systems I have in my mancave and program for fun on, are from the early 80s. They are known inside and out (literally), they all still work and in 10 years they will be exactly the same.

my intent in working on this project was (for my personal education) to start engaging with computers involving the fewest layers of abstraction possible, and the gameboy seemed like a fun way to do that.

my hope was to try to stand these up on systems that i actually use on a day-to-day basis, so it's kinda disheartening that that may be overly ambitious, but i'll write about it if i have any success :)

There absolutely is still black magic between you and the hardware and thinking otherwise can lead to trouble. Yes you can read the architecture documentation but when you get into the realm of how the branch prediction tables work, register allocation schemes, operation reordering etc, what the hardware does will be "special" while (usually) not violating what the architecture specifies. Don't even get me started with load/store semantics for multithreaded architectures (although this is standardizing more with the more recent ARM)

Sure, but the Game Boy’s pseudo‐Z80 has no branch prediction, register allocation, or instruction reordering. The assembly is almost one‐to‐one to the machine code, and the CPU basically does everything in the straightforward way you’d expect.

Even on the Gameboy things aren't quite as simple and self evident as all that, for example from another thread on this post: when the Game Boy's screen is rendering (i.e. almost all the time), the CPU doesn't have access to VRAM. [...] writes are ignored, and reads return garbage.

So one of those platonic store instructions might actually be a no-op; you can't tell by looking at it in isolation.

I was replying directly to a response which generalizes the subject of the original post.

I was hoping someone would say something along these lines. My only experience with assembly has been on very simple educational platforms: nios ii on an Altera DE0 FPGA and a MIPS subset on a custom architecture made in class. I've seen photos of the huge x86 reference manual and can see how "real-life" systems would be way more complex than the simple world of assembly I've tried myself.

My brother wrote an alternate Gameboy BIOS for his emulator, including the Nintendo logo animation:


(The emulator itself started as a fork of Gameyob, but he ended up rewriting it entirely, piece by piece.)

Very cool! Eventually I will pick up an Arduboy(1) or a pocketchip(2) with pico8. The games BMO is loaded with are a great source of inspiration: http://adventuretime.wikia.com/wiki/Super_Good_Boys

1) https://arduboy.com/

2) https://getchip.com/

I gave a Game Boy programming workshop at SHA2017 if anyone is interested. The material can be found on my blog: http://pepijndevos.nl/2017/08/06/introduction-to-game-boy-ha...

Really nice tutorial, thanks !

Aladdin source code article[0] was really nice, I wonder if we have anyone here who was involved in game development for gameboy at its time, who can share a similar article.

[0] - https://news.ycombinator.com/item?id=15458200

A nice simple template like this with explanations of platform quirks and caveats is extremely useful. Well done.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact