Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial commit of simple cocotb testbenches. #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions sim/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Makefile

# defaults
SIM ?= nvc
TOPLEVEL_LANG ?= vhdl
GUI = 1
SCRIPT_FILE =

ifeq ($(SIM),ghdl)
COMPILE_ARGS = --std=08
endif

SIM_ARGS = --wave=nco.ghw

SRC = ../src

VHDL_SOURCES += $(SRC)/nco.vhd \
$(SRC)/sin_cos_lut.vhd

# use VHDL_SOURCES for VHDL files

# TOPLEVEL is the name of the toplevel module in your Verilog or VHDL file
TOPLEVEL = nco

# MODULE is the basename of the Python test file
MODULE = nco_test

# include cocotb's make rules to take care of the simulator setup
include $(shell cocotb-config --makefiles)/Makefile.sim
138 changes: 132 additions & 6 deletions sim/nco_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,148 @@
from cocotb.clock import Clock

@cocotb.test()
async def my_first_test(dut):
"""Try accessing the design."""
async def enable_disable_test(dut):
"""Test enable input."""

dut.clk.value = 0
dut.init.value = 1
dut.phase_delta.value = 100000
dut.phase_adjust.value = 0
dut.freq_word.value = 100000 # per clock cycle
dut.freq_adjust.value = 0

await cocotb.start(Clock(dut.clk, 10, units="ns").start())

await RisingEdge(dut.clk)

dut.init.value = 0

await Timer(1, units="ms")
await Timer(10, units="us")

dut.enable.value = 1

await Timer(100, units="us")
# enabled for 100us == 10e3 cycles
# for total phase of (10e3 - 1) * freq_word = (10e3 - 1) * 1e5

dut.enable.value = 0

await Timer(10, units="us")

dut._log.info("phase is %s", dut.phase_acc.value)
dut._log.info("phase is %d", dut.phase_acc.value.to_unsigned())
assert dut.phase.value.to_unsigned() == 999900000, "phase is not 999900000!" # 1e9 - 1e5


@cocotb.test()
async def enable_disable_test_2(dut):
"""Test enable input."""

dut.clk.value = 0
dut.init.value = 1
dut.freq_word.value = 100000 # per clock cycle
dut.freq_adjust.value = 0

await cocotb.start(Clock(dut.clk, 10, units="ns").start())

await RisingEdge(dut.clk)

dut.init.value = 0

await Timer(10, units="us")

dut.enable.value = 1

await Timer(100, units="us")
# enabled for 100us == 10e3 cycles
# for total phase of (10e3 - 1) * freq_word = (10e3) * 1e5
await Timer(100, units="us")
# enabled for 100us == 10e3 cycles
# for total phase of (10e3 - 1) * freq_word = (10e3 - 1) * 1e5

dut.enable.value = 0

await Timer(10, units="us")

dut._log.info("phase is %s", dut.phase_acc.value)
dut._log.info("phase is %d", dut.phase_acc.value.to_unsigned())
assert dut.phase.value.to_unsigned() == 1999900000, "phase is not 1999900000!" # 1e9 * 2 - 1e5


@cocotb.test()
async def freq_adjust_test(dut):
"""Test frequency adjust."""

dut.clk.value = 0
dut.init.value = 1
dut.enable.value = 0
dut.freq_word.value = 100000 # per clock cycle
dut.freq_adjust.value = 100 # per clock cycle
dut.freq_adj_zero.value = False
dut.freq_adj_valid.value = True

await cocotb.start(Clock(dut.clk, 10, units="ns").start())

await RisingEdge(dut.clk)

dut.init.value = 0

await Timer(10, units="us")

dut.enable.value = 1

await Timer(100, units="us")
# enabled for 100us == 10e3 cycles
# for total phase of 10e3 - 1 (cycles) * (freq_word + freq_adjust) - freq_adjust
# = (10e3 - 1) * (1e5 + 100) - 100 ?? why do we miss one cycle of freq_adj

dut.enable.value = 0

await Timer(10, units="us")

dut._log.info("phase is %s", dut.phase_acc.value)
dut._log.info("phase is %d", dut.phase_acc.value.to_unsigned())
assert dut.phase.value.to_unsigned() == 1000899800, "phase is not 1000899800!" #


@cocotb.test()
async def dynamic_freq_adjust_test(dut):
"""Test frequency adjust dynamically."""

dut.clk.value = 0
dut.init.value = 1
dut.enable.value = 0
dut.freq_word.value = 100000 # per clock cycle
dut.freq_adjust.value = 0
dut.freq_adj_zero.value = True
dut.freq_adj_valid.value = False

await cocotb.start(Clock(dut.clk, 10, units="ns").start())

await RisingEdge(dut.clk)

dut.init.value = 0

await Timer(10, units="us")

dut.enable.value = 1

await Timer(100, units="us")
# enabled for 100us == 10e3 cycles
# for total phase of 10e3 (cycles) * freq_word
# = 10e3 * 1e5

dut.freq_adjust.value = 100
dut.freq_adj_zero.value = False
dut.freq_adj_valid.value = True

await Timer(100, units="us")
# for total phase of 10e3 - 1 (cycles) * (freq_word + freq_adjust)
# = (10e3 - 1) * (1e5 + 100) - 100 ?? again, not sure why we get slippage of freq_adj - delta time?

dut.enable.value = 0

await Timer(10, units="us")

dut._log.info("phase is %s", dut.phase_acc.value)
#assert dut.phase.value != 0, "my_signal_2[0] is not 0!"
dut._log.info("phase is %d", dut.phase_acc.value.to_unsigned())
assert dut.phase.value.to_unsigned() == 2000899800, "phase is not 2000899800!"