Hi, Mick! Good progress so far.
Goal: create an FM-stereo test generator which can output either a composite stereo-audio signal (the usual commercial-FM subcarrier system), or an I/Q quadrature signal that can drive the generation of a 10.7 MHz IF signal which is frequency-modulated by the composite signal. The D-to-A step will be done by a fairly standard audio DAC like the one you sell, drive by I2S at 192000 samples/second.
Steps needed: generate at least four sinewaves - L and R channel audio, 38 kHz subcarrier, and 19 kHz pilot signal. Perform matrixing (create L+R and L-R), multiply L-R by 38 kHz subcarrier (creating a double-sideband suppressed-carrier signal), mix this with L+R and with the pilot tone. The amplitude of this composite signal then controls the phase advance of two more sinewaves (in quadrature) which will be output to the DAC and I/Q mixers (the mixer LO will eventually be a quadrature pair of 10.7 MHz squarewaves from the FPGA).
Gain controls are needed on all inputs. All signals should be low-noise low-distortion (near-CD-quality - no less than 14 bits).
Mighty scary for a first FPGA project… the angels might decide not to tread here, but I have nothing to lose in trying.
Lots of math required - minimum of six sinewaves to compute/interpolate, mixing and multiplying to create the composite signal, and a dash of TPDF dither thrown in to keep the distortions down. A big Vertex 7 might be able to do this by brute force, but if I tried it in the ICE40 I’d run out of gates or timing pretty quickly.
Fortunately the timing requirements aren’t bad… the bit clock will be under 7 MHz, and there are 32 clocks between each new set of 16-bit samples being needed. Brute force isn’t required. I can break the problem up into three or four separate processing pipelines (sinewave phase-advance, sinewave lookup/interpolation, multiplex-mixing, and frequency modulation). Each pipeline needs just one multiply-and-accumulate resource and a bunch of multiplexing logic for the inputs and outputs. I think I have enough cycles to handle a dozen sinewave test signals, not just two.
So - what’s working? I2S transmitter came first… quite easy. The sinewave pipeline came second - this uses one MAC and 16 of the BRAMs to make a couple of big register arrays. I’m getting 15 bits or so of effective resolution out of it.
I wrote the stereo multiplexer/mixer this week, and got it working in behavioral Verilog under iverilog a couple of days ago. The results look quite good.
Getting things to synthesize under yosys was interesting. The design did build, but it was using more logic cells (29%) and fewer SB16_MACs (1) than I expected. I dug into the JSON and source code, and found that the current version of yosys will infer the use of the hardware MAC only for an unsigned multiply (not the addition, and not any signed operations).
So, I rewrote that one step of the sinewave and multiplexer pipelines to use explicitly instantiated SB_MAC16 blocks. Once I figured out what configurations I wanted (controls, and registration-or-not) the design started working again in iverilog… and it now synthesizes using two DSP blocks, and only 12% of the logic cells. Looks like plenty of resources left for other things (the frequency modulator and phase advance, controls, multiple operating modes, and so forth).
I need to wire up my DAC board and actually hook it up to the Shasta and confirm that it can run at speed.
Attached is a plot of the composite-output signal (generated by iverilog $monitor) and an Audacity spectrum analysis. The test inputs are 440 and 1000 Hz audio signals (L and R).