URL
https://opencores.org/ocsvn/pdp1/pdp1/trunk
Subversion Repositories pdp1
Compare Revisions
- This comparison shows the changes necessary to convert path
/pdp1
- from Rev 5 to Rev 6
- ↔ Reverse comparison
Rev 5 → Rev 6
/trunk/rtl/verilog/vector2scanline.v
18,20 → 18,55
// |
////////////////////////////////////////////////////////////////////////////////// |
|
/* |
* 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_i, // clock |
|
clk_xy_i, // clock |
strobe_i, // new exposed pixel trigger |
x_i, // column of exposed pixel |
y_i, // row of exposed pixel |
|
clk_fifo_i, |
|
// Video output interface |
xout_i, // current pixel column |
yout_i, // current pixel row |
clk_video_i, // pixel clock |
xout_i, // current pixel column |
yout_i, // current pixel row |
newline_i, // line buffer swap signal |
newframe_i, // new frame signal |
pixel_o // output pixel intensity |
/*AUTOARG*/); |
pixel_o, // output pixel intensity, unregistered |
/*AUTOARG*/ |
// Inputs |
wipe_i |
); |
|
|
parameter X_WIDTH = 10; // bit width of column coordinate |
39,17 → 74,26
parameter HIST_WIDTH = 10; // log2 of maximum lit pixels (exposure buffer) |
parameter AGE_WIDTH = 8; // width of exposure age counter |
|
input clk_i; |
|
input clk_xy_i; |
input strobe_i; |
input [X_WIDTH-1:0] x_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 [Y_WIDTH-1:0] yout_i; |
input newline_i, newframe_i; |
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 |
reg [X_WIDTH+Y_WIDTH+AGE_WIDTH-1:0] exposures [(2**HIST_WIDTH)-1:0]; |
// output register of exposed pixels buffer |
65,20 → 109,28
// addresses for exposure buffer read and write ports |
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 |
// the other gets filled in with current exposures |
reg [AGE_WIDTH-1:0] scanline0 [(2**X_WIDTH)-1:0]; |
reg [AGE_WIDTH-1:0] scanline1 [(2**X_WIDTH)-1:0]; |
// output intensity for current pixel |
reg [AGE_WIDTH-1:0] pixelout; |
reg [AGE_WIDTH-1:0] scanlines [(2**X_WIDTH):0]; |
// selection register for which scanline buffer is output/filled in |
reg bufsel = 0; |
// address lines for scanline buffers |
wire [X_WIDTH-1:0] sl0w, sl1w; |
// address lines for the two memory ports |
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 |
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]; |
if (!strobe) begin |
// do not skip current read position if strobe inserts a new pixel |
87,50 → 139,52
end |
|
// 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 expy = strobe_i?y_i:expr[Y_WIDTH+AGE_WIDTH-1:AGE_WIDTH]; |
assign expi = strobe_i?(2**AGE_WIDTH)-1:expr[AGE_WIDTH-1:0]; |
assign expx = strobe?x_i:expr[X_WIDTH+Y_WIDTH+AGE_WIDTH-1:Y_WIDTH+AGE_WIDTH]; |
assign expy = strobe?y_i:expr[Y_WIDTH+AGE_WIDTH-1:AGE_WIDTH]; |
assign expi = strobe?(2**AGE_WIDTH)-1:expr[AGE_WIDTH-1:0]; |
// detect whether pixel even needs to be stored back |
assign exposed = expi!=0; |
// detect whether pixel applies to current backbuffer |
// TODO: use a next line input port, this incrementer won't work for |
// line 0 (which is unused in display.vhd) and could be shared. |
assign rowmatch=(expy==y_i+1); |
// TODO: use a next line input port, the double buffering delays this data |
// by an entire scanline. |
assign rowmatch=(expy==yout_i); |
|
always @(posedge clk_i) begin |
always @(posedge clk_fifo_i) begin |
// Feed incoming exposures into exposure buffer |
// TODO: stop scanning until newline once we're through the entire buffer |
if (exposed) begin |
exposures[expwptr] <= {expx, expy, expy==yout_i?expi-1:expi}; |
expwptr <= expwptr+1; |
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 |
pixelout <= bufsel?scanline1[xout_i]:scanline0[xout_i]; |
pixel_o <= scanlines[scanout_addr]; |
end |
|
// Store exposures for next scanline and wipe front buffer |
if (bufsel) begin |
if (rowmatch) |
scanline0[sl0w] <= expi; |
scanline1[sl1w] <= 0; |
end else begin |
if (rowmatch) |
scanline1[sl1w] <= expi; |
scanline0[sl0w] <= 0; |
// Back buffer address |
assign lineplot_addr = {~bufsel, expx}; |
assign lineplot_clk = clk_fifo_i; |
always @(posedge lineplot_clk) begin |
// pixel_o <= scanlines[lineplot_addr]; |
// Store exposures for next scanline |
if (rowmatch) begin |
scanlines[lineplot_addr] <= expi; |
end |
end |
|
always @(posedge clk_video_i) begin |
// swap buffers when signaled |
if (newline_i) begin |
if (newline) begin |
bufsel <= ~bufsel; |
end |
end |
|
// output pixel intensity |
assign pixel_o = pixelout; |
|
endmodule |