home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / ASM / ALIB40.ZIP / ALIB4B.ZIP / CALC.ASM next >
Encoding:
Assembly Source File  |  1997-09-11  |  14.9 KB  |  569 lines

  1. ; Small calculator for programmers.
  2. ;  ALT-Z to pop up
  3. ;
  4. ;  command line of form:   <number> <operation> <number> Enter
  5. ;
  6. ;  <number> is assumed to be decimal unless terminated with "H"
  7. ;  <operation> can be  "+-/*"
  8. ;
  9. ;----------------------------------------------------------------------------
  10.  
  11. debug        equ    0
  12.  
  13. ;---------------------------------------------------------------------------
  14. ; program equates
  15. ;---------------------------------------------------------------------------
  16.  
  17. window_start        equ    80
  18. dec_result_window    equ    120
  19. hex_result_window    equ    142
  20. window_size        equ    40
  21. window_color        equ    70h
  22.  
  23. ;----------------------------------------------------------------------------
  24. ; Bios data in low ram
  25. ;----------------------------------------------------------------------------
  26.  
  27. bios_data       segment at 40h
  28.                 org 17h
  29. bios_kbd_stat   db ?
  30.                 org 4ah
  31. bios_crt_col    dw ?
  32.                 org 63h
  33. addr_6845       dw ?
  34.                 org 84h
  35. bios_crt_row    db ?
  36. bios_data       ends
  37.  
  38. ;----------------------------------------------------------------------------
  39. ; PSP used as database for calculator to save space
  40. ;-----------------------------------------------------------------------------
  41. operation_type  equ     7eh             ;db- 0=none 1=add 2=sub 3=div 4=mul
  42. active        equ    7fh        ;db- 1=active
  43. base_flag       equ     80h             ;dw
  44.  
  45. old_kbd_status  equ     82h             ;db-
  46. old_int_9h      equ     83h             ;dd-
  47.  
  48. op1_base        equ     87h             ;db 0=no entry 10=decimal 16=hex
  49. op1_value       equ     88h             ;dd
  50.  
  51. op2_base        equ     8ch             ;db 0=no entry 10=decimal 16=hex
  52. op2_value       equ     8dh             ;dd
  53.  
  54. result          equ     91h             ;dd
  55.  
  56. display_off_cur equ     95h             ;dw-current display ptr
  57. display_segment equ     97h             ;dw-display memory ptr
  58.  
  59. op1_ascii    equ    99h        ;db(9) bcd followed by -1
  60. op2_ascii    equ    0a4h        ;db(9) bck followed by -1
  61.  
  62. relocated_int09    equ    0b0h        ;code is moved here
  63. ;
  64. ;---------------------------------------------------------------------------
  65. ;
  66. code           segment para public 'code'
  67.                assume cs:code
  68.                org 100h
  69. entry:         jmp initialize
  70. ;------------------------------------------------------------------------------
  71. ; Front-end routine for the keyboard interrupt handler.  Execution is vectored
  72. ; here whenever an interrupt 9 us generated by the PC keyboard.
  73. ;------------------------------------------------------------------------------
  74. int09_trap:
  75.                 assume cs:code,ds:code,es:nothing,ss:nothing
  76.                 cmp    byte ptr cs:active,0
  77.                 jne    quick_out
  78.                 push    ax
  79.                 in    al,60h
  80.                 cmp    al,2ch              ;check for 'z' hot key
  81.                 jne    out1
  82.                 mov    ah,2
  83.                 int    16h                 ;get keyboard flags
  84.                 and    al,0fh
  85.                 cmp    al,8                ;check if alt key down
  86.                 jne     out1                ;exit if no alt key
  87.                 jmp    calculator
  88.                 
  89. out1:           pop ax
  90. quick_out:      jmp dword ptr cs:old_int_9h
  91.  
  92. ;--------------------------------------------
  93. calculator:
  94.                 push bx
  95.                 push cx
  96.                 push dx
  97.                 push si
  98.                 push di
  99.                 push ds
  100.                 push es
  101.                 mov     ax,cs
  102.                 mov     ds,ax
  103. ;
  104. ; KB_RESET resets the keyboard and signals end-of-interrupt to the 8259.
  105. ;
  106.                 in al,61h
  107.                 mov ah,al
  108.                 or al,80h
  109.                 out 61h,al
  110.                 mov al,ah
  111.                 out 61h,al
  112.                 cli
  113.                 mov al,20h
  114.                 out 20h,al
  115.  
  116.                 mov     byte ptr ds:active,1
  117.                 sti
  118.                 mov     word ptr ds:display_off_cur,window_start
  119.  
  120.                 mov     cx,window_size
  121. clear_window:   mov     al,' '
  122.                 call    display_char
  123.                 loop    clear_window
  124.  
  125.                 mov     word ptr ds:display_off_cur,window_start
  126.  
  127. ; The window is now displayed on the screen.  Wait for a keypress.
  128. get_char_loop:
  129.                 mov     ah,0
  130.                 int     28h
  131.                 mov     ah,1
  132.                 int     16h
  133.                 jz      get_char_loop
  134.                 mov     ah,0
  135.                 int     16h
  136. int095:         cmp     al,27
  137.         jne    int09_cont1        ;jmp if not esc
  138. ;
  139. ; escape pressed
  140. ;
  141. done1:        jmp    done
  142.  
  143. int09_cont1:    cmp     al,08
  144.                 jne     int09_cont2
  145.  
  146. ; rubout last char
  147.  
  148. rubout:         cmp     word ptr ds:display_off_cur,window_start
  149.                 je      get_char_loop
  150.  
  151.                 sub     word ptr ds:display_off_cur,2
  152.                 mov     al,' '
  153.                 call    display_char
  154.                 sub     word ptr ds:display_off_cur,2
  155.         jmp    get_char_loop
  156. done_error1:    jmp    done_error
  157. ;
  158. int09_cont2:    cmp    al,0dh
  159.         je    scan_data        ;jmp if enter key
  160.                 call    display_char
  161.         jmp    get_char_loop
  162.  
  163. scan_data:    call    pre_scan
  164.         jc    done_error1
  165. ;
  166. ;  the data has been scanned and is ready for calculations
  167. ;  convert both numbers to binary
  168. ;
  169.         sub    bh,bh
  170.         mov    bl,byte ptr ds:op1_base
  171.         cmp    bl,0
  172.         je    done1
  173.         mov    si,op1_ascii
  174.         mov    di,op1_value
  175.         call    ascii_to_binary
  176.         jc    done_error1
  177.  
  178.         mov    bl,byte ptr ds:op2_base
  179.         cmp    bl,0
  180.         je    convert_only
  181.         mov    si,op2_ascii
  182.         mov    di,op2_value
  183.         call    ascii_to_binary
  184. ;
  185. ; both numbers are in binary at op1_value, op2_value
  186. ; Do operation requested.
  187. ;
  188.         mov    cl,byte ptr ds:operation_type
  189.         mov    ax,word ptr ds:op1_value
  190.         mov    dx,word ptr ds:op1_value+2
  191.  
  192.         dec    cx
  193.         jcxz    add_numbers
  194.         dec    cx
  195.         jcxz    subtract_numbers
  196.         dec    cx
  197.         jcxz    divide_numbers
  198. ;
  199. ; multiply - inputs:  ds:si = dword 1    ds:di = dword2
  200. ;
  201.         mov    bx,word ptr ds:op2_value
  202.         call    multiply        ;result in dx,ax and ds:di
  203.         jmp    display_result
  204. ;
  205. ; add two values
  206. ;
  207. add_numbers:    add    ax,word ptr ds:op2_value
  208.         adc    dx,word ptr ds:op2_value+2
  209.         jmp    display_result
  210. ;
  211. ; subtract two values
  212. ;
  213. subtract_numbers:
  214.         sub    ax,word ptr ds:op2_value
  215.         sbb    dx,word ptr ds:op2_value+2
  216.         jmp    display_result
  217. ;
  218. ; divide two values - inputs:  ds:si = dword1   ds:di = divisor (word)
  219. ;
  220. divide_numbers:    cmp    ax,0
  221.         jne    dok1
  222.         cmp    dx,0
  223.         je    d_exit
  224. dok1:        div    word ptr ds:op2_value    ;result in -ax-
  225. d_exit:        sub    dx,dx            ;clear remainder
  226.         jmp    display_result
  227. ;
  228. ; only op1 was entered, move it to result and display
  229. ;
  230. convert_only:
  231.  
  232. ;
  233. ; display result - dx,ax = result
  234. ;
  235. display_result:
  236.     push    ax
  237.     push    dx
  238.  
  239.     mov    word ptr ds:base_flag,10
  240.     mov    word ptr ds:display_off_cur,dec_result_window
  241.     call    display_number
  242.  
  243.     pop    dx
  244.     pop    ax
  245.     mov    word ptr ds:base_flag,16
  246.     mov    word ptr ds:display_off_cur,hex_result_window
  247.     call    display_number
  248.     mov    al,'H'
  249.     call    display_char
  250.     
  251. done_error:
  252. done:        mov    byte ptr ds:active,0
  253.         pop    es
  254.         pop    ds
  255.         pop    di
  256.         pop    si
  257.         pop    dx
  258.         pop    cx
  259.         pop    bx
  260.         pop    ax
  261.         iret
  262. ;-----------------------------------------------------------------------------
  263. ; scan the entry line and parse to:
  264. ;   op1_base       - 0=not found  10=decimal  16=hex
  265. ;   op1_ascii      - bcd followed by -1    
  266. ;   operation_type - 0=none  1=add 2=sub 3=div 4=mul
  267. ;   op2_base       - 0=not found  10=decimal  16=hex
  268. ;   op2_ascii      - bcd followed by -1   
  269. ;
  270. ;   carry          - set if error
  271. ;
  272. ; inputs:  es:  points at display
  273. ;          ds:  points at code segment
  274. ;
  275. pre_scan:    mov    si,window_start
  276.         mov    di,op1_ascii
  277.                 mov     byte ptr ds:op1_base,0
  278.                 mov     byte ptr ds:op2_base,0
  279.                 mov     byte ptr ds:operation_type,0
  280. ps_loop:    mov    ax,es:[si]        ;get next char
  281.         cmp    al,' '
  282.         jne    ps_cont1        ;jmp if more characters
  283. ;
  284. ; final character found
  285. ;
  286.         mov    al,'='
  287.         call    display_char
  288. ;
  289. ; verify type code are set
  290. ;
  291.         mov    al,byte ptr ds:operation_type
  292.         or    al,byte ptr ds:op1_base
  293.         jz    set_op1_base
  294.         cmp    byte ptr ds:operation_type,0
  295.         je    ps_exit1
  296. ;
  297. ; an operator was found, so verify op2 type was found
  298. ;
  299. ;!        mov    byte ptr ds:[di],-1        ;terminate value2
  300.         cmp    byte ptr ds:op2_base,0
  301.         jne    ps_exit1            ;jmp if type set
  302.         mov    byte ptr ds:op2_base,10        ;set decimal type
  303.         jmp    ps_exit1
  304. set_op1_base:    mov    byte ptr ds:op1_base,10
  305.  
  306. ps_exit1:    mov    byte ptr ds:[di],-1
  307.         clc
  308.         jmp    ps_exit
  309.  
  310. ps_cont1:    cmp    al,'+'
  311.         je    plus_op
  312.         cmp    al,'-'
  313.         je    minus_op
  314.         cmp    al,'/'
  315.         je    divide_op
  316.         cmp    al,'*'
  317.         je    multiply_op
  318.         cmp    al,'h'
  319.         je    hex_entry
  320.         cmp    al,'H'
  321.         je    hex_entry
  322.         cmp    al,'0'
  323.         jb    ignore
  324.         cmp    al,'9'
  325.         jbe    got_numeric
  326.         cmp    al,'A'
  327.         jb    ignore
  328.         cmp    al,'F'
  329.         jbe    got_hex_numeric
  330.         sub    al,20h
  331.         cmp    al,'A'
  332.         jb    ignore
  333.         cmp    al,'F'
  334.         jbe    got_hex_numeric
  335.         jmp    ignore
  336.  
  337. ignore:        jmp    bad_char
  338. got_numeric:    jmp    number_char
  339. got_hex_numeric:jmp    hex_number_char
  340.  
  341. plus_op:    mov    al,1
  342.         jmp    stuff_operation
  343. minus_op:    mov    al,2
  344.         jmp    stuff_operation
  345. divide_op:    mov    al,3
  346.         jmp    stuff_operation
  347. multiply_op:    mov    al,4
  348. stuff_operation:mov    byte ptr ds:operation_type,al
  349.         mov    byte ptr ds:[di],-1        ;terminate op1
  350.         mov    di,op2_ascii
  351.         cmp    byte ptr ds:op1_base,0
  352.         jne    nxt_char2            ;jmp if type known
  353.         mov    byte ptr ds:op1_base,10        ;decimal type
  354.         jmp    nxt_char2
  355.         
  356. hex_entry:      cmp     byte ptr ds:op1_base,0
  357.         je    this_is_op1
  358.         mov    byte ptr ds:op2_base,16
  359.         jmp    nxt_char2
  360. this_is_op1:    mov    byte ptr ds:op1_base,16
  361.         jmp    nxt_char2
  362.         
  363. number_char:    sub    al,'0'
  364.         jmp    nxt_char1
  365.                 
  366. hex_number_char:sub    al,('A'-10)
  367. nxt_char1:    mov    byte ptr ds:[di],al
  368.         inc    di
  369. nxt_char2:    add    si,2
  370.         jmp    ps_loop
  371.  
  372. bad_char:    stc
  373. ps_exit:    ret
  374. ;-----------------------------------------------------------------------------
  375. ; display character
  376. ;  inputs:  al = char
  377. ;
  378. display_char:
  379.     push    di
  380.         cld
  381.         mov     ah,window_color                     ;get attribute
  382.         les     di,dword ptr ds:display_off_cur      ;get display point
  383.         stosw
  384.         mov     word ptr ds:display_off_cur,di
  385.         pop    di
  386.         ret
  387. ;-----------------------------------------------------------------------------
  388. ; convert ascii string to binary
  389. ;  inputs  ds:si numeric string
  390. ;          bx = base
  391. ;          ds:di = result storage area
  392. ;  output
  393. ;          si = updated to point at end of value
  394. ;          carry set if error
  395. ;
  396.  
  397. ascii_to_binary:
  398.     sub    dx,dx            ;clear high accumulator
  399.     sub    ax,ax            ;clear low accumulator
  400.     jmp    ab2
  401. ab_loop:
  402.     inc    si            ;move to next char
  403. ab2:    mov    cl,[si]
  404.     cmp    cl,-1
  405.     je    ab_done            ;jmp if done
  406.     cmp    cl,bl
  407.     ja    ab_err            ;jmp if char. out of range
  408.     sub    ch,ch
  409. ;
  410. ; multiply sum by current base
  411. ;
  412.     call    multiply        ;dx,ax * bx
  413. ;
  414. ; add latest character to sum
  415. ;
  416.     add    ax,cx            ;add to sum
  417.     adc    dx,0            ;add carry
  418.     jmp    ab_loop
  419. ab_done:
  420.     clc
  421.     mov    word ptr ds:[di],ax
  422.     mov    word ptr ds:[di+2],dx
  423.     jmp    ab_exit
  424. ab_err:
  425.     stc
  426. ab_exit:
  427.     ret
  428. ;-----------------------------------------------------------------------------
  429. ;  inputs:  dx,ax = binary value
  430. ;  outputs: none
  431. ;
  432. ;  registers destroyed:  ax,dx
  433. ;
  434.   
  435. display_number:
  436.         push    ax
  437.         mov    ax,dx
  438.         xor    dx,dx
  439.         div    word ptr ds:base_flag
  440.         mov    bx,ax
  441.         pop    ax
  442.         div    word ptr ds:base_flag
  443.         xchg    bx,dx
  444. ;
  445. ; dx,ax = quotient
  446. ;    bx = remainder
  447.  
  448.         or    ax,ax
  449.         jnz    dd_more
  450.         or    dx,dx
  451.         jnz    dd_more
  452.         mov    dx,bx
  453.         jmp    ddb_display
  454. dd_more:
  455.         push    bx            ;save remainder        
  456.     
  457.         call    display_number        ;recursion
  458.         pop    dx
  459. ddb_display:    add    dl,30h            ;convert char. to ascii
  460.         cmp    dl,'9'
  461.         jbe    dd_dsp
  462.         add    dl,('A'-'9'-1)
  463. dd_dsp:        push    ax
  464.         mov    al,dl
  465.         call    display_char
  466.         pop    ax
  467.         ret
  468.  
  469. ;---------------------------------------------------------------------------
  470. ; multiply two numbers
  471. ;  inputs:  dx,ax * bx
  472. ;  output:  dx,ax is updated
  473. ;           result to [di] also
  474. ;
  475. multiply:
  476.     push    ax
  477.     mov    ax,dx
  478.     mul    bx
  479.     mov    word ptr ds:[di+2],ax
  480.     pop    ax
  481.     mul    bx
  482.     add    word ptr ds:[di+2],dx
  483.     mov    word ptr ds:[di],ax
  484.     mov    dx,word ptr ds:[di+2]
  485.     ret    
  486. ;---------------------------------------------------------------------------
  487.  
  488. ;!        db    8 dup (0)  
  489.  
  490. ;------------------------------------------------------------------------------
  491. ; INITIALIZE redirects the keyboard interrupt, then reserves enough memory for
  492. ; the program to remain resident.
  493. ;------------------------------------------------------------------------------
  494. initialize:
  495.  
  496. ; determine location of display segment
  497.  
  498.                 mov     ah,15
  499.                 int     10h
  500.                 mov     bx,0b000h               ;preload mda
  501.                 cmp     al,7
  502.                 je      stuff_vseg
  503.                 mov     bx,0b800h
  504. stuff_vseg:     mov     word ptr ds:[display_segment],bx
  505.  
  506.                 mov     word ptr ds:base_flag,10  ;decimal
  507.                 mov     byte ptr ds:op1_base,0
  508.                 mov     word ptr ds:op1_value,0
  509.                 mov     word ptr ds:op1_value+2,0
  510.                 mov     byte ptr ds:op2_base,0
  511.                 mov     word ptr ds:op2_value,0
  512.                 mov     word ptr ds:op2_value+2,0
  513.                 mov     word ptr ds:result,0
  514.                 mov     word ptr ds:result+2,0
  515.                 mov     byte ptr ds:operation_type,0
  516.                 mov     word ptr ds:display_off_cur,window_start
  517.                 mov     byte ptr ds:active,0
  518.  
  519.                 mov dx,offset program
  520.                 mov ah,9
  521.                 int 21h
  522.  
  523. if debug
  524.     jmp    calculator
  525. endif
  526. ;
  527. ; move code up into psp
  528. ;
  529.         mov    si,offset int09_trap
  530.         mov    di,relocated_int09
  531.         mov    cx,(offset initialize -103h)
  532.         cld
  533.         rep    movsb
  534.         mov    cx,50h
  535.         mov    al,0
  536.         rep    stosb            ;clear end of program
  537.                       
  538. no_copies:      mov ah,35h
  539.                 mov al,9
  540.                 int 21h
  541.                 mov     word ptr ds:old_int_9h,bx
  542.                 mov     word ptr ds:old_int_9h+2,es
  543.                 mov ah,25h
  544.                 mov al,9
  545.                 mov dx,relocated_int09        ;offset int09_trap
  546.                 int 21h
  547. ; Exit by TSR int 31h.
  548.                 mov    dx,offset initialize
  549.                 sub    dx,050h-15
  550.                 mov    cl,4
  551.                 shr    dx,cl
  552.                 mov    ax,3100h
  553.                 int    21h
  554.  
  555. program         db      0dh,0ah
  556.  db '┌────────────────────────────────────────────────────────────────────────┐',0dh,0ah
  557.  db '│  CALC (small programmers calculator)  ** ALT-Z ** for each calculation │',0dh,0ah
  558.  db '│                                                                        │',0dh,0ah
  559.  db '│        Usage:   <number> <operator> <number> Enter                     │',0dh,0ah
  560.  db '│                                                                        │',0dh,0ah
  561.  db '│        <number>  decimal or hex number, hex numbers of form  nnnnH     │',0dh,0ah
  562.  db '│        <operator> any of the following  + - / * Enter                  │',0dh,0ah
  563.  db '│                                                                        │',0dh,0ah
  564.  db '│  Released to public domain by Jeff Owens, Estacada, Oregon             │',0dh,0ah
  565.  db '└────────────────────────────────────────────────────────────────────────┘',0dh,0ah
  566.  db 0dh,0ah,'$'
  567. code            ends
  568.         end     entry
  569.