Add new VHDL entities for image processing and update test scripts for Lab2

This commit is contained in:
2025-03-29 00:50:32 +01:00
parent 58f8384507
commit a5264642a6
14 changed files with 552 additions and 18 deletions

6
LAB2/cons/pins.xdc Normal file
View File

@@ -0,0 +1,6 @@
set_property IOSTANDARD LVCMOS33 [get_ports led_of]
set_property IOSTANDARD LVCMOS33 [get_ports led_ok]
set_property IOSTANDARD LVCMOS33 [get_ports led_uf]
set_property PACKAGE_PIN U16 [get_ports led_of]
set_property PACKAGE_PIN E19 [get_ports led_ok]
set_property PACKAGE_PIN U19 [get_ports led_uf]

128
LAB2/sim/tb_img_conv.vhd Normal file
View File

@@ -0,0 +1,128 @@
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 03/16/2025 04:23:36 PM
-- Design Name:
-- Module Name: img_conv_tb - Behavioral
-- Project Name:
-- Target Devices:
-- Tool Versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity img_conv_tb is
-- Port ( );
end img_conv_tb;
architecture Behavioral of img_conv_tb is
component img_conv is
generic(
LOG2_N_COLS: POSITIVE :=8;
LOG2_N_ROWS: POSITIVE :=8
);
port (
clk : in std_logic;
aresetn : in std_logic;
m_axis_tdata : out std_logic_vector(7 downto 0);
m_axis_tvalid : out std_logic;
m_axis_tready : in std_logic;
m_axis_tlast : out std_logic;
conv_addr: out std_logic_vector(LOG2_N_COLS+LOG2_N_ROWS-1 downto 0);
conv_data: in std_logic_vector(6 downto 0);
start_conv: in std_logic;
done_conv: out std_logic
);
end component;
constant LOG2_N_COLS: POSITIVE :=2;
constant LOG2_N_ROWS: POSITIVE :=2;
type mem_type is array(0 to (2**LOG2_N_COLS)*(2**LOG2_N_ROWS)-1) of std_logic_vector(6 downto 0);
signal mem : mem_type := (0=>"0000001",others => (others => '0'));
signal clk : std_logic :='0';
signal aresetn : std_logic :='0';
signal m_axis_tdata : std_logic_vector(7 downto 0);
signal m_axis_tvalid : std_logic;
signal m_axis_tready : std_logic;
signal m_axis_tlast : std_logic;
signal conv_addr: std_logic_vector(LOG2_N_COLS+LOG2_N_ROWS-1 downto 0);
signal conv_data: std_logic_vector(6 downto 0);
signal start_conv: std_logic;
signal done_conv: std_logic;
begin
m_axis_tready<='1';
clk <= not clk after 5 ns;
process (clk)
begin
if(rising_edge(clk)) then
conv_data<=mem(to_integer(unsigned(conv_addr)));
end if;
end process;
img_conv_inst: img_conv
generic map(
LOG2_N_COLS => LOG2_N_COLS,
LOG2_N_ROWS => LOG2_N_ROWS
)
port map(
clk => clk,
aresetn => aresetn,
m_axis_tdata => m_axis_tdata,
m_axis_tvalid => m_axis_tvalid,
m_axis_tready => m_axis_tready,
m_axis_tlast => m_axis_tlast,
conv_addr => conv_addr,
conv_data => conv_data,
start_conv => start_conv,
done_conv => done_conv
);
process
begin
wait for 10 ns;
aresetn<='1';
wait until rising_edge(clk);
start_conv<='1';
wait until rising_edge(clk);
start_conv<='0';
wait;
end process;
end Behavioral;

View File

@@ -0,0 +1,94 @@
library ieee;
use ieee.std_logic_1164.all;
Library xpm;
use xpm.vcomponents.all;
entity bram_controller is
generic (
ADDR_WIDTH: POSITIVE :=16
);
port (
clk : in std_logic;
aresetn : in std_logic;
addr: in std_logic_vector(ADDR_WIDTH-1 downto 0);
dout: out std_logic_vector(7 downto 0);
din: in std_logic_vector(7 downto 0);
we: in std_logic
);
end entity bram_controller;
architecture rtl of bram_controller is
begin
-- xpm_memory_spram: Single Port RAM
-- Xilinx Parameterized Macro, version 2020.2
xpm_memory_spram_inst : xpm_memory_spram
generic map (
ADDR_WIDTH_A => ADDR_WIDTH, -- DECIMAL
AUTO_SLEEP_TIME => 0, -- DECIMAL
BYTE_WRITE_WIDTH_A => 8, -- DECIMAL
CASCADE_HEIGHT => 0, -- DECIMAL
ECC_MODE => "no_ecc", -- String
MEMORY_INIT_FILE => "none", -- String
MEMORY_INIT_PARAM => "0", -- String
MEMORY_OPTIMIZATION => "true", -- String
MEMORY_PRIMITIVE => "block", -- String
MEMORY_SIZE => (2**ADDR_WIDTH)*8,-- DECIMAL
MESSAGE_CONTROL => 0, -- DECIMAL
READ_DATA_WIDTH_A => 8, -- DECIMAL
READ_LATENCY_A => 1, -- DECIMAL
READ_RESET_VALUE_A => "0", -- String
RST_MODE_A => "SYNC", -- String
SIM_ASSERT_CHK => 0, -- DECIMAL; 0=disable simulation messages, 1=enable simulation messages
USE_MEM_INIT => 1, -- DECIMAL
WAKEUP_TIME => "disable_sleep", -- String
WRITE_DATA_WIDTH_A => 8, -- DECIMAL
WRITE_MODE_A => "read_first" -- String
)
port map (
dbiterra => open, -- 1-bit output: Status signal to indicate double bit error occurrence
-- on the data output of port A.
douta => dout, -- READ_DATA_WIDTH_A-bit output: Data output for port A read operations.
sbiterra => open, -- 1-bit output: Status signal to indicate single bit error occurrence
-- on the data output of port A.
addra => addr, -- ADDR_WIDTH_A-bit input: Address for port A write and read operations.
clka => clk, -- 1-bit input: Clock signal for port A.
dina => din, -- WRITE_DATA_WIDTH_A-bit input: Data input for port A write operations.
ena => '1', -- 1-bit input: Memory enable signal for port A. Must be high on clock
-- cycles when read or write operations are initiated. Pipelined
-- internally.
injectdbiterra => '0', -- 1-bit input: Controls double bit error injection on input data when
-- ECC enabled (Error injection capability is not available in
-- "decode_only" mode).
injectsbiterra => '0', -- 1-bit input: Controls single bit error injection on input data when
-- ECC enabled (Error injection capability is not available in
-- "decode_only" mode).
regcea => '1', -- 1-bit input: Clock Enable for the last register stage on the output
-- data path.
rsta => (not aresetn), -- 1-bit input: Reset signal for the final port A output register
-- stage. Synchronously resets output port douta to the value specified
-- by parameter READ_RESET_VALUE_A.
sleep => '0', -- 1-bit input: sleep signal to enable the dynamic power saving feature.
wea(0) => we -- WRITE_DATA_WIDTH_A/BYTE_WRITE_WIDTH_A-bit input: Write enable vector
-- for port A input data port dina. 1 bit wide when word-wide writes
-- are used. In byte-wide write configurations, each bit controls the
-- writing one byte of dina to address addra. For example, to
-- synchronously write only bits [15-8] of dina when WRITE_DATA_WIDTH_A
-- is 32, wea would be 4'b0010.
);
-- End of xpm_memory_spram_inst instantiation
end architecture;

54
LAB2/src/bram_writer.vhd Normal file
View File

@@ -0,0 +1,54 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bram_writer is
generic(
ADDR_WIDTH: POSITIVE :=16
);
port (
clk : in std_logic;
aresetn : in std_logic;
s_axis_tdata : in std_logic_vector(7 downto 0);
s_axis_tvalid : in std_logic;
s_axis_tready : out std_logic;
s_axis_tlast : in std_logic;
conv_addr: in std_logic_vector(ADDR_WIDTH-1 downto 0);
conv_data: out std_logic_vector(6 downto 0);
start_conv: out std_logic;
done_conv: in std_logic;
write_ok : out std_logic;
overflow : out std_logic;
underflow: out std_logic
);
end entity bram_writer;
architecture rtl of bram_writer is
component bram_controller is
generic (
ADDR_WIDTH: POSITIVE :=16
);
port (
clk : in std_logic;
aresetn : in std_logic;
addr: in std_logic_vector(ADDR_WIDTH-1 downto 0);
dout: out std_logic_vector(7 downto 0);
din: in std_logic_vector(7 downto 0);
we: in std_logic
);
end component;
begin
end architecture;

35
LAB2/src/depacketizer.vhd Normal file
View File

@@ -0,0 +1,35 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity depacketizer is
generic (
HEADER: INTEGER :=16#FF#;
FOOTER: INTEGER :=16#F1#
);
port (
clk : in std_logic;
aresetn : in std_logic;
s_axis_tdata : in std_logic_vector(7 downto 0);
s_axis_tvalid : in std_logic;
s_axis_tready : out std_logic;
m_axis_tdata : out std_logic_vector(7 downto 0);
m_axis_tvalid : out std_logic;
m_axis_tready : in std_logic;
m_axis_tlast : out std_logic
);
end entity depacketizer;
architecture rtl of depacketizer is
begin
end architecture;

41
LAB2/src/img_conv.vhd Normal file
View File

@@ -0,0 +1,41 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity img_conv is
generic(
LOG2_N_COLS: POSITIVE :=8;
LOG2_N_ROWS: POSITIVE :=8
);
port (
clk : in std_logic;
aresetn : in std_logic;
m_axis_tdata : out std_logic_vector(7 downto 0);
m_axis_tvalid : out std_logic;
m_axis_tready : in std_logic;
m_axis_tlast : out std_logic;
conv_addr: out std_logic_vector(LOG2_N_COLS+LOG2_N_ROWS-1 downto 0);
conv_data: in std_logic_vector(6 downto 0);
start_conv: in std_logic;
done_conv: out std_logic
);
end entity img_conv;
architecture rtl of img_conv is
type conv_mat_type is array(0 to 2, 0 to 2) of integer;
constant conv_mat : conv_mat_type := ((-1,-1,-1),(-1,8,-1),(-1,-1,-1));
begin
end architecture;

28
LAB2/src/led_blinker.vhd Normal file
View File

@@ -0,0 +1,28 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity led_blinker is
generic (
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
);
end entity led_blinker;
architecture rtl of led_blinker is
begin
end architecture;

36
LAB2/src/packetizer.vhd Normal file
View File

@@ -0,0 +1,36 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity packetizer is
generic (
HEADER: INTEGER :=16#FF#;
FOOTER: INTEGER :=16#F1#
);
port (
clk : in std_logic;
aresetn : in std_logic;
s_axis_tdata : in std_logic_vector(7 downto 0);
s_axis_tvalid : in std_logic;
s_axis_tready : out std_logic;
s_axis_tlast : in std_logic;
m_axis_tdata : out std_logic_vector(7 downto 0);
m_axis_tvalid : out std_logic;
m_axis_tready : in std_logic
);
end entity packetizer;
architecture rtl of packetizer is
begin
end architecture;

36
LAB2/src/rgb2gray.vhd Normal file
View File

@@ -0,0 +1,36 @@
---------- DEFAULT LIBRARIES -------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.all; -- For LOG **FOR A CONSTANT!!**
------------------------------------
---------- OTHER LIBRARIES ---------
-- NONE
------------------------------------
entity rgb2gray is
Port (
clk : in std_logic;
resetn : in std_logic;
m_axis_tvalid : out std_logic;
m_axis_tdata : out std_logic_vector(7 downto 0);
m_axis_tready : in std_logic;
m_axis_tlast : out std_logic;
s_axis_tvalid : in std_logic;
s_axis_tdata : in std_logic_vector(7 downto 0);
s_axis_tready : out std_logic;
s_axis_tlast : in std_logic
);
end rgb2gray;
architecture Behavioral of rgb2gray is
begin
end Behavioral;

BIN
LAB2/test/LAB2-Test.exe Normal file

Binary file not shown.

87
LAB2/test/test.py Normal file
View File

@@ -0,0 +1,87 @@
def install_and_import(package, package_name=None):
if package_name is None:
package_name = package
import importlib
try:
importlib.import_module(package)
except ImportError:
import pip
pip.main(['install', package_name])
finally:
globals()[package] = importlib.import_module(package)
install_and_import("Serial", "pyserial")
install_and_import("PIL", "pillow")
install_and_import("tqdm")
install_and_import("numpy")
install_and_import("scipy")
from serial import Serial
import serial.tools.list_ports
from tqdm import tqdm
from PIL import Image
from scipy.signal import convolve2d
import numpy as np
IMAGE_NAME2="test2.png"
IMAGE_NAME1="test1.png"
BASYS3_PID=0x6010
BASYS3_VID=0x0403
IMG_HEIGHT=256
IMG_WIDTH=256
dev=""
for port in serial.tools.list_ports.comports():
if(port.vid==BASYS3_VID and port.pid==BASYS3_PID):
dev=port.device
if not dev:
raise RuntimeError("Basys 3 Not Found!")
test_n=int(input("Insert test number (1 or 2): ").strip())
if(test_n not in [1,2]):
raise RuntimeError("Test numer must be be 1 or 2")
dev=Serial(dev,115200)
img=Image.open(IMAGE_NAME1 if test_n==1 else IMAGE_NAME2)
mat=np.asarray(img,dtype=np.uint8)
mat=mat[:,:,:3]
if(mat.max()>127):
mat=mat//2
buff=mat.tobytes()
mat=np.sum(mat,axis=2)//3
sim_img=convolve2d(mat,[[-1,-1,-1],[-1,8,-1],[-1,-1,-1]], mode="same")
sim_img[sim_img<0]=0
sim_img[sim_img>127]=127
dev.write(b'\xff')
for i in tqdm(range(IMG_HEIGHT)):
dev.write(buff[(i)*IMG_WIDTH*3:(i+1)*IMG_WIDTH*3])
dev.write(b'\xf1')
dev.flush()
res=dev.read(IMG_HEIGHT*IMG_WIDTH+2)
res_img=np.frombuffer(res[1:-1],dtype=np.uint8)
res_img=res_img.reshape((IMG_HEIGHT,IMG_WIDTH))
assert np.all(res_img==sim_img), "Image Mismatch!"
im=Image.fromarray(np.uint8(res_img))
im.show()

BIN
LAB2/test/test1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 951 B

BIN
LAB2/test/test2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 955 B

View File

@@ -1,6 +1,3 @@
[server]
enable = true
[libraries] [libraries]
# Assign separate libraries for each project # Assign separate libraries for each project
lab0_lib.files = [ lab0_lib.files = [
@@ -13,25 +10,17 @@ lab1_lib.files = [
"LAB1/sim/**/*.vhd" "LAB1/sim/**/*.vhd"
] ]
# lab2_lib.files = [ lab2_lib.files = [
# "LAB2/src/**/*.vhd", "LAB2/src/**/*.vhd",
# "LAB2/sim/**/*.vhd" "LAB2/sim/**/*.vhd"
# ] ]
# lab3_lib.files = [ # lab3_lib.files = [
# "LAB3/src/**/*.vhd", # "LAB3/src/**/*.vhd",
# "LAB3/sim/**/*.vhd" # "LAB3/sim/**/*.vhd"
# ] # ]
[analyses] xpm.files = [
on_save = true "C:/Xilinx/Vivado/2020.2/data/ip/xpm/xpm_VCOMP.vhd"
on_open = true
[ghdl]
standard = "08"
library_path = [
"C:/Xilinx/Vivado/2020.2/data/vhdl/src"
] ]
xpm.is_third_party = true
[vhdl]
standard = "2008"