flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Problem with my string printing function

Author
Thread Post new topic Reply to topic
Lollyn00b



Joined: 17 Feb 2007
Posts: 5
Lollyn00b
Hey, I've been working on starting a simple real-mode operating system (Yet another DOS clone, I know.), just for practice. I'm currently having trouble getting a string to print to the screen; I've gotten character printing to work, though. I'm relatively new to ASM, so I might've made a stupid mistake somewhere, but could someone take a look at my code, and see where it goes wrong, or if I need to re-do the entire thing?

Here's my character printing function(works.)
Code:
PutChar:
push ax

mov ah,0x07
mov [es:di], ax    ;Print character at cursor location
add di,2           ;Increment cursor location by a word

pop ax
ret    


...and here is my string printing function (doesn't work.)
Code:
PutStrn:
push si
push ax

mov ah, 0x07  ;Grey text on a black background
.lp:
   lodsb

   cmp al,0  ;Check for a null character
   je .dn

   mov [es:di],ax
   add di,2
jmp .lp

.dn:
pop ax
pop si
ret    


Also, in case you're wondering, I've set ES to 0xb800, and DI to 0, in the beginning of the kernel.

Thanks to anyone who can help a newbie from the world of C/C++ Very Happy
Post 19 Feb 2007, 00:28
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Had you set DS register properly? For example, if your code is a boot code (loaded at 7c00h) you have to set DS=0 and that can be done by push cs/pop ds.
Post 19 Feb 2007, 01:05
View user's profile Send private message Reply with quote
Lollyn00b



Joined: 17 Feb 2007
Posts: 5
Lollyn00b
Well, I've tried setting DS to 0, and to 0x1000(where my kernel gets loaded to), but with no effect. I'm not sure exactly about where things are in memory, so I don't really know a lot of what should be where.

Sorry again for being such a noob Confused

Edit: On the topic of 'what goes where', do you know of a site that lists where certain bits of memory are, to begin with, when the computer's turned on? Like, a site that explains the whole 0x7c00 thing, and other things like that?
Post 19 Feb 2007, 02:24
View user's profile Send private message Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 313
Mac2004
hi Lollyn00b!

I just took a quick look at your sources. I noticed that you are not setting the direction flag anywhere while you are using string operations. CLD will do the trick.

regards,
Mac2004
Post 19 Feb 2007, 05:04
View user's profile Send private message Reply with quote
Dex4u



Joined: 08 Feb 2005
Posts: 1601
Location: web
Dex4u
Hi, First i assume that ds:si points to a 0 ended string ? and do you have something like this at start of kernel
Code:
use16org 0x10000    

If so, if nothing else works you can try puting something like this
Code:
mov si,string - 0x10000    

As bubach had a problem with this.
Also maybe if you take a look at MiniDos code may help http://board.flatassembler.net/topic.php?t=5275&start=0
Post 19 Feb 2007, 14:50
View user's profile Send private message Reply with quote
Lollyn00b



Joined: 17 Feb 2007
Posts: 5
Lollyn00b
Well, I've tried your suggestions, and I've been looking at the MiniDOS code for a bit, but I still haven't found a solution... I think I'll just post my source code here (It's very small), and see if anyone can point out a silly mistake, or whatever's causing the not-workage.

Boot.asm (Bootloader)
Code:
org 0x7c00
use16

jmp short LoadKernel

nop
times 0x3B db 0

LoadKernel:
        mov ah, 0x02    ; Read Disk Sectors
        mov al, 0x01    ; Read one sector
        mov ch, 0x00    ; Track 0
        mov cl, 0x02    ; Sector 2
        mov dh, 0x00    ; Head 0
        mov dl, 0x00    ; Drive 0 (Floppy 1)

        mov bx, 0x1000  ; Segment 0x1000
        mov es, bx      

        mov bx, 0x0000  ; Offset 0x0000
ReadSector:
        int 0x13        ; Call BIOS Read Disk Sectors
        jc ReadSector   ; If error, try again

        mov ax, 0x1000  ; Set the data segment register
        mov ds, ax      ; to kernel location in memory

jmp 0x1000:0x0000       ; Jump to kernel


times 510 - ($ - $$) db 0
dw 0aa55h

include 'kern.asm'    


Kern.asm(Kernel)
Code:
call ClrScrn
mov si,msg
call PutStrn

jmp KernelEnd

;;;;;;;;;;;;;;;;;;;;;

include 'ksub.asm'

;;;;;;;;;;;;;;;;;;;;;

KernelEnd:

msg db "Hello, World!",13,10,0

jmp $
times 1024 - ($ - $$) db 0    


Ksub.asm(Kernel subroutines)
Code:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ClrScrn:
push 0xb800
pop  es

xor di,di
mov cx, 2000
.lp:
   mov [es:di],word 00
   add di,word 02
loop .lp

xor di,di
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

PutChar:
push ax

mov ah,0x07
mov [es:di], ax    ;Print character at cursor location
add di,2           ;Increment cursor location by a word

pop ax
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

PutStrn:
push si
pushf
cld

mov ah, 0x07
.lp:
   lodsb

   cmp al,0
   je .dn

   mov [es:di],ax
   add di,2
jmp .lp

.dn:
popf
pop si
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;    


Thanks to anyone willing to help, sorry if I turned this into a 'fix my code luls' topic :\


Edit: This creates a 1024 byte file, the first 512 of which is the bootloader, in case anyone needs to know. Also, I'm doing the testing in QEMU, and burning it to the disk using PartCopy. The bootloader is mostly taken from a disk-reading example on osdever.net.

Edit 2: I tried using PutStrn in my bootloader, and it worked perfectly; I guess it has something to do with the location of my kernel, then. Confused
Post 19 Feb 2007, 19:05
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
I see a big problem, that "jmp KernelEnd " is a fatal bug, it makes the CPU to execute the "hello world" string which obviosly it's not executable (well maybe some bytes but you will get an invalid opcode exception very easily), replace it with a "jmp $" if you really want to hang the program or move the label KernelEnd to that "jmp $" located above "times ...".

Code:
ReadSector: 
        int 0x13        ; Call BIOS Read Disk Sectors 
        jc ReadSector   ; If error, try again     

That part is wrong too, on error AH is modified but to workaround possible BIOS bugs better replace "jc ReadSector" with "jc LoadKernel" instead of just setting AH to 2 again.
Post 19 Feb 2007, 22:45
View user's profile Send private message Reply with quote
Dex4u



Joined: 08 Feb 2005
Posts: 1601
Location: web
Dex4u
I think you need to assemble your bin and kernel file separately and add org 0x10000 to the kernel file.
Here is a example of do it that way http://bos.asmhackers.net/downloads.php
you need to get "BOS version 0.04, with source"
Also see the bach file for writing it to floppy.
Post 19 Feb 2007, 23:39
View user's profile Send private message Reply with quote
Lollyn00b



Joined: 17 Feb 2007
Posts: 5
Lollyn00b
Yeah, I noticed that I had to switch the places of 'Hello, World!' and the hang, right when I looked at my code again; dunno how I missed it... Thanks for pointing out the bug in the loading code, as well.

It's strange, I had my OS set up as two files before, which were stuck together using Dos 'copy /b ...' and it was working fine; dunno why I changed it. As for BOS, I'll take a look at it's source, and see how they did some things--thanks for the link!
Post 20 Feb 2007, 01:18
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Dex, I think that is not a good idea using org $10000, that exeeds by one the maximun possible offset16 and it's unneeded at all since he sets the segment registers to $1000.

AAAH!! I see another problem, the kernel believes that it's loaded at $1000:$7E00, you forgot to add a "ORG 0" just above " include 'kern.asm' ". Try fixing that to see if there is some progress
Post 20 Feb 2007, 01:42
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
I just tried, works with all the modifications I told you. Just a little problem, writing CRLF (13, 10) on the screen memory just makes the video card to show the ASCII characters ♪ and ◙ because the video card recognises at memory all the characters as printable characters, so you have to improve your function a little if you want that CR and LF work as control characters.
Post 20 Feb 2007, 12:26
View user's profile Send private message Reply with quote
Mac2004



Joined: 15 Dec 2003
Posts: 313
Mac2004
Lollyn00b: I noticed you having problems with secondary file loading...

I would suggest you to use a working boot sector while debugging you kernel -file.
Here's my example of working boot sector & secondary file. My example does pretty much same things you trying to do.
Once you get your kernel -file working you can switch to debug your boot sector (if needed...)

http://board.flatassembler.net/topic.php?t=6529

Regards,
Mac2004
Post 20 Feb 2007, 18:13
View user's profile Send private message Reply with quote
Lollyn00b



Joined: 17 Feb 2007
Posts: 5
Lollyn00b
Sorry I couldn't reply earlier; I've gotten my kernel fixed, all I had to do was separate the two files! It works perfectly now, thanks for the help everyone. Very Happy

Edit: Did some work on my putstrn function, and now it works with CRLF capabilities; here's the code, if anyone wants it:
Code:
PutStrn:

push si
push ax
push bx
pushf
cld

mov ah, 0x07
.main_loop:

   lodsb

   cmp al,0             ;If null character
   je .done             ;end string

   cmp al,13            ;
   jne .line_feed       ;checks for carriage return (13), if not, goes to LF check


   push ax

      mov  ax, di       ;
      mov  bh, 0xa0     ;
      div  bh           ;Stores (di % 160) in register ah
      movzx bx, bh      ;
      movzx ax, ah      ;
      sub  di, ax       ;Cursor -= Cursor_x, effectively shifts the cursor
                        ;back to the beginning of the line
   pop ax

   jmp .main_loop       ;Skip to next character

   
   .line_feed:
   cmp al,10
   jne .print

      add di, 0xa0      ;New line
      jmp .main_loop    ;Skip to next character

   .print:
   mov [es:di],ax

   .increment:

   add di,2

jmp .main_loop

.done:

popf
pop bx
pop ax
pop si
ret    

Edit 2: This assumes that ES is 0xb800, that DI is somewhere in the range 0 to 4000 (and is an even number), that SI points to the string, and that DS is set appropriately.

Edit 3: The only thing I could think of that could improve on this is to add text coloring by letting AH be set beforehand; I don't really need this, though, so I'll leave it the way it is for now.

Suggestions/improvements are welcome Very Happy


Last edited by Lollyn00b on 20 Feb 2007, 23:59; edited 3 times in total
Post 20 Feb 2007, 23:18
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Separating the files has the implicit effect of placing a "org 0" at the beginning of the kernel. My test was producing a single boot.bin (not merging two files but using just the one produced by fasm) and then writing it with rawrite for Windows.
Post 20 Feb 2007, 23:23
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.