I am new to SystemVerilog (coming from a VHDL background). I am likely doing something dumb, but I have not been able to solve it by looking stuff up online. When I try to compile the following code, the compiler complains that I need a “default clocking block” in order to use my “##2” statement. But as you can see, I do have a clocking block. I wonder if this error is related to the fact that I am using a task, and the task is somehow separate from the rest of the code? Otherwise I am stumped. I tried setting the “default input…output” clause to values other than zero ns (I don’t think I want to model skew in this case), but that didn’t help. Can someone point out what I am doing wrong?
Thanks.
// begin code
initial begin
fd = start_server();
if (fd < 0)
$finish(1);
fork
wait_for_data();
join_none
end
clocking cb @(posedge clk);
default input #0ns output #0ns;
input do_read, read_buf, read_count;
output do_write, write_buf, write_count;
endclocking
task wait_for_data();
forever begin
do_write = 0;
write_count = recv_data(fd, BUFLEN, write_buf);
if (write_count < 0)
$finish(1);// error message should be displayed from the C code
do_write = 1;
##2;// wait for two clock cycles
end
endtask // wait_for_data
// end code
You want to write the clocking block as
default clocking cb @(posedge clk);
input do_read, read_buf, read_count;
output do_write, write_buf, write_count;
endclocking
There can only be one default clocking block in any scope, and the ##n syntax can only appear in the same scope as the default clocking block. It is more general to write repeat(2) @cb; and then you can have multiple clocking blocks with different clocks.
There are a lot of other problems wit the rest of the code shown.
- Don’t use a fork/join_none unless you really need it. Why do you think you need it in this code?
- If you want to interact with the clocking block signals, you need to prefix any signal with cb.signalname.
If you want to write to a clocking block output, the only allowed syntax is
cb.*signalname* <= *expression*;
You can’t use a blocking assignment ‘=’, or use the output off a task or function.
- You should have the ##2 or @cb at the beginning of the loop. Then any reads or writes of clocking block signals will be synchronized to the clocking block edge.
In reply to dave_59:
Thanks for your response.
So can I use the “repeat(2) @cb” inside the task?
I believe I do need the fork/join_none statement because I am using the DPI interface to call some C code. That is why I am using SystemVerilog to begin with. The C code I am calling will block execution until some asynchronous external event takes place, so I think I need that code running in a separate process/task/thread (?) so that the initialization thread is not blocked.
I was trying to assert the “do_write” signal high for two clock cycles when the asynchronous event takes place so that my VHDL state machine will be guaranteed to see that event and respond appropriately. So I don’t think I really need any synchronous logic in this whole design. I think everything could be combinational, provided I can find some way to assert the “do_write” signal for the right amount of time and then deassert it. Note that this code will be run in different designs with different clock frequencies, so I would rather not make any specific assumptions about what the clock frequency is.
I wish there was some kind of “wait until” statement in SystemVerilog like there is in VHDL, but if there is, I can’t seem to find it. I wonder if I might be better off doing this design in FLI instead of using SystemVerilog at all.
I can post some more code if it would be helpful to explain the problem better.
In reply to fpga_user:
Yes, you can use the repeat (2) @cb inside the task.
You do not need the fork/join_none. An initial block can consume time, and each initial block is an independent concurrent thread.
Here are some VHDL ↔ SystemVerilog equivalents
**VHDL** |
**SystemVerilog** |
WAIT UNTIL A = '1'; |
wait(A==1); |
WAIT FOR 100 ns; |
#100ns |
WAIT ON A; |
@A |
WAIT ON A,B; |
@(A, B) // or @(A or B) |
WAIT UNTIL A='1' FOR 100 ns; |
fork wait(A==1); #100ns; join_any |