observerw's picture
download
raw
7.33 kB
```python
#!/usr/bin/env python3
"""
Testbench for pattern_vg module.
"""
import random
import sys
from pathlib import Path
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, FallingEdge, Timer
from cocotb_tools.runner import get_runner
# Project root is one level above testbench directory
project_root = Path(__file__).resolve().parents[1]
async def reset_dut(dut, active_high=True, duration=10):
"""Reset the DUT."""
if hasattr(dut, "reset"):
dut.reset.value = 1 if active_high else 0
await Timer(duration, units="ns")
dut.reset.value = 0 if active_high else 1
await RisingEdge(dut.clk_in)
await FallingEdge(dut.clk_in)
@cocotb.test()
async def test_reset_and_control_signals(dut):
"""Test reset behavior and control signal passthrough."""
# Create clock
clock = Clock(dut.clk_in, 10, units="ns")
cocotb.start_soon(clock.start())
# Apply reset
await reset_dut(dut, active_high=True, duration=20)
# Test control signal passthrough
for _ in range(10):
vn_val = random.randint(0, 1)
hn_val = random.randint(0, 1)
dn_val = random.randint(0, 1)
dut.vn_in.value = vn_val
dut.hn_in.value = hn_val
dut.dn_in.value = dn_val
await RisingEdge(dut.clk_in)
await FallingEdge(dut.clk_in)
# Control signals should pass through with one cycle delay
assert dut.vn_out.value == vn_val, f"vn_out mismatch: {dut.vn_out.value} != {vn_val}"
assert dut.hn_out.value == hn_val, f"hn_out mismatch: {dut.hn_out.value} != {hn_val}"
assert dut.den_out.value == dn_val, f"den_out mismatch: {dut.den_out.value} != {dn_val}"
@cocotb.test()
async def test_pattern_0_no_pattern(dut):
"""Test pattern 0: no pattern (passthrough)."""
clock = Clock(dut.clk_in, 10, units="ns")
cocotb.start_soon(clock.start())
await reset_dut(dut)
# Set pattern 0
dut.pattern.value = 0
dut.dn_in.value = 1 # Data enable
# Test RGB passthrough
for _ in range(5):
r_val = random.randint(0, 255)
g_val = random.randint(0, 255)
b_val = random.randint(0, 255)
dut.r_in.value = r_val
dut.g_in.value = g_val
dut.b_in.value = b_val
await RisingEdge(dut.clk_in)
await FallingEdge(dut.clk_in)
# RGB should pass through unchanged
assert dut.r_out.value == r_val, f"r_out mismatch: {dut.r_out.value} != {r_val}"
assert dut.g_out.value == g_val, f"g_out mismatch: {dut.g_out.value} != {g_val}"
assert dut.b_out.value == b_val, f"b_out mismatch: {dut.b_out.value} != {b_val}"
@cocotb.test()
async def test_pattern_1_border(dut):
"""Test pattern 1: border pattern."""
clock = Clock(dut.clk_in, 10, units="ns")
cocotb.start_soon(clock.start())
await reset_dut(dut)
# Set pattern 1
dut.pattern.value = 1
dut.dn_in.value = 1
dut.total_active_pix.value = 640
dut.total_active_lines.value = 480
# Test border pixels (should be white)
border_cases = [
(0, 0), # top-left corner
(639, 0), # top-right corner
(0, 479), # bottom-left corner
(639, 479), # bottom-right corner
(320, 0), # top border
(0, 240), # left border
(639, 240), # right border
(320, 479), # bottom border
]
for x, y in border_cases:
dut.x.value = x
dut.y.value = y
dut.r_in.value = 0x12
dut.g_in.value = 0x34
dut.b_in.value = 0x56
await RisingEdge(dut.clk_in)
await FallingEdge(dut.clk_in)
# Border should be white
assert dut.r_out.value == 0xFF, f"Border r_out not white: {dut.r_out.value}"
assert dut.g_out.value == 0xFF, f"Border g_out not white: {dut.g_out.value}"
assert dut.b_out.value == 0xFF, f"Border b_out not white: {dut.b_out.value}"
# Test non-border pixel (should pass through)
dut.x.value = 100
dut.y.value = 100
dut.r_in.value = 0x12
dut.g_in.value = 0x34
dut.b_in.value = 0x56
await RisingEdge(dut.clk_in)
await FallingEdge(dut.clk_in)
assert dut.r_out.value == 0x12, f"Non-border r_out mismatch: {dut.r_out.value}"
assert dut.g_out.value == 0x34, f"Non-border g_out mismatch: {dut.g_out.value}"
assert dut.b_out.value == 0x56, f"Non-border b_out mismatch: {dut.b_out.value}"
@cocotb.test()
async def test_pattern_2_moirex(dut):
"""Test pattern 2: moireX pattern."""
clock = Clock(dut.clk_in, 10, units="ns")
cocotb.start_soon(clock.start())
await reset_dut(dut)
# Set pattern 2
dut.pattern.value = 2
dut.dn_in.value = 1
# Test even and odd x coordinates
test_cases = [(100, 0), (101, 1), (102, 0), (103, 1)]
for x_val, expected_white in test_cases:
dut.x.value = x_val
dut.y.value = 50
dut.r_in.value = 0x12
dut.g_in.value = 0x34
dut.b_in.value = 0x56
await RisingEdge(dut.clk_in)
await FallingEdge(dut.clk_in)
if expected_white:
# Odd x should be white
assert dut.r_out.value == 0xFF, f"moireX odd x not white: {dut.r_out.value}"
assert dut.g_out.value == 0xFF, f"moireX odd x not white: {dut.g_out.value}"
assert dut.b_out.value == 0xFF, f"moireX odd x not white: {dut.b_out.value}"
else:
# Even x should be black
assert dut.r_out.value == 0x00, f"moireX even x not black: {dut.r_out.value}"
assert dut.g_out.value == 0x00, f"moireX even x not black: {dut.g_out.value}"
assert dut.b_out.value == 0x00, f"moireX even x not black: {dut.b_out.value}"
@cocotb.test()
async def test_pattern_4_ramp(dut):
"""Test pattern 4: ramp pattern."""
clock = Clock(dut.clk_in, 10, units="ns")
cocotb.start_soon(clock.start())
await reset_dut(dut)
# Set pattern 4
dut.pattern.value = 4
dut.dn_in.value = 1
dut.total_active_pix.value = 10
dut.ramp_step.value = 0x100 # 8-bit integer step (1.0 in fixed point)
# Test ramp accumulation
for i in range(10):
dut.x.value = i
await RisingEdge(dut.clk_in)
await FallingEdge(dut.clk_in)
# Ramp value should increase by 1 each pixel
expected_rgb = i if i < 256 else 255
assert dut.r_out.value == expected_rgb, f"Ramp r_out mismatch at x={i}: {dut.r_out.value} != {expected_rgb}"
assert dut.g_out.value == expected_rgb, f"Ramp g_out mismatch at x={i}: {dut.g_out.value} != {expected_rgb}"
assert dut.b_out.value == expected_rgb, f"Ramp b_out mismatch at x={i}: {dut.b_out.value} != {expected_rgb}"
# Test reset at end of line
dut.x.value = 9 # Last pixel
await RisingEdge(dut.clk_in)
await FallingEdge(dut.clk_in)
# Next pixel should start from ramp_step
dut.x.value = 0
await RisingEdge(dut.clk_in)
await FallingEdge(dut.clk_in)
assert dut.r_out.value == 1, f"Ramp reset mismatch: {dut.r_out.value} != 1"
def run_tests():
"""Run the tests using cocotb runner."""
sim = "icarus"

Xet Storage Details

Size:
7.33 kB
·
Xet hash:
ab2883ddb8fc7b8f4e972b219bf0e94c869d7f493376c56a0d73d9663983e3d2

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.