diff --git a/software/Makefile b/software/Makefile index 2606cc4..573ca08 100644 --- a/software/Makefile +++ b/software/Makefile @@ -33,10 +33,10 @@ ARCHFLAGS = -march=$(ARCH) -mabi=$(ABI) # vector extension. Kept separate so it doesn't force V onto every program. VEC_ARCHFLAGS = -march=rv64gcv_zfh_zvfh -mabi=$(ABI) -CFLAGS = -std=gnu99 -O2 -fno-common -fno-builtin-printf -Wall -specs=htif_nano.specs +CFLAGS = -std=gnu99 -O2 -fno-common -fno-builtin-printf -Wall -specs=htif_nano.specs -Iinclude LDFLAGS = -specs=htif_nano.specs -PROGRAMS = hello hello0 hello1 router ring-hello ucie-loopback tacit-always tacit-dma ucie-vec-memcpy +PROGRAMS = hello hello0 hello1 router ring-hello ucie-loopback ucie-digital-loopback tacit-always tacit-dma ucie-vec-memcpy .DEFAULT_GOAL := default diff --git a/software/ucie-digital-loopback.c b/software/ucie-digital-loopback.c new file mode 100644 index 0000000..942af0c --- /dev/null +++ b/software/ucie-digital-loopback.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include "marchid.h" +#include "mmio.h" +#include "router.h" +#include "ucie.h" + +#define UCIE0_REG_BASE 0x200000UL +#define UCIE1_REG_BASE 0x208000UL +#define ROUTER_MMIO 0x4000 +#define CHIP_ID_ADDR 0x4080 +#define OFFCHIP_OFFSET 0x800000000L + +uint32_t src[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +uint32_t dest[10]; +uint32_t test[10]; + +int rw_mem(uint64_t offset) { + // remote = dest on the other chip: same local address as our dest, tagged with target chip ID. + // offset = OFFCHIP_OFFSET * target_chipId (a byte offset, added via uint8_t* cast). + void *remote = (void *)((uint8_t *)dest + offset); + + size_t write_start = rdcycle(); + memcpy(remote, src, sizeof(src)); + size_t write_end = rdcycle(); + + printf("Wrote %ld bytes in %ld cycles\n", sizeof(src), write_end - write_start); + + size_t read_start = rdcycle(); + memcpy(test, remote, sizeof(src)); + size_t read_end = rdcycle(); + + for (int i = 0; i < 10; i++) { + if (src[i] != test[i]) { + printf("Remote write/read failed at index %d: wrote %x, read %x\n", i, src[i], test[i]); + exit(1); + } + } + + printf("Read %ld bytes in %ld cycles\n", sizeof(src), read_end - read_start); + + return 0; +} + +int main(void) { + + int chip_id = reg_read64(CHIP_ID_ADDR); + + printf("Got chip ID: %d\n", chip_id); + + // setup_ucie_digital() brings up the PHY, hands both bands to the real + // UCIe digital controller (controllerSel = ucie), and blocks until spec + // link training completes. Unlike ucie-loopback.c's setup_ucie() + + // UCIE_BAND_MODE_TL, which bypasses UcieDigitalTop and frames TileLink + // directly onto the mainband, requests here are carried by the trained + // link through the real protocol layer/D2D adapter/logical PHY stack. + printf("Setting up UCIe0 (digital controller)\n"); + setup_ucie_digital(UCIE0_REG_BASE); + printf("Setting up UCIe1 (digital controller)\n"); + setup_ucie_digital(UCIE1_REG_BASE); + + printf("Testing UCIe at port 0\n"); + program_router(0, 1, 0); + rw_mem(OFFCHIP_OFFSET); + + printf("Testing UCIe at port 1\n"); + program_router(0, 1, 1); + rw_mem(OFFCHIP_OFFSET); + + printf("UCIe digital loopback test complete\n"); + + return 0; +} diff --git a/software/ucie.h b/software/ucie.h index a01c8fe..53bd0df 100644 --- a/software/ucie.h +++ b/software/ucie.h @@ -16,48 +16,51 @@ #define UCIE_TX_DATA_MODE 0x10ULL #define UCIE_TX_LFSR_SEED 0x18ULL #define UCIE_TX_LFSR_SEED_WIDTH 0x8ULL -#define UCIE_TX_RST 0xb0ULL -#define UCIE_TX_EXECUTE 0xb8ULL -#define UCIE_TX_WRITE_CHUNK 0xc0ULL -#define UCIE_TX_PACKETS_SENT 0xc8ULL -#define UCIE_TX_MANUAL_REPEAT_PERIOD 0xd0ULL -#define UCIE_TX_PACKETS_TO_SEND 0xd8ULL -#define UCIE_TX_CLK_P 0xe0ULL -#define UCIE_TX_CLK_N 0xe8ULL -#define UCIE_TX_DATA_LANE_GROUP 0xf0ULL -#define UCIE_TX_DATA_OFFSET 0xf8ULL -#define UCIE_TX_DATA_CHUNK_IN0 0x100ULL -#define UCIE_TX_DATA_CHUNK_IN1 0x108ULL -#define UCIE_TX_DATA_CHUNK_OUT0 0x110ULL -#define UCIE_TX_DATA_CHUNK_OUT1 0x118ULL -#define UCIE_TX_TEST_STATE 0x120ULL -#define UCIE_RX_DATA_MODE 0x128ULL -#define UCIE_RX_LFSR_SEED 0x130ULL +#define UCIE_TX_DIVIDER_RST 0xb0ULL +#define UCIE_RX_DIVIDER_RST 0xb8ULL +#define UCIE_TX_DATAPATH_RST 0xc0ULL +#define UCIE_TX_FSM_RST 0xc8ULL +#define UCIE_TX_EXECUTE 0xd0ULL +#define UCIE_TX_WRITE_CHUNK 0xd8ULL +#define UCIE_TX_PACKETS_SENT 0xe0ULL +#define UCIE_TX_MANUAL_REPEAT_PERIOD 0xe8ULL +#define UCIE_TX_PACKETS_TO_SEND 0xf0ULL +#define UCIE_TX_CLK_P 0xf8ULL +#define UCIE_TX_CLK_N 0x100ULL +#define UCIE_TX_DATA_LANE_GROUP 0x108ULL +#define UCIE_TX_DATA_OFFSET 0x110ULL +#define UCIE_TX_DATA_CHUNK_IN0 0x118ULL +#define UCIE_TX_DATA_CHUNK_IN1 0x120ULL +#define UCIE_TX_DATA_CHUNK_OUT0 0x128ULL +#define UCIE_TX_DATA_CHUNK_OUT1 0x130ULL +#define UCIE_TX_TEST_STATE 0x138ULL +#define UCIE_RX_DATA_MODE 0x140ULL +#define UCIE_RX_LFSR_SEED 0x148ULL #define UCIE_RX_LFSR_SEED_WIDTH 0x8ULL -#define UCIE_RX_BIT_ERRORS 0x1c8ULL +#define UCIE_RX_BIT_ERRORS 0x1e0ULL #define UCIE_RX_BIT_ERRORS_WIDTH 0x8ULL -#define UCIE_RX_BIT_ERRORS_EARLY 0x260ULL +#define UCIE_RX_BIT_ERRORS_EARLY 0x278ULL #define UCIE_RX_BIT_ERRORS_EARLY_WIDTH 0x8ULL -#define UCIE_RX_BIT_ERRORS_LATE 0x2f8ULL +#define UCIE_RX_BIT_ERRORS_LATE 0x310ULL #define UCIE_RX_BIT_ERRORS_LATE_WIDTH 0x8ULL -#define UCIE_RX_RST 0x390ULL -#define UCIE_RX_PACKETS_TO_RECEIVE 0x398ULL -#define UCIE_RX_PAUSE_COUNTERS 0x3a0ULL -#define UCIE_RX_PACKETS_RECEIVED 0x3a8ULL -#define UCIE_RX_SIGNATURE 0x3b0ULL -#define UCIE_RX_DATA_LANE 0x3b8ULL -#define UCIE_RX_DATA_OFFSET 0x3c0ULL -#define UCIE_RX_DATA_CHUNK 0x3c8ULL -#define UCIE_CLK_PHASE_SEL 0x3d0ULL -#define UCIE_CLK_FREQ_SEL 0x3d8ULL -#define UCIE_TXCTL 0x3e0ULL +#define UCIE_RX_DATAPATH_RST 0x3a8ULL +#define UCIE_RX_FSM_RST 0x3b0ULL +#define UCIE_RX_PACKETS_TO_RECEIVE 0x3b8ULL +#define UCIE_RX_PAUSE_COUNTERS 0x3c0ULL +#define UCIE_RX_PACKETS_RECEIVED 0x3c8ULL +#define UCIE_RX_SIGNATURE 0x3d0ULL +#define UCIE_RX_IDLE_WORDS_OBSERVED 0x3d8ULL +#define UCIE_RX_DATA_LANE 0x3e0ULL +#define UCIE_RX_DATA_OFFSET 0x3e8ULL +#define UCIE_RX_DATA_CHUNK 0x3f0ULL +#define UCIE_TXCTL 0x3f8ULL #define UCIE_TXCTL_TILE_OFS 0x0ULL #define UCIE_TXCTL_SHUFFLER_OFS 0x8ULL #define UCIE_TXCTL_SHUFFLER_WIDTH 0x8ULL #define UCIE_TXCTL_SAMPLE_NEGEDGE_OFS 0x108ULL #define UCIE_TXCTL_DELAY_OFS 0x110ULL #define UCIE_TXCTL_WIDTH 0x118ULL -#define UCIE_RXCTL 0x1ad8ULL +#define UCIE_RXCTL 0x1af0ULL #define UCIE_RXCTL_ZEN_OFS 0x0ULL #define UCIE_RXCTL_ZCTL_OFS 0x8ULL #define UCIE_RXCTL_VREF_SEL_OFS 0x10ULL @@ -70,46 +73,146 @@ #define UCIE_RXCTL_SAMPLE_NEGEDGE_OFS 0x138ULL #define UCIE_RXCTL_RX_DELAY_OFS 0x140ULL #define UCIE_RXCTL_WIDTH 0x148ULL -#define UCIE_DEBUG_TX_TEST_MODE 0x35c0ULL -#define UCIE_DEBUG_TX_DATA_MODE 0x35c8ULL -#define UCIE_DEBUG_TX_LFSR_SEED 0x35d0ULL -#define UCIE_DEBUG_TX_FSM_RST 0x35d8ULL -#define UCIE_DEBUG_TX_EXECUTE 0x35e0ULL -#define UCIE_DEBUG_TX_MANUAL_REPEAT_PERIOD 0x35e8ULL -#define UCIE_DEBUG_TX_PACKETS_TO_SEND 0x35f0ULL -#define UCIE_DEBUG_DATA 0x35f8ULL +#define UCIE_DEBUG_TX_TEST_MODE 0x35d8ULL +#define UCIE_DEBUG_TX_DATA_MODE 0x35e0ULL +#define UCIE_DEBUG_TX_LFSR_SEED 0x35e8ULL +#define UCIE_DEBUG_TX_FSM_RST 0x35f0ULL +#define UCIE_DEBUG_TX_EXECUTE 0x35f8ULL +#define UCIE_DEBUG_TX_MANUAL_REPEAT_PERIOD 0x3600ULL +#define UCIE_DEBUG_TX_PACKETS_TO_SEND 0x3608ULL +#define UCIE_DEBUG_DATA 0x3610ULL #define UCIE_DEBUG_DATA_WIDTH 0x8ULL -#define UCIE_DEBUG_DRIVERCTL 0x3678ULL +#define UCIE_DEBUG_DRIVERCTL 0x3690ULL #define UCIE_DEBUG_DRIVERCTL_WIDTH 0x8ULL -#define UCIE_DEBUG_TXCTL_TILE 0x3698ULL -#define UCIE_DEBUG_TXCTL_SHUFFLER 0x36a0ULL +#define UCIE_DEBUG_TXCTL_TILE 0x36b0ULL +#define UCIE_DEBUG_TXCTL_SHUFFLER 0x36b8ULL #define UCIE_DEBUG_TXCTL_SHUFFLER_WIDTH 0x8ULL -#define UCIE_DEBUG_TX_TEST_STATE 0x37a0ULL -#define UCIE_DEBUG_TX_PACKETS_SENT 0x37a8ULL -#define UCIE_DEBUG_CLK_MUX_SEL 0x37b0ULL -#define UCIE_DEBUG_RX_LANE 0x37b8ULL -#define UCIE_DEBUG_RX_BIT 0x37c0ULL -#define UCIE_TX_VALID 0x37c8ULL -#define UCIE_RX_LFSR_VALID 0x37d0ULL -#define UCIE_CONTROLLER_SEL 0x37d8ULL -#define UCIE_MAINBAND_MODE 0x37e0ULL -#define UCIE_SIDEBAND_MODE 0x37e8ULL -#define UCIE_CREDIT_FLOW_ENABLE 0x37f0ULL -#define UCIE_TX_VALID_LANE_SEL 0x37f8ULL -#define UCIE_RX_VALID_LANE_SEL 0x3800ULL -#define UCIE_LAST_SEEN_TL_REQ 0x3808ULL -#define UCIE_SB_TX_PACKET 0x3810ULL -#define UCIE_SB_TX_SEND 0x3818ULL -#define UCIE_SB_TX_BUSY 0x3820ULL -#define UCIE_SB_RX_PACKET 0x3828ULL -#define UCIE_SB_RX_VALID 0x3830ULL -#define UCIE_SB_RX_POP 0x3838ULL -#define UCIE_SB_RX_OVERFLOW 0x3840ULL -#define UCIE_SB_RX_RST 0x3848ULL -#define UCIE_SB_TL_RX_OVERFLOW 0x3850ULL -#define UCIE_UCIE_LINK_RESET 0x3858ULL -#define UCIE_UCIE_PWR_GOOD 0x3860ULL -#define UCIE_UCIE_RETRY_TRAINING_AMT 0x3868ULL +#define UCIE_DEBUG_TX_TEST_STATE 0x37b8ULL +#define UCIE_DEBUG_TX_PACKETS_SENT 0x37c0ULL +#define UCIE_DEBUG_CLK_MUX_SEL 0x37c8ULL +#define UCIE_DEBUG_RX_LANE 0x37d0ULL +#define UCIE_DEBUG_RX_BIT 0x37d8ULL +#define UCIE_TX_VALID 0x37e0ULL +#define UCIE_RX_LFSR_VALID 0x37e8ULL +#define UCIE_CONTROLLER_SEL 0x37f0ULL +#define UCIE_MAINBAND_MODE 0x37f8ULL +#define UCIE_SIDEBAND_MODE 0x3800ULL +#define UCIE_CREDIT_FLOW_ENABLE 0x3808ULL +#define UCIE_TX_VALID_LANE_SEL 0x3810ULL +#define UCIE_RX_VALID_LANE_SEL 0x3818ULL +#define UCIE_LAST_SEEN_TL_REQ 0x3820ULL +#define UCIE_SB_TX_PACKET 0x3828ULL +#define UCIE_SB_TX_SEND 0x3830ULL +#define UCIE_SB_TX_BUSY 0x3838ULL +#define UCIE_SB_RX_PACKET 0x3840ULL +#define UCIE_SB_RX_VALID 0x3848ULL +#define UCIE_SB_RX_POP 0x3850ULL +#define UCIE_SB_RX_OVERFLOW 0x3858ULL +#define UCIE_SB_RX_RST 0x3860ULL +#define UCIE_SB_TL_RX_OVERFLOW 0x3868ULL +#define UCIE_UCIE_LINK_RESET 0x3870ULL +#define UCIE_UCIE_PWR_GOOD 0x3878ULL +#define UCIE_UCIE_RETRY_TRAINING_AMT 0x3880ULL +#define UCIE_PCIE_EXT_CAP_ID 0x4000ULL +#define UCIE_DVSEC_VENDOR_ID 0x4004ULL +#define UCIE_DVSEC_ID 0x4008ULL +#define UCIE_RAW_FORMAT 0x400cULL +#define UCIE_RAW_FORMAT_ENABLE 0x4010ULL +#define UCIE_RAW_FORMAT_ENABLED 0x4014ULL +#define UCIE_LINK_STATUS_CHANGED_INT_EN 0x4018ULL +#define UCIE_LOCATOR0_BIR 0x401cULL +#define UCIE_LOCATOR0_BLOCK_OFFSET_HI 0x4020ULL +#define UCIE_LOCATOR1_BIR 0x4024ULL +#define UCIE_LOCATOR1_BLOCK_OFFSET_HI 0x4028ULL +#define UCIE_MAILBOX_OPCODE 0x402cULL +#define UCIE_MAILBOX_ADDR_HI 0x4030ULL +#define UCIE_MAILBOX_DATA_LO 0x4034ULL +#define UCIE_MAILBOX_DATA_HI 0x4038ULL +#define UCIE_MAILBOX_TRIGGER 0x403cULL +#define UCIE_MAILBOX_STATUS 0x4040ULL +#define UCIE_VENDOR_ID 0x5000ULL +#define UCIE_VENDOR_REG_BLOCK_VERSION 0x5004ULL +#define UCIE_VENDOR_REG_BLOCK_LENGTH 0x5008ULL +#define UCIE_VENDOR_REG_BLOCK_RESERVED 0x500cULL +#define UCIE_UNCORR_ERR_STATUS 0x5010ULL +#define UCIE_UNCORR_ERR_MASK 0x5014ULL +#define UCIE_UNCORR_ERR_SEVERITY 0x5018ULL +#define UCIE_CORR_ERR_STATUS 0x501cULL +#define UCIE_CORR_ERR_MASK 0x5020ULL +#define UCIE_HEADER_LOG1_LO 0x5024ULL +#define UCIE_HEADER_LOG1_HI 0x5028ULL +#define UCIE_HL2_TIMEOUT_ENC 0x502cULL +#define UCIE_REMOTE_REG_ACCESS_THRESHOLD 0x5030ULL +#define UCIE_PARITY_LOG0_LO 0x5034ULL +#define UCIE_PARITY_LOG0_HI 0x5038ULL +#define UCIE_PARITY_LOG1_LO 0x503cULL +#define UCIE_PARITY_LOG1_HI 0x5040ULL +#define UCIE_PARITY_LOG2_LO 0x5044ULL +#define UCIE_PARITY_LOG2_HI 0x5048ULL +#define UCIE_PARITY_LOG3_LO 0x504cULL +#define UCIE_PARITY_LOG3_HI 0x5050ULL +#define UCIE_ADV_ADAPTER_CAP_LO 0x5054ULL +#define UCIE_ADV_ADAPTER_CAP_HI 0x5058ULL +#define UCIE_FIN_ADAPTER_CAP_LO 0x505cULL +#define UCIE_FIN_ADAPTER_CAP_HI 0x5060ULL +#define UCIE_ADV_CXL_CAP_LO 0x5064ULL +#define UCIE_ADV_CXL_CAP_HI 0x5068ULL +#define UCIE_FIN_CXL_CAP_LO 0x506cULL +#define UCIE_FIN_CXL_CAP_HI 0x5070ULL +#define UCIE_ADV_MULTIPROT_CAP_LO 0x5078ULL +#define UCIE_ADV_MULTIPROT_CAP_HI 0x507cULL +#define UCIE_FIN_MULTIPROT_CAP_LO 0x5080ULL +#define UCIE_FIN_MULTIPROT_CAP_HI 0x5084ULL +#define UCIE_ADV_CXL_CAP_STACK1_LO 0x5088ULL +#define UCIE_ADV_CXL_CAP_STACK1_HI 0x508cULL +#define UCIE_FIN_CXL_CAP_STACK1_LO 0x5090ULL +#define UCIE_FIN_CXL_CAP_STACK1_HI 0x5094ULL +#define UCIE_PHY_CAP_RSVD 0x6000ULL +#define UCIE_PHY_CTRL_RSVD 0x6004ULL +#define UCIE_PHY_STATUS_RSVD 0x6008ULL +#define UCIE_INIT_CONTROL 0x600cULL +#define UCIE_RLT_CTRL 0x6100ULL +#define UCIE_MODULE3_LANE_REPAIR_ID_RSVD_HI 0x6104ULL +#define UCIE_RUNTIME_LINK_TEST_BUSY 0x6108ULL +#define UCIE_NULL_EXT_CAP 0x6200ULL +#define UCIE_TS1_DATA_PATTERN_M0 0x6010ULL +#define UCIE_TS2_IDLE_COUNT_M0 0x6020ULL +#define UCIE_TS3_LANE_MASK_LO_M0 0x6030ULL +#define UCIE_TS3_LANE_MASK_HI_M0 0x6034ULL +#define UCIE_TS4_REPAIR_LANE_MASK_M0 0x6050ULL +#define UCIE_CURRENT_LANE_MAP_LO_M0 0x6060ULL +#define UCIE_CURRENT_LANE_MAP_HI_M0 0x6064ULL +#define UCIE_ERR_LOG0_STATE_NM0 0x6080ULL +#define UCIE_ERR_LOG1_STATE_NM3_M0 0x6090ULL +#define UCIE_VENDOR_REG_BLOCK_RSVD 0x700cULL +#define UCIE_VENDOR_DEBUG_UNLOCK 0x7010ULL +#define UCIE_VENDOR_FORCE_LINK_ACTIVE 0x7014ULL +#define UCIE_VENDOR_TS_OVERRIDE_EN 0x7018ULL +#define UCIE_MAIN_CLK_SEL 0x10000ULL +#define UCIE_PLL8_EN 0x10008ULL +#define UCIE_PLL12_EN 0x10010ULL +#define UCIE_PLL16_EN 0x10018ULL +#define UCIE_TX_CLK_DIV 0x10020ULL +#define UCIE_TX_CLK_PHASE 0x10028ULL +#define UCIE_DIG_CLK_DIV 0x10030ULL +#define UCIE_DIG_CLK_BYPASS_EN 0x10038ULL +#define UCIE_CLK_PHASE_SEL 0x10040ULL +#define UCIE_CLK_GATE_EN 0x10048ULL +#define UCIE_RX_CLK_GATE_EN 0x10050ULL +#define UCIE_FREQ_SEL_AUTO_EN 0x10058ULL +#define UCIE_FREQ_SEL_OBSERVED 0x10060ULL +#define UCIE_SB_CLK_DIV 0x10068ULL +#define UCIE_SB_CLK_BYPASS_EN 0x10070ULL +#define UCIE_RX_CLK_FROM_TX_Q 0x10078ULL +#define UCIE_CLK_CFG_APPLY 0x10080ULL +#define UCIE_CLK_CFG_BUSY 0x10088ULL +#define UCIE_CLK_CFG_UNGATE_SRC 0x10090ULL +#define UCIE_CLK_CFG_UNGATE_DELAY 0x10098ULL +#define UCIE_CLK_CFG_UNGATE_REQ 0x100a0ULL +#define UCIE_PLL_LOCK_OBSERVED 0x100a8ULL +#define UCIE_UCIE_RST 0x100b0ULL +#define UCIE_RATE_CFG 0x10100ULL +#define UCIE_RATE_CFG_WIDTH 0x8ULL // === Constants === #define UCIE_TX_TEST_STATE_IDLE 0x0ULL @@ -131,11 +234,35 @@ #define UCIE_DEFAULT_TRACK 0x55555555ULL #define UCIE_ENABLE_DRIVER_CTL 0x3ffeULL #define UCIE_ENABLE_TX_CTL 0x1fff000000000ULL +#define UCIE_TX_CTL_DELAY_LSB 0x0ULL +#define UCIE_TRAIN_LFSR_SEED 0x123456789abcdefULL +#define UCIE_TRAIN_DATA_LANES 0x10ULL +#define UCIE_TRAIN_VALID_LANE 0x10ULL +#define UCIE_TRAIN_SCORE_LANES 0x11ULL +#define UCIE_RATE_CFG_MAIN_CLK_SEL_LSB 0x8ULL +#define UCIE_RATE_CFG_TX_CLK_DIV_LSB 0x6ULL +#define UCIE_RATE_CFG_DIG_CLK_DIV_LSB 0x3ULL +#define UCIE_TRAIN_EYE_FINE_POINTS 0x4ULL +#define UCIE_TRAIN_EYE_FINE_STEP 0x10ULL +#define UCIE_TRAIN_EYE_DIVS 0x3ULL +#define UCIE_TRAIN_GLOBAL_CODES 0x10ULL +#define UCIE_TRAIN_GLOBAL_STEP 0x4ULL +#define UCIE_TRAIN_LOCAL_CODES 0x10ULL +#define UCIE_TRAIN_LOCAL_STEP 0x2ULL +#define UCIE_TRAIN_VREF_CODES 0x10ULL +#define UCIE_TRAIN_VREF_STEP 0x8ULL +#define UCIE_TRAIN_PACKETS 0x10ULL +#define UCIE_TRAIN_SLIP_RATIO 0x4ULL +#define UCIE_CLK_UNGATE_SRC_PLL_LOCK 0x0ULL +#define UCIE_CLK_UNGATE_SRC_MMIO 0x1ULL +#define UCIE_CLK_UNGATE_SRC_DELAY 0x2ULL // === Helper functions === static inline void reset_fsms(uintptr_t base) { - reg_write64(base + UCIE_TX_RST, 0x1ULL); - reg_write64(base + UCIE_RX_RST, 0x1ULL); + reg_write64(base + UCIE_TX_DATAPATH_RST, 0x1ULL); + reg_write64(base + UCIE_RX_DATAPATH_RST, 0x1ULL); + reg_write64(base + UCIE_TX_FSM_RST, 0x1ULL); + reg_write64(base + UCIE_RX_FSM_RST, 0x1ULL); reg_write64(base + UCIE_DEBUG_TX_FSM_RST, 0x1ULL); assert(reg_read64(base + UCIE_TX_TEST_STATE) == (UCIE_TX_TEST_STATE_IDLE)); assert(reg_read64(base + UCIE_TX_PACKETS_SENT) == (0x0ULL)); @@ -150,7 +277,77 @@ static inline void write_rxctl(uintptr_t base, uint64_t lane, uint64_t ofs, uint reg_write64(base + UCIE_RXCTL + lane * UCIE_RXCTL_WIDTH + ofs, v); } +static inline void set_clk_gate(uintptr_t base, uint64_t en) { + reg_write64(base + UCIE_CLK_GATE_EN, en); +} +static inline void set_rate_cfg(uintptr_t base, uint64_t rate, uint64_t main_sel, uint64_t tx_div, uint64_t dig_div, uint64_t pll_en) { + reg_write64(base + UCIE_RATE_CFG + rate * UCIE_RATE_CFG_WIDTH, ((main_sel << UCIE_RATE_CFG_MAIN_CLK_SEL_LSB) | (tx_div << UCIE_RATE_CFG_TX_CLK_DIV_LSB) | (dig_div << UCIE_RATE_CFG_DIG_CLK_DIV_LSB) | pll_en)); +} +static inline void set_freq_sel_auto(uintptr_t base, uint64_t en) { + reg_write64(base + UCIE_FREQ_SEL_AUTO_EN, en); +} +static inline void apply_clk_cfg(uintptr_t base) { + reg_write64(base + UCIE_CLK_CFG_APPLY, 0x1ULL); + for (int w = 0; w < 256; w++) { + uint64_t busy; + busy = reg_read64(base + UCIE_CLK_CFG_BUSY); + if (busy == 0) { + break; + } + } +} +static inline void set_ungate_src(uintptr_t base, uint64_t src, uint64_t delay) { + reg_write64(base + UCIE_CLK_CFG_UNGATE_SRC, src); + reg_write64(base + UCIE_CLK_CFG_UNGATE_DELAY, delay); +} +static inline void release_clk_gate(uintptr_t base) { + reg_write64(base + UCIE_CLK_CFG_UNGATE_REQ, 0x1ULL); +} +static inline void reset_ucie(uintptr_t base) { + reg_write64(base + UCIE_UCIE_RST, 0x1ULL); + reg_write64(base + UCIE_UCIE_RST, 0x0ULL); +} +static inline void reset_dividers(uintptr_t base) { + reg_write64(base + UCIE_TX_DIVIDER_RST, 0x1ULL); + reg_write64(base + UCIE_RX_DIVIDER_RST, 0x1ULL); + reg_write64(base + UCIE_TX_DIVIDER_RST, 0x0ULL); + reg_write64(base + UCIE_RX_DIVIDER_RST, 0x0ULL); +} +static inline void set_main_clk(uintptr_t base, uint64_t src, uint64_t div) { + reg_write64(base + UCIE_MAIN_CLK_SEL, src); + reg_write64(base + UCIE_TX_CLK_DIV, div); + reg_write64(base + UCIE_CLK_GATE_EN, 0x1ULL); + apply_clk_cfg(base); +} +static inline void set_tx_phase(uintptr_t base, uint64_t half_cycles) { + reg_write64(base + UCIE_CLK_GATE_EN, 0x0ULL); + reg_write64(base + UCIE_TX_CLK_PHASE, half_cycles); + reg_write64(base + UCIE_CLK_GATE_EN, 0x1ULL); +} +static inline void use_internal_clk(uintptr_t base, uint64_t dig_div) { + reg_write64(base + UCIE_PLL8_EN, 0x1ULL); + reg_write64(base + UCIE_PLL12_EN, 0x1ULL); + reg_write64(base + UCIE_PLL16_EN, 0x1ULL); + reg_write64(base + UCIE_DIG_CLK_DIV, dig_div); + reg_write64(base + UCIE_DIG_CLK_BYPASS_EN, 0x0ULL); + apply_clk_cfg(base); +} +static inline void set_rx_clk_gate(uintptr_t base, uint64_t en) { + reg_write64(base + UCIE_RX_CLK_GATE_EN, en); +} +static inline void set_global_delay(uintptr_t base, uint64_t taps) { + reg_write64(base + UCIE_CLK_PHASE_SEL, ((0x1ULL << taps) - 0x1ULL)); +} +static inline void set_tx_delay(uintptr_t base, uint64_t lane, uint64_t taps) { + write_txctl(base, lane, UCIE_TXCTL_TILE_OFS, (UCIE_ENABLE_TX_CTL | (((0x1ULL << taps) - 0x1ULL) << UCIE_TX_CTL_DELAY_LSB))); +} + +static inline void set_rx_vref(uintptr_t base, uint64_t lane, uint64_t code) { + write_rxctl(base, lane, UCIE_RXCTL_VREF_SEL_OFS, code); +} + static inline void setup_ucie(uintptr_t base) { + reset_ucie(base); for (int lane = 0; lane < 21; lane++) { write_txctl(base, lane, UCIE_TXCTL_TILE_OFS, UCIE_ENABLE_TX_CTL); write_rxctl(base, lane, UCIE_RXCTL_ZEN_OFS, 0x1ULL); @@ -164,10 +361,72 @@ static inline void setup_ucie(uintptr_t base) { reg_write64(base + UCIE_DEBUG_DRIVERCTL + 8 * i, UCIE_ENABLE_DRIVER_CTL); } reg_write64(base + UCIE_DEBUG_TXCTL_TILE, UCIE_ENABLE_TX_CTL); + set_clk_gate(base, 0x0ULL); + reset_dividers(base); + set_clk_gate(base, 0x1ULL); reset_fsms(base); reg_write64(base + UCIE_CONTROLLER_SEL, UCIE_CONTROLLER_SEL_PHYTEST); reg_write64(base + UCIE_MAINBAND_MODE, UCIE_BAND_MODE_MANUAL); reg_write64(base + UCIE_SIDEBAND_MODE, UCIE_BAND_MODE_MANUAL); } +static inline void setup_ucie_digital(uintptr_t base) { + set_clk_gate(base, 0x0ULL); + set_global_delay(base, 0x1dULL); + reset_dividers(base); + set_clk_gate(base, 0x1ULL); + for (int lane = 0; lane < 20; lane++) { + write_txctl(base, lane, UCIE_TXCTL_TILE_OFS, UCIE_ENABLE_TX_CTL); + } + for (int lane = 0; lane < 18; lane++) { + write_rxctl(base, lane, UCIE_RXCTL_ZEN_OFS, 0x1ULL); + write_rxctl(base, lane, UCIE_RXCTL_ZCTL_OFS, 0x0ULL); + } + reg_write64(base + UCIE_CONTROLLER_SEL, UCIE_CONTROLLER_SEL_UCIE); + uint64_t linkControl; + linkControl = reg_read64(base + UCIE_RAW_FORMAT_ENABLE); + reg_write64(base + UCIE_RAW_FORMAT_ENABLE, linkControl | 0x401ULL); + reg_write64(base + UCIE_UNCORR_ERR_MASK, 0x0ULL); + reg_write64(base + UCIE_CORR_ERR_MASK, 0x0ULL); + while (1) { + uint64_t linkStatus; + linkStatus = reg_read64(base + UCIE_RAW_FORMAT_ENABLED); + if ((linkStatus >> 0xfULL) & 0x1ULL) { + break; + } + } +} + +static inline void seed_lfsrs(uintptr_t base) { + for (int i = 0; i < 19; i++) { + reg_write64(base + UCIE_TX_LFSR_SEED + i * UCIE_TX_LFSR_SEED_WIDTH, UCIE_TRAIN_LFSR_SEED); + reg_write64(base + UCIE_RX_LFSR_SEED + i * UCIE_RX_LFSR_SEED_WIDTH, UCIE_TRAIN_LFSR_SEED); + } +} + +static inline void run_lfsr(uintptr_t base, uint64_t packets) { + reset_fsms(base); + for (int s = 0; s < 64; s++) { + uint64_t settle_w; + settle_w = reg_read64(base + UCIE_RX_IDLE_WORDS_OBSERVED); + if (settle_w >= 4) { + break; + } + } + reg_write64(base + UCIE_TEST_TARGET, UCIE_TEST_TARGET_MAINBAND); + reg_write64(base + UCIE_TX_TEST_MODE, UCIE_TX_TEST_MODE_LFSR); + reg_write64(base + UCIE_TX_DATA_MODE, UCIE_DATA_MODE_FINITE); + reg_write64(base + UCIE_RX_DATA_MODE, UCIE_DATA_MODE_FINITE); + reg_write64(base + UCIE_RX_PACKETS_TO_RECEIVE, packets); + reg_write64(base + UCIE_TX_PACKETS_TO_SEND, packets); + reg_write64(base + UCIE_TX_EXECUTE, 0x1ULL); + for (int w = 0; w < 16; w++) { + uint64_t r; + r = reg_read64(base + UCIE_RX_PACKETS_RECEIVED); + if (r >= packets) { + break; + } + } +} + #endif diff --git a/src/GenUcieHeader.scala b/src/GenUcieHeader.scala index cba06f1..12c67d8 100644 --- a/src/GenUcieHeader.scala +++ b/src/GenUcieHeader.scala @@ -29,19 +29,21 @@ object GenUcieHeader { def render(): String = { val ports = uciePorts // The header holds one register layout, so every port has to agree on - // everything that layout depends on. Address and moduleId do not reach it: - // the offsets are relative to each port's own MMIO base, and the moduleId - // only names modules. + // everything that layout depends on. Address, moduleId and the clock + // distribution netlist do not reach it: the offsets are relative to each + // port's own MMIO base, the moduleId only names modules, and the netlist is + // physical design. val canonical = ports.map( _.copy( address = ports.head.address, - moduleId = ports.head.moduleId + moduleId = ports.head.moduleId, + clkDistLayout = ports.head.clkDistLayout ) ) require( canonical.forall(_ == canonical.head), "UCIe ports must share a register layout, but their parameters differ " + - s"beyond address and moduleId: ${canonical.distinct.mkString("\n")}" + s"beyond address, moduleId and clock distribution: ${canonical.distinct.mkString("\n")}" ) edu.berkeley.cs.uciedigital.tilelink.GenUcieHeader .render(ports.head, regenCommand) diff --git a/src/Iris.scala b/src/Iris.scala index 73ef937..698783c 100644 --- a/src/Iris.scala +++ b/src/Iris.scala @@ -44,6 +44,7 @@ class JTAGChipIO(hasReset: Boolean) extends Bundle { class IrisSystem(implicit p: Parameters) extends edu.berkeley.cs.chippy.ChippySystem with testchipip.soc.CanHaveChipletRouting + with CanHaveUcieClkRegs // UCIe clock registers, which the router can't attach with testchipip.soc.CanHaveSubsystemInjectors // Enables the subsystem injector API with testchipip.soc.CanHaveSwitchableOffchipBus // Enables optional off-chip-bus with interface-switch with testchipip.serdes.CanHavePeripheryTLSerial @@ -478,21 +479,34 @@ class IrisConfig(sim: Boolean = false) routerParams = testchipip.soc.OffchipRouterParams(tableEntries = 4), ports = Seq( // PD hardens the two UCIe links together, so UcieComplexPort puts - // both instances inside one UcieComplex module. They are identical - // logic and share a `moduleId`, so they dedup into a single UcieTL - // underneath it; splitting them again is a matter of giving one its - // own `moduleId`. + // both instances inside one UcieComplex module. Their PHYs differ + // in their lane clock distribution: the analog IP's clock DEF gives + // each link a buffered clock tree laid out for its own bump field -- + // link 0's in the canonical orientation, link 1's turned 90 degrees + // -- and the netlist of that tree is what its PHY instantiates + // outside simulation. So each link is its own module, `moduleId` 0 + // and 1. Each link also has its own high-speed and digital bypass + // clock bumps. UcieComplexPort(edu.berkeley.cs.uciedigital.tilelink.UcieTLParams( address = 0x200000, managerWhere = SBUS, numLanes = 16, - includeDefaultModels = true + includeDefaultModels = true, + sim = sim, + clkDistLayout = + if (sim) edu.berkeley.cs.uciedigital.phy.macros.clocking.ClkDistLayout.Behavioral + else edu.berkeley.cs.uciedigital.phy.macros.clocking.ClkDistLayout.Buffered("r0") )), UcieComplexPort(edu.berkeley.cs.uciedigital.tilelink.UcieTLParams( address = 0x208000, managerWhere = SBUS, numLanes = 16, - includeDefaultModels = true + includeDefaultModels = true, + sim = sim, + moduleId = 1, + clkDistLayout = + if (sim) edu.berkeley.cs.uciedigital.phy.macros.clocking.ClkDistLayout.Behavioral + else edu.berkeley.cs.uciedigital.phy.macros.clocking.ClkDistLayout.Buffered("r90") )) ))) ++ new WithIrisUncore(sim) diff --git a/src/TinyIris.scala b/src/TinyIris.scala index 94a0de6..a8b60da 100644 --- a/src/TinyIris.scala +++ b/src/TinyIris.scala @@ -242,13 +242,15 @@ class TinyIrisConfig(sim: Boolean = false) address = 0x200000, managerWhere = SBUS, numLanes = 16, - includeDefaultModels = true + includeDefaultModels = true, + sim = sim ), edu.berkeley.cs.uciedigital.tilelink.UcieTLParams( address = 0x208000, managerWhere = SBUS, numLanes = 16, - includeDefaultModels = true + includeDefaultModels = true, + sim = sim ) ))) ++ diff --git a/src/UcieComplex.scala b/src/UcieComplex.scala index 820782f..e758e99 100644 --- a/src/UcieComplex.scala +++ b/src/UcieComplex.scala @@ -2,9 +2,11 @@ package edu.berkeley.cs.iris import org.chipsalliance.cde.config.Parameters import freechips.rocketchip.diplomacy._ -import freechips.rocketchip.subsystem.TLBusWrapperLocation -import edu.berkeley.cs.uciedigital.tilelink.UcieTLParams +import freechips.rocketchip.subsystem.{BaseSubsystem, TLBusWrapperLocation} +import freechips.rocketchip.tilelink.{TLBuffer, TLWidthWidget} +import edu.berkeley.cs.uciedigital.tilelink.{UcieChipletLink, UcieTLParams} import testchipip.soc.{ + CanHaveChipletRouting, ChipletLinkParams, ChipletLinkWrapper, ChipletLinkWrapperInstantiationLike, @@ -81,3 +83,40 @@ object UciePort { .map(_.ports.collect { case UciePort(u) => u }) .getOrElse(Nil) } + +/** Attaches the part of each UCIe link that the chiplet router can't. + * + * The router gives every port one control node, coupled to its control bus, + * and one clock. A UCIe link has two register blocks: the main one, on the + * clock its PHY makes, and the clock register block, which sets that clock up + * and so runs on the chip's. Only the main one goes through the router. This + * couples the clock register block to the same bus the same way, and clocks it + * from that bus, so its register port needs no crossing. + * + * The links are found by walking the subsystem's children, since the router + * keeps its ports to itself. Extending [[CanHaveChipletRouting]] makes sure + * they exist by the time this runs. + */ +trait CanHaveUcieClkRegs extends CanHaveChipletRouting { this: BaseSubsystem => + p(ChipletRoutingKey).foreach { params => + def links(lm: LazyModule): Seq[UcieChipletLink] = + lm.getChildren.reverse.flatMap { + case link: UcieChipletLink => Seq(link) + case child => links(child) + } + val ucieLinks = links(this) + require( + ucieLinks.size == UciePort.all(p).size, + s"found ${ucieLinks.size} UCIe links under the subsystem, but the " + + s"chiplet router has ${UciePort.all(p).size} UCIe ports" + ) + + val cbus = locateTLBusWrapper(params.controlBusWhere) + ucieLinks.foreach { link => + link.ucie.chipDigitalClockNode := cbus.fixedClockNode + cbus.coupleTo(s"${link.name}_clk_control") { + link.ucie.clkRegNode := TLWidthWidget(cbus.beatBytes) := TLBuffer() := _ + } + } + } +} diff --git a/test/src/IrisSpec.scala b/test/src/IrisSpec.scala index da209de..55a8e1f 100644 --- a/test/src/IrisSpec.scala +++ b/test/src/IrisSpec.scala @@ -156,13 +156,30 @@ class TestHarness(nChips: Int, binaryPaths: Seq[Path], plusArgs: Seq[Seq[String] ucieBypassClockSource.io.gate := false.B ucieBypassClock := ucieBypassClockSource.io.clk - val ucieDigitalBypassFreqMHz = 800 + val ucieDigitalBypassFreqMHz = 500 // previously was 800 val ucieDigitalBypassClock = Wire(Clock()) val ucieDigitalBypassClockSource = Module(new ClockSourceAtFreqMHz(ucieDigitalBypassFreqMHz)) ucieDigitalBypassClockSource.io.power := true.B ucieDigitalBypassClockSource.io.gate := false.B ucieDigitalBypassClock := ucieDigitalBypassClockSource.io.clk + // The sideband runs off its own bypass clock, at the rate ucie's own + // TileLinkSpec harness uses. + val ucieSidebandBypassFreqMHz = 800 + val ucieSidebandBypassClock = Wire(Clock()) + val ucieSidebandBypassClockSource = Module(new ClockSourceAtFreqMHz(ucieSidebandBypassFreqMHz)) + ucieSidebandBypassClockSource.io.power := true.B + ucieSidebandBypassClockSource.io.gate := false.B + ucieSidebandBypassClock := ucieSidebandBypassClockSource.io.clk + + // Reference for the clocking tile's PLLs. + val ucieRefFreqMHz = 100 + val ucieRefClock = Wire(Clock()) + val ucieRefClockSource = Module(new ClockSourceAtFreqMHz(ucieRefFreqMHz)) + ucieRefClockSource.io.power := true.B + ucieRefClockSource.io.gate := false.B + ucieRefClock := ucieRefClockSource.io.clk + implicit def view[A <: Data, B <: Data] : DataView[testchipip.tsi.TSIIO, TSIIO] = @@ -223,11 +240,13 @@ class TestHarness(nChips: Int, binaryPaths: Seq[Path], plusArgs: Seq[Seq[String] when(dtm_success || success) { chipSuccessReg := true.B } chipSuccesses(chipId) := chipSuccessReg - // The PHY bumps carry a single-ended mainband bypass clock; the PLL - // reference pair and its RDAC bias are no longer bumps. + // The PHY bumps carry single-ended mainband, digital and sideband bypass + // clocks plus the single-ended PLL reference. Seq(chiptop.c2c_ucie0, chiptop.c2c_ucie1).foreach { ucie => ucie.phy.bypassClk := ucieBypassClock ucie.phy.digitalBypassClk := ucieDigitalBypassClock + ucie.phy.sidebandBypassClk := ucieSidebandBypassClock + ucie.phy.refClk := ucieRefClock } Seq(chiptop.c2c_ucie0, chiptop.c2c_ucie1) @@ -440,6 +459,26 @@ class IrisSpec extends AnyFunSpec { ) } + it("should run ucie digital loopback test") { + implicit val p = new IrisConfig(sim = true) + val workDir = Utils.buildRoot / "Iris_should_run_ucie_digital_loopback_test" + + val chipid0 = 1 + val chipidReg = p(ChipletRoutingKey).get.routerParams.tableAddress + p(ChipletRoutingKey).get.routerParams.tableEntries * 32 + val chip0PlusArgs = Seq( + f"+init_write=0x${chipidReg}%08x:0x${chipid0}%08x", + ) + + Utils.simulateTopWithBinaries( + workDir, + nChips = 1, + binaryPaths = Seq(Utils.root / "software/ucie-digital-loopback.riscv"), + plusArgs = Seq(chip0PlusArgs), + fast = true, + debug = true + ) + } + it("should run tacit always trace workload") { implicit val p = new IrisConfig(sim = true) val workDir = Utils.buildRoot / "Iris_should_run_tacit_always_trace" diff --git a/ucie b/ucie index caf0daf..6155d0a 160000 --- a/ucie +++ b/ucie @@ -1 +1 @@ -Subproject commit caf0daf1135f5b87225fa4903fcc3dfb87863de5 +Subproject commit 6155d0a33ce188419ba41ba9e13f9bf80fc60489