It is currently Wed Dec 13, 2017 3:35 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Wed Nov 22, 2017 6:11 pm 
Offline

Joined: Wed Mar 23, 2016 12:27 pm
Posts: 17
Hi,

How can we make Battletoads read input from the Famicom expansion port, for player 1 and player 2? Neither P1 or P2 work, only the hard-wired controllers.

Surprisingly battletoads Japan doesn't work with the exp port either.

I can test hacks on my Everdrive using my Famicom Hori arcade stick that can switch between Player 1/Player 2.

Player 2 mode works on Mario Bros 1 and Mario Bros 3, but did not work on Battletoads or Mario Bros 2 (player 1 does not work for either of these as well).

Here is all I could pull from the USA game. This is the routine that handles reading the controls I think? I got this when setting a breakpoint for #$40 (B Button) on $0029. When I was monitoring the RAM, with each button press I was seeing $0029 get changed.

I didn't really understand much. Before this routine there is an AND #$40 which seems to impact the controls if changed to #$80 or #$10, etc.

Code:
00:8D78:A2 01        LDX #$01
 00:8D7A:8E 16 40  STX $4016 = #$FF
 00:8D7D:CA           DEX
 00:8D7E:8E 16 40  STX $4016 = #$FF
 00:8D81:A2 08       LDX #$08
 00:8D83:AD 16 40  LDA $4016 = #$FF
 00:8D86:6A          ROR
 00:8D87:26 15     ROL $0015 = #$00
 00:8D89:AD 17 40  LDA $4017 = #$FF
 00:8D8C:6A        ROR
 00:8D8D:26 16     ROL $0016 = #$00
 00:8D8F:CA        DEX
 00:8D90:D0 F1     BNE $8D83
 00:8D92:A5 15     LDA $0015 = #$00
 00:8D94:AA        TAX
 00:8D95:45 29     EOR $0029 = #$40
>00:8D97:86 29     STX $0029 = #$40
 00:8D99:25 15     AND $0015 = #$00
 00:8D9B:85 2B     STA $002B = #$40
 00:8D9D:A5 16     LDA $0016 = #$00
 00:8D9F:AA        TAX
 00:8DA0:45 2A     EOR $002A = #$00
 00:8DA2:86 2A     STX $002A = #$00
 00:8DA4:25 16     AND $0016 = #$00
 00:8DA6:85 2C     STA $002C = #$00
 00:8DA8:60        RTS -----------------------------------------


Top
 Profile  
 
PostPosted: Wed Nov 22, 2017 7:02 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19341
Location: NE Indiana, USA (NTSC)
Each ROR instruction at $8D86 and $8D8C needs to be replaced with these two instructions
Code:
AND #$03  ; A = 1 for hardwired, 2 for expansion, 0 for neither
CMP #$01  ; C = 1 iff this button on either controller is pressed


Unfortunately, each of these adds 3 bytes to the routine for a total of 6 bytes. My first recommendation would be to eliminate X using a ring counter, but that'd only save one byte. But I can reclaim a few more bytes by turning the next part, a calculation of which buttons on each controller are newly pressed this frame, into a loop:
Code:
P1 = $4016
P2 = $4017
cur_keys  = $15
last_keys = $29
new_keys  = $2B

.proc read_pads
  ldx #$01
  stx P1
  lda #$00        ; Use A for this because X=1 is needed later
  sta P1
  stx cur_keys+1  ; Once the 1 gets shifted into carry we're done
padbitloop:
  lda P1
  and #$03        ; A = 1 for hardwired, 2 for expansion, 0 for neither
  cmp #$01        ; C = 1 for some press, 0 for none
  rol cur_keys+0
  lda P2
  and #$03
  cmp #$01
  rol cur_keys+1  ; On eighth ROL, carry becomes set
  ; no DEX needed because cur_keys is our loop counter
  bcc padbitloop

  ; Because the above expanded by 6 bytes, compensate by eliminating
  ; the unrolling of last_keys and new_keys calculation
  ; (from 22 bytes to 15)
  ; X is still 1 from the above
fill_new_keys:
  lda last_keys,x  ; A = keys held last frame
  eor #$FF       ; A = keys NOT held last frame
  and cur_keys,x   ; A = keys held this frame but not last frame
  sta new_keys,x
  lda cur_keys,x
  sta last_keys,x
  dex
  bpl fill_new_keys

  ; Gained enough for it to fit
  rts
.endproc

I hope this isn't called in any cycle-timed portions of the game, as it probably won't take the same number of cycles.


Top
 Profile  
 
PostPosted: Wed Nov 22, 2017 7:06 pm 
Offline

Joined: Wed Mar 23, 2016 12:27 pm
Posts: 17
tepples wrote:
Each ROR instruction at $8D86 and $8D8C needs to be replaced with these two instructions
Code:
AND #$03  ; A = 1 for hardwired, 2 for expansion, 0 for neither
CMP #$01  ; C = 1 iff this button on either controller is pressed


Unfortunately, each of these adds 3 bytes to the routine for a total of 6 bytes. My first recommendation would be to eliminate X using a ring counter, but that'd only save one byte. But I can reclaim a few more bytes by turning the next part, a calculation of which buttons on each controller are newly pressed this frame, into a loop:
Code:
P1 = $4016
P2 = $4017
cur_keys  = $15
last_keys = $29
new_keys  = $2B

.proc read_pads
  ldx #$01
  stx P1
  lda #$00        ; Use A for this because X=1 is needed later
  sta P1
  stx cur_keys+1  ; Once the 1 gets shifted into carry we're done
padbitloop:
  lda P1
  and #$03        ; A = 1 for hardwired, 2 for expansion, 0 for neither
  cmp #$01        ; C = 1 for some press, 0 for none
  rol cur_keys+0
  lda P2
  and #$03
  cmp #$01
  rol cur_keys+1  ; On eighth ROL, carry becomes set
  ; no DEX needed because cur_keys is our loop counter
  bcc padbitloop

  ; Because the above expanded by 6 bytes, compensate by eliminating
  ; the unrolling of last_keys and new_keys calculation
  ; (from 22 bytes to 15)
  ; X is still 1 from the above
fill_new_keys:
  lda last_keys,x
  eor #$FF
  and cur_keys,x
  sta new_keys,x
  lda cur_keys,x
  sta last_keys,x
  dex
  bpl fill_new_keys

  ; Gained enough for it to fit
  rts
.endproc


Can we JSR to unused space (stream of FFs maybe?) and replace some of the code so that we can fit those 3 extra bytes?

$9470 has a lot of FF entries it looks like.

Maybe JSR $9470 where ROR occurs which would also replace the ROL $0015 (26, 15).

Then when we jump, we do

AND #$03
CMP #$01
ROL $0015
RTS


Top
 Profile  
 
PostPosted: Wed Nov 22, 2017 7:21 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
Long strings of $00 or $FF aren't always unused space, they may very well be the high byte portion of look-up tables containing lots of values between -256 and -1, or 0 and 255. Always use a code/data logger to be sure of what's actually unused.


Top
 Profile  
 
PostPosted: Wed Nov 22, 2017 7:29 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19341
Location: NE Indiana, USA (NTSC)
JSR/RTS would add even more cycles than the size optimization that I did find (turning $2B/$2C computation into a loop). Try it; it should fit.


Top
 Profile  
 
PostPosted: Wed Nov 22, 2017 7:29 pm 
Offline

Joined: Wed Mar 23, 2016 12:27 pm
Posts: 17
ReverendSA wrote:

Can we JSR to unused space (stream of FFs maybe?) and replace some of the code so that we can fit those 3 extra bytes?

$9470 has a lot of FF entries it looks like.

Maybe JSR $9470 where ROR occurs which would also replace the ROL $0015 (26, 15).

Then when we jump, we do

AND #$03
CMP #$01
ROL $0015
RTS


Here is my proposed modified routine (Psuedo):

Code:
 
LDX #$01
STX $4016
DEX
STX $4016
LDX #$08
LDA $4016
JSR $9470 <--- Changed
LDA $4017
JSR $9480 <--- Changed
DEX
BNE $8D83
LDA $0015
TAX
EOR $0029
STX $0029
AND $0015
STA $002B
LDA $0016
TAX
EOR $002A
STX $002A
AND $0016
STA $002C
RTS


At $9470

Code:
AND #$03
CMP #$01
ROL $0015
RTS


At $9480
Code:
AND #$03
CMP #$01
ROL $0016
RTS


Top
 Profile  
 
PostPosted: Wed Nov 22, 2017 7:31 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19341
Location: NE Indiana, USA (NTSC)
Let me restate what I wrote one more time:

You probably will not need to move things out to $9470 and $9480. Though I made the first part of the routine longer, I made the second part shorter to compensate.


Top
 Profile  
 
PostPosted: Wed Nov 22, 2017 7:50 pm 
Offline

Joined: Wed Mar 23, 2016 12:27 pm
Posts: 17
tepples wrote:
Let me restate what I wrote one more time:

You probably will not need to move things out to $9470 and $9480. Though I made the first part of the routine longer, I made the second part shorter to compensate.


Here is what I have based on your post, to replace the entire routine.

But for BCC and BPL, I do not understand. Your code said BCC padbitloop, but for BCC all I could see was $90. I don't know if it takes arguments, or works automatically.

A2 01
8E 16 40
A9 00
8D 16 40
86 16
AD 16 40
29 03
C9 01
26 15
AD 17 40
29 03
C9 01
26 16
90
B5 29
49 FF
35 15
95 15
B5 15
95 29
CA
10
60


Edit:

Okay, I think the byte next to Branches is FF - X, X being whichever byte you put in there. I revised the above:

A2 01
8E 16 40
A9 00
8D 16 40
86 16
AD 16 40
29 03
C9 01
26 15
AD 17 40
29 03
C9 01
26 16
90 EC
B5 29
49 FF
35 15
95 15
B5 15
95 29
CA
10 F1
60

90 E7 should take us back to AD 16 40 (lda P1; padbitloop).

10 EC should take us back 13 bytes, to B5 29 (lda last_keys,x; fillnewkeys).


Top
 Profile  
 
PostPosted: Wed Nov 22, 2017 9:28 pm 
Offline

Joined: Wed Mar 23, 2016 12:27 pm
Posts: 17
tepples wrote:
Let me restate what I wrote one more time:

You probably will not need to move things out to $9470 and $9480. Though I made the first part of the routine longer, I made the second part shorter to compensate.


For some reason though, pushing the keys does nothing at all. The game is still running though.

I've implemented it as you wrote it (I hope). Here is what FCEUX shows:

00:8D78:A2 01 LDX #$01
00:8D7A:8E 16 40 STX $4016 = #$FF
00:8D7D:A9 00 LDA #$00
00:8D7F:8D 16 40 STA $4016 = #$FF
00:8D82:86 16 STX $0016 = #$FF
00:8D84:AD 16 40 LDA $4016 = #$FF
00:8D87:29 03 AND #$03
00:8D89:C9 01 CMP #$01
00:8D8B:26 15 ROL $0015 = #$00
00:8D8D:AD 17 40 LDA $4017 = #$FF
00:8D90:29 03 AND #$03
00:8D92:C9 01 CMP #$01
00:8D94:26 16 ROL $0016 = #$FF
00:8D96:90 EC BCC $8D84
00:8D98:B5 29 LDA $29,X @ $002B = #$00
00:8D9A:49 FF EOR #$FF
00:8D9C:35 15 AND $15,X @ $0017 = #$55
00:8D9E:95 15 STA $15,X @ $0017 = #$55
00:8DA0:B5 15 LDA $15,X @ $0017 = #$55
00:8DA2:95 29 STA $29,X @ $002B = #$00
00:8DA4:CA DEX
00:8DA5:10 F1 BPL $8D98
00:8DA7:60 RTS ---------------------------------------


Top
 Profile  
 
PostPosted: Wed Nov 22, 2017 9:30 pm 
Offline

Joined: Wed Mar 23, 2016 12:27 pm
Posts: 17
ReverendSA wrote:
tepples wrote:
Let me restate what I wrote one more time:

You probably will not need to move things out to $9470 and $9480. Though I made the first part of the routine longer, I made the second part shorter to compensate.


For some reason though, pushing the keys does nothing at all. The game is still running though.

I've implemented it as you wrote it (I hope). Here is what FCEUX shows:

00:8D78:A2 01 LDX #$01
00:8D7A:8E 16 40 STX $4016 = #$FF
00:8D7D:A9 00 LDA #$00
00:8D7F:8D 16 40 STA $4016 = #$FF
00:8D82:86 16 STX $0016 = #$FF
00:8D84:AD 16 40 LDA $4016 = #$FF
00:8D87:29 03 AND #$03
00:8D89:C9 01 CMP #$01
00:8D8B:26 15 ROL $0015 = #$00
00:8D8D:AD 17 40 LDA $4017 = #$FF
00:8D90:29 03 AND #$03
00:8D92:C9 01 CMP #$01
00:8D94:26 16 ROL $0016 = #$FF
00:8D96:90 EC BCC $8D84
00:8D98:B5 29 LDA $29,X @ $002B = #$00
00:8D9A:49 FF EOR #$FF
00:8D9C:35 15 AND $15,X @ $0017 = #$55
00:8D9E:95 15 STA $15,X @ $0017 = #$55
00:8DA0:B5 15 LDA $15,X @ $0017 = #$55
00:8DA2:95 29 STA $29,X @ $002B = #$00
00:8DA4:CA DEX
00:8DA5:10 F1 BPL $8D98
00:8DA7:60 RTS ---------------------------------------



Oh, my bad!

I was storing storing #$15 at 8D9E when I should have stored #$2B according to your code.

I changed it to #$2B and now my character can jump and punch!! I'm going to test this on my ED and report back.


Top
 Profile  
 
PostPosted: Wed Nov 22, 2017 9:34 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5896
Location: Canada
Just in case it helps, in FCEUX's debugger if you left click in the grey column just to the left of the disassembly, you can use its built-in assembler to type a patch in assembly instead of trying to convert everything to hex.

There are no labels in this assembler, but you type the target address for branches, e.g. "BCC $8D96" will create a branch instruction with the correct relative value to get to $8D96.


Top
 Profile  
 
PostPosted: Wed Nov 22, 2017 9:47 pm 
Offline

Joined: Wed Mar 23, 2016 12:27 pm
Posts: 17
Okay.

It works, holy crap.

Even more surprising, the hack allows player 2 to join via pushing start. I thought start was not applicable for player 2 on Famicom.

That's insane.

Thanks a lot tepples.

My friend and I have been meaning to play Battletoads USA on my famicom since forever and now we can do it.


Top
 Profile  
 
PostPosted: Wed Nov 22, 2017 10:10 pm 
Offline

Joined: Wed Mar 23, 2016 12:27 pm
Posts: 17
rainwarrior wrote:
Just in case it helps, in FCEUX's debugger if you left click in the grey column just to the left of the disassembly, you can use its built-in assembler to type a patch in assembly instead of trying to convert everything to hex.

There are no labels in this assembler, but you type the target address for branches, e.g. "BCC $8D96" will create a branch instruction with the correct relative value to get to $8D96.


Thanks for that info. Would have saved me an extra hour when I was trying to learn branches. The labels were confusing me for a bit.

I'm going to publish this hack as it may very well help others such as myself. I will credit you for your help Tepples.


Top
 Profile  
 
PostPosted: Wed Nov 22, 2017 10:15 pm 
Offline
User avatar

Joined: Sun Dec 12, 2010 10:27 pm
Posts: 298
Location: Hong Kong
ReverendSA wrote:
Okay.
Even more surprising, the hack allows player 2 to join via pushing start. I thought start was not applicable for player 2 on Famicom.

I think it's possible that all the codes for P2 joining in with START are intact, just that the hardwired P2 pad does not have a physical START button so that you can never use this feature, so if you hack the game to recognise inputs from expansion port the START button on the extra P2 controller will work as intended. It may even be possible that if you modify the console by changing the hardwired P2 pad to some other controllers the START button may work too.


Top
 Profile  
 
PostPosted: Thu Nov 23, 2017 8:26 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 10:59 pm
Posts: 1393
Gilbert wrote:
ReverendSA wrote:
Okay.
Even more surprising, the hack allows player 2 to join via pushing start. I thought start was not applicable for player 2 on Famicom.

I think it's possible that all the codes for P2 joining in with START are intact, just that the hardwired P2 pad does not have a physical START button so that you can never use this feature, so if you hack the game to recognise inputs from expansion port the START button on the extra P2 controller will work as intended. It may even be possible that if you modify the console by changing the hardwired P2 pad to some other controllers the START button may work too.

It would also work properly on an AV Famicom, which uses standard 7-pin NES controllers (which both have Select/Start buttons) instead of the hardwired ones.

_________________
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: Bing [Bot], lazygecko and 7 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group