/
vga_refresh.v
208 lines (181 loc) · 4.97 KB
/
vga_refresh.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
// ====================================================================
// VECTOR-06C FPGA REPLICA
//
// Copyright (C) 2007,2008 Viacheslav Slavinsky
//
// This core is distributed under modified BSD license.
// For complete licensing information see LICENSE.TXT.
// --------------------------------------------------------------------
//
// An open implementation of Vector-06C home computer
//
// Author: Viacheslav Slavinsky, http://sensi.org/~svo
//
// Modified by Ivan Gorodetsky
//
// Design File: vga_refresh.v
//
// VGA refresh signals generator. Also takes care of retrace, bordery,
// videoActive signals and row counter for framebuffer/scan doubler.
//
// This version simulates a rather strange PAL mode with only 624
// lines. The original computer sacrificed standard compliance to allow
// some simplification and had 2x312 line scan instead of 312/313
// alternation.
//
// --------------------------------------------------------------------
`default_nettype none
module vga_refresh(clk24, hsync, vsync, YPbPrvsync, videoActive, bordery, retrace, video_scroll_reg, fb_row, fb_row_count, tvhs, tvvs, tvx, tvy);
input clk24;
output hsync;
output vsync;
output YPbPrvsync;
output videoActive;
output reg bordery;
output retrace;
input [7:0] video_scroll_reg;
output [8:0] fb_row;
output [8:0] fb_row_count;
output tvhs, tvvs;
output [9:0] tvx,tvy;
// total = 624
// visible = (16 + 256 + 16)*2 = 288*2 = 576
// rest = 624-576 = 48
parameter SCREENWIDTH = 10'd640;
parameter SCREENHEIGHT = 10'd576;
parameter VISIBLEHEIGHT = SCREENHEIGHT - 2*2*16;
parameter SCROLLLOAD_X = 112; // when on line 0 scroll register is copied into the line counter
reg videoActiveX; // 1 == X is within visible area
reg videoActiveY; // 1 == Y is within visible area
wire videoActive = videoActiveX & videoActiveY;
assign retrace = !videoActiveY;
assign hsync = !(scanxx_state == state2);
assign vsync = !(scanyy_state == state2);
assign YPbPrvsync = !((scanyy_state == state1)&&(scanyy>10'd10));
//assign tvhs = !((tvx > (0)) && (tvx < (96)));
assign tvhs = !(tvx > 800-96);
//assign tvvs = !(tvy < 6);
assign tvvs = !(tvy == 623 && tvx == 800-96);
reg[9:0] tvx;
reg[9:0] tvy;
reg[9:0] realx;
reg[9:0] realy;
reg[2:0] scanxx_state; // x-machine state
reg[2:0] scanyy_state; // y-machine state
reg[9:0] scanxx; // x-state timer/counter
reg[9:0] scanyy; // y-state timer/counter
//
// framebuffer variables
//
reg [8:0] fb_row; // fb row
reg [8:0] fb_row_count;
parameter state0 = 3'b000, state1 = 3'b001, state2 = 3'b010, state3 = 3'b011, state4 = 3'b100, state5 = 3'b101, state6 = 3'b110, state7 = 3'b111;
always @(posedge clk24) begin
if (scanyy == 0) begin
case (scanyy_state)
state0:
begin
scanyy <= 10'd21;
scanyy_state <= state1;
bordery <= 0;
tvy <= 0;
videoActiveY <= 0;
end
state1: // VSYNC
begin
scanyy <= 10'd5;
scanyy_state <= state2;
end
state2: // BACK PORCH + TOP BORDER
begin
scanyy <= 10'd22;
scanyy_state <= state3;
end
state3:
begin
scanyy <= 10'd32; // 16 * 2: top and bottom borders
videoActiveY <= 1;
realy <= 0;
bordery <= 1;
scanyy_state <= state4;
end
state4:
begin
scanyy <= VISIBLEHEIGHT;
bordery <= 0;
scanyy_state <= state5;
end
state5:
begin
//fb_row <= 1;
scanyy <= 2 * (8'd16);
bordery <= 1;
scanyy_state <= state0;
end
default:
begin
scanyy_state <= state0;
end
endcase
end
if (scanxx == 0) begin
case (scanxx_state)
state0: // enter FRONT PORCH + LEFT BORDER
begin
scanxx <= 10'd11 - 1'b1;
scanyy <= scanyy - 1'b1;
scanxx_state <= state1;
videoActiveX <= 1'b0;
realy <= realy + 1'b1;
fb_row <= fb_row - 1'b1;
if (fb_row_count != 0) begin
fb_row_count <= fb_row_count - 1'b1;
end
tvx <= 0;
end
state1: // enter HSYNC PULSE
begin
scanxx <= 10'd56 - 1'b1;
scanxx_state <= state2;
end
state2: // enter BACK PORCH + RIGHT BORDER
begin
scanxx <= 10'd60;
scanxx_state <= state3;
end
state3: // enter VISIBLE AREA
begin
videoActiveX <= 1'b1;
realx <= 9'b0;
scanxx <= SCREENWIDTH - 1'b1 - 1'b1; // borrow one from state4
scanxx_state <= state4;
end
state4:
begin
scanxx_state <= state0;
end
default:
begin
scanxx_state <= state0;
end
endcase
end
else scanxx <= scanxx - 1'b1;
// load scroll register at this precise moment
if (scanyy_state == state5 && realx == SCROLLLOAD_X && scanyy == VISIBLEHEIGHT) begin
fb_row <= {video_scroll_reg, 1'b1};
fb_row_count <= 511;
end
if (videoActiveX) begin
realx <= realx + 1'b1;
end
if (scanxx_state == state0)
tvx <= 0;
else
tvx <= tvx + 1;
if (scanxx_state == state0) begin
tvy <= tvy + 1;
end
end
endmodule
// $Id$