<commit_before>// Copyright (c) 2012-2013 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "dbwrapper.h"
#include "uint256.h"
#include "random.h"
#include "test/test_pivx.h"

#include <boost/test/unit_test.hpp>

// Test if a string consists entirely of null characters
bool is_null_key(const std::vector<unsigned char>& key) {
    bool isnull = true;

    for (unsigned int i = 0; i < key.size(); i++)
        isnull &= (key[i] == '\x00');

    return isnull;
}

BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(dbwrapper)
{
    {
        fs::path ph = fs::temp_directory_path() / fs::unique_path();
        CDBWrapper dbw(ph, (1 << 20), true, false);
        char key = 'k';
        uint256 in = GetRandHash();
        uint256 res;

        BOOST_CHECK(dbw.Write(key, in));
        BOOST_CHECK(dbw.Read(key, res));
        BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
    }
}

// Test batch operations
BOOST_AUTO_TEST_CASE(dbwrapper_batch)
{
    {
        fs::path ph = fs::temp_directory_path() / fs::unique_path();
        CDBWrapper dbw(ph, (1 << 20), true, false);

        char key = 'i';
        uint256 in = GetRandHash();
        char key2 = 'j';
        uint256 in2 = GetRandHash();
        char key3 = 'k';
        uint256 in3 = GetRandHash();

        uint256 res;
        CDBBatch batch;

        batch.Write(key, in);
        batch.Write(key2, in2);
        batch.Write(key3, in3);

        // Remove key3 before it's even been written
        batch.Erase(key3);

        dbw.WriteBatch(batch);

        BOOST_CHECK(dbw.Read(key, res));
        BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
        BOOST_CHECK(dbw.Read(key2, res));
        BOOST_CHECK_EQUAL(res.ToString(), in2.ToString());

        // key3 never should've been written
        BOOST_CHECK(dbw.Read(key3, res) == false);
    }
}

BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
{
    {
        fs::path ph = fs::temp_directory_path() / fs::unique_path();
        CDBWrapper dbw(ph, (1 << 20), true, false);

        // The two keys are intentionally chosen for ordering
        char key = 'j';
        uint256 in = GetRandHash();
        BOOST_CHECK(dbw.Write(key, in));
        char key2 = 'k';
        uint256 in2 = GetRandHash();
        BOOST_CHECK(dbw.Write(key2, in2));

        std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());

        // Be sure to seek past any earlier key (if it exists)
        it->Seek(key);

        char key_res;
        uint256 val_res;

        it->GetKey(key_res);
        it->GetValue(val_res);
        BOOST_CHECK_EQUAL(key_res, key);
        BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString());

        it->Next();

        it->GetKey(key_res);
        it->GetValue(val_res);
        BOOST_CHECK_EQUAL(key_res, key2);
        BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString());

        it->Next();
        BOOST_CHECK_EQUAL(it->Valid(), false);
    }
}

BOOST_AUTO_TEST_CASE(iterator_ordering)
{
    fs::path ph = fs::temp_directory_path() / fs::unique_path();
    CDBWrapper dbw(ph, (1 << 20), true, false);
    for (int x=0x00; x<256; ++x) {
        uint8_t key = x;
        uint32_t value = x*x;
        BOOST_CHECK(dbw.Write(key, value));
    }

    std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
    for (int c=0; c<2; ++c) {
        int seek_start;
        if (c == 0)
            seek_start = 0x00;
        else
            seek_start = 0x80;
        it->Seek((uint8_t)seek_start);
        for (int x=seek_start; x<256; ++x) {
            uint8_t key;
            uint32_t value;
            BOOST_CHECK(it->Valid());
            if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
                break;
            BOOST_CHECK(it->GetKey(key));
            BOOST_CHECK(it->GetValue(value));
            BOOST_CHECK_EQUAL(key, x);
            BOOST_CHECK_EQUAL(value, x*x);
            it->Next();
        }
        BOOST_CHECK(!it->Valid());
    }
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Add test for dbwrapper iterators with same-prefix keys.<commit_after>// Copyright (c) 2012-2013 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "dbwrapper.h"
#include "uint256.h"
#include "random.h"
#include "test/test_pivx.h"

#include <boost/test/unit_test.hpp>

// Test if a string consists entirely of null characters
bool is_null_key(const std::vector<unsigned char>& key) {
    bool isnull = true;

    for (unsigned int i = 0; i < key.size(); i++)
        isnull &= (key[i] == '\x00');

    return isnull;
}

BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(dbwrapper)
{
    {
        fs::path ph = fs::temp_directory_path() / fs::unique_path();
        CDBWrapper dbw(ph, (1 << 20), true, false);
        char key = 'k';
        uint256 in = GetRandHash();
        uint256 res;

        BOOST_CHECK(dbw.Write(key, in));
        BOOST_CHECK(dbw.Read(key, res));
        BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
    }
}

// Test batch operations
BOOST_AUTO_TEST_CASE(dbwrapper_batch)
{
    {
        fs::path ph = fs::temp_directory_path() / fs::unique_path();
        CDBWrapper dbw(ph, (1 << 20), true, false);

        char key = 'i';
        uint256 in = GetRandHash();
        char key2 = 'j';
        uint256 in2 = GetRandHash();
        char key3 = 'k';
        uint256 in3 = GetRandHash();

        uint256 res;
        CDBBatch batch;

        batch.Write(key, in);
        batch.Write(key2, in2);
        batch.Write(key3, in3);

        // Remove key3 before it's even been written
        batch.Erase(key3);

        dbw.WriteBatch(batch);

        BOOST_CHECK(dbw.Read(key, res));
        BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
        BOOST_CHECK(dbw.Read(key2, res));
        BOOST_CHECK_EQUAL(res.ToString(), in2.ToString());

        // key3 never should've been written
        BOOST_CHECK(dbw.Read(key3, res) == false);
    }
}

BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
{
    {
        fs::path ph = fs::temp_directory_path() / fs::unique_path();
        CDBWrapper dbw(ph, (1 << 20), true, false);

        // The two keys are intentionally chosen for ordering
        char key = 'j';
        uint256 in = GetRandHash();
        BOOST_CHECK(dbw.Write(key, in));
        char key2 = 'k';
        uint256 in2 = GetRandHash();
        BOOST_CHECK(dbw.Write(key2, in2));

        std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator());

        // Be sure to seek past any earlier key (if it exists)
        it->Seek(key);

        char key_res;
        uint256 val_res;

        it->GetKey(key_res);
        it->GetValue(val_res);
        BOOST_CHECK_EQUAL(key_res, key);
        BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString());

        it->Next();

        it->GetKey(key_res);
        it->GetValue(val_res);
        BOOST_CHECK_EQUAL(key_res, key2);
        BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString());

        it->Next();
        BOOST_CHECK_EQUAL(it->Valid(), false);
    }
}

BOOST_AUTO_TEST_CASE(iterator_ordering)
{
    fs::path ph = fs::temp_directory_path() / fs::unique_path();
    CDBWrapper dbw(ph, (1 << 20), true, false);
    for (int x=0x00; x<256; ++x) {
        uint8_t key = x;
        uint32_t value = x*x;
        BOOST_CHECK(dbw.Write(key, value));
    }

    std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
    for (int c=0; c<2; ++c) {
        int seek_start;
        if (c == 0)
            seek_start = 0x00;
        else
            seek_start = 0x80;
        it->Seek((uint8_t)seek_start);
        for (int x=seek_start; x<256; ++x) {
            uint8_t key;
            uint32_t value;
            BOOST_CHECK(it->Valid());
            if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
                break;
            BOOST_CHECK(it->GetKey(key));
            BOOST_CHECK(it->GetValue(value));
            BOOST_CHECK_EQUAL(key, x);
            BOOST_CHECK_EQUAL(value, x*x);
            it->Next();
        }
        BOOST_CHECK(!it->Valid());
    }
}

struct StringContentsSerializer {
    // Used to make two serialized objects the same while letting them have a different lengths
    // This is a terrible idea
    std::string str;
    StringContentsSerializer() {}
    StringContentsSerializer(const std::string& inp) : str(inp) {}

    StringContentsSerializer& operator+=(const std::string& s) {
        str += s;
        return *this;
    }
    StringContentsSerializer& operator+=(const StringContentsSerializer& s) { return *this += s.str; }

    ADD_SERIALIZE_METHODS;

    template <typename Stream, typename Operation>
    inline void SerializationOp(Stream& s, Operation ser_action) {
        if (ser_action.ForRead()) {
            str.clear();
            char c = 0;
            while (true) {
                try {
                    READWRITE(c);
                    str.push_back(c);
                } catch (const std::ios_base::failure& e) {
                    break;
                }
            }
        } else {
            for (size_t i = 0; i < str.size(); i++)
                READWRITE(str[i]);
        }
    }
};

BOOST_AUTO_TEST_CASE(iterator_string_ordering)
{
    char buf[10];

    fs::path ph = fs::temp_directory_path() / fs::unique_path();
    CDBWrapper dbw(ph, (1 << 20), true, false);
    for (int x=0x00; x<10; ++x) {
        for (int y = 0; y < 10; y++) {
            sprintf(buf, "%d", x);
            StringContentsSerializer key(buf);
            for (int z = 0; z < y; z++)
                key += key;
            uint32_t value = x*x;
            BOOST_CHECK(dbw.Write(key, value));
        }
    }

    boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
    for (int c=0; c<2; ++c) {
        int seek_start;
        if (c == 0)
            seek_start = 0;
        else
            seek_start = 5;
        sprintf(buf, "%d", seek_start);
        StringContentsSerializer seek_key(buf);
        it->Seek(seek_key);
        for (int x=seek_start; x<10; ++x) {
            for (int y = 0; y < 10; y++) {
                sprintf(buf, "%d", x);
                std::string exp_key(buf);
                for (int z = 0; z < y; z++)
                    exp_key += exp_key;
                StringContentsSerializer key;
                uint32_t value;
                BOOST_CHECK(it->Valid());
                if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure
                    break;
                BOOST_CHECK(it->GetKey(key));
                BOOST_CHECK(it->GetValue(value));
                BOOST_CHECK_EQUAL(key.str, exp_key);
                BOOST_CHECK_EQUAL(value, x*x);
                it->Next();
            }
        }
        BOOST_CHECK(!it->Valid());
    }
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include "serialize.h"

#include <stdint.h>

#include <boost/test/unit_test.hpp>

using namespace std;

BOOST_AUTO_TEST_SUITE(serialize_tests)

BOOST_AUTO_TEST_CASE(varints)
{
    // encode

    CDataStream ss(SER_DISK, 0);
    CDataStream::size_type size = 0;
    for (int i = 0; i < 100000; i++) {
        ss << VARINT(i);
        size += ::GetSerializeSize(VARINT(i), 0, 0);
        BOOST_CHECK(size == ss.size());
    }

    for (uint64_t i = 0;  i < 100000000000ULL; i += 999999937) {
        ss << VARINT(i);
        size += ::GetSerializeSize(VARINT(i), 0, 0);
        BOOST_CHECK(size == ss.size());
    }

    // decode
    for (int i = 0; i < 100000; i++) {
        int j = -1;
        ss >> VARINT(j);
        BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
    }

    for (uint64_t i = 0;  i < 100000000000ULL; i += 999999937) {
        uint64_t j = -1;
        ss >> VARINT(j);
        BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
    }
}

BOOST_AUTO_TEST_CASE(compactsize)
{
    CDataStream ss(SER_DISK, 0);
    vector<char>::size_type i, j;

    for (i = 1; i <= MAX_SIZE; i *= 2)
    {
        WriteCompactSize(ss, i-1);
        WriteCompactSize(ss, i);
    }
    for (i = 1; i <= MAX_SIZE; i *= 2)
    {
        j = ReadCompactSize(ss);
        BOOST_CHECK_MESSAGE((i-1) == j, "decoded:" << j << " expected:" << (i-1));
        j = ReadCompactSize(ss);
        BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
    }
}

static bool isCanonicalException(const std::ios_base::failure& ex)
{
    return std::string("non-canonical ReadCompactSize()") == ex.what();
}

BOOST_AUTO_TEST_CASE(noncanonical)
{
    // Write some non-canonical CompactSize encodings, and
    // make sure an exception is thrown when read back.
    CDataStream ss(SER_DISK, 0);
    vector<char>::size_type n;

    // zero encoded with three bytes:
    ss.write("\xfd\x00\x00", 3);
    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);

    // 0xfc encoded with three bytes:
    ss.write("\xfd\xfc\x00", 3);
    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);

    // 0xfd encoded with three bytes is OK:
    ss.write("\xfd\xfd\x00", 3);
    n = ReadCompactSize(ss);
    BOOST_CHECK(n == 0xfd);

    // zero encoded with five bytes:
    ss.write("\xfe\x00\x00\x00\x00", 5);
    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);

    // 0xffff encoded with five bytes:
    ss.write("\xfe\xff\xff\x00\x00", 5);
    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);

    // zero encoded with nine bytes:
    ss.write("\xff\x00\x00\x00\x00\x00\x00\x00\x00", 9);
    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);

    // 0x01ffffff encoded with nine bytes:
    ss.write("\xff\xff\xff\xff\x01\x00\x00\x00\x00", 9);
    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
}

BOOST_AUTO_TEST_CASE(insert_delete)
{
    // Test inserting/deleting bytes.
    CDataStream ss(SER_DISK, 0);
    BOOST_CHECK_EQUAL(ss.size(), 0);

    ss.write("\x00\x01\x02\xff", 4);
    BOOST_CHECK_EQUAL(ss.size(), 4);

    char c = (char)11;

    // Inserting at beginning/end/middle:
    ss.insert(ss.begin(), c);
    BOOST_CHECK_EQUAL(ss.size(), 5);
    BOOST_CHECK_EQUAL(ss[0], c);
    BOOST_CHECK_EQUAL(ss[1], 0);

    ss.insert(ss.end(), c);
    BOOST_CHECK_EQUAL(ss.size(), 6);
    BOOST_CHECK_EQUAL(ss[4], (char)0xff);
    BOOST_CHECK_EQUAL(ss[5], c);

    ss.insert(ss.begin()+2, c);
    BOOST_CHECK_EQUAL(ss.size(), 7);
    BOOST_CHECK_EQUAL(ss[2], c);

    // Delete at beginning/end/middle
    ss.erase(ss.begin());
    BOOST_CHECK_EQUAL(ss.size(), 6);
    BOOST_CHECK_EQUAL(ss[0], 0);

    ss.erase(ss.begin()+ss.size()-1);
    BOOST_CHECK_EQUAL(ss.size(), 5);
    BOOST_CHECK_EQUAL(ss[4], (char)0xff);

    ss.erase(ss.begin()+1);
    BOOST_CHECK_EQUAL(ss.size(), 4);
    BOOST_CHECK_EQUAL(ss[0], 0);
    BOOST_CHECK_EQUAL(ss[1], 1);
    BOOST_CHECK_EQUAL(ss[2], 2);
    BOOST_CHECK_EQUAL(ss[3], (char)0xff);

    // Make sure GetAndClear does the right thing:
    CSerializeData d;
    ss.GetAndClear(d);
    BOOST_CHECK_EQUAL(ss.size(), 0);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Fix unit test error on OSX 10.9 using Apple LLVM v5.0.<commit_after>#include "serialize.h"

#include <stdint.h>

#include <boost/test/unit_test.hpp>

using namespace std;

BOOST_AUTO_TEST_SUITE(serialize_tests)

BOOST_AUTO_TEST_CASE(varints)
{
    // encode

    CDataStream ss(SER_DISK, 0);
    CDataStream::size_type size = 0;
    for (int i = 0; i < 100000; i++) {
        ss << VARINT(i);
        size += ::GetSerializeSize(VARINT(i), 0, 0);
        BOOST_CHECK(size == ss.size());
    }

    for (uint64_t i = 0;  i < 100000000000ULL; i += 999999937) {
        ss << VARINT(i);
        size += ::GetSerializeSize(VARINT(i), 0, 0);
        BOOST_CHECK(size == ss.size());
    }

    // decode
    for (int i = 0; i < 100000; i++) {
        int j = -1;
        ss >> VARINT(j);
        BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
    }

    for (uint64_t i = 0;  i < 100000000000ULL; i += 999999937) {
        uint64_t j = -1;
        ss >> VARINT(j);
        BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
    }
}

BOOST_AUTO_TEST_CASE(compactsize)
{
    CDataStream ss(SER_DISK, 0);
    vector<char>::size_type i, j;

    for (i = 1; i <= MAX_SIZE; i *= 2)
    {
        WriteCompactSize(ss, i-1);
        WriteCompactSize(ss, i);
    }
    for (i = 1; i <= MAX_SIZE; i *= 2)
    {
        j = ReadCompactSize(ss);
        BOOST_CHECK_MESSAGE((i-1) == j, "decoded:" << j << " expected:" << (i-1));
        j = ReadCompactSize(ss);
        BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i);
    }
}

static bool isCanonicalException(const std::ios_base::failure& ex)
{
    std::string strExplanatoryString("non-canonical ReadCompactSize()");

    return strExplanatoryString == ex.what() ||
           // OSX Apple LLVM version 5.0 (OSX 10.9)
           strExplanatoryString + ": unspecified iostream_category error" == ex.what();
}

BOOST_AUTO_TEST_CASE(noncanonical)
{
    // Write some non-canonical CompactSize encodings, and
    // make sure an exception is thrown when read back.
    CDataStream ss(SER_DISK, 0);
    vector<char>::size_type n;

    // zero encoded with three bytes:
    ss.write("\xfd\x00\x00", 3);
    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);

    // 0xfc encoded with three bytes:
    ss.write("\xfd\xfc\x00", 3);
    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);

    // 0xfd encoded with three bytes is OK:
    ss.write("\xfd\xfd\x00", 3);
    n = ReadCompactSize(ss);
    BOOST_CHECK(n == 0xfd);

    // zero encoded with five bytes:
    ss.write("\xfe\x00\x00\x00\x00", 5);
    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);

    // 0xffff encoded with five bytes:
    ss.write("\xfe\xff\xff\x00\x00", 5);
    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);

    // zero encoded with nine bytes:
    ss.write("\xff\x00\x00\x00\x00\x00\x00\x00\x00", 9);
    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);

    // 0x01ffffff encoded with nine bytes:
    ss.write("\xff\xff\xff\xff\x01\x00\x00\x00\x00", 9);
    BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException);
}

BOOST_AUTO_TEST_CASE(insert_delete)
{
    // Test inserting/deleting bytes.
    CDataStream ss(SER_DISK, 0);
    BOOST_CHECK_EQUAL(ss.size(), 0);

    ss.write("\x00\x01\x02\xff", 4);
    BOOST_CHECK_EQUAL(ss.size(), 4);

    char c = (char)11;

    // Inserting at beginning/end/middle:
    ss.insert(ss.begin(), c);
    BOOST_CHECK_EQUAL(ss.size(), 5);
    BOOST_CHECK_EQUAL(ss[0], c);
    BOOST_CHECK_EQUAL(ss[1], 0);

    ss.insert(ss.end(), c);
    BOOST_CHECK_EQUAL(ss.size(), 6);
    BOOST_CHECK_EQUAL(ss[4], (char)0xff);
    BOOST_CHECK_EQUAL(ss[5], c);

    ss.insert(ss.begin()+2, c);
    BOOST_CHECK_EQUAL(ss.size(), 7);
    BOOST_CHECK_EQUAL(ss[2], c);

    // Delete at beginning/end/middle
    ss.erase(ss.begin());
    BOOST_CHECK_EQUAL(ss.size(), 6);
    BOOST_CHECK_EQUAL(ss[0], 0);

    ss.erase(ss.begin()+ss.size()-1);
    BOOST_CHECK_EQUAL(ss.size(), 5);
    BOOST_CHECK_EQUAL(ss[4], (char)0xff);

    ss.erase(ss.begin()+1);
    BOOST_CHECK_EQUAL(ss.size(), 4);
    BOOST_CHECK_EQUAL(ss[0], 0);
    BOOST_CHECK_EQUAL(ss[1], 1);
    BOOST_CHECK_EQUAL(ss[2], 2);
    BOOST_CHECK_EQUAL(ss[3], (char)0xff);

    // Make sure GetAndClear does the right thing:
    CSerializeData d;
    ss.GetAndClear(d);
    BOOST_CHECK_EQUAL(ss.size(), 0);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>//
//  Bitplanes.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 26/11/2021.
//  Copyright © 2021 Thomas Harte. All rights reserved.
//

#include "Bitplanes.hpp"
#include "Chipset.hpp"

using namespace Amiga;

namespace {

/// Expands @c source so that b7 is the least-significant bit of the most-significant byte of the result,
/// b6 is the least-significant bit of the next most significant byte, etc. b0 stays in place.
constexpr uint64_t expand_bitplane_byte(uint8_t source) {
	uint64_t result = source;									// 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 abcd efgh
	result = (result | (result << 28)) & 0x0000'000f'0000'000f;	// 0000 0000 0000 0000 0000 0000 0000 abcd 0000 0000 0000 0000 0000 0000 0000 efgh
	result = (result | (result << 14)) & 0x0003'0003'0003'0003;	// 0000 0000 0000 00ab 0000 0000 0000 00cd 0000 0000 0000 00ef 0000 0000 0000 00gh
	result = (result | (result << 7)) & 0x0101'0101'0101'0101;	// 0000 000a 0000 000b 0000 000c 0000 000d 0000 000e 0000 000f 0000 000g 0000 000h
	return result;
}

// A very small selection of test cases.
static_assert(expand_bitplane_byte(0xff) == 0x01'01'01'01'01'01'01'01);
static_assert(expand_bitplane_byte(0x55) == 0x00'01'00'01'00'01'00'01);
static_assert(expand_bitplane_byte(0xaa) == 0x01'00'01'00'01'00'01'00);
static_assert(expand_bitplane_byte(0x00) == 0x00'00'00'00'00'00'00'00);

}

// MARK: - Bitplanes.

bool Bitplanes::advance_dma(int cycle) {
#define BIND_CYCLE(offset, plane)								\
	case offset:												\
		if(plane_count_ > plane) {								\
			next[plane] = ram_[pointer_[plane] & ram_mask_];	\
			++pointer_[plane];									\
			if constexpr (!plane) {								\
				chipset_.post_bitplanes(next);					\
			}													\
			return true;										\
		}														\
	return false;

	if(is_high_res_) {
		switch(cycle&3) {
			default: return false;
			BIND_CYCLE(0, 3);
			BIND_CYCLE(1, 1);
			BIND_CYCLE(2, 2);
			BIND_CYCLE(3, 0);
		}
	} else {
		switch(cycle&7) {
			default: return false;
			/* Omitted: 0. */
			BIND_CYCLE(1, 3);
			BIND_CYCLE(2, 5);
			BIND_CYCLE(3, 1);
			/* Omitted: 4. */
			BIND_CYCLE(5, 2);
			BIND_CYCLE(6, 4);
			BIND_CYCLE(7, 0);
		}
	}

	return false;

#undef BIND_CYCLE
}

void Bitplanes::do_end_of_line() {
	// Apply modulos here. Posssibly correct?
	pointer_[0] += modulos_[1];
	pointer_[2] += modulos_[1];
	pointer_[4] += modulos_[1];

	pointer_[1] += modulos_[0];
	pointer_[3] += modulos_[0];
	pointer_[5] += modulos_[0];
}

void Bitplanes::set_control(uint16_t control) {
	is_high_res_ = control & 0x8000;
	plane_count_ = (control >> 12) & 7;

	// TODO: who really has responsibility for clearing the other
	// bit plane fields?
	std::fill(next.begin() + plane_count_, next.end(), 0);
	if(plane_count_ == 7) {
		plane_count_ = 4;
	}
}

// MARK: - BitplaneShifter

void BitplaneShifter::set(const BitplaneData &previous, const BitplaneData &next, int odd_delay, int even_delay) {
	const uint16_t planes[6] = {
		uint16_t(((previous[0] << 16) | next[0]) >> even_delay),
		uint16_t(((previous[1] << 16) | next[1]) >> odd_delay),
		uint16_t(((previous[2] << 16) | next[2]) >> even_delay),
		uint16_t(((previous[3] << 16) | next[3]) >> odd_delay),
		uint16_t(((previous[4] << 16) | next[4]) >> even_delay),
		uint16_t(((previous[5] << 16) | next[5]) >> odd_delay),
	};

	// Swizzle bits into the form:
	//
	//	[b5 b3 b1 b4 b2 b0]
	//
	// ... and assume a suitably adjusted palette is in use elsewhere.
	// This makes dual playfields very easy to separate.
	data_[0] =
		(expand_bitplane_byte(uint8_t(planes[0])) << 0) |
		(expand_bitplane_byte(uint8_t(planes[2])) << 1) |
		(expand_bitplane_byte(uint8_t(planes[4])) << 2) |
		(expand_bitplane_byte(uint8_t(planes[1])) << 3) |
		(expand_bitplane_byte(uint8_t(planes[3])) << 4) |
		(expand_bitplane_byte(uint8_t(planes[5])) << 5);

	data_[1] =
		(expand_bitplane_byte(uint8_t(planes[0] >> 8)) << 0) |
		(expand_bitplane_byte(uint8_t(planes[2] >> 8)) << 1) |
		(expand_bitplane_byte(uint8_t(planes[4] >> 8)) << 2) |
		(expand_bitplane_byte(uint8_t(planes[1] >> 8)) << 3) |
		(expand_bitplane_byte(uint8_t(planes[3] >> 8)) << 4) |
		(expand_bitplane_byte(uint8_t(planes[5] >> 8)) << 5);
}
<commit_msg>Move BitplaneShifter adjacent to `expand_bitplane_byte`.<commit_after>//
//  Bitplanes.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 26/11/2021.
//  Copyright © 2021 Thomas Harte. All rights reserved.
//

#include "Bitplanes.hpp"
#include "Chipset.hpp"

using namespace Amiga;

namespace {

/// Expands @c source so that b7 is the least-significant bit of the most-significant byte of the result,
/// b6 is the least-significant bit of the next most significant byte, etc. b0 stays in place.
constexpr uint64_t expand_bitplane_byte(uint8_t source) {
	uint64_t result = source;									// 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 abcd efgh
	result = (result | (result << 28)) & 0x0000'000f'0000'000f;	// 0000 0000 0000 0000 0000 0000 0000 abcd 0000 0000 0000 0000 0000 0000 0000 efgh
	result = (result | (result << 14)) & 0x0003'0003'0003'0003;	// 0000 0000 0000 00ab 0000 0000 0000 00cd 0000 0000 0000 00ef 0000 0000 0000 00gh
	result = (result | (result << 7)) & 0x0101'0101'0101'0101;	// 0000 000a 0000 000b 0000 000c 0000 000d 0000 000e 0000 000f 0000 000g 0000 000h
	return result;
}

// A very small selection of test cases.
static_assert(expand_bitplane_byte(0xff) == 0x01'01'01'01'01'01'01'01);
static_assert(expand_bitplane_byte(0x55) == 0x00'01'00'01'00'01'00'01);
static_assert(expand_bitplane_byte(0xaa) == 0x01'00'01'00'01'00'01'00);
static_assert(expand_bitplane_byte(0x00) == 0x00'00'00'00'00'00'00'00);

}

// MARK: - BitplaneShifter.

void BitplaneShifter::set(const BitplaneData &previous, const BitplaneData &next, int odd_delay, int even_delay) {
	const uint16_t planes[6] = {
		uint16_t(((previous[0] << 16) | next[0]) >> even_delay),
		uint16_t(((previous[1] << 16) | next[1]) >> odd_delay),
		uint16_t(((previous[2] << 16) | next[2]) >> even_delay),
		uint16_t(((previous[3] << 16) | next[3]) >> odd_delay),
		uint16_t(((previous[4] << 16) | next[4]) >> even_delay),
		uint16_t(((previous[5] << 16) | next[5]) >> odd_delay),
	};

	// Swizzle bits into the form:
	//
	//	[b5 b3 b1 b4 b2 b0]
	//
	// ... and assume a suitably adjusted palette is in use elsewhere.
	// This makes dual playfields very easy to separate.
	data_[0] =
		(expand_bitplane_byte(uint8_t(planes[0])) << 0) |
		(expand_bitplane_byte(uint8_t(planes[2])) << 1) |
		(expand_bitplane_byte(uint8_t(planes[4])) << 2) |
		(expand_bitplane_byte(uint8_t(planes[1])) << 3) |
		(expand_bitplane_byte(uint8_t(planes[3])) << 4) |
		(expand_bitplane_byte(uint8_t(planes[5])) << 5);

	data_[1] =
		(expand_bitplane_byte(uint8_t(planes[0] >> 8)) << 0) |
		(expand_bitplane_byte(uint8_t(planes[2] >> 8)) << 1) |
		(expand_bitplane_byte(uint8_t(planes[4] >> 8)) << 2) |
		(expand_bitplane_byte(uint8_t(planes[1] >> 8)) << 3) |
		(expand_bitplane_byte(uint8_t(planes[3] >> 8)) << 4) |
		(expand_bitplane_byte(uint8_t(planes[5] >> 8)) << 5);
}

// MARK: - Bitplanes.

bool Bitplanes::advance_dma(int cycle) {
#define BIND_CYCLE(offset, plane)								\
	case offset:												\
		if(plane_count_ > plane) {								\
			next[plane] = ram_[pointer_[plane] & ram_mask_];	\
			++pointer_[plane];									\
			if constexpr (!plane) {								\
				chipset_.post_bitplanes(next);					\
			}													\
			return true;										\
		}														\
	return false;

	if(is_high_res_) {
		switch(cycle&3) {
			default: return false;
			BIND_CYCLE(0, 3);
			BIND_CYCLE(1, 1);
			BIND_CYCLE(2, 2);
			BIND_CYCLE(3, 0);
		}
	} else {
		switch(cycle&7) {
			default: return false;
			/* Omitted: 0. */
			BIND_CYCLE(1, 3);
			BIND_CYCLE(2, 5);
			BIND_CYCLE(3, 1);
			/* Omitted: 4. */
			BIND_CYCLE(5, 2);
			BIND_CYCLE(6, 4);
			BIND_CYCLE(7, 0);
		}
	}

	return false;

#undef BIND_CYCLE
}

void Bitplanes::do_end_of_line() {
	// Apply modulos here. Posssibly correct?
	pointer_[0] += modulos_[1];
	pointer_[2] += modulos_[1];
	pointer_[4] += modulos_[1];

	pointer_[1] += modulos_[0];
	pointer_[3] += modulos_[0];
	pointer_[5] += modulos_[0];
}

void Bitplanes::set_control(uint16_t control) {
	is_high_res_ = control & 0x8000;
	plane_count_ = (control >> 12) & 7;

	// TODO: who really has responsibility for clearing the other
	// bit plane fields?
	std::fill(next.begin() + plane_count_, next.end(), 0);
	if(plane_count_ == 7) {
		plane_count_ = 4;
	}
}
<|endoftext|>


<commit_before>//
//  Dave.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 22/06/2021.
//  Copyright © 2021 Thomas Harte. All rights reserved.
//

#include "Dave.hpp"

using namespace Enterprise::Dave;

// MARK: - Audio generator

Audio::Audio(Concurrency::DeferringAsyncTaskQueue &audio_queue) :
	audio_queue_(audio_queue) {}

void Audio::write(uint16_t address, uint8_t value) {
	address &= 0x1f;
	audio_queue_.defer([address, value, this] {
		switch(address) {
			case 0:	case 2:	case 4:
				channels_[address >> 1].reload = (channels_[address >> 1].reload & 0xff00) | value;
			break;
			case 1:	case 3:	case 5:
				channels_[address >> 1].reload = uint16_t((channels_[address >> 1].reload & 0x00ff) | ((value & 0xf) << 8));
				channels_[address >> 1].distortion = Channel::Distortion((value >> 4)&3);
				channels_[address >> 1].high_pass = value & 0x40;
				channels_[address >> 1].ring_modulate = value & 0x80;
			break;
			case 6:
				noise_.frequency = Noise::Frequency(value&3);
				noise_.polynomial = Noise::Polynomial((value >> 2)&3);
				noise_.swap_polynomial = value & 0x10;
				noise_.low_pass = value & 0x20;
				noise_.high_pass = value & 0x40;
				noise_.ring_modulate = value & 0x80;
			break;

			case 7:
				channels_[0].sync = value & 0x01;
				channels_[1].sync = value & 0x02;
				channels_[2].sync = value & 0x04;
				use_direct_output_[0] = value & 0x08;
				use_direct_output_[1] = value & 0x10;
				// Interrupt bits are handled separately.
			break;

			case 8: case 9: case 10:
				channels_[address - 8].amplitude[0] = value & 0x3f;
			break;
			case 12: case 13: case 14:
				channels_[address - 12].amplitude[1] = value & 0x3f;
			break;
			case 11:	noise_.amplitude[0] = value & 0x3f;		break;
			case 15:	noise_.amplitude[1] = value & 0x3f;		break;

			case 31:
				global_divider_reload_ = 2 + ((value >> 1)&1);
			break;
		}
	});
}

void Audio::set_sample_volume_range(int16_t range) {
	audio_queue_.defer([range, this] {
		volume_ = range / (63*4);
	});
}

void Audio::update_channel(int c) {
	if(channels_[c].sync) {
		channels_[c].count = channels_[c].reload;
		channels_[c].output <<= 1;
		return;
	}

	auto output = channels_[c].output & 1;
	channels_[c].output <<= 1;
	if(!channels_[c].count) {
		channels_[c].count = channels_[c].reload;

		if(channels_[c].distortion == Channel::Distortion::None)
			output ^= 1;
		else
			output = poly_state_[int(channels_[c].distortion)];

		if(channels_[c].high_pass && (channels_[(c+1)%3].output&3) == 2) {
			output = 0;
		}
		if(channels_[c].ring_modulate) {
			output = ~(output ^ channels_[(c+2)%3].output) & 1;
		}
	} else {
		--channels_[c].count;
	}

	channels_[c].output |= output;
}

void Audio::get_samples(std::size_t number_of_samples, int16_t *target) {
	int16_t output_level[2];
	size_t c = 0;
	while(c < number_of_samples) {
		// I'm unclear on the details of the time division multiplexing so,
		// for now, just sum the outputs.
		output_level[0] =
			volume_ *
				(use_direct_output_[0] ?
					channels_[0].amplitude[0]
					: (
						channels_[0].amplitude[0] * (channels_[0].output & 1) +
						channels_[1].amplitude[0] * (channels_[1].output & 1) +
						channels_[2].amplitude[0] * (channels_[2].output & 1) +
						noise_.amplitude[0] * noise_.final_output
				));

		output_level[1] =
			volume_ *
				(use_direct_output_[1] ?
					channels_[0].amplitude[1]
					: (
						channels_[0].amplitude[1] * (channels_[0].output & 1) +
						channels_[1].amplitude[1] * (channels_[1].output & 1) +
						channels_[2].amplitude[1] * (channels_[2].output & 1) +
						noise_.amplitude[1] * noise_.final_output
				));

		while(global_divider_ && c < number_of_samples) {
			--global_divider_;
			*reinterpret_cast<uint32_t *>(&target[c << 1]) = *reinterpret_cast<uint32_t *>(output_level);
			++c;
		}

		global_divider_ = global_divider_reload_;
		if(!global_divider_) {
			global_divider_ = global_divider_reload_;
		}
		poly_state_[int(Channel::Distortion::FourBit)] = poly4_.next();
		poly_state_[int(Channel::Distortion::FiveBit)] = poly5_.next();
		poly_state_[int(Channel::Distortion::SevenBit)] = poly7_.next();
		if(noise_.swap_polynomial) {
			poly_state_[int(Channel::Distortion::SevenBit)] = poly_state_[int(Channel::Distortion::None)];
		}

		// Update tone channels.
		update_channel(0);
		update_channel(1);
		update_channel(2);

		// Update noise channel.

		// Step 1: decide whether there is a tick to apply.
		bool noise_tick = false;
		if(noise_.frequency == Noise::Frequency::DivideByFour) {
			if(!noise_.count) {
				noise_tick = true;
				noise_.count = 3;
			} else {
				--noise_.count;
			}
		} else {
			noise_tick = (channels_[int(noise_.frequency) - 1].output&3) == 2;
		}

		// Step 2: tick if necessary.
		int noise_output = noise_.output & 1;
		noise_.output <<= 1;
		if(noise_tick) {
			switch(noise_.polynomial) {
				case Noise::Polynomial::SeventeenBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly17_.next());
				break;
				case Noise::Polynomial::FifteenBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly15_.next());
				break;
				case Noise::Polynomial::ElevenBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly11_.next());
				break;
				case Noise::Polynomial::NineBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly9_.next());
				break;
			}

			noise_output = poly_state_[int(Channel::Distortion::None)];
		}
		noise_.output |= noise_output;

		// Low pass: sample channel 2 on downward transitions of the prima facie output.
		if(noise_.low_pass && (noise_.output & 3) == 2) {
			noise_.output = (noise_.output & ~1) | (channels_[2].output & 1);
		}

		// Apply noise high-pass.
		if(noise_.high_pass && (channels_[0].output & 3) == 2) {
			noise_.output &= ~1;
		}

		// Update noise ring modulation, if any.
		if(noise_.ring_modulate) {
			noise_.final_output = !((noise_.output ^ channels_[1].output) & 1);
		} else {
			noise_.final_output = noise_.output & 1;
		}
	}
}

// MARK: - Interrupt source

uint8_t TimedInterruptSource::get_new_interrupts() {
	const uint8_t result = interrupts_;
	interrupts_ = 0;
	return result;
}

void TimedInterruptSource::write(uint16_t address, uint8_t value) {
	address &= 0x1f;
	switch(address) {
		default: break;

		case 0: case 2:
			channels_[address >> 1].reload = (channels_[address >> 1].reload & 0xff00) | value;
		break;
		case 1:	case 3:
			channels_[address >> 1].reload = uint16_t((channels_[address >> 1].reload & 0x00ff) | ((value & 0xf) << 8));
		break;

		case 7:
			channels_[0].sync = value & 0x01;
			channels_[1].sync = value & 0x02;
			rate_ = InterruptRate((value >> 5) & 3);
		break;

		case 31:
			global_divider_ = Cycles(2 + ((value >> 1)&1));
		break;
	}
}

void TimedInterruptSource::update_channel(int c, bool is_linked, int decrement) {
	if(channels_[c].sync) {
		channels_[c].value = channels_[c].reload;
	} else {
		if(decrement <= channels_[c].value) {
			channels_[c].value -= decrement;
		} else {
			// The decrement is greater than the current value, therefore
			// there'll be at least one flip.
			//
			// After decreasing the decrement by the current value + 1,
			// it'll be clear how many decrements are left after reload.
			//
			// Dividing that by the number of decrements necessary for a
			// flip will provide the total number of flips.
			const int decrements_after_flip = decrement - (channels_[c].value + 1);
			const int num_flips = 1 + decrements_after_flip / (channels_[c].reload + 1);

			// If this is a linked channel, set the interrupt mask if a transition
			// from high to low is amongst the included flips.
			if(is_linked && num_flips + channels_[c].level >= 2) {
				interrupts_ |= uint8_t(Interrupt::VariableFrequency);
				programmable_level_ ^= true;
			}
			channels_[c].level ^= (num_flips & 1);

			// Apply the modulo number of decrements to the reload value to
			// figure out where things stand now.
			channels_[c].value = channels_[c].reload - decrements_after_flip % (channels_[c].reload + 1);
		}
	}
}

void TimedInterruptSource::run_for(Cycles duration) {
	// Determine total number of ticks.
	run_length_ += duration;
	const Cycles cycles = run_length_.divide(global_divider_);
	if(cycles == Cycles(0)) {
		return;
	}

	// Update the two-second counter, from which the 1Hz, 50Hz and 1000Hz signals
	// are derived.
	const int previous_counter = two_second_counter_;
	two_second_counter_ = (two_second_counter_ + cycles.as<int>()) % 500'000;

	// Check for a 1Hz rollover.
	if(previous_counter / 250'000 != two_second_counter_ / 250'000) {
		interrupts_ |= uint8_t(Interrupt::OneHz);
	}

	// Check for 1kHz or 50Hz rollover;
	switch(rate_) {
		default: break;
		case InterruptRate::OnekHz:
			if(previous_counter / 250 != two_second_counter_ / 250) {
				interrupts_ |= uint8_t(Interrupt::VariableFrequency);
				programmable_level_ ^= true;
			}
		break;
		case InterruptRate::FiftyHz:
			if(previous_counter / 5'000 != two_second_counter_ / 5'000) {
				interrupts_ |= uint8_t(Interrupt::VariableFrequency);
				programmable_level_ ^= true;
			}
		break;
	}

	// Update the two tone channels.
	update_channel(0, rate_ == InterruptRate::ToneGenerator0, cycles.as<int>());
	update_channel(1, rate_ == InterruptRate::ToneGenerator1, cycles.as<int>());
}

Cycles TimedInterruptSource::get_next_sequence_point() const {
	switch(rate_) {
		default:
		case InterruptRate::OnekHz:		return Cycles(250 - (two_second_counter_ % 250));
		case InterruptRate::FiftyHz:	return Cycles(5000 - (two_second_counter_ % 5000));

		case InterruptRate::ToneGenerator0:
		case InterruptRate::ToneGenerator1: {
			const auto &channel = channels_[int(rate_) - int(InterruptRate::ToneGenerator0)];
			const int cycles_until_interrupt = channel.value + 1 + (!channel.level) * (channel.reload + 1);

			int result = 250'000 - (two_second_counter_ % 250'000);
			return Cycles(std::min(result, cycles_until_interrupt));
		}
	}
}

uint8_t TimedInterruptSource::get_divider_state() {
	// one_hz_offset_ counts downwards, so when it crosses the halfway mark
	// it enters the high part of its wave.
	return
		(two_second_counter_ < 250'000 ? 0x4 : 0x0) |
		(programmable_level_ ? 0x1 : 0x0);
}
<commit_msg>Minor cleanups.<commit_after>//
//  Dave.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 22/06/2021.
//  Copyright © 2021 Thomas Harte. All rights reserved.
//

#include "Dave.hpp"

using namespace Enterprise::Dave;

// MARK: - Audio generator

Audio::Audio(Concurrency::DeferringAsyncTaskQueue &audio_queue) :
	audio_queue_(audio_queue) {}

void Audio::write(uint16_t address, uint8_t value) {
	address &= 0x1f;
	audio_queue_.defer([address, value, this] {
		switch(address) {
			case 0:	case 2:	case 4:
				channels_[address >> 1].reload = (channels_[address >> 1].reload & 0xff00) | value;
			break;
			case 1:	case 3:	case 5:
				channels_[address >> 1].reload = uint16_t((channels_[address >> 1].reload & 0x00ff) | ((value & 0xf) << 8));
				channels_[address >> 1].distortion = Channel::Distortion((value >> 4)&3);
				channels_[address >> 1].high_pass = value & 0x40;
				channels_[address >> 1].ring_modulate = value & 0x80;
			break;
			case 6:
				noise_.frequency = Noise::Frequency(value&3);
				noise_.polynomial = Noise::Polynomial((value >> 2)&3);
				noise_.swap_polynomial = value & 0x10;
				noise_.low_pass = value & 0x20;
				noise_.high_pass = value & 0x40;
				noise_.ring_modulate = value & 0x80;
			break;

			case 7:
				channels_[0].sync = value & 0x01;
				channels_[1].sync = value & 0x02;
				channels_[2].sync = value & 0x04;
				use_direct_output_[0] = value & 0x08;
				use_direct_output_[1] = value & 0x10;
				// Interrupt bits are handled separately.
			break;

			case 8: case 9: case 10:
				channels_[address - 8].amplitude[0] = value & 0x3f;
			break;
			case 12: case 13: case 14:
				channels_[address - 12].amplitude[1] = value & 0x3f;
			break;
			case 11:	noise_.amplitude[0] = value & 0x3f;		break;
			case 15:	noise_.amplitude[1] = value & 0x3f;		break;

			case 31:
				global_divider_reload_ = 2 + ((value >> 1)&1);
			break;
		}
	});
}

void Audio::set_sample_volume_range(int16_t range) {
	audio_queue_.defer([range, this] {
		volume_ = range / (63*4);
	});
}

void Audio::update_channel(int c) {
	if(channels_[c].sync) {
		channels_[c].count = channels_[c].reload;
		channels_[c].output <<= 1;
		return;
	}

	auto output = channels_[c].output & 1;
	channels_[c].output <<= 1;
	if(!channels_[c].count) {
		channels_[c].count = channels_[c].reload;

		if(channels_[c].distortion == Channel::Distortion::None)
			output ^= 1;
		else
			output = poly_state_[int(channels_[c].distortion)];

		if(channels_[c].high_pass && (channels_[(c+1)%3].output&3) == 2) {
			output = 0;
		}
		if(channels_[c].ring_modulate) {
			output = ~(output ^ channels_[(c+2)%3].output) & 1;
		}
	} else {
		--channels_[c].count;
	}

	channels_[c].output |= output;
}

void Audio::get_samples(std::size_t number_of_samples, int16_t *target) {
	int16_t output_level[2];
	size_t c = 0;
	while(c < number_of_samples) {
		// I'm unclear on the details of the time division multiplexing so,
		// for now, just sum the outputs.
		output_level[0] =
			volume_ *
				(use_direct_output_[0] ?
					channels_[0].amplitude[0]
					: (
						channels_[0].amplitude[0] * (channels_[0].output & 1) +
						channels_[1].amplitude[0] * (channels_[1].output & 1) +
						channels_[2].amplitude[0] * (channels_[2].output & 1) +
						noise_.amplitude[0] * noise_.final_output
				));

		output_level[1] =
			volume_ *
				(use_direct_output_[1] ?
					channels_[0].amplitude[1]
					: (
						channels_[0].amplitude[1] * (channels_[0].output & 1) +
						channels_[1].amplitude[1] * (channels_[1].output & 1) +
						channels_[2].amplitude[1] * (channels_[2].output & 1) +
						noise_.amplitude[1] * noise_.final_output
				));

		while(global_divider_ && c < number_of_samples) {
			--global_divider_;
			*reinterpret_cast<uint32_t *>(&target[c << 1]) = *reinterpret_cast<uint32_t *>(output_level);
			++c;
		}

		global_divider_ = global_divider_reload_;
		if(!global_divider_) {
			global_divider_ = global_divider_reload_;
		}
		poly_state_[int(Channel::Distortion::FourBit)] = poly4_.next();
		poly_state_[int(Channel::Distortion::FiveBit)] = poly5_.next();
		poly_state_[int(Channel::Distortion::SevenBit)] = poly7_.next();
		if(noise_.swap_polynomial) {
			poly_state_[int(Channel::Distortion::SevenBit)] = poly_state_[int(Channel::Distortion::None)];
		}

		// Update tone channels.
		update_channel(0);
		update_channel(1);
		update_channel(2);

		// Update noise channel.

		// Step 1: decide whether there is a tick to apply.
		bool noise_tick = false;
		if(noise_.frequency == Noise::Frequency::DivideByFour) {
			if(!noise_.count) {
				noise_tick = true;
				noise_.count = 3;
			} else {
				--noise_.count;
			}
		} else {
			noise_tick = (channels_[int(noise_.frequency) - 1].output&3) == 2;
		}

		// Step 2: tick if necessary.
		int noise_output = noise_.output & 1;
		noise_.output <<= 1;
		if(noise_tick) {
			switch(noise_.polynomial) {
				case Noise::Polynomial::SeventeenBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly17_.next());
				break;
				case Noise::Polynomial::FifteenBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly15_.next());
				break;
				case Noise::Polynomial::ElevenBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly11_.next());
				break;
				case Noise::Polynomial::NineBit:
					poly_state_[int(Channel::Distortion::None)] = uint8_t(poly9_.next());
				break;
			}

			noise_output = poly_state_[int(Channel::Distortion::None)];
		}
		noise_.output |= noise_output;

		// Low pass: sample channel 2 on downward transitions of the prima facie output.
		if(noise_.low_pass && (noise_.output & 3) == 2) {
			noise_.output = (noise_.output & ~1) | (channels_[2].output & 1);
		}

		// Apply noise high-pass.
		if(noise_.high_pass && (channels_[0].output & 3) == 2) {
			noise_.output &= ~1;
		}

		// Update noise ring modulation, if any.
		if(noise_.ring_modulate) {
			noise_.final_output = !((noise_.output ^ channels_[1].output) & 1);
		} else {
			noise_.final_output = noise_.output & 1;
		}
	}
}

// MARK: - Interrupt source

uint8_t TimedInterruptSource::get_new_interrupts() {
	const uint8_t result = interrupts_;
	interrupts_ = 0;
	return result;
}

void TimedInterruptSource::write(uint16_t address, uint8_t value) {
	address &= 0x1f;
	switch(address) {
		default: break;

		case 0: case 2:
			channels_[address >> 1].reload = (channels_[address >> 1].reload & 0xff00) | value;
		break;
		case 1:	case 3:
			channels_[address >> 1].reload = uint16_t((channels_[address >> 1].reload & 0x00ff) | ((value & 0xf) << 8));
		break;

		case 7:
			channels_[0].sync = value & 0x01;
			channels_[1].sync = value & 0x02;
			rate_ = InterruptRate((value >> 5) & 3);
		break;

		case 31:
			global_divider_ = Cycles(2 + ((value >> 1)&1));
		break;
	}
}

void TimedInterruptSource::update_channel(int c, bool is_linked, int decrement) {
	if(channels_[c].sync) {
		channels_[c].value = channels_[c].reload;
	} else {
		if(decrement <= channels_[c].value) {
			channels_[c].value -= decrement;
		} else {
			// The decrement is greater than the current value, therefore
			// there'll be at least one flip.
			//
			// After decreasing the decrement by the current value + 1,
			// it'll be clear how many decrements are left after reload.
			//
			// Dividing that by the number of decrements necessary for a
			// flip will provide the total number of flips.
			const int decrements_after_flip = decrement - (channels_[c].value + 1);
			const int num_flips = 1 + decrements_after_flip / (channels_[c].reload + 1);

			// If this is a linked channel, set the interrupt mask if a transition
			// from high to low is amongst the included flips.
			if(is_linked && num_flips + channels_[c].level >= 2) {
				interrupts_ |= uint8_t(Interrupt::VariableFrequency);
				programmable_level_ ^= true;
			}
			channels_[c].level ^= (num_flips & 1);

			// Apply the modulo number of decrements to the reload value to
			// figure out where things stand now.
			channels_[c].value = channels_[c].reload - decrements_after_flip % (channels_[c].reload + 1);
		}
	}
}

void TimedInterruptSource::run_for(Cycles duration) {
	// Determine total number of ticks.
	run_length_ += duration;
	const Cycles cycles = run_length_.divide(global_divider_);
	if(cycles == Cycles(0)) {
		return;
	}

	// Update the two-second counter, from which the 1Hz, 50Hz and 1000Hz signals
	// are derived.
	const int previous_counter = two_second_counter_;
	two_second_counter_ = (two_second_counter_ + cycles.as<int>()) % 500'000;

	// Check for a 1Hz rollover.
	if(previous_counter / 250'000 != two_second_counter_ / 250'000) {
		interrupts_ |= uint8_t(Interrupt::OneHz);
	}

	// Check for 1kHz or 50Hz rollover;
	switch(rate_) {
		default: break;
		case InterruptRate::OnekHz:
			if(previous_counter / 250 != two_second_counter_ / 250) {
				interrupts_ |= uint8_t(Interrupt::VariableFrequency);
				programmable_level_ ^= true;
			}
		break;
		case InterruptRate::FiftyHz:
			if(previous_counter / 5'000 != two_second_counter_ / 5'000) {
				interrupts_ |= uint8_t(Interrupt::VariableFrequency);
				programmable_level_ ^= true;
			}
		break;
	}

	// Update the two tone channels.
	update_channel(0, rate_ == InterruptRate::ToneGenerator0, cycles.as<int>());
	update_channel(1, rate_ == InterruptRate::ToneGenerator1, cycles.as<int>());
}

Cycles TimedInterruptSource::get_next_sequence_point() const {
	// Since both the 1kHz and 50Hz timers are integer dividers of the 1Hz timer, there's no need
	// to factor that one in when determining the next sequence point for either of those.
	switch(rate_) {
		default:
		case InterruptRate::OnekHz:		return Cycles(250 - (two_second_counter_ % 250));
		case InterruptRate::FiftyHz:	return Cycles(5000 - (two_second_counter_ % 5000));

		case InterruptRate::ToneGenerator0:
		case InterruptRate::ToneGenerator1: {
			const auto &channel = channels_[int(rate_) - int(InterruptRate::ToneGenerator0)];
			const int cycles_until_interrupt = channel.value + 1 + (!channel.level) * (channel.reload + 1);

			int result = 250'000 - (two_second_counter_ % 250'000);
			return Cycles(std::min(result, cycles_until_interrupt));
		}
	}
}

uint8_t TimedInterruptSource::get_divider_state() {
	return uint8_t((two_second_counter_ / 250'000) * 4 | programmable_level_);
}
<|endoftext|>


<commit_before><commit_msg>Planning: fix code style<commit_after><|endoftext|>


<commit_before>#include "writer/verilog/array.h"

#include "iroha/i_design.h"
#include "iroha/insn_operands.h"
#include "iroha/resource_class.h"
#include "iroha/resource_params.h"
#include "writer/module_template.h"
#include "writer/verilog/embedded_modules.h"
#include "writer/verilog/insn_writer.h"
#include "writer/verilog/internal_sram.h"
#include "writer/verilog/module.h"
#include "writer/verilog/port.h"
#include "writer/verilog/port_set.h"
#include "writer/verilog/state.h"
#include "writer/verilog/table.h"

namespace iroha {
namespace writer {
namespace verilog {

ArrayResource::ArrayResource(const IResource &res, const Table &table)
    : Resource(res, table) {}

void ArrayResource::BuildResource() {
  auto *klass = res_.GetClass();
  if (resource::IsArray(*klass)) {
    IArray *array = res_.GetArray();
    if (array->IsExternal()) {
      BuildExternalSRAM();
    } else {
      BuildInternalSRAM();
    }
  }
}

void ArrayResource::BuildInsn(IInsn *insn, State *st) {
  auto *klass = res_.GetClass();
  if (resource::IsArray(*klass)) {
    BuildMemInsn(insn, st);
  }
}

void ArrayResource::BuildMemInsn(IInsn *insn, State *st) {
  const string &opr = insn->GetOperand();
  if (opr == operand::kSramReadData) {
    ostream &ws = tab_.InsnWireValueSectionStream();
    ws << "  assign " << InsnWriter::InsnOutputWireName(*insn, 0) << " = "
       << SigName("rdata") << ";\n";
  }

  static const char I[] = "          ";
  ostream &os = st->StateBodySectionStream();
  if (opr == "sram_read_address" || opr == "sram_write") {
    os << I << SigName("addr") << " <= "
       << InsnWriter::RegisterValue(*(insn->inputs_[0]), tab_.GetNames())
       << ";\n";
  }
  if (opr == "sram_write") {
    os << I << SigName("wdata") << " <= "
       << InsnWriter::RegisterValue(*(insn->inputs_[1]), tab_.GetNames())
       << ";\n";
  }
}

void ArrayResource::BuildExternalSRAM() {
  IArray *array = res_.GetArray();
  int data_width = array->GetDataType().GetWidth();
  AddPortToTop(SigName("addr"), true, false, array->GetAddressWidth());
  AddPortToTop(SigName("rdata"), false, false, data_width);
  AddPortToTop(SigName("wdata"), true, false, data_width);
  AddPortToTop(SigName("wdata_en"), true, false, 0);
  BuildSRAMWrite();
}

void ArrayResource::BuildInternalSRAM() {
  InternalSRAM *sram = tab_.GetEmbeddedModules()->RequestInternalSRAM(
      *tab_.GetModule(), *res_.GetArray(), 1);
  auto *ports = tab_.GetPortSet();
  ostream &es = tmpl_->GetStream(kEmbeddedInstanceSection);
  string name = sram->GetModuleName();
  string inst = name + "_inst_" + Util::Itoa(res_.GetId());
  es << "  " << name << " " << inst << "("
     << ".clk(" << ports->GetClk() << ")"
     << ", ." << sram->GetResetPinName() << "(" << ports->GetReset() << ")"
     << ", ." << sram->GetAddrPin(0) << "(" << SigName("addr") << ")"
     << ", ." << sram->GetRdataPin(0) << "(" << SigName("rdata") << ")"
     << ", ." << sram->GetWdataPin(0) << "(" << SigName("wdata") << ")"
     << ", ." << sram->GetWenPin(0) << "(" << SigName("wdata_en") << ")"
     << ");\n";
  ostream &rs = tab_.ResourceSectionStream();
  rs << "  reg " << sram->AddressWidthSpec() << SigName("addr") << ";\n"
     << "  wire " << sram->DataWidthSpec() << SigName("rdata") << ";\n"
     << "  reg " << sram->DataWidthSpec() << SigName("wdata") << ";\n"
     << "  reg " << SigName("wdata_en") << ";\n";
  BuildSRAMWrite();
}

void ArrayResource::BuildSRAMWrite() {
  map<IState *, IInsn *> callers;
  CollectResourceCallers("sram_write", &callers);
  ostream &fs = tab_.StateOutputSectionStream();
  fs << "      " << SigName("wdata_en") << " <= ";
  WriteStateUnion(callers, fs);
  fs << ";\n";
}

string ArrayResource::SigName(const string &sig) { return SigName(res_, sig); }

string ArrayResource::SigName(const IResource &res, const string &sig) {
  IArray *array = res.GetArray();
  string res_id;
  if (array != nullptr && array->IsExternal()) {
    string prefix = res.GetParams()->GetPortNamePrefix();
    if (!prefix.empty()) {
      res_id = "_" + prefix;
    }
  } else {
    res_id = Util::Itoa(res.GetId());
  }
  return "sram" + res_id + "_" + sig;
}

IArray *ArrayResource::GetArray() { return res_.GetArray(); }

}  // namespace verilog
}  // namespace writer
}  // namespace iroha
<commit_msg>Adjust address width.<commit_after>#include "writer/verilog/array.h"

#include "iroha/i_design.h"
#include "iroha/insn_operands.h"
#include "iroha/resource_class.h"
#include "iroha/resource_params.h"
#include "writer/module_template.h"
#include "writer/verilog/embedded_modules.h"
#include "writer/verilog/insn_writer.h"
#include "writer/verilog/internal_sram.h"
#include "writer/verilog/module.h"
#include "writer/verilog/port.h"
#include "writer/verilog/port_set.h"
#include "writer/verilog/state.h"
#include "writer/verilog/table.h"

namespace iroha {
namespace writer {
namespace verilog {

ArrayResource::ArrayResource(const IResource &res, const Table &table)
    : Resource(res, table) {}

void ArrayResource::BuildResource() {
  auto *klass = res_.GetClass();
  if (resource::IsArray(*klass)) {
    IArray *array = res_.GetArray();
    if (array->IsExternal()) {
      BuildExternalSRAM();
    } else {
      BuildInternalSRAM();
    }
  }
}

void ArrayResource::BuildInsn(IInsn *insn, State *st) {
  auto *klass = res_.GetClass();
  if (resource::IsArray(*klass)) {
    BuildMemInsn(insn, st);
  }
}

void ArrayResource::BuildMemInsn(IInsn *insn, State *st) {
  const string &opr = insn->GetOperand();
  if (opr == operand::kSramReadData) {
    ostream &ws = tab_.InsnWireValueSectionStream();
    ws << "  assign " << InsnWriter::InsnOutputWireName(*insn, 0) << " = "
       << SigName("rdata") << ";\n";
  }

  static const char I[] = "          ";
  ostream &os = st->StateBodySectionStream();
  if (opr == "sram_read_address" || opr == "sram_write") {
    IArray *array = res_.GetArray();
    os << I << SigName("addr") << " <= "
       << InsnWriter::RegisterValueWithConstWidth(
              *(insn->inputs_[0]), array->GetAddressWidth(), tab_.GetNames())
       << ";\n";
  }
  if (opr == "sram_write") {
    os << I << SigName("wdata") << " <= "
       << InsnWriter::RegisterValue(*(insn->inputs_[1]), tab_.GetNames())
       << ";\n";
  }
}

void ArrayResource::BuildExternalSRAM() {
  IArray *array = res_.GetArray();
  int data_width = array->GetDataType().GetWidth();
  AddPortToTop(SigName("addr"), true, false, array->GetAddressWidth());
  AddPortToTop(SigName("rdata"), false, false, data_width);
  AddPortToTop(SigName("wdata"), true, false, data_width);
  AddPortToTop(SigName("wdata_en"), true, false, 0);
  BuildSRAMWrite();
}

void ArrayResource::BuildInternalSRAM() {
  InternalSRAM *sram = tab_.GetEmbeddedModules()->RequestInternalSRAM(
      *tab_.GetModule(), *res_.GetArray(), 1);
  auto *ports = tab_.GetPortSet();
  ostream &es = tmpl_->GetStream(kEmbeddedInstanceSection);
  string name = sram->GetModuleName();
  string inst = name + "_inst_" + Util::Itoa(res_.GetId());
  es << "  " << name << " " << inst << "("
     << ".clk(" << ports->GetClk() << ")"
     << ", ." << sram->GetResetPinName() << "(" << ports->GetReset() << ")"
     << ", ." << sram->GetAddrPin(0) << "(" << SigName("addr") << ")"
     << ", ." << sram->GetRdataPin(0) << "(" << SigName("rdata") << ")"
     << ", ." << sram->GetWdataPin(0) << "(" << SigName("wdata") << ")"
     << ", ." << sram->GetWenPin(0) << "(" << SigName("wdata_en") << ")"
     << ");\n";
  ostream &rs = tab_.ResourceSectionStream();
  rs << "  reg " << sram->AddressWidthSpec() << SigName("addr") << ";\n"
     << "  wire " << sram->DataWidthSpec() << SigName("rdata") << ";\n"
     << "  reg " << sram->DataWidthSpec() << SigName("wdata") << ";\n"
     << "  reg " << SigName("wdata_en") << ";\n";
  BuildSRAMWrite();
}

void ArrayResource::BuildSRAMWrite() {
  map<IState *, IInsn *> callers;
  CollectResourceCallers("sram_write", &callers);
  ostream &fs = tab_.StateOutputSectionStream();
  fs << "      " << SigName("wdata_en") << " <= ";
  WriteStateUnion(callers, fs);
  fs << ";\n";
}

string ArrayResource::SigName(const string &sig) { return SigName(res_, sig); }

string ArrayResource::SigName(const IResource &res, const string &sig) {
  IArray *array = res.GetArray();
  string res_id;
  if (array != nullptr && array->IsExternal()) {
    string prefix = res.GetParams()->GetPortNamePrefix();
    if (!prefix.empty()) {
      res_id = "_" + prefix;
    }
  } else {
    res_id = Util::Itoa(res.GetId());
  }
  return "sram" + res_id + "_" + sig;
}

IArray *ArrayResource::GetArray() { return res_.GetArray(); }

}  // namespace verilog
}  // namespace writer
}  // namespace iroha
<|endoftext|>


<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/apu/xma_decoder.h"

#include <gflags/gflags.h>

#include "xenia/apu/xma_context.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/ring_buffer.h"
#include "xenia/base/string_buffer.h"
#include "xenia/cpu/processor.h"
#include "xenia/cpu/thread_state.h"
#include "xenia/kernel/objects/xthread.h"
#include "xenia/profiling.h"

extern "C" {
#include "third_party/libav/libavutil/log.h"
}  // extern "C"

// As with normal Microsoft, there are like twelve different ways to access
// the audio APIs. Early games use XMA*() methods almost exclusively to touch
// decoders. Later games use XAudio*() and direct memory writes to the XMA
// structures (as opposed to the XMA* calls), meaning that we have to support
// both.
//
// The XMA*() functions just manipulate the audio system in the guest context
// and let the normal XmaDecoder handling take it, to prevent duplicate
// implementations. They can be found in xboxkrnl_audio_xma.cc
//
// XMA details:
// https://devel.nuclex.org/external/svn/directx/trunk/include/xma2defs.h
// https://github.com/gdawg/fsbext/blob/master/src/xma_header.h
//
// XAudio2 uses XMA under the covers, and seems to map with the same
// restrictions of frame/subframe/etc:
// https://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.xaudio2.xaudio2_buffer(v=vs.85).aspx
//
// XMA contexts are 64b in size and tight bitfields. They are in physical
// memory not usually available to games. Games will use MmMapIoSpace to get
// the 64b pointer in user memory so they can party on it. If the game doesn't
// do this, it's likely they are either passing the context to XAudio or
// using the XMA* functions.

DEFINE_bool(libav_verbose, false, "Verbose libav output (debug and above)");

namespace xe {
namespace apu {

XmaDecoder::XmaDecoder(cpu::Processor* processor)
    : memory_(processor->memory()), processor_(processor) {}

XmaDecoder::~XmaDecoder() = default;

void av_log_callback(void* avcl, int level, const char* fmt, va_list va) {
  if (!FLAGS_libav_verbose && level > AV_LOG_WARNING) {
    return;
  }

  char level_char = '?';
  switch (level) {
    case AV_LOG_ERROR:
      level_char = '!';
      break;
    case AV_LOG_WARNING:
      level_char = 'w';
      break;
    case AV_LOG_INFO:
      level_char = 'i';
      break;
    case AV_LOG_VERBOSE:
      level_char = 'v';
      break;
    case AV_LOG_DEBUG:
      level_char = 'd';
      break;
  }

  StringBuffer buff;
  buff.AppendVarargs(fmt, va);
  xe::LogLineFormat(level_char, "libav: %s", buff.GetString());
}

X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
  // Setup libav logging callback
  av_log_set_callback(av_log_callback);

  // Let the processor know we want register access callbacks.
  memory_->AddVirtualMappedRange(
      0x7FEA0000, 0xFFFF0000, 0x0000FFFF, this,
      reinterpret_cast<cpu::MMIOReadCallback>(MMIOReadRegisterThunk),
      reinterpret_cast<cpu::MMIOWriteCallback>(MMIOWriteRegisterThunk));

  // Setup XMA context data.
  context_data_first_ptr_ = memory()->SystemHeapAlloc(
      sizeof(XMA_CONTEXT_DATA) * kContextCount, 256, kSystemHeapPhysical);
  context_data_last_ptr_ =
      context_data_first_ptr_ + (sizeof(XMA_CONTEXT_DATA) * kContextCount - 1);
  registers_.context_array_ptr = context_data_first_ptr_;

  // Setup XMA contexts.
  for (int i = 0; i < kContextCount; ++i) {
    uint32_t guest_ptr =
        registers_.context_array_ptr + i * sizeof(XMA_CONTEXT_DATA);
    XmaContext& context = contexts_[i];
    if (context.Setup(i, memory(), guest_ptr)) {
      assert_always();
    }
  }
  registers_.next_context = 1;

  worker_running_ = true;
  worker_thread_ = kernel::object_ref<kernel::XHostThread>(
      new kernel::XHostThread(kernel_state, 128 * 1024, 0, [this]() {
        WorkerThreadMain();
        return 0;
      }));
  worker_thread_->set_name("XMA Decoder Worker");
  worker_thread_->Create();

  return X_STATUS_SUCCESS;
}

void XmaDecoder::WorkerThreadMain() {
  while (worker_running_) {
    // Okay, let's loop through XMA contexts to find ones we need to decode!
    for (uint32_t n = 0; n < kContextCount; n++) {
      XmaContext& context = contexts_[n];
      context.Work();

      // TODO: Need thread safety to do this.
      // Probably not too important though.
      // registers_.current_context = n;
      // registers_.next_context = (n + 1) % kContextCount;
    }
  }
}

void XmaDecoder::Shutdown() {
  worker_running_ = false;
  worker_fence_.Signal();
  worker_thread_.reset();

  memory()->SystemHeapFree(registers_.context_array_ptr);
}

int XmaDecoder::GetContextId(uint32_t guest_ptr) {
  static_assert(sizeof(XMA_CONTEXT_DATA) == 64, "FIXME");
  if (guest_ptr < context_data_first_ptr_ ||
      guest_ptr > context_data_last_ptr_) {
    return -1;
  }
  assert_zero(guest_ptr & 0x3F);
  return (guest_ptr - context_data_first_ptr_) >> 6;
}

uint32_t XmaDecoder::AllocateContext() {
  std::lock_guard<xe::mutex> lock(lock_);

  for (uint32_t n = 0; n < kContextCount; n++) {
    XmaContext& context = contexts_[n];
    if (!context.is_allocated()) {
      context.set_is_allocated(true);
      return context.guest_ptr();
    }
  }

  return 0;
}

void XmaDecoder::ReleaseContext(uint32_t guest_ptr) {
  std::lock_guard<xe::mutex> lock(lock_);

  auto context_id = GetContextId(guest_ptr);
  assert_true(context_id >= 0);

  XmaContext& context = contexts_[context_id];
  context.Release();
}

bool XmaDecoder::BlockOnContext(uint32_t guest_ptr, bool poll) {
  std::lock_guard<xe::mutex> lock(lock_);

  auto context_id = GetContextId(guest_ptr);
  assert_true(context_id >= 0);

  XmaContext& context = contexts_[context_id];
  return context.Block(poll);
}

// free60 may be useful here, however it looks like it's using a different
// piece of hardware:
// https://github.com/Free60Project/libxenon/blob/master/libxenon/drivers/xenon_sound/sound.c

uint32_t XmaDecoder::ReadRegister(uint32_t addr) {
  uint32_t r = addr & 0xFFFF;
  XELOGAPU("ReadRegister(%.4X)", r);
  // 1800h is read on startup and stored -- context? buffers?
  // 1818h is read during a lock?

  assert_true(r % 4 == 0);
  uint32_t value = register_file_[r / 4];

  // 1818 is rotating context processing # set to hardware ID of context being
  // processed.
  // If bit 200h is set, the locking code will possibly collide on hardware IDs
  // and error out, so we should never set it (I think?).
  if (r == 0x1818) {
    // To prevent games from seeing a stuck XMA context, return a rotating
    // number
    registers_.current_context = registers_.next_context;
    registers_.next_context = (registers_.next_context + 1) % kContextCount;
  }

  value = xe::byte_swap(value);
  return value;
}

void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) {
  SCOPE_profile_cpu_f("apu");

  uint32_t r = addr & 0xFFFF;
  value = xe::byte_swap(value);
  XELOGAPU("WriteRegister(%.4X, %.8X)", r, value);
  // 1804h is written to with 0x02000000 and 0x03000000 around a lock operation

  assert_true(r % 4 == 0);
  register_file_[r / 4] = uint32_t(value);

  if (r >= 0x1940 && r <= 0x1940 + 9 * 4) {
    // Context kick command.
    // This will kick off the given hardware contexts.
    // Basically, this kicks the SPU and says "hey, decode that audio!"
    // XMAEnableContext

    // The context ID is a bit in the range of the entire context array.
    uint32_t base_context_id = (r - 0x1940) / 4 * 32;
    for (int i = 0; value && i < 32; ++i, value >>= 1) {
      if (value & 1) {
        uint32_t context_id = base_context_id + i;
        XmaContext& context = contexts_[context_id];
        context.Enable();
      }
    }

    // Signal the decoder thread to start processing.
    worker_fence_.Signal();
  } else if (r >= 0x1A40 && r <= 0x1A40 + 9 * 4) {
    // Context lock command.
    // This requests a lock by flagging the context.
    // XMADisableContext
    uint32_t base_context_id = (r - 0x1A40) / 4 * 32;
    for (int i = 0; value && i < 32; ++i, value >>= 1) {
      if (value & 1) {
        uint32_t context_id = base_context_id + i;
        XmaContext& context = contexts_[context_id];
        context.Disable();
      }
    }

    // Signal the decoder thread to start processing.
    worker_fence_.Signal();
  } else if (r >= 0x1A80 && r <= 0x1A80 + 9 * 4) {
    // Context clear command.
    // This will reset the given hardware contexts.
    uint32_t base_context_id = (r - 0x1A80) / 4 * 32;
    for (int i = 0; value && i < 32; ++i, value >>= 1) {
      if (value & 1) {
        uint32_t context_id = base_context_id + i;
        XmaContext& context = contexts_[context_id];
        context.Clear();
      }
    }
  }
}

}  // namespace apu
}  // namespace xe
<commit_msg>Adding a yield in the XMA decoder to give other threads some breathing room.<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/apu/xma_decoder.h"

#include <gflags/gflags.h>

#include "xenia/apu/xma_context.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/ring_buffer.h"
#include "xenia/base/string_buffer.h"
#include "xenia/cpu/processor.h"
#include "xenia/cpu/thread_state.h"
#include "xenia/kernel/objects/xthread.h"
#include "xenia/profiling.h"

extern "C" {
#include "third_party/libav/libavutil/log.h"
}  // extern "C"

// As with normal Microsoft, there are like twelve different ways to access
// the audio APIs. Early games use XMA*() methods almost exclusively to touch
// decoders. Later games use XAudio*() and direct memory writes to the XMA
// structures (as opposed to the XMA* calls), meaning that we have to support
// both.
//
// The XMA*() functions just manipulate the audio system in the guest context
// and let the normal XmaDecoder handling take it, to prevent duplicate
// implementations. They can be found in xboxkrnl_audio_xma.cc
//
// XMA details:
// https://devel.nuclex.org/external/svn/directx/trunk/include/xma2defs.h
// https://github.com/gdawg/fsbext/blob/master/src/xma_header.h
//
// XAudio2 uses XMA under the covers, and seems to map with the same
// restrictions of frame/subframe/etc:
// https://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.xaudio2.xaudio2_buffer(v=vs.85).aspx
//
// XMA contexts are 64b in size and tight bitfields. They are in physical
// memory not usually available to games. Games will use MmMapIoSpace to get
// the 64b pointer in user memory so they can party on it. If the game doesn't
// do this, it's likely they are either passing the context to XAudio or
// using the XMA* functions.

DEFINE_bool(libav_verbose, false, "Verbose libav output (debug and above)");

namespace xe {
namespace apu {

XmaDecoder::XmaDecoder(cpu::Processor* processor)
    : memory_(processor->memory()), processor_(processor) {}

XmaDecoder::~XmaDecoder() = default;

void av_log_callback(void* avcl, int level, const char* fmt, va_list va) {
  if (!FLAGS_libav_verbose && level > AV_LOG_WARNING) {
    return;
  }

  char level_char = '?';
  switch (level) {
    case AV_LOG_ERROR:
      level_char = '!';
      break;
    case AV_LOG_WARNING:
      level_char = 'w';
      break;
    case AV_LOG_INFO:
      level_char = 'i';
      break;
    case AV_LOG_VERBOSE:
      level_char = 'v';
      break;
    case AV_LOG_DEBUG:
      level_char = 'd';
      break;
  }

  StringBuffer buff;
  buff.AppendVarargs(fmt, va);
  xe::LogLineFormat(level_char, "libav: %s", buff.GetString());
}

X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
  // Setup libav logging callback
  av_log_set_callback(av_log_callback);

  // Let the processor know we want register access callbacks.
  memory_->AddVirtualMappedRange(
      0x7FEA0000, 0xFFFF0000, 0x0000FFFF, this,
      reinterpret_cast<cpu::MMIOReadCallback>(MMIOReadRegisterThunk),
      reinterpret_cast<cpu::MMIOWriteCallback>(MMIOWriteRegisterThunk));

  // Setup XMA context data.
  context_data_first_ptr_ = memory()->SystemHeapAlloc(
      sizeof(XMA_CONTEXT_DATA) * kContextCount, 256, kSystemHeapPhysical);
  context_data_last_ptr_ =
      context_data_first_ptr_ + (sizeof(XMA_CONTEXT_DATA) * kContextCount - 1);
  registers_.context_array_ptr = context_data_first_ptr_;

  // Setup XMA contexts.
  for (int i = 0; i < kContextCount; ++i) {
    uint32_t guest_ptr =
        registers_.context_array_ptr + i * sizeof(XMA_CONTEXT_DATA);
    XmaContext& context = contexts_[i];
    if (context.Setup(i, memory(), guest_ptr)) {
      assert_always();
    }
  }
  registers_.next_context = 1;

  worker_running_ = true;
  worker_thread_ = kernel::object_ref<kernel::XHostThread>(
      new kernel::XHostThread(kernel_state, 128 * 1024, 0, [this]() {
        WorkerThreadMain();
        return 0;
      }));
  worker_thread_->set_name("XMA Decoder Worker");
  worker_thread_->Create();

  return X_STATUS_SUCCESS;
}

void XmaDecoder::WorkerThreadMain() {
  while (worker_running_) {
    // Okay, let's loop through XMA contexts to find ones we need to decode!
    for (uint32_t n = 0; n < kContextCount; n++) {
      XmaContext& context = contexts_[n];
      context.Work();

      // TODO: Need thread safety to do this.
      // Probably not too important though.
      // registers_.current_context = n;
      // registers_.next_context = (n + 1) % kContextCount;
    }
    xe::threading::MaybeYield();
  }
}

void XmaDecoder::Shutdown() {
  worker_running_ = false;
  worker_fence_.Signal();
  worker_thread_.reset();

  memory()->SystemHeapFree(registers_.context_array_ptr);
}

int XmaDecoder::GetContextId(uint32_t guest_ptr) {
  static_assert(sizeof(XMA_CONTEXT_DATA) == 64, "FIXME");
  if (guest_ptr < context_data_first_ptr_ ||
      guest_ptr > context_data_last_ptr_) {
    return -1;
  }
  assert_zero(guest_ptr & 0x3F);
  return (guest_ptr - context_data_first_ptr_) >> 6;
}

uint32_t XmaDecoder::AllocateContext() {
  std::lock_guard<xe::mutex> lock(lock_);

  for (uint32_t n = 0; n < kContextCount; n++) {
    XmaContext& context = contexts_[n];
    if (!context.is_allocated()) {
      context.set_is_allocated(true);
      return context.guest_ptr();
    }
  }

  return 0;
}

void XmaDecoder::ReleaseContext(uint32_t guest_ptr) {
  std::lock_guard<xe::mutex> lock(lock_);

  auto context_id = GetContextId(guest_ptr);
  assert_true(context_id >= 0);

  XmaContext& context = contexts_[context_id];
  context.Release();
}

bool XmaDecoder::BlockOnContext(uint32_t guest_ptr, bool poll) {
  std::lock_guard<xe::mutex> lock(lock_);

  auto context_id = GetContextId(guest_ptr);
  assert_true(context_id >= 0);

  XmaContext& context = contexts_[context_id];
  return context.Block(poll);
}

// free60 may be useful here, however it looks like it's using a different
// piece of hardware:
// https://github.com/Free60Project/libxenon/blob/master/libxenon/drivers/xenon_sound/sound.c

uint32_t XmaDecoder::ReadRegister(uint32_t addr) {
  uint32_t r = addr & 0xFFFF;
  XELOGAPU("ReadRegister(%.4X)", r);
  // 1800h is read on startup and stored -- context? buffers?
  // 1818h is read during a lock?

  assert_true(r % 4 == 0);
  uint32_t value = register_file_[r / 4];

  // 1818 is rotating context processing # set to hardware ID of context being
  // processed.
  // If bit 200h is set, the locking code will possibly collide on hardware IDs
  // and error out, so we should never set it (I think?).
  if (r == 0x1818) {
    // To prevent games from seeing a stuck XMA context, return a rotating
    // number
    registers_.current_context = registers_.next_context;
    registers_.next_context = (registers_.next_context + 1) % kContextCount;
  }

  value = xe::byte_swap(value);
  return value;
}

void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) {
  SCOPE_profile_cpu_f("apu");

  uint32_t r = addr & 0xFFFF;
  value = xe::byte_swap(value);
  XELOGAPU("WriteRegister(%.4X, %.8X)", r, value);
  // 1804h is written to with 0x02000000 and 0x03000000 around a lock operation

  assert_true(r % 4 == 0);
  register_file_[r / 4] = uint32_t(value);

  if (r >= 0x1940 && r <= 0x1940 + 9 * 4) {
    // Context kick command.
    // This will kick off the given hardware contexts.
    // Basically, this kicks the SPU and says "hey, decode that audio!"
    // XMAEnableContext

    // The context ID is a bit in the range of the entire context array.
    uint32_t base_context_id = (r - 0x1940) / 4 * 32;
    for (int i = 0; value && i < 32; ++i, value >>= 1) {
      if (value & 1) {
        uint32_t context_id = base_context_id + i;
        XmaContext& context = contexts_[context_id];
        context.Enable();
      }
    }

    // Signal the decoder thread to start processing.
    worker_fence_.Signal();
  } else if (r >= 0x1A40 && r <= 0x1A40 + 9 * 4) {
    // Context lock command.
    // This requests a lock by flagging the context.
    // XMADisableContext
    uint32_t base_context_id = (r - 0x1A40) / 4 * 32;
    for (int i = 0; value && i < 32; ++i, value >>= 1) {
      if (value & 1) {
        uint32_t context_id = base_context_id + i;
        XmaContext& context = contexts_[context_id];
        context.Disable();
      }
    }

    // Signal the decoder thread to start processing.
    worker_fence_.Signal();
  } else if (r >= 0x1A80 && r <= 0x1A80 + 9 * 4) {
    // Context clear command.
    // This will reset the given hardware contexts.
    uint32_t base_context_id = (r - 0x1A80) / 4 * 32;
    for (int i = 0; value && i < 32; ++i, value >>= 1) {
      if (value & 1) {
        uint32_t context_id = base_context_id + i;
        XmaContext& context = contexts_[context_id];
        context.Clear();
      }
    }
  }
}

}  // namespace apu
}  // namespace xe
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: it_named.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 16:54:41 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef ARY_IDL_IT_NAMED_HXX
#define ARY_IDL_IT_NAMED_HXX

// USED SERVICES
    // BASE CLASSES
#include <ary/idl/i_type.hxx>
    // COMPONENTS
    // PARAMETERS

namespace ary
{
namespace idl
{

/** Represents types with a name - in opposite to e.g. sequences,
    which do not have one.
*/
class Named_Type : public Type
{
  public:
    // LIFECYCLE
    virtual             ~Named_Type()           {}

    // INQUIRY
    const String &      Name() const            { return sName; }

  protected:
                        Named_Type(
                            const String &      i_sName )
                                                : sName(i_sName) { }
  private:
    // DATA
    String              sName;
};

}   // namespace idl
}   // namespace ary

#endif

<commit_msg>INTEGRATION: CWS changefileheader (1.2.80); FILE MERGED 2008/03/28 16:01:48 rt 1.2.80.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: it_named.hxx,v $
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef ARY_IDL_IT_NAMED_HXX
#define ARY_IDL_IT_NAMED_HXX

// USED SERVICES
    // BASE CLASSES
#include <ary/idl/i_type.hxx>
    // COMPONENTS
    // PARAMETERS

namespace ary
{
namespace idl
{

/** Represents types with a name - in opposite to e.g. sequences,
    which do not have one.
*/
class Named_Type : public Type
{
  public:
    // LIFECYCLE
    virtual             ~Named_Type()           {}

    // INQUIRY
    const String &      Name() const            { return sName; }

  protected:
                        Named_Type(
                            const String &      i_sName )
                                                : sName(i_sName) { }
  private:
    // DATA
    String              sName;
};

}   // namespace idl
}   // namespace ary

#endif

<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "SolidPropertiesApp.h"
#include "Moose.h"
#include "AppFactory.h"
#include "MooseSyntax.h"

InputParameters
SolidPropertiesApp::validParams()
{
  InputParameters params = MooseApp::validParams();
  params.set<bool>("use_legacy_material_output") = false;
  return params;
}

registerKnownLabel("SolidPropertiesApp");

SolidPropertiesApp::SolidPropertiesApp(InputParameters parameters) : MooseApp(parameters)
{
  SolidPropertiesApp::registerAll(_factory, _action_factory, _syntax);
}

void
SolidPropertiesApp::registerApps()
{
  registerApp(SolidPropertiesApp);
}

static void
associateSyntaxInner(Syntax & syntax, ActionFactory & /*action_factory*/)
{
  registerSyntaxTask(
      "AddSolidPropertiesAction", "Modules/SolidProperties/*", "add_solid_properties");
  registerMooseObjectTask("add_solid_properties", SolidProperties, false);
  registerMooseObjectTask("add_sp_output", Output, false);

  syntax.addDependency("add_solid_properties", "init_displaced_problem");
  syntax.addDependency("add_aux_variable", "add_solid_properties");
  syntax.addDependency("add_variable", "add_solid_properties");
  syntax.addDependency("add_elemental_field_variable", "add_solid_properties");
  syntax.addDependency("add_external_aux_variables", "add_solid_properties");
  syntax.addDependency("add_sp_output", "add_output");
  syntax.addDependency("add_postprocessor", "add_sp_output");
}

void
SolidPropertiesApp::registerAll(Factory & f, ActionFactory & af, Syntax & s)
{
  Registry::registerObjectsTo(f, {"SolidPropertiesApp"});
  Registry::registerActionsTo(af, {"SolidPropertiesApp"});
  associateSyntaxInner(s, af);
}

void
SolidPropertiesApp::registerObjects(Factory & factory)
{
  mooseDeprecated("use registerAll instead of registerObjects");
  Registry::registerObjectsTo(factory, {"SolidPropertiesApp"});
}

void
SolidPropertiesApp::associateSyntax(Syntax & syntax, ActionFactory & action_factory)
{
  mooseDeprecated("use registerAll instead of associateSyntax");
  Registry::registerActionsTo(action_factory, {"SolidPropertiesApp"});
  associateSyntaxInner(syntax, action_factory);
}

void
SolidPropertiesApp::registerExecFlags(Factory & /*factory*/)
{
  mooseDeprecated("use registerAll instead of registerExecFlags");
}

extern "C" void
SolidPropertiesApp__registerAll(Factory & f, ActionFactory & af, Syntax & s)
{
  SolidPropertiesApp::registerAll(f, af, s);
}
extern "C" void
SolidPropertiesApp__registerApps()
{
  SolidPropertiesApp::registerApps();
}
<commit_msg>Deleted add_sp_output task since it is not used<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "SolidPropertiesApp.h"
#include "Moose.h"
#include "AppFactory.h"
#include "MooseSyntax.h"

InputParameters
SolidPropertiesApp::validParams()
{
  InputParameters params = MooseApp::validParams();
  params.set<bool>("use_legacy_material_output") = false;
  return params;
}

registerKnownLabel("SolidPropertiesApp");

SolidPropertiesApp::SolidPropertiesApp(InputParameters parameters) : MooseApp(parameters)
{
  SolidPropertiesApp::registerAll(_factory, _action_factory, _syntax);
}

void
SolidPropertiesApp::registerApps()
{
  registerApp(SolidPropertiesApp);
}

static void
associateSyntaxInner(Syntax & syntax, ActionFactory & /*action_factory*/)
{
  registerSyntaxTask(
      "AddSolidPropertiesAction", "Modules/SolidProperties/*", "add_solid_properties");
  registerMooseObjectTask("add_solid_properties", SolidProperties, false);

  syntax.addDependency("add_solid_properties", "init_displaced_problem");
  syntax.addDependency("add_aux_variable", "add_solid_properties");
  syntax.addDependency("add_variable", "add_solid_properties");
  syntax.addDependency("add_elemental_field_variable", "add_solid_properties");
  syntax.addDependency("add_external_aux_variables", "add_solid_properties");
}

void
SolidPropertiesApp::registerAll(Factory & f, ActionFactory & af, Syntax & s)
{
  Registry::registerObjectsTo(f, {"SolidPropertiesApp"});
  Registry::registerActionsTo(af, {"SolidPropertiesApp"});
  associateSyntaxInner(s, af);
}

void
SolidPropertiesApp::registerObjects(Factory & factory)
{
  mooseDeprecated("use registerAll instead of registerObjects");
  Registry::registerObjectsTo(factory, {"SolidPropertiesApp"});
}

void
SolidPropertiesApp::associateSyntax(Syntax & syntax, ActionFactory & action_factory)
{
  mooseDeprecated("use registerAll instead of associateSyntax");
  Registry::registerActionsTo(action_factory, {"SolidPropertiesApp"});
  associateSyntaxInner(syntax, action_factory);
}

void
SolidPropertiesApp::registerExecFlags(Factory & /*factory*/)
{
  mooseDeprecated("use registerAll instead of registerExecFlags");
}

extern "C" void
SolidPropertiesApp__registerAll(Factory & f, ActionFactory & af, Syntax & s)
{
  SolidPropertiesApp::registerAll(f, af, s);
}
extern "C" void
SolidPropertiesApp__registerApps()
{
  SolidPropertiesApp::registerApps();
}
<|endoftext|>


<commit_before>//===--- RISCV.cpp - Implement RISCV target feature support ---------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements RISCV TargetInfo objects.
//
//===----------------------------------------------------------------------===//

#include "RISCV.h"
#include "clang/Basic/MacroBuilder.h"
#include "llvm/ADT/StringSwitch.h"

using namespace clang;
using namespace clang::targets;

ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const {
  static const char *const GCCRegNames[] = {
      "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
      "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
      "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
      "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31"};
  return llvm::makeArrayRef(GCCRegNames);
}

ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const {
  static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
      {{"zero"}, "x0"}, {{"ra"}, "x1"},  {{"sp"}, "x2"},   {{"gp"}, "x3"},
      {{"tp"}, "x4"},   {{"t0"}, "x5"},  {{"t1"}, "x6"},   {{"t2"}, "x7"},
      {{"s0"}, "x8"},   {{"s1"}, "x9"},  {{"a0"}, "x10"},  {{"a1"}, "x11"},
      {{"a2"}, "x12"},  {{"a3"}, "x13"}, {{"a4"}, "x15"},  {{"a5"}, "x15"},
      {{"a6"}, "x16"},  {{"a7"}, "x17"}, {{"s2"}, "x18"},  {{"s3"}, "x19"},
      {{"s4"}, "x20"},  {{"s5"}, "x21"}, {{"s6"}, "x22"},  {{"s7"}, "x23"},
      {{"s8"}, "x24"},  {{"s9"}, "x25"}, {{"s10"}, "x26"}, {{"s11"}, "x27"},
      {{"t3"}, "x28"},  {{"t4"}, "x29"}, {{"t5"}, "x30"},  {{"t6"}, "x31"}};
  return llvm::makeArrayRef(GCCRegAliases);
}

void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
                                       MacroBuilder &Builder) const {
  Builder.defineMacro("__ELF__");
  Builder.defineMacro("__riscv");
  bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
  Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
  // TODO: modify when more code models and ABIs are supported.
  Builder.defineMacro("__riscv_cmodel_medlow");
  Builder.defineMacro("__riscv_float_abi_soft");

  if (HasM) {
    Builder.defineMacro("__riscv_mul");
    Builder.defineMacro("__riscv_div");
    Builder.defineMacro("__riscv_muldiv");
  }

  if (HasA)
    Builder.defineMacro("__riscv_atomic");

  if (HasF || HasD) {
    Builder.defineMacro("__riscv_flen", HasD ? "64" : "32");
    Builder.defineMacro("__riscv_fdiv");
    Builder.defineMacro("__riscv_fsqrt");
  }

  if (HasC)
    Builder.defineMacro("__riscv_compressed");
}

/// Return true if has this feature, need to sync with handleTargetFeatures.
bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
  bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
  return llvm::StringSwitch<bool>(Feature)
      .Case("riscv", true)
      .Case("riscv32", !Is64Bit)
      .Case("riscv64", Is64Bit)
      .Case("m", HasM)
      .Case("a", HasA)
      .Case("f", HasF)
      .Case("d", HasD)
      .Case("c", HasC)
      .Default(false);
}

/// Perform initialization based on the user configured set of features.
bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
                                           DiagnosticsEngine &Diags) {
  for (const auto &Feature : Features) {
    if (Feature == "+m")
      HasM = true;
    else if (Feature == "+a")
      HasA = true;
    else if (Feature == "+f")
      HasF = true;
    else if (Feature == "+d")
      HasD = true;
    else if (Feature == "+c")
      HasC = true;
  }

  return true;
}
<commit_msg>Fix typo in risc-v register aliases.<commit_after>//===--- RISCV.cpp - Implement RISCV target feature support ---------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements RISCV TargetInfo objects.
//
//===----------------------------------------------------------------------===//

#include "RISCV.h"
#include "clang/Basic/MacroBuilder.h"
#include "llvm/ADT/StringSwitch.h"

using namespace clang;
using namespace clang::targets;

ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const {
  static const char *const GCCRegNames[] = {
      "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
      "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
      "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
      "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31"};
  return llvm::makeArrayRef(GCCRegNames);
}

ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const {
  static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
      {{"zero"}, "x0"}, {{"ra"}, "x1"},  {{"sp"}, "x2"},   {{"gp"}, "x3"},
      {{"tp"}, "x4"},   {{"t0"}, "x5"},  {{"t1"}, "x6"},   {{"t2"}, "x7"},
      {{"s0"}, "x8"},   {{"s1"}, "x9"},  {{"a0"}, "x10"},  {{"a1"}, "x11"},
      {{"a2"}, "x12"},  {{"a3"}, "x13"}, {{"a4"}, "x14"},  {{"a5"}, "x15"},
      {{"a6"}, "x16"},  {{"a7"}, "x17"}, {{"s2"}, "x18"},  {{"s3"}, "x19"},
      {{"s4"}, "x20"},  {{"s5"}, "x21"}, {{"s6"}, "x22"},  {{"s7"}, "x23"},
      {{"s8"}, "x24"},  {{"s9"}, "x25"}, {{"s10"}, "x26"}, {{"s11"}, "x27"},
      {{"t3"}, "x28"},  {{"t4"}, "x29"}, {{"t5"}, "x30"},  {{"t6"}, "x31"}};
  return llvm::makeArrayRef(GCCRegAliases);
}

void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
                                       MacroBuilder &Builder) const {
  Builder.defineMacro("__ELF__");
  Builder.defineMacro("__riscv");
  bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
  Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
  // TODO: modify when more code models and ABIs are supported.
  Builder.defineMacro("__riscv_cmodel_medlow");
  Builder.defineMacro("__riscv_float_abi_soft");

  if (HasM) {
    Builder.defineMacro("__riscv_mul");
    Builder.defineMacro("__riscv_div");
    Builder.defineMacro("__riscv_muldiv");
  }

  if (HasA)
    Builder.defineMacro("__riscv_atomic");

  if (HasF || HasD) {
    Builder.defineMacro("__riscv_flen", HasD ? "64" : "32");
    Builder.defineMacro("__riscv_fdiv");
    Builder.defineMacro("__riscv_fsqrt");
  }

  if (HasC)
    Builder.defineMacro("__riscv_compressed");
}

/// Return true if has this feature, need to sync with handleTargetFeatures.
bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
  bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
  return llvm::StringSwitch<bool>(Feature)
      .Case("riscv", true)
      .Case("riscv32", !Is64Bit)
      .Case("riscv64", Is64Bit)
      .Case("m", HasM)
      .Case("a", HasA)
      .Case("f", HasF)
      .Case("d", HasD)
      .Case("c", HasC)
      .Default(false);
}

/// Perform initialization based on the user configured set of features.
bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
                                           DiagnosticsEngine &Diags) {
  for (const auto &Feature : Features) {
    if (Feature == "+m")
      HasM = true;
    else if (Feature == "+a")
      HasA = true;
    else if (Feature == "+f")
      HasF = true;
    else if (Feature == "+d")
      HasD = true;
    else if (Feature == "+c")
      HasC = true;
  }

  return true;
}
<|endoftext|>


<commit_before><commit_msg>remove unused file<commit_after><|endoftext|>