(注)今回のブログでは、”Zynq-7000 EPP Concepts, Tools, and Techniques A Hands-On Guide to Effective Embedded System Design UG873 (v14.1) May 31, 2012”の19ページからの”Embedded System Design Using the Zynq Processing System and Programmable Logic”チュートリアル(通称、チュートリアル2)で作成したビットファイルでコンフィギュレーションされた回路をZynqのLinux上から動作させている。
このチュートリアルについては、”Zynq-7000(ZC702)のチュートリアル2をやってみた1(XPSプロジェクトの生成)”の記事とそれに続く記事を参照のこと。
#define MIO_GPIO_BASE 0xE000A000
#define AXI_GPIO_BASE 0x41200000
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
// I/O access
volatile unsigned *setup_io(off_t addr);
int main()
{
volatile unsigned *mask_data_0_lsw, *mask_data_0_msw;
volatile unsigned *data_0, *data_0_ro;
volatile unsigned *dirm_0, *oen_0;
volatile unsigned *mio_gpio;
volatile unsigned *axi_gpio, *axi_gpio_tri;
int axi_gpio_val, axi_gpio_val_old;
mio_gpio = setup_io((off_t)MIO_GPIO_BASE);
axi_gpio = setup_io((off_t)AXI_GPIO_BASE);
mask_data_0_lsw = mio_gpio;
mask_data_0_msw = mio_gpio + 1; // 0x4番地
data_0 = mio_gpio + 0x10; // 0x40番地
data_0_ro = mio_gpio + 0x18; // 0x60番地
dirm_0 = mio_gpio + 0x81; // 0x204番地
oen_0 = mio_gpio + 0x82; // 0x208番地
axi_gpio_tri = axi_gpio + 1; // 0x4番地
*(dirm_0) = *(dirm_0)|0x400; // gpio[10]を出力に設定
*(oen_0) = *(oen_0)|0x400; // gpio[10]をイネーブル
*(axi_gpio_tri) = 0x1; // axi_gpio入力設定
printf("AXI_GPIO_TRI = %x\n", *(axi_gpio_tri));
printf("MASK_DATA_0_LSW = %x\n", *(mask_data_0_lsw));
printf("MASK_DATA_0_MSW = %x\n", *(mask_data_0_msw));
printf("DATA_0 = %x\n", *(data_0));
printf("DATA_0_RO = %x\n", *(data_0_ro));
printf("DIRM_0 = %x\n", *(dirm_0));
printf("OEN_0 = %x\n", *(oen_0));
*(data_0) = *(data_0)&(~(0x400)); // DS23 (LED) 消灯
printf("DATA_0 = %x\n", *(data_0));
axi_gpio_val_old = *(axi_gpio);
while(1){
axi_gpio_val = *(axi_gpio);
if (axi_gpio_val)
*(data_0) = *(data_0)|(0x400); // DS23点灯
else
*(data_0) = *(data_0)&(~(0x400)); // DS23消灯
if (!axi_gpio_val && axi_gpio_val_old)
break; // axi_gpio が1から0になった立下りでループを抜ける
axi_gpio_val_old = axi_gpio_val;
}
printf("AXI_GPIO = %x\n", *(axi_gpio));
printf("Hello World\n");
return 0;
}
volatile unsigned *setup_io(off_t mapped_addr)
// void setup_io()
int mem_fd;
char *gpio_mem, *gpio_map;
gpio_map = (unsigned char *)mmap(
(caddr_t)gpio_mem,
BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
mapped_addr
);
// gpio = (volatile unsigned *)gpio_map;
return((volatile unsigned *)gpio_map);
zynq> gdbserver :1234 /Apps/linux_hello_world_0.elf null
Process /Apps/linux_hello_world_0.elf created; pid = 655
Listening on port 1234
Remote debugging from host 10.10.70.121
AXI_GPIO_TRI = 1
MASK_DATA_0_LSW = 2ab2
MASK_DATA_0_MSW = 681
DATA_0 = 6812ab2
DATA_0_RO = 6802a32
DIRM_0 = 480
OEN_0 = 480
DATA_0 = 6c12ab2
AXI_GPIO = 0
Hello World
Child exited with status 0
GDBserver exiting
zynq>
zynq> exit
#define GPIO_BASE 0xE000A000
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
int mem_fd;
char *gpio_mem, *gpio_map;
// I/O access
volatile unsigned *gpio;
void setup_io();
int main()
{
setup_io();
volatile unsigned *mask_data_0_lsw, *mask_data_0_msw;
volatile unsigned *data_0, *data_0_ro;
volatile unsigned *dirm_0, *oen_0;
mask_data_0_lsw = gpio;
mask_data_0_msw = gpio + 1; // 0x4番地
data_0 = gpio + 0x10; // 0x40番地
data_0_ro = gpio + 0x18; // 0x60番地
dirm_0 = gpio + 0x81; // 0x204番地
oen_0 = gpio + 0x82; // 0x208番地
*(dirm_0) = *(dirm_0)|0x400; // gpio[0]を出力に設定
*(oen_0) = *(oen_0)|0x400; // gpio[0]をイネーブル
printf("MASK_DATA_0_LSW = %x\n", *(mask_data_0_lsw));
printf("MASK_DATA_0_MSW = %x\n", *(mask_data_0_msw));
printf("DATA_0 = %x\n", *(data_0));
printf("DATA_0_RO = %x\n", *(data_0_ro));
printf("DIRM_0 = %x\n", *(dirm_0));
printf("OEN_0 = %x\n", *(oen_0));
*(data_0) = *(data_0)&(~(0x400)); // gpio[10]を0にする。DS23(LED)を消灯
printf("DATA_0 = %x\n", *(data_0));
printf("Hello World\n");
return 0;
}
MASK_DATA_0_LSW = 2eb2
MASK_DATA_0_MSW = 6c1
DATA_0 = 6c12eb2
DATA_0_RO = 6c12e32
DIRM_0 = 480
OEN_0 = 480
DATA_0 = 6c02ab2
zynq> cd Apps
zynq> ls -l
total 0
-rw-r--r-- 1 root 0 0 Jan 1 00:29 linux_hello_world_0.elf
zynq> ls -l
total 59
-rwxr-xr-x 1 root 0 58513 Jan 1 00:35 linux_hello_world_0.elf
/* Definitions for peripheral PS7_GPIO_0 */
#define XPAR_PS7_GPIO_0_DEVICE_ID 0
#define XPAR_PS7_GPIO_0_BASEADDR 0xE000A000
#define XPAR_PS7_GPIO_0_HIGHADDR 0xE000AFFF
# Connect to Push Button "SW7"
NET processing_system7_0_GPIO_pin IOSTANDARD=LVCMOS25 | LOC=F19;
# Connect to Push Button "SW5"
NET axi_gpio_0_GPIO_IO_pin IOSTANDARD=LVCMOS25 | LOC=G19;
/* Definitions for peripheral AXI_GPIO_0 */
#define XPAR_AXI_GPIO_0_BASEADDR 0x41200000
#define XPAR_AXI_GPIO_0_HIGHADDR 0x4120FFFF
#define XPAR_AXI_GPIO_0_DEVICE_ID 0
#define XPAR_AXI_GPIO_0_INTERRUPT_PRESENT 0
#define XPAR_AXI_GPIO_0_IS_DUAL 0
FSBL, Video hacked version 1.0
video stuff starting to run
Reset and Initialize the FMC devices ...
Config is 6A
3A Config is 6A
3B Config is 6A
3C Config is 6A
3D Config is 6A
De-skew is 6A
U-Boot 2010.09-01918-g068cc03 (Jan 20 2012 - 14:02:15)
Xilinx Pele Emulation Platform
DRAM: 256 MiB
## Unknown FLASH on Bank 1 - Size = 0x00000000 = 0 MB
Flash: 0 Bytes
MMC: SDHCI: 0
Using default environment
In: serial
Out: serial
Err: serial
Hit any key to stop autoboot: 0
Copying Linux from SD to RAM...
Device: SDHCI
Manufacturer ID: 3
OEM: 5344
Name: SU08G
Tran Speed: 25000000
Rd Block Len: 512
SD version 1.10
High Capacity: Yes
Capacity: 7948206080
Bus Width: 1-bit
reading zImage
2020464 bytes read
reading devicetree.dtb
2347 bytes read
reading ramdisk8M.image.gz
2500546 bytes read
Trying to set up GEM link...
Resetting PHY...
PHY reset complete.
Waiting for PHY to complete auto-negotiation...
Link is now at 100Mbps!
ping failed; host 10.10.70.101 is not alive
## Starting application at 0x00008000 ...
Uncompressing Linux... done, booting the kernel.
Linux version 3.0.0 (djoja@ubuntu) (gcc version 4.5.1 (Sourcery G++ Lite 2010.09-62) ) #54 SMP PREEMPT Thu Jan 19 17:24:27 PST 2012
CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=18c5387d
CPU: VIPT nonaliasing data cache, VIPT aliasing instruction cache
Machine: Xilinx Zynq Platform, model: Xilinx Zynq ZC770 - V&C dt1 - minimum)
Memory policy: ECC disabled, Data cache writealloc
PERCPU: Embedded 7 pages/cpu @c180a000 s4928 r8192 d15552 u32768
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 256000
Kernel command line: console=ttyPS0,115200 root=/dev/ram rw initrd=0x800000,8M ip=192.168.1.10
PID hash table entries: 2048 (order: 1, 8192 bytes)
Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
Memory: 240MB 768MB = 1008MB total
Memory: 1011248k/1011248k available, 37328k reserved, 655360K highmem
Virtual kernel memory layout:
vector : 0xffff0000 - 0xffff1000 ( 4 kB)
fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
DMA : 0xffc00000 - 0xffe00000 ( 2 MB)
vmalloc : 0xd8800000 - 0xe0000000 ( 120 MB)
lowmem : 0xc0000000 - 0xd8000000 ( 384 MB)
pkmap : 0xbfe00000 - 0xc0000000 ( 2 MB)
modules : 0xbf000000 - 0xbfe00000 ( 14 MB)
.init : 0xc0008000 - 0xc002b000 ( 140 kB)
.text : 0xc002b000 - 0xc03b3bc0 (3619 kB)
.data : 0xc03b4000 - 0xc03dbe00 ( 160 kB)
.bss : 0xc03dbe24 - 0xc03f1e4c ( 89 kB)
Preemptible hierarchical RCU implementation.
Verbose stalled-CPUs detection is disabled.
NR_IRQS:246
xlnx,ps7-ttc-1.00.a #0 at 0xd8800000, irq=43
Console: colour dummy device 80x30
Calibrating delay loop... 1594.16 BogoMIPS (lpj=7970816)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
Calibrating local timer... 399.20MHz.
hw perfevents: enabled with ARMv7 Cortex-A9 PMU driver, 7 counters available
CPU1: Booted secondary processor
Brought up 2 CPUs
SMP: Total of 2 processors activated (3188.32 BogoMIPS).
devtmpfs: initialized
NET: Registered protocol family 16
L310 cache controller enabled
l2x0: 8 ways, CACHE_ID 0x410000c8, AUX_CTRL 0x72060000, Cache size: 524288 B
registering platform device 'pl330' id 0
registering platform device 'arm-pmu' id 0
hw-breakpoint: found 6 breakpoint and 1 watchpoint registers.
hw-breakpoint: 1 breakpoint(s) reserved for watchpoint single-step.
hw-breakpoint: maximum watchpoint size is 4 bytes.
bio: create slabat 0
xgpiops e000a000.gpio: gpio at 0xe000a000 mapped to 0xd8808000
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
Switching to clocksource xttcpss_timer1
NET: Registered protocol family 2
IP route cache hash table entries: 16384 (order: 4, 65536 bytes)
TCP established hash table entries: 65536 (order: 7, 524288 bytes)
TCP bind hash table entries: 65536 (order: 7, 786432 bytes)
TCP: Hash tables configured (established 65536 bind 65536)
TCP reno registered
UDP hash table entries: 256 (order: 1, 8192 bytes)
UDP-Lite hash table entries: 256 (order: 1, 8192 bytes)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
Trying to unpack rootfs image as initramfs...
rootfs image is not initramfs (no cpio magic); looks like an initrd
Freeing initrd memory: 8192K
PMU: registered new PMU device of type 0
xscugtimer xscugtimer.0: ioremap f8f00200 to d880a200 with size 400
pl330 dev 0 probe success
highmem bounce pool size: 64 pages
JFFS2 version 2.2. (NAND) (SUMMARY) c 2001-2006 Red Hat, Inc.
msgmni has been set to 711
io scheduler noop registered
io scheduler deadline registered
io scheduler cfq registered (default)
e0001000.uart: ttyPS0 at MMIO 0xe0001000 (irq = 82) is a xuartps
console [ttyPS0] enabled
brd: module loaded
loop: module loaded
m25p80 spi0.1: unrecognized JEDEC id ffffff
xspips e0007000.spi: at 0xE0007000 mapped to 0xD8860000, irq=81
m25p80 spi1.0: n25q128 (16384 Kbytes)
Creating 7 MTD partitions on "serial_flash":
0x000000000000-0x000000080000 : "qspi-fsbl"
0x000000080000-0x000000100000 : "qspi-u-boot"
0x000000100000-0x000000600000 : "qspi-linux"
0x000000600000-0x000000620000 : "qspi-device-tree"
0x000000620000-0x000000700000 : "qspi-user"
0x000000700000-0x000000800000 : "qspi-scratch"
0x000000800000-0x000001000000 : "qspi-rootfs"
xqspips e000d000.spi: at 0xE000D000 mapped to 0xD8862000, irq=51
GEM: BASEADDRESS hw: e000b000 virt: d8864000
XEMACPS mii bus: probed
GEM: phydev d7966c00, phydev->phy_id 0x1410e40, phydev->addr 0x7
GEM: MAC addr 00:00:00:00:00:00
xemacps e000b000.eth: invalid address, use assigned
MAC updated 82:36:7f:74:92:ae
eth0, pdev->id -1, baseaddr 0xe000b000, irq 54
eth0, phy_addr 0x7, phy_id 0x01410e40
eth0, attach [Generic PHY] phy driver
ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
xusbps-ehci xusbps-ehci.0: Xilinx PS USB EHCI Host Controller
xusbps-ehci xusbps-ehci.0: new USB bus registered, assigned bus number 1
xusbps-ehci xusbps-ehci.0: irq 53, io mem 0x00000000
xusbps-ehci xusbps-ehci.0: USB 2.0 started, EHCI 1.00
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
Initializing USB Mass Storage driver...
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
Xilinx PS USB Device Controller driver (Apr 01, 2011)
mousedev: PS/2 mouse device common for all mice
at24 0-0050: 256 byte 24c02 EEPROM, writable, 1 bytes/write
xi2cps e0004000.i2c: 400 kHz mmio e0004000 irq 57
sdhci: Secure Digital Host Controller Interface driver
sdhci: Copyright(c) Pierre Ossman
mmc0: Invalid maximum block size, assuming 512 bytes
mmc0: SDHCI controller on e0100000.sdhci [e0100000.sdhci] using DMA
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
TCP cubic registered
NET: Registered protocol family 17
VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 4
Registering SWP/SWPB emulation handler
drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
GEM: lp->tx_bd ffdfb000 lp->tx_bd_dma 170ee000 lp->tx_skb d7b064a0
GEM: lp->rx_bd ffdfc000 lp->rx_bd_dma 170ed000 lp->rx_skb d7b063a0
GEM: MAC 0x747f3682, 0x0000ae92, 82:36:7f:74:92:ae
mmc0: new SDHC card at address e624
mmcblk0: mmc0:e624 SU08G 7.40 GiB
mmcblk0: p1
GEM: mc addr 0x1:0x0:0x5e:0x0:0x0:0x1
IP-Config: Guessing netmask 255.255.255.0
IP-Config: Complete:
device=eth0, addr=192.168.1.10, mask=255.255.255.0, gw=255.255.255.255,
host=192.168.1.10, domain=, nis-domain=(none),
bootserver=255.255.255.255, rootserver=255.255.255.255, rootpath=
RAMDISK: gzip image found at block 0
VFS: Mounted root (ext2 filesystem) on device 1:0.
devtmpfs: mounted
Starting rcS...
++ Mounting filesystem
++ Setting up mdev
++ Starting telnet daemon
++ Starting http daemon
++ Starting ftp daemon
++ Starting dropbear (ssh) daemon
rcS Complete
zynq>
main()関数 はソフトを実行するエントリポイントです。main() 関数は初期化とシステムの周辺デバイスの設定をします。EMIOインターフェースを使用して、そのようなAXI GPIOおよびPS GPIOなど、さまざまなユースケースを実行するために選択する手順を持っています。シリアル端末上の命令にで、異なるユースケースを選択することができます。
ソフトウェア実行の手順
1.AXI GPIOモジュールを初期化。
2.ボード上のSW5プッシュボタンに接続されている入力ピンとして、AXI GPIOピンの方向コントロールを設定する。ピン配置は、システムの作成時にユーザー制約ファイル(UCF)でLOC制約を使用して固定されている。
3.デバイスIDが0のAXI TIMERモジュールを初期化。
4.AXI timer ISRにコールバック関数を対応付ける。
この関数は、タイマ割り込みが発生するたびに呼び出される。コールバック関数はDS23 LEDをスイッチし、割り込みフラグをセットする。
main()関数は実行を停止する割り込みフラグを使用して、タイマー割り込みを待ち、再起動実行。
5.リセット間にタイマー設定値をタイマーにロード。
6.割り込みモードやAuto Reload mode などのタイマーオプションを設定。
7.PSセクションのGPIOを初期化
8.PSセクションGPIOのチャネル0、ピン番号10を設定する。これはMIOピンにマッピングされ、ボード上のLED"DS23"に接続された出力ピンだ。
9.PSセクションGPIOのチャネル2、ピン番号0を設定する。これはEMIOインターフェースを介してPLサイドに接続されたSW7プッシュポタンスイッチだ。
10.Snoop control unit Global Interrupt controllerを初期化。ID '91'割り込みの割り込みルーチンを登録。例外ハンドラを登録して、割り込み許可。
11. シリアル端末経由で選択されたAXI GPIO または PS GPIO ユースケースを元にシーケンスを実行。
ソフトウェアは、シリアル端末からの選択でプロシージャを実行する。
シリアル端末を経由しての使用例を選択した後は、端末上の指示に従ってボード上のプッシュボタンを押す必要がある。そうすると、'DS23'LEDが消灯、タイマーがスタートし、タイマー割り込みが来るまでウエイトする関数が呼ばれる。タイマー割り込みが起こったら'DS23'LEDを点灯して実行を再スタートする。
(英語に自信がないので、間違っていたらお知らせください)
`default_nettype none
`timescale 100ps / 1ps
// bitmap_disp_cntrler_axi_master_tb.v
// 2012/07/03
module bitmap_disp_cntrler_axi_master_tb;
// Inputs
wire ACLK;
wire ARESETN;
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 [63: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 [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 [63:0] M_AXI_WDATA;
wire [7: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 pixclk;
wire TMDS_tx_clk_p;
wire TMDS_tx_clk_n;
wire TMDS_tx_2_G_p;
wire TMDS_tx_2_G_n;
wire TMDS_tx_1_R_p;
wire TMDS_tx_1_R_n;
wire TMDS_tx_0_B_p;
wire TMDS_tx_0_B_n;
// Instantiate the Unit Under Test (UUT_MASTER)
bitmap_disp_cntrler_axi_master uut_master (
.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),
.pixclk(pixclk),
.TMDS_tx_clk_p(TMDS_tx_clk_p),
.TMDS_tx_clk_n(TMDS_tx_clk_n),
.TMDS_tx_2_G_p(TMDS_tx_2_G_p),
.TMDS_tx_2_G_n(TMDS_tx_2_G_n),
.TMDS_tx_1_R_p(TMDS_tx_1_R_p),
.TMDS_tx_1_R_n(TMDS_tx_1_R_n),
.TMDS_tx_0_B_p(TMDS_tx_0_B_p),
.TMDS_tx_0_B_n(TMDS_tx_0_B_n)
);
defparam uut_master.bitmap_disp_eng_inst.INIT_COUNT_VAL = 20; // 初期化時のWaitタイマー
// 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)
);
// clk_gen のインスタンス(pixclk)
clk_gen #(
.CLK_PERIOD(250), // 25nsec, 40MHz
.CLK_DUTY_CYCLE(0.5),
.CLK_OFFSET(0),
.START_STATE(1'b0)
) pixclk_i (
.clk_out(pixclk)
);
// reset_gen のインスタンス
reset_gen #(
.RESET_STATE(1'b0),
.RESET_TIME(1000) // 100nsec
) RESETi (
.reset_out(ARESETN)
);
// Instantiate the Unit Under Test (UUT_slave)
axi_master_bfm #(
.C_M_AXI_DATA_WIDTH(64),
.READ_ONLY_TRANSACTION(1) // Read Transaciton のみ使用する = 1(データは+1したデータをReadデータとして使用する
) 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(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
);
begin
initial begin
reset_out = RESET_STATE;
#RESET_TIME;
reset_out = ~RESET_STATE;
end
end
endmodule
`default_nettype wire
-----------------------------------------------------------------------------
--
-- AXI Master用 Bus Function Mode (BFM)
--
-----------------------------------------------------------------------------
-- 2012/02/25 : M_AXI_AWBURST=1 (INCR) にのみ対応、AWSIZE, ARSIZE = 000 (1byte), 001 (2bytes), 010 (4bytes) のみ対応。
-- 2012/07/04 : READ_ONLY_TRANSACTION を追加。Read機能のみでも+1したデータを出力することが出来るように変更した。
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.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use IEEE.math_real.all;
library work;
use work.m_seq_bfm_pack.all;
--library unisim;
--use unisim.vcomponents.all;
entity axi_master_bfm is
generic (
C_M_AXI_ID_WIDTH : integer := 1;
C_M_AXI_ADDR_WIDTH : integer := 32;
C_M_AXI_DATA_WIDTH : integer := 32;
C_M_AXI_AWUSER_WIDTH : integer := 1;
C_M_AXI_ARUSER_WIDTH : integer := 1;
C_M_AXI_WUSER_WIDTH : integer := 1;
C_M_AXI_RUSER_WIDTH : integer := 1;
C_M_AXI_BUSER_WIDTH : integer := 1;
C_M_AXI_TARGET : integer := 0;
C_OFFSET_WIDTH : integer := 10; -- 割り当てるRAMのアドレスのビット幅
C_M_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_ONLY_TRANSACTION : integer := 0 -- Read, Write Transaciton 双方を使用する = 0(RAMにWriteしたものをReadする)、Read Transaciton のみ使用する = 1(データは+1したデータをReadデータとして使用する
);
port(
-- System Signals
ACLK : in std_logic;
ARESETN : in std_logic;
-- Master Interface Write Address Ports
M_AXI_AWID : in std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
M_AXI_AWADDR : in std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
M_AXI_AWLEN : in std_logic_vector(8-1 downto 0);
M_AXI_AWSIZE : in std_logic_vector(3-1 downto 0);
M_AXI_AWBURST : in std_logic_vector(2-1 downto 0);
-- M_AXI_AWLOCK : in std_logic_vector(2-1 downto 0);
M_AXI_AWLOCK : in std_logic;
M_AXI_AWCACHE : in std_logic_vector(4-1 downto 0);
M_AXI_AWPROT : in std_logic_vector(3-1 downto 0);
M_AXI_AWQOS : in std_logic_vector(4-1 downto 0);
M_AXI_AWUSER : in std_logic_vector(C_M_AXI_AWUSER_WIDTH-1 downto 0);
M_AXI_AWVALID : in std_logic;
M_AXI_AWREADY : out std_logic;
-- Master Interface Write Data Ports
M_AXI_WDATA : in std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
M_AXI_WSTRB : in std_logic_vector(C_M_AXI_DATA_WIDTH/8-1 downto 0);
M_AXI_WLAST : in std_logic;
M_AXI_WUSER : in std_logic_vector(C_M_AXI_WUSER_WIDTH-1 downto 0);
M_AXI_WVALID : in std_logic;
M_AXI_WREADY : out std_logic;
-- Master Interface Write Response Ports
M_AXI_BID : out std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
M_AXI_BRESP : out std_logic_vector(2-1 downto 0);
M_AXI_BUSER : out std_logic_vector(C_M_AXI_BUSER_WIDTH-1 downto 0);
M_AXI_BVALID : out std_logic;
M_AXI_BREADY : in std_logic;
-- Master Interface Read Address Ports
M_AXI_ARID : in std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
M_AXI_ARADDR : in std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
M_AXI_ARLEN : in std_logic_vector(8-1 downto 0);
M_AXI_ARSIZE : in std_logic_vector(3-1 downto 0);
M_AXI_ARBURST : in std_logic_vector(2-1 downto 0);
M_AXI_ARLOCK : in std_logic_vector(2-1 downto 0);
M_AXI_ARCACHE : in std_logic_vector(4-1 downto 0);
M_AXI_ARPROT : in std_logic_vector(3-1 downto 0);
M_AXI_ARQOS : in std_logic_vector(4-1 downto 0);
M_AXI_ARUSER : in std_logic_vector(C_M_AXI_ARUSER_WIDTH-1 downto 0);
M_AXI_ARVALID : in std_logic;
M_AXI_ARREADY : out std_logic;
-- Master Interface Read Data Ports
M_AXI_RID : out std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
M_AXI_RDATA : out std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
M_AXI_RRESP : out std_logic_vector(2-1 downto 0);
M_AXI_RLAST : out std_logic;
M_AXI_RUSER : out std_logic_vector(C_M_AXI_RUSER_WIDTH-1 downto 0);
M_AXI_RVALID : out std_logic;
M_AXI_RREADY : in std_logic
);
end axi_master_bfm;
architecture implementation of axi_master_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_M_AXI_DATA_WIDTH/8; -- データバスのビット幅
constant ADD_INC_OFFSET : natural := natural(log(real(DATA_BUS_BYTES), 2.0));
-- RAMの生成
constant SLAVE_ADDR_NUMBER : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def := (others => (others => '0'));
-- for write transaction
type write_transaction_state is (idle_wr, awr_wait, awr_accept, wr_burst);
type write_response_state is (idle_wres, bvalid_assert);
type write_wready_state is (idle_wrdy, wready_assert);
signal wrt_cs : write_transaction_state;
signal wrres : write_response_state;
signal wrwr : write_wready_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_bid : std_logic_vector(C_M_AXI_ID_WIDTH-1 downto 0);
signal wr_bresp : std_logic_vector(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;
-- for read transaction
type read_transaction_state is (idle_rd, arr_wait, arr_accept, rd_burst);
type read_last_state is (idle_rlast, rlast_assert);
signal rdt_cs : read_transaction_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_M_AXI_DATA_WIDTH-1 downto 0);
signal reset_1d, reset_2d, reset : std_logic := '1';
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 Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wrt_cs <= idle_wr;
awready <= '0';
else
case (wrt_cs) is
when idle_wr =>
if M_AXI_AWVALID='1' then -- M_AXI_AWVALID が1にアサートされた
if rdt_cs=idle_rd then -- Read Transaction が終了している(Writeの方が優先順位が高い)
wrt_cs <= awr_accept;
awready <= '1';
else -- Read Transaction が終了していないのでWait
wrt_cs <= awr_wait;
end if;
end if;
when awr_wait => -- Read Transaction の終了待ち
if rdt_cs=idle_rd or rdt_cs=arr_wait then -- Read Transaction が終了
wrt_cs <= awr_accept;
awready <= '1';
end if;
when awr_accept => -- M_AXI_AWREADY をアサート
wrt_cs <= wr_burst;
awready <= '0';
when wr_burst => -- Writeデータの転送
if M_AXI_WLAST='1' and M_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
wrt_cs <= idle_wr;
end if;
end case;
end if;
end if;
end process;
M_AXI_AWREADY <= awready;
-- 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 wrt_cs=wr_burst and M_AXI_WVALID='1' 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 wrt_cs=awr_accept then -- 次はwr_burst
if m_seq16_wr(7)='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 wrt_cs=wr_burst and M_AXI_WLAST='1' and M_AXI_WVALID='1' then -- 終了
cs_wready <= idle_wready;
wready <= '0';
elsif wrt_cs=wr_burst and M_AXI_WVALID='1' then -- 1つのトランザクション終了。
if m_seq16_wr(7)='1' then
cs_wready <= deassert_wready;
wready <= '0';
end if;
end if;
when deassert_wready =>
if m_seq16_wr(7)='0' then -- wready='1'
cs_wready <= assert_wready;
wready <= '1';
end if;
end case;
end if;
end if;
end process;
M_AXI_WREADY <= wready;
cdc_we <= '1' when wrt_cs=wr_burst and wready='1' and M_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 wrt_cs=awr_accept then
case (M_AXI_AWSIZE) 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 wrt_cs=awr_accept then
wr_addr <= M_AXI_AWADDR(C_OFFSET_WIDTH-1 downto 0);
elsif wrt_cs=wr_burst and M_AXI_WVALID='1' and wready='1' then -- アドレスを進める
wr_addr <= wr_addr + addr_inc_step_wr;
end if;
end if;
end if;
end process;
-- wr_bid の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_bid <= "0";
else
if wrt_cs=awr_accept then
wr_bid <= M_AXI_AWID;
end if;
end if;
end if;
end process;
M_AXI_BID <= wr_bid;
-- wr_bresp の処理
-- M_AXI_AWBURSTがINCRの時はOKAYを返す。それ以外はSLVERRを返す。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_bresp <= (others => '0');
else
if wrt_cs=awr_accept then
if M_AXI_AWBURST=AxBURST_INCR then -- バーストタイプがアドレス・インクリメントタイプ
wr_bresp <= RESP_OKAY; -- Write Transaction は成功
else
wr_bresp <= RESP_SLVERR; -- エラー
end if;
end if;
end if;
end if;
end process;
M_AXI_BRESP <= wr_bresp;
-- wr_bvalid の処理
-- Write Transaction State Machineには含まない。axi_master のシミュレーションを見ると1クロックで終了しているので、長い間、Master側の都合でWaitしていることは考えない。
-- 次のWrite転送まで遅延しているようであれば、Write Transaction State Machine に入れてブロックすることも考える必要がある。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_bvalid <= '0';
else
if M_AXI_WLAST='1' and M_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
wr_bvalid <= '1';
elsif wr_bvalid='1' and M_AXI_BREADY='1' then -- wr_bvalid が1でMaster側のReadyも1ならばWrite resonse channel の転送も終了
wr_bvalid <= '0';
end if;
end if;
end if;
end process;
M_AXI_BVALID <= wr_bvalid;
M_AXI_BUSER <= (others => '0');
-- AXI4バス Read Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdt_cs <= idle_rd;
arready <= '0';
else
case (rdt_cs) is
when idle_rd =>
if M_AXI_ARVALID='1' then -- Read Transaction 要求
if wrt_cs=idle_wr and M_AXI_AWVALID='0' then -- Write Transaction State Machine がidle でWrite要求もない
rdt_cs <= arr_accept;
arready <= '1';
else -- Write Transaction が終了していないのでWait
rdt_cs <= arr_wait;
end if;
end if;
when arr_wait => -- Write Transaction の終了待ち
if wrt_cs=idle_wr and M_AXI_AWVALID='0' then -- Write Transaction State Machine がidle でWrite要求もない
rdt_cs <= arr_accept;
arready <= '1';
end if;
when arr_accept => -- M_AXI_ARREADY をアサート
rdt_cs <= rd_burst;
arready <= '0';
when rd_burst => -- Readデータの転送
if rd_axi_count=0 and rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction 終了
rdt_cs <= idle_rd;
end if;
end case;
end if;
end if;
end process;
M_AXI_ARREADY <= arready;
-- 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 rdt_cs=rd_burst and M_AXI_RREADY='1' 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 rdt_cs=arr_accept 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 rdt_cs=rd_burst and rlast='1' and M_AXI_RREADY='1' then -- 終了
cs_rvalid <= idle_rvalid;
rvalid <= '0';
elsif rdt_cs=rd_burst and M_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;
M_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 rdt_cs=arr_accept then
case (M_AXI_ARSIZE) 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 rdt_cs=arr_accept then
rd_addr <= M_AXI_ARADDR(C_OFFSET_WIDTH-1 downto 0);
elsif rdt_cs=rd_burst and M_AXI_RREADY='1' and rvalid='1' then
rd_addr <= 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 rdt_cs=arr_accept then -- rd_axi_count のロード
rd_axi_count <= M_AXI_ARLEN;
elsif rdt_cs=rd_burst and rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction が1つ終了
rd_axi_count <= 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 rd_axi_count=1 and rvalid='1' and M_AXI_RREADY='1' then -- バーストする場合
rdlast <= rlast_assert;
rlast <= '1';
elsif rdt_cs=arr_accept and M_AXI_ARLEN=0 then -- 転送数が1の場合
rdlast <= rlast_assert;
rlast <= '1';
end if;
when rlast_assert =>
if rvalid='1' and M_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;
M_AXI_RLAST <= rlast;
-- M_AXI_RID, M_AXI_RUSER の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
M_AXI_RID <= (others => '0');
else
if rdt_cs=arr_accept then
M_AXI_RID <= M_AXI_ARID;
end if;
end if;
end if;
end process;
M_AXI_RUSER <= (others => '0');
-- M_AXI_RRESP は、M_AXI_ARBURST がINCR の場合はOKAYを返す。それ以外はSLVERRを返す。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
M_AXI_RRESP <= (others => '0');
else
if rdt_cs=arr_accept then
if M_AXI_ARBURST=AxBURST_INCR then
M_AXI_RRESP <= RESP_OKAY;
else
M_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_M_AXI_DATA_WIDTH/8-1 loop
if M_AXI_WSTRB(i)='1' then -- Byte Enable
ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= M_AXI_WDATA(i*8+7 downto i*8);
end if;
end loop;
end if;
end if;
end process;
-- Read Transaciton のみの場合のReadデータ(Transction 毎に+1)
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
read_data_count <= (others => '0');
else
if rdt_cs=rd_burst and rvalid='1' and M_AXI_RREADY='1' then -- Read Transaction が1つ終了
read_data_count <= read_data_count + 1;
end if;
end if;
end if;
end process;
M_AXI_RDATA <= ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))) when READ_ONLY_TRANSACTION=0 else read_data_count;
end implementation;
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
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 | 31 | - | - | - | - |