diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2025-12-17 16:20:53 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2025-12-17 16:21:16 +0100 |
| commit | 801710fbce45bbe14d4bc927afc45a973bbf286f (patch) | |
| tree | bacf835d7242d879a7b52ee03a220e95358aed9a | |
| parent | 81a434499424f432a576469aad402ff18e05e6b4 (diff) | |
| download | teachos-801710fbce45bbe14d4bc927afc45a973bbf286f.tar.xz teachos-801710fbce45bbe14d4bc927afc45a973bbf286f.zip | |
x86_64/vga: fix scrolling implementation
| -rw-r--r-- | arch/x86_64/include/x86_64/boot/boot.hpp | 2 | ||||
| -rw-r--r-- | arch/x86_64/include/x86_64/vga/text.hpp | 19 | ||||
| -rw-r--r-- | arch/x86_64/src/vga/text.cpp | 50 |
3 files changed, 53 insertions, 18 deletions
diff --git a/arch/x86_64/include/x86_64/boot/boot.hpp b/arch/x86_64/include/x86_64/boot/boot.hpp index 2c44659..0db2396 100644 --- a/arch/x86_64/include/x86_64/boot/boot.hpp +++ b/arch/x86_64/include/x86_64/boot/boot.hpp @@ -60,7 +60,7 @@ namespace teachos::boot multiboot2::information_view const * mbi; //! The index of the next character to be written in the VGA text buffer after handoff. - std::size_t vga_buffer_index; + std::ptrdiff_t vga_buffer_index; }; } // namespace teachos::boot diff --git a/arch/x86_64/include/x86_64/vga/text.hpp b/arch/x86_64/include/x86_64/vga/text.hpp index bb593e7..9f80f94 100644 --- a/arch/x86_64/include/x86_64/vga/text.hpp +++ b/arch/x86_64/include/x86_64/vga/text.hpp @@ -3,9 +3,11 @@ #include "kapi/cio.hpp" +#include <cstddef> #include <cstdint> #include <span> #include <string_view> +#include <utility> namespace teachos::vga::x86_64::text { @@ -123,14 +125,17 @@ namespace teachos::vga::x86_64::text { write(text, common_attributes::green_on_black); } + auto writeln(std::string_view text) -> void override { writeln(text, common_attributes::green_on_black); } + auto write_error(std::string_view text) -> void override { write(text, common_attributes::red_on_black); } + auto writeln_error(std::string_view text) -> void override { writeln(text, common_attributes::red_on_black); @@ -139,11 +144,19 @@ namespace teachos::vga::x86_64::text private: using glyph = std::pair<char, std::byte>; + [[nodiscard]] auto column() const noexcept -> std::ptrdiff_t; + [[nodiscard]] auto line() const noexcept -> std::ptrdiff_t; + /** * @brief Move the cursor to a new line, scrolling the buffer if necessary. */ auto newline() -> void; + //! Scroll the screen by a number of lines. + //! + //! @param nof_lines The number of lines to scroll up. + auto scroll(std::ptrdiff_t nof_lines = 1) -> void; + /** * @brief Write a string of code points to the VGA text buffer. * @@ -155,6 +168,10 @@ namespace teachos::vga::x86_64::text */ auto write(std::string_view code_points, attribute attribute) -> void; + //! Write a single code point to the VGA text buffer. + //! + //! @param code_point A single (8-bit) code point + //! @param attribute The #attribute to apply to the code point. auto write(char code_point, attribute attribute) -> void; /** @@ -170,7 +187,7 @@ namespace teachos::vga::x86_64::text std::span<glyph> static const buffer; - std::size_t m_position{}; + std::ptrdiff_t m_position{}; }; } // namespace teachos::vga::x86_64::text diff --git a/arch/x86_64/src/vga/text.cpp b/arch/x86_64/src/vga/text.cpp index c9eee71..d4548a2 100644 --- a/arch/x86_64/src/vga/text.cpp +++ b/arch/x86_64/src/vga/text.cpp @@ -19,8 +19,8 @@ namespace teachos::vga::x86_64::text namespace { constexpr auto BUFFER_BASE_ADDRESS = std::uintptr_t{0xb8000}; - constexpr auto DEFAULT_TEXT_BUFFER_WIDTH = 80U; - constexpr auto DEFAULT_TEXT_BUFFER_HEIGHT = 25U; + constexpr auto DEFAULT_TEXT_BUFFER_WIDTH = 80z; + constexpr auto DEFAULT_TEXT_BUFFER_HEIGHT = 25z; constexpr auto CURSOR_ENABLED_BIT = 5U; } // namespace @@ -47,22 +47,33 @@ namespace teachos::vga::x86_64::text crtc::data::write(crtc::data::read() | cursor_disable_byte); } + [[nodiscard]] auto device::column() const noexcept -> std::ptrdiff_t + { + return m_position % DEFAULT_TEXT_BUFFER_WIDTH; + } + + [[nodiscard]] auto device::line() const noexcept -> std::ptrdiff_t + { + return m_position / DEFAULT_TEXT_BUFFER_WIDTH; + } + auto device::newline() -> void { - auto current_line = m_position / DEFAULT_TEXT_BUFFER_WIDTH; - auto next_line = current_line + 1; + auto free_glyphs_in_line = DEFAULT_TEXT_BUFFER_WIDTH - column(); + m_position += free_glyphs_in_line; + } - if (std::cmp_greater_equal(next_line, DEFAULT_TEXT_BUFFER_HEIGHT)) - { - auto begin = buffer.begin() + DEFAULT_TEXT_BUFFER_WIDTH; - auto end = buffer.begin() + DEFAULT_TEXT_BUFFER_WIDTH * DEFAULT_TEXT_BUFFER_HEIGHT; - std::ranges::move(begin, end, buffer.begin()); - m_position = current_line * DEFAULT_TEXT_BUFFER_WIDTH; - } - else - { - m_position = next_line * DEFAULT_TEXT_BUFFER_WIDTH; - } + auto device::scroll(std::ptrdiff_t nof_lines) -> void + { + auto scroll_count = std::min(nof_lines, DEFAULT_TEXT_BUFFER_HEIGHT); + + auto scroll_start = buffer.begin() + (scroll_count * DEFAULT_TEXT_BUFFER_WIDTH); + std::ranges::move(scroll_start, buffer.end(), buffer.begin()); + + auto clear_start = buffer.begin() + (DEFAULT_TEXT_BUFFER_HEIGHT - scroll_count) * DEFAULT_TEXT_BUFFER_WIDTH; + std::ranges::fill(clear_start, buffer.end(), glyph{}); + + m_position = (line() - scroll_count) * DEFAULT_TEXT_BUFFER_WIDTH; } auto device::write(std::string_view code_points, attribute attribute) -> void @@ -72,13 +83,20 @@ namespace teachos::vga::x86_64::text auto device::write(char code_point, attribute attribute) -> void { + if (m_position + 1 > DEFAULT_TEXT_BUFFER_HEIGHT * DEFAULT_TEXT_BUFFER_WIDTH) + { + scroll(); + } buffer[m_position++] = std::pair{code_point, std::bit_cast<std::byte>(attribute)}; }; auto device::writeln(std::string_view code_points, attribute attribute) -> void { std::ranges::for_each(code_points, [&](auto code_point) -> void { write(code_point, attribute); }); - newline(); + if (column()) + { + newline(); + } } } // namespace teachos::vga::x86_64::text |
