by andete. Original documents available at: https://github.com/andete/ym2413/tree/master/results

### Phase-counter

In the previous post we figured out the resolution of the sine table. To do this we choose 'special' values (powers-of-2) for the channel frequency (fnum+block+ML) and looked at 'flat' regions in the output. E.g. near zero where the sine wave is rising/falling the fastest, we still saw multiple successive equal output values (because the sine table only has 1024 entries and the chosen frequency was low enough to require more than 1024 steps per period).

In this post we'll use the same technique to figure out more details about the internal phase calculations. Phase or phase-counter here means the 'position' in the sine wave.

When setting non-power-of-two fnum values we see that the step-size through the sine table is not always the same for successive samples. E.g. the same entry might sometimes repeat 5x sometimes 6x (for lower frequencies) or for each sample we skip ahead sometimes 7 sometimes 8 entries in the table (for higher frequencies). This can easily be explained by assuming fixed-point arithmetic. So instead of only having a 10 bit phase counter (for 1024 entries) we have some additional fractional bits.

Fixed-point calculations are very cheap, both in software and (even more) in hardware. Most (all?) YM2413 emulators also perform the phase calculations in fixed-point. But not all emulation code agrees on the number of bits before and after the decimal point. From the previous post we know there are 10 bits before, but how many bits are there after the decimal point?

The upper (integral) bits determine the entry in the sine table, the lower (fractional) bits track the position between entries. In theory the fractional bits could be used to interpolate between two table entries, this could increase the accuracy of the result. Though interpolation typically requires multiplication and that's likely too expensive for the YM2413 hardware implementation. So for now I'll assume the YM2413 doesn't interpolate. Instead it directly uses the upper 10 bits as the entry position (actually the upper 2 bits 'mirror' the table lookup and only the next 8 bits are used as the actual table index).

So again, how many fractional bits are there? To figure this out I did the following experiment: play a sine wave (exact shape doesn't matter) at various different settings for:

• instrument-car.ML
• channel-block
• channel-fnum

For each combination capture the output and measure the length of 'flat' segments (the number of consecutive equal-value outputs). This gives the following table:

MLblockfnum#repeatsstep-sizeremarks
000inf0#1
001inf0#2
0025121
0035121#4
0042562
0081284
010inf0#1
0115121
0122562
013170.673#3
0141284
018648
020inf0#1
0212562
0221284
02385.336#3
024648
0283216
100inf0#1
1015121
1022562
103170.673#3
1041284
108648
110inf0#1
1112562
1121284
11385.336#3
114648
1183216

The first 3 columns are the input parameters of the experiments. The #repeats column is the measured result. And the step-size column is a calculated value (more on this column below).

The table shows the following 'interesting' data points:

1. Whenever fnum=0 the phase doesn't change, resulting in an infinite segment length.
2. ML=0,block=0,fnum=1 is the only additional combination that also results in a non-changing phase. (Side note: the phase keeps it's current value, it's not reset to zero or something).
3. For fnum=3 I recorded fractional values in the table. E.g for ML=0,block=1,fnum=3 I measured lengths 171,171,170 for 3 successive segments (and that pattern repeats every 3 segments). I summarized that as 170.67.
4. The only odd result for fnum=3 occurs when ML=0,block=0. This does not result in a fractional value.

If we ignore ML=0,block=0 for now, the pattern seems to be

#repeats for ML=x,block=y,fnum=*z*

is equal to

#repeats for ML=x,block=y,fnum=*1* divided by *z*

The highest value in the #repeats column is 512. All other values in that column can be expressed as 512/n with n an integer. This suggests the fixed-point phase-counter has 9 fractional bits.

Let's assume the formula

`step-size = ((fnum * mlTab[ML]) << block) >> 1`

with

`mlTab = {1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30}`
(same table as listed in the datasheet, but each value doubled)

The result of this formula is shown in the 'step-size' column. This value must be interpreted as a fixed-point value with 9 fractional bits (roughly speaking, you get the equivalent mathematical value by dividing the number by 512).

To check this formula let's use it to predict the measured values:

#repeats should be the reciprocal of the step-size. Or expressed in 9-bit fixed-point:

#repeats = 512 / step-size

This matches exactly the measurements.

Let's revisit the earlier remarks:

1. When fnum=0 the formula always evaluates to step-size=0. And that indeed results in an infinite segment length.
2. For ML=0,block=0,fnum=1 the formula still evaluates to step-size=0. (Because of the '>> 1' operation in the formula we loose one bit).
3. For fnum=3 (or any non-power-of-two) 512/fnum indeed results in a fractional value.
4. For ML=0,block=0,fnum=3 step-size evaluates to 1, this is indeed the same value as for ML=0,block=0,fnum=2. (We again loose one bit because of the '>> 1' operation).

What about overflow? If we pick the values ML=15,block=7,fnum=511 (the maximum values) our formula predicts step-size = 981120 (0xEF880). But that doesn't fit in 19 bits.

Let's repeat the above experiment, but now for high frequency settings. Instead of measuring the equal-value-segment-length, we now measure the length of one full sine period:

MLblockfnumperiod-lenstep-sizeremarks
0025640960x00080
0125620480x00100
0225610240x00200
032565120x00400
042562560x00800
052561280x01000
06256640x02000
07256320x04000
17256160x08000
2725680x10000
372565.330x18000
4725640x20000
572563.20x28000
672562.670x30000
772562.290x38000
8725620x40000#1
97256-0x48000#2
157511+/- 7.770xEF880#3
=0x6F880

As before the first 3 columns are the input parameters, the period-len column is the measured result and the step-size column contains our predicted value.

Only the really high values are interesting:

1. For ML=8 block=7 fnum=256 the YM2413 output alternated between only two values (not 100% true because the effect of the modulator could not be fully disabled). This means step-size is indeed 0x40000. So step-size can span the full 19-bit range.
2. This setting is above the Nyquist frequency. We're talking larger steps through the sine-table than half the period. So it appears the sine is going backwards at a lower frequency. This particular value was hard to measure (hard to count the period-length) so I didn't bother.
3. Our formula predicts a step-size=0xEF880, though that requires 20 bits. But actually the extra bit doesn't matter, when adding it to the 19-bit phase counter that extra bit anyway doesn't contribute anything. For this combination I could measure the period length, and it does match the predicted value (when taking frequency aliasing into account, because also here we're above Nyquist).

This all means we can ignore overflow in the step-size calculation.

So the conclusion (so far):

• Phase-counter is a 10.9-fixed-point counter.
• Each sample the phase-counter is increased by a value step-size = ((fnum * mlTab[ML]) << block) >> 1

Though the phase is also influenced by:

• The vibrato-bit of the modulator/carrier in the instrument settings.
• Phase modulation of carrier by modulator.
• Feedback in the modulator.

In this experiment I disabled these 3 influences (or as much as possible). Later we'll possibly have to extend the step-size formula to take these effects into account.

### Die-shot

From time-to-time I look at the YM2413[1] die-shot: http://siliconpr0n.org/map/yamaha/fhb013/mz_ns50xu/

This time I was actually able to find a feature in the die-shot that supports the conclusion of this post: there really seem to be 19 bits allocated to the phase counter(s).

In the large rectangle in the top-right corner you can see 19 horizontal bands. In the left part of that rectangle you see a region that has much less (vertical) wires going across the bands. If you look very closely to the band(s) in that region you see features that (horizontally) repeat 18 times. (Look at the link above for a zoomable image).

That region contains 19 chains of 18 flip-flops. Each flip-flop stores a single bit. There are 19 bands next to each other, combined they form a 19-bit value. There are 18 flip-flops in a chain, that's one phase-counter for each of the 18 operators (9 modulators and 9 carriers). We also see that (only) the upper 10 of the 19 flip-flops are routed further to a (relatively small) block of logic (that performs mirroring depending on the upper two bits?) and the output of that logic is further routed to a ROM (the sine-table).

The YM2413 only has the hardware to do one 'operator-calculation' (modulator or carrier) at a time. This means that the data required for such a calculation somehow has to be routed to that operator logic. A chain of flip-flops is one such possibility: (only) the bits at the head of the chain are used, the other bits are waiting in line (literally). You can also see some wires that connect the head of each chain back to the tail. Those connections close the circle so that the same value comes back every 18 'cycles'. Actually there still is a bit of extra logic present in the loop, this is likely the step-size adder.

### OPL3 reverse engineering forum

A couple of days ago (after I had already finished most experiments for this post) I discovered this forum:

The main focus in that forum is the OPL3, but there's a little info on the OPL2 as well. (YM2413 (OPLL) is an OPL2 derivative, so closer to OPL2 than to OPL3). For this post the following forum-topic is the most relevant:

The information there seems to match, more or less, with my findings. There's one important difference:

• OPL3 uses a 10.10 bit fixed-point phase-counter
• OPLL uses a 10.9 bit fixed-point phase-counter

Though also

• OPL3 has 10 bits for fnum
• OPLL has 9 bits for fnum

So from that point of view the results match again.