aboutsummaryrefslogtreecommitdiffstats
path: root/src/vgaterminal.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vgaterminal.cpp')
-rw-r--r--src/vgaterminal.cpp63
1 files changed, 63 insertions, 0 deletions
diff --git a/src/vgaterminal.cpp b/src/vgaterminal.cpp
new file mode 100644
index 0000000..5f86081
--- /dev/null
+++ b/src/vgaterminal.cpp
@@ -0,0 +1,63 @@
+#include "portio.hpp"
+#include "vgaterminal.hpp"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <utility>
+
+void VGATerminal::write(char c) noexcept
+{
+ checkpos();
+
+ switch (c) {
+ case '\b':
+ if (offset % Width) {
+ --offset;
+ put(' ');
+ --offset;
+ }
+ break;
+ case '\n':
+ offset += Width;
+ [[fallthrough]];
+ case '\r':
+ offset -= offset % Width;
+ break;
+ default:
+ put(c);
+ break;
+ }
+
+ updatecursor();
+}
+
+void VGATerminal::put(char c) noexcept
+{
+ std::uint16_t cell = c
+ | (std::to_underlying(foreground) << 8)
+ | (std::to_underlying(background) << 12);
+
+ auto ptr = reinterpret_cast<std::uint16_t *>(Videoram);
+ ptr[offset++] = cell;
+}
+
+void VGATerminal::checkpos() noexcept
+{
+ if (offset >= Width * Height) {
+ auto ptr = reinterpret_cast<std::uint16_t *>(Videoram);
+ const auto end = ptr + Width * Height;
+ std::copy(ptr + Width, end, ptr);
+ std::fill(end - Width, end, 0);
+ offset = Width * Height - Width;
+ }
+}
+
+void VGATerminal::updatecursor() const noexcept
+{
+ outb(0x03d4, 0x0f);
+ outb(0x03d5, static_cast<std::uint8_t>(offset));
+ outb(0x03d4, 0x0e);
+ outb(0x03d5, static_cast<std::uint8_t>(offset >> 8));
+}
+