case task is
when 1 => task <= 2;
when 2 => task <= 3;
when other =>...
end case
I try to change the switch variable inside the case but it does not effect the value after case clause is passed. What is the proper way to do it?
Since you use a signal assignment <= I assume that task is a signal, not a variable. The new value of task will be available in the next simulation cycle (delta cycle). This usually means that the new value will be visible when the process is executed again, or after a "wait" statement (but you probably don't want wait statements if you are going to synthesize the code).
As an alternative, you can use a variable for task, and use the variable assignment operator: task := 2;
Use a variable, not a signal - this will update the way you expect.
Signals are useful for communication between multiple processes, as their updates are well-controlled. Ordinary variables are not and are therefore limited to process-scope, so can't be inadvertently used for inter-process communication which would then be error-prone.
Related
wait((irq == 1'b1) || (wb_bus.master_read(2'b10,DON) DON == 16'h8000));
Is this possible?
No, not directly. But indirectly is probably not going to do what you want. (Which we have no idea what that is. See the XY Problem)
Assuming master_read is a time consuming task, you can wrap it non-void function that always returns true. The then do fork wb_bus.master_read(2'b10,DON); join_none inside the function. If master_read is not time consuming, then make it a function with a void return.
But you have no control over how often the expression gets evaluated, and therefore how often the task gets called. If irq and DON change at the same time, it could get called once or twice.
Not sure what you're trying to achieve, but I'm guessing you're waiting for either irq == 1 or for a bus read to yield 16'h8000. In that case, you could fork off the two operations, wait for any of them to complete and then stop them. Note that there's an extra fork statement that's necessary so that disable fork doesn't kill ALL the child threads. See #dave_59's answer here.
fork // Container fork to reduce scope of `disable fork`
begin
fork // Actual fork we want to do!
begin
wait(irq == 1'b1);
end
begin
logic [15:0] DON;
do begin // Assuming you want to keep reading until the value is what you want
wb_bus.master_read(2'b10,DON)
end
while(DON != 16'h8000)
end
join_any;
disable fork;
end
join
Have looked for an answer to this question online everywhere but I haven't managed to find an answer yet.
I've got a SystemVerilog project at the moment where I've implemented a circular buffer in a separate module to the main module. The queue module itself has a synchronous portion that acquires data from a set of signals but it also has a combinatorial section that responds to an input. Now when I want to query the state of this queue in my main module a task, inside an always_ff block sets the input using a blocking assignment, then the next statement reads the output and acts on that.
An example would look something like this in almost SystemVerilog:
module foo(clk, ...)
queue = queue(clk, ...)
always_ff#(posedge clk)
begin
check_queue(...)
end
task check_queue();
begin
query_in = 3;
if (query_out == 5)
begin
<<THINGS HAPPEN>>
end
end
endtask
endmodule
module queue(clk, query_in, query_out)
always_comb
begin
query_out = query_in + 2;
end
endmodule
My question essentially comes down to, does this idea work? In my head because the queue is combinatorial it should respond as soon as the input stimulus is applied it should be fine but because it's within a task within an always_ff block I'm a bit concerned about the use of blocking assignments.
Can someone help? If you need more information then let me know and I can give some clarifications.
This creates a race condition and most likely will not work. It has nothing to do with your use of a task. You are trying to read the value of a signal (queue_out) that is being assigned in another concurrent process. Whether it gets updated or not by the time you get to the If statement is a race. U?se a non-blocking assignment to all variable that go outside of the always_ff block and it guarantees you get the previous value.
in order to figure out the stuff, you can just mentally inline the task inside the always_ff. BTW, it really looks like a function in your case. Now, remember that execution of any always block must finish before any other is executed. So, the following will never evaluate to '5' at the same clock edge:
query_in = 3;
if (query_out == 5)
query_out will become 5 after this block (your task) is evaluated and will be ready at the next clock edge only. So, you are supposed to get a one cycle delay.
You need to split it into several always blocks.
I'm having problems with understanding such a simply looking thing: blocking and non-blocking assignments.
I created a small test bench just to simulate the behavior of this code:
module ATest(clk, out);
input wire clk;
output reg [7:0] out;
reg [7:0] A;
initial begin
A <= 8'b0;
end
always #(posedge clk) begin
A = A + 1;
out = A;
end
endmodule
After simulation, I got this wave:
I expected the same value under both A and out, as I assigned values to them sequentially. Why is out "don't care" during the first clock?
Then I tried to use non-blocking assignment. I changed a part of my code into:
always #(posedge clk) begin
A <= A + 1;
out <= A;
end
And I got this wave:
I didn't expect anything here, because non-blocking statements are kind of mystery to me. Why is both A and out set to "don't care"?
Also, I found different names on every page I got to, so please help me out:
Are blocking and non-blocking interchangeable with sequential and concurrent as terms? Which one is right: non-blocking statement or concurrent statement?
Without diving too deep into the simulation cycles used by Verilog Simulators, you can think of non-blocking vs blocking assignment simply as this:
Blocking assignment happens inline at the time the given assignment is executed, so that means if I have a line like A = A + 1, that means we take the present value of A, add 1 and assign A that new value. So, the assignment "blocks" execution until it is done.
Non-blocking assignment (NBA) happens at a time slightly later than while the line is executed. You can think of non-blocking assignments as lines telling the simulator to schedule this assignment for a little bit later (note, later is still with the same simulation time step, so all of this is still happening in simtime t). So, if you have something like A <= A + 1, this means take the value of A at the time of executing this line, add 1 and schedule A to be updated to that value in a little bit, but keep moving on with the lines following that one. So, if the next line after is out = (A == 1) ? 1 : 0, this line will execute using the old value of A, not the incremented one. Once the simulator finished with the active code, it can move on to perform all the non-blocking assignments. Now, A will get the incremented value and all other non-blocking assignments will take effect.
So, to your examples. In case one, we see the delayed effect of NBA. In the initial block, A is assigned to 0, which means A will take on the value of 0 a little bit later (still within sim time 0 remember); ie the assignment is scheduled to take place after all blocking assignments have run (Not strictly true but it works in this case). Also, you have the clock's posedge happen so the always block runs. Here, A takes on the value A + 1, but remember, the assignment of A to 0 hasnt happened, so A still has its initial value of 8'bx. so, A + 1 is also 8'bx. And since this is a blocking assignment, it happens right away. So, A doesnt change from don't care. Continuing on, out gets the current value of A, which is 8'bx. So, we get the don't cares on out. After these and other blocking assignments are done, now we finish up the NBAs, in this case, A to become 0. So, still within sim time 0, A becomes 0 and we are done. At the next posedge of the clock, A is 0, out is don't care and your always block runs as expected, incrementing A and assignment out to the same value.
If you change the always block to use NBA (which it should if it is suppose to be a register), things change slightly. The initial block still results in a NBA scheduled for A to become 0. But now, the always block does something different. Now, A <= A + 1 instead of assigning A to don't cares right away, it schedules A to become 8'bx (remember, the right-hand side expression for what value to assign is evaluated inline, so A + 1 still uses A as don't care just as before; whats changed is when A takes on this new value) and this is scheduled after A to become 0. So, both the NBAs of A are set up, but the one telling A to be 0 happens first and is wiped out by the later assignment of A to 8'bx. out is similarly scheduled to take on 8'bx but now, A never becomes 0. As such, both A and out get stuck at 8'bx.
You can look through the Verilog or SystemVerilog LRM's to get a better understanding of sim cycles and what really goes on, but I hope this helps you better understand the difference!
Your issue come from using a non-blocking assignment in your initial block. Use initial A = 8'b0; instead.
The casue for this is likely how the two assignments are processed. = assignments are done incrementally, with any new values being available to subsequent assignments. Changes made via <= assignments are only available once all assignments have been processed.
Because your first edge is at t = 0 (when intial blocks are processed), in the first example A is assigned 0, but that 0 isn't available to out until after it is processed. That's while the first cycle looks weird, but everything else is OK. In the second, A is assigned both 0 and A+1, so the simulator uses the always block instead of the initial, going with A+1, when A is still an unknown value. As such, the values for A and out are never known.
The terms are equivalent. "Blocking" is the same as "sequential" because "blocking" means that the assignment must be done before the simulator moves to the next line (in sequence). "Non-Blocking" means that all the lines may be done at once. As everything with Verilog, it helps to imagine the hardware intended, so you may think of it as "parallel" vs. "serial" sometimes.
Is there a positive clock edge at time 0 in your simulation?
I understand about race conditions and how with multiple threads accessing the same variable, updates made by one can be ignored and overwritten by others, but what if each thread is writing the same value (not different values) to the same variable; can even this cause problems? Could this code:
GlobalVar.property = 11;
(assuming that property will never be assigned anything other than 11), cause problems if multiple threads execute it at the same time?
The problem comes when you read that state back, and do something about it. Writing is a red herring - it is true that as long as this is a single word most environments guarantee the write will be atomic, but that doesn't mean that a larger piece of code that includes this fragment is thread-safe. Firstly, presumably your global variable contained a different value to begin with - otherwise if you know it's always the same, why is it a variable? Second, presumably you eventually read this value back again?
The issue is that presumably, you are writing to this bit of shared state for a reason - to signal that something has occurred? This is where it falls down: when you have no locking constructs, there is no implied order of memory accesses at all. It's hard to point to what's wrong here because your example doesn't actually contain the use of the variable, so here's a trivialish example in neutral C-like syntax:
int x = 0, y = 0;
//thread A does:
x = 1;
y = 2;
if (y == 2)
print(x);
//thread B does, at the same time:
if (y == 2)
print(x);
Thread A will always print 1, but it's completely valid for thread B to print 0. The order of operations in thread A is only required to be observable from code executing in thread A - thread B is allowed to see any combination of the state. The writes to x and y may not actually happen in order.
This can happen even on single-processor systems, where most people do not expect this kind of reordering - your compiler may reorder it for you. On SMP even if the compiler doesn't reorder things, the memory writes may be reordered between the caches of the separate processors.
If that doesn't seem to answer it for you, include more detail of your example in the question. Without the use of the variable it's impossible to definitively say whether such a usage is safe or not.
It depends on the work actually done by that statement. There can still be some cases where Something Bad happens - for example, if a C++ class has overloaded the = operator, and does anything nontrivial within that statement.
I have accidentally written code that did something like this with POD types (builtin primitive types), and it worked fine -- however, it's definitely not good practice, and I'm not confident that it's dependable.
Why not just lock the memory around this variable when you use it? In fact, if you somehow "know" this is the only write statement that can occur at some point in your code, why not just use the value 11 directly, instead of writing it to a shared variable?
(edit: I guess it's better to use a constant name instead of the magic number 11 directly in the code, btw.)
If you're using this to figure out when at least one thread has reached this statement, you could use a semaphore that starts at 1, and is decremented by the first thread that hits it.
I would expect the result to be undetermined. As in it would vary from compiler to complier, langauge to language and OS to OS etc. So no, it is not safe
WHy would you want to do this though - adding in a line to obtain a mutex lock is only one or two lines of code (in most languages), and would remove any possibility of problem. If this is going to be two expensive then you need to find an alternate way of solving the problem
In General, this is not considered a safe thing to do unless your system provides for atomic operation (operations that are guaranteed to be executed in a single cycle).
The reason is that while the "C" statement looks simple, often there are a number of underlying assembly operations taking place.
Depending on your OS, there are a few things you could do:
Take a mutual exclusion semaphore (mutex) to protect access
in some OS, you can temporarily disable preemption, which guarantees your thread will not swap out.
Some OS provide a writer or reader semaphore which is more performant than a plain old mutex.
Here's my take on the question.
You have two or more threads running that write to a variable...like a status flag or something, where you only want to know if one or more of them was true. Then in another part of the code (after the threads complete) you want to check and see if at least on thread set that status... for example
bool flag = false
threadContainer tc
threadInputs inputs
check(input)
{
...do stuff to input
if(success)
flag = true
}
start multiple threads
foreach(i in inputs)
t = startthread(check, i)
tc.add(t) // Keep track of all the threads started
foreach(t in tc)
t.join( ) // Wait until each thread is done
if(flag)
print "One of the threads were successful"
else
print "None of the threads were successful"
I believe the above code would be OK, assuming you're fine with not knowing which thread set the status to true, and you can wait for all the multi-threaded stuff to finish before reading that flag. I could be wrong though.
If the operation is atomic, you should be able to get by just fine. But I wouldn't do that in practice. It is better just to acquire a lock on the object and write the value.
Assuming that property will never be assigned anything other than 11, then I don't see a reason for assigment in the first place. Just make it a constant then.
Assigment only makes sense when you intend to change the value unless the act of assigment itself has other side effects - like volatile writes have memory visibility side-effects in Java. And if you change state shared between multiple threads, then you need to synchronize or otherwise "handle" the problem of concurrency.
When you assign a value, without proper synchronization, to some state shared between multiple threads, then there's no guarantees for when the other threads will see that change. And no visibility guarantees means that it it possible that the other threads will never see the assignt.
Compilers, JITs, CPU caches. They're all trying to make your code run as fast as possible, and if you don't make any explicit requirements for memory visibility, then they will take advantage of that. If not on your machine, then somebody elses.
What does it mean if a task is declared with the automatic keyword in Verilog?
task automatic do_things;
input [31:0] number_of_things;
reg [31:0] tmp_thing;
begin
// ...
end
endtask;
Note: This question is mostly because I'm curious if there are any hardware programmers on the site. :)
"automatic" does in fact mean "re-entrant". The term itself is stolen from software languages -- for example, C has the "auto" keyword for declaring variables as being allocated on the stack when the scope it's in is executed, and deallocated afterwards, so that multiple invocations of the same scope do not see persistent values of that variable. The reason you may not have heard of this keyword in C is that it is the default storage class for all types :-) The alternatives are "static", which means "allocate this variable statically (to a single global location in memory), and refer to this same memory location throughout the execution of the program, regardless of how many times the function is invoked", and "volatile", which means "this is a register elsewhere on my SoC or something on another device which I have no control over; compiler, please don't optimize reads to me away, even when you think you know my value from previous reads with no intermediate writes in the code".
"automatic" is intended for recursive functions, but also for running the same function in different threads of execution concurrently. For instance, if you "fork" off N different blocks (using Verilog's fork->join statement), and have them all call the same function at the same time, the same problems arise as a function calling itself recursively.
In many cases, your code will be just fine without declaring the task or function as "automatic", but it's good practice to put it in there unless you specifically need it to be otherwise.
It means that the task is re-entrant - items declared within the task are dynamically allocated rather than shared between different invocations of the task.
You see - some of us do Verilog... (ugh)
The "automatic" keyword also allows you to write recursive functions (since verilog 2001). I believe they should be synthesisable if they bottom out, but I'm not sure if they have tool support.
I too, do verilog!
As Will and Marty say, the automatic was intended for recursive functions.
If a normal (i.e. not automatic) function is called with different values and processed by the simulator in the same time slice, the returned value is indeterminate. That can be quite a tricky bug to spot! This is only a simulation issue, when synthesised the logic will be correct.
Making the function automatic fixes this.
In computing, a computer program or subroutine is called re-entrant if multiple invocations can safely run concurrently (Wikipedia).
In simple words, the keyword automatic makes it safe, when multiple instances of a task run at a same time.
:D
Automatic is just opposite to static in usual programming. So is the case with Verilog. Think of static variables, they cannot be re-initialized. See the Verilog description below:
for (int i = 0; i < 3; i++) begin
static int f = 0;
f = f + 1;
end
Result of the above program will be f = 3. Also, see the program below:
for (int i = 0; i < 3; i++) begin
int f = 0;
f = f + 1;
end
The result of above program is f = 1. What makes a difference is static keyword.
Conclusion is tasks in Verilog should be automatic because they are invoked (called) so many times. If they were static (if not declared explicitly, they are static), they could have used the result from the previous call which often we do not want.