]> Joshua Wise's Git repositories - vterm.git/blame - VTerm.v
Add a cursor. Add backspace.
[vterm.git] / VTerm.v
CommitLineData
a55fc9f4
JW
1module 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";
31endmodule
32
33module 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
cad52b37
JW
69 wire [7:0] sertxdata;
70 wire sertxwr;
71
31cc645e
JW
72 wire [6:0] vcursx;
73 wire [4:0] vcursy;
74
d3ae999b 75 CharSet cs(cschar, csrow, csdata);
7b96452d 76 VideoRAM vram(clk25, vraddr + vscroll, vrdata, vwaddr, vwdata, vwr);
31cc645e 77 VDisplay dpy(clk25, x, y, vraddr, vrdata, cschar, csrow, csdata, vcursx, vcursy, odata);
7b96452d 78 SerRX rx(clk25, serwr, serdata, serrx);
cad52b37 79 SerTX tx(clk25, sertxwr, sertxdata, sertx);
31cc645e 80 RXState rxsm(clk25, vwr, vwaddr, vwdata, vscroll, vcursx, vcursy, serwr, serdata);
cad52b37 81 PS2 ps2(clk25, ps2c, ps2d, sertxwr, sertxdata);
d3ae999b 82
a55fc9f4 83 always @(posedge clk25) begin
d3ae999b
JW
84 red <= border ? 0 : {3{odata}};
85 green <= border ? 0 : {3{odata}};
86 blue <= border ? 0 : {2{odata}};
a55fc9f4
JW
87 end
88endmodule
89
90module SyncGen(
91 input pixclk,
92 output reg vs, hs,
93 output reg [11:0] x, y,
94 output reg border);
95
96 parameter XRES = 640;
97 parameter XFPORCH = 16;
98 parameter XSYNC = 96;
99 parameter XBPORCH = 48;
100
101 parameter YRES = 480;
102 parameter YFPORCH = 10;
103 parameter YSYNC = 2;
104 parameter YBPORCH = 29;
105
106 always @(posedge pixclk)
107 begin
108 if (x >= (XRES + XFPORCH + XSYNC + XBPORCH))
109 begin
110 if (y >= (YRES + YFPORCH + YSYNC + YBPORCH))
111 y = 0;
112 else
113 y = y + 1;
114 x = 0;
115 end else
116 x = x + 1;
117 hs <= (x >= (XRES + XFPORCH)) && (x < (XRES + XFPORCH + XSYNC));
118 vs <= (y >= (YRES + YFPORCH)) && (y < (YRES + YFPORCH + YSYNC));
119 border <= (x > XRES) || (y > YRES);
120 end
121endmodule
d3ae999b
JW
122
123module CharSet(
124 input [7:0] char,
125 input [2:0] row,
126 output wire [7:0] data);
127
128 reg [7:0] rom [(256 * 8 - 1):0];
129
130 initial
131 $readmemb("ibmpc1.mem", rom);
132
133 assign data = rom[{char, row}];
134endmodule
135
136module VideoRAM(
137 input pixclk,
7b96452d 138 input [10:0] raddr,
d3ae999b 139 output reg [7:0] rdata,
7b96452d 140 input [10:0] waddr,
d3ae999b
JW
141 input [7:0] wdata,
142 input wr);
143
7b96452d 144 reg [7:0] ram [2047 : 0];
d3ae999b
JW
145
146 always @(posedge pixclk)
147 rdata <= ram[raddr];
148
149 always @(posedge pixclk)
150 if (wr)
151 ram[waddr] <= wdata;
152endmodule
153
154module VDisplay(
155 input pixclk,
156 input [11:0] x,
157 input [11:0] y,
7b96452d 158 output wire [10:0] raddr,
d3ae999b
JW
159 input [7:0] rchar,
160 output wire [7:0] cschar,
161 output wire [2:0] csrow,
162 input [7:0] csdata,
31cc645e
JW
163 input [6:0] cursx,
164 input [4:0] cursy,
01e9841e 165 output reg data);
d3ae999b
JW
166
167 wire [7:0] col = x[11:3];
168 wire [5:0] row = y[9:3];
169 reg [7:0] ch;
170 reg [11:0] xdly;
171
172 assign raddr = ({row,4'b0} + {row,6'b0} + {4'h0,col});
173 assign cschar = rchar;
174 assign csrow = y[2:0];
175
31cc645e
JW
176 reg [23:0] blinktime = 0;
177
178 always @(posedge pixclk) blinktime <= blinktime + 1;
179
180 wire curssel = (cursx == col) && (cursy == row) && blinktime[23];
181
d3ae999b
JW
182 always @(posedge pixclk)
183 xdly <= x;
184
185 always @(posedge pixclk)
31cc645e 186 data = ((xdly < 80 * 8) && (y < 25 * 8)) ? (csdata[7 - xdly[2:0]] ^ curssel) : 0;
d3ae999b 187endmodule
0491ebad
JW
188
189`define IN_CLK 25000000
190`define OUT_CLK 57600
191`define CLK_DIV (`IN_CLK / `OUT_CLK)
192
193module SerRX(
194 input pixclk,
195 output reg wr = 0,
0491ebad 196 output reg [7:0] wchar = 0,
01e9841e 197 input serialrx);
0491ebad
JW
198
199 reg [15:0] rx_clkdiv = 0;
200 reg [3:0] rx_state = 4'b0000;
201 reg [7:0] rx_data_tmp;
202
203
204 always @(posedge pixclk)
205 begin
206 if ((rx_state == 0) && (serialrx == 0) /*&& (rx_hasdata == 0)*/) /* Kick off. */
207 rx_state <= 4'b0001;
208 else if ((rx_state != 4'b0000) && (rx_clkdiv == 0)) begin
209 if (rx_state != 4'b1010)
210 rx_state <= rx_state + 1;
211 else
212 rx_state <= 0;
213 case (rx_state)
214 4'b0001: begin end /* Twiddle thumbs -- this is the end of the half bit. */
215 4'b0010: rx_data_tmp[0] <= serialrx;
216 4'b0011: rx_data_tmp[1] <= serialrx;
217 4'b0100: rx_data_tmp[2] <= serialrx;
218 4'b0101: rx_data_tmp[3] <= serialrx;
219 4'b0110: rx_data_tmp[4] <= serialrx;
220 4'b0111: rx_data_tmp[5] <= serialrx;
221 4'b1000: rx_data_tmp[6] <= serialrx;
222 4'b1001: rx_data_tmp[7] <= serialrx;
223 4'b1010: if (serialrx == 1) begin
224 wr <= 1;
225 wchar <= rx_data_tmp;
226 end
227 endcase
228 end
229
7b96452d 230 if (wr)
0491ebad 231 wr <= 0;
0491ebad
JW
232
233 if ((rx_state == 0) && (serialrx == 0) /*&& (rx_hasdata == 0)*/) /* Wait half a period before advancing. */
234 rx_clkdiv <= `CLK_DIV / 2 + `CLK_DIV / 4;
235 else if (rx_clkdiv == `CLK_DIV)
236 rx_clkdiv <= 0;
237 else
238 rx_clkdiv <= rx_clkdiv + 1;
239 end
01e9841e
JW
240endmodule
241
242module SerTX(
243 input pixclk,
244 input wr,
245 input [7:0] char,
246 output reg serial = 1);
247
248 reg [7:0] tx_data = 0;
249 reg [15:0] tx_clkdiv = 0;
250 reg [3:0] tx_state = 4'b0000;
251 reg tx_busy = 0;
252 wire tx_newdata = wr && !tx_busy;
0491ebad 253
01e9841e
JW
254 always @(posedge pixclk)
255 begin
256 if(tx_newdata) begin
257 tx_data <= char;
258 tx_state <= 4'b0000;
259 tx_busy <= 1;
260 end else if (tx_clkdiv == 0) begin
261 tx_state <= tx_state + 1;
262 if (tx_busy)
263 case (tx_state)
264 4'b0000: serial <= 0;
265 4'b0001: serial <= tx_data[0];
266 4'b0010: serial <= tx_data[1];
267 4'b0011: serial <= tx_data[2];
268 4'b0100: serial <= tx_data[3];
269 4'b0101: serial <= tx_data[4];
270 4'b0110: serial <= tx_data[5];
271 4'b0111: serial <= tx_data[6];
272 4'b1000: serial <= tx_data[7];
273 4'b1001: serial <= 1;
274 4'b1010: tx_busy <= 0;
275 default: $stop;
276 endcase
277 end
278
279 if(tx_newdata || (tx_clkdiv == `CLK_DIV))
280 tx_clkdiv <= 0;
281 else
282 tx_clkdiv <= tx_clkdiv + 1;
283 end
0491ebad 284endmodule
7b96452d
JW
285
286module RXState(
287 input clk25,
288 output reg vwr = 0,
289 output reg [10:0] vwaddr = 0,
290 output reg [7:0] vwdata = 0,
291 output reg [10:0] vscroll = 0,
31cc645e
JW
292 output wire [6:0] vcursx,
293 output wire [4:0] vcursy,
7b96452d
JW
294 input serwr,
295 input [7:0] serdata);
296
297 parameter STATE_IDLE = 4'b0000;
298 parameter STATE_NEWLINE = 4'b0001;
299 parameter STATE_CLEAR = 4'b0010;
300
301 reg [3:0] state = STATE_CLEAR;
302
303 reg [6:0] x = 0;
304 reg [4:0] y = 0;
305
31cc645e
JW
306 assign vcursx = x;
307 assign vcursy = y;
308
7b96452d
JW
309 reg [10:0] clearstart = 0;
310 reg [10:0] clearend = 11'b11111111111;
311
312 always @(posedge clk25)
313 case (state)
314 STATE_IDLE: if (serwr) begin
315 if (serdata == 8'h0A) begin
316 state <= STATE_NEWLINE;
aae86acd 317 x <= 0;
7b96452d
JW
318 vwr <= 0;
319 end else if (serdata == 8'h0D) begin
320 x <= 0;
321 vwr <= 0;
322 end else if (serdata == 8'h0C) begin
323 clearstart <= 0;
324 clearend <= 11'b11111111111;
325 x <= 0;
326 y <= 0;
327 vscroll <= 0;
328 state <= STATE_CLEAR;
31cc645e
JW
329 end else if (serdata == 8'h08) begin
330 if (x != 0)
331 x <= x - 1;
332 vwr <= 0;
7b96452d
JW
333 end else begin
334 vwr <= 1;
335 vwaddr <= ({y,4'b0} + {y,6'b0} + {4'h0,x}) + vscroll;
336 vwdata <= serdata;
337 if (x == 79) begin
338 x <= 0;
339 state <= STATE_NEWLINE;
340 end else
341 x <= x + 1;
342 end
343 end
344 STATE_NEWLINE:
345 begin
346 vwr <= 0;
347 if (y == 24) begin
348 vscroll <= vscroll + 80;
349 clearstart <= (25 * 80) + vscroll;
350 clearend <= (26*80) + vscroll;
351 state <= STATE_CLEAR;
352 end else begin
353 y <= y + 1;
354 state <= STATE_IDLE;
355 end
356 end
357 STATE_CLEAR:
358 begin
359 vwr <= 1;
360 vwaddr <= clearstart;
361 vwdata <= 8'h20;
362 clearstart <= clearstart + 1;
363 if (clearstart == clearend)
364 state <= STATE_IDLE;
365 end
366 endcase
367endmodule
cad52b37
JW
368
369module PS2(
370 input pixclk,
371 input inclk,
372 input indata,
373 output reg wr,
374 output reg [7:0] data
375 );
376
377 reg [3:0] bitcount = 0;
378 reg [7:0] key = 0;
379 reg keyarrow = 0, keyup = 0, parity = 0;
380
381
382 /* Clock debouncing */
383 reg lastinclk = 0;
384 reg [6:0] debounce = 0;
385 reg fixedclk = 0;
386 reg [11:0] resetcountdown = 0;
387
857e180c
JW
388 reg [6:0] unshiftedrom [127:0]; initial $readmemh("scancodes.unshifted.hex", unshiftedrom);
389 reg [6:0] shiftedrom [127:0]; initial $readmemh("scancodes.shifted.hex", shiftedrom);
390
391 reg mod_lshift = 0;
392 reg mod_rshift = 0;
393 reg mod_capslock = 0;
394 wire mod_shifted = (mod_lshift | mod_rshift) ^ mod_capslock;
395
cad52b37
JW
396 reg nd = 0;
397 reg lastnd = 0;
398
399 always @(posedge pixclk) begin
400 if (inclk != lastinclk) begin
401 lastinclk <= inclk;
402 debounce <= 1;
403 resetcountdown <= 12'b111111111111;
404 end else if (debounce == 0) begin
405 fixedclk <= inclk;
406 resetcountdown <= resetcountdown - 1;
407 end else
408 debounce <= debounce + 1;
409
410 if (nd ^ lastnd) begin
411 lastnd <= nd;
412 wr <= 1;
413 end else
414 wr <= 0;
415 end
416
417 always @(negedge fixedclk) begin
418 if (resetcountdown == 0)
419 bitcount <= 0;
420 else if (bitcount == 10) begin
421 bitcount <= 0;
422 if(parity != (^ key)) begin
423 if(keyarrow) begin
857e180c 424 casex(key)
cad52b37 425 8'hF0: keyup <= 1;
857e180c 426 8'hxx: keyarrow <= 0;
cad52b37
JW
427 endcase
428 end
429 else begin
430 if(keyup) begin
431 keyup <= 0;
857e180c
JW
432 keyarrow <= 0;
433 casex (key)
434 8'h12: mod_lshift <= 0;
435 8'h59: mod_rshift <= 0;
436 endcase
cad52b37
JW
437 // handle this? I don't fucking know
438 end
439 else begin
857e180c 440 casex(key)
cad52b37
JW
441 8'hE0: keyarrow <= 1; // handle these? I don't fucking know
442 8'hF0: keyup <= 1;
857e180c
JW
443 8'h12: mod_lshift <= 1;
444 8'h59: mod_rshift <= 1;
445 8'h14: mod_capslock <= ~mod_capslock;
446 8'b0xxxxxxx: begin nd <= ~nd; data <= mod_shifted ? shiftedrom[key] : unshiftedrom[key]; end
447 8'b1xxxxxxx: begin /* AAAAAAASSSSSSSS */ end
cad52b37
JW
448 endcase
449 end
450 end
451 end
452 else begin
453 keyarrow <= 0;
454 keyup <= 0;
455 end
456 end else
457 bitcount <= bitcount + 1;
458
459 case(bitcount)
460 1: key[0] <= indata;
461 2: key[1] <= indata;
462 3: key[2] <= indata;
463 4: key[3] <= indata;
464 5: key[4] <= indata;
465 6: key[5] <= indata;
466 7: key[6] <= indata;
467 8: key[7] <= indata;
468 9: parity <= indata;
469 endcase
470 end
471
472endmodule
This page took 0.066251 seconds and 5 git commands to generate.