Update of /cvsroot/gc-linux/ipl/lowlevel In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5953/lowlevel Added Files: cache.S crt0.s ctype.c exception.S exceptionc.c irq.c string.c string_asm.S time.c Log Message: Sorted all source files int / into the following directories: io, lowlevel, loadand ipl Did some cleaning in the source files, but there is still much to be done --- NEW FILE: cache.S --- #include <asm.h> .globl dcache_flush dcache_flush: cmplwi r4, 0 # zero or negative size? blelr clrlwi. r5, r3, 27 # check for lower bits set in address beq 1f addi r4, r4, 0x20 1: addi r4, r4, 0x1f srwi r4, r4, 5 mtctr r4 2: dcbst r0, r3 addi r3, r3, 0x20 bdnz 2b blr .globl dcache_inv dcache_inv: cmplwi r4, 0 # zero or negative size? blelr clrlwi. r5, r3, 27 # check for lower bits set in address beq 1f addi r4, r4, 0x20 1: addi r4, r4, 0x1f srwi r4, r4, 5 mtctr r4 2: dcbi r0, r3 addi r3, r3, 0x20 bdnz 2b blr .globl flush_code flush_code: lis r5, 0xFFFF ori r5, r5, 0xFFF1 and r5, r5, r3 subf r3, r5, r3 add r4, r4, r3 1: dcbst r0, r5 sync icbi r0, r5 addic r5, r5, 8 subic. r4, r4, 8 bge 1b isync blr --- NEW FILE: crt0.s --- .text .org 0x0 .globl _start # crt0.s file for the GameCube V1.0 by Costis (co...@gb...)! # # This is start-up code for initializing the GameCube system and hardware # before executing the actual user program code. It clears the GPR's, # initializes the FPR's, initializes the Data, Code, and L2 caches, clears # and initializes SPR's, and disables exceptions (interrupts). # # Note: The next version will have full exception (interrupt) initialization # code. As stated above, this version does not support interrupts, # however, there are no freely available interrupt handling functions # yet. So, even with proper interrupt initialization, it would not # actually be useful with the current open source libraries for the # GameCube. # # Have fun!!! Please e-mail any suggestions or bugs to co...@gb.... # Entry Point _start: bl InitGPRS # Initialize the General Purpose Registers bl InitHardware # Initialize the GameCube Hardware (Floating Point Registers, Caches, etc.) bl SystemInit # Initialize more cache aspects, clear a few SPR's, and disable interrupts. # clear BSS .extern __bss_start, _end lis 3, __bss_start@h ori 3, 3, __bss_start@l li 4, 0 lis 5, _end@h ori 5, 5, _end@l sub 5, 5, 3 bl memset bl main # Branch to the user code! eloop: b eloop # If the main function returns, then just loop endlessly. InitGPRS: # Clear all of the GPR's to 0 li 0,0 li 3,0 li 4,0 li 5,0 li 6,0 li 7,0 li 8,0 li 9,0 li 10,0 li 11,0 li 12,0 li 14,0 li 15,0 li 16,0 li 17,0 li 18,0 li 19,0 li 20,0 li 21,0 li 22,0 li 23,0 li 24,0 li 25,0 li 26,0 li 27,0 li 28,0 li 29,0 li 30,0 li 31,0 # lis 1, 0x8160 # Set the Stack Pointer to the top of main RAM. lis 1, 0x8170 # put the fucking stack pointer somewhere else. subi 1, 1, 0x10 lis 2,0x8000 stw 1,0x34(2) # write sp lis 2,_SDA2_BASE_@h ori 2,2,_SDA2_BASE_@l # Set the Small Data 2 (Read Only) base register. lis 13,_SDA_BASE_@h ori 13,13,_SDA_BASE_@l # Set the Small Data (Read\Write) base register. blr InitHardware: mflr 31 # Store the link register in r31 bl PSInit # Initialize Paired Singles bl FPRInit # Initialize the FPR's bl CacheInit # Initialize the system caches mtlr 31 # Retreive the link register from r31 blr PSInit: mfspr 3, 920 # (HID2) oris 3, 3, 0xA000 mtspr 920, 3 # (HID2) # Set the Instruction Cache invalidation bit in HID0 mfspr 3,1008 ori 3,3,0x0800 mtspr 1008,3 sync # Clear various Special Purpose Registers li 3,0 mtspr 912,3 mtspr 913,3 mtspr 914,3 mtspr 915,3 mtspr 916,3 mtspr 917,3 mtspr 918,3 mtspr 919,3 # Return blr FPRInit: # Enable the Floating Point Registers mfmsr 3 ori 3,3,0x2000 mtmsr 3 # Clear all of the FPR's to 0 lis 3, zfloat@h ori 3, 3, zfloat@l lfd 0, 0(3) fmr 1,0 fmr 2,0 fmr 3,0 fmr 4,0 fmr 5,0 fmr 6,0 fmr 7,0 fmr 8,0 fmr 9,0 fmr 10,0 fmr 11,0 fmr 12,0 fmr 13,0 fmr 14,0 fmr 15,0 fmr 16,0 fmr 17,0 fmr 18,0 fmr 19,0 fmr 20,0 fmr 21,0 fmr 22,0 fmr 23,0 fmr 24,0 fmr 25,0 fmr 26,0 fmr 27,0 fmr 28,0 fmr 29,0 fmr 30,0 fmr 31,0 mtfsf 255,0 # Return blr CacheInit: mflr 0 stw 0, 4(1) stwu 1, -16(1) stw 31, 12(1) stw 30, 8(1) mfspr 3,1008 # (HID0) rlwinm 0, 3, 0, 16, 16 cmplwi 0, 0x0000 # Check if the Instruction Cache has been enabled or not. bne ICEnabled # If not, then enable it. isync mfspr 3, 1008 ori 3, 3, 0x8000 mtspr 1008, 3 ICEnabled: mfspr 3, 1008 # bl PPCMfhid0 rlwinm 0, 3, 0, 17, 17 cmplwi 0, 0x0000 # Check if the Data Cache has been enabled or not. bne DCEnabled # If not, then enable it. sync mfspr 3, 1008 ori 3, 3, 0x4000 mtspr 1008, 3 DCEnabled: mfspr 3, 1017 # (L2CR) clrrwi 0, 3, 31 # Clear all of the bits except 31 cmplwi 0, 0x0000 bne L2GISkip # Skip the L2 Global Cache Invalidation process if it has already been done befor. # Store the current state of the MSR in r30 mfmsr 3 mr 30,3 sync # Enable Instruction and Data Address Translation li 3, 48 mtmsr 3 sync sync # Disable the L2 Global Cache. mfspr 3, 1017 # (L2CR clrlwi 3, 3, 1 mtspr 1017, 3 # (L2CR) sync # Invalidate the L2 Global Cache. bl L2GlobalInvalidate # Restore the previous state of the MSR from r30 mr 3, 30 mtmsr 3 # Enable the L2 Global Cache and disable the L2 Data Only bit and the L2 Global Invalidate Bit. mfspr 3, 1017 # (L2CR) oris 0, 3, 0x8000 rlwinm 3, 0, 0, 11, 9 mtspr 1017, 3 # (L2CR) L2GISkip: # Restore the non-volatile registers to their previous values and return. lwz 0, 20(1) lwz 31, 12(1) lwz 30, 8(1) addi 1, 1, 16 mtlr 0 blr L2GlobalInvalidate: mflr 0 stw 0, 4(1) stwu 1, -16(1) stw 31, 12(1) sync # Disable the L2 Cache. mfspr 3, 1017 # bl PPCMf1017 clrlwi 3, 3, 1 mtspr 1017, 3 # bl PPCMt1017 sync # Initiate the L2 Cache Global Invalidation process. mfspr 3, 1017 # (L2CR) oris 3, 3, 0x0020 mtspr 1017, 3 # (L2CR) # Wait until the L2 Cache Global Invalidation has been completed. L2GICheckComplete: mfspr 3, 1017 # (L2CR) clrlwi 0, 3, 31 cmplwi 0, 0x0000 bne L2GICheckComplete # Clear the L2 Data Only bit and the L2 Global Invalidate Bit. mfspr 3, 1017 # (L2CR) rlwinm 3, 3, 0, 11, 9 mtspr 1017, 3 # (L2CR) # Wait until the L2 Cache Global Invalidation status bit signifies that it is ready. L2GDICheckComplete: mfspr 3, 1017 # (L2CR) clrlwi 0, 3, 31 cmplwi 0, 0x0000 bne L2GDICheckComplete # Restore the non-volatile registers to their previous values and return. lwz 0, 20(1) lwz 31, 12(1) addi 1, 1, 16 mtlr 0 blr SystemInit: mflr 0 stw 0, 4(1) stwu 1, -0x18(1) stw 31, 0x14(1) stw 30, 0x10(1) stw 29, 0xC(1) # Disable interrupts! mfmsr 3 rlwinm 4,3,0,17,15 rlwinm 4,4,0,26,24 mtmsr 4 # Clear various SPR's li 3,0 mtspr 952, 3 mtspr 956, 3 mtspr 953, 3 mtspr 954, 3 mtspr 957, 3 mtspr 958, 3 # Disable Speculative Bus Accesses to non-guarded space from both caches. mfspr 3, 1008 # (HID0) ori 3, 3, 0x0200 mtspr 1008, 3 # Set the Non-IEEE mode in the FPSCR mtfsb1 29 mfspr 3,920 # (HID2) rlwinm 3, 3, 0, 2, 0 mtspr 920,3 # (HID2) # Restore the non-volatile registers to their previous values and return. lwz 0, 0x1C(1) lwz 31, 0x14(1) lwz 30, 0x10(1) lwz 29, 0xC(1) addi 1, 1, 0x18 mtlr 0 blr zfloat: .float 0 .align 4 --- NEW FILE: ctype.c --- /* * (C) Copyright 2000 * Wolfgang Denk, DENX Software Engineering, wd...@de.... * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ /* * linux/lib/ctype.c * * Copyright (C) 1991, 1992 Linus Torvalds */ #include <linux/ctype.h> unsigned char _ctype[] = { _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ --- NEW FILE: exception.S --- #include <asm.h> .globl exception_start, exception_end, exception_patch #define EXCEPTION_PROLOG \ stw r0,0(r4); \ stw r1,4(r4); \ stw r2,8(r4); \ stmw r6,24(r4); \ mfspr r0,913; \ stw r0,424(r4); \ mfspr r0,914; \ stw r0,428(r4); \ mfspr r0,915; \ stw r0,432(r4); \ mfspr r0,916; \ stw r0,436(r4); \ mfspr r0,917; \ stw r0,440(r4); \ mfspr r0,918; \ stw r0,444(r4); \ mfspr r0,919; \ stw r0,448(r4); \ mfdsisr r5; \ mfdar r6 exception_start: .set sprg0,272 // we store the current context, and transfer the control to the exception handler mtspr sprg0, r4 lwz r4,0xC0(0) // get current context ptr stw r3, 12(r4) // r3 saved. mfspr r3, sprg0 stw r3, 16(r4) // r4 saved. stw r5, 20(r4) lhz r3, 418(r4) ori r3, r3, 0x0002 sth r3, 418(r4) mfcr r3 stw r3,128(r4) mflr r3 stw r3,132(r4) mfctr r3 stw r3,136(r4) mfxer r3 stw r3,140(r4) mfsrr0 r3 stw r3,408(r4) mfsrr1 r3 stw r3,412(r4) mr r5,r3 nop mfmsr r3 ori r3,r3,0x2030 mtsrr1 r3 exception_patch: li r3,0 lwz r4, 0xD4(0) rlwinm. r5,r5,0,30,30 // check if exception is recoverable lis r5, exception_handler_transfer@h ori r5, r5, exception_handler_transfer@l mtsrr0 r5 bne 1f lis r5, exception_handler_default@h ori r5, r5, exception_handler_default@l rfi // return to exception handler 1: clrlslwi r5, r3, 24, 2 // calculate address in exception handling table lwz r5,0x3000(r5) rfi exception_end: exception_handler_transfer: #if 0 lis r3, 0xc0b0 1: stwu r3, 4(r3) b 1b #endif mtlr r5 EXCEPTION_PROLOG mr r14, r4 blrl mr r3, r14 // fallthrough exception_context_load: lwz r0,0(r3) lwz r1,4(r3) lwz r2,8(r3) lhz r4,418(r3) rlwinm. r5,r4,0,30,30 beq 1f rlwinm r4,r4,0,31,29 sth r4,418(r3) lmw r5,20(r3) b 2f 1: lmw r13,52(r3) 2: lwz r4,424(r3) mtspr 913,r4 lwz r4,428(r3) mtspr 914,r4 lwz r4,432(r3) mtspr 915,r4 lwz r4,436(r3) mtspr 916,r4 lwz r4,440(r3) mtspr 917,r4 lwz r4,444(r3) mtspr 918,r4 lwz r4,448(r3) mtspr 919,r4 lwz r4,128(r3) mtcrf 0xff,r4 lwz r4,132(r3) mtlr r4 lwz r4,136(r3) mtctr r4 lwz r4,140(r3) mtxer r4 mfmsr r4 rlwinm r4,r4,0,17,15 rlwinm r4,r4,0,31,29 mtmsr r4 lwz r4,408(r3) mtsrr0 r4 lwz r4,412(r3) mtsrr1 r4 lwz r4,16(r3) lwz r3,12(r3) rfi .global decCount decCount: .long 0 .global exception_handler_decrementer exception_handler_decrementer: lis r3, decCount@h ori r3, r3, decCount@l lwz r5, 0(r3) addi r5, r5, 1 stw r5, 0(r3) // 40.5 MHz lis r3, 0x0269 ori r3, r3, 0xFB20 mtdec r3 blr .global exception_handler_system_call exception_handler_system_call: mfspr r3, 1008 ori r4, r3, 8 mtspr 1008, r4 isync sync mtspr 1008, r3 blr --- NEW FILE: exceptionc.c --- #include <exception.h> #include <console.h> #include <linux/string.h> #include <irq.h> #include <cache.h> #include <color.h> extern char exception_start, exception_end, exception_patch; extern void exception_handler_default(); extern void exception_handler_decrementer(); extern void exception_handler_system_call(); extern void exception_handler_external(); unsigned long exception_location[15] = { 0x00000100, 0x00000200, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000800, 0x00000900, 0x00000C00, 0x00000D00, 0x00000F00, 0x00001300, 0x00001400, 0x00001700 }; const char *exception_name[15] = { "System Reset", "Machine Check", "DSI", "ISI", "Interrupt", "Alignment", "Program", "Floating Point", "Decrementer", "System Call", "Trace", "Performance", "IABR", "Reserved", "Thermal"}; void exception_init() { int i; for (i = 0; i < 15; ++i) { void * address = (void*)(exception_location[i] | 0x80000000); memcpy(address, &exception_start, &exception_end - &exception_start); // fix the "li" to load the correct exception number *(unsigned long*)(&exception_patch - &exception_start + (int)address) |= i; flush_code(address, &exception_end - &exception_start); exception_set_handler(i, exception_handler_default); // *(long*) address = 0x4c000064; flush_code(address, 0x100); } exception_set_handler(8, exception_handler_decrementer); exception_set_handler(9, exception_handler_system_call); exception_set_handler(4, irq_ext); CONTEXT_CURRENT = 0x80002000; CONTEXT_CURRENT_PHYS = 0x2000; } void exception_close() { int i; for (i = 0; i < 15; ++i) { void * address = (void*)(exception_location[i] | 0x80000000); *(long*) address = 0x4c000064; flush_code(address, 0x100); } mtmsr(mfmsr() & ~0x8000); // EE mtmsr(mfmsr() | 0x2002); // FP, RI } void exception_set_handler(int exception, void (*handler)(int, struct context_s*)) { ((void**)0x80003000)[exception] = handler; } void exception_handler_default(int exception) { struct context_s *c = (struct context_s *)CONTEXT_CURRENT; printf("Exception (%s) occured!\n", exception_name[exception]); printf("GPR00 %08lx GPR08 %08lx GPR16 %08lx GPR24 %08lx\n",c->GPR[0], c->GPR[8], c->GPR[16], c->GPR[24]); printf("GPR01 %08lx GPR09 %08lx GPR17 %08lx GPR25 %08lx\n",c->GPR[1], c->GPR[9], c->GPR[17], c->GPR[25]); printf("GPR02 %08lx GPR10 %08lx GPR18 %08lx GPR26 %08lx\n",c->GPR[2], c->GPR[10], c->GPR[18], c->GPR[26]); printf("GPR03 %08lx GPR11 %08lx GPR19 %08lx GPR27 %08lx\n",c->GPR[3], c->GPR[11], c->GPR[19], c->GPR[27]); printf("GPR04 %08lx GPR12 %08lx GPR20 %08lx GPR28 %08lx\n",c->GPR[4], c->GPR[12], c->GPR[20], c->GPR[28]); printf("GPR05 %08lx GPR13 %08lx GPR21 %08lx GPR29 %08lx\n",c->GPR[5], c->GPR[13], c->GPR[21], c->GPR[29]); printf("GPR06 %08lx GPR14 %08lx GPR22 %08lx GPR30 %08lx\n",c->GPR[6], c->GPR[14], c->GPR[22], c->GPR[30]); printf("GPR07 %08lx GPR15 %08lx GPR23 %08lx GPR31 %08lx\n",c->GPR[7], c->GPR[15], c->GPR[23], c->GPR[31]); printf("LR %08lx SRR0 %08lx %08lx\n", c->LR, c->SRR0, c->SRR1); printf("DAR: %08lx DSISR %08lx\n", mfspr(19), mfspr(18)); if ((exception == 2) || (exception == 7) || (exception == 6)) // DSI { int i; unsigned long *address = (unsigned long*)c->SRR0; printf("CODE DUMP:\n"); for (i=0; i<12; i+=4) printf("%08lx %08lx %08lx %08lx\n", address[i], address[i+1], address[i+2], address[i+3]); } while (1); } --- NEW FILE: irq.c --- #include <irq.h> struct irq_handler_s { irq_handler_proc *handler; void *context; }; static struct irq_handler_s irq_handler[32]; void irq_ext() { int i; unsigned long cause = *(volatile unsigned long*)0xCC003000; cause &= *(volatile unsigned long*)0xCC003004; for (i = 0; i < 32; ++i) if (cause & (0x80000000>>i)) if (irq_handler[i].handler) irq_handler[i].handler(i, irq_handler[i].context); *(volatile unsigned long*)0xCC003000 = cause; } int request_irq(int irq, irq_handler_proc *handler, void *context) { if (irq_handler[irq].handler) return -1; irq_handler[irq].handler = handler; irq_handler[irq].context = context; *(unsigned long*)0xCC003004 |= 0x80000000>>irq; // enable irq return 0; } int free_irq(int irq, void *context) { if (!irq_handler[irq].handler) return -1; if (irq_handler[irq].context != context) return -2; irq_handler[irq].handler = 0; *(unsigned long*)0xCC003004 &= ~(0x80000000>>irq); return 0; } --- NEW FILE: string.c --- /* * linux/lib/string.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* * stupid library routines.. The optimized versions should generally be found * as inline code in <asm-xx/string.h> * * These are buggy as well.. * * * Fri Jun 25 1999, Ingo Oeser <io...@in...> * - Added strsep() which will replace strtok() soon (because strsep() is * reentrant and should be faster). Use only strsep() in new code, please. */ #include <linux/types.h> #include <linux/string.h> #include <linux/ctype.h> #ifndef __HAVE_ARCH_STRNICMP /** * strnicmp - Case insensitive, length-limited string comparison * @s1: One string * @s2: The other string * @len: the maximum number of characters to compare */ int strnicmp(const char *s1, const char *s2, size_t len) { /* Yes, Virginia, it had better be unsigned */ unsigned char c1, c2; c1 = 0; c2 = 0; if (len) { do { c1 = *s1; c2 = *s2; s1++; s2++; if (!c1) break; if (!c2) break; if (c1 == c2) continue; c1 = tolower(c1); c2 = tolower(c2); if (c1 != c2) break; } while (--len); } return (int)c1 - (int)c2; } #endif char * ___strtok; #ifndef __HAVE_ARCH_STRCPY /** * strcpy - Copy a %NUL terminated string * @dest: Where to copy the string to * @src: Where to copy the string from */ char * strcpy(char * dest,const char *src) { char *tmp = dest; while ((*dest++ = *src++) != '\0') /* nothing */; return tmp; } #endif #ifndef __HAVE_ARCH_STRNCPY /** * strncpy - Copy a length-limited, %NUL-terminated string * @dest: Where to copy the string to * @src: Where to copy the string from * @count: The maximum number of bytes to copy * * Note that unlike userspace strncpy, this does not %NUL-pad the buffer. * However, the result is not %NUL-terminated if the source exceeds * @count bytes. */ char * strncpy(char * dest,const char *src,size_t count) { char *tmp = dest; while (count-- && (*dest++ = *src++) != '\0') /* nothing */; return tmp; } #endif #ifndef __HAVE_ARCH_STRCAT /** * strcat - Append one %NUL-terminated string to another * @dest: The string to be appended to * @src: The string to append to it */ char * strcat(char * dest, const char * src) { char *tmp = dest; while (*dest) dest++; while ((*dest++ = *src++) != '\0') ; return tmp; } #endif #ifndef __HAVE_ARCH_STRNCAT /** * strncat - Append a length-limited, %NUL-terminated string to another * @dest: The string to be appended to * @src: The string to append to it * @count: The maximum numbers of bytes to copy * * Note that in contrast to strncpy, strncat ensures the result is * terminated. */ char * strncat(char *dest, const char *src, size_t count) { char *tmp = dest; if (count) { while (*dest) dest++; while ((*dest++ = *src++)) { if (--count == 0) { *dest = '\0'; break; } } } return tmp; } #endif #ifndef __HAVE_ARCH_STRCMP /** * strcmp - Compare two strings * @cs: One string * @ct: Another string */ int strcmp(const char * cs,const char * ct) { register signed char __res; while (1) { if ((__res = *cs - *ct++) != 0 || !*cs++) break; } return __res; } #endif #ifndef __HAVE_ARCH_STRNCMP /** * strncmp - Compare two length-limited strings * @cs: One string * @ct: Another string * @count: The maximum number of bytes to compare */ int strncmp(const char * cs,const char * ct,size_t count) { register signed char __res = 0; while (count) { if ((__res = *cs - *ct++) != 0 || !*cs++) break; count--; } return __res; } #endif #ifndef __HAVE_ARCH_STRCHR /** * strchr - Find the first occurrence of a character in a string * @s: The string to be searched * @c: The character to search for */ char * strchr(const char * s, int c) { for(; *s != (char) c; ++s) if (*s == '\0') return NULL; return (char *) s; } #endif #ifndef __HAVE_ARCH_STRRCHR /** * strrchr - Find the last occurrence of a character in a string * @s: The string to be searched * @c: The character to search for */ char * strrchr(const char * s, int c) { const char *p = s + strlen(s); do { if (*p == (char)c) return (char *)p; } while (--p >= s); return NULL; } #endif #ifndef __HAVE_ARCH_STRLEN /** * strlen - Find the length of a string * @s: The string to be sized */ size_t strlen(const char * s) { const char *sc; for (sc = s; *sc != '\0'; ++sc) /* nothing */; return sc - s; } #endif #ifndef __HAVE_ARCH_STRNLEN /** * strnlen - Find the length of a length-limited string * @s: The string to be sized * @count: The maximum number of bytes to search */ size_t strnlen(const char * s, size_t count) { const char *sc; for (sc = s; count-- && *sc != '\0'; ++sc) /* nothing */; return sc - s; } #endif #ifndef __HAVE_ARCH_STRSPN /** * strspn - Calculate the length of the initial substring of @s which only * contain letters in @accept * @s: The string to be searched * @accept: The string to search for */ size_t strspn(const char *s, const char *accept) { const char *p; const char *a; size_t count = 0; for (p = s; *p != '\0'; ++p) { for (a = accept; *a != '\0'; ++a) { if (*p == *a) break; } if (*a == '\0') return count; ++count; } return count; } #endif #ifndef __HAVE_ARCH_STRPBRK /** * strpbrk - Find the first occurrence of a set of characters * @cs: The string to be searched * @ct: The characters to search for */ char * strpbrk(const char * cs,const char * ct) { const char *sc1,*sc2; for( sc1 = cs; *sc1 != '\0'; ++sc1) { for( sc2 = ct; *sc2 != '\0'; ++sc2) { if (*sc1 == *sc2) return (char *) sc1; } } return NULL; } #endif #ifndef __HAVE_ARCH_STRTOK /** * strtok - Split a string into tokens * @s: The string to be searched * @ct: The characters to search for * * WARNING: strtok is deprecated, use strsep instead. */ char * strtok(char * s,const char * ct) { char *sbegin, *send; sbegin = s ? s : ___strtok; if (!sbegin) { return NULL; } sbegin += strspn(sbegin,ct); if (*sbegin == '\0') { ___strtok = NULL; return( NULL ); } send = strpbrk( sbegin, ct); if (send && *send != '\0') *send++ = '\0'; ___strtok = send; return (sbegin); } #endif #ifndef __HAVE_ARCH_STRSEP /** * strsep - Split a string into tokens * @s: The string to be searched * @ct: The characters to search for * * strsep() updates @s to point after the token, ready for the next call. * * It returns empty tokens, too, behaving exactly like the libc function * of that name. In fact, it was stolen from glibc2 and de-fancy-fied. * Same semantics, slimmer shape. ;) */ char * strsep(char **s, const char *ct) { char *sbegin = *s, *end; if (sbegin == NULL) return NULL; end = strpbrk(sbegin, ct); if (end) *end++ = '\0'; *s = end; return sbegin; } #endif #ifndef __HAVE_ARCH_MEMSET /** * memset - Fill a region of memory with the given value * @s: Pointer to the start of the area. * @c: The byte to fill the area with * @count: The size of the area. * * Do not use memset() to access IO space, use memset_io() instead. */ void * memset(void * s,int c,size_t count) { char *xs = (char *) s; while (count--) *xs++ = c; return s; } #endif #ifndef __HAVE_ARCH_BCOPY /** * bcopy - Copy one area of memory to another * @src: Where to copy from * @dest: Where to copy to * @count: The size of the area. * * Note that this is the same as memcpy(), with the arguments reversed. * memcpy() is the standard, bcopy() is a legacy BSD function. * * You should not use this function to access IO space, use memcpy_toio() * or memcpy_fromio() instead. */ char * bcopy(const char * src, char * dest, int count) { char *tmp = dest; while (count--) *tmp++ = *src++; return dest; } #endif #ifndef __HAVE_ARCH_MEMCPY /** * memcpy - Copy one area of memory to another * @dest: Where to copy to * @src: Where to copy from * @count: The size of the area. * * You should not use this function to access IO space, use memcpy_toio() * or memcpy_fromio() instead. */ void * memcpy(void * dest,const void *src,size_t count) { char *tmp = (char *) dest, *s = (char *) src; while (count--) *tmp++ = *s++; return dest; } #endif #ifndef __HAVE_ARCH_MEMMOVE /** * memmove - Copy one area of memory to another * @dest: Where to copy to * @src: Where to copy from * @count: The size of the area. * * Unlike memcpy(), memmove() copes with overlapping areas. */ void * memmove(void * dest,const void *src,size_t count) { char *tmp, *s; if (dest <= src) { tmp = (char *) dest; s = (char *) src; while (count--) *tmp++ = *s++; } else { tmp = (char *) dest + count; s = (char *) src + count; while (count--) *--tmp = *--s; } return dest; } #endif #ifndef __HAVE_ARCH_MEMCMP /** * memcmp - Compare two areas of memory * @cs: One area of memory * @ct: Another area of memory * @count: The size of the area. */ int memcmp(const void * cs,const void * ct,size_t count) { const unsigned char *su1, *su2; int res = 0; for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) if ((res = *su1 - *su2) != 0) break; return res; } #endif #ifndef __HAVE_ARCH_MEMSCAN /** * memscan - Find a character in an area of memory. * @addr: The memory area * @c: The byte to search for * @size: The size of the area. * * returns the address of the first occurrence of @c, or 1 byte past * the area if @c is not found */ void * memscan(void * addr, int c, size_t size) { unsigned char * p = (unsigned char *) addr; while (size) { if (*p == c) return (void *) p; p++; size--; } return (void *) p; } #endif #ifndef __HAVE_ARCH_STRSTR /** * strstr - Find the first substring in a %NUL terminated string * @s1: The string to be searched * @s2: The string to search for */ char * strstr(const char * s1,const char * s2) { int l1, l2; l2 = strlen(s2); if (!l2) return (char *) s1; l1 = strlen(s1); while (l1 >= l2) { l1--; if (!memcmp(s1,s2,l2)) return (char *) s1; s1++; } return NULL; } #endif #ifndef __HAVE_ARCH_MEMCHR /** * memchr - Find a character in an area of memory. * @s: The memory area * @c: The byte to search for * @n: The size of the area. * * returns the address of the first occurrence of @c, or %NULL * if @c is not found */ void *memchr(const void *s, int c, size_t n) { const unsigned char *p = s; while (n-- != 0) { if ((unsigned char)c == *p++) { return (void *)(p-1); } } return NULL; } #endif --- NEW FILE: string_asm.S --- /* * String handling functions for PowerPC. * * Copyright (C) 1996 Paul Mackerras. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ //#include <linux/config.h> //#include <asm/processor.h> //#include <asm/cache.h> //#include <asm/errno.h> //#include <asm/ppc_asm.h> #include <asm.h> #define COPY_16_BYTES \ lwz r7,4(r4); \ lwz r8,8(r4); \ lwz r9,12(r4); \ lwzu r10,16(r4); \ stw r7,4(r6); \ stw r8,8(r6); \ stw r9,12(r6); \ stwu r10,16(r6) #define COPY_16_BYTES_WITHEX(n) \ 8 ## n ## 0: \ lwz r7,4(r4); \ 8 ## n ## 1: \ lwz r8,8(r4); \ 8 ## n ## 2: \ lwz r9,12(r4); \ 8 ## n ## 3: \ lwzu r10,16(r4); \ 8 ## n ## 4: \ stw r7,4(r6); \ 8 ## n ## 5: \ stw r8,8(r6); \ 8 ## n ## 6: \ stw r9,12(r6); \ 8 ## n ## 7: \ stwu r10,16(r6) #define COPY_16_BYTES_EXCODE(n) \ 9 ## n ## 0: \ addi r5,r5,-(16 * n); \ b 104f; \ 9 ## n ## 1: \ addi r5,r5,-(16 * n); \ b 105f; \ .section __ex_table,"a"; \ .align 2; \ .long 8 ## n ## 0b,9 ## n ## 0b; \ .long 8 ## n ## 1b,9 ## n ## 0b; \ .long 8 ## n ## 2b,9 ## n ## 0b; \ .long 8 ## n ## 3b,9 ## n ## 0b; \ .long 8 ## n ## 4b,9 ## n ## 1b; \ .long 8 ## n ## 5b,9 ## n ## 1b; \ .long 8 ## n ## 6b,9 ## n ## 1b; \ .long 8 ## n ## 7b,9 ## n ## 1b; \ .text .text .globl strcpy strcpy: addi r5,r3,-1 addi r4,r4,-1 1: lbzu r0,1(r4) cmpwi 0,r0,0 stbu r0,1(r5) bne 1b blr .globl strncpy strncpy: cmpwi 0,r5,0 beqlr mtctr r5 addi r6,r3,-1 addi r4,r4,-1 1: lbzu r0,1(r4) cmpwi 0,r0,0 stbu r0,1(r6) bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */ blr .globl strcat strcat: addi r5,r3,-1 addi r4,r4,-1 1: lbzu r0,1(r5) cmpwi 0,r0,0 bne 1b addi r5,r5,-1 1: lbzu r0,1(r4) cmpwi 0,r0,0 stbu r0,1(r5) bne 1b blr .globl strcmp strcmp: addi r5,r3,-1 addi r4,r4,-1 1: lbzu r3,1(r5) cmpwi 1,r3,0 lbzu r0,1(r4) subf. r3,r0,r3 beqlr 1 beq 1b blr .globl strlen strlen: addi r4,r3,-1 1: lbzu r0,1(r4) cmpwi 0,r0,0 bne 1b subf r3,r3,r4 blr .globl memset memset: rlwimi r4,r4,8,16,23 rlwimi r4,r4,16,0,15 addi r6,r3,-4 cmplwi 0,r5,4 blt 7f stwu r4,4(r6) beqlr andi. r0,r6,3 add r5,r0,r5 subf r6,r0,r6 srwi r0,r5,2 mtctr r0 bdz 6f 1: stwu r4,4(r6) bdnz 1b 6: andi. r5,r5,3 7: cmpwi 0,r5,0 beqlr mtctr r5 addi r6,r6,3 8: stbu r4,1(r6) bdnz 8b blr .globl bcopy bcopy: mr r6,r3 mr r3,r4 mr r4,r6 b memcpy .globl memmove memmove: cmplw 0,r3,r4 bgt backwards_memcpy /* fall through */ .globl memcpy memcpy: srwi. r7,r5,3 addi r6,r3,-4 addi r4,r4,-4 beq 2f /* if less than 8 bytes to do */ andi. r0,r6,3 /* get dest word aligned */ mtctr r7 bne 5f 1: lwz r7,4(r4) lwzu r8,8(r4) stw r7,4(r6) stwu r8,8(r6) bdnz 1b andi. r5,r5,7 2: cmplwi 0,r5,4 blt 3f lwzu r0,4(r4) addi r5,r5,-4 stwu r0,4(r6) 3: cmpwi 0,r5,0 beqlr mtctr r5 addi r4,r4,3 addi r6,r6,3 4: lbzu r0,1(r4) stbu r0,1(r6) bdnz 4b blr 5: subfic r0,r0,4 mtctr r0 6: lbz r7,4(r4) addi r4,r4,1 stb r7,4(r6) addi r6,r6,1 bdnz 6b subf r5,r0,r5 rlwinm. r7,r5,32-3,3,31 beq 2b mtctr r7 b 1b .globl backwards_memcpy backwards_memcpy: rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */ add r6,r3,r5 add r4,r4,r5 beq 2f andi. r0,r6,3 mtctr r7 bne 5f 1: lwz r7,-4(r4) lwzu r8,-8(r4) stw r7,-4(r6) stwu r8,-8(r6) bdnz 1b andi. r5,r5,7 2: cmplwi 0,r5,4 blt 3f lwzu r0,-4(r4) subi r5,r5,4 stwu r0,-4(r6) 3: cmpwi 0,r5,0 beqlr mtctr r5 4: lbzu r0,-1(r4) stbu r0,-1(r6) bdnz 4b blr 5: mtctr r0 6: lbzu r7,-1(r4) stbu r7,-1(r6) bdnz 6b subf r5,r0,r5 rlwinm. r7,r5,32-3,3,31 beq 2b mtctr r7 b 1b .globl memcmp memcmp: cmpwi 0,r5,0 ble- 2f mtctr r5 addi r6,r3,-1 addi r4,r4,-1 1: lbzu r3,1(r6) lbzu r0,1(r4) subf. r3,r0,r3 bdnzt 2,1b blr 2: li r3,0 blr .global memchr memchr: cmpwi 0,r5,0 ble- 2f mtctr r5 addi r3,r3,-1 1: lbzu r0,1(r3) cmpw 0,r0,r4 bdnzf 2,1b beqlr 2: li r3,0 blr --- NEW FILE: time.c --- #include "processor.h" #define TB_CLOCK 40500000 unsigned long tb_diff_sec(tb_t *end, tb_t *start) { unsigned long upper, lower; upper = end->u - start->u; if (start->l > end->l) upper--; lower = end->l - start->l; return ((upper*((unsigned long)0x80000000/(TB_CLOCK/2))) + (lower/ TB_CLOCK)); } unsigned long tb_diff_msec(tb_t *end, tb_t *start) { unsigned long upper, lower; upper = end->u - start->u; if (start->l > end->l) upper--; lower = end->l - start->l; return ((upper*((unsigned long)0x80000000/(TB_CLOCK/2000))) + (lower/(TB_CLOCK/1000))); } unsigned long tb_diff_usec(tb_t *end, tb_t *start) { unsigned long upper, lower; upper = end->u - start->u; if (start->l > end->l) upper--; lower = end->l - start->l; return ((upper*((unsigned long)0x80000000/(TB_CLOCK/2000000))) + (lower/(TB_CLOCK/1000000))); } unsigned long tb_diff(tb_t *end, tb_t *start) { unsigned long lower; lower = end->l - start->l; return lower; } void udelay(unsigned int us) { tb_t start, end; mftb(&start); while (1) { mftb(&end); if (tb_diff_usec(&end, &start) >= us) break; } } void mdelay(unsigned int ms) { tb_t start, end; mftb(&start); while (1) { mftb(&end); if (tb_diff_msec(&end, &start) >= ms) break; } } void delay(unsigned int s) { tb_t start, end; mftb(&start); while (1) { mftb(&end); if (tb_diff_sec(&end, &start) >= s) break; } } |