]> Joshua Wise's Git repositories - vterm.git/blob - VTerm.v
Add a cursor. Add backspace.
[vterm.git] / VTerm.v
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,
38         output reg [1:0] blue,
39         input serrx,
40         output sertx,
41         input ps2c, ps2d);
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         
54         wire [7:0] cschar;
55         wire [2:0] csrow;
56         wire [7:0] csdata;
57         
58         wire [10:0] vraddr;
59         wire [7:0] vrdata;
60         
61         wire [10:0] vwaddr;
62         wire [7:0] vwdata;
63         wire [7:0] serdata;
64         wire vwr, serwr;
65         wire [10:0] vscroll;
66         
67         wire odata;
68         
69         wire [7:0] sertxdata;
70         wire sertxwr;
71         
72         wire [6:0] vcursx;
73         wire [4:0] vcursy;
74         
75         CharSet cs(cschar, csrow, csdata);
76         VideoRAM vram(clk25, vraddr + vscroll, vrdata, vwaddr, vwdata, vwr);
77         VDisplay dpy(clk25, x, y, vraddr, vrdata, cschar, csrow, csdata, vcursx, vcursy, odata);
78         SerRX rx(clk25, serwr, serdata, serrx);
79         SerTX tx(clk25, sertxwr, sertxdata, sertx);
80         RXState rxsm(clk25, vwr, vwaddr, vwdata, vscroll, vcursx, vcursy, serwr, serdata);
81         PS2 ps2(clk25, ps2c, ps2d, sertxwr, sertxdata);
82         
83         always @(posedge clk25) begin
84                 red <= border ? 0 : {3{odata}};
85                 green <= border ? 0 : {3{odata}};
86                 blue <= border ? 0 : {2{odata}};
87         end
88 endmodule
89
90 module 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
121 endmodule
122
123 module 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}];
134 endmodule
135
136 module VideoRAM(
137         input pixclk,
138         input [10:0] raddr,
139         output reg [7:0] rdata,
140         input [10:0] waddr,
141         input [7:0] wdata,
142         input wr);
143         
144         reg [7:0] ram [2047 : 0];
145         
146         always @(posedge pixclk)
147                 rdata <= ram[raddr];
148         
149         always @(posedge pixclk)
150                 if (wr)
151                         ram[waddr] <= wdata;
152 endmodule
153
154 module VDisplay(
155         input pixclk,
156         input [11:0] x,
157         input [11:0] y,
158         output wire [10:0] raddr,
159         input [7:0] rchar,
160         output wire [7:0] cschar,
161         output wire [2:0] csrow,
162         input [7:0] csdata,
163         input [6:0] cursx,
164         input [4:0] cursy,
165         output reg data);
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         
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         
182         always @(posedge pixclk)
183                 xdly <= x;
184         
185         always @(posedge pixclk)
186                 data = ((xdly < 80 * 8) && (y < 25 * 8)) ? (csdata[7 - xdly[2:0]] ^ curssel) : 0;
187 endmodule
188
189 `define IN_CLK 25000000
190 `define OUT_CLK 57600
191 `define CLK_DIV (`IN_CLK / `OUT_CLK)
192
193 module SerRX(
194         input pixclk,
195         output reg wr = 0,
196         output reg [7:0] wchar = 0,
197         input serialrx);
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                 
230                 if (wr)
231                         wr <= 0;
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
240 endmodule
241
242 module 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;
253
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
284 endmodule
285
286 module 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,
292         output wire [6:0] vcursx,
293         output wire [4:0] vcursy,
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         
306         assign vcursx = x;
307         assign vcursy = y;
308         
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;
317                                                 x <= 0;
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;
329                                         end else if (serdata == 8'h08) begin
330                                                 if (x != 0)
331                                                         x <= x - 1;
332                                                 vwr <= 0;
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
367 endmodule
368
369 module 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         
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         
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
424                                         casex(key)
425                                                 8'hF0: keyup <= 1;
426                                                 8'hxx: keyarrow <= 0;
427                                         endcase
428                                 end
429                                 else begin
430                                         if(keyup) begin
431                                                 keyup <= 0;
432                                                 keyarrow <= 0;
433                                                 casex (key)
434                                                 8'h12: mod_lshift <= 0;
435                                                 8'h59: mod_rshift <= 0;
436                                                 endcase
437                                                 // handle this? I don't fucking know
438                                         end
439                                         else begin
440                                                 casex(key)
441                                                         8'hE0: keyarrow <= 1;   // handle these? I don't fucking know
442                                                         8'hF0: keyup <= 1;
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
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
472 endmodule
This page took 0.049117 seconds and 4 git commands to generate.