2010年8月24日 星期二

AMBA 4.0 AXI Bus Pt1

檢查拼字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 ...

沒有留言:

張貼留言