$4127.4 -> RF5A18.60 /Phone Off Hook
$4127.5 -> RF5A18.61 /DTMF Output Enable
$4127.6 -> RF5A18.62 /Phone Audio Enable (to TV speakers)
$4127.7 -> RF5A18.63 (Modem P4-19) still unknown, I have always seen this signal high when connecting with PiT and JRA-PAT.
For the RF5A18 input signals from the modem module, I was very surprised not to find a signal that reflected whether there is a dial tone or not. I did find that normalized audio from the phone line gets sent from the modem module into RF5A18 pin 55 when phone is off hook (only), which is also quite unexpected. My 400Hz dialtone being injected gets squashed due to off hook to -1.54V to -3.68V peak-to-peak, and pin 55 gets a signal normalized to 0.15V to 4.87V peak-to-peak. It is slightly phase delayed but not inverted.
That is the only path that I can find that could detect the dial tone. The signal going to pin 44 is a pretty digital looking signal; it could be that RF5A18 pin 55 is some sort of input capture and not necessarily anything fancy analog. If that is the route to dial tone detection, it must show up in a CPU2 $41xx register or Famicom $40Dx register somewhere. Given that CPU2 sends response command $80 with the status byte when the connection fails, it sure seems that CPU2 ought to be making the determination whether there is a dial tone or not, so I think that makes the $40Dx registers unlikely to be the only destination of the dial tone detection (and thus I didn't even look at those when testing.)
It is hard to snoop register reads for this because I am comparing something triggerable (disconnect), versus when it doesn't disconnect until later for different reason, so I don't know a good way to compare those. Also, since the dialing process takes ~5 seconds from when it takes the phone off hook to when it hangs back up, I don't know where to look and my scope just can't capture that much digital info all at once fine enough to decode it. I probably need to work at that from a different angle. I think it would be useful to know just exactly how it figures out if there is a dial tone or not.
The MSM6827L has a call-progress tone detector (bit 1 of DR) that can detect tones between 350Hz and 620Hz. I can't say for sure since I haven't looked through that part of the code yet, but I think that's how it detects the dial tone.
I'm curious what that DTMF output enable pin actually does. The MSM6827L can already generate DTMF signals without the help of external circuitry.
I based that on how the signal goes low exactly at the beginning the first number dialed and goes high exactly when finishing dialing the last number. And it does not do it in pulse mode. That could mean something else, that was just my best guess based on those observations.
I had attempted earlier to trace out the modem module with krzysiobal's awesome KrzysioPCB and I got to a point where I learned how to use the program better and really needed to start over... I was making progress making new parts but I ended up getting distracted with other stuff. I really need to spend some time removing all the SMT parts and measuring the ceramic caps, etc. This PCB is laid out in a way that makes it very difficult to see whether pads connect to traces or not. There are often holes in the PCB that aren't thru-holes but may or may not have a trace connecting across where that hole is... If I remove all those SMT and level everything off, I think it will make things much more clear and traceable. Luckily, the MSM6827L datasheet actually has some very similar example circuits, so that might help figure out how it works. (Though I was still totally clueless looking at that earlier as well.)
Also, my original idea about the signal that enabled the audio through to the TV speakers was incorrect; it ended up to be a different signal.
I added a theory:
19.6608MHz RF5A18 crystal / 2^14 = 1200Hz.
That ends up exactly 1200Hz that way.
And how do you measure the timings you provided, do you have a system running that you are measuring? I want to know your methods how you approached this.
Yes. Chosen for compatibility with standard RS232 rates. See https://en.wikipedia.org/wiki/Crystal_o ... requencies
I found the code for dialing numbers. For pulse dialing in particular, it expects a NMI each time it disconnects or reconnects the line, and it has lookup tables it uses to pick values to write to $4100/4101 after each disconnect or reconnect. These same lookup tables are also used for tone dialing each time it starts or stops a tone. When it disconnects the line, the number it chooses to write to $4100 is about twice as big as when it connects the line, and each pulse is supposed to have the line disconnected for about twice as long as the line is connected. It also has two sets of numbers for pulse dialing, depending on the position of SW1-2, which appeared to correspond with the standard 10 pulses per second and Japan's unusual 20 pulses per second.
In other words, it looked exactly like it was programming a timer interrupt.
The lookup tables are also used for tone dialing, so I worked out approximately how many tones it should dial in one second if my assumptions were correct and then compared with your video.
Cool.Joe wrote: ↑Tue Apr 06, 2021 7:30 pmI found the code for dialing numbers. For pulse dialing in particular, it expects a NMI each time it disconnects or reconnects the line, and it has lookup tables it uses to pick values to write to $4100/4101 after each disconnect or reconnect. These same lookup tables are also used for tone dialing each time it starts or stops a tone. When it disconnects the line, the number it chooses to write to $4100 is about twice as big as when it connects the line, and each pulse is supposed to have the line disconnected for about twice as long as the line is connected. It also has two sets of numbers for pulse dialing, depending on the position of SW1-2, which appeared to correspond with the standard 10 pulses per second and Japan's unusual 20 pulses per second.
In other words, it looked exactly like it was programming a timer interrupt.
Wow, that's amazing. Please let me know anything you would like me to test or measure for you now or in the future. I can run arbitrary code on CPU2 as long as it doesn't use any RAM or stack, and I can trigger my scope on 16-bit address match, revealing the data byte read or written. The way the code is written with sub-vectors at $0100, I should also be able to have custom IRQ/NMI handlers but haven't ever attempted that before. I will see if I can confirm what starts and acknowledges the NMI timer this weekend, that will be fun. In addition, it will be interesting to see if there is a pin correlating to NMI. For example, pin 29 has only a 10k pull-up connected. I found that when I drive that pin low, it generates an NMI. I wonder if it drives itself low during NMI, or maybe a different pin, who knows? I will try to find out.Joe wrote: ↑Tue Apr 06, 2021 7:30 pmThe lookup tables are also used for tone dialing, so I worked out approximately how many tones it should dial in one second if my assumptions were correct and then compared with your video.
The SMT parts were actually held with glue but still came off really easy without damaging any of them. Either the heat or the age of the glue must have helped.
Pardon the typo I copy/pasted on all 3 filenames...
Code: Select all
Error: line 12074, column 32: attribute 'package' references undefined object 'DIP-6' in tag <device>
- In KrzysioPCB, press L with the mouse on any pin of IC4.
- Press delete on the device.
- Save, generate Eagle SCH file
Code: Select all
org $0000 fillvalue $FF pad $0102 ; NMI sub-vector DW nmi_sub_vector pad $01F9 ; $01F9 is the correct spot in the stack for the full system. DW arbitrary_entry pad $01FC ; $01FC is the correct spot in the stack for the standalone chip. DW arbitrary_entry fillvalue $FF pad $0200 arbitrary_entry: sei ; disable interrupts lda #$78 sta $4100 ; NMI timer LSB lda #$00 sta $4101 ; NMI timer MSB lda #$02 sta $4102 cli ; enable interrupts noploop nop jmp noploop nmi_sub_vector: jmp noploop
So there must be more to the puzzle.
Also, just for more verification of my setup, I have a 10k pull-up on pin 29. I took a jumper and shorted that pin to GND, and it did trigger the NMI the same as my previous observation. Furthermore, this did cause execution to grab the 16-bit NMI sub-vector from $0102, and it did follow through to "nmi_sub_vector" in my test code and continue the NOP loop from there, all as expected.
I am remembering now that reading $4103 acknowledges the NMI (probably). CPU2 ROM initializes this at $F3D4:
Code: Select all
lda #$00 sta CPU2_REG_4102 ldx CPU2_REG_4103 ; Throws away X after this.
I did get an NMI when I grounded that pin afterall... And it was bouncy when I connected the jumper and I got probably ~10 NMIs, not ever having done any RTIs. That seems to prove that NMI is not stuck asserted and not waiting for RTI. Anyway, I better put that same exact initialization and try that next time I can.
Code: Select all
org $0000 fillvalue $FF pad $0102 ; NMI sub-vector DW nmi_sub_vector pad $01F9 ; $01F9 is the correct spot for the full system. DW arbitrary_entry pad $01FC ; $01FC is the correct spot in the stack for the standalone chip. DW arbitrary_entry fillvalue $FF pad $0200 arbitrary_entry: sei ; disable interrupts timer_init: ; Init like the original ROM: lda #$00 sta $4102 ldx $4103 lda #$00 sta $4106 sta $4107 ; This middle part WAS necessary to get NMI's. lda #$00 sta $4128 sta $4137 lda #$c1 sta $412F lda #$2f sta $4105 lda #$fd sta $4104 lda #$03 sta $4106 ; Start NMI timer timer_reload: lda #$78 ldx #$00 sta $4100 ; NMI timer LSB stx $4101 ; NMI timer MSB timer_start: lda #$02 sta $4102 ; NMI timer enable flag? noploop: nop jmp noploop nmi_sub_vector: jmp timer_start
If I change the nmi_sub_vector to jump to noploop, I only ever get 1 NMI, even after waiting several minutes. So it does seem that writing 1 to bit 1 of $4102 does cause the timer to reload and start, and does not loop on its own (unless there is a loop bit somewhere that I didn't set.).
I tried skipping the writes to $4100 and $4101 out of curiosity to see what their default values are. I read 52.86 seconds when the nominal of $FFFF would be 54.6125 seconds. That is a 3.2% error which is pretty big for a quartz crystal.
So I changed the code to literally initialize to $FFFF, and sure enough I get 54.56 seconds (0.096% error). (52.86/54.56) * $FFFF = $F805. With too few significant figures, maybe $F800. Seems randomish to me.
Continuing to narrow down that init code, this still works:
Code: Select all
timer_init: ; Init like the original ROM: lda #$00 sta $4102 ldx $4103 lda #$c1 sta $412F ; Start NMI timer timer_reload: ;lda #$06 lda #$78 ldx #$00 sta $4100 ; NMI timer LSB stx $4101 ; NMI timer MSB timer_start: lda #$02 sta $4102 ; NMI timer enable flag? noploop: nop jmp noploop nmi_sub_vector: jmp timer_start
I know that I could still generate pin 29 NMIs with $412F.0 = 0 earlier. So next I test if any of those other write bits can enable/disable pin 29-based NMI. I wrote value #$00 to $412F. This prevented timer NMIs, and still allowed pin 29 NMIs. I then tried value #$FE and that acted the same. So it doesn't seem there is a bit in that register that masks non-maskable-interrupts from pin 29.
Next, I put it back to value #$C1 for $412F and probed around to see if I can find any pin to reflect the timer NMI. I found no such pin, including pin 29, that reflected this.
Next, I thought, what if I skip reading register $4103? Well, I wasn't doing that anyway! I did some other stuff playing with this, only to realize that the built-in ROM is actually handling that before it passes execution to the NMI sub-vector. It is reading it already for me. So I can't test what happens if you don't read it. However, I do see that when I add an additional read of $4103 in my nmi_sub_vector, bit 0 was a 1 when the built-in ROM read it, and bit 0 has become 0 when I read it in my code the 2nd time. That seems to kind of confirm that the bit reflects the NMI flag.
Changing $412F back to $00 to disable the timer, then grounding pin 29, I find that $4103 bit 0 is always 0, so this flag reflects only the timer NMI flag.
I think I covered most of it, not really sure what else to try. I did not try setting $4102.1 = 1 before the timer expired and seeing if it restarted the period or not. I can't think of an easy way to try that. I also did not try changing $4100/$4101 with the timer running for the same reason.
I found that $4102.0 is a loop bit. The timer restarts itself automatically with no further writes to $4102.1 when this bit is set.
Theory: $4100,1,2,3 is the NMI timer, I am betting $4104,5,6,7 is an IRQ timer. It makes total sense that this chip would have 2 hardware timers of different priority. Clues that led me to this:
- Reading $4107 clears an IRQ flag, just like reading $4103 clears the NMI flag.
- Value $03 is written to $4106, which would mean start looping timer in $4102.
- $4105,4 are write-only just like $4101,0, IRQ timer period.
Yes indeed, that's another timer, IRQ-based instead of NMI, and 1 count = 1 CPU cycle. I updated it in the wiki. I can't test its loop bit, or acknowledging the flag, but I was able to test it having the first IRQ and see it change with the period value, also verified the high byte of the period worked as expected. Cool stuff.
The built-in ROM initializes the IRQ timer period to value $2FFD. $2FFD = 12285. 12285 / 2,457,600 = 0.004998779296875 seconds = 5 msec. It sets it into looping mode (writes #$03 to $4106) and not touches the period or mode again.
Have you found any other functions that can be enabled or disabled by writing $412F? (Could there be a similar register in the RF5C66?)
$4127 bit 7 gets written with a 1 during CPU2 initialization, and written with a 0 elsewhere. It does not seem to have a way to be written with a 1 again. I don't have any ideas what that could mean.
It is such a fun puzzle to poke at this stuff, almost a treasure hunt. One of the most intriguing parts is that there is no particular 'goal'. It is just interesting to see where it goes. Someone like you pops in Joe, and all of a sudden we have CRCs and more timers and NMIs and IRQs -- that is so exciting.