Skip to content

Instantly share code, notes, and snippets.

@ikwzm
Created April 4, 2012 12:13
Show Gist options
  • Save ikwzm/2300724 to your computer and use it in GitHub Desktop.
Save ikwzm/2300724 to your computer and use it in GitHub Desktop.
Data Path Reducer (Data Width Converter) VHDL Model.

Data Path Reducer VHDL RTL Model.

###概要### 異なるデータ幅のパスを継ぐためのアダプタです.

REDUCER とは配管用語で径違い継ぎ手、つまり直径違う配管(パイプ)を接続 するために用いる管継手のことです. 論理回路の世界でも、ビット幅の異なるデータパスどうしを継ぐことが多い のでこのような汎用のアダプタを作って REDUCER という名前をつけました.

ちょっと汎用的に作りすぎたせいか、多少回路が冗長です. 特にI_WIDTHが大きいとかなり大きな回路になってしまいます.
例えば32bit入力64bit出力の場合、
WORD_BITS=8 、ENBL_BITS=1、I_WIDTH=4、O_WIDTH=8 とするよりも、
WORD_BITS=32、ENBL_BITS=4、I_WIDTH=1、O_WIDTH=2 としたほうが
回路はコンパクトになります.

O_WIDTH>I_WIDTHの場合、最初のワードデータを出力する際のオフセットを設定できます.
例えばWORD_BITS=8、I_WIDTH=1、O_WIDTH=4(1バイト入力4バイト出力)の場合、
OFFSET="0000"に設定すると、最初に入力したバイトデータは1バイト目から出力されます.
OFFSET="0001"に設定すると、最初に入力したバイトデータは2バイト目から出力されます.
OFFSET="0011"に設定すると、最初に入力したバイトデータは3バイト目から出力されます.
OFFSET="0111"に設定すると、最初に入力したバイトデータは4バイト目から出力されます.

少し変わった使い方として、I_WIDTH以下の任意のワード数を入力して、O_WIDTHの固定長の ワード数がたまった毎に出力させるようにできます。

###TODO### 残念ながらテストベンチは未完成です。すべてのパターンのテストをしているわけではありません。

###ライセンス### 二条項BSDライセンス (2-clause BSD license) で公開しています。

GHDL=ghdl
GHDLFLAGS=--mb-comments
WORK=work
TEST_BENCH = test_bench_dwc_w08_i1_o1_q0_j0 \
test_bench_dwc_w08_i1_o2_q0_j0 \
test_bench_dwc_w08_i1_o3_q0_j0 \
test_bench_dwc_w08_i1_o4_q0_j0 \
test_bench_dwc_w08_i2_o1_q0_j0 \
test_bench_dwc_w08_i2_o2_q0_j0 \
test_bench_dwc_w08_i2_o3_q0_j0 \
test_bench_dwc_w08_i2_o4_q0_j0 \
test_bench_dwc_w08_i3_o1_q0_j0 \
test_bench_dwc_w08_i3_o2_q0_j0 \
test_bench_dwc_w08_i3_o3_q0_j0 \
test_bench_dwc_w08_i3_o4_q0_j0 \
test_bench_dwc_w08_i4_o1_q0_j0 \
test_bench_dwc_w08_i4_o2_q0_j0 \
test_bench_dwc_w08_i4_o3_q0_j0 \
test_bench_dwc_w08_i4_o4_q0_j0 \
test_bench_dwc_w08_i1_o1_q1_j0 \
test_bench_dwc_w08_i1_o2_q2_j0 \
test_bench_dwc_w08_i1_o3_q3_j0 \
test_bench_dwc_w08_i1_o4_q4_j0 \
test_bench_dwc_w08_i2_o1_q2_j0 \
test_bench_dwc_w08_i2_o2_q3_j0 \
test_bench_dwc_w08_i2_o3_q4_j0 \
test_bench_dwc_w08_i2_o4_q5_j0 \
test_bench_dwc_w08_i4_o1_q0_j1 \
test_bench_dwc_w08_i4_o2_q0_j1 \
test_bench_dwc_w08_i4_o3_q0_j1 \
test_bench_dwc_w08_i4_o4_q0_j1 \
test_bench_dwc_w32_i1_o1_q0_j0 \
test_bench_dwc_w32_i1_o2_q0_j0 \
test_bench_dwc_w32_i2_o1_q0_j0 \
test_bench_dwc_w32_i2_o2_q0_j0 \
$(END_LIST)
all: $(TEST_BENCH)
clean:
rm -f *.o *.cf tmp.vhd $(TEST_BENCH) $(addsuffix .o,$(TEST_BENCH)) $(addsuffix .vhd,$(TEST_BENCH))
%.o : %.vhd
$(GHDL) -a $(GHDLFLAGS) --work=$(WORK) $<
$(TEST_BENCH) : $(addsuffix .o,$(TEST_BENCH))
$(GHDL) -e $(GHDLFLAGS) --work=$(WORK) $@
-$(GHDL) -r $(GHDLFLAGS) --work=$(WORK) $@
reducer_test_model.o : reducer.o
$(addsuffix .o,$(TEST_BENCH)) : reducer_test_model.o
test_bench_dwc_w08_i1_o1_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/1/g" -e "s/%O/1/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i1_o2_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/1/g" -e "s/%O/2/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i1_o3_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/1/g" -e "s/%O/3/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i1_o4_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/1/g" -e "s/%O/4/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i2_o1_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/2/g" -e "s/%O/1/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i2_o2_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/2/g" -e "s/%O/2/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i2_o3_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/2/g" -e "s/%O/3/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i2_o4_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/2/g" -e "s/%O/4/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i3_o1_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/3/g" -e "s/%O/1/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i3_o2_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/3/g" -e "s/%O/2/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i3_o3_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/3/g" -e "s/%O/3/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i3_o4_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/3/g" -e "s/%O/4/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i4_o1_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/4/g" -e "s/%O/1/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i4_o2_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/4/g" -e "s/%O/2/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i4_o3_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/4/g" -e "s/%O/3/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i4_o4_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/4/g" -e "s/%O/4/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i1_o1_q1_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/1/g" -e "s/%O/1/g" -e "s/%Q/1/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i1_o2_q2_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/1/g" -e "s/%O/2/g" -e "s/%Q/2/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i1_o3_q3_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/1/g" -e "s/%O/3/g" -e "s/%Q/3/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i1_o4_q4_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/1/g" -e "s/%O/4/g" -e "s/%Q/4/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i2_o1_q2_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/2/g" -e "s/%O/1/g" -e "s/%Q/2/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i2_o2_q3_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/2/g" -e "s/%O/2/g" -e "s/%Q/3/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i2_o3_q4_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/2/g" -e "s/%O/3/g" -e "s/%Q/4/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i2_o4_q5_j0.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/2/g" -e "s/%O/4/g" -e "s/%Q/5/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w08_i4_o1_q0_j1.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/4/g" -e "s/%O/1/g" -e "s/%Q/0/g" -e "s/%J/1/g" < $< > $@
test_bench_dwc_w08_i4_o2_q0_j1.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/4/g" -e "s/%O/2/g" -e "s/%Q/0/g" -e "s/%J/1/g" < $< > $@
test_bench_dwc_w08_i4_o3_q0_j1.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/4/g" -e "s/%O/3/g" -e "s/%Q/0/g" -e "s/%J/1/g" < $< > $@
test_bench_dwc_w08_i4_o4_q0_j1.vhd : test_bench_template.vhd
sed -e "s/%W/08/g" -e "s/%I/4/g" -e "s/%O/4/g" -e "s/%Q/0/g" -e "s/%J/1/g" < $< > $@
test_bench_dwc_w32_i1_o1_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/32/g" -e "s/%I/1/g" -e "s/%O/1/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w32_i1_o2_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/32/g" -e "s/%I/1/g" -e "s/%O/2/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w32_i2_o1_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/32/g" -e "s/%I/2/g" -e "s/%O/1/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
test_bench_dwc_w32_i2_o2_q0_j0.vhd : test_bench_template.vhd
sed -e "s/%W/32/g" -e "s/%I/2/g" -e "s/%O/2/g" -e "s/%Q/0/g" -e "s/%J/0/g" < $< > $@
-----------------------------------------------------------------------------------
--! @file reducer.vhd
--! @brief REDUCER MODULE :
--! 異なるデータ幅のパスを継ぐためのアダプタ
--! @version 0.1.1
--! @date 2012/4/8
--! @author Ichiro Kawazome <ichiro_k@ca2.so-net.ne.jp>
-----------------------------------------------------------------------------------
--
-- Copyright (C) 2012 Ichiro Kawazome
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions
-- are met:
--
-- 1. Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
--
-- 2. 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.
--
-- 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.
--
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
-----------------------------------------------------------------------------------
--! @brief REDUCER :
--! 異なるデータ幅のパスを継ぐためのアダプタ.
--! * REDUCER とは配管用語で径違い継ぎ手、つまり直径違う配管(パイプ)を接続
--! するために用いる管継手のことです.
--! * 論理回路の世界でも、ビット幅の異なるデータパスどうしを継ぐことが多い
--! のでこのような汎用のアダプタを作って REDUCER という名前をつけました.
--! * ちょっと汎用的に作りすぎたせいか、多少回路が冗長です.
--! 特にI_WIDTHが大きいとかなり大きな回路になってしまいます.
--! 例えば32bit入力64bit出力の場合、
--! WORD_BITS=8 、ENBL_BITS=1、I_WIDTH=4、O_WIDTH=8 とするよりも、
--! WORD_BITS=32、ENBL_BITS=4、I_WIDTH=1、O_WIDTH=2 としたほうが
--! 回路はコンパクトになります.
--! * O_WIDTH>I_WIDTHの場合、最初のワードデータを出力する際のオフセットを
--! 設定できます. 詳細はOFFSETの項を参照.
-----------------------------------------------------------------------------------
entity REDUCER is
generic (
WORD_BITS : --! @brief WORD BITS :
--! 1ワードのデータのビット数を指定する.
integer := 8;
ENBL_BITS : --! @brief ENABLE BITS :
--! ワードデータのうち有効なデータであることを示す信号の
--! ビット数を指定する.
integer := 1;
I_WIDTH : --! @brief INPUT WORD WIDTH :
--! 入力側のデータのワード数を指定する.
integer := 4;
O_WIDTH : --! @brief OUTPUT WORD WIDTH :
--! 出力側のデータのワード数を指定する.
integer := 4;
QUEUE_SIZE : --! @brief QUEUE SIZE :
--! キューの大きさをワード数で指定する.
--! * 少なくともキューの大きさは、I_WIDTH+O_WIDTH-1以上で
--! なければならない.
--! * ただしQUEUE_SIZE=0を指定した場合は、キューの深さは
--! 自動的にI_WIDTH+O_WIDTH に設定される.
integer := 0;
VALID_MIN : --! @brief BUFFER VALID MINIMUM NUMBER :
--! VALID信号の配列の最小値を指定する.
integer := 0;
VALID_MAX : --! @brief BUFFER VALID MAXIMUM NUMBER :
--! VALID信号の配列の最大値を指定する.
integer := 0;
I_JUSTIFIED : --! @brief INPUT WORD JUSTIFIED :
--! 入力側の有効なデータが常にLOW側に詰められていることを
--! 示すフラグ.
--! * 常にLOW側に詰められている場合は、シフタが必要なくなる
--! ため回路が簡単になる.
integer := 0;
FLUSH_ENABLE: --! @brief FLUSH ENABLE :
--! FLUSH/I_FLUSHによるフラッシュ処理を有効にするかどうかを
--! 指定する.
--! * FLUSHとDONEとの違いは、DONEは最後のデータの出力時に
--! キューの状態をすべてクリアするのに対して、
--! FLUSHは最後のデータの出力時にENBLだけをクリアしてVALは
--! クリアしない.
--! そのため次の入力データは、最後のデータの次のワード位置
--! から格納される.
--! * フラッシュ処理を行わない場合は、0を指定すると回路が若干
--! 簡単になる.
integer := 1
);
port (
-------------------------------------------------------------------------------
-- クロック&リセット信号
-------------------------------------------------------------------------------
CLK : --! @brief CLOCK :
--! クロック信号
in std_logic;
RST : --! @brief ASYNCRONOUSE RESET :
--! 非同期リセット信号.アクティブハイ.
in std_logic;
CLR : --! @brief SYNCRONOUSE RESET :
--! 同期リセット信号.アクティブハイ.
in std_logic;
-------------------------------------------------------------------------------
-- 各種制御信号
-------------------------------------------------------------------------------
START : --! @brief START :
--! 開始信号.
--! * この信号はOFFSETを内部に設定してキューを初期化する.
--! * 最初にデータ入力と同時にアサートしても構わない.
in std_logic;
OFFSET : --! @brief OFFSET :
--! 最初のワードの出力位置を指定する.
--! * START信号がアサートされた時のみ有効.
--! * O_WIDTH>I_WIDTHの場合、最初のワードデータを出力する際の
--! オフセットを設定できる.
--! * 例えばWORD_BITS=8、I_WIDTH=1(1バイト入力)、O_WIDTH=4(4バイト出力)の場合、
--! OFFSET="0000"に設定すると、最初に入力したバイトデータは
--! 1バイト目から出力される.
--! OFFSET="0001"に設定すると、最初に入力したバイトデータは
--! 2バイト目から出力される.
--! OFFSET="0011"に設定すると、最初に入力したバイトデータは
--! 3バイト目から出力される.
--! OFFSET="0111"に設定すると、最初に入力したバイトデータは
--! 4バイト目から出力される.
in std_logic_vector(O_WIDTH-1 downto 0);
DONE : --! @brief DONE :
--! 終了信号.
--! * この信号をアサートすることで、キューに残っているデータ
--! を掃き出す.
--! その際、最後のワードと同時にO_DONE信号がアサートされる.
--! * FLUSH信号との違いは、FLUSH_ENABLEの項を参照.
in std_logic;
FLUSH : --! @brief FLUSH :
--! フラッシュ信号.
--! * この信号をアサートすることで、キューに残っているデータ
--! を掃き出す.
--! その際、最後のワードと同時にO_FLUSH信号がアサートされる.
--! * DONE信号との違いは、FLUSH_ENABLEの項を参照.
in std_logic;
BUSY : --! @brief BUSY :
--! ビジー信号.
--! * 最初にデータが入力されたときにアサートされる.
--! * 最後のデータが出力し終えたらネゲートされる.
out std_logic;
VALID : --! @brief QUEUE VALID FLAG :
--! キュー有効信号.
--! * 対応するインデックスのキューに有効なワードが入って
--! いるかどうかを示すフラグ.
out std_logic_vector(VALID_MAX downto VALID_MIN);
-------------------------------------------------------------------------------
-- 入力側 I/F
-------------------------------------------------------------------------------
I_DATA : --! @brief INPUT WORD DATA :
--! ワードデータ入力.
in std_logic_vector(I_WIDTH*WORD_BITS-1 downto 0);
I_ENBL : --! @brief INPUT WORD ENABLE :
--! ワードイネーブル信号入力.
in std_logic_vector(I_WIDTH*ENBL_BITS-1 downto 0);
I_DONE : --! @brief INPUT WORD DONE :
--! 最終ワード信号入力.
--! * 最後の力ワードデータ入であることを示すフラグ.
--! * 基本的にはDONE信号と同じ働きをするが、I_DONE信号は
--! 最後のワードデータを入力する際に同時にアサートする.
--! * I_FLUSH信号との違いはFLUSH_ENABLEの項を参照.
in std_logic;
I_FLUSH : --! @brief INPUT WORD FLUSH :
--! 最終ワード信号入力.
--! * 最後のワードデータ入力であることを示すフラグ.
--! * 基本的にはFLUSH信号と同じ働きをするが、I_FLUSH信号は
--! 最後のワードデータを入力する際に同時にアサートする.
--! * I_DONE信号との違いはFLUSH_ENABLEの項を参照.
in std_logic;
I_VAL : --! @brief INPUT WORD VALID :
--! 入力ワード有効信号.
--! * I_DATA/I_ENBL/I_DONE/I_FLUSHが有効であることを示す.
--! * I_VAL='1'and I_RDY='1'でワードデータがキューに取り込まれる.
in std_logic;
I_RDY : --! @brief INPUT WORD READY :
--! 入力レディ信号.
--! * キューが次のワードデータを入力出来ることを示す.
--! * I_VAL='1'and I_RDY='1'でワードデータがキューに取り込まれる.
out std_logic;
-------------------------------------------------------------------------------
-- 出力側 I/F
-------------------------------------------------------------------------------
O_DATA : --! @brief OUTPUT WORD DATA :
--! ワードデータ出力.
out std_logic_vector(O_WIDTH*WORD_BITS-1 downto 0);
O_ENBL : --! @brief OUTPUT WORD ENABLE :
--! ワードイネーブル信号出力.
out std_logic_vector(O_WIDTH*ENBL_BITS-1 downto 0);
O_DONE : --! @brief OUTPUT WORD DONE :
--! 最終ワード信号出力.
--! * 最後のワードデータ出力であることを示すフラグ.
--! * O_FLUSH信号との違いはFLUSH_ENABLEの項を参照.
out std_logic;
O_FLUSH : --! @brief OUTPUT WORD FLUSH :
--! 最終ワード信号出力.
--! * 最後のワードデータ出力であることを示すフラグ.
--! * O_DONE信号との違いはFLUSH_ENABLEの項を参照.
out std_logic;
O_VAL : --! @brief OUTPUT WORD VALID :
--! 出力ワード有効信号.
--! * O_DATA/O_ENBL/O_DONE/O_FLUSHが有効であることを示す.
--! * O_VAL='1'and O_RDY='1'でワードデータがキューから取り除かれる.
out std_logic;
O_RDY : --! @brief OUTPUT WORD READY :
--! 出力レディ信号.
--! * キューから次のワードを取り除く準備が出来ていることを示す.
--! * O_VAL='1'and O_RDY='1'でワードデータがキューから取り除かれる.
in std_logic
);
end REDUCER;
-----------------------------------------------------------------------------------
--
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
architecture RTL of REDUCER is
-------------------------------------------------------------------------------
--! @brief ワード単位でデータ/データイネーブル信号/ワード有効フラグをまとめておく
-------------------------------------------------------------------------------
type WORD_TYPE is record
DATA : std_logic_vector(WORD_BITS-1 downto 0);
ENBL : std_logic_vector(ENBL_BITS-1 downto 0);
VAL : boolean;
end record;
-------------------------------------------------------------------------------
--! @brief WORD TYPE の初期化時の値.
-------------------------------------------------------------------------------
constant WORD_NULL : WORD_TYPE := (DATA => (others => '0'),
ENBL => (others => '0'),
VAL => FALSE);
-------------------------------------------------------------------------------
--! @brief WORD TYPE の配列の定義.
-------------------------------------------------------------------------------
type WORD_VECTOR is array (INTEGER range <>) of WORD_TYPE;
-------------------------------------------------------------------------------
--! @brief キューの最後にワードを追加するプロシージャ.
-------------------------------------------------------------------------------
procedure APPEND(
variable QUEUE : inout WORD_VECTOR;
WORDS : in WORD_VECTOR
) is
alias vec : WORD_VECTOR(0 to WORDS'length-1) is WORDS;
type bv is array (INTEGER range <>) of boolean;
variable val : bv(QUEUE'low to QUEUE'high);
variable hit : boolean;
begin
for i in val'range loop -- 先に val を作っておいた方が論理合成の結果
val(i) := QUEUE(i).VAL; -- が良かった
end loop; --
for i in val'range loop
if (val(i) = FALSE) then
QUEUE(i) := WORD_NULL;
for pos in vec'range loop
if (i-pos-1 < val'low) then
hit := TRUE;
else
hit := val(i-pos-1);
end if;
if (hit) then
QUEUE(i) := vec(pos);
exit;
end if;
end loop;
end if;
end loop;
end APPEND;
-------------------------------------------------------------------------------
--! @brief キューのサイズを計算する関数.
-------------------------------------------------------------------------------
function QUEUE_DEPTH return integer is begin
if (QUEUE_SIZE > 0) then
if (QUEUE_SIZE >= O_WIDTH+I_WIDTH-1) then
return QUEUE_SIZE;
else
assert (QUEUE_SIZE >= I_WIDTH+O_WIDTH-1)
report "require QUEUE_SIZE >= I_WIDTH+O_WIDTH-1" severity WARNING;
return I_WIDTH+O_WIDTH;
end if;
else
return I_WIDTH+O_WIDTH;
end if;
end function;
-------------------------------------------------------------------------------
--! @brief 現在のキューの状態.
-------------------------------------------------------------------------------
signal curr_queue : WORD_VECTOR(0 to QUEUE_DEPTH-1);
-------------------------------------------------------------------------------
--! @brief 1ワード分のイネーブル信号がオール0であることを示す定数.
-------------------------------------------------------------------------------
constant ENBL_NULL : std_logic_vector(ENBL_BITS-1 downto 0) := (others => '0');
-------------------------------------------------------------------------------
--! @brief FLUSH 出力フラグ.
-------------------------------------------------------------------------------
signal flush_output : std_logic;
-------------------------------------------------------------------------------
--! @brief FLUSH 保留フラグ.
-------------------------------------------------------------------------------
signal flush_pending : std_logic;
-------------------------------------------------------------------------------
--! @brief DONE 出力フラグ.
-------------------------------------------------------------------------------
signal done_output : std_logic;
-------------------------------------------------------------------------------
--! @brief DONE 保留フラグ.
-------------------------------------------------------------------------------
signal done_pending : std_logic;
-------------------------------------------------------------------------------
--! @brief O_VAL信号を内部で使うための信号.
-------------------------------------------------------------------------------
signal o_valid : std_logic;
-------------------------------------------------------------------------------
--! @brief I_RDY信号を内部で使うための信号.
-------------------------------------------------------------------------------
signal i_ready : std_logic;
-------------------------------------------------------------------------------
--! @brief BUSY信号を内部で使うための信号.
-------------------------------------------------------------------------------
signal curr_busy : std_logic;
begin
-------------------------------------------------------------------------------
-- メインプロセス
-------------------------------------------------------------------------------
process (CLK, RST)
variable in_word : WORD_VECTOR(0 to I_WIDTH-1);
variable next_queue : WORD_VECTOR(curr_queue'range);
variable next_flush_output : std_logic;
variable next_flush_pending: std_logic;
variable next_flush_fall : std_logic;
variable next_done_output : std_logic;
variable next_done_pending : std_logic;
variable next_done_fall : std_logic;
variable pending_flag : boolean;
begin
if (RST = '1') then
curr_queue <= (others => WORD_NULL);
flush_output <= '0';
flush_pending <= '0';
done_output <= '0';
done_pending <= '0';
i_ready <= '0';
o_valid <= '0';
curr_busy <= '0';
elsif (CLK'event and CLK = '1') then
if (CLR = '1') then
curr_queue <= (others => WORD_NULL);
flush_output <= '0';
flush_pending <= '0';
done_output <= '0';
done_pending <= '0';
i_ready <= '0';
o_valid <= '0';
curr_busy <= '0';
else
-------------------------------------------------------------------
-- 次のクロックでのキューの状態を示す変数に現在のキューの状態をセット
-------------------------------------------------------------------
next_queue := curr_queue;
-------------------------------------------------------------------
-- データ出力時の次のクロックでのキューの状態に更新
-------------------------------------------------------------------
if (o_valid = '1' and O_RDY = '1') then
if (FLUSH_ENABLE > 0 ) and
(flush_output = '1') and
(O_WIDTH > 1 ) and
(curr_queue(O_WIDTH-1).VAL = FALSE) then
for i in next_queue'range loop
if (i < O_WIDTH-1) then
next_queue(i).VAL := curr_queue(i).VAL;
else
next_queue(i).VAL := FALSE;
end if;
next_queue(i).DATA := (others => '0');
next_queue(i).ENBL := (others => '0');
end loop;
else
for i in next_queue'range loop
if (i+O_WIDTH > next_queue'high) then
next_queue(i) := WORD_NULL;
else
next_queue(i) := curr_queue(i+O_WIDTH);
end if;
end loop;
end if;
end if;
-------------------------------------------------------------------
-- キュー初期化時の次のクロックでのキューの状態に更新
-------------------------------------------------------------------
if (START = '1') then
for i in next_queue'range loop
if (i < O_WIDTH-1) then
next_queue(i).VAL := (OFFSET(i) = '1');
else
next_queue(i).VAL := FALSE;
end if;
next_queue(i).DATA := (others => '0');
next_queue(i).ENBL := (others => '0');
end loop;
end if;
-------------------------------------------------------------------
-- データ入力時の次のクロックでのキューの状態に更新
-------------------------------------------------------------------
if (I_VAL = '1' and i_ready = '1') then
for i in in_word'range loop
in_word(i).DATA := I_DATA((i+1)*WORD_BITS-1 downto i*WORD_BITS);
in_word(i).ENBL := I_ENBL((i+1)*ENBL_BITS-1 downto i*ENBL_BITS);
in_word(i).VAL := (I_ENBL((i+1)*ENBL_BITS-1 downto i*ENBL_BITS) /= ENBL_NULL);
end loop;
if (I_JUSTIFIED > 0) or
(in_word'length = 1) then
APPEND(next_queue, in_word);
else
for i in in_word'range loop
if (in_word(i).VAL) then
APPEND(next_queue, in_word(i to in_word'high));
exit;
end if;
end loop;
end if;
end if;
-------------------------------------------------------------------
-- 次のクロックでのキューの状態をレジスタに保持
-------------------------------------------------------------------
curr_queue <= next_queue;
-------------------------------------------------------------------
-- 次のクロックでのキューの状態でO_WIDTHの位置にデータが入って
-- いるか否かをチェック.
-------------------------------------------------------------------
if (next_queue'high >= O_WIDTH) then
pending_flag := (next_queue(O_WIDTH).VAL);
else
pending_flag := FALSE;
end if;
-------------------------------------------------------------------
-- FLUSH制御
-------------------------------------------------------------------
if (FLUSH_ENABLE = 0) then
next_flush_output := '0';
next_flush_pending := '0';
next_flush_fall := '0';
elsif (flush_output = '1') then
if (o_valid = '1' and O_RDY = '1') then
next_flush_output := '0';
next_flush_pending := '0';
next_flush_fall := '1';
else
next_flush_output := '1';
next_flush_pending := '0';
next_flush_fall := '0';
end if;
elsif (flush_pending = '1') or
(FLUSH = '1') or
(I_VAL = '1' and i_ready = '1' and I_FLUSH = '1') then
if (pending_flag) then
next_flush_output := '0';
next_flush_pending := '1';
next_flush_fall := '0';
else
next_flush_output := '1';
next_flush_pending := '0';
next_flush_fall := '0';
end if;
else
next_flush_output := '0';
next_flush_pending := '0';
next_flush_fall := '0';
end if;
flush_output <= next_flush_output;
flush_pending <= next_flush_pending;
-------------------------------------------------------------------
-- DONE制御
-------------------------------------------------------------------
if (done_output = '1') then
if (o_valid = '1' and O_RDY = '1') then
next_done_output := '0';
next_done_pending := '0';
next_done_fall := '1';
else
next_done_output := '1';
next_done_pending := '0';
next_done_fall := '0';
end if;
elsif (done_pending = '1') or
(DONE = '1') or
(I_VAL = '1' and i_ready = '1' and I_DONE = '1') then
if (pending_flag) then
next_done_output := '0';
next_done_pending := '1';
next_done_fall := '0';
else
next_done_output := '1';
next_done_pending := '0';
next_done_fall := '0';
end if;
else
next_done_output := '0';
next_done_pending := '0';
next_done_fall := '0';
end if;
done_output <= next_done_output;
done_pending <= next_done_pending;
-------------------------------------------------------------------
-- 出力有効信号の生成
-------------------------------------------------------------------
if (next_done_output = '1') or
(next_flush_output = '1') or
(next_queue(O_WIDTH-1).VAL = TRUE) then
o_valid <= '1';
else
o_valid <= '0';
end if;
-------------------------------------------------------------------
-- 入力可能信号の生成
-------------------------------------------------------------------
if (next_done_output = '0' and next_done_pending = '0') and
(next_flush_output = '0' and next_flush_pending = '0') and
(next_queue(next_queue'length-I_WIDTH).VAL = FALSE) then
i_ready <= '1';
else
i_ready <= '0';
end if;
-------------------------------------------------------------------
-- 現在処理中であることを示すフラグ
-- 最初に入力があった時点で'1'になり、O_DONEまたはO_FLUSHが出力完了
-- した時点で'0'になる。
-------------------------------------------------------------------
if (curr_busy = '1') then
if (next_flush_fall = '1') or
(next_done_fall = '1') then
curr_busy <= '0';
else
curr_busy <= '1';
end if;
else
if (I_VAL = '1' and i_ready = '1') then
curr_busy <= '1';
else
curr_busy <= '0';
end if;
end if;
end if;
end if;
end process;
-------------------------------------------------------------------------------
-- 各種出力信号の生成
-------------------------------------------------------------------------------
O_FLUSH <= flush_output when(FLUSH_ENABLE > 0) else '0';
O_DONE <= done_output;
O_VAL <= o_valid;
I_RDY <= i_ready;
BUSY <= curr_busy;
process (curr_queue) begin
for i in 0 to O_WIDTH-1 loop
O_DATA((i+1)*WORD_BITS-1 downto i*WORD_BITS) <= curr_queue(i).DATA;
O_ENBL((i+1)*ENBL_BITS-1 downto i*ENBL_BITS) <= curr_queue(i).ENBL;
end loop;
for i in VALID'range loop
if (curr_queue'low <= i and i <= curr_queue'high) then
if (curr_queue(i).VAL) then
VALID(i) <= '1';
else
VALID(i) <= '0';
end if;
else
VALID(i) <= '0';
end if;
end loop;
end process;
end RTL;
-----------------------------------------------------------------------------------
--! @file reducer_test_model.vhd
--! @brief TEST MODEL for REDUCER :
--! @version 1.0.0
--! @date 2012/4/3
--! @author Ichiro Kawazome <ichiro_k@ca2.so-net.ne.jp>
-----------------------------------------------------------------------------------
--
-- Copyright (C) 2012 Ichiro Kawazome
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions
-- are met:
--
-- 1. Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
--
-- 2. 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.
--
-- 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.
--
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
package RANDOM_DATA_TABLE is
procedure GET(
WIDTH : in integer;
OFFSET : in integer;
ADDR : in integer;
SIZE : in integer;
LEN : out integer;
DATA : out std_logic_vector;
ENBL : out std_logic_vector;
DONE : out std_logic);
constant TABLE_SIZE : integer := 4096;
constant ERROR_CODE : std_logic_vector(7 downto 0) := "11001100";
end RANDOM_DATA_TABLE;
-----------------------------------------------------------------------------------
--
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.uniform;
use std.textio.all;
package body RANDOM_DATA_TABLE is
type DATA_TABLE_TYPE is array (INTEGER range <>) of std_logic_vector(7 downto 0);
function DATA_TABLE_GEN(SIZE:integer) return DATA_TABLE_TYPE is
variable table : DATA_TABLE_TYPE(0 to SIZE-1);
variable seed1 : integer := 1234;
variable seed2 : integer := 5678;
variable rnd_num : real;
variable pattern : integer range 0 to 255;
begin
for i in table'range loop
UNIFORM(seed1,seed2,rnd_num);
pattern := integer(rnd_num*255.0);
while (pattern = TO_INTEGER(unsigned(ERROR_CODE))) loop
UNIFORM(seed1,seed2,rnd_num);
pattern := integer(rnd_num*255.0);
end loop;
table(i) := std_logic_vector(TO_UNSIGNED(pattern,8));
end loop;
return table;
end function;
constant DATA_TABLE : DATA_TABLE_TYPE(0 to TABLE_SIZE-1) := DATA_TABLE_GEN(TABLE_SIZE);
procedure GET( WIDTH : in integer;
OFFSET : in integer;
ADDR : in integer;
SIZE : in integer;
LEN : out integer;
DATA : out std_logic_vector;
ENBL : out std_logic_vector;
DONE : out std_logic) is
variable o_data : std_logic_vector(8*WIDTH-1 downto 0);
variable o_enbl : std_logic_vector( WIDTH-1 downto 0);
variable f_enbl : std_logic_vector( WIDTH-1 downto 0);
variable l_enbl : std_logic_vector( WIDTH-1 downto 0);
variable length : integer;
variable addr_end : integer range 0 to TABLE_SIZE-1;
begin
addr_end := OFFSET + SIZE - 1;
for i in f_enbl'range loop
if (i >= OFFSET) then
f_enbl(i) := '1';
else
f_enbl(i) := '0';
end if;
end loop;
for i in l_enbl'range loop
if (i <= addr_end) then
l_enbl(i) := '1';
else
l_enbl(i) := '0';
end if;
end loop;
if (addr_end < WIDTH) then
DONE := '1';
else
DONE := '0';
end if;
o_enbl := f_enbl and l_enbl;
length := 0;
for i in o_enbl'range loop
if (o_enbl(i) = '1') then
length := length + 1;
o_data((i+1)*8-1 downto i*8) := DATA_TABLE(ADDR-OFFSET+i);
else
o_data((i+1)*8-1 downto i*8) := ERROR_CODE;
end if;
end loop;
DATA := o_data;
ENBL := o_enbl;
LEN := length;
end GET;
end RANDOM_DATA_TABLE;
-----------------------------------------------------------------------------------
--
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity REDUCER_TEST_MODEL is
generic (
NAME : string;
DELAY : time;
WORD_BITS : integer := 32;
I_WIDTH : integer := 1;
O_WIDTH : integer := 4;
I_JUSTIFIED : integer := 0;
FLUSH_ENABLE : integer := 0;
AUTO_FINISH : integer := 1
);
port(
CLK : in std_logic;
RST : out std_logic;
CLR : out std_logic;
START : out std_logic;
OFFSET : out std_logic_vector(O_WIDTH-1 downto 0);
DONE : out std_logic;
FLUSH : out std_logic;
I_DATA : out std_logic_vector(I_WIDTH*(WORD_BITS )-1 downto 0);
I_ENBL : out std_logic_vector(I_WIDTH*(WORD_BITS/8)-1 downto 0);
I_FLUSH : out std_logic;
I_DONE : out std_logic;
I_VAL : out std_logic;
I_RDY : in std_logic := '0';
O_DATA : in std_logic_vector(O_WIDTH*(WORD_BITS )-1 downto 0) := (others => '0');
O_ENBL : in std_logic_vector(O_WIDTH*(WORD_BITS/8)-1 downto 0) := (others => '1');
O_FLUSH : in std_logic := '0';
O_DONE : in std_logic := '0';
O_VAL : in std_logic := '0';
O_RDY : out std_logic;
BUSY : in std_logic;
FINISH : out std_logic
);
end REDUCER_TEST_MODEL;
-----------------------------------------------------------------------------------
--
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
use WORK.RANDOM_DATA_TABLE;
architecture MODEL of REDUCER_TEST_MODEL is
constant I_BYTES : integer := I_WIDTH*WORD_BITS/8;
constant O_BYTES : integer := O_WIDTH*WORD_BITS/8;
constant HEX : STRING(1 to 16) := "0123456789ABCDEF";
signal SCENARIO : STRING(1 to 5);
signal RECV_REQ : boolean;
signal RECV_ACK : boolean;
signal RECV_FLUSH : boolean;
signal RECV_EOD : boolean;
signal RECV_ADDR : integer;
signal RECV_SIZE : integer;
signal RECV_MODE : integer;
signal i_valid : std_logic;
signal o_ready : std_logic;
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
-- function INT_TO_STRING(arg:integer;len:integer;space:character) return STRING is
-- variable str : STRING(1 to len);
-- variable value : integer;
-- begin
-- value := arg;
-- for i in str'right downto str'left loop
-- if (value > 0) then
-- case (value mod 10) is
-- when 0 => str(i) := '0';
-- when 1 => str(i) := '1';
-- when 2 => str(i) := '2';
-- when 3 => str(i) := '3';
-- when 4 => str(i) := '4';
-- when 5 => str(i) := '5';
-- when 6 => str(i) := '6';
-- when 7 => str(i) := '7';
-- when 8 => str(i) := '8';
-- when 9 => str(i) := '9';
-- when others => str(i) := 'X';
-- end case;
-- else
-- if (i = str'right) then
-- str(i) := '0';
-- else
-- str(i) := space;
-- end if;
-- end if;
-- value := value / 10;
-- end loop;
-- return str;
-- end INT_TO_STRING;
begin
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
process
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
procedure WAIT_CLK(CNT:integer) is
begin
if (CNT > 0) then
for i in 1 to CNT loop
wait until (CLK'event and CLK = '1');
end loop;
end if;
wait for DELAY;
end WAIT_CLK;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
procedure RECV_START (ADDR,SIZE,MODE:integer;FLUSH,EOD:boolean) is
begin
RECV_REQ <= TRUE;
RECV_ADDR <= ADDR;
RECV_SIZE <= SIZE;
RECV_MODE <= MODE;
RECV_FLUSH<= FLUSH;
RECV_EOD <= EOD;
wait until (CLK'event and CLK = '1' and RECV_ACK = TRUE);
wait for DELAY;
RECV_REQ <= FALSE;
end RECV_START;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
procedure RECV_END is
begin
wait until (CLK'event and CLK = '1' and RECV_ACK = FALSE);
wait for DELAY;
end RECV_END;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
procedure OUTPUT(ADDR,SIZE:integer;INITIALIZE,LAST,FLUSH:boolean) is
variable data : std_logic_vector(I_DATA'range);
variable enbl : std_logic_vector(I_ENBL'range);
variable valid : std_logic;
variable end_of_data : std_logic;
variable pos : integer;
variable bytes : integer;
variable len : integer;
variable lo_pos : integer;
variable num : integer;
begin
if (INITIALIZE and O_WIDTH > 1) then
for i in OFFSET'range loop
if (i < ((ADDR rem O_BYTES)/(WORD_BITS/8))) then
OFFSET(i) <= '1';
else
OFFSET(i) <= '0';
end if;
end loop;
START <= '1';
end if;
pos := ADDR;
bytes := SIZE;
while (bytes > 0) loop
lo_pos := pos rem I_BYTES;
RANDOM_DATA_TABLE.GET(I_BYTES,lo_pos,pos,bytes,len,data,enbl,end_of_data);
pos := pos + len;
bytes := bytes - len;
if (I_JUSTIFIED > 0 and enbl(0) = '0') then
num := 1;
for i in 1 to enbl'high loop
if (enbl(i) = '1') then
num := i;
exit;
end if;
end loop;
for i in enbl'low to enbl'high loop
if (i+num > enbl'high) then
I_DATA(8*(i+1)-1 downto 8*i) <= (others => '0');
I_ENBL( i) <= '0';
else
I_DATA(8*(i+1)-1 downto 8*i) <= data(8*(i+1+num)-1 downto 8*(i+num));
I_ENBL( i) <= enbl(i+num);
end if;
end loop;
else
I_DATA <= data;
I_ENBL <= enbl;
end if;
if (LAST) then
I_DONE <= end_of_data;
else
I_DONE <= '0';
end if;
if (FLUSH) then
I_FLUSH <= end_of_data;
else
I_FLUSH <= '0';
end if;
I_VAL <= '1';
i_valid <= '1';
wait until (CLK'event and CLK = '1' and I_RDY = '1');
wait for DELAY;
START <= '0';
I_VAL <= '0';
i_valid <= '0';
I_DONE <= '0';
I_FLUSH <= '0';
I_DATA <= (others => '1');
I_ENBL <= (others => '1');
end loop;
end procedure;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
procedure OUTPUT(ADDR,SIZE:integer) is
begin
OUTPUT(ADDR,SIZE,TRUE,TRUE,FALSE);
end procedure;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
variable max_addr : integer;
variable max_size : integer;
variable addr : integer;
variable remain_size : integer;
variable block_size : integer;
variable initialize : boolean;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
procedure DONE_REQ is
begin
DONE <= '1';
wait until (CLK'event and CLK = '1');
wait for DELAY;
DONE <= '0';
end procedure;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
procedure FLUSH_REQ is
begin
FLUSH <= '1';
wait until (CLK'event and CLK = '1');
wait for DELAY;
FLUSH <= '0';
end procedure;
begin
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
if (I_BYTES > O_BYTES) then
max_addr := I_BYTES;
max_size := (I_BYTES/O_BYTES)*(I_BYTES*5);
else
max_addr := O_BYTES;
max_size := (O_BYTES/I_BYTES)*(O_BYTES*5);
end if;
---------------------------------------------------------------------------
-- シミュレーションの開始、まずはリセットから。
---------------------------------------------------------------------------
assert(false) report "Starting Run..." severity NOTE;
SCENARIO <= "START";
RST <= '1';
CLR <= '1';
START <= '0';
OFFSET <= (others => '0');
DONE <= '0';
FLUSH <= '0';
I_DATA <= (others => '0');
I_ENBL <= (others => '0');
I_FLUSH <= '0';
I_DONE <= '0';
I_VAL <= '0';
i_valid <= '0';
WAIT_CLK( 4); RST <= '0';
CLR <= '0';
WAIT_CLK( 4);
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
SCENARIO <= "1.0.0";
for size in 1 to max_size loop
for pos in 0 to max_addr loop
addr := pos*max_addr+pos;
RECV_START(addr,size,0,FALSE,TRUE);
OUTPUT (addr,size );
RECV_END;
end loop;
end loop;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
SCENARIO <= "2.0.0";
for size in 1 to max_size loop
for pos in 0 to max_addr loop
addr := pos*max_addr+pos;
RECV_START(addr,size,1,FALSE,TRUE);
OUTPUT (addr,size );
RECV_END;
end loop;
end loop;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
SCENARIO <= "3.0.0";
for size in 1 to max_size loop
for pos in 0 to max_addr loop
addr := pos*max_addr+pos;
RECV_START(addr,size,2,FALSE,TRUE);
OUTPUT (addr,size );
RECV_END;
end loop;
end loop;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
SCENARIO <= "4.0.0";
if (WORD_BITS = 8 and I_WIDTH > 1) then
for size in 8 to 33 loop
for block_size in 1 to 11 loop
addr := 0;
remain_size := size;
RECV_START(addr,size,0,FALSE,TRUE);
initialize := TRUE;
while (remain_size > 0) loop
if (remain_size <= block_size) then
OUTPUT(addr,remain_size,initialize, TRUE ,FALSE);
addr := addr + remain_size;
remain_size := 0;
else
OUTPUT(addr,block_size ,initialize, FALSE,FALSE);
addr := addr + block_size;
remain_size := remain_size - block_size;
end if;
initialize := FALSE;
end loop;
RECV_END;
end loop;
end loop;
end if;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
SCENARIO <= "5.0.0";
if (WORD_BITS = 8 and I_WIDTH > 1) then
for size in 8 to 15 loop
for block_size in 1 to 11 loop
for wait_count in 0 to 3 loop
addr := 0;
remain_size := size;
RECV_START(addr,size,0,FALSE,FALSE);
initialize := TRUE;
while (remain_size > 0) loop
if (remain_size <= block_size) then
OUTPUT(addr,remain_size,initialize, FALSE,FALSE);
addr := addr + remain_size;
remain_size := 0;
else
OUTPUT(addr,block_size ,initialize, FALSE,FALSE);
addr := addr + block_size;
remain_size := remain_size - block_size;
end if;
initialize := FALSE;
end loop;
WAIT_CLK(wait_count);
DONE_REQ;
RECV_END;
end loop;
end loop;
end loop;
end if;
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
SCENARIO <= "6.0.0";wait for 0 ns;
if (FLUSH_ENABLE > 0 and WORD_BITS = 8 and I_WIDTH > 1) then
for size in 8 to 33 loop
for block_size in 1 to 11 loop
addr := 0;
remain_size := size;
initialize := TRUE;
while (remain_size > 0) loop
-- assert false report NAME & ":" & SCENARIO &
-- " addr=" & INT_TO_STRING(addr,4,'0') &
-- " size=" & INT_TO_STRING(size,4,'0') &
-- " remain_size=" & INT_TO_STRING(remain_size,4,'0') &
-- " block_size=" & INT_TO_STRING(block_size ,4,'0') severity note;
if (remain_size <= block_size) then
RECV_START(addr,remain_size,0,FALSE,TRUE);
OUTPUT(addr,remain_size,initialize, TRUE ,FALSE);
RECV_END;
addr := addr + remain_size;
remain_size := 0;
else
RECV_START(addr,block_size, 0,TRUE, TRUE);
OUTPUT(addr,block_size ,initialize, FALSE,TRUE );
RECV_END;
addr := addr + block_size;
remain_size := remain_size - block_size;
end if;
initialize := FALSE;
end loop;
end loop;
end loop;
end if;
---------------------------------------------------------------------------
-- シミュレーション終了
---------------------------------------------------------------------------
WAIT_CLK(10);
SCENARIO <= "DONE.";
WAIT_CLK(10);
if (AUTO_FINISH = 0) then
assert(false) report NAME & " Run complete..." severity NOTE;
FINISH <= 'Z';
else
FINISH <= 'Z';
assert(false) report NAME & " Run complete..." severity FAILURE;
end if;
wait;
end process;
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
RECV:process
variable addr : integer;
variable size : integer;
variable len : integer;
variable lo_pos : integer;
variable data : std_logic_vector(O_DATA'range);
variable enbl : std_logic_vector(O_ENBL'range);
variable end_of_data : std_logic;
variable data_ok : boolean;
begin
RECV_ACK <= FALSE;
O_RDY <= '0';
o_ready <= '0';
RECV_LOOP: loop
wait until (CLK'event and CLK = '1' and RECV_REQ = TRUE);
wait for DELAY;
RECV_ACK <= TRUE;
if (RECV_MODE = 0) then
O_RDY <= '1';
o_ready <= '1';
else
O_RDY <= '0';
o_ready <= '0';
end if;
addr := RECV_ADDR;
size := RECV_SIZE;
CHK_LOOP: loop
wait until (CLK'event and CLK = '1' and O_VAL = '1');
if (RECV_MODE > 0) then
if (RECV_MODE > 1) then
for i in 2 to RECV_MODE loop
wait until (CLK'event and CLK = '1');
end loop;
end if;
wait for DELAY;
O_RDY <= '1';
o_ready <= '1';
wait until (CLK'event and CLK = '1' and O_VAL = '1');
end if;
lo_pos := addr rem O_BYTES;
RANDOM_DATA_TABLE.GET(O_BYTES,lo_pos,addr,size,len,data,enbl,end_of_data);
addr := addr + len;
size := size - len;
assert (O_ENBL = enbl) report NAME & " Mismatch O_ENBL" severity FAILURE;
data_ok := TRUE;
for i in O_ENBL'range loop
if (O_ENBL(i) = '1') then
if (O_DATA((i+1)*8-1 downto i*8) /= data((i+1)*8-1 downto i*8)) then
data_ok := FALSE;
end if;
end if;
end loop;
assert (data_ok) report NAME & " Mismatch O_DATA" severity FAILURE;
if (RECV_EOD = TRUE) then
if (FLUSH_ENABLE > 0 and RECV_FLUSH) then
assert (O_FLUSH = end_of_data)
report NAME & " Mismatch O_FLUSH" severity FAILURE;
else
assert (O_DONE = end_of_data)
report NAME & " Mismatch O_DONE" severity FAILURE;
end if;
end if;
exit CHK_LOOP when (end_of_data = '1');
wait for DELAY;
if (RECV_MODE > 0) then
O_RDY <= '0';
o_ready <= '0';
end if;
end loop;
if (RECV_EOD = FALSE) then
if (FLUSH_ENABLE > 0 and RECV_FLUSH) then
if (O_FLUSH = '0') then
wait until (CLK'event and CLK = '1' and O_FLUSH = '1');
end if;
else
if (O_DONE = '0') then
wait until (CLK'event and CLK = '1' and O_DONE = '1');
end if;
end if;
end if;
wait for DELAY;
RECV_ACK <= FALSE;
O_RDY <= '0';
o_ready <= '0';
end loop;
end process;
-------------------------------------------------------------------------------
--
-------------------------------------------------------------------------------
CHECK_BUSY: process begin
RECV_LOOP: loop
wait until (CLK'event and CLK = '1' and RECV_ACK = TRUE);
CHK_LOOP_0: loop
wait until (CLK'event and CLK = '1');
assert (BUSY = '0')
report NAME & " Mismatch BUSY /= '0'" severity FAILURE;
exit CHK_LOOP_0 when (i_valid = '1' and I_RDY = '1');
end loop;
CHK_LOOP_1: loop
wait until (CLK'event and CLK = '1');
assert (BUSY = '1')
report NAME & " Mismatch BUSY /= '1'" severity FAILURE;
exit CHK_LOOP_1 when (O_VAL = '1' and o_ready = '1' and O_DONE = '1') or
(O_VAL = '1' and o_ready = '1' and O_FLUSH = '1');
end loop;
CHK_LOOP_2: loop
wait until (CLK'event and CLK = '1');
assert (BUSY = '0')
report NAME & " Mismatch BUSY /= '0'" severity FAILURE;
exit CHK_LOOP_2 when (RECV_ACK = FALSE);
end loop;
end loop;
end process;
end MODEL;
-----------------------------------------------------------------------------------
--
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
package COMPONENTS is
component REDUCER is
generic (
WORD_BITS : integer;
ENBL_BITS : integer;
I_WIDTH : integer;
O_WIDTH : integer;
QUEUE_SIZE : integer;
VALID_MIN : integer;
VALID_MAX : integer;
I_JUSTIFIED : integer;
FLUSH_ENABLE: integer
);
port (
CLK : in std_logic;
RST : in std_logic;
CLR : in std_logic;
START : in std_logic;
OFFSET : in std_logic_vector(O_WIDTH-1 downto 0);
DONE : in std_logic;
FLUSH : in std_logic;
BUSY : out std_logic;
VALID : out std_logic_vector(VALID_MAX downto VALID_MIN);
I_DATA : in std_logic_vector(I_WIDTH*WORD_BITS-1 downto 0);
I_ENBL : in std_logic_vector(I_WIDTH*ENBL_BITS-1 downto 0);
I_DONE : in std_logic;
I_FLUSH : in std_logic;
I_VAL : in std_logic;
I_RDY : out std_logic;
O_DATA : out std_logic_vector(O_WIDTH*WORD_BITS-1 downto 0);
O_ENBL : out std_logic_vector(O_WIDTH*ENBL_BITS-1 downto 0);
O_DONE : out std_logic;
O_FLUSH : out std_logic;
O_VAL : out std_logic;
O_RDY : in std_logic
);
end component;
component REDUCER_TEST_MODEL is
generic (
NAME : string;
DELAY : time;
WORD_BITS : integer;
I_WIDTH : integer;
O_WIDTH : integer;
I_JUSTIFIED : integer;
FLUSH_ENABLE: integer;
AUTO_FINISH : integer
);
port(
CLK : in std_logic;
RST : out std_logic;
CLR : out std_logic;
START : out std_logic;
OFFSET : out std_logic_vector(O_WIDTH-1 downto 0);
DONE : out std_logic;
FLUSH : out std_logic;
I_DATA : out std_logic_vector(I_WIDTH*(WORD_BITS )-1 downto 0);
I_ENBL : out std_logic_vector(I_WIDTH*(WORD_BITS/8)-1 downto 0);
I_FLUSH : out std_logic;
I_DONE : out std_logic;
I_VAL : out std_logic;
I_RDY : in std_logic := '0';
O_DATA : in std_logic_vector(O_WIDTH*(WORD_BITS )-1 downto 0) := (others => '0');
O_ENBL : in std_logic_vector(O_WIDTH*(WORD_BITS/8)-1 downto 0) := (others => '1');
O_FLUSH : in std_logic := '0';
O_DONE : in std_logic := '0';
O_VAL : in std_logic := '0';
O_RDY : out std_logic;
BUSY : in std_logic;
FINISH : out std_logic
);
end component;
end COMPONENTS;
-----------------------------------------------------------------------------------
--! @file test_bench_template.vhd
--! @brief TEST MODEL for REDUCER :
--! @version 1.0.0
--! @date 2012/4/3
--! @author Ichiro Kawazome <ichiro_k@ca2.so-net.ne.jp>
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use WORK.COMPONENTS.REDUCER;
use WORK.COMPONENTS.REDUCER_TEST_MODEL;
entity TEST_BENCH_DWC_W%W_I%I_O%O_Q%Q_J%J is
generic(AUTO_FINISH:integer:=1);port(FINISH:out std_logic);
end TEST_BENCH_DWC_W%W_I%I_O%O_Q%Q_J%J;
architecture MODEL of TEST_BENCH_DWC_W%W_I%I_O%O_Q%Q_J%J is
constant WORD_BITS : integer := %W;
constant I_WIDTH : integer := %I;
constant O_WIDTH : integer := %O;
constant QUEUE_SIZE : integer := %Q;
constant FLUSH_ENABLE : integer := 1;
constant I_JUSTIFIED : integer := %J;
constant NAME : string(1 to 19) := "DWC_W%W_I%I_O%O_Q%Q_J%J";
constant PERIOD : time := 10 ns;
constant DELAY : time := 1 ns;
signal CLK : std_logic;
signal RST : std_logic;
signal CLR : std_logic;
signal START : std_logic;
signal OFFSET : std_logic_vector(O_WIDTH-1 downto 0);
signal DONE : std_logic;
signal FLUSH : std_logic;
signal BUSY : std_logic;
signal I_DATA : std_logic_vector(I_WIDTH*(WORD_BITS )-1 downto 0);
signal I_ENBL : std_logic_vector(I_WIDTH*(WORD_BITS/8)-1 downto 0);
signal I_DONE : std_logic;
signal I_FLUSH : std_logic;
signal I_VAL : std_logic;
signal I_RDY : std_logic;
signal O_DATA : std_logic_vector(O_WIDTH*(WORD_BITS )-1 downto 0);
signal O_ENBL : std_logic_vector(O_WIDTH*(WORD_BITS/8)-1 downto 0);
signal O_DONE : std_logic;
signal O_FLUSH : std_logic;
signal O_VAL : std_logic;
signal O_RDY : std_logic;
constant gnd : std_logic_vector(O_WIDTH-1 downto 0) := (others => '0');
begin
U:REDUCER
generic map (
WORD_BITS => WORD_BITS,
ENBL_BITS => WORD_BITS/8,
I_WIDTH => I_WIDTH,
O_WIDTH => O_WIDTH,
QUEUE_SIZE => QUEUE_SIZE,
VALID_MIN => 0,
VALID_MAX => 0,
I_JUSTIFIED => I_JUSTIFIED,
FLUSH_ENABLE => FLUSH_ENABLE
)
port map (
CLK => CLK,
RST => RST,
CLR => CLR,
START => START,
OFFSET => OFFSET,
DONE => DONE,
FLUSH => FLUSH,
I_DATA => I_DATA,
I_ENBL => I_ENBL,
I_FLUSH => I_FLUSH,
I_DONE => I_DONE,
I_VAL => I_VAL,
I_RDY => I_RDY,
O_DATA => O_DATA,
O_ENBL => O_ENBL,
O_FLUSH => O_FLUSH,
O_DONE => O_DONE,
O_VAL => O_VAL,
O_RDY => O_RDY,
BUSY => BUSY ,
VALID => open
);
O:REDUCER_TEST_MODEL
generic map (
AUTO_FINISH => AUTO_FINISH,
NAME => NAME,
DELAY => DELAY,
WORD_BITS => WORD_BITS,
I_WIDTH => I_WIDTH,
O_WIDTH => O_WIDTH,
I_JUSTIFIED => I_JUSTIFIED,
FLUSH_ENABLE => FLUSH_ENABLE
)
port map (
CLK => CLK ,
RST => RST ,
CLR => CLR ,
FINISH => FINISH ,
START => START ,
OFFSET => OFFSET ,
DONE => DONE ,
FLUSH => FLUSH ,
BUSY => BUSY ,
I_DATA => I_DATA ,
I_ENBL => I_ENBL ,
I_DONE => I_DONE ,
I_FLUSH => I_FLUSH ,
I_VAL => I_VAL ,
I_RDY => I_RDY ,
O_DATA => O_DATA ,
O_ENBL => O_ENBL ,
O_DONE => O_DONE ,
O_FLUSH => O_FLUSH ,
O_VAL => O_VAL ,
O_RDY => O_RDY
);
process begin
CLK <= '1'; wait for PERIOD/2;
CLK <= '0'; wait for PERIOD/2;
end process;
end MODEL;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment