diff --git a/src/hulk/console.d b/src/hulk/console.d new file mode 100644 index 0000000..dc08126 --- /dev/null +++ b/src/hulk/console.d @@ -0,0 +1,72 @@ +/** + * HULK Console functionality. + */ +module hulk.console; + +import hulk.framebuffer; +import hulk.kfont; + +struct Console +{ + Framebuffer * m_fb; + size_t m_width; + size_t m_height; + size_t m_x; + size_t m_y; + + public void initialize(Framebuffer * fb) + { + m_fb = fb; + m_width = fb.width / kfont.advance; + m_height = fb.height / kfont.line_height; + } + + public void clear() + { + m_fb.clear(); + m_x = 0u; + m_y = 0u; + } + + public void write(char ch) + { + if (ch == '\n') + { + m_x = 0u; + m_y++; + } + else + { + render_char(m_x, m_y, ch); + m_x++; + if (m_x == m_width) + { + m_x = 0u; + m_y++; + } + } + if (m_y == m_height) + { + m_y--; + m_fb.copy_rows_up(fb_y(m_height - 1u), + (m_height - 1u) * kfont.line_height, + kfont.line_height); + } + } + + private void render_char(size_t x, size_t y, char ch) + { + const(CharInfo) * ci = &kfont.chars[ch]; + m_fb.blit_alpha_bitmap(fb_x(x) + ci.left, fb_y(y) + ci.top - ci.height, ci.bitmap, ci.width, ci.height); + } + + private size_t fb_x(size_t x) + { + return x * kfont.advance; + } + + private size_t fb_y(size_t y) + { + return m_fb.height - ((y + 1u) * kfont.line_height); + } +} diff --git a/src/hulk/framebuffer.d b/src/hulk/framebuffer.d index 8398901..2568661 100644 --- a/src/hulk/framebuffer.d +++ b/src/hulk/framebuffer.d @@ -28,6 +28,22 @@ struct Framebuffer /** Number of pixels in the frame buffer (whether visible or not). */ private uint m_buffer_size; + /** + * Get the framebuffer width. + */ + public @property uint width() + { + return m_width; + } + + /** + * Get the framebuffer height. + */ + public @property uint height() + { + return m_height; + } + /** * Initialize a frame buffer. * @@ -168,6 +184,52 @@ struct Framebuffer blend_alpha_bitmap(x, y, alpha_bitmap.ptr, width, height, color); } + /** + * Blit an 8-bit alpha bitmap to the framebuffer. + * The foreground will be white (based on the alpha value), and the + * background black. + * + * @param x X coordinate of left side of target location. + * @param y Y coordinate of bottom side of target location. + * @param alpha_bitmap 8-bit alpha-channel bitmap. + * @param width Bitmap width. + * @param height Bitmap height. + */ + void blit_alpha_bitmap(size_t x, size_t y, const(ubyte) * alpha_bitmap, + size_t width, size_t height) + { + y += height - 1u; + size_t bitmap_index; + for (size_t iy = 0u; iy < height; iy++) + { + for (size_t ix = 0u; ix < width; ix++) + { + size_t buffer_index = buffer_index(x + ix, y); + ubyte alpha = alpha_bitmap[bitmap_index]; + m_buffer[buffer_index] = (alpha << 16u) | (alpha << 8u) | alpha; + bitmap_index++; + } + y--; + } + } + + /** + * Blit an 8-bit alpha bitmap to the framebuffer. + * The foreground will be white (based on the alpha value), and the + * background black. + * + * @param x X coordinate of left side of target location. + * @param y Y coordinate of bottom side of target location. + * @param alpha_bitmap 8-bit alpha-channel bitmap. + * @param width Bitmap width. + * @param height Bitmap height. + */ + void blit_alpha_bitmap(size_t x, size_t y, const(ubyte)[] alpha_bitmap, + size_t width, size_t height) + { + blit_alpha_bitmap(x, y, alpha_bitmap.ptr, width, height); + } + /** * Copy framebuffer rows up in the framebuffer. * diff --git a/src/hulk/hulk.d b/src/hulk/hulk.d index 148d92a..d265b76 100644 --- a/src/hulk/hulk.d +++ b/src/hulk/hulk.d @@ -6,11 +6,14 @@ module hulk.hulk; import hulk.header; import hulk.bootinfo; import hulk.framebuffer; +import hulk.console; import hos.memory; import ldc.attributes; import hulk.kfont; +static import hulk.klog; private __gshared Framebuffer fb; +private __gshared Console console; extern extern(C) __gshared ubyte _hulk_total_size; @@ -44,6 +47,15 @@ extern(C) void hulk_start(ulong rdi, ulong rsi, ulong rdx, BootInfo * bootinfo) x += kfont.advance; } + console.initialize(&fb); + console.clear(); + hulk.klog.initialize(&console); + + for (size_t i = 1u; i != 0u; i++) + { + hulk.klog.writef("Hello! i = %010u\n", i); + } + for (;;) { } diff --git a/src/hulk/klog.d b/src/hulk/klog.d new file mode 100644 index 0000000..c3fb32b --- /dev/null +++ b/src/hulk/klog.d @@ -0,0 +1,76 @@ +/** + * HULK Kernel Log buffer. + */ +module hulk.klog; + +import core.stdc.stdarg; +import hulk.console; +static import hulk.writef; + +/** + * Kernel buffer size log. + * 16 gives a kernel buffer size of 64KB. + */ +enum size_t KLOG_SIZE_LOG = 16u; + +/** Kernel buffer size. */ +enum size_t KLOG_SIZE = 1u << KLOG_SIZE_LOG; + +/** Kernel log buffer. */ +private __gshared align(4096) char[KLOG_SIZE] klog_buffer; + +/** Write index in the kernel log buffer. */ +private __gshared size_t klog_index; + +/** Pointer to the console to use for kernel log output. */ +private __gshared Console * console; + +/** + * Initialize the klog module. + * + * @param console Pointer to the Console to use for kernel output. + */ +void initialize(Console * console) +{ + .console = console; +} + +/** + * Write a formatted string to the kernel log. + * + * @param s Format string. + * @param args Variable arguments structure. + */ +void writef(string s, va_list args) +{ + hulk.writef.writef(s, args, function void(ubyte ch) { + console.write(ch); + }); +} + +/** + * Write a formatted string to the kernel log. + * + * @param s Format string. + */ +extern (C) void writef(string s, ...) +{ + va_list args; + va_start(args, s); + writef(s, args); + va_end(args); +} + +/** + * Write a formatted string and newline to the console. + * + * @param s Format string. + */ +extern (C) void writefln(string s, ...) +{ + va_list args; + va_start(args, s); + writef(s, args); + writef("\n", args); + va_end(args); +} diff --git a/src/hulk/writef.d b/src/hulk/writef.d new file mode 100644 index 0000000..5f183c3 --- /dev/null +++ b/src/hulk/writef.d @@ -0,0 +1,151 @@ +/** + * HULK Formatted stream writing support. + */ +module hulk.writef; + +import core.stdc.stdarg; + +alias ch_out_fn = void function(ubyte); + +/** + * Format a string and write characters to the given output function. + * + * @param s Format string. + * @param args Variable arguments structure. + * @param ch_out Character output function. + * + * @return Number of characters written. + */ +size_t writef(string s, va_list args, ch_out_fn ch_out) +{ + size_t length_written; + bool escape = false; + char pad = ' '; + size_t width; + foreach (char c; s) + { + if (escape) + { + if (c == 'x') + { + ulong v; + va_arg(args, v); + length_written += write_hex(v, false, pad, width, ch_out); + escape = false; + } + else if (c == 'X') + { + ulong v; + va_arg(args, v); + length_written += write_hex(v, true, pad, width, ch_out); + escape = false; + } + else if (c == 'u') + { + ulong v; + va_arg(args, v); + length_written += write_udec(v, pad, width, ch_out); + escape = false; + } + else if ((c == '0') && (width == 0u)) + { + pad = '0'; + } + else if (('0' <= c) && (c <= '9')) + { + width = (width * 10u) + (c - '0'); + } + else + { + ch_out(c); + escape = false; + } + } + else if (c == '%') + { + escape = true; + pad = ' '; + width = 0u; + } + else + { + ch_out(c); + } + } + return length_written; +} + +/** + * Format a value in hexadecimal to the given output function. + * + * @param v Value to format. + * @param upper Whether to use uppercase letters. + * @param pad Pad character to use. + * @param width Field width. + * @param ch_out Character output function. + * + * @return Number of characters written. + */ +private size_t write_hex(ulong v, bool upper, char pad, size_t width, ch_out_fn ch_out) +{ + string hex_chars_lower = "0123456789abcdef"; + string hex_chars_upper = "0123456789ABCDEF"; + char[16] buf; + size_t i; + do + { + ulong n = v & 0xFu; + buf[i] = upper ? hex_chars_upper[n] : hex_chars_lower[n]; + v >>= 4u; + i++; + } while (v != 0u); + size_t length_written = i; + while (width > i) + { + ch_out(pad); + width--; + length_written++; + } + do + { + i--; + ch_out(buf[i]); + } while (i != 0u); + return length_written; +} + +/** + * Format a value in decimal to the given output function. + * + * @param v Value to format. + * @param pad Pad character to use. + * @param width Field width. + * @param ch_out Character output function. + * + * @return Number of characters written. + */ +private size_t write_udec(ulong v, char pad, size_t width, ch_out_fn ch_out) +{ + char[20] buf; + size_t i; + do + { + ulong d = v % 10u; + buf[i] = cast(char)(d + '0'); + v /= 10u; + i++; + } while (v != 0u); + size_t length_written = i; + while (width > i) + { + ch_out(pad); + width--; + length_written++; + } + do + { + i--; + ch_out(buf[i]); + } while (i != 0u); + return length_written; +}