At its simplest, for every state machine you have three variables:
- Inputs - Driven to the state machine. Not directly controlled by the FSM design.
- State - Internal information about the current state the machine is in.
- Outputs - Driven out of the state machine.
The state machine design about how it defines State and Outputs based on a series of Inputs over time. The State is registered, so on every cycle, you are trying to figure out the next State. The output is combinatorial, so you need to figure out the current output.
For both Mealy and Moore, the next State is determined by some combination of the inputs, current state, and current output. So it's a bunch of things like:
if (current_state == 5)
next_state = 6;
else if (current_state == 4 && input[3] == 1)
next_state = 5;
etc...
The output is typically not sequential, but rather combinatorial. And what is used to calculate this output defines whether it is Mealy or Moore.
The more general case is the Mealy FSM which calculates the output with some combination (i.e. AND/OR/NOT, comparators, etc.) of Input and (current) State.
So again, things like:
if (current_state == 5)
output = 1;
else if (current_state == 4)
if (input[3] == 1)
output = 2;
else
output = 3;
etc..
But if we restrict ourselves to only calculating based on State, it is a Moore FSM.
In this case, it would look like:
if (current_state == 5)
output = 1;
else if (current_state == 4)
output = 2;
else if (current_state == 2 || current_state == 3)
output = 3;
etc..
That really is it. Nothing else. And to top it off, you can convert one form to an equivalent form of the other.
One question that is often unasked is "Why do we separate them into two classes and give them names? Why is it so important?"
The answer is because as you try to create FSMs in real practical circuits, you will find that you are generally able to get better performance from a Moore machine. (They usually can run at higher frequencies). However, for many people intuition leads them to think about state machine problems more closely to the Mealy model.
By classifying them, we can teach ourselves to think about state machines problems in both models. This allows you to pick the correct model for the problem you are trying to solve. The details about why Moore runs faster and the tradeoffs between when to choose the two designs comes with experience and knowledge about digital design.
Verification is a huge part of the design process; in a complex design, it would not be unusual to spend as much time, or even more time on verification than you do on the actual design. That being the case, a question which is essentially 'how do you verify complex designs' is quite broad.
In overview, if the design copes with a large number of scenarios, as indicated by there being very many states in your state machine, a good starting point for the test suite would be to have separate tests that stimulate the design so as to replicate all theses scenarios. You can then use code coverage tools to see which state transitions have been covered, and add new tests until everything is being covered. You can manage different test cases using the configuration
construct in VHDL
It might commonly be the case that there are scenarios that are variations on a theme, for example receiving a packet of some kind, but with different packet lengths, lengths that are out of bounds, etc. In these cases you can write tests that generate a number of random length packets; you would then need to make sure that all your edge cases are met, for example the minimum and maximum lengths, the minimum plus one, the maximum minus one, etc, and that your design does the correct thing in every case. You might also need to test combinations of inputs to the design, and again these combinations could be generated by a test case, as opposed to writing them out manually one by one.
There are a number of methodologies that attempt to help manage the process of generating stimulus and recording the results. I use OSVVM, which I learned about through a course a couple of years ago. I like it because it uses the same VHDL language that I am used to, along with a bit of TCL scripting, and does not require any 'extras' in order to work with my simulator. There are many alternatives, which I won't try to list here, but a quick Google search for 'fpga verification' brings up a lot of resources.
Best Answer
Even though a design may be considered 'stateless' because there is no explicit state machine, you may still be actually coding a type of state mechanism without explicitly calling it that. For example, flags may be used to indicate if one part of the code is busy or not. In your 'calculator' example, you may not have a state machine, but you may have a flag that indicates that data is available and ready for processing. Even though this may not be called a state machine, you are using flags or other signals as a mechanism to ensure that specific operations are performed in a certain sequence. You're essentially making a state machine using your flags.
As a result, a state machine is pretty much present in most things. An explicitly designed one is really just a way for the coder behind the keyboard to keep track of the process their system is going through to ensure that everything performs as expected. When a system is more complicated, this is a really useful mechanism because it's only possible to keep track of so much at once. If it's a simple design, it may just be necessary to use a couple of flags and be done with it. It really just comes down to how complicated the problem is.