1 |
3 |
yannv |
`timescale 1ns / 1ps
|
2 |
|
|
//////////////////////////////////////////////////////////////////////////////////
|
3 |
|
|
// Engineer: Yann Vernier
|
4 |
|
|
//
|
5 |
|
|
// Create Date: 21:37:32 02/19/2011
|
6 |
|
|
// Design Name:
|
7 |
|
|
// Module Name: vector2scanline
|
8 |
|
|
// Project Name: PDP-1
|
9 |
|
|
// Target Devices: Spartan 3A
|
10 |
|
|
// Tool versions:
|
11 |
|
|
// Description: Converts vector data (exposed points) into raster video
|
12 |
|
|
//
|
13 |
|
|
// Dependencies:
|
14 |
|
|
//
|
15 |
5 |
yannv |
// Revision: $Id$
|
16 |
|
|
// $Log$
|
17 |
|
|
// Additional Comments:
|
18 |
|
|
//
|
19 |
3 |
yannv |
//////////////////////////////////////////////////////////////////////////////////
|
20 |
|
|
|
21 |
6 |
yannv |
/*
|
22 |
|
|
* Design: Two interfaces are provided, each with their own clock.
|
23 |
|
|
* The first is an XY plotting interface, where each new point
|
24 |
|
|
* is indicated by a rising edge on strobe_i.
|
25 |
|
|
* The second is the scanline/raster video port, where a pixel
|
26 |
|
|
* clock reads out a single scanline, and rising edges on
|
27 |
|
|
* newline_i and newframe_i indicate when a new or first line
|
28 |
|
|
* should start.
|
29 |
|
|
*
|
30 |
|
|
* The target design runs a pixel clock of 193MHz and plotting clock
|
31 |
|
|
* of 50MHz, ensuring that no plotted point is missed.
|
32 |
|
|
* A register to store the plotted point could be added instead, but
|
33 |
|
|
* currently hold times are guaranteed to work (changes only occur on
|
34 |
|
|
* a 200kHz cycle). Expect timing warnings, however.
|
35 |
|
|
*
|
36 |
|
|
* Internal structure: One ring buffer FIFO stores plotted points and their
|
37 |
|
|
* respective age. Age is decremented only when the points are copied into
|
38 |
|
|
* the scanline buffer (once per frame).
|
39 |
|
|
* A dual-port scanline buffer is filled in with plotted points in a back-
|
40 |
|
|
* buffer while the forward buffer is read out to video and subsequently
|
41 |
|
|
* wiped.
|
42 |
|
|
*
|
43 |
|
|
* The FIFO could be factored out and converted to LFSR counting.
|
44 |
|
|
*
|
45 |
|
|
* TODO: Make the scanning stop once it has reached the edges.
|
46 |
|
|
* Connect to main design. Add next scanline ports, so double
|
47 |
|
|
* buffers do not delay everything one line.
|
48 |
|
|
*
|
49 |
|
|
*/
|
50 |
|
|
|
51 |
3 |
yannv |
module vector2scanline(
|
52 |
6 |
yannv |
clk_xy_i, // clock
|
53 |
5 |
yannv |
strobe_i, // new exposed pixel trigger
|
54 |
|
|
x_i, // column of exposed pixel
|
55 |
|
|
y_i, // row of exposed pixel
|
56 |
3 |
yannv |
|
57 |
6 |
yannv |
clk_fifo_i,
|
58 |
|
|
|
59 |
4 |
yannv |
// Video output interface
|
60 |
6 |
yannv |
clk_video_i, // pixel clock
|
61 |
|
|
xout_i, // current pixel column
|
62 |
|
|
yout_i, // current pixel row
|
63 |
5 |
yannv |
newline_i, // line buffer swap signal
|
64 |
|
|
newframe_i, // new frame signal
|
65 |
6 |
yannv |
pixel_o, // output pixel intensity, unregistered
|
66 |
|
|
/*AUTOARG*/
|
67 |
|
|
// Inputs
|
68 |
|
|
wipe_i
|
69 |
|
|
);
|
70 |
3 |
yannv |
|
71 |
5 |
yannv |
|
72 |
4 |
yannv |
parameter X_WIDTH = 10; // bit width of column coordinate
|
73 |
|
|
parameter Y_WIDTH = 10; // bit width of row coordinate
|
74 |
|
|
parameter HIST_WIDTH = 10; // log2 of maximum lit pixels (exposure buffer)
|
75 |
|
|
parameter AGE_WIDTH = 8; // width of exposure age counter
|
76 |
5 |
yannv |
|
77 |
6 |
yannv |
input clk_xy_i;
|
78 |
5 |
yannv |
input strobe_i;
|
79 |
|
|
input [X_WIDTH-1:0] x_i;
|
80 |
|
|
input [Y_WIDTH-1:0] y_i;
|
81 |
3 |
yannv |
|
82 |
6 |
yannv |
input clk_fifo_i;
|
83 |
|
|
input [AGE_WIDTH-1:0] wipe_i;
|
84 |
|
|
|
85 |
|
|
input clk_video_i;
|
86 |
5 |
yannv |
input [X_WIDTH-1:0] xout_i;
|
87 |
|
|
input [Y_WIDTH-1:0] yout_i;
|
88 |
|
|
input newline_i, newframe_i;
|
89 |
|
|
output [AGE_WIDTH-1:0] pixel_o;
|
90 |
6 |
yannv |
reg pixel_o;
|
91 |
5 |
yannv |
|
92 |
6 |
yannv |
// Used for edge detection on strobe signals
|
93 |
|
|
reg prev_strobe_i, prev_newline_i, prev_newframe_i;
|
94 |
|
|
// Result of edge detectors
|
95 |
|
|
wire strobe, newline, newframe;
|
96 |
|
|
|
97 |
4 |
yannv |
// positions and age of lit pixels
|
98 |
|
|
reg [X_WIDTH+Y_WIDTH+AGE_WIDTH-1:0] exposures [(2**HIST_WIDTH)-1:0];
|
99 |
|
|
// output register of exposed pixels buffer
|
100 |
|
|
reg [X_WIDTH+Y_WIDTH+AGE_WIDTH-1:0] expr;
|
101 |
|
|
// data for next pixel to store in exposure buffer
|
102 |
|
|
wire [X_WIDTH-1:0] expx;
|
103 |
|
|
wire [Y_WIDTH-1:0] expy;
|
104 |
5 |
yannv |
wire [AGE_WIDTH-1:0] expi;
|
105 |
4 |
yannv |
// whether this pixel needs to be stored back in exposure buffer
|
106 |
|
|
wire exposed;
|
107 |
5 |
yannv |
// whether this pixel belongs to the next (backbuffer) scanline
|
108 |
|
|
wire rowmatch;
|
109 |
4 |
yannv |
// addresses for exposure buffer read and write ports
|
110 |
|
|
reg [HIST_WIDTH-1:0] exprptr=0, expwptr=0;
|
111 |
5 |
yannv |
|
112 |
6 |
yannv |
// dual port scanline pixel buffer, stores intensity
|
113 |
4 |
yannv |
// double-buffered; one gets wiped as it is displayed
|
114 |
|
|
// the other gets filled in with current exposures
|
115 |
6 |
yannv |
reg [AGE_WIDTH-1:0] scanlines [(2**X_WIDTH):0];
|
116 |
4 |
yannv |
// selection register for which scanline buffer is output/filled in
|
117 |
|
|
reg bufsel = 0;
|
118 |
6 |
yannv |
// address lines for the two memory ports
|
119 |
|
|
wire [X_WIDTH:0] scanout_addr, lineplot_addr;
|
120 |
|
|
wire scanout_clk, lineplot_clk;
|
121 |
5 |
yannv |
|
122 |
6 |
yannv |
// Edge detectors for strobe lines
|
123 |
|
|
always @(posedge clk_xy_i) prev_strobe_i <= strobe_i;
|
124 |
|
|
assign strobe = strobe_i & ~prev_strobe_i;
|
125 |
|
|
always @(posedge clk_video_i) prev_newline_i <= newline_i;
|
126 |
|
|
assign newline = newline_i & ~prev_newline_i;
|
127 |
|
|
always @(posedge clk_video_i) prev_newframe_i <= newframe_i;
|
128 |
|
|
assign newframe = newframe_i & ~prev_newframe_i;
|
129 |
|
|
|
130 |
|
|
|
131 |
4 |
yannv |
// RAM read out of exposure buffer
|
132 |
6 |
yannv |
always @(posedge clk_fifo_i) begin
|
133 |
|
|
// TODO: stop scanning until newline once we're through the entire buffer
|
134 |
4 |
yannv |
expr<=exposures[exprptr];
|
135 |
|
|
if (!strobe) begin
|
136 |
|
|
// do not skip current read position if strobe inserts a new pixel
|
137 |
|
|
exprptr<=exprptr+1;
|
138 |
|
|
end
|
139 |
|
|
end
|
140 |
3 |
yannv |
|
141 |
4 |
yannv |
// decode and mux: split fields from exposure buffer, or collect new at strobe
|
142 |
6 |
yannv |
assign expx = strobe?x_i:expr[X_WIDTH+Y_WIDTH+AGE_WIDTH-1:Y_WIDTH+AGE_WIDTH];
|
143 |
|
|
assign expy = strobe?y_i:expr[Y_WIDTH+AGE_WIDTH-1:AGE_WIDTH];
|
144 |
|
|
assign expi = strobe?(2**AGE_WIDTH)-1:expr[AGE_WIDTH-1:0];
|
145 |
4 |
yannv |
// detect whether pixel even needs to be stored back
|
146 |
|
|
assign exposed = expi!=0;
|
147 |
5 |
yannv |
// detect whether pixel applies to current backbuffer
|
148 |
6 |
yannv |
// TODO: use a next line input port, the double buffering delays this data
|
149 |
|
|
// by an entire scanline.
|
150 |
|
|
assign rowmatch=(expy==yout_i);
|
151 |
4 |
yannv |
|
152 |
6 |
yannv |
always @(posedge clk_fifo_i) begin
|
153 |
4 |
yannv |
// Feed incoming exposures into exposure buffer
|
154 |
6 |
yannv |
// TODO: stop scanning until newline once we're through the entire buffer
|
155 |
4 |
yannv |
if (exposed) begin
|
156 |
5 |
yannv |
exposures[expwptr] <= {expx, expy, expy==yout_i?expi-1:expi};
|
157 |
4 |
yannv |
expwptr <= expwptr+1;
|
158 |
|
|
end
|
159 |
|
|
end
|
160 |
3 |
yannv |
|
161 |
6 |
yannv |
|
162 |
7 |
yannv |
// Front buffer address
|
163 |
6 |
yannv |
assign scanout_addr = {bufsel,xout_i};
|
164 |
|
|
assign scanout_clk = clk_video_i;
|
165 |
|
|
always @(posedge scanout_clk) begin
|
166 |
|
|
// Wipe front buffer
|
167 |
|
|
scanlines[scanout_addr] <= wipe_i;
|
168 |
4 |
yannv |
// Read out front buffer
|
169 |
6 |
yannv |
pixel_o <= scanlines[scanout_addr];
|
170 |
|
|
end
|
171 |
5 |
yannv |
|
172 |
6 |
yannv |
// Back buffer address
|
173 |
|
|
assign lineplot_addr = {~bufsel, expx};
|
174 |
|
|
assign lineplot_clk = clk_fifo_i;
|
175 |
|
|
always @(posedge lineplot_clk) begin
|
176 |
|
|
// pixel_o <= scanlines[lineplot_addr];
|
177 |
|
|
// Store exposures for next scanline
|
178 |
|
|
if (rowmatch) begin
|
179 |
|
|
scanlines[lineplot_addr] <= expi;
|
180 |
4 |
yannv |
end
|
181 |
6 |
yannv |
end
|
182 |
5 |
yannv |
|
183 |
6 |
yannv |
always @(posedge clk_video_i) begin
|
184 |
4 |
yannv |
// swap buffers when signaled
|
185 |
6 |
yannv |
if (newline) begin
|
186 |
4 |
yannv |
bufsel <= ~bufsel;
|
187 |
|
|
end
|
188 |
|
|
end
|
189 |
5 |
yannv |
|
190 |
3 |
yannv |
endmodule
|