aboutsummaryrefslogtreecommitdiffstats
path: root/src/vgaterminal.cpp
blob: 5f860810ab77535447bb35842fb193939b453167 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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));
}