Oh god. So much work just to avoid calling memmove()... Wait, that code is not even a memmove(), it's a memcpy(). And all just because the author failed to write C and wrote assembler instead. Here's how I would do it:
Code: Select all
#define SCREEN (uint16_t*)0xB8000
void terminal_scroll(int line) {
memcpy(SCREEN + (line - 1) * VGA_WIDTH, SCREEN + line * VGA_WIDTH, VGA_WIDTH * sizeof(uint16_t));
}
There, that is it. That is what that code is trying to do: Copy the given line into the previous one. Done. No bloody loop, no bloody pointer casts, no assembler disguised as C. Just using the language somewhat as it was intended.
You could even model the screen as a two-dimensional array and let the compiler do the dirty work.
Code: Select all
typedef uint16_t screen_t[VGA_HEIGHT][VGA_WIDTH];
#define SCREEN (*(screen_t*)0xB8000)
void terminal_scroll(int line) {
memcpy(SCREEN[line - 1], SCREEN[line], sizeof (SCREEN[0]));
}
The function is still terrible, since if it is called with an out-of-bounds argument (and 0 counts as out-of-bounds), it will fail horribly. It is only used in a single place, and there it is used to scroll the whole screen. So this could just be replaced with
Code: Select all
typedef uint16_t screen_t[VGA_HEIGHT][VGA_WIDTH];
#define SCREEN (*(screen_t*)0xB8000)
void terminal_scroll_whole_screen(void) {
memmove(&SCREEN[0][0], &SCREEN[1][0], (VGA_HEIGHT - 1) * VGA_WIDTH * sizeof (uint16_t));
memset(SCREEN[VGA_HEIGHT - 1], 0, sizeof (SCREEN[0]));
}
Now only someone needs to test this code I just came up with.