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 <[EMAIL PROTECTED]> 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 <[EMAIL PROTECTED]> 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.
// 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
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)