Code: Select all
Sega Mega Mouse
This is a three button mouse (left, middle, right) with an extra button (Start) located near the thumb position. It uses a PIC16C54
microcontroller which manages the buttons and position tracking.
The Sega Mega Mouse that is distributed in North America is incompatible with the European version of Populous 2. The mouse
functions normally but has Y axis inverted so up is down and vice-versa. It may have been designed for the Japanese Mega Drive
mouse, which is a different product with 2 buttons and unique physical appearance.
The protocol works as follows: TH and TR are outputs which tell the microcontroller to stop or start a data transfer, and to
acknowledge received data. TL is an input which returns a busy flag for the microcontroller. D3-D0 are inputs that return the data.
Here's a table showing the communication process:
Write TH TR TL D3 D2 D1 D0 Description
$60 1 1 1 0 0 0 0 Request data
$20 0 1 1 0 0 0 0 ID #0 ($0)
$00 0 0 1 1 0 1 1 ID #1 ($B)
$20 0 1 0 1 1 1 1 ID #2 ($F)
$00 0 0 1 1 1 1 1 ID #3 ($F)
$20 0 1 0 Y Over X Over Y Sign X Sign Axis sign and overflow
$00 0 0 1 Start Middle Right Left Button state
$20 0 1 0 X7 X6 X5 X4 X axis MSN
$00 0 0 1 X3 X2 X1 X0 X axis LSN
$20 0 1 0 Y7 Y6 Y5 Y4 Y axis MSN
$00 0 0 1 Y3 Y2 Y1 Y0 Y axis LSN
Write #$60 when you are done polling to stop the data transfer. If you continue to poll the mouse after collecting all the data by
writing $20 / $00, the Y axis LSN will always be returned. Sega advises polling beyond this point will make the mouse behave
abnormally. It's possible that the PIC code in some versions of the Mega Mouse may have problems if the poll sequence is too
long.
The X/Y overflow flags are supposed to be set if the mouse is moved over a distance greater than can be measured. I can't get
them to become set, maybe the mouse supports a fairly wide range of movement.
You need a considerable delay between writing new values to TH/TR. I think the intention is to poll TL until the microcontroller
returns 'not busy', but I can't get this to work reliably. Sega's mouse reading code also has a timeout when checking TL which
would indicate it may get stuck in a certain state.
All buttons (start, left, middle, right) are active-high logic, so they return '1' when pressed and '0' when released.
Code: Select all
00B640 CMPI.W #$1,D0
00B644 BLE.B START+$B648 ; port not out of range
00B646 RTS
00B648 MOVE.W #$100,($A11100)
00B650 MOVE.W #$100,($A11200)
00B658 BTST #$0,($A11100)
00B660 BNE.B START+$B658 ; wait on Z80 stopped
00B662 ADD.W D0,D0
00B664 MOVEA.L #$A10003,A0
00B66A ADDA.W D0,A0
00B66C MOVE.B #$60,($6,A0) ; set direction bits
00B672 NOP
00B674 NOP
00B676 MOVE.B #$60,(A0) ; restart mouse packet
00B67A NOP
00B67C NOP
00B67E BTST #$4,(A0)
00B682 BEQ.B START+$B67E ; wait on handshake
00B684 MOVE.B (A0),D0
00B686 ANDI.B #$F,D0
00B68A BNE.W START+$B78E ; not 0 means not mouse
00B68E MOVE.B #$20,(A0)
00B692 MOVE.W #$FE,D1
00B696 BTST #$4,(A0)
00B69A BNE.B START+$B6A4 ; handshake
00B69C DBRA D1,START+$B696 ; wait on handshake
00B6A0 BRA.W START+$B780 ; timeout err
00B6A4 MOVE.B (A0),D0
00B6A6 ANDI.W #$F,D0
00B6AA MOVE.B #$0,(A0)
00B6AE CMPI.W #$B,D0
00B6B2 BNE.W START+$B780 ; not $B means not mouse
00B6B6 BTST #$4,(A0)
00B6BA BEQ.B START+$B6C4 ; handshake
00B6BC DBRA D1,START+$B6B6 ; wait on handshake
00B6C0 BRA.W START+$B780 ; timeout err
00B6C4 MOVE.B (A0),D0 ; should be $F
00B6C6 NOP
00B6C8 MOVE.B #$20,(A0)
00B6CC NOP
00B6CE BTST #$4,(A0)
00B6D2 BNE.B START+$B6DC ; handshake
00B6D4 DBRA D1,START+$B6CE ; wait on handshake
00B6D8 BRA.W START+$B780 ; timeout err
00B6DC MOVE.B (A0),D0 ; should be $F as well
00B6DE NOP
00B6E0 NOP
00B6E2 MOVE.B #$0,(A0)
00B6E6 MOVEQ #$0,D0
00B6E8 NOP
00B6EA BTST #$4,(A0)
00B6EE BEQ.B START+$B6F8 ; handshake
00B6F0 DBRA D1,START+$B6EA ; wait on handshake
00B6F4 BRA.W START+$B780 ; timeout err
00B6F8 MOVE.B (A0),D0 ; axis sign/overflow
00B6FA MOVE.B #$20,(A0)
00B6FE LSL.W #$8,D0
00B700 BTST #$4,(A0)
00B704 BNE.B START+$B70C ; handshake
00B706 DBRA D1,START+$B700 ; wait on handshake
00B70A BRA.B START+$B780 ; timeout err
00B70C MOVE.B (A0),D0 ; buttons
00B70E MOVE.B #$0,(A0)
00B712 LSL.B #$4,D0
00B714 LSL.L #$8,D0
00B716 BTST #$4,(A0)
00B71A BEQ.B START+$B722 ; handshake
00B71C DBRA D1,START+$B716 ; wait on handshake
00B720 BRA.B START+$B780 ; timeout err
00B722 MOVE.B (A0),D0 ; x axis hi nibble
00B724 MOVE.B #$20,(A0)
00B728 LSL.B #$4,D0
00B72A LSL.L #$4,D0
00B72C BTST #$4,(A0)
00B730 BNE.B START+$B738 ; handshake
00B732 DBRA D1,START+$B72C ; wait on handshake
00B736 BRA.B START+$B780 ; timeout err
00B738 MOVE.B (A0),D0 ; x axis lo nibble
00B73A MOVE.B #$0,(A0)
00B73E LSL.B #$4,D0
00B740 LSL.L #$4,D0 ; make x axis byte
00B742 BTST #$4,(A0)
00B746 BEQ.B START+$B74E ; handshake
00B748 DBRA D1,START+$B742 ; wait on handshake
00B74C BRA.B START+$B780 ; timeout err
00B74E MOVE.B (A0),D0 ; y axis hi nibble
00B750 MOVE.B #$20,(A0)
00B754 LSL.B #$4,D0
00B756 LSL.L #$4,D0
00B758 BTST #$4,(A0)
00B75C BEQ.B START+$B764 ; handshake
00B75E DBRA D1,START+$B758 ; wait on handshake
00B762 BRA.B START+$B780 ; timeout err
00B764 MOVE.B (A0),D0 ; y axis lo nibble
00B766 MOVE.B #$60,(A0)
00B76A LSL.B #$4,D0
00B76C LSR.L #$4,D0 ; make y axis byte
00B76E BTST #$4,(A0)
00B772 BEQ.B START+$B76E ; wait on handshake
00B774 NOP
00B776 MOVE.W #$0,($A11100) ; free z80 bus
00B77E RTS
00B780 MOVE.B #$60,(A0) ; timeout err -> restart mouse packet
00B784 NOP
00B786 NOP
00B788 BTST #$4,(A0)
00B78C BEQ.B START+$B788 ; wait on handshake
00B78E MOVEQ #-$1,D0
00B790 MOVE.W #$0,($A11100) ; free z80 bus
00B798 RTS
Whew! That's one heck of a routine.