Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

APU CH1 and CH2 volume envelope only work when AOI_MUX_2 cells have output inverted #77

Open
msinger opened this issue Nov 22, 2021 · 2 comments

Comments

@msinger
Copy link

msinger commented Nov 22, 2021

I can't get the volume envelope function of APU channels 1&2 working without somehow inverting the clock that goes into the COUNT cells HEVO...HAFO (CH1) and FENA...FENO (CH2). They are counting in the wrong direction. I checked the schematic with the die shot and can't find any wrong connections that could cause that. So I think one of the following things must be the case:

  • AOI_MUX_2 has an inverter, changing it to AO_MUX_2 so to speak
  • COUNT has its outputs switched
  • COUNT triggers on opposite clock edge

When I modify the behavior of the COUNT cells in any way (or multiple ways at once), they are causing the APU to break everywhere else they are used. This is why I can only think of the AOI_MUX_2 cells being the culprit here. I haven't simulated everything yet, so I can't say if changing them to "AO without I" will break anything else.

It is also possible that silly me has a totally wrong understanding of the COUNT cells. I see them as flip-flops that toggle on a falling clock edge and can be asynchronously set to D whenever LOAD is high. At least this is how they work for me correctly in other places. Here's a truth table:

CLK     D   LOAD  |  COUT
--------------------------
 x      D    H    |   D     (async. load)
H->L    x    L    |  !COUT  (toggle)
L->H    x    L    |  COUT   (keep)
_
Q is always the inverse of COUT.

Please let me know if I misunderstood their function.

@msinger
Copy link
Author

msinger commented Nov 24, 2021

Same goes for the volume envelope of CH4. It needs AO_MUX_2 cells instead of AOI_MUX_2 for FOLE...ELAF.

The two AOI_MUX_4 cells on the same page (page 20) also need to be AO_MUX_4 for the noise generator to work. I'll explain why. Please see #79 first, so you don't get confused about the labels. I tested channel 4 on a real DMG CPU B Gameboy and in a simulation with Icarus using the following register configuration and compared the sound that came out of it:
FF26 <= 0x80
FF20 <= 0x00
FF21 <= 0xF3
FF25 <= 0xFF
FF24 <= 0x77
FF22 <= 0x13
FF23 <= 0x80
(I wrote the registers in the given order.)
This gives a nice white-ish sounding noise if you play that on a real Gameboy. If I play that in my simulation with ELYX and DARY being AOI cells, I can only hear a very subtle clicking, which is caused by a constant 1 showing up on the net CH4_BIT which gets decreased in volume over time by the envelope function. (The subtle clickings are the volume steps that are actually audible if there is nothing else playing.) The constant 1 on CH4_BIT is caused by ELYX not having any of its B inputs set when bits [6:4] in FF22 are set to 001. The same result happens when FF22 is set to something else, like 0x53 for example. In that case it is DARY that never gets a B input set and therefore always outputs a 1. So, CH4_BIT is always 1 when bit 7 of FF22 is not set, which blocks CH4 from generating any noise sound. If I change ELYX and DARY to be AO cells, then they are not blocking each other anymore and CH4_BIT can "randomly" flip between 0 and 1.
The AOI_MUX_6 cell ETYR also doesn't work like it should. Though it has no partner that would block it, it produces wrong sounds compared to the original Gameboy when I implement it as an AOI cell. I set FF22 to 0xD8 to test that. With that setting only the subtle clickings of the volume envelope can be heard in the simulation output. If I change it to AO instead, I hear the same low frequency blubbering that I hear on a real Gameboy with these register settings.

Because of these tests I strongly believe that all the AOI_MUX_n cells are actually AO_MUX_n, becuase they all look the same. They have two rows between the last input and their output at the bottom. This could be enough space for the inverter which would make them AO.

@msinger
Copy link
Author

msinger commented Nov 24, 2021

Also on page 20, the AOI_MUX_2 KAVU gives a different sound when changed to AO without I.
I tested it with FF22 = 0x83. When KAVU is an AO it sounds much more like the original Gameboy.

msinger added a commit to msinger/dmg-sim that referenced this issue Nov 24, 2021
mrehkopf added a commit to mmitch/gbsplay that referenced this issue Feb 7, 2024
Fixes #114.

Switching the LFSR width on the noise channel without retriggering the
channel can cause our LFSR to run out of 1's, rendering the output
silent until the channel is retriggered (using NR44 bit 7).

This is due to the current implementation of the LFSR that differs from
the Gameboy hardware; it moves the taps and provides only a single point
of feedback whereas hardware keeps the taps in place and adds a second
point of feedback near the middle of the LFSR (creating a "split-off"
7-bit-wide LFSR).

cf. https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Noise_Channel

The schematic reverse engineered by @furrtek mostly supports this
description, except the taps being XNOR'd, not XOR'd:
https://github.com/furrtek/DMG-CPU-Inside/blob/master/Schematics/20_CHANNEL4.png

However, implementing the LFSR strictly according to the schematic lead
to a similar issue; there is reason to believe that the output of the
"AOI_MUX_2" selecting the additional feedback point is actually non-
inverting as opposed to the schematic:

furrtek/DMG-CPU-Inside#77 (comment)

Treating it as an AO_MUX_2 indeed yields correct-sounding output.

We can also assume that the flip-flops composing the shift register are
reset to 0 by their /RESET inputs; this also fits the XNOR tap well.

Here is a before-after comparison of the initial LFSR state (wide mode):

  - old -               - new -

 111111111111111       000000000000000
 011111111111111       100000000000000
 001111111111111       110000000000000
[...]
 000000000000011       111111111111100
 000000000000001       111111111111110
 100000000000000       011111111111111
[...]

Due to 0 initialization and inverted tap output, the state is basically
the inverse of the old version, up to the point of a width change.
As a result the noise channel of most tracks (which do not expose the
bug) is now inverted.

Here is a before-after comparison of the LFSR state of previously
incorrect playback, taken from Castlevania 2:

  - old -               - new -

 000001010101000       111110101010111
 000000101010100       111111010101011
 000000010101010       111111101010101
* at this point the game changes LFSR width to 7
 000000001010101       011111110101010
 000000000101010       001111110010101
 000000000010101       000111110001010
 000000000001010       000011110000101
 000000000000101       000001110000010
 000000000000010       000000110000001
 000000000000001       000000010000000
 000000000000000       100000001000000
 000000000000000       110000001100000

And, indeed, the missing parts are now audible and akin to a real
hardware recording.
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

No branches or pull requests

1 participant