add handle_trap
[rv32.git] / vga_text_buffer.v
1 /*
2 * Copyright 2018 Jacob Lifshay
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 *
22 */
23 `timescale 1ns / 100ps
24
25 module vga_text_buffer(
26 input pixel_clock,
27 input [15:0] screen_x,
28 input [15:0] screen_y,
29 input screen_valid,
30 output reg [7:0] screen_char,
31 input clk,
32 input tty_write,
33 input [7:0] tty_data,
34 output reg tty_busy
35 );
36
37 parameter font_x_size = 8;
38 parameter font_y_size = 8;
39 parameter screen_x_size = 800;
40 parameter screen_y_size = 600;
41 parameter text_x_size = screen_x_size / font_x_size;
42 parameter text_y_size = screen_y_size / font_y_size;
43 parameter ram_x_size = 128;
44 parameter ram_y_size = 128;
45
46 // ram_style = "block"
47 reg [7:0] text_ram[ram_x_size * ram_y_size - 1 : 0];
48
49 initial $readmemh("text_initial.hex", text_ram);
50
51 initial tty_busy = 1;
52
53 initial screen_char = 0;
54
55 reg [11:0] scroll_amount;
56
57 initial scroll_amount = 0;
58
59 always @(posedge pixel_clock) begin
60 screen_char <= screen_valid ? text_ram[ram_x_size * ((screen_y / font_y_size) + scroll_amount) + (screen_x / font_x_size)] : 0;
61 end
62
63 reg [11:0] cursor_x;
64 reg [11:0] cursor_y;
65
66 initial cursor_x = 0;
67 initial cursor_y = 0;
68
69 reg [2:0] state;
70
71 initial state = 0;
72
73 wire [11:0] cursor_x_after_tab_unwrapped = ((cursor_x >> 3) + 1) << 3;
74 wire [11:0] cursor_x_after_tab = (cursor_x_after_tab_unwrapped == text_x_size ? 0 : cursor_x_after_tab_unwrapped);
75
76 reg [15:0] text_ram_write_address;
77 reg text_ram_write_enable;
78 reg [7:0] text_ram_write_data;
79
80 always @(posedge clk) begin
81 if(text_ram_write_enable)
82 text_ram[text_ram_write_address] <= text_ram_write_data;
83 end
84
85 parameter space_char = 'h20;
86 parameter escape_char = 'h1B;
87 parameter left_bracket_char = 'h5B;
88 parameter capital_H_char = 'h48;
89
90 always @(posedge clk) begin
91 text_ram_write_enable = 0;
92 case(state)
93 0: begin
94 cursor_x <= 0;
95 cursor_y <= 0;
96 tty_busy <= 1;
97 state <= 1;
98 scroll_amount <= 0;
99 end
100 1: begin
101 if(cursor_x != ram_x_size - 1) begin
102 tty_busy <= 1;
103 text_ram_write_enable = 1;
104 text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
105 text_ram_write_data = space_char;
106 cursor_x <= cursor_x + 1;
107 end
108 else if(cursor_y != ram_y_size - 1) begin
109 tty_busy <= 1;
110 text_ram_write_enable = 1;
111 text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
112 text_ram_write_data = space_char;
113 cursor_x <= 0;
114 cursor_y <= cursor_y + 1;
115 end
116 else begin
117 text_ram_write_enable = 1;
118 text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
119 text_ram_write_data = space_char;
120 tty_busy <= 0;
121 state <= 2;
122 cursor_x <= 0;
123 cursor_y <= 0;
124 end
125 end
126 2: begin
127 if(tty_write) begin
128 case (tty_data)
129 'h0A: begin
130 if(cursor_y != text_y_size - 1) begin
131 cursor_x <= 0;
132 cursor_y <= cursor_y + 1;
133 tty_busy <= 0;
134 end
135 else begin
136 cursor_x <= 0;
137 tty_busy <= 1;
138 state <= 3;
139 scroll_amount <= scroll_amount + 1;
140 end
141 end
142 'h1B: begin
143 tty_busy <= 0;
144 state <= 4;
145 end
146 'h0D: begin
147 cursor_x <= 0;
148 tty_busy <= 0;
149 end
150 'h09: begin
151 cursor_x <= cursor_x_after_tab;
152 tty_busy <= 0;
153 end
154 default: begin
155 text_ram_write_enable = 1;
156 text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
157 text_ram_write_data = tty_data;
158 if(cursor_x != text_x_size - 1) begin
159 cursor_x <= cursor_x + 1;
160 tty_busy <= 0;
161 end
162 else if(cursor_y != text_y_size - 1) begin
163 cursor_x <= 0;
164 cursor_y <= cursor_y + 1;
165 tty_busy <= 0;
166 end
167 else begin
168 cursor_x <= 0;
169 cursor_y <= text_y_size - 1;
170 tty_busy <= 1;
171 state <= 3;
172 scroll_amount <= scroll_amount + 1;
173 end
174 end
175 endcase
176 end
177 else begin
178 tty_busy <= 0;
179 end
180 end
181 3: begin
182 if(cursor_x != ram_x_size - 1) begin
183 tty_busy <= 1;
184 text_ram_write_enable = 1;
185 text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
186 text_ram_write_data = space_char;
187 cursor_x <= cursor_x + 1;
188 end
189 else begin
190 text_ram_write_enable = 1;
191 text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
192 text_ram_write_data = space_char;
193 tty_busy <= 0;
194 state <= 2;
195 cursor_x <= 0;
196 end
197 end
198 4: begin
199 if(tty_write) begin
200 case (tty_data)
201 'h52: begin // "R": reset
202 tty_busy <= 1;
203 state <= 0;
204 end
205 left_bracket_char: begin
206 tty_busy <= 0;
207 state <= 5;
208 end
209 default: begin
210 text_ram_write_enable = 1;
211 text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
212 text_ram_write_data = tty_data;
213 if(cursor_x != text_x_size - 1) begin
214 cursor_x <= cursor_x + 1;
215 tty_busy <= 0;
216 state <= 2;
217 end
218 else if(cursor_y != text_y_size - 1) begin
219 cursor_x <= 0;
220 cursor_y <= cursor_y + 1;
221 tty_busy <= 0;
222 state <= 2;
223 end
224 else begin
225 cursor_x <= 0;
226 cursor_y <= text_y_size - 1;
227 tty_busy <= 1;
228 state <= 3;
229 scroll_amount <= scroll_amount + 1;
230 end
231 end
232 endcase
233 end
234 else begin
235 tty_busy <= 0;
236 end
237 end
238 5: begin
239 if(tty_write) begin
240 case (tty_data)
241 capital_H_char: begin // move to top left
242 tty_busy <= 0;
243 state <= 2;
244 cursor_x <= 0;
245 cursor_y <= 0;
246 end
247 default: begin
248 text_ram_write_enable = 1;
249 text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
250 text_ram_write_data = tty_data;
251 if(cursor_x != text_x_size - 1) begin
252 cursor_x <= cursor_x + 1;
253 tty_busy <= 0;
254 state <= 2;
255 end
256 else if(cursor_y != text_y_size - 1) begin
257 cursor_x <= 0;
258 cursor_y <= cursor_y + 1;
259 tty_busy <= 0;
260 state <= 2;
261 end
262 else begin
263 cursor_x <= 0;
264 cursor_y <= text_y_size - 1;
265 tty_busy <= 1;
266 state <= 3;
267 scroll_amount <= scroll_amount + 1;
268 end
269 end
270 endcase
271 end
272 else begin
273 tty_busy <= 0;
274 end
275 end
276 default: state <= 0;
277 endcase
278 end
279
280 endmodule