CSE467: Advanced Logic Design

Carl Ebeling, Winter 2004


Homework 3

Distributed: Jan. 23 - Due Monday, Feb. 2 (beginning of class)


1. For this problem, you will be writing a software program to prototype the algorithm that you will be implementing in hardware in Lab #5.  The problem is to generate a pure audio tone of varying frequencies.  We will be producing sound digitally by generating a stream of samples at a specific sample rate (44.1kHz). We will eventually be sending this audio stream to an audio codec that will generate the analog signal that will drive the speakers.  For now, we will write this stream to a file that can be converted to WAV and played on the computer.

We will start out using a “wavetable”, that is, a table of samples for the waveform we wish to produce.  Our waveform will be a sine wave, but we could make it any sound we want to generate.  To start with, our wavetable will have 512 16-bit entries that will describe a single complete wave, that is, 0-2p. If we generate these samples at the 44.1kHz sample rate, we will generate a tone with a frequency of 44100/512 = 86.133Hz since that is how many times we go through the table in one second.  Generating other frequencies requires going through the table faster (for higher frequencies) or slower (for lower frequencies).  That is, a 86.133Hz tone can be generated by using a simple counter that increments by 1 through the table one entry per 44.1kHz clock tick.

First find the formula for the increment amount for any desired output frequency.  We will not use floating-point, however, since this is quite complicated and expensive. Instead, we will use a fixed-point number for the wavetable address and add the increment, also a fixed-point number, to this address every cycle.  A fixed-point number has N bits in I.F format, that is, I bits to the left of the binary point and F to the right.  We could just use the rounded integer part of the index to address the wavetable, but this will introduce some error.  Thus we will use the fractional F bits to interpolate between two adjacent wavetable entries. 

Since the increment fixed-point number can only take on discrete values, we cannot generate all frequencies precisely.  How many fractional bits are needed for the index and increment if we want to generate all frequencies from 20Hz to 10kHz with an error of less than .1Hz?  Note that this is different from the error introduced by the limited number of bits used to represent each sample in the wavetable.

For the program below, the wavetable should contain 16-bit signed fractions that represent -1 <= x < 1.  That is, you will have to represent 1 as the largest fraction less than 1, i.e. 0111111111111111.  Write a program using the sin function and floating-point numbers to generate an include file that defines the 512-entry wavetable.  Your sound generation program should just include this file, and not use any floating-point numbers at all.

a) Give the formula for computing the increment from the desired frequency.

b) Decide on a fixed-point number format (I.F) and show how you determined this format.

c) Write a program that generates the frequencies 261.6, 293.7, 329.6, 349.2, 392.0, 440.0, 493.9, 523.2 in order, for one second each.  Write these samples to a file, one 16-bit number per line. (This will be a relatively large file: 9x44,000 entries)  Don’t use a large array to store the output – write the numbers as you generate them.  We will give you a program that will translate this file to a .WAV file that you play on your computer.  You may use any programming language you want.

d) Add a volume “knob” to your program that adjusts the volume linearly from 0 at 0 sec. to full volume at 5 sec. and back to 0 volume at 10 sec.

e) Change your program to play chords, e.g. the 1st, 3rd and 5th note together, for one second at a time. This means generating the samples for several notes simultaneously and adding them to form a composite signal.  Again, don’t use a large array to store the output – write the numbers as you generate them. Make sure you adjust the volume so that you don’t go over the maximum.

f) [Extra credit] Define an input format that allows your program to read music and play it. A simple format could just be a list of frequencies and durations.

2. Implement a FIFO module with the following interface using Verilog.

The DataValid/TakingData signals provide a simple and efficient protocol for communicating with a FIFO.  To write a value to the FIFO, the value is placed on DataIn and DataValidIn is asserted. If the FIFO is able to store the value, it asserts TakingDataIn on the same clock cycle. That is, a value is transferred to the FIFO if (DataValidIn&TakingDataIn). The FIFO always asserts TakingDataIn unless it is full.  The FIFO asserts DataValidOut if there is data in the FIFO – DataOut has the next value in the FIFO.  To remove this value, TakingDataOut is asserted; the next value, if there is one, will be available on the next cycle,  (If not, DataValidOut will be deasserted.)  Note that the FIFO value is available even if it is not being taken. Note also that the input and output interfaces are identical, which means that FIFOs can be connected back-to-back to make a larger FIFO.

The FIFO uses a dual-port memory (a Verilog example is given below) to store values.

 // Dual port memory
  wire [4:0] rd_addr, wr_addr;
  wire [7:0] data_in, data_out;
  reg [7:0] mem [0:31];   // 32 x 8 memory

  assign data_out = mem[rd_addr];
  always @ (posedge clk)
      if (we)  mem[wr_addr] <= data_in;

We will post the test-fixtures you should use to test the FIFO.  Turn in your Verilog files and the simulation console output from running the test fixtures.

 

 

 

 

 


ebeling@cs.washington.edu