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

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
leledumbo
Member
Member
Posts: 103
Joined: Wed Apr 23, 2008 8:46 pm

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

Post 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).
Attachments
fpcos.zip
(59.32 KiB) Downloaded 32 times
Laksen
Member
Member
Posts: 140
Joined: Fri Nov 09, 2007 3:30 am
Location: Aalborg, Denmark

Post 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);
      ...
leledumbo
Member
Member
Posts: 103
Joined: Wed Apr 23, 2008 8:46 pm

Post 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?
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post 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.
leledumbo
Member
Member
Posts: 103
Joined: Wed Apr 23, 2008 8:46 pm

Post 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?!
Laksen
Member
Member
Posts: 140
Joined: Fri Nov 09, 2007 3:30 am
Location: Aalborg, Denmark

Post 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;
leledumbo
Member
Member
Posts: 103
Joined: Wed Apr 23, 2008 8:46 pm

Post 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.
Attachments
fpcos.zip
(62.56 KiB) Downloaded 68 times
Post Reply