I'm a bit unfamiliar with precisely what you're trying to do here, but... Can you "just" scale all of your 6-bit values by 4 (shift left two bits) and treat as 8-bit, with appropriate compensation for divide/multiply if necessary?byuu wrote:Not for the audio portion, though. I had to just reuse the Wiki formulas for that. I suck at FM synthesis. I do have 6-bit signed integers in higan though, so I would like to try and rework that code sometime to use those instead of the strange over/underflow manual checks to work with 8-bit integers that's there now.
Famicom Disk System emulation
-
abridgewater
- Posts: 3
- Joined: Fri Apr 05, 2019 9:47 pm
Re: Famicom Disk System emulation
-
Near
- Founder of higan project
- Posts: 1553
- Joined: Mon Mar 27, 2006 5:23 pm
Re: Famicom Disk System emulation
I certainly could, yes. I just figure that if I have native 6-bit types, I may as well allow the over/underflow behavior to occur naturally.
-
Pokun
- Posts: 3482
- Joined: Tue May 28, 2013 5:49 am
- Location: Hokkaido, Japan
Re: Famicom Disk System emulation
Not a switch, QDs have two plastic tabs (one for each side) that are broken off to enable write protection (just like on tapes), so you need to tape over the slot to disable write protection again. Although games might not work if it's enabled, Nintendo's version of the disks nevertheless always has these tabs, so I see nothing wrong in emulating them.byuu wrote:I haven't *yet* added write protection. Is that just a physical switch on the floppy disk like regular 3.5" disks have?
The tabs are checked by a physical lever inside the disk drive which can get dirty and upset, and throwing unwanted write protection errors even if you press on it with your finger. Never happened to me though.
-
TakuikaNinja
- Posts: 441
- Joined: Mon Jan 09, 2023 6:42 pm
- Location: New Zealand
Re: Famicom Disk System emulation
SCSR on Discord pointed out some undocumented register behaviours that I was able to verify using a custom FDS port of nesmon (NES wozmon) on my Twin Famicom.
$4030.d3 returns the nametable arrangement/mirroring bit from $4025.d3: Setting $4025.d5 = 0 alters bits 1 & 2 of the output on the external connector, which is reflected in $4033 reads: Writing $4025 in this state/mode affects the bits but I can't determine a clear pattern yet. All I could tell was that having certain bits in $4025 transition (0 -> 1 or 1 -> 0) will change bit 1?
I've updated the wiki with this info but test programs need to be written to compare between emulators and original hardware.It would be nice if someone other than myself could write them...
$4030.d3 returns the nametable arrangement/mirroring bit from $4025.d3: Setting $4025.d5 = 0 alters bits 1 & 2 of the output on the external connector, which is reflected in $4033 reads: Writing $4025 in this state/mode affects the bits but I can't determine a clear pattern yet. All I could tell was that having certain bits in $4025 transition (0 -> 1 or 1 -> 0) will change bit 1?
I've updated the wiki with this info but test programs need to be written to compare between emulators and original hardware.
You do not have the required permissions to view the files attached to this post.
-
TakuikaNinja
- Posts: 441
- Joined: Mon Jan 09, 2023 6:42 pm
- Location: New Zealand
Re: Famicom Disk System emulation
I've made a program to test the $4025.D3/$4030.D3 behaviour - it's attached to this post. The PPU nametable arrangement/mirroring is also checked for good measure.
Source Code
Capture from my Twin Famicom: The second test is for the previously undocumented $4030.D3 behaviour and is currently expected to fail on practically all emulators with FDS support. It would be nice to get some extra sets of eyes on this before I link it on the wiki.
UPDATE: A new test has been added to verify newly discovered behaviour, where $4023.D0 = 0 writes effectively reset the nametable arrangement. Please redownload the attachment if you have downloaded it before.
P.S.: I've found that NintendulatorNRS seems to reject FDS disks which have the file amount block > actual number of files on disk (for the purpose of bypassing the license screen).
Source Code
Capture from my Twin Famicom: The second test is for the previously undocumented $4030.D3 behaviour and is currently expected to fail on practically all emulators with FDS support. It would be nice to get some extra sets of eyes on this before I link it on the wiki.
UPDATE: A new test has been added to verify newly discovered behaviour, where $4023.D0 = 0 writes effectively reset the nametable arrangement. Please redownload the attachment if you have downloaded it before.
P.S.: I've found that NintendulatorNRS seems to reject FDS disks which have the file amount block > actual number of files on disk (for the purpose of bypassing the license screen).
You do not have the required permissions to view the files attached to this post.
Last edited by TakuikaNinja on Sun Nov 30, 2025 2:09 am, edited 2 times in total.
-
Aduel
- Posts: 55
- Joined: Wed Feb 05, 2025 8:22 pm
Re: Famicom Disk System emulation
It seems like Sour's Mesen 2 latest build includes this mirroring behavior and passes both tests.
-
TakuikaNinja
- Posts: 441
- Joined: Mon Jan 09, 2023 6:42 pm
- Location: New Zealand
Re: Famicom Disk System emulation
(I swear I posted here last night... whatever)
So it turns out that the read-only registers are mapped and functional even they're disabled via $4023. I haven't checked the sound registers yet but I would expect them to behave in the same way. This means that only the write-only registers are actually disabled in this state. I've seen some emulators map the read-only registers to open bus when "disabled", so those are incorrect.
Exhibit 1 - $4030-$4033 are still readable when $4023 = 0:
Exhibit 2 - $4032 can still recognise the disk being inserted/ejected while in this state (first/second reads = while inserted, third read = after ejection):
So it turns out that the read-only registers are mapped and functional even they're disabled via $4023. I haven't checked the sound registers yet but I would expect them to behave in the same way. This means that only the write-only registers are actually disabled in this state. I've seen some emulators map the read-only registers to open bus when "disabled", so those are incorrect.
Exhibit 1 - $4030-$4033 are still readable when $4023 = 0:
Exhibit 2 - $4032 can still recognise the disk being inserted/ejected while in this state (first/second reads = while inserted, third read = after ejection):
You do not have the required permissions to view the files attached to this post.
-
TakuikaNinja
- Posts: 441
- Joined: Mon Jan 09, 2023 6:42 pm
- Location: New Zealand
Re: Famicom Disk System emulation
I've started a brand new user subpage on the wiki to document hardware-verified information on the FDS registers: https://www.nesdev.org/wiki/User:Takuik ... _Registers
It's intended to replace the contents of the current wiki page once mostly complete, hopefully obsoleting the legacy resources. Therefore, many test programs need to be made to verify things.
It's intended to replace the contents of the current wiki page once mostly complete, hopefully obsoleting the legacy resources. Therefore, many test programs need to be made to verify things.
-
TakuikaNinja
- Posts: 441
- Joined: Mon Jan 09, 2023 6:42 pm
- Location: New Zealand
Re: Famicom Disk System emulation
Just gonna relay some info from the Discord server:
- $4030.D7 is the byte transfer flag, not D1 as indicated on Enri's page. SCSR observed that $4030.D7 is connected to the circuit involving $4025.D7, which is the IRQ enable toggle for the byte transfer flag. To corroborate this: Tonkachi Editor appears to entirely rely on polling $4030.D7 without IRQs for disk I/O, which was why the MiSTer FPGA core for NES/FDS implemented this change.
- In relation to this, SCSR found an unknown timer/counter connected as an input to the 3-input NOR for /IRQ, and also connected to $4030.D1. (i.e. this is another IRQ source in addition to the known timer IRQ and byte transfer flag IRQ) It's currently theorised to be a refresh counter for DRAM chips which require external refreshes (seen on early RAM adapters). He also observed that $4023.D7 is the enable toggle for this IRQ source. I had a look in some commercial games and found that the IRQ handler in many of them check for $4030.D1 and call the Delay131 BIOS routine (the same one used in the "ack + delay" handler) if it's set. Third-party games seem to be a bit spotty but I'd assume all first-party titles with timer IRQ usage check for it at the very least.
You do not have the required permissions to view the files attached to this post.
-
TakuikaNinja
- Posts: 441
- Joined: Mon Jan 09, 2023 6:42 pm
- Location: New Zealand
Re: Famicom Disk System emulation
To account for the possibility of code execution causing DRAM refreshes, here's a "micro" version of the $4030.D1 test which does manual polling (no IRQs) from within system RAM. The only DRAM accesses being made are for the vector reads during NMI (only for the license screen bypass) and reset - everything else is executed either in system RAM or the BIOS ROM.
There are still no changes on my Twin Famicom, so we'll have to see what happens on early RAM adapters.
There are still no changes on my Twin Famicom, so we'll have to see what happens on early RAM adapters.
You do not have the required permissions to view the files attached to this post.
-
TakuikaNinja
- Posts: 441
- Joined: Mon Jan 09, 2023 6:42 pm
- Location: New Zealand
Re: Famicom Disk System emulation
I've finally gotten this IRQ source to trigger on my Twin Famicom! (see the attached AV capture) $4023.D7 appears to be the IRQ enable flag for this source, and $4023.D0 = 1 seems to enable the source itself. Triggering this IRQ seems to require continuous execution of a small section of code in DRAM (consecutive CPU cycles for DRAM access?), as I adapted the "micro" version to use the same IRQ setup and could not get it to trigger at all. lidnariq did suggest on Discord at one point that this whole system may be for synchronising DRAM cycles with CPU cycles, so maybe that's an avenue to pursue. I should also note that this means Yuri213212 had gotten the $4023 interface correct since last year - sorry for taking so long to get to this...
Now I might have to put this IRQ detection code in my own FDS programs to see if this causes significant overhead in performance. At least this now gives us a better idea of why the "ack + delay" IRQ handler is the default selection on reset - it's meant to be transparent for games which don't use other IRQ sources but don't mask IRQs with SEI on startup.
Attached is a version of the test with calls a DRAM copy of the BIOS Delayms routine and the actual BIOS Delayms routine in a loop. The IRQs do not fire while executing the actual BIOS Delayms routine.
Now I might have to put this IRQ detection code in my own FDS programs to see if this causes significant overhead in performance. At least this now gives us a better idea of why the "ack + delay" IRQ handler is the default selection on reset - it's meant to be transparent for games which don't use other IRQ sources but don't mask IRQs with SEI on startup.
Attached is a version of the test with calls a DRAM copy of the BIOS Delayms routine and the actual BIOS Delayms routine in a loop. The IRQs do not fire while executing the actual BIOS Delayms routine.
You do not have the required permissions to view the files attached to this post.
-
TakuikaNinja
- Posts: 441
- Joined: Mon Jan 09, 2023 6:42 pm
- Location: New Zealand
Re: Famicom Disk System emulation
And now I've gotten the micro version to trigger this IRQ by executing a NOP slide in DRAM. The attached version of the micro test displays the return address for the first IRQ that is fired. This acts as a function for the cycle count spent in DRAM - subtract $6000, multiply by 2, then add the overhead of the JSR entry and IRQ handler. My Twin Famicom consistently displays $6637 or $6638. lidnariq and I calculated the resulting time threshold to be about 1.79ms, which is close to the 2ms row refresh period rating on the M5M4416P DRAMs used in early RAM adapters. I should note that running the NOP slide refreshes the relevant DRAM rows regardless of the conditions for triggering the IRQ.
You do not have the required permissions to view the files attached to this post.
-
TakuikaNinja
- Posts: 441
- Joined: Mon Jan 09, 2023 6:42 pm
- Location: New Zealand
Re: Famicom Disk System emulation
Okay, I've finally had the opportunity to test what would happen if the DRAM refresh watchdog is ignored. I noticed that Pachi Com on the FDS has a fixed delay loop (that would otherwise be running exclusively in DRAM) patched inline to use the BIOS' Delay131 routine.
Original:
FDS Version:
I reverted that change and made it always use SEI - the patch file is attached to this post. The patched version ran completely fine on my Twin Famicom. As soon as I got forple to run it on his early-DRAM RAM adapter, however, the game would reliably crash/hang after the "GAME START" screen runs the delay loop. Resetting the console caused the BIOS startup screen to appear, so the program definitely clobbered the stack variables.
Video courtesy of forple: https://youtu.be/VgBiaUGqb4A
This confirms that DRAM decay is indeed an issue on RAM adapters with early DRAM (i.e. the 4 chip one), and that this watchdog IRQ was implemented so that games with "everything in NMI" (e.g. infinite JMP loops) can safely run on the FDS. I'm more motivated to write a dedicated DRAM decay detection test now because of this.
Original:
Code: Select all
; Original cartridge version
.org $8b7d
Delay:
ldx #$00
ldy #$00
:
dex
bne :-
dey
bne :-
rtsCode: Select all
; FDS version
.org $6b7d
Delay:
ldx #$00
ldy #$00
:
jmp NewDelay
dey
bne :-
rts
; FDS version jumps to this brand new routine
; (yes, this overwrites the infamous programmer rant)
.org $60e0
NewDelay:
jsr Delay131
jsr Delay131
jsr Delay131
jsr Delay131
jsr Delay131
jsr Delay131
jsr Delay131
jsr Delay131
jsr Delay131
jsr Delay131
dey
bne NewDelay
rts
Video courtesy of forple: https://youtu.be/VgBiaUGqb4A
This confirms that DRAM decay is indeed an issue on RAM adapters with early DRAM (i.e. the 4 chip one), and that this watchdog IRQ was implemented so that games with "everything in NMI" (e.g. infinite JMP loops) can safely run on the FDS. I'm more motivated to write a dedicated DRAM decay detection test now because of this.
You do not have the required permissions to view the files attached to this post.
-
TakuikaNinja
- Posts: 441
- Joined: Mon Jan 09, 2023 6:42 pm
- Location: New Zealand
Re: Famicom Disk System emulation
Okay, here's a DRAM "soak test" of sorts - here's what it does:
Change the bytes at .fds file offsets $009f and $00a1 for X and Y respectively if desired.
- Fill DRAM with all $ff (change byte at .fds file offset $00ad if desired)
- Copy the aforementioned delay routine into DRAM
- In a loop: calculate/display CRC32 for DRAM, play a ding, run the delay routine
Change the bytes at .fds file offsets $009f and $00a1 for X and Y respectively if desired.
You do not have the required permissions to view the files attached to this post.
-
paulb_nl
- Posts: 54
- Joined: Fri Nov 18, 2016 7:57 am
Re: Famicom Disk System emulation
Thanks for working on all of this.
I am curious about the specifics of how and when the DRAM IRQ is triggered.
The DRAM datasheet that you mentioned states that it needs 128 refresh cycles per 2ms. Since the default IRQ handler delays only a few more than 128 CPU cycles, I assume that one CPU cycle is one refresh cycle.
I guess that it does a refresh every cycle that DRAM is not being accessed by the CPU. So does this mean for example that if we execute out of DRAM and execute a loop with JSR RTS that the IRQ will not be triggered? The CPU will access the stack with the JSR and if the stack is located in $01xx then there are some cycles free for refreshing DRAM.
I am curious about the specifics of how and when the DRAM IRQ is triggered.
The DRAM datasheet that you mentioned states that it needs 128 refresh cycles per 2ms. Since the default IRQ handler delays only a few more than 128 CPU cycles, I assume that one CPU cycle is one refresh cycle.
I guess that it does a refresh every cycle that DRAM is not being accessed by the CPU. So does this mean for example that if we execute out of DRAM and execute a loop with JSR RTS that the IRQ will not be triggered? The CPU will access the stack with the JSR and if the stack is located in $01xx then there are some cycles free for refreshing DRAM.