ERROR: [SDSoC 0-0] Function "lap_filter_axim" argument "cam_fb" is mapped to RAM interface, but it's size is bigger than 16384. Please specify #pragma SDS data zero_copy(cam_fb) or #pragma SDS data access_pattern(cam_fb:SEQUENTIAL)
ERROR: [SDSoC 0-0] Failed to generate interface tcl script: C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/vhls/lap_filter_axim.tcl
ERROR: [SDSoC 0-0] Exiting sdscc : Error when calling 'pragma_gen -func lap_filter_axim -tcl C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/vhls/lap_filter_axim.tcl C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/vhls/laplacian_filter2_pp.c -- -c -D __SDSVHLS__ -IC:/Users/Masaaki/workspace/lap_filter2/src -Wall -O0 -g -fmessage-length=0 -MMD -MP -D __SDSCC__ -I C:/HDL/Xilinx/SDSoC/2016.2/aarch32-linux/include -IC:/Users/Masaaki/workspace/lap_filter2/src -target arm-linux-gnueabihf -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -O0 -g -w -I C:/HDL/Xilinx/SDSoC/2016.2/aarch32-linux/include -I C:/HDL/Xilinx/SDSoC/2016.2/Vivado_HLS/2016.2/include -IC:/HDL/Xilinx/SDSoC/2016.2/SDK/2016.2/gnu/aarch32/nt/gcc-arm-linux-gnueabi/lib/gcc/arm-linux-gnueabihf/4.9.2/include -IC:/HDL/Xilinx/SDSoC/2016.2/SDK/2016.2/gnu/aarch32/nt/gcc-arm-linux-gnueabi/lib/gcc/arm-linux-gnueabihf/4.9.2/include-fixed -IC:/HDL/Xilinx/SDSoC/2016.2/SDK/2016.2/gnu/aarch32/nt/gcc-arm-linux-gnueabi/arm-linux-gnueabihf/include -IC:/HDL/Xilinx/SDSoC/2016.2/SDK/2016.2/gnu/aarch32/nt/gcc-arm-linux-gnueabi/arm-linux-gnueabihf/libc/usr/include'
sdscc log file saved as C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/reports/sds_laplacian_filter2.log
ERROR: [SDSoC 0-0] Build failed
make: *** [src/laplacian_filter2.o] エラー 1
#pragma SDS data zero_copy(cam_fb[0:ALL_PIXEL_VALUE])
#pragma SDS data zero_copy(lap_fb[0:ALL_PIXEL_VALUE])
int lap_filter_axim(int cam_fb[ALL_PIXEL_VALUE], int lap_fb[ALL_PIXEL_VALUE], int width, int height)
{
ERROR: [Place 30-640] Place Check : This design requires more RAMB36/FIFO cells than are available in the target device. This design requires 353 of such cell types but only 60 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-640] Place Check : This design requires more RAMB18 and RAMB36/FIFO cells than are available in the target device. This design requires 708 of such cell types but only 120 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-640] Place Check : This design requires more RAMB36E1 cells than are available in the target device. This design requires 353 of such cell types but only 60 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-99] Placer failed with error: 'Implementation Feasibility check failed, Please see the previously displayed individual error or warning messages for more details.'
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Common 17-69] Command failed: Placer could not place all instances
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [SDSoC 0-0] Exiting system_linker: Error when calling 'C:/HDL/Xilinx/SDSoC/2016.2/Vivado/2016.2/bin/vivado -mode batch -source "C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/top.impl.tcl"'
ERROR: [SDSoC 0-0] Exiting sds++ : Error when calling 'system_linker -cf-input C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/.llvm/apsys_0.xml -cf-output-dir _sds/p0 -ip-db C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/.cdb/xd_ip_db.xml -ip-repo C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/iprepo/repo -sds-pf C:/HDL/Xilinx/SDSoC/2016.2/platforms/zybo:linux -bitstream -bit-name lap_filter2.elf.bit -boot-files -mdev-no-swgen -mdev-no-xsd -sdsoc -sd-output-dir _sds/p0/sd_card -bit-binary -elf C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/swstubs/lap_filter2.elf'
sds++ log file saved as C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/reports/sds.log
ERROR: [SDSoC 0-0] Build failed
make: *** [lap_filter2.elf] エラー 1
#pragma SDS data access_pattern(cam_fb:SEQUENTIAL)
#pragma SDS data access_pattern(lap_fb:SEQUENTIAL)
int lap_filter_axim(int cam_fb[ALL_PIXEL_VALUE], int lap_fb[ALL_PIXEL_VALUE], int width, int height)
{
ERROR: [Place 30-640] Place Check : This design requires more F7 Muxes cells than are available in the target device. This design requires 204055 of such cell types but only 8800 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-640] Place Check : This design requires more F8 Muxes cells than are available in the target device. This design requires 11953 of such cell types but only 4400 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-640] Place Check : This design requires more Slice LUTs cells than are available in the target device. This design requires 573217 of such cell types but only 17600 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device. Please set tcl parameter "drc.disableLUTOverUtilError" to 1 to change this error to warning.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-640] Place Check : This design requires more LUT as Logic cells than are available in the target device. This design requires 212504 of such cell types but only 17600 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device. Please set tcl parameter "drc.disableLUTOverUtilError" to 1 to change this error to warning.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-640] Place Check : This design requires more LUT as Memory cells than are available in the target device. This design requires 360713 of such cell types but only 6000 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device. Please set tcl parameter "drc.disableLUTOverUtilError" to 1 to change this error to warning.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-640] Place Check : This design requires more LUT as Distributed RAM cells than are available in the target device. This design requires 360452 of such cell types but only 6000 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device. Please set tcl parameter "drc.disableLUTOverUtilError" to 1 to change this error to warning.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-640] Place Check : This design requires more LUT4 cells than are available in the target device. This design requires 106690 of such cell types but only 35200 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-640] Place Check : This design requires more LUT6 cells than are available in the target device. This design requires 144752 of such cell types but only 17600 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-640] Place Check : This design requires more MUXF7 cells than are available in the target device. This design requires 204055 of such cell types but only 8800 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-640] Place Check : This design requires more MUXF8 cells than are available in the target device. This design requires 11953 of such cell types but only 4400 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-640] Place Check : This design requires more RAMD64E cells than are available in the target device. This design requires 360048 of such cell types but only 6000 compatible sites are available in the target device. Please analyze your synthesis results and constraints to ensure the design is mapped to Xilinx primitives as expected. If so, please consider targeting a larger device.
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Place 30-99] Placer failed with error: 'Implementation Feasibility check failed, Please see the previously displayed individual error or warning messages for more details.'
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [Common 17-69] Command failed: Placer could not place all instances
INFO: [SDSoC 0-0] See C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/vivado.log for the context of the Vivado message above.
ERROR: [SDSoC 0-0] Exiting system_linker: Error when calling 'C:/HDL/Xilinx/SDSoC/2016.2/Vivado/2016.2/bin/vivado -mode batch -source "C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/p0/ipi/top.impl.tcl"'
ERROR: [SDSoC 0-0] Exiting sds++ : Error when calling 'system_linker -cf-input C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/.llvm/apsys_0.xml -cf-output-dir _sds/p0 -ip-db C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/.cdb/xd_ip_db.xml -ip-repo C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/iprepo/repo -sds-pf C:/HDL/Xilinx/SDSoC/2016.2/platforms/zybo:linux -bitstream -bit-name lap_filter2.elf.bit -boot-files -mdev-no-swgen -mdev-no-xsd -sdsoc -sd-output-dir _sds/p0/sd_card -bit-binary -elf C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/swstubs/lap_filter2.elf'
sds++ log file saved as C:/Users/Masaaki/workspace/lap_filter2/SDDebug/_sds/reports/sds.log
ERROR: [SDSoC 0-0] Build failed
make: *** [lap_filter2.elf] エラー 1
追従走行ロボットカー動作概要
前のロボットカーのマーカーを追いかける。
前車との標準的な距離は 32㎝ とする。
マーカーは水色の四角の中に赤の四角があるものとする。水色の色相(H)は180、赤の色相は0である。
前車との距離が 32cm でも 64cmでも、マーカーをサーチする際に800ピクセル×600行のうちの上から360行の付近を横にサーチすれば水色の四角と赤の四角を横切るので、その辺りで判定する。
1.左側から15ピクセル程度水色判定が続いたら、マーカーだと判定する。
2.赤になった時の幅を確認する。もし赤判定が100ピクセル以下だったら、遠すぎるか、マーカー検出できていないので検出プログラムを停止する。
3.赤判定が外れて5ピクセル以内に水色判定にならないときはエラー。(CMOSカメラのベイヤ配列のためか?赤、水色の境界では、2ピクセルほど色が赤でも水色でもない状態にある)
前車との標準的な距離 32cm のときの赤い四角の幅は 340 ピクセル、64 cm の時は 144 ピクセル
前車との間隔は 赤判定が340~280 ピクセル程度に収まるように車速を調整する。
赤い四角が画像の真ん中に来るようにする。
赤い四角が左に寄っている場合 - 右車輪の回転数を上げるか、左車輪の回転数を下げる。
赤い四角が右に寄っている場合 - 左車輪の回転数を上げるか、右車輪の回転数を下げる。
// platoon_car0.cpp
// Autonomously running car
// 2016/11/15 by marsee
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include "xpwm.h"
#include "xmotor_monitor.h"
#define DIR_LEFT_NORMAL 1
#define DIR_LEFT_REVERSE 0
#define DIR_RIGHT_NORMAL 0
#define DIR_RIGHT_REVERSE 1
#define PIXEL_NUM_OF_BYTES 4
#define SVGA_HORIZONTAL_PIXELS 800
#define SVGA_VERTICAL_LINES 600
#define SVGA_ALL_DISP_ADDRESS (SVGA_HORIZONTAL_PIXELS * SVGA_VERTICAL_LINES * PIXEL_NUM_OF_BYTES)
// Motor
//
void motor_settings(XPwm *motorLp, XPwm *motorRp){
XPwm_DisableAutoRestart(motorLp);
while(!XPwm_IsIdle(motorLp)) ;
XPwm_Start(motorLp);
XPwm_EnableAutoRestart(motorLp);
XPwm_DisableAutoRestart(motorRp);
while(!XPwm_IsIdle(motorRp)) ;
XPwm_Start(motorRp);
XPwm_EnableAutoRestart(motorRp);
}
void Stopped_Zybot(XPwm *motorLp, XPwm *motorRp){
XPwm_Set_sw_late_V(motorLp, 0);
XPwm_Set_sw_late_V(motorRp, 0);
}
void motor_initialize(XPwm &motorL, XPwm &motorR, XMotor_monitor &mmL, XMotor_monitor &mmR){
XPwm *motorLp, *motorRp;
XMotor_monitor *mmLp, *mmRp;
motorLp = &motorL;
motorRp = &motorR;
mmLp = &mmL;
mmRp = &mmR;
// Initialization of motor
if (XPwm_Initialize(motorLp, "pwm_0") != XST_SUCCESS){
fprintf(stderr,"pwm_0 (Left) open error\n");
exit(-1);
}
if (XPwm_Initialize(motorRp, "pwm_1") != XST_SUCCESS){
fprintf(stderr,"pwm_1 (Right) open error\n");
exit(-1);
}
// Initialization of motor monitor
if (XMotor_monitor_Initialize(mmLp, "motor_monitor_0") != XST_SUCCESS){
fprintf(stderr,"motor_monitor_0 (Left) open error\n");
exit(-1);
}
if (XMotor_monitor_Initialize(mmRp, "motor_monitor_1") != XST_SUCCESS){
fprintf(stderr,"motor_monitor_1 (Right) open error\n");
exit(-1);
}
// The Motors is rotated in the forward direction.
XPwm_Set_sw_late_V(motorLp, 0);
XPwm_Set_dir_V(motorLp, 1);
XPwm_Set_sw_late_V(motorRp, 0);
XPwm_Set_dir_V(motorRp, 0);
motor_settings(motorLp, motorRp);
}
int main(){
XPwm motorL, motorR;
XMotor_monitor mmL, mmR;
int c;
// Motor Initialize
motor_initialize(motorL, motorR, mmL, mmR);
XPwm_Set_sw_late_V(&motorL, 25);
XPwm_Set_sw_late_V(&motorR, 25);
sleep(1);
// right turn
XPwm_Set_sw_late_V(&motorL, 30);
XPwm_Set_sw_late_V(&motorR, 10);
// Key input
// r - right turn, l - left turn, g - Go straight, s - stop, q - quit
printf("r - right turn, l - left turn, g - Go straight, s - stop, q - quit\n");
c = getc(stdin);
while(c != 'q'){
switch ((char)c) {
case 'r' : // right turn
XPwm_Set_sw_late_V(&motorL, 30);
XPwm_Set_sw_late_V(&motorR, 10);
break;
case 'l' : // left turn
XPwm_Set_sw_late_V(&motorL, 10);
XPwm_Set_sw_late_V(&motorR, 30);
break;
case 'g' : // Go straight
XPwm_Set_sw_late_V(&motorL, 20);
XPwm_Set_sw_late_V(&motorR, 20);
break;
case 's' : // stop
XPwm_Set_sw_late_V(&motorL, 0);
XPwm_Set_sw_late_V(&motorR, 0);
break;
}
c = getc(stdin);
}
XPwm_Set_sw_late_V(&motorL, 0);
XPwm_Set_sw_late_V(&motorR, 0);
return(0);
}
// laplacian_filter3_2.c
// 2016/11/22 by marsee
//
#define HORIZONTAL_PIXEL_WIDTH 64
#define VERTICAL_PIXEL_WIDTH 48
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);
void rdma_and_rgb2y(int *buf, volatile int *mem, int tripcount);
void wdma_buf(int *buf, volatile int *mem, int tripcount);
int lap_filter_axim(volatile int *cam_fb, volatile int *lap_fb)
{
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb num_read_outstanding=4 max_read_burst_length=16
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb num_write_outstanding=4 max_write_burst_length=16
int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=3 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P
int lap_buf[HORIZONTAL_PIXEL_WIDTH];
int x, y;
int lap_fil_val;
int fl, sl, tl;
// 最初に2ラインの画素を読み込む
Loop1: for (y=0; y<2; y++){ // 2ライン分
rdma_and_rgb2y(&line_buf[y][0], &cam_fb[(y*HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH);
}
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
Loop2: for (y=2; y<VERTICAL_PIXEL_WIDTH; y++){
rdma_and_rgb2y(&line_buf[y%3][0], &cam_fb[(y*HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH);
lap_buf[0] = 0; // ラインの最初に0を代入
lap_buf[HORIZONTAL_PIXEL_WIDTH-1] = 0; // ラインの最後に0を代入
Loop3: for (x=2; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE II=1
fl = (y-2)%3; // 最初のライン, y=2 012, y=3 120, y=4 201, y=5 012
sl = (y-1)%3; // 2番めのライン
tl = y%3; // 3番目のライン
lap_fil_val = laplacian_fil(line_buf[fl][x-2], line_buf[fl][x-1], line_buf[fl][x], line_buf[sl][x-2], line_buf[sl][x-1], line_buf[sl][x], line_buf[tl][x-2], line_buf[tl][x-1], line_buf[tl][x]);
lap_buf[x-1] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val ;
}
wdma_buf(&lap_buf[0], &lap_fb[((y-1)*HORIZONTAL_PIXEL_WIDTH)], HORIZONTAL_PIXEL_WIDTH);
}
Loop4: for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++) // 最初の行に 0 を入れる
#pragma HLS PIPELINE II=1
lap_fb[x] = 0;
Loop5: for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++) // 最後の行に 0 を入れる
#pragma HLS PIPELINE II=1
lap_fb[HORIZONTAL_PIXEL_WIDTH*(VERTICAL_PIXEL_WIDTH-1)+x] = 0;
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);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
int y;
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
void rdma_and_rgb2y(int *buf, volatile int *mem, int tripcount){
int i;
Loop20: for (i=0; i<tripcount; i++){
#pragma HLS PIPELINE II=1
*buf = *mem++;
*buf++ = conv_rgb2y(*buf);
}
}
void wdma_buf(int *buf, volatile int *mem, int tripcount){
int i;
Loop20: for (i=0; i<tripcount; i++)
#pragma HLS PIPELINE II=1
*mem++ = *buf++;
}
Cコードの合成、C/RTL協調シミュレーションを行って、C/RTL協調シミュレーションの波形見たところ、やはり 16 バースト転送だった。#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb
というようにバースト ビヘービアーで 32 バースト転送にしてみた。#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb num_read_outstanding=4 max_read_burst_length=32
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb num_write_outstanding=4 max_write_burst_length=32
// laplacian_filter3.c
// 2016/11/21 by marsee
//
#define HORIZONTAL_PIXEL_WIDTH 64
#define VERTICAL_PIXEL_WIDTH 48
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);
int lap_filter_axim(volatile int *cam_fb, volatile int *lap_fb)
{
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb
int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
#pragma HLS array_partition variable=line_buf block factor=3 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P
int lap_buf[HORIZONTAL_PIXEL_WIDTH];
int x, y;
int lap_fil_val;
int fl, sl, tl;
// 最初に2ラインの画素を読み込む
Loop1: for (y=0; y<2; y++){ // 2ライン分
Loop2: for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){ // ライン
#pragma HLS PIPELINE II=1
line_buf[y][x] = cam_fb[(y*HORIZONTAL_PIXEL_WIDTH)+x];
line_buf[y][x] = conv_rgb2y(line_buf[y][x]);
}
}
// RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
Loop3: for (y=2; y<VERTICAL_PIXEL_WIDTH; y++){
Loop4: for (x=0; x<2; x++){
#pragma HLS PIPELINE II=1
line_buf[y%3][x] = cam_fb[(y*HORIZONTAL_PIXEL_WIDTH)+x];
line_buf[y%3][x] = conv_rgb2y(line_buf[y%3][x]);
}
lap_buf[0] = 0; // ラインの最初に0を代入
lap_buf[HORIZONTAL_PIXEL_WIDTH-1] = 0; // ラインの最後に0を代入
Loop5: for (x=2; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE II=1
// 1つのピクセルを読み込みながらラプラシアン・フィルタを実行する
line_buf[y%3][x] = cam_fb[(y*HORIZONTAL_PIXEL_WIDTH)+x];
// y%3 は、使用済みのラインがに読み込む、y=2 の時 line[0], y=3の時 line[1], y=4の時 line[2]
line_buf[y%3][x] = conv_rgb2y(line_buf[y%3][x]);
fl = (y-2)%3; // 最初のライン, y=2 012, y=3 120, y=4 201, y=5 012
sl = (y-1)%3; // 2番めのライン
tl = y%3; // 3番目のライン
lap_fil_val = laplacian_fil(line_buf[fl][x-2], line_buf[fl][x-1], line_buf[fl][x], line_buf[sl][x-2], line_buf[sl][x-1], line_buf[sl][x], line_buf[tl][x-2], line_buf[tl][x-1], line_buf[tl][x]);
lap_buf[x-1] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val ;
}
Loop6: for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++)
#pragma HLS PIPELINE II=1
lap_fb[((y-1)*HORIZONTAL_PIXEL_WIDTH)+x] = lap_buf[x]; // ラプラシアンフィルタ・データの書き込み
}
Loop7: for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++) // 最初の行に 0 を入れる
#pragma HLS PIPELINE II=1
lap_fb[x] = 0;
Loop8: for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++) // 最後の行に 0 を入れる
#pragma HLS PIPELINE II=1
lap_fb[HORIZONTAL_PIXEL_WIDTH*(VERTICAL_PIXEL_WIDTH-1)+x] = 0;
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);
}
// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1 8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
int y;
y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
if (y<0)
y = 0;
else if (y>255)
y = 255;
return(y);
}
#pragma HLS INTERFACE m_axi depth=3072 port=cam_fb offset=slave bundle=cam_fb num_read_outstanding=4 max_read_burst_length=16
#pragma HLS INTERFACE m_axi depth=3072 port=lap_fb offset=slave bundle=lap_fb num_write_outstanding=4 max_write_burst_length=16
//
// rgb2hsv_rev_plat.c
// Created on: 2016/11/15
// Author: marsee
//
// Refered to http://japan.xilinx.com/support/documentation/sw_manuals_j/xilinx2014_4/ug902-vivado-high-level-synthesis.pdf
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#define CMA_START_ADDRESS 0x17800000
#define VIDEO_BUFFER_START_ADDRESS 0x18000000 // Limit 0x18800000, 800*600*4 = 2MBytes * 2
#define HORIZONTAL_PIXELS 800
#define ALL_CHAR_OF_1LINE (HORIZONTAL_PIXELS/8)
#define VERTICAL_LINES 600
#define ALL_CHAR_OF_ROW (VERTICAL_LINES/8)
#define ALL_DISP_ADDRESS (HORIZONTAL_PIXELS*VERTICAL_LINES*4)
#define ALL_DISP_CHARACTOR (HORIZONTAL_PIXELS*VERTICAL_LINES)
int main(){
int fd1, fd2, fd3, fd4, fd6, fd7, fd9, fd10;
volatile unsigned *axis_switch_0, *axis_switch_1;
volatile unsigned *rgb2hsv_0;
volatile unsigned *dmaw4gabor_0;
volatile unsigned *bmdc_axi_lites0, *bmdc_axi_lites1;
volatile unsigned *frame_buffer_bmdc;
unsigned char attr[1024];
unsigned long phys_addr;
int i, j;
int max, min;
int h, s, v;
int r, g, b;
volatile int *fb_hsv, *fb_rgb;
// axis_switch_0 (UIO2)
fd2 = open("/dev/uio2", O_RDWR); // axis_switch_0 interface AXI4 Lite Slave
if (fd2 < 1){
fprintf(stderr, "/dev/uio2 (axis_switch_0) open error\n");
exit(-1);
}
axis_switch_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
if (!axis_switch_0){
fprintf(stderr, "axis_switch_0 mmap error\n");
exit(-1);
}
// axis_switch_1 (UIO3)
fd3 = open("/dev/uio3", O_RDWR); // axis_switch_1 interface AXI4 Lite Slave
if (fd3 < 1){
fprintf(stderr, "/dev/uio3 (axis_switch_1) open error\n");
exit(-1);
}
axis_switch_1 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd3, 0);
if (!axis_switch_1){
fprintf(stderr, "axis_switch_1 mmap error\n");
exit(-1);
}
// rgb2hsv_0 (UIO15)
fd4 = open("/dev/uio15", O_RDWR); // rgb2hsv_0 interface AXI4 Lite Slave
if (fd4 < 1){
fprintf(stderr, "/dev/uio14 (rgb2hsv_0) open error\n");
exit(-1);
}
rgb2hsv_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd4, 0);
if (!rgb2hsv_0){
fprintf(stderr, "lap_filter_axis_0 mmap error\n");
exit(-1);
}
// dmaw4gabor_0 (UIO1)
fd1 = open("/dev/uio1", O_RDWR); // dmaw4gabor_0 interface AXI4 Lite Slave
if (fd1 < 1){
fprintf(stderr, "/dev/uio1 (dmaw4gabor_0) open error\n");
exit(-1);
}
dmaw4gabor_0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
if (!dmaw4gabor_0){
fprintf(stderr, "dmaw4gabor_0 mmap error\n");
exit(-1);
}
// Bitmap Display Controller 0 AXI4 Lite Slave (UIO6)
fd6 = open("/dev/uio6", O_RDWR); // bitmap_display_controller 0 axi4 lite
if (fd6 < 1){
fprintf(stderr, "/dev/uio6 (bitmap_disp_cntrler_axi_master_0) open error\n");
exit(-1);
}
bmdc_axi_lites0 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd6, 0);
if (!bmdc_axi_lites0){
fprintf(stderr, "bmdc_axi_lites0 mmap error\n");
exit(-1);
}
// Bitmap Display Controller 1 AXI4 Lite Slave (UIO7)
fd7 = open("/dev/uio7", O_RDWR); // bitmap_display_controller axi4 lite
if (fd7 < 1){
fprintf(stderr, "/dev/uio7 (bitmap_disp_cntrler_axi_master_0) open error\n");
exit(-1);
}
bmdc_axi_lites1 = (volatile unsigned *)mmap(NULL, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, fd7, 0);
if (!bmdc_axi_lites1){
fprintf(stderr, "bmdc_axi_lites1 mmap error\n");
exit(-1);
}
// udmabuf0
fd9 = open("/dev/udmabuf0", O_RDWR | O_SYNC); // frame_buffer, The chache is disabled.
if (fd9 == -1){
fprintf(stderr, "/dev/udmabuf0 open error\n");
exit(-1);
}
frame_buffer_bmdc = (volatile unsigned *)mmap(NULL, 5760000, PROT_READ|PROT_WRITE, MAP_SHARED, fd9, 0);
if (!frame_buffer_bmdc){
fprintf(stderr, "frame_buffer_bmdc mmap error\n");
exit(-1);
}
// phys_addr of udmabuf0
fd10 = open("/sys/devices/virtual/udmabuf/udmabuf0/phys_addr", O_RDONLY);
if (fd10 == -1){
fprintf(stderr, "/sys/devices/virtual/udmabuf/udmabuf0/phys_addr open error\n");
exit(-1);
}
read(fd10, attr, 1024);
sscanf(attr, "%lx", &phys_addr);
close(fd10);
printf("phys_addr = %x\n", (int)phys_addr);
// axis_switch_1, 1to2 ,Select M01_AXIS
// Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
axis_switch_1[16] = 0x80000000; // 0x40 = 0x80000000; disable, through
axis_switch_1[17] = 0x80000000; // 0x44 = 0x80000000; disable, laplacian filter
axis_switch_1[18] = 0x80000000; // 0x48 = 0x80000000; disable, gabor filter
axis_switch_1[19] = 0; // 0x48 = 0; RGB2HSV
axis_switch_1[0] = 0x2; // 0x0 = 2; Commit registers
// RGB2HSV AXIS Start
rgb2hsv_0[0] = 0x01; // Start bit set
rgb2hsv_0[0] = 0x80; // Auto Restart bit set
// axis_switch_0, 2to1, Select S01_AXIS
// Refer to http://marsee101.blog19.fc2.com/blog-entry-3177.html
axis_switch_0[16] = 0x3; // 0x40 = 0x2; RGB2HSV
axis_switch_0[0] = 0x2; // 0x0 = 2; Commit registers
// bitmap display controller settings
bmdc_axi_lites0[0] = (int)phys_addr+ALL_DISP_ADDRESS; // Bitmap Display Controller 0 start
bmdc_axi_lites1[0] = (int)phys_addr+ALL_DISP_ADDRESS; // Bitmap Display Controller 1 start
munmap((void *)axis_switch_0, 0x10000);
munmap((void *)axis_switch_1, 0x10000);
munmap((void *)rgb2hsv_0, 0x10000);
munmap((void *)dmaw4gabor_0, 0x10000);
munmap((void *)bmdc_axi_lites0, 0x10000);
munmap((void *)bmdc_axi_lites1, 0x10000);
close(fd1);
close(fd2);
close(fd3);
close(fd4);
close(fd6);
close(fd7);
fb_hsv = (volatile int *)frame_buffer_bmdc;
fb_rgb = (volatile int *)((int)frame_buffer_bmdc+(int)ALL_DISP_ADDRESS);
while(1){
for(j=0; j<VERTICAL_LINES; j++){
for(i=0; i<HORIZONTAL_PIXELS; i++){
h = (fb_hsv[HORIZONTAL_PIXELS*j+i]/65536) & 0x1ff;
s = (fb_hsv[HORIZONTAL_PIXELS*j+i]/256) & 0xff;
v = fb_hsv[HORIZONTAL_PIXELS*j+i] & 0xff;
max = v;
min = max - (int)(((float)s/255.0)*(float)max + 0.5);
if(h>=0 && h<60){
r = max;
g = (int)(((float)h/60.0)*(float)(max-min)+0.5) + min;
b = min;
}else if(h>=60 && h<120){
r = (int)(((120.0-(float)h)/60.0)*((float)(max-min))+0.5) + min;
g = max;
b = min;
}else if(h>=120 && h<180){
r = min;
g = max;
b = (int)((((float)h-120.0)/60.0)*((float)(max-min))+0.5) + min;
}else if(h>=180 && h<240){
r = min;
g = (int)(((240.0-(float)h)/60.0)*((float)(max-min))+0.5) + min;
b = max;
}else if(h>=240 && h<300){
r = (int)((((float)h-240.0)/60.0)*((float)(max-min))+0.5) + min;
g = min;
b = max;
}else{// if(h<=300 && h<=360){
r = max;
g = min;
b = (int)(((360.0-(float)h)/60.0)*((float)(max-min))+0.5) + min;
}
fb_rgb[HORIZONTAL_PIXELS*j+i] = (r&0xff)*65536 | (g&0xff)*256 | b&0xff;
}
}
sleep(1);
}
munmap((void *)frame_buffer_bmdc, 576000);
close(fd9);
return(0);
}
/* AXI Master用 Slave Bus Function Mode (BFM)
axi_slave_BFM_intf.v
2012/02/25 : S_AXI_AWBURST=1 (INCR) にのみ対応、AWSIZE, ARSIZE = 000 (1byte), 001 (2bytes), 010 (4bytes) のみ対応。
2012/07/04 : READ_ONLY_TRANSACTION を追加。Read機能のみでも+1したデータを出力することが出来るように変更した。
2014/01/05 : ポート名をM_AXI?からS_AXI?に修正、Verilogに移植(By Koba)
*/
// 2014/07/18 : Write Respose Channel に sync_fifo を使用した by marsee
// 2014/07/19 : RAM を初期化する初期化ファイルを追加(init_ram_data.txt) by marsee
// 2014/07/20 : RAM 初期化ファイル名を parameter に追加 by marsee
// 2014/08/31 : READ_RANDOM_WAIT=1 の時に、S_AXI_RREADY が S_AXI_RVALID に依存するバグをフィック。 by marsee
// WRITE_RANDOM_WAIT=1 の時に、S_AXI_WVALID が S_AXI_WREADY に依存するバグをフィック。 by marsee
// LOAD_RAM_INIT_FILE パラメータを追加 by marsee
//
// 2016/07/03 : AWREADY_IS_USUALLY_HIGH と ARREADY_IS_USUALLY_HIGH の2つのパラメータを追加 by marsee
//
// ライセンスは二条項BSDライセンス (2-clause BSD license)とします。
//
module axi_slave_bfm #(
parameter integer C_S_AXI_ID_WIDTH = 1,
parameter integer C_S_AXI_ADDR_WIDTH = 32,
parameter integer C_S_AXI_DATA_WIDTH = 32,
parameter integer C_S_AXI_AWUSER_WIDTH = 1,
parameter integer C_S_AXI_ARUSER_WIDTH = 1,
parameter integer C_S_AXI_WUSER_WIDTH = 1,
parameter integer C_S_AXI_RUSER_WIDTH = 1,
parameter integer C_S_AXI_BUSER_WIDTH = 1,
parameter integer C_S_AXI_TARGET = 0,
parameter integer C_OFFSET_WIDTH = 10, // 割り当てるRAMのアドレスのビット幅
parameter integer C_S_AXI_BURST_LEN = 256,
parameter integer WRITE_RANDOM_WAIT = 1, // Write Transactionデータ転送時にランダムなWaitを発生させる=1、Waitしない=0
parameter integer READ_RANDOM_WAIT = 0, // Read Transactionデータ転送時にランダムなWaitを発生させる=1、Waitしない=0
parameter integer READ_DATA_IS_INCREMENT = 0, // Read TransactionでRAMのデータを読み出す=0、0はじまりの+1データを使う=1
parameter integer RANDOM_BVALID_WAIT = 0, // Write Transaction後、BVALIDをランダムにWaitする=1、ランダムにWaitしない=0
parameter [80*8:1] RAM_INIT_FILE = "init_ram_data.data",
parameter integer LOAD_RAM_INIT_FILE = 0, // RAM_INIT_FILE をLoadする - 1, Load しない - 0
parameter integer AWREADY_IS_USUALLY_HIGH = 1, // AWRAEDY は通常はLow=0, High=1
parameter integer ARREADY_IS_USUALLY_HIGH = 1 // AWRAEDY は通常はLow=0, High=1
)
(
// System Signals
input ACLK,
input ARESETN,
// Slave Interface Write Address Ports
input [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_AWID,
input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
input [8-1 : 0] S_AXI_AWLEN,
input [3-1 : 0] S_AXI_AWSIZE,
input [2-1 : 0] S_AXI_AWBURST,
// input S_AXI_AWLOCK [2-1 : 0],
input [1 : 0] S_AXI_AWLOCK,
input [4-1 : 0] S_AXI_AWCACHE,
input [3-1 : 0] S_AXI_AWPROT,
input [4-1 : 0] S_AXI_AWQOS,
input [C_S_AXI_AWUSER_WIDTH-1 :0] S_AXI_AWUSER,
input S_AXI_AWVALID,
output S_AXI_AWREADY,
// Slave Interface Write Data Ports
input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
input [C_S_AXI_DATA_WIDTH/8-1 : 0]S_AXI_WSTRB,
input S_AXI_WLAST,
input [C_S_AXI_WUSER_WIDTH-1 : 0] S_AXI_WUSER,
input S_AXI_WVALID,
output S_AXI_WREADY,
// Slave Interface Write Response Ports
output [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_BID,
output [2-1 : 0] S_AXI_BRESP,
output [C_S_AXI_BUSER_WIDTH-1 : 0] S_AXI_BUSER,
output S_AXI_BVALID,
input S_AXI_BREADY,
// Slave Interface Read Address Ports
input [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_ARID,
input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
input [8-1 : 0] S_AXI_ARLEN,
input [3-1 : 0] S_AXI_ARSIZE,
input [2-1 : 0] S_AXI_ARBURST,
input [2-1 : 0] S_AXI_ARLOCK,
input [4-1 : 0] S_AXI_ARCACHE,
input [3-1 : 0] S_AXI_ARPROT,
input [4-1 : 0] S_AXI_ARQOS,
input [C_S_AXI_ARUSER_WIDTH-1 : 0]S_AXI_ARUSER,
input S_AXI_ARVALID,
output S_AXI_ARREADY,
// Slave Interface Read Data Ports
output reg [C_S_AXI_ID_WIDTH-1: 0] S_AXI_RID,
output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
output reg [2-1 : 0] S_AXI_RRESP,
output S_AXI_RLAST,
output [C_S_AXI_RUSER_WIDTH-1 : 0] S_AXI_RUSER,
output S_AXI_RVALID,
input S_AXI_RREADY
);
localparam AXBURST_FIXED = 2'b00;
localparam AXBURST_INCR = 2'b01;
localparam AXBURST_WRAP = 2'b10;
localparam RESP_OKAY = 2'b00;
localparam RESP_EXOKAY = 2'b01;
localparam RESP_SLVERR = 2'b10;
localparam RESP_DECERR = 2'b11;
localparam DATA_BUS_BYTES = (C_S_AXI_DATA_WIDTH / 8);
//localparam ADD_INC_OFFSET = log2(DATA_BUS_BYTES);
localparam ADD_INC_OFFSET = (DATA_BUS_BYTES==1) ? 0:
(DATA_BUS_BYTES==2) ? 1:
(DATA_BUS_BYTES==4) ? 2:
(DATA_BUS_BYTES==8) ? 3:
(DATA_BUS_BYTES==16) ? 4:
(DATA_BUS_BYTES==32) ? 5:
(DATA_BUS_BYTES==64) ? 6:
(DATA_BUS_BYTES==128) ? 7: 32'hxxxxxxxx;
// fifo depth for address
localparam AD_FIFO_DEPTH = 16;
// wad_fifo field
localparam WAD_FIFO_WIDTH = C_S_AXI_ADDR_WIDTH+5+C_S_AXI_ID_WIDTH-1+1;
localparam WAD_FIFO_AWID_HIGH = C_S_AXI_ADDR_WIDTH+5+C_S_AXI_ID_WIDTH-1;
localparam WAD_FIFO_AWID_LOW = C_S_AXI_ADDR_WIDTH+5;
localparam WAD_FIFO_AWBURST_HIGH = C_S_AXI_ADDR_WIDTH+4;
localparam WAD_FIFO_AWBURST_LOW = C_S_AXI_ADDR_WIDTH+3;
localparam WAD_FIFO_AWSIZE_HIGH = C_S_AXI_ADDR_WIDTH+2;
localparam WAD_FIFO_AWSIZE_LOW = C_S_AXI_ADDR_WIDTH;
localparam WAD_FIFO_ADDR_HIGH = C_S_AXI_ADDR_WIDTH-1;
localparam WAD_FIFO_ADDR_LOW = 0;
// wres_fifo field
localparam WRES_FIFO_WIDTH = 2+C_S_AXI_ID_WIDTH-1+1;
localparam WRES_FIFO_AWID_HIGH = 2+C_S_AXI_ID_WIDTH-1;
localparam WRES_FIFO_AWID_LOW = 2;
localparam WRES_FIFO_AWBURST_HIGH = 1;
localparam WRES_FIFO_AWBURST_LOW = 0;
// rad_fifo field
localparam RAD_FIFO_WIDTH = C_S_AXI_ADDR_WIDTH+13+C_S_AXI_ID_WIDTH-1+1;
localparam RAD_FIFO_ARID_HIGH = C_S_AXI_ADDR_WIDTH+13+C_S_AXI_ID_WIDTH-1;
localparam RAD_FIFO_ARID_LOW = C_S_AXI_ADDR_WIDTH+13;
localparam RAD_FIFO_ARBURST_HIGH = C_S_AXI_ADDR_WIDTH+12;
localparam RAD_FIFO_ARBURST_LOW = C_S_AXI_ADDR_WIDTH+11;
localparam RAD_FIFO_ARSIZE_HIGH = C_S_AXI_ADDR_WIDTH+10;
localparam RAD_FIFO_ARSIZE_LOW = C_S_AXI_ADDR_WIDTH+8;
localparam RAD_FIFO_ARLEN_HIGH = C_S_AXI_ADDR_WIDTH+7;
localparam RAD_FIFO_ARLEN_LOW = C_S_AXI_ADDR_WIDTH;
localparam RAD_FIFO_ADDR_HIGH = C_S_AXI_ADDR_WIDTH-1;
localparam RAD_FIFO_ADDR_LOW = 0;
// RAMの生成
localparam SLAVE_ADDR_NUMBER = 2 ** (C_OFFSET_WIDTH - ADD_INC_OFFSET);
reg [(C_S_AXI_DATA_WIDTH - 1):0] ram_array [0:(SLAVE_ADDR_NUMBER - 1)];
// for write transaction
// write_address_state
localparam IDLE_WRAD = 1'd0;
localparam AWR_ACCEPT = 1'd1;
reg wradr_cs;
// write_data_state
localparam IDLE_WRDT = 1'd0;
localparam WR_BURST = 1'd1;
reg wrdat_cs;
// write_response_state
localparam IDLE_WRES = 2'd0;
localparam WAIT_BVALID = 2'd1;
localparam BVALID_ASSERT = 2'd2;
reg [1:0] wrres_cs;
integer addr_inc_step_wr = 1;
reg awready;
reg [(C_OFFSET_WIDTH - 1):0] wr_addr;
reg [(C_S_AXI_ID_WIDTH - 1):0] wr_bid;
reg [1:0] wr_bresp;
reg wr_bvalid;
reg [15:0] m_seq16_wr;
reg wready;
// wready_state
localparam IDLE_WREADY = 2'd0;
localparam ASSERT_WREADY = 2'd1;
localparam DEASSERT_WREADY = 2'd2;
reg [1:0] cs_wready;
wire cdc_we;
wire wad_fifo_full;
wire wad_fifo_empty;
wire wad_fifo_almost_full;
wire wad_fifo_almost_empty;
wire wad_fifo_rd_en;
wire wad_fifo_wr_en;
wire [WAD_FIFO_WIDTH-1:0] wad_fifo_din;
wire [WAD_FIFO_WIDTH-1:0] wad_fifo_dout;
reg [15:0] m_seq16_wr_res;
reg [4:0] wr_resp_cnt;
// wres_fifo
wire wres_fifo_wr_en;
wire wres_fifo_full;
wire wres_fifo_empty;
wire wres_fifo_almost_full;
wire wres_fifo_almost_empty;
wire wres_fifo_rd_en;
wire [WRES_FIFO_WIDTH-1:0] wres_fifo_din;
wire [WRES_FIFO_WIDTH-1:0] wres_fifo_dout;
// for read transaction
// read_address_state
localparam IDLE_RDA = 1'd0;
localparam ARR_ACCEPT = 1'd1;
reg rdadr_cs;
// read_data_state
localparam IDLE_RDD = 1'd0;
localparam RD_BURST = 1'd1;
reg rddat_cs;
// read_last_state
localparam IDLE_RLAST = 1'd0;
localparam RLAST_ASSERT = 1'd1;
reg rdlast;
integer addr_inc_step_rd = 1;
reg arready;
reg [(C_OFFSET_WIDTH - 1):0] rd_addr;
reg [7:0] rd_axi_count;
reg rvalid;
reg rlast;
reg [15:0] m_seq16_rd;
// rvalid_state
localparam IDLE_RVALID = 2'd0;
localparam ASSERT_RVALID = 2'd1;
localparam DEASSERT_RVALID = 2'd2;
reg [1:0] cs_rvalid;
reg [(C_S_AXI_DATA_WIDTH - 1):0] read_data_count;
reg reset_1d;
reg reset_2d;
wire reset;
wire rad_fifo_full;
wire rad_fifo_empty;
wire rad_fifo_almost_full;
wire rad_fifo_almost_empty;
wire rad_fifo_rd_en;
wire rad_fifo_wr_en;
wire [RAD_FIFO_WIDTH-1:0] rad_fifo_din;
wire [RAD_FIFO_WIDTH-1:0] rad_fifo_dout;
// ram_array を初期化
initial begin
if (LOAD_RAM_INIT_FILE==1) begin
$readmemh(RAM_INIT_FILE, ram_array, 0, (SLAVE_ADDR_NUMBER - 1));
end
end
// ARESETN をACLK で同期化
always @ ( posedge ACLK ) begin
reset_1d <= ~ARESETN;
reset_2d <= reset_1d;
end
assign reset = reset_2d;
// AXI4バス Write Address State Machine
always @ ( posedge ACLK ) begin
if ( reset ) begin
wradr_cs <= IDLE_WRAD;
awready <= 1'b0;
end
else
case (wradr_cs)
IDLE_WRAD: if ((S_AXI_AWVALID == 1'b1) && (wad_fifo_full == 1'b0) && (wres_fifo_full == 1'b0)) // S_AXI_AWVALIDが1にアサートされた
begin
wradr_cs <= AWR_ACCEPT;
awready <= 1'b1;
end
AWR_ACCEPT: begin
wradr_cs <= IDLE_WRAD;
awready <= 1'b0;
end
endcase
end
assign S_AXI_AWREADY = (AWREADY_IS_USUALLY_HIGH==1) ? ~wad_fifo_full : awready;
// {S_AXI_AWID, S_AXI_AWBURST, S_AXI_AWSIZE, S_AXI_AWADDR}を保存しておく同期FIFO
assign wad_fifo_din = {S_AXI_AWID, S_AXI_AWBURST, S_AXI_AWSIZE, S_AXI_AWADDR};
assign wad_fifo_wr_en = (AWREADY_IS_USUALLY_HIGH==1) ? (S_AXI_AWVALID & ~wad_fifo_full) : awready;
sync_fifo #(
.C_MEMORY_SIZE (AD_FIFO_DEPTH),
.DATA_BUS_WIDTH (WAD_FIFO_WIDTH)
) wad_fifo (
.clk (ACLK),
.rst (reset),
.wr_en (wad_fifo_wr_en),
.din (wad_fifo_din),
.full (wad_fifo_full),
.almost_full (wad_fifo_almost_full),
.rd_en (wad_fifo_rd_en),
.dout (wad_fifo_dout),
.empty (wad_fifo_empty),
.almost_empty (wad_fifo_almost_empty)
);
assign wad_fifo_rd_en = (wready & S_AXI_WVALID & S_AXI_WLAST);
// AXI4バス Write Data State Machine
always @( posedge ACLK ) begin
if ( reset )
wrdat_cs <= IDLE_WRDT;
else
case (wrdat_cs)
IDLE_WRDT: if ( wad_fifo_empty == 1'b0 ) // AXI Writeアドレス転送の残りが1個以上ある
wrdat_cs <= WR_BURST;
WR_BURST : if ( S_AXI_WLAST & S_AXI_WVALID & wready ) // Write Transaction終了
wrdat_cs <= IDLE_WRDT;
endcase
end
// M系列による16ビット乱数生成関数
function [15:0] M_SEQ16_BFM_F;
input [15:0] mseq16in;
reg xor_result;
begin
xor_result = mseq16in[15] ^ mseq16in[12] ^ mseq16in[10] ^ mseq16in[8] ^
mseq16in[7] ^ mseq16in[6] ^ mseq16in[3] ^ mseq16in[2];
M_SEQ16_BFM_F = {mseq16in[14:0], xor_result};
end
endfunction
// m_seq_wr、16ビットのM系列を計算する
always @( posedge ACLK ) begin
if ( reset )
m_seq16_wr <= 16'b1;
else begin
if ( WRITE_RANDOM_WAIT ) begin // Write Transaction時にランダムなWaitを挿入する
if ( wrdat_cs == WR_BURST )
m_seq16_wr <= M_SEQ16_BFM_F(m_seq16_wr);
end
else // Wait無し
m_seq16_wr <= 16'b0;
end
end
// wready の処理、M系列を計算して128以上だったらWaitする。
always @( posedge ACLK ) begin
if ( reset ) begin
cs_wready <= IDLE_WREADY;
wready <= 1'b0;
end
else
case (cs_wready)
IDLE_WREADY: if ( (wrdat_cs == IDLE_WRDT) && (wad_fifo_empty == 1'b0) ) begin
if ( (m_seq16_wr[7] == 1'b0) && (wres_fifo_full==1'b0) ) begin
cs_wready <= ASSERT_WREADY;
wready <= 1'b1;
end
else begin
cs_wready <= DEASSERT_WREADY;
wready <= 1'b0;
end
end
ASSERT_WREADY: if ( (wrdat_cs == WR_BURST) && S_AXI_WLAST && S_AXI_WVALID ) begin
cs_wready <= IDLE_WREADY;
wready <= 1'b0;
end
else if ( (wrdat_cs == WR_BURST) && S_AXI_WVALID ) begin
if ((m_seq16_wr[7] == 1'b1) || (wres_fifo_full==1'b1)) begin
cs_wready <= DEASSERT_WREADY;
wready <= 1'b0;
end
end
DEASSERT_WREADY:if ( (m_seq16_wr[7] == 1'b0) && (wres_fifo_full==1'b0) ) begin
cs_wready <= ASSERT_WREADY;
wready <= 1'b1;
end
endcase
end
assign S_AXI_WREADY = wready;
assign cdc_we = ( (wrdat_cs == WR_BURST) && wready && S_AXI_WVALID );
// addr_inc_step_wrの処理
always @ ( posedge ACLK ) begin
if ( reset )
addr_inc_step_wr <= 1;
else begin
if ( (wrdat_cs == IDLE_WRDT) & (wad_fifo_empty == 1'b0) )
case (wad_fifo_dout[WAD_FIFO_AWSIZE_HIGH:WAD_FIFO_AWSIZE_LOW])
3'b000 : addr_inc_step_wr <= 1; // 8ビット転送
3'b001 : addr_inc_step_wr <= 2; // 16ビット転送
3'b010 : addr_inc_step_wr <= 4; // 32ビット転送
3'b011 : addr_inc_step_wr <= 8; // 64ビット転送
3'b100 : addr_inc_step_wr <= 16; // 128ビット転送
3'b101 : addr_inc_step_wr <= 32; // 256ビット転送
3'b110 : addr_inc_step_wr <= 64; // 512ビット転送
default: addr_inc_step_wr <= 128; // 1024ビット転送
endcase
end
end
// wr_addr の処理
always @ (posedge ACLK ) begin
if ( reset )
wr_addr <= 'b0;
else begin
if ( (wrdat_cs == IDLE_WRDT) && (wad_fifo_empty == 1'b0) )
wr_addr <= wad_fifo_dout[(C_OFFSET_WIDTH - 1):0];
else if ( (wrdat_cs == WR_BURST) && S_AXI_WVALID && wready ) // アドレスを進める
wr_addr <= (wr_addr + addr_inc_step_wr);
end
end
// Wirte Response FIFO (wres_fifo)
sync_fifo #(
.C_MEMORY_SIZE(AD_FIFO_DEPTH),
.DATA_BUS_WIDTH(WRES_FIFO_WIDTH)
) wres_fifo (
.clk(ACLK),
.rst(reset),
.wr_en(wres_fifo_wr_en),
.din(wres_fifo_din),
.full(wres_fifo_full),
.almost_full(wres_fifo_almost_full),
.rd_en(wres_fifo_rd_en),
.dout(wres_fifo_dout),
.empty(wres_fifo_empty),
.almost_empty(wres_fifo_almost_empty)
);
assign wres_fifo_wr_en = (S_AXI_WLAST & S_AXI_WVALID & wready) ? 1'b1 : 1'b0; // Write Transaction 終了
assign wres_fifo_din = {wad_fifo_dout[WAD_FIFO_AWID_HIGH:WAD_FIFO_AWID_LOW], wad_fifo_dout[WAD_FIFO_AWBURST_HIGH:WAD_FIFO_AWBURST_LOW]};
assign wres_fifo_rd_en = (wr_bvalid & S_AXI_BREADY) ? 1'b1 : 1'b0;
// S_AXI_BID の処理
assign S_AXI_BID = wres_fifo_dout[WRES_FIFO_AWID_HIGH:WRES_FIFO_AWID_LOW];
// S_AXI_BRESP の処理
// S_AXI_AWBURSTがINCRの時はOKAYを返す。それ以外はSLVERRを返す。
assign S_AXI_BRESP = (wres_fifo_dout[WRES_FIFO_AWBURST_HIGH:WRES_FIFO_AWBURST_LOW]==AXBURST_INCR) ? RESP_OKAY : RESP_SLVERR;
// wr_bvalid の処理
// wr_bvalid のアサートは、Write Data Channelの完了より必ず1クロックは遅延する
always @ ( posedge ACLK ) begin
if ( reset ) begin
wrres_cs <= IDLE_WRES;
wr_bvalid <= 1'b0;
end
else
case (wrres_cs)
IDLE_WRES: if ( wres_fifo_empty == 1'b0 ) begin // Write Transaction 終了
if ( (m_seq16_wr_res == 0) || (RANDOM_BVALID_WAIT == 0) ) begin
wrres_cs <= BVALID_ASSERT;
wr_bvalid <= 1'b1;
end
else
wrres_cs <= WAIT_BVALID;
end
WAIT_BVALID:if ( wr_resp_cnt == 0 ) begin
wrres_cs <= BVALID_ASSERT;
wr_bvalid <= 1'b1;
end
BVALID_ASSERT: if ( S_AXI_BREADY ) begin
wrres_cs <= IDLE_WRES;
wr_bvalid <= 1'b0;
end
endcase
end
assign S_AXI_BVALID = wr_bvalid;
assign S_AXI_BUSER = 'b0;
// wr_resp_cnt
always @ ( posedge ACLK ) begin
if ( reset )
wr_resp_cnt <= 'b0;
else begin
if ( (wrres_cs == IDLE_WRES) && (wres_fifo_empty==1'b0) )
wr_resp_cnt <= m_seq16_wr_res[4:0];
else if ( wr_resp_cnt!=0 )
wr_resp_cnt <= wr_resp_cnt - 1;
end
end
// m_seq_wr_res、16ビットのM系列を計算する
always @ ( posedge ACLK ) begin
if ( reset )
m_seq16_wr_res <= 16'b1;
else
m_seq16_wr_res <= M_SEQ16_BFM_F(m_seq16_wr_res);
end
// AXI4バス Read Address Transaction State Machine
always @ ( posedge ACLK ) begin
if ( reset ) begin
rdadr_cs <= IDLE_RDA;
arready <= 1'b0;
end
else
case (rdadr_cs)
IDLE_RDA: if ( (S_AXI_ARVALID == 1'b1) && (rad_fifo_full == 1'b0) ) begin // Read Transaction要求
rdadr_cs <= ARR_ACCEPT;
arready <= 1'b1;
end
ARR_ACCEPT: begin // S_AXI_ARREADYをアサート
rdadr_cs <= IDLE_RDA;
arready <= 1'b0;
end
endcase
end
assign S_AXI_ARREADY = (ARREADY_IS_USUALLY_HIGH==1) ? ~rad_fifo_full : arready;
// S_AXI_ARID & S_AXI_ARBURST & S_AXI_ARSIZE & S_AXI_ARLEN & S_AXI_ARADDR を保存しておく同期FIFO
assign rad_fifo_din ={S_AXI_ARID, S_AXI_ARBURST, S_AXI_ARSIZE, S_AXI_ARLEN, S_AXI_ARADDR};
assign rad_fifo_wr_en = (ARREADY_IS_USUALLY_HIGH==1) ? (S_AXI_ARVALID & ~rad_fifo_full) : arready;
sync_fifo #(
.C_MEMORY_SIZE (AD_FIFO_DEPTH),
.DATA_BUS_WIDTH (RAD_FIFO_WIDTH)
) rad_fifo
(
.clk (ACLK),
.rst (reset),
.wr_en (rad_fifo_wr_en),
.din (rad_fifo_din),
.full (rad_fifo_full),
.almost_full (rad_fifo_almost_full),
.rd_en (rad_fifo_rd_en),
.dout (rad_fifo_dout),
.empty (rad_fifo_empty),
.almost_empty (rad_fifo_almost_empty)
);
assign rad_fifo_rd_en = (rvalid & S_AXI_RREADY & rlast);
// AXI4バス Read Data Transaction State Machine
always @( posedge ACLK ) begin
if ( reset )
rddat_cs <= IDLE_RDD;
else
case (rddat_cs)
IDLE_RDD: if ( rad_fifo_empty == 1'b0 ) // AXI Read アドレス転送の残りが1個以上ある
rddat_cs <= RD_BURST;
RD_BURST: if ( (rd_axi_count == 0) && rvalid && S_AXI_RREADY ) // Read Transaction終了
rddat_cs <= IDLE_RDD;
endcase
end
// m_seq_rd、16ビットのM系列を計算する
always @ ( posedge ACLK ) begin
if ( reset )
m_seq16_rd <= 16'hffff;
else begin
if ( READ_RANDOM_WAIT) begin
if ( rddat_cs == RD_BURST )
m_seq16_rd <= M_SEQ16_BFM_F(m_seq16_rd);
end else
m_seq16_rd <= 16'b0;
end
end
// rvalidの処理、M系列を計算して128以上だったらWaitする
always @( posedge ACLK ) begin
if ( reset ) begin
cs_rvalid <= IDLE_RVALID;
rvalid <= 1'b0;
end
else
case (cs_rvalid)
IDLE_RVALID: if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) ) begin // 次はrd_burst
if ( m_seq16_rd[7] == 1'b0 ) begin
cs_rvalid <= ASSERT_RVALID;
rvalid <= 1'b1;
end
else begin
cs_rvalid <= DEASSERT_RVALID;
rvalid <= 1'b0;
end
end
ASSERT_RVALID: if ( (rddat_cs == RD_BURST) && rlast && S_AXI_RREADY ) begin // 終了
cs_rvalid <= IDLE_RVALID;
rvalid <= 1'b0;
end
else if ( (rddat_cs == RD_BURST) & S_AXI_RREADY ) begin // 1つのトランザクション終了
if ( m_seq16_rd[7] ) begin
cs_rvalid <= DEASSERT_RVALID;
rvalid <= 1'b0;
end
end
DEASSERT_RVALID:if ( m_seq16_rd[7] == 1'b0 ) begin
cs_rvalid <= ASSERT_RVALID;
rvalid <= 1'b1;
end
endcase
end
assign S_AXI_RVALID = rvalid;
// addr_inc_step_rdの処理
always @( posedge ACLK ) begin
if ( reset )
addr_inc_step_rd <= 1;
else begin
if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) )
case (rad_fifo_dout[RAD_FIFO_ARSIZE_HIGH:RAD_FIFO_ARSIZE_LOW])
3'b000: addr_inc_step_rd <= 1; // 8ビット転送
3'b001: addr_inc_step_rd <= 2; // 16ビット転送
3'b010: addr_inc_step_rd <= 4; // 32ビット転送
3'b011: addr_inc_step_rd <= 8; // 64ビット転送
3'b100: addr_inc_step_rd <= 16; // 128ビット転送
3'b101: addr_inc_step_rd <= 32; // 256ビット転送
3'b110: addr_inc_step_rd <= 64; // 512ビット転送
default:addr_inc_step_rd <= 128; // 1024ビット転送
endcase
end
end
// rd_addr の処理
always @ ( posedge ACLK ) begin
if ( reset )
rd_addr <= 'b0;
else begin
if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) )
rd_addr <= rad_fifo_dout[(C_OFFSET_WIDTH - 1):0];
else if ( (rddat_cs == RD_BURST) && S_AXI_RREADY && rvalid )
rd_addr <= (rd_addr + addr_inc_step_rd);
end
end
// rd_axi_countの処理(AXIバス側のデータカウント)
always @ ( posedge ACLK ) begin
if ( reset )
rd_axi_count <= 'b0;
else begin
if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) ) // rd_axi_countのロード
rd_axi_count <= rad_fifo_dout[RAD_FIFO_ARLEN_HIGH:RAD_FIFO_ARLEN_LOW];
else if ( (rddat_cs == RD_BURST) && rvalid && S_AXI_RREADY ) // Read Transactionが1つ終了
rd_axi_count <= rd_axi_count - 1;
end
end
// rdlast State Machine
always @ ( posedge ACLK ) begin
if ( reset ) begin
rdlast <= IDLE_RLAST;
rlast <= 1'b0;
end
else
case (rdlast)
IDLE_RLAST: if ( (rd_axi_count == 1) && rvalid && S_AXI_RREADY ) begin // バーストする場合
rdlast <= RLAST_ASSERT;
rlast <= 1'b1;
end
else if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) &&
(rad_fifo_dout[RAD_FIFO_ARLEN_HIGH:RAD_FIFO_ARLEN_LOW] == 0) ) begin // 転送数が1の場合
rdlast <= RLAST_ASSERT;
rlast <= 1'b1;
end
RLAST_ASSERT:if ( rvalid && S_AXI_RREADY ) begin // Read Transaction終了(rd_axi_count=0は決定)
rdlast <= IDLE_RLAST;
rlast <= 1'b0;
end
endcase
end
assign S_AXI_RLAST = rlast;
// S_AXI_RID, S_AXI_RUSER の処理
always @ ( posedge ACLK ) begin
if ( reset )
S_AXI_RID <= 'b0;
else begin
if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) )
S_AXI_RID <= rad_fifo_dout[RAD_FIFO_ARID_HIGH:RAD_FIFO_ARID_LOW];
end
end
assign S_AXI_RUSER = 'b0;
// S_AXI_RRESP は、S_AXI_ARBURST がINCR の場合はOKAYを返す。それ以外はSLVERRを返す。
always @( posedge ACLK ) begin
if ( reset )
S_AXI_RRESP <= 'b0;
else begin
if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) ) begin
if ((rad_fifo_dout[RAD_FIFO_ARBURST_HIGH:RAD_FIFO_ARBURST_LOW] == AXBURST_INCR))
S_AXI_RRESP <= RESP_OKAY;
else
S_AXI_RRESP <= RESP_SLVERR;
end
end
end
// RAM
integer i;
always @( posedge ACLK ) begin
if ( cdc_we ) begin :Block_Name_2
for (i=0; i<(C_S_AXI_DATA_WIDTH / 8); i=i+1) begin
if ( S_AXI_WSTRB[i] )
ram_array[wr_addr[(C_OFFSET_WIDTH - 1):ADD_INC_OFFSET]][(i * 8) +: 8]
<= S_AXI_WDATA[(i * 8) +: 8];
end
end
end
// Read Transaciton の時に +1 されたReadデータを使用する(Read 毎に+1)
always @( posedge ACLK ) begin
if ( reset )
read_data_count <= 'b0;
else begin
if ( (rddat_cs == RD_BURST) && rvalid && S_AXI_RREADY )
read_data_count <= read_data_count + 1;
end
end
assign S_AXI_RDATA = (READ_DATA_IS_INCREMENT == 0) ?
ram_array[rd_addr[(C_OFFSET_WIDTH - 1):ADD_INC_OFFSET]] : read_data_count;
endmodule
// Synchronous FIFO for Simulation
//
// 2013/11/08 by marsee
//
// ライセンスは二条項BSDライセンス (2-clause BSD license)とします。
//
`default_nettype none
module sync_fifo #(
parameter integer C_MEMORY_SIZE = 512, // Word (not byte), 2のn乗
parameter integer DATA_BUS_WIDTH = 32 // RAM Data Width
)
(
input wire clk,
input wire rst,
input wire wr_en,
input wire [DATA_BUS_WIDTH-1:0] din,
output wire full,
output wire almost_full,
input wire rd_en,
output wire [DATA_BUS_WIDTH-1:0] dout,
output wire empty,
output wire almost_empty
);
// 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] mem [0:C_MEMORY_SIZE-1];
reg [log2(C_MEMORY_SIZE)-1:0] mem_waddr = 0;
reg [log2(C_MEMORY_SIZE)-1:0] mem_raddr = 0;
reg [log2(C_MEMORY_SIZE)-1:0] rp = 0;
reg [log2(C_MEMORY_SIZE)-1:0] wp = 0;
wire [log2(C_MEMORY_SIZE)-1:0] plus_1 = 1;
wire [log2(C_MEMORY_SIZE)-1:0] plus_2 = 2;
wire almost_full_node;
wire almost_empty_node;
integer i;
// initialize RAM Data
initial begin
for (i=0; i<C_MEMORY_SIZE; i=i+1)
mem[i] = 0;
end
// Write
always @(posedge clk) begin
if (rst) begin
mem_waddr <= 0;
wp <= 0;
end else begin
if (wr_en) begin
mem_waddr <= mem_waddr + 1;
wp <= wp + 1;
end
end
end
always @(posedge clk) begin
if (wr_en) begin
mem[mem_waddr] <= din;
end
end
assign full = (wp+plus_1 == rp) ? 1'b1 : 1'b0;
assign almost_full_node = (wp+plus_2 == rp) ? 1'b1 : 1'b0;
assign almost_full = full | almost_full_node;
// Read
always @(posedge clk) begin
if (rst) begin
mem_raddr <= 0;
rp <= 0;
end else begin
if (rd_en) begin
mem_raddr <= mem_raddr + 1;
rp <= rp + 1;
end
end
end
assign dout = mem[mem_raddr];
assign empty = (wp == rp) ? 1'b1 : 1'b0;
assign almost_empty_node = (wp == rp+plus_1) ? 1'b1 : 1'b0;
assign almost_empty = empty | almost_empty_node;
endmodule
`default_nettype wire
-----------------------------------------------------------------------------
--
-- AXI Master用 Slave Bus Function Mode (BFM) by marsee
-- axi_slave_BFM_initf.vhd
--
-----------------------------------------------------------------------------
-- 2012/02/25 : S_AXI_AWBURST=1 (INCR) にのみ対応、AWSIZE, ARSIZE = 000 (1byte), 001 (2bytes), 010 (4bytes) のみ対応。
-- 2012/07/04 : READ_ONLY_TRANSACTION を追加。Read機能のみでも+1したデータを出力することが出来るように変更した。
-- sync_fifo を使用したオーバーラップ対応版
-- 2014/07/04 : M_AXIをスレーブに対応した名前のS_AXIに変更
-- 2014/07/16 : Write Respose Channel に sync_fifo を使用した
-- 2014/07/19 : RAM を初期化する初期化ファイルを追加(init_ram_data.txt)
-- 2014/07/20 : RAM 初期化ファイル名を generic に追加
-- 2014/08/31 : READ_RANDOM_WAIT=1 の時に、S_AXI_RREADY が S_AXI_RVALID に依存するバグをフィック。
-- WRITE_RANDOM_WAIT=1 の時に、S_AXI_WVALID が S_AXI_WREADY に依存するバグをフィック。
-- LOAD_RAM_INIT_FILE パラメータを追加
--
-- 2016/07/03 : AWREADY_IS_USUALLY_HIGH と ARREADY_IS_USUALLY_HIGH の2つのパラメータを追加 by marsee
--
-- ライセンスは二条項BSDライセンス (2-clause BSD license)とします。
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
package m_seq_bfm_pack is
function M_SEQ16_BFM_F(mseq16in : std_logic_vector
)return std_logic_vector;
end package m_seq_bfm_pack;
package body m_seq_bfm_pack is
function M_SEQ16_BFM_F(mseq16in : std_logic_vector
)return std_logic_vector is
variable mseq16 : std_logic_vector(15 downto 0);
variable xor_result : std_logic;
begin
xor_result := mseq16in(15) xor mseq16in(12) xor mseq16in(10) xor mseq16in(8) xor mseq16in(7) xor mseq16in(6) xor mseq16in(3) xor mseq16in(2);
mseq16 := mseq16in(14 downto 0) & xor_result;
return mseq16;
end M_SEQ16_BFM_F;
end m_seq_bfm_pack;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
use IEEE.math_real.all;
use STD.textio.all;
use IEEE.std_logic_textio.all;
library work;
use work.m_seq_bfm_pack.all;
--library unisim;
--use unisim.vcomponents.all;
entity axi_slave_bfm is
generic (
C_S_AXI_ID_WIDTH : integer := 1;
C_S_AXI_ADDR_WIDTH : integer := 32;
C_S_AXI_DATA_WIDTH : integer := 32;
C_S_AXI_AWUSER_WIDTH : integer := 1;
C_S_AXI_ARUSER_WIDTH : integer := 1;
C_S_AXI_WUSER_WIDTH : integer := 1;
C_S_AXI_RUSER_WIDTH : integer := 1;
C_S_AXI_BUSER_WIDTH : integer := 1;
C_S_AXI_TARGET : integer := 0;
C_OFFSET_WIDTH : integer := 10; -- 割り当てるRAMのアドレスのビット幅
C_S_AXI_BURST_LEN : integer := 256;
WRITE_RANDOM_WAIT : integer := 1; -- Write Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
READ_RANDOM_WAIT : integer := 0; -- Read Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
READ_DATA_IS_INCREMENT : integer := 0; -- ReadトランザクションでRAMの内容をReadする = 0(RAMにWriteしたものをReadする)、Readデータを+1する = 1(データは+1したデータをReadデータとして使用する
RANDOM_BVALID_WAIT : integer := 0; -- Write Data Transaction が終了した後で、BVALID をランダムにWaitする = 1、BVALID をランダムにWaitしない = 0, 31 ~ 0 クロックのWait
RAM_INIT_FILE : string := "init_ram_data.data"; -- RAM の初期化ファイル名
LOAD_RAM_INIT_FILE : integer := 0; -- RAM_INIT_FILE をLoadする - 1, Load しない - 0
AWREADY_IS_USUALLY_HIGH : integer := 1; -- AWRAEDY は通常はLow=0, High=1
ARREADY_IS_USUALLY_HIGH : integer := 1 -- AWRAEDY は通常はLow=0, High=1
);
port(
-- System Signals
ACLK : in std_logic;
ARESETN : in std_logic;
-- Master Interface Write Address Ports
S_AXI_AWID : in std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_AWADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_AWLEN : in std_logic_vector(8-1 downto 0);
S_AXI_AWSIZE : in std_logic_vector(3-1 downto 0);
S_AXI_AWBURST : in std_logic_vector(2-1 downto 0);
-- S_AXI_AWLOCK : in std_logic_vector(2-1 downto 0);
S_AXI_AWLOCK : in std_logic_vector(1 downto 0);
S_AXI_AWCACHE : in std_logic_vector(4-1 downto 0);
S_AXI_AWPROT : in std_logic_vector(3-1 downto 0);
S_AXI_AWQOS : in std_logic_vector(4-1 downto 0);
S_AXI_AWUSER : in std_logic_vector(C_S_AXI_AWUSER_WIDTH-1 downto 0);
S_AXI_AWVALID : in std_logic;
S_AXI_AWREADY : out std_logic;
-- Master Interface Write Data Ports
S_AXI_WDATA : in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_WSTRB : in std_logic_vector(C_S_AXI_DATA_WIDTH/8-1 downto 0);
S_AXI_WLAST : in std_logic;
S_AXI_WUSER : in std_logic_vector(C_S_AXI_WUSER_WIDTH-1 downto 0);
S_AXI_WVALID : in std_logic;
S_AXI_WREADY : out std_logic;
-- Master Interface Write Response Ports
S_AXI_BID : out std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_BRESP : out std_logic_vector(2-1 downto 0);
S_AXI_BUSER : out std_logic_vector(C_S_AXI_BUSER_WIDTH-1 downto 0);
S_AXI_BVALID : out std_logic;
S_AXI_BREADY : in std_logic;
-- Master Interface Read Address Ports
S_AXI_ARID : in std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_ARADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_ARLEN : in std_logic_vector(8-1 downto 0);
S_AXI_ARSIZE : in std_logic_vector(3-1 downto 0);
S_AXI_ARBURST : in std_logic_vector(2-1 downto 0);
S_AXI_ARLOCK : in std_logic_vector(2-1 downto 0);
S_AXI_ARCACHE : in std_logic_vector(4-1 downto 0);
S_AXI_ARPROT : in std_logic_vector(3-1 downto 0);
S_AXI_ARQOS : in std_logic_vector(4-1 downto 0);
S_AXI_ARUSER : in std_logic_vector(C_S_AXI_ARUSER_WIDTH-1 downto 0);
S_AXI_ARVALID : in std_logic;
S_AXI_ARREADY : out std_logic;
-- Master Interface Read Data Ports
S_AXI_RID : out std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_RDATA : out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_RRESP : out std_logic_vector(2-1 downto 0);
S_AXI_RLAST : out std_logic;
S_AXI_RUSER : out std_logic_vector(C_S_AXI_RUSER_WIDTH-1 downto 0);
S_AXI_RVALID : out std_logic;
S_AXI_RREADY : in std_logic
);
end axi_slave_bfm;
architecture implementation of axi_slave_bfm is
constant AxBURST_FIXED : std_logic_vector := "00";
constant AxBURST_INCR : std_logic_vector := "01";
constant AxBURST_WRAP : std_logic_vector := "10";
constant RESP_OKAY : std_logic_vector := "00";
constant RESP_EXOKAY : std_logic_vector := "01";
constant RESP_SLVERR : std_logic_vector := "10";
constant RESP_DECERR : std_logic_vector := "11";
constant DATA_BUS_BYTES : natural := C_S_AXI_DATA_WIDTH/8; -- データバスのビット幅
constant ADD_INC_OFFSET : natural := natural(log(real(DATA_BUS_BYTES), 2.0));
-- fifo depth for address
constant AD_FIFO_DEPTH : natural := 16;
-- wad_fifo field
constant WAD_FIFO_WIDTH : natural := C_S_AXI_ADDR_WIDTH+5+C_S_AXI_ID_WIDTH-1+1;
constant WAD_FIFO_AWID_HIGH : natural := C_S_AXI_ADDR_WIDTH+5+C_S_AXI_ID_WIDTH-1;
constant WAD_FIFO_AWID_LOW : natural := C_S_AXI_ADDR_WIDTH+5;
constant WAD_FIFO_AWBURST_HIGH : natural := C_S_AXI_ADDR_WIDTH+4;
constant WAD_FIFO_AWBURST_LOW : natural := C_S_AXI_ADDR_WIDTH+3;
constant WAD_FIFO_AWSIZE_HIGH : natural := C_S_AXI_ADDR_WIDTH+2;
constant WAD_FIFO_AWSIZE_LOW : natural := C_S_AXI_ADDR_WIDTH;
constant WAD_FIFO_ADDR_HIGH : natural := C_S_AXI_ADDR_WIDTH-1;
constant WAD_FIFO_ADDR_LOW : natural := 0;
-- wres_fifo field
constant WRES_FIFO_WIDTH : natural := 2+C_S_AXI_ID_WIDTH-1+1;
constant WRES_FIFO_AWID_HIGH : natural := 2+C_S_AXI_ID_WIDTH-1;
constant WRES_FIFO_AWID_LOW : natural := 2;
constant WRES_FIFO_AWBURST_HIGH : natural := 1;
constant WRES_FIFO_AWBURST_LOW : natural := 0;
-- rad_fifo field
constant RAD_FIFO_WIDTH : natural := C_S_AXI_ADDR_WIDTH+13+C_S_AXI_ID_WIDTH-1+1;
constant RAD_FIFO_ARID_HIGH : natural := C_S_AXI_ADDR_WIDTH+13+C_S_AXI_ID_WIDTH-1;
constant RAD_FIFO_ARID_LOW : natural := C_S_AXI_ADDR_WIDTH+13;
constant RAD_FIFO_ARBURST_HIGH : natural := C_S_AXI_ADDR_WIDTH+12;
constant RAD_FIFO_ARBURST_LOW : natural := C_S_AXI_ADDR_WIDTH+11;
constant RAD_FIFO_ARSIZE_HIGH : natural := C_S_AXI_ADDR_WIDTH+10;
constant RAD_FIFO_ARSIZE_LOW : natural := C_S_AXI_ADDR_WIDTH+8;
constant RAD_FIFO_ARLEN_HIGH : natural := C_S_AXI_ADDR_WIDTH+7;
constant RAD_FIFO_ARLEN_LOW : natural := C_S_AXI_ADDR_WIDTH;
constant RAD_FIFO_ADDR_HIGH : natural := C_S_AXI_ADDR_WIDTH-1;
constant RAD_FIFO_ADDR_LOW : natural := 0;
-- RAMの生成
constant SLAVE_ADDR_NUMBER : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (0 to SLAVE_ADDR_NUMBER-1) of std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
impure function InitRamFromFile (RamFileName : in string) return ram_array_def is
FILE RamFile : text is in RamFileName;
variable RamFileLine : line;
variable RAM : ram_array_def;
begin
for I in ram_array_def'range loop
if (LOAD_RAM_INIT_FILE=1) then
readline (RamFile, RamFileLine);
hread (RamFileLine, RAM(I));
end if;
end loop;
return RAM;
end function;
signal ram_array : ram_array_def := InitRamFromFile(RAM_INIT_FILE);
-- for write transaction
type write_address_state is (idle_wrad, awr_accept);
type write_data_state is (idle_wrdt, wr_burst);
type write_response_state is (idle_wres, wait_bvalid, bvalid_assert);
signal wradr_cs : write_address_state;
signal wrdat_cs : write_data_state;
signal wrres_cs : write_response_state;
signal addr_inc_step_wr : integer := 1;
signal awready : std_logic;
signal wr_addr : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal wr_bvalid : std_logic;
signal m_seq16_wr : std_logic_vector(15 downto 0);
signal wready : std_logic;
type wready_state is (idle_wready, assert_wready, deassert_wready);
signal cs_wready : wready_state;
signal cdc_we : std_logic;
signal wad_fifo_full, wad_fifo_empty : std_logic;
signal wad_fifo_almost_full, wad_fifo_almost_empty : std_logic;
signal wad_fifo_rd_en : std_logic;
signal wad_fifo_wr_en : std_logic;
signal wad_fifo_din : std_logic_vector(WAD_FIFO_WIDTH-1 downto 0);
signal wad_fifo_dout : std_logic_vector(WAD_FIFO_WIDTH-1 downto 0);
signal m_seq16_wr_res : std_logic_vector(15 downto 0);
signal wr_resp_cnt : std_logic_vector(4 downto 0);
signal wres_fifo_wr_en : std_logic;
signal wres_fifo_full, wres_fifo_empty : std_logic;
signal wres_fifo_almost_full, wres_fifo_almost_empty : std_logic;
signal wres_fifo_rd_en : std_logic;
signal wres_fifo_din : std_logic_vector(WRES_FIFO_WIDTH-1 downto 0);
signal wres_fifo_dout : std_logic_vector(WRES_FIFO_WIDTH-1 downto 0);
-- for read transaction
type read_address_state is (idle_rda, arr_accept);
type read_data_state is (idle_rdd, rd_burst);
type read_last_state is (idle_rlast, rlast_assert);
signal rdadr_cs : read_address_state;
signal rddat_cs : read_data_state;
signal rdlast : read_last_state;
signal addr_inc_step_rd : integer := 1;
signal arready : std_logic;
signal rd_addr : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal rd_axi_count : std_logic_vector(7 downto 0);
signal rvalid : std_logic;
signal rlast : std_logic;
signal m_seq16_rd : std_logic_vector(15 downto 0);
type rvalid_state is (idle_rvalid, assert_rvalid, deassert_rvalid);
signal cs_rvalid : rvalid_state;
signal read_data_count : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal reset_1d, reset_2d, reset : std_logic := '1';
signal rad_fifo_full, rad_fifo_empty : std_logic;
signal rad_fifo_almost_full, rad_fifo_almost_empty : std_logic;
signal rad_fifo_rd_en : std_logic;
signal rad_fifo_wr_en : std_logic;
signal rad_fifo_din : std_logic_vector(RAD_FIFO_WIDTH-1 downto 0);
signal rad_fifo_dout : std_logic_vector(RAD_FIFO_WIDTH-1 downto 0);
component sync_fifo generic (
constant C_MEMORY_SIZE : integer := 512; -- Word (not byte), 2のn乗
constant DATA_BUS_WIDTH : integer := 32 -- RAM Data Width
);
port (
clk : in std_logic;
rst : in std_logic;
wr_en : in std_logic;
din : in std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
full : out std_logic;
almost_full : out std_logic;
rd_en : in std_logic;
dout : out std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
empty : out std_logic;
almost_empty : out std_logic
);
end component;
begin
-- ARESETN をACLK で同期化
process (ACLK) begin
if ACLK'event and ACLK='1' then
reset_1d <= not ARESETN;
reset_2d <= reset_1d;
end if;
end process;
reset <= reset_2d;
-- AXI4バス Write Address State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wradr_cs <= idle_wrad;
awready <= '0';
else
case (wradr_cs) is
when idle_wrad =>
if S_AXI_AWVALID='1' and wad_fifo_full='0' and wres_fifo_full='0' then -- S_AXI_AWVALID が1にアサートされた
wradr_cs <= awr_accept;
awready <= '1';
end if;
when awr_accept => -- S_AXI_AWREADY をアサート
wradr_cs <= idle_wrad;
awready <= '0';
end case;
end if;
end if;
end process;
S_AXI_AWREADY <= not wad_fifo_full when AWREADY_IS_USUALLY_HIGH=1 else awready;
-- S_AXI_AWID & S_AXI_AWBURST & S_AXI_AWSIZE & S_AXI_AWADDR を保存しておく同期FIFO
wad_fifo_din <= (S_AXI_AWID & S_AXI_AWBURST & S_AXI_AWSIZE & S_AXI_AWADDR);
wad_fifo_wr_en <= (S_AXI_AWVALID and (not wad_fifo_full)) when AWREADY_IS_USUALLY_HIGH=1 else awready;
wad_fifo : sync_fifo generic map(
C_MEMORY_SIZE => AD_FIFO_DEPTH,
DATA_BUS_WIDTH => WAD_FIFO_WIDTH
) port map (
clk => ACLK,
rst => reset,
wr_en => wad_fifo_wr_en,
din => wad_fifo_din,
full => wad_fifo_full,
almost_full => wad_fifo_almost_full,
rd_en => wad_fifo_rd_en,
dout => wad_fifo_dout,
empty => wad_fifo_empty,
almost_empty => wad_fifo_almost_empty
);
wad_fifo_rd_en <= '1' when wready='1' and S_AXI_WVALID='1' and S_AXI_WLAST='1' else '0';
-- AXI4バス Write Data State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wrdat_cs <= idle_wrdt;
else
case( wrdat_cs ) is
when idle_wrdt =>
if wad_fifo_empty='0' then -- AXI Write アドレス転送の残りが1個以上ある
wrdat_cs <= wr_burst;
end if;
when wr_burst => -- Writeデータの転送
if S_AXI_WLAST='1' and S_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
wrdat_cs <= idle_wrdt;
end if;
when others =>
end case ;
end if;
end if;
end process;
-- m_seq_wr、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_wr <= (0 => '1', others => '0');
else
if WRITE_RANDOM_WAIT=1 then -- Write Transaction 時にランダムなWaitを挿入する
if wrdat_cs=wr_burst then
m_seq16_wr <= M_SEQ16_BFM_F(m_seq16_wr);
end if;
else -- Wait無し
m_seq16_wr <= (others => '0');
end if;
end if;
end if;
end process;
-- wready の処理、M系列を計算して128以上だったらWaitする。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
cs_wready <= idle_wready;
wready <= '0';
else
case (cs_wready) is
when idle_wready =>
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then -- 次はwr_burst
if m_seq16_wr(7)='0' and wres_fifo_full='0' then -- wready='1'
cs_wready <= assert_wready;
wready <= '1';
else -- m_seq16_wr(7)='1' then -- wready='0'
cs_wready <= deassert_wready;
wready <= '0';
end if;
end if;
when assert_wready => -- 一度wreadyがアサートされたら、1つのトランザクションが終了するまでwready='1'
if wrdat_cs=wr_burst and S_AXI_WLAST='1' and S_AXI_WVALID='1' then -- 終了
cs_wready <= idle_wready;
wready <= '0';
elsif wrdat_cs=wr_burst and S_AXI_WVALID='1' then -- 1つのトランザクション終了。
if m_seq16_wr(7)='1' or wres_fifo_full='1' then
cs_wready <= deassert_wready;
wready <= '0';
end if;
end if;
when deassert_wready =>
if m_seq16_wr(7)='0' and wres_fifo_full='0' then -- wready='1'
cs_wready <= assert_wready;
wready <= '1';
end if;
end case;
end if;
end if;
end process;
S_AXI_WREADY <= wready;
cdc_we <= '1' when wrdat_cs=wr_burst and wready='1' and S_AXI_WVALID='1' else '0';
-- addr_inc_step_wr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
addr_inc_step_wr <= 1;
else
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then
case (wad_fifo_dout(WAD_FIFO_AWSIZE_HIGH downto WAD_FIFO_AWSIZE_LOW)) is
when "000" => -- 8ビット転送
addr_inc_step_wr <= 1;
when "001" => -- 16ビット転送
addr_inc_step_wr <= 2;
when "010" => -- 32ビット転送
addr_inc_step_wr <= 4;
when "011" => -- 64ビット転送
addr_inc_step_wr <= 8;
when "100" => -- 128ビット転送
addr_inc_step_wr <= 16;
when "101" => -- 256ビット転送
addr_inc_step_wr <= 32;
when "110" => -- 512ビット転送
addr_inc_step_wr <= 64;
when others => --"111" => -- 1024ビット転送
addr_inc_step_wr <= 128;
end case;
end if;
end if;
end if;
end process;
-- wr_addr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_addr <= (others => '0');
else
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then
wr_addr <= wad_fifo_dout(C_OFFSET_WIDTH-1 downto 0);
elsif wrdat_cs=wr_burst and S_AXI_WVALID='1' and wready='1' then -- アドレスを進める
wr_addr <= std_logic_vector(unsigned(wr_addr) + addr_inc_step_wr);
end if;
end if;
end if;
end process;
-- Wirte Response FIFO (wres_fifo)
wres_fifo : sync_fifo generic map(
C_MEMORY_SIZE => AD_FIFO_DEPTH,
DATA_BUS_WIDTH => WRES_FIFO_WIDTH
) port map (
clk => ACLK,
rst => reset,
wr_en => wres_fifo_wr_en,
din => wres_fifo_din,
full => wres_fifo_full,
almost_full => wres_fifo_almost_full,
rd_en => wres_fifo_rd_en,
dout => wres_fifo_dout,
empty => wres_fifo_empty,
almost_empty => wres_fifo_almost_empty
);
wres_fifo_wr_en <= '1' when S_AXI_WLAST='1' and S_AXI_WVALID='1' and wready='1' else '0'; -- Write Transaction 終了
wres_fifo_din <= (wad_fifo_dout(WAD_FIFO_AWID_HIGH downto WAD_FIFO_AWID_LOW) & wad_fifo_dout(WAD_FIFO_AWBURST_HIGH downto WAD_FIFO_AWBURST_LOW));
wres_fifo_rd_en <= '1' when wr_bvalid='1' and S_AXI_BREADY='1' and wres_fifo_empty='0' else '0';
-- S_AXI_BID の処理
S_AXI_BID <= wres_fifo_dout(WRES_FIFO_AWID_HIGH downto WRES_FIFO_AWID_LOW);
-- S_AXI_BRESP の処理
-- S_AXI_AWBURSTがINCRの時はOKAYを返す。それ以外はSLVERRを返す。
S_AXI_BRESP <= RESP_OKAY when wres_fifo_dout(WRES_FIFO_AWBURST_HIGH downto WRES_FIFO_AWBURST_LOW)=AxBURST_INCR else RESP_SLVERR;
-- wr_bvalid の処理
-- wr_bvalid のアサートは、Write Data Channelの完了より必ず1クロックは遅延する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wrres_cs <= idle_wres;
wr_bvalid <= '0';
else
case( wrres_cs ) is
when idle_wres =>
if wres_fifo_empty='0' then -- Write Transaction 終了
if unsigned(m_seq16_wr_res) = 0 or RANDOM_BVALID_WAIT=0 then
wrres_cs <= bvalid_assert;
wr_bvalid <= '1';
else
wrres_cs <= wait_bvalid;
end if;
end if;
when wait_bvalid =>
if unsigned(wr_resp_cnt) = 0 then
wrres_cs <= bvalid_assert;
wr_bvalid <= '1';
end if;
when bvalid_assert =>
if (S_AXI_BREADY='1') then
wrres_cs <= idle_wres;
wr_bvalid <= '0';
end if;
when others =>
end case ;
end if;
end if;
end process;
S_AXI_BVALID <= wr_bvalid;
S_AXI_BUSER <= (others => '0');
-- wr_resp_cnt
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_resp_cnt <= (others => '0');
else
if wrres_cs=idle_wres and wres_fifo_empty='0' then
wr_resp_cnt <= m_seq16_wr_res(4 downto 0);
elsif unsigned(wr_resp_cnt) /= 0 then
wr_resp_cnt <= std_logic_vector(unsigned(wr_resp_cnt) - 1);
end if;
end if;
end if;
end process;
-- m_seq_wr_res、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_wr_res <= (0 => '1', others => '0');
else
m_seq16_wr_res <= M_SEQ16_BFM_F(m_seq16_wr_res);
end if;
end if;
end process;
-- AXI4バス Read Address Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdadr_cs <= idle_rda;
arready <= '0';
else
case (rdadr_cs) is
when idle_rda =>
if S_AXI_ARVALID='1' and rad_fifo_full='0' then -- Read Transaction 要求
rdadr_cs <= arr_accept;
arready <= '1';
end if;
when arr_accept => -- S_AXI_ARREADY をアサート
rdadr_cs <= idle_rda;
arready <= '0';
end case;
end if;
end if;
end process;
S_AXI_ARREADY <= not rad_fifo_full when ARREADY_IS_USUALLY_HIGH=1 else arready;
-- S_AXI_ARID & S_AXI_ARBURST & S_AXI_ARSIZE & S_AXI_ARLEN & S_AXI_ARADDR を保存しておく同期FIFO
rad_fifo_din <= (S_AXI_ARID & S_AXI_ARBURST & S_AXI_ARSIZE & S_AXI_ARLEN & S_AXI_ARADDR);
rad_fifo_wr_en <= (S_AXI_ARVALID and (not rad_fifo_full)) when ARREADY_IS_USUALLY_HIGH=1 else arready;
rad_fifo : sync_fifo generic map (
C_MEMORY_SIZE => AD_FIFO_DEPTH,
DATA_BUS_WIDTH => RAD_FIFO_WIDTH
) port map (
clk => ACLK,
rst => reset,
wr_en => rad_fifo_wr_en,
din => rad_fifo_din,
full => rad_fifo_full,
almost_full => rad_fifo_almost_full,
rd_en => rad_fifo_rd_en,
dout => rad_fifo_dout,
empty => rad_fifo_empty,
almost_empty => rad_fifo_almost_empty
);
rad_fifo_rd_en <= '1' when rvalid='1' and S_AXI_RREADY='1' and rlast='1' else '0';
-- AXI4バス Read Data Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rddat_cs <= idle_rdd;
else
case (rddat_cs) is
when idle_rdd =>
if rad_fifo_empty='0' then -- AXI Read アドレス転送の残りが1個以上ある
rddat_cs <= rd_burst;
end if;
when rd_burst =>
if unsigned(rd_axi_count)=0 and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction 終了
rddat_cs <= idle_rdd;
end if;
end case;
end if;
end if;
end process;
-- m_seq_rd、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_rd <= (others => '1'); -- Writeとシードを変更する
else
if READ_RANDOM_WAIT=1 then -- Read Transaciton のデータ転送でランダムなWaitを挿入する場合
if rddat_cs=rd_burst then
m_seq16_rd <= M_SEQ16_BFM_F(m_seq16_rd);
end if;
else -- Wati無し
m_seq16_rd <= (others => '0');
end if;
end if;
end if;
end process;
-- rvalid の処理、M系列を計算して128以上だったらWaitする。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
cs_rvalid <= idle_rvalid;
rvalid <= '0';
else
case (cs_rvalid) is
when idle_rvalid =>
if rddat_cs=idle_rdd and rad_fifo_empty='0' then -- 次はrd_burst
if m_seq16_rd(7)='0' then -- rvalid='1'
cs_rvalid <= assert_rvalid;
rvalid <= '1';
else -- m_seq16_rd(7)='1' then -- rvalid='0'
cs_rvalid <= deassert_rvalid;
rvalid <= '0';
end if;
end if;
when assert_rvalid => -- 一度rvalidがアサートされたら、1つのトランザクションが終了するまでrvalid='1'
if rddat_cs=rd_burst and rlast='1' and S_AXI_RREADY='1' then -- 終了
cs_rvalid <= idle_rvalid;
rvalid <= '0';
elsif rddat_cs=rd_burst and S_AXI_RREADY='1' then -- 1つのトランザクション終了。
if m_seq16_rd(7)='1' then
cs_rvalid <= deassert_rvalid;
rvalid <= '0';
end if;
end if;
when deassert_rvalid =>
if m_seq16_rd(7)='0' then -- rvalid='1'
cs_rvalid <= assert_rvalid;
rvalid <= '1';
end if;
end case;
end if;
end if;
end process;
S_AXI_RVALID <= rvalid;
-- addr_inc_step_rd の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
addr_inc_step_rd <= 1;
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
case (rad_fifo_dout(RAD_FIFO_ARSIZE_HIGH downto RAD_FIFO_ARSIZE_LOW)) is
when "000" => -- 8ビット転送
addr_inc_step_rd <= 1;
when "001" => -- 16ビット転送
addr_inc_step_rd <= 2;
when "010" => -- 32ビット転送
addr_inc_step_rd <= 4;
when "011" => -- 64ビット転送
addr_inc_step_rd <= 8;
when "100" => -- 128ビット転送
addr_inc_step_rd <= 16;
when "101" => -- 256ビット転送
addr_inc_step_rd <= 32;
when "110" => -- 512ビット転送
addr_inc_step_rd <= 64;
when others => -- "111" => -- 1024ビット転送
addr_inc_step_rd <= 128;
end case;
end if;
end if;
end if;
end process;
-- rd_addr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_addr <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
rd_addr <= rad_fifo_dout(C_OFFSET_WIDTH-1 downto 0);
elsif rddat_cs=rd_burst and S_AXI_RREADY='1' and rvalid='1' then
rd_addr <= std_logic_vector(unsigned(rd_addr) + addr_inc_step_rd);
end if;
end if;
end if;
end process;
-- rd_axi_count の処理(AXIバス側のデータカウント)
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_axi_count <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then -- rd_axi_count のロード
rd_axi_count <= rad_fifo_dout(RAD_FIFO_ARLEN_HIGH downto RAD_FIFO_ARLEN_LOW);
elsif rddat_cs=rd_burst and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction が1つ終了
rd_axi_count <= std_logic_vector(unsigned(rd_axi_count) - 1);
end if;
end if;
end if;
end process;
-- rdlast State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdlast <= idle_rlast;
rlast <= '0';
else
case (rdlast) is
when idle_rlast =>
if unsigned(rd_axi_count)=1 and rvalid='1' and S_AXI_RREADY='1' then -- バーストする場合
rdlast <= rlast_assert;
rlast <= '1';
elsif rddat_cs=idle_rdd and rad_fifo_empty='0' and unsigned(rad_fifo_dout(RAD_FIFO_ARLEN_HIGH downto RAD_FIFO_ARLEN_LOW))=0 then -- 転送数が1の場合
rdlast <= rlast_assert;
rlast <= '1';
end if;
when rlast_assert =>
if rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction 終了(rd_axi_count=0は決定)
rdlast <= idle_rlast;
rlast <= '0';
end if;
end case;
end if;
end if;
end process;
S_AXI_RLAST <= rlast;
-- S_AXI_RID, S_AXI_RUSER の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
S_AXI_RID <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
S_AXI_RID <= rad_fifo_dout(RAD_FIFO_ARID_HIGH downto RAD_FIFO_ARID_LOW);
end if;
end if;
end if;
end process;
S_AXI_RUSER <= (others => '0');
-- S_AXI_RRESP は、S_AXI_ARBURST がINCR の場合はOKAYを返す。それ以外はSLVERRを返す。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
S_AXI_RRESP <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
if rad_fifo_dout(RAD_FIFO_ARBURST_HIGH downto RAD_FIFO_ARBURST_LOW)=AxBURST_INCR then
S_AXI_RRESP <= RESP_OKAY;
else
S_AXI_RRESP <= RESP_SLVERR;
end if;
end if;
end if;
end if;
end process;
-- RAM
process (ACLK) begin
if ACLK'event and ACLK='1' then
if cdc_we='1' then
for i in 0 to C_S_AXI_DATA_WIDTH/8-1 loop
if S_AXI_WSTRB(i)='1' then -- Byte Enable
ram_array(TO_INTEGER(unsigned(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))))(i*8+7 downto i*8) <= S_AXI_WDATA(i*8+7 downto i*8);
end if;
end loop;
end if;
end if;
end process;
-- Read Transaciton の時に +1 されたReadデータを使用する(Read 毎に+1)
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
read_data_count <= (others => '0');
else
if rddat_cs=rd_burst and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction が1つ終了
read_data_count <= std_logic_vector(unsigned(read_data_count) + 1);
end if;
end if;
end if;
end process;
S_AXI_RDATA <= ram_array(TO_INTEGER(unsigned(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))) when READ_DATA_IS_INCREMENT=0 else read_data_count;
end implementation;
00000000
00000001
00000002
00000003
00000004
00000005
00000006
00000007
00000008
00000009
0000000A
0000000B
0000000C
0000000D
0000000E
0000000F
00000010
00000011
00000012
00000013
00000014
00000015
00000016
00000017
00000018
00000019
0000001A
0000001B
0000001C
0000001D
0000001E
0000001F
00000020
00000021
00000022
00000023
00000024
00000025
00000026
00000027
00000028
00000029
0000002A
0000002B
0000002C
0000002D
0000002E
0000002F
00000030
00000031
00000032
00000033
00000034
00000035
00000036
00000037
00000038
00000039
0000003A
0000003B
0000003C
0000003D
0000003E
0000003F
00000040
00000041
00000042
00000043
00000044
00000045
00000046
00000047
00000048
00000049
0000004A
0000004B
0000004C
0000004D
0000004E
0000004F
00000050
00000051
00000052
00000053
00000054
00000055
00000056
00000057
00000058
00000059
0000005A
0000005B
0000005C
0000005D
0000005E
0000005F
00000060
00000061
00000062
00000063
00000064
00000065
00000066
00000067
00000068
00000069
0000006A
0000006B
0000006C
0000006D
0000006E
0000006F
00000070
00000071
00000072
00000073
00000074
00000075
00000076
00000077
00000078
00000079
0000007A
0000007B
0000007C
0000007D
0000007E
0000007F
00000080
00000081
00000082
00000083
00000084
00000085
00000086
00000087
00000088
00000089
0000008A
0000008B
0000008C
0000008D
0000008E
0000008F
00000090
00000091
00000092
00000093
00000094
00000095
00000096
00000097
00000098
00000099
0000009A
0000009B
0000009C
0000009D
0000009E
0000009F
000000A0
000000A1
000000A2
000000A3
000000A4
000000A5
000000A6
000000A7
000000A8
000000A9
000000AA
000000AB
000000AC
000000AD
000000AE
000000AF
000000B0
000000B1
000000B2
000000B3
000000B4
000000B5
000000B6
000000B7
000000B8
000000B9
000000BA
000000BB
000000BC
000000BD
000000BE
000000BF
000000C0
000000C1
000000C2
000000C3
000000C4
000000C5
000000C6
000000C7
000000C8
000000C9
000000CA
000000CB
000000CC
000000CD
000000CE
000000CF
000000D0
000000D1
000000D2
000000D3
000000D4
000000D5
000000D6
000000D7
000000D8
000000D9
000000DA
000000DB
000000DC
000000DD
000000DE
000000DF
000000E0
000000E1
000000E2
000000E3
000000E4
000000E5
000000E6
000000E7
000000E8
000000E9
000000EA
000000EB
000000EC
000000ED
000000EE
000000EF
000000F0
000000F1
000000F2
000000F3
000000F4
000000F5
000000F6
000000F7
000000F8
000000F9
000000FA
000000FB
000000FC
000000FD
000000FE
000000FF
-- Synchronous FIFO for Simulation
--
-- 2014/07/03 by marsee
--
-- ライセンスは二条項BSDライセンス (2-clause BSD license)とします。
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
use IEEE.math_real.all;
entity sync_fifo is
generic (
C_MEMORY_SIZE : integer := 512; -- Word (not byte), 2のn乗
DATA_BUS_WIDTH : integer := 32 -- RAM Data Width
);
port (
clk : in std_logic;
rst : in std_logic;
wr_en : in std_logic;
din : in std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
full : out std_logic;
almost_full : out std_logic;
rd_en : in std_logic;
dout : out std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
empty : out std_logic;
almost_empty : out std_logic
);
end sync_fifo;
architecture RTL of sync_fifo is
constant C_MEMORY_LENGTH : natural := natural(ceil(log(real(C_MEMORY_SIZE), 2.0))); -- C_MEMORY_SIZEの2進数の桁数
type mem_type is array (0 to C_MEMORY_SIZE-1) of std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
signal mem : mem_type := (OTHERS => (OTHERS => '0'));
signal mem_waddr : std_logic_vector(C_MEMORY_LENGTH-1 downto 0) := (others => '0');
signal mem_raddr : std_logic_vector(C_MEMORY_LENGTH-1 downto 0) := (others => '0');
signal rp : std_logic_vector(C_MEMORY_LENGTH-1 downto 0) := (others => '0');
signal wp : std_logic_vector(C_MEMORY_LENGTH-1 downto 0) := (others => '0');
signal almost_full_node : std_logic;
signal almost_empty_node : std_logic;
signal full_node : std_logic;
signal empty_node : std_logic;
begin
-- Write
process (clk) begin
if clk'event and clk='1' then
if rst='1' then
mem_waddr <= (others => '0');
wp <= (others => '0');
else
if wr_en='1' then
mem_waddr <= std_logic_vector(unsigned(mem_waddr) + 1);
wp <= std_logic_vector(unsigned(wp) + 1);
end if;
end if;
end if;
end process;
process (clk) begin
if clk'event and clk='1' then
if wr_en='1' then
mem(TO_INTEGER(unsigned(mem_waddr))) <= din;
end if;
end if;
end process;
full_node <= '1' when std_logic_vector(unsigned(wp)+1)=rp else '0';
full <= full_node;
almost_full_node <= '1' when std_logic_vector(unsigned(wp)+2)=rp else '0';
almost_full <= full_node or almost_full_node;
-- Read
process (clk) begin
if clk'event and clk='1' then
if rst='1' then
mem_raddr <= (others => '0');
rp <= (others => '0');
else
if rd_en='1' then
mem_raddr <= std_logic_vector(unsigned(mem_raddr) + 1);
rp <= std_logic_vector(unsigned(rp) + 1);
end if;
end if;
end if;
end process;
dout <= mem(TO_INTEGER(unsigned(mem_raddr)));
empty_node <= '1' when wp=rp else '0';
empty <= empty_node;
almost_empty_node <= '1' when wp=std_logic_vector(unsigned(rp)+1) else '0';
almost_empty <= empty_node or almost_empty_node;
end RTL;
IOBUF mt9d111_iic_sda_iobuf
(.I(mt9d111_iic_sda_o),
.IO(mt9d111_iic_sda_io),
.O(mt9d111_iic_sda_i),
.T(outp));
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | - | - | - |