949dd975eaec8da2ae0e34551b7ca23765a14792
[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 "threads/io.h"
7 #include "threads/interrupt.h"
8 #include "threads/vaddr.h"
9
10 /* VGA text screen support.  See [FREEVGA] for more information. */
11
12 /* Number of columns and rows on the text display. */
13 #define COL_CNT 80
14 #define ROW_CNT 25
15
16 /* Current cursor position.  (0,0) is in the upper left corner of
17    the display. */
18 static size_t cx, cy;
19
20 /* Attribute value for gray text on a black background. */
21 #define GRAY_ON_BLACK 0x07
22
23 /* Framebuffer.  See [FREEVGA] under "VGA Text Mode Operation".
24    The character at (x,y) is fb[y][x][0].
25    The attribute at (x,y) is fb[y][x][1]. */
26 static uint8_t (*fb)[COL_CNT][2];
27
28 static void clear_row (size_t y);
29 static void cls (void);
30 static void newline (void);
31 static void move_cursor (void);
32
33 /* Initializes the VGA text display and clears the screen. */
34 void
35 vga_init (void)
36 {
37   fb = ptov (0xb8000);
38   cls ();
39 }
40
41 /* Writes C to the VGA text display, interpreting control
42    characters in the conventional ways.  */
43 void
44 vga_putc (int c)
45 {
46   /* Disable interrupts to lock out interrupt handlers
47      that might write to the console. */
48   enum intr_level old_level = intr_disable ();
49
50   switch (c) 
51     {
52     case '\n':
53       newline ();
54       break;
55
56     case '\f':
57       cls ();
58       break;
59
60     case '\b':
61       if (cx > 0)
62         cx--;
63       break;
64       
65     case '\r':
66       cx = 0;
67       break;
68
69     case '\t':
70       cx = ROUND_UP (cx + 1, 8);
71       if (cx >= COL_CNT)
72         newline ();
73       break;
74       
75     default:
76       fb[cy][cx][0] = c;
77       fb[cy][cx][1] = GRAY_ON_BLACK;
78       if (++cx >= COL_CNT)
79         newline ();
80       break;
81     }
82
83   /* Update cursor position. */
84   move_cursor ();
85
86   intr_set_level (old_level);
87 }
88 \f
89 /* Clears the screen and moves the cursor to the upper left. */
90 static void
91 cls (void)
92 {
93   size_t y;
94
95   for (y = 0; y < ROW_CNT; y++)
96     clear_row (y);
97
98   cx = cy = 0;
99   move_cursor ();
100 }
101
102 /* Clears row Y to spaces. */
103 static void
104 clear_row (size_t y) 
105 {
106   size_t x;
107
108   for (x = 0; x < COL_CNT; x++)
109     {
110       fb[y][x][0] = ' ';
111       fb[y][x][1] = GRAY_ON_BLACK;
112     }
113 }
114
115 /* Advances the cursor to the first column in the next line on
116    the screen.  If the cursor is already on the last line on the
117    screen, scrolls the screen upward one line. */
118 static void
119 newline (void)
120 {
121   cx = 0;
122   cy++;
123   if (cy >= ROW_CNT)
124     {
125       cy = ROW_CNT - 1;
126       memmove (&fb[0], &fb[1], sizeof fb[0] * (ROW_CNT - 1));
127       clear_row (ROW_CNT - 1);
128     }
129 }
130
131 /* Moves the hardware cursor to (cx,cy). */
132 static void
133 move_cursor (void) 
134 {
135   /* See [FREEVGA] under "Manipulating the Text-mode Cursor". */
136   uint16_t cp = cx + COL_CNT * cy;
137   outw (0x3d4, 0x0e | (cp & 0xff00));
138   outw (0x3d4, 0x0f | (cp << 8));
139 }
140