diff --git a/.gitignore b/.gitignore index 823a8176..ccf8aef1 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,8 @@ Temporary Items !/.gitignore !/README.md +.nvim +venv +virtualenv +.fusesoc_libraries +fusesoc.conf diff --git a/firmware/ip/xcom/component.xml b/firmware/ip/xcom/component.xml new file mode 100755 index 00000000..a90df7d1 --- /dev/null +++ b/firmware/ip/xcom/component.xml @@ -0,0 +1,1652 @@ + + + QICK + QICK + xcom + 1.0 + + + s_axi + + + + + + + + + AWADDR + + + s_axi_awaddr + + + + + AWPROT + + + s_axi_awprot + + + + + AWVALID + + + s_axi_awvalid + + + + + AWREADY + + + s_axi_awready + + + + + WDATA + + + s_axi_wdata + + + + + WSTRB + + + s_axi_wstrb + + + + + WVALID + + + s_axi_wvalid + + + + + WREADY + + + s_axi_wready + + + + + BRESP + + + s_axi_bresp + + + + + BVALID + + + s_axi_bvalid + + + + + BREADY + + + s_axi_bready + + + + + ARADDR + + + s_axi_araddr + + + + + ARPROT + + + s_axi_arprot + + + + + ARVALID + + + s_axi_arvalid + + + + + ARREADY + + + s_axi_arready + + + + + RDATA + + + s_axi_rdata + + + + + RRESP + + + s_axi_rresp + + + + + RVALID + + + s_axi_rvalid + + + + + RREADY + + + s_axi_rready + + + + + + i_core_rstn + + + + + + + RST + + + i_core_rstn + + + + + + POLARITY + ACTIVE_LOW + + + + + i_ps_rstn + + + + + + + RST + + + i_ps_rstn + + + + + + POLARITY + ACTIVE_LOW + + + + + i_time_rstn + + + + + + + RST + + + i_time_rstn + + + + + + POLARITY + ACTIVE_LOW + + + + + i_core_clk + + + + + + + CLK + + + i_core_clk + + + + + + ASSOCIATED_RESET + i_core_rstn + + + ASSOCIATED_BUSIF + QICK_PERIPHERAL + + + + + i_ps_clk + + + + + + + CLK + + + i_ps_clk + + + + + + ASSOCIATED_RESET + i_ps_rstn + + + ASSOCIATED_BUSIF + s_axi + + + + + i_time_clk + + + + + + + CLK + + + i_time_clk + + + + + + ASSOCIATED_RESET + i_time_rstn + + + ASSOCIATED_BUSIF + PROC_CTRL:CORE_CTRL:TIME_CTRL + + + + + PROC_CTRL + Processor control interface + Processor interface control signals + + + + + + + start + + + o_proc_start + + + + + stop + + + o_proc_stop + + + + + + NUM_READ_OUTSTANDING + + + + NUM_WRITE_OUTSTANDING + + + + + + + true + + + + + + CORE_CTRL + + + + + + + start + + + o_core_start + + + + + stop + + + o_core_stop + + + + + + + true + + + + + + TIME_CTRL + + + + + + + time_dt + + + o_time_update_data + + + + + time_rst + + + o_time_rst + + + + + time_updt + + + o_time_update + + + + + + + true + + + + + + QICK_PERIPHERAL + + + + + + + flag + + + o_core_flag + + + + + b_dt + + + i_core_data2 + + + + + a_dt + + + i_core_data1 + + + + + rdy + + + o_core_ready + + + + + Enable + + + i_core_en + + + + + dt_in_2 + + + o_core_data2 + + + + + Operation + + + i_core_op + + + + + dt_in_1 + + + o_core_data1 + + + + + dt_valid + + + o_core_valid + + + + + + NUM_READ_OUTSTANDING + + + + NUM_WRITE_OUTSTANDING + + + + + + i_xcom_clk + + + + + + + CLK + + + i_xcom_clk + + + + + + o_xcom_clk + + + + + + + CLK + + + o_xcom_clk + + + + + + + + s_axi + s_axi + + reg0 + reg0 + 0x0 + 4096 + 32 + register + + + + + + + xilinx_anylanguagesynthesis + Synthesis + :vivado.xilinx.com:synthesis + SystemVerilog + xcom + + xilinx_anylanguagesynthesis_view_fileset + + + + viewChecksum + 04c4fcc1 + + + + + xilinx_anylanguagebehavioralsimulation + Simulation + :vivado.xilinx.com:simulation + SystemVerilog + xcom + + xilinx_anylanguagebehavioralsimulation_view_fileset + + + + viewChecksum + 04c4fcc1 + + + + + xilinx_xpgui + UI Layout + :vivado.xilinx.com:xgui.ui + + xilinx_xpgui_view_fileset + + + + viewChecksum + c3ef407c + + + + + xilinx_utilityxitfiles + Utility XIT/TTCL + :vivado.xilinx.com:xit.util + + xilinx_utilityxitfiles_view_fileset + + + + viewChecksum + 5fe144f7 + + + + + + + i_ps_clk + + in + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_ps_rstn + + in + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_core_clk + + in + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_core_rstn + + in + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_time_clk + + in + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_time_rstn + + in + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_core_en + + in + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_core_op + + in + + 4 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_core_data1 + + in + + 31 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_core_data2 + + in + + 31 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_core_ready + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_core_data1 + + out + + 31 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_core_data2 + + out + + 31 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_core_valid + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_core_flag + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_sync + + in + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + + true + + + + + + o_proc_start + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_proc_stop + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_time_rst + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_time_update + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_time_update_data + + out + + 31 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_core_start + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_core_stop + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_xcom_id + + out + + 3 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_xcom_clk + + in + + 1 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + i_xcom_data + + in + + 1 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_xcom_clk + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + o_xcom_data + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_axi_awaddr + + in + + 5 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_axi_awprot + + in + + 2 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_axi_awvalid + + in + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_axi_awready + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_axi_wdata + + in + + 31 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_axi_wstrb + + in + + 3 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 1 + + + + + s_axi_wvalid + + in + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_axi_wready + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_axi_bresp + + out + + 1 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_axi_bvalid + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_axi_bready + + in + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_axi_araddr + + in + + 5 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_axi_arprot + + in + + 2 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_axi_arvalid + + in + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + s_axi_arready + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_axi_rdata + + out + + 31 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_axi_rresp + + out + + 1 + 0 + + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_axi_rvalid + + out + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + + + s_axi_rready + + in + + + logic + xilinx_anylanguagesynthesis + xilinx_anylanguagebehavioralsimulation + + + + 0 + + + + + + + NCH + Nch + 2 + + + SYNC + Sync + 1 + + + DEBUG + Debug + 1 + + + + + + choice_list_8af5a703 + 0 + 1 + + + choice_list_9d8b0d81 + ACTIVE_HIGH + ACTIVE_LOW + + + choice_pairs_2d96f706 + 0 + 1 + + + + + xilinx_anylanguagesynthesis_view_fileset + + src/fxp_pkg.sv + systemVerilogSource + IMPORTED_FILE + + + src/narrow_en_signal.sv + systemVerilogSource + IMPORTED_FILE + + + src/qick_pkg.sv + systemVerilogSource + IMPORTED_FILE + + + src/req_ack_cmd.sv + systemVerilogSource + IMPORTED_FILE + + + src/rising_edge_det.sv + systemVerilogSource + IMPORTED_FILE + + + src/rx_cmd.sv + systemVerilogSource + IMPORTED_FILE + + + src/synchronizer.sv + systemVerilogSource + IMPORTED_FILE + + + src/tx_cmd.sv + systemVerilogSource + IMPORTED_FILE + + + src/wide_en_signal.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_axil_slv.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_cdc.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_cmd.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_link_rx.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_link_tx.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_qctrl.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_txrx.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom.sv + systemVerilogSource + CHECKSUM_47b71179 + IMPORTED_FILE + + + + xilinx_anylanguagebehavioralsimulation_view_fileset + + src/fxp_pkg.sv + systemVerilogSource + IMPORTED_FILE + + + src/narrow_en_signal.sv + systemVerilogSource + IMPORTED_FILE + + + src/qick_pkg.sv + systemVerilogSource + IMPORTED_FILE + + + src/req_ack_cmd.sv + systemVerilogSource + IMPORTED_FILE + + + src/rising_edge_det.sv + systemVerilogSource + IMPORTED_FILE + + + src/rx_cmd.sv + systemVerilogSource + IMPORTED_FILE + + + src/synchronizer.sv + systemVerilogSource + IMPORTED_FILE + + + src/tx_cmd.sv + systemVerilogSource + IMPORTED_FILE + + + src/wide_en_signal.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_axil_slv.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_cdc.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_cmd.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_link_rx.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_link_tx.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_qctrl.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom_txrx.sv + systemVerilogSource + IMPORTED_FILE + + + src/xcom.sv + systemVerilogSource + IMPORTED_FILE + + + + xilinx_xpgui_view_fileset + + xgui/xcom_v1_0.tcl + tclSource + CHECKSUM_c3ef407c + XGUI_VERSION_2 + + + + xilinx_utilityxitfiles_view_fileset + + ../../common_ip_files/ip_logos/logoQICK_128x128.png + image + LOGO + + + + Board inter-communication and synchronization core + + + NCH + NCH + Number of channels + 2 + + + SYNC + SYNC + Enable synchronization pulse + 1 + + + DEBUG + DEBUG + Enable debug ports + 1 + + + Component_Name + xcom_v1_0 + + + + + + kintex7 + kintex7l + artix7 + artix7l + aartix7 + zynq + azynq + spartan7 + aspartan7 + virtexuplus + virtexuplusHBM + virtexuplus58g + kintexuplus + artixuplus + zynquplus + kintexu + + + /QICK/QICK_Peripheral + + xcom_v1_0 + level_1 + package_project + Quantum Instrumentation Control Kit + https://github.com/openquantumhardware/qick/ + 10 + 2025-06-30T16:07:02Z + + + 2023.1 + + + + + + + + + diff --git a/firmware/ip/xcom/src/fxp_pkg.sv b/firmware/ip/xcom/src/fxp_pkg.sv new file mode 100755 index 00000000..92ad2d3c --- /dev/null +++ b/firmware/ip/xcom/src/fxp_pkg.sv @@ -0,0 +1,30 @@ +package fxp_pkg; + typedef struct packed { + bit sign; + int unsigned nb; + int unsigned nf; + } repr_t; + + typedef enum {SUM, MULT} fxp_op; + + function repr_t get_repr(repr_t val1, repr_t val2, fxp_op op); + case (op) + SUM: begin + return '{ + sign: val1.sign | val2.sign, + nb: (val1.nb > val2.nb ? val1.nb : val2.nb) + 1 + 32'({(val1.sign^val2.sign)}), + nf: val1.nf > val2.nf ? val1.nf : val2.nf + }; + end + MULT: begin + return '{ + sign: val1.sign | val2.sign, + nb: val1.nb + val2.nb + 32'({(val1.sign^val2.sign)}), + nf: val1.nf + val2.nf + }; + end + default: $fatal(1, "Invalid operation"); + endcase + endfunction + +endpackage diff --git a/firmware/ip/xcom/src/narrow_en_signal.sv b/firmware/ip/xcom/src/narrow_en_signal.sv new file mode 100755 index 00000000..c3b08a5f --- /dev/null +++ b/firmware/ip/xcom/src/narrow_en_signal.sv @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: narrow_en_signal.sv +// Project: UTILS +// Description: Enable pulse generator for a narrow enable signal. +// It serves as clock domain crossing (CDC) logic. +// +// Change history: 05/15/25 - Created by @lharnaldi +// +/////////////////////////////////////////////////////////////////////////////// +module narrow_en_signal( + input logic i_clk , + input logic i_rstn , + input logic i_en , + output logic o_en +); + + logic en_strobe; + logic en_q; + + //ad-hoc stretcher + always_ff @ (posedge i_en, posedge en_strobe) begin + if( en_strobe ) begin + en_q <= 1'b0; + end else begin + en_q <= 1'b1; + end + end + + //slow enable pulse generator + synchronizer#( + .NB(1) + ) u_sync( + .i_clk ( i_clk ), + .i_rstn ( i_rstn ), + .i_async ( en_q ), + .o_sync ( en_strobe ) + ); + + rising_edge_det u_edge_detect( + .i_clk ( i_clk ), + .i_rstn ( i_rstn ), + .i_strobe ( en_strobe ), + .o_pulse ( o_en ) + ); + +endmodule diff --git a/firmware/ip/xcom/src/qick_pkg.sv b/firmware/ip/xcom/src/qick_pkg.sv new file mode 100755 index 00000000..27d22bff --- /dev/null +++ b/firmware/ip/xcom/src/qick_pkg.sv @@ -0,0 +1,176 @@ +package qick_pkg; + import fxp_pkg::*; + + parameter VERSION = "0.1.0"; + + /////////// XCOM //////////// + //Opcodes + parameter XCOM_RST = 4'b1111 ;//LOC command + parameter XCOM_WRITE_MEM = 4'b0011 ;//LOC command + parameter XCOM_WRITE_REG = 4'b0010 ;//LOC command + parameter XCOM_WRITE_FLAG = 4'b0001 ;//LOC command + parameter XCOM_SET_ID = 4'b0000 ;//LOC command + parameter XCOM_RFU2 = 4'b1111 ; + parameter XCOM_RFU1 = 4'b1101 ; + parameter XCOM_QCTRL = 4'b1011 ; + parameter XCOM_UPDATE_DT32 = 4'b1110 ; + parameter XCOM_UPDATE_DT16 = 4'b1100 ; + parameter XCOM_UPDATE_DT8 = 4'b1010 ; + parameter XCOM_AUTO_ID = 4'b1001 ; + parameter XCOM_QRST_SYNC = 4'b1000 ; + parameter XCOM_SEND_32BIT_2= 4'b0111 ; + parameter XCOM_SEND_32BIT_1= 4'b0110 ; + parameter XCOM_SEND_16BIT_2= 4'b0101 ; + parameter XCOM_SEND_16BIT_1= 4'b0100 ; + parameter XCOM_SEND_8BIT_2 = 4'b0011 ; + parameter XCOM_SEND_8BIT_1 = 4'b0010 ; + parameter XCOM_SET_FLAG = 4'b0001 ; + parameter XCOM_CLEAR_FLAG = 4'b0000 ; + + typedef struct packed { + logic [32-1:0] xcom_debug ; + logic [32-1:0] xcom_status ; + logic [32-1:0] xcom_tx_data ; + logic [32-1:0] xcom_rx_data ; + logic [32-1:0] xcom_tbd_1 ;//To be defined 1 + logic [32-1:0] xcom_mem ; + logic [32-1:0] xcom_data_2 ; + logic [32-1:0] xcom_data_1 ; + logic xcom_flag ; + logic [5-1:0] board_id ; + logic [32-1:0] xcom_tbd_2 ; //To be defined 2 + logic [5-1:0] axi_addr ; + logic [32-1:0] axi_data_2 ; + logic [32-1:0] axi_data_1 ; + logic [5-1:0] xcom_cfg ; + logic [6-1:0] xcom_ctrl ; + } xcom_register_t; + + typedef struct packed { + logic [5-1:0] rst ;//LOC command + logic [5-1:0] write_mem ;//LOC command + logic [5-1:0] write_reg ;//LOC command + logic [5-1:0] write_flag ;//LOC command + logic [5-1:0] set_id ;//LOC command + logic [5-1:0] rfu2 ; + logic [5-1:0] rfu1 ; + logic [5-1:0] qctrl ; + logic [5-1:0] update_dt32 ; + logic [5-1:0] update_dt16 ; + logic [5-1:0] update_dt8 ; + logic [5-1:0] auto_id ; + logic [5-1:0] qrst_sync ; + logic [5-1:0] send_32bit_2 ; + logic [5-1:0] send_32bit_1 ; + logic [5-1:0] send_16bit_2 ; + logic [5-1:0] send_16bit_1 ; + logic [5-1:0] send_8bit_2 ; + logic [5-1:0] send_8bit_1 ; + logic [5-1:0] set_flag ; + logic [5-1:0] clear_flag ; + } xcom_cmd_t; + + typedef struct packed { + logic [5-1:0] rst ;//LOC command + logic [5-1:0] write_mem ;//LOC command + logic [5-1:0] write_reg ;//LOC command + logic [5-1:0] write_flag ;//LOC command + logic [5-1:0] set_id ;//LOC command + logic [5-1:0] rfu2 ; + logic [5-1:0] rfu1 ; + logic [5-1:0] qctrl ; + logic [5-1:0] update_dt32 ; + logic [5-1:0] update_dt16 ; + logic [5-1:0] update_dt8 ; + logic [5-1:0] auto_id ; + logic [5-1:0] qrst_sync ; + logic [5-1:0] send_32bit_2 ; + logic [5-1:0] send_32bit_1 ; + logic [5-1:0] send_16bit_2 ; + logic [5-1:0] send_16bit_1 ; + logic [5-1:0] send_8bit_2 ; + logic [5-1:0] send_8bit_1 ; + logic [5-1:0] set_flag ; + logic [5-1:0] clear_flag ; + } xcom_opcode_t; + + //////////// CONFIG FRAME ////////// + localparam NB_CONFIG_FRAME = 64; + + //////////// DDS ///////////////// + localparam N_CHN_FREQ = 2; + localparam NB_DDS_CFG = 32; + localparam repr_t dds_freq_repr = '{1, 16, 15}; + typedef logic signed [dds_freq_repr.nb-1:0] dds_freq_t [N_CHN_FREQ][2]; + typedef logic signed [N_CHN_FREQ-1:0][1:0][dds_freq_repr.nb-1:0] dds_freq_packed_t; + typedef logic [N_CHN_FREQ-1:0][NB_DDS_CFG-1:0] dds_config_packed_t; + + /////////// ADC //////////// + localparam int unsigned N_CHN_ADC = 2; + + localparam repr_t rcv_sample_repr = '{1, 16, 15}; + typedef logic signed [1:0][rcv_sample_repr.nb-1:0] packed_rcv_sample_t; + typedef logic signed [N_CHN_ADC-1:0][1:0][rcv_sample_repr.nb-1:0] packed_rcv_sample_vec_t; + + //////////// MIXER ///////////////// + localparam repr_t mixed_sample_full_repr = get_repr( + get_repr(rcv_sample_repr, dds_freq_repr, MULT), + get_repr(rcv_sample_repr, dds_freq_repr, MULT), + SUM + ); + typedef logic signed [mixed_sample_full_repr.nb-1:0] mixed_sample_fr_t [2]; + + localparam repr_t mixed_sample_repr = '{1, 16, 15}; + typedef logic signed [1:0][mixed_sample_repr.nb-1:0] mixed_sample_packed_t; + + //////////// DOWNSAMPLER ///////////////// + + localparam repr_t dec_sample_repr = '{1, 16, 15}; + typedef logic signed [1:0][dec_sample_repr.nb-1:0] dec_sample_t; + + //////////// CHANNELIZER /////////////////// + localparam repr_t interp_beam_repr = '{1, 16, 15}; + typedef logic signed [interp_beam_repr.nb-1:0] interp_beam_t [2]; + + //////////// MIXER ///////////////// + localparam repr_t mixed_tx_sample_full_repr = get_repr( + get_repr(interp_beam_repr, dds_freq_repr, MULT), + get_repr(interp_beam_repr, dds_freq_repr, MULT), + SUM + ); + typedef logic signed [mixed_tx_sample_full_repr.nb-1:0] mixed_tx_sample_fr_t [2]; + + localparam repr_t mixed_tx_sample_repr = '{1, 16, 15}; + typedef logic signed [mixed_tx_sample_repr.nb-1:0] mixed_tx_sample_t [2]; + + //////////// Memory path ///////////////// + typedef struct packed{ + logic [31:0] araddr; + logic [ 7:0] arlen; + logic [ 2:0] arsize; + logic [ 1:0] arburst; + logic [ 2:0] arprot; + logic [ 3:0] arcache; + logic arvalid; + logic rready; + }dma_axi_mm2s_out_t; + + typedef struct packed{ + logic arready; + logic [31:0] rdata; + logic [ 1:0] rresp; + logic rlast; + logic rvalid; + }dma_axi_mm2s_in_t; + + + ////////////////////////////////////////////////////// + // DMA manager/Memory Manager Unit related parameters + ////////////////////////////////////////////////////// + localparam integer unsigned NB_LEN_MMU = 8; + localparam integer unsigned NB_WORD_WIDTH_MMU = 32; + localparam integer unsigned LOG2_NB_WORD_WIDTH_MMU = $clog2(NB_WORD_WIDTH_MMU); + localparam integer unsigned NB_BASE_ADDRESS_MMU = 16; + localparam integer unsigned NB_ADDR_TRANSL_OFFSET = 10; + +endpackage diff --git a/firmware/ip/xcom/src/req_ack_cmd.sv b/firmware/ip/xcom/src/req_ack_cmd.sv new file mode 100755 index 00000000..8bb1d9f7 --- /dev/null +++ b/firmware/ip/xcom/src/req_ack_cmd.sv @@ -0,0 +1,139 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: req_ack_cmd.sv +// Project: QICK +// Description: +// Block to determine if the command must be executed locally (LOC_REQ) to +// the board or if it should be executed through the network of +// connected QICKs (NET_REQ). +// +//Inputs: +// - i_clk clock signal +// - i_rstn active low reset signal +// - i_valid indicates a valid data is available +// - i_op 5-bit port indicating the operation over the data. MSB bit is +// used to indicate a local command operation (LOC_REQ) when it +// is 1 and a network (remote) operation (NET_REQ) when it is 0. +// - i_addr addr of register to work on. +// - i data data port. +// - i_ack acknowledgement port. The xcom_txrx core side should acknowledge +// the command processing requirement +//Outputs: +// - o_req_loc local command requirement signal. Indicates a local command +// should be excecuted. +// - o_req_net network (remote) command requirement signal. Indicates a +// network (remote) command should be excecuted. +// - o_op operation to be excecuted (local or remote). +// - o_data data to be excecuted (local or remote). +// - o_data_cntr command counter. It counts the number of commands received +// locally. This is a port for debug purposes. +// +// +// Change history: 10/20/24 - v2 Started by @mdifederico +// 04/27/25 - Refactored by @lharnaldi +// - the sync_n core was removed to sync all signals +// in one place (external). +// 05/07/25 - Added header documentation @lharnaldi +// 05/27/25 - @lharnaldi Modify the FSM +// +/////////////////////////////////////////////////////////////////////////////// +module req_ack_cmd +( + input logic i_clk , + input logic i_rstn , + // Command Input + input logic i_valid , + input logic [ 5-1:0] i_op , + input logic [ 4-1:0] i_addr , + input logic [32-1:0] i_data , + // Command Execution + input logic i_ack , + output logic o_req_loc , + output logic o_req_net , + output logic [ 8-1:0] o_op , + output logic [32-1:0] o_data , + output logic [ 4-1:0] o_data_cntr +); + + logic [ 8-1:0] cmd_op_r, cmd_op_n; + logic [32-1:0] cmd_dt_r, cmd_dt_n; + logic [ 4-1:0] cmd_cnt_r, cmd_cnt_n; + + typedef enum logic [2-1:0] {IDLE = 2'b00, + LOC_REQ = 2'b01, + NET_REQ = 2'b10, + ACK = 2'b11 + } state_t; + + state_t state_r, state_n; + + //State register + always_ff @ (posedge i_clk) begin + if ( !i_rstn ) state_r <= IDLE; + else state_r <= state_n; + end + + //next state logic + always_comb begin + state_n = state_r; + o_req_loc = 1'b0; + o_req_net = 1'b0; + case (state_r) + IDLE: begin + if( i_valid ) begin + if (i_op[4]) begin + state_n = LOC_REQ; + end else begin + state_n = NET_REQ; + end + end else begin + state_n = IDLE; + end + end + LOC_REQ: begin + o_req_loc = 1'b1; + if (i_ack) state_n = ACK; + else state_n = LOC_REQ; + end + NET_REQ: begin + o_req_net = 1'b1; + if (i_ack) state_n = ACK; + else state_n = NET_REQ; + end + ACK: begin + if (!i_ack) state_n = IDLE; + else state_n = ACK; + end + default: + state_n = state_r; + endcase + end + + always_ff @(posedge i_clk) + if (!i_rstn) begin + cmd_op_r <= '0; + cmd_dt_r <= '0; + cmd_cnt_r <= '0; + end else begin + cmd_op_r <= cmd_op_n; + cmd_dt_r <= cmd_dt_n; + cmd_cnt_r <= cmd_cnt_n; + end + //next state logic + assign cmd_op_n = i_valid ? {i_op[3:0], i_addr} : cmd_op_r; + assign cmd_dt_n = i_valid ? i_data : cmd_dt_r; + assign cmd_cnt_n = i_ack ? cmd_cnt_r + 1'b1 : cmd_cnt_r; + + // OUTPUTS + /////////////////////////////////////////////////////////////////////////////// + assign o_op = cmd_op_r; + assign o_data = cmd_dt_r; + + // DEBUG + /////////////////////////////////////////////////////////////////////////////// + assign o_data_cntr = cmd_cnt_r; + +endmodule diff --git a/firmware/ip/xcom/src/rising_edge_det.sv b/firmware/ip/xcom/src/rising_edge_det.sv new file mode 100755 index 00000000..b2038a35 --- /dev/null +++ b/firmware/ip/xcom/src/rising_edge_det.sv @@ -0,0 +1,37 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: rising_edge_det.sv +// Project: UTILS +// Description: Rising edge detection circuit. +// It serves as clock domain crossing (CDC) logic. +// +// Change history: 05/14/25 - Created by @lharnaldi +// +/////////////////////////////////////////////////////////////////////////////// +module rising_edge_det( + input logic i_clk , + input logic i_rstn , + input logic i_strobe , + output logic o_pulse +); + + logic delay_r, delay_n; + + always_ff @ (posedge i_clk) begin + if(!i_rstn) begin + delay_r <= '0; + end else begin + delay_r <= delay_n; + end + end + + //next-state logic + assign delay_n = i_strobe; + + //output and decoding logic + assign o_pulse = !delay_r & i_strobe; + +endmodule diff --git a/firmware/ip/xcom/src/rx_cmd.sv b/firmware/ip/xcom/src/rx_cmd.sv new file mode 100755 index 00000000..2bfff181 --- /dev/null +++ b/firmware/ip/xcom/src/rx_cmd.sv @@ -0,0 +1,178 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: rx_cmd.sv +// Project: QICK +// Description: +// Receiver interface wrapper for the XCOM block. Synchronizes the +// xcom_link_rx block through the external i_sync signal. +// +//Parameters: +// - NCH number of RX channels +//Inputs: +// - i_clk clock signal +// - i_rstn active low reset signal +// - i_id local ID (address) of the board. The range is from 1 to 16. +// - i xcom_data serial data received. This is the general data input of the +// XCOM block. This port length depends on the number of +// channels +// - i_xcom_clk serial clock for reception. This is the general clock input of +// the XCOM block. This port length depends on the number of +// channels +//Outputs: +// - o_valid signal indicating valid data is available +// - o_op opcode to be excecuted +// - o_data data receved. +// - o_chid id of the board sending data +// - o_dbg_state debug port for monitoring the state of the internal FSM +// +// Change history: 09/20/24 - v1.0.0 Started by @mdifederico +// 05/09/25 - v1.1.0 Refactored by @lharnaldi +// - the sync_n core was removed to sync +// all signals in one place (external). +// +/////////////////////////////////////////////////////////////////////////////// +module rx_cmd # ( + parameter NCH = 2 +)( + input logic i_clk , + input logic i_rstn , + // XCOM CFG + input logic [4-1:0] i_id , + // XCOM CNX + input logic [NCH-1:0] i_xcom_data , + input logic [NCH-1:0] i_xcom_clk , + // Command Processing + output logic o_valid , + output logic [ 4-1:0] o_op , + output logic [32-1:0] o_data , + output logic [ 4-1:0] o_chid , + // XCOM RX DEBUG + output logic [5-1:0] o_dbg_state [NCH] + ); + +typedef enum logic [2-1:0]{ IDLE = 2'b00, + REQ = 2'b01, + ACK = 2'b10 +} state_t; +state_t state_r, state_n; + +logic [NCH-1:0] s_req ; +logic [NCH-1:0] s_ack ; +logic [ 4-1:0] s_cmd [NCH]; +logic [32-1:0] s_data [NCH]; +logic [$clog2(NCH):0] s_channel ; +logic s_valid ; +logic s_cmd_req ; +logic [NCH-1:0] s_cmd_chid ; +logic cmd_ack_r ; +logic cmd_ack_n ; +logic [5-1:0] s_dbg_state [NCH]; + +// LINK RECEIVERS +///////////////////////////////////////////////////////////////////////////// +genvar k; +generate + for (k=0; k < NCH ; k=k+1) begin: RX + xcom_link_rx u_xcom_link_rx( + .i_clk ( i_clk ), + .i_rstn ( i_rstn ), + .i_id ( i_id ), + .o_req ( s_req[k] ), + .i_ack ( s_ack[k] ), + .o_cmd ( s_cmd[k] ), + .o_data ( s_data[k] ), + .i_xcom_data( i_xcom_data[k] ), + .i_xcom_clk ( i_xcom_clk[k] ), + .o_dbg_state( s_dbg_state[k] ) + ); + //debug + assign o_dbg_state[k] = s_dbg_state[k]; + end +endgenerate + + +// RX Command Priority Encoder +///////////////////////////////////////////////////////////////////////////// +assign s_valid = |s_req; + +always_comb begin + s_channel = 0; // Default: clog2(1) = 0 + if (s_req > 1) s_channel = 1; + if (s_req > 2) s_channel = 2; + if (s_req > 4) s_channel = 3; + if (s_req > 8) s_channel = 4; + if (s_req > 16) s_channel = 5; + if (s_req > 32) s_channel = 6; + if (s_req > 64) s_channel = 7; + if (s_req > 128) s_channel = 8; + if (s_req > 256) s_channel = 9; + if (s_req > 512) s_channel = 10; + if (s_req > 1024) s_channel = 11; + if (s_req > 2048) s_channel = 12; + if (s_req > 4096) s_channel = 13; + if (s_req > 8192) s_channel = 14; + if (s_req > 16384) s_channel = 15; +end + +// RX Caller ID +///////////////////////////////////////////////////////////////////////////// +always_ff @ (posedge i_clk) begin + if ( !i_rstn ) s_cmd_chid <= 0; + else if ( s_valid ) s_cmd_chid <= s_channel; +end + +// RX Command Decoder ACK +///////////////////////////////////////////////////////////////////////////// +always_comb begin + for (int ind_ch=0; ind_ch < NCH ; ind_ch=ind_ch+1) begin: RX_DECOX + if (ind_ch == s_cmd_chid) + s_ack[ind_ch] = cmd_ack_r; + else + s_ack[ind_ch] = 1'b0; + end +end + +//registers +always_ff @ (posedge i_clk) begin + if ( !i_rstn ) cmd_ack_r <= 1'b0; + else cmd_ack_r <= cmd_ack_n; +end +assign cmd_ack_n = s_cmd_req ? 1'b1 : 1'b0; + +//RX FSM +always_ff @ (posedge i_clk) begin + if ( !i_rstn ) state_r <= IDLE; + else state_r <= state_n; +end + +always_comb begin + state_n = state_r; + s_cmd_req = 1'b0; + case (state_r) + IDLE: begin + if ( s_valid ) begin + s_cmd_req = 1'b1; + state_n = REQ; + end + end + REQ: begin + if ( cmd_ack_r ) state_n = ACK; + end + ACK: begin + if ( !cmd_ack_r ) state_n = IDLE; + end + default: state_n = state_r; + endcase +end + +// OUTPUTS +/////////////////////////////////////////////////////////////////////////////// +assign o_op = s_cmd[s_cmd_chid]; +assign o_data = s_data[s_cmd_chid]; +assign o_chid = s_cmd_chid ; +assign o_valid = cmd_ack_r; + +endmodule diff --git a/firmware/ip/xcom/src/synchronizer.sv b/firmware/ip/xcom/src/synchronizer.sv new file mode 100755 index 00000000..c0e5a8d8 --- /dev/null +++ b/firmware/ip/xcom/src/synchronizer.sv @@ -0,0 +1,46 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: sync_n.sv +// Project: QICK +// Description: 2 FF, 1-bit data synchronizer. +// It serves as clock domain crossing (CDC) logic. +// +// Change history: 04/29/25 - Created by @lharnaldi +// +/////////////////////////////////////////////////////////////////////////////// +module synchronizer #( + //number of bits in data + parameter NB = 1 +)( + input logic i_clk , + input logic i_rstn, + input logic [NB-1:0] i_async, + output logic [NB-1:0] o_sync +); + + logic [NB-1:0] meta_r, meta_n; + logic [NB-1:0] sync_r, sync_n; + + //two D FFs + always_ff @ (posedge i_clk) begin + if(!i_rstn) begin + meta_r <= '0; + sync_r <= '0; + end else begin + meta_r <= meta_n; + sync_r <= sync_n; + end + end + + //next-state logic + assign meta_n = i_async; + assign sync_n = meta_r; + + //output logic + assign o_sync = sync_r; + +endmodule + diff --git a/firmware/ip/xcom/src/tx_cmd.sv b/firmware/ip/xcom/src/tx_cmd.sv new file mode 100755 index 00000000..7d331380 --- /dev/null +++ b/firmware/ip/xcom/src/tx_cmd.sv @@ -0,0 +1,158 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: tx_cmd.sv +// Project: QICK +// Description: +// Transmitter interface wrapper for the XCOM block. Synchronizes the +// xcom_link_tx block through the external i_sync signal. +// +//Inputs: +// - i_clk clock signal +// - i_rstn active low reset signal +// - i_sync synchronization signal. Lets the XCOM synchronize with an +// external signal. Actuates in coordination with the +// QRST_SYNC command. +// - i_cfg_tick this input is connected to the AXI_CFG register and +// determines the duration of the xcom_clk output signal. +// xcom_clk will be either in state 1 or 0 for CFG_AXI clock +// cycles (i_clk). Possible values ranges from 0 to 7 with +// 0 equal to two clock cycles and 7 equal to 15 clock +// cycles. As an example, if i_cfg_tick = 2 and +// i_clk = 500 MHz, then xcom_clk would be ~125 MHz. +// - i_req transmission requirement signal. Signal indicating a new +// data transmission starts. +// - i header this is the header to be sent to the slaves. +// bit 7 is sometimes used to indicate a +// synchronization in other places in the +// XCOM hierarchy +// bits [6:5] determines the data length to transmit: +// 00 no data +// 01 8-bit data +// 10 16-bit data +// 11 32-bit data +// bit 4 not used in this block +// bits [3:0] not used in this block. Sometimes used +// as mem_id and sometimes used as board +// ID in the XCOM hierarchy +// - i_data the data to be transmitted +//Outputs: +// - o_ready signal indicating the ip is ready to receive new data to +// transmit +// - o_data serial data transmitted. This is the general output of the +// XCOM block +// - o_clk serial clock for transmission. This is the general output of +// the XCOM block +// - o_dbg_state debug port for monitoring the state of the internal FSM +// +// Change history: 09/20/24 - v1 Started by @mdifederico +// 05/06/25 - Refactored by @lharnaldi +// - the sync_n core was removed to sync all signals +// in one place (external). +// +/////////////////////////////////////////////////////////////////////////////// + +module tx_cmd( + input logic i_clk , + input logic i_rstn , + input logic i_sync , + // Config + input logic [4-1:0] i_cfg_tick , + // Transmission + input logic i_req , + input logic [8-1:0] i_header , + input logic [32-1:0] i_data , + output logic o_ready , + // XCOM CNX + output logic o_data , + output logic o_clk , + // XCOM TX DEBUG + output logic [2-1:0] o_dbg_state + ); + +logic s_ready; +logic sync_dly_r, sync_dly_n; +logic s_tx_valid; +logic s_xcmd_sync; +logic s_sync; + +typedef enum logic [2-1:0]{ IDLE = 2'b00, + WVLD = 2'b01, + WSYNC = 2'b10, + WRDY = 2'b11 +} state_t; +state_t state_r, state_n; + + +// PULSE SYNC +/////////////////////////////////////////////////////////////////////////////// +assign s_xcmd_sync = ( i_header[7:4] == 4'b1000 ); // Sync Command + +always_ff@(posedge i_clk) begin + if (!i_rstn) sync_dly_r <= 1'b0; + else sync_dly_r <= sync_dly_n; +end + +assign sync_dly_n = i_sync; +assign s_sync = !sync_dly_r & i_sync ; + + +// TX Control state +/////////////////////////////////////////////////////////////////////////////// +always_ff @ (posedge i_clk) begin + if ( !i_rstn ) state_r <= IDLE; + else state_r <= state_n; +end + +always_comb begin + state_n = state_r; + s_tx_valid = 1'b0; + case (state_r) + IDLE: begin + if ( i_req ) begin + if ( s_xcmd_sync ) begin + state_n = WSYNC; + end else begin + state_n = WVLD; + end + end + end + WVLD: begin + s_tx_valid = 1'b1; + state_n = WRDY; + end + WSYNC: begin + if ( s_sync ) begin + s_tx_valid = 1'b1; + state_n = WRDY; + end + end + WRDY: begin + if ( !i_req & s_ready ) state_n = IDLE; + end + default: state_n = state_r; + endcase +end + +xcom_link_tx +u_xcom_link_tx +( + .i_clk ( i_clk ), + .i_rstn ( i_rstn ), + .i_cfg_tick ( i_cfg_tick ), + .i_valid ( s_tx_valid ), + .i_header ( i_header ), + .i_data ( i_data ), + .o_ready ( s_ready ), + .o_data ( o_data ), + .o_clk ( o_clk ) +); + +// OUTPUTS +assign o_ready = s_ready; +assign o_dbg_state = state_r; + +endmodule + diff --git a/firmware/ip/xcom/src/wide_en_signal.sv b/firmware/ip/xcom/src/wide_en_signal.sv new file mode 100755 index 00000000..ed89f2ec --- /dev/null +++ b/firmware/ip/xcom/src/wide_en_signal.sv @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: wide_en_signal.sv +// Project: UTILS +// Description: Enable pulse generator for a wide enable signal. +// It serves as clock domain crossing (CDC) logic. +// +// Change history: 05/15/25 - Created by @lharnaldi +// +/////////////////////////////////////////////////////////////////////////////// +module wide_en_signal( + input logic i_clk , + input logic i_rstn , + input logic i_en , + output logic o_en +); + + logic en_strobe; + + synchronizer#( + .NB(1) + ) u_sync( + .i_clk ( i_clk ), + .i_rstn ( i_rstn ), + .i_async ( i_en ), + .o_sync ( en_strobe ) + ); + + rising_edge_det u_edge_detect( + .i_clk ( i_clk ), + .i_rstn ( i_rstn ), + .i_strobe ( en_strobe ), + .o_pulse ( o_en ) + ); + +endmodule diff --git a/firmware/ip/xcom/src/xcom.sv b/firmware/ip/xcom/src/xcom.sv new file mode 100755 index 00000000..e34453b5 --- /dev/null +++ b/firmware/ip/xcom/src/xcom.sv @@ -0,0 +1,346 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: xcom.sv +// Project: QICK +// Description: +// Transmitter and Receiver interface for the XCOM block. +// +//Inputs: +// - i_ps_clk clock signal sync to PS +// - i_ps_rstn active low reset signal sync to PS +// - i_core_clk clock signal sync to CORE +// - i_core_rstn active low reset signal sync to CORE +// - i_time_clk clock signal sync to TIME +// - i_time_rstn active low reset signal sync to TIME +// QICK PERIPHERAL INTERFACE (i_core_clk) +// - i_core_en data valid signal coming from the core processor. Indicates +// a valid data is ready for transmission. +// - i_core_op opcode from the core. See xcom opcodes in qick_pkg +// - i_core_data1 data1 to be transmitted, coming from the core processor. +// - i_core_data2 data2 to be transmitted, coming from the core processor. +// Qick CONTROL +// - i_sync synchronization signal. Lets the XCOM synchronize with an +// external signal. Actuates in coordination with the +// XCOM_QRST_SYNC command. +// - i xcom_data serial data received. This is the general data input of the +// XCOM block +// - i_xcom_clk serial clock for reception. This is the general clock input of +// the XCOM block +// +//Outputs: +// QICK PERIPHERAL INTERFACE (i_core_clk) +// - o_core_ready signal indicating the ip is ready to receive new data to +// transmit +// - o_core_data1 data1 to core +// - o_core_data2 data2 to core +// - o_core_valid signal indicating the ip has valid data to write into the +// local board +// - o_core_flag signal indicating to write flag into the core +// Qick CONTROL +// - o_proc_start start signal to the tproc +// - o_proc_stop stop signal to the tproc +// - o_time_rst reset the time reference in processor +// - o_time_update update the time in processor +// - o_time_update_data data to update the time in processor +// - o_core_start start signal to the core in tproc +// - o_core_stop stop signal to the core in tproc +// XCOM +// - o_xcom_id board ID. This is a signal to see the board ID +// into external LEDs. +// IO XCOM (i_time_clk) +// - o xcom_data serial data transmitted. This is the general data output of the +// XCOM block +// - o_xcom_clk serial clock for transmission. This is the general clock output of +// the XCOM block / +// AXI-Lite DATA Slave I/F (i_ps_clk) +// - s_axi signals of the AXI4-Lite interface to PS +// +// Change history: 10/20/24 - v2 Started by @mdifederico +// 05/13/25 - Refactored by @lharnaldi +// - the sync_n core was removed to sync all signals +// in one place (external). +// +/////////////////////////////////////////////////////////////////////////////// +module xcom import qick_pkg::*; +# ( + parameter NCH = 2 , + parameter SYNC = 1 , + parameter DEBUG = 1 +)( + input logic i_ps_clk , + input logic i_ps_rstn , + input logic i_core_clk , + input logic i_core_rstn , + input logic i_time_clk , + input logic i_time_rstn , +// QICK PERIPHERAL INTERFACE (i_core_clk) + input logic i_core_en , + input logic [5-1:0] i_core_op , + input logic [32-1:0] i_core_data1 , + input logic [32-1:0] i_core_data2 , + output logic o_core_ready , + output logic [32-1:0] o_core_data1 , + output logic [32-1:0] o_core_data2 , + output logic o_core_valid , + output logic o_core_flag , +// Qick CONTROL + input logic i_sync , + output logic o_proc_start , + output logic o_proc_stop , + output logic o_time_rst , + output logic o_time_update , + output logic [32-1:0] o_time_update_data , + output logic o_core_start , + output logic o_core_stop , +// XCOM + output logic [ 4-1:0] o_xcom_id , +// IO XCOM (i_time_clk) + input logic [NCH-1:0] i_xcom_clk , + input logic [NCH-1:0] i_xcom_data , + output logic o_xcom_clk , + output logic o_xcom_data , +// AXI-Lite DATA Slave I/F (i_ps_clk) + input logic [6-1:0] s_axi_awaddr , + input logic [3-1:0] s_axi_awprot , + input logic s_axi_awvalid , + output logic s_axi_awready , + input logic [32-1:0] s_axi_wdata , + input logic [ 4-1:0] s_axi_wstrb , + input logic s_axi_wvalid , + output logic s_axi_wready , + output logic [ 2-1:0] s_axi_bresp , + output logic s_axi_bvalid , + input logic s_axi_bready , + input logic [ 6-1:0] s_axi_araddr , + input logic [ 3-1:0] s_axi_arprot , + input logic s_axi_arvalid , + output logic s_axi_arready , + output logic [32-1:0] s_axi_rdata , + output logic [ 2-1:0] s_axi_rresp , + output logic s_axi_rvalid , + input logic s_axi_rready +); + +// Signal Declaration +/////////////////////////////////////////////////////////////////////////////// +logic [ 8-1:0] s_op ; +logic [32-1:0] s_data; +logic [ 4-1:0] s_data_cntr; + +logic [ 4-1:0] s_xcom_id; +logic [ 4-1:0] s_xcom_id_ps; +logic [32-1:0] s_xcom_ctrl ; +logic [6-1:0] s_xcom_ctrl_sync ; +logic [32-1:0] s_xcom_cfg ; +logic [4-1:0] s_xcom_cfg_sync ; +logic [32-1:0] s_axi_data1; +logic [32-1:0] s_axi_data1_sync; +logic [32-1:0] s_axi_data2 ; +logic [32-1:0] s_axi_data2_sync; +logic [ 4-1:0] s_axi_addr ; +logic s_core_en; +logic [ 5-1:0] s_core_op; +logic [2-1:0][32-1:0] s_core_data ; +logic [2-1:0][32-1:0] s_ps_data ; +logic s_req_loc; +logic s_ack_loc; +logic s_req_net; +logic s_ack_net; + +logic s_core_ready; +logic s_core_valid; +logic s_core_flag; +logic s_xcom_flag_ps; +logic [32-1:0] s_core_data1; +logic [32-1:0] s_core_data1_sync; +logic [32-1:0] s_core_data2; +logic [32-1:0] s_core_data2_sync; +logic [32-1:0] s_core_data1_ps; +logic [32-1:0] s_core_data2_ps; + +logic [32-1:0] xcom_mem_data [16]; +logic [32-1:0] axi_mem_data; + +logic [32-1:0] xreg_debug; +logic [32-1:0] xreg_status; +logic [32-1:0] xreg_status_sync_r; +logic [32-1:0] xreg_status_sync_n; + +logic [32-1:0] s_dbg_rx_data ; +logic [32-1:0] s_dbg_tx_data ; +logic [21-1:0] s_dbg_status ; +logic [32-1:0] s_dbg_data ; +logic [32-1:0] s_dbg_rx_data_ps ; +logic [32-1:0] s_dbg_tx_data_ps ; +logic [21-1:0] s_dbg_status_ps ; +logic [32-1:0] s_dbg_data_ps ; +logic [32-1:0] s_dbg_debug_ps ; + + +/////////////////////////////////////////////////////////////////////////////// +// AXI Registers +/////////////////////////////////////////////////////////////////////////////// +xcom_axil_slv#( + .C_S_AXI_ADDR_WIDTH ( 6 ), + .C_S_AXI_DATA_WIDTH ( 32 ) +) u_xcom_axil_slv( + .clk ( i_ps_clk ), + .reset_n ( i_ps_rstn ), + .s_axi_awaddr ( s_axi_awaddr [6-1:0] ), + .s_axi_awvalid ( s_axi_awvalid ), + .s_axi_awready ( s_axi_awready ), + .s_axi_wdata ( s_axi_wdata ), + .s_axi_wstrb ( s_axi_wstrb ), + .s_axi_wvalid ( s_axi_wvalid ), + .s_axi_wready ( s_axi_wready ), + .s_axi_bresp ( s_axi_bresp ), + .s_axi_bvalid ( s_axi_bvalid ), + .s_axi_bready ( s_axi_bready ), + .s_axi_araddr ( s_axi_araddr ), + .s_axi_arvalid ( s_axi_arvalid ), + .s_axi_arready ( s_axi_arready ), + .s_axi_rdata ( s_axi_rdata ), + .s_axi_rresp ( s_axi_rresp ), + .s_axi_rvalid ( s_axi_rvalid ), + .s_axi_rready ( s_axi_rready ), + .o_xcom_ctrl ( s_xcom_ctrl ), + .o_xcom_cfg ( s_xcom_cfg ), + .o_xcom_axi_data1( s_axi_data1 ), + .o_xcom_axi_data2( s_axi_data2 ), + .o_xcom_axi_addr ( s_axi_addr ), + .i_board_id ( {28'h000_0000,s_xcom_id_ps} ), + .i_xcom_flag ( s_xcom_flag_ps ), + .i_xcom_data1 ( s_core_data1_ps ), + .i_xcom_data2 ( s_core_data2_ps ), + .i_xcom_mem ( axi_mem_data ), + .i_xcom_rx_data ( s_dbg_rx_data_ps ), + .i_xcom_tx_data ( s_dbg_tx_data_ps ), + .i_xcom_status ( xreg_status ),//s_dbg_status_ps ), + .i_xcom_debug ( xreg_debug ) //s_dbg_debug_ps ) + ); + +assign axi_mem_data = xcom_mem_data[s_axi_addr]; + +xcom_cdc u_xcom_cdc( + .i_ps_clk ( i_ps_clk ), + .i_ps_rstn ( i_ps_rstn ), + .i_core_clk ( i_core_clk ), + .i_core_rstn ( i_core_rstn ), + .i_time_clk ( i_time_clk ), + .i_time_rstn ( i_time_rstn ), + //core domain - time domain + .i_core_en ( i_core_en ), + .i_core_op ( i_core_op ), + .i_core_data1 ( i_core_data1 ), + .i_core_data2 ( i_core_data2 ), + .o_core_en_sync ( s_core_en ), + .o_core_op_sync ( s_core_op ), + .o_core_data1_sync ( s_core_data1_sync), + .o_core_data2_sync ( s_core_data2_sync), + .i_core_ready ( s_core_ready ), + .i_core_valid ( s_core_valid ), + .i_core_flag ( s_core_flag ), + .o_core_ready_sync ( o_core_ready ), + .o_core_valid_sync ( o_core_valid ), + .o_core_flag_sync ( o_core_flag ), + //time domain - PS time domain + .i_xcom_id ( s_xcom_id ), + .o_xcom_id_sync ( s_xcom_id_ps ), + .i_xcom_ctrl ( s_xcom_ctrl ), + .i_xcom_cfg ( s_xcom_cfg ), + .i_axi_data1 ( s_axi_data1 ), + .i_axi_data2 ( s_axi_data2 ), + .o_xcom_ctrl_sync ( s_xcom_ctrl_sync ), + .o_xcom_cfg_sync ( s_xcom_cfg_sync ), + .o_axi_data1_sync ( s_axi_data1_sync ), + .o_axi_data2_sync ( s_axi_data2_sync ), + .o_xcom_flag_sync ( s_xcom_flag_ps ), + .o_xcom_data1_sync ( s_core_data1_ps ), + .o_xcom_data2_sync ( s_core_data2_ps ), + .i_xcom_rx_data ( s_dbg_rx_data ), + .i_xcom_tx_data ( s_dbg_tx_data ), + .i_xcom_status ( s_dbg_status ), + .i_xcom_debug ( s_dbg_debug ), + .o_xcom_rx_data_sync( s_dbg_rx_data_ps ), + .o_xcom_tx_data_sync( s_dbg_tx_data_ps ), + .o_xcom_status_sync ( s_dbg_status_ps ), + .o_xcom_debug_sync ( s_dbg_debug_ps ) +); + +assign s_core_data = {s_core_data2_sync, s_core_data1_sync}; +assign s_ps_data = {s_axi_data2_sync, s_axi_data1_sync}; + +xcom_cmd u_xcom_cmd( + .i_clk ( i_time_clk ), + .i_rstn ( i_time_rstn ), + .i_core_en ( s_core_en ), + .i_core_op ( s_core_op ), + .i_core_data ( s_core_data ), + .i_ps_ctrl ( s_xcom_ctrl_sync ), + .i_ps_data ( s_ps_data ), + .o_req_loc ( s_req_loc ), + .i_ack_loc ( s_ack_loc ), + .o_req_net ( s_req_net ), + .i_ack_net ( s_ack_net ), + .o_op ( s_op ), + .o_data ( s_data ), + .o_data_cntr ( s_data_cntr ) + ); + +xcom_txrx#( + .NCH ( NCH ), + .SYNC ( 1'b1 ) + ) u_xcom_txrx( + .i_clk ( i_time_clk ), + .i_rstn ( i_time_rstn ), + .i_sync ( i_sync ), + .i_req_loc ( s_req_loc ), + .i_req_net ( s_req_net ), + .i_header ( s_op ), + .i_data ( s_data ), + .o_ack_loc ( s_ack_loc ), + .o_ack_net ( s_ack_net ), + .o_qp_ready ( s_core_ready ), + .o_qp_valid ( s_core_valid ), + .o_qp_flag ( s_core_flag ), + .o_qp_data1 ( s_core_data1 ), + .o_qp_data2 ( s_core_data2 ), + .o_proc_start ( o_proc_start ), + .o_proc_stop ( o_proc_stop ), + .o_time_rst ( o_time_rst ), + .o_time_update ( o_time_update ), + .o_time_update_data( o_time_update_data ), + .o_core_start ( o_core_start ), + .o_core_stop ( o_core_stop ), + .i_cfg_tick ( s_xcom_cfg_sync ), + .o_xcom_id ( s_xcom_id ), + .o_xcom_mem ( xcom_mem_data ),//FIXME: review this because here we are crossing clock domains + .i_xcom_data ( i_xcom_data ), + .i_xcom_clk ( i_xcom_clk ), + .o_xcom_data ( o_xcom_data ), + .o_xcom_clk ( o_xcom_clk ), + .o_dbg_rx_data ( s_dbg_rx_data ), + .o_dbg_tx_data ( s_dbg_tx_data ), + .o_dbg_status ( s_dbg_status ), + .o_dbg_data ( s_dbg_debug ) +); + +assign o_xcom_id = s_xcom_id; +assign xreg_status = {7'd0,s_data_cntr, s_dbg_status_ps}; + +//end of SYNC STAGES +/////////////////////////////////////////////////////////////////////////////// +// DEBUG +/////////////////////////////////////////////////////////////////////////////// +generate + if (DEBUG == 0) begin : DEBUG_NO + assign xreg_debug = '{default:'0} ; + end else if (DEBUG == 1) begin : DEBUG_YES + assign xreg_debug = s_dbg_debug_ps; + end +endgenerate + +endmodule diff --git a/firmware/ip/xcom/src/xcom_axil_slv.sv b/firmware/ip/xcom/src/xcom_axil_slv.sv new file mode 100755 index 00000000..6918fd19 --- /dev/null +++ b/firmware/ip/xcom/src/xcom_axil_slv.sv @@ -0,0 +1,453 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: xcom_axil_slv.sv +// Project: QICK +// Description: +// AXI4-Lite Slave interface for the XCOM core. +// I/O ports corresponds to the AXI4 Interface definition. +// +// Change history: 05/14/25 - v0.1.0 Started by @lharnaldi +// +/////////////////////////////////////////////////////////////////////////////// +module xcom_axil_slv #( + parameter integer C_S_AXI_ADDR_WIDTH = 6, // Address width. Adjust as needed. + parameter integer C_S_AXI_DATA_WIDTH = 32 // Data width (32 or 64). +) ( + input logic clk, // System clock + input logic reset_n, // Active-low reset + // Write address channel signals + input logic [C_S_AXI_ADDR_WIDTH-1:0] s_axi_awaddr, // Write address + input logic s_axi_awvalid, // Write address valid + output logic s_axi_awready, // Write address ready + // Write data channel signals + input logic [C_S_AXI_DATA_WIDTH-1:0] s_axi_wdata, // Write data + input logic [C_S_AXI_DATA_WIDTH/8-1:0] s_axi_wstrb, // Write strobes + input logic s_axi_wvalid, // Write data valid + output logic s_axi_wready, // Write data ready + // Write response channel signals + output logic [1:0] s_axi_bresp, // Write response + output logic s_axi_bvalid, // Write response valid + input logic s_axi_bready, // Write response ready + // Read address channel signals + input logic [C_S_AXI_ADDR_WIDTH-1:0] s_axi_araddr, // Read address + input logic s_axi_arvalid, // Read address valid + output logic s_axi_arready, // Read address ready + // Read data channel signals + output logic [C_S_AXI_DATA_WIDTH-1:0] s_axi_rdata, // Read data + output logic [1:0] s_axi_rresp, // Read response + output logic s_axi_rvalid, // Read data valid + input logic s_axi_rready, // Read data ready + // Registers. + output logic [C_S_AXI_DATA_WIDTH-1:0] o_xcom_ctrl, //out std_logic_vector ( 5 downto 0) ; + output logic [C_S_AXI_DATA_WIDTH-1:0] o_xcom_cfg, //out std_logic_vector ( 3 downto 0) ; + output logic [C_S_AXI_DATA_WIDTH-1:0] o_xcom_axi_data1, //out std_logic_vector (31 downto 0) ; + output logic [C_S_AXI_DATA_WIDTH-1:0] o_xcom_axi_data2, //out std_logic_vector (31 downto 0) ; + output logic [C_S_AXI_DATA_WIDTH-1:0] o_xcom_axi_addr, //out std_logic_vector ( 3 downto 0) ; + input logic [C_S_AXI_DATA_WIDTH-1:0] i_board_id, //in std_logic_vector ( 3 downto 0) ; + input logic [C_S_AXI_DATA_WIDTH-1:0] i_xcom_flag, //in std_logic ; + input logic [C_S_AXI_DATA_WIDTH-1:0] i_xcom_data1, //in std_logic_vector (31 downto 0) ; + input logic [C_S_AXI_DATA_WIDTH-1:0] i_xcom_data2, //in std_logic_vector (31 downto 0) ; + input logic [C_S_AXI_DATA_WIDTH-1:0] i_xcom_mem, //in std_logic_vector (31 downto 0) ; + input logic [C_S_AXI_DATA_WIDTH-1:0] i_xcom_rx_data, //in std_logic_vector (31 downto 0) ; + input logic [C_S_AXI_DATA_WIDTH-1:0] i_xcom_tx_data, //in std_logic_vector (31 downto 0) ; + input logic [C_S_AXI_DATA_WIDTH-1:0] i_xcom_status, //in std_logic_vector (28 downto 0) ; + input logic [C_S_AXI_DATA_WIDTH-1:0] i_xcom_debug //in std_logic_vector (31 downto 0) ); +); + + //------------------------------------------------------------------------- + // Local parameters + //------------------------------------------------------------------------- + + // Example: Define the memory map for this slave. Start at address 0. + localparam integer REG_OFFSET_0 = 0; // Example register 0 offset + localparam integer REG_OFFSET_1 = 4; // Example register 1 offset + localparam integer REG_OFFSET_2 = 8; + localparam integer REG_OFFSET_3 = 12; + localparam integer REG_OFFSET_4 = 16; + localparam integer REG_OFFSET_5 = 20; + localparam integer REG_OFFSET_6 = 24; + localparam integer REG_OFFSET_7 = 28; + localparam integer REG_OFFSET_8 = 32; + localparam integer REG_OFFSET_9 = 36; + localparam integer REG_OFFSET_10 = 40; + localparam integer REG_OFFSET_11 = 44; + localparam integer REG_OFFSET_12 = 48; + localparam integer REG_OFFSET_13 = 52; + localparam integer REG_OFFSET_14 = 56; + localparam integer REG_OFFSET_15 = 60; + + //------------------------------------------------------------------------- + // Local signals + //------------------------------------------------------------------------- + + // Write address channel + logic awready_reg; + logic awvalid_reg; + logic [C_S_AXI_ADDR_WIDTH-1:0] awaddr_reg; + + // Write data channel + logic wready_reg; + logic wvalid_reg; + logic [C_S_AXI_DATA_WIDTH-1:0] wdata_reg; + logic [C_S_AXI_DATA_WIDTH/8-1:0] wstrb_reg; + + // Write response channel + logic bvalid_reg; + logic [1:0] bresp_reg; + + // Read address channel + logic arready_reg; + logic arvalid_reg; + logic [C_S_AXI_ADDR_WIDTH-1:0] araddr_reg; + + // Read data channel + logic rvalid_reg; + logic [1:0] rresp_reg; + logic [C_S_AXI_DATA_WIDTH-1:0] rdata_reg; + + // Internal register array to store data. Example with 16 registers. + logic [C_S_AXI_DATA_WIDTH-1:0] slave_registers [0:15]; + + // FSM state for write operations + typedef enum logic [1:0] { + WRITE_IDLE, + WRITE_ADDR_RCVD, + WRITE_DATA_RCVD, + WRITE_RESP + } write_state_t; + write_state_t write_state_reg, write_state_next; + + // FSM state for read operations + typedef enum logic [1:0] { + READ_IDLE, + READ_ADDR_RCVD, + READ_DATA_SENT + } read_state_t; + read_state_t read_state_reg, read_state_next; + + //------------------------------------------------------------------------- + // I/O assignments + //------------------------------------------------------------------------- + + // Drive the ready signals. Simplest behavior: always ready (no buffering). + assign s_axi_awready = awready_reg; + assign s_axi_wready = wready_reg; + assign s_axi_arready = arready_reg; + + // Drive the response and data signals + assign s_axi_bresp = bresp_reg; + assign s_axi_bvalid = bvalid_reg; + assign s_axi_rdata = rdata_reg; + assign s_axi_rresp = rresp_reg; + assign s_axi_rvalid = rvalid_reg; + + //------------------------------------------------------------------------- + // Finite State Machines + //------------------------------------------------------------------------- + + // Write FSM state register + always_ff @(posedge clk or negedge reset_n) begin + if (!reset_n) begin + write_state_reg <= WRITE_IDLE; + end else begin + write_state_reg <= write_state_next; + end + end + + // Write FSM next-state logic + always_comb begin + write_state_next = write_state_reg; // Default: stay in the same state + case (write_state_reg) + WRITE_IDLE: + if (s_axi_awvalid) + write_state_next = WRITE_ADDR_RCVD; + WRITE_ADDR_RCVD: + if (s_axi_wvalid) + write_state_next = WRITE_DATA_RCVD; + WRITE_DATA_RCVD: + write_state_next = WRITE_RESP; + WRITE_RESP: + if (s_axi_bready) + write_state_next = WRITE_IDLE; + default: + write_state_next = WRITE_IDLE; + endcase + end + + // Read FSM state register + always_ff @(posedge clk or negedge reset_n) begin + if (!reset_n) begin + read_state_reg <= READ_IDLE; + end else begin + read_state_reg <= read_state_next; + end + end + + // Read FSM next-state logic + always_comb begin + read_state_next = read_state_reg; // Default: stay in the same state + case (read_state_reg) + READ_IDLE: + if (s_axi_arvalid) + read_state_next = READ_ADDR_RCVD; + READ_ADDR_RCVD: + read_state_next = READ_DATA_SENT; + READ_DATA_SENT: + if(s_axi_rready) + read_state_next = READ_IDLE; + default: + read_state_next = READ_IDLE; + endcase + end + + //------------------------------------------------------------------------- + // Register logic + //------------------------------------------------------------------------- + + // Capture AWVALID and WVALID, and address/data + always_ff @(posedge clk or negedge reset_n) begin + if (!reset_n) begin + awvalid_reg <= 1'b0; + awaddr_reg <= '0; + wvalid_reg <= 1'b0; + wdata_reg <= '0; + wstrb_reg <= '0; + end else begin + awvalid_reg <= s_axi_awvalid; + if (s_axi_awvalid) begin + awaddr_reg <= s_axi_awaddr; + end + wvalid_reg <= s_axi_wvalid; + if (s_axi_wvalid) begin + wdata_reg <= s_axi_wdata; + wstrb_reg <= s_axi_wstrb; + end + end + end + + always_ff @(posedge clk or negedge reset_n) begin + if (!reset_n) begin + arvalid_reg <= 1'b0; + araddr_reg <= '0; + end else begin + arvalid_reg <= s_axi_arvalid; + if (s_axi_arvalid) begin + araddr_reg <= s_axi_araddr; + end + end + end + + // Write response logic + always_ff @(posedge clk or negedge reset_n) begin + if (!reset_n) begin + bvalid_reg <= 1'b0; + bresp_reg <= 2'b00; // OKAY + end else begin + case (write_state_reg) + WRITE_ADDR_RCVD: begin + awready_reg <= 1'b1; + wready_reg <= 1'b1; + end + WRITE_DATA_RCVD: begin + awready_reg <= 1'b0; + wready_reg <= 1'b0; + bvalid_reg <= 1'b1; + bresp_reg <= 2'b00; // OKAY + end + WRITE_RESP: begin + if (s_axi_bready) + bvalid_reg <= 1'b0; + end + default: begin + bvalid_reg <= 1'b0; + awready_reg <= 1'b0; + wready_reg <= 1'b0; + end + endcase + end + end + + // Read data and response logic + always_ff @(posedge clk or negedge reset_n) begin + if (!reset_n) begin + rvalid_reg <= 1'b0; + rdata_reg <= '0; + rresp_reg <= 2'b00; //OKAY + end + else begin + case(read_state_reg) + READ_ADDR_RCVD: begin + arready_reg <= 1'b0; + rvalid_reg <= 1'b1; + rresp_reg <= 2'b00; + case (araddr_reg[C_S_AXI_ADDR_WIDTH-1:0]) + REG_OFFSET_0: rdata_reg <= slave_registers[0]; + REG_OFFSET_1: rdata_reg <= slave_registers[1]; + REG_OFFSET_2: rdata_reg <= slave_registers[2]; + REG_OFFSET_3: rdata_reg <= slave_registers[3]; + REG_OFFSET_4: rdata_reg <= slave_registers[4]; + REG_OFFSET_5: rdata_reg <= '0; //slave_registers[5]; + REG_OFFSET_6: rdata_reg <= i_board_id; //slave_registers[6]; + REG_OFFSET_7: rdata_reg <= i_xcom_flag; //slave_registers[7]; + REG_OFFSET_8: rdata_reg <= i_xcom_data1; //slave_registers[8]; + REG_OFFSET_9: rdata_reg <= i_xcom_data2; //slave_registers[9]; + REG_OFFSET_10: rdata_reg <= i_xcom_mem; //slave_registers[10]; + REG_OFFSET_11: rdata_reg <= '0; //slave_registers[11]; + REG_OFFSET_12: rdata_reg <= i_xcom_rx_data; //slave_registers[12]; + REG_OFFSET_13: rdata_reg <= i_xcom_tx_data; //slave_registers[13]; + REG_OFFSET_14: rdata_reg <= i_xcom_status; //slave_registers[14]; + REG_OFFSET_15: rdata_reg <= i_xcom_debug; //slave_registers[15]; + default: rdata_reg <= '0; // Or some error value + endcase + end + READ_DATA_SENT: begin + if(s_axi_rready) + rvalid_reg <= 1'b0; + end + default: begin + rvalid_reg <= 1'b0; + arready_reg <= 1'b1; + end + endcase + end + end + + // Register write logic. This is where you write to your slave registers. + always_ff @(posedge clk or negedge reset_n) begin + if (!reset_n) begin + slave_registers[0] <= '0; + slave_registers[1] <= '0; + slave_registers[2] <= '0; + slave_registers[3] <= '0; + slave_registers[4] <= '0; + slave_registers[5] <= '0; + slave_registers[6] <= '0; + slave_registers[7] <= '0; + slave_registers[8] <= '0; + slave_registers[9] <= '0; + slave_registers[10] <= '0; + slave_registers[11] <= '0; + slave_registers[12] <= '0; + slave_registers[13] <= '0; + slave_registers[14] <= '0; + slave_registers[15] <= '0; + end else begin + //reset + if (slave_registers[0][0] != 1'b0) slave_registers[0][0] <= 1'b0; + if (awvalid_reg && wvalid_reg) begin + case (awaddr_reg[C_S_AXI_ADDR_WIDTH-1:0]) + REG_OFFSET_0: begin + if (s_axi_wstrb[0]) slave_registers[0][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[0][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[0][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[0][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_1: begin + if (s_axi_wstrb[0]) slave_registers[1][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[1][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[1][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[1][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_2: begin + if (s_axi_wstrb[0]) slave_registers[2][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[2][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[2][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[2][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_3: begin + if (s_axi_wstrb[0]) slave_registers[3][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[3][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[3][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[3][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_4: begin + if (s_axi_wstrb[0]) slave_registers[4][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[4][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[4][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[4][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_5: begin + if (s_axi_wstrb[0]) slave_registers[5][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[5][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[5][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[5][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_6: begin + if (s_axi_wstrb[0]) slave_registers[6][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[6][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[6][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[6][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_7: begin + if (s_axi_wstrb[0]) slave_registers[7][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[7][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[7][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[7][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_8: begin + if (s_axi_wstrb[0]) slave_registers[8][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[8][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[8][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[8][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_9: begin + if (s_axi_wstrb[0]) slave_registers[9][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[9][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[9][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[9][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_10: begin + if (s_axi_wstrb[0]) slave_registers[10][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[10][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[10][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[10][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_11: begin + if (s_axi_wstrb[0]) slave_registers[11][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[11][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[11][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[11][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_12: begin + if (s_axi_wstrb[0]) slave_registers[12][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[12][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[12][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[12][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_13: begin + if (s_axi_wstrb[0]) slave_registers[13][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[13][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[13][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[13][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_14: begin + if (s_axi_wstrb[0]) slave_registers[14][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[14][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[14][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[14][31:24] <= s_axi_wdata[31:24]; + end + REG_OFFSET_15: begin + if (s_axi_wstrb[0]) slave_registers[15][7:0] <= s_axi_wdata[7:0]; + if (s_axi_wstrb[1]) slave_registers[15][15:8] <= s_axi_wdata[15:8]; + if (s_axi_wstrb[2]) slave_registers[15][23:16] <= s_axi_wdata[23:16]; + if (s_axi_wstrb[3]) slave_registers[15][31:24] <= s_axi_wdata[31:24]; + end + default: ; // Do nothing for invalid address, or return an error + endcase + end + end + end + +// Output Registers. + +assign o_xcom_ctrl = slave_registers[0]; //( 5 downto 0); +assign o_xcom_cfg = slave_registers[1]; //( 3 downto 0); +assign o_xcom_axi_data1 = slave_registers[2]; //(31 downto 0); +assign o_xcom_axi_data2 = slave_registers[3]; //(31 downto 0); +assign o_xcom_axi_addr = slave_registers[4]; //( 3 downto 0); + + +endmodule diff --git a/firmware/ip/xcom/src/xcom_cdc.sv b/firmware/ip/xcom/src/xcom_cdc.sv new file mode 100755 index 00000000..e2a6e00d --- /dev/null +++ b/firmware/ip/xcom/src/xcom_cdc.sv @@ -0,0 +1,283 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: xcom_cdc.sv +// Project: QICK +// Description: +// XCOM clock domain crossing synchronizer. Assumption here is that +// time_clk > core_clk > ps_clk +// +//Inputs: +// - i_ps_clk clock signal synchronous to the PS +// - i_ps_rstn active low reset signal synchronous to the PS +// - i_core_clk clock signal synchronous to the core +// - i_core_rstn active low reset signal synchronous to the core +// - i_time_clk clock signal synchronous to the time clock domain +// - i_time_rstn active low reset signal synchronous to the time clock domain +// - i_sync synchronization signal. Lets the XCOM synchronize with an +// external signal. Actuates in coordination with the +// XCOM_QRST_SYNC command. +// - i_cfg_tick this input is connected to the AXI_CFG register and +// determines the duration of the xcom_clk output signal. +// xcom_clk will be either in state 1 or 0 for CFG_AXI clock +// cycles (i_clk). Possible values ranges from 0 to 7 with +// 0 equal to two clock cycles and 7 equal to 15 clock +// cycles. As an example, if i_cfg_tick = 2 and +// i_clk = 500 MHz, then xcom_clk would be ~125 MHz. +// - i_req_net transmission requirement signal. Signal indicating a new +// data transmission starts. +// - i header this is the header to be sent to the slaves. +// bit 7 is sometimes used to indicate a +// synchronization in other places in the +// XCOM hierarchy +// bits [6:5] determines the data length to transmit: +// 00 no data +// 01 8-bit data +// 10 16-bit data +// 11 32-bit data +// bit 4 not used in this block +// bits [3:0] not used in this block. Sometimes used +// as mem_id and sometimes used as board +// ID in the XCOM hierarchy +// - i_data the data to be transmitted +//Outputs: +// - o_ready signal indicating the ip is ready to receive new data to +// transmit +// - o_data serial data transmitted. This is the general output of the +// XCOM block +// - o_clk serial clock for transmission. This is the general output of +// the XCOM block +// - o_dbg_state debug port for monitoring the state of the internal FSM +// +// Change history: 05/15/25 - Started by @lharnaldi +// +/////////////////////////////////////////////////////////////////////////////// +module xcom_cdc +( + input logic i_ps_clk , + input logic i_ps_rstn , + input logic i_core_clk , + input logic i_core_rstn , + input logic i_time_clk , + input logic i_time_rstn , +// QICK PERIPHERAL INTERFACE (i_core_clk) + input logic i_core_en , + input logic [5-1:0] i_core_op , + input logic [32-1:0] i_core_data1 , + input logic [32-1:0] i_core_data2 , + output logic o_core_en_sync , + output logic [5-1:0] o_core_op_sync , + output logic [32-1:0] o_core_data1_sync , + output logic [32-1:0] o_core_data2_sync , + input logic i_core_ready , + input logic i_core_valid , + input logic i_core_flag , + output logic o_core_ready_sync , + output logic o_core_valid_sync , + output logic o_core_flag_sync , +// XCOM + input logic [ 4-1:0] i_xcom_id , + output logic [ 4-1:0] o_xcom_id_sync , +// AXI-Lite DATA Slave I/F (i_ps_clk) + input logic [32-1:0] i_xcom_ctrl , + input logic [32-1:0] i_xcom_cfg , + input logic [32-1:0] i_axi_data1 , + input logic [32-1:0] i_axi_data2 , + output logic [32-1:0] o_xcom_ctrl_sync , + output logic [32-1:0] o_xcom_cfg_sync , + output logic [32-1:0] o_axi_data1_sync , + output logic [32-1:0] o_axi_data2_sync , + + output logic [32-1:0] o_xcom_flag_sync , + output logic [32-1:0] o_xcom_data1_sync , + output logic [32-1:0] o_xcom_data2_sync , + + input logic [32-1:0] i_xcom_rx_data , + input logic [32-1:0] i_xcom_tx_data , + input logic [32-1:0] i_xcom_status , + input logic [32-1:0] i_xcom_debug , + output logic [32-1:0] o_xcom_rx_data_sync, + output logic [32-1:0] o_xcom_tx_data_sync, + output logic [32-1:0] o_xcom_status_sync , + output logic [32-1:0] o_xcom_debug_sync +); + +//SYNC STAGES +/////////////////////////////////////////////////////////////////////////////// +//Time domain -> PS domain +synchronizer#( + .NB(4) + ) sync_id_ps( + .i_clk ( i_ps_clk ), + .i_rstn ( i_ps_rstn ), + .i_async ( i_xcom_id ), + .o_sync ( o_xcom_id_sync ) +); + +synchronizer#( + .NB(32) + ) sync_rx_data_ps( + .i_clk ( i_ps_clk ), + .i_rstn ( i_ps_rstn ), + .i_async ( i_xcom_rx_data ), + .o_sync ( o_xcom_rx_data_sync ) +); + +synchronizer#( + .NB(32) + ) sync_tx_data_ps( + .i_clk ( i_ps_clk ), + .i_rstn ( i_ps_rstn ), + .i_async ( i_xcom_tx_data ), + .o_sync ( o_xcom_tx_data_sync ) +); + +synchronizer#( + .NB(32) + ) sync_status_ps( + .i_clk ( i_ps_clk ), + .i_rstn ( i_ps_rstn ), + .i_async ( i_xcom_status ), + .o_sync ( o_xcom_status_sync ) +); + +synchronizer#( + .NB(32) + ) sync_debug_ps( + .i_clk ( i_ps_clk ), + .i_rstn ( i_ps_rstn ), + .i_async ( i_xcom_debug ), + .o_sync ( o_xcom_debug_sync ) +); + +narrow_en_signal xcom_flag( + .i_clk ( i_ps_clk ), + .i_rstn ( i_ps_rstn ), + .i_en ( i_core_flag ), + .o_en ( o_xcom_flag_sync[0] ) +); +assign o_xcom_flag_sync[32-1:1] = '0; + +synchronizer#( + .NB(32) + ) sync_data1_ps( + .i_clk ( i_ps_clk ), + .i_rstn ( i_ps_rstn ), + .i_async ( i_core_data1 ), + .o_sync ( o_xcom_data1_sync ) +); + +synchronizer#( + .NB(32) + ) sync_data2_ps( + .i_clk ( i_ps_clk ), + .i_rstn ( i_ps_rstn ), + .i_async ( i_core_data2 ), + .o_sync ( o_xcom_data2_sync ) +); + +/////////////////////////////////////////////////////////////////////////////// +//PS domain -> Time domain +synchronizer#( + .NB(6) + ) sync_xcom_ctrl( + .i_clk ( i_time_clk ), + .i_rstn ( i_time_rstn ), + .i_async ( i_xcom_ctrl[6-1:0] ), + .o_sync ( o_xcom_ctrl_sync[6-1:0] ) +); +assign o_xcom_ctrl_sync[32-1:6] = '0; + +synchronizer#( + .NB(4) + ) sync_xcom_cfg( + .i_clk ( i_time_clk ), + .i_rstn ( i_time_rstn ), + .i_async ( i_xcom_cfg[4-1:0] ), + .o_sync ( o_xcom_cfg_sync[4-1:0] ) +); +assign o_xcom_cfg_sync[32-1:4] = '0; + +synchronizer#( + .NB(32) + ) sync_axi_data1( + .i_clk ( i_time_clk ), + .i_rstn ( i_time_rstn ), + .i_async ( i_axi_data1 ), + .o_sync ( o_axi_data1_sync ) +); + +synchronizer#( + .NB(32) + ) sync_axi_data2( + .i_clk ( i_time_clk ), + .i_rstn ( i_time_rstn ), + .i_async ( i_axi_data2 ), + .o_sync ( o_axi_data2_sync ) +); + +/////////////////////////////////////////////////////////////////////////////// +//Core domain -> Time domain +wide_en_signal sync_core_en( + .i_clk ( i_time_clk ), + .i_rstn ( i_time_rstn ), + .i_en ( i_core_en ), + .o_en ( o_core_en_sync ) + ); + +synchronizer#( + .NB(5) + ) sync_core_op( + .i_clk ( i_time_clk ), + .i_rstn ( i_time_rstn ), + .i_async ( i_core_op ), + .o_sync ( o_core_op_sync ) +); + +synchronizer#( + .NB(32) + ) sync_core_data1( + .i_clk ( i_time_clk ), + .i_rstn ( i_time_rstn ), + .i_async ( i_core_data1 ), + .o_sync ( o_core_data1_sync ) +); + +synchronizer#( + .NB(32) + ) sync_core_data2( + .i_clk ( i_time_clk ), + .i_rstn ( i_time_rstn ), + .i_async ( i_core_data2 ), + .o_sync ( o_core_data2_sync ) +); + +/////////////////////////////////////////////////////////////////////////////// +//Time domain -> Core domain +narrow_en_signal sync_core_ready( + .i_clk ( i_core_clk ), + .i_rstn ( i_core_rstn ), + .i_en ( i_core_ready ), + .o_en ( o_core_ready_sync ) +); + +narrow_en_signal sync_core_flag( + .i_clk ( i_core_clk ), + .i_rstn ( i_core_rstn ), + .i_en ( i_core_flag ), + .o_en ( o_core_flag_sync ) +); + +narrow_en_signal sync_core_valid( + .i_clk ( i_core_clk ), + .i_rstn ( i_core_rstn ), + .i_en ( i_core_valid ), + .o_en ( o_core_valid_sync ) +); + +//end of SYNC STAGES +/////////////////////////////////////////////////////////////////////////////// + +endmodule diff --git a/firmware/ip/xcom/src/xcom_cmd.sv b/firmware/ip/xcom/src/xcom_cmd.sv new file mode 100755 index 00000000..40aa1202 --- /dev/null +++ b/firmware/ip/xcom/src/xcom_cmd.sv @@ -0,0 +1,92 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: xcom_cmd.sv +// Project: QICK +// Description: +// Wrapper and synchronizer block for the XCOM core. +// +//Inputs: +// - i_clk clock signal +// - i_rstn active low reset signal +// - i_core_en data valid signal coming from the core processor. Indicates +// a valid data is ready for transmission. +// - i_core_op opcode from the core. See xcom opcodes in qick_pkg +// - i_core_data data to be transmitted, coming from the core processor. +// - i ps_ctrl port used to send opcode and data valid signal from Python. +// bits [5:1] determines the operation to be done. See xcom +// opcodes in qick_pkg. +// bit 0 data valid signal coming from Python. Indicates +// a valid data is ready for transmission. +// - i_ps_data the data to be transmitted, coming from Python +// - i_ack_loc acknowledge signal to LOCAL commands. This signal is +// generated internally in the core xcom_txrx. +// - i_ack_net acknowledge signal to NETWORK commands. This signal is +// generated internally in the core xcom_txrx. +// +//Outputs: +// - o_req_loc signal requesting a LOCAL command. +// - o_req_net signal requesting a NETWORK command. +// - o_op opcode transmitted +// - o_data data transmittted +// - o_data_cntr data counter for debug +// +// Change history: 09/20/24 - v1 Started by @mdifederico +// 05/06/25 - Refactored by @lharnaldi +// - the sync_n core was removed to sync all signals +// in one place (external). +// +/////////////////////////////////////////////////////////////////////////////// +module xcom_cmd ( + input logic i_clk , + input logic i_rstn , + // Command from tProcessor + input logic i_core_en , + input logic [ 5-1:0] i_core_op , + input logic [2-1:0][32-1:0] i_core_data , + // Command from Python + input logic [ 6-1:0] i_ps_ctrl , + input logic [2-1:0][32-1:0] i_ps_data , + // Command Execution + output logic o_req_loc , + input logic i_ack_loc , + output logic o_req_net , + input logic i_ack_net , + output logic [ 8-1:0] o_op , + output logic [32-1:0] o_data , + output logic [ 4-1:0] o_data_cntr +); + +logic s_valid; +logic [5-1:0] s_op; +logic [4-1:0] s_addr; +logic [32-1:0] s_data; + + //I/O selection + assign s_valid = i_ps_ctrl[0] | i_core_en; + assign s_op = i_ps_ctrl[5:1] | i_core_op; + assign s_addr = i_ps_data[0][3:0] | i_core_data[0][3:0]; + assign s_data = i_ps_data[1] | i_core_data[1]; + + assign s_ack = i_ack_loc | i_ack_net; + +// Command Request +/////////////////////////////////////////////////////////////////////////////// +req_ack_cmd u_req_ack_cmd( + .i_clk ( i_clk ), + .i_rstn ( i_rstn ), + .i_valid ( s_valid ), + .i_op ( s_op ), + .i_addr ( s_addr ), + .i_data ( s_data ), + .i_ack ( s_ack ), + .o_req_loc ( o_req_loc ), + .o_req_net ( o_req_net ), + .o_op ( o_op ), + .o_data ( o_data ), + .o_data_cntr( o_data_cntr ) +); + +endmodule diff --git a/firmware/ip/xcom/src/xcom_link_rx.sv b/firmware/ip/xcom/src/xcom_link_rx.sv new file mode 100755 index 00000000..0f810e15 --- /dev/null +++ b/firmware/ip/xcom/src/xcom_link_rx.sv @@ -0,0 +1,194 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: xcom_link_rx.sv +// Project: QICK +// Description: Receiver interface for the XCOM block +// +//Inputs: +// - i_clk clock signal +// - i_rstn active low reset signal +// - i_id this input configures the ID of the board in the network. It +// can be configured manually or automatically. +// - i_ack it is a one clock duration signal indicating an +// acknowledgement from the tproc/pynq side. This means the +// tproc/pynq side can receive and process the data arriving in +// the XCOM link +// - i xcom_data serial data received. This is the general data input of the +// XCOM block +// - i_xcom_clk serial clock for reception. This is the general clock input of +// the XCOM block +//Outputs: +// - o_req signal indicating valid data arrived. This signal is to +// indicate to the tproc/pynq side there are new valid data to +// process. +// - o_cmd command to be executed by the tproc/pynq +// - o_data data received, to be processed by the tproc/pynq +// - o_dbg_state debug port for monitoring the state of the internal FSM +// +// Change history: 09/20/24 - v1 Started by @mdifederico +// 05/01/25 - Refactored by @lharnaldi +// - the sync_n core was removed to sync all signals +// in one place (external). +// +/////////////////////////////////////////////////////////////////////////////// + +module xcom_link_rx ( + input logic i_clk , + input logic i_rstn , + input logic [4-1:0] i_id , + // Command Processing + input logic i_ack , + output logic o_req , + output logic [4-1:0] o_cmd , + output logic [32-1:0] o_data , + // Xwire COM + input logic i_xcom_data , + input logic i_xcom_clk , + // XCOM RX DEBUG + output logic [5-1:0] o_dbg_state +); + + +logic s_no_data, s_header_last, s_timeout, s_data_last ; +logic s_broadcast, s_local_id; + +logic s_xcom_clk_dly, s_xcom_data_dly; +logic [ 8-1:0] s_header_shreg ; +logic [32-1:0] s_data_shreg ; +logic s_new_data; + +logic s_rx_idle, s_rx_header, s_rx_req ; + +typedef enum logic [3-1:0]{ IDLE = 3'b000, + HEADER = 3'b001, + DATA = 3'b010, + REQ = 3'b011, + ACK = 3'b100 +} state_t; +state_t state_r, state_n; + +logic [6-1:0] s_rx_pack_size; + +// Timeout counter, up to 32 clock cycles. This gives roughly 64 ns with +// a t_clk = 500 MHz +logic [5-1:0] timeout_cntr_r, timeout_cntr_n; +logic [6-1:0] bit_cntr_r, bit_cntr_n ; // Receive up to 40 bits + +// RX Serial to Paralel +/////////////////////////////////////////////////////////////////////////////// +assign s_new_data = s_xcom_clk_dly ^ i_xcom_clk; + +always_ff @ (posedge i_clk) begin + if (!i_rstn) begin + s_xcom_clk_dly <= 1'b0; + s_xcom_data_dly <= 1'b0; + s_data_shreg <= '0; + s_header_shreg <= '0; + end else begin + s_xcom_clk_dly <= i_xcom_clk; + s_xcom_data_dly <= i_xcom_data; + if (s_new_data) begin + if ( s_rx_header ) begin + s_header_shreg <= {s_header_shreg[8-2:0], s_xcom_data_dly}; + s_data_shreg <= '0; + end else + s_data_shreg <= {s_data_shreg[32-2:0], s_xcom_data_dly}; + end + end +end + +///// RX STATE +/////////////////////////////////////////////////////////////////////////////// +always_ff @ (posedge i_clk) begin + if ( !i_rstn ) state_r <= IDLE; + else state_r <= state_n; +end + +always_comb begin + state_n = state_r; + s_rx_idle = 1'b0; + s_rx_header = 1'b0; + s_rx_req = 1'b0; + case (state_r) + IDLE: begin + s_rx_idle = 1'b1; + if ( s_new_data ) begin //detects first 0 to 1 transition + s_rx_header = 1'b1; + state_n = HEADER; + end + end + HEADER: begin + s_rx_header = 1'b1; + if ( s_header_last ) begin + if ( s_no_data ) state_n = REQ ; // Package has No Data + else if ( s_new_data ) state_n = DATA ; // Package has Data + else if ( s_timeout ) state_n = IDLE; // TimeOut + end else if ( s_timeout ) state_n = IDLE; // False start detection (glitch), so return to IDLE. This is needed due to glitches in the communication path + end + DATA: begin + if ( s_data_last ) state_n = REQ; // Last Data Received + else if ( s_timeout ) state_n = IDLE; // TimeOut + end + REQ: begin + if ( s_broadcast | s_local_id ) begin + s_rx_req = 1'b1; + if (i_ack & !s_timeout) state_n = ACK; + else if (!i_ack & s_timeout) state_n = IDLE; + end else + state_n = IDLE; + end + ACK: begin + if (!i_ack) state_n = IDLE; + end + default: state_n = state_r; + + endcase +end + +// RX Length Decoding +/////////////////////////////////////////////////////////////////////////////// +always_comb begin + case ( s_header_shreg [6:5] ) + 2'b00 : s_rx_pack_size = 6'd8 ; //8-bit header + no data + 2'b01 : s_rx_pack_size = 6'd16 ; //8-bit header + 8-bit data + 2'b10 : s_rx_pack_size = 6'd24 ; //8-bit header + 16-bit data + 2'b11 : s_rx_pack_size = 6'd40 ; //8-bit header + 32-bit data + default: s_rx_pack_size = 6'd8 ; //8-bit header + no data + endcase +end + +/////////////////////////////////////////////////////////////////////////////// +// RX Measurment +always_ff @ (posedge i_clk) begin + if (!i_rstn) begin + bit_cntr_r <= 6'b00_0001; + timeout_cntr_r <= '0; + end else begin + bit_cntr_r <= bit_cntr_n; + timeout_cntr_r <= timeout_cntr_n; + end +end + +//next-state logic +assign bit_cntr_n = (s_new_data) ? bit_cntr_r + 1'b1 : (s_rx_idle) ? 6'b00_0001 : bit_cntr_r; +assign timeout_cntr_n = (s_new_data) ? '0 : (s_rx_idle) ? '0 : timeout_cntr_r + 1'b1; + +assign s_no_data = (s_header_shreg [5:4] == 2'b00) ; // +assign s_header_last = s_new_data & (bit_cntr_r == 5'd8) ; // Last Header bit +assign s_data_last = s_new_data & (bit_cntr_r == s_rx_pack_size ) ; // Last Data Received +assign s_broadcast = (s_header_shreg[3:0] == 4'd0); //broadcast +assign s_local_id = (s_header_shreg[3:0] == i_id) ; +assign s_timeout = &timeout_cntr_r ; // New Data was not received in time + +/////////////////////////////////////////////////////////////////////////////// +// OUTPUTS +/////////////////////////////////////////////////////////////////////////////// +assign o_dbg_state = {2'b00,state_r}; +assign o_req = s_rx_req; +assign o_cmd = s_header_shreg[7:4]; +assign o_data = s_data_shreg; + +endmodule diff --git a/firmware/ip/xcom/src/xcom_link_tx.sv b/firmware/ip/xcom/src/xcom_link_tx.sv new file mode 100755 index 00000000..134e12c2 --- /dev/null +++ b/firmware/ip/xcom/src/xcom_link_tx.sv @@ -0,0 +1,208 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: xcom_link_tx.sv +// Project: QICK +// Description: +// Transmitter interface for the XCOM block +// +//Inputs: +// - i_clk clock signal +// - i_rstn active low reset signal +// - i_cfg_tick this input is connected to the AXI_CFG register and +// determines the duration of the xcom_clk output signal. +// xcom_clk will be CFG_AXI clock cycles in states 1 and 0. +// Possible values ranges from 0 to 7 with 0 equal to two +// clock cycles and 7 equal to 15 clock cycles +// - i_valid it is a one clock duration signal indicating a valid data has +// arrived and is ready to be send through the xcom ip +// - i header this is the header to be sent to the slave. +// bit 7 is sometimes used to indicate a synchronization in other +// places in the XCOM hierarchy +// bits [6:5] determines the data length to transmit: +// 00 no data +// 01 8-bit data +// 10 16-bit data +// 11 32-bit data +// bit 4 not used in this block +// bits [3:0] not used in this block. Sometimes used as mem_id +// and sometimes used as board ID in the XCOM hierarchy +// - i_data the data to be transmitted +//Outputs: +// - o_ready signal indicating the ip is ready to receive new data to +// transmit +// - o_data serial data transmitted. This is the general output of the +// XCOM block +// - o_clk serial clock for transmission. This is the general output of +// the XCOM block +// +// Change history: 09/20/24 - v1 Started by @mdifederico +// 04/30/25 - Refactored by @lharnaldi +// - the sync_n core was removed to sync all signals +// in one place (external). +// +/////////////////////////////////////////////////////////////////////////////// + +module xcom_link_tx ( + input logic i_clk , + input logic i_rstn , + // Config + input logic [ 4-1:0] i_cfg_tick , + // Transmittion + input logic i_valid , + input logic [ 8-1:0] i_header , + input logic [32-1:0] i_data , + output logic o_ready , + // Xwire COM + output logic o_data , + output logic o_clk +); + + logic s_last; + //Out Shift Register For Par 2 Ser. (Data encoded on tx_dt) + logic [40-1:0] tx_data_r, tx_data_n ; + // Data and Clock + logic tx_clk_r, tx_clk_n; + //Number of bits transmited (Total Defined in s_tx_pkt_size) + logic [ 6-1:0] tx_bit_cnt_r, tx_bit_cnt_n; + logic [ 6-1:0] tx_pkt_size_r, tx_pkt_size_n; + + // Number of tx_clk per Data + logic [ 4-1:0] tick_cnt; + logic tick_en ; + logic tick_clk ; + logic tick_dt ; + + logic [ 6-1:0] s_tx_pkt_size ; + logic [40-1:0] tx_buff; + + typedef enum logic [2-1:0]{ TX_IDLE = 2'b00, + TX_DATA = 2'b01, + TX_CLK = 2'b10, + TX_END = 2'b11 + } state_t; + state_t state_r, state_n; + logic s_ready; + + + // TICK GENERATOR + /////////////////////////////////////////////////////////////////////////////// + always_ff @ (posedge i_clk) begin + if (!i_rstn) begin + tick_cnt <= 0; + tick_clk <= 1'b0; + tick_dt <= 1'b0; + end else begin + if (tick_en) begin + if (tick_cnt == i_cfg_tick) begin + tick_dt <= 1'b1; + tick_cnt <= 4'b0001; + end else begin + tick_dt <= 1'b0; + tick_cnt <= tick_cnt + 1'b1 ; + end + if (tick_cnt == i_cfg_tick>>1) tick_clk <= 1'b1; + else tick_clk <= 1'b0; + end else begin + tick_cnt <= i_cfg_tick>>1; + tick_dt <= 1'b0; + tick_clk <= 1'b0; + end + end + end + + // TX Encode Header + /////////////////////////////////////////////////////////////////////////////// + always_comb begin + case (i_header[6:5]) + 2'b00 : begin // NO DATA + s_tx_pkt_size = 7; + tx_buff = {i_header, 32'd0}; + end + 2'b01 : begin // 8-bit DATA + s_tx_pkt_size = 15; + tx_buff = {i_header, i_data[8-1:0], 24'd0}; + end + 2'b10 : begin // 16-bit DATA + s_tx_pkt_size = 23; + tx_buff = {i_header, i_data[16-1:0], 16'd0}; + end + 2'b11 : begin //32-bit DATA + s_tx_pkt_size = 39; + tx_buff = {i_header, i_data}; + end + endcase + end + + assign s_last = (tx_bit_cnt_r == tx_pkt_size_r) ; + + /////////////////////////////////////////////////////////////////////////////// + ///// TX STATE + //state register + always_ff @ (posedge i_clk) begin + if ( !i_rstn ) state_r <= TX_IDLE; + else state_r <= state_n; + end + + //next-state logic + always_comb begin + state_n = state_r; + tick_en = 1'b1; + s_ready = 1'b0; + case (state_r) + TX_IDLE: begin + s_ready = 1'b1; + tick_en = 1'b0; + if ( i_valid ) begin + state_n = TX_DATA; + end + end + TX_DATA: begin + if ( tick_dt ) begin + if ( s_last ) state_n = TX_END; + else state_n = TX_CLK; + end + end + TX_CLK: begin + if ( tick_clk ) state_n = TX_DATA; + end + TX_END : begin + if ( tick_clk ) state_n = TX_IDLE; + end + default: state_n = state_r; + endcase + end + + // TX Registers + /////////////////////////////////////////////////////////////////////////////// + always_ff @ (posedge i_clk) begin + if (!i_rstn) begin + tx_clk_r <= 1'b0; + tx_data_r <= '0; + tx_bit_cnt_r <= '0; + tx_pkt_size_r <= '0; + end else begin + tx_clk_r <= tx_clk_n; + tx_data_r <= tx_data_n; + tx_bit_cnt_r <= tx_bit_cnt_n; + tx_pkt_size_r <= tx_pkt_size_n; + end + end + + //next-state logic + assign tx_data_n = (i_valid & s_ready) ? tx_buff : (tick_dt) ? tx_data_r << 1 : tx_data_r; + assign tx_bit_cnt_n = (i_valid & s_ready) ? 6'b0000_01 : (tick_dt) ? tx_bit_cnt_r + 1'b1 : tx_bit_cnt_r; + assign tx_pkt_size_n = (i_valid & s_ready) ? s_tx_pkt_size : tx_pkt_size_r; + assign tx_clk_n = (s_ready) ? 1'b0 : (tick_clk) ? ~tx_clk_r : tx_clk_r; + + /////////////////////////////////////////////////////////////////////////////// + // OUTPUTS + /////////////////////////////////////////////////////////////////////////////// + + assign o_ready = s_ready; + assign o_data = tx_data_r[40-1] ; + assign o_clk = tx_clk_r; + +endmodule diff --git a/firmware/ip/xcom/src/xcom_qctrl.sv b/firmware/ip/xcom/src/xcom_qctrl.sv new file mode 100755 index 00000000..4b62c55d --- /dev/null +++ b/firmware/ip/xcom/src/xcom_qctrl.sv @@ -0,0 +1,165 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: xcom_qctrl.sv +// Project: QICK +// Description: +// Control block to instruct the tproc to start/stop internal processing. +// +//Inputs: +// - i_clk clock signal +// - i_rstn active low reset signal +// - i_sync synchronization signal. Lets the core synchronize with an +// external signal. +// - i_ctrl_req control requirement signal. +// - i_ctrl_data control code to execute when there is a i_ctrl_req +// requirement. +// - i sync_req synchronization requirement signal. +//Outputs: +//The ouput signals in this core instruct the tproc to start/stop internal +//processing +// - o_proc_start processor start signal +// - o_proc_stop processor stop signal +// - o_time_start time start signal +// - o_time_stop time stop signal +// - o_core_start core start signal +// - o_core_stop core stop signal +// +// Change history: 09/20/24 - v1 Started by @mdifederico +// 05/13/25 - Refactored by @lharnaldi +// - the sync_n core was removed to sync all signals +// in one place (external). +// 07/01/25 - @lharnaldi include timeout for state WSYNC and +// register the i_ctrl_data input to improve +// reliability +// +/////////////////////////////////////////////////////////////////////////////// + +module xcom_qctrl ( + input logic i_clk , + input logic i_rstn , + input logic i_sync , + input logic i_ctrl_req , + input logic [3-1:0] i_ctrl_data , + input logic i_sync_req , +// TPROC CONTROL + output logic o_proc_start , + output logic o_proc_stop , + output logic o_time_rst , + output logic o_time_update, + output logic o_core_start , + output logic o_core_stop +); + +logic [3-1:0] ctrl_data_r, ctrl_data_n; +logic [3-1:0] qctrl_cnt_r, qctrl_cnt_n; +logic qctrl_en; +logic qctrl_pulse_end; +logic s_proc_start, s_proc_stop; +logic s_core_start, s_core_stop; +logic s_time_rst, s_time_update; +logic sync_dly_r, sync_dly_n; +logic s_sync ; +logic s_timeout; + +// Timeout counter, up to 2^30 clock cycles. This gives roughly 2.14 s with +// a t_clk = 500 MHz +logic [30-1:0] timeout_cntr_r, timeout_cntr_n; + +typedef enum logic [2-1:0]{ IDLE = 2'b00, + WSYNC = 2'b01, + EXEC_RST = 2'b10, + EXEC_CTRL = 2'b11 +} state_t; +state_t state_r, state_n; + +// PULSE SYNC +/////////////////////////////////////////////////////////////////////////////// +always_ff@(posedge i_clk) begin + if (!i_rstn) sync_dly_r <= 1'b0; + else sync_dly_r <= sync_dly_n; +end + +assign sync_dly_n = i_sync; +assign s_sync = !sync_dly_r & i_sync ; + +assign qctrl_pulse_end = (qctrl_cnt_r == '1); + +// PROCESSOR CONTROL +/////////////////////////////////////////////////////////////////////////////// +always_ff @ (posedge i_clk) begin + if ( !i_rstn ) state_r <= IDLE; + else state_r <= state_n; +end + +always_comb begin + state_n = state_r; + s_proc_start = 1'b0; + s_proc_stop = 1'b0; + s_time_rst = 1'b0; + s_time_update = 1'b0; + s_core_start = 1'b0; + s_core_stop = 1'b0; + qctrl_en = 1'b0; + case (state_r) + IDLE: + if ( i_sync_req ) state_n = WSYNC; + else if ( i_ctrl_req ) state_n = EXEC_CTRL; + + WSYNC: begin + if ( s_sync ) state_n = EXEC_RST; + else if ( s_timeout ) state_n = IDLE; // TimeOut + end + + EXEC_RST: begin + s_proc_start = 1'b1; + qctrl_en = 1'b1; + if ( qctrl_pulse_end ) state_n = IDLE; + end + + EXEC_CTRL: begin + qctrl_en = 1'b1; + case ( ctrl_data_r ) + 3'b010 : s_time_rst = 1'b1; + 3'b011 : s_time_update = 1'b1; + 3'b100 : s_core_start = 1'b1; + 3'b101 : s_core_stop = 1'b1; + 3'b110 : s_proc_start = 1'b1; + 3'b111 : s_proc_stop = 1'b1; + endcase + if ( qctrl_pulse_end ) state_n = IDLE; + end + + default: state_n = state_r; + endcase +end + +always_ff @ (posedge i_clk) begin + if ( !i_rstn ) begin + qctrl_cnt_r <= '0; + timeout_cntr_r <= '0; + ctrl_data_r <= '0; + end else begin + qctrl_cnt_r <= qctrl_cnt_n; + timeout_cntr_r <= timeout_cntr_n; + ctrl_data_r <= ctrl_data_n; + end +end +//next-state logic +assign ctrl_data_n = (i_ctrl_req) ? i_ctrl_data : ctrl_data_r; +assign qctrl_cnt_n = (qctrl_en) ? qctrl_cnt_r + 1'b1 : '0; +assign timeout_cntr_n = (state_r == WSYNC) ? timeout_cntr_r + 1'b1 : '0; +assign s_timeout = &timeout_cntr_r ; // New sync signal was not received in time + +// OUTPUTS +/////////////////////////////////////////////////////////////////////////////// +assign o_proc_start = s_proc_start; +assign o_proc_stop = s_proc_stop; +assign o_core_start = s_core_start; +assign o_core_stop = s_core_stop; +assign o_time_rst = s_time_rst; +assign o_time_update = s_time_update; + +endmodule diff --git a/firmware/ip/xcom/src/xcom_txrx.sv b/firmware/ip/xcom/src/xcom_txrx.sv new file mode 100644 index 00000000..45ef20d5 --- /dev/null +++ b/firmware/ip/xcom/src/xcom_txrx.sv @@ -0,0 +1,459 @@ +/////////////////////////////////////////////////////////////////////////////// +// vim:set shiftwidth=3 softtabstop=3 expandtab: +// +// Fermi Fordward Alliance LLC +// +// Module: xcom_txrx.sv +// Project: QICK +// Description: +// Transmitter and Receiver interface wrapper for the XCOM block. +// +//Inputs: +// - i_clk clock signal +// - i_rstn active low reset signal +// - i_sync synchronization signal. Lets the XCOM synchronize with an +// external signal. Actuates in coordination with the +// XCOM_QRST_SYNC command. +// - i_req_loc local command requirement signal. Signal indicating a new +// data is available to write locally (in the local board). +// - i_req_net transmission requirement signal. Signal indicating a new +// data transmission starts. +// - i header this is the header to be sent to the slaves. +// It is used by the tx_cmd instance here. See the +// documentation in that core. +// - i_data the data to be transmitted. It is used by the tx_cmd +// instance here and for some LOC commands. +// - i_cfg_tick this input is connected to the AXI_CFG register and +// determines the duration of the xcom_clk output signal. +// It is used by the tx_cmd instance here. See the +// documentation in that core. +// - i xcom_data serial data received. This is the general data input of the +// XCOM block +// - i_xcom_clk serial clock for reception. This is the general clock input of +// the XCOM block +// +//Outputs: +// - o_ack_loc acknowledge signal to LOC commands. +// - o_ack_net acknowledge signal to NET commands. +// +//QICK interface: +// - o_qp_ready signal indicating the ip is ready to receive new data to +// transmit +// - o_qp_valid signal indicating the ip has valid data to write into the +// local board +// - o_qp_flag signal indicating to write flag into the core +// - o_qp_data1 data1 to core +// - o_qp_data2 data2 to core +// +//TPROC CONTROL INTERFACE +// - o_proc_start start signal to the tproc +// - o_proc_stop stop signal to the tproc +// - o_time_rst reset the time reference in processor +// - o_time_update update the time in processor +// - o_time_update_data data to update the time in processor +// - o_core_start start signal to the core in tproc +// - o_core_stop stop signal to the core in tproc +// +// XCOM CONFIG +// - o xcom_data serial data transmitted. This is the general data output of the +// XCOM block +// - o_xcom_clk serial clock for transmission. This is the general clock output of +// the XCOM block +// - o_xcom_id board ID. This is a signal to see the board ID into external +// LEDs. +// - o_xcom_mem internal 16-word memory port +// - o_dbg_rx_data debug port for monitoring the rx data +// - o_dbg_tx_data debug port for monitoring the tx data +// - o_dbg_state debug port for monitoring the state of the internal FSM +// - o_dbg_data debug port for monitoring the internal data state +// +// Change history: 09/20/24 - v1 Started by @mdifederico +// 05/13/25 - Refactored by @lharnaldi +// - the sync_n core was removed to sync all signals +// in one place (external). +// +/////////////////////////////////////////////////////////////////////////////// +module xcom_txrx import qick_pkg::*; +#( + parameter NCH = 2 , + parameter SYNC = 1 +)( + input logic i_clk , + input logic i_rstn , + input logic i_sync , +// COMMAND INTERFACE + input logic i_req_loc , + input logic i_req_net , + input logic [ 8-1:0] i_header , + input logic [32-1:0] i_data , + output logic o_ack_loc , + output logic o_ack_net , +// QICK INTERFACE + output logic o_qp_ready , + output logic o_qp_valid , + output logic o_qp_flag , + output logic [32-1:0] o_qp_data1 , + output logic [32-1:0] o_qp_data2 , +// QICK PROCESSOR CONTROL + output logic o_proc_start , + output logic o_proc_stop , + output logic o_time_rst , + output logic o_time_update , + output logic [32-1:0] o_time_update_data , + output logic o_core_start , + output logic o_core_stop , +// XCOM CFG + input logic [4-1:0] i_cfg_tick , + output logic [ 4-1:0] o_xcom_id , + output logic [32-1:0] o_xcom_mem[16] , +// Xlogic COM + input logic [NCH-1:0] i_xcom_data , + input logic [NCH-1:0] i_xcom_clk , + output logic o_xcom_data , + output logic o_xcom_clk , +// DEBUG + output logic [32-1:0] o_dbg_rx_data , + output logic [32-1:0] o_dbg_tx_data , + output logic [21-1:0] o_dbg_status , + output logic [32-1:0] o_dbg_data +); + +// SIGNAL DECLARATION +/////////////////////////////////////////////////////////////////////////////// +logic [4-1:0] s_cfg_tick; +logic [5-1:0] s_rx_dbg_state [NCH]; +logic [2-1:0] s_tx_dbg_state; + +logic [6-1:0] s_loc_dbg_status; +logic [10-1:0] s_net_dbg_status; +logic [9-1:0] rx_cmd_ds; + +logic rx_no_dt, rx_wflg, rx_wreg, rx_wmem ; +logic rx_wflg_en, rx_wreg_en, rx_wmem_en; +logic rx_qsync, rx_qctrl, rx_auto_id, rx_rst; + +logic s_data_flag; +logic data_flag, wreg_r ; +logic [32-1:0] reg_dt_s; +logic [ 4-1:0] mem_addr; +logic [32-1:0] reg1_dt, reg2_dt; +logic [32-1:0] mem_data [16]; +logic s_cmd_exec; + +logic set_id_flg, wflg_flg, wreg_flg, wmem_flg; +logic s_loc_sid; //local set ID +logic s_wflg, s_wreg, s_wmem, s_rst; +logic [ 4-1:0] loc_cmd_op ; + +logic [ 4-1:0] s_rx_chid, s_rx_op ; +logic [32-1:0] s_rx_data ; + +logic tx_auto_id; +logic tx_qrst_sync; +logic [NCH-1:0]s_xcom_clk_sync; +logic [NCH-1:0]s_xcom_data_sync; + +//TX related signals +logic s_nack; +logic s_lack; +logic s_tx_ready; +logic s_req_net; + +//RX related signals +logic [4-1:0] board_id_r, board_id_n; + + typedef enum logic [4-1:0] {IDLE = 4'b0000, + ST_LOC = 4'b0001, + ST_NET = 4'b0010, + ST_SID = 4'b0011, + ST_WFLG = 4'b0100, + ST_WREG = 4'b0101, + ST_WMEM = 4'b0110, + ST_RST = 4'b0111, + ST_WNET = 4'b1000, + ST_LACK = 4'b1001, + ST_NACK = 4'b1010 + } state_t; + + state_t state_r, state_n; + + //State register + always_ff @ (posedge i_clk) begin + if ( !i_rstn ) state_r <= IDLE; + else state_r <= state_n; + end + + //next state logic + always_comb begin + state_n = state_r; + s_loc_sid = 1'b0; + s_wflg = 1'b0; + s_wreg = 1'b0; + s_wmem = 1'b0; + s_rst = 1'b0; + s_lack = 1'b0; + s_nack = 1'b0; + s_req_net = 1'b0; + case (state_r) + IDLE: begin + if( i_req_loc ) begin + state_n = ST_LOC; + end else if ( i_req_net ) begin + state_n = ST_NET; + end else begin + state_n = IDLE; + end + end + ST_LOC: begin + if ( set_id_flg ) begin + state_n = ST_SID; + end else if ( wflg_flg ) begin + state_n = ST_WFLG; + end else if ( wreg_flg ) begin + state_n = ST_WREG; + end else if ( wmem_flg ) begin + state_n = ST_WMEM; + end else if ( rst_flg ) begin + state_n = ST_RST; + end else begin + state_n = IDLE; + end + end + ST_SID: begin + s_loc_sid = 1'b1; + state_n = ST_LACK; + end + ST_WFLG: begin + s_wflg = 1'b1; + state_n = ST_LACK; + end + ST_WREG: begin + s_wreg = 1'b1; + state_n = ST_LACK; + end + ST_WMEM: begin + s_wmem = 1'b1; + state_n = ST_LACK; + end + ST_RST: begin + s_rst = 1'b1; + state_n = ST_LACK; + end + ST_NET: begin + s_req_net = 1'b1; + if ( !s_tx_ready ) begin + state_n = ST_WNET; + end else begin + state_n = ST_NET; + end + end + ST_WNET: begin + if ( s_tx_ready ) begin + state_n = ST_NACK; + end else begin + state_n = ST_WNET; + end + end + ST_LACK: begin + s_lack = 1'b1; + state_n = IDLE; + end + ST_NACK: begin + s_nack = 1'b1; + state_n = IDLE; + end + default: + state_n = state_r; + endcase + end + +// LOC COMMAND +// LOC Decoding +/////////////////////////////////////////////////////////////////////////////// +assign loc_cmd_op = i_header[7:4]; +assign set_id_flg = (loc_cmd_op == XCOM_SET_ID ); +assign wflg_flg = (loc_cmd_op == XCOM_WRITE_FLAG ); +assign wreg_flg = (loc_cmd_op == XCOM_WRITE_REG ); +assign wmem_flg = (loc_cmd_op == XCOM_WRITE_MEM ); +assign rst_flg = (loc_cmd_op == XCOM_RST ); +assign s_cmd_exec = s_loc_sid | s_wflg | s_wreg | s_wmem | s_rst; + +//Transmission +// TRANSMIT NET COMMAND +/////////////////////////////////////////////////////////////////////////////// +assign s_cfg_tick = {i_cfg_tick[3-1:0]+1'b1, 1'b0}; + +tx_cmd u_tx_cmd( + .i_clk ( i_clk ), + .i_rstn ( i_rstn ), + .i_sync ( i_sync ), + .i_cfg_tick ( s_cfg_tick ), + .i_req ( s_req_net ), + .i_header ( i_header ), + .i_data ( i_data ), + .o_ready ( s_tx_ready ), + .o_data ( o_xcom_data ), + .o_clk ( o_xcom_clk ), + .o_dbg_state( s_tx_dbg_state ) +); + +assign tx_auto_id = s_req_net & (loc_cmd_op == XCOM_AUTO_ID); + +//logic to take into account the XCOM_QRST_SYNC command for board +//synchronization +assign tx_qrst_sync = s_nack & (loc_cmd_op == XCOM_QRST_SYNC); + +//end Transmission +// +// Reception +// Write ID +/////////////////////////////////////////////////////////////////////////////// +always_ff @ (posedge i_clk) begin + if ( !i_rstn | s_rst | rx_rst ) board_id_r <= '0; + else board_id_r <= board_id_n; +end +//next-state logic +always_comb begin + if ( s_loc_sid ) board_id_n = i_header[4-1:0]; + else if ( rx_auto_id ) board_id_n = s_rx_chid + 1'b1; + else board_id_n = board_id_r; +end + +// RX COMMAND +/////////////////////////////////////////////////////////////////////////////// +synchronizer#( + .NB(NCH) + ) sync_xcom_clk( + .i_clk ( i_clk ), + .i_rstn ( i_rstn ), + .i_async ( i_xcom_clk ), + .o_sync ( s_xcom_clk_sync ) +); +synchronizer#( + .NB(NCH) + ) sync_xcom_data( + .i_clk ( i_clk ), + .i_rstn ( i_rstn ), + .i_async ( i_xcom_data ), + .o_sync ( s_xcom_data_sync ) +); + +rx_cmd#(.NCH(NCH)) u_rx_cmd( + .i_clk ( i_clk ), + .i_rstn ( i_rstn ), + .i_id ( board_id_r ), + .i_xcom_data ( s_xcom_data_sync ), + .i_xcom_clk ( s_xcom_clk_sync ), + .o_valid ( s_rx_valid ), + .o_op ( s_rx_op ), + .o_data ( s_rx_data ), + .o_chid ( s_rx_chid ), + .o_dbg_state ( s_rx_dbg_state ) +); + +// RX Decoding +/////////////////////////////////////////////////////////////////////////////// +assign rx_no_dt = ~|s_rx_op[2:1]; +assign rx_wflg = !s_rx_op[3] & rx_no_dt ; //000X +assign rx_wreg = !s_rx_op[3] & !rx_no_dt & ~s_rx_op[0]; //001X-010X-011X +assign rx_wmem = !s_rx_op[3] & !rx_no_dt & s_rx_op[0]; //000X + +assign rx_wflg_en = s_rx_valid & rx_wflg; +assign rx_wreg_en = s_rx_valid & rx_wreg; +assign rx_wmem_en = s_rx_valid & rx_wmem; + +assign rx_auto_id = s_rx_valid & s_rx_op == XCOM_AUTO_ID; +assign rx_qsync = (s_rx_valid & s_rx_op == XCOM_QRST_SYNC) | (tx_qrst_sync); +assign rx_qctrl = s_rx_valid & s_rx_op == XCOM_QCTRL; +assign rx_rst = s_rx_valid & s_rx_op == XCOM_RST; +//end Reception +// + +// EXECUTE COMMANDS +/////////////////////////////////////////////////////////////////////////////// + +// Write Register +/////////////////////////////////////////////////////////////////////////////// +assign wflg_en = s_wflg | rx_wflg_en ; +assign wreg_en = s_wreg | rx_wreg_en ; +assign wmem_en = s_wmem | rx_wmem_en ; + +assign s_data_flag = s_cmd_exec ? i_header[0] : s_rx_op[0]; +assign reg_dt_s = s_cmd_exec ? i_data : s_rx_data; +assign mem_addr = s_cmd_exec ? i_header[3:0] : s_rx_chid+1'b1 ; + +always_ff @ (posedge i_clk) begin + if (!i_rstn | s_rst | rx_rst ) begin + data_flag <= 1'b0; + reg1_dt <= '{default:'0} ; + reg2_dt <= '{default:'0} ; + mem_data <= '{default:'0} ; + wreg_r <= 1'b0; + end else begin + wreg_r <= wreg_en ; + if ( wflg_en ) + data_flag <= s_data_flag; // FLAG + else if ( wreg_en ) + case ( s_data_flag ) + 1'b0 : reg1_dt <= reg_dt_s; // Reg_dt1 + 1'b1 : reg2_dt <= reg_dt_s; // Reg_dt2 + endcase + else if ( wmem_en ) + mem_data[mem_addr] <= reg_dt_s; + end +end + +/////////////////////////////////////////////////////////////////////////////// +// SYNC OPTION +/////////////////////////////////////////////////////////////////////////////// + +generate + if (SYNC == 0) begin : SYNC_NO + + end else if (SYNC == 1) begin : SYNC_YES + xcom_qctrl u_xcom_qctrl( + .i_clk ( i_clk ), + .i_rstn ( i_rstn ), + .i_sync ( i_sync ), + .i_ctrl_req ( rx_qctrl ), + .i_ctrl_data ( s_rx_data[2:0] ), + .i_sync_req ( rx_qsync ), + .o_proc_start ( o_proc_start ), + .o_proc_stop ( o_proc_stop ), + .o_time_rst ( o_time_rst ), + .o_time_update( o_time_update ), + .o_core_start ( o_core_start ), + .o_core_stop ( o_core_stop ) + ); + end +endgenerate + +// DEBUG +/////////////////////////////////////////////////////////////////////////////// +assign s_loc_dbg_status = {wmem_flg, wreg_flg, wflg_flg, set_id_flg, s_lack, i_req_loc}; +assign s_net_dbg_status = {i_header, s_nack, i_req_net}; +assign rx_cmd_ds = {rx_wmem, rx_wreg, rx_wflg, rx_no_dt, tx_auto_id, s_rx_op}; + +assign o_dbg_rx_data = s_rx_data; +assign o_dbg_tx_data = i_data; + +assign o_dbg_status = {board_id_r, s_tx_ready, 5'b0_0000, s_rx_dbg_state[0], 2'b00, s_rx_valid, rx_qctrl, s_tx_dbg_state};//FIXME: here was cmd_st_ds. Also we are seeing only state[0] here +assign o_dbg_data = {s_cfg_tick, s_rx_chid, rx_cmd_ds, s_net_dbg_status, s_loc_dbg_status};//4+4+9+10+6 + + +// OUT SIGNALS +/////////////////////////////////////////////////////////////////////////////// +assign o_qp_ready = s_tx_ready & ~i_req_loc & ~s_lack; +assign o_qp_flag = data_flag; +assign o_qp_valid = wreg_r; +assign o_qp_data1 = reg1_dt; +assign o_qp_data2 = reg2_dt; +assign o_xcom_id = board_id_r; +assign o_xcom_mem = mem_data; + +assign o_time_update_data = reg1_dt; + +assign o_ack_loc = s_lack ; +assign o_ack_net = s_nack; + +endmodule diff --git a/firmware/ip/xcom/xgui/xcom_v1_0.tcl b/firmware/ip/xcom/xgui/xcom_v1_0.tcl new file mode 100755 index 00000000..918d7021 --- /dev/null +++ b/firmware/ip/xcom/xgui/xcom_v1_0.tcl @@ -0,0 +1,55 @@ +# Definitional proc to organize widgets for parameters. +proc init_gui { IPINST } { + ipgui::add_param $IPINST -name "Component_Name" + #Adding Page + set Page_0 [ipgui::add_page $IPINST -name "Page 0"] + ipgui::add_param $IPINST -name "NCH" -parent ${Page_0} + ipgui::add_param $IPINST -name "SYNC" -parent ${Page_0} + ipgui::add_param $IPINST -name "DEBUG" -parent ${Page_0} + + +} + +proc update_PARAM_VALUE.DEBUG { PARAM_VALUE.DEBUG } { + # Procedure called to update DEBUG when any of the dependent parameters in the arguments change +} + +proc validate_PARAM_VALUE.DEBUG { PARAM_VALUE.DEBUG } { + # Procedure called to validate DEBUG + return true +} + +proc update_PARAM_VALUE.NCH { PARAM_VALUE.NCH } { + # Procedure called to update NCH when any of the dependent parameters in the arguments change +} + +proc validate_PARAM_VALUE.NCH { PARAM_VALUE.NCH } { + # Procedure called to validate NCH + return true +} + +proc update_PARAM_VALUE.SYNC { PARAM_VALUE.SYNC } { + # Procedure called to update SYNC when any of the dependent parameters in the arguments change +} + +proc validate_PARAM_VALUE.SYNC { PARAM_VALUE.SYNC } { + # Procedure called to validate SYNC + return true +} + + +proc update_MODELPARAM_VALUE.NCH { MODELPARAM_VALUE.NCH PARAM_VALUE.NCH } { + # Procedure called to set VHDL generic/Verilog parameter value(s) based on TCL parameter value + set_property value [get_property value ${PARAM_VALUE.NCH}] ${MODELPARAM_VALUE.NCH} +} + +proc update_MODELPARAM_VALUE.SYNC { MODELPARAM_VALUE.SYNC PARAM_VALUE.SYNC } { + # Procedure called to set VHDL generic/Verilog parameter value(s) based on TCL parameter value + set_property value [get_property value ${PARAM_VALUE.SYNC}] ${MODELPARAM_VALUE.SYNC} +} + +proc update_MODELPARAM_VALUE.DEBUG { MODELPARAM_VALUE.DEBUG PARAM_VALUE.DEBUG } { + # Procedure called to set VHDL generic/Verilog parameter value(s) based on TCL parameter value + set_property value [get_property value ${PARAM_VALUE.DEBUG}] ${MODELPARAM_VALUE.DEBUG} +} + diff --git a/qick_lib/qick/VERSION b/qick_lib/qick/VERSION index c2c94e15..365ff4c9 100644 --- a/qick_lib/qick/VERSION +++ b/qick_lib/qick/VERSION @@ -1 +1 @@ -0.2.353 +0.2.349 diff --git a/qick_lib/qick/drivers/xcom.py b/qick_lib/qick/drivers/xcom.py new file mode 100644 index 00000000..ff2ffadf --- /dev/null +++ b/qick_lib/qick/drivers/xcom.py @@ -0,0 +1,265 @@ +""" +####################################### +XCOM driver for qick_processor. +2025-06-17 + +####################################### +""" +import numpy as np +from qick.ip import SocIP +import re + +class QICK_Xcom(SocIP): + """ + QICK_Comm class + #################### + QICK COM xREG + #################### + XCOM_CTRL Write / Read 32-Bits + XCOM_CFG Write / Read 32-Bits + AXI_DT1 Write / Read 32-Bits + AXI_DT2 Write / Read 32-Bits + AXI_ADDR Write / Read 32-Bits + BOARD_ID Read Only 32-Bits + XCOM_FLAG Read Only 32-Bits + XCOM_DT1 Read Only 32-Bits + XCOM_DT2 Read Only 32-Bits + XCOM_MEM Read Only 32-Bits + XCOM_RX_DT Read Only 32-Bits + XCOM_TX_DT Read Only 32-Bits + XCOM_STATUS Read Only 32-Bits + XCOM_DEBUG Read Only 32-Bits + """ + bindto = ['QICK:QICK:xcom:1.0','user.org:user:xcom_axil_slv:1.0'] + + def __init__(self, description): + """ + Constructor method + """ + super().__init__(description) + + self.REGISTERS = { + 'xcom_ctrl' :0 , + 'xcom_cfg' :1 , + 'axi_dt1' :2 , + 'axi_dt2' :3 , + 'axi_addr' :4 , + 'board_id' :6 , + 'flag' :7 , + 'dt1' :8 , + 'dt2' :9, + 'mem' :10, + 'rx_dt' :12, + 'tx_dt' :13, + 'status' :14, + 'debug' :15 + } + + self.opcodes = { + 'XCOM_RST' : 31 , #5'b1_1111 ;//LOC command + 'XCOM_WRITE_MEM' : 19 , #5'b1_0011 ;//LOC command + 'XCOM_WRITE_REG' : 18 , #5'b1_0010 ;//LOC command + 'XCOM_WRITE_FLAG' : 17 , #5'b1_0001 ;//LOC command + 'XCOM_SET_ID' : 16 , #5'b1_0000 ;//LOC command + 'XCOM_RFU2' : 15 , #5'b0_1111 ; + 'XCOM_RFU1' : 13 , #5'b0_1101 ; + 'XCOM_QCTRL' : 11 , #5'b0_1011 ; + 'XCOM_UPDATE_DT32' : 14 , #5'b0_1110 ; + 'XCOM_UPDATE_DT16' : 12 , #5'b0_1100 ; + 'XCOM_UPDATE_DT8' : 10 , #5'b0_1010 ; + 'XCOM_AUTO_ID' : 9 , #5'b0_1001 ; + 'XCOM_QRST_SYNC' : 8 , #5'b0_1000 ; + 'XCOM_SEND_32BIT_2': 7 , #5'b0_0111 ; + 'XCOM_SEND_32BIT_1': 6 , #5'b0_0110 ; + 'XCOM_SEND_16BIT_2': 5 , #5'b0_0101 ; + 'XCOM_SEND_16BIT_1': 4 , #5'b0_0100 ; + 'XCOM_SEND_8BIT_2' : 3 , #5'b0_0011 ; + 'XCOM_SEND_8BIT_1' : 2 , #5'b0_0010 ; + 'XCOM_SET_FLAG' : 1 , #5'b0_0001 ; + 'XCOM_CLEAR_FLAG' : 0 #5'b0_0000 ; + } + + + # Initial Values + self.xcom_ctrl = 0 + self.xcom_cfg = 0 + self.axi_dt1 = 0 + self.axi_dt2 = 0 + self.axi_addr = 0 + + def __str__(self): + lines = [] + lines.append('---------------------------------------------') + lines.append(' QICK Xcom INFO ') + lines.append('---------------------------------------------') + lines.append("----------\n") + return "\n".join(lines) + + def clear_flag(self, dst): + if (dst < 16 ): + self.axi_dt1 = dst + self.xcom_ctrl = 1+2*0 + else: + raise RuntimeError('Destination Board error should be between 1 and 15 - current Value : %d' % (dst)) + + def set_flag(self, dst): + if (dst < 16 ): + self.axi_dt1 = dst + self.xcom_ctrl = 1+2*1 + else: + raise RuntimeError('Destination Board error should be between 1 and 15 - current Value : %d' % (dst)) + + def set_local_id(self, chid): + if (chid < 16 ): + self.axi_dt1 = chid + self.xcom_ctrl = 1+2*16 + else: + raise RuntimeError('Board ID number should be between 1 and 15 - current Value : %d' % (chid)) + + def write_local_flag(self, flg): + if (flg == 1 ): + self.axi_dt1 = flg + self.xcom_ctrl = 1+2*17 + else: + raise RuntimeError('Flag must be 1 - current Value : %d' % (flg)) + + def send_byte(self, data, dst, reg): + if (dst < 16 ): + self.axi_dt1 = dst + self.axi_dt2 = data + if (reg == 1): + self.xcom_ctrl = 1+2*2 + elif (reg == 2): + self.xcom_ctrl = 1+2*3 + else: + raise RuntimeError('Destination Register error should be 1 or 2 current Value : %d' % (reg)) + else: + raise RuntimeError('Destination Board error should be between 1 and 15 - current Value : %d' % (dst)) + + def send_half_word(self, data, dst, reg): + if (dst < 16 ): + self.axi_dt1 = dst + self.axi_dt2 = data + if (reg == 1): + self.xcom_ctrl = 1+2*4 + elif (reg == 2): + self.xcom_ctrl = 1+2*5 + else: + raise RuntimeError('Destination Register error should be 1 or 2 current Value : %d' % (reg)) + else: + raise RuntimeError('Destination Board error should be between 1 and 15 - current Value : %d' % (dst)) + + def send_word(self, data, dst, reg): + if (dst < 16 ): + self.axi_dt1 = dst + self.axi_dt2 = data + if (reg == 1): + self.xcom_ctrl = 1+2*6 + elif (reg == 2): + self.xcom_ctrl = 1+2*7 + else: + raise RuntimeError('Destination Register error should be 1 or 2 current Value : %d' % (reg)) + else: + raise RuntimeError('Destination Board error should be between 1 and 15 - current Value : %d' % (dst)) + + def auto_id(self): + self.axi_dt1 = 0 + self.axi_dt2 = 0 + self.xcom_ctrl = 1+2*9 + + def update_byte(self, data, dst): + if (dst < 16 ): + self.axi_dt1 = dst + self.axi_dt2 = data + self.xcom_ctrl = 1+2*10 + else: + raise RuntimeError('Destination Board error should be between 0 and 15 - current Value : %d' % (dst)) + + def run_cmd(self, cmd, dt1, dt2): + self.axi_dt1 = dt1 + self.axi_dt2 = dt2 + self.xcom_ctrl = 1+2*cmd + + + def print_dt(self): + print("FLAG:{} DT1:{} DT2:{} ".format(self.flag, self.dt1, self.dt2)) + + def print_axi_regs(self): + print('---------------------------------------------') + print('--- AXI Registers') + for xreg in self.REGISTERS.keys(): + reg_num = getattr(self, xreg) + reg_bin = '{:039_b}'.format(reg_num) + print(f'{xreg:>10}', f'{reg_num:>11}'+' - '+f'{reg_bin:>33}' ) + + def print_status(self): + debug_num = self.status + debug_bin = '{:032b}'.format(debug_num) + #print(debug_bin) + print('---------------------------------------------') + print('--- AXI XCOM Register STATUS') + tx_status = debug_num & 0x3 + if tx_status == 0: + print( ' tx_st : ' + 'IDLE') + elif tx_status == 1: + print( ' tx_st : ' + 'WVLD') + elif tx_status == 2: + print( ' tx_st : ' + 'WSYNC') + elif tx_status == 3: + print( ' tx_st : ' + 'WRDY' ) + else: + print( ' tx_st : ' + 'UNKNOWN' ) + + rx_status = (debug_num & 0x01C0)>>6 + if rx_status == 0: + print( ' rx_st : ' + 'IDLE') + elif rx_status == 1: + print( ' rx_st : ' + 'HEADER') + elif rx_status == 2: + print( ' rx_st : ' + 'DATA') + elif rx_status == 3: + print( ' rx_st : ' + 'REQ' ) + elif rx_status == 4: + print( ' rx_st : ' + 'ACK' ) + else: + print( ' rx_st : ' + 'UNKNOWN' ) + + print( ' tx_ready : ' + debug_bin[15] ) + print( ' board_id : ' + debug_bin[11:15] ) + print( ' rx_data_cntr : ' + debug_bin[7:11] ) + + def print_debug(self): + debug_num = self.debug + debug_bin = '{:032b}'.format(debug_num) + #print(debug_num, debug_bin) + print('---------------------------------------------') + print('--- AXI XCOM DEBUG') + print( ' cmd_loc_req_i : ' + debug_bin[31] ) + print( ' cmd_loc_ack : ' + debug_bin[30] ) + print( ' loc_set_id : ' + debug_bin[29] ) + print( ' loc_wflg : ' + debug_bin[28] ) + print( ' loc_wreg : ' + debug_bin[27] ) + print( ' loc_wmem : ' + debug_bin[26] ) + print( ' cmd_net_req_i : ' + debug_bin[25] ) + print( ' cmd_net_ack : ' + debug_bin[24] ) + print( ' cmd_op_i : ' + debug_bin[16:24] ) + print( ' rx_cmd_op : ' + debug_bin[12:16] ) + print( ' tx_auto_id : ' + debug_bin[11] ) + print( ' rx_no_dt : ' + debug_bin[10] ) + print( ' rx_wflg : ' + debug_bin[9] ) + print( ' rx_wreg : ' + debug_bin[8] ) + print( ' rx_wmem : ' + debug_bin[7] ) + print( ' rx_cmd_id : ' + debug_bin[4:7] ) + print( ' cfg_i : ' + debug_bin[0:4] ) + print('---------------------------------------------') + print('--- AXI XCOM RX_DT') + debug_num = self.rx_dt + debug_bin = '{:032b}'.format(debug_num) + print('rx_dt ', f'{debug_num:>11}'+' - '+f'{debug_bin:>33}' ) + print('---------------------------------------------') + print('--- AXI XCOM TX_DT') + debug_num = self.tx_dt + debug_bin = '{:032b}'.format(debug_num) + print('tx_dt ', f'{debug_num:>11}'+' - '+f'{debug_bin:>33}' ) + + diff --git a/qick_lib/qick/qick.py b/qick_lib/qick/qick.py index 1391b49c..ddc5ee3e 100644 --- a/qick_lib/qick/qick.py +++ b/qick_lib/qick/qick.py @@ -21,6 +21,7 @@ from .drivers.generator import * from .drivers.readout import * from .drivers.tproc import * +from .drivers.xcom import * logger = logging.getLogger(__name__)