Skip to content

Commit 3f0dfd9

Browse files
committed
Pixel beam position is now a signed 16-bit value.
(x,y) and (h,v) have both been replaced with (sx,sy). The use of sx and sy is designed to make it easy to distinguish screen coordinates from world or model coordinates.
1 parent f6957da commit 3f0dfd9

File tree

7 files changed

+81
-108
lines changed

7 files changed

+81
-108
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ To get started take a look at the [demos](#demos) then read [modules](doc/module
66

77
For tutorials and further information visit [projectf.io](https://projectf.io).
88

9+
_NB. Pixel coordinates are now signed values and have been renamed; see module documentation for [display timings](doc/modules.md#display-timings)._
10+
911
## Contents
1012

1113
- [Display Interface Support](#display-interface-support)
@@ -124,9 +126,9 @@ The following table shows utilization of the display-controller with the gradien
124126
Interface LUT FF
125127
-----------------------------
126128
DVI on FPGA 278 86
127-
DVI BML 3-bit 49 32
129+
DVI BML 3-bit 86 32
128130
DVI BML 24-bit TBC TBC
129-
VGA 12-bit 67 32
131+
VGA 12-bit 92 32
130132
-----------------------------
131133
Synthesized and implemented with Vivado 2019.1 using default options.
132134

doc/modules.md

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ The display timings generator turns timing parameters into appropriately timed s
8181

8282
### Inputs
8383

84-
* `i_pixclk` - pixel clock
84+
* `i_pix_clk` - pixel clock
8585
* `i_rst` - reset (active high)
8686

8787
The pixel clock must be suitable for the timings given in the parameters (see display clocks, above).
@@ -92,19 +92,13 @@ The pixel clock must be suitable for the timings given in the parameters (see di
9292
* `o_vs` - vertical sync
9393
* `o_de` - display enable: high during active video
9494
* `o_frame` - high for one tick at the start of each frame
95-
* `o_h [15:0]` - horizontal beam position (including blanking)
96-
* `o_v [15:0]` - vertical beam position (including blanking)
97-
* `o_x [15:0]` - horizontal screen position (active pixels)
98-
* `o_y [15:0]` - vertical screen position (active pixels)
95+
* `o_sx [15:0]` - horizontal screen position (signed)
96+
* `o_sy [15:0]` - vertical screen position (signed)
9997

100-
The positional outputs `(h,v)` and `(x,y)` allow you to determine the current pixel AKA "beam position". The values provided by `h` & `v `include the blanking interval, while `x` & `y` only include valid on-screen positions. For simple drawing or bitmap display you can use `(x,y)` and safely ignore `(h,v)`. However, if you're doing calculations in real time "racing the beam", then you'll want to perform actions in the blanking interval, which is where (h,v) comes in.
101-
102-
Project F considers blanking intervals to occur _before_ active pixels. At the start of a frame (indicated by the `o_frame` signal), you have the blanking intervals in which to work before active pixel drawing occurs. The following sketch this for 1280x720p60 (other resolutions work in the same way):
98+
The current beam position is given by `(sx, sy)`. `sx` and `sy` are *signed* 16-bit values. When display enable (`o_de`) is high these values indicate the active drawing pixel and are always positive. During the blanking interval one or both of `sx` and `sy` will be negative. This allows you to prepare for drawing, e.g. if you have a two cycle latency to retrieve a pixel's colour you can request the data for the first pixel of a line when `sx == -2`.
10399

104100
![](display-controller-hv-xy.jpg?raw=true "")
105101

106-
NB. `x` and `y` are 0 during the blanking interval.
107-
108102
Horizontal and vertical sync may be active high or low depending on the display mode; this is controlled using the `H_POL` and `V_POL` parameters (below).
109103

110104
### Parameters

hdl/demo/display_demo_dvi.v

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ module display_demo_dvi(
5151
);
5252

5353
// Display Timings
54-
wire [15:0] x; // horizontal screen position
55-
wire [15:0] y; // vertical screen position
54+
wire [15:0] sx; // horizontal screen position
55+
wire [15:0] sy; // vertical screen position
5656
wire h_sync; // horizontal sync
5757
wire v_sync; // vertical sync
5858
wire de; // display enable
@@ -71,16 +71,14 @@ module display_demo_dvi(
7171
.V_POL(1) // 0 1 1 1
7272
)
7373
display_timings_inst (
74-
.i_pixclk(pix_clk),
74+
.i_pix_clk(pix_clk),
7575
.i_rst(rst),
7676
.o_hs(h_sync),
7777
.o_vs(v_sync),
7878
.o_de(de),
7979
.o_frame(frame),
80-
.o_h(),
81-
.o_v(),
82-
.o_x(x),
83-
.o_y(y)
80+
.o_sx(sx),
81+
.o_sy(sy)
8482
);
8583

8684
// test card colour output
@@ -92,7 +90,7 @@ module display_demo_dvi(
9290
test_card_simple #(
9391
.H_RES(1280) // horizontal resolution
9492
) test_card_inst (
95-
.i_x(x),
93+
.i_x(sx),
9694
.o_red(red),
9795
.o_green(green),
9896
.o_blue(blue)
@@ -104,8 +102,8 @@ module display_demo_dvi(
104102
// .V_RES(720) // vertical resolution
105103
// )
106104
// test_card_inst (
107-
// .i_x(x),
108-
// .i_y(y),
105+
// .i_x(sx),
106+
// .i_y(sy),
109107
// .o_red(red),
110108
// .o_green(green),
111109
// .o_blue(blue)
@@ -114,8 +112,8 @@ module display_demo_dvi(
114112
// // Test Card: Gradient - ENABLE ONE TEST CARD INSTANCE ONLY
115113
// localparam GRAD_STEP = 2; // step right shift: 480=2, 720=2, 1080=3
116114
// test_card_gradient test_card_inst (
117-
// .i_y(y[GRAD_STEP+7:GRAD_STEP]),
118-
// .i_x(x[5:0]),
115+
// .i_y(sy[GRAD_STEP+7:GRAD_STEP]),
116+
// .i_x(sx[5:0]),
119117
// .o_red(red),
120118
// .o_green(green),
121119
// .o_blue(blue)

hdl/demo/display_demo_dvi_pmod3.v

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ module display_demo_dvi_pmod3(
4646
);
4747

4848
// Display Timings
49-
wire [15:0] x; // horizontal pixel position
50-
wire [15:0] y; // vertical pixel position
49+
wire [15:0] sx; // horizontal pixel position
50+
wire [15:0] sy; // vertical pixel position
5151
wire h_sync; // horizontal sync
5252
wire v_sync; // vertical sync
5353
wire de; // display enable
@@ -66,16 +66,14 @@ module display_demo_dvi_pmod3(
6666
.V_POL(0) // 0 1 1 1
6767
)
6868
display_timings_inst (
69-
.i_pixclk(pix_clk),
69+
.i_pix_clk(pix_clk),
7070
.i_rst(rst),
7171
.o_hs(h_sync),
7272
.o_vs(v_sync),
7373
.o_de(de),
7474
.o_frame(frame),
75-
.o_h(),
76-
.o_v(),
77-
.o_x(x),
78-
.o_y(y)
75+
.o_sx(sx),
76+
.o_sy(sy)
7977
);
8078

8179
// test card colour output
@@ -87,7 +85,7 @@ module display_demo_dvi_pmod3(
8785
test_card_simple #(
8886
.H_RES(640) // horizontal resolution
8987
) test_card_inst (
90-
.i_x(x),
88+
.i_x(sx),
9189
.o_red(red),
9290
.o_green(green),
9391
.o_blue(blue)
@@ -99,8 +97,8 @@ module display_demo_dvi_pmod3(
9997
// .V_RES(480) // vertical resolution
10098
// )
10199
// test_card_inst (
102-
// .i_x(x),
103-
// .i_y(y),
100+
// .i_x(sx),
101+
// .i_y(sy),
104102
// .o_red(red),
105103
// .o_green(green),
106104
// .o_blue(blue)
@@ -109,8 +107,8 @@ module display_demo_dvi_pmod3(
109107
// // Test Card: Gradient - ENABLE ONE TEST CARD INSTANCE ONLY
110108
// localparam GRAD_STEP = 2; // step right shift: 480=2, 720=2, 1080=3
111109
// test_card_gradient test_card_inst (
112-
// .i_x(x[5:0]),
113-
// .i_y(y[GRAD_STEP+7:GRAD_STEP]),
110+
// .i_x(sx[5:0]),
111+
// .i_y(sy[GRAD_STEP+7:GRAD_STEP]),
114112
// .o_red(red),
115113
// .o_green(green),
116114
// .o_blue(blue)

hdl/demo/display_demo_vga.v

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ module display_demo_vga(
4444
);
4545

4646
// Display Timings
47-
wire [15:0] x; // horizontal pixel position
48-
wire [15:0] y; // vertical pixel position
47+
wire [15:0] sx; // horizontal pixel position
48+
wire [15:0] sy; // vertical pixel position
4949
wire h_sync; // horizontal sync
5050
wire v_sync; // vertical sync
5151
wire de; // display enable
@@ -64,16 +64,14 @@ module display_demo_vga(
6464
.V_POL(0) // 0 1 1 1
6565
)
6666
display_timings_inst (
67-
.i_pixclk(pix_clk),
67+
.i_pix_clk(pix_clk),
6868
.i_rst(rst),
6969
.o_hs(h_sync),
7070
.o_vs(v_sync),
7171
.o_de(de),
7272
.o_frame(frame),
73-
.o_h(),
74-
.o_v(),
75-
.o_x(x),
76-
.o_y(y)
73+
.o_sx(sx),
74+
.o_sy(sy)
7775
);
7876

7977
// test card colour output
@@ -85,7 +83,7 @@ module display_demo_vga(
8583
test_card_simple #(
8684
.H_RES(640) // horizontal resolution
8785
) test_card_inst (
88-
.i_x(x),
86+
.i_x(sx),
8987
.o_red(red),
9088
.o_green(green),
9189
.o_blue(blue)
@@ -97,8 +95,8 @@ module display_demo_vga(
9795
// .V_RES(480) // vertical resolution
9896
// )
9997
// test_card_inst (
100-
// .i_x(x),
101-
// .i_y(y),
98+
// .i_x(sx),
99+
// .i_y(sy),
102100
// .o_red(red),
103101
// .o_green(green),
104102
// .o_blue(blue)
@@ -107,8 +105,8 @@ module display_demo_vga(
107105
// // Test Card: Gradient - ENABLE ONE TEST CARD INSTANCE ONLY
108106
// localparam GRAD_STEP = 2; // step right shift: 480=2, 720=2, 1080=3
109107
// test_card_gradient test_card_inst (
110-
// .i_x(x[5:0]),
111-
// .i_y(y[GRAD_STEP+7:GRAD_STEP]),
108+
// .i_x(sx[5:0]),
109+
// .i_y(sy[GRAD_STEP+7:GRAD_STEP]),
112110
// .o_red(red),
113111
// .o_green(green),
114112
// .o_blue(blue)

hdl/display_timings.v

Lines changed: 33 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -20,70 +20,61 @@ module display_timings #(
2020
V_POL=0 // vertical sync polarity (0:neg, 1:pos)
2121
)
2222
(
23-
input wire i_pixclk, // pixel clock
24-
input wire i_rst, // reset: restarts frame (active high)
25-
output wire o_hs, // horizontal sync
26-
output wire o_vs, // vertical sync
27-
output wire o_de, // display enable: high during active video
28-
output wire o_frame, // high for one tick at the start of each frame
29-
output reg [15:0] o_h, // horizontal beam position (including blanking)
30-
output reg [15:0] o_v, // vertical beam position (including blanking)
31-
output wire [15:0] o_x, // horizontal screen position (active pixels)
32-
output wire [15:0] o_y // vertical screen position (active pixels)
23+
input wire i_pix_clk, // pixel clock
24+
input wire i_rst, // reset: restarts frame (active high)
25+
output wire o_hs, // horizontal sync
26+
output wire o_vs, // vertical sync
27+
output wire o_de, // display enable: high during active video
28+
output wire o_frame, // high for one tick at the start of each frame
29+
output reg signed [15:0] o_sx, // horizontal beam position (including blanking)
30+
output reg signed [15:0] o_sy // vertical beam position (including blanking)
3331
);
3432

3533
// Horizontal: sync, active, and pixels
36-
localparam HS_STA = H_FP - 1; // sync start (first pixel is 0)
37-
localparam HS_END = HS_STA + H_SYNC; // sync end
38-
localparam HA_STA = HS_END + H_BP; // active start
39-
localparam HA_END = HA_STA + H_RES; // active end
40-
localparam LINE = HA_END; // line pixels
34+
localparam signed H_STA = 0 - H_FP - H_SYNC - H_BP; // horizontal start
35+
localparam signed HS_STA = H_STA + H_FP; // sync start
36+
localparam signed HS_END = HS_STA + H_SYNC; // sync end
37+
localparam signed HA_STA = 0; // active start = 0
38+
localparam signed HA_END = H_RES - 1; // active end
4139

4240
// Vertical: sync, active, and pixels
43-
localparam VS_STA = V_FP - 1; // sync start (first line is 0)
44-
localparam VS_END = VS_STA + V_SYNC; // sync end
45-
localparam VA_STA = VS_END + V_BP; // active start
46-
localparam VA_END = VA_STA + V_RES; // active end
47-
localparam FRAME = VA_END; // frame lines
41+
localparam signed V_STA = 0 - V_FP - V_SYNC - V_BP; // vertical start
42+
localparam signed VS_STA = V_STA + V_FP; // sync start
43+
localparam signed VS_END = VS_STA + V_SYNC; // sync end
44+
localparam signed VA_STA = 0; // active start
45+
localparam signed VA_END = V_RES - 1; // active end
4846

4947
// generate sync signals with correct polarity
50-
assign o_hs = H_POL ? (o_h > HS_STA && o_h <= HS_END)
51-
: ~(o_h > HS_STA && o_h <= HS_END);
52-
assign o_vs = V_POL ? (o_v > VS_STA && o_v <= VS_END)
53-
: ~(o_v > VS_STA && o_v <= VS_END);
48+
assign o_hs = H_POL ? (o_sx > HS_STA && o_sx <= HS_END)
49+
: ~(o_sx > HS_STA && o_sx <= HS_END);
50+
assign o_vs = V_POL ? (o_sy > VS_STA && o_sy <= VS_END)
51+
: ~(o_sy > VS_STA && o_sy <= VS_END);
5452

5553
// display enable: high during active period
56-
assign o_de = o_h > HA_STA && o_h <= HA_END
57-
&& o_v > VA_STA && o_v <= VA_END;
58-
59-
// keep o_x and o_y bound within active pixels
60-
assign o_x = (o_de && o_h > HA_STA && o_h <= HA_END) ?
61-
o_h - (HA_STA + 1): 0;
62-
assign o_y = (o_de && o_v > VA_STA && o_v <= VA_END) ?
63-
o_v - (VA_STA + 1): 0;
54+
assign o_de = o_sx >= 0 && o_sy >= 0;
6455

6556
// o_frame: high for one tick at the start of each frame
66-
assign o_frame = (o_v == 0 && o_h == 0);
57+
assign o_frame = (o_sy == V_STA && o_sx == H_STA);
6758

68-
always @ (posedge i_pixclk)
59+
always @ (posedge i_pix_clk)
6960
begin
7061
if (i_rst) // reset to start of frame
7162
begin
72-
o_h <= 0;
73-
o_v <= 0;
63+
o_sx <= H_STA;
64+
o_sy <= V_STA;
7465
end
7566
else
7667
begin
77-
if (o_h == LINE) // end of line
68+
if (o_sx == HA_END) // end of line
7869
begin
79-
o_h <= 0;
80-
if (o_v == FRAME) // end of frame
81-
o_v <= 0;
70+
o_sx <= H_STA;
71+
if (o_sy == VA_END) // end of frame
72+
o_sy <= V_STA;
8273
else
83-
o_v <= o_v + 1;
74+
o_sy <= o_sy + 16'sh1;
8475
end
8576
else
86-
o_h <= o_h + 1;
77+
o_sx <= o_sx + 16'sh1;
8778
end
8879
end
8980
endmodule

0 commit comments

Comments
 (0)