Hacker News new | past | comments | ask | show | jobs | submit login
RBoy: A Gameboy Emulator in Rust (github.com/mvdnes)
147 points by NiklasBegley on Sept 24, 2021 | hide | past | favorite | 57 comments



See also https://github.com/Gekkio/mooneye-gb which is more famous for its exhaustive test suite than its emulation accuracy.


Oh that's a really cool approach. I'm not much into the world of emulators - people probably have done this a bunch before, but I guess I've never thought about it - nice to see it presented here so systematically!


Even just collecting that set of devices shows commitment.


I had a quick look at the big match expressions, and this does not look like this project has been through cargo fmt (it would add +2000 lines of code for the whole project). Which is probably a good choice, but as someone who's been looking at this, I wonder if the tradeoffs made in rustfmt are the right ones (note: I have no idea how I would make this better for the general case).


For those looking to see an example of the match expressions:

https://github.com/mvdnes/rboy/blob/9f6b3bc47311ba687326bfff...

This process of matching on opcode and doing a marginally different version of the same basic few operations on one of a set of registers is something that is _much_ easier to do when you're able to see all the opcodes and activities in a densely packed set of lines like this.

(The start of the opcodes that I linked are not the best example of this, but they get more regular the further down the file you go. See https://github.com/mvdnes/rboy/blob/9f6b3bc47311ba687326bfff... )

Beyond knowing that they exist, I haven't explored macros in rust, but I'm curious if they could be of help here. But using cargo fmt, and spreading each of those lines into 3-10 lines would be awful, and would definitely lead to me making mistakes and not noticing typos.


I can't say much about the use of macros, however there are some SM83-specific patterns you can take advantage of if you decode instructions using octals like what I do in my own gameboy emulator here [1]

[1] https://git.musuka.dev/paoda/gb/src/branch/main/src/instruct...


Rust has two flavours of macro. Declarative or "by example" macros, and Procedural ("proc" for short) macros.

Declarative macros might be useful here, at least to cut down on the mindless repetition somewhat. These are fairly hygienic (a technical term meaning that if variable names in the macro are the same as variable names in the code using the macro, this doesn't make them the same variable) and so pretty safe to use but limited.

Procedural macros can do almost anything, they're Rust code that runs inside the compiler when your program is compiled, so e.g. they can have arbitrarily complicated behaviour including completely breaking compilation. You could definitely fix this with proc macros, but, that's not necessarily a good idea.


I can’t speak for the author, but personally I hate tools like go fmt, es-prettify and cargo fmt. I’d never use this stuff by choice because they delete the work I do to make my code easier for me to read. For example, I use extra blank lines to separate different parts of a function, or separate groups of functions visually. These sort of tools like to delete vertical white space, which hurts readability. In javascript I’ve seen plenty of very readable ternary operators (possible with the correct layout) replaced with unreadable junk by the prettifier.

It’s soulless to make all code look like bland corporate cardboard. It appeals to our OCD perfectionist tendencies but in my experience provides very little real value. Software is like writing. It can’t help but express how the author thinks about their code. These tools try to iron that personality out - and for what reason? Who cares in javascript if some files use semicolons and some don’t? Who cares if my where clause is on the same line or the next? The compiler doesn’t care, and neither do I.

(I will grant that all files in a project should have consistent white space, but you don’t need cargo fmt for that.)


> Software is like writing. It can’t help but express how the author thinks about their code. These tools try to iron that personality out - and for what reason?

A single-author novel can have personality. A 100-author 30-volume encyclopedia, less so. Whenever I set up a new single-author codebase, I set up as little automatic code formatting as I please. For collaborating with other developers, I will enforce as much as possible as early as possible.


I enforce formatters wherever possible after working on codebases with 20+ years of people imposing their own unique opinion on where spaces and braces should go. Worse, arguing about what the spacing should be, and making noisy diffs because people change previous peoples styling.

The formatter has no opinion. It follows rules. It doesn't work perfectly everywhere. It works enough. I would argue caring about exact bespoke spacing of all code is the perfectionism you mention.


There is no reason why each of us can't have the formatted according to one's taste (=what works best), instead of this "communism". It's just a matter of IDE support that is lacking.

The IDE should apply user formatting preferences upon reading in the file, and apply the std formatting while writing it (with the aim of having diffs work well). That would make good use of auto-formatters.


Okay, but the IDE support is lacking so that workaround isn't available. If you want that functionality instead you'll have to (1) add it to your IDE (2) force your team to use your favourite IDE instead of their favourite IDE. Insisting on some alternate reality where you have different tools than you actually have isn't helpful


> communism

It's in precisely zero ways like communism and that really doesn't help the clarity of the rest of your post.


This is bad idea, so you want your code to not looks like what's in the repo?


I think it's bad without the rest of the supporting toolchain but it's not axiomatically bad. There are languages with structured editors (e.g. https://hazel.org/), people can use different tabstop settings and even just different editor colours and wrapping settings and I think we can agree that doesn't doesn't hurt anything. Enforcing an automatic formatter is more or less identical to this anyway: you can write your code using whatever style you want but what ends up in the repo is equivalent to the compiler but not identical to what you wrote. You can imagine running your own local formatter on the code before you edit it and running the global formatter afterwards and an observer being unable to tell that that's happened.


Who said that?


> for what reason?

Perhaps you do not remember reading through 10k lines of PHP source that has been formatted by someone who has entirely different ideas about what good formatting is than almost everyone else on earth (or perhaps you never have!), but if you did remember the advantage of a single formatting standard that is ubiquitous would be very clear.


while i agree with you on some parts (ternary operators for example), i love the autoformatters for two reasons:

1. it makes it just plain easier to read others code. it's hard enough to have to grasp the logic behind everything, if they have wildly different formatting on top of that it gets substantially worse (incidentally, this was given as one of the reasons why go was such a success in the open source world).

2. i've been able to get a couple of archaic linter rules dropped, i.e. the brackets around single statement conditionals.

    // for this reason brackets were mandatory
    if (a == b)
        doSomething();
        doSomethingElse();
now with an auto formatters indentation fixes, this mistake becomes instantly obvious and thus a non-issue.


Disappointed by the downvotes here. While formatters help in most instances, sometimes you should break convention for the sake of emphasis or readability. Anyone here can come up with a good example for themselves. Consistency is the hobgoblin of little minds. Patterns and rules help but no rule should be absolute, judging people's quality of code is like judging people for their dress or their vocabulary. While they are important they are certainly not sufficient for a judge of one's character.


Exactly, that's why e.g. C++ projects have some personality feel while Java codebases feel like all the same corporate bland. Go is meant to be Java replacement in corps, so...


rustfmt does not delete vertical whitespace in that way.


I think the core issue here is mainly that a giant match isn't the best way to express opcode tables, and jump tables are just a bit more idiomatic here as in other languages. I've also been working on an emulator for the gameboy in Rust (https://github.com/jawline/Mimic, I wanted to be able to draw gameboy games to the command line) and I think the use of a jump table made it a bunch simpler / easier to refactor (https://github.com/jawline/Mimic/blob/9463b658ebf006b2369d2b...).


You need formatters with options so you set the options to fit your preferences and then when new people come in to the project you just say 'The formatter has no opinions, it just formats'


Rust really shines on this kind of job. Code is clean, simple and modulated.

Where do I find games to test this out?



I'm working on one too! Just got to the milestone of being able to scroll the Nintendo® logo. I refer to rboy a lot, it's been helpful to see another implementation.

https://github.com/percentcer/cerboy


A rust port for the gameboy, that would have been impressive...


There's some ongoing work on a LLVM whole-program backend for the MOS 6502, which can already compile some Rust code (discussed https://news.ycombinator.com/item?id=28581812 ). If that's successful (it does require lots of new optimization passes to match the effectiveness of hand-written code), it would be quite easy to have a backend for the Z80 as well.


A Z80 backend could probably reuse our static stack allocation, but that's about it. It's definitely useful, but the time-consuming part of writing LLVM-MOS's code generator has ended up being... writing LLVM-MOS's code generator. The static stack stuff is maybe like 250 lines of code, and I haven't had to touch it in months.


There is a rust port for the game boy advance https://github.com/rust-console/gba


there's only a barely working, undocumented backend for LLVM on the z80.

You could probably do this with mrustc.


You could, but given that even C and Pascal hardly take advantage of Z80, and have to be used as some kind of fancy macro Assembler, better just deal with Z80 Assembly directly.

But then I am biased, having the Z80 opcodes burned in my brain due to the Speccy days.


I believe it also tosses everything on the stack which is certainly not optimal for the z80


The Game Boy doesn't use a Z80 though. It's based on a SM83 core, an obscure Sharp design.


It's essentially a stripped Z80 without the DD-, ED- and FD-prefix instruction ranges. The core instruction block and CB-prefix range is (nearly) the same.


See the other responses, but my comment was really suggesting that if LLVM barely supports Z80 then the GameBoy CPU is a hopeless lost cause.


True, but the instruction set is very close, so a Z80 implementation is a good starting point.


[flagged]


A couple of years ago every new Go project was being reported here; before that every new Elixir project was being reported; I don’t know if HN was around in the mid-2000’s but I’m pretty sure if it was, it would be full of every new Ruby on Rails project… these phases have been coming and going for as many years as I’ve been signed up here at least ¯\_(ツ)_/¯


HN was around in the late 2000s, which was enough to catch the latter part of the Rails craze, and yes there were a number of posts regularly on X in Rails/RailsClone, Rails vs Sinatra, Rails vs Merb, etc etc


Yep, and everyone still uses all the stoftware written in C/++, and the stuff written in ruby/(and soon go/rust/...) doesn't even run anymore.


Plenty of people still use Ruby, there's a ruby project on the HN front page right now [1]. It just isn't mentioned anymore. The world pretty much runs on C, Java and C# but you won't hear about either, because what's normal isn't exciting. HN isn't a reflection of normalcy, it's a reflection of the unusual and the cutting edge.

1: https://news.ycombinator.com/item?id=28634831


Getting old, forgotten C/C++ code running can be a job. It's really a matter of how well written the make files were and if one still has the original tool chain sitting around. C/++ code written for a paid, closed-source compiler can require a lot of changes to get running under something like GCC.

Not sure how Ruby's backwards compatibility is, since I don't use it, but I have to imagine it's like most other scripting languages in that getting the correct major version is all you need.


I'm not talking about old, forgotten code.

I'm saying that, every time, there is a "${old-existing-thing} in ${current-language-of-the-day}", people upvote it, start it on github, and continue using the old one, written in c/c++.

A few months will go buy, and people will continue using mgba/visualboy/vbam or whatever was popular before.


Before that -- every Java. and before that, every PHP.

What was before PHP? Perl?


I'd put Java's initial trendy period as before PHP's, Java was more concurrent with Perl for that kind of interest. PHP had a fair amount of reacting to the verbosity and tedium of early Java/C++9x static typing in the community


Does every new rust project really get reported here, or do you just only feel the need to post about your annoyance when the projects posted here happen to be written in rust?


It's not even a "new" project. If the multiple "6-8 years ago" files in the root of the repo didn't give it away, a tiny bit of clicking will reveal the first code commit was in 2014. Not only did the project start before Rust 1.0, it started before cargo.


I wouldn't know, I hardly ever see such posts about other languages. Weird, isn't it, that only rust gets that treatment?


Even just the specific example of Gameboy emulators regularly has examples on the front page, regardless of language. (E.g. in the past year some in c++, going back there's ones in JS/Typescript, ...)


As of writing this the font page has the following:

* Slacktyping: I'm typing when you're typing (2018)

* The world's worst Linux kernel module

* Show HN: Go playground powered by WASM that runs in the browser

* Elk: A low footprint JavaScript engine for embedded systems


..and none of them mention "written in XXX", do they? They're just interesting projects. The reason for posting is not "...they're in rust", the language is just an implementation detail.

We can reasonably assume the Go one is written in Go, but the point here is the playground, not the fact that somebody did something in Go.

The slacktyping and kernel module don't mention language at all, they're about some typing... thing and an example of how not to write a kernel module.

The javascript one obviously implements javascript, but there's no mention what language it is implemented in.

Do you see the difference here? These are all about interesting _projects_, not about some implementation detail, being that it is written in language XXX.


> We can reasonably assume the Go one is written in Go

It is in fact written in TypeScript and Rust!


Amusingly enough, the said “Go playground” is actually written in Rust under the hood.


People post all kinds of stuff on HN. So i guess your question is, why does it get upvoted/commented on so much - because a lot of people like it.


Keep in mind there's no downvote button for posts. I suspect it would be a completely different story if there was.


Yes they are, or better said, they were when they had the spotlight and the stage.

Now Rust has the spotlight and the stage.

In one, two years time, that will be Zig, Nim, ..., or some strage one that finally gets an ergonomic way to do dependent types for mainstream developers.


agree tho, always run of the mill hobby project or well established old thing posted because they use rust. big woop, its the only language that gets this tier of fetishism




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: