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:
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]
When you put the text "hello world" on the screen, it becomes this:
Code:
[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:
[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:
[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:
[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.