2020年10月28日水曜日

petalinuxの設定内容を読む,devicetreeカスタム方法

devicetreeのカスタム方法について調査。

基本的にはXSAファイルをmeta-xilinx-toolに渡すと基本的な設定ファイルは抽出されそう。 なのでsystem-user.dtsiでuio設定などを追加で記載すれば良さそう。

新しいマシンを定義して、既存のultra96設定を呼び出すようにしてみる。

意外といけそうなので、とりあえずvanilla-pealinuxをultra96向けにするものを書いてみるか。

参考ページ https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/61669922/Customizing+Device+Trees+in+Xilinx+Yocto

2020年10月27日火曜日

petalinuxの設定内容を読むその4,zcu102-zynqmp.conf

meta-xilinx/meta-xilinx-bsp/conf/machine/zcu102-zynqmp.confを確認していく。

まずはコード。QEMU関連の設定前までを確認する。

#@TYPE: Machine
#@NAME: zcu102-zynqmp
#@DESCRIPTION: Machine support for ZCU102 Evaluation Board.

SOC_VARIANT ?= "eg"

require conf/machine/include/tune-zynqmp.inc
require conf/machine/include/machine-xilinx-overrides.inc
require conf/machine/include/machine-xilinx-default.inc
require conf/machine/include/machine-xilinx-qemu.inc

MACHINE_FEATURES = "rtc ext2 ext3 vfat usbhost"

UBOOT_MACHINE = "xilinx_zynqmp_zcu102_rev1_0_defconfig"
SPL_BINARY ?= "spl/boot.bin"

# Default SD image build onfiguration, use qemu-sd to pad
IMAGE_CLASSES += "image-types-xilinx-qemu"
IMAGE_FSTYPES += "wic.qemu-sd"
WKS_FILES ?= "sdimage-bootpart.wks"

SERIAL_CONSOLE = "115200 ttyPS0"
SERIAL_CONSOLES_CHECK = "${SERIAL_CONSOLES}"

KERNEL_DEVICETREE = "xilinx/zynqmp-zcu102-rev1.0.dtb"

PREFERRED_PROVIDER_virtual/kernel ?= "linux-xlnx"
PREFERRED_PROVIDER_virtual/bootloader ?= "u-boot-xlnx"

EXTRA_IMAGEDEPENDS += " \
        u-boot-zynq-uenv \
        arm-trusted-firmware \
        qemu-devicetrees \
        virtual/boot-bin \
        virtual/bootloader \
        u-boot-zynq-scr \
        "

IMAGE_BOOT_FILES += " \
        uEnv.txt \
        atf-uboot.ub \
        ${@bb.utils.contains('PREFERRED_PROVIDER_virtual/dtb', 'device-tree', 'system.dtb', '', d)} \
        boot.scr \
        "

これまで見た感じの記述がなrんでいる。IMAGE_CLASSESと、IMAGE_FSTYPESと、WKS_FILESはよくわからないな。QEMUもしくはSDカード生成に関係しているのか?とりあえずそのまま採用してみよう。 SPL_BINARYも設定されているので、これもやはり使用してみよう。 DEVICETREEの設定の仕方がいまいち分かっていないので、これは後で追う。
IMAGE_BOOT_FILESはなんとなくブートパーティションに保存しているファイルっぽいけど、ビルドして調べてみるか。

続いてQEMUの設定っぽい部分。 ほとんどqemu呼び出しのための引数設定って感じなので省略。 xilinxのリファレンスマニュアル(UG1169)見れば正しく設定できそう。 実際使うときに細かく確認していくこととする。

あとはデバイスツリー周りとHDF関連の変数の使われ方調べて一区切りさせて、petalinuxをインストールしないでビルドしてみる。

# This machine has a QEMU model, runqemu setup:
IMAGE_CLASSES += "qemuboot-xilinx"
QB_MACHINE = "-machine xlnx-zcu102"
QB_MEM = "-m 4096"
QB_OPT_APPEND ?= "-nographic -serial mon:stdio -serial null"
QB_NETWORK_DEVICE = "-net nic -net nic -net nic -net nic,netdev=net0,macaddr=@MAC@"

# Use qemu-xilinx instead of mainline
PREFERRED_PROVIDER_qemu-helper-native = "qemu-xilinx-helper-native"

# Use the multiarch script instead of launching QEMU directly
QB_SYSTEM_NAME_append = "-multiarch"

# Replicate BootROM like behaviour, having loaded SPL and PMU(ROM+FW)
QB_OPT_APPEND_append_qemuboot-xilinx = " \
        -hw-dtb ${DEPLOY_DIR_IMAGE}/qemu-hw-devicetrees/multiarch/zcu102-arm.dtb \
        ${@qemu_zynqmp_unhalt(d, True)} \
        -device loader,file=${DEPLOY_DIR_IMAGE}/arm-trusted-firmware.elf,cpu-num=0 \
        -device loader,file=${DEPLOY_DIR_IMAGE}/u-boot.elf \
        "

# Attach the rootfs disk image to the second SD interface of QEMU (which is SD0)
QB_DEFAULT_FSTYPE_qemuboot-xilinx = "wic.qemu-sd"
QB_OPT_APPEND_append_qemuboot-xilinx = " -boot mode=5"
QB_ROOTFS_OPT_qemuboot-xilinx = " -drive if=sd,index=1,file=@ROOTFS@,format=raw"

# PMU instance args
PMU_ROM ?= "${DEPLOY_DIR_IMAGE}/pmu-rom.elf"
PMU_FIRMWARE_DEPLOY_DIR ?= "${TOPDIR}/pmutmp/deploy/images/zynqmp-pmu"
PMU_FIRMWARE_IMAGE_NAME ?= "pmu-firmware-zynqmp-pmu"

QB_PMU_OPT = " \
        -M microblaze-fdt \
        -display none \
        -hw-dtb ${DEPLOY_DIR_IMAGE}/qemu-hw-devicetrees/multiarch/zynqmp-pmu.dtb \
        -kernel ${PMU_ROM} \
        -device loader,file=${PMU_FIRMWARE_DEPLOY_DIR}/${PMU_FIRMWARE_IMAGE_NAME}.elf \
        -device loader,addr=0xfd1a0074,data=0x1011003,data-len=4 \
        -device loader,addr=0xfd1a007C,data=0x1010f03,data-len=4 \
        "
QB_OPT_APPEND_append_qemuboot-xilinx = " -pmu-args '${QB_PMU_OPT}'"

do_write_qemuboot_conf[depends] += "u-boot-zynq-uenv:do_deploy"

petalinuxの設定内容を読むその3,petalinuxbsp.conf,plnx-zynqmp.conf

project-spec/meta-user/conf/petalinuxbsp.confを読んでいく。 custom-petalinuxにのみあるファイル。

#User Configuration
#OE_TERMINAL = "tmux"
# Add EXTRA_IMAGEDEPENDS default components
EXTRA_IMAGEDEPENDS_append = " virtual/fsbl virtual/pmu-firmware arm-trusted-firmware qemu-devicetrees"
# prevent U-Boot from deploying the boot.bin
SPL_BINARY = ""
#Remove all qemu contents
IMAGE_CLASSES_remove = "image-types-xilinx-qemu qemuboot-xilinx"
IMAGE_FSTYPES_remove = "wic.qemu-sd"
EXTRA_IMAGEDEPENDS_remove = "qemu-helper-native virtual/boot-bin"

EXTRA_IMAGEDEPENDS_appendはbootloader等を設定している模様。これはそのまま使わせてもらう。
SPL_BINARYはBeagleBone等で必要になってくる設定に思われる。今回は設定不要と思われるので、SPL_BINARY = ""を採用する。
#Remove all qemu contents以降はqemuの機能を省いていると思われる。petalinuxの場合はpetalinux-bootでサポートしているからか?

後はultra96向けには以下の記述の追加が必要な模様。

MACHINE_FEATURES_remove_ultra96-zynqmp = "mipi"
DISTRO_FEATURES_append = " bluez5 dbus"
PREFERRED_VERSION_wilc-firmware = "15.2"

MACHINE_FEATURES_remove_ultra96-zynqmp = "mipi"はバグを回避するために必要な記述のよう。詳細はこちらに記載がある。
DISTRO_FEATURES_append = " bluez5 dbus"はbluetoothとdbusを有効にしているよう。bluez5って良く分かっていないけど。
PREFERRED_VERSION_wilc-firmware = "15.2"はwilc-firmwareのバージョン15.2を指定している。

vanilla-petalinuxは生成物に同様にfsblやpmu-firmwareが含まれているので、 どのようにEXTTRA_IMAGEDEPENDSを指定しているのか調べてみると、 meta-xilinx/meta-xilinx-bsp/conf/machine/zcu102-zynqmp.confに記載されているよう。 これは別途読み込む。

MACHINE設定したconfファイルが読み込まれるのか。 そうすると、plnx-zynqmpも読み込まれる感じもするが。

meta-plnx-generated/conf/machine/plnx-zynqmp.confがあるので、これが読み込まれるのかな。 中身は少ないので確認する。

require conf/machine/include/tune-zynqmp.inc
require conf/machine/include/machine-xilinx-overrides.inc
require conf/machine/include/machine-xilinx-default.inc
require conf/machine/include/machine-xilinx-board.inc

include conf/machine/include/zynqmp-pmu-config.inc

SERIAL_CONSOLES_CHECK = "${SERIAL_CONSOLES}"
MACHINE_FEATURES = "rtc ext2 ext3 vfat usbhost"

tune-zynqmp.inc,machine-xilinx-overrides.inc,machine-xilinx-default.inc,mahcine-xilinx-board.inc, zynqmp-pmu-config.incは別の機会に確認でいいかな。

SERIAL_CONSOLES_CHECKはコンソールのチェック。 MACHINE_FEATURESはusbgadget,wifi,bluetoothを付与かな。

参考ページ
https://www.yoctoproject.org/docs/2.5/ref-manual/ref-manual.html
https://technologicaladvance.blog.fc2.com/blog-category-12.html#174
https://qiita.com/basaro_k/items/066edec6139bcb9d53e5

2020年10月26日月曜日

petalinuxの設定内容を読むその2,plnxtool.conf

前回に続きpetalinuxの設定内容を見ていく。 今回の対象はplnxtool.conf。まずはコード。vanilla-petalinuxには無いので、custom-petalinuxのみで何を行っているか調べる。

#Add Pre-mirrors of tool
SOURCE_MIRROR_URL = "file:///opt/petalinux/components/yocto/downloads/"

#Add Pre-mirrors from petalinux-config
PREMIRRORS = " git://.*/.* http://petalinux.xilinx.com/sswreleases/rel-v2019/downloads \n \
ftp://.*/.* http://petalinux.xilinx.com/sswreleases/rel-v2019/downloads \n \
http://.*/.* http://petalinux.xilinx.com/sswreleases/rel-v2019/downloads \n \
https://.*/.* http://petalinux.xilinx.com/sswreleases/rel-v2019/downloads \n"

#Sttate mirror settings
SSTATE_MIRRORS = "file://universal/(.*) file:///opt/petalinux/components/yocto/source/aarch64/sstate-cache/universal-4.8/\1\n"
SSTATE_MIRRORS .= "\nfile://.* file:///opt/petalinux/components/yocto/source/aarch64/sstate-cache/PATH\n"
SSTATE_MIRRORS_append = "  \
file://.* http://petalinux.xilinx.com/sswreleases/rel-v2019/aarch64/sstate-cache/PATH;downloadfilename=PATH \n \
"

SIGGEN_UNLOCKED_RECIPES += "arm-trusted-firmware busybox init-ifupdown python3"
UNINATIVE_DLDIR = "/opt/petalinux/components/yocto/source/aarch64/downloads/uninative"

MACHINE = "plnx-zynqmp"
PACKAGE_CLASSES = "package_rpm"
DL_DIR = "${TOPDIR}/downloads"
SSTATE_DIR = "${TOPDIR}/sstate-cache"
XILINX_SDK_TOOLCHAIN = "/opt/petalinux/tools/xsct"
USE_XSCT_TARBALL = "0"
IMAGE_LINGUAS = " "
TMPDIR = "/home/akira/work/testprj/petalinux/build/tmp"
hostname_pn-base-files = "petalinux"
PETALINUX_PRODUCT_pn-base-files = "petalinux"
PETALINUX_VERSION_pn-base-files = "1.00"

# Add system HDF/DSA
HDF_EXT_forcevariable = "xsa"
HDF_BASE_forcevariable = "file://"
HDF_PATH_forcevariable = "/home/akira/work/testprj/petalinux/project-spec/hw-description/system.xsa"

#Add FIT Variables
KERNEL_CLASSES += "kernel-fitimage"
KERNEL_IMAGETYPES += "fitImage vmlinux"
UBOOT_ENTRYPOINT  = "0x80000"
UBOOT_LOADADDRESS = "0x80000"

EXTRA_IMAGEDEPENDS_remove = ""
UBOOT_MACHINE_forcevariable = "xilinx_zynqmp_zcu102_rev1_0_defconfig"
HAS_PLATFORM_INIT_append += "xilinx_zynqmp_zcu102_rev1_0_defconfig"
YAML_DT_BOARD_FLAGS_forcevariable = "{BOARD template}"

IMAGE_FSTYPES_forcevariable = "cpio cpio.gz cpio.gz.u-boot tar.gz jffs2"

INITRAMFS_IMAGE_BUNDLE = "1"
INITRAMFS_IMAGE = "petalinux-user-image"
INITRAMFS_MAXSIZE = "524288"

SERIAL_CONSOLE_forcevariable = "115200 ttyPS0"
SOC_VARIANT = "eg"

premirrorやsstatemirrorはビルド時間短縮のためのミラーを調べる部分だから読み飛ばす。
SIGGEN_UNLOCKED_RECIPES,UNINATIVE_DLDIRもソースビルドをするつもりだから読み飛ばす。
MACHINE = "plnx-zynqmp"は結構重要かな。project-spec/meta-plnx-generated/conf/machine/plnx-zynqmp.confがあって、ここでターゲットボード向けの設定が行われている模様。これは別途読み込む。
PACKAGE_CLASSES = "package_rpm"はパッケージ方法の指定。
DL_DIR,SSTATE_DIRはビルド時のデータ保存箇所の指定
XILINX_SDK_TOOLCHAIN = "/opt/petalinux/tools/xsct"はxsctの保存場所を指定している。Vitisのxsctを使っても良いと思われるので、petalinuxをインストールしない場合には考慮する。
USE_XSCT_TARBALL = "0"はXSCTをwebから取得して使用しない設定と思われる。
IMAGE_LINGUAS = " "は言語設定かな?英語だけにするので特に気にしない。 TMPDIR = "/home/akira/work/testprj/petalinux/build/tmp"はtmpフォルダの場所を指定しているだけなので、あまり気にしない。
hostname_pn-base-files = "petalinux"はhostnameを上書きしている模様
PETALINUX_PRODUCT_pn-base-files = "petalinux"と、PETALINUX_VERSION_pn-base-files = "1.00"はどこかのファイルに記載する情報の模様。

HDF_EXT_forcevariable,HDF_BASE_forcevariable,HDF_PATH_forcevariableはHDFのパスを指定している模様。--get-hw-descriptionで指定したxsaのデータがproject-spec/hw-description配下にsystem.xsaとして保存されており、これを指定している。HDF_PATHなど変数の使用方法はmeta-xilinx-toolsに記載があった。hw-descriptionにはpsu_init.cなどのFSBL関係と見られるものも存在しており、これらの使われ方はまだ不明。
IMAGE_INSTALL_append = " xilinx-bootbin"と、HDF_PATHなどの設定を合わせると、BOOT.binまで作成してくれそうな雰囲気。

#Add FIT Variables以降はUBOOTの設定と思われる。UBOOT_MACHINE_forcevariable,HAS_PLATFORM_INIT_append,YAML_DT_BOARD_FLAGS_forcevariableはultra96向けに変更する。avnet_ultra96_rev1_defconfigがu-bootに定義されているのでこれをベースにする。

IMAGE_FSTYPES_forcevariableはtar.gzだけでいいかな。
INITRAMFSはSDブート設定するので不要。
SERIAL_CONSOLE_forcevariable = "115200 ttyPS0"はそのまま使う。 SOC_VARIANT = "eg"もそのまま使う。

続く。

参考ページ
https://www.hiroom2.com/2014/04/18/yocto%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9/
https://www.yoctoproject.org/docs/1.8/ref-manual/ref-manual.html
https://github.com/ARM-software/u-boot

petalinuxの設定内容を読むその1,local.conf

petalinuxが何を設定しているのかを調査していく。

こちらのサイトで紹介されている方法で作成したものを便宜上vanilla-petalinuxと呼び、petalinuxツールで--get-hw-descriptionで生成したプロジェクトをcustom-petalinuxと呼ぶ。

目的はvanila-petalinuxに対してどのような設定を付加するとcustom-petalinux相当のデータが生成されるのかを明らかにすること。 petalinuxのコンフィグファイル、meta-plnx-generated、meta-userを追加すれば良いのだろうけど、何をしているのかがわかればpetalinuxのインストール自体不要となりそうなので調べてみる。 yoctoの理解につながるだろうし。

最初はそれぞれのbuild/conf/local.confを比較していく。 コメントは除き、以下は同じとなっている。

MACHINE ??= "qemuzynq"
PATCHRESOLVE = "noop"
BB_DISKMON_DIRS = "\
    STOPTASKS,${TMPDIR},1G,100K \
    STOPTASKS,${DL_DIR},1G,100K \
    STOPTASKS,${SSTATE_DIR},1G,100K \
    STOPTASKS,/tmp,100M,100K \
    ABORT,${TMPDIR},100M,1K \
    ABORT,${DL_DIR},100M,1K \
    ABORT,${SSTATE_DIR},100M,1K \
    ABORT,/tmp,10M,1K"
XILINX_VER_MAIN = "2019.2"
PMU_FIRMWARE_DEPLOY_DIR = "${DEPLOY_DIR_IMAGE}"
PMU_FIRMWARE_IMAGE_NAME = "pmu-firmware-${MACHINE}"
CONF_VERSION = "1"

特に気になる内容は含まれていない。バージョンの指定、PMU_FIRMWAREの出力先、イメージ名が設定されているのが分かる。

異なっているのは以下の内容でいずれもcustom-petalinuxにのみ記載されている。

INHERIT += "rm_work"

TMPDIR = "${TOPDIR}/tmp"
TCLIBCAPPEND = ""
DL_DIR = "${TOPDIR}/downloads"
INHERIT += "uninative"
UNINATIVE_CHECKSUM[x86_64] = "c6954563dad3c95608117c6fc328099036c832bbd924ebf5fdccb622fc0a8684"

INHERIT_remove = "buildhistory icecc"
CONNECTIVITY_CHECK_URIS = ""

SIGGEN_LOCKEDSIGS_SSTATE_EXISTS_CHECK = "none"

SIGGEN_LOCKEDSIGS_TASKSIG_CHECK = "warn"

BB_HASHCONFIG_WHITELIST_append = " SIGGEN_UNLOCKED_RECIPES"

BB_SETSCENE_ENFORCE_WHITELIST = "%:* *:do_shared_workdir *:do_rm_work wic-tools:* *:do_addto_recipe_sysroot"

BUILDCFG_HEADER = ""

# Provide a flag to indicate we are in the EXT_SDK Context
WITHIN_EXT_SDK = "1"


USE_XSCT_TARBALL = "0"
require conf/locked-sigs.inc
require conf/unlocked-sigs.inc

# Extra settings from environment:
MACHINE = "zynqmp-generic"

include conf/plnxtool.conf
include conf/petalinuxbsp.conf

INHERIT += "rm_work"はpackageのビルド後に不要なファイル等削除するオプション。
TMPDIRはtmpキャッシュ等の保存場所の指定。
TCLIBCAPPENDはlibcの識別に使用するようだけど良く分かっていない。
DL_DIRはダウンロードデータ保存先の指定。
UNINATIVE_CHECKSUMはチェック用。
INHERIT_remove = "buildhistory icecc"はビルド履歴を残す機能や分散ビルドの機能を無効化している。
CONNECTIVITY_CHECK_URIS = ""はpokyでネットワークチェックのために使用する機能をoffにしている。
SIGGEN_LOCKEDSIGS_SSTATE_EXISTS_CHECK = "none"はlockされたタスクのsstateをチェックするかどうかの設定?
SIGGEN_LOCKEDSIGS_TASKSIG_CHECK = "warn"はlockされたタスクでチェックするかとチェック結果をどう扱うかの設定。ミスマッチしてもwarningとする設定と思われる。
BB_HASHCONFIG_WHITELIST_append = " SIGGEN_UNLOCKED_RECIPES"はcache利用するかどうかの判定にSIGGEN_UNLOCKED_RECIPESを含まないことを指定
BB_SETSCENE_ENFORCE_WHITELIST = ...はSDK生成に関連する設定ぽいけど詳細はよくわからなかった。 WITHIN_EXT_SDK = "1"はxsctを供給するかどうかの設定。petalinux同梱のxsctを使用するのでcustom-petalinuxでは1となっていると思われる。 meta-xilinx-tools/classes/xsct-tarball.bbclassにて使用している。
USE_XSCT_TARBALL = "0"はxsctを取得するかどうかの設定。custom-petalinuxではインストール済のxsctを使用するため0となっている。
require conf/locked-sigs.inc,require conf/unlocked-sigs.incはビルド結果を固定するものしないものの指定。
MACHINE = "zynqmp-generic"はMACHINE設定の上書き。
vanilla-petalinuxはコマンドラインで同様の指定を行っている。
include conf/plnxtool.confはcustom-petalinuxの設定を行っている。build/conf/plnxtool.confに記載。中身は別途確認する。
include conf/petalinuxbsp.confはdeploy_imageを設定している模様。project-spec/meta-user/conf/petalinuxbsp.confに記載。中身は別途確認する。

参考ページ
https://www.yoctoproject.org/docs/1.8/ref-manual/ref-manual.html
https://git.yoctoproject.org/cgit.cgi/poky/plain/meta/classes/sstate.bbclass
https://yoctobbq.lineo.co.jp/?q=node/171

2020年10月14日水曜日

Vivado_HLSのcsimは動作するけどcosimが終了しない場合の原因信号の見つけ方

前回の対処方法の対象となる信号を見つけるための方法について記載する。
RTLシミュレーションの信号追うだけなので、内容としてはあまり大したことない。

結論

以下のようにwave_debug有効にして、$finishに至るまでの信号線をチェックしていけば良い。
$finishはsim/verilog/xxx.autotb.vにあるのでここから辿っていき、all_finishを阻害している信号線をさがしていけば見つけることが可能。


 

一応、今回問題となっていたのは以下の部分でbread_num_o_V_read_data_finishが1とならないことであった。 DUTが対応する信号を出力するパスを通らなかったことが原因。

sim/verilog/AESL_axi_slave_AXILiteS.v

always @(reset or posedge clk) begin
    if (reset == 0) begin
        bread_num_o_V_read_data_finish <= 0;
        read_bread_num_o_V_run_flag <= 0;
        read_bread_num_o_V_count = 0;
        count_operate_depth_by_bitwidth_and_depth (bread_num_o_V_c_bitwidth, bread_num_o_V_DEPTH, bread_num_o_V_OPERATE_DEPTH);
    end
    else begin
        if (TRAN_AXILiteS_start_in === 1) begin
            read_bread_num_o_V_run_flag = 1;
        end
        if (TRAN_AXILiteS_transaction_done_in === 1) begin
            bread_num_o_V_read_data_finish <= 0;
            read_bread_num_o_V_count = 0;
        end
        if (read_one_bread_num_o_V_data_done === 1) begin
            read_bread_num_o_V_count = read_bread_num_o_V_count + 1;
            if (read_bread_num_o_V_count == bread_num_o_V_OPERATE_DEPTH) begin
                read_bread_num_o_V_run_flag <= 0;
                bread_num_o_V_read_data_finish <= 1;
            end
        end
    end
end

以下役に立たないおまけ。
RTL simまで動いている場合は問題としては大したことがなさそうという感触が得られた。
それと、WrapCを実行するとC言語からRTL向けのテストベクター生成できそうという感触も得たけど、 当座はこれをやることは無いかな。

cosimの構成

cosimは以下の3段階で進むらしい。(UG902より)
(1)WrapC sim => (2)RTL sim => (3)Post-Checking

全体制御はsolution/sim/verilog/run_sim.tclっぽい。

# ==============================================================
# Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC v2019.2 (64-bit)
# Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
# ==============================================================
set ::env(LD_LIBRARY_PATH) /opt/Xilinx/Vivado/2019.2/lnx64/tools/fpo_v7_0:$::env(LD_LIBRARY_PATH)

set ::env(LD_LIBRARY_PATH) /opt/Xilinx/Vivado/2019.2/lnx64/tools/opencv:$::env(LD_LIBRARY_PATH)
set ::env(LD_LIBRARY_PATH) /opt/Xilinx/Vivado/2019.2/lnx64/tools/fft_v9_1:$::env(LD_LIBRARY_PATH)
set ::env(LD_LIBRARY_PATH) /opt/Xilinx/Vivado/2019.2/lnx64/tools/fir_v7_0:$::env(LD_LIBRARY_PATH)
set ::env(LD_LIBRARY_PATH) /opt/Xilinx/Vivado/2019.2/lnx64/tools/dds_v6_0:$::env(LD_LIBRARY_PATH)
set ::env(LD_LIBRARY_PATH) /usr/lib/x86_64-linux-gnu:$::env(LD_LIBRARY_PATH)

source check_sim.tcl

# --> test vector generation

::AP::printMsg INFO COSIM 302 COSIM_302_998

cd ../wrapc

file delete -force  "err.log"

if {![file exists cosim.tv.exe]} {
    ::AP::printMsg ERR COSIM 321 COSIM_321_999
    return -code error -errorcode $::errorCode
}

set ret [catch {eval exec ./cosim.tv.exe | tee temp0.log >&@ stdout} err]

if {$ret == 1} {
    ::AP::printMsg ERR COSIM 320 COSIM_320_1000
    return -code error -errorcode $::errorCode
}

if {[file isfile zeppeli.autotvin.dat]} {
    file delete -force zeppeli.autotvin.dat
}

if {[file isfile zeppeli.autotvout.dat]} {
    file delete -force zeppeli.autotvout.dat
}

sc_sim_check $ret $err "temp0.log"

cd ../tv/cdatafile
set ret [check_tvin_file]

if {$ret == 1} {
    ::AP::printMsg ERR COSIM 344 COSIM_344_1005
    return -code error -errorcode $::errorCode
}

cd ../

# --> verilog simulation

::AP::printMsg INFO COSIM 323 COSIM_323_1007

::AP::printMsg INFO COSIM 15 COSIM_15_1011

cd ../verilog

file delete -force ".exit.err"
file delete -force ".aesl_error"
file delete -force "err.log"

if {[file isfile run_xsim.sh]} {
    set ret [catch {eval exec "sh ./run_xsim.sh | tee temp2.log" >&@ stdout} err]
}

cd ../tv/rtldatafile

set ret [check_tvout_file]

if {$ret == 1} {
    ::AP::printMsg ERR COSIM 344 COSIM_344_1020
    return -code error -errorcode $::errorCode
}

cd ../../wrapc_pc

::AP::printMsg INFO COSIM 316 COSIM_316_1021

if {![file exists cosim.pc.exe]} {
    ::AP::printMsg ERR COSIM 320 COSIM_320_1022
    return -code error -errorcode $::errorCode
}

set ret [catch {eval exec ./cosim.pc.exe | tee temp0.log >&@ stdout} err]

sc_sim_check $ret $err "temp3.log"

UG902にも書いてあるけど、
(1)は以下のメッセージからfinishまでで、cosim用にテストベクターを生成している。
(上記ファイルの# --> test vector generation以降が該当)

solution/sim配下のwrapcの中の話と思われる。

[SIM-14] Instrumenting C test bench (wrapc)
[SIM-302] Generating test vectors(wrapc)

(2)は以下のメッセージからfinishまでで、いわゆるRTLシミュレーションを行っている。
(# --> verilog simulation以降が該当)
動作させている間は通常のシミュレータ使う感覚でデバッグができる。

[SIM-333] Generating C post check test bench
[SIM-12] Generating RTL test bench
[SIM-323] Starting Verilog simulation (Issued when Verilog is the RTL
verified)
[SIM-322] Starting VHDL simulation (Issued when VHDL is the RTL verified)

(3)は以下のメッセージからfinishまでで、最終出力のチェックを行っている。
(上記ファイルのcd ../../wrapc_pc以降が該当)
ここはよく見ていない。

[SIM-316] Starting C post checking
[SIM-1000] C/RTL co-simulation finished: PASS (If test bench returns a 0)
[SIM-4] C/RTL co-simulation finished: FAIL (If the test bench returns non-
zero)

solution配下のsimディレクトリ構成は以下の通り。

sim
├── autowrap
│   ├── systemc
│   │   ├── apatb_zeppeli.cpp
│   │   └── apatb_zeppeli.h
│   └── testbench
│       ├── tb.status.tcl
│       ├── tb_zeppeli.cpp_pre.cpp
│       ├── tb_zeppeli.cpp_pre.cpp.tb.cpp
│       ├── zeppeli.cpp_pre.cpp
│       └── zeppeli.cpp_pre.cpp.tb.cpp
├── tv
│   ├── cdatafile
│   │   ├── c.zeppeli.autotvin_bread_i_V.dat
│   │   ├── c.zeppeli.autotvout_bread_num_o_V.dat
│   │   └── ref.tcl
│   └── rtldatafile
│       └── rtl.zeppeli.autotvout_bread_num_o_V.dat
├── verilog
│   ├── AESL_axi_slave_AXILiteS.v
│   ├── check_sim.tcl
│   ├── glbl.v
│   ├── run_sim.tcl
│   ├── run_xsim.sh
│   ├── sim.sh
│   ├── webtalk_25187.backup.jou
│   ├── webtalk_25187.backup.log
│   ├── webtalk.jou
│   ├── webtalk.log
│   ├── xelab.log
│   ├── xelab.pb
│   ├── xsim.dir
│   │   ├── work
│   │   │   ├── glbl.sdb
│   │   │   └── work.rlx
│   │   ├── xil_defaultlib
│   │   │   ├── @a@e@s@l_axi_slave_@a@x@i@lite@s.sdb
│   │   │   ├── apatb_zeppeli_top.sdb
│   │   │   ├── xil_defaultlib.rlx
│   │   │   ├── zeppeli_@a@x@i@lite@s_s_axi.sdb
│   │   │   └── zeppeli.sdb
│   │   └── zeppeli
│   │       ├── Compile_Options.txt
│   │       ├── TempBreakPointFile.txt
│   │       ├── webtalk
│   │       │   ├── usage_statistics_ext_xsim.html
│   │       │   └── usage_statistics_ext_xsim.xml
│   │       ├── xsimcrash.log
│   │       ├── xsim.dbg
│   │       ├── xsimk
│   │       ├── xsimkernel.log
│   │       ├── xsim.mem
│   │       ├── xsim.reloc
│   │       ├── xsim.rtti
│   │       ├── xsim_script.tcl
│   │       ├── xsimSettings.ini
│   │       ├── xsim.svtype
│   │       ├── xsim.type
│   │       └── xsim.xdbg
│   ├── xsim.jou
│   ├── xsim.log
│   ├── zeppeli.autotb.v
│   ├── zeppeli_AXILiteS_s_axi.v
│   ├── zeppeli_dataflow_ana.wcfg
│   ├── zeppeli.performance.result.transaction.xml
│   ├── zeppeli.prj
│   ├── zeppeli.protoinst
│   ├── zeppeli.result.lat.rb
│   ├── zeppeli.tcl
│   └── zeppeli.v
├── wrapc
│   ├── AESL_pkg.h
│   ├── apatb_zeppeli.cpp
│   ├── apatb_zeppeli.h
│   ├── cosim.tv.exe
│   ├── cosim.tv.mk
│   ├── Makefile.rules
│   ├── obj
│   │   ├── apatb_zeppeli.d
│   │   ├── apatb_zeppeli.o
│   │   ├── tb_zeppeli.cpp_pre.cpp.tb.o
│   │   └── zeppeli.cpp_pre.cpp.tb.o
│   ├── sc0.log
│   ├── tb_zeppeli.cpp_pre.cpp.tb.cpp
│   └── zeppeli.cpp_pre.cpp.tb.cpp
└── wrapc_pc
   ├── AESL_pkg.h
   ├── apatb_zeppeli.cpp
   ├── apatb_zeppeli.h
   ├── cosim.pc.exe
   ├── cosim.pc.mk
   ├── Makefile.rules
   ├── run_xsim.log
   ├── tb_zeppeli.cpp_pre.cpp.tb.cpp
   └── zeppeli.cpp_pre.cpp.tb.cpp

2020年10月13日火曜日

Vivado_HLSのcsimは動作するけどcosimが終了しない場合の原因と対処方法

タイトルの通り、Vivado_HLSでcsimは期待通りに動作するけど、 C/RTL協調シミュレーション(cosim)でいつまで経ってもシミュレーションが終了しない場合の原因と対処方法。高位合成でカウンタ作ったときとか、うっかりやりがちかも。

結論

関数が呼び出された際に、出力ポートで代入処理が行われないパスを通っているので、代入されるようにすれば良い。だめな信号の見つけ方は次回

再現コード

事象を再現するコードは以下の仕様。 

合成対象:zeppeli
ポート:
in[0:0]: bread_i
out[7:0]: bread_num_o
動作:
bread_num_oに今まで入力されたbread_iの数を出力する。255を超えると0になる。

実装:
zeppeli.h

#ifndef ZEPPELI
#define ZEPPELI

void zeppeli(
    ap_uint<1>  bread_i,
    ap_uint<8>  *bread_num_o
);

#endif

zeppeli.cpp

#include <stdint.h>
#include <ap_int.h>
#include "zeppeli.h"

void zeppeli(
        ap_uint<1>  bread_i,
        ap_uint<8>  *bread_num_o
){
#pragma HLS INTERFACE s_axilite register port=bread_num_o
    static ap_uint<8> bread_num = 0;
    if(bread_i == 1){
        ++bread_num;
        *bread_num_o = bread_num;
    }
}

tb_zeppeli.cpp

#include <stdint.h>
#include <ap_int.h>
#include "zeppeli.h"

int main(int argc, char **argv){
    ap_uint<8> bread_num;
    zeppeli(0,&bread_num);
    return 0;
}

csim実行結果

こちらは正常に完了する。

Starting C simulation ...
/opt/Xilinx/Vivado/2019.2/bin/vivado_hls /home/akira/work/test/zeppeli/zeppeli/solution1/csim.tcl
INFO: [HLS 200-10] Running '/opt/Xilinx/Vivado/2019.2/bin/unwrapped/lnx64.o/vivado_hls'
INFO: [HLS 200-10] For user 'akira' on host 'akira-Surface-Book' (Linux_x86_64 version 5.4.0-48-generic) on Tue Oct 13 00:21:29 JST 2020
INFO: [HLS 200-10] On os Ubuntu 18.04.5 LTS
INFO: [HLS 200-10] In directory '/home/akira/work/test/zeppeli'
Sourcing Tcl script '/home/akira/work/test/zeppeli/zeppeli/solution1/csim.tcl'
INFO: [HLS 200-10] Opening project '/home/akira/work/test/zeppeli/zeppeli'.
INFO: [HLS 200-10] Opening solution '/home/akira/work/test/zeppeli/zeppeli/solution1'.
INFO: [SYN 201-201] Setting up clock 'default' with a period of 10ns.
INFO: [HLS 200-10] Setting target device to 'xczu3eg-sbva484-1-e'
INFO: [SIM 211-2] *************** CSIM start ***************
INFO: [SIM 211-4] CSIM will launch GCC as the compiler.
   Compiling ../../../../tb_zeppeli.cpp in debug mode
   Compiling ../../../../zeppeli.cpp in debug mode
   Generating csim.exe
INFO: [SIM 211-1] CSim done with 0 errors.
INFO: [SIM 211-3] *************** CSIM finish ***************
Finished C simulation.

cosim実行結果(エラー)

見ての通り終わらない。

Starting C/RTL cosimulation ...
/opt/Xilinx/Vivado/2019.2/bin/vivado_hls /home/akira/work/test/zeppeli/zeppeli/solution1/cosim.tcl
INFO: [HLS 200-10] Running '/opt/Xilinx/Vivado/2019.2/bin/unwrapped/lnx64.o/vivado_hls'
INFO: [HLS 200-10] For user 'akira' on host 'akira-Surface-Book' (Linux_x86_64 version 5.4.0-48-generic) on Tue Oct 13 00:23:41 JST 2020
INFO: [HLS 200-10] On os Ubuntu 18.04.5 LTS
INFO: [HLS 200-10] In directory '/home/akira/work/test/zeppeli'
Sourcing Tcl script '/home/akira/work/test/zeppeli/zeppeli/solution1/cosim.tcl'
INFO: [HLS 200-10] Opening project '/home/akira/work/test/zeppeli/zeppeli'.
INFO: [HLS 200-10] Opening solution '/home/akira/work/test/zeppeli/zeppeli/solution1'.
INFO: [SYN 201-201] Setting up clock 'default' with a period of 10ns.
INFO: [HLS 200-10] Setting target device to 'xczu3eg-sbva484-1-e'
INFO: [COSIM 212-47] Using XSIM for RTL simulation.
INFO: [COSIM 212-14] Instrumenting C test bench ...
   Build using "/opt/Xilinx/Vivado/2019.2/tps/lnx64/gcc-6.2.0/bin/g++"
   Compiling apatb_zeppeli.cpp
   Compiling zeppeli.cpp_pre.cpp.tb.cpp
   Compiling tb_zeppeli.cpp_pre.cpp.tb.cpp
   Generating cosim.tv.exe
INFO: [COSIM 212-302] Starting C TB testing ...
INFO: [COSIM 212-333] Generating C post check test bench ...
INFO: [COSIM 212-12] Generating RTL test bench ...
INFO: [COSIM 212-1] *** C/RTL co-simulation file generation completed. ***
INFO: [COSIM 212-323] Starting verilog simulation.
INFO: [COSIM 212-15] Starting XSIM ...
INFO: [XSIM 43-3496] Using init file passed via -initfile option "/opt/Xilinx/Vivado/2019.2/data/xsim/ip/xsim_ip.ini".
Vivado Simulator 2019.2
Copyright 1986-1999, 2001-2019 Xilinx, Inc. All Rights Reserved.
Running: /opt/Xilinx/Vivado/2019.2/bin/unwrapped/lnx64.o/xelab xil_defaultlib.apatb_zeppeli_top glbl -prj zeppeli.prj -L smartconnect_v1_0 -L axi_protocol_checker_v1_1_12 -L axi_protocol_checker_v1_1_13 -L axis_protocol_checker_v1_1_11 -L axis_protocol_checker_v1_1_12 -L xil_defaultlib -L unisims_ver -L xpm --initfile /opt/Xilinx/Vivado/2019.2/data/xsim/ip/xsim_ip.ini --lib ieee_proposed=./ieee_proposed -s zeppeli
Multi-threading is on. Using 2 slave threads.
WARNING: [XSIM 43-3431] One or more environment variables have been detected which affect the operation of the C compiler. These are typically not set in standard installations and are not tested by Xilinx, however they may be appropriate for your system, so the flow will attempt to continue.  If errors occur, try running xelab with the "-mt off -v 1" switches to see more information from the C compiler. The following environment variables have been detected:
    LIBRARY_PATH
INFO: [VRFC 10-2263] Analyzing SystemVerilog file "/home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/glbl.v" into library work
INFO: [VRFC 10-311] analyzing module glbl
INFO: [VRFC 10-2263] Analyzing SystemVerilog file "/home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/AESL_axi_slave_AXILiteS.v" into library xil_defaultlib
INFO: [VRFC 10-311] analyzing module AESL_axi_slave_AXILiteS
INFO: [VRFC 10-2263] Analyzing SystemVerilog file "/home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/zeppeli.autotb.v" into library xil_defaultlib
INFO: [VRFC 10-311] analyzing module apatb_zeppeli_top
INFO: [VRFC 10-2263] Analyzing SystemVerilog file "/home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/zeppeli.v" into library xil_defaultlib
INFO: [VRFC 10-311] analyzing module zeppeli
INFO: [VRFC 10-2263] Analyzing SystemVerilog file "/home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/zeppeli_AXILiteS_s_axi.v" into library xil_defaultlib
INFO: [VRFC 10-311] analyzing module zeppeli_AXILiteS_s_axi
Starting static elaboration
Pass Through NonSizing Optimizer
Completed static elaboration
Starting simulation data flow analysis
Completed simulation data flow analysis
Time Resolution for simulation is 1ps
Compiling module xil_defaultlib.zeppeli_AXILiteS_s_axi
Compiling module xil_defaultlib.zeppeli
Compiling module xil_defaultlib.AESL_axi_slave_AXILiteS
Compiling module xil_defaultlib.apatb_zeppeli_top
Compiling module work.glbl
Built simulation snapshot zeppeli


****** Webtalk v2019.2 (64-bit)
  **** SW Build 2708876 on Wed Nov  6 21:39:14 MST 2019
  **** IP Build 2700528 on Thu Nov  7 00:09:20 MST 2019
    ** Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.


source /home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/xsim.dir/zeppeli/webtalk/xsim_webtalk.tcl -notrace
INFO: [Common 17-186] '/home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/xsim.dir/zeppeli/webtalk/usage_statistics_ext_xsim.xml' has been successfully sent to Xilinx on Tue Oct 13 00:24:02 2020. For additional details about this file, please refer to the WebTalk help file at /opt/Xilinx/Vivado/2019.2/doc/webtalk_introduction.html.
INFO: [Common 17-206] Exiting Webtalk at Tue Oct 13 00:24:02 2020...


****** xsim v2019.2 (64-bit)
  **** SW Build 2708876 on Wed Nov  6 21:39:14 MST 2019
  **** IP Build 2700528 on Thu Nov  7 00:09:20 MST 2019
    ** Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.


source xsim.dir/zeppeli/xsim_script.tcl
# xsim {zeppeli} -autoloadwcfg -tclbatch {zeppeli.tcl}
Vivado Simulator 2019.2
Time resolution is 1 ps
source zeppeli.tcl
## run all
////////////////////////////////////////////////////////////////////////////////////
// Inter-Transaction Progress: Completed Transaction / Total Transaction
// Intra-Transaction Progress: Measured Latency / Latency Estimation * 100%
//
// RTL Simulation : "Inter-Transaction Progress" ["Intra-Transaction Progress"] @ "Simulation Time"
////////////////////////////////////////////////////////////////////////////////////
// RTL Simulation : 0 / 1 [0.00%] @ "125000"
// RTL Simulation : 0 / 1 [1000000000.00%] @ "100000145000"
// RTL Simulation : 0 / 1 [2000000100.00%] @ "200000155000"
// RTL Simulation : 0 / 1 [3000000200.00%] @ "300000165000"
// RTL Simulation : 0 / 1 [4000000300.00%] @ "400000175000"
Finished C/RTL cosimulation.

Task has been canceled!

エラーの解消

問題は関数呼び出しによってbread_oに値が代入されないことによって引き起こされるので、代入されるようにすればよい。

zeppeli.cpp

#include <stdint.h>
#include <ap_int.h>
#include "zeppeli.h"

void zeppeli(
        ap_uint<1>  bread_i,
        ap_uint<8>  *bread_num_o
){
#pragma HLS INTERFACE s_axilite register port=bread_num
    static ap_uint<8> bread_num = 0;
    if(bread_i == 1){
        ++bread_num;
        *bread_num_o = bread_num;
    } else {
        *bread_num_o = bread_num;
    }
}

エラー要因解消後のcosim実行結果

終了するようになった。

INFO: [HLS 200-10] Running '/opt/Xilinx/Vivado/2019.2/bin/unwrapped/lnx64.o/vivado_hls'
INFO: [HLS 200-10] For user 'akira' on host 'akira-Surface-Book' (Linux_x86_64 version 5.4.0-48-generic) on Tue Oct 13 00:33:41 JST 2020
INFO: [HLS 200-10] On os Ubuntu 18.04.5 LTS
INFO: [HLS 200-10] In directory '/home/akira/work/test/zeppeli'
Sourcing Tcl script '/home/akira/work/test/zeppeli/zeppeli/solution1/cosim.tcl'
INFO: [HLS 200-10] Opening project '/home/akira/work/test/zeppeli/zeppeli'.
INFO: [HLS 200-10] Opening solution '/home/akira/work/test/zeppeli/zeppeli/solution1'.
INFO: [SYN 201-201] Setting up clock 'default' with a period of 10ns.
INFO: [HLS 200-10] Setting target device to 'xczu3eg-sbva484-1-e'
INFO: [COSIM 212-47] Using XSIM for RTL simulation.
INFO: [COSIM 212-14] Instrumenting C test bench ...
   Build using "/opt/Xilinx/Vivado/2019.2/tps/lnx64/gcc-6.2.0/bin/g++"
   Compiling apatb_zeppeli.cpp
   Compiling zeppeli.cpp_pre.cpp.tb.cpp
   Compiling tb_zeppeli.cpp_pre.cpp.tb.cpp
   Generating cosim.tv.exe
INFO: [COSIM 212-302] Starting C TB testing ...
INFO: [COSIM 212-333] Generating C post check test bench ...
INFO: [COSIM 212-12] Generating RTL test bench ...
INFO: [COSIM 212-1] *** C/RTL co-simulation file generation completed. ***
INFO: [COSIM 212-323] Starting verilog simulation.
INFO: [COSIM 212-15] Starting XSIM ...
INFO: [XSIM 43-3496] Using init file passed via -initfile option "/opt/Xilinx/Vivado/2019.2/data/xsim/ip/xsim_ip.ini".
Vivado Simulator 2019.2
Copyright 1986-1999, 2001-2019 Xilinx, Inc. All Rights Reserved.
Running: /opt/Xilinx/Vivado/2019.2/bin/unwrapped/lnx64.o/xelab xil_defaultlib.apatb_zeppeli_top glbl -prj zeppeli.prj -L smartconnect_v1_0 -L axi_protocol_checker_v1_1_12 -L axi_protocol_checker_v1_1_13 -L axis_protocol_checker_v1_1_11 -L axis_protocol_checker_v1_1_12 -L xil_defaultlib -L unisims_ver -L xpm --initfile /opt/Xilinx/Vivado/2019.2/data/xsim/ip/xsim_ip.ini --lib ieee_proposed=./ieee_proposed -s zeppeli
Multi-threading is on. Using 2 slave threads.
WARNING: [XSIM 43-3431] One or more environment variables have been detected which affect the operation of the C compiler. These are typically not set in standard installations and are not tested by Xilinx, however they may be appropriate for your system, so the flow will attempt to continue.  If errors occur, try running xelab with the "-mt off -v 1" switches to see more information from the C compiler. The following environment variables have been detected:
    LIBRARY_PATH
INFO: [VRFC 10-2263] Analyzing SystemVerilog file "/home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/glbl.v" into library work
INFO: [VRFC 10-311] analyzing module glbl
INFO: [VRFC 10-2263] Analyzing SystemVerilog file "/home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/AESL_axi_slave_AXILiteS.v" into library xil_defaultlib
INFO: [VRFC 10-311] analyzing module AESL_axi_slave_AXILiteS
INFO: [VRFC 10-2263] Analyzing SystemVerilog file "/home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/zeppeli.autotb.v" into library xil_defaultlib
INFO: [VRFC 10-311] analyzing module apatb_zeppeli_top
INFO: [VRFC 10-2263] Analyzing SystemVerilog file "/home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/zeppeli.v" into library xil_defaultlib
INFO: [VRFC 10-311] analyzing module zeppeli
INFO: [VRFC 10-2263] Analyzing SystemVerilog file "/home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/zeppeli_AXILiteS_s_axi.v" into library xil_defaultlib
INFO: [VRFC 10-311] analyzing module zeppeli_AXILiteS_s_axi
Starting static elaboration
Pass Through NonSizing Optimizer
Completed static elaboration
Starting simulation data flow analysis
Completed simulation data flow analysis
Time Resolution for simulation is 1ps
Compiling module xil_defaultlib.zeppeli_AXILiteS_s_axi
Compiling module xil_defaultlib.zeppeli
Compiling module xil_defaultlib.AESL_axi_slave_AXILiteS
Compiling module xil_defaultlib.apatb_zeppeli_top
Compiling module work.glbl
Built simulation snapshot zeppeli


****** Webtalk v2019.2 (64-bit)
  **** SW Build 2708876 on Wed Nov  6 21:39:14 MST 2019
  **** IP Build 2700528 on Thu Nov  7 00:09:20 MST 2019
    ** Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.


source /home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/xsim.dir/zeppeli/webtalk/xsim_webtalk.tcl -notrace
INFO: [Common 17-186] '/home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/xsim.dir/zeppeli/webtalk/usage_statistics_ext_xsim.xml' has been successfully sent to Xilinx on Tue Oct 13 00:34:05 2020. For additional details about this file, please refer to the WebTalk help file at /opt/Xilinx/Vivado/2019.2/doc/webtalk_introduction.html.
INFO: [Common 17-206] Exiting Webtalk at Tue Oct 13 00:34:05 2020...


****** xsim v2019.2 (64-bit)
  **** SW Build 2708876 on Wed Nov  6 21:39:14 MST 2019
  **** IP Build 2700528 on Thu Nov  7 00:09:20 MST 2019
    ** Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.


source xsim.dir/zeppeli/xsim_script.tcl
# xsim {zeppeli} -autoloadwcfg -tclbatch {zeppeli.tcl}
Vivado Simulator 2019.2
Time resolution is 1 ps
source zeppeli.tcl
## run all
////////////////////////////////////////////////////////////////////////////////////
// Inter-Transaction Progress: Completed Transaction / Total Transaction
// Intra-Transaction Progress: Measured Latency / Latency Estimation * 100%
//
// RTL Simulation : "Inter-Transaction Progress" ["Intra-Transaction Progress"] @ "Simulation Time"
////////////////////////////////////////////////////////////////////////////////////
// RTL Simulation : 0 / 1 [0.00%] @ "125000"
// RTL Simulation : 1 / 1 [100.00%] @ "245000"
////////////////////////////////////////////////////////////////////////////////////
$finish called at time : 285 ns : File "/home/akira/work/test/zeppeli/zeppeli/solution1/sim/verilog/zeppeli.autotb.v" Line 387
## quit
INFO: [Common 17-206] Exiting xsim at Tue Oct 13 00:34:18 2020...
INFO: [COSIM 212-316] Starting C post checking ...
INFO: [COSIM 212-1000] *** C/RTL co-simulation finished: PASS ***
INFO: [COSIM 212-211] II is measurable only when transaction number is greater than 1 in RTL simulation. Otherwise, they will be marked as all NA. If user wants to calculate them, please make sure there are at least 2 transactions in RTL simulation.
Finished C/RTL cosimulation.

2020年10月10日土曜日

VIvado_HLSのテストベンチをgoogletestさせてみた

Vivado_HLSのテストベンチにgoogletestを導入した話。 とりあえず公式で提供されているsample1を動作させるところまでです。 合成対象の関数でも特に問題なく動作するはずだけどこれは別途試します。

Setup

Vivado_HLSはセットアップされているものとします。 googletestをダウンロードしてください。

git clone https://github.com/google/googletest.git <path-to-local-repo>

cmakeを使用しますが、Vivadoについてくるので大丈夫と思います。

googletestのビルド

Vivado_HLSの環境を使用してgoogletestのライブラリを作成します。 コンパイラの設定とライブラリの設定を揃えるのが面倒なので、 Vivado_HLSのターミナル環境を使います。手順は以下の通り。

  1. Vivado_HLSを立ち上げ、ターミナルを表示する(Ctrl+Alt+Shift+T)


     

  2. googletestのリポジトリに移動してビルド&インストールする
    ※追記:vivado2019.2とgoogletest v1.10.0だとcosimがコケるので、googletestをv1.8.0にする必要があったので手順を追加。

cd <path-to-local-repo>
git checkout release-1.8.0
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=<path-to-usr-local>
make
make install

テストベンチを用意する

googletestのsample1を拝借しました。 試すのにファイルの追加とかが面倒だったため少し手を加えています。

テストベンチのCFLAGSとlinker optionを設定する

メニューからProject->Project Settingsを選択し、 Simulationを選んで、テストベンチのCFLAGSにgoogletestのヘッダファイルを追加します。 (<path-to-usr-local>/includeを追加)

また、Linker Flagsにてライブラリパスを追加し、gtest-mainとgtestのリンクを指示してください。


 

テストを実行する

通常と同じようにRun C Simulationを行うだけです。

結果

Starting C simulation ...
/opt/Xilinx/Vivado/2019.2/bin/vivado_hls /home/akira/work/hls/ICS_IF/build/modules/ICS_IF_MAIN/ics_if_main/solution1/csim.tcl
INFO: [HLS 200-10] Running '/opt/Xilinx/Vivado/2019.2/bin/unwrapped/lnx64.o/vivado_hls'
INFO: [HLS 200-10] For user 'akira' on host 'akira-Surface-Book' (Linux_x86_64 version 5.4.0-48-generic) on Sat Oct 10 14:24:09 JST 2020
INFO: [HLS 200-10] On os Ubuntu 18.04.5 LTS
INFO: [HLS 200-10] In directory '/home/akira/work/hls/ICS_IF/build/modules/ICS_IF_MAIN'
Sourcing Tcl script '/home/akira/work/hls/ICS_IF/build/modules/ICS_IF_MAIN/ics_if_main/solution1/csim.tcl'
INFO: [HLS 200-10] Opening project '/home/akira/work/hls/ICS_IF/build/modules/ICS_IF_MAIN/ics_if_main'.
INFO: [HLS 200-10] Opening solution '/home/akira/work/hls/ICS_IF/build/modules/ICS_IF_MAIN/ics_if_main/solution1'.
INFO: [SYN 201-201] Setting up clock 'default' with a period of 10ns.
INFO: [HLS 200-10] Setting target device to 'xczu3eg-sbva484-1-e'
INFO: [SIM 211-2] *************** CSIM start ***************
INFO: [SIM 211-4] CSIM will launch GCC as the compiler.
   Compiling ../../../../../../../modules/ICS_IF_MAIN/src/test.cpp in debug mode
   Compiling ../../../../../../../modules/ICS_IF_MAIN/src/ics_if_main.cpp in debug mode
   Generating csim.exe
[==========] Running 6 tests from 2 test suites.
[----------] Global test environment set-up.
[----------] 3 tests from FactorialTest
[ RUN      ] FactorialTest.Negative
[       OK ] FactorialTest.Negative (0 ms)
[ RUN      ] FactorialTest.Zero
[       OK ] FactorialTest.Zero (0 ms)
[ RUN      ] FactorialTest.Positive
[       OK ] FactorialTest.Positive (0 ms)
[----------] 3 tests from FactorialTest (0 ms total)


[----------] 3 tests from IsPrimeTest
[ RUN      ] IsPrimeTest.Negative
[       OK ] IsPrimeTest.Negative (0 ms)
[ RUN      ] IsPrimeTest.Trivial
[       OK ] IsPrimeTest.Trivial (0 ms)
[ RUN      ] IsPrimeTest.Positive
[       OK ] IsPrimeTest.Positive (0 ms)
[----------] 3 tests from IsPrimeTest (0 ms total)


[----------] Global test environment tear-down
[==========] 6 tests from 2 test suites ran. (0 ms total)
[  PASSED  ] 6 tests.
INFO: [SIM 211-1] CSim done with 0 errors.
INFO: [SIM 211-3] *************** CSIM finish ***************
Finished C simulation.

使用したテストベンチ

// Copyright 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// A sample program demonstrating using Google C++ testing framework.

// This sample shows how to write a simple unit test for a function,
// using Google C++ testing framework.
//
// Writing a unit test using Google C++ testing framework is easy as 1-2-3:


// Step 1. Include necessary header files such that the stuff your
// test logic needs is declared.
//
// Don't forget gtest.h, which declares the testing framework.

#include <limits.h>
#include "gtest/gtest.h"
// Returns n! (the factorial of n).  For negative n, n! is defined to be 1.
int Factorial(int n) {
  int result = 1;
  for (int i = 1; i <= n; i++) {
    result *= i;
  }

  return result;
}

// Returns true if and only if n is a prime number.
bool IsPrime(int n) {
  // Trivial case 1: small numbers
  if (n <= 1) return false;

  // Trivial case 2: even numbers
  if (n % 2 == 0) return n == 2;

  // Now, we have that n is odd and n >= 3.

  // Try to divide n by every odd number i, starting from 3
  for (int i = 3; ; i += 2) {
    // We only have to try i up to the square root of n
    if (i > n/i) break;

    // Now, we have i <= n/i < n.
    // If n is divisible by i, n is not prime.
    if (n % i == 0) return false;
  }

  // n has no integer factor in the range (1, n), and thus is prime.
  return true;
}

namespace {

// Step 2. Use the TEST macro to define your tests.
//
// TEST has two parameters: the test case name and the test name.
// After using the macro, you should define your test logic between a
// pair of braces.  You can use a bunch of macros to indicate the
// success or failure of a test.  EXPECT_TRUE and EXPECT_EQ are
// examples of such macros.  For a complete list, see gtest.h.
//
// <TechnicalDetails>
//
// In Google Test, tests are grouped into test cases.  This is how we
// keep test code organized.  You should put logically related tests
// into the same test case.
//
// The test case name and the test name should both be valid C++
// identifiers.  And you should not use underscore (_) in the names.
//
// Google Test guarantees that each test you define is run exactly
// once, but it makes no guarantee on the order the tests are
// executed.  Therefore, you should write your tests in such a way
// that their results don't depend on their order.
//
// </TechnicalDetails>


// Tests Factorial().

// Tests factorial of negative numbers.
TEST(FactorialTest, Negative) {
  // This test is named "Negative", and belongs to the "FactorialTest"
  // test case.
  EXPECT_EQ(1, Factorial(-5));
  EXPECT_EQ(1, Factorial(-1));
  EXPECT_GT(Factorial(-10), 0);

  // <TechnicalDetails>
  //
  // EXPECT_EQ(expected, actual) is the same as
  //
  //   EXPECT_TRUE((expected) == (actual))
  //
  // except that it will print both the expected value and the actual
  // value when the assertion fails.  This is very helpful for
  // debugging.  Therefore in this case EXPECT_EQ is preferred.
  //
  // On the other hand, EXPECT_TRUE accepts any Boolean expression,
  // and is thus more general.
  //
  // </TechnicalDetails>
}

// Tests factorial of 0.
TEST(FactorialTest, Zero) {
  EXPECT_EQ(1, Factorial(0));
}

// Tests factorial of positive numbers.
TEST(FactorialTest, Positive) {
  EXPECT_EQ(1, Factorial(1));
  EXPECT_EQ(2, Factorial(2));
  EXPECT_EQ(6, Factorial(3));
  EXPECT_EQ(40320, Factorial(8));
}


// Tests IsPrime()

// Tests negative input.
TEST(IsPrimeTest, Negative) {
  // This test belongs to the IsPrimeTest test case.

  EXPECT_FALSE(IsPrime(-1));
  EXPECT_FALSE(IsPrime(-2));
  EXPECT_FALSE(IsPrime(INT_MIN));
}

// Tests some trivial cases.
TEST(IsPrimeTest, Trivial) {
  EXPECT_FALSE(IsPrime(0));
  EXPECT_FALSE(IsPrime(1));
  EXPECT_TRUE(IsPrime(2));
  EXPECT_TRUE(IsPrime(3));
}

// Tests positive input.
TEST(IsPrimeTest, Positive) {
  EXPECT_FALSE(IsPrime(4));
  EXPECT_TRUE(IsPrime(5));
  EXPECT_FALSE(IsPrime(6));
  EXPECT_TRUE(IsPrime(23));
}
}  // namespace

// Step 3. Call RUN_ALL_TESTS() in main().
//
// We do this by linking in src/gtest_main.cc file, which consists of
// a main() function which calls RUN_ALL_TESTS() for us.
//
// This runs all the tests you've defined, prints the result, and
// returns 0 if successful, or 1 otherwise.
//
// Did you notice that we didn't register the tests?  The
// RUN_ALL_TESTS() macro magically knows about all the tests we
// defined.  Isn't this convenient?


int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

2020年10月8日木曜日

UVMのreactive slaveを作ってみた話

UVMでslave動作するモデルを作成してみた話。実装したものはこちら。命名が微妙なのは諦めている。

Verilabの資料を参考に作成してみた。 資料とは異なり、sequencerはuvm_sequencerを使用し、その代わりにconfig_dbを使用してreact_req_fifoをsequenceから利用できるようにしている。参照させるためだけにクラス定義もあれかと思ったので。
加えてmonitor_icsからstorageのアップデートをせず、ics_reactive_seqに管理を一任している。passiveで使うならslaveでないものを使用すれば良いし、その状況下でstorageが必要になるとも思えないと思ったので。

 



プロトコル変換するのと同様に無限ループするシーケンスを用意し、react_req_fifoからデータを取り出して、応答データを作成してsequencerに実行させている。
get_sequencer()でsequencerに設定された設定値をsequenceで取得できるので使用している。
該当の実装は以下の通り。

class simple_ics_slave_env extends uvm_env;
    `uvm_component_utils(simple_ics_slave_env)
    `uvm_new_func
    simple_ics_env ics_env;
    simple_ics_slave_storage storage;
    uvm_tlm_analysis_fifo#(simple_ics_seq_item) react_req_fifo;
    //uvm_sequencer#(simple_ics_seq_item) sequencer;
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        ics_env = simple_ics_env::type_id::create("ics_env",this);
        react_req_fifo = new("react_req_fifo",this);
        storage = simple_ics_slave_storage::type_id::create("storage",this);
        storage.init();
        uvm_config_db #(uvm_tlm_analysis_fifo#(simple_ics_seq_item))::set(this, "*", "react_req_fifo", react_req_fifo);
        uvm_config_db #(simple_ics_slave_storage)::set(this, "*", "storage", storage);
    endfunction

    function void connect_phase(uvm_phase phase);
        ics_env.monitor.react_req_port.connect(react_req_fifo.analysis_export);
    endfunction

    task run_phase(uvm_phase phase);
        ics_reactive_seq reactive_seq;
        reactive_seq = ics_reactive_seq::type_id::create("reactive_seq",this);
        reactive_seq.start(ics_env.sequencer);
    endtask
endclass
class ics_reactive_seq extends uvm_sequence #(simple_ics_seq_item);
    `uvm_object_utils(ics_reactive_seq)
    simple_ics_seq_item received_item;
    simple_ics_seq_item responce_item;
    uvm_tlm_analysis_fifo#(simple_ics_seq_item) react_req_fifo;
    simple_ics_slave_storage storage;
    int baud_rate;
    int bit_period;
    int stop_bit_num;

    function new(string name="ics_reactive_seq");
        super.new(name);
    endfunction

    task body();
        logic[7:0]      rdata;

        if(!uvm_config_db #(uvm_tlm_analysis_fifo#(simple_ics_seq_item))::get(get_sequencer(), "", "react_req_fifo", react_req_fifo)) begin
            `uvm_fatal("CONFIG_DB_ERROR", "Could not find react_req_fifo")
        end
        if(!uvm_config_db #(simple_ics_slave_storage)::get(get_sequencer(),"", "storage", storage)) begin
            `uvm_fatal("CONFIG_DB_ERROR", "Could not find simple_ics_slave_storage")
        end
        //baud rate
        if(!uvm_config_db#(int)::get(get_sequencer(), "", "simple_uart_baud_rate", baud_rate)) begin
            uvm_report_info("CONFIG","baud rate set to default value(115200 bps)");
            baud_rate = 115200;//default value
        end
        case(baud_rate)
            115200: bit_period = 8681;//8680.6 ns for 115200 bps.
            default: `uvm_fatal("CONFIG_ERR","Undefined baud rate.")
        endcase
        //number of stop bit
        if(!uvm_config_db#(int)::get(get_sequencer(), "", "simple_uart_stop_bit_num", stop_bit_num)) begin
            uvm_report_info("CONFIG","number of stop bit set to default value(1bit)");
            stop_bit_num = 1;//default value
        end

        forever begin
            react_req_fifo.get(received_item);
            uvm_report_info("REACT","get item");
            #(bit_period*(0.2+stop_bit_num));
            received_item.print();
            responce_item = new();

            case(received_item.cmd)
                simple_ics_seq_item::POSITION_R: uvm_report_fatal("REACT", "Invalid POSITION_R command received.");
                simple_ics_seq_item::READ_R: uvm_report_fatal("REACT", "Invalid READ_R command received.");
                simple_ics_seq_item::WRITE_R: uvm_report_fatal("REACT", "Invalid WRITE_R command received.");
                simple_ics_seq_item::ID_R: uvm_report_fatal("REACT", "Invalid ID_R command received.");
                simple_ics_seq_item::POSITION:
                    begin
                        storage.write_reg(received_item.id, simple_ics_seq_item::TCH, received_item.data);
                        responce_item.cmd = simple_ics_seq_item::POSITION_R;
                        responce_item.id = received_item.id;
                        responce_item.data = storage.read_reg(received_item.id, simple_ics_seq_item::TCH);
                    end
                simple_ics_seq_item::READ:
                    begin
                        responce_item.cmd = simple_ics_seq_item::READ_R;
                        responce_item.id = received_item.id;
                        if(received_item.sub_cmd === simple_ics_seq_item::EEPROM) begin
                            logic[7:0] eeprom[0:63];
                            //responce_item.eeprom_data = new[64];
                            storage.read_mem(received_item.id, eeprom);
                            responce_item.eeprom_data = eeprom;
                        end else begin
                            responce_item.sub_cmd = received_item.sub_cmd;
                            responce_item.data = storage.read_reg(received_item.id, received_item.sub_cmd);
                        end
                    end
                simple_ics_seq_item::WRITE:
                    begin
                        responce_item.cmd = simple_ics_seq_item::WRITE_R;
                        responce_item.id = received_item.id;
                        if(received_item.sub_cmd === simple_ics_seq_item::EEPROM) begin
                            storage.write_mem(received_item.id, received_item.eeprom_data);
                            responce_item.sub_cmd = simple_ics_seq_item::EEPROM;
                            responce_item.data = 0;
                        end else begin
                            storage.write_reg(received_item.id, received_item.sub_cmd, received_item.data);
                            responce_item.sub_cmd = received_item.sub_cmd;
                            responce_item.data = storage.read_reg(received_item.id, received_item.sub_cmd);
                        end
                    end
                simple_ics_seq_item::ID:
                    begin
                        uvm_report_fatal("REACT", "ID command is not implemented yet.");
                    end
            endcase
            responce_item.print();
            `uvm_send(responce_item);
        end
    endtask

endclass

2020年10月6日火曜日

UVM1.2でプロトコル変換してみた

UVMでプロトコル変換を試してみた話。ICSを題材に実装したものはこちら

Verification Aacademyの記事を参考に作成してみた。

通常のAgentの外側にプロトコルレイヤーを処理するシーケンス、シーケンサー、モニターを追加するだけ。 実装はUARTの通信インターフェースを使ってデータを交換するICSのモデルを作成した。


 

下位から上位へのプロトコル変換はmonitorから受け取ったitemを順次処理すれば良い。 ポイントは下位のsequencerでプロトコル変換用のsequenceを動作させること。
このシーケンスが上位のsequencerのitemを取得し、 それを現在動作しているsequencerの実行アイテムに分してdriverに送り込むことでプロトコルの変換が行われる。
該当の実装は以下の通り。

class ics_item_to_uart_item_seq extends uvm_sequence #(simple_uart_seq_item);
    `uvm_object_utils(ics_item_to_uart_item_seq)
    function new(string name="ics_item_to_uart_item");
        super.new(name);
    endfunction

    uvm_sequencer #(simple_ics_seq_item) up_sequencer;

    virtual task body();
        simple_ics_seq_item ics_item;
        simple_uart_seq_item uart_item;
        logic[4:0] id;
        bit enable_item_port = 0;
        forever begin
            up_sequencer.get_next_item(ics_item);
            uart_item = simple_uart_seq_item::type_id::create("test");
            id = ics_item.id;
            `uvm_create(uart_item)
            case(ics_item.cmd)
                simple_ics_seq_item::POSITION_R:
                    begin
                        `uvm_do_with(uart_item, {char=={simple_ics_seq_item::POSITION_R,id};})
                        `uvm_do_with(uart_item, {char=={0,ics_item.data[13:7]};})
                        `uvm_do_with(uart_item, {char=={0,ics_item.data[ 6:0]};})
                    end
                simple_ics_seq_item::READ_R:
                    begin
                        `uvm_do_with(uart_item, {char=={simple_ics_seq_item::READ_R,id};})
                        `uvm_do_with(uart_item, {char==ics_item.sub_cmd;})
                        if(ics_item.sub_cmd === simple_ics_seq_item::EEPROM) begin
                            for(int i = 0; i < 64; ++i) begin
                                `uvm_do_with(uart_item, {char==ics_item.eeprom_data[i];})
                            end
                        end else if(ics_item.sub_cmd === simple_ics_seq_item::TCH) begin
                            `uvm_do_with(uart_item, {char=={0,ics_item.data[13:7]};})
                            `uvm_do_with(uart_item, {char=={0,ics_item.data[ 6:0]};})
                        end else begin
                            `uvm_do_with(uart_item, {char==ics_item.data[7:0];})
                        end
                    end
                simple_ics_seq_item::WRITE_R:
                    begin
                        `uvm_do_with(uart_item, {char=={simple_ics_seq_item::WRITE_R,id};})
                        `uvm_do_with(uart_item, {char==ics_item.sub_cmd;})
                        if(ics_item.sub_cmd === simple_ics_seq_item::EEPROM) begin
                            //do nothing
                        end else begin
                            `uvm_do_with(uart_item, {char==ics_item.data[7:0];})
                        end
                    end
                simple_ics_seq_item::ID_R:
                    begin
                        `uvm_do_with(uart_item, {char=={simple_ics_seq_item::ID,id};})
                    end
                simple_ics_seq_item::POSITION:
                    begin
                        `uvm_do_with(uart_item, {char=={simple_ics_seq_item::POSITION,id};})
                        `uvm_do_with(uart_item, {char=={0,ics_item.data[13:7]};})
                        `uvm_do_with(uart_item, {char=={0,ics_item.data[ 6:0]};})
                    end
                simple_ics_seq_item::READ:
                    begin
                        `uvm_do_with(uart_item, {char=={simple_ics_seq_item::READ,id};})
                        `uvm_do_with(uart_item, {char==ics_item.sub_cmd;})
                    end
                simple_ics_seq_item::WRITE:
                    begin
                        `uvm_do_with(uart_item, {char=={simple_ics_seq_item::WRITE,id};})
                        `uvm_do_with(uart_item, {char==ics_item.sub_cmd;})
                        if(ics_item.sub_cmd === simple_ics_seq_item::EEPROM) begin
                            for(int i = 0; i < 64; ++i) begin
                                `uvm_do_with(uart_item, {char==ics_item.eeprom_data[i];})
                            end
                        end else begin
                            `uvm_do_with(uart_item, {char==ics_item.data[7:0];})
                        end
                    end
                simple_ics_seq_item::ID:
                    begin
                        if(ics_item.id_sub_cmd === simple_ics_seq_item::ID_READ) begin
                            `uvm_do_with(uart_item, {char==8'hff;})
                        end else begin
                            `uvm_do_with(uart_item, {char=={simple_ics_seq_item::ID,id};})
                        end
                        for(int i = 0; i < 3; ++i) begin
                            `uvm_do_with(uart_item, {char==ics_item.id_sub_cmd;})
                        end
                    end
            endcase
            up_sequencer.item_done();
        end
    endtask

endclass