FC2カウンター FPGAの部屋 2012年06月05日
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

AXI Performance Monitor IPを試してみた3(SDKでCソフトを作成)

AXI Performance Monitor IPを試してみた2(SDK)”の続き。

前回はXMDで直接アドレスを入力してAXI Performance Monitor を試してみたが、今回はCでソフトウェアを作成して1秒あたりのRead/Writeトランザクションのパラメータを取得することにする。
Cソフトウェアでは、標準入出力を使用する。この場合の標準入出力にはシリアルが割り当てられている。そこで、”SDKでstdio.h の関数を使う手順”を参考にxil_printf()とgetc()を使用した。
シリアル出力を見る手段としては、TeraTermを使用した。シリアルの設定値はデフォルトの9600bps, 1stop bit, no parity を使用している。TeraTermの設定メニューの端末の設定を下に示す。
AXI_P_Monitor_19_120605.png

Cソフトウェアのaxi_perf_mon_test.cの全ソースを下に示す。

/* * axi_perf_mon_test.c * *  Created on: 2012/05/31 *      Author: Masaaki */

#include "xbasic_types.h"
#include "xio.h"
#include "mb_interface.h"
#include "xparameters.h"
#include "stdio.h"

// AXI Performance Monitor define
#define AXIPM_CONTROL_REGISTER                XPAR_AXI_PERF_MON_0_BASEADDR
#define AXIPM_READ_LATENCY_A_REG            XPAR_AXI_PERF_MON_0_BASEADDR+0x0004
#define AXIPM_READ_LATENCY_B_REG            XPAR_AXI_PERF_MON_0_BASEADDR+0x0008
#define AXIPM_READ_LATENCY_C_REG            XPAR_AXI_PERF_MON_0_BASEADDR+0x000C
#define AXIPM_READ_LATENCY_D_REG            XPAR_AXI_PERF_MON_0_BASEADDR+0x0010
#define AXIPM_WRITE_LATENCY_A_REG            XPAR_AXI_PERF_MON_0_BASEADDR+0x0014
#define AXIPM_WRITE_LATENCY_B_REG            XPAR_AXI_PERF_MON_0_BASEADDR+0x0018
#define AXIPM_METRIC_SELECTOR_REG            XPAR_AXI_PERF_MON_0_BASEADDR+0x0024
#define AXIPM_SAMPLE_INTERVAL_MSB            XPAR_AXI_PERF_MON_0_BASEADDR+0x0028
#define AXIPM_SAMPLE_INTERVAL_LSB            XPAR_AXI_PERF_MON_0_BASEADDR+0x002C
#define AXIPM_SAMPLE_INTERVAL_CONTROL_REG    XPAR_AXI_PERF_MON_0_BASEADDR+0x0030    
#define AXIPM_GLOBL_INTERRPUT_ENABLE_REG    XPAR_AXI_PERF_MON_0_BASEADDR+0x0040
#define AXIPM_INTERRUPT_ENABLE_REG            XPAR_AXI_PERF_MON_0_BASEADDR+0x0044
#define AXIPM_INTERRUPT_STATUS_REG            XPAR_AXI_PERF_MON_0_BASEADDR+0x0048
#define AXIPM_METRIC_COUNTER_0_H            XPAR_AXI_PERF_MON_0_BASEADDR+0x1000
#define AXIPM_METRIC_COUNTER_0_L            XPAR_AXI_PERF_MON_0_BASEADDR+0x1004
#define AXIPM_METRIC_COUNTER_1_H            XPAR_AXI_PERF_MON_0_BASEADDR+0x1008
#define AXIPM_METRIC_COUNTER_1_L            XPAR_AXI_PERF_MON_0_BASEADDR+0x100C
#define AXIPM_METRIC_COUNTER_2_H            XPAR_AXI_PERF_MON_0_BASEADDR+0x1010
#define AXIPM_METRIC_COUNTER_2_L            XPAR_AXI_PERF_MON_0_BASEADDR+0x1014
#define AXIPM_METRIC_COUNTER_3_H            XPAR_AXI_PERF_MON_0_BASEADDR+0x1018
#define AXIPM_METRIC_COUNTER_3_L            XPAR_AXI_PERF_MON_0_BASEADDR+0x101C
#define AXIPM_METRIC_COUNTER_4_H            XPAR_AXI_PERF_MON_0_BASEADDR+0x1020
#define AXIPM_METRIC_COUNTER_4_L            XPAR_AXI_PERF_MON_0_BASEADDR+0x1024
#define AXIPM_METRIC_COUNTER_5_H            XPAR_AXI_PERF_MON_0_BASEADDR+0x1028
#define AXIPM_METRIC_COUNTER_5_L            XPAR_AXI_PERF_MON_0_BASEADDR+0x102C
#define AXIPM_METRIC_COUNTER_6_H            XPAR_AXI_PERF_MON_0_BASEADDR+0x1030
#define AXIPM_METRIC_COUNTER_6_L            XPAR_AXI_PERF_MON_0_BASEADDR+0x1034
#define AXIPM_METRIC_COUNTER_7_H            XPAR_AXI_PERF_MON_0_BASEADDR+0x1038
#define AXIPM_METRIC_COUNTER_7_L            XPAR_AXI_PERF_MON_0_BASEADDR+0x103C
#define AXIPM_METRIC_COUNTER_8_H            XPAR_AXI_PERF_MON_0_BASEADDR+0x1040
#define AXIPM_METRIC_COUNTER_8_L            XPAR_AXI_PERF_MON_0_BASEADDR+0x1044
#define AXIPM_METRIC_COUNTER_9_H            XPAR_AXI_PERF_MON_0_BASEADDR+0x1048
#define AXIPM_METRIC_COUNTER_9_L            XPAR_AXI_PERF_MON_0_BASEADDR+0x104C
#define AXIPM_GLOBL_CLOCK_COUNTER_3            XPAR_AXI_PERF_MON_0_BASEADDR+0x0800
#define AXIPM_GLOBL_CLOCK_COUNTER_2            XPAR_AXI_PERF_MON_0_BASEADDR+0x0804
#define AXIPM_GLOBL_CLOCK_COUNTER_1            XPAR_AXI_PERF_MON_0_BASEADDR+0x0808
#define AXIPM_GLOBL_CLOCK_COUNTER_0            XPAR_AXI_PERF_MON_0_BASEADDR+0x080C
#define AXIPM_SAMPLED_METRIC_COUNTER_0_H    XPAR_AXI_PERF_MON_0_BASEADDR+0x2000
#define AXIPM_SAMPLED_METRIC_COUNTER_0_L    XPAR_AXI_PERF_MON_0_BASEADDR+0x2004
#define AXIPM_SAMPLED_METRIC_COUNTER_1_H    XPAR_AXI_PERF_MON_0_BASEADDR+0x2008
#define AXIPM_SAMPLED_METRIC_COUNTER_1_L    XPAR_AXI_PERF_MON_0_BASEADDR+0x200C
#define AXIPM_SAMPLED_METRIC_COUNTER_2_H    XPAR_AXI_PERF_MON_0_BASEADDR+0x2010
#define AXIPM_SAMPLED_METRIC_COUNTER_2_L    XPAR_AXI_PERF_MON_0_BASEADDR+0x2014
#define AXIPM_SAMPLED_METRIC_COUNTER_3_H    XPAR_AXI_PERF_MON_0_BASEADDR+0x2018
#define AXIPM_SAMPLED_METRIC_COUNTER_3_L    XPAR_AXI_PERF_MON_0_BASEADDR+0x201C
#define AXIPM_SAMPLED_METRIC_COUNTER_4_H    XPAR_AXI_PERF_MON_0_BASEADDR+0x2020
#define AXIPM_SAMPLED_METRIC_COUNTER_4_L    XPAR_AXI_PERF_MON_0_BASEADDR+0x2024
#define AXIPM_SAMPLED_METRIC_COUNTER_5_H    XPAR_AXI_PERF_MON_0_BASEADDR+0x2028
#define AXIPM_SAMPLED_METRIC_COUNTER_5_L    XPAR_AXI_PERF_MON_0_BASEADDR+0x202C
#define AXIPM_SAMPLED_METRIC_COUNTER_6_H    XPAR_AXI_PERF_MON_0_BASEADDR+0x2030
#define AXIPM_SAMPLED_METRIC_COUNTER_6_L    XPAR_AXI_PERF_MON_0_BASEADDR+0x2034
#define AXIPM_SAMPLED_METRIC_COUNTER_7_H    XPAR_AXI_PERF_MON_0_BASEADDR+0x2038
#define AXIPM_SAMPLED_METRIC_COUNTER_7_L    XPAR_AXI_PERF_MON_0_BASEADDR+0x203C
#define AXIPM_SAMPLED_METRIC_COUNTER_8_H    XPAR_AXI_PERF_MON_0_BASEADDR+0x2040
#define AXIPM_SAMPLED_METRIC_COUNTER_8_L    XPAR_AXI_PERF_MON_0_BASEADDR+0x2044
#define AXIPM_SAMPLED_METRIC_COUNTER_9_H    XPAR_AXI_PERF_MON_0_BASEADDR+0x2048
#define AXIPM_SAMPLED_METRIC_COUNTER_9_L    XPAR_AXI_PERF_MON_0_BASEADDR+0x204C

// MICROBLAZE_INTC define
#define MICROBLAZE_0_INTC_ISR        XPAR_MICROBLAZE_0_INTC_BASEADDR        // Interrupt Status Register
#define MICROBLAZE_0_INTC_IPR        XPAR_MICROBLAZE_0_INTC_BASEADDR+0x4    // Interrupt Pending Register
#define MICROBLAZE_0_INTC_IER        XPAR_MICROBLAZE_0_INTC_BASEADDR+0x8    // Interrupt Enable Register
#define MICROBLAZE_0_INTC_IAR        XPAR_MICROBLAZE_0_INTC_BASEADDR+0xC    // Interrupt Acknowledge Register
#define MICROBLAZE_0_INTC_SIE        XPAR_MICROBLAZE_0_INTC_BASEADDR+0x10    // Set Interrupt Enable Bits
#define MICROBLAZE_0_INTC_CIE        XPAR_MICROBLAZE_0_INTC_BASEADDR+0x14    // Clear Interrupt Enable Bits
#define MICROBLAZE_0_INTC_IVR        XPAR_MICROBLAZE_0_INTC_BASEADDR+0x18    // Interrupt Vector Register
#define MICROBLAZE_0_INTC_MER        XPAR_MICROBLAZE_0_INTC_BASEADDR+0x1C    // Master Enable Register

// AXI_TIMER define
#define AXI_TIMER_0_TCSR0    XPAR_AXI_TIMER_0_BASEADDR    // Control/Status Register 0
#define AXI_TIMER_0_TLR0    XPAR_AXI_TIMER_0_BASEADDR+0x4    // Load Register 0
#define AXI_TIMER_0_TCR0    XPAR_AXI_TIMER_0_BASEADDR+0x8    // Timer/Counter Register 0
#define AXI_TIMER_0_TCSR1    XPAR_AXI_TIMER_0_BASEADDR+0x10    // Control/Status Register 1
#define AXI_TIMER_0_TLR1    XPAR_AXI_TIMER_0_BASEADDR+0x14    // Load Register 1
#define AXI_TIMER_0_TCR1    XPAR_AXI_TIMER_0_BASEADDR+0x18    // Timer/Counter Register 1

#define ENABLE_ALL_TIMERS                (0x1<<10)
#define ENABLE_PULSE_WIDTH_MODULATION    (0x1<<9)
#define    TIMER_INTERRUPT                    (0x1<<8)
#define ENABLE_TIMER                    (0x1<<7)
#define ENABLE_INTERRUPT                (0x1<<6)
#define LOAD_TIMER                        (0x1<<5)
#define AUTO_RELOAD_HOLD_TIMER            (0x1<<4)
#define ENABLE_EXT_CAPTURE_TRIG            (0x1<<3)
#define ENABLE_EXT_GENERATE_SIG            (0x1<<2)
#define DOWN_UP_COUNT_TIMER                (0x1<<1)
#define TIMER_MODE_CAP_GENE                (0x1)

int interrupt = 0;

void axi_intc_init() {
    *(volatile unsigned int *)(MICROBLAZE_0_INTC_IER) = 0x1;    // int0 enable
    *(volatile unsigned int *)(MICROBLAZE_0_INTC_MER) = 0x3;    // IRQ Enable
}

void axi_timer_init(){
    *(volatile unsigned int *)(AXI_TIMER_0_TLR0) = 100000000// 100MHzで1秒
    *(volatile unsigned int *)(AXI_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | LOAD_TIMER; // TLR0へロード
    *(volatile unsigned int *)(AXI_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | ENABLE_TIMER | ENABLE_INTERRUPT | DOWN_UP_COUNT_TIMER; // GenerateモードでDWONカウント、割り込みあり
}

void axi_perf_mon_init(){
    *(volatile unsigned int *)(AXIPM_CONTROL_REGISTER) = 0x303// Reg Reset and Enable
    *(volatile unsigned int *)(AXIPM_CONTROL_REGISTER) = 0x101// Reg and Enable
}

void timer_int_handler(void * arg) {
    interrupt = 1;
}

// 結果表示文字配列の初期化
const char mean_metric[8][10][30] = {
    {"Read Latency Range 1","Read Latency Range 2""Read Latency Range 3","Read Latency Range 4","Read Latency Range 5","Read Latency Range 6","Read Latency Range 7","Read Latency Range 8""Read Latency Range 9","Total Read Latency"},
    {"Write Latency Range 1""Write Latency Range 2","Write Latency Range 3""Write Latency Range 4""Write Latency Range 5""Write Transaction Count","Read Transaction Count","Write Byte Count","Read Byte Count","Total Write Latency"},
    {"Write Transaction Count","Read Transaction Count","Slv_Wr_Idle_Cnt","Mst_Rd_Idle_Cnt","Num_BValids","Num_WLasts","Num_RLasts","Num_Wr_Bursts_Len0","Num_Rd_Bursts_Len0","Total Write Latency"},
    {"Read Latency Range 1","Read Latency Range 2","Read Latency Range 3","Read Latency Range 4","Read Latency Range 5","Read Transaction Count","Num_RLasts","Num_Rd_Bursts_Len0","Read Byte Count","Total Read Latency"},
    {"Write Latency Range 1","Write Latency Range 2","Write Latency Range 3","Write Latency Range 4","Write Latency Range 5","Write Transaction Count","Num_WLasts","Num_BValids","Write Byte Count","Total Write Latency"},
    {"Write Transaction Count","Read Transaction Count","Slv_Wr_Idle_Cnt","Mst_Rd_Idle_Cnt","Num_BValids","Num_WLasts","Num_RLasts","Num_BValids","Num_Rd_Bursts_Len0","Total Write Latency"},
    {"Transfer Cycle Count","Packet Count","Transfer Cycle Count","Mst_Idle_Cnt","Slv_Idle_Cnt","Packet Count","Transfer Cycle Count","Data Byte Count","Position Byte Count","Null Byte Count"},
    {"Transfer Cycle Count","Packet Count","Transfer Cycle Count","Mst_Idle_Cnt","Slv_Idle_Cnt","Packet Count","Transfer Cycle Count","Data Byte Count","Position Byte Count","Null Byte Count"}
};

void interrupt_clear(){
    *(volatile unsigned int *)(AXI_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | ENABLE_TIMER | ENABLE_INTERRUPT | DOWN_UP_COUNT_TIMER | TIMER_INTERRUPT;    // 割り込みクリア
    *(volatile unsigned int *)(MICROBLAZE_0_INTC_IAR) = 0x1;    // int0 clear

    *(volatile unsigned int *)(AXI_TIMER_0_TLR0) = 100000000// 1秒 1000,000,000ns/10ns = 100,000,000
    *(volatile unsigned int *)(AXI_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | LOAD_TIMER; // TLR0へロード、割り込みクリア
    *(volatile unsigned int *)(AXI_TIMER_0_TCSR0) = ENABLE_ALL_TIMERS | ENABLE_TIMER | ENABLE_INTERRUPT | DOWN_UP_COUNT_TIMER; // GenerateモードでDWONカウント、割り込みあり
}

int main()
{
    unsigned char c,d;
    int j;
    unsigned int metric_reg[10];
    
    axi_timer_init();        // axi_timerの初期化
    axi_intc_init();         // axi_intcの初期化
    
    // 割り込みハンドラ登録、割り込み許可
    microblaze_register_handler(timer_int_handler, (void *) 0);
    microblaze_enable_interrupts();

    for(;;){
        xil_printf("Please input Metric_Set_Sel numbler 0 - 7 \n");
        c = getc(stdin);
        d = getc(stdin); // CRを読み飛ばす
        xil_printf("\n");
        if (c < 0x30 || c > 0x37// 0 ~ 7でないので入力待ち
            continue;
        c = c - 0x30;
        
        // axi_timter割り込み待ち
        interrupt_clear();
        interrupt = 0;
        while(interrupt==0);
        *(volatile unsigned int *)(AXIPM_CONTROL_REGISTER) = 0x303// Reg Reset and Enable
        *(volatile unsigned int *)(AXIPM_METRIC_SELECTOR_REG) = c << 16;
        *(volatile unsigned int *)(AXIPM_CONTROL_REGISTER) = 0x101// Reg Reset and Enable
        interrupt_clear(); // 一度、空読みする
        
        // axi_timter割り込み待ち
        interrupt = 0;
        while(interrupt==0);
        // Metric Register の読み出し
        metric_reg[0] = *(volatile unsigned int *)(AXIPM_METRIC_COUNTER_0_L);
        metric_reg[1] = *(volatile unsigned int *)(AXIPM_METRIC_COUNTER_1_L);
        metric_reg[2] = *(volatile unsigned int *)(AXIPM_METRIC_COUNTER_2_L);
        metric_reg[3] = *(volatile unsigned int *)(AXIPM_METRIC_COUNTER_3_L);
        metric_reg[4] = *(volatile unsigned int *)(AXIPM_METRIC_COUNTER_4_L);
        metric_reg[5] = *(volatile unsigned int *)(AXIPM_METRIC_COUNTER_5_L);
        metric_reg[6] = *(volatile unsigned int *)(AXIPM_METRIC_COUNTER_6_L);
        metric_reg[7] = *(volatile unsigned int *)(AXIPM_METRIC_COUNTER_7_L);
        metric_reg[8] = *(volatile unsigned int *)(AXIPM_METRIC_COUNTER_8_L);
        metric_reg[9] = *(volatile unsigned int *)(AXIPM_METRIC_COUNTER_9_L);
        for(j=0; j<10; j=j++)
            xil_printf("%s = %d/sec\n", mean_metric[c][j], metric_reg[j]);
        xil_printf("\n");
        interrupt_clear(); 
    }
        
    return 0;
}


これをSDKでコンパイル実行するとTeraTermに”Please input Metric_Set_Sel numbler 0 - 7”と表示が出るので、Metric Selector Register(C_BASEADDR + 0x0024)のMetric_Set_Selの番号を入力すると、対応するAXI4バスのパラメータが出てくるという寸法だ。
TeraTermの表示を下に示す。これは 3を入力して、Read Transaction のパラメータを数回取っている。
AXI_P_Monitor_20_120605.png

Read Transaction Countは常に 5/sec になっている。これは0.2秒ごとにRead Transaction を行なっているからだ。一方、Read Byte Countの値は毎回違っている。これは、M系列による擬似乱数でバースト数を決定しているためだ。
次にWrite Transaction のパラータを下に示す。WriteもRead同様になっている。
AXI_P_Monitor_21_120605.png

これで、AXI4バスの各パラータを一応モニタすることができるようになった。

最後に現在のAXI Performance Monitorで観測しているcdctest_axi_master_v1_00_aの概要を再度示す。
cdctest_axi_master_v1_00_aは、キャラクタ・ディスプレイ・コントローラAXI4スレーブIPを駆動するAXI4マスタIPとして作られている。仕様や作成過程については下のブログ記事を参照のこと。
AXI4マスタIPの作製(仕様の策定)
AXI4マスタIPの作製2(単体シミュレーション)"
"AXI4マスタIPの作製3(インプリメント)"

  1. 2012年06月05日 05:44 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0