Welcome to FPGA design for embedded systems, when designing HDL code, there tends to be a couple of approaches. One that kind of emphasizes designing for synthesis, the other that emphasizes designing for simulation. In this video, you will learn how the simulator works, so that you can design HDL code that works in simulation. An understanding of the techniques used to model concurrency using sequential software, how to write your code so that it works for both synthesis and simulation, and tips for avoiding common problems and simulation code. An HDL simulators, just a software program, it models, the actions of hardware, but also includes programmatic constructs and interactive elements, based on TCL scripting, it is a complete and powerful development environment. It uses clever programming techniques to create the appearance of concurrency, to correctly model how the real hardware behaves. Some HDL code will simulate but not synthesize, some HDL code will set the size but not simulate, your HDL code describing hardware should both simulate an be synthesizable. Modeling for synthesis is the primary emphasis, but we need to simulate the code as well. Code must satisfy simulation syntax and semantics. So the main simulation concepts are that of a simulation cycle where you have stimulus and response, how simulation timing works, which may not be exactly as you might think. The use of sensitivity lists in order to create events that happen that have to be timed in simulation. The creation of signal drivers to drive signals and resolution functions when you have more than one signal driving a particular input. When were modeling for simulation, we need to be aware of the simulation cycle, VHDL code consists of numerous concurrent statements or processes. It is simulated using a stimulus and response paradigm, where the stimulus or the inputs changes specific simulation times, then the processes are evaluated using those new changed inputs, and that creates then other resulting logic changes. The signal values are going to change after specific simulation time has elapsed, all concurrent processes repeatedly execute in parallel concurrently, following a standard simulation cycle. So here's a picture of the simulation cycle, the pictures meant to help you visualize the simulation cycle as it goes. After all variables, the signals are set to their initial state, the first update cycle runs, this provides stimulus to the processes. Next, the processes are executed in any signal changes based on that execution, create transactions in the simulator schedule or the time Q. If the process execution causes an immediate change, an internal cycle based on an infinitesimal unit of time known as a delta delay, then executes any process activated by the change. This continues until the next scheduled transaction is some units of time of way, then the response occurs in the simulation time is updated to the next transaction time, and the update cycle is run. This provides stimulus and then on you go back to the execution phase, and round and round it goes. So the first part of the simulation cycles the initialization phase, where the simulation time is set to 0, signals are initialized to explicit values specified in the code if they exist, else then the following things are done. Any bit variable is set to 0, any Boolean is set to false, any standard logic or standing logic type is set to U for unknown, and then any integer is set to the least or I guess the largest negative number, before it starts any enumeration type is set to its first value. And then every process runs until it suspends, and the simulation time, though, it's still 0 at this point, so all this kind of setup happens in initialization phase. The second simulation cycle is the update phase, all signals are updated that have a transition schedule, the current simulation time, if some signal events have occurred, then those are going to be updated. Other signals do not change because they don't have any events on them, and the simulation time doesn't change. So all we're doing is we're updating the value of various signals at this particular time. The third part of the simulation cycle is the process execution phase, in this particular cycle, or in this phase, each process is executed if it's sensitive, to signal that had an event in the current simulation cycle. So if there was some change in the sensitivity list to a signal in the sensitivity list then the process will run. The simulation time in the next cycle is determined, this is the earliest time among these possibilities, the smallest time that any signal has an event scheduled, or the smallest time of which any process is scheduled to resume. If the new time is a Delta delay and new simulation cycles began with the same simulation time as the current simulation cycle, otherwise, the simulation time is updated, and a new simulation cycle begins. So within simulation processes will execute a process is either being executed or it is suspended. Execution begins when any signal in its sensitivity list has an event or change in value. During execution, sequential statements and their process are executed in succession. Execution continues, until the process is suspended due to either the execution of the last sequential statement in the process or, the execution of await statement. So here's another view of the simulation loop, the similar it gets the next signal assignment from the time queue, then makes the assignment and determines if an event occurs, then it executes processes triggered by the event, and then cycles back to get the next assignment. So for example here, the process then creates an order pair of events at times shown, which are placed in the queue in time order. The process creates ordered pairs of events, and times as shown, which are placed in the queue in time order, or in chronological order if you will. So if A gets 1 at 2 nanoseconds, and B get 0 at 4 nanoseconds, each of these events will create an ordered pair, and any processes affected by the A change will be executed first, which may lead to other changes and other signals being scheduled at that time, simulation's all about scheduling. A process can be triggered by resumption after a wait statement, or by an event on a signal in its sensitivity list. So there are several processes listed in code here, the sensitivity list for the first process, means that the process will be executed when an event occurs on any signal in this list. So if there's an event on a, b or s they have some kind of change in value, that results in an order pair that has been scheduled once that time occurs, then this process is activated and it will be executed. The process with no sensitive list will always be triggered initially at time 0, a wait without a time delay will suspend forever, effectively killing the process. So if you want the process to end, one way to do that is just put a weight with no time in it, and that will end the process. Otherwise it will only wait for the amount of time listed, and then it will loop back around to the beginning of the process. So here are some guidelines for using processes in simulation, if a process has a sensitivity list, then it cannot contain a wait statement. A process with a sensitivity list is always triggered at times 0, because all signals always have an initial event placed on them at time 0. A process without a sensitivity list, is always triggered at time 0 initially, if a process without a sensitivity list falls out the bottom, then it immediately loops back to the top, until it hits a wait statement. Here a couple of process tips, is possible to have an infinite loop in simulation, and this is never good. A process with no wait or no sensitivity list, will run without stopping and may make the simulator crash, this is definitely something to be avoided, so this code here is an example of such a process, where it sets a variable to a value. There's no wait, there's no sensitivity list, this is just going to cycle through forever, and if we're lucky, the simulator, Is it going to stop it somehow? You might be able to do something to make the simulator stop, but this is a real problem, something that you should never do. So another problem that's even more common is to leave off a signal on the sensitivity list that the process is depended on. In this case, an input was left off of the list and now any changes in B will not be reflected in the output. So this can be a hard bug to find, and it's always good to double check all of your sensitivity lists to make sure that any signal that can look like an input within a process also appears on the sensitivity list. So here are some keys to designing HDL code for simulation. The basic granularity of concurrency is the process, at least in VHDL. In Verilog it's always blocks an initial blocks. Processes are executed concurrently. In other words, you have hardware that all exists in parallel. When there's changes to those signals in hardware, all that hardware than operates on those signals in parallel, concurrently, all at the same time. So we have to be able to model that. Even though we have a computer program that we're using that executes sequentially, it can be written in such a way so that it can keep track of everything that's happening, that's what the time Q is all about, and model things concurrently. And this modeling is actually very accurate. So concurrent signal assignment statements then are one line processes, or they're interpreted to be one line processes. So any assignment statements, any processes, those are all assumed to be running at the same time concurrently. So there's a mechanism for achieving concurrency. All the processes communicate with each other via signals. Signal assignments all require delay before new value is assumed. Simulation time advances when all active processes are complete. So the effect of doing this is concurrent processing. In other words, the order in which processes are actually executed by the simulator does not affect the behavior. And this is exactly what we want. So we'll talk more about the specifics of simulation with Verilog and all about delta delays in the next video. So in this video you have learned how the simulator works do that you can design HDL code that works in simulation. And an understanding of the techniques used to model concurrency using sequential software. How to write your code so that it works for both synthesis and simulation. And tips for avoiding common problems in simulation code.