Changeset 622 for trunk/softs
- Timestamp:
- Jan 29, 2014, 9:30:38 AM (11 years ago)
- Location:
- trunk/softs/giet_tsar
- Files:
-
- 3 added
- 10 deleted
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/softs/giet_tsar/block_device.h
r158 r622 37 37 BLOCK_DEVICE_SIZE, 38 38 BLOCK_DEVICE_BLOCK_SIZE, 39 BLOCK_DEVICE_BUFFER_EXT, 39 40 }; 40 41 -
trunk/softs/giet_tsar/stdio.c
r158 r622 1 /********************************************************************* 2 fichier stdio.c 3 Written Alain greiner & Nicolas Pouillon 4 Date : 19/10/2009 5 6 These function implement the drivers for the SoCLib peripherals. 7 *********************************************************************/ 8 9 #include <stdarg.h> 1 //////////////////////////////////////////////////////////////////////////////////////// 2 // File : stdio.c 3 // Written by Alain Greiner 4 // Date : janvier 2014 5 // 6 // This file define varions functions that can be used by applications to access 7 // peripherals, for the TSAR multi-processors multi_clusters architecture. 8 // There is NO separation between application code and system code, as the 9 // application are running in kernel mode without system calls. 10 // This basic GIET does not support virtual memory, and does not support multi-tasking. 11 // 12 // The supported peripherals are: 13 // - the SoClib multi_tty 14 // - The SoCLib frame_buffer 15 // - The SoCLib block_device 16 // 17 // The following parameters must be defined in the hard_config.h file. 18 // - X_SIZE : number of clusters in a row 19 // - Y_SIZE : number of clusters in a column 20 // - X_WIDTH : number of bits for X field in proc_id 21 // - Y_WIDTH : number of bits for Y field in proc_id 22 // - NB_PROCS_MAX : max number of processor per cluster 23 // - NB_TTY_CHANNELS : max number of TTY channels 24 // 25 // The follobing base addresses must be defined in the ldscript 26 // - seg_tty_base 27 // - seg_fbf_base 28 // - seg_ioc_base 29 //////////////////////////////////////////////////////////////////////////////////////// 10 30 11 31 #include "stdio.h" 12 32 13 #include "timer.h" 14 #include "tty.h" 15 #include "gcd.h" 16 #include "icu.h" 17 #include "dma.h" 18 #include "block_device.h" 19 20 /********************************************************************* 21 We define a generic C function to implement all system calls. 22 *********************************************************************/ 23 inline int sys_call( int call_no, 24 int arg_0, 25 int arg_1, 26 int arg_2, 27 int arg_3 ) 28 { 29 register int reg_no_and_output asm("v0") = call_no; 30 register int reg_a0 asm("a0") = arg_0; 31 register int reg_a1 asm("a1") = arg_1; 32 register int reg_a2 asm("a2") = arg_2; 33 register int reg_a3 asm("a3") = arg_3; 34 35 asm volatile( 36 "syscall" 37 : "=r" (reg_no_and_output) // arguments de sortie 38 : "r" (reg_a0), // arguments d'entrée 39 "r" (reg_a1), 40 "r" (reg_a2), 41 "r" (reg_a3), 42 "r" (reg_no_and_output) 43 : "memory", // ressources modifiees: 44 "at", 45 "v1", 46 "ra", // Ces registres persistants seront sauvegardes 47 "t0", // sur la pile par le compilateur 48 "t1", // seulement s'ils contiennent des donnees 49 "t2", // calculees par la fonction effectuant le syscall, 50 "t3", // et que ces valeurs sont reutilisees par cette 51 "t4", // fonction au retour du syscall. 52 "t5", 53 "t6", 54 "t7", 55 "t8", 56 "t9" 57 ); 58 return reg_no_and_output; 59 } 60 61 /******************************************************************** 62 procid() 63 Returns the processor ident. 64 ********************************************************************/ 65 int procid() 66 { 67 return sys_call(SYSCALL_PROCID, 0, 0, 0, 0); 68 } 69 /******************************************************************** 70 proctime() 71 Returns the local processor time. 72 ********************************************************************/ 73 int proctime() 74 { 75 return sys_call(SYSCALL_PROCTIME, 0, 0, 0, 0); 76 } 77 /******************************************************************** 78 procnumber() 79 Returns the number of processors controled by the system. 80 ********************************************************************/ 81 int procnumber() 82 { 83 return sys_call(SYSCALL_PROCNUMBER, 0, 0, 0, 0); 84 } 85 /******************************************************************** 86 exit() 87 Exit the program with a TTY message, and enter an infinite loop... 88 ********************************************************************/ 89 int exit() 90 { 91 int proc_index = procid(); 92 return sys_call(SYSCALL_EXIT, proc_index, 0, 0, 0); 93 } 94 /******************************************************************** 95 rand() 96 Returns a pseudo-random value derived from the processor cycle count. 97 This value is comprised between 0 & 65535. 98 ********************************************************************/ 99 int rand() 100 { 101 int x = sys_call(SYSCALL_PROCTIME, 0, 0, 0, 0); 102 if((x & 0xF) > 7) 103 return (x*x & 0xFFFF); 33 #define NB_LOCKS 256 34 #define NB_BARRIERS 16 35 36 #define in_drivers __attribute__((section (".drivers"))) 37 #define in_unckdata __attribute__((section (".unckdata"))) 38 39 ////////////////////////////////////////////////////////////// 40 // various informations that must be defined in ldscript 41 ////////////////////////////////////////////////////////////// 42 43 struct plouf; 44 45 extern struct plouf seg_tty_base; 46 extern struct plouf seg_fbf_base; 47 extern struct plouf seg_ioc_base; 48 extern struct plouf seg_mmc_base; 49 50 //////////////////////////////////////////////////////////////////////////////////////// 51 // Global uncachable variables for synchronization between drivers and ISRs 52 //////////////////////////////////////////////////////////////////////////////////////// 53 54 in_unckdata int volatile _ioc_lock = 0; 55 in_unckdata int volatile _ioc_done = 0; 56 in_unckdata int volatile _ioc_status; 57 58 in_unckdata char volatile _tty_get_buf[NB_TTY_CHANNELS]; 59 in_unckdata int volatile _tty_get_full[NB_TTY_CHANNELS] = { [0 ... NB_TTY_CHANNELS-1] = 0 }; 60 61 //////////////////////////////////////////////////////////////////////////////////////// 62 // Global uncachable variables for inter-task barriers 63 //////////////////////////////////////////////////////////////////////////////////////// 64 65 in_unckdata int volatile _barrier_value[NB_BARRIERS] = { [0 ... NB_BARRIERS-1] = 0 }; 66 in_unckdata int volatile _barrier_count[NB_BARRIERS] = { [0 ... NB_BARRIERS-1] = 0 }; 67 in_unckdata int volatile _barrier_lock[NB_BARRIERS] = { [0 ... NB_BARRIERS-1] = 0 }; 68 69 //////////////////////////////////////////////////////////////////////////////////////// 70 // Global uncachable variables for spin_locks using LL/C instructions 71 //////////////////////////////////////////////////////////////////////////////////////// 72 73 in_unckdata int volatile _spin_lock[NB_LOCKS] = { [0 ... NB_LOCKS-1] = 0 }; 74 75 //////////////////////////////////////////////////////////////////////////////////////// 76 // Taken from MutekH. 77 //////////////////////////////////////////////////////////////////////////////////////// 78 in_drivers void* _memcpy( void* _dst, 79 const void* _src, 80 unsigned int size ) 81 { 82 unsigned int *dst = _dst; 83 const unsigned int *src = _src; 84 if ( ! ((unsigned int)dst & 3) && ! ((unsigned int)src & 3) ) 85 { 86 while (size > 3) 87 { 88 *dst++ = *src++; 89 size -= 4; 90 } 91 } 92 93 unsigned char *cdst = (unsigned char*)dst; 94 unsigned char *csrc = (unsigned char*)src; 95 96 while (size--) 97 { 98 *cdst++ = *csrc++; 99 } 100 return _dst; 101 } 102 103 //////////////////////////////////////////////////////////////////////////////////////// 104 // Access CP0 and returns processor ident 105 // No more than 1024 processors... 106 //////////////////////////////////////////////////////////////////////////////////////// 107 in_drivers unsigned int _procid() 108 { 109 unsigned int ret; 110 asm volatile( "mfc0 %0, $15, 1": "=r"(ret) ); 111 return (ret & 0x3FF); 112 } 113 //////////////////////////////////////////////////////////////////////////////////////// 114 // Access CP0 and returns processor time 115 //////////////////////////////////////////////////////////////////////////////////////// 116 in_drivers unsigned int _proctime() 117 { 118 unsigned int ret; 119 asm volatile( "mfc0 %0, $9": "=r"(ret) ); 120 return ret; 121 } 122 //////////////////////////////////////////////////////////////////////////////////////// 123 // Returns the number of processsors controled by the GIET 124 //////////////////////////////////////////////////////////////////////////////////////// 125 in_drivers unsigned int _procnumber() 126 { 127 return (unsigned int)(NB_PROCS_MAX * X_SIZE * Y_SIZE); 128 } 129 //////////////////////////////////////////////////////////////////////////////////////// 130 // Access CP0 and mask IRQs 131 //////////////////////////////////////////////////////////////////////////////////////// 132 in_drivers void _it_mask() 133 { 134 int tmp; 135 asm volatile("mfc0 %0, $12" : "=r" (tmp) ); 136 asm volatile("ori %0, %0, 1" : "=r" (tmp) ); 137 asm volatile("mtc0 %0, $12" : "=r" (tmp) ); 138 } 139 //////////////////////////////////////////////////////////////////////////////////////// 140 // Access CP0 and enable IRQs 141 //////////////////////////////////////////////////////////////////////////////////////// 142 in_drivers void _it_enable() 143 { 144 int tmp; 145 asm volatile("mfc0 %0, $12" : "=r" (tmp) ); 146 asm volatile("addi %0, %0, -1" : "=r" (tmp) ); 147 asm volatile("mtc0 %0, $12" : "=r" (tmp) ); 148 } 149 ////////////////////////////////////////////////////////////////////// 150 // Invalidate all cache lines corresponding to a memory buffer. 151 // This is used by the block_device driver. 152 ///////////////////////////////////////////////////////////////////////// 153 in_drivers void _dcache_buf_invalidate(const void * buffer, size_t size) 154 { 155 size_t i; 156 size_t dcache_line_size; 157 158 // retrieve dcache line size from config register (bits 12:10) 159 asm volatile("mfc0 %0, $16, 1" : "=r" (dcache_line_size)); 160 161 dcache_line_size = 2 << ((dcache_line_size>>10) & 0x7); 162 163 // iterate on lines to invalidate each one of them 164 for ( i=0; i<size; i+=dcache_line_size ) 165 asm volatile(" cache %0, %1" 166 : 167 :"i" (0x11), "R" (*((char*)buffer+i))); 168 } 169 170 /////////////////////////////////////////////////////////////////////////////////////// 171 // Exit (suicide) after printing message on a TTY terminal. 172 /////////////////////////////////////////////////////////////////////////////////////// 173 in_drivers void _exit() 174 { 175 unsigned int proc_id = _procid(); 176 unsigned int l = proc_id % NB_PROCS_MAX; 177 unsigned int x = (proc_id / NB_PROCS_MAX) >> Y_WIDTH; 178 unsigned int y = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1); 179 180 _tty_printf("\n\n!!! Exit Processor (%d,%d,%d) !!!\n", x, y, l ); 181 182 while(1) asm volatile("nop"); // infinite loop... 183 } 184 185 ///////////////////////////////////////////////////////////////////////// 186 // convert a 32 bits unsigned int to a string of 10 decimal characters. 187 ///////////////////////////////////////////////////////////////////////// 188 in_drivers void _itoa_dec(unsigned val, char* buf) 189 { 190 const char DecTab[] = "0123456789"; 191 unsigned int i; 192 for( i=0 ; i<10 ; i++ ) 193 { 194 if( (val!=0) || (i==0) ) buf[9-i] = DecTab[val % 10]; 195 else buf[9-i] = 0x20; 196 val /= 10; 197 } 198 } 199 ////////////////////////////////////////////////////////////////////////// 200 // convert a 32 bits unsigned int to a string of 8 hexadecimal characters. 201 /////////////////////////////////////////////////////////////////////////// 202 in_drivers void _itoa_hex(unsigned int val, char* buf) 203 { 204 const char HexaTab[] = "0123456789ABCD"; 205 unsigned int i; 206 for( i=0 ; i<8 ; i++ ) 207 { 208 buf[7-i] = HexaTab[val % 16]; 209 val /= 16; 210 } 211 } 212 213 214 /////////////////////////////////////////////////////////////////////////////////////// 215 // VCI MULTI_TTY 216 /////////////////////////////////////////////////////////////////////////////////////// 217 // The total number of TTY terminals is defined by NB_TTY_CHANNELS. 218 // 1. If there is only one terminal, it is supposed to be shared, and used by 219 // all processors: a lock must be taken before display. 220 // 2. If there is several terminals, and the number of processors is smaller 221 // than the number of terminals, there is one terminal per processor, but 222 // the TTY index is not equal to the proc_id, due to cluster indexing policy: 223 // - proc_id = cluster_xy * NB_PROCS_MAX + local_id (with cluster_xy = x << Y_WIDTH + y) 224 // - tty_id = cluster_id * NB_PROCS_MAX + local_id (with cluster_id = x * Y_SIZE + y) 225 // 3. If the computed tty_id is larger than NB_TTY_CHANNELS, an error is returned. 226 /////////////////////////////////////////////////////////////////////////////////////// 227 // Write one or several characters directly from a fixed length user buffer 228 // to the TTY_WRITE register of the TTY controler. 229 // This is a non blocking call : it test the TTY_STATUS register. 230 // If the TTY_STATUS_WRITE bit is set, the transfer stops and the function 231 // returns the number of characters that have been actually written. 232 /////////////////////////////////////////////////////////////////////////////////////// 233 in_drivers int _tty_write( char* buffer, 234 unsigned int length, 235 unsigned int channel ) 236 { 237 char* tty_address; 238 unsigned int base = (unsigned int)&seg_tty_base; 239 unsigned int nwritten = 0; 240 int i; 241 242 tty_address = (char*)(base + channel*TTY_SPAN*4); 243 244 for ( i=0 ; i < length ; i++ ) 245 { 246 if((tty_address[TTY_STATUS*4] & 0x2) == 0x2) break; 247 else 248 { 249 tty_address[TTY_WRITE*4] = buffer[i]; // write character 250 nwritten++; 251 } 252 } 253 254 return nwritten; 255 } 256 /////////////////////////////////////////////////////////////////////////////////////// 257 // Fetch one character directly from the TTY_READ register of the TTY controler, 258 // and writes this character to the user buffer. 259 // This is a non blocking call : it returns 0 if the register is empty, 260 // and returns 1 if the register is full. 261 /////////////////////////////////////////////////////////////////////////////////////// 262 in_drivers int _tty_read( char* buffer, 263 unsigned int channel ) 264 { 265 char* tty_address; 266 unsigned int base = (unsigned int)&seg_tty_base; 267 268 tty_address = (char*)(base + channel*TTY_SPAN*4); 269 270 if((tty_address[TTY_STATUS*4] & 0x1) == 0x1) 271 { 272 buffer[0] = tty_address[TTY_READ*4]; 273 return 1; 274 } 104 275 else 105 return (x*x*x & 0xFFFF); 106 } 107 108 /************************************************************************* 109 MULTI-TTY 110 ************************************************************************** 111 tty_putc() 112 Display a single ascii character on a terminal. 113 The terminal index is implicitely defined by the processor ID. 114 (and by the task ID in case of multi-tasking) 115 It doesn't use the TTY_PUT_IRQ interrupt, and the associated kernel buffer. 116 This function returns 0 in case of success. 117 ******************************i*******************************************/ 118 int tty_putc(char byte) 119 { 120 return sys_call(SYSCALL_TTY_WRITE, 121 (int)(&byte), 122 1, 123 0,0); 124 } 125 /************************************************************************* 126 tty_puts() 127 Display a string on a terminal. 128 The terminal index is implicitely defined by the processor ID. 129 (and by the task ID in case of multi-tasking) 130 The string must be terminated by a NUL character. 131 It doesn't use the TTY_PUT_IRQinterrupt, and the associated kernel buffer. 132 This function returns 0 in case of success. 133 **************************************************************************/ 134 int tty_puts(char* string) 276 { 277 return 0; 278 } 279 } 280 ////////////////////////////////////////////////////////////////////////////// 281 // This function displays a string on TTY0. 282 // The string must be terminated by a NUL character. 283 ////////////////////////////////////////////////////////////////////////////// 284 in_drivers void _tty_puts( char* string ) 135 285 { 136 286 int length = 0; 137 while (string[length] != 0) { 138 length++; 139 } 140 return sys_call(SYSCALL_TTY_WRITE, 141 (int)string, 142 length, 143 0,0); 144 } 145 /************************************************************************* 146 tty_putw() 147 Display the value of a 32 bits word (decimal characters). 148 The terminal index is implicitely defined by the processor ID. 149 (and by pthe task ID in case of multi-tasking) 150 It doesn't use the TTY_PUT_IRQ interrupt, and the associated kernel buffer. 151 This function returns 0 in case of success. 152 **************************************************************************/ 153 int tty_putw(int val) 154 { 155 char buf[10]; 156 int i; 157 for( i=0 ; i<10 ; i++ ) { 158 buf[9-i] = (val % 10) + 0x30; 159 val = val / 10; 160 } 161 return sys_call(SYSCALL_TTY_WRITE, 162 (int)buf, 163 10, 164 0,0); 165 } 166 /******************************************************************** 167 tty_getc() 168 Fetch a single ascii character from a terminal. 169 The terminal index is implicitely defined by the processor ID. 170 (and by the task ID in case of multi-tasking) 171 It doesn't use the IRQ_GET interrupt, and the associated kernel buffer. 172 It is a blocking function that returns 0 if a valid char is stored 173 in the buffer, and returns -1 in case of error. 174 ********************************************************************/ 175 int tty_getc(char* buf) 176 { 177 int ret = 0; 178 while( ret == 0 ) 179 { 180 ret = sys_call(SYSCALL_TTY_READ, 181 (int)buf, 182 1, 183 0,0); 184 if ((ret < 0) || (ret > 1)) return -1; // return error 185 } 186 return 0; // return ok 187 } 188 /******************************************************************** 189 tty_getc_irq() 190 Fetch a single ascii character from a terminal. 191 The terminal index is implicitely defined by the processor ID. 192 (and by the task ID in case of multi-tasking) 193 It uses the IRQ_GET interrupt, and the associated kernel buffer. 194 It is a blocking function that returns 0 if a valid char is stored 195 in the buffer, and returns -1 in case of error. 196 ********************************************************************/ 197 int tty_getc_irq(char* buf) 198 { 199 int ret = 0; 200 while( ret == 0 ) 201 { 202 ret = sys_call(SYSCALL_TTY_READ_IRQ, 203 (int)buf, 204 1, 205 0,0); 206 if ((ret < 0) || (ret > 1)) return -1; // return error 207 } 208 return 0; // return ok 209 } 210 /******************************************************************** 211 tty_gets_irq() 212 Fetch a string from a terminal to a bounded length buffer. 213 The terminal index is implicitely defined by the processor ID. 214 (and by the task ID in case of multi-tasking) 215 It uses the TTY_GET_IRQ interrupt, anf the associated kernel buffer. 216 It is a blocking function that returns 0 if a valid string is stored 217 in the buffer, and returns -1 in case of error. 218 Up to (bufsize - 1) characters (including the non printable 219 characters) will be copied into buffer, and the string is 220 always completed by a NUL character. 221 The <LF> character is interpreted, as the function close 222 the string with a NUL character if <LF> is read. 223 The <DEL> character is interpreted, and the corresponding 224 character(s) are removed from the target buffer. 225 ********************************************************************/ 226 int tty_gets_irq(char* buf, int bufsize) 227 { 228 int ret; 229 unsigned char byte; 230 unsigned int index = 0; 231 232 while( index < (bufsize-1) ) 233 { 234 ret = sys_call(SYSCALL_TTY_READ_IRQ, 235 (int)(&byte), 236 1, 237 0,0); 238 239 if ((ret < 0) || (ret > 1)) return -1; // return error 240 241 else if ( ret == 1 ) // valid character 242 { 243 if ( byte == 0x0A ) break; // LF 244 else if ((byte == 0x7F) && (index>0)) index--; // DEL 245 else 287 while (string[length] != 0) length++; 288 _tty_write( string, length, 0 ); 289 } 290 291 /////////////////////////////////////////////////////////////////////////////// 292 // This function displays a 32 bits unsigned int as an hexa string on TTY0. 293 /////////////////////////////////////////////////////////////////////////////// 294 in_drivers void _tty_putx(unsigned int val) 295 { 296 static const char HexaTab[] = "0123456789ABCDEF"; 297 char buf[11]; 298 unsigned int c; 299 300 buf[0] = '0'; 301 buf[1] = 'x'; 302 buf[10] = 0; 303 304 for (c = 0; c < 8; c++) 305 { 306 buf[9 - c] = HexaTab[val & 0xF]; 307 val = val >> 4; 308 } 309 _tty_puts( buf ); 310 } 311 312 /////////////////////////////////////////////////////////////////////////////// 313 // This function displays a 32 bits unsigned int as a decimal string on TTY0. 314 /////////////////////////////////////////////////////////////////////////////// 315 in_drivers void _tty_putd( unsigned int val ) 316 { 317 static const char DecTab[] = "0123456789"; 318 char buf[11]; 319 unsigned int i; 320 unsigned int first; 321 322 buf[10] = 0; 323 324 for (i = 0; i < 10; i++) 325 { 326 if ((val != 0) || (i == 0)) 327 { 328 buf[9 - i] = DecTab[val % 10]; 329 first = 9 - i; 330 } 331 else 332 { 333 break; 334 } 335 val /= 10; 336 } 337 _tty_puts( &buf[first] ); 338 } 339 340 ////////////////////////////////////////////////////////////////////////////// 341 // This function try to take the hardwired lock protecting exclusive access 342 // to TTY terminal identified by the channel argument. 343 // It returns only when the lock has been successfully taken. 344 ////////////////////////////////////////////////////////////////////////////// 345 in_drivers void _tty_get_lock( unsigned int channel ) 346 { 347 unsigned int* tty_address = (unsigned int *) &seg_tty_base; 348 while ( tty_address[channel * TTY_SPAN + TTY_CONFIG] ) asm volatile("nop"); 349 } 350 351 ////////////////////////////////////////////////////////////////////////////// 352 // This function releases the hardwired lock protecting exclusive access 353 // to TTY terminal identified by the channel argument. 354 ////////////////////////////////////////////////////////////////////////////// 355 in_drivers void _tty_release_lock( unsigned int channel ) 356 { 357 unsigned int* tty_address = (unsigned int *) &seg_tty_base; 358 tty_address[channel * TTY_SPAN + TTY_CONFIG] = 0; 359 } 360 361 ////////////////////////////////////////////////////////////////////////////// 362 // This function fetch a single ascii character from a terminal 363 // implicitely defined by the processor ID. 364 // It is a blocking function. 365 ////////////////////////////////////////////////////////////////////////////// 366 in_drivers void _tty_getc( char* buf ) 367 { 368 unsigned int proc_id = _procid(); 369 unsigned int channel; 370 unsigned int l; 371 unsigned int x; 372 unsigned int y; 373 374 // compute TTY terminal index 375 if ( NB_TTY_CHANNELS == 1 ) 376 { 377 channel = 0; 378 } 379 else 380 { 381 l = (proc_id % NB_PROCS_MAX); 382 x = (proc_id / NB_PROCS_MAX) >> Y_WIDTH; 383 y = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1); 384 channel = (x * Y_SIZE + y) * NB_PROCS_MAX + l; 385 if (channel >= NB_TTY_CHANNELS ) 386 { 387 _tty_get_lock( 0 ); 388 _tty_puts( "ERROR in _tty_getc()\n" ); 389 _tty_release_lock( 0 ); 390 _exit(); 391 } 392 } 393 394 while( _tty_read( buf, channel ) == 0 ) asm volatile("nop"); 395 } 396 397 ////////////////////////////////////////////////////////////////////////////// 398 // Fetch a string of decimal characters (most significant digit first) 399 // to build a 32 bits unsigned int. 400 // The terminal index is implicitely defined by the processor ID. 401 // This is a blocking function. 402 // The decimal characters are written in a 32 characters buffer 403 // until a <LF> or <CR> character is read. 404 // The <DEL> character is interpreted, and previous characters can be 405 // cancelled. All others characters are ignored. 406 // When the <LF> or <CR> character is received, the string is converted 407 // to an unsigned int value. If the number of decimal digit is too large 408 // for the 32 bits range, the zero value is returned. 409 ////////////////////////////////////////////////////////////////////////////// 410 in_drivers void _tty_getw( unsigned int* word_buffer ) 411 { 412 char buf[32]; 413 char byte; 414 char cancel_string[3] = { 0x08, 0x20, 0x08 }; 415 char zero = 0x30; 416 unsigned int save = 0; 417 unsigned int val = 0; 418 unsigned int done = 0; 419 unsigned int overflow = 0; 420 unsigned int max = 0; 421 unsigned int proc_id = _procid(); 422 unsigned int i; 423 unsigned int channel; 424 unsigned int l; 425 unsigned int x; 426 unsigned int y; 427 428 // compute TTY terminal index 429 if ( NB_TTY_CHANNELS == 1 ) 430 { 431 channel = 0; 432 } 433 else 434 { 435 l = (proc_id % NB_PROCS_MAX); 436 x = (proc_id / NB_PROCS_MAX) >> Y_WIDTH; 437 y = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1); 438 channel = (x * Y_SIZE + y) * NB_PROCS_MAX + l; 439 if (channel >= NB_TTY_CHANNELS ) 440 { 441 _tty_get_lock( 0 ); 442 _tty_puts( "ERROR in _tty_getw()\n" ); 443 _tty_release_lock( 0 ); 444 _exit(); 445 } 446 } 447 448 while( done == 0 ) 449 { 450 _tty_read( &byte, channel ); 451 452 if (( byte > 0x2F) && (byte < 0x3A)) // decimal character 453 { 454 buf[max] = byte; 455 max++; 456 _tty_write( &byte, 1, channel ); 457 } 458 else if ( (byte == 0x0A) || (byte == 0x0D) ) // LF or CR character 459 { 460 done = 1; 461 } 462 else if ( byte == 0x7F ) // DEL character 463 { 464 if (max > 0) 246 465 { 247 buf[index] = byte; 248 index++; 249 } 250 } 251 } // end while 252 buf[index] = 0; 253 return 0; // return ok 254 } 255 /******************************************************************** 256 tty_getw_irq() 257 Fetch a string of decimal characters (most significant digit first) 258 to build a 32 bits unsigned int. 259 The terminal index is implicitely defined by the processor ID. 260 (and by the task ID in case of multi-tasking) 261 This is a blocking function that returns 0 if a valid unsigned int 262 is stored in the buffer, and returns -1 in case of error. 263 It uses the TTY_GET_IRQ interrupt, anf the associated kernel buffer. 264 The non-blocking system function _tty_read_irq is called several times, 265 and the decimal characters are written in a 32 characters buffer 266 until a <LF> character is read. 267 The <DEL> character is interpreted, and previous characters can be 268 cancelled. All others characters are ignored. 269 When the <LF> character is received, the string is converted to 270 an unsigned int value. If the number of decimal digit is too large 271 for the 32 bits range, the zero value is returned. 272 ********************************************************************/ 273 int tty_getw_irq(int* word_buffer) 274 { 275 unsigned char buf[32]; 276 unsigned char byte; 277 unsigned int save = 0; 278 unsigned int val = 0; 279 unsigned int done = 0; 280 unsigned int overflow = 0; 281 unsigned int max = 0; 282 unsigned int i; 283 int ret; 284 285 while(done == 0) 286 { 287 ret = sys_call(SYSCALL_TTY_READ_IRQ, 288 (int)(&byte), 289 1, 290 0,0); 291 if ((ret < 0) || (ret > 1)) return -1; // return error 292 293 if ( ret == 1 ) // get one character 294 { 295 if (( byte > 0x2F) && (byte < 0x3A)) // decimal character 296 { 297 buf[max] = byte; 298 max++; 299 tty_putc(byte); 300 } 301 else if ( (byte == 0x0A) || (byte == 0x0D) ) // LF or CR character 302 { 303 done = 1; 304 } 305 else if ( byte == 0x7F ) // DEL character 306 { 307 if (max > 0) 308 { 309 max--; // cancel the character 310 tty_putc(0x08); 311 tty_putc(0x20); 312 tty_putc(0x08); 313 } 314 } 315 if ( max == 32 ) // decimal string overflow 316 { 317 for( i=0 ; i<max ; i++) // cancel the string 318 { 319 tty_putc(0x08); 320 tty_putc(0x20); 321 tty_putc(0x08); 322 } 323 tty_putc(0x30); 324 *word_buffer = 0; // return 0 value 325 return 0; 466 max--; // cancel the character 467 _tty_write( cancel_string, 3, channel ); 326 468 } 327 469 } … … 343 485 for( i=0 ; i<max ; i++) // cancel the string 344 486 { 345 tty_putc(0x08); 346 tty_putc(0x20); 347 tty_putc(0x08); 348 } 349 tty_putc(0x30); 487 _tty_write( cancel_string, 3, channel ); 488 } 489 _tty_write( &zero, 1, channel ); 350 490 *word_buffer = 0; // return 0 value 351 491 } 352 return 0; 353 } 354 /********************************************************************* 355 tty_printf() 356 This function is a simplified version of the mutek_printf() function. 357 The terminal index is implicitely defined by the processor ID. 358 (and by the task ID in case of multi-tasking) 359 It doesn't use the IRQ_PUT interrupt, anf the associated kernel buffer. 360 Only a limited number of formats are supported: 361 - %d : signed decimal 362 - %u : unsigned decimal 363 - %x : hexadecimal 364 - %c : char 365 - %s : string 366 *********************************************************************/ 367 int tty_printf(char *format, ...) 492 } 493 494 ////////////////////////////////////////////////////////////////////////////// 495 // This function is a simplified version of the mutek_printf() function. 496 // It takes the TTY lock on the selected channel for exclusive access. 497 // Only a limited number of formats are supported: 498 // - %d : signed decimal 499 // - %u : unsigned decimal 500 // - %x : hexadecimal 501 // - %c : char 502 // - %s : string 503 ////////////////////////////////////////////////////////////////////////////// 504 in_drivers void _tty_printf( char *format, ...) 368 505 { 369 506 va_list ap; 370 va_start(ap, format); 507 va_start( ap, format ); 508 509 unsigned int channel; 510 unsigned int l; 511 unsigned int x; 512 unsigned int y; 513 unsigned int proc_id = _procid(); 514 515 // compute TTY channel 516 if ( NB_TTY_CHANNELS == 1 ) 517 { 518 channel = 0; 519 } 520 else 521 { 522 l = (proc_id % NB_PROCS_MAX); 523 x = (proc_id / NB_PROCS_MAX) >> Y_WIDTH; 524 y = (proc_id / NB_PROCS_MAX) & ((1<<Y_WIDTH) - 1); 525 channel = (x * Y_SIZE + y) * NB_PROCS_MAX + l; 526 if (channel >= NB_TTY_CHANNELS ) 527 { 528 _tty_get_lock( 0 ); 529 _tty_puts("ERROR in _tty_printf() for proc[" ); 530 _tty_putd( x ); 531 _tty_puts(","); 532 _tty_putd( y ); 533 _tty_puts(","); 534 _tty_putd( l ); 535 _tty_puts("] / TTY channel too large = "); 536 _tty_putd( channel ); 537 _tty_puts("\n"); 538 _tty_release_lock( 0 ); 539 _exit(); 540 } 541 } 542 543 // take the TTY lock 544 _tty_get_lock( channel ); 371 545 372 546 printf_text: 373 547 374 while (*format) { 548 while (*format) 549 { 375 550 unsigned int i; 376 551 for (i = 0; format[i] && format[i] != '%'; i++) 377 552 ; 378 if (i) { 379 sys_call(SYSCALL_TTY_WRITE, 380 (int)format, 381 i, 382 0,0); 553 if (i) 554 { 555 _tty_write( format, i, channel ); 383 556 format += i; 384 557 } 385 if (*format == '%') { 558 if (*format == '%') 559 { 386 560 format++; 387 561 goto printf_arguments; … … 389 563 } // end while 390 564 391 va_end(ap); 392 return 0; 565 va_end( ap ); 566 567 // release lock 568 _tty_release_lock( 0 ); 569 570 return; 393 571 394 572 printf_arguments: 395 573 396 574 { 397 int val = va_arg(ap, long);398 char buf[20];399 char* pbuf;575 int val = va_arg(ap, long); 576 char buf[20]; 577 char* pbuf; 400 578 unsigned int len = 0; 401 579 static const char HexaTab[] = "0123456789ABCDEF"; … … 409 587 break; 410 588 case ('d'): // decimal signed integer 411 if (val < 0) { 589 if (val < 0) 590 { 412 591 val = -val; 413 sys_call(SYSCALL_TTY_WRITE, 414 (int)"-", 415 1, 416 0,0); 592 _tty_write( "_" , 1, channel ); 417 593 } 418 594 case ('u'): // decimal unsigned integer 419 for( i=0 ; i<10 ; i++) { 595 for( i=0 ; i<10 ; i++) 596 { 420 597 buf[9-i] = HexaTab[val % 10]; 421 598 if (!(val /= 10)) break; … … 425 602 break; 426 603 case ('x'): // hexadecimal integer 427 sys_call(SYSCALL_TTY_WRITE, 428 (int)"0x", 429 2, 430 0,0); 431 for( i=0 ; i<8 ; i++) { 604 _tty_write( "0x", 2, channel ); 605 for( i=0 ; i<8 ; i++) 606 { 432 607 buf[7-i] = HexaTab[val % 16U]; 433 608 if (!(val /= 16U)) break; … … 447 622 } // end switch 448 623 449 sys_call(SYSCALL_TTY_WRITE, 450 (int)pbuf, 451 len, 452 0,0); 624 _tty_write( pbuf, len, channel ); 453 625 goto printf_text; 454 626 } 455 627 } // end printf() 456 628 457 /******************************************************************** 458 MULTI-TIMER 459 For all system calls, the first argument is the Timer index. 460 ********************************************************************* 461 timer_set_mode() 462 The possible values for the TIMER_MODE register are 463 - 0x0 : Timer not activated 464 - 0x1 : Timer activated, but no interrupt is generated 465 - 0x3 : Timer activarted and periodic interrupts generated 466 ********************************************************************/ 467 int timer_set_mode(int timer_index, int val) 468 { 469 return sys_call(SYSCALL_TIMER_WRITE, 470 timer_index, 471 TIMER_MODE, 472 val, 473 0); 474 } 475 /******************************************************************** 476 timer_set_period() 477 Defines the period value for the periodic interrupt. 478 ********************************************************************/ 479 int timer_set_period(int timer_index, int val) 480 { 481 return sys_call(SYSCALL_TIMER_WRITE, 482 timer_index, 483 TIMER_PERIOD, 484 val, 485 0); 486 } 487 /******************************************************************** 488 timer_reset_irq() 489 ********************************************************************/ 490 int timer_reset_irq(int timer_index) 491 { 492 return sys_call(SYSCALL_TIMER_WRITE, 493 timer_index, 494 TIMER_RESETIRQ, 495 0, 0); 496 } 497 /******************************************************************** 498 timer_get_time() 499 returns the current timer value. 500 ********************************************************************/ 501 int timer_get_time(int timer_index, int* time) 502 { 503 return sys_call(SYSCALL_TIMER_READ, 504 timer_index, 505 TIMER_VALUE, 506 (int)time, 507 0); 508 } 509 510 /******************************************************************** 511 GCD COPROCESSOR 512 ********************************************************************* 513 gcd_set_opa(int val) 514 Set operand A in the GCD (Greater Common Divider) coprocessor. 515 ********************************************************************/ 516 int gcd_set_opa(int val) 517 { 518 return sys_call(SYSCALL_GCD_WRITE, 519 GCD_OPA, 520 val, 521 0, 0); 522 } 523 /******************************************************************** 524 gcd_set_opb(int val) 525 Set operand B in the GCD (Greater Common Divider) coprocessor. 526 ********************************************************************/ 527 int gcd_set_opb(int val) 528 { 529 return sys_call(SYSCALL_GCD_WRITE, 530 GCD_OPB, 531 val, 532 0, 0); 533 } 534 /******************************************************************** 535 gcd_start() 536 Start computation in the GCD (Greater Common Divider) coprocessor. 537 ********************************************************************/ 538 int gcd_start(int val) 539 { 540 return sys_call(SYSCALL_GCD_WRITE, 541 GCD_START, 542 0, 0, 0); 543 } 544 /******************************************************************** 545 gcd_get_status(int* val) 546 Get status fromn the GCD (Greater Common Divider) coprocessor. 547 The value is nul when the coprocessor is idle (computation completed) 548 ********************************************************************/ 549 int gcd_get_status(int* val) 550 { 551 return sys_call(SYSCALL_GCD_READ, 552 GCD_STATUS, 553 (int)val, 554 0, 0); 555 } 556 /******************************************************************** 557 gcd_get_result(int* val) 558 Get result fromn the GCD (Greater Common Divider) coprocessor. 559 ********************************************************************/ 560 int gcd_get_result(int* val) 561 { 562 return sys_call(SYSCALL_GCD_READ, 563 GCD_OPA, 564 (int)val, 565 0, 0); 566 } 567 568 /******************************************************************** 569 ICU(s) 570 ********************************************************************* 571 icu_set_mask() 572 Set some bits in the Interrupt Enable Mask of the ICU component. 573 Each bit set in the written word will be set in the Mask Enable. 574 ********************************************************************/ 575 int icu_set_mask(int val) 576 { 577 return sys_call(SYSCALL_ICU_WRITE, 578 ICU_MASK_SET, 579 val, 580 0, 0); 581 } 582 /******************************************************************** 583 icu_clear_mask() 584 Reset some bits in the Interrupt Enable Mask of the ICU component. 585 Each bit set in the written word will be reset in the Mask Enable. 586 ********************************************************************/ 587 int icu_clear_mask(int val) 588 { 589 return sys_call(SYSCALL_ICU_WRITE, 590 ICU_MASK_CLEAR, 591 val, 592 0, 0); 593 } 594 /******************************************************************** 595 icu_get_mask() 596 Read the Interrupt Enable Mask of the ICU component. 597 ********************************************************************/ 598 int icu_get_mask(int* buffer) 599 { 600 return sys_call(SYSCALL_ICU_READ, 601 ICU_MASK, 602 (int)buffer, 603 0, 0); 604 } 605 /******************************************************************** 606 icu_get_irqs() 607 Read the value of the 32 interrupt lines (IRQ inputs). 608 ********************************************************************/ 609 int icu_get_irqs(int* buffer) 610 { 611 return sys_call(SYSCALL_ICU_READ, 612 ICU_INT, 613 (int)buffer, 614 0, 0); 615 } 616 /******************************************************************** 617 icu_get_index() 618 Read the index of the highest priority active interrupt. 619 (If no active interrupt, -1 is returned). 620 ********************************************************************/ 621 int icu_get_index(int* buffer) 622 { 623 return sys_call(SYSCALL_ICU_READ, 624 ICU_IT_VECTOR, 625 (int)buffer, 626 0, 0); 627 } 628 629 /******************************************************************** 630 LOCKS 631 ********************************************************************* 632 lock_acquire() 633 This system call performs a spin-lock acquisition. 634 It is dedicated to the SoCLib LOCKS peripheral. 635 In case of busy waiting, there is a random delay 636 of about 100 cycles between two successive lock read, 637 to avoid bus saturation. 638 ********************************************************************/ 639 int lock_acquire(int lock_index) 640 { 641 return sys_call(SYSCALL_LOCKS_READ, 642 lock_index, 643 0, 0, 0); 644 } 645 646 /******************************************************************** 647 lock_release() 648 You must use this system call to release a spin-lock, 649 as the LOCKS peripheral is in the kernel segment. 650 ********************************************************************/ 651 int lock_release(int lock_index) 652 { 653 return sys_call(SYSCALL_LOCKS_WRITE, 654 lock_index, 655 0, 0, 0); 656 } 657 658 /******************************************************************** 659 I/O BLOCK DEVICE 660 ********************************************************************* 661 ioc_write() 662 Transfer data from a memory buffer to a file on the block_device. 663 - lba : Logical Block Address (first block index) 664 - buffer : base address of the memory buffer 665 - count : number of blocks to be transfered 666 This function returns 0 if the transfert can be done. 667 It returns -1 if the buffer is not in user address space. 668 ********************************************************************/ 669 int ioc_write(size_t lba, void* buffer, size_t count) 670 { 671 return sys_call(SYSCALL_IOC_WRITE, 672 lba, 673 (int)buffer, 674 count, 675 0); 676 } 677 /******************************************************************** 678 ioc_read() 679 Transfer data from a file on the block_device to a memory buffer. 680 - lba : Logical Block Address (first block index) 681 - buffer : base address of the memory buffer 682 - count : number of blocks to be transfered 683 This function returns 0 if the transfert can be done. 684 It returns -1 if the buffer is not in user address space. 685 ********************************************************************/ 686 int ioc_read(size_t lba, void* buffer, size_t count) 687 { 688 return sys_call(SYSCALL_IOC_READ, 689 lba, 690 (int)buffer, 691 count, 692 0); 693 } 694 /******************************************************************** 695 ioc_completed() 696 This blocking function returns 0 when the I/O transfer is 697 successfully completed, and returns -1 if an address error 698 has been detected. 699 ********************************************************************/ 700 int ioc_completed() 701 { 702 return sys_call(SYSCALL_IOC_COMPLETED, 703 0, 0, 0, 0); 704 } 705 706 /******************************************************************** 707 FRAME BUFFER 708 ********************************************************************* 709 fb_sync_write() 710 This blocking function use a memory copy strategy to transfer data 711 from a user buffer to the frame buffer device in kernel space, 712 - offset : offset (in bytes) in the frame buffer 713 - buffer : base address of the memory buffer 714 - length : number of bytes to be transfered 715 It returns 0 when the transfer is completed. 716 ********************************************************************/ 717 int fb_sync_write(size_t offset, void* buffer, size_t length) 718 { 719 return sys_call(SYSCALL_FB_SYNC_WRITE, 720 offset, 721 (int)buffer, 722 length, 723 0); 724 } 725 /******************************************************************** 726 fb_sync_read() 727 This blocking function use a memory copy strategy to transfer data 728 from the frame buffer device in kernel space to an user buffer. 729 - offset : offset (in bytes) in the frame buffer 730 - buffer : base address of the user buffer 731 - length : number of bytes to be transfered 732 It returns 0 when the transfer is completed. 733 ********************************************************************/ 734 int fb_sync_read(size_t offset, void* buffer, size_t length) 735 { 736 return sys_call(SYSCALL_FB_SYNC_READ, 737 offset, 738 (int)buffer, 739 length, 740 0); 741 } 742 /******************************************************************** 743 fb_write() 744 This non-blocking function use the DMA coprocessor to transfer data 745 from a user buffer to the frame buffer device in kernel space, 746 - offset : offset (in bytes) in the frame buffer 747 - buffer : base address of the user buffer 748 - length : number of bytes to be transfered 749 It returns 0 when the transfer can be started. 750 It returns -1 if the buffer is not in user address space. 751 The transfer completion is signaled by an IRQ, and must be 752 tested by the fb_completed() function. 753 ********************************************************************/ 754 int fb_write(size_t offset, void* buffer, size_t length) 755 { 756 return sys_call(SYSCALL_FB_WRITE, 757 offset, 758 (int)buffer, 759 length, 760 0); 761 } 762 /******************************************************************** 763 fb_read() 764 This non-blocking function use the DMA coprocessor to transfer data 765 from the frame buffer device in kernel space to an user buffer. 766 - offset : offset (in bytes) in the frame buffer 767 - buffer : base address of the memory buffer 768 - length : number of bytes to be transfered 769 It returns 0 when the transfer can be started. 770 It returns -1 if the buffer is not in user address space. 771 The transfer completion is signaled by an IRQ, and must be 772 tested by the fb_completed() function. 773 ********************************************************************/ 774 int fb_read(size_t offset, void* buffer, size_t length) 775 { 776 return sys_call(SYSCALL_FB_READ, 777 offset, 778 (int)buffer, 779 length, 780 0); 781 } 782 /******************************************************************** 783 fb_completed() 784 This blocking function returns when the transfer is completed. 785 It returns 0 if the transfer is successful. 786 It returns -1 if an address error has been detected. 787 ********************************************************************/ 788 int fb_completed() 789 { 790 return sys_call(SYSCALL_FB_COMPLETED, 791 0, 0, 0, 0); 792 } 793 794 /******************************************************************** 795 SYNCHRONISATION BARRIERS 796 ********************************************************************* 797 barrier_init() 798 This function initializes the counter for barrier[index]. 799 - index : index of the barrier (between 0 & 7) 800 - count : number of tasks to be synchronized. 801 The GIET supports up to 8 independant barriers. 802 It returns a non zero value when the barrier index is larger than 7. 803 * ********************************************************************/ 804 int barrier_init(size_t index, size_t count) 805 { 806 return sys_call(SYSCALL_BARRIER_INIT, 807 (int)index, 808 (int)count, 809 0, 0); 810 } 811 /******************************************************************** 812 barrier_wait() 813 This blocking function use a busy waiting policy, and returns only 814 when all synchonized asks have reached the barrier. 815 - index : index of the barrier (between 0 & 7) 816 The GIET supports up to 8 independant barriers. 817 It returns a non zero value when the barrier index is larger than 7. 818 ********************************************************************/ 819 int barrier_wait(size_t index) 820 { 821 return sys_call(SYSCALL_BARRIER_WAIT, 822 (int)index, 823 0, 0, 0); 824 } 629 ////////////////////////////////////////////////////////////////////////////////////// 630 // These functions are the ISRs that must be executed when an IRQ is activated 631 // by the TTY: _tty_isr_X is associated to channel [X]. 632 // It save the character in the communication buffer _tty_get_buf[X], 633 // and set the set/reset variable _tty_get_full[X]. 634 // A character is lost if the buffer is full when the ISR is executed. 635 ////////////////////////////////////////////////////////////////////////////////////// 636 in_drivers void _tty_isr_indexed(size_t index) 637 { 638 char* base = (char*)&seg_tty_base; 639 char* tty_address = (char*)(base + index*TTY_SPAN*4); 640 641 _tty_get_buf[index] = tty_address[TTY_READ*4]; // save character and reset IRQ 642 _tty_get_full[index] = 1; // signals character available 643 } 644 645 in_drivers void _tty_isr_00() { _tty_isr_indexed(0); } 646 in_drivers void _tty_isr_01() { _tty_isr_indexed(1); } 647 in_drivers void _tty_isr_02() { _tty_isr_indexed(2); } 648 in_drivers void _tty_isr_03() { _tty_isr_indexed(3); } 649 in_drivers void _tty_isr_04() { _tty_isr_indexed(4); } 650 in_drivers void _tty_isr_05() { _tty_isr_indexed(5); } 651 in_drivers void _tty_isr_06() { _tty_isr_indexed(6); } 652 in_drivers void _tty_isr_07() { _tty_isr_indexed(7); } 653 in_drivers void _tty_isr_08() { _tty_isr_indexed(8); } 654 in_drivers void _tty_isr_09() { _tty_isr_indexed(9); } 655 in_drivers void _tty_isr_10() { _tty_isr_indexed(10); } 656 in_drivers void _tty_isr_11() { _tty_isr_indexed(11); } 657 in_drivers void _tty_isr_12() { _tty_isr_indexed(12); } 658 in_drivers void _tty_isr_13() { _tty_isr_indexed(13); } 659 in_drivers void _tty_isr_14() { _tty_isr_indexed(14); } 660 in_drivers void _tty_isr_15() { _tty_isr_indexed(15); } 661 in_drivers void _tty_isr_16() { _tty_isr_indexed(16); } 662 in_drivers void _tty_isr_17() { _tty_isr_indexed(17); } 663 in_drivers void _tty_isr_18() { _tty_isr_indexed(18); } 664 in_drivers void _tty_isr_19() { _tty_isr_indexed(19); } 665 in_drivers void _tty_isr_20() { _tty_isr_indexed(20); } 666 in_drivers void _tty_isr_21() { _tty_isr_indexed(21); } 667 in_drivers void _tty_isr_22() { _tty_isr_indexed(22); } 668 in_drivers void _tty_isr_23() { _tty_isr_indexed(23); } 669 in_drivers void _tty_isr_24() { _tty_isr_indexed(24); } 670 in_drivers void _tty_isr_25() { _tty_isr_indexed(25); } 671 in_drivers void _tty_isr_26() { _tty_isr_indexed(26); } 672 in_drivers void _tty_isr_27() { _tty_isr_indexed(27); } 673 in_drivers void _tty_isr_28() { _tty_isr_indexed(28); } 674 in_drivers void _tty_isr_29() { _tty_isr_indexed(29); } 675 in_drivers void _tty_isr_30() { _tty_isr_indexed(30); } 676 in_drivers void _tty_isr_31() { _tty_isr_indexed(31); } 677 678 679 ////////////////////////////////////////////////////////////////////////////////////////// 680 // I/O BLOCK_DEVICE 681 // The three functions below use the three variables _ioc_lock _ioc_done, 682 // and _ioc_status for synchronisation. 683 // - As the IOC component can be used by several programs running in parallel, 684 // the _ioc_lock variable guaranties exclusive access to the device. 685 // The _ioc_read() and _ioc_write() functions use atomic LL/SC to get the lock. 686 // and set _ioc_lock to a non zero value. 687 // The _ioc_write() and _ioc_read() functions are blocking, polling the _ioc_lock 688 // variable until the device is available. 689 // - When the tranfer is completed, the ISR routine activated by the IOC IRQ 690 // set the _ioc_done variable to a non-zero value. Possible address errors detected 691 // by the IOC peripheral are reported by the ISR in the _ioc_status variable. 692 // The _ioc_completed() function is polling the _ioc_done variable, waiting for 693 // tranfer conpletion. When the completion is signaled, the _ioc_completed() function 694 // reset the _ioc_done variable to zero, and releases the _ioc_lock variable. 695 /////////////////////////////////////////////////////////////////////////////////////// 696 // This blocking function is used by the _ioc_read() and _ioc_write() functions 697 // to get _ioc_lock using LL/SC. 698 /////////////////////////////////////////////////////////////////////////////////////// 699 in_drivers void _ioc_get_lock() 700 { 701 register unsigned int* plock = (unsigned int*)&_ioc_lock; 702 703 asm volatile ("_ioc_llsc: \n" 704 "ll $2, 0(%0) \n" // $2 <= _ioc_lock 705 "bnez $2, _ioc_llsc \n" // retry if busy 706 "li $3, 1 \n" // prepare argument for sc 707 "sc $3, 0(%0) \n" // try to set _ioc_busy 708 "beqz $3, _ioc_llsc \n" // retry if not atomic 709 ::"r"(plock):"$2","$3"); 710 } 711 ////////////////////////////////////////////////////////////////////////////////////// 712 // Transfer data from a memory buffer to the block_device. 713 // - lba : first block index on the disk 714 // - buffer : base address of the memory buffer 715 // - count : number of blocks to be transfered 716 // The source buffer must be in user address space. 717 /////////////////////////////////////////////////////////////////////////////////////// 718 in_drivers void _ioc_write( size_t lba, 719 void* buffer, 720 size_t count, 721 size_t ext ) 722 { 723 volatile unsigned int* ioc_address = (unsigned int*)&seg_ioc_base; 724 725 // get the lock 726 _ioc_get_lock(); 727 728 // block_device configuration 729 ioc_address[BLOCK_DEVICE_BUFFER] = (unsigned int)buffer; 730 ioc_address[BLOCK_DEVICE_BUFFER_EXT] = ext; 731 ioc_address[BLOCK_DEVICE_COUNT] = count; 732 ioc_address[BLOCK_DEVICE_LBA] = lba; 733 ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1; 734 ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_WRITE; 735 } 736 /////////////////////////////////////////////////////////////////////////////////////// 737 // Transfer data from a file on the block device to a memory buffer. 738 // - lba : first block index on the disk 739 // - buffer : base address of the memory buffer 740 // - count : number of blocks to be transfered 741 // The destination buffer must be in user address space. 742 // All cache lines corresponding to the the target buffer must be invalidated 743 // for cache coherence. 744 /////////////////////////////////////////////////////////////////////////////////////// 745 in_drivers void _ioc_read( size_t lba, 746 void* buffer, 747 size_t count, 748 size_t ext ) 749 { 750 volatile unsigned int* ioc_address = (unsigned int*)&seg_ioc_base; 751 752 // get the lock 753 _ioc_get_lock(); 754 755 // block_device configuration 756 ioc_address[BLOCK_DEVICE_BUFFER] = (unsigned int)buffer; 757 ioc_address[BLOCK_DEVICE_BUFFER_EXT] = ext; 758 ioc_address[BLOCK_DEVICE_COUNT] = count; 759 ioc_address[BLOCK_DEVICE_LBA] = lba; 760 ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1; 761 ioc_address[BLOCK_DEVICE_OP] = BLOCK_DEVICE_READ; 762 } 763 /////////////////////////////////////////////////////////////////////////////////////// 764 // This blocking function cheks completion of an I/O transfer and reports errors. 765 // It returns 0 if the transfer is successfully completed. 766 // It returns -1 if an error has been reported. 767 /////////////////////////////////////////////////////////////////////////////////////// 768 in_drivers void _ioc_completed() 769 { 770 // waiting for completion 771 while (_ioc_done == 0) asm volatile("nop"); 772 773 // reset synchronisation variables 774 _ioc_done = 0; 775 _ioc_lock = 0; 776 777 if( (_ioc_status != BLOCK_DEVICE_READ_SUCCESS) && 778 (_ioc_status != BLOCK_DEVICE_WRITE_SUCCESS) ) 779 { 780 _tty_get_lock( 0 ); 781 _tty_puts( "ERROR in _ioc_completed()\n"); 782 _tty_release_lock( 0 ); 783 _exit(); 784 } 785 } 786 ////////////////////////////////////////////////////////////////////////////////////// 787 // This ISR must be executed when an IRQ is activated by IOC to signal completion. 788 // It acknowledge the IRQ using the ioc base address, save the status in _ioc_status, 789 // and set the _ioc_done variable to signal completion. 790 // This variable is defined in the drivers.c file. 791 ////////////////////////////////////////////////////////////////////////////////////// 792 in_drivers void _ioc_isr() 793 { 794 int* ioc_address = (int*)&seg_ioc_base; 795 796 _ioc_status = ioc_address[BLOCK_DEVICE_STATUS]; // save status & reset IRQ 797 _ioc_done = 1; // signals completion 798 } 799 800 ////////////////////////////////////////////////////////////////////////////////////// 801 // This ISR must be executed when an IRQ is activated by MEMC to signal 802 // an error detected by the TSAR memory cache after a write transaction. 803 // It displays an error message on the TTY terminal allocated to the processor 804 // executing the ISR. 805 ////////////////////////////////////////////////////////////////////////////////////// 806 in_drivers void _mmc_isr() 807 { 808 int* mmc_address = (int*)&seg_mmc_base; 809 unsigned int cluster_xy = _procid() / NB_PROCS_MAX; 810 811 _tty_printf( "WRITE ERROR signaled by Memory Cache in cluster %x\n", cluster_xy ); 812 } 813 814 ////////////////////////////////////////////////////////////////////////////////////// 815 // FRAME_BUFFER 816 // The _fb_sync_write & _fb_sync_read functions use a memcpy strategy to implement 817 // the transfer between a data buffer and the frame buffer. 818 // They are blocking until completion of the transfer. 819 ////////////////////////////////////////////////////////////////////////////////////// 820 // _fb_sync_write() 821 // Transfer data from an user buffer to the frame_buffer device with a memcpy. 822 // - offset : offset (in bytes) in the frame buffer 823 // - buffer : base address of the memory buffer 824 // - length : number of bytes to be transfered 825 ////////////////////////////////////////////////////////////////////////////////////// 826 in_drivers void _fb_sync_write( size_t offset, 827 void* buffer, 828 size_t length, 829 size_t ext ) 830 { 831 volatile char* fb = (char*)(void*)&seg_fbf_base + offset; 832 char* ub = buffer; 833 834 _memcpy( (void*)fb, (void*)ub, length ); 835 } 836 /////////////////////////////////////////////////////////////////////////////////////// 837 // _fb_sync_read() 838 // Transfer data from the frame_buffer device to an user buffer with a memcpy. 839 // - offset : offset (in bytes) in the frame buffer 840 // - buffer : base address of the memory buffer 841 // - length : number of bytes to be transfered 842 ////////////////////////////////////////////////////////////////////////////////////// 843 in_drivers void _fb_sync_read( size_t offset, 844 void* buffer, 845 size_t length, 846 size_t ext ) 847 { 848 volatile char* fb = (char*)(void*)&seg_fbf_base + offset; 849 char* ub = buffer; 850 851 _memcpy( (void*)ub, (void*)fb, length ); 852 } 853 854 /////////////////////////////////////////////////////////////////////////////////////// 855 // Release a software spin-lock 856 /////////////////////////////////////////////////////////////////////////////////////// 857 in_drivers void _release_lock(size_t index) 858 859 { 860 if( index >= NB_LOCKS ) 861 { 862 _tty_get_lock( 0 ); 863 _tty_puts( "ERROR in _release_lock()" ); 864 _tty_release_lock( 0 ); 865 _exit(); 866 } 867 868 _spin_lock[index] = 0; 869 } 870 /////////////////////////////////////////////////////////////////////////////////////// 871 // Try to take a software spin-lock. 872 // This is a blocking call, as there is a busy-waiting loop, 873 // until the lock is granted to the requester. 874 // There is an internal delay of about 100 cycles between 875 // two successive lock read, to avoid bus saturation. 876 /////////////////////////////////////////////////////////////////////////////////////// 877 in_drivers void _get_lock(size_t index) 878 { 879 if( index >= NB_LOCKS ) 880 { 881 _tty_get_lock( 0 ); 882 _tty_puts( "ERROR in _get_lock()" ); 883 _tty_release_lock( 0 ); 884 _exit(); 885 } 886 887 register int delay = ((_proctime() +_procid()) & 0xF) << 4; 888 register int * plock = (int *) &_spin_lock[index]; 889 890 asm volatile ("_locks_llsc: \n" 891 "ll $2, 0(%0) \n" // $2 <= _locks_lock 892 "bnez $2, _locks_delay \n" // random delay if busy 893 "li $3, 1 \n" // prepare argument for sc 894 "sc $3, 0(%0) \n" // try to set _locks_busy 895 "bnez $3, _locks_ok \n" // exit if atomic 896 "_locks_delay: \n" 897 "move $4, %1 \n" // $4 <= delay 898 "_locks_loop: \n" 899 "addi $4, $4, -1 \n" // $4 <= $4 - 1 900 "beqz $4, _locks_loop \n" // test end delay 901 "j _locks_llsc \n" // retry 902 "_locks_ok: \n" 903 ::"r"(plock),"r"(delay):"$2","$3","$4"); 904 } 905 906 907 ////////////////////////////////////////////////////////////////////////////////////// 908 // This function makes a cooperative initialisation of the barrier: 909 // - barrier_count[index] <= N 910 // - barrier_lock[index] <= 0 911 // All tasks try to initialize the barrier, but the initialisation 912 // is done by only one task, using LL/SC instructions. 913 // This cooperative initialisation is questionnable, 914 // because the barrier can ony be initialised once... 915 ////////////////////////////////////////////////////////////////////////////////////// 916 in_drivers void _barrier_init(unsigned int index, unsigned int value) 917 { 918 919 register int* pinit = (int*)&_barrier_value[index]; 920 register int* pcount = (int*)&_barrier_count[index]; 921 register int* plock = (int*)&_barrier_lock[index]; 922 923 if ( index >= NB_BARRIERS ) 924 { 925 _tty_get_lock( 0 ); 926 _tty_puts( "ERROR in _barrier_init()" ); 927 _tty_release_lock( 0 ); 928 _exit(); 929 } 930 931 // parallel initialisation using atomic instructions LL/SC 932 asm volatile ("_barrier_init_test: \n" 933 "ll $2, 0(%0) \n" // read barrier_value 934 "bnez $2, _barrier_init_done \n" 935 "move $3, %3 \n" 936 "sc $3, 0(%0) \n" // try to write barrier_value 937 "beqz $3, _barrier_init_test \n" 938 "move $3, %3 \n" 939 "sw $3, 0(%1) \n" // barrier_count <= barrier_value 940 "move $3, $0 \n" // 941 "sw $3, 0(%2) \n" // barrier_lock <= 0 942 "_barrier_init_done: \n" 943 ::"r"(pinit),"r"(pcount),"r"(plock),"r"(value):"$2","$3"); 944 } 945 ////////////////////////////////////////////////////////////////////////////////////// 946 // This blocking function uses a busy_wait technics (on the barrier_lock value), 947 // because the GIET does not support dynamic scheduling/descheduling of tasks. 948 // The barrier state is actually defined by two variables: 949 // _barrier_count[index] define the number of particpants that are waiting 950 // _barrier_lock[index] define the bool variable whose value is polled 951 // The last participant change the value of _barrier_lock[index] to release the barrier... 952 // There is at most 16 independant barriers, and an error is returned 953 // if the barrier index is larger than 15. 954 ////////////////////////////////////////////////////////////////////////////////////// 955 in_drivers void _barrier_wait(unsigned int index) 956 { 957 register int* pcount = (int*)&_barrier_count[index]; 958 register int count; 959 960 int lock = _barrier_lock[index]; 961 962 if ( index >= NB_BARRIERS ) 963 { 964 _tty_get_lock( 0 ); 965 _tty_puts( "ERROR in _barrier_wait()" ); 966 _tty_release_lock( 0 ); 967 _exit(); 968 } 969 970 // parallel decrement _barrier_count[index] using atomic instructions LL/SC 971 // input : pointer on _barrier_count[index] 972 // output : count = _barrier_count[index] (before decrementation) 973 asm volatile ("_barrier_decrement: \n" 974 "ll %0, 0(%1) \n" 975 "addi $3, %0, -1 \n" 976 "sc $3, 0(%1) \n" 977 "beqz $3, _barrier_decrement \n" 978 :"=&r"(count) 979 :"r"(pcount) 980 :"$2","$3"); 981 982 // the last task re-initializes the barrier_ count variable 983 // and the barrier_lock variable, waking up all other waiting tasks 984 985 if ( count == 1 ) // last task 986 { 987 _barrier_count[index] = _barrier_value[index]; 988 asm volatile( "sync" ); 989 _barrier_lock[index] = (lock == 0) ? 1 : 0; 990 } 991 else // other tasks 992 { 993 while ( lock == _barrier_lock[index] ) asm volatile("nop"); 994 } 995 } 996 997 825 998 // Local Variables: 826 999 // tab-width: 4; -
trunk/softs/giet_tsar/stdio.h
r158 r622 1 /********************************************************************************* 2 fichier stdio.h 3 Written Alain greiner & Nicolas Pouillon 4 Date : 15/09/2009 5 *********************************************************************************/ 1 //////////////////////////////////////////////////////////////////////////////////////// 2 // File : stdio.h 3 // Written by Alain Greiner 4 // Date : 17/01/2014 5 // 6 // This file define varions functions that can be used by applications to access 7 // peripherals, or other ressources such as processor registers, spin_locks 8 // or synchronisation barriers. 9 // It is dedicated for the TSAR multi-processors multi_clusters architecture. 10 // There is NO separation between application code and system code. 11 // This basic GIET does not use the virtual memory, and does nort support multi-tasking. 12 // 13 //The supported peripherals are: 14 //- the SoClib multi_tty 15 //- The SoCLib frame_buffer 16 //- The SoCLib block_device 17 // 18 //The following parameters must be defined in the hard_config.h file. 19 //- X_SIZE : number of clusters in a row 20 //- Y_SIZE : number of clusters in a column 21 //- X_WIDTH : number of bits for X field in proc_id 22 //- Y_WIDTH : number of bits for Y field in proc_id 23 //- NB_PROCS_MAX : max number of processor per cluster 24 //- NB_TTY_CHANNELS : max number of TTY channels 25 // 26 //The follobing base addresses must be defined in the ldscript 27 //- seg_tty_base 28 //- seg_fbf_base 29 //- seg_ioc_base 30 //////////////////////////////////////////////////////////////////////////////////////// 6 31 7 #ifndef _ STDIO_H_8 #define _ STDIO_H_32 #ifndef _GIET_STDIO_H_ 33 #define _GIET_STDIO_H_ 9 34 10 #define SYSCALL_PROCID 0x00 11 #define SYSCALL_PROCTIME 0x01 12 #define SYSCALL_TTY_WRITE 0x02 13 #define SYSCALL_TTY_READ 0x03 14 #define SYSCALL_TIMER_WRITE 0x04 15 #define SYSCALL_TIMER_READ 0x05 16 #define SYSCALL_GCD_WRITE 0x06 17 #define SYSCALL_GCD_READ 0x07 18 #define SYSCALL_ICU_WRITE 0x08 19 #define SYSCALL_ICU_READ 0x09 20 #define SYSCALL_TTY_READ_IRQ 0x0A 21 #define SYSCALL_TTY_WRITE_IRQ 0x0B 22 #define SYSCALL_LOCKS_WRITE 0x0C 23 #define SYSCALL_LOCKS_READ 0x0D 24 #define SYSCALL_EXIT 0x0E 25 #define SYSCALL_PROCNUMBER 0x0F 35 #include "tty.h" 36 #include "block_device.h" 37 #include "hard_config.h" 38 #include <stdarg.h> 26 39 27 #define SYSCALL_FB_SYNC_WRITE 0x10 28 #define SYSCALL_FB_SYNC_READ 0x11 29 #define SYSCALL_FB_WRITE 0x12 30 #define SYSCALL_FB_READ 0x13 31 #define SYSCALL_FB_COMPLETED 0x14 32 #define SYSCALL_IOC_WRITE 0x15 33 #define SYSCALL_IOC_READ 0x16 34 #define SYSCALL_IOC_COMPLETED 0x17 35 #define SYSCALL_BARRIER_INIT 0x18 36 #define SYSCALL_BARRIER_WAIT 0x19 40 typedef unsigned int size_t; 37 41 38 typedef unsigned int size_t; 42 // global variables defined in stdio.c 39 43 40 /**************************************************************** 41 this is a generic C function to implement all system calls. 42 - The first argument is the system call index. 43 - The four next arguments are the system call arguments. 44 They will be written in registers $2, $4, $5, $6, $7. 45 ****************************************************************/ 46 int sys_call(int call_no, 47 int arg_o, 48 int arg_1, 49 int arg_2, 50 int arg_3); 44 extern int volatile _ioc_lock; 45 extern int volatile _ioc_done; 46 extern int volatile _ioc_status; 51 47 52 /**************************************************************** 53 These functions access the MIPS protected registers 54 ****************************************************************/ 55 int procid(); 56 int proctime(); 57 int procnumber(); 58 int exit(); 59 int rand(); 48 extern char volatile _tty_get_buf[]; 49 extern int volatile _tty_get_full[]; 60 50 61 /**************************************************************** 62 These functions access the MULTI_TTY peripheral 63 ****************************************************************/ 64 int tty_puts(char* string); 65 int tty_putc(char byte); 66 int tty_putw(int word); 67 int tty_getc(char* byte); 68 int tty_getc_irq(char* byte); 69 int tty_gets_irq(char* buf, int bufsize); 70 int tty_getw_irq(int* word); 71 int tty_printf(char* format,...); 51 extern int volatile _barrier_value[]; 52 extern int volatile _barrier_count[]; 53 extern int volatile _barrier_lock[]; 72 54 73 /**************************************************************** 74 These functions access the MULTI_TIMER peripheral 75 ****************************************************************/ 76 int timer_set_mode(int timer_index, int mode); 77 int timer_set_period(int timer_index, int period); 78 int timer_reset_irq(int timer_index); 79 int timer_get_time(int timer_index, int* time); 55 extern int volatile _spin_lock[]; 80 56 81 /**************************************************************** 82 These functions access the GCD peripheral 83 ****************************************************************/ 84 int gcd_set_opa(int val); 85 int gcd_set_opb(int val); 86 int gcd_start(); 87 int gcd_get_result(int* val); 88 int gcd_get_status(int* val); 57 // functions defined in stdio.c 89 58 90 /**************************************************************** 91 These functions access the ICU peripheral 92 ****************************************************************/ 93 int icu_set_mask(int val); 94 int icu_clear_mask(int val); 95 int icu_get_mask(int* buffer); 96 int icu_get_irqs(int* buffer); 97 int icu_get_index(int* buffer); 59 void* _memcpy( void* dst, const void* src, size_t size ); 98 60 99 /**************************************************************** 100 These functions access the LOCKS peripheral 101 ****************************************************************/ 102 int lock_acquire(int lock_index); 103 int lock_release(int lock_index); 61 unsigned int _procid(); 62 unsigned int _proctime(); 63 unsigned int _procnumber(); 104 64 105 /**************************************************************** 106 These functions access the BLOCK_DEVICE peripheral 107 ****************************************************************/ 108 int ioc_read(size_t lba, void* buffer, size_t count); 109 int ioc_write(size_t lba, void* buffer, size_t count); 110 int ioc_completed(); 65 void _it_mask(); 66 void _it_enable(); 111 67 112 /**************************************************************** 113 These functions access the FRAME_BUFFER peripheral 114 ****************************************************************/ 115 int fb_read(size_t offset, void* buffer, size_t length); 116 int fb_write(size_t offset, void* buffer, size_t length); 117 int fb_completed(); 118 int fb_sync_read(size_t offset, void* buffer, size_t length); 119 int fb_sync_write(size_t offset, void* buffer, size_t length); 68 void _dcache_buf_invalidate( const void* buffer, size_t size ); 120 69 121 /**************************************************************** 122 These functions access the synchronization barriers 123 ****************************************************************/ 124 int barrier_init(size_t index, size_t count); 125 int barrier_wait(size_t index); 70 void _exit(); 71 72 void _itoa_dec( unsigned int val, char* buf ); 73 void _itoa_hex( unsigned int val, char* buf ); 74 75 int _tty_write( char* buffer, size_t length, size_t channel ); 76 int _tty_read( char* buffer, size_t channel ); 77 void _tty_puts( char* string ); 78 void _tty_putd( unsigned int val ); 79 void _tty_putx( unsigned int val ); 80 void _tty_get_lock( size_t channel ); 81 void _tty_release_lock( size_t channel ); 82 void _tty_getc( char* buffer ); 83 void _tty_getw( unsigned int* buffer ); 84 void _tty_printf( char* format, ... ); 85 86 void _ioc_get_lock(); 87 void _ioc_write( size_t lba, void* buffer, size_t count, size_t ext ); 88 void _ioc_read (size_t lba, void* buffer, size_t count, size_t ext ); 89 void _ioc_completed(); 90 void _ioc_isr(); 91 92 void _mmc_isr(); 93 94 void _fb_sync_write( size_t offset, void* buffer, size_t length, size_t ext ); 95 void _fb_sync_read( size_t offset, void* buffer, size_t length, size_t ext ); 96 97 void _release_lock( size_t lock_index ); 98 void _get_lock( size_t lock_index ); 99 100 void _barrier_init(size_t index, size_t count); 101 void _barrier_wait(size_t index); 126 102 127 103 #endif
Note: See TracChangeset
for help on using the changeset viewer.