.. _cheat: XC to C Cheat sheet =================== This cheat sheet is intended to act as a quick reference for experienced XC programmers wanting to migrate to using C as per :ref:`lib_xcore_prog_guide`. Parallel tasks & channels ------------------------- .. list-table:: :header-rows: 1 * - XC - C * - .. code-block:: void task1(chanend c) { ... } void task2(chanend c, int count) { ... } void task3(void) { ... } int main(void) { int count = 5; chan c; par { task1(c); task2(c, count); task3(); } } - .. code-block:: #include #include DECLARE_JOB(task1, (chanend_t)); void task1(chanend_t c) { ... } DECLARE_JOB(task2, (chanend_t, int)); void task2(chanend_t c, int count) { ... } DECLARE_JOB(task3, (void)); void task3(void) { ... } int main(void) { int count = 5; channel_t c = chan_alloc(); PAR_JOBS( PJOB(task1, (c.end_a)), PJOB(task2, (c.end_b, count)), PJOB(task3, ()) ); chan_free(c); } * - .. code-block:: int a = 5; c <: a; c :> a; - .. code-block:: int a = 5; chan_out_word(c, a); a = chan_in_word(c); * - .. code-block:: unsigned char a = 5; c <: a; c :> a; - .. code-block:: unsigned char a = 5; chan_out_byte(c, a); a = chan_in_byte(c); * - NA - .. code-block:: uint32_t words[5] = {1,2,3,4,5}; chan_out_buf_word(c, words, 5); chan_in_buf_word(c, words, 5); * - NA - .. code-block:: unsigned char bytes[4] = {1,2,3,4}; chan_out_buf_byte(c, bytes, 4); chan_in_buf_byte(c, bytes, 4); * - .. code-block:: streaming chan c; .. code-block:: int a = 5; c <: a; c :> a; - .. code-block:: #include streaming_channel_t c = s_chan_alloc(); // use streaming channel s_chan_free(); .. code-block:: int a = 5; s_chan_out_word(c, a); a = s_chan_in_word(c); Ports ----- .. list-table:: :header-rows: 1 * - XC - C * - .. code-block:: #include port my_port = XS1_PORT_1J; void port_user(port p) { ... } int main(void) { port_user(my_port); } - .. code-block:: #include #include void port_user(port_t p) { ... } int main(void) { port_t my_port = XS1_PORT_1J; port_enable(my_port); port_user(my_port); port_disable(my_port); } * - .. code-block:: int a; p :> a; p <: a; - .. code-block:: int a; a = port_in(p); port_out(p, a); Timers ------ .. list-table:: :header-rows: 1 * - XC - C * - .. code-block:: int main() { [[hwtimer]] timer t; unsigned v; t :> v; } - .. code-block:: #include int main(void) { hwtimer_t t = hwtimer_alloc(); unsigned v; v = hwtimer_get_time(t); hwtimer_free(t); } 'Selecting' events ------------------ Select Blocks ^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 * - XC - C * - .. code-block:: #include #include int main(void) { [[hwtimer]] timer t; unsigned long now; t :> now; while (1) { select { case t when timerafter(now + 10000000) :> now: printf("Timer handler at time: %lu\n", now); break; default: puts("Nothing happened..."); break; } } } - .. code-block:: #include #include #include int main(void) { hwtimer_t t = hwtimer_alloc(); unsigned long now = hwtimer_get_time(t); hwtimer_set_trigger_time(t, now + 10000000); SELECT_RES( CASE_THEN(t, timer_handler), DEFAULT_THEN(default_handler)) { timer_handler: now = hwtimer_get_time(t); hwtimer_change_trigger_time(t, now + 10000000); printf("Timer handler at time: %lu\n", now); continue; default_handler: puts("Nothing happened..."); continue; } hwtimer_free(t); } * - .. code-block:: [[ordered]] select{ // case statements } - .. code-block:: SELECT_RES_ORDERED( // case specifiers ){} XC's :samp:`[[combine]]` and :samp:`[[combinable]]` keywords are not available in C. Combine the functions manually. Case specifiers ^^^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 * - XC - C * - Guarded case: .. code-block:: case guard_flag => t :> now: - .. code-block:: CASE_GUARD_THEN(t, guard_flag, timer_handler) .. code-block:: timer_handler: now = hwtimer_get_time(t); * - Guarded default case: .. code-block:: guard_flag => default: - .. code-block:: DEFAULT_GUARD_THEN(guard_flag, default_handler) * - Inverted guarded case: .. code-block:: case !guard_flag => t :> now: - .. code-block:: CASE_NGUARD_THEN(t, guard_flag, timer_handler) .. code-block:: timer_handler: now = hwtimer_get_time(t); * - Inverted guarded default case: .. code-block:: !guard_flag => default: - .. code-block:: DEFAULT_NGUARD_THEN(guard_flag, default_handler) Event handlers ^^^^^^^^^^^^^^ Event handlers are denoted by a label which must be immediately followed by a read from the event-generating resource, even if the value is not required. Event handlers can terminated with the following: :samp:`break` Exit implicit select block loop :samp:`continue` Continue implicit select block loop; re-initialise as appropriate With care, and depending on the likely presence or guaranteed absence of a nested select block, :samp:`continue` in the outer select block may be replaced with: :samp:`SELECT_CONTINUE_RESET` Continue; force re-initialisation :samp:`SELECT_CONTINUE_NO_RESET` Continue; force no re-initialisation Locks ----- .. list-table:: :header-rows: 1 * - XC - C * - NA - .. code-block:: #include int task_func(void) { lock_t l = lock_alloc(); lock_acquire(l); // Critical section lock_release(l); lock_free(l); } Locks are not 'eventable' and therefore cannot be referenced within a select block case specifier. Function pointers ----------------- Assist stack size calculation by annotating function pointers: .. code-block:: __attribute__(( fptrgroup("my_functions") )) void func1_small(void) { char cs[64]; cs[0] = 0; } __attribute__(( fptrgroup("my_functions") )) void func2_big(void) { char cs[256]; cs[0] = 0; } int main(void) { __attribute__(( fptrgroup("my_functions") )) void(*fp)(void); fp = func1_small; fp(); fp = func2_big; fp(); } Membership of the correct group is not checked at build-time. Enable runtime checking in the above using the fragment below when the function pointer is declared: .. code-block:: __attribute__(( fptrgroup("my_functions", 1) )) void(*fp)(void); Use of the same fragment on the function declaration has no effect. Targeting multiple tiles ------------------------ Deploying applications onto multiple tiles still requires the use of a minimal :file:`mapfile.xc`: .. code-block:: :caption: mapfile.xc #include typedef chanend chanend_t; extern "C" { void main_tile0(chanend_t); void main_tile1(chanend_t); } int main(void) { chan c; par { on tile[0]: main_tile0(c); on tile[1]: main_tile1(c); } return 0; } Avoid all procedural code within :file:`mapfile.xc`. Instead, place it within the C code: .. code-block:: :caption: main.c #include #include void main_tile0(chanend_t c) { printf("Tile 0 prints first\n"); chan_out_word(c, 1); } void main_tile1(chanend_t c) { int token = chan_in_word(c); printf("Tile 1 prints second\n"); }