
Mega Mouse Usage
Moderator: BigEvilCorporation
- 
				Chilly Willy
- Very interested
- Posts: 2995
- Joined: Fri Aug 17, 2007 9:33 pm
Re: Mega Mouse Usage
I see, you're trying to improve your emulator to get those weird games that didn't follow the rules to work by finding all the edge cases for incorrect usage. Those can be kinda fun to get working without breaking everything else.  
			
			
									
						
										
						
Re: Mega Mouse Usage
Yes, that's pretty much it   
			
			
									
						
										
						
Re: Mega Mouse Usage
Hi, sorry to bother, but i don't know where else to ask about Genesis assembler...
The Russian hacker "Ti" made an almost complete mouse patch for Dune, but lost interest.
It already works well except building placement has problems, sometimes it drifts a bit.
Could anyone else please take a quick look, perhaps (i hope) it's a quick fix?
I ask because there's a whole Russian Genesis Dune romhacking community out here.
And all these giant romhacks would benefit immensely from actual mouse support:
https://www.emu-land.net/forum/index.php?topic=16864
They even have 480x464 hacks of Dune, using a modded Mednafen, it's amazing:

The goal is to play those 480x464 hacks with the mouse.
Attached is the .asm patch i received from Ti, it's for: Dune - The Battle for Arrakis (USA).md CRC 4DEA40BA
Any thoughts or comments? Thanks & cheers
			
							The Russian hacker "Ti" made an almost complete mouse patch for Dune, but lost interest.
It already works well except building placement has problems, sometimes it drifts a bit.
Could anyone else please take a quick look, perhaps (i hope) it's a quick fix?
I ask because there's a whole Russian Genesis Dune romhacking community out here.
And all these giant romhacks would benefit immensely from actual mouse support:
https://www.emu-land.net/forum/index.php?topic=16864
They even have 480x464 hacks of Dune, using a modded Mednafen, it's amazing:

The goal is to play those 480x464 hacks with the mouse.
Attached is the .asm patch i received from Ti, it's for: Dune - The Battle for Arrakis (USA).md CRC 4DEA40BA
Any thoughts or comments? Thanks & cheers
- Attachments
- 
			
		
		
				- dunemouse.rar
- (2.32 KiB) Downloaded 4487 times
 
- 
				Chilly Willy
- Very interested
- Posts: 2995
- Joined: Fri Aug 17, 2007 9:33 pm
Re: Mega Mouse Usage
It drifts because it doesn't handle the sign bits for the mouse. It also doesn't check for overflow, but that's probably not an issue most of the time. Here's how it handles x and y
Note that all it does is simply use the raw x and y values from the mouse, sign extended to a word and divided by two. That may work some of the time, but isn't correct and will drift under the wrong conditions. The proper way to handle it is like this
Here we check for overflow, and then we properly sign extend the value using the sign bits. See how the extension is done? "mx |= mx ? 0xFF00 : 0xFFFF;" That prevents the drift you see in the game.
			
			
									
						
										
						Code: Select all
		move.w	($FFFFBF14).w,d1
		move.b	d0,d2
		ext.w	d2
		asr.w	#1,d2
		sub.w	d2,d1
		cmpi.w	#$D0,d1
		ble.s	*+6
		move.w	#$D0,d1
		cmpi.w	#$10,d1
		bge.s	*+6
		move.w	#$10,d1
		move.w	d1,($FFFFBF14).w		
		lsr.l	#8,d0
		move.w	($FFFFBF12).w,d1
		move.b	d0,d2
		ext.w	d2
		asr.w	#1,d2
		add.w	d2,d1
		cmpi.w	#$130,d1
		ble.s	*+6
		move.w	#$130,d1
		cmpi.w	#$10,d1
		bge.s	*+6
		move.w	#$10,d1	
		move.w	d1,($FFFFBF12).w
Code: Select all
            if (md[0] & 0x04)
                mx = 256; /* x overflow */
            else
                mx = md[2]<<4 | md[3];
            if (md[0] & 0x01)
                mx |= mx ? 0xFF00 : 0xFFFF; /* x sign extend */
            if (md[0] & 0x08)
                my = 256; /* y overflow */
            else
                my = md[4]<<4 | md[5];
            if (md[0] & 0x02)
                my |= my ? 0xFF00 : 0xFFFF; /* y sign extend */
            joyAxisX[port] += (s16)mx;
            joyAxisY[port] += (s16)my;
Re: Mega Mouse Usage
If you're going as far as hacked emulators to use a resolution it wasn't designed for, is that really worth playing vs just running the PC version?
			
			
									
						
										
						Re: Mega Mouse Usage
The drift issue would still happen without the hacked resolution (you can get the mouse to report a large enough motion to trigger the bug).
			
			
									
						
							Sik is pronounced as "seek", not as "sick".
			
						- 
				Chilly Willy
- Very interested
- Posts: 2995
- Joined: Fri Aug 17, 2007 9:33 pm
Re: Mega Mouse Usage
Just posting an update on the Dune mouse patch. Here's my current code to read the mouse. Of note, it assembles (using asmx) to 58 bytes smaller than the original code (400 bytes vs 458) and handles overflow and sign properly. Tested on my Model 2 Genesis + Model 2 CD + 32X with both a Japanese Sega Mouse and a US Mega Mouse, it's smooth as silk.   
 
Note: I could pull the main loops for reading the header and packet out as a subroutine to make the code even smaller, but I wasn't trying to make the code as small as possible, just smaller than the original code despite the extra processing on the packet.
EDIT: Pulling the three-line handshake out as a subroutine reduces the size to 346 bytes. No noticeable impact on the game (I didn't expect any as the cost of the bsr/rts is minimal compared to the overall length of mouse handling).
EDIT 2: Note that while the code above halts the Z80, strictly speaking, it isn't necessary. There's a bug in the MD where under certain conditions, if you don't halt the Z80 while reading the IO area, the Z80 rom access cycle time becomes shortened until you reset the MD. With the original old, slow roms Sega and other devs used when the system first came out, you did need to halt the Z80. However, devs soon realized that higher speed roms could still meet the faster cycle time, so it didn't matter if the cycle time was shortened. As faster roms became cheaper, more and more games quit halting the Z80 while accessing IO. The code above only halts the Z80 because the original patch did, and I wanted to leave the patch alone as much as possible while fixing mouse handling.
			
			
									
						
										
						 
 Note: I could pull the main loops for reading the header and packet out as a subroutine to make the code even smaller, but I wasn't trying to make the code as small as possible, just smaller than the original code despite the extra processing on the packet.
Code: Select all
; ---------------------------------------------------------------------------
        org $2460
mouse_read:
; halt z80
        move.w  #$100,($A11100).l
        move.w  #$100,($A11200).l
wait_z80:
        btst    #0,($A11100).l
        bne.s   wait_z80
        movea.l #$A10005,a0
        move.b  #$60,6(a0)  ; set port direction for TLH
        nop
        nop
        move.b  #$60,(a0)   ; set port for TLH
        nop
        nop
wait_hs1:
        btst    #4,(a0)
        beq.s   wait_hs1
; get header
        move.w  #254,d1     ; # retries
        moveq   #1,d2       ; two bytes (four nibbles) in header
hdr_loop:
        move.b  (a0),d0
        move.b  #$20,(a0)   ; next phase
        lsl.b   #4,d0
        lsl.l   #4,d0       ; save nibble
wait_hs2:
        btst    #4,(a0)
        bne.s   hdr_phase2
        dbra    d1,wait_hs2
        bra.w   mouse_err
hdr_phase2:
        move.b  (a0),d0
        move.b  #0,(a0)     ; next phase
        lsl.b   #4,d0
        lsl.l   #4,d0       ; save nibble
wait_hs3:
        btst    #4,(a0)
        beq.s   hdr_chklp
        dbra    d1,wait_hs3
        bra.w   mouse_err
hdr_chklp:
        dbra    d2,hdr_loop
        lsr.l   #8,d0
; check header
        cmpi.w  #$0BFF,d0   ; check for mouse
        bne.w   mouse_err
; get mouse packet
        moveq   #2,d2       ; three bytes (six nibbles) in packet
pkt_loop:
        move.b  (a0),d0
        move.b  #$20,(a0)   ; next phase
        lsl.b   #4,d0
        lsl.l   #4,d0       ; save nibble
wait_hs4:
        btst    #4,(a0)
        bne.s   pkt_phase2
        dbra    d1,wait_hs4
        bra.w   mouse_err
pkt_phase2:
        move.b  (a0),d0
        move.b  #0,(a0)     ; next phase
        lsl.b   #4,d0
        lsl.l   #4,d0       ; save nibble
wait_hs5:
        btst    #4,(a0)
        beq.s   pkt_chklp
        dbra    d1,wait_hs5
        bra.w   mouse_err
pkt_chklp:
        dbra    d2,pkt_loop
        lsr.l   #8,d0
        move.b  #$60,(a0)           ; TLH done
        move.w  #0,($A11100).l      ; release z80
; process mouse packet
;   d0 = YO XO YS XS S M R L X7 X6 X5 X4 X3 X2 X1 X0 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
        moveq   #0,d2
        move.b  d0,d2
        btst    #23,d0              ; YO
        beq.s   chkys               ; no overflow
        move.w  #$0100,d2
        btst    #21,d0              ; YS
        beq.s   calcy               ; positive
        neg.w   d2
        bra.s   calcy
chkys:
        btst    #21,d0              ; YS
        beq.s   calcy               ; positive
        or.w    #$FF00,d2           ; sign-extend Y
        tst.b   d2
        bne.s   calcy
        seq     d2                  ; handle -0 case
calcy:
        asr.w   #1,d2
        move.w  ($FFFFBF14).w,d1    ; screen Y coord
        sub.w   d2,d1
        cmpi.w  #$D0,d1
        ble.s   *+6
        move.w  #$D0,d1
        cmpi.w  #$10,d1
        bge.s   *+6
        move.w  #$10,d1
        move.w  d1,($FFFFBF14).w    ; update Y coord
        lsr.w   #8,d0
        btst    #22,d0              ; XO
        beq.s   chkxs               ; no overflow
        move.w  #$0100,d0
        btst    #20,d0              ; XS
        beq.s   calcx               ; positive
        neg.w   d0
        bra.s   calcx
chkxs:
        btst    #20,d0              ; XS
        beq.s   calcx               ; positive
        or.w    #$FF00,d0           ; sign-extend X
        tst.b   d0
        bne.s   calcx
        seq     d0                  ; handle -0 case
calcx:
        asr.w   #1,d0
        move.w  ($FFFFBF12).w,d1    ; screen X coord
        add.w   d0,d1
        cmpi.w  #$130,d1
        ble.s   *+6
        move.w  #$130,d1
        cmpi.w  #$10,d1
        bge.s   *+6
        move.w  #$10,d1
        move.w  d1,($FFFFBF12).w    ; update X coord
        clr.b   d1
        btst    #16,d0              ; LMB
        beq.s   *+6
        bset    #6,d1
        btst    #17,d0              ; RMB
        beq.s   *+6
        bset    #4,d1
        move.b  d1,d0
        move.b  ($FFFFE41C).w,d1    ; save current button state
        move.b  d0,($FFFFE41C).w    ; set current button state
        eor.b   d0,d1
        move.b  d1,($FFFFE41D).w    ; change in button state
        rts
; ---------------------------------------------------------------------------
mouse_err:
        move.b  #$60,(a0)
        nop
        nop
wait_err:
        btst    #4,(a0)
        beq.s   wait_err
        moveq   #-1,d0
        move.w  #0,($A11100).l      ; release z80
        rts
Code: Select all
; ---------------------------------------------------------------------------
        org $2460
mouse_read:
; halt z80
        move.w  #$100,($A11100).l
        move.w  #$100,($A11200).l
wait_z80:
        btst    #0,($A11100).l
        bne.s   wait_z80
        movea.l #$A10005,a0
        move.b  #$60,6(a0)          ; set port direction for TLH
        nop
        nop
        move.b  #$60,(a0)           ; set port for TLH
        nop
        nop
wait_hs0:
        btst    #4,(a0)
        beq.s   wait_hs0
        move.w  #254,d1             ; # retries
; get header
        moveq   #1,d2               ; two bytes (four nibbles) in header
        bsr.w   do_tlh
; check header
        cmpi.w  #$0BFF,d0           ; check for mouse
        bne.w   mouse_err
; get mouse packet
        moveq   #2,d2               ; three bytes (six nibbles) in packet
        bsr.w   do_tlh
        move.b  #$60,(a0)           ; TLH done
        move.w  #0,($A11100).l      ; release z80
; process mouse packet
;   d0 = YO XO YS XS S M R L X7 X6 X5 X4 X3 X2 X1 X0 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
        btst    #23,d0              ; YO
        beq.s   chkys               ; no overflow
        move.w  #$0100,d2
        btst    #21,d0              ; YS
        beq.s   calcy               ; positive
        neg.w   d2
        bra.s   calcy
chkys:
        moveq   #0,d2
        move.b  d0,d2
        btst    #21,d0              ; YS
        beq.s   calcy               ; positive
        or.w    #$FF00,d2           ; sign-extend Y
        tst.b   d2
        bne.s   calcy
        seq     d2                  ; handle -0 case
calcy:
        asr.w   #1,d2
        move.w  ($FFFFBF14).w,d1    ; screen Y coord
        sub.w   d2,d1
        cmpi.w  #$D0,d1
        ble.s   chkymin
        move.w  #$D0,d1
chkymin:
        cmpi.w  #$10,d1
        bge.s   updsy
        move.w  #$10,d1
updsy:
        move.w  d1,($FFFFBF14).w    ; update Y coord
        btst    #22,d0              ; XO
        beq.s   chkxs               ; no overflow
        move.w  #$0100,d0
        btst    #20,d0              ; XS
        beq.s   calcx               ; positive
        neg.w   d0
        bra.s   calcx
chkxs:
        lsr.w   #8,d0
        btst    #20,d0              ; XS
        beq.s   calcx               ; positive
        or.w    #$FF00,d0           ; sign-extend X
        tst.b   d0
        bne.s   calcx
        seq     d0                  ; handle -0 case
calcx:
        asr.w   #1,d0
        move.w  ($FFFFBF12).w,d1    ; screen X coord
        add.w   d0,d1
        cmpi.w  #$130,d1
        ble.s   chkxmin
        move.w  #$130,d1
chkxmin:
        cmpi.w  #$10,d1
        bge.s   updsx
        move.w  #$10,d1
updsx:
        move.w  d1,($FFFFBF12).w    ; update X coord
        clr.b   d1
        btst    #16,d0              ; LMB
        beq.s   chkrmb
        bset    #6,d1
chkrmb:
        btst    #17,d0              ; RMB
        beq.s   do_btns
        bset    #4,d1
do_btns:
        move.b  d1,d0
        move.b  ($FFFFE41C).w,d1    ; save current button state
        move.b  d0,($FFFFE41C).w    ; set current button state
        eor.b   d0,d1
        move.b  d1,($FFFFE41D).w    ; change in button state
        rts
do_tlh:
        move.b  (a0),d0
        move.b  #$20,(a0)   ; next phase
        lsl.b   #4,d0
        lsl.l   #4,d0       ; save nibble
wait_hs1:
        btst    #4,(a0)
        bne.s   pkt_phase2
        dbra    d1,wait_hs1
        addq.l  #4,sp       ; pop return address
        bra.s   mouse_err
pkt_phase2:
        move.b  (a0),d0
        move.b  #0,(a0)     ; next phase
        lsl.b   #4,d0
        lsl.l   #4,d0       ; save nibble
wait_hs2:
        btst    #4,(a0)
        beq.s   pkt_chklp
        dbra    d1,wait_hs2
        addq.l  #4,sp       ; pop return address
        bra.s   mouse_err
pkt_chklp:
        dbra    d2,do_tlh
        lsr.l   #8,d0
        rts
; ---------------------------------------------------------------------------
mouse_err:
        move.b  #$60,(a0)           ; TLH done
        move.w  #0,($A11100).l      ; release z80
        moveq   #-1,d0
        rts
Re: Mega Mouse Usage
Big thanks again to Chilly Willy for fixing this & Russian hacker Ti_ for creating the initial Dune mouse patch!
Attached are .ips & .bps versions of the fixed patch, apply to the Dune USA rom with CRC 4dea40ba:
			
							Attached are .ips & .bps versions of the fixed patch, apply to the Dune USA rom with CRC 4dea40ba:
- Attachments
- 
			
		
		
				- GenesisDuneMousePatch.rar
- (8.04 KiB) Downloaded 4465 times
 
Re: Mega Mouse Usage
I would also like to point out a second way to play Dune (and few other Genesis games) with a mouse.
The Gens32 Surreal emulator (latest version from 2013) comes with a few internal mouse drivers!
Drivers for the following games, they are found in the "Tools\Mouse Drivers folder" subfolder:
Cannon Fodder (E) [!].gmd
Dune - The Building of a Dynasty (U) [!].gmd
General Chaos (UE) [!].gmd
LETHAL ENFORCERS.gmd
Lethal Enforcers II - Gun Fighters (UJ) [!].gmd
T2 - The Arcade Game.gmd
For this to work the rom & gmd must be named the same & be in the Gens32 Surreal root folder, example:
Gens32Surreal.exe
T2 - The Arcade Game.bin
T2 - The Arcade Game.gmd
Then just open the rom with Gens32Surreal.exe & press SHIFT + M to enable the mouse, that's it.
You should then see a white "mouse driver loaded" & "mouse enabled" text in the bottom left...
Download Gens32 Surreal here: Gens32_Surreal_V1.90Std.zip or 1.90-std.7z on github
Edit: This method works with unpatched standard roms
			
			
									
						
										
						The Gens32 Surreal emulator (latest version from 2013) comes with a few internal mouse drivers!
Drivers for the following games, they are found in the "Tools\Mouse Drivers folder" subfolder:
Cannon Fodder (E) [!].gmd
Dune - The Building of a Dynasty (U) [!].gmd
General Chaos (UE) [!].gmd
LETHAL ENFORCERS.gmd
Lethal Enforcers II - Gun Fighters (UJ) [!].gmd
T2 - The Arcade Game.gmd
For this to work the rom & gmd must be named the same & be in the Gens32 Surreal root folder, example:
Gens32Surreal.exe
T2 - The Arcade Game.bin
T2 - The Arcade Game.gmd
Then just open the rom with Gens32Surreal.exe & press SHIFT + M to enable the mouse, that's it.
You should then see a white "mouse driver loaded" & "mouse enabled" text in the bottom left...
Download Gens32 Surreal here: Gens32_Surreal_V1.90Std.zip or 1.90-std.7z on github
Edit: This method works with unpatched standard roms