1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/common/x86/cmem.cia Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,300 @@
1.4 +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32\common\x86\cmem.cia
1.18 +//
1.19 +//
1.20 +
1.21 +#include "common.h"
1.22 +
1.23 +
1.24 +#if defined(__MEM_MACHINE_CODED__)
1.25 +extern "C" {
1.26 +
1.27 +
1.28 +// See header file e32cmn.h for the in-source documentation.
1.29 +EXPORT_C __NAKED__ TAny* memmove(TAny* /*aTrg*/, const TAny* /*aSrc*/, unsigned int /*aLength*/)
1.30 + {
1.31 + asm("push ebx");
1.32 + asm("push esi");
1.33 + asm("push edi");
1.34 + asm("mov edi,[esp+16]");// destination address into edi
1.35 + asm("mov esi,[esp+20]");// source address into esi
1.36 + asm("mov ecx,[esp+24]");// byte count into ecx
1.37 + asm("pushfd");
1.38 +
1.39 + asm("mov eax,edi"); // return value
1.40 + asm("cld"); // assume forward copy initially
1.41 + asm("test ecx,ecx"); //
1.42 + asm("jz short memcopy0");// if length=0, nothing to do
1.43 + asm("xor edx,edx"); //
1.44 + asm("cmp edi,esi"); // compare source and dest addresses
1.45 + asm("je short memcopy0");// if equal, nothing to do
1.46 + asm("jc short memcopy1");// if dest<source, must go forwards
1.47 + asm("std"); // else go backwards
1.48 + asm("add esi,ecx"); // and start at end of block
1.49 + asm("add edi,ecx"); //
1.50 + asm("inc edx"); // edx=1 if backwards, 0 if forwards
1.51 + asm("memcopy1:");
1.52 + asm("cmp ecx,16"); // if length<16 don't bother with alignment check
1.53 + asm("jc short memcopy2");//
1.54 + asm("mov ebx,edi"); // ebx = destination address
1.55 + asm("and ebx,3"); // ebx bottom 2 bits = alignment of destination wrt hardware bus
1.56 + asm("jz short memcopy3");// if aligned, proceed with block move
1.57 + asm("or edx,edx"); // check direction of move
1.58 + asm("jnz short memcopy4");// if backwards, ebx = number of byte moves to align destination
1.59 + asm("neg ebx"); // else number of byte moves = 4-ebx
1.60 + asm("add ebx,4"); //
1.61 + asm("memcopy4:");
1.62 + asm("sub ecx,ebx"); // subtract number of bytes from length
1.63 + asm("xchg ecx,ebx"); // temporarily put length in ebx
1.64 + asm("sub edi,edx"); // adjust if backwards move
1.65 + asm("sub esi,edx"); //
1.66 + asm("rep movsb"); // move bytes to align destination
1.67 + asm("add edi,edx"); // adjust if backwards move
1.68 + asm("add esi,edx"); //
1.69 + asm("mov ecx,ebx"); // length back into ecx
1.70 + asm("memcopy3:");
1.71 + asm("mov ebx,ecx"); // save length in ebx
1.72 + asm("shl edx,2"); // adjustment 4 for backwards move
1.73 + asm("shr ecx,2"); // number of dwords to move into ecx
1.74 + asm("sub edi,edx"); // adjust if backwards move
1.75 + asm("sub esi,edx"); //
1.76 + asm("rep movsd"); // perform DWORD block move
1.77 + asm("add edi,edx"); // adjust if backwards move
1.78 + asm("add esi,edx"); //
1.79 + asm("mov ecx,ebx"); // length back into ecx
1.80 + asm("and ecx,3"); // number of remaining bytes to move
1.81 + asm("jz short memcopy0");// if zero, we are finished
1.82 + asm("shr edx,2"); // adjustment 1 for backwards move
1.83 + asm("memcopy2:"); // *** come here for small move
1.84 + asm("sub edi,edx"); // adjust if backwards move
1.85 + asm("sub esi,edx"); //
1.86 + asm("rep movsb"); // move remaining bytes
1.87 +
1.88 + asm("memcopy0:");
1.89 + asm("popfd");
1.90 + asm("pop edi");
1.91 + asm("pop esi");
1.92 + asm("pop ebx");
1.93 + asm("ret"); // finished - return value in EAX
1.94 + }
1.95 +
1.96 +
1.97 +// See header file e32cmn.h for the in-source documentation.
1.98 +EXPORT_C __NAKED__ TAny* memcpy(TAny* /*aTrg*/, const TAny* /*aSrc*/, unsigned int /*aLength*/)
1.99 + {
1.100 + asm("jmp %a0": :"i"(&memmove));
1.101 + }
1.102 +
1.103 +
1.104 +
1.105 +
1.106 +// See header file e32cmn.h for the in-source documentation.
1.107 +EXPORT_C __NAKED__ TAny* wordmove(TAny* /*aTrg*/, const TAny* /*aSrc*/, unsigned int /*aLength*/)
1.108 + {
1.109 + asm("push esi");
1.110 + asm("push edi");
1.111 + asm("mov edi,[esp+12]");// destination address into edi
1.112 + asm("mov esi,[esp+16]");// source address into esi
1.113 + asm("mov ecx,[esp+20]");// byte count into ecx
1.114 + asm("pushfd");
1.115 +
1.116 + asm("mov eax,edi"); // return value
1.117 + asm("cld"); //
1.118 + asm("test ecx,ecx"); //
1.119 + asm("jz short memmove0");// if length=0, nothing to do
1.120 + asm("cmp edi,esi"); // compare source and dest addresses
1.121 + asm("je short memmove0");// if equal, nothing to do
1.122 + asm("jc short memmove1");// if dest<source, must go forwards
1.123 + asm("std"); // else go backwards
1.124 + asm("lea esi,[esi+ecx-4]"); // and start at end of block - 4
1.125 + asm("lea edi,[edi+ecx-4]"); //
1.126 + asm("memmove1:");
1.127 + asm("shr ecx,2"); // ecx now contains number of dwords to move
1.128 + asm("rep movsd"); // do dword block move
1.129 +
1.130 + asm("memmove0:");
1.131 + asm("popfd");
1.132 + asm("pop edi");
1.133 + asm("pop esi");
1.134 + asm("ret"); // finished - return value in EAX
1.135 + }
1.136 +
1.137 +
1.138 +
1.139 +// See header file e32cmn.h for the in-source documentation.
1.140 +EXPORT_C __NAKED__ TAny* memset(TAny* /*aTrg*/, TInt /*aValue*/, unsigned int /*aLength*/)
1.141 + {
1.142 + asm("push edi");
1.143 + asm("mov edi,[esp+8]"); // destination address into edi
1.144 + asm("mov al,[esp+12]"); // fill value into al
1.145 + asm("mov ecx,[esp+16]");// number of bytes to fill into ecx
1.146 + asm("push edi"); // save destination for return value
1.147 + asm("pushfd");
1.148 + asm("cld"); // go forwards through array
1.149 + asm("test ecx,ecx"); //
1.150 + asm("jz short memfill0");// if length zero, nothing to do
1.151 + asm("cmp ecx,8"); // if array very small, just do byte fills
1.152 + asm("jb short memfill1");
1.153 +
1.154 + asm("mov ah,al"); // repeat al in all bytes of eax
1.155 + asm("movzx edx,ax"); //
1.156 + asm("shl eax,16"); //
1.157 + asm("or eax,edx"); //
1.158 + asm("mov edx,ecx"); // length into edx
1.159 + asm("mov ecx,4"); // number of byte fills to align = 4-[edi mod 4]
1.160 + asm("sub ecx,edi"); //
1.161 + asm("and ecx,3"); //
1.162 + asm("jz short memfill2");// if already aligned, proceed to dword fill
1.163 + asm("sub edx,ecx"); // subtract alignment bytes from length
1.164 + asm("rep stosb"); // do byte fills to align
1.165 + asm("memfill2:");
1.166 + asm("mov ecx,edx"); // length remaining into ecx
1.167 + asm("shr ecx,2"); // number of dwords to fill into ecx
1.168 + asm("rep stosd"); // perform dword fill
1.169 + asm("mov ecx,edx"); // calculate number of leftover bytes
1.170 + asm("and ecx,3"); // in ecx
1.171 + asm("jz short memfill0");// if none left, exit
1.172 + asm("memfill1:");
1.173 + asm("rep stosb"); // do byte fills to make up correct length
1.174 +
1.175 + asm("memfill0:");
1.176 + asm("popfd");
1.177 + asm("pop eax"); // return value
1.178 + asm("pop edi");
1.179 + asm("ret");
1.180 + }
1.181 +
1.182 +
1.183 +
1.184 +
1.185 +// See header file e32cmn.h for the in-source documentation.
1.186 +EXPORT_C __NAKED__ TAny* memclr(TAny* /*aTrg*/, unsigned int /*aLength*/)
1.187 + {
1.188 + asm("push edi");
1.189 + asm("mov edi,[esp+8]"); // destination address into edi
1.190 + asm("mov ecx,[esp+12]");// number of bytes to fill into ecx
1.191 + asm("xor eax, eax"); // fill value
1.192 + asm("push edi"); // save destination for return value
1.193 + asm("pushfd");
1.194 + asm("cld"); // go forwards through array
1.195 + asm("test ecx,ecx"); //
1.196 + asm("jz short memclr0");// if length zero, nothing to do
1.197 + asm("cmp ecx,8"); // if array very small, just do byte fills
1.198 + asm("jb short memclr1");
1.199 +
1.200 + asm("mov edx,ecx"); // length into edx
1.201 + asm("mov ecx,4"); // number of byte fills to align = 4-[edi mod 4]
1.202 + asm("sub ecx,edi"); //
1.203 + asm("and ecx,3"); //
1.204 + asm("jz short memclr2");// if already aligned, proceed to dword fill
1.205 + asm("sub edx,ecx"); // subtract alignment bytes from length
1.206 + asm("rep stosb"); // do byte fills to align
1.207 + asm("memclr2:");
1.208 + asm("mov ecx,edx"); // length remaining into ecx
1.209 + asm("shr ecx,2"); // number of dwords to fill into ecx
1.210 + asm("rep stosd"); // perform dword fill
1.211 + asm("mov ecx,edx"); // calculate number of leftover bytes
1.212 + asm("and ecx,3"); // in ecx
1.213 + asm("jz short memclr0");// if none left, exit
1.214 + asm("memclr1:");
1.215 + asm("rep stosb"); // do byte fills to make up correct length
1.216 +
1.217 + asm("memclr0:");
1.218 + asm("popfd");
1.219 + asm("pop eax"); // return value
1.220 + asm("pop edi");
1.221 + asm("ret");
1.222 + }
1.223 +
1.224 +
1.225 +
1.226 +//EXPORT_C __NAKED__ TInt Mem::Compare(const TUint8* /*aLeft*/, TInt /*aLeftL*/, const TUint8* /*aRight*/, TInt /*aRightL*/)
1.227 +// {
1.228 +// asm("jmp _memcompare");
1.229 +// }
1.230 +
1.231 +// See header file e32cmn.h for the in-source documentation.
1.232 +EXPORT_C __NAKED__ TInt memcompare(const TUint8* /*aLeft*/, TInt /*aLeftL*/, const TUint8* /*aRight*/, TInt /*aRightL*/)
1.233 + {
1.234 + asm("push esi");
1.235 + asm("push edi");
1.236 + asm("mov esi,[esp+12]");// left buffer address into esi
1.237 + asm("mov ecx,[esp+16]");// left buffer length into ecx
1.238 + asm("mov edi,[esp+20]");// right buffer address into edi
1.239 + asm("mov eax,[esp+24]");// right buffer length into eax
1.240 + asm("pushfd");
1.241 +
1.242 + asm("mov edx,ecx"); // edx = left len
1.243 + asm("cld"); // go forwards through arrays
1.244 + asm("sub edx,eax"); // edx = [left len - right len]
1.245 + asm("jbe short memcmp1");//
1.246 + asm("mov ecx,eax"); // ecx = min[ left len, right len ]
1.247 + asm("memcmp1:");
1.248 + asm("mov eax,edx"); // save length difference for later use
1.249 + asm("test ecx,ecx"); //
1.250 + asm("jz short memcmp0");// if length=0, nothing to compare
1.251 + asm("cmp ecx,8"); // for small buffers don't bother with alignment check
1.252 + asm("jc short memcmp2");//
1.253 + asm("mov edx,ecx"); // comparison length into edx
1.254 + asm("mov ecx,4"); // number of byte compares to align left ptr = 4-[esi mod 4]
1.255 + asm("sub ecx,esi"); //
1.256 + asm("and ecx,3"); // number of byte compares to align in ecx
1.257 + asm("jz short memcmp3");// if already aligned, proceed with dword compare
1.258 + asm("sub edx,ecx"); // subtract number of byte compares from length
1.259 + asm("repe cmpsb"); // do byte compares to align
1.260 + asm("jne short memcmp4");// if a difference was found, exit
1.261 + asm("memcmp3:");
1.262 + asm("mov ecx,edx"); // length back into ecx
1.263 + asm("shr ecx,2"); // number of dwords to compare
1.264 + asm("repe cmpsd"); // perform DWORD block comparison
1.265 + asm("je short memcmp5");// if no difference found, proceed with leftover bytes
1.266 + asm("mov eax,[esi-4]"); // differing left dword into eax [first char in al]
1.267 + asm("mov edx,[edi-4]"); // differing right dword into edx [first char in dl]
1.268 + asm("cmp al,dl"); // compare 1st chars
1.269 + asm("jne short memcmp7");// if difference found, exit
1.270 + asm("cmp ah,dh"); // compare 2nd chars
1.271 + asm("jne short memcmp6");// if difference found, exit
1.272 + asm("shr eax,16"); // 3rd and 4th chars into al, ah respectively
1.273 + asm("shr edx,16"); // 3rd and 4th chars into dl, dh respectively
1.274 + asm("cmp al,dl"); // compare 3rd chars
1.275 + asm("jne short memcmp7");// if difference found, exit, else 4th chars must differ
1.276 + asm("memcmp6:");
1.277 + asm("mov al,ah"); // differing bytes into al and dl
1.278 + asm("mov dl,dh"); //
1.279 + asm("memcmp7:");
1.280 + asm("movzx eax,al"); // zero extend al into eax
1.281 + asm("movzx edx,dl"); // zero extend dl into edx
1.282 + asm("jmp short memcmp8");// and exit with eax = difference of bytes
1.283 + asm("memcmp5:");
1.284 + asm("mov ecx,edx"); // length back into ecx
1.285 + asm("and ecx,3"); // number of remaining bytes to compare
1.286 + asm("jz short memcmp0");// if zero, exit with eax=length difference
1.287 + asm("memcmp2:"); // *** come here for small buffers
1.288 + asm("repe cmpsb"); // compare remaining bytes
1.289 + asm("je short memcmp0");// if no difference found, exit with eax=length difference
1.290 + asm("memcmp4:"); // *** come here if a byte has been compared and differs
1.291 + asm("movzx eax,byte ptr [esi-1]");
1.292 + asm("movzx edx,byte ptr [edi-1]");
1.293 + asm("memcmp8:");
1.294 + asm("sub eax,edx"); // return value is difference of bytes
1.295 +
1.296 + asm("memcmp0:"); // *** come here if common initial segment identical
1.297 + asm("popfd");
1.298 + asm("pop edi");
1.299 + asm("pop esi");
1.300 + asm("ret");
1.301 + }
1.302 +}
1.303 +#endif