]>
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 | 38 | output reg [1:0] blue, |
01e9841e JW |
39 | input serrx, |
40 | output sertx, | |
41 | input ps2c, ps2d); | |
a55fc9f4 JW |
42 | |
43 | wire clk25; | |
44 | ||
45 | wire [11:0] x, y; | |
46 | wire border; | |
47 | ||
48 | MulDivDCM dcm25(xtal, clk25); | |
49 | defparam dcm25.div = 4; | |
50 | defparam dcm25.mul = 2; | |
51 | ||
52 | SyncGen sync(clk25, vs, hs, x, y, border); | |
53 | ||
d3ae999b JW |
54 | wire [7:0] cschar; |
55 | wire [2:0] csrow; | |
56 | wire [7:0] csdata; | |
57 | ||
7b96452d | 58 | wire [10:0] vraddr; |
d3ae999b JW |
59 | wire [7:0] vrdata; |
60 | ||
7b96452d | 61 | wire [10:0] vwaddr; |
0491ebad | 62 | wire [7:0] vwdata; |
7b96452d JW |
63 | wire [7:0] serdata; |
64 | wire vwr, serwr; | |
65 | wire [10:0] vscroll; | |
d3ae999b JW |
66 | |
67 | wire odata; | |
68 | ||
69 | CharSet cs(cschar, csrow, csdata); | |
7b96452d | 70 | VideoRAM vram(clk25, vraddr + vscroll, vrdata, vwaddr, vwdata, vwr); |
d3ae999b | 71 | VDisplay dpy(clk25, x, y, vraddr, vrdata, cschar, csrow, csdata, odata); |
7b96452d | 72 | SerRX rx(clk25, serwr, serdata, serrx); |
01e9841e | 73 | SerTX tx(clk25, 0, 0, sertx); |
7b96452d | 74 | RXState rxsm(clk25, vwr, vwaddr, vwdata, vscroll, serwr, serdata); |
d3ae999b | 75 | |
a55fc9f4 | 76 | always @(posedge clk25) begin |
d3ae999b JW |
77 | red <= border ? 0 : {3{odata}}; |
78 | green <= border ? 0 : {3{odata}}; | |
79 | blue <= border ? 0 : {2{odata}}; | |
a55fc9f4 JW |
80 | end |
81 | endmodule | |
82 | ||
83 | module SyncGen( | |
84 | input pixclk, | |
85 | output reg vs, hs, | |
86 | output reg [11:0] x, y, | |
87 | output reg border); | |
88 | ||
89 | parameter XRES = 640; | |
90 | parameter XFPORCH = 16; | |
91 | parameter XSYNC = 96; | |
92 | parameter XBPORCH = 48; | |
93 | ||
94 | parameter YRES = 480; | |
95 | parameter YFPORCH = 10; | |
96 | parameter YSYNC = 2; | |
97 | parameter YBPORCH = 29; | |
98 | ||
99 | always @(posedge pixclk) | |
100 | begin | |
101 | if (x >= (XRES + XFPORCH + XSYNC + XBPORCH)) | |
102 | begin | |
103 | if (y >= (YRES + YFPORCH + YSYNC + YBPORCH)) | |
104 | y = 0; | |
105 | else | |
106 | y = y + 1; | |
107 | x = 0; | |
108 | end else | |
109 | x = x + 1; | |
110 | hs <= (x >= (XRES + XFPORCH)) && (x < (XRES + XFPORCH + XSYNC)); | |
111 | vs <= (y >= (YRES + YFPORCH)) && (y < (YRES + YFPORCH + YSYNC)); | |
112 | border <= (x > XRES) || (y > YRES); | |
113 | end | |
114 | endmodule | |
d3ae999b JW |
115 | |
116 | module CharSet( | |
117 | input [7:0] char, | |
118 | input [2:0] row, | |
119 | output wire [7:0] data); | |
120 | ||
121 | reg [7:0] rom [(256 * 8 - 1):0]; | |
122 | ||
123 | initial | |
124 | $readmemb("ibmpc1.mem", rom); | |
125 | ||
126 | assign data = rom[{char, row}]; | |
127 | endmodule | |
128 | ||
129 | module VideoRAM( | |
130 | input pixclk, | |
7b96452d | 131 | input [10:0] raddr, |
d3ae999b | 132 | output reg [7:0] rdata, |
7b96452d | 133 | input [10:0] waddr, |
d3ae999b JW |
134 | input [7:0] wdata, |
135 | input wr); | |
136 | ||
7b96452d | 137 | reg [7:0] ram [2047 : 0]; |
d3ae999b JW |
138 | |
139 | always @(posedge pixclk) | |
140 | rdata <= ram[raddr]; | |
141 | ||
142 | always @(posedge pixclk) | |
143 | if (wr) | |
144 | ram[waddr] <= wdata; | |
145 | endmodule | |
146 | ||
147 | module VDisplay( | |
148 | input pixclk, | |
149 | input [11:0] x, | |
150 | input [11:0] y, | |
7b96452d | 151 | output wire [10:0] raddr, |
d3ae999b JW |
152 | input [7:0] rchar, |
153 | output wire [7:0] cschar, | |
154 | output wire [2:0] csrow, | |
155 | input [7:0] csdata, | |
01e9841e | 156 | output reg data); |
d3ae999b JW |
157 | |
158 | wire [7:0] col = x[11:3]; | |
159 | wire [5:0] row = y[9:3]; | |
160 | reg [7:0] ch; | |
161 | reg [11:0] xdly; | |
162 | ||
163 | assign raddr = ({row,4'b0} + {row,6'b0} + {4'h0,col}); | |
164 | assign cschar = rchar; | |
165 | assign csrow = y[2:0]; | |
166 | ||
167 | always @(posedge pixclk) | |
168 | xdly <= x; | |
169 | ||
170 | always @(posedge pixclk) | |
171 | data = ((xdly < 80 * 8) && (y < 25 * 8)) ? csdata[7 - xdly[2:0]] : 0; | |
172 | endmodule | |
0491ebad JW |
173 | |
174 | `define IN_CLK 25000000 | |
175 | `define OUT_CLK 57600 | |
176 | `define CLK_DIV (`IN_CLK / `OUT_CLK) | |
177 | ||
178 | module SerRX( | |
179 | input pixclk, | |
180 | output reg wr = 0, | |
0491ebad | 181 | output reg [7:0] wchar = 0, |
01e9841e | 182 | input serialrx); |
0491ebad JW |
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 | |
01e9841e JW |
225 | endmodule |
226 | ||
227 | module SerTX( | |
228 | input pixclk, | |
229 | input wr, | |
230 | input [7:0] char, | |
231 | output reg serial = 1); | |
232 | ||
233 | reg [7:0] tx_data = 0; | |
234 | reg [15:0] tx_clkdiv = 0; | |
235 | reg [3:0] tx_state = 4'b0000; | |
236 | reg tx_busy = 0; | |
237 | wire tx_newdata = wr && !tx_busy; | |
0491ebad | 238 | |
01e9841e JW |
239 | always @(posedge pixclk) |
240 | begin | |
241 | if(tx_newdata) begin | |
242 | tx_data <= char; | |
243 | tx_state <= 4'b0000; | |
244 | tx_busy <= 1; | |
245 | end else if (tx_clkdiv == 0) begin | |
246 | tx_state <= tx_state + 1; | |
247 | if (tx_busy) | |
248 | case (tx_state) | |
249 | 4'b0000: serial <= 0; | |
250 | 4'b0001: serial <= tx_data[0]; | |
251 | 4'b0010: serial <= tx_data[1]; | |
252 | 4'b0011: serial <= tx_data[2]; | |
253 | 4'b0100: serial <= tx_data[3]; | |
254 | 4'b0101: serial <= tx_data[4]; | |
255 | 4'b0110: serial <= tx_data[5]; | |
256 | 4'b0111: serial <= tx_data[6]; | |
257 | 4'b1000: serial <= tx_data[7]; | |
258 | 4'b1001: serial <= 1; | |
259 | 4'b1010: tx_busy <= 0; | |
260 | default: $stop; | |
261 | endcase | |
262 | end | |
263 | ||
264 | if(tx_newdata || (tx_clkdiv == `CLK_DIV)) | |
265 | tx_clkdiv <= 0; | |
266 | else | |
267 | tx_clkdiv <= tx_clkdiv + 1; | |
268 | end | |
0491ebad | 269 | endmodule |
7b96452d JW |
270 | |
271 | module RXState( | |
272 | input clk25, | |
273 | output reg vwr = 0, | |
274 | output reg [10:0] vwaddr = 0, | |
275 | output reg [7:0] vwdata = 0, | |
276 | output reg [10:0] vscroll = 0, | |
277 | input serwr, | |
278 | input [7:0] serdata); | |
279 | ||
280 | parameter STATE_IDLE = 4'b0000; | |
281 | parameter STATE_NEWLINE = 4'b0001; | |
282 | parameter STATE_CLEAR = 4'b0010; | |
283 | ||
284 | reg [3:0] state = STATE_CLEAR; | |
285 | ||
286 | reg [6:0] x = 0; | |
287 | reg [4:0] y = 0; | |
288 | ||
289 | reg [10:0] clearstart = 0; | |
290 | reg [10:0] clearend = 11'b11111111111; | |
291 | ||
292 | always @(posedge clk25) | |
293 | case (state) | |
294 | STATE_IDLE: if (serwr) begin | |
295 | if (serdata == 8'h0A) begin | |
296 | state <= STATE_NEWLINE; | |
297 | vwr <= 0; | |
298 | end else if (serdata == 8'h0D) begin | |
299 | x <= 0; | |
300 | vwr <= 0; | |
301 | end else if (serdata == 8'h0C) begin | |
302 | clearstart <= 0; | |
303 | clearend <= 11'b11111111111; | |
304 | x <= 0; | |
305 | y <= 0; | |
306 | vscroll <= 0; | |
307 | state <= STATE_CLEAR; | |
308 | end else begin | |
309 | vwr <= 1; | |
310 | vwaddr <= ({y,4'b0} + {y,6'b0} + {4'h0,x}) + vscroll; | |
311 | vwdata <= serdata; | |
312 | if (x == 79) begin | |
313 | x <= 0; | |
314 | state <= STATE_NEWLINE; | |
315 | end else | |
316 | x <= x + 1; | |
317 | end | |
318 | end | |
319 | STATE_NEWLINE: | |
320 | begin | |
321 | vwr <= 0; | |
322 | if (y == 24) begin | |
323 | vscroll <= vscroll + 80; | |
324 | clearstart <= (25 * 80) + vscroll; | |
325 | clearend <= (26*80) + vscroll; | |
326 | state <= STATE_CLEAR; | |
327 | end else begin | |
328 | y <= y + 1; | |
329 | state <= STATE_IDLE; | |
330 | end | |
331 | end | |
332 | STATE_CLEAR: | |
333 | begin | |
334 | vwr <= 1; | |
335 | vwaddr <= clearstart; | |
336 | vwdata <= 8'h20; | |
337 | clearstart <= clearstart + 1; | |
338 | if (clearstart == clearend) | |
339 | state <= STATE_IDLE; | |
340 | end | |
341 | endcase | |
342 | endmodule |