cndm: Add board control logic to KCU105

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2026-03-17 17:49:47 -07:00
parent f69e6a8c12
commit b3f9b899cb
4 changed files with 177 additions and 5 deletions

View File

@@ -19,6 +19,7 @@ TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
SYN_FILES = $(RTL_DIR)/fpga.sv
SYN_FILES += $(RTL_DIR)/fpga_core.sv
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
SYN_FILES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_brd_ctrl_i2c.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/taxi_eth_mac_1g_fifo.f
SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f

View File

@@ -354,6 +354,14 @@ stat_mux_inst (
);
// I2C
wire [1:0] i2c_scl_o_int;
wire [1:0] i2c_sda_o_int;
assign i2c_scl_o = &i2c_scl_o_int;
assign i2c_sda_o = &i2c_sda_o_int;
wire i2c_scl_i_int = i2c_scl_i & i2c_scl_o;
wire i2c_sda_i_int = i2c_sda_i & i2c_sda_o;
taxi_xfcp_mod_i2c_master #(
.XFCP_EXT_ID_STR("I2C"),
.DEFAULT_PRESCALE(16'(125000000/200000/4))
@@ -371,12 +379,43 @@ xfcp_mod_i2c_inst (
/*
* I2C interface
*/
.i2c_scl_i(i2c_scl_i),
.i2c_scl_o(i2c_scl_o),
.i2c_sda_i(i2c_sda_i),
.i2c_sda_o(i2c_sda_o)
.i2c_scl_i(i2c_scl_i_int),
.i2c_scl_o(i2c_scl_o_int[0]),
.i2c_sda_i(i2c_sda_i_int),
.i2c_sda_o(i2c_sda_o_int[0])
);
localparam logic OPTIC_EN = 1'b1;
localparam OPTIC_CNT = 2;
localparam logic EEPROM_EN = 1'b1;
localparam EEPROM_IDX = OPTIC_EN ? OPTIC_CNT : 0;
localparam logic MAC_EEPROM_EN = EEPROM_EN;
localparam MAC_EEPROM_IDX = EEPROM_IDX;
localparam MAC_EEPROM_OFFSET = 32;
localparam MAC_COUNT = OPTIC_CNT;
localparam logic MAC_FROM_BASE = 1'b1;
localparam logic SN_EEPROM_EN = EEPROM_EN;
localparam SN_EEPROM_IDX = EEPROM_IDX;
localparam SN_EEPROM_OFFSET = 0;
localparam SN_LEN = 32;
localparam logic PLL_EN = 1'b1;
localparam PLL_IDX = EEPROM_IDX + (EEPROM_EN ? 1 : 0);
localparam logic MUX_EN = 1'b1;
localparam MUX_CNT = 2;
localparam logic [MUX_CNT-1:0][6:0] MUX_I2C_ADDR = {7'h75, 7'h74};
localparam DEV_CNT = PLL_IDX + (PLL_EN ? 1 : 0);
localparam logic [DEV_CNT-1:0][6:0] DEV_I2C_ADDR = {7'h5D, 7'h54, 7'h50, 7'h50};
localparam logic [DEV_CNT-1:0][31:0] DEV_ADDR_CFG = {32'h00_00_0000, 32'h00_00_0040, 32'h7e_7f_0070, 32'h7e_7f_0070};
localparam logic [DEV_CNT-1:0][MUX_CNT-1:0][7:0] DEV_MUX_MASK = {{8'h00, 8'h01}, {8'h07, 8'h00}, {8'h00, 8'h08}, {8'h00, 8'h04}};
localparam I2C_PRESCALE = SIM ? 2 : 250000/(400*4);
taxi_axis_if #(
.DATA_W(32),
.KEEP_EN(1),
@@ -386,6 +425,60 @@ taxi_axis_if #(
.USER_W(1)
) axis_brd_ctrl_cmd(), axis_brd_ctrl_rsp();
cndm_brd_ctrl_i2c #(
.OPTIC_EN(OPTIC_EN),
.OPTIC_CNT(OPTIC_CNT),
.EEPROM_EN(EEPROM_EN),
.EEPROM_IDX(EEPROM_IDX),
.MAC_EEPROM_EN(MAC_EEPROM_EN),
.MAC_EEPROM_IDX(MAC_EEPROM_IDX),
.MAC_EEPROM_OFFSET(MAC_EEPROM_OFFSET),
.MAC_COUNT(MAC_COUNT),
.MAC_FROM_BASE(MAC_FROM_BASE),
.SN_EEPROM_EN(SN_EEPROM_EN),
.SN_EEPROM_IDX(SN_EEPROM_IDX),
.SN_EEPROM_OFFSET(SN_EEPROM_OFFSET),
.SN_LEN(SN_LEN),
.PLL_EN(PLL_EN),
.PLL_IDX(PLL_IDX),
.MUX_EN(MUX_EN),
.MUX_CNT(MUX_CNT),
.MUX_I2C_ADDR(MUX_I2C_ADDR),
.DEV_CNT(DEV_CNT),
.DEV_I2C_ADDR(DEV_I2C_ADDR),
.DEV_ADDR_CFG(DEV_ADDR_CFG),
.DEV_MUX_MASK(DEV_MUX_MASK),
.I2C_PRESCALE(I2C_PRESCALE)
)
board_ctrl_i2c_ch_inst (
.clk(pcie_clk),
.rst(pcie_rst),
/*
* Board control command interface
*/
.s_axis_cmd(axis_brd_ctrl_cmd),
.m_axis_rsp(axis_brd_ctrl_rsp),
/*
* I2C interface
*/
.i2c_scl_i(i2c_scl_i_int),
.i2c_scl_o(i2c_scl_o_int[1]),
.i2c_sda_i(i2c_sda_i_int),
.i2c_sda_o(i2c_sda_o_int[1]),
.dev_sel(),
.dev_rst()
);
// BASE-T PHY
assign phy_reset_n = !rst_125mhz;
@@ -841,7 +934,7 @@ cndm_micro_pcie_us #(
// Structural configuration
.PORTS($size(axis_sfp_tx)),
.BRD_CTRL_EN(1'b0),
.BRD_CTRL_EN(1'b1),
.SYS_CLK_PER_NS_NUM(4),
.SYS_CLK_PER_NS_DEN(1),

View File

@@ -25,6 +25,7 @@ TOPLEVEL = $(COCOTB_TOPLEVEL)
VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_micro_pcie_us.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/cndm/rtl/cndm_brd_ctrl_i2c.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/eth/rtl/taxi_eth_mac_1g_fifo.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f

View File

@@ -11,6 +11,7 @@ Authors:
import logging
import os
import struct
import sys
import cocotb_test.simulator
@@ -23,6 +24,7 @@ from cocotbext.axi import AxiStreamBus
from cocotbext.eth import GmiiFrame, GmiiSource, GmiiSink
from cocotbext.eth import XgmiiFrame
from cocotbext.uart import UartSource, UartSink
from cocotbext.i2c import I2cMemory
from cocotbext.pcie.core import RootComplex
from cocotbext.pcie.xilinx.us import UltraScalePcieDevice
@@ -297,9 +299,61 @@ class TB:
gbx_cfg=gbx_cfg
))
# UART
self.uart_source = UartSource(dut.uart_rxd, baud=921600, bits=8, stop_bits=1)
self.uart_sink = UartSink(dut.uart_txd, baud=921600, bits=8, stop_bits=1)
# I2C
self.i2c_eeprom = I2cMemory(sda=dut.i2c_sda_o, sda_o=dut.i2c_sda_i,
scl=dut.i2c_scl_o, scl_o=dut.i2c_scl_i, addr=0x54, size=256)
self.sfp0 = I2cMemory(sda=dut.i2c_sda_o, sda_o=dut.i2c_sda_i,
scl=dut.i2c_scl_o, scl_o=dut.i2c_scl_i, addr=0x50, size=256)
self.si570 = I2cMemory(sda=dut.i2c_sda_o, sda_o=dut.i2c_sda_i,
scl=dut.i2c_scl_o, scl_o=dut.i2c_scl_i, addr=0x5D, size=256)
self.i2c_eeprom.write_mem(0, bytes.fromhex("""
37 35 37 35 31 39 32 37 31 37 33 32 2d 36 39 39
39 36 20 20 20 20 20 20 20 20 20 20 20 20 20 20
00 0a 35 03 72 c9 00 00 00 00 00 00 00 00 00 00
54 53 53 30 31 36 35 2d 30 32 20 20 20 20 20 20
5b 31 31 31 31 31 31 31 31 31 5d 20 20 20 20 20
57 65 64 2c 20 31 36 20 41 75 67 20 32 30 31 37
31 30 3a 33 35 3a 35 36 2b 30 38 30 30 20 20 20
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
4b 43 55 31 30 35 20 20 20 20 20 20 20 20 20 20
31 2e 31 20 20 20 20 20 20 20 20 20 20 20 20 20
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
"""))
self.sfp0.write_mem(0, bytes.fromhex("""
03 04 21 00 00 00 00 00 04 00 00 00 67 00 00 00
00 00 03 00 41 6d 70 68 65 6e 6f 6c 20 20 20 20
20 20 20 20 00 41 50 48 35 37 31 35 34 30 30 30
32 20 20 20 20 20 20 20 4b 20 20 20 01 00 00 f7
00 00 00 00 41 50 46 30 39 34 38 30 30 32 30 32
37 39 20 20 30 39 31 31 32 34 20 20 00 00 00 c1
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00
""" + " ff"*128))
self.si570.write_mem(0, bytes.fromhex("""
4f 02 32 a1 3d 20 00 01 c2 bb ff 84 82 07 c2 c0
00 00 00 00 c2 c0 00 00 00 07 c2 c0 00 00 00 0c
b9 09 80 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20 7f 86 81 7b 81 03 00 10 08 00 00 00 00 02 bb
ff 84 82 00 00 00 62 00 00 00 00 00 00 00 00 00
"""))
dut.phy_gmii_clk_en.setimmediatevalue(1)
dut.btnu.setimmediatevalue(0)
@@ -360,6 +414,28 @@ async def run_test(dut):
tb.log.info("Init complete")
tb.log.info("Read MAC address")
rsp = await driver.exec_cmd(struct.pack("<HHLHHLbbbbLLL",
0, # rsvd
cndm.CNDM_CMD_OP_HWID, # opcode
0x00000000, # flags
0, # index
cndm.CNDM_CMD_BRD_OP_HWID_MAC_RD, # board op
0, # flags
0, # rsvd
0, # dev addr offset
0, # bank
0, # page
0, # addr
0, # len
0, # rsvd
))
print(rsp)
tb.log.info("MAC address: %s", ':'.join(x.hex() for x in struct.unpack_from('6c', rsp, 32+2)))
tb.log.info("Wait for block lock")
for k in range(1200):
await RisingEdge(tb.dut.clk_125mhz)
@@ -459,6 +535,7 @@ def test_fpga_core(request):
os.path.join(tests_dir, f"{toplevel}.sv"),
os.path.join(rtl_dir, f"{dut}.sv"),
os.path.join(taxi_src_dir, "cndm", "rtl", "cndm_micro_pcie_us.f"),
os.path.join(taxi_src_dir, "cndm", "rtl", "cndm_brd_ctrl_i2c.f"),
os.path.join(taxi_src_dir, "eth", "rtl", "taxi_eth_mac_1g_fifo.f"),
os.path.join(taxi_src_dir, "eth", "rtl", "us", "taxi_eth_mac_25g_us.f"),
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_if_uart.f"),