home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Homebrewer's Handbook / vr.iso / vr386 / joytimer.asm < prev    next >
Assembly Source File  |  1996-03-19  |  12KB  |  600 lines

  1.     TITLE    JOYTIMER - CPU INDEPENDANT JOYSTICK READ AND TIMER SPPT
  2.  
  3.     COMMENT $
  4.  
  5.     This special cpu-speed independent joystick reader was
  6.     written by Dave Stampe.  It has about twice the resolution
  7.     of normal joystick readers, about 1200 compared to 600.
  8.  
  9.     It works by counting the number of 1.19 MHz increments of
  10.     the PC timer.  This version re-reads the joystick if the
  11.     timer rolls over: this is becasue the timer handling ISR
  12.     could cause the end-of-count of the joystick to be missed,
  13.     resulting in glitches.
  14.  
  15.     The timer routines that follow give REND386
  16.     the ability to compile with -3 (386 instructions)
  17.     bypassing the bugs in the _interrupt headers
  18.     in BC 3.1.  If your program uses any other routines
  19.     and then crashes, then save all registers with an inline
  20.     pushad and restore with popad to fix the problem.
  21.  
  22.     Also has a keyboard interrupt intercept which can
  23.     monitor key status directly
  24.  
  25. /*
  26.  This code is part of the VR-386 project, created by Dave Stampe.
  27.  VR-386 is a desendent of REND386, created by Dave Stampe and
  28.  Bernie Roehl.  Almost all the code has been rewritten by Dave
  29.  Stampre for VR-386.
  30.  
  31.  Copyright (c) 1994 by Dave Stampe:
  32.  May be freely used to write software for release into the public domain
  33.  or for educational use; all commercial endeavours MUST contact Dave Stampe
  34.  (dstampe@psych.toronto.edu) for permission to incorporate any part of
  35.  this software or source code into their products!  Usually there is no
  36.  charge for under 50-100 items for low-cost or shareware products, and terms
  37.  are reasonable.  Any royalties are used for development, so equipment is
  38.  often acceptable payment.
  39.  
  40.  ATTRIBUTION:  If you use any part of this source code or the libraries
  41.  in your projects, you must give attribution to VR-386 and Dave Stampe,
  42.  and any other authors in your documentation, source code, and at startup
  43.  of your program.  Let's keep the freeware ball rolling!
  44.  
  45.  DEVELOPMENT: VR-386 is a effort to develop the process started by
  46.  REND386, improving programmer access by rewriting the code and supplying
  47.  a standard API.  If you write improvements, add new functions rather
  48.  than rewriting current functions.  This will make it possible to
  49.  include you improved code in the next API release.  YOU can help advance
  50.  VR-386.  Comments on the API are welcome.
  51.  
  52.  CONTACT: dstampe@psych.toronto.edu
  53. */
  54.  
  55. /* Joystick reader (c) 1993 by Dave Stampe
  56. /* Contact: dstampe@sunee.waterloo.edu */
  57.  
  58.         $
  59.  
  60.     .MODEL large
  61.     .386
  62.  
  63.     extrn _vsync:PROC    ; waits for vert. sync
  64.  
  65.     .DATA
  66.  
  67.     PUBLIC _joystick_j1
  68.     PUBLIC _joystick_j2
  69.     PUBLIC _joystick_j3
  70.     PUBLIC _joystick_j4
  71.     PUBLIC _joystick_buttons
  72.  
  73. _joystick_j1        dw 0  ; /* raw joystick results */
  74. _joystick_j2        dw 0
  75. _joystick_j3        dw 0
  76. _joystick_j4        dw 0
  77. _joystick_buttons   dw 0
  78.  
  79.  
  80.     .CODE devices
  81.  
  82.  
  83. READ_TIMER     MACRO    ; result will be in ax
  84.     pushf
  85.     cli
  86.     mov    al,00h            ;/* read PC timer */
  87.     out    043h,al
  88.     nop
  89.     nop
  90.     in    al,040h
  91.     mov    ah,al
  92.     nop
  93.     nop
  94.     in    al,040h
  95.     xchg    al,ah
  96.     popf
  97.     ENDM
  98.  
  99. WRITE_TIMER     MACRO    ; write from BX
  100.     pushf
  101.     cli
  102.     mov    al,34h
  103.     out    43h,al    ; prepare for write
  104.     xor    al,al
  105.     nop
  106.     mov    al,bl
  107.     out    40h,al
  108.     nop
  109.     mov    al,bh
  110.     out    40h,al
  111.     popf
  112.     ENDM
  113.  
  114.  
  115. ;/********* READ JOYSTICK (RAW COUNT) ************/
  116.  
  117.  
  118. mask        equ    [bp+8]          ; arguments
  119.  
  120. vj1        equ    [bp-2]        ; locals
  121. vj2        equ    [bp-4]
  122. vj3        equ    [bp-6]
  123. vj4        equ    [bp-8]
  124. raw        equ    [bp-10]
  125. last_time    equ    [bp-12]
  126. abort        equ    [bp-14]
  127.  
  128.  
  129. ;int raw_joystick_read(int mask) ; fills variables, returns 0 if OK
  130.                  ; if failure, retry later on
  131.  
  132.     PUBLIC    _raw_joystick_read
  133.  
  134. _raw_joystick_read    proc    far
  135.  
  136.     .386
  137.     push    ebp
  138.     mov    ebp,esp
  139.     sub    esp,20
  140.     pushf
  141.     push    dx
  142.  
  143.     test    BYTE PTR mask,-1
  144.     je    quit_now
  145.  
  146.     xor    ax,ax
  147.     mov    vj1,ax
  148.     mov    vj2,ax
  149.     mov    vj3,ax
  150.     mov    vj4,ax
  151.     mov    cx,5000         ;/* safety timer limit */
  152.  
  153. waitforit:
  154.     mov    dx,0201h          ;/* wait for timers clear
  155.     in    al,dx
  156.     and    al,0Fh
  157.     and    al,mask
  158.     je    ready_to_begin
  159.     loop    waitforit
  160.     jmp    quit_now    ; no joystick: abort!
  161.  
  162. ready_to_begin:
  163.     cli
  164.     mov    dx,0201h          ;/* start game port timers */
  165.     mov    al,0ffh
  166.     out    dx,al
  167.  
  168.     READ_TIMER                ; read PC timer count
  169.     mov    last_time,ax
  170.  
  171.     in    al,dx            ;/* record game port value */
  172.     mov    raw,al
  173.     and    al,mask
  174.     mov    bl,al
  175.     je      timeout             ;/* catch very short joy time */
  176.     mov    cx,4000         ;/* safety timer limit */
  177.     sti
  178. wloop:
  179.     sti                      ;/* allow ints to occur here */
  180.     cli
  181.     in    al,dx
  182.     mov    raw,al           ;/* game port change? */
  183.     and    al,mask
  184.     xor    al,bl
  185.     and     al,mask
  186.     jne    timeout
  187.  
  188.     loop    wloop            ;/* safety timer overflow? */
  189.  
  190.     sti
  191.     jmp     quit_now
  192.  
  193.     mov    al,mask
  194.     not    al
  195.     mov    raw,al
  196.     mov    abort,ax         ; abort, no bits changed
  197.  
  198. timeout:
  199.     mov    bl,raw           ;/* record change */
  200.     mov    bh,al
  201.  
  202.     READ_TIMER                ; read PC timer count
  203.     sti
  204.  
  205.     test    word ptr long_interrupt,-1
  206.     jne     quit_now
  207.     sub    ax,last_time     ;/* compute delay */
  208.     neg    ax
  209.     jge    posj
  210.     add    ax,_counts_per_tick     ; fixup for timer rollover
  211. posj:
  212.     cmp    ax,1400
  213.     ja    quit_now    ; timer rollover unrecoverable! exit.
  214.  
  215.     test    bh,8        ;/* update proper joy values */
  216.     je    ns4
  217.     mov    vj4,ax
  218. ns4:
  219.     test    bh,4
  220.     je    ns3
  221.     mov    vj3,ax
  222. ns3:
  223.     test    bh,2
  224.     je    ns2
  225.     mov    vj2,ax
  226. ns2:
  227.     test    bh,1
  228.     je    ns1
  229.     mov    vj1,ax
  230. ns1:
  231.     mov    al,raw        ;/* check if all bits done */
  232.     not    al
  233.     and    al,mask
  234.     cmp    al,mask
  235.     jne    wloop
  236.  
  237. shorttime:
  238.     mov    ax,vj1          ; copy final values
  239.     mov     _joystick_j1,ax
  240.     mov    ax,vj2
  241.     mov     _joystick_j2,ax
  242.     mov    ax,vj3
  243.     mov     _joystick_j3,ax
  244.     mov    ax,vj4
  245.     mov     _joystick_j4,ax
  246.  
  247.     mov    ax,raw        ; extract button flags
  248.     not    ax
  249.     shr    ax,4
  250.     and    ax,0Fh
  251.     mov    _joystick_buttons,ax
  252.     mov    ax,0
  253.  
  254.     pop    dx
  255.     popf
  256.     mov    esp,ebp      ; 0: successful read
  257.     pop    ebp
  258.     ret
  259.  
  260. quit_now:
  261.     mov    word ptr long_interrupt,0
  262.     mov    ax,cx
  263.     inc    ax        ; will be 1 if too long, else timer ovf
  264.  
  265.     pop    dx
  266.     popf
  267.     mov    esp,ebp
  268.     pop    ebp
  269.     ret
  270.  
  271. _raw_joystick_read  endp
  272.  
  273.  
  274. ;/************ TIMER HANDLING DATA ************/
  275.  
  276.     .DATA
  277.  
  278. PUBLIC _timer_tick_count
  279. PUBLIC _timer_vsync_count
  280. PUBLIC _ticks_per_second
  281. PUBLIC _counts_per_tick
  282.  
  283. _timer_tick_count    dd 0          ; number of interrupts so far
  284. _timer_vsync_count    dw 20000        ; timer counts per video frame
  285. _ticks_per_second    dw 1000        ; counter time basis
  286. _counts_per_tick    dw 65535    ; counter time basis
  287.  
  288. PUBLIC _timer_interrupt_hook
  289. PUBLIC _frame_interrupt_hook
  290.  
  291. _timer_interrupt_hook    dd 0    ; timer tick interrupt
  292. _frame_interrupt_hook    dd 0    ; frame-end interrupt (arg=0)
  293.  
  294. PUBLIC _timer_frame_interval
  295. PUBLIC _frame_resync_interval
  296.  
  297. _timer_frame_interval   dw 0    ; number of timer ticks per frame
  298. _frame_resync_interval  dw 5    ; number of frames between resyncs
  299.  
  300. divisor            dw 0    ; used to compute DOS interrupt interval
  301. frame_count          dw 0    ; number of timer ticks to end of frame
  302. frame_sync          dw 0    ; number of frames till sync
  303.  
  304. long_interrupt         dw 0    ; set if processing took too long
  305.  
  306. ;/************* KEYBOARD MONITOR DATA *************/
  307.  
  308. ;;;PUBLIC _keyflags only for debug!
  309.  
  310. _keyflags   db 20 dup (0)    ; room for 128 keycodes
  311.  
  312.     .CODE devices
  313.  
  314.  
  315. ;/************* TIMER SUPPORT ***************/
  316.  
  317. ;unsigned find_vsync_count()  // finds timer clocks per frame
  318.  
  319.     PUBLIC    _find_vsync_count
  320. _find_vsync_count    proc    far
  321.  
  322.     .386
  323.     push    ebp
  324.     mov    ebp,esp
  325.  
  326.     cli
  327.     xor    bx,bx
  328.     WRITE_TIMER     ; set timer for no overflow
  329.  
  330.     sti
  331.  
  332.     call    far ptr _vsync    ; time of frame start
  333.     cli
  334.     READ_TIMER
  335.     push    ax
  336.     call    far ptr _vsync    ; 2xframe delay
  337.     call    far ptr _vsync
  338.     READ_TIMER                ; time of end
  339.     sti
  340.     pop    bx
  341.     sub    bx,ax
  342.     shr    bx,1
  343.     mov     ax,bx             ; compute count
  344.  
  345.     mov    esp,ebp
  346.     pop    ebp
  347.     ret
  348.  
  349. _find_vsync_count  endp
  350.  
  351.  
  352.  
  353. ;void write_timer(unsigned count) // sets timer period, restarts count
  354.  
  355.  
  356. count    equ    [bp+8]
  357.  
  358.     PUBLIC    _write_timer
  359.  
  360. _write_timer    proc    far
  361.  
  362.     .386
  363.     push    ebp
  364.     mov    ebp,esp
  365.  
  366.     mov    bx,count
  367.     WRITE_TIMER
  368.  
  369.     mov    esp,ebp
  370.     pop    ebp
  371.     ret
  372.  
  373. _write_timer  endp
  374.  
  375.  
  376.  
  377. ;unsigned read_timer();   // reads current timer count
  378.  
  379.     PUBLIC    _read_timer
  380.  
  381. _read_timer    proc    far
  382.  
  383.     .386
  384.     push    ebp
  385.     mov    ebp,esp
  386.  
  387.     READ_TIMER
  388.  
  389.     mov    esp,ebp
  390.     pop    ebp
  391.     ret
  392.  
  393. _read_timer  endp
  394.  
  395.  
  396. ;/*********** TIMER ISR *************/
  397.  
  398. ;void timer_isr()    ; does timer interrupt stuff
  399.  
  400.     PUBLIC    _timer_isr
  401.  
  402. _timer_isr    proc    far
  403.  
  404.     .386
  405.     pushf
  406.     pushad
  407.     push    ds
  408.     push    es
  409.     push    fs
  410.     push    gs
  411.  
  412.     cli
  413.     mov    al,20h
  414.     out    20h,al        ; nonspecific EOI to PIC
  415.  
  416.     mov    ax,DGROUP
  417.     mov    ds,ax
  418.  
  419.     inc    DWORD PTR _timer_tick_count
  420.  
  421.     sub    WORD PTR frame_count,1              ; end of frame?
  422.  
  423.     test     DWORD PTR _frame_interrupt_hook,-1  ; frame sync on?
  424.     je    no_frame
  425.     inc     word ptr long_interrupt
  426.     push    WORD PTR frame_count                ; frame interrupt hook
  427.     call    DWORD PTR _frame_interrupt_hook
  428.     add    esp,2
  429.  
  430.     cmp    WORD PTR frame_count,0              ; end of frame?
  431.     jg    no_frame
  432.  
  433.     sub    WORD PTR frame_sync,1
  434.     jg    no_frame
  435.     mov    ax,_frame_resync_interval    ; SYNC INTERVAL
  436.     mov    frame_sync,ax
  437.  
  438.     inc     word ptr long_interrupt
  439.     mov    bx,0                 ; resync timer
  440.     WRITE_TIMER
  441.     call    far ptr _vsync
  442.     mov    bx,_counts_per_tick
  443.     WRITE_TIMER
  444.  
  445. no_frame:
  446.     test     DWORD PTR _timer_interrupt_hook,-1
  447.     je    no_timer_call
  448.     inc     word ptr long_interrupt
  449.     push    WORD PTR frame_count               ; timer tick hook
  450.     call    DWORD PTR _timer_interrupt_hook
  451.     add    esp,2
  452. no_timer_call:
  453.                       ; reset this AFTER for proper args
  454.     cmp    WORD PTR frame_count,0
  455.     jg    notfreset
  456.     mov    ax,_timer_frame_interval
  457.     mov    frame_count,ax
  458. notfreset:
  459.     mov    ax,divisor
  460.     add    ax,_counts_per_tick   ; time to fake 18.2 Hz?
  461.     mov    divisor,ax
  462.     jnc    not_DOS_time
  463.  
  464.     int    78h        ; call old ISR
  465.  
  466. not_DOS_time:                         ; no, get out
  467.     pop    gs
  468.     pop    fs
  469.     pop    es
  470.     pop    ds
  471.     popad
  472.     popf
  473.     iret
  474.  
  475. _timer_isr  endp
  476.  
  477.  
  478. ;/********* RETURN CURRENT TIME IN MILLISECONDS *********/
  479.  
  480. ;long current_time()    ; returns time in msec
  481.  
  482.     PUBLIC    _current_time
  483.  
  484. _current_time    proc    far
  485.  
  486.     .386
  487.     push    ebp
  488.     mov    ebp,esp
  489.  
  490.     pushf
  491.     cli
  492.     READ_TIMER
  493.     movzx    ebx,ax
  494.     mov    eax,_timer_tick_count
  495.     movzx    edx,WORD PTR _counts_per_tick
  496.     popf
  497.  
  498.     imul    edx        ; total count compute
  499.     add    eax,ebx
  500.     adc    edx,0
  501.  
  502.     mov    ebx,1190    ; compute milliseconds
  503.     idiv    ebx
  504.     shld    edx,eax,16    ; return value in eax and dx:ax
  505.  
  506.     mov    esp,ebp
  507.     pop    ebp
  508.     ret
  509.  
  510. _current_time  endp
  511.  
  512.  
  513.  
  514. ;/************* KEYBOARD MONITOR *************/
  515.  
  516.  
  517. ; int is_key_down(unsigned keycode) // returns 1 if key down
  518.  
  519. keycode    equ    WORD PTR [bp+8]    ; arguments
  520.  
  521.     PUBLIC _is_key_down
  522.  
  523. _is_key_down    proc    far
  524.  
  525.     .386
  526.     push    ebp
  527.     mov    ebp,esp
  528.  
  529.     mov    cx,keycode      ; isolate bit
  530.     mov    bx,cx
  531.     xor    bh,bh
  532.     shr    bx,3
  533.     and    cx,7
  534.     mov    al,ds:_keyflags[bx]
  535.     shl     al,cl            ; 0 is msb, 7 is lsb
  536.     and    ax,80h
  537.  
  538.     mov    esp,ebp
  539.     pop    ebp
  540.     ret
  541.  
  542. _is_key_down  endp
  543.  
  544.  
  545.  
  546. ;/*********** KBRD INTERCEPT ISR *************/
  547.  
  548. ;void kbrd_isr()    ; intercepts kbrd interrupt, records key state
  549.  
  550.     PUBLIC    _kbrd_isr
  551.  
  552. _kbrd_isr    proc    far
  553.     pushf
  554.     pushad
  555.     push    ds
  556.  
  557.     cli
  558.  
  559.     mov    ax,DGROUP
  560.     mov    ds,ax
  561.  
  562.     xor    ax,ax
  563.     in    al,60h        ; get key code
  564.     mov    dx,ax
  565.     and    ax,07fh
  566.     mov    bx,ax
  567.     mov    cx,ax
  568.  
  569.     cmp    ax,60h        ; extended code flag
  570.     ja    ignore_it    ; ignore it, just makes keys identical
  571.  
  572.     shr    bx,3        ; offset in table
  573.     and    cl,7            ; bit shift
  574.     mov    ax,080h
  575.     shr    ax,cl           ; create bit mask: 0 is msb
  576.  
  577.     test    dx,80h        ; msb set if keyup even else keydown
  578.     jnz    clear_bit
  579.  
  580.     or    BYTE PTR ds:_keyflags[bx],al
  581.     jmp    done_kbrd
  582.  
  583. clear_bit:
  584.     not    al
  585.     and    BYTE PTR ds:_keyflags[bx],al
  586.  
  587. ignore_it:
  588. done_kbrd:
  589.  
  590.     int    79h    ; call old kbrd isr
  591.  
  592.     pop    ds
  593.     popad
  594.     popf
  595.     iret
  596.  
  597. _kbrd_isr  endp
  598.  
  599.     end
  600.