Skip to content

NES: FDS Accuracy Improvements#133

Open
TakuikaNinja wants to merge 11 commits into
nesdev-org:masterfrom
TakuikaNinja:FDS-Registers-Redo
Open

NES: FDS Accuracy Improvements#133
TakuikaNinja wants to merge 11 commits into
nesdev-org:masterfrom
TakuikaNinja:FDS-Registers-Redo

Conversation

@TakuikaNinja
Copy link
Copy Markdown

@TakuikaNinja TakuikaNinja commented May 21, 2026

This is a redo of #85 which avoids changing the current audio implementation.

Working

  • $4023.D0 only affects writable disk registers, forces certain values for $4025 and $4026
  • $4023.D1 only directly affects $4080 (volume envelope), $4085 (mod counter), and $4088 (mod table write), apply instant volume mute for now
  • External connector: Mask $4026 writes to 7 bits, and force bit 7 = 1 for $4033 reads (i.e. always return good battery/power status)
  • $4030 reads do not clear byte transfer flag/disk IRQs
  • Move byte transfer flag to $4030.D7 (eventually needed by Tonkachi Editor)
  • $4090-$4097 reads (debug audio registers), handled by manually calculating the necessary values this time
  • Add remaining registers to register view
  • Fix off-by-one in envelope timer init

Not addressing

  • Register peeking
  • Actual audio reset state when $4023.D1 = 0 (research ongoing) + rename _soundRegEnabled to reflect its purpose
  • $4095 upper nybble
  • DRAM refresh watchdog ($4030.D1)
  • CRC handling ($4025.D4 & D6)
  • End of head behaviour ($4030.D6)
  • Byte transfer flag behaviour ($4030.D7)
  • Wavetable volume/modulation accuracy improvements
  • Non-linear DAC + volume PWM + filtering (probably not worth the performance hit for a minuscule audio improvement)

Test programs

Passes latest FDS-Mirroring-Test
Disk registers behave closer to hardware in FDS-4023-Test
$4023.D0 = 0 forces output to $7F
Always return good battery status in $4033.D7
Eventually needed by Tonkachi Editor, though it still fails to access disks for editing
Clarify external connector implementation
Clarify comment for $4024 IRQ handling
Move $4025 IRQ handling into SetFdsControlReg()
Allows audio to play properly in FDS-Audio-Registers
@TakuikaNinja
Copy link
Copy Markdown
Author

Here's how the register view currently looks:
image
image

@TakuikaNinja TakuikaNinja marked this pull request as ready for review May 21, 2026 04:58
//TODO $4025 bit 5 is unknown, all known software sets it to 1

_diskReady = (value & 0x40) == 0x40; //TODO $4025 bit 6 is CRC enable, not disk ready flag
_diskIrqEnabled = (value & 0x80) == 0x80;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are all bools, so you don't need to do these comparisons on them; they'll be true if the right hand side is nonzero and false if 0.

void Fds::SetFdsControlReg(uint8_t value)
{
_motorOn = (value & 0x01) == 0x01;
_resetTransfer = (value & 0x02) == 0x02;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your wiki documentation has the drive motor on bit 1 and nothing on bit 0. I'm referencing your material as I review this PR and when it's not consistent, I don't know which one is right. The original documentation has the motor on bit 1 (matching your own documentation) and the transfer reset on bit 0, so I'm guessing you have these inverted here.

Looks like this was actually already backward in the original code (I didn't realize at first that this was just moving code). Definitely something to double check, though.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bits being swapped here results in their meanings also being inverted (it should be bit 0 = 1: scan media, bit 1 = 1: stop motor). I'll keep the current bool names and simply invert the register read/write logic for now so we don't break savestates, but we might want to revisit their naming once we reach the point of reimplementing the disk loading to use the CRC controls and byte transfer flag properly.

void ProcessCpuClock() override;
void UpdateCrc(uint8_t value);

void SetFdsControlReg(uint8_t value);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For stuff like this being moved into a new function, make sure to consult with Sour about whether you need to use __forceinline to avoid a performance impact.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reverted that function anyway, since the values set when $4023.D0 = 0 are constant.

Comment thread Core/NES/Mappers/FDS/Fds.cpp
case 0x4033:
//Always return good battery
return _extConWriteReg;
return _extConWriteReg | 0x80;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For clarity, I suggest either adding a note that 'good battery' is indicated by bit 7, or using a named constant here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants