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 (costis@...)!
#
# 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 costis@....
# 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@...
ori 3, 3, __bss_start@...
li 4, 0
lis 5, _end@...
ori 5, 5, _end@...
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_@...
ori 2,2,_SDA2_BASE_@... # Set the Small Data 2 (Read Only) base register.
lis 13,_SDA_BASE_@...
ori 13,13,_SDA_BASE_@... # 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@...
ori 3, 3, zfloat@...
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@....
*
* 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@...
ori r5, r5, exception_handler_transfer@...
mtsrr0 r5
bne 1f
lis r5, exception_handler_default@...
ori r5, r5, exception_handler_default@...
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@...
ori r3, r3, decCount@...
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 <ioe@...>
* - 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;
}
}
|