home *** CD-ROM | disk | FTP | other *** search
- ; Small calculator for programmers.
- ; ALT-Z to pop up
- ;
- ; command line of form: <number> <operation> <number> Enter
- ;
- ; <number> is assumed to be decimal unless terminated with "H"
- ; <operation> can be "+-/*"
- ;
- ;----------------------------------------------------------------------------
-
- debug equ 0
-
- ;---------------------------------------------------------------------------
- ; program equates
- ;---------------------------------------------------------------------------
-
- window_start equ 80
- dec_result_window equ 120
- hex_result_window equ 142
- window_size equ 40
- window_color equ 70h
-
- ;----------------------------------------------------------------------------
- ; Bios data in low ram
- ;----------------------------------------------------------------------------
-
- bios_data segment at 40h
- org 17h
- bios_kbd_stat db ?
- org 4ah
- bios_crt_col dw ?
- org 63h
- addr_6845 dw ?
- org 84h
- bios_crt_row db ?
- bios_data ends
-
- ;----------------------------------------------------------------------------
- ; PSP used as database for calculator to save space
- ;-----------------------------------------------------------------------------
- operation_type equ 7eh ;db- 0=none 1=add 2=sub 3=div 4=mul
- active equ 7fh ;db- 1=active
- base_flag equ 80h ;dw
-
- old_kbd_status equ 82h ;db-
- old_int_9h equ 83h ;dd-
-
- op1_base equ 87h ;db 0=no entry 10=decimal 16=hex
- op1_value equ 88h ;dd
-
- op2_base equ 8ch ;db 0=no entry 10=decimal 16=hex
- op2_value equ 8dh ;dd
-
- result equ 91h ;dd
-
- display_off_cur equ 95h ;dw-current display ptr
- display_segment equ 97h ;dw-display memory ptr
-
- op1_ascii equ 99h ;db(9) bcd followed by -1
- op2_ascii equ 0a4h ;db(9) bck followed by -1
-
- relocated_int09 equ 0b0h ;code is moved here
- ;
- ;---------------------------------------------------------------------------
- ;
- code segment para public 'code'
- assume cs:code
- org 100h
- entry: jmp initialize
- ;------------------------------------------------------------------------------
- ; Front-end routine for the keyboard interrupt handler. Execution is vectored
- ; here whenever an interrupt 9 us generated by the PC keyboard.
- ;------------------------------------------------------------------------------
- int09_trap:
- assume cs:code,ds:code,es:nothing,ss:nothing
- cmp byte ptr cs:active,0
- jne quick_out
- push ax
- in al,60h
- cmp al,2ch ;check for 'z' hot key
- jne out1
- mov ah,2
- int 16h ;get keyboard flags
- and al,0fh
- cmp al,8 ;check if alt key down
- jne out1 ;exit if no alt key
- jmp calculator
-
- out1: pop ax
- quick_out: jmp dword ptr cs:old_int_9h
-
- ;--------------------------------------------
- calculator:
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- mov ax,cs
- mov ds,ax
- ;
- ; KB_RESET resets the keyboard and signals end-of-interrupt to the 8259.
- ;
- in al,61h
- mov ah,al
- or al,80h
- out 61h,al
- mov al,ah
- out 61h,al
- cli
- mov al,20h
- out 20h,al
-
- mov byte ptr ds:active,1
- sti
- mov word ptr ds:display_off_cur,window_start
-
- mov cx,window_size
- clear_window: mov al,' '
- call display_char
- loop clear_window
-
- mov word ptr ds:display_off_cur,window_start
-
- ; The window is now displayed on the screen. Wait for a keypress.
- get_char_loop:
- mov ah,0
- int 28h
- mov ah,1
- int 16h
- jz get_char_loop
- mov ah,0
- int 16h
- int095: cmp al,27
- jne int09_cont1 ;jmp if not esc
- ;
- ; escape pressed
- ;
- done1: jmp done
-
- int09_cont1: cmp al,08
- jne int09_cont2
-
- ; rubout last char
-
- rubout: cmp word ptr ds:display_off_cur,window_start
- je get_char_loop
-
- sub word ptr ds:display_off_cur,2
- mov al,' '
- call display_char
- sub word ptr ds:display_off_cur,2
- jmp get_char_loop
- done_error1: jmp done_error
- ;
- int09_cont2: cmp al,0dh
- je scan_data ;jmp if enter key
- call display_char
- jmp get_char_loop
-
- scan_data: call pre_scan
- jc done_error1
- ;
- ; the data has been scanned and is ready for calculations
- ; convert both numbers to binary
- ;
- sub bh,bh
- mov bl,byte ptr ds:op1_base
- cmp bl,0
- je done1
- mov si,op1_ascii
- mov di,op1_value
- call ascii_to_binary
- jc done_error1
-
- mov bl,byte ptr ds:op2_base
- cmp bl,0
- je convert_only
- mov si,op2_ascii
- mov di,op2_value
- call ascii_to_binary
- ;
- ; both numbers are in binary at op1_value, op2_value
- ; Do operation requested.
- ;
- mov cl,byte ptr ds:operation_type
- mov ax,word ptr ds:op1_value
- mov dx,word ptr ds:op1_value+2
-
- dec cx
- jcxz add_numbers
- dec cx
- jcxz subtract_numbers
- dec cx
- jcxz divide_numbers
- ;
- ; multiply - inputs: ds:si = dword 1 ds:di = dword2
- ;
- mov bx,word ptr ds:op2_value
- call multiply ;result in dx,ax and ds:di
- jmp display_result
- ;
- ; add two values
- ;
- add_numbers: add ax,word ptr ds:op2_value
- adc dx,word ptr ds:op2_value+2
- jmp display_result
- ;
- ; subtract two values
- ;
- subtract_numbers:
- sub ax,word ptr ds:op2_value
- sbb dx,word ptr ds:op2_value+2
- jmp display_result
- ;
- ; divide two values - inputs: ds:si = dword1 ds:di = divisor (word)
- ;
- divide_numbers: cmp ax,0
- jne dok1
- cmp dx,0
- je d_exit
- dok1: div word ptr ds:op2_value ;result in -ax-
- d_exit: sub dx,dx ;clear remainder
- jmp display_result
- ;
- ; only op1 was entered, move it to result and display
- ;
- convert_only:
-
- ;
- ; display result - dx,ax = result
- ;
- display_result:
- push ax
- push dx
-
- mov word ptr ds:base_flag,10
- mov word ptr ds:display_off_cur,dec_result_window
- call display_number
-
- pop dx
- pop ax
- mov word ptr ds:base_flag,16
- mov word ptr ds:display_off_cur,hex_result_window
- call display_number
- mov al,'H'
- call display_char
-
- done_error:
- done: mov byte ptr ds:active,0
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- iret
- ;-----------------------------------------------------------------------------
- ; scan the entry line and parse to:
- ; op1_base - 0=not found 10=decimal 16=hex
- ; op1_ascii - bcd followed by -1
- ; operation_type - 0=none 1=add 2=sub 3=div 4=mul
- ; op2_base - 0=not found 10=decimal 16=hex
- ; op2_ascii - bcd followed by -1
- ;
- ; carry - set if error
- ;
- ; inputs: es: points at display
- ; ds: points at code segment
- ;
- pre_scan: mov si,window_start
- mov di,op1_ascii
- mov byte ptr ds:op1_base,0
- mov byte ptr ds:op2_base,0
- mov byte ptr ds:operation_type,0
- ps_loop: mov ax,es:[si] ;get next char
- cmp al,' '
- jne ps_cont1 ;jmp if more characters
- ;
- ; final character found
- ;
- mov al,'='
- call display_char
- ;
- ; verify type code are set
- ;
- mov al,byte ptr ds:operation_type
- or al,byte ptr ds:op1_base
- jz set_op1_base
- cmp byte ptr ds:operation_type,0
- je ps_exit1
- ;
- ; an operator was found, so verify op2 type was found
- ;
- ;! mov byte ptr ds:[di],-1 ;terminate value2
- cmp byte ptr ds:op2_base,0
- jne ps_exit1 ;jmp if type set
- mov byte ptr ds:op2_base,10 ;set decimal type
- jmp ps_exit1
- set_op1_base: mov byte ptr ds:op1_base,10
-
- ps_exit1: mov byte ptr ds:[di],-1
- clc
- jmp ps_exit
-
- ps_cont1: cmp al,'+'
- je plus_op
- cmp al,'-'
- je minus_op
- cmp al,'/'
- je divide_op
- cmp al,'*'
- je multiply_op
- cmp al,'h'
- je hex_entry
- cmp al,'H'
- je hex_entry
- cmp al,'0'
- jb ignore
- cmp al,'9'
- jbe got_numeric
- cmp al,'A'
- jb ignore
- cmp al,'F'
- jbe got_hex_numeric
- sub al,20h
- cmp al,'A'
- jb ignore
- cmp al,'F'
- jbe got_hex_numeric
- jmp ignore
-
- ignore: jmp bad_char
- got_numeric: jmp number_char
- got_hex_numeric:jmp hex_number_char
-
- plus_op: mov al,1
- jmp stuff_operation
- minus_op: mov al,2
- jmp stuff_operation
- divide_op: mov al,3
- jmp stuff_operation
- multiply_op: mov al,4
- stuff_operation:mov byte ptr ds:operation_type,al
- mov byte ptr ds:[di],-1 ;terminate op1
- mov di,op2_ascii
- cmp byte ptr ds:op1_base,0
- jne nxt_char2 ;jmp if type known
- mov byte ptr ds:op1_base,10 ;decimal type
- jmp nxt_char2
-
- hex_entry: cmp byte ptr ds:op1_base,0
- je this_is_op1
- mov byte ptr ds:op2_base,16
- jmp nxt_char2
- this_is_op1: mov byte ptr ds:op1_base,16
- jmp nxt_char2
-
- number_char: sub al,'0'
- jmp nxt_char1
-
- hex_number_char:sub al,('A'-10)
- nxt_char1: mov byte ptr ds:[di],al
- inc di
- nxt_char2: add si,2
- jmp ps_loop
-
- bad_char: stc
- ps_exit: ret
- ;-----------------------------------------------------------------------------
- ; display character
- ; inputs: al = char
- ;
- display_char:
- push di
- cld
- mov ah,window_color ;get attribute
- les di,dword ptr ds:display_off_cur ;get display point
- stosw
- mov word ptr ds:display_off_cur,di
- pop di
- ret
- ;-----------------------------------------------------------------------------
- ; convert ascii string to binary
- ; inputs ds:si numeric string
- ; bx = base
- ; ds:di = result storage area
- ; output
- ; si = updated to point at end of value
- ; carry set if error
- ;
-
- ascii_to_binary:
- sub dx,dx ;clear high accumulator
- sub ax,ax ;clear low accumulator
- jmp ab2
- ab_loop:
- inc si ;move to next char
- ab2: mov cl,[si]
- cmp cl,-1
- je ab_done ;jmp if done
- cmp cl,bl
- ja ab_err ;jmp if char. out of range
- sub ch,ch
- ;
- ; multiply sum by current base
- ;
- call multiply ;dx,ax * bx
- ;
- ; add latest character to sum
- ;
- add ax,cx ;add to sum
- adc dx,0 ;add carry
- jmp ab_loop
- ab_done:
- clc
- mov word ptr ds:[di],ax
- mov word ptr ds:[di+2],dx
- jmp ab_exit
- ab_err:
- stc
- ab_exit:
- ret
- ;-----------------------------------------------------------------------------
- ; inputs: dx,ax = binary value
- ; outputs: none
- ;
- ; registers destroyed: ax,dx
- ;
-
- display_number:
- push ax
- mov ax,dx
- xor dx,dx
- div word ptr ds:base_flag
- mov bx,ax
- pop ax
- div word ptr ds:base_flag
- xchg bx,dx
- ;
- ; dx,ax = quotient
- ; bx = remainder
-
- or ax,ax
- jnz dd_more
- or dx,dx
- jnz dd_more
- mov dx,bx
- jmp ddb_display
- dd_more:
- push bx ;save remainder
-
- call display_number ;recursion
- pop dx
- ddb_display: add dl,30h ;convert char. to ascii
- cmp dl,'9'
- jbe dd_dsp
- add dl,('A'-'9'-1)
- dd_dsp: push ax
- mov al,dl
- call display_char
- pop ax
- ret
-
- ;---------------------------------------------------------------------------
- ; multiply two numbers
- ; inputs: dx,ax * bx
- ; output: dx,ax is updated
- ; result to [di] also
- ;
- multiply:
- push ax
- mov ax,dx
- mul bx
- mov word ptr ds:[di+2],ax
- pop ax
- mul bx
- add word ptr ds:[di+2],dx
- mov word ptr ds:[di],ax
- mov dx,word ptr ds:[di+2]
- ret
- ;---------------------------------------------------------------------------
-
- ;! db 8 dup (0)
-
- ;------------------------------------------------------------------------------
- ; INITIALIZE redirects the keyboard interrupt, then reserves enough memory for
- ; the program to remain resident.
- ;------------------------------------------------------------------------------
- initialize:
-
- ; determine location of display segment
-
- mov ah,15
- int 10h
- mov bx,0b000h ;preload mda
- cmp al,7
- je stuff_vseg
- mov bx,0b800h
- stuff_vseg: mov word ptr ds:[display_segment],bx
-
- mov word ptr ds:base_flag,10 ;decimal
- mov byte ptr ds:op1_base,0
- mov word ptr ds:op1_value,0
- mov word ptr ds:op1_value+2,0
- mov byte ptr ds:op2_base,0
- mov word ptr ds:op2_value,0
- mov word ptr ds:op2_value+2,0
- mov word ptr ds:result,0
- mov word ptr ds:result+2,0
- mov byte ptr ds:operation_type,0
- mov word ptr ds:display_off_cur,window_start
- mov byte ptr ds:active,0
-
- mov dx,offset program
- mov ah,9
- int 21h
-
- if debug
- jmp calculator
- endif
- ;
- ; move code up into psp
- ;
- mov si,offset int09_trap
- mov di,relocated_int09
- mov cx,(offset initialize -103h)
- cld
- rep movsb
- mov cx,50h
- mov al,0
- rep stosb ;clear end of program
-
- no_copies: mov ah,35h
- mov al,9
- int 21h
- mov word ptr ds:old_int_9h,bx
- mov word ptr ds:old_int_9h+2,es
- mov ah,25h
- mov al,9
- mov dx,relocated_int09 ;offset int09_trap
- int 21h
- ; Exit by TSR int 31h.
- mov dx,offset initialize
- sub dx,050h-15
- mov cl,4
- shr dx,cl
- mov ax,3100h
- int 21h
-
- program db 0dh,0ah
- db '┌────────────────────────────────────────────────────────────────────────┐',0dh,0ah
- db '│ CALC (small programmers calculator) ** ALT-Z ** for each calculation │',0dh,0ah
- db '│ │',0dh,0ah
- db '│ Usage: <number> <operator> <number> Enter │',0dh,0ah
- db '│ │',0dh,0ah
- db '│ <number> decimal or hex number, hex numbers of form nnnnH │',0dh,0ah
- db '│ <operator> any of the following + - / * Enter │',0dh,0ah
- db '│ │',0dh,0ah
- db '│ Released to public domain by Jeff Owens, Estacada, Oregon │',0dh,0ah
- db '└────────────────────────────────────────────────────────────────────────┘',0dh,0ah
- db 0dh,0ah,'$'
- code ends
- end entry
-