字幕表 動画を再生する 英語字幕をプリント Hello and welcome to Part seven of my Nails emulator Siri's. If you've made it this far, a big thanks to you for sticking with it for so long. This video is about the mappers, specifically, the map is you're going to need to use to implement the bulk of the Nintendo catalogue of games. But whilst I was planning this video, something dawned on me. It's very difficult to make a video about matters, and consequently, this video is presented in a different style to how I would usually make videos. Normally, I like to build up the project line by line and show you it working at various stages and provide small tests and explanations of what's going on. The problem is, matters don't work that way. The work or they don't and they need to exist in their entirety before you even know if they work or not. And this makes them especially difficult to deep book. And so instead, what I'm going to do is present. A review of the map is that I've made already for this project. They're the main mapas you need for most of the Nintendo games on. I'll walk you through how to understand the macro specifications on how to translate that into code. I also expect that given that this is Part seven, and if you have made it this far, you're probably already quite familiar with the nose architecture by now. And so perhaps I don't need to go into quite a CZ much detail as I have done a staff of the Siris. So let's get started with a quick refresher on what it is the map actually does. Fundamentally. It's a device that translates addresses from a CPU or the peopIe you into memory stored on the cartridge itself, such as the program Wrong memory onto the character. Wrong memory. As we'll see later in this video. Some members have additional capabilities, but for now, let's assume they're just doing this simple address. Translation. Recall that certain locations in the CPU address space in the people you address space are expected to serve specific purposes. The CPU can address 64 kilobytes, but there certainly isn't 64 kilobytes of memory on the Nintendo console. On when the CPU rights to addresses that doesn't have a physical hardware implementation, it gets mirrored back to some lower number address. We've covered all of this in great detail. We also looked at where the programs start in the CPU address. Space on it's about halfway. This means there's about 32 kilobytes of addressable program memory at any given time. So let's just look at a few example configurations. Let's assume that's our entire program. Rum on the Cartridge is, in fact, only eight kilobytes. It's a small and simple game. One way to approach this is to map this entire eight kilobyte memory into the 1st 8 kilobytes of our CPU address space after the halfway point. And any reads two addresses beyond the eight kilobytes are simply mirrored in the rest of that space. Hopefully, it's obvious that if we had a 16 kilobyte program run, we could map that twice into the sea pews, addressable space. And if it was 32 kilobytes, well, then it's a perfect fit. The mapping is a want or what, but let's take things to extremes for a moment. Let's assume our program wrong is 100 and 28 kilobytes. Clearly, this can't fit into the 32 kilobyte addressable space. Instead, we must break this 128 kilobytes into 4 32 kilobyte regions on the map. ER will perform that translation for us, depending on which bank we have selected. So thes dotted green lines broadly can be considered bank dividers. At some point, the map A is instructed which bank of program wrong is required to map into the location of the CPUs address space. And in this video, we'll look at the implementation details for some of the more common mappers as they all approach this in slightly different ways. This simplification that I've illustrated is a little unrealistic. It surfaced from. One big problem on that is swapping the entire address space in one go is, well, a bad idea. And this is because as the program is running, there's a great deal of risk in just swapping the memory out as the program counter will start in the exact same location in the new bank of memory. Now, unless you carefully coordinated that to be legitimate, that's really just going to make your life is a developer quite complicated? So instead, there is a different solution. It's convenient to think of program wrong in 16 Killer by chunks and equally think of the program Memories location in the CPU address space also in 16 Killer by chunks. The map may have been configured that all of the addresses in this range are mapped into a specific bank in the program memory, but also that the addresses in this range are mapped to some other bank. This means that when the program counter is operating in this range, it can configure the mapper to change the bank referenced in this range without corrupting the program. And, of course, if the program counter is in this range, it can configure the bank mapped into this range. This keeps things a lot more organized for the programmer. The numbers I've chosen here are somewhat arbitrary on will See that the different mappers handle things in different ways. The address space of the people You is mapped in a pretty much identical way. The dress spaces, of course, smaller. It only goes 23 f f f, the first half of which is used to store the sprite patterns. Ultimately, the tiles that make up the graphics we see on the screen on the's tiles are called characters, and thus this region gets mapped onto the character wrong. The character Ron can be partitioned in many ways, just as the program wrong, Waas on different regions of the pattern, tables can be mapped onto different banks of the character wrong. Typically, these regions are considerably smaller because, as we've seen in previous videos, if you wanted to animate a particular Tarts set, you only want to swap in maybe a couple of rows of the pattern table, and it's possible there are several. Mapping is in place at any one time. The mapping for the people you is a lot more flexible than the CPU because we don't have a program counter to worry about in the purest sense. It really is just mapping one memory address to a memory address somewhere on the cartridge. So that's what the map it does. But how does it do it as discussed? Most of the addresses on the CPU boss have a purpose, but one thing we've not seen is any particular register mapped here that could potentially talk to a map. Er, for example, to talk to the people you we wrote to specific addresses in the CPU address space on that cost, the people you to change its state. That isn't an equivalent for configuring the map. It instead, the map is take advantage of the fact that the program memory is a Rome. By definition, it's read only weaken right to these locations, but nothing happens. It's read only memory. It doesn't change the state of our program. The CPU bus is unaware what read only memory means so it can, quite happily right to a location here. The map will receive this address on the data, but the data simply has nowhere to go. It can't be written to the read only memory. Therefore, if the map aerate detection address, which is in this addressable range where the program is expected to be read from it, can interpret that address as a command to the map for itself. And it's through this mechanism that we can configure the mapper to set up the map ings between the program rahm on the cartridge and the CPU address space on the character room on the cartridge on the people you address space. And even though these are two distinct systems, there is only one mapper controlling them both. Now, as I mentioned at the start of the video, I'm not going to be coding up. The mappers line by line instead was sort of going to review how I've implemented a certain number of mappers on since one of the earliest episodes of the series. We've had a map, a base class which handles, read and write to the CP bus reading right to the people you bust on overtime. It's evolved to have a few more functions, and we'll look at these as we develop the rest of this video in the cartridge CPP file, where we load the wrong image itself. We determine the map. Er i D. According to the I Nez head of former, one of those header entries is how many banks of Program Rahm are there? And it assumes that a bank of program rum is 16 kilobytes. That doesn't necessarily mean the map. Oh will interpret it a 16 kilobytes. That's just for us to load it into, in this case, this vector the program memory on in exactly the same way. We also created a vector for the character memory, and it assumes that the eight killer bite chunks. In that instance, some of the mappers rely on knowing how many program banks and character banks there are. So this information is passed along into the constructor of the map. On will choose the appropriate derived mapper based on the map. Er i d. And for my emulator, I've chosen thes mappers because thes will cover the book off the games. And there's one sort of curiosity mapper, although I'm not going to do them in this order and said, I'm going to do them in order of complexity. The map we've been working with throughout this series so far is map a zero. And as we have throughout this series, it's time to defer to the great. And there's Dead Wicky. So again, a big thanks to the guys that have put this together under the topic mapper. We really see what the community has come together to form a standard for all of the map is, and you can see there's a whole bunch of them. In fact, there's another table worth down here. The book of the Nintendo Games is the most popular in the West, are covered by, say, the first half of this table, and in fact, really the bulk of the games is covered by the 1st 5 or six mappers. I called mine mapper zero because it is the zero for entry in this table. So let's have a look at that. The nice thing about map a zero and the reason we've chosen to do it first is it doesn't really do anything at all. It is not a complicated mapper, but when you're looking at a map her for the first time, it's often worth seeing which games are compatible with this mapper. And you can do that by looking at this ness. Can't d be another fantastic resource created by the community. So here have listed all of the map a zero compatible games, and I should expected that the earlier generation games. But they include titles. We've been working with such a donkey cart me back to my click on Donkey Kong. We can see here I nez map a zero, and it gives us information about the rooms inside here. We've got the program run onto the character Ron, so by implementing mapper zero, we can see we're going to cover about 248 of the release titles now. This also includes all of the slightly more obscure Japanese titles that weren't available to the rest of us. But most importantly, for those at the developing emulators, your usual first goal is to get Mario Brothers up and running on Super Mario. Brothers indeed, uses map a zero. Now I'm going to spend a little bit of time on this first mapper, just looking at how to digest the information provided by the Wiki. The first thing you'll notice is there's lots of peripheral cases. Even though this is map A zero, it starts bombarding us with lots of different types of board information on the's. Airil ever so slight variance off map a zero because I'm trying to keep this Siri's as simple and as accessible as I possibly can. I'm not going to look at all of the specific details of every possible map of variation. Unfortunately, you don't have to to get the bulk of your games working. All of the map is have this little table at the top, and the important entries here are the program Rome capacity and window and character. Wrong capacity Window on. What this is telling us is that this particular board came with either a 16 kilobyte rahm or 32 kilobyte Romm for program memory, it says for the program. Rahm Window, don't that's not applicable and this is map a zero. It is the simplest mapper. This means there is no mapping. At the start of the slides, I showed a 16 K or 32 Kay Graham being put into the program memory, and that is exactly what we've got here. It then suggests that this eight kilobytes off character Rome and again there is no applicable windowing. Windowing is the technical term for mapping. There are a few other tidbits of information on here, too. Recall that are named tables are mirrored in a particular configuration, and on mapper zero games, this is fixed in hard work. Physically, the pins are soldered in a configuration that decides whether it's a horizontal or vertical mapping. There's other bits of information on here, too. On we'll look at those as the map is getting more sophisticated. And again, mapa zero is the simplest mapper, and the weak even highlights this forest. How do we interact with it? Well, we can't This has normally no mapping capability whatsoever, so let's have a look at our map. A zero. Well, it's a derived class that inherits from the mapper base class, and it must provide implementations for the reading right to the appropriate buses. Don't forget there's no way to configure this mapper. It really is very simple on its behavior could be inferred by how many program wrong banks were supplied by the cartridge here when the CPU attempts to read from the address boss in the program Memory range. If the cottage only provided a 16 kilobyte rum, then we mirror the address, effectively splitting the 32 kilobyte range into two identical 16 kilobyte program memories. If, however, we had two banks of program memory, remember, each one is 16 kilobytes. So a total of 32 kilobytes of program memory Well, then that maps directly into the CPU addressable range, where it expects the programs to reside For the peopIe You reading right? Well, there's nothing to do it all. We just directly past the address through these functions, take in an input address on the respective boss of the device that's calling them, and they return a map address. That's the corresponding address in the entirety of the Rome supplied on the cartridge. So when Cp Reed is called the mapper turns that address on the CPU boss into a physical address into the room on the cartridge on this physical address is then used to locate the required data in the program Memory vector. We created off that Rahm will come back to this bid later. The same applies for the right. The same applies for the peopie you read and write so thes functions in our mappers simply translate the local space address bus for the CPU and the people you into the address space of the larger rahm date of actors. I decided to make my map implementation also responsible for other bits of information that the cartridge would usually supply, such as the current mirroring mode. The PEOPIE, you in particular cares about the mirroring mode on needs to interrogate the cartridge to see what it is. And so I've provided this mirror function which interrogates the mapper to determine the mirror mode. But the map er might not always know what the mirror mode is, particularly in some simple mapper like map a zero, the mirroring modus specified in hard work. If this is the case. We simply return the mirroring mode that was defined in the i news file. Former Header. If the mirroring mode is not fixed, it is indeed software programmable. Perhaps, as is the case in some of the more advanced mappers, then will defer to the map to return what the mirroring mode currently is. I also included a reset function for the cartridge, which resets the mapper. This doesn't set the contents of any of the rooms, but it does reset the mapper to unknown state. And as we'll see, not all of the map is just get everything set to zero. Now you might think that the next mapper to look at is Mapa one, but we're going to jump over that one for a minute, straight into a map to a map. ITU is great because it's a very simple mapper to implement, but it is responsible for the mapping of some really cool games. And again, according to the Wiki, there's 155 games in total that use this map. Er, let's just interrogate the table to get some information. Firstly, we can see that it can have quite a large program wrong Now. Program rooms aren't just the execute herbal code that can also be all of the level data on sometimes graphical positioning data that make up the game. Therefore, as the game becomes more detailed and rich and complex, we would expect it to require more program wrong. We know that in the CPU addressable space, we have a total of 32 kilobytes of addressable program memory at any one time on this suggests we have 16 kilobytes, which is flexible, that can be mapped into any location within the Rome, but also 16 kilobytes. That's fixed, so this will always be mapped to a specific location in the rum. This is quite a useful utility tohave, because you could leave all of your system critical functions and start up code in this fixed region that never changes. It's never mapped out on, for example, load in specific level data one bank a time, perhaps representing each level. That's probably not how it's done, but conceptually it could be as and when it's needed. Like with mapa zero, there is no facility for mapping the character wrong. The eight kilobytes supplied in the room is directly mapped into the pattern tables of the peopIe you address boss map. ITU allows the program memory configuration to be set up in the following way. The program room can be very large. It could be a few megabytes, even all split up into 16 kilobyte backs. Regardless of how large this room is, The very last 16 kilobyte bank is always mapped to the top 16 kilobytes of the 32 kilobyte program address space. This is always the case. The lowest 16 kilobytes of the program. Memory can be matched to any other bank in the program wrong, and so the map needs to be instructed. Which bank is mapped into that space? This introduces the concept of the map. Er, having registers on, will see that most sophisticated mappers have more registers. But this very simple mapper just has the one on weaken right to this register by writing to any were in the 32 kilobyte program memory address, space of the CPU address, Boss on defectively. It's telling us that whatever the eight bit data value is that we write to anywhere within that range, that value corresponds to the particular bank number that were interested in. And so here's my implementation of MAPA to again. It just implements the interface of the base class, but it has to. Internal registers on the's are going to be the offsets in banks to the program. Rahm on the cartridge will start by looking at the CP right function because this could be used to to program the mapper. As you can see, we're sensitive to any address in the upper 32 kilobytes on. All we're going to do is take the bottom four bits of the data and assign that to the bank. Select low variable. In this case, Bank Select Low refers to whichever 16 kilobyte bank is in this first half of the address.