Famicom Network System (aka Famicom Modem) Investigations

Discuss hardware-related topics, such as development cartridges, CopyNES, PowerPak, EPROMs, or whatever.

Moderator: Moderators

User avatar
Ben Boldt
Posts: 1148
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Ben Boldt »

I got my original 5A18 running on a breakout board today. I attached the crystal and its asociated resistors and caps, and also put a 10k pull-up on pin 27 to get it running. I wired up a ZIF connector for the ROM chip in place of the RAM. When I fired it up, I found it fetching the reset vector and executing (and also each time I GND and release pin 27), but not following through to my ROM stack trick. I was looking only at the address bus, and I noticed that the spot where I expected an INC instruction as part of the RAM clearing loop wasn't going out and grabbing and incrementing something from "RAM" address space. I think it is possible that this one has a different ROM revision. I think I will need to go back with this one and do that byte-by-byte dump again and see what is different about the code in this one and modify my approach (if possible).

I also found that M2 was not the same pin that I thought it was before. This is likely to be an error that I made. M2 is not the pin shown in the wiki presently. I will have to figure out what went wrong with that.

Once this new setup is up and running, I will be able to access all pins directly to identify port bits. The ZIF will also make it much easier to do lots of ROM tweaks and try these experiments with runaway branches.
User avatar
Ben Boldt
Posts: 1148
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Ben Boldt »

I did get my standalone 5A18 running tonight after a lot of messing around. I realized that the built-in ROM is not initializing the stack pointer, so I am actually getting a different default spot in the stack from the first JSR/RTS. It is consistently located at $01FC/01FD on this chip. I found no difference in the first small bit of ROM when debugging this, but have not re-dumped this ROM to compare the whole thing.

I was also experiencing an IRQ as soon as it entered my custom ROM after fetching the very first instruction LDA #$00. I don't know why it happened right then, it seems more than a bit coincidental... There are a lot of cycles spent clearing RAM before it gets to my code. Anyway, I put an SEI instruction right at the beginning and it luckily took care of that. I do not know what was causing that and I have not yet witnessed an NMI.

To find register bits that control output pins, I ran this program:

Code: Select all

main_loop:
    lda $0000  ; Scope Trigger
    ldx #$00
reg_loop:
    lda #$00
    sec
bit_loop:
    rol
    sta $4100,X
    bne bit_loop
    inx
    cpx #$40
    bmi reg_loop
    jmp main_loop
I then touched an analog scope probe to each possible output pin, and had the scope trigger to that probe. If it triggered, it would show the register address LSB and data written to the register, and I was able to use that to find exactly what caused the toggle.

Next was reading pins. For this, I used a microswitch (aka limit switch) with a big easy to press lever. I connected the common through a 1k resistor to a wire that I could poke each pin easily with. The other terminals of the microswitch were 5V and GND. I then just connected and clicked it a bunch, triggering the scope on different registers to see if the data bus followed my switch. Here is the code I ran for register reads:

Code: Select all

main_read_loop:
    lda $0000  ; Scope Trigger
    lda $4100
    lda $4101
    lda $4102
    lda $4103
    lda $4104
    lda $4105
    lda $4106
    lda $4107
    lda $4108
    lda $4109
    lda $410A
    lda $410B
    lda $410C
    lda $410D
    lda $410E
    lda $410F
    lda $4110
    lda $4111
    lda $4112
    lda $4113
    lda $4114
    lda $4115
    lda $4116
    lda $4117
    lda $4118
    lda $4119
    lda $411A
    lda $411B
    lda $411C
    lda $411D
    lda $411E
    lda $411F
    lda $4120
    lda $4121
    lda $4122
    lda $4123
    lda $4124
    lda $4125
    lda $4126
    lda $4127
    lda $4128
    lda $4129
    lda $412A
    lda $412B
    lda $412C
    lda $412D
    lda $412E
    lda $412F
    lda $4130
    lda $4131
    lda $4132
    lda $4133
    lda $4134
    lda $4135
    lda $4136
    lda $4137
    lda $4138
    lda $4139
    lda $413A
    lda $413B
    lda $413C
    lda $413D
    lda $413E
    lda $413F
    jmp main_read_loop
Edit:
One other thing I forgot about:
I found a /CE pin for that strange open-bus $4129 register. I saw it go low only when writing to that register, regardless of value written. I did not remember to check it when doing the read test.
User avatar
Ben Boldt
Posts: 1148
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Ben Boldt »

I have been playing with runaway branches and found a couple unexpected gotchas.

With $3F/$3F/$3F, basically:
BBR3, looks at bit 3 at memory $3F, if 0 jump forward $3F instructions

For that to work as we intended, I also must have a 3F at memory location 3F because that's a fetch the CPU will do and will re-establish it's internal open-bus with that value. Since value 3F does not have bit 3 = 0, it won't branch.


With $FF/$FF/$FF:
BBS7, looks at bit 7 of memory $FF, if 1, jump forward by $FF (i.e. -1) instructions.

So obviously a jump of only -1 won't give us the flexibility to jump directly to any particular register without stepping through all of the other ones. Since this is a 3-byte instruction, the program counter moves +3, then -1, so actually it is doing a +2 each iteration... Not too useful. It can maybe work for the first couple registers or something...


$BF/$BF/$BF:
BBS3, looks at bit 3 of memory $BF, if 1, jump forward by $BF (i.e. -65) instructions. I was actually successful with this one. I had to a pull-down on D6 and pull-ups on the rest of the data bits to generate $BF during open bus in the $C000-DFFF region. (I made a thing with DIP switches that let me put pull-ups and downs easily switchable.) And I had to hard-code a $BF at memory location $BF. I ran that jumping to $C000 and found the first read less than $4100, which was $26 bytes before $4100. So I knew my baseline jump address for hitting $4100 was $C026. So if I wanted to hit $4101, I would jump to $C027, etc.

As part of the BSS3 instruction, it actually grabs 4 consecutive bytes from memory, so I get $4100, $4101, $4102, $4103 all in 1 go. This is a great thing for 2 reasons:
  • If they're all $BF, 4 tests done in 1 go.
  • Some registers will change the value to $FF or something for example, leaving that value behind when reading the next one. This provides more combinations revealing more bits in several cases.
I chose $BF because it is very nearly the inverse of $41. I then went back and read each register with $40 (LDA $40FF,X style), and $41 again since this standalone setup is different. If we could trust that all bits remain the same (which we can't...), I have covered all bases with these tests. I would like to do the BF/BF/BF and 40 tests on the full system setup again, but that doesn't have a ZIF socket so it will be a rather tedious challenge physically.

I know people like to see setups to get a better idea what I am up to. Here is a photo. After I have done my time at work, I this is what happens at my bench deep into the night. :)

RF5A18_Setup.png
User avatar
Ben Boldt
Posts: 1148
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Ben Boldt »

I made a CPU2 test code today that writes unique values to each CPU2 register and then writes the complement of those values to each register in a loop. I then made a famicom card test code that clears $40B1.3 to start CPU2 running, then reads all $40Dx registers (i.e. the registers controlled by the RF5A18 on the Famicom CPU bus) and monitored with my logic analyzer. I noted the following about each register:

Read $40D0 -> Found matched exactly data written to CPU2 register $4123
Read $40D1 -> Found matched exactly data written to CPU2 register $4124
Read $40D2 -> Found matched exactly data written to CPU2 register $4125
Read $40D3 -> Found matched exactly data written to CPU2 register $4122, only bits 7,6,5 (other bits are open-bus, can follow pull-up / -down)
Read $40D4 -> Read always $07, no toggles
Read $40D5 -> Seemed to be very fast counter, I can see multiple counts carrying within the 1 cycle. (I probably never looked at this register ever before.)
Read $40D6 -> Controlled in non-obvious way by the value CPU2 wrote to $4113
Read $40D7 -> Found all bits open bus (All can follow pull-up / -down)

I didn't test $40D8-$40DF because the RF5A18 only has access to Famicom CPU D0,1,2 and not D3+. I should not try to make too many assumptions when doing these things but I can't see how that wouldn't just be mirrors without any D3 involved, though it does get its /CS decoded as any address $4xDx by the RF5C66, so there should be 256 mirrors of each register...


I have not yet tested anything the other direction, from the Famicom writing to $40Dx and CPU2 receiving it in its $41xx registers. I also have not tested if the famicom writes a value, then reads back, if it is the same value that it wrote. If so, it would suggest that these registers are dual-port, one side Famicom, other side CPU2, but the same physical register. I am not sure how that would be arbitrated if that is true. The Famicom and CPU2 are asynchronous (i.e. don't share a common clock). It may be up to the software to properly follow a sequence of acknowledges to prevent race conditions.


Edit:
so there should be 256 mirrors of each register...
Correction: There should be 256 total addresses that the RF5A18 responds to via its /CS being activated with $4xDx, a total of 8 bits. Since only 3 of those bits are directly available to the RF5A18 for decoding which register is talking, that leaves 8-3 = 5 bits ignored. So 2^5 = 32 mirrors each register.

Looking at it from a different angle, since only 3 address bits are connected to the RF5A18, there are only 2^3 = 8 possible registers. Since /CS is active for 2^8 = 256 registers, the number of mirrors each register would be 256/8 = 32.
User avatar
Ben Boldt
Posts: 1148
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Ben Boldt »

For these cross-over registers between Famicom CPU and CPU2:

Famicom <-> CPU2
$40D0 <-> $4123 (Data byte 0)
$40D1 <-> $4124 (Data byte 1)
$40D2 <-> $4125 (Data byte 2)
$40D3 <-> $4122 (Acknowledge bits)

They are unique in each direction. If the Famicom CPU writes a value to $40D0, that will not be the value that it reads back. It only reads the value that the other CPU wrote. This means that each direction is physically a separate register and not 1 single dual-port register.
User avatar
Ben Boldt
Posts: 1148
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Ben Boldt »

I dug some more into the input pins of the RF5A18 (CPU2) chip. There are a number of pins that are tied directly to +5V or GND on the Famicom Modem PCB, and I replaced those connections with 10k pull-ups/ -downs, then tested those pins with my 1k microswitch clicker thing. I found several register bits corresponding to these pins this way. I found that pin 29 is /NMI input by clicking different pins and setting my scope to trigger on address $FFFA. I also found pin 26 is a +IRQ pin this way, triggering on address $FFFE. Both of these pins are configured on the PCB in such a way as to never generate interrupts. I updated these things in the wiki.

I also made come connections for testing the Famicom bus of the 5A18 chip. I set the following pins:
M2 input = 1
Card R/W (i.e. CPU R/W) input = 1
/CE (i.e. $4xDx register detection normally coming from RF5C66) input = 0

Then I connected CPU A2,A1,A0 = 100 for register $40D4. This made the value of register $40D4 appear in real-time statically on the data bus. I was able to use my clicker and found all 8 bits come from various pins of the RF5A18. The new ones discovered all came from the Tone Rx chip inside the modem module.

I then changed CPU A2,A1,A0 = 101 for $40D5, the register that has a fast counter. Here is what that looks like:


Show full period of all signals, with frequency measurements:
tek00106 freq.png

Zoom in:
tek00107 zoom 1.png

Zoom in more, note the strange phasing of these signals:
tek00108 zoom 2.png

This may be used for generating random numbers or something. Bits 6 and 7 always low in this test.
User avatar
Ben Boldt
Posts: 1148
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Ben Boldt »

Do any of you guys know much about the FDS serial out signal from the RAM adapter? I was looking at pin 79 on the RF5C66 which is putting out a constant 95.95kHz normally. I find that if I write a $44 to $40A3, pin 79 gives a different signal as follows:

tek00109.png

Note: "RAM /CE" is labeled wrong, this is the pin 79 "FDS-ish serial output data". And blue is Famicom M2...

2 wide gaps, 5 skinny gaps, loop. Not having written this $44, it is all skinny gaps normally. I am not sure what to make of it. Does this look familiar to anyone?

I wrote incrementing values to $40A3 and found a few different modes. I can get it where all the bits are wide bits when writing $E0 (previous value DF) or $68 (previous value $67). I can get a single wide bit all on its own when writing value $A2 (previous value A1) or $40 (previous value 3F). Writing just $40 doesn't make single wide bits happen though. The previous value apparently had to be $3F...

It certainly seems registers $40A0 - $40A8 are FDS registers. I wrote different values some of those registers (most notably $40A0 and $40A1) and found no different sequence on pin 79. But again, I am not too familiar with FDS. I noticed FDS has this I/O enable register $4023. However, all the suspected FDS I/O pins seems to function fine with no intervention.
Fiskbit
Posts: 890
Joined: Sat Nov 18, 2017 9:15 pm

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Fiskbit »

Not sure about the FDS' serial interface, but I've been wondering if the P5 connector with its 7-bit interface is intended to hook up to the FDS RAM adapter's external connector port, which is also 7-bit. The port appears to be used by the FDS version of Nomura no Famicom Trade.

Edit: I see that pin 79 goes to the expansion port. The Dataship 1200 allegedly has a setting for a printer to use this port rather than what I believe is its 14-pin Centronics port. Perhaps printer support could be related to what you're seeing here.
User avatar
Ben Boldt
Posts: 1148
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Ben Boldt »

It could certainly be that this port is multi-purpose. Everything I am looking at with the FDS stuff is the P3 port. The P5 port is controlled only by CPU2 so it is a little farther removed from that sort of stuff.

Referring to the FDS technical reference by Brad Taylor:

Code: Select all

Bit     v       v       v       v       v       v       v       v       v       v

Rate    ----____----____----____----____----____----____----____----____----____

Data    ----------------________________________--------________----------------


XOR     ____----____--------____----____----________--------________----____----

Disk    ____-_______-___________-_______-___________-_______________-_______-___


        time --->
Using this to decode 2 long, 5 short in a similar way:

Code: Select all

Bit     v       v       v       v       v       v       v       v       v

Rate    ----____----____----____----____----____----____----____----____---- ...

Data    ________________________________________________------------________ ...
        0       0       0       0       0       0       1       1       0...

XOR     ----____----____----____----____----____----________----________---- ...

Pin 79  _-------_-------_-------_-------_-------_-----------_-----------_--- ...


        time --->
This reveals an 8-bit data loop: 000000110000001100000011 (not sure how to tell the first bit in the loop). I don't have an FDS myself, but it seems strange that the default state is always sending serial data. Is this normal for FDS? I don't see anything in the FDS registers that starts or stops transmitting serial data.

In many of my experiments, I was writing $55 to various registers most of the time expecting to see some 10101010 type toggling (long-short-long-short), but referring to this diagram from Brad Taylor, I think 55 would be giving me all long pulses. So I might need to revisit how I was getting those long pulses and see if I can change it writing values other than $55 to other registers.
User avatar
Ben Boldt
Posts: 1148
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Ben Boldt »

A couple of quick updates on this.

Last I posted, I was looking at the disk drive support and kind of stopped that since then. I have shifted to working on disassembling the CPU2 built-in ROM. I am now using 6502bench SourceGen, as it supports this 65C02 processor with bitwise set/clear/branch instructions. It is actually a fantastic disassembler, I love it. I have been focused on the commands written to CPU2 via registers $40D0-40D3. I have some preliminary info about each possible command, such as all possible command bytes, the expected byte count, and the general structure of each command. This info sheds some light on the command sequences I captured and shared in this thread earlier. Since messages have to be sent in groups of 3 bytes, it reveals the last 1 or 2 bytes being garbage in some cases and answers a lot of the confusion about byte counts. The byte count is always only 1 byte in all cases. It is not ever a 16-bit byte count.

I do not yet know how CPU2 replies to the Famicom, but that will be an approachable problem because I can start with the known $4122-4125 registers and work my way backwards.

Another thing Fiskbit just reminded me of, we know that CPU2 /Reset is controlled by a different RF5C66 pin in old revision Famicom Network Systems. I updated the wiki to show both new and old register bits used for enabling CPU2 out of reset. These don't conflict, so both bits should be written to support both cases should anyone write some software for this thing. Not sure why Nintendo would have made that change. The old revision actually had jumpers where you could set it either way, but pre-populated to be different than new models that don't have the jumpers...

Another note, I had stated earlier somewhere in this thread that the stack pointer does not get initialized, based on my observation that I had to bodge my "ROM" stack differently to get it to return to my arbitrary code on a different RF5A18 chip. That was entirely incorrect because it actually does initialize it:

stack.PNG

So I am not sure what was happening there, seeing as how interrupts are disabled almost immediately with SEI. Maybe I am triggering an NMI somehow, or the code takes a different path based on input pins that I am not aware of?? But oh well, I got around it one way or another. Other than that, I have just been putting new stuff I find directly into the wiki lately. Keep those typo fixes coming lidnariq, it makes me happy someone is watching! :beer:
User avatar
Ben Boldt
Posts: 1148
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Ben Boldt »

I figured out how to generate passkeys for several of the commands that require them, and added to the wiki:

http://wiki.nesdev.com/w/index.php/Fami ... h_Passkeys

I use the term "decrypt" which I do not believe to be correct. This isn't jumbled up data that is being turned back to clear text data. Is there a better term for the steps taken to validate a passcode?
lidnariq
Posts: 11429
Joined: Sun Apr 13, 2008 11:12 am

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by lidnariq »

If it were real cryptography, that'd be a Message Authentication Code.

But I'd probably just call it a CRC, which it looks like it might be.
User avatar
Ben Boldt
Posts: 1148
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Ben Boldt »

I knew it wasn't an encryption but I never thought it might be a checksum/CRC, cool idea, makes perfect sense. It would be neat to boil that down to a CRC-16 polynomial, possibly a common one. I am not exactly sure how to do that at the moment.

I wrote a program that tries all possible values for key 0,1,2 and it comes up with lots of passing results. Not all values of key0 are possible in all cases, but it seems there is always 1 solution when key0 is 0.
User avatar
Ben Boldt
Posts: 1148
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Ben Boldt »

I seem to have located the revision of the RF5A18 internal ROM. The byte immediately preceding the vector table (i.e. address $FFF9) is $03. This byte gets sent in CPU2 command $03 along with a 16-bit checksum of the entire ROM that gets computed each time it boots up. I noticed on the RF5A18 chip itself, there is a 003 printed on it:
003.png

It makes sense that this is also the ROM revision. I have not come across one that is different than this. I have made at least 4 separate dumps of this chip, 3+ on 1 chip and 1 on another. They all match each other, so I am pretty sure I have a good rev 003 dump.

My question for you folks out there, do any of yours have a number printed on it other than 003?
User avatar
Ben Boldt
Posts: 1148
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Famicom Network System (aka Famicom Modem) Investigations

Post by Ben Boldt »

Looking at connect sequences of Okasan no Famicom Trade:

Connecting:
Okasan no Famicom Trade wrote:00 13 00 42 31 20 36 33 57 30 36 30 33 31 33 33 33 39 30 24 67 25 00 00
"...B1 63W0603133390$g%.."
Referring to the wiki for this message, the first byte means command $00:

Code: Select all

Message Bytes:
[$00] [count=N] [xx] [...N bytes...]
  • $00 = command code
  • $13 = Byte count
  • $00 = unused byte, not counted in byte count
  • 42 31 20 36 33 57 30 36 30 33 31 33 33 33 39 30 24 67 25 = "B1 63W0603133390$g%" = data bytes
  • $00 00 = unused padding at the end
I would theorize that the data is a command message to be sent to the Oki MSM6827L modem chip. I should put a bit more work translating that datasheet and maybe this message will make sense. The B1 at the beginning looks exactly like the Hayes modem command to put it into Bell 103 / 212A / 2400 mode, but the rest of the message doesn't seem to follow Hayes. That does appear to be the phone number that it would attempt to dial in the message. I don't have a clue about the space, "63W" or "$g%". But at least we know now how the byte count works for this message and which bytes are just fillers.

The response to this message (which I had not previously seen or shared before):
Okasan no Famicom Trade wrote:80 01 00 01
My guess would be:
  • $80 = response command code
  • $01 = Byte count
  • $00 = unused byte, not counted in byte count
  • $01 = "connection failure" or something.
So this is showing a command $80 coming back from CPU2 in response after the famicom sent command $00 to CPU2. From disassembling the CPU2 code, I already knew that command $03 generates response command $83 and command $12 generates response command $92. It stands to reason that the response command code is the original command code +$80. (i.e. set bit 7). I had not found a response $80 when disassembling yet, but there it is on my scope! It does it somehow.


When sending and receiving messages between the Famicom to CPU2, register $40D3 provides and accepts the acknowledge/ready flags, then 3 message bytes at a time are then provided or accepted sequentially using registers $40D0, 40D1, 40D2.

Writing a message from Famicom to CPU2:
  1. Read $40D3.
  2. Invert bit 7, set bit 7 low, and write it back to $40D3. (CPU2 will echo bit 7 when ready) Edit: I have to confirm what I meant with bit 7...
  3. Loop:
    1. Poll $40D3 until bit 7 matches the value written.
    2. Write 3 bytes data: Write $40D0, then $40D1, then $40D2.
    3. Invert bit 7 from last value written to $40D3 and write it to $40D3.
  4. Stop this process when the number of bytes indicated by the byte count have been written.
  5. Write $FF to $40D3 (bits 7,6,5 = 111)
  6. Poll $40D3 until bit 7 matches the value written.
  7. Write $FF to $40D3 again (bits 7,6,5 = 111)
  8. DONE
  9. All software observed always writes a multiple of 3 bytes, but I don't think that is necessary. (previous writes will just remain as artifacts in the registers if not written...)
Reading a message from CPU2 to Famicom:
  1. Read $40D3.
  2. Invert bit 7, probably do something with bits 6,5 (not observed), and write it back to $40D3. (CPU2 will echo bit 7 inverted when ready)
  3. Loop:
    1. Poll $40D3 until bit 7 is the opposite of the value written.
    2. Read 3 bytes data: Read $40D0, then $40D1, then $40D2.
    3. Invert bit 7 from last value written to $40D3 and write it to $40D3.
  4. Stop this process when the number of bytes indicated by the byte count have been read.
  5. Write $7F to $40D3 (bits 7,6,5 = 011)
  6. Poll $40D3 until bit 7 is the opposite of the value written.
  7. Write $FF to $40D3 (bits 7,6,5 = 111)
  8. DONE
  9. Observed Okasan no Famicom Trade stopped reading at the byte indicated by the byte count, without reading a full multiple of 3 bytes (notice the entire response message was 4 bytes, not reading 2 extra padding bytes at the end to make 6).

Edit:
Just another note on this: This particular 'game' did not write another command to disconnect after the response message. All the other ones I looked at before seemed to go so far as to write a disconnect command whenever it figured out that the connection failed, so this one is different in that way.
Post Reply