Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. $Revision: 431 $
  2. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3. ;;                                                              ;;
  4. ;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;;
  5. ;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa      ;;
  6. ;; Distributed under terms of the GNU General Public License    ;;
  7. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  8.  
  9. align 4
  10. init_events:
  11.            stdcall kernel_alloc, 512*EVENT_SIZE
  12.            mov [events], eax
  13.            xor eax, eax
  14.            mov [event_uid], eax
  15.            not eax
  16.            mov edi, event_map
  17.            mov [event_start], edi
  18.            mov ecx, 64/4
  19.            cld
  20.            rep stosd
  21.            mov [event_end], edi
  22.            ret
  23.  
  24. align 4
  25. proc alloc_event
  26.  
  27.            pushfd
  28.            cli
  29.            mov ebx, [event_start]
  30.            mov ecx, [event_end]
  31. .l1:
  32.            bsf eax,[ebx]
  33.            jnz .found
  34.            add ebx,4
  35.            cmp ebx, ecx
  36.            jb .l1
  37.            popfd
  38.            xor eax,eax
  39.            ret
  40. .found:
  41.            btr [ebx], eax
  42.            mov [event_start],ebx
  43.            inc [event_uid]
  44.  
  45.            sub ebx, event_map
  46.            lea eax,[eax+ebx*8]
  47.  
  48.            lea ebx, [eax+eax*4]
  49.            shl eax,5
  50.            lea eax,[eax+ebx*4]   ;eax*=52 (EVENT_SIZE)
  51.            add eax, [events]
  52.            mov ebx, [event_uid]
  53.            popfd
  54.            ret
  55. endp
  56.  
  57. align 4
  58. free_event:
  59.            sub eax, [events]
  60.            mov ecx, EVENT_SIZE
  61.            mov ebx, event_map
  62.            cdq
  63.            div ecx
  64.  
  65.            pushfd
  66.            cli
  67.            bts [ebx], eax
  68.            shr eax, 3
  69.            and eax, not 3
  70.            add eax, ebx
  71.            cmp [event_start], eax
  72.            ja @f
  73.            popfd
  74.            ret
  75. @@:
  76.            mov [event_start], eax
  77.            popfd
  78.            ret
  79.  
  80. EVENT_WATCHED    equ 0x10000000
  81. EVENT_SIGNALED   equ 0x20000000
  82. MANUAL_RESET     equ 0x40000000
  83. MANUAL_DESTROY   equ 0x80000000
  84.  
  85.  
  86. ; param
  87. ;  eax= event data
  88. ;  ebx= flags
  89. ;
  90. ; retval
  91. ;  eax= event
  92. ;  edx= id
  93.  
  94. create_event:
  95.            .flags  equ  esp+4
  96.            .data   equ  esp
  97.  
  98.            push ebx
  99.            push eax
  100.  
  101.            call alloc_event
  102.            test eax, eax
  103.            jz .fail
  104.  
  105.            mov [eax+APPOBJ.magic], 'EVNT'
  106.            mov [eax+APPOBJ.destroy], destroy_event.internal
  107.            mov [eax+EVENT.id], ebx
  108.  
  109.            mov ebx, [CURRENT_TASK]
  110.            shl ebx, 5
  111.            mov ebx, [CURRENT_TASK+ebx+4]
  112.            mov [eax+APPOBJ.pid], ebx
  113.            mov edx, [.flags]
  114.            mov [eax+EVENT.state], edx
  115.  
  116.            mov esi, [.data]
  117.            test esi, esi
  118.            jz @F
  119.            lea edi, [eax+EVENT.code]
  120.            mov ecx, 6
  121.            cld
  122.            rep movsd
  123. @@:
  124.            mov ecx, [CURRENT_TASK]
  125.            shl ecx,8
  126.            add ecx, SLOT_BASE+APP_OBJ_OFFSET
  127.  
  128.            pushfd
  129.            cli
  130.            mov edx, [ecx+APPOBJ.fd]
  131.            mov [eax+APPOBJ.fd], edx
  132.            mov [eax+APPOBJ.bk], ecx
  133.            mov [ecx+APPOBJ.fd], eax
  134.            mov [edx+APPOBJ.bk], eax
  135.            popfd
  136.            mov edx, [eax+EVENT.id]
  137. .fail:
  138.            add esp, 8
  139.            ret
  140.  
  141. restore .flags
  142. restore .data
  143.  
  144. ; param
  145. ;  eax= event
  146. ;  ebx= id
  147.  
  148. destroy_event:
  149.  
  150.            cmp [eax+APPOBJ.magic], 'EVNT'
  151.            jne .fail
  152.            cmp [eax+EVENT.id], ebx
  153.            jne .fail
  154. .internal:
  155.            mov ebx, [eax+APPOBJ.fd]
  156.            mov ecx, [eax+APPOBJ.bk]
  157.            mov [ebx+APPOBJ.bk], ecx
  158.            mov [ecx+APPOBJ.fd], ebx
  159. .force:
  160.            xor edx, edx             ;clear common header
  161.            mov [eax], edx
  162.            mov [eax+4], edx
  163.            mov [eax+8], edx
  164.            mov [eax+12], edx
  165.            mov [eax+16], edx
  166.  
  167.            call free_event          ;release object memory
  168. .fail:
  169.            ret
  170.  
  171. align 4
  172. proc send_event stdcall pid:dword, event:dword
  173.            locals
  174.              slot     dd ?
  175.            endl
  176.  
  177.            mov eax, [pid]
  178.            call pid_to_slot
  179.            test eax, eax
  180.            jz .fail
  181.  
  182.            shl eax, 8
  183.            cmp [SLOT_BASE+eax+APPDATA.ev_count], 32
  184.            ja .fail
  185.  
  186.            mov [slot], eax
  187.  
  188.            call alloc_event
  189.            test eax, eax
  190.            jz .fail
  191.  
  192.            lea edi, [eax+EVENT.code]
  193.            mov ecx, 6
  194.            mov esi, [event]
  195.            cld
  196.            rep movsd
  197.  
  198.            mov ecx, [slot]
  199.            add ecx, SLOT_BASE+APP_EV_OFFSET
  200.  
  201.            mov [eax+APPOBJ.magic], 'EVNT'
  202.            mov [eax+APPOBJ.destroy], destroy_event
  203.            mov ebx, [pid]
  204.            mov [eax+APPOBJ.pid], ebx
  205.            mov [eax+EVENT.state], EVENT_SIGNALED
  206.  
  207.            pushfd
  208.            cli                         ;insert event into
  209.            mov edx, [ecx+APPOBJ.fd]    ;events list
  210.            mov [eax+APPOBJ.fd], edx    ;and set events flag
  211.            mov [eax+APPOBJ.bk], ecx
  212.            mov [ecx+APPOBJ.fd], eax
  213.            mov [edx+APPOBJ.bk], eax
  214.            inc [ecx+APPDATA.ev_count-APP_EV_OFFSET]
  215.            or  [ecx+APPDATA.event_mask-APP_EV_OFFSET], EVENT_EXTENDED
  216.            popfd
  217. .fail:
  218.            ret
  219. endp
  220.  
  221. ; timeout ignored
  222.  
  223. align 4
  224. proc get_event_ex stdcall, p_ev:dword, timeout:dword
  225.  
  226. .wait:
  227.            mov edx,[CURRENT_TASK]
  228.            shl edx,8
  229. ;           cmp [SLOT_BASE+edx+APPDATA.ev_count], 0
  230. ;           je .switch
  231.  
  232.            add edx, SLOT_BASE+APP_EV_OFFSET
  233.  
  234.            mov eax, [edx+APPOBJ.fd]
  235.            cmp eax, edx
  236.            je .switch
  237.  
  238.            lea esi, [eax+EVENT.code]
  239.            mov edi, [p_ev]                ;copy event data
  240.            mov ecx, 6
  241.            cld
  242.            rep movsd
  243.  
  244.            and dword [edi-24], 0xFF00FFFF ;clear priority field
  245.                                          ;
  246.            test [eax+EVENT.state], MANUAL_RESET
  247.            jnz .done
  248.  
  249.            pushfd
  250.            cli                         ;remove event from events
  251.            mov ebx, [eax+APPOBJ.fd]    ;list (reset event)
  252.            mov ecx, [eax+APPOBJ.bk]    ;and clear events flag
  253.            mov [ebx+APPOBJ.bk], ecx    ;if no active events
  254.            mov [ecx+APPOBJ.fd], ebx
  255.  
  256.            and [eax+EVENT.state], not (EVENT_SIGNALED+EVENT_WATCHED)
  257.  
  258.            dec [edx+APPDATA.ev_count-APP_EV_OFFSET]
  259.            jnz @F
  260.            and [edx+APPDATA.event_mask-APP_EV_OFFSET], not EVENT_EXTENDED
  261. @@:
  262.            popfd
  263.  
  264.            test [eax+EVENT.state], MANUAL_DESTROY
  265.            jz .destroy
  266.  
  267.            add edx, (APP_OBJ_OFFSET-APP_EV_OFFSET)
  268.  
  269.            pushfd
  270.            cli
  271.            mov ebx, [edx+APPOBJ.fd]  ;insert event into
  272.            mov [eax+APPOBJ.fd], ebx  ;objects list
  273.            mov [eax+APPOBJ.bk], edx
  274.            mov [edx+APPOBJ.fd], eax
  275.            mov [ebx+APPOBJ.bk], eax
  276.            popfd
  277. .done:
  278.            ret
  279.  
  280. .destroy:
  281.            call destroy_event.force
  282.            ret
  283. .switch:
  284.            mov eax, [TASK_BASE]
  285.            mov [eax+TASKDATA.state], byte 5
  286.            call change_task
  287.            jmp .wait
  288. endp
  289.  
  290. ; param
  291. ;  eax= event
  292. ;  ebx= id
  293.  
  294. align 4
  295. wait_event:
  296.            .event equ esp
  297.            push eax
  298. .wait:
  299.            cmp [eax+APPOBJ.magic], 'EVNT'
  300.            jne .done
  301.            cmp [eax+EVENT.id], ebx
  302.            jne .done
  303.  
  304.            test [eax+EVENT.state], EVENT_SIGNALED
  305.            jz .switch
  306.  
  307.            test [eax+EVENT.state], MANUAL_RESET
  308.            jnz .done
  309.  
  310.            mov edx,[CURRENT_TASK]
  311.            shl edx,8
  312.            add edx, SLOT_BASE
  313.  
  314.            pushfd
  315.            cli                         ;remove event from events
  316.            mov ebx, [eax+APPOBJ.fd]    ;list (reset event)
  317.            mov ecx, [eax+APPOBJ.bk]    ;and clear events flag
  318.            mov [ebx+APPOBJ.bk], ecx    ;if no active events
  319.            mov [ecx+APPOBJ.fd], ebx
  320.            dec [edx+APPDATA.ev_count]
  321.            jnz @F
  322.            and [edx+APPDATA.event_mask], not EVENT_EXTENDED
  323. @@:
  324.            and [eax+EVENT.state], not (EVENT_SIGNALED+EVENT_WATCHED)
  325.            popfd
  326.  
  327.            test [eax+EVENT.state], MANUAL_DESTROY
  328.            jz .destroy
  329.  
  330.            add edx, APP_OBJ_OFFSET
  331.  
  332.            pushfd
  333.            cli
  334.            mov ecx, [edx+APPOBJ.fd]  ;insert event into
  335.            mov [eax+APPOBJ.fd], ecx  ;objects list
  336.            mov [eax+APPOBJ.bk], edx
  337.            mov [edx+APPOBJ.fd], eax
  338.            mov [ecx+APPOBJ.bk], eax
  339.            popfd
  340. .done:
  341.            add esp, 4
  342.            ret
  343. .destroy:
  344.            call destroy_event.force
  345.            add esp, 4
  346.            ret
  347. .switch:
  348.            or [eax+EVENT.state], EVENT_WATCHED
  349.            mov eax, [TASK_BASE]
  350.            mov [eax+TASKDATA.state], byte 5
  351.            call change_task
  352.            mov eax, [.event]
  353.            jmp .wait
  354. restore .event
  355.  
  356. ; param
  357. ;  eax= event
  358. ;  ebx= id
  359. ;  ecx= flags
  360. ;  edx= event data
  361.  
  362. raise_event:
  363.            .event equ esp
  364.            push eax
  365.  
  366.            cmp [eax+APPOBJ.magic], 'EVNT'
  367.            jne .fail
  368.            cmp [eax+EVENT.id], ebx
  369.            jne .fail
  370.  
  371.            mov eax, [eax+APPOBJ.pid]
  372.            call pid_to_slot
  373.            test eax, eax
  374.            jz .fail
  375.  
  376.            mov esi, edx
  377.            test esi, esi
  378.            mov edx, [.event]
  379.            jz @F
  380.  
  381.            push ecx
  382.            lea edi, [edx+EVENT.code]
  383.            mov ecx, 6
  384.            cld
  385.            rep movsd
  386.            pop ecx
  387. @@:
  388.            test [edx+EVENT.state], EVENT_SIGNALED
  389.            jnz .done
  390.  
  391.            test ecx, EVENT_WATCHED
  392.            jz @F
  393.            test [edx+EVENT.state], EVENT_WATCHED
  394.            jz .done
  395. @@:
  396.            shl eax, 8
  397.            add eax, SLOT_BASE+APP_EV_OFFSET
  398.  
  399.            pushfd
  400.            cli
  401.            mov ebx, [edx+APPOBJ.fd]
  402.            mov ecx, [edx+APPOBJ.bk]
  403.            mov [ebx+APPOBJ.bk], ecx
  404.            mov [ecx+APPOBJ.fd], ebx
  405.  
  406.            mov ecx, [eax+APPOBJ.fd]
  407.            mov [edx+APPOBJ.fd], ecx
  408.            mov [edx+APPOBJ.bk], eax
  409.            mov [eax+APPOBJ.fd], edx
  410.            mov [ecx+APPOBJ.bk], edx
  411.            or [edx+EVENT.state], EVENT_SIGNALED
  412.  
  413.            inc [eax+APPDATA.ev_count-APP_EV_OFFSET]
  414.            or  [eax+APPDATA.event_mask-APP_EV_OFFSET], EVENT_EXTENDED
  415.            popfd
  416. .fail:
  417. .done:
  418.            add esp, 4
  419.            ret
  420. restore .event
  421.  
  422. ; param
  423. ;  eax= event
  424. ;  ebx= id
  425. align 4
  426. clear_event:
  427.            .event equ esp
  428.            push eax
  429.  
  430.            cmp [eax+APPOBJ.magic], 'EVNT'
  431.            jne .fail
  432.            cmp [eax+EVENT.id], ebx
  433.            jne .fail
  434.  
  435.            mov eax, [eax+APPOBJ.pid]
  436.            call pid_to_slot
  437.            test eax, eax
  438.            jz .fail
  439.  
  440.            shl eax, 8
  441.            add eax, SLOT_BASE+APP_EV_OFFSET
  442.            mov edx, [.event]
  443.            pushfd
  444.            cli                         ;remove event from events
  445.            mov ebx, [edx+APPOBJ.fd]    ;list (reset event)
  446.            mov ecx, [edx+APPOBJ.bk]    ;and clear events flag
  447.            mov [ebx+APPOBJ.bk], ecx    ;if no active events
  448.            mov [ecx+APPOBJ.fd], ebx
  449.  
  450.            and [edx+EVENT.state], not (EVENT_SIGNALED+EVENT_WATCHED)
  451.  
  452.            dec [eax+APPDATA.ev_count-APP_EV_OFFSET]
  453.            jnz @F
  454.            and [eax+APPDATA.event_mask-APP_EV_OFFSET], not EVENT_EXTENDED
  455. @@:
  456.            add eax, (APP_OBJ_OFFSET-APP_EV_OFFSET)
  457.  
  458.            mov ecx, [eax+APPOBJ.fd]  ;insert event into
  459.            mov [edx+APPOBJ.fd], ecx  ;objects list
  460.            mov [edx+APPOBJ.bk], eax
  461.            mov [eax+APPOBJ.fd], edx
  462.            mov [ecx+APPOBJ.bk], edx
  463.            popfd
  464. .fail:
  465. .done:
  466.            add esp, 4
  467.            ret
  468. restore .event
  469.  
  470. sys_getevent:
  471.  
  472.      call   get_event_for_app
  473.      mov    [esp+36],eax
  474.      ret
  475.  
  476.  
  477. align 4
  478. sys_wait_event_timeout:
  479.  
  480.      mov   ebx,[timer_ticks]
  481.      add   ebx,eax
  482.      cmp   ebx,[timer_ticks]
  483.      jna   .swfet2
  484. .swfet1:
  485.      call  get_event_for_app
  486.      test  eax,eax
  487.      jne   .eventoccur_time
  488.      call  change_task
  489.      cmp   ebx,[timer_ticks]
  490.      jg    .swfet1
  491. .swfet2:
  492.      xor   eax,eax
  493. .eventoccur_time:
  494.      mov   [esp+36],eax
  495.      ret
  496.  
  497.  
  498. align 4
  499.  
  500. sys_waitforevent:
  501.  
  502.      call  get_event_for_app
  503.      test  eax,eax
  504.      jne   eventoccur
  505.    newwait:
  506.  
  507.      mov   eax, [TASK_BASE]
  508.      mov   [eax+TASKDATA.state], byte 5
  509.      call  change_task
  510.  
  511.      mov eax, [event_sched]
  512.  
  513.    eventoccur:
  514.      mov   [esp+36],eax
  515.      ret
  516.  
  517. get_event_for_app:
  518.  
  519.      pushad
  520.  
  521.      mov   edi,[TASK_BASE]              ; WINDOW REDRAW
  522.      test  [edi+TASKDATA.event_mask],dword 1
  523.      jz    no_eventoccur1
  524.      ;mov   edi,[TASK_BASE]
  525.      cmp   [edi-twdw+WDATA.fl_redraw],byte 0
  526.      je    no_eventoccur1
  527.      popad
  528.      mov   eax,1
  529.      ret
  530.    no_eventoccur1:
  531.  
  532.      ;mov   edi,[TASK_BASE]              ; KEY IN BUFFER
  533.      test  [edi+TASKDATA.event_mask],dword 2
  534.      jz    no_eventoccur2
  535.      mov   ecx, [CURRENT_TASK]
  536.      movzx edx,word [WIN_STACK+ecx*2]
  537.      mov   eax, [TASK_COUNT]
  538.      cmp   eax,edx
  539.      jne   no_eventoccur2x
  540.      cmp   [KEY_COUNT],byte 0
  541.      je    no_eventoccur2x
  542.    eventoccur2:
  543.      popad
  544.      mov   eax,2
  545.      ret
  546.    no_eventoccur2x:
  547.         mov     eax, hotkey_buffer
  548. @@:
  549.         cmp     [eax], ecx
  550.         jz      eventoccur2
  551.         add     eax, 8
  552.         cmp     eax, hotkey_buffer+120*8
  553.         jb      @b
  554.    no_eventoccur2:
  555.  
  556.      ;mov   edi,[TASK_BASE]              ; BUTTON IN BUFFER
  557.      test  [edi+TASKDATA.event_mask],dword 4
  558.      jz    no_eventoccur3
  559.      cmp   [BTN_COUNT],byte 0
  560.      je    no_eventoccur3
  561.      mov   ecx, [CURRENT_TASK]
  562.      movzx edx, word [WIN_STACK+ecx*2]
  563.      mov   eax, [TASK_COUNT]
  564.      cmp   eax,edx
  565.      jnz   no_eventoccur3
  566.      popad
  567.      mov   eax,[BTN_BUFF]
  568.      cmp   eax,65535
  569.      je    no_event_1
  570.      mov   eax,3
  571.      ret
  572.  
  573.     no_event_1:
  574.      mov   [window_minimize],1
  575.      mov   [BTN_COUNT],byte 0
  576.      xor   eax, eax
  577.      ret
  578.  
  579.    no_eventoccur3:
  580.  
  581.  
  582.      ;mov   edi,[TASK_BASE]              ; mouse event
  583.      test  [edi+TASKDATA.event_mask],dword 00100000b
  584.      jz    no_mouse_event
  585.      mov   eax,[CURRENT_TASK]
  586.      shl   eax,8
  587.      test  [eax+SLOT_BASE+APPDATA.event_mask],dword 00100000b
  588.      jz    no_mouse_event
  589.      and   [eax+SLOT_BASE+APPDATA.event_mask],dword 0xffffffff-00100000b
  590.      popad
  591.      mov   eax,6
  592.      ret
  593.    no_mouse_event:
  594.  
  595.  
  596.      ;mov   edi,[TASK_BASE]              ; DESKTOP BACKGROUND REDRAW
  597.      test  [edi+TASKDATA.event_mask],dword 16
  598.      jz    no_eventoccur5
  599.      cmp   [REDRAW_BACKGROUND],byte 2
  600.      jnz   no_eventoccur5
  601.      popad
  602.      mov   eax,5
  603.      ret
  604.    no_eventoccur5:
  605.  
  606.      ;mov   edi,[TASK_BASE]              ; IPC
  607.      test  [edi+TASKDATA.event_mask],dword 01000000b
  608.      jz    no_ipc
  609.      mov   eax,[CURRENT_TASK]
  610.      shl   eax,8
  611.      test  [eax+SLOT_BASE+APPDATA.event_mask],dword 01000000b
  612.      jz    no_ipc
  613.      and   [eax+SLOT_BASE+APPDATA.event_mask],dword 0xffffffff-01000000b
  614.      popad
  615.      mov   eax,7
  616.      ret
  617.    no_ipc:
  618.  
  619.  
  620.      ;mov   edi,[TASK_BASE]              ; STACK
  621.      test  [edi+TASKDATA.event_mask],dword 10000000b
  622.      jz    no_stack_event
  623.      mov   eax,[CURRENT_TASK]
  624.      shl   eax,8
  625.      test  [eax+SLOT_BASE+APPDATA.event_mask],dword 10000000b
  626.      jz    no_stack_event
  627.      and   [eax+SLOT_BASE+APPDATA.event_mask],dword 0xffffffff-10000000b
  628.      popad
  629.      mov   eax,8
  630.      ret
  631.    no_stack_event:
  632.  
  633.      test  byte [edi+TASKDATA.event_mask+1], 1          ; DEBUG
  634.      jz    .test_IRQ
  635.      mov   eax, [CURRENT_TASK]
  636.      shl   eax, 8
  637.      test  byte [eax+SLOT_BASE+APPDATA.event_mask+1], byte 1
  638.      jz    .test_IRQ
  639.      and   byte [eax+SLOT_BASE+APPDATA.event_mask+1], not 1
  640.      popad
  641.      mov   eax, 9
  642.      ret
  643.  
  644. ;.test_ext:
  645. ;     mov   eax, [CURRENT_TASK]
  646. ;     shl   eax, 8
  647. ;     test  dword [eax+SLOT_BASE+APPDATA.event_mask], EVENT_EXTENDED
  648. ;     jz .test_IRQ
  649. ;     popad
  650. ;     mov eax, 10
  651. ;     ret
  652.  
  653. .test_IRQ:
  654.      cmp   dword [edi+TASKDATA.event_mask], 0xFFFF
  655.      jbe   no_events
  656.  
  657.      mov   esi,IRQ_SAVE              ; IRQ'S AND DATA
  658.      mov   ebx,0x00010000
  659.      xor   ecx, ecx
  660.    irq_event_test:
  661.      mov   edi,[TASK_BASE]
  662.      test  [edi+TASKDATA.event_mask],ebx
  663.      jz    no_irq_event
  664.      mov   edi,ecx
  665.      shl   edi,2
  666.      add   edi,irq_owner
  667.      mov   edx,[edi]
  668.      mov   eax,[TASK_BASE]
  669.      mov   eax,[eax+TASKDATA.pid]
  670.      cmp   edx,eax
  671.      jne   no_irq_event
  672.      cmp   [esi],dword 0
  673.      jz    no_irq_event
  674.      mov   eax,ecx
  675.      add   eax,16
  676.      mov   [esp+28],eax
  677.      popad
  678.      ret
  679.     no_irq_event:
  680.      add   esi,0x1000
  681.      shl   ebx,1
  682.      inc   ecx
  683.      cmp   ecx,16
  684.      jb    irq_event_test
  685.  
  686.    no_events:
  687.      popad
  688.      xor   eax, eax
  689.      ret
  690.  
  691.  
  692.  
  693.