diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..d5a8c65 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# Auto detect text files and perform LF normalization +* text=auto + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f25075a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 GP-2022-Bachelor + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..5efc107 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# DDR5 PHY Verification +This repo includes the uvm testbench for the Digital data path of DDR5 phy +*************************************************************************** +Files Organization: +- docs: Verification plan +- rtl: The rtl is not included in this project as it is not part of this work +- scripts: Shell script for test run automation +- testbench: UVM tb environment (comps, sequences, tests, interfaces, transactions) diff --git a/docs/Verification plan/DDR5 Full Verification Plan (DFI & JEDEC).xlsx b/docs/Verification plan/DDR5 Full Verification Plan (DFI & JEDEC).xlsx new file mode 100644 index 0000000..fcce634 Binary files /dev/null and b/docs/Verification plan/DDR5 Full Verification Plan (DFI & JEDEC).xlsx differ diff --git a/docs/Waveforms Runs/Read (2x Freq).pdf b/docs/Waveforms Runs/Read (2x Freq).pdf new file mode 100644 index 0000000..92b83a5 Binary files /dev/null and b/docs/Waveforms Runs/Read (2x Freq).pdf differ diff --git a/docs/Waveforms Runs/Read (4x Freq).pdf b/docs/Waveforms Runs/Read (4x Freq).pdf new file mode 100644 index 0000000..c9cb6f5 Binary files /dev/null and b/docs/Waveforms Runs/Read (4x Freq).pdf differ diff --git a/docs/Waveforms Runs/Read (Matched Freq).pdf b/docs/Waveforms Runs/Read (Matched Freq).pdf new file mode 100644 index 0000000..4da9c83 Binary files /dev/null and b/docs/Waveforms Runs/Read (Matched Freq).pdf differ diff --git a/run/.fsm.sch.verilog.xml b/run/.fsm.sch.verilog.xml new file mode 100644 index 0000000..f730e5d --- /dev/null +++ b/run/.fsm.sch.verilog.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/run/Coverage Reports (HTML).rar b/run/Coverage Reports (HTML).rar new file mode 100644 index 0000000..4835872 Binary files /dev/null and b/run/Coverage Reports (HTML).rar differ diff --git a/run/Makefile Example b/run/Makefile Example new file mode 100644 index 0000000..0effc60 --- /dev/null +++ b/run/Makefile Example @@ -0,0 +1,91 @@ +# Makefile for UVM Lab6 + +LD_LIBRARY_PATH = ${NOVAS_HOME}/share/PLI/VCS/LINUX + +test = ubus_example_base_test +env_path = /u/arwaa/PCIe_Training/makefile/sv +test_path = /u/arwaa/PCIe_Training/makefile/examples +rtl_path = /u/arwaa/PCIe_Training/makefile/examples/ + +PROGRAM_TOP = ${test_path}/ubus_tb_top.sv +TEST_TOP = ${PROGRAM_TOP} +TOP = ${TEST_TOP} +DUT = ${rtl_path}dut_dummy.v +TESTLIST = ubus_example_base_test test_read_modify_write test_r8_w8_r4_w4 test_2m_4s + +log = simv.log +uvm_ver = uvm-1.1 +seed = 1 + +compile_switches = -sverilog -lca -debug_access+all -kdb +vcs+vcdpluson -timescale="1ns/100ps" -l ./scratch/comp.log -ntb_opts ${uvm_ver} +incdir+${env_path}+${test_path} ${TOP} +runtime_switches = -l ${log} +UVM_TESTNAME=${test} + +seq = uvm_reg_bit_bash_seq + +##### Required to create a make file which contains the following targets +########## Target to compile the environment +compile: ${env_path}/*.sv ${TOP} +ifeq ($(CES64),TRUE) + vcs -full64 ${compile_switches} + @echo "Compiled in 64-bit mode" +else + vcs ${compile_switches} + @echo "Compiled in 32-bit mode" +endif + +########## Target to launch a single test +run: + simv +ntb_random_seed=${seed} ${runtime_switches} +seq=${seq} + +random: simv + simv +ntb_random_seed_automatic ${runtime_switches} +seq=${seq} + +########## Target to launch all tests +run_all: + for test in ${TESTLIST} ; do \ + simv +ntb_random_seed=${seed} -cm_dir ./scratch/$$test -l ./scratch/$$test/$$test.log +UVM_TESTNAME=$$test +seq=${seq} ; \ + done +random_all: + for test in ${TESTLIST} ; do \ + simv +ntb_random_seed_automatic -cm_dir ./scratch/$$test -l ./scratch/$$test/$$test.log +UVM_TESTNAME=$$test +seq=${seq} ; \ + done + +########## Target to compile and run the simulation +all: simv run + +########## Target to merge coverage database and generate coverage report +cover: + urg -dir ./scratch/*.vdb + urg -dir ./scratch/*.vdb -format text + +########## Target to clean your workspace before the build +clean: + rm -rf simv* csrc* *.tmp *.vpd *.key log *.h temp *.log .vcs* *.txt DVE* *.hvp urg* .inter.vpd.uvm .restart* .synopsys* novas.* *.dat *.fsdb verdi* work* vlog* + +########## Target for the makefile help +help: + @echo ============================================================================ + @echo " " + @echo " USAGE: make target " + @echo " " + @echo " xxx is the random seed. Can be any integer except 0. Defaults to 1 " + @echo " YYY sets the verbosity filter. Defaults to UVM_MEDIUM " + @echo " ZZZ selects the uvm test. Defaults to test_base " + @echo " " + @echo " ------------------------- Test TARGETS -------------------------------- " + @echo " all => Compile TB and DUT files and run the simulation " + @echo " compile => Compile TB and DUT files " + @echo " run => Run the simulation with seed " + @echo " random => Run the simulation with random seed " + @echo " run_all => Run the simulation with seed for all the tests " + @echo " random_all => Run the simulation with random seed for all the test " + @echo " cover => Merge coverage database and generate coverage report " + @echo " " + @echo " -------------------- ADMINISTRATIVE TARGETS --------------------------- " + @echo " help => Displays this message " + @echo " clean => Remove all intermediate simv and log files " + @echo " " + @echo " ---------------------- EMBEDDED SETTINGS ------------------------------ " + @echo " -timescale=\"1ns/100ps\" " + @echo " -debug_all " + @echo ============================================================================ diff --git a/run/Template_script.sh b/run/Template_script.sh new file mode 100644 index 0000000..1b3b8b9 --- /dev/null +++ b/run/Template_script.sh @@ -0,0 +1,454 @@ +################################### + +# Tool Related + +################################### + +# + +#DUMP="/simulation2/${USER}/sims/" + +DUMP="./" + +LOCAL="FALSE" + +# + +ROOTDIR=".." + +export RTL="$ROOTDIR/rtl" + +testbench="$ROOTDIR/testbench" + +# + +#---PKG + +PKG="${testbench}/tb_pkg.sv" + +# + +# + +################################### + +# Paths/Env variables + +################################### + +TESTCASE="NONE" + +#SEED="1" + +SEED="Z" #Why use a random seed? + +PROBE="" + +CLN_BUILD="FALSE" + +NO_BUILD="FALSE" + +NO_RUN="FALSE" + +UVM_DEBUG="+UVM_VERBOSITY=UVM_MEDIUM" + +GUI_ARG="-c" + +BUILDCMN="FALSE" + +COV="FALSE" + +COVERAGE="" + +LOGS_DIR=${testbench}/run + +EXTRA_CMD="" + +WORK_LIB_vcs="" + +SIMULATOR="vcs" + +NO_BUILD_vcs="" + +LOG="" + +WAVE_START="0" + +WAVE_NAME="waves_wddr" + +WAVE_DEPTH="all" + +UVM_TO="5000000" + +# + +# + +################################### + +# Help + +################################### + +usage_txt=$'\nUsage:simulate.sh [options] + + + +------- Debug and Help and Etc ------- + +-v Enable coverage generation. + +-h Print help/usage + + + +------- Required args ------- + +-e Extra Arguments passed + + + +------- Build control ------- + +-c Clean the work area, do not run sim + +-nb Do not build model + + + +------- Run control ------- + +-nr Do not run the simulation + +-timeout time in ns for timeout + + + +------- Dump control ------- + +-nosave No dump + +-wavst waves dump start time in "us" + +-wavnm waves dump name + +-wavdp waves dump depth in hierarchy from tb_top + + + +------- Logging ------- + +-log log name + +-local save log/shm in local dir + + + +------- Defines ------- + +-mm Wavious Memory Model driver added to environment + + + +' + +# + +#################################### + +# RTL files + +################################### + +RTL_FILES="-f ${ROOTDIR}/testbench/rtl.f" + +# + +################################### + +# Switches + +################################### +while test $# -gt 0 + +do + + case "$1" in + + -t) + + echo "$0: ---> Setting testcase to '$2'" + + TESTCASE="$2" + + LOG="$2.log" + + shift + + ;; + + -x) + + echo "$0: ---> Setting seed to $2" + + SEED="$2" + + shift + + ;; + + -local) + + echo "$0: ---> Dumping log/shm in local directory" + + DUMP="" + + LOCAL="TRUE" + + ;; + + -log) + + echo "$0: ---> Saving log to $2.log" + + LOG="$2.log" + + shift + + ;; + + -wavst) + + echo "$0: ---> Waves: dump start from $2 us" + + WAVE_START="$2" + + shift + + ;; + + -wavnm) + + echo "$0: ---> Waves: dump name $2" + + WAVE_NAME="$2" + + shift + + ;; + + -wavdp) + + echo "$0: ---> Waves: dump depth $2" + + WAVE_DEPTH="$2" + + shift + + ;; + + -timeout) + + echo "$0: ---> UVM Timeout : $2 ns" + + UVM_TO="$2" + + shift + + ;; + + -e) + + echo "$0: ---> Setting extra commands $2" + + EXTRA_CMD="$2" + + shift + + ;; + + -c) + + echo "$0: ---> Clean build" + + CLN_BUILD="TRUE" + + ;; + + -nb) + + echo "$0: ---> not building" + + NO_BUILD="TRUE" + + DUMP="" + + ;; + + -nr) + + echo "$0: ---> not running" + + NO_RUN="TRUE" + + ;; + + -ud) + + UVM_DEBUG="+UVM_VERBOSITY=UVM_DEBUG +UVM_PHASE_TRACE +UVM_OBJECTION_TRACE +UVM_CONFIG_DB_TRACE" + + echo "$0: ---> Add $UVM_DEBUG to vsim." + + ;; + + -uh) + + UVM_DEBUG="+UVM_VERBOSITY=UVM_HIGH +UVM_CONFIG_DB_TRACE" + + echo "$0: ---> Add $UVM_DEBUG to vsim." + + ;; + + -v) + + echo "$0: ---> Enabling coverage collection" + + COV="TRUE" + + ;; + + -h) + + echo "$0: $usage_txt" + + exit 0 + + ;; + + -worklib) + + WORK_LIB_vcs="-r work_wddr -xmlibdirname $2" + + shift + + ;; + + -s) + + echo "$0: ---> blah" + + SIMULATOR="$2" + + shift + + ;; + + *) + + echo "$0: Unsupported argument '$1'" + + exit 1 + + ;; + + esac + + shift + +done + + + +if [ "$CLN_BUILD" == "TRUE" ] + +then + + printf "\n\n$0: ---> Cleaning...\n" + + vcs -clean + + exit 0 + +fi + +# + +# + +########################################### + +# RUN + +########################################### + +if [ "$NO_BUILD" == "TRUE" -a "$NO_RUN" == "TRUE" ] + +then + + printf "\n\n$0: **** HELP **** Both build and run were turned off.\n\n" + + echo "$usage_txt" + + exit 0 + +fi + + + +if [ "$SEED" == "Z" ] + +then + + SEED=`perl -e 'printf "%d\n", rand(2**31-1);'` + +fi + + + +if [ "$COV" == "TRUE" ] + +then + + COVERAGE="-coverage " + +fi + +# + +########################### + +# VCS + +########################### + +EDA_PLAYGND_COMMAND_OPTIONS="-timescale=1ns/1ns +vcs+flush+all +warn=all -sverilog +vcs+vcdpluson" + +EDA_PLAYGND_RUN_OPTIONS="simpleadder_test" + +# + +old='vcs -full64 -R -timescale=1ns/1ns +vcs+flush+all +warn=all -sverilog \ + + -top top_testbench +vcs+vcdpluson -ntb_opts uvm-1.2 \ + + $EXTRA_CMD \ + + $RTL_FILES \ + + $PKG \ + + ${testbench}/top_testbench.sv' + +vcs -full64 -timescale=1ns/1ns +vcs+flush+all +warn=all -sverilog \ + + +vcs+vcdpluson -ntb_opts uvm-1.2 \ + + $EXTRA_CMD \ + + $RTL_FILES \ + + $PKG \ + + ${testbench}/top_testbench.sv + +#EOF diff --git a/run/cm.log b/run/cm.log new file mode 100644 index 0000000..ba65586 --- /dev/null +++ b/run/cm.log @@ -0,0 +1,49 @@ +: // Synopsys, Inc. +: // + +: // Generated by: VCS Coverage Metrics S-2021.09-SP2-1 +: // User: nano +: // Date: Sat Jun 4 14:45:07 2022 + +: Disabling fsm sequence coverage for module uvm_pkg ... +: Disabling fsm sequence coverage for module _vcs_msglog ... +: Disabling fsm sequence coverage for module tb_pkg ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.top_inst ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.top_inst.Ser ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.top_inst.CA_inst ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.DM_inst ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.DM_inst.GC_inst ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.DM_inst.PD_inst ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.DM_inst.PD_inst.FSM_sett_inst ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.DM_inst.PD_inst.generic_FSM_inst ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.DM_inst.FIFO_inst ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.DM_inst.EdgeDetectorFSM_inst ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.DM_inst.CU_inst ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.DM_inst.CC_inst ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.DM_inst.VC_inst ... +: Disabling fsm sequence coverage for module top_testbench.ddr_DUT.Deser_inst ... +: Disabling fsm sequence coverage for module top_testbench.ddr_sva_inst ... +: Starting toggle coverage for module top_testbench.ddr_DUT +: Starting toggle coverage for module top_testbench.ddr_DUT.top_inst +: Starting toggle coverage for module top_testbench.ddr_DUT.top_inst.Ser +: Starting toggle coverage for module top_testbench.ddr_DUT.top_inst.CA_inst +: Starting toggle coverage for module top_testbench.ddr_DUT.DM_inst +: Starting toggle coverage for module top_testbench.ddr_DUT.DM_inst.GC_inst +: Starting toggle coverage for module top_testbench.ddr_DUT.DM_inst.PD_inst +: Starting toggle coverage for module top_testbench.ddr_DUT.DM_inst.PD_inst.FSM_sett_inst +: Starting toggle coverage for module top_testbench.ddr_DUT.DM_inst.PD_inst.generic_FSM_inst +: Starting toggle coverage for module top_testbench.ddr_DUT.DM_inst.FIFO_inst +: Starting toggle coverage for module top_testbench.ddr_DUT.DM_inst.EdgeDetectorFSM_inst +: Starting toggle coverage for module top_testbench.ddr_DUT.DM_inst.CU_inst +: Starting toggle coverage for module top_testbench.ddr_DUT.DM_inst.CC_inst +: Starting toggle coverage for module top_testbench.ddr_DUT.DM_inst.VC_inst +: Starting toggle coverage for module top_testbench.ddr_DUT.Deser_inst +: Reporting line coverage at the end of simulation ... +: End of Line Coverage ... +: Reporting condition coverage at the end of simulation ... +: End of Condition Coverage ... +: Reporting branch coverage at the end of simulation ... +: End of Branch Coverage ... +: Coverage status: End of All Coverages ... + diff --git a/run/cm_hier.file b/run/cm_hier.file new file mode 100644 index 0000000..c47ebae --- /dev/null +++ b/run/cm_hier.file @@ -0,0 +1,23 @@ +begin + line+cond+tgl+fsm+branch+assert -tree top_testbench 1 +end +begin + line+cond+tgl+fsm+branch+assert -tree uvm_custom_install_recording +end +begin + line+cond+tgl+fsm+branch+assert -file ../testbench/interfaces/dfi_intf.sv +end + +begin + line+cond+tgl+fsm+branch+assert -file ../testbench/interfaces/jedec_intf.sv +end +begin + line+cond+tgl+fsm+branch+assert -file /home/nano/Synopsys_tools/VCS/VCS/vcs/S-2021.09-SP2-1/etc/uvm-1.2/uvm_pkg.sv +end +begin + line+cond+tgl+fsm+branch -file ../testbench/interfaces/ddr_assertions.sv +end + +begin + line+cond+tgl+fsm+branch+assert -file ../rtl/CRC_Valid.sv +end diff --git a/run/exclusion_file.el b/run/exclusion_file.el new file mode 100644 index 0000000..3066d23 --- /dev/null +++ b/run/exclusion_file.el @@ -0,0 +1,2 @@ +covergroup tb_pkg::subscriber::DFI_transitions +covergroup tb_pkg::subscriber::JEDEC_transitions diff --git a/run/incdirs.f b/run/incdirs.f new file mode 100644 index 0000000..f0a5324 --- /dev/null +++ b/run/incdirs.f @@ -0,0 +1,9 @@ ++incdir+${RTL} ++incdir+${TESTBENCH} ++incdir+${UVM_COMPONENTS} ++incdir+${UVM_TRANSACTIONS} ++incdir+${UVM_TESTS} ++incdir+${UVM_SEQUENCES} ++incdir+${UVM_INTERFACES} ++incdir+${UVM_DRAM_AGENT} ++incdir+${UVM_MC_AGENT} diff --git a/run/run.sh b/run/run.sh new file mode 100644 index 0000000..1a0927a --- /dev/null +++ b/run/run.sh @@ -0,0 +1,258 @@ +#!/bin/sh + +########################## +# Tool Related +########################## +TESTCASE="ddr_sanity_test" +SEED="1" +UVM_VERBOSITY="+UVM_VERBOSITY=UVM_LOW" +GUI_ARG="" +UVM_TO="10000000" +COMPILE_ONLY="FALSE" #Use it when just compiling +COV="FALSE" #Use it for coverage collection enabling +COVERAGE_OPITONS="" #Complements $COV +NUM_RUNS=1 + +########################### +# Paths +########################### +LOGS="./log" +DUMP="./waves" +RTL="../rtl" +TESTBENCH="../testbench" +UVM_COMPONENTS="$TESTBENCH/components" +UVM_TRANSACTIONS="$TESTBENCH/transactions" +UVM_TESTS="$TESTBENCH/tests" +UVM_SEQUENCES="$TESTBENCH/sequences" +UVM_INTERFACES="$TESTBENCH/interfaces" +UVM_DRAM_AGENT="$TESTBENCH/$UVM_COMPONENTS/dram_agent" +UVM_MC_AGENT="$TESTBENCH/$UVM_COMPONENTS/mc_agent" + + +########################### +# Env definitions +########################### +ratio="ratio_1_to_1" +ASSERTIONS_DEF="" + +################################### +# Help +################################### +usage_txt=$'\nUsage:run.sh [options] + + + +------- Debug and Help and Etc ------- + +-help Print help/usage + +-verbos_debug Set UVM_VERBOSITY="+UVM_VERBOSITY=UVM_DEBUG +UVM_PHASE_TRACE +UVM_OBJECTION_TRACE +UVM_CONFIG_DB_TRACE" + +-verbos_hi Set UVM_VERBOSITY="+UVM_VERBOSITY=UVM_HIGH +UVM_CONFIG_DB_TRACE" + +-gui Open DVE for running and debugging + + + +------- Build and Run control ------- + +-cln_bld Clean the work area before running. + +-cov_en Enable coverage generation. + +-comp_only Compile only, Do not run the simulation + +-timeout Time in ns for timeout + +-runs Specify the number of runs (with different seeds) for the specified test. + + +------- Defines ------- + +-ratio Decide the frequency ratio used thoughout the simulation. + +-assert_en Define flag to bind and use ddr assertions. + + + +------- Dump control ------- + +-nosave No dump + +-wavst Waves dump start time in "us" + +-wavnm Waves dump name + +-wavdp Waves dump depth in hierarchy from tb_top + + + +------- Required args ------- + +-extra Extra Arguments passed +' + +# + +#################################### + +################################### +# Switches +################################### +#Note: a "shift" is done when the option is followed by arguments +while test $# -gt 0 +do + case "$1" in + -test) + echo "$0: ********> Setting testcase to '$2'" + TESTCASE="$2" + LOG="$2.log" + shift + ;; + -seed) + echo "$0: ********> Setting seed to $2" + SEED="$2" + shift + ;; + -wavst) + echo "$0: ********> Waves: dump start from $2 us" + WAVE_START="$2" + shift + ;; + -wavnm) + echo "$0: ********> Waves: dump name $2" + WAVE_NAME="$2" + shift + ;; + -wavdp) + echo "$0: ********> Waves: dump depth $2" + WAVE_DEPTH="$2" + shift + ;; + -timeout) + echo "$0: ********> UVM Timeout : $2 ns" + UVM_TO="$2" + shift + ;; + -extra) + echo "$0: ********> Setting extra commands $2" + EXTRA_CMD="$2" + shift + ;; + -cln_bld) + echo "$0: ********> Clean build" + CLN_BUILD="TRUE" + ;; + -gui) + echo "$0: ********> Open GUI" + GUI_ARG="-gui" + ;; + -comp_only) + echo "$0: ********> not running" + COMPILE_ONLY="TRUE" + ;; + -verbos_debug) + UVM_VERBOSITY="+UVM_VERBOSITY=UVM_DEBUG +UVM_PHASE_TRACE +UVM_OBJECTION_TRACE +UVM_CONFIG_DB_TRACE" + echo "$0: ********> Add $UVM_VERBOSITY to simv." + ;; + -verbos_hi) + UVM_VERBOSITY="+UVM_VERBOSITY=UVM_HIGH +UVM_CONFIG_DB_TRACE" + echo "$0: ********> Add $UVM_VERBOSITY to simv." + ;; + -ratio) + echo "$0: ********> Using frequincy ratio: 1 to $2" + ratio="ratio_1_to_$2" + shift + ;; + -cov_en) + echo "$0: ********> Enabling coverage collection" + COV="TRUE" + COVERAGE_OPITONS="-lca -cm line+cond+tgl+fsm+branch+assert -cm_hier cm_hier.file" + ;; + -assert_en) + echo "$0: ********> Enabling Assertions" + ASSERTIONS_DEF="assert_en" + ;; + -runs) + echo "$0: ********> Running the test $2 times with different seeds" + NUM_RUNS=$2 + shift + ;; + -help) + echo "$0: $usage_txt" + exit 0 + ;; + *) + echo "$0: Unsupported argument '$1'" + exit 1 + ;; + esac + shift +done + + + +########################### +# VCS - Compilation +########################### + +function vcs_cmd +{ + vcs $* \ + $COVERAGE_OPITONS -sverilog -timescale=1ps/1ps -ntb_opts uvm-1.2 -debug_acc+all \ + +define+$ratio +define+$ASSERTIONS_DEF \ + +libext+.sv+ \ + +incdir+$TESTBENCH \ + +incdir+$UVM_SEQUENCES \ + +incdir+$UVM_TESTS \ + +incdir+$RTL \ + $TESTBENCH/top_testbench.sv \ + -assert svaext +lint=TFIPC-L + #-q is to Make VCS quiet -- -assert svaext is for property local variable support + #-y $RTL \ + #Removed the -y option and used `include for RTL to measure code coverage +} + + +#################################### +# Handling some input options +#################################### +if [ "$CLN_BUILD" == "TRUE" ] +then + rm -rf simv* csrc* *.xml *.vdb .tmp *.vpd *.key urgReport *.h temp ./log/*.log .vcs .txt .hvp urg .inter.vpd.uvm .restart* .synopsys* novas.* .dat *.fsdb verdi work* vlog* DVEfiles .fsm.sch.verilog.xml *.log +fi + +if [ "$SEED" == "Z" ] +then + SEED=`perl -e 'printf "%d\n", rand(2**31-1);'` +fi + +if [ "$COMPILE_ONLY" == "FALSE" ] +then + printf "\n\n$0: ********> Compiling...<********\n" + vcs_cmd -l $LOGS/comp.log + printf "\n\n$0: ********> Running, with the following UVM verbosity option: $UVM_VERBOSITY <********\n" + for i in $(seq $NUM_RUNS) + do + SEED=$i + ./simv $GUI_ARG \ + +UVM_TESTNAME=$TESTCASE +UVM_TIMEOUT=$UVM_TO +ntb_random_seed=$SEED \ + +UVM_NO_RELNOTES $UVM_VERBOSITY \ + -cm_dir "${TESTCASE}_${ratio}_${SEED}" -l $LOGS/run.log $COVERAGE_OPITONS \ + #+UVM_TR_RECORD +UVM_LOG_RECORD \ + done + + + + printf "\n\n$0: ********> Sim is done <********.\n" +else + printf "\n\n$0: ********> Compiling...<********\n" + vcs_cmd -l $LOGS/comp.log +fi + +if [ "$COV" == "TRUE" ] +then + printf "\n\n$0: ********> Creating Coverage Reports...<********\n\n" + urg -lca -dir ./*.vdb +fi +# diff --git a/run/run_no_args.sh b/run/run_no_args.sh new file mode 100644 index 0000000..cfe3e04 --- /dev/null +++ b/run/run_no_args.sh @@ -0,0 +1,165 @@ +#!/bin/sh + +########################## +# Tool Related +########################## +TESTCASE="ddr_sanity_test" +SEED="1" +UVM_DEBUG="+UVM_VERBOSITY=UVM_MEDIUM" +GUI_ARG="-c" +UVM_TO="5000000" +COMPILE_ONLY="FALSE" #Use it when just compiling +COV="FALSE" #Use it for coverage collection enabling +COVERAGE="" #Complements $COV + +########################### +# Paths +########################### +LOGS="../logs" +DUMP="../waves" +RTL="../rtl" +TESTBENCH="../testbench" +UVM_COMPONENTS="$TESTBENCH/components" +UVM_TRANSACTIONS="$TESTBENCH/transactions" +UVM_TESTS="$TESTBENCH/tests" +UVM_SEQUENCES="$TESTBENCH/sequences" +UVM_INTERFACES="$TESTBENCH/interfaces" +UVM_DRAM_AGENT="$TESTBENCH/$UVM_COMPONENTS/dram_agent" +UVM_MC_AGENT="$TESTBENCH/$UVM_COMPONENTS/mc_agent" + + +########################### +# Env variables +########################### +ratio_1_to_2="" +ratio_1_to_4="" + + +################################### +# Switches +################################### +while test $# -gt 0 +do + case "$1" in + -test) + echo "$0: ---> Setting testcase to '$2'" + TESTCASE="$2" + LOG="$2.log" + shift + ;; + -seed) + echo "$0: ---> Setting seed to $2" + SEED="$2" + shift + ;; + -wavst) + echo "$0: ---> Waves: dump start from $2 us" + WAVE_START="$2" + shift + ;; + -wavnm) + echo "$0: ---> Waves: dump name $2" + WAVE_NAME="$2" + shift + ;; + -wavdp) + echo "$0: ---> Waves: dump depth $2" + WAVE_DEPTH="$2" + shift + ;; + -timeout) + echo "$0: ---> UVM Timeout : $2 ns" + UVM_TO="$2" + shift + ;; + -extra) + echo "$0: ---> Setting extra commands $2" + EXTRA_CMD="$2" + shift + ;; + -cln) + echo "$0: ---> Clean build" + CLN_BUILD="TRUE" + ;; + -comp_only) + echo "$0: ---> not running" + COMPILE_ONLY="TRUE" + ;; + -uvm_verbos_debug) + UVM_DEBUG="+UVM_VERBOSITY=UVM_DEBUG +UVM_PHASE_TRACE +UVM_OBJECTION_TRACE +UVM_CONFIG_DB_TRACE" + echo "$0: ---> Add $UVM_DEBUG to vsim." + ;; + -uvm_verbos_hi) + UVM_DEBUG="+UVM_VERBOSITY=UVM_HIGH +UVM_CONFIG_DB_TRACE" + echo "$0: ---> Add $UVM_DEBUG to vsim." + ;; + -ratio_1_to_2) + echo "$0: ---> Using frequincy ratio of 1 to 2" + ratio_1_to_2="+define+ratio_1_to_2" + ;; + -ratio_1_to_4) + echo "$0: ---> Using frequincy ratio of 1 to 4" + ratio_1_to_4="+define+ratio_1_to_4" + ;; + -cov_en) + echo "$0: ---> Enabling coverage collection" + COV="TRUE" + ;; + -h) + echo "$0: $usage_txt" + exit 0 + ;; + *) + echo "$0: Unsupported argument '$1'" + exit 1 + ;; + esac + shift +done + + + +########################### +# VCS - Compilation +########################### + +function vcs_cmd +{ + vcs $* \ + -sverilog -timescale=1ns/1ns -ntb_opts uvm-1.2 \ + -y $RTL \ + +libext+.sv+ \ + +incdir+$TESTBENCH \ + +incdir+$UVM_SEQUENCES \ + +incdir+$UVM_TESTS \ + +incdir+$RTL \ + $TESTBENCH/top_testbench.sv +} + + +#################################### +# Handling some input options +#################################### +if [ "$SEED" == "Z" ] +then + SEED=`perl -e 'printf "%d\n", rand(2**31-1);'` +fi + +if [ "$COMPILE_ONLY" == "FALSE" ] +then + printf "\n\n$0: ---> Compiling & Running...\n" + vcs_cmd -l $LOGS/comp.log + ./simv +UVM_TESTNAME=$TESTCASE +UVM_NO_RELNOTES +UVM_TESTNAME=$TESTCASE +UVM_TR_RECORD +UVM_LOG_RECORD -l $LOGS/run.log + printf "\n\n$0: ---> Sim is done.\n" +else + printf "\n\n$0: ---> Compiling...\n" + vcs_cmd -l $LOGS/comp.log +fi + +if [ "$COV" == "TRUE" ] +then + #COVERAGE="-coverage all -covtest $TESTCASE$SEED -covdut ddr_phy_1x32" + urg -report $LOGS/ +fi + + diff --git a/run/simv b/run/simv new file mode 100644 index 0000000..4e475c6 Binary files /dev/null and b/run/simv differ diff --git a/run/tr_db.log b/run/tr_db.log new file mode 100644 index 0000000..ef6b6eb --- /dev/null +++ b/run/tr_db.log @@ -0,0 +1,300 @@ + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} + CREATE_STREAM @0 {NAME:base_seq_inst T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:999} + CREATE_STREAM @0 {NAME:sanity_sequence T:Transactions SCOPE:uvm_test_top.env1.mc_agent1.mc_sequencer1 STREAM:1006} + CREATE_STREAM @0 {NAME:resp_seq T:Transactions SCOPE:uvm_test_top.env1.dram_agent1.dram_sequencer1 STREAM:1008} diff --git a/run/ucli.key b/run/ucli.key new file mode 100644 index 0000000..e69de29 diff --git a/run/vc_hdrs.h b/run/vc_hdrs.h new file mode 100644 index 0000000..c880aa5 --- /dev/null +++ b/run/vc_hdrs.h @@ -0,0 +1,93 @@ +#ifndef _VC_HDRS_H +#define _VC_HDRS_H + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include "svdpi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _VC_TYPES_ +#define _VC_TYPES_ +/* common definitions shared with DirectC.h */ + +typedef unsigned int U; +typedef unsigned char UB; +typedef unsigned char scalar; +typedef struct { U c; U d;} vec32; + +#define scalar_0 0 +#define scalar_1 1 +#define scalar_z 2 +#define scalar_x 3 + +extern long long int ConvUP2LLI(U* a); +extern void ConvLLI2UP(long long int a1, U* a2); +extern long long int GetLLIresult(); +extern void StoreLLIresult(const unsigned int* data); +typedef struct VeriC_Descriptor *vc_handle; + +#ifndef SV_3_COMPATIBILITY +#define SV_STRING const char* +#else +#define SV_STRING char* +#endif + +#endif /* _VC_TYPES_ */ + + + extern int uvm_hdl_check_path(/* INPUT */const char* path); + + extern int uvm_hdl_deposit(/* INPUT */const char* path, const /* INPUT */svLogicVecVal *value); + + extern int uvm_hdl_force(/* INPUT */const char* path, const /* INPUT */svLogicVecVal *value); + + extern int uvm_hdl_release_and_read(/* INPUT */const char* path, /* INOUT */svLogicVecVal *value); + + extern int uvm_hdl_release(/* INPUT */const char* path); + + extern int uvm_hdl_read(/* INPUT */const char* path, /* OUTPUT */svLogicVecVal *value); + + extern SV_STRING uvm_hdl_read_string(/* INPUT */const char* path); + + extern int uvm_memory_load(/* INPUT */const char* nid, /* INPUT */const char* scope, /* INPUT */const char* fileName, /* INPUT */const char* radix, /* INPUT */const char* startaddr, /* INPUT */const char* endaddr, /* INPUT */const char* types); + + extern SV_STRING uvm_dpi_get_next_arg_c(/* INPUT */int init); + + extern SV_STRING uvm_dpi_get_tool_name_c(); + + extern SV_STRING uvm_dpi_get_tool_version_c(); + + extern void* uvm_dpi_regcomp(/* INPUT */const char* regex); + + extern int uvm_dpi_regexec(/* INPUT */void* preg, /* INPUT */const char* str); + + extern void uvm_dpi_regfree(/* INPUT */void* preg); + + extern int uvm_re_match(/* INPUT */const char* re, /* INPUT */const char* str); + + extern void uvm_dump_re_cache(); + + extern SV_STRING uvm_glob_to_re(/* INPUT */const char* glob); + + extern void m__uvm_report_dpi(/* INPUT */int severity, /* INPUT */const char* id, /* INPUT */const char* message, /* INPUT */int verbosity, /* INPUT */const char* filename, /* INPUT */int line); + + extern void* svapfGetAttempt(/* INPUT */unsigned int assertHandle); + + extern void svapfReportResult(/* INPUT */unsigned int assertHandle, /* INPUT */void* ptrAttempt, /* INPUT */int result); + + extern int svapfGetAssertEnabled(/* INPUT */unsigned int assertHandle); +void SdisableFork(); + +#ifdef __cplusplus +} +#endif + + +#endif //#ifndef _VC_HDRS_H + diff --git a/testbench/components/dram_agent/dram_agent.sv b/testbench/components/dram_agent/dram_agent.sv new file mode 100644 index 0000000..332203e --- /dev/null +++ b/testbench/components/dram_agent/dram_agent.sv @@ -0,0 +1,46 @@ +class dram_agent extends uvm_agent; + `uvm_component_utils(dram_agent) + + dram_driver dram_driver1; + dram_monitor dram_monitor1; + dram_sequencer dram_sequencer1; + + //uvm_analysis_port for broadcasting to subscriber and scoreboard + uvm_analysis_port#(ddr_sequence_item) dram_analysis_port; + + + function new (string name = "dram_agent", uvm_component parent = null); + super.new(name,parent); + endfunction + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + dram_driver1 = dram_driver::type_id::create("dram_driver1",this); + dram_monitor1 = dram_monitor::type_id::create("dram_monitor1",this); + dram_sequencer1 = dram_sequencer::type_id::create("dram_sequencer1",this); + dram_analysis_port = new("dram_analysis_port",this); + `uvm_info("Build_Phase", "*************** 'dram_agent' Build Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Connect Phase // + //==========================================================================// + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + //Connect driver port to sequencer imp/export + dram_driver1.seq_item_port.connect(dram_sequencer1.dram_seq_item_imp); + //Connect monitor analysis port to agent analysis port + dram_monitor1.dram_analysis_port.connect(dram_analysis_port); + `uvm_info("Connect_phase", "*************** 'dram_agent' Connect Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + endtask +endclass : dram_agent \ No newline at end of file diff --git a/testbench/components/dram_agent/dram_driver.sv b/testbench/components/dram_agent/dram_driver.sv new file mode 100644 index 0000000..623ee8c --- /dev/null +++ b/testbench/components/dram_agent/dram_driver.sv @@ -0,0 +1,291 @@ +class dram_driver extends uvm_driver#(ddr_sequence_item); + `uvm_component_utils(dram_driver) + + ddr_sequence_item jedec_seq_item_1; + ddr_sequence_item dut_rsp; + virtual jedec_intf jedec_driver_vif; + static bit reset_n; + static bit termination_flag; + static int cmd = 0; + static int cmd1_flag = 0; + static int cancel_flag = 0; + static int clk = 0; + command_t CMD_tmp; + + + function new (string name = "dram_driver", uvm_component parent = null); + super.new(name,parent); + endfunction + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + if(!uvm_config_db#(virtual jedec_intf)::get(this,"","jedec_vif",jedec_driver_vif)) + `uvm_fatal(get_full_name(),"Error in getting jedec_vif from database!") + jedec_seq_item_1 =ddr_sequence_item::type_id::create("jedec_seq_item_1"); + `uvm_info("Build_Phase", "*************** 'dram_driver' Build Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Connect Phase // + //==========================================================================// + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + `uvm_info("Connect_phase", "*************** 'dram_driver' Connect Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Reset Phase // + //==========================================================================// + task reset_phase(uvm_phase phase); + phase.raise_objection(this); + jedec_driver_vif.cb_J.DQS_AD_i <= 0; + jedec_driver_vif.cb_J.DQ_AD_i <= 0; + phase.drop_objection(this); + endtask + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + forever begin + seq_item_port.get_next_item(jedec_seq_item_1); + fork + begin + translation(); + if (jedec_seq_item_1.CMD == MRW) begin + fill_mode_regiser(); + end + end + parse_mode_regisers(); + drive(jedec_seq_item_1, dut_rsp); + join + if(!uvm_config_db#(bit)::get(this,"","reset_n",reset_n)) + `uvm_fatal("Dram driver","Error in getting reset_n from database!") + if(!uvm_config_db#(bit)::get(this,"","termination_flag",termination_flag)) + `uvm_fatal(get_full_name(),"Error in getting Termination flag from database!") + dut_rsp.termination_flag = termination_flag; + dut_rsp.set_id_info(jedec_seq_item_1); + seq_item_port.item_done(dut_rsp); + end + endtask + + + + extern task translation(); + extern task drive(input ddr_sequence_item jedec_seq_item_1, output ddr_sequence_item dut_rsp); + extern task fill_mode_regiser(); + extern task parse_mode_regisers(); +endclass : dram_driver + + + + +//==============================================================================// +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||// +//==============================================================================// +// DRAM Driver Tasks // +//==============================================================================// +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||// +//==============================================================================// + + + + + +//==============================================================================// +// Task: Translation +// Description: This task translates the pin-level activity on the JEDEC interface +// into a higher level jedec-transaction in order to use it for the +// reactive response from the DRAM driver +// Disclaimer: This task is cloned from the DRAM monitor task +//==============================================================================// + +task dram_driver::translation(); + @(jedec_driver_vif.cb_J) //first clock + clk = 1; + if (cmd == 2) begin + clk = 2; + cmd = 1; + end + cmd1_flag = 0; + if (jedec_driver_vif.cb_J.CS_DA_o===0) begin //selected this chip + cmd1_flag = 1; + if (clk == 1) begin + casex(jedec_driver_vif.cb_J.CA_DA_o[4:0]) + //Act: + 5'b???00: begin + CMD_tmp = ACT; + jedec_seq_item_1.ROW[3:0] = jedec_driver_vif.cb_J.CA_DA_o[5:2]; + jedec_seq_item_1.BA[1:0] = jedec_driver_vif.cb_J.CA_DA_o[7:6]; + jedec_seq_item_1.BG[2:0] = jedec_driver_vif.cb_J.CA_DA_o[10:8]; + jedec_seq_item_1.CID[2:0] = jedec_driver_vif.cb_J.CA_DA_o[13:11]; + end + //MRW: + 5'b00101: begin + CMD_tmp = MRW; + jedec_seq_item_1.MRA[7:0] =jedec_driver_vif.cb_J.CA_DA_o[12:5]; + end + //MRR: + 5'b10101: begin + CMD_tmp = MRR; + jedec_seq_item_1.MRA[7:0] =jedec_driver_vif.cb_J.CA_DA_o[12:5]; + end + //RD: + 5'b11101: begin + CMD_tmp =RD; + jedec_seq_item_1.BL_mod =jedec_driver_vif.cb_J.CA_DA_o[5]; + jedec_seq_item_1.BA[1:0] =jedec_driver_vif.cb_J.CA_DA_o[7:6]; + jedec_seq_item_1.BG[2:0] =jedec_driver_vif.cb_J.CA_DA_o[10:8]; + jedec_seq_item_1.CID[2:0] =jedec_driver_vif.cb_J.CA_DA_o[13:11]; + end + //precharge: + 5'b01011: begin + jedec_seq_item_1.CMD =PREab; + jedec_seq_item_1.BA[1:0] =jedec_driver_vif.cb_J.CA_DA_o[7:6]; + jedec_seq_item_1.BG[2:0] =jedec_driver_vif.cb_J.CA_DA_o[10:8]; + jedec_seq_item_1.CID[2:0] =jedec_driver_vif.cb_J.CA_DA_o[13:11]; + jedec_seq_item_1.CID[3] =jedec_driver_vif.cb_J.CA_DA_o[5]; + end + //other: + default: begin + CMD_tmp =DES; + end + endcase + end + `uvm_info("dram driver",$sformatf("driver says: command %s, bc: CA is %b, CS is %b at %t",jedec_seq_item_1.CMD,jedec_driver_vif.cb_J.CA_DA_o,jedec_driver_vif.cb_J.CS_DA_o,$time),UVM_HIGH); + if (jedec_driver_vif.cb_J.CA_DA_o[1]===0) begin //two cycle commands + cmd = 2; + end + end + if (clk == 2) begin + //@(jedec_driver_vif.cb_J) //second clock + if (jedec_driver_vif.cb_J.CS_DA_o===0) begin //check if canceled + jedec_seq_item_1.command_cancel=1; + cancel_flag = 1; + `uvm_info("dram driver",$sformatf("driver says: command cancelled, bc: CA is %b, CS is %b at %t",jedec_driver_vif.cb_J.CA_DA_o,jedec_driver_vif.cb_J.CS_DA_o,$time),UVM_HIGH); + end + else begin //not canceled + if (cancel_flag) CMD_tmp = DES; + case (CMD_tmp) + ACT: begin + jedec_seq_item_1.CMD = ACT; + jedec_seq_item_1.ROW[17:4] =jedec_driver_vif.cb_J.CA_DA_o[13:0]; + jedec_seq_item_1.CID[3] =jedec_driver_vif.cb_J.CA_DA_o[13]; + jedec_seq_item_1.command_cancel=0; + end + MRW: begin + jedec_seq_item_1.CMD = MRW; + jedec_seq_item_1.OP[7:0] =jedec_driver_vif.cb_J.CA_DA_o[7:0]; + jedec_seq_item_1.CW =jedec_driver_vif.cb_J.CA_DA_o[10]; + jedec_seq_item_1.command_cancel=0; + end + MRR: begin + jedec_seq_item_1.CMD = MRR; + jedec_seq_item_1.CW =jedec_driver_vif.cb_J.CA_DA_o[10]; + jedec_seq_item_1.command_cancel=0; + end + RD: begin + jedec_seq_item_1.CMD = RD; + jedec_seq_item_1.Col[10:2] =jedec_driver_vif.cb_J.CA_DA_o[8:0]; + jedec_seq_item_1.AP =jedec_driver_vif.cb_J.CA_DA_o[10]; + jedec_seq_item_1.CID[3] =jedec_driver_vif.cb_J.CA_DA_o[13]; + jedec_seq_item_1.command_cancel=0; + end + other: begin + //nothing + end + default: begin + //nothing + end + endcase + `uvm_info("dram driver",$sformatf("driver says: command %s, cycle 2, bc: CA is %b, CS is %b at %t",jedec_seq_item_1.CMD,jedec_driver_vif.cb_J.CA_DA_o,jedec_driver_vif.cb_J.CS_DA_o,$time),UVM_HIGH); + end + CMD_tmp = DES; + end + + else if (!cmd1_flag) begin + jedec_seq_item_1.CMD =DES; + cancel_flag = 0; + end + if (!reset_n) begin + jedec_seq_item_1.CMD =DES; + end +endtask : translation + + + + +//==============================================================================// +// Task: drive +// Description: This task clones jedec_seq_item_1 to dut_rsp for the reactive +// stimulus purpose, then drives the DQS and DATA bus +//==============================================================================// + +task dram_driver::drive(input ddr_sequence_item jedec_seq_item_1, output ddr_sequence_item dut_rsp); + if(!$cast(dut_rsp,jedec_seq_item_1.clone())) `uvm_fatal("DRVI", "cast to rsp_temp failed") + dut_rsp = jedec_seq_item_1; //Pass jedec_seq_item_1 values to rsp_temp + + + jedec_driver_vif.cb_J.DQS_AD_i <= jedec_seq_item_1.dqs; + jedec_driver_vif.cb_J.DQ_AD_i <= jedec_seq_item_1.data; +endtask + + + + + +//==============================================================================// +// Task: fill_mode_regiser +// Description: This task fills OP values in the mode registers when an MRW is +// received +//==============================================================================// + +task dram_driver::fill_mode_regiser(); //Create Mode registers + jedec_seq_item_1.MR[jedec_seq_item_1.MRA]=jedec_seq_item_1.OP; +endtask + + + + + +//==============================================================================// +// Task: parse_mode_regisers +// Description: This task parses the mode registers and obtain the configurations +// of the DRAM like RL, BL, pre/post amble +//==============================================================================// + +task dram_driver::parse_mode_regisers(); //Create Mode registers + if (!reset_n) begin + jedec_seq_item_1.MR[0] = 0; //Reset Mode registers + jedec_seq_item_1.MR[8] = 0; //Reset Mode registers + jedec_seq_item_1.MR[50] = 0; //Reset Mode registers + end + if (jedec_seq_item_1.CMD != MRR) begin // If BL_mod is activated (Active low) >> Get BL from MR0 + if (!jedec_seq_item_1.BL_mod) begin + case (jedec_seq_item_1.MR[0][1:0]) + 'b00 : jedec_seq_item_1.burst_length=BL16; + 'b01 : jedec_seq_item_1.burst_length=BC8_OTF; + 'b10 : jedec_seq_item_1.burst_length=BL32; + default : jedec_seq_item_1.burst_length=BL16; + endcase + end + else jedec_seq_item_1.burst_length = BL16; //Default for read and MRR + end + else begin + jedec_seq_item_1.burst_length = BL16; //Default for read and MRR + end + jedec_seq_item_1.RL = 22 + 2*jedec_seq_item_1.MR[0][6:2]; + jedec_seq_item_1.read_pre_amble = jedec_seq_item_1.MR[8'h8][2:0]; + + jedec_seq_item_1.read_post_amble = jedec_seq_item_1.MR[8'h8][6]; + + jedec_seq_item_1.CRC_enable = jedec_seq_item_1.MR[8'h32][0]; + +endtask + + + diff --git a/testbench/components/dram_agent/dram_monitor.sv b/testbench/components/dram_agent/dram_monitor.sv new file mode 100644 index 0000000..6ddcb77 --- /dev/null +++ b/testbench/components/dram_agent/dram_monitor.sv @@ -0,0 +1,505 @@ + typedef mailbox #(bit [4:0]) RD_and_MRR_CMD_mbx; // Stores the RD and MRR CMD (commands that sends data on the DQ) + // (To specify the burst length and MMR encoding required) + typedef mailbox #(bit) BL_mod_mbx; // Stores BL_mod corresponding to the Read CMD. + // (the size of this mailbox = # of RD CMDs in RD_and_MRR_CMD_mbx) + typedef mailbox #(int) clock_cycles_between_RD_mbx; // Stores the number of cycles between each two consecutive RD commands. + typedef mailbox #(int) clock_cycles_between_MRR_mbx; // Stores the number of cycles between each two consecutive MRR commands. + + class dram_monitor extends uvm_monitor; + `uvm_component_utils(dram_monitor) + + parameter device_width = 4; + + virtual jedec_intf jedec_monitor_vif; + ddr_sequence_item jedec_seq_item_1; + ddr_sequence_item jedec_seq_item_2; + uvm_analysis_port#(ddr_sequence_item) dram_analysis_port; + //==========================================================================// + // Mode Register Variables // + //==========================================================================// + static bit [2:0] read_pre_amble = 3'b000; + static bit read_post_amble = 0; + static byte RL = 8'd22; + static burst_length_t burst_length = BL16; + static burst_length_t actual_burst_length; + + //==========================================================================// + // mailboxes to specify the Burst Length // + //==========================================================================// + RD_and_MRR_CMD_mbx RD_and_MRR_CMD_mbx_inst; + BL_mod_mbx BL_mod_mbx_inst; + //===============================================================================================// + // mailboxes and varialbes for the number of cycles between RD->RD or MRR->MRR // + //===============================================================================================// + clock_cycles_between_RD_mbx clock_cycles_between_RD_mbx_inst; + clock_cycles_between_MRR_mbx clock_cycles_between_MRR_mbx_inst; + static int number_of_cycles_between_RD; + static bit first_RD_flag = 1; + static int number_of_cycles_between_MRR; + static bit first_MRR_flag = 1; + static int number_of_data_cycles; + + //==========================================================================// + // variables to detect the postamble or interamble // + //==========================================================================// + static int number_of_cycles_between_RD_dataThread; + static int number_of_cycles_between_MRR_dataThread; + static bit [4:0] CMD_type; + static int RD_try_get_result = 1; + static int MRR_try_get_result = 1; + static bit preample_flag = 1; + //==========================================================================// + // Handling Dummy Read // + //==========================================================================// + static bit waiting_dummy_read = 0; + + + function new (string name = "dram_monitor", uvm_component parent = null); + super.new(name,parent); + endfunction : new + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + if(!uvm_config_db#(virtual jedec_intf)::get(this,"","jedec_vif",jedec_monitor_vif)) + `uvm_fatal(get_full_name(),"Error in getting jedec_vif from database!") + jedec_seq_item_1 = ddr_sequence_item::type_id::create("jedec_seq_item_1"); + jedec_seq_item_2 = ddr_sequence_item::type_id::create("jedec_seq_item_2"); + RD_and_MRR_CMD_mbx_inst = new(); + BL_mod_mbx_inst = new(); + clock_cycles_between_RD_mbx_inst = new(); + clock_cycles_between_MRR_mbx_inst = new(); + dram_analysis_port = new("dram_analysis_port",this); + set_db(jedec_seq_item_1); + `uvm_info("Build_Phase", "*************** 'dram_monitor' Build Phase ***************", UVM_HIGH) + endfunction : build_phase + + //==========================================================================// + // Connect Phase // + //==========================================================================// + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + `uvm_info("Connect_phase", "*************** 'dram_monitor' Connect Phase ***************", UVM_HIGH) + endfunction : connect_phase + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + + fork begin + forever begin + monitor_data(); + phase.raise_objection(this); + `uvm_info("D_Monitor_data", $sformatf("data_array = %p, at %t", jedec_seq_item_2.jedec_rddata_queue ,$time), UVM_DEBUG) + dram_analysis_port.write(jedec_seq_item_2); + phase.drop_objection(this); + end + end + begin + forever begin + monitor_cmd(); + if(jedec_seq_item_1.CMD!=DES) begin + phase.raise_objection(this); + dram_analysis_port.write(jedec_seq_item_1); + set_db(jedec_seq_item_1);//Set MR Abstraction into DB to top level + `uvm_info("D_Monitor_cmd", $sformatf("cmd = %p, cancelled: %b,row= %p, CID= %p ,at %t", jedec_seq_item_1.CMD, jedec_seq_item_1.command_cancel,jedec_seq_item_1.ROW,jedec_seq_item_1.CID ,$time), UVM_DEBUG) + phase.drop_objection(this); + end + end + end + join + endtask : run_phase + //==========================================================================// + // dram_monitor Tasks & Functions Prototype // + //==========================================================================// + extern task monitor_data(); + extern task monitor_cmd(); + extern function void set_db(input ddr_sequence_item jedec_seq_item_1); + +endclass : dram_monitor + + //==============================================================================// + // Dram Monitor Tasks // + //==============================================================================// + +task dram_monitor::monitor_cmd(); + jedec_seq_item_1.is_data_only = 0; + jedec_seq_item_1.command_cancel=0; + @(jedec_monitor_vif.cb_J) //first clock + number_of_cycles_between_MRR ++; + number_of_cycles_between_RD ++; + + if (jedec_monitor_vif.cb_J.CS_DA_o===0 && jedec_monitor_vif.cb_J.CA_VALID_DA_o) begin //selected this chip + casex(jedec_monitor_vif.cb_J.CA_DA_o[4:0]) + //Act: + 5'b???00: begin + jedec_seq_item_1.CMD = ACT; + jedec_seq_item_1.ROW[3:0] = jedec_monitor_vif.cb_J.CA_DA_o[5:2]; + jedec_seq_item_1.BA[1:0] = jedec_monitor_vif.cb_J.CA_DA_o[7:6]; + jedec_seq_item_1.BG[2:0] = jedec_monitor_vif.cb_J.CA_DA_o[10:8]; + jedec_seq_item_1.CID[2:0] = jedec_monitor_vif.cb_J.CA_DA_o[13:11]; + end + //MRW: + 5'b00101: begin + jedec_seq_item_1.CMD = MRW; + jedec_seq_item_1.MRA[7:0] = jedec_monitor_vif.cb_J.CA_DA_o[12:5]; + end + //MRR: + 5'b10101: begin + jedec_seq_item_1.CMD = MRR; + jedec_seq_item_1.MRA[7:0] = jedec_monitor_vif.cb_J.CA_DA_o[12:5]; + end + //RD: + 5'b11101: begin + jedec_seq_item_1.CMD = RD; + jedec_seq_item_1.BL_mod = jedec_monitor_vif.cb_J.CA_DA_o[5]; + jedec_seq_item_1.BA[1:0] = jedec_monitor_vif.cb_J.CA_DA_o[7:6]; + jedec_seq_item_1.BG[2:0] = jedec_monitor_vif.cb_J.CA_DA_o[10:8]; + jedec_seq_item_1.CID[2:0] = jedec_monitor_vif.cb_J.CA_DA_o[13:11]; + end + //NOP: + 5'b11111: begin + jedec_seq_item_1.CMD = NOP; + end + //precharge: + 5'b01011: begin + jedec_seq_item_1.CMD = PREab; + jedec_seq_item_1.CID[2:0] = jedec_monitor_vif.cb_J.CA_DA_o[13:11]; + jedec_seq_item_1.CID[3] = jedec_monitor_vif.cb_J.CA_DA_o[5]; + end + //other: + default: begin + jedec_seq_item_1.CMD = other; + end + endcase + `uvm_info("dram monitor",$sformatf("Monitor says: command %s, bc: CA is %b, CS is %b at %t",jedec_seq_item_1.CMD,jedec_monitor_vif.cb_J.CA_DA_o,jedec_monitor_vif.cb_J.CS_DA_o,$time),UVM_HIGH); + if (jedec_monitor_vif.cb_J.CA_DA_o[1]===0) begin //two cycle commands + @(jedec_monitor_vif.cb_J) //second clock + + number_of_cycles_between_MRR ++; + number_of_cycles_between_RD ++; + + if (jedec_monitor_vif.cb_J.CS_DA_o===0) begin //check if canceled + jedec_seq_item_1.command_cancel=1; + `uvm_info("dram monitor",$sformatf("Monitor says: command cancelled, bc: CA is %b, CS is %b at %t",jedec_monitor_vif.cb_J.CA_DA_o,jedec_monitor_vif.cb_J.CS_DA_o,$time),UVM_HIGH); + end + else begin //not canceled + case (jedec_seq_item_1.CMD) + ACT: begin + jedec_seq_item_1.ROW[17:4] = jedec_monitor_vif.cb_J.CA_DA_o[13:0]; + jedec_seq_item_1.CID[3] = jedec_monitor_vif.cb_J.CA_DA_o[13]; + end + MRW: begin + jedec_seq_item_1.OP[7:0] = jedec_monitor_vif.cb_J.CA_DA_o[7:0]; + jedec_seq_item_1.CW = jedec_monitor_vif.cb_J.CA_DA_o[10]; + + case (jedec_seq_item_1.MRA[7:0]) + 8'h00: begin + if (!$cast(burst_length, jedec_seq_item_1.OP[1:0])) // MR0, Burst Length + `uvm_error("dram monitor_cmd:","Cast failed") + RL = 22 + 2*jedec_seq_item_1.OP[6:2]; + jedec_seq_item_1.burst_length = burst_length; + jedec_seq_item_1.RL = RL; + end + 8'h08: begin // MR8 + read_pre_amble[2:0] = jedec_seq_item_1.OP[2:0]; // Read Preamble Settings + read_post_amble = jedec_seq_item_1.OP[6]; // Read Postamble Settings + jedec_seq_item_1.read_pre_amble = read_pre_amble; + jedec_seq_item_1.read_post_amble = read_post_amble; + end + default: begin + //nothing + end + endcase + end + MRR: begin + RD_and_MRR_CMD_mbx_inst.put(5'b10101); + + if (! first_MRR_flag) begin + jedec_seq_item_1.number_of_cycles_between_MRR = number_of_cycles_between_MRR; + clock_cycles_between_MRR_mbx_inst.put(number_of_cycles_between_MRR); // if this is te first read command, then do not put the cycles number in the queue because it has no meaning. + end + if (first_MRR_flag) first_MRR_flag = 0; // This flag marks the first MRR command is issued. + number_of_cycles_between_MRR = 0; + + jedec_seq_item_1.CW = jedec_monitor_vif.cb_J.CA_DA_o[10]; + jedec_seq_item_1.burst_length = burst_length; + + jedec_seq_item_1.actual_burst_length = BL16; + + jedec_seq_item_1.RL = RL; + jedec_seq_item_1.read_pre_amble = read_pre_amble; + jedec_seq_item_1.read_post_amble = read_post_amble; + end + RD: begin + if (!waiting_dummy_read) begin + RD_and_MRR_CMD_mbx_inst.put(5'b11101); + BL_mod_mbx_inst.put(jedec_seq_item_1.BL_mod); + + if (! first_RD_flag) begin + jedec_seq_item_1.number_of_cycles_between_RD = number_of_cycles_between_RD; + clock_cycles_between_RD_mbx_inst.put(number_of_cycles_between_RD); // if this is te first read command, then do not put the cycles number in the queue because it has no meaning. + end + if (first_RD_flag) first_RD_flag = 0; // This flag marks the first RD command is issued. + number_of_cycles_between_RD = 0; + + jedec_seq_item_1.Col[10:2] = jedec_monitor_vif.cb_J.CA_DA_o[8:0]; + jedec_seq_item_1.AP = jedec_monitor_vif.cb_J.CA_DA_o[10]; + jedec_seq_item_1.CID[3] = jedec_monitor_vif.cb_J.CA_DA_o[13]; + jedec_seq_item_1.burst_length = burst_length; + + jedec_seq_item_1.actual_burst_length = jedec_seq_item_1.burst_length; + if (jedec_seq_item_1.BL_mod) jedec_seq_item_1.actual_burst_length = BL16; + + waiting_dummy_read = 0; + if (jedec_seq_item_1.actual_burst_length == BL32) waiting_dummy_read = 1; + + jedec_seq_item_1.RL = RL; + jedec_seq_item_1.read_pre_amble = read_pre_amble; + jedec_seq_item_1.read_post_amble = read_post_amble; + + end else begin + // in this case we are receiving the dummy read + // it will be considered as DES so that it is not sent to the subscriber and scoreboard + jedec_seq_item_1.CMD = DES; + waiting_dummy_read = 0; // for the next cycles + end + end + other: begin + //nothing + end + default: begin + //nothing + end + endcase + `uvm_info("dram monitor",$sformatf("Monitor says: command %s, cycle 2, bc: CA is %b, CS is %b at %t",jedec_seq_item_1.CMD,jedec_monitor_vif.cb_J.CA_DA_o,jedec_monitor_vif.cb_J.CS_DA_o,$time),UVM_HIGH); + end + end + end + else begin + jedec_seq_item_1.CMD = DES; + `uvm_info("dram monitor",$sformatf("Monitor says DOWN: command %s, bc: CA is %b, CS is %b at %t",jedec_seq_item_1.CMD,jedec_monitor_vif.cb_J.CA_DA_o,jedec_monitor_vif.cb_J.CS_DA_o,$time),UVM_HIGH); + end + + endtask : monitor_cmd + +task dram_monitor::monitor_data(); + + // Commands of interest: MRR, RD. Commands not required: Act, NOP, Precharge, others + // the data of MRW command is sent over the CA pins + + bit preamble_pattern []; + bit BL_mod; + bit overlap_flag_2tCK; + bit overlap_flag_3tCK; + bit overlap_flag_4tCK; + + // Setting the "data only" flag to 1 to signify a transaction carrying read/mrr data (not a command) + jedec_seq_item_2.is_data_only = 1; + + // Empty the jedec_rddata_queue from the data of the previous cycle + jedec_seq_item_2.jedec_rddata_queue.delete(); + + //`uvm_info("", $sformatf("before preamble at %t", $time), UVM_DEBUG) + + if (preample_flag) begin + //`uvm_info("", $sformatf("after preamble at %t", $time), UVM_DEBUG) + + //==========================================================================// + // detecting the preamble pattern // + //==========================================================================// + // assuming that the DQS is zero unless there is preamble, interamble, or postamble. + overlap_flag_2tCK = 0; + overlap_flag_3tCK = 0; + overlap_flag_4tCK = 0; + forever begin + @(posedge jedec_monitor_vif.dfi_phy_clk); + case (read_pre_amble[2:0]) // specify the preample pattern + 3'b000: begin // 10 Pattern - in the jedec, this pattern takes 1 tCK, but the design changes DQS + // in the positive edge of the clock only, so it takes 2 tCK + `uvm_info("Preample detection", $sformatf("DQS: %b , at %t", jedec_monitor_vif.DQS_AD_i,$time), UVM_DEBUG) + if ( jedec_monitor_vif.DQS_AD_i !== 1) continue; + @(posedge jedec_monitor_vif.dfi_phy_clk); + `uvm_info("Preample detection", $sformatf("DQS: %b , at %t", jedec_monitor_vif.DQS_AD_i,$time), UVM_DEBUG) + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + `uvm_info("Preample detection", $sformatf("DQS: %b , at %t", jedec_monitor_vif.DQS_AD_i,$time), UVM_DEBUG) + break; + end + 3'b001: begin // 0010 Pattern - in the jedec, this pattern takes 2 tCK, but the design changes DQS + // in the positive edge of the clock only, so it takes 4 tCK + if (overlap_flag_2tCK === 0) begin + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + @(posedge jedec_monitor_vif.dfi_phy_clk); + end + if (jedec_monitor_vif.DQS_AD_i !== 1) begin + overlap_flag_2tCK = 1; + continue; + end + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + break; + end + 3'b010: begin // 1110 Pattern - in the jedec, this pattern takes 2 tCK, but the design changes DQS + // in the positive edge of the clock only, so it takes 4 tCK + `uvm_info("Preample detection", $sformatf("DQS: %b , at %t", jedec_monitor_vif.DQS_AD_i,$time), UVM_DEBUG) + if (jedec_monitor_vif.DQS_AD_i !== 1) continue; + `uvm_info("Preample detection", $sformatf("Pattern detected: 1, at %t" ,$time), UVM_DEBUG) + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 1) continue; + `uvm_info("Preample detection", $sformatf("Pattern detected: 1, at %t" ,$time), UVM_DEBUG) + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 1) continue; + `uvm_info("Preample detection", $sformatf("Pattern detected: 1, at %t" ,$time), UVM_DEBUG) + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + `uvm_info("Preample detection", $sformatf("Pattern detected: 0, at %t" ,$time), UVM_DEBUG) + `uvm_info("Preample detection", $sformatf("Pattern detected, at %t" ,$time), UVM_DEBUG) + break; + end + 3'b011: begin // 000010 Pattern - in the jedec, this pattern takes 3 tCK, but the design changes DQS + // in the positive edge of the clock only, so it takes 6 tCK + if (overlap_flag_3tCK === 0) begin + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + @(posedge jedec_monitor_vif.dfi_phy_clk); + end + if (jedec_monitor_vif.DQS_AD_i !== 1) begin + overlap_flag_3tCK = 1; + continue; + end + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + break; + end + 3'b100: begin // 00001010 Pattern - in the jedec, this pattern takes 4 tCK, but the design changes DQS + // in the positive edge of the clock only, so it takes 8 tCK + if (overlap_flag_4tCK === 0) begin + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + @(posedge jedec_monitor_vif.dfi_phy_clk); + end + if (jedec_monitor_vif.DQS_AD_i !== 1) begin + overlap_flag_4tCK = 1; + continue; + end + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 1) continue; + @(posedge jedec_monitor_vif.dfi_phy_clk); + if (jedec_monitor_vif.DQS_AD_i !== 0) continue; + break; + end + default: begin + + end + endcase + end + `uvm_info("", $sformatf("after case at %t", $time), UVM_DEBUG) + @(posedge jedec_monitor_vif.dfi_phy_clk); + + end else begin + if (CMD_type == 5'b11101) begin // RD command + repeat(number_of_cycles_between_RD_dataThread-number_of_data_cycles) @(posedge jedec_monitor_vif.dfi_phy_clk); + end else if (CMD_type == 5'b10101) begin // MRR command + repeat(number_of_cycles_between_MRR_dataThread-number_of_data_cycles) @(posedge jedec_monitor_vif.dfi_phy_clk); + end + end + `uvm_info("ID1", $sformatf("before determine burst length at %t", $time), UVM_DEBUG) + //==========================================================================// + // Determine The Burst Length // + //==========================================================================// + RD_and_MRR_CMD_mbx_inst.get(CMD_type); // get command type (RD = 5'b11101 or MRR = 5'b10101) + // blocking because if the preample patteren was detected, then surely, there is RD or MRR command. + `uvm_info("ID2", $sformatf("CMD_type %b at %t", CMD_type,$time), UVM_DEBUG) + + actual_burst_length = burst_length; // the burst length is the value specified in corresonding mode register. + // unless specified otherwise in the following conditions: + if (CMD_type == 5'b11101) begin // if RD command, get BL_mod + // if (BL_mod == 1), actual_burst_length = default Burst Length 16 mode + BL_mod_mbx_inst.get(BL_mod); + if (BL_mod) actual_burst_length = BL16; + end + + if (CMD_type == 5'b10101) actual_burst_length = BL16; // if (CMD_type == MRR), actual_burst_length = Burst Length 16 mode + + jedec_seq_item_2.actual_burst_length = actual_burst_length; + //==========================================================================// + // collecting the data // + //==========================================================================// + `uvm_info("ID3", $sformatf("actual_burst_length %b at %t", actual_burst_length,$time), UVM_DEBUG) + case (actual_burst_length) + BL16: number_of_data_cycles = 8; // BL16: 8 Clock cycles + BC8_OTF: number_of_data_cycles = 4; // BC8 OTF: 4 Clock cycles + BL32: number_of_data_cycles = 16; // BL32: 16 Clock cycles + endcase + `uvm_info("ID4", $sformatf("number_of_data_cycles %d at %t", number_of_data_cycles,$time), UVM_DEBUG) + jedec_seq_item_2.jedec_rddata_queue.push_back(jedec_monitor_vif.DQ_AD_i); + `uvm_info("ID5", $sformatf("data_array = %p, at %t", jedec_seq_item_2.jedec_rddata_queue ,$time), UVM_DEBUG) + repeat(number_of_data_cycles - 1) begin + @(posedge jedec_monitor_vif.dfi_phy_clk); + jedec_seq_item_2.jedec_rddata_queue.push_back(jedec_monitor_vif.DQ_AD_i); + `uvm_info("ID6", $sformatf("data_array = %p, at %t", jedec_seq_item_2.jedec_rddata_queue ,$time), UVM_DEBUG) + end + + // if (CMD_type == MRR), the DQ data are encoded according to Table 14, Section 3.4.1 in the JEDEC. + // the monitor decodes this data to send the correct OP. + if (CMD_type == 5'b10101) begin + for (int i = 4; i < 8; i++) begin // burst length is always BL16 for MRR + jedec_seq_item_2.OP[2*(i-4)] = jedec_seq_item_2.jedec_rddata_queue[i][2*device_width-1]; + jedec_seq_item_2.OP[2*(i-4) + 1] = jedec_seq_item_2.jedec_rddata_queue[i][device_width-1]; + end + end + @(posedge jedec_monitor_vif.dfi_phy_clk); + `uvm_info("ID7", $sformatf("data_array = %p, at %t", jedec_seq_item_2.jedec_rddata_queue ,$time), UVM_DEBUG) + + //==========================================================================// + // Setting Flags for Next Cycle // + //==========================================================================// + if (CMD_type == 5'b11101) begin + if (RD_try_get_result == 0) // Edge Case: will be used after the first RD. This is the result from the previous RD command + clock_cycles_between_RD_mbx_inst.get(number_of_cycles_between_RD_dataThread); // blocking because there must be at least one item in the mailbox because the previous command didn't find this element, and we are now stating the postamble of the current RD command which means that + // the current command came at or after the postamble of the previous RD, and we don't need it now. + // must return non-zero value + RD_try_get_result = clock_cycles_between_RD_mbx_inst.try_get(number_of_cycles_between_RD_dataThread); // non-blocking method because there could be no following RD commands at this point + // get the number of cycles between the current RD or MRR command and the next RD or MRR, RESPECTIVELY (RD->RD or MRR->MRR), if exists. + if (RD_try_get_result == 0) preample_flag = 1; + else preample_flag = 0; + end else if (CMD_type == 5'b10101) begin + if (MRR_try_get_result == 0) // Edge Case: will be used after the first RD. This is the result from the previous RD command + clock_cycles_between_MRR_mbx_inst.get(number_of_cycles_between_MRR_dataThread); // blocking because there must be at least one item in the mailbox because the previous command didn't find this element, and we are now stating the postamble of the current RD command which means that + // the current command came at or after the postamble of the previous RD, and we don't need it now. + // must return non-zero value + MRR_try_get_result = clock_cycles_between_MRR_mbx_inst.try_get(number_of_cycles_between_MRR_dataThread); // non-blocking method because there could be no following RD commands at this point + // get the number of cycles between the current RD or MRR command and the next RD or MRR, RESPECTIVELY (RD->RD or MRR->MRR), if exists. + if (MRR_try_get_result == 0) preample_flag = 1; + else preample_flag = 0; + end + + endtask : monitor_data + + + + function void dram_monitor::set_db(input ddr_sequence_item jedec_seq_item_1); + uvm_config_db#(byte)::set(null,"*","RL",jedec_seq_item_1.RL); + uvm_config_db#(burst_length_t)::set(null,"*","burst_length",jedec_seq_item_1.actual_burst_length); + uvm_config_db#(bit)::set(null,"*","pre_amble",jedec_seq_item_1.read_pre_amble); + uvm_config_db#(bit)::set(null,"*","post_amble",jedec_seq_item_1.read_post_amble); + uvm_config_db#(bit)::set(null,"*","CRC_enable",jedec_seq_item_1.CRC_enable); + endfunction diff --git a/testbench/components/dram_agent/dram_sequencer.sv b/testbench/components/dram_agent/dram_sequencer.sv new file mode 100644 index 0000000..b57e9c3 --- /dev/null +++ b/testbench/components/dram_agent/dram_sequencer.sv @@ -0,0 +1,34 @@ +class dram_sequencer extends uvm_sequencer#(ddr_sequence_item); + `uvm_component_utils(dram_sequencer) + + uvm_seq_item_pull_imp#(ddr_sequence_item,ddr_sequence_item, dram_sequencer) dram_seq_item_imp; + + + function new (string name = "dram_sequencer", uvm_component parent = null); + super.new(name, parent); + endfunction + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + dram_seq_item_imp = new("dram_seq_item_imp",this); + `uvm_info("Build_Phase", "*************** 'dram_sequencer' Build Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Connect Phase // + //==========================================================================// + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + `uvm_info("Connect_phase", "*************** 'dram_sequencer' Connect Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + endtask +endclass : dram_sequencer \ No newline at end of file diff --git a/testbench/components/env.sv b/testbench/components/env.sv new file mode 100644 index 0000000..546a722 --- /dev/null +++ b/testbench/components/env.sv @@ -0,0 +1,57 @@ +class env extends uvm_env; + `uvm_component_utils(env) + + dram_agent dram_agent1; + mc_agent mc_agent1; + scoreboard scb1; + subscriber subs1; + virtual dfi_intf env_dfi_vif; + virtual jedec_intf env_jedec_vif; + + + function new (string name = "env", uvm_component parent = null); + super.new(name,parent); + endfunction + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + if(!uvm_config_db#(virtual dfi_intf)::get(this,"","dfi_vif",env_dfi_vif)) + `uvm_fatal(get_full_name(),"Error in getting dfi_vif from database!") + if(!uvm_config_db#(virtual jedec_intf)::get(this,"","jedec_vif",env_jedec_vif)) + `uvm_fatal(get_full_name(),"Error in getting jedec_vif from database!") + + mc_agent1 = mc_agent::type_id::create("mc_agent1",this); + dram_agent1 = dram_agent::type_id::create("dram_agent1",this); + scb1 = scoreboard::type_id::create("scb1",this); + subs1 = subscriber::type_id::create("subs1",this); + `uvm_info("Build_Phase", "*************** 'env' Build Phase ***************", UVM_HIGH) + //set virtual interfaces visible to all components below env in hirarchy + uvm_config_db#(virtual dfi_intf)::set(this,"*","dfi_vif",env_dfi_vif); + uvm_config_db#(virtual jedec_intf)::set(this,"*","jedec_vif",env_jedec_vif); + endfunction + + //==========================================================================// + // Connect Phase // + //==========================================================================// + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + //*************Connect agents analysis port to subscriber and scoreboard analysis imp + //Scoreboard + mc_agent1.mc_analysis_port.connect(scb1.dfi_analysis_imp); + dram_agent1.dram_analysis_port.connect(scb1.jedec_analysis_imp); + //Subscriber + mc_agent1.mc_analysis_port.connect(subs1.mc_analysis_imp); + dram_agent1.dram_analysis_port.connect(subs1.dram_analysis_imp); + `uvm_info("Connect_phase", "*************** 'env' Connect Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + endtask +endclass : env diff --git a/testbench/components/mc_agent/mc_agent.sv b/testbench/components/mc_agent/mc_agent.sv new file mode 100644 index 0000000..7c8b39f --- /dev/null +++ b/testbench/components/mc_agent/mc_agent.sv @@ -0,0 +1,47 @@ +class mc_agent extends uvm_agent; + `uvm_component_utils(mc_agent) + + mc_driver mc_driver1; + mc_monitor mc_monitor1; + mc_sequencer mc_sequencer1; + + //uvm_analysis_port for broadcasting to subscriber and scoreboard + uvm_analysis_port#(ddr_sequence_item) mc_analysis_port; + + + function new (string name = "mc_agent", uvm_component parent = null); + super.new(name,parent); + endfunction + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + mc_driver1 = mc_driver::type_id::create("mc_driver1",this); + mc_monitor1 = mc_monitor::type_id::create("mc_monitor1",this); + mc_sequencer1 = mc_sequencer::type_id::create("mc_sequencer1",this); + mc_analysis_port = new("mc_analysis_port",this); + `uvm_info("Build_Phase", "*************** 'mc_agent' Build Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Connect Phase // + //==========================================================================// + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + //Connect driver port to sequencer imp/export + mc_driver1.seq_item_port.connect(mc_sequencer1.mc_seq_item_imp); + + //Connect monitor analysis port to agent analysis port + mc_monitor1.mc_analysis_port.connect(mc_analysis_port); + `uvm_info("Connect_phase", "*************** 'mc_agent' Connect Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + endtask +endclass : mc_agent \ No newline at end of file diff --git a/testbench/components/mc_agent/mc_driver.sv b/testbench/components/mc_agent/mc_driver.sv new file mode 100644 index 0000000..5657321 --- /dev/null +++ b/testbench/components/mc_agent/mc_driver.sv @@ -0,0 +1,461 @@ +class mc_driver extends uvm_driver#(ddr_sequence_item); + `uvm_component_utils(mc_driver) + parameter Physical_Rank_No = 1; + + ddr_sequence_item dfi_item1, dfi_item1_prev; + virtual dfi_intf dfi_driver_vif; + static int n_words = 0; + static logic [13:0] CMD0,CMD1; + static logic [Physical_Rank_No-1:0] CS0,CS1; + static logic [13:0] CMD_queue [$]; + static logic [Physical_Rank_No-1:0] CS_queue [$]; + static logic rddata_en_queue [$]; + static int start_flag = 1; + static bit termination_flag = 0; //To terminate dram resp_sequence + + function new (string name = "mc_driver", uvm_component parent = null); + super.new(name,parent); + endfunction + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + if(!uvm_config_db#(virtual dfi_intf)::get(this,"","dfi_vif",dfi_driver_vif)) + `uvm_fatal(get_full_name(),"Error in getting dfi_vif from database!") + dfi_item1 = ddr_sequence_item::type_id::create("dfi_item1"); + dfi_item1_prev = ddr_sequence_item::type_id::create("dfi_item1_prev"); + uvm_config_db#(bit)::set(null,"uvm_test_top.env1.dram_agent1.dram_driver1","reset_n",dfi_item1.reset_n_i); //Set reset in db + uvm_config_db#(bit)::set(null,"uvm_test_top.env1.dram_agent1.dram_driver1","termination_flag",termination_flag);//Set termination flag = 0 in db + //`uvm_info("Build_Phase", "*************** 'mc_driver' Build Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Connect Phase // + //==========================================================================// + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + //`uvm_info("Connect_phase", "*************** 'mc_driver' Connect Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Pre-reset Phase // + //==========================================================================// + task pre_reset_phase(uvm_phase phase); //Set initial values + phase.raise_objection(this); + dfi_driver_vif.dfi_address_p0 <= 14'bz; + dfi_driver_vif.dfi_address_p1 <= 14'bz; + dfi_driver_vif.dfi_address_p1 <= 14'bz; + dfi_driver_vif.dfi_address_p2 <= 14'bz; + dfi_driver_vif.dfi_address_p3 <= 14'bz; + `ifdef ratio_1_to_1 + dfi_driver_vif.dfi_cs_p0 <= 1'b1; + dfi_driver_vif.dfi_cs_p1 <= 1'bz; + dfi_driver_vif.dfi_cs_p2 <= 1'bz; + dfi_driver_vif.dfi_cs_p3 <= 1'bz; + dfi_driver_vif.dfi_rddata_en_p0 <= 1'b0; + dfi_driver_vif.dfi_rddata_en_p1 <= 1'bz; + dfi_driver_vif.dfi_rddata_en_p2 <= 1'bz; + dfi_driver_vif.dfi_rddata_en_p3 <= 1'bz; + `elsif ratio_1_to_2 + dfi_driver_vif.dfi_cs_p0 <= 1'b1; + dfi_driver_vif.dfi_cs_p1 <= 1'b1; + dfi_driver_vif.dfi_cs_p2 <= 1'bz; + dfi_driver_vif.dfi_cs_p3 <= 1'bz; + dfi_driver_vif.dfi_rddata_en_p0 <= 1'b0; + dfi_driver_vif.dfi_rddata_en_p1 <= 1'b0; + dfi_driver_vif.dfi_rddata_en_p2 <= 1'bz; + dfi_driver_vif.dfi_rddata_en_p3 <= 1'bz; + `elsif ratio_1_to_4 + dfi_driver_vif.dfi_cs_p0 <= 1'b1; + dfi_driver_vif.dfi_cs_p1 <= 1'b1; + dfi_driver_vif.dfi_cs_p2 <= 1'b1; + dfi_driver_vif.dfi_cs_p3 <= 1'b1; + dfi_driver_vif.dfi_rddata_en_p0 <= 1'b0; + dfi_driver_vif.dfi_rddata_en_p1 <= 1'b0; + dfi_driver_vif.dfi_rddata_en_p2 <= 1'b0; + dfi_driver_vif.dfi_rddata_en_p3 <= 1'b0; + `endif + + phase.drop_objection(this); + endtask + + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + forever begin + seq_item_port.get_next_item(dfi_item1); + drive_dfi(); + seq_item_port.item_done(); + end + endtask + + + //==========================================================================// + // MC Tasks Prototype // + //==========================================================================// + extern task drive_dfi (); + extern task num_of_words(); + extern task decode_cmd(); + extern task ACT_cmd (); // ACT command_decoding + extern task RD_cmd (); // READ command_decoding + extern task MRW_cmd (); // MRW command_decoding + extern task MRR_cmd (); // MRR command_decoding + extern task DES_cmd (); // DES command_decoding + extern task PREab_CMD (); // PREab_CMD command_decoding +endclass : mc_driver + + + + +//==============================================================================// +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||// +//==============================================================================// +// MC Driver Tasks // +//==============================================================================// +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||// +//==============================================================================// + + + + +//==============================================================================// +// Task: drive_dfi +// Description: This is the main task that translates transaction into pin level +// Activity +//==============================================================================// + +task mc_driver::drive_dfi (); + decode_cmd(); + num_of_words(); + + if ((dfi_item1.CMD == DES) || (dfi_item1.CMD == PREab)) begin + CMD_queue = {CMD_queue, CMD0}; + CS_queue = {CS_queue, CS0}; + if (rddata_en_queue.size() < CMD_queue.size()) rddata_en_queue = {rddata_en_queue, 0}; //if !rddata_en then n_words will be 0 + end + else begin + CMD_queue = {CMD_queue, CMD0, CMD1}; + CS_queue = {CS_queue, CS0, CS1}; + if (rddata_en_queue.size() < CMD_queue.size()) begin + if (rddata_en_queue[$] == 1) rddata_en_queue = {rddata_en_queue, 0}; + else rddata_en_queue = {rddata_en_queue, 0, 0}; //if !rddata_en then n_words will be 0 + end + end + + if (n_words > 0) begin + while (n_words > 0) begin //If this cond is true then rddata_en = 1 + rddata_en_queue = {rddata_en_queue, 1}; + n_words = n_words - 1; + end + end + if ((!dfi_item1.reset_n_i)||(!dfi_item1.en_i)) begin + dfi_driver_vif.en_i <= dfi_item1.en_i; + dfi_driver_vif.reset_n_i <= dfi_item1.reset_n_i; + @(dfi_driver_vif.cb_D); + end + dfi_driver_vif.en_i <= dfi_item1.en_i; + dfi_driver_vif.reset_n_i <= dfi_item1.reset_n_i; + dfi_driver_vif.cb_D.phycrc_mode_i <= dfi_item1.phycrc_mode_i; + dfi_driver_vif.cb_D.dfi_freq_ratio_i <= dfi_item1.dfi_freq_ratio; + + + case (dfi_item1.dfi_freq_ratio) + 2'b00 : begin + while (CMD_queue.size() >= 1) begin + @(dfi_driver_vif.cb_D); + dfi_driver_vif.cb_D.dfi_address_p0 <= CMD_queue.pop_front; + dfi_driver_vif.cb_D.dfi_address_p1 <= 14'bz; + dfi_driver_vif.cb_D.dfi_address_p2 <= 14'bz; + dfi_driver_vif.cb_D.dfi_address_p3 <= 14'bz; + dfi_driver_vif.cb_D.dfi_cs_p0 <= CS_queue.pop_front; + dfi_driver_vif.cb_D.dfi_cs_p1 <= 1'bz; + dfi_driver_vif.cb_D.dfi_cs_p2 <= 1'bz; + dfi_driver_vif.cb_D.dfi_cs_p3 <= 1'bz; + dfi_driver_vif.cb_D.dfi_rddata_en_p0 <= rddata_en_queue.pop_front; + dfi_driver_vif.cb_D.dfi_rddata_en_p1 <= 1'bz; + dfi_driver_vif.cb_D.dfi_rddata_en_p2 <= 1'bz; + dfi_driver_vif.cb_D.dfi_rddata_en_p3 <= 1'bz; + //`uvm_info("DRV", $sformatf("Driver: dfi_address_p0 = %b, dfi_item1.ROW = %p, dfi_item1.CID = %p, CS_p0 = %p \t rddata_en_p0 = %p, at %t", dfi_driver_vif.cb_D.dfi_address_p0,dfi_item1.ROW,dfi_item1.CID,dfi_driver_vif.cb_D.dfi_cs_p0, dfi_driver_vif.cb_D.dfi_rddata_en_p0, $time), UVM_DEBUG) + end + end + 2'b01 : begin + while (CMD_queue.size() >= 2) begin + @(dfi_driver_vif.cb_D); + dfi_driver_vif.cb_D.dfi_address_p0 <= CMD_queue.pop_front; + dfi_driver_vif.cb_D.dfi_address_p1 <= CMD_queue.pop_front; + dfi_driver_vif.cb_D.dfi_address_p2 <= 14'bz; + dfi_driver_vif.cb_D.dfi_address_p3 <= 14'bz; + dfi_driver_vif.cb_D.dfi_cs_p0 <= CS_queue.pop_front; + dfi_driver_vif.cb_D.dfi_cs_p1 <= CS_queue.pop_front; + dfi_driver_vif.cb_D.dfi_cs_p2 <= 1'bz; + dfi_driver_vif.cb_D.dfi_cs_p3 <= 1'bz; + dfi_driver_vif.cb_D.dfi_rddata_en_p0 <= rddata_en_queue.pop_front; + dfi_driver_vif.cb_D.dfi_rddata_en_p1 <= rddata_en_queue.pop_front; + dfi_driver_vif.cb_D.dfi_rddata_en_p2 <= 1'bz; + dfi_driver_vif.cb_D.dfi_rddata_en_p3 <= 1'bz; + //`uvm_info("DRV", $sformatf("Driver: Freq. ratio: %b, dfi_address_p0 = %b, dfi_address_p1 = %b, CS_p0 = %p, CS_p1 = %p rddata_en_p0 = %p, rddata_en_p1 = %p, at %t",dfi_item1.dfi_freq_ratio, dfi_driver_vif.cb_D.dfi_address_p0, dfi_driver_vif.cb_D.dfi_address_p1,dfi_driver_vif.cb_D.dfi_cs_p0,dfi_driver_vif.cb_D.dfi_cs_p1,dfi_driver_vif.cb_D.dfi_rddata_en_p0,dfi_driver_vif.cb_D.dfi_rddata_en_p1, $time), UVM_DEBUG) + end + end + 2'b10 : begin + while (CMD_queue.size() >= 4) begin + @(dfi_driver_vif.cb_D); + dfi_driver_vif.cb_D.dfi_address_p0 <= CMD_queue.pop_front; + dfi_driver_vif.cb_D.dfi_address_p1 <= CMD_queue.pop_front; + dfi_driver_vif.cb_D.dfi_address_p2 <= CMD_queue.pop_front; + dfi_driver_vif.cb_D.dfi_address_p3 <= CMD_queue.pop_front; + dfi_driver_vif.cb_D.dfi_cs_p0 <= CS_queue.pop_front; + dfi_driver_vif.cb_D.dfi_cs_p1 <= CS_queue.pop_front; + dfi_driver_vif.cb_D.dfi_cs_p2 <= CS_queue.pop_front; + dfi_driver_vif.cb_D.dfi_cs_p3 <= CS_queue.pop_front; + dfi_driver_vif.cb_D.dfi_rddata_en_p0 <= rddata_en_queue.pop_front; + dfi_driver_vif.cb_D.dfi_rddata_en_p1 <= rddata_en_queue.pop_front; + dfi_driver_vif.cb_D.dfi_rddata_en_p2 <= rddata_en_queue.pop_front; + dfi_driver_vif.cb_D.dfi_rddata_en_p3 <= rddata_en_queue.pop_front; + //`uvm_info("DRV", $sformatf("Driver: Freq. ratio: %b, dfi_address_p0 = %b, dfi_address_p1 = %b, dfi_address_p2 = %b, dfi_address_p3 = %b, CS_p0 = %p, CS_p1 = %p, CS_p2 = %p, CS_p3 = %p , rddata_en_p0 = %p, rddata_en_p1 = %p, rddata_en_p2 = %p, rddata_en_p3 = %p, at %t",dfi_item1.dfi_freq_ratio, dfi_driver_vif.cb_D.dfi_address_p0, dfi_driver_vif.cb_D.dfi_address_p1,dfi_driver_vif.cb_D.dfi_address_p2, dfi_driver_vif.cb_D.dfi_address_p3,dfi_driver_vif.cb_D.dfi_cs_p0,dfi_driver_vif.cb_D.dfi_cs_p1,dfi_driver_vif.cb_D.dfi_cs_p2,dfi_driver_vif.cb_D.dfi_cs_p3, dfi_driver_vif.cb_D.dfi_rddata_en_p0,dfi_driver_vif.cb_D.dfi_rddata_en_p1,dfi_driver_vif.cb_D.dfi_rddata_en_p2,dfi_driver_vif.cb_D.dfi_rddata_en_p3, $time), UVM_DEBUG) + end + end + default : begin + while (CMD_queue.size() >= 1) begin + @(dfi_driver_vif.cb_D); + dfi_driver_vif.cb_D.dfi_address_p0 <= CMD_queue.pop_front; + dfi_driver_vif.cb_D.dfi_address_p1 <= 14'bz; + dfi_driver_vif.cb_D.dfi_address_p2 <= 14'bz; + dfi_driver_vif.cb_D.dfi_address_p3 <= 14'bz; + dfi_driver_vif.cb_D.dfi_cs_p0 <= CS_queue.pop_front; + dfi_driver_vif.cb_D.dfi_cs_p1 <= 1'bz; + dfi_driver_vif.cb_D.dfi_cs_p2 <= 1'bz; + dfi_driver_vif.cb_D.dfi_cs_p3 <= 1'bz; + dfi_driver_vif.cb_D.dfi_rddata_en_p0 <= rddata_en_queue.pop_front; + dfi_driver_vif.cb_D.dfi_rddata_en_p1 <= 1'bz; + dfi_driver_vif.cb_D.dfi_rddata_en_p2 <= 1'bz; + dfi_driver_vif.cb_D.dfi_rddata_en_p3 <= 1'bz; + //`uvm_info("DRV", $sformatf("Driver: dfi_address_p0 = %b, CS_p0 = %p \t rddata_en_p0 = %p, at %t", dfi_driver_vif.cb_D.dfi_address_p0,dfi_driver_vif.cb_D.dfi_cs_p0, dfi_driver_vif.cb_D.dfi_rddata_en_p0, $time), UVM_HIGH) + end + end + endcase + uvm_config_db#(bit)::set(null,"uvm_test_top.env1.dram_agent1.dram_driver1","reset_n",dfi_item1.reset_n_i); + uvm_config_db#(bit)::set(null,"uvm_test_top.env1.dram_agent1.dram_driver1","termination_flag",dfi_item1.termination_flag); //Send termination flag from mc_driver (got from sequence) to dram_driver to terminate dram resp_sequence + +endtask : drive_dfi + + + + +//==============================================================================// +// Task: num_of_words +// Description: This task calculates the number of cycles for read data enable +//==============================================================================// + +task mc_driver::num_of_words(); + if ((dfi_item1.CMD == MRW) && (dfi_item1.MRA == 0) && (dfi_item1.command_cancel != 1)) begin + case (dfi_item1.OP[1:0]) + 'b00 : dfi_item1.num_of_words=BL16; + 'b01 : dfi_item1.num_of_words=BC8_OTF; + 'b10 : dfi_item1.num_of_words=BL32; + default : dfi_item1.num_of_words=BL16; + endcase + end + if ((dfi_item1.rddata_en) && (dfi_item1.command_cancel != 1)) begin + if (dfi_item1.CMD == RD) begin + if (!dfi_item1.BL_mod) begin // If BL_mod is activated (Active low) >> Get BL from MR0 + case (dfi_item1.num_of_words) + //Return (0.5*BL) words (2*Device size) + BL16 : n_words = n_words + 8; + BC8_OTF : n_words = n_words + 4; + BL32 : n_words = n_words + 8; //For each read (initial read and dummy one) + default : n_words = n_words + 0; + endcase + end + else begin + n_words = n_words + 8; //Default setting BL_mod High + end + end + else if (dfi_item1.CMD == MRR) begin + n_words = n_words + 8; //Default for read and MRR + end + end +endtask + + + +//==============================================================================// +// Task: decode_cmd +// Description: This task Chooses which CMD encoding is chosen according to the +// transaction item CMD +//==============================================================================// + +task mc_driver::decode_cmd(); + case (dfi_item1.CMD) + ACT : begin + ACT_cmd(); + end + RD : begin + RD_cmd(); + end + MRW : begin + MRW_cmd(); + end + MRR : begin + MRR_cmd(); + end + DES : begin + DES_cmd(); + end + PREab:begin + PREab_CMD(); + end + default: begin + DES_cmd(); + end + endcase +endtask : decode_cmd + + +//==============================================================================// +// Task: ACT_cmd +// Description: This task performs ACT command encoding +//==============================================================================// + +task automatic mc_driver::ACT_cmd (); // ACT command_decoding + CMD0 = { + dfi_item1.CID[2:0], + dfi_item1.BG[2:0], + dfi_item1.BA[1:0], + dfi_item1.ROW[3:0], + 2'b00 + }; + CMD1 = { + dfi_item1.ROW[17:4] + }; + if(dfi_item1.command_cancel) begin + CS0 = 0; + CS1 = 0; + end + else begin + CS0 = 0; + CS1 = 1; + end +endtask : ACT_cmd + + +//==============================================================================// +// Task: RD_cmd +// Description: This task performs Read command encoding +//==============================================================================// + +task automatic mc_driver::RD_cmd (); // READ command_decoding + CMD0 = { + dfi_item1.CID[2:0], + dfi_item1.BG[2:0], + dfi_item1.BA[1:0], + dfi_item1.BL_mod, //Alternate BL mod (active low) in MR0 activation + 5'b11101 + }; + CMD1 = { + dfi_item1.CID[3], + 2'b00, + dfi_item1.AP, //Auto precHARGE Active low + 1'b0, + dfi_item1.C10, + dfi_item1.Col[9:2] + }; + if(dfi_item1.command_cancel) begin + CS0 = 0; + CS1 = 0; + end + else begin + CS0 = 0; + CS1 = 1; + end +endtask : RD_cmd + + +//==============================================================================// +// Task: MRW_cmd +// Description: This task performs MRW command encoding +//==============================================================================// + +task automatic mc_driver::MRW_cmd (); // MRW command_decoding + CMD0 = { + 1'b0, + dfi_item1.MRA[7:0], + 5'b00101 + }; + CMD1 = { + 3'b000, + dfi_item1.CW, + 2'b00, + dfi_item1.OP[7:0] + }; + if(dfi_item1.command_cancel) begin + CS0 = 0; + CS1 = 0; + end + else begin + CS0 = 0; + CS1 = 1; + end +endtask : MRW_cmd + + + +//==============================================================================// +// Task: MRR_cmd +// Description: This task performs MRR command encoding +//==============================================================================// + +task automatic mc_driver::MRR_cmd (); // MRR command_decoding + CMD0 = { + 1'b0, + dfi_item1.MRA[7:0], + 5'b10101 + }; + CMD1 = { + 3'b000, + dfi_item1.CW, + 10'b0000000000 + }; + if(dfi_item1.command_cancel) begin + CS0 = 0; + CS1 = 0; + end + else begin + CS0 = 0; + CS1 = 1; + end +endtask : MRR_cmd + + + +//==============================================================================// +// Task: DES_cmd +// Description: This task performs DES +//==============================================================================// + +task automatic mc_driver::DES_cmd (); // Deselect command_decoding + CMD0 = 'bz; + CS0 = 1; +endtask : DES_cmd + + +//==============================================================================// +// Task: PREab_CMD +// Description: This task performs precharge command encoding +//==============================================================================// + +task automatic mc_driver::PREab_CMD (); // Precharge All command_decoding + CMD0 = { + dfi_item1.CID[2:0], + 5'b00000, + dfi_item1.CID[3], + 5'b01011 + }; + CS0 = 0; +endtask : PREab_CMD + + diff --git a/testbench/components/mc_agent/mc_monitor.sv b/testbench/components/mc_agent/mc_monitor.sv new file mode 100644 index 0000000..510f7d2 --- /dev/null +++ b/testbench/components/mc_agent/mc_monitor.sv @@ -0,0 +1,456 @@ +typedef mailbox #(burst_length_t) burst_length_mbx; + +class mc_monitor extends uvm_monitor; + `uvm_component_utils(mc_monitor) + virtual dfi_intf dfi_monitor_vif; + ddr_sequence_item dfi_item1; + ddr_sequence_item dfi_item2; + uvm_analysis_port#(ddr_sequence_item) mc_analysis_port; + static bit [3:0] next_start_word = 0;//starting word number for rotation + static bit [3:0] start_word = 0; //temp variable for rotation + static int BLs_queue [$]; //a queue of read data commands' BLs + static bit is_second_cycle = 0; + static bit is_dummy_read = 0; + //static burst_length_t burst_length_queue [$]; + burst_length_mbx burst_length_mbx_inst; + //==========================================================================// + // Mode Register Variables // + //==========================================================================// + static bit [2:0] read_pre_amble = 3'b000; + static bit read_post_amble = 0; + static byte RL = 8'd22; + static burst_length_t burst_length = BL16; + static burst_length_t actual_burst_length; + static burst_length_t data_burst_length = BL16; + static int words_counter=0; + static int number_of_words =8; + static bit get_size_flag=1; + //==========================================================================// + // frequency ratio divider // + //==========================================================================// + `ifdef ratio_1_to_1 + static int freq_ratio_divider = 1; + `elsif ratio_1_to_2 + static int freq_ratio_divider = 2; + `elsif ratio_1_to_4 + static int freq_ratio_divider = 4; + `else + static int freq_ratio_divider = 1; //Default + `endif + + //====================================================================================================================================================// + // DFI_DR_13 && DFI_DR_16 - From Plan: number of dfi_rddata_en assertion clocks = number of dfi_rddata_valid assertion clocks // + //====================================================================================================================================================// + static int num_of_en [$]; + static int num_of_valid [$]; + event counted_en; + event counted_valid; + int count_valid=0, count_en=0; + + function new (string name = "mc_monitor", uvm_component parent = null); + super.new(name,parent); + endfunction + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + if(!uvm_config_db#(virtual dfi_intf)::get(this,"","dfi_vif",dfi_monitor_vif)) + `uvm_fatal(get_full_name(),"Error in getting dfi_vif from database!") + dfi_item1 = ddr_sequence_item::type_id::create("dfi_item1"); + dfi_item2 = ddr_sequence_item::type_id::create("dfi_item2"); + mc_analysis_port = new("mc_analysis_port",this); + burst_length_mbx_inst=new(); + `uvm_info("Build_Phase", "*************** 'mc_monitor' Build Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Connect Phase // + //==========================================================================// + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + `uvm_info("Connect_phase", "*************** 'mc_monitor' Connect Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + + @(posedge dfi_monitor_vif.en_i); + @(posedge dfi_monitor_vif.reset_n_i); + fork begin + forever begin + monitor_data(phase); + end + end + begin + forever begin + monitor_cmd(phase); + end + end + begin + forever begin + count_en_cycles(phase); + end + end + begin + forever begin + @(counted_en); + @(counted_valid); + $display("num_of_en = %d & num_of_valid = %d", num_of_en[0], num_of_valid[0]); + if(num_of_valid.pop_front()==num_of_en.pop_front()) + begin + //Success + end + else + begin + `uvm_error("DDR Assertions", $sformatf("dfi_rddata_valid does not match dfi_rddata_en in length") ); + end + end + end + join + endtask + + extern task monitor_data(uvm_phase phase); + extern task monitor_cmd(uvm_phase phase); + extern task monitor_phase(input [13:0] dfi_address, input dfi_cs, uvm_phase phase); + extern task count_en_cycles(uvm_phase phase); +endclass : mc_monitor + + + +//==============================================================================// +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||// +//==============================================================================// +// MC Monitor Tasks // +//==============================================================================// +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||// +//==============================================================================// + +//==============================================================================// +// Task: count en cycles +// Description: +//==============================================================================// +task mc_monitor::count_en_cycles(uvm_phase phase); + count_en=0; + @(posedge dfi_monitor_vif.dfi_rddata_en_p0 ,posedge dfi_monitor_vif.dfi_rddata_en_p1 ,posedge dfi_monitor_vif.dfi_rddata_en_p2 ,posedge dfi_monitor_vif.dfi_rddata_en_p3); + @(dfi_monitor_vif.cb_D); + while ( (dfi_monitor_vif.dfi_rddata_en_p0 || dfi_monitor_vif.dfi_rddata_en_p1 || dfi_monitor_vif.dfi_rddata_en_p2 || dfi_monitor_vif.dfi_rddata_en_p3) )//|| (dfi_monitor_vif.cb_D.dfi_rddata_en_p0 || dfi_monitor_vif.cb_D.dfi_rddata_en_p1 || dfi_monitor_vif.cb_D.dfi_rddata_en_p2 || dfi_monitor_vif.cb_D.dfi_rddata_en_p3) ) + begin + if (dfi_monitor_vif.dfi_rddata_en_p0) begin + next_start_word=1; + //Counting en Cycles + count_en = count_en+1; + $display("Inside count_en_cycles task: count_en = %d at time = %d", count_en , $time); + // + end + if (dfi_monitor_vif.dfi_rddata_en_p1) begin + next_start_word=2; + //Counting en Cycles + count_en = count_en+1; + $display("Inside count_en_cycles task: count_en = %d at time = %d", count_en , $time); + // + end + if (dfi_monitor_vif.dfi_rddata_en_p2) begin + next_start_word=3; + //Counting en Cycles + count_en = count_en+1; + $display("Inside count_en_cycles task: count_en = %d at time = %d", count_en , $time); + // + end + if (dfi_monitor_vif.dfi_rddata_en_p3) begin + next_start_word=0; + //Counting en Cycles + count_en = count_en+1; + $display("Inside count_en_cycles task: count_en = %d at time = %d", count_en , $time); + // + end + @(dfi_monitor_vif.cb_D); + end + num_of_en.push_back(count_en); + ->counted_en; +endtask + + +//==============================================================================// +// Task: monitor_data +// Description: +//==============================================================================// +task mc_monitor::monitor_data(uvm_phase phase); + dfi_item1.is_data_only = 1; + count_valid=0; + //Removed the ".cb_D." because dfi_rddata_valid_w0 acts as a trigger for the while. If cb_D is used, the first word will be missed! + @(posedge dfi_monitor_vif.dfi_rddata_valid_w0 ,posedge dfi_monitor_vif.dfi_rddata_valid_w1 ,posedge dfi_monitor_vif.dfi_rddata_valid_w2 ,posedge dfi_monitor_vif.dfi_rddata_valid_w3); + //Removed the ".cb_D." because dfi_rddata_valid_w0 acts as a trigger for the while. If cb_D is used, the first word will be missed! + //Added the ORRING of the same expression but with the cb_D to catch the last word; otherwise it will be missed + while ( (dfi_monitor_vif.dfi_rddata_valid_w0 || dfi_monitor_vif.dfi_rddata_valid_w1 || dfi_monitor_vif.dfi_rddata_valid_w2 || dfi_monitor_vif.dfi_rddata_valid_w3) || (dfi_monitor_vif.cb_D.dfi_rddata_valid_w0 || dfi_monitor_vif.cb_D.dfi_rddata_valid_w1 || dfi_monitor_vif.cb_D.dfi_rddata_valid_w2 || dfi_monitor_vif.cb_D.dfi_rddata_valid_w3) ) begin + //@(dfi_monitor_vif.cb_D); + start_word=next_start_word; + for (int i=0; i=number_of_words) begin + //$display("MONITOR: counted %p words and sent them as %p",words_counter,dfi_item1.dfi_rddata_queue); + words_counter=0; + get_size_flag=1; + phase.raise_objection(this); + `uvm_info("MON", $sformatf("Monitor_data: data = %p, at %t", dfi_item1.dfi_rddata_queue, $time), UVM_DEBUG) + mc_analysis_port.write(dfi_item1); + phase.drop_objection(this); + dfi_item1.dfi_rddata_queue = {}; + dfi_item1.is_data_only = 1; + end + end + @(dfi_monitor_vif.cb_D); + end + num_of_valid.push_back(count_valid); + ->counted_valid; +endtask + +//==============================================================================// +// Task: monitor_cmd +// Description: +//==============================================================================// +task mc_monitor::monitor_cmd(uvm_phase phase); + //note: no crc + //assumed one physical rank + + wait(dfi_monitor_vif.en_i) + wait(dfi_monitor_vif.reset_n_i) + @(posedge dfi_monitor_vif.dfi_clk); + dfi_item2.is_data_only = 0; + dfi_item2.command_cancel = 0; + case (dfi_monitor_vif.dfi_freq_ratio_i) + 2'b00 : begin + monitor_phase(dfi_monitor_vif.dfi_address_p0,dfi_monitor_vif.dfi_cs_p0,phase); + end + 2'b01 : begin + monitor_phase(dfi_monitor_vif.dfi_address_p0,dfi_monitor_vif.dfi_cs_p0,phase); + monitor_phase(dfi_monitor_vif.dfi_address_p1,dfi_monitor_vif.dfi_cs_p1,phase); + end + 2'b10 : begin + monitor_phase(dfi_monitor_vif.dfi_address_p0,dfi_monitor_vif.dfi_cs_p0,phase); + monitor_phase(dfi_monitor_vif.dfi_address_p1,dfi_monitor_vif.dfi_cs_p1,phase); + monitor_phase(dfi_monitor_vif.dfi_address_p2,dfi_monitor_vif.dfi_cs_p2,phase); + monitor_phase(dfi_monitor_vif.dfi_address_p3,dfi_monitor_vif.dfi_cs_p3,phase); + end + default: begin + monitor_phase(dfi_monitor_vif.dfi_address_p0,dfi_monitor_vif.dfi_cs_p0,phase); + end + endcase +endtask + + +//==============================================================================// +// Task: monitor_phase +// Description: +//==============================================================================// +task mc_monitor::monitor_phase(input [13:0] dfi_address, input dfi_cs, uvm_phase phase); + if (is_second_cycle) begin //second cycle + if(dfi_cs) begin //good second cycle + case (dfi_item2.CMD) + ACT: begin + dfi_item2.CID[3] = dfi_address[13]; + dfi_item2.ROW[17:4] = dfi_address[13:0]; + end + MRW: begin + dfi_item2.OP[7:0] = dfi_address[7:0]; + dfi_item2.CW = dfi_address[10]; + case (dfi_item2.MRA[7:0]) + 8'h00: begin + if (!$cast(burst_length, dfi_item2.OP[1:0])) // MR0, Burst Length + `uvm_error("mc monitor_cmd:","Cast failed") + RL = 22 + 2*dfi_item2.OP[6:2]; + dfi_item2.burst_length = burst_length; + //$display("MONITOR: mode register changed BL to %p",burst_length); + dfi_item2.RL = RL; + end + 8'h08: begin // MR8 + read_pre_amble[2:0] = dfi_item2.OP[2:0]; // Read Preamble Settings + read_post_amble = dfi_item2.OP[6]; // Read Postamble Settings + dfi_item2.read_pre_amble = read_pre_amble; + dfi_item2.read_post_amble = read_post_amble; + end + default: begin + //nothing + end + endcase + end + MRR: begin + dfi_item2.CW = dfi_address[10]; + dfi_item2.actual_burst_length = BL16; + dfi_item2.RL = RL; + dfi_item2.read_pre_amble = read_pre_amble; + dfi_item2.read_post_amble = read_post_amble; + burst_length_mbx_inst.put(dfi_item2.actual_burst_length); + //$display("MONITOR: MRR command put %p into the mbx",dfi_item2.actual_burst_length); + + end + RD: begin + if (is_dummy_read)begin + dfi_item2.CMD=DES; + is_dummy_read=0; + //$display("MONITOR: Ignored Dummy RD"); + + end + else begin + dfi_item2.Col[10:2] = dfi_address[8:0]; + dfi_item2.AP = dfi_address[10]; + dfi_item2.CID[3] = dfi_address[13]; + dfi_item2.burst_length = burst_length; + dfi_item2.actual_burst_length = dfi_item2.burst_length; + if (dfi_item2.BL_mod) dfi_item2.actual_burst_length = BL16; + dfi_item2.RL = RL; + dfi_item2.read_pre_amble = read_pre_amble; + dfi_item2.read_post_amble = read_post_amble; + burst_length_mbx_inst.put(dfi_item2.actual_burst_length); + //$display("MONITOR: RD command put %p into the mbx",dfi_item2.actual_burst_length); + //dealing with BL32 + if (dfi_item2.actual_burst_length == BL32) begin + is_dummy_read=1; + end + end + end + default: begin + //nothing + end + endcase + end + else begin //canceled second cycle + dfi_item2.command_cancel=1; + end + is_second_cycle=0; + if(dfi_item2.CMD!=DES) begin + phase.raise_objection(this); + `uvm_info("MON", $sformatf("Monitor_cmd: cmd = %p, cancelled: %b ,row= %p, CID= %p, at %t", dfi_item2.CMD, dfi_item2.command_cancel,dfi_item2.ROW,dfi_item2.CID ,$time), UVM_DEBUG) + mc_analysis_port.write(dfi_item2); + phase.drop_objection(this); + end + end + else begin //first cycle + if(!dfi_cs) begin //selected + casex(dfi_address[4:0]) + //Act: + 5'b???00: begin + dfi_item2.CMD = ACT; + dfi_item2.ROW[3:0] = dfi_address[5:2]; + dfi_item2.BA[1:0] = dfi_address[7:6]; + dfi_item2.BG[2:0] = dfi_address[10:8]; + dfi_item2.CID[2:0] = dfi_address[13:11]; + end + //MRW: + 5'b00101: begin + dfi_item2.CMD = MRW; + dfi_item2.MRA[7:0] = dfi_address[12:5]; + end + //MRR: + 5'b10101: begin + dfi_item2.CMD = MRR; + dfi_item2.MRA[7:0] = dfi_address[12:5]; + end + //RD: + 5'b11101: begin + dfi_item2.CMD = RD; + dfi_item2.BL_mod = dfi_address[5]; + dfi_item2.BA[1:0] = dfi_address[7:6]; + dfi_item2.BG[2:0] = dfi_address[10:8]; + dfi_item2.CID[2:0] = dfi_address[13:11]; + end + //NOP: + 5'b11111: begin + dfi_item2.CMD = NOP; + end + //precharge: + 5'b01011: begin + dfi_item2.CMD = PREab; + dfi_item2.CID[2:0] = dfi_address[13:11]; + dfi_item2.CID[3] = dfi_address[5]; + end + //other: + default: begin + dfi_item2.CMD = other; + end + endcase + if (dfi_address[1]) begin //one cycle + phase.raise_objection(this); + `uvm_info("MON", $sformatf("Monitor_cmd: cmd = %p, cancelled: %b ,row= %p, CID= %p, at %t", dfi_item2.CMD, dfi_item2.command_cancel,dfi_item2.ROW,dfi_item2.CID ,$time), UVM_DEBUG) + mc_analysis_port.write(dfi_item2); + phase.drop_objection(this); + end + else begin //two cycles + is_second_cycle=1; + end + end + else begin //deselect + dfi_item2.CMD = DES; + end + end +endtask diff --git a/testbench/components/mc_agent/mc_sequencer.sv b/testbench/components/mc_agent/mc_sequencer.sv new file mode 100644 index 0000000..d747ee0 --- /dev/null +++ b/testbench/components/mc_agent/mc_sequencer.sv @@ -0,0 +1,34 @@ +class mc_sequencer extends uvm_sequencer#(ddr_sequence_item); + `uvm_component_utils(mc_sequencer) + + uvm_seq_item_pull_imp#(ddr_sequence_item,ddr_sequence_item, mc_sequencer) mc_seq_item_imp; + + + function new (string name = "mc_sequencer", uvm_component parent = null); + super.new(name, parent); + endfunction + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + mc_seq_item_imp = new("mc_seq_item_imp",this); + `uvm_info("Build_Phase", "*************** 'mc_sequencer' Build Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Connect Phase // + //==========================================================================// + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + `uvm_info("Connect_phase", "*************** 'mc_sequencer' Connect Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + endtask +endclass : mc_sequencer \ No newline at end of file diff --git a/testbench/components/ref_model.sv b/testbench/components/ref_model.sv new file mode 100644 index 0000000..aa85012 --- /dev/null +++ b/testbench/components/ref_model.sv @@ -0,0 +1,137 @@ + + +class ref_model extends uvm_component; + `uvm_component_utils(ref_model) + + //**********TLM -- Revieving the DFI & JEDEC items from the analysis ports of MC and DRAM agents. + uvm_analysis_imp_port_mc #(ddr_sequence_item, ref_model) mc_analysis_imp; + uvm_analysis_imp_port_dram #(ddr_sequence_item, ref_model) dram_analysis_imp; + + //**********TLM -- Broadcasting the result of the model + uvm_analysis_port#(ddr_sequence_item) dfi_REF_analysis_port; + uvm_analysis_port#(ddr_sequence_item) jedec_REF_analysis_port; + + //**********Two internal items to copy the incoming items in them + ddr_sequence_item dfi_item, dfi_item_to_scbd; //Copy incoming item in dfi_item, while dfi_item_to_scbd is used to send a "processed jedec item" to the scbd. + ddr_sequence_item jedec_item, jedec_item_to_scbd; + + //**************An event to make sure the items are copied before the "run phase" operates on the items + //event recieved_dfi_item; + static int recieved_dfi_item_flag=0; + static int recieved_jedec_item_flag=0; + + //*************Constructor + function new (string name = "ref_model", uvm_component parent = null); + super.new(name,parent); + endfunction : new + + //****************Build Phase + function void build_phase (uvm_phase phase); + super.build_phase(phase); + jedec_item_to_scbd = ddr_sequence_item::type_id::create("jedec_item_to_scbd"); + dfi_item_to_scbd = ddr_sequence_item::type_id::create("dfi_item_to_scbd"); + mc_analysis_imp = new("mc_analysis_imp",this); + dram_analysis_imp = new("dram_analysis_imp",this); + dfi_REF_analysis_port = new("dfi_REF_analysis_port",this); + jedec_REF_analysis_port = new("jedec_REF_analysis_port",this); + `uvm_info("Build_Phase", "*************** 'ref_model' Build Phase ***************", UVM_HIGH) + endfunction : build_phase + + //****************Connect Phase + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + `uvm_info("Connect_phase", "*************** 'ref_model' Connect Phase ***************", UVM_HIGH) + endfunction : connect_phase + + //*****************Run Phase + task run_phase(uvm_phase phase); + super.run_phase(phase); + /*forever + begin + //***********Operate on the items - thread for each item (just in case they come simultaneously) + if(recieved_dfi_item_flag) + begin + process_dfi_item(dfi_item); + recieved_dfi_item_flag =0; //Deactivate the if statement until the write function is called again; i.e., new incoming transaction arrives + jedec_REF_analysis_port.write(jedec_item_to_scbd); + $display("LOL 0"); + end + $display("LOL 1"); + if(recieved_jedec_item_flag) + begin + $display("LOL 0"); + process_jedec_item(jedec_item); + recieved_jedec_item_flag=0; //Deactivate the if statement until the write function is called again; i.e., new incoming transaction arrives + dfi_REF_analysis_port.write(dfi_item_to_scbd); + end + end */ + endtask : run_phase + + //***************Write implementations -- copy the incoming items in the internal items to be processed + function void write_port_mc (ddr_sequence_item item); //write implementation for the mc port + $display("REF is Processing a DFI Item"); + dfi_item = ddr_sequence_item::type_id::create("dfi_item", this); + dfi_item.copy(item); + //-> recieved_dfi_item; + //recieved_dfi_item_flag=1; + process_dfi_item(dfi_item); + //recieved_dfi_item_flag =0; //Deactivate the if statement until the write function is called again; i.e., new incoming transaction arrives + jedec_REF_analysis_port.write(jedec_item_to_scbd); + endfunction : write_port_mc + + function void write_port_dram (ddr_sequence_item item); //write implementation for the dram port + //$display("REF is Processing a JEDEC Item"); + jedec_item = ddr_sequence_item::type_id::create("jedec_item", this); + jedec_item.copy(item); + //-> recieved_jedec_item; + //recieved_jedec_item_flag=1; + process_jedec_item(jedec_item); + //recieved_jedec_item_flag=0; //Deactivate the if statement until the write function is called again; i.e., new incoming transaction arrives + dfi_REF_analysis_port.write(dfi_item_to_scbd); + $display("Sending From REF to Scoreboard FIFO"); + endfunction : write_port_dram + + //***************Functions to process the seq items + function void process_dfi_item(ddr_sequence_item dfi_item1); + case (dfi_item1.CMD) + dfi_item1.ACT : begin + dfi_address_2_CA(); + end + dfi_item1.RD : begin + dfi_address_2_CA(); + end + dfi_item1.MRW : begin + dfi_address_2_CA(); + end + dfi_item1.MRR : begin + dfi_address_2_CA(); + end + dfi_item1.DES : begin + dfi_address_2_CA(); + end + default: begin + //NOTHING + end + endcase + endfunction : process_dfi_item + + function void dfi_address_2_CA(); + //jedec_item_to_scbd.CMD = dfi_item.CMD; + jedec_item_to_scbd.BA = dfi_item.BA; + jedec_item_to_scbd.BG = dfi_item.BG; + jedec_item_to_scbd.CID = dfi_item.CID; + jedec_item_to_scbd.ROW = dfi_item.ROW; + jedec_item_to_scbd.Col = dfi_item.Col; + jedec_item_to_scbd.AP = dfi_item.AP; + jedec_item_to_scbd.BL_mod = dfi_item.BL_mod; + jedec_item_to_scbd.MRA = dfi_item.MRA; + jedec_item_to_scbd.OP = dfi_item.OP; + jedec_item_to_scbd.CW = dfi_item.CW; + jedec_item_to_scbd.command_cancel = dfi_item.command_cancel; + endfunction : dfi_address_2_CA + + function void process_jedec_item(ddr_sequence_item jedec_item); + dfi_item_to_scbd.dfi_rddata_queue = jedec_item.jedec_rddata_queue; + endfunction : process_jedec_item + +endclass : ref_model \ No newline at end of file diff --git a/testbench/components/scoreboard.sv b/testbench/components/scoreboard.sv new file mode 100644 index 0000000..670a96a --- /dev/null +++ b/testbench/components/scoreboard.sv @@ -0,0 +1,240 @@ +class scoreboard extends uvm_scoreboard; + `uvm_component_utils(scoreboard) + parameter device_width = 4; + //==========================================================================// + // Analysis imps // + //==========================================================================// + uvm_analysis_imp_port_mc #(ddr_sequence_item, scoreboard) dfi_analysis_imp; //Connect to dfi_analysis from DUT + uvm_analysis_imp_port_dram #(ddr_sequence_item, scoreboard) jedec_analysis_imp; //Connect to jedec_analysis from DUT + + + ddr_sequence_item jedec_item_DUT, jedec_item_REF; + ddr_sequence_item dfi_item_DUT, dfi_item_REF; + // + ddr_sequence_item dfi_sequence_item_handle, jedec_sequence_item_handle; + + //Syncronization events + event got_dfi_stimulus, got_dfi_response, got_jedec_stimulus, got_jedec_response; + + //==========================================================================// + // Queues to fill before comparison // + //==========================================================================// + static ddr_sequence_item jedec_stimulus_q [$]; // to store jedec data + static ddr_sequence_item jedec_response_q [$]; // to store jedec commands + static ddr_sequence_item dfi_stimulus_q [$]; // to store dfi commands + static ddr_sequence_item dfi_response_q [$]; // to store dfi data + /* + //Using queues of logic to mitigate runtime misbehaviour (different functions can't pass a queue that's inside a transaction) + static logic [2*device_width-1:0] dfi_response_q [$][$]; + static logic [2*device_width-1:0] jedec_stimulus_q [$][$]; + */ + + //==========================================================================// + // Constructor // + //==========================================================================// + function new (string name = "scoreboard", uvm_component parent = null); + super.new(name,parent); + endfunction : new + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + dfi_analysis_imp = new("dfi_analysis_imp", this); + jedec_analysis_imp = new("jedec_analysis_imp", this); + jedec_item_DUT = ddr_sequence_item::type_id::create("jedec_item_DUT"); + jedec_item_REF = ddr_sequence_item::type_id::create("jedec_item_REF"); + dfi_item_DUT = ddr_sequence_item::type_id::create("dfi_item_DUT"); + dfi_item_REF = ddr_sequence_item::type_id::create("dfi_item_REF"); + `uvm_info("Build_Phase", "*************** 'scoreboard' Build Phase ***************", UVM_HIGH) + endfunction : build_phase + + //==========================================================================// + // Connect Phase // + //==========================================================================// + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + `uvm_info("Connect_phase", "*************** 'scoreboard' Connect Phase ***************", UVM_HIGH) + endfunction : connect_phase + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + fork + begin + forever begin + fork + @(got_jedec_stimulus); + @(got_dfi_response); // MC Received read data, comes after got_jedec_stimulus.triggered + join + `uvm_info(" Inside run_phase ", $sformatf("** Before calling compare_dfi() **\ndfi_response_q[0]: %s\njedec_stimulus_q[0]: %s",dfi_response_q[0].convert2string(), jedec_stimulus_q[0].convert2string() ), UVM_DEBUG); + compare_dfi(); // to compare DATA + end + end + begin + forever begin + @(got_dfi_stimulus); + @(got_jedec_response); //DRAM Recieved command, comes after got_dfi_stimulus.triggered + `uvm_info(" Inside run_phase ", $sformatf("** Before calling compare_jedec() **\njedec_response_q[0]: %s\ndfi_stimulus_q[0]: %s",jedec_response_q[0].convert2string(), dfi_stimulus_q[0].convert2string() ), UVM_DEBUG); + compare_jedec(); // to compare commands + end + end + join + endtask : run_phase + + + //==========================================================================// + // Write functions // + //==========================================================================// + function void write_port_dram (ddr_sequence_item item); + jedec_sequence_item_handle = ddr_sequence_item::type_id::create("jedec_sequence_item_handle"); + jedec_sequence_item_handle.copy(item); + if(jedec_sequence_item_handle.is_data_only) begin + jedec_stimulus_q.push_back(jedec_sequence_item_handle); + `uvm_info(" Inside write_port_dram() ", $sformatf("** Scoreboard Received JEDEC Stimulus (data) **\jedec_sequence_item_handle: %s",jedec_sequence_item_handle.convert2string()), UVM_DEBUG); + ->got_jedec_stimulus; + end + else begin + jedec_response_q.push_back(jedec_sequence_item_handle); + `uvm_info(" Inside write_port_dram() ", $sformatf("** Scoreboard Received JEDEC Response (command) **\jedec_sequence_item_handle: %s",jedec_sequence_item_handle.convert2string()), UVM_DEBUG); + ->got_jedec_response; + end + endfunction : write_port_dram + + function void write_port_mc (ddr_sequence_item item); + dfi_sequence_item_handle = ddr_sequence_item::type_id::create("dfi_sequence_item_handle"); + dfi_sequence_item_handle.copy(item); + if(dfi_sequence_item_handle.is_data_only) begin + dfi_response_q.push_back(dfi_sequence_item_handle); + `uvm_info(" Inside write_port_mc()", $sformatf("** Scoreboard Received DFI Response (data) **\dfi_sequence_item_handle: %s", dfi_sequence_item_handle.convert2string()), UVM_DEBUG); + ->got_dfi_response; + end + else begin + dfi_stimulus_q.push_back(dfi_sequence_item_handle); + `uvm_info(" Inside write_port_mc()", $sformatf("** Scoreboard Received DFI Stimulus (command) **\dfi_sequence_item_handle: %s",dfi_sequence_item_handle.convert2string()), UVM_DEBUG); + ->got_dfi_stimulus; + end + endfunction : write_port_mc + + + //==========================================================================// + // Comparison functions // + //==========================================================================// + function void compare_jedec(); + bit correct; + ddr_sequence_item dfi_item; //To store the command item, then send it to REF + dfi_item = ddr_sequence_item::type_id::create("dfi_item"); + //Get command transction from command queue and pass it to REF model methods + dfi_item = dfi_stimulus_q.pop_front(); + jedec_item_REF = process_dfi_item(dfi_item); + //Get DUT response transction from response queue + jedec_item_DUT = jedec_response_q.pop_front(); + //Comparing + correct = (jedec_item_REF.CMD == jedec_item_DUT.CMD ) & + (jedec_item_REF.BA == jedec_item_DUT.BA ) & + (jedec_item_REF.BG == jedec_item_DUT.BG ) & + (jedec_item_REF.CID == jedec_item_DUT.CID ) & + (jedec_item_REF.ROW == jedec_item_DUT.ROW ) & + (jedec_item_REF.Col == jedec_item_DUT.Col ) & + (jedec_item_REF.AP == jedec_item_DUT.AP ) & + (jedec_item_REF.BL_mod == jedec_item_DUT.BL_mod ) & + (jedec_item_REF.MRA == jedec_item_DUT.MRA ) & + (jedec_item_REF.OP == jedec_item_DUT.OP ) & + (jedec_item_REF.CW == jedec_item_DUT.CW ) & + (jedec_item_REF.command_cancel == jedec_item_DUT.command_cancel ); + if(correct) + begin + `uvm_info("Compare_JEDEC", $sformatf("** Test: Ok! **\n\nEXPECTED: %s\nRECEIVED: %s\n", jedec_item_REF.convert2string_Compact(), jedec_item_DUT.convert2string_Compact()), UVM_LOW); + end + else + begin + `uvm_error("Compare_JEDEC", $sformatf("** Test: Fail! **\n\nEXPECTED: %s\nRECEIVED: %s\n", jedec_item_REF.convert2string_Compact(), jedec_item_DUT.convert2string_Compact())); + end + endfunction : compare_jedec + + function void compare_dfi(); + ddr_sequence_item jedec_item; //To store the response item, then send it to REF + jedec_item = ddr_sequence_item::type_id::create("jedec_item"); + //Get command transction from command queue and pass it to REF model methods + jedec_item = jedec_stimulus_q.pop_front(); + dfi_item_REF = process_jedec_item(jedec_item); + //Get DUT response transction from response queue + dfi_item_DUT = dfi_response_q.pop_front(); + //Comparing + if(dfi_item_DUT.dfi_rddata_queue == dfi_item_REF.dfi_rddata_queue) + begin + `uvm_info("Compare_DFI", $sformatf("** Test: Ok! **\n\nEXPECTED: %s\nRECEIVED: %s\n", dfi_item_REF.convert2string_Compact(), dfi_item_DUT.convert2string_Compact()), UVM_LOW); + end + else + begin + `uvm_error("Compare_DFI", $sformatf("** Test: Fail! **\n\nEXPECTED: %s\nRECEIVED: %s\n", dfi_item_REF.convert2string_Compact(), dfi_item_DUT.convert2string_Compact()) ); + end + endfunction : compare_dfi + + + //==========================================================================// + // REF model Functions // + //==========================================================================// + function ddr_sequence_item process_dfi_item(ddr_sequence_item dfi_item); + ddr_sequence_item jedec_item; + jedec_item = ddr_sequence_item::type_id::create("jedec_item"); + case (dfi_item.CMD) + ACT : begin + dfi_address_2_CA(dfi_item, jedec_item); + end + RD : begin + dfi_address_2_CA(dfi_item, jedec_item); + end + MRW : begin + dfi_address_2_CA(dfi_item, jedec_item); + end + MRR : begin + dfi_address_2_CA(dfi_item, jedec_item); + end + DES : begin + dfi_address_2_CA(dfi_item, jedec_item); + end + PREab: begin + dfi_address_2_CA(dfi_item, jedec_item); + end + default: begin + //NOTHING + end + endcase + return jedec_item; + endfunction : process_dfi_item + + function void dfi_address_2_CA(ddr_sequence_item dfi_item, ref ddr_sequence_item jedec_item); + int tmp; //To avoid compile error + tmp = int'(dfi_item.CMD); //To avoid compile error + assert($cast(jedec_item.CMD, dfi_item.CMD)) + else `uvm_error("REF Model: dfi_address_2_CA",$sformatf(" FAILED to Cast dfi_item.CMD to jedec_item.CMD")); + jedec_item.BA = dfi_item.BA; + jedec_item.BG = dfi_item.BG; + jedec_item.CID = dfi_item.CID; + jedec_item.ROW = dfi_item.ROW; + jedec_item.Col = dfi_item.Col; + jedec_item.AP = dfi_item.AP; + jedec_item.BL_mod = dfi_item.BL_mod; + jedec_item.MRA = dfi_item.MRA; + jedec_item.OP = dfi_item.OP; + jedec_item.CW = dfi_item.CW; + jedec_item.command_cancel = dfi_item.command_cancel; + jedec_item.burst_length = dfi_item.burst_length; + jedec_item.actual_burst_length = dfi_item.actual_burst_length; + jedec_item.RL = dfi_item.RL; + jedec_item.read_pre_amble = dfi_item.read_pre_amble; + jedec_item.read_post_amble = dfi_item.read_post_amble; + endfunction : dfi_address_2_CA + + function ddr_sequence_item process_jedec_item(ddr_sequence_item jedec_item); + ddr_sequence_item dfi_item; + dfi_item = ddr_sequence_item::type_id::create("dfi_item"); + dfi_item.dfi_rddata_queue = jedec_item.jedec_rddata_queue; + dfi_item.is_data_only = 1; + return dfi_item; + endfunction : process_jedec_item +endclass : scoreboard diff --git a/testbench/components/subscriber.sv b/testbench/components/subscriber.sv new file mode 100644 index 0000000..0488bea --- /dev/null +++ b/testbench/components/subscriber.sv @@ -0,0 +1,515 @@ + +class subscriber extends uvm_subscriber#(ddr_sequence_item); + `uvm_component_utils(subscriber) + + uvm_analysis_imp_port_mc #(ddr_sequence_item, subscriber) mc_analysis_imp; + uvm_analysis_imp_port_dram #(ddr_sequence_item, subscriber) dram_analysis_imp; + ddr_sequence_item dfi_sequence_item_coverage; + ddr_sequence_item jedec_sequence_item_coverage; + ddr_sequence_item dfi_sequence_item_handle; + ddr_sequence_item jedec_sequence_item_handle; + ddr_sequence_item jedec_complete_sequence_item; + ddr_sequence_item dfi_complete_sequence_item; + + //Syncronization events for receiving a complete transaction (CMD + data) + event dfi_transaction_complete, jedec_transaction_complete; + //==========================================================================// + // Queues to fill before sampling // + //==========================================================================// + static ddr_sequence_item jedec_completeItem_q [$]; + static ddr_sequence_item jedec_commandThread_q [$]; + static ddr_sequence_item dfi_commandThread_q [$]; + static ddr_sequence_item dfi_completeItem_q [$]; + //==========================================================================// + // The number of data cycles of the previous read command // + //==========================================================================// + static int number_of_data_cycles_of_previous_read; // with respect to the sampling event + static bit first_RD_flag = 1; + + //======================================================================================================// + // START of covergroup definitions // + //======================================================================================================// + //==========================================================================// + // JEDEC Coverage // + //==========================================================================// + + covergroup JEDEC_coverage; + type_option.comment = "Coverage model for the JEDEC features"; + //=================================================================================// + // Creating coverpoints that will be used to construct the required cross cross // + // (these coverpoints do NOT contribute to the total coverage calculations) // + //=================================================================================// + CMD_cp: coverpoint jedec_sequence_item_coverage.CMD { + type_option.weight = 0; // only sampled to be used in the cross statement + bins MRR = {MRR}; + bins MRW = {MRW}; + bins ACT = {ACT}; + bins RD = {RD}; + } + MRA_cp: coverpoint jedec_sequence_item_coverage.MRA { + type_option.weight = 0; // only sampled to be used in the cross statement + bins MR0 = {8'h00}; // Burst Length & CAS Latency (RL) + bins MR8 = {8'h08}; // Read pre- and post- amble Settings + // CRC MR is not used because it is not supported in the current design + } + actual_burst_length_cp: coverpoint jedec_sequence_item_coverage.actual_burst_length { + type_option.weight = 0; // only sampled to be used in the cross statement + // 3 bins are created automatically with the following values: BL16, BC8_OTF, BL32 + } + burst_length_cp: coverpoint jedec_sequence_item_coverage.burst_length { + type_option.weight = 0; // only sampled to be used in the cross statement + // 3 bins are created automatically with the following values: BL16, BC8_OTF, BL32 + } + read_pre_amble_cp: coverpoint jedec_sequence_item_coverage.read_pre_amble { + type_option.weight = 0; // only sampled to be used in the cross statement + bins read_pre_amble_Val [] = {[3'b000:3'b100]}; // 5 seperate bins are created + } + read_post_amble_cp: coverpoint jedec_sequence_item_coverage.read_post_amble { + type_option.weight = 0; // only sampled to be used in the cross statement + // 2 bins are created automatically + } + command_cancel_cp: coverpoint jedec_sequence_item_coverage.command_cancel{ + type_option.weight = 0; // only sampled to be used in the cross statement + // 2 bins are created automatically + bins no_cancel = {0}; + bins cancel = {1}; + } + OP_BL_cp: coverpoint jedec_sequence_item_coverage.OP[1:0] { + type_option.weight = 0; // only sampled to be used in the cross statement + // 4 bins are created automatically with the following values: + // 'b00: BL16, 'b01: BC8_OTF, 'b10: BL32 + ignore_bins exclude_BL32_OTF = {3}; + } + OP_read_pre_amble_cp: coverpoint jedec_sequence_item_coverage.OP[2:0] { + type_option.weight = 0; // only sampled to be used in the cross statement + bins read_pre_amble_Val [] = {[3'b000:3'b100]}; // 5 seperate bins are created + } + OP_read_post_amble_cp: coverpoint jedec_sequence_item_coverage.OP[6] { + type_option.weight = 0; // only sampled to be used in the cross statement + // 2 bins are created automatically + } + interamble_cp: coverpoint jedec_sequence_item_coverage.number_of_cycles_between_RD - number_of_data_cycles_of_previous_read { + type_option.weight = 0; // only sampled to be used in the cross statement + bins tCCD_min = {0}; + bins tCCD_minPlusOne = {1}; + bins tCCD_minPlusTwo = {2}; + bins tCCD_minPlusThree = {3}; + bins tCCD_minPlusFour = {4}; + bins tCCD_minPlusFive = {5}; + } + + //=================================================================================// + // JEDEC_DR_4: The MRR has a command burst length 16 regardless of the MR0 setting // + //=================================================================================// + JEDEC_DR_4_cross: cross CMD_cp, actual_burst_length_cp, burst_length_cp { + type_option.comment = "Coverage model for features JEDEC_DR_4"; + // included bins: binsof(CMD_cp.MRR) with (actual_burst_length_cp == BL16) + illegal_bins ill = binsof(CMD_cp.MRR) with (actual_burst_length_cp != BL16); // illegal_bins have higher priority than ignored_bins + ignore_bins excluded_JEDEC_DR_4_bins = !binsof(CMD_cp.MRR); + } + + //=================================================================================// + // JEDEC_DR_6: The read pre-amble and post-amble of MRR are same as normal read // + //=================================================================================// + JEDEC_DR_6_part1_cross: cross CMD_cp, read_pre_amble_cp { // could be: cross CMD_cp, read_pre_amble_cp, read_post_amble_cp; to accommodate for all pre and post combinations + type_option.comment = "Coverage model for features JEDEC_DR_6_part1"; + ignore_bins excluded_JEDEC_DR_6_part1_bins = ! binsof(CMD_cp.MRR); + } + JEDEC_DR_6_part2_cross: cross CMD_cp, read_post_amble_cp { + type_option.comment = "Coverage model for features JEDEC_DR_6_part2"; + ignore_bins excluded_JEDEC_DR_6_part2_bins = ! binsof(CMD_cp.MRR); + } + + //=================================================================================// + // JEDEC_DR_18: The DRAM will not execute these 2-cycle commands if the CS_n is // + // LOW on the 2nd cycle (command cancel). // + //=================================================================================// + JEDEC_DR_18_cross: cross CMD_cp, command_cancel_cp { + type_option.comment = "Coverage model for features JEDEC_DR_18"; + // included bins: binsof(CMD_cp.MRW) || binsof(CMD_cp.ACT) + ignore_bins excluded_JEDEC_DR_18_bins = !binsof(CMD_cp.MRW) && !binsof(CMD_cp.ACT); + } + //=======================================================================================// + // JEDEC_DR_25_and_26: In Read to Read operations with tCCD=BL/2, postamble for 1st // + // command and preamble for 2nd command shall disappear to create // + // consecutive DQS latching edge for seamless burst operations. // + // In the case of Read to Read operations with command interval of // + // tCCD+1, tCCD+2, etc., if the postamble and preambles overlap, // + // the toggles take precedence over static preambles. // + //=======================================================================================// + JEDEC_DR_25_and_26_cross: cross interamble_cp, OP_read_pre_amble_cp, OP_read_post_amble_cp iff ( (jedec_sequence_item_coverage.CMD == RD) && (first_RD_flag == 0) ) { + // (first_RD_flag == 0) is used for the corner case of the first RD command + type_option.comment = "Coverage model for features JEDEC_DR_25_and_26"; + } + + // the following features cover that: + // Part (1): all mode registers have been written into and read from using all possible values (Using MRW and MRR commands). + // Part (2): all these values of the mode registers have been used by using RD command. + + // Part (1) + //=================================================================================// + // JEDEC_DR_8: MRW and MRR to all supported MRA // + //=================================================================================// + JEDEC_DR_8_cross: cross MRA_cp, CMD_cp iff (!jedec_sequence_item_coverage.command_cancel) { + type_option.comment = "Coverage model for features JEDEC_DR_8"; + // included bins: binsof(CMD_cp.MRW) || binsof(CMD_cp.MRR) + ignore_bins excluded_JEDEC_DR_8_bins = !binsof(CMD_cp.MRW) && !binsof(CMD_cp.MRR); + } + + //=======================================================================================// + // JEDEC_DR_14: all burst length values are written and read from the mode register // + //=======================================================================================// + JEDEC_DR_14_cross: cross MRA_cp, OP_BL_cp, CMD_cp iff (!jedec_sequence_item_coverage.command_cancel) { + type_option.comment = "Coverage model for features JEDEC_DR_14"; + // included bins: (binsof(CMD_cp.MRW) || binsof(CMD_cp.MRR)) && binsof(MRA_cp.MR0) + ignore_bins excluded_JEDEC_DR_14_bins = (!binsof(CMD_cp.MRW) && !binsof(CMD_cp.MRR)) || !binsof(MRA_cp.MR0) ; + } + + //===============================================================================================// + // JEDEC_DR_15: all pre- and post- amble values are written and read from the mode register // + //===============================================================================================// + JEDEC_DR_15_part1_cross: cross MRA_cp, OP_read_pre_amble_cp, CMD_cp iff (!jedec_sequence_item_coverage.command_cancel) { + type_option.comment = "Coverage model for features JEDEC_DR_15_part1"; + // included bins: (binsof(CMD_cp.MRW) || binsof(CMD_cp.MRR)) && binsof(MRA_cp.MR8) + ignore_bins excluded_JEDEC_DR_15_part1_bins = (!binsof(CMD_cp.MRW) && !binsof(CMD_cp.MRR)) || !binsof(MRA_cp.MR8) ; + } + JEDEC_DR_15_part2_cross: cross MRA_cp, OP_read_post_amble_cp, CMD_cp iff (!jedec_sequence_item_coverage.command_cancel) { + type_option.comment = "Coverage model for features JEDEC_DR_15_part2"; + // included bins: (binsof(CMD_cp.MRW) || binsof(CMD_cp.MRR)) && binsof(MRA_cp.MR8) + ignore_bins excluded_JEDEC_DR_15_part2_bins = (!binsof(CMD_cp.MRW) && !binsof(CMD_cp.MRR)) || !binsof(MRA_cp.MR8) ; + } + + // Part (2) + //=================================================================================// + // JEDEC_DR_31: when BL_mod != 1, DDR5 shall support BC8, BL16, BL32 (optional) // + // and BL32 OTF (optional) during a READ or WRITE command. // + // MR0[1:0] is used to select burst operation mode. // + //=================================================================================// + JEDEC_DR_31_cross: cross CMD_cp, actual_burst_length_cp { + type_option.comment = "Coverage model for features JEDEC_DR_31"; + // included bins: binsof(CMD_cp.RD) + ignore_bins excluded_JEDEC_DR_31_bins = ! binsof(CMD_cp.RD); + } + + //=================================================================================// + // JEDEC_DR_32: In non-CRC mode, DQS_t and DQS_c stop toggling at the completion // + // of the BC8 data bursts, plus the postamble. // + //=================================================================================// + JEDEC_DR_32_part1_cross: cross CMD_cp, read_pre_amble_cp { + type_option.comment = "Coverage model for features JEDEC_DR_32_part1"; + // included bins: binsof(CMD_cp.RD) + ignore_bins excluded_JEDEC_DR_32_part1_bins = ! binsof(CMD_cp.RD); + } + JEDEC_DR_32_part2_cross: cross CMD_cp, read_post_amble_cp { + type_option.comment = "Coverage model for features JEDEC_DR_32_part2"; + // included bins: binsof(CMD_cp.RD) + ignore_bins excluded_JEDEC_DR_32_part2_bins = ! binsof(CMD_cp.RD); + } + + endgroup: JEDEC_coverage + + covergroup JEDEC_transitions; + //=================================================================================// + // JEDEC_DR_7_and_10 // + //=================================================================================// + JEDEC_DR_7_and_10_cp: coverpoint jedec_sequence_item_coverage.CMD { // note this coverpoint has a weight in the total coverage calculations + type_option.comment = "Coverage model for features JEDEC_DR_7_and_10"; + // JEDEC_DR_7 + bins JEDEC_DR_7 = (MRR => MRR => MRW), + (MRR => MRR => ACT); + // JEDEC_DR_10 + bins JEDEC_DR_10 = (MRW => MRW => MRR), + (MRW => MRW => ACT); + // these bins are hit for the following sequences (with no command cancel in the sequence): + // MRR => DES [indefinite repetition] => MRR => DES [indefinite repetition] => MRW + // MRR => DES [indefinite repetition] => MRR => DES [indefinite repetition] => ACT + // MRW => DES [indefinite repetition] => MRW => DES [indefinite repetition] => MRR + // MRW => DES [indefinite repetition] => MRW => DES [indefinite repetition] => ACT + // why is there indefinite repetition for DES command? because the monitors do not send the DES command transaction. + } + + endgroup : JEDEC_transitions + + //==========================================================================// + // DFI Coverage // + //==========================================================================// + + covergroup DFI_coverage; + type_option.comment = "Coverage model for the DFI features"; + //=================================================================================// + // Creating coverpoints that will be used to construct the required cross cross // + // (these coverpoints do NOT contribute to the total coverage calculations) // + //=================================================================================// + CMD_cp: coverpoint dfi_sequence_item_coverage.CMD { + type_option.weight = 0; // only sampled to be used in the cross statement + bins MRW = {MRW}; + bins MRR = {MRR}; + bins ACT = {ACT}; + bins RD = {RD}; + } + command_cancel_cp: coverpoint dfi_sequence_item_coverage.command_cancel{ + type_option.weight = 0; // only sampled to be used in the cross statement + } + MRA_cp: coverpoint dfi_sequence_item_coverage.MRA { + type_option.weight = 0; // only sampled to be used in the cross statement + bins MR0 = {8'h00}; // Burst Length & CAS Latency (RL) + bins MR8 = {8'h08}; // Read pre- and post- amble Settings + // CRC MR is not used because it is not supported in the current design + } + CW_cp: coverpoint dfi_sequence_item_coverage.CW { + type_option.weight = 0; // only sampled to be used in the cross statement + // 2 bins are created automatically + } + AP_cp: coverpoint dfi_sequence_item_coverage.AP { + type_option.weight = 0; // only sampled to be used in the cross statement + } + BL_mod_cp: coverpoint dfi_sequence_item_coverage.BL_mod { + type_option.weight = 0; // only sampled to be used in the cross statement + } + BA_cp: coverpoint dfi_sequence_item_coverage.BA { + type_option.weight = 0; // only sampled to be used in the cross statement + bins BA [] = {0, 2**2-1}; // first and last bank address + } + BG_cp: coverpoint dfi_sequence_item_coverage.BG { + type_option.weight = 0; // only sampled to be used in the cross statement + bins BG [] = {0, 2**3-1}; // first and last bank group + } + CID_cp: coverpoint dfi_sequence_item_coverage.CID { + type_option.weight = 0; // only sampled to be used in the cross statement + bins CID [] = {0, 2**4-1}; // first and last CID + } + ROW_cp: coverpoint dfi_sequence_item_coverage.ROW { + type_option.weight = 0; // only sampled to be used in the cross statement + bins rows [] = {0, 2**18-1}; // first and last row + } + Col_cp: coverpoint dfi_sequence_item_coverage.Col { + type_option.weight = 0; // only sampled to be used in the cross statement + bins columns [] = {0, 2**9-1}; // first and last columns + } + + //===============================================================================================// + // two_cycle_command_cancel feature // + //===============================================================================================// + two_cycle_command_cancel_cross: cross CMD_cp, command_cancel_cp{ + type_option.comment = "Coverage model for two_cycle_command_cancel feature"; + // included bins: binsof(CMD_cp.MRW) || binsof(CMD_cp.ACT) + ignore_bins two_cycle_command_cancel_bins = !binsof(CMD_cp.MRW) && !binsof(CMD_cp.ACT); + } + + //===============================================================================================// + // All supported mode registers are written into and read from using MRW and MRR // + //===============================================================================================// + mode_register_cross: cross MRA_cp, CW_cp, CMD_cp iff (!dfi_sequence_item_coverage.command_cancel) { + type_option.comment = "Coverage model for MRW & MRR to all supported mode registers"; + // included bins: binsof(CMD_cp.MRW) || binsof(CMD_cp.MRR) + ignore_bins excluded_mode_register_bins = !binsof(CMD_cp.MRW) && !binsof(CMD_cp.MRR); + } + + //===============================================================================================// + // Automatic precharge after RD feature // + //===============================================================================================// + AP_cross: cross CMD_cp, AP_cp { + type_option.comment = "Coverage model for Automatic precharge feature"; + // included bins: binsof(CMD_cp.RD) + ignore_bins excluded_AP_bins = ! binsof(CMD_cp.RD); + } + + //===============================================================================================// + // BL_mod of RD feature // + //===============================================================================================// + BL_mod_cross: cross CMD_cp, BL_mod_cp { + type_option.comment = "Coverage model for BL_mod of RD feature"; + // included bins: binsof(CMD_cp.RD) + ignore_bins excluded_BL_mod_bins = ! binsof(CMD_cp.RD); + } + + //===============================================================================================// + // Address corners // + //===============================================================================================// + BA_cross: cross BA_cp, CMD_cp iff (!dfi_sequence_item_coverage.command_cancel) { + type_option.comment = "Coverage model for BA corners"; + // included bins: binsof(CMD_cp.ACT) || binsof(CMD_cp.RD) + ignore_bins excluded_BA_bins = !binsof(CMD_cp.ACT) && !binsof(CMD_cp.RD); + } + BG_cross: cross BG_cp, CMD_cp iff (!dfi_sequence_item_coverage.command_cancel) { + type_option.comment = "Coverage model for BG corners"; + // included bins: binsof(CMD_cp.ACT) || binsof(CMD_cp.RD) + ignore_bins excluded_BG_bins = !binsof(CMD_cp.ACT) && !binsof(CMD_cp.RD); + } + CID_cross: cross CID_cp, CMD_cp iff (!dfi_sequence_item_coverage.command_cancel) { + type_option.comment = "Coverage model for CID corners"; + // included bins: binsof(CMD_cp.ACT) || binsof(CMD_cp.RD) + ignore_bins excluded_CID_bins = !binsof(CMD_cp.ACT) && !binsof(CMD_cp.RD); + } + ROW_cross: cross ROW_cp, CMD_cp iff (!dfi_sequence_item_coverage.command_cancel) { + type_option.comment = "Coverage model for ROW corners"; + // included bins: binsof(CMD_cp.ACT) + ignore_bins excluded_ROW_bins = ! binsof(CMD_cp.ACT); + } + Col_cross: cross CMD_cp, Col_cp { + type_option.comment = "Coverage model for Col corners"; + // included bins: binsof(CMD_cp.RD) + ignore_bins excluded_Col_bins = ! binsof(CMD_cp.RD); + } + + endgroup : DFI_coverage + + covergroup DFI_transitions; + CMD_cp: coverpoint dfi_sequence_item_coverage.CMD { + bins sequence1 = (ACT => RD); + // this bin is hit for the following sequence: + // ACT => DES [indefinite repetition] => RD + // why is there indefinite repetition for DES command? because the monitors do not send the DES command transaction. + } + + endgroup : DFI_transitions + + //======================================================================================================// + // END of covergroup definitions // + //======================================================================================================// + + function new (string name = "subscriber", uvm_component parent = null); + super.new(name,parent); + DFI_coverage = new (); + DFI_transitions = new (); + JEDEC_coverage = new (); + JEDEC_transitions = new (); + endfunction : new + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + mc_analysis_imp = new("mc_analysis_imp",this); + dram_analysis_imp = new("dram_analysis_imp",this); + `uvm_info("Build_Phase", "*************** 'subscriber' Build Phase ***************", UVM_HIGH) + endfunction : build_phase + + //==========================================================================// + // Connect Phase // + //==========================================================================// + function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + `uvm_info("Connect_phase", "*************** 'subscriber' Connect Phase ***************", UVM_HIGH) + endfunction : connect_phase + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + fork + begin + forever begin + @(dfi_transaction_complete); // MC Received read data, comes after got_jedec_stimulus.triggered + // $display("data_array = %p, at %t", jedec_stimulus_q[0].jedec_rddata_queue ,$time); + dfi_sequence_item_coverage = dfi_completeItem_q.pop_front(); + DFI_coverage.sample(); + if (! dfi_sequence_item_coverage.command_cancel) DFI_transitions.sample(); + end + end + begin + forever begin + @(jedec_transaction_complete); //DRAM Recieved command, comes after got_dfi_stimulus.triggered + jedec_sequence_item_coverage = jedec_completeItem_q.pop_front(); + JEDEC_coverage.sample(); + if (! jedec_sequence_item_coverage.command_cancel) JEDEC_transitions.sample(); + + // the number of data cycles of the previous read command with respect to the sampling event + if (jedec_sequence_item_coverage.CMD == RD) begin + if (first_RD_flag) first_RD_flag = 0; // This flag marks the first RD command is issued. + + case (jedec_sequence_item_coverage.actual_burst_length) + BL16: number_of_data_cycles_of_previous_read = 8; // BL16: 8 Clock cycles + BC8_OTF: number_of_data_cycles_of_previous_read = 4; // BC8 OTF: 4 Clock cycles + BL32: number_of_data_cycles_of_previous_read = 16; // BL32: 16 Clock cycles + endcase + end + + end + end + join + endtask : run_phase + + extern function void write_port_mc (ddr_sequence_item item); //write implementation for the mc port + extern function void write_port_dram (ddr_sequence_item item); //write implementation for the dram port + + + function void write (ddr_sequence_item t); // the built-in write function; NOT used + endfunction : write + +endclass : subscriber + + function void subscriber::write_port_mc (ddr_sequence_item item); //write implementation for the mc port + `uvm_info("write_port_mc", "*************** Hello from write_port_mc ***************", UVM_DEBUG) + `uvm_info("write_port_mc", $sformatf("dfi_item1.CMD = %p, at %t", item.CMD ,$time), UVM_DEBUG) + + dfi_sequence_item_handle = ddr_sequence_item::type_id::create("dfi_sequence_item_handle"); + // $display("before copy: CMD = %p, at %t", item.CMD ,$time); + // $display("before copy: OP = %p, at %t", item.OP ,$time); + dfi_sequence_item_handle.copy(item); + // $display("after copy: CMD = %p, at %t", dfi_sequence_item_handle.CMD ,$time); + // $display("after copy: OP = %p, at %t", dfi_sequence_item_handle.OP ,$time); + + if(dfi_sequence_item_handle.is_data_only) begin + dfi_complete_sequence_item = dfi_commandThread_q.pop_front(); + dfi_complete_sequence_item.dfi_rddata_queue = dfi_sequence_item_handle.dfi_rddata_queue; + dfi_completeItem_q.push_back(dfi_complete_sequence_item); + `uvm_info("DFI data thread", {"item.dfi_rddata_queue"}, UVM_DEBUG); + ->dfi_transaction_complete; + end + else begin + // $display("before pushing: CMD = %p, at %t", dfi_sequence_item_handle.CMD ,$time); + // $display("before pushing: OP = %p, at %t", dfi_sequence_item_handle.OP ,$time); + if ( (dfi_sequence_item_handle.CMD != MRR ) && (dfi_sequence_item_handle.CMD != RD ) ) begin + dfi_complete_sequence_item = dfi_sequence_item_handle; + dfi_completeItem_q.push_back(dfi_complete_sequence_item); + ->dfi_transaction_complete; + end else begin + dfi_commandThread_q.push_back(dfi_sequence_item_handle); + end + `uvm_info("DFI command thread", {"item.CMD"}, UVM_DEBUG); + // $display("after pushing: CMD = %p, at %t", dfi_sequence_item_handle.CMD ,$time); + // $display("after pushing: OP = %p, at %t", dfi_sequence_item_handle.OP ,$time); + end + endfunction : write_port_mc + + function void subscriber::write_port_dram (ddr_sequence_item item); //write implementation for the dram port + `uvm_info("write_port_dram", "*************** Hello from write_port_dram ***************", UVM_DEBUG) + + jedec_sequence_item_handle = ddr_sequence_item::type_id::create("jedec_sequence_item_handle"); + // $display("before copy: CMD = %p, at %t", item.CMD ,$time); + // $display("before copy: OP = %p, at %t", item.OP ,$time); + jedec_sequence_item_handle.copy(item); + // $display("after copy: CMD = %p, at %t", jedec_sequence_item_handle.CMD ,$time); + // $display("after copy: OP = %p, at %t", jedec_sequence_item_handle.OP ,$time); + + if(jedec_sequence_item_handle.is_data_only) begin + jedec_complete_sequence_item = jedec_commandThread_q.pop_front(); + jedec_complete_sequence_item.jedec_rddata_queue = jedec_sequence_item_handle.jedec_rddata_queue; + + if (jedec_complete_sequence_item.CMD == MRR) + jedec_complete_sequence_item.OP = jedec_sequence_item_handle.OP; + + jedec_complete_sequence_item.actual_burst_length = jedec_sequence_item_handle.actual_burst_length; + jedec_completeItem_q.push_back(jedec_complete_sequence_item); + `uvm_info("JEDEC data thread", {"item.jedec_rddata_queue"}, UVM_HIGH); + // $display("data_array = %p, at %t", jedec_sequence_item_handle.jedec_rddata_queue ,$time); + ->jedec_transaction_complete; + end + else begin + // $display("before pushing: CMD = %p, at %t", jedec_sequence_item_handle.CMD ,$time); + // $display("before pushing: OP = %p, at %t", jedec_sequence_item_handle.OP ,$time); + if ( (jedec_sequence_item_handle.CMD != MRR ) && (jedec_sequence_item_handle.CMD != RD ) ) begin + jedec_complete_sequence_item = jedec_sequence_item_handle; + jedec_completeItem_q.push_back(jedec_complete_sequence_item); + ->jedec_transaction_complete; + end else begin + jedec_commandThread_q.push_back(jedec_sequence_item_handle); + end + `uvm_info("JEDEC command thread", {"item.CMD"}, UVM_HIGH); + // $display("after pushing: CMD = %p, at %t", jedec_sequence_item_handle.CMD ,$time); + // $display("after pushing: OP = %p, at %t", jedec_sequence_item_handle.OP ,$time); + end + endfunction : write_port_dram diff --git a/testbench/interfaces/ddr_assertions.sv b/testbench/interfaces/ddr_assertions.sv new file mode 100644 index 0000000..d9d073a --- /dev/null +++ b/testbench/interfaces/ddr_assertions.sv @@ -0,0 +1,1165 @@ +//`include "tb_pkg.sv" +module ddr_assertions + import tb_pkg::*; + import uvm_pkg::*; + #( + /**************************Design Parameters****************************/ + parameter Physical_Rank_No = 1, + parameter device_width = 4, + /**************************DFI Timing Parameters****************************/ + parameter trddata_en = 1 , // Defined By System - Measured from the 2nd rising edge of the DFI_command_clock of the command + parameter tcmd_lat = 0 , // Defined By MC + parameter tctrl_delay = 1 , // Defined By PHY + parameter tphy_rdlat = 66+tctrl_delay+5 , // Defined By PHY: tctrl+max(RL)+phy's jedec to dfi deserialization (5 cycles in 1 to 4 ratio) + /**************************JEDEC Timing Parameters****************************/ + parameter tMRR = 16 +0, // Defined By DRAM + parameter tMRD = 16 +0, // Defined By DRAM + parameter tCMD_cancel = 8 +0, // Defined By DRAM + parameter tMRW = 8, + parameter tRP = 24, + parameter tRRD_S = 8, + parameter tRRD_L = 8, + parameter tCCD_S = 8, + parameter tRTP = 12, + parameter tRAS = 5 + ) +( +// DFI_Interface signals +input bit dfi_clk_i, +input logic reset_n_i, +input logic en_i, +input logic phycrc_mode_i, +input logic [1:0] dfi_freq_ratio_i, +input logic [13:0] dfi_address_p0, dfi_address_p1,dfi_address_p2,dfi_address_p3, +input logic [Physical_Rank_No-1:0]dfi_cs_p0,dfi_cs_p1,dfi_cs_p2,dfi_cs_p3, +input logic dfi_rddata_en_p0,dfi_rddata_en_p1,dfi_rddata_en_p2,dfi_rddata_en_p3, +input logic dfi_alert_n_a0, dfi_alert_n_a1,dfi_alert_n_a2,dfi_alert_n_a3, +input logic dfi_rddata_valid_w0,dfi_rddata_valid_w1,dfi_rddata_valid_w2,dfi_rddata_valid_w3, +input logic [2*device_width-1:0]dfi_rddata_w0,dfi_rddata_w1,dfi_rddata_w2,dfi_rddata_w3, + +// JEDEC Interface signals +input bit dfi_phy_clk_i, +input logic [13:0] CA_DA_o, +input logic CS_DA_o, +input logic CA_VALID_DA_o, +input logic DQS_AD_i, +input logic [2*device_width-1:0] DQ_AD_i, +//Constants fetched from the Env. (DB) +input byte RL, +input burst_length_t burst_length, +input bit [2:0] pre_amble, +input bit post_amble +); + + +`ifdef jedec_assert_en + +//==========================================================================// +// JEDEC Properties // +//==========================================================================// + +/************************************************JEDEC_DR_1**&**JEDEC_DR_2*******************************************/ +// From Plan: The mode register contents are available on the second 8 UI’s of the burst and are repeated across all DQ’s after the RL following the MRR command +sequence dynamic_delay(count); + int v; + (1, v=count) ##0 first_match((1, v=v-1'b1) [*0:$] ##1 v<=0); + endsequence + +property MRR_DATA_spacings; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + (CA_DA_o[4:0]==5'b10101 && !CS_DA_o) |=> dynamic_delay(RL+4) ##0 ( (DQ_AD_i[0] == !DQ_AD_i[1]) and + (DQ_AD_i[0] == DQ_AD_i[2]) and + (DQ_AD_i[0] == !DQ_AD_i[3]) and + (DQ_AD_i[4] == !DQ_AD_i[5]) and + (DQ_AD_i[4] == DQ_AD_i[6]) and + (DQ_AD_i[4] == !DQ_AD_i[7]) + ); +endproperty : MRR_DATA_spacings + +property MRR_DATA_spacings_ZEROs_ONEs; +int v; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + ( CA_DA_o[4:0]==5'b10101 && !CS_DA_o, v=RL) |=> dynamic_delay(v) ##0 (( (DQ_AD_i[0] == 1'b0) && (DQ_AD_i[1] == 1'b1) && (DQ_AD_i[2] == 1'b0) && (DQ_AD_i[3] == 1'b1) && (DQ_AD_i[4] == 1'b0) && (DQ_AD_i[5] == 1'b1) && (DQ_AD_i[6] == 1'b0) && (DQ_AD_i[7] == 1'b1) ) + ##1 ( (DQ_AD_i[0] == 1'b0) && (DQ_AD_i[1] == 1'b1) && (DQ_AD_i[2] == 1'b0) && (DQ_AD_i[3] == 1'b1) && (DQ_AD_i[4] == 1'b0) && (DQ_AD_i[5] == 1'b1) && (DQ_AD_i[6] == 1'b0) && (DQ_AD_i[7] == 1'b1) ) + ##1 ( (DQ_AD_i[0] == 1'b0) && (DQ_AD_i[1] == 1'b1) && (DQ_AD_i[2] == 1'b0) && (DQ_AD_i[3] == 1'b1) && (DQ_AD_i[4] == 1'b0) && (DQ_AD_i[5] == 1'b1) && (DQ_AD_i[6] == 1'b0) && (DQ_AD_i[7] == 1'b1) ) + ##1 ( (DQ_AD_i[0] == 1'b0) && (DQ_AD_i[1] == 1'b1) && (DQ_AD_i[2] == 1'b0) && (DQ_AD_i[3] == 1'b1) && (DQ_AD_i[4] == 1'b0) && (DQ_AD_i[5] == 1'b1) && (DQ_AD_i[6] == 1'b0) && (DQ_AD_i[7] == 1'b1) ) + ); +endproperty: MRR_DATA_spacings_ZEROs_ONEs + +/************************************************JEDEC_DR_3*******************************************/ +// From Plan: DQS is toggled for the duration of the MRR burst. --> DQS is toggled for BL16 +property MRR_DQS_toggle ; +int v; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + (CA_DA_o[4:0] == 5'b10101 && !CS_DA_o, v=RL) |=> dynamic_delay(v) ##0 ( ($changed(DQS_AD_i))[=1] )[*8]; +endproperty: MRR_DQS_toggle + +/************************************************JEDEC_DR_7*******************************************/ +// From Plan: The read pre-amble and post-amble of MRR are same as normal read. +property MRR_preamble; + bit result; int v; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + (!CS_DA_o && CA_DA_o[4:0] == 5'b10101 , v=RL-tRPRE) |=> dynamic_delay(v) ##0 (1, detect_preamble(pre_amble)); +endproperty: MRR_preamble +property MRR_postamble; + bit result; int v; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + (!CS_DA_o && CA_DA_o[4:0] == 5'b10101 , v=RL+8) |=> dynamic_delay(v) ##0 (1, detect_postamble(post_amble)); +endproperty: MRR_postamble + +/************************************************JEDEC_DR_8*******************************************/ +// Elaboration: spacing between MRR CMD and any other CMD is tMRR +// Timing between MRR and MRW is CL+BL/2+1 : not implemented yet +property MRR_CMD_spacings ; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +(CA_DA_o[4:0] == 5'b10101 && !CS_DA_o) |=> CS_DA_o [*tMRR-1]; +endproperty: MRR_CMD_spacings + +/************************************************JEDEC_DR_8*******************************************/ +// Elaboration: spacing between two MRW CMDs is tMRW and any other CMD is tMRR +property MRW_MRW_spacings ; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +(CA_DA_o[4:0] == 5'b00101 && !CS_DA_o) |=> CS_DA_o[*tMRW-1]; +endproperty: MRW_MRW_spacings +property MRW_OTHER_spacings; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +(CA_DA_o[4:0] == 5'b00101 && !CS_DA_o) |=> !(is_ACT()||is_MRR()||is_PREab()||is_RD())[*tMRD-1-1]; +endproperty: MRW_OTHER_spacings + +/************************************************JEDEC_DR_11*******************************************/ +// Elaboration: spacing between PRE CMDs and MRR/MRW is tRP + +property PRE_CMD_spacings ; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + (CA_DA_o[4:0] == 5'b01011 && !CS_DA_o) |=> !((CA_DA_o[4:0] == 5'b00101 || CA_DA_o[4:0] == 5'b10101) && !CS_DA_o) [*tRP-1]; + endproperty: PRE_CMD_spacings + +/************************************************JEDEC_DR_12*******************************************/ +//When a defined register byte (MR#) contains an “RFU” bit, the host must write a ZERO for those specific bits +property host_Write_zero_to_RFU ; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +(CA_DA_o[4:0] == 5'b00101 && CA_DA_o[12:5] == 0 |=> CA_DA_o[7] == 0) and +(CA_DA_o[4:0] == 5'b00101 && CA_DA_o[12:5] == 8'h08 |=> CA_DA_o[5] == 0) and +(CA_DA_o[4:0] == 5'b00101 && CA_DA_o[12:5] == 8'h28 |=> CA_DA_o[7:3] ==0); +endproperty: host_Write_zero_to_RFU + +/************************************************JEDEC_DR_13*******************************************/ +//When the host issues an MRR to a defined register (MR#) that contains RFU bits in it, those specific bits shall always produce a ZERO. +property host_Read_zero_from_RFU ; + int t_13; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +((CA_DA_o[4:0] == 5'b10101 && CA_DA_o[12:5] == 8'h00 && !CS_DA_o, t_13 = RL+7) |=> dynamic_delay(t_13) ##0 DQ_AD_i[4] == 1'b0) and +((CA_DA_o[4:0] == 5'b10101 && CA_DA_o[12:5] == 8'h08 && !CS_DA_o, t_13 = RL+6) |=> dynamic_delay(t_13) ##0 DQ_AD_i[4] == 2'bx0) ; +endproperty: host_Read_zero_from_RFU + +/*****************************JEDEC_DR_17*******************************************/ +//From Plan: Check that the preamble and postamble is equal to the value written in MR8 +int tRPRE; +always_comb begin + case (pre_amble) + 000: tRPRE = 2; + 001: tRPRE = 4; + 010: tRPRE = 4; + 011: tRPRE = 6; + 100: tRPRE = 8; + default: tRPRE = 2; + endcase +end +property RD_preamble; + bit result; int v; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + (!CS_DA_o && CA_DA_o[4:0] == 5'b11101 , v=RL-tRPRE) |=> dynamic_delay(v) ##0 (1, detect_preamble(pre_amble)); +endproperty: RD_preamble +int num_of_bursts; +always_comb begin + case(burst_length) + BL16: num_of_bursts=8; + BC8_OTF: num_of_bursts=4; + BL32: num_of_bursts=16; + //BL32_OTF: num_of_bursts=16; + default: num_of_bursts=8; + endcase +end +property RD_postamble; + bit result; int v; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + (!CS_DA_o && CA_DA_o[4:0] == 5'b11101 , v=RL+num_of_bursts) |=> dynamic_delay(v) ##0 (1, detect_postamble(post_amble)); +endproperty: RD_postamble + +/************************************************JEDEC_DR_21*******************************************/ +// The minimum timing between a cancelled CMD and the following CMD is tCMD_cancel +property CMD_Cancel_timing ; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +(!CS_DA_o)[*2] |=> CS_DA_o[*tCMD_cancel]; +endproperty: CMD_Cancel_timing + + +/************************************************JEDEC_DR_24*******************************************/ +// Once a bank has been precharged, it is in the idle state and must be activated prior to any READ or WRITE commands being issued to that bank +property Pre_then_ACT ; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +(CA_DA_o[4:0] == 5'b01011 && !CS_DA_o) ##[0:$] (CA_DA_o[4:0] != 5'b11101 && !CS_DA_o) || (CA_DA_o[4:0] != 5'b00101 && !CS_DA_o) |-> 1; +endproperty: Pre_then_ACT + +/************************************************JEDEC_DR_25***&**JEDEC_DR_31*******************************************/ +// A PRECHARGE command is allowed if there is no open row in that bank (idle state) or if the previously open row is already in the process of precharging. +property ACT_then_Pre_no_allowed ; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +(( CA_DA_o[1:0] == 2'b00 && !CS_DA_o) ##[0:$] (CA_DA_o[4:0] != 5'b01011 && !CS_DA_o)) |-> 1; +endproperty: ACT_then_Pre_no_allowed + +/************************************************JEDEC_DR_28***&**JEDEC_DR_29*******************************************/ +// tRRD_S (short) is used for timing between banks located in different bank groups. +// tRRD_L (long) is used for timing between banks located in the same bank group. +property ACT_2_ACT_Diff_BG; + logic [2:0] BG; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +( CA_DA_o[1:0] == 2'b00 && !CS_DA_o, BG = CA_DA_o[10:8] ) |=> (!( CA_DA_o[1:0] == 2'b00 && !CS_DA_o ))[*tRRD_S-1]; +endproperty: ACT_2_ACT_Diff_BG +property ACT_2_ACT_Same_BG; + logic [2:0] BG; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +((CA_DA_o[1:0] == 2'b00) && !CS_DA_o, BG = CA_DA_o[10:8]) |=> (!(CA_DA_o[1:0] == 2'b00 && !CS_DA_o && CA_DA_o[10:8] == BG))[*tRRD_L-1]; +endproperty: ACT_2_ACT_Same_BG + + +/************************************************JEDEC_DR_31*******************************************/ +//Read Latency (RL or CL) is defined from the Read command to data and is not affected by the Read DQS offset timing (MR40 OP[2:0]). +property RDCMD_TO_DATA_DELAY ; +int v; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +((CA_DA_o[4:0] == 5'b11101 && !CS_DA_o, v = RL) |=> dynamic_delay(v) ##0 !$isunknown(DQ_AD_i)); +endproperty: RDCMD_TO_DATA_DELAY + +/************************************************JEDEC_DR_32************************************************/ +// From Plan: "If CA5:BL*=L, the command places the DRAM into the alternate Burst mode described by MR0[1:0] instead of the default Burst Length 16 mode." +// This property should measure the BL and compare it to BL16 if CA5==H or compare it to burst_length is CA5==L +task automatic detect_BL(input burst_length_t burst_length); + bit DQS_Internal; + DQS_Internal = DQS_AD_i; + case(burst_length) + BL16: begin + repeat(8-1) begin + @(posedge dfi_phy_clk_i) + if (DQS_Internal == DQS_AD_i) //DQS_AD_i should have toggled by now + begin + `uvm_error("DDR Assertions", $sformatf("detect_BL failure -- BL setting is: %d", burst_length)); + end + else + DQS_Internal = DQS_AD_i; + end + end + BC8_OTF:begin + repeat(4-1) begin + @(posedge dfi_phy_clk_i) + if (DQS_Internal == DQS_AD_i) //DQS_AD_i should have toggled by now + begin + `uvm_error("DDR Assertions", $sformatf("detect_BL failure -- BL setting is: %d", burst_length)); + end + else + DQS_Internal = DQS_AD_i; + end + end + BL32: begin + repeat(16-1) begin + @(posedge dfi_phy_clk_i) + if (DQS_Internal == DQS_AD_i) //DQS_AD_i should have toggled by now + begin + `uvm_error("DDR Assertions", $sformatf("detect_BL failure -- BL setting is: %d", burst_length)); + end + else + DQS_Internal = DQS_AD_i; + end + end + /* + BL32_OTF:begin + repeat(16-1) begin + @(posedge dfi_phy_clk_i) + if (DQS_Internal == DQS_AD_i) //DQS_AD_i should have toggled by now + begin + `uvm_error("DDR Assertions", $sformatf("detect_BL failure -- BL setting is: %d", burst_length)); + end + else + DQS_Internal = DQS_AD_i; + end + end + */ + default:begin + + end + endcase +endtask +property RD_CA5_H; +int v; + @(posedge dfi_phy_clk_i)disable iff (!reset_n_i) + ( (CA_DA_o[4:0] == 5'b11101) && !CS_DA_o && CA_DA_o[5]==1 && burst_length!=BL32, v=RL) |=> dynamic_delay(v) ##0 ( 1 , detect_BL(BL16) ); +endproperty: RD_CA5_H +property RD_CA5_L; +int v; + @(posedge dfi_phy_clk_i)disable iff (!reset_n_i) + //( (CA_DA_o[4:0] == 5'b11101) && !CS_DA_o && CA_DA_o[5]==1, v=RL) |=> (1, v=v-1'b1)[*1:$] ##0 v<=0 ##0 ( ( ($changed(DQS_AD_i))[=1] )[*(num_of_bursts)] ); + ( (CA_DA_o[4:0] == 5'b11101) && !CS_DA_o && CA_DA_o[5]==0, v=RL) |=> dynamic_delay(v) ##0 ( 1 , detect_BL(burst_length) ); +endproperty: RD_CA5_L + +/************************************************JEDEC_DR_35************************************************/ +// From Plan: In non-CRC mode, DQS_t and DQS_c stop toggling at the completion of the BC8 data bursts, plus the postamble -- assert stops toggeling after postamble +int tRPST; +always_comb begin + if (post_amble) + tRPST=1; + else + tRPST=3; +end +property DQS_stop ; +int v; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + (!CS_DA_o && (CA_DA_o[4:0] == 5'b11101 ||CA_DA_o[4:0] == 5'b10101) , v=RL+(num_of_bursts)+tRPST) |=> dynamic_delay(v) ##0 (!$changed(DQS_AD_i) [*10]); //The number 10 is arbitrary to make sure DQS is not toggling anymore +endproperty: DQS_stop + +/************************************************JEDEC_DR_36************************************************/ +//The minimum external Read command to Precharge command spacing to the same bank is equal to tRTP with tRTP being the Internal Read Command to Precharge Command Delay. +property RDToPreSpacing ; + logic [1:0] bankaddress; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +((CA_DA_o[4:0] == 5'b11101) && !CS_DA_o, bankaddress = CA_DA_o[7:6]) |=> !( CA_DA_o[4:0]==5'b01011 && !CS_DA_o && CA_DA_o[7:6]==bankaddress) [*tRTP-1]; +endproperty: RDToPreSpacing + + +/************************************************JEDEC_DR_37************************************************/ +// the minimum ACT to PRE timing, tRAS, must be satisfied as well +property PreToACTSpacing ; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +((CA_DA_o[4:0] == 5'b01011) && !CS_DA_o) |-> ##1 !(!CS_DA_o && (CA_DA_o[1:0] == 2'b00))[*tRAS-1]; +endproperty: PreToACTSpacing + +/************************************************JEDEC_DR_37************************************************/ +// A dummy RD command is required for the second half of the transfer with a delay of 8 clocks from the first RD command in case of BL32 fixed or BL32 OTF + +property DummyRDCMD ; +burst_length_t burstlength = burst_length; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +(((CA_DA_o[4:0] == 5'b11101) && !CS_DA_o && burstlength == BL32) ##1 CA_DA_o[10] == 1) |-> ##7 (!CS_DA_o && (CA_DA_o[4:0] == 5'b11101) ##1 CA_DA_o[10] == 0); +endproperty: DummyRDCMD + +property C10_IS_opposite ; +burst_length_t burstlength_ = burst_length; +logic C10; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + ((CA_DA_o[4:0] == 5'b11101 && !CS_DA_o && burstlength_ == BL32) ##1 ( CA_DA_o[10] == 1, C10 = CA_DA_o[8])) |-> ##7 ((!CS_DA_o && (CA_DA_o[4:0] == 5'b11101)) ##1 (CA_DA_o[8] == !C10 && CA_DA_o[10]== 0)); + +endproperty: C10_IS_opposite + + +property SecondRD_resembles_first ; +burst_length_t burstlength__ = burst_length; +logic [13:0] first_temp_CMD; +logic [13:0] second_temp_CMD; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + ((CA_DA_o[4:0] == 5'b11101 && burstlength__ == BL32 && !CS_DA_o, first_temp_CMD = CA_DA_o[13:0]) ##1 (CA_DA_o[10] == 1, second_temp_CMD = CA_DA_o[13:0])) |-> ##7 ((!CS_DA_o && (CA_DA_o[13:0] == first_temp_CMD)) ##1 (CA_DA_o[7:0] == second_temp_CMD[7:0] && CA_DA_o[13:11] == second_temp_CMD[13:11] && CA_DA_o[9] == second_temp_CMD[9] && CA_DA_o[10]== 0)); +endproperty: SecondRD_resembles_first + +/************************************************JEDEC_DR_44************************************************/ +// From Plan: AP bit must be set to LOW with the CAS command when reading BL16 in BL32 OTF mode -- Assert that The read command has AP low +/* +property BL16_In_BL32OTF ; + @(posedge dfi_phy_clk_i) + (CA_DA_o[4:0] == 5'b11101 && CA_DA_o[5]==1 && burst_length==BL32_OTF && !CS_DA_o) |-> CA_DA_o[10]==0; +endproperty: BL16_In_BL32OTF +*/ + + +property ReadTOReadSameBank ; + logic [4:0] ba; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) +(((CA_DA_o[1:0] == 5'b11101), ba = CA_DA_o[10:6]) |-> ##1 (CS_DA_o[*tCCD_S] or (CS_DA_o [*tRRD_L] ##1 CA_DA_o[10:8] == ba))); + +endproperty: ReadTOReadSameBank + + + +//==========================================================================// +// JEDEC ASSERTIONS // +//==========================================================================// + + Spacing_btn_MRR_Data: assert property(MRR_DATA_spacings) + else `uvm_error("DDR Assertions", $sformatf("Data should be available on 8 UI's RL after MRR CMD")); + COV_Spacing_btn_MRR_Data: cover property(MRR_DATA_spacings); + // + ASRT_MRR_DATA_spacings_ZEROs_ONEs: assert property(MRR_DATA_spacings_ZEROs_ONEs) + else `uvm_error("DDR Assertions", $sformatf("Data Shoulg Be Zeros And Ones when reading from MR")); + COV_MRR_DATA_spacings_ZEROs_ONEs: cover property(MRR_DATA_spacings_ZEROs_ONEs); + + + + +ASRT_MRR_preamble: assert property(MRR_preamble) + else `uvm_error("DDR Assertions", $sformatf("Preamble error after MRR command")); +COV_MRR_preamble: cover property(MRR_preamble); + + `ifdef DQS_toggline + ASRT_MRR_postamble: assert property(MRR_postamble) + else `uvm_error("DDR Assertions", $sformatf("Postamble error after MRR command")); + COV_MRR_postamble: cover property(MRR_postamble); + // + JEDEC_DQSShouldToggleForBL: assert property(MRR_DQS_toggle) + else `uvm_error("DDR Assertions", $sformatf("DQS Should Toggle For BL")); + COV_JEDEC_DQSShouldToggleForBL: cover property(MRR_DQS_toggle); + `endif + +Spacing_btn_MRR_CMD: assert property(MRR_CMD_spacings) + else `uvm_error("DDR Assertions", $sformatf("Spacing between MRR CMD and any other CMD should be tMRR")); +COV_Spacing_btn_MRR_CMD: cover property(MRR_CMD_spacings); +// +ASRT_MRW_MRW_spacings: assert property(MRW_MRW_spacings) + else `uvm_error("DDR Assertions", $sformatf("Spacing between two MRW CMDs should be tMRW ")); +COV_MRW_MRW_spacings: cover property(MRW_MRW_spacings); +// +ASRT_MRW_OTHER_spacings: assert property(MRW_OTHER_spacings) + else `uvm_error("DDR Assertions", $sformatf("Spacing between two MRW CMD and any other CMD should tMRR")); +COV_MRW_OTHER_spacings: cover property(MRW_OTHER_spacings); +// +Spacing_btn_PRE_MRR: assert property(PRE_CMD_spacings) + else `uvm_error("DDR Assertions", $sformatf("Spacing between PRE CMDs and MRR/MRW should be tRP")); +COV_Spacing_btn_PRE_MRR: cover property(PRE_CMD_spacings); +// +host_should_Write_zero_to_RFU: assert property(host_Write_zero_to_RFU) + else `uvm_error("DDR Assertions", $sformatf("“RFU” bits must be written ZERO by the host")); +COV_host_should_Write_zero_to_RFU: cover property(host_Write_zero_to_RFU); +// + //`ifdef allow_ram_hog + host_should_Read_zero_from_RFU: assert property(host_Read_zero_from_RFU) + else `uvm_error("DDR Assertions", $sformatf("RFU bits shall always produce a ZERO when it's being read")); + COV_host_should_Read_zero_from_RFU: cover property(host_Read_zero_from_RFU); + //`endif +// + +ASRT_RD_preamble: assert property(RD_preamble) + else `uvm_error("DDR Assertions", $sformatf("Preamble error after RD command")); +COV_RD_preamble: cover property(RD_preamble); + + `ifdef DQS_toggline + ASRT_RD_postamble: assert property(RD_postamble) + else `uvm_error("DDR Assertions", $sformatf("Postamble error after RD command")); + COV_RD_postamble: cover property(RD_postamble); + `endif +// +timing_btn_Canceled_CMD: assert property(CMD_Cancel_timing) + else `uvm_error("DDR Assertions", $sformatf("The minimum timing between a cancelled CMD and the following CMD should be tCMD_cancel")); +COV_timing_btn_Canceled_CMD: cover property(CMD_Cancel_timing); +// + `ifdef allow_ram_hog + ACT_Should_follow_PRE: assert property(Pre_then_ACT) + else `uvm_error("DDR Assertions", $sformatf("a bank must be activated prior to any READ or WRITE commands being issued to that bank")); + COV_ACT_Should_follow_PRE: cover property(Pre_then_ACT); + // + PRE_Mustnt_follow_ACT: assert property(ACT_then_Pre_no_allowed) + else `uvm_error("DDR Assertions", $sformatf("Precharge CMD mustn't follow activate CMD directely")); + COV_PRE_Mustnt_follow_ACT: cover property(ACT_then_Pre_no_allowed); + `endif +// +ASRT_ACT_2_ACT_Diff_BG: assert property(ACT_2_ACT_Diff_BG) + else `uvm_error("DDR Assertions", $sformatf("timing between banks located in different bank groups should be tRRD_S")); +COV_ACT_2_ACT_Diff_BG: cover property(ACT_2_ACT_Diff_BG); +ASRT_ACT_2_ACT_Same_BG: assert property(ACT_2_ACT_Same_BG) + else `uvm_error("DDR Assertions", $sformatf("timing between banks located in the same bank group should be tRRD_L")); +COV_ACT_2_ACT_Same_BG: cover property(ACT_2_ACT_Same_BG); +// +/* --------------------------- LOW PRIORITY, SO DISABLED ------------------------------ +Four_ACT_CMD_withen_tFAW: assert property(Max_timing_for_four_ACT_CMD) + else `uvm_error("DDR Assertions", $sformatf("// Spec: Consecutive ACTIVATE commands, allowed to be issued at tRRDmin, are restricted to a maximum of four within the time period tFAW (four activate window).")); +COV_Four_ACT_CMD_withen_tFAW: cover property(Max_timing_for_four_ACT_CMD); +//*/ +ReadToDataDelayIstRL: assert property(RDCMD_TO_DATA_DELAY) + else `uvm_error("DDR Assertions", $sformatf("The delay between read command and data should be RL")); +COV_ReadToDataDelayIstRL: cover property(RDCMD_TO_DATA_DELAY); +// + `ifdef DQS_toggline + ASRT_RD_CA5_H: assert property(RD_CA5_H) + else `uvm_error("DDR Assertions", $sformatf("BL is not BL16 when CA5==H in a RD cmd")); + COV_RD_CA5_H: cover property(RD_CA5_H); + + ASRT_RD_CA5_L: assert property(RD_CA5_L) + else `uvm_error("DDR Assertions", $sformatf("BL is not equal to burst_length from DB when CA5==L in a RD cmd")); + COV_RD_CA5_L: cover property(RD_CA5_L); + // + ASRT_DQS_stop: assert property(DQS_stop) + else `uvm_error("DDR Assertions", $sformatf("DQS did not stop after postamble")); + COV_DQS_stop: cover property(DQS_stop); + // + `endif +// +ReadToPrechargeDelayIsttPTR: assert property(RDToPreSpacing) + else `uvm_error("DDR Assertions", $sformatf("The delay between read command and precharge command should be tRTB")); +COV_ReadToPrechargeDelayIsttPTR: cover property(RDToPreSpacing); +// +PrechargeToACTDelayIsttRAS: assert property(PreToACTSpacing) + else `uvm_error("DDR Assertions", $sformatf("The delay between precharge command and ACT command should be tRAS")); +COV_PrechargeToACTDelayIsttRAS: cover property(PreToACTSpacing); +// +ADummyReadCMDShouldExitInBL32: assert property(DummyRDCMD) + else `uvm_error("DDR Assertions", $sformatf("A Dummy Read CMD Should Exit In BL32")); +COV_ADummyReadCMDShouldExitInBL32: cover property(DummyRDCMD); +// +C10ShouldBeOppositeInTheSecondCMD: assert property(C10_IS_opposite) + else `uvm_error("DDR Assertions", $sformatf("C10 Should Be Opposite In TheSecond CMD")); +COV_C10ShouldBeOppositeInTheSecondCMD: cover property(C10_IS_opposite); +// +SecondCMDShouldResembleFirstCMD: assert property(SecondRD_resembles_first) + else `uvm_error("DDR Assertions", $sformatf("Second CMD Should Resemble First CMD")); +COV_SecondCMDShouldResembleFirstCMD: cover property(SecondRD_resembles_first); +// + /* + ASRT_BL16_In_BL32OTF: assert property(BL16_In_BL32OTF) + else `uvm_error("DDR Assertions", $sformatf("CA10 Should Be High For BL16 In BL32")); + COV_BL16_In_BL32OTF: cover property(BL16_In_BL32OTF); + */ +// +ReadTOReadSameBankDelay: assert property(ReadTOReadSameBank) + else `uvm_error("DDR Assertions", $sformatf("Read TO Read SameBank Delay should be tCCD_L")); +COV_ReadTOReadSameBankDelay: cover property(ReadTOReadSameBank); +// + +`endif + + +`ifdef dfi_assert_en +//==========================================================================// +// DFI Properties for 1 to 1 ratio // +//==========================================================================// + +`ifdef ratio_1_to_1 + + /*****************************DFI_DR_1 && DFI_DR_2*******************************************/ + // From plan: command is driven for at least 1 DFI PHY clock cycle after the CS is active. + // tcmd_lat specifies the number of DFI clocks after the dfi_cs signal is asserted until the associated CA signals are driven. + property dfi_address_valid(dfi_cs_px, dfi_address_px); + @(posedge dfi_clk_i) disable iff (!reset_n_i) + !dfi_cs_px |-> (##tcmd_lat !$isunknown(dfi_address_px) [*1:2]); + endproperty: dfi_address_valid + + /*****************************DFI_DR_6*******************************************/ + // From plan: Check the correct behaviour of CS_n on the DRAM interface (follows the behaviour of dfi_cs meaning 0=>1=>0) + // Elaboration: when dfi_cs toggles (1=>0=>1), CS_n should follow the exact same behaviour after translation delay of tctrl_delay + property CS_n_to_dfi_cs_translation(dfi_cs_px, CS_DA_o, tctrl_delay); + bit CS_tmp; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + ($changed(dfi_cs_px), CS_tmp=dfi_cs_px) |-> ##(tctrl_delay+1) CS_DA_o===CS_tmp; //where x is the phase number + //**NOTE: Added 1 to all timing that envolves an input singal (TB stimulus) AND an output signal (DUT response) + // because we drive on the negative edge, but the DUT's output is on the positive edge + endproperty: CS_n_to_dfi_cs_translation + + /*****************************DFI_DR_11*******************************************/ + // Translation delay between DFI and JEDEC + property dfi_address_to_CA_translation(dfi_cs_px, dfi_address_px,CA_DA_o); + logic [13:0] CA_temp; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + ($changed(dfi_address_px) , CA_temp=dfi_address_px) |-> (##(tctrl_delay+1) (CA_temp===CA_DA_o)); + //**NOTE: Added 1 to all timing that envolves an input singal (TB stimulus) AND an output signal (DUT response) + // because we drive on the negative edge, but the DUT's output is on the positive edge + endproperty: dfi_address_to_CA_translation + + /*****************************DFI_DR_13*******************************************/ + //From Plan: check that valid data is being transferred when the dfi_rddata_valid signal is asserted + property dfi_rddata_signal_valid(dfi_rddata_valid_wx, dfi_rddata_wx); + @(posedge dfi_clk_i) disable iff (!reset_n_i) + dfi_rddata_valid_w0 |-> !$isunknown(dfi_rddata_wx); + endproperty: dfi_rddata_signal_valid + + /*****************************DFI_DR_13 && DFI_DR_16*******************************************/ + // From Plan: dfi_rddata_en is asserted after a RD command by trddata_en DFI_PHY_clock cycles + property dfi_rddata_en_signal_asserted(dfi_address_px, dfi_cs_px, dfi_rddata_en_px); + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + ((dfi_address_px[4:0] == 5'b11101) && !(dfi_cs_px)) |-> (##(trddata_en+1) dfi_rddata_en_px); + //**NOTE: used ##(trddata_en+1) because the first part of the command is the antecident; therefore, an extra "1" is added to "trddata_en" + endproperty: dfi_rddata_en_signal_asserted + + + /*****************************DFI_DR_13 && DFI_DR_16*******************************************/ + // From Plan: asserting on tphy_rdlat + property dfi_rddata_en_to_dfi_rddata_valid_delay(dfi_rddata_en, dfi_rddata_valid); + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + $rose(dfi_rddata_en) |-> ##[0:tphy_rdlat+1] $rose(dfi_rddata_valid) ; + //**NOTE: Added 1 to all timing that envolves an input singal (TB stimulus) AND an output signal (DUT response) + // because we drive on the negative edge, but the DUT's output is on the positive edge + endproperty: dfi_rddata_en_to_dfi_rddata_valid_delay + + + +//==========================================================================// +// DFI Assertions for 1 to 1 ratio // +//==========================================================================// + + dfi_address_VALID_p0: assert property (dfi_address_valid(dfi_cs_p0, dfi_address_p0)) + else `uvm_error("DDR Assertions", $sformatf("Spacing between dfi_cs_p0 and dfi_address_p0 is not %d",tcmd_lat)); + COV_dfi_address_VALID_p0: cover property(dfi_address_valid(dfi_cs_p0, dfi_address_p0)); + + CS_n_to_dfi_cs_Translation_p0: assert property(CS_n_to_dfi_cs_translation(dfi_cs_p0, CS_DA_o, tctrl_delay))//$display("CS_n_to_dfi_cs_translation Assertion Passed at time t=%d", $time); + else `uvm_error("DDR Assertions", $sformatf("The dfi_cs_p0 translational delay between DFI interface and JEDEC interface isn't %d",tctrl_delay+0)); + COV_CS_n_to_dfi_cs_Translation_p0:cover property(CS_n_to_dfi_cs_translation(dfi_cs_p0, CS_DA_o, tctrl_delay)); + + dfi_address_to_CA_delay_p0: assert property(dfi_address_to_CA_translation(dfi_cs_p0, dfi_address_p0, CA_DA_o)) + else `uvm_error("DDR Assertions", $sformatf("The dfi_address_p0 translational delay between DFI interface and JEDEC interface isn't %d --- Sampled CA: ",tctrl_delay+0, $sampled(CA_DA_o))); + COV_dfi_address_to_CA_delay_p0: cover property(dfi_address_to_CA_translation(dfi_cs_p0, dfi_address_p0, CA_DA_o)); + + dfi_rddata_signal_valid_p0: assert property(dfi_rddata_signal_valid(dfi_rddata_valid_w0, dfi_rddata_w0)) + else `uvm_error("DDR Assertions", $sformatf("dfi_rddata_w0 is sent without dfi_rddata_valid_w0")); + + dfi_rddata_en_signal_asserted_p0:assert property(dfi_rddata_en_signal_asserted(dfi_address_p0, dfi_cs_p0, dfi_rddata_en_p0)) + else `uvm_error("DDR Assertions", $sformatf("dfi_rddata_en_p0 should be asserted %d cycles after dfi_address_p0", trddata_en)); + + dfi_rddata_en_to_dfi_rddata_valid_delay_p0:assert property(dfi_rddata_en_to_dfi_rddata_valid_delay(dfi_rddata_en_p0, dfi_rddata_valid_w0)) + else `uvm_error("DDR Assertions", $sformatf("DFI_DR_13 && DFI_DR_16 Failure -- dfi_rddata_en to dfi_rddata_valid delay is not %d", tphy_rdlat)); + +`endif + +`ifdef ratio_1_to_2 +//==========================================================================// +// DFI Properties for 1 to 2 ratio // +//==========================================================================// + /*****************************DFI_DR_1 && DFI_DR_2*******************************************/ + // From plan: command is driven for at least 1 DFI PHY clock cycle after the CS is active. + // tcmd_lat specifies the number of DFI clocks after the dfi_cs signal is asserted until the associated CA signals are driven. + property dfi_address_valid(dfi_cs_px, dfi_address_px); + @(posedge dfi_clk_i) disable iff (!reset_n_i) + !dfi_cs_px |-> (##tcmd_lat !$isunknown(dfi_address_px) [*1:2]); + endproperty: dfi_address_valid + + /*****************************DFI_DR_6*******************************************/ + // From plan: Check the correct behaviour of CS_n on the DRAM interface (follows the behaviour of dfi_cs meaning 0=>1=>0) + // Elaboration: when dfi_cs toggles (1=>0=>1), CS_n should follow the exact same behaviour after translation delay of tctrl_delay + property CS_n_to_dfi_cs_translation(dfi_cs_px, CS_DA_o, phase); + bit CS_tmp; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + ($changed(dfi_cs_px), CS_tmp=dfi_cs_px) |-> ##(2*tctrl_delay+1+phase) CS_DA_o===CS_tmp; //where phase is the phase number + //**NOTE: Added 1 to all timing that envolves an input singal (TB stimulus) AND an output signal (DUT response) + // because we drive on the negative edge, but the DUT's output is on the positive edge + //**NOTE: Multiplied tctrl_delay by 2 because 1_to_2 ration; tctrl_delay is 1 dfi_clk cycle. + endproperty: CS_n_to_dfi_cs_translation + + /*****************************DFI_DR_7 -----NOT IMPLEMENTED BY THE DESIGN YET------*******************************************/ + // From plan: Check the correct behaviour of reset_n on the DRAM interface (follows the behaviour of dfi_reset_n meaning 0=>1=>0) + // Elaboration: when dfi_reset_n toggles, reset_n should follow the exact same behaviour after translation delay of tctrl_delay + /* + property ; + @(posedge dfi_clk_i) + (dfi_reset_n ##1 !dfi_reset_n ##1 dfi_reset_n) |-> (##tctrl_delay (reset_n ##1 !reset_n ##1 reset_n)); + endproperty: + ERR_: assert property(); + */ + + /*****************************DFI_DR_11*******************************************/ + // Translation delay between DFI and JEDEC + property dfi_address_to_CA_translation(dfi_cs_px, dfi_address_px,CA_DA_o, phase); + logic [13:0] CA_temp; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + //( $rose(dfi_clk_i) && !dfi_cs_px && $changed(dfi_address_px) , CA_temp=dfi_address_px) |-> (##(tctrl_delay+x) (CA_temp==CA_DA_o)); + ($changed(dfi_address_px) , CA_temp=dfi_address_px) |-> ##(2*tctrl_delay+1+phase) (CA_temp===CA_DA_o); + endproperty: dfi_address_to_CA_translation + + /*****************************DFI_DR_13*******************************************/ + //From Plan: check that valid data is being transferred when the dfi_rddata_valid signal is asserted + property dfi_rddata_signal_valid(dfi_rddata_valid_wx, dfi_rddata_wx); + @(posedge dfi_clk_i) disable iff (!reset_n_i) + dfi_rddata_valid_w0 |-> !$isunknown(dfi_rddata_wx); + endproperty: dfi_rddata_signal_valid + + /*****************************DFI_DR_13 && DFI_DR_16*******************************************/ + // From Plan: dfi_rddata_en is asserted after a RD command by trddata_en DFI_PHY_clock cycles + property dfi_rddata_en_signal_asserted(dfi_address_px, dfi_cs_px, dfi_rddata_en_px, a); + @(posedge dfi_clk_i) disable iff (!reset_n_i) + ( ((dfi_address_px[4:0] == 5'b11101) && !(dfi_cs_px)) |-> ##(trddata_en) dfi_rddata_en_px && !(a) ); //This line encapsulates the 2 lines below; 2 assertions must be used + /* + ( ((dfi_address_p0[4:0] == 5'b11101) && !(dfi_cs_p0)) |-> (##(trddata_en) dfi_rddata_en_p0) ) + or + ( ((dfi_address_p1[4:0] == 5'b11101) && !(dfi_cs_p1)) |-> (##(trddata_en) dfi_rddata_en_p1 && !(dfi_rddata_en_p0) ) ); //Making sure that no rddata_en is driven before two phy clocks (i.e., phases) + */ + endproperty: dfi_rddata_en_signal_asserted + + + /*****************************DFI_DR_13 && DFI_DR_16*******************************************/ + // From Plan: asserting on tphy_rdlat + property dfi_rddata_en_to_dfi_rddata_valid_delay(dfi_rddata_en, dfi_rddata_valid); + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + $rose(dfi_rddata_en) |-> ##[0:tphy_rdlat+1] $rose(dfi_rddata_valid) ; + //**NOTE: Added 1 to all timing that envolves an input singal (TB stimulus) AND an output signal (DUT response) + // because we drive on the negative edge, but the DUT's output is on the positive edge + endproperty: dfi_rddata_en_to_dfi_rddata_valid_delay + +//==========================================================================// +// DFI Assertions for 1 to 2 ratio // +//==========================================================================// + dfi_address_p0_VALID: assert property (dfi_address_valid(dfi_cs_p0, dfi_address_p0)) + else `uvm_error("DDR Assertions", $sformatf("Spacing between dfi_cs_p0 and dfi_address_p0 is not %d",tcmd_lat)); + COV_dfi_address_p0_VALID: cover property(dfi_address_valid(dfi_cs_p0, dfi_address_p0)); + + CS_n_to_dfi_cs_Translation_p0: assert property(CS_n_to_dfi_cs_translation(dfi_cs_p0, CS_DA_o, 0)) + else `uvm_error("DDR Assertions", $sformatf("The dfi_cs_p0 translational delay between DFI interface and JEDEC interface isn't tctrl_delay: %d",tctrl_delay)); + COV_CS_n_to_dfi_cs_Translation_p0:cover property(CS_n_to_dfi_cs_translation(dfi_cs_p0, CS_DA_o, 0)); + + dfi_address_to_CA_delay_p0: assert property(dfi_address_to_CA_translation(dfi_cs_p0, dfi_address_p0, CA_DA_o, 0)) + else `uvm_error("DDR Assertions", $sformatf("The dfi_address_p0 translational delay between DFI interface and JEDEC interface isn't tctrl_delay: %d --- Sampled CA: ",tctrl_delay, $sampled(CA_DA_o))); + COV_dfi_address_to_CA_delay_p0: cover property(dfi_address_to_CA_translation(dfi_cs_p0, dfi_address_p0, CA_DA_o, 0)); + + dfi_rddata_signal_valid_p0: assert property(dfi_rddata_signal_valid(dfi_rddata_valid_w0, dfi_rddata_w0)) + else `uvm_error("DDR Assertions", $sformatf("dfi_rddata_w0 is sent without dfi_rddata_valid_w0")); + /* + dfi_rddata_en_signal_asserted_p0_p1:assert property(dfi_rddata_en_signal_asserted(dfi_address_p0, dfi_cs_p0, dfi_rddata_en_p0)) + else `uvm_error("DDR Assertions", $sformatf("Relating to dfi_address_p to dfi_rddata_en delay -- trddata_en=%d PHY_CLK cycles", trddata_en)); + */ + dfi_rddata_en_signal_asserted_p0:assert property(dfi_rddata_en_signal_asserted(dfi_address_p0, dfi_cs_p0, dfi_rddata_en_p0, 0)) + else `uvm_error("DDR Assertions", $sformatf("Relating to dfi_address_p to dfi_rddata_en delay -- trddata_en=%d PHY_CLK cycles", trddata_en)); + dfi_rddata_en_signal_asserted_p1:assert property(dfi_rddata_en_signal_asserted(dfi_address_p1, dfi_cs_p1, dfi_rddata_en_p1, dfi_rddata_en_p0)) + else `uvm_error("DDR Assertions", $sformatf("Relating to dfi_address_p to dfi_rddata_en delay -- trddata_en=%d PHY_CLK cycles", trddata_en)); + + + dfi_address_p1_VALID: assert property(dfi_address_valid(dfi_cs_p1, dfi_address_p1)) + else `uvm_error("DDR Assertions", $sformatf("Spacing between dfi_cs_p1 and dfi_address_p1 is not %d",tcmd_lat)); + COV_dfi_address_p1_VALID: cover property(dfi_address_valid(dfi_cs_p1, dfi_address_p1)); + + CS_n_to_dfi_cs_Translation_p1: assert property(CS_n_to_dfi_cs_translation(dfi_cs_p1, CS_DA_o, 1))//$display("CS_n_to_dfi_cs_translation Assertion Passed at time t=%d", $time); + else `uvm_error("DDR Assertions", $sformatf("The dfi_cs_p1 translational delay between DFI interface and JEDEC interface isn't tctrl_delay: %d",tctrl_delay)); + COV_CS_n_to_dfi_cs_Translation_p1:cover property(CS_n_to_dfi_cs_translation(dfi_cs_p1, CS_DA_o, 1)); + + dfi_address_to_CA_delay_p1: assert property(dfi_address_to_CA_translation(dfi_cs_p1, dfi_address_p1, CA_DA_o, 1)) + else `uvm_error("DDR Assertions", $sformatf("The dfi_address_p1 translational delay between DFI interface and JEDEC interface isn't tctrl_delay: %d",tctrl_delay)); + COV_dfi_address_to_CA_delay_p1: cover property(dfi_address_to_CA_translation(dfi_cs_p1, dfi_address_p1, CA_DA_o, 1)); + + dfi_rddata_signal_valid_p1: assert property(dfi_rddata_signal_valid(dfi_rddata_valid_w1, dfi_rddata_w1)) + else `uvm_error("DDR Assertions", $sformatf("dfi_rddata_w1 is sent without dfi_rddata_valid_w1")); + + dfi_rddata_en_to_dfi_rddata_valid_delay_p0:assert property(dfi_rddata_en_to_dfi_rddata_valid_delay(dfi_rddata_en_p0, dfi_rddata_valid_w0)) + else `uvm_error("DDR Assertions", $sformatf("DFI_DR_13 && DFI_DR_16 Failure -- dfi_rddata_en to dfi_rddata_valid delay is not %d", tphy_rdlat)); + dfi_rddata_en_to_dfi_rddata_valid_delay_p1:assert property(dfi_rddata_en_to_dfi_rddata_valid_delay(dfi_rddata_en_p1, dfi_rddata_valid_w1)) + else `uvm_error("DDR Assertions", $sformatf("DFI_DR_13 && DFI_DR_16 Failure -- dfi_rddata_en to dfi_rddata_valid delay is not %d", tphy_rdlat)); +`endif + +`ifdef ratio_1_to_4 +//==========================================================================// +// DFI Properties for 1 to 4 ratio // +//==========================================================================// + /*****************************DFI_DR_1 && DFI_DR_2*******************************************/ + // From plan: command is driven for at least 1 DFI PHY clock cycle after the CS is active. + // tcmd_lat specifies the number of DFI clocks after the dfi_cs signal is asserted until the associated CA signals are driven. + property dfi_address_valid(dfi_cs_px, dfi_address_px); + @(posedge dfi_clk_i) disable iff (!reset_n_i) + !dfi_cs_px |-> (##tcmd_lat !$isunknown(dfi_address_px) [*1:2]); + endproperty: dfi_address_valid + + /*****************************DFI_DR_6*******************************************/ + // From plan: Check the correct behaviour of CS_n on the DRAM interface (follows the behaviour of dfi_cs meaning 0=>1=>0) + // Elaboration: when dfi_cs toggles (1=>0=>1), CS_n should follow the exact same behaviour after translation delay of tctrl_delay + property CS_n_to_dfi_cs_translation(dfi_cs_px, CS_DA_o, phase); //where phase is the phase number + bit CS_tmp; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + ($changed(dfi_cs_px), CS_tmp=dfi_cs_px) ##1 1 |-> ##(4*tctrl_delay+phase) CS_DA_o===CS_tmp; //Working + //**NOTE: Multiplied tctrl_delay by 4 because 1_to_4 ratio; tctrl_delay is 1 dfi_clk cycle. + //**NOTE: added the "##1 1" because the change is detected 1 phy cycle before the negedge of dfi_clk. + //**NOTE: the "phase" accounts for the additional delay added for each phase + endproperty: CS_n_to_dfi_cs_translation + + /*****************************DFI_DR_7 -----NOT IMPLEMENTED BY THE DESIGN YET------*******************************************/ + // From plan: Check the correct behaviour of reset_n on the DRAM interface (follows the behaviour of dfi_reset_n meaning 0=>1=>0) + // Elaboration: when dfi_reset_n toggles, reset_n should follow the exact same behaviour after translation delay of tctrl_delay + /* + property ; + @(posedge dfi_clk_i) + (dfi_reset_n ##1 !dfi_reset_n ##1 dfi_reset_n) |-> (##tctrl_delay (reset_n ##1 !reset_n ##1 reset_n)); + endproperty: + ERR_: assert property(); + */ + + /*****************************DFI_DR_11*******************************************/ + // Translation delay between DFI and JEDEC + property dfi_address_to_CA_translation(dfi_cs_px, dfi_address_px,CA_DA_o, phase); + logic [13:0] CA_temp; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + ($changed(dfi_address_px) , CA_temp=dfi_address_px) ##1 1 |-> ##(4*tctrl_delay+phase) (CA_temp===CA_DA_o); + endproperty: dfi_address_to_CA_translation + + /*****************************DFI_DR_13*******************************************/ + //From Plan: check that valid data is being transferred when the dfi_rddata_valid signal is asserted + property dfi_rddata_signal_valid(dfi_rddata_valid_wx, dfi_rddata_wx); + @(posedge dfi_clk_i) disable iff (!reset_n_i) + dfi_rddata_valid_w0 |-> !$isunknown(dfi_rddata_wx); + endproperty: dfi_rddata_signal_valid + + /*****************************DFI_DR_13 && DFI_DR_16*******************************************/ + // From Plan: dfi_rddata_en is asserted after a RD command by trddata_en DFI_PHY_clock cycles + property dfi_rddata_en_signal_asserted(dfi_address_px, dfi_cs_px, dfi_rddata_en_px, k, a, b, c); + @(posedge dfi_clk_i) disable iff (!reset_n_i) + ( ((dfi_address_px[4:0] == 5'b11101) && !(dfi_cs_px)) |-> ##(k*trddata_en) dfi_rddata_en_px && !(a||b||c) ); //This line encapsulates the 4 lines below; 4 assertions must be used + /* + ( ((dfi_address_p0[4:0] == 5'b11101) && !(dfi_cs_p0)) |-> ##(0*trddata_en) dfi_rddata_en_p2 && !(dfi_rddata_en_p0||dfi_rddata_en_p1) ) //Making sure that no rddata_en is driven before two phy clocks (i.e., phases) + or + ( ((dfi_address_p1[4:0] == 5'b11101) && !(dfi_cs_p1)) |-> ##(0*trddata_en) dfi_rddata_en_p3 && !(dfi_rddata_en_p0||dfi_rddata_en_p1||dfi_rddata_en_p2) ) + or + ( ((dfi_address_p2[4:0] == 5'b11101) && !(dfi_cs_p2)) |-> ##(1*trddata_en) dfi_rddata_en_p0 ) + or + ( ((dfi_address_p3[4:0] == 5'b11101) && !(dfi_cs_p3)) |-> ##(1*trddata_en) dfi_rddata_en_p1 && !(dfi_rddata_en_p0) ); //Must check that dfi_rddata_en_p0 is zero because trddata_en is Measured from the 2nd rising edge of the DFI_command_clock of the command + */ + endproperty: dfi_rddata_en_signal_asserted + + + /*****************************DFI_DR_13 && DFI_DR_16*******************************************/ + // From Plan: asserting on tphy_rdlat + property dfi_rddata_en_to_dfi_rddata_valid_delay(dfi_rddata_en, dfi_rddata_valid); + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + $rose(dfi_rddata_en) |-> ##[0:tphy_rdlat+1] $rose(dfi_rddata_valid) ; + //**NOTE: Added 1 to all timing that envolves an input singal (TB stimulus) AND an output signal (DUT response) + // because we drive on the negative edge, but the DUT's output is on the positive edge + endproperty: dfi_rddata_en_to_dfi_rddata_valid_delay + +//==========================================================================// +// DFI Assertions for 1 to 4 ratio // +//==========================================================================// + dfi_address_VALID_p0: assert property (dfi_address_valid(dfi_cs_p0, dfi_address_p0)) + else `uvm_error("DDR Assertions", $sformatf("Spacing between dfi_cs_p0 and dfi_address_p0 is not %d",tcmd_lat)); + COV_dfi_address_VALID_p0: cover property(dfi_address_valid(dfi_cs_p0, dfi_address_p0)); + + CS_n_to_dfi_cs_Translation_p0: assert property(CS_n_to_dfi_cs_translation(dfi_cs_p0, CS_DA_o, 0)) + else `uvm_error("DDR Assertions", $sformatf("The dfi_cs_p0 translational delay between DFI interface and JEDEC interface isn't tctrl_delay=%d",tctrl_delay+0)); + COV_CS_n_to_dfi_cs_Translation_p0:cover property(CS_n_to_dfi_cs_translation(dfi_cs_p0, CS_DA_o, 0)); + + dfi_address_to_CA_delay_p0: assert property(dfi_address_to_CA_translation(dfi_cs_p0, dfi_address_p0, CA_DA_o, 0)) + else `uvm_error("DDR Assertions", $sformatf("The dfi_address_p0 translational delay between DFI interface and JEDEC interface isn't tctrl_delay=%d --- Sampled CA: ",tctrl_delay+0, $sampled(CA_DA_o))); + COV_dfi_address_to_CA_delay_p0: cover property(dfi_address_to_CA_translation(dfi_cs_p0, dfi_address_p0, CA_DA_o, 0)); + + dfi_rddata_signal_valid_p0: assert property(dfi_rddata_signal_valid(dfi_rddata_valid_w0, dfi_rddata_w0)) + else `uvm_error("DDR Assertions", $sformatf("dfi_rddata_w0 is sent without dfi_rddata_valid_w0")); + /* + dfi_rddata_en_signal_asserted_p0_p1_p2_p3:assert property(dfi_rddata_en_signal_asserted(dfi_address_p0, dfi_cs_p0, dfi_rddata_en_p0)) + else `uvm_error("DDR Assertions", $sformatf("Relating to dfi_address_p to dfi_rddata_en delay -- trddata_en=%d PHY_CLK cycles", trddata_en)); + */ + dfi_rddata_en_signal_asserted_p0:assert property(dfi_rddata_en_signal_asserted(dfi_address_p0, dfi_cs_p0, dfi_rddata_en_p2, 0, dfi_rddata_en_p0, dfi_rddata_en_p1, 0)) + else `uvm_error("DDR Assertions", $sformatf("Relating to dfi_address_p to dfi_rddata_en delay -- trddata_en=%d PHY_CLK cycles", trddata_en)); + dfi_rddata_en_signal_asserted_p1:assert property(dfi_rddata_en_signal_asserted(dfi_address_p1, dfi_cs_p1, dfi_rddata_en_p3, 0, dfi_rddata_en_p0, dfi_rddata_en_p1, dfi_rddata_en_p2)) + else `uvm_error("DDR Assertions", $sformatf("Relating to dfi_address_p to dfi_rddata_en delay -- trddata_en=%d PHY_CLK cycles", trddata_en)); + dfi_rddata_en_signal_asserted_p2:assert property(dfi_rddata_en_signal_asserted(dfi_address_p2, dfi_cs_p2, dfi_rddata_en_p0, 1, 0, 0, 0)) + else `uvm_error("DDR Assertions", $sformatf("Relating to dfi_address_p to dfi_rddata_en delay -- trddata_en=%d PHY_CLK cycles", trddata_en)); + dfi_rddata_en_signal_asserted_p3:assert property(dfi_rddata_en_signal_asserted(dfi_address_p3, dfi_cs_p3, dfi_rddata_en_p1, 1, dfi_rddata_en_p0, 0, 0)) + else `uvm_error("DDR Assertions", $sformatf("Relating to dfi_address_p to dfi_rddata_en delay -- trddata_en=%d PHY_CLK cycles", trddata_en)); + + dfi_address_p1_VALID_p1: assert property(dfi_address_valid(dfi_cs_p1, dfi_address_p1)) + else `uvm_error("DDR Assertions", $sformatf("Spacing between dfi_cs_p1 and dfi_address_p1 is not %d",tcmd_lat)); + COV_dfi_address_p1_VALID_p1: cover property(dfi_address_valid(dfi_cs_p1, dfi_address_p1)); + + dfi_address_p2_VALID_p2: assert property(dfi_address_valid(dfi_cs_p2, dfi_address_p2)) + else `uvm_error("DDR Assertions", $sformatf("Spacing between dfi_cs_p2 and dfi_address_p2 is not %d",tcmd_lat)); + COV_dfi_address_p2_VALID_p2: cover property(dfi_address_valid(dfi_cs_p2, dfi_address_p2)); + + dfi_address_p3_VALID_p3: assert property(dfi_address_valid(dfi_cs_p3, dfi_address_p3)) + else `uvm_error("DDR Assertions", $sformatf("Spacing between dfi_cs_p3 and dfi_address_p3 is not %d",tcmd_lat)); + COV_dfi_address_p3_VALID_p3: cover property(dfi_address_valid(dfi_cs_p3, dfi_address_p3)); + + CS_n_to_dfi_cs_Translation_p1: assert property(CS_n_to_dfi_cs_translation(dfi_cs_p1, CS_DA_o, 1)) + else `uvm_error("DDR Assertions", $sformatf("The dfi_cs_p1 translational delay between DFI interface and JEDEC interface isn't tctrl_delay=%d",tctrl_delay)); + COV_CS_n_to_dfi_cs_Translation_p1:cover property(CS_n_to_dfi_cs_translation(dfi_cs_p1, CS_DA_o, 1));//, 1)); + + CS_n_to_dfi_cs_Translation_p2: assert property(CS_n_to_dfi_cs_translation(dfi_cs_p2, CS_DA_o, 2)) + else `uvm_error("DDR Assertions", $sformatf("The dfi_cs_p2 translational delay between DFI interface and JEDEC interface isn't tctrl_delay=%d",tctrl_delay)); + COV_CS_n_to_dfi_cs_Translation_p2:cover property(CS_n_to_dfi_cs_translation(dfi_cs_p2, CS_DA_o, 2)); + + CS_n_to_dfi_cs_Translation_p3: assert property(CS_n_to_dfi_cs_translation(dfi_cs_p3, CS_DA_o, 3)) + else `uvm_error("DDR Assertions", $sformatf("The dfi_cs_p3 translational delay between DFI interface and JEDEC interface isn't tctrl_delay=%d",tctrl_delay)); + COV_CS_n_to_dfi_cs_Translation_p3:cover property(CS_n_to_dfi_cs_translation(dfi_cs_p3, CS_DA_o, 3)); + + dfi_address_to_CA_delay_p1: assert property(dfi_address_to_CA_translation(dfi_cs_p1, dfi_address_p1, CA_DA_o, 1)) + else `uvm_error("DDR Assertions", $sformatf("The dfi_address_p1 translational delay between DFI interface and JEDEC interface isn't tctrl_delay=%d",tctrl_delay)); + COV_dfi_address_to_CA_delay_p1: cover property(dfi_address_to_CA_translation(dfi_cs_p1, dfi_address_p1, CA_DA_o, 1)); + + dfi_address_to_CA_delay_p2: assert property(dfi_address_to_CA_translation(dfi_cs_p2, dfi_address_p2, CA_DA_o, 2)) + else `uvm_error("DDR Assertions", $sformatf("The dfi_address_p2 translational delay between DFI interface and JEDEC interface isn't tctrl_delay=%d",tctrl_delay)); + COV_dfi_address_to_CA_delay_p2: cover property(dfi_address_to_CA_translation(dfi_cs_p2, dfi_address_p2, CA_DA_o, 2)); + + dfi_address_to_CA_delay_p3: assert property(dfi_address_to_CA_translation(dfi_cs_p3, dfi_address_p3, CA_DA_o, 3)) + else `uvm_error("DDR Assertions", $sformatf("The dfi_address_p3 translational delay between DFI interface and JEDEC interface isn't tctrl_delay=%d",tctrl_delay)); + COV_dfi_address_to_CA_delay_p3: cover property(dfi_address_to_CA_translation(dfi_cs_p3, dfi_address_p3, CA_DA_o, 3)); + + dfi_rddata_signal_valid_p1: assert property(dfi_rddata_signal_valid(dfi_rddata_valid_w1, dfi_rddata_w1)) + else `uvm_error("DDR Assertions", $sformatf("dfi_rddata_w1 is sent without dfi_rddata_valid_w1")); + + dfi_rddata_signal_valid_p2: assert property(dfi_rddata_signal_valid(dfi_rddata_valid_w2, dfi_rddata_w2)) + else `uvm_error("DDR Assertions", $sformatf("dfi_rddata_w2 is sent without dfi_rddata_valid_w2")); + + dfi_rddata_signal_valid_p3: assert property(dfi_rddata_signal_valid(dfi_rddata_valid_w3, dfi_rddata_w3)) + else `uvm_error("DDR Assertions", $sformatf("dfi_rddata_w3 is sent without dfi_rddata_valid_w3")); + + dfi_rddata_en_to_dfi_rddata_valid_delay_p0:assert property(dfi_rddata_en_to_dfi_rddata_valid_delay(dfi_rddata_en_p0, dfi_rddata_valid_w0)) + else `uvm_error("DDR Assertions", $sformatf("DFI_DR_13 && DFI_DR_16 Failure -- dfi_rddata_en to dfi_rddata_valid delay is not %d", tphy_rdlat)); + dfi_rddata_en_to_dfi_rddata_valid_delay_p1:assert property(dfi_rddata_en_to_dfi_rddata_valid_delay(dfi_rddata_en_p1, dfi_rddata_valid_w1)) + else `uvm_error("DDR Assertions", $sformatf("DFI_DR_13 && DFI_DR_16 Failure -- dfi_rddata_en to dfi_rddata_valid delay is not %d", tphy_rdlat)); + dfi_rddata_en_to_dfi_rddata_valid_delay_p2:assert property(dfi_rddata_en_to_dfi_rddata_valid_delay(dfi_rddata_en_p2, dfi_rddata_valid_w2)) + else `uvm_error("DDR Assertions", $sformatf("DFI_DR_13 && DFI_DR_16 Failure -- dfi_rddata_en to dfi_rddata_valid delay is not %d", tphy_rdlat)); + dfi_rddata_en_to_dfi_rddata_valid_delay_p3:assert property(dfi_rddata_en_to_dfi_rddata_valid_delay(dfi_rddata_en_p3, dfi_rddata_valid_w3)) + else `uvm_error("DDR Assertions", $sformatf("DFI_DR_13 && DFI_DR_16 Failure -- dfi_rddata_en to dfi_rddata_valid delay is not %d", tphy_rdlat)); + +`endif + +`endif // This guard turns DFI off to avoid RAM problem on windows + + +task automatic detect_preamble(input bit[2:0]pre_amble) ; + case (pre_amble[2:0]) + 3'b000: begin + //@(posedge dfi_phy_clk_i); + if (DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d -- First edge is not HIGH", pre_amble)); + return; + end + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*result = 1;//Success */ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d -- Second edge is not LOW", pre_amble)); + return; + end + end + 3'b001: begin // 0010 Pattern - in the jedec, this pattern takes 2 tCK, but the design changes DQS + // in the positive edge of the clock only, so it takes 4 tCK + //@(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d -- First edge is not LOW", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d -- 2nd edge is not LOW", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d -- 3rd edge is not HIGH", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*result = 1;//Success */ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d -- 4th edge is not LOW", pre_amble)); + return; + end//result = 0; + end + 3'b010: begin // 1110 Pattern - in the jedec, this pattern takes 2 tCK, but the design changes DQS + // in the positive edge of the clock only, so it takes 4 tCK + //@(posedge dfi_phy_clk_i); + if (DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d -- First edge is not HIGH", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d -- 2nd edge is not HIGH", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d -- 3rd edge is not HIGH", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*result = 1;//Success */ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d -- 4th edge is not LOW", pre_amble)); + return; + end//result = 0; + end + 3'b011: begin // 000010 Pattern - in the jedec, this pattern takes 3 tCK, but the design changes DQS + // in the positive edge of the clock only, so it takes 6 tCK + //@(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*result = 1;//Success */ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + end + 3'b100: begin // 00001010 Pattern - in the jedec, this pattern takes 4 tCK, but the design changes DQS + // in the positive edge of the clock only, so it takes 8 tCK + //@(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (DQS_AD_i) + begin /*Continue*/ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*result = 1;//Success */ end + else + begin + `uvm_error("DDR Assertions", $sformatf("detect_preamble failure -- pre_amble setting is: %d", pre_amble)); + return; + end//result = 0; + end + default: begin + //nothing + end + endcase +endtask +task automatic detect_postamble(input bit post_amble);//, output bit result); + case (post_amble) + 1'b0: begin + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*result = 1;//Success */ end + else + `uvm_error("DDR Assertions", $sformatf("detect_postamble failure -- post_amble setting is: %d", post_amble));//result = 0; //Error + end + 1'b1: begin + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*Continue*/ end + else + `uvm_error("DDR Assertions", $sformatf("detect_postamble failure -- post_amble setting is: %d", post_amble));//result = 0; + @(posedge dfi_phy_clk_i); + if (DQS_AD_i) + begin /*Continue*/ end + else + `uvm_error("DDR Assertions", $sformatf("detect_postamble failure -- post_amble setting is: %d", post_amble));//result = 0; + @(posedge dfi_phy_clk_i); + if (!DQS_AD_i) + begin /*result = 1;//Success */ end + else + `uvm_error("DDR Assertions", $sformatf("detect_postamble failure -- post_amble setting is: %d", post_amble));//result = 0; + end + default: begin + //nothing + end + endcase +endtask + +////==============================================================================// +// Description: The following funtions are used to determine the type of command +//==============================================================================// +function bit is_ACT(); + return CA_DA_o[1:0]===2'b00 && !CS_DA_o; +endfunction +function bit is_RD(); + return CA_DA_o[4:0]===5'b11101 && !CS_DA_o; +endfunction +function bit is_MRW(); + return CA_DA_o[4:0]===5'b00101 && !CS_DA_o; +endfunction +function bit is_MRR(); + return (CA_DA_o[4:0]==5'b10101 && !CS_DA_o); +endfunction +function bit is_PREab(); + return CA_DA_o[4:0]===5'b01011 && !CS_DA_o; +endfunction + +endmodule diff --git a/testbench/interfaces/dfi_assertions.sv b/testbench/interfaces/dfi_assertions.sv new file mode 100644 index 0000000..2cd38bb --- /dev/null +++ b/testbench/interfaces/dfi_assertions.sv @@ -0,0 +1,226 @@ +module dfi_jedec_asserts + #( + parameter Physical_Rank_No = 1, + parameter device_width = 4, + /**************************Timing Parameters*******************************/ + parameter trddata_en = 2, // specify the needed delay as "number of cycles" + parameter tphy_rdlat = 2, + parameter tcmd_lat = 0, + parameter tctrl_delay = 1) +( +// DFI_Interface signals +input logic reset_n_i, +input logic en_i, +input logic dfi_clk, +input logic phycrc_mode_i, +input logic [1:0] dfi_freq_ratio_i, +input logic [13:0] dfi_address_p0, dfi_address_p1,dfi_address_p2,dfi_address_p3, +input logic [Physical_Rank_No-1:0]dfi_cs_p0,dfi_cs_p1,dfi_cs_p2,dfi_cs_p3, +input logic dfi_rddata_en_p0,dfi_rddata_en_p1,dfi_rddata_en_p2,dfi_rddata_en_p3, +input logic dfi_alert_n_a0, dfi_alert_n_a1,dfi_alert_n_a2,dfi_alert_n_a3, +input logic dfi_rddata_valid_w0,dfi_rddata_valid_w1,dfi_rddata_valid_w2,dfi_rddata_valid_w3, +input logic [2*device_width-1:0]dfi_rddata_w0,dfi_rddata_w1,dfi_rddata_w2,dfi_rddata_w3, + +// JEDEC Interface signals +input logic CS_DA_o, +input logic [13:0]CA_DA_o +); + + +//Continue +/**************************************************************************/ + +//==========================================================================// +// Property definitions // +//==========================================================================// + +/*****************************DFI_DR_1 & DFI_DR_2*******************************************/ +// command is driven for at least 1 DFI PHY clock cycle after the CS is active. +// tcmd_lat specifies the number of DFI clocks after the dfi_cs signal is asserted until the associated CA signals are driven. +property dfi_address_valid(dfi_cs_px, dfi_address_px); + @(posedge dfi_clk) + ~dfi_cs_px |-> (##tcmd_lat ~$isunknown(dfi_address_px) [*2]); +endproperty: dfi_address_valid + +/*****************************DFI_DR_6*******************************************/ +// From plan: Check the correct behaviour of CS_n on the DRAM interface (follows the behaviour of dfi_cs meaning 0=>1=>0) +// Elaboration: when dfi_cs toggles (1=>0=>1), CS_n should follow the exact same behaviour after translation delay of tctrl_delay +property CS_n_to_dfi_cs_translation(dfi_cs_px, CS_DA_o); + @(posedge dfi_clk) + (dfi_cs_px ##1 ~dfi_cs_px ##1 dfi_cs_px) |-> (##tctrl_delay (CS_DA_o ##1 ~CS_DA_o ##1 CS_DA_o)); +endproperty: CS_n_to_dfi_cs_translation + +/*****************************DFI_DR_7*******************************************/ +// From plan: Check the correct behaviour of reset_n on the DRAM interface (follows the behaviour of dfi_reset_n meaning 0=>1=>0) +// Elaboration: when dfi_reset_n toggles, reset_n should follow the exact same behaviour after translation delay of tctrl_delay +/*property ; + @(posedge dfi_clk) + (dfi_reset_n ##1 ~dfi_reset_n ##1 dfi_reset_n) |-> (##[tctrl_delay] (reset_n ##1 ~reset_n ##1 reset_n)); +endproperty: +ERR_: assert property();*/ // NOT IMPLEMENTED BY THE DESIGN YET + + +/*****************************DFI_DR_11*******************************************/ +// Translation delay between DFI and JEDEC +property dfi_address_CA_delay(dfi_cs_px, dfi_address_px,CA_DA_o); + int temp; + @(posedge dfi_clk) + ( ~dfi_cs_px && ~$isunknown(dfi_address_px) , temp=dfi_address_px) |-> (##[0:tctrl_delay] (temp==CA_DA_o)); +endproperty: dfi_address_CA_delay +/*property dfi_address_CA_delay ; + @(posedge dfi_clk) //---------THIS IS A WRONG IMPLEMENTATION OF THE ASSERTION-------------// + (~$isunknown(dfi_address_p0) or ~$isunknown(dfi_address_p1) or ~$isunknown(dfi_address_p2) or ~$isunknown(dfi_address_p3)) |-> ##[0:tctrl_delay] ~$isunknown(CA_DA_o); +endproperty: dfi_address_CA_delay*/ + +/*****************************DFI_DR_13*******************************************/ +//From Plan: check that valid data is being transferred when the dfi_rddata_valid signal is asserted +property dfi_rddata_signal_valid(dfi_rddata_valid_wx, dfi_rddata_wx); + @(posedge dfi_clk) + dfi_rddata_valid_w0 |-> ~$isunknown(dfi_rddata_wx); +endproperty: dfi_rddata_signal_valid + +/*****************************DFI_DR_13 & DFI_DR_16*******************************************/ +property dfi_rddata_en_signal_asserted(dfi_address_px, dfi_cs_px, dfi_rddata_en_px); + @(posedge dfi_clk) + ((dfi_address_px[4:0] == 5'b11101) && ~(dfi_cs_px)) |-> (##trddata_en dfi_rddata_en_px); +endproperty: dfi_rddata_en_signal_asserted + +/*****************************DFI_DR_13 & DFI_DR_16*******************************************/ +// From Plan: number of dfi_rddata_en assertion clocks = number of dfi_rddata_valid assertion clocks +property dfi_rddata_valid_match_dfi_rddata_en(dfi_rddata_en_px, dfi_rddata_valid_wx); + @(posedge dfi_clk) + ($rose(dfi_rddata_en_px) |-> ##tphy_rdlat $rose(dfi_rddata_valid_wx)) and ($fell(dfi_rddata_en_px) |-> ##tphy_rdlat $fell(dfi_rddata_valid_wx)); +endproperty: dfi_rddata_valid_match_dfi_rddata_en + + + +//==========================================================================// +// Assertions // +//==========================================================================// + +dfi_address_p0_VALID: assert property(dfi_address_valid(dfi_cs_p0, dfi_address_p0)) + else $error("ERROR"); +COV_dfi_address_p0_VALID: cover property(dfi_address_valid(dfi_cs_p0, dfi_address_p0)); + +CS_n_to_dfi_cs_Translation_p0: assert property(CS_n_to_dfi_cs_translation(dfi_cs_p0, CS_DA_o)) + else $error("ERROR"); +COV_CS_n_to_dfi_cs_Translation_p0:cover property(CS_n_to_dfi_cs_translation(dfi_cs_p0, CS_DA_o)); + +dfi_address_to_CA_delay_p0: assert property(dfi_address_CA_delay(dfi_cs_p0, dfi_address_p0, CA_DA_o)) + else $error("ERROR"); +COV_dfi_address_to_CA_delay_p0: cover property(dfi_address_CA_delay(dfi_cs_p0, dfi_address_p0, CA_DA_o)); + +dfi_rddata_signal_valid_p0: assert property(dfi_rddata_signal_valid(dfi_rddata_valid_w0, dfi_rddata_w0)) + else $error("ERROR"); + +dfi_rddata_en_signal_asserted_p0:assert property(dfi_rddata_en_signal_asserted(dfi_address_p0, dfi_cs_p0, dfi_rddata_en_p0)) + else $error("ERROR"); + +dfi_rddata_valid_match_dfi_rddata_en_p0:assert property(dfi_rddata_valid_match_dfi_rddata_en(dfi_rddata_en_p0, dfi_rddata_valid_w0)) + else $error("DFI_DR_13 & DFI_DR_16 Failure -- dfi_rddata_valid does not match dfi_rddata_en in length after tphy_rdlat"); + +`ifdef ratio_one_to_two + dfi_address_p1_VALID: assert property(dfi_address_valid(dfi_cs_p1, dfi_address_p1)) + else $error("ERROR"); + COV_dfi_address_p1_VALID: cover property(dfi_address_valid(dfi_cs_p1, dfi_address_p1)); + + CS_n_to_dfi_cs_Translation_p1: assert property(CS_n_to_dfi_cs_translation(dfi_cs_p1, CS_DA_o)) // This should be activated only when freq ratio is 1:2 or 1:4 + else $error("ERROR"); + COV_CS_n_to_dfi_cs_Translation_p1:cover property(CS_n_to_dfi_cs_translation(dfi_cs_p1, CS_DA_o)); // This should be activated only when freq ratio is 1:2 or 1:4 + + dfi_address_to_CA_delay_p1: assert property(dfi_address_CA_delay(dfi_cs_p1, dfi_address_p1, CA_DA_o)) + else $error("ERROR"); + COV_dfi_address_to_CA_delay_p1: cover property(dfi_address_CA_delay(dfi_cs_p1, dfi_address_p1, CA_DA_o)); + + dfi_rddata_signal_valid_p1: assert property(dfi_rddata_signal_valid(dfi_rddata_valid_w1, dfi_rddata_w1)) + else $error("ERROR"); + + dfi_rddata_en_signal_asserted_p1:assert property(dfi_rddata_en_signal_asserted(dfi_address_p1, dfi_cs_p1, dfi_rddata_en_p1)) + else $error("ERROR"); + + dfi_rddata_valid_match_dfi_rddata_en_p1:assert property(dfi_rddata_valid_match_dfi_rddata_en(dfi_rddata_en_p1, dfi_rddata_valid_w1)) + else $error("ERROR");$error("DFI_DR_13 & DFI_DR_16 Failure -- dfi_rddata_valid does not match dfi_rddata_en in length after tphy_rdlat"); +`endif + +`ifdef ratio_one_to_four + dfi_address_p1_VALID_p1: assert property(dfi_address_valid(dfi_cs_p1, dfi_address_p1)) + else $error("ERROR"); + COV_dfi_address_p1_VALID_p1: cover property(dfi_address_valid(dfi_cs_p1, dfi_address_p1)); + + dfi_address_p2_VALID_p2: assert property(dfi_address_valid(dfi_cs_p2, dfi_address_p2)) + else $error("ERROR"); + COV_dfi_address_p2_VALID_p2: cover property(dfi_address_valid(dfi_cs_p2, dfi_address_p2)); + + dfi_address_p3_VALID_p3: assert property(dfi_address_valid(dfi_cs_p3, dfi_address_p3)) + else $error("ERROR"); + COV_dfi_address_p3_VALID_p3: cover property(dfi_address_valid(dfi_cs_p3, dfi_address_p3)); + + CS_n_to_dfi_cs_Translation_p1: assert property(CS_n_to_dfi_cs_translation(dfi_cs_p1, CS_DA_o)) // This should be activated only when freq ratio is 1:2 or 1:4 + else $error("ERROR"); + COV_CS_n_to_dfi_cs_Translation_p1:cover property(CS_n_to_dfi_cs_translation(dfi_cs_p1, CS_DA_o)); // This should be activated only when freq ratio is 1:2 or 1:4 + + CS_n_to_dfi_cs_Translation_p2: assert property(CS_n_to_dfi_cs_translation(dfi_cs_p2, CS_DA_o)) // This should be activated only when freq ratio is 1:4 + else $error("ERROR"); + COV_CS_n_to_dfi_cs_Translation_p2:cover property(CS_n_to_dfi_cs_translation(dfi_cs_p2, CS_DA_o)); // This should be activated only when freq ratio is 1:4 + + CS_n_to_dfi_cs_Translation_p3: assert property(CS_n_to_dfi_cs_translation(dfi_cs_p3, CS_DA_o)) // This should be activated only when freq ratio is 1:4 + else $error("ERROR"); + COV_CS_n_to_dfi_cs_Translation_p3:cover property(CS_n_to_dfi_cs_translation(dfi_cs_p3, CS_DA_o)); // This should be activated only when freq ratio is 1:4 + + dfi_address_to_CA_delay_p1: assert property(dfi_address_CA_delay(dfi_cs_p1, dfi_address_p1, CA_DA_o)) + else $error("ERROR"); + COV_dfi_address_to_CA_delay_p1: cover property(dfi_address_CA_delay(dfi_cs_p1, dfi_address_p1, CA_DA_o)); + + dfi_address_to_CA_delay_p2: assert property(dfi_address_CA_delay(dfi_cs_p2, dfi_address_p2, CA_DA_o)) + else $error("ERROR"); + COV_dfi_address_to_CA_delay_p2: cover property(dfi_address_CA_delay(dfi_cs_p2, dfi_address_p2, CA_DA_o)); + + dfi_address_to_CA_delay_p3: assert property(dfi_address_CA_delay(dfi_cs_p3, dfi_address_p3, CA_DA_o)) + else $error("ERROR"); + COV_dfi_address_to_CA_delay_p3: cover property(dfi_address_CA_delay(dfi_cs_p3, dfi_address_p3, CA_DA_o)); + + dfi_rddata_signal_valid_p1: assert property(dfi_rddata_signal_valid(dfi_rddata_valid_w1, dfi_rddata_w1)) + else $error("ERROR"); + + dfi_rddata_signal_valid_p2: assert property(dfi_rddata_signal_valid(dfi_rddata_valid_w2, dfi_rddata_w2)) + else $error("ERROR"); + + dfi_rddata_signal_valid_p3: assert property(dfi_rddata_signal_valid(dfi_rddata_valid_w3, dfi_rddata_w3)) + else $error("ERROR"); + + dfi_rddata_en_signal_asserted_p1:assert property(dfi_rddata_en_signal_asserted(dfi_address_p1, dfi_cs_p1, dfi_rddata_en_p1)) + else $error("ERROR"); + + dfi_rddata_en_signal_asserted_p2:assert property(dfi_rddata_en_signal_asserted(dfi_address_p2, dfi_cs_p2, dfi_rddata_en_p2)) + else $error("ERROR"); + + dfi_rddata_en_signal_asserted_p3:assert property(dfi_rddata_en_signal_asserted(dfi_address_p3, dfi_cs_p3, dfi_rddata_en_p3)) + else $error("ERROR"); + + dfi_rddata_valid_signal_dfi_rddata_en_p1:assert property(dfi_rddata_valid_match_dfi_rddata_en(dfi_rddata_en_p1, dfi_rddata_valid_w1)) + else $error("ERROR");$error("DFI_DR_13 & DFI_DR_16 Failure -- dfi_rddata_valid does not match dfi_rddata_en in length after tphy_rdlat"); + + dfi_rddata_valid_signal_dfi_rddata_en_p2:assert property(dfi_rddata_valid_match_dfi_rddata_en(dfi_rddata_en_p2, dfi_rddata_valid_w2)) + else $error("ERROR");$error("DFI_DR_13 & DFI_DR_16 Failure -- dfi_rddata_valid does not match dfi_rddata_en in length after tphy_rdlat"); + + dfi_rddata_valid_signal_dfi_rddata_en_p3:assert property(dfi_rddata_valid_match_dfi_rddata_en(dfi_rddata_en_p3, dfi_rddata_valid_w3)) + else $error("ERROR");$error("DFI_DR_13 & DFI_DR_16 Failure -- dfi_rddata_valid does not match dfi_rddata_en in length after tphy_rdlat"); +`endif + + +/*****************************DFI_DR_13 & DFI_DR_16******************************************* +property dfi_rddata_valid_signal_asserted ; + @(posedge dfi_clk) + dfi_rddata_en_p0 |-> ##[0:tphy_rdlat] dfi_rddata_valid_w0; + dfi_rddata_en_p1 |-> ##[0:tphy_rdlat] dfi_rddata_valid_w1; + dfi_rddata_en_p2 |-> ##[0:tphy_rdlat] dfi_rddata_valid_w2; + dfi_rddata_en_p3 |-> ##[0:tphy_rdlat] dfi_rddata_valid_w3; + +endproperty: dfi_rddata_valid_signal_asserted + +ERR_dfi_rddata_valid_signal_not_asserted: assert property(dfi_rddata_valid_signal_asserted); // CONSIDER REMOVING: THIS IS DISABLED CUZ THE ONE ABOVE IT DOES THE SAME JOB +*/ + + + +endmodule diff --git a/testbench/interfaces/dfi_intf.sv b/testbench/interfaces/dfi_intf.sv new file mode 100644 index 0000000..4ec2d59 --- /dev/null +++ b/testbench/interfaces/dfi_intf.sv @@ -0,0 +1,40 @@ +interface dfi_intf(input logic dfi_clk); + + parameter Physical_Rank_No = 1; + parameter device_width = 4; + logic reset_n_i; + logic en_i; + logic phycrc_mode_i; + logic [1:0] dfi_freq_ratio_i; + logic [13:0] dfi_address_p0; + logic [13:0] dfi_address_p1; + logic [13:0] dfi_address_p2; + logic [13:0] dfi_address_p3; + logic [Physical_Rank_No-1:0 ] dfi_cs_p0; + logic [Physical_Rank_No-1:0 ] dfi_cs_p1; + logic [Physical_Rank_No-1:0 ] dfi_cs_p2; + logic [Physical_Rank_No-1:0 ] dfi_cs_p3; + logic dfi_rddata_en_p0; + logic dfi_rddata_en_p1; + logic dfi_rddata_en_p2; + logic dfi_rddata_en_p3; + logic dfi_alert_n_a0; + logic dfi_alert_n_a1; + logic dfi_alert_n_a2; + logic dfi_alert_n_a3; + logic dfi_rddata_valid_w0; + logic dfi_rddata_valid_w1; + logic dfi_rddata_valid_w2; + logic dfi_rddata_valid_w3; + logic [2*device_width-1:0] dfi_rddata_w0; + logic [2*device_width-1:0] dfi_rddata_w1; + logic [2*device_width-1:0] dfi_rddata_w2; + logic [2*device_width-1:0] dfi_rddata_w3; + + clocking cb_D @(posedge dfi_clk); + //Drive on negedge -- Sample at #1step + default input #1step output negedge; + input dfi_alert_n_a0, dfi_alert_n_a1,dfi_alert_n_a2,dfi_alert_n_a3, dfi_rddata_valid_w0,dfi_rddata_valid_w1,dfi_rddata_valid_w2,dfi_rddata_valid_w3, dfi_rddata_w0,dfi_rddata_w1,dfi_rddata_w2,dfi_rddata_w3; + output reset_n_i, en_i, phycrc_mode_i, dfi_freq_ratio_i, dfi_address_p0, dfi_address_p1,dfi_address_p2,dfi_address_p3, dfi_cs_p0,dfi_cs_p1,dfi_cs_p2,dfi_cs_p3, dfi_rddata_en_p0,dfi_rddata_en_p1,dfi_rddata_en_p2,dfi_rddata_en_p3; + endclocking +endinterface \ No newline at end of file diff --git a/testbench/interfaces/jedec_assertion.sv b/testbench/interfaces/jedec_assertion.sv new file mode 100644 index 0000000..567e337 --- /dev/null +++ b/testbench/interfaces/jedec_assertion.sv @@ -0,0 +1,500 @@ +// TODO Preamble +// TODO Interamble +// TO postpremble + +module dfi_jedec_asserts + #( + parameter device_width = 4, + /**************************Timing Parameters*******************************/ + parameter tMRW = 2, // specify the needed delay as "number of cycles" + parameter tMRR = 2, + parameter tMRD = 2, + parameter tRP = 1, + parameter tCMD_cancel = 1, + parameter tRRD_S = 1, + parameter tRRD_L = 1, + parameter RL = 5 + + + ) +( + // JEDEC Interface + input logic dfi_phy_clk, + input logic [13:0] CA_DA_o, + input logic CS_DA_o, + input logic CA_VALID_DA_o, + input logic DQS_AD_i, + input logic [2*device_width-1:0] DQ_AD_i +); + + +//------------------------------------------------------------------------------------------------------------- +//------------------------------------------------Property definitions----------------------------------------- +//------------------------------------------------------------------------------------------------------------- + +/************************************************JEDEC_DR_1**&**JEDEC_DR_2*******************************************/ + +// The mode register contents are available on the second 8 UI’s of the burst and are repeated across all DQ’s after the RL following the MRR command +/*property MRR_DATA_spacings ; + logic [1:0] x; + @(posedge dfi_phy_clk) + ((CA_DA_o[4:0] == 5'b10101) |->(##RL DQ_AD_i[1:0] == 2'b00 ##4 x = DQ_AD_i[1:0]) and + (##RL DQ_AD_i[3:2] == 2'b11 ##4 DQ_AD_i[3:2] != x) and + (##RL DQ_AD_i[5:4] == 2'b00 ##4 DQ_AD_i[5:4] == x) and + (##RL DQ_AD_i[7:6] == 2'b11 ##4 DQ_AD_i[7:6] != x)); +endproperty: MRR_DATA_spacings +*/ +property MRR_DATA_spacings ; + @(posedge dfi_phy_clk) + (CA_DA_o[4:0] == 5'b10101) |-> ##(RL+1+4) (DQ_AD_i[1:0] == !DQ_AD_i[3:2]) and + (DQ_AD_i[1:0] == DQ_AD_i[5:4]) and + (DQ_AD_i[1:0] == !DQ_AD_i[7:6]); +endproperty: MRR_DATA_spacings +property MRR_DATA_spacings_ZEROs_ONEs ; + @(posedge dfi_phy_clk) + (CA_DA_o[4:0] == 5'b10101) |-> ##(RL+1) ( (DQ_AD_i[1:0] == 2'b00) & (DQ_AD_i[3:2] == 2'b11) & (DQ_AD_i[5:4] == 2'b00) & (DQ_AD_i[7:6] == 2'b11) ) + ##1 ( (DQ_AD_i[1:0] == 2'b00) & (DQ_AD_i[3:2] == 2'b11) & (DQ_AD_i[5:4] == 2'b00) & (DQ_AD_i[7:6] == 2'b11) ) + ##1 ( (DQ_AD_i[1:0] == 2'b00) & (DQ_AD_i[3:2] == 2'b11) & (DQ_AD_i[5:4] == 2'b00) & (DQ_AD_i[7:6] == 2'b11) ) + ##1 ( (DQ_AD_i[1:0] == 2'b00) & (DQ_AD_i[3:2] == 2'b11) & (DQ_AD_i[5:4] == 2'b00) & (DQ_AD_i[7:6] == 2'b11) ); +endproperty: MRR_DATA_spacings + +/************************************************JEDEC_DR_3*******************************************/ +// From Plan: DQS is toggled for the duration of the MRR burst. --> DQS is toggled for 16 BL +property MRR_DQS_toggle ; + @(posedge dfi_phy_clk) + (CA_DA_o[0:4] == 5'b10101) |-> ##(RL+1) ( ($changed(DQS_AD_i))[=1] )[*16]; +endproperty: MRR_DQS_toggle + +/************************************************JEDEC_DR_7*******************************************/ +// From Plan: The read pre-amble and post-amble of MRR are same as normal read. +property MRR_preamble; + bit result; + @(posedge dfi_phy_clk) + (!CS_DA_o & CA_DA_o[4:0] == 5'b11101 , result=0) |-> ##(RL+1-tRPRE) (1, detect_preamble(pre_amble, result)) ##0 result; +endproperty: MRR_preamble +property MRR_postamble; + bit result; + @(posedge dfi_phy_clk) + (!CS_DA_o & CA_DA_o[4:0] == 5'b11101 , result=0) |-> ##(RL+1+tRPRE+8) (1, detect_postamble(post_amble, result)) ##0 result; //burst_length is always 8 for MRR +endproperty: MRR_postamble + +/************************************************JEDEC_DR_8*******************************************/ +// Elaboration: spacing between MRR CMD and any other CMD is tMRR +// Timing between MRR and MRW is CL+BL/2+1 : not implemented yet +property MRR_CMD_spacings ; + @(posedge dfi_phy_clk) +((CA_DA_o[4:0] == 5'b10101) |-> ##1 CS_DA_o [*tMRR]); +endproperty: MRR_CMD_spacings + +/************************************************JEDEC_DR_8*******************************************/ +// Elaboration: spacing between two MRW CMDs is tMRW and any other CMD is tMRR +property MRW_CMD_spacings ; + @(posedge dfi_phy_clk) +((CA_DA_o[4:0] == 5'b00101) |-> ##1 ((CS_DA_o [*tMRW:tMRD] ##1 CA_DA_o[4:0] == 5'b00101) or CS_DA_o [*tMRD])) ; +endproperty: MRW_CMD_spacings + +/************************************************JEDEC_DR_11*******************************************/ +// Elaboration: spacing between PRE CMDs and MRR/MRW is tRP +property PRE_CMD_spacings ; + @(posedge dfi_phy_clk) + ((CA_DA_o[4:0] == 5'b01011) |-> ##1 (CS_DA_o [*tRP] ##1 ((CA_DA_o[4:0] == 5'b00101) || (CA_DA_o[4:0] == 5'b10101)))) ; + endproperty: PRE_CMD_spacings + +/************************************************JEDEC_DR_12*******************************************/ +//When a defined register byte (MR#) contains an “RFU” bit, the host must write a ZERO for those specific bits +property host_Write_zero_to_RFU ; + @(posedge dfi_phy_clk) +(CA_DA_o[4:0] == 5'b00101 & CA_DA_o[12:5] == 0 |=> CA_DA_o[7] == 0) and +(CA_DA_o[4:0] == 5'b00101 & CA_DA_o[12:5] == 8'h08 |=> CA_DA_o[5] == 0) and +(CA_DA_o[4:0] == 5'b00101 & CA_DA_o[12:5] == 8'h28 |=> CA_DA_o[7:3] ==0); +endproperty: host_Write_zero_to_RFU + +/************************************************JEDEC_DR_13*******************************************/ +//When the host issues an MRR to a defined register (MR#) that contains RFU bits in it, those specific bits shall always produce a ZERO. +property host_Read_zero_from_RFU ; + @(posedge dfi_phy_clk) +(CA_DA_o[4:0] == 5'b10101 & CA_DA_o[12:5] == 8'h00 & ~CS_DA_o |-> ##(RL+1+3) DQ_AD_i[1:0] == 2'bx0) and +(CA_DA_o[4:0] == 5'b10101 & CA_DA_o[12:5] == 8'h08 & ~CS_DA_o |-> ##(RL+1+2) DQ_AD_i[1:0] == 2'bx0) ; +endproperty: host_Read_zero_from_RFU + +/*****************************JEDEC_DR_17*******************************************/ +//From Plan: Check that the preamble and postamble is equal to the value written in MR8 +int tRPRE; +always_comb begin + case (pre_amble) + 000: tRPRE = 2; + 001: tRPRE = 4; + 010: tRPRE = 4; + 011: tRPRE = 6; + 100: tRPRE = 8; + default: tRPRE = 2; + endcase +end +property RD_preamble; + bit result; + @(posedge dfi_phy_clk) + (!CS_DA_o & CA_DA_o[4:0] == 5'b11101 , result=0) |-> ##(RL+1-tRPRE) (1, detect_preamble(pre_amble, result)) ##0 result; +endproperty: RD_preamble +property RD_postamble; + bit result; + @(posedge dfi_phy_clk) + (!CS_DA_o & CA_DA_o[4:0] == 5'b11101 , result=0) |-> ##(RL+1+tRPRE+burst_length/2) (1, detect_postamble(post_amble, result)) ##0 result; +endproperty: RD_postamble + +/************************************************JEDEC_DR_21*******************************************/ +// The minimum timing between a cancelled CMD and the following CMD is tCMD_cancel +property CMD_Cancel_timing ; + @(posedge dfi_phy_clk) +(!CS_DA_o[*2] ##tCMD_cancel !CS_DA_o ##1 CS_DA_o); +endproperty: CMD_Cancel_timing + + +/************************************************JEDEC_DR_24*******************************************/ +// Once a bank has been precharged, it is in the idle state and must be activated prior to any READ or WRITE commands being issued to that bank +property Pre_then_ACT ; + @(posedge dfi_phy_clk) +((CA_DA_o[4:0] == 5'b11011 ##[0:$] CA_DA_o[4:0] == 5'b11101) or +( CA_DA_o[4:0] == 5'b11011 ##[0:$] CA_DA_o[4:0] == 5'b00101) or +( CA_DA_o[4:0] == 5'b11011 ##[0:$] CA_DA_o[4:0] == 5'b10101)) |-> 0; +endproperty: Pre_then_ACT + +/************************************************JEDEC_DR_25***&**JEDEC_DR_31*******************************************/ +// A PRECHARGE command is allowed if there is no open row in that bank (idle state) or if the previously open row is already in the process of precharging. +property ACT_then_Pre_no_allowed ; + @(posedge dfi_phy_clk) +((CA_DA_o[1:0] == 2'b00 ##[0:$] CA_DA_o[4:0] == 5'b11011) +( CA_DA_o[1:0] == 2'b00 ##[0:$] CA_DA_o[4:0] == 5'b00101) +( CA_DA_o[1:0] == 2'b00 ##[0:$] CA_DA_o[4:0] == 5'b10101)) |-> 0; +endproperty: ACT_then_Pre_no_allowed + +/************************************************JEDEC_DR_28***&**JEDEC_DR_29*******************************************/ +// tRRD_S (short) is used for timing between banks located in different bank groups. +// tRRD_L (long) is used for timing between banks located in the same bank group. +property Different_AND_Same_bank_group_ACT_timing ; + logic [2:0] temp; + @(posedge dfi_phy_clk) +(((CA_DA_o[1:0] == 2'b00), temp = CA_DA_o[10:8]) |-> ##1 (CS_DA_o [*tRRD_S] or (CS_DA_o [*tRRD_L] ##1 CA_DA_o[10:8] == temp))); + +endproperty: Different_AND_Same_bank_group_ACT_timing + + +/************************************************JEDEC_DR_31*******************************************/ +//Read Latency (RL or CL) is defined from the Read command to data and is not affected by the Read DQS offset timing (MR40 OP[2:0]). +property RDCMD_TO_DATA_DELAY ; + @(posedge dfi_phy_clk) +(CA_DA_o[4:0] == 5'b11101 & ~CS_DA_o |-> ##(RL+1) ~$isunknown(DQ_AD_i)); +endproperty: RDCMD_TO_DATA_DELAY + +/************************************************JEDEC_DR_32************************************************/ +// From Plan: "If CA5:BL*=L, the command places the DRAM into the alternate Burst mode described by MR0[1:0] instead of the default Burst Length 16 mode." +property ; + @(posedge dfi_phy_clk) + (CA_DA_o[4:0] == 5'b11101 || CA_DA_o[4:0] == 5'b10101) & ~CS_DA_o +endproperty: + + + +/************************************************JEDEC_DR_36************************************************/ +//The minimum external Read command to Precharge command spacing to the same bank is equal to tRTP with tRTP being the Internal Read Command to Precharge Command Delay. +property RDToPreSpacing ; + logic [2:0] temp; + @(posedge dfi_phy_clk) +(((CA_DA_o[4:0] == 5'b11101), temp = CA_DA_o[7:6]) |-> ##1 (CS_DA_o [*tRTP] ##1 (CA_DA_o[4:0] == 5'b01011) & CA_DA_o[7:6] == temp)); +endproperty: RDToPreSpacing + + + +/************************************************JEDEC_DR_37************************************************/ +// the minimum ACT to PRE timing, tRAS, must be satisfied as well +// the implemetation of this assertion is not correct +property PreToACTSpacing ; +logic temp; + @(posedge dfi_phy_clk) +((CA_DA_o[4:0] == 5'b01011) |-> ##1 (CS_DA_o [*tRAS] ##1 (CA_DA_o[4:0] == 5'b01011))) & +((CA_DA_o[4:0] == 5'b01011) |-> ##1 (CS_DA_o [*tRAS] ##1 (CA_DA_o[4:0] == 5'b01011))) ; +endproperty: PreToACTSpacing + +/************************************************JEDEC_DR_37************************************************/ +// A dummy RD command is required for the second half of the transfer with a delay of 8 clocks from the first RD command in case of BL32 fixed or BL32 OTF + +property DummyRDCMD ; +logic temp = BL; + @(posedge dfi_phy_clk) +(((CA_DA_o[4:0] == 5'b11101), (temp == BL32), ~CS_DA_o, ##1 CA_DA_o[10]== 1) |-> ##8 (~CS_DA_o & (CA_DA_o[4:0] == 5'b11101 & ##1 CA_DA_o[10] == 0))); +endproperty: DummyRDCMD + +property C10_IS_opposite ; +logic temp = BL; +logic C10; + @(posedge dfi_phy_clk) + (((CA_DA_o[4:0] == 5'b11101), (temp == BL32), ~CS_DA_o, ##1 (C10 = CA_DA_o[8] & CA_DA_o[10]== 1)) |-> ##8 (~CS_DA_o & (CA_DA_o[4:0] == 5'b11101) & ##1 (CA_DA_o[8] == ~C10 & CA_DA_o[10]== 0))); + +endproperty: C10_IS_opposite + + +property SecondRD_resembles_first ; +logic temp = BL; +logic [13:0] first_temp_CMD; +logic [13:0] second_temp_CMD; + + @(posedge dfi_phy_clk) + (((CA_DA_o[4:0] == 5'b11101), (temp == BL32), ~CS_DA_o, first_temp_CMD = CA_DA_o[13:0], ##1 (second_temp_CMD = CA_DA_o[13:0] & CA_DA_o[10]== 1)) + |-> ##8 (~CS_DA_o & (CA_DA_o[13:0] == first_temp_CMD) & ##1 CA_DA_o[7:0] == second_temp_CMD[7:0] & CA_DA_o[13:11] == second_temp_CMD[13:11] & CA_DA_o[9] == second_temp_CMD[9] & CA_DA_o[10]== 0)); + +endproperty: SecondRD_resembles_first + +property BL16InBL32 ; +logic temp = BL; + @(posedge dfi_phy_clk) + (((CA_DA_o[4:0] == 5'b11101), (temp == BL32), ~CS_DA_o, ##1 CA_DA_o[10]== 0) ##8 ~ |-> 0; +endproperty: BL16InBL32 + +property ReadTOReadSameBank ; + logic [3:0] temp; + @(posedge dfi_phy_clk) +(((CA_DA_o[1:0] == 5'b11101), temp = CA_DA_o[10:6]) |-> ##1 (CS_DA_o[*tCCD_S] or (CS_DA_o [*tRRD_L] ##1 CA_DA_o[10:8] == temp))); + +endproperty: ReadTOReadSameBank + + + +//------------------------------------------------------------------------------------------------------------- +//------------------------------------------------Assertions----------------------------------------- +//------------------------------------------------------------------------------------------------------------- +/*Spacing_btn_MRR_Data: assert property(MRR_DATA_spacings) + else $error("ERROR: Data should be available on 8 UI's RL after MRR CMD"); +COV_Spacing_btn_MRR_Data: cover property(MRR_DATA_spacings); +*/// +Spacing_btn_MRR_CMD: assert property(MRR_CMD_spacings) + else $error("ERROR: Spacing between MRR CMD and any other CMD should be tMRR"); +COV_Spacing_btn_MRR_CMD: cover property(MRR_CMD_spacings); +// +Spacing_btn_MRW_CMD: assert property(MRW_CMD_spacings) + else $error("ERROR: Spacing between two MRW CMDs is tMRW and any other CMD should tMRR"); +COV_Spacing_btn_MRW_CMD: cover property(MRW_CMD_spacings); +// +Spacing_btn_PRE_MRR: assert property(PRE_CMD_spacings) + else $error("ERROR: Spacing between PRE CMDs and MRR/MRW should be tRP"); +COV_Spacing_btn_PRE_MRR: cover property(PRE_CMD_spacings); +// +host_should_Write_zero_to_RFU: assert property(host_Write_zero_to_RFU) + else $error("ERROR: “RFU” bits must be written ZERO by the host"); +COV_host_should_Write_zero_to_RFU: cover property(host_Write_zero_to_RFU); +// +host_should_Read_zero_from_RFU: assert property(host_Read_zero_from_RFU) + else $error("RFU bits shall always produce a ZERO when it's being read"); +COV_host_should_Read_zero_from_RFU: cover property(host_Read_zero_from_RFU); +// +timing_btn_Canceled_CMD: assert property(CMD_Cancel_timing) + else $error("ERROR: The minimum timing between a cancelled CMD and the following CMD should be tCMD_cancel"); +COV_timing_btn_Canceled_CMD: cover property(CMD_Cancel_timing); +// +ACT_Should_follow_PRE: assert property(Pre_then_ACT) + else $error("ERROR: a bank must be activated prior to any READ or WRITE commands being issued to that bank"); +COV_ACT_Should_follow_PRE: cover property(Pre_then_ACT); +// +PRE_Mustnt_follow_ACT: assert property(ACT_then_Pre_no_allowed) + else $error("ERROR: Precharge CMD mustn't follow activate CMD directely"); +COV_PRE_Mustnt_follow_ACT: cover property(ACT_then_Pre_no_allowed); +// +Timing_btn_several_ACT_CMDs: assert property(Different_AND_Same_bank_group_ACT_timing) + else $error("ERROR: timing between banks located in different bank groups should be tRRD_S while timing between banks located in the same bank group should be tRRD_L"); +COV_Timing_btn_several_ACT_CMDs: cover property(Different_AND_Same_bank_group_ACT_timing); +// +Four_ACT_CMD_withen_tFAW: assert property(Max_timing_for_four_ACT_CMD) + else $error("ERROR: // Spec: Consecutive ACTIVATE commands, allowed to be issued at tRRDmin, are restricted to a maximum of four within the time period tFAW (four activate window)."); +COV_Four_ACT_CMD_withen_tFAW: cover property(Max_timing_for_four_ACT_CMD); +// + + +endmodule +/* +function bit is_RD_MRR(); //Check if the command is RD or MRR + bit r; + r = (CA_DA_o[0:4] == 5'b10101) || (CA_DA_o[0:4] == 5'b10111); + return r; +endfunction +*/ + +task detect_preamble(input bit[2:0]pre_amble, output bit result); + case (pre_amble[2:0]) + 3'b000: begin + @(posedge dfi_phy_clk); + if (DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + result = 1;//Success + else + result = 0; + end + 3'b001: begin // 0010 Pattern - in the jedec, this pattern takes 2 tCK, but the design changes DQS + // in the positive edge of the clock only, so it takes 4 tCK + forever begin + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + result = 1;//Success + else + result = 0; + end + end + 3'b010: begin // 1110 Pattern - in the jedec, this pattern takes 2 tCK, but the design changes DQS + // in the positive edge of the clock only, so it takes 4 tCK + forever begin + @(posedge dfi_phy_clk); + if (DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + result = 1;//Success + else + result = 0; + end + end + 3'b011: begin // 000010 Pattern - in the jedec, this pattern takes 3 tCK, but the design changes DQS + // in the positive edge of the clock only, so it takes 6 tCK + forever begin + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + result = 1;//Success + else + result = 0; + end + end + 3'b100: begin // 00001010 Pattern - in the jedec, this pattern takes 4 tCK, but the design changes DQS + // in the positive edge of the clock only, so it takes 8 tCK + forever begin + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + result = 1;//Success + else + result = 0; + end + end + default: begin + //nothing + end + endcase +endtask +task detect_postamble(input bit post_amble, output bit result); + case (post_amble) + 1'b0: begin + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + result = 1; //Success + else + result = 0; //Error + end + 1'b1: begin + forever begin + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (DQS_AD_i) + //Continue + else + result = 0; + @(posedge dfi_phy_clk); + if (!DQS_AD_i) + result = 1;//Success + else + result = 0; + end + end + default: begin + //nothing + end + endcase +endtask diff --git a/testbench/interfaces/jedec_intf.sv b/testbench/interfaces/jedec_intf.sv new file mode 100644 index 0000000..029d714 --- /dev/null +++ b/testbench/interfaces/jedec_intf.sv @@ -0,0 +1,17 @@ +interface jedec_intf(input logic dfi_phy_clk); + + parameter device_width = 4; + + logic [13:0] CA_DA_o; + logic CS_DA_o; + logic CA_VALID_DA_o; + logic DQS_AD_i; + logic [2*device_width-1:0] DQ_AD_i; + + clocking cb_J @(posedge dfi_phy_clk); + //Drive on negedge -- Sample at #1step + default input #1step output negedge; + input CA_DA_o, CS_DA_o, CA_VALID_DA_o; + output DQS_AD_i, DQ_AD_i; + endclocking +endinterface diff --git a/testbench/interfaces/tmp_assertions.sv b/testbench/interfaces/tmp_assertions.sv new file mode 100644 index 0000000..15af5fb --- /dev/null +++ b/testbench/interfaces/tmp_assertions.sv @@ -0,0 +1,36 @@ + + +//############################################################################################################## +/*****************************DFI_DR_1 & DFI_DR_2*******************************************/ +//----------------------------------------------ONE TO ONE---------------------------------------------- +// From plan: command is driven for at least 1 DFI PHY clock cycle after the CS is active. +// tcmd_lat specifies the number of DFI clocks after the dfi_cs signal is asserted until the associated CA signals are driven. +property dfi_address_valid(dfi_cs_px, dfi_address_px); + @(posedge dfi_clk_i) disable iff (!reset_n_i) + ~dfi_cs_px |-> (##tcmd_lat ~$isunknown(dfi_address_px) [*1:2]); +endproperty: dfi_address_valid + + +//----------------------------------------------ONE TO TWO---------------------------------------------- +//The same property will work according to FIGURE 28. in DFI: second WR command is initiated in phase1 +/*****************************END OF PROPERTY**************************************************/ + + + +/*****************************DFI_DR_6*******************************************/ +//----------------------------------------------ONE TO ONE---------------------------------------------- +// From plan: Check the correct behaviour of CS_n on the DRAM interface (follows the behaviour of dfi_cs meaning 0=>1=>0) +// Elaboration: when dfi_cs toggles (1=>0=>1), CS_n should follow the exact same behaviour after translation delay of tctrl_delay +property CS_n_to_dfi_cs_translation(dfi_cs_px, CS_DA_o); + bit CS_tmp; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + ($changed(dfi_cs_px),CS_tmp=dfi_cs_px) |-> ##tctrl_delay CS_DA_o==CS_tmp; +endproperty: CS_n_to_dfi_cs_translation + +//----------------------------------------------ONE TO TWO---------------------------------------------- +property CS_n_to_dfi_cs_translation(dfi_cs_px, CS_DA_o, x); + bit CS_tmp; + @(posedge dfi_phy_clk_i) disable iff (!reset_n_i) + ($changed(dfi_cs_px),CS_tmp=dfi_cs_px) |-> ##(tctrl_delay+x) CS_DA_o==CS_tmp; //where x is the phase number +endproperty: CS_n_to_dfi_cs_translation +/*****************************END OF PROPERTY**************************************************/ diff --git a/testbench/sequences/ACT_seq.sv b/testbench/sequences/ACT_seq.sv new file mode 100644 index 0000000..9c73e3d --- /dev/null +++ b/testbench/sequences/ACT_seq.sv @@ -0,0 +1,41 @@ +/***************************** ACT Sequence Description **************************** + +Class : ACT_seq +Description : This sequence performs a ACT command + +************************************************************************************/ + +class ACT_seq extends base_seq; + function new(string name="ACT_seq"); + super.new(name); + endfunction + + `uvm_object_utils(ACT_seq) + + ddr_sequence_item des_item, next_item; + + task pre_body(); + des_item = ddr_sequence_item::type_id::create ("des_item"); + next_item = ddr_sequence_item::type_id::create ("next_item"); + assert (next_item.randomize() with { + next_item.CMD_prev == local::CMD_prev; + next_item.max_tCCD == local::max_tCCD; + next_item.CMD == ACT; //ACT + }) + else `uvm_fatal("ACT_seq", "ACT_seq randomization failed"); + endtask + + task body(); + + `uvm_info("ACT_seq", $sformatf("This CMD = %p, CMD_prev = %p, tCCD = %p, %t",next_item.CMD, CMD_prev, next_item.tCCD, $time),UVM_MEDIUM); + + repeat (next_item.tCCD - 2) begin //(tCCD - 2) is the nummber of actuad DES bet CMDs to account for true tCCD bet. CMDs + start_item (des_item); + des_item.CMD = DES; + finish_item (des_item); + end + + start_item (next_item); + finish_item (next_item); + endtask +endclass diff --git a/testbench/sequences/ACT_seq_corners.sv b/testbench/sequences/ACT_seq_corners.sv new file mode 100644 index 0000000..7ca8e1c --- /dev/null +++ b/testbench/sequences/ACT_seq_corners.sv @@ -0,0 +1,43 @@ +/***************************** ACT Sequence Description **************************** + +Class : ACT_seq_corners +Description : This sequence performs a ACT command + +************************************************************************************/ + +class ACT_seq_corners extends base_seq; + function new(string name="ACT_seq_corners"); + super.new(name); + endfunction + + `uvm_object_utils(ACT_seq_corners) + + ddr_sequence_item des_item, next_item; + + task pre_body(); + des_item = ddr_sequence_item::type_id::create ("des_item"); + next_item = ddr_sequence_item::type_id::create ("next_item"); + assert (next_item.randomize() with { + next_item.CMD_prev == local::CMD_prev; + next_item.max_tCCD == local::max_tCCD; + next_item.CMD == ACT; + next_item.ROW inside {2**18-1,0}; + next_item.Col inside {2**9-1,0}; //ACT + }) + else `uvm_fatal("ACT_seq_corners", "ACT_seq_corners randomization failed"); + endtask + + task body(); + + `uvm_info("ACT_seq_corners", $sformatf("This CMD = %p, CMD_prev = %p, tCCD = %p, %t",next_item.CMD, CMD_prev, next_item.tCCD, $time),UVM_MEDIUM); + + repeat (next_item.tCCD - 2) begin //(tCCD - 2) is the nummber of actuad DES bet CMDs to account for true tCCD bet. CMDs + start_item (des_item); + des_item.CMD = DES; + finish_item (des_item); + end + + start_item (next_item); + finish_item (next_item); + endtask +endclass diff --git a/testbench/sequences/DES_seq.sv b/testbench/sequences/DES_seq.sv new file mode 100644 index 0000000..034f7a2 --- /dev/null +++ b/testbench/sequences/DES_seq.sv @@ -0,0 +1,34 @@ +/***************************** DES_seq Description **************************** + +Class : DES_seq +Description : This sequence performs a random DES_seq command + +************************************************************************************/ + +class DES_seq extends base_seq; + function new(string name="DES_seq"); + super.new(name); + endfunction + + `uvm_object_utils(DES_seq) + + ddr_sequence_item item1; + + + task pre_body(); + item1 = ddr_sequence_item::type_id::create ("item1"); + endtask + + task body(); + repeat (4) begin + start_item (item1); + item1.CMD = DES; //DES + finish_item (item1); + end + + start_item (item1); + item1.termination_flag = 1; + finish_item (item1); + endtask + +endclass diff --git a/testbench/sequences/MRR_seq.sv b/testbench/sequences/MRR_seq.sv new file mode 100644 index 0000000..90f8a35 --- /dev/null +++ b/testbench/sequences/MRR_seq.sv @@ -0,0 +1,43 @@ +/***************************** MRR_seq Description **************************** + +Class : MRR_seq +Description : This sequence performs a random MRR_seq command + +************************************************************************************/ + +class MRR_seq extends base_seq; + function new(string name="MRR_seq"); + super.new(name); + endfunction + + `uvm_object_utils(MRR_seq) + + ddr_sequence_item des_item, next_item; + + task pre_body(); + des_item = ddr_sequence_item::type_id::create ("des_item"); + next_item = ddr_sequence_item::type_id::create ("next_item"); + assert (next_item.randomize() with { + next_item.CMD_prev == local::CMD_prev; + next_item.max_tCCD == local::max_tCCD; + next_item.CMD == MRR; //MRR + }) + else `uvm_fatal("MRR_seq", "MRR_Seq randomization failed"); + endtask + + task body(); + + `uvm_info("MRR_seq", $sformatf("This CMD = %p, CMD_prev = %p, tCCD = %p, %t",next_item.CMD, next_item.CMD_prev, next_item.tCCD, $time),UVM_MEDIUM); + + repeat (next_item.tCCD - 2) begin //(tCCD - 2) is the nummber of actuad DES bet CMDs to account for true tCCD bet. CMDs + start_item (des_item); + des_item.CMD = DES; + finish_item (des_item); + end + + + start_item (next_item); + finish_item (next_item); + endtask + +endclass diff --git a/testbench/sequences/MRW_seq.sv b/testbench/sequences/MRW_seq.sv new file mode 100644 index 0000000..8c2c3e7 --- /dev/null +++ b/testbench/sequences/MRW_seq.sv @@ -0,0 +1,43 @@ +/***************************** MRW_seq Description **************************** + +Class : MRW_seq +Description : This sequence performs a random MRW_seq command + +************************************************************************************/ + +class MRW_seq extends base_seq; + function new(string name="MRW_seq"); + super.new(name); + endfunction + + `uvm_object_utils(MRW_seq) + + ddr_sequence_item des_item, next_item; + + task pre_body(); + des_item = ddr_sequence_item::type_id::create ("des_item"); + next_item = ddr_sequence_item::type_id::create ("next_item"); + assert (next_item.randomize() with { + next_item.CMD_prev == local::CMD_prev; + next_item.max_tCCD == local::max_tCCD; + next_item.CMD == MRW; //MRW + }) + else `uvm_fatal("MRW_seq", "MRW_Seq randomization failed"); + endtask + + task body(); + + `uvm_info("MRW_seq", $sformatf("This CMD = %p, CMD_prev = %p, tCCD = %p, %t",next_item.CMD, next_item.CMD_prev, next_item.tCCD, $time),UVM_MEDIUM); + + repeat (next_item.tCCD - 2) begin //(tCCD - 2) is the nummber of actuad DES bet CMDs to account for true tCCD bet. CMDs + start_item (des_item); + des_item.CMD = DES; + finish_item (des_item); + end + + + start_item (next_item); + finish_item (next_item); + endtask + +endclass diff --git a/testbench/sequences/PREab_seq.sv b/testbench/sequences/PREab_seq.sv new file mode 100644 index 0000000..cc26e0d --- /dev/null +++ b/testbench/sequences/PREab_seq.sv @@ -0,0 +1,42 @@ +/***************************** PREab_seq Description **************************** + +Class : PREab_seq +Description : This sequence performs a random PREab_seq command + +************************************************************************************/ + +class PREab_seq extends base_seq; + function new(string name="PREab_seq"); + super.new(name); + endfunction + + `uvm_object_utils(PREab_seq) + + ddr_sequence_item des_item, next_item; + + task pre_body(); + des_item = ddr_sequence_item::type_id::create ("des_item"); + next_item = ddr_sequence_item::type_id::create ("next_item"); + assert (next_item.randomize() with { + next_item.CMD_prev == local::CMD_prev; + next_item.max_tCCD == local::max_tCCD; + next_item.CMD == PREab; //MRR + }) + else `uvm_fatal("PREab_seq", "PREab_seq randomization failed"); + endtask + + task body(); + + `uvm_info("PREab_seq", $sformatf("This CMD = %p, CMD_prev = %p, tCCD = %p, %t",next_item.CMD, next_item.CMD_prev, next_item.tCCD, $time),UVM_MEDIUM); + + repeat (next_item.tCCD - 1) begin //(tCCD - 1) is the nummber of actuad DES bet CMDs to account for true tCCD bet. CMDs + start_item (des_item); + des_item.CMD = DES; + finish_item (des_item); + end + + start_item (next_item); + finish_item (next_item); + endtask + +endclass diff --git a/testbench/sequences/RD_seq.sv b/testbench/sequences/RD_seq.sv new file mode 100644 index 0000000..8cf05ee --- /dev/null +++ b/testbench/sequences/RD_seq.sv @@ -0,0 +1,73 @@ +/***************************** RD_seq Description **************************** + +Class : RD_seq +Description : This sequence performs a random RD_seq command + +************************************************************************************/ + +class RD_seq extends base_seq; + function new(string name="RD_seq"); + super.new(name); + endfunction + + `uvm_object_utils(RD_seq) + + ddr_sequence_item des_item, next_item; + burst_length_t burst_length; + + task pre_body(); + des_item = ddr_sequence_item::type_id::create ("des_item"); + next_item = ddr_sequence_item::type_id::create ("next_item"); + assert (next_item.randomize() with { + next_item.CMD_prev == local::CMD_prev; + next_item.max_tCCD == local::max_tCCD; + next_item.CMD == RD; //RD + }) + else `uvm_fatal("RD_seq", "RD Seq randomization failed"); + endtask + + task body(); + + `uvm_info("RD_seq", $sformatf("This CMD = %p, CMD_prev = %p, tCCD = %p, %t",next_item.CMD, next_item.CMD_prev, next_item.tCCD, $time),UVM_MEDIUM); + + repeat (next_item.tCCD - 2) begin //(tCCD - 2) is the nummber of actuad DES bet CMDs to account for true tCCD bet. CMDs + start_item (des_item); + des_item.CMD = DES; + finish_item (des_item); + end + + + + + if ((burst_length == BL32) && (next_item.BL_mod == 0)) begin + $display("jbbuh"); + start_item (next_item); + next_item.AP = 1; + next_item.C10 = 1; + finish_item (next_item); + + + repeat (6) begin //tCCD = 8 exactly + start_item (des_item); + des_item.CMD = DES; + finish_item (des_item); + end + + //Dummy read (identical to the first read except for AP & C10) + start_item (next_item); + next_item.C10 = 0; //C10 should be opposite to 1st cycle + next_item.command_cancel = 0; //CMD cancel should not be asserted for dummy read + next_item.rand_mode(0); + next_item.AP.rand_mode(1); //Randomize AP of second cycle + assert (next_item.randomize) else `uvm_fatal("RD_seq", "Dummy read randomization failed"); + finish_item (next_item); + end + + else begin //IF not BL32 + start_item (next_item); + finish_item (next_item); + end + + endtask + +endclass diff --git a/testbench/sequences/RD_seq_corners.sv b/testbench/sequences/RD_seq_corners.sv new file mode 100644 index 0000000..5493948 --- /dev/null +++ b/testbench/sequences/RD_seq_corners.sv @@ -0,0 +1,47 @@ +/***************************** RD_seq_corners Description **************************** + +Class : RD_seq_corners +Description : This sequence performs a random RD_seq_corners command + +************************************************************************************/ + +class RD_seq_corners extends base_seq; + function new(string name="RD_seq_corners"); + super.new(name); + endfunction + + `uvm_object_utils(RD_seq_corners) + + ddr_sequence_item des_item, next_item; + + + task pre_body(); + des_item = ddr_sequence_item::type_id::create ("des_item"); + next_item = ddr_sequence_item::type_id::create ("next_item"); + assert (next_item.randomize() with { + next_item.CMD_prev == local::CMD_prev; + next_item.max_tCCD == local::max_tCCD; + next_item.CMD == RD; //RD + next_item.rddata_en == 1; + next_item.ROW inside {2**18-1,0}; + next_item.Col inside {2**9-1,0}; + }) + else `uvm_fatal("RD_seq_corners", "RD Seq randomization failed"); + endtask + + task body(); + + `uvm_info("RD_seq_corners", $sformatf("This CMD = %p, CMD_prev = %p, tCCD = %p, %t",next_item.CMD, next_item.CMD_prev, next_item.tCCD, $time),UVM_MEDIUM); + + repeat (next_item.tCCD - 2) begin //(tCCD - 2) is the nummber of actuad DES bet CMDs to account for true tCCD bet. CMDs + start_item (des_item); + des_item.CMD = DES; + finish_item (des_item); + end + + + start_item (next_item); + finish_item (next_item); + endtask + +endclass diff --git a/testbench/sequences/b2b_seq.sv b/testbench/sequences/b2b_seq.sv new file mode 100644 index 0000000..a11d7f6 --- /dev/null +++ b/testbench/sequences/b2b_seq.sv @@ -0,0 +1,174 @@ +/***************************** b2b Sequence Description **************************** + +Class : b2b_seq +Description : This sequence performs a b2b read/MRR commands with all + combinations of pre/post/interamble + +************************************************************************************/ + +class b2b_seq extends base_seq; + + function new(string name="b2b_seq"); + super.new(name); + endfunction + + `uvm_object_utils(b2b_seq) + + ddr_sequence_item item1; + command_t CMD = MRW; + + + task pre_body(); + item1 = ddr_sequence_item::type_id::create ("item1"); + endtask + + task body(); + + MRW_cmd(.MRA(8'h00), .OP(8'b0_00000_00), .delay(8), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); //Set CAS LATENCY, BL = 16 + + for (bit [1:0] post=0; post<=1; ++post) begin + for (bit [5:0] pre=0; pre<=4; ++pre) begin + for (int delay=0; delay<7; ++delay) begin + MRW_cmd(.MRA(8'h08), .OP({post,pre}), .delay(24), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); //Set Read Preamble + + ACT_cmd(.iscanceled(0), .delay(8), .CMD_prev(CMD), .CMD(CMD)); + + read_cmd(.BL_mod(0), .AP(1), .C10(1), .iscanceled(0), .delay(8), .CMD_prev(CMD), .CMD(CMD)); //Activate BL_mode in MR0, deactivate AP + + read_cmd(.BL_mod(0), .AP(1), .C10(1), .iscanceled(0), .delay(8+delay), .CMD_prev(CMD), .CMD(CMD)); //Activate BL_mode in MR0, deactivate AP + + PREab_cmd(.AP(1), .delay(12), .CMD_prev(CMD), .CMD(CMD)); + end + end + end + + terminate(.delay(8)); //Send termination flag to dram_resp_seq after some delay + + endtask + + extern task MRW_cmd(byte MRA, bit [7:0] OP, int delay, bit iscanceled, command_t CMD_prev, output command_t CMD); + extern task read_cmd(bit BL_mod, bit AP, bit C10, bit iscanceled, int delay, command_t CMD_prev, output command_t CMD); + extern task PREab_cmd(bit AP, int delay, command_t CMD_prev, output command_t CMD); + extern task ACT_cmd(bit iscanceled, int delay, command_t CMD_prev, output command_t CMD); + extern task MRR_cmd(byte MRA, int delay, bit iscanceled, command_t CMD_prev, output command_t CMD); + extern task terminate(int delay); +endclass : b2b_seq + + + +task b2b_seq::MRW_cmd(byte MRA, bit [7:0] OP, int delay, bit iscanceled, command_t CMD_prev, output command_t CMD); + repeat (delay-2) begin + start_item (item1); + item1.CMD = DES; //DES + finish_item (item1); + end + + start_item (item1); + assert (item1.randomize() with { + item1.CMD_prev == CMD_prev; + item1.CMD == MRW; //MRW + item1.MRA == local::MRA; + item1.OP == local::OP; + item1.command_cancel == local::iscanceled; + }) + else `uvm_fatal("DFI_Sanity", "MRW randomization failed"); + CMD = item1.CMD; + finish_item (item1); +endtask + +task b2b_seq::read_cmd(bit BL_mod, bit AP, bit C10, bit iscanceled, int delay, command_t CMD_prev, output command_t CMD); + + repeat (delay - 2) begin + start_item (item1); + item1.CMD = DES; //DES + finish_item (item1); + end + + start_item (item1); + assert (item1.randomize() with { + item1.CMD_prev == CMD_prev; + item1.CMD == RD; //Read + item1.BL_mod == local::BL_mod; + item1.AP == local::AP; + item1.C10 == local::C10; + item1.command_cancel == local::iscanceled; + }) + else `uvm_fatal("DFI_Sanity", "RD randomization failed"); + CMD = item1.CMD; + finish_item (item1); +endtask + +task b2b_seq::MRR_cmd(byte MRA, int delay, bit iscanceled, command_t CMD_prev, output command_t CMD); + + repeat (delay - 2) begin + start_item (item1); + item1.CMD = DES; //DES + finish_item (item1); + end + + + start_item (item1); + assert (item1.randomize() with { + item1.CMD_prev == CMD_prev; + item1.CMD == MRR; //MRR + item1.MRA == local::MRA; + item1.command_cancel == local::iscanceled; + }) + else `uvm_fatal("DFI_Sanity", "MRR randomization failed"); + CMD = item1.CMD; + finish_item (item1); + +endtask + +task b2b_seq::ACT_cmd(bit iscanceled, int delay, command_t CMD_prev, output command_t CMD); + + repeat (delay - 2) begin + start_item (item1); + item1.CMD = DES; //DES + finish_item (item1); + end + + start_item (item1); + assert (item1.randomize() with { + item1.CMD_prev == CMD_prev; + item1.CMD == ACT; //ACT + item1.command_cancel == local::iscanceled; + }) + else `uvm_fatal("DFI_Sanity", "ACT randomization failed"); + CMD = item1.CMD; + finish_item (item1); +endtask + +task b2b_seq::PREab_cmd(bit AP, int delay, command_t CMD_prev, output command_t CMD); + + repeat (delay - 2) begin + start_item (item1); + item1.CMD = DES; //DES + finish_item (item1); + end + + + start_item (item1); + assert (item1.randomize() with { + item1.AP == local::AP; + item1.CMD_prev == CMD_prev; + item1.CMD == PREab; //PREab + }) + else `uvm_fatal("DFI_Sanity", "PREab randomization failed"); + CMD = item1.CMD; + finish_item (item1); +endtask + + +task b2b_seq::terminate(int delay); + + repeat (delay) begin + start_item (item1); + item1.CMD = DES; //DES + finish_item (item1); + end + + start_item (item1); + item1.termination_flag = 1; + finish_item (item1); +endtask \ No newline at end of file diff --git a/testbench/sequences/base_seq.sv b/testbench/sequences/base_seq.sv new file mode 100644 index 0000000..497a187 --- /dev/null +++ b/testbench/sequences/base_seq.sv @@ -0,0 +1,25 @@ +/*********************************Sequence Description**************************** +// The DFI base sequence. All children sequences inherit this behavior. It raises/drops objections in the pre/post_body. +*/ +class base_seq extends uvm_sequence #(ddr_sequence_item); + + function new(string name="base_seq"); + super.new(name); + endfunction + + `uvm_object_utils(base_seq) + + int max_tCCD = 20; + + command_t CMD_prev; + + virtual task pre_body(); + endtask + + virtual task body(); + endtask + + virtual task post_body(); + endtask + +endclass : base_seq diff --git a/testbench/sequences/ddr_sanity_seq.sv b/testbench/sequences/ddr_sanity_seq.sv new file mode 100644 index 0000000..31ad8b5 --- /dev/null +++ b/testbench/sequences/ddr_sanity_seq.sv @@ -0,0 +1,282 @@ +/***************************** mc_sanity Sequence Description **************************** + +Class : ddr_sanity_seq +Description : This sequence performs a mc_sanity sequence (for direct test) + +************************************************************************************/ + +class ddr_sanity_seq extends base_seq; + + function new(string name="ddr_sanity_seq"); + super.new(name); + endfunction + + `uvm_object_utils(ddr_sanity_seq) + + ddr_sequence_item item1; + command_t CMD = MRW; + + + task pre_body(); + item1 = ddr_sequence_item::type_id::create ("item1"); + endtask + + task body(); + ACT_cmd(.iscanceled(0), .delay(8), .CMD_prev(CMD), .CMD(CMD)); + + read_cmd(.BL_mod(0), .AP(1), .C10(1), .iscanceled(0), .delay(8), .CMD_prev(CMD), .CMD(CMD)); //Activate BL_mode in MR0, deactivate AP + + PREab_cmd(.AP(1), .delay(12), .CMD_prev(CMD), .CMD(CMD)); + + MRW_cmd(.MRA(8'h08), .OP(8'b00000_000), .delay(24), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); //Set Read Preamble + + MRW_cmd(.MRA(8'h00), .OP(8'b0_00111_00), .delay(8), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); //Set CAS LATENCY, BL + + MRR_cmd(.MRA('d0), .delay(16), .iscanceled(1), .CMD_prev(CMD), .CMD(CMD)); + + MRR_cmd(.MRA('d0), .delay(16), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); + + ACT_cmd(.iscanceled(0), .delay(30), .CMD_prev(CMD), .CMD(CMD)); + + read_cmd(.BL_mod(0), .AP(1), .C10(1), .iscanceled(0), .delay(24), .CMD_prev(CMD), .CMD(CMD)); + + read_cmd(.BL_mod(0), .AP(0), .C10(0), .iscanceled(0), .delay(8), .CMD_prev(CMD), .CMD(CMD)); + + ACT_cmd(.iscanceled(0), .delay(86), .CMD_prev(CMD), .CMD(CMD)); + + read_cmd(.BL_mod(0), .AP(1), .C10(1), .iscanceled(0), .delay(24), .CMD_prev(CMD), .CMD(CMD)); + + read_cmd(.BL_mod(0), .AP(0), .C10(0), .iscanceled(0), .delay(8), .CMD_prev(CMD), .CMD(CMD)); + + ACT_cmd(.iscanceled(0), .delay(36), .CMD_prev(CMD), .CMD(CMD)); + + read_cmd(.BL_mod(0), .AP(1), .C10(1), .iscanceled(1), .delay(24), .CMD_prev(CMD), .CMD(CMD)); + + read_cmd(.BL_mod(0), .AP(0), .C10(0), .iscanceled(1), .delay(8), .CMD_prev(CMD), .CMD(CMD)); + + read_cmd(.BL_mod(0), .AP(1), .C10(1), .iscanceled(0), .delay(11), .CMD_prev(CMD), .CMD(CMD)); + + read_cmd(.BL_mod(0), .AP(0), .C10(0), .iscanceled(1), .delay(8), .CMD_prev(CMD), .CMD(CMD)); + + //PREab_cmd(.AP(1), .delay(80), .CMD_prev(CMD), .CMD(CMD)); +/* Furthur Combinations + + //BC8_OTF, Preamble 4, + MRW_cmd(.MRA(8'h08), .OP(8'b00000_100), .delay(8), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); //Set Read Preamble + + MRW_cmd(.MRA(8'h00), .OP(8'b0_00101_01), .delay(16), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); //Set CAS LATENCY, BL + + MRR_cmd(.MRA('d0), .delay(8), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); + + ACT_cmd(.iscanceled(0), .delay(8), .CMD_prev(CMD), .CMD(CMD)); + + read_cmd(.BL_mod(0), .AP(1), .C10(1), .iscanceled(0), .delay(8), .CMD_prev(CMD), .CMD(CMD)); + + + //BL32, Preamble 0 + MRW_cmd(.MRA(8'h08), .OP(8'b00000_000), .delay(8), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); //Set Read Preamble + + MRW_cmd(.MRA(8'h00), .OP(8'b0_00101_10), .delay(16), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); //Set CAS LATENCY, BL + + MRR_cmd(.MRA('d0), .delay(8), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); + + ACT_cmd(.iscanceled(0), .delay(8), .CMD_prev(CMD), .CMD(CMD)); + + read_cmd(.BL_mod(0), .AP(1), .C10(1), .iscanceled(0), .delay(8), .CMD_prev(CMD), .CMD(CMD)); + + + + //BL32_OTF, Preamble 2 + MRW_cmd(.MRA(8'h08), .OP(8'b00000_010), .delay(8), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); //Set Read Preamble + + MRW_cmd(.MRA(8'h00), .OP(8'b0_00101_11), .delay(16), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); //Set CAS LATENCY, BL + + MRR_cmd(.MRA('d0), .delay(8), .iscanceled(0), .CMD_prev(CMD), .CMD(CMD)); + + ACT_cmd(.iscanceled(0), .delay(8), .CMD_prev(CMD), .CMD(CMD)); + + read_cmd(.BL_mod(0), .AP(1), .C10(1), .iscanceled(0), .delay(8), .CMD_prev(CMD), .CMD(CMD)); + + +*/ + terminate(.delay(8)); //Send termination flag to dram_resp_seq after some delay + + endtask + + extern task MRW_cmd(byte MRA, bit [7:0] OP, int delay, bit iscanceled, command_t CMD_prev, output command_t CMD); + extern task read_cmd(bit BL_mod, bit AP, bit C10, bit iscanceled, int delay, command_t CMD_prev, output command_t CMD); + extern task PREab_cmd(bit AP, int delay, command_t CMD_prev, output command_t CMD); + extern task ACT_cmd(bit iscanceled, int delay, command_t CMD_prev, output command_t CMD); + extern task MRR_cmd(byte MRA, int delay, bit iscanceled, command_t CMD_prev, output command_t CMD); + extern task terminate(int delay); +endclass : ddr_sanity_seq + + +//==============================================================================// +// Task: MRW_cmd +// Description: This task perfoms MRW command transaction with various arguments +// to configure the MRW transaction +//==============================================================================// + +task ddr_sanity_seq::MRW_cmd(byte MRA, bit [7:0] OP, int delay, bit iscanceled, command_t CMD_prev, output command_t CMD); + repeat (delay-2) begin + start_item (item1); + item1.CMD = DES; //DES + finish_item (item1); + end + + start_item (item1); + assert (item1.randomize() with { + item1.CMD_prev == CMD_prev; + item1.CMD == MRW; //MRW + item1.MRA == local::MRA; + item1.OP == local::OP; + item1.command_cancel == local::iscanceled; + }) + else `uvm_fatal("DFI_Sanity", "MRW randomization failed"); + CMD = item1.CMD; + finish_item (item1); +endtask + + + + +//==============================================================================// +// Task: read_cmd +// Description: This task perfoms RD command transaction with various arguments +// to configure the RD transaction +//==============================================================================// + +task ddr_sanity_seq::read_cmd(bit BL_mod, bit AP, bit C10, bit iscanceled, int delay, command_t CMD_prev, output command_t CMD); + + repeat (delay - 2) begin + start_item (item1); + item1.CMD = DES; //DES + finish_item (item1); + end + + start_item (item1); + assert (item1.randomize() with { + item1.CMD_prev == CMD_prev; + item1.CMD == RD; //Read + item1.BL_mod == local::BL_mod; + item1.AP == local::AP; + item1.C10 == local::C10; + item1.command_cancel == local::iscanceled; + }) + else `uvm_fatal("DFI_Sanity", "RD randomization failed"); + CMD = item1.CMD; + finish_item (item1); +endtask + + + + +//==============================================================================// +// Task: MRR_cmd +// Description: This task perfoms MRR command transaction with various arguments +// to configure the MRR transaction +//==============================================================================// + +task ddr_sanity_seq::MRR_cmd(byte MRA, int delay, bit iscanceled, command_t CMD_prev, output command_t CMD); + + repeat (delay - 2) begin + start_item (item1); + item1.CMD = DES; //DES + finish_item (item1); + end + + + start_item (item1); + assert (item1.randomize() with { + item1.CMD_prev == CMD_prev; + item1.CMD == MRR; //MRR + item1.MRA == local::MRA; + item1.command_cancel == local::iscanceled; + }) + else `uvm_fatal("DFI_Sanity", "MRR randomization failed"); + CMD = item1.CMD; + finish_item (item1); + +endtask + + + + + + +//==============================================================================// +// Task: ACT_cmd +// Description: This task perfoms ACT command transaction with various arguments +// to configure the ACT transaction +//==============================================================================// + +task ddr_sanity_seq::ACT_cmd(bit iscanceled, int delay, command_t CMD_prev, output command_t CMD); + + repeat (delay - 2) begin + start_item (item1); + item1.CMD = DES; //DES + finish_item (item1); + end + + start_item (item1); + assert (item1.randomize() with { + item1.CMD_prev == CMD_prev; + item1.CMD == ACT; //ACT + item1.command_cancel == local::iscanceled; + }) + else `uvm_fatal("DFI_Sanity", "ACT randomization failed"); + CMD = item1.CMD; + finish_item (item1); +endtask + + + + + +//==============================================================================// +// Task: PREab_cmd +// Description: This task perfoms PREab command transaction with various arguments +// to configure the PREab transaction +//==============================================================================// + +task ddr_sanity_seq::PREab_cmd(bit AP, int delay, command_t CMD_prev, output command_t CMD); + + repeat (delay - 2) begin + start_item (item1); + item1.CMD = DES; //DES + finish_item (item1); + end + + + start_item (item1); + assert (item1.randomize() with { + item1.AP == local::AP; + item1.CMD_prev == CMD_prev; + item1.CMD == PREab; //PREab + }) + else `uvm_fatal("DFI_Sanity", "PREab randomization failed"); + CMD = item1.CMD; + finish_item (item1); +endtask + + + + +//==============================================================================// +// Task: PREab_cmd +// Description: This task perfoms terminates the TB +//==============================================================================// + +task ddr_sanity_seq::terminate(int delay); + + repeat (delay) begin + start_item (item1); + item1.CMD = DES; //DES + finish_item (item1); + end + + start_item (item1); + item1.termination_flag = 1; + finish_item (item1); +endtask \ No newline at end of file diff --git a/testbench/sequences/dram_resp_seq.sv b/testbench/sequences/dram_resp_seq.sv new file mode 100644 index 0000000..77b5220 --- /dev/null +++ b/testbench/sequences/dram_resp_seq.sv @@ -0,0 +1,499 @@ +/***************************** dram_resp_seq Sequence Description **************************** + +Class : dram_resp_seq +Description : This sequence performs a dram_resp_seq + +************************************************************************************/ + +class dram_resp_seq extends uvm_sequence #(ddr_sequence_item); + static int n_words = 0; + function new(string name="dram_resp_seq"); + super.new(name); + endfunction + + `uvm_object_utils(dram_resp_seq) + ddr_sequence_item drv_item; + ddr_sequence_item rsp_item; + static bit [2:0] dqs_period; + static logic [7:0] Data_queue [$]; + static logic DQS_queue [$]; + static int gap_flag = 1; + static int gap_counter = 66; + static int gap_q [$]; + static int rddata_delay; + + task pre_body(); + drv_item = ddr_sequence_item::type_id::create ("drv_item"); + rsp_item = ddr_sequence_item::type_id::create ("rsp_item"); + endtask + + task body(); + while(!(rsp_item.termination_flag && (Data_queue.size() == 0))) begin //Condition on termination got from dram driver resp item + DRAM_resp(); + end + + repeat (8) begin + start_item (drv_item); + drv_item.data = 0; + drv_item.dqs = 0; + finish_item (drv_item); + end + + endtask + + + extern task DRAM_resp(); + extern task fill_data_q(); + extern task fill_dqs_pre_q(); + extern task fill_dqs_post_q(); + extern task fill_dqs_inter_q(); + extern task calc_rd_gap(); + extern task drive_MRR(); +endclass : dram_resp_seq + +task dram_resp_seq::DRAM_resp (); + calc_rd_gap(); + //$display("Data_queue = %p\nDQS_queue = %p\ngap_flag = %p, gap_q = %p, counter = %p, rddata_delay = %p, n_words = %p, %t\n\n", Data_queue, DQS_queue, gap_flag, gap_q, gap_counter, rddata_delay, n_words, $time); + if ((rsp_item.CMD == RD) || (rsp_item.CMD == MRR)) begin // Function to Check RD + `uvm_info("Build_Phase", $sformatf("BL = %p, Preamble: %p, RL = %p",rsp_item.burst_length, rsp_item.read_pre_amble, rsp_item.RL), UVM_DEBUG) + + case (rsp_item.burst_length) + BL16 : n_words = 8; + BC8_OTF: n_words = 4; + BL32 : n_words = 8; + endcase + + case (rsp_item.read_pre_amble) + 0 : dqs_period=2; + 1 : dqs_period=4; + 2 : dqs_period=4; + 3 : dqs_period=6; + 4 : dqs_period=8; + default : dqs_period = 2; + endcase + + if ((gap_q.size() != 0) && (gap_q[0] < rsp_item.RL)) begin + rddata_delay = gap_q.pop_front() - n_words; + fill_data_q(); + if(rddata_delay <= 5) fill_dqs_inter_q(); + else fill_dqs_pre_q(); + end + else begin + if (gap_q.size() != 0) gap_q.delete(0); + rddata_delay = rsp_item.RL - dqs_period; + fill_data_q(); + fill_dqs_pre_q(); + end + + if (rsp_item.CMD == RD) begin //If read randomise DQ bus + while (n_words > 0) begin + if (!(drv_item.randomize())) `uvm_fatal("TR_S", "tr_sequence randomization failed") + Data_queue = {Data_queue, drv_item.data}; + DQS_queue = {DQS_queue, 0}; + n_words = n_words - 1; + end + end + else begin //IF MRR + drive_MRR(); + end + fill_dqs_post_q(); //Apply postample only if rddata_delay > 0 (if 0 implies b2b read) + + end + + + start_item (drv_item); + drv_item.data = Data_queue.pop_front(); + drv_item.dqs = DQS_queue.pop_front(); + finish_item (drv_item); + get_response(rsp_item); + +endtask : DRAM_resp + + + + + +task dram_resp_seq::fill_data_q(); + for (int i = 2; i < rddata_delay; i = i + 1) begin //i = 1 bec. [ resp latency (2CK) - CA latency (1CK) ] + Data_queue = {Data_queue, 0}; + DQS_queue = {DQS_queue, 0}; + end + +endtask : fill_data_q + + + + + +task dram_resp_seq::fill_dqs_pre_q(); + case (rsp_item.read_pre_amble) + 0 : begin + Data_queue = {Data_queue, 0, 0}; + DQS_queue = {DQS_queue, 1, 0}; + end + 1 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 1, 0}; + end + 2 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 1, 1, 1, 0}; + end + 3 : begin + Data_queue = {Data_queue, 0, 0, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0, 1, 0}; + end + 4 : begin + Data_queue = {Data_queue, 0, 0, 0, 0, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0, 1, 0, 1, 0}; + end + default : begin + Data_queue = {Data_queue, 0, 0}; + DQS_queue = {DQS_queue, 1, 0}; + end + endcase +endtask + + +task dram_resp_seq::fill_dqs_post_q(); + DQS_queue = DQS_queue [0:$-1]; //Delete last item in DQS queue because postample begins with last data word + case (rsp_item.read_post_amble) + 0 : begin + DQS_queue = {DQS_queue, 0}; + end + 1 : begin + Data_queue = {Data_queue, 0, 0}; + DQS_queue = {DQS_queue, 0, 1, 0}; + end + default : begin + DQS_queue = {DQS_queue, 0}; + end + endcase +endtask + + + + +task dram_resp_seq::fill_dqs_inter_q(); + case (rddata_delay) //rddata_delay = tCCD - BL/2 + 0 : begin //If tCCD = BL/2 + if (rsp_item.read_post_amble) begin //Delete postamble + Data_queue = Data_queue [0:$-2]; + DQS_queue = DQS_queue [0:$-2]; + end + end + 1 : begin //If tCCD = BL/2 + 1 + if (!rsp_item.read_post_amble) begin + Data_queue = {Data_queue, 0, 0}; + DQS_queue = {DQS_queue, 1, 0}; + end + end + 2 : begin //If tCCD = BL/2 + 2 + if (rsp_item.read_post_amble) begin + Data_queue = {Data_queue, 0, 0}; + DQS_queue = {DQS_queue, 1, 0}; + end + else begin + case (rsp_item.read_pre_amble) + 0 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 1, 0}; + end + 1 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 1, 0}; + end + 2 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 1, 1, 1, 0}; + end + 3 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 1, 0}; + end + 4 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 1, 0, 1, 0}; + end + default: begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 1, 0}; + end + endcase + end + + end + 3 : begin //If tCCD = BL/2 + 3 + if (rsp_item.read_post_amble) begin + case (rsp_item.read_pre_amble) + 0 : begin + Data_queue = {Data_queue, 0, 0}; + DQS_queue = {DQS_queue, 0, 0}; + fill_dqs_pre_q(); + end + 1 : begin + fill_dqs_pre_q(); + end + 2 : begin + fill_dqs_pre_q(); + end + 3 : begin + Data_queue = {Data_queue, 0, 0, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 1, 0, 1, 0}; + end + 4 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 1, 0}; + end + default: begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 1, 0, 1, 0}; + end + endcase + end + else begin + case (rsp_item.read_pre_amble) + 0 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + 1 : begin + Data_queue = {Data_queue, 0, 0}; + DQS_queue = {DQS_queue, 0, 0}; + fill_dqs_pre_q(); + end + 2 : begin + Data_queue = {Data_queue, 0, 0}; + DQS_queue = {DQS_queue, 0, 0}; + fill_dqs_pre_q(); + end + 3 : begin + fill_dqs_pre_q(); + end + 4 : begin + Data_queue = {Data_queue, 0, 0, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 1, 0, 1, 0}; + end + default: begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + endcase + end + end + 4 : begin //If tCCD = BL/2 + 4 + if (rsp_item.read_post_amble) begin + case (rsp_item.read_pre_amble) + 0 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + 1 : begin + Data_queue = {Data_queue, 0, 0}; + DQS_queue = {DQS_queue, 0, 0}; + fill_dqs_pre_q(); + end + 2 : begin + Data_queue = {Data_queue, 0, 0}; + DQS_queue = {DQS_queue, 0, 0}; + fill_dqs_pre_q(); + end + 3 : begin + fill_dqs_pre_q(); + end + 4 : begin + Data_queue = {Data_queue, 0, 0, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 1, 0, 1, 0}; + end + default: begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + endcase + end + else begin + case (rsp_item.read_pre_amble) + 0 : begin + Data_queue = {Data_queue, 0, 0, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + 1 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + 2 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + 3 : begin + Data_queue = {Data_queue, 0, 0}; + DQS_queue = {DQS_queue, 0, 0}; + fill_dqs_pre_q(); + end + 4 : begin + fill_dqs_pre_q(); + end + default: begin + Data_queue = {Data_queue, 0, 0, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + endcase + end + end + 5 : begin //If tCCD = BL/2 + 5 + if (rsp_item.read_post_amble) begin + case (rsp_item.read_pre_amble) + 0 : begin + Data_queue = {Data_queue, 0, 0, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + 1 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + 2 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + 3 : begin + Data_queue = {Data_queue, 0, 0}; + DQS_queue = {DQS_queue, 0, 0}; + fill_dqs_pre_q(); + end + 4 : begin + fill_dqs_pre_q(); + end + default: begin + Data_queue = {Data_queue, 0, 0, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + endcase + end + else begin + case (rsp_item.read_pre_amble) + 0 : begin + Data_queue = {Data_queue, 0, 0, 0, 0, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + 1 : begin + Data_queue = {Data_queue, 0, 0, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + 2 : begin + Data_queue = {Data_queue, 0, 0, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + 3 : begin + Data_queue = {Data_queue, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + 4 : begin + Data_queue = {Data_queue, 0, 0}; + DQS_queue = {DQS_queue, 0, 0}; + fill_dqs_pre_q(); + end + default: begin + Data_queue = {Data_queue, 0, 0, 0, 0, 0, 0, 0, 0}; + DQS_queue = {DQS_queue, 0, 0, 0, 0, 0, 0, 0, 0}; + fill_dqs_pre_q(); + end + endcase + end + end + default : begin + //Do nothing + end + endcase +endtask + + +task dram_resp_seq::calc_rd_gap(); + if ((gap_flag) && ((rsp_item.CMD == RD) || (rsp_item.CMD == MRR))) begin //second time + gap_flag=2; + end + else if ((rsp_item.CMD == RD) || (rsp_item.CMD == MRR)) begin + gap_flag=1; + end + + if (gap_flag) begin + gap_counter=gap_counter + 1; + + end + else gap_counter=0; + + if (gap_flag == 2) begin + gap_q.push_back(gap_counter); + gap_flag=1; + gap_counter=0; + end +endtask + + + + + +task dram_resp_seq::drive_MRR(); + + if (rsp_item.CMD == MRR) begin //MRR + DQS_queue = {DQS_queue, 0, 0, 0, 0, 0, 0, 0, 0}; + + Data_queue = {Data_queue, + 8'b10101010, + 8'b10101010, + 8'b10101010, + 8'b10101010, + {!rsp_item.MR[rsp_item.MRA][0], + rsp_item.MR[rsp_item.MRA][0], + !rsp_item.MR[rsp_item.MRA][0], + rsp_item.MR[rsp_item.MRA][0], + !rsp_item.MR[rsp_item.MRA][1], + rsp_item.MR[rsp_item.MRA][1], + !rsp_item.MR[rsp_item.MRA][1], + rsp_item.MR[rsp_item.MRA][1] + }, + {!rsp_item.MR[rsp_item.MRA][2], + rsp_item.MR[rsp_item.MRA][2], + !rsp_item.MR[rsp_item.MRA][2], + rsp_item.MR[rsp_item.MRA][2], + !rsp_item.MR[rsp_item.MRA][3], + rsp_item.MR[rsp_item.MRA][3], + !rsp_item.MR[rsp_item.MRA][3], + rsp_item.MR[rsp_item.MRA][3] + }, + {!rsp_item.MR[rsp_item.MRA][4], + rsp_item.MR[rsp_item.MRA][4], + !rsp_item.MR[rsp_item.MRA][4], + rsp_item.MR[rsp_item.MRA][4], + !rsp_item.MR[rsp_item.MRA][5], + rsp_item.MR[rsp_item.MRA][5], + !rsp_item.MR[rsp_item.MRA][5], + rsp_item.MR[rsp_item.MRA][5] + }, + {!rsp_item.MR[rsp_item.MRA][6], + rsp_item.MR[rsp_item.MRA][6], + !rsp_item.MR[rsp_item.MRA][6], + rsp_item.MR[rsp_item.MRA][6], + !rsp_item.MR[rsp_item.MRA][7], + rsp_item.MR[rsp_item.MRA][7], + !rsp_item.MR[rsp_item.MRA][7], + rsp_item.MR[rsp_item.MRA][7] + } + }; + end +endtask \ No newline at end of file diff --git a/testbench/sequences/rand_seq.sv b/testbench/sequences/rand_seq.sv new file mode 100644 index 0000000..d34e0e7 --- /dev/null +++ b/testbench/sequences/rand_seq.sv @@ -0,0 +1,118 @@ +/***************************** mc_sanity Sequence Description **************************** + +Class : rand_seq +Description : This sequence performs a random commands with constraints + +************************************************************************************/ + +class rand_seq extends base_seq; + + function new(string name="rand_seq"); + super.new(name); + endfunction + + `uvm_object_utils(rand_seq) + + mc_sequencer m_sequencer; + + ddr_sequence_item item1; + RD_seq RD_seq_inst ; + MRR_seq MRR_seq_inst; + MRW_seq MRW_seq_inst; + ACT_seq ACT_seq_inst; + PREab_seq PREab_seq_inst; + + //Initialization + command_t CMD_prev = MRW; + bit AP_prev = 1; + bit command_cancel_prev = 0; + burst_length_t burst_length; + + task pre_body(); + item1 = ddr_sequence_item::type_id::create ("item1"); + RD_seq_inst = RD_seq::type_id::create ("RD_seq_inst "); + MRR_seq_inst = MRR_seq::type_id::create ("MRR_seq_inst"); + MRW_seq_inst = MRW_seq::type_id::create ("MRW_seq_inst"); + ACT_seq_inst = ACT_seq::type_id::create ("ACT_seq_inst"); + PREab_seq_inst = PREab_seq::type_id::create ("PREab_seq_inst"); + RD_seq_inst.CMD_prev = CMD_prev; + MRR_seq_inst.CMD_prev = CMD_prev; + MRW_seq_inst.CMD_prev = CMD_prev; + ACT_seq_inst.CMD_prev = CMD_prev; + PREab_seq_inst.CMD_prev = CMD_prev; + RD_seq_inst.max_tCCD = max_tCCD; + MRR_seq_inst.max_tCCD = max_tCCD; + MRW_seq_inst.max_tCCD = max_tCCD; + ACT_seq_inst.max_tCCD = max_tCCD; + PREab_seq_inst.max_tCCD = max_tCCD; + + RD_seq_inst.burst_length = burst_length; + endtask + + task body(); + + assert (item1.randomize() with { + item1.CMD_prev == local::CMD_prev; + item1.AP_prev == local::AP_prev; + item1.command_cancel_prev == local::command_cancel_prev; + }) + else `uvm_fatal("Rand_seq", "Rand Seq randomization failed"); + + `uvm_info("rand_seq", $sformatf("In rand, CMD_next = %p, %t", item1.CMD, $time),UVM_MEDIUM); + case (item1.CMD) + MRW : begin + MRW_seq_inst.start(m_sequencer); + item1 = MRW_seq_inst.next_item; + end + MRR : begin + MRR_seq_inst.start(m_sequencer); + item1 = MRR_seq_inst.next_item; + end + ACT : begin + ACT_seq_inst.start(m_sequencer); + item1 = ACT_seq_inst.next_item; + end + RD : begin + RD_seq_inst.start(m_sequencer); + item1 = RD_seq_inst.next_item; + end + PREab : begin + PREab_seq_inst.start(m_sequencer); + item1 = PREab_seq_inst.next_item; + end + default : MRW_seq_inst.start(m_sequencer); + endcase + endtask + + task post_body(); + CMD_prev = item1.CMD; + AP_prev = item1.AP; + command_cancel_prev = item1.command_cancel; + get_MRW_settings(item1); + endtask + + extern task get_MRW_settings(input ddr_sequence_item item1); +endclass : rand_seq + + + + + +task rand_seq::get_MRW_settings(input ddr_sequence_item item1); + if (item1.CMD == MRW) begin + case (item1.MRA) + 8'h00 : begin + case (item1.OP[1:0]) + 'b00 : burst_length = BL16; + 'b01 : burst_length = BC8_OTF; + 'b10 : burst_length = BL32; + default : burst_length = BL16; + endcase + end + 8'h08 : begin + item1.read_pre_amble = item1.OP[2:0]; + item1.read_post_amble = item1.OP[6]; + end + endcase + end +endtask \ No newline at end of file diff --git a/testbench/sequences/rand_seq_corners.sv b/testbench/sequences/rand_seq_corners.sv new file mode 100644 index 0000000..6c6e3b7 --- /dev/null +++ b/testbench/sequences/rand_seq_corners.sv @@ -0,0 +1,104 @@ +/***************************** mc_sanity Sequence Description **************************** + +Class : rand_seq_corners +Description : This sequence performs a random commands at corner rows and columns + +************************************************************************************/ + +class rand_seq_corners extends base_seq; + function new(string name="rand_seq_corners"); + super.new(name); + endfunction + + `uvm_object_utils(rand_seq_corners) + + mc_sequencer m_sequencer; + + ddr_sequence_item item1; + RD_seq_corners RD_seq_corners_inst ; + MRR_seq MRR_seq_inst; + MRW_seq MRW_seq_inst; + ACT_seq_corners ACT_seq_corners_inst; + PREab_seq PREab_seq_inst; + + command_t CMD_prev = MRW; + bit AP_prev = 1; + bit command_cancel_prev = 0; + + + task pre_body(); + item1 = ddr_sequence_item::type_id::create ("item1"); + RD_seq_corners_inst = RD_seq_corners::type_id::create ("RD_seq_corners_inst"); + MRR_seq_inst = MRR_seq::type_id::create ("MRR_seq_inst"); + MRW_seq_inst = MRW_seq::type_id::create ("MRW_seq_inst"); + ACT_seq_corners_inst = ACT_seq_corners::type_id::create ("ACT_seq_corners_inst"); + PREab_seq_inst = PREab_seq::type_id::create ("PREab_seq_inst"); + RD_seq_corners_inst.CMD_prev = CMD_prev; + MRR_seq_inst.CMD_prev = CMD_prev; + MRW_seq_inst.CMD_prev = CMD_prev; + ACT_seq_corners_inst.CMD_prev = CMD_prev; + PREab_seq_inst.CMD_prev = CMD_prev; + /*RD_seq_corners_inst.AP_prev = AP_prev; + MRR_seq_inst.AP_prev = AP_prev; + MRW_seq_inst.AP_prev = AP_prev; + ACT_seq_corners_inst.AP_prev = AP_prev; + PREab_seq_inst.AP_prev = AP_prev; + RD_seq_corners_inst.command_cancel_prev = command_cancel_prev; + MRR_seq_inst.command_cancel_prev = command_cancel_prev; + MRW_seq_inst.command_cancel_prev = command_cancel_prev; + ACT_seq_corners_inst.command_cancel_prev = command_cancel_prev; + PREab_seq_inst.command_cancel_prev = command_cancel_prev;*/ + RD_seq_corners_inst.max_tCCD = max_tCCD; + MRR_seq_inst.max_tCCD = max_tCCD; + MRW_seq_inst.max_tCCD = max_tCCD; + ACT_seq_corners_inst.max_tCCD = max_tCCD; + PREab_seq_inst.max_tCCD = max_tCCD; + endtask + + task body(); + + assert (item1.randomize() with { + item1.CMD_prev == local::CMD_prev; + item1.AP_prev == local::AP_prev; + item1.command_cancel_prev == local::command_cancel_prev; + item1.ROW inside {2**18-1,0}; + item1.Col inside {2**9-1,0}; + }) + $display("hello, row: %p, col: %p",item1.ROW,item1.Col); + else `uvm_fatal("Rand_seq_corners", "Rand Seq randomization failed"); + + `uvm_info("rand_seq_corners", $sformatf("In rand, CMD_next = %p, %t", item1.CMD, $time),UVM_MEDIUM); + case (item1.CMD) + MRW : begin + MRW_seq_inst.start(m_sequencer); + item1 = MRW_seq_inst.next_item; + end + MRR : begin + MRR_seq_inst.start(m_sequencer); + item1 = MRR_seq_inst.next_item; + end + ACT : begin + ACT_seq_corners_inst.start(m_sequencer); + item1 = ACT_seq_corners_inst.next_item; + + end + RD : begin + RD_seq_corners_inst.start(m_sequencer); + item1 = RD_seq_corners_inst.next_item; + end + PREab : begin + PREab_seq_inst.start(m_sequencer); + item1 = PREab_seq_inst.next_item; + end + default : MRW_seq_inst.start(m_sequencer); + endcase + endtask + + task post_body(); + CMD_prev = item1.CMD; + AP_prev = item1.AP; + command_cancel_prev = item1.command_cancel; + endtask + +endclass : rand_seq_corners + diff --git a/testbench/sequences/reset_seq.sv b/testbench/sequences/reset_seq.sv new file mode 100644 index 0000000..4fefc81 --- /dev/null +++ b/testbench/sequences/reset_seq.sv @@ -0,0 +1,40 @@ +/***************************** b2b Sequence Description **************************** + +Class : reset_seq +Description : This sequence performs dut reset (executed in reset phase + of base test) + +************************************************************************************/ + +class reset_seq extends base_seq; + + function new(string name="reset_seq"); + super.new(name); + endfunction + + `uvm_object_utils(reset_seq) + + ddr_sequence_item item1; + command_t CMD = MRW; + + + task pre_body(); + item1 = ddr_sequence_item::type_id::create ("item1"); + endtask + + task body(); + + start_item (item1); + item1.reset_n_i = 0; + item1.en_i = 0; + finish_item (item1); + + start_item (item1); + item1.reset_n_i = 1; + item1.en_i = 1; + finish_item (item1); + + endtask + +endclass : reset_seq + diff --git a/testbench/sequences/sequence_lib.sv b/testbench/sequences/sequence_lib.sv new file mode 100644 index 0000000..c5cfca4 --- /dev/null +++ b/testbench/sequences/sequence_lib.sv @@ -0,0 +1,15 @@ +`include "base_seq.sv" +`include "reset_seq.sv" +`include "ddr_sanity_seq.sv" +`include "ACT_seq.sv" +`include "RD_seq.sv" +`include "MRW_seq.sv" +`include "MRR_seq.sv" +`include "PREab_seq.sv" +`include "DES_seq.sv" +`include "dram_resp_seq.sv" +`include "rand_seq.sv" +`include "b2b_seq.sv" +`include "ACT_seq_corners.sv" +`include "RD_seq_corners.sv" +`include "rand_seq_corners.sv" diff --git a/testbench/tb_pkg.sv b/testbench/tb_pkg.sv new file mode 100644 index 0000000..c837cd0 --- /dev/null +++ b/testbench/tb_pkg.sv @@ -0,0 +1,31 @@ +package tb_pkg; + import uvm_pkg::*; + //Declaration macros to provide multiple implemenation ports (multiple write functions). + `uvm_analysis_imp_decl(_port_mc) // DFI Port + `uvm_analysis_imp_decl(_port_dram) // JEDEC Port + //Data Types definitions + typedef enum bit [2:0] {DES, MRW, MRR, ACT, RD, NOP, PREab, other} command_t; + typedef enum bit [1:0] {BL16, BC8_OTF, BL32} burst_length_t; //Double data words + //Includes + `include "uvm_macros.svh" + `include "transactions/ddr_sequence_item.sv" + `include "components/mc_agent/mc_sequencer.sv" + `include "components/mc_agent/mc_driver.sv" + `include "components/mc_agent/mc_monitor.sv" + `include "components/mc_agent/mc_agent.sv" + `include "components/dram_agent/dram_sequencer.sv" + `include "components/dram_agent/dram_driver.sv" + `include "components/dram_agent/dram_monitor.sv" + `include "components/dram_agent/dram_agent.sv" + `include "components/scoreboard.sv" + `include "components/subscriber.sv" + `include "components/env.sv" + `include "sequences/sequence_lib.sv" + `include "tests/test_lib.sv" +endpackage : tb_pkg + +`include "interfaces/dfi_intf.sv" +`include "interfaces/jedec_intf.sv" + + + diff --git a/testbench/tests/b2b_test.sv b/testbench/tests/b2b_test.sv new file mode 100644 index 0000000..55d3e44 --- /dev/null +++ b/testbench/tests/b2b_test.sv @@ -0,0 +1,33 @@ +class b2b_test extends base_test; + `uvm_component_utils(b2b_test) + + b2b_seq b2b_sequence; + dram_resp_seq resp_seq; + + function new (string name = "b2b_test", uvm_component parent = null); + super.new(name,parent); + endfunction + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + b2b_sequence = b2b_seq::type_id::create("b2b_sequence"); + resp_seq = dram_resp_seq::type_id::create("resp_seq"); + `uvm_info("Build_Phase", "*************** 'b2b_test' Build Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + phase.raise_objection(this); + fork + b2b_sequence.start(env1.mc_agent1.mc_sequencer1); + resp_seq.start(env1.dram_agent1.dram_sequencer1); + join + phase.drop_objection(this); + endtask +endclass : b2b_test; diff --git a/testbench/tests/base_test.sv b/testbench/tests/base_test.sv new file mode 100644 index 0000000..68f820b --- /dev/null +++ b/testbench/tests/base_test.sv @@ -0,0 +1,64 @@ +class base_test extends uvm_test; + `uvm_component_utils(base_test) + + env env1; + base_seq base_seq_inst; + reset_seq reset_seq_inst; + virtual dfi_intf test_dfi_vif; + virtual jedec_intf test_jedec_vif; + virtual dfi_intf env_dfi_vif; + virtual jedec_intf env_jedec_vif; + + function new (string name = "base_test", uvm_component parent = null); + super.new(name,parent); + endfunction + + //==========================================================================// + // Build Phase // + //==========================================================================// + virtual function void build_phase (uvm_phase phase); + super.build_phase(phase); + if(!uvm_config_db#(virtual dfi_intf)::get(this,"","dfi_vif",test_dfi_vif)) + `uvm_fatal(get_full_name(),"Error in getting dfi_vif from database!") + if(!uvm_config_db#(virtual jedec_intf)::get(this,"","jedec_vif",test_jedec_vif)) + `uvm_fatal(get_full_name(),"Error in getting jedec_vif from database!") + + env_dfi_vif = test_dfi_vif; + env_jedec_vif = test_jedec_vif; + env1 = env::type_id::create("env1",this); + uvm_config_db#(virtual dfi_intf)::set(this,"env1","dfi_vif",env_dfi_vif); + uvm_config_db#(virtual jedec_intf)::set(this,"env1","jedec_vif",env_jedec_vif); + + `uvm_info("Build_Phase", "*************** 'base_test' Build Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Connect Phase // + //==========================================================================// + virtual function void connect_phase(uvm_phase phase); + super.connect_phase(phase); + `uvm_info("Connect_phase", "*************** 'base_test' Connect Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // End of Elaboration Phase // + //==========================================================================// + virtual function void end_of_elaboration_phase(uvm_phase phase); + super.end_of_elaboration_phase(phase); + uvm_top.print_topology(); + `uvm_info("End of Elaboration Phase", "*************** 'base_test' End of Elaboration Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Run Phase // + //==========================================================================// + virtual task run_phase(uvm_phase phase); + reset_seq_inst = reset_seq::type_id::create("reset_seq_inst"); + base_seq_inst = base_seq::type_id::create("base_seq_inst"); + super.run_phase(phase); + phase.raise_objection(this); + reset_seq_inst.start(env1.mc_agent1.mc_sequencer1); + base_seq_inst.start(env1.mc_agent1.mc_sequencer1); + phase.drop_objection(this); + endtask +endclass : base_test; diff --git a/testbench/tests/ddr_sanity_test.sv b/testbench/tests/ddr_sanity_test.sv new file mode 100644 index 0000000..ff94a6a --- /dev/null +++ b/testbench/tests/ddr_sanity_test.sv @@ -0,0 +1,33 @@ +class ddr_sanity_test extends base_test; + `uvm_component_utils(ddr_sanity_test) + + ddr_sanity_seq sanity_sequence; + dram_resp_seq resp_seq; + + function new (string name = "ddr_sanity_test", uvm_component parent = null); + super.new(name,parent); + endfunction + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + sanity_sequence = ddr_sanity_seq::type_id::create("sanity_sequence"); + resp_seq = dram_resp_seq::type_id::create("resp_seq"); + `uvm_info("Build_Phase", "*************** 'ddr_sanity_test' Build Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + phase.raise_objection(this); + fork + sanity_sequence.start(env1.mc_agent1.mc_sequencer1); + resp_seq.start(env1.dram_agent1.dram_sequencer1); + join + phase.drop_objection(this); + endtask +endclass : ddr_sanity_test; diff --git a/testbench/tests/rand_test.sv b/testbench/tests/rand_test.sv new file mode 100644 index 0000000..c56e479 --- /dev/null +++ b/testbench/tests/rand_test.sv @@ -0,0 +1,48 @@ +class rand_test extends base_test; + `uvm_component_utils(rand_test) + + rand_seq rand_seq_inst; + dram_resp_seq resp_seq; + DES_seq DES_seq_inst; + int no_of_transfers; + + function new (string name = "rand_test", uvm_component parent = null); + super.new(name,parent); + endfunction + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + rand_seq_inst = rand_seq::type_id::create("rand_seq_inst"); + DES_seq_inst = DES_seq::type_id::create("DES_seq_inst"); + resp_seq = dram_resp_seq::type_id::create("resp_seq"); + `uvm_info("Build_Phase", "*************** 'rand_test' Build Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + phase.raise_objection(this); + no_of_transfers = 300; //use in cmd line (to do) + rand_seq_inst.max_tCCD = 40; + rand_seq_inst.m_sequencer = env1.mc_agent1.mc_sequencer1; + + + fork + begin + repeat (no_of_transfers) begin + assert (rand_seq_inst.randomize) + else `uvm_fatal("DFI_Sanity", "Sanity Seq randomization failed"); + rand_seq_inst.start(env1.mc_agent1.mc_sequencer1); + end + DES_seq_inst.start(env1.mc_agent1.mc_sequencer1); + end + resp_seq.start(env1.dram_agent1.dram_sequencer1); + join + phase.drop_objection(this); + endtask +endclass : rand_test; diff --git a/testbench/tests/rand_test_corners.sv b/testbench/tests/rand_test_corners.sv new file mode 100644 index 0000000..2ef2387 --- /dev/null +++ b/testbench/tests/rand_test_corners.sv @@ -0,0 +1,48 @@ +class rand_test_corners extends base_test; + `uvm_component_utils(rand_test_corners) + + rand_seq_corners rand_seq_corners_inst; + dram_resp_seq resp_seq; + DES_seq DES_seq_inst; + int no_of_transfers; + + function new (string name = "rand_test_corners", uvm_component parent = null); + super.new(name,parent); + endfunction + + //==========================================================================// + // Build Phase // + //==========================================================================// + function void build_phase (uvm_phase phase); + super.build_phase(phase); + rand_seq_corners_inst = rand_seq_corners::type_id::create("rand_seq_corners_inst"); + DES_seq_inst = DES_seq::type_id::create("DES_seq_inst"); + resp_seq = dram_resp_seq::type_id::create("resp_seq"); + `uvm_info("Build_Phase", "*************** 'rand_test_corners' Build Phase ***************", UVM_HIGH) + endfunction + + //==========================================================================// + // Run Phase // + //==========================================================================// + task run_phase(uvm_phase phase); + super.run_phase(phase); + phase.raise_objection(this); + no_of_transfers = 300; //use in cmd line (to do) + rand_seq_corners_inst.max_tCCD = 40; + rand_seq_corners_inst.m_sequencer = env1.mc_agent1.mc_sequencer1; + + + fork + begin + repeat (no_of_transfers) begin + assert (rand_seq_corners_inst.randomize) + else `uvm_fatal("DFI_Sanity", "Sanity Seq randomization failed"); + rand_seq_corners_inst.start(env1.mc_agent1.mc_sequencer1); + end + DES_seq_inst.start(env1.mc_agent1.mc_sequencer1); + end + resp_seq.start(env1.dram_agent1.dram_sequencer1); + join + phase.drop_objection(this); + endtask +endclass : rand_test_corners; diff --git a/testbench/tests/test_lib.sv b/testbench/tests/test_lib.sv new file mode 100644 index 0000000..2082deb --- /dev/null +++ b/testbench/tests/test_lib.sv @@ -0,0 +1,8 @@ +`include "base_test.sv" +`include "ddr_sanity_test.sv" +`include "rand_test.sv" +`include "rand_test_corners.sv" +`include "b2b_test.sv" + + + diff --git a/testbench/top_testbench.sv b/testbench/top_testbench.sv new file mode 100644 index 0000000..b61eac9 --- /dev/null +++ b/testbench/top_testbench.sv @@ -0,0 +1,239 @@ +`include "uvm_pkg.sv" +`include "tb_pkg.sv" +`include "interfaces/ddr_assertions.sv" +//RTL includes +`include "Serializer_V1.sv" +`include "CRC_Valid.sv" +`include "CA_Manager.sv" +`include "FSM_setting.sv" +`include "generic_FSM.sv" +`include "GapCounter.sv" +`include "CountCalc.sv" +`include "FIFO.sv" +`include "EdgeDetectorFSM.sv" +`include "pattern_detector.sv" +`include "ControlUnit.sv" +`include "ValidCounter.sv" +`include "top.sv" +`include "DataManager.sv" +`include "Deserializer_V1.sv" +`include "DDR5_PHY.sv" +`timescale 1ps/1ps + + +module top_testbench; + import uvm_pkg::*; + import tb_pkg::*; + + logic dfi_clk_i = 1; + logic dfi_phy_clk_i = 1; + + dfi_intf dfi_if (dfi_clk_i); + jedec_intf jedec_if (dfi_phy_clk_i); + + parameter DFI_CLK_PERIOD = 800; + `ifdef ratio_1_to_1 + parameter PHY_CLK_PERIOD = DFI_CLK_PERIOD; + `elsif ratio_1_to_2 + parameter PHY_CLK_PERIOD = DFI_CLK_PERIOD/2; + `elsif ratio_1_to_4 + parameter PHY_CLK_PERIOD = DFI_CLK_PERIOD/4; + `else + parameter PHY_CLK_PERIOD = DFI_CLK_PERIOD; //Default + `endif + + + always #(DFI_CLK_PERIOD/2) dfi_clk_i = ~dfi_clk_i; + always #(PHY_CLK_PERIOD/2) dfi_phy_clk_i = ~dfi_phy_clk_i; //TO BE Considered Freq_ratio + + DDR5_PHY #( + // Prameters + .Physical_Rank_No (1), + .device_width (4) + ) ddr_DUT ( + // Inputs + .dfi_phy_clk_i (dfi_phy_clk_i ), //Fast clock + .dfi_clk_i (dfi_clk_i ), //Slow clock + .reset_n_i (dfi_if.reset_n_i ), + .en_i (dfi_if.en_i ), + .phycrc_mode_i (dfi_if.phycrc_mode_i ), //one if CRC implemented in PHY, zero if not + .dfi_freq_ratio_i (dfi_if.dfi_freq_ratio_i ), //freq ratio between MC and PHY supported ratios are 1x, 2x, 4x, not in the interface + .dfi_address_p0 (dfi_if.dfi_address_p0 ), + .dfi_address_p1 (dfi_if.dfi_address_p1 ), + .dfi_address_p2 (dfi_if.dfi_address_p2 ), + .dfi_address_p3 (dfi_if.dfi_address_p3 ), + .dfi_cs_p0 (dfi_if.dfi_cs_p0 ), + .dfi_cs_p1 (dfi_if.dfi_cs_p1 ), + .dfi_cs_p2 (dfi_if.dfi_cs_p2 ), + .dfi_cs_p3 (dfi_if.dfi_cs_p3 ), + .dfi_rddata_en_p0 (dfi_if.dfi_rddata_en_p0 ), + .dfi_rddata_en_p1 (dfi_if.dfi_rddata_en_p1 ), + .dfi_rddata_en_p2 (dfi_if.dfi_rddata_en_p2 ), + .dfi_rddata_en_p3 (dfi_if.dfi_rddata_en_p3 ), + .DQS_AD_i (jedec_if.DQS_AD_i ), //data strobe + .DQ_AD_i (jedec_if.DQ_AD_i ), //data bus + + // Outputs + .dfi_alert_n_a0 (dfi_if.dfi_alert_n_a0 ), + .dfi_alert_n_a1 (dfi_if.dfi_alert_n_a1 ), + .dfi_alert_n_a2 (dfi_if.dfi_alert_n_a2 ), + .dfi_alert_n_a3 (dfi_if.dfi_alert_n_a3 ), + .dfi_rddata_valid_w0 (dfi_if.dfi_rddata_valid_w0 ), + .dfi_rddata_valid_w1 (dfi_if.dfi_rddata_valid_w1 ), + .dfi_rddata_valid_w2 (dfi_if.dfi_rddata_valid_w2 ), + .dfi_rddata_valid_w3 (dfi_if.dfi_rddata_valid_w3 ), + .dfi_rddata_w0 (dfi_if.dfi_rddata_w0 ), + .dfi_rddata_w1 (dfi_if.dfi_rddata_w1 ), + .dfi_rddata_w2 (dfi_if.dfi_rddata_w2 ), + .dfi_rddata_w3 (dfi_if.dfi_rddata_w3 ), + .CA_DA_o (jedec_if.CA_DA_o ), + .CS_DA_o (jedec_if.CS_DA_o ), + .CA_VALID_DA_o (jedec_if.CA_VALID_DA_o ) + ); + + static bit CRC_enable = 0; + static bit [2:0] pre_amble = 3'b000; + static bit post_amble = 0; + static byte RL = 8'd22; + static burst_length_t burst_length = BL16; + initial begin + uvm_config_db #(virtual dfi_intf )::set(null,"uvm_test_top","dfi_vif" ,dfi_if ); + uvm_config_db #(virtual jedec_intf )::set(null,"uvm_test_top","jedec_vif" ,jedec_if); + run_test(); + end + + initial begin + fork + forever begin + uvm_config_db #(byte)::wait_modified(null, "*", "RL"); + if(!uvm_config_db#(byte)::get(null,"","RL",RL)) + `uvm_fatal("TOP","Error in getting RL from database!") + $display("********************RL FROM TOP = %p",RL); + end + forever begin + uvm_config_db #(burst_length_t)::wait_modified(null, "*", "burst_length"); + if(!uvm_config_db#(burst_length_t)::get(null,"","burst_length",burst_length)) + `uvm_fatal("TOP","Error in getting burst_length from database!") + $display("********************BL FROM TOP = %p",burst_length); + end + forever begin + uvm_config_db #(bit)::wait_modified(null, "*", "pre_amble"); + if(!uvm_config_db#(bit)::get(null,"","pre_amble",pre_amble)) + `uvm_fatal("TOP","Error in getting pre_amble from database!") + //$display("********************Pre FROM TOP = %p",pre_amble); + end + forever begin + uvm_config_db #(bit)::wait_modified(null, "*", "post_amble"); + if(!uvm_config_db#(bit)::get(null,"","post_amble",post_amble)) + `uvm_fatal("TOP","Error in getting post_amble from database!") + //$display("********************POST FROM TOP = %p",post_amble); + end + forever begin + uvm_config_db #(bit)::wait_modified(null, "*", "CRC_enable"); + if(!uvm_config_db#(bit)::get(null,"","CRC_enable",CRC_enable)) + `uvm_fatal("TOP","Error in getting CRC_enable from database!") + //$display("********************CRC_enable FROM TOP = %p",CRC_enable); + end + join + end + + + +`ifdef assert_en + ddr_assertions ddr_sva_inst ( + // Inputs + .dfi_phy_clk_i (dfi_phy_clk_i ), //Fast clock + .dfi_clk_i (dfi_clk_i ), //Slow clock + .reset_n_i (dfi_if.reset_n_i ), + .en_i (dfi_if.en_i ), + .phycrc_mode_i (dfi_if.phycrc_mode_i ), //one if CRC implemented in PHY, zero if not + .dfi_freq_ratio_i (dfi_if.dfi_freq_ratio_i ), //freq ratio between MC and PHY supported ratios are 1x, 2x, 4x, not in the interface + .dfi_address_p0 (dfi_if.dfi_address_p0 ), + .dfi_address_p1 (dfi_if.dfi_address_p1 ), + .dfi_address_p2 (dfi_if.dfi_address_p2 ), + .dfi_address_p3 (dfi_if.dfi_address_p3 ), + .dfi_cs_p0 (dfi_if.dfi_cs_p0 ), + .dfi_cs_p1 (dfi_if.dfi_cs_p1 ), + .dfi_cs_p2 (dfi_if.dfi_cs_p2 ), + .dfi_cs_p3 (dfi_if.dfi_cs_p3 ), + .dfi_rddata_en_p0 (dfi_if.dfi_rddata_en_p0 ), + .dfi_rddata_en_p1 (dfi_if.dfi_rddata_en_p1 ), + .dfi_rddata_en_p2 (dfi_if.dfi_rddata_en_p2 ), + .dfi_rddata_en_p3 (dfi_if.dfi_rddata_en_p3 ), + .DQS_AD_i (jedec_if.DQS_AD_i ), //data strobe + .DQ_AD_i (jedec_if.DQ_AD_i ), //data bus + + // Outputs + .dfi_alert_n_a0 (dfi_if.dfi_alert_n_a0 ), + .dfi_alert_n_a1 (dfi_if.dfi_alert_n_a1 ), + .dfi_alert_n_a2 (dfi_if.dfi_alert_n_a2 ), + .dfi_alert_n_a3 (dfi_if.dfi_alert_n_a3 ), + .dfi_rddata_valid_w0 (dfi_if.dfi_rddata_valid_w0 ), + .dfi_rddata_valid_w1 (dfi_if.dfi_rddata_valid_w1 ), + .dfi_rddata_valid_w2 (dfi_if.dfi_rddata_valid_w2 ), + .dfi_rddata_valid_w3 (dfi_if.dfi_rddata_valid_w3 ), + .dfi_rddata_w0 (dfi_if.dfi_rddata_w0 ), + .dfi_rddata_w1 (dfi_if.dfi_rddata_w1 ), + .dfi_rddata_w2 (dfi_if.dfi_rddata_w2 ), + .dfi_rddata_w3 (dfi_if.dfi_rddata_w3 ), + .CA_DA_o (jedec_if.CA_DA_o ), + .CS_DA_o (jedec_if.CS_DA_o ), + .CA_VALID_DA_o (jedec_if.CA_VALID_DA_o ), + .RL (RL), + .burst_length (burst_length), + .pre_amble (pre_amble), + .post_amble (post_amble) + ); +`endif + + + +endmodule : top_testbench + +//==========================================================================// +// Binding Assertions // +//==========================================================================// +/* +`ifdef assert_en + bind top_testbench.ddr_DUT ddr_assertions ddr_sva_inst ( + // Inputs + .dfi_phy_clk_i (dfi_phy_clk_i ), //Fast clock + .dfi_clk_i (dfi_clk_i ), //Slow clock + .reset_n_i (dfi_if.reset_n_i ), + .en_i (dfi_if.en_i ), + .phycrc_mode_i (dfi_if.phycrc_mode_i ), //one if CRC implemented in PHY, zero if not + .dfi_freq_ratio_i (dfi_if.dfi_freq_ratio_i ), //freq ratio between MC and PHY supported ratios are 1x, 2x, 4x, not in the interface + .dfi_address_p0 (dfi_if.dfi_address_p0 ), + .dfi_address_p1 (dfi_if.dfi_address_p1 ), + .dfi_address_p2 (dfi_if.dfi_address_p2 ), + .dfi_address_p3 (dfi_if.dfi_address_p3 ), + .dfi_cs_p0 (dfi_if.dfi_cs_p0 ), + .dfi_cs_p1 (dfi_if.dfi_cs_p1 ), + .dfi_cs_p2 (dfi_if.dfi_cs_p2 ), + .dfi_cs_p3 (dfi_if.dfi_cs_p3 ), + .dfi_rddata_en_p0 (dfi_if.dfi_rddata_en_p0 ), + .dfi_rddata_en_p1 (dfi_if.dfi_rddata_en_p1 ), + .dfi_rddata_en_p2 (dfi_if.dfi_rddata_en_p2 ), + .dfi_rddata_en_p3 (dfi_if.dfi_rddata_en_p3 ), + .DQS_AD_i (jedec_if.DQS_AD_i ), //data strobe + .DQ_AD_i (jedec_if.DQ_AD_i ), //data bus + + // Outputs + .dfi_alert_n_a0 (dfi_if.dfi_alert_n_a0 ), + .dfi_alert_n_a1 (dfi_if.dfi_alert_n_a1 ), + .dfi_alert_n_a2 (dfi_if.dfi_alert_n_a2 ), + .dfi_alert_n_a3 (dfi_if.dfi_alert_n_a3 ), + .dfi_rddata_valid_w0 (dfi_if.dfi_rddata_valid_w0 ), + .dfi_rddata_valid_w1 (dfi_if.dfi_rddata_valid_w1 ), + .dfi_rddata_valid_w2 (dfi_if.dfi_rddata_valid_w2 ), + .dfi_rddata_valid_w3 (dfi_if.dfi_rddata_valid_w3 ), + .dfi_rddata_w0 (dfi_if.dfi_rddata_w0 ), + .dfi_rddata_w1 (dfi_if.dfi_rddata_w1 ), + .dfi_rddata_w2 (dfi_if.dfi_rddata_w2 ), + .dfi_rddata_w3 (dfi_if.dfi_rddata_w3 ), + .CA_DA_o (jedec_if.CA_DA_o ), + .CS_DA_o (jedec_if.CS_DA_o ), + .CA_VALID_DA_o (jedec_if.CA_VALID_DA_o ) + ); +`endif +*/ \ No newline at end of file diff --git a/testbench/transactions/ddr_sequence_item.sv b/testbench/transactions/ddr_sequence_item.sv new file mode 100644 index 0000000..1967d62 --- /dev/null +++ b/testbench/transactions/ddr_sequence_item.sv @@ -0,0 +1,423 @@ +class ddr_sequence_item extends uvm_sequence_item; + + parameter device_width = 4; + parameter Physical_Rank_No = 1; + + `uvm_object_utils(ddr_sequence_item) + + + //================================ dfi_freq_ratio abstraction ==============================// + //According to DFI, freq ratio 'b00 = 1:1, 'b01 = 1:2, 'b10 = 1:4 + `ifdef ratio_1_to_1 + bit [1:0] dfi_freq_ratio = 'b00; + `elsif ratio_1_to_2 + bit [1:0] dfi_freq_ratio = 'b01; + `elsif ratio_1_to_4 + bit [1:0] dfi_freq_ratio = 'b10; + `else + bit [1:0] dfi_freq_ratio = 'b00; //Default + `endif + + + //================================ dfi_reset_n abstraction =================================// + bit reset_n_i = 1; + bit en_i = 1; + bit dfi_reset_n; + + //================================ phycrc_mode_i abstraction ===============================// + bit phycrc_mode_i = 0; + + //=============================== No of DES (tCCD) abstraction ==============================// + rand int tCCD; //******Abdullah: changed type from "randc" to rand + rand int max_tCCD; //******Abdullah: changed type from "randc" to rand + int number_of_cycles_between_RD; // used for interamble coverage + int number_of_cycles_between_MRR; // used for interamble coverage + + + //===================================== Data abstraction =====================================// + rand bit [2*device_width-1:0] data ; //data + bit dqs = 1; + byte MR [50:0] ; //MRs + bit CS_DA_o; + logic [2*device_width-1:0] jedec_rddata_queue [$]; + bit is_data_only; + bit termination_flag; + + //=============================== For rand test abstraction ====================================// + rand command_t CMD_prev; + rand bit AP_prev; + rand bit command_cancel_prev; + + //=============================== dfi_address/CA abstraction ===================================// + rand command_t CMD; + randc bit [1:0] BA; //Bank Address + randc bit [2:0] BG; //Bank Group + randc bit [3:0] CID; + randc bit [17:0] ROW; //Row Address + randc bit [10:2] Col; //Column Address + randc bit AP; + randc bit BL_mod; + rand bit [7:0] MRA; //Mode Register Address + rand bit [7:0] OP; //Mode Register Write Data (Sent on the CA bus) + randc bit CW; //Control Word + rand bit C10; + rand bit command_cancel; + + //=============================== MR Abstraction =====================================// + burst_length_t burst_length; // burst length value in the MR + burst_length_t actual_burst_length; + byte RL = 22; // Read/CAS latency [22:66] + bit [2:0] read_pre_amble = 0; + bit read_post_amble = 0; + bit CRC_enable = 0; + + //=============================== dfi_rddata_en abstraction ===============================// + burst_length_t num_of_words; //number of cycle to make dfi_rddata_en HIGH = 0.5*BL + rand bit rddata_en; // I need this item (John) in the driver + logic [2*device_width-1:0] dfi_rddata_queue [$]; + + + //===========================================================================// + // Constraints // + //===========================================================================// + //constraint c_dfi_reset_n {dfi_reset_n == 1;} // df1_reset_n is forced to 0 manually at the begnning of each sequence. + + constraint c_MRA {MRA inside {8'h00, 8'h08, 8'h32};} // MR0, MR8, MR40, MR50 (The only registers used in the current DUT) + + constraint c_OP{ + if (MRA == 8'h00){ // MR0 + OP[1:0] inside {[2'b00:2'b10]}; // Burst Length: exlcude 11 (BL32 OTF) because it is not implemented in the current design + OP[6:2] inside {[5'b000_00:5'b101_10]}; // CAS Latency (RL) + OP[7] == 0; // RFU bit = 0 + }else { + if (MRA == 8'h08){ // MR8 + OP[2:0] inside {[3'b000:3'b100]}; // Read Preamble Settings + OP[5] == 0; // RFU bit = 0 + } else { + if (MRA == 8'h32){ // MR50 + OP[0] dist {0:/70, 1:/30}; // To favor the default value for most cases + OP[7:6] == 0; // RFU bits = 0 + }}} + solve MRA before OP; + } + + constraint c_command_cancel {command_cancel dist {0:/95, 1:/5};} + + constraint c_tCCD{ + if (CMD_prev == MRW) { + if (command_cancel){ + tCCD inside {[8:8 + max_tCCD]}; + } + else { + if (CMD == MRW){ + tCCD inside {[8 :8 + max_tCCD]}; //Note min tMRW = 8 clk Page 20 + } + else { + tCCD inside {[16:16 + max_tCCD]}; //Note min tMRD = 16 clk + } + } + } + else if (CMD_prev == MRR) { + if (command_cancel){ + tCCD inside {[8:8 + max_tCCD]}; + } + else { + if (CMD == MRR){ + tCCD inside {[16:16 + max_tCCD]}; //Note min tMRR = 16 clk (back to back MRRs) + } + else if (CMD == MRW) { + tCCD inside {[RL + 9 : RL + 9 + max_tCCD]}; /*Need Attention*/ //Note min from MRR to MRW = CL + BL/2 +1 = CL + 9 + } + else { + tCCD inside {[16:16 + max_tCCD]}; //Note min tMRD = 16 clk + } + } + } + else if (CMD_prev == RD) { + if (command_cancel){ + tCCD inside {[8:8 + max_tCCD]}; + } + else { + if (CMD == PREab){ + tCCD inside {[12:12 + max_tCCD]}; //Note min tRTP = 12 clk = 7.5 ns (Jedec Page 127, P 446) + } + else if (CMD == RD) { + tCCD inside {[8:8 + max_tCCD]}; /*Need Attention*/ //Note min tCCD_s, tCCD_L = 8 (p444) BL16 in BL32 OTF or whatever (but in Fixed BL32 theremust be a dummy read after 8 nCK) + } + else { //Else AP must be activated (see rand seq constraints) + tCCD inside {[36:36 + max_tCCD]}; //Note min delay = tRTP + tRP = 36 (Jedec Page 134) + } + } + } + else if (CMD_prev == ACT) { + if (command_cancel){ + tCCD inside {[8:8 + max_tCCD]}; + } + else { + if (CMD == ACT) { + tCCD inside {[8:8 + max_tCCD]}; //Note: tRRD = 8 clk (Act to ACt) (Jedec page 446) + } //else : RD cmd + else { + tCCD inside {[24:24 + max_tCCD]}; //Note: tRCD = 14 ns = 24 clk (ACT to Read or Write command) (Jedec Page 412) + } + } + } + else if (CMD_prev == PREab) { + if (CMD == PREab){ + tCCD inside {[2:2 + max_tCCD]}; //Prechage to precharge delay tPPD = 2 P115 + } + else { + tCCD inside {[24:24 + max_tCCD]}; //Note: tRP = 14 ns = 24 clk (ROW Precharge) (Jedec Page 412) + } + } + solve CMD before tCCD; + solve max_tCCD before tCCD; + } + + + + + constraint c_CMD{ + if (CMD_prev == MRW) { + CMD inside {MRW, MRR, ACT}; + } + else if (CMD_prev == MRR) { + CMD inside {MRW, MRR, ACT}; + } + else if (CMD_prev == RD) { + if ((!AP_prev) && (!command_cancel_prev)){ //If Auto Precharge is activated (active low) and not cancelled + CMD inside {MRW, MRR, ACT}; + } + else { + CMD inside {PREab, RD}; + } + } + else if (CMD_prev == ACT) { + if (command_cancel_prev) { + CMD inside {MRW, MRR, ACT}; + } + else { + CMD inside {ACT, RD}; + CMD dist {ACT:/20, RD:/80}; //Favor rd after act + } + } + else if (CMD_prev == PREab) { + CMD inside {ACT, MRW, MRR/*, PREab*/}; + } + else { + CMD inside {MRW, MRR, ACT}; + } + solve CMD_prev before CMD; + } + + + constraint c_rddata_en{ + if ((CMD == RD)||(CMD == MRR)) { + rddata_en == 1; + } + else { + rddata_en == 0; + } + solve CMD before rddata_en; + } + + //***********Functions***********// + extern function new (string name = "ddr_sequence_item"); + + virtual function void do_copy (uvm_object rhs); + ddr_sequence_item item; + if (!$cast(item, rhs)) begin + `uvm_error("do_copy:","Cast failed") + return; + end + super.do_copy(rhs); // chain the copy with parent classes + data = item.data ; + dqs = item.dqs; + CS_DA_o = item.CS_DA_o; + jedec_rddata_queue = item.jedec_rddata_queue; + is_data_only = item.is_data_only; + dfi_freq_ratio = item.dfi_freq_ratio; + dfi_reset_n = item.dfi_reset_n; + phycrc_mode_i = item.phycrc_mode_i; + CMD = item.CMD; + BA = item.BA; + BG = item.BG; + CID = item.CID; + ROW = item.ROW; + Col = item.Col; + AP = item.AP; + BL_mod = item.BL_mod; + MRA = item.MRA; + OP = item.OP; + CW = item.CW; + command_cancel = item.command_cancel; + burst_length = item.burst_length; + actual_burst_length = item.actual_burst_length; + RL = item.RL; + tCCD = item.tCCD; + AP = item.AP; + read_pre_amble = item.read_pre_amble; + read_post_amble = item.read_post_amble; + CRC_enable = item.CRC_enable; + //num_of_words = item.num_of_words; //**********Abdullah: Remove because not used anymore + rddata_en = item.rddata_en; + dfi_rddata_queue = item.dfi_rddata_queue; + number_of_cycles_between_RD = item.number_of_cycles_between_RD; + number_of_cycles_between_MRR = item.number_of_cycles_between_MRR; + endfunction : do_copy + + virtual function string convert2string(); + string contents = ""; + $sformat(contents, "%s \n CMD \t\t= %p\n",contents, CMD); + $sformat(contents, "%s dfi_rddata_queue \t= %p\n",contents, dfi_rddata_queue); + $sformat(contents, "%s dfi_freq_ratio \t= %p\n",contents, dfi_freq_ratio); + $sformat(contents, "%s dfi_reset_n \t= %p\n",contents, dfi_reset_n); + $sformat(contents, "%s phycrc_mode_i \t= %p\n",contents, phycrc_mode_i); + $sformat(contents, "%s data \t\t= %p\n",contents, data); + $sformat(contents, "%s dqs \t\t= %p\n",contents, dqs); + $sformat(contents, "%s CS_DA_o \t\t= %p\n",contents, CS_DA_o); + $sformat(contents, "%s jedec_rddata_queue\t= %p\n",contents, jedec_rddata_queue); + $sformat(contents, "%s is_data_only \t= %p\n",contents, is_data_only); + $sformat(contents, "%s BA \t\t= %p\n",contents, BA); + $sformat(contents, "%s BG \t\t= %p\n",contents, BG); + $sformat(contents, "%s CID \t\t= %p\n",contents, CID); + $sformat(contents, "%s ROW \t\t= %p\n",contents, ROW); + $sformat(contents, "%s Col \t\t= %p\n",contents, Col); + $sformat(contents, "%s AP \t\t= %p\n",contents, AP); + $sformat(contents, "%s BL_mod \t\t= %p\n",contents, BL_mod); + $sformat(contents, "%s MRA \t\t= %p\n",contents, MRA); + $sformat(contents, "%s OP \t\t= %p\n",contents, OP); + $sformat(contents, "%s CW \t\t= %p\n",contents, CW); + $sformat(contents, "%s command_cancel \t= %p\n",contents, command_cancel); + $sformat(contents, "%s burst_length \t= %p\n",contents, burst_length); + $sformat(contents, "%s actual_burst_length \t= %p\n",contents, actual_burst_length); + $sformat(contents, "%s RL \t\t= %p\n",contents, RL); + $sformat(contents, "%s read_pre_amble \t= %p\n",contents, read_pre_amble); + $sformat(contents, "%s read_post_amble \t= %p\n",contents, read_post_amble); + $sformat(contents, "%s CRC_enable \t= %p\n",contents, CRC_enable); + //$sformat(contents, "%s num_of_words \t= %p\n",contents, num_of_words); //**********Abdullah: Remove because not used anymore + $sformat(contents, "%s rddata_en \t= %p\n",contents, rddata_en); + $sformat(contents, "%s is_data_only \t= %p\n",contents, is_data_only); + $sformat(contents, "%s number_of_cycles_between_RD \t= %p\n",contents, number_of_cycles_between_RD); + $sformat(contents, "%s number_of_cycles_between_MRR \t= %p\n",contents, number_of_cycles_between_MRR); + return contents; + // To print the content of any object, use the following: + // `uvm_info("obj_name", obj_name.convert2string(), UVM_MEDIUM) + endfunction : convert2string + + virtual function string convert2string_Compact(); + string contents = ""; + $sformat(contents, "%s \n CMD \t\t= %p\n",contents, CMD); + $sformat(contents, "%s dfi_rddata_queue \t= %p\n",contents, dfi_rddata_queue); + $sformat(contents, "%s command_cancel \t= %p\n",contents, command_cancel); + $sformat(contents, "%s tCCD \t\t= %p\n",contents, tCCD); + $sformat(contents, "%s AP \t\t= %p\n",contents, AP); + $sformat(contents, "%s BL_mod \t\t= %p\n",contents, BL_mod); + $sformat(contents, "%s MRA \t\t= %p\n",contents, MRA); + $sformat(contents, "%s burst_length \t= %p\n",contents, burst_length); + $sformat(contents, "%s actual_burst_length \t= %p\n",contents, actual_burst_length); + $sformat(contents, "%s RL \t\t= %p\n",contents, RL); + $sformat(contents, "%s read_pre_amble \t= %p\n",contents, read_pre_amble); + return contents; + // To print the content of any object, use the following: + // `uvm_info("obj_name", obj_name.convert2string_Compact(), UVM_MEDIUM) + endfunction : convert2string_Compact + + virtual function void do_print(uvm_printer printer); + $display("\n\n\t\t*** print() and sprint() are not implemented ", "for this transaction type ***\n\n"); + endfunction : do_print + + +endclass : ddr_sequence_item + + +function ddr_sequence_item::new (string name = "ddr_sequence_item"); + super.new(name); +endfunction + + +/* +variables used for coverage: + From data thread: + actual_burst_length + jedec_rddata_queue + OP (if MRR) + From cmd thread: + CMD + BA + BG + CID + ROW + MRA + BL_mod + command_cancel + OP (if MRW) + CW + Col + AP + number_of_cycles_between_RD + RL + read_pre_amble + burst_length // the burst length in the MR + +*/ +/* +ACT: +CMD +ROW +BA +BG +CID +command_cancel +------------------------------------------- +MRW: +CMD +MRA +command_cancel +OP +CW +burst_length +RL +read_pre_amble +read_post_amble +-------------------------------------------- +MRR: +CMD +MRA +command_cancel +CW +burst_length +actual_burst_length +RL +read_pre_amble +read_post_amble +-------------------------------------------- +RD: +CMD +BL_mod +BA +BG +CID +command_cancel +Col +AP +burst_length +actual_burst_length +RL +read_pre_amble +read_post_amble +-------------------------------------------- +NOP: +CMD +command_cancel +-------------------------------------------- +precharge: +CMD +BA +BG +CID +command_cancel +-------------------------------------------- +*/ +// New Variable: actual_burst_length +