2011-08-31 100 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。 –