Ok, here's a template for head zero. This is the one that connects to
the 330MHz triple-DAC and to the first pair of DVI transmitters. I'd
like to check this into SVN, but I don't want to stick it just any old
place, so I was hoping others could make a suggestion so I can keep
things clean.
Below is a paste of the module. Somewhere in there, we'll insert
whatever logic generates signals.
module head0_video_out(
clock,
clock_2x,
reset,
// Common data pins
vid_data,
// Syncs and clock for analog interface
dac_hsync,
dac_vsync,
dac_de,
dac_clk,
// Syncs and clocks for DVI interface
dvi_m_clk,
dvi_s_clk,
dvi_hsync,
dvi_vsync,
dvi_de
);
input clock, reset;
output [29:0] vid_data;
output dac_hsync, dac_vsync, dac_de, dac_clk;
output dvi_m_clk, dvi_s_clk, dvi_hsync, dvi_vsync, dvi_de;
reg dac_hsync, dac_vsync, dac_de;
reg dvi_hsync, dvi_vsync, dvi_de;
// ----------
// Pixel data -- notice that we process two pixels per clock
reg [9:0] r0, g0, b0; // even pixel
reg [9:0] r1, g1, b1; // odd pixel
// And the syncs
reg hsync, vsync, de;
// ----------
// Dual-link DVI
// There are two DVI transmitters. One takes the even pixels, and
// the other takes the odd pixels. Each one takes data at double-
// data rate. On the rising edge, the master transmitter wants
// {r0[7:0], g0[7:4]}, and on the falling edge, {g0[3:0], b0[7:0]}.
// The slave transmitter wants the same for r1, g1, and b1.
wire [11:0] dvi_data_m_0 = {r0[9:2], g0[9:6]};
wire [11:0] dvi_data_m_1 = {g0[5:2], b0[9:2]};
wire [11:0] dvi_data_s_0 = {r1[9:2], g1[9:6]};
wire [11:0] dvi_data_s_1 = {g1[5:2], b1[9:2]};
// Now splice together the bits that go together in time.
// The lower 6 bits correspond to the extra analog precision,
// which are don't-cares for DVI.
wire [29:0] vid_data_dvi0 = {dvi_data_m_0, dvi_data_s_0, 6'b0};
wire [29:0] vid_data_dvi1 = {dvi_data_m_1, dvi_data_s_1, 6'b0};
// Since this is a DDR interface, it is convenient to use a DDR FF
// to provide the clock signal. IIRC, we want data0 to appear with
// the rising edge of the clock, so we want to produce it on the
// negative edge.
ddrff1 ff0 (.Q(dvi_m_clk), .C0(clock), .C1(~clock), .D0(1'b0),
.D1(1'b1), .OE(1'b1));
ddrff1 ff1 (.Q(dvi_s_clk), .C0(clock), .C1(~clock), .D0(1'b0),
.D1(1'b1), .OE(1'b1));
// Syncs for DVI
always @(posedge clock) begin
dvi_hsync <= hsync;
dvi_vsync <= vsync;
dvi_de <= de;
end
// Analog, 330MHz
// There is a single triple-DAC that takes one 30-bit pixel per clock,
// at the pixel rate. We can use DDR flipflops for the data (indeed, we must
// because we use the same pins for DVI), but the clock signal has to be twice
// as fast. This results in a radically different arrangement of bits for
// analog. Additionally, logically, we have separated out the lower pairs
// of bits for the 10-bit precision.
wire [24:0] dac_data_hi0 = {r0[9:2], g0[9:2], b0[9:2]};
wire [5:0] dac_data_lo0 = {r0[1:0], g0[1:0], b0[1:0]};
wire [24:0] dac_data_hi1 = {r1[9:2], g1[9:2], b1[9:2]};
wire [5:0] dac_data_lo1 = {r1[1:0], g1[1:0], b1[1:0]};
// Splice together in order
wire [29:0] vid_data_dac0 = {dac_data_hi0, dac_data_lo0};
wire [29:0] vid_data_dac1 = {dac_data_hi1, dac_data_lo1};
// There is a single clock signal, but at twice the rate, so here we
// use a 2x clock that will be generated from a DCM.
// Did I get the polarity right?
ddrff1 ff2 (.Q(dac_clk), .C0(clock_2x), .C1(~clock_2x), .D0(1'b0),
.D1(1'b1), .OE(1'b1));
// Syncs for Analog
// In actuality, we'll want to replace these with shift registers.
// DVI transmitters take syncs, but with analog, our sync signals go
// directly to the connector, while the video data itself has a few
// cycles of latency through the DAC. We need to delay the syncs
// to line up with the data. In OGA, we'll make this delay variable.
always @(posedge clock) begin
dac_hsync <= hsync;
dac_vsync <= vsync;
dac_de <= de;
end
// Now, select the data for DVI or analog and connect to the I/O drivers
wire using_dvi = 1;
wire [29:0] vid_data0 = using_dvi ? vid_data_dvi0 : vid_data_dac0;
wire [29:0] vid_data1 = using_dvi ? vid_data_dvi1 : vid_data_dac1;
ddrff30 ff2 (.Q(vid_data), .C0(clock), .C1(~clock),
.D0(vid_data0), .D1(vid_data1), .OE(1'b1));
endmodule
// For convenience, instantiate sets of DDR flipflops. You can basically
// ignore this.
module ddrff1(Q, C0, C1, D0, D1, OE);
input C0, C1, D0, D1, OE;
output Q;
wire R;
FDDRRSE ff0 (.Q(R), .C0(C0), .C1(C1), .CE(1'b1), .D0(D0), .D1(D1),
.R(1'b0), .S(1'b0));
assign Q = OE ? R : 1'bz;
endmodule
module ddrff4(Q, C0, C1, D0, D1, OE);
input C0, C1, OE;
input [3:0] D0, D1;
output [3:0] Q;
ddrff1 ff0 (.Q(Q[0]), .C0(C0), .C1(C1), .D0(D0[0]), .D1(D1[0]), .OE(OE));
ddrff1 ff1 (.Q(Q[1]), .C0(C0), .C1(C1), .D0(D0[1]), .D1(D1[1]), .OE(OE));
ddrff1 ff2 (.Q(Q[2]), .C0(C0), .C1(C1), .D0(D0[2]), .D1(D1[2]), .OE(OE));
ddrff1 ff3 (.Q(Q[3]), .C0(C0), .C1(C1), .D0(D0[3]), .D1(D1[3]), .OE(OE));
endmodule
module ddrff30(Q, C0, C1, D0, D1, OE);
input C0, C1, OE;
input [29:0] D0, D1;
output [29:0] Q;
ddrff4 ff0 (.Q(Q[ 3: 0]), .C0(C0), .C1(C1), .D0(D0[ 3: 0]), .D1(D1[ 3:
0]), .OE(OE));
ddrff4 ff1 (.Q(Q[ 7: 4]), .C0(C0), .C1(C1), .D0(D0[ 7: 4]), .D1(D1[ 7:
4]), .OE(OE));
ddrff4 ff2 (.Q(Q[11: 8]), .C0(C0), .C1(C1), .D0(D0[11: 8]), .D1(D1[11:
8]), .OE(OE));
ddrff4 ff3 (.Q(Q[15:12]), .C0(C0), .C1(C1), .D0(D0[15:12]),
.D1(D1[15:12]), .OE(OE));
ddrff4 ff4 (.Q(Q[19:16]), .C0(C0), .C1(C1), .D0(D0[19:16]),
.D1(D1[19:16]), .OE(OE));
ddrff4 ff5 (.Q(Q[23:20]), .C0(C0), .C1(C1), .D0(D0[23:20]),
.D1(D1[23:20]), .OE(OE));
ddrff4 ff6 (.Q(Q[27:24]), .C0(C0), .C1(C1), .D0(D0[27:24]),
.D1(D1[27:24]), .OE(OE));
ddrff1 ff7 (.Q(Q[28]), .C0(C0), .C1(C1), .D0(D0[28]), .D1(D1[28]), .OE(OE));
ddrff4 ff8 (.Q(Q[29]), .C0(C0), .C1(C1), .D0(D0[29]), .D1(D1[29]), .OE(OE));
endmodule
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)