What's new

twistedsymphony

Enlightened
Staff member
Immortal
Joined
Jul 21, 2015
Messages
11,655
Reaction score
13,071
Location
NH, USA
I'm working on a conversion, it's 99% complete but there is an issue with the controls. I think I have a solution but I'm a total 68K noob so I wanted to bounce this off some of the experts here on AP.

Overview of the problem:
The original hardware for the target game (the game I'm converting TO) had inputs mapped to an IO chip with all player 1 controls mapped to 1 byte, and all player 2 controls mapped to a different byte, joysticks in the upper nibble and buttons in the lower nibble

The new hardware from the donor game (the PCB I'm converting) has inputs mapped to the same IO chip but with joysticks for both players mapped to 1 byte and buttons for both players mapped to a different byte. with player 1 in the upper nibble and player 2in the lower nibble.

Unfortunately fixing this in hardware would require cutting half the traces and re-wiring :-/

the code in the target game currently looks like this (A5 = 108000):
Code:
010F1A   move.b  $30000F.l, (-$8000,A5)      1B79 0030 0006 8000
010F22   move.b  $300005.l, (-$7fff,A5)      1B79 0030 0005 8001
0x30000F is the location of the IO address for joysticks, 0x300005 is the location of the IO address for buttons.
and 0x100000 is end memory location for Player 1 controls and 0x100001 is the end memory location for player 2 controls.

So the results is that when you play the game Player 1 has to use player 2's joysticks for buttons and player 2 has to use player 1's buttons as a joystick.


Simplification

basically we need to do this
#read value 0xAB from 0x30000F
#read value 0xCD from 0x300005

#write value 0xAC to 0x100000
#write value 0xBD to 0x100001

since the destination forms a single word we could also consider:
#write value 0xACBD to 0x100000


What I'm thinking for solutions

I don't think I'll be able to make a solution work in the space available for the original 2 lines of code, so I'll likely have to jump to an unused area of the program ROM:
I've identified an empty range here: 6E8E4 - 7FE00



IDEA #1
Code:
jmp $6E900  ; place this in location of original line

; starting at location 6E900
move.b  $30000F.l, (-$8000,A5) ; move all joy data from IO to P1 Memory location
move.b  $300005.l, (-$7fff,A5) ; move all button data from IO to P2 memory location

andi.w #$FF0, (-$8000,A5) ; use AND mask to clear P1 button data and P2 joy data

move.b  $300005.l, D0     ; move all button data to D0
lsr.b  #4, D0             ; shift data right to move p1 button data to correct spot and remove p2 button data
or.b   D0, (-$8000,A5)    ; OR result into P1 memory location

move.b  $30000F.l, D0     ; move all joy data to D0
lsl.b  #4, D0             ; shift data left to move P2 joy data to correct spot and remove p1 joy data
or.b   D0, (-$7fff,A5)    ; OR result into P2 memory location

jmp $10F2A   ; jump back to original location


IDEA #2
Code:
jmp $6E900  ; place this in location of original line

; starting at location 6E900
move.b  $30000F.l, D0    ; move all joy data from IO to D0
lsl.w   #4, D0           ; shift all joy data up one nibble (00** -> 0**0)
lsr.b   #4, D0           ; shift p2 joy data back down one nibble (*0 -> 0*)
lsl.w   #4, D0           ; shift all joy data up one nibble (0*0*-> *0*0)
move.w  D0, (-$8000,A5)  ; move joy data to P1 and P2 memory with 00 for button data

move.w  #$0, D0          ; clear the lower word of D0
move.b  $300005.l, D0    ; move all button data from IO to D0
lsl.w   #4, D0           ; shift all button data up one nibble (00** -> 0**0)
lsr.b   #4, D0           ; shift p2 button data back down one nibble (*0 -> 0*)
or.w    D0, (-$8000,A5)  ; OR D0 button data with P1 and P2 joy data into memory

jmp $10F2A   ; jump back to original location
I feel like option 2 would be more efficient but I'm not sure if it would actually work as it relies on being able to shift the first byte of D0 without moving the second byte (does shifting work that way or does it always shift the whole register?)

Questions for the experts...
Do either of these approaches make sense?

Are there efficiency problems here?
If so, what's more efficient method?

Are there problems with utilizing D0?
if so, there is a: "move.w D0, $300000.l" operation before the inputs are collected, so should I move 0x300000 back into D0 once I'm done?
 
I'm by no means an expert, but my advice is just give it a go!

You have the right idea to jump out to your code and jump back afterwards. Just make sure you fill any extra space in the original code you are overwriting with nops.

Set a breakpoint in MAME for your code, then step through it one instruction at a time to confirm what you want to happen is actually happening.

Watch the registers in MAME debugger on left and have the memory viewer open too.

You probably won't have any problems using D0, but I guess if you did you could back up D0 first and restore it after your code runs.

Generally the most efficient method is going to be the one with the least number of instructions. What you have here with 5-10 instructions shouldn't cause a performance hit.
 
Already said i'd check it on the weekend, it's not saturday yet have some patience ;)
 
Thanks, I dumped the game assembly out of MAME and I've manged to find corresponding hex values for all of the instructions I want to execute in "idea #2"; essentially manually compiling it. I'm sure there's a better way but my tool set at the moment is just mame debugger and a hex editor; ie: banging two rocks together. So I'll be testing that out first and see how it goes. :D

I also found this wiki entry talking about clock cycle calculations: https://wiki.neogeodev.org/index.php?title=68k_instructions_timings

from a "line of code" stand point they're the same but it seems some instructions are more efficient than others and your data source/destination can have an effect too.
 
Already said i'd check it on the weekend, it's not saturday yet have some patience
I don't want someone to do it for me, I'd like to figure it out myself. :P I'm doing this as much for the learning experience as anything else.

as you can see I've got two potential solutions worked out, just looking for feedback from a conceptual standpoint.
 
depending on the chip, you may only be able to read the register, it may even clear itself after the read.
i would copy both bytes to ram,
then use a combination of masking , shifting and adding to shuffle the nibbbles around.
then point the gamecode at the ram bytes
 
Thanks, I dumped the game assembly out of MAME and I've manged to find corresponding hex values for all of the instructions I want to execute in "idea #2"; essentially manually compiling it. I'm sure there's a better way but my tool set at the moment is just mame debugger and a hex editor; ie: banging two rocks together. So I'll be testing that out first and see how it goes. :D

I also found this wiki entry talking about clock cycle calculations: https://wiki.neogeodev.org/index.php?title=68k_instructions_timings

from a "line of code" stand point they're the same but it seems some instructions are more efficient than others and your data source/destination can have an effect too.
All you need is MAME, a hex editor and an assembler and you're all set. For the assembler, Easy68k is a decent option.

Don't get too bogged down in the details as far as optimising your code. For a learning experience like this, trial and error plus some patience is the way to go.
 
Not so noob, you have interesting ideas and a good understanding of the mecanism and logic behind assembly.

I would copy 30000f to 100000 and 300005 to 100001 to obtain word ABCD
Then rotate left by 4 bits the word @100000 giving BCDA
Rotate left (or right) the byte @100000 by 4 bits giving CB
Lastly rotating right the word @100000 by 4 bits giving ACBD

No need to use D0 or any other temporary memory location. And to answer your question it's safe to use a data register if it's overwritten downstream without any move in between.

3 extra instructions executed I guess every frame, that's nothing.
 
Last edited by a moderator:
ah, I didn't realize there was a rotate command! thanks for the advice :)
 
I don't want someone to do it for me, I'd like to figure it out myself. :P I'm doing this as much for the learning experience as anything else.
as you can see I've got two potential solutions worked out, just looking for feedback from a conceptual standpoint.
Go for it!

is just mame debugger and a hex editor; ie: banging two rocks together. So I'll be testing that out first and see how it goes. :D
Find a opcode list somewhere and make your own commands up. There's lots on the 68k, there will be websites with opcode examples and good explanations.
or find a generator but can't always get them but there's some out there for 68k.

EDIT, a nice list of opcodes: http://info.sonicretro.org/SCHG:68000_ASM-to-Hex_Code_Reference

There's 100 ways to do it, you know the way, just jump out, mess about, jump back (and don't forget to tidy up the ram / stack / registers).

For a learning experience like this, trial and error plus some patience is the way to go.
Basically this, you know what to do! just have a go.
 
Already said i'd check it on the weekend, it's not saturday yet have some patience
I don't want someone to do it for me, I'd like to figure it out myself. :P I'm doing this as much for the learning experience as anything else.
as you can see I've got two potential solutions worked out, just looking for feedback from a conceptual standpoint.
I'm looking into 68k assembly but for different reasons (hook the gun inputs for Teraburst in MAME). I will edit this post sometime later so I can reflect what is going on Teraburst's I/O 68k program.

Code:
000060: 0000 098C                ori.b   #$8c, D0; IRQ0
000064: 0000 0992                ori.b   #$92, D0; IRQ1
000068: 0000 0760                ori.b   #$60, D0; IRQ2
00006C: 0000 0766                ori.b   #$66, D0; IRQ3
000070: 0000 076C                ori.b   #$6c, D0; IRQ4
000074: 0000 089C                ori.b   #$9c, D0; IRQ5
000078: 0000 0932                ori.b   #$32, D0; IRQ6
00007C: 0000 0998                ori.b   #$98, D0; IRQ7
IRQ 4
Code:
00076C: 48E7 0070                movem.l A1-A3, -(A7)
000770: 267C 0030 0000           movea.l #$300000, A3
000776: 082B 0006 000F           btst    #$6, ($f,A3)
00077C: 6600 0012                bne     $790
000780: 082B 0007 000F           btst    #$7, ($f,A3)
000786: 6600 008E                bne     $816
00078A: 4CDF 0E00                movem.l (A7)+, A1-A3
00078E: 4E73                     rte
000790: 5279 0020 202E           addq.w  #1, $20202e.l
000796: 0839 0000 0020 202F      btst    #$0, $20202f.l
00079E: 6700 006A                beq     $80a
0007A2: 0279 0001 0020 2186      andi.w  #$1, $202186.l
0007AA: 6600 005E                bne     $80a
0007AE: 227C 0020 2026           movea.l #$202026, A1
0007B4: 247C 0020 2020           movea.l #$202020, A2
0007BA: 0C79 0001 0020 2024      cmpi.w  #$1, $202024.l
0007C2: 6600 0026                bne     $7ea
0007C6: 33FC 0000 0020 2024      move.w  #$0, $202024.l
0007CE: 24BC 0020 0000           move.l  #$200000, (A2)
0007D4: 33D1 0020 2028           move.w  (A1), $202028.l
0007DA: 32BC 0000                move.w  #$0, (A1)
0007DE: 33FC 0001 0020 2186      move.w  #$1, $202186.l
0007E6: 6000 0022                bra     $80a
0007EA: 33FC 0001 0020 2024      move.w  #$1, $202024.l
0007F2: 24BC 0020 0800           move.l  #$200800, (A2)
0007F8: 33D1 0020 2028           move.w  (A1), $202028.l
0007FE: 32BC 0000                move.w  #$0, (A1)
000802: 33FC 0001 0020 2186      move.w  #$1, $202186.l
00080A: 377C 0000 0004           move.w  #$0, ($4,A3)
000810: 4CDF 0E00                movem.l (A7)+, A1-A3
000814: 4E73                     rte
000816: 5279 0020 2060           addq.w  #1, $202060.l
00081C: 0839 0000 0020 2061      btst    #$0, $202061.l
000824: 6700 006A                beq     $890
000828: 0279 0001 0020 2188      andi.w  #$1, $202188.l
000830: 6600 005E                bne     $890
000834: 227C 0020 2058           movea.l #$202058, A1
00083A: 247C 0020 2052           movea.l #$202052, A2
000840: 0C79 0001 0020 2056      cmpi.w  #$1, $202056.l
000848: 6600 0026                bne     $870
00084C: 33FC 0000 0020 2056      move.w  #$0, $202056.l
000854: 24BC 0020 1000           move.l  #$201000, (A2)
00085A: 33D1 0020 205A           move.w  (A1), $20205a.l
000860: 32BC 0000                move.w  #$0, (A1)
000864: 33FC 0001 0020 2188      move.w  #$1, $202188.l
00086C: 6000 0022                bra     $890
000870: 33FC 0001 0020 2056      move.w  #$1, $202056.l
000878: 24BC 0020 1800           move.l  #$201800, (A2)
00087E: 33D1 0020 205A           move.w  (A1), $20205a.l
000884: 32BC 0000                move.w  #$0, (A1)
000888: 33FC 0001 0020 2188      move.w  #$1, $202188.l
000890: 377C 0000 0006           move.w  #$0, ($6,A3)
000896: 4CDF 0E00                movem.l (A7)+, A1-A3
00089A: 4E73                     rte
IRQ 5
Code:
00089C: 48E7 0078                movem.l A1-A4, -(A7)
0008A0: 267C 0030 0000           movea.l #$300000, A3
0008A6: 082B 0004 000F           btst    #$4, ($f,A3)
0008AC: 6600 0012                bne     $8c0
0008B0: 082B 0005 000F           btst    #$5, ($f,A3)
0008B6: 6600 0040                bne     $8f8
0008BA: 4CDF 1E00                movem.l (A7)+, A1-A4
0008BE: 4E73                     rte
0008C0: 227C 0020 2026           movea.l #$202026, A1
0008C6: 247C 0020 2020           movea.l #$202020, A2
0008CC: 0C51 0100                cmpi.w  #$100, (A1)
0008D0: 6500 000E                bcs     $8e0
0008D4: 377C 0000 000C           move.w  #$0, ($c,A3)
0008DA: 4CDF 1E00                movem.l (A7)+, A1-A4
0008DE: 4E73                     rte
0008E0: 2852                     movea.l (A2), A4
0008E2: 28D3                     move.l  (A3), (A4)+
0008E4: 38AB 0004                move.w  ($4,A3), (A4)
0008E8: 5251                     addq.w  #1, (A1)
0008EA: 5092                     addq.l  #8, (A2)
0008EC: 377C 0000 000C           move.w  #$0, ($c,A3)
0008F2: 4CDF 1E00                movem.l (A7)+, A1-A4
0008F6: 4E73                     rte
0008F8: 227C 0020 2058           movea.l #$202058, A1
0008FE: 247C 0020 2052           movea.l #$202052, A2
000904: 0C51 0100                cmpi.w  #$100, (A1)
000908: 6500 000E                bcs     $918
00090C: 377C 0000 000E           move.w  #$0, ($e,A3)
000912: 4CDF 1E00                movem.l (A7)+, A1-A4
000916: 4E73                     rte
000918: 2852                     movea.l (A2), A4
00091A: 28EB 0006                move.l  ($6,A3), (A4)+
00091E: 38AB 000A                move.w  ($a,A3), (A4)
000922: 5251                     addq.w  #1, (A1)
000924: 5092                     addq.l  #8, (A2)
000926: 377C 0000 000E           move.w  #$0, ($e,A3)
00092C: 4CDF 1E00                movem.l (A7)+, A1-A4
000930: 4E73                     rte
000932: 6100 1C46                bsr     $257a
000936: 4E73                     rte
Something?
Code:
00257A: 4E56 0000                link    A6, #$0
00257E: 48E7 F078                movem.l D0-D3/A1-A4, -(A7)
002582: 47F9 0020 2180           lea     $202180.l, A3
002588: 45F9 0020 2170           lea     $202170.l, A2
00258E: 227C 0040 0000           movea.l #$400000, A1
002594: 223C 0000 0080           move.l  #$80, D1
00259A: 4EB9 0000 253C           jsr     $253c.l
0025A0: 5279 0020 217E           addq.w  #1, $20217e.l
0025A6: 3011                     move.w  (A1), D0
0025A8: 3400                     move.w  D0, D2
0025AA: 0242 000F                andi.w  #$f, D2
0025AE: 7600                     moveq   #$0, D3
0025B0: 3602                     move.w  D2, D3
0025B2: 7401                     moveq   #$1, D2
0025B4: B682                     cmp.l   D2, D3
0025B6: 6D00 01CA                blt     $2782
0025BA: 7405                     moveq   #$5, D2
0025BC: B682                     cmp.l   D2, D3
0025BE: 6E00 01C2                bgt     $2782
0025C2: 5383                     subq.l  #1, D3
0025C4: E583                     asl.l   #2, D3
0025C6: 287B 3804                movea.l ($4,PC,D3.l), A4
0025CA: 4ED4                     jmp     (A4)
 
Last edited:
I would copy 30000f to 100000 and 300005 to 100001 to obtain word ABCD
Then rotate left by 4 bits the word @100000 giving BCDA
Rotate left (or right) the byte @100000 by 4 bits giving CB
Lastly rotating right the word @100000 by 4 bits giving ACBD

No need to use D0 or any other temporary memory location. And to answer your question it's safe to use a data register if it's overwritten downstream without any move in between.
What a rabit hole!

Playing around with ROR and ROL commands it seems that they only work with absolute addresses if you're rotating by word, and then only 1 bit at a time. So unfortunately this method still requires using D0 or another temp holding location.

For the assembler, Easy68k is a decent option.
I'm really liking easy68k is really great, if nothing else it's helps me troubleshoot syntax and convert to hex without any fuss.


basically we need to do this
#read value 0xAB from 0x30000F
#read value 0xCD from 0x300005

#write value 0xACBD to 0x100000
I've discovered I was wrong about the swap order it's actually
ABCD -> DBCA

so I ended up with the following:
Code:
move.b  $30000F.l, D0  ; ??AB
andi.w  #$FF, D0       ; 00AB
ror.w   #4, D0         ; B00A
lsl.b   #4, D0         ; B0A0
ror.w   #4, D0         ; 0B0A
move.w  D0, (-$8000,A5); move to memory
move.b  $300005.l, D0  ; 0BCD
ror.w   #4, D0         ; D0BC
lsl.b   #4, D0         ; D0C0
or.w    D0, (-$8000,A5); OR with memory
jmp     $10F2A.l
the next use of D0 when this code runs is overwriting the lower word with data from another address so there's no worry about leaving data in there.


I did find however that occasionally there is junk left in D0 before I run this, so that's why I needed to run the "andi.w #$FF, D0" so it clears out any residual data.

works in mame... works on hardware and now it's 100%

thanks for the advice and kind words everyone :D
 
Back
Top