This is the memory access scheduler. Some of you may notice that I
haven't yet taken into account certain suggestions. For instance,
read counters are still external to the scheduler. Those kinds of
optimizations will trickle in. In the mean time, this is just a model
of how it should work (roughly). Also, it's most certainly going to
need to be pipelined.
Please look this over.
// 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 [27: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 [27:0] vid0_addr,
input vid0_valid,
output vid0_deq,
// Read end of video request queue (head0)
input [27: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;
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;
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
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;
assign 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);
assign 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
assign 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}} & vid0_addr[20:8]);
// 16-bit 256Mb chips have 9-bit column; we use only even numbers
// Must make these configurable for ASIC
assign 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}} & vid0_addr[7:0]);
assign col_mem[0] = lmr_cmd & lmr_data[0];
assign wdata_mem = br_wdata;
assign wbytes_mem = br_bytes;
assign rtag_mem = {pci_read_cmd, vid0_cmd, vid1_cmd};
// 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
--
Timothy Normand Miller
http://www.cse.ohio-state.edu/~millerti
Open Graphics Project
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)