<< >> << References >> <<<<< << >> o onl:~onl/npr/ intel_sdk/ xxx microengineC/src/intrinsic.c IXP2XXX_book/ xxx onl_router/ xxx pluginFramework/ plugin framework code including plugin_api.[ch] (plugin_api.c is no longer used) plugins/ sample plugin code o laptop:arl/research/np-router/IXP2XXX_book/Chapter12/timers.c << >> << Initializing ME Timer >> <<<<< << >> o Don't really need to do this since the CSR is already initialized. void plugin_init_user() { SIGNAL timer_sig; __declspec(sram_write_reg) unsigned int misc_ctl; if(ctx() == 0) { // enable timer misc_ctl = 1 << 7; cap_csr_write( &misc_ctl, // bit 7 turns on timer csr_misc_control, // operation ctx_swap, // sync type &timer_sig); // which signal // init timer signal local_csr_write( local_csr_active_future_count_signal, __signal_number(&timer_sig)); } } << >> << Return difference between 2 timestamps in msec >> <<<<< << >> o Timestamps are 64 bits and consists of the TIMESTAMP_LOW and TIMESTAMP_HIGH CSRs - Each unit (tick) is equal to 16 ME clock cycles o You MUST read TIMESTAMP_LOW first to ensure an atomic read. static __forceinline unsigned long diff_msec( __declspec(local_mem) long long t2, __declspec(local_mem) long long t1 ) { __declspec(gp_reg) unsigned long msec; msec = ( ((t2 - t1)<<4) /100000)/14; // 16*delta/10^5/14 return msec; } << >> << Convert msec to ME cycles >> <<<<< << >> o Only works if argument is <= 49,000 o Note: - MEs run at 1.4 GHz ==> 1.4 cycles/nanosecond 1,400 cycles/microsecond or 1.4 Kcycles 1,400,000 cycles/millisecond or 1400 Kcycles // CAVEAT: msec <= 49000 msec static __forceinline unsigned long msec2cycles ( __declspec(gp_reg) unsigned long msec ) { __declspec(gp_reg) unsigned long cycles; cycles = ( 1400*msec*1000 ); return cycles; } << Debug Messages >> <<<<< o Note that there is only 640 words of local memory. Debug msgs can chew up a large part of this especially when you take into account padding. o Normally, spill to NN, then local memory, then SRAM. void handle_pkt_user() { __declspec(local_mem) char dbgmsg[28] = "got pkt "; __declspec(local_mem) char pkt_count_str[9]; __declspec(local_mem) char dot_str[2] = "."; __declspec(local_mem) char tm_str[18]; __declspec(gp_reg) unsigned long msec; ... pkt_count++; onl_api_int2str(pkt_count, pkt_count_str); // cnvrt int to string strcat_lmem(dbgmsg, pkt_count_str); // concatenate to msg strcat_lmem(dbgmsg, dot_str); // + "." instead of space tm_now = __timestamp_stop( tm_handle ); // get elapsed time msec = diff_msec( tm_now, tm_old ); // cnvrt time to msec onl_api_int2str( msec, tm_str ); // cnvrt strcat_lmem( dbgmsg, tm_str ); // concatenate onl_api_debug_message( msgNextBlock, dbgmsg ); // output ... } << Sleep for 50 msec >> <<<<< o If local_csr_timestamp_high doesn't change, then ylo-xlo should show 50 msec (= 50 * 1400 Kcycles = 70 Mcycles) o The sleep call will only work for arguments that can fit into 16 bits (64K). The sleep argument is #cycles. 'sleep' uses the FUTURE_COUNT register and signal, and can not sleep more than 2^20 - 1 cycles; i.e., 2^16 -1 ticks = 65,535 ticks. Furthermore, sleep masks off the rightmost 16 bits (i.e., it has a granularity of 1 tick or 16 cycles) xlo = local_csr_read( local_csr_timestamp_low ); for (i=0; i<50; i++) { // repeat sleeping 1 msec 50 times sleep( 700000 ); // sleep 500 usec sleep( 700000 ); // sleep 500 usec } ylo = local_csr_read( local_csr_timestamp_low );