From e6470cf8ceeb0cf0d523455273030179036c57f6 Mon Sep 17 00:00:00 2001 From: Max Becker Date: Tue, 15 Sep 2026 11:19:48 +0200 Subject: [PATCH] fpga: x4xx: Extend GPIO SPI support Extend GPIO SPI transactions up to 64 bits and update the X4xx FPGA register map and RTL to support the new access width. Migrate the GPIO SPI register definitions to SystemVerilog. Add testbench for X4xx GPIO SPI module covering both exisiting 32bit functionality and added 64bit functionality. Separate TB Makefiles for X4xx and X410 implementation variant. Bump the FPGA compatibility number so host and MPM software can reject images that do not provide the required GPIO SPI register interface. --- fpga/usrp3/top/x400/Makefile.x4xx.inc | 3 +- fpga/usrp3/top/x400/doc/X410/X410_FPGA.htm | 303 ++++++++++++--- fpga/usrp3/top/x400/doc/X420/X420_FPGA.htm | 303 ++++++++++++--- fpga/usrp3/top/x400/doc/X440/X440_FPGA.htm | 303 ++++++++++++--- .../top/x400/regmap/XmlSvPkgDIG_IFC_REGMAP.sv | 163 ++++++++ .../top/x400/regmap/dig_ifc_regmap_utils.vh | 102 ----- .../x410/versioning_regs_regmap_utils.vh | 6 +- .../x420/versioning_regs_regmap_utils.vh | 6 +- .../x440/versioning_regs_regmap_utils.vh | 6 +- .../x400/sim/x4xx_gpio_spi_tb/x410/Makefile | 23 ++ .../x400/sim/x4xx_gpio_spi_tb/x4xx/Makefile | 20 + .../sim/x4xx_gpio_spi_tb/x4xx/Makefile.common | 21 + .../sim/x4xx_gpio_spi_tb/x4xx_gpio_spi_tb.sv | 364 ++++++++++++++++++ fpga/usrp3/top/x400/x4xx.sv | 6 +- .../{x4xx_gpio_spi.v => x4xx_gpio_spi.sv} | 225 +++++++---- 15 files changed, 1524 insertions(+), 330 deletions(-) create mode 100644 fpga/usrp3/top/x400/regmap/XmlSvPkgDIG_IFC_REGMAP.sv delete mode 100644 fpga/usrp3/top/x400/regmap/dig_ifc_regmap_utils.vh create mode 100644 fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x410/Makefile create mode 100644 fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x4xx/Makefile create mode 100644 fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x4xx/Makefile.common create mode 100644 fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x4xx_gpio_spi_tb.sv rename fpga/usrp3/top/x400/{x4xx_gpio_spi.v => x4xx_gpio_spi.sv} (71%) diff --git a/fpga/usrp3/top/x400/Makefile.x4xx.inc b/fpga/usrp3/top/x400/Makefile.x4xx.inc index 70056034e..93d9d50c9 100644 --- a/fpga/usrp3/top/x400/Makefile.x4xx.inc +++ b/fpga/usrp3/top/x400/Makefile.x4xx.inc @@ -62,7 +62,8 @@ x4xx_global_regs.v \ x4xx_versioning_regs.v \ x4xx_dio.v \ x4xx_gpio_atr.v \ -x4xx_gpio_spi.v \ +regmap/XmlSvPkgDIG_IFC_REGMAP.sv \ +x4xx_gpio_spi.sv \ x4xx_dram.v \ ctrlport_spi_master.v \ cpld_interface.v \ diff --git a/fpga/usrp3/top/x400/doc/X410/X410_FPGA.htm b/fpga/usrp3/top/x400/doc/X410/X410_FPGA.htm index a2716ff54..ed85fd7fe 100644 --- a/fpga/usrp3/top/x400/doc/X410/X410_FPGA.htm +++ b/fpga/usrp3/top/x400/doc/X410/X410_FPGA.htm @@ -1029,6 +1029,11 @@ p.offset_info, td.offset_info {

+

+ SPI_TRANSACTION_LSB +

+ +

SPI_TRANSACTION_GO

@@ -1039,6 +1044,11 @@ p.offset_info, td.offset_info {

+

+ SPI_FULL_RESPONSE_MSB +

+ +

CONTROLLER_INFO

@@ -8329,9 +8339,9 @@ This port has a 40-bit address bus.

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.
It uses RegType SPI_SETUP which is - defined in HDL source file x4xx_gpio_spi.v. + defined in HDL source file x4xx_gpio_spi.sv.

@@ -8351,7 +8361,7 @@ Set of configuration registers for the supported slaves. - 31..28 + 31..29

Reserved   

@@ -8359,7 +8369,7 @@ Set of configuration registers for the supported slaves. - 27 + 28

MOSI_EDGE   (initialvalue=0)

Controls the edge in which the MOSI line is updated.
@@ -8369,7 +8379,7 @@ Set of configuration registers for the supported slaves. - 26 + 27

MISO_EDGE   (initialvalue=0)

Controls the edge in which the MISO line is latched.
@@ -8379,10 +8389,13 @@ Set of configuration registers for the supported slaves. - 25..20 + 26..20

SPI_LENGTH   (initialvalue=0)

-

Indicates the length of SPI transactions to this slave.

+

Indicates the length of SPI transactions to this slave.
+ Valid transaction lengths are 1 through 64 bits.
+ This is not checked on FPGA and other values will
+ lead to undefined behavior.

@@ -8505,7 +8518,7 @@ Set of configuration registers for the supported slaves. Initial Value = 0x00000000

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.

@@ -8554,11 +8567,112 @@ Set of configuration registers for the supported slaves. +
+ + +

+ Offset 0x0014: SPI_TRANSACTION_LSB + Register + (W) + 🔗 +

+
+ (showhide extended info) +
+ + + + + + + + + + + + + + +
+ + +
Port RFNoC Radio 0
+
+ + + +
RFNOC_RADIO_REGMAP|PERIPH_WINDOW
  0x080000
+
+ + + +
RADIO_CTRLPORT_REGMAP|DIO_WINDOW
  0x00C000
+
+ + + +
RADIO_DIO_REGMAP|DIGITAL_IFC_REGS
  0x002000
+
+ + + +
SPI_TRANSACTION_LSB
  offset=0x0014
+
+ + + + + +
Total Offset =0x08E014
+
+ + +
Port RFNoC Radio 1
+
+ + + + + +
Total Offset =0x08E014
+
+

+ + Initial Value = 0x00000000 +

+

+ This register is defined in HDL source file x4xx_gpio_spi.sv. +

+
+
+
+ For SPI transactions with SPI_SLAVE_CONFIG.SPI_LENGTH > 32, this must be written + before SPI_TRANSACTION_GO. +
+ + + + + + + + + +
BitsName
31..0w +

SPI_DATA_LSB   (initialvalue=0)

+

Left-aligned LSB payload for SPI transaction with SPI_SLAVE_CONFIG.SPI_LENGTH > 32.
+ See SPI_TRANSACTION_GO for more information.

+
+
+ + + +

- Offset 0x0014: SPI_TRANSACTION_GO + Offset 0x0018: SPI_TRANSACTION_GO Register (W) 🔗 @@ -8595,14 +8709,14 @@ Set of configuration registers for the supported slaves. - +
SPI_TRANSACTION_GO
  offset=0x0014
  offset=0x0018
- +
Total Offset =0x08E0140x08E018
@@ -8617,7 +8731,7 @@ Set of configuration registers for the supported slaves. - +
Total Offset =0x08E0140x08E018
@@ -8628,12 +8742,13 @@ Set of configuration registers for the supported slaves. Initial Value = 0x00000000

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.

- Starts a SPI transaction + Starts a SPI transaction. Does not check whether a previous transaction is still ongoing. + If so, the running transaction may be corrupted.
@@ -8644,8 +8759,12 @@ Set of configuration registers for the supported slaves.
31..0w

SPI_DATA   (initialvalue=0)

-

Payload to be sent for the SPI transaction. If the payload is shorter than 32 bits, - it must be aligned to the MSbs in this field. LSbs are ignored in this scenario.

+

Payload to be sent for the SPI transaction.
+ If the payload is shorter than 32 bits, it must be left-aligned. + The first transmitted bit is the MSB and data is shifted out to the left.
+ If the desired payload is longer than 32 bits, the remaining LSBs + must be written to SPI_TRANSACTION_LSB.SPI_DATA_LSB (left-aligned) before starting + the transaction.

@@ -8658,7 +8777,7 @@ Set of configuration registers for the supported slaves.

- Offset 0x0018: SPI_STATUS + Offset 0x001C: SPI_STATUS Register (R) 🔗 @@ -8695,14 +8814,14 @@ Set of configuration registers for the supported slaves. - +
SPI_STATUS
  offset=0x0018
  offset=0x001C
- +
Total Offset =0x08E0180x08E01C
@@ -8717,7 +8836,7 @@ Set of configuration registers for the supported slaves. - +
Total Offset =0x08E0180x08E01C
@@ -8728,12 +8847,13 @@ Set of configuration registers for the supported slaves. Initial Value = 0x00000000

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.

- Contains the status of the SPI engine. + Contains the status of the SPI engine and the least-significant 31 bits of the response. + Also read SPI_FULL_RESPONSE_MSB for bit 32 or for transactions longer than 32 bits.
@@ -8741,26 +8861,119 @@ Set of configuration registers for the supported slaves. - - - - - - + - - + + + +
31..25 -

Reserved   

-

-
2431

SPI_READY   (initialvalue=0)

Indicates the SPI engine is ready to start a new SPI transaction.

23..0
30..0

SPI_RESPONSE   (initialvalue=0)

-

Records the response of the last completed SPI transaction.

+

Records only the least-significant 31 bits of the last completed SPI response.

+
+

+ + + + +
+ + +

+ Offset 0x0020: SPI_FULL_RESPONSE_MSB + Register + (R) + 🔗 +

+
+ (showhide extended info) +
+ + + + + + + + + + + + + + +
+ + +
Port RFNoC Radio 0
+
+ + + +
RFNOC_RADIO_REGMAP|PERIPH_WINDOW
  0x080000
+
+ + + +
RADIO_CTRLPORT_REGMAP|DIO_WINDOW
  0x00C000
+
+ + + +
RADIO_DIO_REGMAP|DIGITAL_IFC_REGS
  0x002000
+
+ + + +
SPI_FULL_RESPONSE_MSB
  offset=0x0020
+
+ + + + + +
Total Offset =0x08E020
+
+ + +
Port RFNoC Radio 1
+
+ + + + + +
Total Offset =0x08E020
+
+

+ + Initial Value = 0x00000000 +

+

+ This register is defined in HDL source file x4xx_gpio_spi.sv. +

+
+
+
+ Contains bits 62 through 31 of the last completed SPI response. + For transactions shorter than 31 bits, the upper bits in this register are undefined. + The regmap does not expose the most significant bit (bit 63) of the response. +
+ + + + + + + +
BitsName
31..0 +

SPI_FULL_RESPONSE_MSB_DATA   (initialvalue=0)

+

@@ -8773,7 +8986,7 @@ Set of configuration registers for the supported slaves.

- Offset 0x001C: CONTROLLER_INFO + Offset 0x0024: CONTROLLER_INFO Register (R) 🔗 @@ -8810,14 +9023,14 @@ Set of configuration registers for the supported slaves. - +
CONTROLLER_INFO
  offset=0x001C
  offset=0x0024
- +
Total Offset =0x08E01C0x08E024
@@ -8832,7 +9045,7 @@ Set of configuration registers for the supported slaves. - +
Total Offset =0x08E01C0x08E024
@@ -8843,7 +9056,7 @@ Set of configuration registers for the supported slaves. Initial Value not specified

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.

@@ -32928,8 +33141,8 @@ used with 100Gb ethernet

- 11 - 0x0000000B + 12 + 0x0000000C

@@ -32941,8 +33154,8 @@ used with 100Gb ethernet

- 11 - 0x0000000B + 12 + 0x0000000C

@@ -32954,8 +33167,8 @@ used with 100Gb ethernet

- 637675285 - 0x26022715 + 638124305 + 0x26090111

diff --git a/fpga/usrp3/top/x400/doc/X420/X420_FPGA.htm b/fpga/usrp3/top/x400/doc/X420/X420_FPGA.htm index 0a0f76d5a..b124e451c 100644 --- a/fpga/usrp3/top/x400/doc/X420/X420_FPGA.htm +++ b/fpga/usrp3/top/x400/doc/X420/X420_FPGA.htm @@ -1175,6 +1175,11 @@ p.offset_info, td.offset_info {

+

+ SPI_TRANSACTION_LSB +

+ +

SPI_TRANSACTION_GO

@@ -1185,6 +1190,11 @@ p.offset_info, td.offset_info {

+

+ SPI_FULL_RESPONSE_MSB +

+ +

CONTROLLER_INFO

@@ -11389,9 +11399,9 @@ This port has a 40-bit address bus.

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.
It uses RegType SPI_SETUP which is - defined in HDL source file x4xx_gpio_spi.v. + defined in HDL source file x4xx_gpio_spi.sv.

@@ -11411,7 +11421,7 @@ Set of configuration registers for the supported slaves. - 31..28 + 31..29

Reserved   

@@ -11419,7 +11429,7 @@ Set of configuration registers for the supported slaves. - 27 + 28

MOSI_EDGE   (initialvalue=0)

Controls the edge in which the MOSI line is updated.
@@ -11429,7 +11439,7 @@ Set of configuration registers for the supported slaves. - 26 + 27

MISO_EDGE   (initialvalue=0)

Controls the edge in which the MISO line is latched.
@@ -11439,10 +11449,13 @@ Set of configuration registers for the supported slaves. - 25..20 + 26..20

SPI_LENGTH   (initialvalue=0)

-

Indicates the length of SPI transactions to this slave.

+

Indicates the length of SPI transactions to this slave.
+ Valid transaction lengths are 1 through 64 bits.
+ This is not checked on FPGA and other values will
+ lead to undefined behavior.

@@ -11565,7 +11578,7 @@ Set of configuration registers for the supported slaves. Initial Value = 0x00000000

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.

@@ -11614,11 +11627,112 @@ Set of configuration registers for the supported slaves. +
+ + +

+ Offset 0x0014: SPI_TRANSACTION_LSB + Register + (W) + 🔗 +

+
+ (showhide extended info) +
+ + + + + + + + + + + + + + +
+ + +
Port RFNoC Radio 0
+
+ + + +
RFNOC_RADIO_REGMAP|PERIPH_WINDOW
  0x080000
+
+ + + +
RADIO_CTRLPORT_REGMAP|DIO_WINDOW
  0x00C000
+
+ + + +
RADIO_DIO_REGMAP|DIGITAL_IFC_REGS
  0x002000
+
+ + + +
SPI_TRANSACTION_LSB
  offset=0x0014
+
+ + + + + +
Total Offset =0x08E014
+
+ + +
Port RFNoC Radio 1
+
+ + + + + +
Total Offset =0x08E014
+
+

+ + Initial Value = 0x00000000 +

+

+ This register is defined in HDL source file x4xx_gpio_spi.sv. +

+
+
+
+ For SPI transactions with SPI_SLAVE_CONFIG.SPI_LENGTH > 32, this must be written + before SPI_TRANSACTION_GO. +
+ + + + + + + + + +
BitsName
31..0w +

SPI_DATA_LSB   (initialvalue=0)

+

Left-aligned LSB payload for SPI transaction with SPI_SLAVE_CONFIG.SPI_LENGTH > 32.
+ See SPI_TRANSACTION_GO for more information.

+
+
+ + + +

- Offset 0x0014: SPI_TRANSACTION_GO + Offset 0x0018: SPI_TRANSACTION_GO Register (W) 🔗 @@ -11655,14 +11769,14 @@ Set of configuration registers for the supported slaves. - +
SPI_TRANSACTION_GO
  offset=0x0014
  offset=0x0018
- +
Total Offset =0x08E0140x08E018
@@ -11677,7 +11791,7 @@ Set of configuration registers for the supported slaves. - +
Total Offset =0x08E0140x08E018
@@ -11688,12 +11802,13 @@ Set of configuration registers for the supported slaves. Initial Value = 0x00000000

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.

- Starts a SPI transaction + Starts a SPI transaction. Does not check whether a previous transaction is still ongoing. + If so, the running transaction may be corrupted.
@@ -11704,8 +11819,12 @@ Set of configuration registers for the supported slaves.
31..0w

SPI_DATA   (initialvalue=0)

-

Payload to be sent for the SPI transaction. If the payload is shorter than 32 bits, - it must be aligned to the MSbs in this field. LSbs are ignored in this scenario.

+

Payload to be sent for the SPI transaction.
+ If the payload is shorter than 32 bits, it must be left-aligned. + The first transmitted bit is the MSB and data is shifted out to the left.
+ If the desired payload is longer than 32 bits, the remaining LSBs + must be written to SPI_TRANSACTION_LSB.SPI_DATA_LSB (left-aligned) before starting + the transaction.

@@ -11718,7 +11837,7 @@ Set of configuration registers for the supported slaves.

- Offset 0x0018: SPI_STATUS + Offset 0x001C: SPI_STATUS Register (R) 🔗 @@ -11755,14 +11874,14 @@ Set of configuration registers for the supported slaves. - +
SPI_STATUS
  offset=0x0018
  offset=0x001C
- +
Total Offset =0x08E0180x08E01C
@@ -11777,7 +11896,7 @@ Set of configuration registers for the supported slaves. - +
Total Offset =0x08E0180x08E01C
@@ -11788,12 +11907,13 @@ Set of configuration registers for the supported slaves. Initial Value = 0x00000000

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.

- Contains the status of the SPI engine. + Contains the status of the SPI engine and the least-significant 31 bits of the response. + Also read SPI_FULL_RESPONSE_MSB for bit 32 or for transactions longer than 32 bits.
@@ -11801,26 +11921,119 @@ Set of configuration registers for the supported slaves. - - - - - - + - - + + + +
31..25 -

Reserved   

-

-
2431

SPI_READY   (initialvalue=0)

Indicates the SPI engine is ready to start a new SPI transaction.

23..0
30..0

SPI_RESPONSE   (initialvalue=0)

-

Records the response of the last completed SPI transaction.

+

Records only the least-significant 31 bits of the last completed SPI response.

+
+

+ + + + +
+ + +

+ Offset 0x0020: SPI_FULL_RESPONSE_MSB + Register + (R) + 🔗 +

+
+ (showhide extended info) +
+ + + + + + + + + + + + + + +
+ + +
Port RFNoC Radio 0
+
+ + + +
RFNOC_RADIO_REGMAP|PERIPH_WINDOW
  0x080000
+
+ + + +
RADIO_CTRLPORT_REGMAP|DIO_WINDOW
  0x00C000
+
+ + + +
RADIO_DIO_REGMAP|DIGITAL_IFC_REGS
  0x002000
+
+ + + +
SPI_FULL_RESPONSE_MSB
  offset=0x0020
+
+ + + + + +
Total Offset =0x08E020
+
+ + +
Port RFNoC Radio 1
+
+ + + + + +
Total Offset =0x08E020
+
+

+ + Initial Value = 0x00000000 +

+

+ This register is defined in HDL source file x4xx_gpio_spi.sv. +

+
+
+
+ Contains bits 62 through 31 of the last completed SPI response. + For transactions shorter than 31 bits, the upper bits in this register are undefined. + The regmap does not expose the most significant bit (bit 63) of the response. +
+ + + + + + + +
BitsName
31..0 +

SPI_FULL_RESPONSE_MSB_DATA   (initialvalue=0)

+

@@ -11833,7 +12046,7 @@ Set of configuration registers for the supported slaves.

- Offset 0x001C: CONTROLLER_INFO + Offset 0x0024: CONTROLLER_INFO Register (R) 🔗 @@ -11870,14 +12083,14 @@ Set of configuration registers for the supported slaves. - +
CONTROLLER_INFO
  offset=0x001C
  offset=0x0024
- +
Total Offset =0x08E01C0x08E024
@@ -11892,7 +12105,7 @@ Set of configuration registers for the supported slaves. - +
Total Offset =0x08E01C0x08E024
@@ -11903,7 +12116,7 @@ Set of configuration registers for the supported slaves. Initial Value not specified

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.

@@ -37693,8 +37906,8 @@ used with 100Gb ethernet

- 11 - 0x0000000B + 12 + 0x0000000C

@@ -37706,8 +37919,8 @@ used with 100Gb ethernet

- 11 - 0x0000000B + 12 + 0x0000000C

@@ -37719,8 +37932,8 @@ used with 100Gb ethernet

- 637675285 - 0x26022715 + 638124305 + 0x26090111

diff --git a/fpga/usrp3/top/x400/doc/X440/X440_FPGA.htm b/fpga/usrp3/top/x400/doc/X440/X440_FPGA.htm index bee9464ea..e8fb419fd 100644 --- a/fpga/usrp3/top/x400/doc/X440/X440_FPGA.htm +++ b/fpga/usrp3/top/x400/doc/X440/X440_FPGA.htm @@ -895,6 +895,11 @@ p.offset_info, td.offset_info {

+

+ SPI_TRANSACTION_LSB +

+ +

SPI_TRANSACTION_GO

@@ -905,6 +910,11 @@ p.offset_info, td.offset_info {

+

+ SPI_FULL_RESPONSE_MSB +

+ +

CONTROLLER_INFO

@@ -5345,9 +5355,9 @@ This port has a 40-bit address bus.

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.
It uses RegType SPI_SETUP which is - defined in HDL source file x4xx_gpio_spi.v. + defined in HDL source file x4xx_gpio_spi.sv.

@@ -5367,7 +5377,7 @@ Set of configuration registers for the supported slaves. - 31..28 + 31..29

Reserved   

@@ -5375,7 +5385,7 @@ Set of configuration registers for the supported slaves. - 27 + 28

MOSI_EDGE   (initialvalue=0)

Controls the edge in which the MOSI line is updated.
@@ -5385,7 +5395,7 @@ Set of configuration registers for the supported slaves. - 26 + 27

MISO_EDGE   (initialvalue=0)

Controls the edge in which the MISO line is latched.
@@ -5395,10 +5405,13 @@ Set of configuration registers for the supported slaves. - 25..20 + 26..20

SPI_LENGTH   (initialvalue=0)

-

Indicates the length of SPI transactions to this slave.

+

Indicates the length of SPI transactions to this slave.
+ Valid transaction lengths are 1 through 64 bits.
+ This is not checked on FPGA and other values will
+ lead to undefined behavior.

@@ -5521,7 +5534,7 @@ Set of configuration registers for the supported slaves. Initial Value = 0x00000000

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.

@@ -5570,11 +5583,112 @@ Set of configuration registers for the supported slaves. +
+ + +

+ Offset 0x0014: SPI_TRANSACTION_LSB + Register + (W) + 🔗 +

+
+ (showhide extended info) +
+ + + + + + + + + + + + + + +
+ + +
Port RFNoC Radio 0
+
+ + + +
RFNOC_RADIO_REGMAP|PERIPH_WINDOW
  0x080000
+
+ + + +
RADIO_CTRLPORT_REGMAP|DIO_WINDOW
  0x00C000
+
+ + + +
RADIO_DIO_REGMAP|DIGITAL_IFC_REGS
  0x002000
+
+ + + +
SPI_TRANSACTION_LSB
  offset=0x0014
+
+ + + + + +
Total Offset =0x08E014
+
+ + +
Port RFNoC Radio 1
+
+ + + + + +
Total Offset =0x08E014
+
+

+ + Initial Value = 0x00000000 +

+

+ This register is defined in HDL source file x4xx_gpio_spi.sv. +

+
+
+
+ For SPI transactions with SPI_SLAVE_CONFIG.SPI_LENGTH > 32, this must be written + before SPI_TRANSACTION_GO. +
+ + + + + + + + + +
BitsName
31..0w +

SPI_DATA_LSB   (initialvalue=0)

+

Left-aligned LSB payload for SPI transaction with SPI_SLAVE_CONFIG.SPI_LENGTH > 32.
+ See SPI_TRANSACTION_GO for more information.

+
+
+ + + +

- Offset 0x0014: SPI_TRANSACTION_GO + Offset 0x0018: SPI_TRANSACTION_GO Register (W) 🔗 @@ -5611,14 +5725,14 @@ Set of configuration registers for the supported slaves. - +
SPI_TRANSACTION_GO
  offset=0x0014
  offset=0x0018
- +
Total Offset =0x08E0140x08E018
@@ -5633,7 +5747,7 @@ Set of configuration registers for the supported slaves. - +
Total Offset =0x08E0140x08E018
@@ -5644,12 +5758,13 @@ Set of configuration registers for the supported slaves. Initial Value = 0x00000000

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.

- Starts a SPI transaction + Starts a SPI transaction. Does not check whether a previous transaction is still ongoing. + If so, the running transaction may be corrupted.
@@ -5660,8 +5775,12 @@ Set of configuration registers for the supported slaves.
31..0w

SPI_DATA   (initialvalue=0)

-

Payload to be sent for the SPI transaction. If the payload is shorter than 32 bits, - it must be aligned to the MSbs in this field. LSbs are ignored in this scenario.

+

Payload to be sent for the SPI transaction.
+ If the payload is shorter than 32 bits, it must be left-aligned. + The first transmitted bit is the MSB and data is shifted out to the left.
+ If the desired payload is longer than 32 bits, the remaining LSBs + must be written to SPI_TRANSACTION_LSB.SPI_DATA_LSB (left-aligned) before starting + the transaction.

@@ -5674,7 +5793,7 @@ Set of configuration registers for the supported slaves.

- Offset 0x0018: SPI_STATUS + Offset 0x001C: SPI_STATUS Register (R) 🔗 @@ -5711,14 +5830,14 @@ Set of configuration registers for the supported slaves. - +
SPI_STATUS
  offset=0x0018
  offset=0x001C
- +
Total Offset =0x08E0180x08E01C
@@ -5733,7 +5852,7 @@ Set of configuration registers for the supported slaves. - +
Total Offset =0x08E0180x08E01C
@@ -5744,12 +5863,13 @@ Set of configuration registers for the supported slaves. Initial Value = 0x00000000

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.

- Contains the status of the SPI engine. + Contains the status of the SPI engine and the least-significant 31 bits of the response. + Also read SPI_FULL_RESPONSE_MSB for bit 32 or for transactions longer than 32 bits.
@@ -5757,26 +5877,119 @@ Set of configuration registers for the supported slaves. - - - - - - + - - + + + +
31..25 -

Reserved   

-

-
2431

SPI_READY   (initialvalue=0)

Indicates the SPI engine is ready to start a new SPI transaction.

23..0
30..0

SPI_RESPONSE   (initialvalue=0)

-

Records the response of the last completed SPI transaction.

+

Records only the least-significant 31 bits of the last completed SPI response.

+
+

+ + + + +
+ + +

+ Offset 0x0020: SPI_FULL_RESPONSE_MSB + Register + (R) + 🔗 +

+
+ (showhide extended info) +
+ + + + + + + + + + + + + + +
+ + +
Port RFNoC Radio 0
+
+ + + +
RFNOC_RADIO_REGMAP|PERIPH_WINDOW
  0x080000
+
+ + + +
RADIO_CTRLPORT_REGMAP|DIO_WINDOW
  0x00C000
+
+ + + +
RADIO_DIO_REGMAP|DIGITAL_IFC_REGS
  0x002000
+
+ + + +
SPI_FULL_RESPONSE_MSB
  offset=0x0020
+
+ + + + + +
Total Offset =0x08E020
+
+ + +
Port RFNoC Radio 1
+
+ + + + + +
Total Offset =0x08E020
+
+

+ + Initial Value = 0x00000000 +

+

+ This register is defined in HDL source file x4xx_gpio_spi.sv. +

+
+
+
+ Contains bits 62 through 31 of the last completed SPI response. + For transactions shorter than 31 bits, the upper bits in this register are undefined. + The regmap does not expose the most significant bit (bit 63) of the response. +
+ + + + + + + +
BitsName
31..0 +

SPI_FULL_RESPONSE_MSB_DATA   (initialvalue=0)

+

@@ -5789,7 +6002,7 @@ Set of configuration registers for the supported slaves.

- Offset 0x001C: CONTROLLER_INFO + Offset 0x0024: CONTROLLER_INFO Register (R) 🔗 @@ -5826,14 +6039,14 @@ Set of configuration registers for the supported slaves. - +
CONTROLLER_INFO
  offset=0x001C
  offset=0x0024
- +
Total Offset =0x08E01C0x08E024
@@ -5848,7 +6061,7 @@ Set of configuration registers for the supported slaves. - +
Total Offset =0x08E01C0x08E024
@@ -5859,7 +6072,7 @@ Set of configuration registers for the supported slaves. Initial Value not specified

- This register is defined in HDL source file x4xx_gpio_spi.v. + This register is defined in HDL source file x4xx_gpio_spi.sv.

@@ -27548,8 +27761,8 @@ used with 100Gb ethernet

- 11 - 0x0000000B + 12 + 0x0000000C

@@ -27561,8 +27774,8 @@ used with 100Gb ethernet

- 11 - 0x0000000B + 12 + 0x0000000C

@@ -27574,8 +27787,8 @@ used with 100Gb ethernet

- 637675285 - 0x26022715 + 638124305 + 0x26090111

diff --git a/fpga/usrp3/top/x400/regmap/XmlSvPkgDIG_IFC_REGMAP.sv b/fpga/usrp3/top/x400/regmap/XmlSvPkgDIG_IFC_REGMAP.sv new file mode 100644 index 000000000..661d765b1 --- /dev/null +++ b/fpga/usrp3/top/x400/regmap/XmlSvPkgDIG_IFC_REGMAP.sv @@ -0,0 +1,163 @@ +//----------------------------------------------------------------------------- +// File: XmlSvPkgDIG_IFC_REGMAP.sv +// Author: Autogenerated by XmlParse +// Original Project: -- +// Date: -- +//----------------------------------------------------------------------------- +// (c) 2026 National Instruments Corporation. All Rights Reserved. +//----------------------------------------------------------------------------- +// Purpose: +// The constants in this file are autogenerated by XmlParse. +//----------------------------------------------------------------------------- + +package XmlSvPkgDIG_IFC_REGMAP; + +//=============================================================================== +// A numerically ordered list of registers and their HDL source files +//=============================================================================== + + // SPI_SLAVE_CONFIG : 0x0 (x4xx_gpio_spi.sv) + // SPI_TRANSACTION_CONFIG : 0x10 (x4xx_gpio_spi.sv) + // SPI_TRANSACTION_LSB : 0x14 (x4xx_gpio_spi.sv) + // SPI_TRANSACTION_GO : 0x18 (x4xx_gpio_spi.sv) + // SPI_STATUS : 0x1C (x4xx_gpio_spi.sv) + // SPI_FULL_RESPONSE_MSB : 0x20 (x4xx_gpio_spi.sv) + // CONTROLLER_INFO : 0x24 (x4xx_gpio_spi.sv) + +//=============================================================================== +// Register Group SPI_OVER_GPIO_REGS +//=============================================================================== + + // SPI_SLAVE_CONFIG Register (from x4xx_gpio_spi.sv) + localparam kSPI_SLAVE_CONFIGCount = 4; // Number of elements in array + + // SPI_TRANSACTION_CONFIG Register (from x4xx_gpio_spi.sv) + localparam kSPI_TRANSACTION_CONFIG = 'h10; // Register Offset + localparam kSPI_TRANSACTION_CONFIGSize = 32; // register width in bits + localparam kSPI_TRANSACTION_CONFIGMask = 32'h3FFFF; + localparam kSPI_CLK_DIVSize = 16; //SPI_TRANSACTION_CONFIG:SPI_CLK_DIV + localparam kSPI_CLK_DIVMsb = 15; //SPI_TRANSACTION_CONFIG:SPI_CLK_DIV + localparam kSPI_CLK_DIV = 0; //SPI_TRANSACTION_CONFIG:SPI_CLK_DIV + localparam kSPI_SLAVE_SELECTSize = 2; //SPI_TRANSACTION_CONFIG:SPI_SLAVE_SELECT + localparam kSPI_SLAVE_SELECTMsb = 17; //SPI_TRANSACTION_CONFIG:SPI_SLAVE_SELECT + localparam kSPI_SLAVE_SELECT = 16; //SPI_TRANSACTION_CONFIG:SPI_SLAVE_SELECT + + typedef struct packed { + logic [13:0] Rsvd31_18; // [31:18] 14 bit spacer + logic [1:0] SPI_SLAVE_SELECT; // [17:16] 2 bit bitfield + logic [15:0] SPI_CLK_DIV; // [15: 0] 16 bit bitfield + } SPI_TRANSACTION_CONFIG; + + // SPI_TRANSACTION_LSB Register (from x4xx_gpio_spi.sv) + localparam kSPI_TRANSACTION_LSB = 'h14; // Register Offset + localparam kSPI_TRANSACTION_LSBSize = 32; // register width in bits + localparam kSPI_TRANSACTION_LSBMask = 32'hFFFFFFFF; + localparam kSPI_DATA_LSBSize = 32; //SPI_TRANSACTION_LSB:SPI_DATA_LSB + localparam kSPI_DATA_LSBMsb = 31; //SPI_TRANSACTION_LSB:SPI_DATA_LSB + localparam kSPI_DATA_LSB = 0; //SPI_TRANSACTION_LSB:SPI_DATA_LSB + + typedef struct packed { + logic [31:0] SPI_DATA_LSB; // [31: 0] 32 bit bitfield + } SPI_TRANSACTION_LSB; + + // SPI_TRANSACTION_GO Register (from x4xx_gpio_spi.sv) + localparam kSPI_TRANSACTION_GO = 'h18; // Register Offset + localparam kSPI_TRANSACTION_GOSize = 32; // register width in bits + localparam kSPI_TRANSACTION_GOMask = 32'hFFFFFFFF; + localparam kSPI_DATASize = 32; //SPI_TRANSACTION_GO:SPI_DATA + localparam kSPI_DATAMsb = 31; //SPI_TRANSACTION_GO:SPI_DATA + localparam kSPI_DATA = 0; //SPI_TRANSACTION_GO:SPI_DATA + + typedef struct packed { + logic [31:0] SPI_DATA; // [31: 0] 32 bit bitfield + } SPI_TRANSACTION_GO; + + // SPI_STATUS Register (from x4xx_gpio_spi.sv) + localparam kSPI_STATUS = 'h1C; // Register Offset + localparam kSPI_STATUSSize = 32; // register width in bits + localparam kSPI_STATUSMask = 32'hFFFFFFFF; + localparam kSPI_RESPONSESize = 31; //SPI_STATUS:SPI_RESPONSE + localparam kSPI_RESPONSEMsb = 30; //SPI_STATUS:SPI_RESPONSE + localparam kSPI_RESPONSE = 0; //SPI_STATUS:SPI_RESPONSE + localparam kSPI_READYSize = 1; //SPI_STATUS:SPI_READY + localparam kSPI_READYMsb = 31; //SPI_STATUS:SPI_READY + localparam kSPI_READY = 31; //SPI_STATUS:SPI_READY + + typedef struct packed { + logic SPI_READY; // [31:31] 1 bit bitfield + logic [30:0] SPI_RESPONSE; // [30: 0] 31 bit bitfield + } SPI_STATUS; + + // SPI_FULL_RESPONSE_MSB Register (from x4xx_gpio_spi.sv) + localparam kSPI_FULL_RESPONSE_MSB = 'h20; // Register Offset + localparam kSPI_FULL_RESPONSE_MSBSize = 32; // register width in bits + localparam kSPI_FULL_RESPONSE_MSBMask = 32'hFFFFFFFF; + localparam kSPI_FULL_RESPONSE_MSB_DATASize = 32; //SPI_FULL_RESPONSE_MSB:SPI_FULL_RESPONSE_MSB_DATA + localparam kSPI_FULL_RESPONSE_MSB_DATAMsb = 31; //SPI_FULL_RESPONSE_MSB:SPI_FULL_RESPONSE_MSB_DATA + localparam kSPI_FULL_RESPONSE_MSB_DATA = 0; //SPI_FULL_RESPONSE_MSB:SPI_FULL_RESPONSE_MSB_DATA + + typedef struct packed { + logic [31:0] SPI_FULL_RESPONSE_MSB_DATA; // [31: 0] 32 bit bitfield + } SPI_FULL_RESPONSE_MSB; + + // CONTROLLER_INFO Register (from x4xx_gpio_spi.sv) + localparam kCONTROLLER_INFO = 'h24; // Register Offset + localparam kCONTROLLER_INFOSize = 32; // register width in bits + localparam kCONTROLLER_INFOMask = 32'hF; + localparam kSLAVE_COUNTSize = 4; //CONTROLLER_INFO:SLAVE_COUNT + localparam kSLAVE_COUNTMsb = 3; //CONTROLLER_INFO:SLAVE_COUNT + localparam kSLAVE_COUNT = 0; //CONTROLLER_INFO:SLAVE_COUNT + + typedef struct packed { + logic [27:0] Rsvd31_4; // [31: 4] 28 bit spacer + logic [3:0] SLAVE_COUNT; // [ 3: 0] 4 bit bitfield + } CONTROLLER_INFO; + +//=============================================================================== +// RegTypes +//=============================================================================== + + // SPI_SETUP Type (from x4xx_gpio_spi.sv) + localparam kSPI_SETUPSize = 32; + localparam kSPI_SETUPMask = 32'h1FFFFFFF; + localparam kSLAVE_CLKSize = 5; //SPI_SETUP:SLAVE_CLK + localparam kSLAVE_CLKMsb = 4; //SPI_SETUP:SLAVE_CLK + localparam kSLAVE_CLK = 0; //SPI_SETUP:SLAVE_CLK + localparam kSLAVE_MOSISize = 5; //SPI_SETUP:SLAVE_MOSI + localparam kSLAVE_MOSIMsb = 9; //SPI_SETUP:SLAVE_MOSI + localparam kSLAVE_MOSI = 5; //SPI_SETUP:SLAVE_MOSI + localparam kSLAVE_MISOSize = 5; //SPI_SETUP:SLAVE_MISO + localparam kSLAVE_MISOMsb = 14; //SPI_SETUP:SLAVE_MISO + localparam kSLAVE_MISO = 10; //SPI_SETUP:SLAVE_MISO + localparam kSLAVE_CSSize = 5; //SPI_SETUP:SLAVE_CS + localparam kSLAVE_CSMsb = 19; //SPI_SETUP:SLAVE_CS + localparam kSLAVE_CS = 15; //SPI_SETUP:SLAVE_CS + localparam kSPI_LENGTHSize = 7; //SPI_SETUP:SPI_LENGTH + localparam kSPI_LENGTHMsb = 26; //SPI_SETUP:SPI_LENGTH + localparam kSPI_LENGTH = 20; //SPI_SETUP:SPI_LENGTH + localparam kMISO_EDGESize = 1; //SPI_SETUP:MISO_EDGE + localparam kMISO_EDGEMsb = 27; //SPI_SETUP:MISO_EDGE + localparam kMISO_EDGE = 27; //SPI_SETUP:MISO_EDGE + localparam kMOSI_EDGESize = 1; //SPI_SETUP:MOSI_EDGE + localparam kMOSI_EDGEMsb = 28; //SPI_SETUP:MOSI_EDGE + localparam kMOSI_EDGE = 28; //SPI_SETUP:MOSI_EDGE + + typedef struct packed { + logic [2:0] Rsvd31_29; // [31:29] 3 bit spacer + logic MOSI_EDGE; // [28:28] 1 bit bitfield + logic MISO_EDGE; // [27:27] 1 bit bitfield + logic [6:0] SPI_LENGTH; // [26:20] 7 bit bitfield + logic [4:0] SLAVE_CS; // [19:15] 5 bit bitfield + logic [4:0] SLAVE_MISO; // [14:10] 5 bit bitfield + logic [4:0] SLAVE_MOSI; // [ 9: 5] 5 bit bitfield + logic [4:0] SLAVE_CLK; // [ 4: 0] 5 bit bitfield + } SPI_SETUP; + + // Return the offset of an element of register array kSPI_SLAVE_CONFIG + function automatic integer kSPI_SLAVE_CONFIG (input integer i); + begin + kSPI_SLAVE_CONFIG = (i * 'h4) + 'h0; + end + endfunction + +endpackage : XmlSvPkgDIG_IFC_REGMAP diff --git a/fpga/usrp3/top/x400/regmap/dig_ifc_regmap_utils.vh b/fpga/usrp3/top/x400/regmap/dig_ifc_regmap_utils.vh deleted file mode 100644 index 7f75caf48..000000000 --- a/fpga/usrp3/top/x400/regmap/dig_ifc_regmap_utils.vh +++ /dev/null @@ -1,102 +0,0 @@ -// -// Copyright 2025 Ettus Research, a National Instruments Brand -// -// SPDX-License-Identifier: LGPL-3.0-or-later -// -// Module: dig_ifc_regmap_utils.vh -// -// Description: -// -// The constants in this file are autogenerated by XmlParse. -// - -//=============================================================================== -// A numerically ordered list of registers and their HDL source files -//=============================================================================== - - // SPI_SLAVE_CONFIG : 0x0 (x4xx_gpio_spi.v) - // SPI_TRANSACTION_CONFIG : 0x10 (x4xx_gpio_spi.v) - // SPI_TRANSACTION_GO : 0x14 (x4xx_gpio_spi.v) - // SPI_STATUS : 0x18 (x4xx_gpio_spi.v) - // CONTROLLER_INFO : 0x1C (x4xx_gpio_spi.v) - -//=============================================================================== -// RegTypes -//=============================================================================== - - // SPI_SETUP Type (from x4xx_gpio_spi.v) - localparam SPI_SETUP_SIZE = 32; - localparam SPI_SETUP_MASK = 32'hFFFFFFF; - localparam SLAVE_CLK_SIZE = 5; //SPI_SETUP:SLAVE_CLK - localparam SLAVE_CLK_MSB = 4; //SPI_SETUP:SLAVE_CLK - localparam SLAVE_CLK = 0; //SPI_SETUP:SLAVE_CLK - localparam SLAVE_MOSI_SIZE = 5; //SPI_SETUP:SLAVE_MOSI - localparam SLAVE_MOSI_MSB = 9; //SPI_SETUP:SLAVE_MOSI - localparam SLAVE_MOSI = 5; //SPI_SETUP:SLAVE_MOSI - localparam SLAVE_MISO_SIZE = 5; //SPI_SETUP:SLAVE_MISO - localparam SLAVE_MISO_MSB = 14; //SPI_SETUP:SLAVE_MISO - localparam SLAVE_MISO = 10; //SPI_SETUP:SLAVE_MISO - localparam SLAVE_CS_SIZE = 5; //SPI_SETUP:SLAVE_CS - localparam SLAVE_CS_MSB = 19; //SPI_SETUP:SLAVE_CS - localparam SLAVE_CS = 15; //SPI_SETUP:SLAVE_CS - localparam SPI_LENGTH_SIZE = 6; //SPI_SETUP:SPI_LENGTH - localparam SPI_LENGTH_MSB = 25; //SPI_SETUP:SPI_LENGTH - localparam SPI_LENGTH = 20; //SPI_SETUP:SPI_LENGTH - localparam MISO_EDGE_SIZE = 1; //SPI_SETUP:MISO_EDGE - localparam MISO_EDGE_MSB = 26; //SPI_SETUP:MISO_EDGE - localparam MISO_EDGE = 26; //SPI_SETUP:MISO_EDGE - localparam MOSI_EDGE_SIZE = 1; //SPI_SETUP:MOSI_EDGE - localparam MOSI_EDGE_MSB = 27; //SPI_SETUP:MOSI_EDGE - localparam MOSI_EDGE = 27; //SPI_SETUP:MOSI_EDGE - -//=============================================================================== -// Register Group SPI_OVER_GPIO_REGS -//=============================================================================== - - // SPI_SLAVE_CONFIG Register (from x4xx_gpio_spi.v) - localparam SPI_SLAVE_CONFIG_COUNT = 4; // Number of elements in array - - // SPI_TRANSACTION_CONFIG Register (from x4xx_gpio_spi.v) - localparam SPI_TRANSACTION_CONFIG = 'h10; // Register Offset - localparam SPI_TRANSACTION_CONFIG_SIZE = 32; // register width in bits - localparam SPI_TRANSACTION_CONFIG_MASK = 32'h3FFFF; - localparam SPI_CLK_DIV_SIZE = 16; //SPI_TRANSACTION_CONFIG:SPI_CLK_DIV - localparam SPI_CLK_DIV_MSB = 15; //SPI_TRANSACTION_CONFIG:SPI_CLK_DIV - localparam SPI_CLK_DIV = 0; //SPI_TRANSACTION_CONFIG:SPI_CLK_DIV - localparam SPI_SLAVE_SELECT_SIZE = 2; //SPI_TRANSACTION_CONFIG:SPI_SLAVE_SELECT - localparam SPI_SLAVE_SELECT_MSB = 17; //SPI_TRANSACTION_CONFIG:SPI_SLAVE_SELECT - localparam SPI_SLAVE_SELECT = 16; //SPI_TRANSACTION_CONFIG:SPI_SLAVE_SELECT - - // SPI_TRANSACTION_GO Register (from x4xx_gpio_spi.v) - localparam SPI_TRANSACTION_GO = 'h14; // Register Offset - localparam SPI_TRANSACTION_GO_SIZE = 32; // register width in bits - localparam SPI_TRANSACTION_GO_MASK = 32'hFFFFFFFF; - localparam SPI_DATA_SIZE = 32; //SPI_TRANSACTION_GO:SPI_DATA - localparam SPI_DATA_MSB = 31; //SPI_TRANSACTION_GO:SPI_DATA - localparam SPI_DATA = 0; //SPI_TRANSACTION_GO:SPI_DATA - - // SPI_STATUS Register (from x4xx_gpio_spi.v) - localparam SPI_STATUS = 'h18; // Register Offset - localparam SPI_STATUS_SIZE = 32; // register width in bits - localparam SPI_STATUS_MASK = 32'h1FFFFFF; - localparam SPI_RESPONSE_SIZE = 24; //SPI_STATUS:SPI_RESPONSE - localparam SPI_RESPONSE_MSB = 23; //SPI_STATUS:SPI_RESPONSE - localparam SPI_RESPONSE = 0; //SPI_STATUS:SPI_RESPONSE - localparam SPI_READY_SIZE = 1; //SPI_STATUS:SPI_READY - localparam SPI_READY_MSB = 24; //SPI_STATUS:SPI_READY - localparam SPI_READY = 24; //SPI_STATUS:SPI_READY - - // CONTROLLER_INFO Register (from x4xx_gpio_spi.v) - localparam CONTROLLER_INFO = 'h1C; // Register Offset - localparam CONTROLLER_INFO_SIZE = 32; // register width in bits - localparam CONTROLLER_INFO_MASK = 32'hF; - localparam SLAVE_COUNT_SIZE = 4; //CONTROLLER_INFO:SLAVE_COUNT - localparam SLAVE_COUNT_MSB = 3; //CONTROLLER_INFO:SLAVE_COUNT - localparam SLAVE_COUNT = 0; //CONTROLLER_INFO:SLAVE_COUNT - - // Return the offset of an element of register array SPI_SLAVE_CONFIG - function automatic integer SPI_SLAVE_CONFIG (input integer i); - begin - SPI_SLAVE_CONFIG = (i * 'h4) + 'h0; - end - endfunction diff --git a/fpga/usrp3/top/x400/regmap/x410/versioning_regs_regmap_utils.vh b/fpga/usrp3/top/x400/regmap/x410/versioning_regs_regmap_utils.vh index 0c6a71da3..69b7b120f 100644 --- a/fpga/usrp3/top/x400/regmap/x410/versioning_regs_regmap_utils.vh +++ b/fpga/usrp3/top/x400/regmap/x410/versioning_regs_regmap_utils.vh @@ -86,9 +86,9 @@ localparam FPGA_CURRENT_VERSION_BUILD = 'h0; // FPGA_VERSION:FPGA_CURRENT_VERSION_BUILD localparam FPGA_OLDEST_COMPATIBLE_VERSION_MINOR = 'h0; // FPGA_VERSION:FPGA_OLDEST_COMPATIBLE_VERSION_MINOR localparam FPGA_OLDEST_COMPATIBLE_VERSION_BUILD = 'h0; // FPGA_VERSION:FPGA_OLDEST_COMPATIBLE_VERSION_BUILD - localparam FPGA_CURRENT_VERSION_MAJOR = 'hB; // FPGA_VERSION:FPGA_CURRENT_VERSION_MAJOR - localparam FPGA_OLDEST_COMPATIBLE_VERSION_MAJOR = 'hB; // FPGA_VERSION:FPGA_OLDEST_COMPATIBLE_VERSION_MAJOR - localparam FPGA_VERSION_LAST_MODIFIED_TIME = 'h26022715; // FPGA_VERSION:FPGA_VERSION_LAST_MODIFIED_TIME + localparam FPGA_CURRENT_VERSION_MAJOR = 'hC; // FPGA_VERSION:FPGA_CURRENT_VERSION_MAJOR + localparam FPGA_OLDEST_COMPATIBLE_VERSION_MAJOR = 'hC; // FPGA_VERSION:FPGA_OLDEST_COMPATIBLE_VERSION_MAJOR + localparam FPGA_VERSION_LAST_MODIFIED_TIME = 'h26090111; // FPGA_VERSION:FPGA_VERSION_LAST_MODIFIED_TIME // Enumerated type RF_CORE_100M_VERSION localparam RF_CORE_100M_VERSION_SIZE = 7; diff --git a/fpga/usrp3/top/x400/regmap/x420/versioning_regs_regmap_utils.vh b/fpga/usrp3/top/x400/regmap/x420/versioning_regs_regmap_utils.vh index 13d39ab37..13555555d 100644 --- a/fpga/usrp3/top/x400/regmap/x420/versioning_regs_regmap_utils.vh +++ b/fpga/usrp3/top/x400/regmap/x420/versioning_regs_regmap_utils.vh @@ -86,9 +86,9 @@ localparam FPGA_CURRENT_VERSION_BUILD = 'h0; // FPGA_VERSION:FPGA_CURRENT_VERSION_BUILD localparam FPGA_OLDEST_COMPATIBLE_VERSION_MINOR = 'h0; // FPGA_VERSION:FPGA_OLDEST_COMPATIBLE_VERSION_MINOR localparam FPGA_OLDEST_COMPATIBLE_VERSION_BUILD = 'h0; // FPGA_VERSION:FPGA_OLDEST_COMPATIBLE_VERSION_BUILD - localparam FPGA_CURRENT_VERSION_MAJOR = 'hB; // FPGA_VERSION:FPGA_CURRENT_VERSION_MAJOR - localparam FPGA_OLDEST_COMPATIBLE_VERSION_MAJOR = 'hB; // FPGA_VERSION:FPGA_OLDEST_COMPATIBLE_VERSION_MAJOR - localparam FPGA_VERSION_LAST_MODIFIED_TIME = 'h26022715; // FPGA_VERSION:FPGA_VERSION_LAST_MODIFIED_TIME + localparam FPGA_CURRENT_VERSION_MAJOR = 'hC; // FPGA_VERSION:FPGA_CURRENT_VERSION_MAJOR + localparam FPGA_OLDEST_COMPATIBLE_VERSION_MAJOR = 'hC; // FPGA_VERSION:FPGA_OLDEST_COMPATIBLE_VERSION_MAJOR + localparam FPGA_VERSION_LAST_MODIFIED_TIME = 'h26090111; // FPGA_VERSION:FPGA_VERSION_LAST_MODIFIED_TIME // Enumerated type RF_CORE_1000M_VERSION localparam RF_CORE_1000M_VERSION_SIZE = 7; diff --git a/fpga/usrp3/top/x400/regmap/x440/versioning_regs_regmap_utils.vh b/fpga/usrp3/top/x400/regmap/x440/versioning_regs_regmap_utils.vh index cba6f18ba..bf25eec24 100644 --- a/fpga/usrp3/top/x400/regmap/x440/versioning_regs_regmap_utils.vh +++ b/fpga/usrp3/top/x400/regmap/x440/versioning_regs_regmap_utils.vh @@ -86,9 +86,9 @@ localparam FPGA_CURRENT_VERSION_BUILD = 'h0; // FPGA_VERSION:FPGA_CURRENT_VERSION_BUILD localparam FPGA_OLDEST_COMPATIBLE_VERSION_MINOR = 'h0; // FPGA_VERSION:FPGA_OLDEST_COMPATIBLE_VERSION_MINOR localparam FPGA_OLDEST_COMPATIBLE_VERSION_BUILD = 'h0; // FPGA_VERSION:FPGA_OLDEST_COMPATIBLE_VERSION_BUILD - localparam FPGA_CURRENT_VERSION_MAJOR = 'hB; // FPGA_VERSION:FPGA_CURRENT_VERSION_MAJOR - localparam FPGA_OLDEST_COMPATIBLE_VERSION_MAJOR = 'hB; // FPGA_VERSION:FPGA_OLDEST_COMPATIBLE_VERSION_MAJOR - localparam FPGA_VERSION_LAST_MODIFIED_TIME = 'h26022715; // FPGA_VERSION:FPGA_VERSION_LAST_MODIFIED_TIME + localparam FPGA_CURRENT_VERSION_MAJOR = 'hC; // FPGA_VERSION:FPGA_CURRENT_VERSION_MAJOR + localparam FPGA_OLDEST_COMPATIBLE_VERSION_MAJOR = 'hC; // FPGA_VERSION:FPGA_OLDEST_COMPATIBLE_VERSION_MAJOR + localparam FPGA_VERSION_LAST_MODIFIED_TIME = 'h26090111; // FPGA_VERSION:FPGA_VERSION_LAST_MODIFIED_TIME // Enumerated type RF_CORE_200M_VERSION localparam RF_CORE_200M_VERSION_SIZE = 7; diff --git a/fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x410/Makefile b/fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x410/Makefile new file mode 100644 index 000000000..4d706680d --- /dev/null +++ b/fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x410/Makefile @@ -0,0 +1,23 @@ +# +# Copyright 2026 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# +# Description: X410 variant of the X4xx GPIO SPI simulation shell. +# + +VLOG_ARGS += +define+X410 +SVLOG_ARGS += +define+X410 + +#------------------------------------------------- +# Top-of-Makefile +#------------------------------------------------- +BASE_DIR = $(abspath ../../../../../top) +include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak + +include ../x4xx/Makefile.common + +#------------------------------------------------- +# Bottom-of-Makefile +#------------------------------------------------- +include $(BASE_DIR)/../tools/make/viv_simulator.mak diff --git a/fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x4xx/Makefile b/fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x4xx/Makefile new file mode 100644 index 000000000..17ff340f0 --- /dev/null +++ b/fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x4xx/Makefile @@ -0,0 +1,20 @@ +# +# Copyright 2026 Ettus Research, a National Instruments Brand +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# +# Description: X4xx variant of the X4xx GPIO SPI simulation shell. +# + +#------------------------------------------------- +# Top-of-Makefile +#------------------------------------------------- +BASE_DIR = $(abspath ../../../../../top) +include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak + +include ./Makefile.common + +#------------------------------------------------- +# Bottom-of-Makefile +#------------------------------------------------- +include $(BASE_DIR)/../tools/make/viv_simulator.mak diff --git a/fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x4xx/Makefile.common b/fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x4xx/Makefile.common new file mode 100644 index 000000000..c1512da29 --- /dev/null +++ b/fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x4xx/Makefile.common @@ -0,0 +1,21 @@ +#------------------------------------------------- +# Design Specific +#------------------------------------------------- +include $(BASE_DIR)/../lib/control/Makefile.srcs +include $(BASE_DIR)/../lib/rfnoc/Makefile.srcs + +DESIGN_SRCS += $(abspath \ +$(CONTROL_LIB_SRCS) \ +$(RFNOC_FRAMEWORK_SRCS) \ +../../../regmap/XmlSvPkgDIG_IFC_REGMAP.sv \ +../../../x4xx_gpio_spi.sv \ +) + +#------------------------------------------------- +# Testbench Specific +#------------------------------------------------- +SIM_TOP = x4xx_gpio_spi_tb + +SIM_SRCS = $(abspath \ +../x4xx_gpio_spi_tb.sv \ +) diff --git a/fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x4xx_gpio_spi_tb.sv b/fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x4xx_gpio_spi_tb.sv new file mode 100644 index 000000000..662112b9b --- /dev/null +++ b/fpga/usrp3/top/x400/sim/x4xx_gpio_spi_tb/x4xx_gpio_spi_tb.sv @@ -0,0 +1,364 @@ +// +// Copyright 2026 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Module: x4xx_gpio_spi_tb +// +// Description: X4xx GPIO SPI transaction testbench for four peripheral slots. +// +// Validates GPIO pin configuration, CS idle state, and SPI write/readback for +// 20-, 32-, 40-, and 64-bit transactions. Tests cover consecutive transfers, +// switching peripheral slots and clock dividers, randomized payloads, the +// status and extended response registers, and SPI timing checks. +// +// This testbench does not cover invalid register configurations, unsupported +// transaction lengths, concurrent transactions. +// The DUT does not properly handle these unsupported scenarios. +// +// For testing X410, run with VLOG_ARGS='+define+X410' SVLOG_ARGS='+define+X410' +// + +`default_nettype none + +module x4xx_gpio_spi_tb; + `include "test_exec.svh" + import PkgTestExec::*; + import ctrlport_pkg::*; + import ctrlport_bfm_pkg::*; + import spi_slave_bfm_pkg::*; + + import XmlSvPkgDIG_IFC_REGMAP::*; + + localparam int unsigned NUM_PERIPHERALS = 4; + + // Compile-time BFM widths for the peripheral slots. + localparam int unsigned TRANSACTION_LENGTH_0 = 64; + localparam int unsigned TRANSACTION_LENGTH_1 = 40; + localparam int unsigned TRANSACTION_LENGTH_2 = 32; + localparam int unsigned TRANSACTION_LENGTH_3 = 20; + + + localparam time CLK_2X_PERIOD = 12ns; + `ifdef X410 + localparam bit DOUBLE_CLOCK = 1; + `else + localparam bit DOUBLE_CLOCK = 0; + `endif + localparam int unsigned CLK_DIV_1 = 2; + localparam int unsigned CLK_DIV_2 = 6; + // SPI edge toggle: 0 updates on falling and samples on rising; 1 reverses it. + localparam bit SPI_UPDATE_ON_RISING = 1; + localparam int unsigned SDI_PIN = 1; + localparam int unsigned SDO_PIN = 2; + localparam int unsigned CLK_PIN = 3; + localparam int unsigned CS_PINS [0:NUM_PERIPHERALS-1] = '{0, 4, 5, 6}; + localparam int unsigned TRANSACTION_LENGTHS [0:NUM_PERIPHERALS-1] = '{64, 40, 32, 20}; + + // The DUT uses a control clock and a 2x SPI engine clock. + logic clk, clkx2, reset; + sim_clock_gen #(.PERIOD(CLK_2X_PERIOD*2), .AUTOSTART(0)) clk_gen ( + .clk(clk), .rst(reset)); + sim_clock_gen #(.PERIOD(CLK_2X_PERIOD), .AUTOSTART(0)) clk_gen_x2 ( + .clk(clkx2), .rst()); + + // GPIO interface signals + logic [31:0] gpio_out; + logic [31:0] gpio_ddr; + wire logic [31:0] gpio_in; + + // SPI interfaces for the peripheral slots. + spi_if spi_if [0:NUM_PERIPHERALS-1] (); + + // All slots share SCK, MOSI, and MISO GPIO pins; each has its own CS pin. + for (genvar spi_idx = 0; spi_idx < NUM_PERIPHERALS; spi_idx++) begin : gen_spi_wiring + assign spi_if[spi_idx].cs_n = gpio_out[CS_PINS[spi_idx]]; + assign spi_if[spi_idx].sck = gpio_out[CLK_PIN]; + assign spi_if[spi_idx].mosi = gpio_out[SDO_PIN]; + assign gpio_in[SDI_PIN] = spi_if[spi_idx].miso; + end + + // The BFMs must remain explicit because length is a class specialization parameter. + spi_slave_bfm #(.TRANSACTION_LENGTH(TRANSACTION_LENGTH_0)) spi_bfm_0 = new(spi_if[0]); + spi_slave_bfm #(.TRANSACTION_LENGTH(TRANSACTION_LENGTH_1)) spi_bfm_1 = new(spi_if[1]); + spi_slave_bfm #(.TRANSACTION_LENGTH(TRANSACTION_LENGTH_2)) spi_bfm_2 = new(spi_if[2]); + spi_slave_bfm #(.TRANSACTION_LENGTH(TRANSACTION_LENGTH_3)) spi_bfm_3 = new(spi_if[3]); + + // Each slot has an independent monitor so timing expectations follow the + // selected transaction clock divider. + spi_timing_monitor_bfm spi_timing_mon [0:NUM_PERIPHERALS-1]; + + for (genvar spi_idx = 0; spi_idx < NUM_PERIPHERALS; spi_idx++) begin : gen_spi_timing_monitor + initial begin + spi_timing_mon[spi_idx] = new( + .iface(spi_if[spi_idx]), .half_per_time(get_half_per_time(CLK_DIV_1)), + .cs_hold_time(0), .cs_to_first_rise_time(0), .cs_guard_time(0)); + end + end + + // Control-port connection to the GPIO SPI DUT. + logic [1:0] spi_ctrlport_resp_status; + ctrlport_if gpio_ctrlport_if (.clk(clk), .rst(reset)); + ctrlport_bfm gpio_ctrlport_bfm = new(gpio_ctrlport_if); + + x4xx_gpio_spi dut ( + .ctrlport_clk (clk), + .ctrlport_clk_2x (clkx2), + .ctrlport_rst (reset), + .s_ctrlport_req_wr (gpio_ctrlport_if.req.wr), + .s_ctrlport_req_rd (gpio_ctrlport_if.req.rd), + .s_ctrlport_req_addr (gpio_ctrlport_if.req.addr), + .s_ctrlport_req_data (gpio_ctrlport_if.req.data), + .s_ctrlport_resp_ack (gpio_ctrlport_if.resp.ack), + .s_ctrlport_resp_status(spi_ctrlport_resp_status), + .s_ctrlport_resp_data (gpio_ctrlport_if.resp.data), + .gpio_out (gpio_out), + .gpio_ddr (gpio_ddr), + .gpio_in (gpio_in) + ); + + assign gpio_ctrlport_if.resp.status = ctrlport_status_t'(spi_ctrlport_resp_status); + + // Return the SPI half-period expected by the timing monitor. X410 runs the + // SPI engine at twice the clock rate used by the other X4xx variants. + function automatic time get_half_per_time(input int unsigned clk_div); + return (clk_div + 1) * CLK_2X_PERIOD * (DOUBLE_CLOCK ? 1 : 2); + endfunction + + function automatic logic [63:0] get_response_mask( + input int unsigned transaction_length + ); + // SPI_FULL_RESPONSE_MSB exposes bits 62:31; bit 63 is not returned. + return (64'h1 << ((transaction_length < 63) ? transaction_length : 63)) - 1; + endfunction + + function automatic logic [31:0] get_status_mask( + input int unsigned transaction_length + ); + // SPI_STATUS exposes at most 31 response bits below SPI_READY. + return (32'h1 << ((transaction_length < 31) ? transaction_length : 31)) - 1; + endfunction + + // Program the pin mapping and fixed transaction length for one SPI slot. + task automatic configure_peripheral(input int unsigned selected_peripheral); + SPI_SETUP peripheral_config_fields; + + peripheral_config_fields = '0; + peripheral_config_fields.MOSI_EDGE = SPI_UPDATE_ON_RISING; + peripheral_config_fields.MISO_EDGE = !SPI_UPDATE_ON_RISING; + peripheral_config_fields.SPI_LENGTH = TRANSACTION_LENGTHS[selected_peripheral]; + peripheral_config_fields.SLAVE_CS = CS_PINS[selected_peripheral]; + peripheral_config_fields.SLAVE_MISO = SDI_PIN; + peripheral_config_fields.SLAVE_MOSI = SDO_PIN; + peripheral_config_fields.SLAVE_CLK = CLK_PIN; + gpio_ctrlport_bfm.write(kSPI_SLAVE_CONFIG(selected_peripheral), peripheral_config_fields); + endtask + + task automatic configure_transaction( + input int unsigned selected_peripheral, + input int unsigned clk_div + ); + SPI_TRANSACTION_CONFIG transaction_config_fields; + + // The selected selected_peripheral and divider apply to the next transaction. + transaction_config_fields = '0; + transaction_config_fields.SPI_CLK_DIV = clk_div; + transaction_config_fields.SPI_SLAVE_SELECT = selected_peripheral; + gpio_ctrlport_bfm.write(kSPI_TRANSACTION_CONFIG, transaction_config_fields); + spi_timing_mon[selected_peripheral].set_timing( + .half_per_time(get_half_per_time(clk_div)), + .cs_hold_time(0), .cs_to_first_rise_time(0), .cs_guard_time(0)); + endtask + + task automatic queue_bfm_transaction( + input int unsigned selected_peripheral, + input logic [63:0] write_data, + input logic [63:0] expected_response + ); + // Keep the typed BFM dispatch in one place for simulator portability. + case (selected_peripheral) + 0: spi_bfm_0.async_write_read(write_data, expected_response); + 1: spi_bfm_1.async_write_read(write_data, expected_response); + 2: spi_bfm_2.async_write_read(write_data, expected_response); + 3: spi_bfm_3.async_write_read(write_data, expected_response); + default: $fatal(1, "Invalid SPI peripheral index: %0d", selected_peripheral); + endcase + endtask + + task automatic wait_for_cs(input int unsigned selected_peripheral); + // Dynamic bit-select event controls are avoided for Vivado XSim. + case (selected_peripheral) + 0: @(posedge gpio_out[CS_PINS[0]]); + 1: @(posedge gpio_out[CS_PINS[1]]); + 2: @(posedge gpio_out[CS_PINS[2]]); + 3: @(posedge gpio_out[CS_PINS[3]]); + default: $fatal(1, "Invalid SPI peripheral index: %0d", selected_peripheral); + endcase + endtask + + task automatic get_bfm_error_count(input int unsigned selected_peripheral, output int count); + case (selected_peripheral) + 0: count = spi_bfm_0.get_error_count(); + 1: count = spi_bfm_1.get_error_count(); + 2: count = spi_bfm_2.get_error_count(); + 3: count = spi_bfm_3.get_error_count(); + default: $fatal(1, "Invalid SPI peripheral index: %0d", selected_peripheral); + endcase + endtask + + task automatic start_bfms(); + // Start all models, including inactive slots. Inactive CS lines remain + // high and therefore do not consume queued transactions. + spi_bfm_0.run(); + spi_bfm_1.run(); + spi_bfm_2.run(); + spi_bfm_3.run(); + for (int unsigned spi_idx = 0; spi_idx < NUM_PERIPHERALS; spi_idx++) begin + spi_timing_mon[spi_idx].run(); + end + endtask + + task automatic start_transaction( + input int unsigned transaction_length, + input logic [63:0] write_data + ); + if (transaction_length > 32) begin + gpio_ctrlport_bfm.write( + kSPI_TRANSACTION_LSB, + (write_data << (64 - transaction_length)) & kSPI_TRANSACTION_LSBMask); + gpio_ctrlport_bfm.write( + kSPI_TRANSACTION_GO, + (write_data >> (transaction_length - 32)) & kSPI_TRANSACTION_GOMask); + end else begin + gpio_ctrlport_bfm.write( + kSPI_TRANSACTION_GO, + (write_data << (32 - transaction_length)) & kSPI_TRANSACTION_GOMask); + end + endtask + + task automatic execute_transaction( + input int unsigned selected_peripheral, + input logic [63:0] write_data, + input logic [63:0] expected_response + ); + int unsigned spi_status_read; + int unsigned spi_response_msb; + int bfm_error_count; + int timing_error_count; + int unsigned transaction_length; + logic [62:0] full_response; + logic [63:0] response_mask; + logic [31:0] status_mask; + + + transaction_length = TRANSACTION_LENGTHS[selected_peripheral]; + response_mask = get_response_mask(transaction_length); + status_mask = get_status_mask(transaction_length); + queue_bfm_transaction(selected_peripheral, write_data, expected_response); + start_transaction(transaction_length, write_data); + wait_for_cs(selected_peripheral); + repeat (20) @(posedge clk); + gpio_ctrlport_bfm.read(kSPI_STATUS, spi_status_read); + + test.assert_error( + spi_status_read[kSPI_READY], + $sformatf("SPI%0d transaction not complete", transaction_length)); + test.assert_error( + (spi_status_read & status_mask) == (expected_response & status_mask), + $sformatf("SPI%0d status response failed. Expected 0x%0h, got 0x%0h", + transaction_length, expected_response & status_mask, + spi_status_read & status_mask)); + + full_response = {32'b0, spi_status_read[30:0]}; + if (transaction_length > 31) begin + gpio_ctrlport_bfm.read(kSPI_FULL_RESPONSE_MSB, spi_response_msb); + full_response[62:31] = spi_response_msb; + end + test.assert_error( + (full_response & response_mask) == (expected_response & response_mask), + $sformatf("SPI%0d full response failed. Expected 0x%0h, got 0x%0h, mask 0x%0h", + transaction_length, expected_response, full_response, response_mask)); + + get_bfm_error_count(selected_peripheral, bfm_error_count); + test.assert_error( + bfm_error_count == 0, + $sformatf("SPI%0d BFM reported %0d errors", transaction_length, bfm_error_count)); + timing_error_count = spi_timing_mon[selected_peripheral].get_error_count(); + test.assert_error( + timing_error_count == 0, + $sformatf("SPI%0d timing monitor reported %0d errors", + transaction_length, timing_error_count)); + endtask + + initial begin : main + string tb_name; + int unsigned selected_peripheral; + int unsigned previous_peripheral; + + `ifdef X410 + tb_name = "x410_gpio_spi_tb"; + `else + tb_name = "x4xx_gpio_spi_tb"; + `endif + test.start_tb(tb_name); + gpio_ctrlport_bfm.run(); + clk_gen.start(); + clk_gen_x2.start(); + clk_gen.reset(50); + //------------------------------------------------------------------------- + + test.start_test("Full configuration and transaction", 100us); + + for (int unsigned selected_peripheral = 0; selected_peripheral < NUM_PERIPHERALS; selected_peripheral++) begin + configure_peripheral(selected_peripheral); + test.assert_error( + gpio_out[CS_PINS[selected_peripheral]] === 1'b1, + $sformatf("SPI%0d CS is not high after configuration", TRANSACTION_LENGTHS[selected_peripheral])); + test.assert_error( + gpio_ddr[CS_PINS[selected_peripheral]] === 1'b1, + $sformatf("SPI%0d CS is not configured as an output", TRANSACTION_LENGTHS[selected_peripheral])); + end + test.assert_error(gpio_ddr[CLK_PIN] === 1'b1, "SPI clock is not configured as an output"); + test.assert_error(gpio_ddr[SDO_PIN] === 1'b1, "SPI SDO is not configured as an output"); + test.assert_error(gpio_ddr[SDI_PIN] === 1'b0, "SPI SDI is not configured as an input"); + + // Only start SPI BFM after configuration is done (CS is high) + start_bfms(); + + configure_transaction(0, CLK_DIV_1); + execute_transaction(0, 64'hFAFAFAFA00000001, 64'h0123456789ABCDEF); + //Consecutive transaction with new divider + configure_transaction(0, CLK_DIV_2); + execute_transaction(0, 64'hFAFAFAFA00000001, 64'h0123456789ABCDEF); + //Transaction on different peripheral and new divider + configure_transaction(2, CLK_DIV_1); + execute_transaction(2, 64'hBA4B0EB4, 64'h98765432); + //Transaction on different peripheral and new divider + configure_transaction(1, CLK_DIV_1); + execute_transaction(1, 64'h0000000A010FA7BF, 64'h000000DCBA987654); + //Consecutive transaction without changing the clock divider + configure_transaction(3, CLK_DIV_1); + execute_transaction(3, 64'h00000000000FA7BF, 64'h0000000000054321); + execute_transaction(3, 64'h00000000000FA00F, 64'h0000000000054001); + + test.end_test(); + //------------------------------------------------------------------------- + + test.start_test("Random transactions", 2ms); + previous_peripheral = NUM_PERIPHERALS; + for (int unsigned transaction = 0; transaction < 100; transaction++) begin + selected_peripheral = $urandom_range(NUM_PERIPHERALS - 1, 0); + if (selected_peripheral != previous_peripheral) begin + configure_transaction(selected_peripheral, CLK_DIV_2); + end + execute_transaction(selected_peripheral, {$urandom(), $urandom()}, {$urandom(), $urandom()}); + previous_peripheral = selected_peripheral; + end + test.end_test(); + + test.end_tb(); + end + +endmodule + +`default_nettype wire diff --git a/fpga/usrp3/top/x400/x4xx.sv b/fpga/usrp3/top/x400/x4xx.sv index 7906db898..aed5df6d0 100644 --- a/fpga/usrp3/top/x400/x4xx.sv +++ b/fpga/usrp3/top/x400/x4xx.sv @@ -3843,13 +3843,13 @@ endmodule //

  • Oldest compatible version: @.VERSIONING_REGS_REGMAP..OLDEST_COMPATIBLE_VERSION //
  • Version last modified: @.VERSIONING_REGS_REGMAP..VERSION_LAST_MODIFIED // -// +// // // -// +// // // -// +// // // // diff --git a/fpga/usrp3/top/x400/x4xx_gpio_spi.v b/fpga/usrp3/top/x400/x4xx_gpio_spi.sv similarity index 71% rename from fpga/usrp3/top/x400/x4xx_gpio_spi.v rename to fpga/usrp3/top/x400/x4xx_gpio_spi.sv index 08eacd108..c857d7b17 100644 --- a/fpga/usrp3/top/x400/x4xx_gpio_spi.v +++ b/fpga/usrp3/top/x400/x4xx_gpio_spi.sv @@ -1,5 +1,5 @@ // -// Copyright 2021 Ettus Research, A National Instruments Brand +// Copyright 2026 Ettus Research, A National Instruments Brand // // SPDX-License-Identifier: LGPL-3.0-or-later // @@ -28,7 +28,7 @@ module x4xx_gpio_spi #( parameter NUM_SLAVES = 4, parameter [19:0] BASE_ADDRESS = 0, - parameter [19:0] SIZE_ADDRESS = 19'h20 + parameter [19:0] SIZE_ADDRESS = 19'h2C ) ( input wire ctrlport_clk, input wire ctrlport_clk_2x, @@ -52,14 +52,14 @@ module x4xx_gpio_spi #( ); `include "../../lib/rfnoc/core/ctrlport.vh" - `include "regmap/dig_ifc_regmap_utils.vh" + import XmlSvPkgDIG_IFC_REGMAP::*; // Registers / wires for SPI core communication reg [31:0] set_data = 0; reg [ 7:0] set_addr = 0; reg set_stb = 1'b0; - wire [31:0] readback; + wire [63:0] readback; wire readback_stb; wire readback_stb_extended; @@ -80,10 +80,10 @@ module x4xx_gpio_spi #( // These arrays are set to the maximum supported SPI slaves instead of // the provided NUM_SLAVES to facilitate concurrent re-mapping. // See section(GPIO Mapping) of this file. - reg [ SLAVE_CLK_SIZE-1:0] sclk_mapping [3:0]; - reg [SLAVE_MOSI_SIZE-1:0] mosi_mapping [3:0]; - reg [SLAVE_MISO_SIZE-1:0] miso_mapping [3:0]; - reg [ SLAVE_CS_SIZE-1:0] ss_mapping [3:0]; + reg [kSLAVE_CLKSize-1:0] sclk_mapping [3:0]; + reg [kSLAVE_MOSISize-1:0] mosi_mapping [3:0]; + reg [kSLAVE_MISOSize-1:0] miso_mapping [3:0]; + reg [ kSLAVE_CSSize-1:0] ss_mapping [3:0]; //--------------------------------------------------------------------------- // Address calculation @@ -95,8 +95,8 @@ module x4xx_gpio_spi #( // Check that address is targeting slave configuration. wire address_is_slave = - (s_ctrlport_req_addr >= BASE_ADDRESS + SPI_SLAVE_CONFIG(0)) && - (s_ctrlport_req_addr <= BASE_ADDRESS + SPI_SLAVE_CONFIG(3)); + (s_ctrlport_req_addr >= BASE_ADDRESS + kSPI_SLAVE_CONFIG(0)) && + (s_ctrlport_req_addr <= BASE_ADDRESS + kSPI_SLAVE_CONFIG(3)); // Decode the slave being addressed. wire [1:0]slave_address = s_ctrlport_req_addr[3:2]; @@ -108,7 +108,7 @@ module x4xx_gpio_spi #( // These settings are registered individually for each slave reg [ NUM_SLAVES-1:0] data_in_edge = {NUM_SLAVES{1'b0}}; reg [ NUM_SLAVES-1:0] data_out_edge = {NUM_SLAVES{1'b0}}; - reg [SPI_LENGTH_SIZE-1:0] slave_spi_length [NUM_SLAVES-1:0]; + reg [kSPI_LENGTHSize-1:0] slave_spi_length [NUM_SLAVES-1:0]; // One-hot encoding to indicate active slave reg [NUM_SLAVES-1:0] slave_select = {NUM_SLAVES{1'b0}}; @@ -119,20 +119,25 @@ module x4xx_gpio_spi #( localparam IDLE = 3'd0; localparam SET_DIVIDER = 3'd1; - localparam WRITE_SPI = 3'd2; - localparam CONFIG_TRANSFER = 3'd3; - localparam WAIT_SPI = 3'd4; + localparam WRITE_SPI_LSB = 3'd2; + localparam WRITE_SPI = 3'd3; + localparam CONFIG_TRANSFER = 3'd4; + localparam WAIT_SPI = 3'd5; + // Addresses in simple_spi_core_64bit.v localparam DIVIDER_ADDRESS = 8'd0; localparam CTRL_ADDRESS = 8'd1; localparam DATA_ADDRESS = 8'd2; + localparam DATA_LSB_ADDRESS = 8'd3; reg [ 2:0] state = IDLE; reg [ 31:0] data_cache; - reg [SPI_CLK_DIV_SIZE-1:0] divider; + reg [kSPI_CLK_DIVSize-1:0] divider; reg [ 1:0] cs; reg spi_go = 1'b0; reg spi_ready = 1'b0; + // Additional bits for optional 64 bit transaction + reg [ 31:0] data_cache_lsb; integer slave_i; @@ -146,20 +151,21 @@ module x4xx_gpio_spi #( s_ctrlport_resp_ack <= 1'b0; spi_go <= 1'b0; spi_ready <= 1'b0; - divider <= {SPI_CLK_DIV_SIZE{1'b0}}; + divider <= {kSPI_CLK_DIVSize{1'b0}}; cs <= 2'b0; + data_cache <= 32'h0; - // Assigned to unassigned mapping. This avoids overwriting - // signals with those from uninitialized slaves. + // Assigned to unassigned mapping (pin 31 is unused). This avoids + // overwriting signals with those from uninitialized slaves. for ( slave_i = 0; slave_i < 4; slave_i = slave_i + 1 ) begin - sclk_mapping[slave_i] <= 5'h31; - mosi_mapping[slave_i] <= 5'h31; - miso_mapping[slave_i] <= 5'h31; - ss_mapping [slave_i] <= 5'h31; + sclk_mapping[slave_i] <= 5'd31; + mosi_mapping[slave_i] <= 5'd31; + miso_mapping[slave_i] <= 5'd31; + ss_mapping [slave_i] <= 5'd31; end for ( slave_i = 0; slave_i < NUM_SLAVES; slave_i = slave_i + 1) begin - slave_spi_length[slave_i] <= {SPI_LENGTH_SIZE{1'b0}}; + slave_spi_length[slave_i] <= {kSPI_LENGTHSize{1'b0}}; end end else begin @@ -175,26 +181,33 @@ module x4xx_gpio_spi #( // Address spi configuration writes if(address_is_slave) begin + automatic SPI_SETUP spi_setup = s_ctrlport_req_data; // GPIO mapping - sclk_mapping [slave_address] <= s_ctrlport_req_data[SLAVE_CLK_MSB:SLAVE_CLK]; - mosi_mapping [slave_address] <= s_ctrlport_req_data[SLAVE_MOSI_MSB:SLAVE_MOSI]; - miso_mapping [slave_address] <= s_ctrlport_req_data[SLAVE_MISO_MSB:SLAVE_MISO]; - ss_mapping [slave_address] <= s_ctrlport_req_data[SLAVE_CS_MSB:SLAVE_CS]; + sclk_mapping [slave_address] <= spi_setup.SLAVE_CLK; + mosi_mapping [slave_address] <= spi_setup.SLAVE_MOSI; + miso_mapping [slave_address] <= spi_setup.SLAVE_MISO; + ss_mapping [slave_address] <= spi_setup.SLAVE_CS; // Transfer Configuration - slave_spi_length [slave_address] <= s_ctrlport_req_data[SPI_LENGTH_MSB:SPI_LENGTH]; - data_in_edge [slave_address] <= s_ctrlport_req_data[MISO_EDGE]; - data_out_edge [slave_address] <= s_ctrlport_req_data[MOSI_EDGE]; + slave_spi_length [slave_address] <= spi_setup.SPI_LENGTH; + data_in_edge [slave_address] <= spi_setup.MISO_EDGE; + data_out_edge [slave_address] <= spi_setup.MOSI_EDGE; end else begin case (s_ctrlport_req_addr) - BASE_ADDRESS + SPI_TRANSACTION_CONFIG: begin - divider <= s_ctrlport_req_data[SPI_CLK_DIV_MSB:SPI_CLK_DIV]; - cs <= s_ctrlport_req_data[SPI_SLAVE_SELECT_MSB:SPI_SLAVE_SELECT]; + BASE_ADDRESS + kSPI_TRANSACTION_CONFIG: begin + automatic SPI_TRANSACTION_CONFIG spi_transaction_config = s_ctrlport_req_data; + divider <= spi_transaction_config.SPI_CLK_DIV; + cs <= spi_transaction_config.SPI_SLAVE_SELECT; end - BASE_ADDRESS + SPI_TRANSACTION_GO: begin + BASE_ADDRESS + kSPI_TRANSACTION_LSB: begin + data_cache_lsb <= s_ctrlport_req_data; + end + + BASE_ADDRESS + kSPI_TRANSACTION_GO: begin spi_ready <= 1'b0; spi_go <= 1'b1; + data_cache <= s_ctrlport_req_data; end // No register implementation for provided address @@ -214,22 +227,34 @@ module x4xx_gpio_spi #( end else if(s_ctrlport_req_rd) begin // default assumption: valid request - s_ctrlport_resp_ack <= 1'b1; - s_ctrlport_resp_status <= CTRL_STS_OKAY; - s_ctrlport_resp_data <= {32{1'b0}}; + s_ctrlport_resp_ack <= 1'b1; + s_ctrlport_resp_status <= CTRL_STS_OKAY; + s_ctrlport_resp_data <= {32{1'b0}}; case (s_ctrlport_req_addr) - BASE_ADDRESS + SPI_TRANSACTION_CONFIG: begin - s_ctrlport_resp_data[SPI_CLK_DIV_MSB:SPI_CLK_DIV] <= divider; + BASE_ADDRESS + kSPI_TRANSACTION_CONFIG: begin + automatic SPI_TRANSACTION_CONFIG spi_transaction_config = '0; + spi_transaction_config.SPI_CLK_DIV = divider; + s_ctrlport_resp_data <= spi_transaction_config; end - BASE_ADDRESS + SPI_STATUS: begin - s_ctrlport_resp_data[SPI_READY] <= spi_ready; - s_ctrlport_resp_data[SPI_RESPONSE_MSB:SPI_RESPONSE] <= readback[SPI_RESPONSE_MSB:SPI_RESPONSE]; + BASE_ADDRESS + kSPI_STATUS: begin + automatic SPI_STATUS spi_status = '0; + spi_status.SPI_READY = spi_ready; + spi_status.SPI_RESPONSE = readback[30:0]; + s_ctrlport_resp_data <= spi_status; end - BASE_ADDRESS + CONTROLLER_INFO: begin - s_ctrlport_resp_data[SLAVE_COUNT_MSB:SLAVE_COUNT] <= NUM_SLAVES; + BASE_ADDRESS + kSPI_FULL_RESPONSE_MSB: begin + automatic SPI_FULL_RESPONSE_MSB spi_full_response = '0; + spi_full_response.SPI_FULL_RESPONSE_MSB_DATA = readback[62:31]; + s_ctrlport_resp_data <= spi_full_response; + end + + BASE_ADDRESS + kCONTROLLER_INFO: begin + automatic CONTROLLER_INFO controller_info = '0; + controller_info.SLAVE_COUNT = NUM_SLAVES; + s_ctrlport_resp_data <= controller_info; end // No register implementation for provided address @@ -260,9 +285,8 @@ module x4xx_gpio_spi #( always @ (posedge ctrlport_clk) begin if (ctrlport_rst) begin - state <= IDLE; - set_stb <= 1'b0; - data_cache <= 32'h0; + state <= IDLE; + set_stb <= 1'b0; end else begin // Default Assignments @@ -270,8 +294,6 @@ module x4xx_gpio_spi #( case (state) IDLE: begin - // Save data and address for further steps - data_cache <= s_ctrlport_req_data; if (spi_go) begin state <= CONFIG_TRANSFER; @@ -286,23 +308,37 @@ module x4xx_gpio_spi #( set_stb <= 1'b1; set_addr <= CTRL_ADDRESS; - set_data <= { data_out_edge[cs], // 1 bit - data_in_edge[cs], // 1 bit - slave_spi_length[cs], // 6 bits - {24-NUM_SLAVES{1'b0}}, // Padding for slaves - slave_select // NUM_SLAVES bits + set_data <= { data_out_edge[cs], // 1 bit + data_in_edge[cs], // 1 bit + slave_spi_length[cs][5:0], // 6 bits, ignore MSB, 0 is considered as 64 + {24-NUM_SLAVES{1'b0}}, // Padding for slaves + slave_select // NUM_SLAVES bits }; end // Write divider to SPI core SET_DIVIDER: begin - state <= WRITE_SPI; + if (slave_spi_length[cs] > 32) begin + state <= WRITE_SPI_LSB; + end else begin + state <= WRITE_SPI; + end set_stb <= 1'b1; set_addr <= DIVIDER_ADDRESS; set_data <= {16'b0, divider}; end + + // Write data bits to SPI core (aligned to MSB) + WRITE_SPI_LSB: begin + state <= WRITE_SPI; + + set_stb <= 1'b1; + set_addr <= DATA_LSB_ADDRESS; + set_data <= data_cache_lsb; + end + // Write data bits to SPI core (aligned to MSB) WRITE_SPI: begin state <= WAIT_SPI; @@ -326,14 +362,14 @@ module x4xx_gpio_spi #( endcase // Update Auxiliary signals - gpio_is_mosi <= 32'h0; - gpio_is_sclk <= 32'h0; - gpio_is_cs <= 32'h0; + gpio_is_mosi <= 32'h0; + gpio_is_sclk <= 32'h0; + gpio_is_cs <= 32'h0; for ( slave_i = 0; slave_i < NUM_SLAVES; slave_i = slave_i + 1) begin - gpio_is_mosi [mosi_mapping[slave_i]] <= 1'b1; - gpio_is_sclk [sclk_mapping[slave_i]] <= 1'b1; - gpio_is_cs [ ss_mapping[slave_i]] <= 1'b1; + gpio_is_mosi[mosi_mapping[slave_i]] <= 1'b1; + gpio_is_sclk[sclk_mapping[slave_i]] <= 1'b1; + gpio_is_cs [ ss_mapping[slave_i]] <= 1'b1; end end @@ -345,11 +381,12 @@ module x4xx_gpio_spi #( `ifndef X410 - simple_spi_core #( + simple_spi_core_64bit #( .BASE (0), .WIDTH (NUM_SLAVES), .CLK_IDLE (0), - .SEN_IDLE ({NUM_SLAVES{1'b1}}) + .SEN_IDLE ({NUM_SLAVES{1'b1}}), + .MAX_BITS (64) ) simple_spi_core_i ( .clock (ctrlport_clk), .reset (ctrlport_rst), @@ -414,11 +451,12 @@ module x4xx_gpio_spi #( end end - simple_spi_core #( + simple_spi_core_64bit #( .BASE (0), .WIDTH (NUM_SLAVES), .CLK_IDLE (0), - .SEN_IDLE ({NUM_SLAVES{1'b1}}) + .SEN_IDLE ({NUM_SLAVES{1'b1}}), + .MAX_BITS (64) ) simple_spi_core_i ( .clock (ctrlport_clk_2x), .reset (ctrlport_rst), @@ -514,7 +552,7 @@ endmodule `default_nettype wire //XmlParse xml_on -// +// // // // @@ -550,19 +588,22 @@ endmodule // 16-27: Port B GPIO // // -// +// // -// Indicates the length of SPI transactions to this slave. +// Indicates the length of SPI transactions to this slave.
    +// Valid transaction lengths are 1 through 64 bits.
    +// This is not checked on FPGA and other values will
    +// lead to undefined behavior. //
    //
    -// +// // // Controls the edge in which the MISO line is latched.
    // 0 = falling edge of SCLK.
    // 1 = rising edge of SCLK. //
    //
    -// +// // // Controls the edge in which the MOSI line is updated.
    // 0 = falling edge of SCLK.
    @@ -588,27 +629,51 @@ endmodule //
    // // -// +// // -// Starts a SPI transaction +// For SPI transactions with @.SPI_SLAVE_CONFIG.SPI_LENGTH > 32, this must be written +// before @.SPI_TRANSACTION_GO. +// +// +// Left-aligned LSB payload for SPI transaction with @.SPI_SLAVE_CONFIG.SPI_LENGTH > 32.
    +// See @.SPI_TRANSACTION_GO for more information.
    +//
    +//
    +// +// +// Starts a SPI transaction. Does not check whether a previous transaction is still ongoing. +// If so, the running transaction may be corrupted. // // -// Payload to be sent for the SPI transaction. If the payload is shorter than 32 bits, -// it must be aligned to the MSbs in this field. LSbs are ignored in this scenario. +// Payload to be sent for the SPI transaction.
    +// If the payload is shorter than 32 bits, it must be left-aligned. +// The first transmitted bit is the MSB and data is shifted out to the left.
    +// If the desired payload is longer than 32 bits, the remaining LSBs +// must be written to @.SPI_TRANSACTION_LSB.SPI_DATA_LSB (left-aligned) before starting +// the transaction.
    //
    //
    -// +// // -// Contains the status of the SPI engine. +// Contains the status of the SPI engine and the least-significant 31 bits of the response. +// Also read SPI_FULL_RESPONSE_MSB for bit 32 or for transactions longer than 32 bits. // -// +// // Indicates the SPI engine is ready to start a new SPI transaction. // -// -// Records the response of the last completed SPI transaction. +// +// Records only the least-significant 31 bits of the last completed SPI response. // // -// +// +// +// Contains bits 62 through 31 of the last completed SPI response. +// For transactions shorter than 31 bits, the upper bits in this register are undefined. +// The regmap does not expose the most significant bit (bit 63) of the response. +// +// +// +// // // Contains information pertaining this SPI controller block. //