[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