 greetings, risk five friends, check out all this stuff. So this is the schematic that I've been working on. Last week, we basically saw just the sequencer ROM and the trap ROM and these multiplex card connections. And then I have this thing in the middle, which I said was a multiplexer. Well, it turns out that I didn't actually need that multiplexer. And the reason is that we can see here these output enable pins. So the sequencer ROMs are, they're just flash ROMs and they have output enables. So, and because only one of these is going to be active at a time, I could just tie the outputs together and use the output enables to select which one I want to output. So, there really wasn't any point in putting multiplexers in there. So I did a whole bunch of other things. So why don't we take a look at the sequencer ROM enable block right over here. So this is the thing that outputs the output enables. And I can show you that in the code. So here I've highlighted the line that generates the sequencer enable output. So you can see that it's basically a function of three things. There is this misaligned instruction that actually should be misaligned PC, not misaligned instruction. It's that the PC is misaligned. In other words, it's not on a 32 bit boundary. And then there is a bad instruction which is what happens when either the instruction is all ones or the low 16 bits are all zeros. And those are defined as bad instructions or a trap is happening. So a trap meaning some other like bad opcode or bad data in the instruction or maybe a misaligned store or a load or an interrupt or a user exception. Those are all traps. So how exactly is this implemented in the schematic? So let's just go ahead and open this up. And we can see that. Well, basically it's a straight, almost a straight translation. The code actually used knots in front of this and then it used an and so, you know, De Morgan's rule that's just a nor gate. So you can see that I'm taking the inputs trap, misaligned PC and bad instruction and I'm putting it through this nice one gate package. And I'll talk about the one gate packages in a moment and why I'm using those. So this is a nor gate and that goes to sequencer ROM enabled. Now I need the negative of that because the enable is a negative signal. So I also have this straight nor gate and that produces the negative of that signal. So of course this signal is going to go to the sequencer ROM while this signal which is the opposite is going to go to the trap ROM. Now the other thing is this was pretty interesting. So in the comments, somebody said, well, you know, if you're going to have a multiplexer and you're going to have, you know, one signal be the opposite of the other in order to select, you know, which output you want. You don't really want them both going up at the same time because then they're both going to be enabled and they're going to fight each other. So I've become a bit blasé about that. And I'm like, you know, it's okay if, you know, there's like one or two nanoseconds of delay between, you know, one going high and the other disabling, one enabling and one disabling. I don't really care at this point, but, you know, I did want to make some effort. But anyway, so the comment was that what I could do to generate both a positive and the negative of the signal is use two XOR gates. So the signal that I want goes into both XOR gates. Then on one XOR gate, I feed in a zero. The other XOR gate, I feed in a one. When you feed a one into an XOR gate, that basically inverts the signal. So what I'm effectively doing is I'm having the same gate, applying, you know, either a straight through or a negate. And because they're the same gate, they would be roughly the same propagation delay, which means that I get roughly the same timing. Now that's not strictly speaking true because the propagation delay of a gate depends not only on how the gate is made, but also what's attached to its output. Because remember, the output of a gate is going to go to the input of some other gates and the inputs are all MOSFETs. And we know that the, you know, in order to change a MOSFET state, you basically have to fill up that kind of capacitor that's associated with the gate of a MOSFET. So of course, the more MOSFETs you have attached to an output, that's just more capacitance that you need to fill up to a certain level. And the more capacitance you need to fill up, the longer it takes. So, you know, that's really the propagation delay of a gate when it's compared to another gate of the same kind. Okay, now why am I using these single gates? Well, first of all, I kind of like the single gate packages. They're small, they're compact, they're like SOP 23 sized. The other nice thing is, first of all, usually, you know, if you had say a triple NOR gate, if you get your ordinary 74 series package, it's gonna have three of those, or maybe four, depending, I don't know. If you had a two input NOR gate, you'd definitely get four in a package. So the thing is that, you know, I'm only using one here, and if I use another one in the same package, it would be somewhere else in the circuit. Physically, what that means is that I would have to route that signal to that one package, which means that, you know, if I've got four gates battered all over the schematic, I would have to somehow contrive to get those signals to the same approximate location in the printed circuit board, which is sometimes not a great idea. So, you know, using single gates really makes things easier to route. So there's that. The other thing is, well, why, you know, if I've got something like this, why couldn't I use something like a gal? And, you know, let's, let's suppose, okay, so these are two gates. Let's suppose I had five gates. Why couldn't I use a gal or a CPLD or something like that for generating logic like this? So I have a kind of a rule that I'm applying, which is that at some point, it's okay to use a gal or a CPLD because in my mind, if the logic gets really complex, then I would ordinarily replace all that logic with a ROM. So, you know, if I had, say, five inputs and three outputs and there were a whole bunch of gates associated with it, not talking about flip-flops, just gates, so multiplexers, gates, that sort of thing, then really what I want is a 32 address ROM with three bits out, output. They don't make those, so you have several choices. You can just make it out of discrete logic or you can stuff all that logic into one single chip, which is a gal or a CPLD and call it a ROM. You know, way back when you probably could get really small ROMs. So I think that's an okay use of a gal or a CPLD. The one thing that I don't want to do is use a CPLD because I think the logic is just, you know, there's just a lot of it. So for example, you know, I have two gates here, maybe in another block I have three gates, in another block I might have five gates and it's really tempting to just combine all that into a single block. So the problem with that is, one, you have, again, you're routing all your logic into a single physical location. And two, you know, that's sort of like now you're putting ROMs together when they're actually separate. So, you know, it's kind of a waste if you have five inputs that generate one bit and another five inputs that generate another bit. Well, you could replace those with two ROMs, each with 32 addresses, or you can replace it with a single ROM with 1,024 addresses, which doesn't really seem very efficient to me. So anyway, that's my kind of reasoning. So there you go. Okay, so this is this one block. We can take a look at, so what I've been doing over the past week is I've basically been creating one block, putting the inputs into it and, you know, whatever outputs there are, and then looking at the inputs and seeing how they are generated and then how they are generated and then how the inputs of that block is generated and so on. So what I've got here, let me see if I can zoom in a little bit. So let's take a look at bad instruction. Okay, so bad instruction, let's go back to the code. Okay, so here's the logic for bad instruction. Now you can see that I've defined yet another clock. I think, so remember that the clock, there's basically six machine cycles per, no, six system cycles per machine cycle. And each machine cycle does something different. So I've decided that the very first machine cycle is the thing that loads the instruction. So at the very end of the cycle where there is a positive edge, that's the thing that's going to, that's the thing that's going to store the instruction into the flip flops. Originally I had a latch and I decided that I didn't like that because it seemed like there was going to be a combinatorial cycle in the schematic and I didn't like that. So I just changed it so that it's just edge triggered. So anyway, so pH2R is just a clock that goes low and then high on the very first system, a system cycle of the machine cycle. So once the instruction is loaded, so that clock is now high, it means that the instruction has been loaded and I can look at it. So what I want to do is I want to compare it to all ones and I want to compare the low 16 bits to all zeros. So let's take a look at the schematic and see how that is implemented. Right, so here's the block that generates bad instruction. So we'll open it up and okay, so it looks pretty complex, but if you think about it, I have to compare all the bits of the instruction to something and in the 74 LVC series, there is no 74 LVC 688, which is actually an 8-bit comparator, which is unfortunate, so I just have to hokey something else up. And what I've done is I've used 74 LVC 07s and 06s. 07s are open drain buffers and 06s are open drain inverters. Now the nice thing about open drain is that basically if you, so for a buffer, if you feed in a zero, then you get out a zero. In other words, the output is tied to ground, but if you feed in a one, the output is high impedance. What this means is that you can tie two outputs together and that's effectively kind of like an OR gate, except it's zero or zero. So if any of the inputs are zero, then the output is zero. Okay, I guess that's an AND gate. So if all of the inputs are one, then the output is high impedance because none of the outputs are gonna be tied to ground. Now, because it's high impedance, you still have to attach a pull-up resistor to plus in order to turn that high impedance into a one. So basically what I did was I took all of these instruction bits, so there's 32 of them, and I fed them into six LVCO sevens. And unfortunately there are no eight gate versions of this. And there are four gate versions, but I just decided to use the six gate version. And I fed all 32 bits into them and then I tied all of the outputs together. So as long as any of them is zero, the output is gonna be zero, which means that the output of this signal, which detects all ones, is gonna be zero. If all of the inputs are one, then the output is gonna be high impedance. It gets pulled up to plus, which means that the output is one. So this is my comparator to all ones. Now I did the same thing to compare the low 16 bits to all zeros, except this time I used the inverter version of the open drain output chips, and I pull it up to high. So I've got two signals, one of them is for all Fs, one of them is for don't care, and then zeros on the low 16 bits. Then I need to ore those together, and then I need to end that with the phase two read signal, and that's my bad instruction signal. Okay, there's another input, which is misaligned PC. Now all misaligned PC does, is it looks at the low two bits of the PC and makes sure that they're both zero. So what does that look like? Well, I'm just taking the low two bits and oring them together. So if any of them are one, that's bad, so that's a misaligned PC. Okay, and that's basically how I generate that. Now trap is a different story. So trap is a flip flop. So let's go to the trap section. So this is trap, and basically the way the trap works is that the ROMs, either the sequencer ROM or the trap ROM, will tell the trap flip flop to load a next value. And if you don't load a next value, then you just retain your current value. And next trap, next trap zero, low trap zero and next trap zero come from the, where did they come from? Okay, they come from the trap ROM. And low trap one and next trap one, where did they come from? Oh, yeah, right, okay, sorry. I should step back a moment. So there are actually, for the low trap and next trap signals, there are actually three sources of these signals. The first source is either from the sequencer ROM or the trap ROM. So again, because only one of those is gonna be enabled at a time, I can tie those outputs together. And that's what load trap zero and next trap zero are. Load trap one and next trap one come from, this is a block that handles interrupts. So IRQs like a timer interrupt or an external interrupt or something like that. So that too is allowed to set the trap value because a trap happens when you get an interrupt or an exception. So let's go into this block and the trap is always loaded on phase one. And I also have a reset signal because when you start the machine up, you wanna make sure that trap is set to zero, otherwise you're immediately in a trap condition, which doesn't make any sense. Okay, so this is kind of a fun little diagram. Let's take a look at it. So here's next trap zero, next trap one, load trap zero and load trap one. So of course, I wonder if I, yeah, okay. So this may look a little bit odd, right? Because what this circuit is basically saying is if I either want to load from the sequencer ROM or the trap ROM, or I want to load from the IRQ circuit, then I want to load. What this gate is saying is if I want to load, then I wanna take the or of whatever's coming out of the sequencer ROM or trap ROM and whatever's coming out of the interrupt ROM. So if the interrupt block wants to load a trap, then it's going to decide whether it's gonna be a zero or a one, but if it doesn't want to load a trap, then load trap is zero, but also next trap is zero. So that kind of makes it safe to just order these values together. Okay, now I just have this multiplexer, which should be familiar. We've done this before with the multiplexer card. So we have a single flip flop and we select either the output of that flip flop or the result of next trap. And that becomes the trap data that we want to put into the flip flop. So depending on whether we wanna load the trap or not, we either retain the same value or we load the trap data, one of the next trap values. The clock goes to phase one, the clear, that's an asynchronous clear. So that goes to the reset signal that just resets everything. And there's a bunch of capacitors, one for each gate. So currently in the schematic, I sort of stopped putting in capacitors because number one, when you're dealing with single gates like this, it's kind of the equivalent of a four gate package and you only need one capacitor for a four gate package. So you shouldn't strictly speaking need a single capacitor for every one of these gates. You could probably get away with putting a single capacitor for like four gates or six gates or something like that. Maybe. So maybe I don't need all of these capacitors. So I just decided, well, I'm not gonna put capacitors anywhere on the schematic yet. I'm gonna make a decision later on as to how many capacitors I need. So that's the trap value. Let's take a look at, okay, well we can take a look at exception. This is actually the same thing. We've got a load exception and when we want to load the exception, we get a next exception value and also an extra signal that tells us whether the exception was fatal or not. That happens on the phase two clock. So if we look at that, it's basically the same thing except of course we don't have any OR gates. We've got a pair of resettable D flip flops and single bit multiplexers. And that's it. Let's see what else we've got. Okay, so we talked about trap. We talked about misaligned PC and bad instruction. So bad instruction. So misaligned PC just takes the PC and we can get the PC from the card that has the PC on it. So there it is right there. So for the instruction, basically what we wanna do is we want to take it from something. If we take a look at where that signal comes from, it's mem data read. So in other words, we're reading the instruction from memory. When do we read the instruction from memory? Well, on phase two read and also when load instruction is high. So here's what this looks like. It's basically 16 bit 374s. Here is the input. So now you're probably gonna yell at me for being hypocritical, but yes, I've taken a clock signal and I've put it into a gate. Now, in my mind, this is okay because I've carefully analyzed this and I've determined that the load instruction signal does not change during the period of time that phase two write is active. So this is a safe use of doing that. Number two, I'm not using an FPGA, which means that I can actually put a clock into a gate. You don't wanna do that with an FPGA because then you run into things like clock skew problems. Now, yes, this additional gate does cause a clock skew. It's maybe a nanosecond, but again, because I'm not gonna be running my circuit very quickly and because the input data is not going to change on exactly at the edge, there's gonna be some period of time where that data is stable. I don't really need to worry that much about the clock skew. So through careful analysis, I've determined that this is okay. Obviously, if you don't wanna do that careful analysis, don't shove your clocks into a gate. So that's what that is. Okay, load instruction. What does load instruction look like? Well, this comes from this IRQ slash load ROM, load meaning load instruction. So it takes in three signals, namely the instruction, whether the instruction phase is zero or not, whether there's an interrupt going on and whether the sequence of ROM is enabled and it generates load instruction, memory, load trap and next trap. So let's just take a look at this. So we can see this is what happens when there's a load instruction. So all of these have to be high. Basically, there cannot be an interrupt happening. The sequence of ROM has to be enabled, which means that, by the way, which means that we're not in a trap either. And the instruction phase has to be zero. Okay, so this sequence of ROM enable thing is what worried me about this combinatorial cycle. So let's take a look and zoom out a little bit and you can see what I mean. So here's where the instruction comes in, right? So from the instruction, we could possibly generate a bad instruction. The bad instruction generates a sequence of ROM enable signal, which goes back into the load ROM here, which generates the load instruction signal. And if this were a latch, well, the load instruction signal can start going unstable. Well, so instead, what I did was I made sure that this was an edge triggered flip-flop, not a latch. So this is now controlled by the clock and not by the load instruction signal. And the nice thing is, is that even if the load instruction signal is unstable, if phase two right is not active, nothing is gonna happen. And if phase two right is active, well, all it means is that it's gonna bounce up and down and I wanted it to load anyway. So I guess that's okay. Let's see what else. Okay, so there's a whole bunch of other blocks. Let's take a look at, what should we look at? How about opcode select? Okay, so what opcode select is, in the code, it's basically a switch statement. So it takes in the opcode of the instruction and it sort of compresses it down to four bits because there are at most 16 opcodes that I wanna deal with. And also the opcode format, that really should be immediate format because it tells me where the bits of the immediate value in the instruction are. So if we look at it, we can see that, oh, I've used some CPLDs. Why did I use some CPLDs? Because I thought that this looked like a ROM. And it basically is a ROM. So it takes in all 32 bits. Now, that would be a four gigabyte ROM. The reality is that I can actually split it effectively into two ROMs. One taking in the high 16 bits, which also generates a few extra signals. And one taking in the low 16 bits, which also generates this one signal. You can see it 0073. That is the system opcode. And then if there's a system opcode, you need to look at the high bits to determine what the actual opcode is. And that's system zero, system one, and system two, which are actually E-Call, E-Break, and Emret. So in this case, I think I'm allowed to use a CPLD because these are effectively two ROMs. How big are these ROMs? Well, this one is 16 bits input, plus 17, 18, 19 bits input. So this is a 512K ROM. And it outputs one, two, three, four, five, six, seven, eight bits. Okay, 512K by eight. Okay, that's fine. Here's one that takes in 16 bits plus an additional bit. So this is 128K and now it puts three bits. So at this point I said, well, instead of putting a whole lot of logic in here, I think it's more efficient to replace this with ROM and the ROM is reasonably sized. So I'm okay with that. So the CPLD that I've chosen is the ATF-1502, which is sort of like the evolution of the gal. It has 32 macro cells in it. So I could generate 32 outputs. It's got a whole bunch of inputs. So this is nice. It's also programmed through JTAG. So you can see, if I zoom in a little bit, you can see that there's TDI, TMS, there's VPP, oh, there's TDO and TCK. So with these four signals here, that's a JTAG interface. It's a small JTAG interface. So that's the programming interface. And there is a programmer that I've got here. This comes from Microchip. I think it costs like 60 bucks or something like that. But it's got the connectors on the back that you would connect to this interface. And it would be the JTAG-A interface that you use. So that's the thing that contains the TDI, TMS, TDO, and TCK signals. It also contains ground and power. So this connects to USB to your computer and then you use Microchip's software in order to create the logic and then that generates the fuse map and then that goes into the chip when you program it. So there you go. This would be in-circuit programmable because in the schematic, I leave those pins unconnected. So I could just put a JTAG connector next to it and then just plug the programmer in and reprogram the thing. I don't really wanna do that for several reasons. One is that in order to do that, I would need to power up the entire machine. And that would be, I don't know what would happen if I powered up the entire machine and programmed the chip at the same time. And the second thing is that I'm using the PLCC package with a socket so I can just pop the chip out, put it into the programmer. This is not a programmer per se. I mean, it is kind of a programmer but you still need a carrier board. And there is a board that I'll link to down below developed by S100 computers, which actually takes the JTAG interface and has a socket and you can pop the chip into the socket and program it. So that's kind of nice. Okay, so those are the CPLDs over there. Let's take a look at the immediate decode. Now the immediate decode is a little more intensive because this time it does depend on all 32 bits of the instruction. So it's not really easily separatable. So if you look at it, I basically implemented it as one of those big connectors. And the idea is that I'm gonna create a card that slots into here. So I decided that I wanted to have it as kind of a separate module. It is gonna be kind of complex, maybe multiplexery-like, maybe a bit ROM-like. I'm not really sure. So I decided to just punt and say, well, I'm just gonna include a card slot for it. And that way, if I want to change the formats or add new instructions or implement more instructions, I can just pop the card out and just redo that card and then pop it in. At least that's the theory. All right, let's take a look at some other things. Okay, so let's take a look at the sequence of ROM. So what I've done is I've loaded it up with all the signals that it takes in and all the signals that it gives out. So these are all the output signals over here. These are all the input signals over here. And there's, of course, this output enable. So I did say that the sequence of ROM has only 20 bits in. Well, what are these things over here? Like why am I taking all 32 bits of the instruction and all 32 bits of the memory address? Well, the answer is that I don't actually use all 32 bits of the instruction. In fact, I only use a few. And the same thing with the memory address. In fact, I only use the low two bits of the memory address. And that's mainly to make sure that I'm not doing like a misaligned loader stores or something like that. Is that right? No, it's something else. But anyway, the point is that I still have to put the entire bus in here. I can't just say mem address zero to two because I'm not really sure what Kaikad will do. And the same thing with the instruction. I can't simply say like, let's suppose I use bits 12 through 15 as an example. I don't think I can simply say instruction 12 through 15. I think I have to feed the entire bus in and then do something like I did with bad, not bad instruction, misaligned PC where I feed in the entire bus but I only use a few signals. So in any case, those are the 20 bits in. Now the sequencer ROM, if I go in there, you can see that I have these hierarchical pins but they're not actually connected to anything. They will eventually be connected to card slot connectors. And I have to go back to the flash ROM card that I made to figure out where all of these signals actually go so I can route the signals to the proper pins on the connectors. Same thing with the trap ROM. That'll go to a connector. So right now I just have all of these signals defined. Let's see. So what I thought I would do today is just create this CSR select block. So what is the CSR select block? So you might notice that all the way here at the edge of the schematic, I've got these lines going to nowhere. And this is just me saying these will eventually go to some card edge connectors which are sort of external to the sequencer. So you can see that the X, Y and Z bus will go to this big bus that will go to other cards. The mem data write signal, and I guess I should do the same thing with memory address. Why don't I just do that right now, mem address. So those will go to the memory. Temp actually doesn't go anywhere. It's a temporary register. It stays where it is. EmptyVec and PC are only used internally so they don't go outside the sequencer card. There's this line over here. Where does it come from? That is the ALU op to Z. So that's part of the bus that goes to the ALU card to tell it what to do. So CSR num is one of those signals that goes out to this big bus. And that way you can plug in different CSR cards and those cards will be enabled when it sees that its number is in the CSR num section of the bus. Now there are 12 bits to the CSR number because it's a 4096 address space. And what the sequencer card does, what the sequencer card does is it can do one of three things. It can either put the MEPC CSR number onto the CSR number or it could put the MCoS CSR number onto the CSR num or it can take the FUNCT12, 12 bits of the instruction and put it into the CSR number and that would be for the CSR instructions. So MEPC and MCoS are for when we're busy creating a trap. FUNCT12 is for the ordinary CSR functions. So what I need to do is create a number and a block that looks at these and uses also the input from the instruction because FUNCT12 is gonna be 12 bits out of the instruction and then outputs 12 bits of the CSR number. So let's go into the block and so I've got some pins here already. Okay, so these are the ports that I'm gonna use. There's gonna be another port here. So that's the instruction. So when FUNCT12 to CSR num is high, what I wanna do is I wanna feed the 12 bits from the instruction to the CSR number. If MEPC num is high, then I want to feed the MEPC number into the CSR number and the same thing with MCoS. CSR num is MTVEC is a special signal that I need because the sequencer card also holds the MTVEC CSR. So I need to know if the instruction is calling out the MTVEC. So that's gonna be a comparator signal. Let me just move that down a bit, somewhere over there. All right, so how are we gonna do this? Well, the most straightforward way of doing this is to have a multiplexer. So there would be a 12-bit multiplexer. The other way that I could do this is I could turn it into a ROM because I've got 12 bits of the instruction and then I've got these three other bits. That's 15 bits, which is a 32K by 1213. 32K by 13 ROM. So the question is, what do I do? Well, if I wanna make this a multiplexer, then I'm gonna need 12 bits and I know that I have 16 bit and I also have eight bit and I probably also have four bit buffers. That can be tri-stated. So if I do that, let's see, let's take a look at the LVCs that are available and see if there's like a four-bit multiplexer. So let me go 74LVC and let's just take a look at what we've got here. So what I'm looking for, so here's a single buffer. Obviously, I don't need that and what I actually want is a tri-state buffer. So let's see. So there's a single tri-state buffer. That doesn't really help. Yeah, maybe I shouldn't be looking at the 1Gs. I should probably be looking at the LVCs that I've already looked at. So, yeah, that's not it. Yeah, so it's just going to be an octal buffer. There may be something in the LS series and if I'm lucky, there's an equivalent of the LVC. So let's see. Can I just type in like tri-state? I'm not seeing that. Can I just type in like buffer? Here's a four-bit bus transceiver. That's kind of like that. I mean, even though it's a bus transceiver, which usually means bi-directional, so if there is a 74 LVC 243, that would be great, but chances are there aren't any. I'm going to go take a look at it right now. Okay, so the answer is no. You only get to use eight-bit buffers or if you want to use the single-gate versions, you can use those. So that kind of means that I'd be wasting some of the bits because I'd need 12 bits, which means that, I guess I could use a 16-bit buffer and then I'd use three chips basically, which I guess is okay. Um, yeah, let's just do that. Okay, so what I really need to do is go to some place that I had those 16-bit buffers and I may not have used them anywhere. No, those are six bits. No, okay, so what I'll do is I will just go ahead and grab a 16, 373, no, yes, this is a latch. That's weird, why isn't it coming up? Well, I know where I do have one. I'm just going to load it up right now. See where is it? Right here, it is 74 LVC 16244. So I'm just going to grab that with its power and ground, go up one, copy it in here and then delete that sheet. Okay, so just kind of a roundabout way of getting this chip in here. So it's kind of a big chip. And I'm going to need three of those. So let me go ahead and move these ports out of the way. And what I'm also going to do, originally what I was doing was I was putting the decoupling capacitor right here. And I don't really need to do that because in fact, this requires, oh, wait a minute, I just noticed something. These actually have separate output enables for every four bits. This is a good thing because now I could use one, two, three. Oh, I guess it doesn't matter. One, I could use three quarters of the chip for one signal. Another three quarters of a chip for another signal and then another three quarters of a chip. That's nine quarters of a chip. Unfortunately, that's two and one quarter chips. So I still end up with three chips. Oh, well. So that means that I may as well just use one chip per signal. Okay, anyway, what I was saying is that this thing actually has four VCC pins. So you want to decouple each one of those. So I usually put the capacitors on the side like you saw before. So there's no real reason to have these wires connecting the VCC and ground. I could just make this a little more compact. Okay, so here we go. What I'm gonna do is attach a wire to the output enable to all the output enables like this. Okay, and that's gonna be the signal to our signals, right? The other thing is these inputs. So let me go ahead and just add a bunch of these inputs. And the bottom ones are never gonna be used. So I'm just gonna tie them to ground because you always have to tie inputs to something. And then that means that these outputs are also not gonna be used. So I can just no connect them. All right, and these outputs, the outputs that are all gonna be tied together, and they're gonna eventually become CSR num. So I can name them now. Let's just do that. Grab these and move them to here. And this is a bus, so let's do that up to a bus, which I will then connect to something else. All right, so this is my module effectively that I'm gonna multiply three times. So I'm gonna have three of these. Now one of the unfortunate things is that I've used mainly positive logic all over the place in other words, when I want to activate a function, the signal that controls that function is a one and not a zero, but in a lot of chips you can see like output enable is negative, so it's active low. So I am gonna have to invert these signals. The alternative is, well, there is no alternative. Well, yeah, okay, so there is one alternative and the alternative is that instead of outputting three separate signals, I can output two bits, which encodes these three signals. And then I can use a three to eight decoder or a two to four decoder if such a thing actually existed in LVC, which outputs negative signals. Unfortunately, that's just more chips. But then again, I have to invert these signals. So those are these little tiny individual packages. I think I'll suffer with the individual packages. I think that's okay. So let me go ahead and grab an inverter from somewhere. Nope, that's not it. That's not it. Where do I have an inverter? Here's one. Let me just grab that and let's put that here. Okay, so. So I'm gonna need three of these. One, two, three. I am probably gonna wanna move this over a bit and let me copy it. Are those aligned? This one is not aligned. For some reason, it's hard for me to see whether these things are aligned or not. And I know that I can turn on this little crosshairs thing but sometimes that gets really annoying. So I'll turn that off. Okay, so these are my three things. First thing I can do is I can connect these buses together. That's an easy thing to do. And the output is CSRNUM. So let's just go ahead and grab it from here. The signal to here. So this is of course not CSRNUM. It is actually CSRNUM 0211. I think I'm gonna have to take all of this and move it over say here to fit everything into this small sheet. And then I've got this other thing which I'm gonna have to deal with. So that's gonna be some sort of a comparator that I'm gonna have to hooky up. All right, so let's move the instruction down here. Funked 12, this thing, nothing. Okay, so wire to here, wire to here and wire to here. All right, so let's suppose that this first one is going to be for Funked 12. Second one, second one is MEPC. Third one is M-CAUSE. I have a feeling that I'm gonna have to make this page bigger in order to fit in the comparison block. The other thing is the other possibility is that I can just make it a separate block. But let's just fit it into this block. So the next thing is instruction. So I need to figure out which bits out of the instruction I need. And that turns out to be the high 12 bits of the instruction. So let's go ahead and give me a label here. So there's, no it's not Instruction 12, it's Instruction 20. I can take these four and move them to here. These, these four and move them to here. And now some bus things and let's move the instruction input. Okay, so, oops, bus, all right. So, okay, that is the part of the multiplexer that will select the 12 bits out of the instruction when Funked 12 to CSRNUM is active. Okay, now we've got MEPC in here. We've got MEPC NUM, it's a constant. So the constant in hex is 341. So let's see what that is. So what I'm gonna do is I'm just gonna run a ground line. I mean a one here and a zero here. And I'm just gonna put junctions for where the things are. So 341, so let's start from the high bits. So three is 0011. So there is 0011. Four is zero, why is this difficult for me? It's difficult because I'm thinking that this line right over here is on the bottom, which to me means zero. So I'm gonna make this make sense to me. Okay, let's try this again. So zero to me is on the bottom. One in my mind is at the top. Okay, now, junction. 341. So that's 0011. Four is 0100. And one is 0001. There we go. And I'm gonna put a reminder here for me that this is MEPC. And now we do the same thing for this one, except instead of MEPC, it's M cause. So let's go ahead and say copy this. So that's M cause. Well, let's draw the lines. So those are one and zero. Now, this sort of thing is quite literally a matrix, a ROM matrix, except in this case, I'm sort of selecting which address I want using these multiplexers. So that's what that kind of looks like to me. Let me just double check 341. Yep, okay. M cause is 342. So it's basically the same 34 and two, 0010. Okay, so that's M cause. So I suppose I could actually combine these things, considering that MEPC and M cause only differ in the last two bits. So I could probably just turn that into logic, but I would still need one of these chips to multiplex between funk 12 and this. So overall, it's kind of, I think, just easier. Slap another chip in here. Okay, now, how do we determine whether the CSR num that we're outputting here, right over here, is MTVEC? So what I'm gonna do, first of all, let me put a note in here saying that M cause is 342. And then for MEPC, that it's 342. For MEPC, that it's 341. Okay, now let me put another note saying what MTVEC is. So text. So MTVEC is 305. Okay, so I need a comparator that will compare the 12 bits to 305. Now, we've already done comparators before for the instruction. So let's go to the instruction comparator for bad instructions. And we can see that what we've done is we've used these open drain inverters and buffers. Now, you might think, oh, hey, that's great. There are six of these per chip. So I just need to use two chips. Well, that's not true because some bits I need to compare to one and some bits I need to compare to zero. If I need to compare a bit to one, then I need the 07. And if I wanna compare a bit to zero, then I need the 06. So how many of each chip do I need? Well, MTVEC is 305. So how many high bits are there? Well, three, that's two, and five, that's another two. So I'd need four comparisons to high bits and the rest were eight comparisons to low bits. So in fact, I need three of these chips. So what I'm gonna do is I'm gonna grab one of each CSR select. Do I have enough room for this? No, I probably don't. So let me expand the sheet. That's enough room. I can put it right over here because I need to feed off of CSR num. So what did we say? The 06 was for comparing to zero and the 07 was for comparing to one. So I need another 06. Let's put that down here and then I can just sort of tighten this up a little. Okay, so now what I need to do is feed the various CSR num signals into here. So CSR num 8 to 11 should be three. So in other words, I want 11 and 10 to be zero, which means I need 11 and 10 over here. So I'm just gonna start from the bottom and I'm going to just take CSR num 11 and put it down here, CSR num 10, and put it down here. And then I need high bits here and I know that there's gonna be four of them, okay? So CSR num 8 and 9, that there. Okay, what's the next zero? So I need to compare the next four to zero. So that's CSR num 7, six, five, and four. Okay, and now I need five, which would be zero, one, zero, one. So three needs to be a zero, two needs to be one, one needs to be zero and zero needs to be one. So that's our pattern. So I don't need these lines now, okay? So that's what that looks like. Yeah, and again, there aren't any eight-bit versions of these. This is all you get. So the LVC series is quite limited. I guess because by the time they needed LVC, they kind of knew from the LS series what people were using. So, okay, so this is all in a bus. So let's go ahead and have these bus taps in here, okay? I can take that and just connect these two buses because that's CSR num. The other signals I now have to tie to ground. These are the unused signals. And I need to no connect the signals that I don't use. Okay, so we need to tie all of the outputs together. So let's do that, easy enough to do. Okay, so all the outputs are tied together. We need a pull-up resistor. So let me go grab a pull-up resistor from somewhere. From somewhere, here's one. I used 10K just because 10K seems reasonably high enough that it isn't gonna cause so much current that things are bad. Okay, so there's my pull-up resistor and now here is my output. Now, the question is, is the output gonna be zero or one? Well, we said that as long as all of the outputs are one, we're gonna get a one. But, so this is a straight through buffer and these are the ones. So in fact, I'm gonna put a, no, I'm not gonna put a node in here. So these are ones. So I want these to be ones and these are inverted. So these are all zeros, which means I believe that I don't need to invert this signal. Now, sometimes I get things backwards. So let's double-check. So for five, we want zero and two to be one, right? Because the low four bits are gonna be zero, one, zero, one. That's five. So these are gonna be ones. So those are gonna result in high impedance on the output. So if any one of those are zero, it's gonna pull the output to zero, which is correct. So, you know, and because these are inverted, one and three would need to be zero in order for the output to be high impedance, which is correct because if any of those is one, the output is gonna be zero and that's gonna pull this down to zero. And that is my circuit. So there we've created that block. Again, I'm not gonna put the capacitors in until afterwards. I know that each of these is gonna require four capacitors and each one of these chips is also gonna require one capacitor. So, you know, that's 15 capacitors in here. I could just slap them down right now, but I'll, oh, and then we've got these three inverters. Probably together they need one more capacitor. So, you know, afterwards I'll just do a pass throughout the entire schematic and put the right capacitors in. Yeah, so that is the CSR block. So let's go ahead and import the signals. So there's the CSR num, which is the output. We've got instruction as an input. This thing as an input. This thing as an input. And there's an additional input, so I'm just gonna need to make this a little bigger. Okay, so I can take this and let me take this and move this down. So it kind of looks like that. I can actually tighten this up a bit. That's why I sort of offset the outputs from the inputs instead of doing something like this where the outputs and inputs are on the same line because you can compact this thing a little better. Okay, so let's order the inputs the same way that they're ordered here. So funk 12 would go on the top and m-cause would go on the bottom. So I need to move these down. I need to move this up one and this down one. Okay, and now I can just say m-cause goes to here, m-e-p-c goes to here and funk 12 goes to here. Okay, now where is instruction? It's actually up here. So I can just say instruction comes from here. And now I've got CSR none, which I know goes to the outside of the card. And there we go. There is our brand new block. So things like X-Reg cell, I think those go straight out. Memrite goes straight out. Memrite is a little difficult because I know that there is another signal here that's generated from the IRQ load ROM. And there's nothing that's generated from the trap ROM. So I just need to figure out what I need to do for that. Same thing with Memrite mask, that goes straight out. Reg to X and reg to Y. Those also go out to the bus. And I think that's probably it. So in fact, a lot of this is already done. So we can take another look at the whole big thing. So this is, yeah, this is another thing that I need to work on. So this is the incrementer. It's gonna increment the PC by four. So here's the PC. It comes out of the card. It goes into the incrementer and it goes back into the multiplexers so that maybe PC can be loaded with increment with the incremented PC. So what does it look like right now? It doesn't look like anything. So I'm gonna need to figure out what I wanna do. Now, I could use the LS ALU chips. There is no LVC version. So that's gonna be a bit of a problem. I don't wanna make this a ROM because that would be a four gigabyte ROM. I could split it into eight bit sections. So that would be a 256 address or eight bit input. And then the output would basically be a carry plus the sum. So that would be actually nine bits out. And actually that would be nine bits in because there would be a carry in as well. So I could have a 512 by nine ROM for those daisy chain together. The problem with that is that they're daisy chain together which means that if each ROM is 70 nanoseconds then I would have to wait 280 nanoseconds for the output which doesn't make any sense. The other possibility is that I can use carry look ahead units but that still doesn't get around the fact that each chip is gonna result in a 70 nanosecond delay. And in the case of carry look ahead that would be three delays which isn't that much better than four. So that's a problem. So the alternative is that I could use the five volt ALU chips. And I can probably get away with that because three volt logic is compatible if you plug it into five volt logic because the input logic levels are compatible. For five volt logic, you have to go above like, I don't know, I think it's 2.4 or 2.8 volts and 3.3 volt logic does output that. So if you take a 3V3 output and put it into a five volt input, it'll work. The question is now, what about a five volt output? Okay, so that's your increment PC. So that would go into this multiplexer card as a five volt signal. So the question is, are the chips on the multiplexer card five volt tolerant? And I think the answer is yes. The ones, so increment PC is the input to a multiplexer. And for multiplexers, I use these 16244 chips. Now let's go ahead and look up the datasheet for that. Okay, so here we go, 16-bit buffer line driver. Right away it says five volt input output tolerant. So that'll work. So yeah, so I shouldn't have any problem to use those 74 LS series logic chips, ALU chips. So here's what I'm talking about in terms of the logic units. So there's a 74, so this is a four-bit ALU. It can do add, it can do a bunch of other things, but of course I'm just gonna be using it as an add. And it's a 181 four-bit, so I'm gonna need eight of these. And then there's a 182, which is a carry look ahead unit. So when you're using one level of carry look ahead, I think that you can connect eight of these chips together. Yeah, I'm not actually sure of that. Let me find out. Okay, no, I was wrong. You can only connect four of these together. So if I wanted to have a 32-bit ALU, then I would need two layers of carry look ahead. Right, because each one of these carry look ahead units can handle 16 bits, so I would need an additional one. The alternative is that I could just live with the delay. So every time that you have an ALU and a carry look ahead, so the ALU generates outputs, which the carry look ahead uses to feed back into the carries. And then from the carries, you go to the output, so that's three delays. And that's for 16 bits. So if you want to do a ripple carry, that would be another three delays for all 32 bits. If you want to add a layer of look ahead, then let's see, you would have just one more delay, I believe, so that would be four delays. Let's take a look at what a delay looks like. So all we have to do is look for the propagation delay here and we see that the propagation delay typically, let's just go with the highest one, it looks like around seven nanoseconds, which is actually pretty good. I mean, that's sort of on the order of a gal. The fastest gal is seven nanoseconds. The fastest CPLD, the ones that I'm using is 10 nanoseconds, so that's on the order. So actually what I could do is I could probably use those CPLDs as a replacement for these so that I don't have to use them in dip form. They're 3V3, so why don't I just do that? Yeah, why don't I just do that? So I think that's allowed because I'm basically swapping one chip for another. The alternative is, I could, yeah. So the alternative is that I could say, well, you know, those CPLDs, they have a lot of inputs and outputs, so I could probably have two of these ALU chips in one CPLD. But my rules don't allow that. Remember when I said that, you know, if I had a bunch of logic here and a bunch of logic here and they were completely independent, I could turn each one into a ROM, but I'm not allowed to combine them because that's basically a squaring function. It's O n squared in terms of the number of inputs. So I don't wanna do that. Now, yes, you could argue that, well, you know, if you have four bits, if you have a four-bit ALU here and a four-bit ALU here, you know, that's however number of inputs they are. But once you add a carry look ahead unit, you can combine those inputs, but you don't get order n squared. You still get order n. Yeah, that's a little bit of a tenuous argument to me. So instead, I think, you know, maybe I'll just use one CPLD per chip. So how many chips does that mean? Well, the 181s, those are four bits each and I'm gonna need eight of those. And then the carry look ahead units, I'm gonna need two layers. So that's two chips on the first layer and one chip on the end. That's three chips. So that's 11 total CPLDs. I guess that's okay. Now, because that's 11 of them and I'm gonna need them in sockets, they are gonna be kind of big. So instead of putting it on the sequencer itself, I think I'll just end up putting it on a card. And the interesting thing is the ALU is gonna be the same thing, except that instead of addition, I'm going to do a bunch of other operations. So maybe I could just create an ALU card and just get away with tying some of the inputs to be hard-coded to add. There we go. There's my solution. So when I go back to here, so what's gonna go in between these is basically a card connector for one of the cards. In this case, an ALU card. So that's interesting. Now, I could get away with a single connector because remember, a single connector contains three 32-bit buses, one or possibly two four-bit buses and then a bunch of extra signals. So for the generic card, I'm gonna have to use two connectors. If I only cared about an ALU card and just PC in and incremented PC out, I could get away with one connector, but then I'd have different boards. So I don't really wanna do that. So I just don't wanna do that. The other possibility that I could do is that I could maybe get away with is finesse things so that all of the signals that the ALU needs are on one of the connectors of the two connectors in the general bus. But I mean, that's just, I don't know, that's just too ridiculous. I mean, there's optimization and then there's going a little too far. So that's just way too much optimization. So I think what's gonna happen is I'm gonna have two card connectors over here. Now, I haven't decided where the buses on that card connector go, but that's gonna be over here. So what I'm gonna do is I'm gonna say ALU card here and there we go. So that's my solution. Okay, so anyway, this is basically most of it. There are a few missing pieces. Remember I was talking about Excel, how Excel actually has three possible inputs. So I'm still gonna need to create a little hierarchical module for Excel. There's the reset signals, which I need to tie all together. There are the clock signals, which I need to bring out onto the general bus. And I think that's pretty much about it. So yeah, so there it is. Oh, here's my little diagram of the clock. So you can see here's pH one, here's pH two, here's the right cycle of pH two. And then I call this pH two read because I thought it would be over here, but in fact it is over here. So that's kind of a misnomer. But anyway, that's the signal for loading the memory into the instruction register. So that's kind of neat. Eventually I'm gonna need to make a clock generator for this. But in any case, these clock signals go on that general bus to feed all of the cards. So there it is. There is the sequencer. So the thing that I'm gonna need to do is go over the ROM cards for this and assign signals to those connectors. There was another one here, which was the immediate format, which has a connector. So I'm gonna have to figure that one out. Then I need to decide what the external connectors are gonna be for the bus. And then I need to decide what the connector is gonna look like for memory because memory is a whole separate system. So those are really the next steps. So thanks for sticking with me so far. This is really interesting. This is kind of a nice pleasing diagram. I may actually move some of these blocks around to make it look a little nicer. But for now, I don't really care that much. All I care is that this is correct. So I'm gonna have to double check this against the logic and the code. But that's, I guess, about it. So thanks for watching. See you on the next video.