Modeling ISRs with VMM RAL
Posted by Amit Sharma on 4th November 2010
In a verification environment, different components may be trying to access the DUT registers and memories. For example, the BFM might be programming some registers while the bus monitor might be sampling the values of these registers. In specific cases, there may be an interrupt monitor which triggers an Interrupt Service Routine (ISR) whenever it sees an Interrupt pin toggling in the interface. The ISR might end up having to read the Interrupt registers and end up clearing the Interrupt bit/s through a front door access.
To ensure that different components in a verification environment can access the DUT registers at any given point in time, the RAL model instantiated in the environment can be passed to different VMM components. These different components whose methods are executing in separate parallel threads can now access the same set of registers in the DUT through the RAL model. A question many folks ask is: when there are multiple parallel register accesses, how do they get scheduled through the RAL layer? Here is an explanation of how threads are scheduled in RAL:
A Register read/write from different threads is comparable to an ‘atomic’ channel.put() from different threads. Hence it gets scheduled in the order of pipelining of the threads.
A write/read would basically consist of the following atomic operations:
- A generic vmm_rw_access transaction with its fields (addr, data, kind etc) being populated and posted onto the execute_single() task of the Translate Transactor
- The transaction being translated in the execute_single() task and pushed into the input channel of the user BFM
- The transaction being retrieved through get/activate in the User BFM main thread and then subsequently driven to the DUT interface
Thus ‘posting’ of RAL accesses whenever a Read/Write/Mirror/Update is invoked is in the same order they are issued. Subsequently, the execute_single() task just translates the generic RW RAL transaction to a User BFM comprehensible transaction, and doesn’t change the order.
Now, how do we handle a scenario when specific register accesses like those coming from an ISR need to be given a higher priority than accesses coming from other threads in a verification environment? VMM and RAL methods give us specific hooks to achievethis requirement. Here is one of the options on how this can be done.
If we look at the vmm_ral_reg::write method, we have the given signature:
virtual task write( output vmm_rw::status_e status,
input bit [63:0] value,
input vmm_ral::path_e path = vmm_ral::DEFAULT,
input string domain = "",
input int data_id = -1,
input int scenario_id = -1,
input int stream_id = -1)
Now, a generic RAL transaction that gets created through any Register access has the same data_id, scenario_id, stream_id arguments which get passed on from the read/write call. These arguments help us tag and track the transactions if that is so desired. Now, these arguments can be made use of in the execute_single() task to ensure that accesses from ISRs have the highest priority. But, first, if we go back to the earlier post by Varun, Issuing concurrent READ/WRITE accesses to the same register on two physical interfaces using RAL, Issuing concurrent accesses to the same registers on two physical interfaces using RAL , we note that if the RAL model is processing a ‘register access’ , it will not initiate the next one until the earlier one is completed. So, this is what we need to get done.We first use the RAL Proxy transactor to schedule the ISR register access simultaneously. After that, we flush out any existing accesses and prevent any new register access through RAL until access from the ISR is completed
This is how it, will be done:
For a normal register access, a read/write method will be invoked as follows:
ral_model.<reg_name>.write(stat,wdata, “AHB”); //’wdata’ is the value to be driven, “AHB” is the domain /physical interface
For a register access in an ISR modeled in a MS Scenario, we have:
env.bfm.to_ahb.grab(this); //grabs the channel
env.ral.read(status, env.ral_model.<reg_name>.get_address_in_system("AHB"), data, 32, "AHB",,,1); // The last argument is again the “stream_id” argument
env.bfm.to_ahb.ungrab(this); //allows the channel to be accessed from other threads once the ISR is completed
Once, this is done, the execute_single() task inside the translate Transcator will know if an access is through an ISR and can ensure that ISRs are processed on priority through a combination of functionality provided through the VMM Channel methods in combination with a semaphore:
virtual task execute_single(vmm_rw_access tr);
AHB_tr cyc;
AHB_tr cyc_active; //to keep any transactions residing on the active slot
semaphore sem = new(1); //semaphore with a single key to prevent new accesses when a reg access from an ISR is processed
// Translate the generic RW into a simple RW
cyc = new;
{cyc.dev, cyc.addr} = tr.addr;
if (tr.kind == vmm_rw::WRITE) begin
cyc.cycle = simple_tr::WRITE;
cyc.data = tr.data;
…
end
else begin
cyc.cycle = simple_tr::READ;
…
end
if (tr.stream_id != 1) sem.get(1); // regular register access gets blocked here when a reg access from an ISR is processed
else begin
if(this.bfm.to_ahb.is_full()) begin
this.bfm.to_ahb.activate(cyc_active); //removes any existing transactions in the channel’s active slot so that the current access can be pushed through
this.in_chan.start();
this.in_chan.complete();
this.in_chan.remove();
this.bfm.to_ahb.put(cyc);
this.bfm.to_ahb.put(cyc_active); //restores the original transaction back into the active slot
cyc = cyc_active;
sem.put(1); //ths ISR access puts back the key for normal accesses to resume
end
else this.bfm.to_ahb.put(cyc);
end
// Send the result back to the RAL
if (tr.kind == vmm_rw::READ) begin
tr.data = cyc.data;
end
endtask: execute_single
Posted in Register Abstraction Model with RAL, VMM infrastructure, vmm_channel | No Comments »