SPRUGR9H November 2010 – April 2015 66AK2E05 , 66AK2H06 , 66AK2H12 , 66AK2H14 , 66AK2L06 , AM5K2E02 , AM5K2E04 , SM320C6678-HIREL , TMS320C6652 , TMS320C6654 , TMS320C6655 , TMS320C6657 , TMS320C6670 , TMS320C6671 , TMS320C6672 , TMS320C6674 , TMS320C6678
Multicore Navigator is designed to be initialized at startup with enough resources to keep it running successfully during normal operation.
First, define memory areas to be used, and align them to 16 byte boundaries (only the QM memories require alignment, but it is a good idea to align the others as well):
#pragma DATA_ALIGN (host_region, 16)
Uint8 host_region[64 * 64];
#pragma DATA_ALIGN (mono_region, 16)
Uint8 mono_region[32 * 160];
#pragma DATA_ALIGN (buffers, 16)
Uint32 buffers[64 * 256]; //these buffers are for Host Packets
#pragma DATA_ALIGN (hostList, 16)
Uint32 hostList[34]; // ping/pong of (16 + 1 word for list count)
#pragma DATA_ALIGN (monoList, 16)
Uint32 monoList[34]; // ping/pong of (16 + 1 word for list count)
Some declarations for clarity in the following code segments (see appendices for type definitions):
MNAV_HostPacketDescriptor *host_pkt;
MNAV_MonolithicPacketDescriptor *mono_pkt;
Qmss_AccCmd cmd;
Next, setup the QM memory regions to be used. This example will setup two: one for host descriptors and another for monolithic descriptors. The part that requires the most attention is specifying the size. The last parameter writes to the Memory Region Setup Register, and defines the size of the descriptor and the number of descriptors (see this register definition in previous sections).
/* Setup Memory Region 0 for 40 56 byte Host descriptors. Our
* Host descriptors will be 32 bytes plus up to 6 words of PS data,
* but the next best size is 64 bytes times 64 descriptors. */
set_memory_region(0, (Uint32) host_region, 0, 0x00030001);
/* Setup Memory Region 1 for 8 148B Monolithic descriptors. Our
* Mono descriptors will be 12 bytes plus 16 bytes of EPIB Info, plus
* 128 bytes of payload, but the next best size is 160 bytes times
* 32 descriptors. (dead space is possible) */
set_memory_region(1, (Uint32) mono_region, 64, 0x00090000);
An external Linking RAM needs to be configured with one 64-bit word for each descriptor in the memory regions that use the external Linking RAM. The internal Linking RAM does not require a buffer to be allocated for it.
/*****************************************************************
* Configure Linking RAM 0 to use the 16k entry internal link ram.
*/
set_link_ram(0, 0x00080000, 0x3FFF);
Note that Linking RAM 0 may be configured to use internal QMSS memory as shown here. Linking RAM 1 may use L2 or DDR. For efficiency reasons, it is best to use the internal QMSS Link RAM memory whenever possible.
Once the memory regions and Link RAMs have been configured, two types of queues should be filled with empty descriptors: TX completion queues (otherwise known as TX FDQs), and RX FDQs.
/* Initialize descriptor regions to zero */
memset(host_region, 0, 64 * 64);
memset(mono_region, 0, 32 * 160);
/* Push Host Descriptors to Tx Completion Queue (FDQ) 5000 */
for (idx = 0; idx < 20; idx ++)
{
host_pkt = (MNAV_HostPacketDescriptor *)(host_region + (idx * 64));
host_pkt->pkt_return_qmgr = 1;
host_pkt->pkt_return_qnum = 0;
host_pkt->orig_buff0_len = 64 * 4;
host_pkt->orig_buff0_ptr = (Uint32)(buffers + (idx * 128));
host_pkt->next_desc_ptr = NULL;
push_queue(5000, 1, 0, (Uint32)(host_pkt));
}
/* Push Monolithic packets to Tx Completion Queue (FDQ) 5001 */
for (idx = 0; idx < 16; idx ++)
{
mono_pkt = (MNAV_MonolithicPacketDescriptor *)(mono_region + (idx * 160));
mono_pkt->pkt_return_qmgr = 1;
mono_pkt->pkt_return_qnum = 1;
push_queue(5001, 1, 0, (Uint32)(mono_pkt));
}
/* Push Host Descriptors to Rx FDQ 7000 */
for (idx = 20; idx < 64; idx ++)
{
host_pkt = (MNAV_HostPacketDescriptor *)(host_region + (idx * 64));
/* Set non-Rx overwrite fields */
host_pkt->orig_buff0_len = 64 * 4;
host_pkt->orig_buff0_ptr = (Uint32)(buffers + (idx * 128));
host_pkt->next_desc_ptr = NULL; //don’t link Host buffers in Rx FDQ
push_queue(7000, 1, 0, (Uint32)(host_pkt));
}
/* Push Monolithic packets to Rx FDQ 7001 */
for (idx = 16; idx < 32; idx ++)
{
mono_pkt = (MNAV_MonolithicPacketDescriptor *)(mono_region + (idx * 160));
push_queue(7001, 1, 0, (Uint32)(mono_pkt));
}
Last, program the accumulator channels that are needed. Both of these channels are programmed to return only the QM Reg D value per descriptor. The high priority program will use the list count method and the low priority program will use NULL termination. The second time the interrupt triggers, the accumulators will write to the pong side of the lists (in both cases starting with word 17). It is up to the host to process and recycle the descriptors before that ping or pong side is needed again by the accumulator (which does not check for consumption).
/*****************************************************************
* Program a hi-pri accumulation channel for queue 712.
*/
cmd.command = 0x81; //enable
cmd.channel = 8; //will trigger qmss_intr1_8 to core 0
cmd.queue_mask = 0; //not used in single mode
cmd.list_address = (uint32_t)hostList; //address of ping buffer
cmd.max_entries = 17; //list can hold up to 16 (max-1)
cmd.qm_index = 712; //que to monitor for channel 8
cmd.cfg_multi_q = 0; //0=single queue mode
cmd.cfg_list_mode = 1; //1=list count in first entry
cmd.cfg_list_size = 0; //0="D" Reg
cmd.cfg_int_delay = 1; //1=delay since last interrupt (pacing mode)
cmd.timer_count = 1; //number of timer ticks to delay interrupt
program_accumulator(1, &cmd);
/*****************************************************************
* Program a lo-pri accumulation channel for queue 32.
*/
cmd.command = 0x81; //enable
cmd.channel = 1; //will trigger qmss_intr0_1 to all cores
cmd.queue_mask = 0x00000001; //look only at queue 32 for this example
cmd.list_address = (uint32_t)monoList; //address of ping buffer
cmd.max_entries = 17; //list can hold up to 16 (max-1)
cmd.qm_index = 32; //first que to monitor for this channel
cmd.cfg_multi_q = 1; //1=multi queue mode
cmd.cfg_list_mode = 0; //0=NULL terminated list
cmd.cfg_list_size = 0; //0="D" Reg
cmd.cfg_int_delay = 1; //1=delay since last interrupt (pacing mode)
cmd.timer_count = 1; //number of timer ticks to delay interrupt
program_accumulator(0, &cmd);
/* Clear the Accumulator lists. */
memset(hostList, 0, 34 * 4);
memset(monoList, 0, 34 * 4);