summaryrefslogtreecommitdiff
path: root/kernel/cio.c
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-03-25 17:36:52 -0400
committerFreya Murphy <freya@freyacat.org>2025-03-25 17:38:22 -0400
commit6af21e6a4f2251e71353562d5df7f376fdffc270 (patch)
treede20c7afc9878422c81e34f30c6b010075e9e69a /kernel/cio.c
downloadcomus-6af21e6a4f2251e71353562d5df7f376fdffc270.tar.gz
comus-6af21e6a4f2251e71353562d5df7f376fdffc270.tar.bz2
comus-6af21e6a4f2251e71353562d5df7f376fdffc270.zip
initial checkout from wrc
Diffstat (limited to 'kernel/cio.c')
-rw-r--r--kernel/cio.c796
1 files changed, 796 insertions, 0 deletions
diff --git a/kernel/cio.c b/kernel/cio.c
new file mode 100644
index 0000000..cfff543
--- /dev/null
+++ b/kernel/cio.c
@@ -0,0 +1,796 @@
+/*
+** SCCS ID: @(#)cio.c 2.10 1/22/25
+**
+** @file cio.c
+**
+** @author Warren R. Carithers
+**
+** Based on: c_io.c 1.13 (Ken Reek, Jon Coles, Warren R. Carithers)
+**
+** Console I/O routines
+**
+** This module implements a simple set of input and output routines
+** for the console screen and keyboard on the machines in the DSL.
+** Refer to the header file comments for complete details.
+**
+** Naming conventions:
+**
+** Externally-visible functions have names beginning with the
+** characters "cio_".
+**
+*/
+
+#include <cio.h>
+#include <lib.h>
+#include <support.h>
+#include <x86/arch.h>
+#include <x86/pic.h>
+#include <x86/ops.h>
+
+/*
+** Bit masks for the lower five and eight bits of a value
+*/
+#define BMASK5 0x1f
+#define BMASK8 0xff
+
+/*
+** Video parameters
+*/
+#define SCREEN_MIN_X 0
+#define SCREEN_MIN_Y 0
+#define SCREEN_X_SIZE 80
+#define SCREEN_Y_SIZE 25
+#define SCREEN_MAX_X ( SCREEN_X_SIZE - 1 )
+#define SCREEN_MAX_Y ( SCREEN_Y_SIZE - 1 )
+
+/*
+** Video state
+*/
+static unsigned int scroll_min_x, scroll_min_y;
+static unsigned int scroll_max_x, scroll_max_y;
+static unsigned int curr_x, curr_y;
+static unsigned int min_x, min_y;
+static unsigned int max_x, max_y;
+
+// pointer to input notification function
+static void (*notify)(int);
+
+#ifdef SA_DEBUG
+#include <stdio.h>
+#define cio_putchar putchar
+#define cio_puts(x) fputs( x, stdout )
+#endif
+
+
+/*
+** VGA definitions.
+*/
+
+// calculate the memory address of a specific character position
+// within VGA memory
+#define VIDEO_ADDR(x,y) ( unsigned short * ) \
+ ( VID_BASE_ADDR + 2 * ( (y) * SCREEN_X_SIZE + (x) ) )
+
+// port addresses
+#define VGA_CTRL_IX_ADDR 0x3d4
+# define VGA_CTRL_CUR_HIGH 0x0e // cursor location, high byte
+# define VGA_CTRL_CUR_LOW 0x0f // cursor location, low byte
+#define VGA_CTRL_IX_DATA 0x3d5
+
+// attribute bits
+#define VGA_ATT_BBI 0x80 // blink, or background intensity
+#define VGA_ATT_BGC 0x70 // background color
+#define VGA_ATT_FICS 0x80 // foreground intensity or char font select
+#define VGA_ATT_FGC 0x70 // foreground color
+
+// color selections
+#define VGA_BG_BLACK 0x0000 // background colors
+#define VGA_BG_BLUE 0x1000
+#define VGA_BG_GREEN 0x2000
+#define VGA_BG_CYAN 0x3000
+#define VGA_BG_RED 0x4000
+#define VGA_BG_MAGENTA 0x5000
+#define VGA_BG_BROWN 0x6000
+#define VGA_BG_WHITE 0x7000
+
+#define VGA_FG_BLACK 0x0000 // foreground colors
+#define VGA_FG_BLUE 0x0100
+#define VGA_FG_GREEN 0x0200
+#define VGA_FG_CYAN 0x0300
+#define VGA_FG_RED 0x0400
+#define VGA_FG_MAGENTA 0x0500
+#define VGA_FG_BROWN 0x0600
+#define VGA_FG_WHITE 0x0700
+
+// color combinations
+#define VGA_WHITE_ON_BLACK (VGA_FG_WHITE | VGA_BG_BLACK)
+#define VGA_BLACK_ON_WHITE (VGA_FG_BLACK | VGA_BG_WHITE)
+
+/*
+** Internal support routines.
+*/
+
+/*
+** setcursor: set the cursor location (screen coordinates)
+*/
+static void setcursor( void ) {
+ unsigned addr;
+ unsigned int y = curr_y;
+
+ if( y > scroll_max_y ) {
+ y = scroll_max_y;
+ }
+
+ addr = (unsigned)( y * SCREEN_X_SIZE + curr_x );
+
+ outb( VGA_CTRL_IX_ADDR, VGA_CTRL_CUR_HIGH );
+ outb( VGA_CTRL_IX_DATA, ( addr >> 8 ) & BMASK8 );
+ outb( VGA_CTRL_IX_ADDR, VGA_CTRL_CUR_LOW );
+ outb( VGA_CTRL_IX_DATA, addr & BMASK8 );
+}
+
+/*
+** putchar_at: physical output to the video memory
+*/
+static void putchar_at( unsigned int x, unsigned int y, unsigned int c ) {
+ /*
+ ** If x or y is too big or small, don't do any output.
+ */
+ if( x <= max_x && y <= max_y ) {
+ unsigned short *addr = VIDEO_ADDR( x, y );
+
+ /*
+ ** The character may have attributes associated with it; if
+ ** so, use those, otherwise use white on black.
+ */
+ c &= 0xffff; // keep only the lower bytes
+ if( c > BMASK8 ) {
+ *addr = (unsigned short)c;
+ } else {
+ *addr = (unsigned short)c | VGA_WHITE_ON_BLACK;
+ }
+ }
+}
+
+/*
+** Globally-visible support routines.
+*/
+
+/*
+** Set the scrolling region
+*/
+void cio_setscroll( unsigned int s_min_x, unsigned int s_min_y,
+ unsigned int s_max_x, unsigned int s_max_y ) {
+ scroll_min_x = bound( min_x, s_min_x, max_x );
+ scroll_min_y = bound( min_y, s_min_y, max_y );
+ scroll_max_x = bound( scroll_min_x, s_max_x, max_x );
+ scroll_max_y = bound( scroll_min_y, s_max_y, max_y );
+ curr_x = scroll_min_x;
+ curr_y = scroll_min_y;
+ setcursor();
+}
+
+/*
+** Cursor movement in the scroll region
+*/
+void cio_moveto( unsigned int x, unsigned int y ) {
+ curr_x = bound( scroll_min_x, x + scroll_min_x, scroll_max_x );
+ curr_y = bound( scroll_min_y, y + scroll_min_y, scroll_max_y );
+ setcursor();
+}
+
+/*
+** The putchar family
+*/
+void cio_putchar_at( unsigned int x, unsigned int y, unsigned int c ) {
+ if( ( c & 0x7f ) == '\n' ) {
+ unsigned int limit;
+
+ /*
+ ** If we're in the scroll region, don't let this loop
+ ** leave it. If we're not in the scroll region, don't
+ ** let this loop enter it.
+ */
+ if( x > scroll_max_x ) {
+ limit = max_x;
+ }
+ else if( x >= scroll_min_x ) {
+ limit = scroll_max_x;
+ }
+ else {
+ limit = scroll_min_x - 1;
+ }
+ while( x <= limit ) {
+ putchar_at( x, y, ' ' );
+ x += 1;
+ }
+ }
+ else {
+ putchar_at( x, y, c );
+ }
+}
+
+#ifndef SA_DEBUG
+void cio_putchar( unsigned int c ) {
+ /*
+ ** If we're off the bottom of the screen, scroll the window.
+ */
+ if( curr_y > scroll_max_y ) {
+ cio_scroll( curr_y - scroll_max_y );
+ curr_y = scroll_max_y;
+ }
+
+ switch( c & BMASK8 ) {
+ case '\n':
+ /*
+ ** Erase to the end of the line, then move to new line
+ ** (actual scroll is delayed until next output appears).
+ */
+ while( curr_x <= scroll_max_x ) {
+ putchar_at( curr_x, curr_y, ' ' );
+ curr_x += 1;
+ }
+ curr_x = scroll_min_x;
+ curr_y += 1;
+ break;
+
+ case '\r':
+ curr_x = scroll_min_x;
+ break;
+
+ default:
+ putchar_at( curr_x, curr_y, c );
+ curr_x += 1;
+ if( curr_x > scroll_max_x ) {
+ curr_x = scroll_min_x;
+ curr_y += 1;
+ }
+ break;
+ }
+ setcursor();
+}
+#endif
+
+/*
+** The puts family
+*/
+void cio_puts_at( unsigned int x, unsigned int y, const char *str ) {
+ unsigned int ch;
+
+ while( (ch = *str++) != '\0' && x <= max_x ) {
+ cio_putchar_at( x, y, ch );
+ x += 1;
+ }
+}
+
+#ifndef SA_DEBUG
+void cio_puts( const char *str ) {
+ unsigned int ch;
+
+ while( (ch = *str++) != '\0' ) {
+ cio_putchar( ch );
+ }
+}
+#endif
+
+/*
+** Write a "sized" buffer (like cio_puts(), but no NUL)
+*/
+void cio_write( const char *buf, int length ) {
+ for( int i = 0; i < length; ++i ) {
+ cio_putchar( buf[i] );
+ }
+}
+
+void cio_clearscroll( void ) {
+ unsigned int nchars = scroll_max_x - scroll_min_x + 1;
+ unsigned int l;
+ unsigned int c;
+
+ for( l = scroll_min_y; l <= scroll_max_y; l += 1 ) {
+ unsigned short *to = VIDEO_ADDR( scroll_min_x, l );
+
+ for( c = 0; c < nchars; c += 1 ) {
+ *to++ = ' ' | 0x0700;
+ }
+ }
+}
+
+void cio_clearscreen( void ) {
+ unsigned short *to = VIDEO_ADDR( min_x, min_y );
+ unsigned int nchars = ( max_y - min_y + 1 ) * ( max_x - min_x + 1 );
+
+ while( nchars > 0 ) {
+ *to++ = ' ' | 0x0700;
+ nchars -= 1;
+ }
+}
+
+
+void cio_scroll( unsigned int lines ) {
+ unsigned short *from;
+ unsigned short *to;
+ int nchars = scroll_max_x - scroll_min_x + 1;
+ int line, c;
+
+ /*
+ ** If # of lines is the whole scrolling region or more, just clear.
+ */
+ if( lines > scroll_max_y - scroll_min_y ) {
+ cio_clearscroll();
+ curr_x = scroll_min_x;
+ curr_y = scroll_min_y;
+ setcursor();
+ return;
+ }
+
+ /*
+ ** Must copy it line by line.
+ */
+ for( line = scroll_min_y; line <= scroll_max_y - lines; line += 1 ) {
+ from = VIDEO_ADDR( scroll_min_x, line + lines );
+ to = VIDEO_ADDR( scroll_min_x, line );
+ for( c = 0; c < nchars; c += 1 ) {
+ *to++ = *from++;
+ }
+ }
+
+ for( ; line <= scroll_max_y; line += 1 ) {
+ to = VIDEO_ADDR( scroll_min_x, line );
+ for( c = 0; c < nchars; c += 1 ) {
+ *to++ = ' ' | 0x0700;
+ }
+ }
+}
+
+static int mypad( int x, int y, int extra, int padchar ) {
+ while( extra > 0 ) {
+ if( x != -1 || y != -1 ) {
+ cio_putchar_at( x, y, padchar );
+ x += 1;
+ }
+ else {
+ cio_putchar( padchar );
+ }
+ extra -= 1;
+ }
+ return x;
+}
+
+static int mypadstr( int x, int y, char *str, int len, int width,
+ int leftadjust, int padchar ) {
+ int extra;
+
+ if( len < 0 ) {
+ len = strlen( str );
+ }
+ extra = width - len;
+ if( extra > 0 && !leftadjust ) {
+ x = mypad( x, y, extra, padchar );
+ }
+ if( x != -1 || y != -1 ) {
+ cio_puts_at( x, y, str );
+ x += len;
+ }
+ else {
+ cio_puts( str );
+ }
+ if( extra > 0 && leftadjust ) {
+ x = mypad( x, y, extra, padchar );
+ }
+ return x;
+}
+
+static void do_printf( int x, int y, char **f ) {
+ char *fmt = *f;
+ int *ap;
+ char buf[ 12 ];
+ char ch;
+ char *str;
+ int leftadjust;
+ int width;
+ int len;
+ int padchar;
+
+ /*
+ ** Get characters from the format string and process them
+ */
+
+ ap = (int *)( f + 1 );
+
+ while( (ch = *fmt++) != '\0' ) {
+
+ /*
+ ** Is it the start of a format code?
+ */
+
+ if( ch == '%' ) {
+
+ /*
+ ** Yes, get the padding and width options (if there).
+ ** Alignment must come at the beginning, then fill,
+ ** then width.
+ */
+
+ leftadjust = 0;
+ padchar = ' ';
+ width = 0;
+
+ ch = *fmt++;
+
+ if( ch == '-' ) {
+ leftadjust = 1;
+ ch = *fmt++;
+ }
+
+ if( ch == '0' ) {
+ padchar = '0';
+ ch = *fmt++;
+ }
+
+ while( ch >= '0' && ch <= '9' ) {
+ width *= 10;
+ width += ch - '0';
+ ch = *fmt++;
+ }
+
+ /*
+ ** What data type do we have?
+ */
+ switch( ch ) {
+
+ case 'c':
+ // ch = *( (int *)ap )++;
+ ch = *ap++;
+ buf[ 0 ] = ch;
+ buf[ 1 ] = '\0';
+ x = mypadstr( x, y, buf, 1, width, leftadjust, padchar );
+ break;
+
+ case 'd':
+ // len = cvtdec( buf, *( (int *)ap )++ );
+ len = cvtdec( buf, *ap++ );
+ x = mypadstr( x, y, buf, len, width, leftadjust, padchar );
+ break;
+
+ case 's':
+ // str = *( (char **)ap )++;
+ str = (char *) (*ap++);
+ x = mypadstr( x, y, str, -1, width, leftadjust, padchar );
+ break;
+
+ case 'x':
+ // len = cvthex( buf, *( (int *)ap )++ );
+ len = cvthex( buf, *ap++ );
+ x = mypadstr( x, y, buf, len, width, leftadjust, padchar );
+ break;
+
+ case 'o':
+ // len = cvtoct( buf, *( (int *)ap )++ );
+ len = cvtoct( buf, *ap++ );
+ x = mypadstr( x, y, buf, len, width, leftadjust, padchar );
+ break;
+
+ case 'u':
+ len = cvtuns( buf, *ap++ );
+ x = mypadstr( x, y, buf, len, width, leftadjust, padchar );
+ break;
+
+ }
+ } else {
+
+ /*
+ ** No - just print it normally.
+ */
+
+ if( x != -1 || y != -1 ) {
+ cio_putchar_at( x, y, ch );
+ switch( ch ) {
+ case '\n':
+ y += 1;
+ /* FALL THRU */
+
+ case '\r':
+ x = scroll_min_x;
+ break;
+
+ default:
+ x += 1;
+ }
+ }
+ else {
+ cio_putchar( ch );
+ }
+ }
+ }
+}
+
+void cio_printf_at( unsigned int x, unsigned int y, char *fmt, ... ) {
+ do_printf( x, y, &fmt );
+}
+
+void cio_printf( char *fmt, ... ) {
+ do_printf( -1, -1, &fmt );
+}
+
+/*
+** These are the "standard" IBM AT "Set 1" keycodes.
+*/
+
+static unsigned char scan_code[ 2 ][ 128 ] = {
+ { // unshifted characters
+/* 00-07 */ '\377', '\033', '1', '2', '3', '4', '5', '6',
+/* 08-0f */ '7', '8', '9', '0', '-', '=', '\b', '\t',
+/* 10-17 */ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+/* 18-1f */ 'o', 'p', '[', ']', '\n', '\377', 'a', 's',
+/* 20-27 */ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+/* 28-2f */ '\'', '`', '\377', '\\', 'z', 'x', 'c', 'v',
+/* 30-37 */ 'b', 'n', 'm', ',', '.', '/', '\377', '*',
+/* 38-3f */ '\377', ' ', '\377', '\377', '\377', '\377', '\377', '\377',
+/* 40-47 */ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '7',
+/* 48-4f */ '8', '9', '-', '4', '5', '6', '+', '1',
+/* 50-57 */ '2', '3', '0', '.', '\377', '\377', '\377', '\377',
+/* 58-5f */ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377',
+/* 60-67 */ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377',
+/* 68-6f */ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377',
+/* 70-77 */ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377',
+/* 78-7f */ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377'
+ },
+
+ { // shifted characters
+/* 00-07 */ '\377', '\033', '!', '@', '#', '$', '%', '^',
+/* 08-0f */ '&', '*', '(', ')', '_', '+', '\b', '\t',
+/* 10-17 */ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+/* 18-1f */ 'O', 'P', '{', '}', '\n', '\377', 'A', 'S',
+/* 20-27 */ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+/* 28-2f */ '"', '~', '\377', '|', 'Z', 'X', 'C', 'V',
+/* 30-37 */ 'B', 'N', 'M', '<', '>', '?', '\377', '*',
+/* 38-3f */ '\377', ' ', '\377', '\377', '\377', '\377', '\377', '\377',
+/* 40-47 */ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '7',
+/* 48-4f */ '8', '9', '-', '4', '5', '6', '+', '1',
+/* 50-57 */ '2', '3', '0', '.', '\377', '\377', '\377', '\377',
+/* 58-5f */ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377',
+/* 60-67 */ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377',
+/* 68-6f */ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377',
+/* 70-77 */ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377',
+/* 78-7f */ '\377', '\377', '\377', '\377', '\377', '\377', '\377', '\377'
+ }
+};
+
+/*
+** Scan code masks
+*/
+
+// 'release' bit
+#define REL_BIT 0x80
+#define CODE_BITS 0x7f
+
+#define IS_PRESS(c) (((c) & REL_BIT) == 0)
+#define IS_RELEASE(c) (((c) & REL_BIT) != 0)
+
+/*
+** Scan codes for some special characters
+*/
+
+// escape code - followed by another code byte
+#define SCAN_ESC 0xe0
+
+// shift keys: press, release
+#define L_SHIFT_DN 0x2a
+#define R_SHIFT_DN 0x36
+#define L_SHIFT_UP 0xaa
+#define R_SHIFT_UP 0xb6
+
+// control keys
+#define L_CTRL_DN 0x1d
+#define L_CTRL_UP 0x9d
+
+/*
+** I/O communication constants
+*/
+#define KBD_DATA 0x60
+#define KBD_STATUS 0x64
+#define READY 0x1
+
+/*
+** Circular buffer for input characters. Characters are inserted at
+** next_space, and are removed at next_char. Buffer is empty if
+** these are equal.
+*/
+#define C_BUFSIZE 200
+
+static char input_buffer[ C_BUFSIZE ];
+static volatile char *next_char = input_buffer;
+static volatile char *next_space = input_buffer;
+
+static volatile char *increment( volatile char *pointer ) {
+ if( ++pointer >= input_buffer + C_BUFSIZE ) {
+ pointer = input_buffer;
+ }
+ return pointer;
+}
+
+static int input_scan_code( int code ) {
+ static int shift = 0;
+ static int ctrl_mask = BMASK8;
+ int rval = -1;
+
+ /*
+ ** Do the shift processing
+ */
+ code &= BMASK8;
+ switch( code ) {
+ case L_SHIFT_DN:
+ case R_SHIFT_DN:
+ shift = 1;
+ break;
+
+ case L_SHIFT_UP:
+ case R_SHIFT_UP:
+ shift = 0;
+ break;
+
+ case L_CTRL_DN:
+ ctrl_mask = BMASK5;
+ break;
+
+ case L_CTRL_UP:
+ ctrl_mask = BMASK8;
+ break;
+
+ default:
+ /*
+ ** Process ordinary characters only on the press (to handle
+ ** autorepeat). Ignore undefined scan codes.
+ */
+ if( IS_PRESS(code) ) {
+ code = scan_code[ shift ][ (int)code ];
+ if( code != '\377' ) {
+ volatile char *next = increment( next_space );
+
+ /*
+ ** Store character only if there's room
+ */
+ rval = code & ctrl_mask;
+ if( next != next_char ) {
+ *next_space = code & ctrl_mask;
+ next_space = next;
+ }
+ }
+ }
+ }
+ return( rval );
+}
+
+static void keyboard_isr( int vector, int code ) {
+
+ int data = inb( KBD_DATA );
+ int val = input_scan_code( data );
+
+ // if there is a notification function, call it
+ if( val != -1 && notify )
+ notify( val );
+
+ outb( PIC1_CMD, PIC_EOI );
+}
+
+int cio_getchar( void ) {
+ char c;
+ int interrupts_enabled = r_eflags() & EFL_IF;
+
+ while( next_char == next_space ) {
+ if( !interrupts_enabled ) {
+ /*
+ ** Must read the next keystroke ourselves.
+ */
+ while( ( inb( KBD_STATUS ) & READY ) == 0 ) {
+ ;
+ }
+ (void) input_scan_code( inb( KBD_DATA ) );
+ }
+ }
+
+ c = *next_char & BMASK8;
+ next_char = increment( next_char );
+ if( c != EOT ) {
+ cio_putchar( c );
+ }
+ return c;
+}
+
+int cio_gets( char *buffer, unsigned int size ) {
+ char ch;
+ int count = 0;
+
+ while( size > 1 ) {
+ ch = cio_getchar();
+ if( ch == EOT ) {
+ break;
+ }
+ *buffer++ = ch;
+ count += 1;
+ size -= 1;
+ if( ch == '\n' ) {
+ break;
+ }
+ }
+ *buffer = '\0';
+ return count;
+}
+
+int cio_input_queue( void ) {
+ int n_chars = next_space - next_char;
+
+ if( n_chars < 0 ) {
+ n_chars += C_BUFSIZE;
+ }
+ return n_chars;
+}
+
+/*
+** Initialization routines
+*/
+void cio_init( void (*fcn)(int) ) {
+ /*
+ ** Screen dimensions
+ */
+ min_x = SCREEN_MIN_X;
+ min_y = SCREEN_MIN_Y;
+ max_x = SCREEN_MAX_X;
+ max_y = SCREEN_MAX_Y;
+
+ /*
+ ** Scrolling region
+ */
+ scroll_min_x = SCREEN_MIN_X;
+ scroll_min_y = SCREEN_MIN_Y;
+ scroll_max_x = SCREEN_MAX_X;
+ scroll_max_y = SCREEN_MAX_Y;
+
+ /*
+ ** Initial cursor location
+ */
+ curr_y = min_y;
+ curr_x = min_x;
+ setcursor();
+
+ /*
+ ** Notification function (or NULL)
+ */
+ notify = fcn;
+
+ /*
+ ** Set up the interrupt handler for the keyboard
+ */
+ install_isr( VEC_KBD, keyboard_isr );
+}
+
+#ifdef SA_DEBUG
+int main() {
+ cio_printf( "%d\n", 123 );
+ cio_printf( "%d\n", -123 );
+ cio_printf( "%d\n", 0x7fffffff );
+ cio_printf( "%d\n", 0x80000001 );
+ cio_printf( "%d\n", 0x80000000 );
+ cio_printf( "x%14dy\n", 0x80000000 );
+ cio_printf( "x%-14dy\n", 0x80000000 );
+ cio_printf( "x%014dy\n", 0x80000000 );
+ cio_printf( "x%-014dy\n", 0x80000000 );
+ cio_printf( "%s\n", "xyz" );
+ cio_printf( "|%10s|\n", "xyz" );
+ cio_printf( "|%-10s|\n", "xyz" );
+ cio_printf( "%c\n", 'x' );
+ cio_printf( "|%4c|\n", 'y' );
+ cio_printf( "|%-4c|\n", 'y' );
+ cio_printf( "|%04c|\n", 'y' );
+ cio_printf( "|%-04c|\n", 'y' );
+ cio_printf( "|%3d|\n", 5 );
+ cio_printf( "|%3d|\n", 54321 );
+ cio_printf( "%x\n", 0x123abc );
+ cio_printf( "|%04x|\n", 20 );
+ cio_printf( "|%012x|\n", 0xfedcba98 );
+ cio_printf( "|%-012x|\n", 0x76543210 );
+}
+
+int curr_x, curr_y, max_x, max_y;
+#endif