blob: adcecdbd49899684f465802f68764f0e92722693 [file]
// Copyright 2023 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 "mpact/sim/generic/complex_resource_operand.h"
#include "absl/status/status.h"
#include "googlemock/include/gmock/gmock.h"
#include "googletest/include/gtest/gtest.h"
namespace {
using ::mpact::sim::generic::ArchState;
using ::mpact::sim::generic::ComplexResource;
using ::mpact::sim::generic::ComplexResourceOperand;
using ::mpact::sim::generic::SourceOperandInterface;
constexpr size_t kCycleDepth = 234;
constexpr size_t kLow = 100;
constexpr size_t kHigh = 107;
constexpr char kResourceName[] = "my_resource";
constexpr char kArchName[] = "test_architecture";
// Bits 100-107 are cleared in this bit vector.
constexpr uint64_t kFree100To107[] = {
0xffff'ffff'ffff'ffff, 0xffff'f00f'ffff'ffff, 0xffff'ffff'ffff'ffff,
0x0000'03ff'ffff'ffff};
// Longer than what is supported.
constexpr uint64_t kTooLong[5] = {0xffff, 0, 0, 0, 0};
// All zeros, no cycle is reserved.
constexpr uint64_t kAllZeros[4] = {0};
// The request vector corresponding to kFree100To107
constexpr uint64_t kAcquire100To107[] = {~kFree100To107[0], ~kFree100To107[1],
~kFree100To107[2],
~kFree100To107[3] & 0x3ff'ffff'ffff};
// ArchState derived class that is passed in to the resource (so that it can
// access the clock.
class MockArchState : public ArchState {
public:
MockArchState(absl::string_view id, SourceOperandInterface *pc_op)
: ArchState(id, pc_op) {}
explicit MockArchState(absl::string_view id) : MockArchState(id, nullptr) {}
void set_cycle(uint64_t value) { ArchState::set_cycle(value); }
};
// Test fixture. Instantiates and deletes instances of MockArchState and the
// ComplexResource and ComplexResourceOperand.
class ComplexResourceOperandTest : public testing::Test {
protected:
ComplexResourceOperandTest() {
arch_state_ = new MockArchState(kArchName);
resource_ = new ComplexResource(arch_state_, kResourceName, kCycleDepth);
operand_ = new ComplexResourceOperand(resource_);
}
~ComplexResourceOperandTest() override {
delete operand_;
delete resource_;
delete arch_state_;
}
MockArchState *arch_state_;
ComplexResource *resource_;
ComplexResourceOperand *operand_;
};
// Check error status from setting the cycle mask.
TEST_F(ComplexResourceOperandTest, CycleMask) {
auto *op = new ComplexResourceOperand(nullptr);
EXPECT_TRUE(absl::IsInternal(op->SetCycleMask(kLow, kHigh)));
EXPECT_TRUE(absl::IsInvalidArgument(operand_->SetCycleMask(kHigh, kLow)));
EXPECT_TRUE(
absl::IsInvalidArgument(operand_->SetCycleMask(kLow, kCycleDepth)));
EXPECT_TRUE(operand_->SetCycleMask(kLow, kHigh).ok());
EXPECT_THAT(
operand_->bit_array(),
testing::ElementsAreArray(absl::MakeSpan(kAcquire100To107)
.first(operand_->bit_array().size())));
// Now try setting using arrays.
EXPECT_TRUE(absl::IsInvalidArgument(operand_->SetCycleMask(kTooLong)));
EXPECT_TRUE(absl::IsInvalidArgument(operand_->SetCycleMask(kAllZeros)));
EXPECT_TRUE(operand_->SetCycleMask(kAcquire100To107).ok());
delete op;
}
// Test IsFree function.
TEST_F(ComplexResourceOperandTest, IsFree) {
// First set the resource to be busy except for cycles 100..107.
resource_->Acquire(kFree100To107);
// Initialize the cycle mask in the operand.
EXPECT_TRUE(operand_->SetCycleMask(kLow, kHigh).ok());
// Verify the bit array in the resource.
EXPECT_THAT(resource_->bit_array(), testing::ElementsAreArray(kFree100To107));
EXPECT_TRUE(operand_->IsFree());
// Set the operand mask using the array itself.
EXPECT_TRUE(operand_->SetCycleMask(kAcquire100To107).ok());
EXPECT_THAT(operand_->bit_array(),
testing::ElementsAreArray(kAcquire100To107));
EXPECT_TRUE(operand_->IsFree());
// Advance the cycle count (which shifts the resource bit vector at the next
// call).
arch_state_->set_cycle(1);
// The call should fail now as a "busy" cycle has been shifted into the
// request window.
EXPECT_FALSE(operand_->IsFree());
}
// Test Acquire
TEST_F(ComplexResourceOperandTest, Acquire) {
EXPECT_TRUE(operand_->SetCycleMask(kLow, kHigh).ok());
operand_->Acquire();
// Verify that the resource was acquired for the right cycles.
EXPECT_THAT(resource_->bit_array(),
testing::ElementsAreArray(kAcquire100To107));
}
} // namespace