This is really rough, probably quite broken, and in desperate need of
simulation. But release early and often...
/*
Note: PCI addresses are byte addresses.
Note: All other agents use word (32-bit boundary) addresses
Be careful with this.
Need to make bridge interface use fifos, primarily because
this and the bridge are in different clock domains.
*/
module pci_address_decode(
input clock, // pci clock (66 max)
input reset_,
// PCI read interface
input [27:0] read_address,
output [31:0] read_data,
input start_read,
input end_read,
output read_valid,
input deq_read,
// PCI write interface
input [27:0] write_address,
input [3:0] write_bytes,
input [31:0] write_data,
input do_write,
output can_write,
// PCI other
input [4:0] access_target,
input [31:0] decode_address,
output [4:0] decode_target,
input set_parity_error,
output parity_error_enable,
// SPI prom read interface
// For the moment, this is just for reading the BIOS prom
// Add other stuff later
output [23:2] prom_read_addr,
input prom_busy,
input [31:0] prom_read_data,
input prom_read_valid,
// Interface to bridge
// Write end of command fifo
output [1:0] br_command,
output [31:0] br_data,
output [3:0] br_flags,
output br_enq,
input br_full,
// Read end of return data fifo
input [31:0] br_read_data,
input br_read_valid,
output br_deq_read
);
// Access targets. Move into header!
parameter TARGET_CFG=0;
parameter TARGET_ENG=1;
parameter TARGET_MEM=2;
parameter TARGET_PROM=3;
parameter TARGET_IO=4;
wire [31:0] cfg_read_data;
wire cfg_read_valid;
// Data cache for graphics memory access
// Two lines of 16 32-bit words
reg [31:0] cache [0:31];
reg [27:4] cache_addr [0:1];
reg [31:0] cache_valid;
reg cache_replace;
// This read loop is combinatorial. That's probably bad. We
// may want to register it
wire hit_line0 = read_address[29:6] == cache_addr[0];
wire hit_line1 = read_address[29:6] == cache_addr[1];
wire [31:0] cache_data = cache[{hit_line1, read_address[5:2]}];
wire cache_valid_word = cache_valid[{hit_line1, read_address[5:2]}];
wire cache_hit = (hit_line0 || hit_line1) && cache_valid_word;
// Data grabbed from PROM
reg [31:0] spi_data;
reg spi_data_valid;
always @(posedge clock) begin
if (read_deq) spi_data_valid <= 0;
if (prom_read_valid) begin
spi_data <= prom_read_data;
spi_data_valid <= 1;
end
end
// Multiplex all read sources
assign read_data =
({32{access_target[TARGET_MEM]}} & cache_data) |
({32{access_target[TARGET_ENG]}} & br_read_data) |
({32{access_target[TARGET_PROM]}} & spi_data) |
({32{access_target[TARGET_CFG]}} & cfg_read_data);
assign read_valid =
(access_target[TARGET_MEM] && cache_hit) ||
(access_target[TARGET_ENG] && br_read_valid) ||
(access_target[TARGET_PROM] && spi_data_valid) ||
(access_target[TARGET_CFG] && cfg_read_valid);
wire bridge_access = (access_target[TARGET_MEM] || access_target[TARGET_ENG]);
wire eng_read = access_target[TARGET_ENG];
wire mem_read = access_target[TARGET_MEM] && !cache_hit;
// When to dequeue read return data
assign br_deq_read = (eng_read && read_deq) ||
doing_cache_read;
reg [3:0] cache_read_addr, read_counter;
reg doing_cache_read;
reg doing_eng_read;
// States
reg [1:0] state;
parameter s_idle = 0;
parameter s_read = 1;
parameter s_write = 2;
parameter s_read_count = 3;
// Can write freely to CFG
// When PROM writing is enabled, make it pay attention to busy
// MEM and ENG require that the bridge command fifo have a free entry
assign can_write = access_target[TARGET_CFG] ||
access_target[TARGET_PROM] || // fix this later
(bridge_access && (!br_full || !br_enq) && state==s_write);
// Cache manager
always @(posedge clock or negedge reset_) begin
if (!reset_) begin
cache_addr[0] <= 0;
cache_addr[1] <= 0;
cache_valid <= 0;
br_enq <= 0;
br_flags <= 0;
br_command <= 0;
read_counter <= 0;
cache_replace <= 0;
cache_read_addr <= 0;
doing_cache_read <= 0;
doing_eng_read <= 0;
state <= 0;
end else begin
// Wipe the cache on any memory write. We could do
// write-through later.
if (doing_write && access_target[TARGET_MEM]) begin
cache_valid <= 0;
end
if (!br_full) br_enq <= 0;
if (!br_full || !br_enq) begin
case (state)
s_idle: begin
// Waiting for something to happen
doing_cache_read <= 0;
doing_eng_read <= 0;
br_command <= b_addr;
br_flags <= access_target[...];
if (start_write) begin
// We catch address early
br_data <= read_address; // this is correct
br_enq <= 1;
state <= s_write;
end else if (do_write) begin
// br fifo doesn't free up until later
br_data <= write_address;
br_enq <= 1;
state <= s_write;
end else if ((start_read || do_read) && eng_read) begin
// Any engine read causes a request to bridge
// (Unless we make some XP10 regs appear in this
// space)
br_data <= read_address;
br_enq <= 1;
read_counter <= 1;
state <= s_read_count;
doing_cache_read <= 0;
doing_eng_read <= 1;
end else if ((start_read || do_read) && mem_read) begin
// Any memory cache miss
br_data <= read_address;
br_enq <= 1;
read_counter <= 16;
state <= s_read_count;
doing_cache_read <= 1;
doing_eng_read <= 0;
end
end
s_read_count: begin
// Send read address, now need to send read count
br_command = b_rcount;
br_data <= read_counter;
br_enq <= 1;
// Cache word address
cache_read_addr <= 0;
// Round-robbin use of cache lines
cache_replace <= !cache_replace;
if (0==cache_replace) begin // reversed sense
cache_valid[31:16] <= 0;
cache_addr[1] <= read_address[29:6];
end else begin
cache_valid[15:0] <= 0;
cache_addr[0] <= read_address[29:6];
end
end
s_write: begin
// Doing writes
br_data <= write_data;
br_flags <= write_bytes;
br_enq <= do_write;
if (end_write) state <= s_idle;
end
endcase
end
if (br_read_valid) begin
// If we're filling cache line, increment address when
// data arrives
cache_read_addr <= cache_read_addr + 1;
cache_valid[{cache_replace, cache_read_addr}] <= 1;
end
if (state==s_read && br_read_valid) begin
// Count down pending reads
read_counter <= read_counter - 1;
if (read_counter <= 1) begin
// When the counter hits zero, go idle
state <= s_idle;
doing_cache_read <= 0;
doing_eng_read <= 0;
end
end
end
end
always @(posedge clock) begin
// When filling cache, store data in distributed RAM
if (br_read_valid && doing_cache_read) begin
cache[{cache_replace, cache_read_addr}] <= br_read_data;
end
end
// Config space
config_space cfg (
.clock (clock),
._reset (_reset),
.read_address (read_address[7:0]),
.start_read (start_read),
.end_read (end_read),
.read_data (cfg_read_data),
.read_valid (cfg_read_valid),
.write_address (write_address[7:0]),
.write_bytes (write_bytes),
.write_data (write_data),
.do_write (do_write && access_target[0]),
.decode_address (decode_address),
.decode_target (decode_target),
.class_other (1'b0),
.class_xga (1'b0),
.class_3d (1'b0),
.allow_66mhz (1'b0),
.capabilities_pointer (8'b0),
.enable_new_capabilities (1'b0),
.mem_decode_en_i (7'b1111111),
.set_parity_error (set_parity_error),
.master_set_parity_error (1'b0), // xxx hook this up
.parity_error_enable(parity_error_enable)
);
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)