The quickest thing I can think of is remove the instance variable from you Terminal class altogether. Define your Terminal class this way:
Code:
#pragma once
#include "stddef.h"
#include "stdint.h"
class Terminal
{
static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 25;
size_t row;
size_t column;
uint16_t* buffer;
public:
static constexpr const char* Status = "$WHITE![$LIGHT_BLUE!--$WHITE!] $LIGHT_GREY!\0";
static constexpr const char* Good = "$WHITE![$LIGHT_GREEN!:)$WHITE!] $LIGHT_GREY!\0";
static constexpr const char* EOL = "\n";
static Terminal &instance();
void put_entry_at(char c, uint8_t color, size_t x, size_t y);
void put_char(char c, uint8_t color);
void write(const char* data, size_t size);
void write(const char* data);
void write(int num);
void println(const char* data = "");
void shift();
private:
Terminal();
Terminal(Terminal const&);
void operator=(Terminal const&);
};
template<typename T>
Terminal& operator<<(Terminal& term, T data)
{
term.write(data);
return term;
}
template<typename T>
Terminal* operator<<(Terminal* term, T data)
{
term->write(data);
return term;
}
I have deleted the `instance` variable (in the header and in the Terminal.cpp file) and created an `instance` function that returns a Terminal reference. I have also made the constructor private so that you can't create a Terminal object directly. In your Terminal.cpp you can add this new instance function:
Code:
Terminal &Terminal::instance()
{
static Terminal instance;
return instance;
}
This has a static `Terminal` object called 'instance' in it. We just return a reference to that object to the caller. The instance() function will take care of initializing `instance` by calling its constructor if needed. This is what produces a singleton object. To use it in Kernel.cpp you'd do something like:
Code:
void kernel_main()
{
Terminal &terminal = Terminal::instance();
terminal << logo;
terminal << Terminal::EOL;
// rest of code here
}
In your ISRHandlerImpl you could use it like:
Code:
Terminal::instance().write(keycode);
Terminal::instance().write("\n");
Depending on your compiler you may also have to add the option `'-fno-threadsafe-statics'` to meson.build compile arguments. This is because many compilers will produce thread safe code around the static local object ('instance' in this case). This could generate calls to functions you haven't implemented that maintain thread safe access to these objects. Implementing the required functions to maintain thread safety would be the best course of action in the long term. There is a page somewhere on the OSDev Wiki about the functions that need to be implemented.