/xbmc/visualizations/Vortex/angelscript/angelscript/source/as_callfunc_sh4.cpp

http://github.com/xbmc/xbmc · C++ · 517 lines · 375 code · 60 blank · 82 comment · 66 complexity · b10ad81834371ded448edc4488577459 MD5 · raw file

  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2009 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. andreas@angelcode.com
  22. */
  23. //
  24. // as_callfunc_sh4.cpp
  25. //
  26. // These functions handle the actual calling of system functions
  27. //
  28. // This version is SH4 specific and was originally written
  29. // by Fredrik Ehnbom in May, 2004
  30. // Later updated for angelscript 2.0.0 by Fredrik Ehnbom in Jan, 2005
  31. // References:
  32. // * http://www.renesas.com/avs/resource/japan/eng/pdf/mpumcu/e602156_sh4.pdf
  33. // * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcechp40/html/_callsh4_SH_4_Calling_Standard.asp
  34. #include "as_config.h"
  35. #ifndef MAX_PORTABILITY
  36. #ifdef AS_SH4
  37. #include "as_callfunc.h"
  38. #include "as_scriptengine.h"
  39. #include "as_texts.h"
  40. #include "as_tokendef.h"
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. BEGIN_AS_NAMESPACE
  44. #define AS_SH4_MAX_ARGS 32
  45. // The array used to send values to the correct places.
  46. // first 0-4 regular values to load into the r4-r7 registers
  47. // then 0-8 float values to load into the fr4-fr11 registers
  48. // then (AS_SH4_MAX_ARGS - 12) values to load onto the stack
  49. // the +1 is for when CallThis (object methods) is used
  50. // extra +1 when returning in memory
  51. extern "C" {
  52. static asDWORD sh4Args[AS_SH4_MAX_ARGS + 1 + 1];
  53. }
  54. // Loads all data into the correct places and calls the function.
  55. // intArgSize is the size in bytes for how much data to put in int registers
  56. // floatArgSize is the size in bytes for how much data to put in float registers
  57. // stackArgSize is the size in bytes for how much data to put on the callstack
  58. extern "C" asQWORD sh4Func(int intArgSize, int floatArgSize, int stackArgSize, asDWORD func);
  59. asm(""
  60. " .align 4\n"
  61. " .global _sh4Func\n"
  62. "_sh4Func:\n"
  63. " mov.l r14,@-r15\n"
  64. " mov.l r13,@-r15\n"
  65. " mov.l r12,@-r15\n"
  66. " sts.l pr,@-r15\n" // must be saved since we call a subroutine
  67. " mov r7, r14\n" // func
  68. " mov r6, r13\n" // stackArgSize
  69. " mov.l r5,@-r15\n" // floatArgSize
  70. " mov.l sh4Args,r0\n"
  71. " pref @r0\n"
  72. " mov r4, r1\n" // intArgsize
  73. " mov #33*4,r2\n"
  74. " extu.b r2,r2\n" // make unsigned (33*4 = 132 => 128)
  75. " mov.l @(r0,r2), r2\n" // r2 has adress for when returning in memory
  76. "_sh4f_intarguments:\n" // copy all the int arguments to the respective registers
  77. " mov #4*2*2,r3\n" // calculate how many bytes to skip
  78. " sub r1,r3\n"
  79. " braf r3\n"
  80. " add #-4,r1\n" // we are indexing the array backwards, so subtract one (delayed slot)
  81. " mov.l @(r0,r1),r7\n" // 4 arguments
  82. " add #-4,r1\n"
  83. " mov.l @(r0,r1),r6\n" // 3 arguments
  84. " add #-4,r1\n"
  85. " mov.l @(r0,r1),r5\n" // 2 arguments
  86. " add #-4,r1\n"
  87. " mov.l @(r0,r1),r4\n" // 1 argument
  88. " nop\n"
  89. "_sh4f_floatarguments:\n" // copy all the float arguments to the respective registers
  90. " add #4*4, r0\n"
  91. " mov.l @r15+,r1\n" // floatArgSize
  92. " mov #8*2*2,r3\n" // calculate how many bytes to skip
  93. " sub r1,r3\n"
  94. " braf r3\n"
  95. " add #-4,r1\n" // we are indexing the array backwards, so subtract one (delayed slot)
  96. " fmov.s @(r0,r1),fr11\n" // 8 arguments
  97. " add #-4,r1\n"
  98. " fmov.s @(r0,r1),fr10\n" // 7 arguments
  99. " add #-4,r1\n"
  100. " fmov.s @(r0,r1),fr9\n" // 6 arguments
  101. " add #-4,r1\n"
  102. " fmov.s @(r0,r1),fr8\n" // 5 arguments
  103. " add #-4,r1\n"
  104. " fmov.s @(r0,r1),fr7\n" // 4 arguments
  105. " add #-4,r1\n"
  106. " fmov.s @(r0,r1),fr6\n" // 3 arguments
  107. " add #-4,r1\n"
  108. " fmov.s @(r0,r1),fr5\n" // 2 arguments
  109. " add #-4,r1\n"
  110. " fmov.s @(r0,r1),fr4\n" // 1 argument
  111. " nop\n"
  112. "_sh4f_stackarguments:\n" // copy all the stack argument onto the stack
  113. " add #8*4, r0\n"
  114. " mov r0, r1\n"
  115. " mov #0, r0\n" // init position counter (also used as a 0-check on the line after)
  116. " cmp/eq r0, r13\n"
  117. " bt _sh4f_functioncall\n" // no arguments to push onto the stack
  118. " mov r13, r3\n" // stackArgSize
  119. " sub r3,r15\n" // "allocate" space on the stack
  120. " shlr2 r3\n" // make into a counter
  121. "_sh4f_stackloop:\n"
  122. " mov.l @r1+, r12\n"
  123. " mov.l r12, @(r0, r15)\n"
  124. " add #4, r0\n"
  125. " dt r3\n"
  126. " bf _sh4f_stackloop\n"
  127. "_sh4f_functioncall:\n"
  128. " jsr @r14\n" // no arguments
  129. " nop\n"
  130. " add r13, r15\n" // restore stack position
  131. " lds.l @r15+,pr\n"
  132. " mov.l @r15+, r12\n"
  133. " mov.l @r15+, r13\n"
  134. " rts\n"
  135. " mov.l @r15+, r14\n" // delayed slot
  136. "\n"
  137. " .align 4\n"
  138. "sh4Args:\n"
  139. " .long _sh4Args\n"
  140. );
  141. // puts the arguments in the correct place in the sh4Args-array. See comments above.
  142. // This could be done better.
  143. inline void splitArgs(const asDWORD *args, int argNum, int &numRegIntArgs, int &numRegFloatArgs, int &numRestArgs, int hostFlags) {
  144. int i;
  145. int argBit = 1;
  146. for (i = 0; i < argNum; i++) {
  147. if (hostFlags & argBit) {
  148. if (numRegFloatArgs < 12 - 4) {
  149. // put in float register
  150. sh4Args[4 + numRegFloatArgs] = args[i];
  151. numRegFloatArgs++;
  152. } else {
  153. // put in stack
  154. sh4Args[4 + 8 + numRestArgs] = args[i];
  155. numRestArgs++;
  156. }
  157. } else {
  158. if (numRegIntArgs < 8 - 4) {
  159. // put in int register
  160. sh4Args[numRegIntArgs] = args[i];
  161. numRegIntArgs++;
  162. } else {
  163. // put in stack
  164. sh4Args[4 + 8 + numRestArgs] = args[i];
  165. numRestArgs++;
  166. }
  167. }
  168. argBit <<= 1;
  169. }
  170. }
  171. asQWORD CallCDeclFunction(const asDWORD *args, int argSize, asDWORD func, int flags)
  172. {
  173. int argNum = argSize >> 2;
  174. int intArgs = 0;
  175. int floatArgs = 0;
  176. int restArgs = 0;
  177. // put the arguments in the correct places in the sh4Args array
  178. if (argNum > 0)
  179. splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags);
  180. return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func);
  181. }
  182. // This function is identical to CallCDeclFunction, with the only difference that
  183. // the value in the first parameter is the object
  184. asQWORD CallThisCallFunction(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags)
  185. {
  186. int argNum = argSize >> 2;
  187. int intArgs = 1;
  188. int floatArgs = 0;
  189. int restArgs = 0;
  190. sh4Args[0] = (asDWORD) obj;
  191. // put the arguments in the correct places in the sh4Args array
  192. if (argNum >= 1)
  193. splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags);
  194. return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func);
  195. }
  196. // This function is identical to CallCDeclFunction, with the only difference that
  197. // the value in the last parameter is the object
  198. asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags)
  199. {
  200. int argNum = argSize >> 2;
  201. int intArgs = 0;
  202. int floatArgs = 0;
  203. int restArgs = 0;
  204. // put the arguments in the correct places in the sh4Args array
  205. if (argNum >= 1)
  206. splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags);
  207. if (intArgs < 4) {
  208. sh4Args[intArgs] = (asDWORD) obj;
  209. intArgs++;
  210. } else {
  211. sh4Args[4 + 8 + restArgs] = (asDWORD) obj;
  212. restArgs++;
  213. }
  214. return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func);
  215. }
  216. asDWORD GetReturnedFloat()
  217. {
  218. asDWORD f;
  219. asm("fmov.s fr0, %0\n" : "=m"(f));
  220. return f;
  221. }
  222. // sizeof(double) == 4 with sh-elf-gcc (3.4.0) -m4
  223. // so this isn't really used...
  224. asQWORD GetReturnedDouble()
  225. {
  226. asQWORD d;
  227. asm("fmov dr0, %0\n" : "=m"(d));
  228. return d;
  229. }
  230. int CallSystemFunction(int id, asCContext *context, void *objectPointer)
  231. {
  232. asCScriptEngine *engine = context->engine;
  233. asSSystemFunctionInterface *sysFunc = engine->scriptFunctions[id]->sysFuncIntf;
  234. int callConv = sysFunc->callConv;
  235. if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD )
  236. return context->CallGeneric(id, objectPointer);
  237. asQWORD retQW = 0;
  238. asCScriptFunction *descr = engine->scriptFunctions[id];
  239. void *func = (void*)sysFunc->func;
  240. int paramSize = sysFunc->paramSize;
  241. asDWORD *args = context->regs.stackPointer;
  242. void *retPointer = 0;
  243. void *obj = 0;
  244. asDWORD *vftable;
  245. int popSize = paramSize;
  246. context->regs.objectType = descr->returnType.GetObjectType();
  247. if( descr->returnType.IsObject() && !descr->returnType.IsReference() && !descr->returnType.IsObjectHandle() )
  248. {
  249. // Allocate the memory for the object
  250. retPointer = engine->CallAlloc(descr->returnType.GetObjectType());
  251. sh4Args[AS_SH4_MAX_ARGS+1] = (asDWORD) retPointer;
  252. if( sysFunc->hostReturnInMemory )
  253. {
  254. // The return is made in memory
  255. callConv++;
  256. }
  257. }
  258. if( callConv >= ICC_THISCALL )
  259. {
  260. if( objectPointer )
  261. {
  262. obj = objectPointer;
  263. }
  264. else
  265. {
  266. // The object pointer should be popped from the context stack
  267. popSize++;
  268. // Check for null pointer
  269. obj = (void*)*(args + paramSize);
  270. if( obj == 0 )
  271. {
  272. context->SetInternalException(TXT_NULL_POINTER_ACCESS);
  273. if( retPointer )
  274. engine->CallFree(retPointer);
  275. return 0;
  276. }
  277. // Add the base offset for multiple inheritance
  278. obj = (void*)(int(obj) + sysFunc->baseOffset);
  279. }
  280. }
  281. asASSERT(descr->parameterTypes.GetLength() <= 32);
  282. // mark all float arguments
  283. int argBit = 1;
  284. int hostFlags = 0;
  285. int intArgs = 0;
  286. for( int a = 0; a < descr->parameterTypes.GetLength(); a++ ) {
  287. if (descr->parameterTypes[a].IsFloatType()) {
  288. hostFlags |= argBit;
  289. } else intArgs++;
  290. argBit <<= 1;
  291. }
  292. asDWORD paramBuffer[64];
  293. if( sysFunc->takesObjByVal )
  294. {
  295. paramSize = 0;
  296. int spos = 0;
  297. int dpos = 1;
  298. for( int n = 0; n < descr->parameterTypes.GetLength(); n++ )
  299. {
  300. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
  301. {
  302. #ifdef COMPLEX_OBJS_PASSED_BY_REF
  303. if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
  304. {
  305. paramBuffer[dpos++] = args[spos++];
  306. paramSize++;
  307. }
  308. else
  309. #endif
  310. {
  311. // Copy the object's memory to the buffer
  312. memcpy(&paramBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
  313. // Delete the original memory
  314. engine->CallFree(*(char**)(args+spos));
  315. spos++;
  316. dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
  317. paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
  318. }
  319. }
  320. else
  321. {
  322. // Copy the value directly
  323. paramBuffer[dpos++] = args[spos++];
  324. if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
  325. paramBuffer[dpos++] = args[spos++];
  326. paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
  327. }
  328. }
  329. // Keep a free location at the beginning
  330. args = &paramBuffer[1];
  331. }
  332. context->isCallingSystemFunction = true;
  333. switch( callConv )
  334. {
  335. case ICC_CDECL:
  336. case ICC_CDECL_RETURNINMEM:
  337. case ICC_STDCALL:
  338. case ICC_STDCALL_RETURNINMEM:
  339. retQW = CallCDeclFunction(args, paramSize<<2, (asDWORD)func, hostFlags);
  340. break;
  341. case ICC_THISCALL:
  342. case ICC_THISCALL_RETURNINMEM:
  343. retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags);
  344. break;
  345. case ICC_VIRTUAL_THISCALL:
  346. case ICC_VIRTUAL_THISCALL_RETURNINMEM:
  347. // Get virtual function table from the object pointer
  348. vftable = *(asDWORD**)obj;
  349. retQW = CallThisCallFunction(obj, args, paramSize<<2, vftable[asDWORD(func)>>2], hostFlags);
  350. break;
  351. case ICC_CDECL_OBJLAST:
  352. case ICC_CDECL_OBJLAST_RETURNINMEM:
  353. retQW = CallThisCallFunction_objLast(obj, args, paramSize<<2, (asDWORD)func, hostFlags);
  354. break;
  355. case ICC_CDECL_OBJFIRST:
  356. case ICC_CDECL_OBJFIRST_RETURNINMEM:
  357. retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags);
  358. break;
  359. default:
  360. context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
  361. }
  362. context->isCallingSystemFunction = false;
  363. #ifdef COMPLEX_OBJS_PASSED_BY_REF
  364. if( sysFunc->takesObjByVal )
  365. {
  366. // Need to free the complex objects passed by value
  367. args = context->regs.stackPointer;
  368. if( callConv >= ICC_THISCALL && !objectPointer )
  369. args++;
  370. int spos = 0;
  371. for( int n = 0; n < descr->parameterTypes.GetLength(); n++ )
  372. {
  373. if( descr->parameterTypes[n].IsObject() &&
  374. !descr->parameterTypes[n].IsReference() &&
  375. (descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK) )
  376. {
  377. void *obj = (void*)args[spos++];
  378. asSTypeBehaviour *beh = &descr->parameterTypes[n].GetObjectType()->beh;
  379. if( beh->destruct )
  380. engine->CallObjectMethod(obj, beh->destruct);
  381. engine->CallFree(obj);
  382. }
  383. else
  384. spos += descr->parameterTypes[n].GetSizeInMemoryDWords();
  385. }
  386. }
  387. #endif
  388. // Store the returned value in our stack
  389. if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
  390. {
  391. if( descr->returnType.IsObjectHandle() )
  392. {
  393. context->regs.objectRegister = (void*)(asDWORD)retQW;
  394. if( sysFunc->returnAutoHandle && context->regs.objectRegister )
  395. engine->CallObjectMethod(context->regs.objectRegister, descr->returnType.GetObjectType()->beh.addref);
  396. }
  397. else
  398. {
  399. if( !sysFunc->hostReturnInMemory )
  400. {
  401. // Copy the returned value to the pointer sent by the script engine
  402. if( sysFunc->hostReturnSize == 1 )
  403. *(asDWORD*)retPointer = (asDWORD)retQW;
  404. else
  405. *(asQWORD*)retPointer = retQW;
  406. }
  407. // Store the object in the register
  408. context->regs.objectRegister = retPointer;
  409. }
  410. }
  411. else
  412. {
  413. // Store value in valueRegister
  414. if( sysFunc->hostReturnFloat )
  415. {
  416. if( sysFunc->hostReturnSize == 1 )
  417. *(asDWORD*)&context->regs.valueRegister = GetReturnedFloat();
  418. else
  419. context->regs.valueRegister = GetReturnedDouble();
  420. }
  421. else if( sysFunc->hostReturnSize == 1 )
  422. *(asDWORD*)&context->regs.valueRegister = (asDWORD)retQW;
  423. else
  424. context->regs.valueRegister = retQW;
  425. }
  426. if( sysFunc->hasAutoHandles )
  427. {
  428. args = context->regs.stackPointer;
  429. if( callConv >= ICC_THISCALL && !objectPointer )
  430. args++;
  431. int spos = 0;
  432. for( int n = 0; n < descr->parameterTypes.GetLength(); n++ )
  433. {
  434. if( sysFunc->paramAutoHandles[n] && args[spos] )
  435. {
  436. // Call the release method on the type
  437. engine->CallObjectMethod((void*)args[spos], descr->parameterTypes[n].GetObjectType()->beh.release);
  438. args[spos] = 0;
  439. }
  440. if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
  441. spos++;
  442. else
  443. spos += descr->parameterTypes[n].GetSizeOnStackDWords();
  444. }
  445. }
  446. return popSize;
  447. }
  448. END_AS_NAMESPACE
  449. #endif // AS_SH4
  450. #endif // AS_MAX_PORTABILITY