Mega Mouse Usage

For anything related to IO (joypad, serial, XE...)

Moderator: BigEvilCorporation

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Re: Mega Mouse Usage

Post by Chilly Willy » Mon Jul 10, 2017 2:30 pm

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. :D

Eke
Very interested
Posts: 884
Joined: Wed Feb 28, 2007 2:57 pm
Contact:

Re: Mega Mouse Usage

Post by Eke » Tue Jul 11, 2017 10:18 pm

Yes, that's pretty much it :wink:

elfor
Newbie
Posts: 8
Joined: Sat Sep 08, 2018 1:30 am

Re: Mega Mouse Usage

Post by elfor » Sun Sep 16, 2018 3:18 pm

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:
Image

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 489 times

Chilly Willy
Very interested
Posts: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Re: Mega Mouse Usage

Post by Chilly Willy » Mon Sep 17, 2018 5:53 pm

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

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
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

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;
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.

cero
Very interested
Posts: 338
Joined: Mon Nov 30, 2015 1:55 pm

Re: Mega Mouse Usage

Post by cero » Tue Sep 18, 2018 11:00 am

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?

Sik
Very interested
Posts: 939
Joined: Thu Apr 10, 2008 3:03 pm
Contact:

Re: Mega Mouse Usage

Post by Sik » Tue Sep 18, 2018 3:00 pm

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: 2984
Joined: Fri Aug 17, 2007 9:33 pm

Re: Mega Mouse Usage

Post by Chilly Willy » Fri Sep 28, 2018 1:29 pm

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. 8)

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
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).

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
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.

elfor
Newbie
Posts: 8
Joined: Sat Sep 08, 2018 1:30 am

Re: Mega Mouse Usage

Post by elfor » Sun Nov 11, 2018 5:26 pm

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:
Attachments
GenesisDuneMousePatch.rar
(8.04 KiB) Downloaded 462 times

elfor
Newbie
Posts: 8
Joined: Sat Sep 08, 2018 1:30 am

Re: Mega Mouse Usage

Post by elfor » Mon Nov 12, 2018 2:03 pm

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

Post Reply