 Greetings, 6,800 friends, and in fact, it looks like I've got more than 6,800 friends. I have over 25,000 friends, subscribers that is. So thank you very much for that. It's actually pretty humbling to have that many subscribers, to have that many people just listening to me waffle on about technical subjects. I actually gained about 10,000 subscribers a few months ago when YouTube recommended my video on reverse engineering a chip. And apparently some people thought that I was reverse engineering a potato chip. But it turned out to be a little bit different than that. So anyway, I got a huge bump out of that, so that was kind of interesting. Anyway, I was kind of bragging to a friend of mine about that little 10k bump. He is a pretty popular YouTuber. And he said, you know what I call that? Monday. Also, you may be looking at the video and thinking, wow, I look a lot less blurry. And the reason is that I've switched cameras to a new camera instead of the old Logitech camera that I was using, which apparently wasn't very good. So hopefully views of my face will be a little higher resolution than before. Great. Let's continue with part four of building a 6800 processor using Nmogen. A few comments before we begin. So a person who goes by the repo name of guzztech on GitHub has created a Spinal HDL version of my code, which is pretty awesome. Spinal HDL is yet another high level HDL. So you can check that out in the link below. Let's see. Another comment is that I think that I've been engaging in some premature optimization. So remember when I drew out buses in the very first video, and I showed how, oh, you can put this on the bus and take this off the bus. Well, it turns out that that was premature optimization. Really what I should be doing and what I will be doing in the future is just writing the Python code as it is and not bothering to optimize for the hardware at this point. I can optimize for Python that would just be refactoring and would make sense because it would make the coding go a lot more efficiently and quickly. But in terms of making things more efficient at the hardware level, well, if I do that, now I'm sort of refactoring two layers at a time, and that gets very difficult to reason about. So I'm just going to be sticking with refactoring Python and making that a little more optimal. Obviously not to the point where it's unreadable. I never want to do that. So that's what we'll be doing. So it seems like we have created two instructions, Knop and Jump Extended. Let's go ahead and code up another instruction. All right, so here I have added 8B, rather B8, which is load accumulator A with the contents of the address in the operand. So basically, we start with essentially a copy of Jump Extended because in extended mode we're always going to read the next two bytes and use that as the operand. So that's here. Now the next thing is, of course, we want to go to cycle three, and we want to set up the address to read the operand. So there's the operand right there, and we want to set it up to do a read. So in cycle three, we simply store whatever is on the data lines into the A accumulator, and then we can end the instruction. And for formal verification, we have to register that we've done a read. So that would be the third read in this instruction. So let's do some formal verification and make sure that it works. So I've already written this file, formal underscore LDAA. So there, again, is B8 for the value. So notice that we don't have our postA equals preA anymore because, of course, A is going to change. So we are going to check that the PC has incremented by two. We're going to make sure that we've read three addresses. The first two, again, are the same as before. But the third address needs to be composed of the data that we read from the previous two addresses because that is the address operand. And then finally, we want to make sure that A, after the instruction, is set to whatever was in the third address that we read. So let's go ahead and see if that works. So I'm compiling specifically for the LDAA, formal verification. And now I'm going to run formal verification. And you can see that it's taking a little bit longer, three seconds instead of two. Again, this is because we have more logic and more code. So we can see that we've passed the cover state and we have passed BMC. So that's pretty good. One minor change that I made in verification is, let's see. So one minor change that I made with verification is I changed the cover and the assume. I changed the cover and the assume statements so that instead of looking for just the instruction is the instruction that we're looking for, I want to make sure that we've taken a snapshot. And the reason is that I found in looking at some of the traces from before that the verification engine felt free to just reset the processor over and over. So what actually would happen is it would set up the instruction that it's looking for and then it would do a bunch of resets. And remember that a lot of our registers are reset list, which means that core.instruction would never change. So I got rid of that. And now we just look at the snapshot taken bit because that basically means that we've taken a snapshot because we just executed the instruction that we're interested in. Okay, so that's a jump extended and load a accumulator extended. Now I still haven't dealt with the flags and I will deal with that later. The other thing that I want to point out is that I have removed some of the buses and especially for the increment decrement unit. In fact, let me see if I can get rid of source 16 as well. I don't need source 16 select anymore. And so I don't need to set this as a default and I don't need to set up the bus either. Now the reason that I'm going to do this is that I feel that by creating all these buses I may have indulged in some premature optimization. So I did find that it was getting a little more complicated than I thought it would be. So instead what I'm just going to do is concentrate on the Python part. And then once I've refactored the Python part, then I will go ahead and look at the hardware and see if there are any optimizations that I can do there. Now I'm still going to keep around this source 81 and two bus and ALU really because that is just going to go to the ALU. And I will need to code up the ALU at some point. So we have jump extended and load A extended and we will note that the first cycle is pretty much identical. It does the same thing. And a lot of the second cycle is also identical. And of course the reason that they're identical is because that the modes are the same in the two instructions, extended mode. And again in extended mode, you always read the first two bytes after the instruction as an operand. So let's go ahead and refactor that. So I've created this mode extended function, which basically just generates the logic for an extended mode instruction, at least partially. So cycle one is basically just a straight copy. Cycle two is just what is common and notice that I had to put the operand up here instead of down here because I do want to return the operand. Now I put in a comment here saying that the operand is only valid during cycle two. In addition, remember when I went through cycle one and I stored the data lines into the high byte of temp 16 and I didn't do anything with the low byte of temp 16. Well here I am actually storing the data lines into the low byte of temp 16. However, remember that temp 16 will only be set at the end of the cycle. So during cycle two, if I really want to access my 16-bit value, that's what this operand is for. So during cycle two, if you want the 16-bit operand, use operand. And during cycle three, if you want the 16-bit operand, well it's been stored in temp 16 for you. So how does that work? Let's go to jump extended. So the first thing that I need to do is just call self mode extended. And it returns an operand. So cycle one has already been taken care of. In cycle two, this read has been taken care of. So I don't need that. I do need to state that I want to end the instruction and I don't need the formal verification because that's already taken care of by mode extended. So that's what jump extended turns into. Oh, yes. And notice that when I end the instruction, I use the operand, which again is valid only during cycle two. Now let's look at what load A extended would look like. So again, because this is an extended mode instruction, I'm just going to call mode extended to generate the logic to do all the extended mode stuff. I don't need cycle one because that's already been taken care of. And in cycle two, let's see. So these three statements have been taken care of, right? Yep. Okay. So this is all that's left. And I don't need this other registration for the read. So that's it. So during cycle two, aside from the whole extended mode stuff, basically I take the operand and stick it in the address register, set up to do a read on the next cycle and on the next cycle, take whatever is in the data lines and stick it in self.a. And then I can end the instruction and I still need this registration of what I read at cycle three. So let's just run formal verification to make sure that that still works. And the good thing about formal verification is that if it runs, you can be pretty sure that your code is working properly unless, of course, you screw up formal verification itself, in which case all bets are off. And that's what the cover statement is for, to make sure that you're actually doing the right thing. So we can see that we've gotten passes. Let's take a look at the jump instruction as well. Make sure that's still working. Yep. Everything still passes. Okay. So that refactoring actually worked. Okay. Let's start on the ALU. Now right now, all I'm going to be using the ALU for is looking at the register that we're loading and setting the flags V, Z and N, which are for load. So the first thing that I want to do is I do want to keep source eight one and source eight two, but I think I'm going to get rid of the destination bus. And again, the reason is that I don't think it's a great idea at this point to do that. In addition, I don't like the fact that I can choose to write any registers that I like and that may actually conflict with writing registers elsewhere. So for example, in the LDAA instruction, I do directly write the A register. Right over, where is it? Right over here. So if I happen to forget, you know, that I set the destination bus to something and then I wrote another register, well, you know, which write gets precedence depends on where it appears in the code, which isn't that great and can be very difficult to reason about. So I'm just going to get rid of the destination bus entirely. So I don't need that. Now I still do need ALU eight because now that's just going to be the output from the ALU. And speaking about the ALU, I'm going to create a new module called ALU eight. So there's going to be two inputs, self.input one and self.input two. And there's also going to be an output. Now in addition, we're going to need to know the function that the ALU should do. So I'm going to create an enumerated value called ALU eight func. And I'm going to have the usual none equals zero to do nothing. And then there's just going to be a load, which is one. And then I can just add whatever I want after that. So the ALU eight also has to have the function that it's going to do. So that's an ALU eight func signal. Now in addition, there are the flags that the ALU was going to keep around. So self.ccs, that's the way it's described in the manual. I think that stands for condition codes. So that's also going to be a signal of eight, technically six, because there are only six flags. The top two flags are always one. So I do want to set up a reset value. I really would like to set up a reset value. And it would be one one, because the top two unused flags are always one. Next comes the H flag. Next comes the interrupt mask flag, then NZVC. So this will reset the flags to the correct value. The other flags, maybe they should have been resetless, but let's just leave it at that for now. All right, so let's write some logic. So for load, basically all I want to do is say with m.switch self.funk, if it's load, then all I want to do is say self.m.d.comb. I want to set the output equal to input one, we're going to ignore input two. But also we need to say, let me add some, maybe some useful values for the flags. So flags. So I'm going to have H, which is flag number five, four, three, two, one, zero. So there's the I flag, the N flag, the Z flag, the V flag and the C flag. So now I can just say self.ccs of, let's see, Z for zero equals. And then this is just going to be whether self.input one is zero. And for the negative flag, well, that's just if self.input one, if the high bit of self.input one is set, then it's a negative number. In addition, the overflow flag is reset, otherwise I basically do nothing and I leave the flags alone. I'll leave the output alone. Don't do anything. Okay. So I think that's correct. Now if I go back into the core, let me set up the buses now. So basically it would just be, so first of all, I do need to set up a sub module. So m.submodules.alu8 equals alu8 equals u8. Okay, now by default, the alu8 function, and I need now a function signal, I guess I don't need alu right, do I? So this is going to be called alu8funk, and it's a signal of alu8.alu8funk. And it's going to give me an error because I don't have that import, right? I thought it would give me an error, but I guess not. So self.alu8funk is alu8funk.none, that's the default. And now, alu8.alufunk, alu8. Okay, still doesn't like it. Oh, now it thinks right, because that's a variable. Okay, I'm just going to call it alu then here. Okay, and now I think I do need to import it at some point. So from, how about from alu8 import alu8funk and alu8? That way I don't have to have alu8.anywhere, where's the other one, right here, right, right. Okay, now I can finally set up the connections. So m.d.com equals alu.input1 is always equal to self.source81, and same thing with input2. And I want to connect alu8, that's our output bus, to alu.output, and self.alu.funk is self.alu8funk. Okay, that should set up the alu. So now all I have to do is set alu8funk to whatever function I want to do, set up the inputs, and then just read the outputs. And the alu is basically combinatorial. Oh, wait, is it? Is it? No, okay, so the CCS register needs to be set on phase one. There we go. Okay, so the output is combinatorial. It's just that the flags get set, like all registers do, at the end of phase one. Okay, so now what I can do is I can go into LDAA extended, and instead of just directly setting A from data in, what I would do is I would say m.d.combinatorial. Self.source81 is self.dn, and I can set the alu function to alu8funk.load, and then instead of loading A from dn, I load A from alu8output. Okay, and what that does is it sort of has the side effect of setting the flags properly. Now, speaking of setting the flags properly, notice that I haven't formally verified it yet, so I need to do that. So the first thing I'm going to do is copy the CCS flags from the alu, and I'm just going to say these are flags from the alu. And in the setup for the alu, I'll just do the copy. So self.ccs is alu.ccs. Okay, now in formal verification, I should pass CCS in. So let's see. For the snapshot, I think here I want to also pass in the value. So I'm going to say m.d.phase1 self.preccs equals CCS. Now, do I have pre-CCS? No, not yet. So I'm just going to create pre-condition codes and post-condition codes. And then in the post snapshot, I should also give the condition codes. And that's post-ccs. Okay, so I've set pre-CCS and post-CCS. Oops, equals CCS. Okay, great. Now in the core, when I take those snapshots, I need to be sure to pass those values in. So here we go. Okay, so we've got errors because, of course, I need to pass in self.ccs. Self.ccs. Okay, now in the formal verification files, for jump, the flags should not change. For load A, the flags do need to change. Okay, so I've added a few utility functions to verification. So the first one is just called flags. And what this allows me to do is construct flags. Save would be the previous value of flags. And then I can just say n equals whatever and v equals whatever. And those will be set in the return value. So that's kind of useful. Basically I want to construct flags such that the flags that I'm not interested in have not changed. But the flags that I am interested in, I can just set the values using keyword arguments. And then assert flags is basically just going to assert that every flag is as is expected. So and that's where I call flags. So basically I just say assert flags, and then I say what the post flags are and the pre snapshot flags are. And then whichever one of these I set, and I can set any or all or several or none. Those are the flags that will expect to be changed to that value. And the other flags are not expected to change. So one assert per flag so that when, when if it fails, it tells me what line is failing. And I can just say, oh, that's that particular flag. Because otherwise if I just check post flags against pre flags, it'll just say that that line failed. And then I have to figure out which one was the flag that actually failed. So now in load a, all I really need to do is let's see. I think it would just be self dot assert flags. And let's take a look at what I need. I need the module. So M. I need the post flags and the pre flags. So that's data dot post CCS data dot pre CCS. And now I just need to set the flags that I need to check for changes. So let's see the Z flag, of course, needs to change. And that's just going to be equal to data dot post a equals zero. The end flag is just data dot post a of seven. And the V flag is always going to be zero. Okay, so I think that should do it. Let's go ahead and run formal verification on LDA a and see what happens. Okay, and great, everything still works. And I think it took slightly longer because now I've got again, more logic. I've got an ALU, which can take various functions. I've got flags. So of course, the checker has to be able to, you know, check that, regardless of which flag was set that only the flags that should be changed were changed and all other flags were not changed. So it just takes a little bit longer. Okay, how about we do some other instructions? Also extended instructions, let's see, how about ADC, add, SBC and sub. So add, add with carry, subtract and subtract with carry. Those will be interesting. Those are probably one of the more difficult instructions to implement just because of the way that addition and subtraction actually work. So speaking of that, let's take a look. Say you want to add two eight bit binary numbers. We first separate the digits into the lower four bits, the next three bits and the high bit. We add the bottom four bits making a five bit sum. The fifth bit is the carry into position four. This is the half carry bit and gets stored in the H flag. We then add the next three bits with the half carry making a four bit sum. The fourth bit is the carry into position seven. Next we add the high bits with the position seven carry making a two bit sum. The second bit is the carry into position eight. This is the carry out and becomes the carry flag. The carry out and the position seven carry are exclusive or together and this is stored as the V or overflow flag. The N or negative flag is simply the high bit of the sum because in two's complement arithmetic negative numbers always have their high bits set. The Z or zero flag is set if the result is zero. That with carry works the same way except we use the carry flag as the carry in bit. Subtraction is almost the same with a twist. In two's complement the negative of a number is the inverse of that number plus one. For example one would get inverted to one one one one one one oh. Then we would add one which makes negative one equal to one one one one one one one one in eight bits two's complement. To compute a minus b we add a plus negative b which is a plus the inverse of b plus one. Subtract with carry if carry were one additionally subtract one. So we can see that to subtract with carry we add with carry except the carry in to use is the inverse of the carry in we want. One final twist after we invert the carry in and the add end the carry out after all flags including overflow has been calculated is also inverted. Alright so the first thing that I did was add all of those functions to the ALU's list of functions that it can do. So as you saw earlier we've got some intermediate signals that we're going to need and for add basically I use this intermediate signal carry in to tell whether I'm actually doing a carry in or not based on whether we're doing an add or an ADC right over here. Same thing with subtract and subtract with carry so basically I'm just either selecting zero or the existing carry. Alright so the next thing that I do is I split up the addition into sums here's the four bit sum which is actually a five bit sum and then there is the next one and the next one and so on basically as the animation showed and then we set the flags according to the results. Same thing with subtract so the carry in is the same except you can see here that we are inverting the carry and we are also inverting all of the add ends right over here and we are also inverting the carry out. Now one thing that you'll notice is that there is no half carry so we don't actually need that middle part of the sum so we can just go straight to adding the first seven bits and then adding the last bit. I don't really know why the half carry is not used for subtraction. The half carry is mainly good for when you are doing binary coded decimal in other words when each four bits encodes a number between zero and nine and in that case when you do something like nine plus one you want the result to be ten, one zero not actually a. So the half carry actually turns out to be important for this and then there's another instruction which we'll get to further down the road called DAA which is decimal adjust accumulator so after you do an addition you can decimal adjust it so that all the numbers now become binary coded decimal instead of just hexadecimal and the half carry flag is integral to that. Why that's not the case with subtract I don't know but there it is. So that's the code now I've also gone ahead and formally verified it so within the alu8.py function so within the alu8.py file I have written some formal verifications and even though it looks like I'm basically copying the code and just formally verifying whether I can copy code it's actually subtly different. So one of the things that I'm doing is I'm creating a sum five which is a five bit sum, a sum eight which is the sum of the first seven digits with a carry and some nine which is the sum of the two add ends plus the carry in. So I'm not actually breaking up my addition and doing a sort of ripple addition but I'm actually doing three different additions so one addition is adding the first four bits another addition is adding the first seven bits and the other addition is adding them all. The next thing that I'm doing is I'm making sure that the output of the alu is basically the same as the input one plus the input two plus the carry in truncated to eight bits because that's really what it should be. So the alu's output is the result of all those rippled additions while sum nine is the result of just this one single you know non-rippled addition so I am really comparing the results from two different methods and then of course the half carry the negative the carry bit the zero bit and the overflow bit are all based on those slightly different methods of doing addition so that's how I do the formal verification of addition same thing with the formal verification for subtraction and what I'm also doing here is I've got an additional assertion because I want to make sure that when I actually do subtraction when I take input one minus input two minus the carry in that is actually equivalent to the twos complement addition method which is input one plus the inverse of input two plus the inverse of the carry in so I'm additionally making sure that my whole theory about subtraction being the same as twos complement addition actually works. So let's go ahead and run that so first we generate the code and then we're just going to formally verify it okay and bounded model checking passed and well we didn't have any cover statements but that passed too because we don't have any cover statements so one of the things that I didn't do is actually check that the flags that I haven't touched haven't changed so I'm going to add an assert here that alu underscore CCS I that's the interrupt flag is equal to alu dot CCS of I in other words the temporary version of the flags remain equal to what the register is and I'm going to do the same thing for subtract but I also want to make sure that the H flag has not changed either I don't really need to worry about the other flags these are the top two bits in the flags registered because those should never be touched they should always be one one and I guess I may as well assert that as well so this is going to be asserted all the time so m dot d dot com so I'm going to assert that alu dot CCS of what is it six and seven is equal to one one all the time okay let's run that and just make sure that everything is still working compile and verify great it still passes okay that's good perfect so now we know that our alu can add and subtract properly now what we're going to do is go back into the core and implement those instructions so let's go ahead and find add and ADC okay so there is ADC A and ADC B so this is B plus whatever memory is plus the carry or A plus the memory plus whatever carry I think we're only going to do A at this point and I believe that there's going to be a pattern between when you choose A and when you choose B and then we can immediately just upgrade or level up all the instructions so that they can handle the B register as well so in terms of the extended version okay so here is the extended opcode for add it's B B so let's go ahead and add that and we can also see that ADC is B9 now you can see over on the right side of the table that for add and add with carry the H flag is changed along with the NZV and C flags and if we go to subtract we can see that the H flag is not actually modified so subtract sub is B0 and subtract with carry is B2 great those are the four instructions that we need to perform so let's go ahead and define them down let's see here it's probably going to be similar to LDA A so let's do add a first okay so we've already done the extended part of loading the operand okay so in cycle two we of course want to read whatever is in that address then in cycle three what do we want to do um okay we definitely want to put the data in onto one input of the ALU we also want to put on the other input the A register we want to tell the ALU to do an add instruction and we want to store the result of the ALU into A and remember that the ALU keeps the flags so that's already taken care of and then we want to end the instruction and of course because we read a bit of data here we want to make sure that we have indicated for formal verification that we've done that read all right let's just copy this over for ADC all right and everything is identical except the function that we call in fact everything's going to be identical for sub and SBC as well so let's just do sub A sub and SBC A SBC okay that should be that now let's go ahead and write the formal verification classes for these instructions so I'm going to start with formal LDA and I'm just going to copy this and call it formal add A okay so let's go ahead and look at add A now what I like to do is I like to look at the table again and look at the bit pattern and type the bit pattern again that way I'm just not copying and pasting and I may be copying and pasting a mistake so let's take a look at add A again add A is BB I'm pretty sure that's not B8 in fact there's this nice website here that has a nice table of all of the op codes so we can see that add A is right here it's 8 add A is oh it's right add A extended is B B so that was correct so this is B B 101 101 okay A changes B does not X does not SP does not and we've not and we don't write anything the post PC is just going to be the pre PC plus two because it's a three byte instruction wait a minute that's not right that's totally not right now I got this line wrong didn't I because in fact after the instruction the program counter should be three more than the program counter was then at the beginning of the instruction because the instruction is three bytes long there's the op code and the two bytes of the operand so I should be looking for this and in fact when I run formal verification it does say that bounded model checking failed and let's take a look at why all right so here are the waveforms let's just pull up the clock the address and data okay and out of the core let's take a look at the instruction register okay so there is our b6 I assume and let's take a look at the program counter so our program counter was at this point F F F D and then it went to F F F E F F F and then it did not go to zero so this is in fact incorrect so this means that we forgot something so what I really need to do is in mode extension function I need to add one to the program counter after I've read the second byte of the operand now the question is will that screw up our jump instruction because remember that the jump instruction takes the operand and then puts that into the program counter so if we're putting PC plus one into the program counter here and we're putting the operand into the program counter for jump which one takes precedence not only this but we're changing the cycle number to three but we're also changing the cycle number to zero for jump when we end the instruction so which one takes precedence and the answer is that for n my gen it's the code that's written last that takes precedence so here is jump extended here's where we call mode extended and here's where we call end instruction so any code that gets generated by end instruction that conflicts with any code that's written for mode extension will override that code so let's go ahead and run formal verification and make sure that jump works and remember that jump should still work because PC plus one doesn't really happen for jump but it will happen for ldaa so here let us run let's compile for jump and then formally verify okay that looks like it worked and let's take a look at ldaa and formally verify and that's working great also okay so for formally verifying the ad instruction uh i basically copied the formal verification file for lda and uh the check is actually going to use a don't care for bit one in the instruction the reason is that this file is actually going to check both ad and ad with carry now in terms of the actual formal verification i've basically copied what i did in the al use formal verification because well i mean it works so i may as well just copy that over the only difference of course is that now one of the inputs is not just any input it's the previous contents of the a register the other input is whatever was read for the operand um and the output is just going to be the contents of the a register after the instruction and in terms of the flags well we already have our assert flags function so i can just say that we want the z and v c and h flags to be as they are calculated to be now because i'm going to be checking both instructions uh i do need to add a few statements here so for example with carry is only true if bit one of the instruction is zero that indicates that it's a carry instruction and here uh if with carry is true then i assign carry in with whatever was in the carry flag prior to the instruction otherwise i just assign it to zero so let's see if this actually works so first we're going to compile with add a okay that compiles and now let's run the verification okay and it worked and again it's taking progressively longer and longer because again i'm adding more and more logic and we're going to do the same thing for subtraction so this is the file formal sub a here we go oh it doesn't work why doesn't it work okay well one way of trying to figure out why it doesn't work instead of staring at the code and trying to figure out what i screwed up let's uh let's look at the trace that it came up with okay so as usual let us look for the clock the address and the data in and let's look at the instruction register all right so b zero is the instruction that we're looking at and b zero is subtract without carry so let's see what's going on here there is b zero so the operand is b f f f and the contents of b f f f is six zero so let's take a look at the a register there's the a register so the a register was zero and it looks like the a register changed to six zero and that is definitely not correct okay we can see that i reverse these operands this should be we're not doing data in minus a we're doing a minus data in this as well okay rerunning formal verification for the what is this fourth time here we go hoping for a win all right it's looking great okay great it works okay so now that i've got all of these instructions um there is a bit of commonality between them uh one of the common bits is basically this right over here what i'm doing is during cycle two i'm setting up the address to read some particular address i'm setting up read write signal to be one which means read and on the very next cycle i'm using the data in and in addition i'm registering that i've done a read um data in uh for load a seems to go into source eight one for add a it goes into source eight one although it doesn't really need to uh because of course d in plus a is the same as a plus d in uh for sub a it's just going into source eight two now maybe what i can do is write a simple function called i don't know read byte and what i'm going to do is i'm going to start it like that and i'm going to copy this part of the instruction along with this part of the instruction okay now i have to think about how i might use this read byte well first of all the uh address is always going to change so i need to say what is the address okay so there's that uh the next thing is that the destination may always change so let me say a combinatorial destination is going to be some single combinatorial destination because i want to make absolutely clear that this is going to be combinatorial in other words if i wanted to take if i wanted to read d in and then store it somewhere using phase one then i couldn't actually use this at at this point uh let's see the verification remains the same now the only other thing is the cycle to do this on now i suppose that i may want to read a byte starting at cycle three or maybe starting at cycle four or five or whatever so maybe it would be a good idea to say which cycle this thing should generate code for so cycle is just going to be an integer and then this is just going to be cycle and this is just going to be cycle plus one now the interesting thing is that this cycle is an integer it is a python integer it isn't a signal it is not a value it is not an n my gen value so n my gen when it encounters this code will actually put the constant in here and cycle plus one as a constant so it's not going to have an adder over here at least i hope it doesn't okay so that's what read byte does okay now for ldaa we're simply going to say read byte starting from cycle two the address is the operand and the destination is self dot source 81 that means that i can get rid of this section i can get rid of this line and i can get rid of that line oh i need the module okay so let's formally verify load a again because i made a change it's always a good idea to formally verify to make sure that logically everything is the same and that looks great so i think the next thing that i'm going to do is i'm going to use keyword arguments because just putting down some integers and some other things doesn't exactly make things clear how about doing that okay that definitely makes things clear so now i can just do the same thing for add a so the cycle is two the address is still operand and the combinatorial destination is source 81 so that can go that can go and that can go in fact just to make things the same as subtraction i'm going to change the operands around so now it's a plus the operand rather than the operand plus a sure why not okay we make the same change for add with carry this is now one we make the same change for subtract okay things are looking better the functions are shorter let us just formally verify add and subtract to make sure it works and add works let's make sure i didn't make any mistakes for subtract and subtract works excellent so now we've got five instructions we've got well actually seven instructions we've got no op which i still need to formally verify we've got no op we've got jump we've got load a we've got add and add with carry and we've got sub and sub with carry how's that cat