uvm register write is stuck and never return - system-verilog

I have some block of register along with corresponding register adaptor setup to translate into some bus protocol.
When I called the write method to one of my register, I could see the transaction going on, and driver complete its job, but write is stuck somewhere.
Please see excerpt of driver and sequence below:
// ...uvm driver
forever begin
seq_item_port.get_next_item(req);
$display("DEBUG A");
// ... do transaction
seq_item_port.item_done();
$display("DEBUG B");
end
// ... sequence
$display("START WRITE");
my_reg_block.my_reg1.write(
$display("DONE WRITE");
The result:
START WRITE
DEBUG A
DEBUG B
and then simulation stuck there - I never see DONE WRITE.
I am quite sure all the connect, set_sequencer has been made properly - otherwise my driver shouldn't see transaction in the first place. And this is pretty simple test - only doing that write.
Any idea why it is stuck in register write method eventhough the driver seems to have completed the transaction? I probably missed something.

In uvm_reg_map::do_bus_write(...) there's the following code snippet that handles the bus request for a register access:
bus_req.set_sequencer(sequencer);
rw.parent.start_item(bus_req,rw.prior);
if (rw.parent != null && i == 0)
rw.parent.mid_do(rw);
rw.parent.finish_item(bus_req);
bus_req.end_event.wait_on();
Notice the end_event.wait_on(). This event is normally triggered on a sequence item by the sequencer, once item_done() was called and finish_item() returns:
`ifndef UVM_DISABLE_AUTO_ITEM_RECORDING
sequencer.end_tr(item);
`endif
It's possible to turn this off using the define, which is what I guess is happening in your case.

Related

Anylogic: Queue TimeOut blocks flow

I have a pretty simple Anylogic DE model where POs are launched regularly, and a certain amount of material gets to the incoming Queue in one shot (See Sample Picture below). Then the Manufacturing process starts using that material at a regular rate, but I want to check if the material in the queue gets outdated, so I'm using the TimeOut option of that queue, in order to scrap the outdated material (older than 40wks).
The problem is that every time that some material gets scrapped through this Timeout exit, the downstream Manufacturing process "stops" pulling more material, instead of continuing, and it does not get restarted until a new batch of material gets received into the Queue.
What am I doing wrong here? Thanks a lot in advance!!
Kindest regards
Your situation is interesting because there doesn't seem to be anything wrong with what you're doing. So even though what you are doing seems to be correct, I will provide you with a workaround. Instead of the Queue block, use a Wait block. You can assign a timeout and link the timeout port just like you did for the queue (seem image at the end of the answer).
In the On Enter field of the wait block (which I will assume is named Fridge), write the following code:
if( MFG.size() < MFG.capacity ) {
self.free(agent);
}
In the On Enter of MFG block write the following:
if( self.size() < self.capacity && Fridge.size() > 0 ) {
Fridge.free(Fridge.get(0));
}
And finally, in the On Exit of your MFG block write the following:
if( Fridge.size() > 0 ) {
Fridge.free(Fridge.get(0));
}
What we are doing in the above, is we are manually pushing the agents. Each time an agent is processed, the model checks if there is capacity to send more, if yes, a new agent is sent.
I know this is an unpleasant workaround, but it provides you with a solution until AnyLogic support can figure it out.

what's the application of sequential transmission of I2C in HAL library in STM32f746ng

I can understand that you can use first frame option for first frame and next frame options for others, but since you can use them as FIRS_FRAME_LAST_FRAME, what is the advantage of other? and when we must use them?
Findings:
A code use wile to continuously transmit two number and get a callback to see if module has accepted that, if this happen correctly the led must blink.
In this simple code I've tested every xferoption of sequential transmission, every options worked except: I2C_LAST_FRAME_NO_STOP and I2C_FIRST_FRAME.
Code:
while (1)
{
value=300;
*(uint16_t*) buffer=(value<<8)|(value>>8);//Data prepared for DAC module
HAL_I2C_Master_Seq_Transmit_IT (&hi2c1, (MCP4725A0_ADDR_A00<<1), buffer, 2,I2C_LAST_FRAME_NO_STOP);
HAL_Delay(1);
HAL_I2C_Master_Receive(&hi2c1, (MCP4725A0_ADDR_A00<<1), rxbuffer, 3, 1000);
if( (uint16_t)(((uint16_t)rxbuffer[1])<<8|((uint16_t)rxbuffer[2]))>>4 == value ){
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);}
HAL_Delay(50);
value=4000;
*(uint16_t*) buffer=(value<<8)|(value>>8);
HAL_I2C_Master_Seq_Transmit_IT (&hi2c1, (MCP4725A0_ADDR_A00<<1), buffer, 2,I2C_LAST_FRAME_NO_STOP);
HAL_Delay(1);
HAL_I2C_Master_Receive(&hi2c1, (MCP4725A0_ADDR_A00<<1), rxbuffer, 3, 1000);
if( (uint16_t)(((uint16_t)rxbuffer[1])<<8|((uint16_t)rxbuffer[2]))>>4 == value ){
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET);}
HAL_Delay(50);
}
The HAL sometimes poorly documents these variables functions, and you will need to dive into the reference manual !
Looking at what the #defines are
https://github.com/STMicroelectronics/STM32CubeF7/blob/f8bda023e34ce9935cb4efb9d1c299860137b6f3/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_i2c.h#L302-L307
/** #defgroup I2C_XFEROPTIONS I2C Sequential Transfer Options
* #{
*/
#define I2C_FIRST_FRAME ((uint32_t)I2C_SOFTEND_MODE)
#define I2C_FIRST_AND_NEXT_FRAME ((uint32_t)(I2C_RELOAD_MODE | I2C_SOFTEND_MODE))
#define I2C_NEXT_FRAME ((uint32_t)(I2C_RELOAD_MODE | I2C_SOFTEND_MODE))
#define I2C_FIRST_AND_LAST_FRAME ((uint32_t)I2C_AUTOEND_MODE)
#define I2C_LAST_FRAME ((uint32_t)I2C_AUTOEND_MODE)
#define I2C_LAST_FRAME_NO_STOP ((uint32_t)I2C_SOFTEND_MODE)
We can see references to RELOAD and AUTOEND and SOFTEND.
Digging into the reference manual
https://www.st.com/resource/en/reference_manual/rm0385-stm32f75xxx-and-stm32f74xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf#page=969
So we can see here the reference to
AUTOEND - as a way to automatically implement a STOP condition after the set bytes end
SOFTEND as a way to prevent the automatic STOP condition and require the software to decide.
Relationship to your observed behaviour
The define's using the SOFTEND mode is where you saw things not working, and this is to be expected, the I2C protocol was not being fulfilled as there was nothing in the code to indicate the STOP condition.
So what does this mean you can do - an example of a variable byte i2c slave receiver
I haven't found a shining example from ST for this, but let me illustrate an example I have implemented in a project for an I2C Slave.
Let us look at the callbacks that are called:
https://github.com/STMicroelectronics/STM32CubeF7/blob/master/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_i2c.c#L76-L97
*** Interrupt mode IO operation ***
===================================
[..]
(+) Transmit in master mode an amount of data in non-blocking mode using HAL_I2C_Master_Transmit_IT()
(+) At transmission end of transfer, HAL_I2C_MasterTxCpltCallback() is executed and users can
add their own code by customization of function pointer HAL_I2C_MasterTxCpltCallback()
(+) Receive in master mode an amount of data in non-blocking mode using HAL_I2C_Master_Receive_IT()
(+) At reception end of transfer, HAL_I2C_MasterRxCpltCallback() is executed and users can
add their own code by customization of function pointer HAL_I2C_MasterRxCpltCallback()
(+) Transmit in slave mode an amount of data in non-blocking mode using HAL_I2C_Slave_Transmit_IT()
(+) At transmission end of transfer, HAL_I2C_SlaveTxCpltCallback() is executed and users can
add their own code by customization of function pointer HAL_I2C_SlaveTxCpltCallback()
(+) Receive in slave mode an amount of data in non-blocking mode using HAL_I2C_Slave_Receive_IT()
(+) At reception end of transfer, HAL_I2C_SlaveRxCpltCallback() is executed and users can
add their own code by customization of function pointer HAL_I2C_SlaveRxCpltCallback()
(+) In case of transfer Error, HAL_I2C_ErrorCallback() function is executed and users can
add their own code by customization of function pointer HAL_I2C_ErrorCallback()
(+) Abort a master I2C process communication with Interrupt using HAL_I2C_Master_Abort_IT()
(+) End of abort process, HAL_I2C_AbortCpltCallback() is executed and users can
add their own code by customization of function pointer HAL_I2C_AbortCpltCallback()
(+) Discard a slave I2C process communication using __HAL_I2C_GENERATE_NACK() macro.
This action will inform Master to generate a Stop condition to discard the communication.
Therefore, you could implement a I2C slave that could read a variable/dynamic amount of data:
Receive 1 byte - using the SOFTEND based options
This prevents the stop condition being raised, but once this first byte is received will trigger the HAL_I2C_SlaveRxCpltCallback().
In the HAL_I2C_SlaveRxCpltCallback() check the value of the first byte and then request more data of any further length, but this time using an AUTOEND based option.

How to create listener for publisher in CycloneDDS?

I am trying to use listeners for publishers in cyclonedds. but CycloneDDS does not have any examples on it.
can someone explain how to use them in the code?
From the above link, the publisher sending data part
For this example, we'd like to have a subscriber to actually read
our message. This is not always necessary. Also, the way it is
done here is just to illustrate the easiest way to do so. It isn't
really recommended to do a wait in a polling loop, however.
Please take a look at Listeners and WaitSets for a much better
solutions, albeit somewhat more elaborate ones.
std::cout << "=== [Publisher] Waiting for subscriber." << std::endl;
while (writer.publication_matched_status().current_count() == 0) { // how to use a listener here?
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
HelloWorldData::Msg msg(1, "Hello World");
writer.write(msg);
Wait for the subscriber to have stopped to be sure it received the, message not normally necessary and not recommended to do this in a polling loop.
std::cout << "=== [Publisher] Waiting for sample to be accepted." << std::endl;
while (writer.publication_matched_status().current_count() > 0) {// how to use a listener here?
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
Listeners are installed by:
dds_listener_t *l = dds_create_listener (...);
dds_lset_...
dds_set_listener (entity, l);
where the "dds_lset_..." stands for setting the listener callbacks you want to install, e.g., "dds_lset_publication_matched". What it doesn't do is help you with waiting until the event happens, you'll simply get a callback. You can of course wait for a trigger on a condition variable (or the writing of a byte into a pipe or ...) and use the callback to generate that trigger.
Using a waitset you can use the DDS API to wait for the event. For example, you could replace the polling loop in the publisher with:
dds_entity_t ws = dds_create_waitset (participant);
// The third argument of attach() is how the entity is
// identified in the output from wait(). Here, we know
// so any value will do.
dds_waitset_attach (ws, writer, 0);
// Wait() only returns once something triggered, and
// here there is only a single entity attached to it,
// with the status mask set to the only event we want
// to wait for, so an infinite timeout and ignoring
// the return value or list of triggered suffices for
// the example.
(void) dds_waitset_wait (ws, NULL, 0, DDS_INFINITY);
If I were to do this "for real" I would add error checking and inspect the result of the wait call. It is only in very limited cases, like this example, that you can get away with not checking anything.

B&R get drive serial number via MC_BR_GetHardwareInfo function block

I'm trying to retrieve the serial number from a drive using the MC_BR_GetHardwareInfo function block. Since the documentation lacks any kind of example code on this topic I'm getting nowhere.
Which information should I provide to the function block in order to get the desired serial number?
Below sample will crash in the PLC, probably because the function block requires certain pointers to be addressed:
MC_HARDWARE_INFO_REF hwinfo;
MC_BR_GetHardwareInfo(&hwinfo);
You are probably getting a page fault, because you provide the MC_BR_GetHardwareInfo function block (FUB) a wrong type, which leads to random behavior.
A function block is basically a function which requires a reference to a specific type as parameter. This type contains the actual in- and outputs which are used, internal state variables, etc. We need this, because of the synchronous execution of the code. This means unlike a function, you need to call a FUB until it is done.
Let's take a look to the help of the FUB:
Guid: 056444ea-2a15-4af6-a5ae-0675894b17d3
So the FUB needs a reference to the Axis object of which you want to know the HW info and an Execute command. It will give you some status bits, an error code and the actual data you want to have within the structure HardwareInfo of the type MC_HARDWARE_INFO_REF.
First we need to instantiate the FUB by create a variable of its type. We do this in the local *.var file of the task:
VAR
fbGetHwInfo : MC_BR_GetHardwareInfo := (0);
END_VAR
Then we call set the parameters of the FUB and call it, which might look like this:
void _CYCLIC ProgramCyclic(void)
{
//should be set by the application or in watch/monitor; now it only
//executes once
fbGetHwInfo.Execute = 1;
//reference to your axis object; when using a wizard the first axis
//will be gAxis01 on default
fbGetHwInfo.Axis = (UDINT)&gAxis01;
//call the FUB
MC_BR_GetHardwareInfo(&fbGetHwInfo);
if(fbGetHwInfo.Error == 1)
{
//TODO: errorhandling
}
else if(fbGetHwInfo.Done == 1)
{
//TODO use output
//fbGetHwInfo.HardwareInfo
}
}
typically you would do this in some statemachine. Also you probably have to wait until the network to the drive is initialized. You could check this with the MC_BR_ReadDriveStatus FUB. Just for testing it should be enough to wait for some seconds after reboot and set the Execute flag in monitor mode.

Basic UVM sequence simulation query

I have a couple of issues with a basic UVM based TB I'm trying out to understand sequences and their working.
bvalid is being always picked as 0 in the driver when being updated in the response item
Couple of error messages for last 2 transactions (# UVM_ERROR # 18: uvm_test_top.axi_agent1.axi_base_seqr1##axi_base_seq1 [uvm_test_top.axi_agent1.axi_base_seqr1.axi_base_seq1] Response queue overflow, response was dropped)
Here is the link to the compiling code on EDA Playground
http://www.edaplayground.com/x/3x9
Any suggestions on what I'm missing??
Thanks
venkstart
Having a look at the specification for $urandom_range it shows the signature as: function int unsigned $urandom_range( int unsigned maxval, int unsigned minval = 0 ). Change your call to $urandom_range(1, 0) and it should work.
The second error comes from the fact that you are sending responses from the driver and not picking them up in your sequence. This is the line that does it: seq_item_port.item_done(axi_item_driv_src);. Either just do seq_item_port.item_done(); (don't send responses) or put a call to get_response() inside your sequence after finish_item(). What I usually do is update the fields of the original request and just call item_done(). For example, if I start a read transaction, in my driver I would drive the control signals and wait for the DUT to respond, update the data field of the request with the data I got from the DUT and call item_done() in my driver to mark the request as done. This way if I need this data in my sequence (to constrain some future item, for example) I have it.