Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

asm.h

Go to the documentation of this file.
00001 // See the end of this file for license information.
00002 
00003 #ifndef TORSION_ASM_H
00004 #define TORSION_ASM_H
00005 
00006 #include "types.h"
00007 
00008 inline void
00009 enable_interrupts() {
00010   asm volatile("sti");
00011 }
00012 
00013 inline void
00014 disable_interrupts() {
00015   asm volatile("cli");
00016 }
00017 
00018 inline bool
00019 atomic_test_and_set(bool& target) {
00020   Uint8 result;
00021                                                                                 
00022   asm volatile("lock; bts $0, %1\n"
00023                "setc %0"
00024              : "=r" (result), "=m" (target));
00025                                                                                 
00026   return result;
00027 }
00028 
00029 inline unsigned long long
00030 system_cycles() {
00031   unsigned long time_high, time_low;
00032 
00033   asm volatile("rdtsc" : "=d" (time_high), "=a" (time_low));
00034 
00035   return ((unsigned long long)time_high << 32) | time_low;
00036 }
00037 
00038 inline unsigned
00039 system_milliseconds(unsigned cycles_per_millisecond) {
00040   unsigned total_seconds;
00041 
00042   asm volatile("rdtsc\n"
00043                "divl %%ebx"
00044        : "=a" (total_seconds)
00045        : "b" (cycles_per_millisecond));
00046 
00047   return total_seconds;
00048 }
00049 
00050 // thank you, Linux kernel!
00051 // all the functions/macros that we don't use currently are #if 0'd out
00052 
00053 // send a byte out to a port
00054 inline void
00055 outb(unsigned short int value, unsigned port) {
00056   asm volatile("outb %%al, %%dx" : : "a" (value), "d" (port));
00057 }
00058 
00059 inline unsigned char
00060 inb(unsigned port) {
00061    unsigned char value;
00062    asm volatile("inb %%dx, %%al" : "=a" (value) : "d" (port));
00063    return value;
00064 }
00065 
00066 #if 0
00067 static inline char * strcpy(char * dest,const char *src)
00068 {
00069 int d0, d1, d2;
00070 __asm__ __volatile__(
00071   "1:\tlodsb\n\t"
00072   "stosb\n\t"
00073   "testb %%al,%%al\n\t"
00074   "jne 1b"
00075   : "=&S" (d0), "=&D" (d1), "=&a" (d2)
00076   :"0" (src),"1" (dest) : "memory");
00077 return dest;
00078 }
00079 
00080 static inline char * strncpy(char * dest,const char *src,Size count)
00081 {
00082 int d0, d1, d2, d3;
00083 __asm__ __volatile__(
00084   "1:\tdecl %2\n\t"
00085   "js 2f\n\t"
00086   "lodsb\n\t"
00087   "stosb\n\t"
00088   "testb %%al,%%al\n\t"
00089   "jne 1b\n\t"
00090   "rep\n\t"
00091   "stosb\n"
00092   "2:"
00093   : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
00094   :"0" (src),"1" (dest),"2" (count) : "memory");
00095 return dest;
00096 }
00097 
00098 static inline char * strcat(char * dest,const char * src)
00099 {
00100 int d0, d1, d2, d3;
00101 __asm__ __volatile__(
00102   "repne\n\t"
00103   "scasb\n\t"
00104   "decl %1\n"
00105   "1:\tlodsb\n\t"
00106   "stosb\n\t"
00107   "testb %%al,%%al\n\t"
00108   "jne 1b"
00109   : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
00110   : "0" (src), "1" (dest), "2" (0), "3" (0xffffffff):"memory");
00111 return dest;
00112 }
00113 
00114 static inline char * strncat(char * dest,const char * src,Size count)
00115 {
00116 int d0, d1, d2, d3;
00117 __asm__ __volatile__(
00118   "repne\n\t"
00119   "scasb\n\t"
00120   "decl %1\n\t"
00121   "movl %8,%3\n"
00122   "1:\tdecl %3\n\t"
00123   "js 2f\n\t"
00124   "lodsb\n\t"
00125   "stosb\n\t"
00126   "testb %%al,%%al\n\t"
00127   "jne 1b\n"
00128   "2:\txorl %2,%2\n\t"
00129   "stosb"
00130   : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
00131   : "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count)
00132   : "memory");
00133 return dest;
00134 }
00135 #endif
00136 
00137 static inline int strcmp(const char * cs,const char * ct)
00138 {
00139 int d0, d1;
00140 register int __res;
00141 __asm__ __volatile__(
00142   "1:\tlodsb\n\t"
00143   "scasb\n\t"
00144   "jne 2f\n\t"
00145   "testb %%al,%%al\n\t"
00146   "jne 1b\n\t"
00147   "xorl %%eax,%%eax\n\t"
00148   "jmp 3f\n"
00149   "2:\tsbbl %%eax,%%eax\n\t"
00150   "orb $1,%%al\n"
00151   "3:"
00152   :"=a" (__res), "=&S" (d0), "=&D" (d1)
00153          :"1" (cs),"2" (ct));
00154 return __res;
00155 }
00156 
00157 static inline int strncmp(const char * cs,const char * ct,Size count)
00158 {
00159 register int __res;
00160 int d0, d1, d2;
00161 __asm__ __volatile__(
00162   "1:\tdecl %3\n\t"
00163   "js 2f\n\t"
00164   "lodsb\n\t"
00165   "scasb\n\t"
00166   "jne 3f\n\t"
00167   "testb %%al,%%al\n\t"
00168   "jne 1b\n"
00169   "2:\txorl %%eax,%%eax\n\t"
00170   "jmp 4f\n"
00171   "3:\tsbbl %%eax,%%eax\n\t"
00172   "orb $1,%%al\n"
00173   "4:"
00174          :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
00175          :"1" (cs),"2" (ct),"3" (count));
00176 return __res;
00177 }
00178 
00179 #if 0
00180 static inline char * strchr(const char * s, int c)
00181 {
00182 int d0;
00183 register char * __res;
00184 __asm__ __volatile__(
00185   "movb %%al,%%ah\n"
00186   "1:\tlodsb\n\t"
00187   "cmpb %%ah,%%al\n\t"
00188   "je 2f\n\t"
00189   "testb %%al,%%al\n\t"
00190   "jne 1b\n\t"
00191   "movl $1,%1\n"
00192   "2:\tmovl %1,%0\n\t"
00193   "decl %0"
00194   :"=a" (__res), "=&S" (d0) : "1" (s),"0" (c));
00195 return __res;
00196 }
00197 
00198 static inline char * strrchr(const char * s, int c)
00199 {
00200 int d0, d1;
00201 register char * __res;
00202 __asm__ __volatile__(
00203   "movb %%al,%%ah\n"
00204   "1:\tlodsb\n\t"
00205   "cmpb %%ah,%%al\n\t"
00206   "jne 2f\n\t"
00207   "leal -1(%%esi),%0\n"
00208   "2:\ttestb %%al,%%al\n\t"
00209   "jne 1b"
00210   :"=g" (__res), "=&S" (d0), "=&a" (d1) :"0" (0),"1" (s),"2" (c));
00211 return __res;
00212 }
00213 #endif
00214 
00215 static inline Size strlen(const char * s)
00216 {
00217 int d0;
00218 register int __res;
00219 __asm__ __volatile__(
00220   "repne\n\t"
00221   "scasb\n\t"
00222   "notl %0\n\t"
00223   "decl %0"
00224   :"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff));
00225 return __res;
00226 }
00227 
00228 static inline void * __memcpy(void * to, const void * from, Size n)
00229 {
00230 int d0, d1, d2;
00231 __asm__ __volatile__(
00232   "rep ; movsl\n\t"
00233   "testb $2,%b4\n\t"
00234   "je 1f\n\t"
00235   "movsw\n"
00236   "1:\ttestb $1,%b4\n\t"
00237   "je 2f\n\t"
00238   "movsb\n"
00239   "2:"
00240   : "=&c" (d0), "=&D" (d1), "=&S" (d2)
00241   :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
00242   : "memory");
00243 return (to);
00244 }
00245 
00246 /*
00247  * This looks horribly ugly, but the compiler can optimize it totally,
00248  * as the count is constant.
00249  */
00250 static inline void * __constant_memcpy(void * to, const void * from, Size n)
00251 {
00252   switch (n) {
00253     case 0:
00254       return to;
00255     case 1:
00256       *(unsigned char *)to = *(const unsigned char *)from;
00257       return to;
00258     case 2:
00259       *(unsigned short *)to = *(const unsigned short *)from;
00260       return to;
00261     case 3:
00262       *(unsigned short *)to = *(const unsigned short *)from;
00263       *(2+(unsigned char *)to) = *(2+(const unsigned char *)from);
00264       return to;
00265     case 4:
00266       *(unsigned long *)to = *(const unsigned long *)from;
00267       return to;
00268     case 6: /* for Ethernet addresses */
00269       *(unsigned long *)to = *(const unsigned long *)from;
00270       *(2+(unsigned short *)to) = *(2+(const unsigned short *)from);
00271       return to;
00272     case 8:
00273       *(unsigned long *)to = *(const unsigned long *)from;
00274       *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
00275       return to;
00276     case 12:
00277       *(unsigned long *)to = *(const unsigned long *)from;
00278       *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
00279       *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
00280       return to;
00281     case 16:
00282       *(unsigned long *)to = *(const unsigned long *)from;
00283       *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
00284       *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
00285       *(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
00286       return to;
00287     case 20:
00288       *(unsigned long *)to = *(const unsigned long *)from;
00289       *(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
00290       *(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
00291       *(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
00292       *(4+(unsigned long *)to) = *(4+(const unsigned long *)from);
00293       return to;
00294   }
00295 #define COMMON(x) \
00296 __asm__ __volatile__( \
00297   "rep ; movsl" \
00298   x \
00299   : "=&c" (d0), "=&D" (d1), "=&S" (d2) \
00300   : "0" (n/4),"1" ((long) to),"2" ((long) from) \
00301   : "memory");
00302 {
00303   int d0, d1, d2;
00304   switch (n % 4) {
00305     case 0: COMMON(""); return to;
00306     case 1: COMMON("\n\tmovsb"); return to;
00307     case 2: COMMON("\n\tmovsw"); return to;
00308     default: COMMON("\n\tmovsw\n\tmovsb"); return to;
00309   }
00310 }
00311   
00312 #undef COMMON
00313 }
00314 
00315 #define memcpy(t, f, n) \
00316 (__builtin_constant_p(n) ? \
00317  __constant_memcpy((t),(f),(n)) : \
00318  __memcpy((t),(f),(n)))
00319 
00320 #if 0
00321 /*
00322  * struct_cpy(x,y), copy structure *x into (matching structure) *y.
00323  *
00324  * We get link-time errors if the structure sizes do not match.
00325  * There is no runtime overhead, it's all optimized away at
00326  * compile time.
00327  */
00328 extern void __struct_cpy_bug (void);
00329 
00330 #define struct_cpy(x,y)       \
00331 ({            \
00332   if (sizeof(*(x)) != sizeof(*(y)))   \
00333     __struct_cpy_bug;   \
00334   memcpy(x, y, sizeof(*(x)));   \
00335 })
00336 #endif
00337 
00338 static inline void * memmove(void * dest,const void * src, Size n)
00339 {
00340 int d0, d1, d2;
00341 if (dest<src)
00342 __asm__ __volatile__(
00343   "rep\n\t"
00344   "movsb"
00345   : "=&c" (d0), "=&S" (d1), "=&D" (d2)
00346   :"0" (n),"1" (src),"2" (dest)
00347   : "memory");
00348 else
00349 __asm__ __volatile__(
00350   "std\n\t"
00351   "rep\n\t"
00352   "movsb\n\t"
00353   "cld"
00354   : "=&c" (d0), "=&S" (d1), "=&D" (d2)
00355   :"0" (n),
00356    "1" (n-1+(const char *)src),
00357    "2" (n-1+(char *)dest)
00358   :"memory");
00359 return dest;
00360 }
00361 
00362 #if 0
00363 #define memcmp __builtin_memcmp
00364 
00365 static inline void * memchr(const void * cs,int c,Size count)
00366 {
00367 int d0;
00368 register void * __res;
00369 if (!count)
00370   return NULL;
00371 __asm__ __volatile__(
00372   "repne\n\t"
00373   "scasb\n\t"
00374   "je 1f\n\t"
00375   "movl $1,%0\n"
00376   "1:\tdecl %0"
00377   :"=D" (__res), "=&c" (d0) : "a" (c),"0" (cs),"1" (count));
00378 return __res;
00379 }
00380 #endif
00381 
00382 static inline void * __memset_generic(void * s, char c,Size count)
00383 {
00384 int d0, d1;
00385 __asm__ __volatile__(
00386   "rep\n\t"
00387   "stosb"
00388   : "=&c" (d0), "=&D" (d1)
00389   :"a" (c),"1" (s),"0" (count)
00390   :"memory");
00391 return s;
00392 }
00393 
00394 /* we might want to write optimized versions of these later */
00395 #define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
00396 
00397 /*
00398  * memset(x,0,y) is a reasonably common thing to do, so we want to fill
00399  * things 32 bits at a time even when we don't know the size of the
00400  * area at compile-time..
00401  */
00402 static inline void * __constant_c_memset(void * s, unsigned long c, Size count)
00403 {
00404 int d0, d1;
00405 __asm__ __volatile__(
00406   "rep ; stosl\n\t"
00407   "testb $2,%b3\n\t"
00408   "je 1f\n\t"
00409   "stosw\n"
00410   "1:\ttestb $1,%b3\n\t"
00411   "je 2f\n\t"
00412   "stosb\n"
00413   "2:"
00414   : "=&c" (d0), "=&D" (d1)
00415   :"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
00416   :"memory");
00417 return (s); 
00418 }
00419 
00420 #if 0
00421 /* Added by Gertjan van Wingerde to make minix and sysv module work */
00422 static inline Size strnlen(const char * s, Size count)
00423 {
00424 int d0;
00425 register int __res;
00426 __asm__ __volatile__(
00427   "movl %2,%0\n\t"
00428   "jmp 2f\n"
00429   "1:\tcmpb $0,(%0)\n\t"
00430   "je 3f\n\t"
00431   "incl %0\n"
00432   "2:\tdecl %1\n\t"
00433   "cmpl $-1,%1\n\t"
00434   "jne 1b\n"
00435   "3:\tsubl %2,%0"
00436   :"=a" (__res), "=&d" (d0)
00437   :"c" (s),"1" (count));
00438 return __res;
00439 }
00440 /* end of additional stuff */
00441 
00442 extern char *strstr(const char *cs, const char *ct);
00443 #endif
00444 
00445 /*
00446  * This looks horribly ugly, but the compiler can optimize it totally,
00447  * as we by now know that both pattern and count is constant..
00448  */
00449 static inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, Size count)
00450 {
00451   switch (count) {
00452     case 0:
00453       return s;
00454     case 1:
00455       *(unsigned char *)s = pattern;
00456       return s;
00457     case 2:
00458       *(unsigned short *)s = pattern;
00459       return s;
00460     case 3:
00461       *(unsigned short *)s = pattern;
00462       *(2+(unsigned char *)s) = pattern;
00463       return s;
00464     case 4:
00465       *(unsigned long *)s = pattern;
00466       return s;
00467   }
00468 #define COMMON(x) \
00469 __asm__  __volatile__( \
00470   "rep ; stosl" \
00471   x \
00472   : "=&c" (d0), "=&D" (d1) \
00473   : "a" (pattern),"0" (count/4),"1" ((long) s) \
00474   : "memory")
00475 {
00476   int d0, d1;
00477   switch (count % 4) {
00478     case 0: COMMON(""); return s;
00479     case 1: COMMON("\n\tstosb"); return s;
00480     case 2: COMMON("\n\tstosw"); return s;
00481     default: COMMON("\n\tstosw\n\tstosb"); return s;
00482   }
00483 }
00484   
00485 #undef COMMON
00486 }
00487 
00488 #define __constant_c_x_memset(s, c, count) \
00489 (__builtin_constant_p(count) ? \
00490  __constant_c_and_count_memset((s),(c),(count)) : \
00491  __constant_c_memset((s),(c),(count)))
00492 
00493 #define __memset(s, c, count) \
00494 (__builtin_constant_p(count) ? \
00495  __constant_count_memset((s),(c),(count)) : \
00496  __memset_generic((s),(c),(count)))
00497 
00498 #define __HAVE_ARCH_MEMSET
00499 #define memset(s, c, count) \
00500 (__builtin_constant_p(c) ? \
00501  __constant_c_x_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) : \
00502  __memset((s),(c),(count)))
00503 
00504 #if 0
00505 /*
00506  * find the first occurrence of byte 'c', or 1 past the area if none
00507  */
00508 #define __HAVE_ARCH_MEMSCAN
00509 static inline void * memscan(void * addr, int c, Size size)
00510 {
00511   if (!size)
00512     return addr;
00513   __asm__("repnz; scasb\n\t"
00514     "jnz 1f\n\t"
00515     "dec %%edi\n"
00516     "1:"
00517     : "=D" (addr), "=c" (size)
00518     : "0" (addr), "1" (size), "a" (c));
00519   return addr;
00520 }
00521 
00528 static __inline__ unsigned long ffz(unsigned long word)
00529 {
00530   __asm__("bsfl %1,%0"
00531     :"=r" (word)
00532     :"r" (~word));
00533   return word;
00534 }
00535 
00544 static __inline__ int ffs(int x)
00545 {
00546   int r;
00547 
00548   __asm__("bsfl %1,%0\n\t"
00549     "jnz 1f\n\t"
00550     "movl $-1,%0\n"
00551     "1:" : "=r" (r) : "g" (x));
00552   return r+1;
00553 }
00554 #endif
00555 
00556 #endif
00557 
00558 /* Torsion Operating System, Copyright (C) 2000-2004 Dan Helfman
00559  *
00560  * This program is free software; you can redistribute it and/or modify it
00561  * under the terms of the GNU General Public License as published by the
00562  * Free Software Foundation; either version 2 of the License, or (at your
00563  * option) any later version.
00564  * 
00565  * This program is distributed in the hope that it will be useful, but
00566  * WITHOUT ANY WARRANTY; without even the implied warranty of
00567  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00568  * General Public License for more details (in the COPYING file).
00569  * 
00570  * You should have received a copy of the GNU General Public License along
00571  * with this program; if not, write to the Free Software Foundation, Inc.,
00572  * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00573  */

Torsion Operating System, Copyright (C) 2000-2004 Dan Helfman