Line 16... |
Line 16... |
// $Log$
|
// $Log$
|
// Additional Comments:
|
// Additional Comments:
|
//
|
//
|
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
module vector2scanline(
|
/*
|
clk_i, // clock
|
* Design: Two interfaces are provided, each with their own clock.
|
|
* The first is an XY plotting interface, where each new point
|
|
* is indicated by a rising edge on strobe_i.
|
|
* The second is the scanline/raster video port, where a pixel
|
|
* clock reads out a single scanline, and rising edges on
|
|
* newline_i and newframe_i indicate when a new or first line
|
|
* should start.
|
|
*
|
|
* The target design runs a pixel clock of 193MHz and plotting clock
|
|
* of 50MHz, ensuring that no plotted point is missed.
|
|
* A register to store the plotted point could be added instead, but
|
|
* currently hold times are guaranteed to work (changes only occur on
|
|
* a 200kHz cycle). Expect timing warnings, however.
|
|
*
|
|
* Internal structure: One ring buffer FIFO stores plotted points and their
|
|
* respective age. Age is decremented only when the points are copied into
|
|
* the scanline buffer (once per frame).
|
|
* A dual-port scanline buffer is filled in with plotted points in a back-
|
|
* buffer while the forward buffer is read out to video and subsequently
|
|
* wiped.
|
|
*
|
|
* The FIFO could be factored out and converted to LFSR counting.
|
|
*
|
|
* TODO: Make the scanning stop once it has reached the edges.
|
|
* Connect to main design. Add next scanline ports, so double
|
|
* buffers do not delay everything one line.
|
|
*
|
|
*/
|
|
|
|
module vector2scanline(
|
|
clk_xy_i, // clock
|
strobe_i, // new exposed pixel trigger
|
strobe_i, // new exposed pixel trigger
|
x_i, // column of exposed pixel
|
x_i, // column of exposed pixel
|
y_i, // row of exposed pixel
|
y_i, // row of exposed pixel
|
|
|
|
clk_fifo_i,
|
|
|
// Video output interface
|
// Video output interface
|
|
clk_video_i, // pixel clock
|
xout_i, // current pixel column
|
xout_i, // current pixel column
|
yout_i, // current pixel row
|
yout_i, // current pixel row
|
newline_i, // line buffer swap signal
|
newline_i, // line buffer swap signal
|
newframe_i, // new frame signal
|
newframe_i, // new frame signal
|
pixel_o // output pixel intensity
|
pixel_o, // output pixel intensity, unregistered
|
/*AUTOARG*/);
|
/*AUTOARG*/
|
|
// Inputs
|
|
wipe_i
|
|
);
|
|
|
|
|
parameter X_WIDTH = 10; // bit width of column coordinate
|
parameter X_WIDTH = 10; // bit width of column coordinate
|
parameter Y_WIDTH = 10; // bit width of row coordinate
|
parameter Y_WIDTH = 10; // bit width of row coordinate
|
parameter HIST_WIDTH = 10; // log2 of maximum lit pixels (exposure buffer)
|
parameter HIST_WIDTH = 10; // log2 of maximum lit pixels (exposure buffer)
|
parameter AGE_WIDTH = 8; // width of exposure age counter
|
parameter AGE_WIDTH = 8; // width of exposure age counter
|
|
|
input clk_i;
|
input clk_xy_i;
|
|
|
input strobe_i;
|
input strobe_i;
|
input [X_WIDTH-1:0] x_i;
|
input [X_WIDTH-1:0] x_i;
|
input [Y_WIDTH-1:0] y_i;
|
input [Y_WIDTH-1:0] y_i;
|
|
|
|
input clk_fifo_i;
|
|
input [AGE_WIDTH-1:0] wipe_i;
|
|
|
|
input clk_video_i;
|
input [X_WIDTH-1:0] xout_i;
|
input [X_WIDTH-1:0] xout_i;
|
input [Y_WIDTH-1:0] yout_i;
|
input [Y_WIDTH-1:0] yout_i;
|
input newline_i, newframe_i;
|
input newline_i, newframe_i;
|
output [AGE_WIDTH-1:0] pixel_o;
|
output [AGE_WIDTH-1:0] pixel_o;
|
|
reg pixel_o;
|
|
|
|
// Used for edge detection on strobe signals
|
|
reg prev_strobe_i, prev_newline_i, prev_newframe_i;
|
|
// Result of edge detectors
|
|
wire strobe, newline, newframe;
|
|
|
// positions and age of lit pixels
|
// positions and age of lit pixels
|
reg [X_WIDTH+Y_WIDTH+AGE_WIDTH-1:0] exposures [(2**HIST_WIDTH)-1:0];
|
reg [X_WIDTH+Y_WIDTH+AGE_WIDTH-1:0] exposures [(2**HIST_WIDTH)-1:0];
|
// output register of exposed pixels buffer
|
// output register of exposed pixels buffer
|
reg [X_WIDTH+Y_WIDTH+AGE_WIDTH-1:0] expr;
|
reg [X_WIDTH+Y_WIDTH+AGE_WIDTH-1:0] expr;
|
Line 63... |
Line 107... |
// whether this pixel belongs to the next (backbuffer) scanline
|
// whether this pixel belongs to the next (backbuffer) scanline
|
wire rowmatch;
|
wire rowmatch;
|
// addresses for exposure buffer read and write ports
|
// addresses for exposure buffer read and write ports
|
reg [HIST_WIDTH-1:0] exprptr=0, expwptr=0;
|
reg [HIST_WIDTH-1:0] exprptr=0, expwptr=0;
|
|
|
// scanline pixel buffers, store intensity
|
// dual port scanline pixel buffer, stores intensity
|
// double-buffered; one gets wiped as it is displayed
|
// double-buffered; one gets wiped as it is displayed
|
// the other gets filled in with current exposures
|
// the other gets filled in with current exposures
|
reg [AGE_WIDTH-1:0] scanline0 [(2**X_WIDTH)-1:0];
|
reg [AGE_WIDTH-1:0] scanlines [(2**X_WIDTH):0];
|
reg [AGE_WIDTH-1:0] scanline1 [(2**X_WIDTH)-1:0];
|
|
// output intensity for current pixel
|
|
reg [AGE_WIDTH-1:0] pixelout;
|
|
// selection register for which scanline buffer is output/filled in
|
// selection register for which scanline buffer is output/filled in
|
reg bufsel = 0;
|
reg bufsel = 0;
|
// address lines for scanline buffers
|
// address lines for the two memory ports
|
wire [X_WIDTH-1:0] sl0w, sl1w;
|
wire [X_WIDTH:0] scanout_addr, lineplot_addr;
|
|
wire scanout_clk, lineplot_clk;
|
|
|
|
// Edge detectors for strobe lines
|
|
always @(posedge clk_xy_i) prev_strobe_i <= strobe_i;
|
|
assign strobe = strobe_i & ~prev_strobe_i;
|
|
always @(posedge clk_video_i) prev_newline_i <= newline_i;
|
|
assign newline = newline_i & ~prev_newline_i;
|
|
always @(posedge clk_video_i) prev_newframe_i <= newframe_i;
|
|
assign newframe = newframe_i & ~prev_newframe_i;
|
|
|
|
|
// RAM read out of exposure buffer
|
// RAM read out of exposure buffer
|
always @(posedge clk_i) begin
|
always @(posedge clk_fifo_i) begin
|
|
// TODO: stop scanning until newline once we're through the entire buffer
|
expr<=exposures[exprptr];
|
expr<=exposures[exprptr];
|
if (!strobe) begin
|
if (!strobe) begin
|
// do not skip current read position if strobe inserts a new pixel
|
// do not skip current read position if strobe inserts a new pixel
|
exprptr<=exprptr+1;
|
exprptr<=exprptr+1;
|
end
|
end
|
end
|
end
|
|
|
// decode and mux: split fields from exposure buffer, or collect new at strobe
|
// decode and mux: split fields from exposure buffer, or collect new at strobe
|
assign expx = strobe_i?x_i:expr[X_WIDTH+Y_WIDTH+AGE_WIDTH-1:Y_WIDTH+AGE_WIDTH];
|
assign expx = strobe?x_i:expr[X_WIDTH+Y_WIDTH+AGE_WIDTH-1:Y_WIDTH+AGE_WIDTH];
|
assign expy = strobe_i?y_i:expr[Y_WIDTH+AGE_WIDTH-1:AGE_WIDTH];
|
assign expy = strobe?y_i:expr[Y_WIDTH+AGE_WIDTH-1:AGE_WIDTH];
|
assign expi = strobe_i?(2**AGE_WIDTH)-1:expr[AGE_WIDTH-1:0];
|
assign expi = strobe?(2**AGE_WIDTH)-1:expr[AGE_WIDTH-1:0];
|
// detect whether pixel even needs to be stored back
|
// detect whether pixel even needs to be stored back
|
assign exposed = expi!=0;
|
assign exposed = expi!=0;
|
// detect whether pixel applies to current backbuffer
|
// detect whether pixel applies to current backbuffer
|
// TODO: use a next line input port, this incrementer won't work for
|
// TODO: use a next line input port, the double buffering delays this data
|
// line 0 (which is unused in display.vhd) and could be shared.
|
// by an entire scanline.
|
assign rowmatch=(expy==y_i+1);
|
assign rowmatch=(expy==yout_i);
|
|
|
always @(posedge clk_i) begin
|
always @(posedge clk_fifo_i) begin
|
// Feed incoming exposures into exposure buffer
|
// Feed incoming exposures into exposure buffer
|
|
// TODO: stop scanning until newline once we're through the entire buffer
|
if (exposed) begin
|
if (exposed) begin
|
exposures[expwptr] <= {expx, expy, expy==yout_i?expi-1:expi};
|
exposures[expwptr] <= {expx, expy, expy==yout_i?expi-1:expi};
|
expwptr <= expwptr+1;
|
expwptr <= expwptr+1;
|
end
|
end
|
end
|
end
|
|
|
// scanline buffers switch output or expose roles based on bufsel
|
|
assign sl0w=bufsel?expx:xout_i;
|
|
assign sl1w=bufsel?xout_i:expx;
|
|
|
|
always @(posedge clk_i) begin
|
// Fron buffer address
|
|
assign scanout_addr = {bufsel,xout_i};
|
|
assign scanout_clk = clk_video_i;
|
|
always @(posedge scanout_clk) begin
|
|
// Wipe front buffer
|
|
scanlines[scanout_addr] <= wipe_i;
|
// Read out front buffer
|
// Read out front buffer
|
pixelout <= bufsel?scanline1[xout_i]:scanline0[xout_i];
|
pixel_o <= scanlines[scanout_addr];
|
|
end
|
|
|
// Store exposures for next scanline and wipe front buffer
|
// Back buffer address
|
if (bufsel) begin
|
assign lineplot_addr = {~bufsel, expx};
|
if (rowmatch)
|
assign lineplot_clk = clk_fifo_i;
|
scanline0[sl0w] <= expi;
|
always @(posedge lineplot_clk) begin
|
scanline1[sl1w] <= 0;
|
// pixel_o <= scanlines[lineplot_addr];
|
end else begin
|
// Store exposures for next scanline
|
if (rowmatch)
|
if (rowmatch) begin
|
scanline1[sl1w] <= expi;
|
scanlines[lineplot_addr] <= expi;
|
scanline0[sl0w] <= 0;
|
end
|
end
|
end
|
|
|
|
always @(posedge clk_video_i) begin
|
// swap buffers when signaled
|
// swap buffers when signaled
|
if (newline_i) begin
|
if (newline) begin
|
bufsel <= ~bufsel;
|
bufsel <= ~bufsel;
|
end
|
end
|
end
|
end
|
|
|
// output pixel intensity
|
|
assign pixel_o = pixelout;
|
|
|
|
endmodule
|
endmodule
|
|
|
No newline at end of file
|
No newline at end of file
|