; CIS-261
;
; ADD_SUB_EFLAGS.ASM
;
; Program inputs two 16-bit signed integers, then 
; computes the sum and difference of lower bytes
; and displays the CPU status flags.
;

INCLUDE IO.H        ; header file for input/output

.386                ; Tells MASM to use Intel 80386 instruction set.
.MODEL FLAT         ; Flat memory model
option casemap:none ; Treat labels as case-sensitive

.CONST          ; Constant data segment
    TXT_ENTER   BYTE    "- - - - - - - - - Please enter two numbers - - - - - - - - - - - -", 0
    TXT_OP1     BYTE    "OP1> ", 0
    TXT_OP2     BYTE    "OP2> ", 0
    TXT_SUM     BYTE    " SUM> ", 0
    TXT_DIFF    BYTE    "DIFF> ", 0
    ENDL        BYTE    13, 10, 0
    OVERFLOW    BYTE    "*** Bad format, please retry!", 0
    TXT_EFLAGS  BYTE    "S Z - a - p V C   EFLAGS: Sign Zero AuxCarry Parity oVerflow Carry",
                        13, 10,
                        13, 10,
                        "7 6 5 4 3 2 * 0   (*) oVerflow is 11th bit of EFLAGS", 0
    TXT_LINE    BYTE    "__________________________________________________________________", 0
    TXT_UNSIG   BYTE    "  Unsigned: ", 0
    TXT_BIN     BYTE    "   Binary:  ", 0
    
.STACK 100h     ; (default is 1-kilobyte stack)

.DATA           ; Begin initialised data segment
    bit_buffer  BYTE    32 dup(' '), 0 ; output buffer
    inp_buffer  BYTE    8 DUP (?)    ; input buffer
    
.CODE           ; Begin code segment
_main PROC      ; Main entry point into program

program_top:
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; Input operand one:
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@:
    output ENDL
    output TXT_LINE
    output ENDL
    output TXT_ENTER
    output ENDL
    output  TXT_OP1          ; Please enter a number...
    input   inp_buffer, 8    ; Read zero to 6 ASCII characters
    atoi    inp_buffer       ; Convert string to 2's complement number
    jno     @F               ; Check the overflow flag
    ; Handle input error:
    output  OVERFLOW         ; print error message
    output  ENDL             ; print new line
    jmp     @B               ; back to the prompt
@@:
    ; Success: result of conversion is in AX
    xor edx, edx             ; set EDX to zero
    mov dl, al               ; store first operand in DL

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; Input operand two:
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@:
    output  TXT_OP2          ; Please enter a number...
    input   inp_buffer, 8    ; Read zero to 6 ASCII characters
    atoi    inp_buffer       ; Convert string to 2's complement number
    jno     @F               ; Check the overflow flag
    ; Handle input error:
    output  OVERFLOW         ; print error message
    output  ENDL             ; print new line
    jmp     @B               ; back to the prompt
@@:
    ; Success: result of conversion is in AX

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; Compute the sum:
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;
    push eax                 ; Preserve EAX
    push edx                 ; Preserve EDX
    
    output TXT_LINE
    output ENDL
    output  TXT_SUM          ; uncomment to show sum
    add dl, al               ; compute sum in DL

    lahf                     ; load flags into AH
    jno @F                   ; Check the overflow flag
    or  ah, 2                ; set 2nd bit in AH (indicates overflow)
    jmp display_sum
@@:
    and ah, 11111101y        ; clear 2nd bit in AH (indicates no overflow)
    
display_sum:
    call   show_dx
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; Compute the difference:
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;
    pop edx                  ; Restore EDX
    pop eax                  ; Restore EAX
    
    output TXT_LINE
    output ENDL
    output  TXT_DIFF         ; uncomment to show diff
    sub dl, al               ; compute difference in DL
    
    lahf                     ; load flags into AH
    jno @F                   ; Check the overflow flag
    or  ah, 2                ; set 2nd bit in AH (indicates overflow)
    jmp display_diff
@@:
    and ah, 11111101y        ; clear 2nd bit in AH (indicates no overflow)
    
display_diff:
    call   show_dx
    
    jmp    program_top    
    
    ret
_main ENDP

show_dx PROC
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; Display DX and flags
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; Input: DX = value to display, AH = STATUS FLAGS to display
    movsx   dx, dl           ; sign-extend DL into DX
    itoa    inp_buffer, dx   ; Convert 16-bit signed integer to string

    output  inp_buffer       ; print result
    output  TXT_UNSIG
    
    movzx   dx, dl           ; zero-extend DL into DX
    itoa    inp_buffer, dx   ; Convert 16-bit signed integer to string
    output  inp_buffer       ; print result
        
    push    eax
    mov     ah, dl
    call    ah_2_bit_buffer  ; Prepare bit buffer
    output  TXT_BIN
    output  bit_buffer       ; show bits
    pop     eax
        
    output  ENDL             ; print new line
    output  ENDL
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; Display lower byte of EFLAGS from AH
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    call   ah_2_bit_buffer  ; Prepare bit buffer
    output bit_buffer       ; show flags
    output ENDL
    output TXT_EFLAGS       ; show labels
    output ENDL
    
    ret
show_dx ENDP

ah_2_bit_buffer PROC
    mov ecx, 8  ; number of bits to display
    mov esi, OFFSET bit_buffer

next_bit:
    shl ah, 1               ; shift high bit into Carry flag
    mov BYTE PTR [esi], '0' ; display zero by default
    jnc next_byte           ; if no Carry, advance to next byte
    mov BYTE PTR [esi], '1' ; otherwise display 1
next_byte:
    inc esi                 ; next buffer position
    inc esi                 ; next buffer position
    loop next_bit           ; shift another bit to left

    ; Display bits
    mov BYTE PTR [esi], 0   ; add null char
    ret
ah_2_bit_buffer ENDP

END _main       ; Marks the end of the module and sets the program entry point label
