Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test and set utility #7

Open
Alessandro0110 opened this issue Feb 27, 2019 · 12 comments
Open

test and set utility #7

Alessandro0110 opened this issue Feb 27, 2019 · 12 comments

Comments

@Alessandro0110
Copy link

Alessandro0110 commented Feb 27, 2019

Hello, thank you for your work. I would like to seek clarification about test and set utility located in the header "rt_utils.h":

  1. There are three different functions that can be used to implement test and set behavior: rt_tas_lock_8, rt_tas_lock_16, rt_tas_lock_32. I would like to understand the differences between them.

  2. The lock function takes as parameter an unsigned int variable called addr and return an int variable (int rt_tas_lock(unsigned int addr). I would like to ask you the meaning of these two variables.

  3. Same question for the unsigned int addr and the unsigned char values taken as parameter by the rt_tas_unlock (unsigned int addr, unsigned char value) function.

The reason why I am asking these clarification is that in my program I need two integer semaphores or four binary semaphores.

Thank you in advance for the help.

@haugoug
Copy link
Member

haugoug commented Feb 27, 2019

The test and set feature is a HW feature which does 2 operations atomically:

  • Does a normal load to the address
  • Stores -1 to the same address
    As it is atomic, this allows implementing multi-core synchronizations.
    The size of the -1 store is the same as the load, that's why there are 3 variants, 8bits, 16bits and 32bits, dependent on the size of your variable.
    The whole L1 can be used as test-and-set location. The test-and-set is done if the L1 address is accessed through a special offset that this function is adding to the L1 address.
    So the address you give to rt_tas_lock is the address of your variable on which you want to do a test-and-set. The same for rt_tas_unlock and you also have to give the value that your want to store back.
    You can browse the runtime code for examples to see how this feature is working.

@Alessandro0110
Copy link
Author

The value that you store in the variable when you make the unlock could be any values except -1, according to the number of bits chosen, is it right?
Consequently first it is necessary a declaration of a variable in the L1. Then I retrieve the address of this variable that will be provided to the lock function. Since the variable has to assume only two values eight bits should be enough. Do you agree with me?
Last question:
The offset should be "1<<ARCHI_L1_TAS_BIT" in which ARCHI_L1_TAS_BIT is equal to 20. But I would like to know the reason why this offset is added.

Thank you in advance for the help.

@haugoug
Copy link
Member

haugoug commented Feb 27, 2019

Yes indeed, the "normal value" of the variable should never be -1, otherwise you cannot distinguish between the case where the variable is locked or not.
The offset which is added is just to tell to the HW to do the test-and-set access. Accessing the normal variable address which do a classic load while accessing it through the normal variable address + 1<<ARCHI_L1_TAS_BIT will do a normal load plus a store of -1

@Alessandro0110
Copy link
Author

Thank you very much. I have another question, I tried to use the eight bits TAS but it didn't wok. I made something like this:

RT_L1_DATA volatile signed char tas=-1;

void function(){

...
while (rt_tas_lock_8((unsigned int)&tas) == -1);
...
}

Are there any mistakes in this piece of code?

I tried also with an unsigned char variable.
Besides I tried a solution without the initialization:

RT_L1_DATA volatile signed char tas;

void function(){

...
while (rt_tas_lock_8((unsigned int)&tas) == -1);
while (rt_tas_lock_8((unsigned int)&tas) == -1);
...
}

In both cases the problem is that the program is not blocked by the while statements. What do you think about this?
Thank you in advance for the help.

@haugoug
Copy link
Member

haugoug commented Mar 8, 2019

The lock should be initialized to something different from 0 otherwise it is already locked, that's why you never go out of the while loop.

@Alessandro0110
Copy link
Author

It is initialized to "-1" not to 0. In any case the problem is that the program is able to go out of the while loop. I would like that the program is blocked in the while loop in order to prove that the tas utility works well, but it doesn't happen.

Thank you in advance for the help.

@haugoug
Copy link
Member

haugoug commented Mar 8, 2019

Can you show the instruction traces for this code ? It is usually under build/pulp/trace_core_1f_0.log

@Alessandro0110
Copy link
Author

Since the program in which I'm using the TAS is much more complicated, I have made a simpler program that highlights the problem. This is the instruction trace:

trace_core_1f_0.log

@haugoug
Copy link
Member

haugoug commented Mar 8, 2019

I cannot see any TAS access in this trace, can you send me your code ?

@Alessandro0110
Copy link
Author

Sure. In test.c I start the cluster. In cluster.c I make the fork and the TAS.

prova_TAS.zip

@Alessandro0110
Copy link
Author

I forgot to say that the 32 bits TAS works. The other TAS gave me these problems.

Thank you in advance for the help.

@haugoug
Copy link
Member

haugoug commented Mar 13, 2019

There was an issue with the tas functions, the return type was always "int", so the function was actually returning 255 instead of -1.
As a short term work-around you can check against 255.
I've also updated the functions so that they return a char or short

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants