Skip to content

Commit

Permalink
Move shared memory definitions to specific file, implement GIC initia…
Browse files Browse the repository at this point in the history
…lization
  • Loading branch information
codecubepi committed Mar 2, 2024
1 parent d151b29 commit 38a47fe
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 128 deletions.
2 changes: 1 addition & 1 deletion sdk/shared/sys/icc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
65 changes: 1 addition & 64 deletions sdk/shared/sys/icc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <stdint.h>
Expand Down Expand Up @@ -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,
Expand Down
136 changes: 80 additions & 56 deletions sdk/shared/sys/intr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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
9 changes: 2 additions & 7 deletions sdk/shared/sys/intr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -12,8 +12,6 @@
#include <stdint.h>
#include <stdio.h>

// test

///////////////////////////////////////////////////////
// THIS IS A SHARED FILE, SO IT IS ALWAYS
// IN SYNC IN BOTH CPU0 AND CPU1
Expand All @@ -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();

Expand Down
Loading

0 comments on commit 38a47fe

Please sign in to comment.