简体   繁体   中英

8086 not printing first character printing nulls instead

There is an error in this code. The print_string doesnt print to the screen after pointing to the string, it only prints if the line in the code mov bx,8000h is removed and the two lines after it, but then i cant write alot of bytes to ram the whole thing crashes after calling alloc and incrementing the basepointer like 20 times. what should i do, how do I get to write the string and make it not crash after writing like 20 bytes

[bits 16]
[org 0x7c00]

SEAM_STD_BUFFER equ 0
SEAM_STD_LIMIT equ 255

xor ax,ax
mov bx,ax
mov bx,cx
mov dx,0
mov ds,bx
mov es,bx

mov bp,0
mov sp,bp
mov ss,bp
mov bx,8000h
mov sp,bx
mov ss,bx

mov bp,0
jmp _start

 _start:
    call clear

.repeat:        
    mov bp, OS_USERNAME_DESCRIPT
    call print_string
    call Set_BasePointer_std
    call read_string_show
    jmp .repeat

Set_BasePointer_std:
    mov bp,SEAM_STD_BUFFER  
    ret
read_char_show:;() returns al
    call read_char
    cmp al,8
    je .back
    call print
    ret
    .back:
        cmp bp,SEAM_STD_BUFFER
        je .done
        call print
    .done:
    mov al,0
    ret
read_string: ; (ptr bp place to allocate string)
    call read_char
    cmp al,13
    je .done
    call alloc
    inc bp
    cmp bp,SEAM_STD_LIMIT
    jge .resetbp
    jmp read_string
    .done:
        mov al,0
        call alloc
        ret
    .resetbp:
        call Set_BasePointer_std
        jmp read_string
read_string_show: ; (ptr bp place to allocate string)
    call read_char_show
    cmp al,0
    je read_string_show
    cmp al,13
    je .done
    cmp al,8;;NOT GOOD ENOUGH
    je .skip;;NOT GOOD ENOUGH
    call alloc
    inc bp
    .skip:;;NOT GOOD ENOUGH
    cmp bp,SEAM_STD_LIMIT
    jge .resetbp
    jmp read_string_show
    .resetbp:
        call Set_BasePointer_std
        jmp read_string
    .done:
    mov al,0
    call alloc
    call next_line
    ret
read_char: ;() returns al
    mov ax,0x00
    int 0x16
    ret 

clear:; ()
    mov ah,0
    mov al,3
    int 0x10   
    ret
free:;(bp ptr at place start to free, ax at end )
    mov [bp],byte 0
    cmp bp,ax
    je .done
    inc bp
    jmp free
    .done:
    ret
dalloc:; (ptr bp)
    mov al,[bp]
    ret
alloc: ;(bp place to allocate,al byte value)
    mov [bp], al
    ret
clear_line:
    mov dh,0
    call clear
    ret
next_line:
    mov ah,2
    mov dl,0
    inc dh
    cmp dh ,25
    jge clear_line
    int 10h
    ret
previous_line:
    dec dh
    mov ah,2
    mov dl,0
    int 10h
    ret
next_char:; finish
string_compare:;finish  

print: ; (al Character to print, bl color)
    mov ah,0x0E
    int 10h
    ret
print_string: ;(ptr bp Place of string start)
    call dalloc
    cmp al,0
    je .done
    call print
    inc bp
    jmp print_string
    .done:
    ret
OS_WELCOME db 'What is giong on',0
OS_USERNAME_DESCRIPT db 'Username:'
times (510 - ($-$$)) db 0x00
dw 0xAA55

Getting your printing on track

 xor ax,ax mov bx,ax mov bx,cx <-- Here CX goes to BX mov dx,0 mov ds,bx <-- Here (via BX) CX goes to DS mov es,bx <-- Here (via BX) CX goes to ES 

You don't setup the DS and ES segment registers correctly!
You've stored the value of CX in them but CX never got initialized with any useful value .


 mov bp,0 mov sp,bp mov ss,bp mov bx,8000h mov sp,bx mov ss,bx 

There's alot wrong with how you setup the stack. Doing it twice can't help much! Also when setting up the stackpointer always first assign SS and immediately after assign SP . The order is important.

For the actual value to put in SS , frankly you got no choice. (Technically you have but let's not complicate things...) Given that you want to use BP to point at your strings and that the whole program gets encoded with an ORG 0x7C00 the only correct value to put in SS is zero.
I suggest you write:

xor ax, ax
mov ss, ax
mov sp, 0x7C00

This will put the stack just below your bootloader program, a safe place.
And because DS and ES also need a good initialization, make the whole thing:

xor ax, ax
mov ss, ax
mov sp, 0x7C00
mov ds, ax
mov es, ax

 print: ; (al Character to print, bl color) mov ah,0x0E int 10h ret 

This print routine still needs that you say to which display page the BIOS teletype function should write. The selection is done via the BH register.

print:
    mov bh, 0
    mov ah, 0x0E
    int 10h
    ret

In order to verify that the printing works, you could make the program wait for a key:

_start:
    call clear
.repeat:        
    mov  bp, OS_USERNAME_DESCRIPT
    call print_string
    mov  ah, 00h     ;Wait for a key
    int  16h         ;Wait for a key

Once you're confident that this part of the code works fine, you just remove these 2 lines.


Something that will backfire eventually

 OS_USERNAME_DESCRIPT db 'Username:' times (510 - ($-$$)) db 0x00 

Do terminate the string with an explicit zero. Don't rely on the following padding that happens to use zeroes.

In future:

  • you might pad with some other value than zero
  • the bootloader might got crowded so there would be no padding at all

My answer complements the answer given by Sep Roland that solved the matter of printing (and more).
It deals with the fact that the program keeps crashing after a number of characters have been inputted.

The problem lies in this line:

 SEAM_STD_BUFFER equ 0 

and its companion:

 mov bp,SEAM_STD_BUFFER 

Because the stack segment is now correctly positioned at 0, you should no longer store your characters starting at bp=0 . You do this in the alloc code mov [bp], al .

You can store it in lots of other places but a good one would be directly behind the bootloader.

SEAM_STD_BUFFER equ 0x7E00

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM