]>
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 | ||
57 | wire [11:0] vraddr; | |
58 | wire [7:0] vrdata; | |
59 | ||
0491ebad JW |
60 | wire [11:0] vwaddr; |
61 | wire [7:0] vwdata; | |
62 | wire vwr; | |
d3ae999b JW |
63 | |
64 | wire odata; | |
65 | ||
66 | CharSet cs(cschar, csrow, csdata); | |
0491ebad | 67 | VideoRAM vram(clk25, vraddr, vrdata, vwaddr, vwdata, vwr); |
d3ae999b | 68 | VDisplay dpy(clk25, x, y, vraddr, vrdata, cschar, csrow, csdata, odata); |
0491ebad | 69 | SerRX rx(clk25, vwr, vwaddr, vwdata, serrx); |
d3ae999b | 70 | |
a55fc9f4 | 71 | always @(posedge clk25) begin |
d3ae999b JW |
72 | red <= border ? 0 : {3{odata}}; |
73 | green <= border ? 0 : {3{odata}}; | |
74 | blue <= border ? 0 : {2{odata}}; | |
a55fc9f4 JW |
75 | end |
76 | endmodule | |
77 | ||
78 | module SyncGen( | |
79 | input pixclk, | |
80 | output reg vs, hs, | |
81 | output reg [11:0] x, y, | |
82 | output reg border); | |
83 | ||
84 | parameter XRES = 640; | |
85 | parameter XFPORCH = 16; | |
86 | parameter XSYNC = 96; | |
87 | parameter XBPORCH = 48; | |
88 | ||
89 | parameter YRES = 480; | |
90 | parameter YFPORCH = 10; | |
91 | parameter YSYNC = 2; | |
92 | parameter YBPORCH = 29; | |
93 | ||
94 | always @(posedge pixclk) | |
95 | begin | |
96 | if (x >= (XRES + XFPORCH + XSYNC + XBPORCH)) | |
97 | begin | |
98 | if (y >= (YRES + YFPORCH + YSYNC + YBPORCH)) | |
99 | y = 0; | |
100 | else | |
101 | y = y + 1; | |
102 | x = 0; | |
103 | end else | |
104 | x = x + 1; | |
105 | hs <= (x >= (XRES + XFPORCH)) && (x < (XRES + XFPORCH + XSYNC)); | |
106 | vs <= (y >= (YRES + YFPORCH)) && (y < (YRES + YFPORCH + YSYNC)); | |
107 | border <= (x > XRES) || (y > YRES); | |
108 | end | |
109 | endmodule | |
d3ae999b JW |
110 | |
111 | module CharSet( | |
112 | input [7:0] char, | |
113 | input [2:0] row, | |
114 | output wire [7:0] data); | |
115 | ||
116 | reg [7:0] rom [(256 * 8 - 1):0]; | |
117 | ||
118 | initial | |
119 | $readmemb("ibmpc1.mem", rom); | |
120 | ||
121 | assign data = rom[{char, row}]; | |
122 | endmodule | |
123 | ||
124 | module VideoRAM( | |
125 | input pixclk, | |
126 | input [11:0] raddr, | |
127 | output reg [7:0] rdata, | |
128 | input [11:0] waddr, | |
129 | input [7:0] wdata, | |
130 | input wr); | |
131 | ||
132 | reg [7:0] ram [80*25-1 : 0]; | |
133 | ||
134 | always @(posedge pixclk) | |
135 | rdata <= ram[raddr]; | |
136 | ||
137 | always @(posedge pixclk) | |
138 | if (wr) | |
139 | ram[waddr] <= wdata; | |
140 | endmodule | |
141 | ||
142 | module VDisplay( | |
143 | input pixclk, | |
144 | input [11:0] x, | |
145 | input [11:0] y, | |
146 | output wire [11:0] raddr, | |
147 | input [7:0] rchar, | |
148 | output wire [7:0] cschar, | |
149 | output wire [2:0] csrow, | |
150 | input [7:0] csdata, | |
151 | output reg data | |
152 | ); | |
153 | ||
154 | wire [7:0] col = x[11:3]; | |
155 | wire [5:0] row = y[9:3]; | |
156 | reg [7:0] ch; | |
157 | reg [11:0] xdly; | |
158 | ||
159 | assign raddr = ({row,4'b0} + {row,6'b0} + {4'h0,col}); | |
160 | assign cschar = rchar; | |
161 | assign csrow = y[2:0]; | |
162 | ||
163 | always @(posedge pixclk) | |
164 | xdly <= x; | |
165 | ||
166 | always @(posedge pixclk) | |
167 | data = ((xdly < 80 * 8) && (y < 25 * 8)) ? csdata[7 - xdly[2:0]] : 0; | |
168 | endmodule | |
0491ebad JW |
169 | |
170 | `define IN_CLK 25000000 | |
171 | `define OUT_CLK 57600 | |
172 | `define CLK_DIV (`IN_CLK / `OUT_CLK) | |
173 | ||
174 | module SerRX( | |
175 | input pixclk, | |
176 | output reg wr = 0, | |
177 | output reg [11:0] waddr = 0, | |
178 | output reg [7:0] wchar = 0, | |
179 | input serialrx | |
180 | ); | |
181 | ||
182 | reg [15:0] rx_clkdiv = 0; | |
183 | reg [3:0] rx_state = 4'b0000; | |
184 | reg [7:0] rx_data_tmp; | |
185 | ||
186 | ||
187 | always @(posedge pixclk) | |
188 | begin | |
189 | if ((rx_state == 0) && (serialrx == 0) /*&& (rx_hasdata == 0)*/) /* Kick off. */ | |
190 | rx_state <= 4'b0001; | |
191 | else if ((rx_state != 4'b0000) && (rx_clkdiv == 0)) begin | |
192 | if (rx_state != 4'b1010) | |
193 | rx_state <= rx_state + 1; | |
194 | else | |
195 | rx_state <= 0; | |
196 | case (rx_state) | |
197 | 4'b0001: begin end /* Twiddle thumbs -- this is the end of the half bit. */ | |
198 | 4'b0010: rx_data_tmp[0] <= serialrx; | |
199 | 4'b0011: rx_data_tmp[1] <= serialrx; | |
200 | 4'b0100: rx_data_tmp[2] <= serialrx; | |
201 | 4'b0101: rx_data_tmp[3] <= serialrx; | |
202 | 4'b0110: rx_data_tmp[4] <= serialrx; | |
203 | 4'b0111: rx_data_tmp[5] <= serialrx; | |
204 | 4'b1000: rx_data_tmp[6] <= serialrx; | |
205 | 4'b1001: rx_data_tmp[7] <= serialrx; | |
206 | 4'b1010: if (serialrx == 1) begin | |
207 | wr <= 1; | |
208 | wchar <= rx_data_tmp; | |
209 | end | |
210 | endcase | |
211 | end | |
212 | ||
213 | if (wr) begin | |
214 | wr <= 0; | |
215 | waddr <= waddr + 1; | |
216 | end | |
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 |