The reason why your carriage return and line feed characters are displaying wrong is because the VGA doesn't understand text flow, it's just a grid of characters. Think of it like this (ignoring colour):
Code: Select all
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
When you put the text "hello world" on the screen, it becomes this:
Code: Select all
[h][e][l][l][o][ ][w][o][r][l]
[d][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
The text wraps because each "box" is a memory location and the first line of boxes comes first in memory, followed by the second line of boxes, and so on.
Suppose you change the text to "hello\nworld" ("\n" refers to the line feed character). Your character grid will become:
Code: Select all
[h][e][l][l][o][*][w][o][r][l]
[d][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
where "*" is the line feed character. The VGA doesn't put the text on the next line, because the characters are in the memory locations for the previous line. Control characters (most commonly carriage return, line feed, tab, and delete) don't mean anything to it. This means that you have to handle these characters yourself, by changing the memory address at which you put the characters to "skip" to the next line:
Code: Select all
[h][e][l][l][o][ ][ ][ ][ ][ ]
[w][o][r][l][d][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
Notice that there is a row of blank "boxes" after the word "hello" continuing to the end of the line, before the word "world" appears. In the computer's memory, which is a single straight line, this appears as:
Code: Select all
[h][e][l][l][o][ ][ ][ ][ ][ ][w][o][r][l][d][ ][ ][ ][ ][ ]...
The reason why you get music notes and triangles is because, since the VGA doesn't understand these control characters, they're used to display extra symbols. All of the character codes from 0x00 to 0x1F (0x20 is a space) are used like this. A similar thing is done with the characters from 0x7F (delete) upwards, and you can find a table of all of the available characters
here.
Also note that some platforms use both a carriage return and a line feed to represent a newline, and others use just a line feed. When you display this, you want to display only a single new line. My preferred way to handle this is to output a new line whenever the line feed character occurs in the source string and to ignore the carriage return without either outputting it to the screen or changing the address where the next character will be located. This will handle both platforms that use a carriage return and a line feed and those that use just a line feed, and you don't need to detect the sequence of a carriage return followed by a line feed and can simply handle each character on its own.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.
Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing