The CRTC Interface
Essential aspects of display page and cursor control for standard
80-column by 25-row text
Motivation
• When a UNIX application wishes to write a text message to the display, and then wait for a keyboard-response from the user, the application will want a ‘cursor’ to be visible at the position where the next keystroke is going to be echoed
• EXAMPLE: Please type a number:
We expect a blinking cursor to appear here
But it’s tedious to program…
• To write code that draws a blinking cursor on the screen would be a time-consuming chore for both programmer and processor:– You have to repeatedly ‘draw’ and then ‘hide’– You have to setup careful timing controls– Your program-loop will keep the CPU busy!
• Fortunately the video system’s hardware is able to handle this tedious chore for you!
Info the CRTC engine needs
• The display hardware already knows how to do the timing for normal cursor blinking (i.e., usually about two blinks per second)
• Software only needs to tell the hardware a few specific pieces of information:– Where does the cursor appear (row, column)? – How large is the cursor? Where does it start
and end within the 8x16 character-cell?– Which region of display-memory is visible?
Hardware registers
• The CRT Controller is a peripheral chip • It implements 25 standard CRTC registers• Access to these registers is accomplished
via a multiplexing scheme which uses just two I/O port-addresses for color text:
address-port: 0x03D4data-port: 0x03D5
How it works
• The multiplexing scheme for access to the CRTC registers was designed to function as a two-step operation:– First, specify which register is to be accessed
(by writing the register’s index to port 0x3D4)– Then, read (or write) to the specified register
(by inputting, or outputting, at port 0x3D5) • But a multi-step scheme is problematic for
preemptive multitasking (also it is slow!)
A useful optimization
• To improve the multiplexing scheme when writing values to CRTC registers, the CPU is able to perform the two steps in a single ‘atomic’ fetch-execute cycle:
• Here the ‘outw’ instruction will write AL to port $0x03D4 and AH to port $0x03D5
mov $0x03D4, %dxmov $0xFF14, %axoutw %ax, %dx
Cursor-related CRTC registers
• For text-mode cursor-control, we are concerned with just 6 (of the 25) standard CRTC registers:
• Index 0x0A: CURSOR_START• Index 0x0B: CURSOR_END• Index 0x0C: START_ADDRESS_HI• Index 0x0D: START_ADDRESS_LO• Index 0x0E: CURSOR_LOCATION_HI• Index 0x0F: CURSOR_LOCATION_LO
8x16 character boxscanline 0scanline 1 scanline 2scanline 3scanline 4scanline 5scanline 6scanline 7scanline 8scanline 9scanline 10scanline 11scanline 12scanline 13scanline 14scanline 15
Cursor_start = 12Cursor_end = 13
CURSOR START/END
dis-able starting_scanline
skew ending_scanline
7 6 5 4 3 2 1 0
7 6 5 4 3 2 1 0
Index 0x0A:
Index 0x0B:
CURSOR_START REGISTER
CURSOR_END REGISTER
NOTE: The ‘skew’ capability works by delaying the cursor’s appearance for0, 1, 2, or 3 character-cells (i.e., shifting the cursor toward the right). WhenIs this useful? We couldn’t find any examples. Recommend skew be zero.
Organization of the VRAM
Page 0
Page 1
Page 2
Page 3
Page 4
Page 5
Page 6
Page 7
Base_Address = 0xB8000
4KB
4KB
4KB
4KB
4KB
4KB
4KB
4KB
Changing the visual page7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
START_ADDRESS_HI START_ADDRESS_LOregister-index 0x0C register-index 0x0D
Programming example: # switches display to vram page 5
# the word-offset for page 5 is 0x2800 (= 5 * 2048)mov $0x03D4, %dx # port-address in register DXmov $0x280C, %ax # value=0x28, register=0x0Cout %ax, %dx # write value to CRTC registermov $0x000D, %ax # value=0x00, register=0x0Dout %ax, %dx # write value to CRTC register
Moving the CRT’s cursor7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
CURSOR_LOCATION_HI CURSOR_LOCATION_LOregister-index 0x0E register-index 0x0F
Programming example: // moves cursor to row 5, column 9, on page 0
mov $0x03D4, %dx // port-address in register DXmov $5, %bx // row-numberimul $80, %bx // times cells-per-rowadd $9, %bx // plus column-numbermov %bh, %ah // cursor offset’s MSBmov $0x0E, %al // CURSOR_HI indexout %ax, %dx // write value to CRTC registermov %bl, %ah // cursor offset’s LSBmov $0x0F, %al // CURSOR_LO indexout %ax, %dx // write value to CRTC register
Scrolling the screen
• Here’s a code-fragment that will scroll the contents of vram page 0 up by one line:
mov $0xB800, %ax // address vram page 0 mov %ax, %ds // with DS register mov %ax, %es // also ES register mov $0, %di // destination is the top line mov $160, %si // source is one line lower cld // do forward copying mov $3840, %cx // 24 times 160 rep movsb // perform the copying mov $0x0720, %ax // blank character w/color mov $80, %cx // characters on bottom line rep stosw // fill final line with blanks
Linux uses hardware scrolling
• The value of the CRT START_ADDRESS is reprogrammed, to change the region of visible vram by one line (i.e., add #80)
• So instead of subdividing vram into eight 4KB pages, the entire 32KB vram is one continuous page, but only partially visible
• To scroll up by one line, Linux adds $80 to the value of the CRT_START_ADDRESS
The ROM-BIOS variables
• Several variables in the ROM-BIOS DATA AREA are used by the VIDEO ROM-BIOS routines (i.e., int-0x10) to keep track of the current visisible page and of the positions of the cursors on each of the eight pages
• The locations of these variables are part of the IBM-PC BIOS standard, and as such they are widely documented
Standard data-addresses
0x449 (byte) current video mode-number0x44A (word) number of columns on screen0x44C (word) current page-size (in bytes)0x44E (word) current page-address0x450 (byte array) cursor-positions (col,row)0x460 byte-pair) cursor type (END, START)0x462 (byte) current display page-number0x463 (word) CRTC base i/o port-address
Real-mode INT-0x10 services• Function 0x00: set_display_mode• Function 0x01: set_cursor_type• Function 0x02: set_cursor_position• Function 0x03: get_cursor_position_and_type• Function 0x05: select_new_video_page • Function 0x06: scroll_current_page_up• Function 0x07: scroll_current_page_down• Function 0x08: read_char_and_attrib_from_screen• Function 0x09: write_char_and_attrib_to_screen• Function 0x0A: write char_only_to_screen• Function 0x0E: write_teletype_to_active_page• Function 0x0F: return_video_status• Function 0x13: write_stringNOTE: These ROM-BIOS services are not available in protected-mode
Cursor-movement demo
• To illustrate reprogramming of the six CRT controller registers, we wrote ‘arrows.s’
• It lets the user control the cursor position and visible page by using arrow-keys
• It also changes the height of the cursor • An unusual feature (not recommended) is
its use of “polled mode” keyboard device-programming (instead of “interrupt-driven”)
Polling the status-register
• The keyboard controller’s interrupt is masked• The keyboard controller’s status-register is read
and reread in a tight loop until bit #0 gets set, indicating that a key was pressed (or released) and hence the output-buffer register is now “full”
• So then the output-buffer register is read by the CPU to get the key’s “scancode”
• For the arrow-keys, the cursor will get moved• Other keys are just ignored (except ESCAPE)
Disadvantage of polling
• Almost all of the CPU’s time is consumed by continually reading the status-register
• So this would not be a good design to use in writing a multitasking operating system!
• On the other hand, for single-tasking it has the advantage of not requiring an Interrupt Service Routine to be written, so the demo code we write can be shorter and simpler
Another noteworthy feature
• The ‘arrows.s’ demo uses a ‘jump-table’ to efficiently dispatch control to appropriate subroutines, based on a variable’s value
• This is a similar programming situation to using a ‘switch’ statement in C/C++
• The jump-table avoids the long chain of ‘compare-and-branch’ statements for all the various possible cases that can occur
In-Class exercise
• To insure your mastery of the jump-table concept, and cement your grasp of how the CRTC START_ADDRESS registers are programmed, try modifying the demo to incorporate these additional actions: when one of the function-keys F1-F7 is pressed, the display is switched to the correspondingly numbered display-page