/********************************************************************* fichier stdio.c Written Alain greiner & Nicolas Pouillon Date : 19/10/2009 These function implement the drivers for the SoCLib peripherals. *********************************************************************/ #include #include "stdio.h" #include "timer.h" #include "tty.h" #include "gcd.h" #include "icu.h" #include "dma.h" #include "block_device.h" /********************************************************************* We define a generic C function to implement all system calls. *********************************************************************/ inline int sys_call( int call_no, int arg_0, int arg_1, int arg_2, int arg_3 ) { register int reg_no_and_output asm("v0") = call_no; register int reg_a0 asm("a0") = arg_0; register int reg_a1 asm("a1") = arg_1; register int reg_a2 asm("a2") = arg_2; register int reg_a3 asm("a3") = arg_3; asm volatile( "syscall" : "=r" (reg_no_and_output) // arguments de sortie : "r" (reg_a0), // arguments d'entrée "r" (reg_a1), "r" (reg_a2), "r" (reg_a3), "r" (reg_no_and_output) : "memory", // ressources modifiees: "at", "v1", "ra", // Ces registres persistants seront sauvegardes "t0", // sur la pile par le compilateur "t1", // seulement s'ils contiennent des donnees "t2", // calculees par la fonction effectuant le syscall, "t3", // et que ces valeurs sont reutilisees par cette "t4", // fonction au retour du syscall. "t5", "t6", "t7", "t8", "t9" ); return reg_no_and_output; } /******************************************************************** procid() Returns the processor ident. ********************************************************************/ int procid() { return sys_call(SYSCALL_PROCID, 0, 0, 0, 0); } /******************************************************************** proctime() Returns the local processor time. ********************************************************************/ int proctime() { return sys_call(SYSCALL_PROCTIME, 0, 0, 0, 0); } /******************************************************************** procnumber() Returns the number of processors controled by the system. ********************************************************************/ int procnumber() { return sys_call(SYSCALL_PROCNUMBER, 0, 0, 0, 0); } /******************************************************************** exit() Exit the program with a TTY message, and enter an infinite loop... ********************************************************************/ int exit() { int proc_index = procid(); return sys_call(SYSCALL_EXIT, proc_index, 0, 0, 0); } /******************************************************************** rand() Returns a pseudo-random value derived from the processor cycle count. This value is comprised between 0 & 65535. ********************************************************************/ int rand() { int x = sys_call(SYSCALL_PROCTIME, 0, 0, 0, 0); if((x & 0xF) > 7) return (x*x & 0xFFFF); else return (x*x*x & 0xFFFF); } /************************************************************************* MULTI-TTY ************************************************************************** tty_putc() Display a single ascii character on a terminal. The terminal index is implicitely defined by the processor ID. (and by the task ID in case of multi-tasking) It doesn't use the TTY_PUT_IRQ interrupt, and the associated kernel buffer. This function returns 0 in case of success. ******************************i*******************************************/ int tty_putc(char byte) { return sys_call(SYSCALL_TTY_WRITE, (int)(&byte), 1, 0,0); } /************************************************************************* tty_puts() Display a string on a terminal. The terminal index is implicitely defined by the processor ID. (and by the task ID in case of multi-tasking) The string must be terminated by a NUL character. It doesn't use the TTY_PUT_IRQinterrupt, and the associated kernel buffer. This function returns 0 in case of success. **************************************************************************/ int tty_puts(char* string) { int length = 0; while (string[length] != 0) { length++; } return sys_call(SYSCALL_TTY_WRITE, (int)string, length, 0,0); } /************************************************************************* tty_putw() Display the value of a 32 bits word (decimal characters). The terminal index is implicitely defined by the processor ID. (and by pthe task ID in case of multi-tasking) It doesn't use the TTY_PUT_IRQ interrupt, and the associated kernel buffer. This function returns 0 in case of success. **************************************************************************/ int tty_putw(int val) { char buf[10]; int i; for( i=0 ; i<10 ; i++ ) { buf[9-i] = (val % 10) + 0x30; val = val / 10; } return sys_call(SYSCALL_TTY_WRITE, (int)buf, 10, 0,0); } /******************************************************************** tty_getc() Fetch a single ascii character from a terminal. The terminal index is implicitely defined by the processor ID. (and by the task ID in case of multi-tasking) It doesn't use the IRQ_GET interrupt, and the associated kernel buffer. It is a blocking function that returns 0 if a valid char is stored in the buffer, and returns -1 in case of error. ********************************************************************/ int tty_getc(char* buf) { int ret = 0; while( ret == 0 ) { ret = sys_call(SYSCALL_TTY_READ, (int)buf, 1, 0,0); if ((ret < 0) || (ret > 1)) return -1; // return error } return 0; // return ok } /******************************************************************** tty_getc_irq() Fetch a single ascii character from a terminal. The terminal index is implicitely defined by the processor ID. (and by the task ID in case of multi-tasking) It uses the IRQ_GET interrupt, and the associated kernel buffer. It is a blocking function that returns 0 if a valid char is stored in the buffer, and returns -1 in case of error. ********************************************************************/ int tty_getc_irq(char* buf) { int ret = 0; while( ret == 0 ) { ret = sys_call(SYSCALL_TTY_READ_IRQ, (int)buf, 1, 0,0); if ((ret < 0) || (ret > 1)) return -1; // return error } return 0; // return ok } /******************************************************************** tty_gets_irq() Fetch a string from a terminal to a bounded length buffer. The terminal index is implicitely defined by the processor ID. (and by the task ID in case of multi-tasking) It uses the TTY_GET_IRQ interrupt, anf the associated kernel buffer. It is a blocking function that returns 0 if a valid string is stored in the buffer, and returns -1 in case of error. Up to (bufsize - 1) characters (including the non printable characters) will be copied into buffer, and the string is always completed by a NUL character. The character is interpreted, as the function close the string with a NUL character if is read. The character is interpreted, and the corresponding character(s) are removed from the target buffer. ********************************************************************/ int tty_gets_irq(char* buf, int bufsize) { int ret; unsigned char byte; unsigned int index = 0; while( index < (bufsize-1) ) { ret = sys_call(SYSCALL_TTY_READ_IRQ, (int)(&byte), 1, 0,0); if ((ret < 0) || (ret > 1)) return -1; // return error else if ( ret == 1 ) // valid character { if ( byte == 0x0A ) break; // LF else if ((byte == 0x7F) && (index>0)) index--; // DEL else { buf[index] = byte; index++; } } } // end while buf[index] = 0; return 0; // return ok } /******************************************************************** tty_getw_irq() Fetch a string of decimal characters (most significant digit first) to build a 32 bits unsigned int. The terminal index is implicitely defined by the processor ID. (and by the task ID in case of multi-tasking) This is a blocking function that returns 0 if a valid unsigned int is stored in the buffer, and returns -1 in case of error. It uses the TTY_GET_IRQ interrupt, anf the associated kernel buffer. The non-blocking system function _tty_read_irq is called several times, and the decimal characters are written in a 32 characters buffer until a character is read. The character is interpreted, and previous characters can be cancelled. All others characters are ignored. When the character is received, the string is converted to an unsigned int value. If the number of decimal digit is too large for the 32 bits range, the zero value is returned. ********************************************************************/ int tty_getw_irq(int* word_buffer) { unsigned char buf[32]; unsigned char byte; unsigned int save = 0; unsigned int val = 0; unsigned int done = 0; unsigned int overflow = 0; unsigned int max = 0; unsigned int i; int ret; while(done == 0) { ret = sys_call(SYSCALL_TTY_READ_IRQ, (int)(&byte), 1, 0,0); if ((ret < 0) || (ret > 1)) return -1; // return error if ( ret == 1 ) // get one character { if (( byte > 0x2F) && (byte < 0x3A)) // decimal character { buf[max] = byte; max++; tty_putc(byte); } else if ( (byte == 0x0A) || (byte == 0x0D) ) // LF or CR character { done = 1; } else if ( byte == 0x7F ) // DEL character { if (max > 0) { max--; // cancel the character tty_putc(0x08); tty_putc(0x20); tty_putc(0x08); } } if ( max == 32 ) // decimal string overflow { for( i=0 ; i