Next one is the triangle waveform.
The upper 12 bits of the oscillator run from 0 to $fff, at a speed dependent on the frequency, producing a sawtooth waveform.
A triangle waveform is obtained by XORing the bits with the oscillator's MSB, in this way during the second half of the wave, when the MSB is 1, the bits are inverted forming the descending ramp of the triangle. As the result is only 11 bits the value is shifted to the left and the LSB is set to 0, thus halving the resolution but retaining full amplitude.
It is possible to apply a ring modulation effect, controlled by Bit 2 of the Control Register, so the MSB is XORed with the (inverted) MSB of the preceeding voice producing non-harmonic overtones.
This is the XOR logic applied to the first eleven bits of the oscillator's output:
Attachment:
Tri_bit_IC.png [ 9.09 KiB | Viewed 8760 times ]
The output results from the following expression:
Tri_bitX = ¬((TriXOR ∧ bitX) ∨ ¬(TriXOR ∨ bitX))
= TriXOR + bitX
Attachment:
Tri_bit.png [ 7.44 KiB | Viewed 8760 times ]
The xor input is generated by the following circuit:
Attachment:
Triangle_XOR_IC.png [ 16.72 KiB | Viewed 8760 times ]
The output results from the following expression:
TriXOR = ¬(a ∨ Saw ∨ (b ∧ bit23))
= ¬Saw ∧ ¬a ∧ ¬(b ∧ bit23)
where:
a = ¬(b ∨ bit23)
b = ¬(V3 ∨ ¬Ring) = ¬V3 ∧ Ring
(V3 is the 23rd bit of the ring modulating voice's oscillator)
resulting in:
TriXOR = ¬Saw ∧ (b ∨ bit23) ∧ ¬(b ∧ bit23)
= ¬Saw ∧ (b + bit23)
= ¬Saw ∧ ((¬V3 ∧ Ring) + bit23)
Attachment:
Triangle_XOR.png [ 12.66 KiB | Viewed 8760 times ]
So TriXOR is high for the following combinations:
Code:
S | b23 | V3 | R
--|-----|----|--
0 | 1 | 0 | 0
0 | 1 | 1 | 0
0 | 0 | 0 | 1
0 | 1 | 1 | 1
In other words if the sawtooth waveform is not selected the oscillator bits are inverted when ring modulation is diabled and the MSB is 1 or when ring modulation is enabled and the two MSBs, from the current and the modulating voices, are equal.
When the sawtooth is selected the XORing is disabled as the same output is used for both waweforms.
An interesting thing is that in resid the V3 value is not inverted, so either I've found a bug or I did some mistake. That's something worth exploring