Jump to content

  • Log In with Google      Sign In   
  • Create Account

- - - - -

Angelscript on Raspberry Pi


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
131 replies to this topic

#81 Andreas Jonsson   Moderators   -  Reputation: 3445

Like
0Likes
Like

Posted 06 December 2012 - 05:57 PM

It does.

How many tests are still failing now?

I still haven't had the chance to log in to your environment to test it on my own.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Sponsor:

#82 Tzarls   Members   -  Reputation: 916

Like
0Likes
Like

Posted 07 December 2012 - 12:38 AM

Well, the string test that was failing now passes, but when performing a general pass I´ve found that I´ve managed to break a test that previously passed (not related to the r11 thing) so I´m trying to fix that before continuing fixing the other failing tests.

EDIT: False alarm, everything that was working before is working now - I must have messed something when testing.
The test that are still failing are:

TestRegisterType
TestVector3
TestStdString

Edited by Tzarls, 07 December 2012 - 01:34 AM.


#83 Andreas Jonsson   Moderators   -  Reputation: 3445

Like
0Likes
Like

Posted 07 December 2012 - 08:38 AM

It's progressing well then. I would think it's just a few minor adjustments left to make.

Where in the tests are the failures happening?
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#84 Tzarls   Members   -  Reputation: 916

Like
0Likes
Like

Posted 07 December 2012 - 03:15 PM

Well, the test_registertype is failing in the TestIrrTypes() function. The dim2f constructor is called, receives the values with no problem and creates an object that when inspected seems to be ok. But then when the script calls operator+ for the total_res = video_res + video_res; part, the "other" object is ok, but our own members (this->Width and this->Height) have wrong values.

The other tests I haven´t checked yet. I´m facing one bug at a time.

#85 Andreas Jonsson   Moderators   -  Reputation: 3445

Like
0Likes
Like

Posted 07 December 2012 - 05:30 PM

The operator+ method should most likely be called like this:

this pointer in r0
other pointer in r1
return value will be placed in s0, s1

It might be a good idea to dissembly the operator+ method to confirm that this is actually what the method does.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#86 Tzarls   Members   -  Reputation: 916

Like
0Likes
Like

Posted 08 December 2012 - 12:26 AM

Well, operator+ uses the armFuncR0R1 function, and that´s one of the functions I haven´t changed, so that might be the problem.

#87 Andreas Jonsson   Moderators   -  Reputation: 3445

Like
0Likes
Like

Posted 08 December 2012 - 06:55 AM

That would mean that AngelScript thinks the dim2f is supposed to be returned in memory. I'm not certain this is true.

If it was I think it would have worked as the function is not taking any floats.

I think it is necessary to disassemble the operator. So we can be certain what the function actually looks like.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#88 quarnster   Members   -  Reputation: 266

Like
0Likes
Like

Posted 10 December 2012 - 03:56 AM

Long thread so this might have been mentioned already, but I wanted to make it explicit that passing floating point values in floating point registers (aka hard float) isn't a Raspberry Pi specific thing, and you can in fact get a soft-float (floating point values in int registers) Raspberry Pi OS from http://www.raspberrypi.org/downloads

If you make sure to never pass any floats between your program and pre compiled lib you could also (in theorytm) use the hard float call convention in your programs on Android/iPhone/WinCE by providing the appropriate float abi flags to the compilers.

#89 Andreas Jonsson   Moderators   -  Reputation: 3445

Like
0Likes
Like

Posted 10 December 2012 - 06:54 AM

Yeah, the thread started out as a Raspberry Pi specific thing, but we soon saw that it was a generic Linux/ARM system.

It's interesting to see that there are multiple variants though. Do you have any idea if there is any macro defined that will allow me to differentiate between the use of soft-floats and hard-floats in as_config.h?
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#90 Tzarls   Members   -  Reputation: 916

Like
0Likes
Like

Posted 10 December 2012 - 06:46 PM

Sorry for the delay. Here are the disassemblies for operator+:
Code:
#include <iostream>
#include <string>
typedef unsigned long asDWORD;
template <class T>
class dimension2d
{
public:
  dimension2d() : Width(0), Height(0) {}
  dimension2d(const T& width, const T& height) :
   Width(width), Height(height) {}
  template <class U>
  explicit dimension2d(const dimension2d<U>& other) :
   Width((T)other.Width), Height((T)other.Height) { }
  template <class U>
  dimension2d<T>& operator=(const dimension2d<U>& other)
  {
   Width = (T) other.Width;
   Height = (T) other.Height;
   return *this;
  }
  dimension2d<T> operator+(const dimension2d<T>& other) const
  {
   return dimension2d<T>(Width+other.Width, Height+other.Height);
  }
  T Width;
  T Height;
};
int main()
{
    dimension2d<float> video_res(800,600);
    dimension2d<float> total_res;
    total_res = video_res + video_res;
    std::cout << "X: " << total_res.Width  << ".\n";
    std::cout << "Y: " << total_res.Height << ".\n";
    return 0;
}
main:
0x8620 push {r11, lr}
0x8624 add r11, sp, #4
0x8628 sub sp, sp, #32
0x862c ldr r3, [pc, #212] ; 0x8708 <main()+232>
0x8630 str r3, [r11, #-12]
0x8634 ldr r3, [pc, #208] ; 0x870c <main()+236>
0x8638 str r3, [r11, #-8]
0x863c sub r1, r11, #20
0x8640 sub r2, r11, #12
0x8644 sub r3, r11, #8
0x8648 mov r0, r1
0x864c mov r1, r2
0x8650 mov r2, r3
0x8654 bl 0x87a0 <dimension2d<float>::dimension2d(float const&, float const&)>
0x8658 sub r3, r11, #28
0x865c mov r0, r3
0x8660 bl 0x87ec <dimension2d<float>::dimension2d()>
0x8664 sub r2, r11, #20
0x8668 sub r3, r11, #20
0x866c mov r0, r2
0x8670 mov r1, r3
0x8674 bl 0x882c <dimension2d<float>::operator+(dimension2d<float> const&) const>
0x8678 vmov.f32 s14, s0
0x867c vmov.f32 s15, s1
0x8680 vstr s14, [r11, #-36] ; 0xffffffdc
0x8684 vstr s15, [r11, #-32] ; 0xffffffe0
0x8688 sub r3, r11, #28
0x868c sub r2, r11, #36 ; 0x24
0x8690 ldm r2, {r0, r1}
0x8694 stm r3, {r0, r1}
0x8698 ldr r0, [pc, #112] ; 0x8710 <main()+240>
0x869c ldr r1, [pc, #112] ; 0x8714 <main()+244>
0x86a0 bl 0x8550 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)>
0x86a4 mov r3, r0
0x86a8 vldr s15, [r11, #-28] ; 0xffffffe4
0x86ac mov r0, r3
0x86b0 vmov.f32 s0, s15
0x86b4 bl 0x8568 <std::ostream::operator<<(float)>
0x86b8 mov r3, r0
0x86bc mov r0, r3
0x86c0 ldr r1, [pc, #80] ; 0x8718 <main()+248>
0x86c4 bl 0x8550 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)>
0x86c8 ldr r0, [pc, #64] ; 0x8710 <main()+240>
0x86cc ldr r1, [pc, #72] ; 0x871c <main()+252>
0x86d0 bl 0x8550 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)>
0x86d4 mov r3, r0
0x86d8 vldr s15, [r11, #-24] ; 0xffffffe8
0x86dc mov r0, r3
0x86e0 vmov.f32 s0, s15
0x86e4 bl 0x8568 <std::ostream::operator<<(float)>
0x86e8 mov r3, r0
0x86ec mov r0, r3
0x86f0 ldr r1, [pc, #32] ; 0x8718 <main()+248>
0x86f4 bl 0x8550 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)>
0x86f8 mov r3, #0
0x86fc mov r0, r3
0x8700 sub sp, r11, #4
0x8704 pop {r11, pc}
0x8708 strbmi r0, [r8], #-0
0x870c ldrmi r0, [r6], #-0
0x8710 ; <UNDEFINED> instruction: 0x00010ab0
0x8714 andeq r8, r0, r12, lsr #18
0x8718 andeq r8, r0, r0, lsr r9
0x871c andeq r8, r0, r4, lsr r9
operator+:
0x882c push {r11, lr}
0x8830 add r11, sp, #4
0x8834 sub sp, sp, #40 ; 0x28
0x8838 str r0, [r11, #-32]
0x883c str r1, [r11, #-36] ; 0x24
0x8840 ldr r3, [r11, #-32]
0x8844 vldr s14, [r3]
0x8848 ldr r3, [r11, #-36] ; 0x24
0x884c vldr s15, [r3]
0x8850 vadd.f32 s15, s14, s15
0x8854 vstr s15, [r11, #-12]
0x8858 ldr r3, [r11, #-32]
0x885c vldr s14, [r3, #4]
0x8860 ldr r3, [r11, #-36] ; 0x24
0x8864 vldr s15, [r3, #4]
0x8868 vadd.f32 s15, s14, s15
0x886c vstr s15, [r11, #-8]
0x8870 sub r1, r11, #20
0x8874 sub r2, r11, #12
0x8878 sub r3, r11, #8
0x887c mov r0, r1
0x8880 mov r1, r2
0x8884 mov r2, r3
0x8888 bl 0x87a0 <dimension2d<float>::dimension2d(float const&, float const&)>
0x888c sub r3, r11, #28
0x8890 sub r2, r11, #20
0x8894 ldm r2, {r0, r1}
0x8898 stm r3, {r0, r1}
0x889c ldr r2, [r11, #-28]
0x88a0 ldr r3, [r11, #-24]
0x88a4 vmov s14, r2
0x88a8 vmov s15, r3
0x88ac vmov.f32 s0, s14
0x88b0 vmov.f32 s1, s15
0x88b4 sub sp, r11, #4
0x88b8 pop {r11, pc}
Can you see where the problem might be?

#91 Andreas Jonsson   Moderators   -  Reputation: 3445

Like
0Likes
Like

Posted 10 December 2012 - 07:59 PM

Well, the function should truly be called the way I suspected. Now we need to understand why AS decides to use armFuncR0R1 when it should be using armFuncR0.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#92 Tzarls   Members   -  Reputation: 916

Like
0Likes
Like

Posted 11 December 2012 - 01:22 AM

Well, there´s something strange going on here... When this line (1276) is executed:

r = ExecuteString(engine, "dim2f video_res(800,600);\n"
					    "dim2f total_res;\n"
		 "total_res = video_res + video_res;\n"
		 "assert( total_res.x == 1600 && total_res.y == 1200 );\n"
		 "ByValue(dim2f(1,2)); \n");

The constructor for video_res and total_res is called (armFuncObjLast), then operator+ is called (armFuncR0R1) but the function receives wrong values (which is to be expected since it isn´t being called by the appropriate asm function) but then opAssign (operator=) is scheduled for being called using armFuncR0, and in fact the asm function is called but for some reason the program never reaches the actual code for operator+.The "blx r4" line is executed, there´s a jump to some other place in the code, then the program returns to the line after "blx r4" and continues to finally display the assert failure.

#93 Andreas Jonsson   Moderators   -  Reputation: 3445

Like
0Likes
Like

Posted 11 December 2012 - 11:53 AM

I'm out of ideas. I think I'll finally have to log in to your machine and do some debugging on my own to figure out what's going on.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#94 Tzarls   Members   -  Reputation: 916

Like
0Likes
Like

Posted 11 December 2012 - 04:50 PM

Where does AS decides the calling convention to be used? Doesn´t it respect the one used when you make the binding?

Anyway, you have the details for logging into my RPi so feel free to check if you can find the problem. Meanwhile I´ll try to fix the other failing tests.

#95 Andreas Jonsson   Moderators   -  Reputation: 3445

Like
0Likes
Like

Posted 11 December 2012 - 04:59 PM

Part of it happens when the function is registered, in DetectCallingConvention(). The other part happens as a step before compiling the scripts when the full application interface is registered, in PrepareSystemFunction(). Both of these are located in the as_callfunc.cpp file, and the configurations in as_config.h control how they work on each platform.

Regards,
Andreas
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#96 Andreas Jonsson   Moderators   -  Reputation: 3445

Like
1Likes
Like

Posted 11 December 2012 - 05:33 PM

I logged and reviewed the code changes you had made and I see the problem with the dim2f.

The logic you put in the end to treat returned objects that have the flag asOBJ_APP_CLASS_ALLFLOATS. Also needs to be added in the beginning of the function where the condition if( sysFunc->hostReturnInMemory ) is made.

If this condition is true, but the returned object in memory is a non-complex object with asOBJ_APP_CLASS_ALLFLOATS and it is smaller than or equal to 8 bytes, then callConv should not be incremented.

It is this increment that is making the code use armFuncR0R1 instead of just armFuncR0 that it should.

---

EDIT. I didn't make any changes to the code as I didn't have much time to spend on this at the moment.

Edited by Andreas Jonsson, 11 December 2012 - 05:39 PM.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#97 Tzarls   Members   -  Reputation: 916

Like
0Likes
Like

Posted 11 December 2012 - 10:16 PM

I changed that to:

if( sysFunc->hostReturnInMemory )
{
  int vv=1;
  if ( !( descr->returnType.GetObjectType()->flags & COMPLEX_RETURN_MASK )  &&
	 ( descr->returnType.GetObjectType()->flags & asOBJ_APP_CLASS_ALLFLOATS ) &&
	   descr->returnType.GetSizeInMemoryBytes() <= 8 )
   vv--;
 
  // The return is made in memory
  callConv += vv;
}

And the call to operator+ is competed succesfully, using the armFuncR0 function. Then operator= is called, but not the one defined in the class´ definition - nevertheless the assertion passes. Now I´m getting an error in the ByValue(...) function. I´ll investigate a little to see what´s going on here. BTW, ByValue(...) is being called with the armFunc function.

Edited by Tzarls, 11 December 2012 - 11:09 PM.


#98 Andreas Jonsson   Moderators   -  Reputation: 3445

Like
0Likes
Like

Posted 12 December 2012 - 07:22 AM

Without looking at the code I can imagine that ByValue() has a similar need.

By default the configuration in as_config.h will make dim2f be identified as a large class due to having a size larger than 4 bytes and thus AngelScript will pass it as a reference. However, due to being a structure of 2 floats, (asOBJ_APP_CLASS_ALLFLOATS) it should be treated as a simple class and passed in the S registers.

At least, this is how I think this needs to be handled. A disassembly of the ByValue function can confirm that.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#99 Tzarls   Members   -  Reputation: 916

Like
0Likes
Like

Posted 12 December 2012 - 08:28 AM

Disassemblies. For this code:

code:

#include <iostream>
#include <string>
typedef unsigned long asDWORD;
template <class T>
class dimension2d
{
public:
  dimension2d() : Width(0), Height(0) {}
  dimension2d(const T& width, const T& height) :
   Width(width), Height(height) {}
  template <class U>
  explicit dimension2d(const dimension2d<U>& other) :
   Width((T)other.Width), Height((T)other.Height) { }
  template <class U>
  dimension2d<T>& operator=(const dimension2d<U>& other)
  {
   Width = (T) other.Width;
   Height = (T) other.Height;
   return *this;
  }

  dimension2d<T> operator+(const dimension2d<T>& other) const
  {
   return dimension2d<T>(Width+other.Width, Height+other.Height);
  }
  T Width;
  T Height;
};
void ByValue(dimension2d<float> val)
{
    std::cout << "X: " << val.Width << "\n";
    std::cout << "Y: " << val.Height << "\n";
}

int main()
{
    ByValue(dimension2d<float>(1,2));
    return 0;
}
main:
0x86b4 push {r11, lr}
0x86b8 add r11, sp, #4
0x86bc sub sp, sp, #16
0x86c0 ldr r3, [pc, #72] ; 0x8710 <main()+92>
0x86c4 str r3, [r11, #-12]
0x86c8 ldr r3, [pc, #68] ; 0x8714 <main()+96>
0x86cc str r3, [r11, #-8]
0x86d0 sub r1, r11, #20
0x86d4 sub r2, r11, #12
0x86d8 sub r3, r11, #8
0x86dc mov r0, r1
0x86e0 mov r1, r2
0x86e4 mov r2, r3
0x86e8 bl 0x8798 <dimension2d<float>::dimension2d(float const&, float const&)>
0x86ec vldr s14, [r11, #-20] ; 0xffffffec
0x86f0 vldr s15, [r11, #-16]
0x86f4 vmov.f32 s0, s14
0x86f8 vmov.f32 s1, s15
0x86fc bl 0x8620 <ByValue(dimension2d<float>)>
0x8700 mov r3, #0
0x8704 mov r0, r3
0x8708 sub sp, r11, #4
0x870c pop {r11, pc}
0x8710 svccc 0x00800000
0x8714 andmi r0, r0, r0
ByValue:
0x8620 push {r11, lr}
0x8624 add r11, sp, #4
0x8628 sub sp, sp, #8
0x862c vmov.f32 s14, s0
0x8630 vmov.f32 s15, s1
0x8634 vstr s14, [r11, #-12]
0x8638 vstr s15, [r11, #-8]
0x863c ldr r0, [pc, #96] ; 0x86a4 <ByValue(dimension2d<float>)+132>
0x8640 ldr r1, [pc, #96] ; 0x86a8 <ByValue(dimension2d<float>)+136>
0x8644 bl 0x8550 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)>
0x8648 mov r3, r0
0x864c vldr s15, [r11, #-12]
0x8650 mov r0, r3
0x8654 vmov.f32 s0, s15
0x8658 bl 0x8568 <std::ostream::operator<<(float)>
0x865c mov r3, r0
0x8660 mov r0, r3
0x8664 ldr r1, [pc, #64] ; 0x86ac <ByValue(dimension2d<float>)+140>
0x8668 bl 0x8550 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)>
0x866c ldr r0, [pc, #48] ; 0x86a4 <ByValue(dimension2d<float>)+132>
0x8670 ldr r1, [pc, #56] ; 0x86b0 <ByValue(dimension2d<float>)+144>
0x8674 bl 0x8550 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)>
0x8678 mov r3, r0
0x867c vldr s15, [r11, #-8]
0x8680 mov r0, r3
0x8684 vmov.f32 s0, s15
0x8688 bl 0x8568 <std::ostream::operator<<(float)>
0x868c mov r3, r0
0x8690 mov r0, r3
0x8694 ldr r1, [pc, #16] ; 0x86ac <ByValue(dimension2d<float>)+140>
0x8698 bl 0x8550 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)>
0x869c sub sp, r11, #4
0x86a0 pop {r11, pc}
0x86a4 strdeq r0, [r1], -r0 ; <UNPREDICTABLE>
0x86a8 andeq r8, r0, r4, asr r8
0x86ac andeq r8, r0, r8, asr r8
0x86b0 andeq r8, r0, r12, asr r8

So yes, it is being passed in the "s" registers. So I guess I have to add some logic to the part where the object memory is copied to the buffer to detect if it is an asOBJ_APP_CLASS_ALLFLOATS and if so then I copy the object to the s registers, right? (Taking care, of course, to not overwrite anything that has already been stored in s or d registers - oh god...). What happens if I need more space than registers are available? Use the stack? I guess a disassembly of this case should show me how to proceed in such case.

In this case there´s no need to mess with the "if( sysFunc->hostReturnInMemory )" part, right?

#100 Andreas Jonsson   Moderators   -  Reputation: 3445

Like
0Likes
Like

Posted 12 December 2012 - 10:35 AM

Isn't it fun to figure out how ABIs work? :)

My guess (hope) is that if there is not enough space to fit the entire object in the available registers, the entire object will be pushed on the stack. It would also be necessary to determine if the two floats needs to be aligned on even registers, i.e. similar to a double.

I believe we have already confirmed that if the type is larger than 8 bytes it will not be passed in the registers, even if it is asOBJ_APP_CLASS_ALLFLOATS, but it may be a good idea to do a disassembly of that case too.






Once everything is working I'll do some refactoring on the code you're implementing now. This special treatment for classes with asOBJ_APP_CLASS_ALLFLOATS should be identified in as_config.h, so these checks whether the type is passed in registers or by reference is done at compile time in PrepareSystemFunction, rather than at runtime. But you don't need to worry about that, I'll make this myself later, and I'll just ask you to test it or perhaps I'll do the testing myself if you allow me to use your RPi remotely for this.
AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS