On Sat, 2006-10-14 at 12:35 -0400, Nicholas wrote:
> 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
I already have a new version. This one should draw correctly, and it
turns out gimp directly supports PPM!
Next step is to integrate gen_head0_signals into test_head0, so that I
can actually use the DDR FF and [r,g,b][0,1]. After that, another
rewrite of vidsim and it should all work reasonably. Once I get a single
frame displayed correctly, I'll do the string magic to get each frame
into a separate file. I also noticed some glitching at the end of the
image on lines 599 & 600 which I need to fix.
nick
//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,"1023\n"); //max color value
end else begin
$display("P3\n"); //magic code for PPM plain
$display("# Test image drawn by DVI tester for OGP\n");
$display("%d ",WIDTH);
$display("%d\n",HEIGHT);
$display("1023\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);
$fwrite(ch,"%d ",g);
$fwrite(ch,"%d\n",b);
//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);
$display("%d ",g);
$display("%d\n",b);
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);
$fwrite(ch,"%d ",g);
$fwrite(ch,"%d\n",b);
//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);
$display("%d ",g);
$display("%d\n",b);
end
end
end
endmodule
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 @(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
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)