www.pudn.com > zsnes117b-src.zip > sw32.asm


;Copyright (C) 1997-2001 ZSNES Team ( zsknight@zsnes.com / _demo_@zsnes.com ) 
; 
;This program is free software; you can redistribute it and/or 
;modify it under the terms of the GNU General Public License 
;as published by the Free Software Foundation; either 
;version 2 of the License, or (at your option) any later 
;version. 
; 
;This program is distributed in the hope that it will be useful, 
;but WITHOUT ANY WARRANTY; without even the implied warranty of 
;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
;GNU General Public License for more details. 
; 
;You should have received a copy of the GNU General Public License 
;along with this program; if not, write to the Free Software 
;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 
 
 
 
 
 
 
 
;32-bit DOS-Mode driver for the Microsoft Sidewinder Gamepad 
;Multi-SW Version 1.5 
;(C) 1997, 1998 Robert William Grubbs, All Rights Reserved 
;Latest revision 1/20/98 
;  Driver Source code Include file 
 
;C-linkable, rewrote decoder -sardu 
 
;Flat memory mode (Protected mode extender required!  Tested with DOS32) 
;Tested with TASM 4.0+ 
 
 
SW1 dd 0                ;SW #1's button status 
SW2 dd 0                ;SW #2's button status 
SW3 dd 0                ;SW #3's button status 
SW4 dd 0                ;SW #4's button status 
SWCount dd 1            ;Tell the driver how many sidewinders are present 
SWSetup dd 0            ;Tell the driver what polling mode to use 
                        ;  0=Interrupts disabled, Multiple OUT statements 
                        ;  1=Interrupts disabled, Single OUT statement 
                        ;  2=Interrupts enabled, Multiple OUT statements 
                        ;  3=Interrupts enabled, Single OUT statement 
 
gDump times 100h db 0   ;SW Status dump buffer (space for 256 bytes, uses 200) 
bDump times 80h db 0    ;buffer to hold button data (Modes A and B, all SW) 
 
;This macro calculates parity for the buttons and compares it to the SW's 
; parity bit.  If they don't match, the button data is discarded. 
%macro ParityCheckSW 1 
  mov ecx,ebx                    ;duplicate button status 
  xor cl,ch                      ; 
  jpe %%ParChkSW 
  mov [%1],ebx              ;update button status for SW #n 
%%ParChkSW                      ;done 
%endmacro 
 
;The main subroutine;  this is the important one;  bow down before it 
;IN: None 
;Out: SWx=buttons (bit 0=null 1=up 2=dn 3=rt 4=lt 5=A 6=B 7=C 8=X) 
;                 (9=Y 10=Z 11=L 12=R 13=St 14=M 15=Parity) 
;No registers destroyed 
 
readSideWinder: 
  pushad 
 
  mov ecx,200                 ;dump buffer fill size 
  mov ebx,gDump               ;initial dump pointer 
  mov edx,0201h               ;joystick port 
 
  cmp dword[SWSetup],0 
  jne NotSW0 
  cli                         ;Disable interrupts (required to avoid jitter) 
  GetSWDataLoop:              ; 
  out dx,al                   ;trigger joystick port 
  in al,dx                    ;read SW status byte 
  mov [ebx],al                ;dump status byte 
  inc ebx                     ;increment dump pointer 
  dec ecx 
  jnz GetSWDataLoop 
  sti                         ;Re-enable interrupts 
  jmp SWPollDone 
 
  NotSW0: 
  cmp dword[SWSetup],1 
  jne NotSW1 
  cli                         ;Disable interrupts (required to avoid jitter) 
  out dx,al                   ;trigger joystick port 
  GetSWDataLoop1:             ; 
  in al,dx                    ;read SW status byte 
  mov [ebx],al                ;dump status byte 
  inc ebx                     ;increment dump pointer 
  dec ecx 
  jnz GetSWDataLoop1 
  sti                         ;Re-enable interrupts 
  jmp SWPollDone 
 
  NotSW1: 
  cmp dword[SWSetup],2 
  jne NotSW2 
  GetSWDataLoop2:             ; 
  out dx,al                   ;trigger joystick port 
  in al,dx                    ;read SW status byte 
  mov [ebx],al                ;dump status byte 
  inc ebx                     ;increment dump pointer 
  dec ecx 
  jnz GetSWDataLoop2 
  jmp SWPollDone 
 
  NotSW2: 
  ;default all others to SWStatus=3 
  out dx,al                   ;trigger joystick port 
  GetSWDataLoop3:             ; 
  in al,dx                    ;read SW status byte 
  mov [ebx],al                ;dump status byte 
  inc ebx                     ;increment dump pointer 
  dec ecx 
  jnz GetSWDataLoop3 
 
  SWPollDone: 
 
  mov ecx,0                   ;tick count 
  mov esi,1                   ;initialize output mask 
  mov ebx,0                   ;initialize output 
  mov edi,0                   ;initialize input pointer 
 
  ;My current method of cycle detection is to look for 15 highs in a row on 
  ; the strobe line.  Cycle ends is detected by 15 lows in a row. 
  ;Mode A has 15 strobes in a cycle, Mode B has 5. 
  ; Note that the 15 highs/lows for cycle detection may be too high for slow 
  ; machines.  I havn't seen a problem yet, but it may exist... 
  ;Multiple Sidewinder data complicates things.  Each additional SW tags 
  ; another set of strobes to the cycle, 5 more in mode B, 15 more in mode A. 
  ; Detecting extra SW gamepad data is fairly simple: count the number of 
  ; strobes. If it is a multiple of 5, you're in mode B and can divide by 5 
  ; to get the total number of gamepads.  If it's divisible by 15, use mode A. 
  ; However, this method cannot distinguish between mode A for one SW and mode 
  ; B for three SW.  In that case, the SWCount variable must be set correctly. 
 
  FindCycle: 
  mov al,[gDump+edi]          ;get next status byte 
  inc edi                     ;increment input pointer 
  cmp edi,200                 ;test for end of status block 
  je SWNoFind                 ;if it's the end, quit sub with error 
  test al,00010000b           ;Check for nonzero bits 
  jnz WMFCS1                  ; 
  xor ecx,ecx                 ;if zero, reset tick count 
  jmp FindCycle               ;can't be pre-cycle 
  WMFCS1:                     ;Possibly pre-cycle 
  inc ecx                     ;increment tick count 
  cmp ecx,15                  ;test for sufficient ticks for cycle start 
  jne FindCycle               ;if insufficient, get next status byte 
                              ;Yippie! it found a (probable) cycle! 
 
  mov ebp,0                   ;initialize bDump index (strobe count) 
 
  FindStrobeLow:              ;Search for leading edge of data strobe 
  mov al,[gDump+edi]          ;get next status byte 
  inc edi                     ;increment input pointer 
  cmp edi,200                 ;test for end of status block 
  je SWNoFind                 ;if it's the end, quit sub with error 
  test al,00010000b           ;get "strobe" bit 
  jnz SHORT FindStrobeLow     ;if it isn't zero, we're not there yet 
  xor ecx,ecx                 ;initialize cycle end test count 
 
  FindStrobeHigh: 
  inc ecx                     ;increment zero count 
  cmp ecx,0fh                 ;is it 15? 
  je SWModeCheck              ;if so, goto mode check 
  mov al,[gDump+edi]          ;get next status byte 
  inc edi                     ;increment input pointer 
  cmp edi,200                 ;test for end of status block 
  je SWNoFind                 ;if it's the end, quit sub with error 
  test al,00010000b           ;get "strobe" bit 
  jz FindStrobeHigh           ;if it is zero, we're not there yet 
                              ;if not, we're there!  data bit is valid (probably) 
  mov [bDump+ebp],al          ;preserve data for button decoding 
  inc ebp                     ;increment strobe count/bDump index 
  jmp FindStrobeLow           ;wait for the next button 
 
 SMWDone: 
 SWNoFind: 
  popad 
  ret                         ;return to calling procedure 
 
 SWModeCheck:                ;Check strobe count to identify mode and # of SW 
  cmp ebp,15                  ;Is it Mode A with 1 Sidewinder or B with 3? 
  je ModeA1 
  cmp ebp,5                   ;Is it Mode B with 1 Sidewinders? 
  je ModeB1 
  cmp ebp,30                  ;Is it Mode A with 2 Sidewinders? 
  je ModeA2 
  cmp ebp,10                  ;Is it Mode B with 2 Sidewinders? 
  je near ModeB2 
  cmp ebp,45                  ;Is it Mode A with 3 Sidewinders? 
  je near ModeA3 
  cmp ebp,60                  ;Is it Mode A with 4 Sidewinders? 
  je near ModeA4 
  cmp ebp,20                  ;Is it Mode B with 4 Sidewinders? 
  je near ModeB4 
  jmp SHORT SWNoFind          ;Any other # of strobes is invalid data 
 
  ModeB1: 
  xor ebp,ebp 
  call DoModeB 
  ParityCheckSW SW1 
  jmp SMWDone 
 
  ModeA1: 
  cmp dword [SWCount],3 
  je near ModeB3 
  xor ebp,ebp 
  call DoModeA 
  ParityCheckSW SW1 
  jmp SMWDone 
 
  ModeA2: 
  xor ebp,ebp 
  call DoModeA 
  ParityCheckSW SW1 
  mov ebp,15 
  call DoModeA 
  ParityCheckSW SW2 
  jmp SMWDone 
 
  ModeA3: 
  xor ebp,ebp 
  call DoModeA 
  ParityCheckSW SW1 
  mov ebp,15 
  call DoModeA 
  ParityCheckSW SW2 
  mov ebp,30 
  call DoModeA 
  ParityCheckSW SW3 
  jmp SMWDone 
 
  ModeA4: 
  xor ebp,ebp 
  call DoModeA 
  ParityCheckSW SW1 
  mov ebp,15 
  call DoModeA 
  ParityCheckSW SW2 
  mov ebp,30 
  call DoModeA 
  ParityCheckSW SW3 
  mov ebp,45 
  call DoModeA 
  ParityCheckSW SW4 
  jmp SMWDone 
 
  ModeB2: 
  xor ebp,ebp 
  call DoModeB 
  ParityCheckSW SW1 
  mov ebp,5 
  call DoModeB 
  ParityCheckSW SW2 
  jmp SMWDone 
 
  ModeB3: 
  xor ebp,ebp 
  call DoModeB 
  ParityCheckSW SW1 
  mov ebp,5 
  call DoModeB 
  ParityCheckSW SW2 
  mov ebp,10 
  call DoModeB 
  ParityCheckSW SW3 
  jmp SMWDone 
 
  ModeB4: 
  xor ebp,ebp 
  call DoModeB 
  ParityCheckSW SW1 
  mov ebp,5 
  call DoModeB 
  ParityCheckSW SW2 
  mov ebp,10 
  call DoModeB 
  ParityCheckSW SW3 
  mov ebp,15 
  call DoModeB 
  ParityCheckSW SW4 
  jmp SMWDone 
ENDP 
 
%macro SWRepeat 1 
  mov al,[bDump+ebp+%1] 
  shr al,5       ;get upper 3 bits 
  shl eax,1+3*%1  ;shift into place 
  or  ebx,eax    ;or into output 
%endmacro 
 
DoModeB: 
  xor ebx,ebx                 ;Initialize output 
  xor eax,eax 
 
  SWRepeat 0 
  SWRepeat 1 
  SWRepeat 2 
  SWRepeat 3 
  SWRepeat 4 
 
  xor ebx,0FFFEh 
  ret 
 
DoModeA: 
  xor ebx,ebx                 ;Clear output 
  mov ecx,15 ;bit count 
 
ALP: 
  mov al,[bDump+ebp] 
  inc ebp 
  shl al,3 
  rcr ebx,1 
  dec ecx 
  jg  ALP 
 
  shr ebx,16 
  xor ebx,0FFFEh 
  ret