

在
learning plus: AMBA 4 ARM ,
learning plus: AHB Platform emulator @ SystemC,
learning plus: ESL Design Flow 中我們有介紹 AMBA 2.0 AHB跟APB 的 Bus 架構,跟 SystemC Module @ AHB,APB 的 virtual platform .不過 ARM 在 AMBA 3.0之後為了要增加 Bus 的效能,而改變了先前 AMBA 2.0 的 protocol,主要在於 AMBA 2.0 採用的是 in-order 機制,就是Data傳輸完後 Bus 的使用權才會被Release.表示一組Transfer是不能被中斷的,相對的Bus會一值被Lock.導致整個系統的 performance會被慢速的 Transfer 給影響,所以在 AMBA 3.0 之後採用 out-of-order 的概念做不對等的傳輸方式,表示在每組 Transfer 可根據自己本身速度的快慢來 Access Bus.
Ex: AMBA 2.0 Burst(4) type M1@33Mhz, M2@66Mhz
SEQ : M1->M2
M1(0), M1(1), M1(2), M1(3), M2(0), M2(1), M2(2), M2(3)
要等 M1 完成, M2 才開始
Ex: AMBA >=3.0 Burst(4) type M1@33Mhz, M2@66Mhz
SEQ : M1->M2
M2(0), M2(1), M2(2), M2(3),M1(0),M1(1) M1(2), M2(3)
取決於 M1, M2 的速度,不必等 M1 完成, M2 即可開始
當然這除了硬體要支援sort跟reorder機制,跟 Address Phase 和 Data Phase 完全分開.

底下用sample code來模擬 in-order 跟 out-of-order的差別
in_order.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define MAX_BURST 4
#define MAX_TEST_COT 3
pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t condition_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condition_cond = PTHREAD_COND_INITIALIZER;
enum BUS_STATUS {
BUS_ON_BUSY =0,
BUS_OFF_BUSY =1,
BUS_ON_LOCK =2,
BUS_OFF_LOCK =3,
};
enum BUS_ADDR_MAP {
BUS_SLAVE_1_ST = 0x00000100,
BUS_SLAVE_1_ED = 0x000001ff,
BUS_SLAVE_2_ST = 0x00000200,
BUS_SLAVE_2_ED = 0x000002ff,
BUS_MASTER_1_ST = 0x00000300,
BUS_MASTER_1_ED = 0x000003ff,
};
typedef struct Bus {
int FmAddr;
int ToAddr;
int Data[MAX_BURST];
int Busy;
int Lock;
} Bus_Buf;
Bus_Buf BusPtr;
int TEST_COT=0;
void Bus_Initial(){
BusPtr.Busy = BUS_OFF_BUSY;
BusPtr.Lock = BUS_OFF_LOCK;
}
void *MASTER_1_Transmitter(void *t){
long my_id = (long)t;
while( TEST_COT < MAX_TEST_COT ){
int cot =10;
while( BusPtr.Busy == BUS_ON_BUSY ){
sleep(1);
if( cot==0 ){ printf("Out-of-Time-Wait M1 Transmitter retry...\n"); break; }
cot--;
}
if( cot>0 ){
printf("M1 Transmitter @ %d\n", TEST_COT);
pthread_mutex_lock(&count_mutex);
BusPtr.FmAddr = BUS_MASTER_1_ST;
BusPtr.ToAddr = ( TEST_COT%2==0 )? BUS_SLAVE_1_ST: BUS_SLAVE_2_ST;
BusPtr.Busy = BUS_ON_BUSY;
pthread_mutex_unlock(&count_mutex);
} else {
sleep(2);
}
sleep(3);
}
pthread_exit(NULL);
}
void *MASTER_1_Receiver(void *t){
long my_id = (long)t;
int cot =10;
while( TEST_COT < MAX_TEST_COT ){
while( BusPtr.Busy == BUS_ON_BUSY && BusPtr.Lock == BUS_OFF_LOCK ){
sleep(1);
if( cot==0 ){ printf("Out-of-Time wait M1 Receiver retry...\n"); break; }
cot--;
}
int i;
if( cot>0 && BUS_MASTER_1_ST <= BusPtr.FmAddr && BusPtr.FmAddr <= BUS_MASTER_1_ED ){
pthread_mutex_lock(&count_mutex);
BusPtr.Busy = BUS_OFF_BUSY;
BusPtr.Lock = BUS_OFF_LOCK;
for(i=0; i<MAX_BURST; i++){
printf("M1 Receive Fm %d,%d,%d\n",BusPtr.ToAddr,i,BusPtr.Data[i]);
}
printf("M1 Reveive Done @ %d\n",TEST_COT);
printf("\n");
TEST_COT++;
pthread_mutex_unlock(&count_mutex);
} else {
sleep(2);
}
sleep(3);
}
pthread_exit(NULL);
}
void *SLAVE_1_DO(void *t){
long my_id = (long)t;
while( TEST_COT < MAX_TEST_COT ){
while( BusPtr.Busy == BUS_OFF_BUSY ){
sleep(1);
}
int i;
if( BUS_SLAVE_1_ST <= BusPtr.ToAddr && BusPtr.ToAddr <= BUS_SLAVE_1_ED ){
pthread_mutex_lock(&count_mutex);
BusPtr.Lock = BUS_ON_LOCK;
for(i=0; i<MAX_BURST; i++){
BusPtr.Data[i] = i+10;
}
pthread_mutex_unlock(&count_mutex);
} else {
sleep(3);
}
sleep(3);
}
pthread_exit(NULL);
}
void *SLAVE_2_DO(void *t){
long my_id = (long)t;
while( TEST_COT < MAX_TEST_COT ){
while( BusPtr.Busy == BUS_OFF_BUSY ){
sleep(1);
}
int i;
if( BUS_SLAVE_2_ST <= BusPtr.ToAddr && BusPtr.ToAddr <= BUS_SLAVE_2_ED ){
pthread_mutex_lock(&count_mutex);
BusPtr.Lock = BUS_ON_LOCK;
for(i=0; i<MAX_BURST; i++){
BusPtr.Data[i] = i+100;
}
pthread_mutex_unlock(&count_mutex);
} else {
sleep(3);
}
sleep(3);
}
pthread_exit(NULL);
}
int main(int argc,char* argv[]){
Bus_Initial();
pthread_t thread[4];
pthread_create( &thread[0],NULL, MASTER_1_Transmitter, NULL);
pthread_create( &thread[1],NULL, MASTER_1_Receiver, NULL);
pthread_create( &thread[2],NULL, SLAVE_1_DO, NULL);
pthread_create( &thread[3],NULL, SLAVE_2_DO, NULL);
pthread_join( thread[0],NULL);
pthread_join( thread[1],NULL);
pthread_join( thread[2],NULL);
pthread_join( thread[3],NULL);
pthread_exit(NULL);
return 0;
}
Results
M1 Transmitter @ 0
M1 Receive Fm 256,0,10
M1 Receive Fm 256,1,11
M1 Receive Fm 256,2,12
M1 Receive Fm 256,3,13
M1 Reveive Done @ 0
M1 Transmitter @ 1
M1 Receive Fm 512,0,100
M1 Receive Fm 512,1,101
M1 Receive Fm 512,2,102
M1 Receive Fm 512,3,103
M1 Reveive Done @ 1
sample code download
here
Refs:
ARM Technology
基于AMBA AXI总线的低功耗扩展设计
On Chip Communication Architectures
AHB vs.
AXI Burst.
AHB Burst. Address and Data are locked together (single pipeline stage); HREADY controls intervals of address and data
...
沒有留言:
張貼留言