FC2カウンター FPGAの部屋 Co-design
fc2ブログ

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

FPGAの部屋

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

AXI4 Master アクセスのラプラシアン・フィルタ IP9(できた。完成)

AXI4 Master アクセスのラプラシアン・フィルタ IP8(インプリメント2、実機テスト)”の続き。

前回、バグが見つかったので、修正した。

・論理合成、インプリメント、ビットストリームの生成をProject Navigator で行い、ハードウェアをSDKにエクスポートして、SDKを立ちあげた。

・SDKでBOOT.binを作製して、SDカードに書き込んだ。

・SDカードをZedBoardに入れて、電源ON

・SDKで、lap_filter_axim の Run Configuration を作製して起動した。

うまく表示されました。完成。。。
axi4m_lap_filter_36_131202.jpg

トータルの実行時間は 23.6msec 程度だった。(起動しているソフトウェアは、lap_filter_axim.elf)
最適化したソフトウェア laplacian_filter.elf の実行時間は約398msec だったので、398 / 23.6 ≒ 16.9倍、高速になった。
axi4m_lap_filter_37_131202.png

フレームレートの16.7msec には足りないが、23.6msec は、ソフトウェア実行時間、全てのトータルの時間だ。

次に、ハードウェア処理のラプラシアン・フィルタ部分のみの経過時間を計測した。
axi4m_lap_filter_38_131202.png

約 10.1msec となった。これだと、フレームレートよりも速くなり、十分に仕様を満足する。これで、C言語で生成できる形式でのラプラシアン・フィルタのハードウェアのオフロードは終了とする。この様なハードウェアをVivado HLSでCソフトウェアで簡単に出力できるととっても良いと思う。今回のは作るのに時間が掛かってしまったが、HLSで合成できればとっても良いと思う。

最後に、lap_filter_axim.c のCソースを貼っておく。

// lap_filter_axim.c
// AXI4 Master のVivado HLS出力ハードウェア・バージョン
// RGBをYに変換後にラプラシアンフィルタを掛ける。
// ピクセルのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 2013/10/15

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <ctype.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/kernel.h>
#include "lap_fil_axim_uty.h"

#define LAP_FILTER_AXIM_HW_ADDRESS    0x4a000000    // 自作ラプラシアン・フィルタのAXI4 Masterハードウェアのアドレス

#define HORIZONTAL_PIXEL_WIDTH    800
#define VERTICAL_PIXEL_WIDTH    600
#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

#define BUFSIZE    1024

#define MEASURE_COUNT    5000

int conv_rgb2y(int rgb);
int chkhex(char *str);
volatile unsigned *setup_io(off_t mapped_addr, unsigned int *buf_addr);

int main()
{
    FILE *fd;
    unsigned int bitmap_dc_reg_addr;
    unsigned int read_num;
    volatile unsigned *bm_disp_cnt_reg;
    unsigned int fb_addr, next_frame_addr;
    int return_val;
    struct timeval start_time, end_time;
    unsigned int rmmap_cnt=0, wmmap_cnt=0;
    unsigned int lap_fil_hw, *lap_fil_hw_addr;
    char buf[BUFSIZE], *token;
    unsigned int val;
    unsigned int bitmap_buf;

    gettimeofday(&start_time, NULL);    // プログラム起動時の時刻を記録

    // fb_start_addr.txt の内容をパイプに入れる
    memset(buf, '\0'sizeof(buf)); // buf すべてに\0 を入れる
    // fb_start_addr.txt を開く
    fd = popen("cat /Apps/fb_start_addr.txt""r");
    if (fd != NULL){
        read_num = fread(buf, sizeof(unsigned char), BUFSIZE, fd);
        if (read_num > 0){
            sscanf(buf, "%x\n", &fb_addr);
        }
    }
    pclose(fd);

    // ラプラシアンフィルタの結果を入れておくフレーム・バッファ
    next_frame_addr = ((fb_addr + (ALL_PIXEL_VALUE*4)) & (~(int)(PAGE_SIZE-1))) + PAGE_SIZE;

    // Vivado HLS で作製したラプラシアン・フィルタIPのアドレスを取得
    lap_fil_hw_addr = setup_io((off_t)LAP_FILTER_AXIM_HW_ADDRESS, &lap_fil_hw);

    lap_fil_initialize(lap_fil_hw_addr);    // ラプラシアン・フィルタIPの初期化とap_start
    lap_fil_env_set(lap_fil_hw_addr, fb_addr, next_frame_addr);    // ラプラシアン・フィルタ環境セット

    gettimeofday(&start_time, NULL);    // プログラム起動時の時刻を記録
    // ラプラシアン・フィルタAXI4 Master IPスタート
    return_val = laplacian_fil_hw(lap_fil_hw_addr);
    gettimeofday(&end_time, NULL);

    if (end_time.tv_usec < start_time.tv_usec) {
        printf("total time = %d.%6.6d sec\n", end_time.tv_sec - start_time.tv_sec - 11000000 + end_time.tv_usec - start_time.tv_usec);
    }
    else {
        printf("total time = %d.%6.6d sec\n", end_time.tv_sec - start_time.tv_sec, end_time.tv_usec - start_time.tv_usec);
    }
    printf("return Value = %d\n", return_val);
    
    munmap((unsigned int *)lap_fil_hw_addr, BLOCK_SIZE);
    free((unsigned int *)lap_fil_hw);

    // bitmap-disp-cntrler-axi-master のアドレスを取得
    memset(buf, '\0'sizeof(buf)); // buf すべてに\0 を入れる
    // ls /sys/devices/axi.0 の内容をパイプに入れる
    fd = popen("ls /sys/devices/axi.0""r");
    if (fd != NULL){
        read_num = fread(buf, sizeof(unsigned char), BUFSIZE, fd);
        if (read_num > 0){
            token = buf;
            if ((token=strtok(token, ".\n")) != NULL){
                do {
                    if (chkhex(token)){ // 16進数
                        sscanf(token, "%x", &val);
                    } else {
                        if (strcmp(token, "bitmap-disp-cntrler-axi-master") == 0)
                            bitmap_dc_reg_addr = val;
                    }
                }while((token=strtok(NULL, ".\n")) != NULL);
            }
        }
    }
    pclose(fd);

    // ラプラシアンフィルタの掛かった画像のスタートアドレスを bitmap-disp-cntrler-axi-master にセット
    bm_disp_cnt_reg = setup_io((off_t)bitmap_dc_reg_addr, &bitmap_buf);
    *bm_disp_cnt_reg = next_frame_addr;

    munmap((unsigned int *)bm_disp_cnt_reg, BLOCK_SIZE);
    free((unsigned int *)bitmap_buf);

    /*gettimeofday(&end_time, NULL);    if (end_time.tv_usec < start_time.tv_usec) {        printf("total time = %d.%6.6d sec\n", end_time.tv_sec - start_time.tv_sec - 1, 1000000 + end_time.tv_usec - start_time.tv_usec);    }    else {        printf("total time = %d.%6.6d sec\n", end_time.tv_sec - start_time.tv_sec, end_time.tv_usec - start_time.tv_usec);    }    return(0);*/
}


// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
    int r, g, b, y_f;
    int y;

    b = rgb & 0xff;
    g = (rgb>>8) & 0xff;
    r = (rgb>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
    y = y_f >> 8// 256で割る

    return(y);
}

//
// Set up a memory regions to access GPIO
//
volatile unsigned *setup_io(off_t mapped_addr, unsigned int *buf_addr)
// void setup_io()
{
    int  mem_fd;
    char *gpio_mem, *gpio_map;

   /* open /dev/mem */
   if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
      printf("can't open /dev/mem \n");
      printf("mapped_addr = %x\n", mapped_addr);
      exit (-1);
   }

   /* mmap GPIO */

   // Allocate MAP block
   if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
      printf("allocation error \n");
      exit (-1);
   }
    *buf_addr = gpio_mem;    // mallocしたアドレスをコピー

   // Make sure pointer is on 4K boundary
   if ((unsigned long)gpio_mem % PAGE_SIZE)
     gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE);

   // Now map it
   gpio_map = (unsigned char *)mmap(
      (caddr_t)gpio_mem,
      BLOCK_SIZE,
      PROT_READ|PROT_WRITE,
      MAP_SHARED|MAP_FIXED,
      mem_fd,
      mapped_addr
   );

   if ((long)gpio_map < 0) {
      printf("mmap error %d\n", (int)gpio_map);
      printf("mapped_addr = %x\n", mapped_addr);
      exit (-1);
   }

   close(mem_fd); // /dev/mem のクローズ

   // Always use volatile pointer!
   // gpio = (volatile unsigned *)gpio_map;
   return((volatile unsigned *)gpio_map);

// setup_io

// 文字列が16進数かを調べる
int chkhex(char *str){
    while (*str != '\0'){
        if (!isxdigit(*str))
            return 0;
        str++;
    }
    return 1;
}


(追加)
ランダム遅延なしのシミュレーション波形を下に示す。大体、10msec で終了していて、実機テストの時の値と合う。つまり、ほとんどAXIバスでのWaitは無いということだと思う。
axi4m_lap_filter_39_131202.png

ChipScope の波形を見ても、Write, Read共に、下のようにほとんどWaitがない。
axi4m_lap_filter_40_131202.png

axi4m_lap_filter_41_131202.png

やはりReadの方が、DDR3 SDRAMからRead するレイテンシがあるので、遅くなるようだ。

(2013/12/03:追記)
変更した、lap_fil_axim_uty.c と lap_fil_axim_uty.h を貼っておきます。
lap_fil_axim_uty.c です。

/* * lap_fil_axim_uty.c * *  Created on: 2013/10/15 *      Author: Masaaki */

#include "xlap_filter_axim_hw.h"

#define AP_START_BIT_POS        1    // ap_start のビット位置 bit0
#define AP_DONE_BIT_POS            2    // ap_done のビット位置 bit1
#define AP_AUTO_RESTART_BIT_POS    0x80    // auto_restart のビット位置 bit7
#define VLD_BIT_POS                1

void lap_fil_initialize(unsigned int *lap_fil_hw_addr)
{
    *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_AP_CTRL) = 0;
    *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_GIE) = 0;
    *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_IER) = 1;    // ap_done=1
    *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_CTRL) = 0;
    *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_CTRL) = 0;
}

// ラプラシアン・フィルタ環境セット
int lap_fil_env_set(unsigned int *lap_fil_hw_addr, unsigned int cam_fb, unsigned int lap_fb)
{
    int ap_status, ap_done;
    int ap_return;
    int cam_fb_read, lap_fb_read;
    int cam_addr_vld, lap_addr_vld;

    *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_DATA) = cam_fb;
    *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_DATA) = lap_fb;
    cam_fb_read = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_DATA);
    lap_fb_read = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_DATA);

     // vld enable
    *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_CAM_ADDR_CTRL) = VLD_BIT_POS;
    *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_LAP_ADDR_CTRL) = VLD_BIT_POS;
}

// ラプラシアン・フィルタ・スタート
int laplacian_fil_hw(unsigned int *lap_fil_hw_addr)
{
    int ap_status, ap_done;
    int ap_return;

    // ap_start enable
    *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_AP_CTRL) = AP_START_BIT_POS;

    // wait ap_done
    do{
        ap_status = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_AP_CTRL);
        ap_done = ap_status & AP_DONE_BIT_POS;
    }while(!ap_done);
    
    // ap_return read
    ap_return = *(volatile int *)((unsigned int)lap_fil_hw_addr + (unsigned int)XLAP_FILTER_AXIM_LITES_ADDR_AP_RETURN);
    //printf("ap_return = %d\n", ap_return);
    return(ap_return);
}


lap_fil_axim_uty.h です。


* lap_fil_axim_uty.h
*
* Created on: 2013/10/15
* Author: Masaaki
*/

#ifndef LAP_FIL_AXIM_UTY_H_
#define LAP_FIL_AXIM_UTY_H_

void lap_fil_initialize(unsigned int *lap_fil_hw_addr);
int laplacian_fil_hw(unsigned int *lap_fil_hw_addr);
void lap_fil_env_set(unsigned int *lap_fil_hw_addr, unsigned int *cam_fb, unsigned int *lap_fb);

#endif /* LAP_FIL_AXIM_UTY_H_ */

  1. 2013年12月02日 18:15 |
  2. Co-design
  3. | トラックバック:0
  4. | コメント:0

AXI4 Master アクセスのラプラシアン・フィルタ IP8(インプリメント2、実機テスト)

AXI4 Master アクセスのラプラシアン・フィルタ IP7(インプリメント1)”の続き。

・XPSプロジェクトで、Generate Netlistが終了した。今度は、system_lap_filter_axim_0_wapper のLUT使用率が586になっていて良い感じだ。
axi4m_lap_filter_28_131129.png

・Poject Navigator に戻って、論理合成、インプリメント、ビットストリームの生成を行った。成功した。
axi4m_lap_filter_30_131130.png

・FPGA Editor を立ちあげて、lap_filter_axim_0 を見ると、lap_filter_axim_LiteS_if_Uがあった。これで一安心。
axi4m_lap_filter_29_131130.png

・SDKを立ちあげ、SDカードに入れるブートイメージを作製した。

・BOOT.bin をSDカードに入れて、Linuxをブート。

・lap_filte_axim のデバック・コンフィギュレーションを作って、デバック。(手順はかなり省略しています。詳しい手順は、”Vivado HLSで作ったラプラシアン・フィルタAXI4 Master IPを使う2”をどうぞ)

・まずは、ソフトコアで作ったラプラシアン・フィルタ・ソフトウェアを起動して実行した。(詳しくは、”ソフトウエアのプロファイリング4(ハードウェアと同じ方式)”をどうぞ)
axi4m_lap_filter_34_131130.jpg

・lap_filte_axim を実行するソフトウェアを実行すると、下の写真のようになった。
axi4m_lap_filter_35_131130.jpg

・画面の1/4しか、書き込んでいないみたいだ。ショック。。。

・ChipScope Pro を仕掛けておいたので、起動した。下に、WVAILD の立ち上がりでトリガを掛けた時の波形を示す。
axi4m_lap_filter_31_131130.png

・Write Address Channel を拡大してみた。なにかおかしい?
axi4m_lap_filter_32_131130.png

・Read Address Channel を拡大すると理由がわかった。Write Address Channel のアドレス増加ステップがデータバス幅 32/8 = 4 ではなくて、1 だ。
axi4m_lap_filter_33_131130.png

HDLコードの Writeアドレスの増加ステップがおかしかったので、修正を行った。
  1. 2013年11月30日 13:11 |
  2. Co-design
  3. | トラックバック:0
  4. | コメント:0

AXI4 Master アクセスのラプラシアン・フィルタ IP7(インプリメント1)

AXI4 Master アクセスのラプラシアン・フィルタ IP6(line_read_and_y.v と Dual_Port_Memory.v)”の続き。

今回は、MPDファイルやPAOファイルを作って、カスタムIPとしてXPSプロジェクトにADD IPして、ISEから論理合成、インプリメントを行った。

・まずは、XPSプロジェクトに lap_filter_axim IP をADD IPした。
axi4m_lap_filter_16_131126.png

・Portsタブでクロックを接続。
axi4m_lap_filter_17_131126.png

・Addressesタブで、アドレスを 0x4A000000 に設定
axi4m_lap_filter_18_131126.png

・Project Navigator に戻って、論理合成、インプリメント、ビットストリームの生成を行った。成功した。
axi4m_lap_filter_19_131126.png

・試しに、FPGA Editor で見てみると、lap_filter_axim_0 のロジックが大幅に少ない。lap_filter_axim_LiteS_if.v は消去されていた。
axi4m_lap_filter_21_131128.png

・試しにVivado HLS で生成した lap_filter_axim_top_0 を Delete して、XPSプロジェクトで Hardware メニューから Generate Netlistをやってみた。
axi4m_lap_filter_22_131129.png

・Summary を見ると、system_lap_filter_axim_0_wapper に使用リソースが少ない。
axi4m_lap_filter_23_131129.png

・system_lap_filter_axim_0_wapper をクリックすると、XSTのログが出る。そこで、s_axi_lite_wstrb が接続されていないという WARNING が出ていた。
axi4m_lap_filter_24_131129.png

WARNING:Xst:2898 - Port 's_axi_lite_wstrb', unconnected in block instance 'lap_filter_axim_0', is tied to GND.


・Portsタブで確認すると確かに、s_axi_lite_wstrb が接続されていない。
axi4m_lap_filter_25_131129.png

・lap_filter_axim_v2_1_0.mpd ファイルを見ると、s_axi_lite_wstrb の定義が書いていない。これは、ビットマップ・ディスプレイ・コントローラから持ってきたのだが、そこでは、s_axi_lite_wstrb は使っていなかった。

## AXI4 Lite Slave Ports
PORT s_axi_lite_awvalid = AWVALID, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_awready = AWREADY, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_awaddr = AWADDR, DIR = I, VEC = [C_S_AXI_LITE_ADDR_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_wvalid = WVALID, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_wready = WREADY, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_wdata = WDATA, DIR = I, VEC = [C_S_AXI_LITE_DATA_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_bresp = BRESP, DIR = O, VEC = [1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_bvalid = BVALID, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_bready = BREADY, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_arvalid = ARVALID, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_arready = ARREADY, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_araddr = ARADDR, DIR = I, VEC = [C_S_AXI_LITE_ADDR_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_rvalid = RVALID, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_rready = RREADY, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_rdata = RDATA, DIR = O, VEC = [C_S_AXI_LITE_DATA_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_rresp = RRESP, DIR = O, VEC = [1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE


・s_axi_lite_wstrb の定義をMPDファイルに追加した。

## AXI4 Lite Slave Ports
PORT s_axi_lite_awvalid = AWVALID, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_awready = AWREADY, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_awaddr = AWADDR, DIR = I, VEC = [C_S_AXI_LITE_ADDR_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_wvalid = WVALID, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_wready = WREADY, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_wdata = WDATA, DIR = I, VEC = [C_S_AXI_LITE_DATA_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_wstrb = WSTRB, DIR = I, VEC = [((C_S_AXI_LITE_DATA_WIDTH/8)-1):0], ENDIAN = LITTLE, BUS = S_AXI_LITE
PORT s_axi_lite_bresp = BRESP, DIR = O, VEC = [1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_bvalid = BVALID, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_bready = BREADY, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_arvalid = ARVALID, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_arready = ARREADY, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_araddr = ARADDR, DIR = I, VEC = [C_S_AXI_LITE_ADDR_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_rvalid = RVALID, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_rready = RREADY, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_rdata = RDATA, DIR = O, VEC = [C_S_AXI_LITE_DATA_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_rresp = RRESP, DIR = O, VEC = [1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE


・Project メニューから Rescan User Repositories を行うと、s_axi_lite_wstrb が見えた。
axi4m_lap_filter_27_131129.png

・これで、もう一度、 Hardware メニューから Generate Netlistを行った。

今、 Generate Netlistを行っている最中です。結果は次回のブログでお知らせします。
  1. 2013年11月29日 04:43 |
  2. Co-design
  3. | トラックバック:0
  4. | コメント:0

AXI4 Master アクセスのラプラシアン・フィルタ IP6(line_read_and_y.v と Dual_Port_Memory.v)

AXI4 Master アクセスのラプラシアン・フィルタ IP6(lap_filter_axim_LiteS_if.v のHDLソース)”の続き。

今回は、下位モジュールの line_read_and_y.v と Dual_Port_Memory.v を貼っておく。

line_read_and_y.v は、HORIZONTAL_PIXELS 分のピクセルデータを start_addr から AXI4 Master Readして、RGB - Y変換を行い、y_data へ出力する下位モジュールだ。
line_read_and_y.v を下に貼る。

`default_nettype none

//
// line_read_and_y.v
// HORIZONTAL_PIXELS 分のピクセルデータを start_addr から AXI4 Master Read する
// RGB - Y変換を行い、y_data へ出力する
// 2013/11/17
//

module line_read_and_y #(
    parameter    integer    C_M_AXI_ADDR_WIDTH        = 32,
    parameter    integer    C_M_AXI_DATA_WIDTH        = 32,
    parameter     integer    HORIZONTAL_PIXELS        = 800
)
(
    input    wire                                clk,
    input    wire                                reset,
    input    wire    [C_M_AXI_ADDR_WIDTH-1:0]    start_addr,
    input    wire                                start,
    output    reg                                    done,
    output    reg        [7:0]                        y_data,
    output    reg                                    y_data_valid,

    output    wire                                read_adfifo_wr_ena,
    output    reg        [C_M_AXI_ADDR_WIDTH-1:0]    read_adfifo_addr,
    output    reg        [8-1:0]                        read_adfifo_arlen,
    input    wire                                read_adfifo_full,

    output    wire                                 read_fifo_rd_ena,
    input    wire    [C_M_AXI_DATA_WIDTH-1:0]    read_fifo_read_data,
    input    wire                                read_fifo_empty_n,
    input    wire                                read_fifo_almost_empty_n
);

    // Beyond Circuts, Constant Function in Verilog 2001を参照しました
    // http://www.beyond-circuits.com/wordpress/2008/11/constant-functions/
    function integer log2;
        input integer addr;
        begin
            addr = addr - 1;
            for (log2=0; addr>0; log2=log2+1)
                addr = addr >> 1;
        end
    endfunction

    reg        [log2(HORIZONTAL_PIXELS)-1:0]    h_addr_cnt;

    parameter     IDLE_READ_ADDR =    1'b0,
                READ_ADDR_ACTIVE =     1'b1;
    reg        read_addr_req_cs;
    wire    [log2(HORIZONTAL_PIXELS)-1:0]    BURST_LIMIT_VAL = 256;
    wire    [log2(HORIZONTAL_PIXELS)-1:0]    ONE = 1;
    reg        op_state;
    reg        [log2(HORIZONTAL_PIXELS)-1:0]    y_data_cnt;


    // start が来たら op_state を1にする。全部のReadデータを受け取った時に0にする
    always @(posedge clk) begin : proc_op_state
       if(reset) begin
            op_state <= 1'b0;
       end else begin
               if (start)
                   op_state <= 1'b1;
               else if (y_data_cnt==ONE && y_data_valid==1'b1)
                   op_state <= 1'b0;
       end
    end

    // Read Address Transaction State Machine
    always @(posedge clk) begin : proc_Read_Addr_Tran_SM
       if(reset) begin
            read_addr_req_cs <= IDLE_READ_ADDR;
       end else begin
               case (read_addr_req_cs)
                   IDLE_READ_ADDR :
                       if (read_adfifo_full==1'b0 && h_addr_cnt!=0 && op_state==1'b1)
                           read_addr_req_cs <= READ_ADDR_ACTIVE;
                   READ_ADDR_ACTIVE :
                       read_addr_req_cs <= IDLE_READ_ADDR;

                  default : /* default */;
               endcase
       end
    end
    assign read_adfifo_wr_ena = (read_addr_req_cs==READ_ADDR_ACTIVE) ? 1'b1 : 1'b0;

    // h_addr_cnt の処理
    always @(posedge clk) begin : proc_h_addr_cnt
       if(reset) begin
            h_addr_cnt <= HORIZONTAL_PIXELS;
            read_adfifo_arlen <= 8'd0;
       end else begin
               if (start) begin
                   h_addr_cnt <= HORIZONTAL_PIXELS;
            end else if (h_addr_cnt!=0 && read_addr_req_cs==IDLE_READ_ADDR && read_adfifo_full==1'b0 && op_state==1'b1) begin
                if (h_addr_cnt>=BURST_LIMIT_VAL) begin
                    h_addr_cnt <= h_addr_cnt - BURST_LIMIT_VAL;
                    read_adfifo_arlen <= 8'd255;
                end else begin
                    h_addr_cnt <= 0;
                    read_adfifo_arlen <= h_addr_cnt[7:0] - 8'd1;
                end
            end
       end
    end

    // read_adfifo_addr の処理
    always @(posedge clk) begin : proc_read_adfifo_addr
       if(reset) begin
            read_adfifo_addr <= 0;
       end else begin
               if (start)
                   read_adfifo_addr <= start_addr;
            else if (read_addr_req_cs == READ_ADDR_ACTIVE)
                read_adfifo_addr <= read_adfifo_addr + (read_adfifo_arlen+8'd1)*(C_M_AXI_DATA_WIDTH/8);
       end
    end

    // RGBからYへの変換
    // RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
    // 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
    // "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
    always @(posedge clk) begin : proc_RGB2Y
        reg [15:0]    y_f;
        reg [7:0]    b, g, r;

       if(reset) begin
            y_data <= 8'd0;
       end else begin
               r = read_fifo_read_data[23:16];
               g = read_fifo_read_data[15:0];
               b = read_fifo_read_data[7:0];

               y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
               y_data <= y_f[15:8];    // 256で割る
       end
    end

    // y_data_valid の処理
    always @(posedge clk) begin : proc_y_data_valid
       if(reset) begin
            y_data_valid <= 1'b0;
       end else begin
            if (read_fifo_empty_n)
                y_data_valid <= 1'b1;
            else
                y_data_valid <= 1'b0;
       end
    end

    assign read_fifo_rd_ena = 1'b1;

    // y_data のカウント
    always @(posedge clk) begin : proc_y_data_cnt
       if(reset) begin
            y_data_cnt <= HORIZONTAL_PIXELS;
       end else begin
               if (op_state==1'b1 && y_data_valid==1'b1 && y_data_cnt!=0)
                   y_data_cnt <= y_data_cnt - ONE;
               else if (start)
                   y_data_cnt <= HORIZONTAL_PIXELS;
       end
    end

    // done の処理
    always @(posedge clk) begin : proc_done
       if(reset) begin
            done <= 1'b0;
       end else begin
               if (y_data_cnt==ONE && y_data_valid==1'b1)
                   done <= 1'b1;
               else
                   done <= 1'b0;
       end
    end
endmodule

`default_nettype wire


次は、 Dual_Port_Memory.v だが、これは、”XST に Dual Port Memory を推論させる (Verilog HDL)”の Dual_Port_Memory_test.v と同じだが、モジュール名を変更したので、もう一度、貼っておく。

`default_nettype none

module Dual_Port_Memory #(
  parameter integer C_MEMORY_SIZE =   1024, // Word Memory Size (not byte)
  parameter integer DATA_BUS_WIDTH =  32    // RAM Data Width
)
(
    input  wire clk,
    input  wire we,
    input  wire [log2(C_MEMORY_SIZE)-1:0]   waddr,
    input  wire [log2(C_MEMORY_SIZE)-1:0]   raddr,
    input  wire [DATA_BUS_WIDTH-1:0]  din,
    output reg  [DATA_BUS_WIDTH-1:0]  dout
);

    // Beyond Circuts, Constant Function in Verilog 2001を参照しました
    // http://www.beyond-circuits.com/wordpress/2008/11/constant-functions/
    function integer log2;
        input integer addr;
        begin
            addr = addr - 1;
            for (log2=0; addr>0; log2=log2+1)
                addr = addr >> 1;
        end
    endfunction

    reg  [DATA_BUS_WIDTH-1:0]  ram  [0:C_MEMORY_SIZE-1];

    initial begin : memory_initialize
        integer i;
        for (i=0; i<C_MEMORY_SIZE; i=i+1)
            ram[i] = 0;
    end

    always  @(posedge  clk) begin
        if  (we)
            ram[waddr]  <=  din;

        dout  <=  ram[raddr];
    end

endmodule

`default_nettype wire

  1. 2013年11月28日 05:04 |
  2. Co-design
  3. | トラックバック:0
  4. | コメント:0

AXI4 Master アクセスのラプラシアン・フィルタ IP6(lap_filter_axim_LiteS_if.v のHDLソース)

AXI4 Master アクセスのラプラシアン・フィルタ IP5(lap_filter_axim.v のHDLソース)”の続き。

今回は、Vivado HLSでラプラシアン・フィルタ AXI Master IP を作った際のAXI4 Lite Slave モジュール lap_filter_axim_LiteS_if.v を貼っておく。

// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2013.3
// Copyright (C) 2013 Xilinx Inc. All rights reserved.
// 
// ==============================================================

`timescale 1ns/1ps
module lap_filter_axim_LiteS_if
#(parameter
    C_ADDR_WIDTH = 6,
    C_DATA_WIDTH = 32
)(
    // axi4 lite slave signals
    input  wire                      ACLK,
    input  wire                      ARESETN,
    input  wire [C_ADDR_WIDTH-1:0]   AWADDR,
    input  wire                      AWVALID,
    output wire                      AWREADY,
    input  wire [C_DATA_WIDTH-1:0]   WDATA,
    input  wire [C_DATA_WIDTH/8-1:0] WSTRB,
    input  wire                      WVALID,
    output wire                      WREADY,
    output wire [1:0]                BRESP,
    output wire                      BVALID,
    input  wire                      BREADY,
    input  wire [C_ADDR_WIDTH-1:0]   ARADDR,
    input  wire                      ARVALID,
    output wire                      ARREADY,
    output wire [C_DATA_WIDTH-1:0]   RDATA,
    output wire [1:0]                RRESP,
    output wire                      RVALID,
    input  wire                      RREADY,
    output wire                      interrupt,
    // user signals
    output wire [31:0]               I_cam_addr,
    output wire                      I_cam_addr_ap_vld,
    input  wire                      I_cam_addr_ap_ack,
    output wire [31:0]               I_lap_addr,
    output wire                      I_lap_addr_ap_vld,
    output wire                      I_ap_start,
    input  wire                      O_ap_ready,
    input  wire                      O_ap_done,
    input  wire                      O_ap_idle,
    input  wire [31:0]               O_ap_return
);
//------------------------Address Info-------------------
// 0x00 : Control signals
//        bit 0  - ap_start (Read/Write/COH)
//        bit 1  - ap_done (Read/COR)
//        bit 2  - ap_idle (Read)
//        bit 3  - ap_ready (Read)
//        bit 7  - auto_restart (Read/Write)
//        others - reserved
// 0x04 : Global Interrupt Enable Register
//        bit 0  - Global Interrupt Enable (Read/Write)
//        others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x10 : Control signal of cam_addr
//        bit 0  - cam_addr_ap_vld (Read/Write/COH)
//        bit 1  - cam_addr_ap_ack (Read)
//        others - reserved
// 0x14 : Data signal of cam_addr
//        bit 31~0 - cam_addr[31:0] (Read/Write)
// 0x18 : Control signal of lap_addr
//        bit 0  - lap_addr_ap_vld (Read/Write/SC)
//        others - reserved
// 0x1c : Data signal of lap_addr
//        bit 31~0 - lap_addr[31:0] (Read/Write)
// 0x20 : Data signal of ap_return
//        bit 31~0 - ap_return[31:0] (Read)
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)

//------------------------Parameter----------------------
// address bits
localparam
    ADDR_BITS = 6;

// address
localparam
    ADDR_AP_CTRL         = 6'h00,
    ADDR_GIE             = 6'h04,
    ADDR_IER             = 6'h08,
    ADDR_ISR             = 6'h0c,
    ADDR_CAM_ADDR_CTRL   = 6'h10,
    ADDR_CAM_ADDR_DATA_0 = 6'h14,
    ADDR_LAP_ADDR_CTRL   = 6'h18,
    ADDR_LAP_ADDR_DATA_0 = 6'h1c,
    ADDR_AP_RETURN_0     = 6'h20;

// axi write fsm
localparam
    WRIDLE = 2'd0,
    WRDATA = 2'd1,
    WRRESP = 2'd2;

// axi read fsm
localparam
    RDIDLE = 2'd0,
    RDDATA = 2'd1;

//------------------------Local signal-------------------
// axi write
reg  [1:0]           wstate;
reg  [1:0]           wnext;
reg  [ADDR_BITS-1:0] waddr;
wire [31:0]          wmask;
wire                 aw_hs;
wire                 w_hs;
// axi read
reg  [1:0]           rstate;
reg  [1:0]           rnext;
reg  [31:0]          rdata;
wire                 ar_hs;
wire [ADDR_BITS-1:0] raddr;
// internal registers
wire                 ap_idle;
reg                  ap_done;
wire                 ap_ready;
reg                  ap_start;
reg                  auto_restart;
reg                  gie;
reg  [1:0]           ier;
reg  [1:0]           isr;
reg  [31:0]          _cam_addr;
reg                  _cam_addr_ap_vld;
wire                 _cam_addr_ap_ack;
reg  [31:0]          _lap_addr;
reg                  _lap_addr_ap_vld;
wire [31:0]          ap_return;

//------------------------Body---------------------------
//++++++++++++++++++++++++axi write++++++++++++++++++++++
assign AWREADY = (wstate == WRIDLE);
assign WREADY  = (wstate == WRDATA);
assign BRESP   = 2'b00;  // OKAY
assign BVALID  = (wstate == WRRESP);
assign wmask   = { {8{WSTRB[3]}}, {8{WSTRB[2]}}, {8{WSTRB[1]}}, {8{WSTRB[0]}} };
assign aw_hs   = AWVALID & AWREADY;
assign w_hs    = WVALID & WREADY;

// wstate
always @(posedge ACLK) begin
    if (~ARESETN)
        wstate <= WRIDLE;
    else
        wstate <= wnext;
end

// wnext
always @(*) begin
    case (wstate)
        WRIDLE:
            if (AWVALID)
                wnext = WRDATA;
            else
                wnext = WRIDLE;
        WRDATA:
            if (WVALID)
                wnext = WRRESP;
            else
                wnext = WRDATA;
        WRRESP:
            if (BREADY)
                wnext = WRIDLE;
            else
                wnext = WRRESP;
        default:
            wnext = WRIDLE;
    endcase
end

// waddr
always @(posedge ACLK) begin
    if (aw_hs)
        waddr <= AWADDR[ADDR_BITS-1:0];
end
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++

//++++++++++++++++++++++++axi read+++++++++++++++++++++++
assign ARREADY = (rstate == RDIDLE);
assign RDATA   = rdata;
assign RRESP   = 2'b00;  // OKAY
assign RVALID  = (rstate == RDDATA);
assign ar_hs   = ARVALID & ARREADY;
assign raddr   = ARADDR[ADDR_BITS-1:0];

// rstate
always @(posedge ACLK) begin
    if (~ARESETN)
        rstate <= RDIDLE;
    else
        rstate <= rnext;
end

// rnext
always @(*) begin
    case (rstate)
        RDIDLE:
            if (ARVALID)
                rnext = RDDATA;
            else
                rnext = RDIDLE;
        RDDATA:
            if (RREADY)
                rnext = RDIDLE;
            else
                rnext = RDDATA;
        default:
            rnext = RDIDLE;
    endcase
end

// rdata
always @(posedge ACLK) begin
    if (ar_hs) begin
        rdata <= 1'b0;
        case (raddr)
            ADDR_AP_CTRL: begin
                rdata[0] <= ap_start;
                rdata[1] <= ap_done;
                rdata[2] <= ap_idle;
                rdata[3] <= ap_ready;
                rdata[7] <= auto_restart;
            end
            ADDR_GIE: begin
                rdata <= gie;
            end
            ADDR_IER: begin
                rdata <= ier;
            end
            ADDR_ISR: begin
                rdata <= isr;
            end
            ADDR_CAM_ADDR_CTRL: begin
                rdata[0] <= _cam_addr_ap_vld;
                rdata[1] <= _cam_addr_ap_ack;
            end
            ADDR_CAM_ADDR_DATA_0: begin
                rdata <= _cam_addr[31:0];
            end
            ADDR_LAP_ADDR_CTRL: begin
                rdata[0] <= _lap_addr_ap_vld;
            end
            ADDR_LAP_ADDR_DATA_0: begin
                rdata <= _lap_addr[31:0];
            end
            ADDR_AP_RETURN_0: begin
                rdata <= ap_return[31:0];
            end
        endcase
    end
end
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++

//++++++++++++++++++++++++internal registers+++++++++++++
assign interrupt         = gie & (|isr);
assign I_ap_start        = ap_start;
assign ap_idle           = O_ap_idle;
assign ap_ready          = O_ap_ready;
assign I_cam_addr_ap_vld = _cam_addr_ap_vld;
assign _cam_addr_ap_ack  = I_cam_addr_ap_ack;
assign I_cam_addr        = _cam_addr;
assign I_lap_addr_ap_vld = _lap_addr_ap_vld;
assign I_lap_addr        = _lap_addr;
assign ap_return         = O_ap_return;

// ap_start
always @(posedge ACLK) begin
    if (~ARESETN)
        ap_start <= 1'b0;
    else if (w_hs && waddr == ADDR_AP_CTRL && WSTRB[0] && WDATA[0])
        ap_start <= 1'b1;
    else if (O_ap_ready)
        ap_start <= auto_restart; // clear on handshake/auto restart
end

// ap_done
always @(posedge ACLK) begin
    if (~ARESETN)
        ap_done <= 1'b0;
    else if (O_ap_done)
        ap_done <= 1'b1;
    else if (ar_hs && raddr == ADDR_AP_CTRL)
        ap_done <= 1'b0; // clear on read
end

// auto_restart
always @(posedge ACLK) begin
    if (~ARESETN)
        auto_restart <= 1'b0;
    else if (w_hs && waddr == ADDR_AP_CTRL && WSTRB[0])
        auto_restart <=  WDATA[7];
end

// gie
always @(posedge ACLK) begin
    if (~ARESETN)
        gie <= 1'b0;
    else if (w_hs && waddr == ADDR_GIE && WSTRB[0])
        gie <= WDATA[0];
end

// ier
always @(posedge ACLK) begin
    if (~ARESETN)
        ier <= 1'b0;
    else if (w_hs && waddr == ADDR_IER && WSTRB[0])
        ier <= WDATA[1:0];
end

// isr[0]
always @(posedge ACLK) begin
    if (~ARESETN)
        isr[0] <= 1'b0;
    else if (ier[0] & O_ap_done)
        isr[0] <= 1'b1;
    else if (w_hs && waddr == ADDR_ISR && WSTRB[0])
        isr[0] <= isr[0] ^ WDATA[0]; // toggle on write
end

// isr[1]
always @(posedge ACLK) begin
    if (~ARESETN)
        isr[1] <= 1'b0;
    else if (ier[1] & O_ap_ready)
        isr[1] <= 1'b1;
    else if (w_hs && waddr == ADDR_ISR && WSTRB[0])
        isr[1] <= isr[1] ^ WDATA[1]; // toggle on write
end

// _cam_addr_ap_vld
always @(posedge ACLK) begin
    if (~ARESETN)
        _cam_addr_ap_vld <= 1'b0;
    else if (w_hs && waddr == ADDR_CAM_ADDR_CTRL && WSTRB[0] && WDATA[0])
        _cam_addr_ap_vld <= 1'b1;
    else if (I_cam_addr_ap_ack)
        _cam_addr_ap_vld <= 1'b0; // clear on handshake
end

// _cam_addr[31:0]
always @(posedge ACLK) begin
    if (w_hs && waddr == ADDR_CAM_ADDR_DATA_0)
        _cam_addr[31:0] <= (WDATA[31:0] & wmask) | (_cam_addr[31:0] & ~wmask);
end

// _lap_addr_ap_vld
always @(posedge ACLK) begin
    if (~ARESETN)
        _lap_addr_ap_vld <= 1'b0;
    else if (w_hs && waddr == ADDR_LAP_ADDR_CTRL && WSTRB[0] && WDATA[0])
        _lap_addr_ap_vld <= 1'b1;
    else
        _lap_addr_ap_vld <= 1'b0; // self clear
end

// _lap_addr[31:0]
always @(posedge ACLK) begin
    if (w_hs && waddr == ADDR_LAP_ADDR_DATA_0)
        _lap_addr[31:0] <= (WDATA[31:0] & wmask) | (_lap_addr[31:0] & ~wmask);
end

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++

endmodule


  1. 2013年11月28日 04:53 |
  2. Co-design
  3. | トラックバック:0
  4. | コメント:0

AXI4 Master アクセスのラプラシアン・フィルタ IP5(lap_filter_axim.v のHDLソース)

AXI4 Master アクセスのラプラシアン・フィルタ IP4(シミュレーション2)”の続き。

現在のところの lap_filter_axim.v を貼っておく。この回路の動作を下に示す。

1.画像データのDDR3メモリのアドレスと、ラプラシアン・フィルタ後の画像データのDDR3メモリのアドレスを内部レジスタに AXI4 Lite Slave アクセスでARMプロセッサからレジスタにWriteしてもらう。この行為に依って、ラプラシアン・フィルタ回路が動作する。
2.DDR3 メモリから画像データを1ライン分、AXI4 Master Read Transaction でRead する。
3.ラプラシアン・フィルタを掛けた後に、異なるDDR3 メモリのアドレスに、AXI4 Master Write Transaction でフィルタ後の1ライン分の画像データをWriteする。
3.2.から3.を1フレーム分行う。
4.レジスタのap_done ビットをセットする。


下に、lap_filter_axim.v を示す。(2013/12/02:修正)

`default_nettype none

//
// lap_filter_axim.v
// 2013/11/13 by marsee
//


module lap_filter_axim #(/*autoport*/
    // AXI4 Lite Slave Interface
    parameter integer C_S_AXI_LITE_ADDR_WIDTH       = 9,
    parameter integer C_S_AXI_LITE_DATA_WIDTH       = 32,

    // AXI Master Interface
    parameter integer C_INTERCONNECT_M_AXI_WRITE_ISSUING = 8,
    parameter integer C_M_AXI_THREAD_ID_WIDTH       = 1,
    parameter integer C_M_AXI_ADDR_WIDTH            = 32,
    parameter integer C_M_AXI_DATA_WIDTH            = 32,
    parameter integer C_M_AXI_AWUSER_WIDTH          = 1,
    parameter integer C_M_AXI_ARUSER_WIDTH          = 1,
    parameter integer C_M_AXI_WUSER_WIDTH           = 1,
    parameter integer C_M_AXI_RUSER_WIDTH           = 1,
    parameter integer C_M_AXI_BUSER_WIDTH           = 1,
    parameter [31:0]  C_M_AXI_TARGET                = 32'h00000000,
    parameter integer C_M_AXI_BURST_LEN             = 256,
    parameter integer C_OFFSET_WIDTH                = 32,

    /* Disabling these parameters will remove any throttling.
    The resulting ERROR flag will not be useful */
    parameter integer C_M_AXI_SUPPORTS_WRITE         = 1,
    parameter integer C_M_AXI_SUPPORTS_READ          = 1,

    parameter integer HORIZONTAL_PIXELS             = 800,
    parameter integer VERTICAL_LINES                = 600
)
(
    // Clocks and Reset
    input wire                                      s_axi_lite_aclk,
    input wire                                      M_AXI_ACLK,
    input wire                                      ARESETN,

    ///////////////////////////////
    // AXI4 Lite Slave Interface //
    ///////////////////////////////
    // AXI Lite Write Address Channel
    input   wire                                    s_axi_lite_awvalid,
    output  wire                                    s_axi_lite_awready,
    input   wire    [C_S_AXI_LITE_ADDR_WIDTH-1:0]   s_axi_lite_awaddr,

    // AXI Lite Write Data Channel
    input   wire                                    s_axi_lite_wvalid,
    output  wire                                    s_axi_lite_wready,
    input   wire    [C_S_AXI_LITE_DATA_WIDTH-1:0]   s_axi_lite_wdata,
    input   wire    [C_S_AXI_LITE_DATA_WIDTH/8-1:0] s_axi_lite_wstrb,

    // AXI Lite Write Response Channel
    output  wire    [1:0]                           s_axi_lite_bresp,
    output  wire                                    s_axi_lite_bvalid,
    input   wire                                    s_axi_lite_bready,

    // AXI Lite Read Address Channel
    input   wire                                    s_axi_lite_arvalid,
    output  wire                                    s_axi_lite_arready,
    input   wire    [C_S_AXI_LITE_ADDR_WIDTH-1:0]   s_axi_lite_araddr,

    // AXI Lite Read Data Channel
    output  wire                                    s_axi_lite_rvalid,
    input   wire                                    s_axi_lite_rready,
    output  wire    [C_S_AXI_LITE_DATA_WIDTH-1:0]   s_axi_lite_rdata,
    output  wire    [1:0]                           s_axi_lite_rresp,

    ///////////////////////////////
    // AXI4 Master Interface //
    ///////////////////////////////
    // Master Interface Write Address
    output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]       M_AXI_AWID,
    output wire [C_M_AXI_ADDR_WIDTH-1:0]            M_AXI_AWADDR,
    output wire [8-1:0]                             M_AXI_AWLEN,
    output wire [3-1:0]                             M_AXI_AWSIZE,
    output wire [2-1:0]                             M_AXI_AWBURST,
    output wire                  M_AXI_AWLOCK,
    output wire [4-1:0]                             M_AXI_AWCACHE,
    output wire [3-1:0]                             M_AXI_AWPROT,
    // AXI3 output wire [4-1:0]                  M_AXI_AWREGION,
    output wire [4-1:0]                             M_AXI_AWQOS,
    output wire [C_M_AXI_AWUSER_WIDTH-1:0]          M_AXI_AWUSER,
    output wire                                     M_AXI_AWVALID,
    input  wire                                     M_AXI_AWREADY,

    // Master Interface Write Data
    // AXI3 output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]     M_AXI_WID,
    output wire [C_M_AXI_DATA_WIDTH-1:0]            M_AXI_WDATA,
    output wire [C_M_AXI_DATA_WIDTH/8-1:0]          M_AXI_WSTRB,
    output wire                                     M_AXI_WLAST,
    output wire [C_M_AXI_WUSER_WIDTH-1:0]           M_AXI_WUSER,
    output wire                                     M_AXI_WVALID,
    input  wire                                     M_AXI_WREADY,

    // Master Interface Write Response
    input  wire [C_M_AXI_THREAD_ID_WIDTH-1:0]       M_AXI_BID,
    input  wire [2-1:0]                             M_AXI_BRESP,
    input  wire [C_M_AXI_BUSER_WIDTH-1:0]           M_AXI_BUSER,
    input  wire                                     M_AXI_BVALID,
    output wire                                     M_AXI_BREADY,

    // Master Interface Read Address
    output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]       M_AXI_ARID,
    output wire [C_M_AXI_ADDR_WIDTH-1:0]            M_AXI_ARADDR,
    output wire [8-1:0]                             M_AXI_ARLEN,
    output wire [3-1:0]                             M_AXI_ARSIZE,
    output wire [2-1:0]                             M_AXI_ARBURST,
    output wire [2-1:0]                             M_AXI_ARLOCK,
    output wire [4-1:0]                             M_AXI_ARCACHE,
    output wire [3-1:0]                             M_AXI_ARPROT,
    // AXI3 output wire [4-1:0]          M_AXI_ARREGION,
    output wire [4-1:0]                             M_AXI_ARQOS,
    output wire [C_M_AXI_ARUSER_WIDTH-1:0]          M_AXI_ARUSER,
    output wire                                     M_AXI_ARVALID,
    input  wire                                     M_AXI_ARREADY,

    // Master Interface Read Data
    input  wire [C_M_AXI_THREAD_ID_WIDTH-1:0]       M_AXI_RID,
    input  wire [C_M_AXI_DATA_WIDTH-1:0]            M_AXI_RDATA,
    input  wire [2-1:0]                             M_AXI_RRESP,
    input  wire                                     M_AXI_RLAST,
    input  wire [C_M_AXI_RUSER_WIDTH-1:0]           M_AXI_RUSER,
    input  wire                                     M_AXI_RVALID,
    output wire                                     M_AXI_RREADY,

    // User Signals
    output  wire                                    interrupt,

    // Error Signal
    output  reg                                     write_fifo_overflow
);

    // Beyond Circuts, Constant Function in Verilog 2001
    // http://www.beyond-circuits.com/wordpress/2008/11/constant-functions/
    function integer log2;
        input integer addr;
        begin
            addr = addr - 1;
            for (log2=0; addr>0; log2=log2+1)
                addr = addr >> 1;
        end
    endfunction

    wire [31:0]               I_cam_addr;
    wire                      I_cam_addr_ap_vld;
    reg                       I_cam_addr_ap_ack;
    wire [31:0]               I_lap_addr;
    wire                      I_lap_addr_ap_vld;
    wire                      I_ap_start;
    wire                      O_ap_ready;
    wire                      O_ap_done;
    wire                      O_ap_idle;
    wire [31:0]               O_ap_return;
    reg     lap_addr_ap_vld_hold;

    reg write_adfifo_wr_ena;
    reg [C_M_AXI_ADDR_WIDTH-1:0] write_adfifo_addr;
    reg [7:0] write_adfifo_awlen;
    reg write_fifo_wr_ena;
    wire [31:0] write_fifo_write_data;
    wire [3:0] write_fifo_wstrb;
    wire read_adfifo_wr_ena;
    wire [31:0] read_adfifo_addr;
    wire [7:0] read_adfifo_arlen;
    wire read_fifo_rd_ena;
    reg init_done;
    wire write_adfifo_full;
    wire write_fifo_full;
    wire write_fifo_almost_full;
    wire read_adfifo_full;
    wire [31:0] read_fifo_read_data;
    wire read_fifo_empty_n;
    wire read_fifo_almost_empty_n;
    wire wr_resp_err;

    parameter [2:0] IDLE_MAIN =                     3'b000,
                    LINE_READ_AND_Y_1ST =           3'b001,
                    LINE_READ_AND_Y_2ND =           3'b011,
                    LINE_READ_AND_Y =               3'b010,
                    LAP_FILTER_AND_WRITE =          3'b110,
                    WAIT_AXI_WRITE_TRANSACTION =    3'b111,
                    AP_DONE_ACTIVE =                3'b101;
    reg     [2:0]   main_cs;

    parameter [1:0] IDLE_LINE_READ_AND_Y =      2'b00,
                    LINE_READ_AND_Y_START =     2'b01,
                    LINE_READ_AND_Y_ACTIVE =    2'b11;
    reg     [1:0]   line_read_y_cs;
    reg             line_read_y_start;
    reg     [C_M_AXI_ADDR_WIDTH-1:0]  start_addr;
    wire    line_read_y_done;
    wire    [7:0]   y_data;
    wire            y_data_valid;
    reg     [1:0]   line_buffer_wcount, line_buffer_rcount;
    wire            line_buf0_we, line_buf1_we, line_buf2_we;
    wire    [7:0]   line_buf_dout0, line_buf_dout1, line_buf_dout2;
    reg     [9:0]  line_buf_waddr, line_buf_raddr;
    reg     [7:0]   Xp1Ym1, Xp1Yn, Xp1Yp1;
    reg     [7:0]   XnYm1, XnYn, XnYp1, Xm1Ym1, Xm1Yn, Xm1Yp1;
    reg     [7:0]   lap_filter_out;
    reg     [log2(HORIZONTAL_PIXELS)-1:0]   lap_pixel_count;
    reg     [log2(VERTICAL_LINES)-1:0]      lap_line_count;

    parameter       IDLE_WRITE_ADDR =   1'b0,
                    WRITE_ADDR_ISSUE =  1'b1;
    reg             write_addr_cs;
    reg     [log2(HORIZONTAL_PIXELS)-1:0]   write_addr_count;
    wire            ACLK;
    wire            lap_line_end;
    wire            lap_frame_end;
    wire            write_fifo_empty;


    assign ACLK = M_AXI_ACLK;

    // AXI4 Lite Slave Module
    lap_filter_axim_LiteS_if #(
        .C_ADDR_WIDTH(C_S_AXI_LITE_ADDR_WIDTH),
        .C_DATA_WIDTH(C_S_AXI_LITE_DATA_WIDTH)
    ) lap_filter_axim_LiteS_if_U(
        .ACLK(s_axi_lite_aclk),
        .ARESETN(ARESETN),
        .AWADDR(s_axi_lite_awaddr),
        .AWVALID(s_axi_lite_awvalid),
        .AWREADY(s_axi_lite_awready),
        .WDATA(s_axi_lite_wdata),
        .WSTRB(s_axi_lite_wstrb),
        .WVALID(s_axi_lite_wvalid),
        .WREADY(s_axi_lite_wready),
        .BRESP(s_axi_lite_bresp),
        .BVALID(s_axi_lite_bvalid),
        .BREADY(s_axi_lite_bready),
        .ARADDR(s_axi_lite_araddr),
        .ARVALID(s_axi_lite_arvalid),
        .ARREADY(s_axi_lite_arready),
        .RDATA(s_axi_lite_rdata),
        .RRESP(s_axi_lite_rresp),
        .RVALID(s_axi_lite_rvalid),
        .RREADY(s_axi_lite_rready),
        .interrupt(interrupt),
        .I_cam_addr(I_cam_addr),
        .I_cam_addr_ap_vld(I_cam_addr_ap_vld),
        .I_cam_addr_ap_ack(I_cam_addr_ap_ack),
        .I_lap_addr(I_lap_addr),
        .I_lap_addr_ap_vld(I_lap_addr_ap_vld),
        .I_ap_start(I_ap_start),
        .O_ap_ready(O_ap_ready),
        .O_ap_done(O_ap_done),
        .O_ap_idle(O_ap_idle),
        .O_ap_return(O_ap_return)
    );

    // I_lap_addr_ap_vld
    always @(posedge ACLK) begin : proc_lap_addr_ap_valid_hold
       if(~ARESETN) begin
            lap_addr_ap_vld_hold <= 1'b0;
       end else begin
            if (I_lap_addr_ap_vld)
                lap_addr_ap_vld_hold <= 1'b1;
       end
    end

    // cam_addr_ap_vld, lap_addr_ap_vld  init_done
    always @(posedge s_axi_lite_aclk) begin : proc_init_done
       if(~ARESETN) begin
            init_done <= 1'b0;
            I_cam_addr_ap_ack <= 1'b0;
       end else begin
            if (lap_addr_ap_vld_hold & I_cam_addr_ap_vld) begin
                init_done <= 1'b1;
                I_cam_addr_ap_ack <= 1'b1;
            end
       end
    end

    assign O_ap_return = 32'd1;

    // axi4_master_inf instance
    axi4_master_inf #(
        .C_M_AXI_DATA_WIDTH(32)
    ) axi4_master_inf_U (
        .ACLK(ACLK),
        .ARESETN(ARESETN),
        .M_AXI_AWID(M_AXI_AWID),
        .M_AXI_AWADDR(M_AXI_AWADDR),
        .M_AXI_AWLEN(M_AXI_AWLEN),
        .M_AXI_AWSIZE(M_AXI_AWSIZE),
        .M_AXI_AWBURST(M_AXI_AWBURST),
        .M_AXI_AWLOCK(M_AXI_AWLOCK),
        .M_AXI_AWCACHE(M_AXI_AWCACHE),
        .M_AXI_AWPROT(M_AXI_AWPROT),
        .M_AXI_AWQOS(M_AXI_AWQOS),
        .M_AXI_AWUSER(M_AXI_AWUSER),
        .M_AXI_AWVALID(M_AXI_AWVALID),
        .M_AXI_AWREADY(M_AXI_AWREADY),
        .M_AXI_WDATA(M_AXI_WDATA),
        .M_AXI_WSTRB(M_AXI_WSTRB),
        .M_AXI_WLAST(M_AXI_WLAST),
        .M_AXI_WUSER(M_AXI_WUSER),
        .M_AXI_WVALID(M_AXI_WVALID),
        .M_AXI_WREADY(M_AXI_WREADY),
        .M_AXI_BID(M_AXI_BID),
        .M_AXI_BRESP(M_AXI_BRESP),
        .M_AXI_BUSER(M_AXI_BUSER),
        .M_AXI_BVALID(M_AXI_BVALID),
        .M_AXI_BREADY(M_AXI_BREADY),
        .M_AXI_ARID(M_AXI_ARID),
        .M_AXI_ARADDR(M_AXI_ARADDR),
        .M_AXI_ARLEN(M_AXI_ARLEN),
        .M_AXI_ARSIZE(M_AXI_ARSIZE),
        .M_AXI_ARBURST(M_AXI_ARBURST),
        .M_AXI_ARLOCK(M_AXI_ARLOCK),
        .M_AXI_ARCACHE(M_AXI_ARCACHE),
        .M_AXI_ARPROT(M_AXI_ARPROT),
        .M_AXI_ARQOS(M_AXI_ARQOS),
        .M_AXI_ARUSER(M_AXI_ARUSER),
        .M_AXI_ARVALID(M_AXI_ARVALID),
        .M_AXI_ARREADY(M_AXI_ARREADY),
        .M_AXI_RID(M_AXI_RID),
        .M_AXI_RDATA(M_AXI_RDATA),
        .M_AXI_RRESP(M_AXI_RRESP),
        .M_AXI_RLAST(M_AXI_RLAST),
        .M_AXI_RUSER(M_AXI_RUSER),
        .M_AXI_RVALID(M_AXI_RVALID),
        .M_AXI_RREADY(M_AXI_RREADY),
        .write_clk(ACLK),
        .write_rst(~ARESETN),
        .write_adfifo_wr_ena(write_adfifo_wr_ena),
        .write_adfifo_addr(write_adfifo_addr),
        .write_adfifo_awlen(write_adfifo_awlen),
        .write_adfifo_full(write_adfifo_full),
        .write_fifo_wr_ena(write_fifo_wr_ena),
        .write_fifo_write_data(write_fifo_write_data),
        .write_fifo_wstrb(write_fifo_wstrb),
        .write_fifo_full(write_fifo_full),
        .write_fifo_almost_full(write_fifo_almost_full),
        .write_fifo_empty(write_fifo_empty),
        .read_clk(ACLK),
        .read_rst(~ARESETN),
        .read_adfifo_wr_ena(read_adfifo_wr_ena),
        .read_adfifo_addr(read_adfifo_addr),
        .read_adfifo_arlen(read_adfifo_arlen),
        .read_adfifo_full(read_adfifo_full),
        .read_fifo_rd_ena(read_fifo_rd_ena),
        .read_fifo_read_data(read_fifo_read_data),
        .read_fifo_empty_n(read_fifo_empty_n),
        .read_fifo_almost_empty_n(read_fifo_almost_empty_n),
        .wr_resp_err(wr_resp_err),
        .init_done(init_done)
    );

    // write_fifo_overflow
    always @(posedge ACLK) begin : proc_write_fifo_overflow
       if(~ARESETN) begin
            write_fifo_overflow <= 1'b0;
       end else begin
            if (write_fifo_full & write_adfifo_wr_ena)
                write_fifo_overflow <= 1'b1;
       end
    end

    // Main State Machine
    always @(posedge ACLK) begin : proc_main_sm
       if(~ARESETN) begin
            main_cs <= IDLE_MAIN;
       end else begin
            case (main_cs)
                IDLE_MAIN :
                    if (init_done & I_ap_start) begin
                        main_cs <= LINE_READ_AND_Y_1ST;
                    end
                LINE_READ_AND_Y_1ST :
                    if (line_read_y_done) begin
                        main_cs <= LINE_READ_AND_Y;
                    end
                LINE_READ_AND_Y :
                    if (line_read_y_done) begin
                        main_cs <= LAP_FILTER_AND_WRITE;
                    end
                LAP_FILTER_AND_WRITE :
                    if (lap_frame_end) begin
                        main_cs <= AP_DONE_ACTIVE;
                    end else if (lap_line_end) begin
                        main_cs <= WAIT_AXI_WRITE_TRANSACTION;
                    end
                WAIT_AXI_WRITE_TRANSACTION :    // Write Transaction が完了するまでWait
                    if (write_fifo_empty)
                         main_cs <= LINE_READ_AND_Y;
                AP_DONE_ACTIVE : begin
                    main_cs <= IDLE_MAIN;
                end

               default : /* default */;
            endcase
       end
    end

    assign O_ap_done = (main_cs==AP_DONE_ACTIVE) ? 1'b1 : 1'b0;
    assign O_ap_ready = (main_cs==AP_DONE_ACTIVE) ? 1'b1 : 1'b0;
    assign O_ap_idle = (main_cs==IDLE_MAIN) ? 1'b1 : 1'b0;

    // 1 line Read State Machine
    always @(posedge ACLK) begin : proc_line_read_and_y_SM
       if(~ARESETN) begin
            line_read_y_cs <= IDLE_LINE_READ_AND_Y;
            line_read_y_start <= 1'b0;
       end else begin
            case (line_read_y_cs)
                IDLE_LINE_READ_AND_Y :
                    if (main_cs==LINE_READ_AND_Y_1ST || main_cs==LINE_READ_AND_Y_2ND || main_cs==LINE_READ_AND_Y) begin
                        line_read_y_cs <= LINE_READ_AND_Y_START;
                        line_read_y_start <= 1'b1;
                    end
                LINE_READ_AND_Y_START : begin
                    line_read_y_cs <= LINE_READ_AND_Y_ACTIVE;
                    line_read_y_start <= 1'b0;
                end
                LINE_READ_AND_Y_ACTIVE :
                    if (line_read_y_done)
                        line_read_y_cs <= IDLE_LINE_READ_AND_Y;
               default : /* default */;
            endcase
       end
    end

    line_read_and_y #(
        .C_M_AXI_ADDR_WIDTH(32),
        .C_M_AXI_DATA_WIDTH(32),
        .HORIZONTAL_PIXELS(800)
    ) line_read_and_y_U (/*autoinst*/
        .clk(ACLK),
        .reset(~ARESETN),
        .start_addr(start_addr[C_M_AXI_ADDR_WIDTH-1:0]),
        .start(line_read_y_start),
        .done(line_read_y_done),
        .y_data(y_data[7:0]),
        .y_data_valid(y_data_valid),
        .read_adfifo_wr_ena(read_adfifo_wr_ena),
        .read_adfifo_addr(read_adfifo_addr[C_M_AXI_ADDR_WIDTH-1:0]),
        .read_adfifo_arlen(read_adfifo_arlen[8-1:0]),
        .read_fifo_rd_ena(read_fifo_rd_ena),
        .read_adfifo_full(read_adfifo_full),
        .read_fifo_read_data(read_fifo_read_data[C_M_AXI_DATA_WIDTH-1:0]),
        .read_fifo_empty_n(read_fifo_empty_n),
        .read_fifo_almost_empty_n(read_fifo_almost_empty_n)
    );

    // line_read_and_y の start_addr の処理
    always @(posedge ACLK) begin : proc_start_addr
       if(~ARESETN) begin
            start_addr <= 0;
       end else begin
            if (I_cam_addr_ap_vld)
                start_addr <= I_cam_addr;
            else if (line_read_y_start) begin
                start_addr <= start_addr + HORIZONTAL_PIXELS*(C_M_AXI_DATA_WIDTH/8);
            end
       end
    end

    // line buffer として使用するDual Port Memory を決定する
    always @(posedge ACLK) begin : proc_line_buffer_wcount
       if(~ARESETN) begin
            line_buffer_wcount <= 2'd0;
       end else begin
            if (line_read_y_done) begin
                if (line_buffer_wcount == 2'd2)
                    line_buffer_wcount <= 2'd0;
                else
                    line_buffer_wcount <= line_buffer_wcount + 2'd1;
            end
       end
    end

    assign line_buf0_we = (line_buffer_wcount==2'd0 && y_data_valid==1'b1) ? 1'b1 : 1'b0;
    assign line_buf1_we = (line_buffer_wcount==2'd1 && y_data_valid==1'b1) ? 1'b1 : 1'b0;
    assign line_buf2_we = (line_buffer_wcount==2'd2 && y_data_valid==1'b1) ? 1'b1 : 1'b0;

    // line buffer 0
    Dual_Port_Memory #(
        .C_MEMORY_SIZE(1024),
        .DATA_BUS_WIDTH(8)
    ) line_buffer_0 (/*autoinst*/
            .dout(line_buf_dout0),
            .clk(ACLK),
            .we(line_buf0_we),
            .waddr(line_buf_waddr),
            .raddr(line_buf_raddr),
            .din(y_data)
     );
        // line buffer 1
    Dual_Port_Memory #(
        .C_MEMORY_SIZE(1024),
        .DATA_BUS_WIDTH(8)
    ) line_buffer_1 (/*autoinst*/
            .dout(line_buf_dout1),
            .clk(ACLK),
            .we(line_buf1_we),
            .waddr(line_buf_waddr),
            .raddr(line_buf_raddr),
            .din(y_data)
     );
        // line buffer 2
    Dual_Port_Memory #(
        .C_MEMORY_SIZE(1024),
        .DATA_BUS_WIDTH(8)
    ) line_buffer_2 (/*autoinst*/
            .dout(line_buf_dout2),
            .clk(ACLK),
            .we(line_buf2_we),
            .waddr(line_buf_waddr),
            .raddr(line_buf_raddr),
            .din(y_data)
     );

    // line_buf_waddr
    always @(posedge ACLK) begin : proc_line_buf_waddr
       if(~ARESETN) begin
            line_buf_waddr <= 10'd0;
       end else begin
            if (line_read_y_start)
                line_buf_waddr <= 10'd0;
            else if (y_data_valid)
                line_buf_waddr <= line_buf_waddr + 10'd1;
       end
    end

    // line_buf_raddr
    always @(posedge ACLK) begin : proc_line_buf_raddr
       if(~ARESETN) begin
            line_buf_raddr <= 10'd0;
       end else begin
            if (main_cs == LAP_FILTER_AND_WRITE)
                line_buf_raddr <= line_buf_raddr + 10'd1;
            else
                line_buf_raddr <= 10'd0;
       end
    end

    // line_buffer_rcount
    always @(posedge ACLK) begin : proc_line_buffer_rcount
       if(~ARESETN) begin
            line_buffer_rcount <= 2'd0;
       end else begin
            if (lap_line_end) begin
                if (line_buffer_rcount==2'd2)
                    line_buffer_rcount <= 2'd0;
                else
                    line_buffer_rcount <= line_buffer_rcount + 2'd1;
            end
       end
    end

    // Xp1Ym1, Xp1Yn, Xp1Yp1
    // 最初のラインは3ライン揃っていない状態でオール0の値を出力するので、3ライン揃うのはline_buffer_rcount==1の時からなので、1つずれている
    always @(posedge ACLK) begin : proc_XY_first_input
       if(~ARESETN) begin
            Xp1Ym1  <=  8'd0;
            Xp1Yn   <=  8'd0;
            Xp1Yp1  <=  8'd0;
       end else begin
            if (main_cs == LAP_FILTER_AND_WRITE) begin
                case (line_buffer_rcount)
                    2'd0 : begin
                        Xp1Ym1  <=  line_buf_dout2;
                        Xp1Yn   <=  line_buf_dout0;
                        Xp1Yp1  <=  line_buf_dout1;
                    end
                    2'd1 : begin
                        Xp1Ym1  <=  line_buf_dout0;
                        Xp1Yn   <=  line_buf_dout1;
                        Xp1Yp1  <=  line_buf_dout2;
                    end
                    2'd2 : begin
                        Xp1Ym1  <=  line_buf_dout1;
                        Xp1Yn   <=  line_buf_dout2;
                        Xp1Yp1  <=  line_buf_dout0;
                    end
                    default : /* default */;
                endcase
            end
       end
    end

    // XnYm1, XnYn, XnYp1, Xm1Ym1, Xm1Yn, Xm1Yp1
    always @(posedge ACLK) begin : proc_XY_2_3_stage
       if(~ARESETN) begin
            XnYm1   <=  8'd0;
            XnYn    <=  8'd0;
            XnYp1   <=  8'd0;
            Xm1Ym1  <=  8'd0;
            Xm1Yn   <=  8'd0;
            Xm1Yp1  <=  8'd0;
       end else begin
            XnYm1   <=  Xp1Ym1;
            XnYn    <=  Xp1Yn;
            XnYp1   <=  Xp1Yp1;
            Xm1Ym1  <=  XnYm1;
            Xm1Yn   <=  XnYn;
            Xm1Yp1  <=  XnYp1;
       end
    end

    // laplacian filter
    // DPMで1クロック、ラプラシアン・フィルタ用FFで3クロック遅延している
    always @(posedge ACLK) begin : proc_laplacian_filter
        reg    [12:0]  laplacian_filter;

       if(~ARESETN) begin
            lap_filter_out <= 8'd0;
       end else begin
            laplacian_filter = {1'b0, XnYn, 3'b000} - {4'b0000, Xp1Ym1} - {4'b0000, Xp1Yn} - {4'b0000, Xp1Yp1} - {4'b0000, XnYm1} - {4'b0000, XnYm1} - {4'b0000, Xm1Ym1} - {4'b0000, Xm1Yn} - {4'b0000, Xm1Yp1};

            // 1line のうちの最初と最後は0
            // DPMで1クロック、ラプラシアン・フィルタ用FFで3クロック遅延している。つまりデータが出てくるのは、lap_pixel_count=4 の時
            if (main_cs==LAP_FILTER_AND_WRITE && lap_pixel_count>=4 && lap_pixel_count<HORIZONTAL_PIXELS+2 && lap_line_count>=1 && lap_line_count<VERTICAL_LINES-1) begin
                if (laplacian_filter[11])   // minus
                    lap_filter_out <= 8'd0;
                else if (laplacian_filter[10]==1'b1 || laplacian_filter[9]==1'b1 || laplacian_filter[8]==1'b1)
                    lap_filter_out <= 8'd255;
                else
                    lap_filter_out <= laplacian_filter[7:0];
            end else
                lap_filter_out <= 8'd0;
       end
    end
    assign write_fifo_write_data = {8'b0000_0000, lap_filter_out, lap_filter_out, lap_filter_out};  // 8'd0, R, G, B
    assign write_fifo_wstrb = 4'b1111;

    // lap_pixel_count
    // ラプラシアン/フィルタの1 line = lap_pixel_count>=3 && lap_pixel_count<HORIZONTAL_PIXELS+3
    always @(posedge ACLK) begin : proc_lap_pixel_count
       if(~ARESETN) begin
            lap_pixel_count <= 0;
       end else begin
            if (main_cs==LAP_FILTER_AND_WRITE) begin
                if (lap_pixel_count == HORIZONTAL_PIXELS+2)
                    lap_pixel_count <= 0;
                else
                    lap_pixel_count <= lap_pixel_count + 1;
            end else
                lap_pixel_count <= 0;
       end
    end
    assign lap_line_end = (lap_pixel_count==HORIZONTAL_PIXELS+2) ? 1'b1 : 1'b0;

    // lap_line_count
    always @(posedge ACLK) begin : proc_lap_line_count
       if(~ARESETN) begin
            lap_line_count <= 0;
       end else begin
            if (main_cs==LAP_FILTER_AND_WRITE) begin
                if (lap_pixel_count==HORIZONTAL_PIXELS+2) begin
                    if (lap_line_count==VERTICAL_LINES-1)
                                lap_line_count <= 0;
                    else
                        lap_line_count <= lap_line_count + 1;
                end
            end
       end
    end
    assign lap_frame_end = (lap_pixel_count==HORIZONTAL_PIXELS+2 && lap_line_count==VERTICAL_LINES-1) ? 1'b1 : 1'b0;

    // wirte_fifo_wr_ena
    // ラプラシアン/フィルタの1 line = lap_pixel_count>=3 && lap_pixel_count<HORIZONTAL_PIXELS+3
    // write_adfifo_wr_ena の enable は、1クロック早く、ap_pixel_count==2 でenableし、ap_pixel_count==HORIZONTAL_PIXELS+2でディスエーブル
    always @(posedge ACLK) begin : proc_wirte_fifo_wr_ena
       if(~ARESETN) begin
            write_fifo_wr_ena <= 1'b0;
       end else begin
            if (write_fifo_almost_full)
                write_fifo_wr_ena <= 1'b0;
            else if (lap_pixel_count==2)
                write_fifo_wr_ena <= 1'b1;
            else if (lap_pixel_count==HORIZONTAL_PIXELS+2)
                write_fifo_wr_ena <= 1'b0;
       end
    end

    // write_adfifo_wr_ena, write_adfifo_wr_ena State Machine
    always @(posedge ACLK) begin : proc_write_addr_SM
       if(~ARESETN) begin
            write_addr_cs <= IDLE_WRITE_ADDR;
            write_adfifo_wr_ena <= 1'b0;
       end else begin
            case (write_addr_cs)
                IDLE_WRITE_ADDR :
                    if (main_cs==LAP_FILTER_AND_WRITE && write_addr_count!=0) begin
                        write_addr_cs <= WRITE_ADDR_ISSUE;
                        write_adfifo_wr_ena <= 1'b1;
                    end
                WRITE_ADDR_ISSUE :
                    begin
                        write_addr_cs <= IDLE_WRITE_ADDR;
                        write_adfifo_wr_ena <= 1'b0;
                    end
               default : /* default */;
            endcase
       end
    end

    // write_addr_count, write_adfifo_awlen
    always @(posedge ACLK) begin : proc_write_addr_count
       if(~ARESETN) begin
            write_addr_count <= HORIZONTAL_PIXELS;
            write_adfifo_awlen <= 8'd255;
       end else begin
            if (write_addr_cs==IDLE_WRITE_ADDR && main_cs==LAP_FILTER_AND_WRITE && write_addr_count!=0) begin
                if (write_addr_count >= 256) begin
                    write_addr_count <= write_addr_count - 10'd256;
                    write_adfifo_awlen <= 8'd255;
                end else begin // less than 256
                    write_addr_count <= 10'd0;
                    write_adfifo_awlen <= write_addr_count[7:0]-8'd1;
                end
            end else if (main_cs == LINE_READ_AND_Y)
                write_addr_count <= HORIZONTAL_PIXELS;
       end
    end

    // write_adfifo_addr
    always @(posedge ACLK) begin : proc_write_addr
       if(~ARESETN) begin
            write_adfifo_addr <= I_lap_addr;
       end else begin
            if (I_lap_addr_ap_vld)
                write_adfifo_addr <= I_lap_addr;
            else if (write_adfifo_wr_ena)
                write_adfifo_addr <= write_adfifo_addr + (write_adfifo_awlen + 8'd1)*(C_M_AXI_DATA_WIDTH/8);
       end
    end

endmodule

`default_nettype wire

  1. 2013年11月27日 05:21 |
  2. Co-design
  3. | トラックバック:0
  4. | コメント:0

AXI4 Master アクセスのラプラシアン・フィルタ IP4(シミュレーション2)

AXI4 Master アクセスのラプラシアン・フィルタ IP3(シミュレーション)”の続き。

前回の AXI4 Master アクセスのラプラシアン・フィルタ IP には欠点があった。それは、ラプラシアン・フィルタ結果をDDR3 SDRAMにWrite するときに終了をブロックしていないことだ。もし、AXI4 Write Transaction の終了、次のAXI4 Read Transaction より長く掛かってしまった場合は、write_data FIFOが溢れてしまう危険がある。現在のところwrite_data FIFOがFULLなった時ののデータ停止は行っていない。つまり手抜きです。。。
その代わり、AXI4 Write Transaction の終了までブロックするようにメインのステートマシンを変更した。メインのステートマシンを下に示す。

    // Main State Machine
    always @(posedge ACLK) begin : proc_main_sm
       if(~ARESETN) begin
            main_cs <= IDLE_MAIN;
       end else begin
            case (main_cs)
                IDLE_MAIN :
                    if (init_done & I_ap_start) begin
                        main_cs <= LINE_READ_AND_Y_1ST;
                    end
                LINE_READ_AND_Y_1ST :
                    if (line_read_y_done) begin
                        main_cs <= LINE_READ_AND_Y;
                    end
                LINE_READ_AND_Y :
                    if (line_read_y_done) begin
                        main_cs <= LAP_FILTER_AND_WRITE;
                    end
                LAP_FILTER_AND_WRITE :
                    if (lap_frame_end) begin
                        main_cs <= AP_DONE_ACTIVE;
                    end else if (lap_line_end) begin
                        main_cs <= WAIT_AXI_WRITE_TRANSACTION;
                    end
                WAIT_AXI_WRITE_TRANSACTION :    // Write Transaction が完了するまでWait
                    if (write_fifo_empty)
                         main_cs <= LINE_READ_AND_Y;
                AP_DONE_ACTIVE : begin
                    main_cs <= IDLE_MAIN;
                end

               default : /* default */;
            endcase
       end
    end


WAIT_AXI_WRITE_TRANSACTION ステートが新たに新設したAXI4 Write Transaction の終了までブロックするステートだ。axi_master_inf.v に、write_data FIFO のempty をwrite_clk で同期した write_fifo_empty ポートを増設して、それを見ている。これで write_data が空なのが確認できる。
更に、write_data FIFO の overflow を監視するために、write_fifo_overflow ポートを増やした。これは、write_fifo_full の時に、write_adfifo_wr_ena が来たかどうかを確認している。

下に、AXI4 TransactionのWrite とReadの様子のシミュレーション波形を示す。上の AXI4 Write Transction のデータ・チャネルの長さが、下の AXI4 Read Transaction のデータ・チャネルより長くなっているのが見える。長くなっても、ReadがWriteを待っているのがわかると追う。これは、AXI4 Write データ・チャネルの WREADY をランダムに Waitさせている。これは、AXI4_Slave_BFM の機能だ。
axi4m_lap_filter_14_131126.png

今度は、1フレームのラプラシアン・フィルタに 14.7msec ほどかかっている。全体のシミュレーション波形を示す。write_fifo_overflow はずっと 0 のままである。つまり、FIFOのオーバーフロー・エラーは無い。
axi4m_lap_filter_15_131126.png

因みに、AXI4 Readは、元々ブロックされているので、ブロックする必要はない。これでIPの実装を行うことにする。
下に、テストベンチの lap_filter_axim_tb.v を貼っておく。

`default_nettype none
`timescale 100ps / 1ps

////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date:   18:18:43 11/22/2013
// Design Name:   lap_filter_axim
// Module Name:   D:/HDL/FndtnISEWork/Zynq-7000/ZedBoard/Zed_OOB_Design2_HLS/hw/xps_proj/pcores/lap_filter_axim_v1_00_a/lap_filter_axim/lap_filter_axim_tb.v
// Project Name:  lap_filter_axim
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: lap_filter_axim
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////

module lap_filter_axim_tb;

    parameter integer C_S_AXI_LITE_ADDR_WIDTH = 9; // Address width of the AXI Lite Interface
    parameter integer C_S_AXI_LITE_DATA_WIDTH = 32; // Data width of the AXI Lite Interface

    parameter DELAY = 1;

    // Inputs
    wire s_axi_lite_aclk;
    wire ACLK;
    wire ARESETN;
    reg s_axi_lite_awvalid;
    reg [8:0] s_axi_lite_awaddr;
    reg s_axi_lite_wvalid;
    reg [31:0] s_axi_lite_wdata;
    reg [3:0] s_axi_lite_wstrb;
    reg s_axi_lite_bready;
    reg s_axi_lite_arvalid;
    reg [8:0] s_axi_lite_araddr;
    reg s_axi_lite_rready;
    wire M_AXI_AWREADY;
    wire M_AXI_WREADY;
    wire [0:0] M_AXI_BID;
    wire [1:0] M_AXI_BRESP;
    wire [0:0] M_AXI_BUSER;
    wire M_AXI_BVALID;
    wire M_AXI_ARREADY;
    wire [0:0] M_AXI_RID;
    wire [31:0] M_AXI_RDATA;
    wire [1:0] M_AXI_RRESP;
    wire M_AXI_RLAST;
    wire [0:0] M_AXI_RUSER;
    wire M_AXI_RVALID;

    // Outputs
    wire s_axi_lite_awready;
    wire s_axi_lite_wready;
    wire [1:0] s_axi_lite_bresp;
    wire s_axi_lite_bvalid;
    wire s_axi_lite_arready;
    wire s_axi_lite_rvalid;
    wire [31:0] s_axi_lite_rdata;
    wire [1:0] s_axi_lite_rresp;
    wire [0:0] M_AXI_AWID;
    wire [31:0] M_AXI_AWADDR;
    wire [7:0] M_AXI_AWLEN;
    wire [2:0] M_AXI_AWSIZE;
    wire [1:0] M_AXI_AWBURST;
    wire M_AXI_AWLOCK;
    wire [3:0] M_AXI_AWCACHE;
    wire [2:0] M_AXI_AWPROT;
    wire [3:0] M_AXI_AWQOS;
    wire [0:0] M_AXI_AWUSER;
    wire M_AXI_AWVALID;
    wire [31:0] M_AXI_WDATA;
    wire [3:0] M_AXI_WSTRB;
    wire M_AXI_WLAST;
    wire [0:0] M_AXI_WUSER;
    wire M_AXI_WVALID;
    wire M_AXI_BREADY;
    wire [0:0] M_AXI_ARID;
    wire [31:0] M_AXI_ARADDR;
    wire [7:0] M_AXI_ARLEN;
    wire [2:0] M_AXI_ARSIZE;
    wire [1:0] M_AXI_ARBURST;
    wire [1:0] M_AXI_ARLOCK;
    wire [3:0] M_AXI_ARCACHE;
    wire [2:0] M_AXI_ARPROT;
    wire [3:0] M_AXI_ARQOS;
    wire [0:0] M_AXI_ARUSER;
    wire M_AXI_ARVALID;
    wire M_AXI_RREADY;
    wire interrupt;
    wire write_fifo_overflow;


    // Instantiate the Unit Under Test (UUT)
    lap_filter_axim # (
            .C_S_AXI_LITE_ADDR_WIDTH(C_S_AXI_LITE_ADDR_WIDTH),
            .C_S_AXI_LITE_DATA_WIDTH(C_S_AXI_LITE_DATA_WIDTH)
        ) uut (
        .s_axi_lite_aclk(s_axi_lite_aclk),
        .M_AXI_ACLK(ACLK),
        .ARESETN(ARESETN),
        .s_axi_lite_awvalid(s_axi_lite_awvalid),
        .s_axi_lite_awready(s_axi_lite_awready),
        .s_axi_lite_awaddr(s_axi_lite_awaddr),
        .s_axi_lite_wvalid(s_axi_lite_wvalid),
        .s_axi_lite_wready(s_axi_lite_wready),
        .s_axi_lite_wdata(s_axi_lite_wdata),
        .s_axi_lite_wstrb(s_axi_lite_wstrb),
        .s_axi_lite_bresp(s_axi_lite_bresp),
        .s_axi_lite_bvalid(s_axi_lite_bvalid),
        .s_axi_lite_bready(s_axi_lite_bready),
        .s_axi_lite_arvalid(s_axi_lite_arvalid),
        .s_axi_lite_arready(s_axi_lite_arready),
        .s_axi_lite_araddr(s_axi_lite_araddr),
        .s_axi_lite_rvalid(s_axi_lite_rvalid),
        .s_axi_lite_rready(s_axi_lite_rready),
        .s_axi_lite_rdata(s_axi_lite_rdata),
        .s_axi_lite_rresp(s_axi_lite_rresp),
        .M_AXI_AWID(M_AXI_AWID),
        .M_AXI_AWADDR(M_AXI_AWADDR),
        .M_AXI_AWLEN(M_AXI_AWLEN),
        .M_AXI_AWSIZE(M_AXI_AWSIZE),
        .M_AXI_AWBURST(M_AXI_AWBURST),
        .M_AXI_AWLOCK(M_AXI_AWLOCK),
        .M_AXI_AWCACHE(M_AXI_AWCACHE),
        .M_AXI_AWPROT(M_AXI_AWPROT),
        .M_AXI_AWQOS(M_AXI_AWQOS),
        .M_AXI_AWUSER(M_AXI_AWUSER),
        .M_AXI_AWVALID(M_AXI_AWVALID),
        .M_AXI_AWREADY(M_AXI_AWREADY),
        .M_AXI_WDATA(M_AXI_WDATA),
        .M_AXI_WSTRB(M_AXI_WSTRB),
        .M_AXI_WLAST(M_AXI_WLAST),
        .M_AXI_WUSER(M_AXI_WUSER),
        .M_AXI_WVALID(M_AXI_WVALID),
        .M_AXI_WREADY(M_AXI_WREADY),
        .M_AXI_BID(M_AXI_BID),
        .M_AXI_BRESP(M_AXI_BRESP),
        .M_AXI_BUSER(M_AXI_BUSER),
        .M_AXI_BVALID(M_AXI_BVALID),
        .M_AXI_BREADY(M_AXI_BREADY),
        .M_AXI_ARID(M_AXI_ARID),
        .M_AXI_ARADDR(M_AXI_ARADDR),
        .M_AXI_ARLEN(M_AXI_ARLEN),
        .M_AXI_ARSIZE(M_AXI_ARSIZE),
        .M_AXI_ARBURST(M_AXI_ARBURST),
        .M_AXI_ARLOCK(M_AXI_ARLOCK),
        .M_AXI_ARCACHE(M_AXI_ARCACHE),
        .M_AXI_ARPROT(M_AXI_ARPROT),
        .M_AXI_ARQOS(M_AXI_ARQOS),
        .M_AXI_ARUSER(M_AXI_ARUSER),
        .M_AXI_ARVALID(M_AXI_ARVALID),
        .M_AXI_ARREADY(M_AXI_ARREADY),
        .M_AXI_RID(M_AXI_RID),
        .M_AXI_RDATA(M_AXI_RDATA),
        .M_AXI_RRESP(M_AXI_RRESP),
        .M_AXI_RLAST(M_AXI_RLAST),
        .M_AXI_RUSER(M_AXI_RUSER),
        .M_AXI_RVALID(M_AXI_RVALID),
        .M_AXI_RREADY(M_AXI_RREADY),
        .interrupt(interrupt),
        .write_fifo_overflow(write_fifo_overflow)
    );

    initial begin : initial_state
        integer i;

        // Initialize Inputs
        s_axi_lite_awaddr = 0;
        s_axi_lite_awvalid = 0;
        s_axi_lite_wvalid = 0;
        s_axi_lite_wdata = 0;
        s_axi_lite_wvalid = 0;
        s_axi_lite_bready = 0;
        s_axi_lite_araddr = 0;
        s_axi_lite_arvalid = 0;
        s_axi_lite_rready = 0;
        s_axi_lite_wstrb = 0;

        // Wait Reset rising edge
        @(posedge ARESETN);

        for (i=0; i<10; i=i+1) begin
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
        end

        s_axi_lite_wstrb = 4'b1111;

        // Add stimulus here
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_0014, 32'h1000_0000);    // cam_addr write
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_0010, 32'h0000_0001);    // cam_addr_ap_vld = 1
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_001C, 32'h2000_0000);    // lap_addr write
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_0018, 32'h0000_0001);    // lap_addr_ap_vld = 1
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_0008, 32'h0000_0001);    // IP Interrupt Enable Registe(ap_done=1)
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_0000, 32'h0000_0001);    // ap_start = 1
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_RADC1(32'h0000_0000);

        forever begin
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
            AXI_MASTER_RADC1(32'h0000_0000);
        end
    end

    // Write Transcation 1
    task AXI_MASTER_WADC1;
        input    [C_S_AXI_LITE_ADDR_WIDTH-1:0]    awaddr;
        input    [C_S_AXI_LITE_DATA_WIDTH-1:0]    wdata;
        begin
            s_axi_lite_awaddr    = awaddr;
            s_axi_lite_awvalid    = 1'b1;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_awvalid <= 1'b0;
            s_axi_lite_wdata = wdata;
            s_axi_lite_wvalid = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
            s_axi_lite_wvalid = 1'b0;
            s_axi_lite_bready = 1'b1;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_bready = 1'b0;
        end
    endtask

    // Read Transcation 1
    task AXI_MASTER_RADC1;
        input    [31:0]    araddr;
        begin
            s_axi_lite_araddr    = araddr;
            s_axi_lite_arvalid     = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_araddr    = 0;
            s_axi_lite_arvalid     = 1'b0;
            s_axi_lite_rready = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_rready = 1'b0;
        end
    endtask

    // clk_gen のインスタンス(ACLK)
    clk_gen #(
        .CLK_PERIOD(100),    // 10nsec, 100MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) ACLKi (
        .clk_out(ACLK)
    );
    assign s_axi_lite_aclk = ACLK;

    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b0),
        .RESET_TIME(1000)    // 100nsec
    ) RESETi (
        .reset_out(ARESETN),
        .init_done()
    );

    // Instantiate the Unit Under Test (UUT_slave)
    axi_slave_bfm # (
        .C_M_AXI_DATA_WIDTH(32),
        .WRITE_RANDOM_WAIT(1),    // Write Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
        .READ_RANDOM_WAIT(0),    //  Read Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
        .READ_DATA_IS_INCREMENT(1),    // ReadトランザクションでRAMの内容をReadする = 0(RAMにWriteしたものをReadする)、Readデータを+1する = 1(データは+1したデータをReadデータとして使用する
        .RUNDAM_BVALID_WAIT(0)
    ) uut_slave (
        .ACLK(ACLK),
        .ARESETN(ARESETN),
        .M_AXI_AWID(M_AXI_AWID),
        .M_AXI_AWADDR(M_AXI_AWADDR),
        .M_AXI_AWLEN(M_AXI_AWLEN),
        .M_AXI_AWSIZE(M_AXI_AWSIZE),
        .M_AXI_AWBURST(M_AXI_AWBURST),
        .M_AXI_AWLOCK({1'b0, M_AXI_AWLOCK}),
        .M_AXI_AWCACHE(M_AXI_AWCACHE),
        .M_AXI_AWPROT(M_AXI_AWPROT),
        .M_AXI_AWQOS(M_AXI_AWQOS),
        .M_AXI_AWUSER(M_AXI_AWUSER),
        .M_AXI_AWVALID(M_AXI_AWVALID),
        .M_AXI_AWREADY(M_AXI_AWREADY),
        .M_AXI_WDATA(M_AXI_WDATA),
        .M_AXI_WSTRB(M_AXI_WSTRB),
        .M_AXI_WLAST(M_AXI_WLAST),
        .M_AXI_WUSER(M_AXI_WUSER),
        .M_AXI_WVALID(M_AXI_WVALID),
        .M_AXI_WREADY(M_AXI_WREADY),
        .M_AXI_BID(M_AXI_BID),
        .M_AXI_BRESP(M_AXI_BRESP),
        .M_AXI_BUSER(M_AXI_BUSER),
        .M_AXI_BVALID(M_AXI_BVALID),
        .M_AXI_BREADY(M_AXI_BREADY),
        .M_AXI_ARID(M_AXI_ARID),
        .M_AXI_ARADDR(M_AXI_ARADDR),
        .M_AXI_ARLEN(M_AXI_ARLEN),
        .M_AXI_ARSIZE(M_AXI_ARSIZE),
        .M_AXI_ARBURST(M_AXI_ARBURST),
        .M_AXI_ARLOCK(M_AXI_ARLOCK),
        .M_AXI_ARCACHE(M_AXI_ARCACHE),
        .M_AXI_ARPROT(M_AXI_ARPROT),
        .M_AXI_ARQOS(M_AXI_ARQOS),
        .M_AXI_ARUSER(M_AXI_ARUSER),
        .M_AXI_ARVALID(M_AXI_ARVALID),
        .M_AXI_ARREADY(M_AXI_ARREADY),
        .M_AXI_RID(M_AXI_RID),
        .M_AXI_RDATA(M_AXI_RDATA),
        .M_AXI_RRESP(M_AXI_RRESP),
        .M_AXI_RLAST(M_AXI_RLAST),
        .M_AXI_RUSER(M_AXI_RUSER),
        .M_AXI_RVALID(M_AXI_RVALID),
        .M_AXI_RREADY(M_AXI_RREADY)
    );

endmodule

module clk_gen #(
    parameter         CLK_PERIOD = 100,
    parameter real    CLK_DUTY_CYCLE = 0.5,
    parameter        CLK_OFFSET = 0,
    parameter        START_STATE    = 1'b0 )
(
    output    reg        clk_out
);
    begin
        initial begin
            #CLK_OFFSET;
            forever
            begin
                clk_out = START_STATE;
                #(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
                #(CLK_PERIOD*CLK_DUTY_CYCLE);
            end
        end
    end
endmodule

module reset_gen #(
    parameter    RESET_STATE = 1'b1,
    parameter    RESET_TIME = 100 )
(
    output    reg        reset_out,
    output    reg        init_done
);
    begin
        initial begin
            reset_out = RESET_STATE;
            init_done = 1'b0;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
            init_done = 1'b1;
        end
    end
endmodule

`default_nettype wire

  1. 2013年11月26日 04:20 |
  2. Co-design
  3. | トラックバック:0
  4. | コメント:0
»