Welcome to this video about Verilog structure. In this video you will learn how to use modules as building blocks of Verilog circuit design descriptions, how to include an instance of another module within a module to build hierarchical designs, and two ways to instantiate a module, and which one is better. Modules are the basic building blocks in Verilog. Module definition always starts with the keyword module, followed by the module name, the port list, port declarations and parameters. This is followed in any order by variable definitions which have local scope, dataflow statements, continuous assignment statements, instantiation of lower modules, behavioral blocks, and tasks or functions. Then at the end, there's always going to be the keyword endmodule, which isn't going to have a semicolon after it. Like you might see in VHDL, here you're going to leave that off. So if you need a picture of a module, it looks something like this. You always have the module keyword, followed by the module name and port list, but then you have port declarations that show the connections to the outside world the module, then variable definitions, then parameters which allow us to quickly reconfigure the design at compile-time, then dataflow statements which include assignments and other similar kind of statements, then module instantiations, then behavioral blocks like an always block, then task or functions which are like subroutines that are not often used for synthesis, but maybe included here, and then timing specifications possibly, and then finally the endmodule keyword. So other than the first line and the last line, everything in between here doesn't necessarily have to be in this order. So we're not implying that there's some order, we're just numbering these things so that you can see there's basically seven different types of things that have to be included inside of a module, or could be included inside of a module. A lot of times people will put parameters first after the module name and port list, because the parameters will get involved in the variable definitions and so on that follow. By instantiating modules, which may also have modules instantiated inside of them, which may also have modules instantiated inside of them and so on, you can build up a hierarchical design. To instantiate a module, we just need to type the module name, followed by an instance name, and then the port list. The port list can use top-level signal names only, as long as they are in the same order as the signals they need to connect to in the original module port definition. So the preferred way though is to use signal pairs when you're connecting top-level signals and module signals together. So in that case, both module signal and top-level signals are going to be listed. So in the example that we have here, you see a couple of instantiations both for 4-bit full adders, and in what case you're using the ordered way of doing things. We have sum, C out, A B and C in, and those are top level signal names and they have to be in the same order. So they're going to be implicitly connected to signals that are listed in the same order within the module definition. In the second instantiation, which you see as signal pairs that have been created. So the top-level signals are in parentheses. The signals from the module definition have a period in front of them, and so here we have periods sum, and then parentheses sum. The top-level signals are all in caps, and the module signals are lowercase to try to distinguish between the two of them in this particular example. So what you have is a one-to-one mapping then of signals from the top level into the module that's being instantiated, and even though it's shown this way where all the signal names are the same, when you use the second type of instantiation, the names don't have to be the same. So you could have sum, and then you could have something called sum 1, or output, or something like that if you wanted to, and you know we'll still make that one-to-one correspondence. Not the case when you're using an ordered set though. So the problem with the port list way of instantiating modules is that if there is a swap in the order of the list, the outputs are then going to be wrong. In this case if C out and sum, if they're swapped like they have been in this list, from the previous definition, then those outputs are going to be wrong as sum will not be sum but instead it'll be carry out, and carry out will be sum, and you're not going to get an error when this happens. So the assumption is that you know what names of the top-level signals are that need to be connected and in what order, this is Verilog so they assume that you know what you're doing, there isn't going to be a check for this. So if you do this, this is going to be an error that's only going to be found after the FPGAs programs when you're doing debug on the board, and that's a situation that you'd like to avoid. So the second case here, even though we've changed the order now of the signals because they're signal pairs, that mapping is still going to be one-to-one, the outputs will still appear as they should, even though the order of the ports hasn't been preserved. So this method is highly preferred over using the ordered list. We can instantiate modules to build larger circuits out of smaller building blocks. For example, if you wanted to build a four-input multiplexer given this two-input multiplexer, how would you go about it? One answer is you can cascade two-input muxes to build a four-input mux. So this code first muxes inputs a and b together, then c and d together, then takes those two outputs and muxes them together. We could have also made this by nesting conditional statements. However, at some level, nested conditional statements are going to be hard to follow. So this structured way of building up a larger circuit from smaller circuits, is perhaps a little more clear, and maybe a better approach in general. All the data inputs and outputs are four bits. In this case, we can parameterize the two input module, slit any number of bits could be used to make this model more useful in general. Note that if the low and high wire definition were emitted, the low and high signals would be scalars by default, which would be a disaster. All the output mux inputs except for bit zero, would then default the ground because they wouldn't have anything driving them anymore, since it's no longer a vector, it's just a scalar, and so the output that you get would just be completely wrong. Again, in a case like this, you may not get an error. You probably get some warning perhaps. But the lesson learned here is that you have to be careful to make sure that all of your internal signals are defined, and so you don't want to skip those internal signal definitions. So remember again this picture of a structure of a module. Let's put this all together in a single example and see what that would look like. So in this example, we have a multiply accumulator that's being built, and we see most of the elements of a module. The port list includes vectors for input and output. The output is a rag, so it's registered, so it's going to be stored for at least one clock cycle in this case. An internal wire is declared for the adder output. The multiplier is an instantiated IP block that expects a parameter as an input, giving the width of the multiplier. The two data inputs are multiplied together by the multiplier, then this is added to the output, which then provides the outputs of the module. So you have a feedback path here to the adder from the output, so the output gets added to whatever the multiplied output is, and then that output gets presented as the output of the module, after of course it has been registered in the always behavioral block that's listed here. So in this video, you've learned how to use modules as building blocks for Verilog circuit design descriptions, by instantiating or including an instance of the module. You've learned two ways to instantiate a module, and which one is better, and of course using the matched pair type of instantiation is a better way to go. Lastly, how to include an instance of another module within a module, to build a hierarchical design.