[00:00.000 --> 00:11.400] All right, so yeah, our last speaker for the day, for this year actually, is Tirmang [00:11.400 --> 00:12.400] Gomez. [00:12.400 --> 00:16.400] And this is his first time doing a talk in general, so he's very nervous. [00:16.400 --> 00:39.520] Okay, so this is the title of my talk. [00:39.520 --> 00:42.520] It's a bit long, but the short version is at the bottom, I'm just gonna talk to you. [00:42.520 --> 00:48.240] I spent some time, a couple of years ago, making a Gimbo emulator, and I'm gonna talk [00:48.240 --> 00:51.280] to you about it. [00:51.280 --> 00:55.080] So wanting some introductions, that's my name, and if you want to reach out to me after [00:55.080 --> 00:57.480] the conference, those are some of the ways. [00:57.480 --> 00:59.360] I work as a software engineer. [00:59.360 --> 01:03.680] I don't work on emulators, I use them sometimes, but it's not part of my work. [01:03.680 --> 01:08.520] This is mostly just a hobby, so I've done all of this on my own time. [01:08.520 --> 01:13.400] And I can emulate the Gimbo camera as well. [01:13.400 --> 01:19.920] So this is what I'm gonna talk about today, points 1, 2, 3, I'm going to talk to you about [01:19.920 --> 01:24.880] my particular emulator, how you can run it if you want to do so. [01:24.880 --> 01:29.120] And afterwards, I'm gonna talk more generally about Gimbo emulation and how you can build [01:29.120 --> 01:31.480] your own emulator. [01:31.480 --> 01:36.280] I'll give some tips that I found that are useful for debugging. [01:36.280 --> 01:45.440] And at the end, some lessons learned, and hopefully, if there is time, some demo. [01:45.440 --> 01:51.560] So this is what my target audience here is mostly, for this talk, is mostly going to [01:51.560 --> 01:55.520] be emulator beginners, emulator development beginners. [01:55.520 --> 01:59.280] I find the Gimbo to be quite beginner-friendly. [01:59.280 --> 02:03.040] One other reason is because it's very heavily documented, and there are other reasons as [02:03.040 --> 02:06.440] well that I'll get to later. [02:06.440 --> 02:11.160] If you're interested in Rust and WebAssembly, you're going to see a use case. [02:11.160 --> 02:19.280] And if you're just generally a fan of this device, then you might enjoy that also. [02:19.280 --> 02:23.280] So why make this in the first place? [02:23.280 --> 02:27.400] The main reason I'm sure many people here will relate, or people making emulators is [02:27.400 --> 02:28.400] the nostalgia. [02:28.400 --> 02:34.640] I used to own one of these, so I want to know how it works. [02:34.640 --> 02:39.840] Another reason, more generally speaking, this system is very attractive to emulate because [02:39.840 --> 02:45.680] of the, there's a huge amount of software out there, so you can spend many hours just [02:45.680 --> 02:48.000] trying games and seeing if they work. [02:48.000 --> 02:52.640] And if they don't work, then you can spend many more hours trying to fix them. [02:52.640 --> 02:55.640] And it's just something I do for fun. [02:55.640 --> 03:04.280] 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.280 --> 03:06.040] So it's made in Rust. [03:06.040 --> 03:09.280] The selling points for Rust are performance and memory save. [03:09.280 --> 03:15.680] My main selling point is that it has a very useful package manager and build tool. [03:15.680 --> 03:20.000] It's very quick to prototype things, and I was able to put this together very quickly [03:20.000 --> 03:22.640] actually. [03:22.640 --> 03:27.640] And one of the other main reasons I want to use it is because of WebAssembly. [03:27.640 --> 03:35.240] The support in Rust is great, so you almost get WebAssembly for free if you use Rust. [03:35.240 --> 03:37.680] The tools are very nice. [03:37.680 --> 03:42.480] And it runs on the website because it's WebAssembly can run on the browser, so it's very portable. [03:42.480 --> 03:46.280] That's my phone, that's my PC. [03:46.280 --> 03:47.280] It also runs natively. [03:47.280 --> 03:49.760] It's not just WebAssembly. [03:49.760 --> 03:53.760] So if you want to run it, these are the commands you need to run. [03:53.760 --> 03:56.680] There's a native build, single command. [03:56.680 --> 04:00.280] You give it the ROM and it will emulate it. [04:00.280 --> 04:04.000] The web build, this is the few more commands because you have to deploy a web application. [04:04.000 --> 04:07.480] So it's just, but it's very straightforward. [04:07.480 --> 04:09.880] It just works. [04:09.880 --> 04:14.560] And that's the link if you want to try it. [04:14.560 --> 04:17.480] So I'm going to talk about the architecture and emulation. [04:17.480 --> 04:20.120] So these are the two devices that I emulate. [04:20.120 --> 04:23.440] The original Gameboy came out in 1989. [04:23.440 --> 04:24.560] It was extremely popular. [04:24.560 --> 04:29.240] It was designed to be as cheap as possible, so lots of games were made for it. [04:29.240 --> 04:30.720] And it lasted close to 10 years. [04:30.720 --> 04:35.360] There were a few revisions in between, but it was mostly the same system. [04:35.360 --> 04:41.000] And then almost 10 years later, the Nintendo released the color version, which has still [04:41.000 --> 04:43.160] a very similar shape. [04:43.160 --> 04:46.360] And also internally, the system is also very similar. [04:46.360 --> 04:51.920] So the Gameboy color is like a super set of the original Gameboy. [04:51.920 --> 04:55.480] So these are the two devices that I target. [04:55.480 --> 04:57.800] And I have to mention the Gameboy Advance. [04:57.800 --> 04:59.360] It's a completely different system. [04:59.360 --> 05:00.680] It's arm-based. [05:00.680 --> 05:04.960] It was still backwards compatible, but it's very different under the hood. [05:04.960 --> 05:10.840] So I don't support it for the time being. [05:10.840 --> 05:12.920] So I'm going to talk about the architecture. [05:12.920 --> 05:16.320] I'm going to, so if you open the original Gameboy, you'll see a bunch of stuff. [05:16.320 --> 05:20.760] But for emulation purposes, we only care about those three chips. [05:20.760 --> 05:26.840] One of them has the CPU and the pixel processing unit, which and the other chips are memory. [05:26.840 --> 05:31.240] So I'm going to narrow, I'm going to limit this section to just talking about the CPU, [05:31.240 --> 05:38.200] the pixel processing unit, which does graphics and at the end to wrap it all up, I'll talk [05:38.200 --> 05:44.280] about the memory map that you, which is what allows the CPU and the pixel processing unit [05:44.280 --> 05:47.360] to talk to each other basically. [05:47.360 --> 05:50.360] So some basic stats about the CPU. [05:50.360 --> 05:53.560] It has 8-bit registers and 16-bit registers. [05:53.560 --> 06:02.000] It can do 500 things, has 500 instructions, a 16-bit address bus and an 8-bit data bus, [06:02.000 --> 06:04.920] and it can run at two different speeds. [06:04.920 --> 06:08.520] The original Gameboy could only run at four megahertz, but the Gameboy color could choose [06:08.520 --> 06:14.360] between either of those two speeds. [06:14.360 --> 06:20.640] So about the registers and some general information, it has general purpose registers. [06:20.640 --> 06:26.040] These are here for intermediate calculations. [06:26.040 --> 06:33.000] There's also a flag register, which has information about the last arithmetic instruction that [06:33.000 --> 06:34.000] run. [06:34.000 --> 06:38.800] So if you add two numbers together or subtract numbers together and the result is zero, this [06:38.800 --> 06:45.200] register will tell you and other things. [06:45.200 --> 06:53.840] The 16-bit registers are basically just the 8-bit ones, but used in combinations of two, [06:53.840 --> 06:56.360] mostly just for 0.3. [06:56.360 --> 07:01.680] The general purpose ones, it has the normal program counter with the address of in-memory [07:01.680 --> 07:07.800] of the next instruction, a stack pointer for implemented subroutines, and there's a global [07:07.800 --> 07:13.920] switch for interrupts, it's Boolean, so when you set it to zero, the CPU will stop listening [07:13.920 --> 07:21.920] to interrupts, such as bottom presses, until you set it back to one. [07:21.920 --> 07:24.520] So how can you model this in Rust? [07:24.520 --> 07:25.520] It's very simple. [07:25.520 --> 07:29.000] This is exactly what it looks like on mine. [07:29.000 --> 07:34.880] The state is very simple, it's just a few fields for the registers. [07:34.880 --> 07:38.880] So I'm going to talk about instructions. [07:38.880 --> 07:42.240] This CPU has 500 instructions. [07:42.240 --> 07:48.080] It has your typical instructions that you would expect, so memory reads and writes, arithmetic [07:48.080 --> 07:51.920] and branch instructions, so jumps and calling to subroutines. [07:51.920 --> 07:57.920] Some of the instructions can be conditional using the F register, and on this website [07:57.920 --> 08:03.200] you can see them in color coded in a very nice table. [08:03.200 --> 08:08.320] So this is at the core of the CPU, this is how you implement the instructions. [08:08.320 --> 08:12.560] So you have to do the three things, first you have to fetch the instruction from memory [08:12.560 --> 08:18.520] using the PC register, afterwards you have to decode the instruction, so that means figuring [08:18.520 --> 08:24.240] out what instruction to run based on that byte that you just read, and you can do this [08:24.240 --> 08:30.960] with a, in C++ you would use a switch statement, in Rust you can use a match statement. [08:30.960 --> 08:33.960] And after you decode the instructions you have to run it, so those are the three things [08:33.960 --> 08:39.080] you do, you fetch, you decode and you run, and you run it in a loop, in a loop and that's [08:39.080 --> 08:41.480] what the CPU does. [08:41.480 --> 08:47.160] So this is one example of an instruction, the code is very simple, this is a memory [08:47.160 --> 08:53.360] instruction, I'm only going to comment on the return statement, this particular instruction [08:53.360 --> 08:57.840] on the real CPU would take eight cycles of the clock, and we need to keep track of this [08:57.840 --> 09:04.440] because afterwards we need to see this information to synchronize all of the emulator, otherwise [09:04.440 --> 09:09.640] it would lead to bugs, so that's why I returned the number. [09:09.640 --> 09:15.240] Another example of instruction, an arithmetic instruction and exit operation, this one takes [09:15.240 --> 09:22.920] for cycles and it's arithmetic so it modifies the contents of the F register. [09:22.920 --> 09:29.840] And you can look up how to implement every instruction on this PDF. [09:29.840 --> 09:37.160] So you do this for 500 times, you might make mistakes but there are ways to fix those, [09:37.160 --> 09:40.360] I'll get to those later. [09:40.360 --> 09:44.400] So you do it 500 times and you will end up with a massive match statement or a switch [09:44.400 --> 09:49.920] statement, but the code inside of each of the branches is very simple, but it's still [09:49.920 --> 09:50.920] error prone. [09:50.920 --> 09:57.240] This is an optional thing you can do, because this is going to run very frequently, it doesn't [09:57.240 --> 10:03.360] hurt to turn that into a sort of binary search, so you can optimize the code a bit using, [10:03.360 --> 10:10.960] in Rust this is very straightforward using the match statements. [10:10.960 --> 10:14.600] So that's pretty much the CPU. [10:14.600 --> 10:20.160] I'm going to switch to the pixel processing unit, this is the chip responsible for graphics. [10:20.160 --> 10:32.200] So the Game Boy had an LCD panel, this size is 160 pixels by 144, total of 4 colors, more [10:32.200 --> 10:38.240] on Game Boy color of course, and it runs at roughly 60 hertz. [10:38.240 --> 10:43.080] And the way graphics works on this particular system is by a composition of three layers, [10:43.080 --> 10:49.080] you have the window layer, the spread layer and the background layer, and then there are, [10:49.080 --> 10:55.680] the CPU has registers, this device also has registers to program how you composite these [10:55.680 --> 10:58.160] layers together. [10:58.160 --> 11:00.920] So I'm going to go layer by layer. [11:00.920 --> 11:06.600] So the first layer is the window layer. [11:06.600 --> 11:12.480] This is usually reserved for things like game stats, it's fixed on the LCD, you can move [11:12.480 --> 11:17.920] it around, but the graphics within the layer are not movable, they are constrained to a [11:17.920 --> 11:18.920] grid. [11:18.920 --> 11:21.160] Can anybody guess this game? [11:21.160 --> 11:26.120] Yes, Link's Awakening, yeah. [11:26.120 --> 11:31.120] So that's Link, Link is a sprite on the sprite layer. [11:31.120 --> 11:37.920] So sprites are basically freely movable objects on the LCD, you can have 14 in total and they [11:37.920 --> 11:44.080] come in two different sizes, programmable by registers again, along with other things [11:44.080 --> 11:48.160] like color and position and orientation and things like that. [11:48.160 --> 11:53.560] And finally the background layer, what I think is the most interesting one, it's basically [11:53.560 --> 12:02.240] a grid of 32 by 32 tiles, each tile is 8 by 8, so the total size is 256 by 256, so it [12:02.240 --> 12:07.760] doesn't fit on the LCD screen, but you can scroll it using registers. [12:07.760 --> 12:14.000] So that's, and also furthermore, the scrolling wraps around so you can be clever and implement [12:14.000 --> 12:17.520] infinite scrolling that way. [12:17.520 --> 12:24.400] So it cannot, so there are more registers, I don't have time to talk about all of them, [12:24.400 --> 12:29.160] but there's a link. [12:29.160 --> 12:36.080] So by today's standards, this graphic-wise, this system cannot do much, but there are [12:36.080 --> 12:38.520] games that are quite clever using these limitations. [12:38.520 --> 12:44.200] So this is one example, it's not really a game, it's more of a technical demo, but still. [12:44.200 --> 12:49.960] So this particular example is used in the background layer only, and it's modifying this scrolling [12:49.960 --> 12:54.640] register, so it's actually moving it around the screen, however, it's changing the value [12:54.640 --> 12:59.480] of the register on every single line, and what this accomplishes is like a vertical [12:59.480 --> 13:05.040] stretching effect, and at the same time they are stretching the Nintendo logo horizontally [13:05.040 --> 13:10.680] in memory, you can see right there, and in combination these two things looks like they [13:10.680 --> 13:15.760] are zooming in the Nintendo logo, which is something that the gameboy cannot do in hardware, [13:15.760 --> 13:22.240] but they work around this by combining hardware and software, so I think it's quite interesting. [13:22.240 --> 13:28.920] And there are many more examples of games being clever, this is one. [13:28.920 --> 13:36.280] So implementation-wise, this pixel processing unit is a bit more tricky to implement, like [13:36.280 --> 13:42.880] on the CPU, and because of that it is a source of most of my bugs, and this game is easy [13:42.880 --> 13:48.600] to recognize, it's Tony Hawk. [13:48.600 --> 13:53.680] So the reason it's tricky to implement correctly is because we need to keep the CPU and the [13:53.680 --> 13:58.480] pixel processing unit in constant sync, that's the reason I was returning the number of cycles [13:58.480 --> 14:04.400] on each instruction before, and if you don't do it accurately enough it would lead to stuff [14:04.400 --> 14:11.760] like this happening, however I found that most games don't really care, most games are [14:11.760 --> 14:16.320] quite forgiving of inaccuracies, every now and then you will encounter a situation like [14:16.320 --> 14:21.000] this, in this particular example the rest of the game looks fine, it's only the interesting [14:21.000 --> 14:29.680] that is glitchy, and I think this is one of the reasons why the gameboy is a good emulation [14:29.680 --> 14:35.400] emulator, beginning-friendly emulation project because you don't need to be super accurate [14:35.400 --> 14:39.120] to emulate most games. [14:39.120 --> 14:46.880] So yeah, this is how you would implement the synchronization, this is how I do it, so first [14:46.880 --> 14:53.640] you on each iteration step you implement, you run the CPU for an instruction, it will [14:53.640 --> 14:57.800] give you the number of cycles that it will take, and then you use that to synchronize [14:57.800 --> 15:01.200] the rest of the components, so you feed it to the rest of the components so that they [15:01.200 --> 15:07.480] catch up to the CPU, so you do this forever, basically this loop right here is the core [15:07.480 --> 15:12.720] of this emulator, this is what the emulator looks like, there are a few things like getting [15:12.720 --> 15:24.520] the image from the screen and so on, but conceptually this is an emulator, it's very simple. [15:24.520 --> 15:30.960] So I've talked about the CPU and the pixel processing unit, both have registers, but [15:30.960 --> 15:36.800] they are separate things on the circuit board, so the CPU needs to be able to modify the [15:36.800 --> 15:43.360] registers of the pixel processing unit, and the way this is done is through memory, because [15:43.360 --> 15:48.920] these registers, every register that is not a CPU register is exposed in memory, so by [15:48.920 --> 15:52.840] reading and writing particular values to a particular address in memory, you can modify [15:52.840 --> 16:01.280] the registers of these devices, and you can map the memory map a bit like this, you have [16:01.280 --> 16:06.320] the characters right there, the video RAM and work RAM are the same size, because they [16:06.320 --> 16:10.280] are those two chips on the circuit board, those two other chips, they are the exact [16:10.280 --> 16:17.560] same chip, and there are other things, the buttons themselves are inside of these registers [16:17.560 --> 16:24.280] I.O., so yeah, there are some regions that are a bit special, you are not allowed to write [16:24.280 --> 16:31.400] to this region for some reason, and there are other details, this link has a technical [16:31.400 --> 16:37.840] documentation of the rest of the map in detail. [16:37.840 --> 16:43.600] So implementing the memory is quite easy, you just list every single component and every [16:43.600 --> 16:51.320] single register, a bit like this, so you get the cartridge, the video RAM, pixel processing [16:51.320 --> 16:58.760] unit registers, the buttons, sound registers, interrupt, controller, and then you need to [16:58.760 --> 17:05.240] be able to read from them, so based on the address range you can you route it to the [17:05.240 --> 17:12.080] appropriate device, and you need a similar method for writing values, some of the values [17:12.080 --> 17:23.320] will be read only, so keep that in mind, so at this point maybe you will have a sort of [17:23.320 --> 17:28.200] working emulator, but if it is your first emulator, as was my case, then you will run [17:28.200 --> 17:34.520] into bugs, and there are a few things, and they can be a bit tricky compared to other [17:34.520 --> 17:42.920] types of software I found, so there are a few strategies that I, sorry, so there are [17:42.920 --> 17:46.240] a few strategies you can follow in order to track down bugs, the first one I could give [17:46.240 --> 17:52.080] is just, because there is so much documentation about the Game Boy you can turn it into unit [17:52.080 --> 18:02.280] tests, to unit test particular sections of the hardware, the other reason why the Game [18:02.280 --> 18:08.480] Boy is so beginner friendly is you can actually run the diagnostics, there are available ROMs [18:08.480 --> 18:13.120] you can run and it will tell you where you are, where you have issues, so if you make [18:13.120 --> 18:19.120] a mistake on the CPU, which is likely, then this particular ROM will tell you what the [18:19.120 --> 18:25.760] mistake was, and you can also integrate this into your testing framework to run in CIO [18:25.760 --> 18:34.080] for extra credit, so the next one, the next tip is debugging, I am going to show debugging [18:34.080 --> 18:41.240] using an example, so after you have an emulator, the logical step is to build a debugger for [18:41.240 --> 18:46.480] it, because it will allow you to see how, it will teach you things about the games running, [18:46.480 --> 18:51.560] but it will also teach you where you might be making mistakes, so in this particular [18:51.560 --> 18:57.160] example, when I run this game, at the moment it doesn't work, so basically this is what [18:57.160 --> 19:04.440] it looks like, it just gives you a black screen, so there is nothing going on, but if you spend [19:04.440 --> 19:13.000] time making a debugger, then you can start finding clues, in this case, I spend sometimes [19:13.000 --> 19:18.920] just getting the instructions, the registers, the disassembly, very useful, and in this [19:18.920 --> 19:27.800] particular example, I know what the issue with this game is, so it is writing a value [19:27.800 --> 19:32.640] from this address and expecting a value that is never there, so this address corresponds [19:32.640 --> 19:37.760] to something called a DMA transfer, and what this tells me is that I have made a mistake [19:37.760 --> 19:42.880] in this emulation, so I can go to that particular section of my project and fix it, but I haven't [19:42.880 --> 19:48.200] fixed it yet, because I found it quite recently, and also I found that it is a lot more fun [19:48.200 --> 19:56.240] to add debugging features than it is fixing the issues themselves, and I've been a bit [19:56.240 --> 20:03.880] busy recently, so that's the end of my technical talk, and I'm going to finish with some conclusions, [20:03.880 --> 20:09.280] this is my favorite glitch by the way, it only happens when you set the name to a particular [20:09.280 --> 20:16.680] name, it is very weird, so writing an emulator, at least on a Gameboy emulator, is the easy [20:16.680 --> 20:21.640] part of emulating a Gameboy, like I said, there's tons of documentation, and the hard [20:21.640 --> 20:25.600] part of the work has been done by other people who have been kindly enough to write down [20:25.600 --> 20:30.560] their findings, so I just have to read the information, interpret it, and turn it into [20:30.560 --> 20:39.640] a program, so I keep that in mind when I move to the next system to emulate, because it might [20:39.640 --> 20:48.000] not be as easy, so most games as I said are forgiving of inaccuracies, except this is more [20:48.000 --> 20:53.320] of an issue with my emulator, but most games are forgiving of inaccuracies in the graphics, [20:53.320 --> 21:00.760] so this is yet one other reason why it's friendly for beginners, and finally, WebAssembly and [21:00.760 --> 21:07.280] Rust are great, if you just Rust, it's using WebAssembly, it's very natural, if the support [21:07.280 --> 21:30.640] is great, and I have a small demo, it runs on the browser, so that's the LCD, I'm also [21:30.640 --> 21:37.800] drawing the video memory and the color palettes, and one of the things you can emulate on the [21:37.800 --> 21:46.400] Gameboy is, it came with a camera, so if you load the camera on this application, it will [21:46.400 --> 21:52.320] request permission for the camera, but I've shown the picture at the beginning, so if [21:52.320 --> 22:08.720] you cancel the permission, it will still boot, so it has a fallback, so it cannot get the [22:08.720 --> 22:35.360] webcam, because I haven't given it permissions, but it can still put the file in there. I think [22:35.360 --> 22:40.000] you can play games with it, but I don't know how it works, but that's the demo, so that's [22:40.000 --> 23:02.720] it from me. Can I just break in? I'm leaving immediately, but if you go out, please continue [23:02.720 --> 23:06.920] your questions and your discussion, please look around you and take any garbage that [23:06.920 --> 23:11.200] you see from the room here and put it in the back, if a lot of people help, it's not much [23:11.200 --> 23:14.920] work, otherwise we will be here forever. Thank you. [23:14.920 --> 23:43.520] I have a question. Can I modify it in such a way that I can mess with the logic of the [23:43.520 --> 24:11.600] game? The question was, can I identify particular things happening on the different games? [24:11.600 --> 24:23.360] Do you know about these trainers? No, I don't. [24:23.360 --> 24:53.080] Can I implement something like a game shark to cheat on games? Yes, I could. The emulator [24:53.080 --> 24:58.480] is built as a library, so you can use it as a library and read and write arbitrary bytes [24:58.480 --> 25:02.360] to arbitrary addresses, so you could potentially build something like that, yes. [25:02.360 --> 25:23.920] Thank you. You also had a corporate check. You have a single loop, where every part we're [25:23.920 --> 25:25.920] I'm like, see, what? [25:25.920 --> 25:27.920] You still in your program? [25:27.920 --> 25:29.920] Oh, she's like, okay. [25:29.920 --> 25:31.920] Yeah, I know. [25:31.920 --> 25:33.920] Well, my question was that [25:33.920 --> 25:35.920] you have a single room [25:35.920 --> 25:37.920] that has processes on the CPU. [25:37.920 --> 25:39.920] Yes, it's, yeah. [25:39.920 --> 25:41.920] What if you wanted, [25:41.920 --> 25:43.920] what if you were emulating with Rust [25:43.920 --> 25:45.920] a system where you want [25:45.920 --> 25:47.920] to have different threads for different peripherals. [25:47.920 --> 25:49.920] But they are all accessing the memory. [25:49.920 --> 25:51.920] Wouldn't the Rust [25:51.920 --> 25:53.920] have the same interview with that? [25:53.920 --> 25:55.920] Um, so [25:55.920 --> 25:57.920] can I use Rust to, [25:57.920 --> 25:59.920] can I run things in different threads [25:59.920 --> 26:01.920] with the first problems? [26:01.920 --> 26:03.920] And probably yes, [26:03.920 --> 26:05.920] but that was a kind of worms that I didn't want to open. [26:07.920 --> 26:09.920] And also, if the system [26:09.920 --> 26:11.920] was simple enough like this one, you don't really need to [26:11.920 --> 26:13.920] optimize like that. [26:13.920 --> 26:15.920] It can all run in a single thread. [26:15.920 --> 26:17.920] But for a more complex device, [26:17.920 --> 26:19.920] sure, I would have to [26:19.920 --> 26:21.920] investigate more on that. [26:21.920 --> 26:23.920] But I didn't have to do that on this one. [26:23.920 --> 26:25.920] Yeah. [26:25.920 --> 26:27.920] Why did you pick Rust? [26:27.920 --> 26:29.920] Was there any reason that you did not [26:29.920 --> 26:31.920] select C++? [26:31.920 --> 26:33.920] Yeah. [26:33.920 --> 26:35.920] Why did I pick Rust over [26:35.920 --> 26:37.920] something like C++? [26:37.920 --> 26:39.920] It's what I use Rust [26:39.920 --> 26:41.920] for my personal projects. [26:41.920 --> 26:43.920] It's what I like using it. [26:43.920 --> 26:45.920] It's what I like using. [26:45.920 --> 26:47.920] And you know Rust better than C++? [26:47.920 --> 26:49.920] Yeah. [26:49.920 --> 26:51.920] And the processor is a 6502 or is it? [26:51.920 --> 26:53.920] So the processor, [26:53.920 --> 26:55.920] the question was what the processor [26:55.920 --> 26:57.920] is. [26:57.920 --> 26:59.920] Yeah, it's not a 6502. [26:59.920 --> 27:01.920] I think it's a mix of [27:01.920 --> 27:03.920] a Psylog Z80 [27:03.920 --> 27:05.920] and an Intel 8080. [27:05.920 --> 27:07.920] So it's like a combination of the two. [27:07.920 --> 27:09.920] I think it is [27:09.920 --> 27:17.920] I'm not really sure. [27:17.920 --> 27:19.920] You split your match up into [27:19.920 --> 27:21.920] the binary sets. Did you actually benchmark that? [27:21.920 --> 27:23.920] Because I thought the compiler would have [27:23.920 --> 27:25.920] just translated into a jump tape. [27:25.920 --> 27:27.920] On mic, you know. [27:27.920 --> 27:29.920] And we're going to get kicked out. [27:29.920 --> 27:31.920] I'll be honest, I didn't benchmark that [27:31.920 --> 27:41.920] everybody was in change.