Num timers for startKIT and eXplorerKIT

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
aclassifier
Respected Member
Posts: 507
Joined: Wed Apr 25, 2012 8:52 pm

Num timers for startKIT and eXplorerKIT

Post by aclassifier »

  • Why does startKIT and eXplorerKIT have different number of timers in this code?
  • The question really is why is the startKIT is listed with one more timer than the code shows? DEBUG_PRINT_TEST makes no difference
  • Also, number of chanends starts at 4 and increments by 3 per new client. Why doesn't it start with 3 chanends? DEBUG_PRINT_TEST makes no difference here either
  • Some of this has been discussed before here at XCore Exchange, at Calculating number of chanends
  • With DO_PLACED == 1 the code breaks completely down. I have filed this as an XMOS Ticket
  • Aside: I am showing this and other examples at Client-server and call-based notification, placement and chanend numbers (disclaimer: no money, ads, gifts with my notes (just fun and expenses!))

Code: Select all

#include <platform.h> // core
#include <stdio.h>
#include <timer.h> // delay_milliseconds(200), XS1_TIMER_HZ etc

#define DEBUG_PRINT_TEST 1
#define debug_print(fmt, ...) do { if(DEBUG_PRINT_TEST) printf(fmt, __VA_ARGS__); } while (0)

typedef enum {false,true} bool;
typedef signed int time32_t;
typedef unsigned data_t;

typedef interface notify_if_t {

    [[guarded]]
    void start_collect_data (void);

    [[notification]]
    slave void data_ready (void);

    [[clears_notification]]
    data_t get_data (void);

} notify_if_t;

#define NUM_CLIENTS 7 // DO_PLACED 0: MAX 7. 1 timer and 3 chanends per client

[[combinable]]
void server_task (server notify_if_t i_notify[NUM_CLIENTS]) {
    timer     tmr;
    time32_t  time;
    bool      collectData = false;
    bool      session = false; // Necessary!
    data_t    data = 0;
    int       session_index_of_client;

    debug_print ("%s\n", "server_task");
    tmr :> time; // immediately

    while (1) {
        select {
            case (session == false) => i_notify[int index_of_client].start_collect_data (void) : {
                collectData = true;
                session = true;
                debug_print ("%d started\n", index_of_client);
                session_index_of_client = index_of_client;
                tmr :> time; // immediately
            } break;
            case (collectData == true) => tmr when timerafter (time) :> void : {
                collectData = false;
                data++; // This is supposed to take a while, that's why we used notification: to get it decoupled
                debug_print ("%d produced %u\n", session_index_of_client, data);
                i_notify[session_index_of_client].data_ready();
            } break;
            case i_notify[int index_of_client].get_data (void) -> data_t return_Data : {
                debug_print ("%d sent %u\n", index_of_client, data);
                session = false;
                return_Data = data;
            } break;
        }
    }
}

[[combinable]]
void client_task (client notify_if_t i_notify, const int index_of_client) {
    timer     tmr;
    time32_t  time;
    bool      expect_notification = false;
    unsigned  cnt = 0;
    debug_print ("client_task %d\n", index_of_client);

    tmr :> time; // immediately

    while (1) {
        select {
            case (expect_notification == false) => tmr when timerafter (time) :> void : {
                debug_print ("\n%d START\n", index_of_client);
                i_notify.start_collect_data();
                expect_notification = true;
            } break;
            case (expect_notification == true) => i_notify.data_ready() : {
                data_t data = i_notify.get_data();
                cnt++;
                debug_print ("%d GOT %u is #%u\n", index_of_client, data, cnt);
                expect_notification = false;
                time += XS1_TIMER_HZ; // 1 second
            } break;
        }
    }
}

int main() {
    #define DO_PLACED 0 // 1 simply does not work!

    notify_if_t if_notify[NUM_CLIENTS];
    #if (DO_PLACED == 0)
        /*
        STARTKIT:
        NUM_CLIENTS 1 Cores 2  Timers 3  Chanends  4  OKAY.
        NUM_CLIENTS 2 Cores 3  Timers 4  Chanends  7  OKAY.
        NUM_CLIENTS 3 Cores 4  Timers 5  Chanends 10  OKAY.
        NUM_CLIENTS 4 Cores 5  Timers 6  Chanends 13  OKAY.
        NUM_CLIENTS 5 Cores 6  Timers 7  Chanends 16  OKAY.
        NUM_CLIENTS 6 Cores 7  Timers 8  Chanends 19  OKAY.
        NUM_CLIENTS 7 Cores 8  Timers 9  Chanends 22  OKAY.

        XCORE-200-EXPLORER has one less timer (xTIMEcomposer 14.3.3):
        NUM_CLIENTS 1 Cores 2  Timers 2  Chanends  4  OKAY.
        NUM_CLIENTS 2 Cores 3  Timers 3  Chanends  7  OKAY.
        NUM_CLIENTS 3 Cores 4  Timers 4  Chanends 10  OKAY.
        NUM_CLIENTS 4 Cores 5  Timers 5  Chanends 13  OKAY.
        NUM_CLIENTS 5 Cores 6  Timers 6  Chanends 16  OKAY.
        NUM_CLIENTS 6 Cores 7  Timers 7  Chanends 19  OKAY.
        NUM_CLIENTS 7 Cores 8  Timers 8  Chanends 22  OKAY.
        */
        par {
            server_task(if_notify);
            par (size_t i = 0; i < NUM_CLIENTS; i++) {
                client_task (if_notify[i], i);
            }
        }
    #elif (DO_PLACED == 1)
        /*
        NUM_CLIENTS 1 Cores 1  Timers 2  Chanends 2  OKAY.  Constraints checks PASSED. BUT DOES NOT RUN!
        NUM_CLIENTS 2 Cores 1+ Timers 2+ Chanends 3+ MAYBE. PASSED WITH CAVEATS.       DOES NOT RUN
        NUM_CLIENTS 3 Cores 1+ Timers 2+ Chanends 4+ MAYBE. PASSED WITH CAVEATS.       DOES NOT RUN
        Constraint check for tile[0]:
          Cores available:            8,   used:          1+.  MAYBE
          Timers available:          10,   used:          2+.  MAYBE
          Chanends available:        32,   used:          4+.  MAYBE
          Memory available:       65536,   used:      12460+.  MAYBE
            (Stack: 1112+, Code: 10380, Data: 968)
        Constraints checks PASSED WITH CAVEATS.
        */
        par {
            on tile[0].core[0]: server_task(if_notify);
            par (size_t i = 0; i < NUM_CLIENTS; i++) {
                on tile[0].core[0]: client_task (if_notify[i], i);
            }
        }
    #endif
    return 0;
}
--
Øyvind Teig
Trondheim (Norway)
https://www.teigfam.net/oyvind/home/
User avatar
infiniteimprobability
Verified
XCore Legend
Posts: 1149
Joined: Thu May 27, 2010 10:08 am

Post by infiniteimprobability »

Not sure where that code comes from but resource numbers can be found in:

xs2a_user.h for xCORE200 (Explorer kit))
xs1b_user.h for XS1 (Startkit)

They both have the following:

Code: Select all

#define XS1_NUM_TIMERS 0xa
Engineer at XMOS
User avatar
aclassifier
Respected Member
Posts: 507
Joined: Wed Apr 25, 2012 8:52 pm

Post by aclassifier »

Thanks. But I guess that's the number of available timers?

But why does the compiler/linker seem to use an extra timer (that's not visible in my code) on the startKIT?
--
Øyvind Teig
Trondheim (Norway)
https://www.teigfam.net/oyvind/home/
User avatar
infiniteimprobability
Verified
XCore Legend
Posts: 1149
Joined: Thu May 27, 2010 10:08 am

Post by infiniteimprobability »

Hmm, good question. I don't know.. I do know that from tools 13 a time is allocated per used core automatically but that doesn't explain it in this situation.
May need to phone a friend...
Engineer at XMOS