random: Fix behavior of kernel option "-rs".
[pintos-anon] / src / devices / vga.c
1 #include "devices/vga.h"
2 #include <round.h>
3 #include <stdint.h>
4 #include <stddef.h>
5 #include <string.h>
6 #include "devices/speaker.h"
7 #include "threads/io.h"
8 #include "threads/interrupt.h"
9 #include "threads/vaddr.h"
10
11 /* VGA text screen support.  See [FREEVGA] for more information. */
12
13 /* Number of columns and rows on the text display. */
14 #define COL_CNT 80
15 #define ROW_CNT 25
16
17 /* Current cursor position.  (0,0) is in the upper left corner of
18    the display. */
19 static size_t cx, cy;
20
21 /* Attribute value for gray text on a black background. */
22 #define GRAY_ON_BLACK 0x07
23
24 /* Framebuffer.  See [FREEVGA] under "VGA Text Mode Operation".
25    The character at (x,y) is fb[y][x][0].
26    The attribute at (x,y) is fb[y][x][1]. */
27 static uint8_t (*fb)[COL_CNT][2];
28
29 static void clear_row (size_t y);
30 static void cls (void);
31 static void newline (void);
32 static void move_cursor (void);
33 static void find_cursor (size_t *x, size_t *y);
34
35 /* Initializes the VGA text display. */
36 static void
37 init (void)
38 {
39   /* Already initialized? */
40   static bool inited;
41   if (!inited)
42     {
43       fb = ptov (0xb8000);
44       find_cursor (&cx, &cy);
45       inited = true; 
46     }
47 }
48
49 /* Writes C to the VGA text display, interpreting control
50    characters in the conventional ways.  */
51 void
52 vga_putc (int c)
53 {
54   /* Disable interrupts to lock out interrupt handlers
55      that might write to the console. */
56   enum intr_level old_level = intr_disable ();
57
58   init ();
59   
60   switch (c) 
61     {
62     case '\n':
63       newline ();
64       break;
65
66     case '\f':
67       cls ();
68       break;
69
70     case '\b':
71       if (cx > 0)
72         cx--;
73       break;
74       
75     case '\r':
76       cx = 0;
77       break;
78
79     case '\t':
80       cx = ROUND_UP (cx + 1, 8);
81       if (cx >= COL_CNT)
82         newline ();
83       break;
84
85     case '\a':
86       intr_set_level (old_level);
87       speaker_beep ();
88       intr_disable ();
89       break;
90       
91     default:
92       fb[cy][cx][0] = c;
93       fb[cy][cx][1] = GRAY_ON_BLACK;
94       if (++cx >= COL_CNT)
95         newline ();
96       break;
97     }
98
99   /* Update cursor position. */
100   move_cursor ();
101
102   intr_set_level (old_level);
103 }
104 \f
105 /* Clears the screen and moves the cursor to the upper left. */
106 static void
107 cls (void)
108 {
109   size_t y;
110
111   for (y = 0; y < ROW_CNT; y++)
112     clear_row (y);
113
114   cx = cy = 0;
115   move_cursor ();
116 }
117
118 /* Clears row Y to spaces. */
119 static void
120 clear_row (size_t y) 
121 {
122   size_t x;
123
124   for (x = 0; x < COL_CNT; x++)
125     {
126       fb[y][x][0] = ' ';
127       fb[y][x][1] = GRAY_ON_BLACK;
128     }
129 }
130
131 /* Advances the cursor to the first column in the next line on
132    the screen.  If the cursor is already on the last line on the
133    screen, scrolls the screen upward one line. */
134 static void
135 newline (void)
136 {
137   cx = 0;
138   cy++;
139   if (cy >= ROW_CNT)
140     {
141       cy = ROW_CNT - 1;
142       memmove (&fb[0], &fb[1], sizeof fb[0] * (ROW_CNT - 1));
143       clear_row (ROW_CNT - 1);
144     }
145 }
146
147 /* Moves the hardware cursor to (cx,cy). */
148 static void
149 move_cursor (void) 
150 {
151   /* See [FREEVGA] under "Manipulating the Text-mode Cursor". */
152   uint16_t cp = cx + COL_CNT * cy;
153   outw (0x3d4, 0x0e | (cp & 0xff00));
154   outw (0x3d4, 0x0f | (cp << 8));
155 }
156
157 /* Reads the current hardware cursor position into (*X,*Y). */
158 static void
159 find_cursor (size_t *x, size_t *y) 
160 {
161   /* See [FREEVGA] under "Manipulating the Text-mode Cursor". */
162   uint16_t cp;
163
164   outb (0x3d4, 0x0e);
165   cp = inb (0x3d5) << 8;
166
167   outb (0x3d4, 0x0f);
168   cp |= inb (0x3d5);
169
170   *x = cp % COL_CNT;
171   *y = cp / COL_CNT;
172 }