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)