home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / sound / midi / mbm.asm < prev    next >
Assembly Source File  |  1988-03-20  |  24KB  |  598 lines

  1.         TITLE   MPU/MIDI primitives for Modular Sequencer
  2.         NAME    MBM
  3.         .SALL
  4. ;==============================================================
  5. ; MusicBox Modular Sequencer, Version 2
  6. ; midi and clock interface
  7. ;--------------------------------------------------------------
  8. ; author: John Dunn
  9. ; date:   03/07/86
  10. ; update: 03/20/88
  11. ;--------------------------------------------------------------
  12. ; COPYRIGHT (C) 1986 John Dunn, All Rights Reserved 
  13. ; Entered into the Public Domain, March 20, 1988
  14. ;
  15. ; Use and copying of this software and preparation of derivative works
  16. ; based upon this software are permitted.  Any distribution of this
  17. ; software or derivative works must comply with all applicable United
  18. ; States export control laws.
  19. ; This software is made available AS IS, and the author makes no warranty 
  20. ; about the software, its performance, or its conformity to any specification.
  21. ; Any person obtaining a copy of this software is requested to send their
  22. ; name and address address to:
  23. ;
  24. ;       John Dunn, Senior Research Fellow
  25. ;       Time Arts Inc.
  26. ;       3436 Mendocino Ave.
  27. ;       Santa Rosa, CA 95401
  28. ;
  29. ;==============================================================
  30.         include    order.asm
  31. ;--------------------------------------------------------------
  32.         include equates.asm
  33. ;==============================================================
  34. _DATA   SEGMENT
  35.         ASSUME DS:DGROUP, CS:_TEXT
  36. ;--------------------------------------------------------------
  37.         public  midip
  38. ;--------------------------------------------------------------
  39.         extrn   midiok:byte
  40. ;--------------------------------------------------------------
  41. moboix0 dw      0               ; MIDI Out Buffer Index
  42. mobiix0 dw      0               ; MIDI In Buffer Index
  43. ;--------------------------------------------------------------
  44. moboix1 dw      0               ; MIDI Out Buffer Index
  45. mobiix1 dw      0               ; MIDI In Buffer Index
  46. ;--------------------------------------------------------------
  47. midip   db      0               ; midi port number 0/1
  48. mpuis   db      0               ; nz if mpu intes happening
  49. savint0 db      0               ; saved int byte from 8259A
  50. ;--------------------------------------------------------------
  51. _DATA   ENDS
  52. ;==============================================================
  53. _TEXT   SEGMENT
  54.     ASSUME  CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: NOTHING
  55. ;==============================================================
  56.         extrn   _dummy:far
  57.         extrn   loops:word
  58. ;==============================================================
  59. ; basic midi port routines
  60. ;--------------------------------------------------------------
  61. ; words declared in the CS for faster interrupt service  
  62.         public  midixs,mstop,mstart,mcont,midata,miflag,midatix,misend
  63.         public  _mpuinf,_mpuinm
  64. ;--------------------------------------------------------------
  65. midixs  db      0               ; midi extrnal sync tick
  66. mstop   db      0               ; midi stop tick
  67. mstart  db      0               ; midi start tick
  68. mcont   db      0               ; midi continue tick
  69. midata  db      0               ; midi input data byte
  70. miflag  db      0               ; midi input data flag
  71. misysx  db      0               ; midi sys exclusive flag
  72. midatix db      0               ; midi data index
  73. misend  db      0               ; midi send data flag
  74. _mpuinf db      0               ; mpu input from 1=1, 2=2, 0=none
  75. _mpuinm db      3               ; mpu input mask        
  76. nottrue db      'install patch area',0,1,3,7,0
  77. mobuf1  db      8192+105 dup(?) ; MIDI Out Buffer
  78. mobuf0  db      8192+128 dup(?) ; MIDI Out Buffer
  79. ;--------------------------------------------------------------
  80. ; initialize mpu, int vectors, etc.
  81. ; must be called once only on startup
  82. ; sets direct MIDI mode, with interrupt on input
  83. ; sets interrupt vector 0AH at 0000:0028, for
  84. ; hardware interrupt 2.
  85. ;
  86.         public  startm  
  87. startm  proc    near
  88.         test    mpuis,1         ; already done it?
  89.         jnz     initmx          ; yes, split
  90.         push    es              ; save current es
  91.         mov     ah,35h          ; get current int 2
  92.         mov     al,0AH
  93.         int     21H
  94.         mov     word ptr cs:orgint+3,es        ; save it
  95.         mov     word ptr cs:orgint+1,bx
  96.         pop     es              ; restore es
  97.  
  98.         push    ds              ; save current ds
  99.         mov     ah,25H          ; set int vect
  100.         mov     al,0AH          ; int 2 for MPU
  101.         mov     dx,offset mpuint
  102.         mov     cx,seg mpuint
  103.         mov     ds,cx
  104.         int     21H             ; set new int vect
  105.         pop     ds              ; restore ds
  106.  
  107.         cli
  108.         call    mpurst          ; reset mpu
  109.         in      al,21H          ; enable irq2
  110.         mov     savint0,al      ; save it
  111.         and     al,0FBH
  112.         out     21H,al
  113.         mov     mpuis,1         ; flag = active
  114.         sti
  115. initmx: ret
  116. startm  endp                     ; end of init mpu
  117. ;--------------------------------------------------------------
  118. ; shutdown mpu, restore int vectors, etc.
  119. ; must be called once only on exit
  120. ;
  121.         public  stopm  
  122. stopm   proc    near
  123.         test    mpuis,1         ; already done it?
  124.         jz      exitmx          ; yes, split
  125.         cli
  126.         mov     al,0FFH         ; issue mpu reset
  127.         mov     dx,mpucmd
  128.         out     dx,al
  129.         add     dx,2            ; do 2nd port
  130.         out     dx,al
  131.         mov     al,savint0      ; get original irq masks
  132.         out     21H,al          ; restore them
  133.         mov     mpuis,0         ; flag = inactive
  134.         ;
  135.         push    ds
  136.         mov     ah,25h          ; restore previous irq2
  137.         mov     al,0AH
  138.         mov     dx,word ptr cs:orgint+1
  139.         mov     cx,word ptr cs:orgint+3
  140.         mov     ds,cx
  141.         int     21h
  142.         pop     ds
  143.         ;
  144. exitmx: ret
  145. stopm   endp
  146.  
  147. ;--------------------------------------------------------------
  148. ; this routine is only called by int 2
  149. ; if it was not generated by the mpu, it vectors
  150. ; to the original int address, otherwise it saves
  151. ; registers, then calls the c routine _mpuint,
  152. ; after which it restores registers, clears nmi
  153. ; and returns from int. 
  154. ;
  155. mpuint  proc    far
  156.         cli                     ; disable interupts
  157.         push    ax              ; save ax
  158.         push    dx
  159.  
  160.         mov     ah,1            ; set mpu in flag to mpu#1
  161.         mov     dx,mpstat       ; read mpu status
  162.         in      al,dx
  163.         and     al,mpdsr        ; generated by mpu?
  164.         jz      mpui1           ; yes, branch
  165.         add     dx,2            ; no, check other port
  166.         mov     ah,2            ; set mpu in flag to mpu#1
  167.         in      al,dx
  168.         and     al,mpdsr        ; generated by mpu?
  169.         jz      mpui1           ; yes, branch
  170.  
  171.         mov     ah,1            ; set mpu in flag to mpu#1
  172.         mov     dx,mpstat       ; read mpu status
  173.         in      al,dx
  174.         and     al,mpdsr        ; generated by mpu?
  175.         jz      mpui1           ; yes, branch
  176.         add     dx,2            ; no, check other port
  177.         mov     ah,2            ; set mpu in flag to mpu#1
  178.         in      al,dx
  179.         and     al,mpdsr        ; generated by mpu?
  180.         jz      mpui1           ; yes, branch
  181.  
  182.         mov     ah,1            ; set mpu in flag to mpu#1
  183.         mov     dx,mpstat       ; read mpu status
  184.         in      al,dx
  185.         and     al,mpdsr        ; generated by mpu?
  186.         jz      mpui1           ; yes, branch
  187.         add     dx,2            ; no, check other port
  188.         mov     ah,2            ; set mpu in flag to mpu#1
  189.         in      al,dx
  190.         and     al,mpdsr        ; generated by mpu?
  191.         jz      mpui1           ; yes, branch
  192.  
  193.         mov     al,20H
  194.         out     20H,al
  195.  
  196.         pop     dx              ; restore cpu
  197.         pop     ax
  198.         sti                     ; enable interupts
  199.         iret
  200. orgint: jmp     far ptr _dummy  ; dummy vector, filled by _initm
  201.  
  202. mpui1:
  203.         push    bx              ; save cpu state
  204.         push    cx
  205.         push    di
  206.         push    si
  207.         push    bp
  208.         push    ds
  209.         push    es
  210.  
  211.         mov     cx,cs           ; set up seg regs
  212.         mov     ds,cx
  213.  
  214.         dec     dx              ; get mpu int data
  215.         in      al,dx           ; /
  216.  
  217.         mov     _mpuinf,ah      ; save flag status
  218.         test    ah,_mpuinm      ; check against mask
  219.         jz      mpuiz           ; exit if masked out
  220.  
  221.         cmp     al,0feh         ; Active Sensing
  222.         jz      mpuiz           ; yes, exit
  223.         cmp     al,0f8H         ; Midi Sync?
  224.         jnz     mpui2           ; no, branch
  225.         inc     midixs          ; yes, inc the flag
  226.         jmp     short mpuiz     ; .. and on to work
  227. mpui2:  cmp     al,0fah         ; Midi Start?
  228.         jnz     mpui3           ; no, branch
  229.         inc     mstart          ; yes, inc the flag
  230.         jmp     short mpuiz     ; .. and on to work
  231. mpui3:  cmp     al,0fbh         ; Midi Continue
  232.         jnz     mpui4           ; no, branch
  233.         inc     mcont           ; yes, inc the flag
  234.         jmp     short mpuiz     ; .. and on to work
  235. mpui4:  cmp     al,0fch         ; Midi stop?
  236.         jnz     mpui5           ; no, branch
  237.         inc     mstop           ; yes, inc the flag
  238.         jmp     short mpuiz     ; .. and on to work
  239. mpui5:  mov     midata,al       ; put the data byte away 
  240.         mov     miflag,1        ; set the data-in flag
  241.         cmp     al,0f0h         ; system exclusive
  242.         jnz     mpui6           ; no, branch
  243.         mov     misysx,1        ; yes, set the flag
  244.         jmp     short mpuiz     ; exit
  245. mpui6:  cmp     al,0f7h         ; EOX?
  246.         jnz     mpui7           ; no, branch
  247.         mov     misysx,0        ; yes, clear the flag
  248.         jmp     short mpuiz     ; exit
  249. mpui7:  test    misysx,-1       ; sys exclusive happening?
  250.         jnz     mpuiz           ; yes, branch
  251.         test    misend,-1       ; want to send data?
  252.         jz      mpui8           ; no, branch
  253.         mov     dx,seg bufsp    ; yes get the buffer
  254.         mov     es,dx           ; /
  255.         mov     bl,midatix      ; get the index
  256.         mov     bh,0FH          ; put in bank "F"
  257.         mov     es:[bx],al      ; put the byte away
  258. mpui8:  inc     midatix         ; inc the index
  259. mpuiz:  ;
  260.         pop     es              ; restore seg regs
  261.         pop     ds
  262.         pop     bp              ; restore cpu state
  263.         pop     si
  264.         pop     di
  265.         pop     cx
  266.         pop     bx
  267.         pop     dx
  268.         mov     al,20H
  269.         out     20H,al
  270.         pop     ax
  271.         sti                     ; enable interrupts
  272.         iret                    ; return from interrupt
  273. mpuint  endp
  274. ;--------------------------------------------------------------
  275. ; mpurst
  276. ; clear out the mpu, and set for direct MIDI i/o
  277. ;
  278.         public  mpurst
  279. mpurst  proc    near
  280.         cli                     ; disable intes
  281.         mov     dx,mpdata       ; read mpu data port
  282.         in      al,dx           ; get the data
  283.         jmp     short $+2       ; wait
  284.         in      al,dx           ; get the data
  285.         jmp     short $+2       ; wait
  286.         in      al,dx           ; get the data
  287.         jmp     short $+2       ; wait
  288.         in      al,dx           ; get the data
  289.         jmp     short $+2       ; wait
  290.         mov     dx,mpstat       ; mpu status port
  291. mpurs1: in      al,dx           ; get the status
  292.         and     al,mpdrr        ; test for Data Recieve Ready
  293.         jnz     mpurs1          ; loop til ready
  294.         mov     ax,03FH         ; MPU UART command
  295.         out     dx,al           ; send to mpu
  296.         mov     cx,800H         ; delay
  297. mpurs2: loop    mpurs2          ; /
  298.         mov     dx,mpdata       ; read mpu data port
  299.         in      al,dx           ; get the data
  300.         jmp     short $+2       ; wait
  301.         in      al,dx           ; get the data
  302.         ;
  303.         ; do 2nd MPU
  304.         ;
  305.         test    midiok,2        ; 2nd MPU online?
  306.         jz      mpursx          ; no, just exit
  307.         ;
  308.         mov     dx,mpdata+2     ; read mpu data port
  309.         in      al,dx           ; get the data
  310.         jmp     short $+2       ; wait
  311.         in      al,dx           ; get the data
  312.         jmp     short $+2       ; wait
  313.         in      al,dx           ; get the data
  314.         jmp     short $+2       ; wait
  315.         in      al,dx           ; get the data
  316.         jmp     short $+2       ; wait
  317.         mov     dx,mpstat+2     ; mpu status port
  318. mpurs3: in      al,dx           ; get the status
  319.         and     al,mpdrr        ; test for Data Recieve Ready
  320.         jnz     mpurs3          ; loop til ready
  321.         mov     ax,03FH         ; MPU UART command
  322.         out     dx,al           ; send to mpu
  323.         mov     cx,800H         ; delay
  324. mpurs4: loop    mpurs4          ; /
  325.         mov     dx,mpdata+2     ; read mpu data port
  326.         in      al,dx           ; get the data
  327.         jmp     short $+2       ; wait
  328.         in      al,dx           ; get the data
  329.         ;
  330. mpursx: sti                     ; enable interrupts
  331.         ret                     ; exit
  332. mpurst  endp
  333. ;--------------------------------------------------------------
  334. ; send a byte in AL to MIDI Out Buffer
  335. ;
  336.         public  tomidi
  337. tomidi  proc    near
  338.         test    midip,10H       ; test midi port
  339.         jnz     tomidi1         ; branch if port 1
  340.         ;
  341.         mov     bx,mobiix0      ; get midi out buffer out index
  342.         mov     cs:mobuf0[bx],al; put next byte
  343.         inc     bx              ; bump index
  344.         and     bx,8191         ; wrap-around
  345.         mov     mobiix0,bx      ; store new mob out index
  346.         ret
  347.         ;
  348. tomidi1:mov     bx,mobiix1      ; get midi out buffer out index
  349.         mov     cs:mobuf1[bx],al; put next byte
  350.         inc     bx              ; bump index
  351.         and     bx,8191         ; wrap-around
  352.         mov     mobiix1,bx      ; store new mob out index
  353.         ret
  354. tomidi  endp
  355. ;--------------------------------------------------------------
  356. ; send a byte in AL to all MIDI Out Buffers
  357. ;
  358.         public  allmidi
  359. allmidi proc    near
  360.         ;
  361.         mov     bx,mobiix0      ; get midi out buffer out index
  362.         mov     cs:mobuf0[bx],al; put next byte
  363.         inc     bx              ; bump index
  364.         and     bx,8191         ; wrap-around
  365.         mov     mobiix0,bx      ; store new mob out index
  366.         ;
  367.         mov     bx,mobiix1      ; get midi out buffer out index
  368.         mov     cs:mobuf1[bx],al; put next byte
  369.         inc     bx              ; bump index
  370.         and     bx,8191         ; wrap-around
  371.         mov     mobiix1,bx      ; store new mob out index
  372.         ret
  373. allmidi endp
  374. ;--------------------------------------------------------------
  375. ; get next byte from pass buffer and send to midi
  376. ; does nothing if midi output port is busy  
  377. ; or if the buffer is empty
  378.         public  sendm
  379. sendm   proc    near 
  380.         mov     bx,moboix0      ; get midi out buffer out index
  381.         cmp     bx,mobiix0      ; same as midi out buffer in index?
  382.         jz      sendm1          ; yes, exit
  383.         ;
  384.         test    midiok,1        ; ok to do it?
  385.         jz      sendm2          ; no, then fake it 
  386.         ;
  387.         mov     dx,mpstat       ; mpu status port
  388.         in      al,dx           ; get the status
  389.         and     al,mpdrr        ; test for Data Recieve Ready
  390.         jnz     sendm1          ; exit if midi out port is busy
  391.         ;
  392.         mov     al,cs:mobuf0[bx]; get next byte
  393.         mov     dx,mpdata       ; mpu data port
  394.         out     dx,al           ; send to mpu
  395. sendm2: inc     bx              ; bump index
  396.         and     bx,8191         ; wrap-around
  397.         mov     moboix0,bx      ; store new mob out index
  398.         ;
  399.         ; do 2nd buffer
  400.         ;
  401. sendm1: mov     bx,moboix1      ; get midi out buffer out index
  402.         cmp     bx,mobiix1      ; same as midi out buffer in index?
  403.         jz      sendm3          ; yes, exit
  404.         ;
  405.         test    midiok,2        ; ok to do it?
  406.         jz      sendm4          ; no, then fake it 
  407.         ;
  408.         mov     dx,mpstat+2     ; mpu status port
  409.         in      al,dx           ; get the status
  410.         and     al,mpdrr        ; test for Data Recieve Ready
  411.         jnz     sendm3          ; exit if midi out port is busy
  412.         ;
  413.         mov     al,cs:mobuf1[bx]; get next byte
  414.         mov     dx,mpdata+2     ; mpu data port
  415.         out     dx,al           ; send to mpu
  416. sendm4: inc     bx              ; bump index
  417.         and     bx,8191         ; wrap-around
  418.         mov     moboix1,bx      ; store new mob out index
  419. sendm3: ret
  420. sendm   endp        
  421. ;--------------------------------------------------------------
  422. ; Clear all MIDI channels
  423. ;
  424.         public  allclr
  425. allclr  proc    near
  426. allclr1:mov     midip,0         ; set midi port 0
  427.         call    sendm           ; now really do it
  428. allclr2:mov     midip,10H       ; set midi port 1
  429.         call    sendm           ; now really do it
  430.         mov     bx,moboix0      ; get midi out buffer out index
  431.         cmp     bx,mobiix0      ; same as midi in buffer in index?
  432.         jnz     allclr1         ; no, keep sending
  433.         mov     bx,moboix1      ; get midi out buffer out index
  434.         cmp     bx,mobiix1      ; same as midi in buffer in index?
  435.         jnz     allclr2         ; no, keep sending
  436.         ret
  437. allclr  endp
  438.  
  439. ;--------------------------------------------------------------
  440. ; test for midi output buffers empty
  441. ; returns al bits 0,1 set if buffers are not empty
  442. ;
  443.         public  tstmob
  444. tstmob: xor     al,al           ; clear flag
  445.         mov     bx,moboix0      ; get midi out buffer out index
  446.         cmp     bx,mobiix0      ; same as midi in buffer in index?
  447.         jz      tstmob1         ; yes, branch
  448.         inc     al              ; no, set the bit        
  449. tstmob1:mov     bx,moboix1      ; get midi out buffer out index
  450.         cmp     bx,mobiix1      ; same as midi in buffer in index?
  451.         jz      tstmob2         ; yes, branch
  452.         or      al,2            ; no, set the bit
  453. tstmob2:ret                     ; exit w result in AL
  454. ;--------------------------------------------------------------
  455. ; Turn off all MIDI modules
  456. ;
  457.         public  alloff
  458. alloff  proc    near
  459.         ;
  460.         mov     dh,0            ; for channels
  461.         mov     cl,dh           ; dummy data byte
  462. workh1c:mov     ah,0B0H         ; MIDI Channel message
  463.         or      ah,dh           ; add channel info
  464.         ;
  465.         mov     al,ah           ; midi channel msg
  466.         call    allmidi         ; /
  467.         mov     al,7CH          ; omni off 
  468.         call    allmidi         ; send
  469.         mov     al,cl           ; send dummy
  470.         call    allmidi         ; /
  471.         ;
  472.         mov     al,ah           ; midi channel msg
  473.         call    allmidi         ; /
  474.         mov     al,7FH          ; poly, ano
  475.         call    allmidi         ; /
  476.         mov     al,cl           ; send dummy
  477.         call    allmidi         ; /
  478.         ;
  479.         inc     dh              ; next channel
  480.         test    dh,16           ; 16 channels
  481.         jz      workh1c         ; /
  482.         ;
  483.         call    allclr          ; clear the channels
  484.         ret
  485. alloff  endp
  486. ;--------------------------------------------------------------
  487. ; TIMER ROUTINES
  488. ;--------------------------------------------------------------
  489. ; words declared in the CS for faster interrupt service  
  490.         public  ticks,ticks1,timer,seconds,secondf
  491. ;--------------------------------------------------------------
  492. timeis  db      0               ; nz if timer inte is happening
  493. times0  dw      0               ; storage for dos timer vector
  494. times1  dw      0               ; saa
  495. ticks   dw      0               ; lsw of tick count
  496. ticks1  dw      0               ; msw of tick count
  497. timer   dw      0               ; system timer count
  498. second0 dw      582             ; real time clk ticker
  499. seconds dw      0               ; running seconds count
  500. secondf db      0               ; nz if seconds was incremented
  501. ;--------------------------------------------------------------
  502. ; startt ( sets timer int to vector to dotime )
  503.         public  startt
  504. startt  proc    near
  505.         test    cs:timeis,1     ; already done it?
  506.         jnz     starttx         ; yes, split
  507.         push    es
  508.         mov     ah,35H          ; get current int 8
  509.         mov     al,8            ;   /
  510.         int     21H             ; /
  511.         mov     cs:times1,es    ; save it
  512.         mov     cs:times0,bx
  513.         pop     es
  514.         ;
  515.         push    ds              ; save data seg
  516.         mov     ah,25H          ; set int vect
  517.         mov     al,8            ; int 8 for MS timer
  518.         mov     dx,offset dotime;
  519.         mov     cx,seg dotime   ;
  520.         mov     ds,cx           ;
  521.         int     21H             ; set new int vect
  522.         pop     ds              ; restore data seg
  523.         mov     cs:timeis,1     ; flag = active
  524.         ;
  525.         cli
  526. ;        mov     ax,00fffh       ; set new timing
  527.         mov     ax,007ffh       ; set new timing
  528.         out     40H,al
  529.         jmp     short $+2
  530.         mov     al,ah
  531.         out     40H,al
  532.         sti
  533. starttx:ret
  534. startt  endp
  535. ;--------------------------------------------------------------
  536. ; stopt  ( restores oringinal dos int )
  537. ;
  538.         public  stopt
  539. stopt   proc    near
  540.         test    cs:timeis,1     ; already done it?
  541.         jz      stoptx          ; yes, split
  542.         push    ds              ; save current data seg
  543.         mov     ah,25h          ; restore previous irq
  544.         mov     al,8            ;         /
  545.         mov     dx,cs:times0    ;       /
  546.         mov     cx,cs:times1    ;     /
  547.         mov     ds,cx           ;   /
  548.         int     21h             ; /
  549.         pop     ds              ; restore data seg
  550.         mov     cs:timeis,0     ; flag = inactive
  551.         ;
  552.         cli                     ; restore original timing
  553.         mov     ax,0ffffh
  554.         out     40H,al
  555.         jmp     short $+2
  556.         mov     al,ah
  557.         out     40H,al
  558.         sti
  559. stoptx: ret
  560. stopt   endp
  561.  
  562. ;--------------------------------------------------------------
  563. ; DOTIME  interrupt routine called every clock tick
  564. ;
  565. dotime  proc    far
  566.         dec     cs:second0      ; count down second timer
  567.         jnz     dotim2          ; branch if not time
  568.         inc     cs:seconds      ; else bump seconds count
  569.         mov     cs:second0,582  ; 582.4 ticks/sec
  570.         mov     cs:secondf,1    ; set the flag
  571. dotim2:
  572.         test    cs:timer,-1     ; timer zero
  573.         jz      dotim1          ; yes, branch
  574.         dec     cs:timer        ; no, count down
  575. dotim1: inc     cs:ticks        ; inc ls word
  576.         jnz     dotim0          ; branch if not overflow
  577.         inc     cs:ticks1       ; else inc ms word
  578. ;dotim0: test    cs:ticks,15     ; bump system stuff every 16th clock
  579. dotim0: test    cs:ticks,31     ; bump system stuff every 32th clock
  580.         jz      dotimx          ; branch if time to doit
  581.         push    ax
  582.         mov     al,20h
  583.         out     20h,al
  584.         pop     ax
  585.         iret                    ; else just return from interrupt
  586. dotimx: push    cs:times1       ; on to the original inte
  587.         push    cs:times0       ;   /
  588.         ret                     ; /
  589. dotime  endp
  590. ;--------------------------------------------------------------
  591. _TEXT   ENDS
  592.         END
  593.  
  594.