ARM Technical Support Knowledge Articles

How do I implement an AMBAPV ACE master?

Applies to: Fast Models



The purpose of this example system is to demonstrate the implementation of an AMBA-PV ACE master. ACE is a protocol used to provide system level coherency for the sharing of memory by system components and to maintain coherency between caches. The ACE protocol enables system architects to select the most appropriate technique for sharing data between system components. The protocol does not define specific usage cases, but some examples are:

The System

The main components of the example system are:

ACE Master (SystemC)

The ACE master in this example is a simple reactive component that has:

The ace port is used for all transactions and snooping. The signal port on the other hand is only used by the A-15 core to signal the ACE master component to initiate a read transaction. In order to implement an AMBA-PV ACE master, follow these general guidelines.

Setting up the ACE master class

     * Ace master module definition.
     class ace_master : public sc_core::sc_module, 
                        public amba_pv::amba_pv_ace_master_base,
public amba_pv::signal_slave_base<bool>
* Invalidates DMI pointers previously established for the
* specified DMI region.
* Default implementation in amba_pv_ace_master_base.h does nothing.
* So implement here if DMI is support required. 
void ace_master::invalidate_direct_mem_ptr(int,
* Blocking snoop transport.
* Function used to deal with SNOOP requests and SNOOP responses 
void ace_master::b_snoop(int,
amba_pv::amba_pv_transaction & trans,
sc_core::sc_time &) 
   amba_pv::amba_pv_transaction  trans;
           amba_pv::amba_pv_extension    ex(4, NULL);
            * Set transaction attributes, i.e. size, cacheable etc.
           * Set pointer to this extension object
   /* Transaction proceeds */ 
           amba_pv_ace_m->b_transport(trans, t);
           /* Get response upon completion of transaction */
case amba_pv::AMBA_PV_SLVERR: 
case amba_pv::AMBA_PV_DECERR: 
printf("\n\nError returned on bus\n\n");
case amba_pv::AMBA_PV_OKAY:
if (ex.is_exclusive())
printf("\n\nExclusive fail\n\n");
case amba_pv::AMBA_PV_EXOKAY:

SNOOP Responses

There are 3 new channels defined by the ACE protocol. These are snoop address, snoop response, and snoop data channels. Snoop transactions are a subset of coherent transactions and cache maintenance transactions. For the purpose of responding to a SNOOP response, the ACE Master needs to set the relevant signals of the snoop response channel as per requirements. The real hardware's snoop response channel has the following signals:

You can find more information on the ACE protocol and snoop responses in the AMBA-PV ACE reference manual found here.

There are multiple ways an ACE master can respond to snoop requests, for example, a snooped master can handle all snoop transactions in the same way as a ReadUnique transaction. This is permitted because a ReadUnique transaction is an accepted alternative snoop transaction for all other snoop transactions. Our example does exactly this, i.e. treats every snoop as a ReadUnique transaction.

* Blocking snoop transport.
* Function used to deal with SNOOP requests and SNOOP responses 
void ace_master::b_snoop(int,
amba_pv::amba_pv_transaction & trans,
          sc_core::sc_time &) 
//No DMI allowed during upstream snoops

// Retrieve AMBA-PV extension
                amba_pv::amba_pv_extension * ex = NULL;

//Check if AMBA-PV extension was retrieved successfully
                if (ex == 0)

//Identify the kind of snoop
case amba_pv::AMBA_PV_READ_ONCE:
std::cout << name() << ": AMBA_PV_READ_ONCE Snoop received.\n";

if(cacheLine.Invalid) {
std::cout << name() << ": Cache line is invalid! [MISS]\n\n";
//Send response "cache line invalid" by setting appropriate response bits
ex->set_snoop_data_transfer(false);   // CRRESP[0]
ex->set_snoop_error(false);           // CRRESP[1]
ex->set_pass_dirty(false);            // CRRESP[2]
ex->set_shared(false);                // CRRESP[3]
ex->set_snoop_was_unique(false);      // CRRESP[4]
} else {
std::cout << name() << ": Cache line is valid! [HIT]\n";
std::cout << name() << ": Sending line to A-15 and invalidating the line.\n";

// Copy cacheline into the transaction buffer 
memcpy(trans.get_data_ptr(), cacheline, 64); 
//Send response and data by setting appropriate response bits
ex->set_snoop_data_transfer(true);   // CRRESP[0]
ex->set_snoop_error(false);          // CRRESP[1]
ex->set_pass_dirty(true);            // CRRESP[2]
ex->set_shared(false);               // CRRESP[3]
ex->set_snoop_was_unique(true);      // CRRESP[4]

//Make cache line invalid after transferring it
cacheLine.Invalid = true;

case amba_pv::AMBA_PV_READ_CLEAN:
std::cout << "\n\n" << name() << ": Invalid SNOOP request received!\n" << std::endl;

As it can be seen from the above code snippet, in the b_snoop() method, we first extract the extension object from the transaction using trans.get_extension(). Then we need to identify the kind of snoop request in order to deal with it appropriately. This is done using the "get_snoop()" function. Once, the snoop has been identified, the ACE master checks if its cache line is valid or not. If invalid, i.e. a miss, it returns an error back as a response by setting all the bits of CRESP[4:0] signal to '0'. If the cache line is valid, i.e. a hit, the entire cache line is transferred back to initiator. This is done by setting the CRESP[0] signal to HIGH. In Fast Models, this can be done using the "set_snoop_data_transfer(true)" API. The response also indicates to the initiator that the data being passed is dirty since the ACE master will now invalidate its cache. This is done using the "set_pass_dirty(true)" API (setting the CRESP[2] signal). 

Application Code

The application code for this example sets up the page table entries and enables the MMU. To demonstrate the coherency between the A-15 core and the ACE master component the following tests are carried out from software.

  1. The A-15 reads a cacheable location (address 0x10000000).
  2. The ACE master component receives an AMBA_PV_READ_SHARED snoop. Since the ACE master's cache is initialized with dirty data, it is a cache hit and the line data and ownership is passed on to A-15's cache.
  3. Now A-15 writes a value to the same location (value 0xCAFEBEEF) and makes it's cache line dirty.
  4. The ACE master performs a read at address location 0x10000000.
  5. A snoop transaction is now received by A-15 and data is passed onto the ACE master component. 
  6. The ACE master cache contents are displayed and the 0xCAFEBEEF can now be found in its cache line.

To run the example

  1. Build the example system using the provided makefile inside the "Build" directory.
  2. Build application code using the provided batch file inside the "App" directory.
  3. Run the simulation using the following command:

      ACEDemo.exe -a ..\App\image.axf

Attachments: Ace_Master.png , Untitled.png ,

Article last edited on: 2013-08-27 13:35:21

Rate this article

Disagree? Move your mouse over the bar and click

Did you find this article helpful? Yes No

How can we improve this article?

Link to this article
Copyright © 2011 ARM Limited. All rights reserved. External (Open), Non-Confidential