Submind YouTube summaries
Thumbnail for How to Code a 6502 Emulator in Python Part 17

How to Code a 6502 Emulator in Python Part 17

Watch on YouTube

Video summary

In this installment of the 6502 emulator series, the creator returns after a brief hiatus due to illness to tackle two new topics: implementing the BIT instruction and defining indirect addressing modes involving X and Y registers. The BIT command is introduced as being nearly identical to the previously implemented AND operation, with the sole distinction that it performs a bitwise AND between an operand and the accumulator without storing the result back into the accumulator; instead, its purpose is solely to update processor flags such as Negative (N) and Zero (Z). To achieve this in Python, the developer copies the existing logic for the AND instruction but introduces a temporary variable to hold the calculated value before setting the appropriate flags, acknowledging that handling the Overflow flag remains an issue for future updates. The implementation covers both zero-page and absolute addressing modes by adding corresponding entries to the command dictionary with their specific opcodes. The video then shifts focus to the more complex indirect X and indirect Y addressing modes, which operate exclusively within the zero-page memory range from 0x01 to 0xFF. These modes function similarly to standard indirect addressing but include an offset added either before or after retrieving a pointer address. For Indirect (X), the process involves taking a base value stored in zero page, adding the current X register value to it, and then using that resulting sum as an index into memory to fetch two bytes of data; specifically, the least significant byte is located at the calculated offset plus one relative to the start of the pointer block. The creator implements this by modifying existing helper functions to handle these specific offsets, ensuring the logic correctly navigates zero-page boundaries where necessary. Conversely, Indirect (Y) follows a slightly different sequence where the base address in zero page is first retrieved and interpreted as an offset into memory without adding Y immediately; instead, after fetching the two bytes at that location to form a full 16-bit pointer value, the current Y register is added to this complete address. This distinction highlights how X modifies the initial lookup while Y modifies the final target address derived from the data found in zero page. The developer proceeds to update the command dictionary with opcodes for LDA and other instructions that utilize these modes, carefully correcting an earlier mistake regarding opcode values before compiling the code. Although testing is deferred due to fatigue, the structural logic appears sound as it compiles without errors, setting the stage for future verification steps in subsequent videos.
Read the full video transcript
Okay, welcome to 6502 emulator in Python part 17 with Tokyo EdTech. That is me. If you've been following along from the beginning, uh I know it's been a bit of a gap since my last video. I've been kind of sick. Uh nothing serious, but just, you know, flu, CO, who knows? Uh off and on for the past couple weeks. So, you can probably still hear it in my voice. Anyway, let's get started. Uh today we're going to be taking a look at the bit instruction which is very similar to and it just has like one important difference that I know of and then we're also going to try and create the addressing modes for indirect X and indirect Y and they are a little bit different and you'll see that today. So let's go ahead and get started. Uh I'm not going to do any testing code today. Sorry. I just didn't have time to put it together and I just really wanted to get back on the back on the horse and ride here. So let's go ahead and take a look at bit. So I'm going to go ahead and I think I have it up here. Um so it says here it's very similar to the and command which we've already done. So the main difference is that the and instruction performs a bitwise and with the accumulator and stores the result back in the accumulator while the bit instruction performs a bitwise and with the accumulator but does not store the result. Um, it's just used to set the processor flags. Um, so basically what that tells me is I can just copy the bit command and yeah, I just copy it and just make a couple changes. Again, I'm not going to do any testing code. Just not in the mood, I guess you'd say. Um, so let's go ahead and find the and command here. And so I'm just going to go ahead and just copy this. And uh I think again there's still some of the the flag stuff is still missing but let's just go ahead and live with it. So I'm going to do bit and so basically what we're doing is we're going to still get the value like we did before and we need to do the the and now in the previous version uh this was compared to the accumulator which we're still doing but the result was stored back in the accumulator. So I'm going to go ahead and put a temp variable there. And then we set the N and Z flags based on that. So that should be all I have to do. Now, if I was looking back at the uh description here, it says I'm setting the NV and Z flags. So I think Oops. I think I'm only setting the N and Z flags. I'm going to deal with that some other day. Uh again, just trying to get move forward here and trying to, you know, push through this last part of the um uh of this, you know, this project that I've been kind of, you know, got a little derailed on. So, I do apologize. Reasonably confident this would work. Don't know until I test it. Um but let's just go ahead and make sure we throw that in there somewhere. So, let's uh find the bit command. And it only has two modes. So, I guess we can just go ahead and just throw that in there quick. Um, let's see here. So, let's go up to our commands. Scroll up instead of that. Yeah. So, let's just go ahead and plot this in here. And doop. And so, we're going to go ahead and copy that. And we're going to paste that twice. So, this one is 44. This one is going to be bit and the mode is zero page. All right, zero page. And the second one is 2C and this is also going to be bit. And the mode here is absolute. So it's really all we need to do to implement bit. Again, I know the V flag is missing. We're going to just come back to that some other day. Uh, I'm just going to be confident. I'm going to hit compile at least. See if it compiles. I'm going to call that a win. So, um, yeah, feel free to play around with that. And if you see any problems, let me know. Uh, the next part I think is a little bit more interesting. Um, is the addressing mode. So, we're doing indirect X and indirect Y. Uh, and they are a little bit different, at least based on what I've been able to find. So, let's go ahead and take a look at the description. And I found a really good description here on this website uh mass work and it has a really good explanation of it. So basically what it is it's very similar to zero page x u but because it's indirect um has a it's similar to the indirect mode actually but it's like indirect zero page x if you can think of it that way. Um so this instruction here this or sorry this chart here is really great. So let's say we have LDA uh $1.70X. Okay. So this this is a two byte instruction. So it's only going to work with zero page. So that's 0 to 255 the the first you know area of memory. Um so in this example we have A1 which is going to be the uh op code for LDA indirect X and then the value is 70. That's the memory location. And in this particular example X is five. So what we do is we add five to 70 that gives us 75. Then we look we take the value of the bytes that are at that location. So remember it is uh you know the most significant bite is second least bite is first. So the memory location is 3023. It takes the value in that memory location and adds it to the accumulator. In this case, LDA or okay, but the point is the value comes from the location plus X. Look that up. Get the data and put that into whatever we're going to do with it. So, the value comes from here. So, let's go ahead and see if we can implement that. Um, so first thing we got to do is create the mode here. So, I'm going to do indirect x equals auto. I'm just going to do indirect y while I'm at it, just since I'm here, so I don't have to keep jumping around. So, we're going to do that one next. And then I'm going to scroll down and in my get location by mode. Okay. Um, let's see here. Okay, get location. So, this is going to give us the location of where that is found. So, we're going to do l if mode equals mode uh indirect x. [Music] So, the location. Okay. So, I'm just going to go ahead and copy this um because I think this is going to help us. Um so, location is going to be uh location. Yeah, we're going to need that actually. U that's indirect. Uh actually, that's not the Okay, we're going to go jump back here. Um so, let's go ahead and How's this going to work? C++ one. Yeah. Okay. So, I'm going to use the zero page. Actually, it's I can just use zero page X here. Um because it's basically the same thing. So, I'm going to do the least significant bite is self memory self PC but + one. Okay. Now, it's zero page. So, I don't really have to do anything else. Um and then again, I'm going to add same thing here. I'm going to add the X to that. Now, in the zero page X, we would just get the value. That would be the memory location. Okay. However, um actually this is not quite right. Um okay, I got it. I think plus X. Okay. Okay, the MSB would equal L self.mmemory self.pc + 1 plus actually plus two. No, no, no, no. Plus one + one. Okay, I think that's right. I I'll explain this in a second. Um, so then the location is going to be this thing. Okay, the location and then that's where the jump address is. So it looks very similar to this. So I think that's one plus one. Yeah. Um yeah, that's correct. And then the jump I can just call this. So this not the jump, it's going to be the location. So now Yeah. So now we're going to change it to that second set. Yeah, that's it. Okay, we're done. Um yeah. Wow, that's pretty that's pretty pretty funky. Um so let me explain that um now that I think I figured it out. So if you remember, let's take a look at indirect. Um, so this is where we're jumping to a memory location that's stored in another memory location. So our least significant bite comes from, you know, where the instruction is plus one. That tells us the memory block um that that's going to be in. And then self-memory. Yeah. Um but in this case it's you know it's in the same section of the code but what this does is it tells us so we're going to get the one. So in the case it was 70 in the example and then it's 70 + one no 70 plus it's going to be plus two I think. And I got to think this one through here. Um, we need Yeah, cuz it's zero page. All right. So, I'm going to copy that again. And I should have done some testing code anyway. So it's self-memory PC + one and that's the location because the most sign by going to be zero because it's in the zero page. Okay, I'll I'll take that. Then the least significant bit of where we're going comes from this location which would be 75 in the example and then 76 which is that + one. Then we get the location the new location which is the the real yeah which is stored in the memory and then we go I'm happy with that. I think that's correct. Um if anybody watching at home says hey that's wrong let me know. Um let's go ahead and try and do why uh which is a little bit different. Um you'll see that you'll see the difference here uh in a second. So let's go back to here. I'm fairly certain this is going to work. I should have done some testing code, but except I'm a little tired today. I apologize. Um, so this is similar except that we look up the address first, then we add the Y. Okay, so with indirect X, you know, we were given location 70, we added five, took the two bytes. This would be 7576 and then we get the location from that um or we get the location. And then from there we get the you know we get the data from that location. Um in the case of y and notice you can tell because it's because of the way it's written. Um here the x is inside the parenthesis so it's applied to the memory location. Here it's outside the parenthesis. So it's applied to here the lookup value. Um so if we get 3543 we add 10. That gives us 3553. Again, I know I'm not dealing with, you know, kind of overflow stuff, but we'll deal with that's that's a problem for another day. Uh, yeah. So, let's go go ahead and just see if we can code that. Um, so basically what I'm do is I'm just going to copy this because they're very very similar. Um, I probably should comment this better, but have one of those days. So, this should be Y. And so, that gives us the memory location. And then actually that's not that's not what we want. The y doesn't go there. Once we get the location, we add the y location plus equals y. So we get the initial location. Uh so that in the example here what was it? Uh it was 70 as well. Okay. Then from there we get the least significant bite the most significant bite transfer that to the relative. So that's the location of where that points to that gives us this and then we add y to this location and then that's it. Um yeah that's it. Command S or control S. See if it compiles. It's a good sign. Um, again, I have haven't done any testing code, but I I think this is pretty close to what we want. Let's just go back real quick and see if we can find a command or two that has that. Uh, sorry, an instruction. I know I was I was chastised for using command. Um, but an instruction that has indirect X. So, what does L does LDA have that? That's always a good one to play with. Yeah. So, let's go ahead and just implement the LDA version of this. And uh then we'll call it a day. Okay. So, let's Where's our LDAS at? There we go. So, let's go ahead and pop that in there. Going to go ahead and copy this a couple times. And again, I know I should do some testing code, but uh it's just not in the card today. Again, I apologize. Um 44. Uh nope, sorry. This should be A1. Excuse me. A1 and B1. And this should be I didn't mess that up. Indirect X indirect Y. Yeah, I'm thinking about doing a whole video on just testing this uh thing, but uh haven't quite decided yet how far I'm going to go with that. We'll see. So, I'm not super concerned about the testing. Um, so yeah, that's that should do it again. Let's see if it compiles. That's a good sign. Um, I'm going to go back down here, make sure I didn't mess this up bit thing. So, let's go back and see if we can find bit again. Um, so it's 24 and 2 C because I think I used 44. Um, 24 and 2C. I should have known. They're so different. Okay, so those of you watching home that were like probably like, "Dude, you just messed that up." Um, yeah, I caught that hopefully here at the end. Uh, again, there's going to be a lot of like testing and verifying that this is doing what it's supposed to. Uh, yeah, that's that's a big project in and of itself. Uh, something I didn't think about when I started this. So, uh, going back to coding concepts, uh, what we did was we implemented bit, which is very similar to an. So, I was able to just copy and paste that code and just make the change where we didn't store the value into the accumulator. Again, I know I got to go back and do the uh V flag, I think it was. Uh but yeah, that's a problem for another day. And then the addressing modes, uh we talked about indirect X and indirect Y. Uh again, X uh is added before you get the data of the jump address or the you get the address that you're the indirect address you're referring to. And then in the case of Y, you get the address and then you add the Y to it. So um so the X in X it's applied to the zero page location in Y it's applied to the location that's returned uh from the data that's in the zero page if that makes sense. So uh yeah, thanks for watching and uh as I like to say, keep on coding.