Ok, here's the bridge for the Spartan chip.  What's missing?  Right
now, what I need is help with organizing this in SVN and then with
filling in the top-level modules, which is an error-prone job that
needs more eyes.







// Spartan side of the bridge

/*
Notes:
    Can only handle even numbers of words in read requests.


Optimizations:
    eng_addr and mem_addr could be merged into one register,
    where the address loses a bit when connecting to the fifo.
    Similar for mem_data and eng_wdata.
*/


module s3_bridge(
    input clock,
    input reset_,

    // External interface
    input [31:0] bridge_ad_in,
    output reg [31:0] bridge_ad_out,  // wire in and out to same pins
    output reg bridge_oe,
    input [3:0] bridge_flags,
    input [1:0] bridge_cmd,
    output reg bridge_rdata_valid,
    output reg bridge_busy,

    // Engine interface
    output [15:0] eng_addr,
    input [31:0] eng_rdata,
    output reg [31:0] eng_wdata,
    output reg eng_do_write,

    // Write end of memory access fifo
    output reg [27:0] mem_addr,
    output reg [63:0] mem_data,
    output reg [7:0] mem_bytes,
    output reg mem_do_write,
    output reg mem_do_read,
    output reg mem_enq,
    input mem_full,
    input mem_nearly_full,  // When the fifo has <=4 entries free
    // (I think 4 is enough; otherwise use 8)

    // Read end of memory read return fifo
    input [63:0] mem_rdata,
    input mem_rdata_valid,
    output mem_rdata_deq
);


// Commands -- move to header file!
parameter b_idle = 0;
parameter b_addr = 1;
parameter b_rcount = 2;
parameter b_write = 3;


// These target numbers are different from in the XP10
parameter TARGET_ENG=0;
parameter TARGET_MEM=1;



// Busy
always @(posedge clock) begin
    bridge_busy <= mem_nearly_full;
end



// Register bridge inputs
reg [31:0] bridge_ad_in_d;
reg [3:0] bridge_flags_d;
reg [1:0] bridge_cmd_d;
always @(posedge clock) begin
    bridge_ad_in_d <= bridge_ad_in;
    bridge_flags_d <= bridge_flags;
    bridge_cmd_d <= bridge_cmd;
end


// Manage address and memory access
reg [31:0] address;
reg [3:0] target;
reg [6:0] rcount;
always @(posedge clock) begin
    if (!mem_full) mem_enq <= 0;
    eng_do_write <= 0;

    case (bridge_cmd_d)
        b_addr: begin
            address <= bridge_ad_in_d;
            target <= bridge_flags_d;
        end
        b_rcount: rcount <= bridge_ad_in_d;
        b_write: begin
            mem_addr <= address[28:1];  // shift correct?
            // Cheat by not combining adjacent writes
            // This should be easy to optimize later
            mem_data <= {bridge_ad_in_d, bridge_ad_in_d};

            // Important:  Lower address goes into lower half of word
            mem_bytes[3:0] <= {4{!address[0]}} & bridge_flags_d;
            mem_bytes[7:4] <= {4{address[0]}} & bridge_flags_d;
            mem_do_write <= 1;
            mem_do_read <= 0;
            mem_enq <= target[TARGET_MEM];
        end
    endcase

    if (rcount[6:1]) begin
        mem_addr <= address[28:1];  // shift?
        mem_do_write <= 0;
        mem_do_read <= 1;
        mem_enq <= target[TARGET_MEM];

        address[6:1] <= address[6:1] + 1;
        rcount[6:1] <= rcount[6:1] - 1;
    end
end


// Mem and engine read return
reg [6:0] return_half;
reg [1:0] eng_read_count;
always @(posedge clock or negedge reset_) begin
    if (!reset_) begin
        return_half <= 0;
        bridge_oe <= 0;
    end else begin
        if (bridge_cmd_d == b_rcount) begin
            return_half <= 0;
        end

        bridge_oe <= 0;
        bridge_rdata_valid <= 0;
        if (target[TARGET_MEM] && mem_rdata_valid) begin
            bridge_oe <= 1;
            bridge_ad_out <= return_half ?
                mem_rdata[63:32] : mem_rdata[31:0];
            bridge_rdata_valid <= 1;
        end

        if (eng_read_count == 1) begin
            bridge_oe <= 1;
            bridge_ad_out <= eng_rdata;
            bridge_rdata_valid <= 1;
        end
    end
end

// Dequeue when we're sending the top half
assign mem_rdata_deq = return_half;



// Engine register access
always @(posedge clock or negedge reset_) begin
    eng_do_write <= 0;

    case (bridge_cmd_d)
        b_rcount: begin
            eng_addr <= address;
            // Start counter at 3
            eng_read_count <= {2{target[TARGET_ENG]}};
        end
        b_write: begin
            eng_addr <= address;
            eng_wdata <= bridge_ad_in_d;
            eng_do_write <= target[TARGET_ENG];
        end
        default:
            eng_read_count <= 0;
            eng_addr <= 0;
        end
    endcase

    if (eng_read_count) begin
        eng_read_count <= eng_read_count - 1;
    end
end


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