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)

Reply via email to