Emulator development in Java
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 542 | |
Author | ||
License | CC Attribution 2.0 Belgium: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor. | |
Identifiers | 10.5446/61419 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
00:00
Game theoryEmulatorComputerSoftware testingArchitectureHand fanHacker (term)Read-only memoryBuildingComputer fileProgrammable read-only memoryServer (computing)BefehlsprozessorExecution unitPixelProcess (computing)Address spaceInformationLogicFlagPointer (computer programming)StrutEmulatorGroup actionRevision controlHypermediaData miningState of matterMereologyCalculationInformationGame theoryPhysical systemSoftware developerComputer architectureValue-added networkSemiconductor memoryField (computer science)Multiplication signArmData structurePoint (geometry)Web browserCoefficient of determinationInterrupt <Informatik>Traffic reportingFamilyClosed setForestPointer (computer programming)Process (computing)Similarity (geometry)CoprocessorNormal (geometry)WebsiteConstructor (object-oriented programming)BlogReal numberCASE <Informatik>Execution unitSheaf (mathematics)Musical ensembleSoftware engineering1 (number)Graph coloringComputer virusHand fanSoftwarePixelAddress spaceFlagNumberResultantNintendo Co. Ltd.Web 2.0Web applicationSubsetVirtual memoryBefehlsprozessorGreatest elementBuildingComputer programmingStatisticsData managementPrototypeFreewareSingle-precision floating-point formatComputer animation
07:37
Read-only memoryReading (process)Operations researchLogicConditional probabilityBranch (computer science)Total S.A.ArchitecturePixelGame theoryExecution unitProcess (computing)BefehlsprozessorOpcodeEmbedded systemEuclidean vectorWindowStatisticsPosition operatorCartesian coordinate systemAttribute grammarTable (information)Electric currentConfiguration spaceElectronic visual displayConvex hullEmulatorSynchronizationSource codeLoop (music)Component-based software engineeringStatement (computer science)Position operatorMassCore dumpMatching (graph theory)IterationNumberCycle (graph theory)Right angleSemiconductor memoryTesselationPhysical systemBranch (computer science)StatisticsGame theoryPixelEmulatorBefehlsprozessorConnectivity (graph theory)Multiplication signCoprocessorSoftwareBitWindowLine (geometry)Sound effectInformationGoodness of fitSoftware bugNintendo Co. Ltd.Graph coloringContent (media)Probability density functionSynchronizationLoop (music)Ferry CorstenLink (knot theory)Dependent and independent variablesTotal S.A.Different (Kate Ryan album)Programmer (hardware)TrailObject (grammar)Orientation (vector space)Fitness functionTouchscreenMachine codeSource codeAverageError messageCombinational logicLogical constantProjective planeConstructor (object-oriented programming)GoogolFrequencyCuboidExecution unitMathematicsMedical imagingGroup actionMultilaterationQuantum stateComputer simulationView (database)FamilyWordData storage deviceWeightObservational studyServer (computing)Graph (mathematics)Service (economics)Bit rateRow (database)Table (information)Computer hardwareLimit (category theory)Level (video gaming)ArmQuicksortHydraulic jumpComputer animation
15:08
Duality (mathematics)Loop (music)BefehlsprozessorSynchronizationRead-only memoryComponent-based software engineeringGame theoryArchitecturePixelStrutEinsteckmodulMachine codeGame controllerReading (process)Computer hardwareExecution unitSoftware testingEmulatorDebuggerCore dumpTouchscreenAddress spaceAsynchronous Transfer ModeSource codeMemory managementMountain passMathematicsDemosceneComputer virusLevel (video gaming)WindowComputer programOracleDisintegrationDecision theoryMenu (computing)Game theoryShooting methodInterpreter (computing)Web browserTouchscreenMedical imagingDigital electronicsVideoconferencingWebcamBitAddress spaceRight angleBefehlsprozessorMoment (mathematics)Multiplication signExecution unitSoftware frameworkChief information officerVirtual memoryDemo (music)DisassemblerUnit testingHeat transferComputer hardwareMereologySoftware testingSheaf (mathematics)DebuggerPixelRoutingConnectivity (graph theory)Point (geometry)Process (computing)Range (statistics)SoftwarePhysical systemStrategy gameType theoryGraph coloringSoftware bugSemiconductor memoryOrder (biology)EmulatorLevel (video gaming)Electronic mailing listEinsteckmodulDialectLink (knot theory)Computer simulationFamilyComputer programmingSingle-precision floating-point formatDatabaseCASE <Informatik>Ring (mathematics)Dependent and independent variablesView (database)CuboidWritingArmMachine visionQuicksortInformationRegulator geneUniverse (mathematics)Natural numberObservational studyGame controllerCondition numberComputer animation
22:39
Computer virusDiscrete element methodLevel (video gaming)Reading (process)Address spaceWritingLevel (video gaming)Different (Kate Ryan album)Group actionLogicEmulatorLibrary (computing)NeuroinformatikMoment (mathematics)Electronic program guideGame theoryStrategy gameRule of inferenceComputer animationLecture/Conference
25:09
Computer virusDiscrete element methodVideo GenieCombinational logicProcess (computing)Mixed realityThread (computing)1 (number)Video gameAdditionGrass (card game)Different (Kate Ryan album)Physical systemFamilyProjective planeSemiconductor memoryPresentation of a groupSystem callMereologySelectivity (electronic)Computer wormTable (information)Loop (music)CoprocessorSet (mathematics)CompilerMatching (graph theory)BefehlsprozessorView (database)Lecture/Conference
27:34
Program flowchart
Transcript: English(auto-generated)
00:06
All right, so yeah, our last speaker for the day, for this year actually, is German Gomez, and this is his first talk, first time doing a talk in general, so he's very nervous. And he's more nervous, actually.
00:28
And he has a very low voice, so if you could stop reading, it will, yeah. Okay, do I start now? Okay. Hello. So this is the title of my talk. It's a bit long, but the short version is at the bottom.
00:42
I'm just going to talk to you. I spent some time a couple of years ago making a Game Boy emulator, and I'm going to talk to you about it. So, wanting some introductions, but that's my name, and if you want to reach out to me after the conference, those are some of the ways. I work as a software engineer. I don't work on emulators.
01:01
I use them sometimes, but it's not part of my work. This is mostly just a hobby, so I've done all of this on my own time. And I can emulate the Game Boy camera as well. So this is what I'm going to talk about today. Points one, two, three are going to be... I'm going to talk to you about my particular emulator, how you can run it if you want
01:23
to do so, and afterwards I'm going to talk more generally about Game Boy emulation and how you can build your own emulator. I'll give some tips that I found that are useful for debugging. And at the end, some lessons learned and hopefully, if there is time, some demo.
01:45
So this is what my target audience here is mostly, for this talk, is mostly going to be emulator beginners, emulator development beginners. I find the Game Boy to be quite beginner-friendly. One of the reasons is because it's very heavily documented, and there are other reasons
02:03
as well that I'll get to later. If you're interested in Rust and WebAssembly, you're going to see a use case. And if you're just generally a fan of this device, then you might enjoy it also. So why make this in the first place?
02:23
The main reason I'm sure many people here will relate, or people making emulators, is the nostalgia. I used to own one of these, so I want to know how it works. Another reason, more generally speaking, this system is very attractive to emulate, because there's a huge amount of software out there, so you can spend many hours
02:45
just trying games and seeing if they work. And if they don't work, then you can spend many more hours trying to fix them. And it's just something I do for fun. I did it mostly, I don't work on it much these days, but every time I do, it's a lot of fun.
03:04
So it's made in Rust. The selling points for Rust are performance and memory save. My main selling point is that it has a very useful package manager and build tool. It's very quick to prototype things, and I was able to put this together very quickly, actually.
03:22
And one of the other main reasons I want to use it is because WebAssembly. The support in Rust is great, so you almost get WebAssembly for free if you use Rust. The tools are very nice. And it runs on the website, because WebAssembly can run on the browser, so it's very portable.
03:42
That's my phone, that's my PC. It also runs natively, it's not just WebAssembly. So if you want to run it, these are the commands you need to run. There's a native build, single command. You give it the ROM and it will emulate it.
04:00
The web build, this is a few more commands because you have to deploy a web application. It's very straightforward. It just works. And that's the link, if you want to try it. So I'm going to talk about the architecture and emulation. So these are the two devices that I emulate.
04:20
The original Game Boy came out in 1989. It was extremely popular. It was designed to be as cheap as possible, so lots of games were made for it. And it lasted close to 10 years. There were a few revisions in between, but it was mostly the same system. And then almost 10 years later, the Nintendo released the color version, which has still a very similar shape.
04:43
And also internally, the system is also very similar. The Game Boy Color is like a superset of the original Game Boy. So these are the two devices that I target. And I have to mention the Game Boy Advance. It's a completely different system. It's ARM-based.
05:01
It was still backwards compatible, but it's very different under the hood. So I don't support it for the time being. So I'm going to talk about the architecture. So if you open the original Game Boy, you'll see a bunch of stuff. But for emulation purposes, we only care about those three chips.
05:20
One of them has the CPU and the pixel processing unit, and the other chips are memory. So I'm going to limit this section to just talking about the CPU, the pixel processing unit, which does graphics. And at the end, to wrap it all up, I'll talk about the memory map tile,
05:42
which is what allows the CPU and the pixel processing unit to talk to each other, basically. So some basic stats about the CPU. It has 8-bit registers and 16-bit registers. It can do 500 things. It has 500 instructions, a 16-bit address bus, and an 8-bit data bus,
06:02
and it can run at two different speeds. The original Game Boy could only run at 4 MHz, but the Game Boy Color could choose between either of those two speeds. So about the registers and some general information, it has general-purpose registers.
06:20
These are here for intermediate calculations. There's also a flag register, which has information about the last arithmetic instructions that run. So if you add two numbers together, or subtract numbers together, and the result is zero, this register will tell you, and other things.
06:47
And the 16-bit registers are basically just the 8-bit ones, but used in combinations of two. Mostly just for pointers. The general-purpose ones, it has the normal program counter, with the address in memory of the next instruction,
07:04
a stack pointer for implementing subroutines, and there's a global switch for interrupts. It's Boolean, so when you set it to zero, the CPU will stop listening to interrupts, such as bottom presses, until you set it back to one.
07:22
So how can you model this in Rust? It's very simple. This is exactly what it looks like on mine. The state is very simple. It's just a few fields for the registers. So I'm going to talk about instructions. This CPU has 500 instructions.
07:42
It has your typical instructions as you would expect, so memory reads and writes, arithmetic, and branch instructions, so jumps and calling to subroutines. Some of the instructions can be conditional, using the F register. On this website, you can see them color-coded in a very nice table.
08:04
At the core of the CPU, this is how you implement instructions. So you have to do three things. First, you have to fetch the instruction from memory, using the PC register. Afterwards, you have to decode the instruction, so that means figuring out what instruction to run
08:21
based on that byte that you just read. And you can do this in C++, which is a switch statement. In Rust, you can use a match statement. And after you decode the instructions, you have to run it. So those are the three things you do. You fetch, you decode, and you run. And you run it in a loop, and that's what the CPU does.
08:41
So this is one example of an instruction. The code is very simple. This is a memory instruction. I'm only going to comment on the return statement. This particular instruction on the real CPU would take eight cycles of the clock, and we need to keep track of this, because afterwards, we need this information
09:00
to synchronize all of the emulator. Otherwise, it will lead to bugs. So that's why I returned the number. Another example of instruction, an arithmetic instruction, an exit operation. This one takes four cycles, and it's arithmetic, so it modifies the contents of the F register.
09:23
And you can look up how to implement every instruction on this PDF. So you do this for 500 times. You might make mistakes, but there are ways to fix those. I'll get to those later.
09:40
So you do it 500 times, and you will end up with a massive match statement or a switch statement. But the code inside of each of the branches is very simple, but it's still error-prone. This is an optional thing you can do, because this is going to run very frequently. It doesn't hurt to turn that into a binary search.
10:00
So you can optimize the code a bit. In Rust, this is very straightforward, using the match statements. So that's pretty much the CPU. I'm going to switch to the pixel processing unit. This is the chip responsible for graphics.
10:22
So the Game Boy had an LCD panel. The size is 160 pixels by 144. A total of four colors. More on Game Boy Color, of course. And it runs at roughly 60 hertz. And the way graphics work on this particular system
10:41
is by a composition of three layers. You have the window layer, the sprite layer, and the background layer. And then there are, like the CPU has registers, this device also has registers to program how you composite these layers together. So I'm going to go layer by layer.
11:01
So the first layer is the window layer. This is usually reserved for things like game stats. It's fixed on the LCD. You can move it around, but the graphics within the layer are not movable. They are constrained to a grid. Can anybody guess this game?
11:23
Yes, Link's Awakening. So that's Link. Link is a sprite on the sprite layer. Sprites are basically freely movable objects on the LCD. You can have 40 in total, and they come in two different sizes, programmable by registers, again.
11:43
Along with other things like color and position and orientation and things like that. And finally the background layer, what I think is the most interesting one. It's basically a grid of 32x32 tiles. Each tile is 8x8, so the total size is 256x256.
12:02
So it doesn't fit on the LCD screen, but you can scroll it using registers. And also furthermore, the scrolling wraps around, so you can be clever and implement infinite scrolling that way.
12:20
There are more registers. I don't have time to talk about all of them, but there's a link. So by today's standards, graphic-wise, this system cannot do much, but there are games that are quite clever using these limitations. So this is one example. It's not really a game,
12:40
it's more of a technical demo, but still. So this particular example is used in the background layer only, and it's modifying this scrolling register. So it's actually moving it around the screen. However, it's changing the value of the register on every single line. And what this accomplishes is a vertical stretching effect.
13:01
And at the same time, they are stretching the Nintendo logo horizontally in memory. You can see it right there. And in combination, these two things look like they are zooming in the Nintendo logo, which is something that the Game Boy cannot do in hardware, but they work around this by combining hardware and software. So I think it's quite interesting.
13:22
And there are many more examples of games being clever, this is one. So implementation-wise, this pixel processing unit is a bit more tricky to implement than the CPU. And because of that, it's the source of most of my bugs.
13:42
And this game is easy to recognize. It's Tony Hawk. So the reason it's tricky to implement correctly is because we need to keep the CPU and the pixel processing unit in constant sync. That's the reason I was returning the number of cycles on each instruction before.
14:01
And if you don't do it accurately enough, it will lead to stuff like this happening. However, I found that most games don't really care. Most games are quite forgiving of inaccuracies. Every now and then you will encounter a situation like this. In this particular example, the rest of the game looks fine. It's only the intro screen
14:21
that is glitchy. And I think this is one of the reasons why the game was a good beginner-friendly emulation project, because you don't need to be super accurate to emulate most games.
14:42
This is how you would implement the synchronization. This is how I do it. First, on each iteration step you implement, you run the CPU for an instruction. It will give you the number of cycles that it will take. And then you use that to synchronize the rest of the components. So you feed it to the rest of the components
15:00
so that they catch up to the CPU. Basically, this loop right here is the core of this emulator. This is what the emulator looks like. There are a few things like getting the image from the screen and so on. Conceptually, this is an emulator. It's very simple.
15:25
I've talked about the CPU and the pixel processing unit. Both have registers, but they are separate things on the circuit board. The CPU needs to be able to modify the registers of the pixel processing unit. The way this is done
15:41
is through memory, because every register that is not a CPU is exposed in memory. By reading and writing particular values to a particular address in memory, you can modify the registers of these devices. You can map the memory map a bit like this.
16:01
You have the cartridge right there. The video RAM and work RAM are the same size because they are those two chips on the circuit board. They are the exact same chip. There are other things. The buttons themselves are inside of this registers.io.
16:20
There are some regions that are a bit special. You are not allowed to write to this region for some reason. There are other details. This link has a technical documentation of the rest of the map in detail. Implementing the memory is quite easy.
16:42
You just list every single component and every single register a bit like this. You get the cartridge, the video RAM, pixel processing unit's registers, the buttons, sound registers, interrupt, controller, and then you need to be able to read from them.
17:01
Based on the address range you route it to the appropriate device and you need a similar method for writing values. Some of the values will be read only, so keep that in mind.
17:21
At this point maybe you'll have a working emulator, but if it's your first emulator, as was my case, then you'll run into bugs. There are a few things and they can be a bit tricky compared to other types of software I found. There are a few strategies that I sorry
17:42
So there are a few strategies you can follow in order to track down bugs. The first one I could give is just because there's so much documentation about the Game Boy, you can turn it into unit tests, to unit tests particular sections of the hardware. The other reason
18:01
why the Game Boy is so beginner friendly is you can actually run the diagnostics. There are available ROMs you can run and it will tell you where you are where you have issues. So if you make a mistake on the CPU, which is likely, then this particular ROM will tell you what the mistake was.
18:21
And you can also integrate this into your testing framework to run in CIO for extra credit. So the next one, the next tip is debugging. I'm going to show debugging using an example. So after you have an emulator, the logical step is to build a debugger for it.
18:43
Because it will allow you to see how, it will teach you things about the games running, but it will also teach you where you might be making mistakes. So in this particular example, when I run this game, at the moment it doesn't work. So basically this is what it looks like. It just gives you
19:00
a black screen, so there's nothing going on. But if you spend time making a debugger, then you can start finding clues. In this case, I spent some time just getting the instructions, the registers, the disassembly. Very useful. And in this particular example, thanks to that, I know what the
19:22
issue with this game is. So it's reading a value from this address and expecting a value that is never there. So this address corresponds to something called a DMA transfer. And what this tells me is that I have made a mistake in this emulation. So I can go to that particular section of my project and
19:42
fix it. But I haven't fixed it yet, because I found it quite recently. And also I found that it's more fun to add debugging features than it is fixing the issues themselves. And I've been a bit busy recently. So that's the end of my technical talk. And I'm going to finish with some
20:02
conclusions. This is my favorite glitch, by the way. Only happens when you set the name to a particular name. This is very weird. So writing an emulator, at least on a Game Boy emulator, is the easy part of emulating a Game Boy. Like I said, there's tons of documentation. And the hard part
20:22
of the work has been done by other people who have been kindly enough to write down their findings. So I just have to read the information, interpret it, and turn it into a program. So I'll keep that in mind when I move to the next system to emulate, because it might not be as easy.
20:42
So most games, as I said, are forgiving of inaccuracies. This is more of an issue with my emulator. But yeah, most games are forgiving of inaccuracies in the graphics. So this is yet one other reason why it's friendly for beginners. And finally,
21:00
WebAssembly and Rust are great. If you use Rust, using WebAssembly is very natural, if the support is great. And I have a small demo. It runs on the browser. Shoot.
21:21
Okay. So that's the LCD. I'm also drawing the video memory and the color palettes. And one of the things you can emulate on the Game Boy is, it came with a camera.
21:43
So if you load the camera on this application, it will request permission for the camera. But I've shown the picture at the beginning, so if you cancel the permission, it will still boot. So it has a fallback.
22:05
That's the Game Boy camera. So you cannot get the webcam because I haven't given you permissions, but you can still put the fallback in there.
22:25
And then you can, I don't know how to use this. I think no. Well, I think you can play games with it, but I don't know how it works. But that's the demo. So that's it from me.
22:42
So, thank you. We got permission for like five minutes, extra for questions. So people leave, please leave quietly. Can I just break in? I'm leaving immediately.
23:00
If you go out or please continue your questions and your discussion. Please look around you and take any garbage that you see from the room here and put it in the back. If a lot of people help, it's not much work. Otherwise, we will be here forever. Thank you. I have a question. With the emulator, is it easier to add like a
23:20
printer mode, like the action replay, like you can do unlimited drives and you can enter levels that aren't otherwise I have a, so the question was if I can just to make sure that I understood the question correctly. Can I
23:41
modify it in such a way that I can mess with the logic of the game? Was that? You can, you can, yeah, so
24:01
can I, so the question was can I, can I identify particular things happening on the on the, on the different games? And use it, sorry? Do you use that in trainers? Do you know about trainers? No, I don't.
24:21
You cheat, basically. You can change the value of a register and play action replay once all the home computers have the action replay. You also had action replay. Oh, I know GameShark. Can I
24:40
Yeah, I can, so the emulator is the, so the question is can I implement something like a GameShark to cheat on games? And yes I could, I can, the emulator is built as a library so you can use it as a library and read and write arbitrary bytes to arbitrary addresses so you could potentially build
25:01
something like that, yes. That was your first talk, right? Yeah. Yeah, well done. Thank you. It was really good, actually. Thank you. It's better than the last presentation I ate today. Thank you. I also had a call from Shane. So, like, with the
25:20
whole loop, you have a single loop where every part were like What? He's like, okay. Yeah, I know. Well, you know, my question was that you have a single loop that has processes on the CPU Yes, it's, it's, yeah.
25:40
What if you wanted, what if you were emulating with Rust a system where you want to have different threads for different peripherals, but they are all accessing the memory. Wouldn't the Rust memory safe interfere with that? Um, so can I use Rust to or can I, can I run things in different threads? And would that cause
26:02
problems? And probably yes, but that was a kind of worm that I didn't want to open. And also, if the system was simple enough, like this one, you don't really need to optimize like that. You can now run in a single thread. But for a more complex device, sure, I would have to investigate more on that.
26:21
But I didn't have to do that on this one. Question. Why did you pick Rust? Was there any reason that you did not select C++? So, What's that? Why did I pick Rust over something like C++? I use Rust for my personal
26:40
projects. It's what I like using it. And you know Rust better than C++? I think I do, yeah. And the processor is a 6502? So the processor the question was what the processor is. It's not a 6502.
27:01
It's a Cilux 80 and Intel 8080. So it's like a combination of the two. I think it is specific. I'm not really sure. How is this thing working? So, you mentioned you split your match up into binary sets. Did you actually benchmark that?
27:22
Because I thought the compiler would have translated it into a jump table. On my view now. And we're going to get kicked out. I'll be honest, I did not benchmark that. Because that was a very recent change.