aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2025-12-17 16:20:53 +0100
committerFelix Morgner <felix.morgner@ost.ch>2025-12-17 16:21:16 +0100
commit801710fbce45bbe14d4bc927afc45a973bbf286f (patch)
treebacf835d7242d879a7b52ee03a220e95358aed9a
parent81a434499424f432a576469aad402ff18e05e6b4 (diff)
downloadteachos-801710fbce45bbe14d4bc927afc45a973bbf286f.tar.xz
teachos-801710fbce45bbe14d4bc927afc45a973bbf286f.zip
x86_64/vga: fix scrolling implementation
-rw-r--r--arch/x86_64/include/x86_64/boot/boot.hpp2
-rw-r--r--arch/x86_64/include/x86_64/vga/text.hpp19
-rw-r--r--arch/x86_64/src/vga/text.cpp50
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