Page 1 of 1

( bkerndev tutorial + De Deyn Kim tutorial ) = wrong output

Posted: Thu Jun 05, 2008 1:35 am
by leledumbo
After reading both tutorials, I decided to combine them. As the implementation language, I use Pascal with FreePascal as the compiler. I make everything from scratch, except for the stub.asm and I choose the better implementation (at least IMO) between both for some functions. However, the output under Qemu doesn't seem correct. The screen doesn't get cleared and no message is printed. I'll provide both code and other functions they call:

Code: Select all

var
  VidMem: PChar;
  CursorPosX,CursorPosY: Integer;
  Attrib: Integer;
  Blank: Word;
...
procedure Move(Src,Dest: Pointer; Count: Word);
var
  sp,dp: PByte;
begin
//{
  // Assembler way
  asm
    mov esi,Src
    mov edi,Dest
    mov ecx,Count
    rep movsb
  end;
//}
{
  // Pascal way
  sp:=PByte(Src);
  dp:=PByte(Dest);
  while Count>0 do begin
    dp^:=sp^;
    Inc(dp);
    Inc(sp);
    Dec(Count);
  end;
}
end;

procedure FillWord(Dest: Pointer; const W: Word; Count: Word);
var
  dp: PWord;
begin
  dp:=PWord(Dest);
  while Count>0 do begin
    dp^:=W;
    Inc(dp);
    Dec(Count);
  end;
end;

procedure WritePort(Port: LongInt; Value: Byte);
begin
  asm
    mov edx,port
    mov al,value
    out dx,al
  end ['EAX','EDX'];
end;

procedure Scroll;
var
  temp: Word;
  dest: PChar;
begin
  if CursorPosY>=25 then begin
    temp:=CursorPosY-26;
    dest:=VidMem+temp*80;
    Move(VidMem,dest,(25-temp)*160);
    dest:=VidMem+(25-temp)*80;
    FillWord(dest,Blank,80);
    CursorPosY:=24;
  end;
end;

procedure MoveCursor;
var
  temp: Word;
begin
  temp:=CursorPosY*80+CursorPosX;
  WritePort($3D4,14);
  WritePort($3D5,temp shr 8);
  WritePort($3D4,15);
  WritePort($3D5,temp);
end;

procedure ClearScreen;
var
  i: Word;
begin
  for i:=0 to 3999 do
    VidMem[i]:=#0;
  CursorPosX:=0;
  CursorPosY:=0;
  MoveCursor;
end;

procedure WriteChr(const c: Char);
var
  offset: Word;
begin
  case c of
    #08: if CursorPosX<>0 then Dec(CursorPosX);
    #09: Inc(CursorPosX,8);
    #13: CursorPosX:=0;
    #10: Inc(CursorPosY);
    #32..#255: begin
      offset:=(CursorPosX shl 1)+(CursorPosY*160);
      VidMem[offset]:=c;
      Inc(offset);
      VidMem[offset]:=Char(Attrib shl 8);
      Inc(CursorPosX);
    end;
  end;
  if CursorPosX>=80 then begin
    CursorPosX:=0;
    Inc(CursorPosY);
  end;
  Scroll;
  MoveCursor;
end;

procedure WriteStr(const P: PChar);
var
  i: LongWord;
begin
  i:=0;
  while P[i]<>#0 do
    WriteChr(P[i]);
end;
...
initialization
  VidMem:=PChar($b8000);
  CursorPosX:=0;
  CursorPosY:=0;
  Attrib:=$0F;
  Blank:=$20 or (Attrib shl 8);
...
The kernel code only calls ClearScreen, WriteStr('Hello, World'), and finally an infinite loop. If you want to check yourself, please download the attachment. I've made a build.bat script to make building easier, please notice that some things might need to be set (i.e. my ld is named i386-linux-ld because it's a cross linker).

Posted: Thu Jun 05, 2008 2:23 am
by Laksen
There are loads of problems with your code.

1. Initialization/Finalization sections are not call as you are not compiling a program. You are only compiling a unit and on boot grub will jump directly to kernel_entry
You will have to make a new procedure InitScreen or eventually make the variables initialized:

Code: Select all

var
  VidMem: PChar = PChar($B8000);
  CursorPosX: integer = 0;
  CursorPosY: Integer = 0;
  Attrib: Integer = $0F;
  Blank: Word = $0F02;
2. You don't increment i in writestr :wink:
3. You should call CLD in your move procedure just to be on the safe side
4. Your writechar procedure looks like it's borkens, I would fix it up like this:

Code: Select all

      ...
      VidMem[offset]:=c;
      Inc(offset);
      VidMem[offset]:=Char(Attrib);
      ...

Posted: Thu Jun 05, 2008 3:01 am
by leledumbo
1. Thank you. Didn't know about it (must learn again, argh...)
2. (Slap) stupid mistake
3. Err...where should I call it?
4. You're right, (Attrib shl 8) makes everything black. But according to bkerndev, 0000_0000_1111_1111 shifted by 8 will produce 1111_1111_0000_0000 which means: backcolor = white, forecolor = white. Did I misunderstand something?

It runs fine now, thanks! But...where's the blinking cursor?

Posted: Thu Jun 05, 2008 3:18 am
by JamesM
4. You're right, (Attrib shl Cool makes everything black. But according to bkerndev, 0000_0000_1111_1111 shifted by 8 will produce 1111_1111_0000_0000 which means: backcolor = white, forecolor = white. Did I misunderstand something?
You're declaring VidMem as an array of 8-bit bytes, so shifting left a value by 8 bits will just result in 0!

The shift is required if you're using an array of 16-bit values, but you're not, so it doesn't matter.

Posted: Thu Jun 05, 2008 3:31 am
by leledumbo
Ah...so that's the problem. Thanks, I gotta re-learn my digital system lesson. This bit thing is quite confusing.

Oh, no! Now the scroll procedure doesn't work, too?!

Posted: Thu Jun 05, 2008 3:37 am
by Laksen
Try:

Code: Select all

procedure Scroll; 
var 
  temp: Word; 
  dest: PChar; 
begin 
  if CursorPosY>=25 then begin 
    temp:=CursorPosY-26; 
    dest:=VidMem+2*80; 
    Move(dest,VidMem,24*160); 
    dest:=VidMem+24*160;
    FillWord(dest,Blank,80); 
    CursorPosY:=24;
  end;
end;

Posted: Thu Jun 05, 2008 3:56 am
by leledumbo
Yippie, now it works! I change the code as temp isn't needed.

Code: Select all

procedure Scroll;
var
  dest: PChar;
begin
  if CursorPosY>=25 then begin
    dest:=VidMem+2*80;
    Move(dest,VidMem,24*160);
    dest:=VidMem+24*160;
    FillWord(dest,Blank,80);
    CursorPosY:=24;
  end;
end;
I repost the attachment for others who are interested.