Add testbench for LED blinker, enhance bram_writer with state management, and update test script for overflow/underflow handling

This commit is contained in:
2025-04-17 22:55:49 +02:00
parent 667632bfa3
commit a054085341
7 changed files with 185 additions and 44 deletions

View File

@@ -0,0 +1,74 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb_led_blinker is
end entity;
architecture behavior of tb_led_blinker is
-- Constants
constant CLK_PERIOD_NS : time := 10 ns;
constant BLINK_PERIOD_MS : integer := 1000;
constant N_BLINKS : integer := 4;
-- DUT signals
signal clk : std_logic := '0';
signal aresetn : std_logic := '0';
signal start_blink : std_logic := '0';
signal led : std_logic;
begin
-- Clock process
clk_process : process
begin
while true loop
clk <= not clk;
wait for CLK_PERIOD_NS / 2;
end loop;
end process;
-- Instantiate DUT
uut: entity work.led_blinker
generic map (
CLK_PERIOD_NS => 10,
BLINK_PERIOD_MS => BLINK_PERIOD_MS,
N_BLINKS => N_BLINKS
)
port map (
clk => clk,
aresetn => aresetn,
start_blink => start_blink,
led => led
);
-- Stimulus process
stimulus : process
begin
-- Reset
aresetn <= '0';
wait for 50 ns;
aresetn <= '1';
wait for 50 ns;
-- Primo impulso di start_blink
start_blink <= '1';
wait for 10 ns;
start_blink <= '0';
-- Aspetta met<65> blinking, poi rilancia start_blink
wait for 3 sec;
-- Secondo impulso (durante blinking)
start_blink <= '1';
wait for 10 ns;
start_blink <= '0';
-- Aspetta che finisca tutto
wait for 10 sec;
-- Fine simulazione
assert false report "Test completed." severity failure;
end process;
end architecture;

View File

@@ -46,7 +46,7 @@ ARCHITECTURE rtl OF bram_writer IS
);
END COMPONENT;
TYPE state_type IS (IDLE, RECEIVING, CHECK_START_CONV, CONVOLUTION);
TYPE state_type IS (IDLE, RECEIVING, CHECK_DATA, CONVOLUTION);
SIGNAL state : state_type := IDLE;
SIGNAL s_axis_tready_int : STD_LOGIC := '0';
@@ -58,6 +58,8 @@ ARCHITECTURE rtl OF bram_writer IS
SIGNAL wr_addr : STD_LOGIC_VECTOR(ADDR_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); -- Write address for BRAM
SIGNAL overflow_flag : STD_LOGIC := '0'; -- Overflow flag for BRAM write
BEGIN
-- Instantiate BRAM controller
@@ -100,6 +102,8 @@ BEGIN
write_ok <= '0';
overflow <= '0';
underflow <= '0';
overflow_flag <= '0';
ELSE
-- Default assignments for each clock cycle
start_conv <= '0';
@@ -126,9 +130,9 @@ BEGIN
IF s_axis_tvalid = '1' AND s_axis_tready_int = '1' THEN
-- Check for overflow: if address reaches max image size
IF unsigned(wr_addr) = (IMG_SIZE ** 2 - 1) THEN
overflow <= '1';
state <= IDLE;
ELSE
overflow_flag <= '1';
END IF;
-- Increment write address and write data to BRAM
wr_addr <= STD_LOGIC_VECTOR(unsigned(wr_addr) + 1);
bram_we <= '1'; -- Enable write to BRAM
@@ -136,14 +140,17 @@ BEGIN
-- Check for last data signal
IF s_axis_tlast = '1' THEN
state <= CHECK_START_CONV;
END IF;
state <= CHECK_DATA;
END IF;
END IF;
WHEN CHECK_START_CONV =>
-- Check for underflow: if not enough data received
IF unsigned(wr_addr) < (IMG_SIZE ** 2 - 2) THEN
WHEN CHECK_DATA =>
-- Check for overflow/underflow
IF overflow_flag = '1' THEN
overflow <= '1';
overflow_flag <= '0';
state <= IDLE;
ELSIF unsigned(wr_addr) < (IMG_SIZE ** 2 - 1) THEN
underflow <= '1';
state <= IDLE;
ELSE

View File

@@ -1,28 +1,78 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity led_blinker is
generic (
CLK_PERIOD_NS: POSITIVE :=10;
BLINK_PERIOD_MS : POSITIVE :=1000;
N_BLINKS : POSITIVE := 4
CLK_PERIOD_NS : positive := 10;
BLINK_PERIOD_MS : positive := 1000;
N_BLINKS : positive := 4
);
port (
clk : in std_logic;
aresetn : in std_logic;
start_blink : in std_logic;
led: out std_logic
led : out std_logic
);
end entity led_blinker;
end entity;
architecture rtl of led_blinker is
-- Calcoli per larghezze e valori massimi
constant CLK_PER_MS : integer := 1_000_000 / CLK_PERIOD_NS;
constant MAX_COUNT : integer := CLK_PER_MS * BLINK_PERIOD_MS;
constant CNT_WIDTH : integer := integer(ceil(log2(real(MAX_COUNT))));
constant BLINK_WIDTH : integer := integer(ceil(log2(real(N_BLINKS + 1))));
signal counter : unsigned(CNT_WIDTH-1 downto 0) := (others => '0');
signal blink_cnt : unsigned(BLINK_WIDTH-1 downto 0) := (others => '0');
signal blinking : std_logic := '0';
signal led_reg : std_logic := '0';
signal start_prev : std_logic := '0';
signal start_edge : std_logic;
begin
led <= led_reg;
process(clk, aresetn)
begin
if aresetn = '0' then
counter <= (others => '0');
blink_cnt <= (others => '0');
blinking <= '0';
led_reg <= '0';
start_prev <= '0';
start_edge <= '0';
elsif rising_edge(clk) then
-- Rileva fronte di salita di start_blink
start_edge <= start_blink and not start_prev;
start_prev <= start_blink;
if blinking = '0' then
if start_edge = '1' then
blinking <= '1';
counter <= (others => '0');
blink_cnt <= (others => '0');
led_reg <= '1';
end if;
else -- blinking = '1'
if counter = to_unsigned(MAX_COUNT - 1, counter'length) then
counter <= (others => '0');
led_reg <= not led_reg;
if led_reg = '1' then -- fine fase ON
blink_cnt <= blink_cnt + 1;
if blink_cnt + 1 = to_unsigned(N_BLINKS, blink_cnt'length) then
blinking <= '0';
led_reg <= '0';
end if;
end if;
else
counter <= counter + 1;
end if;
end if;
end if;
end process;
end architecture;

View File

@@ -1,4 +1,4 @@
import sys
""" import sys
import subprocess
def install_and_import(package, package_name=None):
@@ -16,7 +16,7 @@ install_and_import("serial", "pyserial")
install_and_import("PIL", "pillow")
install_and_import("tqdm")
install_and_import("numpy")
install_and_import("scipy")
install_and_import("scipy") """
from serial import Serial
import serial.tools.list_ports
@@ -25,8 +25,11 @@ from PIL import Image
from scipy.signal import convolve2d
import numpy as np
IMAGE_NAME2 = "test2.png"
IMAGE_NAME1 = "test1.png"
IMAGE_OF = r'C:\DESD\LAB2\test\test_of.png'
IMAGE_UF = r'C:\DESD\LAB2\test\test_uf.png'
IMAGE_NAME3 = r'C:\DESD\LAB2\test\test3.png'
IMAGE_NAME2 = r'C:\DESD\LAB2\test\test2.png'
IMAGE_NAME1 = r'C:\DESD\LAB2\test\test1.png'
BASYS3_PID = 0x6010
BASYS3_VID = 0x0403
@@ -42,16 +45,19 @@ for port in serial.tools.list_ports.comports():
if not dev:
raise RuntimeError("Basys 3 Not Found!")
test_n = int(input("Insert test number (1 or 2): ").strip())
test_n = int(input("Insert test number (1, 2, 3, overflow (4) or underflow (5)): ").strip())
if test_n not in [1, 2]:
raise RuntimeError("Test number must be 1 or 2")
if test_n not in [1, 2, 3, 4, 5]:
raise RuntimeError("Test number must be 1, 2, 3, 4 (overflow) or 5 (underflow)")
dev = Serial(dev, 115200)
img = Image.open(IMAGE_NAME1 if test_n == 1 else IMAGE_NAME2)
img = Image.open(IMAGE_NAME1 if test_n == 1 else IMAGE_NAME2 if test_n == 2 else IMAGE_NAME3 if test_n == 3 else IMAGE_UF if test_n == 5 else IMAGE_OF)
if img.mode != "RGB":
img = img.convert("RGB")
IMG_WIDTH, IMG_HEIGHT = img.size # Get dimensions from the image
mat = np.asarray(img, dtype=np.uint8)
mat = mat[:, :, :3]
@@ -75,6 +81,13 @@ for i in tqdm(range(IMG_HEIGHT)):
dev.write(b'\xf1')
dev.flush()
if test_n == 4:
print("Check for overflow (LED U16)")
exit()
elif test_n == 5:
print("Check for underflow (LED U19)")
exit()
res = dev.read(IMG_HEIGHT * IMG_WIDTH + 2)
res_img = np.frombuffer(res[1:-1], dtype=np.uint8)

BIN
LAB2/test/test_of.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
LAB2/test/test_uf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -47,7 +47,7 @@
<Option Name="IPStaticSourceDir" Val="$PIPUSERFILESDIR/ipstatic"/>
<Option Name="EnableBDX" Val="FALSE"/>
<Option Name="DSABoardId" Val="basys3"/>
<Option Name="WTXSimLaunchSim" Val="22"/>
<Option Name="WTXSimLaunchSim" Val="31"/>
<Option Name="WTModelSimLaunchSim" Val="0"/>
<Option Name="WTQuestaLaunchSim" Val="0"/>
<Option Name="WTIesLaunchSim" Val="0"/>
@@ -101,6 +101,7 @@
</Config>
</FileSet>
<FileSet Name="sim_1" Type="SimulationSrcs" RelSrcDir="$PSRCDIR/sim_1" RelGenDir="$PGENDIR/sim_1">
<Filter Type="Srcs"/>
<File Path="$PPRDIR/../../sim/tb_bram_writer.vhd">
<FileInfo>
<Attr Name="UsedIn" Val="synthesis"/>
@@ -156,9 +157,7 @@
<Runs Version="1" Minor="15">
<Run Id="synth_1" Type="Ft3:Synth" SrcSet="sources_1" Part="xc7a35tcpg236-1" ConstrsSet="constrs_1" Description="Vivado Synthesis Defaults" AutoIncrementalCheckpoint="false" WriteIncrSynthDcp="false" State="current" IncludeInArchive="true" AutoIncrementalDir="$PSRCDIR/utils_1/imports/synth_1">
<Strategy Version="1" Minor="2">
<StratHandle Name="Vivado Synthesis Defaults" Flow="Vivado Synthesis 2020">
<Desc>Vivado Synthesis Defaults</Desc>
</StratHandle>
<StratHandle Name="Vivado Synthesis Defaults" Flow="Vivado Synthesis 2020"/>
<Step Id="synth_design"/>
</Strategy>
<ReportStrategy Name="Vivado Synthesis Default Reports" Flow="Vivado Synthesis 2020"/>
@@ -167,9 +166,7 @@
</Run>
<Run Id="impl_1" Type="Ft2:EntireDesign" Part="xc7a35tcpg236-1" ConstrsSet="constrs_1" Description="Default settings for Implementation." AutoIncrementalCheckpoint="false" WriteIncrSynthDcp="false" State="current" SynthRun="synth_1" IncludeInArchive="true" GenFullBitstream="true" AutoIncrementalDir="$PSRCDIR/utils_1/imports/impl_1">
<Strategy Version="1" Minor="2">
<StratHandle Name="Vivado Implementation Defaults" Flow="Vivado Implementation 2020">
<Desc>Default settings for Implementation.</Desc>
</StratHandle>
<StratHandle Name="Vivado Implementation Defaults" Flow="Vivado Implementation 2020"/>
<Step Id="init_design"/>
<Step Id="opt_design"/>
<Step Id="power_opt_design"/>