From 21c5733fc839becea17ff1763a2dc6edf6b45ef8 Mon Sep 17 00:00:00 2001 From: Patrick Nowakowski Date: Mon, 26 Feb 2024 17:20:15 -0600 Subject: [PATCH 1/6] Update ICC files to pass MessageBuffer data, handles, and callback pointers using shared memory --- sdk/freertos_app_cpu0/src/main.c | 14 ++-- sdk/freertos_app_cpu1/src/main.c | 16 ++--- sdk/shared/sys/icc.c | 115 ++++++++++++++++++++++--------- sdk/shared/sys/icc.h | 90 +++++++++++++++--------- sdk/shared/sys/intr.c | 8 +-- 5 files changed, 158 insertions(+), 85 deletions(-) diff --git a/sdk/freertos_app_cpu0/src/main.c b/sdk/freertos_app_cpu0/src/main.c index 9a77b434..bc6034d1 100644 --- a/sdk/freertos_app_cpu0/src/main.c +++ b/sdk/freertos_app_cpu0/src/main.c @@ -155,7 +155,7 @@ int main(void) (const char *) "CPU0_Tx", /* Text name for the task, provided to assist debugging only. */ configMINIMAL_STACK_SIZE, /* The stack allocated to the task. */ NULL, /* The task parameter is not used, so set to NULL. */ - tskIDLE_PRIORITY, /* The task runs at the idle priority. */ + tskIDLE_PRIORITY, &xTxTaskHandle); xTaskCreate(prvRxTask, /* The function that implements the task. */ @@ -233,15 +233,15 @@ static void prvTxTask(void *pvParameters) // HWstring, /* The address of the data being sent. */ // 0UL); /* The block time. */ - xil_printf("DEBUG: CPU 0 about to attempt send\r\n"); + xil_printf("DEBUG: CPU0 about to attempt send\r\n"); // Send a message to the other core - size_t bytes_sent = xMessageBufferSend(xCPU0to1MessageBuffer, HWstring, sizeof(HWstring), 0UL); + size_t bytes_sent = xMessageBufferSend(xCPU0to1MessageBufferHandle, HWstring, sizeof(HWstring), 0UL); xil_printf("DEBUG: CPU0 sent %d bytes to ICC buffer\r\n", bytes_sent); if (bytes_sent == 0) { - xil_printf("ERROR: CPU 0 failed to write to ICC buffer\r\n"); + xil_printf("ERROR: CPU0 failed to write to ICC buffer\r\n"); } } } @@ -263,14 +263,14 @@ static void prvRxTask(void *pvParameters) // Rcvdstring, /* Data is read into this address. */ // portMAX_DELAY); /* Wait without a timeout for data. */ - xil_printf("DEBUG: CPU 0 about to attempt rcv\r\n"); + xil_printf("DEBUG: CPU0 about to attempt rcv\r\n"); - size_t bytes_rcvd = xMessageBufferReceive(xCPU1to0MessageBuffer, Rcvdstring, 32, portMAX_DELAY); + size_t bytes_rcvd = xMessageBufferReceive(xCPU1to0MessageBufferHandle, Rcvdstring, 32, portMAX_DELAY); xil_printf("DEBUG: CPU0 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd); if (bytes_rcvd == 0) { - xil_printf("CPU 0 failed to receive from ICC buffer\r\n"); + xil_printf("CPU0 failed to receive from ICC buffer\r\n"); } else { /* Print the received data. */ xil_printf("CPU0 - Rx task received string from CPU1 Tx: %s\r\n", Rcvdstring); diff --git a/sdk/freertos_app_cpu1/src/main.c b/sdk/freertos_app_cpu1/src/main.c index 3565a044..4e6a884b 100644 --- a/sdk/freertos_app_cpu1/src/main.c +++ b/sdk/freertos_app_cpu1/src/main.c @@ -129,7 +129,7 @@ int main(void) (const char *) "CPU1_Tx", /* Text name for the task, provided to assist debugging only. */ configMINIMAL_STACK_SIZE, /* The stack allocated to the task. */ NULL, /* The task parameter is not used, so set to NULL. */ - tskIDLE_PRIORITY, /* The task runs at the idle priority. */ + tskIDLE_PRIORITY, &xTxTaskHandle); xTaskCreate(prvRxTask, /* The function that implements the task. */ @@ -199,15 +199,15 @@ static void prvTxTask(void *pvParameters) // HWstring, /* The address of the data being sent. */ // 0UL); /* The block time. */ - xil_printf("DEBUG: CPU 1 about to attempt send\r\n"); + xil_printf("DEBUG: CPU1 about to attempt send\r\n"); // Send a message to the other core - size_t bytes_sent = xMessageBufferSend(xCPU1to0MessageBuffer, HWstring, sizeof(HWstring), 0UL); + size_t bytes_sent = xMessageBufferSend(xCPU1to0MessageBufferHandle, HWstring, sizeof(HWstring), 0UL); xil_printf("DEBUG: CPU1 sent %d bytes to ICC buffer\r\n", bytes_sent); if (bytes_sent == 0) { - xil_printf("ERROR: CPU 1 failed to write to ICC buffer\r\n"); + xil_printf("ERROR: CPU1 failed to write to ICC buffer\r\n"); } } } @@ -229,14 +229,14 @@ static void prvRxTask(void *pvParameters) // Rcvdstring, /* Data is read into this address. */ // portMAX_DELAY); /* Wait without a timeout for data. */ - xil_printf("DEBUG: CPU 1 about to attempt rcv\r\n"); + xil_printf("DEBUG: CPU1 about to attempt rcv\r\n"); - size_t bytes_rcvd = xMessageBufferReceive(xCPU0to1MessageBuffer, Rcvdstring, 32, portMAX_DELAY); + size_t bytes_rcvd = xMessageBufferReceive(xCPU0to1MessageBufferHandle, Rcvdstring, 32, portMAX_DELAY); - xil_printf("DEBUG: CPU1 rcvd %d bytes from ICC buffer", bytes_rcvd); + xil_printf("DEBUG: CPU1 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd); if (bytes_rcvd == 0) { - xil_printf("CPU 1 failed to receive from ICC buffer\r\n"); + xil_printf("CPU1 failed to receive from ICC buffer\r\n"); } else { /* Print the received data. */ xil_printf("CPU1 - Rx task received string from CPU0 Tx: %s\r\n", Rcvdstring); diff --git a/sdk/shared/sys/icc.c b/sdk/shared/sys/icc.c index 2673a593..8f092647 100644 --- a/sdk/shared/sys/icc.c +++ b/sdk/shared/sys/icc.c @@ -8,31 +8,74 @@ // CPUs, use "#if XPAR_CPU_ID == ?" /////////////////////////////////////////////////////// -void icc_init(uint32_t cpu_num) +void icc_init() { #if XPAR_CPU_ID == 0 - // ONLY CPU 0 INITIALIZES THE MESSAGE BUFFERS + // ONLY CPU 0 INITIALIZES THE MESSAGE BUFFERS + + // Wait for CPU1 to provide the function pointers to its callbacks () + while (!ICC_getFunctionPointersReady) + ; + + // Use the getters once ready + void (*vCPU0to1ReceiveCallback)() = ICC_getCPU0to1ReceiveCallback; + xil_printf("DEBUG: CPU 0 got 0to1 Receive Callback %p\r\n", (void *) vCPU0to1ReceiveCallback); + void (*vCPU1to0SendCallback)() = ICC_getCPU1to0SendCallback; + xil_printf("DEBUG: CPU 0 got 1to0 Send Callback %p\r\n", (void *) vCPU1to0SendCallback); /* Create two message buffers for inter-core communication that use the callback * functions below as send and receive completed callback functions. */ - xCPU0to1MessageBuffer = xMessageBufferCreateStaticWithCallback(ICC_BUFFER_SIZE - 1, - ICC_CPU0to1_BufferSpaceAddr, - ICC_CPU0to1_BufferStructAddr, - vCPU0to1SendCallback, - vCPU0to1ReceiveCallback); - - xCPU1to0MessageBuffer = xMessageBufferCreateStaticWithCallback(ICC_BUFFER_SIZE - 1, - ICC_CPU1to0_BufferSpaceAddr, - ICC_CPU1to0_BufferStructAddr, - vCPU1to0SendCallback, - vCPU1to0ReceiveCallback); + xCPU0to1MessageBufferHandle = xMessageBufferCreateStaticWithCallback( + ICC_BUFFER_SIZE - 1, + ICC_CPU0to1BufferSpaceAddr, + ICC_CPU0to1BufferStructAddr, + vCPU0to1SendCallback, // Called by CPU0 after placing message in 0to1 buffer + vCPU0to1ReceiveCallback); // Called by CPU1 after removing message from 0to1 buffer + + xCPU1to0MessageBufferHandle = xMessageBufferCreateStaticWithCallback( + ICC_BUFFER_SIZE - 1, + ICC_CPU1to0BufferSpaceAddr, + ICC_CPU1to0BufferStructAddr, + vCPU1to0SendCallback, // Called by CPU1 after placing message in 1to0 buffer + vCPU1to0ReceiveCallback); // Called by CPU0 after removing message from 1to0 buffer + + ICC_setCPU0to1Handle(xCPU0to1MessageBufferHandle); + xil_printf("DEBUG: CPU 0 set 0to1 Handle %p\r\n", (void *) xCPU0to1MessageBufferHandle); + // void * test = ICC_getCPU0to1Handle; + // xil_printf("DEBUG: CPU 0 got 0to1 Handle %p\r\n",(void *)test); + ICC_setCPU1to0Handle(xCPU1to0MessageBufferHandle); + xil_printf("DEBUG: CPU 0 set 1to0 Handle %p\r\n", (void *) xCPU1to0MessageBufferHandle); + + ICC_setHandleComplete; +#elif XPAR_CPU_ID == 1 + /* need to stall 10ms to "guarantee" that CPU1 does not get before CPU0 sets + * The APU freq is 666,666,687 Hz (per ps7_init.h), so a single NOP is 1/(666,666,687) or 1.5ns + * Therefore we need 6.66E6 NOPs to stall 10ms + */ + + // Make CPU1's callback function pointers available to CPU0 + ICC_setCPU1to0SendCallback(&vCPU1to0SendCallback); + xil_printf("DEBUG: CPU 1 set 1to0 Send Callback %p\r\n", &vCPU1to0SendCallback); + ICC_setCPU0to1ReceiveCallback(&vCPU0to1ReceiveCallback); + xil_printf("DEBUG: CPU 1 set 0to1 Receive Callback %p\r\n", &vCPU0to1ReceiveCallback); + + ICC_setFunctionPointersReady; + + // Wait for CPU0 to finish creating buffers and providing the handles + while (!ICC_getHandleComplete) + ; + + xCPU0to1MessageBufferHandle = ICC_getCPU0to1Handle; + xil_printf("DEBUG: CPU 1 got 0to1 Handle %p\r\n", (void *) xCPU0to1MessageBufferHandle); + xCPU1to0MessageBufferHandle = ICC_getCPU1to0Handle; + xil_printf("DEBUG: CPU 1 got 1to0 Handle %p\r\n", (void *) xCPU1to0MessageBufferHandle); #endif } /* From FreeRTOS: * Insert code into callback which is invoked when a message is written to the message buffer. * This is useful when a message buffer is used to pass messages between - * cores on a multicore processor. In that scenario, this callback + * cores on a multi-core processor. In that scenario, this callback * can be implemented to generate an interrupt in the other CPU core, * and the interrupt's service routine can then use the * xMessageBufferSendCompletedFromISR() API function to check, and if @@ -46,46 +89,50 @@ void icc_init(uint32_t cpu_num) * send to the 0 to 1 buffer, so in CPU 1 this callback doesn't need to DO ANYTHING except exist. * - Patrick */ +#if XPAR_CPU_ID == 0 + void vCPU0to1SendCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken) { -#if XPAR_CPU_ID == 0 - xil_printf("DEBUG: CPU 0 to 1 Send Callback reached\r\n"); - // In CPU 0, this callback should send an interrupt to CPU 1's Rx task - XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_SEND_INTERRUPT_ID, CPU1_ID); -#endif + xil_printf("DEBUG: CPU 0 to 1 Send Callback reached (in CPU0)\r\n"); + // In CPU 0, this callback should send an interrupt to CPU 1 to unblock its Rx task + + // XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_SEND_INTERRUPT_ID, CPU1_ID); } void vCPU1to0ReceiveCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken) { -#if XPAR_CPU_ID == 0 - xil_printf("DEBUG: CPU 1 to 0 Receive Callback reached\r\n"); - // In CPU 0, this callback should send an interrupt to CPU 1's Tx task - XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_RCVE_INTERRUPT_ID, CPU1_ID); -#endif + xil_printf("DEBUG: CPU 1 to 0 Receive Callback reached (in CPU0)\r\n"); + // In CPU 0, this callback should send an interrupt to CPU 1 to unblock its Tx task + // (since the buffer might have an open space now) + + // XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_RCVE_INTERRUPT_ID, CPU1_ID); } +#elif XPAR_CPU_ID == 1 + void vCPU1to0SendCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken) { -#if XPAR_CPU_ID == 1 - xil_printf("DEBUG: CPU 1 to 0 Send Callback reached\r\n"); - // In CPU 1, this callback should send an interrupt to CPU 0's Rx task - XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_SEND_INTERRUPT_ID, CPU0_ID); -#endif + xil_printf("DEBUG: CPU 1 to 0 Send Callback reached (in CPU1)\r\n"); + // In CPU 1, this callback should send an interrupt to CPU 0 to unblock its Rx task + + // XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_SEND_INTERRUPT_ID, CPU0_ID); } void vCPU0to1ReceiveCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken) { -#if XPAR_CPU_ID == 1 - xil_printf("DEBUG: CPU 0 to 1 Receive Callback reached\r\n"); - // In CPU 1, this callback should send an interrupt to CPU 0's Tx task - XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_RCVE_INTERRUPT_ID, CPU0_ID); -#endif + xil_printf("DEBUG: CPU 0 to 1 Receive Callback reached (in CPU1)\r\n"); + // In CPU 1, this callback should send an interrupt to CPU 0 to unblock its Tx task + // (since the buffer might have an open space) + + // XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_RCVE_INTERRUPT_ID, CPU0_ID); } + +#endif diff --git a/sdk/shared/sys/icc.h b/sdk/shared/sys/icc.h index c8d82879..2fecadc7 100644 --- a/sdk/shared/sys/icc.h +++ b/sdk/shared/sys/icc.h @@ -36,54 +36,80 @@ // of OCM is split between low addresses and high addresses in 64 KB chunks. // // We will pick to use the highest 64 KB chunk as our base address: -#define OCM_BASE_ADDR (0xFFFF0000) +#define OCM_BASE_ADDR (0xFFFF0000) #define ICC_BUFFER_STRUCT_SIZE (sizeof(StaticMessageBuffer_t)) -#define ICC_BUFFER_SIZE (4 * 1024) -#define ICC_HANDLE_SIZE (sizeof(MessageBufferHandle_t)) - - -/* Define the pointers to the two structs (that store the metadata) and two message spaces (that hold the messages) in shared memory. - * The ICC_BUFFER_SIZE Should be one more than the value passed in the xBufferSizeBytes parameter. - * The two structs will be located back-to-back right at the base addr of the shared OCM, followed thereafter by the actual message buffers. */ -#define ICC_CPU0to1_BufferStructAddr ((uint8_t *) (OCM_BASE_ADDR + (0 * ICC_BUFFER_STRUCT_SIZE))) -#define ICC_CPU1to0_BufferStructAddr ((uint8_t *) (OCM_BASE_ADDR + (1 * ICC_BUFFER_STRUCT_SIZE))) - -#define ICC_CPU0to1_BufferSpaceAddr ((uint8_t *) (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (0 * ICC_BUFFER_SIZE))) -#define ICC_CPU1to0_BufferSpaceAddr ((uint8_t *) (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (1 * ICC_BUFFER_SIZE))) - - -/* These memory spaces are used to transfer the Message Buffer Handles from CPU0 (who does the initialization work, and gets the handles - * from the xMessageBufferCreateStaticWithCallback function) to CPU1 (who doesn't initialize anything and gets the handles from CPU0, via - * these drop-zones) */ -#define ICC_CPU0to1_HandleDropzoneAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (0 * ICC_HANDLE_SIZE))) -#define ICC_CPU1to0_HandleDropzoneAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (1 * ICC_HANDLE_SIZE))) - -#define ICC_getCPU0to1Handle (*((MessageBufferHandle_t *) ICC_CPU0to1_HandleDropzoneAddr)) -#define ICC_setCPU0to1Handle(handle) (*((MessageBufferHandle_t *) ICC_CPU0to1_HandleDropzoneAddr) = handle) -#define ICC_getCPU1to0Handle (*((MessageBufferHandle_t *) ICC_CPU1to0_HandleDropzoneAddr)) -#define ICC_setCPU1to0Handle(handle) (*((MessageBufferHandle_t *) ICC_CPU1to0_HandleDropzoneAddr) = handle) - - +#define ICC_BUFFER_SIZE (4 * 1024) +#define ICC_HANDLE_SIZE (sizeof(MessageBufferHandle_t)) +#define ICC_LOCK_SIZE (sizeof(uint8_t)) +#define ICC_FUNC_PTR_SIZE (sizeof(void *)) + +/* Define the pointers to the two structs (that store the metadata) and two message spaces (that hold the messages) in + * shared memory. The ICC_BUFFER_SIZE Should be one more than the value passed in the xBufferSizeBytes parameter. The + * two structs will be located back-to-back right at the base addr of the shared OCM, followed thereafter by the actual + * message buffers. */ +#define ICC_CPU0to1BufferStructAddr ((uint8_t *) (OCM_BASE_ADDR + (0 * ICC_BUFFER_STRUCT_SIZE))) +#define ICC_CPU1to0BufferStructAddr ((uint8_t *) (OCM_BASE_ADDR + (1 * ICC_BUFFER_STRUCT_SIZE))) + +#define ICC_CPU0to1BufferSpaceAddr ((uint8_t *) (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (0 * ICC_BUFFER_SIZE))) +#define ICC_CPU1to0BufferSpaceAddr ((uint8_t *) (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (1 * ICC_BUFFER_SIZE))) + +/* These memory spaces are used to transfer the Message Buffer Handles from CPU0 (who does the initialization work, and + * gets the handles from the xMessageBufferCreateStaticWithCallback function) to CPU1 (who doesn't initialize anything + * and gets the handles from CPU0, via these drop-zones) */ +#define ICC_CPU0to1HandleDropzoneAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (0 * ICC_HANDLE_SIZE))) +#define ICC_CPU1to0HandleDropzoneAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (1 * ICC_HANDLE_SIZE))) + +#define ICC_getCPU0to1Handle ((*((MessageBufferHandle_t *) ICC_CPU0to1HandleDropzoneAddr)) +#define ICC_setCPU0to1Handle(handle) ((*((MessageBufferHandle_t *) ICC_CPU0to1HandleDropzoneAddr) = handle) +#define ICC_getCPU1to0Handle ((*((MessageBufferHandle_t *) ICC_CPU1to0HandleDropzoneAddr)) +#define ICC_setCPU1to0Handle(handle) ((*((MessageBufferHandle_t *) ICC_CPU1to0HandleDropzoneAddr) = handle) + +/* We need a concurrency lock in the shared memory to make sure that CPU0 always sets the handles before + * CPU1 attempts to get them. This is initialized to 0, and CPU0 sets it to 1. CPU1 will wait till it sees + * this change before attempting to get the handles. */ +#define ICC_initLockAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (2 * ICC_HANDLE_SIZE))) + +#define ICC_getHandleComplete ((*((uint8_t *) ICC_initLockAddr)) +#define ICC_setHandleComplete ((*((uint8_t *) ICC_initLockAddr) = 1) + +/* These memory spaces are used to transfer callback function pointers from CPU1 to CPU0 for initialization */ +#define ICC_CPU1to0SendCallbackAddr (ICC_initLockAddr + ICC_LOCK_SIZE + (0 * ICC_FUNC_PTR_SIZE)) +#define ICC_CPU0to1ReceiveCallbackAddr (ICC_initLockAddr + ICC_LOCK_SIZE + (1 * ICC_FUNC_PTR_SIZE)) + +#define ICC_getCPU1to0SendCallback ((*((void **) ICC_CPU1to0SendCallbackAddr)) +#define ICC_setCPU1to0SendCallback(func_ptr) ((*((void **) ICC_CPU1to0SendCallbackAddr) = func_ptr) +#define ICC_getCPU0to1ReceiveCallback ((*((void **) ICC_CPU0to1ReceiveCallbackAddr)) +#define ICC_setCPU0to1ReceiveCallback(func_ptr) ((*((void **) ICC_CPU0to1ReceiveCallbackAddr) = func_ptr) + +/* We need a concurrency lock in the shared memory to make sure that CPU1 always provides the function pointers before + * CPU0 attempts to get them. This is initialized to 0, and CPU1 sets it to 1. CPU0 will wait till it sees + * this change before attempting to get the function pointers. */ +#define ICC_functionPointersLockAddr (ICC_initLockAddr + ICC_LOCK_SIZE + (2 * ICC_FUNC_PTR_SIZE)) + +#define ICC_getFunctionPointersReady ((*((uint8_t *) ICC_functionPointersLockAddr)) +#define ICC_setFunctionPointersReady ((*((uint8_t *) ICC_functionPointersLockAddr) = 1) /* These are the handles for the Message Buffers that need to be used by other tasks * In reality, the handle is just the pointer to the message buffer struct (its memory address) * These should end up being the addresses computed above */ -MessageBufferHandle_t xCPU0to1MessageBuffer; -MessageBufferHandle_t xCPU1to0MessageBuffer; - +MessageBufferHandle_t xCPU0to1MessageBufferHandle; +MessageBufferHandle_t xCPU1to0MessageBufferHandle; void icc_init(); +#if XPAR_CPU_ID == 0 void vCPU0to1SendCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken); -void vCPU0to1ReceiveCallback(MessageBufferHandle_t xMessageBuffer, +void vCPU1to0ReceiveCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken); +#elif XPAR_CPU_ID == 1 void vCPU1to0SendCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken); -void vCPU1to0ReceiveCallback(MessageBufferHandle_t xMessageBuffer, +void vCPU0to1ReceiveCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken); +#endif /* Callback declarations */ #endif /* ICC_H */ diff --git a/sdk/shared/sys/intr.c b/sdk/shared/sys/intr.c index 253dcbbc..afd5d602 100644 --- a/sdk/shared/sys/intr.c +++ b/sdk/shared/sys/intr.c @@ -81,7 +81,7 @@ void CPU0WakeTxHandler() xil_printf("CPU 0 - WakeTxHandler reached\r\n"); BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xMessageBufferReceiveCompletedFromISR(xCPU0to1MessageBuffer, &xHigherPriorityTaskWoken); + xMessageBufferReceiveCompletedFromISR(xCPU0to1MessageBufferHandle, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } @@ -90,7 +90,7 @@ void CPU0WakeRxHandler() xil_printf("CPU 0 - WakeRxHandler reached\r\n"); BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xMessageBufferSendCompletedFromISR(xCPU1to0MessageBuffer, &xHigherPriorityTaskWoken); + xMessageBufferSendCompletedFromISR(xCPU1to0MessageBufferHandle, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } #elif XPAR_CPU_ID == 1 @@ -99,7 +99,7 @@ void CPU1WakeTxHandler() xil_printf("CPU 1 - WakeTxHandler reached\r\n"); BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xMessageBufferReceiveCompletedFromISR(xCPU1to0MessageBuffer, &xHigherPriorityTaskWoken); + xMessageBufferReceiveCompletedFromISR(xCPU1to0MessageBufferHandle, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } @@ -108,7 +108,7 @@ void CPU1WakeRxHandler() xil_printf("CPU 1 - WakeRxHandler reached\r\n"); BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xMessageBufferSendCompletedFromISR(xCPU0to1MessageBuffer, &xHigherPriorityTaskWoken); + xMessageBufferSendCompletedFromISR(xCPU0to1MessageBufferHandle, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } #endif From d3876c8a423e232e477e2f59a84d6958186dab9b Mon Sep 17 00:00:00 2001 From: Patrick Nowakowski Date: Fri, 1 Mar 2024 19:53:30 -0600 Subject: [PATCH 2/6] Move shared memory definitions to specific file, implement GIC initialization --- sdk/shared/sys/icc.c | 2 +- sdk/shared/sys/icc.h | 65 +--------------- sdk/shared/sys/intr.c | 136 +++++++++++++++++++-------------- sdk/shared/sys/intr.h | 9 +-- sdk/shared/sys/shared_memory.h | 99 ++++++++++++++++++++++++ 5 files changed, 183 insertions(+), 128 deletions(-) create mode 100644 sdk/shared/sys/shared_memory.h diff --git a/sdk/shared/sys/icc.c b/sdk/shared/sys/icc.c index 8f092647..a0129d2d 100644 --- a/sdk/shared/sys/icc.c +++ b/sdk/shared/sys/icc.c @@ -11,7 +11,7 @@ void icc_init() { #if XPAR_CPU_ID == 0 - // ONLY CPU 0 INITIALIZES THE MESSAGE BUFFERS + // CPU0 HANDLES INITIALIZING THE MESSAGE BUFFERS // Wait for CPU1 to provide the function pointers to its callbacks () while (!ICC_getFunctionPointersReady) diff --git a/sdk/shared/sys/icc.h b/sdk/shared/sys/icc.h index 2fecadc7..38944597 100644 --- a/sdk/shared/sys/icc.h +++ b/sdk/shared/sys/icc.h @@ -2,7 +2,7 @@ #define ICC_H #include "FreeRTOS.h" -#include "intr.h" +#include "shared_memory.h" #include "message_buffer.h" #include "xil_printf.h" #include @@ -32,69 +32,6 @@ // https://www.freertos.org/RTOS-message-buffer-API.html // https://www.freertos.org/2020/02/simple-multicore-core-to-core-communication-using-freertos-message-buffers.html -// Per Zynq-7000 TRM Ch. 4: System Addresses (page 106), the initial mapping -// of OCM is split between low addresses and high addresses in 64 KB chunks. -// -// We will pick to use the highest 64 KB chunk as our base address: -#define OCM_BASE_ADDR (0xFFFF0000) -#define ICC_BUFFER_STRUCT_SIZE (sizeof(StaticMessageBuffer_t)) -#define ICC_BUFFER_SIZE (4 * 1024) -#define ICC_HANDLE_SIZE (sizeof(MessageBufferHandle_t)) -#define ICC_LOCK_SIZE (sizeof(uint8_t)) -#define ICC_FUNC_PTR_SIZE (sizeof(void *)) - -/* Define the pointers to the two structs (that store the metadata) and two message spaces (that hold the messages) in - * shared memory. The ICC_BUFFER_SIZE Should be one more than the value passed in the xBufferSizeBytes parameter. The - * two structs will be located back-to-back right at the base addr of the shared OCM, followed thereafter by the actual - * message buffers. */ -#define ICC_CPU0to1BufferStructAddr ((uint8_t *) (OCM_BASE_ADDR + (0 * ICC_BUFFER_STRUCT_SIZE))) -#define ICC_CPU1to0BufferStructAddr ((uint8_t *) (OCM_BASE_ADDR + (1 * ICC_BUFFER_STRUCT_SIZE))) - -#define ICC_CPU0to1BufferSpaceAddr ((uint8_t *) (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (0 * ICC_BUFFER_SIZE))) -#define ICC_CPU1to0BufferSpaceAddr ((uint8_t *) (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (1 * ICC_BUFFER_SIZE))) - -/* These memory spaces are used to transfer the Message Buffer Handles from CPU0 (who does the initialization work, and - * gets the handles from the xMessageBufferCreateStaticWithCallback function) to CPU1 (who doesn't initialize anything - * and gets the handles from CPU0, via these drop-zones) */ -#define ICC_CPU0to1HandleDropzoneAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (0 * ICC_HANDLE_SIZE))) -#define ICC_CPU1to0HandleDropzoneAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (1 * ICC_HANDLE_SIZE))) - -#define ICC_getCPU0to1Handle ((*((MessageBufferHandle_t *) ICC_CPU0to1HandleDropzoneAddr)) -#define ICC_setCPU0to1Handle(handle) ((*((MessageBufferHandle_t *) ICC_CPU0to1HandleDropzoneAddr) = handle) -#define ICC_getCPU1to0Handle ((*((MessageBufferHandle_t *) ICC_CPU1to0HandleDropzoneAddr)) -#define ICC_setCPU1to0Handle(handle) ((*((MessageBufferHandle_t *) ICC_CPU1to0HandleDropzoneAddr) = handle) - -/* We need a concurrency lock in the shared memory to make sure that CPU0 always sets the handles before - * CPU1 attempts to get them. This is initialized to 0, and CPU0 sets it to 1. CPU1 will wait till it sees - * this change before attempting to get the handles. */ -#define ICC_initLockAddr (OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (2 * ICC_HANDLE_SIZE))) - -#define ICC_getHandleComplete ((*((uint8_t *) ICC_initLockAddr)) -#define ICC_setHandleComplete ((*((uint8_t *) ICC_initLockAddr) = 1) - -/* These memory spaces are used to transfer callback function pointers from CPU1 to CPU0 for initialization */ -#define ICC_CPU1to0SendCallbackAddr (ICC_initLockAddr + ICC_LOCK_SIZE + (0 * ICC_FUNC_PTR_SIZE)) -#define ICC_CPU0to1ReceiveCallbackAddr (ICC_initLockAddr + ICC_LOCK_SIZE + (1 * ICC_FUNC_PTR_SIZE)) - -#define ICC_getCPU1to0SendCallback ((*((void **) ICC_CPU1to0SendCallbackAddr)) -#define ICC_setCPU1to0SendCallback(func_ptr) ((*((void **) ICC_CPU1to0SendCallbackAddr) = func_ptr) -#define ICC_getCPU0to1ReceiveCallback ((*((void **) ICC_CPU0to1ReceiveCallbackAddr)) -#define ICC_setCPU0to1ReceiveCallback(func_ptr) ((*((void **) ICC_CPU0to1ReceiveCallbackAddr) = func_ptr) - -/* We need a concurrency lock in the shared memory to make sure that CPU1 always provides the function pointers before - * CPU0 attempts to get them. This is initialized to 0, and CPU1 sets it to 1. CPU0 will wait till it sees - * this change before attempting to get the function pointers. */ -#define ICC_functionPointersLockAddr (ICC_initLockAddr + ICC_LOCK_SIZE + (2 * ICC_FUNC_PTR_SIZE)) - -#define ICC_getFunctionPointersReady ((*((uint8_t *) ICC_functionPointersLockAddr)) -#define ICC_setFunctionPointersReady ((*((uint8_t *) ICC_functionPointersLockAddr) = 1) - -/* These are the handles for the Message Buffers that need to be used by other tasks - * In reality, the handle is just the pointer to the message buffer struct (its memory address) - * These should end up being the addresses computed above */ -MessageBufferHandle_t xCPU0to1MessageBufferHandle; -MessageBufferHandle_t xCPU1to0MessageBufferHandle; - void icc_init(); #if XPAR_CPU_ID == 0 void vCPU0to1SendCallback(MessageBufferHandle_t xMessageBuffer, diff --git a/sdk/shared/sys/intr.c b/sdk/shared/sys/intr.c index afd5d602..fa4653eb 100644 --- a/sdk/shared/sys/intr.c +++ b/sdk/shared/sys/intr.c @@ -8,68 +8,92 @@ // CPUs, use "#if XPAR_CPU_ID == ?" /////////////////////////////////////////////////////// +/// GENERAL INFO /* The functions in this file are responsible for setting up the * Xilinx Generic Interrupt Controller (GIC). * * Interrupts are needed for Inter-Core Communication, specifically - * the ability to trigger an interrupt in the receiving CPU after a - * message is placed into an empty ICC Message Buffer, + * the ability to trigger an interrupt in the receiving CPU after a + * message is placed into an empty ICC Message Buffer, * OR - * the ability to trigger an interrupt in the sending CPU after a - * message is removed from a full ICC Message Buffer + * the ability to trigger an interrupt in the sending CPU after a + * message is removed from a full ICC Message Buffer * * See sys/icc.c for more info. + * +// RELEVENT TRM SECTIONS + * Read Chapter 7: Interrupts in the Zynq-7000 TRM + * It starts on page 231 of the PDF + * Appendix A contains all the memory-mapped register details + * Relevant subsection is the "Application Processing Unit (mpcore)" section + * that starts on page 1483. + * Registers starting with ICD are the ones we care about + * These are the "distributor" registers starting with ICDDCR at absolute address 0xF8F01000 + * +// USEFUL XILINX-PROVIDED FILES TO READ + * - xparameters.h : Search for "SCUGIC" related definitions + * - XPAR_PS7_SCUGIC_0_DEVICE_ID 0U + * - XPAR_PS7_SCUGIC_0_BASEADDR 0xF8F00100U + * - XPAR_PS7_SCUGIC_0_HIGHADDR 0xF8F001FFU + * - XPAR_PS7_SCUGIC_0_DIST_BASEADDR 0xF8F01000U + * - xscugic_sinit.c : Contains the necessary LookupConfig() function + * - xscugic.c : Contains most of the useful GIC functions + * - XScuGic_CfgInitialize() + * Uses the ConfigPtr* from lookup to initialize a GIC Instance struct + * - XScuGic_DistWriteReg() + * Write a GIC register + * - XScuGic_DistReadReg() + * Read a GIC register + * - XScuGic_Connect() + * - XScuGic_Disconnect() + * - XScuGic_Enable() + * - XScuGic_Disable() + * - XScuGic_SoftwareIntr() + * - XScuGic_GetPriorityTriggerType() + * - XScuGic_SetPriorityTriggerType() + * - XScuGic_InterruptMaptoCpu() + * - XScuGic_InterruptUnmapFromCpu() + * - XScuGic_UnmapAllInterruptsFromCpu() + * - XScuGic_Stop() + * - XScuGic_SetCpuID() + * - XScuGic_GetCpuID() */ int intr_init() { - int Status = XST_FAILURE; +#if XPAR_CPU_ID == 0 + // CPU0 HANDLES INITIALIZING EVERYTHING INTERRUPT-RELATED - XScuGic_Config *IntcConfig; + // Initialize the GIC Here + xil_printf("GIC: Initializing...\n"); + XScuGic_Config * gic_config_ptr = XScuGic_LookupConfig(INTR_GIC_DEVICE_ID); + s32 gic_init_status = XScuGic_CfgInitialize(&INTR_GIC_INSTANCE, gic_config_ptr, gic_config_ptr->CpuBaseAddress); - IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); - XScuGic_CfgInitialize(&InterruptController, IntcConfig, IntcConfig->CpuBaseAddress); + if (gic_init_status != XST_SUCCESS) { + xil_printf("GIC: Initialization Failed\n"); + while(1); + } + xil_printf("GIC: Initialization Success\n"); - /* - * Perform a self-test to ensure that the hardware was built - * correctly - */ - Status = XScuGic_SelfTest(&InterruptController); - if (Status != XST_SUCCESS) { - return XST_FAILURE; - } - // Initialize the interrupt controller - Xil_ExceptionRegisterHandler( - XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, &InterruptController); - Xil_ExceptionEnable(); -#if XPAR_CPU_ID == 0 + + // // Initialize the interrupt controller + // Xil_ExceptionRegisterHandler( + // XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, &InterruptController); + // Xil_ExceptionEnable(); + + // Connect the given interrupt with its handler - XScuGic_Connect(&InterruptController, INTC_1TO0_SEND_INTERRUPT_ID, (Xil_ExceptionHandler) CPU0WakeRxHandler, NULL); - XScuGic_Connect(&InterruptController, INTC_0TO1_RCVE_INTERRUPT_ID, (Xil_ExceptionHandler) CPU0WakeTxHandler, NULL); + // XScuGic_Connect(&InterruptController, INTC_1TO0_SEND_INTERRUPT_ID, (Xil_ExceptionHandler) CPU0WakeRxHandler, NULL); + // XScuGic_Connect(&InterruptController, INTC_0TO1_RCVE_INTERRUPT_ID, (Xil_ExceptionHandler) CPU0WakeTxHandler, NULL); #elif XPAR_CPU_ID == 1 // Connect the given interrupt with its handler - XScuGic_Connect(&InterruptController, INTC_0TO1_SEND_INTERRUPT_ID, (Xil_ExceptionHandler) CPU1WakeRxHandler, NULL); - XScuGic_Connect(&InterruptController, INTC_1TO0_RCVE_INTERRUPT_ID, (Xil_ExceptionHandler) CPU1WakeTxHandler, NULL); + // XScuGic_Connect(&InterruptController, INTC_0TO1_SEND_INTERRUPT_ID, (Xil_ExceptionHandler) CPU1WakeRxHandler, NULL); + // XScuGic_Connect(&InterruptController, INTC_1TO0_RCVE_INTERRUPT_ID, (Xil_ExceptionHandler) CPU1WakeTxHandler, NULL); #endif - /* - // Enable the interrupt for the second CPU core - XScuGic_SetPriorityTriggerType(&InterruptController, INTC_INTERRUPT_ID, 0xA0, 3); // Set priority and trigger type - XScuGic_Enable(&InterruptController, INTC_INTERRUPT_ID); - - // Enable the interrupt for CPU1 - Xil_Out32(XPAR_PS7_SCUGIC_DIST_BASEADDR + XSCUGIC_CPU_PRIOR_OFFSET + (CPU1_ID * 4), 0xFF); - Xil_Out32(XPAR_PS7_SCUGIC_DIST_BASEADDR + XSCUGIC_CPU_TARGET_OFFSET + (CPU1_ID * 4), 0x1); - - // Enable interrupts globally - Xil_ExceptionEnableMask(XIL_EXCEPTION_NON_CRITICAL); - - print("Interrupt system setup complete.\r\n"); - */ - return XST_SUCCESS; } @@ -78,37 +102,37 @@ int intr_init() #if XPAR_CPU_ID == 0 void CPU0WakeTxHandler() { - xil_printf("CPU 0 - WakeTxHandler reached\r\n"); + // xil_printf("CPU 0 - WakeTxHandler reached\r\n"); - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xMessageBufferReceiveCompletedFromISR(xCPU0to1MessageBufferHandle, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + // BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // xMessageBufferReceiveCompletedFromISR(xCPU0to1MessageBufferHandle, &xHigherPriorityTaskWoken); + // portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } void CPU0WakeRxHandler() { - xil_printf("CPU 0 - WakeRxHandler reached\r\n"); + // xil_printf("CPU 0 - WakeRxHandler reached\r\n"); - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xMessageBufferSendCompletedFromISR(xCPU1to0MessageBufferHandle, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + // BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // xMessageBufferSendCompletedFromISR(xCPU1to0MessageBufferHandle, &xHigherPriorityTaskWoken); + // portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } #elif XPAR_CPU_ID == 1 void CPU1WakeTxHandler() { - xil_printf("CPU 1 - WakeTxHandler reached\r\n"); + // xil_printf("CPU 1 - WakeTxHandler reached\r\n"); - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xMessageBufferReceiveCompletedFromISR(xCPU1to0MessageBufferHandle, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + // BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // xMessageBufferReceiveCompletedFromISR(xCPU1to0MessageBufferHandle, &xHigherPriorityTaskWoken); + // portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } void CPU1WakeRxHandler() { - xil_printf("CPU 1 - WakeRxHandler reached\r\n"); + // xil_printf("CPU 1 - WakeRxHandler reached\r\n"); - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xMessageBufferSendCompletedFromISR(xCPU0to1MessageBufferHandle, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + // BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // xMessageBufferSendCompletedFromISR(xCPU0to1MessageBufferHandle, &xHigherPriorityTaskWoken); + // portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } #endif diff --git a/sdk/shared/sys/intr.h b/sdk/shared/sys/intr.h index 137771a4..8dadd71c 100644 --- a/sdk/shared/sys/intr.h +++ b/sdk/shared/sys/intr.h @@ -2,7 +2,7 @@ #define INTR_H #include "FreeRTOS.h" -#include "icc.h" +#include "shared_memory.h" #include "xil_exception.h" #include "xil_printf.h" #include "xparameters.h" @@ -12,8 +12,6 @@ #include #include -// test - /////////////////////////////////////////////////////// // THIS IS A SHARED FILE, SO IT IS ALWAYS // IN SYNC IN BOTH CPU0 AND CPU1 @@ -25,16 +23,13 @@ #define CPU0_ID (XSCUGIC_SPI_CPU0_MASK << 0) #define CPU1_ID (XSCUGIC_SPI_CPU0_MASK << 1) -#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#define INTR_GIC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID // good #define INTC_0TO1_SEND_INTERRUPT_ID 0U #define INTC_1TO0_RCVE_INTERRUPT_ID 1U #define INTC_1TO0_SEND_INTERRUPT_ID 2U #define INTC_0TO1_RCVE_INTERRUPT_ID 3U -// Interrupt Controller Instance -// Defined here to be accessable in sys/icc.c -static XScuGic InterruptController; int intr_init(); diff --git a/sdk/shared/sys/shared_memory.h b/sdk/shared/sys/shared_memory.h new file mode 100644 index 00000000..69773be8 --- /dev/null +++ b/sdk/shared/sys/shared_memory.h @@ -0,0 +1,99 @@ +#ifndef SHARED_MEMORY_H +#define SHARED_MEMORY_H + +#include "xparameters.h" +#include "xscugic.h" +#include "xil_printf.h" + +/////////////////////////////////////////////////////// +// THIS IS A SHARED FILE, SO IT IS ALWAYS +// IN SYNC IN BOTH CPU0 AND CPU1 +// +// If you need to differentiate something between +// CPUs, use "#if XPAR_CPU_ID == ?" +/////////////////////////////////////////////////////// + +/* This file contains all the macro definitions that need to be shared between CPU0 and CPU1 + * This includes definitions for Inter-Core Communication, Inter-Core Interrupts, + * the Generic Interrupt Controller (GIC) definitions and metadata, etc + * + * Per Zynq-7000 TRM Ch. 4: System Addresses (page 106), the initial mapping + * of OCM is split between low addresses and high addresses in 64 KB chunks. + * We will pick to use the highest 64 KB chunk as our base address: */ +#define SHARED_OCM_BASE_ADDR (0xFFFF0000) + +/////////////////////////////////// +// INTER-CORE COMMUNICATION +///////////////////////////////// +#define ICC_BUFFER_STRUCT_SIZE (sizeof(StaticMessageBuffer_t)) +#define ICC_BUFFER_SIZE (4 * 1024) +#define ICC_HANDLE_SIZE (sizeof(MessageBufferHandle_t)) +#define ICC_LOCK_SIZE (sizeof(uint8_t)) +#define ICC_FUNC_PTR_SIZE (sizeof(void *)) + +/* Define the pointers to the two structs (that store the metadata) and two message spaces (that hold the messages) in + * shared memory. The ICC_BUFFER_SIZE Should be one more than the value passed in the xBufferSizeBytes parameter. The + * two structs will be located back-to-back right at the base addr of the shared OCM, followed thereafter by the actual + * message buffers. */ +#define ICC_CPU0to1BufferStructAddr ((uint8_t *) (SHARED_OCM_BASE_ADDR + (0 * ICC_BUFFER_STRUCT_SIZE))) +#define ICC_CPU1to0BufferStructAddr ((uint8_t *) (SHARED_OCM_BASE_ADDR + (1 * ICC_BUFFER_STRUCT_SIZE))) + +#define ICC_CPU0to1BufferSpaceAddr ((uint8_t *) (SHARED_OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (0 * ICC_BUFFER_SIZE))) +#define ICC_CPU1to0BufferSpaceAddr ((uint8_t *) (SHARED_OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (1 * ICC_BUFFER_SIZE))) + +/* These are the handles for the Message Buffers that need to be used by other tasks + * In reality, the handle is just the pointer to the message buffer struct (its memory address) + * These should end up being the addresses computed above */ +MessageBufferHandle_t xCPU0to1MessageBufferHandle; +MessageBufferHandle_t xCPU1to0MessageBufferHandle; + +/* These memory spaces are used to transfer the Message Buffer Handles from CPU0 (who does the initialization work, and + * gets the handles from the xMessageBufferCreateStaticWithCallback function) to CPU1 (who doesn't initialize anything + * and gets the handles from CPU0, via these drop-zones) */ +#define ICC_CPU0to1HandleDropzoneAddr (SHARED_OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (0 * ICC_HANDLE_SIZE))) +#define ICC_CPU1to0HandleDropzoneAddr (SHARED_OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (1 * ICC_HANDLE_SIZE))) + +#define ICC_getCPU0to1Handle ((*((MessageBufferHandle_t *) ICC_CPU0to1HandleDropzoneAddr)) +#define ICC_setCPU0to1Handle(handle) ((*((MessageBufferHandle_t *) ICC_CPU0to1HandleDropzoneAddr) = handle) +#define ICC_getCPU1to0Handle ((*((MessageBufferHandle_t *) ICC_CPU1to0HandleDropzoneAddr)) +#define ICC_setCPU1to0Handle(handle) ((*((MessageBufferHandle_t *) ICC_CPU1to0HandleDropzoneAddr) = handle) + +/* We need a concurrency lock in the shared memory to make sure that CPU0 always sets the handles before + * CPU1 attempts to get them. This is initialized to 0, and CPU0 sets it to 1. CPU1 will wait till it sees + * this change before attempting to get the handles. */ +#define ICC_initLockAddr (SHARED_OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (2 * ICC_BUFFER_SIZE) + (2 * ICC_HANDLE_SIZE))) + +#define ICC_getHandleComplete ((*((uint8_t *) ICC_initLockAddr)) +#define ICC_setHandleComplete ((*((uint8_t *) ICC_initLockAddr) = 1) + +/* These memory spaces are used to transfer callback function pointers from CPU1 to CPU0 for initialization */ +#define ICC_CPU1to0SendCallbackAddr (ICC_initLockAddr + ICC_LOCK_SIZE + (0 * ICC_FUNC_PTR_SIZE)) +#define ICC_CPU0to1ReceiveCallbackAddr (ICC_initLockAddr + ICC_LOCK_SIZE + (1 * ICC_FUNC_PTR_SIZE)) + +#define ICC_getCPU1to0SendCallback ((*((void **) ICC_CPU1to0SendCallbackAddr)) +#define ICC_setCPU1to0SendCallback(func_ptr) ((*((void **) ICC_CPU1to0SendCallbackAddr) = func_ptr) +#define ICC_getCPU0to1ReceiveCallback ((*((void **) ICC_CPU0to1ReceiveCallbackAddr)) +#define ICC_setCPU0to1ReceiveCallback(func_ptr) ((*((void **) ICC_CPU0to1ReceiveCallbackAddr) = func_ptr) + +/* We need a concurrency lock in the shared memory to make sure that CPU1 always provides the function pointers before + * CPU0 attempts to get them. This is initialized to 0, and CPU1 sets it to 1. CPU0 will wait till it sees + * this change before attempting to get the function pointers. */ +#define ICC_functionPointersLockAddr (ICC_initLockAddr + ICC_LOCK_SIZE + (2 * ICC_FUNC_PTR_SIZE)) + +#define ICC_getFunctionPointersReady ((*((uint8_t *) ICC_functionPointersLockAddr)) +#define ICC_setFunctionPointersReady ((*((uint8_t *) ICC_functionPointersLockAddr) = 1) + + +/////////////////////////////////// +// INTERRUPTS / GIC +///////////////////////////////// +#define INTR_SHARED_MEMORY_BASE_ADDR (ICC_functionPointersLockAddr + sizeof(uint8_t)) +#define INTR_GIC_INSTANCE_SIZE (sizeof(XScuGic)) + +// Interrupt Controller Instance +// Defined here to be accessable in both sys/icc.c and sys/intr.h +#define INTR_GenericInterruptControllerInstanceAddr (INTR_SHARED_MEMORY_BASE_ADDR) +#define INTR_GIC_INSTANCE (*((XScuGic *)INTR_GenericInterruptControllerInstanceAddr)) + + +#endif /* SHARED_MEMORY_H */ \ No newline at end of file From 09a28893cb701602aaa07586de0bce9639f15b5c Mon Sep 17 00:00:00 2001 From: Patrick Nowakowski Date: Mon, 18 Mar 2024 21:36:47 -0500 Subject: [PATCH 3/6] Update shared ICC and Intr files, SGIs from CPU1 can wake blocked tasks in CPU0 --- sdk/shared/sys/icc.c | 54 +++++++++---------- sdk/shared/sys/intr.c | 94 +++++++++++++++++++++------------- sdk/shared/sys/intr.h | 20 ++------ sdk/shared/sys/shared_memory.h | 33 ++++++++---- 4 files changed, 111 insertions(+), 90 deletions(-) diff --git a/sdk/shared/sys/icc.c b/sdk/shared/sys/icc.c index a0129d2d..dbdfdb00 100644 --- a/sdk/shared/sys/icc.c +++ b/sdk/shared/sys/icc.c @@ -19,9 +19,9 @@ void icc_init() // Use the getters once ready void (*vCPU0to1ReceiveCallback)() = ICC_getCPU0to1ReceiveCallback; - xil_printf("DEBUG: CPU 0 got 0to1 Receive Callback %p\r\n", (void *) vCPU0to1ReceiveCallback); + //xil_printf("DEBUG: CPU 0 got 0to1 Receive Callback %p\r\n", (void *) vCPU0to1ReceiveCallback); void (*vCPU1to0SendCallback)() = ICC_getCPU1to0SendCallback; - xil_printf("DEBUG: CPU 0 got 1to0 Send Callback %p\r\n", (void *) vCPU1to0SendCallback); + //xil_printf("DEBUG: CPU 0 got 1to0 Send Callback %p\r\n", (void *) vCPU1to0SendCallback); /* Create two message buffers for inter-core communication that use the callback * functions below as send and receive completed callback functions. */ @@ -40,11 +40,9 @@ void icc_init() vCPU1to0ReceiveCallback); // Called by CPU0 after removing message from 1to0 buffer ICC_setCPU0to1Handle(xCPU0to1MessageBufferHandle); - xil_printf("DEBUG: CPU 0 set 0to1 Handle %p\r\n", (void *) xCPU0to1MessageBufferHandle); - // void * test = ICC_getCPU0to1Handle; - // xil_printf("DEBUG: CPU 0 got 0to1 Handle %p\r\n",(void *)test); + //xil_printf("DEBUG: CPU 0 set 0to1 Handle %p\r\n", (void *) xCPU0to1MessageBufferHandle); ICC_setCPU1to0Handle(xCPU1to0MessageBufferHandle); - xil_printf("DEBUG: CPU 0 set 1to0 Handle %p\r\n", (void *) xCPU1to0MessageBufferHandle); + //xil_printf("DEBUG: CPU 0 set 1to0 Handle %p\r\n", (void *) xCPU1to0MessageBufferHandle); ICC_setHandleComplete; #elif XPAR_CPU_ID == 1 @@ -55,9 +53,9 @@ void icc_init() // Make CPU1's callback function pointers available to CPU0 ICC_setCPU1to0SendCallback(&vCPU1to0SendCallback); - xil_printf("DEBUG: CPU 1 set 1to0 Send Callback %p\r\n", &vCPU1to0SendCallback); + //xil_printf("DEBUG: CPU 1 set 1to0 Send Callback %p\r\n", &vCPU1to0SendCallback); ICC_setCPU0to1ReceiveCallback(&vCPU0to1ReceiveCallback); - xil_printf("DEBUG: CPU 1 set 0to1 Receive Callback %p\r\n", &vCPU0to1ReceiveCallback); + //xil_printf("DEBUG: CPU 1 set 0to1 Receive Callback %p\r\n", &vCPU0to1ReceiveCallback); ICC_setFunctionPointersReady; @@ -66,9 +64,9 @@ void icc_init() ; xCPU0to1MessageBufferHandle = ICC_getCPU0to1Handle; - xil_printf("DEBUG: CPU 1 got 0to1 Handle %p\r\n", (void *) xCPU0to1MessageBufferHandle); + //xil_printf("DEBUG: CPU 1 got 0to1 Handle %p\r\n", (void *) xCPU0to1MessageBufferHandle); xCPU1to0MessageBufferHandle = ICC_getCPU1to0Handle; - xil_printf("DEBUG: CPU 1 got 1to0 Handle %p\r\n", (void *) xCPU1to0MessageBufferHandle); + //xil_printf("DEBUG: CPU 1 got 1to0 Handle %p\r\n", (void *) xCPU1to0MessageBufferHandle); #endif } @@ -95,21 +93,22 @@ void vCPU0to1SendCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken) { - xil_printf("DEBUG: CPU 0 to 1 Send Callback reached (in CPU0)\r\n"); - // In CPU 0, this callback should send an interrupt to CPU 1 to unblock its Rx task + //xil_printf("DEBUG: CPU 0 to 1 Send Callback reached (in CPU0)\r\n"); + xil_printf("K\r\n"); - // XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_SEND_INTERRUPT_ID, CPU1_ID); + // CPU 0 should send an interrupt to CPU1 to unblock its Rx task + int status = XScuGic_SoftwareIntr(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_RX_INT_ID, XSCUGIC_SPI_CPU1_MASK); } void vCPU1to0ReceiveCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken) { - xil_printf("DEBUG: CPU 1 to 0 Receive Callback reached (in CPU0)\r\n"); - // In CPU 0, this callback should send an interrupt to CPU 1 to unblock its Tx task - // (since the buffer might have an open space now) - - // XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_RCVE_INTERRUPT_ID, CPU1_ID); + //xil_printf("DEBUG: CPU 1 to 0 Receive Callback reached (in CPU0)\r\n"); + xil_printf("L\r\n"); + + // CPU0 should send an interrupt to CPU1 to unblock its Tx task (the buffer might have an open space now) + int status = XScuGic_SoftwareIntr(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_TX_INT_ID, XSCUGIC_SPI_CPU1_MASK); } #elif XPAR_CPU_ID == 1 @@ -118,21 +117,22 @@ void vCPU1to0SendCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken) { - xil_printf("DEBUG: CPU 1 to 0 Send Callback reached (in CPU1)\r\n"); - // In CPU 1, this callback should send an interrupt to CPU 0 to unblock its Rx task - - // XScuGic_SoftwareIntr(&InterruptController, INTC_1TO0_SEND_INTERRUPT_ID, CPU0_ID); + //xil_printf("DEBUG: CPU 1 to 0 Send Callback reached (in CPU1)\r\n"); + xil_printf("k\r\n"); + + // CPU 1 should send an interrupt to CPU0 to unblock its Rx task + int status = XScuGic_SoftwareIntr(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_RX_INT_ID, XSCUGIC_SPI_CPU0_MASK); } void vCPU0to1ReceiveCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken) { - xil_printf("DEBUG: CPU 0 to 1 Receive Callback reached (in CPU1)\r\n"); - // In CPU 1, this callback should send an interrupt to CPU 0 to unblock its Tx task - // (since the buffer might have an open space) - - // XScuGic_SoftwareIntr(&InterruptController, INTC_0TO1_RCVE_INTERRUPT_ID, CPU0_ID); + //xil_printf("DEBUG: CPU 0 to 1 Receive Callback reached (in CPU1)\r\n"); + xil_printf("l\r\n"); + + // CPU 1 should send an interrupt to CPU0 to unblock its Tx task (the buffer might have an open space) + int status = XScuGic_SoftwareIntr(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_TX_INT_ID, XSCUGIC_SPI_CPU0_MASK); } #endif diff --git a/sdk/shared/sys/intr.c b/sdk/shared/sys/intr.c index fa4653eb..dce7f24b 100644 --- a/sdk/shared/sys/intr.c +++ b/sdk/shared/sys/intr.c @@ -62,36 +62,56 @@ int intr_init() { #if XPAR_CPU_ID == 0 - // CPU0 HANDLES INITIALIZING EVERYTHING INTERRUPT-RELATED - - // Initialize the GIC Here - xil_printf("GIC: Initializing...\n"); + // CPU0 handles initialization of the Generic Interrrupt Controller + xil_printf("INTR: Initializing GIC...\n"); XScuGic_Config * gic_config_ptr = XScuGic_LookupConfig(INTR_GIC_DEVICE_ID); - s32 gic_init_status = XScuGic_CfgInitialize(&INTR_GIC_INSTANCE, gic_config_ptr, gic_config_ptr->CpuBaseAddress); + // gic_config_ptr provides the Xilinx base addresses of: + // - the GIC's distributor registers (the distributor is a shared resource that distributes interrupts to the CPUs) + // - the "CPU Interface" registers, each CPU has an interface that needs to be configured to interact with the GIC + s32 gic_init_status = XScuGic_CfgInitialize(INTR_GIC_INSTANCE_ADDR, gic_config_ptr, gic_config_ptr->CpuBaseAddress); if (gic_init_status != XST_SUCCESS) { - xil_printf("GIC: Initialization Failed\n"); - while(1); + xil_printf("INTR: GIC Initialization Failed\n"); + return XST_FAILURE; } - xil_printf("GIC: Initialization Success\n"); - - - - - // // Initialize the interrupt controller - // Xil_ExceptionRegisterHandler( - // XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, &InterruptController); - // Xil_ExceptionEnable(); - + xil_printf("INTR: GIC Initialization Success\n"); + INTR_setGicInitReady; +#elif XPAR_CPU_ID == 1 + // Wait for CPU0 to finish GIC initialization + while (!INTR_getGicInitReady) + ; + + // CPU1 still needs to configure its own CPU Interface, using these lines pulled from CPUInitialize() in xscugic.c + // CPU0 does this by calling CPUInitialize() within XScuGic_CfgInitialize() (xscugic.c, Line 481), but because of the GIC + // ready check on Line 439 of xscugic.c, if CPU1 calls XScuGic_CfgInitialize(), it will skip the call to CPUInitialize() + // if CPU0 has already marked the GIC as ready. + XScuGic_CPUWriteReg(INTR_GIC_INSTANCE_ADDR, XSCUGIC_CPU_PRIOR_OFFSET, 0xF0U); + XScuGic_CPUWriteReg(INTR_GIC_INSTANCE_ADDR, XSCUGIC_CONTROL_OFFSET, 0x07U); +#endif - // Connect the given interrupt with its handler - // XScuGic_Connect(&InterruptController, INTC_1TO0_SEND_INTERRUPT_ID, (Xil_ExceptionHandler) CPU0WakeRxHandler, NULL); - // XScuGic_Connect(&InterruptController, INTC_0TO1_RCVE_INTERRUPT_ID, (Xil_ExceptionHandler) CPU0WakeTxHandler, NULL); + // BOTH CORES: Connect the ARM processor's InterruptHandler logic to the initialized GIC + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, INTR_GIC_INSTANCE_ADDR); + Xil_ExceptionEnable(); +#if XPAR_CPU_ID == 0 + // Each CPU needs to connect its software interrupts to the appropriate handlers defined below, then enable + XScuGic_Connect(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_RX_INT_ID, + (Xil_ExceptionHandler)CPU0UnblockRxHandler, (void *)INTR_GIC_INSTANCE_ADDR); + XScuGic_Enable(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_RX_INT_ID); + + XScuGic_Connect(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_TX_INT_ID, + (Xil_ExceptionHandler)CPU0UnblockTxHandler, (void *)INTR_GIC_INSTANCE_ADDR); + XScuGic_Enable(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_TX_INT_ID); + #elif XPAR_CPU_ID == 1 - // Connect the given interrupt with its handler - // XScuGic_Connect(&InterruptController, INTC_0TO1_SEND_INTERRUPT_ID, (Xil_ExceptionHandler) CPU1WakeRxHandler, NULL); - // XScuGic_Connect(&InterruptController, INTC_1TO0_RCVE_INTERRUPT_ID, (Xil_ExceptionHandler) CPU1WakeTxHandler, NULL); + XScuGic_Connect(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_RX_INT_ID, + (Xil_ExceptionHandler)CPU1UnblockRxHandler, (void *)INTR_GIC_INSTANCE_ADDR); + XScuGic_Enable(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_RX_INT_ID); + + XScuGic_Connect(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_TX_INT_ID, + (Xil_ExceptionHandler)CPU1UnblockTxHandler, (void *)INTR_GIC_INSTANCE_ADDR); + XScuGic_Enable(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_TX_INT_ID); + #endif return XST_SUCCESS; @@ -100,39 +120,39 @@ int intr_init() /* We only need to define the handlers in the appropriate core */ #if XPAR_CPU_ID == 0 -void CPU0WakeTxHandler() +void CPU0UnblockRxHandler() { - // xil_printf("CPU 0 - WakeTxHandler reached\r\n"); + xil_printf("M\r\n"); - // BaseType_t xHigherPriorityTaskWoken = pdFALSE; - // xMessageBufferReceiveCompletedFromISR(xCPU0to1MessageBufferHandle, &xHigherPriorityTaskWoken); - // portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xMessageBufferSendCompletedFromISR(xCPU1to0MessageBufferHandle, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } -void CPU0WakeRxHandler() +void CPU0UnblockTxHandler() { - // xil_printf("CPU 0 - WakeRxHandler reached\r\n"); + xil_printf("N\r\n"); // BaseType_t xHigherPriorityTaskWoken = pdFALSE; - // xMessageBufferSendCompletedFromISR(xCPU1to0MessageBufferHandle, &xHigherPriorityTaskWoken); + // xMessageBufferReceiveCompletedFromISR(xCPU0to1MessageBufferHandle, &xHigherPriorityTaskWoken); // portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } #elif XPAR_CPU_ID == 1 -void CPU1WakeTxHandler() +void CPU1UnblockRxHandler() { - // xil_printf("CPU 1 - WakeTxHandler reached\r\n"); + xil_printf("m\r\n"); // BaseType_t xHigherPriorityTaskWoken = pdFALSE; - // xMessageBufferReceiveCompletedFromISR(xCPU1to0MessageBufferHandle, &xHigherPriorityTaskWoken); + // xMessageBufferSendCompletedFromISR(xCPU0to1MessageBufferHandle, &xHigherPriorityTaskWoken); // portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } -void CPU1WakeRxHandler() +void CPU1UnblockTxHandler() { - // xil_printf("CPU 1 - WakeRxHandler reached\r\n"); + xil_printf("n\r\n"); // BaseType_t xHigherPriorityTaskWoken = pdFALSE; - // xMessageBufferSendCompletedFromISR(xCPU0to1MessageBufferHandle, &xHigherPriorityTaskWoken); + // xMessageBufferReceiveCompletedFromISR(xCPU1to0MessageBufferHandle, &xHigherPriorityTaskWoken); // portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } #endif diff --git a/sdk/shared/sys/intr.h b/sdk/shared/sys/intr.h index 8dadd71c..59c9c4d6 100644 --- a/sdk/shared/sys/intr.h +++ b/sdk/shared/sys/intr.h @@ -20,27 +20,17 @@ // CPUs, use "#if XPAR_CPU_ID == ?" /////////////////////////////////////////////////////// -#define CPU0_ID (XSCUGIC_SPI_CPU0_MASK << 0) -#define CPU1_ID (XSCUGIC_SPI_CPU0_MASK << 1) - #define INTR_GIC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID // good -#define INTC_0TO1_SEND_INTERRUPT_ID 0U -#define INTC_1TO0_RCVE_INTERRUPT_ID 1U -#define INTC_1TO0_SEND_INTERRUPT_ID 2U -#define INTC_0TO1_RCVE_INTERRUPT_ID 3U - - int intr_init(); -/* We only need to define the handlers in the appropriate core - */ +// We only need to define the handlers in the appropriate core #if XPAR_CPU_ID == 0 -void CPU0WakeTxHandler(); -void CPU0WakeRxHandler(); +void CPU0UnblockRxHandler(); +void CPU0UnblockTxHandler(); #elif XPAR_CPU_ID == 1 -void CPU1WakeTxHandler(); -void CPU1WakeRxHandler(); +void CPU1UnblockRxHandler(); +void CPU1UnblockTxHandler(); #endif #endif /* INTR_H */ diff --git a/sdk/shared/sys/shared_memory.h b/sdk/shared/sys/shared_memory.h index 69773be8..cae87bdd 100644 --- a/sdk/shared/sys/shared_memory.h +++ b/sdk/shared/sys/shared_memory.h @@ -4,6 +4,7 @@ #include "xparameters.h" #include "xscugic.h" #include "xil_printf.h" +#include "message_buffer.h" /////////////////////////////////////////////////////// // THIS IS A SHARED FILE, SO IT IS ALWAYS @@ -31,6 +32,12 @@ #define ICC_LOCK_SIZE (sizeof(uint8_t)) #define ICC_FUNC_PTR_SIZE (sizeof(void *)) +/* These are the handles for the Message Buffers that need to be used by other tasks + * In reality, the handle is just the pointer to the message buffer struct (its memory address) + * These should end up being the addresses computed above */ +MessageBufferHandle_t xCPU0to1MessageBufferHandle; +MessageBufferHandle_t xCPU1to0MessageBufferHandle; + /* Define the pointers to the two structs (that store the metadata) and two message spaces (that hold the messages) in * shared memory. The ICC_BUFFER_SIZE Should be one more than the value passed in the xBufferSizeBytes parameter. The * two structs will be located back-to-back right at the base addr of the shared OCM, followed thereafter by the actual @@ -41,12 +48,6 @@ #define ICC_CPU0to1BufferSpaceAddr ((uint8_t *) (SHARED_OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (0 * ICC_BUFFER_SIZE))) #define ICC_CPU1to0BufferSpaceAddr ((uint8_t *) (SHARED_OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (1 * ICC_BUFFER_SIZE))) -/* These are the handles for the Message Buffers that need to be used by other tasks - * In reality, the handle is just the pointer to the message buffer struct (its memory address) - * These should end up being the addresses computed above */ -MessageBufferHandle_t xCPU0to1MessageBufferHandle; -MessageBufferHandle_t xCPU1to0MessageBufferHandle; - /* These memory spaces are used to transfer the Message Buffer Handles from CPU0 (who does the initialization work, and * gets the handles from the xMessageBufferCreateStaticWithCallback function) to CPU1 (who doesn't initialize anything * and gets the handles from CPU0, via these drop-zones) */ @@ -87,13 +88,23 @@ MessageBufferHandle_t xCPU1to0MessageBufferHandle; /////////////////////////////////// // INTERRUPTS / GIC ///////////////////////////////// -#define INTR_SHARED_MEMORY_BASE_ADDR (ICC_functionPointersLockAddr + sizeof(uint8_t)) +#define INTR_UNBLOCK_CPU0_RX_INT_ID 0 +#define INTR_UNBLOCK_CPU0_TX_INT_ID 1 +#define INTR_UNBLOCK_CPU1_RX_INT_ID 2 +#define INTR_UNBLOCK_CPU1_TX_INT_ID 3 + +#define INTR_SHARED_MEMORY_BASE_ADDR (0xFFFFF000)//(ICC_functionPointersLockAddr + sizeof(uint8_t)) #define INTR_GIC_INSTANCE_SIZE (sizeof(XScuGic)) // Interrupt Controller Instance -// Defined here to be accessable in both sys/icc.c and sys/intr.h -#define INTR_GenericInterruptControllerInstanceAddr (INTR_SHARED_MEMORY_BASE_ADDR) -#define INTR_GIC_INSTANCE (*((XScuGic *)INTR_GenericInterruptControllerInstanceAddr)) +// Defined here to be accessible in both sys/icc.c and sys/intr.h +#define INTR_GIC_INSTANCE_ADDR ((XScuGic *)INTR_SHARED_MEMORY_BASE_ADDR) +#define INTR_gicInstance (*((XScuGic *)INTR_GIC_INSTANCE_ADDR)) + +// Interrupt Controller Initializaton Lock w/ getter & setter +#define INTR_gicInitLockAddr (INTR_GIC_INSTANCE_ADDR + INTR_GIC_INSTANCE_SIZE) +#define INTR_getGicInitReady (*((uint8_t *) INTR_gicInitLockAddr)) +#define INTR_setGicInitReady (*((uint8_t *) INTR_gicInitLockAddr) = 1) -#endif /* SHARED_MEMORY_H */ \ No newline at end of file +#endif /* SHARED_MEMORY_H */ From b15ec790aea551882a6adbbe767d2f34a8975852 Mon Sep 17 00:00:00 2001 From: Patrick Nowakowski Date: Mon, 18 Mar 2024 21:37:33 -0500 Subject: [PATCH 4/6] Update print statements in main.c files to print single chars for interrupt debugging --- sdk/freertos_app_cpu0/src/main.c | 33 +++++++++++++++++++------------- sdk/freertos_app_cpu1/src/main.c | 33 ++++++++++++++++++++------------ 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/sdk/freertos_app_cpu0/src/main.c b/sdk/freertos_app_cpu0/src/main.c index bc6034d1..98b242ca 100644 --- a/sdk/freertos_app_cpu0/src/main.c +++ b/sdk/freertos_app_cpu0/src/main.c @@ -135,7 +135,6 @@ int main(void) __asm__("sev"); #endif - Xil_ExceptionInit(); intr_init(); icc_init(); vPortInstallFreeRTOSVectorTable(); @@ -148,8 +147,6 @@ int main(void) const TickType_t x10seconds = pdMS_TO_TICKS(DELAY_10_SECONDS); - xil_printf("CPU0 - Hello from FreeRTOS example main()!\r\n"); - /* Create the three tasks */ xTaskCreate(prvTxTask, /* The function that implements the task. */ (const char *) "CPU0_Tx", /* Text name for the task, provided to assist debugging only. */ @@ -233,15 +230,18 @@ static void prvTxTask(void *pvParameters) // HWstring, /* The address of the data being sent. */ // 0UL); /* The block time. */ - xil_printf("DEBUG: CPU0 about to attempt send\r\n"); + //xil_printf("DEBUG: CPU0 about to attempt send\r\n"); + xil_printf("A\r\n"); // Send a message to the other core size_t bytes_sent = xMessageBufferSend(xCPU0to1MessageBufferHandle, HWstring, sizeof(HWstring), 0UL); - xil_printf("DEBUG: CPU0 sent %d bytes to ICC buffer\r\n", bytes_sent); + //xil_printf("DEBUG: CPU0 sent %d bytes to ICC buffer\r\n", bytes_sent); + xil_printf("B\r\n"); if (bytes_sent == 0) { - xil_printf("ERROR: CPU0 failed to write to ICC buffer\r\n"); + //xil_printf("ERROR: CPU0 failed to write to ICC buffer\r\n"); + xil_printf("C\r\n"); } } } @@ -263,17 +263,21 @@ static void prvRxTask(void *pvParameters) // Rcvdstring, /* Data is read into this address. */ // portMAX_DELAY); /* Wait without a timeout for data. */ - xil_printf("DEBUG: CPU0 about to attempt rcv\r\n"); + //xil_printf("DEBUG: CPU0 about to attempt rcv\r\n"); + xil_printf("D\r\n"); size_t bytes_rcvd = xMessageBufferReceive(xCPU1to0MessageBufferHandle, Rcvdstring, 32, portMAX_DELAY); - xil_printf("DEBUG: CPU0 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd); + //xil_printf("DEBUG: CPU0 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd); + xil_printf("E\r\n"); if (bytes_rcvd == 0) { - xil_printf("CPU0 failed to receive from ICC buffer\r\n"); + //xil_printf("CPU0 failed to receive from ICC buffer\r\n"); + xil_printf("F\r\n"); } else { /* Print the received data. */ - xil_printf("CPU0 - Rx task received string from CPU1 Tx: %s\r\n", Rcvdstring); + //xil_printf("CPU0 - Rx task received string from CPU1 Tx: %s\r\n", Rcvdstring); + xil_printf("G\r\n"); RxtaskCntr++; } } @@ -341,7 +345,8 @@ static void vTimerCallback(TimerHandle_t pxTimer) lTimerId = (long) pvTimerGetTimerID(pxTimer); if (lTimerId != TIMER_ID) { - xil_printf("CPU0 - FreeRTOS Hello World Example FAILED"); + //xil_printf("CPU0 - FreeRTOS Hello World Example FAILED"); + xil_printf("H\r\n"); } /* If the RxtaskCntr is updated every time the Rx task is called. The @@ -351,10 +356,12 @@ static void vTimerCallback(TimerHandle_t pxTimer) have a value of 9 (TIMER_CHECK_THRESHOLD) when the timer expires. */ if (RxtaskCntr >= TIMER_CHECK_THRESHOLD) { message_status = 1; - xil_printf("CPU0 - FreeRTOS Hello World Example PASSED\r\n"); + //xil_printf("CPU0 - FreeRTOS Hello World Example PASSED\r\n"); + xil_printf("I\r\n"); } else { message_status = 2; - xil_printf("CPU0 - FreeRTOS Hello World Example FAILED\r\n"); + //xil_printf("CPU0 - FreeRTOS Hello World Example FAILED\r\n"); + xil_printf("J\r\n"); } } diff --git a/sdk/freertos_app_cpu1/src/main.c b/sdk/freertos_app_cpu1/src/main.c index 4e6a884b..0e819937 100644 --- a/sdk/freertos_app_cpu1/src/main.c +++ b/sdk/freertos_app_cpu1/src/main.c @@ -120,8 +120,6 @@ int main(void) const TickType_t x10seconds = pdMS_TO_TICKS(DELAY_10_SECONDS); - xil_printf("CPU1 - Hello from FreeRTOS example main()!\r\n"); - /* Create the two tasks. The Tx task is given a lower priority than the Rx task, so the Rx task will leave the Blocked state and pre-empt the Tx task as soon as the Tx task places an item in the queue. */ @@ -199,15 +197,19 @@ static void prvTxTask(void *pvParameters) // HWstring, /* The address of the data being sent. */ // 0UL); /* The block time. */ - xil_printf("DEBUG: CPU1 about to attempt send\r\n"); + //xil_printf("DEBUG: CPU1 about to attempt send\r\n"); + xil_printf("a\r\n"); + // Send a message to the other core size_t bytes_sent = xMessageBufferSend(xCPU1to0MessageBufferHandle, HWstring, sizeof(HWstring), 0UL); - xil_printf("DEBUG: CPU1 sent %d bytes to ICC buffer\r\n", bytes_sent); + //xil_printf("DEBUG: CPU1 sent %d bytes to ICC buffer\r\n", bytes_sent); + xil_printf("b\r\n"); if (bytes_sent == 0) { - xil_printf("ERROR: CPU1 failed to write to ICC buffer\r\n"); + //xil_printf("ERROR: CPU1 failed to write to ICC buffer\r\n"); + xil_printf("c\r\n"); } } } @@ -229,17 +231,21 @@ static void prvRxTask(void *pvParameters) // Rcvdstring, /* Data is read into this address. */ // portMAX_DELAY); /* Wait without a timeout for data. */ - xil_printf("DEBUG: CPU1 about to attempt rcv\r\n"); + //xil_printf("DEBUG: CPU1 about to attempt rcv\r\n"); + xil_printf("d\r\n"); size_t bytes_rcvd = xMessageBufferReceive(xCPU0to1MessageBufferHandle, Rcvdstring, 32, portMAX_DELAY); - xil_printf("DEBUG: CPU1 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd); + //xil_printf("DEBUG: CPU1 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd); + xil_printf("e\r\n"); if (bytes_rcvd == 0) { - xil_printf("CPU1 failed to receive from ICC buffer\r\n"); + //xil_printf("CPU1 failed to receive from ICC buffer\r\n"); + xil_printf("f\r\n"); } else { /* Print the received data. */ - xil_printf("CPU1 - Rx task received string from CPU0 Tx: %s\r\n", Rcvdstring); + //xil_printf("CPU1 - Rx task received string from CPU0 Tx: %s\r\n", Rcvdstring); + xil_printf("g\r\n"); RxtaskCntr++; } } @@ -255,7 +261,8 @@ static void vTimerCallback(TimerHandle_t pxTimer) lTimerId = (long) pvTimerGetTimerID(pxTimer); if (lTimerId != TIMER_ID) { - xil_printf("CPU1 - FreeRTOS Hello World Example FAILED"); + //xil_printf("CPU1 - FreeRTOS Hello World Example FAILED"); + xil_printf("h\r\n"); } /* If the RxtaskCntr is updated every time the Rx task is called. The @@ -265,10 +272,12 @@ static void vTimerCallback(TimerHandle_t pxTimer) have a value of 9 (TIMER_CHECK_THRESHOLD) when the timer expires. */ if (RxtaskCntr >= TIMER_CHECK_THRESHOLD) { message_status = 1; - xil_printf("CPU1 - FreeRTOS Hello World Example PASSED\r\n"); + //xil_printf("CPU1 - FreeRTOS Hello World Example PASSED\r\n"); + xil_printf("i\r\n"); } else { message_status = 2; - xil_printf("CPU1 - FreeRTOS Hello World Example FAILED\r\n"); + //xil_printf("CPU1 - FreeRTOS Hello World Example FAILED\r\n"); + xil_printf("j\r\n"); } } From ea684e69bf4ae0660f32db1849744dfa1a04b293 Mon Sep 17 00:00:00 2001 From: Patrick Nowakowski Date: Mon, 18 Mar 2024 21:51:56 -0500 Subject: [PATCH 5/6] Apply clang format --- sdk/freertos_app_cpu0/src/main.c | 28 +++++++-------- sdk/freertos_app_cpu1/src/main.c | 21 ++++++----- sdk/shared/sys/icc.c | 38 ++++++++++---------- sdk/shared/sys/icc.h | 2 +- sdk/shared/sys/intr.c | 62 ++++++++++++++++++-------------- sdk/shared/sys/intr.h | 2 +- sdk/shared/sys/shared_memory.h | 29 +++++++-------- 7 files changed, 96 insertions(+), 86 deletions(-) diff --git a/sdk/freertos_app_cpu0/src/main.c b/sdk/freertos_app_cpu0/src/main.c index 98b242ca..b2611557 100644 --- a/sdk/freertos_app_cpu0/src/main.c +++ b/sdk/freertos_app_cpu0/src/main.c @@ -230,17 +230,17 @@ static void prvTxTask(void *pvParameters) // HWstring, /* The address of the data being sent. */ // 0UL); /* The block time. */ - //xil_printf("DEBUG: CPU0 about to attempt send\r\n"); + // xil_printf("DEBUG: CPU0 about to attempt send\r\n"); xil_printf("A\r\n"); // Send a message to the other core size_t bytes_sent = xMessageBufferSend(xCPU0to1MessageBufferHandle, HWstring, sizeof(HWstring), 0UL); - //xil_printf("DEBUG: CPU0 sent %d bytes to ICC buffer\r\n", bytes_sent); + // xil_printf("DEBUG: CPU0 sent %d bytes to ICC buffer\r\n", bytes_sent); xil_printf("B\r\n"); if (bytes_sent == 0) { - //xil_printf("ERROR: CPU0 failed to write to ICC buffer\r\n"); + // xil_printf("ERROR: CPU0 failed to write to ICC buffer\r\n"); xil_printf("C\r\n"); } } @@ -263,21 +263,21 @@ static void prvRxTask(void *pvParameters) // Rcvdstring, /* Data is read into this address. */ // portMAX_DELAY); /* Wait without a timeout for data. */ - //xil_printf("DEBUG: CPU0 about to attempt rcv\r\n"); - xil_printf("D\r\n"); + // xil_printf("DEBUG: CPU0 about to attempt rcv\r\n"); + xil_printf("D\r\n"); size_t bytes_rcvd = xMessageBufferReceive(xCPU1to0MessageBufferHandle, Rcvdstring, 32, portMAX_DELAY); - //xil_printf("DEBUG: CPU0 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd); + // xil_printf("DEBUG: CPU0 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd); xil_printf("E\r\n"); if (bytes_rcvd == 0) { - //xil_printf("CPU0 failed to receive from ICC buffer\r\n"); - xil_printf("F\r\n"); + // xil_printf("CPU0 failed to receive from ICC buffer\r\n"); + xil_printf("F\r\n"); } else { /* Print the received data. */ - //xil_printf("CPU0 - Rx task received string from CPU1 Tx: %s\r\n", Rcvdstring); - xil_printf("G\r\n"); + // xil_printf("CPU0 - Rx task received string from CPU1 Tx: %s\r\n", Rcvdstring); + xil_printf("G\r\n"); RxtaskCntr++; } } @@ -345,8 +345,8 @@ static void vTimerCallback(TimerHandle_t pxTimer) lTimerId = (long) pvTimerGetTimerID(pxTimer); if (lTimerId != TIMER_ID) { - //xil_printf("CPU0 - FreeRTOS Hello World Example FAILED"); - xil_printf("H\r\n"); + // xil_printf("CPU0 - FreeRTOS Hello World Example FAILED"); + xil_printf("H\r\n"); } /* If the RxtaskCntr is updated every time the Rx task is called. The @@ -356,11 +356,11 @@ static void vTimerCallback(TimerHandle_t pxTimer) have a value of 9 (TIMER_CHECK_THRESHOLD) when the timer expires. */ if (RxtaskCntr >= TIMER_CHECK_THRESHOLD) { message_status = 1; - //xil_printf("CPU0 - FreeRTOS Hello World Example PASSED\r\n"); + // xil_printf("CPU0 - FreeRTOS Hello World Example PASSED\r\n"); xil_printf("I\r\n"); } else { message_status = 2; - //xil_printf("CPU0 - FreeRTOS Hello World Example FAILED\r\n"); + // xil_printf("CPU0 - FreeRTOS Hello World Example FAILED\r\n"); xil_printf("J\r\n"); } } diff --git a/sdk/freertos_app_cpu1/src/main.c b/sdk/freertos_app_cpu1/src/main.c index 0e819937..f4a58afb 100644 --- a/sdk/freertos_app_cpu1/src/main.c +++ b/sdk/freertos_app_cpu1/src/main.c @@ -197,18 +197,17 @@ static void prvTxTask(void *pvParameters) // HWstring, /* The address of the data being sent. */ // 0UL); /* The block time. */ - //xil_printf("DEBUG: CPU1 about to attempt send\r\n"); + // xil_printf("DEBUG: CPU1 about to attempt send\r\n"); xil_printf("a\r\n"); - // Send a message to the other core size_t bytes_sent = xMessageBufferSend(xCPU1to0MessageBufferHandle, HWstring, sizeof(HWstring), 0UL); - //xil_printf("DEBUG: CPU1 sent %d bytes to ICC buffer\r\n", bytes_sent); + // xil_printf("DEBUG: CPU1 sent %d bytes to ICC buffer\r\n", bytes_sent); xil_printf("b\r\n"); if (bytes_sent == 0) { - //xil_printf("ERROR: CPU1 failed to write to ICC buffer\r\n"); + // xil_printf("ERROR: CPU1 failed to write to ICC buffer\r\n"); xil_printf("c\r\n"); } } @@ -231,20 +230,20 @@ static void prvRxTask(void *pvParameters) // Rcvdstring, /* Data is read into this address. */ // portMAX_DELAY); /* Wait without a timeout for data. */ - //xil_printf("DEBUG: CPU1 about to attempt rcv\r\n"); + // xil_printf("DEBUG: CPU1 about to attempt rcv\r\n"); xil_printf("d\r\n"); size_t bytes_rcvd = xMessageBufferReceive(xCPU0to1MessageBufferHandle, Rcvdstring, 32, portMAX_DELAY); - //xil_printf("DEBUG: CPU1 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd); + // xil_printf("DEBUG: CPU1 rcvd %d bytes from ICC buffer\r\n", bytes_rcvd); xil_printf("e\r\n"); if (bytes_rcvd == 0) { - //xil_printf("CPU1 failed to receive from ICC buffer\r\n"); + // xil_printf("CPU1 failed to receive from ICC buffer\r\n"); xil_printf("f\r\n"); } else { /* Print the received data. */ - //xil_printf("CPU1 - Rx task received string from CPU0 Tx: %s\r\n", Rcvdstring); + // xil_printf("CPU1 - Rx task received string from CPU0 Tx: %s\r\n", Rcvdstring); xil_printf("g\r\n"); RxtaskCntr++; } @@ -261,7 +260,7 @@ static void vTimerCallback(TimerHandle_t pxTimer) lTimerId = (long) pvTimerGetTimerID(pxTimer); if (lTimerId != TIMER_ID) { - //xil_printf("CPU1 - FreeRTOS Hello World Example FAILED"); + // xil_printf("CPU1 - FreeRTOS Hello World Example FAILED"); xil_printf("h\r\n"); } @@ -272,11 +271,11 @@ static void vTimerCallback(TimerHandle_t pxTimer) have a value of 9 (TIMER_CHECK_THRESHOLD) when the timer expires. */ if (RxtaskCntr >= TIMER_CHECK_THRESHOLD) { message_status = 1; - //xil_printf("CPU1 - FreeRTOS Hello World Example PASSED\r\n"); + // xil_printf("CPU1 - FreeRTOS Hello World Example PASSED\r\n"); xil_printf("i\r\n"); } else { message_status = 2; - //xil_printf("CPU1 - FreeRTOS Hello World Example FAILED\r\n"); + // xil_printf("CPU1 - FreeRTOS Hello World Example FAILED\r\n"); xil_printf("j\r\n"); } } diff --git a/sdk/shared/sys/icc.c b/sdk/shared/sys/icc.c index dbdfdb00..3b0611c5 100644 --- a/sdk/shared/sys/icc.c +++ b/sdk/shared/sys/icc.c @@ -19,9 +19,9 @@ void icc_init() // Use the getters once ready void (*vCPU0to1ReceiveCallback)() = ICC_getCPU0to1ReceiveCallback; - //xil_printf("DEBUG: CPU 0 got 0to1 Receive Callback %p\r\n", (void *) vCPU0to1ReceiveCallback); + // xil_printf("DEBUG: CPU 0 got 0to1 Receive Callback %p\r\n", (void *) vCPU0to1ReceiveCallback); void (*vCPU1to0SendCallback)() = ICC_getCPU1to0SendCallback; - //xil_printf("DEBUG: CPU 0 got 1to0 Send Callback %p\r\n", (void *) vCPU1to0SendCallback); + // xil_printf("DEBUG: CPU 0 got 1to0 Send Callback %p\r\n", (void *) vCPU1to0SendCallback); /* Create two message buffers for inter-core communication that use the callback * functions below as send and receive completed callback functions. */ @@ -40,9 +40,9 @@ void icc_init() vCPU1to0ReceiveCallback); // Called by CPU0 after removing message from 1to0 buffer ICC_setCPU0to1Handle(xCPU0to1MessageBufferHandle); - //xil_printf("DEBUG: CPU 0 set 0to1 Handle %p\r\n", (void *) xCPU0to1MessageBufferHandle); + // xil_printf("DEBUG: CPU 0 set 0to1 Handle %p\r\n", (void *) xCPU0to1MessageBufferHandle); ICC_setCPU1to0Handle(xCPU1to0MessageBufferHandle); - //xil_printf("DEBUG: CPU 0 set 1to0 Handle %p\r\n", (void *) xCPU1to0MessageBufferHandle); + // xil_printf("DEBUG: CPU 0 set 1to0 Handle %p\r\n", (void *) xCPU1to0MessageBufferHandle); ICC_setHandleComplete; #elif XPAR_CPU_ID == 1 @@ -53,9 +53,9 @@ void icc_init() // Make CPU1's callback function pointers available to CPU0 ICC_setCPU1to0SendCallback(&vCPU1to0SendCallback); - //xil_printf("DEBUG: CPU 1 set 1to0 Send Callback %p\r\n", &vCPU1to0SendCallback); + // xil_printf("DEBUG: CPU 1 set 1to0 Send Callback %p\r\n", &vCPU1to0SendCallback); ICC_setCPU0to1ReceiveCallback(&vCPU0to1ReceiveCallback); - //xil_printf("DEBUG: CPU 1 set 0to1 Receive Callback %p\r\n", &vCPU0to1ReceiveCallback); + // xil_printf("DEBUG: CPU 1 set 0to1 Receive Callback %p\r\n", &vCPU0to1ReceiveCallback); ICC_setFunctionPointersReady; @@ -64,9 +64,9 @@ void icc_init() ; xCPU0to1MessageBufferHandle = ICC_getCPU0to1Handle; - //xil_printf("DEBUG: CPU 1 got 0to1 Handle %p\r\n", (void *) xCPU0to1MessageBufferHandle); + // xil_printf("DEBUG: CPU 1 got 0to1 Handle %p\r\n", (void *) xCPU0to1MessageBufferHandle); xCPU1to0MessageBufferHandle = ICC_getCPU1to0Handle; - //xil_printf("DEBUG: CPU 1 got 1to0 Handle %p\r\n", (void *) xCPU1to0MessageBufferHandle); + // xil_printf("DEBUG: CPU 1 got 1to0 Handle %p\r\n", (void *) xCPU1to0MessageBufferHandle); #endif } @@ -93,8 +93,8 @@ void vCPU0to1SendCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken) { - //xil_printf("DEBUG: CPU 0 to 1 Send Callback reached (in CPU0)\r\n"); - xil_printf("K\r\n"); + // xil_printf("DEBUG: CPU 0 to 1 Send Callback reached (in CPU0)\r\n"); + xil_printf("K\r\n"); // CPU 0 should send an interrupt to CPU1 to unblock its Rx task int status = XScuGic_SoftwareIntr(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_RX_INT_ID, XSCUGIC_SPI_CPU1_MASK); @@ -104,9 +104,9 @@ void vCPU1to0ReceiveCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken) { - //xil_printf("DEBUG: CPU 1 to 0 Receive Callback reached (in CPU0)\r\n"); - xil_printf("L\r\n"); - + // xil_printf("DEBUG: CPU 1 to 0 Receive Callback reached (in CPU0)\r\n"); + xil_printf("L\r\n"); + // CPU0 should send an interrupt to CPU1 to unblock its Tx task (the buffer might have an open space now) int status = XScuGic_SoftwareIntr(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_TX_INT_ID, XSCUGIC_SPI_CPU1_MASK); } @@ -117,9 +117,9 @@ void vCPU1to0SendCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken) { - //xil_printf("DEBUG: CPU 1 to 0 Send Callback reached (in CPU1)\r\n"); - xil_printf("k\r\n"); - + // xil_printf("DEBUG: CPU 1 to 0 Send Callback reached (in CPU1)\r\n"); + xil_printf("k\r\n"); + // CPU 1 should send an interrupt to CPU0 to unblock its Rx task int status = XScuGic_SoftwareIntr(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_RX_INT_ID, XSCUGIC_SPI_CPU0_MASK); } @@ -128,9 +128,9 @@ void vCPU0to1ReceiveCallback(MessageBufferHandle_t xMessageBuffer, BaseType_t xIsInsideISR, BaseType_t *const pxHigherPriorityTaskWoken) { - //xil_printf("DEBUG: CPU 0 to 1 Receive Callback reached (in CPU1)\r\n"); - xil_printf("l\r\n"); - + // xil_printf("DEBUG: CPU 0 to 1 Receive Callback reached (in CPU1)\r\n"); + xil_printf("l\r\n"); + // CPU 1 should send an interrupt to CPU0 to unblock its Tx task (the buffer might have an open space) int status = XScuGic_SoftwareIntr(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_TX_INT_ID, XSCUGIC_SPI_CPU0_MASK); } diff --git a/sdk/shared/sys/icc.h b/sdk/shared/sys/icc.h index 38944597..5e365b96 100644 --- a/sdk/shared/sys/icc.h +++ b/sdk/shared/sys/icc.h @@ -2,8 +2,8 @@ #define ICC_H #include "FreeRTOS.h" -#include "shared_memory.h" #include "message_buffer.h" +#include "shared_memory.h" #include "xil_printf.h" #include diff --git a/sdk/shared/sys/intr.c b/sdk/shared/sys/intr.c index dce7f24b..fcaa9c9a 100644 --- a/sdk/shared/sys/intr.c +++ b/sdk/shared/sys/intr.c @@ -20,7 +20,7 @@ * message is removed from a full ICC Message Buffer * * See sys/icc.c for more info. - * + * // RELEVENT TRM SECTIONS * Read Chapter 7: Interrupts in the Zynq-7000 TRM * It starts on page 231 of the PDF @@ -29,13 +29,13 @@ * that starts on page 1483. * Registers starting with ICD are the ones we care about * These are the "distributor" registers starting with ICDDCR at absolute address 0xF8F01000 - * + * // USEFUL XILINX-PROVIDED FILES TO READ * - xparameters.h : Search for "SCUGIC" related definitions * - XPAR_PS7_SCUGIC_0_DEVICE_ID 0U * - XPAR_PS7_SCUGIC_0_BASEADDR 0xF8F00100U * - XPAR_PS7_SCUGIC_0_HIGHADDR 0xF8F001FFU - * - XPAR_PS7_SCUGIC_0_DIST_BASEADDR 0xF8F01000U + * - XPAR_PS7_SCUGIC_0_DIST_BASEADDR 0xF8F01000U * - xscugic_sinit.c : Contains the necessary LookupConfig() function * - xscugic.c : Contains most of the useful GIC functions * - XScuGic_CfgInitialize() @@ -64,17 +64,18 @@ int intr_init() #if XPAR_CPU_ID == 0 // CPU0 handles initialization of the Generic Interrrupt Controller xil_printf("INTR: Initializing GIC...\n"); - XScuGic_Config * gic_config_ptr = XScuGic_LookupConfig(INTR_GIC_DEVICE_ID); + XScuGic_Config *gic_config_ptr = XScuGic_LookupConfig(INTR_GIC_DEVICE_ID); // gic_config_ptr provides the Xilinx base addresses of: - // - the GIC's distributor registers (the distributor is a shared resource that distributes interrupts to the CPUs) - // - the "CPU Interface" registers, each CPU has an interface that needs to be configured to interact with the GIC + // - the GIC's distributor registers (the distributor is a shared resource that distributes interrupts to the + // CPUs) + // - the "CPU Interface" registers, each CPU has an interface that needs to be configured to interact with the GIC s32 gic_init_status = XScuGic_CfgInitialize(INTR_GIC_INSTANCE_ADDR, gic_config_ptr, gic_config_ptr->CpuBaseAddress); if (gic_init_status != XST_SUCCESS) { - xil_printf("INTR: GIC Initialization Failed\n"); - return XST_FAILURE; - } - xil_printf("INTR: GIC Initialization Success\n"); + xil_printf("INTR: GIC Initialization Failed\n"); + return XST_FAILURE; + } + xil_printf("INTR: GIC Initialization Success\n"); INTR_setGicInitReady; #elif XPAR_CPU_ID == 1 // Wait for CPU0 to finish GIC initialization @@ -82,36 +83,45 @@ int intr_init() ; // CPU1 still needs to configure its own CPU Interface, using these lines pulled from CPUInitialize() in xscugic.c - // CPU0 does this by calling CPUInitialize() within XScuGic_CfgInitialize() (xscugic.c, Line 481), but because of the GIC - // ready check on Line 439 of xscugic.c, if CPU1 calls XScuGic_CfgInitialize(), it will skip the call to CPUInitialize() - // if CPU0 has already marked the GIC as ready. - XScuGic_CPUWriteReg(INTR_GIC_INSTANCE_ADDR, XSCUGIC_CPU_PRIOR_OFFSET, 0xF0U); - XScuGic_CPUWriteReg(INTR_GIC_INSTANCE_ADDR, XSCUGIC_CONTROL_OFFSET, 0x07U); + // CPU0 does this by calling CPUInitialize() within XScuGic_CfgInitialize() (xscugic.c, Line 481), but because of + // the GIC ready check on Line 439 of xscugic.c, if CPU1 calls XScuGic_CfgInitialize(), it will skip the call to + // CPUInitialize() if CPU0 has already marked the GIC as ready. + XScuGic_CPUWriteReg(INTR_GIC_INSTANCE_ADDR, XSCUGIC_CPU_PRIOR_OFFSET, 0xF0U); + XScuGic_CPUWriteReg(INTR_GIC_INSTANCE_ADDR, XSCUGIC_CONTROL_OFFSET, 0x07U); #endif // BOTH CORES: Connect the ARM processor's InterruptHandler logic to the initialized GIC - Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, INTR_GIC_INSTANCE_ADDR); + Xil_ExceptionRegisterHandler( + XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, INTR_GIC_INSTANCE_ADDR); Xil_ExceptionEnable(); #if XPAR_CPU_ID == 0 // Each CPU needs to connect its software interrupts to the appropriate handlers defined below, then enable - XScuGic_Connect(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_RX_INT_ID, - (Xil_ExceptionHandler)CPU0UnblockRxHandler, (void *)INTR_GIC_INSTANCE_ADDR); + XScuGic_Connect(INTR_GIC_INSTANCE_ADDR, + INTR_UNBLOCK_CPU0_RX_INT_ID, + (Xil_ExceptionHandler) CPU0UnblockRxHandler, + (void *) INTR_GIC_INSTANCE_ADDR); XScuGic_Enable(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_RX_INT_ID); - XScuGic_Connect(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_TX_INT_ID, - (Xil_ExceptionHandler)CPU0UnblockTxHandler, (void *)INTR_GIC_INSTANCE_ADDR); + XScuGic_Connect(INTR_GIC_INSTANCE_ADDR, + INTR_UNBLOCK_CPU0_TX_INT_ID, + (Xil_ExceptionHandler) CPU0UnblockTxHandler, + (void *) INTR_GIC_INSTANCE_ADDR); XScuGic_Enable(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU0_TX_INT_ID); - + #elif XPAR_CPU_ID == 1 - XScuGic_Connect(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_RX_INT_ID, - (Xil_ExceptionHandler)CPU1UnblockRxHandler, (void *)INTR_GIC_INSTANCE_ADDR); + XScuGic_Connect(INTR_GIC_INSTANCE_ADDR, + INTR_UNBLOCK_CPU1_RX_INT_ID, + (Xil_ExceptionHandler) CPU1UnblockRxHandler, + (void *) INTR_GIC_INSTANCE_ADDR); XScuGic_Enable(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_RX_INT_ID); - XScuGic_Connect(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_TX_INT_ID, - (Xil_ExceptionHandler)CPU1UnblockTxHandler, (void *)INTR_GIC_INSTANCE_ADDR); + XScuGic_Connect(INTR_GIC_INSTANCE_ADDR, + INTR_UNBLOCK_CPU1_TX_INT_ID, + (Xil_ExceptionHandler) CPU1UnblockTxHandler, + (void *) INTR_GIC_INSTANCE_ADDR); XScuGic_Enable(INTR_GIC_INSTANCE_ADDR, INTR_UNBLOCK_CPU1_TX_INT_ID); - + #endif return XST_SUCCESS; diff --git a/sdk/shared/sys/intr.h b/sdk/shared/sys/intr.h index 59c9c4d6..51308e35 100644 --- a/sdk/shared/sys/intr.h +++ b/sdk/shared/sys/intr.h @@ -20,7 +20,7 @@ // CPUs, use "#if XPAR_CPU_ID == ?" /////////////////////////////////////////////////////// -#define INTR_GIC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID // good +#define INTR_GIC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID // good int intr_init(); diff --git a/sdk/shared/sys/shared_memory.h b/sdk/shared/sys/shared_memory.h index cae87bdd..faf1d67a 100644 --- a/sdk/shared/sys/shared_memory.h +++ b/sdk/shared/sys/shared_memory.h @@ -1,10 +1,10 @@ #ifndef SHARED_MEMORY_H #define SHARED_MEMORY_H +#include "message_buffer.h" +#include "xil_printf.h" #include "xparameters.h" #include "xscugic.h" -#include "xil_printf.h" -#include "message_buffer.h" /////////////////////////////////////////////////////// // THIS IS A SHARED FILE, SO IT IS ALWAYS @@ -15,13 +15,13 @@ /////////////////////////////////////////////////////// /* This file contains all the macro definitions that need to be shared between CPU0 and CPU1 - * This includes definitions for Inter-Core Communication, Inter-Core Interrupts, + * This includes definitions for Inter-Core Communication, Inter-Core Interrupts, * the Generic Interrupt Controller (GIC) definitions and metadata, etc * * Per Zynq-7000 TRM Ch. 4: System Addresses (page 106), the initial mapping * of OCM is split between low addresses and high addresses in 64 KB chunks. - * We will pick to use the highest 64 KB chunk as our base address: */ -#define SHARED_OCM_BASE_ADDR (0xFFFF0000) + * We will pick to use the highest 64 KB chunk as our base address: */ +#define SHARED_OCM_BASE_ADDR (0xFFFF0000) /////////////////////////////////// // INTER-CORE COMMUNICATION @@ -45,8 +45,10 @@ MessageBufferHandle_t xCPU1to0MessageBufferHandle; #define ICC_CPU0to1BufferStructAddr ((uint8_t *) (SHARED_OCM_BASE_ADDR + (0 * ICC_BUFFER_STRUCT_SIZE))) #define ICC_CPU1to0BufferStructAddr ((uint8_t *) (SHARED_OCM_BASE_ADDR + (1 * ICC_BUFFER_STRUCT_SIZE))) -#define ICC_CPU0to1BufferSpaceAddr ((uint8_t *) (SHARED_OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (0 * ICC_BUFFER_SIZE))) -#define ICC_CPU1to0BufferSpaceAddr ((uint8_t *) (SHARED_OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (1 * ICC_BUFFER_SIZE))) +#define ICC_CPU0to1BufferSpaceAddr \ + ((uint8_t *) (SHARED_OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (0 * ICC_BUFFER_SIZE))) +#define ICC_CPU1to0BufferSpaceAddr \ + ((uint8_t *) (SHARED_OCM_BASE_ADDR + (2 * ICC_BUFFER_STRUCT_SIZE) + (1 * ICC_BUFFER_SIZE))) /* These memory spaces are used to transfer the Message Buffer Handles from CPU0 (who does the initialization work, and * gets the handles from the xMessageBufferCreateStaticWithCallback function) to CPU1 (who doesn't initialize anything @@ -84,7 +86,6 @@ MessageBufferHandle_t xCPU1to0MessageBufferHandle; #define ICC_getFunctionPointersReady ((*((uint8_t *) ICC_functionPointersLockAddr)) #define ICC_setFunctionPointersReady ((*((uint8_t *) ICC_functionPointersLockAddr) = 1) - /////////////////////////////////// // INTERRUPTS / GIC ///////////////////////////////// @@ -93,18 +94,18 @@ MessageBufferHandle_t xCPU1to0MessageBufferHandle; #define INTR_UNBLOCK_CPU1_RX_INT_ID 2 #define INTR_UNBLOCK_CPU1_TX_INT_ID 3 -#define INTR_SHARED_MEMORY_BASE_ADDR (0xFFFFF000)//(ICC_functionPointersLockAddr + sizeof(uint8_t)) -#define INTR_GIC_INSTANCE_SIZE (sizeof(XScuGic)) +#define INTR_SHARED_MEMORY_BASE_ADDR (0xFFFFF000) //(ICC_functionPointersLockAddr + sizeof(uint8_t)) +#define INTR_GIC_INSTANCE_SIZE (sizeof(XScuGic)) // Interrupt Controller Instance // Defined here to be accessible in both sys/icc.c and sys/intr.h -#define INTR_GIC_INSTANCE_ADDR ((XScuGic *)INTR_SHARED_MEMORY_BASE_ADDR) -#define INTR_gicInstance (*((XScuGic *)INTR_GIC_INSTANCE_ADDR)) +#define INTR_GIC_INSTANCE_ADDR ((XScuGic *) INTR_SHARED_MEMORY_BASE_ADDR) +#define INTR_gicInstance (*((XScuGic *) INTR_GIC_INSTANCE_ADDR)) // Interrupt Controller Initializaton Lock w/ getter & setter #define INTR_gicInitLockAddr (INTR_GIC_INSTANCE_ADDR + INTR_GIC_INSTANCE_SIZE) -#define INTR_getGicInitReady (*((uint8_t *) INTR_gicInitLockAddr)) -#define INTR_setGicInitReady (*((uint8_t *) INTR_gicInitLockAddr) = 1) +#define INTR_getGicInitReady (*((uint8_t *) INTR_gicInitLockAddr)) +#define INTR_setGicInitReady (*((uint8_t *) INTR_gicInitLockAddr) = 1) #endif /* SHARED_MEMORY_H */ From 7f764afe315bbe6046ebe11651804f2c1e092740 Mon Sep 17 00:00:00 2001 From: Patrick Nowakowski Date: Tue, 19 Mar 2024 12:40:29 -0500 Subject: [PATCH 6/6] Add another unmatched paranthese in shared_memory.h to stop preprocessor macros from breaking build --- sdk/shared/sys/shared_memory.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/shared/sys/shared_memory.h b/sdk/shared/sys/shared_memory.h index faf1d67a..43aa6422 100644 --- a/sdk/shared/sys/shared_memory.h +++ b/sdk/shared/sys/shared_memory.h @@ -94,13 +94,13 @@ MessageBufferHandle_t xCPU1to0MessageBufferHandle; #define INTR_UNBLOCK_CPU1_RX_INT_ID 2 #define INTR_UNBLOCK_CPU1_TX_INT_ID 3 -#define INTR_SHARED_MEMORY_BASE_ADDR (0xFFFFF000) //(ICC_functionPointersLockAddr + sizeof(uint8_t)) +#define INTR_SHARED_MEMORY_BASE_ADDR (ICC_functionPointersLockAddr + sizeof(uint8_t)) #define INTR_GIC_INSTANCE_SIZE (sizeof(XScuGic)) // Interrupt Controller Instance // Defined here to be accessible in both sys/icc.c and sys/intr.h -#define INTR_GIC_INSTANCE_ADDR ((XScuGic *) INTR_SHARED_MEMORY_BASE_ADDR) -#define INTR_gicInstance (*((XScuGic *) INTR_GIC_INSTANCE_ADDR)) +#define INTR_GIC_INSTANCE_ADDR ((XScuGic *) (INTR_SHARED_MEMORY_BASE_ADDR) +#define INTR_gicInstance (*((XScuGic *) INTR_GIC_INSTANCE_ADDR)) // Interrupt Controller Initializaton Lock w/ getter & setter #define INTR_gicInitLockAddr (INTR_GIC_INSTANCE_ADDR + INTR_GIC_INSTANCE_SIZE)