Normal memory can be further augmented by other attributes as well. Different types of normal memory can become weaker to allow for extra behaviors based on these attributes. For example, if we mark a normal memory to also be cacheable, then that means this data may be cached or may exist inside a cache, not that they must or will be cached. Another attribute is the shareable attribute, which indicates whether other masters will also need to access this shared data. Complex systems may make this data visible using extra coherency logic. If we make a particular normal memory to be normal and cacheable, then that means it could exist in processing element zeros cache or processing element ones cache. If it is ever modified, the cache coherency logic hardware will maintain the cache coherency automatically. If we wanted to share this memory between one processing element with coherent cache and another processing element without a coherent cache, or that there are no hardware coherency logic that maintains between these two processing elements, then marking that normal region to be normal and shareable and cacheable will be implemented as not possible to be cached. Because there are no hardware coherency to maintain the transparency of access between the two processing elements, then that means it will be treating those implementations non-cacheable. If the same normal shareable memory is implemented on a non-cacheable PE, well, then there's nothing special can do since it doesn't have a cache, so it cannot be cached. The last bullet point here that says software that specifies the correct memory type for the desired behavior will then work correctly on any implementation is just another way of saying if you mark your memory correctly with this intended usage, it will behave although differently on your permutations with different features and capabilities, it will always be treated as correct. For example, the three examples below here, when we mark a normal memory to be both cacheable and shareable in a complex core with coherency logic, this is taken care of by the hardware coherency logic. On implementation with no hardware coherency logic or the only way to be cacheable and shareable is for it to be treated as non-cache since the different PEs cannot look inside each other's caches without the coherency logic. Lastly, the last example here. If we cannot have or we have a processing element without caches, then even if you mark it as cacheable, it will always be treated essentially non-cacheable on that implementation. In other words, depending on the implementation you're on, the actual behavior may differ even though you have marked the normal memory with this intended usage. Let's look into a little bit deeper detail about the shareability attribute. The sharable attribute is used to define whether a location is shared with multiple processors. There are three options here. Non-shareable, which means that only is used by one particular observer with one processing elements. We can also mark normal memory to be inner shareable or outer shareable, meaning this memory is intended to be shared with other observers, however, the division between inner and outer shareable is technically implementation defined and could be different from one processor to the next. For example, if we have some local memory that's reserved for just one processor, in this case, processing element 1, PE1, then we mark that as non-shared. Regardless of whether it's cacheable or not, we can be free to access it however we like since we have now marked it as never being shared with anyone else. For example, if we do want to share some amount of memory between PE1 and PE2, we can mark that to have the inner shareable attribute, which means that it will only be shared with masters that are considered to be the inner domain. There could be other memory that we also want to share not only with the observers in the inner domain, but also observers in the outer domain. For example, there's some memory buffer that we want to share between PE1 and PE2, but also being able to be read by an external DMA engine, then we can mark this memory to be outer shareable, which is now visible essentially to everyone. These attributes can define these sets observers for which the shareability attribute make the data or unified caches transparent for data accesses. Of course, the wider we make the accesses available, the more observers that are able to see it, but also it cost a bit more in terms of power and latency to access. So there's a bit of a trade-off on what's visible and what you actually need afford to do.