Conditional jump instructions
Skills:
ML Maths Basics90%
Key Takeaways
The video demonstrates the implementation of conditional jump instructions in a microcode ROM, specifically the JC (jump carry) and JZ (jump zero) instructions, and tests them using various programs, including a loop that counts up and down and a multiplication routine.
Full Transcript
in the last video we built the hardware for a Flags register which we can use to track certain conditions like whether the result of an operation is zero that's what the zero flag is for or whether an operation generated a carry out of this last bit into the carry flag for example if we add two numbers and the result is more than fits and eight bits then we'd want to set the carry flag we also hooked up a control line to control exactly when we load a new value into our Flags register and that says flags in signal down here which is part of our control word we also hooked up the the output or really the current state of the Flags register we hook that around into two additional address lines of our microcode eproms that way what's going on in the flags register can influence the control signals that are coming out of the eproms so we can create instructions that work differently depending on what's going on with our Flags so let's actually create some instructions that use the flags register now this is the micro code that's currently programmed in the eeproms and remember that you problems are really just a big lookup table you've got some address lines going in and depending on whatever those address lines are set to you've got some particular output that comes out so for example if we look at our add command for this particular step we're saying if the instruction is zero zero one zero and step is zero one zero then this is the control word we get and you can see these three address lines here are the step they're coming down from the step counter over here and then these next four address lines are the instruction and you can see that coming from the instruction register and so if all of those are set like this then we want this control work of course this control word is 16 bits so we've got two eproms and I'm using the 8th address line to tell one EEPROM you give me these 8 bits and tell the other EEPROM give me these 8 bits well used to be 7 bits before we added the flags register and you can see that 8th address line here it's just hardwired low on this EEPROM and high on this other EEPROM and that just lets us program both eeproms identically so now we're adding two more address lines for our flags and that's going to change what our lookup table needs to look like so here's a copy of that lookup table where I've added the carry flag and the zero flag now because our control word is now going to depend on the instruction the step and the flags now most cases you don't see you see the flags don't matter and we want to do the same thing regardless of whether the flags are set or not in fact all of the instructions have got so far like that because we haven't had these flags until now but I've added two new instructions jump on carry and jump on 0 here they do make use of the flags so jump on carry for step 2 0 1 0 if the carry flag is not set then none of the control signals are set yeah we don't want to do anything but for jump on carry a step 2 if the carry flag is set then this is the control word we're doing instruction register out and jump and this is the same thing as just a normal jump instruction and of course that makes sense at the jump on carry instruction would do what a normal jump instruction does only when the carry flag is set then for steps 3 & 4 regardless of what the flags are set to we do nothing and that's just because we don't need to do anything else for or jump in any case jump on 0 works the same way except in this case whether we do the jump or not depends on the zero flag rather than the carry flag it's one other change I made here which is I added this last column here for the new flags in signal ya before this this extra bit wasn't used and it was always just zero but now I want to have it set during the last step of the add and subtract instructions because it's at this point when we've just done our addition or subtraction and we're taking the result and putting it back in the a register we also want to update the Flags register to match whether that result was 0 or had a carry now in all these situations where we don't care what the carry flag or 0 flag are you know all of these X's here it means we need to have the same thing programmed in the eproms in each of the different possible combinations so that means we're going to be using a lot more of the EEPROM memory in other words we look at how this information is mapped to memory addresses in the eproms it looks something like this right now so a 0 through a to tell us which step of the instruction cycle we're on the next four bits a3 a4 a5 and a6 are the opcode of whatever instruction we're executing that comes right from the instruction register and then a7 is this address line I'm calling byte select which tells us which eight bits of the control word we're getting out if it's a 0 then we're getting the first 8 bits and if it's a 1 then we're getting the last 8 bits of the control word that's why to get 16 bits at the same time we've got two of these eeproms and the programmed identically and then a7 is just 0 here and it's 1 here they're just hardwired so that's what's programmed there now we've got all the opcodes 0 through 15 and then for each of those opcodes we've got the steps 0 through 7 and that's for the first half of the control word and then we just repeat that again for the second half of the control word and so that goes from address 0 all zeroes here up to address 255 we've got 8 ones here but now we also need to handle all the combinations of this carry flag and the zero flag so that actually means we need 4 copies of this the one we've got one with the carry flag set one with the zero flag set and then one with both flag set and for the most part these 4 copies will be pretty much identical because for the most part the control word it really doesn't depend on the flags but there are these two places where we do want it to depend on the flags here and here and this will let us do that now you might say it's you know maybe inefficient to take up four times as much memory and the EPROM is just to handle these these two little one-off cases and fair enough you know if you want to minimize the size of the eeproms that you need then you know this might not be the solution for you there's probably other solutions that you could come up with that would be better to achieve that goal you know but that's the deal with engineering you're always making trade-offs you know it's virtually impossible to come up with a perfect design that's going to optimize every variable especially when you consider that the cost of the time that you spend cooking up that perfect solution is also something that you probably want to minimize but but my goal for this is really just to be flexible enough to tinker with and easy enough to understand and hopefully I've done ok on that ok so now let's take a look at actually programming as eproms so I'm going to use this Arduino based EEPROM programmer that I came up with in a previous video so if you're unfamiliar with what this is or how it works check out that other video here's the code from that from before and I'll start by making a copy so we can hang on to the previous version now that way it'll be easier for to find the code for anyone watching those previous videos and the first thing I can do is pretty straightforward you know remember we added another control signal to the control word for loading the flags register so I can define that flags in signal as using that final bit of the control word and then we're using that flags in signal here on step 2 of the add and subtract instructions and so we can just add Fi to that step of add and subtract and now fix up all the spacing I'm sure it's not gonna work right if everything doesn't line up perfectly there we go now could this nice representation of our micro code here but like I was talking about before we basically need four copies of this you know slightly tweaked now I could just copy and paste in this array just these 16 lines here you know 4 times and just end up with a big long list of 64 lines that you know repeats mostly the same thing but you know I worry that that's just kind of asking for trouble if you know if the four copies get out of sync in some subtle way by by accident you know there'll be a real pain to chase down what's going wrong so instead what I'm going to do is use what I've got is kind of a template and have the program make four copies of it now that way we can explicitly make just a few tweaks that we want to each of the four copies and know that the rest will be the same so what I'll do is define an array of arrays to hold all four copies and then what I'll do is I'll rename this data array here to make it clear that it's the template and then I'll define a function to initialize that microcode array and basically what I want to do is just copy that template into the micro code array four times and so this is taking this template that I have here this micro code template and just making four copies of it in these four spots in this micro code array and the first copy is for when the zero flag and the carry flag are both cleared next is for when the carry flag is set then for when the zero flag is set and finally for when both the zero flag and the carry flag are said I'm also going to change the way that this array is defined to be a little bit more structured so rather than being just kind of a flat array of I think is 128 control words is what this works out to be rather than just being kind of flat array of 28 control words what I want to do is change that to be an array of 16 instructions up to 16 instructions and then each of those instructions will be an array of 8 control words so it's going to look pretty much the same but what I'm going to do is each of these instructions will be an array of eight control words and then the overall template will be 16 of those instructions so I'll go ahead and just add all these extra braces here and you'll see why I'm doing this here in a minute basically is just going to make it easier to get at a particular value if we know the instruction in the step and then another sort of cosmetic thing I'll do is just define some constants here to make it more clear what the different combinations flags are so this is just the different values of the flags then I can come down here and replace these sort of zero one two three with those constants to make this a little bit more clear and I think that makes it just a little more explicit what's going on with the microcode array you know I know I've already got comments here but I like making the code itself as self-explanatory as possible since I found that comments don't always tend to stay up to date and you know there's nothing that it forces that the comments are correct so now of course we've got to go and call this initialization function so I'll go ahead and do that down here at our sort of entry point here and setup so just when we start off we'll call that function and then for the actual programming here where we're programming the EEPROM you know since we've changed around the data structure so much I think it's probably gonna be easiest to replace most of this code that that's writing to the eproms so what I'm gonna do is rather than splitting this up into the two loops here the four the eight high order bits and then a low order bits I'm just going to collapse this into one loop that goes through the whole address range so I'll get rid of one of these loops and so the whole process from when we start programming that you prom to when we're done will just be this one loop and if we're going through the whole address range if we go and look at how our EEPROM memory is laid out and we want to go from where all the bits are zero so from address zero all the way through all of these up until we get to where all of the bits are ones and so we've got ten bits you have ten bits of one's is a thousand twenty-three we can also check that by doing two to the power of ten because we've got ten bits and that's a thousand twenty-four so there's a thousand 24 combinations that you can get with ten bits so we'll loop our address from address 0 up into 1024 okay so when we get to that address when we write to the EEPROM at that address what is it that we want to write well we want to write that microcode value that we generated here when we initialize things and so that microcode go back up here where we define that it's an array with four values in it so the first index into that array is going to be the flags then the next index into it is going to be well into the into the template that we copied in and so actually maybe what will make sense is since this template is an array of 16 instructions each with eight steps I can make the microcode an array of four flags values each with 16 instructions each of those instructions with 8 steps so we've got flags instruction and then step so when we're writing that out to the EEPROM we're writing to each address in turn from that our microcode the correct value for a particular Flags value a particular instruction and then a particular step but how do we figure out what this Flags value this instruction value or this step value ought to be well we should be able to figure that out from the address or well we're in this loop that's going through all of our addresses from 0 all the way up to 10 23 so we're going through every possible value of address and our address is broken up you know by bits so if we look at just three bits of that address value we can figure out what step we're on if we look at just these four bits we can figure out what opcode we're on if we look at just these two bits we can figure out what flags were on so what we want to do is when we get into this loop we want to look at this address and from that address we ought to be able to compute what Flags value were at what instruction we're at and what step we're at so the flags that's going to be the first two bits of the address so we're looping through this whole thing and then we're going to start at 0 1 2 3 4 5 as we loop through our addresses and we just want to look at the first two bits so to look at the first 2 bits what we can do is we can do a shift write operation so we have 10 bits here if we shift all of this to the right by 8 bits then the only 2 bits that we'll have left are the first 2 bits over here they'll be shifted all the way to the right and everything else will be 0 and so those two bits that we've shifted will be our flag bits so we can take to sort of figure out our Flags we can take address and shift right 8 bits so that's Flags and so that'll get the right Flags value for this particular address how about instruction well instruction is our opcode here and so opcode is these 4 bits and we could do the same thing we could shift right well in this case three spaces and that would that would get our opcode over here to the right and then the value of the of those four bits then would be the opcode but we might have some other stuff over here we might have our our byte select we might have our Flags what we can do is we can use a bit mask to just pick out those four bits before we shift them over so here's what I'm talking about so if we take our address and we and it with a binary value of 0 0 0 1 1 1 1 0 0 0 basically what we're saying is if there's any bits in our address in any of these places that are zeros since we're anding it with a 0 we're going to get a 0 no matter what if there's any bits in this address that are either a 0 or a 1 we're gonna get that same 0 or 1 when we end it with a 1 and so what does it going to effectively do is if you take an address any value anywhere in here and you and it with that with that binary value what it's going to do is it's going to zero out everything but the opcode so once we've zeroed that out what we can do is we can shift that to the right and then we'll be left with just the opcode as a number from 0 to 15 so if we take this address ANDed by this bit mask we can shift right by 3 and that will give us our instruction as a number from 0 to 15 as to which which instruction associated with that particular address and then we can do the same thing with step so step is going to be our address and in this case step is already shifted to the right I mean it's it's just these first 3 bits over here on the right so we don't need to shift it anywhere but we do need to kind of zero out the rest of the bits and so we can do the same thing with an and so we can end this by all zeros and then three ones and those three ones will preserve the last 3 bits of the address here and give us the step and it'll zero out the rest of that even if you know we get it get into here where not all of these bits are zeros it'll still 0 the Mount and we'll just have our step from 0 to 7 so I can actually clean this up a little bit make things kind of line up and the other thing I could do is actually with the flags we're shifting this all the way to the right but for consistency what I can do is I can also say we're going to zero out all but those two bits and that again it just sort of makes the code more readable so if we say address and those first two bits and then the rest are 0 and we shift right to the 8th that doesn't really do anything because when we shift right to the 8th we lose all these other bits anyway but it does make it more consistent here and you can see ok the flags are the first two bits the instruction are these four bits and the step are these last 3 bits and that's you know consistent with with what we see here but of course we've forgotten one bit there which is our byte select and so that suggests that maybe there's something missing in our code here too and in fact is because when we write our micro code value here remember this micro code value is a 16-bit value and the EEPROM is only going to look at the least significant 8 bits of that and right now because we're ignoring this byte select we're gonna be writing only these least significant 8 bits to every value whether the byte select is set or not so to fix that first what we want to do is figure out you know if we're on an address where the bytes like this is set so so we can do byte select equals and it's gonna be the same pattern here and of course will be this bit that we don't match yet and so now you can see we're matching all the bits the first two bits are the flags the next bit is the byte select the next four bits are the instruction the last three bits or the step and here we want to shift right as well the byte select is here we want to shift that all the way to right so that's going to be seven places to the right and so now that we have our byte select what we can do is depending on whether the byte select is set or not so if it's set what does that mean so byte select you can see that set here on the chip on the right and so when that's set we want to get these bits on the right here which are the least significant bits so if byte select is set then what we want to do is write out the last eight bits of our 16-bit word here so so if we actually just do what we're doing here we're writing the value that we get from the microcode this right eeep ROM is only going to take eight bits anyway so it's just gonna it's gonna chop off the first eight bits like this and we're gonna be left with with what we want so what we want to do is when byte select is not set so the other case here else we want to do the same thing we want to write to the EEPROM but we don't want to write these eight bits we want to write the top eight bits and so what we need to do is we need to shift them over eight places so we shift right eight and that'll shift all 16 of these bits over to the right here and we'll lose these these lower eight and we'll just be left with the high eight bits here and that ought to give us what we want and so I think this ought a program all thousand 24 bytes of our EEPROM correctly and then we print done and then we print the contents of the EEPROM and actually I think here when we print the contents we're probably not printing enough to see everything that we programmed yeah so if I find our print contents here to see we're going from 0 to 255 but maybe this should be 1024 but actually what I'll do is I'll just give it a length and then we can pass that in and in fact we can give it a start point too so this print contents will now take a start in a length and print however much we want so here I'll just say start at address 0 you can't give us a thousand 24 bytes so that should print the whole thing so let me try compiling this and see what mistakes I made okay well that's supposed to be flags you probably were all screaming at me when you saw me type that and we're missing a semicolon and it's compiled but I'm getting this low memory available and that's because the the Arduino Nano has only got two K of memory which is not a lot and we're using a lot with all of this data that we're we're now we've gone out got in here for not only our template but also all of the copies for the different flags values and so this is just warning us that we're using a lot of that memory now the Arduino has got some different types of memory so the atmega 328p is the arduino chip that we're using and it's got two K of SRAM but it's got 32 K of flash and so if you've got data that you don't need to write to you don't need to modify it's just gonna stay the same throughout the entire program you can actually put that in this flash memory to free up some of this SRAM and so in our case we've got the template here and we never modify the template we modify this micro code right because we copy things from the template into it and when we add some exceptions here we're gonna be changing some things in the you know in this micro code here but we're never changing the template itself so what we can do is we can actually put the template in flash which is which is called program memory rather than rather than loading it into the SRAM when the program runs and that'll save well sixteen times eight and these are 16-bit values so that'll be 256 bytes which it has a decent chunk of this 1598 that we're using so to put this into that flash memory that program memory you basically just preface this with Const program for a program memory and that'll store this in that flash rather than loading that into the limited SRAM that we have of 2048 bytes although there's one big gotcha with this which is if we're copying from program memory into s which we're doing here with this mem copy you've got to use a special version of em copy so you got to do em copy underscore capital P - to use the Arduino version of mem copy that will copy from program memory so if we don't do that we're gonna find these mem copies don't actually work so now let's verify this and now it's compiled and you see we're using less memory and we're not getting that warning anymore and of course I do need to add you know the jump carry and the jump zero instructions that's the whole sort of whole point of what we're doing here but before I do that what I'll do is just test out what I've got so far before we add anything more complex to it just to make sure I haven't broken anything yet so I'll pull these eeproms out so we can reprogram them and then I want to put each one into the EEPROM programmer here and hook the programmer up to my computer alright so what I'll do is open up the serial monitor yeah and it looks like it's already programming because I guess it had some old code in there from before but anyway we'll give this a go and try uploading our code to the Arduino see there it's writing that's good and there it goes so now it's programming and it looks like that got everything in there this is sort of weird that this last row is all FS oh it looks like actually or maybe we're just reading too many because 4 0 0 would be 1024 and so this would be 1025 1026 or reading past what we want to use let's just see if we haven't off by one error somewhere oh yeah here we go so we're saying base less than or equal to length I think we just want to say base less than length because we're passing in 1024 it'll just re-upload and rerun that not that it really matters it's just cosmetic but it's nice to see everything working the way it should ok and there we go and so this is 10 23 3 FF but that looks good so that's one EEPROM I'll pull that out and I'll stick in the next EEPROM this is where it's nice that these are both programmed the same you just pop the other one in and program it the exact same way so I think I'll just reset this and it ought to rerun the programming code yep and there it goes yeah that should program the second you prom the same and there it goes and now we've got them both programmed so let's test it out and see if it still works pull that out and then I'll pop both of these back in where they long it'll power it up reset and everything looks good it's now just to test things out what I'll do is put in a simple program that just counts by tens okay that's what I've done is just put in a simple program that doesn't add from address 15 I've got a 10 in address 15 so it adds 10 and then it will output the result and then it will jump back to zero so that's what we've got programmed in here so let's reset and let her rip and there goes it's counting by tens so clearly we have not broken things too badly and the reason I counted by tens is because then we should see the carry flag when it flips around past 255 so let's wait for that 20 30 40 50 and then the carry flag is set and it keeps going so that's a really strong indicator that this is working well because if the carry flag is on and the computer continued to execute instructions properly that means we must have the same instructions set up in the other parts of the eproms that are addressed when the carry flag is set so now I'm pretty confident that we've got things working well at this point now obviously I can do a lot more testing right now but I am going to push on and add the conditional jump instructions and the way I've set this up hopefully would be fairly straightforward to add those conditional jump instructions because essentially what they are is they're exceptions to this copy right because what we've done is we've just taken this template and we've copied it four times so we're doing the same thing no matter what the flags are but in these cases where the flags are different then we can do something different by just sort of adding some exceptions here so I'll show you what I mean first what I'm going to do is define some more constants just to kind of make things again just make the code a little bit more self-documenting and the first constants I'll define are for the jump carry and jump 0 just mapping the memnon ik to the binary value for those instructions and I'll actually spell out the full binary value here just because we've been looking at everything else in binary ok now we've got those defined and the reason I'm doing that is just kind of make things a little bit more straightforward when we define our exceptions so we're gonna add you know a couple op codes here for our jump carry and our jump 0 so jump carry is going to be this 0 1 1 1 and jump 0 is going to be this 1 0 0 0 opcode and so for jump carry and jump 0 you know in the case where the flags are all zeros so here we're at zero then basically all of the steps are zeros so I'm gonna leave it that way in the code here so right now these are just all zeros so there's essentially no ops but where they're not going to be zeros is in these cases where the appropriate flag is a 1 and that's where we have these exceptions and so the way we can define those exceptions is after we made the copies of our templates here we can add these exceptions and so in this case here for example for jump carry when the carry flag is 1 basically what we want to say is that for the carry flag is 1 on step 2 right this is step 2 of jump carry when the carry flag is 1 then we want this to be our control word right we want our instruction register out and jump so what I can say here is I can say after we've made that copy I can say microcode and so this is going to be flags where the the zero flag is 0 but the carry flag is 1 so in the case where the carry flag is 1 for that instruction so the instruction in this case is going to be jump carry whoops jump carry and step 2 so in that particular case then what I want the control word to look like is I want the control word to say instruction register out and jump which is going to put the contents of the instruction register into the program counter so this is just kind of our exception so it says when the carry flag is 1 and we're on a jump carry instruction and we're at step 2 then this is the control word and that just overrides what we would have here so what we would have here is if our instruction is the jump carry instruction that's here and we're on step 2 so this is step 0 step 1 so step 2 currently have nothing and so normally we would want nothing but in this one case where we have the carry flag set then we actually want to do that jump so that that gives gives us a way to sort of you know easily have a sort of an override I guess for for when a particular flag is set we basically want to do the same thing for when the zero flag is set so when the zero flag is set zero flag is set carry flag is not set on our jump zero instruction on step two we want to do the same thing we want to actually do the jump so instruction register out and jump and then for this last case here where the zero flag is set and the carry flag is set we also want to do our jump because you know we might have a case where we're doing a jump carry and the carry flag is set but the zero flag also happens to be set so we want to do that and then same thing here the zero flag is set we don't really care if the carry flag is said or not this is zero flag is set carry flag is set for a jump carry on step two we want to do a jump and then zero flag is set carry flag is set for a jump zero on step two we want to do a jump and so I don't know you may or may not like the way that I've written this and that's totally fine you can choose to do it your own way if you want to but I think this is a fairly compact way of defining kind of a template for the sort of normal case where we don't care about the flags for each instruction and then if we have an instruction where we do want to do something different for the different flags then we have kind of a spot here where we can fairly clearly say what we want to do so if the flags are in a particular condition and we're on a particular command then on a particular step we want to do this this different thing that's different from our template so I don't know I think that makes sense to me but again with engineering there's many ways you can do the same thing and it depends what you're going for I think at least the way my brain works this this is a pretty clear way of defining these things so okay let's reprogram our EEPROM so disconnect power here pop these guys out stick them in the programmer yeah I'll go ahead and upload that and it's programming the first EEPROM and there it goes and I could pick through this and try to find the particular exceptions and things that we programmed in there but you know I'm feeling adventurous so I'm just gonna try it out and write a program that uses conditional jumps and see if it works but first we'll program the second EEPROM here pop that in yeah and if I just hit the reset that auto reprogram that one okay there we go so let's pull that guy out put it back and what looks like the right spot and so now let's power that up and give it a try stop that reset okay that looks good at least as a initial sanity check now I suppose we probably ought to write a program that uses a conditional jump so I want to write a program that uses one of these conditional jump instructions and so what I'm gonna do is I'm just going to start with an output so output whatever is in the a register and you know when we reset the computer it's just gonna output a zero then what we'll do is we'll add something to that I'll add 15 and I'll just put a 1 in address 15 so an address 15 here I'll just put a 1 so we'll add 1 then what I'm going to do is jump back to zero so I'll say jump back to zero so what this is going to do is just going to keep adding one and outputting results are just going to count what I want to do is when it counts and it wraps around so if I add this one in it and it we get a carry so I'm gonna do a jump carry then I want to jump down past this loop so I wanna count up until we wrap around and then I want to do something else so I'm gonna do a jump carry see this is gonna be addressed to address three so address four I'm gonna jump carry to address four otherwise I'm going to jump back because remember that if there isn't a carry from this addition this jump carries is gonna be a no op it's not going to do anything so we're gonna loop and add 15 output the results we're just gonna count up until we wrap around when we wrap around we're gonna come down to instruction 4 and now what I'm gonna do is I'm actually gonna start subtracting so I'm going to say subtract 15 so what I basically want to do is count up and then start counting down again so I'll subtract 15 and then output that result and Lybia address 5 and then after I output that result basically wanna keep looping in this subtract so I'm gonna I'm gonna loop around adding 1 and counting up and then if we if we wrap around then I want to jump down to address 4 and I want to create another loop down here and that's going to loop around subtracting 1 each time until we get to 0 so now I can do a jump 0 and if we get to 0 then I will just want to go all the way back up to the top and start over again so that'll be on searching 6 instructions 7 will be that but if if we haven't gotten to 0 yet then I want to just continue in this loop where I'm subtracting so I want to jump back to address 4 and so you can see I've created these two loops here right so there's this jump 0 that loops back to address 0 there's this jump for the loops back to address 4 and so there's these two loops where I'm just outputting and adding and here I'm outputting and then subtracting or subtracting and outputting but then I have these conditional jumps so if we have a carry from our addition so we've we've maxed out our 8 bits then I jump down here and if we get to 0 and we're subtracting then I jump back up here so hopefully that makes sense so basically if this program works then what we're gonna do is we're just going to count up from zero to 255 and then count down from 255 back to zero and then count up again and just keep doing that and so I think this will be a good way to test the jump carry and the jump zero instructions and see if they work and this is also a program that we couldn't have done before on the computer without a conditional jump instruction of some sort okay so I'll go ahead and put this program in you know here's my cheat sheet so I can see what the binary is for each of those commands okay so I think I've got that all programmed in and just to show that a conditional jumps so we've got a jump carry yet address too so let's go to address to make sure that one's right and jump carry is 0 1 1 1 so that's that and this is 4 right 1 2 4 so jump carry four in address 2 and then we have a jump 0 in address 6 yeah jump 0 is 1 0 0 0 1 0 0 0 and we're jump we're jumping if 0 to address 0 it's confusing and then there's the 0 there so let's let her rip okay and there it's counting very slowly I'm gonna speed up the clock here and there it goes counting up and so hopefully when it gets past 255 we'll see the carry flag blank there and we'll see it start to count down again almost there and there we go and now it's counting down and so we're now we're in this bottom loop where it's subtracting outputting and then if we get to 0 then it jumps to the top and start adding again but we haven't gotten to 0 yet so it's just going to keep in this loop down here subtracting until it gets to 0 and we'll see the zero flag flash and now it's back in this top loop again so it looks like our jump carry fly or jump carry instruction rather and our job 0 instruction are both working or so it would seem so that's exciting what else can we do with it you know how about multiplication you may recall that I mentioned in my previous video and turn completeness that a conditional jump instruction was the key to being able to compute anything and that certainly includes multiplication now a few people found a clever workaround to doing multiplication without conditional jump using self-modifying code I think the first person to post about it was Matthew over on patreon where of course all my cleverest viewers hang out and he also wrote a really good description of how it works so I would definitely suggest checking that out but if you do you'll see that it outputs intermediate values before it gets to the solution and there's also no way for it to do anything but halt once it's found the solution so I don't know that it's a pure multiplication function but it is extremely clever given the constraints of not having conditional jump instructions and considering I said this give it a try look at these instructions see if you can write a program but I don't think it's possible I think it's pretty cool that a few of you proved me wrong so thanks for teaching me something but anyway now that we've got some conditional jump instructions yeah let's look at writing a multiplication routine that doesn't have those side effects it's the way I like to think about writing a more complex program is to start by writing pseudocode to come up with a general algorithm and then refine from there into the actual machine language so if we want to write a program that multiplies two numbers let's start with some variables you know let's say x and y are the numbers that we want to multiply and then product is going to be the result so of course the challenge is our computer doesn't have a multiply instruction but it's got an add instruction and multiplication is really just repeated addition so here's this algorithm that I came up with and the bulk of it is this loop and the goal is to go through this loop x times at the beginning we start with product equal to 0 and then each time through the loop we add Y to the product and also to make sure we go through the loop exactly x times we subtract 1 from X each time through and then stop the loop once X hits 0 so in other words if product starts as 0 and we add Y to it x times then product is going to end up equaling x times y and then we can just output the the answer down here at the bottom so that's all well and good but how do we actually do this loop until X is is 0 thing we've got to jump 0 instruction what seems like it might help but remember that our conditional jump instructions depend on the flags that are set only after an addition or subtraction so we want to check whether X is 0 we've got to do it after an addition or subtraction from X and right now the only arithmetic we're doing with X is right here this subtract 1 ok so fair enough what if we do a jump at 0 right after the subtract command here you know and jump down to the bottom where we output our product and then we're done with our loop well maybe you see the problem with that you know we'd have an off by one error because we want to check if x is 0 before we tract one not after there's a couple things we could do one is we could put an ad zero right here that wouldn't change X but it would update the flags register then we could do a jump of zero based on the original value of x before the subtract that's one thing we could do it would take an extra instruction but you know that's not the craziest thing in the world the Intel x86 processors had a compare in instruction that was designed to set the flags before doing a conditional jump basically the the compare instruction does a subtraction and then throws away the result but it updates the flags so you can see here it says the comparison is performed by subtracting the second operand from the first operand and setting the status flags in the same manner as a subtract instruction so I bet if you've been following along with this series of videos you could probably figure out how to implement a compare instruction like that on our computer so that's an option if if we want to use the jump zero instruction but as I mentioned in my video on turing completeness in order for a computer to be turing complete we only really need one type of conditional jump instruction so that suggests that it's possible to do this with a jump carry instruction somehow and it turns out that it works out quite nicely so let's think about what happens with the carry bit when we subtract one so we actually negate the one to get negative one and then really what we do is add negative one to two x in this case so what does negative 1 look like in binary well if you're not sure how negative one is represented in binary you might want to check out my video on negative numbers in binary because it turns out negative 1 is represented in binary as all ones so in other words it's the same as 255 so it's actually subtracting one from X is exactly the same as adding 255 to X and again if that doesn't make sense check out that video on negative numbers in binary so what happens to the carry bit when you add 255 to something well a carry bits gonna get said any time the result of an addition overflows says if it's more than 255 well it's gonna happen if you had 255 to anything well anything except 0 so I think about that for a second after we subtract 1 here the carry bit will always be set unless X was zero before the subtract so bingo a jump on carry after the subtract will know whether X was zero at the beginning of the loop or not so does a show that it's possible to write this using either jump zero or jump carry so now I can rewrite the pseudocode to be a little bit closer to what we would program the computer with although I'm still using variables and I'm using labels to sort of suggest where we're jumping to rather than filling in all the addresses just yet but now we've got the jump carry instruction here like I talked about and we can walk through this to see if it makes sense so let's say we're multiplying 3 times 5 so X would be 3y lb 5 and products is gonna start out at 0 so we start by loading X which is 3 and a subtract 1 from it and when we do that the carry bit will be set because when we subtract 1 from anything but 0 the carry bit will be set so the jump carry it jumps down to continue here then we store X which is now to load the product add 5 to it and then store that then we go back to the top next time through is the same X is 2 we subtract 1 from it the carry bit will be set so we continue down here update X which is now 1 and add 5 to product and store that so now product is 10 then we go back to the top now X is 1 we subtract 1 again the carry bit is set so we continue down down here we store X which is now 0 add another 5 to product so now product is 15 and then we go back to the top this time though we subtract 1 from X which was 0 but when we subtract 1 from 0 the carry bit isn't set so this time we drop into this code here and here we load up the product which is 15 output it to the display and then halt and there we go we multiplied 3 times 5 and of course we could do other things here other than you know instead of halting so unlike that clever workaround that a few of you came up with here we could theoretically jump somewhere else we could execute more code or continue on with our program so finally to take this to the next step this is what the completed code would look like for for this program and really all I've done is substituting actual memory locations for for the variables so instead of saying load a X now I'm saying load a 14 and 14 is the address where where our x value is going to be and here where I said subtract 1 well well the way the subtract instruction works is it subtracts a value from memory so now we've got subtract 12 and then we've got a 1 sitting in memory address 12 and instead of jumping to labels like you know continue or top I just filled in the actual addresses so the jump carry six or jump zero so this is what we'd actually need to program into the computer and if I convert all those instructions to to binary these are the actual ones and zeros I've kind of toggle into the dip switches and of course we'll just need to fill in the X&Y value to whatever numbers we want to multiply all right well let's see if this thing actually works I'm gonna go ahead and program this thing in so I'll just go through each address one by one and put in the binary machine code for each instruction and I'm sure I'll speed all this up so you don't have to watch me do it in real time all right so everything's in but we still need to initialize our product x and y values and so I've already got zero put in for the product and so then X and y are going to be the two numbers that we want to multiply so if we want to do that same example of three times five then we can put that in so in address fourteen we'll put the three so that's the three in address fourteen and then address fifteen we'll put five and so that'll be three times five and then the product is going to is going to be put in address 13 and that's initialized with 0 which is which is where we want it to start so let's give this thing a try if we go back into run mode we're already reset if I start the clock this ought to run the whole thing and output the result of 3 times 5 on our output and then halt so let's let's give it a whirl hey and there it goes 15 and it halted so that looks like it's working perfectly it's now if we want we can try multiplying two different numbers maybe give it a little bit of a harder problem and so again we've got to initialize our variables so our product now has got a 15 in it right because we just ran the program and got 15 so we need to initialize that back to 0 before we start and then x and y of course are gonna be the two numbers we want to multiply so let's make X 7 and Y we'll make 8 seven times eight is a nice hard multiplication problem right and so we'll go back into run mode reset and start the clock and we should get seven times eight 56 I think that's right and so there we go we do implemented enough of an instruction set to be turing-complete now with only 16 bytes of RAM the computer is still pretty limited but I'm really curious to see what programs you all can devise for it you know the most interesting program I've been able to come up with in 16 bytes is this program that computes Fibonacci numbers and you can check out one of my older videos where I walk through how it works but I also know a number of people have expanded the memory to 256 bytes or even 64 K I'm really excited to see what programs people can run on those machines and maybe in a future video be fun to feature some things that different people have come up with so if you'd like to see that and if you've enjoyed my videos in general consider clicking the subscribe button and also clicking that notification bell so you'll find out about future videos and if you want you can even support these videos directly over on patreon and I really want to thank my patrons there whose contributions are truly helping me make more content like this so on behalf of all my viewers thank you very much for helping make this possible
Original Description
In this video we program the microcode of the 8-bit breadboard computer so that it supports two conditional jump instructions: JC (jump carry) and JZ (jump zero). We also test out these new instructions and write several programs using them.
Code from this video: https://github.com/beneater/eeprom-programmer
Matthew's Patreon post with clever self-modifying code: https://www.patreon.com/posts/how-to-make-16240529
Intel x86 developers guide (4800 pages! CMP instruction is on p.726): https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf#page=726
More 8-bit computer: https://eater.net/8bit
Support me on Patreon: https://www.patreon.com/beneater
------------------
Social media:
Website: https://www.eater.net
Twitter: https://x.com/beneater
Patreon: https://patreon.com/beneater
Reddit: https://www.reddit.com/r/beneater
Watch on YouTube ↗
(saves to browser)
Sign in to unlock AI tutor explanation · ⚡30
Playlist
Uploads from Ben Eater · Ben Eater · 32 of 60
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
▶
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
KA 60 Minutes Sep 2013 rerun (10x speed)
Ben Eater
Frame formats | Networking tutorial (6 of 13)
Ben Eater
TCP: Transmission control protocol | Networking tutorial (12 of 13)
Ben Eater
Clock synchronization and Manchester coding | Networking tutorial (3 of 13)
Ben Eater
TCP connection walkthrough | Networking tutorial (13 of 13)
Ben Eater
Lower layers of the OSI model | Networking tutorial (7 of 13)
Ben Eater
Hop-by-hop routing | Networking tutorial (11 of 13)
Ben Eater
Sending digital information over a wire | Networking tutorial (1 of 13)
Ben Eater
ARP: Mapping between IP and Ethernet | Networking tutorial (9 of 13)
Ben Eater
Analyzing actual Ethernet encoding | Networking tutorial (4 of 13)
Ben Eater
Intro to fiber optics and RF encoding | Networking tutorial (2 of 13)
Ben Eater
The Internet Protocol | Networking tutorial (8 of 13)
Ben Eater
Looking at ARP and ping packets | Networking tutorial (10 of 13)
Ben Eater
The importance of framing | Networking tutorial (5 of 13)
Ben Eater
Programming my 8-bit breadboard computer
Ben Eater
Programming Fibonacci on a breadboard computer
Ben Eater
Connecting to a mystery signal | Digital electronics (4 of 10)
Ben Eater
Using a transistor to solve our problem | Digital electronics (8 of 10)
Ben Eater
Inverting the signal with a transistor | Digital electronics (9 of 10)
Ben Eater
8-bit computer update
Ben Eater
Bus architecture and how register transfers work - 8 bit register - Part 1
Ben Eater
RAM module build - part 2
Ben Eater
Using an EEPROM to replace combinational logic
Ben Eater
Build an Arduino EEPROM programmer
Ben Eater
Build an 8-bit decimal display for our 8-bit computer
Ben Eater
8-bit CPU control logic: Part 2
Ben Eater
Reprogramming CPU microcode with an Arduino
Ben Eater
Update and PODCAST ANNOUNCEMENT!
Ben Eater
The case against Net Neutrality?
Ben Eater
Making a computer Turing complete
Ben Eater
CPU flags register
Ben Eater
Conditional jump instructions
Ben Eater
“Hello, world” from scratch on a 6502 — Part 1
Ben Eater
What is a stack and how does it work? — 6502 part 5
Ben Eater
RAM and bus timing — 6502 part 6
Ben Eater
Subroutine calls, now with RAM — 6502 part 7
Ben Eater
Why build an entire computer on breadboards?
Ben Eater
How assembly language loops work
Ben Eater
Binary to decimal can’t be that hard, right?
Ben Eater
Hardware interrupts
Ben Eater
What is error correction? Hamming codes in hardware
Ben Eater
Installing the world’s worst video card
Ben Eater
World's worst video card gets better?
Ben Eater
Breadboarding tips
Ben Eater
So how does a PS/2 keyboard interface work?
Ben Eater
Keyboard interface hardware
Ben Eater
Keyboard interface software
Ben Eater
How does a USB keyboard work?
Ben Eater
How does USB device discovery work?
Ben Eater
How does n-key rollover work?
Ben Eater
SPI: The serial peripheral interface
Ben Eater
Why was Facebook down for five hours?
Ben Eater
How do hardware timers work?
Ben Eater
The RS-232 protocol
Ben Eater
Hacking a weird TV censoring device
Ben Eater
Let's build a voltage multiplier!
Ben Eater
6502 serial interface
Ben Eater
RS232 interface with the 6551 UART
Ben Eater
Fixing a hardware bug in software (65C51 UART)
Ben Eater
Running Apple 1 software on a breadboard computer (Wozmon)
Ben Eater
More on: ML Maths Basics
View skill →
🎓
Tutor Explanation
DeepCamp AI