blob: 944693a65683252f9326295262b916419738aa94 [file]
// Copyright 2023-2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdint>
#include "absl/functional/bind_front.h"
#include "googlemock/include/gmock/gmock.h"
#include "mpact/sim/generic/action_point_manager_base.h"
#include "mpact/sim/generic/breakpoint_manager.h"
#include "mpact/sim/generic/component.h"
#include "mpact/sim/generic/data_buffer.h"
#include "mpact/sim/util/memory/flat_demand_memory.h"
#include "riscv/riscv_action_point_memory_interface.h"
namespace {
#ifndef EXPECT_OK
#define EXPECT_OK(x) EXPECT_TRUE(x.ok())
#endif
using ::mpact::sim::generic::ActionPointManagerBase;
using ::mpact::sim::generic::BreakpointManager;
using ::mpact::sim::generic::Component;
using ::mpact::sim::generic::DataBuffer;
using ::mpact::sim::generic::DataBufferFactory;
using ::mpact::sim::riscv::RiscVActionPointMemoryInterface;
using ::mpact::sim::util::FlatDemandMemory;
constexpr uint64_t kBreak32Address = 0x1000;
constexpr uint64_t kBreak16Address = 0x1004;
constexpr uint64_t kBreakBadAddress = 0x1008;
constexpr uint32_t kAdd32Instruction = 0b0000000'00010'00001'000'00011'0110011;
constexpr uint32_t kAdd16Instruction = 0b100'1'00011'00010'10;
constexpr uint32_t kBadInstruction = 0xffff'ffff;
class RiscVBreakpointTest : public testing::Test, public Component {
protected:
RiscVBreakpointTest() : Component("test") {
db2_ = db_factory_.Allocate<uint16_t>(1);
db4_ = db_factory_.Allocate<uint32_t>(2);
memory_ = new FlatDemandMemory(0);
// Initialize the memory with instruction words.
db4_->Set<uint32_t>(0, kAdd32Instruction);
memory_->Store(kBreak32Address, db4_);
db4_->Set<uint32_t>(0, kBadInstruction);
memory_->Store(kBreakBadAddress, db4_);
db2_->Set<uint16_t>(0, kAdd16Instruction);
memory_->Store(kBreak16Address, db2_);
rv_ap_memory_interface_ = new RiscVActionPointMemoryInterface(
memory_, absl::bind_front(&RiscVBreakpointTest::Invalidate, this));
ap_manager_ = new ActionPointManagerBase(rv_ap_memory_interface_);
bp_manager_ = new BreakpointManager(ap_manager_, nullptr);
}
~RiscVBreakpointTest() override {
db2_->DecRef();
db4_->DecRef();
delete bp_manager_;
delete ap_manager_;
delete rv_ap_memory_interface_;
delete memory_;
}
void Invalidate(uint64_t address) { latch_address_ = address; }
uint64_t latch_address_ = 0;
int latch_size_ = -1;
RiscVActionPointMemoryInterface *rv_ap_memory_interface_;
ActionPointManagerBase *ap_manager_;
BreakpointManager *bp_manager_;
DataBufferFactory db_factory_;
FlatDemandMemory *memory_;
DataBuffer *db2_;
DataBuffer *db4_;
};
TEST_F(RiscVBreakpointTest, Breakpoint16) {
// There shouldn't be a breakpoint set, and the enable/disable/clear should
// fail.
EXPECT_FALSE(bp_manager_->HasBreakpoint(kBreak16Address));
EXPECT_FALSE(bp_manager_->EnableBreakpoint(kBreak16Address).ok());
EXPECT_FALSE(bp_manager_->DisableBreakpoint(kBreak16Address).ok());
EXPECT_FALSE(bp_manager_->ClearBreakpoint(kBreak16Address).ok());
// Set the breakpoint.
EXPECT_OK(bp_manager_->SetBreakpoint(kBreak16Address));
EXPECT_TRUE(bp_manager_->HasBreakpoint(kBreak16Address));
EXPECT_TRUE(bp_manager_->IsBreakpoint(kBreak16Address));
memory_->Load(kBreak16Address, db2_, nullptr, nullptr);
EXPECT_EQ(db2_->Get<uint16_t>(0), RiscVActionPointMemoryInterface::kEBreak16);
EXPECT_EQ(latch_address_, kBreak16Address);
latch_address_ = 0;
latch_size_ = -1;
// Disable the breakpoint.
EXPECT_OK(bp_manager_->DisableBreakpoint(kBreak16Address));
EXPECT_TRUE(bp_manager_->HasBreakpoint(kBreak16Address));
EXPECT_FALSE(bp_manager_->IsBreakpoint(kBreak16Address));
// Enable the breakpoint.
EXPECT_OK(bp_manager_->EnableBreakpoint(kBreak16Address));
EXPECT_TRUE(bp_manager_->HasBreakpoint(kBreak16Address));
EXPECT_TRUE(bp_manager_->IsBreakpoint(kBreak16Address));
// Clear the breakpoint.
EXPECT_OK(bp_manager_->ClearBreakpoint(kBreak16Address));
EXPECT_FALSE(bp_manager_->HasBreakpoint(kBreak16Address));
memory_->Load(kBreak16Address, db2_, nullptr, nullptr);
EXPECT_EQ(db2_->Get<uint16_t>(0), kAdd16Instruction);
EXPECT_EQ(latch_address_, kBreak16Address);
latch_address_ = 0;
latch_size_ = -1;
}
TEST_F(RiscVBreakpointTest, Breakpoint32) {
// There shouldn't be a breakpoint set, and the enable/disable/clear should
// fail.
EXPECT_FALSE(bp_manager_->HasBreakpoint(kBreak32Address));
EXPECT_FALSE(bp_manager_->EnableBreakpoint(kBreak32Address).ok());
EXPECT_FALSE(bp_manager_->DisableBreakpoint(kBreak32Address).ok());
EXPECT_FALSE(bp_manager_->ClearBreakpoint(kBreak32Address).ok());
EXPECT_EQ(latch_address_, 0);
EXPECT_EQ(latch_size_, -1);
// Set the breakpoint.
EXPECT_OK(bp_manager_->SetBreakpoint(kBreak32Address));
EXPECT_TRUE(bp_manager_->HasBreakpoint(kBreak32Address));
EXPECT_TRUE(bp_manager_->IsBreakpoint(kBreak32Address));
memory_->Load(kBreak32Address, db4_, nullptr, nullptr);
EXPECT_EQ(db4_->Get<uint32_t>(0), RiscVActionPointMemoryInterface::kEBreak32);
EXPECT_EQ(latch_address_, kBreak32Address);
latch_address_ = 0;
latch_size_ = -1;
// Disable the breakpoint.
EXPECT_OK(bp_manager_->DisableBreakpoint(kBreak32Address));
EXPECT_TRUE(bp_manager_->HasBreakpoint(kBreak32Address));
EXPECT_FALSE(bp_manager_->IsBreakpoint(kBreak32Address));
latch_address_ = 0;
latch_size_ = -1;
// Enable the breakpoint.
EXPECT_OK(bp_manager_->EnableBreakpoint(kBreak32Address));
EXPECT_TRUE(bp_manager_->HasBreakpoint(kBreak32Address));
EXPECT_TRUE(bp_manager_->IsBreakpoint(kBreak32Address));
memory_->Load(kBreak32Address, db4_, nullptr, nullptr);
latch_address_ = 0;
latch_size_ = -1;
// Clear the breakpoint.
EXPECT_OK(bp_manager_->ClearBreakpoint(kBreak32Address));
EXPECT_FALSE(bp_manager_->HasBreakpoint(kBreak32Address));
memory_->Load(kBreak32Address, db4_, nullptr, nullptr);
EXPECT_EQ(db4_->Get<uint32_t>(0), kAdd32Instruction);
EXPECT_EQ(latch_address_, kBreak32Address);
latch_address_ = 0;
latch_size_ = -1;
}
} // namespace