2011-08-31 174 views
0

我已經寫了一個有getline和print_string「functions」的小實驗引導程序。引導的東西取自MikeOS教程,但其餘的我寫了自己。我用NASM編譯並在QEMU中運行它。清除字符串變量

所以真正的問題:我已經在第6行聲明瞭這個變量curInpLn。用戶類型被保存在該變量中,然後在輸入命中後,它會向用戶顯示一些額外的消息。我想要做的是在每次調用getline函數時清除curInpLn的內容,但出於某種原因,我無法做到這一點。我現在非常適合初學者。

您可以將代碼編譯爲bin格式,然後使用以下命令創建它的軟盤映像:「dd status = noxfer conv = notrunc if = FILENAME.bin of = FILENAME.flp」並在qemu中使用:「qemu -FDA FILENAME.flp」

BITS 16 

jmp start 
welcomeSTR:   db 'Welcome!',0 
promptSTR:   db 'Please prompt something: ',0 
responseSTR:   db 'You prompted: ',0 

curInpLn: times 80 db 0      ;this is a variable to hold the input 'command' 

curCharCnt:   dw 0 

curLnNum:   dw 1 


start: 

    mov ax, 07C0h   ; Set up 4K stack space after this bootloader 

    add ax, 288   ; (4096 + 512)/16 bytes per paragraph 

    mov ss, ax 

    mov sp, 4096 



    mov ax, 07C0h   ; Set data segment to where we're loaded 

    mov ds, ax 


    call clear_screen 



    lea bx, [welcomeSTR]  ; Put string position into SI 

    call print_string 
    call new_line 

    .waitCMD: 

     lea bx, [promptSTR] 

     call print_string 
     call getLine  ; Call our string-printing routine 



    jmp .waitCMD 



getLine: 



    cld 

    mov cx, 80     ;number of loops for loopne 

    mov di, 0     ;offset to bx 

    lea bx, [curInpLn]   ;the address of our string 



    .gtlLoop: 

     mov ah, 00h    ;This is an bios interrupt to 

     int 16h     ;wait for a keypress and save it to al 



     cmp al, 08h    ;see if backspace was pressed 

     je .gtlRemChar   ;if so, jump 







     mov [bx+di], al  ;effective address of our curInpLn string 

     inc di     ;is saved in bx, di is an offset where we will 

        ;insert our char in al 



     cmp al, 0Dh    ;see if character typed is car-return (enter) 

     je .gtlDone   ;if so, jump 



     mov ah, 0Eh    ;bios interrupt to show the char in al 

     int 10h 

    .gtlCont: 

     loopne .gtlLoop   ;loopne loops until cx is zero 

     jmp .gtlDone 



    .gtlRemChar: 

     ;mov [bx][di-1], 0 ;this needs to be solved. NASM gives error on this. 

     dec di 

     jmp .gtlCont 



    .gtlDone: 

     call new_line 
     lea bx, [responseSTR] 

     call print_string 

     mov [curCharCnt], di ;save the amount of chars entered to a var 


     lea bx, [curInpLn] 
     call print_string 
     call new_line 

ret 





print_string:    ; Routine: output string in SI to screen 



    mov si, bx 



    mov ah, 0Eh   ; int 10h 'print char' function 



    .repeat: 

     lodsb    ; Get character from string 

     cmp al, 0 

     je .done   ; If char is zero, end of string 

     int 10h    ; Otherwise, print it 

    jmp .repeat 



.done: 


ret 


new_line: 

    mov ax, [curLnNum] 
    inc ax 
    mov [curLnNum], ax 

    mov ah, 02h 
    mov dl, 0 
    mov dh, [curLnNum] 
    int 10h 

ret 

clear_screen: 
    push ax 
    mov ax, 3 
    int 10h 
    pop ax 
ret 


times 510-($-$$) db 0  ; Pad remainder of boot sector with 0s 

dw 0xAA55   ; The standard PC boot signature 
+0

你有什麼試過,不起作用?順便說一句,你應該設置'es'等於'ds',因爲'di'本身隱含地以'es'爲前綴,而不是'ds'(如'sp'和'bp'使用'ss')。另外'mov [bx] [di-1],0'可以寫爲'mov byte [bx + di-1],0'。 – user786653

+0

嗨!之後:lea bx,[curInpLn]我試過a)mov byte [bx],0,就在它之前我試過了a)mov byte [curInpLn],''和b)mov ax,0 mov [curInpLn],斧 –

+0

恐怕我還沒有跟着你。你是否想要'curInpLn'中的所有80個字節設置爲零,你只是想將第一個字節設置爲零或完全是其他的嗎?當我讀取你的代碼時,你不需要清除它,因爲無論如何你每次都從頭開始。你只是希望NUL(零字節)終止字符串(在這種情況下,只需在'.gtlDone:'之後執行'mov byte [bx + di],0',並且可能將'mov cx,80'改爲mov cx ,79'來反映它)? – user786653

回答

0

我沒有在彙編語言編寫代碼20年(!),但它看起來像你需要使用‘STOSW’指令(或‘STOSB’)。 STOSB將保存在AL中的值加載到由ES:DI指向的字節,而STOSSW將保存在AX中的值加載到由ES:DI指向的。指令自動前進指針。由於您的變量curInpLn長度爲80個字節,因此您可以通過40次STOSW進行清除。像

xor ax, ax     ; ax = 0 
mov es, ds     ; point es to our data segment 
mov di, offset curInpLn ; point di at the variable 
mov cx, 40     ; how many repetitions 
rep stosw     ; zap the variable 

這種方法的東西可能是清​​除變量,因爲它並不需要CPU來從預取隊列中的任何指令的最快的方法。事實上,它允許預取隊列填滿,從而允許儘快執行任何後續指令。

+0

欣賞努力,但真正回答以「我多年來沒有做過x ...」開頭並不總是有幫助。 LODSx指令*將內存中的數據加載到ax寄存器中。我認爲你的意思是STOSx,它存儲從ax到內存的值。 – adelphus

+0

我已更正我的代碼以使用es:di和stosw而不是ds:si和lodsw。 –