Let's say I have an entity called "HostToDevice" which has a "ps2c" inout signal (VHDL). In this entity I only set this signal to 'Z' (high impedance) because I want an other entity to control it.
I created a test bench to check the behavior and something strange (for me) happens. In the test bench I have this code:
ps2ctemp_process :process
begin
ps2ctemp <= '0';
wait for ps2c_period/2;
ps2ctemp <= '1';
wait for ps2c_period/2;
end process;
And after:
stim_proc: process
begin
ps2c <= ps2ctemp;
wait;
end process;
When I run the simulation (behavioral) the "ps2c" inout signal is just low and doesn't change like ps2ctemp signal does.
Instead if I drive manually the ps2c signal without using another signal it works fine; like this:
ps2c <= '1';
wait for 10 ns;
ps2c <= '0';
wait for 10 ns;
ps2c <= '1';
Your "stim_proc" has no sensitivity list, and one "wait" without event or timeout, so it is intended to run once and wait forever. This seems to be what the sim is doing, so, good.
Now I'll make a wild guess here, that you actually want it to wake up every time ps2ctemp changes, and pass on the new value to ps2c.
There are two ways to do that:
(1) with a sensitivity list
stim_proc: process(psc2temp)
begin
ps2c <= ps2ctemp;
--wait;
-- no, we want the process to complete, so it can be woken up
-- and run from the start again
end process;
(2) with a wait for a specific event...
stim_proc: process
begin
ps2c <= ps2ctemp;
wait until ps2ctemp'event;
-- any activity at all on ps2ctemp should wake this process,
-- in case there is something it ought to be doing...
end process;
In this simple case, these two forms are essentially equivalent. So the simpler one (sensitivity list) is to be preferred...
Related
In case I want to end the simulation from my monitor (I know that it is not the recommended way) how can I do this?
lets say I got this code inside my monitor:
Virtual task monitor_run();
fork
forever begin
.....
end
forever begin
.....
end
forever begin
.....
end
join
endtask : monitor_run
Every forever loop check that outputs of the DUT came on time, in case they doesnt it should stop simulation.
This special monitor should break the simulation in case of mismatch(error) and there is no Scoreboard.
I still want to manage nice end of simulation behaviour. I tried use raise and drop objection but I get an error of OBJT_ZERO sometimes. Does anyone knows a good way to end the simulation in that case?
thanks!
The UVM is set up by default so that uvm_report_fatal ends the test immediately, and uvm_report_error lets the simulation continue until hitting an error limit that you can set. And you can control the actions of each severity for an individual component. See uvm_report_object which is the base class of uvm_component.
Upon ending the test, the UVM calls uvm_report_server::report_summarize() that dumps out all the severity counts. If you insist, you can create a final block in your testbench module that gathers the severity counts from the report server and print the last message. For example:
module top;
initial run_test();
uvm_report_server rs = uvm_report_server::get_server();
final if (rs.get_severity_count(UVM_FATAL) != 0 ||
rs.get_severity_count(UVM_ERROR) !=0 )
$display("Test Failed");
endmodule
But this is really unnecessary and may not catch other non-UVM errors like assertion failures or timing checks. Many tools have a TESTSTATUS exit code that reports the most severe message encounte, UVM or tool.
I am trying to have a loop where it will start at 100 and drop until it hits to a point where the while condition no longer holds true.
I started with
While Solar_Power_House_W_Solar_PER <= OneHundred AND BatChargePercent < OneHundred DO
State_Dis_Charge := false
FOR PLC_SetLoopChargeValue:= 100 TO 0 By -1 DO
ConvertoReal := INT_TO_LREAL(PLC_SetLoopChargeValue);
Divide := ConvertoReal DIV(100);
PLC_SetCharge := Divide;
PLC_Charge := 1500 * PLC_SetCharge;
RB_Charge := PLC_Charge;
Visual_RBPower := 1500 * PLC_SetCharge; (*Charge *)
END_FOR;
The problem I believe I have with this is that it cycles too fast so the condition never gets out of the while loop because it takes a while for the system to update so I thought of adding a delay portion:
While Solar_Power_House_W_Solar_PER <= OneHundred AND BatChargePercent < OneHundred DO
State_Dis_Charge := false;
wait(IN:=not wait.Q , PT:=T#50ms);
if Wait.Q Then
FOR PLC_SetLoopChargeValue:= 100 TO 0 By -1 DO
ConvertoReal := INT_TO_LREAL(PLC_SetLoopChargeValue);
Divide := ConvertoReal DIV(100);
PLC_SetCharge := Divide;
PLC_Charge := 1500 * PLC_SetCharge;
RB_Charge := PLC_Charge;
Visual_RBPower := 1500 * PLC_SetCharge; (*Charge *)
END_FOR;
END_IF;
END_WHILE;
How I think it should work is every 50ms 1 for loop should run. Currently nothing happens every 50ms.
You have to consider that WHILE and FOR are executed synchronously. It means blocking. It means that interpreter do not execute next line, until previous line is finished.
This means that "running to fast" cannot apply here. It does not matter how fast it runs, the execution of the lines will be always in order.
The only thing I would change and loop not from 100 to 0 but vice versa from 0 to 100, because I am not sure this backward will work fine. And then all you have to change:
ConvertoReal := INT_TO_LREAL(100 - PLC_SetLoopChargeValue);
You do now show all code it is VERY HARD to judge but if FOR loom is complete it totally make no sense. You calculate some variables but you do not use them there. You know that you cannot use them outside of your FOR loop, right? Because outside of your FOR loop those variable will be always same value of last loop.
In your second example your FOR loop, although it might work, you should not use timer to run the loop inside the loop. Because loops are synchronous and times async.
As I understand you task you do not need WHILE at all. With this approach your program execution of other parts will be blocked until 100%. That might take a while as I can see. So you have to use IF.
IF Solar_Power_House_W_Solar_PER <= OneHundred AND BatChargePercent < OneHundred DO
// ....
END_IF;
The difference is significant. With WHILE it will block your program till WHILE finish and other parts will not be executed for this long, in the same PLC cycle FOR might be executed so many times.
With IF if will run FOR one time per one PLC cycle and actualy doe snot change your logic.
If you would share your full code or at least parts where variables you have here are used so that the whole picture is visible, you might get a better help. Edit your post and I'll edit my comment.
With this answer im only adressing your issue with the for loop not being executed every 50ms.
The other answers why the while loop cant be exited are correct unless the variables Solar_Power_House_W_Solar_PER and BatChargePercent aren't changed in a parrellel thread.
I suggest wait is a TON function block. Please mind that names of FBs are case sensitive: wait.Q is possibly unequal Wait.Q. I think that is the main reason your for loop is not executed, because you check the output of another FB. Maybe check your declaration list for doubles with higher or lower cases.
Another possibility is, that your condition for the while loop isn't met at all and you didn't notice. In this case the for loop wouldn't be executed too of course.
Say we have a call-back timer function call_time(obj, event). I want to know the elapsed time (delt_time) during the execution of timer function once it is started.
Furthermore, I want to use that elapsed time to decide if the function will be continued executing or be terminated (say delt_time > 60s). I want the timer function to determine the running time concurrently. By doing this way, the code knows when to terminate the program once it reaches to the threshold. Actually, I have asked a couple of similar questions on the basis of different ways that I have tried. But no answers yet.
Now I've tried
function call_time(obj, event)
event_time = event.Data.time;
event_time = event.Data.time - event_time;
while event_time < 60
%execute commands
end
if event_time > 60
%terminate execution
end
end
But it does not work.Below is how I call the timer function.
TimerHandle = timer;
TimerHandle.StartFcn = #(~,thisEvent)disp([thisEvent.Type ' executed '...
datestr(thisEvent.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);
TimerHandle.TimerFcn = #call_time;
TimerHandle.StopFcn = #TimerCleanup;
TimerHandle.period = 10;
TimerHandle.ExecutionMode = 'fixedRate';
start(TimerHandle);
I also tried the way that Tom suggested. But not working as well.
function call_time(obj, event)
event_time = event.Data.time;
delta_time = event.Data.time - event_time;
while delta_time < 60
%execute commands
delta_time = event.Data.time - event_time;
fprintf('Elapsed %.2f sec\n', delta_time);
end
if delta_time > 60
%terminate execution
end
end
Assuming you want to track time since the callback entrance, you can use tic/toc:
function call_time(obj, event)
elapsed_sec = 0;
t = tic();
while elapsed_sec < 60
% execute commands, e.g. something time-consuming
A = randn(10000);
elapsed_sec = toc(t);
fprintf('Elapsed %.2f sec\n', elapsed_sec);
end
end
UPDATE on concurrency - Matlab execution is single-threaded, so nothing like this exists out of the box. You could spawn java treads and have one terminate another, but you would obviously not be able to run Matlab code inside (not easily, at least).
For a pure java solution, you can check out this question. If you really-really need to terminate Matlab code, you can use aforementioned Java solution, and call back from Java to Matlab via JMI / MatlabControl or MATLAB Engine API for Java (I am actually not even certain the thread would be terminated in this case). Even if it does work, this is unnecessarily more complicated than simply adding a bunch of toc checks between your statements.
I am new to system verilog and was trying a basic mailbox code using Modelsim Student Version. I was able to compile the code successfully and simulate it but i am not getting the expected result. There is a for loop inside the put and get tasks but the loop is not getting executed.
Foll is the code :
// simple mailbox //
module mailbox_new();
mailbox my_mailbox;
initial begin
my_mailbox =new();
if(my_mailbox)
begin
fork
put_packets();
get_packets();
#1000;
join_any
end
#1000;
$display("END OF PROGRAM");
end
task put_packets();
integer i;
begin
for(i=0;i<10;i++);
begin
#10;
my_mailbox.put(i);
$display("Done putting packet %d #time %d",i, $time);
end
end
endtask
task get_packets();
integer j;
begin
for(j=0;j<10;j++);
begin
#10;
my_mailbox.get(j);
$display("Done getting packet %d #time %d",j, $time);
end
end
endtask
endmodule
// end of code /////
the result being displayed is :
# Done putting packet 10 #time 10
# Done getting packet 10 #time 10
# END OF PROGRAM
That is my for loop is not getting executed properly. Can you pls help me on this. Whether its a coding issue or a tool issue
There are multiple things wrong with your code, but the most obvious one is that you put a semicolon ; after the for statements. This means you'll loop and not do anything and then execute the begin...end block. Remove the extra ;s and you should be fine.
Just from the tester flow (no changes to design) is there a quick way to assert that all the design signals are initialized during reset?
Design uses synchronous active low reset.
On the rising edge of reset I want to assert that every signal in the design is not 'U' without having to call out each signal or architecture.
Using VHDL 2008, Modelsim 10.1c with HDL Designer.
You can adapt the use of the Modelsim when command from this answer to look for 'U' in any signals after the synchronous reset is released. As it exists it works with scalars and arrays but cannot examine record members.
Note that the rising edge of reset is not the time that reset is released since you are using synchronous reset. I would make the test wait for the first falling edge of clock when reset is high to test for 'U'. This will ensure that you see the new state on signals when their drivers update after the reset. The when expression would be something like:
"clk'event and clk = '0' and reset = '1' and $sig = [string repeat U [string length [examine $sig]]]"
Another option would be to create a sentinel signal in the testbench that evaluates to true when reset is released and test for that in the when expression:
signal reset_inactive : boolean;
process(clk) is
begin
if rising_edge(clk) then
if reset = '1' then
reset_inactive <= true;
else
reset_inactive <= false;
end if;
end if;
end process;
...
When expression:
"reset_inactive'event and reset_inactive = true and $sig = ..."
Once complete it would be a good idea to cancel the waits with the nowait command to avoid the performance hit of having a wait on every signal in the design since you only need this test after reset.