Page 1 of 1

How do I use the same clock block in two different cores?

Posted: Thu Apr 09, 2015 10:12 am
by infiniteimprobability
I would like to use the same clock block to clock ports in two different cores. However the compiler gives me a "parallel usage violation" error. How can I do this?


Answer 3239

Posted: Thu Apr 09, 2015 10:17 am
by infiniteimprobability
Sharing clockblocks is OK to do in the architecture (actually the hidden clockblock number 0 aka the 100MHz ref clock does this), however the compiler by default prevents any resource from being used in differnt cores, even though in this case it is safe.

Using the tools 13 features (unsafe pointers) you can have an alias of the clock block and pass it to two different cores. Please make sure they are on the same tile! Only channel/interface calls traverse tiles..nothing else is shared across tiles.

Finally, don't try this with ports or timers unless you know what you are doing - it is dangerous to share these across cores without locks to ensure two instructions accessing the same resource don't find themselves in the pipeline at the same time (exception)..

Here's the code example showing how to use the same clockblock :

 

#include <xs1.h>

buffered out port:32 p_1 = XS1_PORT_1A;
buffered out port:32 p_2 = XS1_PORT_1B;
 
clock clk = XS1_CLKBLK_1;
 
void task1(buffered out port:32 p_clocked, clock * unsafe clk_p){
  unsafe{
    configure_out_port_no_ready(p_clocked, *clk_p, 0);
  }
  while(1){
    p_clocked <: 0xaaaaaaaa;
  }
}
 
void task2(buffered out port:32 p_clocked, clock * unsafe clk_p){
  unsafe {
    configure_out_port_no_ready(p_clocked, *clk_p, 0);
  start_clock(*clk_p);
  }
  while(1){
    p_clocked <: 0xf0f0f0f0;
  }
}
 
int main(void){
  stop_clock(clk);
  configure_clock_ref(clk, 17); //About 3MHz
 
  unsafe {
 
    clock * unsafe clk_ptr1 = &clk;
    clock * unsafe clk_ptr2 = &clk;
 
    par{
      task1(p_1, clk_ptr1);
      task2(p_2, clk_ptr1);
    }
  }//unsafe region
return 0;
}

Re: How do I use the same clock block in two different cores

Posted: Wed Nov 02, 2016 3:27 pm
by ffomich
Hi infiniteimprobability,
please clarify 2 moments:

1.

Code: Select all

void task1(buffered out port:32 p_clocked, clock * unsafe clk_p){ 
  unsafe{ 
    configure_out_port_no_ready(p_clocked, *clk_p, 0); 
  } 

Code: Select all

void task2(buffered out port:32 p_clocked, clock * unsafe clk_p){ 
  unsafe { 
    configure_out_port_no_ready(p_clocked, *clk_p, 0); 
  start_clock(*clk_p); <- must be only in task2() ?
  } 
2.

Code: Select all

int main(void){ 
  ...
    par{ 
      task1(p_1, clk_ptr1); 
      task2(p_2, clk_ptr1); <- must be clk_ptr2 here?
    } 
 ...
}

Re: How do I use the same clock block in two different cores

Posted: Fri Nov 04, 2016 9:37 am
by DemoniacMilk
Ill just randomly add my 2 cents here if oyu dont mind.

1) Starting the clock block once is enough, its the same ressource after all, so you don't need to start it twice

2) I think you could just declare one unsafe pointer and pass it to both tasks.
He was talking about aliasing pointers earlier, I havent really used those, so I dont know what the compiler allows in that case.

EDIT: Tested, on using alias pointers you have to use ptr1 and ptr2 as parameters. However, i end up getting an error "../src/00_clkShare.xc:49:18: error: use of alias pointer `clk_ptr2' declared outside of par block" (and a similar error for clt_ptr1)

Re: How do I use the same clock block in two different cores

Posted: Fri Nov 04, 2016 6:20 pm
by infiniteimprobability
task2(p_2, clk_ptr1); <- must be clk_ptr2 here?
Yes - looks like I accidentally passed in the same pointer to both tasks (typo). However this worked so two pointers apparently are not required.

DemoniacMilk's other comments look pretty fair.

Re: How do I use the same clock block in two different cores?

Posted: Wed Feb 15, 2023 1:58 pm
by CousinItt
It may be a bit late in the day, but it is possible to share a constant clock block without tears.

It could be useful for configuring ports, but it's fairly limited, For example it wouldn't work if one of the shared instances needs to do something to the clock, like start it.

This code compiles without complaint (using 14.4.1 tools):

Code: Select all

#include <xs1.h>
#include <platform.h>

on tile[0]: in port pa = XS1_PORT_1A;
on tile[0]: in port pb = XS1_PORT_1B;

on tile[0]: clock bclk = XS1_CLKBLK_1;

void clock_test_1(in port p, const clock clk)
{
   configure_in_port(p, clk);
}

void clock_test_2(in port p, const clock clk)
{
   configure_in_port(p, clk);
}

void tile_0_tasks(void)
{
   par
   {
      clock_test_1(pa, bclk);
      clock_test_2(pb, bclk);
   }
}

int main(void)
{
   par
   {
      on tile[0]: tile_0_tasks();
   }

   return 0;
}

Re: How do I use the same clock block in two different cores?

Posted: Sun Feb 19, 2023 9:27 am
by fabriceo
Hi CousinItt
I m using a single clock block for 4 Spdif_rx tasks, but I had to read the clock_block with an assembly statement (ldw %0,dp[clk_blk]) and pass the result as an unsigned value to each tasks... this was during my early days on xmos where I had very much difficulty to understand all the constrains linked to concurrent task and exclusive resource allocation...

Re: How do I use the same clock block in two different cores?

Posted: Tue Feb 21, 2023 1:05 pm
by CousinItt
Thanks Fabriceo, your method looks like a better compromise than declaring unsafe all functions that use a clock block just to share it.

Re: How do I use the same clock block in two different cores?

Posted: Thu Mar 30, 2023 5:05 pm
by Ross
The easiest thing to do is configure the ports/clocks before the par

Code: Select all

void main()
{
   configure_in_port(p0, clk);
   configure_in_port(p1, clk);
   par
   {
       task0(p0);
       task1(p1);
   }
}