[Open-graphics] Help with specs on TV chip?

Nicholas nova at macintoshclub.com
Fri Oct 6 21:25:44 EDT 2006


> In another thread, I posted this module.  Here it is again:
> 
> module FDDRRSE(Q, C0, C1, CE, D0, D1, R, S);
> output Q;
> reg Q;
> input C0, C1, CE, D0, D1, R, S;
> always @(posedge C0) Q <= D0;
> always @(posedge C1) Q <= D1;
> endmodule
> Add this to your test module that wraps the video module.

All right, I fixed that. I'll be sure to keep this module around from
now on :-).

I now control the DVI sync signals in my module, and it should produce
the right waveform now. I can actually use = and <= properly now,
instead of dreading what each one means :-)

The one thing is that I don't control the data at all. I plan on just
making one of two changes:
1) making gen_head0_signals module merge into head0_video_out,
2) making r,g,b into wires which are then controlled from
gen_head0_signals.
Which is a better idea? I would prefer (2) because that way people only
have to deal with gen_head0_signals and there is a semi-abstraction
barrier between the modules, but either one should work fine.

Also note that the output that is fixed is at 2652768 seconds (since the
rest is just a full frame, which takes a while).

and appended is the modules themselves.

nick

module test_head0;
//simple test interface
wire clkout,clk2out,resetout;
reg clock, clock_2x,reset;
initial begin
    clock = 0;
    forever begin
        clock = !clock;
        #2;
    end
end

initial begin
    clock_2x = 0;
    forever begin
        clock_2x = !clock_2x;
        #1;
    end
end

initial begin
    $dumpfile( "testDVI.vcd" );
    $dumpvars;
    
    reset = 0;
    #100;
    reset = 1;
    
    #3000000;
    $finish;
end

assign clkout=clock;
assign clk2out=clock_2x;
assign resetout=reset;
gen_head0_signals u0(clkout, clk2out,resetout);
endmodule


module gen_head0_signals(
	clock,
	clock_2x,
	reset);
input clock,clock_2x,reset;
wire clock,clock_2x,reset;
wire hsync,vsync,de;module test_head0;
//simple test interface
wire clkout,clk2out,resetout;
reg clock, clock_2x,reset;
initial begin
    clock = 0;
    forever begin
        clock = !clock;
        #2;
    end
end

initial begin
    clock_2x = 0;
    forever begin
        clock_2x = !clock_2x;
        #1;
    end
end

initial begin
    $dumpfile( "testDVI.vcd" );
    $dumpvars;
    
    reset = 0;
    #100;
    reset = 1;
    
    #3000000;
    $finish;
end

assign clkout=clock;
assign clk2out=clock_2x;
assign resetout=reset;
gen_head0_signals u0(clkout, clk2out,resetout);
endmodule


module gen_head0_signals(
	clock,
	clock_2x,
	reset);
input clock,clock_2x,reset;
wire clock,clock_2x,reset;
wire hsync,vsync,de;
reg hs,vs,en;
assign hsync=hs;
assign vsync=vs;
assign de=en;
head0_video_out u0(clock,clock_2x,reset,hsync,vsync,de,,,,,,,,,,);

// 800 X 600 @ 60Hz with a 40.000MHz pixel clock
parameter 	H_ACTIVE =	800,	// pixels
 		H_FRONT_PORCH =	40,	// pixels
		H_SYNCH =	128,	// pixels
		H_BACK_PORCH =	88,	// pixels
		H_TOTAL = 	1056,	// pixels
		V_ACTIVE =	600,	// lines
		V_FRONT_PORCH =	1,	// lines
		V_SYNCH =	4,	// lines
		V_BACK_PORCH =	23,	// lines
		V_TOTAL =	628;	// lines

parameter 	SYNC_STATE=1'b1,
		PORCH_STATE=1'b0,
		DATA_STATE=2'b00;	


reg [9:0] vert; //current vertical scanline location
reg [11:0] horiz; //current pixel in scanline
reg [1:0] hstate; //horizontal and vertical states
reg [1:0] vstate; //so it is easier to ref them.

always @(posedge clock or negedge reset)
begin
	if (!reset) begin

reg hs,vs,en;
assign hsync=hs;
assign vsync=vs;
assign de=en;
head0_video_out u0(clock,clock_2x,reset,hsync,vsync,de,,,,,,,,,,);

// 800 X 600 @ 60Hz with a 40.000MHz pixel clock
parameter 	H_ACTIVE =	800,	// pixels
 		H_FRONT_PORCH =	40,	// pixels
		H_SYNCH =	128,	// pixels
		H_BACK_PORCH =	88,	// pixels
		H_TOTAL = 	1056,	// pixels
		V_ACTIVE =	600,	// lines
		V_FRONT_PORCH =	1,	// lines
		V_SYNCH =	4,	// lines
		V_BACK_PORCH =	23,	// lines
		V_TOTAL =	628;	// lines

parameter 	SYNC_STATE=1'b1,
		PORCH_STATE=1'b0,
		DATA_STATE=2'b00;	


reg [9:0] vert; //current vertical scanline location
reg [11:0] horiz; //current pixel in scanline
reg [1:0] hstate; //horizontal and vertical states
reg [1:0] vstate; //so it is easier to ref them.

always @(posedge clock or negedge reset)
begin
	if (!reset) begin
		vert<=0;
		horiz<=0;
		hstate<=0;
		vstate<=0;
		en<=1'b0;
	end else begin
		horiz <= horiz + 1;
		case (horiz)
			H_TOTAL-1:
				begin
					hstate <= 0;
					horiz <=0;
					vert=vert + 1;
					//because the blocking
					//occurs one time-delta
					//later, it misses when
					//vert is tested and then
					//it is switched next time
					//around.
				end
			H_SYNCH + H_FRONT_PORCH + H_ACTIVE-1:
				begin
					hstate <= 3;
				end
			H_FRONT_PORCH + H_ACTIVE-1:
				begin
					hstate <= 2;
				end
			H_ACTIVE-1:
				begin
					hstate <= 1;
				end
		endcase
	end
end

always @(hstate or vstate)
begin
	//now all the states are correct:
	//0) Active - White.
	//1) Front Porch.
	//2) Sync signal. 0.
	//3) Back Porch.

	//now all is ready.
	//insert here the code to make colors based
	//on the various values.
	//example: just sync signals.
	if (vstate==2) //sync state
	begin
		vs<=SYNC_STATE;
		en<=1'b0;
	end
	if (hstate==2) //sync state
	begin
		hs<=SYNC_STATE;
		en<=1'b0;
	end
	if (hstate==1 || hstate==3) //porch state
	begin
		hs<=PORCH_STATE;
		en<=1'b0;
	end
	if (vstate==1 || vstate==3) //vertporch state
	begin
		vs<=PORCH_STATE;
		en<=1'b0;
	end
	if (hstate==0 && vstate==0) //draw state
	begin
		{hs,vs}<=DATA_STATE;
		en<=1'b1;
	end
end
always @(posedge clock)
begin
	//Now set up Vert in the same way... 
		case(vert)
			V_TOTAL-1:
				begin
					if (horiz==H_TOTAL-1)
					begin
						vert <=0;
						vstate <=0;
					end
					// new frame
				end
			V_SYNCH + V_FRONT_PORCH + V_ACTIVE-1:
				begin
					vstate <= 3;
				end
			V_FRONT_PORCH + V_ACTIVE-1:
				begin
					vstate <= 2;
				end
			V_ACTIVE-1:
				begin
					vstate <= 1;
				end
		endcase
end



endmodule


module head0_video_out(
    clock,
    clock_2x,
    reset,
    hsync,
    vsync,
    de,
    // 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, clock_2x, reset,hsync,vsync,de;

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
wire 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 ff3 (.Q(vid_data), .C0(clock), .C1(~clock),
    .D0(vid_data0), .D1(vid_data1), .OE(1'b1));

endmodule


module FDDRRSE(Q, C0, C1, CE, D0, D1, R, S);
output Q;
reg Q;
input C0, C1, CE, D0, D1, R, S;
always @(posedge C0) Q <= D0;
always @(posedge C1) Q <= D1;
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));
ddrff1 ff8
(.Q(Q[29]), .C0(C0), .C1(C1), .D0(D0[29]), .D1(D1[29]), .OE(OE));
endmodule



More information about the Open-graphics mailing list