From a7645a9b0f6e6dab4b57ecb6692897c6a2e6aea4 Mon Sep 17 00:00:00 2001 From: xross Date: Thu, 8 Mar 2018 17:40:56 +0000 Subject: [PATCH] Audiohub now takes some resources as params (prev was global) --- lib_xua/api/xua_audiohub.h | 24 ++- lib_xua/api/xua_conf_full.h | 6 + lib_xua/doc/rst/using.rst | 101 ++++++++++++- lib_xua/src/core/audiohub/init_ports.h | 106 ++++++++++++++ lib_xua/src/core/audiohub/xua_audiohub.xc | 169 +++++----------------- tests/app_test_i2s_loopback/main.xc | 2 +- 6 files changed, 268 insertions(+), 140 deletions(-) create mode 100644 lib_xua/src/core/audiohub/init_ports.h diff --git a/lib_xua/api/xua_audiohub.h b/lib_xua/api/xua_audiohub.h index 80ad562a..bf073f99 100644 --- a/lib_xua/api/xua_audiohub.h +++ b/lib_xua/api/xua_audiohub.h @@ -15,14 +15,24 @@ * This function drives I2S ports and handles samples to/from other digital * I/O threads. * - * \param c_aud Audio sample channel connected to the mixer() thread or the - * decouple() thread - * \param c_dig channel connected to the clockGen() thread for - * receiving/transmitting samples - * \param c_config An optional channel that will be passed on to the - * CODEC configuration functions. + * \param c_aud Audio sample channel connected to the mixer() thread or the + * decouple() thread + * + * \param clk_audio_mclk Nullable clockblock to be clocked from master clock + * + * \param clk_audio_mclk Nullable clockblock to be clocked from i2s clock + * + * \param p_mclk_in Master clock inport port (must be 1-bit) + * + * \param c_dig channel connected to the clockGen() thread for + * receiving/transmitting samples */ -void XUA_AudioHub(chanend ?c_aud +void XUA_AudioHub(chanend ?c_aud, + clock ?clk_audio_mclk, + clock ?clk_audio_bclk, + in port p_mclk_in, + buffered _XUA_CLK_DIR port:32 ?p_lrclk, + buffered _XUA_CLK_DIR port:32 ?p_bclk #if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE) , chanend c_spdif_tx #endif diff --git a/lib_xua/api/xua_conf_full.h b/lib_xua/api/xua_conf_full.h index 16a279cd..affbebc1 100644 --- a/lib_xua/api/xua_conf_full.h +++ b/lib_xua/api/xua_conf_full.h @@ -8,4 +8,10 @@ #include "xua_conf_default.h" +#if CODEC_MASTER + #define _XUA_CLK_DIR in +#else + #define _XUA_CLK_DIR out +#endif + #endif diff --git a/lib_xua/doc/rst/using.rst b/lib_xua/doc/rst/using.rst index dd090b49..1def1561 100644 --- a/lib_xua/doc/rst/using.rst +++ b/lib_xua/doc/rst/using.rst @@ -21,11 +21,11 @@ The code is split into several directories. - Device Firmware Upgrade code -Note, the midi and dfu directories are potential canditates for separate libs in their own right. +Note, the midi and dfu directories are potential candidates for separate libs in their own right. Including in a project -~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~ All `lib_xua` functions can be accessed via the ``xud.h`` header filer:: @@ -34,4 +34,101 @@ All `lib_xua` functions can be accessed via the ``xud.h`` header filer:: It is also requited to to add ``lib_xua`` to the ``USED_MODULES`` field of your application Makefile. +Core hardware resources +~~~~~~~~~~~~~~~~~~~~~~~ +Currently all hardware resources used by `lib_xua` are simply declared globally. + +As an absolute minimum the following resources are required + +- A 1-bit port for audio master clock input +- A n-bit port for internal feedback calculation (typically a free, unused port is used e.g. `16B`) +- A clock-block, which will be clocked from the master clock input port + +.. note:: + + Since these resources are accessed globally naming is of importance + +Example declaration of these resources might look as follows:: + + in port p_mclk_in = PORT_MCLK_IN; + in port p_for_mclk_count = PORT_MCLK_COUNT; /* Extra port for counting master clock ticks */ + clock clk_audio_mclk = on tile[0]: XS1_CLKBLK_5; /* Master clock */ + + +If the ``XUD_AudioHub()`` and ``XUD_Buffer()`` cores reside on separate tiles a separate master clock input port must be provided to each, for example:: + + /* Master clock for the audio IO tile */ + in port p_mclk_in = PORT_MCLK_IN; + + /* Resources for USB feedback */ + in port p_mclk_in_usb = PORT_MCLK_IN_USB; /* Extra master clock input for the USB tile */ + +Whilst this satisfies the basic requirements for the operation of `lib_xua` projects typically also needs some additional audio I/O, I2S or SPDIF for example. +These should be passed into the various cores as required (see API section) + +Running the core components +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In their most basic form the core components can be run as follows:: + + par + { + /* Endpoint 0 core from lib_xua */ + XUA_Endpoint0(c_ep_out[0], c_ep_in[0], c_aud_ctl, null, null, null, null); + + /* Buffering cores - handles audio data to/from EP's and gives/gets data to/from the audio I/O core */ + /* Note, this spawns two cores */ + XUA_Buffer(c_ep_out[1], c_ep_in[1], c_sof, c_aud_ctl, p_for_mclk_count, c_aud); + + /* AudioHub/IO core does most of the audio IO i.e. I2S (also serves as a hub for all audio) */ + XUA_AudioHub(c_aud); + } + +``XUA_Buffer()`` expects its ``p_for_mclk_count`` argument to be clocked from the audio master clock +The following code satisfies this requirement:: + + { + /* Connect master-clock clock-block to clock-block pin */ + set_clock_src(clk_audio_mclk_usb, p_mclk_in_usb); /* Clock clock-block from mclk pin */ + set_port_clock(p_for_mclk_count, clk_audio_mclk_usb); /* Clock the "count" port from the clock block */ + start_clock(clk_audio_mclk_usb); /* Set the clock off running */ + + XUA_Buffer(c_ep_out[1], c_ep_in[1], c_sof, c_aud_ctl, p_for_mclk_count, c_aud); + + } + +.. note:: By keeping this configuraiton outside of the ``XUA_Buffer()`` function allow the possiblity to share the ``p_mclk_in_usb`` port with additional components + +To produce a fully operating device a call to ``XUD_Main()`` (from ``lib_xud``) must also be made for USB connectivity:: + + /* Low level USB device layer core */ + on tile[1]: XUD_Main(c_ep_out, 2, c_ep_in, 2, c_sof, epTypeTableOut, epTypeTableIn, null, null, -1, XUD_SPEED_HS, XUD_PWR_SELF); + +Additionally the required communication channels must also be declared:: + + /* Channel arrays for lib_xud */ + chan c_ep_out[2]; + chan c_ep_in[2]; + + /* Channel for communicating SOF notifications from XUD to the Buffering cores */ + chan c_sof; + + /* Channel for audio data between buffering cores and AudioHub/IO core */ + chan c_aud; + + /* Channel for communicating control messages from EP0 to the rest of the device (via the buffering cores) */ + chan c_aud_ctl; + + + +Configuring XUA +~~~~~~~~~~~~~~~ + +Built in main() +~~~~~~~~~~~~~~~ + +Enabling Additional Features +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This sections describes only the basic feature set of ``lib_xua`` details on enabling additional features e.g. S/PDIF can be found later in this document. diff --git a/lib_xua/src/core/audiohub/init_ports.h b/lib_xua/src/core/audiohub/init_ports.h new file mode 100644 index 00000000..f02e9f50 --- /dev/null +++ b/lib_xua/src/core/audiohub/init_ports.h @@ -0,0 +1,106 @@ +#if !CODEC_MASTER +static inline void InitPorts_master(unsigned divide, buffered out port:32 p_lrclk, buffered out port:32 p_bclk) +{ +#if (DSD_CHANS_DAC > 0) + if(dsdMode == DSD_MODE_OFF) + { +#endif + +#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) + + /* Clear I2S port buffers */ + clearbuf(p_lrclk); + +#if (I2S_CHANS_DAC != 0) + for(int i = 0; i < I2S_WIRES_DAC; i++) + { + clearbuf(p_i2s_dac[i]); + } +#endif + +#if (I2S_CHANS_ADC != 0) + for(int i = 0; i < I2S_WIRES_ADC; i++) + { + clearbuf(p_i2s_adc[i]); + } +#endif + +#pragma xta endpoint "divide_1" + unsigned tmp; + p_lrclk <: 0 @ tmp; + tmp += 100; + + /* Since BCLK is free-running, setup outputs/inputs at a known point in the future */ +#if (I2S_CHANS_DAC != 0) +#pragma loop unroll + for(int i = 0; i < I2S_WIRES_DAC; i++) + { + p_i2s_dac[i] @ tmp <: 0; + } +#endif + + p_lrclk @ tmp <: 0x7FFFFFFF; + +#if (I2S_CHANS_ADC != 0) + for(int i = 0; i < I2S_WIRES_ADC; i++) + { + asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1)); + } +#endif +#endif /* (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) */ + + +#if (DSD_CHANS_DAC > 0) + } /* if (!dsdMode) */ + else + { + /* p_dsd_clk must start high */ + p_dsd_clk <: 0x80000000; + } +#endif +} +#endif + +#if CODEC_MASTER +static inline void InitPorts_slave(unsigned divide, buffered in port:32 p_lrclk, buffered in port:32 p_bclk) +{ +#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) + unsigned tmp; + + /* Wait for LRCLK edge (in I2S LRCLK = 0 is left, TDM rising edge is start of frame) */ + p_lrclk when pinseq(0) :> void; + p_lrclk when pinseq(1) :> void; + p_lrclk when pinseq(0) :> void; + p_lrclk when pinseq(1) :> void; +#if I2S_MODE_TDM + p_lrclk when pinseq(0) :> void; + p_lrclk when pinseq(1) :> void @ tmp; +#else + p_lrclk when pinseq(0) :> void @ tmp; +#endif + + tmp += (I2S_CHANS_PER_FRAME * 32) - 32 + 1 ; + /* E.g. 2 * 32 - 32 + 1 = 33 for stereo */ + /* E.g. 8 * 32 - 32 + 1 = 225 for 8 chan TDM */ + +#if (I2S_CHANS_DAC != 0) +#pragma loop unroll + for(int i = 0; i < I2S_WIRES_DAC; i++) + { + p_i2s_dac[i] @ tmp <: 0; + } +#endif + +#if (I2S_CHANS_ADC != 0) +#pragma loop unroll + for(int i = 0; i < I2S_WIRES_ADC; i++) + { + asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1)); + } +#endif + + asm("setpt res[%0], %1"::"r"(p_lrclk),"r"(tmp-1)); +#endif /* (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) */ +} +#endif + diff --git a/lib_xua/src/core/audiohub/xua_audiohub.xc b/lib_xua/src/core/audiohub/xua_audiohub.xc index 09e80453..1c67f487 100755 --- a/lib_xua/src/core/audiohub/xua_audiohub.xc +++ b/lib_xua/src/core/audiohub/xua_audiohub.xc @@ -76,21 +76,9 @@ extern buffered out port:32 p_i2s_dac[I2S_WIRES_DAC]; extern buffered in port:32 p_i2s_adc[I2S_WIRES_ADC]; #endif -/* I2S LR/Bit clock I/O */ -#if CODEC_MASTER -extern buffered in port:32 p_lrclk; -extern buffered in port:32 p_bclk; -#else -extern buffered out port:32 p_lrclk; -extern buffered out port:32 p_bclk; -#endif unsigned dsdMode = DSD_MODE_OFF; -/* Master clock input */ -extern in port p_mclk_in; -extern in port p_mclk_in2; - #if (XUA_SPDIF_TX_EN) extern buffered out port:32 p_spdif_tx; #endif @@ -99,15 +87,10 @@ extern buffered out port:32 p_spdif_tx; extern buffered out port:32 p_adat_tx; #endif -extern clock clk_audio_mclk; -extern clock clk_audio_bclk; - #if XUA_SPDIF_TX_EN || defined(ADAT_TX) extern clock clk_mst_spd; #endif -//extern void device_reboot(void); - #define MAX_DIVIDE_48 (MCLK_48/MIN_FREQ_48/64) #define MAX_DIVIDE_44 (MCLK_44/MIN_FREQ_44/64) #if (MAX_DIVIDE_44 > MAX_DIVIDE_48) @@ -116,10 +99,14 @@ extern clock clk_mst_spd; #define MAX_DIVIDE (MAX_DIVIDE_48) #endif + +#include "init_ports.h" + #ifdef ADAT_TX unsigned adatCounter = 0; unsigned adatSamples[8]; + #pragma unsafe arrays static inline void TransferAdatTxSamples(chanend c_adat_out, const unsigned samplesFromHost[], int smux, int handshake) { @@ -182,9 +169,11 @@ static inline unsigned DoSampleTransfer(chanend c_out, const int readBuffNo, con #ifndef CODEC_MASTER if(dsdMode == DSD_MODE_OFF) { - // Set clocks low +#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) + /* Set clocks low */ p_lrclk <: 0; p_bclk <: 0; +#endif } else { @@ -293,9 +282,11 @@ static inline int DoDsdDopCheck(unsigned &dsdMode, int &dsdCount, unsigned curSa dsdCount = 0; dsdMarker = DSD_MARKER_2; +#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) // Set clocks low p_lrclk <: 0; p_bclk <: 0; +#endif p_dsd_clk <: 0; return 0; } @@ -315,8 +306,10 @@ static inline int DoDsdDopCheck(unsigned &dsdMode, int &dsdCount, unsigned curSa { dsdMode = DSD_MODE_OFF; // Set clocks low +#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) p_lrclk <: 0; p_bclk <: 0; +#endif p_dsd_clk <: 0; return 0; } @@ -327,104 +320,6 @@ static inline int DoDsdDopCheck(unsigned &dsdMode, int &dsdCount, unsigned curSa } #endif -#if !CODEC_MASTER -static inline void InitPorts_master(unsigned divide) -{ - unsigned tmp; -#if (DSD_CHANS_DAC > 0) - if(dsdMode == DSD_MODE_OFF) - { -#endif - /* Clear I2S port buffers */ - clearbuf(p_lrclk); - -#if (I2S_CHANS_DAC != 0) - for(int i = 0; i < I2S_WIRES_DAC; i++) - { - clearbuf(p_i2s_dac[i]); - } -#endif - -#if (I2S_CHANS_ADC != 0) - for(int i = 0; i < I2S_WIRES_ADC; i++) - { - clearbuf(p_i2s_adc[i]); - } -#endif - -#pragma xta endpoint "divide_1" - p_lrclk <: 0 @ tmp; - tmp += 100; - - /* Since BCLK is free-running, setup outputs/inputs at a known point in the future */ -#if (I2S_CHANS_DAC != 0) -#pragma loop unroll - for(int i = 0; i < I2S_WIRES_DAC; i++) - { - p_i2s_dac[i] @ tmp <: 0; - } -#endif - - p_lrclk @ tmp <: 0x7FFFFFFF; - -#if (I2S_CHANS_ADC != 0) - for(int i = 0; i < I2S_WIRES_ADC; i++) - { - asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1)); - } -#endif - -#if (DSD_CHANS_DAC > 0) - } /* if (!dsdMode) */ - else - { - /* p_dsd_clk must start high */ - p_dsd_clk <: 0x80000000; - } -#endif -} -#endif - -#if CODEC_MASTER -static inline void InitPorts_slave(unsigned divide) -{ - unsigned tmp; - - /* Wait for LRCLK edge (in I2S LRCLK = 0 is left, TDM rising edge is start of frame) */ - p_lrclk when pinseq(0) :> void; - p_lrclk when pinseq(1) :> void; - p_lrclk when pinseq(0) :> void; - p_lrclk when pinseq(1) :> void; -#if I2S_MODE_TDM - p_lrclk when pinseq(0) :> void; - p_lrclk when pinseq(1) :> void @ tmp; -#else - p_lrclk when pinseq(0) :> void @ tmp; -#endif - - tmp += (I2S_CHANS_PER_FRAME * 32) - 32 + 1 ; - /* E.g. 2 * 32 - 32 + 1 = 33 for stereo */ - /* E.g. 8 * 32 - 32 + 1 = 225 for 8 chan TDM */ - -#if (I2S_CHANS_DAC != 0) -#pragma loop unroll - for(int i = 0; i < I2S_WIRES_DAC; i++) - { - p_i2s_dac[i] @ tmp <: 0; - } -#endif - -#if (I2S_CHANS_ADC != 0) -#pragma loop unroll - for(int i = 0; i < I2S_WIRES_ADC; i++) - { - asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1)); - } -#endif - - asm("setpt res[%0], %1"::"r"(p_lrclk),"r"(tmp-1)); -} -#endif @@ -442,6 +337,7 @@ unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out #if (NUM_PDM_MICS > 0) , chanend c_pdm_pcm #endif + , buffered out port:32 p_lrclk, buffered out port:32 p_bclk ) { /* Since DAC and ADC buffered ports off by one sample we buffer previous ADC frame */ @@ -533,7 +429,7 @@ unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out return command; } - InitPorts_master(divide); + InitPorts_master(divide, p_lrclk, p_bclk); /* Main Audio I/O loop */ while (1) @@ -598,11 +494,13 @@ unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out /* LR clock delayed by one clock, This is so MSB is output on the falling edge of BCLK * after the falling edge on which LRCLK was toggled. (see I2S spec) */ /* Generate clocks LR Clock low - LEFT */ -#if I2S_MODE_TDM +#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) +#if I2S_MODE_TDM p_lrclk <: 0x00000000; #else p_lrclk <: 0x80000000; #endif +#endif #pragma xta endpoint "i2s_output_l" @@ -725,6 +623,7 @@ unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out } #endif +#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) #if I2S_MODE_TDM if(frameCount == (I2S_CHANS_PER_FRAME-2)) p_lrclk <: 0x80000000; @@ -732,6 +631,7 @@ unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out p_lrclk <: 0x00000000; #else p_lrclk <: 0x7FFFFFFF; +#endif #endif index = 0; @@ -821,6 +721,7 @@ unsigned static deliver_slave(chanend ?c_out, chanend ?c_spd_out #if (NUM_PDM_MICS > 0) , chanend c_pdm_pcm #endif + , buffered in port:32 p_lrclk, buffered in port:32 p_bclk ) { /* Since DAC and ADC buffered ports off by one sample we buffer previous ADC frame */ @@ -903,7 +804,7 @@ unsigned static deliver_slave(chanend ?c_out, chanend ?c_spd_out unsigned lrval; unsigned syncError = 0; - InitPorts_slave(divide); + InitPorts_slave(divide, p_lrclk, p_bclk); while (!syncError) { @@ -956,8 +857,10 @@ unsigned static deliver_slave(chanend ?c_out, chanend ?c_spd_out } #endif //(I2S_CHANS_ADC != 0) +#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) /* LR Clock sync check */ p_lrclk :> lrval; +#endif if(I2S_MODE_TDM) { @@ -1094,9 +997,10 @@ unsigned static deliver_slave(chanend ?c_out, chanend ?c_spd_out } #endif //(I2S_CHANS_ADC != 0) +#if (I2S_CHANS_ADC != 0 || I2S_CHANS_DAC != 0) /* LR Clock sync check */ p_lrclk :> lrval; - +#endif if(I2S_MODE_TDM) { /* Do nothing */ @@ -1179,7 +1083,7 @@ void SpdifTxWrapper(chanend c_spdif_tx) // TODO could share clock block here.. // NOTE, Assuming SPDIF tile == USB tile here.. - asm("ldw %0, dp[p_mclk_in2]":"=r"(portId)); + asm("ldw %0, dp[p_mclk_in_usb]":"=r"(portId)); asm("setclk res[%0], %1"::"r"(clk_mst_spd), "r"(portId)); configure_out_port_no_ready(p_spdif_tx, clk_mst_spd, 0); set_clock_fall_delay(clk_mst_spd, 7); @@ -1261,7 +1165,10 @@ static void dummy_deliver(chanend ?c_out, unsigned &command) void DFUHandler(server interface i_dfu i, chanend ?c_user_cmd); #endif -void XUA_AudioHub(chanend ?c_mix_out +void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk, + in port p_mclk_in, + buffered _XUA_CLK_DIR port:32 ?p_lrclk, + buffered _XUA_CLK_DIR port:32 ?p_bclk #if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE) , chanend c_spdif_out #endif @@ -1457,7 +1364,7 @@ void XUA_AudioHub(chanend ?c_mix_out #endif /* Handshake back */ #ifndef NO_USB - outct(c_mix_out, XS1_CT_END); + outct(c_aud, XS1_CT_END); #endif } } @@ -1505,9 +1412,9 @@ void XUA_AudioHub(chanend ?c_mix_out outuint(c_adat_out, adatSmuxMode); #endif #if CODEC_MASTER - command = deliver_slave(c_mix_out + command = deliver_slave(c_aud #else - command = deliver_master(c_mix_out + command = deliver_master(c_aud #endif #if (XUA_SPDIF_TX_EN) , c_spdif_out @@ -1525,12 +1432,14 @@ void XUA_AudioHub(chanend ?c_mix_out #if (NUM_PDM_MICS > 0) , c_pdm_in #endif + , p_lrclk, + p_bclk ); #ifndef NO_USB if(command == SET_SAMPLE_FREQ) { - curSamFreq = inuint(c_mix_out) * AUD_TO_USB_RATIO; + curSamFreq = inuint(c_aud) * AUD_TO_USB_RATIO; } else if(command == SET_STREAM_FORMAT_OUT) { @@ -1538,17 +1447,17 @@ void XUA_AudioHub(chanend ?c_mix_out * DOP = 1 * Native = 2 */ - dsdMode = inuint(c_mix_out); - curSamRes_DAC = inuint(c_mix_out); + dsdMode = inuint(c_aud); + curSamRes_DAC = inuint(c_aud); } #if (XUA_DFU_EN == 1) /* Currently no more audio will happen after this point */ if ((curSamFreq / AUD_TO_USB_RATIO) == AUDIO_STOP_FOR_DFU) { - outct(c_mix_out, XS1_CT_END); + outct(c_aud, XS1_CT_END); - outuint(c_mix_out, 0); + outuint(c_aud, 0); while (1) { diff --git a/tests/app_test_i2s_loopback/main.xc b/tests/app_test_i2s_loopback/main.xc index a32d7b39..dc73e726 100644 --- a/tests/app_test_i2s_loopback/main.xc +++ b/tests/app_test_i2s_loopback/main.xc @@ -219,7 +219,7 @@ int main(void) { par { - XUA_AudioHub(c_out); + XUA_AudioHub(c_out, clk_audio_mclk, clk_audio_bclk, p_mclk_in, p_lrclk, p_bclk); generator(c_checker, c_out); checker(c_checker, 0); #ifdef SIMULATION