]>
Commit | Line | Data |
---|---|---|
a55fc9f4 JW |
1 | module MulDivDCM(input xtal, output clk); |
2 | parameter div = 5; | |
3 | parameter mul = 2; | |
4 | ||
5 | wire CLKFX_BUF; | |
6 | wire GND_BIT = 0; | |
7 | BUFG CLKFX_BUFG_INST (.I(CLKFX_BUF), | |
8 | .O(clk)); | |
9 | DCM_SP DCM_SP_INST (.CLKFB(GND_BIT), | |
10 | .CLKIN(xtal), | |
11 | .DSSEN(GND_BIT), | |
12 | .PSCLK(GND_BIT), | |
13 | .PSEN(GND_BIT), | |
14 | .PSINCDEC(GND_BIT), | |
15 | .RST(GND_BIT), | |
16 | .CLKFX(CLKFX_BUF)); | |
17 | defparam DCM_SP_INST.CLK_FEEDBACK = "NONE"; | |
18 | defparam DCM_SP_INST.CLKDV_DIVIDE = 2.0; | |
19 | defparam DCM_SP_INST.CLKFX_DIVIDE = div; | |
20 | defparam DCM_SP_INST.CLKFX_MULTIPLY = mul; | |
21 | defparam DCM_SP_INST.CLKIN_DIVIDE_BY_2 = "FALSE"; | |
22 | defparam DCM_SP_INST.CLKIN_PERIOD = 20.000; | |
23 | defparam DCM_SP_INST.CLKOUT_PHASE_SHIFT = "NONE"; | |
24 | defparam DCM_SP_INST.DESKEW_ADJUST = "SYSTEM_SYNCHRONOUS"; | |
25 | defparam DCM_SP_INST.DFS_FREQUENCY_MODE = "LOW"; | |
26 | defparam DCM_SP_INST.DLL_FREQUENCY_MODE = "LOW"; | |
27 | defparam DCM_SP_INST.DUTY_CYCLE_CORRECTION = "TRUE"; | |
28 | defparam DCM_SP_INST.FACTORY_JF = 16'hC080; | |
29 | defparam DCM_SP_INST.PHASE_SHIFT = 0; | |
30 | defparam DCM_SP_INST.STARTUP_WAIT = "TRUE"; | |
31 | endmodule | |
32 | ||
33 | module VTerm( | |
34 | input xtal, | |
35 | output wire vs, hs, | |
36 | output reg [2:0] red, | |
37 | output reg [2:0] green, | |
0491ebad JW |
38 | output reg [1:0] blue, |
39 | input serrx | |
a55fc9f4 JW |
40 | ); |
41 | ||
42 | wire clk25; | |
43 | ||
44 | wire [11:0] x, y; | |
45 | wire border; | |
46 | ||
47 | MulDivDCM dcm25(xtal, clk25); | |
48 | defparam dcm25.div = 4; | |
49 | defparam dcm25.mul = 2; | |
50 | ||
51 | SyncGen sync(clk25, vs, hs, x, y, border); | |
52 | ||
d3ae999b JW |
53 | wire [7:0] cschar; |
54 | wire [2:0] csrow; | |
55 | wire [7:0] csdata; | |
56 | ||
7b96452d | 57 | wire [10:0] vraddr; |
d3ae999b JW |
58 | wire [7:0] vrdata; |
59 | ||
7b96452d | 60 | wire [10:0] vwaddr; |
0491ebad | 61 | wire [7:0] vwdata; |
7b96452d JW |
62 | wire [7:0] serdata; |
63 | wire vwr, serwr; | |
64 | wire [10:0] vscroll; | |
d3ae999b JW |
65 | |
66 | wire odata; | |
67 | ||
68 | CharSet cs(cschar, csrow, csdata); | |
7b96452d | 69 | VideoRAM vram(clk25, vraddr + vscroll, vrdata, vwaddr, vwdata, vwr); |
d3ae999b | 70 | VDisplay dpy(clk25, x, y, vraddr, vrdata, cschar, csrow, csdata, odata); |
7b96452d JW |
71 | SerRX rx(clk25, serwr, serdata, serrx); |
72 | RXState rxsm(clk25, vwr, vwaddr, vwdata, vscroll, serwr, serdata); | |
d3ae999b | 73 | |
a55fc9f4 | 74 | always @(posedge clk25) begin |
d3ae999b JW |
75 | red <= border ? 0 : {3{odata}}; |
76 | green <= border ? 0 : {3{odata}}; | |
77 | blue <= border ? 0 : {2{odata}}; | |
a55fc9f4 JW |
78 | end |
79 | endmodule | |
80 | ||
81 | module SyncGen( | |
82 | input pixclk, | |
83 | output reg vs, hs, | |
84 | output reg [11:0] x, y, | |
85 | output reg border); | |
86 | ||
87 | parameter XRES = 640; | |
88 | parameter XFPORCH = 16; | |
89 | parameter XSYNC = 96; | |
90 | parameter XBPORCH = 48; | |
91 | ||
92 | parameter YRES = 480; | |
93 | parameter YFPORCH = 10; | |
94 | parameter YSYNC = 2; | |
95 | parameter YBPORCH = 29; | |
96 | ||
97 | always @(posedge pixclk) | |
98 | begin | |
99 | if (x >= (XRES + XFPORCH + XSYNC + XBPORCH)) | |
100 | begin | |
101 | if (y >= (YRES + YFPORCH + YSYNC + YBPORCH)) | |
102 | y = 0; | |
103 | else | |
104 | y = y + 1; | |
105 | x = 0; | |
106 | end else | |
107 | x = x + 1; | |
108 | hs <= (x >= (XRES + XFPORCH)) && (x < (XRES + XFPORCH + XSYNC)); | |
109 | vs <= (y >= (YRES + YFPORCH)) && (y < (YRES + YFPORCH + YSYNC)); | |
110 | border <= (x > XRES) || (y > YRES); | |
111 | end | |
112 | endmodule | |
d3ae999b JW |
113 | |
114 | module CharSet( | |
115 | input [7:0] char, | |
116 | input [2:0] row, | |
117 | output wire [7:0] data); | |
118 | ||
119 | reg [7:0] rom [(256 * 8 - 1):0]; | |
120 | ||
121 | initial | |
122 | $readmemb("ibmpc1.mem", rom); | |
123 | ||
124 | assign data = rom[{char, row}]; | |
125 | endmodule | |
126 | ||
127 | module VideoRAM( | |
128 | input pixclk, | |
7b96452d | 129 | input [10:0] raddr, |
d3ae999b | 130 | output reg [7:0] rdata, |
7b96452d | 131 | input [10:0] waddr, |
d3ae999b JW |
132 | input [7:0] wdata, |
133 | input wr); | |
134 | ||
7b96452d | 135 | reg [7:0] ram [2047 : 0]; |
d3ae999b JW |
136 | |
137 | always @(posedge pixclk) | |
138 | rdata <= ram[raddr]; | |
139 | ||
140 | always @(posedge pixclk) | |
141 | if (wr) | |
142 | ram[waddr] <= wdata; | |
143 | endmodule | |
144 | ||
145 | module VDisplay( | |
146 | input pixclk, | |
147 | input [11:0] x, | |
148 | input [11:0] y, | |
7b96452d | 149 | output wire [10:0] raddr, |
d3ae999b JW |
150 | input [7:0] rchar, |
151 | output wire [7:0] cschar, | |
152 | output wire [2:0] csrow, | |
153 | input [7:0] csdata, | |
154 | output reg data | |
155 | ); | |
156 | ||
157 | wire [7:0] col = x[11:3]; | |
158 | wire [5:0] row = y[9:3]; | |
159 | reg [7:0] ch; | |
160 | reg [11:0] xdly; | |
161 | ||
162 | assign raddr = ({row,4'b0} + {row,6'b0} + {4'h0,col}); | |
163 | assign cschar = rchar; | |
164 | assign csrow = y[2:0]; | |
165 | ||
166 | always @(posedge pixclk) | |
167 | xdly <= x; | |
168 | ||
169 | always @(posedge pixclk) | |
170 | data = ((xdly < 80 * 8) && (y < 25 * 8)) ? csdata[7 - xdly[2:0]] : 0; | |
171 | endmodule | |
0491ebad JW |
172 | |
173 | `define IN_CLK 25000000 | |
174 | `define OUT_CLK 57600 | |
175 | `define CLK_DIV (`IN_CLK / `OUT_CLK) | |
176 | ||
177 | module SerRX( | |
178 | input pixclk, | |
179 | output reg wr = 0, | |
0491ebad JW |
180 | output reg [7:0] wchar = 0, |
181 | input serialrx | |
182 | ); | |
183 | ||
184 | reg [15:0] rx_clkdiv = 0; | |
185 | reg [3:0] rx_state = 4'b0000; | |
186 | reg [7:0] rx_data_tmp; | |
187 | ||
188 | ||
189 | always @(posedge pixclk) | |
190 | begin | |
191 | if ((rx_state == 0) && (serialrx == 0) /*&& (rx_hasdata == 0)*/) /* Kick off. */ | |
192 | rx_state <= 4'b0001; | |
193 | else if ((rx_state != 4'b0000) && (rx_clkdiv == 0)) begin | |
194 | if (rx_state != 4'b1010) | |
195 | rx_state <= rx_state + 1; | |
196 | else | |
197 | rx_state <= 0; | |
198 | case (rx_state) | |
199 | 4'b0001: begin end /* Twiddle thumbs -- this is the end of the half bit. */ | |
200 | 4'b0010: rx_data_tmp[0] <= serialrx; | |
201 | 4'b0011: rx_data_tmp[1] <= serialrx; | |
202 | 4'b0100: rx_data_tmp[2] <= serialrx; | |
203 | 4'b0101: rx_data_tmp[3] <= serialrx; | |
204 | 4'b0110: rx_data_tmp[4] <= serialrx; | |
205 | 4'b0111: rx_data_tmp[5] <= serialrx; | |
206 | 4'b1000: rx_data_tmp[6] <= serialrx; | |
207 | 4'b1001: rx_data_tmp[7] <= serialrx; | |
208 | 4'b1010: if (serialrx == 1) begin | |
209 | wr <= 1; | |
210 | wchar <= rx_data_tmp; | |
211 | end | |
212 | endcase | |
213 | end | |
214 | ||
7b96452d | 215 | if (wr) |
0491ebad | 216 | wr <= 0; |
0491ebad JW |
217 | |
218 | if ((rx_state == 0) && (serialrx == 0) /*&& (rx_hasdata == 0)*/) /* Wait half a period before advancing. */ | |
219 | rx_clkdiv <= `CLK_DIV / 2 + `CLK_DIV / 4; | |
220 | else if (rx_clkdiv == `CLK_DIV) | |
221 | rx_clkdiv <= 0; | |
222 | else | |
223 | rx_clkdiv <= rx_clkdiv + 1; | |
224 | end | |
225 | ||
226 | endmodule | |
7b96452d JW |
227 | |
228 | module RXState( | |
229 | input clk25, | |
230 | output reg vwr = 0, | |
231 | output reg [10:0] vwaddr = 0, | |
232 | output reg [7:0] vwdata = 0, | |
233 | output reg [10:0] vscroll = 0, | |
234 | input serwr, | |
235 | input [7:0] serdata); | |
236 | ||
237 | parameter STATE_IDLE = 4'b0000; | |
238 | parameter STATE_NEWLINE = 4'b0001; | |
239 | parameter STATE_CLEAR = 4'b0010; | |
240 | ||
241 | reg [3:0] state = STATE_CLEAR; | |
242 | ||
243 | reg [6:0] x = 0; | |
244 | reg [4:0] y = 0; | |
245 | ||
246 | reg [10:0] clearstart = 0; | |
247 | reg [10:0] clearend = 11'b11111111111; | |
248 | ||
249 | always @(posedge clk25) | |
250 | case (state) | |
251 | STATE_IDLE: if (serwr) begin | |
252 | if (serdata == 8'h0A) begin | |
253 | state <= STATE_NEWLINE; | |
254 | vwr <= 0; | |
255 | end else if (serdata == 8'h0D) begin | |
256 | x <= 0; | |
257 | vwr <= 0; | |
258 | end else if (serdata == 8'h0C) begin | |
259 | clearstart <= 0; | |
260 | clearend <= 11'b11111111111; | |
261 | x <= 0; | |
262 | y <= 0; | |
263 | vscroll <= 0; | |
264 | state <= STATE_CLEAR; | |
265 | end else begin | |
266 | vwr <= 1; | |
267 | vwaddr <= ({y,4'b0} + {y,6'b0} + {4'h0,x}) + vscroll; | |
268 | vwdata <= serdata; | |
269 | if (x == 79) begin | |
270 | x <= 0; | |
271 | state <= STATE_NEWLINE; | |
272 | end else | |
273 | x <= x + 1; | |
274 | end | |
275 | end | |
276 | STATE_NEWLINE: | |
277 | begin | |
278 | vwr <= 0; | |
279 | if (y == 24) begin | |
280 | vscroll <= vscroll + 80; | |
281 | clearstart <= (25 * 80) + vscroll; | |
282 | clearend <= (26*80) + vscroll; | |
283 | state <= STATE_CLEAR; | |
284 | end else begin | |
285 | y <= y + 1; | |
286 | state <= STATE_IDLE; | |
287 | end | |
288 | end | |
289 | STATE_CLEAR: | |
290 | begin | |
291 | vwr <= 1; | |
292 | vwaddr <= clearstart; | |
293 | vwdata <= 8'h20; | |
294 | clearstart <= clearstart + 1; | |
295 | if (clearstart == clearend) | |
296 | state <= STATE_IDLE; | |
297 | end | |
298 | endcase | |
299 | endmodule |