Page 1 of 2

[C]Print a character

Posted: Thu Dec 22, 2016 11:33 am
by leosa99
Hi !
I'm trying to print a character to the screen with this code :

Code: Select all

#define RAMSCREEN 0xB8000 // Video address.

void printCharacter(char row, char column) // It print a character at the selected location.
{
unsigned char *res_location;
res_location = (unsigned char*)(RAMSCREEN + 2 * (row * 80 + column));
res_location[0]='W';
res_location[1]=0xd;
}
I call it with :

Code: Select all

printCharacter(1,3);
It does not print the "W" at (1;3) but at an other place.

Re: [C]Print a character

Posted: Thu Dec 22, 2016 11:55 am
by jojo
Your math is alllll screwy. Remember that the general rule for placing a value at (x, y) is

Code: Select all

bitmap_buffer[y * bitmap_width + x]
Also, C order of operations generally follows standard PEMDAS. But if you're not sure, use parens.

Re: [C]Print a character

Posted: Thu Dec 22, 2016 12:03 pm
by IanSeyler
Can you try the following?:

Code: Select all

(RAMSCREEN + (2 * (row * 80 + column)))

Re: [C]Print a character

Posted: Thu Dec 22, 2016 12:29 pm
by leosa99
In fact I already tried, it still doesn't work ...

Re: [C]Print a character

Posted: Thu Dec 22, 2016 12:33 pm
by hgoel
Just to make sure, what happens if you call it row and column set to 0?

Re: [C]Print a character

Posted: Thu Dec 22, 2016 12:41 pm
by leosa99
If I call it row and column set to 0 the location of the "W" does not change.

Re: [C]Print a character

Posted: Thu Dec 22, 2016 12:53 pm
by hgoel
Does changing the parameters in any way change anything at all?

Re: [C]Print a character

Posted: Thu Dec 22, 2016 1:09 pm
by leosa99
No it does not change anything.

Re: [C]Print a character

Posted: Thu Dec 22, 2016 3:52 pm
by Schol-R-LEA
Might I suggest that rather than trying to muck about with a pointer, you treat the buffer as two-dimensional array of a struct containing the two bytes?

Code: Select all

typedef struct {
    uint8_t attrib;
    unsigned char glyph;
} TEXT_FRAME;

TEXT_FRAME *text_buffer = (TEXT_FRAME *) 0xb8000;

#define COLUMN_OFFSET 80

// ...

    text_buffer[(rows * COLUMN_OFFSET) + columns].glyph = 'W';
    text_buffer[(rows * COLUMN_OFFSET) + columns].attrib = 0xd;
Actually, given that there are several text modes, and you also need to bounds-check the text buffer (among other things), I would go with something more like:

Code: Select all

#define DEFAULT_TEXT_MODE 0x03
#define DEFAULT_CODE_PAGE 437   // or set this to a page suited to your native language 

struct {
    uint8_t total_rows, total_columns;
} TEXT_MODES[255] = {
    // populate this with a lookup table for the modes by mode #
};

typedef struct {
    uint16_t row, column;
} TEXT_CURSOR;

typedef struct {
    TEXT_MODE mode;
     uint16_t code_page;
    TEXT_CURSOR cursor;   
    TEXT_BUFFER buffer;
} TEXT_PAGE;

const TEXT_BUFFER buffers[] = {
    (TEXT_FRAME *) 0xB8000,
    // .. I can't seem to find the rest of the entry points for the other three 
    // text pages ... anyone?
};  

TEXT_PAGE pages[4];

void kinit_console()
{ 
    int i;

    for (i = 0; i < 4; i++) 
    {
        pages[i].mode = DEFAULT_TEXT_MODE;
        pages[i].code_page = DEFAULT_CODE_PAGE;
        pages[i].cursor.row = 0;
        pages[i].cursor.column = 0;
        pages[i].buffer = buffers[i];
}

bool k_gotoxy(TEXT_BUFFER *page, uint8_t row, uint8_t col, bool reset_hw_cursor)
{
    if (row >= page ->text_mode.total_rows || col >= page ->text_mode.total_columns)
    {
        return false;
    }

    page ->cursor.row = row;
    page ->cursor.column = col;
    if (reset_hw_cursor)
    {
        set_vga_cursor(row, col);
    }

    return true;
}

void kputchar(TEXT_BUFFER *page, unsigned char ch)
{
    int *x = &page ->cursor.columns;
    int *y = &page ->cursor.rows;
    int x_offset = page ->text_mode.total_columns;
    int y_offset = page ->text_mode.total_rows;
    FRAME_BUFFER *buffer = page ->buffer;

    if (x <= x_offset)
    {
        x = 0;
        y++;
    }
    else
    {
        x++;
    }

    if (y <= y_offset)
    {
        // handle scrolling or clearing page as you choose
    }
    
    buffer[(y * x_offset) + x].glyph = ch;

    set_vga_cursor(x, y);
}
(Not tested code, just use this as a guide.)

Re: [C]Print a character

Posted: Thu Dec 22, 2016 4:00 pm
by Schol-R-LEA
Having said all that, it occurs to me I forgot to ask: just where is it writing the character to?

Re: [C]Print a character

Posted: Thu Dec 22, 2016 8:25 pm
by irvanherz
Does this will put X at the corner of your screen?

Code: Select all

*((char*)0xB8000) = 'X';
If not, maybe you have initialized wrong GDT base address

Re: [C]Print a character

Posted: Fri Dec 23, 2016 4:05 am
by leosa99
yes it put an X.
If i keep the previous code, the W keeps showing at (0;12).

Re: [C]Print a character

Posted: Fri Dec 23, 2016 5:39 am
by iansjack
You should

1. Inspect the generated code.

2. Then single-step through it in a debugger.

It should then be fairly obvious what is going wrong.

Re: [C]Print a character

Posted: Wed Dec 28, 2016 6:27 am
by matt11235
Schol-R-LEA wrote:

Code: Select all

typedef struct {
    uint8_t attrib;
    unsigned char glyph;
} TEXT_FRAME;
Shouldn't the character be before the attribute byte in the struct?

Re: [C]Print a character

Posted: Wed Dec 28, 2016 6:42 am
by bauen1
zenzizenzicube wrote:
Schol-R-LEA wrote:

Code: Select all

typedef struct {
    uint8_t attrib;
    unsigned char glyph;
} TEXT_FRAME;
Shouldn't the character be before the attribute byte in the struct?
Correct me if i'm wrong but should this have the packed attribute ?