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

How to Code a 6502 Emulator in Python Part 16

Watch on YouTube

Video summary

In Part 16 of his series on building a 6502 emulator in Python, the developer focuses on implementing logic for the overflow flag, which is crucial for handling signed 8-bit arithmetic correctly. Unlike the carry flag that deals with unsigned numbers ranging from 0 to 255, the overflow flag applies to the range of -128 to +127 used by two's complement representation. The core concept explained is that an overflow occurs specifically when adding or subtracting two operands of the same sign results in a value whose sign bit flips unexpectedly; for instance, adding two positive numbers should not yield a negative result, nor should subtracting two negatives yield a positive one. The implementation process involves modifying the existing code for the ADC (Add with Carry) and SBC (Subtract with Carry) instructions to detect these specific conditions before they wrap around. The developer writes logic that compares the sign bits of the original operands against the sign bit of the final wrapped result, setting a flag if there is a mismatch indicating an invalid mathematical outcome within the signed range. This requires careful manipulation of temporary variables to preserve the initial state of the accumulator and the operand being added or subtracted before any arithmetic operations alter their values in memory. Throughout the coding session, the developer encounters several syntax errors and logical pitfalls while testing various scenarios with positive and negative numbers using Python's boolean logic. After initially struggling with incorrect assumptions about how specific combinations like adding 64 to another value should behave, he refines his code through iterative debugging until it correctly identifies overflow events in cases such as combining two large negative values or exceeding the maximum positive limit. Once satisfied that the detection mechanism works for addition, he copies this logic over to the subtraction routine with minor adjustments, acknowledging that while there is still one unimplemented instruction regarding bit manipulation, the core functionality for signed arithmetic errors is now operational.
Read the full video transcript
Okay, welcome to 6502 emulator in Python part 16. We're moving right along. In today's video, we're going to be working on the overflow flag. Um, which is very similar to carry, uh, which is, if you recall when we, let's say we have 255 and, you know, it's 8 bits. So, we have 255, we add one, uh, we carry the one, so we wrap around a zero and the carry flag is set. or if we're at zero, we subtract one, we wrap around 255, and we set the carry flag. We're doing the same thing here, but with signed 8 bit numbers. And I'll explain that in just a sec here. And there are two instructions I'm going to add this code to. There's actually a third, but I haven't implemented that yet. So, I'm just going to do the ones that I've already implemented. So, add with carry and subtract with carry. So, let's take a look at our code first. So, you know, previously we've been working on these different flags. We haven't done them all, but we've done we've done stuff with negative. So if a number is negative, we set the negative flag to true. Uh we haven't done overflow yet. We have that's what we're going to do now. We haven't done break or decimal. We have done interrupt. Um so we're but we have done zero and carry in just you know various places. So uh yeah, so we're going to be working on the overflow. So let's let's take a look at what that actually is. Um, so there's an explanation here on this page and it talks about the the overflow flag is generally misunderstood and um it goes through a bunch of stuff makes it a bit complicated to understand. But if you recall um from a while ago we looked at uh signed versus unsigned uh 8bit values. So 0 through 127 are just as you would expect. Those are the positive numbers from 0 to 127. But because we're using this last bit here to represent negative, so 0 is positive, 1 is negative. So 128 as an unsigned decimal is actually -28. Okay. So let's say that we have, you know, - 128 and we add 127, we're going to get -1. So we we haven't wrapped around. We we're going to we're not wrapping around. But if we subtract 127, uh obviously we're going to wrap around. Um you we subtract one, we're going to wrap around. Um so it gets weird just the way the the math works out. Um but basically that's what we're looking at. So instead of uh 0 and 255 being our boundaries, our boundaries are going to be -128 and 127. And there's actually an easy way to to figure out, you know, figure this out without actually having to do a lot of math. And that's why it's good that we have a second source uh here which talks about it as well. And so basically explains here uh how is signed overflow different from the carry flag and it talks about blah blah blah blah blah blah blah. But the important part is if the operins are of the same sign, the case may occur where the sign bit flips as indicated by a change of the negative flag while the result is still of the same sign. Um the condition is indicated by the overflow flag. So notably an overflow can never occur when the operins are of opposite signs. Huh. So what does that actually mean? So um to give an example here. So we load uh 40 which is here. Now notice this is set to positive. I should make that a little bigger on the screen. So dollar is 40. This is that's 64. So this is one. This is zero means we're looking at positive 64. We're going to add 40. So that flips over to here. That gives us 1. Now, normally that would give us 128. Uh, but because we're in negative territory now because we just switched over to negative uh what is that? I guess that's zero. Um, so 1 0 0. Actually, that flips over to -1 128 cuz I g 0 0. So the way to tell if I understand correctly from what it's saying is that if this bit is zero for this value and this bit is zero and the result is non zero here we've overflowed. By the same token if this is one and this is one and this becomes zero we've overflowed. That's my understanding of it. Um, so let's see if that works. Let's let's just let's just program it that way and hope for the best. Um, yeah, I'll have to test out some other systems to see if I got it right. But I think that that makes sense. So let's go ahead and look at the coding side of this. Now, as I said, it only affects the add with carry and the subtract with carry. So what I'm going to do is I'm going to add carry. And the thing is we need the original value and we need the accumulator value. Okay. So that says if the carry flag is set add one. I'm going to assume that's afterwards. Um okay. So this gives us a bit of a wrap. Um so that's interesting. How do we deal with that? Do we have to worry about that or not? I guess we don't because we are just looking at the overflow thing. So, let's go ahead and set overflow if necessary. And this may not be 100% correct. That's my current understanding. That was part of this project was to try to figure these things out. Let's go ahead and code it as if my understanding is correct. So, again, we've got value and we got self. A. So, um So we need to check. So we need if uh what's that? So value and um 128 that tells us if it's negative um and I think this is I'm going to try this. This is what we were told in the previous video by Ry. He said this should do what I won't do. So basically I'm trying to say is the 128 bit set which is the far left bit that tells us if it's positive or negative. So if it's negative and uh bull sorry yeah bull self a wait the value is negative no we need the self a okay so all right so we get the value here so it's the original value so I'm going have to make a temp value temp value for overflow overflow checking. Okay, so temp equals value. All right, so if cuz here we've changed the value. So we need to know if the temp is negative and the final value. We got to do this after wrapping. Um that's tough. Uh let's see here. H. Okay, let's try it. self. Wrap. There we go. Value. Notice we're not changing the value. We're just getting the wrapped value. So that that'll work. All right. That's that. H. All right. So, the first two. Okay. Jeez. All right. Um, I really should have Yeah, I'm messing this one up. So we need to know we know the original value of a the original value that we're adding and the result of that ad wrapped. Wow. Okay. So temp value equals value temp a equals self a. All right, there we go. Cuz here we're making some changes cuz we we calculate the value. We've added the value to self a. Yeah. And that gives us our final that's our final value. Okay. So, we got two cases. So, we're going to do pause pause neg. We're going to do neg pause. All right, let's try this. So, I'm doing a different order than I did last time. Okay. So if [sighs and gasps] temp value and 128 bool temp value. So if that's set that's no no let's do neg positive that's easier. Um, copy paste X. All right. Negative positive. All right. And 128 and B temp A. Um, and 128. So if that's negative and not not well bool let's try this try not bool self wrap self a uh selfv equals true because if I'm doing this right we have a negative number a ne so the value is negative a is negative and the result of a is not negative so whatever results is not negative and then it is not it is true that that means it's an overflow so by the same token in we should be able to do this if not bool not bool and b. So I just do else selfv equals false. Does that make sense? How about that? We'll do the we'll do else if here. Um like a little logic error there. LF. All righty. Get rid of that. So, negative and positive. Positive. positive and neg. Yeah, let's try it. I'm going to see if it compiles first. Okay. I've been programming too much Java lately. and and and and all right. I'm sure there's a much more elegant way to do this, but um why is that still red? Let's compile. Invalid syntax is it just not god. All right. If not pool um do a lot of Java lately. Is this going to work syntax? If pool All right, let's try this. Okay, compile. That's a good sign. Okay, so I already did some testing code. So, I'm just doing that example, that exact example. I'm taking 40 and I'm adding carry 40. Um, and then I got to actually No, I think no, I don't do that. That's all I got to do. Um, yeah, let's try it. See what happens. Okay, so we've got 64. Okay, notice the overflow is not set. We're going to add 64, which is going to push it to 128, which is going to give us that one in the uh leftmost column. And for heaven's sakes, not add carry. What I do tempus self. Okay, [sighs and gasps] let's try this again. All right, 64. We're going to add and negative is set, but the overflow is not set. Well, that's annoying. Um, all right, let's go back to the drawing board. Let's make sure first of all this is correct. So where's add carry immediate 069. All right, that's a good sign. Um let's go back to the command. So we have a positive positive No temp equals true. Ah, duh. See, Java would have caught that. I think it just did lowerase V. Yeah. Selfb. Why did I capitalize that? I probably always capitalize the literature. Um, makes sense. All right, let's try it again. Okay, 64. Now we have 128 and the V flag is set. Oh my gosh, I'm so happy. All right, I'm going to try a different value here. Uh, I just want to make sure that it doesn't go over. So, let's try two positive. Let's try a positive value. Um, so let's try 40 and 20. So, that's going to give us positive positive and it'll result in a positive of 60. Um yeah, is that positive? Yeah. Oh, maybe we'll find out. 96. No, it is positive. Okay, let's do one. Uh 01 should consistent that there. Okay, so we're going take 40. We're going to add one. So, that should just give us 41, which is not high enough. I'm annoyed. I'm officially annoyed. [gasps] Um, that should not overflow. That should be 65. Yeah, that's not overflow. Shouldn't overflow. All right, back to the drawing board. I'm making an assumption here that this is correct. I'm going to try and So printing do a little testing now. I I know I can do debugging and set break points and things but um See if this works. All right. False. False. False. Then why is overflow set [laughter] false? All right, let's try this again. Wait, wait, wait, wait, wait. Yeah, the logic is completely wrong. Okay. So, okay. So, negative negative. Oh, that was dumb. And 128. There are just days when I just feel like I should just give up. Do something stupid like that. All right, let's uh go ahead and put that in there. All right, it's already done that. All right, let's try this again. System. This is why I got to test it, right? Because we got we had a false, you know, positive there. 64 65 no overflow. Okay, let's go back and do one that we know gives an overflow. 40 and 64 overflow and negative. Awesome, dude. I'm so excited. Um, all right, let's try two negative values. Let's do um well, let's do Oops. Let's do the 0x 80. Let's do Let's do 80 and 80. 80 and 80. Okay. So, that should hopefully wrap us around to zero. So 128 128 gives us 256 which so yeah 128 is like you know negative whatever 128 I think and then 128 that wraps us around and we have the wrap so I think that is working as it's supposed to. So oops control Y. All righty. So that is that. Um, so basically what I can do is because it works the same subtract. Now that I got this working, I can just copy and paste it over to SBC, I believe. SBC. Where did I put that? Let's see here. SBC ADC. I put it after the carry thing. Okay. So, SBC. All right. And I do the same thing with temp ADC. Getting the value. Copy. All righty. Compile. Yeah. All right. Let's go up to here. Let's go back and find out what SBC is. E9. I'm going to go back to here. Here I'm going to do SBC and it's going to give us E9. Um the only thing is subtract is if we subtract two negative numbers. Yeah. Okay. Because it can't go. Yeah. We have to go over. Okay, that makes sense. All right. So we got we got a negative number and a negative number. and negative number and a negative number. 128 and that doesn't overflow. Oh, did I change that? Yeah. So, 80. Let's go back to the example over here and see if we can figure that out. 81. So 81's negative 127. Oh, let's add um let's see here. So he's right. Okay, let's subtract. Okay, that was that was good. 255 is still a negative number. So let's subtract 01. Crl + Z 126 which is a positive number. Uh, let's try F. All right, let me think this through. Um, let's go back to here. 128. Is it different with subtract? I do not know. Let's go back to here. I'll try again. can never go. Overflow may only occur if both operands are of the same sign. There's the same sign. All right, I'm just going to go by what this says and assume that I'm doing it right. I have to think about like a prop something something to test that because I don't quite get the math on it to be honest. But I am going to go ahead and say I'm going to put this in the wing column. It's uh video's long enough. So anyway, uh just back to what we did. Uh we looked at the overflow uh flag which is again similar to carry but relevant only to signed 8 bit numbers. We saw some examples there. reasonably confident this is correct and uh implemented only with add with carry and subtract with carry. There's one more command bit, but I'm not 100% sure what it does. I've read the instructions, but I got to read it again to be sure. So, yeah. Uh, making some progress getting into some of the harder nitty-gritty stuff. So, I hope you're enjoying this. Comment below, follow, subscribe, you know, the whole thing. Uh, you know what? And most importantly, keep on coding. Take care.