 This is a single 32-bit register for a RISC-5 processor. I'm building a RISC-5 processor, not on an FPGA. Greetings, processor friends. Today I'm going to talk about the RISC-5 processor. Now, RISC-5 isn't actually a processor. RISC-5 is not actually a particular processor or a particular class of processors like ARM or x86. It's an open instruction set architecture, which means that there is a free paper online which specifies the instructions and their formats and there's also an application binary interface so that anybody can implement a RISC-5 type processor. Now, the nice thing about the RISC-5 ISA, aside from it's being open and completely license free, is that it's modular. So there are a bunch of modules that you can implement for a RISC-5 processor. The only required module is the I, which is the integer instruction set. There's a 32-bit integer instruction set, a 64-bit, which is optional, and a 128-bit, which is also optional. There's also the E extension for embedded processors, which essentially reduces the number of registers available. Then there's the M extension, which stands for multiply and divide for integers. Again, this is an optional extension. The only required extension is I. A are for atomic memory operations. F, D, and Q are for single, double, and quad precision floating point numbers. And C is for a compressed or variable size instruction set. The instructions in 32i are all 32-bits long, but there is a compressed version where the instructions can be, for example, 16-bits long, and you can have two instructions per word. All of these extensions have been pretty much finalized and frozen by the foundation, but there are a bunch more extensions in the works. For example, L are for decimal floats, like, for example, in a calculator. B is for bit manipulation, so things like setting and clearing bits. And then there are other extensions, which are mainly placeholders for when they become defined. V is an interesting one. It's for vector instructions. Now, aside from it being modular, it's also regular in its instruction format. So if you look at the instruction formats, you can see that decoding an instruction takes very little effort, unlike, for example, the crazy way that x86 instructions are encoded, or z80 instructions. It's also extensible. There's a range of instructions which are reserved for customized instructions. So if you're a manufacturer of processors that need to do very specific things in an efficient way, you can encode them as custom instructions. Now, of course, the processor is in the risk class, reduced instruction set. These aren't complex instructions, and there are very few of them. There's less than 50 instructions in the basic set. The basic set is called g, the general extension, which means that your processor implements i, which is, of course, required, integer, multiply, and divide, atomic memory operations, and single and double precision floats. One of the interesting things is that the risk five spec specifies no status flags. So things like the zero flag, the carry flag, they just don't exist in risk five. That can be actually taken care of by other instructions. Risk five also defines four privilege levels of execution. The highest one, of course, is the machine level, which is required, but then you get hypervisor, which would be for virtual machines. The supervisor level, which is for your operating system or kernel. And then finally, all the way at the bottom is the privilege level for the users, which is the application level. Now, if you want to take a look at the specs, they're available for free online at riskv.org. And the main reason that I'm doing this is that, yes, I'm starting another project. This project is going to be about creating a very basic risk five processor out of discrete logic. Now, I don't mean simple ands and ors, things like buffers and counters and flip flops, that sort of thing. Now, it's very popular to create a risk five processor using an FPGA. It's very simple. I decided that I wanted to make it out of discrete logic because I wanted people to be able to see the various parts of the processor, adding LEDs so that people can see what parts of the processor are doing what, so that they can learn about the internals of a risk five processor without just seeing a single chip that claims, I am a risk five processor. Now, in risk five, there are registers, and these registers are 32-bit registers. The specification states that there is a program counter, PC, and 32 32-bit registers, labeled X0 through X31. Now, I've set aside X0 because that, when you read it, is always zero, and when you write it, nothing happens. The reason for this is that zero is an often used constant, and very often, you'll see that compilers actually set aside a register simply to hold zero. Well, the creators of risk five recognize that and simply decided to formalize that. Now, the ABI, or Application Binary Interface for risk five, specifies that certain registers are for certain uses, and each register has a particular name in the ABI, which you will see if you look at an assembly language listing. So, for example, X0, which we know is always set to zero, is simply called zero. X1 is used for return addresses. X2 is the stack pointer, X3 is a global pointer, and X4 is a thread pointer. Now, X5 through 7 are temporaries, zero through two, so any subroutine can use them for anything they want. And the caller can't make any assumptions about what the values of T0 through T2 are going to be after a subroutine returns. So, X8 is a saved register, or a frame pointer, and X9 is another saved register. X10 through X11 are A0 through A1. Now, these are arguments that get passed from one subroutine to another, and return values that get passed back. X12 through 17 are arguments 2 through 7. X18 through 27 are also a bunch of saved registers, and X28 through 31 are temporaries. Now, the registers that I've marked with star are cally saved registers, and what that means is that if a subroutine wants to use these registers for something, they have to save the original state of the register, and then just before they return, they have to restore that state. Which makes sense for a stack pointer because, of course, if a subroutine needs to push things onto a stack for whatever reason, it needs to make sure that the stack pointer is restored just before it returns to its caller. So the same thing is true of these saved registers. That's why they're called saved registers. So the ABI is not my concern at this point. My concern is simply creating the hardware for a risk five processor. So what we're going to do is we're going to start with the basic register set. Now, again, we're going to implement only the simplest required extensions of risk five, and this would be the I instruction set, or the integer instruction set. And we're also going to implement it in 32 bits. So we're going to be implementing the 32 I extension only. In the 32 I extension, all of these registers are 32 bits. So we've got a program counter, and we've got 32 32 bit registers, one of which is always hard coded to zero. Okay, here's a 32 bit register. It's very simple. There's a clock, and on the rising edge of the clock, the register stores the value that's in the D input and always outputs that value on the Q output. There aren't any 32 bit registered chips, but there are 16 bit registered chips, which is what I'll be using to implement the registers. Now, most instructions look kind of like this. They have a destination register, and they have one or possibly two source registers. The rest are used for opcode values, immediate numbers, that sort of thing. Some instructions only have the destination register. Other instructions have one source register or two source registers. So for example, if you want to add two registers and store it in a third, you specify all of these. If you want to add an immediate value to a register and then store it in another register, well, that would be the instruction format that doesn't have the RS2 value. So here's kind of a very simplified view of what happens in an instruction that specifies two sources and a destination. So here we have our two sources, let's say the registers X2 and X3, and they send their values into some sort of operation. Maybe it's an ALU or some other piece of hardware. The result of that operation goes into the destination register, and here I've specified it as X1. So obviously we need some sort of a clock over here, and obviously we're going to have clocks here and over here. And of course, depending on which destination register is chosen, you would clock that particular register to store the value. Now in the same way, you can specify any of these registers as source one and source two, which means that we're going to have to have some sort of a multiplexer over here in order to choose which register goes onto which bus. And that's one of the keys to this architecture is that I'm going to have a destination bus and two source buses, source one and source two. So let's see what that looks like. So this is basically the circuitry for a single register. We have our 32-bit D flip-flop right over here, and we also have two 32-bit tri-state buffers. We have a destination bus over here, and we have two source buses over here, and all of those are also 32-bits wide. Now for each register, we have a clock signal which can clock the data from the destination bus into the register. And we also have two tri-state enable signals, one which will put the value of the register onto the source one bus, and the other puts the value of the register onto the source two bus. Now you can imagine an instruction that, for example, takes the value of the register and adds it to itself and then stores it to itself. And this will handle that. All you have to do is enable both of these buffers so that the output of the register goes onto both source buses. Those source buses feed into the adder, which outputs to the destination bus, and when you clock the register, the value in the destination bus goes into the register itself. So this will handle basically all combinations of registers. So let's just say that this is our register circuitry for a single register. So in terms of the number of signals, well, we have 32 over here and then 32 for each source bus, and we have these three control lines, so that's already 99 signals. Now I've chosen a 196-bit bus, and the reason for that is signal integrity. Now on a printed circuit board, what you want is a ground plane, and then you want the signals traveling on top of that and on the bottom of that so that the signals don't affect each other and that they can propagate cleanly. Now, when you go from one printed circuit board to, say, a card on another printed circuit board, the problem is you don't just want to pass the signals up through the connector. You want grounds to be connected between the signals on the connector. That way, each signal is still close to a ground at every point along its length. So that's why instead of 32, it's probably more like, I don't know, 48 or so signals. So when you multiply all that together, and then instead of having maybe just three buses, you have the capability of having a fourth bus for whatever, you end up with about 196 signals. Now I can do that using a PCI Express socket, which has 98 signals in it, 98 times 2 being 196. Let's take a look at a concrete implementation of what I just discussed. So here is our register, and here are some buffers for source 1 and source 2. Now I've chosen a 74 LVT16374. This is a 16-bit register. LV indicates that it's low voltage, in other words, 3.3 volts, rather than the usual TTL 5 volts. And the T means that it's ABT technology, which is a by CMOS technology. It just means that it's a little bit faster than the usual CMOS. And for the buffers, I've chosen the 74 LVTH162541. These are also 16-bit buffers. Again, they're LV, so they're 3.3 volts. T is the technology, and H means that these have bus hold feature. Bus hold simply means that if one of the inputs is disconnected, then the input is forced to one or the other logic value, as opposed to simply floating and possibly one or possibly the other. The disadvantage in bus hold is that it requires a large amount of current in order to force the input to a particular state. Now the other reason that I've chosen the H version is that the plain old LVT version is already obsolete. So they don't sell them anymore. Now, since we need 32 bits and not 16, you basically take this and multiply it by 2, and that's your 32-bit register. You connect all the clocks together, you connect the output enables for source 1 and source 2 together, and you're done. So that would be two of these, and then of course you would multiply that by 31, because we need 31 registers. Remembering that register x0 is always 0. Now here's an alternative architecture. What I've done here is I've eliminated the two buffers, and the reason for that is that the 16-bit registers have output-enable signals. The problem of course is that these registers don't have two outputs, which you can enable one or the other. So you have to have two registers with their inputs connected, and they will store the same value. And then you can simply output one or output the other, or output both, or output none, depending on the output-enable signals. So at first glance, this looks a lot better than the previous architecture because we're only using two chips rather than three. Of course, remember that you have to multiply this by 2 in order to get all 32 bits, so that means that you would have four chips rather than six chips. And that might add up, because again you have to multiply by 31 for the number of registers. Let's also compare the two architectures by cost. Now in quantity 100, because of course we're going to need a whole lot of these, each of these registers is 62 cents from DigiCy, and each of these buffers is $1.59. Whereas if we go to this architecture, of course, we're only spending twice 62. So if we add up the cost overall, this version costs less. So that's a plus for this architecture. If we also look at the drive capability, here's the datasheet for the 16374, and if we take a look at the output current, we can see that these registers can source 32 milliamps. On the other hand, if we look at the 16251 datasheet, these buffers can only source 12 milliamps. So in my opinion, that's another plus for this architecture. Now it would be nice to be able to display the current contents of each register. We can do that very simply over here by adding an LED, and they would all have a jumper to ground in case you wanted to disable them. And you can very simply add that into the circuit right over here, because this will take very few milliamps. On the other hand, for the bottom circuit, you don't have that capability. You would in fact have to add another one of these just to display the register value. And that would be another 62 cents, first of all. That would be another chip, so now our chip count is now identical, but our cost hasn't gone up enough to exceed the cost of this top one. So overall, that's probably a neutral. Now you might be asking yourself also, well, there are 8-bit versions of this. What happens if we go to an 8-bit version? Well, one of those in quantity 100 costs 54 cents. So if you need two of those to make 16 bits, that would be $1.08, which of course exceeds the 62 cents required for the 16-bit version. So it really looks like this bottom architecture is what we want to go with. What's this that I received today? It's printed circuit boards and bonus LEDs, I guess. So these are the printed circuit boards for the register cards. I got 50 of them. It even came with a pen. So here's one block of the printed circuit boards. Now you'll notice that I didn't have these fingers gold-plated. Usually you have fingers gold-plated when you plan on taking a card and inserting it and removing it and inserting it and removing it continuously. And I felt that it just wasn't worth the expense for this because most likely I would just be plugging it in and leaving it there, so I didn't really care about having gold fingers. Also, what's this that I happen to get in the mail at the same time? It's a stencil for the board. And the reason that I got a stencil is that I will prototype one by hand soldering it, but if I want to do a bunch, well, a stainless steel stencil is really the way to go. You just put solder paste on it and then you throw it in the oven. Well, not throw it, but you place it gently in the oven a bunch at a time, say maybe four or five at a time, as many as will fit, and you've got your board soldered. And since I need at least 31 of these boards, possibly even 32 for register zero, investing in a stencil is a pretty good idea. And normally in the package you get a solder paste spreader. Now I have seen people use some kind of a special squeegee to do this, but this works pretty well anyway. And I got a bunch of stickers. Yay, we can all use more stickers. And also a few days ago I received 2,000 LEDs. Now I really only need about a thousand, but I figured you may as well have some extras and they were really, really cheap. So go to aliexpress.com and search for LEDs. Now this may be a little hard to see, but so I have this case of LEDs, just again a cheap sort of sample pack of LEDs, and the one on the right came from that sample pack and the one on the left is the ones that I ordered from Aliexpress. Now it may be very, very hard to see, but you can see this kind of a lip on this LED on the right, and there's no such lip on the LED on the left. Now they're both 3mm LEDs. That refers to the size of the top. It doesn't refer to the size of this what's called a flange. And the reason that these have a flange is so that you can take the LED and stick it in a 3mm hole and then it just sort of stops at the flange. While this has no flange, it's called flange-less, and the reason that I needed it flange-less is that the spacing on these pads is just small enough to fit 3mm LEDs, but it can't be any larger than this because otherwise the board would be bigger. And unfortunately, if you take the flanged LED, it turns out to be something like, I don't know, 3.2mm or 3.3mm, and that 10% or less adds up when you are dealing with 32 LEDs in a row. So that's why I opted for the flange-less ones. They're rarer, but when you find a bag of a thousand for like 10 bucks, you go ahead and buy it. So, of course, now that I have one of these printed circuit boards, I'm going to just build one of them. And I think I'm just going to populate one of the chips in each storage box. I don't really need to populate the second one because each chip has 16 bits, and I don't really need to test all 32 bits, except maybe when I'm doing quality control. And really, I only need... I only want to test a single bit out of this. I want to make sure that we're storing the bit in all of these registers and that the bit gets displayed on the correct LED and that when I enable either Source 1 or Source 2, that bit appears down below. So that's really all I'm going to do to prove that the basic idea works is that I haven't made some terrible mistake on my printed circuit boards. Once I do that, then I can populate the entire board and test all of the bits to make sure that everything is working the way that I expect it. Then I can go ahead and effectively start mass manufacturing these so that I'll have a full complement of registers and then I can finally continue with the second stage in building the RISC-5 processor. Now, maybe a little bit on why I chose JLCPCB instead of, say, Oshpark. I love Oshpark. They've got these great purple circuit boards. However, this is a four-layer circuit board and when you get a four-layer circuit board from Oshpark, it's much, much more expensive than their two-layer boards. These were pretty cheap, even though I got 50 of them. And I want to say this was about $200 shipped. Very cheap, much cheaper compared to Oshpark. The other thing I like about the JLCPCB boards is that they don't come with tabs. Now, when you get boards from Oshpark, they always come with these little tabs because when the printed circuit boards are made, they're sort of made in a large panel like this. And what they do is they drill little holes that connect each PCB to every other PCB so that they can just pull the panel out and then put it on their inspection machine or whatever as an entire set. Then when they're done, they just sort of snap the PCBs apart and then they send it to you. Well, I like these because they don't come with those little, I don't know, little nubbin things. So that's another reason why I chose to go with JLCPCB. And finally, when you go to PCBshopper.com and you plug in all the numbers, usually you'll see somebody like JLCPCB pop up as the cheapest or possibly all PCB. And I have done printed circuit boards from all PCB. I did do a run of these printed circuit boards through all PCB, but I didn't like what they came back to me with. They started asking me questions about Green Oil Bridge and I had no idea what Green Oil Bridge was. It turned out that what they were talking about was Tented Vias, but they gave me a really poor JPEG image with a lot of artifacts in it and some arrows that were pointing to, I don't know what they were pointing to. It seemed like they were pointing to this entire section over here and they were pointing to every single chip. And I tried to ask them what exactly was a Green Oil Bridge and they couldn't explain it. But eventually I figured out that what they were asking for was whether I wanted the vias Tented or not. And Tenting Vias simply means that they take the solder mask, which is green, hence why they call it Green Oil I guess, and they just squeegee it right over the vias so that you could actually put the silk screen over the vias and not have the silk screen broken up at random points by the vias. So because of that little snafu I wasn't really sure that all PCB knew exactly what they were doing so that's why I opted to go with like the second or third least expensive option, which was JLCPCB. So that was just the reasoning of which vendor I chose to make my printed circuit boards. So the components that I need for this are the 7416374 16 bit registers. These are the LVTH rather than the LVT. Again the H means that these are the bus hold versions so they do need more current in order to switch their state. But this was all that I had lying around so I'm just going to use them for now. And I've got my .1 microfarad capacitors these are the ones that you sprinkle on a printed circuit board to appease the gods. And I've also got my 1.5K ohm resistors which are used to give a suitable current through the LEDs. The voltage is 3.3 volts and the resistance is 1.5K that's kind of on the order of 2 milliamps per LED. Yes that's an awful lot of milliamps if you're going to light all of the LEDs but hopefully the power supply is up to that. And finally of course you know that I've got my big bag of a thousand LEDs so I can get started. And for easy testing I also have these PCIe that's the PCI Express sockets so the card just slides in like so and they would fit on the back plane just like that. And I can just attach some test clips to some of these leads and test the board. It's another box from JLCPCB let's take a look. Alright we got a pen that goes in the pile of other pens and we've got more LEDs in fun colors. That goes in the pile of LEDs in fun colors. And finally we get our printed circuit boards, yay! Printed circuit boards. Sticky, okay. So I'm pretty sure I didn't order this many let's see, three, six, nine, ten, ten. That's an even number. Maybe I did. Anyway, so what this is is a breakout board for my register cards. So I would put these sockets in just like that and just like that and then I can put the card in here just like that and it fits. Okay so that's all 200 or so connections soldered in and that's how the card looks. Now I just have to add headers over here so that I can start plugging in wires. And it looks like I've got one of these double headers but mainly a whole bunch of single headers. I guess I'll use the single headers and save the double one for a special occasion. And this is the result after soldering a total of about 400 connections. It's not that bad. It didn't take that long and these were the leftovers from the breakaway headers. So fairly efficient. Okay, so now that I've got my breakout board completely done and I have a sample card in here it's time to actually test this by stimulating the card with signals and reading some of the signals back. And speaking of pretty blinking lights I am not entirely pleased about how all of these LEDs came out. They're not quite lined up and they're not quite regular so I think I'm going to have to think of some kind of a jig to hold the LEDs while I solder them all in. So I got this digital analog discovery 2 in order to do the stimulation of the signals and reading back of the signals rather than using my usual routine of an Arduino just because I wanted to see how easy this was to work with. Okay, so I've found the place in waveforms where I can send output signals. I've designated this pin 0 or digital output 0 as being a clock at 2 hertz and then I've set some sort of a pattern to be sent out on digital I01. And hopefully we should see this final bit change state every so often. I go to supplies and enable whoa that's okay that's interesting all of them are lit and now let's go to and run. Okay, and that is pretty much exactly what I expected which is that our display storage oops, wow that's interesting so I'm touching it so I was touching the back here ah okay well I was touching the back here maybe that's sensitive but I'm wiggling the board and nothing is actually happening which is a good thing so I know that this is sensitive to electrostatic which kind of makes sense because this is kind of sort of CMOS and the other bits hold some random state it's just whatever the chip was powered on with and the chip is actually reading all of these other inputs so in theory if I touch some of these I thought that maybe I could get some of these values to change now the thing that's a bit worrisome here is that I am sending this signal over to what I thought was input 31 now this may actually be a result of my left right confusion in fact this may actually be 30 and the one below it is actually 31 which means that this one yeah okay so as I guess I should have predicted I labeled these jumpers backwards this is a problem with left right confusion is that you know you think that something's on the left but it's actually on the right I know that I right with my right hand and I know that I don't right with my left hand so I know what is right and what is left but when I'm just looking at something and I make a snap decision as to what's on the right and what's on the left I usually get it wrong 50% of the time okay but that's enough about me so here we have our light blinking and of course if I remove the signal and put it back in I can put it on another bit great okay that's pretty good so it seems to be storing my bits correctly now the other question is is it going to output the bits correctly when I instruct the register to output on source bus on or source bus too let's find out okay so I've set up yet another signal to output an output enable signal over here and I have set up another IO to read the data and I do see in fact that the data tracks the input as long as the output enable is set but it outputs basically nothing when the output enable is disabled so I'm looking at the schematic and I see that the LEDs are controlled through the output of this central display storage register and there's an output enable on that register and that output enable is supposed to be connected to a resistor going to plus which should disable it by default and to this jumper which needs to be grounded in order to set output enable to low which is a negative signal and that would let the chip output its signals however it seems to be outputting its signals anyway so the first thing that I really need to do is take a look at the actual output enable signal voltage and see what's coming out on it now doing that is pretty easy because P2 has one of its pins grounded and the other pin goes to the output enable so if I take a look at it I'm seeing about 0.5 volts which is incorrect so I'm kind of wondering did I leave that resistor out and in fact I did leave that resistor out it is supposed to be populated right over here so that pretty much explains why I'm getting an output here and not here it's because the chip picked up whatever static my finger had and set its output to that random signal which happens to enable the output let me go populate that resistor and try again ok so with the resistor populated I can now power the board up and I can gently brush my finger against these jumpers and nothing actually happens which is expected and I can measure the voltage going to the output enable now and see what it says ok and now it says 3.3 volts which is correct that means that the output is disabled now if I were to short this jumper which I'm going to do with the probe leads we should immediately start seeing the output of the LEDs excellent now the other thing is that these LEDs are controlled by a different jumper and that jumper I can also short and we should start seeing one of these LEDs blank soon there we go that means that the output is enabled and when it goes out the output is disabled so that works pretty well and this should have been the LED for let's see I'm plugged into source 2 and the label says source 2 that's good at least I didn't get that wrong ok so really the only thing wrong with this board actually there is nothing wrong with the register card itself there is something wrong with the breakout board which is that I got the numbering on the headers incorrect ok well I can just take a marker and just sort of put the correct numbers in there excellent ok we have a working register and I think that's going to be about it for this video we're going to end with a working register which is nice and the next video we'll talk about what can we do with this register well we need to have some sort of maybe an ALU or an instruction bus maybe an ALU well we're going to have to have maybe an ALU some kind of interface to memory something like that instruction decoder let's see what we can come up with I'm building a risk 5 processor not on an PGA