Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / api / memsync / src / LoadStoreBuffer.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: LoadStoreBuffer.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
//
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
//
// The above named program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
// ========== Copyright Header End ============================================
/************************************************************************
**
** Copyright (C) 2002, Sun Microsystems, Inc.
**
** Sun considers its source code as an unpublished, proprietary
** trade secret and it is available only under strict license provisions.
** This copyright notice is placed here only to protect Sun in the event
** the source is deemed a published work. Disassembly, decompilation,
** or other means of reducing the object code to human readable form
** is prohibited by the license agreement under which this code is
** provided to the user or company in possession of this copy."
**
*************************************************************************/
#include "LoadStoreBuffer.h"
#include <sstream>
using namespace std;
////////////////////////////////////////////////
LoadStoreBuffer::LoadStoreBuffer()
{
// cerr << "LoadStoreBuffer Created, size= " << buf_.size() << endl;
}
////////////////////////////////////////////////
LoadStoreBuffer::LoadStoreBuffer( const LoadStoreBuffer & orig )
{
}
////////////////////////////////////////////////
LoadStoreBuffer::~LoadStoreBuffer()
{
}
////////////////////////////////////////////////
const LoadStoreBuffer &
LoadStoreBuffer::operator=( const LoadStoreBuffer & rhs )
{
return *this;
}
////////////////////////////////////////////////
bool
LoadStoreBuffer::operator==( const LoadStoreBuffer & rhs ) const
{
return false;
}
////////////////////////////////////////////////
string
LoadStoreBuffer::toString() const
{
ostringstream os;
list<LoadStoreEntry>::const_iterator ii;
os << bufName_ << " (size=" << buf_.size() << ")" << endl;
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
os << ii->toString();
}
os << endl;
return os.str();
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::pushBack(LoadStoreEntry& entry)
{
// cerr << "In LoadStoreBuffer::pushBack" << endl;
list<LoadStoreEntry>::iterator it;
buf_.push_back(entry);
#ifdef MMDEBUG
//MSYNC_DEBUG(1, "%s", toString().c_str());
MSYNC_DEBUG(1, "%s Pushback\n%s", bufName_, entry.toString().c_str());
MSYNC_DEBUG(1, "%s", toString().c_str());
#endif
it = buf_.end();
return (--it);
}
void
LoadStoreBuffer::erase(list<LoadStoreEntry>::iterator ii)
{
//assert(buf_.size() > 0);
if (buf_.size() == 0) return;
#ifdef MMDEBUG
MSYNC_DEBUG(1, "%s Erase\n%s", bufName_, ii->toString().c_str());
#endif
buf_.erase(ii);
#ifdef MMDEBUG
MSYNC_DEBUG(1, "%s", toString().c_str());
#endif
}
void
LoadStoreBuffer::popFront()
{
list<LoadStoreEntry>::iterator ii;
//assert(buf_.size() > 0);
if (buf_.size() == 0) return;
ii = buf_.begin();
#ifdef MMDEBUG
MSYNC_DEBUG(1, "%s Remove (front)\n%s", bufName_, ii->toString().c_str());
#endif
buf_.pop_front();
#ifdef MMDEBUG
MSYNC_DEBUG(1, "%s", toString().c_str());
#endif
}
void
LoadStoreBuffer::popBack(int count)
{
list<LoadStoreEntry>::iterator ii;
//assert (buf_.size() >= count);
if (buf_.size() < count) return;
for (int i = 0; i < count; i++) {
ii = --(buf_.end());
#ifdef MMDEBUG
MSYNC_DEBUG(1, "%s Remove (back)\n%s", bufName_, ii->toString().c_str());
#endif
buf_.pop_back();
}
#ifdef MMDEBUG
MSYNC_DEBUG(1, "%s", toString().c_str());
#endif
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::findMatchY2O(uint64_t addr, uint8_t size_vector)
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
ii = buf_.end();
do {
ii--;
assert(ii->isValid());
if ((addr & ADDR_MASK) == (ii->getAddr() & ADDR_MASK) &&
(size_vector == (size_vector & ii->getSizeV()))) {
return (ii);
}
} while (ii != buf_.begin());
return (buf_.end()); // use buf_.end() to indicate not found
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::findMatchY2O(uint64_t id, uint64_t addr, uint8_t size_vector)
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
ii = buf_.end();
do {
ii--;
assert(ii->isValid());
if (id == ii->getId() &&
(addr & ADDR_MASK) == (ii->getAddr() & ADDR_MASK) &&
size_vector == (size_vector & ii->getSizeV())) {
// assert(ii->isLinkValid() == false);
return (ii);
}
} while (ii != buf_.begin());
return (buf_.end()); // use buf_.end() to indicate not found
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::findMatchO2Y(uint64_t addr, uint8_t size_vector)
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
assert(ii->isValid());;
if (ii->isLinkValid() == false &&
(addr & ADDR_MASK) == (ii->getAddr() & ADDR_MASK) &&
size_vector == (size_vector & ii->getSizeV())) {
return (ii);
}
}
return (buf_.end()); // use buf_.end() to indicate not found
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::findMatchO2Y(uint64_t id, uint64_t addr, uint8_t size_vector)
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
assert(ii->isValid());;
if (id == ii->getId() &&
(addr & ADDR_MASK) == (ii->getAddr() & ADDR_MASK) &&
size_vector == ii->getSizeV()) {
// assert(ii->isLinkValid() == false);
return (ii);
}
}
return (buf_.end()); // use buf_.end() to indicate not found
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::findMatchO2Y(uint64_t addr, enum LS_ENTRY_STATE state, uint64_t addrMask)
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
assert(ii->isValid());;
if ((addr & addrMask) == (ii->getAddr() & addrMask) &&
state == ii->getState()) {
// assert(ii->isLinkValid() == false);
return (ii);
}
}
return (buf_.end()); // use buf_.end() to indicate not found
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::findMatchO2Y(uint64_t addr)
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
assert(ii->isValid());;
if (addr == ii->getAddr()) {
// assert(ii->isLinkValid() == false);
return (ii);
}
}
return (buf_.end()); // use buf_.end() to indicate not found
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::findMatchO2Y(uint64_t addr, bool rmo, uint64_t addrMask)
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
assert(ii->isValid());;
if (((addr & addrMask) == (ii->getAddr() & addrMask)) &&
((rmo && ii->isRMOstore()) || (!rmo && !ii->isRMOstore()))) {
return (ii);
}
}
return (buf_.end()); // use buf_.end() to indicate not found
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::findNotIssuedO2Y(uint64_t addr)
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
assert(ii->isValid());;
if (!ii->isIssued() &&
(addr == ii->getAddr())) {
return (ii);
}
}
return (buf_.end()); // use buf_.end() to indicate not found
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::find1stNoLink(uint64_t id, uint64_t addr, uint64_t addrMask)
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
assert(ii->isValid());;
if (!ii->isLinkValid() &&
(ii->getId() == id) &&
(ii->getAddr() & addrMask) == (addr & addrMask)) {
return (ii);
}
}
return (buf_.end()); // use buf_.end() to indicate not found
}
/* Note that this function exclude prefetch instruction */
list<LoadStoreEntry>::iterator
LoadStoreBuffer::find1stNonExe()
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
assert(ii->isValid());;
if (!(ii->isExecuted())) {
/* Riesling does not access memory for prefetch instruction, and hence
no STEP callback. To overcome this issue, the MemorySync model use
the next non-prefetch instruction to remove the prefetch instructions
in the LoadBuffer and MemoryAccessBuffer by setting its executed_.
*/
if (ii->getItype() != ITYPE_PREFETCH) {
return (ii);
} else {
ii->setExecuted(true);
if (!ii->isLinkValid())
{
MS_ERROR("Found prio prefetch in LoadBuffer does not have LoadData");
return buf_.end();
}
ii->getLink()->setExecuted(true);
}
}
}
return (buf_.end()); // use buf_.end() to indicate not found
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::find1stNonExeMatchedAddr(uint64_t addr)
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
#ifdef MMDEBUG
MSYNC_DEBUG(1, "Find addr=%#llx \n%s", addr, toString().c_str());
// cerr << "FIND addr=0x" << hex << addr << endl;
// cerr << toString();
#endif
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
assert(ii->isValid());;
if (!(ii->isExecuted()) && addr == ii->getAddr()) {
return (ii);
}
}
return (buf_.end()); // use buf_.end() to indicate not found
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::find1stNonExeFetch(uint64_t addr)
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
#ifdef MMDEBUG
MSYNC_DEBUG(1, "Find addr=%#llx \n%s", addr, toString().c_str());
// cerr << "FIND addr=0x" << hex << addr << endl;
// cerr << toString();
#endif
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
assert(ii->isValid());;
if (!(ii->isExecuted()) &&
// (ii->getState() == LS_ACK) &&
addr == ii->getAddr()) {
return (ii);
}
}
return (buf_.end()); // use buf_.end() to indicate not found
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::find1stNonExeOrMatchedAddrAtomic(uint64_t addr)
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
#ifdef MMDEBUG
MSYNC_DEBUG(1, "Find addr=%#llx \n%s", addr, toString().c_str());
// cerr << "FIND addr=0x" << hex << addr << endl;
// cerr << toString();
#endif
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
assert(ii->isValid());;
if (!(ii->isExecuted())) {
if (ii->getItype() != ITYPE_ATOMIC) {
return (ii);
} else { // atomic
if (addr == ii->getAddr()) {
return (ii);
} else {
ii->setExecuted(true);
if (ii->isLinkValid()) {
ii->getLink()->setExecuted(true);
}
}
}
}
}
return (buf_.end()); // use buf_.end() to indicate not found
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::findNeedTDataO2Y(uint64_t addr)
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
assert(ii->isValid());
if (!ii->isIssued() && ii->getState() != LS_TDATA && // only possible states are NEW & RDATA
(addr) == (ii->getAddr())) {
// assert(ii->isLinkValid() == false);
return (ii);
}
}
return (buf_.end()); // use buf_.end() to indicate not found
}
list<LoadStoreEntry>::iterator
LoadStoreBuffer::findDataBypassing (uint64_t addr, uint8_t size_vector)
{
list<LoadStoreEntry>::iterator ii;
uint8_t overlap;
if (buf_.size() == 0) {
return buf_.end();
}
ii = buf_.end();
do {
ii--;
assert(ii->isValid());
if ((addr & ADDR_MASK) == (ii->getAddr() & ADDR_MASK)) {
overlap = size_vector & ii->getSizeV();
if (overlap == size_vector) { // entry's data is a superset => bypassing
return (ii);
} else if (overlap == 0) { // no overlap, search for next
continue;
} else { // partially overlap => access from L2
return (buf_.end());
}
}
} while (ii != buf_.begin());
return (buf_.end()); // use buf_.end() to indicate not found
}
/******************************************************************************
* The store buffer bypassing check criteria is changed on 5/17/04 that treats
* multiple hits as partial hit. In other words, no bypassing. To know this,
* the algorithm has to check the whole store buffer.
******************************************************************************/
list<LoadStoreEntry>::iterator
LoadStoreBuffer::findN2DataBypassing (uint64_t addr, uint8_t size_vector)
{
list<LoadStoreEntry>::iterator ii;
list<LoadStoreEntry>::iterator matched_ste;
bool matched;
uint8_t overlap;
if (buf_.size() == 0) {
return buf_.end();
}
matched = false;
for (ii = buf_.begin(); ii != buf_.end(); ii++) {
assert(ii->isValid());
if ((addr & ADDR_MASK) == (ii->getAddr() & ADDR_MASK)) {
overlap = size_vector & ii->getSizeV();
if (overlap == size_vector) { // entry's data is a superset => bypassing
if (matched) {
return (buf_.end()); // multiple hits
} else {
matched = true;
matched_ste = ii;
continue;
}
} else if (overlap == 0) { // no overlap, search for next
continue;
} else { // partially overlap => access from L2
return (buf_.end());
}
}
}
return (matched ? matched_ste : buf_.end()); // use buf_.end() to indicate not found
}
//=============================================================================
//=============================================================================
void
LoadStoreBuffer::empty()
{
//cerr << "DBX: LoadStoreBuffer::empty: " << bufName_ << " size=" << buf_.size() << endl;//DBX
//TODO make sure we free the space properly
buf_.clear();
// while (buf_.size() > 0) {
// buf_.pop_front();
// }
}
//=============================================================================
//=============================================================================
list<LoadStoreEntry>::iterator
LoadStoreBuffer::queryBack()
{
list<LoadStoreEntry>::iterator ii;
if (buf_.size() == 0) {
return buf_.end();
}
else {
ii = --(buf_.end());
return (ii);
}
}
//=============================================================================
//=============================================================================
void
LoadStoreBuffer::markPop()
{
list<LoadStoreEntry>::iterator ii = buf_.end();
int size = buf_.size();
while (size > 0) {
ii--;
size--;
if (ii->isLinkValid() && ii->getLink()->isPopped()) {
//ii->setExecuted(true);
buf_.erase(ii);
}
}
}