Author Topic: FPGA VGA Controller for 8-bit computer  (Read 511005 times)

0 Members and 3 Guests are viewing this topic.

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3450 on: July 26, 2022, 07:30:39 pm »
Update 2 - now have commands to the PSG working.  Trace below shows a simple command being sent to the PSG to make it play a tone.

Nope, your command was for generating random noise at volume 14 out of 15....

Well... There is a bunch a junk to do.

1) You need to verify fix your clock pulse generator to my accurate one, add a second for the HDMI sample clock, add the linked example DC filter, create your own I2S serializer and test the PSG as is.

If sound is OK, we need to:

2) Make our own smarter DC filter which will allow no pops or DC but still allow low frequency sound by interpreting the bottom of the graph outperforming all other strategies.

4) Modify the PSG HDL's to Increase the depth of each channel from 8 bit to 12 bit.  The YM PSG uses a proper volumetric logarithmic DAC for 16 volume steps which needs to sound linear to the ear, but our hi-res audio DACS today are linear, so we need a few more bits for precision since the current design's first few volume steps are too loud and with a few repeats in the first 3 steps.

5) A proper 3 channel mixer which will deliver 16 bit full amplitude output and a ~12-15Khz low pass filter so that resampling the 1.78Mhz square wave samples to 48000Hz or 44100Hz will not produce really sharp spiky toned result when mixing high frequency tones.

6) Generate a new Github page with the enhanced project offering from input to the final I2S output with built in clock generators.

You wanted a 'ym2149_audio', now you will have the best sounding one.  Note that the YM2151 wouldn't need to DC filter or low pass filter as it makes proper AC waveforms at a full 16 bit.

(Note that I will rely on you to create me a sample 10khz tone with a few ramp settings.)
« Last Edit: July 27, 2022, 12:11:59 am by BrianHG »
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3451 on: July 27, 2022, 03:57:40 am »
 |O Ok, thanks to a bunch of unassigned power-up values in the jt49 source, his DC filter wont simulate unless I patch a bunch of regs assigning their default equal to '0'.

Here you go:



So, download this latest source, and you still need to read everything like I said 2 posts ago!!!

Next, fix the clocks, adding an I2S clock.
And make an I2S transmitter.

Now, I better see it being 1 or 2 if/else lines of code.  Plus a double latched DFF outputs.
Within this simulation.  It is that simple.
(You will need to see an I2S waveform example and also convert the signed input to unsigned.  Also, the HDMI IS has 4 dat inputs for 8 channel audio, just wire the 4 dats together)

Just so we are clear, in my floating point clock divider, my 'audio_ena' output is your strobe and my 'clk_audio' output is the 50/50 duty cycle clock signal.  Make 3 parameter inputs, CLK_IN_HZ, CLK_OUT_HZ, and USE_FLOATING_POINT.  The rest you should be able to figure out.
« Last Edit: July 27, 2022, 04:27:08 am by BrianHG »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #3452 on: July 27, 2022, 01:27:38 pm »
Ok, I got it working.

Take a look: (Note that I shrunk your clock divider from 56 down to 2 so that we see a waveform without having to simulate for 100s seconds before we see anything meaningful...)

Awesome! ;D

     Now, download my source code and read every line in the _tb.  You went way overboard with the coding.  This Verilog PSG source is easy to interface with and does NOT require you to time your commands.  You can send commands at a full 100MHz ignoring that clk_strobe timing and the PSG will registers them all.  This means all you had to do was feed an address and a data in parallel with the write strobe.

     In other words, use Z80 port #10 bottom 4 bits into the address, use Z80 port #11 into data, and use the data strobe of port #11, invert it, feed it to the the wr_n input.  To send a command, just write port 10 with the address 0-15, and then write port 11 with the data and you are done.  No delay, no waits, no absurd routine to generate that 8bit multiplexed bus timed to the clk_enable.

Wow, that's much simpler.  It'll mean I can remove some of the bridging interface from the GPU_DECA_top module and simplify the connection from Bridgette to the PSG massively. :-+

     Now, we have one new problem.  This PSG was designed with a cheap DC output,  the actual IC.  The HDL is just replicating it.  This is very bad for HiFi audio equipment, but good enough for a tiny PC speaker.  Like I said earlier, this problem would be solved with analog circuitry in the PC RF modulator, or output op-amp with nothing more than a wired series cap which blocks DC.  But with direct digital audio or a HiFi DAC which supports low frequencies, you could be sending frequencies below 10hz, or even below 1hz every time the sound starts and stops.  For this, we will need to add this software DC filter code (emulated that DC blocking series cap) to the 10bit 'sound' output:

https://github.com/jotego/jt49/tree/master/hdl/filter

I'll take a look later tonight as it has some extra unused components for simulation, not the way we would do it.  (And if we never simulated this chip, I would have never known and you would have potentially burned out someones expensive amp, burned out or popped out some unsuspecting user's expensive woofer/subwoofer.)

Yeah, I'll hang fire on testing the jt49 on the physical device for this reason; although it probably won't do much harm to the TV I'm using, I can hold off the excitement until we've got the filter working properly. ^-^
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3453 on: July 27, 2022, 05:29:47 pm »
Ok, I got it working.

Take a look: (Note that I shrunk your clock divider from 56 down to 2 so that we see a waveform without having to simulate for 100s seconds before we see anything meaningful...)

Awesome! ;D

     Now, download my source code and read every line in the _tb.  You went way overboard with the coding.  This Verilog PSG source is easy to interface with and does NOT require you to time your commands.  You can send commands at a full 100MHz ignoring that clk_strobe timing and the PSG will registers them all.  This means all you had to do was feed an address and a data in parallel with the write strobe.

     In other words, use Z80 port #10 bottom 4 bits into the address, use Z80 port #11 into data, and use the data strobe of port #11, invert it, feed it to the the wr_n input.  To send a command, just write port 10 with the address 0-15, and then write port 11 with the data and you are done.  No delay, no waits, no absurd routine to generate that 8bit multiplexed bus timed to the clk_enable.

Wow, that's much simpler.  It'll mean I can remove some of the bridging interface from the GPU_DECA_top module and simplify the connection from Bridgette to the PSG massively. :-+

     Now, we have one new problem.  This PSG was designed with a cheap DC output,  the actual IC.  The HDL is just replicating it.  This is very bad for HiFi audio equipment, but good enough for a tiny PC speaker.  Like I said earlier, this problem would be solved with analog circuitry in the PC RF modulator, or output op-amp with nothing more than a wired series cap which blocks DC.  But with direct digital audio or a HiFi DAC which supports low frequencies, you could be sending frequencies below 10hz, or even below 1hz every time the sound starts and stops.  For this, we will need to add this software DC filter code (emulated that DC blocking series cap) to the 10bit 'sound' output:

https://github.com/jotego/jt49/tree/master/hdl/filter

I'll take a look later tonight as it has some extra unused components for simulation, not the way we would do it.  (And if we never simulated this chip, I would have never known and you would have potentially burned out someones expensive amp, burned out or popped out some unsuspecting user's expensive woofer/subwoofer.)

Yeah, I'll hang fire on testing the jt49 on the physical device for this reason; although it probably won't do much harm to the TV I'm using, I can hold off the excitement until we've got the filter working properly. ^-^

 :-// Hun ?  I just showed you a proper working DC filter....
That output is already safe...  It's ready to test and go...  I just stated we can do better than anyone else out there in history.  I also stated that we can also make the tone a bit more pleasant to the ear.  For now, let's get some audio out with what we have immediately!

Next, change your clock divider to mine.  I literally sent you all the code to copy and paste.  You just need to rename a few things...  You should have done this first, but, here we are now.  Don't forget to leave proper credits at the top as we will be making a new Yamaha PSG repository with 4 wire direct drive to any modern I2S audio DACs and patching up the jt49 author's little mistakes.

Then, and for some reason you have been avoiding like a plague, we will make an I2S transmitter and get your sound working.  We will do this code live on this thread as it is too easy and you will be baffled at your confusion.

Just pm me when you will be around and everything in this post should take less than an hour.

(Since I never owned a YM2149, I only looked at its data sheet, wrote a moving tone ramp, saw a result in Modelsim similar to a scope shot in the data sheet and assumed its OK.  You will need to be the judge here.  It only 3 x 12bit oscillators with 1 bit output, IE counters with the top MSB flipping a 1 bit as an output + another 16bit counter for tied to a 5bit counter for the volume ramping.  If you had the time, it looks like you could have programmed your own. )
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3454 on: July 28, 2022, 04:10:54 am »


Ok, here is the I2S audio data sheets.

     For the TI part, it only supports the 32 clocks or more per channel, IE 64 clocks per stereo sample.  So we need our own I2S transmitter.  You can also see the HDMI transmitter can do both the 16 and 32 clocks per channel, so we will create a 32 clocks per channel transmitter so that a single I2S output can drive both ICs in parallel.

     Now, the TI audio codec DAC also requires a separate MCLK from the I2S buss' SCLK, LRCLK and I2SDATA.  You also see it has an internal PLL which can operate at the our new SCLK frequencies (see red notes).  If using our SCLK to feed the MCLK in parallel is too jittery for good DAC performance based on it being a fractional divide of our core 100 MHz clock, then we can use a pll to generate & feed a 12 MHz or 16 MHz clock for the MCLK while the SCLK is allowed to run independently.

Also, we now can send 24bit audio...
« Last Edit: July 28, 2022, 05:17:41 am by BrianHG »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #3455 on: July 28, 2022, 08:02:09 am »
Yeah, I'll hang fire on testing the jt49 on the physical device for this reason; although it probably won't do much harm to the TV I'm using, I can hold off the excitement until we've got the filter working properly. ^-^

 :-// Hun ?  I just showed you a proper working DC filter....

Oh sorry, must have misunderstood your post then - I though we still had to add the filter in.

That output is already safe...  It's ready to test and go...  I just stated we can do better than anyone else out there in history.  I also stated that we can also make the tone a bit more pleasant to the ear.  For now, let's get some audio out with what we have immediately!



Next, change your clock divider to mine.  I literally sent you all the code to copy and paste.  You just need to rename a few things...  You should have done this first, but, here we are now.  Don't forget to leave proper credits at the top as we will be making a new Yamaha PSG repository with 4 wire direct drive to any modern I2S audio DACs and patching up the jt49 author's little mistakes.

Righto.  You mean the floating point divider?  I had a look at that and there were parameter references that I had to copy from the HDMI serialiser that were linked to other parameters which were themselves linked to blocks of HDL that just made it all a bit of a rat's nest.  I certainly didn't interpret it as a 'simple copy and paste', but I was probably overthinking something as usual.

Then, and for some reason you have been avoiding like a plague, we will make an I2S transmitter and get your sound working.  We will do this code live on this thread as it is too easy and you will be baffled at your confusion.

I just haven't needed it - I can hear the audio fine through the TV, having a set of headphones lying around as well just added another cable to the spaghetti on my desk already. ;)

Just pm me when you will be around and everything in this post should take less than an hour.

Okay, will do - tomorrow's looking good at the moment.  Will PM you with more details.

(Since I never owned a YM2149, I only looked at its data sheet, wrote a moving tone ramp, saw a result in Modelsim similar to a scope shot in the data sheet and assumed its OK.  You will need to be the judge here.  It only 3 x 12bit oscillators with 1 bit output, IE counters with the top MSB flipping a 1 bit as an output + another 16bit counter for tied to a 5bit counter for the volume ramping.  If you had the time, it looks like you could have programmed your own. )

Yeah, I was amazed how simple the HDL for the PSG was.  The problem is, music/audio is more a dark art to me than electronics ever was.  All this talk of envelopes, sustains, attack/decay etc makes me want to run for the hills. :scared:  One of the reasons I wanted to emulate the AY-8910 chip was that it was familiar to me (in the sense I'd 'used one before' in my first computer) and I had some software in CP/M that could play some tunes to test on it.  Writing my own PSG, or using some other PSG (note the YM2149 is, to all intents and purposes, the same as the AY-891x chips) would have meant a huge problem with finding test music to run on it.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #3456 on: July 28, 2022, 08:13:43 am »
:-// Hun ?  I just showed you a proper working DC filter....

Just realised, I've somehow missed an entire post of yours at the top of this page.  That's how I'd didn't know about the working DC filter.  I'll download that code and work from that.  ::)
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3457 on: July 28, 2022, 03:01:25 pm »
Quote
Righto.  You mean the floating point divider?  I had a look at that and there were parameter references that I had to copy from the HDMI serialiser that were linked to other parameters which were themselves linked to blocks of HDL that just made it all a bit of a rat's nest.  I certainly didn't interpret it as a 'simple copy and paste', but I was probably overthinking something as usual.

Actually, it is a copy and paste.

You just need to create the CLK input and 2 outputs, then assign the signals in my code to them or just name the IOs accordingly.
Also, one again, just make the 3 parameters I requested.  Then either rename the parameters in my localparams to the new names, or, make 3 additional localparams which has the OLD_LOCAL_PARAM names = NEW_PARAMETER_INPUTS.

And the code should work.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #3458 on: July 28, 2022, 03:10:36 pm »
Actually, it is a copy and paste.

You just need to create the CLK input and 2 outputs, then assign the signals in my code to them or just name the IOs accordingly.
Also, one again, just make the 3 parameters I requested.  Then either rename the parameters in my localparams to the new names, or, make 3 additional localparams which has the OLD_LOCAL_PARAM names = NEW_PARAMETER_INPUTS.

And the code should work.

:o Okay, I think I'm taking your previous post too literally then.  I need to copy the entire module, rather than just the code snippet you quoted in that post, as there's no way that snippet of code will work without defining what PLL1_OUT_TRUE_HZ and HDPLL_AUDIO_HZ are, amongst others?

In other news, I've just had a spare five minutes to wire the jt49 module (and DC filter!) into the GPU module and briefly test it.  It produces the best sounds yet. :-+

 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3459 on: July 28, 2022, 03:17:54 pm »
Code: [Select]
Yeah, I was amazed how simple the HDL for the PSG was.  The problem is, music/audio is more a dark art to me than electronics ever was.  All this talk of envelopes, sustains, attack/decay etc makes me want to run for the hills. :scared:  One of the reasons I wanted to emulate the AY-8910 chip was that it was familiar to me (in the sense I'd 'used one before' in my first computer) and I had some software in CP/M that could play some tunes to test on it.  Writing my own PSG, or using some other PSG (note the YM2149 is, to all intents and purposes, the same as the AY-891x chips) would have meant a huge problem with finding test music to run on it.
The YM2149 is a piece of (... well lets just call is an old 3 channel 1 bit audio device ...).  You can make a total of 3 tones, each a square or noise.  Each with a frequency period.  Each with a 5bit volume.  The envelope (a single envelope for all 3 channels) is an auto volume ramp with speed select for fade in, fade out, modulate up and down, and repeat.

The YM2151 looks much better (again, I linked to the IC's .pdfs and verilog source code a few posts back).  It has 8 channels.  Each channel you can select sine, square, triangle, saw, or noise.  The period/pitch of the sound.  The attach time (envelope volume up speed to an initial peak) for when you turn on the note, the sustain time, constant volume after the attach peak while you keep the note on, and decay time, the envelope volume fate out time of the note once you turned off your note.  As you can see, this chip has controls and responds a whole lot more like a real 8 channel midi instrument.  Set your parameters for each of the 8 instrument, then just feed the 8 channels with notes and let the IC worry about the fancy volume envelopes.
« Last Edit: July 28, 2022, 03:31:58 pm by BrianHG »
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3460 on: July 28, 2022, 03:20:29 pm »
Actually, it is a copy and paste.

You just need to create the CLK input and 2 outputs, then assign the signals in my code to them or just name the IOs accordingly.
Also, one again, just make the 3 parameters I requested.  Then either rename the parameters in my localparams to the new names, or, make 3 additional localparams which has the OLD_LOCAL_PARAM names = NEW_PARAMETER_INPUTS.

And the code should work.

:o Okay, I think I'm taking your previous post too literally then.  I need to copy the entire module, rather than just the code snippet you quoted in that post, as there's no way that snippet of code will work without defining what PLL1_OUT_TRUE_HZ and HDPLL_AUDIO_HZ are, amongst others?

In other news, I've just had a spare five minutes to wire the jt49 module (and DC filter!) into the GPU module and briefly test it.  It produces the best sounds yet. :-+

Yes, I wasn't joking... Take it literally...  That is the entire program.

Just copy the test code text in my post on the previous page.
All it needs is the clk in, clk out, and strobe out.
3 parameters in, INPUT_CLK_IN_HZ, OUTPUT_CLK_IN_HZ, and USE_FLOATING_POINT_PRECISION_DIVIDE.

Or, whatever names you choose, or just use the names in my code snipet.
« Last Edit: July 28, 2022, 03:22:18 pm by BrianHG »
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3461 on: July 28, 2022, 03:27:45 pm »
Look:

parameter INPUT_CLK_HZ = 100000000 ;
parameter OUTPUT_CLK_HZ = 3579545 ;
parameter USE_FLOATING_DIVIDE = 1 ;

Now, this:
Code: [Select]
localparam bit [63:0] aud_per_x4096  = PLL1_OUT_TRUE_HZ*4096/HDPLL_AUDIO_HZ ;                               // Determine the audio period 4096 fold.
localparam bit [63:0] aud_per_round  = aud_per_x4096 + 2048 ;                                               // Prepare a rounded version.
localparam bit [12:0] aud_per_int    = HDPLL_AUDIO_TCK_FLOAT ? aud_per_x4096[24:12] : aud_per_round[24:12]; // Select between the rounded integer period or true integer period.
localparam bit [11:0] aud_per_f      = HDPLL_AUDIO_TCK_FLOAT ? aud_per_x4096[11:0]  : 12'd0  ;              // select between no floating point and floating point adjusted audio clock generation.
localparam bit [63:0] aud_tru_hz     = PLL1_OUT_TRUE_HZ*4096 / (aud_per_int*4096+aud_per_f)  ;              // Calculate the true audio output clock based on oscilator frequencies & HDPLL_AUDIO_TCK_FLOAT settings.

Changes to this:
Code: [Select]
localparam bit [63:0] aud_per_x4096  = INPUT_CLK_HZ*4096/OUTPUT_CLK_HZ ;                               // Determine the audio period 4096 fold.
localparam bit [63:0] aud_per_round  = aud_per_x4096 + 2048 ;                                               // Prepare a rounded version.
localparam bit [12:0] aud_per_int    = USE_FLOATING_DIVIDE ? aud_per_x4096[24:12] : aud_per_round[24:12]; // Select between the rounded integer period or true integer period.
localparam bit [11:0] aud_per_f      = USE_FLOATING_DIVIDE ? aud_per_x4096[11:0]  : 12'd0  ;              // select between no floating point and floating point adjusted audio clock generation.
localparam bit [63:0] aud_tru_hz     = INPUT_CLK_HZ*4096 / (aud_per_int*4096+aud_per_f)  ;              // Calculate the true audio output clock based on oscillator frequencies & USE_FLOATING_DIVIDE settings.

How hard was that?

You can also rename all the ' aud_ ' to ' clk_out_ ' to make things read even better.

The 2 assigns after that are useless.
The in the code, just rename the clk in and 2 output strobes as I specified earlier.
« Last Edit: July 28, 2022, 03:31:10 pm by BrianHG »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #3462 on: July 28, 2022, 03:48:10 pm »
Okay, so the testbench is showing a final value of 7159, which is okay I guess considering the simulation runs for 2000ns and the requested output is 3579545 Hz?
« Last Edit: July 28, 2022, 04:20:09 pm by nockieboy »
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3463 on: July 28, 2022, 03:58:39 pm »
Okay, so the testbench is showing a final value of 7159, which is okay I guess considering the simulation runs for 2000ns and the requested output is 3579545 Hz?

If you are not sure, run the sim for 1 second, or 0.1 second if you do not want to wait.  You may need to wait for 2 minutes, but you will see the true Hz.
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3464 on: July 28, 2022, 04:01:29 pm »
Okay, so the testbench is showing a final value of 7159, which is okay I guess considering the simulation runs for 2000ns and the requested output is 3579545 Hz?
:palm: You attached the wrong code...
That one still has your old divider.
And, already 3 have downloaded the error code...
« Last Edit: July 28, 2022, 04:09:59 pm by BrianHG »
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3465 on: July 28, 2022, 04:13:25 pm »
@nockieboy, do you know how much you are costing me in Haagen-Dazs and an increasing waist-line?
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #3466 on: July 28, 2022, 04:22:29 pm »
@nockieboy, do you know how much you are costing me in Haagen-Dazs and an increasing waist-line?

Whuh?  No idea how that happened.  I'll try again here - don't know if it was the forum messing me about, but attaching the zip file to that last post just seemed to link to the old copy again.  :-//

EDIT: I've double-checked - it's the right zip file.
« Last Edit: July 28, 2022, 04:24:18 pm by nockieboy »
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3467 on: July 28, 2022, 04:54:13 pm »
Ok, it's because yo used a new source code name, not entering my code into your divider.

Ok, the analysis...

In jt49_tb.sv, You should have:
Code: [Select]
`timescale 1 ns/1 ns

localparam  CLK_IN_HZ  = 100000000                   ; // Frequency of simulated clock
localparam  CLK_PSG_HZ = 1789000                     ; // PSG of simulated clock
localparam  CLK_I2S_HZ = 3072000                     ; // I2S bit clock rate of simulated clock

localparam  CLK_PERIOD = 1000000000/CLK_IN_HZ        ; // Period of simulated clock.
localparam  CMD_COUNT  = 8                           ; // Number of commands to send to PSG.
localparam  ENDTIME    = (1000 * 1000 * 10) + 20     ; // Number of ns to stop simulation at.

and, you should have: (Just download the attached new tb source)
Code: [Select]
    // Instantiate DUT
    fp_div #(
   
    .INPUT_CLK_HZ  (CLK_IN_HZ ),
    .OUTPUT_CLK_HZ (CLK_PSG_HZ)
   
    ) DUT (

        .clk_in     ( clk   ), // source clock for strobe (divided by DIVISOR if >1)
        .clk_out    ( p_div ), // divided clock 50:50 duty cycle output
        .strobe_out ( p_stb )  // divided clock strobe output

    );

Now, after simulating and inspecting both the waveform and the 'DUT' module to see it's registers, we see:


You can see a simulation of 0.01 seconds of real time gives us a result of 17890 just prior to the 0.01 second mark and my localparam of 'aud_tru_hz' is 1789005, in other words, 5hz too fast.

So, your integer divider was set to 56, IE 100000000/56 = 1785714hz, 3286Hz too slow.

We can still do better, lets modify my code to go from 12bit float to 16bit float to iron out that last bit of error.
« Last Edit: July 28, 2022, 05:40:13 pm by BrianHG »
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3468 on: July 28, 2022, 05:14:55 pm »
Ok, after the 12 to 16 bit floating accumulator change, we see this:


A tighter timing at the 0.01 second mark and aud_tru_hz reports that if we simulated for 1 full second, we would have 1789000Hz.  Though, we do not see the fractions after the last Hz, so we can say this output will be within dead perfect to 0.999999Hz faster than the readout instead of the 12bit version output which would be anywhere from +5.0000 to +5.999999Hz too fast.

Just download the attache source code changes and lets next develop the I2S transmitter.

(Separate sim project as we will first replicate the DECA's HDMI demo 1Khz sine wave with our I2S transmitter, but now using our new clock divider instead of the old DECA pll design, running off of one of my simple 1080p video out demos.)
 
The following users thanked this post: nockieboy

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3469 on: July 28, 2022, 06:09:53 pm »
Ok, after a billion ns of simulated runtime, IE: 1 second, with the new 16bit float, we can now see that the oscillator is only around 0.25hz to fast compared to the requested hz, not 3286Hz too slow when using an integer only clock divider.



Next, I will make a quick-sim patch as simulating a second can be done much faster for testing the PSG.
« Last Edit: July 28, 2022, 06:11:52 pm by BrianHG »
 
The following users thanked this post: nockieboy

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3470 on: August 02, 2022, 07:25:48 pm »
Ok Nockieboy, here is your serializer hint:

module name I2S_transmitter.

Parameter int BITS         = 16  // Audio width, can be anything from 8 to 24...
Parameter bit INV_BCLK = 0   // When set, make I2S_BCLK fall during valid data...

Inputs:
clk_in              // High speed clock.
clk_i2s            // 50/50 duty cycle serial audio clock to feed through.
clk_i2s_pulse  // Should pulse for one clk_in cycle at the beginning of each new clk_i2s.

sample_in                    // Optional input to reset the sample position.  This should either be tied to GND or only pulse once every 64 'clk_i2s_pulse's.
[BITS-1:0] DAC_Left    // Left channel digital audio sampled once every 'sample_pulse' output.
[BITS-1:0] DAC_Right  // Right channel digital audio sampled once every 'sample_pulse' output.

Outputs:
reg sample_pulse   // Pulses once when a new stereo sample is taken from the DAC_Left/Right inputs.  Hint: once every 64 clk_i2s_pulse's.
reg I2S_BCLK    // I2S serial bit clock output, basically the clk_i2s input in the correct phase.
reg I2S_WCLK  // I2S !left/right output.
red I2S_DATA  // Serial data output.

This is all we need this module to do.
Since we have 64 clock pulses there will be obviously one 6 bit reg counter.
I expect a serial shift out register plus a second register to buffer the right DAC input.
The code should be a few embedded if(), 1 for the main counter, one for the serial load/shifter, and a last reg buffering the output regs.

Lets see what you can come up with.
We will copy/rename the PSG and make a new module testing the serializer with our fp_divider driving the serializer to show our I2S output in the waveform view.  The left and right inputs should be created in the _tb module.
 
« Last Edit: August 02, 2022, 07:34:59 pm by BrianHG »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #3471 on: August 03, 2022, 01:52:47 pm »
Ok Nockieboy, here is your serializer hint:

module name I2S_transmitter.

Parameter int BITS         = 16  // Audio width, can be anything from 8 to 24...
Parameter bit INV_BCLK = 0   // When set, make I2S_BCLK fall during valid data...

Inputs:
clk_in              // High speed clock.
clk_i2s            // 50/50 duty cycle serial audio clock to feed through.
clk_i2s_pulse  // Should pulse for one clk_in cycle at the beginning of each new clk_i2s.

sample_in                    // Optional input to reset the sample position.  This should either be tied to GND or only pulse once every 64 'clk_i2s_pulse's.
[BITS-1:0] DAC_Left    // Left channel digital audio sampled once every 'sample_pulse' output.
[BITS-1:0] DAC_Right  // Right channel digital audio sampled once every 'sample_pulse' output.

Outputs:
reg sample_pulse   // Pulses once when a new stereo sample is taken from the DAC_Left/Right inputs.  Hint: once every 64 clk_i2s_pulse's.
reg I2S_BCLK    // I2S serial bit clock output, basically the clk_i2s input in the correct phase.
reg I2S_WCLK  // I2S !left/right output.
red I2S_DATA  // Serial data output.

This is all we need this module to do.
Since we have 64 clock pulses there will be obviously one 6 bit reg counter.
I expect a serial shift out register plus a second register to buffer the right DAC input.
The code should be a few embedded if(), 1 for the main counter, one for the serial load/shifter, and a last reg buffering the output regs.

Lets see what you can come up with.
We will copy/rename the PSG and make a new module testing the serializer with our fp_divider driving the serializer to show our I2S output in the waveform view.  The left and right inputs should be created in the _tb module.

Okay, so something like the attached file?  I haven't had the time to test it in ModelSim yet, so it's barely more than pseudo-code - but is it going in the right direction? ???
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3472 on: August 03, 2022, 02:27:22 pm »
Ok, that's one way to go about it.

Your:
Code: [Select]
            I2S_DATA     <= DAC_Buffer[ bitcounter ] ;Is valid, but the extra addressing and position counter wont hamper anything at this rate, but the clues of a serial shift register.  For now, just a simple logic error on your part here:

Code: [Select]
        // Strobe sample_pulse once every 64 cycles & sample appropriate L/R input
        if ( I2S_counter == 0 ) begin

            DAC_Buffer   <= DAC_Left  ;
            sample_pulse <= 1'b1      ;
            bitcounter   <= ~0        ; // set bitcounter to all 1's
            I2S_WCLK     <= LEFT      ;

        end else if ( I2S_counter == 32 ) begin

            DAC_Buffer   <= DAC_Right ;  <<<<<<
            sample_pulse <= 1'b1      ;     <<<<<< REMEMBER, we want to do 1 stereo sample every 64 clocks.
            bitcounter   <= ~0        ; // set bitcounter to all 1's
            I2S_WCLK     <= RIGHT     ;
       
        end else begin

Ok, let's take a look at a simpler serial shifter.
Some other changes is that everything except the I2S_BCLK is now inside the 'if ( clk_i2s_pulse ) begin':

Code: [Select]
// Initial I2S_transmitter code, untested, by nockieboy August 2022.

module I2S_transmitter #(

    parameter int           BITS     = 16,  // Audio width, can be anything from 8 to 24
    parameter bit           INV_BCLK = 0    // When set, make I2S_BCLK fall during valid data

)(

    //Inputs
    input  logic            clk_in,         // High speed clock
    input  logic            clk_i2s,        // 50/50 duty cycle serial audio clock to feed through
    input  logic            clk_i2s_pulse,  // Should strobe for one clk_in cycle at the beginning of each new clk_i2s
    input  logic            sample_in,      // Optional input to reset the sample position.  This should either be tied to GND or only pulse once every 64 'clk_i2s_pulse's
    input  logic [BITS-1:0] DAC_Left,       // Left channel digital audio sampled once every 'sample_pulse' output
    input  logic [BITS-1:0] DAC_Right,      // Right channel digital audio sampled once every 'sample_pulse' output

    //Outputs
    output logic            sample_pulse,   // Pulses once when a new stereo sample is taken from the DAC_Left/Right inputs.  Hint: once every 64 clk_i2s_pulse's
    output logic            I2S_BCLK,       // I2S serial bit clock output (SCLK), basically the clk_i2s input in the correct phase
    output logic            I2S_WCLK,       // I2S !left / right output (LRCLK)
    output logic            I2S_DATA        // Serial data output

);

    logic              [5:0] I2S_counter       <= 0 ;
    logic         [BITS-1:0] DAC_right_buffer  <= 0 ;
    logic         [BITS-1:0] DAC_serial_buffer <= 0 ;

    // Since I2S uses 64 clock pulses, we need one 6-bit reg counter.
    // I expect a serial shift out register plus a second register to buffer the right DAC input.
    // The code should be a few embedded if(), 1 for the main counter, one for the serial load/shifter,
    // and a last reg buffering the output regs.

    // We will copy/rename the PSG and make a new module testing the serializer with our fp_divider driving
    // the serializer to show our I2S output in the waveform view.  The left and right inputs should be
    // created in the _tb module.


assign I2S_WCLK = I2S_counter[5] ;             // Hard wire the I2S Word Clock to the I2S_counter MSB.
assign I2S_DATA = DAC_serial_buffer [BITS-1] ; // Hard wire the I2S serial data bits to the MSB of the serial data buffer.

  always_ff @( posedge clk_in ) begin

    // Optional Invert clk_i2s for correct I2S_BCLK phase
    I2S_BCLK <= clk_i2s ^ !INV_BCLK ;

        // Manage I2S pulse counter and serialisation
    if ( clk_i2s_pulse ) begin

            if (sample_in) I2S_counter  <= 0               ; // Optional clear to I2S counter position '0'
            else           I2S_counter  <= I2S_counter + 1 ;


            sample_pulse       <= ( I2S_counter == 0 )     ; // Pulse the output reference sample clock.

        // Strobe sample_pulse once every 64 cycles & sample appropriate L/R input
        if ( I2S_counter == 0 ) begin

            DAC_right_buffer   <= DAC_Right              ; // Keep a copy of the Right channel data to be transmitted during the second half.
                                                           // This was done to make sure both left and right channel data are captured in parallel on the same clock.

            DAC_serial_buffer  <= DAC_LEFT               ; // Transfer the left channel for immediate transmission.

        end else if ( I2S_counter == 32 ) begin

            DAC_serial_buffer  <= DAC_right_buffer       ; // Transfer the right channel's sample for immediate transmission.
       
        end else begin

            DAC_serial_buffer  <= DAC_serial_buffer << 1 ; // Left shift the serial out data.

        end


    end // if ( clk_i2s_pulse ) begin
  end // always

endmodule

This code should do it.  If it simulates ok, we will test wire in this sine-table with counter to verify that you still hear a clean sine tone once wired into the HDMI output project.
« Last Edit: August 03, 2022, 02:33:30 pm by BrianHG »
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8144
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #3473 on: August 03, 2022, 02:32:23 pm »
Don't forget this sine table code:
Code: [Select]
module Sine_1KHz_16b_48ksps (

input  logic               clk,
    input  logic               clk_ena,
output logic signed [15:0] audio
);

logic [5:0] sam_pos;

always_ff @(posedge clk) begin

  if (clk_ena) begin

    if   (sam_pos==6'd47) sam_pos <= 6'd0 ;
    else                  sam_pos <= sam_pos + 1'b1 ;

// 48 word sine table.
if (sam_pos==6'd0) audio <= 16'(0);
if (sam_pos==6'd1) audio <= 16'(4276);
if (sam_pos==6'd2) audio <= 16'(8480);
if (sam_pos==6'd3) audio <= 16'(12539);
if (sam_pos==6'd4) audio <= 16'(16383);
if (sam_pos==6'd5) audio <= 16'(19947);
if (sam_pos==6'd6) audio <= 16'(23169);
if (sam_pos==6'd7) audio <= 16'(25995);
if (sam_pos==6'd8) audio <= 16'(28377);
if (sam_pos==6'd9) audio <= 16'(30272);
if (sam_pos==6'd10) audio <= 16'(31650);
if (sam_pos==6'd11) audio <= 16'(32486);
if (sam_pos==6'd12) audio <= 16'(32767);
if (sam_pos==6'd13) audio <= 16'(32486);
if (sam_pos==6'd14) audio <= 16'(31650);
if (sam_pos==6'd15) audio <= 16'(30272);
if (sam_pos==6'd16) audio <= 16'(28377);
if (sam_pos==6'd17) audio <= 16'(25995);
if (sam_pos==6'd18) audio <= 16'(23169);
if (sam_pos==6'd19) audio <= 16'(19947);
if (sam_pos==6'd20) audio <= 16'(16383);
if (sam_pos==6'd21) audio <= 16'(12539);
if (sam_pos==6'd22) audio <= 16'(8480);
if (sam_pos==6'd23) audio <= 16'(4276);
if (sam_pos==6'd24) audio <= 16'(-1);
if (sam_pos==6'd25) audio <= 16'(-4277);
if (sam_pos==6'd26) audio <= 16'(-8481);
if (sam_pos==6'd27) audio <= 16'(-12540);
if (sam_pos==6'd28) audio <= 16'(-16384);
if (sam_pos==6'd29) audio <= 16'(-19948);
if (sam_pos==6'd30) audio <= 16'(-23170);
if (sam_pos==6'd31) audio <= 16'(-25996);
if (sam_pos==6'd32) audio <= 16'(-28378);
if (sam_pos==6'd33) audio <= 16'(-30273);
if (sam_pos==6'd34) audio <= 16'(-31651);
if (sam_pos==6'd35) audio <= 16'(-32487);
if (sam_pos==6'd36) audio <= 16'(-32767);
if (sam_pos==6'd37) audio <= 16'(-32487);
if (sam_pos==6'd38) audio <= 16'(-31651);
if (sam_pos==6'd39) audio <= 16'(-30273);
if (sam_pos==6'd40) audio <= 16'(-28378);
if (sam_pos==6'd41) audio <= 16'(-25996);
if (sam_pos==6'd42) audio <= 16'(-23170);
if (sam_pos==6'd43) audio <= 16'(-19948);
if (sam_pos==6'd44) audio <= 16'(-16384);
if (sam_pos==6'd45) audio <= 16'(-12540);
if (sam_pos==6'd46) audio <= 16'(-8481);
if (sam_pos==6'd47) audio <= 16'(-4277);

  end
end
endmodule
 
The following users thanked this post: nockieboy

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #3474 on: August 03, 2022, 02:48:21 pm »
Code: [Select]
           sample_pulse       <= ( I2S_counter == 0 )     ; // Pulse the output reference sample clock.

Just a quick question about the quoted line of code above.  Would the following also be a valid method of testing for a zero value?

Code: [Select]
sample_pulse <= ( !I2S_counter ) ;
And if so, which would be best and why? :-//
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf