Specman e: A sequence drives its BFM also its MAIN was not defined in a test - uvm

I'm building UART verification environment.
I have 2 sequenceses:
For driving DUT UART configuration - vr_ad_sequence
For driving frames to DUT UART Rx - uart_sequence
Both sequences, their drivers and BFMs work Ok.
BUT, when I created a simple test that ONLY uses configuration sequence, the DUT UART Rx is driven by the verification environment (also there is NO extension of MAIN uart_sequence)! The test looks like this:
// The test that drives ALSO uart_sequence
extend MAIN vr_ad_sequence { // Configuration sequence
body()#driver.clock is only {
// Configuration logic
};
};
The only way I succeeded to stop Rx to be driven is by "overwriting" the MAIN uart_sequence body():
// The test that does not drives UART Rx
extend MAIN uart_sequence { // Rx sequence
body() #driver.clock is only {
};
};
extend MAIN vr_ad_sequence { // Configuration sequence
body()#driver.clock is only {
// Configuration logic
};
};
Here is the how the UART Rx sequence, driver and BFM are defined in the verification environment:
sequence uart_sequence using
item = uart_frame_s,
created_driver = uart_driver_u;
extend uart_driver_u {
event clock is only rise(port_clk$) #sim;
};
extend uart_rx_agent_u {
driver: uart_driver_u is instance;
};
extend uart_rx_agent_u {
uart_monitor : uart_rx_monitor_u is instance; // like uvm_monitor
uart_bfm : uart_rx_bfm_u is instance; // like uvm_bfm
};
extend uart_rx_bfm_u {
!cur_frame: uart_frame_s;
run() is also {
start execute_items();
};
execute_items() #rx_clk is {
while (TRUE) do{
cur_frame = p_agent.driver.get_next_item();
drive_frame(cur_frame);
};
};
drive_frame(cur_frame : uart_frame_s) #rx_clk is {
// Drive frame logic
};
};
Do you have any idea why uart_sequence drives its BFM even when its MAIN was not extended? Thank you for your help

In the Specman documentation there is an example and the explanation states:
The MAIN sequence creates count sequences of any kind, randomly
selected from the currently loaded ATM sequences.
The MAIN sequence is also described in its own section:
The MAIN sequence subtype is defined directly under the sequence
driver, and is started by default. It is the root for the whole
sequence tree.
The code for it is:
extend MAIN sequence_name {
count: uint;
!sequence: sequence_name;
keep soft count > 0;
keep soft count <= MAX_RANDOM_COUNT;
keep sequence.kind not in [RANDOM, MAIN];
body() #driver.clock is only {
for i from 1 to count do {
do sequence;
};
};
};
By extending it and overwriting its body() you are disabling the automatically generated code that starts random sequences.
You can also disable the MAIN sequence by constraining gen_and_start_main in the UART sequence driver.

Related

How to avoid globals in EEPROM structs for system settings?

I'm struggling with getting system settings from EEPROM and trying to avoid having them as global variables and wondered what the prevailing wisdom is and if there's an accepted practice and / or elegant solution.
I'm getting system settings stored in an EEPROM via structures with some error checking and the sizeof operator in main.c along the lines of:
// EEPROM data structures
typedef struct system_tag
{
uint8_t buzzer_volume;
uint8_t led_brightness;
uint8_t data_field_3;
} system_t;
typedef struct counters_tag
{
uint16_t counter_1;
uint16_t counter_2;
uint16_t counter_3;
} counters_t;
typedef struct eeprom_tag
{
system_t system_data;
uint8_t system_crc;
counters_t counters;
uint8_t counters_crc;
} eeprom_t;
// Default values
static system_t system_data =
{
.buzzer_volume = 50,
.led_brightness = 50,
.data_field_3 = 30
};
static counters_t counter =
{
.counter_1 = 0,
.counter_2 = 0,
.counter_3 = 0
};
// Get system settings data from the EEPROM
if (EEPROM_check_ok(EEPROM_BASE_ADDRESS, sizeof(system_t)))
{
eeprom_read_block(&system_data, (uint16_t *) EEPROM_BASE_ADDRESS, sizeof(system_t));
}
if (EEPROM_check_ok((EEPROM_BASE_ADDRESS + offsetof(eeprom_t, counters)), sizeof(counters_t)))
{
eeprom_read_block(&counter, (uint16_t *) EEPROM_BASE_ADDRESS, sizeof(counters_t));
}
I'm then using the system settings data at the moment to set other variables in different modules. E.g. in another file, buzzer.c, I have a module static variable (in an effort to avoid globals) with accessor functions to try and give some encapsulation:
// Current volume setting of the buzzer
static uint8_t volume = 50;
void BUZZER_volume_set(uint8_t new_volume)
{
volume = new_volume;
}
uint8_t BUZZER_volume_get(void)
{
return (volume);
}
The problem I feel is I've now got unnecessary duplication of data, as when I pass the buzzer_volume from the system data to set the static volume variable in the buzzer module things could get out of synchronisation. Having the system settings as globals would be easy, but I know this is frowned upon.
Is there a more elegant way of doing this without using globals and still having some encapsulation?
Any suggestions would be gratefully received.
General advice to avoiding globals (and why you need to do so) are given in Jack Ganssle's excelent article "A Pox on Globals". Essential reading.
One solution is simply to have accessor functions in main.c (or better a separate nvdata.c, to protect it from direct access by anything).
Rather then relying on a single initialisation function being called before any access to the data, I would suggest an "initialise on first use" semantic thus:
const system_t* getSystemData()
{
static bool initialised = false ;
if( !initialised )
{
eeprom_read_block( &system_data,
(uint16_t*)EEPROM_BASE_ADDRESS,
sizeof(system_t) ) ;
initialised = true ;
}
return &system_data ;
}
void setSystemData( const system_t* new_system_data )
{
system_data = *new_system_data ;
eeprom_write_block( &system_data,
(uint16_t*)EEPROM_BASE_ADDRESS,
sizeof(system_t));
}
Then in buzzer.c:
uint8_t BUZZER_volume_get(void)
{
return getSystemData()->buzzer_volume ;
}
void BUZZER_volume_set( uint8_t new_volume )
{
system_t new_system_data = *getSystemData() ;
new_system_data.buzzer_volume = new_volume ;
setSystemData( &new_system_data ) ;
}
There are some issues with this - such as if your structures are large updating a single member can be expensive. That could be resolved however, but may not be an issue in your application.
Another issue is the writing back to the EEPROM on every change - that may cause unnecessary thrashing of the EEPROM and stall your program for significant periods if you have several sequential changes to the same structure. In that case a simple method is to have a separate commit operation:
void setSystemData( const system_t* new_system_data )
{
system_data = *new_system_data ;
system_data_commit_pending = true ;
}
void commitSystemData()
{
if( system_data_commit_pending )
{
eeprom_write_block( &system_data,
(uint16_t*)EEPROM_BASE_ADDRESS,
sizeof(system_t));
}
}
where you commit the data only when necessary or safe to do so - such as on a controlled shutdown or explicitly selected UI "save settings" operation for example.
A more sophisticated method is to set a timer on change and have the commit function called when the timer expires, each "set" would restart the timer, so the commit would only occur in "quiet" periods. This method is especially suited to a multi-threaded solution.

Synchronisation mechanism without disabling interrupts on Cortex M0

To clarify a question assume that we have:
Static Button object: static Button_T sButton = {0};
Function to get Button: void GetButton(Button_T * p_button); that is called from main loop context
ISR handler: void ButtonISRHandler(void);
Assumptions:
GetButton execution can be interrupted by any interrupt that does not execute ButtonISRHandler
ButtonISRHandler execution can be interrupted by other iterrupts
GetButton execution takes less time than the minimum time between two ButtonISRHandler interrupts call.
Button interrupt is a cyclic interrupt triggered for instance every 10 ms.
In ButtonISRHandler we have procedures like checking button PIN state or detecting if button is touched (in touch button case). If a given PIN state is stable in e.g. for 5 consequtive calls then sButton object state is updated.
Button_T is generic object - it could be classic tact switch or touch button etc.
ScanButtonAndUpdate could handle a list of Button_T objects but GetButton function operates only on the one button object.
The problem is: classic case when an interrupt can occur when program counter is inside GetButton
The question is: How to synchronize GetButton with ButtonISRHandler without disableing Interrupts?
My target processor is Cortex M0 without LDREX/STREX operation so I cannot use atomics from C11 that would be great solution in this case.
My Proposed Solution
Use Critical Section in GetButton.
If an interrupt occured when the program counter is inside Critical Section then do not handle ScanButtonAndUpdate in interrupt but handle it on ExitCriticalSection. Defer ScanButtonAndUpdate execution.
There is no possibility to call ScanButtonAndUpdate function from interrupt and main context in the same time - this behaviour is protected by semaphore
Implementation
#define SEMAPHORE_GIVEN 0
#define SEMAPHORE_TAKEN 1
typedef uint32_t BaseType_T;
typedef struct Button_T;
static volatile BaseType_T sSemaphore = SEMAPHORE_GIVEN;
static volatile bool sIsPendingISR = false;
static volatile Button_T sButton = {0};
void GetButton(Button_T * p_button)
{
EnterCriticalSection();
memcpy(p_button, &sButton, sizeof(Button_T))
/* Other procedures on sButton... */
ExitCriticalSection();
}
/* Cyclic executed handler */
void ButtonISRHandler(void)
{
if (!BinarySemaphoreTake()) {
SetISRPending();
}
else {
ScanButtonAndUpdate();
BinarySemaphoreGive();
}
}
void ScanButtonAndUpdate(void)
{
/* Scan for instance a current PIN state and update sButton object
if state is stable in next calls */
}
static void EnterCriticalSection(void)
{
while(false == BinarySemaphoreTake()) continue;
}
static void ExitCriticalSection(void)
{
BinarySemaphoreGive();
if (IsPendingISR()){
ScanButtonAndUpdate();
ResetISRPending();
}
}
static bool BinarySemaphoreTake(void)
{
if (SEMAPHORE_GIVEN == sSemaphore) {
/* Value Store operation is atomic on the architecture native type */
sSemaphore = SEMAPHORE_TAKEN;
return true;
}
else {
return false;
}
}
static void BinarySemaphoreGive(void)
{
sSemaphore = SEMAPHORE_GIVEN;
}
static void SetISRPending(void)
{
sIsPendingISR = true;
}
static void ResetISRPending(void)
{
sIsPendingISR = false;
}
static bool IsPendingISR(void)
{
return sIsPendingISR;
}
This solution was tested and works great without problems but I am not sure that this is the best solution without hidden bugs.
EDIT 1: Updated Assumptions and added missing ScanButtonAndUpdate function
There is a hidden synchronization which affects whether you have a race condition or not: what gates the Interrupt? The two most common scenarios are edge and level triggered; an edge trigger means that the interrupt will be inhibited until the device is cleared, whereas a level trigger means that the interrupt will repeatedly re-assert until the device is cleared.
If your code uses level triggered interrupts, then you have omitted this synchronization entirely, or you are pretending that sIsPendingISR is the mask & status flag. In that case, you look alright
If it is level triggered, then it can re-assert during /* Update sButton object */, causing the device handling code to be executing in two contexts (interrupt + normal). Most device code is not designed to do this.
Btw, there is a software protocol called “Dekkers Algorithm” which provides a general solution to mutual exclusion without hardware support. You have sort of integrated a version of it here.

ns2 rebroadcasting packet when timer is expired

i need to rebroadcast packet when a waiting timer is expired, i follow steps defined at How to add timer in aodv using ns2 , i define agent and timer classes; the cross reference; initialization of timer object in agent constructor; and finally expire(Event*) for class B_suppression. when the execution reach
agent->rebroadcast((Packet*)p, 0); it abort with following message 'invalid SDVCAST packet type'. is casting from Event to Packet causes the problem?
class SDVCAST;
class B_suppression_Timer : public TimerHandler {
friend class SDVCAST;
public:
B_suppression_Timer (SDVCAST *s){agent = s;};
virtual void expire (Event *p);
private:
SDVCAST *agent;
};
class SDVCAST: public Agent
{ //define object from timer
B_suppression_Timer bstimer;
}
//initialized timer in Constructor of the SDVCAST
SDVCAST::SDVCAST(nsaddr_t id) : Agent(PT_SDVCAST),
bstimer(this){
}
// start timer
void
SDVCAST::weightepersistence(Packet *p, double delay){
bstimer.resched(delay);
}
// define expire of bstimer
void
B_suppression_Timer::expire(Event *p){
agent->rebroadcast((Packet*)p, 0);
}
Add the new packet type PT_SDVCAST to common/packet.h
static const packet_t PT_ SDVCAST = 73;
// insert new packet types here
static packet_t PT_NTYPE = 74; // This MUST be the LAST one
.
.
type == PT_SDVCAST)
.
.
name_[PT_SDVCAST]= "SDVCAST"
And maybe add SDVCAST to tcl/lib/ns-packet.tcl, ns-default.tcl , ns-agent.tcl etc.
EDIT : Answer to "Segmentation fault"
"The implementation of the Packet data structure of NS2 does not math
the realities. The packet in ns2 simulation keeps all packet headers
for any protocols implemented in NS2. For example, a DSR routing
packet may keep DSDV, AODV, or even a PING application header. For
this reason, till today, a packet used in ns2 simulation, would have a
header size around 40~64KB. And NO packet would be deleted to release
the memory it holds until the end of the simulation. So for a typical
simulation with 100 nodes in ns2 around 1M packets exchanged (of
course, you may reuse the packets already being freed through
Packet::free(Packet*). To learn the implementation of it, please check
file common/packet{.h,.cc} ), you may hold 10% of it, 100K packets,
and you may use a memory at least 100K*64KB -> 6.4GB, which definitely
would crash your computer (even it is a super server)."
Etc. etc. See http://www.linuxquestions.org/questions/linux-networking-3/ns2-and-aqua-sim-4175507630/#3
http://www.linuxquestions.org/questions/tags/segmentation%20fault%20ns2/

Does this Interrupt Disable/Enable pair from TI's gamepad example project accomplish anything?

This code from TI's ek-tm4c123gxl usb-dev-gamepad CCS example wraps an volatile enum assignment to g_iGamepadState in an interrupt disable/enable pair. To me it looks like a bug; that it should instead be wrapping the send report function USBDHIDGamepadSendReport() to prevent mid-send interruption. As is I would assume this it's preventing the interrupt of a single store instruction, which would be redundant.
Below is the all code which references the enum...
volatile enum {
eStateNotConfigured, // Not yet configured.
eStateIdle, // Connected, not waiting on data to be sent
eStateSuspend, // Suspended
eStateSending // Connected, waiting on data to be sent out
} g_iGamepadState;
...
//*****************************************************************************
//
// Handles asynchronous events from the HID gamepad driver.
//
// \param pvCBData is the event callback pointer provided during
// USBDHIDGamepadInit(). This is a pointer to our gamepad device structure
// (&g_sGamepadDevice).
// \param ui32Event identifies the event we are being called back for.
// \param ui32MsgData is an event-specific value.
// \param pvMsgData is an event-specific pointer.
//
// This function is called by the HID gamepad driver to inform the application
// of particular asynchronous events related to operation of the gamepad HID
// device.
//
// \return Returns 0 in all cases.
//
//*****************************************************************************
uint32_t GamepadHandler(void *pvCBData, uint32_t ui32Event,
uint32_t ui32MsgData, void *pvMsgData) {
switch (ui32Event) {
case USB_EVENT_CONNECTED: {
g_iGamepadState = eStateIdle;
break;
}
case USB_EVENT_DISCONNECTED: {
g_iGamepadState = eStateNotConfigured;
break;
}
case USB_EVENT_TX_COMPLETE: {
g_iGamepadState = eStateIdle;
break;
}
case USB_EVENT_SUSPEND: {
g_iGamepadState = eStateSuspend;
break;
}
case USB_EVENT_RESUME: {
g_iGamepadState = eStateIdle;
break;
}
...
default: {
break;
}
}
return (0);
}
...
int main(void) {
...
// Not configured initially.
g_iGamepadState = eStateNotConfigured;
...
while (1) {
//
// Wait here until USB device is connected to a host.
//
if (g_GamepadState == eStateIdle) {
...
USBDHIDGamepadSendReport(&g_sGamepadDevice, &sReport,
sizeof(sReport));
//
// Now sending data but protect this from an interrupt since
// it can change in interrupt context as well.
//
IntMasterDisable();
g_iGamepadState = eStateSending;
IntMasterEnable();
}
}
}
From TI's E2E forum...
I think you are correct. This may be a bug.
It is possible for an Idle TX event to return between sending the report and changing to the sending state enum, which would then never leave the sending state. This explanation seems to make the most sense as to why the disable/enable interrupt pair is there in the first place.

Alternative to blocking code

Attempting to use mbed OS scheduler for a small project.
As mbed os is Asynchronous I need to avoid blocking code.
However the library for my wireless receiver uses a blocking line of:
while (!(wireless.isRxData()));
Is there an alternative way to do this that won't block all the code until a message is received?
static void listen(void) {
wireless.quickRxSetup(channel, addr1);
sprintf(ackData,"Ack data \r\n");
wireless.acknowledgeData(ackData, strlen(ackData), 1);
while (!(wireless.isRxData()));
len = wireless.getRxData(msg);
}
static void motor(void) {
pc.printf("Motor\n");
m.speed(1);
n.speed(1);
led1 = 1;
wait(0.5);
m.speed(0);
n.speed(0);
}
static void sendData() {
wireless.quickTxSetup(channel, addr1);
strcpy(accelData, "Robot");
wireless.transmitData(accelData ,strlen(accelData));
}
void app_start(int, char**) {
minar::Scheduler::postCallback(listen).period(minar::milliseconds(500)).tolerance(minar::milliseconds(1000));
minar::Scheduler::postCallback(motor).period(minar::milliseconds(500));
minar::Scheduler::postCallback(sendData).period(minar::milliseconds(500)).delay(minar::milliseconds(3000));
}
You should remove the while (!(wireless.isRxData())); loop in your listen function. Replace it with:
if (wireless.isRxData()) {
len = wireless.getRxData(msg);
// Process data
}
Then, you can process your data in that if statement, or you can call postCallback on another function that will do your processing.
Instead of looping until data is available, you'll want to poll for data. If RX data is not available, exit the function and set a timer to go off after a short interval. When the timer goes off, check for data again. Repeat until data is available. I'm not familiar with your OS so I can't offer any specific code. This may be as simple as adding a short "sleep" call inside the while loop, or may involve creating another callback from the scheduler.

Resources