Not able to write onto file in the order I want (assembly emu8086)

Viewed 27

Hello I am pretty new to assembly and I am trying to write onto a file a score, a name and a date (by this order) from a game I developed in emu8086. However I can't write the score before the name (It only writes the name and the date). Any help?

Here's the code:

    push si
    push ax
    push bx
    push cx
    push dx
    
     ;Score
    push 4
    mov ax, Score
    call GetAscii >**; transforms number into ascii and puts it into [si]****
    add sp, 4
   > **;player name**
    lea si, Result
    add si, 12
    mov [si], ';'
    inc si
            
    >**;Date**
    push 2 
    mov ah, 2ah
    int 21h
    xor ax, ax
    mov al, dl    ;
    call GetAscii ;Day
    mov [si], '/'
    inc si
    mov al, dh    ;
    call GetAscii ;Month
    mov [si], '/'
    inc si
    mov ax, cx
    push 4   
    call GetAscii ;year
    add sp, 2
    mov [si], ';'
    inc si
    
    ;time
    mov ah, 2ch
    int 21h
    xor ax, ax
    mov al, ch    ;
    call GetAscii ;Hours
    mov [si], ':'
    inc si
    mov al, cl    ;
    call GetAscii ;minutes
    mov [si], ':'
    inc si
    mov al, dh    ;
    call GetAscii ;Seconds
    mov [si], ';'
    inc si
    
    
    
    ;write onto file "Resultados.txt"
    lea dx, ResultadosFile
    mov al, 2
    call FOpen
    jnc WriteData
    xor cx, cx
    call FCreate
    
    WriteData:
        mov bx, ax
        xor cx, cx
        xor dx, dx
        mov al, 2 
        call FSeek
        lea dx, Result
        mov cx, 40
        call FWrite
                
    call FClose
               
    pop dx
    pop cx
    pop bx
    pop ax
    pop si
    ret
RegScore endp
GetAscii proc
    push dx
    push cx
    push bx
    push bp
    
    mov bp, sp
    
    xor bh, bh
    mov bl, 10
    xor cx, cx
    
    GetNum:
        xor dx, dx
        div bx
        push dx  
        inc cx
        cmp ax, 0
        jne GetNum
        PutZero:
            cmp cx, [bp+10]
            je PutNum
            push 0
            inc cx
            jmp PutZero
        
    PutNum:
        pop [si]
        add [si], 48
        inc si
        dec cx
        or cx, 0
        jz EndAscii
        jmp PutNum          
        
    EndAscii:
        pop bp
        pop bx
        pop cx
        pop dx
        ret                 
GetAscii endp

On the file it only appears the name of the player and the date.
If I put the score lines after the lea si, result it now shows the score.

1 Answers
push dx

;Score
push 4
mov ax, Score
call GetAscii >**; transforms number into ascii and puts it into [si]****
add sp, 4

Seeing that the GetAscii procedure depends on the value in the SI register, you need to define it before invoking the procedure. If you don't then the score could land anywhere.

pop [si]

Using this word-sized instruction in the GetAscii procedure will introduce a zero byte at the end of your 4-character score. Some tool could be hiding content that follows a NULL.

There are two problems with keeping a balanced stack

That add sp, 4 instruction is not only getting rid of the pushed parameter (4), it is also removing the DX register that was to be preserved. add sp, 2 is the correct instruction.

The push 2 at the start of the date part has still to be removed at the end of the time part.

Your code didn't crash and the RegScore procedure returned just fine because these two problems came together, cancelling out on the stackpointer and always returning DX=2.

See in the below solution how you can more easily keep track of what is on the stack using numbered tail comments like (1) that always have to come in pairs. If they don't then something is amiss!

Solution

You write a fixed amount of 40 bytes to the text file. Next code assumes the following layout:

SSSS;NNNNNNNNNNNNNN;DD/MM/YYYY;HH:MM:SS;
^
|
Result
<--------------- 40 bytes ------------->

;Score
lea  si, Result
mov  ax, Score
push 4                  ; (1)
call GetAscii
mov  [si], ';'
inc  si
add  sp, 2              ; (1) Use `pop dx` for shorter code

; Name
add  si, 14             ; Skip player name ???
mov  [si], ';'
inc  si

;Date
push 2                  ; (2)
mov  ah, 2ah
int  21h
xor  ax, ax
mov  al, dl
call GetAscii
mov  [si], '/'
inc  si
mov  al, dh
call GetAscii
mov  [si], '/'
inc  si
mov  ax, cx
push 4                  ; (3)
call GetAscii
add  sp, 2              ; (3) Use `pop dx` for shorter code
mov  [si], ';'
inc  si

;Time
mov  ah, 2ch
int  21h
xor  ax, ax
mov  al, ch
call GetAscii
mov  [si], ':'
inc  si
mov  al, cl
call GetAscii
mov  [si], ':'
inc  si
mov  al, dh
call GetAscii
mov  [si], ';'
inc  si
add  sp, 2              ; (2) Use `pop dx` for shorter code
...

This would be a good way to write the characters:

PutNum:
    pop  dx
    add  dl, 48
    mov  [si], dl       ; Only writing a byte because a char is byte-sized
    inc  si
    dec  cx
    jnz  PutNum          
EndAscii:
Related