From 2e5353f468b520c08e322f4ea444d592d3486e43 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 1 Dec 2023 18:48:11 -0800 Subject: [PATCH 01/96] eliminate unnecessary slices and fix RX demodulator output width --- HDL/projects/ocra_mri/block_design.tcl | 40 ++++---------------------- HDL/projects/ocra_mri/rx2.tcl | 4 +-- 2 files changed, 8 insertions(+), 36 deletions(-) diff --git a/HDL/projects/ocra_mri/block_design.tcl b/HDL/projects/ocra_mri/block_design.tcl index 75800427..d67d767c 100644 --- a/HDL/projects/ocra_mri/block_design.tcl +++ b/HDL/projects/ocra_mri/block_design.tcl @@ -36,33 +36,12 @@ cell xilinx.com:ip:clk_wiz:6.0 pll_0 { clk_in1_p adc_clk_p_i clk_in1_n adc_clk_n_i } + cell open-mri:user:axi_config_registers:1.0 cfg8 { AXI_ADDR_WIDTH 5 AXI_DATA_WIDTH 32 } -# Create slice with the TX configuration, which uses the bottom 32 bits -cell xilinx.com:ip:xlslice:1.0 txinterpolator_slice_0 { - DIN_WIDTH 32 DIN_FROM 31 DIN_TO 0 DOUT_WIDTH 32 -} { - Din cfg8/config_0 -} - -# Create slice with the RX configuration and NCO configuration -# RX seems to use the bottom 16 bit of the upper 32 bit -# NCO uses the bottom 32 bit -cell xilinx.com:ip:xlslice:1.0 nco_slice_0 { - DIN_WIDTH 32 DIN_FROM 31 DIN_TO 0 DOUT_WIDTH 32 -} { - Din cfg8/config_1 -} - -cell xilinx.com:ip:xlslice:1.0 rx_slice_0 { - DIN_WIDTH 32 DIN_FROM 31 DIN_TO 0 DOUT_WIDTH 32 -} { - Din cfg8/config_2 -} - # ADC switch slice cell xilinx.com:ip:xlslice:1.0 cfg_adc_switch { DIN_WIDTH 32 DIN_FROM 1 DIN_TO 0 DOUT_WIDTH 2 @@ -81,12 +60,6 @@ cell xilinx.com:ip:xpm_cdc_gen:1.0 xpm_cdc_gen_0 { set_property CONFIG.CDC_TYPE {xpm_cdc_array_single} [get_bd_cells xpm_cdc_gen_0] set_property CONFIG.WIDTH {2} [get_bd_cells xpm_cdc_gen_0] -# Create another slice with data for the TX, which is another 32 bit -cell xilinx.com:ip:xlslice:1.0 cfg_slice_1 { - DIN_WIDTH 32 DIN_FROM 31 DIN_TO 0 DOUT_WIDTH 32 -} { - Din cfg8/config_3 -} # ADC # Create axis_red_pitaya_adc @@ -110,7 +83,6 @@ cell pavel-demin:user:axis_red_pitaya_dac:1.0 dac_0 {} { dac_dat dac_dat_o } - # Create xlconstant cell xilinx.com:ip:xlconstant:1.1 const_0 @@ -119,18 +91,18 @@ cell xilinx.com:ip:xlconstant:1.1 const_0 module rx_0 { source projects/ocra_mri/rx2.tcl } { - rate_slice/Din rx_slice_0/Dout + rate_slice/Din cfg8/config_2 fifo_0/S_AXIS adc_0/M_AXIS fifo_0/s_axis_aclk pll_0/clk_out1 fifo_0/s_axis_aresetn const_0/dout } -# axis_interpolator_0/cfg_data txinterpolator_slice_0/Dout +# axis_interpolator_0/cfg_data cfg8/config_0 module tx_0 { source projects/ocra_mri/tx6.tcl } { - slice_1/Din cfg_slice_1/Dout - axis_interpolator_0/cfg_data txinterpolator_slice_0/Dout + slice_1/Din cfg8/config_3 + axis_interpolator_0/cfg_data cfg8/config_0 fifo_1/M_AXIS dac_0/S_AXIS fifo_1/m_axis_aclk pll_0/clk_out1 fifo_1/m_axis_aresetn const_0/dout @@ -139,7 +111,7 @@ module tx_0 { module nco_0 { source projects/ocra_mri/nco.tcl } { - slice_1/Din nco_slice_0/Dout + slice_1/Din cfg8/config_1 bcast_nco/M00_AXIS rx_0/mult_0/S_AXIS_B bcast_nco/M01_AXIS tx_0/mult_0/S_AXIS_B } diff --git a/HDL/projects/ocra_mri/rx2.tcl b/HDL/projects/ocra_mri/rx2.tcl index 67192183..499e3852 100644 --- a/HDL/projects/ocra_mri/rx2.tcl +++ b/HDL/projects/ocra_mri/rx2.tcl @@ -27,7 +27,7 @@ cell pavel-demin:user:axis_lfsr:1.0 lfsr_0 {} { aresetn /rst_0/peripheral_aresetn } -# Create cmpy +# The top 24 bits is the most we need, 16 would probably be fine as well cell xilinx.com:ip:cmpy:6.0 mult_0 { FLOWCONTROL Blocking APORTWIDTH.VALUE_SRC USER @@ -35,7 +35,7 @@ cell xilinx.com:ip:cmpy:6.0 mult_0 { APORTWIDTH 16 BPORTWIDTH 24 ROUNDMODE Random_Rounding - OUTPUTWIDTH 26 + OUTPUTWIDTH 24 } { S_AXIS_A fifo_0/M_AXIS S_AXIS_CTRL lfsr_0/M_AXIS From 1459b95d8058e94c53ad365c11276b4a7f6e7c84 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 3 Dec 2023 06:33:10 -0800 Subject: [PATCH 02/96] fix the broadcaster width in the receiver part initial tidy up of the transmit path experiments with board_dependent configuration --- HDL/projects/ocra_mri/block_design.tcl | 8 +++++ HDL/projects/ocra_mri/nco.tcl | 2 +- HDL/projects/ocra_mri/rx2.tcl | 4 +-- HDL/projects/ocra_mri/tx6.tcl | 49 +++----------------------- 4 files changed, 16 insertions(+), 47 deletions(-) diff --git a/HDL/projects/ocra_mri/block_design.tcl b/HDL/projects/ocra_mri/block_design.tcl index d67d767c..f1fd6304 100644 --- a/HDL/projects/ocra_mri/block_design.tcl +++ b/HDL/projects/ocra_mri/block_design.tcl @@ -3,6 +3,14 @@ global project_name set ps_preset boards/${board_name}/ps_${project_name}.xml +variable dsp_clk_freq + +if {$board_name == "stemlab_122_16"} { + set dsp_clk_freq 122.88 +} else { + set dsp_clk_freq 125 +} + # Create processing_system7 cell xilinx.com:ip:processing_system7:5.5 ps_0 { PCW_IMPORT_BOARD_PRESET $ps_preset diff --git a/HDL/projects/ocra_mri/nco.tcl b/HDL/projects/ocra_mri/nco.tcl index 945d012e..42047a69 100644 --- a/HDL/projects/ocra_mri/nco.tcl +++ b/HDL/projects/ocra_mri/nco.tcl @@ -18,7 +18,7 @@ cell pavel-demin:user:axis_constant:1.0 phase_nco { # Create dds_compiler cell xilinx.com:ip:dds_compiler:6.0 dds_nco { - DDS_CLOCK_RATE 125 + DDS_CLOCK_RATE $dsp_clk_freq SPURIOUS_FREE_DYNAMIC_RANGE 138 FREQUENCY_RESOLUTION 0.2 PHASE_INCREMENT Streaming diff --git a/HDL/projects/ocra_mri/rx2.tcl b/HDL/projects/ocra_mri/rx2.tcl index 499e3852..64b8bd5d 100644 --- a/HDL/projects/ocra_mri/rx2.tcl +++ b/HDL/projects/ocra_mri/rx2.tcl @@ -46,10 +46,10 @@ cell xilinx.com:ip:cmpy:6.0 mult_0 { cell xilinx.com:ip:axis_broadcaster:1.1 bcast_0 { S_TDATA_NUM_BYTES.VALUE_SRC USER M_TDATA_NUM_BYTES.VALUE_SRC USER - S_TDATA_NUM_BYTES 8 + S_TDATA_NUM_BYTES 6 M_TDATA_NUM_BYTES 3 M00_TDATA_REMAP {tdata[23:0]} - M01_TDATA_REMAP {tdata[55:32]} + M01_TDATA_REMAP {tdata[47:24]} } { S_AXIS mult_0/M_AXIS_DOUT aclk /ps_0/FCLK_CLK0 diff --git a/HDL/projects/ocra_mri/tx6.tcl b/HDL/projects/ocra_mri/tx6.tcl index 787d8ce3..b5a3b028 100644 --- a/HDL/projects/ocra_mri/tx6.tcl +++ b/HDL/projects/ocra_mri/tx6.tcl @@ -76,13 +76,15 @@ cell pavel-demin:user:axis_interpolator:1.0 axis_interpolator_0 { # ROUNDMODE Random_Rounding # No control connection needed # S_AXIS_CTRL lfsr_0/M_AXIS + +# take the top 16 bit of the product. This means TX pulses should be scaled full range of a signed short in the data to the FPGA cell xilinx.com:ip:cmpy:6.0 mult_0 { FLOWCONTROL Blocking APORTWIDTH.VALUE_SRC USER BPORTWIDTH.VALUE_SRC USER APORTWIDTH 16 BPORTWIDTH 24 - OUTPUTWIDTH 41 + OUTPUTWIDTH 16 } { S_AXIS_A axis_interpolator_0/M_AXIS aclk /ps_0/FCLK_CLK0 @@ -91,43 +93,17 @@ cell xilinx.com:ip:cmpy:6.0 mult_0 { # extract the real component of the product using a broadcaster in to I and Q # a simpler alternative would be to use a axis_subset_converter cell xilinx.com:ip:axis_subset_converter:1.1 real_0 { - S_TDATA_NUM_BYTES.VALUE_SRC USER - M_TDATA_NUM_BYTES.VALUE_SRC USER - S_TDATA_NUM_BYTES 10 - M_TDATA_NUM_BYTES 2 - TDATA_REMAP {tdata[40:25]} -} { - S_AXIS mult_0/M_AXIS_DOUT - aclk /ps_0/FCLK_CLK0 - aresetn /rst_0/peripheral_aresetn -} - -# extract the real component of the product using a broadcaster in to I and Q -# a simpler alternative would be to use a axis_subset_converter -cell xilinx.com:ip:axis_subset_converter:1.1 quotient_0 { S_TDATA_NUM_BYTES.VALUE_SRC USER M_TDATA_NUM_BYTES.VALUE_SRC USER S_TDATA_NUM_BYTES 4 M_TDATA_NUM_BYTES 2 - TDATA_REMAP {tdata[31:16]} + TDATA_REMAP {tdata[15:0]} } { + S_AXIS mult_0/M_AXIS_DOUT aclk /ps_0/FCLK_CLK0 aresetn /rst_0/peripheral_aresetn } -#cell xilinx.com:ip:axis_broadcaster:1.1 bcast_0 { -# S_TDATA_NUM_BYTES.VALUE_SRC USER -# M_TDATA_NUM_BYTES.VALUE_SRC USER -# S_TDATA_NUM_BYTES 8 -# M_TDATA_NUM_BYTES 3 -# M00_TDATA_REMAP {tdata[23:0]} -# M01_TDATA_REMAP {tdata[55:32]} -#} { -# S_AXIS mult_0/M_AXIS_DOUT -# aclk /ps_0/FCLK_CLK0 -# aresetn /rst_0/peripheral_aresetn -#} - # Create axis_clock_converter cell xilinx.com:ip:axis_clock_converter:1.1 fifo_1 { TDATA_NUM_BYTES.VALUE_SRC USER @@ -138,18 +114,3 @@ cell xilinx.com:ip:axis_clock_converter:1.1 fifo_1 { s_axis_aresetn /rst_0/peripheral_aresetn } -## DO all this below to insert the divider by 4 -create_bd_cell -type ip -vlnv xilinx.com:ip:div_gen:5.1 div_gen_0 -create_bd_cell -type ip -vlnv pavel-demin:user:axis_constant:1.0 axis_constant_0 -set_property -dict [list CONFIG.AXIS_TDATA_WIDTH {16}] [get_bd_cells axis_constant_0] -connect_bd_intf_net [get_bd_intf_pins axis_constant_0/M_AXIS] [get_bd_intf_pins div_gen_0/S_AXIS_DIVISOR] -create_bd_cell -type ip -vlnv xilinx.com:ip:xlconstant:1.1 xlconstant_0 -# Constant was 4, now its 1 -set_property -dict [list CONFIG.CONST_WIDTH {16} CONFIG.CONST_VAL {1}] [get_bd_cells xlconstant_0] -connect_bd_net [get_bd_pins xlconstant_0/dout] [get_bd_pins axis_constant_0/cfg_data] -connect_bd_net [get_bd_pins aclk] [get_bd_pins axis_constant_0/aclk] -connect_bd_net [get_bd_pins aclk] [get_bd_pins div_gen_0/aclk] -delete_bd_objs [get_bd_intf_nets real_0_M_AXIS] -connect_bd_intf_net [get_bd_intf_pins real_0/M_AXIS] [get_bd_intf_pins div_gen_0/S_AXIS_DIVIDEND] -connect_bd_intf_net [get_bd_intf_pins div_gen_0/M_AXIS_DOUT] [get_bd_intf_pins quotient_0/S_AXIS] -connect_bd_intf_net [get_bd_intf_pins quotient_0/M_AXIS] [get_bd_intf_pins fifo_1/S_AXIS] From d946118851438777dfde3b7ec5ced8d7c489b223 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 3 Dec 2023 15:30:11 -0800 Subject: [PATCH 03/96] incorporated new DAC core that uses the 14 MSB of a 16 bit DAC word --- HDL/Makefile | 2 +- HDL/projects/ocra_mri/block_design.tcl | 10 +++++++--- HDL/projects/ocra_mri/nco.tcl | 2 ++ HDL/projects/ocra_mri/rx2.tcl | 6 ++++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/HDL/Makefile b/HDL/Makefile index 90548bbf..26c4e5ab 100644 --- a/HDL/Makefile +++ b/HDL/Makefile @@ -15,7 +15,7 @@ CORES_PAVEL = axi_axis_reader_v1_0 axi_axis_writer_v1_0 axi_bram_reader_v1_0 \ axis_zeroer_v1_0 axis_variable_v1_0 axis_interpolator_v1_0 \ axi_sts_register_v1_0 -CORES = micro_sequencer_v1_0 axi_dac_spi_sequencer_v1_1 axi_dac_daisy_spi_sequencer_v1_0 axis_segmented_bram_reader_v1_0 axi_serial_attenuator_v1_0 axi_four_ltc2656_spi_v1_0 axi_trigger_core_v1_0 axis_red_pitaya_adc_v3_0 axi_config_registers_v1_0 +CORES = micro_sequencer_v1_0 axi_dac_spi_sequencer_v1_1 axi_dac_daisy_spi_sequencer_v1_0 axis_segmented_bram_reader_v1_0 axi_serial_attenuator_v1_0 axi_four_ltc2656_spi_v1_0 axi_trigger_core_v1_0 axis_red_pitaya_adc_v3_0 axi_config_registers_v1_0 axis_red_pitaya_dac_v1_1 VIVADO = vivado -nolog -nojournal -mode batch HSI = xsct diff --git a/HDL/projects/ocra_mri/block_design.tcl b/HDL/projects/ocra_mri/block_design.tcl index f1fd6304..c062a3a0 100644 --- a/HDL/projects/ocra_mri/block_design.tcl +++ b/HDL/projects/ocra_mri/block_design.tcl @@ -3,12 +3,13 @@ global project_name set ps_preset boards/${board_name}/ps_${project_name}.xml +# define some variables needed for later variable dsp_clk_freq if {$board_name == "stemlab_122_16"} { set dsp_clk_freq 122.88 } else { - set dsp_clk_freq 125 + set dsp_clk_freq 125.0 } # Create processing_system7 @@ -28,11 +29,14 @@ apply_bd_automation -rule xilinx.com:bd_rule:processing_system7 -config { # Create proc_sys_reset cell xilinx.com:ip:proc_sys_reset:5.0 rst_0 +puts "OCRA: DSP_CLK_FREQ:" +puts $dsp_clk_freq + # Create clk_wiz cell xilinx.com:ip:clk_wiz:6.0 pll_0 { PRIMITIVE PLL PRIM_IN_FREQ.VALUE_SRC USER - PRIM_IN_FREQ 125.0 + PRIM_IN_FREQ $dsp_clk_freq PRIM_SOURCE Differential_clock_capable_pin CLKOUT1_USED true CLKOUT1_REQUESTED_OUT_FREQ 125.0 @@ -80,7 +84,7 @@ cell open-mri:user:axis_red_pitaya_adc:3.0 adc_0 {} { } # Create axis_red_pitaya_dac -cell pavel-demin:user:axis_red_pitaya_dac:1.0 dac_0 {} { +cell open-mri:user:axis_red_pitaya_dac:1.1 dac_0 {} { aclk pll_0/clk_out1 ddr_clk pll_0/clk_out2 locked pll_0/locked diff --git a/HDL/projects/ocra_mri/nco.tcl b/HDL/projects/ocra_mri/nco.tcl index 42047a69..9c3315fe 100644 --- a/HDL/projects/ocra_mri/nco.tcl +++ b/HDL/projects/ocra_mri/nco.tcl @@ -3,6 +3,8 @@ # 2017 by Thomas Witzel # block design for the NCO +global dsp_clk_freq + # Create xlslice cell xilinx.com:ip:xlslice:1.0 slice_1 { DIN_WIDTH 32 DIN_FROM 31 DIN_TO 0 DOUT_WIDTH 32 diff --git a/HDL/projects/ocra_mri/rx2.tcl b/HDL/projects/ocra_mri/rx2.tcl index 64b8bd5d..db186fe2 100644 --- a/HDL/projects/ocra_mri/rx2.tcl +++ b/HDL/projects/ocra_mri/rx2.tcl @@ -1,3 +1,5 @@ +global dsp_clk_freq + # Create xlslice # Trigger slice on Bit 1 (RX pulse) cell xilinx.com:ip:xlslice:1.0 slice_0 { @@ -83,7 +85,7 @@ cell xilinx.com:ip:cic_compiler:4.0 cic_0 { MINIMUM_RATE 25 MAXIMUM_RATE 8192 FIXED_OR_INITIAL_RATE 625 - INPUT_SAMPLE_FREQUENCY 125 + INPUT_SAMPLE_FREQUENCY $dsp_clk_freq CLOCK_FREQUENCY 125 INPUT_DATA_WIDTH 24 QUANTIZATION Truncation @@ -107,7 +109,7 @@ cell xilinx.com:ip:cic_compiler:4.0 cic_1 { MINIMUM_RATE 25 MAXIMUM_RATE 8192 FIXED_OR_INITIAL_RATE 625 - INPUT_SAMPLE_FREQUENCY 125 + INPUT_SAMPLE_FREQUENCY $dsp_clk_freq CLOCK_FREQUENCY 125 INPUT_DATA_WIDTH 24 QUANTIZATION Truncation From ef0bb7cad2b3a98c86eb90676c820f65d4846398 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 3 Dec 2023 15:37:13 -0800 Subject: [PATCH 04/96] new DAC core --- .../axis_red_pitaya_dac.v | 80 +++++++++++++++++++ .../axis_red_pitaya_dac_v1_1/core_config.tcl | 17 ++++ 2 files changed, 97 insertions(+) create mode 100644 HDL/cores/axis_red_pitaya_dac_v1_1/axis_red_pitaya_dac.v create mode 100644 HDL/cores/axis_red_pitaya_dac_v1_1/core_config.tcl diff --git a/HDL/cores/axis_red_pitaya_dac_v1_1/axis_red_pitaya_dac.v b/HDL/cores/axis_red_pitaya_dac_v1_1/axis_red_pitaya_dac.v new file mode 100644 index 00000000..6d3f6d02 --- /dev/null +++ b/HDL/cores/axis_red_pitaya_dac_v1_1/axis_red_pitaya_dac.v @@ -0,0 +1,80 @@ + +`timescale 1 ns / 1 ps + +module axis_red_pitaya_dac # +( + parameter integer DAC_DATA_WIDTH = 14, + parameter integer AXIS_TDATA_WIDTH = 32 +) +( + // PLL signals + input wire aclk, + input wire ddr_clk, + input wire locked, + + // DAC signals + output wire dac_clk, + output wire dac_rst, + output wire dac_sel, + output wire dac_wrt, + output wire [DAC_DATA_WIDTH-1:0] dac_dat, + + // Slave side + output wire s_axis_tready, + input wire [AXIS_TDATA_WIDTH-1:0] s_axis_tdata, + input wire s_axis_tvalid +); + + reg [DAC_DATA_WIDTH-1:0] int_dat_a_reg; + reg [DAC_DATA_WIDTH-1:0] int_dat_b_reg; + reg int_rst_reg; + + wire [DAC_DATA_WIDTH-1:0] int_dat_a_wire; + wire [DAC_DATA_WIDTH-1:0] int_dat_b_wire; + + localparam PAD = AXIS_TDATA_WIDTH/2 - DAC_DATA_WIDTH; + + // Make sure we take the 14 MSB, not LSB + assign int_dat_a_wire = s_axis_tdata[AXIS_TDATA_WIDTH/2-1:PAD]; + assign int_dat_b_wire = s_axis_tdata[AXIS_TDATA_WIDTH-1:AXIS_TDATA_WIDTH/2+PAD]; + + genvar j; + + always @(posedge aclk) + begin + if(~locked | ~s_axis_tvalid) + begin + int_dat_a_reg <= {(DAC_DATA_WIDTH){1'b0}}; + int_dat_b_reg <= {(DAC_DATA_WIDTH){1'b0}}; + end + else + begin + int_dat_a_reg <= {int_dat_a_wire[DAC_DATA_WIDTH-1], ~int_dat_a_wire[DAC_DATA_WIDTH-2:0]}; + int_dat_b_reg <= {int_dat_b_wire[DAC_DATA_WIDTH-1], ~int_dat_b_wire[DAC_DATA_WIDTH-2:0]}; + end + int_rst_reg <= ~locked | ~s_axis_tvalid; + end + + ODDR ODDR_rst(.Q(dac_rst), .D1(int_rst_reg), .D2(int_rst_reg), .C(aclk), .CE(1'b1), .R(1'b0), .S(1'b0)); + ODDR ODDR_sel(.Q(dac_sel), .D1(1'b0), .D2(1'b1), .C(aclk), .CE(1'b1), .R(1'b0), .S(1'b0)); + ODDR ODDR_wrt(.Q(dac_wrt), .D1(1'b0), .D2(1'b1), .C(ddr_clk), .CE(1'b1), .R(1'b0), .S(1'b0)); + ODDR ODDR_clk(.Q(dac_clk), .D1(1'b0), .D2(1'b1), .C(ddr_clk), .CE(1'b1), .R(1'b0), .S(1'b0)); + + generate + for(j = 0; j < DAC_DATA_WIDTH; j = j + 1) + begin : DAC_DAT + ODDR ODDR_inst( + .Q(dac_dat[j]), + .D1(int_dat_a_reg[j]), + .D2(int_dat_b_reg[j]), + .C(aclk), + .CE(1'b1), + .R(1'b0), + .S(1'b0) + ); + end + endgenerate + + assign s_axis_tready = 1'b1; + +endmodule diff --git a/HDL/cores/axis_red_pitaya_dac_v1_1/core_config.tcl b/HDL/cores/axis_red_pitaya_dac_v1_1/core_config.tcl new file mode 100644 index 00000000..d6bf45ff --- /dev/null +++ b/HDL/cores/axis_red_pitaya_dac_v1_1/core_config.tcl @@ -0,0 +1,17 @@ +set display_name {AXI4-Stream Red Pitaya DAC} + +set core [ipx::current_core] + +set_property DISPLAY_NAME $display_name $core +set_property DESCRIPTION $display_name $core + +core_parameter AXIS_TDATA_WIDTH {AXIS TDATA WIDTH} {Width of the S_AXIS data bus.} +core_parameter DAC_DATA_WIDTH {DAC DATA WIDTH} {Width of the DAC data bus.} + +set bus [ipx::get_bus_interfaces -of_objects $core s_axis] +set_property NAME S_AXIS $bus +set_property INTERFACE_MODE slave $bus + +set bus [ipx::get_bus_interfaces aclk] +set parameter [ipx::get_bus_parameters -of_objects $bus ASSOCIATED_BUSIF] +set_property VALUE S_AXIS $parameter From d7bd152a693733c91601c451e8911ec00d3bd4b0 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Mon, 4 Dec 2023 19:08:51 -0800 Subject: [PATCH 05/96] reduced bitwidth of fir filter and adjusted floating point format --- HDL/projects/ocra_mri/rx2.tcl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HDL/projects/ocra_mri/rx2.tcl b/HDL/projects/ocra_mri/rx2.tcl index db186fe2..e105cded 100644 --- a/HDL/projects/ocra_mri/rx2.tcl +++ b/HDL/projects/ocra_mri/rx2.tcl @@ -161,7 +161,7 @@ cell xilinx.com:ip:fir_compiler:7.2 fir_0 { SAMPLE_FREQUENCY 5.0 CLOCK_FREQUENCY 125 OUTPUT_ROUNDING_MODE Convergent_Rounding_to_Even - OUTPUT_WIDTH 26 + OUTPUT_WIDTH 24 M_DATA_HAS_TREADY true HAS_ARESETN true } { @@ -190,8 +190,8 @@ cell xilinx.com:ip:floating_point:7.1 fp_0 { C_A_EXPONENT_WIDTH.VALUE_SRC USER C_A_FRACTION_WIDTH.VALUE_SRC USER A_PRECISION_TYPE Custom - C_A_EXPONENT_WIDTH 2 - C_A_FRACTION_WIDTH 22 + C_A_EXPONENT_WIDTH 8 + C_A_FRACTION_WIDTH 24 RESULT_PRECISION_TYPE Single HAS_ARESETN true } { From b14a5eb4d22105d8d0dd4e3fba8b1f9f28400eb4 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Tue, 5 Dec 2023 17:31:24 -0800 Subject: [PATCH 06/96] remove fp conversion from FPGA and move into server --- Applications/relax2/server/relax_server_dev.c | 80 ++++++++++++------- HDL/projects/ocra_mri/rx2.tcl | 36 +-------- 2 files changed, 53 insertions(+), 63 deletions(-) diff --git a/Applications/relax2/server/relax_server_dev.c b/Applications/relax2/server/relax_server_dev.c index e7887228..09616e59 100644 --- a/Applications/relax2/server/relax_server_dev.c +++ b/Applications/relax2/server/relax_server_dev.c @@ -8336,6 +8336,21 @@ void update_RF_pulses(volatile uint16_t *tx_size, void *tx_data, int32_t RF_amp memcpy(tx_data, pulse, 2 * size); } +typedef union mixer { + uint64_t x; + int32_t y[2]; + float z[2]; +} mixer_t; + +// new function to take over the conversion to float, because it would be tough in numpy +uint64_t cast_int32cplx_float32cplx(uint64_t x) +{ + mixer_t X,Y; + X.x = x; + Y.z[0] = (float)(X.y[0]); + Y.z[1] = (float)(X.y[1]); + return Y.x; +} int main(int argc) { @@ -8707,7 +8722,11 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) { + + buffer[j] = cast_int32cplx_float32cplx(*rx_data); + + } send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -8761,7 +8780,8 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) + buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -8815,7 +8835,7 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -8871,7 +8891,7 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -8931,7 +8951,7 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -8989,7 +9009,7 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9035,7 +9055,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9079,7 +9099,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9123,7 +9143,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9168,7 +9188,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9212,7 +9232,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9258,7 +9278,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9300,7 +9320,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9351,7 +9371,7 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 5000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9405,7 +9425,7 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9461,7 +9481,7 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9514,7 +9534,7 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9561,7 +9581,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9606,7 +9626,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9652,7 +9672,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9697,7 +9717,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9744,7 +9764,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9791,7 +9811,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9837,7 +9857,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9894,7 +9914,7 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9936,7 +9956,7 @@ int main(int argc) //printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -9988,7 +10008,7 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -10002,7 +10022,7 @@ int main(int argc) usleep(1000000); // Sleep 1s for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -10056,7 +10076,7 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; @@ -10070,7 +10090,7 @@ int main(int argc) // printf("Number of RX samples in FIFO: %d\n",*rx_cntr); for(i = 0; i < 10; ++i) { while(*rx_cntr < 10000) usleep(500); - for(j = 0; j < 5000; ++j) buffer[j] = *rx_data; + for(j = 0; j < 5000; ++j) buffer[j] = cast_int32cplx_float32cplx(*rx_data); send(sock_client, buffer, 5000*8, MSG_NOSIGNAL | (i<9?MSG_MORE:0)); } seq_config[0] = 0x00000000; diff --git a/HDL/projects/ocra_mri/rx2.tcl b/HDL/projects/ocra_mri/rx2.tcl index e105cded..f9b5faa0 100644 --- a/HDL/projects/ocra_mri/rx2.tcl +++ b/HDL/projects/ocra_mri/rx2.tcl @@ -161,7 +161,7 @@ cell xilinx.com:ip:fir_compiler:7.2 fir_0 { SAMPLE_FREQUENCY 5.0 CLOCK_FREQUENCY 125 OUTPUT_ROUNDING_MODE Convergent_Rounding_to_Even - OUTPUT_WIDTH 24 + OUTPUT_WIDTH 32 M_DATA_HAS_TREADY true HAS_ARESETN true } { @@ -170,43 +170,13 @@ cell xilinx.com:ip:fir_compiler:7.2 fir_0 { aresetn /rst_0/peripheral_aresetn } -# Create axis_subset_converter -cell xilinx.com:ip:axis_subset_converter:1.1 subset_0 { - S_TDATA_NUM_BYTES.VALUE_SRC USER - M_TDATA_NUM_BYTES.VALUE_SRC USER - S_TDATA_NUM_BYTES 4 - M_TDATA_NUM_BYTES 3 - TDATA_REMAP {tdata[23:0]} -} { - S_AXIS fir_0/M_AXIS_DATA - aclk /ps_0/FCLK_CLK0 - aresetn /rst_0/peripheral_aresetn -} - -# Create floating_point -cell xilinx.com:ip:floating_point:7.1 fp_0 { - OPERATION_TYPE Fixed_to_float - A_PRECISION_TYPE.VALUE_SRC USER - C_A_EXPONENT_WIDTH.VALUE_SRC USER - C_A_FRACTION_WIDTH.VALUE_SRC USER - A_PRECISION_TYPE Custom - C_A_EXPONENT_WIDTH 8 - C_A_FRACTION_WIDTH 24 - RESULT_PRECISION_TYPE Single - HAS_ARESETN true -} { - S_AXIS_A subset_0/M_AXIS - aclk /ps_0/FCLK_CLK0 - aresetn /rst_0/peripheral_aresetn -} - -# Create axis_dwidth_converter +# Convert the 64 bit wide complex word into sequential 32 bit words of real and imag cell xilinx.com:ip:axis_dwidth_converter:1.1 conv_1 { S_TDATA_NUM_BYTES.VALUE_SRC USER S_TDATA_NUM_BYTES 4 M_TDATA_NUM_BYTES 8 } { - S_AXIS fp_0/M_AXIS_RESULT + S_AXIS fir_0/M_AXIS_DATA aclk /ps_0/FCLK_CLK0 aresetn /rst_0/peripheral_aresetn } From 4bc605037da5dc5a1be56d5c4b59a450a99d95a6 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Tue, 5 Dec 2023 17:32:27 -0800 Subject: [PATCH 07/96] set execution permission on cross-build script --- Applications/relax2/server/cross-build.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 Applications/relax2/server/cross-build.sh diff --git a/Applications/relax2/server/cross-build.sh b/Applications/relax2/server/cross-build.sh old mode 100644 new mode 100755 From 270d9ccff7f5524f8c6addc888ee426de54e7d91 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 6 Dec 2023 10:16:53 -0800 Subject: [PATCH 08/96] added packing to union, probably not necessary --- Applications/relax2/server/relax_server_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Applications/relax2/server/relax_server_dev.c b/Applications/relax2/server/relax_server_dev.c index 09616e59..7a60a030 100644 --- a/Applications/relax2/server/relax_server_dev.c +++ b/Applications/relax2/server/relax_server_dev.c @@ -8336,7 +8336,7 @@ void update_RF_pulses(volatile uint16_t *tx_size, void *tx_data, int32_t RF_amp memcpy(tx_data, pulse, 2 * size); } -typedef union mixer { +typedef __attribute__((packed)) union mixer { uint64_t x; int32_t y[2]; float z[2]; From c4d535e472a7d556abb191ec7009e74e596c0d1b Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 15 Sep 2024 17:25:03 -0700 Subject: [PATCH 09/96] don't build device tree by default --- HDL/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HDL/Makefile b/HDL/Makefile index 90548bbf..baea8e6c 100644 --- a/HDL/Makefile +++ b/HDL/Makefile @@ -34,7 +34,7 @@ DTREE_URL = https://github.com/Xilinx/device-tree-xlnx/ .PHONY: clean all xpr bit dtbo setup .ONESHELL: -all: setup tmp/%.bin tmp/%.dtbo +all: setup tmp/%.bin .ONESHELL: From b6bd1070d81f18d30bcc09ebbddf9afda177d2b0 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 15 Sep 2024 17:26:10 -0700 Subject: [PATCH 10/96] add .Xil to gitignore --- HDL/.gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HDL/.gitignore b/HDL/.gitignore index 83d92837..b5d5df77 100644 --- a/HDL/.gitignore +++ b/HDL/.gitignore @@ -3,4 +3,5 @@ uImage devicetree.dtb *~ tmp/ -vivado* \ No newline at end of file +vivado* +.Xil/ \ No newline at end of file From 2db1ea8eaae39a605010e731ba45975287ba0e20 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 15 Sep 2024 17:36:34 -0700 Subject: [PATCH 11/96] updated the Makefile to use the 2024.1 device tree compiler updated the README --- HDL/Makefile | 2 +- HDL/README.md | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/HDL/Makefile b/HDL/Makefile index baea8e6c..692efa0d 100644 --- a/HDL/Makefile +++ b/HDL/Makefile @@ -23,7 +23,7 @@ RM = rm -rf VIVADO_VER = $(shell vivado -version | grep "v20" | sed -r 's/.*v(20[0-9]{2}.[0-9]).*/\1/g') -DTREE_TAG = xlnx_rel_v2022.2 +DTREE_TAG = xlnx_rel_v2024.1 DTREE_DIR = tmp/device-tree-xlnx-$(DTREE_TAG) DTREE_URL = https://github.com/Xilinx/device-tree-xlnx/ diff --git a/HDL/README.md b/HDL/README.md index 833cd580..17b20af8 100644 --- a/HDL/README.md +++ b/HDL/README.md @@ -2,11 +2,11 @@ This directory contains all the HDL code of the ocra project. The code is organized in projects, which can be found in subdirectories of the projects folders. -In order to build the HDL code you need to have Xilinx Vitis 2022.2 full edition. We highly recommend that you use Linux, because the build system and other tooling relies on Linux. We are working on and recommend [Ubuntu 22.04 LTS](https://ubuntu.com/download/desktop). +In order to build the HDL code you need to have at least Xilinx Vitis 2022.2 full edition. This build has been tested up to Vitis 2024.1. We highly recommend that you use Linux, because the build system and other tooling relies on Linux. We are working on and recommend [Ubuntu 22.04 LTS or Ubuntu 24.04 LTS](https://ubuntu.com/download/desktop). **Basic working knowledge of Linux and bash is more or less required to follow these instructions.** -In order to install Vitis you will need about 110 GB of free disk space, and you will need to register an account with Xilinx website (remember the password, because the installer will also require the same login credentials that you created on the Xilinx website. It is best to download the [Vitis web installer](https://www.xilinx.com/member/forms/download/xef.html?filename=Xilinx_Unified_2022.2_1014_8888_Lin64.bin). +In order to install Vitis you will need about 110 GB of free disk space, and you will need to register an account with Xilinx website (remember the password, because the installer will also require the same login credentials that you created on the Xilinx website. It is best to download the [Vitis web installer](https://account.amd.com/en/forms/downloads/xef.html?filename=FPGAs_AdaptiveSoCs_Unified_2024.1_0522_2023_Lin64.bin). Vivado (the main tool in the Vitis package) is a bit of a beast and requires a reasonably powerful workstation. @@ -15,15 +15,18 @@ All building of the HDL is done by a [GNU Makefile](https://www.gnu.org/software This makes it straightforward to build multiple projects etc. from the command line without having to wrestle the Vivado GUI. This entire setup is based on the [red-pitaya-notes](https://github.com/pavel-demin/red-pitaya-notes) by Pavel Demin, and some of his architecture and cores can also be found in this repository. This repository makes use of Vivado board files, which requires additional configuration of your Vivado/Vitis setup. In order to make everything work the following configuration steps need to be taken: -1. Add `source /tools/Xilinx/Vitis/2022.2/settings64.sh` to your `.bash_profile` +1. Add `source /tools/Xilinx/Vitis/2024.1/settings64.sh` to your `.bash_profile` 1. Define the environment variable OCRA_DIR in your `.bash_profile` to point to the ocra directory -2. Include the following in your local Vivado config (i.e. $HOME/.Xilinx/Vivado/2022.2/Vivado_init.tcl): +2. Include the following in your local Vivado config (i.e. $HOME/.Xilinx/Vivado/2024.1/Vivado_init.tcl): ``` # set up the OCRA project set ocra_dir $::env(OCRA_DIR) source $ocra_dir/HDL/scripts/Vivado_ocra_init.tcl ``` +You may need to adjust the path of your Vitis installation as appropriate for this to be correct on your installation. + + To get a quick start, assuming you have Vitis/Vivado configured in your path, you should be able to build the base_pl project for the snickerdoodle_black ``` cd $OCRA_DIR/HDL @@ -35,4 +38,12 @@ Similarily, you can build the ocra_mri project for the stemlab_125_14 by calling make NAME=ocra_mri BOARD=stemlab_125_14 ``` +This will build bitfiles that can be used with on a Linux installation on your Zynq so long it supports the fpga_manager. If you want to build a device tree and the associated files to create your own bootloader etc. you need to run + +``` +make dtbo NAME=ocra_mri BOARD=stemlab_125_14 +``` + +Note that this requires the HSI tool xsct and the device tree compiler dtc. + This is pretty easy, isn't it? \ No newline at end of file From c5dfb1cf224d645594b08e6fa27bde95b3c7b9fb Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 15 Sep 2024 21:04:32 -0700 Subject: [PATCH 12/96] start moving properties for the ports to the ports.tcl This might allow us to set the properties for pins that are optimized away, as opposed to using the constraints that will create a whole bunch of warnings when trying to constrain a pin that isn't used in the project Also try and update the README a little more --- HDL/README.md | 8 +- HDL/boards/stemlab_125_14/ports.tcl | 50 ++++++++-- HDL/boards/stemlab_125_14/ports.xdc | 133 +++++++++++-------------- HDL/projects/ocra_mri/block_design.tcl | 10 -- 4 files changed, 109 insertions(+), 92 deletions(-) diff --git a/HDL/README.md b/HDL/README.md index 17b20af8..e4d0595c 100644 --- a/HDL/README.md +++ b/HDL/README.md @@ -37,13 +37,17 @@ Similarily, you can build the ocra_mri project for the stemlab_125_14 by calling ``` make NAME=ocra_mri BOARD=stemlab_125_14 ``` +This will build bitfiles that can be used with on a Linux installation on your Zynq so long it supports the fpga_manager. -This will build bitfiles that can be used with on a Linux installation on your Zynq so long it supports the fpga_manager. If you want to build a device tree and the associated files to create your own bootloader etc. you need to run +Sometimes you might want to only quickly generate the project file for Vivado, which you make by calling: +``` +make xpr NAME=ocra_mri BOARD=stemlab_125_14 +``` +If you want to build a device tree and the associated files to create your own bootloader etc. you need to run: ``` make dtbo NAME=ocra_mri BOARD=stemlab_125_14 ``` - Note that this requires the HSI tool xsct and the device tree compiler dtc. This is pretty easy, isn't it? \ No newline at end of file diff --git a/HDL/boards/stemlab_125_14/ports.tcl b/HDL/boards/stemlab_125_14/ports.tcl index 5823941c..c4a19984 100644 --- a/HDL/boards/stemlab_125_14/ports.tcl +++ b/HDL/boards/stemlab_125_14/ports.tcl @@ -26,18 +26,56 @@ create_bd_port -dir O dac_wrt_o create_bd_port -dir O -from 3 -to 0 dac_pwm_o ### XADC - -create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vp_Vn -create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vaux0 -create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vaux1 -create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vaux9 -create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vaux8 +# create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vp_Vn +# create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vaux0 +# create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vaux1 +# create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vaux9 +# create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vaux8 ### Expansion connector create_bd_port -dir IO -from 7 -to 0 exp_p_tri_io create_bd_port -dir IO -from 7 -to 0 exp_n_tri_io +set_property IOSTANDARD LVCMOS33 [get_ports {exp_p_tri_io[*]}] +set_property IOSTANDARD LVCMOS33 [get_ports {exp_n_tri_io[*]}] +set_property SLEW FAST [get_ports {exp_p_tri_io[*]}] +set_property SLEW FAST [get_ports {exp_n_tri_io[*]}] +set_property DRIVE 8 [get_ports {exp_p_tri_io[*]}] +set_property DRIVE 8 [get_ports {exp_n_tri_io[*]}] +set_property PULLTYPE PULLUP [get_ports {exp_p_tri_io[*]}] +set_property PULLTYPE PULLUP [get_ports {exp_n_tri_io[*]}] + +set_property PACKAGE_PIN G17 [get_ports {exp_p_tri_io[0]}] +set_property PACKAGE_PIN G18 [get_ports {exp_n_tri_io[0]}] +set_property PACKAGE_PIN H16 [get_ports {exp_p_tri_io[1]}] +set_property PACKAGE_PIN H17 [get_ports {exp_n_tri_io[1]}] +set_property PACKAGE_PIN J18 [get_ports {exp_p_tri_io[2]}] +set_property PACKAGE_PIN H18 [get_ports {exp_n_tri_io[2]}] +set_property PACKAGE_PIN K17 [get_ports {exp_p_tri_io[3]}] +set_property PACKAGE_PIN K18 [get_ports {exp_n_tri_io[3]}] +set_property PACKAGE_PIN L14 [get_ports {exp_p_tri_io[4]}] +set_property PACKAGE_PIN L15 [get_ports {exp_n_tri_io[4]}] +set_property PACKAGE_PIN L16 [get_ports {exp_p_tri_io[5]}] +set_property PACKAGE_PIN L17 [get_ports {exp_n_tri_io[5]}] +set_property PACKAGE_PIN K16 [get_ports {exp_p_tri_io[6]}] +set_property PACKAGE_PIN J16 [get_ports {exp_n_tri_io[6]}] +set_property PACKAGE_PIN M14 [get_ports {exp_p_tri_io[7]}] +set_property PACKAGE_PIN M15 [get_ports {exp_n_tri_io[7]}] + ### LED create_bd_port -dir O -from 7 -to 0 led_o + +set_property IOSTANDARD LVCMOS33 [get_ports {led_o[*]}] +set_property SLEW SLOW [get_ports {led_o[*]}] +set_property DRIVE 8 [get_ports {led_o[*]}] + +set_property PACKAGE_PIN F16 [get_ports {led_o[0]}] +set_property PACKAGE_PIN F17 [get_ports {led_o[1]}] +set_property PACKAGE_PIN G15 [get_ports {led_o[2]}] +set_property PACKAGE_PIN H15 [get_ports {led_o[3]}] +set_property PACKAGE_PIN K14 [get_ports {led_o[4]}] +set_property PACKAGE_PIN G14 [get_ports {led_o[5]}] +set_property PACKAGE_PIN J15 [get_ports {led_o[6]}] +set_property PACKAGE_PIN J14 [get_ports {led_o[7]}] \ No newline at end of file diff --git a/HDL/boards/stemlab_125_14/ports.xdc b/HDL/boards/stemlab_125_14/ports.xdc index 790160c7..4fd2f530 100644 --- a/HDL/boards/stemlab_125_14/ports.xdc +++ b/HDL/boards/stemlab_125_14/ports.xdc @@ -1,4 +1,3 @@ - # set_property CFGBVS VCCO [current_design] # set_property CONFIG_VOLTAGE 3.3 [current_design] @@ -120,90 +119,76 @@ set_property PACKAGE_PIN U13 [get_ports {dac_pwm_o[3]}] ### XADC -set_property IOSTANDARD LVCMOS33 [get_ports Vp_Vn_v_p] -set_property IOSTANDARD LVCMOS33 [get_ports Vp_Vn_v_n] -set_property IOSTANDARD LVCMOS33 [get_ports Vaux0_v_p] -set_property IOSTANDARD LVCMOS33 [get_ports Vaux0_v_n] -set_property IOSTANDARD LVCMOS33 [get_ports Vaux1_v_p] -set_property IOSTANDARD LVCMOS33 [get_ports Vaux1_v_n] -set_property IOSTANDARD LVCMOS33 [get_ports Vaux8_v_p] -set_property IOSTANDARD LVCMOS33 [get_ports Vaux8_v_n] -set_property IOSTANDARD LVCMOS33 [get_ports Vaux9_v_p] -set_property IOSTANDARD LVCMOS33 [get_ports Vaux9_v_n] - -set_property PACKAGE_PIN K9 [get_ports Vp_Vn_v_p] -set_property PACKAGE_PIN L10 [get_ports Vp_Vn_v_n] -set_property PACKAGE_PIN C20 [get_ports Vaux0_v_p] -set_property PACKAGE_PIN B20 [get_ports Vaux0_v_n] -set_property PACKAGE_PIN E17 [get_ports Vaux1_v_p] -set_property PACKAGE_PIN D18 [get_ports Vaux1_v_n] -set_property PACKAGE_PIN B19 [get_ports Vaux8_v_p] -set_property PACKAGE_PIN A20 [get_ports Vaux8_v_n] -set_property PACKAGE_PIN E18 [get_ports Vaux9_v_p] -set_property PACKAGE_PIN E19 [get_ports Vaux9_v_n] +# set_property IOSTANDARD LVCMOS33 [get_ports Vp_Vn_v_p] +# set_property IOSTANDARD LVCMOS33 [get_ports Vp_Vn_v_n] +# set_property IOSTANDARD LVCMOS33 [get_ports Vaux0_v_p] +# set_property IOSTANDARD LVCMOS33 [get_ports Vaux0_v_n] +# set_property IOSTANDARD LVCMOS33 [get_ports Vaux1_v_p] +# set_property IOSTANDARD LVCMOS33 [get_ports Vaux1_v_n] +# set_property IOSTANDARD LVCMOS33 [get_ports Vaux8_v_p] +# set_property IOSTANDARD LVCMOS33 [get_ports Vaux8_v_n] +# set_property IOSTANDARD LVCMOS33 [get_ports Vaux9_v_p] +# set_property IOSTANDARD LVCMOS33 [get_ports Vaux9_v_n] + +# set_property PACKAGE_PIN K9 [get_ports Vp_Vn_v_p] +# set_property PACKAGE_PIN L10 [get_ports Vp_Vn_v_n] +# set_property PACKAGE_PIN C20 [get_ports Vaux0_v_p] +# set_property PACKAGE_PIN B20 [get_ports Vaux0_v_n] +# set_property PACKAGE_PIN E17 [get_ports Vaux1_v_p] +# set_property PACKAGE_PIN D18 [get_ports Vaux1_v_n] +# set_property PACKAGE_PIN B19 [get_ports Vaux8_v_p] +# set_property PACKAGE_PIN A20 [get_ports Vaux8_v_n] +# set_property PACKAGE_PIN E18 [get_ports Vaux9_v_p] +# set_property PACKAGE_PIN E19 [get_ports Vaux9_v_n] ### Expansion connector -set_property IOSTANDARD LVCMOS33 [get_ports {exp_p_tri_io[*]}] -set_property IOSTANDARD LVCMOS33 [get_ports {exp_n_tri_io[*]}] -set_property SLEW FAST [get_ports {exp_p_tri_io[*]}] -set_property SLEW FAST [get_ports {exp_n_tri_io[*]}] -set_property DRIVE 8 [get_ports {exp_p_tri_io[*]}] -set_property DRIVE 8 [get_ports {exp_n_tri_io[*]}] -set_property PULLTYPE PULLUP [get_ports {exp_p_tri_io[*]}] -set_property PULLTYPE PULLUP [get_ports {exp_n_tri_io[*]}] - -set_property PACKAGE_PIN G17 [get_ports {exp_p_tri_io[0]}] -set_property PACKAGE_PIN G18 [get_ports {exp_n_tri_io[0]}] -set_property PACKAGE_PIN H16 [get_ports {exp_p_tri_io[1]}] -set_property PACKAGE_PIN H17 [get_ports {exp_n_tri_io[1]}] -set_property PACKAGE_PIN J18 [get_ports {exp_p_tri_io[2]}] -set_property PACKAGE_PIN H18 [get_ports {exp_n_tri_io[2]}] -set_property PACKAGE_PIN K17 [get_ports {exp_p_tri_io[3]}] -set_property PACKAGE_PIN K18 [get_ports {exp_n_tri_io[3]}] -set_property PACKAGE_PIN L14 [get_ports {exp_p_tri_io[4]}] -set_property PACKAGE_PIN L15 [get_ports {exp_n_tri_io[4]}] -set_property PACKAGE_PIN L16 [get_ports {exp_p_tri_io[5]}] -set_property PACKAGE_PIN L17 [get_ports {exp_n_tri_io[5]}] -set_property PACKAGE_PIN K16 [get_ports {exp_p_tri_io[6]}] -set_property PACKAGE_PIN J16 [get_ports {exp_n_tri_io[6]}] -set_property PACKAGE_PIN M14 [get_ports {exp_p_tri_io[7]}] -set_property PACKAGE_PIN M15 [get_ports {exp_n_tri_io[7]}] - -set_property IOSTANDARD LVCMOS33 [get_ports exp_p_trg] -set_property SLEW FAST [get_ports exp_p_trg] -set_property DRIVE 8 [get_ports exp_p_trg] - -set_property PACKAGE_PIN M14 [get_ports exp_p_trg] - -set_property IOSTANDARD LVCMOS33 [get_ports {exp_n_alex[*]}] -set_property SLEW FAST [get_ports {exp_n_alex[*]}] -set_property DRIVE 8 [get_ports {exp_n_alex[*]}] - -set_property PACKAGE_PIN L15 [get_ports {exp_n_alex[0]}] -set_property PACKAGE_PIN L17 [get_ports {exp_n_alex[1]}] -set_property PACKAGE_PIN J16 [get_ports {exp_n_alex[2]}] -set_property PACKAGE_PIN M15 [get_ports {exp_n_alex[3]}] +# set_property IOSTANDARD LVCMOS33 [get_ports {exp_p_tri_io[*]}] +# set_property IOSTANDARD LVCMOS33 [get_ports {exp_n_tri_io[*]}] +# set_property SLEW FAST [get_ports {exp_p_tri_io[*]}] +# set_property SLEW FAST [get_ports {exp_n_tri_io[*]}] +# set_property DRIVE 8 [get_ports {exp_p_tri_io[*]}] +# set_property DRIVE 8 [get_ports {exp_n_tri_io[*]}] +# set_property PULLTYPE PULLUP [get_ports {exp_p_tri_io[*]}] +# set_property PULLTYPE PULLUP [get_ports {exp_n_tri_io[*]}] + +# set_property PACKAGE_PIN G17 [get_ports {exp_p_tri_io[0]}] +# set_property PACKAGE_PIN G18 [get_ports {exp_n_tri_io[0]}] +# set_property PACKAGE_PIN H16 [get_ports {exp_p_tri_io[1]}] +# set_property PACKAGE_PIN H17 [get_ports {exp_n_tri_io[1]}] +# set_property PACKAGE_PIN J18 [get_ports {exp_p_tri_io[2]}] +# set_property PACKAGE_PIN H18 [get_ports {exp_n_tri_io[2]}] +# set_property PACKAGE_PIN K17 [get_ports {exp_p_tri_io[3]}] +# set_property PACKAGE_PIN K18 [get_ports {exp_n_tri_io[3]}] +# set_property PACKAGE_PIN L14 [get_ports {exp_p_tri_io[4]}] +# set_property PACKAGE_PIN L15 [get_ports {exp_n_tri_io[4]}] +# set_property PACKAGE_PIN L16 [get_ports {exp_p_tri_io[5]}] +# set_property PACKAGE_PIN L17 [get_ports {exp_n_tri_io[5]}] +# set_property PACKAGE_PIN K16 [get_ports {exp_p_tri_io[6]}] +# set_property PACKAGE_PIN J16 [get_ports {exp_n_tri_io[6]}] +# set_property PACKAGE_PIN M14 [get_ports {exp_p_tri_io[7]}] +# set_property PACKAGE_PIN M15 [get_ports {exp_n_tri_io[7]}] + ### SATA connector -set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_p_o[*]] -set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_n_o[*]] +# set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_p_o[*]] +# set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_n_o[*]] -set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_p_i[*]] -set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_n_i[*]] +# set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_p_i[*]] +# set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_n_i[*]] -set_property PACKAGE_PIN T12 [get_ports {daisy_p_o[0]}] -set_property PACKAGE_PIN U12 [get_ports {daisy_n_o[0]}] +# set_property PACKAGE_PIN T12 [get_ports {daisy_p_o[0]}] +# set_property PACKAGE_PIN U12 [get_ports {daisy_n_o[0]}] -set_property PACKAGE_PIN U14 [get_ports {daisy_p_o[1]}] -set_property PACKAGE_PIN U15 [get_ports {daisy_n_o[1]}] +# set_property PACKAGE_PIN U14 [get_ports {daisy_p_o[1]}] +# set_property PACKAGE_PIN U15 [get_ports {daisy_n_o[1]}] -set_property PACKAGE_PIN P14 [get_ports {daisy_p_i[0]}] -set_property PACKAGE_PIN R14 [get_ports {daisy_n_i[0]}] +# set_property PACKAGE_PIN P14 [get_ports {daisy_p_i[0]}] +# set_property PACKAGE_PIN R14 [get_ports {daisy_n_i[0]}] -set_property PACKAGE_PIN N18 [get_ports {daisy_p_i[1]}] -set_property PACKAGE_PIN P19 [get_ports {daisy_n_i[1]}] +# set_property PACKAGE_PIN N18 [get_ports {daisy_p_i[1]}] +# set_property PACKAGE_PIN P19 [get_ports {daisy_n_i[1]}] ### LED diff --git a/HDL/projects/ocra_mri/block_design.tcl b/HDL/projects/ocra_mri/block_design.tcl index 75800427..bf4802ce 100644 --- a/HDL/projects/ocra_mri/block_design.tcl +++ b/HDL/projects/ocra_mri/block_design.tcl @@ -415,16 +415,6 @@ set_property -dict [list CONFIG.Register_PortB_Output_of_Memory_Primitives {true # # try to connect the bottom 8 bits of the pulse output of the sequencer to the positive gpoi # -# Delete input/output port -delete_bd_objs [get_bd_ports exp_p_tri_io] -delete_bd_objs [get_bd_ports exp_n_tri_io] - -# Create newoutput port -create_bd_port -dir O -from 7 -to 0 exp_p_tri_io -#connect_bd_net [get_bd_pins exp_p_tri_io] [get_bd_pins trigger_slice_0/Dout] - -# Create output port for the SPI stuff -create_bd_port -dir O -from 7 -to 0 exp_n_tri_io # 09/2019: For the new board we are doing this differently. The SPI bus will use seven pins on the n side of the header # and the txgate will use the eight' pin on the n side From 48d8b80c02dea75ee8723098ca4a5f5c8b014128 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 15 Sep 2024 21:20:35 -0700 Subject: [PATCH 13/96] remove unused tcl script --- HDL/scripts/app_cpu1.tcl | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 HDL/scripts/app_cpu1.tcl diff --git a/HDL/scripts/app_cpu1.tcl b/HDL/scripts/app_cpu1.tcl deleted file mode 100644 index 8fda3259..00000000 --- a/HDL/scripts/app_cpu1.tcl +++ /dev/null @@ -1,22 +0,0 @@ - -set project_name [lindex $argv 0] - -set proc_name ps7_cortexa9_1 - -set hard_path tmp/$project_name.hard -set cpu1_path tmp/$project_name.cpu1 - -file mkdir $hard_path -file copy -force tmp/$project_name.hwdef $hard_path/$project_name.hdf - -open_hw_design $hard_path/$project_name.hdf -create_sw_design -proc $proc_name -os standalone system - -set_property CONFIG.stdin {none} [get_os] -set_property CONFIG.stdout {none} [get_os] - -set_property CONFIG.extra_compiler_flags { -g -DUSE_AMP=1 -DSTDOUT_REDIR=1} [get_sw_processor] - -generate_bsp -proc $proc_name -dir $cpu1_path/app_cpu1_bsp - -close_hw_design [current_hw_design] From 8d0e4f87088c09ca44ef3d2c7f80f1a27829ee73 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 15 Sep 2024 21:21:21 -0700 Subject: [PATCH 14/96] remove a bunch of unneeded shell scripts --- HDL/scripts/debian-ecosystem.sh | 338 -------------------------------- HDL/scripts/debian-gnuradio.sh | 286 --------------------------- HDL/scripts/debian-wspr.sh | 301 ---------------------------- HDL/scripts/debian.sh | 281 -------------------------- HDL/scripts/ubuntu.sh | 266 ------------------------- 5 files changed, 1472 deletions(-) delete mode 100644 HDL/scripts/debian-ecosystem.sh delete mode 100644 HDL/scripts/debian-gnuradio.sh delete mode 100644 HDL/scripts/debian-wspr.sh delete mode 100644 HDL/scripts/debian.sh delete mode 100644 HDL/scripts/ubuntu.sh diff --git a/HDL/scripts/debian-ecosystem.sh b/HDL/scripts/debian-ecosystem.sh deleted file mode 100644 index 82a00453..00000000 --- a/HDL/scripts/debian-ecosystem.sh +++ /dev/null @@ -1,338 +0,0 @@ -device=$1 - -boot_dir=`mktemp -d /tmp/BOOT.XXXXXXXXXX` -root_dir=`mktemp -d /tmp/ROOT.XXXXXXXXXX` - -ecosystem_tar=red-pitaya-ecosystem-0.95-20160526.tgz -ecosystem_url=https://www.dropbox.com/sh/5fy49wae6xwxa8a/AADrueq0P1OJFy9z6AaJ72nWa/red-pitaya-ecosystem/red-pitaya-ecosystem-0.95-20160526.tgz?dl=1 - -# Choose mirror automatically, depending the geographic and network location -mirror=http://httpredir.debian.org/debian - -distro=jessie -arch=armhf - -hostapd_url=https://www.dropbox.com/sh/5fy49wae6xwxa8a/AAAQHa5NkpLYFocaOrrnft-Pa/rtl8192cu/hostapd-armhf?dl=1 - -passwd=changeme -timezone=Europe/Brussels - -# Create partitions - -parted -s $device mklabel msdos -parted -s $device mkpart primary fat16 4MB 16MB -parted -s $device mkpart primary ext4 16MB 100% - -boot_dev=/dev/`lsblk -lno NAME $device | sed '2!d'` -root_dev=/dev/`lsblk -lno NAME $device | sed '3!d'` - -# Create file systems - -mkfs.vfat -v $boot_dev -mkfs.ext4 -F -j $root_dev - -# Mount file systems - -mount $boot_dev $boot_dir -mount $root_dev $root_dir - -# Copy files to the boot file system - -cp boot.bin devicetree.dtb uImage uEnv.txt $boot_dir - -# Install Debian base system to the root file system - -debootstrap --foreign --arch $arch $distro $root_dir $mirror - -# Add missing configuration files and packages - -cp /etc/resolv.conf $root_dir/etc/ -cp /usr/bin/qemu-arm-static $root_dir/usr/bin/ - -cp patches/fw_env.config $root_dir/etc/ - -mkdir -p $root_dir/usr/local/bin -cp fw_printenv $root_dir/usr/local/bin/fw_printenv -cp fw_printenv $root_dir/usr/local/bin/fw_setenv - -mkdir -p $root_dir/usr/local/sbin -curl -L $hostapd_url -o $root_dir/usr/local/sbin/hostapd -chmod +x $root_dir/usr/local/sbin/hostapd - -test -f $ecosystem_tar || curl -L $ecosystem_url -o $ecosystem_tar - -mkdir -p $root_dir/var/log/nginx -mkdir -p $root_dir/var/log/redpitaya_nginx -mkdir -p $root_dir/opt -tar -zxf $ecosystem_tar --directory=$root_dir/opt - -chroot $root_dir <<- EOF_CHROOT -export LANG=C -export LC_ALL=C - -# Add missing paths - -echo :$PATH: | grep -q :/sbin: || export PATH=$PATH:/sbin -echo :$PATH: | grep -q :/bin: || export PATH=$PATH:/bin -echo :$PATH: | grep -q :/usr/sbin: || export PATH=$PATH:/usr/sbin -echo :$PATH: | grep -q :/usr/bin: || export PATH=$PATH:/usr/bin - -/debootstrap/debootstrap --second-stage - -cat <<- EOF_CAT > /etc/apt/sources.list -deb $mirror $distro main contrib non-free -deb-src $mirror $distro main contrib non-free -deb $mirror $distro-updates main contrib non-free -deb-src $mirror $distro-updates main contrib non-free -deb http://security.debian.org/debian-security $distro/updates main contrib non-free -deb-src http://security.debian.org/debian-security $distro/updates main contrib non-free -EOF_CAT - -cat <<- EOF_CAT > etc/apt/apt.conf.d/99norecommends -APT::Install-Recommends "0"; -APT::Install-Suggests "0"; -EOF_CAT - -cat <<- EOF_CAT > etc/fstab -# /etc/fstab: static file system information. -# -/dev/mmcblk0p2 / ext4 errors=remount-ro 0 1 -/dev/mmcblk0p1 /boot vfat defaults 0 2 -EOF_CAT - -cat <<- EOF_CAT >> etc/securetty - -# Serial Console for Xilinx Zynq-7000 -ttyPS0 -EOF_CAT - -echo red-pitaya > etc/hostname - -apt-get update -apt-get -y upgrade - -apt-get -y install locales - -sed -i "/^# en_US.UTF-8 UTF-8$/s/^# //" etc/locale.gen -locale-gen -update-locale LANG=en_US.UTF-8 - -echo $timezone > etc/timezone -dpkg-reconfigure --frontend=noninteractive tzdata - -apt-get -y install openssh-server ca-certificates ntp ntpdate fake-hwclock \ - usbutils psmisc lsof parted curl vim wpasupplicant hostapd isc-dhcp-server \ - iw firmware-realtek firmware-ralink firmware-atheros firmware-brcm80211 \ - build-essential libconfig-dev libpcre3-dev libluajit-5.1-dev libssl-dev \ - libboost-regex1.55-dev libboost-system1.55-dev libboost-thread1.55-dev \ - libcurl4-openssl-dev libcrypto++-dev libfftw3-dev libasound2-dev zlib1g-dev \ - unzip ifplugd ntfs-3g alsa-utils lua-cjson parallel subversion git - -sed -i 's/^PermitRootLogin.*/PermitRootLogin yes/' etc/ssh/sshd_config - -cat <<- EOF_CAT > etc/systemd/system/redpitaya_nginx.service -[Unit] -Description=Customized Nginx web server for Red Pitaya applications -After=network.target - -[Service] -Type=forking -PIDFile=/run/redpitaya_nginx.pid -Environment=PATH_REDPITAYA=/opt/redpitaya -Environment=LD_LIBRARY_PATH=/opt/redpitaya/lib -Environment=PATH=/usr/sbin:/usr/bin:/sbin:/bin:/opt/redpitaya/sbin:/opt/redpitaya/bin -ExecStart=/opt/redpitaya/sbin/nginx -p \\\${PATH_REDPITAYA}/www -ExecReload=/opt/redpitaya/sbin/nginx -p \\\${PATH_REDPITAYA}/www -s reload -ExecStop=/opt/redpitaya/sbin/nginx -p \\\${PATH_REDPITAYA}/www -s quit - -[Install] -WantedBy=multi-user.target -EOF_CAT - -cat <<- EOF_CAT > etc/systemd/system/redpitaya_scpi.service -[Unit] -Description=SCPI server for Red Pitaya -After=network.target - -[Service] -Type=simple -Restart=always -Environment=PATH_REDPITAYA=/opt/redpitaya -Environment=LD_LIBRARY_PATH=/opt/redpitaya/lib -Environment=PATH=/usr/sbin:/usr/bin:/sbin:/bin:/opt/redpitaya/sbin:/opt/redpitaya/bin -ExecStart=/opt/redpitaya/bin/scpi-server -ExecStop=/bin/kill -15 \\\${MAINPID} - -[Install] -WantedBy=multi-user.target -EOF_CAT - -systemctl enable redpitaya_nginx - -cat <<- EOF_CAT > etc/profile.d/red-pitaya.sh -export PATH=\\\$PATH:/opt/redpitaya/bin -export LD_LIBRARY_PATH=\\\$LD_LIBRARY_PATH:/opt/redpitaya/lib -EOF_CAT - -touch etc/udev/rules.d/75-persistent-net-generator.rules - -cat <<- EOF_CAT > etc/network/interfaces.d/eth0 -iface eth0 inet dhcp -EOF_CAT - -cat <<- EOF_CAT > etc/default/ifplugd -INTERFACES="eth0" -HOTPLUG_INTERFACES="" -ARGS="-q -f -u0 -d10 -w -I" -SUSPEND_ACTION="stop" -EOF_CAT - -cat <<- EOF_CAT > etc/network/interfaces.d/wlan0 -allow-hotplug wlan0 -iface wlan0 inet static - address 192.168.42.1 - netmask 255.255.255.0 - post-up service hostapd restart - post-up service isc-dhcp-server restart - post-up iptables-restore < /etc/iptables.ipv4.nat - pre-down iptables-restore < /etc/iptables.ipv4.nonat - pre-down service isc-dhcp-server stop - pre-down service hostapd stop -EOF_CAT - -cat <<- EOF_CAT > etc/hostapd/hostapd.conf -interface=wlan0 -ssid=RedPitaya -driver=nl80211 -hw_mode=g -channel=6 -macaddr_acl=0 -auth_algs=1 -ignore_broadcast_ssid=0 -wpa=2 -wpa_passphrase=RedPitaya -wpa_key_mgmt=WPA-PSK -wpa_pairwise=CCMP -rsn_pairwise=CCMP -EOF_CAT - -cat <<- EOF_CAT > etc/default/hostapd -DAEMON_CONF=/etc/hostapd/hostapd.conf - -if [ "\\\$1" = "start" ] -then - iw wlan0 info > /dev/null 2>&1 - if [ \\\$? -eq 0 ] - then - sed -i '/^driver/s/=.*/=nl80211/' /etc/hostapd/hostapd.conf - DAEMON_SBIN=/usr/sbin/hostapd - else - sed -i '/^driver/s/=.*/=rtl871xdrv/' /etc/hostapd/hostapd.conf - DAEMON_SBIN=/usr/local/sbin/hostapd - fi - echo \\\$DAEMON_SBIN > /run/hostapd.which -elif [ "\\\$1" = "stop" ] -then - DAEMON_SBIN=\\\$(cat /run/hostapd.which) -fi -EOF_CAT - -cat <<- EOF_CAT > etc/dhcp/dhcpd.conf -ddns-update-style none; -default-lease-time 600; -max-lease-time 7200; -authoritative; -log-facility local7; -subnet 192.168.42.0 netmask 255.255.255.0 { - range 192.168.42.10 192.168.42.50; - option broadcast-address 192.168.42.255; - option routers 192.168.42.1; - default-lease-time 600; - max-lease-time 7200; - option domain-name "local"; - option domain-name-servers 8.8.8.8, 8.8.4.4; -} -EOF_CAT - -cat <<- EOF_CAT >> etc/dhcp/dhclient.conf -timeout 20; - -lease { - interface "eth0"; - fixed-address 192.168.1.100; - option subnet-mask 255.255.255.0; - renew 2 2030/1/1 00:00:01; - rebind 2 2030/1/1 00:00:01; - expire 2 2030/1/1 00:00:01; -} -EOF_CAT - -sed -i '/^#net.ipv4.ip_forward=1$/s/^#//' etc/sysctl.conf - -cat <<- EOF_CAT > etc/iptables.ipv4.nat -*nat -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] --A POSTROUTING -o eth0 -j MASQUERADE -COMMIT -*mangle -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*filter -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] --A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT --A FORWARD -i wlan0 -o eth0 -j ACCEPT -COMMIT -EOF_CAT - -cat <<- EOF_CAT > etc/iptables.ipv4.nonat -*nat -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*mangle -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*filter -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -COMMIT -EOF_CAT - -apt-get clean - -echo root:$passwd | chpasswd - -service ntp stop -service ssh stop - -history -c - -sync -EOF_CHROOT - -rm $root_dir/etc/resolv.conf -rm $root_dir/usr/bin/qemu-arm-static - -# Unmount file systems - -umount $boot_dir $root_dir - -rmdir $boot_dir $root_dir - -zerofree $root_dev diff --git a/HDL/scripts/debian-gnuradio.sh b/HDL/scripts/debian-gnuradio.sh deleted file mode 100644 index 44334006..00000000 --- a/HDL/scripts/debian-gnuradio.sh +++ /dev/null @@ -1,286 +0,0 @@ -device=$1 - -boot_dir=`mktemp -d /tmp/BOOT.XXXXXXXXXX` -root_dir=`mktemp -d /tmp/ROOT.XXXXXXXXXX` - -# Choose mirror automatically, depending the geographic and network location -mirror=http://httpredir.debian.org/debian - -distro=jessie -arch=armhf - -hostapd_url=https://www.dropbox.com/sh/5fy49wae6xwxa8a/AAAQHa5NkpLYFocaOrrnft-Pa/rtl8192cu/hostapd-armhf?dl=1 - -passwd=changeme -timezone=Europe/Brussels - -# Create partitions - -parted -s $device mklabel msdos -parted -s $device mkpart primary fat16 4MB 16MB -parted -s $device mkpart primary ext4 16MB 100% - -boot_dev=/dev/`lsblk -lno NAME $device | sed '2!d'` -root_dev=/dev/`lsblk -lno NAME $device | sed '3!d'` - -# Create file systems - -mkfs.vfat -v $boot_dev -mkfs.ext4 -F -j $root_dev - -# Mount file systems - -mount $boot_dev $boot_dir -mount $root_dev $root_dir - -# Copy files to the boot file system - -cp boot.bin devicetree.dtb uImage uEnv.txt $boot_dir - -# Install Debian base system to the root file system - -debootstrap --foreign --arch $arch $distro $root_dir $mirror - -# Add missing configuration files and packages - -cp /etc/resolv.conf $root_dir/etc/ -cp /usr/bin/qemu-arm-static $root_dir/usr/bin/ - -cp patches/fw_env.config $root_dir/etc/ - -mkdir -p $root_dir/usr/local/bin -cp fw_printenv $root_dir/usr/local/bin/fw_printenv -cp fw_printenv $root_dir/usr/local/bin/fw_setenv - -mkdir -p $root_dir/usr/local/sbin -curl -L $hostapd_url -o $root_dir/usr/local/sbin/hostapd -chmod +x $root_dir/usr/local/sbin/hostapd - -mkdir -p $root_dir/root/gnuradio -cp projects/sdr_transceiver_emb/gnuradio/* $root_dir/root/gnuradio/ - -chroot $root_dir <<- EOF_CHROOT -export LANG=C -export LC_ALL=C - -# Add missing paths - -echo :$PATH: | grep -q :/sbin: || export PATH=$PATH:/sbin -echo :$PATH: | grep -q :/bin: || export PATH=$PATH:/bin -echo :$PATH: | grep -q :/usr/sbin: || export PATH=$PATH:/usr/sbin -echo :$PATH: | grep -q :/usr/bin: || export PATH=$PATH:/usr/bin - -/debootstrap/debootstrap --second-stage - -cat <<- EOF_CAT > /etc/apt/sources.list -deb $mirror $distro main contrib non-free -deb-src $mirror $distro main contrib non-free -deb $mirror $distro-updates main contrib non-free -deb-src $mirror $distro-updates main contrib non-free -deb http://security.debian.org/debian-security $distro/updates main contrib non-free -deb-src http://security.debian.org/debian-security $distro/updates main contrib non-free -EOF_CAT - -cat <<- EOF_CAT > etc/apt/apt.conf.d/99norecommends -APT::Install-Recommends "0"; -APT::Install-Suggests "0"; -EOF_CAT - -cat <<- EOF_CAT > etc/fstab -# /etc/fstab: static file system information. -# -/dev/mmcblk0p2 / ext4 errors=remount-ro 0 1 -/dev/mmcblk0p1 /boot vfat defaults 0 2 -EOF_CAT - -cat <<- EOF_CAT >> etc/securetty - -# Serial Console for Xilinx Zynq-7000 -ttyPS0 -EOF_CAT - -echo red-pitaya > etc/hostname - -apt-get update -apt-get -y upgrade - -apt-get -y install locales - -sed -i "/^# en_US.UTF-8 UTF-8$/s/^# //" etc/locale.gen -locale-gen -update-locale LANG=en_US.UTF-8 - -echo $timezone > etc/timezone -dpkg-reconfigure --frontend=noninteractive tzdata - -apt-get -y install openssh-server ca-certificates ntp ntpdate fake-hwclock \ - usbutils psmisc lsof parted curl vim wpasupplicant hostapd isc-dhcp-server \ - iw firmware-realtek firmware-ralink firmware-atheros firmware-brcm80211 \ - build-essential libasound2-dev libconfig-dev libfftw3-dev subversion git \ - alsa-utils gnuradio python-numpy python-gtk2 python-urwid python-serial \ - python-alsaaudio xauth xterm parallel ifplugd ntfs-3g - -sed -i 's/^PermitRootLogin.*/PermitRootLogin yes/' etc/ssh/sshd_config - -touch etc/udev/rules.d/75-persistent-net-generator.rules - -cat <<- EOF_CAT > etc/network/interfaces.d/eth0 -iface eth0 inet dhcp -EOF_CAT - -cat <<- EOF_CAT > etc/default/ifplugd -INTERFACES="eth0" -HOTPLUG_INTERFACES="" -ARGS="-q -f -u0 -d10 -w -I" -SUSPEND_ACTION="stop" -EOF_CAT - -cat <<- EOF_CAT > etc/network/interfaces.d/wlan0 -allow-hotplug wlan0 -iface wlan0 inet static - address 192.168.42.1 - netmask 255.255.255.0 - post-up service hostapd restart - post-up service isc-dhcp-server restart - post-up iptables-restore < /etc/iptables.ipv4.nat - pre-down iptables-restore < /etc/iptables.ipv4.nonat - pre-down service isc-dhcp-server stop - pre-down service hostapd stop -EOF_CAT - -cat <<- EOF_CAT > etc/hostapd/hostapd.conf -interface=wlan0 -ssid=RedPitaya -driver=nl80211 -hw_mode=g -channel=6 -macaddr_acl=0 -auth_algs=1 -ignore_broadcast_ssid=0 -wpa=2 -wpa_passphrase=RedPitaya -wpa_key_mgmt=WPA-PSK -wpa_pairwise=CCMP -rsn_pairwise=CCMP -EOF_CAT - -cat <<- EOF_CAT > etc/default/hostapd -DAEMON_CONF=/etc/hostapd/hostapd.conf - -if [ "\\\$1" = "start" ] -then - iw wlan0 info > /dev/null 2>&1 - if [ \\\$? -eq 0 ] - then - sed -i '/^driver/s/=.*/=nl80211/' /etc/hostapd/hostapd.conf - DAEMON_SBIN=/usr/sbin/hostapd - else - sed -i '/^driver/s/=.*/=rtl871xdrv/' /etc/hostapd/hostapd.conf - DAEMON_SBIN=/usr/local/sbin/hostapd - fi - echo \\\$DAEMON_SBIN > /run/hostapd.which -elif [ "\\\$1" = "stop" ] -then - DAEMON_SBIN=\\\$(cat /run/hostapd.which) -fi -EOF_CAT - -cat <<- EOF_CAT > etc/dhcp/dhcpd.conf -ddns-update-style none; -default-lease-time 600; -max-lease-time 7200; -authoritative; -log-facility local7; -subnet 192.168.42.0 netmask 255.255.255.0 { - range 192.168.42.10 192.168.42.50; - option broadcast-address 192.168.42.255; - option routers 192.168.42.1; - default-lease-time 600; - max-lease-time 7200; - option domain-name "local"; - option domain-name-servers 8.8.8.8, 8.8.4.4; -} -EOF_CAT - -cat <<- EOF_CAT >> etc/dhcp/dhclient.conf -timeout 20; - -lease { - interface "eth0"; - fixed-address 192.168.1.100; - option subnet-mask 255.255.255.0; - renew 2 2030/1/1 00:00:01; - rebind 2 2030/1/1 00:00:01; - expire 2 2030/1/1 00:00:01; -} -EOF_CAT - -sed -i '/^#net.ipv4.ip_forward=1$/s/^#//' etc/sysctl.conf - -cat <<- EOF_CAT > etc/iptables.ipv4.nat -*nat -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] --A POSTROUTING -o eth0 -j MASQUERADE -COMMIT -*mangle -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*filter -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] --A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT --A FORWARD -i wlan0 -o eth0 -j ACCEPT -COMMIT -EOF_CAT - -cat <<- EOF_CAT > etc/iptables.ipv4.nonat -*nat -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*mangle -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*filter -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -COMMIT -EOF_CAT - -apt-get clean - -echo root:$passwd | chpasswd - -service ntp stop -service ssh stop - -history -c - -sync -EOF_CHROOT - -rm $root_dir/etc/resolv.conf -rm $root_dir/usr/bin/qemu-arm-static - -# Unmount file systems - -umount $boot_dir $root_dir - -rmdir $boot_dir $root_dir - -zerofree $root_dev diff --git a/HDL/scripts/debian-wspr.sh b/HDL/scripts/debian-wspr.sh deleted file mode 100644 index bc876ca2..00000000 --- a/HDL/scripts/debian-wspr.sh +++ /dev/null @@ -1,301 +0,0 @@ -device=$1 - -boot_dir=`mktemp -d /tmp/BOOT.XXXXXXXXXX` -root_dir=`mktemp -d /tmp/ROOT.XXXXXXXXXX` - -# Choose mirror automatically, depending the geographic and network location -mirror=http://httpredir.debian.org/debian - -distro=jessie -arch=armhf - -hostapd_url=https://www.dropbox.com/sh/5fy49wae6xwxa8a/AAAQHa5NkpLYFocaOrrnft-Pa/rtl8192cu/hostapd-armhf?dl=1 - -passwd=changeme -timezone=Europe/Brussels - -# Create partitions - -parted -s $device mklabel msdos -parted -s $device mkpart primary fat16 4MB 16MB -parted -s $device mkpart primary ext4 16MB 100% - -boot_dev=/dev/`lsblk -lno NAME $device | sed '2!d'` -root_dev=/dev/`lsblk -lno NAME $device | sed '3!d'` - -# Create file systems - -mkfs.vfat -v $boot_dev -mkfs.ext4 -F -j $root_dev - -# Mount file systems - -mount $boot_dev $boot_dir -mount $root_dev $root_dir - -# Copy files to the boot file system - -cp boot.bin devicetree.dtb uImage uEnv.txt $boot_dir - -# Install Debian base system to the root file system - -debootstrap --foreign --arch $arch $distro $root_dir $mirror - -# Add missing configuration files and packages - -cp /etc/resolv.conf $root_dir/etc/ -cp /usr/bin/qemu-arm-static $root_dir/usr/bin/ - -cp patches/fw_env.config $root_dir/etc/ - -mkdir -p $root_dir/usr/local/bin -cp fw_printenv $root_dir/usr/local/bin/fw_printenv -cp fw_printenv $root_dir/usr/local/bin/fw_setenv - -mkdir -p $root_dir/usr/local/sbin -curl -L $hostapd_url -o $root_dir/usr/local/sbin/hostapd -chmod +x $root_dir/usr/local/sbin/hostapd - -mkdir -p $root_dir/root -cp projects/sdr_transceiver_wspr/transmit-wspr-message.c $root_dir/root/ -cp projects/sdr_transceiver_wspr/transmit-wspr-message.cfg $root_dir/root/ -cp projects/sdr_transceiver_wspr/transmit-wspr.sh $root_dir/root/ -cp projects/sdr_transceiver_wspr/write-c2-files.c $root_dir/root/ -cp projects/sdr_transceiver_wspr/write-c2-files.cfg $root_dir/root/ -cp projects/sdr_transceiver_wspr/decode-wspr.sh $root_dir/root/ -cp projects/sdr_transceiver_wspr/gpio-output.c $root_dir/root/ -cp projects/sdr_transceiver_wspr/wspr.cron $root_dir/root/ -cp projects/sdr_transceiver_wspr/README $root_dir/root/ -cp projects/sdr_transceiver_wspr/Makefile $root_dir/root/ - -chroot $root_dir <<- EOF_CHROOT -export LANG=C -export LC_ALL=C - -# Add missing paths - -echo :$PATH: | grep -q :/sbin: || export PATH=$PATH:/sbin -echo :$PATH: | grep -q :/bin: || export PATH=$PATH:/bin -echo :$PATH: | grep -q :/usr/sbin: || export PATH=$PATH:/usr/sbin -echo :$PATH: | grep -q :/usr/bin: || export PATH=$PATH:/usr/bin - -/debootstrap/debootstrap --second-stage - -cat <<- EOF_CAT > /etc/apt/sources.list -deb $mirror $distro main contrib non-free -deb-src $mirror $distro main contrib non-free -deb $mirror $distro-updates main contrib non-free -deb-src $mirror $distro-updates main contrib non-free -deb http://security.debian.org/debian-security $distro/updates main contrib non-free -deb-src http://security.debian.org/debian-security $distro/updates main contrib non-free -EOF_CAT - -cat <<- EOF_CAT > etc/apt/apt.conf.d/99norecommends -APT::Install-Recommends "0"; -APT::Install-Suggests "0"; -EOF_CAT - -cat <<- EOF_CAT > etc/fstab -# /etc/fstab: static file system information. -# -/dev/mmcblk0p2 / ext4 errors=remount-ro 0 1 -/dev/mmcblk0p1 /boot vfat defaults 0 2 -EOF_CAT - -cat <<- EOF_CAT >> etc/securetty - -# Serial Console for Xilinx Zynq-7000 -ttyPS0 -EOF_CAT - -echo red-pitaya > etc/hostname - -apt-get update -apt-get -y upgrade - -apt-get -y install locales - -sed -i "/^# en_US.UTF-8 UTF-8$/s/^# //" etc/locale.gen -locale-gen -update-locale LANG=en_US.UTF-8 - -echo $timezone > etc/timezone -dpkg-reconfigure --frontend=noninteractive tzdata - -apt-get -y install openssh-server ca-certificates ntp ntpdate fake-hwclock \ - usbutils psmisc lsof parted curl vim wpasupplicant hostapd isc-dhcp-server \ - iw firmware-realtek firmware-ralink firmware-atheros firmware-brcm80211 \ - build-essential subversion libfftw3-dev libconfig-dev parallel ifplugd ntfs-3g - -cd root -svn co svn://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx/lib/wsprd -make -C wsprd CFLAGS='-O3 -march=armv7-a -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon -mfloat-abi=hard -ffast-math -fsingle-precision-constant -mvectorize-with-neon-quad' wsprd -make -cd .. - -ln -sf /root/wspr.cron etc/cron.d/wspr - -sed -i 's/^PermitRootLogin.*/PermitRootLogin yes/' etc/ssh/sshd_config - -touch etc/udev/rules.d/75-persistent-net-generator.rules - -cat <<- EOF_CAT > etc/network/interfaces.d/eth0 -iface eth0 inet dhcp -EOF_CAT - -cat <<- EOF_CAT > etc/default/ifplugd -INTERFACES="eth0" -HOTPLUG_INTERFACES="" -ARGS="-q -f -u0 -d10 -w -I" -SUSPEND_ACTION="stop" -EOF_CAT - -cat <<- EOF_CAT > etc/network/interfaces.d/wlan0 -allow-hotplug wlan0 -iface wlan0 inet static - address 192.168.42.1 - netmask 255.255.255.0 - post-up service hostapd restart - post-up service isc-dhcp-server restart - post-up iptables-restore < /etc/iptables.ipv4.nat - pre-down iptables-restore < /etc/iptables.ipv4.nonat - pre-down service isc-dhcp-server stop - pre-down service hostapd stop -EOF_CAT - -cat <<- EOF_CAT > etc/hostapd/hostapd.conf -interface=wlan0 -ssid=RedPitaya -driver=nl80211 -hw_mode=g -channel=6 -macaddr_acl=0 -auth_algs=1 -ignore_broadcast_ssid=0 -wpa=2 -wpa_passphrase=RedPitaya -wpa_key_mgmt=WPA-PSK -wpa_pairwise=CCMP -rsn_pairwise=CCMP -EOF_CAT - -cat <<- EOF_CAT > etc/default/hostapd -DAEMON_CONF=/etc/hostapd/hostapd.conf - -if [ "\\\$1" = "start" ] -then - iw wlan0 info > /dev/null 2>&1 - if [ \\\$? -eq 0 ] - then - sed -i '/^driver/s/=.*/=nl80211/' /etc/hostapd/hostapd.conf - DAEMON_SBIN=/usr/sbin/hostapd - else - sed -i '/^driver/s/=.*/=rtl871xdrv/' /etc/hostapd/hostapd.conf - DAEMON_SBIN=/usr/local/sbin/hostapd - fi - echo \\\$DAEMON_SBIN > /run/hostapd.which -elif [ "\\\$1" = "stop" ] -then - DAEMON_SBIN=\\\$(cat /run/hostapd.which) -fi -EOF_CAT - -cat <<- EOF_CAT > etc/dhcp/dhcpd.conf -ddns-update-style none; -default-lease-time 600; -max-lease-time 7200; -authoritative; -log-facility local7; -subnet 192.168.42.0 netmask 255.255.255.0 { - range 192.168.42.10 192.168.42.50; - option broadcast-address 192.168.42.255; - option routers 192.168.42.1; - default-lease-time 600; - max-lease-time 7200; - option domain-name "local"; - option domain-name-servers 8.8.8.8, 8.8.4.4; -} -EOF_CAT - -cat <<- EOF_CAT >> etc/dhcp/dhclient.conf -timeout 20; - -lease { - interface "eth0"; - fixed-address 192.168.1.100; - option subnet-mask 255.255.255.0; - renew 2 2030/1/1 00:00:01; - rebind 2 2030/1/1 00:00:01; - expire 2 2030/1/1 00:00:01; -} -EOF_CAT - -sed -i '/^#net.ipv4.ip_forward=1$/s/^#//' etc/sysctl.conf - -cat <<- EOF_CAT > etc/iptables.ipv4.nat -*nat -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] --A POSTROUTING -o eth0 -j MASQUERADE -COMMIT -*mangle -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*filter -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] --A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT --A FORWARD -i wlan0 -o eth0 -j ACCEPT -COMMIT -EOF_CAT - -cat <<- EOF_CAT > etc/iptables.ipv4.nonat -*nat -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*mangle -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*filter -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -COMMIT -EOF_CAT - -apt-get clean - -echo root:$passwd | chpasswd - -service ntp stop -service ssh stop - -history -c - -sync -EOF_CHROOT - -rm $root_dir/etc/resolv.conf -rm $root_dir/usr/bin/qemu-arm-static - -# Unmount file systems - -umount $boot_dir $root_dir - -rmdir $boot_dir $root_dir - -zerofree $root_dev diff --git a/HDL/scripts/debian.sh b/HDL/scripts/debian.sh deleted file mode 100644 index 781d9a99..00000000 --- a/HDL/scripts/debian.sh +++ /dev/null @@ -1,281 +0,0 @@ -device=$1 - -boot_dir=`mktemp -d /tmp/BOOT.XXXXXXXXXX` -root_dir=`mktemp -d /tmp/ROOT.XXXXXXXXXX` - -# Choose mirror automatically, depending the geographic and network location -mirror=http://httpredir.debian.org/debian - -distro=jessie -arch=armhf - -hostapd_url=https://www.dropbox.com/sh/5fy49wae6xwxa8a/AAAQHa5NkpLYFocaOrrnft-Pa/rtl8192cu/hostapd-armhf?dl=1 - -passwd=changeme -timezone=Europe/Brussels - -# Create partitions - -parted -s $device mklabel msdos -parted -s $device mkpart primary fat16 4MB 16MB -parted -s $device mkpart primary ext4 16MB 100% - -boot_dev=/dev/`lsblk -lno NAME $device | sed '2!d'` -root_dev=/dev/`lsblk -lno NAME $device | sed '3!d'` - -# Create file systems - -mkfs.vfat -v $boot_dev -mkfs.ext4 -F -j $root_dev - -# Mount file systems - -mount $boot_dev $boot_dir -mount $root_dev $root_dir - -# Copy files to the boot file system - -cp boot.bin devicetree.dtb uImage uEnv.txt $boot_dir - -# Install Debian base system to the root file system - -debootstrap --foreign --arch $arch $distro $root_dir $mirror - -# Add missing configuration files and packages - -cp /etc/resolv.conf $root_dir/etc/ -cp /usr/bin/qemu-arm-static $root_dir/usr/bin/ - -cp patches/fw_env.config $root_dir/etc/ - -mkdir -p $root_dir/usr/local/bin -cp fw_printenv $root_dir/usr/local/bin/fw_printenv -cp fw_printenv $root_dir/usr/local/bin/fw_setenv - -mkdir -p $root_dir/usr/local/sbin -curl -L $hostapd_url -o $root_dir/usr/local/sbin/hostapd -chmod +x $root_dir/usr/local/sbin/hostapd - -chroot $root_dir <<- EOF_CHROOT -export LANG=C -export LC_ALL=C - -# Add missing paths - -echo :$PATH: | grep -q :/sbin: || export PATH=$PATH:/sbin -echo :$PATH: | grep -q :/bin: || export PATH=$PATH:/bin -echo :$PATH: | grep -q :/usr/sbin: || export PATH=$PATH:/usr/sbin -echo :$PATH: | grep -q :/usr/bin: || export PATH=$PATH:/usr/bin - -/debootstrap/debootstrap --second-stage - -cat <<- EOF_CAT > /etc/apt/sources.list -deb $mirror $distro main contrib non-free -deb-src $mirror $distro main contrib non-free -deb $mirror $distro-updates main contrib non-free -deb-src $mirror $distro-updates main contrib non-free -deb http://security.debian.org/debian-security $distro/updates main contrib non-free -deb-src http://security.debian.org/debian-security $distro/updates main contrib non-free -EOF_CAT - -cat <<- EOF_CAT > etc/apt/apt.conf.d/99norecommends -APT::Install-Recommends "0"; -APT::Install-Suggests "0"; -EOF_CAT - -cat <<- EOF_CAT > etc/fstab -# /etc/fstab: static file system information. -# -/dev/mmcblk0p2 / ext4 errors=remount-ro 0 1 -/dev/mmcblk0p1 /boot vfat defaults 0 2 -EOF_CAT - -cat <<- EOF_CAT >> etc/securetty - -# Serial Console for Xilinx Zynq-7000 -ttyPS0 -EOF_CAT - -echo red-pitaya > etc/hostname - -apt-get update -apt-get -y upgrade - -apt-get -y install locales - -sed -i "/^# en_US.UTF-8 UTF-8$/s/^# //" etc/locale.gen -locale-gen -update-locale LANG=en_US.UTF-8 - -echo $timezone > etc/timezone -dpkg-reconfigure --frontend=noninteractive tzdata - -apt-get -y install openssh-server ca-certificates ntp ntpdate fake-hwclock \ - usbutils psmisc lsof parted curl vim wpasupplicant hostapd isc-dhcp-server \ - iw firmware-realtek firmware-ralink firmware-atheros firmware-brcm80211 \ - ifplugd ntfs-3g - -sed -i 's/^PermitRootLogin.*/PermitRootLogin yes/' etc/ssh/sshd_config - -touch etc/udev/rules.d/75-persistent-net-generator.rules - -cat <<- EOF_CAT > etc/network/interfaces.d/eth0 -iface eth0 inet dhcp -EOF_CAT - -cat <<- EOF_CAT > etc/default/ifplugd -INTERFACES="eth0" -HOTPLUG_INTERFACES="" -ARGS="-q -f -u0 -d10 -w -I" -SUSPEND_ACTION="stop" -EOF_CAT - -cat <<- EOF_CAT > etc/network/interfaces.d/wlan0 -allow-hotplug wlan0 -iface wlan0 inet static - address 192.168.42.1 - netmask 255.255.255.0 - post-up service hostapd restart - post-up service isc-dhcp-server restart - post-up iptables-restore < /etc/iptables.ipv4.nat - pre-down iptables-restore < /etc/iptables.ipv4.nonat - pre-down service isc-dhcp-server stop - pre-down service hostapd stop -EOF_CAT - -cat <<- EOF_CAT > etc/hostapd/hostapd.conf -interface=wlan0 -ssid=RedPitaya -driver=nl80211 -hw_mode=g -channel=6 -macaddr_acl=0 -auth_algs=1 -ignore_broadcast_ssid=0 -wpa=2 -wpa_passphrase=RedPitaya -wpa_key_mgmt=WPA-PSK -wpa_pairwise=CCMP -rsn_pairwise=CCMP -EOF_CAT - -cat <<- EOF_CAT > etc/default/hostapd -DAEMON_CONF=/etc/hostapd/hostapd.conf - -if [ "\\\$1" = "start" ] -then - iw wlan0 info > /dev/null 2>&1 - if [ \\\$? -eq 0 ] - then - sed -i '/^driver/s/=.*/=nl80211/' /etc/hostapd/hostapd.conf - DAEMON_SBIN=/usr/sbin/hostapd - else - sed -i '/^driver/s/=.*/=rtl871xdrv/' /etc/hostapd/hostapd.conf - DAEMON_SBIN=/usr/local/sbin/hostapd - fi - echo \\\$DAEMON_SBIN > /run/hostapd.which -elif [ "\\\$1" = "stop" ] -then - DAEMON_SBIN=\\\$(cat /run/hostapd.which) -fi -EOF_CAT - -cat <<- EOF_CAT > etc/dhcp/dhcpd.conf -ddns-update-style none; -default-lease-time 600; -max-lease-time 7200; -authoritative; -log-facility local7; -subnet 192.168.42.0 netmask 255.255.255.0 { - range 192.168.42.10 192.168.42.50; - option broadcast-address 192.168.42.255; - option routers 192.168.42.1; - default-lease-time 600; - max-lease-time 7200; - option domain-name "local"; - option domain-name-servers 8.8.8.8, 8.8.4.4; -} -EOF_CAT - -cat <<- EOF_CAT >> etc/dhcp/dhclient.conf -timeout 20; - -lease { - interface "eth0"; - fixed-address 192.168.1.100; - option subnet-mask 255.255.255.0; - renew 2 2030/1/1 00:00:01; - rebind 2 2030/1/1 00:00:01; - expire 2 2030/1/1 00:00:01; -} -EOF_CAT - -sed -i '/^#net.ipv4.ip_forward=1$/s/^#//' etc/sysctl.conf - -cat <<- EOF_CAT > etc/iptables.ipv4.nat -*nat -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] --A POSTROUTING -o eth0 -j MASQUERADE -COMMIT -*mangle -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*filter -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] --A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT --A FORWARD -i wlan0 -o eth0 -j ACCEPT -COMMIT -EOF_CAT - -cat <<- EOF_CAT > etc/iptables.ipv4.nonat -*nat -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*mangle -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*filter -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -COMMIT -EOF_CAT - -apt-get clean - -echo root:$passwd | chpasswd - -service ntp stop -service ssh stop - -history -c - -sync -EOF_CHROOT - -rm $root_dir/etc/resolv.conf -rm $root_dir/usr/bin/qemu-arm-static - -# Unmount file systems - -umount $boot_dir $root_dir - -rmdir $boot_dir $root_dir - -zerofree $root_dev diff --git a/HDL/scripts/ubuntu.sh b/HDL/scripts/ubuntu.sh deleted file mode 100644 index 37cacc30..00000000 --- a/HDL/scripts/ubuntu.sh +++ /dev/null @@ -1,266 +0,0 @@ -device=$1 - -boot_dir=`mktemp -d /tmp/BOOT.XXXXXXXXXX` -root_dir=`mktemp -d /tmp/ROOT.XXXXXXXXXX` - -root_tar=ubuntu-base-14.04.5-core-armhf.tar.gz -root_url=http://cdimage.ubuntu.com/ubuntu-base/releases/14.04/release/$root_tar - -hostapd_url=https://www.dropbox.com/sh/5fy49wae6xwxa8a/AAAQHa5NkpLYFocaOrrnft-Pa/rtl8192cu/hostapd-armhf?dl=1 - -passwd=changeme -timezone=Europe/Brussels - -# Create partitions - -parted -s $device mklabel msdos -parted -s $device mkpart primary fat16 4MB 16MB -parted -s $device mkpart primary ext4 16MB 100% - -boot_dev=/dev/`lsblk -lno NAME $device | sed '2!d'` -root_dev=/dev/`lsblk -lno NAME $device | sed '3!d'` - -# Create file systems - -mkfs.vfat -v $boot_dev -mkfs.ext4 -F -j $root_dev - -# Mount file systems - -mount $boot_dev $boot_dir -mount $root_dev $root_dir - -# Copy files to the boot file system - -cp boot.bin devicetree.dtb uImage uEnv.txt $boot_dir - -# Copy Ubuntu Core to the root file system - -test -f $root_tar || curl -L $root_url -o $root_tar - -tar -zxf $root_tar --directory=$root_dir - -# Add missing configuration files and packages - -cp /etc/resolv.conf $root_dir/etc/ -cp /usr/bin/qemu-arm-static $root_dir/usr/bin/ - -cp patches/fw_env.config $root_dir/etc/ - -cp fw_printenv $root_dir/usr/local/bin/fw_printenv -cp fw_printenv $root_dir/usr/local/bin/fw_setenv - -curl -L $hostapd_url -o $root_dir/usr/local/sbin/hostapd -chmod +x $root_dir/usr/local/sbin/hostapd - -chroot $root_dir <<- EOF_CHROOT -export LANG=C -export LC_ALL=C - -# Add missing paths - -echo :$PATH: | grep -q :/sbin: || export PATH=$PATH:/sbin -echo :$PATH: | grep -q :/bin: || export PATH=$PATH:/bin -echo :$PATH: | grep -q :/usr/sbin: || export PATH=$PATH:/usr/sbin -echo :$PATH: | grep -q :/usr/bin: || export PATH=$PATH:/usr/bin - -cat <<- EOF_CAT > etc/apt/apt.conf.d/99norecommends -APT::Install-Recommends "0"; -APT::Install-Suggests "0"; -EOF_CAT - -cat <<- EOF_CAT > etc/fstab -# /etc/fstab: static file system information. -# -/dev/mmcblk0p2 / ext4 errors=remount-ro 0 1 -/dev/mmcblk0p1 /boot vfat defaults 0 2 -EOF_CAT - -cat <<- EOF_CAT >> etc/securetty - -# Serial Console for Xilinx Zynq-7000 -ttyPS0 -EOF_CAT - -sed 's/tty1/ttyPS0/g; s/38400/115200/' etc/init/tty1.conf > etc/init/ttyPS0.conf - -echo red-pitaya > etc/hostname - -sed -i '/^# deb .* universe$/s/^# //' etc/apt/sources.list - -sed -i '/### END INIT INFO/aexit 0' /etc/init.d/udev -apt-get update -apt-get -y upgrade -sed -i '/### END INIT INFO/{n;d}' /etc/init.d/udev - -apt-get -y install locales - -locale-gen en_US.UTF-8 -update-locale LANG=en_US.UTF-8 - -echo $timezone > etc/timezone -dpkg-reconfigure --frontend=noninteractive tzdata - -apt-get -y install openssh-server ca-certificates ntp usbutils psmisc lsof \ - parted curl less vim man-db iw wpasupplicant linux-firmware ntfs-3g - -sed -i 's/^PermitRootLogin.*/PermitRootLogin yes/' etc/ssh/sshd_config - -apt-get -y install hostapd isc-dhcp-server iptables - -touch etc/udev/rules.d/75-persistent-net-generator.rules - -cat <<- EOF_CAT >> etc/network/interfaces.d/eth0 -allow-hotplug eth0 -iface eth0 inet dhcp -EOF_CAT - -cat <<- EOF_CAT > etc/network/interfaces.d/wlan0 -allow-hotplug wlan0 -iface wlan0 inet static - address 192.168.42.1 - netmask 255.255.255.0 - post-up service hostapd restart - post-up service isc-dhcp-server restart - post-up iptables-restore < /etc/iptables.ipv4.nat - pre-down iptables-restore < /etc/iptables.ipv4.nonat - pre-down service isc-dhcp-server stop - pre-down service hostapd stop -EOF_CAT - -cat <<- EOF_CAT > etc/hostapd/hostapd.conf -interface=wlan0 -ssid=RedPitaya -driver=nl80211 -hw_mode=g -channel=6 -macaddr_acl=0 -auth_algs=1 -ignore_broadcast_ssid=0 -wpa=2 -wpa_passphrase=RedPitaya -wpa_key_mgmt=WPA-PSK -wpa_pairwise=CCMP -rsn_pairwise=CCMP -EOF_CAT - -cat <<- EOF_CAT > etc/default/hostapd -DAEMON_CONF=/etc/hostapd/hostapd.conf - -if [ "\\\$1" = "start" ] -then - iw wlan0 info > /dev/null 2>&1 - if [ \\\$? -eq 0 ] - then - sed -i '/^driver/s/=.*/=nl80211/' /etc/hostapd/hostapd.conf - DAEMON_SBIN=/usr/sbin/hostapd - else - sed -i '/^driver/s/=.*/=rtl871xdrv/' /etc/hostapd/hostapd.conf - DAEMON_SBIN=/usr/local/sbin/hostapd - fi - echo \\\$DAEMON_SBIN > /run/hostapd.which -elif [ "\\\$1" = "stop" ] -then - DAEMON_SBIN=\\\$(cat /run/hostapd.which) -fi -EOF_CAT - -cat <<- EOF_CAT > etc/dhcp/dhcpd.conf -ddns-update-style none; -default-lease-time 600; -max-lease-time 7200; -authoritative; -log-facility local7; -subnet 192.168.42.0 netmask 255.255.255.0 { - range 192.168.42.10 192.168.42.50; - option broadcast-address 192.168.42.255; - option routers 192.168.42.1; - default-lease-time 600; - max-lease-time 7200; - option domain-name "local"; - option domain-name-servers 8.8.8.8, 8.8.4.4; -} -EOF_CAT - -cat <<- EOF_CAT >> etc/dhcp/dhclient.conf -timeout 20; - -lease { - interface "eth0"; - fixed-address 192.168.1.100; - option subnet-mask 255.255.255.0; - renew 2 2030/1/1 00:00:01; - rebind 2 2030/1/1 00:00:01; - expire 2 2030/1/1 00:00:01; -} -EOF_CAT - -sed -i '/^#net.ipv4.ip_forward=1$/s/^#//' etc/sysctl.conf - -cat <<- EOF_CAT > etc/iptables.ipv4.nat -*nat -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] --A POSTROUTING -o eth0 -j MASQUERADE -COMMIT -*mangle -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*filter -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] --A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT --A FORWARD -i wlan0 -o eth0 -j ACCEPT -COMMIT -EOF_CAT - -cat <<- EOF_CAT > etc/iptables.ipv4.nonat -*nat -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*mangle -:PREROUTING ACCEPT [0:0] -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -:POSTROUTING ACCEPT [0:0] -COMMIT -*filter -:INPUT ACCEPT [0:0] -:FORWARD ACCEPT [0:0] -:OUTPUT ACCEPT [0:0] -COMMIT -EOF_CAT - -apt-get clean - -echo root:$passwd | chpasswd - -service ntp stop -service ssh stop - -history -c - -sync -EOF_CHROOT - -rm $root_dir/etc/resolv.conf -rm $root_dir/usr/bin/qemu-arm-static - -# Unmount file systems - -umount $boot_dir $root_dir - -rmdir $boot_dir $root_dir - -zerofree $root_dev From 1712a041c0d36b93ffb0fa9c488ec8730b5e90c2 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 15 Sep 2024 21:48:32 -0700 Subject: [PATCH 15/96] reverting some of the changes I made --- HDL/boards/stemlab_125_14/ports.tcl | 43 ++--------------------------- HDL/boards/stemlab_125_14/ports.xdc | 21 ++++++++++---- 2 files changed, 18 insertions(+), 46 deletions(-) diff --git a/HDL/boards/stemlab_125_14/ports.tcl b/HDL/boards/stemlab_125_14/ports.tcl index c4a19984..fbee07e5 100644 --- a/HDL/boards/stemlab_125_14/ports.tcl +++ b/HDL/boards/stemlab_125_14/ports.tcl @@ -34,48 +34,9 @@ create_bd_port -dir O -from 3 -to 0 dac_pwm_o ### Expansion connector -create_bd_port -dir IO -from 7 -to 0 exp_p_tri_io -create_bd_port -dir IO -from 7 -to 0 exp_n_tri_io - -set_property IOSTANDARD LVCMOS33 [get_ports {exp_p_tri_io[*]}] -set_property IOSTANDARD LVCMOS33 [get_ports {exp_n_tri_io[*]}] -set_property SLEW FAST [get_ports {exp_p_tri_io[*]}] -set_property SLEW FAST [get_ports {exp_n_tri_io[*]}] -set_property DRIVE 8 [get_ports {exp_p_tri_io[*]}] -set_property DRIVE 8 [get_ports {exp_n_tri_io[*]}] -set_property PULLTYPE PULLUP [get_ports {exp_p_tri_io[*]}] -set_property PULLTYPE PULLUP [get_ports {exp_n_tri_io[*]}] - -set_property PACKAGE_PIN G17 [get_ports {exp_p_tri_io[0]}] -set_property PACKAGE_PIN G18 [get_ports {exp_n_tri_io[0]}] -set_property PACKAGE_PIN H16 [get_ports {exp_p_tri_io[1]}] -set_property PACKAGE_PIN H17 [get_ports {exp_n_tri_io[1]}] -set_property PACKAGE_PIN J18 [get_ports {exp_p_tri_io[2]}] -set_property PACKAGE_PIN H18 [get_ports {exp_n_tri_io[2]}] -set_property PACKAGE_PIN K17 [get_ports {exp_p_tri_io[3]}] -set_property PACKAGE_PIN K18 [get_ports {exp_n_tri_io[3]}] -set_property PACKAGE_PIN L14 [get_ports {exp_p_tri_io[4]}] -set_property PACKAGE_PIN L15 [get_ports {exp_n_tri_io[4]}] -set_property PACKAGE_PIN L16 [get_ports {exp_p_tri_io[5]}] -set_property PACKAGE_PIN L17 [get_ports {exp_n_tri_io[5]}] -set_property PACKAGE_PIN K16 [get_ports {exp_p_tri_io[6]}] -set_property PACKAGE_PIN J16 [get_ports {exp_n_tri_io[6]}] -set_property PACKAGE_PIN M14 [get_ports {exp_p_tri_io[7]}] -set_property PACKAGE_PIN M15 [get_ports {exp_n_tri_io[7]}] +create_bd_port -dir O -from 7 -to 0 exp_p_tri_io +create_bd_port -dir O -from 7 -to 0 exp_n_tri_io ### LED create_bd_port -dir O -from 7 -to 0 led_o - -set_property IOSTANDARD LVCMOS33 [get_ports {led_o[*]}] -set_property SLEW SLOW [get_ports {led_o[*]}] -set_property DRIVE 8 [get_ports {led_o[*]}] - -set_property PACKAGE_PIN F16 [get_ports {led_o[0]}] -set_property PACKAGE_PIN F17 [get_ports {led_o[1]}] -set_property PACKAGE_PIN G15 [get_ports {led_o[2]}] -set_property PACKAGE_PIN H15 [get_ports {led_o[3]}] -set_property PACKAGE_PIN K14 [get_ports {led_o[4]}] -set_property PACKAGE_PIN G14 [get_ports {led_o[5]}] -set_property PACKAGE_PIN J15 [get_ports {led_o[6]}] -set_property PACKAGE_PIN J14 [get_ports {led_o[7]}] \ No newline at end of file diff --git a/HDL/boards/stemlab_125_14/ports.xdc b/HDL/boards/stemlab_125_14/ports.xdc index 4fd2f530..32e423d4 100644 --- a/HDL/boards/stemlab_125_14/ports.xdc +++ b/HDL/boards/stemlab_125_14/ports.xdc @@ -1,3 +1,18 @@ +proc set_port_property_if_exists { port_name property_name property_value } { + # Get the port + set port_obj [get_ports $port_name] + + # Check if the port exists + if { [llength $port_obj] > 0 } { + # Port exists, set the property + set_property $property_name $property_value $port_obj + puts "Property '$property_name' set to '$property_value' on port '$port_name'." + } else { + # Port does not exist + puts "Port '$port_name' does not exist. Skipping property setting." + } +} + # set_property CFGBVS VCCO [current_design] # set_property CONFIG_VOLTAGE 3.3 [current_design] @@ -36,11 +51,7 @@ set_property PACKAGE_PIN T19 [get_ports {adc_dat_b_i[6]}] set_property PACKAGE_PIN U20 [get_ports {adc_dat_b_i[7]}] set_property PACKAGE_PIN V20 [get_ports {adc_dat_b_i[8]}] set_property PACKAGE_PIN W20 [get_ports {adc_dat_b_i[9]}] -set_property PACKAGE_PIN W19 [get_ports {adc_dat_b_i[10]}] -set_property PACKAGE_PIN Y19 [get_ports {adc_dat_b_i[11]}] -set_property PACKAGE_PIN W18 [get_ports {adc_dat_b_i[12]}] -set_property PACKAGE_PIN Y18 [get_ports {adc_dat_b_i[13]}] - +set_property PACKAGEled_o_led_o # clock input set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports adc_clk_p_i] From 0a3ae44e1b9c42ccea9b2cce03316937e6e1afb0 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 15 Sep 2024 22:04:36 -0700 Subject: [PATCH 16/96] fully reverted the ports.xdc file --- HDL/boards/stemlab_125_14/ports.xdc | 152 ++++++++++++++-------------- 1 file changed, 78 insertions(+), 74 deletions(-) diff --git a/HDL/boards/stemlab_125_14/ports.xdc b/HDL/boards/stemlab_125_14/ports.xdc index 32e423d4..790160c7 100644 --- a/HDL/boards/stemlab_125_14/ports.xdc +++ b/HDL/boards/stemlab_125_14/ports.xdc @@ -1,17 +1,3 @@ -proc set_port_property_if_exists { port_name property_name property_value } { - # Get the port - set port_obj [get_ports $port_name] - - # Check if the port exists - if { [llength $port_obj] > 0 } { - # Port exists, set the property - set_property $property_name $property_value $port_obj - puts "Property '$property_name' set to '$property_value' on port '$port_name'." - } else { - # Port does not exist - puts "Port '$port_name' does not exist. Skipping property setting." - } -} # set_property CFGBVS VCCO [current_design] # set_property CONFIG_VOLTAGE 3.3 [current_design] @@ -51,7 +37,11 @@ set_property PACKAGE_PIN T19 [get_ports {adc_dat_b_i[6]}] set_property PACKAGE_PIN U20 [get_ports {adc_dat_b_i[7]}] set_property PACKAGE_PIN V20 [get_ports {adc_dat_b_i[8]}] set_property PACKAGE_PIN W20 [get_ports {adc_dat_b_i[9]}] -set_property PACKAGEled_o_led_o +set_property PACKAGE_PIN W19 [get_ports {adc_dat_b_i[10]}] +set_property PACKAGE_PIN Y19 [get_ports {adc_dat_b_i[11]}] +set_property PACKAGE_PIN W18 [get_ports {adc_dat_b_i[12]}] +set_property PACKAGE_PIN Y18 [get_ports {adc_dat_b_i[13]}] + # clock input set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports adc_clk_p_i] @@ -130,76 +120,90 @@ set_property PACKAGE_PIN U13 [get_ports {dac_pwm_o[3]}] ### XADC -# set_property IOSTANDARD LVCMOS33 [get_ports Vp_Vn_v_p] -# set_property IOSTANDARD LVCMOS33 [get_ports Vp_Vn_v_n] -# set_property IOSTANDARD LVCMOS33 [get_ports Vaux0_v_p] -# set_property IOSTANDARD LVCMOS33 [get_ports Vaux0_v_n] -# set_property IOSTANDARD LVCMOS33 [get_ports Vaux1_v_p] -# set_property IOSTANDARD LVCMOS33 [get_ports Vaux1_v_n] -# set_property IOSTANDARD LVCMOS33 [get_ports Vaux8_v_p] -# set_property IOSTANDARD LVCMOS33 [get_ports Vaux8_v_n] -# set_property IOSTANDARD LVCMOS33 [get_ports Vaux9_v_p] -# set_property IOSTANDARD LVCMOS33 [get_ports Vaux9_v_n] - -# set_property PACKAGE_PIN K9 [get_ports Vp_Vn_v_p] -# set_property PACKAGE_PIN L10 [get_ports Vp_Vn_v_n] -# set_property PACKAGE_PIN C20 [get_ports Vaux0_v_p] -# set_property PACKAGE_PIN B20 [get_ports Vaux0_v_n] -# set_property PACKAGE_PIN E17 [get_ports Vaux1_v_p] -# set_property PACKAGE_PIN D18 [get_ports Vaux1_v_n] -# set_property PACKAGE_PIN B19 [get_ports Vaux8_v_p] -# set_property PACKAGE_PIN A20 [get_ports Vaux8_v_n] -# set_property PACKAGE_PIN E18 [get_ports Vaux9_v_p] -# set_property PACKAGE_PIN E19 [get_ports Vaux9_v_n] +set_property IOSTANDARD LVCMOS33 [get_ports Vp_Vn_v_p] +set_property IOSTANDARD LVCMOS33 [get_ports Vp_Vn_v_n] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux0_v_p] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux0_v_n] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux1_v_p] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux1_v_n] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux8_v_p] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux8_v_n] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux9_v_p] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux9_v_n] + +set_property PACKAGE_PIN K9 [get_ports Vp_Vn_v_p] +set_property PACKAGE_PIN L10 [get_ports Vp_Vn_v_n] +set_property PACKAGE_PIN C20 [get_ports Vaux0_v_p] +set_property PACKAGE_PIN B20 [get_ports Vaux0_v_n] +set_property PACKAGE_PIN E17 [get_ports Vaux1_v_p] +set_property PACKAGE_PIN D18 [get_ports Vaux1_v_n] +set_property PACKAGE_PIN B19 [get_ports Vaux8_v_p] +set_property PACKAGE_PIN A20 [get_ports Vaux8_v_n] +set_property PACKAGE_PIN E18 [get_ports Vaux9_v_p] +set_property PACKAGE_PIN E19 [get_ports Vaux9_v_n] ### Expansion connector -# set_property IOSTANDARD LVCMOS33 [get_ports {exp_p_tri_io[*]}] -# set_property IOSTANDARD LVCMOS33 [get_ports {exp_n_tri_io[*]}] -# set_property SLEW FAST [get_ports {exp_p_tri_io[*]}] -# set_property SLEW FAST [get_ports {exp_n_tri_io[*]}] -# set_property DRIVE 8 [get_ports {exp_p_tri_io[*]}] -# set_property DRIVE 8 [get_ports {exp_n_tri_io[*]}] -# set_property PULLTYPE PULLUP [get_ports {exp_p_tri_io[*]}] -# set_property PULLTYPE PULLUP [get_ports {exp_n_tri_io[*]}] - -# set_property PACKAGE_PIN G17 [get_ports {exp_p_tri_io[0]}] -# set_property PACKAGE_PIN G18 [get_ports {exp_n_tri_io[0]}] -# set_property PACKAGE_PIN H16 [get_ports {exp_p_tri_io[1]}] -# set_property PACKAGE_PIN H17 [get_ports {exp_n_tri_io[1]}] -# set_property PACKAGE_PIN J18 [get_ports {exp_p_tri_io[2]}] -# set_property PACKAGE_PIN H18 [get_ports {exp_n_tri_io[2]}] -# set_property PACKAGE_PIN K17 [get_ports {exp_p_tri_io[3]}] -# set_property PACKAGE_PIN K18 [get_ports {exp_n_tri_io[3]}] -# set_property PACKAGE_PIN L14 [get_ports {exp_p_tri_io[4]}] -# set_property PACKAGE_PIN L15 [get_ports {exp_n_tri_io[4]}] -# set_property PACKAGE_PIN L16 [get_ports {exp_p_tri_io[5]}] -# set_property PACKAGE_PIN L17 [get_ports {exp_n_tri_io[5]}] -# set_property PACKAGE_PIN K16 [get_ports {exp_p_tri_io[6]}] -# set_property PACKAGE_PIN J16 [get_ports {exp_n_tri_io[6]}] -# set_property PACKAGE_PIN M14 [get_ports {exp_p_tri_io[7]}] -# set_property PACKAGE_PIN M15 [get_ports {exp_n_tri_io[7]}] - +set_property IOSTANDARD LVCMOS33 [get_ports {exp_p_tri_io[*]}] +set_property IOSTANDARD LVCMOS33 [get_ports {exp_n_tri_io[*]}] +set_property SLEW FAST [get_ports {exp_p_tri_io[*]}] +set_property SLEW FAST [get_ports {exp_n_tri_io[*]}] +set_property DRIVE 8 [get_ports {exp_p_tri_io[*]}] +set_property DRIVE 8 [get_ports {exp_n_tri_io[*]}] +set_property PULLTYPE PULLUP [get_ports {exp_p_tri_io[*]}] +set_property PULLTYPE PULLUP [get_ports {exp_n_tri_io[*]}] + +set_property PACKAGE_PIN G17 [get_ports {exp_p_tri_io[0]}] +set_property PACKAGE_PIN G18 [get_ports {exp_n_tri_io[0]}] +set_property PACKAGE_PIN H16 [get_ports {exp_p_tri_io[1]}] +set_property PACKAGE_PIN H17 [get_ports {exp_n_tri_io[1]}] +set_property PACKAGE_PIN J18 [get_ports {exp_p_tri_io[2]}] +set_property PACKAGE_PIN H18 [get_ports {exp_n_tri_io[2]}] +set_property PACKAGE_PIN K17 [get_ports {exp_p_tri_io[3]}] +set_property PACKAGE_PIN K18 [get_ports {exp_n_tri_io[3]}] +set_property PACKAGE_PIN L14 [get_ports {exp_p_tri_io[4]}] +set_property PACKAGE_PIN L15 [get_ports {exp_n_tri_io[4]}] +set_property PACKAGE_PIN L16 [get_ports {exp_p_tri_io[5]}] +set_property PACKAGE_PIN L17 [get_ports {exp_n_tri_io[5]}] +set_property PACKAGE_PIN K16 [get_ports {exp_p_tri_io[6]}] +set_property PACKAGE_PIN J16 [get_ports {exp_n_tri_io[6]}] +set_property PACKAGE_PIN M14 [get_ports {exp_p_tri_io[7]}] +set_property PACKAGE_PIN M15 [get_ports {exp_n_tri_io[7]}] + +set_property IOSTANDARD LVCMOS33 [get_ports exp_p_trg] +set_property SLEW FAST [get_ports exp_p_trg] +set_property DRIVE 8 [get_ports exp_p_trg] + +set_property PACKAGE_PIN M14 [get_ports exp_p_trg] + +set_property IOSTANDARD LVCMOS33 [get_ports {exp_n_alex[*]}] +set_property SLEW FAST [get_ports {exp_n_alex[*]}] +set_property DRIVE 8 [get_ports {exp_n_alex[*]}] + +set_property PACKAGE_PIN L15 [get_ports {exp_n_alex[0]}] +set_property PACKAGE_PIN L17 [get_ports {exp_n_alex[1]}] +set_property PACKAGE_PIN J16 [get_ports {exp_n_alex[2]}] +set_property PACKAGE_PIN M15 [get_ports {exp_n_alex[3]}] ### SATA connector -# set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_p_o[*]] -# set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_n_o[*]] +set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_p_o[*]] +set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_n_o[*]] -# set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_p_i[*]] -# set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_n_i[*]] +set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_p_i[*]] +set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_n_i[*]] -# set_property PACKAGE_PIN T12 [get_ports {daisy_p_o[0]}] -# set_property PACKAGE_PIN U12 [get_ports {daisy_n_o[0]}] +set_property PACKAGE_PIN T12 [get_ports {daisy_p_o[0]}] +set_property PACKAGE_PIN U12 [get_ports {daisy_n_o[0]}] -# set_property PACKAGE_PIN U14 [get_ports {daisy_p_o[1]}] -# set_property PACKAGE_PIN U15 [get_ports {daisy_n_o[1]}] +set_property PACKAGE_PIN U14 [get_ports {daisy_p_o[1]}] +set_property PACKAGE_PIN U15 [get_ports {daisy_n_o[1]}] -# set_property PACKAGE_PIN P14 [get_ports {daisy_p_i[0]}] -# set_property PACKAGE_PIN R14 [get_ports {daisy_n_i[0]}] +set_property PACKAGE_PIN P14 [get_ports {daisy_p_i[0]}] +set_property PACKAGE_PIN R14 [get_ports {daisy_n_i[0]}] -# set_property PACKAGE_PIN N18 [get_ports {daisy_p_i[1]}] -# set_property PACKAGE_PIN P19 [get_ports {daisy_n_i[1]}] +set_property PACKAGE_PIN N18 [get_ports {daisy_p_i[1]}] +set_property PACKAGE_PIN P19 [get_ports {daisy_n_i[1]}] ### LED From 4088a741543b03da1cafb454f04c147e819c64ff Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 15 Sep 2024 22:28:05 -0700 Subject: [PATCH 17/96] modify the board file to pass the validator --- HDL/boards/stemlab_125_14/brd/1.1/board.xml | 2 - .../stemlab_125_14/brd/1.1/part0_pins.xml | 136 +++++++++--------- 2 files changed, 68 insertions(+), 70 deletions(-) diff --git a/HDL/boards/stemlab_125_14/brd/1.1/board.xml b/HDL/boards/stemlab_125_14/brd/1.1/board.xml index a8d751d9..927a8f07 100644 --- a/HDL/boards/stemlab_125_14/brd/1.1/board.xml +++ b/HDL/boards/stemlab_125_14/brd/1.1/board.xml @@ -26,6 +26,4 @@ - - diff --git a/HDL/boards/stemlab_125_14/brd/1.1/part0_pins.xml b/HDL/boards/stemlab_125_14/brd/1.1/part0_pins.xml index 0d6e4168..cf9e5400 100644 --- a/HDL/boards/stemlab_125_14/brd/1.1/part0_pins.xml +++ b/HDL/boards/stemlab_125_14/brd/1.1/part0_pins.xml @@ -2,81 +2,81 @@ - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + - - + + From 0cd4b166b982dc340feb2ccd300b21778c374b65 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 15 Sep 2024 22:38:17 -0700 Subject: [PATCH 18/96] more updates to board files for schema validity and IO standards --- HDL/boards/stemlab_122_16/brd/1.0/board.xml | 2 - .../stemlab_122_16/brd/1.0/part0_pins.xml | 136 +++++++++--------- .../stemlab_125_14/brd/1.1/part0_pins.xml | 16 +-- 3 files changed, 76 insertions(+), 78 deletions(-) diff --git a/HDL/boards/stemlab_122_16/brd/1.0/board.xml b/HDL/boards/stemlab_122_16/brd/1.0/board.xml index 7a46bdb3..bfb54d83 100644 --- a/HDL/boards/stemlab_122_16/brd/1.0/board.xml +++ b/HDL/boards/stemlab_122_16/brd/1.0/board.xml @@ -26,6 +26,4 @@ - - diff --git a/HDL/boards/stemlab_122_16/brd/1.0/part0_pins.xml b/HDL/boards/stemlab_122_16/brd/1.0/part0_pins.xml index 3b45ff68..5f20aba7 100644 --- a/HDL/boards/stemlab_122_16/brd/1.0/part0_pins.xml +++ b/HDL/boards/stemlab_122_16/brd/1.0/part0_pins.xml @@ -2,81 +2,81 @@ - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - + + - - + + diff --git a/HDL/boards/stemlab_125_14/brd/1.1/part0_pins.xml b/HDL/boards/stemlab_125_14/brd/1.1/part0_pins.xml index cf9e5400..785721bd 100644 --- a/HDL/boards/stemlab_125_14/brd/1.1/part0_pins.xml +++ b/HDL/boards/stemlab_125_14/brd/1.1/part0_pins.xml @@ -29,14 +29,14 @@ - - - - - - - - + + + + + + + + From 1cffeadea3e14218de88261409aa5f06bd121ae9 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 15 Sep 2024 22:46:32 -0700 Subject: [PATCH 19/96] deleted empty connections section from snickerdoodle_black board --- HDL/boards/snickerdoodle_black/brd/1.0/board.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/HDL/boards/snickerdoodle_black/brd/1.0/board.xml b/HDL/boards/snickerdoodle_black/brd/1.0/board.xml index 6d54eaa5..cce08a60 100755 --- a/HDL/boards/snickerdoodle_black/brd/1.0/board.xml +++ b/HDL/boards/snickerdoodle_black/brd/1.0/board.xml @@ -25,6 +25,4 @@ - - From b33970a154fd248aa7371540a8e43e2225bab8a3 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 15 Sep 2024 22:55:23 -0700 Subject: [PATCH 20/96] add board files for the digilent eclypse Z7 board --- HDL/boards/eclypse_z7/brd/A.0/board.xml | 376 ++++++++++++ HDL/boards/eclypse_z7/brd/A.0/part0_pins.xml | 57 ++ HDL/boards/eclypse_z7/brd/A.0/preset.xml | 608 +++++++++++++++++++ HDL/boards/eclypse_z7/brd/B.0/board.xml | 376 ++++++++++++ HDL/boards/eclypse_z7/brd/B.0/part0_pins.xml | 57 ++ HDL/boards/eclypse_z7/brd/B.0/preset.xml | 608 +++++++++++++++++++ 6 files changed, 2082 insertions(+) create mode 100644 HDL/boards/eclypse_z7/brd/A.0/board.xml create mode 100644 HDL/boards/eclypse_z7/brd/A.0/part0_pins.xml create mode 100644 HDL/boards/eclypse_z7/brd/A.0/preset.xml create mode 100644 HDL/boards/eclypse_z7/brd/B.0/board.xml create mode 100644 HDL/boards/eclypse_z7/brd/B.0/part0_pins.xml create mode 100644 HDL/boards/eclypse_z7/brd/B.0/preset.xml diff --git a/HDL/boards/eclypse_z7/brd/A.0/board.xml b/HDL/boards/eclypse_z7/brd/A.0/board.xml new file mode 100644 index 00000000..f5148031 --- /dev/null +++ b/HDL/boards/eclypse_z7/brd/A.0/board.xml @@ -0,0 +1,376 @@ + + + + + A.0 + +1.0 +Eclypse Z7 + + + + + + + + + + + + + + + + + + + Buttons + + + + + + + + + + + + + + 8 LEDs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3.3V Single-Ended 125 MHz clock from Ethernet PHY + + + Buttons 1 to 0 + + + RGB leds 5 to 0 (3 per LED, Ordered "RGBRGB") + + + Pmod Connector JA + + + Pmod Connector JB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HDL/boards/eclypse_z7/brd/A.0/part0_pins.xml b/HDL/boards/eclypse_z7/brd/A.0/part0_pins.xml new file mode 100644 index 00000000..b2155f3e --- /dev/null +++ b/HDL/boards/eclypse_z7/brd/A.0/part0_pins.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HDL/boards/eclypse_z7/brd/A.0/preset.xml b/HDL/boards/eclypse_z7/brd/A.0/preset.xml new file mode 100644 index 00000000..352e4591 --- /dev/null +++ b/HDL/boards/eclypse_z7/brd/A.0/preset.xml @@ -0,0 +1,608 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HDL/boards/eclypse_z7/brd/B.0/board.xml b/HDL/boards/eclypse_z7/brd/B.0/board.xml new file mode 100644 index 00000000..20768cd0 --- /dev/null +++ b/HDL/boards/eclypse_z7/brd/B.0/board.xml @@ -0,0 +1,376 @@ + + + + + B.0 + +1.1 +Eclypse Z7 + + + + + + + + + + + + + + + + + + + Buttons + + + + + + + + + + + + + + 8 LEDs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3.3V Single-Ended 125 MHz clock from Ethernet PHY + + + Buttons 1 to 0 + + + RGB leds 5 to 0 (3 per LED, Ordered "RGBRGB") + + + Pmod Connector JA + + + Pmod Connector JB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HDL/boards/eclypse_z7/brd/B.0/part0_pins.xml b/HDL/boards/eclypse_z7/brd/B.0/part0_pins.xml new file mode 100644 index 00000000..71a442f5 --- /dev/null +++ b/HDL/boards/eclypse_z7/brd/B.0/part0_pins.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HDL/boards/eclypse_z7/brd/B.0/preset.xml b/HDL/boards/eclypse_z7/brd/B.0/preset.xml new file mode 100644 index 00000000..c32c99d5 --- /dev/null +++ b/HDL/boards/eclypse_z7/brd/B.0/preset.xml @@ -0,0 +1,608 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 5cd53f5b4871216d215e25d7623036727dd624b5 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 15 Sep 2024 22:56:58 -0700 Subject: [PATCH 21/96] add the eclypse boards to the vivado repo path --- HDL/scripts/Vivado_ocra_init.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HDL/scripts/Vivado_ocra_init.tcl b/HDL/scripts/Vivado_ocra_init.tcl index 29c658d2..4b6d4e5b 100644 --- a/HDL/scripts/Vivado_ocra_init.tcl +++ b/HDL/scripts/Vivado_ocra_init.tcl @@ -1,4 +1,4 @@ # source this from your Vivado_init.tcl set ocra_dir $::env(OCRA_DIR) -set_param board.repoPaths [list ${ocra_dir}/HDL/boards/snickerdoodle_black/brd/1.0/ ${ocra_dir}/HDL/boards/stemlab_125_14/brd/1.1/ ${ocra_dir}/HDL/boards/stemlab_122_16/brd/1.0/ ] +set_param board.repoPaths [list ${ocra_dir}/HDL/boards/snickerdoodle_black/brd/1.0/ ${ocra_dir}/HDL/boards/stemlab_125_14/brd/1.1/ ${ocra_dir}/HDL/boards/stemlab_122_16/brd/1.0/ ${ocra_dir}/HDL/boards/eclypse_z7/brd/A.0/ ${ocra_dir}/HDL/boards/eclypse_z7/brd/B.0/ ] From 8d332693d5c5ce33a5788e82d39456f30ef6785e Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 22 Sep 2024 06:42:09 -0700 Subject: [PATCH 22/96] renamed the projects folder for clarity --- .../base_pl/block_design.tcl | 0 HDL/{projects => blockdesign-projects}/ocra_mri/README.md | 0 .../ocra_mri/block_design.tcl | 8 ++++---- .../ocra_mri/client/COPYING | 0 .../ocra_mri/client/pulsed_nmr.py | 0 .../ocra_mri/client/pulsed_nmr.ui | 0 .../ocra_mri/filters/fir_0.r | 0 .../ocra_mri/gradient_dacs.tcl | 0 .../ocra_mri/gradient_dacs_daisy.tcl | 0 HDL/{projects => blockdesign-projects}/ocra_mri/nco.tcl | 0 HDL/{projects => blockdesign-projects}/ocra_mri/rx2.tcl | 0 .../ocra_mri/server-c++/pulsed_nmr_server.cpp | 0 .../ocra_mri/server/pulsed_nmr_old_backend.c | 0 HDL/{projects => blockdesign-projects}/ocra_mri/tx6.tcl | 0 .../shim_controller/block_design.tcl | 0 .../shim_controller/shim_dacs.tcl | 0 HDL/scripts/project.tcl | 4 ++-- 17 files changed, 6 insertions(+), 6 deletions(-) rename HDL/{projects => blockdesign-projects}/base_pl/block_design.tcl (100%) rename HDL/{projects => blockdesign-projects}/ocra_mri/README.md (100%) rename HDL/{projects => blockdesign-projects}/ocra_mri/block_design.tcl (98%) rename HDL/{projects => blockdesign-projects}/ocra_mri/client/COPYING (100%) rename HDL/{projects => blockdesign-projects}/ocra_mri/client/pulsed_nmr.py (100%) rename HDL/{projects => blockdesign-projects}/ocra_mri/client/pulsed_nmr.ui (100%) rename HDL/{projects => blockdesign-projects}/ocra_mri/filters/fir_0.r (100%) rename HDL/{projects => blockdesign-projects}/ocra_mri/gradient_dacs.tcl (100%) rename HDL/{projects => blockdesign-projects}/ocra_mri/gradient_dacs_daisy.tcl (100%) rename HDL/{projects => blockdesign-projects}/ocra_mri/nco.tcl (100%) rename HDL/{projects => blockdesign-projects}/ocra_mri/rx2.tcl (100%) rename HDL/{projects => blockdesign-projects}/ocra_mri/server-c++/pulsed_nmr_server.cpp (100%) rename HDL/{projects => blockdesign-projects}/ocra_mri/server/pulsed_nmr_old_backend.c (100%) rename HDL/{projects => blockdesign-projects}/ocra_mri/tx6.tcl (100%) rename HDL/{projects => blockdesign-projects}/shim_controller/block_design.tcl (100%) rename HDL/{projects => blockdesign-projects}/shim_controller/shim_dacs.tcl (100%) diff --git a/HDL/projects/base_pl/block_design.tcl b/HDL/blockdesign-projects/base_pl/block_design.tcl similarity index 100% rename from HDL/projects/base_pl/block_design.tcl rename to HDL/blockdesign-projects/base_pl/block_design.tcl diff --git a/HDL/projects/ocra_mri/README.md b/HDL/blockdesign-projects/ocra_mri/README.md similarity index 100% rename from HDL/projects/ocra_mri/README.md rename to HDL/blockdesign-projects/ocra_mri/README.md diff --git a/HDL/projects/ocra_mri/block_design.tcl b/HDL/blockdesign-projects/ocra_mri/block_design.tcl similarity index 98% rename from HDL/projects/ocra_mri/block_design.tcl rename to HDL/blockdesign-projects/ocra_mri/block_design.tcl index 7dc09320..aa406d18 100644 --- a/HDL/projects/ocra_mri/block_design.tcl +++ b/HDL/blockdesign-projects/ocra_mri/block_design.tcl @@ -101,7 +101,7 @@ cell xilinx.com:ip:xlconstant:1.1 const_0 # Removed this connection from rx: # slice_0/Din rst_slice_0/Dout module rx_0 { - source projects/ocra_mri/rx2.tcl + source blockdesign-projects/ocra_mri/rx2.tcl } { rate_slice/Din cfg8/config_2 fifo_0/S_AXIS adc_0/M_AXIS @@ -111,7 +111,7 @@ module rx_0 { # axis_interpolator_0/cfg_data cfg8/config_0 module tx_0 { - source projects/ocra_mri/tx6.tcl + source blockdesign-projects/ocra_mri/tx6.tcl } { slice_1/Din cfg8/config_3 axis_interpolator_0/cfg_data cfg8/config_0 @@ -121,7 +121,7 @@ module tx_0 { } module nco_0 { - source projects/ocra_mri/nco.tcl + source blockdesign-projects/ocra_mri/nco.tcl } { slice_1/Din cfg8/config_1 bcast_nco/M00_AXIS rx_0/mult_0/S_AXIS_B @@ -346,7 +346,7 @@ set_property RANGE 8K [get_bd_addr_segs ps_0/Data/SEG_gradient_writerz2_reg0] set_property OFFSET 0x40008000 [get_bd_addr_segs ps_0/Data/SEG_gradient_writerz2_reg0] module gradient_dac_0 { - source projects/ocra_mri/gradient_dacs.tcl + source blockdesign-projects/ocra_mri/gradient_dacs.tcl } { spi_sequencer_0/BRAM_PORTX gradient_memoryx/BRAM_PORTB spi_sequencer_0/BRAM_PORTY gradient_memoryy/BRAM_PORTB diff --git a/HDL/projects/ocra_mri/client/COPYING b/HDL/blockdesign-projects/ocra_mri/client/COPYING similarity index 100% rename from HDL/projects/ocra_mri/client/COPYING rename to HDL/blockdesign-projects/ocra_mri/client/COPYING diff --git a/HDL/projects/ocra_mri/client/pulsed_nmr.py b/HDL/blockdesign-projects/ocra_mri/client/pulsed_nmr.py similarity index 100% rename from HDL/projects/ocra_mri/client/pulsed_nmr.py rename to HDL/blockdesign-projects/ocra_mri/client/pulsed_nmr.py diff --git a/HDL/projects/ocra_mri/client/pulsed_nmr.ui b/HDL/blockdesign-projects/ocra_mri/client/pulsed_nmr.ui similarity index 100% rename from HDL/projects/ocra_mri/client/pulsed_nmr.ui rename to HDL/blockdesign-projects/ocra_mri/client/pulsed_nmr.ui diff --git a/HDL/projects/ocra_mri/filters/fir_0.r b/HDL/blockdesign-projects/ocra_mri/filters/fir_0.r similarity index 100% rename from HDL/projects/ocra_mri/filters/fir_0.r rename to HDL/blockdesign-projects/ocra_mri/filters/fir_0.r diff --git a/HDL/projects/ocra_mri/gradient_dacs.tcl b/HDL/blockdesign-projects/ocra_mri/gradient_dacs.tcl similarity index 100% rename from HDL/projects/ocra_mri/gradient_dacs.tcl rename to HDL/blockdesign-projects/ocra_mri/gradient_dacs.tcl diff --git a/HDL/projects/ocra_mri/gradient_dacs_daisy.tcl b/HDL/blockdesign-projects/ocra_mri/gradient_dacs_daisy.tcl similarity index 100% rename from HDL/projects/ocra_mri/gradient_dacs_daisy.tcl rename to HDL/blockdesign-projects/ocra_mri/gradient_dacs_daisy.tcl diff --git a/HDL/projects/ocra_mri/nco.tcl b/HDL/blockdesign-projects/ocra_mri/nco.tcl similarity index 100% rename from HDL/projects/ocra_mri/nco.tcl rename to HDL/blockdesign-projects/ocra_mri/nco.tcl diff --git a/HDL/projects/ocra_mri/rx2.tcl b/HDL/blockdesign-projects/ocra_mri/rx2.tcl similarity index 100% rename from HDL/projects/ocra_mri/rx2.tcl rename to HDL/blockdesign-projects/ocra_mri/rx2.tcl diff --git a/HDL/projects/ocra_mri/server-c++/pulsed_nmr_server.cpp b/HDL/blockdesign-projects/ocra_mri/server-c++/pulsed_nmr_server.cpp similarity index 100% rename from HDL/projects/ocra_mri/server-c++/pulsed_nmr_server.cpp rename to HDL/blockdesign-projects/ocra_mri/server-c++/pulsed_nmr_server.cpp diff --git a/HDL/projects/ocra_mri/server/pulsed_nmr_old_backend.c b/HDL/blockdesign-projects/ocra_mri/server/pulsed_nmr_old_backend.c similarity index 100% rename from HDL/projects/ocra_mri/server/pulsed_nmr_old_backend.c rename to HDL/blockdesign-projects/ocra_mri/server/pulsed_nmr_old_backend.c diff --git a/HDL/projects/ocra_mri/tx6.tcl b/HDL/blockdesign-projects/ocra_mri/tx6.tcl similarity index 100% rename from HDL/projects/ocra_mri/tx6.tcl rename to HDL/blockdesign-projects/ocra_mri/tx6.tcl diff --git a/HDL/projects/shim_controller/block_design.tcl b/HDL/blockdesign-projects/shim_controller/block_design.tcl similarity index 100% rename from HDL/projects/shim_controller/block_design.tcl rename to HDL/blockdesign-projects/shim_controller/block_design.tcl diff --git a/HDL/projects/shim_controller/shim_dacs.tcl b/HDL/blockdesign-projects/shim_controller/shim_dacs.tcl similarity index 100% rename from HDL/projects/shim_controller/shim_dacs.tcl rename to HDL/blockdesign-projects/shim_controller/shim_dacs.tcl diff --git a/HDL/scripts/project.tcl b/HDL/scripts/project.tcl index a3fff02c..6fbfb86f 100644 --- a/HDL/scripts/project.tcl +++ b/HDL/scripts/project.tcl @@ -104,7 +104,7 @@ proc get_slice_pin {pin_name from to {cell_name ""}} { } -source projects/$project_name/block_design.tcl +source blockdesign-projects/$project_name/block_design.tcl rename cell {} rename module {} @@ -118,7 +118,7 @@ make_wrapper -files [get_files $bd_path/system.bd] -top add_files -norecurse $bd_path/hdl/system_wrapper.v -set files [glob -nocomplain projects/$project_name/*.v projects/$project_name/*.sv] +set files [glob -nocomplain blockdesign-projects/$project_name/*.v blockdesign-projects/$project_name/*.sv] if {[llength $files] > 0} { add_files -norecurse $files } From 9c57daf044fce27ff1d45248842cc7bb81356688 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 22 Sep 2024 06:44:30 -0700 Subject: [PATCH 23/96] updated to newer versions of python packages for relax2 --- Applications/relax2/poetry.lock | 716 +++++++++++++++++++++++++++----- 1 file changed, 607 insertions(+), 109 deletions(-) diff --git a/Applications/relax2/poetry.lock b/Applications/relax2/poetry.lock index 60e7218a..798e1602 100644 --- a/Applications/relax2/poetry.lock +++ b/Applications/relax2/poetry.lock @@ -1,81 +1,362 @@ +# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. + [[package]] name = "contourpy" -version = "1.0.7" +version = "1.1.1" description = "Python library for calculating contours of 2D quadrilateral grids" category = "main" optional = false python-versions = ">=3.8" +files = [ + {file = "contourpy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:46e24f5412c948d81736509377e255f6040e94216bf1a9b5ea1eaa9d29f6ec1b"}, + {file = "contourpy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e48694d6a9c5a26ee85b10130c77a011a4fedf50a7279fa0bdaf44bafb4299d"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a66045af6cf00e19d02191ab578a50cb93b2028c3eefed999793698e9ea768ae"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ebf42695f75ee1a952f98ce9775c873e4971732a87334b099dde90b6af6a916"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6aec19457617ef468ff091669cca01fa7ea557b12b59a7908b9474bb9674cf0"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:462c59914dc6d81e0b11f37e560b8a7c2dbab6aca4f38be31519d442d6cde1a1"}, + {file = "contourpy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6d0a8efc258659edc5299f9ef32d8d81de8b53b45d67bf4bfa3067f31366764d"}, + {file = "contourpy-1.1.1-cp310-cp310-win32.whl", hash = "sha256:d6ab42f223e58b7dac1bb0af32194a7b9311065583cc75ff59dcf301afd8a431"}, + {file = "contourpy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:549174b0713d49871c6dee90a4b499d3f12f5e5f69641cd23c50a4542e2ca1eb"}, + {file = "contourpy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:407d864db716a067cc696d61fa1ef6637fedf03606e8417fe2aeed20a061e6b2"}, + {file = "contourpy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe80c017973e6a4c367e037cb31601044dd55e6bfacd57370674867d15a899b"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e30aaf2b8a2bac57eb7e1650df1b3a4130e8d0c66fc2f861039d507a11760e1b"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3de23ca4f381c3770dee6d10ead6fff524d540c0f662e763ad1530bde5112532"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:566f0e41df06dfef2431defcfaa155f0acfa1ca4acbf8fd80895b1e7e2ada40e"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b04c2f0adaf255bf756cf08ebef1be132d3c7a06fe6f9877d55640c5e60c72c5"}, + {file = "contourpy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d0c188ae66b772d9d61d43c6030500344c13e3f73a00d1dc241da896f379bb62"}, + {file = "contourpy-1.1.1-cp311-cp311-win32.whl", hash = "sha256:0683e1ae20dc038075d92e0e0148f09ffcefab120e57f6b4c9c0f477ec171f33"}, + {file = "contourpy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:8636cd2fc5da0fb102a2504fa2c4bea3cbc149533b345d72cdf0e7a924decc45"}, + {file = "contourpy-1.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:560f1d68a33e89c62da5da4077ba98137a5e4d3a271b29f2f195d0fba2adcb6a"}, + {file = "contourpy-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24216552104ae8f3b34120ef84825400b16eb6133af2e27a190fdc13529f023e"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56de98a2fb23025882a18b60c7f0ea2d2d70bbbcfcf878f9067234b1c4818442"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:07d6f11dfaf80a84c97f1a5ba50d129d9303c5b4206f776e94037332e298dda8"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1eaac5257a8f8a047248d60e8f9315c6cff58f7803971170d952555ef6344a7"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19557fa407e70f20bfaba7d55b4d97b14f9480856c4fb65812e8a05fe1c6f9bf"}, + {file = "contourpy-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:081f3c0880712e40effc5f4c3b08feca6d064cb8cfbb372ca548105b86fd6c3d"}, + {file = "contourpy-1.1.1-cp312-cp312-win32.whl", hash = "sha256:059c3d2a94b930f4dafe8105bcdc1b21de99b30b51b5bce74c753686de858cb6"}, + {file = "contourpy-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:f44d78b61740e4e8c71db1cf1fd56d9050a4747681c59ec1094750a658ceb970"}, + {file = "contourpy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:70e5a10f8093d228bb2b552beeb318b8928b8a94763ef03b858ef3612b29395d"}, + {file = "contourpy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8394e652925a18ef0091115e3cc191fef350ab6dc3cc417f06da66bf98071ae9"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5bd5680f844c3ff0008523a71949a3ff5e4953eb7701b28760805bc9bcff217"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66544f853bfa85c0d07a68f6c648b2ec81dafd30f272565c37ab47a33b220684"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0c02b75acfea5cab07585d25069207e478d12309557f90a61b5a3b4f77f46ce"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41339b24471c58dc1499e56783fedc1afa4bb018bcd035cfb0ee2ad2a7501ef8"}, + {file = "contourpy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f29fb0b3f1217dfe9362ec55440d0743fe868497359f2cf93293f4b2701b8251"}, + {file = "contourpy-1.1.1-cp38-cp38-win32.whl", hash = "sha256:f9dc7f933975367251c1b34da882c4f0e0b2e24bb35dc906d2f598a40b72bfc7"}, + {file = "contourpy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:498e53573e8b94b1caeb9e62d7c2d053c263ebb6aa259c81050766beb50ff8d9"}, + {file = "contourpy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ba42e3810999a0ddd0439e6e5dbf6d034055cdc72b7c5c839f37a7c274cb4eba"}, + {file = "contourpy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c06e4c6e234fcc65435223c7b2a90f286b7f1b2733058bdf1345d218cc59e34"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca6fab080484e419528e98624fb5c4282148b847e3602dc8dbe0cb0669469887"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93df44ab351119d14cd1e6b52a5063d3336f0754b72736cc63db59307dabb718"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eafbef886566dc1047d7b3d4b14db0d5b7deb99638d8e1be4e23a7c7ac59ff0f"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efe0fab26d598e1ec07d72cf03eaeeba8e42b4ecf6b9ccb5a356fde60ff08b85"}, + {file = "contourpy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f08e469821a5e4751c97fcd34bcb586bc243c39c2e39321822060ba902eac49e"}, + {file = "contourpy-1.1.1-cp39-cp39-win32.whl", hash = "sha256:bfc8a5e9238232a45ebc5cb3bfee71f1167064c8d382cadd6076f0d51cff1da0"}, + {file = "contourpy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:c84fdf3da00c2827d634de4fcf17e3e067490c4aea82833625c4c8e6cdea0887"}, + {file = "contourpy-1.1.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:229a25f68046c5cf8067d6d6351c8b99e40da11b04d8416bf8d2b1d75922521e"}, + {file = "contourpy-1.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a10dab5ea1bd4401c9483450b5b0ba5416be799bbd50fc7a6cc5e2a15e03e8a3"}, + {file = "contourpy-1.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4f9147051cb8fdb29a51dc2482d792b3b23e50f8f57e3720ca2e3d438b7adf23"}, + {file = "contourpy-1.1.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a75cc163a5f4531a256f2c523bd80db509a49fc23721b36dd1ef2f60ff41c3cb"}, + {file = "contourpy-1.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b53d5769aa1f2d4ea407c65f2d1d08002952fac1d9e9d307aa2e1023554a163"}, + {file = "contourpy-1.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11b836b7dbfb74e049c302bbf74b4b8f6cb9d0b6ca1bf86cfa8ba144aedadd9c"}, + {file = "contourpy-1.1.1.tar.gz", hash = "sha256:96ba37c2e24b7212a77da85004c38e7c4d155d3e72a45eeaf22c1f03f607e8ab"}, +] [package.dependencies] -numpy = ">=1.16" +numpy = {version = ">=1.16,<2.0", markers = "python_version <= \"3.11\""} [package.extras] -bokeh = ["bokeh", "chromedriver", "selenium"] -docs = ["furo", "sphinx-copybutton"] -mypy = ["contourpy", "docutils-stubs", "mypy (==0.991)", "types-pillow"] -test = ["matplotlib", "pillow", "pytest"] -test-no-images = ["pytest"] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.4.1)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "wurlitzer"] [[package]] name = "cycler" -version = "0.11.0" +version = "0.12.1" description = "Composable style cycles" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" +files = [ + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, +] + +[package.extras] +docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] +tests = ["pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "fonttools" -version = "4.39.2" +version = "4.53.1" description = "Tools to manipulate font files" category = "main" optional = false python-versions = ">=3.8" +files = [ + {file = "fonttools-4.53.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0679a30b59d74b6242909945429dbddb08496935b82f91ea9bf6ad240ec23397"}, + {file = "fonttools-4.53.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8bf06b94694251861ba7fdeea15c8ec0967f84c3d4143ae9daf42bbc7717fe3"}, + {file = "fonttools-4.53.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b96cd370a61f4d083c9c0053bf634279b094308d52fdc2dd9a22d8372fdd590d"}, + {file = "fonttools-4.53.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1c7c5aa18dd3b17995898b4a9b5929d69ef6ae2af5b96d585ff4005033d82f0"}, + {file = "fonttools-4.53.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e013aae589c1c12505da64a7d8d023e584987e51e62006e1bb30d72f26522c41"}, + {file = "fonttools-4.53.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9efd176f874cb6402e607e4cc9b4a9cd584d82fc34a4b0c811970b32ba62501f"}, + {file = "fonttools-4.53.1-cp310-cp310-win32.whl", hash = "sha256:c8696544c964500aa9439efb6761947393b70b17ef4e82d73277413f291260a4"}, + {file = "fonttools-4.53.1-cp310-cp310-win_amd64.whl", hash = "sha256:8959a59de5af6d2bec27489e98ef25a397cfa1774b375d5787509c06659b3671"}, + {file = "fonttools-4.53.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1"}, + {file = "fonttools-4.53.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923"}, + {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719"}, + {file = "fonttools-4.53.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bee32ea8765e859670c4447b0817514ca79054463b6b79784b08a8df3a4d78e3"}, + {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6e08f572625a1ee682115223eabebc4c6a2035a6917eac6f60350aba297ccadb"}, + {file = "fonttools-4.53.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b21952c092ffd827504de7e66b62aba26fdb5f9d1e435c52477e6486e9d128b2"}, + {file = "fonttools-4.53.1-cp311-cp311-win32.whl", hash = "sha256:9dfdae43b7996af46ff9da520998a32b105c7f098aeea06b2226b30e74fbba88"}, + {file = "fonttools-4.53.1-cp311-cp311-win_amd64.whl", hash = "sha256:d4d0096cb1ac7a77b3b41cd78c9b6bc4a400550e21dc7a92f2b5ab53ed74eb02"}, + {file = "fonttools-4.53.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d92d3c2a1b39631a6131c2fa25b5406855f97969b068e7e08413325bc0afba58"}, + {file = "fonttools-4.53.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3b3c8ebafbee8d9002bd8f1195d09ed2bd9ff134ddec37ee8f6a6375e6a4f0e8"}, + {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f029c095ad66c425b0ee85553d0dc326d45d7059dbc227330fc29b43e8ba60"}, + {file = "fonttools-4.53.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f5e6c3510b79ea27bb1ebfcc67048cde9ec67afa87c7dd7efa5c700491ac7f"}, + {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f677ce218976496a587ab17140da141557beb91d2a5c1a14212c994093f2eae2"}, + {file = "fonttools-4.53.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f"}, + {file = "fonttools-4.53.1-cp312-cp312-win32.whl", hash = "sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670"}, + {file = "fonttools-4.53.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab"}, + {file = "fonttools-4.53.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c818c058404eb2bba05e728d38049438afd649e3c409796723dfc17cd3f08749"}, + {file = "fonttools-4.53.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:651390c3b26b0c7d1f4407cad281ee7a5a85a31a110cbac5269de72a51551ba2"}, + {file = "fonttools-4.53.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e54f1bba2f655924c1138bbc7fa91abd61f45c68bd65ab5ed985942712864bbb"}, + {file = "fonttools-4.53.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9cd19cf4fe0595ebdd1d4915882b9440c3a6d30b008f3cc7587c1da7b95be5f"}, + {file = "fonttools-4.53.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2af40ae9cdcb204fc1d8f26b190aa16534fcd4f0df756268df674a270eab575d"}, + {file = "fonttools-4.53.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:35250099b0cfb32d799fb5d6c651220a642fe2e3c7d2560490e6f1d3f9ae9169"}, + {file = "fonttools-4.53.1-cp38-cp38-win32.whl", hash = "sha256:f08df60fbd8d289152079a65da4e66a447efc1d5d5a4d3f299cdd39e3b2e4a7d"}, + {file = "fonttools-4.53.1-cp38-cp38-win_amd64.whl", hash = "sha256:7b6b35e52ddc8fb0db562133894e6ef5b4e54e1283dff606fda3eed938c36fc8"}, + {file = "fonttools-4.53.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75a157d8d26c06e64ace9df037ee93a4938a4606a38cb7ffaf6635e60e253b7a"}, + {file = "fonttools-4.53.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4824c198f714ab5559c5be10fd1adf876712aa7989882a4ec887bf1ef3e00e31"}, + {file = "fonttools-4.53.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:becc5d7cb89c7b7afa8321b6bb3dbee0eec2b57855c90b3e9bf5fb816671fa7c"}, + {file = "fonttools-4.53.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84ec3fb43befb54be490147b4a922b5314e16372a643004f182babee9f9c3407"}, + {file = "fonttools-4.53.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:73379d3ffdeecb376640cd8ed03e9d2d0e568c9d1a4e9b16504a834ebadc2dfb"}, + {file = "fonttools-4.53.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:02569e9a810f9d11f4ae82c391ebc6fb5730d95a0657d24d754ed7763fb2d122"}, + {file = "fonttools-4.53.1-cp39-cp39-win32.whl", hash = "sha256:aae7bd54187e8bf7fd69f8ab87b2885253d3575163ad4d669a262fe97f0136cb"}, + {file = "fonttools-4.53.1-cp39-cp39-win_amd64.whl", hash = "sha256:e5b708073ea3d684235648786f5f6153a48dc8762cdfe5563c57e80787c29fbb"}, + {file = "fonttools-4.53.1-py3-none-any.whl", hash = "sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d"}, + {file = "fonttools-4.53.1.tar.gz", hash = "sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4"}, +] [package.extras] -all = ["fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "zopfli (>=0.1.4)", "lz4 (>=1.7.4.2)", "matplotlib", "sympy", "skia-pathops (>=0.5.0)", "uharfbuzz (>=0.23.0)", "brotlicffi (>=0.8.0)", "scipy", "brotli (>=1.0.1)", "munkres", "unicodedata2 (>=15.0.0)", "xattr"] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] -interpolatable = ["scipy", "munkres"] -lxml = ["lxml (>=4.0,<5)"] +interpolatable = ["munkres", "pycairo", "scipy"] +lxml = ["lxml (>=4.0)"] pathops = ["skia-pathops (>=0.5.0)"] plot = ["matplotlib"] repacker = ["uharfbuzz (>=0.23.0)"] symfont = ["sympy"] type1 = ["xattr"] ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=15.0.0)"] -woff = ["zopfli (>=0.1.4)", "brotlicffi (>=0.8.0)", "brotli (>=1.0.1)"] +unicode = ["unicodedata2 (>=15.1.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "importlib-resources" -version = "5.12.0" +version = "6.4.5" description = "Read resources from Python packages" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717"}, + {file = "importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065"}, +] [package.dependencies] zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "sphinx-lint", "jaraco.tidelift (>=1.4)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "pytest-flake8"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy"] [[package]] name = "kiwisolver" -version = "1.4.4" +version = "1.4.7" description = "A fast implementation of the Cassowary constraint solver" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8a9c83f75223d5e48b0bc9cb1bf2776cf01563e00ade8775ffe13b0b6e1af3a6"}, + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58370b1ffbd35407444d57057b57da5d6549d2d854fa30249771775c63b5fe17"}, + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aa0abdf853e09aff551db11fce173e2177d00786c688203f52c87ad7fcd91ef9"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d53103597a252fb3ab8b5845af04c7a26d5e7ea8122303dd7a021176a87e8b9"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:88f17c5ffa8e9462fb79f62746428dd57b46eb931698e42e990ad63103f35e6c"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a9ca9c710d598fd75ee5de59d5bda2684d9db36a9f50b6125eaea3969c2599"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f4d742cb7af1c28303a51b7a27aaee540e71bb8e24f68c736f6f2ffc82f2bf05"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e28c7fea2196bf4c2f8d46a0415c77a1c480cc0724722f23d7410ffe9842c407"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e968b84db54f9d42046cf154e02911e39c0435c9801681e3fc9ce8a3c4130278"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0c18ec74c0472de033e1bebb2911c3c310eef5649133dd0bedf2a169a1b269e5"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8f0ea6da6d393d8b2e187e6a5e3fb81f5862010a40c3945e2c6d12ae45cfb2ad"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f106407dda69ae456dd1227966bf445b157ccc80ba0dff3802bb63f30b74e895"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:84ec80df401cfee1457063732d90022f93951944b5b58975d34ab56bb150dfb3"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win32.whl", hash = "sha256:71bb308552200fb2c195e35ef05de12f0c878c07fc91c270eb3d6e41698c3bcc"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:44756f9fd339de0fb6ee4f8c1696cfd19b2422e0d70b4cefc1cc7f1f64045a8c"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:78a42513018c41c2ffd262eb676442315cbfe3c44eed82385c2ed043bc63210a"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d2b0e12a42fb4e72d509fc994713d099cbb15ebf1103545e8a45f14da2dfca54"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2a8781ac3edc42ea4b90bc23e7d37b665d89423818e26eb6df90698aa2287c95"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46707a10836894b559e04b0fd143e343945c97fd170d69a2d26d640b4e297935"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef97b8df011141c9b0f6caf23b29379f87dd13183c978a30a3c546d2c47314cb"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab58c12a2cd0fc769089e6d38466c46d7f76aced0a1f54c77652446733d2d02"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:803b8e1459341c1bb56d1c5c010406d5edec8a0713a0945851290a7930679b51"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9a9e8a507420fe35992ee9ecb302dab68550dedc0da9e2880dd88071c5fb052"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18077b53dc3bb490e330669a99920c5e6a496889ae8c63b58fbc57c3d7f33a18"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6af936f79086a89b3680a280c47ea90b4df7047b5bdf3aa5c524bbedddb9e545"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3abc5b19d24af4b77d1598a585b8a719beb8569a71568b66f4ebe1fb0449460b"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:933d4de052939d90afbe6e9d5273ae05fb836cc86c15b686edd4b3560cc0ee36"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:65e720d2ab2b53f1f72fb5da5fb477455905ce2c88aaa671ff0a447c2c80e8e3"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3bf1ed55088f214ba6427484c59553123fdd9b218a42bbc8c6496d6754b1e523"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win32.whl", hash = "sha256:4c00336b9dd5ad96d0a558fd18a8b6f711b7449acce4c157e7343ba92dd0cf3d"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:929e294c1ac1e9f615c62a4e4313ca1823ba37326c164ec720a803287c4c499b"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:e33e8fbd440c917106b237ef1a2f1449dfbb9b6f6e1ce17c94cd6a1e0d438376"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5360cc32706dab3931f738d3079652d20982511f7c0ac5711483e6eab08efff2"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942216596dc64ddb25adb215c3c783215b23626f8d84e8eff8d6d45c3f29f75a"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:48b571ecd8bae15702e4f22d3ff6a0f13e54d3d00cd25216d5e7f658242065ee"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad42ba922c67c5f219097b28fae965e10045ddf145d2928bfac2eb2e17673640"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:612a10bdae23404a72941a0fc8fa2660c6ea1217c4ce0dbcab8a8f6543ea9e7f"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e838bba3a3bac0fe06d849d29772eb1afb9745a59710762e4ba3f4cb8424483"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22f499f6157236c19f4bbbd472fa55b063db77a16cd74d49afe28992dff8c258"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693902d433cf585133699972b6d7c42a8b9f8f826ebcaf0132ff55200afc599e"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4e77f2126c3e0b0d055f44513ed349038ac180371ed9b52fe96a32aa071a5107"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:657a05857bda581c3656bfc3b20e353c232e9193eb167766ad2dc58b56504948"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4bfa75a048c056a411f9705856abfc872558e33c055d80af6a380e3658766038"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:34ea1de54beef1c104422d210c47c7d2a4999bdecf42c7b5718fbe59a4cac383"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:90da3b5f694b85231cf93586dad5e90e2d71b9428f9aad96952c99055582f520"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win32.whl", hash = "sha256:18e0cca3e008e17fe9b164b55735a325140a5a35faad8de92dd80265cd5eb80b"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:58cb20602b18f86f83a5c87d3ee1c766a79c0d452f8def86d925e6c60fbf7bfb"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:f5a8b53bdc0b3961f8b6125e198617c40aeed638b387913bf1ce78afb1b0be2a"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2e6039dcbe79a8e0f044f1c39db1986a1b8071051efba3ee4d74f5b365f5226e"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a1ecf0ac1c518487d9d23b1cd7139a6a65bc460cd101ab01f1be82ecf09794b6"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ab9ccab2b5bd5702ab0803676a580fffa2aa178c2badc5557a84cc943fcf750"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f816dd2277f8d63d79f9c8473a79fe54047bc0467754962840782c575522224d"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf8bcc23ceb5a1b624572a1623b9f79d2c3b337c8c455405ef231933a10da379"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dea0bf229319828467d7fca8c7c189780aa9ff679c94539eed7532ebe33ed37c"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c06a4c7cf15ec739ce0e5971b26c93638730090add60e183530d70848ebdd34"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913983ad2deb14e66d83c28b632fd35ba2b825031f2fa4ca29675e665dfecbe1"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5337ec7809bcd0f424c6b705ecf97941c46279cf5ed92311782c7c9c2026f07f"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c26ed10c4f6fa6ddb329a5120ba3b6db349ca192ae211e882970bfc9d91420b"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c619b101e6de2222c1fcb0531e1b17bbffbe54294bfba43ea0d411d428618c27"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:073a36c8273647592ea332e816e75ef8da5c303236ec0167196793eb1e34657a"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3ce6b2b0231bda412463e152fc18335ba32faf4e8c23a754ad50ffa70e4091ee"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win32.whl", hash = "sha256:f4c9aee212bc89d4e13f58be11a56cc8036cabad119259d12ace14b34476fd07"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:8a3ec5aa8e38fc4c8af308917ce12c536f1c88452ce554027e55b22cbbfbff76"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:76c8094ac20ec259471ac53e774623eb62e6e1f56cd8690c67ce6ce4fcb05650"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5d5abf8f8ec1f4e22882273c423e16cae834c36856cac348cfbfa68e01c40f3a"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:aeb3531b196ef6f11776c21674dba836aeea9d5bd1cf630f869e3d90b16cfade"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7d755065e4e866a8086c9bdada157133ff466476a2ad7861828e17b6026e22c"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08471d4d86cbaec61f86b217dd938a83d85e03785f51121e791a6e6689a3be95"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bbfcb7165ce3d54a3dfbe731e470f65739c4c1f85bb1018ee912bae139e263b"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d34eb8494bea691a1a450141ebb5385e4b69d38bb8403b5146ad279f4b30fa3"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9242795d174daa40105c1d86aba618e8eab7bf96ba8c3ee614da8302a9f95503"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a0f64a48bb81af7450e641e3fe0b0394d7381e342805479178b3d335d60ca7cf"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8e045731a5416357638d1700927529e2b8ab304811671f665b225f8bf8d8f933"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4322872d5772cae7369f8351da1edf255a604ea7087fe295411397d0cfd9655e"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e1631290ee9271dffe3062d2634c3ecac02c83890ada077d225e081aca8aab89"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:edcfc407e4eb17e037bca59be0e85a2031a2ac87e4fed26d3e9df88b4165f92d"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4d05d81ecb47d11e7f8932bd8b61b720bf0b41199358f3f5e36d38e28f0532c5"}, + {file = "kiwisolver-1.4.7-cp38-cp38-win32.whl", hash = "sha256:b38ac83d5f04b15e515fd86f312479d950d05ce2368d5413d46c088dda7de90a"}, + {file = "kiwisolver-1.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:d83db7cde68459fc803052a55ace60bea2bae361fc3b7a6d5da07e11954e4b09"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3f9362ecfca44c863569d3d3c033dbe8ba452ff8eed6f6b5806382741a1334bd"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8df2eb9b2bac43ef8b082e06f750350fbbaf2887534a5be97f6cf07b19d9583"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f32d6edbc638cde7652bd690c3e728b25332acbadd7cad670cc4a02558d9c417"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e2e6c39bd7b9372b0be21456caab138e8e69cc0fc1190a9dfa92bd45a1e6e904"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dda56c24d869b1193fcc763f1284b9126550eaf84b88bbc7256e15028f19188a"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79849239c39b5e1fd906556c474d9b0439ea6792b637511f3fe3a41158d89ca8"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e3bc157fed2a4c02ec468de4ecd12a6e22818d4f09cde2c31ee3226ffbefab2"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3da53da805b71e41053dc670f9a820d1157aae77b6b944e08024d17bcd51ef88"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8705f17dfeb43139a692298cb6637ee2e59c0194538153e83e9ee0c75c2eddde"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:82a5c2f4b87c26bb1a0ef3d16b5c4753434633b83d365cc0ddf2770c93829e3c"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce8be0466f4c0d585cdb6c1e2ed07232221df101a4c6f28821d2aa754ca2d9e2"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:409afdfe1e2e90e6ee7fc896f3df9a7fec8e793e58bfa0d052c8a82f99c37abb"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5b9c3f4ee0b9a439d2415012bd1b1cc2df59e4d6a9939f4d669241d30b414327"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win32.whl", hash = "sha256:a79ae34384df2b615eefca647a2873842ac3b596418032bef9a7283675962644"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:cf0438b42121a66a3a667de17e779330fc0f20b0d97d59d2f2121e182b0505e4"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:764202cc7e70f767dab49e8df52c7455e8de0df5d858fa801a11aa0d882ccf3f"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:94252291e3fe68001b1dd747b4c0b3be12582839b95ad4d1b641924d68fd4643"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5b7dfa3b546da08a9f622bb6becdb14b3e24aaa30adba66749d38f3cc7ea9706"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd3de6481f4ed8b734da5df134cd5a6a64fe32124fe83dde1e5b5f29fe30b1e6"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a91b5f9f1205845d488c928e8570dcb62b893372f63b8b6e98b863ebd2368ff2"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fa14dbd66b8b8f470d5fc79c089a66185619d31645f9b0773b88b19f7223c4"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:eb542fe7933aa09d8d8f9d9097ef37532a7df6497819d16efe4359890a2f417a"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bfa1acfa0c54932d5607e19a2c24646fb4c1ae2694437789129cf099789a3b00"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:eee3ea935c3d227d49b4eb85660ff631556841f6e567f0f7bda972df6c2c9935"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f3160309af4396e0ed04db259c3ccbfdc3621b5559b5453075e5de555e1f3a1b"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a17f6a29cf8935e587cc8a4dbfc8368c55edc645283db0ce9801016f83526c2d"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10849fb2c1ecbfae45a693c070e0320a91b35dd4bcf58172c023b994283a124d"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ac542bf38a8a4be2dc6b15248d36315ccc65f0743f7b1a76688ffb6b5129a5c2"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8b01aac285f91ca889c800042c35ad3b239e704b150cfd3382adfc9dcc780e39"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:48be928f59a1f5c8207154f935334d374e79f2b5d212826307d072595ad76a2e"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f37cfe618a117e50d8c240555331160d73d0411422b59b5ee217843d7b693608"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:599b5c873c63a1f6ed7eead644a8a380cfbdf5db91dcb6f85707aaab213b1674"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:801fa7802e5cfabe3ab0c81a34c323a319b097dfb5004be950482d882f3d7225"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0c6c43471bc764fad4bc99c5c2d6d16a676b1abf844ca7c8702bdae92df01ee0"}, + {file = "kiwisolver-1.4.7.tar.gz", hash = "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60"}, +] [[package]] name = "matplotlib" -version = "3.7.1" +version = "3.7.5" description = "Python plotting package" category = "main" optional = false python-versions = ">=3.8" +files = [ + {file = "matplotlib-3.7.5-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:4a87b69cb1cb20943010f63feb0b2901c17a3b435f75349fd9865713bfa63925"}, + {file = "matplotlib-3.7.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d3ce45010fefb028359accebb852ca0c21bd77ec0f281952831d235228f15810"}, + {file = "matplotlib-3.7.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fbea1e762b28400393d71be1a02144aa16692a3c4c676ba0178ce83fc2928fdd"}, + {file = "matplotlib-3.7.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec0e1adc0ad70ba8227e957551e25a9d2995e319c29f94a97575bb90fa1d4469"}, + {file = "matplotlib-3.7.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6738c89a635ced486c8a20e20111d33f6398a9cbebce1ced59c211e12cd61455"}, + {file = "matplotlib-3.7.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1210b7919b4ed94b5573870f316bca26de3e3b07ffdb563e79327dc0e6bba515"}, + {file = "matplotlib-3.7.5-cp310-cp310-win32.whl", hash = "sha256:068ebcc59c072781d9dcdb82f0d3f1458271c2de7ca9c78f5bd672141091e9e1"}, + {file = "matplotlib-3.7.5-cp310-cp310-win_amd64.whl", hash = "sha256:f098ffbaab9df1e3ef04e5a5586a1e6b1791380698e84938d8640961c79b1fc0"}, + {file = "matplotlib-3.7.5-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:f65342c147572673f02a4abec2d5a23ad9c3898167df9b47c149f32ce61ca078"}, + {file = "matplotlib-3.7.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4ddf7fc0e0dc553891a117aa083039088d8a07686d4c93fb8a810adca68810af"}, + {file = "matplotlib-3.7.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0ccb830fc29442360d91be48527809f23a5dcaee8da5f4d9b2d5b867c1b087b8"}, + {file = "matplotlib-3.7.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efc6bb28178e844d1f408dd4d6341ee8a2e906fc9e0fa3dae497da4e0cab775d"}, + {file = "matplotlib-3.7.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b15c4c2d374f249f324f46e883340d494c01768dd5287f8bc00b65b625ab56c"}, + {file = "matplotlib-3.7.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d028555421912307845e59e3de328260b26d055c5dac9b182cc9783854e98fb"}, + {file = "matplotlib-3.7.5-cp311-cp311-win32.whl", hash = "sha256:fe184b4625b4052fa88ef350b815559dd90cc6cc8e97b62f966e1ca84074aafa"}, + {file = "matplotlib-3.7.5-cp311-cp311-win_amd64.whl", hash = "sha256:084f1f0f2f1010868c6f1f50b4e1c6f2fb201c58475494f1e5b66fed66093647"}, + {file = "matplotlib-3.7.5-cp312-cp312-macosx_10_12_universal2.whl", hash = "sha256:34bceb9d8ddb142055ff27cd7135f539f2f01be2ce0bafbace4117abe58f8fe4"}, + {file = "matplotlib-3.7.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c5a2134162273eb8cdfd320ae907bf84d171de948e62180fa372a3ca7cf0f433"}, + {file = "matplotlib-3.7.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:039ad54683a814002ff37bf7981aa1faa40b91f4ff84149beb53d1eb64617980"}, + {file = "matplotlib-3.7.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d742ccd1b09e863b4ca58291728db645b51dab343eebb08d5d4b31b308296ce"}, + {file = "matplotlib-3.7.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:743b1c488ca6a2bc7f56079d282e44d236bf375968bfd1b7ba701fd4d0fa32d6"}, + {file = "matplotlib-3.7.5-cp312-cp312-win_amd64.whl", hash = "sha256:fbf730fca3e1f23713bc1fae0a57db386e39dc81ea57dc305c67f628c1d7a342"}, + {file = "matplotlib-3.7.5-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:cfff9b838531698ee40e40ea1a8a9dc2c01edb400b27d38de6ba44c1f9a8e3d2"}, + {file = "matplotlib-3.7.5-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:1dbcca4508bca7847fe2d64a05b237a3dcaec1f959aedb756d5b1c67b770c5ee"}, + {file = "matplotlib-3.7.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4cdf4ef46c2a1609a50411b66940b31778db1e4b73d4ecc2eaa40bd588979b13"}, + {file = "matplotlib-3.7.5-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:167200ccfefd1674b60e957186dfd9baf58b324562ad1a28e5d0a6b3bea77905"}, + {file = "matplotlib-3.7.5-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:53e64522934df6e1818b25fd48cf3b645b11740d78e6ef765fbb5fa5ce080d02"}, + {file = "matplotlib-3.7.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3e3bc79b2d7d615067bd010caff9243ead1fc95cf735c16e4b2583173f717eb"}, + {file = "matplotlib-3.7.5-cp38-cp38-win32.whl", hash = "sha256:6b641b48c6819726ed47c55835cdd330e53747d4efff574109fd79b2d8a13748"}, + {file = "matplotlib-3.7.5-cp38-cp38-win_amd64.whl", hash = "sha256:f0b60993ed3488b4532ec6b697059897891927cbfc2b8d458a891b60ec03d9d7"}, + {file = "matplotlib-3.7.5-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:090964d0afaff9c90e4d8de7836757e72ecfb252fb02884016d809239f715651"}, + {file = "matplotlib-3.7.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:9fc6fcfbc55cd719bc0bfa60bde248eb68cf43876d4c22864603bdd23962ba25"}, + {file = "matplotlib-3.7.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7cc3078b019bb863752b8b60e8b269423000f1603cb2299608231996bd9d54"}, + {file = "matplotlib-3.7.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e4e9a868e8163abaaa8259842d85f949a919e1ead17644fb77a60427c90473c"}, + {file = "matplotlib-3.7.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa7ebc995a7d747dacf0a717d0eb3aa0f0c6a0e9ea88b0194d3a3cd241a1500f"}, + {file = "matplotlib-3.7.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3785bfd83b05fc0e0c2ae4c4a90034fe693ef96c679634756c50fe6efcc09856"}, + {file = "matplotlib-3.7.5-cp39-cp39-win32.whl", hash = "sha256:29b058738c104d0ca8806395f1c9089dfe4d4f0f78ea765c6c704469f3fffc81"}, + {file = "matplotlib-3.7.5-cp39-cp39-win_amd64.whl", hash = "sha256:fd4028d570fa4b31b7b165d4a685942ae9cdc669f33741e388c01857d9723eab"}, + {file = "matplotlib-3.7.5-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2a9a3f4d6a7f88a62a6a18c7e6a84aedcaf4faf0708b4ca46d87b19f1b526f88"}, + {file = "matplotlib-3.7.5-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9b3fd853d4a7f008a938df909b96db0b454225f935d3917520305b90680579c"}, + {file = "matplotlib-3.7.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0ad550da9f160737d7890217c5eeed4337d07e83ca1b2ca6535078f354e7675"}, + {file = "matplotlib-3.7.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:20da7924a08306a861b3f2d1da0d1aa9a6678e480cf8eacffe18b565af2813e7"}, + {file = "matplotlib-3.7.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b45c9798ea6bb920cb77eb7306409756a7fab9db9b463e462618e0559aecb30e"}, + {file = "matplotlib-3.7.5-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a99866267da1e561c7776fe12bf4442174b79aac1a47bd7e627c7e4d077ebd83"}, + {file = "matplotlib-3.7.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b6aa62adb6c268fc87d80f963aca39c64615c31830b02697743c95590ce3fbb"}, + {file = "matplotlib-3.7.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e530ab6a0afd082d2e9c17eb1eb064a63c5b09bb607b2b74fa41adbe3e162286"}, + {file = "matplotlib-3.7.5.tar.gz", hash = "sha256:1e5c971558ebc811aa07f54c7b7c677d78aa518ef4c390e14673a09e0860184a"}, +] [package.dependencies] contourpy = ">=1.0.1" @@ -83,28 +364,107 @@ cycler = ">=0.10" fonttools = ">=4.22.0" importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} kiwisolver = ">=1.0.1" -numpy = ">=1.20" +numpy = ">=1.20,<2" packaging = ">=20.0" pillow = ">=6.2.0" pyparsing = ">=2.3.1" python-dateutil = ">=2.7" -setuptools_scm = ">=7" [[package]] name = "numpy" -version = "1.24.2" +version = "1.24.4" description = "Fundamental package for array computing in Python" category = "main" optional = false python-versions = ">=3.8" +files = [ + {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"}, + {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"}, + {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"}, + {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"}, + {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"}, + {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"}, + {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"}, + {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"}, + {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"}, + {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"}, + {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, +] + +[[package]] +name = "numpy" +version = "1.26.4" +description = "Fundamental package for array computing in Python" +category = "main" +optional = false +python-versions = ">=3.9" +files = [ + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, +] [[package]] name = "packaging" -version = "23.0" +version = "24.1" description = "Core utilities for Python packages" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] [[package]] name = "pandas" @@ -113,6 +473,35 @@ description = "Powerful data structures for data analysis, time series, and stat category = "main" optional = false python-versions = ">=3.8" +files = [ + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23"}, + {file = "pandas-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6"}, + {file = "pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14e45300521902689a81f3f41386dc86f19b8ba8dd5ac5a3c7010ef8d2932813"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9842b6f4b8479e41968eced654487258ed81df7d1c9b7b870ceea24ed9459b31"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26d9c71772c7afb9d5046e6e9cf42d83dd147b5cf5bcb9d97252077118543792"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fbcb19d6fceb9e946b3e23258757c7b225ba450990d9ed63ccceeb8cae609f7"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:565fa34a5434d38e9d250af3c12ff931abaf88050551d9fbcdfafca50d62babf"}, + {file = "pandas-1.5.3-cp38-cp38-win32.whl", hash = "sha256:87bd9c03da1ac870a6d2c8902a0e1fd4267ca00f13bc494c9e5a9020920e1d51"}, + {file = "pandas-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:41179ce559943d83a9b4bbacb736b04c928b095b5f25dd2b7389eda08f46f373"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c74a62747864ed568f5a82a49a23a8d7fe171d0c69038b38cedf0976831296fa"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c4c00e0b0597c8e4f59e8d461f797e5d70b4d025880516a8261b2817c47759ee"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a50d9a4336a9621cab7b8eb3fb11adb82de58f9b91d84c2cd526576b881a0c5a"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd05f7783b3274aa206a1af06f0ceed3f9b412cf665b7247eacd83be41cf7bf0"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5"}, + {file = "pandas-1.5.3-cp39-cp39-win32.whl", hash = "sha256:7cec0bee9f294e5de5bbfc14d0573f65526071029d036b753ee6507d2a21480a"}, + {file = "pandas-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfd681c5dc216037e0b0a2c821f5ed99ba9f03ebcf119c7dac0e9a7b960b9ec9"}, + {file = "pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1"}, +] [package.dependencies] numpy = [ @@ -128,73 +517,207 @@ test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] [[package]] name = "pillow" -version = "9.4.0" +version = "10.4.0" description = "Python Imaging Library (Fork)" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e"}, + {file = "pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b"}, + {file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e"}, + {file = "pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46"}, + {file = "pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984"}, + {file = "pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141"}, + {file = "pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c"}, + {file = "pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe"}, + {file = "pillow-10.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d"}, + {file = "pillow-10.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696"}, + {file = "pillow-10.4.0-cp311-cp311-win32.whl", hash = "sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496"}, + {file = "pillow-10.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91"}, + {file = "pillow-10.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94"}, + {file = "pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef"}, + {file = "pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b"}, + {file = "pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9"}, + {file = "pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42"}, + {file = "pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a"}, + {file = "pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3"}, + {file = "pillow-10.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0"}, + {file = "pillow-10.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a"}, + {file = "pillow-10.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309"}, + {file = "pillow-10.4.0-cp313-cp313-win32.whl", hash = "sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060"}, + {file = "pillow-10.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea"}, + {file = "pillow-10.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736"}, + {file = "pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b"}, + {file = "pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84"}, + {file = "pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0"}, + {file = "pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e"}, + {file = "pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d"}, + {file = "pillow-10.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b"}, + {file = "pillow-10.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1"}, + {file = "pillow-10.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df"}, + {file = "pillow-10.4.0-cp39-cp39-win32.whl", hash = "sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef"}, + {file = "pillow-10.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5"}, + {file = "pillow-10.4.0-cp39-cp39-win_arm64.whl", hash = "sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885"}, + {file = "pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27"}, + {file = "pillow-10.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3"}, + {file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"}, +] [package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +typing = ["typing-extensions"] +xmp = ["defusedxml"] [[package]] name = "pyparsing" -version = "3.0.9" +version = "3.1.4" description = "pyparsing module - Classes and methods to define and execute parsing grammars" category = "main" optional = false python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.1.4-py3-none-any.whl", hash = "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c"}, + {file = "pyparsing-3.1.4.tar.gz", hash = "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032"}, +] [package.extras] -diagrams = ["railroad-diagrams", "jinja2"] +diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pyqt5" -version = "5.15.9" +version = "5.15.11" description = "Python bindings for the Qt cross platform application toolkit" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "PyQt5-5.15.11-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c8b03dd9380bb13c804f0bdb0f4956067f281785b5e12303d529f0462f9afdc2"}, + {file = "PyQt5-5.15.11-cp38-abi3-macosx_11_0_x86_64.whl", hash = "sha256:6cd75628f6e732b1ffcfe709ab833a0716c0445d7aec8046a48d5843352becb6"}, + {file = "PyQt5-5.15.11-cp38-abi3-manylinux_2_17_x86_64.whl", hash = "sha256:cd672a6738d1ae33ef7d9efa8e6cb0a1525ecf53ec86da80a9e1b6ec38c8d0f1"}, + {file = "PyQt5-5.15.11-cp38-abi3-win32.whl", hash = "sha256:76be0322ceda5deecd1708a8d628e698089a1cea80d1a49d242a6d579a40babd"}, + {file = "PyQt5-5.15.11-cp38-abi3-win_amd64.whl", hash = "sha256:bdde598a3bb95022131a5c9ea62e0a96bd6fb28932cc1619fd7ba211531b7517"}, + {file = "PyQt5-5.15.11.tar.gz", hash = "sha256:fda45743ebb4a27b4b1a51c6d8ef455c4c1b5d610c90d2934c7802b5c1557c52"}, +] [package.dependencies] -PyQt5-Qt5 = ">=5.15.2" -PyQt5-sip = ">=12.11,<13" +PyQt5-Qt5 = ">=5.15.2,<5.16.0" +PyQt5-sip = ">=12.15,<13" [[package]] name = "pyqt5-qt5" -version = "5.15.2" +version = "5.15.15" description = "The subset of a Qt installation needed by PyQt5." category = "main" optional = false python-versions = "*" +files = [ + {file = "PyQt5_Qt5-5.15.15-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:eb74072935958a830887115b1de1ff26341fc2d5881b28129de39612b10a260e"}, + {file = "PyQt5_Qt5-5.15.15-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f8b174725fbe29c1a22f8acce5798933a65c8a083f1d9833ff212479ec2b3c14"}, + {file = "PyQt5_Qt5-5.15.15-py3-none-manylinux2014_x86_64.whl", hash = "sha256:611505d04ffb06a5e5bcf98f5ff0e4e15ba7785565ccbe7bd3b2e40642ea3bdd"}, +] [[package]] name = "pyqt5-sip" -version = "12.11.1" +version = "12.15.0" description = "The sip module support for PyQt5" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "PyQt5_sip-12.15.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:749f7a3ffd6e3d2d5db65ed92c95cbd14490631595c61f0c0672c9238bfb17de"}, + {file = "PyQt5_sip-12.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b4adc529fa4ec05728e14ea55194d907cc51f18d6f2ac5cc9f6eb52ac038aa0f"}, + {file = "PyQt5_sip-12.15.0-cp310-cp310-win32.whl", hash = "sha256:83d247cdc43ef224410b14c97413067ea26356dfa39e9ed0fe702a31e25710b0"}, + {file = "PyQt5_sip-12.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:13f0c6a78e781255863e3e160304648efaf62276b7102741af637b63a6e96930"}, + {file = "PyQt5_sip-12.15.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:855563d4d3b59ce7438bbf2dd32fed2707787defa40f3efe94f204a19ef92b25"}, + {file = "PyQt5_sip-12.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0b718a362f4392430903bbb2a4b9bbff9841a16a52f0cfdd5b5bbd9d11457980"}, + {file = "PyQt5_sip-12.15.0-cp311-cp311-win32.whl", hash = "sha256:2575f428de584a12009fd29d00c89df16ed101a3b38beba818dfdcbc4a10709c"}, + {file = "PyQt5_sip-12.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c85be433fbafcb3d417581c0e1b67c8198d23858166e4f938e971c2262c13cdb"}, + {file = "PyQt5_sip-12.15.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:852b75cf208825602480e95ab63314108f872d0da251e9ad3deaaff5a183a6f5"}, + {file = "PyQt5_sip-12.15.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0cd21c3215e3c47fdd5fa7a2dc3dd1e07a7230b0626e905a7217925068c788b9"}, + {file = "PyQt5_sip-12.15.0-cp312-cp312-win32.whl", hash = "sha256:b58eeedc9b2a3037b136bf96915196c391a33be470ed1c0723d7163ef0b727a2"}, + {file = "PyQt5_sip-12.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:24a1d4937332bf0a38dd95bb2ce4d89723df449f6e912b52ef0e107e11fefac1"}, + {file = "PyQt5_sip-12.15.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:91b9538458a3a23e033c213bc879ce64f3d0a33d5a49cbd03e1e584efe307a35"}, + {file = "PyQt5_sip-12.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0c1c727ede7fdc464a1fe2e46109ba836509b2d7187a46fdeae443148ce51d1c"}, + {file = "PyQt5_sip-12.15.0-cp38-cp38-win32.whl", hash = "sha256:dd241de9c569c07bbba62bff1049996e5b52478164f61f430073a87bf6d26d33"}, + {file = "PyQt5_sip-12.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:f600ae6f03e4bff91153c0dc7ebe52f90bd2b6afda58fd580e6990b3b951adc0"}, + {file = "PyQt5_sip-12.15.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c0c543d604116af26694a8a5ba90f510551ff9124d503ae5ee14bb73a61363a3"}, + {file = "PyQt5_sip-12.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:97f2d6e8d9b7b3d3e795d576d7f56e6257f524221f6383b33ded7287763e9f06"}, + {file = "PyQt5_sip-12.15.0-cp39-cp39-win32.whl", hash = "sha256:ed5221c6241981bd98d39504823efb9cbe36841bf8917288f8fe8fc1d5569a41"}, + {file = "PyQt5_sip-12.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:7f88c85702dce80ac2e1a162054f688ed394811d6dd03a5574b3fa8111b0a6db"}, + {file = "PyQt5_sip-12.15.0.tar.gz", hash = "sha256:d23fdfcf363b5cedd9d39f8a9c5710e7d52804f5b08a58e91c638b36eafcb702"}, +] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] [package.dependencies] six = ">=1.5" [[package]] name = "pytz" -version = "2022.7.1" +version = "2024.2" description = "World timezone definitions, modern and historical" category = "main" optional = false python-versions = "*" +files = [ + {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, + {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, +] [[package]] name = "scipy" @@ -203,31 +726,37 @@ description = "Fundamental algorithms for scientific computing in Python" category = "main" optional = false python-versions = "<3.12,>=3.8" +files = [ + {file = "scipy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7354fd7527a4b0377ce55f286805b34e8c54b91be865bac273f527e1b839019"}, + {file = "scipy-1.10.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:4b3f429188c66603a1a5c549fb414e4d3bdc2a24792e061ffbd607d3d75fd84e"}, + {file = "scipy-1.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1553b5dcddd64ba9a0d95355e63fe6c3fc303a8fd77c7bc91e77d61363f7433f"}, + {file = "scipy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c0ff64b06b10e35215abce517252b375e580a6125fd5fdf6421b98efbefb2d2"}, + {file = "scipy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:fae8a7b898c42dffe3f7361c40d5952b6bf32d10c4569098d276b4c547905ee1"}, + {file = "scipy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f1564ea217e82c1bbe75ddf7285ba0709ecd503f048cb1236ae9995f64217bd"}, + {file = "scipy-1.10.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d925fa1c81b772882aa55bcc10bf88324dadb66ff85d548c71515f6689c6dac5"}, + {file = "scipy-1.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaea0a6be54462ec027de54fca511540980d1e9eea68b2d5c1dbfe084797be35"}, + {file = "scipy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15a35c4242ec5f292c3dd364a7c71a61be87a3d4ddcc693372813c0b73c9af1d"}, + {file = "scipy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:43b8e0bcb877faf0abfb613d51026cd5cc78918e9530e375727bf0625c82788f"}, + {file = "scipy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5678f88c68ea866ed9ebe3a989091088553ba12c6090244fdae3e467b1139c35"}, + {file = "scipy-1.10.1-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:39becb03541f9e58243f4197584286e339029e8908c46f7221abeea4b749fa88"}, + {file = "scipy-1.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bce5869c8d68cf383ce240e44c1d9ae7c06078a9396df68ce88a1230f93a30c1"}, + {file = "scipy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07c3457ce0b3ad5124f98a86533106b643dd811dd61b548e78cf4c8786652f6f"}, + {file = "scipy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:049a8bbf0ad95277ffba9b3b7d23e5369cc39e66406d60422c8cfef40ccc8415"}, + {file = "scipy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cd9f1027ff30d90618914a64ca9b1a77a431159df0e2a195d8a9e8a04c78abf9"}, + {file = "scipy-1.10.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:79c8e5a6c6ffaf3a2262ef1be1e108a035cf4f05c14df56057b64acc5bebffb6"}, + {file = "scipy-1.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51af417a000d2dbe1ec6c372dfe688e041a7084da4fdd350aeb139bd3fb55353"}, + {file = "scipy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b4735d6c28aad3cdcf52117e0e91d6b39acd4272f3f5cd9907c24ee931ad601"}, + {file = "scipy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ff7f37b1bf4417baca958d254e8e2875d0cc23aaadbe65b3d5b3077b0eb23ea"}, + {file = "scipy-1.10.1.tar.gz", hash = "sha256:2cf9dfb80a7b4589ba4c40ce7588986d6d5cebc5457cad2c2880f6bc2d42f3a5"}, +] [package.dependencies] numpy = ">=1.19.5,<1.27.0" [package.extras] -test = ["pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "asv", "mpmath", "gmpy2", "threadpoolctl", "scikit-umfpack", "pooch"] -doc = ["sphinx (!=4.1.0)", "pydata-sphinx-theme (==0.9.0)", "sphinx-design (>=0.2.0)", "matplotlib (>2)", "numpydoc"] -dev = ["mypy", "typing-extensions", "pycodestyle", "flake8", "rich-click", "click", "doit (>=0.36.0)", "pydevtool"] - -[[package]] -name = "setuptools-scm" -version = "7.1.0" -description = "the blessed package to manage your versions by scm tags" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -packaging = ">=20.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} -typing-extensions = "*" - -[package.extras] -test = ["pytest (>=6.2)", "virtualenv (>20)"] -toml = ["setuptools (>=42)"] +dev = ["click", "doit (>=0.36.0)", "flake8", "mypy", "pycodestyle", "pydevtool", "rich-click", "typing_extensions"] +doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-design (>=0.2.0)"] +test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] name = "six" @@ -236,63 +765,32 @@ description = "Python 2 and 3 compatibility utilities" category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -category = "main" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "typing-extensions" -version = "4.5.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" -optional = false -python-versions = ">=3.7" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] [[package]] name = "zipp" -version = "3.15.0" +version = "3.20.2" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, + {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, +] [package.extras] -docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "sphinx-lint", "jaraco.tidelift (>=1.4)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "jaraco.functools", "more-itertools", "big-o", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "pytest-flake8"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] [metadata] -lock-version = "1.1" +lock-version = "2.0" python-versions = "<3.12,>=3.8" content-hash = "d91f94789b834755329a2b187c53a3c0fe903c8a52ab11c39a26eeb7ac0d9478" - -[metadata.files] -contourpy = [] -cycler = [] -fonttools = [ - {file = "fonttools-4.39.2-py3-none-any.whl", hash = "sha256:85245aa2fd4cf502a643c9a9a2b5a393703e150a6eaacc3e0e84bb448053f061"}, - {file = "fonttools-4.39.2.zip", hash = "sha256:e2d9f10337c9e3b17f9bce17a60a16a885a7d23b59b7f45ce07ea643e5580439"}, -] -importlib-resources = [] -kiwisolver = [] -matplotlib = [] -numpy = [] -packaging = [] -pandas = [] -pillow = [] -pyparsing = [] -pyqt5 = [] -pyqt5-qt5 = [] -pyqt5-sip = [] -python-dateutil = [] -pytz = [] -scipy = [] -setuptools-scm = [] -six = [] -tomli = [] -typing-extensions = [] -zipp = [] From a658a5b2df2767af0f18f07c62b4c67f4c6188c8 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 22 Sep 2024 07:07:31 -0700 Subject: [PATCH 24/96] my initial attempts at building an async fifo for cdc and the appropriate test framework around that --- HDL/projects/async_fifo/Makefile | 21 ++++ HDL/projects/async_fifo/async_fifo.sv | 81 ++++++++++++++ HDL/projects/async_fifo/main.cpp | 127 +++++++++++++++++++++ HDL/projects/async_fifo/tb_async_fifo.sv | 137 +++++++++++++++++++++++ 4 files changed, 366 insertions(+) create mode 100644 HDL/projects/async_fifo/Makefile create mode 100644 HDL/projects/async_fifo/async_fifo.sv create mode 100644 HDL/projects/async_fifo/main.cpp create mode 100644 HDL/projects/async_fifo/tb_async_fifo.sv diff --git a/HDL/projects/async_fifo/Makefile b/HDL/projects/async_fifo/Makefile new file mode 100644 index 00000000..d3448c77 --- /dev/null +++ b/HDL/projects/async_fifo/Makefile @@ -0,0 +1,21 @@ +VERILATOR = verilator +TOP_MODULE = tb_async_fifo +VERILATED = obj_dir/V$(TOP_MODULE) + +SRC_FILES = async_fifo.sv tb_async_fifo.sv +CPP_FILES = main.cpp + +all: sim + +sim: $(VERILATED) + ./$(VERILATED) + +$(VERILATED): $(SRC_FILES) $(CPP_FILES) + $(VERILATOR) -Wall --cc $(SRC_FILES) --exe $(CPP_FILES) --top-module $(TOP_MODULE) --trace + make -C obj_dir -f V$(TOP_MODULE).mk V$(TOP_MODULE) + +clean: + rm -rf obj_dir + rm -f sim.vcd + +.PHONY: all sim clean diff --git a/HDL/projects/async_fifo/async_fifo.sv b/HDL/projects/async_fifo/async_fifo.sv new file mode 100644 index 00000000..2d9b4de9 --- /dev/null +++ b/HDL/projects/async_fifo/async_fifo.sv @@ -0,0 +1,81 @@ +module async_fifo_custom #( + parameter DATA_WIDTH = 16, + parameter ADDR_WIDTH = 4 // FIFO depth = 2^ADDR_WIDTH +)( + input wire wr_clk, + input wire wr_rst_n, + input wire [DATA_WIDTH-1:0] wr_data, + input wire wr_en, + output wire full, + + input wire rd_clk, + input wire rd_rst_n, + output wire [DATA_WIDTH-1:0] rd_data, + input wire rd_en, + output wire empty +); + // FIFO memory + reg [DATA_WIDTH-1:0] mem [0:(1< +#include + +int main(int argc, char **argv) +{ + Verilated::commandArgs(argc, argv); + + // Instantiate the top module + Vtb_async_fifo *top = new Vtb_async_fifo; + + // Initialize simulation inputs + top->wr_clk = 0; + top->rd_clk = 0; + top->wr_rst_n = 0; + top->rd_rst_n = 0; + top->wr_en = 0; + top->rd_en = 0; + + // Variables for simulation + vluint64_t main_time = 0; // Current simulation time + const vluint64_t sim_time = 100000; // Adjust as needed + + // Open VCD dump file + Verilated::traceEverOn(true); + VerilatedVcdC *tfp = new VerilatedVcdC; + top->trace(tfp, 99); // Trace 99 levels of hierarchy + tfp->open("sim.vcd"); + + // Reset sequence + while (main_time < 20) + { + top->wr_clk = !top->wr_clk; + top->rd_clk = !top->rd_clk; + top->eval(); + tfp->dump(main_time); + main_time++; + } + top->wr_rst_n = 1; + top->rd_rst_n = 1; + + bool prev_wr_clk = 0; + bool prev_rd_clk = 0; + + while (main_time < sim_time) + { + // Toggle clocks + if ((main_time % 5) == 0) + { + top->wr_clk = !top->wr_clk; + } + if ((main_time % 7) == 0) + { + top->rd_clk = !top->rd_clk; + } + + // Write process + if (top->wr_clk && !prev_wr_clk) + { // Rising edge of wr_clk + if (main_time > 20) + { // After reset + if (!top->full) + { + top->wr_en = 1; + top->wr_data = wr_data; + wr_data++; + write_count++; + } + else + { + top->wr_en = 0; + } + } + } + prev_wr_clk = top->wr_clk; + + // Read process + if (top->rd_clk && !prev_rd_clk) + { // Rising edge of rd_clk + if (main_time > 20) + { // After reset + if (!top->empty) + { + top->rd_en = 1; + } + else + { + top->rd_en = 0; + } + + // Data integrity check + if (top->rd_en && !top->empty) + { + if (top->rd_data != expected_data) + { + std::cout << "ERROR: Data Mismatch at time " << main_time + << ": Expected " << expected_data << ", Got " << top->rd_data << std::endl; + exit(1); + } + expected_data++; + read_count++; + } + } + } + prev_rd_clk = top->rd_clk; + + // Check for simulation end + if (write_count >= 50 && read_count >= 50) + { + std::cout << "Simulation completed successfully at time " << main_time << std::endl; + break; + } + + top->eval(); // Evaluate model + tfp->dump(main_time); // Dump signals to VCD file + + main_time++; + } + + // Cleanup + tfp->close(); + delete top; + return 0; +} diff --git a/HDL/projects/async_fifo/tb_async_fifo.sv b/HDL/projects/async_fifo/tb_async_fifo.sv new file mode 100644 index 00000000..54995768 --- /dev/null +++ b/HDL/projects/async_fifo/tb_async_fifo.sv @@ -0,0 +1,137 @@ +module tb_async_fifo; + + // Parameters + parameter DATA_WIDTH = 16; + parameter ADDR_WIDTH = 4; // FIFO depth = 2^ADDR_WIDTH + + // Signals + reg wr_clk; + reg wr_rst_n; + reg [DATA_WIDTH-1:0] wr_data; + reg wr_en; + wire full; + + reg rd_clk; + reg rd_rst_n; + wire [DATA_WIDTH-1:0] rd_data; + reg rd_en; + wire empty; + + integer write_count; + integer read_count; + reg [DATA_WIDTH-1:0] expected_data; + + // Instantiate the FIFO + async_fifo_custom #( + .DATA_WIDTH(DATA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH) + ) fifo_inst ( + .wr_clk (wr_clk), + .wr_rst_n (wr_rst_n), + .wr_data (wr_data), + .wr_en (wr_en), + .full (full), + .rd_clk (rd_clk), + .rd_rst_n (rd_rst_n), + .rd_data (rd_data), + .rd_en (rd_en), + .empty (empty) + ); + + // Clock generation + initial begin + wr_clk = 0; + forever #5 wr_clk = ~wr_clk; // 100 MHz clock + end + + initial begin + rd_clk = 0; + forever #7 rd_clk = ~rd_clk; // Approximately 71.4 MHz clock + end + + // Reset generation + initial begin + wr_rst_n = 0; + rd_rst_n = 0; + #20; + wr_rst_n = 1; + rd_rst_n = 1; + end + + // Write process + initial begin + wr_en = 0; + wr_data = 0; + write_count = 0; + @(posedge wr_rst_n); + @(posedge wr_clk); + + // Write data until a certain count + while (write_count < 50) begin + @(posedge wr_clk); + if (!full) begin + wr_en = 1; + wr_data = write_count; + write_count = write_count + 1; + end else begin + wr_en = 0; + end + end + wr_en = 0; + end + + // Read process + initial begin + rd_en = 0; + expected_data = 0; + read_count = 0; + @(posedge rd_rst_n); + @(posedge rd_clk); + + // Read data until all written data is read + while (read_count < 50) begin + @(posedge rd_clk); + if (!empty) begin + rd_en = 1; + end else begin + rd_en = 0; + end + end + rd_en = 0; + end + + // Data integrity check + always @(posedge rd_clk) begin + if (rd_en && !empty) begin + if (rd_data !== expected_data) begin + $display("ERROR: Data Mismatch at time %t: Expected %0d, Got %0d", $time, expected_data, rd_data); + $stop; + end else begin + expected_data = expected_data + 1; + read_count = read_count + 1; + end + end + end + + // Monitor full and empty flags + always @(posedge wr_clk) begin + if (full && wr_en) begin + $display("INFO: FIFO is full at time %t", $time); + end + end + + always @(posedge rd_clk) begin + if (empty && rd_en) begin + $display("INFO: FIFO is empty at time %t", $time); + end + end + + // Terminate simulation + initial begin + wait (write_count == 50 && read_count == 50); + #100; // Wait for any remaining activity + $display("Simulation completed successfully at time %t", $time); + $stop; + end + +endmodule From a9d104cdd41fae87d4a5db45e38d65773daafe69 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 22 Sep 2024 07:10:54 -0700 Subject: [PATCH 25/96] small syntax issues --- HDL/projects/async_fifo/Makefile | 2 +- HDL/projects/async_fifo/async_fifo.sv | 2 +- HDL/projects/async_fifo/tb_async_fifo.sv | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/HDL/projects/async_fifo/Makefile b/HDL/projects/async_fifo/Makefile index d3448c77..8652f7c2 100644 --- a/HDL/projects/async_fifo/Makefile +++ b/HDL/projects/async_fifo/Makefile @@ -11,7 +11,7 @@ sim: $(VERILATED) ./$(VERILATED) $(VERILATED): $(SRC_FILES) $(CPP_FILES) - $(VERILATOR) -Wall --cc $(SRC_FILES) --exe $(CPP_FILES) --top-module $(TOP_MODULE) --trace + $(VERILATOR) -Wall --cc $(SRC_FILES) --exe $(CPP_FILES) --top-module $(TOP_MODULE) --trace --timing make -C obj_dir -f V$(TOP_MODULE).mk V$(TOP_MODULE) clean: diff --git a/HDL/projects/async_fifo/async_fifo.sv b/HDL/projects/async_fifo/async_fifo.sv index 2d9b4de9..fdfb4fa9 100644 --- a/HDL/projects/async_fifo/async_fifo.sv +++ b/HDL/projects/async_fifo/async_fifo.sv @@ -1,4 +1,4 @@ -module async_fifo_custom #( +module async_fifo #( parameter DATA_WIDTH = 16, parameter ADDR_WIDTH = 4 // FIFO depth = 2^ADDR_WIDTH )( diff --git a/HDL/projects/async_fifo/tb_async_fifo.sv b/HDL/projects/async_fifo/tb_async_fifo.sv index 54995768..c62a9cef 100644 --- a/HDL/projects/async_fifo/tb_async_fifo.sv +++ b/HDL/projects/async_fifo/tb_async_fifo.sv @@ -22,7 +22,7 @@ module tb_async_fifo; reg [DATA_WIDTH-1:0] expected_data; // Instantiate the FIFO - async_fifo_custom #( + async_fifo #( .DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH) ) fifo_inst ( From a650013df301f7a2148152ec660057412ab954c6 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 22 Sep 2024 07:18:16 -0700 Subject: [PATCH 26/96] fixed the system verilog test bench. --- HDL/projects/async_fifo/tb_async_fifo.sv | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HDL/projects/async_fifo/tb_async_fifo.sv b/HDL/projects/async_fifo/tb_async_fifo.sv index c62a9cef..409a537b 100644 --- a/HDL/projects/async_fifo/tb_async_fifo.sv +++ b/HDL/projects/async_fifo/tb_async_fifo.sv @@ -71,7 +71,7 @@ module tb_async_fifo; @(posedge wr_clk); if (!full) begin wr_en = 1; - wr_data = write_count; + wr_data = write_count[DATA_WIDTH-1:0]; write_count = write_count + 1; end else begin wr_en = 0; @@ -107,8 +107,8 @@ module tb_async_fifo; $display("ERROR: Data Mismatch at time %t: Expected %0d, Got %0d", $time, expected_data, rd_data); $stop; end else begin - expected_data = expected_data + 1; - read_count = read_count + 1; + expected_data <= expected_data + 1; + read_count <= read_count + 1; end end end From b614452dff003db2ee6dd044bee7cb951494ce43 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 22 Sep 2024 07:28:34 -0700 Subject: [PATCH 27/96] adding some documentation --- HDL/projects/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 HDL/projects/README.md diff --git a/HDL/projects/README.md b/HDL/projects/README.md new file mode 100644 index 00000000..a33b9c48 --- /dev/null +++ b/HDL/projects/README.md @@ -0,0 +1,24 @@ +# HDL Projects + +This folder contains projects written in SystemVerilog and other Hardware Description Languages (HDL). Each project is organized with separate directories for simulations and testbenches. + +## Structure + +- `src/`: Source files for the HDL projects. +- `sim/`: Simulation files and scripts. +- `tb/`: Testbenches for verifying the HDL designs. + +## Getting Started + +1. Navigate to the project directory. +2. Run the simulation scripts located in the `sim/` directory. +3. Verify the design using the testbenches in the `tb/` directory. + +## Requirements + +- SystemVerilog or other HDL tools. +- Simulation software compatible with the HDL used. + +## Contributing + +Feel free to contribute by adding new projects, improving existing ones, or updating documentation. From e59b2ad95e51461fe35eb39d8d5e2d1acf4e65a3 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 22 Sep 2024 07:31:24 -0700 Subject: [PATCH 28/96] more documentation --- HDL/projects/async_fifo/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 HDL/projects/async_fifo/README.md diff --git a/HDL/projects/async_fifo/README.md b/HDL/projects/async_fifo/README.md new file mode 100644 index 00000000..e57f9da9 --- /dev/null +++ b/HDL/projects/async_fifo/README.md @@ -0,0 +1,10 @@ +# async_fifo + +This project is to build and understand asynchronous FIFOs for clock-domain crossing. + +At the same time this is also a testbed on how to leverage both verilator and Vivado techniques to generate simulations and reports on +clock-domain crossing issues. + +## Requirements + +This project requires verilator. \ No newline at end of file From cd21c0ca7f56279ddde6a1f8cb872cd7ccf8e9f5 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 22 Sep 2024 07:36:37 -0700 Subject: [PATCH 29/96] completed the verilator testbench first try --- HDL/projects/async_fifo/Makefile | 4 ++-- HDL/projects/async_fifo/main.cpp | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/HDL/projects/async_fifo/Makefile b/HDL/projects/async_fifo/Makefile index 8652f7c2..cbf10209 100644 --- a/HDL/projects/async_fifo/Makefile +++ b/HDL/projects/async_fifo/Makefile @@ -1,8 +1,8 @@ VERILATOR = verilator -TOP_MODULE = tb_async_fifo +TOP_MODULE = async_fifo VERILATED = obj_dir/V$(TOP_MODULE) -SRC_FILES = async_fifo.sv tb_async_fifo.sv +SRC_FILES = async_fifo.sv CPP_FILES = main.cpp all: sim diff --git a/HDL/projects/async_fifo/main.cpp b/HDL/projects/async_fifo/main.cpp index 0b7c7664..592235d5 100644 --- a/HDL/projects/async_fifo/main.cpp +++ b/HDL/projects/async_fifo/main.cpp @@ -1,5 +1,5 @@ // main.cpp -#include "Vtb_async_fifo.h" +#include "Vasync_fifo.h" #include "verilated.h" #include "verilated_vcd_c.h" #include @@ -10,7 +10,7 @@ int main(int argc, char **argv) Verilated::commandArgs(argc, argv); // Instantiate the top module - Vtb_async_fifo *top = new Vtb_async_fifo; + Vasync_fifo *top = new Vasync_fifo; // Initialize simulation inputs top->wr_clk = 0; @@ -42,6 +42,10 @@ int main(int argc, char **argv) top->wr_rst_n = 1; top->rd_rst_n = 1; + uint16_t write_count = 0; + uint16_t read_count = 0; + uint16_t expected_data = 0; + uint16_t wr_data = 0; bool prev_wr_clk = 0; bool prev_rd_clk = 0; From 042f1c340ec68b6d32fab27c0f47ab5f041de0b2 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 22 Sep 2024 07:41:09 -0700 Subject: [PATCH 30/96] tiny Makefile improvement to include gtkwave --- HDL/projects/async_fifo/Makefile | 1 + HDL/projects/async_fifo/README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/HDL/projects/async_fifo/Makefile b/HDL/projects/async_fifo/Makefile index cbf10209..9d0e7899 100644 --- a/HDL/projects/async_fifo/Makefile +++ b/HDL/projects/async_fifo/Makefile @@ -9,6 +9,7 @@ all: sim sim: $(VERILATED) ./$(VERILATED) + gtkwave sim.vcd $(VERILATED): $(SRC_FILES) $(CPP_FILES) $(VERILATOR) -Wall --cc $(SRC_FILES) --exe $(CPP_FILES) --top-module $(TOP_MODULE) --trace --timing diff --git a/HDL/projects/async_fifo/README.md b/HDL/projects/async_fifo/README.md index e57f9da9..0448cb49 100644 --- a/HDL/projects/async_fifo/README.md +++ b/HDL/projects/async_fifo/README.md @@ -7,4 +7,4 @@ clock-domain crossing issues. ## Requirements -This project requires verilator. \ No newline at end of file +This project requires verilator and gtkwave. \ No newline at end of file From 83d9c7f749c68d8ec5f772643f36aa6fc1996be1 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 22 Sep 2024 09:24:58 -0700 Subject: [PATCH 31/96] removed gtkwave from the Makefile increased the simulation time --- HDL/projects/async_fifo/Makefile | 1 - HDL/projects/async_fifo/main.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/HDL/projects/async_fifo/Makefile b/HDL/projects/async_fifo/Makefile index 9d0e7899..cbf10209 100644 --- a/HDL/projects/async_fifo/Makefile +++ b/HDL/projects/async_fifo/Makefile @@ -9,7 +9,6 @@ all: sim sim: $(VERILATED) ./$(VERILATED) - gtkwave sim.vcd $(VERILATED): $(SRC_FILES) $(CPP_FILES) $(VERILATOR) -Wall --cc $(SRC_FILES) --exe $(CPP_FILES) --top-module $(TOP_MODULE) --trace --timing diff --git a/HDL/projects/async_fifo/main.cpp b/HDL/projects/async_fifo/main.cpp index 592235d5..c0b40f8f 100644 --- a/HDL/projects/async_fifo/main.cpp +++ b/HDL/projects/async_fifo/main.cpp @@ -22,7 +22,7 @@ int main(int argc, char **argv) // Variables for simulation vluint64_t main_time = 0; // Current simulation time - const vluint64_t sim_time = 100000; // Adjust as needed + const vluint64_t sim_time = 4000000; // Adjust as needed // Open VCD dump file Verilated::traceEverOn(true); @@ -112,7 +112,7 @@ int main(int argc, char **argv) prev_rd_clk = top->rd_clk; // Check for simulation end - if (write_count >= 50 && read_count >= 50) + if (write_count >= 500 && read_count >= 500) { std::cout << "Simulation completed successfully at time " << main_time << std::endl; break; From 734415c03298f3e8866930c29d608f3867ed8e51 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 22 Sep 2024 09:27:19 -0700 Subject: [PATCH 32/96] updated reference to display tool --- HDL/projects/async_fifo/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HDL/projects/async_fifo/README.md b/HDL/projects/async_fifo/README.md index 0448cb49..71f154ab 100644 --- a/HDL/projects/async_fifo/README.md +++ b/HDL/projects/async_fifo/README.md @@ -7,4 +7,4 @@ clock-domain crossing issues. ## Requirements -This project requires verilator and gtkwave. \ No newline at end of file +This project requires verilator and a tool to display the simulations. There are either gtkwave or surfer project that I would recommend. \ No newline at end of file From 9f1d2429a8de6353928df0073985ed808ad891f2 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 22 Sep 2024 10:05:44 -0700 Subject: [PATCH 33/96] update my async fifo to use double flop gray code synchronizers for the counters --- HDL/projects/async_fifo/async_fifo.sv | 76 ++++++++++++++++++--------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/HDL/projects/async_fifo/async_fifo.sv b/HDL/projects/async_fifo/async_fifo.sv index fdfb4fa9..072fc512 100644 --- a/HDL/projects/async_fifo/async_fifo.sv +++ b/HDL/projects/async_fifo/async_fifo.sv @@ -14,68 +14,92 @@ module async_fifo #( input wire rd_en, output wire empty ); + + // Function to convert binary to Gray code + function [ADDR_WIDTH:0] binary_to_gray(input [ADDR_WIDTH:0] bin); + binary_to_gray = (bin >> 1) ^ bin; + endfunction + + + // Function to convert Gray code to binary + function [ADDR_WIDTH:0] gray_to_binary(input [ADDR_WIDTH:0] gray); + integer i; + begin + gray_to_binary[ADDR_WIDTH] = gray[ADDR_WIDTH]; + for (i = ADDR_WIDTH-1; i >= 0; i = i - 1) + gray_to_binary[i] = gray[i] ^ gray_to_binary[i+1]; + end + endfunction + // FIFO memory reg [DATA_WIDTH-1:0] mem [0:(1< Date: Sun, 22 Sep 2024 10:32:46 -0700 Subject: [PATCH 34/96] add almost_full and almost_empty flags for improved flow control --- HDL/projects/async_fifo/async_fifo.sv | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/HDL/projects/async_fifo/async_fifo.sv b/HDL/projects/async_fifo/async_fifo.sv index 072fc512..e5e02d19 100644 --- a/HDL/projects/async_fifo/async_fifo.sv +++ b/HDL/projects/async_fifo/async_fifo.sv @@ -1,18 +1,22 @@ module async_fifo #( parameter DATA_WIDTH = 16, - parameter ADDR_WIDTH = 4 // FIFO depth = 2^ADDR_WIDTH + parameter ADDR_WIDTH = 4, // FIFO depth = 2^ADDR_WIDTH + parameter ALMOST_FULL_THRESHOLD = 2, // Adjust as needed + parameter ALMOST_EMPTY_THRESHOLD = 2 // Adjust as needed )( input wire wr_clk, input wire wr_rst_n, input wire [DATA_WIDTH-1:0] wr_data, input wire wr_en, output wire full, + output wire almost_full, input wire rd_clk, input wire rd_rst_n, output wire [DATA_WIDTH-1:0] rd_data, input wire rd_en, - output wire empty + output wire empty, + output wire almost_empty ); // Function to convert binary to Gray code @@ -102,4 +106,17 @@ module async_fifo #( assign empty = (rd_ptr_bin == wr_ptr_bin_rd_clk); + // ALMOST FULL calculation is done in write clock domain + wire [ADDR_WIDTH:0] fifo_count_wr_clk; + assign fifo_count_wr_clk = wr_ptr_bin - rd_ptr_bin_wr_clk; + + // since the ptrs wrap circularily we need to be very careful with the subtractions. Best to have a test + assign almost_full = (fifo_count_wr_clk >= ((1 << ADDR_WIDTH) - ALMOST_FULL_THRESHOLD)); + + // ALMOST EMPTY calculation is done in read clock domain + wire [ADDR_WIDTH:0] fifo_count_rd_clk; + assign fifo_count_rd_clk = wr_ptr_bin_rd_clk - rd_ptr_bin; + + assign almost_empty = (fifo_count_rd_clk <= ALMOST_EMPTY_THRESHOLD); + endmodule From 5a2fd85f1f3fd1e8b00df1d93c4cca350238a744 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Tue, 12 Nov 2024 17:36:21 -0800 Subject: [PATCH 35/96] adding a new core for SPI device control --- HDL/Makefile | 2 + .../axi_bidirectional_spi.v | 431 ++++++++++++++++++ .../bidirectional_spi.sv | 28 ++ .../axi_bidrectional_spi_v1_0/core_config.tcl | 17 + 4 files changed, 478 insertions(+) create mode 100644 HDL/cores/axi_bidrectional_spi_v1_0/axi_bidirectional_spi.v create mode 100644 HDL/cores/axi_bidrectional_spi_v1_0/bidirectional_spi.sv create mode 100644 HDL/cores/axi_bidrectional_spi_v1_0/core_config.tcl diff --git a/HDL/Makefile b/HDL/Makefile index db8d86c7..d236ef61 100644 --- a/HDL/Makefile +++ b/HDL/Makefile @@ -36,6 +36,8 @@ DTREE_URL = https://github.com/Xilinx/device-tree-xlnx/ .ONESHELL: all: setup tmp/%.bin +.ONESHELL: +xsa: setup tmp/%.xsa .ONESHELL: xpr: setup tmp/%.xpr diff --git a/HDL/cores/axi_bidrectional_spi_v1_0/axi_bidirectional_spi.v b/HDL/cores/axi_bidrectional_spi_v1_0/axi_bidirectional_spi.v new file mode 100644 index 00000000..8b2225d6 --- /dev/null +++ b/HDL/cores/axi_bidrectional_spi_v1_0/axi_bidirectional_spi.v @@ -0,0 +1,431 @@ + +`timescale 1 ns / 1 ps + +// This core is for driving a sinlge lane SPI device with a bidirectional data line +// In the first version of this core, there are only 4 registers +// 0x00 32 bit register for the data to be sent +// 0x04 32 bit register for the R/W mask +// 0x08 32 bit register for the data bit-length in the bottom 8 bits and the status of the SPI interface in the top 24bits +// 0x12 32 bit register for the data read +module axi_bidirectional_spi # +( + parameter integer C_S_AXI_DATA_WIDTH = 32, + parameter integer C_S_AXI_ADDR_WIDTH = 2 +) +( + // Control Signals for the SPI interface + inout wire spi_sdio, + output wire spi_sclk, + output wire spi_cs_n, + + // Do not modify the ports beyond this line + + // Global Clock Signal + input wire S_AXI_ACLK, + // Global Reset Signal. This Signal is Active LOW + input wire S_AXI_ARESETN, + // Write address (issued by master, acceped by Slave) + input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR, + // Write channel Protection type. This signal indicates the + // privilege and security level of the transaction, and whether + // the transaction is a data access or an instruction access. + input wire [2 : 0] S_AXI_AWPROT, + // Write address valid. This signal indicates that the master signaling + // valid write address and control information. + input wire S_AXI_AWVALID, + // Write address ready. This signal indicates that the slave is ready + // to accept an address and associated control signals. + output wire S_AXI_AWREADY, + // Write data (issued by master, acceped by Slave) + input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA, + // Write strobes. This signal indicates which byte lanes hold + // valid data. There is one write strobe bit for each eight + // bits of the write data bus. + input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB, + // Write valid. This signal indicates that valid write + // data and strobes are available. + input wire S_AXI_WVALID, + // Write ready. This signal indicates that the slave + // can accept the write data. + output wire S_AXI_WREADY, + // Write response. This signal indicates the status + // of the write transaction. + output wire [1 : 0] S_AXI_BRESP, + // Write response valid. This signal indicates that the channel + // is signaling a valid write response. + output wire S_AXI_BVALID, + // Response ready. This signal indicates that the master + // can accept a write response. + input wire S_AXI_BREADY, + // Read address (issued by master, acceped by Slave) + input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR, + // Protection type. This signal indicates the privilege + // and security level of the transaction, and whether the + // transaction is a data access or an instruction access. + input wire [2 : 0] S_AXI_ARPROT, + // Read address valid. This signal indicates that the channel + // is signaling valid read address and control information. + input wire S_AXI_ARVALID, + // Read address ready. This signal indicates that the slave is + // ready to accept an address and associated control signals. + output wire S_AXI_ARREADY, + // Read data (issued by slave) + output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA, + // Read response. This signal indicates the status of the + // read transfer. + output wire [1 : 0] S_AXI_RRESP, + // Read valid. This signal indicates that the channel is + // signaling the required read data. + output wire S_AXI_RVALID, + // Read ready. This signal indicates that the master can + // accept the read data and response information. + input wire S_AXI_RREADY +); + + // + // AXI4LITE signals + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr; + reg axi_awready; + reg axi_wready; + reg [1 : 0] axi_bresp; + reg axi_bvalid; + reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr; + reg axi_arready; + reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata; + reg [1 : 0] axi_rresp; + reg axi_rvalid; + + // Example-specific design signals + // local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH + // ADDR_LSB is used for addressing 32/64 bit registers/memories + // ADDR_LSB = 2 for 32 bits (n downto 2) + // ADDR_LSB = 3 for 64 bits (n downto 3) + localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1; + localparam integer OPT_MEM_ADDR_BITS = 3; + //---------------------------------------------- + //-- Signals for user logic register space example + //------------------------------------------------ + //-- Number of Slave Registers 4 + reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0; + reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg1; + reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg2; + reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg3; + + + wire slv_reg_rden; + wire slv_reg_wren; + reg [C_S_AXI_DATA_WIDTH-1:0] reg_data_out; + integer byte_index; + + // I/O Connections assignments + + assign S_AXI_AWREADY = axi_awready; + assign S_AXI_WREADY = axi_wready; + assign S_AXI_BRESP = axi_bresp; + assign S_AXI_BVALID = axi_bvalid; + assign S_AXI_ARREADY = axi_arready; + assign S_AXI_RDATA = axi_rdata; + assign S_AXI_RRESP = axi_rresp; + assign S_AXI_RVALID = axi_rvalid; + // Implement axi_awready generation + // axi_awready is asserted for one S_AXI_ACLK clock cycle when both + // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_awready is + // de-asserted when reset is low. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_awready <= 1'b0; + end + else + begin + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID) + begin + // slave is ready to accept write address when + // there is a valid write address and write data + // on the write address and data bus. This design + // expects no outstanding transactions. + axi_awready <= 1'b1; + end + else + begin + axi_awready <= 1'b0; + end + end + end + + // Implement axi_awaddr latching + // This process is used to latch the address when both + // S_AXI_AWVALID and S_AXI_WVALID are valid. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_awaddr <= 0; + end + else + begin + if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID) + begin + // Write Address latching + axi_awaddr <= S_AXI_AWADDR; + end + end + end + + // Implement axi_wready generation + // axi_wready is asserted for one S_AXI_ACLK clock cycle when both + // S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is + // de-asserted when reset is low. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_wready <= 1'b0; + end + else + begin + if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID) + begin + // slave is ready to accept write data when + // there is a valid write address and write data + // on the write address and data bus. This design + // expects no outstanding transactions. + axi_wready <= 1'b1; + end + else + begin + axi_wready <= 1'b0; + end + end + end + + // Implement memory mapped register select and write logic generation + // The write data is accepted and written to memory mapped registers when + // axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to + // select byte enables of slave registers while writing. + // These registers are cleared when reset (active low) is applied. + // Slave register write enable is asserted when valid address and data are available + // and the slave is ready to accept the write address and write data. + assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID; + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + slv_reg0 <= 8'h00; + //slv_reg1 <= 8'h10; + //slv_reg2 <= 8'h20; + //slv_reg3 <= 8'h30; + //slv_reg4 <= 8'h40; + //slv_reg5 <= 8'h50; + //slv_reg6 <= 8'h60; + //slv_reg7 <= 8'h70; + //slv_reg8 <= 8'h80; + //slv_reg9 <= 8'h90; + //slv_reg10 <= 8'h77; + end + else begin + if (slv_reg_wren) + begin + case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) + 4'h0: + for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) + if ( S_AXI_WSTRB[byte_index] == 1 ) begin + // Respective byte enables are asserted as per write strobes + // Slave register 0 + slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; + end + 4'h1: + for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) + if ( S_AXI_WSTRB[byte_index] == 1 ) begin + // Respective byte enables are asserted as per write strobes + // Slave register 1 + slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; + end + 4'h2: + for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) + if ( S_AXI_WSTRB[byte_index] == 1 ) begin + // Respective byte enables are asserted as per write strobes + // Slave register 2 + slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; + end + 4'h3: + for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) + if ( S_AXI_WSTRB[byte_index] == 1 ) begin + // Respective byte enables are asserted as per write strobes + // Slave register 3 + slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; + end + default : begin + //slv_reg0 <= slv_reg0; + //slv_reg1 <= slv_reg1; + //slv_reg2 <= slv_reg2; + //slv_reg3 <= slv_reg3; + end + endcase + end + end + end + + // Implement write response logic generation + // The write response and response valid signals are asserted by the slave + // when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted. + // This marks the acceptance of address and indicates the status of + // write transaction. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_bvalid <= 0; + axi_bresp <= 2'b0; + end + else + begin + if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID) + begin + // indicates a valid write response is available + axi_bvalid <= 1'b1; + axi_bresp <= 2'b0; // 'OKAY' response + end // work error responses in future + else + begin + if (S_AXI_BREADY && axi_bvalid) + //check if bready is asserted while bvalid is high) + //(there is a possibility that bready is always asserted high) + begin + axi_bvalid <= 1'b0; + end + end + end + end + + // Implement axi_arready generation + // axi_arready is asserted for one S_AXI_ACLK clock cycle when + // S_AXI_ARVALID is asserted. axi_awready is + // de-asserted when reset (active low) is asserted. + // The read address is also latched when S_AXI_ARVALID is + // asserted. axi_araddr is reset to zero on reset assertion. + + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_arready <= 1'b0; + axi_araddr <= 32'b0; + end + else + begin + if (~axi_arready && S_AXI_ARVALID) + begin + // indicates that the slave has acceped the valid read address + axi_arready <= 1'b1; + // Read address latching + axi_araddr <= S_AXI_ARADDR; + end + else + begin + axi_arready <= 1'b0; + end + end + end + + // Implement axi_arvalid generation + // axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both + // S_AXI_ARVALID and axi_arready are asserted. The slave registers + // data are available on the axi_rdata bus at this instance. The + // assertion of axi_rvalid marks the validity of read data on the + // bus and axi_rresp indicates the status of read transaction.axi_rvalid + // is deasserted on reset (active low). axi_rresp and axi_rdata are + // cleared to zero on reset (active low). + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_rvalid <= 0; + axi_rresp <= 0; + end + else + begin + if (axi_arready && S_AXI_ARVALID && ~axi_rvalid) + begin + // Valid read data is available at the read data bus + axi_rvalid <= 1'b1; + axi_rresp <= 2'b0; // 'OKAY' response + end + else if (axi_rvalid && S_AXI_RREADY) + begin + // Read data is accepted by the master + axi_rvalid <= 1'b0; + end + end + end + + // Implement memory mapped register select and read logic generation + // Slave register read enable is asserted when valid address is available + // and the slave is ready to accept the read address. + assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid; + always @(*) + begin + // Address decoding for reading registers + case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] ) + 4'h0 : reg_data_out <= slv_reg0; + 4'h1 : reg_data_out <= slv_reg1; + 4'h2 : reg_data_out <= slv_reg2; + 4'h3 : reg_data_out <= slv_reg3; + 4'h4 : reg_data_out <= slv_reg4; + 4'h5 : reg_data_out <= slv_reg5; + + default : reg_data_out <= 0; + endcase + end + + // Output register or memory read data + always @( posedge S_AXI_ACLK ) + begin + if ( S_AXI_ARESETN == 1'b0 ) + begin + axi_rdata <= 0; + end + else + begin + // When there is a valid read address (S_AXI_ARVALID) with + // acceptance of read address by the slave (axi_arready), + // output the read dada + if (slv_reg_rden) + begin + axi_rdata <= reg_data_out; // register read data + end + end + end + + // Add user logic here + reg spi_dir; // Direction control for the SPI interface (1 for write, 0 for read) + reg [31:0] shift_out; // SPI Data to be shifted out + reg [31:0] shift_in; // SPI Data to be shifted in + assign spi_sdio = spi_dir ? shift_out[31] : 1'bz; + + + // State Machine to Control the SPI Interface + always @(posedge S_AXI_ACLK or negedge S_AXI_ARESETN) begin + if (~S_AXI_ARESETN) begin + spi_sclk <= 0; // keep the spi clock low + spi_cs_n <= 1; // deassert the chip select line + spi_dir <= 1; // start in write mode + shift_out <= 0; // clear the shift out register + shift_in <= 0; // clear the shift in register + end else begin + case (slv_reg2[7:0]) + 8'h00: begin + spi_sclk <= 0; + spi_cs_n <= 1; + spi_dir <= 1; + shift_out <= 0; + end + 8'h01: begin + spi_sclk <= +endmodule diff --git a/HDL/cores/axi_bidrectional_spi_v1_0/bidirectional_spi.sv b/HDL/cores/axi_bidrectional_spi_v1_0/bidirectional_spi.sv new file mode 100644 index 00000000..d3e17e03 --- /dev/null +++ b/HDL/cores/axi_bidrectional_spi_v1_0/bidirectional_spi.sv @@ -0,0 +1,28 @@ +module bidirectional_spi ( + input wire [7:0] transaction_length; + input wire [31:0] transaction_data; + input wire [31:0] transaction_rw_mask; + output reg [31:0] transaction_read_data; + + input wire reset_n; + input wire spi_clk; + + inout wire spi_sdio; + output reg spi_sclk; + output reg spi_cs_n; +); + + reg spi_dir; // Direction control for the SPI interface (1 for write, 0 for read) + reg [31:0] shift_out; // SPI Data to be shifted out + reg [31:0] shift_in; // SPI Data to be shifted in + assign spi_sdio = spi_dir ? shift_out[31] : 1'bz; + + + // State Machine to Control the SPI Interface + always @(posedge spi_clk or negedge reset_n) begin + if (~reset_n) begin + spi_dir <= 1'b1; + shift_out <= 32'b0; + shift_in <= 32'b0; + spi + end \ No newline at end of file diff --git a/HDL/cores/axi_bidrectional_spi_v1_0/core_config.tcl b/HDL/cores/axi_bidrectional_spi_v1_0/core_config.tcl new file mode 100644 index 00000000..00c5f5c5 --- /dev/null +++ b/HDL/cores/axi_bidrectional_spi_v1_0/core_config.tcl @@ -0,0 +1,17 @@ +set display_name {AXI-4 Lite Bi-directional SPI Master} + +set core [ipx::current_core] + +set_property DISPLAY_NAME $display_name $core +set_property DESCRIPTION $display_name $core + +core_parameter C_S_AXI_DATA_WIDTH {AXI DATA WIDTH} {Width of the AXI data bus.} +core_parameter C_S_AXI_ADDR_WIDTH {AXI ADDR WIDTH} {Width of the AXI address bus.} + +set bus [ipx::get_bus_interfaces -of_objects $core S_AXI] +set_property NAME S_AXI $bus +set_property INTERFACE_MODE slave $bus + +set bus [ipx::get_bus_interfaces S_AXI_ACLK] +set parameter [ipx::get_bus_parameters -of_objects $bus ASSOCIATED_BUSIF] +set_property VALUE S_AXI $parameter From fc5dbff2048ea70be0e1ed657d45a97ed49196e9 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 13 Nov 2024 06:07:37 -0800 Subject: [PATCH 36/96] add the quadrature clock divider change the spi core to accept quadrature clock and spi mode control bits --- .../bidirectional_spi.sv | 6 ++- .../quadrature_clock_divider.sv | 49 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 HDL/cores/axi_bidrectional_spi_v1_0/quadrature_clock_divider.sv diff --git a/HDL/cores/axi_bidrectional_spi_v1_0/bidirectional_spi.sv b/HDL/cores/axi_bidrectional_spi_v1_0/bidirectional_spi.sv index d3e17e03..7b648991 100644 --- a/HDL/cores/axi_bidrectional_spi_v1_0/bidirectional_spi.sv +++ b/HDL/cores/axi_bidrectional_spi_v1_0/bidirectional_spi.sv @@ -5,7 +5,11 @@ module bidirectional_spi ( output reg [31:0] transaction_read_data; input wire reset_n; - input wire spi_clk; + input wire spi_clk_0; // 0 degree clock + input wire spi_clk_90; // 90 degree clock + // SPI Mode control + input wire spi_cpol; // Clock polarity + input wire spi_cpha; // Clock phase inout wire spi_sdio; output reg spi_sclk; diff --git a/HDL/cores/axi_bidrectional_spi_v1_0/quadrature_clock_divider.sv b/HDL/cores/axi_bidrectional_spi_v1_0/quadrature_clock_divider.sv new file mode 100644 index 00000000..480e20f7 --- /dev/null +++ b/HDL/cores/axi_bidrectional_spi_v1_0/quadrature_clock_divider.sv @@ -0,0 +1,49 @@ +// this divider uses the counts per quarter cycle to ensure the division is always valid +// the application for this simple module is the generation of quadrature clocks that are +// divided from a fast input clock. +// Common applications are SPI buses for example. +module quadrature_clock_divider ( + input wire clk_in, // Fast input clock + input wire reset_n, // Reset signal + input wire [7:0] div_factor_4, // Division factor as multiplier to 4 + // or "counts per quarter cycle" + output reg sck_0, // 0-degree phase clock + output reg sck_90 // 90-degree phase-shifted clock +); + + reg [9:0] counter; // Counter for clock division + reg [8:0] half_cycle; // Half-cycle count for 50% duty cycle + reg [7:0] quarter_cycle; // Quarter-cycle count for 90-degree shift + + always @(posedge clk_in or negedge reset_n) begin + if (~reset_n) begin + counter <= 0; + sck_0 <= 0; + sck_90 <= 0; + end else begin + // Calculate half and quarter cycles based on the division factor + half_cycle <= div_factor << 1; // 50% duty cycle + quarter_cycle <= div_factor; // 90-degree phase shift + + // Counter logic to generate sck_0 and sck_90 + if (counter >= (div_factor << 2) - 1) begin + counter <= 0; // Reset counter at the end of the cycle + end else begin + counter <= counter + 1; + end + + // Generate sck_0 and sck_90 based on counter values + if (counter == 0) begin + sck_0 <= 1; + end else if (counter == half_cycle) begin + sck_0 <= 0; + end + + if (counter == quarter_cycle) begin + sck_90 <= 1; + end else if (counter == half_cycle + quarter_cycle) begin + sck_90 <= 0; + end + end + end +endmodule \ No newline at end of file From d2d21a5ce731b48b6b2a868e7e3ecf1f4dd969c2 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 13 Nov 2024 06:19:56 -0800 Subject: [PATCH 37/96] made the divider bit width parametrizable --- .../quadrature_clock_divider.sv | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/HDL/cores/axi_bidrectional_spi_v1_0/quadrature_clock_divider.sv b/HDL/cores/axi_bidrectional_spi_v1_0/quadrature_clock_divider.sv index 480e20f7..b0f312d1 100644 --- a/HDL/cores/axi_bidrectional_spi_v1_0/quadrature_clock_divider.sv +++ b/HDL/cores/axi_bidrectional_spi_v1_0/quadrature_clock_divider.sv @@ -1,19 +1,23 @@ // this divider uses the counts per quarter cycle to ensure the division is always valid // the application for this simple module is the generation of quadrature clocks that are -// divided from a fast input clock. +// divided from a fast input clock. +// The bit-width of the division factor is configurable for this module and refers to the +// number of bits in the quarter cycle count // Common applications are SPI buses for example. -module quadrature_clock_divider ( +module quadrature_clock_divider #( + parameter DIVIDER_WIDTH = 8 +)( input wire clk_in, // Fast input clock input wire reset_n, // Reset signal - input wire [7:0] div_factor_4, // Division factor as multiplier to 4 + input wire [DIVIDER_WIDTH-1:0] div_factor_4, // Division factor as multiplier to 4 // or "counts per quarter cycle" output reg sck_0, // 0-degree phase clock output reg sck_90 // 90-degree phase-shifted clock ); - reg [9:0] counter; // Counter for clock division - reg [8:0] half_cycle; // Half-cycle count for 50% duty cycle - reg [7:0] quarter_cycle; // Quarter-cycle count for 90-degree shift + reg [DIVIDER_WIDTH+1:0] counter; // Counter for clock division + reg [DIVIDER_WIDTH:0] half_cycle; // Half-cycle count for 50% duty cycle + reg [DIVIDER_WIDTH-1:0] quarter_cycle; // Quarter-cycle count for 90-degree shift always @(posedge clk_in or negedge reset_n) begin if (~reset_n) begin From 2773614f8839c73fd7eaf52c3de38f0987c1d1d7 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 20 Nov 2024 05:47:54 -0800 Subject: [PATCH 38/96] moving some files aorund --- .../bidirectional_spi.sv | 32 ------------- .../bidirectional_spi/bidirectional_spi.sv | 47 +++++++++++++++++++ .../quadrature_clock_divider.sv | 0 3 files changed, 47 insertions(+), 32 deletions(-) delete mode 100644 HDL/cores/axi_bidrectional_spi_v1_0/bidirectional_spi.sv create mode 100644 HDL/projects/bidirectional_spi/bidirectional_spi.sv rename HDL/{cores/axi_bidrectional_spi_v1_0 => projects/quadrature_clock_divider}/quadrature_clock_divider.sv (100%) diff --git a/HDL/cores/axi_bidrectional_spi_v1_0/bidirectional_spi.sv b/HDL/cores/axi_bidrectional_spi_v1_0/bidirectional_spi.sv deleted file mode 100644 index 7b648991..00000000 --- a/HDL/cores/axi_bidrectional_spi_v1_0/bidirectional_spi.sv +++ /dev/null @@ -1,32 +0,0 @@ -module bidirectional_spi ( - input wire [7:0] transaction_length; - input wire [31:0] transaction_data; - input wire [31:0] transaction_rw_mask; - output reg [31:0] transaction_read_data; - - input wire reset_n; - input wire spi_clk_0; // 0 degree clock - input wire spi_clk_90; // 90 degree clock - // SPI Mode control - input wire spi_cpol; // Clock polarity - input wire spi_cpha; // Clock phase - - inout wire spi_sdio; - output reg spi_sclk; - output reg spi_cs_n; -); - - reg spi_dir; // Direction control for the SPI interface (1 for write, 0 for read) - reg [31:0] shift_out; // SPI Data to be shifted out - reg [31:0] shift_in; // SPI Data to be shifted in - assign spi_sdio = spi_dir ? shift_out[31] : 1'bz; - - - // State Machine to Control the SPI Interface - always @(posedge spi_clk or negedge reset_n) begin - if (~reset_n) begin - spi_dir <= 1'b1; - shift_out <= 32'b0; - shift_in <= 32'b0; - spi - end \ No newline at end of file diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv new file mode 100644 index 00000000..d1dcb61b --- /dev/null +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -0,0 +1,47 @@ +// bidirectional_spi module +// This module implements a bidirectional SPI interface with the following features: +// - uses a mask to determine which bits are written or read +// - supports all four SPI modes (CPOL=0, CPHA=0; CPOL=0, CPHA=1; CPOL=1, CPHA=0; CPOL=1, CPHA=1) +// - supports configurable data width +// - supports input of an arbitary quadrature clock for SPI clocking +// - raise an error flag if invalid parameters are used +// Bidirectional SPI is an interface where the data can be written and read using a single wire. +// this is also known as half-duplex SPI. +// this core can be adapted to full-duplex SPI by adding a second data wire. +module bidirectional_spi #( + parameter DATA_WIDTH = 32, + parameter TRANSACTION_LEN_WIDTH = 8 +) +( + input wire [TRANSACTION_LEN_WIDTH-1:0] transaction_length; + input wire [DATA_WIDTH-1:0] transaction_data; + input wire [DATA_WIDTH-1:0] transaction_rw_mask; + output reg [DATA_WIDTH-1:0] transaction_read_data; + + input wire reset_n; + input wire fabric_clk; + input wire spi_clk_0; // 0 degree clock + input wire spi_clk_90; // 90 degree clock + // SPI Mode control + input wire spi_cpol; // Clock polarity + input wire spi_cpha; // Clock phase + + inout wire spi_sdio; + output reg spi_sclk; + output reg spi_cs_n; +); + + reg spi_dir; // Direction control for the SPI interface (1 for write, 0 for read) + reg [31:0] shift_out; // SPI Data to be shifted out + reg [31:0] shift_in; // SPI Data to be shifted in + assign spi_sdio = spi_dir ? shift_out[31] : 1'bz; + + + // State Machine to Control the SPI Interface + always @(posedge spi_clk or negedge reset_n) begin + if (~reset_n) begin + spi_dir <= 1'b1; + shift_out <= 32'b0; + shift_in <= 32'b0; + spi + end \ No newline at end of file diff --git a/HDL/cores/axi_bidrectional_spi_v1_0/quadrature_clock_divider.sv b/HDL/projects/quadrature_clock_divider/quadrature_clock_divider.sv similarity index 100% rename from HDL/cores/axi_bidrectional_spi_v1_0/quadrature_clock_divider.sv rename to HDL/projects/quadrature_clock_divider/quadrature_clock_divider.sv From abe6cbb4f0e047899c468bb84d324f005bd745c2 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 20 Nov 2024 06:01:08 -0800 Subject: [PATCH 39/96] added some more test framework --- HDL/projects/bidirectional_spi/Makefile | 21 ++++++ .../bidirectional_spi/bidirectional_spi.sv | 37 ++++++----- HDL/projects/bidirectional_spi/main.cpp | 66 +++++++++++++++++++ .../bidirectional_spi/tb_bidirectional_spi.sv | 0 4 files changed, 106 insertions(+), 18 deletions(-) create mode 100644 HDL/projects/bidirectional_spi/Makefile create mode 100644 HDL/projects/bidirectional_spi/main.cpp create mode 100644 HDL/projects/bidirectional_spi/tb_bidirectional_spi.sv diff --git a/HDL/projects/bidirectional_spi/Makefile b/HDL/projects/bidirectional_spi/Makefile new file mode 100644 index 00000000..424d88d7 --- /dev/null +++ b/HDL/projects/bidirectional_spi/Makefile @@ -0,0 +1,21 @@ +VERILATOR = verilator +TOP_MODULE = bidirectional_spi +VERILATED = obj_dir/V$(TOP_MODULE) + +SRC_FILES = bidirectional_spi.sv +CPP_FILES = main.cpp + +all: sim + +sim: $(VERILATED) + ./$(VERILATED) + +$(VERILATED): $(SRC_FILES) $(CPP_FILES) + $(VERILATOR) -Wall --cc $(SRC_FILES) --exe $(CPP_FILES) --top-module $(TOP_MODULE) --trace --timing + make -C obj_dir -f V$(TOP_MODULE).mk V$(TOP_MODULE) + +clean: + rm -rf obj_dir + rm -f sim.vcd + +.PHONY: all sim clean diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index d1dcb61b..2215e1db 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -11,24 +11,23 @@ module bidirectional_spi #( parameter DATA_WIDTH = 32, parameter TRANSACTION_LEN_WIDTH = 8 -) -( - input wire [TRANSACTION_LEN_WIDTH-1:0] transaction_length; - input wire [DATA_WIDTH-1:0] transaction_data; - input wire [DATA_WIDTH-1:0] transaction_rw_mask; - output reg [DATA_WIDTH-1:0] transaction_read_data; +)( + input wire [TRANSACTION_LEN_WIDTH-1:0] transaction_length, + input wire [DATA_WIDTH-1:0] transaction_data, + input wire [DATA_WIDTH-1:0] transaction_rw_mask, + output reg [DATA_WIDTH-1:0] transaction_read_data, - input wire reset_n; - input wire fabric_clk; - input wire spi_clk_0; // 0 degree clock - input wire spi_clk_90; // 90 degree clock + input wire reset_n, + input wire fabric_clk, + input wire spi_clk_0, // 0 degree clock + input wire spi_clk_90, // 90 degree clock // SPI Mode control - input wire spi_cpol; // Clock polarity - input wire spi_cpha; // Clock phase + input wire spi_cpol, // Clock polarity + input wire spi_cpha, // Clock phase - inout wire spi_sdio; - output reg spi_sclk; - output reg spi_cs_n; + inout wire spi_sdio, + output reg spi_sclk, + output reg spi_cs_n, ); reg spi_dir; // Direction control for the SPI interface (1 for write, 0 for read) @@ -36,12 +35,14 @@ module bidirectional_spi #( reg [31:0] shift_in; // SPI Data to be shifted in assign spi_sdio = spi_dir ? shift_out[31] : 1'bz; - // State Machine to Control the SPI Interface always @(posedge spi_clk or negedge reset_n) begin if (~reset_n) begin spi_dir <= 1'b1; shift_out <= 32'b0; shift_in <= 32'b0; - spi - end \ No newline at end of file + end + end + + endmodule + diff --git a/HDL/projects/bidirectional_spi/main.cpp b/HDL/projects/bidirectional_spi/main.cpp new file mode 100644 index 00000000..3a536d9d --- /dev/null +++ b/HDL/projects/bidirectional_spi/main.cpp @@ -0,0 +1,66 @@ +// main.cpp +#include "Vbidirectional_spi.h" +#include "verilated.h" +#include "verilated_vcd_c.h" +#include +#include + +int main(int argc, char **argv) +{ + Verilated::commandArgs(argc, argv); + + // Instantiate the top module + Vbidirectional_spi *top = new Vbidirectional_spi; + + // Initialize simulation inputs + top->transaction_length = 0; + top->transaction_data = 0; + top->transaction_rw_mask = 0; + top->transaction_read_data = 0; + top->reset_n = 0; + top->fabric_clk = 0; + top->spi_clk_0 = 0; + top->spi_clk_90 = 0; + top->spi_cpol = 0; + top->spi_cpha = 0; + top->spi_sdio = 0; + + // Variables for simulation + vluint64_t main_time = 0; // Current simulation time + const vluint64_t sim_time = 4000000; // Adjust as needed + + // Open VCD dump file + Verilated::traceEverOn(true); + VerilatedVcdC *tfp = new VerilatedVcdC; + top->trace(tfp, 99); // Trace 99 levels of hierarchy + tfp->open("sim.vcd"); + + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_time) + { + // Toggle clocks + if ((main_time % 5) == 0) + { + top->fabric_clk = !top->fabric_clk; + } + + top->eval(); // Evaluate model + tfp->dump(main_time); // Dump signals to VCD file + + main_time++; + } + + // Cleanup + tfp->close(); + delete top; + return 0; +} diff --git a/HDL/projects/bidirectional_spi/tb_bidirectional_spi.sv b/HDL/projects/bidirectional_spi/tb_bidirectional_spi.sv new file mode 100644 index 00000000..e69de29b From ab248b2e9f1ef4fb215bcaf72866483be74c8f7e Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 20 Nov 2024 06:01:29 -0800 Subject: [PATCH 40/96] remove unneeded testbench --- HDL/projects/bidirectional_spi/tb_bidirectional_spi.sv | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 HDL/projects/bidirectional_spi/tb_bidirectional_spi.sv diff --git a/HDL/projects/bidirectional_spi/tb_bidirectional_spi.sv b/HDL/projects/bidirectional_spi/tb_bidirectional_spi.sv deleted file mode 100644 index e69de29b..00000000 From 196a5e1215c05a16a85847e7e5780feb462b2834 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 20 Nov 2024 06:22:41 -0800 Subject: [PATCH 41/96] do some more structure for the spi core --- .../bidirectional_spi/bidirectional_spi.sv | 45 ++++++++++++++++--- .../spi_clock_generator.sv | 28 ++++++++++++ 2 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 HDL/projects/spi_clock_generator/spi_clock_generator.sv diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index 2215e1db..0a750601 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -27,22 +27,55 @@ module bidirectional_spi #( inout wire spi_sdio, output reg spi_sclk, - output reg spi_cs_n, + output reg spi_cs_n ); reg spi_dir; // Direction control for the SPI interface (1 for write, 0 for read) - reg [31:0] shift_out; // SPI Data to be shifted out - reg [31:0] shift_in; // SPI Data to be shifted in + reg [DATA_WIDTH-1:0] shift_out; // SPI Data to be shifted out + reg [DATA_WIDTH-1:0] shift_in; // SPI Data to be shifted in assign spi_sdio = spi_dir ? shift_out[31] : 1'bz; + wire spi_data_clk; - // State Machine to Control the SPI Interface - always @(posedge spi_clk or negedge reset_n) begin + // Reset logic for the core + always @(posedge fabric_clk or negedge reset_n) begin if (~reset_n) begin spi_dir <= 1'b1; shift_out <= 32'b0; - shift_in <= 32'b0; + shift_in <= 32'b0; + spi_sclk <= 1'b0; + spi_cs_n <= 1'b1; end end + // assign the SPI clocks based on the SPI mode + spi_clock_generator #( + .DATA_WIDTH(DATA_WIDTH) + ) spi_clock_gen ( + .clk_0(spi_clk_0), + .clk_90(spi_clk_90), + .cpol(spi_cpol), + .cpha(spi_cpha), + .spi_clk(spi_data_clk), + .shift_clk(spi_sclk) + ); + + // Instantiate the asynchronous FIFO for the transaction length + async_fifo #( + .DATA_WIDTH(TRANSACTION_LEN_WIDTH), + .ADDR_WIDTH(3) + ) fifo ( + .wr_clk(fabric_clk), + .wr_rst_n(reset_n), + .wr_data(transaction_length), + .wr_en(1'b1), + .rd_clk(spi_data_clk), + .rd_rst_n(reset_n), + .rd_data(transaction_length), + .rd_en(1'b1), + .empty(), + .almost_empty() + ); + + endmodule diff --git a/HDL/projects/spi_clock_generator/spi_clock_generator.sv b/HDL/projects/spi_clock_generator/spi_clock_generator.sv new file mode 100644 index 00000000..e84b6622 --- /dev/null +++ b/HDL/projects/spi_clock_generator/spi_clock_generator.sv @@ -0,0 +1,28 @@ +module spi_clock_generator ( + input wire clk_0, // External clock (0° phase) + input wire clk_90, // External clock (90° phase) + input wire cpol, // Clock Polarity + input wire cpha, // Clock Phase + output logic spi_clk, // Generated SPI clock + output logic shift_clk // Data shift clock +); + + // Generate spi_clk based on cpol + always_comb begin + if (cpol == 0) begin + spi_clk = clk_0; // SPI clock idle state low + end else begin + spi_clk = ~clk_0; // SPI clock idle state high + end + end + + // Generate shift_clk based on cpha + always_comb begin + if (cpha == 0) begin + shift_clk = clk_0; // Sample on first edge of spi_clk + end else begin + shift_clk = clk_90; // Sample on second edge of spi_clk + end + end + +endmodule \ No newline at end of file From 786b4652466e7b7beda8e14e03a578eec83293b2 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 20 Nov 2024 08:55:45 -0800 Subject: [PATCH 42/96] some more reformatting --- HDL/projects/bidirectional_spi/Makefile | 2 +- .../{main.cpp => bidirectional_spi_tb.cpp} | 0 HDL/projects/spi_clock_generator/Makefile | 21 ++++++ .../spi_clock_generator.sv | 4 +- .../spi_clock_generator_tb.cpp | 75 +++++++++++++++++++ 5 files changed, 99 insertions(+), 3 deletions(-) rename HDL/projects/bidirectional_spi/{main.cpp => bidirectional_spi_tb.cpp} (100%) create mode 100644 HDL/projects/spi_clock_generator/Makefile create mode 100644 HDL/projects/spi_clock_generator/spi_clock_generator_tb.cpp diff --git a/HDL/projects/bidirectional_spi/Makefile b/HDL/projects/bidirectional_spi/Makefile index 424d88d7..5a3e7057 100644 --- a/HDL/projects/bidirectional_spi/Makefile +++ b/HDL/projects/bidirectional_spi/Makefile @@ -3,7 +3,7 @@ TOP_MODULE = bidirectional_spi VERILATED = obj_dir/V$(TOP_MODULE) SRC_FILES = bidirectional_spi.sv -CPP_FILES = main.cpp +CPP_FILES = bidirectional_spi_tb.cpp all: sim diff --git a/HDL/projects/bidirectional_spi/main.cpp b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp similarity index 100% rename from HDL/projects/bidirectional_spi/main.cpp rename to HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp diff --git a/HDL/projects/spi_clock_generator/Makefile b/HDL/projects/spi_clock_generator/Makefile new file mode 100644 index 00000000..9b96c193 --- /dev/null +++ b/HDL/projects/spi_clock_generator/Makefile @@ -0,0 +1,21 @@ +VERILATOR = verilator +TOP_MODULE = spi_clock_generator +VERILATED = obj_dir/V$(TOP_MODULE) + +SRC_FILES = spi_clock_generator.sv +CPP_FILES = spi_clock_generator_tb.cpp + +all: sim + +sim: $(VERILATED) + ./$(VERILATED) + +$(VERILATED): $(SRC_FILES) $(CPP_FILES) + $(VERILATOR) -Wall --cc $(SRC_FILES) --exe $(CPP_FILES) --top-module $(TOP_MODULE) --trace --timing + make -C obj_dir -f V$(TOP_MODULE).mk V$(TOP_MODULE) + +clean: + rm -rf obj_dir + rm -f sim.vcd + +.PHONY: all sim clean diff --git a/HDL/projects/spi_clock_generator/spi_clock_generator.sv b/HDL/projects/spi_clock_generator/spi_clock_generator.sv index e84b6622..2e49e4b0 100644 --- a/HDL/projects/spi_clock_generator/spi_clock_generator.sv +++ b/HDL/projects/spi_clock_generator/spi_clock_generator.sv @@ -3,7 +3,7 @@ module spi_clock_generator ( input wire clk_90, // External clock (90° phase) input wire cpol, // Clock Polarity input wire cpha, // Clock Phase - output logic spi_clk, // Generated SPI clock + output reg spi_clk, // Generated SPI clock output logic shift_clk // Data shift clock ); @@ -25,4 +25,4 @@ module spi_clock_generator ( end end -endmodule \ No newline at end of file +endmodule diff --git a/HDL/projects/spi_clock_generator/spi_clock_generator_tb.cpp b/HDL/projects/spi_clock_generator/spi_clock_generator_tb.cpp new file mode 100644 index 00000000..b61ecd54 --- /dev/null +++ b/HDL/projects/spi_clock_generator/spi_clock_generator_tb.cpp @@ -0,0 +1,75 @@ +#include +#include +#include +#include "Vspi_clock_generator.h" // Include the generated Verilator header + +// Define clock signal generation helper +void toggle_clock(bool &clk) +{ + clk = !clk; +} + +int main(int argc, char **argv) +{ + Verilated::commandArgs(argc, argv); + Verilated::traceEverOn(true); + + // Instantiate the DUT (Device Under Test) + Vspi_clock_generator *dut = new Vspi_clock_generator; + + // Initialize trace file + VerilatedVcdC *vcd = new VerilatedVcdC; + dut->trace(vcd, 10); + vcd->open("spi_clock_generator.vcd"); + + // Simulation variables + bool clk_0 = 0; // Clock signal (0° phase) + bool clk_90 = 0; // Clock signal (90° phase) + int clk_0_count = 0; + + // Test CPOL and CPHA configurations + for (int cpol = 0; cpol <= 1; ++cpol) + { + for (int cpha = 0; cpha <= 1; ++cpha) + { + // Initialize DUT inputs + dut->cpol = cpol; + dut->cpha = cpha; + + // Run simulation for a few clock cycles + for (int i = 0; i < 20; ++i) + { + // Toggle clocks + if (clk_0_count % 2 == 0) + toggle_clock(clk_0); + if (clk_0_count % 4 == 0) + toggle_clock(clk_90); // 90° phase assumes clk_90 toggles half as often + + // Drive inputs + dut->clk_0 = clk_0; + dut->clk_90 = clk_90; + + // Evaluate the DUT + dut->eval(); + vcd->dump(clk_0_count); + // Print results + std::cout << "CPOL: " << cpol + << " CPHA: " << cpha + << " clk_0: " << clk_0 + << " clk_90: " << clk_90 + << " spi_clk: " << (dut->spi_clk ? "1" : "0") + << " shift_clk: " << (dut->shift_clk ? "1" : "0") + << std::endl; + + // Increment clock cycle count + clk_0_count++; + } + } + } + + // Cleanup + dut->final(); + vcd->close(); + delete dut; + return 0; +} \ No newline at end of file From 5da57a15a907fdc5599a68523582e824b65830f0 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 20 Nov 2024 10:50:39 -0800 Subject: [PATCH 43/96] fix the spi clock generation to match the 4 modes --- .../spi_clock_generator.sv | 25 +++++++++++-------- .../spi_clock_generator_tb.cpp | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/HDL/projects/spi_clock_generator/spi_clock_generator.sv b/HDL/projects/spi_clock_generator/spi_clock_generator.sv index 2e49e4b0..de636dd1 100644 --- a/HDL/projects/spi_clock_generator/spi_clock_generator.sv +++ b/HDL/projects/spi_clock_generator/spi_clock_generator.sv @@ -10,18 +10,21 @@ module spi_clock_generator ( // Generate spi_clk based on cpol always_comb begin if (cpol == 0) begin - spi_clk = clk_0; // SPI clock idle state low + if (cpha == 0) begin + spi_clk = clk_90; // SPI mode 0 + shift_clk = clk_0; + end else begin + spi_clk = clk_0; // SPI mode 1 + shift_clk = clk_90; + end end else begin - spi_clk = ~clk_0; // SPI clock idle state high - end - end - - // Generate shift_clk based on cpha - always_comb begin - if (cpha == 0) begin - shift_clk = clk_0; // Sample on first edge of spi_clk - end else begin - shift_clk = clk_90; // Sample on second edge of spi_clk + if (cpha == 0) begin + spi_clk = ~clk_90; // SPI mode 2 + shift_clk = clk_0; + end else begin + spi_clk = ~clk_0; // SPI mode 3 + shift_clk = clk_90; + end end end diff --git a/HDL/projects/spi_clock_generator/spi_clock_generator_tb.cpp b/HDL/projects/spi_clock_generator/spi_clock_generator_tb.cpp index b61ecd54..7cc4ad32 100644 --- a/HDL/projects/spi_clock_generator/spi_clock_generator_tb.cpp +++ b/HDL/projects/spi_clock_generator/spi_clock_generator_tb.cpp @@ -42,7 +42,7 @@ int main(int argc, char **argv) // Toggle clocks if (clk_0_count % 2 == 0) toggle_clock(clk_0); - if (clk_0_count % 4 == 0) + if (clk_0_count % 2 == 1) toggle_clock(clk_90); // 90° phase assumes clk_90 toggles half as often // Drive inputs From 0dd383cd07d6f81d83bf029838adb09b25008aaa Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 20 Nov 2024 10:54:35 -0800 Subject: [PATCH 44/96] cleanup --- HDL/projects/spi_clock_generator/spi_clock_generator.sv | 2 +- HDL/projects/spi_clock_generator/spi_clock_generator_tb.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/HDL/projects/spi_clock_generator/spi_clock_generator.sv b/HDL/projects/spi_clock_generator/spi_clock_generator.sv index de636dd1..39d3e2b7 100644 --- a/HDL/projects/spi_clock_generator/spi_clock_generator.sv +++ b/HDL/projects/spi_clock_generator/spi_clock_generator.sv @@ -3,7 +3,7 @@ module spi_clock_generator ( input wire clk_90, // External clock (90° phase) input wire cpol, // Clock Polarity input wire cpha, // Clock Phase - output reg spi_clk, // Generated SPI clock + output logic spi_clk, // Generated SPI clock output logic shift_clk // Data shift clock ); diff --git a/HDL/projects/spi_clock_generator/spi_clock_generator_tb.cpp b/HDL/projects/spi_clock_generator/spi_clock_generator_tb.cpp index 7cc4ad32..3043882b 100644 --- a/HDL/projects/spi_clock_generator/spi_clock_generator_tb.cpp +++ b/HDL/projects/spi_clock_generator/spi_clock_generator_tb.cpp @@ -28,6 +28,7 @@ int main(int argc, char **argv) int clk_0_count = 0; // Test CPOL and CPHA configurations + // The way of doing these tests is causing ugly glitches in the cpol=1 case for (int cpol = 0; cpol <= 1; ++cpol) { for (int cpha = 0; cpha <= 1; ++cpha) From a8fb0af7a360c0a9a481c7835eb30fdb235e956c Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 20 Nov 2024 18:17:14 -0800 Subject: [PATCH 45/96] intermediate state --- HDL/projects/bidirectional_spi/Makefile | 2 +- .../bidirectional_spi/bidirectional_spi.sv | 162 ++++++++++++++++-- 2 files changed, 144 insertions(+), 20 deletions(-) diff --git a/HDL/projects/bidirectional_spi/Makefile b/HDL/projects/bidirectional_spi/Makefile index 5a3e7057..54f2a17a 100644 --- a/HDL/projects/bidirectional_spi/Makefile +++ b/HDL/projects/bidirectional_spi/Makefile @@ -2,7 +2,7 @@ VERILATOR = verilator TOP_MODULE = bidirectional_spi VERILATED = obj_dir/V$(TOP_MODULE) -SRC_FILES = bidirectional_spi.sv +SRC_FILES = bidirectional_spi.sv ../async_fifo/async_fifo.sv ../spi_clock_generator/spi_clock_generator.sv ../reset_synchronizer/reset_synchronizer.sv CPP_FILES = bidirectional_spi_tb.cpp all: sim diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index 0a750601..2e00d11e 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -31,51 +31,175 @@ module bidirectional_spi #( ); reg spi_dir; // Direction control for the SPI interface (1 for write, 0 for read) - reg [DATA_WIDTH-1:0] shift_out; // SPI Data to be shifted out - reg [DATA_WIDTH-1:0] shift_in; // SPI Data to be shifted in - assign spi_sdio = spi_dir ? shift_out[31] : 1'bz; + reg shift_out; // SPI Data to be shifted out + + // Some of our data in the spi_clk domain + reg [TRANSACTION_LEN_WIDTH-1:0] bitcounter_sc; + reg [DATA_WIDTH-1:0] transaction_rw_mask_sc; + reg [DATA_WIDTH-1:0] transaction_data_sc; + + reg [TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:0] sc_data, fc_data; + + reg [DATA_WIDTH-1:0] transaction_read_data_sc; + + assign fc_data = {transaction_length, transaction_rw_mask, transaction_data}; + + assign spi_sdio = spi_dir ? shift_out : 1'bz; wire spi_data_clk; + wire spi_clk; + + reg to_spi_fifo_empty; // Reset logic for the core always @(posedge fabric_clk or negedge reset_n) begin if (~reset_n) begin - spi_dir <= 1'b1; - shift_out <= 32'b0; - shift_in <= 32'b0; - spi_sclk <= 1'b0; - spi_cs_n <= 1'b1; + end end + // Reset synchronizer + wire reset_n_sc; + reset_synchronizer reset_sync ( + .reset_n(reset_n), + .clk(spi_data_clk), + .sync_reset_n(reset_n_sc) + ); + // assign the SPI clocks based on the SPI mode - spi_clock_generator #( - .DATA_WIDTH(DATA_WIDTH) - ) spi_clock_gen ( + spi_clock_generator spi_clock_gen ( .clk_0(spi_clk_0), .clk_90(spi_clk_90), .cpol(spi_cpol), .cpha(spi_cpha), - .spi_clk(spi_data_clk), - .shift_clk(spi_sclk) + .spi_clk(spi_clk), + .shift_clk(spi_data_clk) ); // Instantiate the asynchronous FIFO for the transaction length async_fifo #( - .DATA_WIDTH(TRANSACTION_LEN_WIDTH), + .DATA_WIDTH(TRANSACTION_LEN_WIDTH+2*DATA_WIDTH), .ADDR_WIDTH(3) - ) fifo ( + ) to_spi_fifo ( .wr_clk(fabric_clk), .wr_rst_n(reset_n), - .wr_data(transaction_length), + .wr_data(fc_data), .wr_en(1'b1), .rd_clk(spi_data_clk), .rd_rst_n(reset_n), - .rd_data(transaction_length), + .rd_data(sc_data), + .rd_en(1'b1), + .empty(to_spi_fifo_empty), + /* verilator lint_off PINCONNECTEMPTY */ + .almost_empty(), + .full(), + .almost_full() + /* verilator lint_on PINCONNECTEMPTY */ + ); + + reg to_fabric_fifo_full, to_fabric_filo_wr_en; + + // Instantiate the asynchronous FIFO for the write data + async_fifo #( + .DATA_WIDTH(DATA_WIDTH), + .ADDR_WIDTH(3) + ) to_fabric_fifo ( + .wr_clk(spi_data_clk), + .wr_rst_n(reset_n), + .wr_data(transaction_read_data_sc), + .wr_en(to_fabric_filo_wr_en), + .rd_clk(fabric_clk), + .rd_rst_n(reset_n), + .rd_data(transaction_read_data), .rd_en(1'b1), - .empty(), - .almost_empty() + .full(to_fabric_fifo_full), + /* verilator lint_off PINCONNECTEMPTY */ + .empty(), + .almost_empty(), + .almost_full() + /* verilator lint_on PINCONNECTEMPTY */ ); + // SPI side reset logic + always @(posedge spi_data_clk or negedge reset_n_sc) begin + if (~reset_n_sc) begin + spi_dir <= 1'b1; + shift_out <= 1'b0; + spi_sclk <= 1'b0; + spi_cs_n <= 1'b1; + to_fabric_filo_wr_en <= 1'b0; + end + end + + // SPI state machine stuff + typedef enum logic [1:0] { + IDLE, + CS_ASSERT, + WRITE, + DONE + } state_t; + + state_t spi_state; + + // reset the state machine + always_ff @(posedge spi_data_clk or negedge reset_n_sc) begin + if (~reset_n_sc) begin + spi_state <= IDLE; + end + end + + // generate the spi clock output + always_ff @(posedge spi_clk) begin + if (reset_n_sc) begin + if (spi_state == WRITE) begin + spi_sclk <= spi_clk; + end else begin + spi_sclk <= 1'b0; + end + end + end + + always_ff @(posedge spi_data_clk) begin + if (reset_n_sc) begin + if (spi_state == IDLE) begin + to_fabric_filo_wr_en <= 1'b0; + if(~to_spi_fifo_empty) begin + spi_state <= CS_ASSERT; + // copy the data from the fifo + bitcounter_sc <= sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; + transaction_rw_mask_sc <= sc_data[DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH]; + transaction_data_sc <= sc_data[DATA_WIDTH-1:0]; + end else begin + spi_state <= IDLE; + end + end else if (spi_state == CS_ASSERT) begin + spi_state <= WRITE; + spi_cs_n <= 1'b0; + end else if (spi_state == WRITE) begin + if (bitcounter_sc == 0) begin + spi_state <= DONE; + spi_cs_n <= 1'b1; + spi_dir <= 1'b1; + end else begin + spi_state <= WRITE; + spi_dir <= transaction_rw_mask_sc[bitcounter_sc - 1]; + shift_out <= transaction_data_sc[bitcounter_sc - 1]; + bitcounter_sc <= bitcounter_sc - 1; + if (~transaction_rw_mask_sc[bitcounter_sc - 1]) begin + transaction_read_data_sc[bitcounter_sc -1] <= spi_sdio; + end else begin + transaction_read_data_sc[bitcounter_sc -1] <= 0; + end + end + end else if (spi_state == DONE) begin + if (~to_fabric_fifo_full) begin + spi_state <= IDLE; + to_fabric_filo_wr_en <= 1'b1; + end else begin + spi_state <= DONE; + end + end + end + end endmodule From 8ef7a0bc986286e9aae152cdb5f090dd157536c2 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 20 Nov 2024 23:15:14 -0800 Subject: [PATCH 46/96] add reset synchronizer core --- .../reset_synchronizer/reset_synchronizer.sv | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 HDL/projects/reset_synchronizer/reset_synchronizer.sv diff --git a/HDL/projects/reset_synchronizer/reset_synchronizer.sv b/HDL/projects/reset_synchronizer/reset_synchronizer.sv new file mode 100644 index 00000000..b87ce198 --- /dev/null +++ b/HDL/projects/reset_synchronizer/reset_synchronizer.sv @@ -0,0 +1,19 @@ +// A reset synchronizer synchronizes the deassertion of reset with respect to the clock domain. +// In other words, a reset synchronizer manipulates the asynchronous reset to have synchronous deassertion. + +module reset_synchronizer ( + input wire reset_n, + input wire clk, + output reg sync_reset_n +); + reg Q1; + always @ (posedge clk or negedge reset_n) begin + if(~reset_n) begin + Q1 <= 1'b0; + sync_reset_n <= 1'b0; + end else begin + Q1 <= 1'b1; + sync_reset_n <= Q1; + end + end +endmodule From 05c2d3fa419ca328e1ef0fe793e3b6a8db9fb206 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 20 Nov 2024 23:25:16 -0800 Subject: [PATCH 47/96] cleaned up code some more --- HDL/projects/bidirectional_spi/bidirectional_spi.sv | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index 2e00d11e..bc32099a 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -124,7 +124,6 @@ module bidirectional_spi #( if (~reset_n_sc) begin spi_dir <= 1'b1; shift_out <= 1'b0; - spi_sclk <= 1'b0; spi_cs_n <= 1'b1; to_fabric_filo_wr_en <= 1'b0; end @@ -148,17 +147,19 @@ module bidirectional_spi #( end // generate the spi clock output - always_ff @(posedge spi_clk) begin + always_ff @(posedge spi_clk or negedge reset_n_sc) begin if (reset_n_sc) begin if (spi_state == WRITE) begin spi_sclk <= spi_clk; end else begin spi_sclk <= 1'b0; end + end else begin + spi_sclk <= 1'b0; end end - always_ff @(posedge spi_data_clk) begin + always_ff @(posedge spi_data_clk or negedge reset_n_sc) begin if (reset_n_sc) begin if (spi_state == IDLE) begin to_fabric_filo_wr_en <= 1'b0; From 560018c527ef1e508e23937c7a220239a9b9f839 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Thu, 21 Nov 2024 06:38:34 -0800 Subject: [PATCH 48/96] add a second reset synchronizer into the spi clock domain verilator now compiles fine --- .../bidirectional_spi/bidirectional_spi.sv | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index bc32099a..d6caccc7 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -58,13 +58,19 @@ module bidirectional_spi #( end // Reset synchronizer - wire reset_n_sc; + wire reset_n_sc, reset_n_sc2; reset_synchronizer reset_sync ( .reset_n(reset_n), .clk(spi_data_clk), .sync_reset_n(reset_n_sc) ); + reset_synchronizer reset_sync2 ( + .reset_n(reset_n), + .clk(spi_clk), + .sync_reset_n(reset_n_sc2) + ); + // assign the SPI clocks based on the SPI mode spi_clock_generator spi_clock_gen ( .clk_0(spi_clk_0), @@ -75,7 +81,7 @@ module bidirectional_spi #( .shift_clk(spi_data_clk) ); - // Instantiate the asynchronous FIFO for the transaction length + // Instantiate the asynchronous FIFO for the data going to the SPI side async_fifo #( .DATA_WIDTH(TRANSACTION_LEN_WIDTH+2*DATA_WIDTH), .ADDR_WIDTH(3) @@ -98,7 +104,7 @@ module bidirectional_spi #( reg to_fabric_fifo_full, to_fabric_filo_wr_en; - // Instantiate the asynchronous FIFO for the write data + // Instantiate the asynchronous FIFO for the data coming from the SPI side async_fifo #( .DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(3) @@ -147,8 +153,8 @@ module bidirectional_spi #( end // generate the spi clock output - always_ff @(posedge spi_clk or negedge reset_n_sc) begin - if (reset_n_sc) begin + always_ff @(posedge spi_clk or negedge reset_n_sc2) begin + if (reset_n_sc2) begin if (spi_state == WRITE) begin spi_sclk <= spi_clk; end else begin From ccec38a098e434093c92f093fd7ab46469b1bc51 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Thu, 21 Nov 2024 06:43:34 -0800 Subject: [PATCH 49/96] add to_spi_fifo_rd_en handling logic --- .../bidirectional_spi/bidirectional_spi.sv | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index d6caccc7..be4a1838 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -81,6 +81,7 @@ module bidirectional_spi #( .shift_clk(spi_data_clk) ); + reg to_spi_fifo_rd_en; // Instantiate the asynchronous FIFO for the data going to the SPI side async_fifo #( .DATA_WIDTH(TRANSACTION_LEN_WIDTH+2*DATA_WIDTH), @@ -93,7 +94,7 @@ module bidirectional_spi #( .rd_clk(spi_data_clk), .rd_rst_n(reset_n), .rd_data(sc_data), - .rd_en(1'b1), + .rd_en(to_spi_fifo_rd_en), .empty(to_spi_fifo_empty), /* verilator lint_off PINCONNECTEMPTY */ .almost_empty(), @@ -132,6 +133,7 @@ module bidirectional_spi #( shift_out <= 1'b0; spi_cs_n <= 1'b1; to_fabric_filo_wr_en <= 1'b0; + to_spi_fifo_rd_en <= 1'b0; end end @@ -171,16 +173,18 @@ module bidirectional_spi #( to_fabric_filo_wr_en <= 1'b0; if(~to_spi_fifo_empty) begin spi_state <= CS_ASSERT; - // copy the data from the fifo - bitcounter_sc <= sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; - transaction_rw_mask_sc <= sc_data[DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH]; - transaction_data_sc <= sc_data[DATA_WIDTH-1:0]; + to_spi_fifo_rd_en <= 1'b1; // assert the read enable end else begin spi_state <= IDLE; end end else if (spi_state == CS_ASSERT) begin spi_state <= WRITE; spi_cs_n <= 1'b0; + to_spi_fifo_rd_en <= 1'b0; // deassert the read enable + // copy the data from the fifo + bitcounter_sc <= sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; + transaction_rw_mask_sc <= sc_data[DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH]; + transaction_data_sc <= sc_data[DATA_WIDTH-1:0]; end else if (spi_state == WRITE) begin if (bitcounter_sc == 0) begin spi_state <= DONE; From b821a0368d7846b6ae7f93b6b6c9d67eff4f368d Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Thu, 21 Nov 2024 06:51:51 -0800 Subject: [PATCH 50/96] add some code to not write to the to_fabric fifo if nothing was read in the SPI transaction. --- .../bidirectional_spi/bidirectional_spi.sv | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index be4a1838..c3fc5ae9 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -34,7 +34,9 @@ module bidirectional_spi #( reg shift_out; // SPI Data to be shifted out // Some of our data in the spi_clk domain - reg [TRANSACTION_LEN_WIDTH-1:0] bitcounter_sc; + reg [TRANSACTION_LEN_WIDTH-1:0] bitcounter_sc; + reg [TRANSACTION_LEN_WIDTH-1:0] read_bitcounter_sc; + reg [DATA_WIDTH-1:0] transaction_rw_mask_sc; reg [DATA_WIDTH-1:0] transaction_data_sc; @@ -134,6 +136,7 @@ module bidirectional_spi #( spi_cs_n <= 1'b1; to_fabric_filo_wr_en <= 1'b0; to_spi_fifo_rd_en <= 1'b0; + read_bitcounter_sc <= 0; end end @@ -185,6 +188,9 @@ module bidirectional_spi #( bitcounter_sc <= sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; transaction_rw_mask_sc <= sc_data[DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH]; transaction_data_sc <= sc_data[DATA_WIDTH-1:0]; + + read_bitcounter_sc <= 0; + transaction_read_data_sc <= 0; end else if (spi_state == WRITE) begin if (bitcounter_sc == 0) begin spi_state <= DONE; @@ -196,13 +202,18 @@ module bidirectional_spi #( shift_out <= transaction_data_sc[bitcounter_sc - 1]; bitcounter_sc <= bitcounter_sc - 1; if (~transaction_rw_mask_sc[bitcounter_sc - 1]) begin + read_bitcounter_sc <= read_bitcounter_sc + 1; transaction_read_data_sc[bitcounter_sc -1] <= spi_sdio; end else begin + // this is to fill in blank bits if the mask is not continuous transaction_read_data_sc[bitcounter_sc -1] <= 0; end end end else if (spi_state == DONE) begin - if (~to_fabric_fifo_full) begin + if (read_bitcounter_sc == 0) begin + spi_state <= IDLE; + to_fabric_filo_wr_en <= 1'b0; + end else if (~to_fabric_fifo_full) begin spi_state <= IDLE; to_fabric_filo_wr_en <= 1'b1; end else begin From 5710e1c192aa54b6f0eee18a5ec86adff4759436 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sat, 30 Nov 2024 14:29:47 -0800 Subject: [PATCH 51/96] fix the quadrature clock divider --- .../quadrature_clock_divider/Makefile | 21 +++++++ .../quadrature_clock_divider.sv | 13 +++-- .../quadrature_clock_divider_tb.cpp | 56 +++++++++++++++++++ 3 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 HDL/projects/quadrature_clock_divider/Makefile create mode 100644 HDL/projects/quadrature_clock_divider/quadrature_clock_divider_tb.cpp diff --git a/HDL/projects/quadrature_clock_divider/Makefile b/HDL/projects/quadrature_clock_divider/Makefile new file mode 100644 index 00000000..414a75a8 --- /dev/null +++ b/HDL/projects/quadrature_clock_divider/Makefile @@ -0,0 +1,21 @@ +VERILATOR = verilator +TOP_MODULE = quadrature_clock_divider +VERILATED = obj_dir/V$(TOP_MODULE) + +SRC_FILES = quadrature_clock_divider.sv +CPP_FILES = quadrature_clock_divider_tb.cpp + +all: sim + +sim: $(VERILATED) + ./$(VERILATED) + +$(VERILATED): $(SRC_FILES) $(CPP_FILES) + $(VERILATOR) -Wall --cc $(SRC_FILES) --exe $(CPP_FILES) --top-module $(TOP_MODULE) --trace --timing + make -C obj_dir -f V$(TOP_MODULE).mk V$(TOP_MODULE) + +clean: + rm -rf obj_dir + rm -f sim.vcd + +.PHONY: all sim clean diff --git a/HDL/projects/quadrature_clock_divider/quadrature_clock_divider.sv b/HDL/projects/quadrature_clock_divider/quadrature_clock_divider.sv index b0f312d1..74760244 100644 --- a/HDL/projects/quadrature_clock_divider/quadrature_clock_divider.sv +++ b/HDL/projects/quadrature_clock_divider/quadrature_clock_divider.sv @@ -16,8 +16,8 @@ module quadrature_clock_divider #( ); reg [DIVIDER_WIDTH+1:0] counter; // Counter for clock division - reg [DIVIDER_WIDTH:0] half_cycle; // Half-cycle count for 50% duty cycle - reg [DIVIDER_WIDTH-1:0] quarter_cycle; // Quarter-cycle count for 90-degree shift + reg [DIVIDER_WIDTH+1:0] half_cycle; // Half-cycle count for 50% duty cycle + reg [DIVIDER_WIDTH+1:0] quarter_cycle; // Quarter-cycle count for 90-degree shift always @(posedge clk_in or negedge reset_n) begin if (~reset_n) begin @@ -26,11 +26,11 @@ module quadrature_clock_divider #( sck_90 <= 0; end else begin // Calculate half and quarter cycles based on the division factor - half_cycle <= div_factor << 1; // 50% duty cycle - quarter_cycle <= div_factor; // 90-degree phase shift + half_cycle <= {1'b0, div_factor_4, 1'b0}; // 50% duty cycle + quarter_cycle <= {2'b00, div_factor_4}; // 90-degree phase shift // Counter logic to generate sck_0 and sck_90 - if (counter >= (div_factor << 2) - 1) begin + if (counter >= {div_factor_4, 2'b00} - 1) begin counter <= 0; // Reset counter at the end of the cycle end else begin counter <= counter + 1; @@ -50,4 +50,5 @@ module quadrature_clock_divider #( end end end -endmodule \ No newline at end of file +endmodule + diff --git a/HDL/projects/quadrature_clock_divider/quadrature_clock_divider_tb.cpp b/HDL/projects/quadrature_clock_divider/quadrature_clock_divider_tb.cpp new file mode 100644 index 00000000..bd1752a6 --- /dev/null +++ b/HDL/projects/quadrature_clock_divider/quadrature_clock_divider_tb.cpp @@ -0,0 +1,56 @@ +// main.cpp +#include "Vquadrature_clock_divider.h" +#include "verilated.h" +#include "verilated_vcd_c.h" +#include +#include + +int main(int argc, char **argv) +{ + Verilated::commandArgs(argc, argv); + + // Instantiate the top module + Vquadrature_clock_divider *top = new Vquadrature_clock_divider; + + // Initialize simulation inputs + top->reset_n = 0; + top->div_factor_4 = 1; + // Variables for simulation + vluint64_t main_time = 0; // Current simulation time + const vluint64_t sim_time = 4000000; // Adjust as needed + + // Open VCD dump file + Verilated::traceEverOn(true); + VerilatedVcdC *tfp = new VerilatedVcdC; + top->trace(tfp, 99); // Trace 99 levels of hierarchy + tfp->open("sim.vcd"); + + // Reset sequence + while (main_time < 20) + { + top->clk_in = !top->clk_in; + top->eval(); + tfp->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_time) + { + // Toggle clocks + if ((main_time % 5) == 0) + { + top->clk_in = !top->clk_in; + } + + top->eval(); // Evaluate model + tfp->dump(main_time); // Dump signals to VCD file + + main_time++; + } + + // Cleanup + tfp->close(); + delete top; + return 0; +} From c2db857e446d2ad8efe594dacb0ad4f1d2f219e2 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sat, 30 Nov 2024 16:38:25 -0800 Subject: [PATCH 52/96] OMG --- .../quadrature_clock_divider.sv | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/HDL/projects/quadrature_clock_divider/quadrature_clock_divider.sv b/HDL/projects/quadrature_clock_divider/quadrature_clock_divider.sv index 74760244..ec37ee96 100644 --- a/HDL/projects/quadrature_clock_divider/quadrature_clock_divider.sv +++ b/HDL/projects/quadrature_clock_divider/quadrature_clock_divider.sv @@ -18,12 +18,16 @@ module quadrature_clock_divider #( reg [DIVIDER_WIDTH+1:0] counter; // Counter for clock division reg [DIVIDER_WIDTH+1:0] half_cycle; // Half-cycle count for 50% duty cycle reg [DIVIDER_WIDTH+1:0] quarter_cycle; // Quarter-cycle count for 90-degree shift + reg [DIVIDER_WIDTH+1:0] zero; always @(posedge clk_in or negedge reset_n) begin if (~reset_n) begin counter <= 0; sck_0 <= 0; sck_90 <= 0; + zero <= 0; + half_cycle <= {1'b0, div_factor_4, 1'b0}; // 50% duty cycle + quarter_cycle <= {2'b00, div_factor_4}; // 90-degree phase shift end else begin // Calculate half and quarter cycles based on the division factor half_cycle <= {1'b0, div_factor_4, 1'b0}; // 50% duty cycle @@ -37,15 +41,15 @@ module quadrature_clock_divider #( end // Generate sck_0 and sck_90 based on counter values - if (counter == 0) begin + if (counter >= zero && counter < half_cycle) begin sck_0 <= 1; - end else if (counter == half_cycle) begin + end else begin sck_0 <= 0; end - if (counter == quarter_cycle) begin + if (counter >= quarter_cycle && counter < half_cycle + quarter_cycle) begin sck_90 <= 1; - end else if (counter == half_cycle + quarter_cycle) begin + end else begin sck_90 <= 0; end end From d49ca583af4c8ef55823742476313e2cb83bcf4d Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 1 Dec 2024 03:07:52 -0800 Subject: [PATCH 53/96] it is what it is --- HDL/projects/bidirectional_spi/Makefile | 2 +- .../bidirectional_spi/bidirectional_spi.sv | 58 ++++++++++++++----- .../bidirectional_spi_tb.cpp | 2 - 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/HDL/projects/bidirectional_spi/Makefile b/HDL/projects/bidirectional_spi/Makefile index 54f2a17a..33d27014 100644 --- a/HDL/projects/bidirectional_spi/Makefile +++ b/HDL/projects/bidirectional_spi/Makefile @@ -2,7 +2,7 @@ VERILATOR = verilator TOP_MODULE = bidirectional_spi VERILATED = obj_dir/V$(TOP_MODULE) -SRC_FILES = bidirectional_spi.sv ../async_fifo/async_fifo.sv ../spi_clock_generator/spi_clock_generator.sv ../reset_synchronizer/reset_synchronizer.sv +SRC_FILES = bidirectional_spi.sv ../async_fifo/async_fifo.sv ../spi_clock_generator/spi_clock_generator.sv ../reset_synchronizer/reset_synchronizer.sv ../quadrature_clock_divider/quadrature_clock_divider.sv CPP_FILES = bidirectional_spi_tb.cpp all: sim diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index c3fc5ae9..9c1bf735 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -19,8 +19,7 @@ module bidirectional_spi #( input wire reset_n, input wire fabric_clk, - input wire spi_clk_0, // 0 degree clock - input wire spi_clk_90, // 90 degree clock + // SPI Mode control input wire spi_cpol, // Clock polarity input wire spi_cpha, // Clock phase @@ -51,14 +50,47 @@ module bidirectional_spi #( wire spi_clk; reg to_spi_fifo_empty; + + // fabric side state machine states + typedef enum logic [1:0] { + F_IDLE, + F_WRITE, + F_DONE + } fstate_t; + + fstate_t fabric_state; - // Reset logic for the core + // Fabric side state machine always @(posedge fabric_clk or negedge reset_n) begin if (~reset_n) begin - + to_spi_fifo_wr_en <= 1'b0; + to_fabric_fifo_rd_en <= 1'b0; + fabric_state <= F_IDLE; + end else if (fabric_state == F_IDLE) begin + if (transaction_length > 0) begin + fabric_state <= F_WRITE; + to_spi_fifo_wr_en <= 1'b1; + end else begin + fabric_state <= F_IDLE; + end + end else if (fabric_state == F_WRITE) begin + fabric_state <= F_IDLE; + to_spi_fifo_wr_en <= 1'b0; end end + + wire spi_clk_0,spi_clk_90; + + // Generate the clocks + quadrature_clock_divider clock_div ( + .reset_n(reset_n), + .clk_in(fabric_clk), + .div_factor_4(2), + .sck_0(spi_clk_0), + .sck_90(spi_clk_90) + ); + // Reset synchronizer wire reset_n_sc, reset_n_sc2; reset_synchronizer reset_sync ( @@ -83,7 +115,7 @@ module bidirectional_spi #( .shift_clk(spi_data_clk) ); - reg to_spi_fifo_rd_en; + reg to_spi_fifo_rd_en, to_spi_fifo_wr_en; // Instantiate the asynchronous FIFO for the data going to the SPI side async_fifo #( .DATA_WIDTH(TRANSACTION_LEN_WIDTH+2*DATA_WIDTH), @@ -92,7 +124,7 @@ module bidirectional_spi #( .wr_clk(fabric_clk), .wr_rst_n(reset_n), .wr_data(fc_data), - .wr_en(1'b1), + .wr_en(to_spi_fifo_wr_en), .rd_clk(spi_data_clk), .rd_rst_n(reset_n), .rd_data(sc_data), @@ -105,7 +137,7 @@ module bidirectional_spi #( /* verilator lint_on PINCONNECTEMPTY */ ); - reg to_fabric_fifo_full, to_fabric_filo_wr_en; + reg to_fabric_fifo_full, to_fabric_fifo_wr_en, to_fabric_fifo_rd_en; // Instantiate the asynchronous FIFO for the data coming from the SPI side async_fifo #( @@ -115,11 +147,11 @@ module bidirectional_spi #( .wr_clk(spi_data_clk), .wr_rst_n(reset_n), .wr_data(transaction_read_data_sc), - .wr_en(to_fabric_filo_wr_en), + .wr_en(to_fabric_fifo_wr_en), .rd_clk(fabric_clk), .rd_rst_n(reset_n), .rd_data(transaction_read_data), - .rd_en(1'b1), + .rd_en(to_fabric_fifo_rd_en), .full(to_fabric_fifo_full), /* verilator lint_off PINCONNECTEMPTY */ .empty(), @@ -134,7 +166,7 @@ module bidirectional_spi #( spi_dir <= 1'b1; shift_out <= 1'b0; spi_cs_n <= 1'b1; - to_fabric_filo_wr_en <= 1'b0; + to_fabric_fifo_wr_en <= 1'b0; to_spi_fifo_rd_en <= 1'b0; read_bitcounter_sc <= 0; end @@ -173,7 +205,7 @@ module bidirectional_spi #( always_ff @(posedge spi_data_clk or negedge reset_n_sc) begin if (reset_n_sc) begin if (spi_state == IDLE) begin - to_fabric_filo_wr_en <= 1'b0; + to_fabric_fifo_wr_en <= 1'b0; if(~to_spi_fifo_empty) begin spi_state <= CS_ASSERT; to_spi_fifo_rd_en <= 1'b1; // assert the read enable @@ -212,10 +244,10 @@ module bidirectional_spi #( end else if (spi_state == DONE) begin if (read_bitcounter_sc == 0) begin spi_state <= IDLE; - to_fabric_filo_wr_en <= 1'b0; + to_fabric_fifo_wr_en <= 1'b0; end else if (~to_fabric_fifo_full) begin spi_state <= IDLE; - to_fabric_filo_wr_en <= 1'b1; + to_fabric_fifo_wr_en <= 1'b1; end else begin spi_state <= DONE; end diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp index 3a536d9d..27fa9201 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp +++ b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp @@ -19,8 +19,6 @@ int main(int argc, char **argv) top->transaction_read_data = 0; top->reset_n = 0; top->fabric_clk = 0; - top->spi_clk_0 = 0; - top->spi_clk_90 = 0; top->spi_cpol = 0; top->spi_cpha = 0; top->spi_sdio = 0; From b9588eda15c37fa23a0a609e7be537d33969b68e Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 1 Dec 2024 05:13:19 -0800 Subject: [PATCH 54/96] initial checkin --- .../bidirectional_spi/surfer_state.ron | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 HDL/projects/bidirectional_spi/surfer_state.ron diff --git a/HDL/projects/bidirectional_spi/surfer_state.ron b/HDL/projects/bidirectional_spi/surfer_state.ron new file mode 100644 index 00000000..5c8b6d74 --- /dev/null +++ b/HDL/projects/bidirectional_spi/surfer_state.ron @@ -0,0 +1,147 @@ +( + show_hierarchy: None, + show_menu: None, + show_ticks: None, + show_toolbar: None, + show_tooltip: None, + show_overview: None, + show_statusbar: None, + align_names_right: None, + show_variable_indices: None, + show_variable_direction: None, + show_empty_scopes: None, + show_parameters_in_scopes: None, + waves: Some(( + source: File("sim_reset_n_clock.vcd"), + format: Vcd, + active_scope: Some(WaveScope(( + strs: [ + "TOP", + "bidirectional_spi", + ], + ))), + displayed_items_order: [ + (2), + (1), + (3), + (4), + ], + displayed_items: { + (4): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_clk_90", + ), + color: Some("yellow"), + background_color: None, + display_name: "spi_clk_90", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (1): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + ], + ), + name: "fabric_clk", + ), + color: None, + background_color: None, + display_name: "fabric_clk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (2): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + ], + ), + name: "reset_n", + ), + color: None, + background_color: None, + display_name: "reset_n", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (3): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_clk_0", + ), + color: Some("yellow"), + background_color: None, + display_name: "spi_clk_0", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + }, + display_item_ref_counter: 4, + viewports: [ + ( + curr_left: (0.0), + curr_right: (1.0), + target_left: (0.0), + target_right: (1.0), + move_start_left: (0.0), + move_start_right: (1.0), + move_duration: None, + move_strategy: Instant, + ), + ], + cursor: None, + markers: {}, + focused_item: Some((3)), + focused_transaction: (None, None), + selected_items: [], + default_variable_name_type: Unique, + scroll_offset: 0.0, + display_variable_indices: true, + graphics: {}, + )), + drag_started: false, + drag_source_idx: None, + drag_target_idx: Some((1)), + previous_waves: None, + count: None, + blacklisted_translators: [], + show_about: false, + show_keys: false, + show_gestures: false, + show_quick_start: false, + show_license: false, + show_performance: false, + show_logs: false, + show_cursor_window: false, + wanted_timeunit: PicoSeconds, + time_string_format: None, + show_url_entry: false, + variable_name_filter_focused: false, + variable_name_filter_type: Fuzzy, + variable_name_filter_case_insensitive: true, + rename_target: None, + sidepanel_width: Some(300.0), + ui_zoom_factor: None, +) \ No newline at end of file From f976a695faa50ed85cddf69e7bdaacc4d6724324 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 1 Dec 2024 06:36:41 -0800 Subject: [PATCH 55/96] Updated Makefile to clean more vcd files Added another surfer state file --- HDL/projects/bidirectional_spi/Makefile | 5 + .../bidirectional_spi/bidirectional_spi.sv | 54 ++- .../bidirectional_spi_tb.cpp | 181 +++++++- .../bidirectional_spi/surfer_load_data.ron | 396 ++++++++++++++++++ 4 files changed, 604 insertions(+), 32 deletions(-) create mode 100644 HDL/projects/bidirectional_spi/surfer_load_data.ron diff --git a/HDL/projects/bidirectional_spi/Makefile b/HDL/projects/bidirectional_spi/Makefile index 33d27014..8ae185cb 100644 --- a/HDL/projects/bidirectional_spi/Makefile +++ b/HDL/projects/bidirectional_spi/Makefile @@ -17,5 +17,10 @@ $(VERILATED): $(SRC_FILES) $(CPP_FILES) clean: rm -rf obj_dir rm -f sim.vcd + rm -r sim_reset_n_clock.vcd + rm -r sim_load_value_mode0.vcd + rm -r sim_load_value_mode1.vcd + rm -r sim_load_value_mode2.vcd + rm -r sim_load_value_mode3.vcd .PHONY: all sim clean diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index 9c1bf735..eefd32b9 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -33,17 +33,17 @@ module bidirectional_spi #( reg shift_out; // SPI Data to be shifted out // Some of our data in the spi_clk domain - reg [TRANSACTION_LEN_WIDTH-1:0] bitcounter_sc; + reg [TRANSACTION_LEN_WIDTH-1:0] bitcounter_sc, r_transaction_length; reg [TRANSACTION_LEN_WIDTH-1:0] read_bitcounter_sc; - reg [DATA_WIDTH-1:0] transaction_rw_mask_sc; - reg [DATA_WIDTH-1:0] transaction_data_sc; + reg [DATA_WIDTH-1:0] transaction_rw_mask_sc, r_transaction_rw_mask; + reg [DATA_WIDTH-1:0] transaction_data_sc, r_transaction_data; reg [TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:0] sc_data, fc_data; reg [DATA_WIDTH-1:0] transaction_read_data_sc; - assign fc_data = {transaction_length, transaction_rw_mask, transaction_data}; + assign fc_data = {r_transaction_length, r_transaction_rw_mask, r_transaction_data}; assign spi_sdio = spi_dir ? shift_out : 1'bz; wire spi_data_clk; @@ -66,10 +66,16 @@ module bidirectional_spi #( to_spi_fifo_wr_en <= 1'b0; to_fabric_fifo_rd_en <= 1'b0; fabric_state <= F_IDLE; + r_transaction_length <= 0; + r_transaction_rw_mask <= 0; + r_transaction_data <= 0; end else if (fabric_state == F_IDLE) begin if (transaction_length > 0) begin fabric_state <= F_WRITE; to_spi_fifo_wr_en <= 1'b1; + r_transaction_length <= transaction_length; + r_transaction_rw_mask <= transaction_rw_mask; + r_transaction_data <= transaction_data; end else begin fabric_state <= F_IDLE; end @@ -92,18 +98,20 @@ module bidirectional_spi #( ); // Reset synchronizer - wire reset_n_sc, reset_n_sc2; + wire reset_n_sc; // reset_n_sc2; reset_synchronizer reset_sync ( .reset_n(reset_n), .clk(spi_data_clk), .sync_reset_n(reset_n_sc) ); + /* reset_synchronizer reset_sync2 ( .reset_n(reset_n), .clk(spi_clk), .sync_reset_n(reset_n_sc2) ); + */ // assign the SPI clocks based on the SPI mode spi_clock_generator spi_clock_gen ( @@ -173,8 +181,9 @@ module bidirectional_spi #( end // SPI state machine stuff - typedef enum logic [1:0] { - IDLE, + typedef enum logic [2:0] { + IDLE, + FIFO_READ, CS_ASSERT, WRITE, DONE @@ -186,35 +195,31 @@ module bidirectional_spi #( always_ff @(posedge spi_data_clk or negedge reset_n_sc) begin if (~reset_n_sc) begin spi_state <= IDLE; + spi_clk_en <= 1'b0; end end - // generate the spi clock output - always_ff @(posedge spi_clk or negedge reset_n_sc2) begin - if (reset_n_sc2) begin - if (spi_state == WRITE) begin - spi_sclk <= spi_clk; - end else begin - spi_sclk <= 1'b0; - end - end else begin - spi_sclk <= 1'b0; - end - end + // combinatorial logic to assign the SPI clock + assign spi_sclk = spi_clk_en ? spi_clk : 1'b0; + + reg spi_clk_en; always_ff @(posedge spi_data_clk or negedge reset_n_sc) begin if (reset_n_sc) begin if (spi_state == IDLE) begin to_fabric_fifo_wr_en <= 1'b0; + shift_out <= 1'b0; + spi_clk_en <= 1'b0; if(~to_spi_fifo_empty) begin - spi_state <= CS_ASSERT; + spi_state <= FIFO_READ; to_spi_fifo_rd_en <= 1'b1; // assert the read enable end else begin spi_state <= IDLE; end - end else if (spi_state == CS_ASSERT) begin + end else if (spi_state == FIFO_READ) begin spi_state <= WRITE; spi_cs_n <= 1'b0; + spi_clk_en <= 1'b0; to_spi_fifo_rd_en <= 1'b0; // deassert the read enable // copy the data from the fifo bitcounter_sc <= sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; @@ -223,12 +228,18 @@ module bidirectional_spi #( read_bitcounter_sc <= 0; transaction_read_data_sc <= 0; + end else if (spi_state == CS_ASSERT) begin + spi_state <= WRITE; + spi_cs_n <= 1'b0; + spi_clk_en <= 1'b0; end else if (spi_state == WRITE) begin if (bitcounter_sc == 0) begin spi_state <= DONE; spi_cs_n <= 1'b1; spi_dir <= 1'b1; + spi_clk_en <= 1'b0; end else begin + spi_clk_en <= 1'b1; spi_state <= WRITE; spi_dir <= transaction_rw_mask_sc[bitcounter_sc - 1]; shift_out <= transaction_data_sc[bitcounter_sc - 1]; @@ -242,6 +253,7 @@ module bidirectional_spi #( end end end else if (spi_state == DONE) begin + shift_out <= 1'b0; if (read_bitcounter_sc == 0) begin spi_state <= IDLE; to_fabric_fifo_wr_en <= 1'b0; diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp index 27fa9201..a6c8b9ab 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp +++ b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp @@ -24,14 +24,20 @@ int main(int argc, char **argv) top->spi_sdio = 0; // Variables for simulation - vluint64_t main_time = 0; // Current simulation time - const vluint64_t sim_time = 4000000; // Adjust as needed + vluint64_t main_time = 0; // Current simulation time + const vluint64_t sim_time_reset_n_clock = 100; // Adjust as needed + const vluint64_t sim_load_value_fifo = 600; // Adjust as needed // Open VCD dump file Verilated::traceEverOn(true); VerilatedVcdC *tfp = new VerilatedVcdC; + VerilatedVcdC *tfp2 = new VerilatedVcdC; + VerilatedVcdC *tfp3 = new VerilatedVcdC; + VerilatedVcdC *tfp4 = new VerilatedVcdC; + VerilatedVcdC *tfp5 = new VerilatedVcdC; + top->trace(tfp, 99); // Trace 99 levels of hierarchy - tfp->open("sim.vcd"); + tfp->open("sim_reset_n_clock.vcd"); // Reset sequence while (main_time < 20) @@ -43,22 +49,175 @@ int main(int argc, char **argv) } top->reset_n = 1; - while (main_time < sim_time) + while (main_time < sim_time_reset_n_clock) { - // Toggle clocks - if ((main_time % 5) == 0) - { - top->fabric_clk = !top->fabric_clk; - } - + top->fabric_clk = !top->fabric_clk; top->eval(); // Evaluate model tfp->dump(main_time); // Dump signals to VCD file main_time++; } - // Cleanup + // Cleanup sim file tfp->close(); + + top->trace(tfp2, 99); // Trace 99 levels of hierarchy + tfp2->open("sim_load_value_mode0.vcd"); + main_time = 0; // Reset time + + top->spi_cpol = 0; + top->spi_cpha = 0; + + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp2->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo) + { + if (main_time == 20) + { + top->transaction_length = 24; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0x00FFFFFF; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp2->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp2->close(); + + top->trace(tfp3, 99); // Trace 99 levels of hierarchy + tfp3->open("sim_load_value_mode1.vcd"); + main_time = 0; // Reset time + + top->spi_cpol = 0; + top->spi_cpha = 1; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp3->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo) + { + if (main_time == 20) + { + top->transaction_length = 24; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0x00FFFFFF; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp3->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp3->close(); + + top->trace(tfp4, 99); // Trace 99 levels of hierarchy + tfp4->open("sim_load_value_mode2.vcd"); + main_time = 0; // Reset time + + top->spi_cpol = 1; + top->spi_cpha = 0; + + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp4->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo) + { + if (main_time == 20) + { + top->transaction_length = 24; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0x00FFFFFF; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp4->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp4->close(); + + top->trace(tfp5, 99); // Trace 99 levels of hierarchy + tfp5->open("sim_load_value_mode3.vcd"); + main_time = 0; // Reset time + + top->spi_cpol = 1; + top->spi_cpha = 1; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp5->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo) + { + if (main_time == 20) + { + top->transaction_length = 24; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0x00FFFFFF; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp5->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp5->close(); delete top; return 0; } diff --git a/HDL/projects/bidirectional_spi/surfer_load_data.ron b/HDL/projects/bidirectional_spi/surfer_load_data.ron new file mode 100644 index 00000000..cb3b488e --- /dev/null +++ b/HDL/projects/bidirectional_spi/surfer_load_data.ron @@ -0,0 +1,396 @@ +( + show_hierarchy: None, + show_menu: None, + show_ticks: None, + show_toolbar: None, + show_tooltip: None, + show_overview: None, + show_statusbar: None, + align_names_right: None, + show_variable_indices: None, + show_variable_direction: None, + show_empty_scopes: None, + show_parameters_in_scopes: None, + waves: Some(( + source: File("sim_load_value.vcd"), + format: Vcd, + active_scope: Some(WaveScope(( + strs: [ + "TOP", + "bidirectional_spi", + ], + ))), + displayed_items_order: [ + (1), + (2), + (3), + (4), + (5), + (6), + (7), + (8), + (9), + (10), + (11), + (12), + (14), + (13), + (15), + (16), + (17), + ], + displayed_items: { + (16): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_state", + ), + color: None, + background_color: None, + display_name: "spi_state [2:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (4): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + ], + ), + name: "transaction_length", + ), + color: None, + background_color: None, + display_name: "transaction_length [7:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (7): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "to_spi_fifo_empty", + ), + color: None, + background_color: None, + display_name: "to_spi_fifo_empty", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (12): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_cs_n", + ), + color: Some("red"), + background_color: None, + display_name: "spi_cs_n", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (17): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "bitcounter_sc", + ), + color: None, + background_color: None, + display_name: "bitcounter_sc [7:0]", + display_name_type: Unique, + manual_name: None, + format: Some("Unsigned"), + field_formats: [], + )), + (5): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "to_spi_fifo_wr_en", + ), + color: None, + background_color: None, + display_name: "to_spi_fifo_wr_en", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (1): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + ], + ), + name: "reset_n", + ), + color: None, + background_color: None, + display_name: "reset_n", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (14): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_sclk", + ), + color: Some("red"), + background_color: None, + display_name: "spi_sclk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (8): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_data_clk", + ), + color: Some("yellow"), + background_color: None, + display_name: "spi_data_clk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (9): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_clk", + ), + color: Some("yellow"), + background_color: None, + display_name: "spi_clk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (6): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + "to_spi_fifo", + "mem", + ], + ), + name: "[0]", + ), + color: None, + background_color: None, + display_name: "[0] [71:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (2): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + ], + ), + name: "fabric_clk", + ), + color: None, + background_color: None, + display_name: "fabric_clk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (10): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "to_spi_fifo_rd_en", + ), + color: None, + background_color: None, + display_name: "to_spi_fifo_rd_en", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (15): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_dir", + ), + color: None, + background_color: None, + display_name: "spi_dir", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (11): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "transaction_data_sc", + ), + color: None, + background_color: None, + display_name: "transaction_data_sc [31:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (13): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_sdio", + ), + color: Some("blue"), + background_color: None, + display_name: "spi_sdio", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (3): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + ], + ), + name: "transaction_data", + ), + color: None, + background_color: None, + display_name: "transaction_data [31:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + }, + display_item_ref_counter: 17, + viewports: [ + ( + curr_left: (-0.14871098911518355), + curr_right: (0.8662955966984591), + target_left: (0.0), + target_right: (1.0), + move_start_left: (0.0), + move_start_right: (1.0), + move_duration: None, + move_strategy: Instant, + ), + ], + cursor: Some((1, [ + 450, + ])), + markers: {}, + focused_item: Some((16)), + focused_transaction: (None, None), + selected_items: [], + default_variable_name_type: Unique, + scroll_offset: 0.0, + display_variable_indices: true, + graphics: {}, + )), + drag_started: false, + drag_source_idx: None, + drag_target_idx: None, + previous_waves: None, + count: None, + blacklisted_translators: [], + show_about: false, + show_keys: false, + show_gestures: false, + show_quick_start: false, + show_license: false, + show_performance: false, + show_logs: false, + show_cursor_window: false, + wanted_timeunit: PicoSeconds, + time_string_format: None, + show_url_entry: false, + variable_name_filter_focused: false, + variable_name_filter_type: Fuzzy, + variable_name_filter_case_insensitive: true, + rename_target: None, + sidepanel_width: Some(300.0), + ui_zoom_factor: None, +) \ No newline at end of file From 407524a12c50c7ba347fd7ad08892a89e593b2c1 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 1 Dec 2024 07:47:45 -0800 Subject: [PATCH 56/96] make sure all 4 spi modes are correct --- .../bidirectional_spi/bidirectional_spi.sv | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index eefd32b9..556997b6 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -47,7 +47,7 @@ module bidirectional_spi #( assign spi_sdio = spi_dir ? shift_out : 1'bz; wire spi_data_clk; - wire spi_clk; + wire spi_clk, spi_clk_gen; reg to_spi_fifo_empty; @@ -98,20 +98,20 @@ module bidirectional_spi #( ); // Reset synchronizer - wire reset_n_sc; // reset_n_sc2; + wire reset_n_sc, reset_n_sc2; reset_synchronizer reset_sync ( .reset_n(reset_n), .clk(spi_data_clk), .sync_reset_n(reset_n_sc) ); - /* + reset_synchronizer reset_sync2 ( .reset_n(reset_n), .clk(spi_clk), .sync_reset_n(reset_n_sc2) ); - */ + // assign the SPI clocks based on the SPI mode spi_clock_generator spi_clock_gen ( @@ -119,10 +119,13 @@ module bidirectional_spi #( .clk_90(spi_clk_90), .cpol(spi_cpol), .cpha(spi_cpha), - .spi_clk(spi_clk), + .spi_clk(spi_clk_gen), .shift_clk(spi_data_clk) ); + // I know this is super hacky, but it allows the logic below to look cleaner + assign spi_clk = spi_cpol ? ~spi_clk_gen : spi_clk_gen; + reg to_spi_fifo_rd_en, to_spi_fifo_wr_en; // Instantiate the asynchronous FIFO for the data going to the SPI side async_fifo #( @@ -195,21 +198,33 @@ module bidirectional_spi #( always_ff @(posedge spi_data_clk or negedge reset_n_sc) begin if (~reset_n_sc) begin spi_state <= IDLE; - spi_clk_en <= 1'b0; + spi_clock_hot <= 1'b0; end end // combinatorial logic to assign the SPI clock - assign spi_sclk = spi_clk_en ? spi_clk : 1'b0; + assign spi_sclk = spi_clk_en ? (spi_cpol ? ~spi_clk : spi_clk) : spi_cpol; reg spi_clk_en; + // Synchronize the SPI clock enable signal + always_ff @(posedge spi_clk or negedge reset_n_sc2) begin + if (~reset_n_sc2) begin + spi_clk_en <= 1'b0; + end else if (spi_clock_hot) begin + spi_clk_en <= 1'b1; + end else begin + spi_clk_en <= 1'b0; + end + end + + reg spi_clock_hot; + always_ff @(posedge spi_data_clk or negedge reset_n_sc) begin if (reset_n_sc) begin if (spi_state == IDLE) begin to_fabric_fifo_wr_en <= 1'b0; shift_out <= 1'b0; - spi_clk_en <= 1'b0; if(~to_spi_fifo_empty) begin spi_state <= FIFO_READ; to_spi_fifo_rd_en <= 1'b1; // assert the read enable @@ -219,7 +234,6 @@ module bidirectional_spi #( end else if (spi_state == FIFO_READ) begin spi_state <= WRITE; spi_cs_n <= 1'b0; - spi_clk_en <= 1'b0; to_spi_fifo_rd_en <= 1'b0; // deassert the read enable // copy the data from the fifo bitcounter_sc <= sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; @@ -228,18 +242,24 @@ module bidirectional_spi #( read_bitcounter_sc <= 0; transaction_read_data_sc <= 0; + if (spi_cpha) begin + spi_clock_hot <= 1'b1; + end end else if (spi_state == CS_ASSERT) begin spi_state <= WRITE; spi_cs_n <= 1'b0; - spi_clk_en <= 1'b0; end else if (spi_state == WRITE) begin if (bitcounter_sc == 0) begin spi_state <= DONE; spi_cs_n <= 1'b1; spi_dir <= 1'b1; - spi_clk_en <= 1'b0; + spi_clock_hot <= 1'b0; end else begin - spi_clk_en <= 1'b1; + if (spi_cpha && bitcounter_sc == 1) begin + spi_clock_hot <= 1'b0; + end else begin + spi_clock_hot <= 1'b1; + end spi_state <= WRITE; spi_dir <= transaction_rw_mask_sc[bitcounter_sc - 1]; shift_out <= transaction_data_sc[bitcounter_sc - 1]; From 4be654dbf4ef3a9c4493cb9dcfb9eaacc68939ad Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 1 Dec 2024 18:47:05 -0800 Subject: [PATCH 57/96] moved the sampling of the read data into the spi_clk trigger --- .../bidirectional_spi/bidirectional_spi.sv | 17 +++- .../bidirectional_spi_tb.cpp | 81 +++++++++++++++++++ 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index 556997b6..f0042565 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -179,7 +179,7 @@ module bidirectional_spi #( spi_cs_n <= 1'b1; to_fabric_fifo_wr_en <= 1'b0; to_spi_fifo_rd_en <= 1'b0; - read_bitcounter_sc <= 0; + //read_bitcounter_sc <= 0; end end @@ -213,6 +213,10 @@ module bidirectional_spi #( spi_clk_en <= 1'b0; end else if (spi_clock_hot) begin spi_clk_en <= 1'b1; + if (spi_dir == 0) begin + read_bitcounter_sc <= read_bitcounter_sc + 1; + transaction_read_data_sc[bitcounter_sc -1] <= spi_sdio; + end end else begin spi_clk_en <= 1'b0; end @@ -240,8 +244,10 @@ module bidirectional_spi #( transaction_rw_mask_sc <= sc_data[DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH]; transaction_data_sc <= sc_data[DATA_WIDTH-1:0]; + /* read_bitcounter_sc <= 0; transaction_read_data_sc <= 0; + */ if (spi_cpha) begin spi_clock_hot <= 1'b1; end @@ -254,6 +260,7 @@ module bidirectional_spi #( spi_cs_n <= 1'b1; spi_dir <= 1'b1; spi_clock_hot <= 1'b0; + shift_out <= 0; end else begin if (spi_cpha && bitcounter_sc == 1) begin spi_clock_hot <= 1'b0; @@ -262,8 +269,13 @@ module bidirectional_spi #( end spi_state <= WRITE; spi_dir <= transaction_rw_mask_sc[bitcounter_sc - 1]; - shift_out <= transaction_data_sc[bitcounter_sc - 1]; + if (transaction_rw_mask_sc[bitcounter_sc - 1]) begin + shift_out <= transaction_data_sc[bitcounter_sc - 1]; + end else begin + shift_out <= 0; + end bitcounter_sc <= bitcounter_sc - 1; + /* if (~transaction_rw_mask_sc[bitcounter_sc - 1]) begin read_bitcounter_sc <= read_bitcounter_sc + 1; transaction_read_data_sc[bitcounter_sc -1] <= spi_sdio; @@ -271,6 +283,7 @@ module bidirectional_spi #( // this is to fill in blank bits if the mask is not continuous transaction_read_data_sc[bitcounter_sc -1] <= 0; end + */ end end else if (spi_state == DONE) begin shift_out <= 1'b0; diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp index a6c8b9ab..a51f2e2c 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp +++ b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp @@ -27,6 +27,7 @@ int main(int argc, char **argv) vluint64_t main_time = 0; // Current simulation time const vluint64_t sim_time_reset_n_clock = 100; // Adjust as needed const vluint64_t sim_load_value_fifo = 600; // Adjust as needed + const vluint64_t sim_load_value_fifo_32 = 700; // Adjust as needed // Open VCD dump file Verilated::traceEverOn(true); @@ -35,6 +36,8 @@ int main(int argc, char **argv) VerilatedVcdC *tfp3 = new VerilatedVcdC; VerilatedVcdC *tfp4 = new VerilatedVcdC; VerilatedVcdC *tfp5 = new VerilatedVcdC; + VerilatedVcdC *tfp6 = new VerilatedVcdC; + VerilatedVcdC *tfp7 = new VerilatedVcdC; top->trace(tfp, 99); // Trace 99 levels of hierarchy tfp->open("sim_reset_n_clock.vcd"); @@ -218,6 +221,84 @@ int main(int argc, char **argv) } // cleanup sim file tfp5->close(); + + top->trace(tfp6, 99); // Trace 99 levels of hierarchy + tfp6->open("sim_load_value_mode0_32bit.vcd"); + main_time = 0; // Reset time + + top->spi_cpol = 0; + top->spi_cpha = 0; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp6->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0xFFFFFFFF; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp6->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp6->close(); + + top->trace(tfp7, 99); // Trace 99 levels of hierarchy + tfp7->open("sim_load_value_mode0_24_8rbit.vcd"); + main_time = 0; // Reset time + + top->spi_cpol = 1; + top->spi_cpha = 0; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp7->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0xFFFFFF00; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp7->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp7->close(); delete top; return 0; } From b5c998869cf25fc5f5474b03a47f7e18e90ebdd1 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Mon, 2 Dec 2024 04:22:31 -0800 Subject: [PATCH 58/96] support all 4 SPI modes for the read sampling correctly --- .../bidirectional_spi/bidirectional_spi.sv | 27 ++++++++++++------- .../bidirectional_spi_tb.cpp | 2 +- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index f0042565..6a5ba559 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -208,18 +208,27 @@ module bidirectional_spi #( reg spi_clk_en; // Synchronize the SPI clock enable signal - always_ff @(posedge spi_clk or negedge reset_n_sc2) begin + always_ff @(posedge spi_clk or negedge spi_clk or negedge reset_n_sc2) begin if (~reset_n_sc2) begin spi_clk_en <= 1'b0; - end else if (spi_clock_hot) begin - spi_clk_en <= 1'b1; - if (spi_dir == 0) begin - read_bitcounter_sc <= read_bitcounter_sc + 1; - transaction_read_data_sc[bitcounter_sc -1] <= spi_sdio; - end end else begin - spi_clk_en <= 1'b0; - end + // manage the clock enable signal only on rising edge + if (spi_clk) begin + if (spi_clock_hot) begin + spi_clk_en <= 1'b1; + end else begin + spi_clk_en <= 1'b0; + end + end + // do the reads on either the rising or falling edge of the clock, depending + // on the SPI mode + if (spi_clock_hot && spi_dir == 0) begin + if ((spi_clk && ~spi_cpha) || (~spi_clk && spi_cpha)) begin + read_bitcounter_sc <= read_bitcounter_sc + 1; + transaction_read_data_sc[bitcounter_sc -1] <= spi_sdio; + end + end + end end reg spi_clock_hot; diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp index a51f2e2c..ab1e2d88 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp +++ b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp @@ -266,7 +266,7 @@ int main(int argc, char **argv) main_time = 0; // Reset time top->spi_cpol = 1; - top->spi_cpha = 0; + top->spi_cpha = 1; // Reset sequence while (main_time < 20) { From a3c8bca0b65c33ba7933ad2d892384d2a8246d13 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Mon, 2 Dec 2024 04:27:12 -0800 Subject: [PATCH 59/96] add some more test cases and another surfer state --- .../bidirectional_spi_tb.cpp | 127 +++++- .../bidirectional_spi/surfer_load_data_rw.ron | 415 ++++++++++++++++++ 2 files changed, 539 insertions(+), 3 deletions(-) create mode 100644 HDL/projects/bidirectional_spi/surfer_load_data_rw.ron diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp index ab1e2d88..b19fd642 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp +++ b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp @@ -38,6 +38,9 @@ int main(int argc, char **argv) VerilatedVcdC *tfp5 = new VerilatedVcdC; VerilatedVcdC *tfp6 = new VerilatedVcdC; VerilatedVcdC *tfp7 = new VerilatedVcdC; + VerilatedVcdC *tfp8 = new VerilatedVcdC; + VerilatedVcdC *tfp9 = new VerilatedVcdC; + VerilatedVcdC *tfp10 = new VerilatedVcdC; top->trace(tfp, 99); // Trace 99 levels of hierarchy tfp->open("sim_reset_n_clock.vcd"); @@ -262,11 +265,11 @@ int main(int argc, char **argv) tfp6->close(); top->trace(tfp7, 99); // Trace 99 levels of hierarchy - tfp7->open("sim_load_value_mode0_24_8rbit.vcd"); + tfp7->open("sim_load_value_mode0_24_8rbit_mode0.vcd"); main_time = 0; // Reset time - top->spi_cpol = 1; - top->spi_cpha = 1; + top->spi_cpol = 0; + top->spi_cpha = 0; // Reset sequence while (main_time < 20) { @@ -299,6 +302,124 @@ int main(int argc, char **argv) } // cleanup sim file tfp7->close(); + + top->trace(tfp8, 99); // Trace 99 levels of hierarchy + tfp8->open("sim_load_value_mode0_24_8rbit_mode1.vcd"); + main_time = 0; // Reset time + + top->spi_cpol = 0; + top->spi_cpha = 1; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp8->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0xFFFFFF00; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp8->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp8->close(); + + top->trace(tfp9, 99); // Trace 99 levels of hierarchy + tfp9->open("sim_load_value_mode0_24_8rbit_mode2.vcd"); + main_time = 0; // Reset time + + top->spi_cpol = 1; + top->spi_cpha = 0; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp9->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0xFFFFFF00; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp9->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp9->close(); + + top->trace(tfp10, 99); // Trace 99 levels of hierarchy + tfp10->open("sim_load_value_mode0_24_8rbit_mode3.vcd"); + main_time = 0; // Reset time + + top->spi_cpol = 1; + top->spi_cpha = 1; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp10->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0xFFFFFF00; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp10->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp10->close(); + delete top; return 0; } diff --git a/HDL/projects/bidirectional_spi/surfer_load_data_rw.ron b/HDL/projects/bidirectional_spi/surfer_load_data_rw.ron new file mode 100644 index 00000000..5670c205 --- /dev/null +++ b/HDL/projects/bidirectional_spi/surfer_load_data_rw.ron @@ -0,0 +1,415 @@ +( + show_hierarchy: None, + show_menu: None, + show_ticks: None, + show_toolbar: None, + show_tooltip: None, + show_overview: None, + show_statusbar: None, + align_names_right: None, + show_variable_indices: None, + show_variable_direction: None, + show_empty_scopes: None, + show_parameters_in_scopes: None, + waves: Some(( + source: File("sim_load_value_mode0_24_8rbit_mode0.vcd"), + format: Vcd, + active_scope: Some(WaveScope(( + strs: [ + "TOP", + "bidirectional_spi", + ], + ))), + displayed_items_order: [ + (1), + (2), + (3), + (4), + (5), + (6), + (7), + (8), + (9), + (10), + (11), + (12), + (14), + (13), + (15), + (16), + (17), + (18), + ], + displayed_items: { + (12): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_cs_n", + ), + color: Some("red"), + background_color: None, + display_name: "spi_cs_n", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (5): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "to_spi_fifo_wr_en", + ), + color: None, + background_color: None, + display_name: "to_spi_fifo_wr_en", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (2): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + ], + ), + name: "fabric_clk", + ), + color: None, + background_color: None, + display_name: "fabric_clk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (9): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_clk", + ), + color: Some("yellow"), + background_color: None, + display_name: "spi_clk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (18): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "read_bitcounter_sc", + ), + color: Some("violet"), + background_color: None, + display_name: "read_bitcounter_sc [7:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (15): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_dir", + ), + color: None, + background_color: None, + display_name: "spi_dir", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (16): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_state", + ), + color: None, + background_color: None, + display_name: "spi_state [2:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (3): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + ], + ), + name: "transaction_data", + ), + color: None, + background_color: None, + display_name: "transaction_data [31:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (6): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + "to_spi_fifo", + "mem", + ], + ), + name: "[0]", + ), + color: None, + background_color: None, + display_name: "[0] [71:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (1): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + ], + ), + name: "reset_n", + ), + color: None, + background_color: None, + display_name: "reset_n", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (10): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "to_spi_fifo_rd_en", + ), + color: None, + background_color: None, + display_name: "to_spi_fifo_rd_en", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (7): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "to_spi_fifo_empty", + ), + color: None, + background_color: None, + display_name: "to_spi_fifo_empty", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (14): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_sclk", + ), + color: Some("red"), + background_color: None, + display_name: "spi_sclk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (13): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_sdio", + ), + color: Some("blue"), + background_color: None, + display_name: "spi_sdio", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (11): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "transaction_data_sc", + ), + color: None, + background_color: None, + display_name: "transaction_data_sc [31:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (8): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_data_clk", + ), + color: Some("yellow"), + background_color: None, + display_name: "spi_data_clk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (4): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + ], + ), + name: "transaction_length", + ), + color: None, + background_color: None, + display_name: "transaction_length [7:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (17): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "bitcounter_sc", + ), + color: None, + background_color: None, + display_name: "bitcounter_sc [7:0]", + display_name_type: Unique, + manual_name: None, + format: Some("Unsigned"), + field_formats: [], + )), + }, + display_item_ref_counter: 18, + viewports: [ + ( + curr_left: (0.5484446044212009), + curr_right: (0.8239406535331145), + target_left: (0.0), + target_right: (1.0), + move_start_left: (0.0), + move_start_right: (1.0), + move_duration: None, + move_strategy: Instant, + ), + ], + cursor: Some((1, [ + 450, + ])), + markers: {}, + focused_item: Some((17)), + focused_transaction: (None, None), + selected_items: [], + default_variable_name_type: Unique, + scroll_offset: 0.0, + display_variable_indices: true, + graphics: {}, + )), + drag_started: false, + drag_source_idx: None, + drag_target_idx: None, + previous_waves: None, + count: None, + blacklisted_translators: [], + show_about: false, + show_keys: false, + show_gestures: false, + show_quick_start: false, + show_license: false, + show_performance: false, + show_logs: false, + show_cursor_window: false, + wanted_timeunit: PicoSeconds, + time_string_format: None, + show_url_entry: false, + variable_name_filter_focused: false, + variable_name_filter_type: Fuzzy, + variable_name_filter_case_insensitive: true, + rename_target: None, + sidepanel_width: Some(300.0), + ui_zoom_factor: None, +) \ No newline at end of file From 495ea1f694461d83f6d35b3a27507df61118062b Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Mon, 2 Dec 2024 04:46:02 -0800 Subject: [PATCH 60/96] some cleanup --- .../bidirectional_spi/bidirectional_spi.sv | 22 +++++++------------ .../bidirectional_spi_tb.cpp | 1 + 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index 6a5ba559..d49d6b7a 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -211,6 +211,9 @@ module bidirectional_spi #( always_ff @(posedge spi_clk or negedge spi_clk or negedge reset_n_sc2) begin if (~reset_n_sc2) begin spi_clk_en <= 1'b0; + // delete the read data stuff + read_bitcounter_sc <= 0; + transaction_read_data_sc <= 0; end else begin // manage the clock enable signal only on rising edge if (spi_clk) begin @@ -220,6 +223,7 @@ module bidirectional_spi #( spi_clk_en <= 1'b0; end end + // do the reads on either the rising or falling edge of the clock, depending // on the SPI mode if (spi_clock_hot && spi_dir == 0) begin @@ -227,6 +231,9 @@ module bidirectional_spi #( read_bitcounter_sc <= read_bitcounter_sc + 1; transaction_read_data_sc[bitcounter_sc -1] <= spi_sdio; end + end else if (spi_state == IDLE) begin + read_bitcounter_sc <= 0; + transaction_read_data_sc <= 0; end end end @@ -238,6 +245,7 @@ module bidirectional_spi #( if (spi_state == IDLE) begin to_fabric_fifo_wr_en <= 1'b0; shift_out <= 1'b0; + spi_cs_n <= 1'b1; if(~to_spi_fifo_empty) begin spi_state <= FIFO_READ; to_spi_fifo_rd_en <= 1'b1; // assert the read enable @@ -252,11 +260,6 @@ module bidirectional_spi #( bitcounter_sc <= sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; transaction_rw_mask_sc <= sc_data[DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH]; transaction_data_sc <= sc_data[DATA_WIDTH-1:0]; - - /* - read_bitcounter_sc <= 0; - transaction_read_data_sc <= 0; - */ if (spi_cpha) begin spi_clock_hot <= 1'b1; end @@ -284,15 +287,6 @@ module bidirectional_spi #( shift_out <= 0; end bitcounter_sc <= bitcounter_sc - 1; - /* - if (~transaction_rw_mask_sc[bitcounter_sc - 1]) begin - read_bitcounter_sc <= read_bitcounter_sc + 1; - transaction_read_data_sc[bitcounter_sc -1] <= spi_sdio; - end else begin - // this is to fill in blank bits if the mask is not continuous - transaction_read_data_sc[bitcounter_sc -1] <= 0; - end - */ end end else if (spi_state == DONE) begin shift_out <= 1'b0; diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp index b19fd642..648220a2 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp +++ b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp @@ -294,6 +294,7 @@ int main(int argc, char **argv) top->transaction_data = 0x00000000; top->transaction_rw_mask = 0x00000000; } + top->fabric_clk = !top->fabric_clk; top->eval(); // Evaluate model tfp7->dump(main_time); // Dump signals to VCD file From 2eee600c1c7b22705624076a76b88a59021b48c3 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Mon, 2 Dec 2024 05:02:19 -0800 Subject: [PATCH 61/96] added a TODO file --- HDL/projects/bidirectional_spi/TODO.md | 5 +++++ .../bidirectional_spi/bidirectional_spi.sv | 19 ++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 HDL/projects/bidirectional_spi/TODO.md diff --git a/HDL/projects/bidirectional_spi/TODO.md b/HDL/projects/bidirectional_spi/TODO.md new file mode 100644 index 00000000..ea8026ab --- /dev/null +++ b/HDL/projects/bidirectional_spi/TODO.md @@ -0,0 +1,5 @@ +Important issues remaining on this core +- [ ] Reading doesn't shift into correct bits (off by one) (not done) +- [ ] To fabric FIFO transfer does not finnish due to possible reset (not done) +- [ ] Asserts in testbench (not done) +- [ ] inout doesn't work in test bench (not done) \ No newline at end of file diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index d49d6b7a..ce2f05fd 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -55,6 +55,7 @@ module bidirectional_spi #( typedef enum logic [1:0] { F_IDLE, F_WRITE, + F_READ, F_DONE } fstate_t; @@ -79,9 +80,21 @@ module bidirectional_spi #( end else begin fabric_state <= F_IDLE; end + // check if there is something to read + if (~to_fabric_fifo_empty) begin + to_fabric_fifo_rd_en <= 1'b1; + fabric_state <= F_READ; + end else begin + to_fabric_fifo_rd_en <= 1'b0; + end end else if (fabric_state == F_WRITE) begin fabric_state <= F_IDLE; to_spi_fifo_wr_en <= 1'b0; + end else if (fabric_state == F_READ) begin + to_fabric_fifo_rd_en <= 1'b0; + fabric_state <= F_IDLE; + // should also copy the data from the FIFO + end end @@ -148,7 +161,7 @@ module bidirectional_spi #( /* verilator lint_on PINCONNECTEMPTY */ ); - reg to_fabric_fifo_full, to_fabric_fifo_wr_en, to_fabric_fifo_rd_en; + reg to_fabric_fifo_full, to_fabric_fifo_empty, to_fabric_fifo_wr_en, to_fabric_fifo_rd_en; // Instantiate the asynchronous FIFO for the data coming from the SPI side async_fifo #( @@ -164,8 +177,8 @@ module bidirectional_spi #( .rd_data(transaction_read_data), .rd_en(to_fabric_fifo_rd_en), .full(to_fabric_fifo_full), + .empty(to_fabric_fifo_empty), /* verilator lint_off PINCONNECTEMPTY */ - .empty(), .almost_empty(), .almost_full() /* verilator lint_on PINCONNECTEMPTY */ @@ -229,7 +242,7 @@ module bidirectional_spi #( if (spi_clock_hot && spi_dir == 0) begin if ((spi_clk && ~spi_cpha) || (~spi_clk && spi_cpha)) begin read_bitcounter_sc <= read_bitcounter_sc + 1; - transaction_read_data_sc[bitcounter_sc -1] <= spi_sdio; + transaction_read_data_sc[bitcounter_sc -1] <= 1'b1; //spi_sdio; end end else if (spi_state == IDLE) begin read_bitcounter_sc <= 0; From 46adb2d9f51de1b9e5b25ab5fecc0115de522d29 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Mon, 2 Dec 2024 07:32:01 -0800 Subject: [PATCH 62/96] counters are still wrong --- HDL/projects/bidirectional_spi/TODO.md | 3 ++- .../bidirectional_spi/bidirectional_spi.sv | 22 ++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/HDL/projects/bidirectional_spi/TODO.md b/HDL/projects/bidirectional_spi/TODO.md index ea8026ab..60fd7681 100644 --- a/HDL/projects/bidirectional_spi/TODO.md +++ b/HDL/projects/bidirectional_spi/TODO.md @@ -2,4 +2,5 @@ Important issues remaining on this core - [ ] Reading doesn't shift into correct bits (off by one) (not done) - [ ] To fabric FIFO transfer does not finnish due to possible reset (not done) - [ ] Asserts in testbench (not done) -- [ ] inout doesn't work in test bench (not done) \ No newline at end of file +- [ ] inout doesn't work in test bench (not done) +- [ ] correct bitlengths for transaction length and bitcounters \ No newline at end of file diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index ce2f05fd..7f3d1643 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -10,7 +10,7 @@ // this core can be adapted to full-duplex SPI by adding a second data wire. module bidirectional_spi #( parameter DATA_WIDTH = 32, - parameter TRANSACTION_LEN_WIDTH = 8 + parameter TRANSACTION_LEN_WIDTH = 6 )( input wire [TRANSACTION_LEN_WIDTH-1:0] transaction_length, input wire [DATA_WIDTH-1:0] transaction_data, @@ -32,9 +32,11 @@ module bidirectional_spi #( reg spi_dir; // Direction control for the SPI interface (1 for write, 0 for read) reg shift_out; // SPI Data to be shifted out + localparam BIT_COUNT_WIDTH = $clog2(DATA_WIDTH); + // Some of our data in the spi_clk domain - reg [TRANSACTION_LEN_WIDTH-1:0] bitcounter_sc, r_transaction_length; - reg [TRANSACTION_LEN_WIDTH-1:0] read_bitcounter_sc; + reg [TRANSACTION_LEN_WIDTH-1:0] r_transaction_length; + reg [BIT_COUNT_WIDTH-1:0] bitcounter_sc, read_bitcounter_sc; reg [DATA_WIDTH-1:0] transaction_rw_mask_sc, r_transaction_rw_mask; reg [DATA_WIDTH-1:0] transaction_data_sc, r_transaction_data; @@ -242,7 +244,7 @@ module bidirectional_spi #( if (spi_clock_hot && spi_dir == 0) begin if ((spi_clk && ~spi_cpha) || (~spi_clk && spi_cpha)) begin read_bitcounter_sc <= read_bitcounter_sc + 1; - transaction_read_data_sc[bitcounter_sc -1] <= 1'b1; //spi_sdio; + transaction_read_data_sc[bitcounter_sc] <= 1'b1; //spi_sdio; end end else if (spi_state == IDLE) begin read_bitcounter_sc <= 0; @@ -252,6 +254,10 @@ module bidirectional_spi #( end reg spi_clock_hot; + /* verilator lint_off UNUSEDSIGNAL */ + wire[BIT_COUNT_WIDTH:0] intermediate_bitcounter; + assign intermediate_bitcounter = sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH] - 1; + /* verilator lint_on UNUSEDSIGNAL */ always_ff @(posedge spi_data_clk or negedge reset_n_sc) begin if (reset_n_sc) begin @@ -270,7 +276,7 @@ module bidirectional_spi #( spi_cs_n <= 1'b0; to_spi_fifo_rd_en <= 1'b0; // deassert the read enable // copy the data from the fifo - bitcounter_sc <= sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; + bitcounter_sc <= intermediate_bitcounter[BIT_COUNT_WIDTH-1:0]; transaction_rw_mask_sc <= sc_data[DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH]; transaction_data_sc <= sc_data[DATA_WIDTH-1:0]; if (spi_cpha) begin @@ -293,9 +299,9 @@ module bidirectional_spi #( spi_clock_hot <= 1'b1; end spi_state <= WRITE; - spi_dir <= transaction_rw_mask_sc[bitcounter_sc - 1]; - if (transaction_rw_mask_sc[bitcounter_sc - 1]) begin - shift_out <= transaction_data_sc[bitcounter_sc - 1]; + spi_dir <= transaction_rw_mask_sc[bitcounter_sc]; + if (transaction_rw_mask_sc[bitcounter_sc]) begin + shift_out <= transaction_data_sc[bitcounter_sc]; end else begin shift_out <= 0; end From 599dea83ef797a333abddba742de24958533ec5a Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 4 Dec 2024 15:51:07 -0800 Subject: [PATCH 63/96] first simplified "single clock" master, still needs work though --- HDL/projects/bidirectional_spi/TODO.md | 3 +- .../bidirectional_spi/bidirectional_spi.sv | 124 ++++++++---------- 2 files changed, 56 insertions(+), 71 deletions(-) diff --git a/HDL/projects/bidirectional_spi/TODO.md b/HDL/projects/bidirectional_spi/TODO.md index 60fd7681..294c090d 100644 --- a/HDL/projects/bidirectional_spi/TODO.md +++ b/HDL/projects/bidirectional_spi/TODO.md @@ -3,4 +3,5 @@ Important issues remaining on this core - [ ] To fabric FIFO transfer does not finnish due to possible reset (not done) - [ ] Asserts in testbench (not done) - [ ] inout doesn't work in test bench (not done) -- [ ] correct bitlengths for transaction length and bitcounters \ No newline at end of file +- [ ] correct bitlengths for transaction length and bitcounters (not done) +- [ ] remove dual clock approach and replace with simple single clock \ No newline at end of file diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index 7f3d1643..9bb9b363 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -36,7 +36,7 @@ module bidirectional_spi #( // Some of our data in the spi_clk domain reg [TRANSACTION_LEN_WIDTH-1:0] r_transaction_length; - reg [BIT_COUNT_WIDTH-1:0] bitcounter_sc, read_bitcounter_sc; + reg [BIT_COUNT_WIDTH:0] bitcounter_sc, read_bitcounter_sc; reg [DATA_WIDTH-1:0] transaction_rw_mask_sc, r_transaction_rw_mask; reg [DATA_WIDTH-1:0] transaction_data_sc, r_transaction_data; @@ -48,7 +48,6 @@ module bidirectional_spi #( assign fc_data = {r_transaction_length, r_transaction_rw_mask, r_transaction_data}; assign spi_sdio = spi_dir ? shift_out : 1'bz; - wire spi_data_clk; wire spi_clk, spi_clk_gen; reg to_spi_fifo_empty; @@ -98,46 +97,28 @@ module bidirectional_spi #( // should also copy the data from the FIFO end - end - - - wire spi_clk_0,spi_clk_90; + end // Generate the clocks quadrature_clock_divider clock_div ( .reset_n(reset_n), .clk_in(fabric_clk), .div_factor_4(2), - .sck_0(spi_clk_0), - .sck_90(spi_clk_90) + .sck_0(spi_clk_gen), + /* verilator lint_off PINCONNECTEMPTY */ + .sck_90() + /* verilator lint_on PINCONNECTEMPTY */ ); // Reset synchronizer - wire reset_n_sc, reset_n_sc2; - reset_synchronizer reset_sync ( - .reset_n(reset_n), - .clk(spi_data_clk), - .sync_reset_n(reset_n_sc) - ); + wire reset_n_sc; - - reset_synchronizer reset_sync2 ( + reset_synchronizer reset_sync ( .reset_n(reset_n), .clk(spi_clk), - .sync_reset_n(reset_n_sc2) + .sync_reset_n(reset_n_sc) ); - - // assign the SPI clocks based on the SPI mode - spi_clock_generator spi_clock_gen ( - .clk_0(spi_clk_0), - .clk_90(spi_clk_90), - .cpol(spi_cpol), - .cpha(spi_cpha), - .spi_clk(spi_clk_gen), - .shift_clk(spi_data_clk) - ); - // I know this is super hacky, but it allows the logic below to look cleaner assign spi_clk = spi_cpol ? ~spi_clk_gen : spi_clk_gen; @@ -151,7 +132,7 @@ module bidirectional_spi #( .wr_rst_n(reset_n), .wr_data(fc_data), .wr_en(to_spi_fifo_wr_en), - .rd_clk(spi_data_clk), + .rd_clk(spi_clk), .rd_rst_n(reset_n), .rd_data(sc_data), .rd_en(to_spi_fifo_rd_en), @@ -170,7 +151,7 @@ module bidirectional_spi #( .DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(3) ) to_fabric_fifo ( - .wr_clk(spi_data_clk), + .wr_clk(spi_clk), .wr_rst_n(reset_n), .wr_data(transaction_read_data_sc), .wr_en(to_fabric_fifo_wr_en), @@ -186,18 +167,6 @@ module bidirectional_spi #( /* verilator lint_on PINCONNECTEMPTY */ ); - // SPI side reset logic - always @(posedge spi_data_clk or negedge reset_n_sc) begin - if (~reset_n_sc) begin - spi_dir <= 1'b1; - shift_out <= 1'b0; - spi_cs_n <= 1'b1; - to_fabric_fifo_wr_en <= 1'b0; - to_spi_fifo_rd_en <= 1'b0; - //read_bitcounter_sc <= 0; - end - end - // SPI state machine stuff typedef enum logic [2:0] { IDLE, @@ -209,19 +178,10 @@ module bidirectional_spi #( state_t spi_state; - // reset the state machine - always_ff @(posedge spi_data_clk or negedge reset_n_sc) begin - if (~reset_n_sc) begin - spi_state <= IDLE; - spi_clock_hot <= 1'b0; - end - end - // combinatorial logic to assign the SPI clock - assign spi_sclk = spi_clk_en ? (spi_cpol ? ~spi_clk : spi_clk) : spi_cpol; - - reg spi_clk_en; + assign spi_sclk = spi_clock_hot ? (spi_cpol ? ~spi_clk : spi_clk) : spi_cpol; + /* // Synchronize the SPI clock enable signal always_ff @(posedge spi_clk or negedge spi_clk or negedge reset_n_sc2) begin if (~reset_n_sc2) begin @@ -244,7 +204,7 @@ module bidirectional_spi #( if (spi_clock_hot && spi_dir == 0) begin if ((spi_clk && ~spi_cpha) || (~spi_clk && spi_cpha)) begin read_bitcounter_sc <= read_bitcounter_sc + 1; - transaction_read_data_sc[bitcounter_sc] <= 1'b1; //spi_sdio; + //transaction_read_data_sc[bitcounter_sc] <= 1'b1; //spi_sdio; end end else if (spi_state == IDLE) begin read_bitcounter_sc <= 0; @@ -253,14 +213,26 @@ module bidirectional_spi #( end end + */ + reg spi_clock_hot; /* verilator lint_off UNUSEDSIGNAL */ wire[BIT_COUNT_WIDTH:0] intermediate_bitcounter; - assign intermediate_bitcounter = sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH] - 1; + assign intermediate_bitcounter = sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; /* verilator lint_on UNUSEDSIGNAL */ - always_ff @(posedge spi_data_clk or negedge reset_n_sc) begin - if (reset_n_sc) begin + always_ff @(posedge spi_clk or negedge spi_clk or negedge reset_n_sc) begin + if (~reset_n_sc) begin + spi_dir <= 1'b1; + shift_out <= 1'b0; + spi_cs_n <= 1'b1; + to_spi_fifo_rd_en <= 1'b0; + to_fabric_fifo_wr_en <= 1'b0; + spi_state <= IDLE; + spi_clock_hot <= 1'b0; + transaction_read_data_sc <= 0; + read_bitcounter_sc <= 0; + end else begin if (spi_state == IDLE) begin to_fabric_fifo_wr_en <= 1'b0; shift_out <= 1'b0; @@ -272,19 +244,25 @@ module bidirectional_spi #( spi_state <= IDLE; end end else if (spi_state == FIFO_READ) begin - spi_state <= WRITE; - spi_cs_n <= 1'b0; + spi_state <= CS_ASSERT; to_spi_fifo_rd_en <= 1'b0; // deassert the read enable // copy the data from the fifo - bitcounter_sc <= intermediate_bitcounter[BIT_COUNT_WIDTH-1:0]; + bitcounter_sc <= intermediate_bitcounter; //[BIT_COUNT_WIDTH-1:0]; transaction_rw_mask_sc <= sc_data[DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH]; transaction_data_sc <= sc_data[DATA_WIDTH-1:0]; - if (spi_cpha) begin - spi_clock_hot <= 1'b1; - end end else if (spi_state == CS_ASSERT) begin spi_state <= WRITE; spi_cs_n <= 1'b0; + spi_clock_hot <= 1'b1; + if (~spi_clk && ~spi_cpha) begin + spi_dir <= transaction_rw_mask_sc[bitcounter_sc-1]; + if (transaction_rw_mask_sc[bitcounter_sc-1]) begin + shift_out <= transaction_data_sc[bitcounter_sc-1]; + end else begin + shift_out <= 0; + end + bitcounter_sc <= bitcounter_sc - 1; + end end else if (spi_state == WRITE) begin if (bitcounter_sc == 0) begin spi_state <= DONE; @@ -293,19 +271,25 @@ module bidirectional_spi #( spi_clock_hot <= 1'b0; shift_out <= 0; end else begin + /* if (spi_cpha && bitcounter_sc == 1) begin spi_clock_hot <= 1'b0; end else begin spi_clock_hot <= 1'b1; end - spi_state <= WRITE; - spi_dir <= transaction_rw_mask_sc[bitcounter_sc]; - if (transaction_rw_mask_sc[bitcounter_sc]) begin - shift_out <= transaction_data_sc[bitcounter_sc]; - end else begin - shift_out <= 0; + */ + if ((spi_clk && spi_cpha) || (~spi_clk && ~spi_cpha)) begin + + spi_state <= WRITE; + bitcounter_sc <= bitcounter_sc - 1; + + spi_dir <= transaction_rw_mask_sc[bitcounter_sc-1]; + if (transaction_rw_mask_sc[bitcounter_sc-1]) begin + shift_out <= transaction_data_sc[bitcounter_sc-1]; + end else begin + shift_out <= 0; + end end - bitcounter_sc <= bitcounter_sc - 1; end end else if (spi_state == DONE) begin shift_out <= 1'b0; From ed5b8f745de333b0ef6b3cc02eb60c4bf3f31882 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 4 Dec 2024 16:04:10 -0800 Subject: [PATCH 64/96] fix the 0th bit --- .../bidirectional_spi/bidirectional_spi.sv | 35 +++++++------------ 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index 9bb9b363..4a7f1fc5 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -254,7 +254,7 @@ module bidirectional_spi #( spi_state <= WRITE; spi_cs_n <= 1'b0; spi_clock_hot <= 1'b1; - if (~spi_clk && ~spi_cpha) begin + if (~spi_cpol && ~spi_clk && ~spi_cpha) begin spi_dir <= transaction_rw_mask_sc[bitcounter_sc-1]; if (transaction_rw_mask_sc[bitcounter_sc-1]) begin shift_out <= transaction_data_sc[bitcounter_sc-1]; @@ -266,33 +266,24 @@ module bidirectional_spi #( end else if (spi_state == WRITE) begin if (bitcounter_sc == 0) begin spi_state <= DONE; - spi_cs_n <= 1'b1; - spi_dir <= 1'b1; - spi_clock_hot <= 1'b0; - shift_out <= 0; end else begin - /* - if (spi_cpha && bitcounter_sc == 1) begin - spi_clock_hot <= 1'b0; - end else begin - spi_clock_hot <= 1'b1; - end - */ - if ((spi_clk && spi_cpha) || (~spi_clk && ~spi_cpha)) begin - - spi_state <= WRITE; - bitcounter_sc <= bitcounter_sc - 1; + spi_state <= WRITE; + end + if ((spi_clk && spi_cpha) || (~spi_clk && ~spi_cpha)) begin + bitcounter_sc <= bitcounter_sc - 1; - spi_dir <= transaction_rw_mask_sc[bitcounter_sc-1]; - if (transaction_rw_mask_sc[bitcounter_sc-1]) begin - shift_out <= transaction_data_sc[bitcounter_sc-1]; - end else begin - shift_out <= 0; - end + spi_dir <= transaction_rw_mask_sc[bitcounter_sc-1]; + if (transaction_rw_mask_sc[bitcounter_sc-1]) begin + shift_out <= transaction_data_sc[bitcounter_sc-1]; + end else begin + shift_out <= 0; end end end else if (spi_state == DONE) begin shift_out <= 1'b0; + spi_clock_hot <= 1'b0; + spi_dir <= 1'b1; + spi_cs_n <= 1'b1; if (read_bitcounter_sc == 0) begin spi_state <= IDLE; to_fabric_fifo_wr_en <= 1'b0; From 4c74d46dcd2e47711fa1fbbf39580b7c082eb59d Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 4 Dec 2024 16:49:30 -0800 Subject: [PATCH 65/96] fixed some of the vcd file names --- HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp index 648220a2..4668d62c 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp +++ b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp @@ -265,7 +265,7 @@ int main(int argc, char **argv) tfp6->close(); top->trace(tfp7, 99); // Trace 99 levels of hierarchy - tfp7->open("sim_load_value_mode0_24_8rbit_mode0.vcd"); + tfp7->open("sim_load_value_24w_8rbit_mode0.vcd"); main_time = 0; // Reset time top->spi_cpol = 0; @@ -305,7 +305,7 @@ int main(int argc, char **argv) tfp7->close(); top->trace(tfp8, 99); // Trace 99 levels of hierarchy - tfp8->open("sim_load_value_mode0_24_8rbit_mode1.vcd"); + tfp8->open("sim_load_value_24w_8rbit_mode1.vcd"); main_time = 0; // Reset time top->spi_cpol = 0; @@ -344,7 +344,7 @@ int main(int argc, char **argv) tfp8->close(); top->trace(tfp9, 99); // Trace 99 levels of hierarchy - tfp9->open("sim_load_value_mode0_24_8rbit_mode2.vcd"); + tfp9->open("sim_load_value_24w_8rbit_mode2.vcd"); main_time = 0; // Reset time top->spi_cpol = 1; @@ -383,7 +383,7 @@ int main(int argc, char **argv) tfp9->close(); top->trace(tfp10, 99); // Trace 99 levels of hierarchy - tfp10->open("sim_load_value_mode0_24_8rbit_mode3.vcd"); + tfp10->open("sim_load_value_24w_8rbit_mode3.vcd"); main_time = 0; // Reset time top->spi_cpol = 1; From 4645f4009f9646c3561c94019c8d5522ff3a9359 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 4 Dec 2024 17:13:04 -0800 Subject: [PATCH 66/96] mode 0 read sampling added again --- HDL/projects/bidirectional_spi/bidirectional_spi.sv | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index 4a7f1fc5..015d29ca 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -259,6 +259,7 @@ module bidirectional_spi #( if (transaction_rw_mask_sc[bitcounter_sc-1]) begin shift_out <= transaction_data_sc[bitcounter_sc-1]; end else begin + read_bitcounter_sc <= read_bitcounter_sc + 1; shift_out <= 0; end bitcounter_sc <= bitcounter_sc - 1; @@ -275,9 +276,14 @@ module bidirectional_spi #( spi_dir <= transaction_rw_mask_sc[bitcounter_sc-1]; if (transaction_rw_mask_sc[bitcounter_sc-1]) begin shift_out <= transaction_data_sc[bitcounter_sc-1]; - end else begin - shift_out <= 0; end + end + if (~spi_dir) begin + // this is where the reading takes place + if (spi_clk && ~spi_cpha) begin + read_bitcounter_sc <= read_bitcounter_sc + 1; + shift_out <= 0; + end end end else if (spi_state == DONE) begin shift_out <= 1'b0; From 496839c4ba828df91ecb2eba512aa7ea3480d6da Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Wed, 4 Dec 2024 17:21:40 -0800 Subject: [PATCH 67/96] fixed testbench resets added a test for reading before writing mode0 --- .../bidirectional_spi_tb.cpp | 61 ++++++++++++++++--- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp index 4668d62c..41c9a679 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp +++ b/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp @@ -41,10 +41,11 @@ int main(int argc, char **argv) VerilatedVcdC *tfp8 = new VerilatedVcdC; VerilatedVcdC *tfp9 = new VerilatedVcdC; VerilatedVcdC *tfp10 = new VerilatedVcdC; + VerilatedVcdC *tfp11 = new VerilatedVcdC; top->trace(tfp, 99); // Trace 99 levels of hierarchy tfp->open("sim_reset_n_clock.vcd"); - + top->reset_n = 0; // Reset sequence while (main_time < 20) { @@ -70,7 +71,7 @@ int main(int argc, char **argv) top->trace(tfp2, 99); // Trace 99 levels of hierarchy tfp2->open("sim_load_value_mode0.vcd"); main_time = 0; // Reset time - + top->reset_n = 0; top->spi_cpol = 0; top->spi_cpha = 0; @@ -110,7 +111,7 @@ int main(int argc, char **argv) top->trace(tfp3, 99); // Trace 99 levels of hierarchy tfp3->open("sim_load_value_mode1.vcd"); main_time = 0; // Reset time - + top->reset_n = 0; top->spi_cpol = 0; top->spi_cpha = 1; // Reset sequence @@ -149,7 +150,7 @@ int main(int argc, char **argv) top->trace(tfp4, 99); // Trace 99 levels of hierarchy tfp4->open("sim_load_value_mode2.vcd"); main_time = 0; // Reset time - + top->reset_n = 0; top->spi_cpol = 1; top->spi_cpha = 0; @@ -189,7 +190,7 @@ int main(int argc, char **argv) top->trace(tfp5, 99); // Trace 99 levels of hierarchy tfp5->open("sim_load_value_mode3.vcd"); main_time = 0; // Reset time - + top->reset_n = 0; top->spi_cpol = 1; top->spi_cpha = 1; // Reset sequence @@ -228,7 +229,7 @@ int main(int argc, char **argv) top->trace(tfp6, 99); // Trace 99 levels of hierarchy tfp6->open("sim_load_value_mode0_32bit.vcd"); main_time = 0; // Reset time - + top->reset_n = 0; top->spi_cpol = 0; top->spi_cpha = 0; // Reset sequence @@ -267,7 +268,7 @@ int main(int argc, char **argv) top->trace(tfp7, 99); // Trace 99 levels of hierarchy tfp7->open("sim_load_value_24w_8rbit_mode0.vcd"); main_time = 0; // Reset time - + top->reset_n = 0; top->spi_cpol = 0; top->spi_cpha = 0; // Reset sequence @@ -307,7 +308,7 @@ int main(int argc, char **argv) top->trace(tfp8, 99); // Trace 99 levels of hierarchy tfp8->open("sim_load_value_24w_8rbit_mode1.vcd"); main_time = 0; // Reset time - + top->reset_n = 0; top->spi_cpol = 0; top->spi_cpha = 1; // Reset sequence @@ -346,7 +347,7 @@ int main(int argc, char **argv) top->trace(tfp9, 99); // Trace 99 levels of hierarchy tfp9->open("sim_load_value_24w_8rbit_mode2.vcd"); main_time = 0; // Reset time - + top->reset_n = 0; top->spi_cpol = 1; top->spi_cpha = 0; // Reset sequence @@ -385,7 +386,7 @@ int main(int argc, char **argv) top->trace(tfp10, 99); // Trace 99 levels of hierarchy tfp10->open("sim_load_value_24w_8rbit_mode3.vcd"); main_time = 0; // Reset time - + top->reset_n = 0; top->spi_cpol = 1; top->spi_cpha = 1; // Reset sequence @@ -421,6 +422,46 @@ int main(int argc, char **argv) // cleanup sim file tfp10->close(); + /* this test case is unrealistic, as reading before writing doesn't make any + sense in most practical scenarios, nevertheless it should work */ + top->trace(tfp11, 99); // Trace 99 levels of hierarchy + tfp11->open("sim_load_value_24r_8w_mode0.vcd"); + main_time = 0; // Reset time + top->reset_n = 0; + top->spi_cpol = 0; + top->spi_cpha = 0; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp11->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0x000000FF; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp11->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp11->close(); delete top; return 0; } From 31e66c2685f42c63baaf1c9176d8952e75f9e603 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 13:40:16 -0800 Subject: [PATCH 68/96] switch to shift registers --- .../bidirectional_spi/bidirectional_spi.sv | 79 ++++++++++++------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index 015d29ca..d913f132 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -33,25 +33,27 @@ module bidirectional_spi #( reg shift_out; // SPI Data to be shifted out localparam BIT_COUNT_WIDTH = $clog2(DATA_WIDTH); - + //localparam integer IMASK = (1 << $clog2(DATA_WIDTH)) - 1; // Some of our data in the spi_clk domain reg [TRANSACTION_LEN_WIDTH-1:0] r_transaction_length; reg [BIT_COUNT_WIDTH:0] bitcounter_sc, read_bitcounter_sc; - reg [DATA_WIDTH-1:0] transaction_rw_mask_sc, r_transaction_rw_mask; - reg [DATA_WIDTH-1:0] transaction_data_sc, r_transaction_data; + //reg [DATA_WIDTH-1:0] transaction_rw_mask_sc + reg [DATA_WIDTH-1:0] r_transaction_rw_mask; + //reg [DATA_WIDTH-1:0] transaction_data_sc, + reg [DATA_WIDTH-1:0] r_transaction_data; reg [TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:0] sc_data, fc_data; reg [DATA_WIDTH-1:0] transaction_read_data_sc; - + assign fc_data = {r_transaction_length, r_transaction_rw_mask, r_transaction_data}; assign spi_sdio = spi_dir ? shift_out : 1'bz; wire spi_clk, spi_clk_gen; reg to_spi_fifo_empty; - + // fabric side state machine states typedef enum logic [1:0] { F_IDLE, @@ -221,6 +223,8 @@ module bidirectional_spi #( assign intermediate_bitcounter = sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; /* verilator lint_on UNUSEDSIGNAL */ + reg [DATA_WIDTH-1:0] shiftout_register, rw_shift_register; + always_ff @(posedge spi_clk or negedge spi_clk or negedge reset_n_sc) begin if (~reset_n_sc) begin spi_dir <= 1'b1; @@ -247,44 +251,61 @@ module bidirectional_spi #( spi_state <= CS_ASSERT; to_spi_fifo_rd_en <= 1'b0; // deassert the read enable // copy the data from the fifo - bitcounter_sc <= intermediate_bitcounter; //[BIT_COUNT_WIDTH-1:0]; - transaction_rw_mask_sc <= sc_data[DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH]; - transaction_data_sc <= sc_data[DATA_WIDTH-1:0]; + bitcounter_sc <= intermediate_bitcounter; //[BIT_COUNT_WIDTH-1:0]; + shiftout_register <= sc_data[DATA_WIDTH-1:0]; + /* + if (DATA_WIDTH > 1) begin + rw_shift_register <= {sc_data[DATA_WIDTH+DATA_WIDTH-2:DATA_WIDTH], 1'b1}; + end else begin + rw_shift_register <= 1; + end + spi_dir <= sc_data[DATA_WIDTH+DATA_WIDTH-1]; + */ + rw_shift_register <= sc_data[DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH]; end else if (spi_state == CS_ASSERT) begin spi_state <= WRITE; spi_cs_n <= 1'b0; spi_clock_hot <= 1'b1; - if (~spi_cpol && ~spi_clk && ~spi_cpha) begin - spi_dir <= transaction_rw_mask_sc[bitcounter_sc-1]; - if (transaction_rw_mask_sc[bitcounter_sc-1]) begin - shift_out <= transaction_data_sc[bitcounter_sc-1]; - end else begin - read_bitcounter_sc <= read_bitcounter_sc + 1; - shift_out <= 0; - end + + // deal with the write case for Mode 0, I doubt there is a read case here + // at all directly after CS is asserted + if (~spi_cpol && ~spi_clk && ~spi_cpha && spi_dir) begin + spi_dir <= rw_shift_register[DATA_WIDTH-1]; + rw_shift_register <= {rw_shift_register[DATA_WIDTH-2:0], 1'b0}; + + shift_out <= shiftout_register[DATA_WIDTH-1]; + shiftout_register <= {shiftout_register[DATA_WIDTH-2:0],1'b0}; bitcounter_sc <= bitcounter_sc - 1; end + end else if (spi_state == WRITE) begin if (bitcounter_sc == 0) begin spi_state <= DONE; end else begin spi_state <= WRITE; end - if ((spi_clk && spi_cpha) || (~spi_clk && ~spi_cpha)) begin - bitcounter_sc <= bitcounter_sc - 1; - - spi_dir <= transaction_rw_mask_sc[bitcounter_sc-1]; - if (transaction_rw_mask_sc[bitcounter_sc-1]) begin - shift_out <= transaction_data_sc[bitcounter_sc-1]; + + // all valid transitions that advance the state machine + if ((spi_dir && ((spi_clk && spi_cpha) || (~spi_clk && ~spi_cpha))) || + (~spi_dir && spi_clk && ~spi_cpha)) begin + spi_dir <= rw_shift_register[DATA_WIDTH-1]; + rw_shift_register <= {rw_shift_register[DATA_WIDTH-2:0], 1'b0}; + if (spi_dir == rw_shift_register[DATA_WIDTH-1]) begin + // do not decrement when the direction changes + bitcounter_sc <= bitcounter_sc - 1; end - end - if (~spi_dir) begin - // this is where the reading takes place - if (spi_clk && ~spi_cpha) begin - read_bitcounter_sc <= read_bitcounter_sc + 1; - shift_out <= 0; - end end + + if (((spi_clk && spi_cpha) || (~spi_clk && ~spi_cpha)) && spi_dir) begin + shift_out <= shiftout_register[DATA_WIDTH-1]; + shiftout_register <= {shiftout_register[DATA_WIDTH-2:0],1'b0}; + + end else if (~spi_dir && spi_clk && ~spi_cpha) begin + // it is a read transaction, so increment the read counter + read_bitcounter_sc <= read_bitcounter_sc + 1; + end + + end else if (spi_state == DONE) begin shift_out <= 1'b0; spi_clock_hot <= 1'b0; From ccfdcd6a4080c75ebb1052c03ef1f3001e4e545c Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 15:15:23 -0800 Subject: [PATCH 69/96] added actually reading the data --- .../bidirectional_spi/bidirectional_spi.sv | 93 +++++----- .../bidirectional_spi/surfer_load_data_rw.ron | 161 ++++++++++-------- 2 files changed, 130 insertions(+), 124 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index d913f132..e827363f 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -174,6 +174,7 @@ module bidirectional_spi #( IDLE, FIFO_READ, CS_ASSERT, + READ, WRITE, DONE } state_t; @@ -183,47 +184,15 @@ module bidirectional_spi #( // combinatorial logic to assign the SPI clock assign spi_sclk = spi_clock_hot ? (spi_cpol ? ~spi_clk : spi_clk) : spi_cpol; - /* - // Synchronize the SPI clock enable signal - always_ff @(posedge spi_clk or negedge spi_clk or negedge reset_n_sc2) begin - if (~reset_n_sc2) begin - spi_clk_en <= 1'b0; - // delete the read data stuff - read_bitcounter_sc <= 0; - transaction_read_data_sc <= 0; - end else begin - // manage the clock enable signal only on rising edge - if (spi_clk) begin - if (spi_clock_hot) begin - spi_clk_en <= 1'b1; - end else begin - spi_clk_en <= 1'b0; - end - end - - // do the reads on either the rising or falling edge of the clock, depending - // on the SPI mode - if (spi_clock_hot && spi_dir == 0) begin - if ((spi_clk && ~spi_cpha) || (~spi_clk && spi_cpha)) begin - read_bitcounter_sc <= read_bitcounter_sc + 1; - //transaction_read_data_sc[bitcounter_sc] <= 1'b1; //spi_sdio; - end - end else if (spi_state == IDLE) begin - read_bitcounter_sc <= 0; - transaction_read_data_sc <= 0; - end - end - end - - */ - reg spi_clock_hot; /* verilator lint_off UNUSEDSIGNAL */ wire[BIT_COUNT_WIDTH:0] intermediate_bitcounter; assign intermediate_bitcounter = sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; /* verilator lint_on UNUSEDSIGNAL */ - reg [DATA_WIDTH-1:0] shiftout_register, rw_shift_register; + reg [DATA_WIDTH-1:0] shiftout_register, rw_shift_register, shiftin_register; + + assign transaction_read_data_sc = shiftin_register; always_ff @(posedge spi_clk or negedge spi_clk or negedge reset_n_sc) begin if (~reset_n_sc) begin @@ -234,8 +203,8 @@ module bidirectional_spi #( to_fabric_fifo_wr_en <= 1'b0; spi_state <= IDLE; spi_clock_hot <= 1'b0; - transaction_read_data_sc <= 0; read_bitcounter_sc <= 0; + shiftin_register <= 0; end else begin if (spi_state == IDLE) begin to_fabric_fifo_wr_en <= 1'b0; @@ -253,17 +222,13 @@ module bidirectional_spi #( // copy the data from the fifo bitcounter_sc <= intermediate_bitcounter; //[BIT_COUNT_WIDTH-1:0]; shiftout_register <= sc_data[DATA_WIDTH-1:0]; - /* - if (DATA_WIDTH > 1) begin - rw_shift_register <= {sc_data[DATA_WIDTH+DATA_WIDTH-2:DATA_WIDTH], 1'b1}; - end else begin - rw_shift_register <= 1; - end - spi_dir <= sc_data[DATA_WIDTH+DATA_WIDTH-1]; - */ rw_shift_register <= sc_data[DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH]; end else if (spi_state == CS_ASSERT) begin - spi_state <= WRITE; + if (rw_shift_register[DATA_WIDTH-1]) begin + spi_state <= WRITE; + end else begin + spi_state <= READ; + end spi_cs_n <= 1'b0; spi_clock_hot <= 1'b1; @@ -275,7 +240,10 @@ module bidirectional_spi #( shift_out <= shiftout_register[DATA_WIDTH-1]; shiftout_register <= {shiftout_register[DATA_WIDTH-2:0],1'b0}; - bitcounter_sc <= bitcounter_sc - 1; + shiftin_register <= {shiftin_register[DATA_WIDTH-2:0],1'b0}; + if (spi_dir == rw_shift_register[DATA_WIDTH-1]) begin + bitcounter_sc <= bitcounter_sc - 1; + end end end else if (spi_state == WRITE) begin @@ -286,26 +254,45 @@ module bidirectional_spi #( end // all valid transitions that advance the state machine - if ((spi_dir && ((spi_clk && spi_cpha) || (~spi_clk && ~spi_cpha))) || - (~spi_dir && spi_clk && ~spi_cpha)) begin + if ((spi_clk && spi_cpha) || (~spi_clk && ~spi_cpha)) begin spi_dir <= rw_shift_register[DATA_WIDTH-1]; rw_shift_register <= {rw_shift_register[DATA_WIDTH-2:0], 1'b0}; - if (spi_dir == rw_shift_register[DATA_WIDTH-1]) begin - // do not decrement when the direction changes + if (rw_shift_register[DATA_WIDTH-1]) begin + // only decrement when direction stays the same bitcounter_sc <= bitcounter_sc - 1; + end else begin + spi_state <= READ; end end if (((spi_clk && spi_cpha) || (~spi_clk && ~spi_cpha)) && spi_dir) begin shift_out <= shiftout_register[DATA_WIDTH-1]; shiftout_register <= {shiftout_register[DATA_WIDTH-2:0],1'b0}; - - end else if (~spi_dir && spi_clk && ~spi_cpha) begin + shiftin_register <= {shiftin_register[DATA_WIDTH-2:0],1'b0}; + end + + end else if (spi_state == READ) begin + if (bitcounter_sc == 0) begin + spi_state <= DONE; + end else begin + spi_state <= READ; + end + if (spi_clk && ~spi_cpha) begin + if (~rw_shift_register[DATA_WIDTH-1]) begin + spi_dir <= rw_shift_register[DATA_WIDTH-1]; + rw_shift_register <= {rw_shift_register[DATA_WIDTH-2:0], 1'b0}; + end else begin + spi_state <= WRITE; + end + end + + if (~spi_dir && spi_clk && ~spi_cpha) begin // it is a read transaction, so increment the read counter read_bitcounter_sc <= read_bitcounter_sc + 1; + shiftin_register <= {shiftin_register[DATA_WIDTH-2:0],1'b1}; + bitcounter_sc <= bitcounter_sc - 1; end - end else if (spi_state == DONE) begin shift_out <= 1'b0; spi_clock_hot <= 1'b0; diff --git a/HDL/projects/bidirectional_spi/surfer_load_data_rw.ron b/HDL/projects/bidirectional_spi/surfer_load_data_rw.ron index 5670c205..52d6ed4b 100644 --- a/HDL/projects/bidirectional_spi/surfer_load_data_rw.ron +++ b/HDL/projects/bidirectional_spi/surfer_load_data_rw.ron @@ -12,7 +12,7 @@ show_empty_scopes: None, show_parameters_in_scopes: None, waves: Some(( - source: File("sim_load_value_mode0_24_8rbit_mode0.vcd"), + source: File("sim_load_value_24r_8w_mode0.vcd"), format: Vcd, active_scope: Some(WaveScope(( strs: [ @@ -39,9 +39,10 @@ (16), (17), (18), + (19), ], displayed_items: { - (12): Variable(( + (9): Variable(( variable_ref: ( path: ( strs: [ @@ -49,52 +50,55 @@ "bidirectional_spi", ], ), - name: "spi_cs_n", + name: "spi_clk", ), - color: Some("red"), + color: Some("yellow"), background_color: None, - display_name: "spi_cs_n", + display_name: "spi_clk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (5): Variable(( + (6): Variable(( variable_ref: ( path: ( strs: [ "TOP", "bidirectional_spi", + "to_spi_fifo", + "mem", ], ), - name: "to_spi_fifo_wr_en", + name: "[0]", ), color: None, background_color: None, - display_name: "to_spi_fifo_wr_en", + display_name: "[0] [69:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (2): Variable(( + (7): Variable(( variable_ref: ( path: ( strs: [ "TOP", + "bidirectional_spi", ], ), - name: "fabric_clk", + name: "to_spi_fifo_empty", ), color: None, background_color: None, - display_name: "fabric_clk", + display_name: "to_spi_fifo_empty", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (9): Variable(( + (18): Variable(( variable_ref: ( path: ( strs: [ @@ -102,17 +106,17 @@ "bidirectional_spi", ], ), - name: "spi_clk", + name: "read_bitcounter_sc", ), - color: Some("yellow"), + color: Some("violet"), background_color: None, - display_name: "spi_clk", + display_name: "read_bitcounter_sc [5:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (18): Variable(( + (13): Variable(( variable_ref: ( path: ( strs: [ @@ -120,17 +124,17 @@ "bidirectional_spi", ], ), - name: "read_bitcounter_sc", + name: "spi_sdio", ), - color: Some("violet"), + color: Some("blue"), background_color: None, - display_name: "read_bitcounter_sc [7:0]", + display_name: "spi_sdio", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (15): Variable(( + (19): Variable(( variable_ref: ( path: ( strs: [ @@ -138,17 +142,17 @@ "bidirectional_spi", ], ), - name: "spi_dir", + name: "transaction_read_data_sc", ), color: None, background_color: None, - display_name: "spi_dir", + display_name: "transaction_read_data_sc [31:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (16): Variable(( + (5): Variable(( variable_ref: ( path: ( strs: [ @@ -156,71 +160,70 @@ "bidirectional_spi", ], ), - name: "spi_state", + name: "to_spi_fifo_wr_en", ), color: None, background_color: None, - display_name: "spi_state [2:0]", + display_name: "to_spi_fifo_wr_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (3): Variable(( + (2): Variable(( variable_ref: ( path: ( strs: [ "TOP", ], ), - name: "transaction_data", + name: "fabric_clk", ), color: None, background_color: None, - display_name: "transaction_data [31:0]", + display_name: "fabric_clk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (6): Variable(( + (14): Variable(( variable_ref: ( path: ( strs: [ "TOP", "bidirectional_spi", - "to_spi_fifo", - "mem", ], ), - name: "[0]", + name: "spi_sclk", ), - color: None, + color: Some("red"), background_color: None, - display_name: "[0] [71:0]", + display_name: "spi_sclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (1): Variable(( + (17): Variable(( variable_ref: ( path: ( strs: [ "TOP", + "bidirectional_spi", ], ), - name: "reset_n", + name: "bitcounter_sc", ), color: None, background_color: None, - display_name: "reset_n", + display_name: "bitcounter_sc [5:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Unsigned"), field_formats: [], )), - (10): Variable(( + (15): Variable(( variable_ref: ( path: ( strs: [ @@ -228,17 +231,17 @@ "bidirectional_spi", ], ), - name: "to_spi_fifo_rd_en", + name: "spi_dir", ), color: None, background_color: None, - display_name: "to_spi_fifo_rd_en", + display_name: "spi_dir", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (7): Variable(( + (12): Variable(( variable_ref: ( path: ( strs: [ @@ -246,35 +249,34 @@ "bidirectional_spi", ], ), - name: "to_spi_fifo_empty", + name: "spi_cs_n", ), - color: None, + color: Some("red"), background_color: None, - display_name: "to_spi_fifo_empty", + display_name: "spi_cs_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (14): Variable(( + (3): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", ], ), - name: "spi_sclk", + name: "transaction_data", ), - color: Some("red"), + color: None, background_color: None, - display_name: "spi_sclk", + display_name: "transaction_data [31:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (13): Variable(( + (10): Variable(( variable_ref: ( path: ( strs: [ @@ -282,35 +284,34 @@ "bidirectional_spi", ], ), - name: "spi_sdio", + name: "to_spi_fifo_rd_en", ), - color: Some("blue"), + color: None, background_color: None, - display_name: "spi_sdio", + display_name: "to_spi_fifo_rd_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (11): Variable(( + (1): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", ], ), - name: "transaction_data_sc", + name: "reset_n", ), color: None, background_color: None, - display_name: "transaction_data_sc [31:0]", + display_name: "reset_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (8): Variable(( + (11): Placeholder(( variable_ref: ( path: ( strs: [ @@ -318,11 +319,11 @@ "bidirectional_spi", ], ), - name: "spi_data_clk", + name: "transaction_data_sc", ), - color: Some("yellow"), + color: None, background_color: None, - display_name: "spi_data_clk", + display_name: "transaction_data_sc [31:0]", display_name_type: Unique, manual_name: None, format: None, @@ -339,13 +340,13 @@ ), color: None, background_color: None, - display_name: "transaction_length [7:0]", + display_name: "transaction_length [5:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (17): Variable(( + (16): Variable(( variable_ref: ( path: ( strs: [ @@ -353,22 +354,40 @@ "bidirectional_spi", ], ), - name: "bitcounter_sc", + name: "spi_state", ), color: None, background_color: None, - display_name: "bitcounter_sc [7:0]", + display_name: "spi_state [2:0]", display_name_type: Unique, manual_name: None, - format: Some("Unsigned"), + format: None, + field_formats: [], + )), + (8): Placeholder(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "spi_data_clk", + ), + color: Some("yellow"), + background_color: None, + display_name: "spi_data_clk", + display_name_type: Unique, + manual_name: None, + format: None, field_formats: [], )), }, - display_item_ref_counter: 18, + display_item_ref_counter: 20, viewports: [ ( - curr_left: (0.5484446044212009), - curr_right: (0.8239406535331145), + curr_left: (0.0005178343624356449), + curr_right: (0.551509932586263), target_left: (0.0), target_right: (1.0), move_start_left: (0.0), @@ -381,7 +400,7 @@ 450, ])), markers: {}, - focused_item: Some((17)), + focused_item: Some((18)), focused_transaction: (None, None), selected_items: [], default_variable_name_type: Unique, From 6c5824144f5c886dc6f0e68508ded19d7b23836a Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 15:23:11 -0800 Subject: [PATCH 70/96] support mode 1 for both write and read --- HDL/projects/bidirectional_spi/bidirectional_spi.sv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index e827363f..b9f23c58 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -277,7 +277,7 @@ module bidirectional_spi #( end else begin spi_state <= READ; end - if (spi_clk && ~spi_cpha) begin + if ((spi_clk && ~spi_cpha) || (~spi_clk && spi_cpha)) begin if (~rw_shift_register[DATA_WIDTH-1]) begin spi_dir <= rw_shift_register[DATA_WIDTH-1]; rw_shift_register <= {rw_shift_register[DATA_WIDTH-2:0], 1'b0}; @@ -286,7 +286,7 @@ module bidirectional_spi #( end end - if (~spi_dir && spi_clk && ~spi_cpha) begin + if ((spi_clk && ~spi_cpha) || (~spi_clk && spi_cpha)) begin // it is a read transaction, so increment the read counter read_bitcounter_sc <= read_bitcounter_sc + 1; shiftin_register <= {shiftin_register[DATA_WIDTH-2:0],1'b1}; From 74678ef5838e50a1257ef44a7cf2b232463a41e4 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 15:30:16 -0800 Subject: [PATCH 71/96] support mode 2 correctly for write on cs assert --- HDL/projects/bidirectional_spi/bidirectional_spi.sv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index b9f23c58..ede87313 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -232,9 +232,9 @@ module bidirectional_spi #( spi_cs_n <= 1'b0; spi_clock_hot <= 1'b1; - // deal with the write case for Mode 0, I doubt there is a read case here + // deal with the write case for Mode 0 & 2, I doubt there is a read case here // at all directly after CS is asserted - if (~spi_cpol && ~spi_clk && ~spi_cpha && spi_dir) begin + if (~spi_clk && ~spi_cpha && spi_dir) begin spi_dir <= rw_shift_register[DATA_WIDTH-1]; rw_shift_register <= {rw_shift_register[DATA_WIDTH-2:0], 1'b0}; From 7ee69cfc223decb026df5e4fa9618df8586a05a5 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 15:39:51 -0800 Subject: [PATCH 72/96] simplified code a tad --- HDL/projects/bidirectional_spi/bidirectional_spi.sv | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index ede87313..50313daf 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -185,11 +185,6 @@ module bidirectional_spi #( assign spi_sclk = spi_clock_hot ? (spi_cpol ? ~spi_clk : spi_clk) : spi_cpol; reg spi_clock_hot; - /* verilator lint_off UNUSEDSIGNAL */ - wire[BIT_COUNT_WIDTH:0] intermediate_bitcounter; - assign intermediate_bitcounter = sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; - /* verilator lint_on UNUSEDSIGNAL */ - reg [DATA_WIDTH-1:0] shiftout_register, rw_shift_register, shiftin_register; assign transaction_read_data_sc = shiftin_register; @@ -220,7 +215,7 @@ module bidirectional_spi #( spi_state <= CS_ASSERT; to_spi_fifo_rd_en <= 1'b0; // deassert the read enable // copy the data from the fifo - bitcounter_sc <= intermediate_bitcounter; //[BIT_COUNT_WIDTH-1:0]; + bitcounter_sc <= sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; shiftout_register <= sc_data[DATA_WIDTH-1:0]; rw_shift_register <= sc_data[DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH]; end else if (spi_state == CS_ASSERT) begin From f285530b0cc7c715d6953805c68195cdcb346917 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 16:48:16 -0800 Subject: [PATCH 73/96] implement reading from the to_fabric fifo --- .../bidirectional_spi/bidirectional_spi.sv | 38 ++-- .../bidirectional_spi/surfer_load_data_rw.ron | 194 ++++++++++++------ 2 files changed, 160 insertions(+), 72 deletions(-) diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/bidirectional_spi/bidirectional_spi.sv index 50313daf..7083c287 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/bidirectional_spi/bidirectional_spi.sv @@ -42,6 +42,7 @@ module bidirectional_spi #( reg [DATA_WIDTH-1:0] r_transaction_rw_mask; //reg [DATA_WIDTH-1:0] transaction_data_sc, reg [DATA_WIDTH-1:0] r_transaction_data; + reg [DATA_WIDTH-1:0] r_transaction_read_data, f_transaction_read_data; reg [TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:0] sc_data, fc_data; @@ -50,6 +51,9 @@ module bidirectional_spi #( assign fc_data = {r_transaction_length, r_transaction_rw_mask, r_transaction_data}; assign spi_sdio = spi_dir ? shift_out : 1'bz; + + assign transaction_read_data = r_transaction_read_data; + wire spi_clk, spi_clk_gen; reg to_spi_fifo_empty; @@ -97,7 +101,7 @@ module bidirectional_spi #( to_fabric_fifo_rd_en <= 1'b0; fabric_state <= F_IDLE; // should also copy the data from the FIFO - + r_transaction_read_data <= f_transaction_read_data; end end @@ -159,7 +163,7 @@ module bidirectional_spi #( .wr_en(to_fabric_fifo_wr_en), .rd_clk(fabric_clk), .rd_rst_n(reset_n), - .rd_data(transaction_read_data), + .rd_data(f_transaction_read_data), .rd_en(to_fabric_fifo_rd_en), .full(to_fabric_fifo_full), .empty(to_fabric_fifo_empty), @@ -176,7 +180,8 @@ module bidirectional_spi #( CS_ASSERT, READ, WRITE, - DONE + DONE, + FIFO_WRITE } state_t; state_t spi_state; @@ -205,6 +210,8 @@ module bidirectional_spi #( to_fabric_fifo_wr_en <= 1'b0; shift_out <= 1'b0; spi_cs_n <= 1'b1; + read_bitcounter_sc <= 0; + shiftin_register <= 0; if(~to_spi_fifo_empty) begin spi_state <= FIFO_READ; to_spi_fifo_rd_en <= 1'b1; // assert the read enable @@ -289,18 +296,23 @@ module bidirectional_spi #( end end else if (spi_state == DONE) begin - shift_out <= 1'b0; - spi_clock_hot <= 1'b0; - spi_dir <= 1'b1; - spi_cs_n <= 1'b1; - if (read_bitcounter_sc == 0) begin + if (spi_clk) begin + shift_out <= 1'b0; + spi_clock_hot <= 1'b0; + spi_dir <= 1'b1; + spi_cs_n <= 1'b1; + if (read_bitcounter_sc == 0 || to_fabric_fifo_full) begin + spi_state <= IDLE; + to_fabric_fifo_wr_en <= 1'b0; + end else begin + spi_state <= FIFO_WRITE; + to_fabric_fifo_wr_en <= 1'b1; + end + end + end else if (spi_state == FIFO_WRITE) begin + if (spi_clk) begin spi_state <= IDLE; to_fabric_fifo_wr_en <= 1'b0; - end else if (~to_fabric_fifo_full) begin - spi_state <= IDLE; - to_fabric_fifo_wr_en <= 1'b1; - end else begin - spi_state <= DONE; end end end diff --git a/HDL/projects/bidirectional_spi/surfer_load_data_rw.ron b/HDL/projects/bidirectional_spi/surfer_load_data_rw.ron index 52d6ed4b..442ab93e 100644 --- a/HDL/projects/bidirectional_spi/surfer_load_data_rw.ron +++ b/HDL/projects/bidirectional_spi/surfer_load_data_rw.ron @@ -12,7 +12,7 @@ show_empty_scopes: None, show_parameters_in_scopes: None, waves: Some(( - source: File("sim_load_value_24r_8w_mode0.vcd"), + source: File("sim_load_value_24w_8rbit_mode0.vcd"), format: Vcd, active_scope: Some(WaveScope(( strs: [ @@ -40,9 +40,13 @@ (17), (18), (19), + (20), + (21), + (22), + (23), ], displayed_items: { - (9): Variable(( + (12): Variable(( variable_ref: ( path: ( strs: [ @@ -50,37 +54,52 @@ "bidirectional_spi", ], ), - name: "spi_clk", + name: "spi_cs_n", ), - color: Some("yellow"), + color: Some("red"), background_color: None, - display_name: "spi_clk", + display_name: "spi_cs_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (6): Variable(( + (18): Variable(( variable_ref: ( path: ( strs: [ "TOP", "bidirectional_spi", - "to_spi_fifo", - "mem", ], ), - name: "[0]", + name: "read_bitcounter_sc", + ), + color: Some("violet"), + background_color: None, + display_name: "read_bitcounter_sc [5:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (2): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + ], + ), + name: "fabric_clk", ), color: None, background_color: None, - display_name: "[0] [69:0]", + display_name: "fabric_clk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (7): Variable(( + (5): Variable(( variable_ref: ( path: ( strs: [ @@ -88,17 +107,17 @@ "bidirectional_spi", ], ), - name: "to_spi_fifo_empty", + name: "to_spi_fifo_wr_en", ), color: None, background_color: None, - display_name: "to_spi_fifo_empty", + display_name: "to_spi_fifo_wr_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (18): Variable(( + (10): Variable(( variable_ref: ( path: ( strs: [ @@ -106,11 +125,11 @@ "bidirectional_spi", ], ), - name: "read_bitcounter_sc", + name: "to_spi_fifo_rd_en", ), - color: Some("violet"), + color: None, background_color: None, - display_name: "read_bitcounter_sc [5:0]", + display_name: "to_spi_fifo_rd_en", display_name_type: Unique, manual_name: None, format: None, @@ -134,7 +153,7 @@ format: None, field_formats: [], )), - (19): Variable(( + (15): Variable(( variable_ref: ( path: ( strs: [ @@ -142,52 +161,51 @@ "bidirectional_spi", ], ), - name: "transaction_read_data_sc", + name: "spi_dir", ), color: None, background_color: None, - display_name: "transaction_read_data_sc [31:0]", + display_name: "spi_dir", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (5): Variable(( + (3): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", ], ), - name: "to_spi_fifo_wr_en", + name: "transaction_data", ), color: None, background_color: None, - display_name: "to_spi_fifo_wr_en", + display_name: "transaction_data [31:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (2): Variable(( + (1): Variable(( variable_ref: ( path: ( strs: [ "TOP", ], ), - name: "fabric_clk", + name: "reset_n", ), color: None, background_color: None, - display_name: "fabric_clk", + display_name: "reset_n", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (14): Variable(( + (7): Variable(( variable_ref: ( path: ( strs: [ @@ -195,11 +213,11 @@ "bidirectional_spi", ], ), - name: "spi_sclk", + name: "to_spi_fifo_empty", ), - color: Some("red"), + color: None, background_color: None, - display_name: "spi_sclk", + display_name: "to_spi_fifo_empty", display_name_type: Unique, manual_name: None, format: None, @@ -223,7 +241,7 @@ format: Some("Unsigned"), field_formats: [], )), - (15): Variable(( + (16): Variable(( variable_ref: ( path: ( strs: [ @@ -231,17 +249,17 @@ "bidirectional_spi", ], ), - name: "spi_dir", + name: "spi_state", ), color: None, background_color: None, - display_name: "spi_dir", + display_name: "spi_state [2:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (12): Variable(( + (14): Variable(( variable_ref: ( path: ( strs: [ @@ -249,34 +267,35 @@ "bidirectional_spi", ], ), - name: "spi_cs_n", + name: "spi_sclk", ), color: Some("red"), background_color: None, - display_name: "spi_cs_n", + display_name: "spi_sclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (3): Variable(( + (20): Variable(( variable_ref: ( path: ( strs: [ "TOP", + "bidirectional_spi", ], ), - name: "transaction_data", + name: "to_fabric_fifo_wr_en", ), color: None, background_color: None, - display_name: "transaction_data [31:0]", + display_name: "to_fabric_fifo_wr_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (10): Variable(( + (11): Placeholder(( variable_ref: ( path: ( strs: [ @@ -284,34 +303,35 @@ "bidirectional_spi", ], ), - name: "to_spi_fifo_rd_en", + name: "transaction_data_sc", ), color: None, background_color: None, - display_name: "to_spi_fifo_rd_en", + display_name: "transaction_data_sc [31:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (1): Variable(( + (21): Variable(( variable_ref: ( path: ( strs: [ "TOP", + "bidirectional_spi", ], ), - name: "reset_n", + name: "to_fabric_fifo_empty", ), color: None, background_color: None, - display_name: "reset_n", + display_name: "to_fabric_fifo_empty", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (11): Placeholder(( + (9): Variable(( variable_ref: ( path: ( strs: [ @@ -319,46 +339,67 @@ "bidirectional_spi", ], ), - name: "transaction_data_sc", + name: "spi_clk", + ), + color: Some("yellow"), + background_color: None, + display_name: "spi_clk", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (22): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "to_fabric_fifo_rd_en", ), color: None, background_color: None, - display_name: "transaction_data_sc [31:0]", + display_name: "to_fabric_fifo_rd_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (4): Variable(( + (23): Variable(( variable_ref: ( path: ( strs: [ "TOP", + "bidirectional_spi", ], ), - name: "transaction_length", + name: "transaction_read_data", ), color: None, background_color: None, - display_name: "transaction_length [5:0]", + display_name: "transaction_read_data [31:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (16): Variable(( + (6): Variable(( variable_ref: ( path: ( strs: [ "TOP", "bidirectional_spi", + "to_spi_fifo", + "mem", ], ), - name: "spi_state", + name: "[0]", ), color: None, background_color: None, - display_name: "spi_state [2:0]", + display_name: "[0] [69:0]", display_name_type: Unique, manual_name: None, format: None, @@ -382,12 +423,47 @@ format: None, field_formats: [], )), + (19): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + "bidirectional_spi", + ], + ), + name: "transaction_read_data_sc", + ), + color: None, + background_color: None, + display_name: "transaction_read_data_sc [31:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), + (4): Variable(( + variable_ref: ( + path: ( + strs: [ + "TOP", + ], + ), + name: "transaction_length", + ), + color: None, + background_color: None, + display_name: "transaction_length [5:0]", + display_name_type: Unique, + manual_name: None, + format: None, + field_formats: [], + )), }, - display_item_ref_counter: 20, + display_item_ref_counter: 23, viewports: [ ( - curr_left: (0.0005178343624356449), - curr_right: (0.551509932586263), + curr_left: (0.5438265502617963), + curr_right: (1.0948186484856248), target_left: (0.0), target_right: (1.0), move_start_left: (0.0), @@ -400,7 +476,7 @@ 450, ])), markers: {}, - focused_item: Some((18)), + focused_item: Some((22)), focused_transaction: (None, None), selected_items: [], default_variable_name_type: Unique, From d364ec0ec930fda0d6daae8c6ab2c819d0702983 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 17:45:22 -0800 Subject: [PATCH 74/96] renamed the module --- .../Makefile | 6 +++--- .../TODO.md | 0 .../half_duplex_spi_master.sv} | 14 ++++++-------- .../half_duplex_spi_master_tb.cpp} | 4 ++-- .../surfer_load_data.ron | 0 .../surfer_load_data_rw.ron | 0 .../surfer_state.ron | 0 7 files changed, 11 insertions(+), 13 deletions(-) rename HDL/projects/{bidirectional_spi => half_duplex_spi_master}/Makefile (65%) rename HDL/projects/{bidirectional_spi => half_duplex_spi_master}/TODO.md (100%) rename HDL/projects/{bidirectional_spi/bidirectional_spi.sv => half_duplex_spi_master/half_duplex_spi_master.sv} (95%) rename HDL/projects/{bidirectional_spi/bidirectional_spi_tb.cpp => half_duplex_spi_master/half_duplex_spi_master_tb.cpp} (99%) rename HDL/projects/{bidirectional_spi => half_duplex_spi_master}/surfer_load_data.ron (100%) rename HDL/projects/{bidirectional_spi => half_duplex_spi_master}/surfer_load_data_rw.ron (100%) rename HDL/projects/{bidirectional_spi => half_duplex_spi_master}/surfer_state.ron (100%) diff --git a/HDL/projects/bidirectional_spi/Makefile b/HDL/projects/half_duplex_spi_master/Makefile similarity index 65% rename from HDL/projects/bidirectional_spi/Makefile rename to HDL/projects/half_duplex_spi_master/Makefile index 8ae185cb..17c061ab 100644 --- a/HDL/projects/bidirectional_spi/Makefile +++ b/HDL/projects/half_duplex_spi_master/Makefile @@ -1,9 +1,9 @@ VERILATOR = verilator -TOP_MODULE = bidirectional_spi +TOP_MODULE = half_duplex_spi_master VERILATED = obj_dir/V$(TOP_MODULE) -SRC_FILES = bidirectional_spi.sv ../async_fifo/async_fifo.sv ../spi_clock_generator/spi_clock_generator.sv ../reset_synchronizer/reset_synchronizer.sv ../quadrature_clock_divider/quadrature_clock_divider.sv -CPP_FILES = bidirectional_spi_tb.cpp +SRC_FILES = half_duplex_spi_master.sv ../async_fifo/async_fifo.sv ../reset_synchronizer/reset_synchronizer.sv ../quadrature_clock_divider/quadrature_clock_divider.sv +CPP_FILES = half_duplex_spi_master_tb.cpp all: sim diff --git a/HDL/projects/bidirectional_spi/TODO.md b/HDL/projects/half_duplex_spi_master/TODO.md similarity index 100% rename from HDL/projects/bidirectional_spi/TODO.md rename to HDL/projects/half_duplex_spi_master/TODO.md diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi.sv b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv similarity index 95% rename from HDL/projects/bidirectional_spi/bidirectional_spi.sv rename to HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv index 7083c287..915ed67a 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi.sv +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv @@ -1,14 +1,12 @@ -// bidirectional_spi module -// This module implements a bidirectional SPI interface with the following features: +// half_duplex_spi_master module +// This module implements a half-duplex (bidirectional) SPI master interface with the following features: // - uses a mask to determine which bits are written or read // - supports all four SPI modes (CPOL=0, CPHA=0; CPOL=0, CPHA=1; CPOL=1, CPHA=0; CPOL=1, CPHA=1) // - supports configurable data width -// - supports input of an arbitary quadrature clock for SPI clocking +// - supports input of an arbitary spi clock // - raise an error flag if invalid parameters are used -// Bidirectional SPI is an interface where the data can be written and read using a single wire. -// this is also known as half-duplex SPI. -// this core can be adapted to full-duplex SPI by adding a second data wire. -module bidirectional_spi #( +// Half-duplex SPI is an interface where the data can be written and read using a single wire. +module half_duplex_spi_master #( parameter DATA_WIDTH = 32, parameter TRANSACTION_LEN_WIDTH = 6 )( @@ -33,7 +31,7 @@ module bidirectional_spi #( reg shift_out; // SPI Data to be shifted out localparam BIT_COUNT_WIDTH = $clog2(DATA_WIDTH); - //localparam integer IMASK = (1 << $clog2(DATA_WIDTH)) - 1; + // Some of our data in the spi_clk domain reg [TRANSACTION_LEN_WIDTH-1:0] r_transaction_length; reg [BIT_COUNT_WIDTH:0] bitcounter_sc, read_bitcounter_sc; diff --git a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp similarity index 99% rename from HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp rename to HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp index 41c9a679..9df6fa68 100644 --- a/HDL/projects/bidirectional_spi/bidirectional_spi_tb.cpp +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp @@ -1,5 +1,5 @@ // main.cpp -#include "Vbidirectional_spi.h" +#include "Vhalf_duplex_spi_master.h" #include "verilated.h" #include "verilated_vcd_c.h" #include @@ -10,7 +10,7 @@ int main(int argc, char **argv) Verilated::commandArgs(argc, argv); // Instantiate the top module - Vbidirectional_spi *top = new Vbidirectional_spi; + Vhalf_duplex_spi_master *top = new Vhalf_duplex_spi_master; // Initialize simulation inputs top->transaction_length = 0; diff --git a/HDL/projects/bidirectional_spi/surfer_load_data.ron b/HDL/projects/half_duplex_spi_master/surfer_load_data.ron similarity index 100% rename from HDL/projects/bidirectional_spi/surfer_load_data.ron rename to HDL/projects/half_duplex_spi_master/surfer_load_data.ron diff --git a/HDL/projects/bidirectional_spi/surfer_load_data_rw.ron b/HDL/projects/half_duplex_spi_master/surfer_load_data_rw.ron similarity index 100% rename from HDL/projects/bidirectional_spi/surfer_load_data_rw.ron rename to HDL/projects/half_duplex_spi_master/surfer_load_data_rw.ron diff --git a/HDL/projects/bidirectional_spi/surfer_state.ron b/HDL/projects/half_duplex_spi_master/surfer_state.ron similarity index 100% rename from HDL/projects/bidirectional_spi/surfer_state.ron rename to HDL/projects/half_duplex_spi_master/surfer_state.ron From 21740660445828da65875d0b1947f63f5e4633b7 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 19:24:37 -0800 Subject: [PATCH 75/96] fixed a bug in Makefile updated TODO --- HDL/projects/half_duplex_spi_master/Makefile | 10 +++++----- HDL/projects/half_duplex_spi_master/TODO.md | 9 +++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/HDL/projects/half_duplex_spi_master/Makefile b/HDL/projects/half_duplex_spi_master/Makefile index 17c061ab..6bcf7243 100644 --- a/HDL/projects/half_duplex_spi_master/Makefile +++ b/HDL/projects/half_duplex_spi_master/Makefile @@ -17,10 +17,10 @@ $(VERILATED): $(SRC_FILES) $(CPP_FILES) clean: rm -rf obj_dir rm -f sim.vcd - rm -r sim_reset_n_clock.vcd - rm -r sim_load_value_mode0.vcd - rm -r sim_load_value_mode1.vcd - rm -r sim_load_value_mode2.vcd - rm -r sim_load_value_mode3.vcd + rm -f sim_reset_n_clock.vcd + rm -f sim_load_value_mode0.vcd + rm -f sim_load_value_mode1.vcd + rm -f sim_load_value_mode2.vcd + rm -f sim_load_value_mode3.vcd .PHONY: all sim clean diff --git a/HDL/projects/half_duplex_spi_master/TODO.md b/HDL/projects/half_duplex_spi_master/TODO.md index 294c090d..05fd19ac 100644 --- a/HDL/projects/half_duplex_spi_master/TODO.md +++ b/HDL/projects/half_duplex_spi_master/TODO.md @@ -1,7 +1,8 @@ Important issues remaining on this core -- [ ] Reading doesn't shift into correct bits (off by one) (not done) -- [ ] To fabric FIFO transfer does not finnish due to possible reset (not done) +- [x] Reading doesn't shift into correct bits (off by one) (done) +- [x] To fabric FIFO transfer does not finnish due to possible reset (done) - [ ] Asserts in testbench (not done) - [ ] inout doesn't work in test bench (not done) -- [ ] correct bitlengths for transaction length and bitcounters (not done) -- [ ] remove dual clock approach and replace with simple single clock \ No newline at end of file +- [x] correct bitlengths for transaction length and bitcounters (done) +- [x] remove dual clock approach and replace with simple single clock (done) +- [ ] make a separate module for the verilator tests (not done) \ No newline at end of file From d46fc7bc8879491f897894b5aa3b7fa6f599f5b6 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 19:56:15 -0800 Subject: [PATCH 76/96] Made an additional top-level module with built-in clock divider --- HDL/projects/half_duplex_spi_master/Makefile | 4 +- HDL/projects/half_duplex_spi_master/TODO.md | 3 +- .../half_duplex_spi_master.sv | 18 +- .../half_duplex_spi_master_clkdiv.sv | 56 +++ .../half_duplex_spi_master_tb.cpp | 4 +- .../surfer_load_data.ron | 396 ------------------ .../surfer_load_data_rw.ron | 254 +++++------ .../half_duplex_spi_master/surfer_state.ron | 147 ------- 8 files changed, 165 insertions(+), 717 deletions(-) create mode 100644 HDL/projects/half_duplex_spi_master/half_duplex_spi_master_clkdiv.sv delete mode 100644 HDL/projects/half_duplex_spi_master/surfer_load_data.ron delete mode 100644 HDL/projects/half_duplex_spi_master/surfer_state.ron diff --git a/HDL/projects/half_duplex_spi_master/Makefile b/HDL/projects/half_duplex_spi_master/Makefile index 6bcf7243..725505a2 100644 --- a/HDL/projects/half_duplex_spi_master/Makefile +++ b/HDL/projects/half_duplex_spi_master/Makefile @@ -1,8 +1,8 @@ VERILATOR = verilator -TOP_MODULE = half_duplex_spi_master +TOP_MODULE = half_duplex_spi_master_clkdiv VERILATED = obj_dir/V$(TOP_MODULE) -SRC_FILES = half_duplex_spi_master.sv ../async_fifo/async_fifo.sv ../reset_synchronizer/reset_synchronizer.sv ../quadrature_clock_divider/quadrature_clock_divider.sv +SRC_FILES = half_duplex_spi_master_clkdiv.sv half_duplex_spi_master.sv ../async_fifo/async_fifo.sv ../reset_synchronizer/reset_synchronizer.sv ../quadrature_clock_divider/quadrature_clock_divider.sv CPP_FILES = half_duplex_spi_master_tb.cpp all: sim diff --git a/HDL/projects/half_duplex_spi_master/TODO.md b/HDL/projects/half_duplex_spi_master/TODO.md index 05fd19ac..f445142e 100644 --- a/HDL/projects/half_duplex_spi_master/TODO.md +++ b/HDL/projects/half_duplex_spi_master/TODO.md @@ -5,4 +5,5 @@ Important issues remaining on this core - [ ] inout doesn't work in test bench (not done) - [x] correct bitlengths for transaction length and bitcounters (done) - [x] remove dual clock approach and replace with simple single clock (done) -- [ ] make a separate module for the verilator tests (not done) \ No newline at end of file +- [x] make a separate module for the verilator tests (done) +- [ ] check all the reset conditions (not done) \ No newline at end of file diff --git a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv index 915ed67a..b2501546 100644 --- a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv @@ -17,11 +17,13 @@ module half_duplex_spi_master #( input wire reset_n, input wire fabric_clk, + input wire spi_clk_in, // SPI Mode control input wire spi_cpol, // Clock polarity input wire spi_cpha, // Clock phase + // The 3-wire output inout wire spi_sdio, output reg spi_sclk, output reg spi_cs_n @@ -52,7 +54,7 @@ module half_duplex_spi_master #( assign transaction_read_data = r_transaction_read_data; - wire spi_clk, spi_clk_gen; + wire spi_clk; reg to_spi_fifo_empty; @@ -103,17 +105,6 @@ module half_duplex_spi_master #( end end - // Generate the clocks - quadrature_clock_divider clock_div ( - .reset_n(reset_n), - .clk_in(fabric_clk), - .div_factor_4(2), - .sck_0(spi_clk_gen), - /* verilator lint_off PINCONNECTEMPTY */ - .sck_90() - /* verilator lint_on PINCONNECTEMPTY */ - ); - // Reset synchronizer wire reset_n_sc; @@ -124,7 +115,7 @@ module half_duplex_spi_master #( ); // I know this is super hacky, but it allows the logic below to look cleaner - assign spi_clk = spi_cpol ? ~spi_clk_gen : spi_clk_gen; + assign spi_clk = spi_cpol ? ~spi_clk_in : spi_clk_in; reg to_spi_fifo_rd_en, to_spi_fifo_wr_en; // Instantiate the asynchronous FIFO for the data going to the SPI side @@ -317,4 +308,3 @@ module half_duplex_spi_master #( end endmodule - diff --git a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_clkdiv.sv b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_clkdiv.sv new file mode 100644 index 00000000..e486e036 --- /dev/null +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_clkdiv.sv @@ -0,0 +1,56 @@ +/* a top level module with built-in clock divider */ +module half_duplex_spi_master_clkdiv #( + parameter DATA_WIDTH = 32, + parameter TRANSACTION_LEN_WIDTH = 6, + parameter CLOCK_DIVIDER = 2 +)( + input wire [TRANSACTION_LEN_WIDTH-1:0] transaction_length, + input wire [DATA_WIDTH-1:0] transaction_data, + input wire [DATA_WIDTH-1:0] transaction_rw_mask, + output reg [DATA_WIDTH-1:0] transaction_read_data, + + input wire reset_n, + input wire fabric_clk, + + // SPI Mode control + input wire spi_cpol, // Clock polarity + input wire spi_cpha, // Clock phase + + inout wire spi_sdio, + output reg spi_sclk, + output reg spi_cs_n +); + +wire spi_clk_gen; + +// Generate the clocks +quadrature_clock_divider clock_div ( + .reset_n(reset_n), + .clk_in(fabric_clk), + .div_factor_4(CLOCK_DIVIDER), + .sck_0(spi_clk_gen), + /* verilator lint_off PINCONNECTEMPTY */ + .sck_90() + /* verilator lint_on PINCONNECTEMPTY */ + ); + +// Instantiate the spi_master core +half_duplex_spi_master #( + .DATA_WIDTH(DATA_WIDTH), .TRANSACTION_LEN_WIDTH(TRANSACTION_LEN_WIDTH) +) hdsm ( + .transaction_length(transaction_length), + .transaction_data(transaction_data), + .transaction_rw_mask(transaction_rw_mask), + .transaction_read_data(transaction_read_data), + .reset_n(reset_n), + .fabric_clk(fabric_clk), + .spi_clk_in(spi_clk_gen), + .spi_cpol(spi_cpol), + .spi_cpha(spi_cpha), + + .spi_sdio(spi_sdio), + .spi_sclk(spi_sclk), + .spi_cs_n(spi_cs_n) +); + +endmodule diff --git a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp index 9df6fa68..42f5cb23 100644 --- a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp @@ -1,5 +1,5 @@ // main.cpp -#include "Vhalf_duplex_spi_master.h" +#include "Vhalf_duplex_spi_master_clkdiv.h" #include "verilated.h" #include "verilated_vcd_c.h" #include @@ -10,7 +10,7 @@ int main(int argc, char **argv) Verilated::commandArgs(argc, argv); // Instantiate the top module - Vhalf_duplex_spi_master *top = new Vhalf_duplex_spi_master; + Vhalf_duplex_spi_master_clkdiv *top = new Vhalf_duplex_spi_master_clkdiv; // Initialize simulation inputs top->transaction_length = 0; diff --git a/HDL/projects/half_duplex_spi_master/surfer_load_data.ron b/HDL/projects/half_duplex_spi_master/surfer_load_data.ron deleted file mode 100644 index cb3b488e..00000000 --- a/HDL/projects/half_duplex_spi_master/surfer_load_data.ron +++ /dev/null @@ -1,396 +0,0 @@ -( - show_hierarchy: None, - show_menu: None, - show_ticks: None, - show_toolbar: None, - show_tooltip: None, - show_overview: None, - show_statusbar: None, - align_names_right: None, - show_variable_indices: None, - show_variable_direction: None, - show_empty_scopes: None, - show_parameters_in_scopes: None, - waves: Some(( - source: File("sim_load_value.vcd"), - format: Vcd, - active_scope: Some(WaveScope(( - strs: [ - "TOP", - "bidirectional_spi", - ], - ))), - displayed_items_order: [ - (1), - (2), - (3), - (4), - (5), - (6), - (7), - (8), - (9), - (10), - (11), - (12), - (14), - (13), - (15), - (16), - (17), - ], - displayed_items: { - (16): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "spi_state", - ), - color: None, - background_color: None, - display_name: "spi_state [2:0]", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (4): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - ], - ), - name: "transaction_length", - ), - color: None, - background_color: None, - display_name: "transaction_length [7:0]", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (7): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "to_spi_fifo_empty", - ), - color: None, - background_color: None, - display_name: "to_spi_fifo_empty", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (12): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "spi_cs_n", - ), - color: Some("red"), - background_color: None, - display_name: "spi_cs_n", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (17): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "bitcounter_sc", - ), - color: None, - background_color: None, - display_name: "bitcounter_sc [7:0]", - display_name_type: Unique, - manual_name: None, - format: Some("Unsigned"), - field_formats: [], - )), - (5): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "to_spi_fifo_wr_en", - ), - color: None, - background_color: None, - display_name: "to_spi_fifo_wr_en", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (1): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - ], - ), - name: "reset_n", - ), - color: None, - background_color: None, - display_name: "reset_n", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (14): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "spi_sclk", - ), - color: Some("red"), - background_color: None, - display_name: "spi_sclk", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (8): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "spi_data_clk", - ), - color: Some("yellow"), - background_color: None, - display_name: "spi_data_clk", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (9): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "spi_clk", - ), - color: Some("yellow"), - background_color: None, - display_name: "spi_clk", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (6): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - "to_spi_fifo", - "mem", - ], - ), - name: "[0]", - ), - color: None, - background_color: None, - display_name: "[0] [71:0]", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (2): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - ], - ), - name: "fabric_clk", - ), - color: None, - background_color: None, - display_name: "fabric_clk", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (10): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "to_spi_fifo_rd_en", - ), - color: None, - background_color: None, - display_name: "to_spi_fifo_rd_en", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (15): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "spi_dir", - ), - color: None, - background_color: None, - display_name: "spi_dir", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (11): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "transaction_data_sc", - ), - color: None, - background_color: None, - display_name: "transaction_data_sc [31:0]", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (13): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "spi_sdio", - ), - color: Some("blue"), - background_color: None, - display_name: "spi_sdio", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (3): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - ], - ), - name: "transaction_data", - ), - color: None, - background_color: None, - display_name: "transaction_data [31:0]", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - }, - display_item_ref_counter: 17, - viewports: [ - ( - curr_left: (-0.14871098911518355), - curr_right: (0.8662955966984591), - target_left: (0.0), - target_right: (1.0), - move_start_left: (0.0), - move_start_right: (1.0), - move_duration: None, - move_strategy: Instant, - ), - ], - cursor: Some((1, [ - 450, - ])), - markers: {}, - focused_item: Some((16)), - focused_transaction: (None, None), - selected_items: [], - default_variable_name_type: Unique, - scroll_offset: 0.0, - display_variable_indices: true, - graphics: {}, - )), - drag_started: false, - drag_source_idx: None, - drag_target_idx: None, - previous_waves: None, - count: None, - blacklisted_translators: [], - show_about: false, - show_keys: false, - show_gestures: false, - show_quick_start: false, - show_license: false, - show_performance: false, - show_logs: false, - show_cursor_window: false, - wanted_timeunit: PicoSeconds, - time_string_format: None, - show_url_entry: false, - variable_name_filter_focused: false, - variable_name_filter_type: Fuzzy, - variable_name_filter_case_insensitive: true, - rename_target: None, - sidepanel_width: Some(300.0), - ui_zoom_factor: None, -) \ No newline at end of file diff --git a/HDL/projects/half_duplex_spi_master/surfer_load_data_rw.ron b/HDL/projects/half_duplex_spi_master/surfer_load_data_rw.ron index 442ab93e..26dbc901 100644 --- a/HDL/projects/half_duplex_spi_master/surfer_load_data_rw.ron +++ b/HDL/projects/half_duplex_spi_master/surfer_load_data_rw.ron @@ -17,21 +17,18 @@ active_scope: Some(WaveScope(( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ))), displayed_items_order: [ (1), (2), - (3), - (4), (5), (6), (7), - (8), (9), (10), - (11), (12), (14), (13), @@ -46,37 +43,39 @@ (23), ], displayed_items: { - (12): Variable(( + (10): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "spi_cs_n", + name: "to_spi_fifo_rd_en", ), - color: Some("red"), + color: None, background_color: None, - display_name: "spi_cs_n", + display_name: "to_spi_fifo_rd_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (18): Variable(( + (7): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "read_bitcounter_sc", + name: "to_spi_fifo_empty", ), - color: Some("violet"), + color: None, background_color: None, - display_name: "read_bitcounter_sc [5:0]", + display_name: "to_spi_fifo_empty", display_name_type: Unique, manual_name: None, format: None, @@ -99,48 +98,13 @@ format: None, field_formats: [], )), - (5): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "to_spi_fifo_wr_en", - ), - color: None, - background_color: None, - display_name: "to_spi_fifo_wr_en", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (10): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "to_spi_fifo_rd_en", - ), - color: None, - background_color: None, - display_name: "to_spi_fifo_rd_en", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), (13): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), name: "spi_sdio", @@ -153,92 +117,97 @@ format: None, field_formats: [], )), - (15): Variable(( + (9): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "spi_dir", + name: "spi_clk", ), - color: None, + color: Some("yellow"), background_color: None, - display_name: "spi_dir", + display_name: "spi_clk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (3): Variable(( + (5): Variable(( variable_ref: ( path: ( strs: [ "TOP", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "transaction_data", + name: "to_spi_fifo_wr_en", ), color: None, background_color: None, - display_name: "transaction_data [31:0]", + display_name: "to_spi_fifo_wr_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (1): Variable(( + (19): Variable(( variable_ref: ( path: ( strs: [ "TOP", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "reset_n", + name: "transaction_read_data_sc", ), color: None, background_color: None, - display_name: "reset_n", + display_name: "transaction_read_data_sc [31:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (7): Variable(( + (21): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "to_spi_fifo_empty", + name: "to_fabric_fifo_empty", ), color: None, background_color: None, - display_name: "to_spi_fifo_empty", + display_name: "to_fabric_fifo_empty", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (17): Variable(( + (1): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", ], ), - name: "bitcounter_sc", + name: "reset_n", ), color: None, background_color: None, - display_name: "bitcounter_sc [5:0]", + display_name: "reset_n", display_name_type: Unique, manual_name: None, - format: Some("Unsigned"), + format: None, field_formats: [], )), (16): Variable(( @@ -246,7 +215,8 @@ path: ( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), name: "spi_state", @@ -259,200 +229,174 @@ format: None, field_formats: [], )), - (14): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "spi_sclk", - ), - color: Some("red"), - background_color: None, - display_name: "spi_sclk", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (20): Variable(( + (23): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "to_fabric_fifo_wr_en", + name: "transaction_read_data", ), color: None, background_color: None, - display_name: "to_fabric_fifo_wr_en", + display_name: "transaction_read_data [31:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (11): Placeholder(( + (18): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "transaction_data_sc", + name: "read_bitcounter_sc", ), - color: None, + color: Some("violet"), background_color: None, - display_name: "transaction_data_sc [31:0]", + display_name: "read_bitcounter_sc [5:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (21): Variable(( + (6): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", + "to_spi_fifo", + "mem", ], ), - name: "to_fabric_fifo_empty", + name: "[0]", ), color: None, background_color: None, - display_name: "to_fabric_fifo_empty", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (9): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "spi_clk", - ), - color: Some("yellow"), - background_color: None, - display_name: "spi_clk", + display_name: "[0] [69:0]", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (22): Variable(( + (15): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "to_fabric_fifo_rd_en", + name: "spi_dir", ), color: None, background_color: None, - display_name: "to_fabric_fifo_rd_en", + display_name: "spi_dir", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (23): Variable(( + (14): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "transaction_read_data", + name: "spi_sclk", ), - color: None, + color: Some("red"), background_color: None, - display_name: "transaction_read_data [31:0]", + display_name: "spi_sclk", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (6): Variable(( + (20): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", - "to_spi_fifo", - "mem", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "[0]", + name: "to_fabric_fifo_wr_en", ), color: None, background_color: None, - display_name: "[0] [69:0]", + display_name: "to_fabric_fifo_wr_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (8): Placeholder(( + (22): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "spi_data_clk", + name: "to_fabric_fifo_rd_en", ), - color: Some("yellow"), + color: None, background_color: None, - display_name: "spi_data_clk", + display_name: "to_fabric_fifo_rd_en", display_name_type: Unique, manual_name: None, format: None, field_formats: [], )), - (19): Variable(( + (17): Variable(( variable_ref: ( path: ( strs: [ "TOP", - "bidirectional_spi", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "transaction_read_data_sc", + name: "bitcounter_sc", ), color: None, background_color: None, - display_name: "transaction_read_data_sc [31:0]", + display_name: "bitcounter_sc [5:0]", display_name_type: Unique, manual_name: None, - format: None, + format: Some("Unsigned"), field_formats: [], )), - (4): Variable(( + (12): Variable(( variable_ref: ( path: ( strs: [ "TOP", + "half_duplex_spi_master_clkdiv", + "hdsm", ], ), - name: "transaction_length", + name: "spi_cs_n", ), - color: None, + color: Some("red"), background_color: None, - display_name: "transaction_length [5:0]", + display_name: "spi_cs_n", display_name_type: Unique, manual_name: None, format: None, @@ -462,8 +406,8 @@ display_item_ref_counter: 23, viewports: [ ( - curr_left: (0.5438265502617963), - curr_right: (1.0948186484856248), + curr_left: (0.22314915249669653), + curr_right: (1.3251333489443518), target_left: (0.0), target_right: (1.0), move_start_left: (0.0), @@ -473,10 +417,10 @@ ), ], cursor: Some((1, [ - 450, + 406, ])), markers: {}, - focused_item: Some((22)), + focused_item: Some((2)), focused_transaction: (None, None), selected_items: [], default_variable_name_type: Unique, diff --git a/HDL/projects/half_duplex_spi_master/surfer_state.ron b/HDL/projects/half_duplex_spi_master/surfer_state.ron deleted file mode 100644 index 5c8b6d74..00000000 --- a/HDL/projects/half_duplex_spi_master/surfer_state.ron +++ /dev/null @@ -1,147 +0,0 @@ -( - show_hierarchy: None, - show_menu: None, - show_ticks: None, - show_toolbar: None, - show_tooltip: None, - show_overview: None, - show_statusbar: None, - align_names_right: None, - show_variable_indices: None, - show_variable_direction: None, - show_empty_scopes: None, - show_parameters_in_scopes: None, - waves: Some(( - source: File("sim_reset_n_clock.vcd"), - format: Vcd, - active_scope: Some(WaveScope(( - strs: [ - "TOP", - "bidirectional_spi", - ], - ))), - displayed_items_order: [ - (2), - (1), - (3), - (4), - ], - displayed_items: { - (4): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "spi_clk_90", - ), - color: Some("yellow"), - background_color: None, - display_name: "spi_clk_90", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (1): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - ], - ), - name: "fabric_clk", - ), - color: None, - background_color: None, - display_name: "fabric_clk", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (2): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - ], - ), - name: "reset_n", - ), - color: None, - background_color: None, - display_name: "reset_n", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - (3): Variable(( - variable_ref: ( - path: ( - strs: [ - "TOP", - "bidirectional_spi", - ], - ), - name: "spi_clk_0", - ), - color: Some("yellow"), - background_color: None, - display_name: "spi_clk_0", - display_name_type: Unique, - manual_name: None, - format: None, - field_formats: [], - )), - }, - display_item_ref_counter: 4, - viewports: [ - ( - curr_left: (0.0), - curr_right: (1.0), - target_left: (0.0), - target_right: (1.0), - move_start_left: (0.0), - move_start_right: (1.0), - move_duration: None, - move_strategy: Instant, - ), - ], - cursor: None, - markers: {}, - focused_item: Some((3)), - focused_transaction: (None, None), - selected_items: [], - default_variable_name_type: Unique, - scroll_offset: 0.0, - display_variable_indices: true, - graphics: {}, - )), - drag_started: false, - drag_source_idx: None, - drag_target_idx: Some((1)), - previous_waves: None, - count: None, - blacklisted_translators: [], - show_about: false, - show_keys: false, - show_gestures: false, - show_quick_start: false, - show_license: false, - show_performance: false, - show_logs: false, - show_cursor_window: false, - wanted_timeunit: PicoSeconds, - time_string_format: None, - show_url_entry: false, - variable_name_filter_focused: false, - variable_name_filter_type: Fuzzy, - variable_name_filter_case_insensitive: true, - rename_target: None, - sidepanel_width: Some(300.0), - ui_zoom_factor: None, -) \ No newline at end of file From 4c22ec34f64be60666f76989b7aeedcccec6bf27 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 20:25:00 -0800 Subject: [PATCH 77/96] some more Makefile cleanups and more tests --- HDL/projects/half_duplex_spi_master/Makefile | 12 + .../half_duplex_spi_master_tb.cpp | 251 +++++++++++++++++- 2 files changed, 258 insertions(+), 5 deletions(-) diff --git a/HDL/projects/half_duplex_spi_master/Makefile b/HDL/projects/half_duplex_spi_master/Makefile index 725505a2..b10d6ad5 100644 --- a/HDL/projects/half_duplex_spi_master/Makefile +++ b/HDL/projects/half_duplex_spi_master/Makefile @@ -18,9 +18,21 @@ clean: rm -rf obj_dir rm -f sim.vcd rm -f sim_reset_n_clock.vcd + rm -f sim_load_value_32w_mode0.vcd + rm -f sim_load_value_32w_mode1.vcd + rm -f sim_load_value_32w_mode2.vcd + rm -f sim_load_value_32w_mode3.vcd rm -f sim_load_value_mode0.vcd rm -f sim_load_value_mode1.vcd rm -f sim_load_value_mode2.vcd rm -f sim_load_value_mode3.vcd + rm -f sim_load_value_24w_8r_mode0.vcd + rm -f sim_load_value_24w_8r_mode1.vcd + rm -f sim_load_value_24w_8r_mode2.vcd + rm -f sim_load_value_24w_8r_mode3.vcd + rm -f sim_load_value_24r_8w_mode0.vcd + rm -f sim_load_value_24r_8w_mode1.vcd + rm -f sim_load_value_24r_8w_mode2.vcd + rm -f sim_load_value_24r_8w_mode3.vcd .PHONY: all sim clean diff --git a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp index 42f5cb23..0da9b589 100644 --- a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp @@ -42,6 +42,12 @@ int main(int argc, char **argv) VerilatedVcdC *tfp9 = new VerilatedVcdC; VerilatedVcdC *tfp10 = new VerilatedVcdC; VerilatedVcdC *tfp11 = new VerilatedVcdC; + VerilatedVcdC *tfp12 = new VerilatedVcdC; + VerilatedVcdC *tfp13 = new VerilatedVcdC; + VerilatedVcdC *tfp14 = new VerilatedVcdC; + VerilatedVcdC *tfp15 = new VerilatedVcdC; + VerilatedVcdC *tfp16 = new VerilatedVcdC; + VerilatedVcdC *tfp17 = new VerilatedVcdC; top->trace(tfp, 99); // Trace 99 levels of hierarchy tfp->open("sim_reset_n_clock.vcd"); @@ -227,7 +233,7 @@ int main(int argc, char **argv) tfp5->close(); top->trace(tfp6, 99); // Trace 99 levels of hierarchy - tfp6->open("sim_load_value_mode0_32bit.vcd"); + tfp6->open("sim_load_value_32w_mode0.vcd"); main_time = 0; // Reset time top->reset_n = 0; top->spi_cpol = 0; @@ -266,7 +272,7 @@ int main(int argc, char **argv) tfp6->close(); top->trace(tfp7, 99); // Trace 99 levels of hierarchy - tfp7->open("sim_load_value_24w_8rbit_mode0.vcd"); + tfp7->open("sim_load_value_24w_8r_mode0.vcd"); main_time = 0; // Reset time top->reset_n = 0; top->spi_cpol = 0; @@ -306,7 +312,7 @@ int main(int argc, char **argv) tfp7->close(); top->trace(tfp8, 99); // Trace 99 levels of hierarchy - tfp8->open("sim_load_value_24w_8rbit_mode1.vcd"); + tfp8->open("sim_load_value_24w_8r_mode1.vcd"); main_time = 0; // Reset time top->reset_n = 0; top->spi_cpol = 0; @@ -345,7 +351,7 @@ int main(int argc, char **argv) tfp8->close(); top->trace(tfp9, 99); // Trace 99 levels of hierarchy - tfp9->open("sim_load_value_24w_8rbit_mode2.vcd"); + tfp9->open("sim_load_value_24w_8r_mode2.vcd"); main_time = 0; // Reset time top->reset_n = 0; top->spi_cpol = 1; @@ -384,7 +390,7 @@ int main(int argc, char **argv) tfp9->close(); top->trace(tfp10, 99); // Trace 99 levels of hierarchy - tfp10->open("sim_load_value_24w_8rbit_mode3.vcd"); + tfp10->open("sim_load_value_24w_8r_mode3.vcd"); main_time = 0; // Reset time top->reset_n = 0; top->spi_cpol = 1; @@ -462,6 +468,241 @@ int main(int argc, char **argv) } // cleanup sim file tfp11->close(); + + top->trace(tfp15, 99); // Trace 99 levels of hierarchy + tfp15->open("sim_load_value_24r_8w_mode1.vcd"); + main_time = 0; // Reset time + top->reset_n = 0; + top->spi_cpol = 0; + top->spi_cpha = 1; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp15->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0x000000FF; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp15->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp15->close(); + + top->trace(tfp16, 99); // Trace 99 levels of hierarchy + tfp16->open("sim_load_value_24r_8w_mode2.vcd"); + main_time = 0; // Reset time + top->reset_n = 0; + top->spi_cpol = 1; + top->spi_cpha = 0; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp16->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0x000000FF; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp16->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp16->close(); + + top->trace(tfp17, 99); // Trace 99 levels of hierarchy + tfp17->open("sim_load_value_24r_8w_mode3.vcd"); + main_time = 0; // Reset time + top->reset_n = 0; + top->spi_cpol = 1; + top->spi_cpha = 1; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp17->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0x000000FF; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp17->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp17->close(); + + top->trace(tfp12, 99); // Trace 99 levels of hierarchy + tfp12->open("sim_load_value_32w_mode1.vcd"); + main_time = 0; // Reset time + top->reset_n = 0; + top->spi_cpol = 0; + top->spi_cpha = 1; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp12->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0xFFFFFFFF; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp12->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp12->close(); + + top->trace(tfp13, 99); // Trace 99 levels of hierarchy + tfp13->open("sim_load_value_32w_mode2.vcd"); + main_time = 0; // Reset time + top->reset_n = 0; + top->spi_cpol = 1; + top->spi_cpha = 0; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp13->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0xFFFFFFFF; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp13->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp13->close(); + + top->trace(tfp14, 99); // Trace 99 levels of hierarchy + tfp14->open("sim_load_value_32w_mode3.vcd"); + main_time = 0; // Reset time + top->reset_n = 0; + top->spi_cpol = 1; + top->spi_cpha = 1; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp14->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0xFFFFFFFF; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp14->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp14->close(); + delete top; return 0; } From 79d83958eca24ad5842ef98fc6c4e28b2ede7d28 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 20:46:03 -0800 Subject: [PATCH 78/96] added some more tests --- .../half_duplex_spi_master_tb.cpp | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp index 0da9b589..bd31e659 100644 --- a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp @@ -48,6 +48,8 @@ int main(int argc, char **argv) VerilatedVcdC *tfp15 = new VerilatedVcdC; VerilatedVcdC *tfp16 = new VerilatedVcdC; VerilatedVcdC *tfp17 = new VerilatedVcdC; + VerilatedVcdC *tfp18 = new VerilatedVcdC; + VerilatedVcdC *tfp19 = new VerilatedVcdC; top->trace(tfp, 99); // Trace 99 levels of hierarchy tfp->open("sim_reset_n_clock.vcd"); @@ -703,6 +705,87 @@ int main(int argc, char **argv) // cleanup sim file tfp14->close(); + /* this test case is unrealistic, as reading before writing doesn't make any + sense in most practical scenarios, nevertheless it should work */ + top->trace(tfp18, 99); // Trace 99 levels of hierarchy + tfp18->open("sim_load_value_32inter_mode0.vcd"); + main_time = 0; // Reset time + top->reset_n = 0; + top->spi_cpol = 0; + top->spi_cpha = 0; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp18->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xFFFFFFFF; + top->transaction_rw_mask = 0xAAAAAAAA; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp18->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp18->close(); + + /* this test case is unrealistic, as reading before writing doesn't make any + sense in most practical scenarios, nevertheless it should work */ + top->trace(tfp19, 99); // Trace 99 levels of hierarchy + tfp19->open("sim_load_value_32interb_mode0.vcd"); + main_time = 0; // Reset time + top->reset_n = 0; + top->spi_cpol = 0; + top->spi_cpha = 0; + // Reset sequence + while (main_time < 20) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp19->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 20) + { + top->transaction_length = 32; + top->transaction_data = 0xFFFFFFFF; + top->transaction_rw_mask = 0x55555555; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp19->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp19->close(); delete top; return 0; } From e13c1db1069cd3258f57e0a77ea5b6a4508e17fa Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 20:47:02 -0800 Subject: [PATCH 79/96] noted the next bug in the input shift register FSM --- HDL/projects/half_duplex_spi_master/TODO.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HDL/projects/half_duplex_spi_master/TODO.md b/HDL/projects/half_duplex_spi_master/TODO.md index f445142e..8f30a0c0 100644 --- a/HDL/projects/half_duplex_spi_master/TODO.md +++ b/HDL/projects/half_duplex_spi_master/TODO.md @@ -6,4 +6,5 @@ Important issues remaining on this core - [x] correct bitlengths for transaction length and bitcounters (done) - [x] remove dual clock approach and replace with simple single clock (done) - [x] make a separate module for the verilator tests (done) -- [ ] check all the reset conditions (not done) \ No newline at end of file +- [ ] check all the reset conditions (not done) +- [x] fix the input shift register shifts when writing out \ No newline at end of file From ccd86e163b8b7b5d00cf9c1c805a70fc6d34c846 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 21:38:33 -0800 Subject: [PATCH 80/96] fix the input register shifts --- HDL/projects/half_duplex_spi_master/TODO.md | 2 +- HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/HDL/projects/half_duplex_spi_master/TODO.md b/HDL/projects/half_duplex_spi_master/TODO.md index 8f30a0c0..9e09adc6 100644 --- a/HDL/projects/half_duplex_spi_master/TODO.md +++ b/HDL/projects/half_duplex_spi_master/TODO.md @@ -7,4 +7,4 @@ Important issues remaining on this core - [x] remove dual clock approach and replace with simple single clock (done) - [x] make a separate module for the verilator tests (done) - [ ] check all the reset conditions (not done) -- [x] fix the input shift register shifts when writing out \ No newline at end of file +- [x] fix the input shift register shifts when writing out (done) \ No newline at end of file diff --git a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv index b2501546..5b39e455 100644 --- a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv @@ -256,7 +256,7 @@ module half_duplex_spi_master #( end end - if (((spi_clk && spi_cpha) || (~spi_clk && ~spi_cpha)) && spi_dir) begin + if (((spi_clk && spi_cpha) || (~spi_clk && ~spi_cpha)) && rw_shift_register[DATA_WIDTH-1]) begin shift_out <= shiftout_register[DATA_WIDTH-1]; shiftout_register <= {shiftout_register[DATA_WIDTH-2:0],1'b0}; shiftin_register <= {shiftin_register[DATA_WIDTH-2:0],1'b0}; From 2fc3430292639a608ef64f59e028f90d1d298581 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 22:06:51 -0800 Subject: [PATCH 81/96] synchronize spi mode through fifo so it cannot change during a transaction --- HDL/projects/half_duplex_spi_master/TODO.md | 14 +++++--- .../half_duplex_spi_master.sv | 32 ++++++++++++------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/HDL/projects/half_duplex_spi_master/TODO.md b/HDL/projects/half_duplex_spi_master/TODO.md index 9e09adc6..0f99125b 100644 --- a/HDL/projects/half_duplex_spi_master/TODO.md +++ b/HDL/projects/half_duplex_spi_master/TODO.md @@ -1,10 +1,14 @@ Important issues remaining on this core - [x] Reading doesn't shift into correct bits (off by one) (done) - [x] To fabric FIFO transfer does not finnish due to possible reset (done) -- [ ] Asserts in testbench (not done) -- [ ] inout doesn't work in test bench (not done) -- [x] correct bitlengths for transaction length and bitcounters (done) +- [ ] Asserts in test bench (not done) +- [x] correct bit-lengths for transaction length and bit counters (done) - [x] remove dual clock approach and replace with simple single clock (done) -- [x] make a separate module for the verilator tests (done) +- [x] make a separate module with built-in clock-divider for the verilator tests (done) - [ ] check all the reset conditions (not done) -- [x] fix the input shift register shifts when writing out (done) \ No newline at end of file +- [x] fix the input shift register shifts when writing out (done) +- [ ] check that SPI modes cannot be changed in the middle of transactions etc (not done) +- [ ] remove unnecessary register (not done) +- [ ] check for unnecessary priority encoders (not done) +- [ ] change the state machine to follow standard pattern (not done) +- [ ] implement and test error detection (not done) \ No newline at end of file diff --git a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv index 5b39e455..eec9fa8d 100644 --- a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv @@ -31,6 +31,7 @@ module half_duplex_spi_master #( reg spi_dir; // Direction control for the SPI interface (1 for write, 0 for read) reg shift_out; // SPI Data to be shifted out + reg r_spi_cpol, r_spi_cpha, spi_cpol_sc, spi_cpha_sc; localparam BIT_COUNT_WIDTH = $clog2(DATA_WIDTH); @@ -44,11 +45,11 @@ module half_duplex_spi_master #( reg [DATA_WIDTH-1:0] r_transaction_data; reg [DATA_WIDTH-1:0] r_transaction_read_data, f_transaction_read_data; - reg [TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:0] sc_data, fc_data; + reg [2+TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:0] sc_data, fc_data; reg [DATA_WIDTH-1:0] transaction_read_data_sc; - assign fc_data = {r_transaction_length, r_transaction_rw_mask, r_transaction_data}; + assign fc_data = {r_spi_cpol, r_spi_cpha, r_transaction_length, r_transaction_rw_mask, r_transaction_data}; assign spi_sdio = spi_dir ? shift_out : 1'bz; @@ -77,6 +78,8 @@ module half_duplex_spi_master #( r_transaction_length <= 0; r_transaction_rw_mask <= 0; r_transaction_data <= 0; + r_spi_cpol <= 0; + r_spi_cpha <= 0; end else if (fabric_state == F_IDLE) begin if (transaction_length > 0) begin fabric_state <= F_WRITE; @@ -84,6 +87,8 @@ module half_duplex_spi_master #( r_transaction_length <= transaction_length; r_transaction_rw_mask <= transaction_rw_mask; r_transaction_data <= transaction_data; + r_spi_cpol <= spi_cpol; + r_spi_cpha <= spi_cpha; end else begin fabric_state <= F_IDLE; end @@ -115,12 +120,12 @@ module half_duplex_spi_master #( ); // I know this is super hacky, but it allows the logic below to look cleaner - assign spi_clk = spi_cpol ? ~spi_clk_in : spi_clk_in; + assign spi_clk = spi_cpol_sc ? ~spi_clk_in : spi_clk_in; reg to_spi_fifo_rd_en, to_spi_fifo_wr_en; // Instantiate the asynchronous FIFO for the data going to the SPI side async_fifo #( - .DATA_WIDTH(TRANSACTION_LEN_WIDTH+2*DATA_WIDTH), + .DATA_WIDTH(2+TRANSACTION_LEN_WIDTH+2*DATA_WIDTH), .ADDR_WIDTH(3) ) to_spi_fifo ( .wr_clk(fabric_clk), @@ -176,7 +181,7 @@ module half_duplex_spi_master #( state_t spi_state; // combinatorial logic to assign the SPI clock - assign spi_sclk = spi_clock_hot ? (spi_cpol ? ~spi_clk : spi_clk) : spi_cpol; + assign spi_sclk = spi_clock_hot ? (spi_cpol_sc ? ~spi_clk : spi_clk) : spi_cpol_sc; reg spi_clock_hot; reg [DATA_WIDTH-1:0] shiftout_register, rw_shift_register, shiftin_register; @@ -194,6 +199,9 @@ module half_duplex_spi_master #( spi_clock_hot <= 1'b0; read_bitcounter_sc <= 0; shiftin_register <= 0; + // pickup the mode on reset + spi_cpol_sc <= spi_cpol; + spi_cpha_sc <= spi_cpha; end else begin if (spi_state == IDLE) begin to_fabric_fifo_wr_en <= 1'b0; @@ -210,7 +218,9 @@ module half_duplex_spi_master #( end else if (spi_state == FIFO_READ) begin spi_state <= CS_ASSERT; to_spi_fifo_rd_en <= 1'b0; // deassert the read enable - // copy the data from the fifo + // copy the data from the fifo + spi_cpol_sc <= sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH+1]; + spi_cpha_sc <= sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH]; bitcounter_sc <= sc_data[TRANSACTION_LEN_WIDTH+DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH+DATA_WIDTH]; shiftout_register <= sc_data[DATA_WIDTH-1:0]; rw_shift_register <= sc_data[DATA_WIDTH+DATA_WIDTH-1:DATA_WIDTH]; @@ -225,7 +235,7 @@ module half_duplex_spi_master #( // deal with the write case for Mode 0 & 2, I doubt there is a read case here // at all directly after CS is asserted - if (~spi_clk && ~spi_cpha && spi_dir) begin + if (~spi_clk && ~spi_cpha_sc && spi_dir) begin spi_dir <= rw_shift_register[DATA_WIDTH-1]; rw_shift_register <= {rw_shift_register[DATA_WIDTH-2:0], 1'b0}; @@ -245,7 +255,7 @@ module half_duplex_spi_master #( end // all valid transitions that advance the state machine - if ((spi_clk && spi_cpha) || (~spi_clk && ~spi_cpha)) begin + if ((spi_clk && spi_cpha_sc) || (~spi_clk && ~spi_cpha_sc)) begin spi_dir <= rw_shift_register[DATA_WIDTH-1]; rw_shift_register <= {rw_shift_register[DATA_WIDTH-2:0], 1'b0}; if (rw_shift_register[DATA_WIDTH-1]) begin @@ -256,7 +266,7 @@ module half_duplex_spi_master #( end end - if (((spi_clk && spi_cpha) || (~spi_clk && ~spi_cpha)) && rw_shift_register[DATA_WIDTH-1]) begin + if (((spi_clk && spi_cpha_sc) || (~spi_clk && ~spi_cpha_sc)) && rw_shift_register[DATA_WIDTH-1]) begin shift_out <= shiftout_register[DATA_WIDTH-1]; shiftout_register <= {shiftout_register[DATA_WIDTH-2:0],1'b0}; shiftin_register <= {shiftin_register[DATA_WIDTH-2:0],1'b0}; @@ -268,7 +278,7 @@ module half_duplex_spi_master #( end else begin spi_state <= READ; end - if ((spi_clk && ~spi_cpha) || (~spi_clk && spi_cpha)) begin + if ((spi_clk && ~spi_cpha_sc) || (~spi_clk && spi_cpha_sc)) begin if (~rw_shift_register[DATA_WIDTH-1]) begin spi_dir <= rw_shift_register[DATA_WIDTH-1]; rw_shift_register <= {rw_shift_register[DATA_WIDTH-2:0], 1'b0}; @@ -277,7 +287,7 @@ module half_duplex_spi_master #( end end - if ((spi_clk && ~spi_cpha) || (~spi_clk && spi_cpha)) begin + if ((spi_clk && ~spi_cpha_sc) || (~spi_clk && spi_cpha_sc)) begin // it is a read transaction, so increment the read counter read_bitcounter_sc <= read_bitcounter_sc + 1; shiftin_register <= {shiftin_register[DATA_WIDTH-2:0],1'b1}; From 98ec50af4d3a98c4d5a70d1d349c32afc3ebf855 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 22:08:33 -0800 Subject: [PATCH 82/96] added one more task --- HDL/projects/half_duplex_spi_master/TODO.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HDL/projects/half_duplex_spi_master/TODO.md b/HDL/projects/half_duplex_spi_master/TODO.md index 0f99125b..c6c4b1bd 100644 --- a/HDL/projects/half_duplex_spi_master/TODO.md +++ b/HDL/projects/half_duplex_spi_master/TODO.md @@ -11,4 +11,5 @@ Important issues remaining on this core - [ ] remove unnecessary register (not done) - [ ] check for unnecessary priority encoders (not done) - [ ] change the state machine to follow standard pattern (not done) -- [ ] implement and test error detection (not done) \ No newline at end of file +- [ ] implement and test error detection (not done) +- [ ] bring a busy flag to the fabric domain using a double flop synchronizer (not done) \ No newline at end of file From 591446130233da6378345ab2cd4a96415a9dc5c9 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 22:17:33 -0800 Subject: [PATCH 83/96] cleanup in the read state --- HDL/projects/half_duplex_spi_master/TODO.md | 6 +++--- .../half_duplex_spi_master/half_duplex_spi_master.sv | 11 ++++------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/HDL/projects/half_duplex_spi_master/TODO.md b/HDL/projects/half_duplex_spi_master/TODO.md index c6c4b1bd..d919f996 100644 --- a/HDL/projects/half_duplex_spi_master/TODO.md +++ b/HDL/projects/half_duplex_spi_master/TODO.md @@ -1,14 +1,14 @@ Important issues remaining on this core - [x] Reading doesn't shift into correct bits (off by one) (done) -- [x] To fabric FIFO transfer does not finnish due to possible reset (done) +- [x] To fabric FIFO transfer does not finish due to possible reset (done) - [ ] Asserts in test bench (not done) - [x] correct bit-lengths for transaction length and bit counters (done) - [x] remove dual clock approach and replace with simple single clock (done) - [x] make a separate module with built-in clock-divider for the verilator tests (done) - [ ] check all the reset conditions (not done) - [x] fix the input shift register shifts when writing out (done) -- [ ] check that SPI modes cannot be changed in the middle of transactions etc (not done) -- [ ] remove unnecessary register (not done) +- [x] make sure SPI modes cannot be changed in the middle of transactions etc (done) +- [ ] remove unnecessary registers (not done) - [ ] check for unnecessary priority encoders (not done) - [ ] change the state machine to follow standard pattern (not done) - [ ] implement and test error detection (not done) diff --git a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv index eec9fa8d..fd556ad8 100644 --- a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv @@ -278,7 +278,11 @@ module half_duplex_spi_master #( end else begin spi_state <= READ; end + if ((spi_clk && ~spi_cpha_sc) || (~spi_clk && spi_cpha_sc)) begin + read_bitcounter_sc <= read_bitcounter_sc + 1; + shiftin_register <= {shiftin_register[DATA_WIDTH-2:0],1'b1}; + bitcounter_sc <= bitcounter_sc - 1; if (~rw_shift_register[DATA_WIDTH-1]) begin spi_dir <= rw_shift_register[DATA_WIDTH-1]; rw_shift_register <= {rw_shift_register[DATA_WIDTH-2:0], 1'b0}; @@ -287,13 +291,6 @@ module half_duplex_spi_master #( end end - if ((spi_clk && ~spi_cpha_sc) || (~spi_clk && spi_cpha_sc)) begin - // it is a read transaction, so increment the read counter - read_bitcounter_sc <= read_bitcounter_sc + 1; - shiftin_register <= {shiftin_register[DATA_WIDTH-2:0],1'b1}; - bitcounter_sc <= bitcounter_sc - 1; - end - end else if (spi_state == DONE) begin if (spi_clk) begin shift_out <= 1'b0; From 039c26af17d05079facdefcac5739a10d00cf38c Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Fri, 6 Dec 2024 22:46:18 -0800 Subject: [PATCH 84/96] added a combinatorial state transition machine --- .../half_duplex_spi_master.sv | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv index fd556ad8..c03aee0e 100644 --- a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv @@ -178,7 +178,9 @@ module half_duplex_spi_master #( FIFO_WRITE } state_t; - state_t spi_state; + /* verilator lint_off UNUSEDSIGNAL */ + state_t spi_state, next_spi_state; + /* verilator lint_on UNUSEDSIGNAL */ // combinatorial logic to assign the SPI clock assign spi_sclk = spi_clock_hot ? (spi_cpol_sc ? ~spi_clk : spi_clk) : spi_cpol_sc; @@ -188,6 +190,58 @@ module half_duplex_spi_master #( assign transaction_read_data_sc = shiftin_register; + // traditional FSM pattern + + always_comb begin + next_spi_state = spi_state; + + case (spi_state) + IDLE: begin + if(~to_spi_fifo_empty) next_spi_state = FIFO_READ; + end + + FIFO_READ: begin + next_spi_state = CS_ASSERT; + end + + CS_ASSERT: begin + if (rw_shift_register[DATA_WIDTH-1]) begin + next_spi_state = WRITE; + end else begin + next_spi_state = READ; + end + end + + WRITE: begin + if (bitcounter_sc == 0) begin + next_spi_state = DONE; + end else if (~rw_shift_register[DATA_WIDTH-1]) begin + next_spi_state = READ; + end + end + + READ: begin + if (bitcounter_sc == 0) begin + next_spi_state = DONE; + end else if (rw_shift_register[DATA_WIDTH-1]) begin + next_spi_state = WRITE; + end + end + + DONE: begin + if (read_bitcounter_sc == 0 || to_fabric_fifo_full) begin + next_spi_state = IDLE; + end else begin + next_spi_state = FIFO_WRITE; + end + end + + FIFO_WRITE: next_spi_state = IDLE; + + default: next_spi_state = IDLE; + endcase + end + always_ff @(posedge spi_clk or negedge spi_clk or negedge reset_n_sc) begin if (~reset_n_sc) begin spi_dir <= 1'b1; From c9118eb86f5bc63748d0847f777fcd794b64d362 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sat, 7 Dec 2024 23:00:26 -0800 Subject: [PATCH 85/96] added the 4-input redpitaya as boardx --- .../stemlab_125_14_4in/brd/1.0/board.xml | 29 +++ .../stemlab_125_14_4in/brd/1.0/part0_pins.xml | 84 +++++++ .../stemlab_125_14_4in/brd/1.0/preset.xml | 166 +++++++++++++ .../stemlab_125_14_4in/brd/1.0/redpitaya.jpg | Bin 0 -> 42583 bytes HDL/boards/stemlab_125_14_4in/clocks.xdc | 2 + .../stemlab_125_14_4in/ocra_config.json | 8 + HDL/boards/stemlab_125_14_4in/ports.tcl | 43 ++++ HDL/boards/stemlab_125_14_4in/ports.xdc | 225 ++++++++++++++++++ 8 files changed, 557 insertions(+) create mode 100644 HDL/boards/stemlab_125_14_4in/brd/1.0/board.xml create mode 100644 HDL/boards/stemlab_125_14_4in/brd/1.0/part0_pins.xml create mode 100644 HDL/boards/stemlab_125_14_4in/brd/1.0/preset.xml create mode 100644 HDL/boards/stemlab_125_14_4in/brd/1.0/redpitaya.jpg create mode 100644 HDL/boards/stemlab_125_14_4in/clocks.xdc create mode 100644 HDL/boards/stemlab_125_14_4in/ocra_config.json create mode 100644 HDL/boards/stemlab_125_14_4in/ports.tcl create mode 100644 HDL/boards/stemlab_125_14_4in/ports.xdc diff --git a/HDL/boards/stemlab_125_14_4in/brd/1.0/board.xml b/HDL/boards/stemlab_125_14_4in/brd/1.0/board.xml new file mode 100644 index 00000000..1b869b60 --- /dev/null +++ b/HDL/boards/stemlab_125_14_4in/brd/1.0/board.xml @@ -0,0 +1,29 @@ + + + + + STEMLab-125.14 4-input Board File + + + 1.0 + Red Pitaya STEMLab-125.14 4-input + + 1.0 + + + + FPGA part on the board + + + + + + + + + + + + + + diff --git a/HDL/boards/stemlab_125_14_4in/brd/1.0/part0_pins.xml b/HDL/boards/stemlab_125_14_4in/brd/1.0/part0_pins.xml new file mode 100644 index 00000000..5f20aba7 --- /dev/null +++ b/HDL/boards/stemlab_125_14_4in/brd/1.0/part0_pins.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HDL/boards/stemlab_125_14_4in/brd/1.0/preset.xml b/HDL/boards/stemlab_125_14_4in/brd/1.0/preset.xml new file mode 100644 index 00000000..07481caf --- /dev/null +++ b/HDL/boards/stemlab_125_14_4in/brd/1.0/preset.xml @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HDL/boards/stemlab_125_14_4in/brd/1.0/redpitaya.jpg b/HDL/boards/stemlab_125_14_4in/brd/1.0/redpitaya.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e5676cbfac6ff54134495c182c5d02c8cc11ba9b GIT binary patch literal 42583 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�SXGjiRICvR%^9^&b2>U`$@6OZA6|W!U5Im219~SFzLY8O3Cqns$y&< zifJ3Ynwm7jp{sTf@w!-|@5$!GFXuswz_1c%LiQ-!t}=RAsfN4GtPfcXAQ`gLM^)_t zp!~dS5tAzl0i(}3Og9#(R53%|fNiG4(ibJv^9<^C;Vy7wu~B3mIr*70S8lArWwIx$ z{*~*R!q=;k^Ss+eAot=vx3~ixz6E@~#L;_{)t6haLD{}w#NhN1W)dFdpV;QS?S->_ zRNxRW^?Awkjm*4|8CG%Wli;*+ zKRXxx?b}v@LwT%ZPJXvfKko-Fq<7cboDI_|Zq48XJM7I|6*?yV;r$q+ALavP0RX0^1K+CAl$~OAAh3#FppQ$~j8c5*pe`8E@o~m=J zJ`8WZ2%7t2{EGgT5aaOgYv1}wXUE_iFALZZ=t#7_n?2R^?mx%)4AW039Zncb~V zkkdoy$H8GSVfa?GbhYNH|Jtqg{KPJkp8IK~+#0bn3=NwDv5lY0>%o7g9K zm>nC-!Nt5~Ta}{TR_yg#t&<5tq!>wN30WV_eXdH5m)n&R;WSBr6jjh7s(j!BMV2M0 zyy&@Z-`rH(Y>t@OG&Nip{i*-ASlY|_{(^%kf?P(rXxhdnQz+@RxUcgT=61aY6#YD9 zpseLX4l4}S^#%T3=xm)BP>?pSD+{;i?p=YwYtGlC;;mzlyp@~ z*L7AU8!%-l*du59m}~L(_-b%3oi@Q|K4(taxKS9D0zq`x=iuuCmBzDgFL*(rBvE4` Uq<)?R2feztEgf%tu>P6-f0T}R`2YX_ literal 0 HcmV?d00001 diff --git a/HDL/boards/stemlab_125_14_4in/clocks.xdc b/HDL/boards/stemlab_125_14_4in/clocks.xdc new file mode 100644 index 00000000..d2cfe3fa --- /dev/null +++ b/HDL/boards/stemlab_125_14_4in/clocks.xdc @@ -0,0 +1,2 @@ +set_input_delay -max 1.000 -clock adc_clk_p_i [get_ports adc_dat_a_i[*]] +set_input_delay -max 1.000 -clock adc_clk_p_i [get_ports adc_dat_b_i[*]] diff --git a/HDL/boards/stemlab_125_14_4in/ocra_config.json b/HDL/boards/stemlab_125_14_4in/ocra_config.json new file mode 100644 index 00000000..c3b762ae --- /dev/null +++ b/HDL/boards/stemlab_125_14_4in/ocra_config.json @@ -0,0 +1,8 @@ +{ + "HDL": { + "part": "xc7z020clg400-1", + "proc": "ps7_cortexa9_0", + "board_part": "redpitaya.com:stemlab_125_14_4in:part0:1.0", + "projects": ["ocra_mri", "base_pl"] + } +} diff --git a/HDL/boards/stemlab_125_14_4in/ports.tcl b/HDL/boards/stemlab_125_14_4in/ports.tcl new file mode 100644 index 00000000..9a7319b7 --- /dev/null +++ b/HDL/boards/stemlab_125_14_4in/ports.tcl @@ -0,0 +1,43 @@ + +### ADC + +create_bd_port -dir I -from 15 -to 0 adc_dat_a_i +create_bd_port -dir I -from 15 -to 0 adc_dat_b_i + +create_bd_port -dir I adc_clk_p_i +create_bd_port -dir I adc_clk_n_i + +create_bd_port -dir O adc_enc_p_o +create_bd_port -dir O adc_enc_n_o + +create_bd_port -dir O adc_csn_o + +### DAC + +create_bd_port -dir O -from 13 -to 0 dac_dat_o + +create_bd_port -dir O dac_clk_o +create_bd_port -dir O dac_rst_o +create_bd_port -dir O dac_sel_o +create_bd_port -dir O dac_wrt_o + +### PWM + +create_bd_port -dir O -from 3 -to 0 dac_pwm_o + +### XADC + +create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vp_Vn +create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vaux0 +create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vaux1 +create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vaux9 +create_bd_intf_port -mode Slave -vlnv xilinx.com:interface:diff_analog_io_rtl:1.0 Vaux8 + +### Expansion connector + +create_bd_port -dir IO -from 7 -to 0 exp_p_tri_io +create_bd_port -dir IO -from 7 -to 0 exp_n_tri_io + +### LED + +create_bd_port -dir O -from 7 -to 0 led_o diff --git a/HDL/boards/stemlab_125_14_4in/ports.xdc b/HDL/boards/stemlab_125_14_4in/ports.xdc new file mode 100644 index 00000000..8bdea47d --- /dev/null +++ b/HDL/boards/stemlab_125_14_4in/ports.xdc @@ -0,0 +1,225 @@ + +# set_property CFGBVS VCCO [current_design] +# set_property CONFIG_VOLTAGE 3.3 [current_design] + +### ADC + +# data + +set_property IOSTANDARD LVCMOS18 [get_ports {adc_dat_a_i[*]}] +set_property IOB TRUE [get_ports {adc_dat_a_i[*]}] + +set_property PACKAGE_PIN V17 [get_ports {adc_dat_a_i[0]}] +set_property PACKAGE_PIN_U17 [get_ports {adc_dat_a_i[1]}] +set_property PACKAGE_PIN Y17 [get_ports {adc_dat_a_i[2]}] +set_property PACKAGE_PIN W16 [get_ports {adc_dat_a_i[3]}] +set_property PACKAGE_PIN Y16 [get_ports {adc_dat_a_i[4]}] +set_property PACKAGE_PIN W15 [get_ports {adc_dat_a_i[5]}] +set_property PACKAGE_PIN W14 [get_ports {adc_dat_a_i[6]}] +set_property PACKAGE_PIN Y14 [get_ports {adc_dat_a_i[7]}] +set_property PACKAGE_PIN W13 [get_ports {adc_dat_a_i[8]}] +set_property PACKAGE_PIN V12 [get_ports {adc_dat_a_i[9]}] +set_property PACKAGE_PIN V13 [get_ports {adc_dat_a_i[10]}] +set_property PACKAGE_PIN T14 [get_ports {adc_dat_a_i[11]}] +set_property PACKAGE_PIN T15 [get_ports {adc_dat_a_i[12]}] +set_property PACKAGE_PIN V15 [get_ports {adc_dat_a_i[13]}] +set_property PACKAGE_PIN T16 [get_ports {adc_dat_a_i[14]}] +set_property PACKAGE_PIN V16 [get_ports {adc_dat_a_i[15]}] + +set_property IOSTANDARD LVCMOS18 [get_ports {adc_dat_b_i[*]}] +set_property IOB TRUE [get_ports {adc_dat_b_i[*]}] + +set_property PACKAGE_PIN T17 [get_ports {adc_dat_b_i[0]}] +set_property PACKAGE_PIN R16 [get_ports {adc_dat_b_i[1]}] +set_property PACKAGE_PIN R18 [get_ports {adc_dat_b_i[2]}] +set_property PACKAGE_PIN P16 [get_ports {adc_dat_b_i[3]}] +set_property PACKAGE_PIN P18 [get_ports {adc_dat_b_i[4]}] +set_property PACKAGE_PIN N17 [get_ports {adc_dat_b_i[5]}] +set_property PACKAGE_PIN R19 [get_ports {adc_dat_b_i[6]}] +set_property PACKAGE_PIN T20 [get_ports {adc_dat_b_i[7]}] +set_property PACKAGE_PIN T19 [get_ports {adc_dat_b_i[8]}] +set_property PACKAGE_PIN U20 [get_ports {adc_dat_b_i[9]}] +set_property PACKAGE_PIN V20 [get_ports {adc_dat_b_i[10]}] +set_property PACKAGE_PIN W20 [get_ports {adc_dat_b_i[11]}] +set_property PACKAGE_PIN W19 [get_ports {adc_dat_b_i[12]}] +set_property PACKAGE_PIN Y19 [get_ports {adc_dat_b_i[13]}] +set_property PACKAGE_PIN W18 [get_ports {adc_dat_b_i[14]}] +set_property PACKAGE_PIN Y18 [get_ports {adc_dat_b_i[15]}] + +# clock input + +set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports adc_clk_p_i] +set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports adc_clk_n_i] +set_property PACKAGE_PIN U18 [get_ports adc_clk_p_i] +set_property PACKAGE_PIN U19 [get_ports adc_clk_n_i] + +# clock output + +set_property IOSTANDARD LVCMOS18 [get_ports adc_enc_p_o] +set_property IOSTANDARD LVCMOS18 [get_ports adc_enc_n_o] + +set_property SLEW FAST [get_ports adc_enc_p_o] +set_property SLEW FAST [get_ports adc_enc_n_o] + +set_property DRIVE 8 [get_ports adc_enc_p_o] +set_property DRIVE 8 [get_ports adc_enc_n_o] + +set_property PACKAGE_PIN N20 [get_ports adc_enc_p_o] +set_property PACKAGE_PIN P20 [get_ports adc_enc_n_o] + +# clock duty cycle stabilizer (CSn) + +set_property IOSTANDARD LVCMOS18 [get_ports adc_csn_o] +set_property PACKAGE_PIN V18 [get_ports adc_csn_o] +set_property SLEW FAST [get_ports adc_csn_o] +set_property DRIVE 8 [get_ports adc_csn_o] + +### DAC + +# data + +set_property IOSTANDARD LVCMOS33 [get_ports {dac_dat_o[*]}] +set_property SLEW SLOW [get_ports {dac_dat_o[*]}] +set_property DRIVE 4 [get_ports {dac_dat_o[*]}] +# set_property IOB TRUE [get_ports {dac_dat_o[*]}] + +set_property PACKAGE_PIN M19 [get_ports {dac_dat_o[0]}] +set_property PACKAGE_PIN M20 [get_ports {dac_dat_o[1]}] +set_property PACKAGE_PIN L19 [get_ports {dac_dat_o[2]}] +set_property PACKAGE_PIN L20 [get_ports {dac_dat_o[3]}] +set_property PACKAGE_PIN K19 [get_ports {dac_dat_o[4]}] +set_property PACKAGE_PIN J19 [get_ports {dac_dat_o[5]}] +set_property PACKAGE_PIN J20 [get_ports {dac_dat_o[6]}] +set_property PACKAGE_PIN H20 [get_ports {dac_dat_o[7]}] +set_property PACKAGE_PIN G19 [get_ports {dac_dat_o[8]}] +set_property PACKAGE_PIN G20 [get_ports {dac_dat_o[9]}] +set_property PACKAGE_PIN F19 [get_ports {dac_dat_o[10]}] +set_property PACKAGE_PIN F20 [get_ports {dac_dat_o[11]}] +set_property PACKAGE_PIN D20 [get_ports {dac_dat_o[12]}] +set_property PACKAGE_PIN D19 [get_ports {dac_dat_o[13]}] + +# control + +set_property IOSTANDARD LVCMOS33 [get_ports dac_*_o] +set_property SLEW FAST [get_ports dac_*_o] +set_property DRIVE 8 [get_ports dac_*_o] +# set_property IOB TRUE [get_ports {dac_*_o}] + +set_property PACKAGE_PIN M17 [get_ports dac_wrt_o] +set_property PACKAGE_PIN N16 [get_ports dac_sel_o] +set_property PACKAGE_PIN M18 [get_ports dac_clk_o] +set_property PACKAGE_PIN N15 [get_ports dac_rst_o] + +### PWM + +set_property IOSTANDARD LVCMOS18 [get_ports {dac_pwm_o[*]}] +set_property SLEW FAST [get_ports {dac_pwm_o[*]}] +set_property DRIVE 12 [get_ports {dac_pwm_o[*]}] +# set_property IOB TRUE [get_ports {dac_pwm_o[*]}] + +set_property PACKAGE_PIN T10 [get_ports {dac_pwm_o[0]}] +set_property PACKAGE_PIN T11 [get_ports {dac_pwm_o[1]}] +set_property PACKAGE_PIN P15 [get_ports {dac_pwm_o[2]}] +set_property PACKAGE_PIN U13 [get_ports {dac_pwm_o[3]}] + +### XADC + +set_property IOSTANDARD LVCMOS33 [get_ports Vp_Vn_v_p] +set_property IOSTANDARD LVCMOS33 [get_ports Vp_Vn_v_n] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux0_v_p] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux0_v_n] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux1_v_p] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux1_v_n] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux8_v_p] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux8_v_n] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux9_v_p] +set_property IOSTANDARD LVCMOS33 [get_ports Vaux9_v_n] + +set_property PACKAGE_PIN K9 [get_ports Vp_Vn_v_p] +set_property PACKAGE_PIN L10 [get_ports Vp_Vn_v_n] +set_property PACKAGE_PIN C20 [get_ports Vaux0_v_p] +set_property PACKAGE_PIN B20 [get_ports Vaux0_v_n] +set_property PACKAGE_PIN E17 [get_ports Vaux1_v_p] +set_property PACKAGE_PIN D18 [get_ports Vaux1_v_n] +set_property PACKAGE_PIN B19 [get_ports Vaux8_v_p] +set_property PACKAGE_PIN A20 [get_ports Vaux8_v_n] +set_property PACKAGE_PIN E18 [get_ports Vaux9_v_p] +set_property PACKAGE_PIN E19 [get_ports Vaux9_v_n] + +### Expansion connector + +set_property IOSTANDARD LVCMOS33 [get_ports {exp_p_tri_io[*]}] +set_property IOSTANDARD LVCMOS33 [get_ports {exp_n_tri_io[*]}] +set_property SLEW FAST [get_ports {exp_p_tri_io[*]}] +set_property SLEW FAST [get_ports {exp_n_tri_io[*]}] +set_property DRIVE 8 [get_ports {exp_p_tri_io[*]}] +set_property DRIVE 8 [get_ports {exp_n_tri_io[*]}] +set_property PULLTYPE PULLUP [get_ports {exp_p_tri_io[*]}] +set_property PULLTYPE PULLUP [get_ports {exp_n_tri_io[*]}] + +set_property PACKAGE_PIN G17 [get_ports {exp_p_tri_io[0]}] +set_property PACKAGE_PIN G18 [get_ports {exp_n_tri_io[0]}] +set_property PACKAGE_PIN H16 [get_ports {exp_p_tri_io[1]}] +set_property PACKAGE_PIN H17 [get_ports {exp_n_tri_io[1]}] +set_property PACKAGE_PIN J18 [get_ports {exp_p_tri_io[2]}] +set_property PACKAGE_PIN H18 [get_ports {exp_n_tri_io[2]}] +set_property PACKAGE_PIN K17 [get_ports {exp_p_tri_io[3]}] +set_property PACKAGE_PIN K18 [get_ports {exp_n_tri_io[3]}] +set_property PACKAGE_PIN L14 [get_ports {exp_p_tri_io[4]}] +set_property PACKAGE_PIN L15 [get_ports {exp_n_tri_io[4]}] +set_property PACKAGE_PIN L16 [get_ports {exp_p_tri_io[5]}] +set_property PACKAGE_PIN L17 [get_ports {exp_n_tri_io[5]}] +set_property PACKAGE_PIN K16 [get_ports {exp_p_tri_io[6]}] +set_property PACKAGE_PIN J16 [get_ports {exp_n_tri_io[6]}] +set_property PACKAGE_PIN M14 [get_ports {exp_p_tri_io[7]}] +set_property PACKAGE_PIN M15 [get_ports {exp_n_tri_io[7]}] + +set_property IOSTANDARD LVCMOS33 [get_ports exp_p_trg] +set_property SLEW FAST [get_ports exp_p_trg] +set_property DRIVE 8 [get_ports exp_p_trg] + +set_property PACKAGE_PIN M14 [get_ports exp_p_trg] + +set_property IOSTANDARD LVCMOS33 [get_ports {exp_n_alex[*]}] +set_property SLEW FAST [get_ports {exp_n_alex[*]}] +set_property DRIVE 8 [get_ports {exp_n_alex[*]}] + +set_property PACKAGE_PIN L15 [get_ports {exp_n_alex[0]}] +set_property PACKAGE_PIN L17 [get_ports {exp_n_alex[1]}] +set_property PACKAGE_PIN J16 [get_ports {exp_n_alex[2]}] +set_property PACKAGE_PIN M15 [get_ports {exp_n_alex[3]}] + +### SATA connector + +set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_p_o[*]] +set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_n_o[*]] + +set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_p_i[*]] +set_property IOSTANDARD DIFF_HSTL_I_18 [get_ports daisy_n_i[*]] + +set_property PACKAGE_PIN T12 [get_ports {daisy_p_o[0]}] +set_property PACKAGE_PIN U12 [get_ports {daisy_n_o[0]}] + +set_property PACKAGE_PIN U14 [get_ports {daisy_p_o[1]}] +set_property PACKAGE_PIN U15 [get_ports {daisy_n_o[1]}] + +set_property PACKAGE_PIN P14 [get_ports {daisy_p_i[0]}] +set_property PACKAGE_PIN R14 [get_ports {daisy_n_i[0]}] + +set_property PACKAGE_PIN N18 [get_ports {daisy_p_i[1]}] +set_property PACKAGE_PIN P19 [get_ports {daisy_n_i[1]}] + +### LED + +set_property IOSTANDARD LVCMOS33 [get_ports {led_o[*]}] +set_property SLEW SLOW [get_ports {led_o[*]}] +set_property DRIVE 8 [get_ports {led_o[*]}] + +set_property PACKAGE_PIN F16 [get_ports {led_o[0]}] +set_property PACKAGE_PIN F17 [get_ports {led_o[1]}] +set_property PACKAGE_PIN G15 [get_ports {led_o[2]}] +set_property PACKAGE_PIN H15 [get_ports {led_o[3]}] +set_property PACKAGE_PIN K14 [get_ports {led_o[4]}] +set_property PACKAGE_PIN G14 [get_ports {led_o[5]}] +set_property PACKAGE_PIN J15 [get_ports {led_o[6]}] +set_property PACKAGE_PIN J14 [get_ports {led_o[7]}] From f277fbe5d6aacc05922823da9b147b72732694e6 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Sun, 8 Dec 2024 07:00:24 -0800 Subject: [PATCH 86/96] add new base_pl_new project --- HDL/boards/stemlab_125_14/ocra_config.json | 2 +- HDL/boards/stemlab_125_14/ps_base_pl_new.xml | 164 +++++++++++++++++++ 2 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 HDL/boards/stemlab_125_14/ps_base_pl_new.xml diff --git a/HDL/boards/stemlab_125_14/ocra_config.json b/HDL/boards/stemlab_125_14/ocra_config.json index e491552d..6afb074b 100644 --- a/HDL/boards/stemlab_125_14/ocra_config.json +++ b/HDL/boards/stemlab_125_14/ocra_config.json @@ -3,6 +3,6 @@ "part": "xc7z010clg400-1", "proc": "ps7_cortexa9_0", "board_part": "redpitaya.com:stemlab_125_14:part0:1.0", - "projects": ["ocra_mri", "shim_controller", "base_pl"] + "projects": ["ocra_mri", "shim_controller", "base_pl","base_pl_new"] } } diff --git a/HDL/boards/stemlab_125_14/ps_base_pl_new.xml b/HDL/boards/stemlab_125_14/ps_base_pl_new.xml new file mode 100644 index 00000000..33a9fc8d --- /dev/null +++ b/HDL/boards/stemlab_125_14/ps_base_pl_new.xml @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3554220f61732f06276e8ddabd8b822f1c57759e Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Mon, 9 Dec 2024 19:45:29 -0800 Subject: [PATCH 87/96] changed the design to operate with a single double frequency clock and to trigger transitions on an even-strobe or odd-strobe --- HDL/projects/half_duplex_spi_master/TODO.md | 3 +- .../half_duplex_spi_master.sv | 30 ++++++++++++++----- .../half_duplex_spi_master_clkdiv.sv | 2 +- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/HDL/projects/half_duplex_spi_master/TODO.md b/HDL/projects/half_duplex_spi_master/TODO.md index d919f996..910344cf 100644 --- a/HDL/projects/half_duplex_spi_master/TODO.md +++ b/HDL/projects/half_duplex_spi_master/TODO.md @@ -12,4 +12,5 @@ Important issues remaining on this core - [ ] check for unnecessary priority encoders (not done) - [ ] change the state machine to follow standard pattern (not done) - [ ] implement and test error detection (not done) -- [ ] bring a busy flag to the fabric domain using a double flop synchronizer (not done) \ No newline at end of file +- [ ] bring a busy flag to the fabric domain using a double flop synchronizer (not done) +- [x] rewrite to use a FSM running on double clock speed to only have positive edge sensitivity (not done) diff --git a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv index c03aee0e..ff8094f7 100644 --- a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master.sv @@ -183,13 +183,27 @@ module half_duplex_spi_master #( /* verilator lint_on UNUSEDSIGNAL */ // combinatorial logic to assign the SPI clock - assign spi_sclk = spi_clock_hot ? (spi_cpol_sc ? ~spi_clk : spi_clk) : spi_cpol_sc; + assign spi_sclk = spi_clock_hot ? (spi_cpol_sc ? ~odd_strobe : odd_strobe) : spi_cpol_sc; reg spi_clock_hot; reg [DATA_WIDTH-1:0] shiftout_register, rw_shift_register, shiftin_register; assign transaction_read_data_sc = shiftin_register; + // the even-odd strobe + reg eotoggle; + wire even_strobe, odd_strobe; + assign even_strobe = ~eotoggle; + assign odd_strobe = eotoggle; + + always @(posedge spi_clk or negedge reset_n_sc) begin + if (~reset_n_sc) begin + eotoggle <= 1'b0; + end else begin + eotoggle <= ~eotoggle; + end + end + // traditional FSM pattern always_comb begin @@ -242,7 +256,7 @@ module half_duplex_spi_master #( endcase end - always_ff @(posedge spi_clk or negedge spi_clk or negedge reset_n_sc) begin + always_ff @(posedge spi_clk or negedge reset_n_sc) begin if (~reset_n_sc) begin spi_dir <= 1'b1; shift_out <= 1'b0; @@ -289,7 +303,7 @@ module half_duplex_spi_master #( // deal with the write case for Mode 0 & 2, I doubt there is a read case here // at all directly after CS is asserted - if (~spi_clk && ~spi_cpha_sc && spi_dir) begin + if (odd_strobe && ~spi_cpha_sc && spi_dir) begin spi_dir <= rw_shift_register[DATA_WIDTH-1]; rw_shift_register <= {rw_shift_register[DATA_WIDTH-2:0], 1'b0}; @@ -309,7 +323,7 @@ module half_duplex_spi_master #( end // all valid transitions that advance the state machine - if ((spi_clk && spi_cpha_sc) || (~spi_clk && ~spi_cpha_sc)) begin + if ((even_strobe && spi_cpha_sc) || (odd_strobe && ~spi_cpha_sc)) begin spi_dir <= rw_shift_register[DATA_WIDTH-1]; rw_shift_register <= {rw_shift_register[DATA_WIDTH-2:0], 1'b0}; if (rw_shift_register[DATA_WIDTH-1]) begin @@ -320,7 +334,7 @@ module half_duplex_spi_master #( end end - if (((spi_clk && spi_cpha_sc) || (~spi_clk && ~spi_cpha_sc)) && rw_shift_register[DATA_WIDTH-1]) begin + if (((even_strobe && spi_cpha_sc) || (odd_strobe && ~spi_cpha_sc)) && rw_shift_register[DATA_WIDTH-1]) begin shift_out <= shiftout_register[DATA_WIDTH-1]; shiftout_register <= {shiftout_register[DATA_WIDTH-2:0],1'b0}; shiftin_register <= {shiftin_register[DATA_WIDTH-2:0],1'b0}; @@ -333,7 +347,7 @@ module half_duplex_spi_master #( spi_state <= READ; end - if ((spi_clk && ~spi_cpha_sc) || (~spi_clk && spi_cpha_sc)) begin + if ((even_strobe && ~spi_cpha_sc) || (odd_strobe && spi_cpha_sc)) begin read_bitcounter_sc <= read_bitcounter_sc + 1; shiftin_register <= {shiftin_register[DATA_WIDTH-2:0],1'b1}; bitcounter_sc <= bitcounter_sc - 1; @@ -346,7 +360,7 @@ module half_duplex_spi_master #( end end else if (spi_state == DONE) begin - if (spi_clk) begin + if (even_strobe) begin shift_out <= 1'b0; spi_clock_hot <= 1'b0; spi_dir <= 1'b1; @@ -360,7 +374,7 @@ module half_duplex_spi_master #( end end end else if (spi_state == FIFO_WRITE) begin - if (spi_clk) begin + if (even_strobe) begin spi_state <= IDLE; to_fabric_fifo_wr_en <= 1'b0; end diff --git a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_clkdiv.sv b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_clkdiv.sv index e486e036..128e2a10 100644 --- a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_clkdiv.sv +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_clkdiv.sv @@ -2,7 +2,7 @@ module half_duplex_spi_master_clkdiv #( parameter DATA_WIDTH = 32, parameter TRANSACTION_LEN_WIDTH = 6, - parameter CLOCK_DIVIDER = 2 + parameter CLOCK_DIVIDER = 1 )( input wire [TRANSACTION_LEN_WIDTH-1:0] transaction_length, input wire [DATA_WIDTH-1:0] transaction_data, From f38c7602b18768720d1ff8b0d601936fa7d2d948 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Tue, 10 Dec 2024 08:10:54 -0800 Subject: [PATCH 88/96] updated todo to reflect new problems added another test case which maybe pointless --- HDL/projects/half_duplex_spi_master/TODO.md | 1 + .../half_duplex_spi_master_tb.cpp | 44 ++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/HDL/projects/half_duplex_spi_master/TODO.md b/HDL/projects/half_duplex_spi_master/TODO.md index 910344cf..b45e5e92 100644 --- a/HDL/projects/half_duplex_spi_master/TODO.md +++ b/HDL/projects/half_duplex_spi_master/TODO.md @@ -14,3 +14,4 @@ Important issues remaining on this core - [ ] implement and test error detection (not done) - [ ] bring a busy flag to the fabric domain using a double flop synchronizer (not done) - [x] rewrite to use a FSM running on double clock speed to only have positive edge sensitivity (not done) +- [ ] rewrite logic so that for sure only 1 read value is written to the fabric fifo (not done) \ No newline at end of file diff --git a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp index bd31e659..72e68b2c 100644 --- a/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp +++ b/HDL/projects/half_duplex_spi_master/half_duplex_spi_master_tb.cpp @@ -50,7 +50,8 @@ int main(int argc, char **argv) VerilatedVcdC *tfp17 = new VerilatedVcdC; VerilatedVcdC *tfp18 = new VerilatedVcdC; VerilatedVcdC *tfp19 = new VerilatedVcdC; - + VerilatedVcdC *tfp20 = new VerilatedVcdC; + top->trace(tfp, 99); // Trace 99 levels of hierarchy tfp->open("sim_reset_n_clock.vcd"); top->reset_n = 0; @@ -786,6 +787,47 @@ int main(int argc, char **argv) } // cleanup sim file tfp19->close(); + + top->trace(tfp20, 99); // Trace 99 levels of hierarchy + tfp20->open("sim_load_value_24w_8r_21reset_mode0.vcd"); + main_time = 0; // Reset time + top->reset_n = 0; + top->spi_cpol = 0; + top->spi_cpha = 0; + // Reset sequence + while (main_time < 22) + { + top->fabric_clk = !top->fabric_clk; + top->eval(); + tfp20->dump(main_time); + main_time++; + } + top->reset_n = 1; + + while (main_time < sim_load_value_fifo_32) + { + if (main_time == 22) + { + top->transaction_length = 32; + top->transaction_data = 0xAAA00F0F; + top->transaction_rw_mask = 0xFFFFFF00; + } + else + { + top->transaction_length = 0; + top->transaction_data = 0x00000000; + top->transaction_rw_mask = 0x00000000; + } + + top->fabric_clk = !top->fabric_clk; + top->eval(); // Evaluate model + tfp20->dump(main_time); // Dump signals to VCD file + + main_time++; + } + // cleanup sim file + tfp20->close(); + delete top; return 0; } From 182ef9d7bf8ee5e10dc70171c4f4848cf51fbeae Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Mon, 23 Dec 2024 13:12:31 -0800 Subject: [PATCH 89/96] added the Avent ZUB-1CG MPSoc board --- HDL/boards/zub1cg/brd/1.2/LICENSE | 15 + HDL/boards/zub1cg/brd/1.2/ZUBoard_temp.xdc | 5 + HDL/boards/zub1cg/brd/1.2/board.xml | 580 ++++++++++++++++ HDL/boards/zub1cg/brd/1.2/changelog.txt | 6 + HDL/boards/zub1cg/brd/1.2/part0_pins.xml | 126 ++++ HDL/boards/zub1cg/brd/1.2/preset.xml | 736 +++++++++++++++++++++ HDL/boards/zub1cg/brd/1.2/xitem.json | 40 ++ HDL/boards/zub1cg/brd/1.2/zub1cg_top.png | Bin 0 -> 497659 bytes HDL/scripts/Vivado_ocra_init.tcl | 2 +- 9 files changed, 1509 insertions(+), 1 deletion(-) create mode 100644 HDL/boards/zub1cg/brd/1.2/LICENSE create mode 100644 HDL/boards/zub1cg/brd/1.2/ZUBoard_temp.xdc create mode 100644 HDL/boards/zub1cg/brd/1.2/board.xml create mode 100644 HDL/boards/zub1cg/brd/1.2/changelog.txt create mode 100644 HDL/boards/zub1cg/brd/1.2/part0_pins.xml create mode 100644 HDL/boards/zub1cg/brd/1.2/preset.xml create mode 100644 HDL/boards/zub1cg/brd/1.2/xitem.json create mode 100644 HDL/boards/zub1cg/brd/1.2/zub1cg_top.png diff --git a/HDL/boards/zub1cg/brd/1.2/LICENSE b/HDL/boards/zub1cg/brd/1.2/LICENSE new file mode 100644 index 00000000..64d3aace --- /dev/null +++ b/HDL/boards/zub1cg/brd/1.2/LICENSE @@ -0,0 +1,15 @@ +######################################################################### +Copyright (C) 2021, Avnet Inc - All rights reserved + +Licensed under the Apache License, Version 2.0 (the "License"). You may +not use this file except in compliance with the License. A copy of the +License is located at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations +under the License. +######################################################################### diff --git a/HDL/boards/zub1cg/brd/1.2/ZUBoard_temp.xdc b/HDL/boards/zub1cg/brd/1.2/ZUBoard_temp.xdc new file mode 100644 index 00000000..0225a080 --- /dev/null +++ b/HDL/boards/zub1cg/brd/1.2/ZUBoard_temp.xdc @@ -0,0 +1,5 @@ +set_property PACKAGE_PIN G7 [get_ports {click_spi_pl_ss_io[0]}] +set_property PACKAGE_PIN G5 [get_ports {click_spi_pl_ss_io[1]}] + +set_property IOSTANDARD LVCMOS18 [get_ports {click_spi_pl_ss_io[1]}] +set_property IOSTANDARD LVCMOS18 [get_ports {click_spi_pl_ss_io[0]}] \ No newline at end of file diff --git a/HDL/boards/zub1cg/brd/1.2/board.xml b/HDL/boards/zub1cg/brd/1.2/board.xml new file mode 100644 index 00000000..2c62c351 --- /dev/null +++ b/HDL/boards/zub1cg/brd/1.2/board.xml @@ -0,0 +1,580 @@ + + + + + + + + + + ZUBoard 1CG DK Image + + + + + Rev 1 + + + 1.2 + + ZUBoard 1CG Development Board + + + + + + + + + + + + + + + + + + + + + + + + + + + Zynq UltraScale+ part on the board + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Click Reset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PL Push Button + + + + + + + + + + + + + + + PL RGB LED 1 + + + + + + + + + + + + + + + PL RGB LED 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PL Click I2C + + + + + + + + + PL Click Reset Input + + + + + PL Click SPI + + + + + PL Click UART + + + + + PL Push Button + + + + + PL RGB LED, 2 to 0, Active High + + + PL RGB LED, 2 to 0, Active High + + + + + PL Temp Sensor I2C + + + + + HSIO DNA I2C + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HDL/boards/zub1cg/brd/1.2/changelog.txt b/HDL/boards/zub1cg/brd/1.2/changelog.txt new file mode 100644 index 00000000..a65eb0cc --- /dev/null +++ b/HDL/boards/zub1cg/brd/1.2/changelog.txt @@ -0,0 +1,6 @@ +1.2 +Updated company to Tria (an Avnet Company) +Updated search keywords + +1.0 +Original version diff --git a/HDL/boards/zub1cg/brd/1.2/part0_pins.xml b/HDL/boards/zub1cg/brd/1.2/part0_pins.xml new file mode 100644 index 00000000..0c2b89a2 --- /dev/null +++ b/HDL/boards/zub1cg/brd/1.2/part0_pins.xml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HDL/boards/zub1cg/brd/1.2/preset.xml b/HDL/boards/zub1cg/brd/1.2/preset.xml new file mode 100644 index 00000000..3bf146c4 --- /dev/null +++ b/HDL/boards/zub1cg/brd/1.2/preset.xml @@ -0,0 +1,736 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HDL/boards/zub1cg/brd/1.2/xitem.json b/HDL/boards/zub1cg/brd/1.2/xitem.json new file mode 100644 index 00000000..a18f39a7 --- /dev/null +++ b/HDL/boards/zub1cg/brd/1.2/xitem.json @@ -0,0 +1,40 @@ +{ + "config": { + "items": [ + { + "infra": { + "name": "ZUBoard_1CG", + "display": "ZUBoard 1CG Development Board", + "revision": "1.2", + "description": "ZUBoard 1CG Development Board", + + "company": "Tria (an Avnet Company)", + "company_display": "Tria (an Avnet Company)", + "author": "Avnet", + "contributors": [ + { + "group": "Avnet", + "url": "avnet.me/ZUBoard-1CG" + } + ], + "category": "Evaluation Boards", + "website": "avnet.me/ZUBoard-1CG", + "search-keywords": [ + "zuboard", + "zu1", + "1cg", + "devkit", + "avnet", + "tria", + "avnet.com", + "tria-technologies.com", + "board", + "Evaluation Boards" + ] + } + } + ] + }, + "_major": 1, + "_minor": 0 +} diff --git a/HDL/boards/zub1cg/brd/1.2/zub1cg_top.png b/HDL/boards/zub1cg/brd/1.2/zub1cg_top.png new file mode 100644 index 0000000000000000000000000000000000000000..2cf641611ee76e35531709d8e98506f2fbd42519 GIT binary patch literal 497659 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ȟyVV6A^m0%H|e@I!hb305UkH8F`(e@b;TMI#Kt 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 Date: Tue, 17 Jun 2025 16:02:53 -0700 Subject: [PATCH 90/96] added some vivado framework to test and evaluate the async fifo --- HDL/projects/async_fifo/sim/.gitignore | 9 ++ HDL/projects/async_fifo/sim/async_fifo.xdc | 18 ++++ HDL/projects/async_fifo/sim/async_fifo_tb.v | 85 +++++++++++++++++++ .../sim/simulate_async_fifo_project.tcl | 22 +++++ .../sim/synth_async_fifo_project.tcl | 33 +++++++ 5 files changed, 167 insertions(+) create mode 100644 HDL/projects/async_fifo/sim/.gitignore create mode 100644 HDL/projects/async_fifo/sim/async_fifo.xdc create mode 100644 HDL/projects/async_fifo/sim/async_fifo_tb.v create mode 100644 HDL/projects/async_fifo/sim/simulate_async_fifo_project.tcl create mode 100644 HDL/projects/async_fifo/sim/synth_async_fifo_project.tcl diff --git a/HDL/projects/async_fifo/sim/.gitignore b/HDL/projects/async_fifo/sim/.gitignore new file mode 100644 index 00000000..638db2ad --- /dev/null +++ b/HDL/projects/async_fifo/sim/.gitignore @@ -0,0 +1,9 @@ +# Ignore text files +*.txt + +# Ignore log files +*.log + +# Ignore Vivado journal files +*.jou + diff --git a/HDL/projects/async_fifo/sim/async_fifo.xdc b/HDL/projects/async_fifo/sim/async_fifo.xdc new file mode 100644 index 00000000..29bff1cc --- /dev/null +++ b/HDL/projects/async_fifo/sim/async_fifo.xdc @@ -0,0 +1,18 @@ +## Clock constraints +# Set the fastest clock speed you may use in your project +create_clock -name wr_clk -period 4.000 [get_ports wr_clk] ;# 250 MHz +create_clock -name rd_clk -period 10.000 [get_ports rd_clk] ;# 100 MHz + +## Clock groups: prevent Vivado from timing between async domains +set_clock_groups -asynchronous -group {wr_clk} -group {rd_clk} + +## Optional: false paths between clock domains +set_false_path -from [get_clocks wr_clk] -to [get_clocks rd_clk] +set_false_path -from [get_clocks rd_clk] -to [get_clocks wr_clk] + +## Optional: false paths between synchronizer stages (safe if using proper double flops) +set_false_path -from [get_cells -hierarchical -filter {NAME =~ "*wr_ptr_gray_rd_clk_sync1_reg[*]"}] +set_false_path -from [get_cells -hierarchical -filter {NAME =~ "*wr_ptr_gray_rd_clk_sync2_reg[*]"}] +set_false_path -from [get_cells -hierarchical -filter {NAME =~ "*rd_ptr_gray_wr_clk_sync1_reg[*]"}] +set_false_path -from [get_cells -hierarchical -filter {NAME =~ "*rd_ptr_gray_wr_clk_sync2_reg[*]"}] + diff --git a/HDL/projects/async_fifo/sim/async_fifo_tb.v b/HDL/projects/async_fifo/sim/async_fifo_tb.v new file mode 100644 index 00000000..155599a3 --- /dev/null +++ b/HDL/projects/async_fifo/sim/async_fifo_tb.v @@ -0,0 +1,85 @@ +// async_fifo_tb.v + +`timescale 1ns/1ps + +module async_fifo_tb; + + localparam DATA_WIDTH = 16; + localparam ADDR_WIDTH = 4; + + reg wr_clk = 0; + reg wr_rst_n = 0; + reg wr_en = 0; + reg [DATA_WIDTH-1:0] wr_data = 0; + wire full; + wire almost_full; + + reg rd_clk = 0; + reg rd_rst_n = 0; + wire [DATA_WIDTH-1:0] rd_data; + wire rd_valid; + reg rd_en = 0; + wire empty; + wire almost_empty; + + async_fifo #( + .DATA_WIDTH(DATA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH) + ) dut ( + .wr_clk(wr_clk), + .wr_rst_n(wr_rst_n), + .wr_data(wr_data), + .wr_en(wr_en), + .full(full), + .almost_full(almost_full), + + .rd_clk(rd_clk), + .rd_rst_n(rd_rst_n), + .rd_data(rd_data), + .rd_valid(rd_valid), + .rd_en(rd_en), + .empty(empty), + .almost_empty(almost_empty) + ); + + // Write clock: 10ns period (100 MHz) + always #5 wr_clk = ~wr_clk; + + // Read clock: 12ns period (~83.3 MHz) + always #6 rd_clk = ~rd_clk; + + initial begin + $dumpfile("fifo_tb.vcd"); + $dumpvars(0, async_fifo_tb); + + #0 wr_rst_n = 0; rd_rst_n = 0; + #20 wr_rst_n = 1; rd_rst_n = 1; + + // Write 20 values into FIFO + repeat (20) begin + @(posedge wr_clk); + if (!full) begin + wr_en <= 1; + wr_data <= wr_data + 1; + end else begin + wr_en <= 0; + end + end + wr_en <= 0; + + // Wait a few cycles + repeat (10) @(posedge wr_clk); + + // Begin reading + repeat (25) begin + @(posedge rd_clk); + rd_en <= ~empty; + end + rd_en <= 0; + + // End simulation + repeat (10) @(posedge rd_clk); + $finish; + end +endmodule + diff --git a/HDL/projects/async_fifo/sim/simulate_async_fifo_project.tcl b/HDL/projects/async_fifo/sim/simulate_async_fifo_project.tcl new file mode 100644 index 00000000..dfe73550 --- /dev/null +++ b/HDL/projects/async_fifo/sim/simulate_async_fifo_project.tcl @@ -0,0 +1,22 @@ +# Create a new Vivadc prcject for async FIFO +create_project -force async_fifo_proj ./async_fifo_proj -part xc7z010clg400-1 + +# Set the top module for simulation +set_property top async_fifo_tb [current_fileset -simset] + +# Add Verilog source files (adjust paths as needed) +add_files -norecurse ../async_fifo.sv +add_files -fileset sim_1 -norecurse ./async_fifo_tb.v + +# Add constraints +add_files -fileset constrs_1 async_fifo.xdc + +# Set simulation top module +set_property top async_fifo_tb [get_filesets sim_1] + +# Optional: set simulation language +set_property target_language Verilog [current_project] + +# Launch simulation +launch_simulation + diff --git a/HDL/projects/async_fifo/sim/synth_async_fifo_project.tcl b/HDL/projects/async_fifo/sim/synth_async_fifo_project.tcl new file mode 100644 index 00000000..0a94bce7 --- /dev/null +++ b/HDL/projects/async_fifo/sim/synth_async_fifo_project.tcl @@ -0,0 +1,33 @@ +# Create and open your project +create_project -f async_fifo async_fifo_proj -part xc7z010clg400-1 +add_files ../async_fifo.sv async_fifo_tb.v +read_xdc async_fifo.xdc +set_property top async_fifo [current_fileset] + +# Run synthesis +launch_runs synth_1 -jobs 4 +wait_on_run synth_1 + +# Open synthesized design +open_run synth_1 + +# Generate reports +report_utilization -file utilization_report.txt +report_timing_summary -file timing_summary.txt +report_timing -sort_by group -max_paths 10 -file detailed_timing.txt + +file delete -force failing_timing_paths.txt +report_timing -max_paths 100 -slack_lesser_than 0 -file failing_timing_paths.txt + +# some more interesting outputs +# Report all registers with ASYNC_REG attribute +set outfile [open "async_reg_report.txt" "w"] +set all_cells [get_cells -hierarchical -filter {PRIMITIVE_TYPE =~ "FLOP_LATCH.*"}] + +foreach cell $all_cells { + if {[get_property ASYNC_REG $cell] == 1} { + puts $outfile "$cell" + } +} +close $outfile +puts "✅ async_reg_report.txt has been generated." From 498e782036cc587b36f87c702ba890399d3db2e5 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Tue, 17 Jun 2025 16:30:35 -0700 Subject: [PATCH 91/96] Modified the async FIFO to remove all asynchronous resets - BRAMs do not support asynchronous resets and could not be inferred so long the async resets were in the design. Added a registered output to the FIFO, which is standard --- HDL/projects/async_fifo/async_fifo.sv | 74 ++++++++++++++++----------- HDL/projects/async_fifo/main.cpp | 2 +- 2 files changed, 44 insertions(+), 32 deletions(-) diff --git a/HDL/projects/async_fifo/async_fifo.sv b/HDL/projects/async_fifo/async_fifo.sv index e5e02d19..4760782b 100644 --- a/HDL/projects/async_fifo/async_fifo.sv +++ b/HDL/projects/async_fifo/async_fifo.sv @@ -1,3 +1,4 @@ +`timescale 1ns/1ps module async_fifo #( parameter DATA_WIDTH = 16, parameter ADDR_WIDTH = 4, // FIFO depth = 2^ADDR_WIDTH @@ -14,6 +15,7 @@ module async_fifo #( input wire rd_clk, input wire rd_rst_n, output wire [DATA_WIDTH-1:0] rd_data, + output wire rd_valid, input wire rd_en, output wire empty, output wire almost_empty @@ -24,7 +26,6 @@ module async_fifo #( binary_to_gray = (bin >> 1) ^ bin; endfunction - // Function to convert Gray code to binary function [ADDR_WIDTH:0] gray_to_binary(input [ADDR_WIDTH:0] gray); integer i; @@ -35,18 +36,18 @@ module async_fifo #( end endfunction - // FIFO memory - reg [DATA_WIDTH-1:0] mem [0:(1<= ((1 << ADDR_WIDTH) - ALMOST_FULL_THRESHOLD)); - // ALMOST EMPTY calculation is done in read clock domain - wire [ADDR_WIDTH:0] fifo_count_rd_clk; - assign fifo_count_rd_clk = wr_ptr_bin_rd_clk - rd_ptr_bin; - + wire [ADDR_WIDTH:0] fifo_count_rd_clk = wr_ptr_bin_rd_clk - rd_ptr_bin; assign almost_empty = (fifo_count_rd_clk <= ALMOST_EMPTY_THRESHOLD); endmodule diff --git a/HDL/projects/async_fifo/main.cpp b/HDL/projects/async_fifo/main.cpp index c0b40f8f..b108c91a 100644 --- a/HDL/projects/async_fifo/main.cpp +++ b/HDL/projects/async_fifo/main.cpp @@ -96,7 +96,7 @@ int main(int argc, char **argv) } // Data integrity check - if (top->rd_en && !top->empty) + if (top->rd_valid) { if (top->rd_data != expected_data) { From 894970d25a1ea3ff499912f031903cca4f68822a Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Tue, 17 Jun 2025 16:32:40 -0700 Subject: [PATCH 92/96] this is not needed anymore --- HDL/projects/async_fifo/tb_async_fifo.sv | 137 ----------------------- 1 file changed, 137 deletions(-) delete mode 100644 HDL/projects/async_fifo/tb_async_fifo.sv diff --git a/HDL/projects/async_fifo/tb_async_fifo.sv b/HDL/projects/async_fifo/tb_async_fifo.sv deleted file mode 100644 index 409a537b..00000000 --- a/HDL/projects/async_fifo/tb_async_fifo.sv +++ /dev/null @@ -1,137 +0,0 @@ -module tb_async_fifo; - - // Parameters - parameter DATA_WIDTH = 16; - parameter ADDR_WIDTH = 4; // FIFO depth = 2^ADDR_WIDTH - - // Signals - reg wr_clk; - reg wr_rst_n; - reg [DATA_WIDTH-1:0] wr_data; - reg wr_en; - wire full; - - reg rd_clk; - reg rd_rst_n; - wire [DATA_WIDTH-1:0] rd_data; - reg rd_en; - wire empty; - - integer write_count; - integer read_count; - reg [DATA_WIDTH-1:0] expected_data; - - // Instantiate the FIFO - async_fifo #( - .DATA_WIDTH(DATA_WIDTH), - .ADDR_WIDTH(ADDR_WIDTH) - ) fifo_inst ( - .wr_clk (wr_clk), - .wr_rst_n (wr_rst_n), - .wr_data (wr_data), - .wr_en (wr_en), - .full (full), - .rd_clk (rd_clk), - .rd_rst_n (rd_rst_n), - .rd_data (rd_data), - .rd_en (rd_en), - .empty (empty) - ); - - // Clock generation - initial begin - wr_clk = 0; - forever #5 wr_clk = ~wr_clk; // 100 MHz clock - end - - initial begin - rd_clk = 0; - forever #7 rd_clk = ~rd_clk; // Approximately 71.4 MHz clock - end - - // Reset generation - initial begin - wr_rst_n = 0; - rd_rst_n = 0; - #20; - wr_rst_n = 1; - rd_rst_n = 1; - end - - // Write process - initial begin - wr_en = 0; - wr_data = 0; - write_count = 0; - @(posedge wr_rst_n); - @(posedge wr_clk); - - // Write data until a certain count - while (write_count < 50) begin - @(posedge wr_clk); - if (!full) begin - wr_en = 1; - wr_data = write_count[DATA_WIDTH-1:0]; - write_count = write_count + 1; - end else begin - wr_en = 0; - end - end - wr_en = 0; - end - - // Read process - initial begin - rd_en = 0; - expected_data = 0; - read_count = 0; - @(posedge rd_rst_n); - @(posedge rd_clk); - - // Read data until all written data is read - while (read_count < 50) begin - @(posedge rd_clk); - if (!empty) begin - rd_en = 1; - end else begin - rd_en = 0; - end - end - rd_en = 0; - end - - // Data integrity check - always @(posedge rd_clk) begin - if (rd_en && !empty) begin - if (rd_data !== expected_data) begin - $display("ERROR: Data Mismatch at time %t: Expected %0d, Got %0d", $time, expected_data, rd_data); - $stop; - end else begin - expected_data <= expected_data + 1; - read_count <= read_count + 1; - end - end - end - - // Monitor full and empty flags - always @(posedge wr_clk) begin - if (full && wr_en) begin - $display("INFO: FIFO is full at time %t", $time); - end - end - - always @(posedge rd_clk) begin - if (empty && rd_en) begin - $display("INFO: FIFO is empty at time %t", $time); - end - end - - // Terminate simulation - initial begin - wait (write_count == 50 && read_count == 50); - #100; // Wait for any remaining activity - $display("Simulation completed successfully at time %t", $time); - $stop; - end - -endmodule From 099a61e5f61058c5af79080308ecc3e3126b5a3b Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Tue, 17 Jun 2025 16:33:05 -0700 Subject: [PATCH 93/96] Just a quick note, to be continued --- HDL/projects/async_fifo/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/HDL/projects/async_fifo/README.md b/HDL/projects/async_fifo/README.md index 71f154ab..ca92ae0b 100644 --- a/HDL/projects/async_fifo/README.md +++ b/HDL/projects/async_fifo/README.md @@ -7,4 +7,10 @@ clock-domain crossing issues. ## Requirements -This project requires verilator and a tool to display the simulations. There are either gtkwave or surfer project that I would recommend. \ No newline at end of file +This project requires verilator and a tool to display the simulations. There are either gtkwave or surfer project that I would recommend. + + +## Stuff + +Run the synthesis check in vivado +vivado -mode batch -source synth_async_fifo_project.tcl \ No newline at end of file From 467898862a325123aa5eea51914c514b25187cdc Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Tue, 17 Jun 2025 16:33:20 -0700 Subject: [PATCH 94/96] set the timing constraint to 200MHz write, which this design will support... --- HDL/projects/async_fifo/sim/async_fifo.xdc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HDL/projects/async_fifo/sim/async_fifo.xdc b/HDL/projects/async_fifo/sim/async_fifo.xdc index 29bff1cc..eba5c512 100644 --- a/HDL/projects/async_fifo/sim/async_fifo.xdc +++ b/HDL/projects/async_fifo/sim/async_fifo.xdc @@ -1,6 +1,6 @@ ## Clock constraints # Set the fastest clock speed you may use in your project -create_clock -name wr_clk -period 4.000 [get_ports wr_clk] ;# 250 MHz +create_clock -name wr_clk -period 5.000 [get_ports wr_clk] ;# 200 MHz create_clock -name rd_clk -period 10.000 [get_ports rd_clk] ;# 100 MHz ## Clock groups: prevent Vivado from timing between async domains From 327f4feae1f0ce1ccd8c96181c75dc481b2ef8e9 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Tue, 17 Jun 2025 20:51:22 -0700 Subject: [PATCH 95/96] test something in this testbench --- HDL/projects/async_fifo/sim/async_fifo_tb.v | 98 +++++++++++++++------ 1 file changed, 69 insertions(+), 29 deletions(-) diff --git a/HDL/projects/async_fifo/sim/async_fifo_tb.v b/HDL/projects/async_fifo/sim/async_fifo_tb.v index 155599a3..ed43e081 100644 --- a/HDL/projects/async_fifo/sim/async_fifo_tb.v +++ b/HDL/projects/async_fifo/sim/async_fifo_tb.v @@ -1,11 +1,10 @@ -// async_fifo_tb.v - `timescale 1ns/1ps module async_fifo_tb; localparam DATA_WIDTH = 16; - localparam ADDR_WIDTH = 4; + localparam ADDR_WIDTH = 5; + localparam MAX_COUNT = 32; reg wr_clk = 0; reg wr_rst_n = 0; @@ -16,12 +15,13 @@ module async_fifo_tb; reg rd_clk = 0; reg rd_rst_n = 0; + reg rd_en = 0; wire [DATA_WIDTH-1:0] rd_data; wire rd_valid; - reg rd_en = 0; wire empty; wire almost_empty; + // Instantiate DUT async_fifo #( .DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH) @@ -42,44 +42,84 @@ module async_fifo_tb; .almost_empty(almost_empty) ); - // Write clock: 10ns period (100 MHz) - always #5 wr_clk = ~wr_clk; + // Clock generation + always #5 wr_clk = ~wr_clk; // 100 MHz + always #6 rd_clk = ~rd_clk; // ~83 MHz - // Read clock: 12ns period (~83.3 MHz) - always #6 rd_clk = ~rd_clk; + // Counters and expected data + integer wr_count = 0; + integer rd_count = 0; + reg [DATA_WIDTH-1:0] expected_data = 0; + // Reset sequence initial begin - $dumpfile("fifo_tb.vcd"); - $dumpvars(0, async_fifo_tb); - - #0 wr_rst_n = 0; rd_rst_n = 0; - #20 wr_rst_n = 1; rd_rst_n = 1; + wr_rst_n = 0; + rd_rst_n = 0; + #20; + wr_rst_n = 1; + rd_rst_n = 1; + end - // Write 20 values into FIFO - repeat (20) begin - @(posedge wr_clk); - if (!full) begin + // Write process + always @(posedge wr_clk) begin + if (wr_rst_n) begin + if (wr_count < MAX_COUNT && !full) begin wr_en <= 1; - wr_data <= wr_data + 1; + wr_data <= wr_count[DATA_WIDTH-1:0]; + wr_count <= wr_count + 1; end else begin wr_en <= 0; end end - wr_en <= 0; - - // Wait a few cycles - repeat (10) @(posedge wr_clk); + end - // Begin reading - repeat (25) begin - @(posedge rd_clk); + // Read process + always @(posedge rd_clk) begin + if (rd_rst_n) begin rd_en <= ~empty; + end else begin + rd_en <= 0; end - rd_en <= 0; + end - // End simulation - repeat (10) @(posedge rd_clk); + // Verification + always @(posedge rd_clk) begin + if (rd_valid) begin + if (rd_data !== expected_data) begin + $display("❌ ERROR: Data mismatch at time %t: expected %0d, got %0d", + $time, expected_data, rd_data); + $fatal; + end else begin + $display("✅ Read %0d at time %t", rd_data, $time); + expected_data <= expected_data + 1; + rd_count <= rd_count + 1; + end + end + end + + // Monitor flags + always @(posedge wr_clk) begin + if (wr_en && full) + $display("⚠️ WARNING: FIFO full while writing at time %t", $time); + end + + always @(posedge rd_clk) begin + if (rd_en && empty) + $display("⚠️ WARNING: FIFO empty while reading at time %t", $time); + end + + // Finish condition + initial begin + wait (rd_count == MAX_COUNT); + #20; + $display("🎉 PASS: All data transferred correctly."); $finish; end -endmodule + // VCD trace + initial begin + $dumpfile("fifo_tb.vcd"); + $dumpvars(0, async_fifo_tb); + end + +endmodule From e6524ea2d77af2895af264faddba5378d40af464 Mon Sep 17 00:00:00 2001 From: Thomas Witzel Date: Tue, 17 Jun 2025 22:10:11 -0700 Subject: [PATCH 96/96] initial checkin of something new --- HDL/projects/complex_mul/complex_mul.sv | 65 +++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 HDL/projects/complex_mul/complex_mul.sv diff --git a/HDL/projects/complex_mul/complex_mul.sv b/HDL/projects/complex_mul/complex_mul.sv new file mode 100644 index 00000000..d5ca1c5d --- /dev/null +++ b/HDL/projects/complex_mul/complex_mul.sv @@ -0,0 +1,65 @@ +module complex_mul #( + parameter WIDTH = 16 +)( + input logic clk, + input logic rst_n, + + input logic signed [WIDTH-1:0] a_real, + input logic signed [WIDTH-1:0] a_imag, + input logic signed [WIDTH-1:0] b_real, + input logic signed [WIDTH-1:0] b_imag, + input logic valid_in, + + output logic signed [2*WIDTH-1:0] result_real, + output logic signed [2*WIDTH-1:0] result_imag, + output logic valid_out +); + + // Stage 1: Multiply — request DSP inference + (* use_dsp = "yes" *) logic signed [2*WIDTH-1:0] ac, bd, ad, bc; + logic v1; + + always_ff @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + ac <= 0; bd <= 0; ad <= 0; bc <= 0; + v1 <= 0; + end else begin + ac <= a_real * b_real; + bd <= a_imag * b_imag; + ad <= a_real * b_imag; + bc <= a_imag * b_real; + v1 <= valid_in; + end + end + + // Stage 2: Add/Sub + logic signed [2*WIDTH-1:0] real_tmp, imag_tmp; + logic v2; + + always_ff @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + real_tmp <= 0; + imag_tmp <= 0; + v2 <= 0; + end else begin + real_tmp <= ac - bd; + imag_tmp <= ad + bc; + v2 <= v1; + end + end + + // Stage 3: Output register + always_ff @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + result_real <= 0; + result_imag <= 0; + valid_out <= 0; + end else begin + result_real <= real_tmp; + result_imag <= imag_tmp; + valid_out <= v2; + end + end + +endmodule +