[Open-graphics] OGA1 mad dash: What's left

Farhan Mohamed Ali farhan at cmu.edu
Sun Dec 30 06:02:31 EST 2007


Attached is an updated version of the arbiter from SVN, fixed a few 
syntax errors (missing declarations, assign statements for regs, etc).

I have a few questions about the load mode register part for now, can 
you explain what this part does in more detail, and i have a few 
specific questions about the code, which i ask below:

    // Config regs and load mode register (lmr)
    reg [14:0] 		   lmr_data;
    reg [3:0] 		   lmr_delay;
    reg 			   lmr_addr;
    reg [10:0] 		   refresh_delay;
    reg 			   refresh_enable;
    reg [1:0] 		   lmr_write; // missing, added
***is the lmr_write reg only 2 bits?***


    always @(posedge reg_clock or negedge reset_) begin
       if (!reset_) begin
          lmr_write[0] <= 0;
          lmr_write[1] <= 0;
          lmr_data <= 0;
       end else begin
          lmr_write[0] <= lmr_write[0] >> 1;
          lmr_write[1] <= lmr_write[1] >> 1;
***does the right shift do anything here? seems to me like it's just 
copying back the same value***


          if (reg_do_write) begin
             case (reg_addr[1:0])
               0: begin
                  lmr_data <= reg_data;
                  lmr_delay <= 4'b1110;
                  lmr_addr <= 0;
               end
               2: begin
                  lmr_addr <= 1;
                  lmr_delay <= 4'b1110;
               end
               3: {refresh_enable, refresh_delay} <= reg_data;
             endcase
          end
       end
    end


    reg last_lmr_delay;
    reg do_lmr;

    always @(posedge clock) begin
       last_lmr_delay <= lmr_delay[0];
       do_lmr <= !last_lmr_delay && lmr_delay[0];
    end
***the value of lmr_delay doesn't seem to change from 4'b1110, so do_lmr 
  value doesn't change? is there a shift register missing?***


Timothy Normand Miller wrote:
> Ok, maybe the arbiter itself hasn't changed that much.  In any case,
> just work from the version in SVN.
> 
> Thanks.
> 
> On 12/29/07, Farhan Mohamed Ali <farhan at cmu.edu> wrote:
>> I have looked in the SVN. Looks the same as the one in the "Draft of
>> arbiter" post on the mailing list. This is the latest version, correct?
>>
>> Timothy Normand Miller wrote:
>>> It has changed massively.  Please check out a copy from SVN.
>>>
>>> Thank you for your help.  The arbiter is mostly done, so you just need
>>> to make sense of it and make sure it makes sense.  :)
>>>
>>>
>>> On 12/28/07, Farhan Mohamed Ali <farhan at cmu.edu> wrote:
>>>> I've started looking at the arbiter. I have about 2 weeks to work on it,
>>>> so i'll be able to get some useful work done. Has it been changed or
>>>> updated since the very first version you posted on the mailing list?
>>>>
>>>> -Farhan
>>>>
>>>> Timothy Normand Miller wrote:
>>>>> There are a handful of things left to code.  Some of these are the
>>>>> sorts of things that Howard is best suited for.  Those include clock
>>>>> managers and constraints files.  The XP10 top level is basically done,
>>>>> and Howard will be sending me some code this week.
>>>>>
>>>>> The S3 still needs work.  I've been trying to get some people to help
>>>>> me check the connections, but no one's reported anything to me.
>>>>> Wiring top levels (getting the wire instances right and stuff) are my
>>>>> greatest weakness.  This is where I make the most mistakes.  This kind
>>>>> of checking has to be done first.  Right now, I have one memory
>>>>> controller and one video controller wired up.  After the checking, we
>>>>> can wire up the remaining 3 memory controllers and 1 video controller
>>>>> (along with the output blocks), and check it again.  Still, there will
>>>>> be details that remain to be fixed.
>>>>>
>>>>> Finally, we need to create a simulation wrapper that binds together
>>>>> the two FPGA top levels, a PCI master that is in the repository, and
>>>>> some test code that tries out various basic functions like accessing
>>>>> memory and scanning out a video frame.  This too falls squarely into
>>>>> where-I-suck territory and would be done much quicker and better by
>>>>> someone with far greater talent with this kind of detail.
>>>>>
>>>>> The break is nearing its end, and I need help with these things.  The
>>>>> next step after that is synthesis and fixing things to meet timing.
>>>>> Those are things I'm good at.  It would be best if we can get this
>>>>> simulation stuff done before classes start before we work on
>>>>> synthesis.
>>>>>
>>>
>>
> 
> 
-------------- next part --------------


// There will be four instances of this arbiter, one for each memory 
// controller.


/*
Notes:
    It will become an issue later that there is no way to throttle
    the return data coming from the memory controller.  A variety
    of solutions exist, one of which is to count the outstanding
    requests for a given agent and never submit more than can be
    accepted by the return queue.
    
    This is not a problem for video, as its huge return queue will
    never fill.
    
Addresses:
    All addresses refer to 64-bit words

    
LMR:
    To load the mode register, first ensure that refresh is disabled.
    Check the spec for the DRAMs for required delays, which must be 
    enforced by software.
    A precharge command must be issued (reg 2).
    Then LMR or LMR-extended (reg 0) can be issued.
*/

module arbiter(
	       input clock,
	       input reset_,
    
	       // Config interface
	       input reg_clock,
	       input [2:0] reg_addr,
	       input [31:0] reg_data,
	       input reg_do_write,
	       
	       // Read end of request queue from bridge
	       // This is only a 32-bit interface
	       input [24:0] br_addr,
	       input [63:0] br_wdata,
	       input [7:0] br_bytes,
	       input br_do_read,
	       input br_do_write,
	       input br_valid,
	       output br_deq,
	       
	       // Write end of read return queue to bridge
	       output [63:0] br_rdata,
	       output br_rdata_enq,
	       // input [3:0] br_rdata_free,
    
	       // Read end of video request queue (head0)
	       input [24:0] vid0_addr,
	       input vid0_valid,
	       output vid0_deq,

	       // Read end of video request queue (head1)
	       input [24:0] vid1_addr,
	       input vid1_valid,
	       output vid1_deq,
    
	       // Write end of read return queue to video
	       output [63:0] vid0_rdata,
	       output vid0_rdata_enq,
	       
	       // Write end of read return queue to video
	       output [63:0] vid1_rdata,
	       output vid1_rdata_enq,
	       
	       // Memory controller
	       output reg [2:0] cmd_mem,
	       output reg [1:0] bank_mem,
	       output reg [12:0] row_mem, 
	       output reg [12:0] col_mem,
	       output reg [63:0] wdata_mem,
	       output reg [7:0] wbytes_mem,
	       output reg [2:0] rtag_mem,
	       input busy_mem,
	       
	       input [63:0] rdata_mem, 
	       input rdata_valid_mem, 
	       input [2:0] rtag_return 
	       );
   
   
   
   // Config regs and load mode register (lmr)
   reg [14:0] 		   lmr_data;
   reg [3:0] 		   lmr_delay;
   reg 			   lmr_addr;
   reg [10:0] 		   refresh_delay;
   reg 			   refresh_enable;
   reg [1:0] 		   lmr_write;
   
   
   always @(posedge reg_clock or negedge reset_) begin
      if (!reset_) begin
         lmr_write[0] <= 0;
         lmr_write[1] <= 0;
         lmr_data <= 0;
      end else begin
         lmr_write[0] <= lmr_write[0] >> 1;
         lmr_write[1] <= lmr_write[1] >> 1;
         if (reg_do_write) begin
            case (reg_addr[1:0])
              0: begin
                 lmr_data <= reg_data;
                 lmr_delay <= 4'b1110;
                 lmr_addr <= 0;
              end
              2: begin
                 lmr_addr <= 1;
                 lmr_delay <= 4'b1110;
              end
              3: {refresh_enable, refresh_delay} <= reg_data;
            endcase
         end
      end
   end
   
   
   reg last_lmr_delay;
   reg do_lmr;
   
   always @(posedge clock) begin
      last_lmr_delay <= lmr_delay[0];
      do_lmr <= !last_lmr_delay && lmr_delay[0];
   end
   
   
   
   
   // Refresh counter
   integer i;
   reg [10:0] refresh_counter;
   reg [11:0] borrow, zero;
   always @(posedge clock or negedge reset_) begin
      if (!reset_) begin
	 borrow <= 1;
	 zero <= 1;
	 refresh_counter <= 0;
      end else begin
	 if (zero[11]) begin
            refresh_counter <= refresh_delay;
            zero <= 1;
            borrow <= 1;
	 end else begin
            for (i=0; i<11; i=i+1) begin
               zero[i+1] <= zero[i] && !refresh_counter[i];
               borrow[i+1] <= !refresh_counter[i] && borrow[i];
               refresh_counter[i] <= refresh_counter[i] ^ borrow[i];
            end
	 end
      end
   end
   
   reg refresh_pending;
   wire refresh_deq;
   always @(posedge clock or negedge reset_) begin
      if (!reset_) begin
         refresh_pending <= 0;
      end else begin
         if (zero[11] && refresh_enable) refresh_pending <= 1;
         if (refresh_deq) refresh_pending <= 0;
      end
   end
   
   
   
   parameter mem_read = 3'd1;
   parameter mem_write = 3'd2;
   parameter mem_precharge = 3'd3;
   parameter mem_refresh = 3'd4;
   parameter mem_lmr = 3'd5;
   
   
   
   wire      pci_access = br_valid;
   wire vid0_access = vid0_valid;
   wire vid1_access = vid1_valid;
   wire refresh_access = refresh_pending;
   
   // Scheduler
   reg 	allow_pci, allow_vid0, allow_vid1, allow_refresh;
   always @(posedge clock or negedge reset_) begin
      if (!reset_) begin
         allow_pci <= 0;
         allow_vid0 <= 0;
         allow_vid1 <= 0;
         allow_refresh <= 0;
      end else begin
         if (refresh_access) begin
            allow_refresh <= 1;
            allow_pci <= 0;
            allow_vid0 <= 0;
            allow_vid1 <= 0;
         end else if (vid0_access) begin
            allow_vid0 <= 1;
            allow_pci <= 0;
            allow_refresh <= 0;
            allow_vid1 <= 0;
         end else if (vid1_access) begin
            allow_vid0 <= 1;
            allow_pci <= 0;
            allow_refresh <= 0;
            allow_vid1 <= 1;
         end else if (pci_access) begin
            allow_pci <= 1;
            allow_vid0 <= 0;
            allow_refresh <= 0;
            allow_vid1 <= 0;
         end
      end
   end
   
   wire vid_deq;
   assign br_deq = allow_pci && !memctl_busy;
   assign vid_deq = allow_video && !memctl_busy;
   assign refresh_deq = allow_refresh && !memctl_busy;
   
   
   // We will definitely need a stage of pipelining added here
   
   wire   lmr_cmd = do_lmr && !lmr_addr;
   wire   precharge_cmd = do_lmr && lmr_addr;
   wire   refresh_cmd = allow_refresh;
   wire   pci_read_cmd = allow_pci && br_do_read && br_valid;
   wire   pci_write_cmd = allow_pci && br_do_write && br_valid;
   wire   vid0_cmd = allow_vid0 && vid0_valid;
   wire   vid1_cmd = allow_vid1 && vid1_valid;

   always@(*) begin
      cmd_mem = 
		({3{lmr_cmd}} & mem_lmr) |
		({3{precharge_cmd}} & mem_precharge) |
		({3{refresh_cmd}} & mem_refresh) |
		({3{pci_read_cmd}} & mem_read) |
		({3{pci_write_cmd}} & mem_write) |
		({3{vid0_cmd}} & mem_read) |
		({3{vid1_cmd}} & mem_read);
      
      bank_mem = 
		 ({2{lmr_cmd}} & lmr_data[14:13]) |
		 ({2{pci_read_cmd}} & br_addr[22:21]) |
		 ({2{pci_write_cmd}} & br_addr[22:21]) |
		 ({2{vid0_cmd}} & vid0_addr[22:21]) |
		 ({2{vid1_cmd}} & vid1_addr[22:21]);
      
      // 13-bit row
      row_mem = 
		({13{pci_read_cmd}} & br_addr[20:8]) |
		({13{pci_write_cmd}} & br_addr[20:8]) |
		({13{vid0_cmd}} & vid0_addr[20:8]) |
		({13{vid1_cmd}} & vid1_addr[20:8]);
      
      // 16-bit 256Mb chips have 9-bit column; we use only even numbers
      // Must make these configurable for ASIC
      col_mem[8:1] = 
		     ({8{lmr_cmd}} & lmr_data[8:1]) |
		     ({8{pci_read_cmd}} & br_addr[7:0]) |
		     ({8{pci_write_cmd}} & br_addr[7:0]) |
		     ({8{vid0_cmd}} & vid0_addr[7:0]) |
		     ({8{vid1_cmd}} & vid1_addr[7:0]);
      col_mem[0] = lmr_cmd & lmr_data[0];
      
      wdata_mem = br_wdata;
      wbytes_mem = br_bytes;
      
      rtag_mem = {pci_read_cmd, vid0_cmd, vid1_cmd};
   end // always@ (*)
   
   // Return path for read data
   assign br_rdata = rdata_mem;
   assign vid0_rdata = rdata_mem;
   assign vid1_rdata = rdata_mem;
   assign br_rdata_enq = rdata_valid_mem & rtag_return[2];
   assign vid0_rdata_enq = rdata_valid_mem & rtag_return[1];
   assign vid1_rdata_enq = rdata_valid_mem & rtag_return[0];
   
   
endmodule



More information about the Open-graphics mailing list