Jump to content

How to use and manage memory with my FPGA?


GalD101

Recommended Posts

13 minutes ago, GalD101 said:

100ns? I'm not sure what is it in terms of clock cycles


No, I'm asking about the period in clock cycles. That's independent of the frequency of the clock; you should be able to figure that out without knowing the clock frequency, just by inspecting the FSM module's code.

This is really a question you should be able to answer. The thing goes through a bunch of states (where the state is the collection of its registered values), periodically. I want to know the period of that little dance, expressed in clock cycles.

- answer it first for the 10 MHz / 30% duty cycle you did before.
- then answer it for the FSM you're currently working on.

It's not a problem if you don't know the answer immediately, but with a bit of thought you should be able to give those two numbers, because otherwise, you don't really understand what you're doing.

It may be useful to draw a state diagram for the first FSM. That's essentially a graph of all states, with each node annotated with the value of the registers in that state, and edges between states that are visited in succession. This graph will have a cycle, and I'm asking about the period of that cycle.

It's a question that is a lot more trivial than you may think.
 

Link to comment
Share on other sites

2 minutes ago, GalD101 said:

for 3 clock cycles I get a 1 after that I get a 0 for 7 clock cycles repeat.
for the FSM I'm currently working on, I get a 1 for 868 clock cycles then 0 for 868 clock cycles repeat.

So, what does that mean in terms of the period of the state machines...?

Link to comment
Share on other sites

Just now, GalD101 said:

what do you mean by period? how often does the output changes?

I defined it above.

The period is the number of states the FSM goes through (one per clock cycle) before it ends up in exactly the same state (and, henceforth, will keep on repeating the same cycles over and over again). It's the length of the cycle in the FSM's state diagram.


 

Link to comment
Share on other sites


Good! That wasn't so hard was it. Periodicity is a pretty important concept in state machines. Good that we figured out this concept didn't come natural to you. We may need it in the future.

Okay, so your assertion is that the second FSM has a period of 2 * 868 = 1736 clock cycles. I agree that's what it should do.

Now back to the code you posted, with two bugs:
 

  wire [3:0] next_counter = (r_counter + 1) % (868*2 + 1);
  wire       next_fsm_out = (next_counter < 868) ? 1 : 0;


What values does r_counter take on during a full cycle? And how many different values are that? Does that fit in 1736 cycles?


 

Link to comment
Share on other sites

4 minutes ago, reddish said:


Good! That wasn't so hard was it. Periodicity is a pretty important concept in state machines. Good that we figured out this concept didn't come natural to you. We may need it in the future.

Okay, so your assertion is that the second FSM has a period of 2 * 868 = 1736 clock cycles. I agree that's what it should do.

Now back to the code you posted, with two bugs:
 

  wire [3:0] next_counter = (r_counter + 1) % (868*2 + 1);
  wire       next_fsm_out = (next_counter < 868) ? 1 : 0;


What values does r_counter take on during a full cycle? And how many different values are that? Does that fit in 1736 cycles?


 

it ranges from 0 to 1736 so 1737 different values.
I still don't get the problem with this code:
 

  wire [10:0] next_counter = (r_counter + 1) % (11'd1738);
  wire       next_fsm_out = (next_counter < 10'd867) ? 1'b1 : 1'b0;

 

Link to comment
Share on other sites

> it ranges from 0 to 1736 so 1737 different values.

So just one question remains, which you skipped: does that fit in 1736 cycles?

While going through N cycles, can a state variable take on more than N distinct values?


(We'll get to your updated version later. It fixes the first bug but unfortunately, it introduces another one.)

Sorry for pestering you about these details, but when programming, details matter.

 

Link to comment
Share on other sites

20 minutes ago, GalD101 said:

no....

So we arrive at a contradiction. You say the r_counter variable takes on 1737 different values but the cycle length of your FSM should by design be 1736, so one of its registers can never take on 1737 distinct values during one full period.

We can conclude that this implementation is inconsistent with the intended design. QED.

It's a bit heavy-handed to mathematically prove that the implementation is not correct. Let's get back down to earth. Your original version had:

wire [3:0] next_counter = (r_counter + 1) % (868*2 + 1);

which should have been
 

wire [3:0] next_counter = (r_counter + 1) % (868*2);

Your modulus has an off-by-one error. This makes the period of your state machine 1737 rather than 1736, which is not what you intend to do.


Your newly proposed version fixes this specific problem, but it introduces another off-by-one error, in this line:

wire       next_fsm_out = (next_counter < 10'd867) ? 1'b1 : 1'b0;


I hope you see it. The gateway question is: per 1736-cycle period, how many cycles with FSM_OUT = 1'b1 do you want? And how many do you get, according to the line above? Count them.


These off-by-one errors suck. They are prevalent in normal programming, and also in HDL programming, and they can make your design not work and lead to super hard-to-debug problems. I urge you to get into the habit of becoming very careful about counting stuff.

By the way: I don't think your insistence on using bitlength-prefixed integer literals improves readability; rather to the contrary. But do as you please.





 

Edited by reddish
Link to comment
Share on other sites

Hi @GalD101

 

Okay, I've been doing a bit of a whirlwind tour through Verilog. In particular, I've read Chapter 4 of this: Digital Design and Computer Architecture, 2nd edition, by Harris and Harris. It's a great intro into SystemVerilog, because they have VHDL/SystemVerilog code examples side by side, allowing me to see the differences and similarities. Highly recommended reading! And to know that it has been sitting on my bookshelf for a few years, tssk.

What I got out of this book is that we've been using old-school Verilog, and that's essentially archaic. SystemVerilog has been around since 2008/2009, and the tool support has been slow to pick up (as always), but it's mostly there at this point. Vivado supports SystemVerilog just fine.

Some key highlights of SystemVerilog relative to old-school Verilog:

  • No more wire and reg distinction. The standards committee realized the confusion they caused and subsumed their functionality in a new type: logic.
  • Proper ability to define struct types (or "record" types, as we know them in VHDL). Also, enum types.
  • Proper support for functions.
  • The generic always block is still available, but now there are more specialized variants like always_ff and always_comb that indicate the programmer's intent to either implement sequential or combinatorial logic. This allows the compiler to do a lot of error checking, preventing unintended instantiation of flip-flops, latches, etc, which is a big cause of grief. Not too elegant, but super useful in practice.
  • Source files end in ".sv" rather than ".v" ... :-)

These changes allow me to write code in a style that is very close to what I am used to in VHDL. So I would propose we switch over to SystemVerilog.

It's pretty painless, I already ported the examples on my side. If you agree, I will post my latest versions and we can proceed to use SystemVerilog going forward. The added expressiveness will save us a lot of time.

Edited by reddish
Link to comment
Share on other sites

Okay here's the test FSM in SystemVerilog.  It may be best to just start a new project in Vivado and add these as SystemVerilog files (using the drop-down menu).

Have a good look, especially at my_first_fsm.sv; it changed quite a bit to take advantage of the nice new things available in SystemVerilog.

This is essentially the style I use all the time in VHDL: define register struct and a reset constant; define a next_state transition function; define the state update (using the always_ff), and hook state registers into output ports.

It may take some getting used to, but this implementation style is powerful and clean as you get used to it; Mostly so, because in the "next_state" function, you can just think in terms of semantics that you're used to in regular programming languages. Specifically, assignments have an immediate effect, and the code in the function body is executed front-to-end. That takes much of the confusion out of HDL design.

Let this digest for a bit and let me know if you get this up and running. I'll be offline for a couple of hours.

 

clock_synthesizer.sv my_first_fsm.sv toplevel.sv

Link to comment
Share on other sites

1 minute ago, GalD101 said:

Is it kind of like a superset of Verilog? Similar to how C++ is a superset of C

Pretty much.

Although I must object to the statement that C++ is a superset of C, it is not (quite), if you're pedantic enough. And I am nothing if not pedantic :)

Link to comment
Share on other sites

I looked up always_ff and it seems to be just like the regular always but with restrictions. A bit of an unrelated question: in our case, the good old reg (now logic) will be flipflops only (that is, we will only use ffs for memory (reg)? because I think I once saw that it's also possible to use LUTs instead?) It says that "A always_ff procedure adds a restriction that it can contain one and only one event control and no blocking timing controls" and that "Variables written on the left-hand side of assignments within always_ff... cannot be written by other processes". Why did you choose to use an "always_ff" block in line 44 of my_first_fsm.sv?
Also, in line 44, why won't you add a negedge or posedge of the reset to the sensitivity list like so?

always_ff @ (posedge CLK or negedge RESET) state <= next_state(state, RESET);

I now read a bit about event control and it says on the quote above that always_ff can only use one - so is that the reason you didn't add another event (negedge RESET) to the sensitivity list? because always_ff doesn't allow to? I just want to make sure I understand what event control is.
As for "blocking timing controls" is it that thing you mentioned before (blocking assignments (=) and nonblocking assignments (<=)?) so that is why you used a function that does these operations instead? Also, why did you use a blocking assignment inside the function? I thought we need it to happen simultaneously, or is it because the function is running sequentially but when you do the nonblocking assignment later on line 44 it runs the function and once it's finished you assign it with <= to "state" so it doesn't matter if you did blocking assignments (=) inside the body of the function because you "fix" it when you use non blocking assignment later on line 44?

Link to comment
Share on other sites

Another unrelated question that came across my mind (I'm using the clocking wizard again to generate a 100MHz clock). Why can't I choose a value of M to be 25 and D to be 3 instead of 50 and 6 respectively? Is it just cause or is there a deeper reason as to why, after all 50/6 = 25/3

Edited by GalD101
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...