On Fri, 2006-10-13 at 20:06 -0400, Timothy Miller wrote:
> On 10/13/06, Nicholas <[EMAIL PROTECTED]> wrote:
> 
> >
> > >
> > > Is there anything else a learner like myself could work on? i was thinking
> > > about looking a bit more on how the interfacing with the dvi transmitters
> > > work and see if I could write some module for that. But I guess that 
> > > without
> > > a development board it's better to work on something internal to the fpga.
> >
> > Yes, same here.
> 
> How about simulating a video device?
> 

Coming right up!
This is a version that has been hacked together, and is really nasty. I
should get the DVI signals dvi_s_clk and dvi_m_clk to be controlled
inside the test_head0 module, but I was lazy and it just does this for
now. Also note that the PPM file has some extra lines (since the capture
size is greater than a single frame), but it worked with ppmtobmp for
me. I don't actually know if it is producing correct waveforms, but it
does make a picture that looks reasonably accurate. Also, if you remove
the dvi_s_clk code from vidsim and just draw two pixels on dvi_m_clk, it
produces a nice blend from R->B. I haven't really checked why the
dvi_s_clk doesn't work.
To compile:
iverilog vidsim.v test_head0.v -o vidsim
./vidsim
ppmtobmp scanimage.ppm > scan.bmp
<insert favorite viewer here - e.g. gimp> scan.bmp

Also note that gtkwave testDVI.vcd now complains about the file being
172 MB and it might not load, but it works on this end.

last but not least, the 800x600 picture size is hardcoded in vidsim.v,
so remember to change that if you want to muck around with different
picture sizes!

> 
> And learn how to do text strings in Verilog, which is kludgy.
> 
> For a 10-char string, you would do something like:
> 
> reg [0:8*10-1] string;
> 
> ...
> 
>     string = "somestringx";
> 
> 

I haven't done this yet, but for multiple outputs it should be
relatively easy to use sprintf to generate the file name. My current
program doesn't actually detect the end of a frame, but it could be
programmed to by just counting the H/V en strobes.

I will have some time later today and will try to make this work a bit
nicer, but this is what I have from last night and this morning.

cheers!
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;
reg hs,vs,en;
reg [29:0] vid_data_store;
assign hsync=hs;
assign vsync=vs;
assign de=en;
wire [29:0] vid_data;
assign vid_data=vid_data_store;
wire dac_hsync,dac_vsync,dac_de,dac_clk;
wire dvi_m_clk,dvi_s_clk,dvi_hsync,dvi_vsync,dvi_de;
reg dvi_clk_m,dvi_clk_s;
assign dvi_m_clk=dvi_clk_m;
assign dvi_s_clk=dvi_clk_s;

head0_video_out u0(clock,clock_2x,reset,hsync,vsync,de,
                        ,dac_hsync,dac_vsync,dac_de,dac_clk,
                        ,,dvi_hsync,dvi_vsync,dvi_de); //DVI clocks in 
gen_head0_signals for now


vidfake faker(vid_data,dac_hsync,dac_vsync,dac_de,dac_clk,
                dvi_m_clk,dvi_s_clk,dvi_hsync,dvi_vsync,dvi_de); //This is a 
fake DVI monitor that outputs PPM

// 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;
                vid_data_store<=0;
        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 @(posedge clock_2x or negedge reset)
begin
        if (!reset) begin
                dvi_clk_m<=0;
        end else begin
                dvi_clk_m<=!dvi_clk_m;
        end
end
always @(negedge clock_2x or negedge reset)
begin
        if (!reset) begin
                dvi_clk_s<=0;
        end else begin
                dvi_clk_s<=!dvi_clk_s;
        end
end
always @(negedge clock)
begin
        vid_data_store[29:20]<=vert;
        vid_data_store[19:0]<=horiz;
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
//This is a module for simulating a video device for OGP.
//It is inspired by this message from Timothy Miller:

//How about simulating a video device?

//When we did TROZ, we developed simulation code that watched video
//signals coming out of the design and pretended to be a monitor.  Each
//frame of raster scan got output to an ASCII-format PPM file (the kind
//with "P3" as the first line) that we could look at later with an image
//viewer.

//Look up the functions $fopen, $fdisplay, $fwrite, and $fclose.

//And learn how to do text strings in Verilog, which is kludgy.

//For a 10-char string, you would do something like:

//reg [0:8*10-1] string;

//...

//    string = "somestringx";


//There are actually a number of things we could use simulation models
//for.  The one for SPI, I think, was okay, but it could be expanded.
//We need one for DDR SDRAM; the one from Samsung won't work with
//icarus, so we either fix it, or we write our own (that does NOT have
//to be as sophisticated).

//Also, if you work on something related to OGD1, then that will really
//help, but really, you can work on other things, and I'll be glad to
//help with those too.

module vidfake(    
// 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 );
parameter WIDTH=800,HEIGHT=600;
//currently just DVI because that is what I have been doing, but it is
// almost the same code for DAC. However, I haven't figured out the master
// and slave DVI transmitter yet, so just use the master, since it sounds 
// like the more important one.
input [29:0] vid_data;
input dac_hsync,dac_vsync,dac_de,dac_clk;
input dvi_m_clk,dvi_s_clk,dvi_hsync,dvi_vsync,dvi_de;

wire [29:0] vid_data;
wire dac_hsync,dac_vsync,dac_de,dac_clk;
wire dvi_m_clk,dvi_s_clk,dvi_hsync,dvi_vsync,dvi_de;

integer file; //the file descriptor
reg tofile; //are we printing or writing to a file the output?
integer ch; //something - channel? 
reg startedframe;
//from http://www-ee.eng.hawaii.edu/~msmith/ASICs/HTML/Book/CH11/CH11.13.htm
//other resources:
//http://www.chris.spear.net/pli/fileio.htm
//http://www.sugawara-systems.com/verilog-2001/fileio.htm

//and for PPM format:
//http://netpbm.sourceforge.net/doc/ppm.html
//http://www.physics.emory.edu/~weeks/graphics/mkppm.html
reg [9:0] r,g,b; //red, green, blue color components
initial begin
   file=$fopen("scanimage.ppm","w");
   if (file==0) begin
      $display("error with opening file, printing instead...");
      tofile=1'b0;
   end else begin
      tofile=1'b1;
      ch=file|1;
   end
   //this is going to be read during the first frame eventually, but for now
   // it is easier if it is just hardcoded.
   if (tofile==1'b1) begin
           $fwrite(ch,"P3\n"); //magic code for PPM plain
           $fwrite(ch,"# Test image drawn by DVI tester for OGP\n");
           $fwrite(ch,"%d ",WIDTH);
           $fwrite(ch,"%d\n",HEIGHT);
           $fwrite(ch,"255\n"); //max color value
   end else begin
           $display("P3\n"); //magic code for PPM plain
           $display("%d ",WIDTH);
           $display("%d\n",HEIGHT);
           $display("65535\n"); //max color value
   end
end
always @(posedge dvi_m_clk) begin
        if (dvi_de) begin
                r=vid_data[29:20];
                g=vid_data[19:10];
                b=vid_data[9:0];
                //store in 8:8:8 RGB format, 24bpp.
                if (tofile==1'b1) begin
                        $fwrite(ch,"%d ",r[9:1]);
                        $fwrite(ch,"%d ",g[9:1]);
                        $fwrite(ch,"%d\n",b[9:1]);
                        //this should make each line longer, but I don't
                        //want to have to deal with that for now.
                end else begin
                        $display("%d ",r[9:5]);
                        $display("%d ",g[9:4]);
                        $display("%d\n",b[9:5]);
                        $display("%d ",r[9:5]);
                        $display("%d ",g[9:4]);
                        $display("%d\n",b[9:5]);
                end
        end
end
always @(posedge dvi_s_clk) begin
        if (dvi_de) begin
                r=vid_data[29:20];
                g=vid_data[19:10];
                b=vid_data[9:0];
                //store in 8:8:8 RGB format, 24bpp.
                if (tofile==1'b1) begin
                        $fwrite(ch,"%d ",r[9:1]);
                        $fwrite(ch,"%d ",g[9:1]);
                        $fwrite(ch,"%d\n",b[9:1]);
                        //this should make each line longer, but I don't
                        //want to have to deal with that for now.
                end else begin
                        $display("%d ",r[9:5]);
                        $display("%d ",g[9:4]);
                        $display("%d\n",b[9:5]);
                end
        end
end
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)

Reply via email to