diff --git a/.gitignore b/.gitignore index 7747d92..73b2a23 100644 --- a/.gitignore +++ b/.gitignore @@ -43,7 +43,7 @@ *.wdf *.lpr *.bxml - +*.zip # Vivado project directories *.sim/ @@ -64,6 +64,8 @@ vivado_pid*.str vivado*.backup.jou vivado*.backup.log +# Directories to ignore +.venv # SDK workspace .sdk/ @@ -78,4 +80,8 @@ vivado*.backup.log **/design/**/*.xdc # Other files -**/test/*.zip \ No newline at end of file +**/test/*.zip +**/test/*.exe +*.spec +**/dist/ +**/build/ \ No newline at end of file diff --git a/LAB3/cons/io.xdc b/LAB3/cons/io.xdc index ee4f8ea..262649a 100644 --- a/LAB3/cons/io.xdc +++ b/LAB3/cons/io.xdc @@ -1,3 +1,21 @@ +# pmod I2S2 connected to JB +set_property IOSTANDARD LVCMOS33 [get_ports rx_lrck_0] +set_property IOSTANDARD LVCMOS33 [get_ports rx_mclk_0] +set_property IOSTANDARD LVCMOS33 [get_ports rx_sclk_0] +set_property IOSTANDARD LVCMOS33 [get_ports rx_sdin_0] +set_property IOSTANDARD LVCMOS33 [get_ports tx_lrck_0] +set_property IOSTANDARD LVCMOS33 [get_ports tx_mclk_0] +set_property IOSTANDARD LVCMOS33 [get_ports tx_sclk_0] +set_property IOSTANDARD LVCMOS33 [get_ports tx_sdout_0] +set_property PACKAGE_PIN A14 [get_ports tx_mclk_0] +set_property PACKAGE_PIN A16 [get_ports tx_lrck_0] +set_property PACKAGE_PIN B15 [get_ports tx_sclk_0] +set_property PACKAGE_PIN B16 [get_ports tx_sdout_0] +set_property PACKAGE_PIN A15 [get_ports rx_mclk_0] +set_property PACKAGE_PIN A17 [get_ports rx_lrck_0] +set_property PACKAGE_PIN C15 [get_ports rx_sclk_0] +set_property PACKAGE_PIN C16 [get_ports rx_sdin_0] + # SPI connected to JA, top row set_property PACKAGE_PIN J1 [get_ports SPI_M_0_ss_io] set_property PACKAGE_PIN G2 [get_ports SPI_M_0_sck_io] @@ -7,7 +25,45 @@ set_property IOSTANDARD LVCMOS33 [get_ports SPI_M_0_io0_io] set_property IOSTANDARD LVCMOS33 [get_ports SPI_M_0_io1_io] set_property IOSTANDARD LVCMOS33 [get_ports SPI_M_0_sck_io] set_property IOSTANDARD LVCMOS33 [get_ports SPI_M_0_ss_io] -set_property OFFCHIP_TERM NONE [get_ports SPI_M_0_io0_io] -set_property OFFCHIP_TERM NONE [get_ports SPI_M_0_io1_io] -set_property OFFCHIP_TERM NONE [get_ports SPI_M_0_sck_io] -set_property OFFCHIP_TERM NONE [get_ports SPI_M_0_ss_io] + +# Button +set_property IOSTANDARD LVCMOS33 [get_ports effect] +set_property PACKAGE_PIN T18 [get_ports effect] + +# Switch +set_property IOSTANDARD LVCMOS33 [get_ports {lfo_enable}] +set_property PACKAGE_PIN V17 [get_ports {lfo_enable}] + +# LEDs +set_property PACKAGE_PIN U16 [get_ports {LED[0]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[0]}] +set_property PACKAGE_PIN E19 [get_ports {LED[1]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[1]}] +set_property PACKAGE_PIN U19 [get_ports {LED[2]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[2]}] +set_property PACKAGE_PIN V19 [get_ports {LED[3]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[3]}] +set_property PACKAGE_PIN W18 [get_ports {LED[4]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[4]}] +set_property PACKAGE_PIN U15 [get_ports {LED[5]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[5]}] +set_property PACKAGE_PIN U14 [get_ports {LED[6]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[6]}] +set_property PACKAGE_PIN V14 [get_ports {LED[7]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[7]}] +set_property PACKAGE_PIN V13 [get_ports {LED[8]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[8]}] +set_property PACKAGE_PIN V3 [get_ports {LED[9]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[9]}] +set_property PACKAGE_PIN W3 [get_ports {LED[10]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[10]}] +set_property PACKAGE_PIN U3 [get_ports {LED[11]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[11]}] +set_property PACKAGE_PIN P3 [get_ports {LED[12]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[12]}] +set_property PACKAGE_PIN N3 [get_ports {LED[13]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[13]}] +set_property PACKAGE_PIN P1 [get_ports {LED[14]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[14]}] +set_property PACKAGE_PIN L1 [get_ports {LED[15]}] + set_property IOSTANDARD LVCMOS33 [get_ports {LED[15]}] \ No newline at end of file diff --git a/LAB3/design/diligent_jstk/diligent_jstk.bd b/LAB3/design/diligent_jstk/diligent_jstk.bd index ced2b7f..1570bb4 100644 --- a/LAB3/design/diligent_jstk/diligent_jstk.bd +++ b/LAB3/design/diligent_jstk/diligent_jstk.bd @@ -5,7 +5,7 @@ "device": "xc7a35tcpg236-1", "name": "diligent_jstk", "rev_ctrl_bd_flag": "RevCtrlBdOff", - "synth_flow_mode": "None", + "synth_flow_mode": "Hierarchical", "tool_version": "2020.2", "validated": "true" }, @@ -13,9 +13,10 @@ "proc_sys_reset_0": "", "clk_wiz_0": "", "AXI4Stream_UART_0": "", - "digilent_jstk2_0": "", "jstk_uart_bridge_0": "", - "axi4stream_spi_master_0": "" + "axi4stream_spi_master_0": "", + "system_ila_0": "", + "digilent_jstk2_0": "" }, "interface_ports": { "usb_uart": { @@ -83,8 +84,8 @@ }, "clk_wiz_0": { "vlnv": "xilinx.com:ip:clk_wiz:6.0", - "xci_name": "diligent_jstk_clk_wiz_0_1", - "xci_path": "ip\\diligent_jstk_clk_wiz_0_1\\diligent_jstk_clk_wiz_0_1.xci", + "xci_name": "diligent_jstk_clk_wiz_0_0", + "xci_path": "ip\\diligent_jstk_clk_wiz_0_0\\diligent_jstk_clk_wiz_0_0.xci", "inst_hier_path": "clk_wiz_0", "parameters": { "CLK_IN1_BOARD_INTERFACE": { @@ -101,6 +102,9 @@ "xci_path": "ip\\diligent_jstk_AXI4Stream_UART_0_0\\diligent_jstk_AXI4Stream_UART_0_0.xci", "inst_hier_path": "AXI4Stream_UART_0", "parameters": { + "UART_BAUD_RATE": { + "value": "115200" + }, "UART_BOARD_INTERFACE": { "value": "usb_uart" }, @@ -109,216 +113,6 @@ } } }, - "digilent_jstk2_0": { - "vlnv": "xilinx.com:module_ref:digilent_jstk2:1.0", - "xci_name": "diligent_jstk_digilent_jstk2_0_0", - "xci_path": "ip\\diligent_jstk_digilent_jstk2_0_0\\diligent_jstk_digilent_jstk2_0_0.xci", - "inst_hier_path": "digilent_jstk2_0", - "reference_info": { - "ref_type": "hdl", - "ref_name": "digilent_jstk2", - "boundary_crc": "0x0" - }, - "interface_ports": { - "m_axis": { - "mode": "Master", - "vlnv": "xilinx.com:interface:axis_rtl:1.0", - "parameters": { - "TDATA_NUM_BYTES": { - "value": "1", - "value_src": "constant" - }, - "TDEST_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TID_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TUSER_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "HAS_TREADY": { - "value": "1", - "value_src": "constant" - }, - "HAS_TSTRB": { - "value": "0", - "value_src": "constant" - }, - "HAS_TKEEP": { - "value": "0", - "value_src": "constant" - }, - "HAS_TLAST": { - "value": "0", - "value_src": "constant" - }, - "FREQ_HZ": { - "value": "100000000", - "value_src": "ip_prop" - }, - "PHASE": { - "value": "0.0", - "value_src": "ip_prop" - }, - "CLK_DOMAIN": { - "value": "/clk_wiz_0_clk_out1", - "value_src": "ip_prop" - } - }, - "port_maps": { - "TDATA": { - "physical_name": "m_axis_tdata", - "direction": "O", - "left": "7", - "right": "0" - }, - "TVALID": { - "physical_name": "m_axis_tvalid", - "direction": "O" - }, - "TREADY": { - "physical_name": "m_axis_tready", - "direction": "I" - } - } - }, - "s_axis": { - "mode": "Slave", - "vlnv": "xilinx.com:interface:axis_rtl:1.0", - "parameters": { - "TDATA_NUM_BYTES": { - "value": "1", - "value_src": "constant" - }, - "TDEST_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TID_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TUSER_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "HAS_TREADY": { - "value": "0", - "value_src": "constant" - }, - "HAS_TSTRB": { - "value": "0", - "value_src": "constant" - }, - "HAS_TKEEP": { - "value": "0", - "value_src": "constant" - }, - "HAS_TLAST": { - "value": "0", - "value_src": "constant" - }, - "FREQ_HZ": { - "value": "100000000", - "value_src": "ip_prop" - }, - "PHASE": { - "value": "0.0", - "value_src": "ip_prop" - }, - "CLK_DOMAIN": { - "value": "/clk_wiz_0_clk_out1", - "value_src": "ip_prop" - } - }, - "port_maps": { - "TDATA": { - "physical_name": "s_axis_tdata", - "direction": "I", - "left": "7", - "right": "0" - }, - "TVALID": { - "physical_name": "s_axis_tvalid", - "direction": "I" - } - } - } - }, - "ports": { - "aclk": { - "type": "clk", - "direction": "I", - "parameters": { - "ASSOCIATED_BUSIF": { - "value": "m_axis:s_axis", - "value_src": "constant" - }, - "ASSOCIATED_RESET": { - "value": "aresetn", - "value_src": "constant" - }, - "FREQ_HZ": { - "value": "100000000", - "value_src": "ip_prop" - }, - "PHASE": { - "value": "0.0", - "value_src": "ip_prop" - }, - "CLK_DOMAIN": { - "value": "/clk_wiz_0_clk_out1", - "value_src": "ip_prop" - } - } - }, - "aresetn": { - "type": "rst", - "direction": "I", - "parameters": { - "POLARITY": { - "value": "ACTIVE_LOW", - "value_src": "constant" - } - } - }, - "jstk_x": { - "direction": "O", - "left": "9", - "right": "0" - }, - "jstk_y": { - "direction": "O", - "left": "9", - "right": "0" - }, - "btn_jstk": { - "direction": "O" - }, - "btn_trigger": { - "direction": "O" - }, - "led_r": { - "direction": "I", - "left": "7", - "right": "0" - }, - "led_g": { - "direction": "I", - "left": "7", - "right": "0" - }, - "led_b": { - "direction": "I", - "left": "7", - "right": "0" - } - } - }, "jstk_uart_bridge_0": { "vlnv": "xilinx.com:module_ref:jstk_uart_bridge:1.0", "xci_name": "diligent_jstk_jstk_uart_bridge_0_0", @@ -537,34 +331,266 @@ "vlnv": "DigiLAB:ip:axi4stream_spi_master:1.0", "xci_name": "diligent_jstk_axi4stream_spi_master_0_0", "xci_path": "ip\\diligent_jstk_axi4stream_spi_master_0_0\\diligent_jstk_axi4stream_spi_master_0_0.xci", - "inst_hier_path": "axi4stream_spi_master_0" + "inst_hier_path": "axi4stream_spi_master_0", + "parameters": { + "c_sclkfreq": { + "value": "5000" + } + } + }, + "system_ila_0": { + "vlnv": "xilinx.com:ip:system_ila:1.1", + "xci_name": "diligent_jstk_system_ila_0_0", + "xci_path": "ip\\diligent_jstk_system_ila_0_0\\diligent_jstk_system_ila_0_0.xci", + "inst_hier_path": "system_ila_0", + "parameters": { + "C_MON_TYPE": { + "value": "MIX" + }, + "C_NUM_MONITOR_SLOTS": { + "value": "2" + }, + "C_NUM_OF_PROBES": { + "value": "7" + }, + "C_SLOT": { + "value": "1" + }, + "C_SLOT_0_INTF_TYPE": { + "value": "xilinx.com:interface:axis_rtl:1.0" + }, + "C_SLOT_1_INTF_TYPE": { + "value": "xilinx.com:interface:axis_rtl:1.0" + } + }, + "interface_ports": { + "SLOT_0_AXIS": { + "mode": "Monitor", + "vlnv": "xilinx.com:interface:axis_rtl:1.0" + }, + "SLOT_1_AXIS": { + "mode": "Monitor", + "vlnv": "xilinx.com:interface:axis_rtl:1.0" + } + } + }, + "digilent_jstk2_0": { + "vlnv": "xilinx.com:module_ref:digilent_jstk2:1.0", + "xci_name": "diligent_jstk_digilent_jstk2_0_0", + "xci_path": "ip\\diligent_jstk_digilent_jstk2_0_0\\diligent_jstk_digilent_jstk2_0_0.xci", + "inst_hier_path": "digilent_jstk2_0", + "parameters": { + "SPI_SCLKFREQ": { + "value": "5000" + } + }, + "reference_info": { + "ref_type": "hdl", + "ref_name": "digilent_jstk2", + "boundary_crc": "0x0" + }, + "interface_ports": { + "m_axis": { + "mode": "Master", + "vlnv": "xilinx.com:interface:axis_rtl:1.0", + "parameters": { + "TDATA_NUM_BYTES": { + "value": "1", + "value_src": "constant" + }, + "TDEST_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TID_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TUSER_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "HAS_TREADY": { + "value": "1", + "value_src": "constant" + }, + "HAS_TSTRB": { + "value": "0", + "value_src": "constant" + }, + "HAS_TKEEP": { + "value": "0", + "value_src": "constant" + }, + "HAS_TLAST": { + "value": "0", + "value_src": "constant" + }, + "FREQ_HZ": { + "value": "100000000", + "value_src": "ip_prop" + }, + "PHASE": { + "value": "0.0", + "value_src": "ip_prop" + }, + "CLK_DOMAIN": { + "value": "/clk_wiz_0_clk_out1", + "value_src": "ip_prop" + } + }, + "port_maps": { + "TDATA": { + "physical_name": "m_axis_tdata", + "direction": "O", + "left": "7", + "right": "0" + }, + "TVALID": { + "physical_name": "m_axis_tvalid", + "direction": "O" + }, + "TREADY": { + "physical_name": "m_axis_tready", + "direction": "I" + } + } + }, + "s_axis": { + "mode": "Slave", + "vlnv": "xilinx.com:interface:axis_rtl:1.0", + "parameters": { + "TDATA_NUM_BYTES": { + "value": "1", + "value_src": "constant" + }, + "TDEST_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TID_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TUSER_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "HAS_TREADY": { + "value": "0", + "value_src": "constant" + }, + "HAS_TSTRB": { + "value": "0", + "value_src": "constant" + }, + "HAS_TKEEP": { + "value": "0", + "value_src": "constant" + }, + "HAS_TLAST": { + "value": "0", + "value_src": "constant" + }, + "FREQ_HZ": { + "value": "100000000", + "value_src": "ip_prop" + }, + "PHASE": { + "value": "0.0", + "value_src": "ip_prop" + }, + "CLK_DOMAIN": { + "value": "/clk_wiz_0_clk_out1", + "value_src": "ip_prop" + } + }, + "port_maps": { + "TDATA": { + "physical_name": "s_axis_tdata", + "direction": "I", + "left": "7", + "right": "0" + }, + "TVALID": { + "physical_name": "s_axis_tvalid", + "direction": "I" + } + } + } + }, + "ports": { + "aclk": { + "type": "clk", + "direction": "I", + "parameters": { + "ASSOCIATED_BUSIF": { + "value": "m_axis:s_axis", + "value_src": "constant" + }, + "ASSOCIATED_RESET": { + "value": "aresetn", + "value_src": "constant" + }, + "FREQ_HZ": { + "value": "100000000", + "value_src": "ip_prop" + }, + "PHASE": { + "value": "0.0", + "value_src": "ip_prop" + }, + "CLK_DOMAIN": { + "value": "/clk_wiz_0_clk_out1", + "value_src": "ip_prop" + } + } + }, + "aresetn": { + "type": "rst", + "direction": "I", + "parameters": { + "POLARITY": { + "value": "ACTIVE_LOW", + "value_src": "constant" + } + } + }, + "jstk_x": { + "direction": "O", + "left": "9", + "right": "0" + }, + "jstk_y": { + "direction": "O", + "left": "9", + "right": "0" + }, + "btn_jstk": { + "direction": "O" + }, + "btn_trigger": { + "direction": "O" + }, + "led_r": { + "direction": "I", + "left": "7", + "right": "0" + }, + "led_g": { + "direction": "I", + "left": "7", + "right": "0" + }, + "led_b": { + "direction": "I", + "left": "7", + "right": "0" + } + } } }, "interface_nets": { - "jstk_uart_bridge_0_m_axis": { - "interface_ports": [ - "AXI4Stream_UART_0/S00_AXIS_TX", - "jstk_uart_bridge_0/m_axis" - ] - }, - "axi4stream_spi_master_0_M_AXIS": { - "interface_ports": [ - "axi4stream_spi_master_0/M_AXIS", - "digilent_jstk2_0/s_axis" - ] - }, - "digilent_jstk2_0_m_axis": { - "interface_ports": [ - "digilent_jstk2_0/m_axis", - "axi4stream_spi_master_0/S_AXIS" - ] - }, - "AXI4Stream_UART_0_UART": { - "interface_ports": [ - "usb_uart", - "AXI4Stream_UART_0/UART" - ] - }, "AXI4Stream_UART_0_M00_AXIS_RX": { "interface_ports": [ "AXI4Stream_UART_0/M00_AXIS_RX", @@ -576,6 +602,32 @@ "SPI_M_0", "axi4stream_spi_master_0/SPI_M" ] + }, + "axi4stream_spi_master_0_M_AXIS": { + "interface_ports": [ + "axi4stream_spi_master_0/M_AXIS", + "digilent_jstk2_0/s_axis", + "system_ila_0/SLOT_1_AXIS" + ] + }, + "jstk_uart_bridge_0_m_axis": { + "interface_ports": [ + "AXI4Stream_UART_0/S00_AXIS_TX", + "jstk_uart_bridge_0/m_axis" + ] + }, + "digilent_jstk2_0_m_axis": { + "interface_ports": [ + "digilent_jstk2_0/m_axis", + "axi4stream_spi_master_0/S_AXIS", + "system_ila_0/SLOT_0_AXIS" + ] + }, + "AXI4Stream_UART_0_UART": { + "interface_ports": [ + "usb_uart", + "AXI4Stream_UART_0/UART" + ] } }, "nets": { @@ -603,63 +655,72 @@ "clk_wiz_0/clk_out1", "proc_sys_reset_0/slowest_sync_clk", "axi4stream_spi_master_0/aclk", - "digilent_jstk2_0/aclk", "AXI4Stream_UART_0/clk_uart", "AXI4Stream_UART_0/m00_axis_rx_aclk", "jstk_uart_bridge_0/aclk", - "AXI4Stream_UART_0/s00_axis_tx_aclk" + "AXI4Stream_UART_0/s00_axis_tx_aclk", + "system_ila_0/clk", + "digilent_jstk2_0/aclk" ] }, "digilent_jstk2_0_btn_trigger": { "ports": [ "digilent_jstk2_0/btn_trigger", - "jstk_uart_bridge_0/btn_trigger" + "jstk_uart_bridge_0/btn_trigger", + "system_ila_0/probe6" ] }, "digilent_jstk2_0_btn_jstk": { "ports": [ "digilent_jstk2_0/btn_jstk", - "jstk_uart_bridge_0/btn_jstk" + "jstk_uart_bridge_0/btn_jstk", + "system_ila_0/probe5" ] }, "digilent_jstk2_0_jstk_y": { "ports": [ "digilent_jstk2_0/jstk_y", - "jstk_uart_bridge_0/jstk_y" + "jstk_uart_bridge_0/jstk_y", + "system_ila_0/probe4" ] }, "digilent_jstk2_0_jstk_x": { "ports": [ "digilent_jstk2_0/jstk_x", - "jstk_uart_bridge_0/jstk_x" + "jstk_uart_bridge_0/jstk_x", + "system_ila_0/probe3" ] }, "jstk_uart_bridge_0_led_r": { "ports": [ "jstk_uart_bridge_0/led_r", + "system_ila_0/probe0", "digilent_jstk2_0/led_r" ] }, "jstk_uart_bridge_0_led_g": { "ports": [ "jstk_uart_bridge_0/led_g", + "system_ila_0/probe1", "digilent_jstk2_0/led_g" ] }, "jstk_uart_bridge_0_led_b": { "ports": [ "jstk_uart_bridge_0/led_b", + "system_ila_0/probe2", "digilent_jstk2_0/led_b" ] }, "proc_sys_reset_0_peripheral_aresetn": { "ports": [ "proc_sys_reset_0/peripheral_aresetn", - "digilent_jstk2_0/aresetn", "AXI4Stream_UART_0/m00_axis_rx_aresetn", "jstk_uart_bridge_0/aresetn", "AXI4Stream_UART_0/s00_axis_tx_aresetn", - "axi4stream_spi_master_0/aresetn" + "axi4stream_spi_master_0/aresetn", + "system_ila_0/resetn", + "digilent_jstk2_0/aresetn" ] }, "proc_sys_reset_0_peripheral_reset": { diff --git a/LAB3/design/diligent_jstk/diligent_jstk.bda b/LAB3/design/diligent_jstk/diligent_jstk.bda index 0f3d98f..aafae03 100644 --- a/LAB3/design/diligent_jstk/diligent_jstk.bda +++ b/LAB3/design/diligent_jstk/diligent_jstk.bda @@ -26,17 +26,17 @@ VR + diligent_jstk + BC + + active 2 PM - - diligent_jstk - BC - - + - + diff --git a/LAB3/design/diligent_jstk/hdl/diligent_jstk_wrapper.vhd b/LAB3/design/diligent_jstk/hdl/diligent_jstk_wrapper.vhd index 9c30c60..9d1328b 100644 --- a/LAB3/design/diligent_jstk/hdl/diligent_jstk_wrapper.vhd +++ b/LAB3/design/diligent_jstk/hdl/diligent_jstk_wrapper.vhd @@ -1,8 +1,8 @@ --Copyright 1986-2020 Xilinx, Inc. All Rights Reserved. ---------------------------------------------------------------------------------- --Tool Version: Vivado v.2020.2 (win64) Build 3064766 Wed Nov 18 09:12:45 MST 2020 ---Date : Mon May 12 15:44:44 2025 ---Host : Davide-Samsung running 64-bit major release (build 9200) +--Date : Fri May 30 13:56:20 2025 +--Host : DavideASUS running 64-bit major release (build 9200) --Command : generate_target diligent_jstk_wrapper.bd --Design : diligent_jstk_wrapper --Purpose : IP block netlist @@ -29,8 +29,6 @@ architecture STRUCTURE of diligent_jstk_wrapper is port ( reset : in STD_LOGIC; sys_clock : in STD_LOGIC; - usb_uart_txd : out STD_LOGIC; - usb_uart_rxd : in STD_LOGIC; SPI_M_0_sck_t : out STD_LOGIC; SPI_M_0_io1_o : out STD_LOGIC; SPI_M_0_ss_t : out STD_LOGIC; @@ -42,7 +40,9 @@ architecture STRUCTURE of diligent_jstk_wrapper is SPI_M_0_sck_o : out STD_LOGIC; SPI_M_0_ss_i : in STD_LOGIC; SPI_M_0_io1_i : in STD_LOGIC; - SPI_M_0_io0_i : in STD_LOGIC + SPI_M_0_io0_i : in STD_LOGIC; + usb_uart_txd : out STD_LOGIC; + usb_uart_rxd : in STD_LOGIC ); end component diligent_jstk; component IOBUF is diff --git a/LAB3/design/lab_3/hdl/lab_3_wrapper.vhd b/LAB3/design/lab_3/hdl/lab_3_wrapper.vhd index 1709770..726d18d 100644 --- a/LAB3/design/lab_3/hdl/lab_3_wrapper.vhd +++ b/LAB3/design/lab_3/hdl/lab_3_wrapper.vhd @@ -1,8 +1,8 @@ --Copyright 1986-2020 Xilinx, Inc. All Rights Reserved. ---------------------------------------------------------------------------------- --Tool Version: Vivado v.2020.2 (win64) Build 3064766 Wed Nov 18 09:12:45 MST 2020 ---Date : Mon May 12 14:54:08 2025 ---Host : Davide-Samsung running 64-bit major release (build 9200) +--Date : Fri May 30 14:28:09 2025 +--Host : DavideASUS running 64-bit major release (build 9200) --Command : generate_target lab_3_wrapper.bd --Design : lab_3_wrapper --Purpose : IP block netlist diff --git a/LAB3/design/lab_3/lab_3.bd b/LAB3/design/lab_3/lab_3.bd index a2d9475..9863b6c 100644 --- a/LAB3/design/lab_3/lab_3.bd +++ b/LAB3/design/lab_3/lab_3.bd @@ -13,21 +13,21 @@ "clk_wiz_0": "", "proc_sys_reset_0": "", "proc_sys_reset_1": "", - "digilent_jstk2_0": "", "edge_detector_toggle_0": "", "edge_detector_toggle_1": "", "debouncer_0": "", "axis_broadcaster_0": "", - "moving_average_filte_0": "", + "axi4stream_spi_master_0": "", + "axis_dual_i2s_0": "", "volume_controller_0": "", - "LFO_0": "", "balance_controller_0": "", "effect_selector_0": "", - "led_controller_0": "", "led_level_controller_0": "", + "led_controller_0": "", "mute_controller_0": "", - "axi4stream_spi_master_0": "", - "axis_dual_i2s_0": "" + "moving_average_filte_0": "", + "LFO_0": "", + "digilent_jstk2_0": "" }, "interface_ports": { "SPI_M_0": { @@ -178,221 +178,6 @@ "xci_path": "ip\\lab_3_proc_sys_reset_1_0\\lab_3_proc_sys_reset_1_0.xci", "inst_hier_path": "proc_sys_reset_1" }, - "digilent_jstk2_0": { - "vlnv": "xilinx.com:module_ref:digilent_jstk2:1.0", - "xci_name": "lab_3_digilent_jstk2_0_0", - "xci_path": "ip\\lab_3_digilent_jstk2_0_0\\lab_3_digilent_jstk2_0_0.xci", - "inst_hier_path": "digilent_jstk2_0", - "parameters": { - "CLKFREQ": { - "value": "215000000" - } - }, - "reference_info": { - "ref_type": "hdl", - "ref_name": "digilent_jstk2", - "boundary_crc": "0x0" - }, - "interface_ports": { - "m_axis": { - "mode": "Master", - "vlnv": "xilinx.com:interface:axis_rtl:1.0", - "parameters": { - "TDATA_NUM_BYTES": { - "value": "1", - "value_src": "constant" - }, - "TDEST_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TID_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TUSER_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "HAS_TREADY": { - "value": "1", - "value_src": "constant" - }, - "HAS_TSTRB": { - "value": "0", - "value_src": "constant" - }, - "HAS_TKEEP": { - "value": "0", - "value_src": "constant" - }, - "HAS_TLAST": { - "value": "0", - "value_src": "constant" - }, - "FREQ_HZ": { - "value": "100000000", - "value_src": "ip_prop" - }, - "PHASE": { - "value": "0.0", - "value_src": "ip_prop" - }, - "CLK_DOMAIN": { - "value": "/clk_wiz_0_clk_out1", - "value_src": "ip_prop" - } - }, - "port_maps": { - "TDATA": { - "physical_name": "m_axis_tdata", - "direction": "O", - "left": "7", - "right": "0" - }, - "TVALID": { - "physical_name": "m_axis_tvalid", - "direction": "O" - }, - "TREADY": { - "physical_name": "m_axis_tready", - "direction": "I" - } - } - }, - "s_axis": { - "mode": "Slave", - "vlnv": "xilinx.com:interface:axis_rtl:1.0", - "parameters": { - "TDATA_NUM_BYTES": { - "value": "1", - "value_src": "constant" - }, - "TDEST_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TID_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TUSER_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "HAS_TREADY": { - "value": "0", - "value_src": "constant" - }, - "HAS_TSTRB": { - "value": "0", - "value_src": "constant" - }, - "HAS_TKEEP": { - "value": "0", - "value_src": "constant" - }, - "HAS_TLAST": { - "value": "0", - "value_src": "constant" - }, - "FREQ_HZ": { - "value": "100000000", - "value_src": "ip_prop" - }, - "PHASE": { - "value": "0.0", - "value_src": "ip_prop" - }, - "CLK_DOMAIN": { - "value": "/clk_wiz_0_clk_out1", - "value_src": "ip_prop" - } - }, - "port_maps": { - "TDATA": { - "physical_name": "s_axis_tdata", - "direction": "I", - "left": "7", - "right": "0" - }, - "TVALID": { - "physical_name": "s_axis_tvalid", - "direction": "I" - } - } - } - }, - "ports": { - "aclk": { - "type": "clk", - "direction": "I", - "parameters": { - "ASSOCIATED_BUSIF": { - "value": "m_axis:s_axis", - "value_src": "constant" - }, - "ASSOCIATED_RESET": { - "value": "aresetn", - "value_src": "constant" - }, - "FREQ_HZ": { - "value": "100000000", - "value_src": "ip_prop" - }, - "PHASE": { - "value": "0.0", - "value_src": "ip_prop" - }, - "CLK_DOMAIN": { - "value": "/clk_wiz_0_clk_out1", - "value_src": "ip_prop" - } - } - }, - "aresetn": { - "type": "rst", - "direction": "I", - "parameters": { - "POLARITY": { - "value": "ACTIVE_LOW", - "value_src": "constant" - } - } - }, - "jstk_x": { - "direction": "O", - "left": "9", - "right": "0" - }, - "jstk_y": { - "direction": "O", - "left": "9", - "right": "0" - }, - "btn_jstk": { - "direction": "O" - }, - "btn_trigger": { - "direction": "O" - }, - "led_r": { - "direction": "I", - "left": "7", - "right": "0" - }, - "led_g": { - "direction": "I", - "left": "7", - "right": "0" - }, - "led_b": { - "direction": "I", - "left": "7", - "right": "0" - } - } - }, "edge_detector_toggle_0": { "vlnv": "xilinx.com:module_ref:edge_detector_toggle:1.0", "xci_name": "lab_3_edge_detector_toggle_0_0", @@ -502,7 +287,7 @@ "inst_hier_path": "debouncer_0", "parameters": { "CLOCK_FREQ": { - "value": "200000000" + "value": "100000000" } }, "reference_info": { @@ -557,200 +342,26 @@ "xci_path": "ip\\lab_3_axis_broadcaster_0_0\\lab_3_axis_broadcaster_0_0.xci", "inst_hier_path": "axis_broadcaster_0" }, - "moving_average_filte_0": { - "vlnv": "xilinx.com:module_ref:moving_average_filter_en:1.0", - "xci_name": "lab_3_moving_average_filte_0_0", - "xci_path": "ip\\lab_3_moving_average_filte_0_0\\lab_3_moving_average_filte_0_0.xci", - "inst_hier_path": "moving_average_filte_0", - "reference_info": { - "ref_type": "hdl", - "ref_name": "moving_average_filter_en", - "boundary_crc": "0x0" - }, - "interface_ports": { - "m_axis": { - "mode": "Master", - "vlnv": "xilinx.com:interface:axis_rtl:1.0", - "parameters": { - "TDATA_NUM_BYTES": { - "value": "3", - "value_src": "auto" - }, - "TDEST_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TID_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TUSER_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "HAS_TREADY": { - "value": "1", - "value_src": "constant" - }, - "HAS_TSTRB": { - "value": "0", - "value_src": "constant" - }, - "HAS_TKEEP": { - "value": "0", - "value_src": "constant" - }, - "HAS_TLAST": { - "value": "1", - "value_src": "constant" - }, - "FREQ_HZ": { - "value": "100000000", - "value_src": "ip_prop" - }, - "PHASE": { - "value": "0.0", - "value_src": "ip_prop" - }, - "CLK_DOMAIN": { - "value": "/clk_wiz_0_clk_out1", - "value_src": "ip_prop" - } - }, - "port_maps": { - "TDATA": { - "physical_name": "m_axis_tdata", - "direction": "O", - "left": "23", - "right": "0" - }, - "TLAST": { - "physical_name": "m_axis_tlast", - "direction": "O" - }, - "TVALID": { - "physical_name": "m_axis_tvalid", - "direction": "O" - }, - "TREADY": { - "physical_name": "m_axis_tready", - "direction": "I" - } - } + "axi4stream_spi_master_0": { + "vlnv": "DigiLAB:ip:axi4stream_spi_master:1.0", + "xci_name": "lab_3_axi4stream_spi_master_0_0", + "xci_path": "ip\\lab_3_axi4stream_spi_master_0_0\\lab_3_axi4stream_spi_master_0_0.xci", + "inst_hier_path": "axi4stream_spi_master_0", + "parameters": { + "c_clkfreq": { + "value": "100000000" }, - "s_axis": { - "mode": "Slave", - "vlnv": "xilinx.com:interface:axis_rtl:1.0", - "parameters": { - "TDATA_NUM_BYTES": { - "value": "3", - "value_src": "auto" - }, - "TDEST_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TID_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TUSER_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "HAS_TREADY": { - "value": "1", - "value_src": "constant" - }, - "HAS_TSTRB": { - "value": "0", - "value_src": "constant" - }, - "HAS_TKEEP": { - "value": "0", - "value_src": "constant" - }, - "HAS_TLAST": { - "value": "1", - "value_src": "constant" - }, - "FREQ_HZ": { - "value": "100000000", - "value_src": "ip_prop" - }, - "PHASE": { - "value": "0.0", - "value_src": "ip_prop" - }, - "CLK_DOMAIN": { - "value": "/clk_wiz_0_clk_out1", - "value_src": "ip_prop" - } - }, - "port_maps": { - "TDATA": { - "physical_name": "s_axis_tdata", - "direction": "I", - "left": "23", - "right": "0" - }, - "TLAST": { - "physical_name": "s_axis_tlast", - "direction": "I" - }, - "TVALID": { - "physical_name": "s_axis_tvalid", - "direction": "I" - }, - "TREADY": { - "physical_name": "s_axis_tready", - "direction": "O" - } - } - } - }, - "ports": { - "aclk": { - "type": "clk", - "direction": "I", - "parameters": { - "ASSOCIATED_BUSIF": { - "value": "m_axis:s_axis", - "value_src": "constant" - }, - "ASSOCIATED_RESET": { - "value": "aresetn", - "value_src": "constant" - }, - "FREQ_HZ": { - "value": "100000000", - "value_src": "ip_prop" - }, - "PHASE": { - "value": "0.0", - "value_src": "ip_prop" - }, - "CLK_DOMAIN": { - "value": "/clk_wiz_0_clk_out1", - "value_src": "ip_prop" - } - } - }, - "aresetn": { - "type": "rst", - "direction": "I", - "parameters": { - "POLARITY": { - "value": "ACTIVE_LOW", - "value_src": "constant" - } - } - }, - "enable_filter": { - "direction": "I" + "c_sclkfreq": { + "value": "5000" } } }, + "axis_dual_i2s_0": { + "vlnv": "DigiLAB:ip:axis_dual_i2s:1.0", + "xci_name": "lab_3_axis_dual_i2s_0_0", + "xci_path": "ip\\lab_3_axis_dual_i2s_0_0\\lab_3_axis_dual_i2s_0_0.xci", + "inst_hier_path": "axis_dual_i2s_0" + }, "volume_controller_0": { "vlnv": "xilinx.com:module_ref:volume_controller:1.0", "xci_name": "lab_3_volume_controller_0_0", @@ -952,210 +563,6 @@ } } }, - "LFO_0": { - "vlnv": "xilinx.com:module_ref:LFO:1.0", - "xci_name": "lab_3_LFO_0_0", - "xci_path": "ip\\lab_3_LFO_0_0\\lab_3_LFO_0_0.xci", - "inst_hier_path": "LFO_0", - "parameters": { - "CLK_PERIOD_NS": { - "value": "10" - } - }, - "reference_info": { - "ref_type": "hdl", - "ref_name": "LFO", - "boundary_crc": "0x0" - }, - "interface_ports": { - "m_axis": { - "mode": "Master", - "vlnv": "xilinx.com:interface:axis_rtl:1.0", - "parameters": { - "TDATA_NUM_BYTES": { - "value": "3", - "value_src": "auto" - }, - "TDEST_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TID_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TUSER_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "HAS_TREADY": { - "value": "1", - "value_src": "constant" - }, - "HAS_TSTRB": { - "value": "0", - "value_src": "constant" - }, - "HAS_TKEEP": { - "value": "0", - "value_src": "constant" - }, - "HAS_TLAST": { - "value": "1", - "value_src": "constant" - }, - "FREQ_HZ": { - "value": "100000000", - "value_src": "ip_prop" - }, - "PHASE": { - "value": "0.0", - "value_src": "ip_prop" - }, - "CLK_DOMAIN": { - "value": "/clk_wiz_0_clk_out1", - "value_src": "ip_prop" - } - }, - "port_maps": { - "TDATA": { - "physical_name": "m_axis_tdata", - "direction": "O", - "left": "23", - "right": "0" - }, - "TLAST": { - "physical_name": "m_axis_tlast", - "direction": "O" - }, - "TVALID": { - "physical_name": "m_axis_tvalid", - "direction": "O" - }, - "TREADY": { - "physical_name": "m_axis_tready", - "direction": "I" - } - } - }, - "s_axis": { - "mode": "Slave", - "vlnv": "xilinx.com:interface:axis_rtl:1.0", - "parameters": { - "TDATA_NUM_BYTES": { - "value": "3", - "value_src": "auto" - }, - "TDEST_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TID_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "TUSER_WIDTH": { - "value": "0", - "value_src": "constant" - }, - "HAS_TREADY": { - "value": "1", - "value_src": "constant" - }, - "HAS_TSTRB": { - "value": "0", - "value_src": "constant" - }, - "HAS_TKEEP": { - "value": "0", - "value_src": "constant" - }, - "HAS_TLAST": { - "value": "1", - "value_src": "constant" - }, - "FREQ_HZ": { - "value": "100000000", - "value_src": "ip_prop" - }, - "PHASE": { - "value": "0.0", - "value_src": "ip_prop" - }, - "CLK_DOMAIN": { - "value": "/clk_wiz_0_clk_out1", - "value_src": "ip_prop" - } - }, - "port_maps": { - "TDATA": { - "physical_name": "s_axis_tdata", - "direction": "I", - "left": "23", - "right": "0" - }, - "TLAST": { - "physical_name": "s_axis_tlast", - "direction": "I" - }, - "TVALID": { - "physical_name": "s_axis_tvalid", - "direction": "I" - }, - "TREADY": { - "physical_name": "s_axis_tready", - "direction": "O" - } - } - } - }, - "ports": { - "aclk": { - "type": "clk", - "direction": "I", - "parameters": { - "ASSOCIATED_BUSIF": { - "value": "m_axis:s_axis", - "value_src": "constant" - }, - "ASSOCIATED_RESET": { - "value": "aresetn", - "value_src": "constant" - }, - "FREQ_HZ": { - "value": "100000000", - "value_src": "ip_prop" - }, - "PHASE": { - "value": "0.0", - "value_src": "ip_prop" - }, - "CLK_DOMAIN": { - "value": "/clk_wiz_0_clk_out1", - "value_src": "ip_prop" - } - } - }, - "aresetn": { - "type": "rst", - "direction": "I", - "parameters": { - "POLARITY": { - "value": "ACTIVE_LOW", - "value_src": "constant" - } - } - }, - "lfo_period": { - "direction": "I", - "left": "9", - "right": "0" - }, - "lfo_enable": { - "direction": "I" - } - } - }, "balance_controller_0": { "vlnv": "xilinx.com:module_ref:balance_controller:1.0", "xci_name": "lab_3_balance_controller_0_0", @@ -1425,40 +832,6 @@ } } }, - "led_controller_0": { - "vlnv": "xilinx.com:module_ref:led_controller:1.0", - "xci_name": "lab_3_led_controller_0_0", - "xci_path": "ip\\lab_3_led_controller_0_0\\lab_3_led_controller_0_0.xci", - "inst_hier_path": "led_controller_0", - "reference_info": { - "ref_type": "hdl", - "ref_name": "led_controller", - "boundary_crc": "0x0" - }, - "ports": { - "mute_enable": { - "direction": "I" - }, - "filter_enable": { - "direction": "I" - }, - "led_r": { - "direction": "O", - "left": "7", - "right": "0" - }, - "led_g": { - "direction": "O", - "left": "7", - "right": "0" - }, - "led_b": { - "direction": "O", - "left": "7", - "right": "0" - } - } - }, "led_level_controller_0": { "vlnv": "xilinx.com:module_ref:led_level_controller:1.0", "xci_name": "lab_3_led_level_controller_0_0", @@ -1590,6 +963,40 @@ } } }, + "led_controller_0": { + "vlnv": "xilinx.com:module_ref:led_controller:1.0", + "xci_name": "lab_3_led_controller_0_0", + "xci_path": "ip\\lab_3_led_controller_0_0\\lab_3_led_controller_0_0.xci", + "inst_hier_path": "led_controller_0", + "reference_info": { + "ref_type": "hdl", + "ref_name": "led_controller", + "boundary_crc": "0x0" + }, + "ports": { + "mute_enable": { + "direction": "I" + }, + "filter_enable": { + "direction": "I" + }, + "led_r": { + "direction": "O", + "left": "7", + "right": "0" + }, + "led_g": { + "direction": "O", + "left": "7", + "right": "0" + }, + "led_b": { + "direction": "O", + "left": "7", + "right": "0" + } + } + }, "mute_controller_0": { "vlnv": "xilinx.com:module_ref:mute_controller:1.0", "xci_name": "lab_3_mute_controller_0_0", @@ -1784,52 +1191,621 @@ } } }, - "axi4stream_spi_master_0": { - "vlnv": "DigiLAB:ip:axi4stream_spi_master:1.0", - "xci_name": "lab_3_axi4stream_spi_master_0_0", - "xci_path": "ip\\lab_3_axi4stream_spi_master_0_0\\lab_3_axi4stream_spi_master_0_0.xci", - "inst_hier_path": "axi4stream_spi_master_0", - "parameters": { - "c_clkfreq": { - "value": "215000000" + "moving_average_filte_0": { + "vlnv": "xilinx.com:module_ref:moving_average_filter_en:1.0", + "xci_name": "lab_3_moving_average_filte_0_0", + "xci_path": "ip\\lab_3_moving_average_filte_0_0\\lab_3_moving_average_filte_0_0.xci", + "inst_hier_path": "moving_average_filte_0", + "reference_info": { + "ref_type": "hdl", + "ref_name": "moving_average_filter_en", + "boundary_crc": "0x0" + }, + "interface_ports": { + "m_axis": { + "mode": "Master", + "vlnv": "xilinx.com:interface:axis_rtl:1.0", + "parameters": { + "TDATA_NUM_BYTES": { + "value": "3", + "value_src": "auto" + }, + "TDEST_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TID_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TUSER_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "HAS_TREADY": { + "value": "1", + "value_src": "constant" + }, + "HAS_TSTRB": { + "value": "0", + "value_src": "constant" + }, + "HAS_TKEEP": { + "value": "0", + "value_src": "constant" + }, + "HAS_TLAST": { + "value": "1", + "value_src": "constant" + }, + "FREQ_HZ": { + "value": "100000000", + "value_src": "ip_prop" + }, + "PHASE": { + "value": "0.0", + "value_src": "ip_prop" + }, + "CLK_DOMAIN": { + "value": "/clk_wiz_0_clk_out1", + "value_src": "ip_prop" + } + }, + "port_maps": { + "TDATA": { + "physical_name": "m_axis_tdata", + "direction": "O", + "left": "23", + "right": "0" + }, + "TLAST": { + "physical_name": "m_axis_tlast", + "direction": "O" + }, + "TVALID": { + "physical_name": "m_axis_tvalid", + "direction": "O" + }, + "TREADY": { + "physical_name": "m_axis_tready", + "direction": "I" + } + } }, - "c_sclkfreq": { - "value": "5000" + "s_axis": { + "mode": "Slave", + "vlnv": "xilinx.com:interface:axis_rtl:1.0", + "parameters": { + "TDATA_NUM_BYTES": { + "value": "3", + "value_src": "auto" + }, + "TDEST_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TID_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TUSER_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "HAS_TREADY": { + "value": "1", + "value_src": "constant" + }, + "HAS_TSTRB": { + "value": "0", + "value_src": "constant" + }, + "HAS_TKEEP": { + "value": "0", + "value_src": "constant" + }, + "HAS_TLAST": { + "value": "1", + "value_src": "constant" + }, + "FREQ_HZ": { + "value": "100000000", + "value_src": "ip_prop" + }, + "PHASE": { + "value": "0.0", + "value_src": "ip_prop" + }, + "CLK_DOMAIN": { + "value": "/clk_wiz_0_clk_out1", + "value_src": "ip_prop" + } + }, + "port_maps": { + "TDATA": { + "physical_name": "s_axis_tdata", + "direction": "I", + "left": "23", + "right": "0" + }, + "TLAST": { + "physical_name": "s_axis_tlast", + "direction": "I" + }, + "TVALID": { + "physical_name": "s_axis_tvalid", + "direction": "I" + }, + "TREADY": { + "physical_name": "s_axis_tready", + "direction": "O" + } + } + } + }, + "ports": { + "aclk": { + "type": "clk", + "direction": "I", + "parameters": { + "ASSOCIATED_BUSIF": { + "value": "m_axis:s_axis", + "value_src": "constant" + }, + "ASSOCIATED_RESET": { + "value": "aresetn", + "value_src": "constant" + }, + "FREQ_HZ": { + "value": "100000000", + "value_src": "ip_prop" + }, + "PHASE": { + "value": "0.0", + "value_src": "ip_prop" + }, + "CLK_DOMAIN": { + "value": "/clk_wiz_0_clk_out1", + "value_src": "ip_prop" + } + } + }, + "aresetn": { + "type": "rst", + "direction": "I", + "parameters": { + "POLARITY": { + "value": "ACTIVE_LOW", + "value_src": "constant" + } + } + }, + "enable_filter": { + "direction": "I" } } }, - "axis_dual_i2s_0": { - "vlnv": "DigiLAB:ip:axis_dual_i2s:1.0", - "xci_name": "lab_3_axis_dual_i2s_0_0", - "xci_path": "ip\\lab_3_axis_dual_i2s_0_0\\lab_3_axis_dual_i2s_0_0.xci", - "inst_hier_path": "axis_dual_i2s_0" + "LFO_0": { + "vlnv": "xilinx.com:module_ref:LFO:1.0", + "xci_name": "lab_3_LFO_0_0", + "xci_path": "ip\\lab_3_LFO_0_0\\lab_3_LFO_0_0.xci", + "inst_hier_path": "LFO_0", + "parameters": { + "CLK_PERIOD_NS": { + "value": "10" + } + }, + "reference_info": { + "ref_type": "hdl", + "ref_name": "LFO", + "boundary_crc": "0x0" + }, + "interface_ports": { + "m_axis": { + "mode": "Master", + "vlnv": "xilinx.com:interface:axis_rtl:1.0", + "parameters": { + "TDATA_NUM_BYTES": { + "value": "3", + "value_src": "auto" + }, + "TDEST_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TID_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TUSER_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "HAS_TREADY": { + "value": "1", + "value_src": "constant" + }, + "HAS_TSTRB": { + "value": "0", + "value_src": "constant" + }, + "HAS_TKEEP": { + "value": "0", + "value_src": "constant" + }, + "HAS_TLAST": { + "value": "1", + "value_src": "constant" + }, + "FREQ_HZ": { + "value": "100000000", + "value_src": "ip_prop" + }, + "PHASE": { + "value": "0.0", + "value_src": "ip_prop" + }, + "CLK_DOMAIN": { + "value": "/clk_wiz_0_clk_out1", + "value_src": "ip_prop" + } + }, + "port_maps": { + "TDATA": { + "physical_name": "m_axis_tdata", + "direction": "O", + "left": "23", + "right": "0" + }, + "TLAST": { + "physical_name": "m_axis_tlast", + "direction": "O" + }, + "TVALID": { + "physical_name": "m_axis_tvalid", + "direction": "O" + }, + "TREADY": { + "physical_name": "m_axis_tready", + "direction": "I" + } + } + }, + "s_axis": { + "mode": "Slave", + "vlnv": "xilinx.com:interface:axis_rtl:1.0", + "parameters": { + "TDATA_NUM_BYTES": { + "value": "3", + "value_src": "auto" + }, + "TDEST_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TID_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TUSER_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "HAS_TREADY": { + "value": "1", + "value_src": "constant" + }, + "HAS_TSTRB": { + "value": "0", + "value_src": "constant" + }, + "HAS_TKEEP": { + "value": "0", + "value_src": "constant" + }, + "HAS_TLAST": { + "value": "1", + "value_src": "constant" + }, + "FREQ_HZ": { + "value": "100000000", + "value_src": "ip_prop" + }, + "PHASE": { + "value": "0.0", + "value_src": "ip_prop" + }, + "CLK_DOMAIN": { + "value": "/clk_wiz_0_clk_out1", + "value_src": "ip_prop" + } + }, + "port_maps": { + "TDATA": { + "physical_name": "s_axis_tdata", + "direction": "I", + "left": "23", + "right": "0" + }, + "TLAST": { + "physical_name": "s_axis_tlast", + "direction": "I" + }, + "TVALID": { + "physical_name": "s_axis_tvalid", + "direction": "I" + }, + "TREADY": { + "physical_name": "s_axis_tready", + "direction": "O" + } + } + } + }, + "ports": { + "aclk": { + "type": "clk", + "direction": "I", + "parameters": { + "ASSOCIATED_BUSIF": { + "value": "m_axis:s_axis", + "value_src": "constant" + }, + "ASSOCIATED_RESET": { + "value": "aresetn", + "value_src": "constant" + }, + "FREQ_HZ": { + "value": "100000000", + "value_src": "ip_prop" + }, + "PHASE": { + "value": "0.0", + "value_src": "ip_prop" + }, + "CLK_DOMAIN": { + "value": "/clk_wiz_0_clk_out1", + "value_src": "ip_prop" + } + } + }, + "aresetn": { + "type": "rst", + "direction": "I", + "parameters": { + "POLARITY": { + "value": "ACTIVE_LOW", + "value_src": "constant" + } + } + }, + "lfo_period": { + "direction": "I", + "left": "9", + "right": "0" + }, + "lfo_enable": { + "direction": "I" + } + } + }, + "digilent_jstk2_0": { + "vlnv": "xilinx.com:module_ref:digilent_jstk2:1.0", + "xci_name": "lab_3_digilent_jstk2_0_0", + "xci_path": "ip\\lab_3_digilent_jstk2_0_0\\lab_3_digilent_jstk2_0_0.xci", + "inst_hier_path": "digilent_jstk2_0", + "parameters": { + "CLKFREQ": { + "value": "215000000" + } + }, + "reference_info": { + "ref_type": "hdl", + "ref_name": "digilent_jstk2", + "boundary_crc": "0x0" + }, + "interface_ports": { + "m_axis": { + "mode": "Master", + "vlnv": "xilinx.com:interface:axis_rtl:1.0", + "parameters": { + "TDATA_NUM_BYTES": { + "value": "1", + "value_src": "constant" + }, + "TDEST_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TID_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TUSER_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "HAS_TREADY": { + "value": "1", + "value_src": "constant" + }, + "HAS_TSTRB": { + "value": "0", + "value_src": "constant" + }, + "HAS_TKEEP": { + "value": "0", + "value_src": "constant" + }, + "HAS_TLAST": { + "value": "0", + "value_src": "constant" + }, + "FREQ_HZ": { + "value": "100000000", + "value_src": "ip_prop" + }, + "PHASE": { + "value": "0.0", + "value_src": "ip_prop" + }, + "CLK_DOMAIN": { + "value": "/clk_wiz_0_clk_out1", + "value_src": "ip_prop" + } + }, + "port_maps": { + "TDATA": { + "physical_name": "m_axis_tdata", + "direction": "O", + "left": "7", + "right": "0" + }, + "TVALID": { + "physical_name": "m_axis_tvalid", + "direction": "O" + }, + "TREADY": { + "physical_name": "m_axis_tready", + "direction": "I" + } + } + }, + "s_axis": { + "mode": "Slave", + "vlnv": "xilinx.com:interface:axis_rtl:1.0", + "parameters": { + "TDATA_NUM_BYTES": { + "value": "1", + "value_src": "constant" + }, + "TDEST_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TID_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "TUSER_WIDTH": { + "value": "0", + "value_src": "constant" + }, + "HAS_TREADY": { + "value": "0", + "value_src": "constant" + }, + "HAS_TSTRB": { + "value": "0", + "value_src": "constant" + }, + "HAS_TKEEP": { + "value": "0", + "value_src": "constant" + }, + "HAS_TLAST": { + "value": "0", + "value_src": "constant" + }, + "FREQ_HZ": { + "value": "100000000", + "value_src": "ip_prop" + }, + "PHASE": { + "value": "0.0", + "value_src": "ip_prop" + }, + "CLK_DOMAIN": { + "value": "/clk_wiz_0_clk_out1", + "value_src": "ip_prop" + } + }, + "port_maps": { + "TDATA": { + "physical_name": "s_axis_tdata", + "direction": "I", + "left": "7", + "right": "0" + }, + "TVALID": { + "physical_name": "s_axis_tvalid", + "direction": "I" + } + } + } + }, + "ports": { + "aclk": { + "type": "clk", + "direction": "I", + "parameters": { + "ASSOCIATED_BUSIF": { + "value": "m_axis:s_axis", + "value_src": "constant" + }, + "ASSOCIATED_RESET": { + "value": "aresetn", + "value_src": "constant" + }, + "FREQ_HZ": { + "value": "100000000", + "value_src": "ip_prop" + }, + "PHASE": { + "value": "0.0", + "value_src": "ip_prop" + }, + "CLK_DOMAIN": { + "value": "/clk_wiz_0_clk_out1", + "value_src": "ip_prop" + } + } + }, + "aresetn": { + "type": "rst", + "direction": "I", + "parameters": { + "POLARITY": { + "value": "ACTIVE_LOW", + "value_src": "constant" + } + } + }, + "jstk_x": { + "direction": "O", + "left": "9", + "right": "0" + }, + "jstk_y": { + "direction": "O", + "left": "9", + "right": "0" + }, + "btn_jstk": { + "direction": "O" + }, + "btn_trigger": { + "direction": "O" + }, + "led_r": { + "direction": "I", + "left": "7", + "right": "0" + }, + "led_g": { + "direction": "I", + "left": "7", + "right": "0" + }, + "led_b": { + "direction": "I", + "left": "7", + "right": "0" + } + } } }, "interface_nets": { - "axis_dual_i2s_0_m_axis": { - "interface_ports": [ - "axis_dual_i2s_0/m_axis", - "moving_average_filte_0/s_axis" - ] - }, - "LFO_0_m_axis": { - "interface_ports": [ - "LFO_0/m_axis", - "mute_controller_0/s_axis" - ] - }, - "digilent_jstk2_0_m_axis": { - "interface_ports": [ - "digilent_jstk2_0/m_axis", - "axi4stream_spi_master_0/S_AXIS" - ] - }, - "axi4stream_spi_master_0_SPI_M": { - "interface_ports": [ - "SPI_M_0", - "axi4stream_spi_master_0/SPI_M" - ] - }, "volume_controller_0_m_axis": { "interface_ports": [ "volume_controller_0/m_axis", @@ -1842,10 +1818,34 @@ "axis_broadcaster_0/S_AXIS" ] }, - "axis_broadcaster_0_M01_AXIS": { + "moving_average_filte_0_m_axis": { "interface_ports": [ - "axis_broadcaster_0/M01_AXIS", - "led_level_controller_0/s_axis" + "balance_controller_0/s_axis", + "moving_average_filte_0/m_axis" + ] + }, + "axis_dual_i2s_0_m_axis": { + "interface_ports": [ + "axis_dual_i2s_0/m_axis", + "moving_average_filte_0/s_axis" + ] + }, + "digilent_jstk2_0_m_axis": { + "interface_ports": [ + "digilent_jstk2_0/m_axis", + "axi4stream_spi_master_0/S_AXIS" + ] + }, + "LFO_0_m_axis": { + "interface_ports": [ + "LFO_0/m_axis", + "mute_controller_0/s_axis" + ] + }, + "axi4stream_spi_master_0_SPI_M": { + "interface_ports": [ + "SPI_M_0", + "axi4stream_spi_master_0/SPI_M" ] }, "axis_broadcaster_0_M00_AXIS": { @@ -1854,18 +1854,18 @@ "axis_dual_i2s_0/s_axis" ] }, + "axis_broadcaster_0_M01_AXIS": { + "interface_ports": [ + "axis_broadcaster_0/M01_AXIS", + "led_level_controller_0/s_axis" + ] + }, "balance_controller_0_m_axis": { "interface_ports": [ "balance_controller_0/m_axis", "volume_controller_0/s_axis" ] }, - "moving_average_filte_0_m_axis": { - "interface_ports": [ - "balance_controller_0/s_axis", - "moving_average_filte_0/m_axis" - ] - }, "axi4stream_spi_master_0_M_AXIS": { "interface_ports": [ "axi4stream_spi_master_0/M_AXIS", @@ -1884,20 +1884,20 @@ "ports": [ "clk_wiz_0/clk_out1", "proc_sys_reset_0/slowest_sync_clk", - "digilent_jstk2_0/aclk", "edge_detector_toggle_0/clk", "edge_detector_toggle_1/clk", "debouncer_0/clk", "axis_broadcaster_0/aclk", - "moving_average_filte_0/aclk", + "axi4stream_spi_master_0/aclk", + "axis_dual_i2s_0/aclk", "volume_controller_0/aclk", - "LFO_0/aclk", "balance_controller_0/aclk", "effect_selector_0/aclk", "led_level_controller_0/aclk", "mute_controller_0/aclk", - "axi4stream_spi_master_0/aclk", - "axis_dual_i2s_0/aclk" + "moving_average_filte_0/aclk", + "LFO_0/aclk", + "digilent_jstk2_0/aclk" ] }, "reset_1": { @@ -1925,18 +1925,18 @@ "proc_sys_reset_0_peripheral_aresetn": { "ports": [ "proc_sys_reset_0/peripheral_aresetn", - "digilent_jstk2_0/aresetn", "debouncer_0/reset", "axis_broadcaster_0/aresetn", - "moving_average_filte_0/aresetn", + "axi4stream_spi_master_0/aresetn", + "axis_dual_i2s_0/aresetn", "volume_controller_0/aresetn", - "LFO_0/aresetn", "balance_controller_0/aresetn", "effect_selector_0/aresetn", "led_level_controller_0/aresetn", "mute_controller_0/aresetn", - "axi4stream_spi_master_0/aresetn", - "axis_dual_i2s_0/aresetn" + "moving_average_filte_0/aresetn", + "LFO_0/aresetn", + "digilent_jstk2_0/aresetn" ] }, "proc_sys_reset_1_peripheral_aresetn": { @@ -2015,8 +2015,8 @@ "edge_detector_toggle_1_output_signal": { "ports": [ "edge_detector_toggle_1/output_signal", - "moving_average_filte_0/enable_filter", - "led_controller_0/filter_enable" + "led_controller_0/filter_enable", + "moving_average_filte_0/enable_filter" ] }, "led_controller_0_led_r": { @@ -2086,17 +2086,17 @@ "debouncer_0/input_signal" ] }, - "led_level_controller_0_led": { - "ports": [ - "led_level_controller_0/led", - "LED" - ] - }, "debouncer_0_debounced": { "ports": [ "debouncer_0/debounced", "effect_selector_0/effect" ] + }, + "led_level_controller_0_led": { + "ports": [ + "led_level_controller_0/led", + "LED" + ] } } } diff --git a/LAB3/design/lab_3/lab_3.bda b/LAB3/design/lab_3/lab_3.bda index 3fa1797..c595aff 100644 --- a/LAB3/design/lab_3/lab_3.bda +++ b/LAB3/design/lab_3/lab_3.bda @@ -26,17 +26,17 @@ VR + lab_3 + BC + + active 2 PM - - lab_3 - BC - - + - + diff --git a/LAB3/sim/ReadMe.md b/LAB3/sim/ReadMe.md deleted file mode 100644 index 0f8aee3..0000000 --- a/LAB3/sim/ReadMe.md +++ /dev/null @@ -1,3 +0,0 @@ -# Placeholder - -This is a placeholder. \ No newline at end of file diff --git a/LAB3/sim/tb_LFO.vhd b/LAB3/sim/tb_LFO.vhd new file mode 100644 index 0000000..50fe8e1 --- /dev/null +++ b/LAB3/sim/tb_LFO.vhd @@ -0,0 +1,146 @@ +-- filepath: c:\DESD\LAB3\sim\tb_LFO.vhd +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY tb_LFO IS +END tb_LFO; + +ARCHITECTURE sim OF tb_LFO IS + + CONSTANT CHANNEL_LENGHT : INTEGER := 24; + CONSTANT JOYSTICK_LENGHT : INTEGER := 10; + CONSTANT TRIANGULAR_COUNTER_LENGHT: INTEGER := 10; + CONSTANT CLK_PERIOD_NS : INTEGER := 10; + + SIGNAL aclk : STD_LOGIC := '0'; + SIGNAL aresetn : STD_LOGIC := '0'; + + SIGNAL lfo_period : STD_LOGIC_VECTOR(JOYSTICK_LENGHT-1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL lfo_enable : STD_LOGIC := '0'; + + SIGNAL s_axis_tvalid : STD_LOGIC := '0'; + SIGNAL s_axis_tdata : STD_LOGIC_VECTOR(CHANNEL_LENGHT-1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL s_axis_tlast : STD_LOGIC := '0'; + SIGNAL s_axis_tready : STD_LOGIC; + + SIGNAL m_axis_tvalid : STD_LOGIC; + SIGNAL m_axis_tdata : STD_LOGIC_VECTOR(CHANNEL_LENGHT-1 DOWNTO 0); + SIGNAL m_axis_tlast : STD_LOGIC; + SIGNAL m_axis_tready : STD_LOGIC := '1'; + + -- DUT + COMPONENT LFO + GENERIC ( + CHANNEL_LENGHT : INTEGER := 24; + JOYSTICK_LENGHT : INTEGER := 10; + CLK_PERIOD_NS : INTEGER := 10; + TRIANGULAR_COUNTER_LENGHT : INTEGER := 10 + ); + PORT ( + aclk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; + lfo_period : IN STD_LOGIC_VECTOR(JOYSTICK_LENGHT-1 DOWNTO 0); + lfo_enable : IN STD_LOGIC; + s_axis_tvalid : IN STD_LOGIC; + s_axis_tdata : IN STD_LOGIC_VECTOR(CHANNEL_LENGHT-1 DOWNTO 0); + s_axis_tlast : IN STD_LOGIC; + s_axis_tready : OUT STD_LOGIC; + m_axis_tvalid : OUT STD_LOGIC; + m_axis_tdata : OUT STD_LOGIC_VECTOR(CHANNEL_LENGHT-1 DOWNTO 0); + m_axis_tlast : OUT STD_LOGIC; + m_axis_tready : IN STD_LOGIC + ); + END COMPONENT; + +BEGIN + + -- Clock generation + clk_proc : PROCESS + BEGIN + aclk <= '0'; + WAIT FOR 5 ns; + aclk <= '1'; + WAIT FOR 5 ns; + END PROCESS; + + -- DUT instantiation + dut: LFO + GENERIC MAP ( + CHANNEL_LENGHT => CHANNEL_LENGHT, + JOYSTICK_LENGHT => JOYSTICK_LENGHT, + CLK_PERIOD_NS => CLK_PERIOD_NS, + TRIANGULAR_COUNTER_LENGHT => TRIANGULAR_COUNTER_LENGHT + ) + PORT MAP ( + aclk => aclk, + aresetn => aresetn, + lfo_period => lfo_period, + lfo_enable => lfo_enable, + s_axis_tvalid => s_axis_tvalid, + s_axis_tdata => s_axis_tdata, + s_axis_tlast => s_axis_tlast, + s_axis_tready => s_axis_tready, + m_axis_tvalid => m_axis_tvalid, + m_axis_tdata => m_axis_tdata, + m_axis_tlast => m_axis_tlast, + m_axis_tready => m_axis_tready + ); + + -- Stimulus process + stim_proc : PROCESS + VARIABLE data_cnt : INTEGER := 0; + VARIABLE lr_flag : STD_LOGIC := '0'; -- '0' = SX, '1' = DX + BEGIN + -- Reset + aresetn <= '0'; + WAIT FOR 20 ns; + aresetn <= '1'; + WAIT FOR 10 ns; + + -- Imposta parametri iniziali + lfo_enable <= '1'; + lfo_period <= std_logic_vector(to_unsigned(1023, JOYSTICK_LENGHT)); + + WHILE TRUE LOOP + -- Prepara il dato + IF lr_flag = '0' THEN + -- SX: aggiungi +100 + s_axis_tdata <= std_logic_vector(to_signed(data_cnt + 100, CHANNEL_LENGHT)); + s_axis_tlast <= '0'; + ELSE + -- DX: valore normale + s_axis_tdata <= std_logic_vector(to_signed(data_cnt, CHANNEL_LENGHT)); + s_axis_tlast <= '1'; + END IF; + s_axis_tvalid <= '1'; + + -- Attendi handshake + WAIT UNTIL rising_edge(aclk); + WHILE s_axis_tready = '0' LOOP + WAIT UNTIL rising_edge(aclk); + END LOOP; + + -- Dopo handshake, aggiorna flag/counter + IF lr_flag = '0' THEN + lr_flag := '1'; -- prossimo sarà DX + ELSE + lr_flag := '0'; -- prossimo sarà SX + data_cnt := data_cnt + 1; -- passa al prossimo campione solo dopo DX + END IF; + END LOOP; + END PROCESS; + + -- Simula backpressure abbassando m_axis_tready ogni tanto + backpressure_proc : PROCESS + BEGIN + WAIT FOR 200 ns; + WAIT UNTIL rising_edge(aclk); + m_axis_tready <= '0'; + WAIT FOR 500 ns; + WAIT UNTIL rising_edge(aclk); + m_axis_tready <= '1'; + WAIT; + END PROCESS; + +END sim; \ No newline at end of file diff --git a/LAB3/sim/tb_balance_controller.vhd b/LAB3/sim/tb_balance_controller.vhd new file mode 100644 index 0000000..ff9e6f9 --- /dev/null +++ b/LAB3/sim/tb_balance_controller.vhd @@ -0,0 +1,170 @@ +---------------------------------------------------------------------------------- +-- Testbench for balance_controller +---------------------------------------------------------------------------------- +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +ENTITY tb_balance_controller IS +END tb_balance_controller; + +ARCHITECTURE Behavioral OF tb_balance_controller IS + + CONSTANT TDATA_WIDTH : POSITIVE := 24; + CONSTANT BALANCE_WIDTH : POSITIVE := 10; + CONSTANT BALANCE_STEP_2 : POSITIVE := 6; + CONSTANT N_SAMPLES : INTEGER := 8; + CONSTANT N_BALANCES : INTEGER := 5; + + COMPONENT balance_controller IS + GENERIC ( + TDATA_WIDTH : POSITIVE := 24; + BALANCE_WIDTH : POSITIVE := 10; + BALANCE_STEP_2 : POSITIVE := 6 + ); + PORT ( + aclk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; + s_axis_tvalid : IN STD_LOGIC; + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + s_axis_tready : OUT STD_LOGIC; + s_axis_tlast : IN STD_LOGIC; + m_axis_tvalid : OUT STD_LOGIC; + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + m_axis_tready : IN STD_LOGIC; + m_axis_tlast : OUT STD_LOGIC; + balance : IN STD_LOGIC_VECTOR(BALANCE_WIDTH - 1 DOWNTO 0) + ); + END COMPONENT; + + SIGNAL aclk : STD_LOGIC := '0'; + SIGNAL aresetn : STD_LOGIC := '0'; + SIGNAL s_axis_tvalid : STD_LOGIC := '0'; + SIGNAL s_axis_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL s_axis_tlast : STD_LOGIC := '0'; + SIGNAL s_axis_tready : STD_LOGIC; + SIGNAL m_axis_tvalid : STD_LOGIC; + SIGNAL m_axis_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + SIGNAL m_axis_tlast : STD_LOGIC; + SIGNAL m_axis_tready : STD_LOGIC := '1'; + SIGNAL balance : STD_LOGIC_VECTOR(BALANCE_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); + + -- Test input samples + TYPE sample_mem_type IS ARRAY(0 TO N_SAMPLES-1) OF STD_LOGIC_VECTOR(TDATA_WIDTH-1 DOWNTO 0); + SIGNAL sample_mem : sample_mem_type := ( + x"000100", -- +256 + x"FFFE00", -- -512 + x"000001", -- +1 + x"FFFFFF", -- -1 (2's comp) + x"7FFFFF", -- max positive + x"800000", -- max negative + x"000A00", -- +2560 + x"FFF600" -- -2560 + ); + + -- Balance values: left, center, right, slightly left, slightly right + TYPE balance_mem_type IS ARRAY(0 TO N_BALANCES-1) OF STD_LOGIC_VECTOR(BALANCE_WIDTH-1 DOWNTO 0); + SIGNAL balance_mem : balance_mem_type := ( + std_logic_vector(to_unsigned(0, BALANCE_WIDTH)), -- full left + std_logic_vector(to_unsigned(480, BALANCE_WIDTH)), -- center + std_logic_vector(to_unsigned(1023, BALANCE_WIDTH)), -- full right + std_logic_vector(to_unsigned(240, BALANCE_WIDTH)), -- slightly left + std_logic_vector(to_unsigned(800, BALANCE_WIDTH)) -- slightly right + ); + +BEGIN + + -- Clock generation + aclk <= NOT aclk AFTER 5 ns; + + -- DUT instantiation + uut: balance_controller + GENERIC MAP ( + TDATA_WIDTH => TDATA_WIDTH, + BALANCE_WIDTH => BALANCE_WIDTH, + BALANCE_STEP_2 => BALANCE_STEP_2 + ) + PORT MAP ( + aclk => aclk, + aresetn => aresetn, + s_axis_tvalid => s_axis_tvalid, + s_axis_tdata => s_axis_tdata, + s_axis_tready => s_axis_tready, + s_axis_tlast => s_axis_tlast, + m_axis_tvalid => m_axis_tvalid, + m_axis_tdata => m_axis_tdata, + m_axis_tready => m_axis_tready, + m_axis_tlast => m_axis_tlast, + balance => balance + ); + + -- Stimulus process + stimulus : PROCESS + BEGIN + -- Reset + WAIT FOR 10 ns; + aresetn <= '1'; + WAIT UNTIL rising_edge(aclk); + + -- Set balance to center + balance <= balance_mem(1); + WAIT UNTIL rising_edge(aclk); + + -- Send all samples (center) + FOR i IN 0 TO N_SAMPLES-1 LOOP + s_axis_tdata <= sample_mem(i); + s_axis_tvalid <= '1'; + IF i = N_SAMPLES-1 THEN + s_axis_tlast <= '1'; + ELSE + s_axis_tlast <= '0'; + END IF; + WAIT UNTIL rising_edge(aclk); + WHILE s_axis_tready = '0' LOOP + WAIT UNTIL rising_edge(aclk); + END LOOP; + END LOOP; + s_axis_tvalid <= '0'; + s_axis_tlast <= '0'; + + -- Change balance to full left + WAIT FOR 20 ns; + balance <= balance_mem(0); + + -- Send one more sample (left) + WAIT UNTIL rising_edge(aclk); + s_axis_tdata <= x"000100"; + s_axis_tvalid <= '1'; + s_axis_tlast <= '1'; + WAIT UNTIL rising_edge(aclk); + WHILE s_axis_tready = '0' LOOP + WAIT UNTIL rising_edge(aclk); + END LOOP; + s_axis_tvalid <= '0'; + s_axis_tlast <= '0'; + + -- Sweep through other balance values + FOR i IN 2 TO N_BALANCES-1 LOOP + WAIT FOR 20 ns; + balance <= balance_mem(i); + WAIT UNTIL rising_edge(aclk); + END LOOP; + + -- Wait and finish + WAIT FOR 100 ns; + WAIT; + END PROCESS; + + -- Optionally, block m_axis_tready to test backpressure + PROCESS + BEGIN + WAIT FOR 60 ns; + WAIT UNTIL rising_edge(aclk); + m_axis_tready <= '0'; + WAIT FOR 20 ns; + WAIT UNTIL rising_edge(aclk); + m_axis_tready <= '1'; + WAIT; + END PROCESS; + +END Behavioral; \ No newline at end of file diff --git a/LAB3/sim/tb_digilent_jstk2.vhd b/LAB3/sim/tb_digilent_jstk2.vhd new file mode 100644 index 0000000..fde276e --- /dev/null +++ b/LAB3/sim/tb_digilent_jstk2.vhd @@ -0,0 +1,160 @@ +---------------------------------------------------------------------------------- +-- Company: +-- Engineer: +-- +-- Create Date: 05/13/2025 +-- Design Name: +-- Module Name: tb_digilent_jstk2 - sim +-- Project Name: +-- Target Devices: +-- Tool Versions: +-- Description: Testbench for digilent_jstk2, sends data only after CMDSETLEDRGB is received +-- +-- Dependencies: +-- +-- Revision: +-- Revision 0.01 - File Created +-- Additional Comments: +-- +---------------------------------------------------------------------------------- + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY tb_digilent_jstk2 IS +END tb_digilent_jstk2; + +ARCHITECTURE sim OF tb_digilent_jstk2 IS + + -- Testbench constants + CONSTANT CLKFREQ : INTEGER := 100_000_000; + CONSTANT DELAY_US : INTEGER := 25; + CONSTANT SPI_SCLKFREQ : INTEGER := 5_000; + CONSTANT CMDSETLEDRGB : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"84"; + + -- Component declaration for digilent_jstk2 + COMPONENT digilent_jstk2 IS + GENERIC ( + DELAY_US : INTEGER; + CLKFREQ : INTEGER; + SPI_SCLKFREQ : INTEGER + ); + PORT ( + aclk : IN STD_LOGIC; + aresetn : 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; + s_axis_tvalid : IN STD_LOGIC; + s_axis_tdata : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + jstk_x : OUT STD_LOGIC_VECTOR(9 DOWNTO 0); + jstk_y : OUT STD_LOGIC_VECTOR(9 DOWNTO 0); + btn_jstk : OUT STD_LOGIC; + btn_trigger : OUT STD_LOGIC; + led_r : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + led_g : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + led_b : IN STD_LOGIC_VECTOR(7 DOWNTO 0) + ); + END COMPONENT; + + -- Signals for DUT + SIGNAL aclk : STD_LOGIC := '0'; + SIGNAL aresetn : STD_LOGIC := '0'; + SIGNAL m_axis_tvalid : STD_LOGIC; + SIGNAL m_axis_tdata : STD_LOGIC_VECTOR(7 DOWNTO 0); + SIGNAL m_axis_tready : STD_LOGIC := '1'; -- Always ready in TB + SIGNAL s_axis_tvalid : STD_LOGIC := '0'; + SIGNAL s_axis_tdata : STD_LOGIC_VECTOR(7 DOWNTO 0) := (OTHERS => '0'); + SIGNAL jstk_x : STD_LOGIC_VECTOR(9 DOWNTO 0); + SIGNAL jstk_y : STD_LOGIC_VECTOR(9 DOWNTO 0); + SIGNAL btn_jstk : STD_LOGIC; + SIGNAL btn_trigger : STD_LOGIC; + SIGNAL led_r : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"AA"; + SIGNAL led_g : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"55"; + SIGNAL led_b : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"FF"; + + -- Stimulus memory for SPI responses (simulate JSTK2 module) + TYPE spi_mem_type IS ARRAY(0 TO 4) OF STD_LOGIC_VECTOR(7 DOWNTO 0); + SIGNAL spi_mem : spi_mem_type := ( + 0 => x"34", -- JSTK_X_LOW + 1 => x"02", -- JSTK_X_HIGH (2 LSBs used) + 2 => x"56", -- JSTK_Y_LOW + 3 => x"01", -- JSTK_Y_HIGH (2 LSBs used) + 4 => "00000011" -- BUTTONS: btn_jstk='1', btn_trigger='1' + ); + +BEGIN + + -- Clock generation + aclk <= NOT aclk AFTER 5 ns; + + -- DUT instantiation + uut : digilent_jstk2 + GENERIC MAP( + DELAY_US => DELAY_US, + CLKFREQ => CLKFREQ, + SPI_SCLKFREQ => SPI_SCLKFREQ + ) + PORT MAP( + aclk => aclk, + aresetn => aresetn, + m_axis_tvalid => m_axis_tvalid, + m_axis_tdata => m_axis_tdata, + m_axis_tready => m_axis_tready, + s_axis_tvalid => s_axis_tvalid, + s_axis_tdata => s_axis_tdata, + jstk_x => jstk_x, + jstk_y => jstk_y, + btn_jstk => btn_jstk, + btn_trigger => btn_trigger, + led_r => led_r, + led_g => led_g, + led_b => led_b + ); + + -- Stimulus process + stimulus : PROCESS + VARIABLE send_data : BOOLEAN := FALSE; + VARIABLE mem_idx : INTEGER := 0; + BEGIN + -- Reset + aresetn <= '0'; + WAIT FOR 20 ns; + aresetn <= '1'; + WAIT UNTIL rising_edge(aclk); + + -- Wait for the DUT to start sending SPI packets + WAIT FOR 1000 ns; + + -- Main loop: wait for CMDSETLEDRGB, then send mem bytes for each byte received + WHILE TRUE LOOP + WAIT UNTIL rising_edge(aclk); + + -- Default: s_axis_tvalid low unless sending + s_axis_tvalid <= '0'; + + IF m_axis_tvalid = '1' THEN + IF m_axis_tdata = CMDSETLEDRGB THEN + send_data := TRUE; + mem_idx := 0; + END IF; + + IF send_data AND mem_idx <= 4 THEN + -- Present data for one cycle when master is ready + s_axis_tdata <= spi_mem(mem_idx); + s_axis_tvalid <= '1'; + WAIT UNTIL rising_edge(aclk); -- handshake + s_axis_tvalid <= '0'; + mem_idx := mem_idx + 1; + -- Simula il tempo di risposta reale del JSTK2 (1,6 ms per byte) + WAIT FOR 1600 us; + IF mem_idx > 4 THEN + send_data := FALSE; + END IF; + END IF; + END IF; + END LOOP; + END PROCESS; + +END sim; \ No newline at end of file diff --git a/LAB3/sim/tb_moving_average.vhd b/LAB3/sim/tb_moving_average.vhd new file mode 100644 index 0000000..d8a0bd2 --- /dev/null +++ b/LAB3/sim/tb_moving_average.vhd @@ -0,0 +1,142 @@ +-- filepath: c:\DESD\LAB3\sim\tb_moving_average.vhd +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY tb_moving_average IS +END tb_moving_average; + +ARCHITECTURE sim OF tb_moving_average IS + + CONSTANT TDATA_WIDTH : INTEGER := 24; + CONSTANT FILTER_ORDER_PWR : INTEGER := 5; + + SIGNAL aclk : STD_LOGIC := '0'; + SIGNAL aresetn : STD_LOGIC := '0'; + + SIGNAL s_axis_tvalid : STD_LOGIC := '0'; + SIGNAL s_axis_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH-1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL s_axis_tlast : STD_LOGIC := '0'; + SIGNAL s_axis_tready : STD_LOGIC; + + SIGNAL m_axis_tvalid : STD_LOGIC; + SIGNAL m_axis_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH-1 DOWNTO 0); + SIGNAL m_axis_tlast : STD_LOGIC; + SIGNAL m_axis_tready : STD_LOGIC := '1'; + + SIGNAL enable_filter : STD_LOGIC := '0'; + + -- DUT + COMPONENT moving_average_filter_en + GENERIC ( + FILTER_ORDER_POWER : INTEGER := 5; + TDATA_WIDTH : POSITIVE := 24 + ); + PORT ( + aclk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; + s_axis_tvalid : IN STD_LOGIC; + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH-1 DOWNTO 0); + s_axis_tlast : IN STD_LOGIC; + s_axis_tready : OUT STD_LOGIC; + m_axis_tvalid : OUT STD_LOGIC; + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH-1 DOWNTO 0); + m_axis_tlast : OUT STD_LOGIC; + m_axis_tready : IN STD_LOGIC; + enable_filter : IN STD_LOGIC + ); + END COMPONENT; + +BEGIN + + -- Clock generation + clk_proc : PROCESS + BEGIN + aclk <= '0'; + WAIT FOR 5 ns; + aclk <= '1'; + WAIT FOR 5 ns; + END PROCESS; + + -- DUT instantiation + dut: moving_average_filter_en + GENERIC MAP ( + FILTER_ORDER_POWER => FILTER_ORDER_PWR, + TDATA_WIDTH => TDATA_WIDTH + ) + PORT MAP ( + aclk => aclk, + aresetn => aresetn, + s_axis_tvalid => s_axis_tvalid, + s_axis_tdata => s_axis_tdata, + s_axis_tlast => s_axis_tlast, + s_axis_tready => s_axis_tready, + m_axis_tvalid => m_axis_tvalid, + m_axis_tdata => m_axis_tdata, + m_axis_tlast => m_axis_tlast, + m_axis_tready => m_axis_tready, + enable_filter => enable_filter + ); + + -- Stimulus process + stim_proc : PROCESS + BEGIN + -- Reset + aresetn <= '0'; + WAIT FOR 20 ns; + aresetn <= '1'; + WAIT FOR 10 ns; + + -- Test All Pass (enable_filter = '0') + enable_filter <= '0'; + FOR i IN 0 TO 7 LOOP + -- SX sample + s_axis_tdata <= std_logic_vector(to_signed(i*100, TDATA_WIDTH)); + s_axis_tvalid <= '1'; + s_axis_tlast <= '0'; + WAIT UNTIL rising_edge(aclk); + WHILE s_axis_tready /= '1' LOOP + WAIT UNTIL rising_edge(aclk); + END LOOP; + s_axis_tvalid <= '0'; + + -- DX sample (tlast high) + s_axis_tdata <= std_logic_vector(to_signed(i*100+50, TDATA_WIDTH)); + s_axis_tvalid <= '1'; + s_axis_tlast <= '1'; + WAIT UNTIL rising_edge(aclk); + WHILE s_axis_tready /= '1' LOOP + WAIT UNTIL rising_edge(aclk); + END LOOP; + s_axis_tvalid <= '0'; + END LOOP; + + -- Test Moving Average (enable_filter = '1') + enable_filter <= '1'; + FOR i IN 0 TO 7 LOOP + -- SX sample + s_axis_tdata <= std_logic_vector(to_signed(i*100, TDATA_WIDTH)); + s_axis_tvalid <= '1'; + s_axis_tlast <= '0'; + WAIT UNTIL rising_edge(aclk); + WHILE s_axis_tready /= '1' LOOP + WAIT UNTIL rising_edge(aclk); + END LOOP; + s_axis_tvalid <= '0'; + + -- DX sample (tlast high) + s_axis_tdata <= std_logic_vector(to_signed(i*100+50, TDATA_WIDTH)); + s_axis_tvalid <= '1'; + s_axis_tlast <= '1'; + WAIT UNTIL rising_edge(aclk); + WHILE s_axis_tready /= '1' LOOP + WAIT UNTIL rising_edge(aclk); + END LOOP; + s_axis_tvalid <= '0'; + END LOOP; + + -- End simulation + WAIT FOR 50 ns; + END PROCESS; + +END sim; \ No newline at end of file diff --git a/LAB3/sim/tb_volume_multiplier.vhd b/LAB3/sim/tb_volume_multiplier.vhd new file mode 100644 index 0000000..b91b495 --- /dev/null +++ b/LAB3/sim/tb_volume_multiplier.vhd @@ -0,0 +1,178 @@ +---------------------------------------------------------------------------------- +-- Testbench for volume_multiplier +---------------------------------------------------------------------------------- +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +ENTITY tb_volume_multiplier IS +END tb_volume_multiplier; + +ARCHITECTURE Behavioral OF tb_volume_multiplier IS + + CONSTANT TDATA_WIDTH : POSITIVE := 24; + CONSTANT VOLUME_WIDTH : POSITIVE := 10; + CONSTANT VOLUME_STEP_2 : POSITIVE := 6; + CONSTANT N_SAMPLES : INTEGER := 8; + CONSTANT N_VOLUMES : INTEGER := 10; + + -- Output width calculation (as in DUT) + CONSTANT TDATA_OUT_WIDTH : INTEGER := TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) + 1; + + COMPONENT volume_multiplier IS + GENERIC ( + TDATA_WIDTH : POSITIVE := 24; + VOLUME_WIDTH : POSITIVE := 10; + VOLUME_STEP_2 : POSITIVE := 6 + ); + PORT ( + aclk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; + s_axis_tvalid : IN STD_LOGIC; + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + s_axis_tlast : IN STD_LOGIC; + s_axis_tready : OUT STD_LOGIC; + m_axis_tvalid : OUT STD_LOGIC; + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_OUT_WIDTH - 1 DOWNTO 0); + m_axis_tlast : OUT STD_LOGIC; + m_axis_tready : IN STD_LOGIC; + volume : IN STD_LOGIC_VECTOR(VOLUME_WIDTH - 1 DOWNTO 0) + ); + END COMPONENT; + + SIGNAL aclk : STD_LOGIC := '0'; + SIGNAL aresetn : STD_LOGIC := '0'; + SIGNAL s_axis_tvalid : STD_LOGIC := '0'; + SIGNAL s_axis_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL s_axis_tlast : STD_LOGIC := '0'; + SIGNAL s_axis_tready : STD_LOGIC; + SIGNAL m_axis_tvalid : STD_LOGIC; + SIGNAL m_axis_tdata : STD_LOGIC_VECTOR(TDATA_OUT_WIDTH - 1 DOWNTO 0); + SIGNAL m_axis_tlast : STD_LOGIC; + SIGNAL m_axis_tready : STD_LOGIC := '1'; + SIGNAL volume : STD_LOGIC_VECTOR(VOLUME_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); + + -- Test input samples + TYPE sample_mem_type IS ARRAY(0 TO N_SAMPLES-1) OF STD_LOGIC_VECTOR(TDATA_WIDTH-1 DOWNTO 0); + SIGNAL sample_mem : sample_mem_type := ( + x"000100", -- +256 + x"FFFE00", -- -512 + x"000001", -- +1 + x"FFFFFF", -- -1 (2's comp) + x"7FFFFF", -- max positive + x"800000", -- max negative + x"000A00", -- +2560 + x"FFF600" -- -2560 + ); + + -- Vettore di memoria per i valori di volume + TYPE volume_mem_type IS ARRAY(0 TO N_VOLUMES-1) OF STD_LOGIC_VECTOR(VOLUME_WIDTH-1 DOWNTO 0); + SIGNAL volume_mem : volume_mem_type := ( + std_logic_vector(to_unsigned(0, VOLUME_WIDTH)), -- 0.25x (forte attenuazione) + std_logic_vector(to_unsigned(64, VOLUME_WIDTH)), -- 0.375x (attenuazione media) + std_logic_vector(to_unsigned(479, VOLUME_WIDTH)), -- 0.4375x (leggera attenuazione) + std_logic_vector(to_unsigned(480, VOLUME_WIDTH)), -- 0.5x (volume neutro) + std_logic_vector(to_unsigned(513, VOLUME_WIDTH)), -- Circa 0.5x (volume neutro) + std_logic_vector(to_unsigned(576, VOLUME_WIDTH)), -- 0.5625x (leggero aumento) + std_logic_vector(to_unsigned(640, VOLUME_WIDTH)), -- 0.625x (aumento medio) + std_logic_vector(to_unsigned(768, VOLUME_WIDTH)), -- 0.75x (aumento forte) + std_logic_vector(to_unsigned(896, VOLUME_WIDTH)), -- 0.875x (aumento molto forte) + std_logic_vector(to_unsigned(1023, VOLUME_WIDTH)) -- 1x (massimo volume) + ); + +BEGIN + + -- Clock generation + aclk <= NOT aclk AFTER 5 ns; + + -- DUT instantiation + uut: volume_multiplier + GENERIC MAP ( + TDATA_WIDTH => TDATA_WIDTH, + VOLUME_WIDTH => VOLUME_WIDTH, + VOLUME_STEP_2 => VOLUME_STEP_2 + ) + PORT MAP ( + aclk => aclk, + aresetn => aresetn, + s_axis_tvalid => s_axis_tvalid, + s_axis_tdata => s_axis_tdata, + s_axis_tlast => s_axis_tlast, + s_axis_tready => s_axis_tready, + m_axis_tvalid => m_axis_tvalid, + m_axis_tdata => m_axis_tdata, + m_axis_tlast => m_axis_tlast, + m_axis_tready => m_axis_tready, + volume => volume + ); + + -- Stimulus process + stimulus : PROCESS + BEGIN + -- Reset + WAIT FOR 10 ns; + aresetn <= '1'; + WAIT UNTIL rising_edge(aclk); + + -- Set volume to mid (no gain/loss) + volume <= volume_mem(7); + WAIT UNTIL rising_edge(aclk); + + -- Send all samples + FOR i IN 0 TO N_SAMPLES-1 LOOP + s_axis_tdata <= sample_mem(i); + s_axis_tvalid <= '1'; + IF i = N_SAMPLES-1 THEN + s_axis_tlast <= '1'; + ELSE + s_axis_tlast <= '0'; + END IF; + -- Wait for handshake + WAIT UNTIL rising_edge(aclk); + WHILE s_axis_tready = '0' LOOP + WAIT UNTIL rising_edge(aclk); + END LOOP; + END LOOP; + s_axis_tvalid <= '0'; + s_axis_tlast <= '0'; + + -- Change volume (attenuate) + WAIT FOR 20 ns; + volume <= volume_mem(1); + + -- Send one more sample + WAIT UNTIL rising_edge(aclk); + s_axis_tdata <= x"000100"; + s_axis_tvalid <= '1'; + s_axis_tlast <= '1'; + WAIT UNTIL rising_edge(aclk); + WHILE s_axis_tready = '0' LOOP + WAIT UNTIL rising_edge(aclk); + END LOOP; + s_axis_tvalid <= '0'; + s_axis_tlast <= '0'; + + FOR i IN 2 TO N_VOLUMES-1 LOOP + WAIT FOR 20 ns; + volume <= volume_mem(i); + WAIT UNTIL rising_edge(aclk); + END LOOP; + + -- Wait and finish + WAIT FOR 100 ns; + WAIT; + END PROCESS; + + -- Optionally, block m_axis_tready to test backpressure + PROCESS + BEGIN + WAIT FOR 60 ns; + WAIT UNTIL rising_edge(aclk); + m_axis_tready <= '0'; + WAIT FOR 20 ns; + WAIT UNTIL rising_edge(aclk); + m_axis_tready <= '1'; + WAIT; + END PROCESS; + +END Behavioral; \ No newline at end of file diff --git a/LAB3/sim/tb_volume_saturator.vhd b/LAB3/sim/tb_volume_saturator.vhd new file mode 100644 index 0000000..4782913 --- /dev/null +++ b/LAB3/sim/tb_volume_saturator.vhd @@ -0,0 +1,157 @@ +---------------------------------------------------------------------------------- +-- Company: +-- Engineer: +-- +-- Create Date: 05/20/2025 +-- Design Name: +-- Module Name: tb_volume_saturator - Behavioral +-- Project Name: +-- Target Devices: +-- Tool Versions: Vivado 2020.2 +-- Description: Testbench for volume_saturator (stereo, L->R, tlast on R) +-- +---------------------------------------------------------------------------------- +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +ENTITY tb_volume_saturator IS +END tb_volume_saturator; + +ARCHITECTURE Behavioral OF tb_volume_saturator IS + + CONSTANT TDATA_WIDTH : POSITIVE := 24; + CONSTANT VOLUME_WIDTH : POSITIVE := 10; + CONSTANT VOLUME_STEP_2 : POSITIVE := 6; + CONSTANT STEREO_SAMPLES : INTEGER := 8; + + -- Calculate s_axis_tdata width + CONSTANT TDATA_IN_WIDTH : INTEGER := TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) + 1; + + COMPONENT volume_saturator IS + GENERIC ( + TDATA_WIDTH : POSITIVE := 24; + VOLUME_WIDTH : POSITIVE := 10; + VOLUME_STEP_2 : POSITIVE := 6; -- i.e., number_of_steps = 2**(VOLUME_STEP_2) + HIGHER_BOUND : INTEGER := 2 ** 15 - 1; -- Inclusive + LOWER_BOUND : INTEGER := - 2 ** 15 -- Inclusive + ); + PORT ( + aclk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; + + s_axis_tvalid : IN STD_LOGIC; + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) DOWNTO 0); + s_axis_tlast : IN STD_LOGIC; + s_axis_tready : OUT STD_LOGIC; + + m_axis_tvalid : OUT STD_LOGIC; + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + m_axis_tlast : OUT STD_LOGIC; + m_axis_tready : IN STD_LOGIC + ); + END COMPONENT; + + SIGNAL aclk : STD_LOGIC := '0'; + SIGNAL aresetn : STD_LOGIC := '0'; + SIGNAL s_axis_tvalid : STD_LOGIC := '0'; + SIGNAL s_axis_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) DOWNTO 0) := (OTHERS => '0'); + SIGNAL s_axis_tlast : STD_LOGIC := '0'; + SIGNAL s_axis_tready : STD_LOGIC; + SIGNAL m_axis_tvalid : STD_LOGIC; + SIGNAL m_axis_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + SIGNAL m_axis_tlast : STD_LOGIC; + SIGNAL m_axis_tready : STD_LOGIC := '1'; + + -- Example stereo audio: L, R, L, R, ... (tlast on R) + TYPE stereo_mem_type IS ARRAY(0 TO 2 * STEREO_SAMPLES - 1) OF STD_LOGIC_VECTOR(TDATA_IN_WIDTH - 1 DOWNTO 0); + SIGNAL stereo_mem : stereo_mem_type := ( + x"00009C40", -- +40000 (clipping positivo) + x"00007FFF", -- +32767 (HIGHER_BOUND) + x"00007FFE", -- +32766 (appena sotto HIGHER_BOUND) + x"00000000", -- 0 + x"FFFF8001", -- -32767 (appena sopra LOWER_BOUND) + x"FFFF8000", -- -32768 (LOWER_BOUND) + x"FFFF63C0", -- -40000 (clipping negativo) + x"00003039", -- +12345 (valore positivo intermedio) + x"FFFFCFC7", -- -12345 (valore negativo intermedio) + x"00007FFF", -- +32767 (HIGHER_BOUND, ripetuto) + x"FFFF8000", -- -32768 (LOWER_BOUND, ripetuto) + x"00009C40", -- +40000 (clipping positivo, ripetuto) + x"FFFF63C0", -- -40000 (clipping negativo, ripetuto) + x"00000001", -- +1 + x"FFFFFFFF", -- -1 + x"00000000" -- 0 (ripetuto) + ); + +BEGIN + + -- Clock generation + aclk <= NOT aclk AFTER 5 ns; + + -- DUT instantiation + uut : volume_saturator + GENERIC MAP( + TDATA_WIDTH => TDATA_WIDTH, + VOLUME_WIDTH => VOLUME_WIDTH, + VOLUME_STEP_2 => VOLUME_STEP_2, + HIGHER_BOUND => 2 ** 15 - 1, + LOWER_BOUND => - 2 ** 15 + ) + PORT MAP( + aclk => aclk, + aresetn => aresetn, + s_axis_tvalid => s_axis_tvalid, + s_axis_tdata => s_axis_tdata, + s_axis_tlast => s_axis_tlast, + s_axis_tready => s_axis_tready, + m_axis_tvalid => m_axis_tvalid, + m_axis_tdata => m_axis_tdata, + m_axis_tlast => m_axis_tlast, + m_axis_tready => m_axis_tready + ); + + -- Stimulus process: send stereo samples, tlast on R + stimulus : PROCESS + BEGIN + -- Reset + WAIT FOR 10 ns; + aresetn <= '1'; + WAIT UNTIL rising_edge(aclk); + + FOR i IN 0 TO stereo_mem'high LOOP + s_axis_tdata <= stereo_mem(i); + s_axis_tvalid <= '1'; + -- tlast asserted on every R channel (odd index) + IF (i MOD 2) = 1 THEN + s_axis_tlast <= '1'; + ELSE + s_axis_tlast <= '0'; + END IF; + -- Wait for handshake + WAIT UNTIL rising_edge(aclk); + WHILE s_axis_tready = '0' LOOP + WAIT UNTIL rising_edge(aclk); + END LOOP; + END LOOP; + s_axis_tvalid <= '0'; + s_axis_tlast <= '0'; + + -- Wait and finish + WAIT FOR 100 ns; + WAIT; + END PROCESS; + + -- Optionally, block m_axis_tready for a few cycles to test backpressure + PROCESS + BEGIN + WAIT FOR 80 ns; + WAIT UNTIL rising_edge(aclk); + m_axis_tready <= '0'; + WAIT FOR 30 ns; + WAIT UNTIL rising_edge(aclk); + m_axis_tready <= '1'; + WAIT; + END PROCESS; + +END Behavioral; \ No newline at end of file diff --git a/LAB3/src/LFO.vhd b/LAB3/src/LFO.vhd index b596bb8..5279f36 100644 --- a/LAB3/src/LFO.vhd +++ b/LAB3/src/LFO.vhd @@ -1,40 +1,225 @@ - library IEEE; -use IEEE.STD_LOGIC_1164.ALL; +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; --- Uncomment the following library declaration if using --- arithmetic functions with Signed or Unsigned values -use IEEE.NUMERIC_STD.ALL; - -entity LFO is - generic( - CHANNEL_LENGHT : integer := 24; - JOYSTICK_LENGHT : integer := 10; - CLK_PERIOD_NS : integer := 10; - TRIANGULAR_COUNTER_LENGHT : integer := 10 -- Triangular wave period length +-- Entity: LFO (Low Frequency Oscillator) - Alternative Implementation +-- Purpose: Applies effect to audio by modulating amplitude with a triangular wave +-- This is a simplified, single-process implementation compared to the pipelined version +-- Provides real-time audio amplitude modulation for musical effects +ENTITY LFO IS + GENERIC ( + CHANNEL_LENGHT : INTEGER := 24; -- Bit width of audio samples (24-bit signed) + JOYSTICK_LENGHT : INTEGER := 10; -- Bit width of joystick input (10-bit = 0-1023 range) + CLK_PERIOD_NS : INTEGER := 10; -- Clock period in nanoseconds (10ns = 100MHz) + TRIANGULAR_COUNTER_LENGHT : INTEGER := 10 -- Triangular wave counter length (affects modulation depth) ); - Port ( - - aclk : in std_logic; - aresetn : in std_logic; - - lfo_period : in std_logic_vector(JOYSTICK_LENGHT-1 downto 0); - - lfo_enable : in std_logic; - - s_axis_tvalid : in std_logic; - s_axis_tdata : in std_logic_vector(CHANNEL_LENGHT-1 downto 0); - s_axis_tlast : in std_logic; - s_axis_tready : out std_logic; - - m_axis_tvalid : out std_logic; - m_axis_tdata : out std_logic_vector(CHANNEL_LENGHT-1 downto 0); - m_axis_tlast : out std_logic; - m_axis_tready : in std_logic - ); -end entity LFO; + PORT ( + -- Clock and Reset + aclk : IN STD_LOGIC; -- Main system clock + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset -architecture Behavioral of LFO is + -- LFO Control inputs + lfo_period : IN STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0); -- Controls LFO frequency (joystick Y-axis) + lfo_enable : IN STD_LOGIC; -- Enable/bypass LFO effect -begin + -- Slave AXI Stream interface (audio input) + s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal + s_axis_tdata : IN STD_LOGIC_VECTOR(CHANNEL_LENGHT - 1 DOWNTO 0); -- Audio sample input + s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) + s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data -end architecture; \ No newline at end of file + -- Master AXI Stream interface (audio output) + m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal + m_axis_tdata : OUT STD_LOGIC_VECTOR(CHANNEL_LENGHT - 1 DOWNTO 0); -- Modulated audio sample output + m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough + m_axis_tready : IN STD_LOGIC -- Downstream ready signal + ); +END ENTITY LFO; + +ARCHITECTURE Behavioral OF LFO IS + + -- LFO timing configuration constants + CONSTANT LFO_COUNTER_BASE_PERIOD_US : INTEGER := 1000; -- Base period: 1ms (1kHz base frequency) + CONSTANT ADJUSTMENT_FACTOR : INTEGER := 90; -- Frequency adjustment sensitivity (clock cycles per joystick unit) + CONSTANT JSTK_CENTER_VALUE : INTEGER := 2 ** (JOYSTICK_LENGHT - 1); -- Joystick center position (512 for 10-bit) + + -- Calculate base clock cycles for 1ms period at current clock frequency + CONSTANT LFO_COUNTER_BASE_CLK_CYCLES : INTEGER := LFO_COUNTER_BASE_PERIOD_US * 1000 / CLK_PERIOD_NS; -- 1ms = 100,000 clk cycles + + -- Calculate frequency range limits based on joystick range + CONSTANT LFO_CLK_CYCLES_MIN : INTEGER := LFO_COUNTER_BASE_CLK_CYCLES - ADJUSTMENT_FACTOR * (2 ** (JOYSTICK_LENGHT - 1)); -- 53,920 clk cycles (faster) + CONSTANT LFO_CLK_CYCLES_MAX : INTEGER := LFO_COUNTER_BASE_CLK_CYCLES + ADJUSTMENT_FACTOR * (2 ** (JOYSTICK_LENGHT - 1) - 1); -- 145,990 clk cycles (slower) + + -- LFO timing control signals + SIGNAL step_clk_cycles_delta : INTEGER RANGE - 2 ** (JOYSTICK_LENGHT - 1) * ADJUSTMENT_FACTOR TO (2 ** (JOYSTICK_LENGHT - 1) - 1) * ADJUSTMENT_FACTOR := 0; + SIGNAL step_clk_cycles : INTEGER RANGE LFO_CLK_CYCLES_MIN TO LFO_CLK_CYCLES_MAX := LFO_COUNTER_BASE_CLK_CYCLES; + SIGNAL step_counter : NATURAL RANGE 0 TO LFO_CLK_CYCLES_MAX := 0; + + -- Triangular wave generation signals + -- Note: Using signed counter with extra bit to handle full range calculations + SIGNAL tri_counter : SIGNED(TRIANGULAR_COUNTER_LENGHT DOWNTO 0) := (OTHERS => '0'); -- Triangular wave amplitude + SIGNAL direction_up : STD_LOGIC := '1'; -- Wave direction: '1' = ascending, '0' = descending + + -- AXI4-Stream control signals + SIGNAL trigger : STD_LOGIC := '0'; -- Trigger to indicate new processed data is ready + SIGNAL s_axis_tlast_reg : STD_LOGIC := '0'; -- Registered version of tlast for output synchronization + SIGNAL m_axis_tvalid_int : STD_LOGIC := '0'; -- Internal output valid signal + + -- Audio processing signal with extended width for multiplication + -- Width accommodates: audio sample + triangular counter to prevent overflow + SIGNAL m_axis_tdata_temp : SIGNED(CHANNEL_LENGHT + TRIANGULAR_COUNTER_LENGHT DOWNTO 0) := (OTHERS => '0'); + +BEGIN + + -- Output signal assignments with proper AXI4-Stream flow control + m_axis_tvalid <= m_axis_tvalid_int; + -- Input ready logic: Ready when downstream is ready OR no valid data pending, AND not in reset + s_axis_tready <= (m_axis_tready OR NOT m_axis_tvalid_int) AND aresetn; + + -- Optimized single process for LFO timing and triangular waveform generation + -- This process handles both the frequency control and wave shape generation + triangular_wave_lfo_generator : PROCESS (aclk) + BEGIN + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset LFO generator to initial state + step_clk_cycles <= LFO_COUNTER_BASE_CLK_CYCLES; -- Set to base frequency + step_counter <= 0; -- Clear timing counter + tri_counter <= (OTHERS => '0'); -- Start triangular wave at zero + direction_up <= '1'; -- Start counting up + + ELSE + -- Calculate LFO period based on joystick input + -- Joystick mapping: + -- 0-511: Slower than base frequency (longer period, lower frequency) + -- 512: Base frequency (1kHz) + -- 513-1023: Faster than base frequency (shorter period, higher frequency) + step_clk_cycles_delta <= (to_integer(unsigned(lfo_period)) - JSTK_CENTER_VALUE); + step_clk_cycles <= LFO_COUNTER_BASE_CLK_CYCLES - step_clk_cycles_delta * ADJUSTMENT_FACTOR; + + -- Generate triangular wave when LFO is enabled + IF lfo_enable = '1' THEN + + -- Clock divider: Update triangular wave at calculated rate + IF step_counter >= step_clk_cycles THEN + step_counter <= 0; -- Reset counter for next period + + -- Check for triangular wave direction changes at extremes + -- Note: Using (2^n - 2) and 1 instead of (2^n - 1) and 0 due to process signal assignment + IF tri_counter = (2 ** TRIANGULAR_COUNTER_LENGHT) - 2 THEN + direction_up <= '0'; -- Switch to descending at near-maximum + + ELSIF tri_counter = 1 THEN + direction_up <= '1'; -- Switch to ascending at near-minimum + + END IF; + + -- Update triangular wave value based on current direction + -- This creates the classic triangular waveform shape + IF direction_up = '1' THEN + tri_counter <= tri_counter + 1; -- Ascending: increment + ELSE + tri_counter <= tri_counter - 1; -- Descending: decrement + END IF; + + ELSE + step_counter <= step_counter + 1; -- Continue counting towards next update + + END IF; + + END IF; + + END IF; + + END IF; + + END PROCESS triangular_wave_lfo_generator; + + -- AXI4-Stream handshake logic and audio processing + -- This process handles input/output data flow and applies the LFO modulation + AXIS : PROCESS (aclk) + BEGIN + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset AXI4-Stream interface and audio processing + s_axis_tlast_reg <= '0'; -- Clear registered channel indicator + m_axis_tdata_temp <= (OTHERS => '0'); -- Clear temporary audio data + m_axis_tvalid_int <= '0'; -- No valid output data + m_axis_tlast <= '0'; -- Clear output channel indicator + + ELSE + -- Output handshake management: + -- Clear valid flag when downstream accepts data + IF m_axis_tready = '1' THEN + m_axis_tvalid_int <= '0'; + END IF; + + -- Data output logic: Send processed audio when trigger is active and output is available + IF trigger = '1' AND (m_axis_tvalid_int = '0' OR m_axis_tready = '1') THEN + -- Scale down the multiplication result to original audio bit width + -- Right shift by TRIANGULAR_COUNTER_LENGHT effectively divides by 2^TRIANGULAR_COUNTER_LENGHT + -- This maintains proper audio amplitude after modulation + m_axis_tdata <= STD_LOGIC_VECTOR( + resize( + shift_right( + m_axis_tdata_temp, -- Wide multiplication result + TRIANGULAR_COUNTER_LENGHT -- Scale factor + ), + CHANNEL_LENGHT -- Final audio sample width + ) + ); + m_axis_tlast <= s_axis_tlast_reg; -- Output registered channel indicator + + m_axis_tvalid_int <= '1'; -- Mark output as valid + trigger <= '0'; -- Clear trigger - data has been output + + END IF; + + -- Data input logic: Process new audio samples when available and output is ready + IF s_axis_tvalid = '1' AND (m_axis_tready = '1' OR m_axis_tvalid_int = '0') THEN + IF lfo_enable = '1' THEN + -- Apply LFO effect: multiply audio sample by triangular wave + -- This creates amplitude modulation (effect) + m_axis_tdata_temp <= signed(s_axis_tdata) * tri_counter; + s_axis_tlast_reg <= s_axis_tlast; -- Register channel indicator + + ELSE + -- LFO disabled: pass audio through unchanged but maintain bit width + -- Left shift compensates for the right shift that occurs during output + -- This ensures unity gain when LFO is bypassed + m_axis_tdata_temp <= shift_left( + resize( + signed(s_axis_tdata), -- Convert input to signed + m_axis_tdata_temp'length -- Extend to full processing width + ), + TRIANGULAR_COUNTER_LENGHT -- Compensate for output scaling + ); + s_axis_tlast_reg <= s_axis_tlast; -- Register channel indicator + + END IF; + + trigger <= '1'; -- Set trigger to indicate new processed data is ready + + END IF; + + END IF; + + END IF; + + END PROCESS AXIS; + + -- LFO Implementation Summary: + -- 1. Generates triangular wave at frequency controlled by joystick input + -- 2. When enabled: multiplies audio samples by triangular wave (multiplier value range from 0 to 1) + -- 3. When disabled: passes audio through unchanged (bypass mode) + -- 4. Uses proper AXI4-Stream handshaking for real-time audio processing + -- + -- Effect Characteristics: + -- - Frequency range: Approximately 0.1Hz to 10Hz (typical for audio LFO) + -- - Modulation depth: Controlled by TRIANGULAR_COUNTER_LENGHT generic + -- - Waveform: Triangular (linear amplitude changes, smooth transitions) + -- - Bypass capability: Clean audio passthrough when disabled + +END ARCHITECTURE Behavioral; \ No newline at end of file diff --git a/LAB3/src/LFO_1.vhd b/LAB3/src/LFO_1.vhd new file mode 100644 index 0000000..d04411f --- /dev/null +++ b/LAB3/src/LFO_1.vhd @@ -0,0 +1,256 @@ +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +-- Entity: LFO_1 (Low Frequency Oscillator) +-- Purpose: Applies tremolo effect to audio by modulating amplitude with a triangular wave +-- Creates classic audio effects like vibrato, tremolo, and amplitude modulation +-- Implements a 3-stage pipeline for efficient real-time audio processing +ENTITY LFO_1 IS + GENERIC ( + CHANNEL_LENGHT : INTEGER := 24; -- Bit width of audio samples (24-bit signed) + JOYSTICK_LENGHT : INTEGER := 10; -- Bit width of joystick input (10-bit = 0-1023 range) + CLK_PERIOD_NS : INTEGER := 10; -- Clock period in nanoseconds (10ns = 100MHz) + TRIANGULAR_COUNTER_LENGHT : INTEGER := 10 -- Bit width of triangular wave counter (affects modulation depth) + ); + PORT ( + -- Clock and Reset + aclk : IN STD_LOGIC; -- Main system clock + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset + + -- LFO_1 Control inputs + lfo_period : IN STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0); -- Controls LFO_1 frequency (joystick Y-axis) + lfo_enable : IN STD_LOGIC; -- Enable/bypass LFO_1 effect + + -- Slave AXI Stream interface (audio input) + s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal + s_axis_tdata : IN STD_LOGIC_VECTOR(CHANNEL_LENGHT - 1 DOWNTO 0); -- Audio sample input + s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) + s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data + + -- Master AXI Stream interface (audio output) + m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal + m_axis_tdata : OUT STD_LOGIC_VECTOR(CHANNEL_LENGHT - 1 DOWNTO 0); -- Modulated audio sample output + m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough + m_axis_tready : IN STD_LOGIC -- Downstream ready signal + ); +END ENTITY LFO_1; + +ARCHITECTURE Behavioral OF LFO_1 IS + + -- Constants for LFO_1 timing configuration + CONSTANT BASE_PERIOD_MICROSECONDS : INTEGER := 1000; -- Base period: 1ms (1kHz base frequency) + CONSTANT FREQUENCY_ADJUSTMENT_FACTOR : INTEGER := 90; -- Frequency adjustment sensitivity (clock cycles per joystick unit) + CONSTANT JOYSTICK_CENTER_VALUE : INTEGER := 2 ** (JOYSTICK_LENGHT - 1); -- Joystick center position (512 for 10-bit) + + -- Calculate base clock cycles for 1ms period at current clock frequency + CONSTANT BASE_CLOCK_CYCLES : INTEGER := BASE_PERIOD_MICROSECONDS * 1000 / CLK_PERIOD_NS; + + -- Calculate frequency range limits based on joystick range + -- Minimum frequency (fastest LFO_1): occurs when joystick is at minimum position + CONSTANT MIN_CLOCK_CYCLES : INTEGER := BASE_CLOCK_CYCLES - FREQUENCY_ADJUSTMENT_FACTOR * (2 ** (JOYSTICK_LENGHT - 1)); + -- Maximum frequency (slowest LFO_1): occurs when joystick is at maximum position + CONSTANT MAX_CLOCK_CYCLES : INTEGER := BASE_CLOCK_CYCLES + FREQUENCY_ADJUSTMENT_FACTOR * (2 ** (JOYSTICK_LENGHT - 1) - 1); + + -- Internal signals for LFO_1 control + -- Period adjustment based on joystick input (positive = slower, negative = faster) + SIGNAL period_adjustment_delta : INTEGER RANGE - 2 ** (JOYSTICK_LENGHT - 1) * FREQUENCY_ADJUSTMENT_FACTOR + TO (2 ** (JOYSTICK_LENGHT - 1) - 1) * FREQUENCY_ADJUSTMENT_FACTOR := 0; + SIGNAL current_period_cycles : INTEGER RANGE MIN_CLOCK_CYCLES TO MAX_CLOCK_CYCLES := BASE_CLOCK_CYCLES; + + -- Pipeline stage 1 registers - Input processing and period calculation + SIGNAL audio_data_stage1 : STD_LOGIC_VECTOR(CHANNEL_LENGHT - 1 DOWNTO 0) := (OTHERS => '0'); -- Registered audio input + SIGNAL enable_flag_stage1 : STD_LOGIC := '0'; -- Registered LFO_1 enable + SIGNAL valid_flag_stage1 : STD_LOGIC := '0'; -- Valid data in stage 1 + SIGNAL last_flag_stage1 : STD_LOGIC := '0'; -- Registered channel indicator + + -- Pipeline stage 2 registers - Triangular wave generation + SIGNAL triangular_wave_value : unsigned(TRIANGULAR_COUNTER_LENGHT - 1 DOWNTO 0) := (OTHERS => '0'); -- Current triangular wave amplitude + SIGNAL wave_direction_up : STD_LOGIC := '1'; -- Triangle wave direction: '1' = ascending, '0' = descending + SIGNAL timing_counter : NATURAL RANGE 0 TO MAX_CLOCK_CYCLES := 0; -- Clock cycle counter for LFO_1 timing + SIGNAL enable_flag_stage2 : STD_LOGIC := '0'; -- LFO_1 enable flag for stage 2 + SIGNAL valid_flag_stage2 : STD_LOGIC := '0'; -- Valid data in stage 2 + SIGNAL last_flag_stage2 : STD_LOGIC := '0'; -- Channel indicator for stage 2 + SIGNAL audio_data_stage2 : STD_LOGIC_VECTOR(CHANNEL_LENGHT - 1 DOWNTO 0) := (OTHERS => '0'); -- Audio data for stage 2 + + -- Pipeline stage 3 registers - Modulation and output + -- Extended width to accommodate multiplication result before scaling + SIGNAL multiplication_result : STD_LOGIC_VECTOR(CHANNEL_LENGHT + TRIANGULAR_COUNTER_LENGHT - 1 DOWNTO 0) := (OTHERS => '0'); + + -- Internal AXI4-Stream control signals + SIGNAL master_valid_internal : STD_LOGIC := '0'; -- Internal output valid signal + SIGNAL slave_ready_internal : STD_LOGIC := '1'; -- Internal input ready signal + +BEGIN + + -- Direct connection: tlast passes through unchanged (maintains channel timing) + m_axis_tlast <= last_flag_stage1; + + -- Pipeline stage 1: Input registration and LFO_1 period calculation + -- This stage captures input data and calculates the LFO_1 period based on joystick position + input_processing_stage : PROCESS (aclk) + BEGIN + IF rising_edge(aclk) THEN + IF aresetn = '0' THEN + -- Reset all stage 1 registers to safe initial states + audio_data_stage1 <= (OTHERS => '0'); -- Clear audio data + current_period_cycles <= BASE_CLOCK_CYCLES; -- Set to base frequency + enable_flag_stage1 <= '0'; -- Disable LFO_1 + valid_flag_stage1 <= '0'; -- No valid data + last_flag_stage1 <= '0'; -- Clear channel indicator + ELSE + -- Calculate LFO_1 period based on joystick y-axis input + -- Joystick mapping: + -- 0-511: Faster than base frequency (shorter period) + -- 512: Base frequency (1kHz) + -- 513-1023: Slower than base frequency (longer period) + period_adjustment_delta <= (to_integer(unsigned(lfo_period)) - JOYSTICK_CENTER_VALUE) * FREQUENCY_ADJUSTMENT_FACTOR; + current_period_cycles <= BASE_CLOCK_CYCLES - period_adjustment_delta; + + -- AXI4-Stream handshake: accept new data when both valid and ready + IF s_axis_tvalid = '1' AND slave_ready_internal = '1' THEN + audio_data_stage1 <= s_axis_tdata; -- Register input audio sample + enable_flag_stage1 <= lfo_enable; -- Register enable control + valid_flag_stage1 <= '1'; -- Mark data as valid for next stage + last_flag_stage1 <= s_axis_tlast; -- Register channel boundary signal + ELSE + valid_flag_stage1 <= '0'; -- No valid data to pass to next stage + END IF; + END IF; + END IF; + END PROCESS input_processing_stage; + + -- Pipeline stage 2: Triangular wave generation + -- This stage generates the triangular wave that will modulate the audio amplitude + triangular_wave_generator : PROCESS (aclk) + BEGIN + IF rising_edge(aclk) THEN + IF aresetn = '0' THEN + -- Reset triangular wave generator to initial state + timing_counter <= 0; -- Clear timing counter + triangular_wave_value <= (OTHERS => '0'); -- Start at zero amplitude + wave_direction_up <= '1'; -- Start counting up + enable_flag_stage2 <= '0'; -- Disable LFO_1 + valid_flag_stage2 <= '0'; -- No valid data + last_flag_stage2 <= '0'; -- Clear channel indicator + audio_data_stage2 <= (OTHERS => '0'); -- Clear audio data + ELSE + -- Pass through pipeline registers from stage 1 to stage 2 + enable_flag_stage2 <= enable_flag_stage1; -- Forward enable flag + valid_flag_stage2 <= valid_flag_stage1; -- Forward valid flag + last_flag_stage2 <= last_flag_stage1; -- Forward channel indicator + audio_data_stage2 <= audio_data_stage1; -- Forward audio data + + -- Generate triangular wave when LFO_1 is enabled + IF enable_flag_stage1 = '1' THEN + -- Clock divider: update triangular counter based on calculated period + IF timing_counter < current_period_cycles THEN + timing_counter <= timing_counter + 1; -- Count towards period target + ELSE + timing_counter <= 0; -- Reset counter for next period + + -- Update triangular wave: count up or down based on current direction + -- This creates the classic triangular waveform shape + IF wave_direction_up = '1' THEN + -- Ascending phase: check if we reached maximum amplitude + IF triangular_wave_value = (2 ** TRIANGULAR_COUNTER_LENGHT) - 1 THEN + wave_direction_up <= '0'; -- Switch to descending phase + triangular_wave_value <= triangular_wave_value - 1; -- Start decreasing + ELSE + triangular_wave_value <= triangular_wave_value + 1; -- Continue increasing + END IF; + ELSE + -- Descending phase: check if we reached minimum amplitude + IF triangular_wave_value = 0 THEN + wave_direction_up <= '1'; -- Switch to ascending phase + triangular_wave_value <= triangular_wave_value + 1; -- Start increasing + ELSE + triangular_wave_value <= triangular_wave_value - 1; -- Continue decreasing + END IF; + END IF; + END IF; + ELSE + -- LFO_1 disabled: reset triangular wave generator to idle state + timing_counter <= 0; -- Clear timing counter + triangular_wave_value <= (OTHERS => '0'); -- Reset to zero amplitude + wave_direction_up <= '1'; -- Reset to ascending direction + END IF; + END IF; + END IF; + END PROCESS triangular_wave_generator; + + -- Pipeline stage 3: Audio modulation and output control + -- This stage applies the LFO_1 effect by multiplying audio samples with the triangular wave + modulation_and_output : PROCESS (aclk) + BEGIN + IF rising_edge(aclk) THEN + IF aresetn = '0' THEN + -- Reset output stage to safe initial state + m_axis_tdata <= (OTHERS => '0'); -- Clear output data + master_valid_internal <= '0'; -- No valid output + slave_ready_internal <= '1'; -- Ready to accept input + ELSE + -- Output flow control: handle backpressure from downstream modules + IF master_valid_internal = '1' AND m_axis_tready = '0' THEN + -- Downstream not ready: maintain current output valid state + -- This implements proper AXI4-Stream backpressure handling + master_valid_internal <= '1'; + ELSIF valid_flag_stage2 = '1' THEN + -- New data available from stage 2: apply LFO_1 effect or bypass + IF enable_flag_stage2 = '1' THEN + -- Apply LFO_1 tremolo effect: multiply audio sample by triangular wave + -- This creates amplitude modulation (tremolo effect) + multiplication_result <= STD_LOGIC_VECTOR( + resize( + signed(audio_data_stage2) * signed('0' & triangular_wave_value), + multiplication_result'length + ) + ); + -- Scale down result by removing lower bits (equivalent to division by 2^TRIANGULAR_COUNTER_LENGHT) + -- This maintains proper audio amplitude range after multiplication + m_axis_tdata <= multiplication_result(multiplication_result'high DOWNTO TRIANGULAR_COUNTER_LENGHT); + ELSE + -- LFO_1 disabled: pass audio through unchanged (bypass mode) + -- This allows seamless switching between effect and clean audio + m_axis_tdata <= audio_data_stage2; + END IF; + master_valid_internal <= '1'; -- Mark output as valid + ELSE + -- No new data available: clear output valid flag + master_valid_internal <= '0'; + END IF; + + -- AXI4-Stream ready signal management for proper flow control + IF master_valid_internal = '1' AND m_axis_tready = '1' THEN + -- Successful output handshake: ready for new input data + slave_ready_internal <= '1'; + ELSIF s_axis_tvalid = '1' AND slave_ready_internal = '1' THEN + -- Accepted new input: not ready until current output is consumed + -- This prevents data loss in the pipeline + slave_ready_internal <= '0'; + END IF; + END IF; + END IF; + END PROCESS modulation_and_output; + + -- Output signal assignments + s_axis_tready <= slave_ready_internal; -- Connect internal ready to output port + m_axis_tvalid <= master_valid_internal; -- Connect internal valid to output port + + -- LFO_1 Effect Summary: + -- 1. Stage 1: Calculates LFO_1 frequency based on joystick position + -- 2. Stage 2: Generates triangular wave at calculated frequency + -- 3. Stage 3: Multiplies audio samples by triangular wave (tremolo effect) + -- + -- Audio Effect Characteristics: + -- - Tremolo: Periodic amplitude modulation creates "shaking" sound + -- - Frequency range: Approximately 0.1Hz to 10Hz (typical for audio LFO_1) + -- - Modulation depth: Controlled by TRIANGULAR_COUNTER_LENGHT generic + -- - Bypass capability: Clean audio passthrough when disabled + -- + -- Pipeline Benefits: + -- - Maintains real-time audio processing with no dropouts + -- - Allows complex calculations without affecting audio timing + -- - Provides proper AXI4-Stream flow control and backpressure handling + +END ARCHITECTURE Behavioral; \ No newline at end of file diff --git a/LAB3/src/all_pass_filter.vhd b/LAB3/src/all_pass_filter.vhd index 6d9de3b..4a4a782 100644 --- a/LAB3/src/all_pass_filter.vhd +++ b/LAB3/src/all_pass_filter.vhd @@ -1,29 +1,123 @@ -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use ieee.numeric_std.all; +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE ieee.numeric_std.ALL; -entity all_pass_filter is - generic ( - TDATA_WIDTH : positive := 24 - ); - Port ( - aclk : in std_logic; - aresetn : in std_logic; +-- Entity: all_pass_filter +-- Purpose: A pass-through filter that maintains the same interface and timing +-- characteristics as the moving average filter but passes data unchanged. +ENTITY all_pass_filter IS + GENERIC ( + TDATA_WIDTH : POSITIVE := 24 -- Width of the data bus in bits + ); + PORT ( + -- Clock and reset signals + aclk : IN STD_LOGIC; -- Main clock input + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset - s_axis_tvalid : in std_logic; - s_axis_tdata : in std_logic_vector(TDATA_WIDTH-1 downto 0); - s_axis_tlast : in std_logic; - s_axis_tready : out std_logic; + -- AXI4-Stream Slave Interface (Input) + s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Input data + s_axis_tlast : IN STD_LOGIC; -- Input end-of-packet signal + s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data - m_axis_tvalid : out std_logic; - m_axis_tdata : out std_logic_vector(TDATA_WIDTH-1 downto 0); - m_axis_tlast : out std_logic; - m_axis_tready : in std_logic - ); -end all_pass_filter; + -- AXI4-Stream Master Interface (Output) + m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Output data + m_axis_tlast : OUT STD_LOGIC; -- Output end-of-packet signal + m_axis_tready : IN STD_LOGIC -- Downstream ready signal + ); +END all_pass_filter; -architecture Behavioral of all_pass_filter is +ARCHITECTURE Behavioral OF all_pass_filter IS -begin + -- Internal control signal to trigger data output after input processing + SIGNAL trigger : STD_LOGIC := '0'; -end Behavioral; + -- Internal slave interface signals + SIGNAL s_axis_tready_int : STD_LOGIC := '0'; -- Internal ready signal for input + SIGNAL s_axis_tlast_reg : STD_LOGIC := '0'; -- Registered version of input tlast + SIGNAL s_axis_tdata_reg : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); -- Temporary storage for input data + + -- Internal data storage and master interface signals + SIGNAL m_axis_tvalid_int : STD_LOGIC := '0'; -- Internal valid signal for output + +BEGIN + + -- Architecture Overview: + -- This design mimics the structure, handshake logic, and timing (clock cycles spent) + -- of the moving_average_filter, but does not process or modify the samples. + -- It simply passes input data to the output unchanged, ensuring the same latency and interface behavior. + + -- Data Flow: + -- 1. Input data is captured when s_axis_tvalid and s_axis_tready are both high + -- 2. Data is stored in temporary registers and a trigger is set + -- 3. On the next clock cycle, if output interface is ready, data is output + -- 4. This creates a 1-clock cycle latency matching the moving average filter + + -- Connect internal signals to output ports + m_axis_tvalid <= m_axis_tvalid_int; -- Drive output valid with internal signal + s_axis_tready <= s_axis_tready_int; -- Drive input ready with internal signal + + -- Main processing logic - synchronous to clock + PROCESS (aclk) + BEGIN + IF rising_edge(aclk) THEN + + -- Asynchronous reset logic (active low) + IF aresetn = '0' THEN + -- Reset all internal signals to known states + trigger <= '0'; -- Clear data processing trigger + s_axis_tlast_reg <= '0'; -- Clear registered tlast + s_axis_tready_int <= '0'; -- Not ready to accept data during reset + s_axis_tdata_reg <= (OTHERS => '0'); -- Clear temporary data storage + m_axis_tvalid_int <= '0'; -- No valid data on output during reset + m_axis_tlast <= '0'; -- Clear output tlast + + ELSE + -- Normal operation logic + + -- Output handshake management: + -- Clear the output valid flag when downstream is ready to accept data + -- This allows new data to be output on the next cycle + IF m_axis_tready = '1' THEN + m_axis_tvalid_int <= '0'; + END IF; + + -- Data output logic: + -- Output data when trigger is set AND output interface is available + -- (either no valid data pending OR downstream is ready) + IF trigger = '1' AND (m_axis_tvalid_int = '0' OR m_axis_tready = '1') THEN + -- Transfer stored data to output + m_axis_tdata <= s_axis_tdata_reg; -- Output the stored input data unchanged + m_axis_tlast <= s_axis_tlast_reg; -- Output the registered tlast signal + + -- Set output control signals + m_axis_tvalid_int <= '1'; -- Mark output data as valid + trigger <= '0'; -- Clear trigger - data has been output + END IF; + + -- Data input logic: + -- Capture input data when both valid and ready are asserted (AXI handshake) + IF s_axis_tvalid = '1' AND s_axis_tready_int = '1' THEN + -- Store input signals for later output + s_axis_tlast_reg <= s_axis_tlast; -- Register the tlast signal + s_axis_tdata_reg <= s_axis_tdata; -- Store input data (pass-through, no processing) + + -- Set trigger to indicate data is ready for output + trigger <= '1'; + END IF; + + -- Input ready logic: + -- Ready to accept new input when: + -- - Downstream is ready (can immediately pass data through), OR + -- - No valid data is pending on output (have buffer space) + -- This implements backpressure - if output is blocked, input will be blocked + s_axis_tready_int <= m_axis_tready OR NOT m_axis_tvalid_int; + + END IF; + + END IF; + + END PROCESS; + +END Behavioral; \ No newline at end of file diff --git a/LAB3/src/balance_controller.vhd b/LAB3/src/balance_controller.vhd index 1d5f90c..9abd755 100644 --- a/LAB3/src/balance_controller.vhd +++ b/LAB3/src/balance_controller.vhd @@ -1,33 +1,147 @@ -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use ieee.numeric_std.all; +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE ieee.numeric_std.ALL; -entity balance_controller is - generic ( - TDATA_WIDTH : positive := 24; - BALANCE_WIDTH : positive := 10; - BALANCE_STEP_2 : positive := 6 -- i.e., balance_values_per_step = 2**VOLUME_STEP_2 - ); - Port ( - aclk : in std_logic; - aresetn : in std_logic; +-- Entity: balance_controller +-- Purpose: Controls the stereo balance (left/right channel volume) of audio data +-- based on a balance control input. Implements variable attenuation +-- using bit shifting for efficient hardware implementation. +ENTITY balance_controller IS + GENERIC ( + TDATA_WIDTH : POSITIVE := 24; -- Width of audio data bus (24-bit audio samples) + BALANCE_WIDTH : POSITIVE := 10; -- Width of balance control input (10-bit = 0-1023 range) + BALANCE_STEP_2 : POSITIVE := 6 -- Log2 of balance values per step (2^6 = 64 values per step) + ); + PORT ( + -- Clock and reset + aclk : IN STD_LOGIC; -- Main clock + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset - s_axis_tvalid : in std_logic; - s_axis_tdata : in std_logic_vector(TDATA_WIDTH-1 downto 0); - s_axis_tready : out std_logic; - s_axis_tlast : in std_logic; + -- AXI4-Stream Slave Interface (Audio Input) + s_axis_tvalid : IN STD_LOGIC; -- Input data valid + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample data + s_axis_tready : OUT STD_LOGIC; -- Ready to accept input + s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) - m_axis_tvalid : out std_logic; - m_axis_tdata : out std_logic_vector(TDATA_WIDTH-1 downto 0); - m_axis_tready : in std_logic; - m_axis_tlast : out std_logic; + -- AXI4-Stream Master Interface (Audio Output) + m_axis_tvalid : OUT STD_LOGIC; -- Output data valid + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Balanced audio sample + m_axis_tready : IN STD_LOGIC; -- Downstream ready + m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough - balance : in std_logic_vector(BALANCE_WIDTH-1 downto 0) - ); -end balance_controller; + -- Balance Control Input + balance : IN STD_LOGIC_VECTOR(BALANCE_WIDTH - 1 DOWNTO 0) -- Balance position (0=full left, 1023=full right, 512=center) + ); +END balance_controller; -architecture Behavioral of balance_controller is +ARCHITECTURE Behavioral OF balance_controller IS -begin + -- Balance calculation constants + CONSTANT BALANCE_STEPS : INTEGER := (2 ** (BALANCE_WIDTH - 1)) / (2 ** BALANCE_STEP_2) + 1; -- Number of attenuation steps (9 steps for 10-bit balance) + CONSTANT BAL_MID : INTEGER := 2 ** (BALANCE_WIDTH - 1); -- Center balance position (512 for 10-bit) + CONSTANT DEAD_ZONE : INTEGER := (2 ** BALANCE_STEP_2) / 2; -- Dead zone around center (32 for step size 64) -end Behavioral; + -- Channel attenuation levels (number of bit shifts for volume reduction) + SIGNAL left_channel : INTEGER RANGE 0 TO BALANCE_STEPS := 0; -- Left channel attenuation (0 = no attenuation, higher = more attenuation) + SIGNAL right_channel : INTEGER RANGE 0 TO BALANCE_STEPS := 0; -- Right channel attenuation (0 = no attenuation, higher = more attenuation) + + -- Internal AXI signals + SIGNAL m_axis_tvalid_int : STD_LOGIC; -- Internal valid signal for output + +BEGIN + -- Connect internal signals to output ports + m_axis_tvalid <= m_axis_tvalid_int; + -- Input ready logic: Ready when downstream is ready OR no valid data pending, AND not in reset + s_axis_tready <= (m_axis_tready OR NOT m_axis_tvalid_int) AND aresetn; + + -- Balance calculation process + -- Converts joystick x-axis position to attenuation levels for each channel + BALANCE_CALC : PROCESS (aclk) + BEGIN + + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset: No attenuation on either channel + left_channel <= 0; + right_channel <= 0; + + ELSE + -- Balance Mapping: + -- balance = 0-479: Left (right channel attenuated) + -- balance = 480-543: Center with dead zone (no attenuation) + -- balance = 544-1023: Right (left channel attenuated) + + -- Right-leaning balance: Attenuate left channel + IF to_integer(unsigned(balance)) > (BAL_MID + DEAD_ZONE) THEN + -- Calculate left channel attenuation based on how far right of center + -- Subtract center+deadzone, divide by step size, add 1 for rounding + left_channel <= to_integer((unsigned(balance) - to_unsigned(BAL_MID + DEAD_ZONE, balance'length)) SRL BALANCE_STEP_2) + 1; + ELSE + -- Balance not significantly right of center: no left attenuation + left_channel <= 0; + END IF; + + -- Left-leaning balance: Attenuate right channel + IF to_integer(unsigned(balance)) < (BAL_MID - DEAD_ZONE) THEN + -- Calculate right channel attenuation based on how far left of center + -- Subtract balance from center-deadzone, divide by step size, add 1 for rounding + right_channel <= to_integer((to_unsigned(BAL_MID - DEAD_ZONE, balance'length) - unsigned(balance)) SRL BALANCE_STEP_2) + 1; + ELSE + -- Balance not significantly left of center: no right attenuation + right_channel <= 0; + END IF; + + END IF; + + END IF; + + END PROCESS BALANCE_CALC; + + -- AXI4-Stream data processing + -- Applies calculated attenuation to audio samples based on channel + AXIS : PROCESS (aclk) + BEGIN + + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset output interface + m_axis_tvalid_int <= '0'; -- No valid output data + m_axis_tlast <= '0'; -- Clear channel indicator + + ELSE + -- Output handshake: Clear valid flag when downstream accepts data + IF m_axis_tready = '1' THEN + m_axis_tvalid_int <= '0'; + END IF; + + -- Data processing: Apply balance when input and output are ready + IF s_axis_tvalid = '1' AND m_axis_tready = '1' THEN + -- Channel identification based on tlast signal: + -- tlast = '0': Left channel sample + -- tlast = '1': Right channel sample + + IF s_axis_tlast = '0' THEN + -- Left channel: Apply left channel attenuation + -- Arithmetic right shift preserves sign for signed audio data + m_axis_tdata <= STD_LOGIC_VECTOR(shift_right(signed(s_axis_tdata), left_channel)); + ELSE + -- Right channel: Apply right channel attenuation + -- Arithmetic right shift preserves sign for signed audio data + m_axis_tdata <= STD_LOGIC_VECTOR(shift_right(signed(s_axis_tdata), right_channel)); + END IF; + + -- Set output control signals + m_axis_tvalid_int <= '1'; -- Mark output as valid + m_axis_tlast <= s_axis_tlast; -- Pass through channel indicator + + END IF; + + END IF; + + END IF; + + END PROCESS AXIS; + +END Behavioral; \ No newline at end of file diff --git a/LAB3/src/digilent_jstk2.vhd b/LAB3/src/digilent_jstk2.vhd index 9194ef3..1872503 100644 --- a/LAB3/src/digilent_jstk2.vhd +++ b/LAB3/src/digilent_jstk2.vhd @@ -1,49 +1,199 @@ -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; -entity digilent_jstk2 is - generic ( - DELAY_US : integer := 25; -- Delay (in us) between two packets - CLKFREQ : integer := 100_000_000; -- Frequency of the aclk signal (in Hz) - SPI_SCLKFREQ : integer := 66_666 -- Frequency of the SPI SCLK clock signal (in Hz) - ); - Port ( - aclk : in STD_LOGIC; - aresetn : in STD_LOGIC; +-- Entity: digilent_jstk2 +-- Purpose: Interface controller for the Digilent JSTK2 joystick module via SPI +-- Sends LED color commands and receives joystick/button data +ENTITY digilent_jstk2 IS + GENERIC ( + DELAY_US : INTEGER := 25; -- Delay (in microseconds) between two SPI packets + CLKFREQ : INTEGER := 100_000_000; -- Frequency of the aclk signal (in Hz) + SPI_SCLKFREQ : INTEGER := 5_000 -- Frequency of the SPI SCLK clock signal (in Hz) + ); + PORT ( + aclk : IN STD_LOGIC; -- Main clock input + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset - -- Data going TO the SPI IP-Core (and so, to the JSTK2 module) - m_axis_tvalid : out STD_LOGIC; - m_axis_tdata : out STD_LOGIC_VECTOR(7 downto 0); - m_axis_tready : in STD_LOGIC; + -- AXI4-Stream Master Interface: Data going TO the SPI IP-Core (and so, to the JSTK2 module) + m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal + m_axis_tdata : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); -- 8-bit data to send via SPI + m_axis_tready : IN STD_LOGIC; -- SPI IP-Core ready to accept data - -- Data coming FROM the SPI IP-Core (and so, from the JSTK2 module) - -- There is no tready signal, so you must be always ready to accept and use the incoming data, or it will be lost! - s_axis_tvalid : in STD_LOGIC; - s_axis_tdata : in STD_LOGIC_VECTOR(7 downto 0); + -- AXI4-Stream Slave Interface: Data coming FROM the SPI IP-Core (and so, from the JSTK2 module) + -- Note: There is no tready signal, so you must be always ready to accept incoming data, or it will be lost! + s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal + s_axis_tdata : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- 8-bit data received via SPI - -- Joystick and button values read from the module - jstk_x : out std_logic_vector(9 downto 0); - jstk_y : out std_logic_vector(9 downto 0); - btn_jstk : out std_logic; - btn_trigger : out std_logic; + -- Joystick and button values read from the JSTK2 module + jstk_x : OUT STD_LOGIC_VECTOR(9 DOWNTO 0); -- X-axis joystick position (10-bit, 0-1023) + jstk_y : OUT STD_LOGIC_VECTOR(9 DOWNTO 0); -- Y-axis joystick position (10-bit, 0-1023) + btn_jstk : OUT STD_LOGIC; -- Joystick button state (1=pressed) + btn_trigger : OUT STD_LOGIC; -- Trigger button state (1=pressed) - -- LED color to send to the module - led_r : in std_logic_vector(7 downto 0); - led_g : in std_logic_vector(7 downto 0); - led_b : in std_logic_vector(7 downto 0) - ); -end digilent_jstk2; + -- LED color values to send to the JSTK2 module + led_r : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- Red LED intensity (0-255) + led_g : IN STD_LOGIC_VECTOR(7 DOWNTO 0); -- Green LED intensity (0-255) + led_b : IN STD_LOGIC_VECTOR(7 DOWNTO 0) -- Blue LED intensity (0-255) + ); +END digilent_jstk2; -architecture Behavioral of digilent_jstk2 is +ARCHITECTURE Behavioral OF digilent_jstk2 IS - -- Code for the SetLEDRGB command, see the JSTK2 datasheet. - constant CMDSETLEDRGB : std_logic_vector(7 downto 0) := x"84"; + -- Command code for the SetLEDRGB command, see the JSTK2 datasheet + CONSTANT CMDSETLEDRGB : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"84"; - -- Do not forget that you MUST wait a bit between two packets. See the JSTK2 datasheet (and the SPI IP-Core README). - ------------------------------------------------------------ + -- Calculate delay in clock cycles: (delay_period + 1_SPI_clock_period) * clock_frequency + -- This ensures proper timing between SPI packets as required by JSTK2 datasheet + CONSTANT DELAY_CLK_CYCLES : INTEGER := (DELAY_US + 1_000_000 / SPI_SCLKFREQ) * (CLKFREQ / 1_000_000) - 1; -begin + -- State machine type definitions + TYPE tx_state_type IS (DELAY, SEND_CMD, SEND_RED, SEND_GREEN, SEND_BLUE, SEND_DUMMY); + TYPE rx_state_type IS (JSTK_X_LOW, JSTK_X_HIGH, JSTK_Y_LOW, JSTK_Y_HIGH, BUTTONS); - -- ... + -- State machine signals + SIGNAL tx_state : tx_state_type := DELAY; -- Transmit state machine current state + SIGNAL rx_state : rx_state_type := JSTK_X_LOW; -- Receive state machine current state -end architecture; + -- Timing and data storage signals + SIGNAL tx_delay_counter : INTEGER RANGE 0 TO DELAY_CLK_CYCLES := 0; -- Counter for inter-packet delay timing + SIGNAL rx_cache : STD_LOGIC_VECTOR(s_axis_tdata'range); -- Temporary storage for multi-byte data reception + +BEGIN + + -- Output valid signal control: Set to '1' when we want to send data to SPI IP-Core + -- Only inactive during DELAY state when waiting between packets + WITH tx_state SELECT m_axis_tvalid <= + '0' WHEN DELAY, -- No transmission during delay + '1' WHEN SEND_CMD, -- Send command byte + '1' WHEN SEND_RED, -- Send red LED value + '1' WHEN SEND_GREEN, -- Send green LED value + '1' WHEN SEND_BLUE, -- Send blue LED value + '1' WHEN SEND_DUMMY; -- Send dummy byte to complete transaction + + -- Output data multiplexer: Select what data to send based on current TX state + WITH tx_state SELECT m_axis_tdata <= + (OTHERS => '0') WHEN DELAY, -- No data during delay + CMDSETLEDRGB WHEN SEND_CMD, -- SetLEDRGB command (0x84) + led_r WHEN SEND_RED, -- Red LED intensity value + led_g WHEN SEND_GREEN, -- Green LED intensity value + led_b WHEN SEND_BLUE, -- Blue LED intensity value + "01101001" WHEN SEND_DUMMY; -- Dummy byte to complete 5-byte transaction + + -- TX State Machine: Sends LED color commands to JSTK2 module + -- Protocol: Command(1) + Red(1) + Green(1) + Blue(1) + Dummy(1) = 5 bytes total > Delay before next command + -- The delay is required by the JSTK datasheet to ensure proper timing between SPI transactions + TX : PROCESS (aclk) + BEGIN + IF rising_edge(aclk) THEN + IF aresetn = '0' THEN + -- Reset: Start in delay state with counter cleared + tx_state <= DELAY; + tx_delay_counter <= 0; + + ELSE + + CASE tx_state IS + + WHEN DELAY => + -- Wait for required delay period between SPI transactions + IF tx_delay_counter = DELAY_CLK_CYCLES THEN + tx_delay_counter <= 0; -- Reset counter + tx_state <= SEND_CMD; -- Start new transmission + ELSE + tx_delay_counter <= tx_delay_counter + 1; -- Continue counting + END IF; + + WHEN SEND_CMD => + -- Send SetLEDRGB command byte + IF m_axis_tready = '1' THEN + tx_state <= SEND_RED; -- Move to red LED transmission + END IF; + + WHEN SEND_RED => + -- Send red LED intensity value + IF m_axis_tready = '1' THEN + tx_state <= SEND_GREEN; -- Move to green LED transmission + END IF; + + WHEN SEND_GREEN => + -- Send green LED intensity value + IF m_axis_tready = '1' THEN + tx_state <= SEND_BLUE; -- Move to blue LED transmission + END IF; + + WHEN SEND_BLUE => + -- Send blue LED intensity value + IF m_axis_tready = '1' THEN + tx_state <= SEND_DUMMY; -- Move to dummy byte transmission + END IF; + + WHEN SEND_DUMMY => + -- Send dummy byte to complete 5-byte transaction + IF m_axis_tready = '1' THEN + tx_state <= DELAY; -- Return to delay state + END IF; + + END CASE; + END IF; + END IF; + END PROCESS TX; + + -- RX State Machine: Receives 5 bytes of response data and updates outputs + -- Protocol: X_low(1) + X_high(1) + Y_low(1) + Y_high(1) + Buttons(1) = 5 bytes total + RX : PROCESS (aclk) + BEGIN + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset: Start waiting for X-axis low byte + rx_state <= JSTK_X_LOW; + rx_cache <= (OTHERS => '0'); + + ELSE + + CASE rx_state IS + + WHEN JSTK_X_LOW => + -- Receive X-axis low byte (bits 7:0) + IF s_axis_tvalid = '1' THEN + rx_cache <= s_axis_tdata; -- Store low byte temporarily + rx_state <= JSTK_X_HIGH; -- Wait for high byte + END IF; + + WHEN JSTK_X_HIGH => + -- Receive X-axis high byte (bits 9:8) and assemble complete X value + IF s_axis_tvalid = '1' THEN + -- Combine: high_byte(1:0) & low_byte(7:0) = 10-bit X position + jstk_x <= s_axis_tdata(1 DOWNTO 0) & rx_cache; + rx_state <= JSTK_Y_LOW; -- Move to Y-axis reception + END IF; + + WHEN JSTK_Y_LOW => + -- Receive Y-axis low byte (bits 7:0) + IF s_axis_tvalid = '1' THEN + rx_cache <= s_axis_tdata; -- Store low byte temporarily + rx_state <= JSTK_Y_HIGH; -- Wait for high byte + END IF; + + WHEN JSTK_Y_HIGH => + -- Receive Y-axis high byte (bits 9:8) and assemble complete Y value + IF s_axis_tvalid = '1' THEN + -- Combine: high_byte(1:0) & low_byte(7:0) = 10-bit Y position + jstk_y <= s_axis_tdata(1 DOWNTO 0) & rx_cache; + rx_state <= BUTTONS; -- Move to button reception + END IF; + + WHEN BUTTONS => + -- Receive button states byte + IF s_axis_tvalid = '1' THEN + btn_jstk <= s_axis_tdata(0); -- Joystick button (bit 0) + btn_trigger <= s_axis_tdata(1); -- Trigger button (bit 1) + rx_state <= JSTK_X_LOW; -- Return to start for next packet + END IF; + + END CASE; + END IF; + END IF; + END PROCESS RX; + +END ARCHITECTURE; \ No newline at end of file diff --git a/LAB3/src/edge_detector_toggle.vhd b/LAB3/src/edge_detector_toggle.vhd index 061c3fa..441a64a 100644 --- a/LAB3/src/edge_detector_toggle.vhd +++ b/LAB3/src/edge_detector_toggle.vhd @@ -15,6 +15,39 @@ end edge_detector_toggle; architecture Behavioral of edge_detector_toggle is + signal output_signal_int : std_logic; + signal input_signal_old : std_logic; + begin + -- We will have to read output_signal, but it's an output port, so we have to + -- define a new signal and connect it directly with the output port. + -- In this way signal and output port have the exact same value without delays, + -- but the signal can be read. + output_signal <= output_signal_int; + + process(clk) + begin + if rising_edge(clk) then + + if reset = '1' then + output_signal_int <= '0'; + input_signal_old <= '0'; + else + + -- Sample the old input_signal + -- In this way, at each clock cycle, we have the current value and the previous one. + input_signal_old <= input_signal; + + -- Toggle output_signal if we see a 0 --> 1 transition (or 1 --> 0 for the falling edge case). + if (EDGE_RISING = true and input_signal_old = '0' and input_signal = '1') or + (EDGE_RISING = false and input_signal_old = '1' and input_signal = '0') then + output_signal_int <= not output_signal_int; + end if; + + end if; + + end if; + end process; + end Behavioral; diff --git a/LAB3/src/effect_selector.vhd b/LAB3/src/effect_selector.vhd index f8b1184..fee2456 100644 --- a/LAB3/src/effect_selector.vhd +++ b/LAB3/src/effect_selector.vhd @@ -1,54 +1,82 @@ ----------------------------------------------------------------------------------- --- Company: --- Engineer: --- --- Create Date: 04/29/2024 10:12:03 AM --- Design Name: --- Module Name: effect_selector - 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; +USE IEEE.NUMERIC_STD.ALL; - -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 effect_selector is - generic( - JOYSTICK_LENGHT : integer := 10 +-- Entity: effect_selector +-- Purpose: Routes joystick input to different audio control parameters based on effect mode +-- Acts as a multiplexer/router for joystick control signals +ENTITY effect_selector IS + GENERIC ( + JOYSTICK_LENGHT : INTEGER := 10 -- Width of joystick position data (10-bit = 0-1023 range) ); - Port ( - aclk : in STD_LOGIC; - aresetn : in STD_LOGIC; - effect : in STD_LOGIC; - jstck_x : in STD_LOGIC_VECTOR(JOYSTICK_LENGHT-1 downto 0); - jstck_y : in STD_LOGIC_VECTOR(JOYSTICK_LENGHT-1 downto 0); - volume : out STD_LOGIC_VECTOR(JOYSTICK_LENGHT-1 downto 0); - balance : out STD_LOGIC_VECTOR(JOYSTICK_LENGHT-1 downto 0); - lfo_period : out STD_LOGIC_VECTOR(JOYSTICK_LENGHT-1 downto 0) + PORT ( + -- Clock and reset signals + aclk : IN STD_LOGIC; -- Main clock input + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset + + -- Control and input signals + effect : IN STD_LOGIC; -- Effect mode selector (0=volume/balance mode, 1=LFO) + jstck_x : IN STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0); -- X-axis joystick position + jstck_y : IN STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0); -- Y-axis joystick position + + -- Output control parameters + volume : OUT STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0); -- Volume control output + balance : OUT STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0); -- Balance control output + lfo_period : OUT STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0) -- LFO period control output ); -end effect_selector; +END effect_selector; -architecture Behavioral of effect_selector is +ARCHITECTURE Behavioral OF effect_selector IS -begin + constant JOYSTICK_DEFAULT : STD_LOGIC_VECTOR(JOYSTICK_LENGHT - 1 DOWNTO 0) := STD_LOGIC_VECTOR(to_unsigned(2 ** (JOYSTICK_LENGHT - 1), JOYSTICK_LENGHT)); -- Default joystick value (center position for 10-bit joystick is 512) + +BEGIN -end Behavioral; + -- Main control logic process + -- Routes joystick axes to appropriate audio control parameters based on selected mode + PROCESS (aclk) + BEGIN + + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset all outputs to default/center values + volume <= JOYSTICK_DEFAULT; -- Default volume (center position) + balance <= JOYSTICK_DEFAULT; -- Center balance position + lfo_period <= JOYSTICK_DEFAULT; -- Default LFO period (center position) + + ELSE + -- Normal operation: Route joystick inputs based on effect mode + + -- Y-axis always controls different parameters based on effect mode + -- X-axis behavior differs between modes + -- Note: When switching between modes, some outputs are reset while others preserved + IF effect = '1' THEN + -- LFO Mode: + -- Y-axis controls Low Frequency Oscillator period + -- X-axis is ignored in this mode + lfo_period <= jstck_y; + + -- Volume remains at last set value (preserved from previous mode) + + -- Reset balance to center/default position when in LFO mode + balance <= JOYSTICK_DEFAULT; -- Reset balance to center position + + ELSE + -- Volume/Balance Mode: + -- Y-axis controls overall volume level + -- X-axis controls left/right audio balance + volume <= jstck_y; + balance <= jstck_x; + + -- LFO period remains at last set value (preserved from previous LFO mode) + + END IF; + + END IF; + + END IF; + + END PROCESS; + +END Behavioral; \ No newline at end of file diff --git a/LAB3/src/led_controller.vhd b/LAB3/src/led_controller.vhd index 023a503..8c7e198 100644 --- a/LAB3/src/led_controller.vhd +++ b/LAB3/src/led_controller.vhd @@ -1,22 +1,64 @@ -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; -entity led_controller is - Generic ( - LED_WIDTH : positive := 8 - ); - Port ( - mute_enable : in std_logic; - filter_enable : in std_logic; +-- Entity: led_controller +-- Purpose: Controls RGB LED indicators based on audio system status +-- Provides visual feedback for mute and filter enable states +ENTITY led_controller IS + GENERIC ( + LED_WIDTH : POSITIVE := 8 -- Width of LED intensity control (8-bit = 0-255 intensity levels) + ); + PORT ( + -- Control input signals + mute_enable : IN STD_LOGIC; -- Mute status (1=audio muted, 0=audio active) + filter_enable : IN STD_LOGIC; -- Filter status (1=filter active, 0=filter bypassed) - led_r : out std_logic_vector(LED_WIDTH-1 downto 0); - led_g : out std_logic_vector(LED_WIDTH-1 downto 0); - led_b : out std_logic_vector(LED_WIDTH-1 downto 0) - ); -end led_controller; + -- RGB LED output signals (intensity control) + led_r : OUT STD_LOGIC_VECTOR(LED_WIDTH - 1 DOWNTO 0); -- Red LED intensity (0-255) + led_g : OUT STD_LOGIC_VECTOR(LED_WIDTH - 1 DOWNTO 0); -- Green LED intensity (0-255) + led_b : OUT STD_LOGIC_VECTOR(LED_WIDTH - 1 DOWNTO 0) -- Blue LED intensity (0-255) + ); +END led_controller; -architecture Behavioral of led_controller is +ARCHITECTURE Behavioral OF led_controller IS -begin + -- Constants for LED intensity levels + CONSTANT ALL_ON : STD_LOGIC_VECTOR(LED_WIDTH - 1 DOWNTO 0) := (OTHERS => '1'); -- Maximum brightness (255) + CONSTANT ALL_OFF : STD_LOGIC_VECTOR(LED_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); -- LED off (0) -end Behavioral; +BEGIN + + -- LED Status Indication Logic: + -- Priority-based color coding for system status + -- + -- Color Scheme: + -- RED = Mute active (highest priority - audio completely off) + -- BLUE = Filter active (medium priority - audio processing enabled) + -- GREEN = Normal operation (lowest priority - audio pass-through) + + -- Red LED Control: Indicates mute status + -- Turn on red LED when audio is muted, regardless of filter state + led_r <= ALL_ON WHEN mute_enable = '1' ELSE + ALL_OFF; + + -- Blue LED Control: Indicates filter activation + -- Turn on blue LED when filter is active AND audio is not muted + -- Mute has higher priority than filter indication + led_b <= ALL_ON WHEN (mute_enable = '0' AND filter_enable = '1') ELSE + ALL_OFF; + + -- Green LED Control: Indicates normal operation + -- Turn on green LED when audio is active (not muted) AND filter is disabled + -- This represents the default "audio pass-through" state + led_g <= ALL_ON WHEN (mute_enable = '0' AND filter_enable = '0') ELSE + ALL_OFF; + + -- Truth Table for LED States: + -- mute_enable | filter_enable | RED | GREEN | BLUE | Status + -- ------------|---------------|-----|-------|------|------------------ + -- 0 | 0 | 0 | 1 | 0 | Normal (Green) + -- 0 | 1 | 0 | 0 | 1 | Filter On (Blue) + -- 1 | 0 | 1 | 0 | 0 | Muted (Red) + -- 1 | 1 | 1 | 0 | 0 | Muted (Red) + +END Behavioral; \ No newline at end of file diff --git a/LAB3/src/led_level_controller.vhd b/LAB3/src/led_level_controller.vhd index 01f2cf0..4627985 100644 --- a/LAB3/src/led_level_controller.vhd +++ b/LAB3/src/led_level_controller.vhd @@ -1,60 +1,165 @@ ----------------------------------------------------------------------------------- --- Company: --- Engineer: --- --- Create Date: 22.05.2021 15:42:35 --- Design Name: --- Module Name: led_level_controller - 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; +USE IEEE.NUMERIC_STD.ALL; +USE IEEE.MATH_REAL.ALL; - -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 led_level_controller is - generic( - NUM_LEDS : positive := 16; - CHANNEL_LENGHT : positive := 24; - refresh_time_ms: positive :=1; - clock_period_ns: positive :=10 +-- Entity: led_level_controller +-- Purpose: Audio level meter using LEDs to display real-time audio amplitude +-- Processes stereo audio samples and drives a bar graph LED display +ENTITY led_level_controller IS + GENERIC ( + NUM_LEDS : POSITIVE := 16; -- Number of LEDs in the level meter display + CHANNEL_LENGHT : POSITIVE := 24; -- Width of audio data (24-bit audio samples) + refresh_time_ms : POSITIVE := 1; -- LED refresh rate in milliseconds (1ms = 1kHz update rate) + clock_period_ns : POSITIVE := 10 -- System clock period in nanoseconds (10ns = 100MHz) ); - Port ( - - aclk : in std_logic; - aresetn : in std_logic; - - led : out std_logic_vector(NUM_LEDS-1 downto 0); + PORT ( + -- Clock and reset signals + aclk : IN STD_LOGIC; -- Main clock input + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset - s_axis_tvalid : in std_logic; - s_axis_tdata : in std_logic_vector(CHANNEL_LENGHT-1 downto 0); - s_axis_tlast : in std_logic; - s_axis_tready : out std_logic + -- LED output array (bar graph display) + led : OUT STD_LOGIC_VECTOR(NUM_LEDS - 1 DOWNTO 0); -- LED control signals (1=on, 0=off) + -- AXI4-Stream Slave Interface (Audio Input) + s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal + s_axis_tdata : IN STD_LOGIC_VECTOR(CHANNEL_LENGHT - 1 DOWNTO 0); -- Audio sample input + s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=right, 1=left) + s_axis_tready : OUT STD_LOGIC -- Always ready to accept data ); -end led_level_controller; +END led_level_controller; -architecture Behavioral of led_level_controller is +ARCHITECTURE Behavioral OF led_level_controller IS -begin + -- Calculate clock cycles needed for LED refresh timing + CONSTANT REFRESH_CYCLES : INTEGER := (refresh_time_ms * 1_000_000) / clock_period_ns - 1; -end Behavioral; + -- Calculate the number of bits needed to represent the number of LEDs + CONSTANT NUMLEDS_BITS : INTEGER := INTEGER(ceil(log2(real(NUM_LEDS)))); + + -- LED refresh timing control signals + SIGNAL refresh_counter : INTEGER RANGE 0 TO REFRESH_CYCLES := 0; -- Counts clock cycles between LED updates + SIGNAL refresh_tick : STD_LOGIC := '0'; -- Pulse signal generated every refresh period + + -- Audio amplitude storage for both stereo channels + -- Stores absolute values (magnitude) of left and right audio channels + SIGNAL abs_l : UNSIGNED(CHANNEL_LENGHT - 1 DOWNTO 0) := (OTHERS => '0'); -- Absolute left channel amplitude registers + SIGNAL combined_amp : UNSIGNED(CHANNEL_LENGHT - 1 DOWNTO 0) := (OTHERS => '0'); -- Combined amplitude for LED level calculation + +BEGIN + + -- Always ready for AXI4-Stream input + s_axis_tready <= '1'; + + -- Capture absolute value of input sample for left/right channel + PROCESS (aclk) + BEGIN + + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset: Clear both channel amplitude registers + abs_l <= (OTHERS => '0'); + combined_amp <= (OTHERS => '0'); + + ELSIF s_axis_tvalid = '1' THEN + -- Valid audio data received: Process the sample + + -- Channel routing based on AXI4-Stream tlast signal + -- tlast = '1' indicates right channel, tlast = '0' indicates left channel + IF s_axis_tlast = '1' THEN + -- Right channel: Combine left and right channel amplitudes + -- RESIZE ensures the sum fits within the variable's bit width. + -- There isn't data loss since both abs_l and abs(s_axis_tdata) are one bit shorter than combined_amp, + -- due to the absolute value operation. + combined_amp <= RESIZE(abs_l + UNSIGNED(ABS(SIGNED(s_axis_tdata))), combined_amp'LENGTH); + + ELSE + -- Left channel: Store absolute value of audio sample + abs_l <= UNSIGNED(ABS(SIGNED(s_axis_tdata))); + + END IF; + + END IF; + + END IF; + + END PROCESS; + + -- LED refresh tick generator + PROCESS (aclk) + BEGIN + + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset: Initialize counter and tick signal + refresh_counter <= 0; + refresh_tick <= '0'; + + ELSE + IF refresh_counter = REFRESH_CYCLES THEN + refresh_counter <= 0; + refresh_tick <= '1'; + + ELSE + refresh_counter <= refresh_counter + 1; + refresh_tick <= '0'; + + END IF; + + END IF; + + END IF; + + END PROCESS; + + -- LED level calculation and bar graph generation process + -- Combines left and right channel amplitudes and converts to LED display pattern + -- Updates only when refresh_tick is active to maintain stable visual display + PROCESS (aclk) + + VARIABLE led_level : INTEGER RANGE 0 TO 2 ** NUMLEDS_BITS := 0; + + BEGIN + + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset: Turn off all LEDs and reset level counter + led <= (OTHERS => '0'); + + ELSIF refresh_tick = '1' THEN + -- LED update cycle: Calculate new LED pattern based on audio amplitude + + -- Linear scale to LED level conversion to get the best visual effect + IF combined_amp = 0 THEN + led_level := 0; -- No audio signal, turn off all LEDs + + ELSE + led_level := 1 + to_integer(shift_right(combined_amp, CHANNEL_LENGHT - NUMLEDS_BITS)); + + END IF; + + -- Saturation protection: Limit LED level to maximum available LEDs + -- Prevents overflow and ensures the LED index stays within bounds. + IF led_level > NUM_LEDS THEN + led_level := NUM_LEDS; + + END IF; + + -- Update LED output based on calculated level + led <= (OTHERS => '0'); + + IF led_level > 0 THEN + led(led_level - 1 DOWNTO 0) <= (OTHERS => '1'); + + END IF; + + END IF; + + END IF; + + END PROCESS; + +END Behavioral; \ No newline at end of file diff --git a/LAB3/src/moving_average_filter.vhd b/LAB3/src/moving_average_filter.vhd index 73dd17b..bd307a6 100644 --- a/LAB3/src/moving_average_filter.vhd +++ b/LAB3/src/moving_average_filter.vhd @@ -1,32 +1,200 @@ -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use ieee.numeric_std.all; +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE ieee.numeric_std.ALL; -entity moving_average_filter is - generic ( - -- Filter order expressed as 2^(FILTER_ORDER_POWER) - FILTER_ORDER_POWER : integer := 5; +-- Entity: moving_average_filter +-- Purpose: Implements a moving average filter for audio data +-- Maintains separate circular buffers for left and right audio channels +-- Filter order is configurable as 2^(FILTER_ORDER_POWER) samples +ENTITY moving_average_filter IS + GENERIC ( + -- Filter order expressed as 2^(FILTER_ORDER_POWER) + -- Example: FILTER_ORDER_POWER = 5 means 32-sample moving average + FILTER_ORDER_POWER : INTEGER := 5; - TDATA_WIDTH : positive := 24 - ); - Port ( - aclk : in std_logic; - aresetn : in std_logic; + TDATA_WIDTH : POSITIVE := 24 -- Width of audio data bus (24-bit audio samples) + ); + PORT ( + -- Clock and reset signals + aclk : IN STD_LOGIC; -- Main clock input + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset - s_axis_tvalid : in std_logic; - s_axis_tdata : in std_logic_vector(TDATA_WIDTH-1 downto 0); - s_axis_tlast : in std_logic; - s_axis_tready : out std_logic; + -- AXI4-Stream Slave Interface (Audio Input) + s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample input + s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) + s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data - m_axis_tvalid : out std_logic; - m_axis_tdata : out std_logic_vector(TDATA_WIDTH-1 downto 0); - m_axis_tlast : out std_logic; - m_axis_tready : in std_logic - ); -end moving_average_filter; + -- AXI4-Stream Master Interface (Audio Output) + m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Filtered audio sample output + m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough + m_axis_tready : IN STD_LOGIC -- Downstream ready signal + ); +END moving_average_filter; -architecture Behavioral of moving_average_filter is +ARCHITECTURE Behavioral OF moving_average_filter IS -begin + -- Calculate actual filter order from power-of-2 representation + CONSTANT FILTER_ORDER : INTEGER := 2 ** FILTER_ORDER_POWER; -end Behavioral; + -- Array type for storing audio samples in circular buffers + TYPE sample_array IS ARRAY (0 TO FILTER_ORDER - 1) OF signed(TDATA_WIDTH - 1 DOWNTO 0); + + -- Right channel (RX) processing signals + SIGNAL samples_rx : sample_array := (OTHERS => (OTHERS => '0')); -- Circular buffer for right channel samples + SIGNAL sum_rx : signed(TDATA_WIDTH + FILTER_ORDER_POWER - 1 DOWNTO 0) := (OTHERS => '0'); -- Running sum of right channel samples + SIGNAL wr_ptr_rx : INTEGER RANGE 0 TO FILTER_ORDER - 1 := 0; -- Write pointer for right channel buffer + + -- Left channel (LX) processing signals + SIGNAL samples_lx : sample_array := (OTHERS => (OTHERS => '0')); -- Circular buffer for left channel samples + SIGNAL sum_lx : signed(TDATA_WIDTH + FILTER_ORDER_POWER - 1 DOWNTO 0) := (OTHERS => '0'); -- Running sum of left channel samples + SIGNAL wr_ptr_lx : INTEGER RANGE 0 TO FILTER_ORDER - 1 := 0; -- Write pointer for left channel buffer + + -- Control and interface signals + SIGNAL trigger : STD_LOGIC := '0'; -- Trigger signal to indicate when to output filtered data + SIGNAL s_axis_tready_int : STD_LOGIC := '0'; -- Internal ready signal for input interface + SIGNAL s_axis_tlast_reg : STD_LOGIC := '0'; -- Registered version of tlast for output synchronization + SIGNAL m_axis_tvalid_int : STD_LOGIC := '0'; -- Internal valid signal for output interface + +BEGIN + + -- Connect internal signals to output ports + m_axis_tvalid <= m_axis_tvalid_int; + s_axis_tready <= s_axis_tready_int; + + -- Main processing logic - synchronous to clock + PROCESS (aclk) + BEGIN + + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset all filter state and control signals + samples_rx <= (OTHERS => (OTHERS => '0')); -- Clear right channel sample buffer + samples_lx <= (OTHERS => (OTHERS => '0')); -- Clear left channel sample buffer + sum_rx <= (OTHERS => '0'); -- Clear right channel running sum + sum_lx <= (OTHERS => '0'); -- Clear left channel running sum + wr_ptr_rx <= 0; -- Reset right channel write pointer + wr_ptr_lx <= 0; -- Reset left channel write pointer + + -- Reset AXI4-Stream interface signals + s_axis_tlast_reg <= '0'; -- Clear registered tlast + s_axis_tready_int <= '0'; -- Not ready during reset + m_axis_tvalid_int <= '0'; -- No valid output during reset + m_axis_tlast <= '0'; -- Clear output tlast + + ELSE + -- Normal operation + + -- Output handshake management: + -- Clear valid flag when downstream accepts data + IF m_axis_tready = '1' THEN + m_axis_tvalid_int <= '0'; + END IF; + + -- Data output logic: + -- Output filtered data when trigger is set AND output interface is available + IF trigger = '1' AND (m_axis_tvalid_int = '0' OR m_axis_tready = '1') THEN + + -- Select which channel's filtered data to output based on registered tlast + IF s_axis_tlast_reg = '1' THEN + -- Right channel: Output averaged right channel data + -- Divide sum by filter order using right shift (efficient division by power of 2) + m_axis_tdata <= STD_LOGIC_VECTOR( + resize( + shift_right( + sum_rx, -- Right channel running sum + FILTER_ORDER_POWER -- Divide by 2^FILTER_ORDER_POWER + ), + m_axis_tdata'length -- Resize to output width + ) + ); + + ELSE + -- Left channel: Output averaged left channel data + -- Divide sum by filter order using right shift (efficient division by power of 2) + m_axis_tdata <= STD_LOGIC_VECTOR( + resize( + shift_right( + sum_lx, -- Left channel running sum + FILTER_ORDER_POWER -- Divide by 2^FILTER_ORDER_POWER + ), + m_axis_tdata'length -- Resize to output width + ) + ); + + END IF; + + -- Set output control signals + m_axis_tlast <= s_axis_tlast_reg; -- Pass through the registered channel indicator + m_axis_tvalid_int <= '1'; -- Mark output as valid + trigger <= '0'; -- Clear trigger - data has been output + + END IF; + + -- Data input logic: + -- Process new input samples when both valid and ready are asserted + IF s_axis_tvalid = '1' AND s_axis_tready_int = '1' THEN + + -- Channel identification and processing based on tlast signal + IF s_axis_tlast = '1' THEN + -- Right channel processing (tlast = '1') + + -- Store new sample in circular buffer, overwriting oldest sample + samples_rx(wr_ptr_rx) <= signed(s_axis_tdata); + + -- Update write pointer with wraparound (circular buffer behavior) + wr_ptr_rx <= (wr_ptr_rx + 1) MOD FILTER_ORDER; + + -- Update running sum using sliding window technique: + -- Remove the oldest sample (about to be overwritten) and add the new sample + -- This maintains the sum of the most recent FILTER_ORDER samples + sum_rx <= sum_rx - samples_rx(wr_ptr_rx) + signed(s_axis_tdata); + + -- Register tlast for output synchronization + s_axis_tlast_reg <= s_axis_tlast; + + ELSE + -- Left channel processing (tlast = '0') + + -- Store new sample in circular buffer, overwriting oldest sample + samples_lx(wr_ptr_lx) <= signed(s_axis_tdata); + + -- Update write pointer with wraparound (circular buffer behavior) + wr_ptr_lx <= (wr_ptr_lx + 1) MOD FILTER_ORDER; + + -- Update running sum using sliding window technique: + -- Remove the oldest sample (about to be overwritten) and add the new sample + -- This maintains the sum of the most recent FILTER_ORDER samples + sum_lx <= sum_lx - samples_lx(wr_ptr_lx) + signed(s_axis_tdata); + + -- Register tlast for output synchronization + s_axis_tlast_reg <= s_axis_tlast; + + END IF; + + -- Set trigger to indicate that new filtered data is ready for output + trigger <= '1'; + + END IF; + + -- Input ready logic: + -- Ready to accept new input when downstream is ready OR no valid output pending + -- This implements proper AXI4-Stream backpressure handling + s_axis_tready_int <= m_axis_tready OR NOT m_axis_tvalid_int; + + END IF; + + END IF; + + END PROCESS; + + -- Filter Operation Summary: + -- 1. Maintains separate circular buffers for left and right audio channels + -- 2. Uses running sum technique for efficient moving average calculation + -- 3. Each new sample: removes oldest from sum, adds newest to sum + -- 4. Output = sum / FILTER_ORDER (using efficient bit shift division) + -- 5. Provides low-pass filtering with configurable filter order + +END Behavioral; \ No newline at end of file diff --git a/LAB3/src/moving_average_filter_en.vhd b/LAB3/src/moving_average_filter_en.vhd index 70c0d4c..5a57442 100644 --- a/LAB3/src/moving_average_filter_en.vhd +++ b/LAB3/src/moving_average_filter_en.vhd @@ -1,34 +1,168 @@ -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use ieee.numeric_std.all; +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE ieee.numeric_std.ALL; -entity moving_average_filter_en is - generic ( - -- Filter order expressed as 2^(FILTER_ORDER_POWER) - FILTER_ORDER_POWER : integer := 5; +-- Entity: moving_average_filter_en +-- Purpose: Switchable audio filter that can be enabled or disabled at runtime +-- When enabled: applies moving average low-pass filtering +-- When disabled: passes audio through unchanged (all-pass filter) +-- This allows real-time comparison between filtered and unfiltered audio +ENTITY moving_average_filter_en IS + GENERIC ( + -- Filter order expressed as 2^(FILTER_ORDER_POWER) + -- Example: FILTER_ORDER_POWER = 5 means filter order = 32 samples + FILTER_ORDER_POWER : INTEGER := 5; - TDATA_WIDTH : positive := 24 - ); - Port ( - aclk : in std_logic; - aresetn : in std_logic; + TDATA_WIDTH : POSITIVE := 24 -- Width of audio data bus (24-bit audio samples) + ); + PORT ( + -- Clock and reset signals + aclk : IN STD_LOGIC; -- Main clock input + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset - s_axis_tvalid : in std_logic; - s_axis_tdata : in std_logic_vector(TDATA_WIDTH-1 downto 0); - s_axis_tlast : in std_logic; - s_axis_tready : out std_logic; + -- AXI4-Stream Slave Interface (Audio Input) + s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample input + s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) + s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data - m_axis_tvalid : out std_logic; - m_axis_tdata : out std_logic_vector(TDATA_WIDTH-1 downto 0); - m_axis_tlast : out std_logic; - m_axis_tready : in std_logic; + -- AXI4-Stream Master Interface (Audio Output) + m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample output (filtered or unfiltered) + m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough + m_axis_tready : IN STD_LOGIC; -- Downstream ready signal - enable_filter : in std_logic - ); -end moving_average_filter_en; + -- Filter control input + enable_filter : IN STD_LOGIC -- Filter enable control (1=moving average filter, 0=all-pass filter) + ); +END moving_average_filter_en; -architecture Behavioral of moving_average_filter_en is +ARCHITECTURE Behavioral OF moving_average_filter_en IS -begin + -- Component declaration for all-pass filter + -- This filter passes audio unchanged but maintains the same latency as the moving average filter + COMPONENT all_pass_filter IS + GENERIC ( + TDATA_WIDTH : POSITIVE := 24 + ); + PORT ( + aclk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; -end Behavioral; + s_axis_tvalid : IN STD_LOGIC; + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + s_axis_tlast : IN STD_LOGIC; + s_axis_tready : OUT STD_LOGIC; + + m_axis_tvalid : OUT STD_LOGIC; + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + m_axis_tlast : OUT STD_LOGIC; + m_axis_tready : IN STD_LOGIC + ); + END COMPONENT; + + -- Component declaration for moving average filter + -- This filter applies low-pass filtering by averaging multiple audio samples + COMPONENT moving_average_filter IS + GENERIC ( + FILTER_ORDER_POWER : INTEGER := 5; + TDATA_WIDTH : POSITIVE := 24 + ); + PORT ( + aclk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; + + s_axis_tvalid : IN STD_LOGIC; + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + s_axis_tlast : IN STD_LOGIC; + s_axis_tready : OUT STD_LOGIC; + + m_axis_tvalid : OUT STD_LOGIC; + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + m_axis_tlast : OUT STD_LOGIC; + m_axis_tready : IN STD_LOGIC + ); + END COMPONENT; + + -- Internal signals for the all-pass filter path + -- These signals carry data when filtering is disabled + SIGNAL all_pass_m_tvalid : STD_LOGIC; -- All-pass filter output valid + SIGNAL all_pass_m_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- All-pass filter output data + SIGNAL all_pass_m_tlast : STD_LOGIC; -- All-pass filter output tlast + SIGNAL all_pass_s_tready : STD_LOGIC; -- All-pass filter input ready + + -- Internal signals for the moving average filter path + -- These signals carry data when filtering is enabled + SIGNAL moving_avg_m_tvalid : STD_LOGIC; -- Moving average filter output valid + SIGNAL moving_avg_m_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Moving average filter output data + SIGNAL moving_avg_m_tlast : STD_LOGIC; -- Moving average filter output tlast + SIGNAL moving_avg_s_tready : STD_LOGIC; -- Moving average filter input ready + +BEGIN + + -- Instantiate the all-pass filter (bypass path) + -- This provides unfiltered audio with matched latency for seamless switching + all_pass_inst : all_pass_filter + GENERIC MAP( + TDATA_WIDTH => TDATA_WIDTH + ) + PORT MAP( + aclk => aclk, + aresetn => aresetn, + + -- Connect input directly to all-pass filter + s_axis_tvalid => s_axis_tvalid, + s_axis_tdata => s_axis_tdata, + s_axis_tlast => s_axis_tlast, + s_axis_tready => all_pass_s_tready, + + -- All-pass filter outputs (used when enable_filter = '0') + m_axis_tvalid => all_pass_m_tvalid, + m_axis_tdata => all_pass_m_tdata, + m_axis_tlast => all_pass_m_tlast, + m_axis_tready => m_axis_tready + ); + + -- Instantiate the moving average filter (filtering path) + -- This provides low-pass filtered audio for noise reduction + moving_avg_inst : moving_average_filter + GENERIC MAP( + FILTER_ORDER_POWER => FILTER_ORDER_POWER, + TDATA_WIDTH => TDATA_WIDTH + ) + PORT MAP( + aclk => aclk, + aresetn => aresetn, + + -- Connect input directly to moving average filter + s_axis_tvalid => s_axis_tvalid, + s_axis_tdata => s_axis_tdata, + s_axis_tlast => s_axis_tlast, + s_axis_tready => moving_avg_s_tready, + + -- Moving average filter outputs (used when enable_filter = '1') + m_axis_tvalid => moving_avg_m_tvalid, + m_axis_tdata => moving_avg_m_tdata, + m_axis_tlast => moving_avg_m_tlast, + m_axis_tready => m_axis_tready + ); + + -- Output multiplexer: Select between filtered and unfiltered audio paths + -- This switching is controlled by the enable_filter signal + + -- Input ready selection: Route backpressure to the active filter + s_axis_tready <= all_pass_s_tready WHEN enable_filter = '0' ELSE moving_avg_s_tready; + + -- Output data selection: Route output from the active filter + m_axis_tvalid <= all_pass_m_tvalid WHEN enable_filter = '0' ELSE moving_avg_m_tvalid; + m_axis_tdata <= all_pass_m_tdata WHEN enable_filter = '0' ELSE moving_avg_m_tdata; + m_axis_tlast <= all_pass_m_tlast WHEN enable_filter = '0' ELSE moving_avg_m_tlast; + + -- Filter Path Selection Logic: + -- enable_filter = '0': All-pass path (unfiltered audio with matched latency) + -- enable_filter = '1': Moving average path (low-pass filtered audio) + -- + -- Both filters run continuously but only the selected path is routed to output + -- This allows for glitch-free switching between filtered and unfiltered audio + +END Behavioral; \ No newline at end of file diff --git a/LAB3/src/mute_controller.vhd b/LAB3/src/mute_controller.vhd index 2afdbf0..32e5fc8 100644 --- a/LAB3/src/mute_controller.vhd +++ b/LAB3/src/mute_controller.vhd @@ -1,31 +1,96 @@ -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; -entity mute_controller is - Generic ( - TDATA_WIDTH : positive := 24 - ); - Port ( - aclk : in std_logic; - aresetn : in std_logic; +-- Entity: mute_controller +-- Purpose: Controls audio muting by replacing audio samples with zeros when mute is active +-- Implements AXI4-Stream interface for seamless integration in audio processing chain +ENTITY mute_controller IS + GENERIC ( + TDATA_WIDTH : POSITIVE := 24 -- Width of audio data bus (24-bit audio samples) + ); + PORT ( + -- Clock and reset signals + aclk : IN STD_LOGIC; -- Main clock input + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset - s_axis_tvalid : in std_logic; - s_axis_tdata : in std_logic_vector(TDATA_WIDTH-1 downto 0); - s_axis_tlast : in std_logic; - s_axis_tready : out std_logic; + -- AXI4-Stream Slave Interface (Audio Input) + s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample input + s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) + s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data - m_axis_tvalid : out std_logic; - m_axis_tdata : out std_logic_vector(TDATA_WIDTH-1 downto 0); - m_axis_tlast : out std_logic; - m_axis_tready : in std_logic; + -- AXI4-Stream Master Interface (Audio Output) + m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample output (muted or passed through) + m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough + m_axis_tready : IN STD_LOGIC; -- Downstream ready signal - mute : in std_logic - ); -end mute_controller; + -- Control input + mute : IN STD_LOGIC -- Mute control (1=mute audio, 0=pass audio through) + ); +END mute_controller; -architecture Behavioral of mute_controller is +ARCHITECTURE Behavioral OF mute_controller IS -begin + -- Internal signal for output valid control + SIGNAL m_axis_tvalid_int : STD_LOGIC; -end Behavioral; +BEGIN + + -- Connect internal signals to output ports + m_axis_tvalid <= m_axis_tvalid_int; + + -- Input ready logic: Ready when downstream is ready OR no valid data pending, AND not in reset + -- This implements proper AXI4-Stream backpressure handling + s_axis_tready <= (m_axis_tready OR NOT m_axis_tvalid_int) AND aresetn; + + -- Main mute control process + -- Handles AXI4-Stream protocol and mute functionality + PROCESS (aclk) + BEGIN + + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset state: Clear all output control signals + m_axis_tvalid_int <= '0'; -- No valid output data during reset + m_axis_tlast <= '0'; -- Clear channel indicator + + ELSE + -- Normal operation + + -- Output handshake management: + -- Clear valid flag when downstream accepts data + -- This allows new data to be output on the next cycle + IF m_axis_tready = '1' THEN + m_axis_tvalid_int <= '0'; + END IF; + + -- Data processing: Handle mute control when both input and output are ready + -- This ensures proper AXI4-Stream handshaking + IF s_axis_tvalid = '1' AND m_axis_tready = '1' THEN + -- Mute control logic: + IF mute = '1' THEN + -- Mute active: Replace audio data with silence (all zeros) + -- This effectively removes all audio content while maintaining data flow + m_axis_tdata <= (OTHERS => '0'); + ELSE + -- Mute inactive: Pass audio data through unchanged + -- Normal audio processing mode + m_axis_tdata <= s_axis_tdata; + END IF; + + -- Set output control signals + m_axis_tvalid_int <= '1'; -- Mark output data as valid + m_axis_tlast <= s_axis_tlast; -- Pass through channel indicator unchanged + + END IF; + + END IF; + + END IF; + + END PROCESS; + +END Behavioral; \ No newline at end of file diff --git a/LAB3/src/volume_controller.vhd b/LAB3/src/volume_controller.vhd index f47429f..d567757 100644 --- a/LAB3/src/volume_controller.vhd +++ b/LAB3/src/volume_controller.vhd @@ -1,35 +1,170 @@ -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; -entity volume_controller is - Generic ( - TDATA_WIDTH : positive := 24; - VOLUME_WIDTH : positive := 10; - VOLUME_STEP_2 : positive := 6; -- i.e., volume_values_per_step = 2**VOLUME_STEP_2 - HIGHER_BOUND : integer := 2**23-1; -- Inclusive - LOWER_BOUND : integer := -2**23 -- Inclusive - ); - Port ( - aclk : in std_logic; - aresetn : in std_logic; +-- Entity: volume_controller +-- Purpose: Controls audio volume by scaling audio samples according to volume control input +-- Implements a two-stage processing pipeline: multiplication followed by saturation +-- This approach prevents overflow and distortion in the audio signal +ENTITY volume_controller IS + GENERIC ( + TDATA_WIDTH : POSITIVE := 24; -- Width of audio data bus (24-bit audio samples) + VOLUME_WIDTH : POSITIVE := 10; -- Width of volume control input (10-bit = 0-1023 range) + VOLUME_STEP_2 : POSITIVE := 6; -- Log2 of volume values per step (2^6 = 64 values per step) + HIGHER_BOUND : INTEGER := 2 ** 23 - 1; -- Maximum positive value for saturation (inclusive) + LOWER_BOUND : INTEGER := - 2 ** 23 -- Maximum negative value for saturation (inclusive) + ); + PORT ( + -- Clock and reset signals + aclk : IN STD_LOGIC; -- Main clock input + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset - s_axis_tvalid : in std_logic; - s_axis_tdata : in std_logic_vector(TDATA_WIDTH-1 downto 0); - s_axis_tlast : in std_logic; - s_axis_tready : out std_logic; + -- AXI4-Stream Slave Interface (Audio Input) + s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample input + s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) + s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data - m_axis_tvalid : out std_logic; - m_axis_tdata : out std_logic_vector(TDATA_WIDTH-1 downto 0); - m_axis_tlast : out std_logic; - m_axis_tready : in std_logic; + -- AXI4-Stream Master Interface (Audio Output) + m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample output (volume adjusted) + m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough + m_axis_tready : IN STD_LOGIC; -- Downstream ready signal - volume : in std_logic_vector(VOLUME_WIDTH-1 downto 0) - ); -end volume_controller; + -- Volume control input + volume : IN STD_LOGIC_VECTOR(VOLUME_WIDTH - 1 DOWNTO 0) -- Volume level (0=minimum, 1023=maximum) + ); +END volume_controller; -architecture Behavioral of volume_controller is +ARCHITECTURE Behavioral OF volume_controller IS -begin + -- Component declaration for volume multiplier + -- First stage: multiplies audio samples by volume scaling factor + -- Output has wider bit width to accommodate multiplication results + COMPONENT volume_multiplier IS + GENERIC ( + TDATA_WIDTH : POSITIVE := 24; -- Input audio data width + VOLUME_WIDTH : POSITIVE := 10; -- Volume control width + VOLUME_STEP_2 : POSITIVE := 6 -- Step size for volume control + ); + PORT ( + aclk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; -end Behavioral; + -- Input AXI4-Stream interface + s_axis_tvalid : IN STD_LOGIC; + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + s_axis_tlast : IN STD_LOGIC; + s_axis_tready : OUT STD_LOGIC; + + -- Output AXI4-Stream interface (wider data width due to multiplication) + m_axis_tvalid : OUT STD_LOGIC; + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) DOWNTO 0); + m_axis_tlast : OUT STD_LOGIC; + m_axis_tready : IN STD_LOGIC; + + volume : IN STD_LOGIC_VECTOR(VOLUME_WIDTH - 1 DOWNTO 0) + ); + END COMPONENT; + + -- Component declaration for volume saturator + -- Second stage: clips multiplication results to prevent overflow and distortion + -- Reduces bit width back to original audio format + COMPONENT volume_saturator IS + GENERIC ( + TDATA_WIDTH : POSITIVE := 24; -- Final audio data width + VOLUME_WIDTH : POSITIVE := 10; -- Volume control width + VOLUME_STEP_2 : POSITIVE := 6; -- Step size for volume control + HIGHER_BOUND : INTEGER := 2 ** 15 - 1; -- Upper saturation limit (inclusive) + LOWER_BOUND : INTEGER := - 2 ** 15 -- Lower saturation limit (inclusive) + ); + PORT ( + aclk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; + + -- Input AXI4-Stream interface (wide data from multiplier) + s_axis_tvalid : IN STD_LOGIC; + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) DOWNTO 0); + s_axis_tlast : IN STD_LOGIC; + s_axis_tready : OUT STD_LOGIC; + + -- Output AXI4-Stream interface (original audio data width) + m_axis_tvalid : OUT STD_LOGIC; + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + m_axis_tlast : OUT STD_LOGIC; + m_axis_tready : IN STD_LOGIC + ); + END COMPONENT; + + -- Internal AXI4-Stream signals between multiplier and saturator + -- These signals carry the wide multiplication results before saturation + SIGNAL int_axis_tvalid : STD_LOGIC; -- Valid signal between stages + SIGNAL int_axis_tready : STD_LOGIC; -- Ready signal between stages + SIGNAL int_axis_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) DOWNTO 0); -- Wide data between stages + SIGNAL int_axis_tlast : STD_LOGIC; -- Channel indicator between stages + +BEGIN + + -- Instantiate volume_multiplier (First Stage) + -- Multiplies incoming audio samples by volume scaling factor + -- Output has extended bit width to prevent loss of precision + volume_multiplier_inst : volume_multiplier + GENERIC MAP( + TDATA_WIDTH => TDATA_WIDTH, -- Input audio sample width + VOLUME_WIDTH => VOLUME_WIDTH, -- Volume control resolution + VOLUME_STEP_2 => VOLUME_STEP_2 -- Volume step size + ) + PORT MAP( + aclk => aclk, + aresetn => aresetn, + + -- Connect to external input interface + s_axis_tvalid => s_axis_tvalid, + s_axis_tdata => s_axis_tdata, + s_axis_tlast => s_axis_tlast, + s_axis_tready => s_axis_tready, + + -- Connect to internal interface (wide data) + m_axis_tvalid => int_axis_tvalid, + m_axis_tdata => int_axis_tdata, + m_axis_tlast => int_axis_tlast, + m_axis_tready => int_axis_tready, + + volume => volume + ); + + -- Instantiate volume_saturator (Second Stage) + -- Clips multiplication results to prevent overflow and distortion + -- Reduces bit width back to original audio format for output + volume_saturator_inst : volume_saturator + GENERIC MAP( + TDATA_WIDTH => TDATA_WIDTH, -- Final audio sample width + VOLUME_WIDTH => VOLUME_WIDTH, -- Volume control resolution + VOLUME_STEP_2 => VOLUME_STEP_2, -- Volume step size + HIGHER_BOUND => HIGHER_BOUND, -- Upper saturation limit + LOWER_BOUND => LOWER_BOUND -- Lower saturation limit + ) + PORT MAP( + aclk => aclk, + aresetn => aresetn, + + -- Connect to internal interface (wide data from multiplier) + s_axis_tvalid => int_axis_tvalid, + s_axis_tdata => int_axis_tdata, + s_axis_tlast => int_axis_tlast, + s_axis_tready => int_axis_tready, + + -- Connect to external output interface + m_axis_tvalid => m_axis_tvalid, + m_axis_tdata => m_axis_tdata, + m_axis_tlast => m_axis_tlast, + m_axis_tready => m_axis_tready + ); + + -- Pipeline Operation: + -- 1. Audio samples enter volume_multiplier with original bit width + -- 2. Multiplier scales samples by volume factor, output has extended bit width + -- 3. Saturator clips results to prevent overflow, reduces to original bit width + -- 4. Final audio samples has adjusted volume and bit width, ready for downstream processing + +END Behavioral; \ No newline at end of file diff --git a/LAB3/src/volume_multiplier.vhd b/LAB3/src/volume_multiplier.vhd index 34641e2..26c2d49 100644 --- a/LAB3/src/volume_multiplier.vhd +++ b/LAB3/src/volume_multiplier.vhd @@ -1,33 +1,170 @@ -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; -entity volume_multiplier is - Generic ( - TDATA_WIDTH : positive := 24; - VOLUME_WIDTH : positive := 10; - VOLUME_STEP_2 : positive := 6 -- i.e., volume_values_per_step = 2**VOLUME_STEP_2 - ); - Port ( - aclk : in std_logic; - aresetn : in std_logic; +-- Entity: volume_multiplier +-- Purpose: First stage of volume control pipeline - multiplies audio samples by volume scaling factor +-- Uses bit-shifting multiplication for efficient hardware implementation +-- Implements exponential volume scaling for natural-feeling volume control +ENTITY volume_multiplier IS + GENERIC ( + TDATA_WIDTH : POSITIVE := 24; -- Width of input audio data (24-bit audio samples) + VOLUME_WIDTH : POSITIVE := 10; -- Width of volume control input (10-bit = 0-1023 range) + VOLUME_STEP_2 : POSITIVE := 6 -- Log2 of volume values per step (2^6 = 64 values per step) + ); + PORT ( + -- Clock and reset signals + aclk : IN STD_LOGIC; -- Main clock input + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset - s_axis_tvalid : in std_logic; - s_axis_tdata : in std_logic_vector(TDATA_WIDTH-1 downto 0); - s_axis_tlast : in std_logic; - s_axis_tready : out std_logic; + -- AXI4-Stream Slave Interface (Audio Input) + s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Audio sample input + s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) + s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data - m_axis_tvalid : out std_logic; - m_axis_tdata : out std_logic_vector(TDATA_WIDTH-1 + 2**(VOLUME_WIDTH-VOLUME_STEP_2-1) downto 0); - m_axis_tlast : out std_logic; - m_axis_tready : in std_logic; + -- AXI4-Stream Master Interface (Audio Output with extended width) + m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) DOWNTO 0); -- Extended width output data + m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough + m_axis_tready : IN STD_LOGIC; -- Downstream ready signal - volume : in std_logic_vector(VOLUME_WIDTH-1 downto 0) - ); -end volume_multiplier; + -- Volume control input + volume : IN STD_LOGIC_VECTOR(VOLUME_WIDTH - 1 DOWNTO 0) -- Volume level (0=minimum, 1023=maximum) + ); +END volume_multiplier; -architecture Behavioral of volume_multiplier is +ARCHITECTURE Behavioral OF volume_multiplier IS -begin + -- Calculate volume control parameters based on generics + CONSTANT VOLUME_STEPS : INTEGER := (2 ** (VOLUME_WIDTH - 1)) / (2 ** VOLUME_STEP_2) + 1; -- Number of volume steps (9 steps for 10-bit) + CONSTANT VOL_MID : INTEGER := 2 ** (VOLUME_WIDTH - 1); -- Center volume position (512 for 10-bit) + CONSTANT DEAD_ZONE : INTEGER := (2 ** VOLUME_STEP_2) / 2; -- Dead zone around center (32 for step size 64) -end Behavioral; + -- Volume scaling factor as exponential multiplier + -- Positive values = amplification (left shift), negative values = attenuation (right shift) + SIGNAL volume_exp_mult : INTEGER RANGE -VOLUME_STEPS TO VOLUME_STEPS := 0; + + -- Internal AXI4-Stream signals + SIGNAL m_axis_tvalid_int : STD_LOGIC; -- Internal valid signal for output + +BEGIN + -- Connect internal signals to output ports + m_axis_tvalid <= m_axis_tvalid_int; + + -- Input ready logic: Ready when downstream is ready OR no valid data pending, AND not in reset + -- This implements proper AXI4-Stream backpressure handling + s_axis_tready <= (m_axis_tready OR NOT m_axis_tvalid_int) AND aresetn; + + -- Volume to exponent conversion process + -- Converts joystick y-axis position to bit-shift amount for exponential volume scaling + VOLUME_CALC : PROCESS (aclk) + BEGIN + + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset: Set to unity gain (no scaling) + volume_exp_mult <= 0; + + ELSE + -- Volume mapping and conversion to exponential scaling factor: + -- 1. Convert volume to signed value + -- 2. Center around middle position (VOL_MID) + -- 3. Apply dead zone offset for smooth center operation + -- 4. Divide by step size to get exponential scaling factor + -- + -- Volume Range Mapping: + -- volume = 0-479: Negative exponent (attenuation, right shift) + -- volume = 480-543: Zero exponent (unity gain, dead zone) + -- volume = 544-1023: Positive exponent (amplification, left shift) + + volume_exp_mult <= to_integer( + shift_right( + signed('0' & volume) - to_signed(VOL_MID - DEAD_ZONE, volume'length + 1), + VOLUME_STEP_2 + ) + ); + + END IF; + + END IF; + + END PROCESS VOLUME_CALC; + + -- AXI4-Stream data processing + -- Applies exponential volume scaling using bit-shifting multiplication + AXIS : PROCESS (aclk) + BEGIN + + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset output interface + m_axis_tvalid_int <= '0'; -- No valid output data + m_axis_tlast <= '0'; -- Clear channel indicator + + ELSE + -- Output handshake management: + -- Clear valid flag when downstream accepts data + IF m_axis_tready = '1' THEN + m_axis_tvalid_int <= '0'; + END IF; + + -- Data processing: Apply volume scaling when both input and output are ready + IF s_axis_tvalid = '1' AND m_axis_tready = '1' THEN + -- Volume scaling using bit-shifting for exponential response: + -- + -- Joystick mapping (from datasheet): + -- Y-axis: 0 = tilted all the way down (minimum volume) + -- 1023 = tilted all the way up (maximum volume) + -- + -- Scaling method: + -- Positive exponent: Left shift = amplification (multiply by 2^n) + -- Negative exponent: Right shift = attenuation (divide by 2^n) + -- Zero exponent: No shift = unity gain (pass through) + + IF volume_exp_mult >= 0 THEN + -- Amplification: Left shift for volume boost + -- Resize to extended width first to prevent overflow + m_axis_tdata <= STD_LOGIC_VECTOR( + shift_left( + resize(signed(s_axis_tdata), m_axis_tdata'LENGTH), + volume_exp_mult + ) + ); + + ELSE + -- Attenuation: Right shift for volume reduction + -- Arithmetic right shift preserves sign for signed audio data + m_axis_tdata <= STD_LOGIC_VECTOR( + shift_right( + resize(signed(s_axis_tdata), m_axis_tdata'LENGTH), + - volume_exp_mult -- Convert negative to positive shift amount + ) + ); + + END IF; + + -- Set output control signals + m_axis_tvalid_int <= '1'; -- Mark output data as valid + m_axis_tlast <= s_axis_tlast; -- Pass through channel indicator + + END IF; + + END IF; + + END IF; + + END PROCESS AXIS; + + -- Example scaling factors (VOLUME_STEP_2 = 6, 64 values per step): + -- volume_exp_mult = -3: Divide by 8 (>>3) + -- volume_exp_mult = -2: Divide by 4 (>>2) + -- volume_exp_mult = -1: Divide by 2 (>>1) + -- volume_exp_mult = 0: No change (unity) + -- volume_exp_mult = +1: Multiply by 2 (<<1) + -- volume_exp_mult = +2: Multiply by 4 (<<2) + -- volume_exp_mult = +3: Multiply by 8 (<<3) + +END Behavioral; \ No newline at end of file diff --git a/LAB3/src/volume_saturator.vhd b/LAB3/src/volume_saturator.vhd index ae69f9f..697e44e 100644 --- a/LAB3/src/volume_saturator.vhd +++ b/LAB3/src/volume_saturator.vhd @@ -1,33 +1,110 @@ -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; -entity volume_saturator is - Generic ( - TDATA_WIDTH : positive := 24; - VOLUME_WIDTH : positive := 10; - VOLUME_STEP_2 : positive := 6; -- i.e., number_of_steps = 2**(VOLUME_STEP_2) - HIGHER_BOUND : integer := 2**15-1; -- Inclusive - LOWER_BOUND : integer := -2**15 -- Inclusive - ); - Port ( - aclk : in std_logic; - aresetn : in std_logic; +-- Entity: volume_saturator +-- Purpose: Second stage of volume control pipeline - clips multiplication results to prevent overflow +-- Reduces bit width from extended multiplier output back to original audio format +-- Implements saturation (clipping) to prevent audio distortion from mathematical overflow +ENTITY volume_saturator IS + GENERIC ( + TDATA_WIDTH : POSITIVE := 24; -- Width of final audio data output (24-bit audio samples) + VOLUME_WIDTH : POSITIVE := 10; -- Width of volume control input (10-bit = 0-1023 range) + VOLUME_STEP_2 : POSITIVE := 6; -- Log2 of volume values per step (2^6 = 64 values per step) + HIGHER_BOUND : INTEGER := 2 ** 15 - 1; -- Maximum positive value for saturation (inclusive) + LOWER_BOUND : INTEGER := - 2 ** 15 -- Maximum negative value for saturation (inclusive) + ); + PORT ( + -- Clock and reset signals + aclk : IN STD_LOGIC; -- Main clock input + aresetn : IN STD_LOGIC; -- Active-low asynchronous reset - s_axis_tvalid : in std_logic; - s_axis_tdata : in std_logic_vector(TDATA_WIDTH-1 + 2**(VOLUME_WIDTH-VOLUME_STEP_2-1) downto 0); - s_axis_tlast : in std_logic; - s_axis_tready : out std_logic; + -- AXI4-Stream Slave Interface (Extended width input from multiplier) + s_axis_tvalid : IN STD_LOGIC; -- Input data valid signal + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) DOWNTO 0); -- Wide input data from multiplier + s_axis_tlast : IN STD_LOGIC; -- Channel indicator (0=left, 1=right) + s_axis_tready : OUT STD_LOGIC; -- Ready to accept input data - m_axis_tvalid : out std_logic; - m_axis_tdata : out std_logic_vector(TDATA_WIDTH-1 downto 0); - m_axis_tlast : out std_logic; - m_axis_tready : in std_logic - ); -end volume_saturator; + -- AXI4-Stream Master Interface (Original width output for audio) + m_axis_tvalid : OUT STD_LOGIC; -- Output data valid signal + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); -- Saturated audio sample output + m_axis_tlast : OUT STD_LOGIC; -- Channel indicator passthrough + m_axis_tready : IN STD_LOGIC -- Downstream ready signal + ); +END volume_saturator; -architecture Behavioral of volume_saturator is +ARCHITECTURE Behavioral OF volume_saturator IS -begin + -- Pre-calculated saturation bounds as STD_LOGIC_VECTORS for efficient comparison + -- These constants define the valid range for audio samples after volume processing + CONSTANT HIGHER_BOUND_VEC : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0) := STD_LOGIC_VECTOR(to_signed(HIGHER_BOUND, TDATA_WIDTH)); + CONSTANT LOWER_BOUND_VEC : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0) := STD_LOGIC_VECTOR(to_signed(LOWER_BOUND, TDATA_WIDTH)); -end Behavioral; + -- Internal AXI4-Stream control signal + SIGNAL m_axis_tvalid_int : STD_LOGIC; + +BEGIN + + -- Connect internal signals to output ports + m_axis_tvalid <= m_axis_tvalid_int; + + -- Input ready logic: Ready when downstream is ready OR no valid data pending, AND not in reset + -- This implements proper AXI4-Stream backpressure handling + s_axis_tready <= (m_axis_tready OR NOT m_axis_tvalid_int) AND aresetn; + + -- Main saturation and data processing logic + PROCESS (aclk) + BEGIN + + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + -- Reset output interface + m_axis_tvalid_int <= '0'; -- No valid output data during reset + m_axis_tlast <= '0'; -- Clear channel indicator + + ELSE + -- Normal operation + + -- Output handshake management: + -- Clear valid flag when downstream accepts data + IF m_axis_tready = '1' THEN + m_axis_tvalid_int <= '0'; + END IF; + + -- Data processing: Apply saturation when both input and output are ready + IF s_axis_tvalid = '1' AND m_axis_tready = '1' THEN + + -- Saturation Logic: + -- Check if the wide input data exceeds the valid audio range + -- If so, clip (saturate) to the nearest valid value + -- This prevents overflow distortion while preserving audio quality + + IF signed(s_axis_tdata) > signed(HIGHER_BOUND_VEC) THEN + -- Positive overflow: Clip to maximum positive value + m_axis_tdata <= HIGHER_BOUND_VEC; + + ELSIF signed(s_axis_tdata) < signed(LOWER_BOUND_VEC) THEN + -- Negative overflow: Clip to maximum negative value + m_axis_tdata <= LOWER_BOUND_VEC; + + ELSE + -- Value within valid range: Resize to output width without clipping + -- This preserves the original audio quality when no overflow occurs + m_axis_tdata <= STD_LOGIC_VECTOR(resize(signed(s_axis_tdata), TDATA_WIDTH)); + + END IF; + + -- Set output control signals + m_axis_tvalid_int <= '1'; -- Mark output data as valid + m_axis_tlast <= s_axis_tlast; -- Pass through channel indicator + + END IF; + + END IF; + + END IF; + + END PROCESS; + +END Behavioral; \ No newline at end of file diff --git a/LAB3/test/Color_circle_(RGB).png b/LAB3/test/Color_circle_(RGB).png new file mode 100644 index 0000000..87bd55c Binary files /dev/null and b/LAB3/test/Color_circle_(RGB).png differ diff --git a/LAB3/test/uart_viewer.py b/LAB3/test/uart_viewer.py new file mode 100644 index 0000000..296882a --- /dev/null +++ b/LAB3/test/uart_viewer.py @@ -0,0 +1,175 @@ +import serial +import serial.tools.list_ports +import time +import queue +import threading +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import io +from PIL import Image +import numpy as np + +# CONFIGURAZIONE +BASYS3_PID = 0x6010 +BASYS3_VID = 0x0403 +BAUDRATE = 115200 # Imposta la tua velocità +CHUNK_SIZE = 4 # 4 byte per riga + +# Ricerca automatica della porta Basys3 +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!") + +PORT = dev + +def receive_mode(ser): + print("Modalità ricezione. Premi Ctrl+C per uscire.\n") + while True: + if ser.in_waiting >= CHUNK_SIZE: + data = ser.read(CHUNK_SIZE) + hex_bytes = ' '.join(f"{b:02X}" for b in data) + print(f"HH | {hex_bytes}") + +def receive_graph_mode(ser): + print("Modalità ricezione e visualizzazione coordinate in tempo reale. Premi Ctrl+C per uscire.\n") + q = queue.Queue() + + def serial_reader(): + while True: + if ser.in_waiting >= CHUNK_SIZE: + data = ser.read(CHUNK_SIZE) + if len(data) >= 4: + x = data[1] + y = data[2] + flags = data[3] + q.put((x, y, flags)) + + reader_thread = threading.Thread(target=serial_reader, daemon=True) + reader_thread.start() + + point = [64, 64] # Punto iniziale al centro del grafico + color = 'blue' + size = 100 + + release = True + rgb = [0, 0, 0] + + fig, ax = plt.subplots() + + # Load PNG directly + png_path = r'LAB3\test\Color_circle_(RGB).png' + img = Image.open(png_path).convert('RGB') + img = img.resize((127, 127), Image.Resampling.LANCZOS) # Ensure image is 127x127 + img_np = np.array(img) + + # Show the image as background + ax.imshow(img, extent=(0, 127, 0, 127), aspect='auto', zorder=0) + + sc = ax.scatter([point[0]], [point[1]], s=[size], zorder=1) + ax.set_xlim(0, 127) + ax.set_ylim(0, 127) + ax.set_xlabel("X") + ax.set_ylabel("Y") + ax.set_title("Coordinate in tempo reale") + + def send_rgb_over_serial(ser, rgb): + """ + Send RGB values over serial with a fixed first byte (0xC0). + """ + bytes_to_send = [0xC0] # Primo byte fisso + for part in rgb: + val = int(part) + bytes_to_send.append(val) + ser.write(bytearray(bytes_to_send)) + print(f"Inviato: {' '.join(f'{b:02X}' for b in bytes_to_send)}") + + def update(frame): + nonlocal point, color, size, release, rgb + + while not q.empty(): + x, y, flags = q.get() + point[0] = x + point[1] = y + + if flags & 0b00000001: + rgb = [0, 0, 0] + size = 50 + if release: + send_rgb_over_serial(ser, rgb) + release = False + + elif flags & 0b00000010: + flipped_y = 127 - y # Flip y to match image coordinates + rgb = img_np[flipped_y, x] + size = 300 + if release: + send_rgb_over_serial(ser, rgb) + release = False + + else: + size = 100 + release = True # Reset release when no button is pressed + + sc.set_offsets([point]) + sc.set_sizes([size]) + return sc, + + ani = animation.FuncAnimation(fig, update, interval=10, blit=True, cache_frame_data=False) + plt.show() + +def send_mode(ser): + print("Modalità invio. Inserisci 3 byte in esadecimale (il primo sarà sempre 'C0').") + print("Formato: XX XX XX (dove XX è tra 00 e FF). Premi Ctrl+C per uscire.\n") + while True: + try: + user_input = input("Inserisci 3 byte (es: 12 34 AB): ").strip() + parts = user_input.split() + if len(parts) != 3: + print("Devi inserire esattamente 3 byte.") + continue + try: + bytes_to_send = [0xC0] # Primo byte fisso + for part in parts: + val = int(part, 16) + if not (0x00 <= val <= 0xFF): + raise ValueError + bytes_to_send.append(val) + ser.write(bytearray(bytes_to_send)) + print(f"Inviato: {' '.join(f'{b:02X}' for b in bytes_to_send)}") + except ValueError: + print("Valori non validi. Usa solo byte esadecimali tra 00 e FF.") + except KeyboardInterrupt: + print("\nChiusura modalità invio...") + break + +ser = None +try: + mode = "" + while mode not in ["r", "s", "g"]: + mode = input("Vuoi ricevere (r), inviare (s), o ricevere con grafico (g)? [r/s/g]: ").strip().lower() + + ser = serial.Serial(PORT, BAUDRATE, timeout=1) + print(f"Aperta porta seriale: {PORT} a {BAUDRATE} baud.\n") + + if mode == "r": + receive_mode(ser) + elif mode == "s": + send_mode(ser) + elif mode == "g": + receive_graph_mode(ser) + else: + print("Selezione non valida. Uscita...") + ser.close() + exit(1) + +except KeyboardInterrupt: + print("\nChiusura programma...") +except serial.SerialException as e: + print(f"Errore nella connessione seriale: {e}") +finally: + if ser is not None and ser.is_open: + ser.close() diff --git a/LAB3/vivado/LFO/LFO.xpr b/LAB3/vivado/LFO/LFO.xpr new file mode 100644 index 0000000..7206ae2 --- /dev/null +++ b/LAB3/vivado/LFO/LFO.xpr @@ -0,0 +1,391 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default_dashboard + + + diff --git a/LAB3/vivado/LFO/tb_LFO_behav.wcfg b/LAB3/vivado/LFO/tb_LFO_behav.wcfg new file mode 100644 index 0000000..3668c4c --- /dev/null +++ b/LAB3/vivado/LFO/tb_LFO_behav.wcfg @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + aclk + aclk + + + aresetn + aresetn + + + step_counter + step_counter + UNSIGNEDDECRADIX + + + step_clk_cycles + step_clk_cycles + UNSIGNEDDECRADIX + + + tri_counter[10:0] + tri_counter[10:0] + UNSIGNEDDECRADIX + + + lfo_period[9:0] + lfo_period[9:0] + UNSIGNEDDECRADIX + + + lfo_enable + lfo_enable + + + s_axis + label + + + s_axis_tdata[23:0] + s_axis_tdata[23:0] + SIGNEDDECRADIX + + + s_axis_tlast + s_axis_tlast + + + s_axis_tvalid + s_axis_tvalid + #00FFFF + true + + + s_axis_tready + s_axis_tready + #FFD700 + true + + + m_axis + label + + + m_axis_tdata[23:0] + m_axis_tdata[23:0] + SIGNEDDECRADIX + + + m_axis_tlast + m_axis_tlast + + + m_axis_tvalid + m_axis_tvalid + #00FFFF + true + + + m_axis_tready + m_axis_tready + #FFD700 + true + + diff --git a/LAB3/vivado/balance_controller/balance_controller.xpr b/LAB3/vivado/balance_controller/balance_controller.xpr new file mode 100644 index 0000000..732795d --- /dev/null +++ b/LAB3/vivado/balance_controller/balance_controller.xpr @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vivado Synthesis Defaults + + + + + + + + + + + Default settings for Implementation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default_dashboard + + + diff --git a/LAB3/vivado/balance_controller/tb_balance_controller_behav.wcfg b/LAB3/vivado/balance_controller/tb_balance_controller_behav.wcfg new file mode 100644 index 0000000..d0b7ed1 --- /dev/null +++ b/LAB3/vivado/balance_controller/tb_balance_controller_behav.wcfg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + aclk + aclk + + + aresetn + aresetn + + + Balance + label + + + balance[9:0] + balance[9:0] + UNSIGNEDDECRADIX + + + left_channel + left_channel + + + right_channel + right_channel + + + s_axis + label + + + s_axis_tdata[23:0] + s_axis_tdata[23:0] + SIGNEDDECRADIX + + + s_axis_tlast + s_axis_tlast + + + s_axis_tvalid + s_axis_tvalid + #00FFFF + true + + + s_axis_tready + s_axis_tready + #FFD700 + true + + + m_axis + label + + + m_axis_tdata[23:0] + m_axis_tdata[23:0] + SIGNEDDECRADIX + + + m_axis_tlast + m_axis_tlast + + + m_axis_tvalid + m_axis_tvalid + #00FFFF + true + + + m_axis_tready + m_axis_tready + #FFD700 + true + + diff --git a/LAB3/vivado/diligent_jstk/diligent_jstk.xpr b/LAB3/vivado/diligent_jstk/diligent_jstk.xpr index 68f7553..b3d8a31 100644 --- a/LAB3/vivado/diligent_jstk/diligent_jstk.xpr +++ b/LAB3/vivado/diligent_jstk/diligent_jstk.xpr @@ -48,20 +48,20 @@