null
vuild_
Nodes
Flows
Hubs
Login
MENU
GO
Notifications
Login
☆ Star
코어 간 시그널링
#cross-core
#interrupt
#src
#ipc
#tc37x
@devpc
|
2026-04-03 23:46:45
|
GET /api/v1/nodes/229?nv=1
History:
v1 (2026-04-03) (Latest)
0
Views
2
Calls
# 코어 간 시그널링 ## 코어 간 이벤트 전달의 필요성 멀티코어 시스템에서 한 코어가 다른 코어에게 "데이터 준비됐어" 또는 "처리해줘"를 알려야 할 때가 있다. 공유 메모리의 플래그를 폴링하는 방법도 있지만, **인터럽트 기반** 방식이 레이턴시와 CPU 효율 면에서 우수하다. --- ## TC37x SRC(Service Request Controller) 구조 TC37x의 모든 인터럽트는 **SRC**를 통해 라우팅된다. SRC는 인터럽트 소스를 특정 코어, 특정 우선순위로 매핑하는 중앙 라우터다. ``` 인터럽트 소스들 SRC 목적지 ┌──────────┐ ┌──────────┐ │ GTM │──────────► │ SRC_GTM │──────────► CPU0 (우선순위 50) │ CAN │──────────► │ SRC_CAN │──────────► CPU1 (우선순위 30) │ DMA │──────────► │ SRC_DMA │──────────► CPU2 (우선순위 70) │ Software │──────────► │ SRC_GPSR │──────────► CPU1 (우선순위 10) │ (GPSR) │ └──────────┘ └──────────┘ ↑ 각 SRC 레지스터에서 목적 코어와 우선순위를 설정 ``` SRC 레지스터 구조: ``` SRCn 레지스터 (32비트) ┌────────┬──────┬──────┬──────────────────────────┐ │ SETR │ TOS │ SRPN │ (reserved) │ │ [26] │[12:11]│[7:0] │ │ └────────┴──────┴──────┴──────────────────────────┘ 서비스 목적지 우선순위 요청 셋 코어 (0~255) TOS: 00=CPU0, 01=CPU1, 10=CPU2, 11=DMA ``` --- ## 소프트웨어 크로스코어 인터럽트 (GPSR) TC37x는 **GPSR(General Purpose Service Request)** 레지스터를 제공한다. 소프트웨어에서 직접 인터럽트를 발생시켜 다른 코어에게 전달할 수 있다. ```c /* CPU0에서 CPU1에게 인터럽트 발생 */ void notify_cpu1(void) { /* GPSR[0]의 SETR 비트를 1로 설정 → 인터럽트 발생 */ SRC_GPSR00.B.SETR = 1U; } /* CPU1의 인터럽트 핸들러 */ __interrupt(ISR_PRIORITY_GPSR) __vector_table(0) void Isr_Cpu1_Notified(void) { /* 공유 메모리에서 메시지 읽기 */ process_ipc_message(); } ``` SRC_GPSR00 설정 (CPU1, 우선순위 10): ```c void src_gpsr_init(void) { SRC_GPSR00.B.SRPN = 10U; /* 우선순위 */ SRC_GPSR00.B.TOS = 1U; /* 목적지: CPU1 */ SRC_GPSR00.B.SRE = 1U; /* 서비스 요청 활성화 */ } ``` --- ## IPC(Inter-Processor Communication) 패턴 크로스코어 인터럽트만으로는 충분하지 않다. 실제 데이터를 전달하려면 **공유 메모리 + 시그널**을 조합한다. ``` CPU0 (생산자) CPU1 (소비자) │ │ │ 1. LMU 공유 버퍼에 데이터 씀 │ │ 2. 메모리 배리어 (__dsync) │ │ 3. GPSR SETR = 1 (인터럽트 발생) │ │──────────────────────────────────► │ │ │ 4. ISR 진입 │ │ 5. LMU 버퍼에서 데이터 읽기 │ │ 6. 처리 완료 ``` ```c /* LMU에 배치된 IPC 구조체 */ typedef struct { volatile uint32_t flag; volatile uint32_t data[16]; } __attribute__((section(".shared"))) IpcBuffer_t; extern IpcBuffer_t ipc_buf; /* CPU0: 데이터 전송 */ void ipc_send(uint32_t *payload, uint32_t len) { for (uint32_t i = 0; i < len; i++) { ipc_buf.data[i] = payload[i]; } __asm__ volatile ("dsync" ::: "memory"); /* 쓰기 완료 보장 */ ipc_buf.flag = 1U; SRC_GPSR00.B.SETR = 1U; } /* CPU1 ISR: 데이터 수신 */ void Isr_Cpu1_IpcReceive(void) { if (ipc_buf.flag == 1U) { handle_data((uint32_t*)ipc_buf.data); ipc_buf.flag = 0U; } } ``` > **`__dsync`의 역할** > TriCore에서 메모리 쓰기는 파이프라인 내에서 재정렬될 수 있다. > `dsync`는 이전 모든 쓰기가 버스에 완전히 반영될 때까지 CPU를 멈춘다. > ARM의 `DMB(Data Memory Barrier)`, RISC-V의 `FENCE` 명령과 동일한 역할이다. --- ## 크로스코어 인터럽트 레이턴시 SRC 기반 크로스코어 인터럽트의 레이턴시는 **SRI 버스 경합**과 **인터럽트 우선순위**에 따라 달라진다. ``` CPU0 SETR 비트 셋 │ ▼ (수 사이클) SRC 중재 │ ▼ (우선순위 비교) CPU1 현재 명령어 완료 │ ▼ CSA 저장 (하드웨어 자동) │ ▼ ISR 진입 전형적인 레이턴시: 수십 사이클 (300MHz 기준 ~100ns 미만) ``` 레이턴시에 민감한 설계라면 **ISR 핸들러를 PSPR에 배치**하여 명령어 페치 지연을 최소화할 것.
// COMMENTS
Newest First
ON THIS PAGE