<commit_before>#include "terminalpp/terminal.hpp"
#include "terminalpp/ansi/osc.hpp"
#include "terminalpp/detail/terminal_control.hpp"
#include "terminalpp/detail/terminal_cursor_control.hpp"
#include "terminalpp/detail/element_difference.hpp"
#include "terminalpp/detail/parser.hpp"
#include "terminalpp/detail/well_known_virtual_key.hpp"
#include <cassert>

namespace terminalpp {

namespace {

// ==========================================================================
// WRITE_ELEMENT
// ==========================================================================
std::string write_element(const element& elem)
{
    std::string text;

    if (elem.glyph_.charset_ == terminalpp::ansi::charset::utf8)
    {
        for (size_t index = 0;
             index < sizeof(elem.glyph_.ucharacter_)
          && elem.glyph_.ucharacter_[index] != '\0';
             ++index)
        {
            text += elem.glyph_.ucharacter_[index];

            if (!(elem.glyph_.ucharacter_[index] & 0x80))
            {
                break;
            }
        }
    }
    else
    {
        text += elem.glyph_.character_;
    }

    return text;
}

// ==========================================================================
// REPLACE_WELL_KNOWN_VIRTUAL_KEYS
// ==========================================================================
std::vector<token> replace_well_known_virtual_keys(std::vector<token> tokens)
{
    std::transform(tokens.begin(), tokens.end(), tokens.begin(),
        detail::get_well_known_virtual_key);

    return tokens;
}

}

// ==========================================================================
// CONSTRUCTOR
// ==========================================================================
terminal::terminal(terminal::behaviour const &behaviour)
  : behaviour_(behaviour)
{
}

// ==========================================================================
// INIT
// ==========================================================================
std::string terminal::init()
{
    std::string result;

    if (behaviour_.can_use_eight_bit_control_codes
     && !behaviour_.uses_eight_bit_control_codes_by_default)
    {
        result += terminalpp::ansi::control8::ENABLE;
    }

    return result;
}

// ==========================================================================
// ENABLE_MOUSE
// ==========================================================================
std::string terminal::enable_mouse()
{
    std::string result;

    if (behaviour_.supports_all_mouse_motion_tracking)
    {
        result += detail::csi(control_mode_)
                + ansi::DEC_PRIVATE_MODE
                + ansi::dec_pm::ALL_MOTION_MOUSE_TRACKING
                + ansi::dec_pm::SET;
    }
    else if (behaviour_.supports_basic_mouse_tracking)
    {
        result += detail::csi(control_mode_)
                + ansi::DEC_PRIVATE_MODE
                + ansi::dec_pm::BASIC_MOUSE_TRACKING
                + ansi::dec_pm::SET;
    }

    return result;
}

// ==========================================================================
// SET_WINDOW_TITLE
// ==========================================================================
std::string terminal::set_window_title(std::string const &title)
{
    if (behaviour_.supports_window_title_bel)
    {
        return detail::osc(control_mode_)
             + ansi::osc::SET_WINDOW_TITLE
             + ansi::PS
             + title
             + ascii::BEL;
    }

    if (behaviour_.supports_window_title_st)
    {
        return detail::osc(control_mode_)
             + ansi::osc::SET_WINDOW_TITLE
             + ansi::PS
             + title
             + detail::st(control_mode_);
    }

    return {};
}

// ==========================================================================
// SET_SIZE
// ==========================================================================
void terminal::set_size(const extent& size)
{
    size_ = size;
}

// ==========================================================================
// SHOW_CURSOR
// ==========================================================================
std::string terminal::show_cursor()
{
    if (cursor_mode_ != cursor_mode::shown)
    {
        cursor_mode_ = cursor_mode::shown;

        return detail::csi(control_mode_)
             + terminalpp::ansi::DEC_PRIVATE_MODE
             + terminalpp::ansi::dec_pm::CURSOR
             + terminalpp::ansi::dec_pm::SET;
    }
    else
    {
        return {};
    }
}

// ==========================================================================
// HIDE_CURSOR
// ==========================================================================
std::string terminal::hide_cursor()
{
    if (cursor_mode_ != cursor_mode::hidden)
    {
        cursor_mode_ = cursor_mode::hidden;

        return detail::csi(control_mode_)
             + terminalpp::ansi::DEC_PRIVATE_MODE
             + terminalpp::ansi::dec_pm::CURSOR
             + terminalpp::ansi::dec_pm::RESET;
    }
    else
    {
        return {};
    }
}

// ==========================================================================
// SAVE_CURSOR
// ==========================================================================
std::string terminal::save_cursor()
{
    saved_cursor_position_ = cursor_position_;

    return detail::csi(control_mode_)
         + terminalpp::ansi::csi::SAVE_CURSOR_POSITION;
}

// ==========================================================================
// RESTORE_CURSOR
// ==========================================================================
std::string terminal::restore_cursor()
{
    cursor_position_ = saved_cursor_position_;

    return detail::csi(control_mode_)
         + terminalpp::ansi::csi::RESTORE_CURSOR_POSITION;
}

// ==========================================================================
// MOVE_CURSOR
// ==========================================================================
std::string terminal::move_cursor(point const &pos)
{
    std::string result;

    // Note: terminal uses 0-based co-ordinates whereas ANSI uses a
    // 1-based indexing.  Therefore, we need to offset the cursor position
    // in order to get the correct output when actually calling functions
    // that refer to co-ordinates (cursor_position and
    // cursor_horizontal_absolute).
    auto ansipos = pos + point{1, 1};

    if (cursor_position_)
    {
        // If we have a known cursor position, then we may be able to return a
        // shorter sequence, depending on the exact operation required.

        // If we're staying on the same line, then the following options are
        // available to us, if they are supported.
        //    * Cursor Horizontal Absolute (move to position on current line)
        //    * Cursor Forward
        //    * Cursor Backward
        if (*cursor_position_ == pos)
        {
            // Do nothing.
            return result;
        }

        if (cursor_position_->y == pos.y)
        {
            if (ansipos.x < 10 && behaviour_.supports_cha)
            {
                // Note: Cursor Horizontal Absolute uses 1-based indexing,
                // where terminal uses 0-based indexing.  Therefore, it needs
                // an offset.
                result =
                    detail::cursor_horizontal_absolute(
                        ansipos.x, behaviour_, control_mode_);
            }
            else
            {
                if (pos.x > cursor_position_->x)
                {
                    result =
                        detail::cursor_forward(
                            pos.x - cursor_position_->x,
                            control_mode_);
                }
                else
                {
                    result =
                        detail::cursor_backward(
                            cursor_position_->x - pos.x,
                            control_mode_);
                }
            }
        }
        else if (cursor_position_->x == pos.x)
        {
            if (cursor_position_->y > pos.y)
            {
                result = detail::cursor_up(cursor_position_->y - pos.y, control_mode_);
            }
            else
            {
                result = detail::cursor_down(pos.y - cursor_position_->y, control_mode_);
            }
        }
        else
        {
            // Since we must move in both dimensions, there's no short-cut
            // command to use.
            result = detail::cursor_position(ansipos, behaviour_, control_mode_);
        }
    }
    else
    {
        // The cursor position was unknown.  There are no shortcuts we can
        // sensibly take in this situation.
        result = detail::cursor_position(ansipos, behaviour_, control_mode_);
    }

    cursor_position_ = pos;

    return result;
}

// ==========================================================================
// READ
// ==========================================================================
std::vector<terminalpp::token> terminal::read(std::string const &data)
{
    std::vector<terminalpp::token> results;

    std::for_each(data.begin(), data.end(),
    [&](auto ch)
    {
        auto result = parser_(ch);

        if (result)
        {
            results.push_back(*result);
        }
    });

    // Some postprocessing for well-known control sequence->
    // virtual key mappings.
    return replace_well_known_virtual_keys(results);
}

// ==========================================================================
// WRITE
// ==========================================================================
std::string terminal::write(element const &elem)
{
    std::string result = detail::element_difference(last_element_, elem)
                       + write_element(elem);

    if (cursor_position_)
    {
        ++(cursor_position_->x);

        if (size_)
        {
            while (cursor_position_->x > size_->width)
            {
                cursor_position_->x -= size_->width;

                if (cursor_position_->y < size_->height)
                {
                    ++cursor_position_->y;
                }
            }
        }
    }

    last_element_ = elem;

    return result;
}

// ==========================================================================
// WRITE
// ==========================================================================
std::string terminal::write(string const& str)
{
    std::string result;

    std::for_each(str.begin(), str.end(),
        [&result, this](auto const &elem) mutable
        {
            result += write(elem);
        });

    return result;
}

// ==========================================================================
// ERASE_IN_DISPLAY
// ==========================================================================
std::string terminal::erase_in_display(terminal::erase_display how)
{
    std::string result;

    result = detail::csi(control_mode_);

    switch (how)
    {
        default :
            // Fall-through
        case terminal::erase_display::all :
            result += terminalpp::ansi::csi::ERASE_IN_DISPLAY_ALL;
            break;

        case terminal::erase_display::above :
            result += terminalpp::ansi::csi::ERASE_IN_DISPLAY_ABOVE;
            break;

        case terminal::erase_display::below :
            result += terminalpp::ansi::csi::ERASE_IN_DISPLAY_BELOW;
            break;
    }

    result += terminalpp::ansi::csi::ERASE_IN_DISPLAY;

    return result;
}

// ==========================================================================
// ERASE_IN_LINE
// ==========================================================================
std::string terminal::erase_in_line(terminal::erase_line how)
{
    std::string result;

    result = detail::csi(control_mode_);

    switch (how)
    {
        default :
            // Fall-through
        case terminal::erase_line::all :
            result += terminalpp::ansi::csi::ERASE_IN_LINE_ALL;
            break;

        case terminal::erase_line::left :
            result += terminalpp::ansi::csi::ERASE_IN_LINE_LEFT;
            break;

        case terminal::erase_line::right :
            result += terminalpp::ansi::csi::ERASE_IN_LINE_RIGHT;
            break;
    }

    result += terminalpp::ansi::csi::ERASE_IN_LINE;

    return result;
}

}
<commit_msg>Addition of this-> in lambda because g++ requires it.<commit_after>#include "terminalpp/terminal.hpp"
#include "terminalpp/ansi/osc.hpp"
#include "terminalpp/detail/terminal_control.hpp"
#include "terminalpp/detail/terminal_cursor_control.hpp"
#include "terminalpp/detail/element_difference.hpp"
#include "terminalpp/detail/parser.hpp"
#include "terminalpp/detail/well_known_virtual_key.hpp"
#include <cassert>

namespace terminalpp {

namespace {

// ==========================================================================
// WRITE_ELEMENT
// ==========================================================================
std::string write_element(const element& elem)
{
    std::string text;

    if (elem.glyph_.charset_ == terminalpp::ansi::charset::utf8)
    {
        for (size_t index = 0;
             index < sizeof(elem.glyph_.ucharacter_)
          && elem.glyph_.ucharacter_[index] != '\0';
             ++index)
        {
            text += elem.glyph_.ucharacter_[index];

            if (!(elem.glyph_.ucharacter_[index] & 0x80))
            {
                break;
            }
        }
    }
    else
    {
        text += elem.glyph_.character_;
    }

    return text;
}

// ==========================================================================
// REPLACE_WELL_KNOWN_VIRTUAL_KEYS
// ==========================================================================
std::vector<token> replace_well_known_virtual_keys(std::vector<token> tokens)
{
    std::transform(tokens.begin(), tokens.end(), tokens.begin(),
        detail::get_well_known_virtual_key);

    return tokens;
}

}

// ==========================================================================
// CONSTRUCTOR
// ==========================================================================
terminal::terminal(terminal::behaviour const &behaviour)
  : behaviour_(behaviour)
{
}

// ==========================================================================
// INIT
// ==========================================================================
std::string terminal::init()
{
    std::string result;

    if (behaviour_.can_use_eight_bit_control_codes
     && !behaviour_.uses_eight_bit_control_codes_by_default)
    {
        result += terminalpp::ansi::control8::ENABLE;
    }

    return result;
}

// ==========================================================================
// ENABLE_MOUSE
// ==========================================================================
std::string terminal::enable_mouse()
{
    std::string result;

    if (behaviour_.supports_all_mouse_motion_tracking)
    {
        result += detail::csi(control_mode_)
                + ansi::DEC_PRIVATE_MODE
                + ansi::dec_pm::ALL_MOTION_MOUSE_TRACKING
                + ansi::dec_pm::SET;
    }
    else if (behaviour_.supports_basic_mouse_tracking)
    {
        result += detail::csi(control_mode_)
                + ansi::DEC_PRIVATE_MODE
                + ansi::dec_pm::BASIC_MOUSE_TRACKING
                + ansi::dec_pm::SET;
    }

    return result;
}

// ==========================================================================
// SET_WINDOW_TITLE
// ==========================================================================
std::string terminal::set_window_title(std::string const &title)
{
    if (behaviour_.supports_window_title_bel)
    {
        return detail::osc(control_mode_)
             + ansi::osc::SET_WINDOW_TITLE
             + ansi::PS
             + title
             + ascii::BEL;
    }

    if (behaviour_.supports_window_title_st)
    {
        return detail::osc(control_mode_)
             + ansi::osc::SET_WINDOW_TITLE
             + ansi::PS
             + title
             + detail::st(control_mode_);
    }

    return {};
}

// ==========================================================================
// SET_SIZE
// ==========================================================================
void terminal::set_size(const extent& size)
{
    size_ = size;
}

// ==========================================================================
// SHOW_CURSOR
// ==========================================================================
std::string terminal::show_cursor()
{
    if (cursor_mode_ != cursor_mode::shown)
    {
        cursor_mode_ = cursor_mode::shown;

        return detail::csi(control_mode_)
             + terminalpp::ansi::DEC_PRIVATE_MODE
             + terminalpp::ansi::dec_pm::CURSOR
             + terminalpp::ansi::dec_pm::SET;
    }
    else
    {
        return {};
    }
}

// ==========================================================================
// HIDE_CURSOR
// ==========================================================================
std::string terminal::hide_cursor()
{
    if (cursor_mode_ != cursor_mode::hidden)
    {
        cursor_mode_ = cursor_mode::hidden;

        return detail::csi(control_mode_)
             + terminalpp::ansi::DEC_PRIVATE_MODE
             + terminalpp::ansi::dec_pm::CURSOR
             + terminalpp::ansi::dec_pm::RESET;
    }
    else
    {
        return {};
    }
}

// ==========================================================================
// SAVE_CURSOR
// ==========================================================================
std::string terminal::save_cursor()
{
    saved_cursor_position_ = cursor_position_;

    return detail::csi(control_mode_)
         + terminalpp::ansi::csi::SAVE_CURSOR_POSITION;
}

// ==========================================================================
// RESTORE_CURSOR
// ==========================================================================
std::string terminal::restore_cursor()
{
    cursor_position_ = saved_cursor_position_;

    return detail::csi(control_mode_)
         + terminalpp::ansi::csi::RESTORE_CURSOR_POSITION;
}

// ==========================================================================
// MOVE_CURSOR
// ==========================================================================
std::string terminal::move_cursor(point const &pos)
{
    std::string result;

    // Note: terminal uses 0-based co-ordinates whereas ANSI uses a
    // 1-based indexing.  Therefore, we need to offset the cursor position
    // in order to get the correct output when actually calling functions
    // that refer to co-ordinates (cursor_position and
    // cursor_horizontal_absolute).
    auto ansipos = pos + point{1, 1};

    if (cursor_position_)
    {
        // If we have a known cursor position, then we may be able to return a
        // shorter sequence, depending on the exact operation required.

        // If we're staying on the same line, then the following options are
        // available to us, if they are supported.
        //    * Cursor Horizontal Absolute (move to position on current line)
        //    * Cursor Forward
        //    * Cursor Backward
        if (*cursor_position_ == pos)
        {
            // Do nothing.
            return result;
        }

        if (cursor_position_->y == pos.y)
        {
            if (ansipos.x < 10 && behaviour_.supports_cha)
            {
                // Note: Cursor Horizontal Absolute uses 1-based indexing,
                // where terminal uses 0-based indexing.  Therefore, it needs
                // an offset.
                result =
                    detail::cursor_horizontal_absolute(
                        ansipos.x, behaviour_, control_mode_);
            }
            else
            {
                if (pos.x > cursor_position_->x)
                {
                    result =
                        detail::cursor_forward(
                            pos.x - cursor_position_->x,
                            control_mode_);
                }
                else
                {
                    result =
                        detail::cursor_backward(
                            cursor_position_->x - pos.x,
                            control_mode_);
                }
            }
        }
        else if (cursor_position_->x == pos.x)
        {
            if (cursor_position_->y > pos.y)
            {
                result = detail::cursor_up(cursor_position_->y - pos.y, control_mode_);
            }
            else
            {
                result = detail::cursor_down(pos.y - cursor_position_->y, control_mode_);
            }
        }
        else
        {
            // Since we must move in both dimensions, there's no short-cut
            // command to use.
            result = detail::cursor_position(ansipos, behaviour_, control_mode_);
        }
    }
    else
    {
        // The cursor position was unknown.  There are no shortcuts we can
        // sensibly take in this situation.
        result = detail::cursor_position(ansipos, behaviour_, control_mode_);
    }

    cursor_position_ = pos;

    return result;
}

// ==========================================================================
// READ
// ==========================================================================
std::vector<terminalpp::token> terminal::read(std::string const &data)
{
    std::vector<terminalpp::token> results;

    std::for_each(data.begin(), data.end(),
    [&](auto ch)
    {
        auto result = parser_(ch);

        if (result)
        {
            results.push_back(*result);
        }
    });

    // Some postprocessing for well-known control sequence->
    // virtual key mappings.
    return replace_well_known_virtual_keys(results);
}

// ==========================================================================
// WRITE
// ==========================================================================
std::string terminal::write(element const &elem)
{
    std::string result = detail::element_difference(last_element_, elem)
                       + write_element(elem);

    if (cursor_position_)
    {
        ++(cursor_position_->x);

        if (size_)
        {
            while (cursor_position_->x > size_->width)
            {
                cursor_position_->x -= size_->width;

                if (cursor_position_->y < size_->height)
                {
                    ++cursor_position_->y;
                }
            }
        }
    }

    last_element_ = elem;

    return result;
}

// ==========================================================================
// WRITE
// ==========================================================================
std::string terminal::write(string const& str)
{
    std::string result;

    std::for_each(str.begin(), str.end(),
        [&result, this](auto const &elem)
        {
            result += this->write(elem);
        });

    return result;
}

// ==========================================================================
// ERASE_IN_DISPLAY
// ==========================================================================
std::string terminal::erase_in_display(terminal::erase_display how)
{
    std::string result;

    result = detail::csi(control_mode_);

    switch (how)
    {
        default :
            // Fall-through
        case terminal::erase_display::all :
            result += terminalpp::ansi::csi::ERASE_IN_DISPLAY_ALL;
            break;

        case terminal::erase_display::above :
            result += terminalpp::ansi::csi::ERASE_IN_DISPLAY_ABOVE;
            break;

        case terminal::erase_display::below :
            result += terminalpp::ansi::csi::ERASE_IN_DISPLAY_BELOW;
            break;
    }

    result += terminalpp::ansi::csi::ERASE_IN_DISPLAY;

    return result;
}

// ==========================================================================
// ERASE_IN_LINE
// ==========================================================================
std::string terminal::erase_in_line(terminal::erase_line how)
{
    std::string result;

    result = detail::csi(control_mode_);

    switch (how)
    {
        default :
            // Fall-through
        case terminal::erase_line::all :
            result += terminalpp::ansi::csi::ERASE_IN_LINE_ALL;
            break;

        case terminal::erase_line::left :
            result += terminalpp::ansi::csi::ERASE_IN_LINE_LEFT;
            break;

        case terminal::erase_line::right :
            result += terminalpp::ansi::csi::ERASE_IN_LINE_RIGHT;
            break;
    }

    result += terminalpp::ansi::csi::ERASE_IN_LINE;

    return result;
}

}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	FIFO (first in first out)
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>

namespace utils {

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    /*!
        @brief  fifo クラス
		@param[in]	size	バッファサイズ
    */
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint16_t size_ = 256>
	class fifo {

		volatile uint16_t	get_;
		volatile uint16_t	put_;

		char		buff_[size_];

	public:
        //-----------------------------------------------------------------//
        /*!
            @brief  コンストラクター
        */
        //-----------------------------------------------------------------//
		fifo() : get_(0), put_(0) { }

        //-----------------------------------------------------------------//
        /*!
            @brief  クリア
        */
        //-----------------------------------------------------------------//
		void clear() { get_ = put_ = 0; }

        //-----------------------------------------------------------------//
        /*!
            @brief  値の格納
			@param[in]	v	値
        */
        //-----------------------------------------------------------------//
		void put(uint8_t v) {
			buff_[put_] = v;
			++put_;
			if(put_ >= size_) {
				put_ = 0;
			}
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  値の取得
			@return	値
        */
        //-----------------------------------------------------------------//
		uint8_t get() {
			uint8_t data = buff_[get_];
			++get_;
			if(get_ >= size_) {
				get_ = 0;
			}
			return data;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  長さを返す
			@return	長さ
        */
        //-----------------------------------------------------------------//
		uint16_t length() const {
			if(put_ >= get_) return (put_ - get_);
			else return (size_ + put_ - get_);
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  get 位置を返す
			@return	位置
        */
        //-----------------------------------------------------------------//
		uint16_t pos_get() const { return get_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  put 位置を返す
			@return	位置
        */
        //-----------------------------------------------------------------//
		uint16_t pos_put() const { return put_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  バッファのサイズを返す
			@return	バッファのサイズ
        */
        //-----------------------------------------------------------------//
		uint16_t size() const { return size_; }

	};

}
<commit_msg>コメント修正<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	FIFO (first in first out)
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>

namespace utils {

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    /*!
        @brief  fifo クラス
		@param[in]	size_	バッファサイズ
    */
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint16_t size_ = 256>
	class fifo {

		volatile uint16_t	get_;
		volatile uint16_t	put_;

		char		buff_[size_];

	public:
        //-----------------------------------------------------------------//
        /*!
            @brief  コンストラクター
        */
        //-----------------------------------------------------------------//
		fifo() : get_(0), put_(0) { }

        //-----------------------------------------------------------------//
        /*!
            @brief  クリア
        */
        //-----------------------------------------------------------------//
		void clear() { get_ = put_ = 0; }

        //-----------------------------------------------------------------//
        /*!
            @brief  値の格納
			@param[in]	v	値
        */
        //-----------------------------------------------------------------//
		void put(uint8_t v) {
			buff_[put_] = v;
			++put_;
			if(put_ >= size_) {
				put_ = 0;
			}
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  値の取得
			@return	値
        */
        //-----------------------------------------------------------------//
		uint8_t get() {
			uint8_t data = buff_[get_];
			++get_;
			if(get_ >= size_) {
				get_ = 0;
			}
			return data;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  長さを返す
			@return	長さ
        */
        //-----------------------------------------------------------------//
		uint16_t length() const {
			if(put_ >= get_) return (put_ - get_);
			else return (size_ + put_ - get_);
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  get 位置を返す
			@return	位置
        */
        //-----------------------------------------------------------------//
		uint16_t pos_get() const { return get_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  put 位置を返す
			@return	位置
        */
        //-----------------------------------------------------------------//
		uint16_t pos_put() const { return put_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  バッファのサイズを返す
			@return	バッファのサイズ
        */
        //-----------------------------------------------------------------//
		uint16_t size() const { return size_; }

	};

}
<|endoftext|>


<commit_before>/*
============================================================================
DELLY: Structural variant discovery by integrated PE mapping and SR analysis
============================================================================
Copyright (C) 2012 Tobias Rausch

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
============================================================================
Contact: Tobias Rausch (rausch@embl.de)
============================================================================
*/

#include <iostream>
#include <fstream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>
#include <boost/program_options/cmdline.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/zlib.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/progress.hpp>
#include "api/BamReader.h"
#include "api/BamIndex.h"

#include "tags.h"
#include "coverage.h"
#include "tokenizer.h"
#include "memory_mapped_file.h"
#include "version.h"
#include "fasta_reader.h"
#include "util.h"

using namespace torali;

struct Config {
  unsigned int window_size;
  unsigned int window_offset;
  uint16_t minMapQual;
  bool bp_flag;
  bool avg_flag;
  bool inclCigar;
  boost::filesystem::path outfile;
  boost::filesystem::path int_file;
  std::vector<boost::filesystem::path> files;
};

template<typename TSingleHit>
inline int
run(Config const& c, TSingleHit)
{
  // Create library objects
  typedef std::map<std::string, LibraryInfo> TLibraryMap;
  typedef std::map<std::string, TLibraryMap> TSampleLibrary;
  TSampleLibrary sampleLib;

  // Scan libraries
  for(unsigned int file_c = 0; file_c < c.files.size(); ++file_c) {
    // Get a sample name
    std::string sampleName(c.files[file_c].stem().string());

    // Check that all input bam files exist
    BamTools::BamReader reader;
    if ( ! reader.Open(c.files[file_c].string()) ) {
      std::cerr << "Could not open input bam file: " << c.files[file_c].string() << std::endl;
      reader.Close();
      return -1;
    }

    // Check that all input bam files are indexed
    reader.LocateIndex();
    if ( !reader.HasIndex() ) {
      std::cerr << "Missing bam index file: " << c.files[file_c].string() << std::endl;
      reader.Close();
      return -1;
    }

    // Get library parameters and overall maximum insert size
    TLibraryMap libInfo;
    getLibraryParams(c.files[file_c], libInfo, 0, 5);
    sampleLib.insert(std::make_pair(sampleName, libInfo));
  }

  // Read all SV intervals
  typedef std::vector<StructuralVariantRecord> TSVs;
  TSVs svs;
  std::map<unsigned int, std::string> idToName;
  unsigned int intervalCount=1;
  if (boost::filesystem::exists(c.int_file) && boost::filesystem::is_regular_file(c.int_file) && boost::filesystem::file_size(c.int_file)) {
    Memory_mapped_file interval_file(c.int_file.string().c_str());
    char interval_buffer[Memory_mapped_file::MAX_LINE_LENGTH];
    while (interval_file.left_bytes() > 0) {
      interval_file.read_line(interval_buffer);
      // Read single interval line
      StructuralVariantRecord sv;
      Tokenizer token(interval_buffer, Memory_mapped_file::MAX_LINE_LENGTH);
      std::string interval_rname;
      token.getString(sv.chr);
      sv.svStart = token.getUInt();
      sv.svEnd = token.getUInt() + 1;
      std::string svName;
      token.getString(svName);
      idToName.insert(std::make_pair(intervalCount, svName));
      sv.id = intervalCount++;
      svs.push_back(sv);
    }
    interval_file.close();
  } else {
    // Create artificial intervals
    BamTools::BamReader readerRef;
    if ( ! readerRef.Open(c.files[0].string()) ) return -1;
    BamTools::RefVector references = readerRef.GetReferenceData();
    typename BamTools::RefVector::const_iterator itRef = references.begin();
    for(int refIndex=0;itRef!=references.end();++itRef, ++refIndex) {
      int32_t pos = 0;
      while (pos < references[refIndex].RefLength) {
	int32_t window_len = pos+c.window_size;
	if (window_len > references[refIndex].RefLength) window_len = references[refIndex].RefLength;
	StructuralVariantRecord sv;
	sv.chr = references[refIndex].RefName;
	sv.svStart = pos;
	sv.svEnd = window_len;
	std::stringstream s;
	s << sv.chr << ":" << sv.svStart << "-" << sv.svEnd;
	idToName.insert(std::make_pair(intervalCount, s.str()));
	sv.id = intervalCount++;
	svs.push_back(sv);
	pos += c.window_offset;
      }
    }
  }

  // Output data types
  typedef std::pair<std::string, int> TSampleSVPair;
  typedef std::pair<int, int> TBpRead;
  typedef std::map<TSampleSVPair, TBpRead> TCountMap;
  TCountMap countMap;

  // Annotate coverage
  annotateCoverage(c.files, c.minMapQual, c.inclCigar, sampleLib, svs, countMap, TSingleHit());

  // Output library statistics
  std::cout << "Library statistics" << std::endl;
  TSampleLibrary::const_iterator sampleIt=sampleLib.begin();
  for(;sampleIt!=sampleLib.end();++sampleIt) {
    std::cout << "Sample: " << sampleIt->first << std::endl;
    TLibraryMap::const_iterator libIt=sampleIt->second.begin();
    for(;libIt!=sampleIt->second.end();++libIt) {
      std::cout << "RG: ID=" << libIt->first << ",Median=" << libIt->second.median << ",MAD=" << libIt->second.mad << ",Orientation=" << (int) libIt->second.defaultOrient << ",MappedReads=" << libIt->second.mappedReads << ",DuplicatePairs=" << libIt->second.non_unique_pairs << ",UniquePairs=" << libIt->second.unique_pairs << std::endl;
    }
  }

  // Output file
  boost::iostreams::filtering_ostream dataOut;
  dataOut.push(boost::iostreams::gzip_compressor());
  dataOut.push(boost::iostreams::file_sink(c.outfile.string().c_str(), std::ios_base::out | std::ios_base::binary));

  // Iterate all SVs
  typename TSVs::const_iterator itSV = svs.begin();
  typename TSVs::const_iterator itSVEnd = svs.end();
  for(;itSV!=itSVEnd;++itSV) {
    dataOut << itSV->chr << "\t" << itSV->svStart << "\t" << itSV->svEnd << "\t" << idToName.find(itSV->id)->second;
    // Iterate all samples
    for(unsigned int file_c = 0; file_c < c.files.size(); ++file_c) {
      // Get the sample name
      std::string sampleName(c.files[file_c].stem().string());
      TSampleSVPair sampleSVPair = std::make_pair(sampleName, itSV->id);
      typename TCountMap::iterator countMapIt=countMap.find(sampleSVPair);
      dataOut << "\t";
      if (c.avg_flag) dataOut << ( (countMapIt->second.first) / (double) (itSV->svEnd - itSV->svStart)) << "\t";
      if (c.bp_flag) dataOut << countMapIt->second.first << "\t";
      dataOut << countMapIt->second.second;
    }
    dataOut << std::endl;
  }

  // End
  boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
  std::cout << '[' << boost::posix_time::to_simple_string(now) << "] Done." << std::endl;;
  return 0;
}

int main(int argc, char **argv) {
  Config c;

  // Define generic options
  boost::program_options::options_description generic("Generic options");
  generic.add_options()
    ("help,?", "show help message")
    ("bp-count,b", "show base pair count")
    ("avg-cov,a", "show average coverage")
    ("quality-cut,q", boost::program_options::value<uint16_t>(&c.minMapQual)->default_value(0), "exclude all alignments with quality < q")
    ("outfile,f", boost::program_options::value<boost::filesystem::path>(&c.outfile)->default_value("cov.gz"), "coverage output file")
    ;

  // Define window options
  boost::program_options::options_description window("Window options");
  window.add_options()
    ("window-size,s", boost::program_options::value<unsigned int>(&c.window_size)->default_value(10000), "window size")
    ("window-offset,o", boost::program_options::value<unsigned int>(&c.window_offset)->default_value(10000), "window offset")
    ;

  // Define interval options
  boost::program_options::options_description interval("Interval options");
  interval.add_options()
    ("interval-file,i", boost::program_options::value<boost::filesystem::path>(&c.int_file), "interval file")
    ;

  // Define hidden options
  boost::program_options::options_description hidden("Hidden options");
  hidden.add_options()
    ("input-file", boost::program_options::value< std::vector<boost::filesystem::path> >(&c.files), "input file")
    ("license,l", "show license")
    ("warranty,w", "show warranty")
    ;
  boost::program_options::positional_options_description pos_args;
  pos_args.add("input-file", -1);

  // Set the visibility
  boost::program_options::options_description cmdline_options;
  cmdline_options.add(generic).add(window).add(interval).add(hidden);
  boost::program_options::options_description visible_options;
  visible_options.add(generic).add(window).add(interval);
  boost::program_options::variables_map vm;
  boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(cmdline_options).positional(pos_args).run(), vm);
  boost::program_options::notify(vm);

  // Check command line arguments
  if ((vm.count("help")) || (!vm.count("input-file"))) {
    printTitle("Coverage calculation");
    if (vm.count("warranty")) {
      displayWarranty();
    } else if (vm.count("license")) {
      gplV3();
    } else {
      std::cout << "Usage: " << argv[0] << " [OPTIONS] <sample1.bam> <sample2.bam> ..." << std::endl;
      std::cout << visible_options << "\n";
    }
    return 1;
  }
  if (vm.count("bp-count")) c.bp_flag = true;
  else c.bp_flag = false;
  if (vm.count("avg-cov")) c.avg_flag = true;
  else c.avg_flag = false;
  if ((c.bp_flag) || (c.avg_flag)) c.inclCigar = true;
  else c.inclCigar = false;

  // Show cmd
  boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
  std::cout << '[' << boost::posix_time::to_simple_string(now) << "] ";
  for(int i=0; i<argc; ++i) { std::cout << argv[i] << ' '; }
  std::cout << std::endl;

  // Run coverage annotation
  if (c.inclCigar) return run(c, SingleHit<int32_t, std::string>());
  else return run(c, SingleHit<int32_t, void>());
}
<commit_msg>Changed chr names to ids.<commit_after>/*
============================================================================
DELLY: Structural variant discovery by integrated PE mapping and SR analysis
============================================================================
Copyright (C) 2012 Tobias Rausch

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
============================================================================
Contact: Tobias Rausch (rausch@embl.de)
============================================================================
*/

#include <iostream>
#include <fstream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>
#include <boost/program_options/cmdline.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/zlib.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/progress.hpp>
#include "api/BamReader.h"
#include "api/BamIndex.h"

#include "tags.h"
#include "coverage.h"
#include "tokenizer.h"
#include "memory_mapped_file.h"
#include "version.h"
#include "fasta_reader.h"
#include "util.h"

using namespace torali;

struct Config {
  unsigned int window_size;
  unsigned int window_offset;
  uint16_t minMapQual;
  bool bp_flag;
  bool avg_flag;
  bool inclCigar;
  boost::filesystem::path outfile;
  boost::filesystem::path int_file;
  std::vector<boost::filesystem::path> files;
};

template<typename TSingleHit>
inline int
run(Config const& c, TSingleHit)
{
  // Create library objects
  typedef std::map<std::string, LibraryInfo> TLibraryMap;
  typedef std::map<std::string, TLibraryMap> TSampleLibrary;
  TSampleLibrary sampleLib;

  // Scan libraries
  for(unsigned int file_c = 0; file_c < c.files.size(); ++file_c) {
    // Get a sample name
    std::string sampleName(c.files[file_c].stem().string());

    // Check that all input bam files exist
    BamTools::BamReader reader;
    if ( ! reader.Open(c.files[file_c].string()) ) {
      std::cerr << "Could not open input bam file: " << c.files[file_c].string() << std::endl;
      reader.Close();
      return -1;
    }

    // Check that all input bam files are indexed
    reader.LocateIndex();
    if ( !reader.HasIndex() ) {
      std::cerr << "Missing bam index file: " << c.files[file_c].string() << std::endl;
      reader.Close();
      return -1;
    }

    // Get library parameters and overall maximum insert size
    TLibraryMap libInfo;
    getLibraryParams(c.files[file_c], libInfo, 0, 5);
    sampleLib.insert(std::make_pair(sampleName, libInfo));
  }

  // Get references
  BamTools::BamReader readerRef;
  if ( ! readerRef.Open(c.files[0].string()) ) return -1;
  BamTools::RefVector references = readerRef.GetReferenceData();

  // Read all SV intervals
  typedef std::vector<StructuralVariantRecord> TSVs;
  TSVs svs;
  std::map<unsigned int, std::string> idToName;
  unsigned int intervalCount=1;
  if (boost::filesystem::exists(c.int_file) && boost::filesystem::is_regular_file(c.int_file) && boost::filesystem::file_size(c.int_file)) {
    Memory_mapped_file interval_file(c.int_file.string().c_str());
    char interval_buffer[Memory_mapped_file::MAX_LINE_LENGTH];
    while (interval_file.left_bytes() > 0) {
      interval_file.read_line(interval_buffer);
      // Read single interval line
      StructuralVariantRecord sv;
      Tokenizer token(interval_buffer, Memory_mapped_file::MAX_LINE_LENGTH);
      std::string chrName;
      token.getString(chrName);
      typename BamTools::RefVector::const_iterator itRef = references.begin();
      for(int refIndex=0;itRef!=references.end();++itRef, ++refIndex) {
	if (chrName==references[refIndex].RefName) {
	  sv.chr = refIndex;
	  break;
	}
      }
      sv.svStart = token.getUInt();
      sv.svEnd = token.getUInt() + 1;
      std::string svName;
      token.getString(svName);
      idToName.insert(std::make_pair(intervalCount, svName));
      sv.id = intervalCount++;
      svs.push_back(sv);
    }
    interval_file.close();
  } else {
    // Create artificial intervals
    typename BamTools::RefVector::const_iterator itRef = references.begin();
    for(int refIndex=0;itRef!=references.end();++itRef, ++refIndex) {
      int32_t pos = 0;
      while (pos < references[refIndex].RefLength) {
	int32_t window_len = pos+c.window_size;
	if (window_len > references[refIndex].RefLength) window_len = references[refIndex].RefLength;
	StructuralVariantRecord sv;
	sv.chr = refIndex;
	sv.svStart = pos;
	sv.svEnd = window_len;
	std::stringstream s;
	s << references[sv.chr].RefName << ":" << sv.svStart << "-" << sv.svEnd;
	idToName.insert(std::make_pair(intervalCount, s.str()));
	sv.id = intervalCount++;
	svs.push_back(sv);
	pos += c.window_offset;
      }
    }
  }

  // Output data types
  typedef std::pair<std::string, int> TSampleSVPair;
  typedef std::pair<int, int> TBpRead;
  typedef std::map<TSampleSVPair, TBpRead> TCountMap;
  TCountMap countMap;

  // Annotate coverage
  annotateCoverage(c.files, c.minMapQual, c.inclCigar, sampleLib, svs, countMap, TSingleHit());

  // Output library statistics
  std::cout << "Library statistics" << std::endl;
  TSampleLibrary::const_iterator sampleIt=sampleLib.begin();
  for(;sampleIt!=sampleLib.end();++sampleIt) {
    std::cout << "Sample: " << sampleIt->first << std::endl;
    TLibraryMap::const_iterator libIt=sampleIt->second.begin();
    for(;libIt!=sampleIt->second.end();++libIt) {
      std::cout << "RG: ID=" << libIt->first << ",Median=" << libIt->second.median << ",MAD=" << libIt->second.mad << ",Orientation=" << (int) libIt->second.defaultOrient << ",MappedReads=" << libIt->second.mappedReads << ",DuplicatePairs=" << libIt->second.non_unique_pairs << ",UniquePairs=" << libIt->second.unique_pairs << std::endl;
    }
  }

  // Output file
  boost::iostreams::filtering_ostream dataOut;
  dataOut.push(boost::iostreams::gzip_compressor());
  dataOut.push(boost::iostreams::file_sink(c.outfile.string().c_str(), std::ios_base::out | std::ios_base::binary));

  // Iterate all SVs
  typename TSVs::const_iterator itSV = svs.begin();
  typename TSVs::const_iterator itSVEnd = svs.end();
  for(;itSV!=itSVEnd;++itSV) {
    dataOut << references[itSV->chr].RefName << "\t" << itSV->svStart << "\t" << itSV->svEnd << "\t" << idToName.find(itSV->id)->second;
    // Iterate all samples
    for(unsigned int file_c = 0; file_c < c.files.size(); ++file_c) {
      // Get the sample name
      std::string sampleName(c.files[file_c].stem().string());
      TSampleSVPair sampleSVPair = std::make_pair(sampleName, itSV->id);
      typename TCountMap::iterator countMapIt=countMap.find(sampleSVPair);
      dataOut << "\t";
      if (c.avg_flag) dataOut << ( (countMapIt->second.first) / (double) (itSV->svEnd - itSV->svStart)) << "\t";
      if (c.bp_flag) dataOut << countMapIt->second.first << "\t";
      dataOut << countMapIt->second.second;
    }
    dataOut << std::endl;
  }

  // End
  boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
  std::cout << '[' << boost::posix_time::to_simple_string(now) << "] Done." << std::endl;;
  return 0;
}

int main(int argc, char **argv) {
  Config c;

  // Define generic options
  boost::program_options::options_description generic("Generic options");
  generic.add_options()
    ("help,?", "show help message")
    ("bp-count,b", "show base pair count")
    ("avg-cov,a", "show average coverage")
    ("quality-cut,q", boost::program_options::value<uint16_t>(&c.minMapQual)->default_value(0), "exclude all alignments with quality < q")
    ("outfile,f", boost::program_options::value<boost::filesystem::path>(&c.outfile)->default_value("cov.gz"), "coverage output file")
    ;

  // Define window options
  boost::program_options::options_description window("Window options");
  window.add_options()
    ("window-size,s", boost::program_options::value<unsigned int>(&c.window_size)->default_value(10000), "window size")
    ("window-offset,o", boost::program_options::value<unsigned int>(&c.window_offset)->default_value(10000), "window offset")
    ;

  // Define interval options
  boost::program_options::options_description interval("Interval options");
  interval.add_options()
    ("interval-file,i", boost::program_options::value<boost::filesystem::path>(&c.int_file), "interval file")
    ;

  // Define hidden options
  boost::program_options::options_description hidden("Hidden options");
  hidden.add_options()
    ("input-file", boost::program_options::value< std::vector<boost::filesystem::path> >(&c.files), "input file")
    ("license,l", "show license")
    ("warranty,w", "show warranty")
    ;
  boost::program_options::positional_options_description pos_args;
  pos_args.add("input-file", -1);

  // Set the visibility
  boost::program_options::options_description cmdline_options;
  cmdline_options.add(generic).add(window).add(interval).add(hidden);
  boost::program_options::options_description visible_options;
  visible_options.add(generic).add(window).add(interval);
  boost::program_options::variables_map vm;
  boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(cmdline_options).positional(pos_args).run(), vm);
  boost::program_options::notify(vm);

  // Check command line arguments
  if ((vm.count("help")) || (!vm.count("input-file"))) {
    printTitle("Coverage calculation");
    if (vm.count("warranty")) {
      displayWarranty();
    } else if (vm.count("license")) {
      gplV3();
    } else {
      std::cout << "Usage: " << argv[0] << " [OPTIONS] <sample1.bam> <sample2.bam> ..." << std::endl;
      std::cout << visible_options << "\n";
    }
    return 1;
  }
  if (vm.count("bp-count")) c.bp_flag = true;
  else c.bp_flag = false;
  if (vm.count("avg-cov")) c.avg_flag = true;
  else c.avg_flag = false;
  if ((c.bp_flag) || (c.avg_flag)) c.inclCigar = true;
  else c.inclCigar = false;

  // Show cmd
  boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
  std::cout << '[' << boost::posix_time::to_simple_string(now) << "] ";
  for(int i=0; i<argc; ++i) { std::cout << argv[i] << ' '; }
  std::cout << std::endl;

  // Run coverage annotation
  if (c.inclCigar) return run(c, SingleHit<int32_t, std::string>());
  else return run(c, SingleHit<int32_t, void>());
}
<|endoftext|>


<commit_before>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include <cmath>
#include <queue>

#include "log.h"
#include "route.h"

namespace {

USING_NEXTPNR_NAMESPACE

struct QueuedWire
{
    WireId wire;
    PipId pip;

    float delay = 0, togo = 0;

    struct Greater
    {
        bool operator()(const QueuedWire &lhs, const QueuedWire &rhs) const
                noexcept
        {
            return (lhs.delay + lhs.togo) > (rhs.delay + rhs.togo);
        }
    };
};

void ripup_net(Design *design, IdString net_name)
{
    auto &chip = design->chip;
    auto net_info = design->nets.at(net_name);

    for (auto &it : net_info->wires) {
        if (it.second != PipId())
            chip.unbindPip(it.second);
        chip.unbindWire(it.first);
    }

    net_info->wires.clear();
}

struct Router
{
    std::unordered_set<IdString> rippedNets;
    int visitCnt = 0, revisitCnt = 0;
    bool routedOkay = false;
    float maxDelay = 0.0;

    Router(Design *design, IdString net_name, bool verbose, bool ripup = false,
           float ripup_pip_penalty = 5.0, float ripup_wire_penalty = 5.0)
    {
        auto &chip = design->chip;
        auto net_info = design->nets.at(net_name);

        if (verbose)
            log("Routing net %s.\n", net_name.c_str());

        if (verbose)
            log("  Source: %s.%s.\n", net_info->driver.cell->name.c_str(),
                net_info->driver.port.c_str());

        auto src_bel = net_info->driver.cell->bel;

        if (src_bel == BelId())
            log_error("Source cell %s (%s) is not mapped to a bel.\n",
                      net_info->driver.cell->name.c_str(),
                      net_info->driver.cell->type.c_str());

        if (verbose)
            log("    Source bel: %s\n", chip.getBelName(src_bel).c_str());

        IdString driver_port = net_info->driver.port;

        auto driver_port_it = net_info->driver.cell->pins.find(driver_port);
        if (driver_port_it != net_info->driver.cell->pins.end())
            driver_port = driver_port_it->second;

        auto src_wire = chip.getWireBelPin(src_bel, portPinFromId(driver_port));

        if (src_wire == WireId())
            log_error("No wire found for port %s (pin %s) on source cell %s "
                      "(bel %s).\n",
                      net_info->driver.port.c_str(), driver_port.c_str(),
                      net_info->driver.cell->name.c_str(),
                      chip.getBelName(src_bel).c_str());

        if (verbose)
            log("    Source wire: %s\n", chip.getWireName(src_wire).c_str());

        std::unordered_map<WireId, DelayInfo> src_wires;
        src_wires[src_wire] = DelayInfo();
        net_info->wires[src_wire] = PipId();
        chip.bindWire(src_wire, net_name);

        for (auto &user_it : net_info->users) {
            if (verbose)
                log("  Route to: %s.%s.\n", user_it.cell->name.c_str(),
                    user_it.port.c_str());

            auto dst_bel = user_it.cell->bel;

            if (dst_bel == BelId())
                log_error("Destination cell %s (%s) is not mapped to a bel.\n",
                          user_it.cell->name.c_str(),
                          user_it.cell->type.c_str());

            if (verbose)
                log("    Destination bel: %s\n",
                    chip.getBelName(dst_bel).c_str());

            IdString user_port = user_it.port;

            auto user_port_it = user_it.cell->pins.find(user_port);

            if (user_port_it != user_it.cell->pins.end())
                user_port = user_port_it->second;

            auto dst_wire =
                    chip.getWireBelPin(dst_bel, portPinFromId(user_port));

            if (dst_wire == WireId())
                log_error("No wire found for port %s (pin %s) on destination "
                          "cell %s (bel %s).\n",
                          user_it.port.c_str(), user_port.c_str(),
                          user_it.cell->name.c_str(),
                          chip.getBelName(dst_bel).c_str());

            if (verbose) {
                log("    Destination wire: %s\n",
                    chip.getWireName(dst_wire).c_str());
                log("    Path delay estimate: %.2f\n",
                    chip.estimateDelay(src_wire, dst_wire));
            }

            std::unordered_map<WireId, QueuedWire> visited;
            std::priority_queue<QueuedWire, std::vector<QueuedWire>,
                                QueuedWire::Greater>
                    queue;

            for (auto &it : src_wires) {
                QueuedWire qw;
                qw.wire = it.first;
                qw.pip = PipId();
                qw.delay = it.second.avgDelay();
                qw.togo = chip.estimateDelay(qw.wire, dst_wire);

                queue.push(qw);
                visited[qw.wire] = qw;
            }

            while (!queue.empty() && !visited.count(dst_wire)) {
                QueuedWire qw = queue.top();
                queue.pop();

                for (auto pip : chip.getPipsDownhill(qw.wire)) {
                    float next_delay = qw.delay;
                    visitCnt++;

                    if (!chip.checkPipAvail(pip)) {
                        if (!ripup || net_name == chip.getPipNet(pip, true))
                            continue;
                        next_delay += ripup_pip_penalty;
                    }

                    WireId next_wire = chip.getPipDstWire(pip);
                    next_delay += chip.getPipDelay(pip).avgDelay();

                    if (visited.count(next_wire)) {
                        if (visited.at(next_wire).delay <= next_delay + 1e-3)
                            continue;
#if 0 // FIXME
                        if (verbose)
                            log("Found better route to %s. Old vs new delay "
                                "estimate: %.2f %.2f\n",
                                chip.getWireName(next_wire).c_str(),
                                visited.at(next_wire).delay, next_delay);
#endif
                        revisitCnt++;
                    }

                    if (!chip.checkWireAvail(next_wire)) {
                        if (!ripup ||
                            net_name == chip.getWireNet(next_wire, true))
                            continue;
                        next_delay += ripup_wire_penalty;
                    }

                    QueuedWire next_qw;
                    next_qw.wire = next_wire;
                    next_qw.pip = pip;
                    next_qw.delay = next_delay;
                    next_qw.togo = chip.estimateDelay(next_wire, dst_wire);
                    visited[next_qw.wire] = next_qw;
                    queue.push(next_qw);
                }
            }

            if (visited.count(dst_wire) == 0) {
                if (verbose)
                    log("Failed to route %s -> %s.\n",
                        chip.getWireName(src_wire).c_str(),
                        chip.getWireName(dst_wire).c_str());
                else if (ripup)
                    log_info("Failed to route %s -> %s.\n",
                             chip.getWireName(src_wire).c_str(),
                             chip.getWireName(dst_wire).c_str());
                ripup_net(design, net_name);
                return;
            }

            if (verbose)
                log("    Final path delay: %.2f\n", visited[dst_wire].delay);
            maxDelay = fmaxf(maxDelay, visited[dst_wire].delay);

            if (verbose)
                log("    Route (from destination to source):\n");

            WireId cursor = dst_wire;

            while (1) {
                if (verbose)
                    log("    %8.2f %s\n", visited[cursor].delay,
                        chip.getWireName(cursor).c_str());

                if (src_wires.count(cursor))
                    break;

                IdString conflicting_net = chip.getWireNet(cursor, true);

                if (conflicting_net != IdString()) {
                    assert(ripup);
                    assert(conflicting_net != net_name);
                    ripup_net(design, conflicting_net);
                    rippedNets.insert(conflicting_net);
                }

                conflicting_net = chip.getPipNet(visited[cursor].pip, true);

                if (conflicting_net != IdString()) {
                    assert(ripup);
                    assert(conflicting_net != net_name);
                    ripup_net(design, conflicting_net);
                    rippedNets.insert(conflicting_net);
                }

                net_info->wires[cursor] = visited[cursor].pip;
                chip.bindWire(cursor, net_name);
                chip.bindPip(visited[cursor].pip, net_name);

                src_wires[cursor] = chip.getPipDelay(visited[cursor].pip);
                cursor = chip.getPipSrcWire(visited[cursor].pip);
            }
        }

        routedOkay = true;
    }
};

} // namespace

NEXTPNR_NAMESPACE_BEGIN

void route_design(Design *design, bool verbose)
{
    auto &chip = design->chip;
    float maxDelay = 0.0;
    float ripup_pip_penalty = 5.0;
    float ripup_wire_penalty = 5.0;

    log_info("Routing..\n");

    std::unordered_set<IdString> netsQueue;

    for (auto &net_it : design->nets) {
        auto net_name = net_it.first;
        auto net_info = net_it.second;

        if (net_info->driver.cell == nullptr)
            continue;

        if (!net_info->wires.empty())
            continue;

        netsQueue.insert(net_name);
    }

    if (netsQueue.empty()) {
        log_info("found no unrouted nets. no routing necessary.\n");
        return;
    }

    log_info("found %d unrouted nets. starting routing procedure.\n",
             int(netsQueue.size()));

    float estimatedTotalDelay = 0.0;
    int estimatedTotalDelayCnt = 0;

    for (auto net_name : netsQueue) {
        auto net_info = design->nets.at(net_name);

        auto src_bel = net_info->driver.cell->bel;

        if (src_bel == BelId())
            continue;

        IdString driver_port = net_info->driver.port;

        auto driver_port_it = net_info->driver.cell->pins.find(driver_port);
        if (driver_port_it != net_info->driver.cell->pins.end())
            driver_port = driver_port_it->second;

        auto src_wire = chip.getWireBelPin(src_bel, portPinFromId(driver_port));

        if (src_wire == WireId())
            continue;

        for (auto &user_it : net_info->users) {
            auto dst_bel = user_it.cell->bel;

            if (dst_bel == BelId())
                continue;

            IdString user_port = user_it.port;

            auto user_port_it = user_it.cell->pins.find(user_port);

            if (user_port_it != user_it.cell->pins.end())
                user_port = user_port_it->second;

            auto dst_wire =
                    chip.getWireBelPin(dst_bel, portPinFromId(user_port));

            if (dst_wire == WireId())
                continue;

            estimatedTotalDelay += chip.estimateDelay(src_wire, dst_wire);
            estimatedTotalDelayCnt++;
        }
    }

    log_info("estimated total wire delay: %.2f (avg %.2f)\n",
             estimatedTotalDelay, estimatedTotalDelay / estimatedTotalDelayCnt);

    while (!netsQueue.empty()) {
        int visitCnt = 0, revisitCnt = 0, netCnt = 0;

        std::unordered_set<IdString> ripupQueue;

        for (auto net_name : netsQueue) {
            Router router(design, net_name, verbose, false);

            netCnt++;
            visitCnt += router.visitCnt;
            revisitCnt += router.revisitCnt;

            if (router.routedOkay) {
                maxDelay = fmaxf(maxDelay, router.maxDelay);
            } else {
                ripupQueue.insert(net_name);
            }

            if (netCnt % 100 == 0)
                log_info("  processed %d nets. (%d routed, %d failed)\n",
                         netCnt, netCnt - int(ripupQueue.size()),
                         int(ripupQueue.size()));
        }

        netsQueue.clear();

        if (netCnt % 100 != 0)
            log_info("  processed %d nets. (%d routed, %d failed)\n", netCnt,
                     netCnt - int(ripupQueue.size()), int(ripupQueue.size()));
        log_info("routing pass visited %d PIPs (%.2f%% revisits).\n", visitCnt,
                 (100.0 * revisitCnt) / visitCnt);

        if (!ripupQueue.empty()) {
            log_info("failed to route %d nets. re-routing in ripup mode.\n",
                     int(ripupQueue.size()));

            visitCnt = 0;
            revisitCnt = 0;
            netCnt = 0;
            int ripCnt = 0;

            for (auto net_name : ripupQueue) {
                Router router(design, net_name, verbose, true,
                              ripup_pip_penalty, ripup_wire_penalty);

                netCnt++;
                visitCnt += router.visitCnt;
                revisitCnt += router.revisitCnt;

                if (!router.routedOkay)
                    log_error("Net %s is impossible to route.\n",
                              net_name.c_str());

                maxDelay = fmaxf(maxDelay, router.maxDelay);

                for (auto it : router.rippedNets)
                    netsQueue.insert(it);

                ripCnt += router.rippedNets.size();

                if (netCnt % 100 == 0)
                    log_info("  routed %d nets, ripped %d nets.\n", netCnt,
                             ripCnt);
            }

            if (netCnt % 100 != 0)
                log_info("  routed %d nets, ripped %d nets.\n", netCnt, ripCnt);
            log_info("routing pass visited %d PIPs (%.2f%% revisits).\n",
                     visitCnt, (100.0 * revisitCnt) / visitCnt);

            log_info("ripped up %d previously routed nets. continue routing.\n",
                     int(netsQueue.size()));

            ripup_pip_penalty *= 1.5;
            ripup_wire_penalty *= 1.5;
        }
    }

    log_info("routing complete. longest path delay: %.2f\n", maxDelay);
}

NEXTPNR_NAMESPACE_END
<commit_msg>router: Fixing loop issue<commit_after>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include <cmath>
#include <queue>

#include "log.h"
#include "route.h"

namespace {

USING_NEXTPNR_NAMESPACE

struct QueuedWire
{
    WireId wire;
    PipId pip;

    float delay = 0, togo = 0;

    struct Greater
    {
        bool operator()(const QueuedWire &lhs, const QueuedWire &rhs) const
                noexcept
        {
            return (lhs.delay + lhs.togo) > (rhs.delay + rhs.togo);
        }
    };
};

void ripup_net(Design *design, IdString net_name)
{
    auto &chip = design->chip;
    auto net_info = design->nets.at(net_name);

    for (auto &it : net_info->wires) {
        if (it.second != PipId())
            chip.unbindPip(it.second);
        chip.unbindWire(it.first);
    }

    net_info->wires.clear();
}

struct Router
{
    std::unordered_set<IdString> rippedNets;
    int visitCnt = 0, revisitCnt = 0;
    bool routedOkay = false;
    float maxDelay = 0.0;

    Router(Design *design, IdString net_name, bool verbose, bool ripup = false,
           float ripup_pip_penalty = 5.0, float ripup_wire_penalty = 5.0)
    {
        auto &chip = design->chip;
        auto net_info = design->nets.at(net_name);

        if (verbose)
            log("Routing net %s.\n", net_name.c_str());

        if (verbose)
            log("  Source: %s.%s.\n", net_info->driver.cell->name.c_str(),
                net_info->driver.port.c_str());

        auto src_bel = net_info->driver.cell->bel;

        if (src_bel == BelId())
            log_error("Source cell %s (%s) is not mapped to a bel.\n",
                      net_info->driver.cell->name.c_str(),
                      net_info->driver.cell->type.c_str());

        if (verbose)
            log("    Source bel: %s\n", chip.getBelName(src_bel).c_str());

        IdString driver_port = net_info->driver.port;

        auto driver_port_it = net_info->driver.cell->pins.find(driver_port);
        if (driver_port_it != net_info->driver.cell->pins.end())
            driver_port = driver_port_it->second;

        auto src_wire = chip.getWireBelPin(src_bel, portPinFromId(driver_port));

        if (src_wire == WireId())
            log_error("No wire found for port %s (pin %s) on source cell %s "
                      "(bel %s).\n",
                      net_info->driver.port.c_str(), driver_port.c_str(),
                      net_info->driver.cell->name.c_str(),
                      chip.getBelName(src_bel).c_str());

        if (verbose)
            log("    Source wire: %s\n", chip.getWireName(src_wire).c_str());

        std::unordered_map<WireId, DelayInfo> src_wires;
        src_wires[src_wire] = DelayInfo();
        net_info->wires[src_wire] = PipId();
        chip.bindWire(src_wire, net_name);

        for (auto &user_it : net_info->users) {
            if (verbose)
                log("  Route to: %s.%s.\n", user_it.cell->name.c_str(),
                    user_it.port.c_str());

            auto dst_bel = user_it.cell->bel;

            if (dst_bel == BelId())
                log_error("Destination cell %s (%s) is not mapped to a bel.\n",
                          user_it.cell->name.c_str(),
                          user_it.cell->type.c_str());

            if (verbose)
                log("    Destination bel: %s\n",
                    chip.getBelName(dst_bel).c_str());

            IdString user_port = user_it.port;

            auto user_port_it = user_it.cell->pins.find(user_port);

            if (user_port_it != user_it.cell->pins.end())
                user_port = user_port_it->second;

            auto dst_wire =
                    chip.getWireBelPin(dst_bel, portPinFromId(user_port));

            if (dst_wire == WireId())
                log_error("No wire found for port %s (pin %s) on destination "
                          "cell %s (bel %s).\n",
                          user_it.port.c_str(), user_port.c_str(),
                          user_it.cell->name.c_str(),
                          chip.getBelName(dst_bel).c_str());

            if (verbose) {
                log("    Destination wire: %s\n",
                    chip.getWireName(dst_wire).c_str());
                log("    Path delay estimate: %.2f\n",
                    chip.estimateDelay(src_wire, dst_wire));
            }

            std::unordered_map<WireId, QueuedWire> visited;
            std::priority_queue<QueuedWire, std::vector<QueuedWire>,
                                QueuedWire::Greater>
                    queue;

            for (auto &it : src_wires) {
                QueuedWire qw;
                qw.wire = it.first;
                qw.pip = PipId();
                qw.delay = it.second.avgDelay();
                qw.togo = chip.estimateDelay(qw.wire, dst_wire);

                queue.push(qw);
                visited[qw.wire] = qw;
            }

            while (!queue.empty() && !visited.count(dst_wire)) {
                QueuedWire qw = queue.top();
                queue.pop();

                for (auto pip : chip.getPipsDownhill(qw.wire)) {
                    float next_delay = qw.delay;
                    visitCnt++;

                    if (!chip.checkPipAvail(pip)) {
                        if (!ripup || net_name == chip.getPipNet(pip, true))
                            continue;
                        next_delay += ripup_pip_penalty;
                    }

                    WireId next_wire = chip.getPipDstWire(pip);
                    next_delay += chip.getPipDelay(pip).avgDelay();

                    if (visited.count(next_wire)) {
                        if (visited.at(next_wire).delay <= next_delay + 1e-3)
                            continue;
#if 0 // FIXME
                        if (verbose)
                            log("Found better route to %s. Old vs new delay "
                                "estimate: %.2f %.2f\n",
                                chip.getWireName(next_wire).c_str(),
                                visited.at(next_wire).delay, next_delay);
#endif
                        revisitCnt++;
                        continue;
                    }

                    if (!chip.checkWireAvail(next_wire)) {
                        if (!ripup ||
                            net_name == chip.getWireNet(next_wire, true))
                            continue;
                        next_delay += ripup_wire_penalty;
                    }

                    QueuedWire next_qw;
                    next_qw.wire = next_wire;
                    next_qw.pip = pip;
                    next_qw.delay = next_delay;
                    next_qw.togo = chip.estimateDelay(next_wire, dst_wire);
                    visited[next_qw.wire] = next_qw;
                    queue.push(next_qw);
                }
            }

            if (visited.count(dst_wire) == 0) {
                if (verbose)
                    log("Failed to route %s -> %s.\n",
                        chip.getWireName(src_wire).c_str(),
                        chip.getWireName(dst_wire).c_str());
                else if (ripup)
                    log_info("Failed to route %s -> %s.\n",
                             chip.getWireName(src_wire).c_str(),
                             chip.getWireName(dst_wire).c_str());
                ripup_net(design, net_name);
                return;
            }

            if (verbose)
                log("    Final path delay: %.2f\n", visited[dst_wire].delay);
            maxDelay = fmaxf(maxDelay, visited[dst_wire].delay);

            if (verbose)
                log("    Route (from destination to source):\n");

            WireId cursor = dst_wire;

            while (1) {
                if (verbose)
                    log("    %8.2f %s\n", visited[cursor].delay,
                        chip.getWireName(cursor).c_str());

                if (src_wires.count(cursor))
                    break;

                IdString conflicting_net = chip.getWireNet(cursor, true);

                if (conflicting_net != IdString()) {
                    assert(ripup);
                    assert(conflicting_net != net_name);
                    ripup_net(design, conflicting_net);
                    rippedNets.insert(conflicting_net);
                }

                conflicting_net = chip.getPipNet(visited[cursor].pip, true);

                if (conflicting_net != IdString()) {
                    assert(ripup);
                    assert(conflicting_net != net_name);
                    ripup_net(design, conflicting_net);
                    rippedNets.insert(conflicting_net);
                }

                net_info->wires[cursor] = visited[cursor].pip;
                chip.bindWire(cursor, net_name);
                chip.bindPip(visited[cursor].pip, net_name);

                src_wires[cursor] = chip.getPipDelay(visited[cursor].pip);
                cursor = chip.getPipSrcWire(visited[cursor].pip);
            }
        }

        routedOkay = true;
    }
};

} // namespace

NEXTPNR_NAMESPACE_BEGIN

void route_design(Design *design, bool verbose)
{
    auto &chip = design->chip;
    float maxDelay = 0.0;
    float ripup_pip_penalty = 5.0;
    float ripup_wire_penalty = 5.0;

    log_info("Routing..\n");

    std::unordered_set<IdString> netsQueue;

    for (auto &net_it : design->nets) {
        auto net_name = net_it.first;
        auto net_info = net_it.second;

        if (net_info->driver.cell == nullptr)
            continue;

        if (!net_info->wires.empty())
            continue;

        netsQueue.insert(net_name);
    }

    if (netsQueue.empty()) {
        log_info("found no unrouted nets. no routing necessary.\n");
        return;
    }

    log_info("found %d unrouted nets. starting routing procedure.\n",
             int(netsQueue.size()));

    float estimatedTotalDelay = 0.0;
    int estimatedTotalDelayCnt = 0;

    for (auto net_name : netsQueue) {
        auto net_info = design->nets.at(net_name);

        auto src_bel = net_info->driver.cell->bel;

        if (src_bel == BelId())
            continue;

        IdString driver_port = net_info->driver.port;

        auto driver_port_it = net_info->driver.cell->pins.find(driver_port);
        if (driver_port_it != net_info->driver.cell->pins.end())
            driver_port = driver_port_it->second;

        auto src_wire = chip.getWireBelPin(src_bel, portPinFromId(driver_port));

        if (src_wire == WireId())
            continue;

        for (auto &user_it : net_info->users) {
            auto dst_bel = user_it.cell->bel;

            if (dst_bel == BelId())
                continue;

            IdString user_port = user_it.port;

            auto user_port_it = user_it.cell->pins.find(user_port);

            if (user_port_it != user_it.cell->pins.end())
                user_port = user_port_it->second;

            auto dst_wire =
                    chip.getWireBelPin(dst_bel, portPinFromId(user_port));

            if (dst_wire == WireId())
                continue;

            estimatedTotalDelay += chip.estimateDelay(src_wire, dst_wire);
            estimatedTotalDelayCnt++;
        }
    }

    log_info("estimated total wire delay: %.2f (avg %.2f)\n",
             estimatedTotalDelay, estimatedTotalDelay / estimatedTotalDelayCnt);

    while (!netsQueue.empty()) {
        int visitCnt = 0, revisitCnt = 0, netCnt = 0;

        std::unordered_set<IdString> ripupQueue;

        for (auto net_name : netsQueue) {
            Router router(design, net_name, verbose, false);

            netCnt++;
            visitCnt += router.visitCnt;
            revisitCnt += router.revisitCnt;

            if (router.routedOkay) {
                maxDelay = fmaxf(maxDelay, router.maxDelay);
            } else {
                ripupQueue.insert(net_name);
            }

            if (netCnt % 100 == 0)
                log_info("  processed %d nets. (%d routed, %d failed)\n",
                         netCnt, netCnt - int(ripupQueue.size()),
                         int(ripupQueue.size()));
        }

        netsQueue.clear();

        if (netCnt % 100 != 0)
            log_info("  processed %d nets. (%d routed, %d failed)\n", netCnt,
                     netCnt - int(ripupQueue.size()), int(ripupQueue.size()));
        log_info("routing pass visited %d PIPs (%.2f%% revisits).\n", visitCnt,
                 (100.0 * revisitCnt) / visitCnt);

        if (!ripupQueue.empty()) {
            log_info("failed to route %d nets. re-routing in ripup mode.\n",
                     int(ripupQueue.size()));

            visitCnt = 0;
            revisitCnt = 0;
            netCnt = 0;
            int ripCnt = 0;

            for (auto net_name : ripupQueue) {
                Router router(design, net_name, verbose, true,
                              ripup_pip_penalty, ripup_wire_penalty);

                netCnt++;
                visitCnt += router.visitCnt;
                revisitCnt += router.revisitCnt;

                if (!router.routedOkay)
                    log_error("Net %s is impossible to route.\n",
                              net_name.c_str());

                maxDelay = fmaxf(maxDelay, router.maxDelay);

                for (auto it : router.rippedNets)
                    netsQueue.insert(it);

                ripCnt += router.rippedNets.size();

                if (netCnt % 100 == 0)
                    log_info("  routed %d nets, ripped %d nets.\n", netCnt,
                             ripCnt);
            }

            if (netCnt % 100 != 0)
                log_info("  routed %d nets, ripped %d nets.\n", netCnt, ripCnt);
            log_info("routing pass visited %d PIPs (%.2f%% revisits).\n",
                     visitCnt, (100.0 * revisitCnt) / visitCnt);

            log_info("ripped up %d previously routed nets. continue routing.\n",
                     int(netsQueue.size()));

            ripup_pip_penalty *= 1.5;
            ripup_wire_penalty *= 1.5;
        }
    }

    log_info("routing complete. longest path delay: %.2f\n", maxDelay);
}

NEXTPNR_NAMESPACE_END
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Jacob Harvey <jlharvey@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <mss.H>
#include <lib/utils/find.H>
#include <lib/eff_config/timing.H>

namespace mss
{

enum temp_mode : uint8_t
{
    NORMAL = 1,
    EXTENDED = 2,
};

// Proposed DDR4 Full spec update(79-4B)
// Item No. 1716.78C
// pg.46
// Table 24 - tREFI and tRFC parameters (in ps)
constexpr uint64_t TREFI_BASE = 7800000;

// Proposed DDR4 3DS Addendum
// Item No. 1727.58A
// pg. 69 - 71
// Table 42 - Refresh parameters by logical rank density
static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR1 =
{
    // { density in GBs, tRFC4(min) in picoseconds }
    {4, 90000},
    {8, 120000},
    // 16Gb - TBD
};

// Proposed DDR4 3DS Addendum
// Item No. 1727.58A
// pg. 69 - 71
// Table 42 - Refresh parameters by logical rank density
static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR2 =
{
    // { density in GBs, tRFC4(min) in picoseconds }
    {4, 55000},
    {8, 90000}
    // 16Gb - TBD
};

// Proposed DDR4 3DS Addendum
// Item No. 1727.58A
// pg. 69 - 71
// Table 42 - Refresh parameters by logical rank density
static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR4 =
{
    // { density in GBs, tRFC4(min) in picoseconds }
    {4, 40000},
    {8, 55000}
    // 16Gb - TBD
};

///
/// @brief Calculates refresh interval time
/// @param[in] i_mode fine refresh rate mode
/// @param[in] i_temp_refresh_range temperature refresh range
/// @param[out] o_value timing val in ps
/// @return fapi2::ReturnCode
///
fapi2::ReturnCode calc_trefi( const refresh_rate i_mode,
                              const uint8_t i_temp_refresh_range,
                              uint64_t& o_timing )
{
    uint64_t l_multiplier = 0;
    uint64_t l_quotient = 0;
    uint64_t l_remainder = 0;

    switch(i_temp_refresh_range)
    {
        case fapi2::ENUM_ATTR_MSS_MRW_TEMP_REFRESH_RANGE_NORMAL:
            l_multiplier = temp_mode::NORMAL;
            break;

        case fapi2::ENUM_ATTR_MSS_MRW_TEMP_REFRESH_RANGE_EXTEND:
            l_multiplier = temp_mode::EXTENDED;
            break;

        default:
            // Temperature Refresh Range will be a platform attribute set by the MRW,
            // which they "shouldn't" mess up as long as use "attribute" enums.
            // if someone messes this up we can at least catch it
            FAPI_ASSERT( false,
                         fapi2::MSS_INVALID_TEMP_REFRESH()
                         .set_TEMP_REFRESH_RANGE(i_temp_refresh_range),
                         "Incorrect Temperature Ref. Range received: %d ",
                         i_temp_refresh_range);
            break;
    }

    l_quotient = TREFI_BASE / ( int64_t(i_mode) * l_multiplier );
    l_remainder = TREFI_BASE % ( int64_t(i_mode) * l_multiplier );
    o_timing = l_quotient + (l_remainder == 0 ? 0 : 1);

    FAPI_INF( "tREFI: %d, quotient: %d, remainder: %d, tREFI_base: %d",
              o_timing, l_quotient, l_remainder, TREFI_BASE );

    // FAPI_ASSERT doesn't set current error to good
    return fapi2::FAPI2_RC_SUCCESS;
fapi_try_exit:
    return fapi2::current_err;
}

/// @brief Calculates Minimum Refresh Recovery Delay Time (different logical rank)
/// @param[in] i_mode fine refresh rate mode
/// @param[in] i_density SDRAM density
/// @param[out] o_trfc_in_ps timing val in ps
/// @return fapi2::FAPI2_RC_SUCCESS iff okay
///
fapi2::ReturnCode calc_trfc_dlr(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
                                const uint8_t i_refresh_mode,
                                const uint8_t i_density,
                                uint64_t& o_trfc_in_ps)
{
    bool l_is_val_found = 0;

    // Selects appropriate tRFC based on fine refresh mode
    switch(i_refresh_mode)
    {
        case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_NORMAL:
            l_is_val_found = find_value_from_key(TRFC_DLR1, i_density, o_trfc_in_ps);
            break;

        case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_2X:
        case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_2X:
            l_is_val_found = find_value_from_key(TRFC_DLR2, i_density, o_trfc_in_ps);
            break;

        case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_4X:
        case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_4X:
            l_is_val_found = find_value_from_key(TRFC_DLR4, i_density, o_trfc_in_ps);
            break;

        default:
            // Fine Refresh Mode will be a platform attribute set by the MRW,
            // which they "shouldn't" mess up as long as use "attribute" enums.
            // if openpower messes this up we can at least catch it
            FAPI_ASSERT( false,
                         fapi2::MSS_INVALID_FINE_REFRESH()
                         .set_REFRESH_MODE(i_refresh_mode),
                         "Incorrect Fine Refresh Mode received: %d ",
                         i_refresh_mode);
            break;
    }// switch

    FAPI_ASSERT( l_is_val_found,
                 fapi2::MSS_FAILED_TO_FIND_TRFC()
                 .set_SDRAM_DENSITY(i_density)
                 .set_REFRESH_MODE(i_refresh_mode)
                 .set_TARGET(i_target),
                 "%s: Unable to find tRFC (ps) from map with SDRAM density key %d with %d refresh mode",
                 mss::c_str(i_target),
                 i_density,
                 i_refresh_mode);

    // Again, FAPI_ASSERT doesn't set current_err to good, only to bad
    return fapi2::FAPI2_RC_SUCCESS;
fapi_try_exit:
    return fapi2::current_err;
}

}// mss
<commit_msg>Move find API to share among memory controllers<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/eff_config/timing.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
// *HWP HWP Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP HWP Backup: Jacob Harvey <jlharvey@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <mss.H>
#include <generic/memory/lib/utils/find.H>
#include <lib/eff_config/timing.H>

namespace mss
{

enum temp_mode : uint8_t
{
    NORMAL = 1,
    EXTENDED = 2,
};

// Proposed DDR4 Full spec update(79-4B)
// Item No. 1716.78C
// pg.46
// Table 24 - tREFI and tRFC parameters (in ps)
constexpr uint64_t TREFI_BASE = 7800000;

// Proposed DDR4 3DS Addendum
// Item No. 1727.58A
// pg. 69 - 71
// Table 42 - Refresh parameters by logical rank density
static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR1 =
{
    // { density in GBs, tRFC4(min) in picoseconds }
    {4, 90000},
    {8, 120000},
    // 16Gb - TBD
};

// Proposed DDR4 3DS Addendum
// Item No. 1727.58A
// pg. 69 - 71
// Table 42 - Refresh parameters by logical rank density
static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR2 =
{
    // { density in GBs, tRFC4(min) in picoseconds }
    {4, 55000},
    {8, 90000}
    // 16Gb - TBD
};

// Proposed DDR4 3DS Addendum
// Item No. 1727.58A
// pg. 69 - 71
// Table 42 - Refresh parameters by logical rank density
static const std::vector<std::pair<uint8_t, uint64_t> > TRFC_DLR4 =
{
    // { density in GBs, tRFC4(min) in picoseconds }
    {4, 40000},
    {8, 55000}
    // 16Gb - TBD
};

///
/// @brief Calculates refresh interval time
/// @param[in] i_mode fine refresh rate mode
/// @param[in] i_temp_refresh_range temperature refresh range
/// @param[out] o_value timing val in ps
/// @return fapi2::ReturnCode
///
fapi2::ReturnCode calc_trefi( const refresh_rate i_mode,
                              const uint8_t i_temp_refresh_range,
                              uint64_t& o_timing )
{
    uint64_t l_multiplier = 0;
    uint64_t l_quotient = 0;
    uint64_t l_remainder = 0;

    switch(i_temp_refresh_range)
    {
        case fapi2::ENUM_ATTR_MSS_MRW_TEMP_REFRESH_RANGE_NORMAL:
            l_multiplier = temp_mode::NORMAL;
            break;

        case fapi2::ENUM_ATTR_MSS_MRW_TEMP_REFRESH_RANGE_EXTEND:
            l_multiplier = temp_mode::EXTENDED;
            break;

        default:
            // Temperature Refresh Range will be a platform attribute set by the MRW,
            // which they "shouldn't" mess up as long as use "attribute" enums.
            // if someone messes this up we can at least catch it
            FAPI_ASSERT( false,
                         fapi2::MSS_INVALID_TEMP_REFRESH()
                         .set_TEMP_REFRESH_RANGE(i_temp_refresh_range),
                         "Incorrect Temperature Ref. Range received: %d ",
                         i_temp_refresh_range);
            break;
    }

    l_quotient = TREFI_BASE / ( int64_t(i_mode) * l_multiplier );
    l_remainder = TREFI_BASE % ( int64_t(i_mode) * l_multiplier );
    o_timing = l_quotient + (l_remainder == 0 ? 0 : 1);

    FAPI_INF( "tREFI: %d, quotient: %d, remainder: %d, tREFI_base: %d",
              o_timing, l_quotient, l_remainder, TREFI_BASE );

    // FAPI_ASSERT doesn't set current error to good
    return fapi2::FAPI2_RC_SUCCESS;
fapi_try_exit:
    return fapi2::current_err;
}

/// @brief Calculates Minimum Refresh Recovery Delay Time (different logical rank)
/// @param[in] i_mode fine refresh rate mode
/// @param[in] i_density SDRAM density
/// @param[out] o_trfc_in_ps timing val in ps
/// @return fapi2::FAPI2_RC_SUCCESS iff okay
///
fapi2::ReturnCode calc_trfc_dlr(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target,
                                const uint8_t i_refresh_mode,
                                const uint8_t i_density,
                                uint64_t& o_trfc_in_ps)
{
    bool l_is_val_found = 0;

    // Selects appropriate tRFC based on fine refresh mode
    switch(i_refresh_mode)
    {
        case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_NORMAL:
            l_is_val_found = find_value_from_key(TRFC_DLR1, i_density, o_trfc_in_ps);
            break;

        case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_2X:
        case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_2X:
            l_is_val_found = find_value_from_key(TRFC_DLR2, i_density, o_trfc_in_ps);
            break;

        case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FIXED_4X:
        case fapi2::ENUM_ATTR_MSS_MRW_FINE_REFRESH_MODE_FLY_4X:
            l_is_val_found = find_value_from_key(TRFC_DLR4, i_density, o_trfc_in_ps);
            break;

        default:
            // Fine Refresh Mode will be a platform attribute set by the MRW,
            // which they "shouldn't" mess up as long as use "attribute" enums.
            // if openpower messes this up we can at least catch it
            FAPI_ASSERT( false,
                         fapi2::MSS_INVALID_FINE_REFRESH()
                         .set_REFRESH_MODE(i_refresh_mode),
                         "Incorrect Fine Refresh Mode received: %d ",
                         i_refresh_mode);
            break;
    }// switch

    FAPI_ASSERT( l_is_val_found,
                 fapi2::MSS_FAILED_TO_FIND_TRFC()
                 .set_SDRAM_DENSITY(i_density)
                 .set_REFRESH_MODE(i_refresh_mode)
                 .set_TARGET(i_target),
                 "%s: Unable to find tRFC (ps) from map with SDRAM density key %d with %d refresh mode",
                 mss::c_str(i_target),
                 i_density,
                 i_refresh_mode);

    // Again, FAPI_ASSERT doesn't set current_err to good, only to bad
    return fapi2::FAPI2_RC_SUCCESS;
fapi_try_exit:
    return fapi2::current_err;
}

}// mss
<|endoftext|>


<commit_before><commit_msg>Increasing AI spawn timer from 30 > 60 seconds.<commit_after><|endoftext|>