[Open-graphics] Initial release of video controller block

Timothy Miller theosib at gmail.com
Sun Jul 2 20:58:44 EDT 2006


I'll check this into SVN later, but some people may want to look at it
and discuss it for educational purposes.  The following is a prototype
of the OGA video controller block, which will also be supplied with
OGD1.  This is being issued under Traversal's dual license.  I say
it's a prototype because it isn't tested (which I'm hoping some of you
will help with), and there are major flaws in the cursor overlay block
(which I expect you to find!) that I just haven't gotten around to
fixing.  There's also a potential metastability issue with the
interrupt reset that I have to address.  Note that the wrapper is
there primarily as a way to isolate the other blocks from the I/O
buffers when synthesizing so I can tell how the block will perform.
Also, I need to add lots of comments and clean up the sloppiness.
Let's see if anyone can figure out how this is supposed to work.  :)

Without further ado, here it is:



module vid_wrapper(
    vid_clock,
    pci_clock,
    reset,

    reg_write_data,
    reg_write_addr,
    reg_write,

    req_addr,
    req_enq,
    req_busy,

    in_fifo_data,
    deq_in_fifo,

    out_pixels,
    out_signals,

    interrupt
);

input vid_clock, pci_clock, reset;
input [31:0] reg_write_data;
input [10:0] reg_write_addr;
input reg_write;

input req_busy;
output [27:0] req_addr;
output req_enq;
reg [27:0] req_addr;
reg req_enq;

input [0:255] in_fifo_data;
output deq_in_fifo;
reg deq_in_fifo;

output [0:127] out_pixels;
output [2:0] out_signals;
reg [0:127] out_pixels;
reg [2:0] out_signals;

output interrupt;
reg interrupt;


reg [31:0] reg_write_data_r;
reg [10:0] reg_write_addr_r;
reg reg_write_r;
always @(posedge pci_clock) begin
    {reg_write_data_r, reg_write_addr_r, reg_write_r} <=
        {reg_write_data, reg_write_addr, reg_write};
end

wire [27:0] req_addr_i;
wire req_enq_i;
wire [11:0] cursor_x_i, cursor_y_i;
wire [127:0] out_pixels_i;
wire [2:0] out_signals_i;
wire [127:0] out_pixels_j;
wire [2:0] out_signals_j;
wire interrupt_i;
reg req_busy_r;
reg [0:255] in_fifo_data_r;
wire deq_in_fifo_i;
always @(posedge vid_clock) begin
    req_addr <= req_addr_i;
    req_enq <= req_enq_i;
    req_busy_r <= req_busy;

    {out_pixels, out_signals} <= {out_pixels_i, out_signals_i};
    interrupt <= interrupt_i;

    in_fifo_data_r <= in_fifo_data;
    deq_in_fifo <= deq_in_fifo_i;
end


vid_control vc (
    .vid_clock          (vid_clock),
    .pci_clock          (pci_clock),
    .reset              (reset),
    .reg_write_data     (reg_write_data_r),
    .reg_write_addr     (reg_write_addr_r[9:0]),
    .reg_write          (reg_write_r && !reg_write_addr_r[10]),
    .req_addr           (req_addr_i),
    .req_enq            (req_enq_i),
    .req_busy           (req_busy_r),
    .in_fifo_data       (in_fifo_data_r),
    .deq_in_fifo        (deq_in_fifo_i),
    .out_pixels         (out_pixels_j),
    .out_signals        (out_signals_j),
    .cursor_x           (cursor_x_i),
    .cursor_y           (cursor_y_i),
    .interrupt          (interrupt_i)
);


cursor_overlay co (
    .vid_clock          (vid_clock),
    .pci_clock          (pci_clock),
    .reset              (reset),
    .reg_write_data     (reg_write_data_r),
    .reg_write_addr     (reg_write_addr_r[9:0]),
    .reg_write          (reg_write_r && reg_write_addr_r[10]),
    .cursor_x           (cursor_x_i),
    .cursor_y           (cursor_y_i),
    .in_pixels          (out_pixels_j),
    .in_signals         (out_signals_j),
    .out_pixels         (out_pixels_i),
    .out_signals        (out_signals_i)
);


endmodule



module vid_control(
    vid_clock,
    pci_clock,
    reset,

    reg_write_data,
    reg_write_addr,
    reg_write,

    req_addr,
    req_enq,
    req_busy,

    in_fifo_data,
    deq_in_fifo,

    out_pixels,
    out_signals,

    cursor_x,
    cursor_y,

    interrupt
);

input vid_clock, pci_clock, reset;
input [31:0] reg_write_data;
input [9:0] reg_write_addr;
input reg_write;

input req_busy;
output [27:0] req_addr;
output req_enq;

input [0:255] in_fifo_data;
output deq_in_fifo;

output [0:127] out_pixels;
output [2:0] out_signals;
reg [0:127] out_pixels;
reg [2:0] out_signals;

output [11:0] cursor_x, cursor_y;
reg [11:0] cursor_x, cursor_y;

output interrupt;
reg interrupt;


reg [8:0] ins_addr;

wire [31:0] ins;
RAMB16_S36_S36 dlist_ram (
    .DOA(ins), .DOPA(),
    .DOB(), .DOPB(),
    .ADDRA(ins_addr),  .CLKA(vid_clock),
    .DIA(32'b0),  .DIPA(4'b0),
    .DIB(reg_write_data),  .DIPB(4'b0),
    .ADDRB(reg_write_addr[8:0]),  .CLKB(pci_clock),
    .ENA(1'b1), .SSRA(1'b0),
    .ENB(1'b1), .SSRB(1'b0),
    .WEA(1'b0), .WEB(reg_write && !reg_write_addr[9]));


reg [11:0] cursor_x_start, cursor_y_start;
reg [7:0] clear_int;
reg [2:0] depth;
always @(posedge pci_clock) begin
    clear_int <= {clear_int[6:0], 1'b0};

    if (reg_write && reg_write_addr[9]) begin
        case (reg_write_addr[1:0])
            0: cursor_x_start <= reg_write_data;
            1: cursor_y_start <= reg_write_data;
            2: clear_int <= 8'hff;
            3: depth <= reg_write_data;
        endcase
    end
end


reg [8:0] pc, npc, retpc, retnpc;
reg [11:0] counter0, counter1;
reg [1:0] counting;

wire jump_ins = ins[23:22]==0;

//wire [11:0] next_counter = counting[0] ? counter[0] : ins[20:9];
wire no_loop = counting[0] ? counter0[11] : ins[20];

always @(ins or jump_ins or no_loop or pc or npc or retpc or retnpc) begin
    if (jump_ins) begin
        ins_addr = ins[8:0];
    end else if (!no_loop) begin
        ins_addr = ins[26] ? retpc : pc;
    end else begin
        ins_addr = ins[26] ? retnpc : npc;
    end
end



reg [7:0] req_count;
reg [27:0] req_addr;
reg req_enq;
reg [1:0] inc_carry;

reg [3:0] deq_count;
reg [2:0] shift_count;
reg send_pixel;
assign deq_in_fifo = send_pixel && deq_count[3];

reg [0:255] shifted_pixels;
reg [0:127] pixels16, pixels8;
reg [0:127] muxed_pixels;
reg [7:0] i;

always @(shifted_pixels or depth) begin
    //shifted_pixels = in_fifo_data << {shift_count, 5'b0};

    for (i=0; i<128; i=i+1) begin
        pixels16[i] = shifted_pixels[{i[6:5], i[3:0]}];
    end

    for (i=0; i<128; i=i+1) begin
        pixels8[i] = shifted_pixels[{i[6:5], i[2:0]}];
    end

    muxed_pixels = shifted_pixels[0:127] & {128{depth[2]}};
    muxed_pixels = muxed_pixels | (pixels16 & {128{depth[1]}});
    muxed_pixels = muxed_pixels | (pixels8 & {128{depth[0]}});
end


always @(posedge vid_clock) begin
    out_pixels <= muxed_pixels;
end


//wire [31:0] const_pixel = {8'b0, ins[20:14], ins[20],
//    ins[13:7], ins[13], ins[6:0], ins[6]};
reg [2:0] out_signals_a, out_signals_b;



reg [20:0] addr_val;
reg addr_add, addr_set;


always @(posedge vid_clock or negedge reset) begin
    if (!reset) begin
        pc <= 0;
        npc <= 1;
        {retpc, retnpc} <= 0;
        counter0 <= 0;
        counter1 <= 0;
        counting <= 0;
        req_addr <= 0;
        req_count <= 0;
        req_enq <= 0;
        //out_pixels <= 0;
        out_signals <= 0;
        out_signals_a <= 0;
        {cursor_x, cursor_y} <= 0;
        inc_carry <= 0;
        deq_count <= 0;
        send_pixel <= 0;
        out_signals_b <= 0;
        {addr_val, addr_add, addr_set} <= 0;
    end else begin
        out_signals_b <= ins[31:29];
        out_signals_a <= out_signals_b;
        out_signals <= out_signals_a;

        inc_carry <= 0;
        {inc_carry[1], req_addr[17:9]} <= req_addr[17:9] + inc_carry[0];
        req_addr[27:18] <= req_addr[27:18] + inc_carry[1];

        /*case (1'b1)     // synthesis parallel_case
            req_enq: begin
                if (!req_busy) begin
                    if (!inc_carry) begin
                        {inc_carry[0], req_addr[8:0]} <= req_addr[8:0] + 1;
                    end
                    if (req_addr[8:0] == 9'h1ff ||
                        (inc_carry[0] && req_addr[17:9] == 9'h1ff)) begin
                        req_enq <= 0;
                    end else begin
                        req_count <= req_count - 1;
                        req_enq <= req_count > 1;
                    end
                end
            end
            addr_set: begin
                req_addr <= {addr_val, 7'b0};
            end
            addr_add: begin
                {inc_carry[0], req_addr[8:0]} <= req_addr[8:0] + addr_val[8:0];
                {inc_carry[1], req_addr[17:9]} <= req_addr[17:9] +
addr_val[17:9];
                req_addr[27:18] <= req_addr[27:18] + addr_val[20:18];
            end
        endcase*/

        if (req_enq && !req_busy) begin
            if (!inc_carry) begin
                {inc_carry[0], req_addr[8:0]} <= req_addr[8:0] + 1;
            end
            if (req_addr[8:0] == 9'h1ff ||
                (inc_carry[0] && req_addr[17:9] == 9'h1ff)) begin
                req_enq <= 0;
            end else begin
                req_count <= req_count - 1;
                req_enq <= req_count > 1;
            end
        end

        if (addr_set) begin
            req_addr <= {addr_val, 7'b0};
        end
        if (addr_add) begin
            {inc_carry[0], req_addr[8:0]} <= req_addr[8:0] + addr_val[8:0];
            {inc_carry[1], req_addr[17:9]} <= req_addr[17:9] + addr_val[17:9];
            req_addr[27:18] <= req_addr[27:18] + addr_val[20:18];
        end

        pc <= ins_addr;
        npc <= ins_addr + 1;

        if (ins[27]) begin
            cursor_x <= cursor_x_start;
            deq_count <= depth[2:0];
            shift_count <= 0;
        end
        case (ins[28:27])
            0: ;
            1: cursor_y <= cursor_y - 1;
            2, 3: cursor_y <= cursor_y_start;
        endcase
/*        if (ins[28]) begin
            cursor_y <= cursor_y_start;
        end
        if (ins[28:27] == 1) begin
            cursor_y <= cursor_y - 1;
        end*/

        {addr_add, addr_set} <= 0;
        case (ins[23:21])
            0: ;
            1: begin
                if (counting) begin
                    counter1 <= counter0 - 1;
                    counting[1] <= counter0 > 0;
                end else begin
                    counter1 <= ins[20:9];
                    counting[1] <= ins[20:9] > 0;
                end
                retpc <= pc;
                retnpc <= npc;
            end
            2, 3: begin
                if (counting) begin
                    counter0 <= counter0 - 1;
                    counting[0] <= !counter0[11];
                end else begin
                    counter0 <= ins[20:9];
                    counting[0] <= !ins[20];
                end
            end
            5: begin
                req_count <= ins[20:9];
                req_enq <= 1;
            end
            /*7: begin
                //shifted_pixels[0:127] <= {4{const_pixel}};
            end*/
            6, 7: begin
                addr_val <= ins[20:0];
                addr_set <= !ins[21];
                addr_add <= ins[21];
            end
        endcase

        send_pixel <= (ins[23:21] == 3);
        if (send_pixel) begin
            shifted_pixels <= in_fifo_data << {shift_count, 5'b0};
            cursor_x <= cursor_x - 4;
            shift_count <= deq_count;
            deq_count <= deq_count + depth[2:0];
        end

        if (ins[25]) begin
            interrupt <= 1;
        end
        if (clear_int[7]) begin
            interrupt <= 0;
        end

        if (ins[26] && no_loop) begin
            counter0 <= counter1;
            counting[0] <= counting[1];
        end
    end
end

endmodule



module cursor_overlay(
    vid_clock,
    pci_clock,
    reset,

    reg_write_data,
    reg_write_addr,
    reg_write,

    cursor_x,
    cursor_y,
    in_pixels,
    in_signals,

    out_pixels,
    out_signals
);

input vid_clock, pci_clock, reset;
input [31:0] reg_write_data;
input [9:0] reg_write_addr;
input reg_write;

output [0:127] out_pixels;
output [2:0] out_signals;
reg [0:127] out_pixels;
reg [2:0] out_signals;

input [0:127] in_pixels;
input [2:0] in_signals;

input [11:0] cursor_x, cursor_y;


wire in_range = !cursor_y[11:5] && !cursor_x[11:5];

wire [7:0] cursor_addr = ~{cursor_y[4:0], cursor_x[4:2]};

wire [0:127] cram_bits;
RAMB16_S36_S36 cram0 (
    .DOA(cram_bits[0:31]), .DOPA(),
    .DOB(cram_bits[32:63]), .DOPB(),
    .ADDRA({1'b0, cursor_addr}),  .CLKA(vid_clock),
    .DIA(32'b0),  .DIPA(4'b0),
    .DIB(reg_write_data),  .DIPB(4'b0),
    .ADDRB(reg_write ? reg_write_addr[8:0] : {1'b1, cursor_addr}),
    .CLKB(pci_clock),
    .ENA(1'b1), .SSRA(1'b0),
    .ENB(1'b1), .SSRB(1'b0),
    .WEA(1'b0), .WEB(reg_write && !reg_write_addr[9]));

RAMB16_S36_S36 cram1 (
    .DOA(cram_bits[64:95]), .DOPA(),
    .DOB(cram_bits[96:127]), .DOPB(),
    .ADDRA({1'b0, cursor_addr}),  .CLKA(vid_clock),
    .DIA(32'b0),  .DIPA(4'b0),
    .DIB(reg_write_data),  .DIPB(4'b0),
    .ADDRB(reg_write ? reg_write_addr[8:0] : {1'b1, cursor_addr}),
    .CLKB(pci_clock),
    .ENA(1'b1), .SSRA(1'b0),
    .ENB(1'b1), .SSRB(1'b0),
    .WEA(1'b0), .WEB(reg_write && reg_write_addr[9]));

reg last_mask, mask;
reg [0:127] last_word;

always @(posedge vid_clock) begin
    last_word <= cram_bits;
    mask <= in_range;
    last_mask <= mask;
end


reg [0:127] cursor_bits;
reg [0:3] mask_bits;

always @(posedge vid_clock) begin
    case (cursor_x[1:0])
        0: cursor_bits <= cram_bits;
        1: cursor_bits <= {last_word[96:127], cram_bits[0:95]};
        2: cursor_bits <= {last_word[64:127], cram_bits[0:63]};
        3: cursor_bits <= {last_word[32:127], cram_bits[0:31]};
    endcase
end


always @(posedge vid_clock) begin
    case (cursor_x[1:0])
        0: mask_bits <= {4{mask}};
        1: mask_bits <= {last_mask, {3{mask}}};
        2: mask_bits <= {{2{last_mask}}, {2{mask}}};
        3: mask_bits <= {{3{last_mask}}, mask};
    endcase
end


always @(posedge vid_clock) begin
    out_pixels[0:31] <= mask_bits[0] ? cursor_bits[0:31] : in_pixels[0:31];
    out_pixels[32:63] <= mask_bits[1] ? cursor_bits[32:63] : in_pixels[32:63];
    out_pixels[64:95] <= mask_bits[2] ? cursor_bits[64:95] : in_pixels[64:95];
    out_pixels[96:127] <=
        mask_bits[3] ? cursor_bits[96:127] : in_pixels[96:127];

    out_signals <= in_signals;
end

endmodule


More information about the Open-graphics mailing list