<commit_before>#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <sauce/sauce>

using ::testing::Sequence;
using ::testing::Return;

namespace sauce {
namespace test {

class Chasis {};
class CoupChasis:
  public Chasis {};

class Engine {};
class HybridEngine:
  public Engine {};

class Vehicle {};
class Herbie:
  public Vehicle {
public:
  Chasis & chasis;
  Engine & engine;

  Herbie(Chasis & chasis, Engine & engine):
    chasis(chasis),
    engine(engine) {}
};

class MyModule {
public:

  template<typename Injector>
  static ::sauce::internal::bindings::New<Injector, Chasis, CoupChasis()> * bindings(Chasis *) {
    return 0;
  }

  template<typename Injector>
  static ::sauce::internal::bindings::Dereference<Injector, Chasis> * bindings(Chasis &) {
    return 0;
  }

  template<typename Injector>
  static ::sauce::internal::bindings::New<Injector, Engine, HybridEngine()> * bindings(Engine *) {
    return 0;
  }

  template<typename Injector>
  static ::sauce::internal::bindings::Dereference<Injector, Engine> * bindings(Engine &) {
    return 0;
  }

  template<typename Injector>
  static ::sauce::internal::bindings::New<Injector, Vehicle, Herbie(Chasis &, Engine &)> * bindings(
    Vehicle *) {
    return 0;
  }

};

// Our mock for the new and delete operations.
//
// Gmock is unable to provide a general mock, so we roll one for our fixure
// types.  Our mocked methods are actually arbitrary non-templated methods,
// delegated to by template specializations for our types.
class MockNewDelete {
public:

  template<class C>
  C * _new();

  template<class C, typename A1, typename A2>
  C * _new(A1, A2);
  template<class C>
  void _delete(C *);

  MOCK_METHOD0(new_coup_chasis, CoupChasis * ());
  MOCK_METHOD0(new_hybrid_engine, HybridEngine * ());
  MOCK_METHOD2(new_herbie, Herbie * (Chasis *, Engine *));

  MOCK_METHOD1(delete_chasis, void(Chasis *));
  MOCK_METHOD1(delete_engine, void(Engine *));
  MOCK_METHOD1(delete_vehicle, void(Vehicle *));

};

template<>
CoupChasis * MockNewDelete::_new<CoupChasis>() {
  return new_coup_chasis();
}

template<>
HybridEngine * MockNewDelete::_new<HybridEngine>() {
  return new_hybrid_engine();
}

template<>
Herbie * MockNewDelete::_new<Herbie>(Chasis & chasis, Engine & engine) {
  // Use addresses here only because googletest doesn't know how to
  // deal with references aside from copying them (and thus breaking my
  // object-identity comparators)
  return new_herbie(&chasis, &engine);
}

template<>
void MockNewDelete::_delete<Chasis>(Chasis * chasis) {
  delete_chasis(chasis);
}

template<>
void MockNewDelete::_delete<Engine>(Engine * engine) {
  delete_engine(engine);
}

template<>
void MockNewDelete::_delete<Vehicle>(Vehicle * vehicle) {
  delete_vehicle(vehicle);
}

class SauceTest:
  public ::testing::Test {
public:

  ::sauce::Injector<MyModule, MockNewDelete> injector;
  MockNewDelete & newDelete;

  // SauceTest is a friend of Injector
  SauceTest():
    injector(),
    newDelete(injector.newDelete) {}

};

TEST_F(SauceTest, should_provide_a_dependency) {
  CoupChasis chasis;
  EXPECT_CALL(newDelete, new_coup_chasis()).WillOnce(Return(&chasis));
  Chasis * actual = injector.provide<Chasis *>();
  ASSERT_EQ(&chasis, actual);
}

TEST_F(SauceTest, should_dispose_a_dependency) {
  CoupChasis chasis;
  EXPECT_CALL(newDelete, delete_chasis(&chasis));
  injector.dispose<Chasis *>(&chasis);
}

TEST_F(SauceTest, should_dereference_addresses_with_dereference_bindings) {
  CoupChasis chasis;
  EXPECT_CALL(newDelete, new_coup_chasis()).WillOnce(Return(&chasis));
  EXPECT_CALL(newDelete, delete_chasis(&chasis));

  Chasis & actual = injector.provide<Chasis &>();
  ASSERT_EQ(&chasis, &actual);
  injector.dispose<Chasis &>(actual);
}

TEST_F(SauceTest, should_provide_and_dispose_of_dependencies_transitively) {
  CoupChasis chasis;
  HybridEngine engine;
  Herbie vehicle(chasis, engine);

  // We don't care about the relative ordering between chasis and engine:
  // only about how they stand relative to the vehicle.
  Sequence injected_chasis, injected_engine;

  EXPECT_CALL(newDelete, new_coup_chasis()).
  InSequence(injected_chasis).
  WillOnce(Return(&chasis));

  EXPECT_CALL(newDelete, new_hybrid_engine()).
  InSequence(injected_engine).
  WillOnce(Return(&engine));

  EXPECT_CALL(newDelete, new_herbie(&chasis, &engine)).
  InSequence(injected_chasis, injected_engine).
  WillOnce(Return(&vehicle));

  EXPECT_CALL(newDelete, delete_vehicle(&vehicle)).
  InSequence(injected_chasis, injected_engine);

  // EXPECT_CALL(newDelete, delete_engine(&engine)).
  // InSequence(injected_engine);

  // EXPECT_CALL(newDelete, delete_chasis(&chasis)).
  // InSequence(injected_chasis);

  Vehicle * actual = injector.provide<Vehicle *>();
  ASSERT_EQ(&vehicle, actual);
  injector.dispose<Vehicle *>(actual);
}

}
}<commit_msg>Drop snake case in favor of camel.<commit_after>#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <sauce/sauce>

using ::testing::Sequence;
using ::testing::Return;

namespace sauce {
namespace test {

class Chasis {};
class CoupChasis:
  public Chasis {};

class Engine {};
class HybridEngine:
  public Engine {};

class Vehicle {};
class Herbie:
  public Vehicle {
public:
  Chasis & chasis;
  Engine & engine;

  Herbie(Chasis & chasis, Engine & engine):
    chasis(chasis),
    engine(engine) {}
};

class MyModule {
public:

  template<typename Injector>
  static ::sauce::internal::bindings::New<Injector, Chasis, CoupChasis()> * bindings(Chasis *) {
    return 0;
  }

  template<typename Injector>
  static ::sauce::internal::bindings::Dereference<Injector, Chasis> * bindings(Chasis &) {
    return 0;
  }

  template<typename Injector>
  static ::sauce::internal::bindings::New<Injector, Engine, HybridEngine()> * bindings(Engine *) {
    return 0;
  }

  template<typename Injector>
  static ::sauce::internal::bindings::Dereference<Injector, Engine> * bindings(Engine &) {
    return 0;
  }

  template<typename Injector>
  static ::sauce::internal::bindings::New<Injector, Vehicle, Herbie(Chasis &, Engine &)> * bindings(
    Vehicle *) {
    return 0;
  }

};

// Our mock for the new and delete operations.
//
// Gmock is unable to provide a general mock, so we roll one for our fixure
// types.  Our mocked methods are actually arbitrary non-templated methods,
// delegated to by template specializations for our types.
class MockNewDelete {
public:

  template<class C>
  C * _new();

  template<class C, typename A1, typename A2>
  C * _new(A1, A2);
  template<class C>
  void _delete(C *);

  MOCK_METHOD0(newCoupChasis, CoupChasis * ());
  MOCK_METHOD0(newHybridEngine, HybridEngine * ());
  MOCK_METHOD2(newHerbie, Herbie * (Chasis *, Engine *));

  MOCK_METHOD1(deleteChasis, void(Chasis *));
  MOCK_METHOD1(deleteEngine, void(Engine *));
  MOCK_METHOD1(deleteVehicle, void(Vehicle *));

};

template<>
CoupChasis * MockNewDelete::_new<CoupChasis>() {
  return newCoupChasis();
}

template<>
HybridEngine * MockNewDelete::_new<HybridEngine>() {
  return newHybridEngine();
}

template<>
Herbie * MockNewDelete::_new<Herbie>(Chasis & chasis, Engine & engine) {
  // Use addresses here only because googletest doesn't know how to
  // deal with references aside from copying them (and thus breaking my
  // object-identity comparators)
  return newHerbie(&chasis, &engine);
}

template<>
void MockNewDelete::_delete<Chasis>(Chasis * chasis) {
  deleteChasis(chasis);
}

template<>
void MockNewDelete::_delete<Engine>(Engine * engine) {
  deleteEngine(engine);
}

template<>
void MockNewDelete::_delete<Vehicle>(Vehicle * vehicle) {
  deleteVehicle(vehicle);
}

class SauceTest:
  public ::testing::Test {
public:

  ::sauce::Injector<MyModule, MockNewDelete> injector;
  MockNewDelete & newDelete;

  // SauceTest is a friend of Injector
  SauceTest():
    injector(),
    newDelete(injector.newDelete) {}

};

TEST_F(SauceTest, should_provide_a_dependency) {
  CoupChasis chasis;
  EXPECT_CALL(newDelete, newCoupChasis()).WillOnce(Return(&chasis));
  Chasis * actual = injector.provide<Chasis *>();
  ASSERT_EQ(&chasis, actual);
}

TEST_F(SauceTest, should_dispose_a_dependency) {
  CoupChasis chasis;
  EXPECT_CALL(newDelete, deleteChasis(&chasis));
  injector.dispose<Chasis *>(&chasis);
}

TEST_F(SauceTest, should_dereference_addresses_with_dereference_bindings) {
  CoupChasis chasis;
  EXPECT_CALL(newDelete, newCoupChasis()).WillOnce(Return(&chasis));
  EXPECT_CALL(newDelete, deleteChasis(&chasis));

  Chasis & actual = injector.provide<Chasis &>();
  ASSERT_EQ(&chasis, &actual);
  injector.dispose<Chasis &>(actual);
}

TEST_F(SauceTest, should_provide_and_dispose_of_dependencies_transitively) {
  CoupChasis chasis;
  HybridEngine engine;
  Herbie vehicle(chasis, engine);

  // We don't care about the relative ordering between chasis and engine:
  // only about how they stand relative to the vehicle.
  Sequence injectedChasis, injectedEngine;

  EXPECT_CALL(newDelete, newCoupChasis()).
  InSequence(injectedChasis).
  WillOnce(Return(&chasis));

  EXPECT_CALL(newDelete, newHybridEngine()).
  InSequence(injectedEngine).
  WillOnce(Return(&engine));

  EXPECT_CALL(newDelete, newHerbie(&chasis, &engine)).
  InSequence(injectedChasis, injectedEngine).
  WillOnce(Return(&vehicle));

  EXPECT_CALL(newDelete, deleteVehicle(&vehicle)).
  InSequence(injectedChasis, injectedEngine);

  // EXPECT_CALL(newDelete, deleteEngine(&engine)).
  // InSequence(injectedEngine);

  // EXPECT_CALL(newDelete, deleteChasis(&chasis)).
  // InSequence(injectedChasis);

  Vehicle * actual = injector.provide<Vehicle *>();
  ASSERT_EQ(&vehicle, actual);
  injector.dispose<Vehicle *>(actual);
}

}
}<|endoftext|>


<commit_before>/*

Copyright (c) 2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/file.hpp"
#include "test.hpp"
#include <vector>
#include <set>

using namespace libtorrent;

int touch_file(std::string const& filename, int size)
{
	using namespace libtorrent;

	std::vector<char> v;
	v.resize(size);
	for (int i = 0; i < size; ++i)
		v[i] = i & 255;

	file f;
	error_code ec;
	if (!f.open(filename, file::write_only, ec)) return -1;
	if (ec) return -1;
	file::iovec_t b = {&v[0], v.size()};
	size_type written = f.writev(0, &b, 1, ec);
	if (written != int(v.size())) return -3;
	if (ec) return -3;
	return 0;
}

int test_main()
{
	error_code ec;

	create_directory("file_test_dir", ec);
	if (ec) fprintf(stderr, "create_directory: %s\n", ec.message().c_str());
	TEST_CHECK(!ec);

	std::string cwd = current_working_directory();

	touch_file(combine_path("file_test_dir", "abc"), 10);
	touch_file(combine_path("file_test_dir", "def"), 100);
	touch_file(combine_path("file_test_dir", "ghi"), 1000);

	std::set<std::string> files;
	for (directory i("file_test_dir", ec); !i.done(); i.next(ec))
	{
		std::string f = i.file();
		TEST_CHECK(files.count(f) == 0);
		files.insert(f);
		fprintf(stderr, " %s\n", f.c_str());
	}

	TEST_CHECK(files.count("abc") == 1);
	TEST_CHECK(files.count("def") == 1);
	TEST_CHECK(files.count("ghi") == 1);
	TEST_CHECK(files.count("..") == 1);
	TEST_CHECK(files.count(".") == 1);

	remove_all("file_test_dir", ec);
	if (ec) fprintf(stderr, "create_directory: %s\n", ec.message().c_str());

	return 0;
}

<commit_msg>expand file test<commit_after>/*

Copyright (c) 2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/file.hpp"
#include "test.hpp"
#include <vector>
#include <set>

using namespace libtorrent;

int touch_file(std::string const& filename, int size)
{
	using namespace libtorrent;

	std::vector<char> v;
	v.resize(size);
	for (int i = 0; i < size; ++i)
		v[i] = i & 255;

	file f;
	error_code ec;
	if (!f.open(filename, file::write_only, ec)) return -1;
	if (ec) return -1;
	file::iovec_t b = {&v[0], v.size()};
	size_type written = f.writev(0, &b, 1, ec);
	if (written != int(v.size())) return -3;
	if (ec) return -3;
	return 0;
}

int test_main()
{
	error_code ec;

	create_directory("file_test_dir", ec);
	if (ec) fprintf(stderr, "create_directory: %s\n", ec.message().c_str());
	TEST_CHECK(!ec);

	std::string cwd = current_working_directory();

	touch_file(combine_path("file_test_dir", "abc"), 10);
	touch_file(combine_path("file_test_dir", "def"), 100);
	touch_file(combine_path("file_test_dir", "ghi"), 1000);

	std::set<std::string> files;
	for (directory i("file_test_dir", ec); !i.done(); i.next(ec))
	{
		std::string f = i.file();
		TEST_CHECK(files.count(f) == 0);
		files.insert(f);
		fprintf(stderr, " %s\n", f.c_str());
	}

	TEST_CHECK(files.count("abc") == 1);
	TEST_CHECK(files.count("def") == 1);
	TEST_CHECK(files.count("ghi") == 1);
	TEST_CHECK(files.count("..") == 1);
	TEST_CHECK(files.count(".") == 1);
	files.clear();

	recursive_copy("file_test_dir", "file_test_dir2", ec);

	for (directory i("file_test_dir2", ec); !i.done(); i.next(ec))
	{
		std::string f = i.file();
		TEST_CHECK(files.count(f) == 0);
		files.insert(f);
		fprintf(stderr, " %s\n", f.c_str());
	}

	remove_all("file_test_dir", ec);
	if (ec) fprintf(stderr, "remove_all: %s\n", ec.message().c_str());
	remove_all("file_test_dir2", ec);
	if (ec) fprintf(stderr, "remove_all: %s\n", ec.message().c_str());

	return 0;
}

<|endoftext|>


<commit_before>#include "nano.h"
#include "class.h"
#include "utest.h"
#include "function.h"
#include "math/random.h"
#include "math/epsilon.h"

using namespace nano;

struct loss_function_t final : public function_t
{
        loss_function_t(const rloss_t& loss, const vector_t& target) :
                function_t("loss", target.size(), target.size(), target.size(), convexity::no, 1e+6),
                m_loss(loss), m_target(target)
        {
        }

        scalar_t vgrad(const vector_t& x, vector_t* gx) const override
        {
                if (gx)
                {
                        *gx = m_loss->vgrad(m_target, x);
                }
                return m_loss->value(m_target, x);
        }

        const rloss_t&          m_loss;
        const vector_t&         m_target;
};

static void check_grad(const string_t& loss_id, const tensor_size_t n_dims, const size_t n_tests)
{
        const auto loss = get_losses().get(loss_id);
        const auto target = class_target(n_dims / 2, n_dims);
        const auto function = loss_function_t(loss, target);

        // check the gradient using random parameters
        for (size_t t = 0; t < n_tests; ++ t)
        {
                random_t<scalar_t> rgen(scalar_t(-0.1), scalar_t(+0.1));

                vector_t x(n_dims);
                rgen(x.data(), x.data() + n_dims);

                NANO_CHECK_GREATER(function.eval(x), 0.0);
                NANO_CHECK_LESS(function.grad_accuracy(x), epsilon2<scalar_t>());
        }
}

NANO_BEGIN_MODULE(test_loss)

NANO_CASE(evaluate)
{
        const strings_t loss_ids = get_losses().ids();

        const tensor_size_t cmd_min_dims = 2;
        const tensor_size_t cmd_max_dims = 10;
        const size_t cmd_tests = 128;

        // evaluate the analytical gradient vs. the finite difference approximation
        for (const string_t& loss_id : loss_ids)
        {
                for (tensor_size_t cmd_dims = cmd_min_dims; cmd_dims <= cmd_max_dims; ++ cmd_dims)
                {
                        check_grad(loss_id, cmd_dims, cmd_tests);
                }
        }
}

NANO_END_MODULE()
<commit_msg>extend unit test to check that the loss value upper bounds the error function<commit_after>#include "nano.h"
#include "class.h"
#include "utest.h"
#include "function.h"
#include "math/random.h"
#include "math/epsilon.h"

using namespace nano;

struct loss_function_t final : public function_t
{
        loss_function_t(const rloss_t& loss, const vector_t& target) :
                function_t("loss", target.size(), target.size(), target.size(), convexity::no, 1e+6),
                m_loss(loss), m_target(target)
        {
        }

        scalar_t vgrad(const vector_t& x, vector_t* gx) const override
        {
                if (gx)
                {
                        *gx = m_loss->vgrad(m_target, x);
                }
                return m_loss->value(m_target, x);
        }

        const rloss_t&          m_loss;
        const vector_t&         m_target;
};

NANO_BEGIN_MODULE(test_loss)

NANO_CASE(evaluate)
{
        const strings_t loss_ids = get_losses().ids();

        const tensor_size_t cmd_min_dims = 2;
        const tensor_size_t cmd_max_dims = 10;
        const size_t cmd_tests = 128;

        // evaluate the analytical gradient vs. the finite difference approximation
        for (const string_t& loss_id : loss_ids)
        {
                for (tensor_size_t cmd_dims = cmd_min_dims; cmd_dims <= cmd_max_dims; ++ cmd_dims)
                {
                        const auto loss = get_losses().get(loss_id);
                        const auto target = class_target(cmd_dims / 2, cmd_dims);
                        const auto function = loss_function_t(loss, target);

                        random_t<scalar_t> rgen(scalar_t(-0.1), scalar_t(+0.1));

                        vector_t x(cmd_dims);

                        // check the gradient using random parameters
                        for (size_t t = 0; t < cmd_tests; ++ t)
                        {
                                rgen(x.data(), x.data() + x.size());

                                NANO_CHECK_GREATER(function.eval(x), 0.0);
                                NANO_CHECK_LESS(function.grad_accuracy(x), epsilon2<scalar_t>());

                                // loss value should upper-bound the error function
                                NANO_CHECK_GREATER(loss->value(x, target), loss->error(x, target) + epsilon0<scalar_t>());
                        }
                }
        }
}

NANO_END_MODULE()
<|endoftext|>


<commit_before>// Copyright 2018 Alessio Sclocco <alessio@sclocco.eu>
//
// 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
//
//     http://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 <utils.hpp>
#include <gtest/gtest.h>

TEST(ReplaceTest, PlaceholderInString) {
  EXPECT_EQ(std::string("Hello World!"), *(isa::utils::replace(new std::string("Hello <%NAME%>!"), "<%NAME%>", "World")));
  EXPECT_EQ(std::string("Hello WorldWorldWorld!"), *(isa::utils::replace(new std::string("Hello <%NAME%><%NAME%><%NAME%>!"), "<%NAME%>", "World")));
  EXPECT_EQ(std::string("Please to meet you John."), *(isa::utils::replace(new std::string("<%SENTENCE%>."), "<%SENTENCE%>", "Please to meet you John", true)));
}

TEST(ReplaceTest, PlaceholderNotInString) {
  EXPECT_EQ(std::string("Hello again, World!"), *(isa::utils::replace(new std::string("Hello again, World!"), "<%PLACEHOLDER%>", "John")));
  EXPECT_EQ(std::string("<%SENTENCE%>."), *(isa::utils::replace(new std::string("<%SENTENCE%>."), "<%PLACEHOLDER%>", "Please to meet you Mike", true)));
}

TEST(ReplaceTest, EraseString) {
  EXPECT_EQ(std::string(""), *(isa::utils::replace(new std::string("Hello World!"), "Hello World!", "")));
  EXPECT_EQ(std::string(""), *(isa::utils::replace(new std::string("Hello World!"), "Hello World!", "", true)));
}

TEST(SameTest, SameValue) {
  float singlePrecision = 932.728292f;
  double doublePrecision = 932.728636126;

  EXPECT_TRUE(isa::utils::same(singlePrecision, singlePrecision)) << "Values: " << singlePrecision << " " << singlePrecision;
  EXPECT_TRUE(isa::utils::same(doublePrecision, doublePrecision, 1.0e-03)) << "Values: " << doublePrecision << " " << singlePrecision;
  EXPECT_TRUE(isa::utils::same(doublePrecision, doublePrecision)) << "Values: " << doublePrecision << " " << doublePrecision;
  EXPECT_TRUE(isa::utils::same(doublePrecision, doublePrecision, 1.0e-09)) << "Values: " << doublePrecision << " " << doublePrecision;
}

TEST(SameTest, DifferentValue) {
  float singlePrecision = 932.728292f;
  double doublePrecision = 932.728636126;

  EXPECT_FALSE(isa::utils::same(static_cast<double>(singlePrecision), doublePrecision)) << "Values: " << static_cast<double>(singlePrecision) << " " << doublePrecision;
  EXPECT_FALSE(isa::utils::same(static_cast<float>(doublePrecision), singlePrecision)) << "Values: " << static_cast<float>(doublePrecision) << " " << singlePrecision;
  EXPECT_TRUE(isa::utils::same(singlePrecision, doublePrecision, 1.0e-03)) << "Values: " << singlePrecision << " " << doublePrecision;
  EXPECT_TRUE(isa::utils::same(doublePrecision, singlePrecision, 1.0e-03)) << "Values: " << doublePrecision << " " << singlePrecision;
  EXPECT_FALSE(isa::utils::same(singlePrecision, doublePrecision, 1.0e-04)) << "Values: " << singlePrecision << " " << doublePrecision;
  EXPECT_FALSE(isa::utils::same(doublePrecision, singlePrecision, 1.0e-04)) << "Values: " << doublePrecision << " " << singlePrecision;
}

TEST(CastToTypeTest, TypeDifferent) {
  int integer;
  float singlePrecision;
  double doublePrecision;
  std::string stringNumber;

  singlePrecision = 12.379238f;
  integer = isa::utils::castToType<float, int>(singlePrecision);
  EXPECT_EQ(12, integer);
  integer = 42;
  doublePrecision = isa::utils::castToType<int, double>(integer);
  EXPECT_EQ(42.0, doublePrecision);
  stringNumber = "1923";
  integer = isa::utils::castToType<std::string, int>(stringNumber);
  EXPECT_EQ(1923, integer);
  stringNumber = "92.732";
  singlePrecision = isa::utils::castToType<std::string, float>(stringNumber);
  EXPECT_EQ(92.732f, singlePrecision);
  doublePrecision = 82372.8;
  stringNumber = isa::utils::castToType<double, std::string>(doublePrecision);
  EXPECT_EQ("82372.8", stringNumber);
}

TEST(CastToTypeTest, TypeEqual) {
  int integerOne, integerTwo;
  float singlePrecisionOne, singlePrecisionTwo;
  double doublePrecisionOne, doublePrecisionTwo;

  integerOne = 42;
  integerTwo = isa::utils::castToType<int, int>(integerOne);
  EXPECT_EQ(integerOne, integerTwo);
  singlePrecisionOne = 12.379f;
  singlePrecisionTwo = isa::utils::castToType<float, float>(singlePrecisionOne);
  EXPECT_TRUE(isa::utils::same(singlePrecisionOne, singlePrecisionTwo, 1.0e-03)) << "Values: " << singlePrecisionOne << " " << singlePrecisionTwo;
  doublePrecisionOne = 928.728;
  doublePrecisionTwo = isa::utils::castToType<double, double>(doublePrecisionOne);
  EXPECT_TRUE(isa::utils::same(doublePrecisionOne, doublePrecisionTwo, 1.0e-03)) << "Values: " << doublePrecisionOne << " " << doublePrecisionTwo;
}

TEST(PadTest, NumberIsPadded) {
  EXPECT_EQ(10, isa::utils::pad(7, 5));
  EXPECT_EQ(83, isa::utils::pad(12, 83));
}

TEST(PadTest, NumberIsNotPadded) {
  EXPECT_EQ(92, isa::utils::pad(92, 92));
  EXPECT_EQ(92, isa::utils::pad(92, 2));
  EXPECT_EQ(92, isa::utils::pad(92, 1));
  EXPECT_EQ(28, isa::utils::pad(28, 7));
}

TEST(TeraTest, TeraConversion) {
  EXPECT_TRUE(isa::utils::same(123.456789123, isa::utils::tera(123456789123456), 1.0e-09)) << "Values: " << 123.456789123 << " " << isa::utils::tera(123456789123456);
  EXPECT_TRUE(isa::utils::same(0.123456789, isa::utils::tera(123456789123), 1.0e-09)) << "Values: " << 0.123456789 << " " << isa::utils::tera(123456789123);
  EXPECT_TRUE(isa::utils::same(0.000123456, isa::utils::tera(123456789), 1.0e-09)) << "Values: " << 0.000123456 << " " << isa::utils::tera(123456789);
  EXPECT_TRUE(isa::utils::same(0.000000123, isa::utils::tera(123456), 1.0e-09)) << "Values: " << 0.000000123 << " " << isa::utils::tera(123456);
}

TEST(GigaTest, GigaConversion) {
  EXPECT_TRUE(isa::utils::same(123.789123456, isa::utils::giga(123789123456), 1.0e-09)) << "Values: " << 123.789123456 << " " << isa::utils::giga(123789123456);
  EXPECT_TRUE(isa::utils::same(0.123456789, isa::utils::giga(123456789), 1.0e-09)) << "Values: " << 0.123456789 << " " << isa::utils::giga(123456789);
  EXPECT_TRUE(isa::utils::same(0.000123456, isa::utils::giga(123456), 1.0e-09)) << "Values: " << 0.000123456 << " " << isa::utils::giga(123456);
  EXPECT_TRUE(isa::utils::same(0.000000123, isa::utils::giga(123), 1.0e-09)) << "Values: " << 0.000000123 << " " << isa::utils::giga(123);
}

TEST(MegaTest, MegaConversion) {
  EXPECT_TRUE(isa::utils::same(123789.123456, isa::utils::mega(123789123456))) << "Values: " << 123789.123456 << " " << isa::utils::mega(123789123456);
  EXPECT_TRUE(isa::utils::same(123.456789, isa::utils::mega(123456789))) << "Values: " << 123.456789 << " " << isa::utils::mega(123456789);
  EXPECT_TRUE(isa::utils::same(0.123456, isa::utils::mega(123456))) << "Values: " << 0.123456 << " " << isa::utils::mega(123456);
  EXPECT_TRUE(isa::utils::same(0.000123, isa::utils::mega(123))) << "Values: " << 0.000123 << " " << isa::utils::mega(123);
}

TEST(KiloTest, KiloConversion) {
  EXPECT_TRUE(isa::utils::same(123789123.456, isa::utils::kilo(123789123456), 1.0e-03)) << "Values: " << 123789123.456 << " " << isa::utils::kilo(123789123456);
  EXPECT_TRUE(isa::utils::same(123456.789, isa::utils::kilo(123456789), 1.0e-03)) << "Values: " << 123456.789 << " " << isa::utils::kilo(123456789);
  EXPECT_TRUE(isa::utils::same(123.456, isa::utils::kilo(123456), 1.0e-03)) << "Values: " << 123.456 << " " << isa::utils::kilo(123456);
  EXPECT_TRUE(isa::utils::same(0.123, isa::utils::kilo(123), 1.0e-03)) << "Values: " << 0.123 << " " << isa::utils::kilo(123);
}
<commit_msg>Need to cast values because same() expects boat floatin point values being of the same type.<commit_after>// Copyright 2018 Alessio Sclocco <alessio@sclocco.eu>
//
// 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
//
//     http://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 <utils.hpp>
#include <gtest/gtest.h>

TEST(ReplaceTest, PlaceholderInString) {
  EXPECT_EQ(std::string("Hello World!"), *(isa::utils::replace(new std::string("Hello <%NAME%>!"), "<%NAME%>", "World")));
  EXPECT_EQ(std::string("Hello WorldWorldWorld!"), *(isa::utils::replace(new std::string("Hello <%NAME%><%NAME%><%NAME%>!"), "<%NAME%>", "World")));
  EXPECT_EQ(std::string("Please to meet you John."), *(isa::utils::replace(new std::string("<%SENTENCE%>."), "<%SENTENCE%>", "Please to meet you John", true)));
}

TEST(ReplaceTest, PlaceholderNotInString) {
  EXPECT_EQ(std::string("Hello again, World!"), *(isa::utils::replace(new std::string("Hello again, World!"), "<%PLACEHOLDER%>", "John")));
  EXPECT_EQ(std::string("<%SENTENCE%>."), *(isa::utils::replace(new std::string("<%SENTENCE%>."), "<%PLACEHOLDER%>", "Please to meet you Mike", true)));
}

TEST(ReplaceTest, EraseString) {
  EXPECT_EQ(std::string(""), *(isa::utils::replace(new std::string("Hello World!"), "Hello World!", "")));
  EXPECT_EQ(std::string(""), *(isa::utils::replace(new std::string("Hello World!"), "Hello World!", "", true)));
}

TEST(SameTest, SameValue) {
  float singlePrecision = 932.728292f;
  double doublePrecision = 932.728636126;

  EXPECT_TRUE(isa::utils::same(singlePrecision, singlePrecision)) << "Values: " << singlePrecision << " " << singlePrecision;
  EXPECT_TRUE(isa::utils::same(doublePrecision, doublePrecision, 1.0e-03)) << "Values: " << doublePrecision << " " << singlePrecision;
  EXPECT_TRUE(isa::utils::same(doublePrecision, doublePrecision)) << "Values: " << doublePrecision << " " << doublePrecision;
  EXPECT_TRUE(isa::utils::same(doublePrecision, doublePrecision, 1.0e-09)) << "Values: " << doublePrecision << " " << doublePrecision;
}

TEST(SameTest, DifferentValue) {
  float singlePrecision = 932.728292f;
  double doublePrecision = 932.728636126;

  EXPECT_FALSE(isa::utils::same(static_cast<double>(singlePrecision), doublePrecision)) << "Values: " << static_cast<double>(singlePrecision) << " " << doublePrecision;
  EXPECT_FALSE(isa::utils::same(static_cast<float>(doublePrecision), singlePrecision)) << "Values: " << static_cast<float>(doublePrecision) << " " << singlePrecision;
  EXPECT_TRUE(isa::utils::same(static_cast<double>(singlePrecision), doublePrecision, 1.0e-03)) << "Values: " << static_cast<double>(singlePrecision) << " " << doublePrecision;
  EXPECT_TRUE(isa::utils::same(static_cast<float>(doublePrecision), singlePrecision, 1.0e-03)) << "Values: " << static_cast<float>(doublePrecision) << " " << singlePrecision;
  EXPECT_FALSE(isa::utils::same(static_cast<double>(singlePrecision), doublePrecision, 1.0e-04)) << "Values: " << static_cast<double>(singlePrecision) << " " << doublePrecision;
  EXPECT_FALSE(isa::utils::same(static_cast<float>(doublePrecision), singlePrecision, 1.0e-04)) << "Values: " << static_cast<float>(doublePrecision) << " " << singlePrecision;
}

TEST(CastToTypeTest, TypeDifferent) {
  int integer;
  float singlePrecision;
  double doublePrecision;
  std::string stringNumber;

  singlePrecision = 12.379238f;
  integer = isa::utils::castToType<float, int>(singlePrecision);
  EXPECT_EQ(12, integer);
  integer = 42;
  doublePrecision = isa::utils::castToType<int, double>(integer);
  EXPECT_EQ(42.0, doublePrecision);
  stringNumber = "1923";
  integer = isa::utils::castToType<std::string, int>(stringNumber);
  EXPECT_EQ(1923, integer);
  stringNumber = "92.732";
  singlePrecision = isa::utils::castToType<std::string, float>(stringNumber);
  EXPECT_EQ(92.732f, singlePrecision);
  doublePrecision = 82372.8;
  stringNumber = isa::utils::castToType<double, std::string>(doublePrecision);
  EXPECT_EQ("82372.8", stringNumber);
}

TEST(CastToTypeTest, TypeEqual) {
  int integerOne, integerTwo;
  float singlePrecisionOne, singlePrecisionTwo;
  double doublePrecisionOne, doublePrecisionTwo;

  integerOne = 42;
  integerTwo = isa::utils::castToType<int, int>(integerOne);
  EXPECT_EQ(integerOne, integerTwo);
  singlePrecisionOne = 12.379f;
  singlePrecisionTwo = isa::utils::castToType<float, float>(singlePrecisionOne);
  EXPECT_TRUE(isa::utils::same(singlePrecisionOne, singlePrecisionTwo, 1.0e-03)) << "Values: " << singlePrecisionOne << " " << singlePrecisionTwo;
  doublePrecisionOne = 928.728;
  doublePrecisionTwo = isa::utils::castToType<double, double>(doublePrecisionOne);
  EXPECT_TRUE(isa::utils::same(doublePrecisionOne, doublePrecisionTwo, 1.0e-03)) << "Values: " << doublePrecisionOne << " " << doublePrecisionTwo;
}

TEST(PadTest, NumberIsPadded) {
  EXPECT_EQ(10, isa::utils::pad(7, 5));
  EXPECT_EQ(83, isa::utils::pad(12, 83));
}

TEST(PadTest, NumberIsNotPadded) {
  EXPECT_EQ(92, isa::utils::pad(92, 92));
  EXPECT_EQ(92, isa::utils::pad(92, 2));
  EXPECT_EQ(92, isa::utils::pad(92, 1));
  EXPECT_EQ(28, isa::utils::pad(28, 7));
}

TEST(TeraTest, TeraConversion) {
  EXPECT_TRUE(isa::utils::same(123.456789123, isa::utils::tera(123456789123456), 1.0e-09)) << "Values: " << 123.456789123 << " " << isa::utils::tera(123456789123456);
  EXPECT_TRUE(isa::utils::same(0.123456789, isa::utils::tera(123456789123), 1.0e-09)) << "Values: " << 0.123456789 << " " << isa::utils::tera(123456789123);
  EXPECT_TRUE(isa::utils::same(0.000123456, isa::utils::tera(123456789), 1.0e-09)) << "Values: " << 0.000123456 << " " << isa::utils::tera(123456789);
  EXPECT_TRUE(isa::utils::same(0.000000123, isa::utils::tera(123456), 1.0e-09)) << "Values: " << 0.000000123 << " " << isa::utils::tera(123456);
}

TEST(GigaTest, GigaConversion) {
  EXPECT_TRUE(isa::utils::same(123.789123456, isa::utils::giga(123789123456), 1.0e-09)) << "Values: " << 123.789123456 << " " << isa::utils::giga(123789123456);
  EXPECT_TRUE(isa::utils::same(0.123456789, isa::utils::giga(123456789), 1.0e-09)) << "Values: " << 0.123456789 << " " << isa::utils::giga(123456789);
  EXPECT_TRUE(isa::utils::same(0.000123456, isa::utils::giga(123456), 1.0e-09)) << "Values: " << 0.000123456 << " " << isa::utils::giga(123456);
  EXPECT_TRUE(isa::utils::same(0.000000123, isa::utils::giga(123), 1.0e-09)) << "Values: " << 0.000000123 << " " << isa::utils::giga(123);
}

TEST(MegaTest, MegaConversion) {
  EXPECT_TRUE(isa::utils::same(123789.123456, isa::utils::mega(123789123456))) << "Values: " << 123789.123456 << " " << isa::utils::mega(123789123456);
  EXPECT_TRUE(isa::utils::same(123.456789, isa::utils::mega(123456789))) << "Values: " << 123.456789 << " " << isa::utils::mega(123456789);
  EXPECT_TRUE(isa::utils::same(0.123456, isa::utils::mega(123456))) << "Values: " << 0.123456 << " " << isa::utils::mega(123456);
  EXPECT_TRUE(isa::utils::same(0.000123, isa::utils::mega(123))) << "Values: " << 0.000123 << " " << isa::utils::mega(123);
}

TEST(KiloTest, KiloConversion) {
  EXPECT_TRUE(isa::utils::same(123789123.456, isa::utils::kilo(123789123456), 1.0e-03)) << "Values: " << 123789123.456 << " " << isa::utils::kilo(123789123456);
  EXPECT_TRUE(isa::utils::same(123456.789, isa::utils::kilo(123456789), 1.0e-03)) << "Values: " << 123456.789 << " " << isa::utils::kilo(123456789);
  EXPECT_TRUE(isa::utils::same(123.456, isa::utils::kilo(123456), 1.0e-03)) << "Values: " << 123.456 << " " << isa::utils::kilo(123456);
  EXPECT_TRUE(isa::utils::same(0.123, isa::utils::kilo(123), 1.0e-03)) << "Values: " << 0.123 << " " << isa::utils::kilo(123);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 */

#include "arch/arm/stacktrace.hh"

#include <string>

#include "arch/arm/isa_traits.hh"
#include "arch/arm/vtophys.hh"
#include "base/bitfield.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "mem/fs_translating_port_proxy.hh"
#include "sim/system.hh"

namespace ArmISA
{

ProcessInfo::ProcessInfo(ThreadContext *_tc)
    : tc(_tc)
{
    Addr addr = 0;

    FSTranslatingPortProxy &vp = tc->getVirtProxy();

    if (!tc->getSystemPtr()->kernelSymtab->findAddress(
                "thread_info_size", addr)) {
        panic("thread info not compiled into kernel\n");
    }
    thread_info_size = vp.readGtoH<int32_t>(addr);

    if (!tc->getSystemPtr()->kernelSymtab->findAddress(
                "task_struct_size", addr)) {
        panic("thread info not compiled into kernel\n");
    }
    task_struct_size = vp.readGtoH<int32_t>(addr);

    if (!tc->getSystemPtr()->kernelSymtab->findAddress(
                "thread_info_task", addr)) {
        panic("thread info not compiled into kernel\n");
    }
    task_off = vp.readGtoH<int32_t>(addr);

    if (!tc->getSystemPtr()->kernelSymtab->findAddress(
                "task_struct_pid", addr)) {
        panic("thread info not compiled into kernel\n");
    }
    pid_off = vp.readGtoH<int32_t>(addr);

    if (!tc->getSystemPtr()->kernelSymtab->findAddress(
                "task_struct_comm", addr)) {
        panic("thread info not compiled into kernel\n");
    }
    name_off = vp.readGtoH<int32_t>(addr);
}

Addr
ProcessInfo::task(Addr ksp) const
{
    Addr base = ksp & ~0x1fff;
    if (base == ULL(0xffffffffc0000000))
        return 0;

    Addr tsk;

    FSTranslatingPortProxy &vp = tc->getVirtProxy();
    tsk = vp.readGtoH<Addr>(base + task_off);

    return tsk;
}

int
ProcessInfo::pid(Addr ksp) const
{
    Addr task = this->task(ksp);
    if (!task)
        return -1;

    uint16_t pd;

    FSTranslatingPortProxy &vp = tc->getVirtProxy();
    pd = vp.readGtoH<uint16_t>(task + pid_off);

    return pd;
}

std::string
ProcessInfo::name(Addr ksp) const
{
    Addr task = this->task(ksp);
    if (!task)
        return "unknown";

    char comm[256];
    CopyStringOut(tc, comm, task + name_off, sizeof(comm));
    if (!comm[0])
        return "startup";

    return comm;
}

StackTrace::StackTrace()
    : tc(0), stack(64)
{
}

StackTrace::StackTrace(ThreadContext *_tc, const StaticInstPtr &inst)
    : tc(0), stack(64)
{
    trace(_tc, inst);
}

StackTrace::~StackTrace()
{
}

void
StackTrace::trace(ThreadContext *_tc, bool is_call)
{
}

bool
StackTrace::isEntry(Addr addr)
{
    return false;
}

bool
StackTrace::decodeStack(MachInst inst, int &disp)
{
    return false;
}

bool
StackTrace::decodeSave(MachInst inst, int &reg, int &disp)
{
    return false;
}

/*
 * Decode the function prologue for the function we're in, and note
 * which registers are stored where, and how large the stack frame is.
 */
bool
StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
                           int &size, Addr &ra)
{
    return false;
}

#if TRACING_ON
void
StackTrace::dump()
{
    DPRINTFN("------ Stack ------\n");

    DPRINTFN(" Not implemented\n");
}
#endif
}
<commit_msg>arm: Factor some repetition out of the ProcessInfo constructor.<commit_after>/*
 * Copyright (c) 2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 */

#include "arch/arm/stacktrace.hh"

#include <string>

#include "arch/arm/isa_traits.hh"
#include "arch/arm/vtophys.hh"
#include "base/bitfield.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "mem/fs_translating_port_proxy.hh"
#include "sim/system.hh"

namespace ArmISA
{

static int32_t
readSymbol(ThreadContext *tc, const std::string name)
{
    FSTranslatingPortProxy &vp = tc->getVirtProxy();
    SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;

    Addr addr;
    if (!symtab->findAddress(name, addr))
        panic("thread info not compiled into kernel\n");

    return vp.readGtoH<int32_t>(addr);
}

ProcessInfo::ProcessInfo(ThreadContext *_tc) : tc(_tc)
{
    thread_info_size = readSymbol(tc, "thread_info_size");
    task_struct_size = readSymbol(tc, "task_struct_size");
    task_off = readSymbol(tc, "thread_info_task");
    pid_off = readSymbol(tc, "task_struct_pid");
    name_off = readSymbol(tc, "task_struct_comm");
}

Addr
ProcessInfo::task(Addr ksp) const
{
    Addr base = ksp & ~0x1fff;
    if (base == ULL(0xffffffffc0000000))
        return 0;

    Addr tsk;

    FSTranslatingPortProxy &vp = tc->getVirtProxy();
    tsk = vp.readGtoH<Addr>(base + task_off);

    return tsk;
}

int
ProcessInfo::pid(Addr ksp) const
{
    Addr task = this->task(ksp);
    if (!task)
        return -1;

    uint16_t pd;

    FSTranslatingPortProxy &vp = tc->getVirtProxy();
    pd = vp.readGtoH<uint16_t>(task + pid_off);

    return pd;
}

std::string
ProcessInfo::name(Addr ksp) const
{
    Addr task = this->task(ksp);
    if (!task)
        return "unknown";

    char comm[256];
    CopyStringOut(tc, comm, task + name_off, sizeof(comm));
    if (!comm[0])
        return "startup";

    return comm;
}

StackTrace::StackTrace()
    : tc(0), stack(64)
{
}

StackTrace::StackTrace(ThreadContext *_tc, const StaticInstPtr &inst)
    : tc(0), stack(64)
{
    trace(_tc, inst);
}

StackTrace::~StackTrace()
{
}

void
StackTrace::trace(ThreadContext *_tc, bool is_call)
{
}

bool
StackTrace::isEntry(Addr addr)
{
    return false;
}

bool
StackTrace::decodeStack(MachInst inst, int &disp)
{
    return false;
}

bool
StackTrace::decodeSave(MachInst inst, int &reg, int &disp)
{
    return false;
}

/*
 * Decode the function prologue for the function we're in, and note
 * which registers are stored where, and how large the stack frame is.
 */
bool
StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
                           int &size, Addr &ra)
{
    return false;
}

#if TRACING_ON
void
StackTrace::dump()
{
    DPRINTFN("------ Stack ------\n");

    DPRINTFN(" Not implemented\n");
}
#endif
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 */

#include <string>

#include "arch/arm/isa_traits.hh"
#include "arch/arm/stacktrace.hh"
#include "arch/arm/vtophys.hh"
#include "base/bitfield.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "mem/fs_translating_port_proxy.hh"
#include "sim/system.hh"

using namespace std;
namespace ArmISA
{
    ProcessInfo::ProcessInfo(ThreadContext *_tc)
        : tc(_tc)
    {
        Addr addr = 0;

        FSTranslatingPortProxy &vp = tc->getVirtProxy();

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
            panic("thread info not compiled into kernel\n");
        thread_info_size = vp.readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
            panic("thread info not compiled into kernel\n");
        task_struct_size = vp.readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
            panic("thread info not compiled into kernel\n");
        task_off = vp.readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
            panic("thread info not compiled into kernel\n");
        pid_off = vp.readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
            panic("thread info not compiled into kernel\n");
        name_off = vp.readGtoH<int32_t>(addr);
    }

    Addr
    ProcessInfo::task(Addr ksp) const
    {
        return 0;
    }

    int
    ProcessInfo::pid(Addr ksp) const
    {
        return -1;
    }

    string
    ProcessInfo::name(Addr ksp) const
    {
        return "Implement me";
    }

    StackTrace::StackTrace()
        : tc(0), stack(64)
    {
    }

    StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst)
        : tc(0), stack(64)
    {
        trace(_tc, inst);
    }

    StackTrace::~StackTrace()
    {
    }

    void
    StackTrace::trace(ThreadContext *_tc, bool is_call)
    {
    }

    bool
    StackTrace::isEntry(Addr addr)
    {
        return false;
    }

    bool
    StackTrace::decodeStack(MachInst inst, int &disp)
    {
        return false;
    }

    bool
    StackTrace::decodeSave(MachInst inst, int &reg, int &disp)
    {
        return false;
    }

    /*
     * Decode the function prologue for the function we're in, and note
     * which registers are stored where, and how large the stack frame is.
     */
    bool
    StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
                               int &size, Addr &ra)
    {
        return false;
    }

#if TRACING_ON
    void
    StackTrace::dump()
    {
        DPRINTFN("------ Stack ------\n");

        DPRINTFN(" Not implemented\n");
    }
#endif
}
<commit_msg>ARM: implement the ProcessInfo methods<commit_after>/*
 * Copyright (c) 2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 */

#include <string>

#include "arch/arm/isa_traits.hh"
#include "arch/arm/stacktrace.hh"
#include "arch/arm/vtophys.hh"
#include "base/bitfield.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "mem/fs_translating_port_proxy.hh"
#include "sim/system.hh"

using namespace std;
namespace ArmISA
{
    ProcessInfo::ProcessInfo(ThreadContext *_tc)
        : tc(_tc)
    {
        Addr addr = 0;

        FSTranslatingPortProxy &vp = tc->getVirtProxy();

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
            panic("thread info not compiled into kernel\n");
        thread_info_size = vp.readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
            panic("thread info not compiled into kernel\n");
        task_struct_size = vp.readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
            panic("thread info not compiled into kernel\n");
        task_off = vp.readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
            panic("thread info not compiled into kernel\n");
        pid_off = vp.readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
            panic("thread info not compiled into kernel\n");
        name_off = vp.readGtoH<int32_t>(addr);
    }

    Addr
    ProcessInfo::task(Addr ksp) const
    {
        Addr base = ksp & ~0x1fff;
        if (base == ULL(0xffffffffc0000000))
            return 0;

        Addr tsk;

        FSTranslatingPortProxy &vp = tc->getVirtProxy();
        tsk = vp.readGtoH<Addr>(base + task_off);

        return tsk;
    }

    int
    ProcessInfo::pid(Addr ksp) const
    {
        Addr task = this->task(ksp);
        if (!task)
            return -1;

        uint16_t pd;

        FSTranslatingPortProxy &vp = tc->getVirtProxy();
        pd = vp.readGtoH<uint16_t>(task + pid_off);

        return pd;
    }

    string
    ProcessInfo::name(Addr ksp) const
    {
        Addr task = this->task(ksp);
        if (!task)
            return "unknown";

        char comm[256];
        CopyStringOut(tc, comm, task + name_off, sizeof(comm));
        if (!comm[0])
            return "startup";

        return comm;
    }

    StackTrace::StackTrace()
        : tc(0), stack(64)
    {
    }

    StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst)
        : tc(0), stack(64)
    {
        trace(_tc, inst);
    }

    StackTrace::~StackTrace()
    {
    }

    void
    StackTrace::trace(ThreadContext *_tc, bool is_call)
    {
    }

    bool
    StackTrace::isEntry(Addr addr)
    {
        return false;
    }

    bool
    StackTrace::decodeStack(MachInst inst, int &disp)
    {
        return false;
    }

    bool
    StackTrace::decodeSave(MachInst inst, int &reg, int &disp)
    {
        return false;
    }

    /*
     * Decode the function prologue for the function we're in, and note
     * which registers are stored where, and how large the stack frame is.
     */
    bool
    StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
                               int &size, Addr &ra)
    {
        return false;
    }

#if TRACING_ON
    void
    StackTrace::dump()
    {
        DPRINTFN("------ Stack ------\n");

        DPRINTFN(" Not implemented\n");
    }
#endif
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2006 The Regents of The University of Michigan
 * Copyright (c) 2007 MIPS Technologies, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __ARCH_MIPS_REGISTERS_HH__
#define __ARCH_MIPS_REGISTERS_HH__

#include "arch/generic/vec_pred_reg.hh"
#include "arch/generic/vec_reg.hh"
#include "arch/mips/generated/max_inst_regs.hh"
#include "base/logging.hh"
#include "base/types.hh"

class ThreadContext;

namespace MipsISA
{

using MipsISAInst::MaxInstSrcRegs;
using MipsISAInst::MaxInstDestRegs;
using MipsISAInst::MaxMiscDestRegs;

// Constants Related to the number of registers
const int NumIntArchRegs = 32;
const int NumIntSpecialRegs = 9;
const int NumFloatArchRegs = 32;
const int NumFloatSpecialRegs = 5;

const int MaxShadowRegSets = 16; // Maximum number of shadow register sets
const int NumIntRegs = NumIntArchRegs + NumIntSpecialRegs;        //HI & LO Regs
const int NumFloatRegs = NumFloatArchRegs + NumFloatSpecialRegs;//
const int NumVecRegs = 1;  // Not applicable to MIPS
                           // (1 to prevent warnings)
const int NumVecPredRegs = 1;  // Not applicable to MIPS
                               // (1 to prevent warnings)
const int NumCCRegs = 0;

const uint32_t MIPS32_QNAN = 0x7fbfffff;
const uint64_t MIPS64_QNAN = ULL(0x7ff7ffffffffffff);

enum FPControlRegNums {
   FLOATREG_FIR = NumFloatArchRegs,
   FLOATREG_FCCR,
   FLOATREG_FEXR,
   FLOATREG_FENR,
   FLOATREG_FCSR
};

enum FCSRBits {
    Inexact = 1,
    Underflow,
    Overflow,
    DivideByZero,
    Invalid,
    Unimplemented
};

enum FCSRFields {
    Flag_Field = 1,
    Enable_Field = 6,
    Cause_Field = 11
};

enum MiscIntRegNums {
   INTREG_LO = NumIntArchRegs,
   INTREG_DSP_LO0 = INTREG_LO,
   INTREG_HI,
   INTREG_DSP_HI0 = INTREG_HI,
   INTREG_DSP_ACX0,
   INTREG_DSP_LO1,
   INTREG_DSP_HI1,
   INTREG_DSP_ACX1,
   INTREG_DSP_LO2,
   INTREG_DSP_HI2,
   INTREG_DSP_ACX2,
   INTREG_DSP_LO3,
   INTREG_DSP_HI3,
   INTREG_DSP_ACX3,
   INTREG_DSP_CONTROL
};

// semantically meaningful register indices
const int ZeroReg = 0;
const int AssemblerReg = 1;
const int SyscallSuccessReg = 7;
const int FirstArgumentReg = 4;
const int ReturnValueReg = 2;

const int KernelReg0 = 26;
const int KernelReg1 = 27;
const int GlobalPointerReg = 28;
const int StackPointerReg = 29;
const int FramePointerReg = 30;
const int ReturnAddressReg = 31;

const int SyscallPseudoReturnReg = 3;

// Enumerate names for 'Control' Registers in the CPU
// Reference MIPS32 Arch. for Programmers, Vol. III, Ch.8
// (Register Number-Register Select) Summary of Register
//------------------------------------------------------
// The first set of names classify the CP0 names as Register Banks
// for easy indexing when using the 'RD + SEL' index combination
// in CP0 instructions.
enum MiscRegIndex{
    MISCREG_INDEX = 0,       //Bank 0: 0 - 3
    MISCREG_MVP_CONTROL,
    MISCREG_MVP_CONF0,
    MISCREG_MVP_CONF1,

    MISCREG_CP0_RANDOM = 8,      //Bank 1: 8 - 15
    MISCREG_VPE_CONTROL,
    MISCREG_VPE_CONF0,
    MISCREG_VPE_CONF1,
    MISCREG_YQMASK,
    MISCREG_VPE_SCHEDULE,
    MISCREG_VPE_SCHEFBACK,
    MISCREG_VPE_OPT,

    MISCREG_ENTRYLO0 = 16,   //Bank 2: 16 - 23
    MISCREG_TC_STATUS,
    MISCREG_TC_BIND,
    MISCREG_TC_RESTART,
    MISCREG_TC_HALT,
    MISCREG_TC_CONTEXT,
    MISCREG_TC_SCHEDULE,
    MISCREG_TC_SCHEFBACK,

    MISCREG_ENTRYLO1 = 24,   // Bank 3: 24

    MISCREG_CONTEXT = 32,    // Bank 4: 32 - 33
    MISCREG_CONTEXT_CONFIG,

    MISCREG_PAGEMASK = 40, //Bank 5: 40 - 41
    MISCREG_PAGEGRAIN = 41,

    MISCREG_WIRED = 48,          //Bank 6:48-55
    MISCREG_SRS_CONF0,
    MISCREG_SRS_CONF1,
    MISCREG_SRS_CONF2,
    MISCREG_SRS_CONF3,
    MISCREG_SRS_CONF4,

    MISCREG_HWRENA = 56,         //Bank 7: 56-63

    MISCREG_BADVADDR = 64,       //Bank 8: 64-71

    MISCREG_COUNT = 72,          //Bank 9: 72-79

    MISCREG_ENTRYHI = 80,        //Bank 10: 80-87

    MISCREG_COMPARE = 88,        //Bank 11: 88-95

    MISCREG_STATUS = 96,         //Bank 12: 96-103
    MISCREG_INTCTL,
    MISCREG_SRSCTL,
    MISCREG_SRSMAP,

    MISCREG_CAUSE = 104,         //Bank 13: 104-111

    MISCREG_EPC = 112,           //Bank 14: 112-119

    MISCREG_PRID = 120,          //Bank 15: 120-127,
    MISCREG_EBASE,

    MISCREG_CONFIG = 128,        //Bank 16: 128-135
    MISCREG_CONFIG1,
    MISCREG_CONFIG2,
    MISCREG_CONFIG3,
    MISCREG_CONFIG4,
    MISCREG_CONFIG5,
    MISCREG_CONFIG6,
    MISCREG_CONFIG7,

    MISCREG_LLADDR = 136,        //Bank 17: 136-143

    MISCREG_WATCHLO0 = 144,      //Bank 18: 144-151
    MISCREG_WATCHLO1,
    MISCREG_WATCHLO2,
    MISCREG_WATCHLO3,
    MISCREG_WATCHLO4,
    MISCREG_WATCHLO5,
    MISCREG_WATCHLO6,
    MISCREG_WATCHLO7,

    MISCREG_WATCHHI0 = 152,     //Bank 19: 152-159
    MISCREG_WATCHHI1,
    MISCREG_WATCHHI2,
    MISCREG_WATCHHI3,
    MISCREG_WATCHHI4,
    MISCREG_WATCHHI5,
    MISCREG_WATCHHI6,
    MISCREG_WATCHHI7,

    MISCREG_XCCONTEXT64 = 160, //Bank 20: 160-167

                       //Bank 21: 168-175

                       //Bank 22: 176-183

    MISCREG_DEBUG = 184,       //Bank 23: 184-191
    MISCREG_TRACE_CONTROL1,
    MISCREG_TRACE_CONTROL2,
    MISCREG_USER_TRACE_DATA,
    MISCREG_TRACE_BPC,

    MISCREG_DEPC = 192,        //Bank 24: 192-199

    MISCREG_PERFCNT0 = 200,    //Bank 25: 200-207
    MISCREG_PERFCNT1,
    MISCREG_PERFCNT2,
    MISCREG_PERFCNT3,
    MISCREG_PERFCNT4,
    MISCREG_PERFCNT5,
    MISCREG_PERFCNT6,
    MISCREG_PERFCNT7,

    MISCREG_ERRCTL = 208,      //Bank 26: 208-215

    MISCREG_CACHEERR0 = 216,   //Bank 27: 216-223
    MISCREG_CACHEERR1,
    MISCREG_CACHEERR2,
    MISCREG_CACHEERR3,

    MISCREG_TAGLO0 = 224,      //Bank 28: 224-231
    MISCREG_DATALO1,
    MISCREG_TAGLO2,
    MISCREG_DATALO3,
    MISCREG_TAGLO4,
    MISCREG_DATALO5,
    MISCREG_TAGLO6,
    MISCREG_DATALO7,

    MISCREG_TAGHI0 = 232,      //Bank 29: 232-239
    MISCREG_DATAHI1,
    MISCREG_TAGHI2,
    MISCREG_DATAHI3,
    MISCREG_TAGHI4,
    MISCREG_DATAHI5,
    MISCREG_TAGHI6,
    MISCREG_DATAHI7,

    MISCREG_ERROR_EPC = 240,    //Bank 30: 240-247

    MISCREG_DESAVE = 248,       //Bank 31: 248-256

    MISCREG_LLFLAG = 257,
    MISCREG_TP_VALUE,

    MISCREG_NUMREGS
};

const int NumMiscRegs = MISCREG_NUMREGS;

const int TotalNumRegs = NumIntRegs + NumFloatRegs + NumMiscRegs;

// Not applicable to MIPS
using VecElem = ::DummyVecElem;
using VecReg = ::DummyVecReg;
using ConstVecReg = ::DummyConstVecReg;
using VecRegContainer = ::DummyVecRegContainer;
constexpr unsigned NumVecElemPerVecReg = ::DummyNumVecElemPerVecReg;
constexpr size_t VecRegSizeBytes = ::DummyVecRegSizeBytes;

// Not applicable to MIPS
using VecPredReg = ::DummyVecPredReg;
using ConstVecPredReg = ::DummyConstVecPredReg;
using VecPredRegContainer = ::DummyVecPredRegContainer;
constexpr size_t VecPredRegSizeBits = ::DummyVecPredRegSizeBits;
constexpr bool VecPredRegHasPackedRepr = ::DummyVecPredRegHasPackedRepr;

} // namespace MipsISA

#endif
<commit_msg>arch-mips: Delete unused register related constants.<commit_after>/*
 * Copyright (c) 2006 The Regents of The University of Michigan
 * Copyright (c) 2007 MIPS Technologies, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __ARCH_MIPS_REGISTERS_HH__
#define __ARCH_MIPS_REGISTERS_HH__

#include "arch/generic/vec_pred_reg.hh"
#include "arch/generic/vec_reg.hh"
#include "arch/mips/generated/max_inst_regs.hh"
#include "base/logging.hh"
#include "base/types.hh"

class ThreadContext;

namespace MipsISA
{

using MipsISAInst::MaxInstSrcRegs;
using MipsISAInst::MaxInstDestRegs;
using MipsISAInst::MaxMiscDestRegs;

// Constants Related to the number of registers
const int NumIntArchRegs = 32;
const int NumIntSpecialRegs = 9;
const int NumFloatArchRegs = 32;
const int NumFloatSpecialRegs = 5;

const int MaxShadowRegSets = 16; // Maximum number of shadow register sets
const int NumIntRegs = NumIntArchRegs + NumIntSpecialRegs;        //HI & LO Regs
const int NumFloatRegs = NumFloatArchRegs + NumFloatSpecialRegs;//
const int NumVecRegs = 1;  // Not applicable to MIPS
                           // (1 to prevent warnings)
const int NumVecPredRegs = 1;  // Not applicable to MIPS
                               // (1 to prevent warnings)
const int NumCCRegs = 0;

const uint32_t MIPS32_QNAN = 0x7fbfffff;
const uint64_t MIPS64_QNAN = ULL(0x7ff7ffffffffffff);

enum FPControlRegNums {
   FLOATREG_FIR = NumFloatArchRegs,
   FLOATREG_FCCR,
   FLOATREG_FEXR,
   FLOATREG_FENR,
   FLOATREG_FCSR
};

enum FCSRBits {
    Inexact = 1,
    Underflow,
    Overflow,
    DivideByZero,
    Invalid,
    Unimplemented
};

enum FCSRFields {
    Flag_Field = 1,
    Enable_Field = 6,
    Cause_Field = 11
};

enum MiscIntRegNums {
   INTREG_LO = NumIntArchRegs,
   INTREG_DSP_LO0 = INTREG_LO,
   INTREG_HI,
   INTREG_DSP_HI0 = INTREG_HI,
   INTREG_DSP_ACX0,
   INTREG_DSP_LO1,
   INTREG_DSP_HI1,
   INTREG_DSP_ACX1,
   INTREG_DSP_LO2,
   INTREG_DSP_HI2,
   INTREG_DSP_ACX2,
   INTREG_DSP_LO3,
   INTREG_DSP_HI3,
   INTREG_DSP_ACX3,
   INTREG_DSP_CONTROL
};

// semantically meaningful register indices
const int ZeroReg = 0;
const int SyscallSuccessReg = 7;
const int FirstArgumentReg = 4;
const int ReturnValueReg = 2;

const int StackPointerReg = 29;

const int SyscallPseudoReturnReg = 3;

// Enumerate names for 'Control' Registers in the CPU
// Reference MIPS32 Arch. for Programmers, Vol. III, Ch.8
// (Register Number-Register Select) Summary of Register
//------------------------------------------------------
// The first set of names classify the CP0 names as Register Banks
// for easy indexing when using the 'RD + SEL' index combination
// in CP0 instructions.
enum MiscRegIndex{
    MISCREG_INDEX = 0,       //Bank 0: 0 - 3
    MISCREG_MVP_CONTROL,
    MISCREG_MVP_CONF0,
    MISCREG_MVP_CONF1,

    MISCREG_CP0_RANDOM = 8,      //Bank 1: 8 - 15
    MISCREG_VPE_CONTROL,
    MISCREG_VPE_CONF0,
    MISCREG_VPE_CONF1,
    MISCREG_YQMASK,
    MISCREG_VPE_SCHEDULE,
    MISCREG_VPE_SCHEFBACK,
    MISCREG_VPE_OPT,

    MISCREG_ENTRYLO0 = 16,   //Bank 2: 16 - 23
    MISCREG_TC_STATUS,
    MISCREG_TC_BIND,
    MISCREG_TC_RESTART,
    MISCREG_TC_HALT,
    MISCREG_TC_CONTEXT,
    MISCREG_TC_SCHEDULE,
    MISCREG_TC_SCHEFBACK,

    MISCREG_ENTRYLO1 = 24,   // Bank 3: 24

    MISCREG_CONTEXT = 32,    // Bank 4: 32 - 33
    MISCREG_CONTEXT_CONFIG,

    MISCREG_PAGEMASK = 40, //Bank 5: 40 - 41
    MISCREG_PAGEGRAIN = 41,

    MISCREG_WIRED = 48,          //Bank 6:48-55
    MISCREG_SRS_CONF0,
    MISCREG_SRS_CONF1,
    MISCREG_SRS_CONF2,
    MISCREG_SRS_CONF3,
    MISCREG_SRS_CONF4,

    MISCREG_HWRENA = 56,         //Bank 7: 56-63

    MISCREG_BADVADDR = 64,       //Bank 8: 64-71

    MISCREG_COUNT = 72,          //Bank 9: 72-79

    MISCREG_ENTRYHI = 80,        //Bank 10: 80-87

    MISCREG_COMPARE = 88,        //Bank 11: 88-95

    MISCREG_STATUS = 96,         //Bank 12: 96-103
    MISCREG_INTCTL,
    MISCREG_SRSCTL,
    MISCREG_SRSMAP,

    MISCREG_CAUSE = 104,         //Bank 13: 104-111

    MISCREG_EPC = 112,           //Bank 14: 112-119

    MISCREG_PRID = 120,          //Bank 15: 120-127,
    MISCREG_EBASE,

    MISCREG_CONFIG = 128,        //Bank 16: 128-135
    MISCREG_CONFIG1,
    MISCREG_CONFIG2,
    MISCREG_CONFIG3,
    MISCREG_CONFIG4,
    MISCREG_CONFIG5,
    MISCREG_CONFIG6,
    MISCREG_CONFIG7,

    MISCREG_LLADDR = 136,        //Bank 17: 136-143

    MISCREG_WATCHLO0 = 144,      //Bank 18: 144-151
    MISCREG_WATCHLO1,
    MISCREG_WATCHLO2,
    MISCREG_WATCHLO3,
    MISCREG_WATCHLO4,
    MISCREG_WATCHLO5,
    MISCREG_WATCHLO6,
    MISCREG_WATCHLO7,

    MISCREG_WATCHHI0 = 152,     //Bank 19: 152-159
    MISCREG_WATCHHI1,
    MISCREG_WATCHHI2,
    MISCREG_WATCHHI3,
    MISCREG_WATCHHI4,
    MISCREG_WATCHHI5,
    MISCREG_WATCHHI6,
    MISCREG_WATCHHI7,

    MISCREG_XCCONTEXT64 = 160, //Bank 20: 160-167

                       //Bank 21: 168-175

                       //Bank 22: 176-183

    MISCREG_DEBUG = 184,       //Bank 23: 184-191
    MISCREG_TRACE_CONTROL1,
    MISCREG_TRACE_CONTROL2,
    MISCREG_USER_TRACE_DATA,
    MISCREG_TRACE_BPC,

    MISCREG_DEPC = 192,        //Bank 24: 192-199

    MISCREG_PERFCNT0 = 200,    //Bank 25: 200-207
    MISCREG_PERFCNT1,
    MISCREG_PERFCNT2,
    MISCREG_PERFCNT3,
    MISCREG_PERFCNT4,
    MISCREG_PERFCNT5,
    MISCREG_PERFCNT6,
    MISCREG_PERFCNT7,

    MISCREG_ERRCTL = 208,      //Bank 26: 208-215

    MISCREG_CACHEERR0 = 216,   //Bank 27: 216-223
    MISCREG_CACHEERR1,
    MISCREG_CACHEERR2,
    MISCREG_CACHEERR3,

    MISCREG_TAGLO0 = 224,      //Bank 28: 224-231
    MISCREG_DATALO1,
    MISCREG_TAGLO2,
    MISCREG_DATALO3,
    MISCREG_TAGLO4,
    MISCREG_DATALO5,
    MISCREG_TAGLO6,
    MISCREG_DATALO7,

    MISCREG_TAGHI0 = 232,      //Bank 29: 232-239
    MISCREG_DATAHI1,
    MISCREG_TAGHI2,
    MISCREG_DATAHI3,
    MISCREG_TAGHI4,
    MISCREG_DATAHI5,
    MISCREG_TAGHI6,
    MISCREG_DATAHI7,

    MISCREG_ERROR_EPC = 240,    //Bank 30: 240-247

    MISCREG_DESAVE = 248,       //Bank 31: 248-256

    MISCREG_LLFLAG = 257,
    MISCREG_TP_VALUE,

    MISCREG_NUMREGS
};

const int NumMiscRegs = MISCREG_NUMREGS;

// Not applicable to MIPS
using VecElem = ::DummyVecElem;
using VecReg = ::DummyVecReg;
using ConstVecReg = ::DummyConstVecReg;
using VecRegContainer = ::DummyVecRegContainer;
constexpr unsigned NumVecElemPerVecReg = ::DummyNumVecElemPerVecReg;
constexpr size_t VecRegSizeBytes = ::DummyVecRegSizeBytes;

// Not applicable to MIPS
using VecPredReg = ::DummyVecPredReg;
using ConstVecPredReg = ::DummyConstVecPredReg;
using VecPredRegContainer = ::DummyVecPredRegContainer;
constexpr size_t VecPredRegSizeBits = ::DummyVecPredRegSizeBits;
constexpr bool VecPredRegHasPackedRepr = ::DummyVecPredRegHasPackedRepr;

} // namespace MipsISA

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.  Redistributions
 * in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.  Neither the name of
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#ifndef __ARCH_X86_INTERRUPTS_HH__
#define __ARCH_X86_INTERRUPTS_HH__

#include "arch/x86/apicregs.hh"
#include "arch/x86/faults.hh"
#include "arch/x86/intmessage.hh"
#include "base/bitfield.hh"
#include "cpu/thread_context.hh"
#include "dev/io_device.hh"
#include "dev/x86/intdev.hh"
#include "params/X86LocalApic.hh"
#include "sim/eventq.hh"

class ThreadContext;
class BaseCPU;

namespace X86ISA {

class Interrupts : public BasicPioDevice, IntDev
{
  protected:
    // Storage for the APIC registers
    uint32_t regs[NUM_APIC_REGS];

    BitUnion32(LVTEntry)
        Bitfield<7, 0> vector;
        Bitfield<10, 8> deliveryMode;
        Bitfield<12> status;
        Bitfield<13> polarity;
        Bitfield<14> remoteIRR;
        Bitfield<15> trigger;
        Bitfield<16> masked;
        Bitfield<17> periodic;
    EndBitUnion(LVTEntry)

    /*
     * Timing related stuff.
     */
    Tick latency;
    Tick clock;

    class ApicTimerEvent : public Event
    {
      private:
        Interrupts *localApic;
      public:
        ApicTimerEvent(Interrupts *_localApic) :
            Event(), localApic(_localApic)
        {}

        void process()
        {
            assert(localApic);
            if (localApic->triggerTimerInterrupt()) {
                localApic->setReg(APIC_INITIAL_COUNT,
                        localApic->readReg(APIC_INITIAL_COUNT));
            }
        }
    };

    ApicTimerEvent apicTimerEvent;

    /*
     * A set of variables to keep track of interrupts that don't go through
     * the IRR.
     */
    bool pendingSmi;
    uint8_t smiVector;
    bool pendingNmi;
    uint8_t nmiVector;
    bool pendingExtInt;
    uint8_t extIntVector;
    bool pendingInit;
    uint8_t initVector;
    bool pendingStartup;
    uint8_t startupVector;
    bool startedUp;

    // This is a quick check whether any of the above (except ExtInt) are set.
    bool pendingUnmaskableInt;

    // A count of how many IPIs are in flight.
    int pendingIPIs;

    /*
     * IRR and ISR maintenance.
     */
    uint8_t IRRV;
    uint8_t ISRV;

    int
    findRegArrayMSB(ApicRegIndex base)
    {
        int offset = 7;
        do {
            if (regs[base + offset] != 0) {
                return offset * 32 + findMsbSet(regs[base + offset]);
            }
        } while (offset--);
        return 0;
    }

    void
    updateIRRV()
    {
        IRRV = findRegArrayMSB(APIC_INTERRUPT_REQUEST_BASE);
    }

    void
    updateISRV()
    {
        ISRV = findRegArrayMSB(APIC_IN_SERVICE_BASE);
    }

    void
    setRegArrayBit(ApicRegIndex base, uint8_t vector)
    {
        regs[base + (vector % 32)] |= (1 << (vector >> 5));
    }

    void
    clearRegArrayBit(ApicRegIndex base, uint8_t vector)
    {
        regs[base + (vector % 32)] &= ~(1 << (vector >> 5));
    }

    bool
    getRegArrayBit(ApicRegIndex base, uint8_t vector)
    {
        return bits(regs[base + (vector % 32)], vector >> 5);
    }

    void requestInterrupt(uint8_t vector, uint8_t deliveryMode, bool level);

    BaseCPU *cpu;

  public:
    /*
     * Params stuff.
     */
    typedef X86LocalApicParams Params;

    void setCPU(BaseCPU * newCPU);

    void
    setClock(Tick newClock)
    {
        clock = newClock;
    }

    const Params *
    params() const
    {
        return dynamic_cast<const Params *>(_params);
    }

    /*
     * Functions to interact with the interrupt port from IntDev.
     */
    Tick read(PacketPtr pkt);
    Tick write(PacketPtr pkt);
    Tick recvMessage(PacketPtr pkt);
    Tick recvResponse(PacketPtr pkt);

    bool
    triggerTimerInterrupt()
    {
        LVTEntry entry = regs[APIC_LVT_TIMER];
        if (!entry.masked)
            requestInterrupt(entry.vector, entry.deliveryMode, entry.trigger);
        return entry.periodic;
    }

    void addressRanges(AddrRangeList &range_list);
    void getIntAddrRange(AddrRangeList &range_list);

    Port *getPort(const std::string &if_name, int idx = -1)
    {
        if (if_name == "int_port")
            return intPort;
        return BasicPioDevice::getPort(if_name, idx);
    }

    /*
     * Functions to access and manipulate the APIC's registers.
     */

    uint32_t readReg(ApicRegIndex miscReg);
    void setReg(ApicRegIndex reg, uint32_t val);
    void
    setRegNoEffect(ApicRegIndex reg, uint32_t val)
    {
        regs[reg] = val;
    }

    /*
     * Constructor.
     */

    Interrupts(Params * p);

    /*
     * Functions for retrieving interrupts for the CPU to handle.
     */

    bool checkInterrupts(ThreadContext *tc) const;
    Fault getInterrupt(ThreadContext *tc);
    void updateIntrInfo(ThreadContext *tc);

    /*
     * Serialization.
     */

    void
    serialize(std::ostream &os)
    {
        panic("Interrupts::serialize unimplemented!\n");
    }

    void
    unserialize(Checkpoint *cp, const std::string &section)
    {
        panic("Interrupts::unserialize unimplemented!\n");
    }

    /*
     * Old functions needed for compatability but which will be phased out
     * eventually.
     */
    void
    post(int int_num, int index)
    {
        panic("Interrupts::post unimplemented!\n");
    }

    void
    clear(int int_num, int index)
    {
        panic("Interrupts::clear unimplemented!\n");
    }

    void
    clearAll()
    {
        panic("Interrupts::clearAll unimplemented!\n");
    }
};

} // namespace X86ISA

#endif // __ARCH_X86_INTERRUPTS_HH__
<commit_msg>X86: Fix the functions that manipulate large bit arrays in the local APIC.<commit_after>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.  Redistributions
 * in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.  Neither the name of
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#ifndef __ARCH_X86_INTERRUPTS_HH__
#define __ARCH_X86_INTERRUPTS_HH__

#include "arch/x86/apicregs.hh"
#include "arch/x86/faults.hh"
#include "arch/x86/intmessage.hh"
#include "base/bitfield.hh"
#include "cpu/thread_context.hh"
#include "dev/io_device.hh"
#include "dev/x86/intdev.hh"
#include "params/X86LocalApic.hh"
#include "sim/eventq.hh"

class ThreadContext;
class BaseCPU;

namespace X86ISA {

class Interrupts : public BasicPioDevice, IntDev
{
  protected:
    // Storage for the APIC registers
    uint32_t regs[NUM_APIC_REGS];

    BitUnion32(LVTEntry)
        Bitfield<7, 0> vector;
        Bitfield<10, 8> deliveryMode;
        Bitfield<12> status;
        Bitfield<13> polarity;
        Bitfield<14> remoteIRR;
        Bitfield<15> trigger;
        Bitfield<16> masked;
        Bitfield<17> periodic;
    EndBitUnion(LVTEntry)

    /*
     * Timing related stuff.
     */
    Tick latency;
    Tick clock;

    class ApicTimerEvent : public Event
    {
      private:
        Interrupts *localApic;
      public:
        ApicTimerEvent(Interrupts *_localApic) :
            Event(), localApic(_localApic)
        {}

        void process()
        {
            assert(localApic);
            if (localApic->triggerTimerInterrupt()) {
                localApic->setReg(APIC_INITIAL_COUNT,
                        localApic->readReg(APIC_INITIAL_COUNT));
            }
        }
    };

    ApicTimerEvent apicTimerEvent;

    /*
     * A set of variables to keep track of interrupts that don't go through
     * the IRR.
     */
    bool pendingSmi;
    uint8_t smiVector;
    bool pendingNmi;
    uint8_t nmiVector;
    bool pendingExtInt;
    uint8_t extIntVector;
    bool pendingInit;
    uint8_t initVector;
    bool pendingStartup;
    uint8_t startupVector;
    bool startedUp;

    // This is a quick check whether any of the above (except ExtInt) are set.
    bool pendingUnmaskableInt;

    // A count of how many IPIs are in flight.
    int pendingIPIs;

    /*
     * IRR and ISR maintenance.
     */
    uint8_t IRRV;
    uint8_t ISRV;

    int
    findRegArrayMSB(ApicRegIndex base)
    {
        int offset = 7;
        do {
            if (regs[base + offset] != 0) {
                return offset * 32 + findMsbSet(regs[base + offset]);
            }
        } while (offset--);
        return 0;
    }

    void
    updateIRRV()
    {
        IRRV = findRegArrayMSB(APIC_INTERRUPT_REQUEST_BASE);
    }

    void
    updateISRV()
    {
        ISRV = findRegArrayMSB(APIC_IN_SERVICE_BASE);
    }

    void
    setRegArrayBit(ApicRegIndex base, uint8_t vector)
    {
        regs[base + (vector / 32)] |= (1 << (vector % 32));
    }

    void
    clearRegArrayBit(ApicRegIndex base, uint8_t vector)
    {
        regs[base + (vector / 32)] &= ~(1 << (vector % 32));
    }

    bool
    getRegArrayBit(ApicRegIndex base, uint8_t vector)
    {
        return bits(regs[base + (vector / 32)], vector % 5);
    }

    void requestInterrupt(uint8_t vector, uint8_t deliveryMode, bool level);

    BaseCPU *cpu;

  public:
    /*
     * Params stuff.
     */
    typedef X86LocalApicParams Params;

    void setCPU(BaseCPU * newCPU);

    void
    setClock(Tick newClock)
    {
        clock = newClock;
    }

    const Params *
    params() const
    {
        return dynamic_cast<const Params *>(_params);
    }

    /*
     * Functions to interact with the interrupt port from IntDev.
     */
    Tick read(PacketPtr pkt);
    Tick write(PacketPtr pkt);
    Tick recvMessage(PacketPtr pkt);
    Tick recvResponse(PacketPtr pkt);

    bool
    triggerTimerInterrupt()
    {
        LVTEntry entry = regs[APIC_LVT_TIMER];
        if (!entry.masked)
            requestInterrupt(entry.vector, entry.deliveryMode, entry.trigger);
        return entry.periodic;
    }

    void addressRanges(AddrRangeList &range_list);
    void getIntAddrRange(AddrRangeList &range_list);

    Port *getPort(const std::string &if_name, int idx = -1)
    {
        if (if_name == "int_port")
            return intPort;
        return BasicPioDevice::getPort(if_name, idx);
    }

    /*
     * Functions to access and manipulate the APIC's registers.
     */

    uint32_t readReg(ApicRegIndex miscReg);
    void setReg(ApicRegIndex reg, uint32_t val);
    void
    setRegNoEffect(ApicRegIndex reg, uint32_t val)
    {
        regs[reg] = val;
    }

    /*
     * Constructor.
     */

    Interrupts(Params * p);

    /*
     * Functions for retrieving interrupts for the CPU to handle.
     */

    bool checkInterrupts(ThreadContext *tc) const;
    Fault getInterrupt(ThreadContext *tc);
    void updateIntrInfo(ThreadContext *tc);

    /*
     * Serialization.
     */

    void
    serialize(std::ostream &os)
    {
        panic("Interrupts::serialize unimplemented!\n");
    }

    void
    unserialize(Checkpoint *cp, const std::string &section)
    {
        panic("Interrupts::unserialize unimplemented!\n");
    }

    /*
     * Old functions needed for compatability but which will be phased out
     * eventually.
     */
    void
    post(int int_num, int index)
    {
        panic("Interrupts::post unimplemented!\n");
    }

    void
    clear(int int_num, int index)
    {
        panic("Interrupts::clear unimplemented!\n");
    }

    void
    clearAll()
    {
        panic("Interrupts::clearAll unimplemented!\n");
    }
};

} // namespace X86ISA

#endif // __ARCH_X86_INTERRUPTS_HH__
<|endoftext|>