CSE467: Advanced Logic Design

Carl Ebeling, Winter 2004

Homework 5

Distributed: March 5 - Due Friday, March 12 (beginning of class)


1. Let’s return to the problem from HW #4 (copied below) and replace the registers with real registers that have setup and hold times and propagation delays. Use the following values for all the registers: Setup time = 2ns, Hold time = 1ns, Propagation delay = 3ns.

 

a) If you draw the data-flow graph directly from the code below, what is the minimum clock period that can be used?  Use the register parameters given above.

b) How do you change the max-ratio theorem so that it is still valid?  Explain why it still holds with your modifications.

c) What is the minimum theoretical clock period for this computation now that we have “real” registers?

d) Does the fact that we have real registers change the pipelining/retiming used to produce the fastest circuit?  Why can you still use your result from HW4?

e) What is the performance now for the optimally pipelined/retimed circuit?

 

Now assume that there can be arbitrary clock skew of up to 1ns. between any two registers. 

f) Does the original circuit (part a) still work?  Why/why not?

g) How fast can you now clock the optimally pipelined/retimed circuit?  Show how you get your answer.

*h) Can you use retiming to increase the amount of clock skew a circuit can tolerate?  Explain.

 

Below is a computation that is performed repeatedly on an input stream to produce an output stream.  Multiplies take 10ns. and adds and take 5ns.

     for (i=0;i<N;i++) {

        t1 = x[i] * t6;

        t6 = x[i] + t5;

        t2 = t1 * t6;

        t5 = t1 + t4;

        t4 = t2 + t3;

        t3 = t2 * t5;

        y[i] = t6;

      }

 


2. A very nice way to send data from one circuit to another that is running on a different clock is to place a FIFO between them.  The sender writes data into the FIFO using its clock, and the receiver reads data from the FIFO using its clock.  This should work fine because writing data into the FIFO clocks one counter (and the memory) while reading data from the FIFO clocks the other counter and the memory output is used combinationally.

a) Given below is the Verilog for a synchronous FIFO.  Modify this FIFO to make it into an asynchronous FIFO, i.e. a FIFO that has two clocks, one for the input port and one for the output port.  (Ignore problems that arise because of the two clocks – it will “mostly” work.)

 

b) The asynchronous FIFO that you have designed does not work because it uses two different clocks.  Describe precisely where these problems happen.

 

c) Now fix the asynchronous FIFO you designed so that it does work.  You will need to replace the normal counters used in the synchronous FIFO with gray-code counters.  (The Verilog for a gray-code counter is given below as well.)  Explain why you need to use gray-code counters?  (You do not need to simulate the resulting designs – simulation will not tell you if it works or not anyway!)

 

module sync_fifo(/*AUTOARG*/

  // Outputs

  full, data_out, empty,

  // Inputs

  clk, reset, data_in, dataValid, takingData

  );

  parameter ADDR_BITS = 3;

  parameter  MEM_DEPTH = 8;

  parameter  WIDTH = 32;

 

  input      clk;

  input      reset;

 

  input [WIDTH-1 :0] data_in;

  input          dataValid;

  output         full;

 

  output [WIDTH-1 :0] data_out;

  output         empty;

  input          takingData;

 

// FIFO head and tail pointers

  reg [ADDR_BITS-1:0] wr_ptr;

  wire [ADDR_BITS-1:0] wr_ptr_1;

  reg [ADDR_BITS-1:0] rd_ptr;

 

  // FIFO memory

  reg [WIDTH-1:0]     mem [0:MEM_DEPTH-1];

 

  //  Write pointer generation.

  //  It increments when there is a dataValid.

  //  It resets to zero if there is a reset

 

  // Share the + 1 with the full computation

  // (Synthesis should find this common expression though)

  assign wr_ptr_1 = wr_ptr + 1;

 

  always @ (posedge clk) begin

     if (reset)

       wr_ptr <= 0;

     else if (dataValid & !full)

       wr_ptr <= wr_ptr_1;

   end

 

//  Read pointer generation.

//  It increments when there is a takingData.

//  It resets to zero if there is a reset.

  always @ (posedge clk) begin

    if (reset)

      rd_ptr <= 0;

    else if (takingData & !empty)

      rd_ptr <= rd_ptr + 1;

  end

 

  assign full = (wr_ptr_1 == rd_ptr);

  assign empty = (rd_ptr == wr_ptr);

 

  // Read port

  assign data_out = mem[rd_ptr];

 

  // Write port

  always @ (posedge clk) begin

    if (dataValid && !full)

      mem[wr_ptr] <= data_in;

  end

 

endmodule

 

module gray_count (/*AUTOARG*/

  // Outputs

  gray_cnt, gray_nxt,

  // Inputs

  clk, reset, cnt_ena

  );

 

  parameter CNT_WIDTH = 4;

 

  input     clk;        // Clock input (Rising edge sampled)

  input     reset;            // System Reset - Asynchronous, Active Low

  input     cnt_ena;          // Count enable

 

  output [CNT_WIDTH-1:0] gray_cnt;// Count output

  output [CNT_WIDTH-1:0] gray_nxt;

 

  reg [CNT_WIDTH-1:0]    bin_cnt;// Binary counter - hidden state

 

  /*AUTOREG*/

  // Beginning of automatic regs (for this module's undeclared outputs)

  reg [CNT_WIDTH-1:0]   gray_cnt;

  // End of automatics

 

  // Convert binary count to gray code

  assign          gray_nxt = bin_cnt ^ {1'b0, bin_cnt[CNT_WIDTH-1:1]};

 

  always @(posedge clk) begin

    if (reset) begin

      bin_cnt  <= 1;

      // gray_cnt follows bin_cnt by a cycle

      gray_cnt <= 0;

    end else begin

      if (cnt_ena) begin

      bin_cnt  <= bin_cnt + 1;

      gray_cnt <= gray_nxt;

      end

    end

  end

 

endmodule