Page 5 of 6

Re: FPGA implementation

PostPosted: Wed Jul 15, 2015 12:58 am
by synthop
Here's an SD card image:

As far as building from scratch, I have scripts setup to build the FPGA but not the software portion and boot image yet. In the FPGA folder, you may simply run 'make bitstream' to build an FPGA image that may be loaded onto the SD card or loaded in via JTAG (which is normally how I do it for debugging). This is assuming you're under a Linux environment, with Xilinx Vivado 2015.1 installed and in your path. I'll soon get around to creating scripts for the software portion and boot image.

I've since discovered that the feedback seems to be causing some fuzzy sounding distortion apparent during certain songs (it goes away if I set feedback to 0). I'm trying to figure out why Steffen is shifting the feedback by 9 in his code:
Code: Select all
     * @brief Calculate adjusted phase feedback
     * @return Adjusted phase feedback using m_fb (11 bit)
     * @details
     * The OPL stores the last 2 samples independent of feedback.
    int16_t feedback() const {
        if( m_fb == 0 ) {
            return 0;
        return ( ( m_feedback[0] + m_feedback[1] ) << m_fb ) >> 9;
     * @brief Push feedback into the queue
     * @param[in] fb 13 bit feedback from channel output
    void pushFeedback( int16_t fb ) {
        m_feedback[0] = m_feedback[1];
        m_feedback[1] = fb;

I'm replicating this exact code in the FPGA. I may also have an issue with assigning the values at the wrong time in the time slot; I need to check this more thoroughly in simulation.

Re: FPGA implementation

PostPosted: Wed Jul 15, 2015 8:31 pm
by opl3
Thanks, the image works and plays Doom music. I see the terminal has some debug output at 115200 bps, listing some songs, but can I control it somehow?

About the feedback,
The m_fb variable holds 0..7 just like FB bits in register of real chip.
When m_fb is 0, there is no feedback.

Steffen's phase generator keeps track of the phase internally in 19-bit form, but it returns the value >> 9 to basically return the high 10 bits used to index the waveform table. The modulation works in the table index domain range so the modulation can come from modulator output or feedback calculation and it is just summed to table index. It is done like this to correctly get rid of bits that should be truncated off, so the result of feedback calculation can be just summed to phase index.

operator output range about +/- 4k or +/- 8*pi
sum of curr+ṕrev outputs, range is +/- 8k, or +/- 16*pi.

In other words, it could also be shifted right by (9-m_fb):

7: (curr+prev)>>2, the range is +/- 2k = 4*pi
6: (curr+prev)>>3, range +/- 1k = 2*pi
5: (curr+prev)>>4, range +/- 510 = pi
4: (curr+prev)>>5, range +/- 255 = pi/2
3: (curr+prev)>>6, range +/- 127 = pi/4
2: (curr+prev)>>7, range +/- 63 = pi/8
1: (curr+prev)>>8, range +/- 31 = pi/16
0: 0

So the index to waveform table in general is just
index = ((phaseaccumulator>>9) + (modulation))&0x3FF;
Where modulation is either modulator output PCM value directly, or PCM value of feedback calculation scaled by feedback ratio.
It is just a coincidence the feedback calculation also has >>9 like the index calculation from phase if going through (x<<m_fb)>>9 route.

Re: FPGA implementation

PostPosted: Thu Jul 16, 2015 5:47 pm
by synthop
Glad it works for you! Yeah the debug output on the console doesn't do much right now except list the files in the In-Memory Filesystem. The software is so minimal; I just hacked it up to test the FPGA--it's hardcoded to play one song. I'd like to have a command line interface to play songs and/or play songs on button presses or whatever. Eventually it would be cool to create a USB device and corresponding driver that would allow it to be used as a music device on a PC. I think there's also a DosBOX version for ARM so that could be cool. Lots of possibilities there.

Yes I understand regarding the bit width of the phase generator and high 10 bits used to index the waveform table (the modulation addition I believe is correct for me). It makes sense that the shift by 9 for the feedback was purely a coincidence; I suspected as much I just didn't see where it was derived from.

How you just described it made me realize I'm adding the previous 2 samples together for the feedback, not the current + the previous. That could be where the distortion is coming from? What's a bit tricky is that the data propagation through the waveform tables has to happen twice in the same time slot which makes things a bit harder, but I *think* I have enough cycles. I'll try that.

Re: FPGA implementation

PostPosted: Fri Jul 17, 2015 8:55 am
by opl3
I also recall there are some DosBox/ScummVM versions with OPL passthrough if you happen to have a sound card with onboard OPL. So yes, interesting. It's enough to emulate the OPL3, I would not want to write a full 386 emulation for FPGA :) Maybe anything below 286 is easy enough though..

Anyway, you mentioned it would be harder to take current and previous output as feedback when generating next sample. I don't know if that is large enough difference to be heard, but it could be. Why the data would propagate twice through the waveform calculation? I haven't read your code that much and I am not a FPGA expert, but does not each operator have an output "register" where the next output gets stored? Then you only need one delay element for keeping the delayed output sample because the current output is already latched. So you can just use current output and delayed output (sum them and shift to correct position) and use them as feedback. Sorry if I am not making any sense here.

Re: FPGA implementation

PostPosted: Thu Jul 23, 2015 4:12 am
by synthop
Okay I think we just had a little bit of a mix up on semantics, but that was not the problem anyway. I was in fact latching the feedback in the wrong operator time slot, and the value was also being truncated. I fixed both problems and things sound very good now with feedback.

Next onto the rhythm instrument implementations and additional software work.

I updated the SD card image at

Re: FPGA implementation

PostPosted: Sun Jul 26, 2015 9:59 pm
by synthop
So I've implemented the rhythm instruments. It's hard to tell if they're working or not because I'm not sure if the music I'm listening to is using them or not. If you guys have some tough test cases (preferably in DRO format) I'd like to push it through.

Here's another youtube video, this one playing the Descent theme (using stereo, bank 2, possibly some other OPL3 features).

Re: FPGA implementation

PostPosted: Thu Jul 30, 2015 10:33 pm
by opl3
I tried the latest binary, it sounds very nice although I don't remember the original song (I have heard Descent..)

I have very little knowledge which songs use rhythm but the ones I have don't use it.

Try to search VGMPF for songs, but they may not have many in .DRO format. I have a crude .vgm player for DOS, but it's made in Turbo Pascal so I guess you can't use that much. I've been thinking I should rewrite some in C someday.

Re: FPGA implementation

PostPosted: Wed Aug 05, 2015 3:12 am
by synthop

Re: FPGA implementation

PostPosted: Fri Sep 18, 2015 8:26 am
by carbon14
Just watched the Descent video.


Good work.

Re: FPGA implementation

PostPosted: Sat Sep 19, 2015 2:10 am
by synthop
That means a lot man, thanks. Honestly I would not have gotten very far without all the time and effort you all put into reverse engineering this chip. Amazing work.