mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: add I2C support to the SoC topology and formal verification
- Updated to include I2C1 in IRQ bindings. - Modified to increase IRQ group width and add I2C1 interrupt. - Enhanced to include I2C formal properties and adjust timeouts. - Added I2C-related source files to the formal verification flow. - Updated DMA wrapper in to handle I2C DMA signals. - Created a new testbench for I2C functionality verification. - Implemented I2C helper functions in for testing. - Added I2C tests in to validate controller behavior and recovery. - Updated existing tests to accommodate changes in DMA and IRQ handling.
This commit is contained in:
48 files changed
+3862
-1030
No files matched your search
+1
-2
@@ -28,9 +28,8 @@ The SDRAM controller implementation in rtl/ip/ribp/memory/sdram_core.sv retains
|
||||
|
||||
## 4. EmbedFire
|
||||
|
||||
Several SPI/I2C-related RTL files retain the original attribution to EmbedFire and refer to source files such as sd_init.v, sd_write.v, sd_read.v, data_rw_ctrl.v, and i2c_ctrl.v:
|
||||
Several SPI SD card related RTL files retain the original attribution to EmbedFire and refer to source files such as sd_init.v, sd_write.v, sd_read.v, and data_rw_ctrl.v:
|
||||
|
||||
- rtl/ip/ribp/serial/i2c_core.sv
|
||||
- rtl/ip/ribp/storage/spisd_core.sv
|
||||
- rtl/ip/ribp/storage/spisd_data.sv
|
||||
- rtl/ip/ribp/storage/spisd_init.sv
|
||||
|
||||
@@ -252,7 +252,7 @@ endif
|
||||
benchmark-report coremark-report \
|
||||
pin-map check-pin-map soc-topology check-soc-topology user-extensions check-user-extensions \
|
||||
check-clock-reset-domains tech-cell-test rtl-lint check-rtl-lint \
|
||||
formal formal-bus formal-rib-adapter formal-rib2apb formal-gpio formal-ws2812 formal-uart formal-timer formal-clean formal-doctor
|
||||
formal formal-bus formal-rib-adapter formal-rib2apb formal-gpio formal-ws2812 formal-uart formal-i2c formal-timer formal-clean formal-doctor
|
||||
.NOTPARALLEL: setup
|
||||
|
||||
help:
|
||||
@@ -280,7 +280,7 @@ help:
|
||||
' check-clock-reset-domains validate the root clock/reset and CDC inventory' \
|
||||
' rtl-lint | check-rtl-lint run/check strict Verilator RTL lint warnings' \
|
||||
' formal | formal-bus | formal-rib-adapter | formal-rib2apb run SBY protocol proofs' \
|
||||
' formal-sysctrl | formal-pll-rcu | formal-gpio | formal-ws2812 | formal-uart | formal-timer | formal-clint run peripheral proofs' \
|
||||
' formal-sysctrl | formal-pll-rcu | formal-gpio | formal-ws2812 | formal-uart | formal-i2c | formal-timer | formal-clint run peripheral proofs' \
|
||||
' formal-doctor check the SBY, Yosys, sv2v, and Bitwuzla formal toolchain' \
|
||||
' benchmark-report run the memory/DMA profile and write meta/performance.json' \
|
||||
' coremark-report run the quick CoreMark profile and write meta/coremark.json' \
|
||||
|
||||
@@ -7,6 +7,6 @@ The following third-party projects or authors are referenced in the RTL source h
|
||||
- ETH Zurich and University of Bologna: notices are preserved in several RTL files under rtl/managed/clusterip/, rtl/managed/mpw/core/username7/ibex/, and in rtl/tech/tc_clk.sv.
|
||||
- Ravenna / PicoRV32 in ASIC: notices are preserved in rtl/ip/ribp/peripheral/gpio.sv, rtl/ip/ribp/peripheral/timer.sv, and rtl/ip/ribp/serial/uart.sv.
|
||||
- Hirosh Dabui: the original copyright notice is preserved in rtl/ip/ribp/memory/sdram_core.sv.
|
||||
- EmbedFire: attribution is preserved in rtl/ip/ribp/serial/i2c_core.sv and the SPI SD card related files under rtl/ip/ribp/storage/.
|
||||
- EmbedFire: attribution is preserved in the SPI SD card related files under rtl/ip/ribp/storage/.
|
||||
|
||||
These notices are included solely to preserve attribution for the retained third-party source material. They do not alter the licensing terms of the retroSoC repository itself, which is distributed under the Mulan PSL v2 license.
|
||||
@@ -28,7 +28,7 @@ under the [Mulan Permissive Software License, Version 2](LICENSE).
|
||||
- Configurable GF180, SKY130, IHP130, and ICS55 implementation targets with
|
||||
open-source CI coverage.
|
||||
- A memory-mapped peripheral subsystem with GPIO, UART,
|
||||
[dual general timers](docs/ip/timer.md), PWM, I2C, I2S, PS2,
|
||||
[dual general timers](docs/ip/timer.md), PWM, [dual I2C controllers](docs/ip/i2c.md), I2S, PS2,
|
||||
WS2812, SPI/QSPI, SDIO, PSRAM/OPI-PSRAM, SDRAM, DMA, LCD, RTC, watchdog, RNG, and CRC
|
||||
support. Available interfaces depend on the selected SoC configuration.
|
||||
- A standalone RISC-V runtime, HAL, board support, middleware, and `benchmark`, `bringup`,
|
||||
|
||||
@@ -33,7 +33,7 @@ int main(void) {
|
||||
return 1;
|
||||
}
|
||||
rs_booter();
|
||||
if (rs_i2c0_init((uint8_t)(CPU_FREQ / 2 - 1)) != RS_OK) {
|
||||
if (rs_i2c_init(RS_I2C_BUS_0, CPU_FREQ * UINT32_C(1000000), UINT32_C(400000)) != RS_OK) {
|
||||
return 1;
|
||||
}
|
||||
qspi_dev_init();
|
||||
|
||||
+13
-6
@@ -3,6 +3,13 @@
|
||||
#include <retrosoc/hal/i2c.h>
|
||||
#include <retrosoc/board/at24cxx.h>
|
||||
|
||||
static const rs_i2c_register_access_t at24c64_test_access = {
|
||||
.address = AT24C64_DEV_ADDR,
|
||||
.ten_bit_address = false,
|
||||
.register_address = 0U,
|
||||
.register_address_width = RS_I2C_REGISTER_ADDRESS_16_BIT,
|
||||
};
|
||||
|
||||
void at24cxx_test(void) {
|
||||
printf("AT24C64 wr/rd test\n");
|
||||
// prepare ref data
|
||||
@@ -11,14 +18,14 @@ void at24cxx_test(void) {
|
||||
ref_data[i] = i;
|
||||
}
|
||||
// write AT24C64
|
||||
if (rs_i2c0_write(AT24C64_DEV_ADDR, 0U, RS_I2C_DEVICE_ADDRESS_16BIT, I2C_TEST_NUM, ref_data,
|
||||
RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
if (rs_i2c_register_write(RS_I2C_BUS_0, &at24c64_test_access, ref_data, I2C_TEST_NUM,
|
||||
RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
printf("AT24C64 write timed out\n");
|
||||
return;
|
||||
}
|
||||
// read AT24C64
|
||||
if (rs_i2c0_read(AT24C64_DEV_ADDR, 0U, RS_I2C_DEVICE_ADDRESS_16BIT, I2C_TEST_NUM, rd_data,
|
||||
RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
if (rs_i2c_register_read(RS_I2C_BUS_0, &at24c64_test_access, rd_data, I2C_TEST_NUM,
|
||||
RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
printf("AT24C64 read timed out\n");
|
||||
return;
|
||||
}
|
||||
@@ -29,8 +36,8 @@ void at24cxx_test(void) {
|
||||
printf("test fail\n");
|
||||
}
|
||||
|
||||
(void)rs_i2c0_write(AT24C64_DEV_ADDR, 0U, RS_I2C_DEVICE_ADDRESS_16BIT, I2C_TEST_NUM, ref_data,
|
||||
RS_TIMEOUT_DEFAULT);
|
||||
(void)rs_i2c_register_write(RS_I2C_BUS_0, &at24c64_test_access, ref_data, I2C_TEST_NUM,
|
||||
RS_TIMEOUT_DEFAULT);
|
||||
|
||||
printf("AT24C64 wr/rd test done\n");
|
||||
}
|
||||
+11
-4
@@ -40,19 +40,26 @@ static const uint8_t es8388_init_cfg[] = {
|
||||
|
||||
void es8388_init(void) {
|
||||
const uint32_t init_cfg_len = sizeof(es8388_init_cfg) / sizeof(es8388_init_cfg[0]);
|
||||
rs_i2c_register_access_t access = {
|
||||
.address = ES8388_DEV_ADDR,
|
||||
.ten_bit_address = false,
|
||||
.register_address = 0U,
|
||||
.register_address_width = RS_I2C_REGISTER_ADDRESS_8_BIT,
|
||||
};
|
||||
|
||||
printf("[ES8388] init cfg len: %u\n", init_cfg_len);
|
||||
for (uint32_t i = 0U; i < init_cfg_len; i += 2U) {
|
||||
if (rs_i2c0_write(ES8388_DEV_ADDR, (uint16_t)es8388_init_cfg[i], RS_I2C_DEVICE_ADDRESS_8BIT,
|
||||
1U, es8388_init_cfg + i + 1, RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
access.register_address = es8388_init_cfg[i];
|
||||
if (rs_i2c_register_write(RS_I2C_BUS_0, &access, es8388_init_cfg + i + 1, 1U,
|
||||
RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
printf("[ES8388] write failed at register %d\n", es8388_init_cfg[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t rxdata[60] = {0};
|
||||
if (rs_i2c0_read(ES8388_DEV_ADDR, 0U, RS_I2C_DEVICE_ADDRESS_8BIT, 53U, rxdata,
|
||||
RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
access.register_address = 0U;
|
||||
if (rs_i2c_register_read(RS_I2C_BUS_0, &access, rxdata, 53U, RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
printf("[ES8388] read failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
#include <retrosoc/hal/i2c.h>
|
||||
#include <retrosoc/board/pcf8563b.h>
|
||||
|
||||
static const rs_i2c_register_access_t pcf8563b_time_access = {
|
||||
.address = PCF8563B_DEV_ADDR,
|
||||
.ten_bit_address = false,
|
||||
.register_address = PCF8563B_SECOND_REG,
|
||||
.register_address_width = RS_I2C_REGISTER_ADDRESS_8_BIT,
|
||||
};
|
||||
|
||||
uint8_t pcf8563b_bin2bcd(uint8_t val) {
|
||||
uint8_t bcdhigh = 0;
|
||||
while (val >= 10) {
|
||||
@@ -33,8 +40,8 @@ void pcf8563b_wr_reg(PCF8563B_info_t *info) {
|
||||
*(wr_data + 4) = pcf8563b_bin2bcd(info->date.weekday);
|
||||
*(wr_data + 5) = pcf8563b_bin2bcd(info->date.month);
|
||||
*(wr_data + 6) = pcf8563b_bin2bcd(info->date.year);
|
||||
if (rs_i2c0_write(PCF8563B_DEV_ADDR, PCF8563B_SECOND_REG, RS_I2C_DEVICE_ADDRESS_8BIT, 7U,
|
||||
wr_data, RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
if (rs_i2c_register_write(RS_I2C_BUS_0, &pcf8563b_time_access, wr_data, 7U,
|
||||
RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
printf("[PCF8563B] write failed\n");
|
||||
}
|
||||
}
|
||||
@@ -43,8 +50,8 @@ PCF8563B_info_t pcf8563b_rd_reg(void) {
|
||||
uint8_t rd_data[7] = {0};
|
||||
PCF8563B_info_t info = {0};
|
||||
|
||||
if (rs_i2c0_read(PCF8563B_DEV_ADDR, PCF8563B_SECOND_REG, RS_I2C_DEVICE_ADDRESS_8BIT, 7U,
|
||||
rd_data, RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
if (rs_i2c_register_read(RS_I2C_BUS_0, &pcf8563b_time_access, rd_data, 7U,
|
||||
RS_TIMEOUT_DEFAULT) != RS_OK) {
|
||||
printf("[PCF8563B] read failed\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -43,15 +43,6 @@
|
||||
#define reg_spisd_rxdata RS_SOC_REG32(RS_SOC_RIBP_SPISD_BASE, UINT32_C(0x10))
|
||||
#define reg_spisd_status RS_SOC_REG32(RS_SOC_RIBP_SPISD_BASE, UINT32_C(0x14))
|
||||
#define reg_spisd_sync RS_SOC_REG32(RS_SOC_RIBP_SPISD_BASE, UINT32_C(0x18))
|
||||
// i2c0
|
||||
#define reg_i2c0_clkdiv RS_SOC_REG32(RS_SOC_RIBP_I2C0_BASE, UINT32_C(0x00))
|
||||
#define reg_i2c0_devaddr RS_SOC_REG32(RS_SOC_RIBP_I2C0_BASE, UINT32_C(0x04))
|
||||
#define reg_i2c0_regaddr RS_SOC_REG32(RS_SOC_RIBP_I2C0_BASE, UINT32_C(0x08))
|
||||
#define reg_i2c0_txdata RS_SOC_REG32(RS_SOC_RIBP_I2C0_BASE, UINT32_C(0x0C))
|
||||
#define reg_i2c0_rxdata RS_SOC_REG32(RS_SOC_RIBP_I2C0_BASE, UINT32_C(0x10))
|
||||
#define reg_i2c0_xfer RS_SOC_REG32(RS_SOC_RIBP_I2C0_BASE, UINT32_C(0x14))
|
||||
#define reg_i2c0_cfg RS_SOC_REG32(RS_SOC_RIBP_I2C0_BASE, UINT32_C(0x18))
|
||||
#define reg_i2c0_status RS_SOC_REG32(RS_SOC_RIBP_I2C0_BASE, UINT32_C(0x1C))
|
||||
// i2s
|
||||
#define reg_i2s_mode RS_SOC_REG32(RS_SOC_RIBP_I2S_BASE, UINT32_C(0x00))
|
||||
#define reg_i2s_format RS_SOC_REG32(RS_SOC_RIBP_I2S_BASE, UINT32_C(0x04))
|
||||
@@ -192,15 +183,6 @@
|
||||
#define reg_dvp_recven RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x00))
|
||||
#define reg_dvp_rxdata RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x04))
|
||||
#define reg_dvp_status RS_SOC_REG32(RS_SOC_RIBP_DVP_BASE, UINT32_C(0x08))
|
||||
// i2c1
|
||||
#define reg_i2c1_clkdiv RS_SOC_REG32(RS_SOC_RIBP_I2C1_BASE, UINT32_C(0x00))
|
||||
#define reg_i2c1_devaddr RS_SOC_REG32(RS_SOC_RIBP_I2C1_BASE, UINT32_C(0x04))
|
||||
#define reg_i2c1_regaddr RS_SOC_REG32(RS_SOC_RIBP_I2C1_BASE, UINT32_C(0x08))
|
||||
#define reg_i2c1_txdata RS_SOC_REG32(RS_SOC_RIBP_I2C1_BASE, UINT32_C(0x0C))
|
||||
#define reg_i2c1_rxdata RS_SOC_REG32(RS_SOC_RIBP_I2C1_BASE, UINT32_C(0x10))
|
||||
#define reg_i2c1_xfer RS_SOC_REG32(RS_SOC_RIBP_I2C1_BASE, UINT32_C(0x14))
|
||||
#define reg_i2c1_cfg RS_SOC_REG32(RS_SOC_RIBP_I2C1_BASE, UINT32_C(0x18))
|
||||
#define reg_i2c1_status RS_SOC_REG32(RS_SOC_RIBP_I2C1_BASE, UINT32_C(0x1C))
|
||||
// archinfo
|
||||
#define reg_archinfo_sys RS_SOC_REG32(RS_SOC_APB_ARCHINFO_BASE, UINT32_C(0x00))
|
||||
#define reg_archinfo_idl RS_SOC_REG32(RS_SOC_APB_ARCHINFO_BASE, UINT32_C(0x04))
|
||||
|
||||
@@ -17,6 +17,10 @@ typedef struct {
|
||||
#define RS_DMA_MODE_QSPI_RX UINT32_C(4)
|
||||
#define RS_DMA_MODE_UART_TX UINT32_C(5)
|
||||
#define RS_DMA_MODE_UART_RX UINT32_C(6)
|
||||
#define RS_DMA_MODE_I2C0_TX UINT32_C(7)
|
||||
#define RS_DMA_MODE_I2C0_RX UINT32_C(8)
|
||||
#define RS_DMA_MODE_I2C1_TX UINT32_C(9)
|
||||
#define RS_DMA_MODE_I2C1_RX UINT32_C(10)
|
||||
|
||||
rs_status_t rs_dma_config(uint32_t mode, uintptr_t source, uint32_t source_increment,
|
||||
uintptr_t destination, uint32_t destination_increment,
|
||||
|
||||
@@ -1,19 +1,118 @@
|
||||
#ifndef RETROSOC_HAL_I2C_H
|
||||
#define RETROSOC_HAL_I2C_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/core/status.h>
|
||||
|
||||
#define RS_I2C_XFER_WRITE 0x2U
|
||||
#define RS_I2C_XFER_READ 0x3U
|
||||
#define RS_I2C_DEVICE_ADDRESS_8BIT 0U
|
||||
#define RS_I2C_DEVICE_ADDRESS_16BIT 1U
|
||||
#define RS_I2C_DMA_MAX_BYTES 16U
|
||||
|
||||
rs_status_t rs_i2c0_init(uint8_t clock_divider);
|
||||
rs_status_t rs_i2c0_write(uint8_t device_address, uint16_t register_address, uint8_t address_width,
|
||||
uint8_t count, const uint8_t *data, rs_timeout_t timeout);
|
||||
rs_status_t rs_i2c0_read(uint8_t device_address, uint16_t register_address, uint8_t address_width,
|
||||
uint8_t count, uint8_t *data, rs_timeout_t timeout);
|
||||
#define RS_I2C_ERROR_ADDR_NACK (UINT32_C(1) << 0U)
|
||||
#define RS_I2C_ERROR_DATA_NACK (UINT32_C(1) << 1U)
|
||||
#define RS_I2C_ERROR_ARB_LOST (UINT32_C(1) << 2U)
|
||||
#define RS_I2C_ERROR_STRETCH_TO (UINT32_C(1) << 3U)
|
||||
#define RS_I2C_ERROR_BUS_TO (UINT32_C(1) << 4U)
|
||||
#define RS_I2C_ERROR_COMMAND_TO (UINT32_C(1) << 5U)
|
||||
#define RS_I2C_ERROR_COMMAND (UINT32_C(1) << 6U)
|
||||
#define RS_I2C_ERROR_RX_OVERFLOW (UINT32_C(1) << 7U)
|
||||
#define RS_I2C_ERROR_CONFIG (UINT32_C(1) << 8U)
|
||||
#define RS_I2C_ERROR_ABORTED (UINT32_C(1) << 9U)
|
||||
#define RS_I2C_ERROR_RECOVERY (UINT32_C(1) << 10U)
|
||||
#define RS_I2C_ERROR_ALL UINT32_C(0x7FF)
|
||||
|
||||
#define RS_I2C_INTR_DONE (UINT32_C(1) << 0U)
|
||||
#define RS_I2C_INTR_CMD_WATERMARK (UINT32_C(1) << 1U)
|
||||
#define RS_I2C_INTR_RX_WATERMARK (UINT32_C(1) << 2U)
|
||||
#define RS_I2C_INTR_NACK (UINT32_C(1) << 3U)
|
||||
#define RS_I2C_INTR_ARB_LOST (UINT32_C(1) << 4U)
|
||||
#define RS_I2C_INTR_TIMEOUT (UINT32_C(1) << 5U)
|
||||
#define RS_I2C_INTR_ERROR (UINT32_C(1) << 6U)
|
||||
#define RS_I2C_INTR_RECOVERY_DONE (UINT32_C(1) << 7U)
|
||||
#define RS_I2C_INTR_ALL UINT32_C(0xFF)
|
||||
|
||||
typedef enum {
|
||||
RS_I2C_BUS_0 = 0,
|
||||
RS_I2C_BUS_1 = 1,
|
||||
} rs_i2c_bus_t;
|
||||
|
||||
typedef enum {
|
||||
RS_I2C_REGISTER_ADDRESS_8_BIT = 1,
|
||||
RS_I2C_REGISTER_ADDRESS_16_BIT = 2,
|
||||
} rs_i2c_register_address_width_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t scl_low_cycles;
|
||||
uint16_t scl_high_cycles;
|
||||
uint16_t start_hold_cycles;
|
||||
uint16_t start_setup_cycles;
|
||||
uint16_t data_hold_cycles;
|
||||
uint16_t data_setup_cycles;
|
||||
uint16_t stop_setup_cycles;
|
||||
uint16_t bus_free_cycles;
|
||||
} rs_i2c_timing_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t source_clock_hz;
|
||||
uint32_t bus_hz;
|
||||
uint32_t stretch_timeout_us;
|
||||
uint32_t bus_idle_timeout_us;
|
||||
uint32_t command_timeout_us;
|
||||
uint8_t scl_filter_cycles;
|
||||
uint8_t sda_filter_cycles;
|
||||
uint8_t command_watermark;
|
||||
uint8_t rx_watermark;
|
||||
} rs_i2c_config_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t address;
|
||||
bool ten_bit_address;
|
||||
const uint8_t *tx_data;
|
||||
size_t tx_length;
|
||||
uint8_t *rx_data;
|
||||
size_t rx_length;
|
||||
} rs_i2c_transfer_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t address;
|
||||
bool ten_bit_address;
|
||||
uint16_t register_address;
|
||||
rs_i2c_register_address_width_t register_address_width;
|
||||
} rs_i2c_register_access_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t flags;
|
||||
uint32_t command_level;
|
||||
uint32_t rx_level;
|
||||
uint32_t errors;
|
||||
uint32_t interrupt_state;
|
||||
} rs_i2c_status_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t words[RS_I2C_DMA_MAX_BYTES];
|
||||
} rs_i2c_dma_workspace_t;
|
||||
|
||||
rs_status_t rs_i2c_timing_calculate(uint32_t source_clock_hz, uint32_t bus_hz,
|
||||
rs_i2c_timing_t *timing);
|
||||
rs_status_t rs_i2c_configure(rs_i2c_bus_t bus, const rs_i2c_config_t *config, rs_timeout_t timeout);
|
||||
rs_status_t rs_i2c_init(rs_i2c_bus_t bus, uint32_t source_clock_hz, uint32_t bus_hz);
|
||||
rs_status_t rs_i2c_transfer(rs_i2c_bus_t bus, const rs_i2c_transfer_t *transfer,
|
||||
rs_timeout_t timeout);
|
||||
rs_status_t rs_i2c_register_write(rs_i2c_bus_t bus, const rs_i2c_register_access_t *access,
|
||||
const uint8_t *data, size_t length, rs_timeout_t timeout);
|
||||
rs_status_t rs_i2c_register_read(rs_i2c_bus_t bus, const rs_i2c_register_access_t *access,
|
||||
uint8_t *data, size_t length, rs_timeout_t timeout);
|
||||
rs_status_t rs_i2c_abort(rs_i2c_bus_t bus, rs_timeout_t timeout);
|
||||
rs_status_t rs_i2c_recover(rs_i2c_bus_t bus, rs_timeout_t timeout);
|
||||
rs_status_t rs_i2c_get_status(rs_i2c_bus_t bus, rs_i2c_status_t *status);
|
||||
rs_status_t rs_i2c_irq_enable(rs_i2c_bus_t bus, uint32_t mask);
|
||||
rs_status_t rs_i2c_irq_ack(rs_i2c_bus_t bus, uint32_t mask);
|
||||
rs_status_t rs_i2c_irq_test(rs_i2c_bus_t bus, uint32_t mask);
|
||||
rs_status_t rs_i2c_write_dma(rs_i2c_bus_t bus, uint16_t address, bool ten_bit_address,
|
||||
const uint8_t *data, size_t length, rs_i2c_dma_workspace_t *workspace,
|
||||
rs_timeout_t timeout);
|
||||
rs_status_t rs_i2c_read_dma(rs_i2c_bus_t bus, uint16_t address, bool ten_bit_address, uint8_t *data,
|
||||
size_t length, rs_i2c_dma_workspace_t *workspace, rs_timeout_t timeout);
|
||||
|
||||
#endif
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
rs_status_t rs_dma_config(uint32_t mode, uintptr_t source, uint32_t source_increment,
|
||||
uintptr_t destination, uint32_t destination_increment,
|
||||
uint32_t transfer_words) {
|
||||
if ((mode > RS_DMA_MODE_UART_RX) || (source == 0U) || (destination == 0U) ||
|
||||
if ((mode > RS_DMA_MODE_I2C1_RX) || (source == 0U) || (destination == 0U) ||
|
||||
(transfer_words == 0U) || (source_increment > 1U) || (destination_increment > 1U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
|
||||
+501
-36
@@ -1,59 +1,524 @@
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/core/wait.h>
|
||||
#include <retrosoc/hal/dma.h>
|
||||
#include <retrosoc/hal/gpio.h>
|
||||
#include <retrosoc/hal/i2c.h>
|
||||
|
||||
static rs_status_t rs_i2c0_validate(uint8_t address_width, uint8_t count, const void *data) {
|
||||
if ((address_width > RS_I2C_DEVICE_ADDRESS_16BIT) || ((count != 0U) && (data == NULL))) {
|
||||
#define RS_I2C_CTRL_OFFSET UINT32_C(0x00)
|
||||
#define RS_I2C_SCL_TIMING_OFFSET UINT32_C(0x04)
|
||||
#define RS_I2C_START_TIMING_OFFSET UINT32_C(0x08)
|
||||
#define RS_I2C_DATA_TIMING_OFFSET UINT32_C(0x0C)
|
||||
#define RS_I2C_STOP_TIMING_OFFSET UINT32_C(0x10)
|
||||
#define RS_I2C_FILTER_OFFSET UINT32_C(0x14)
|
||||
#define RS_I2C_STRETCH_TIMEOUT_OFFSET UINT32_C(0x18)
|
||||
#define RS_I2C_BUS_IDLE_TIMEOUT_OFFSET UINT32_C(0x1C)
|
||||
#define RS_I2C_COMMAND_TIMEOUT_OFFSET UINT32_C(0x20)
|
||||
#define RS_I2C_TARGET_ADDR_OFFSET UINT32_C(0x24)
|
||||
#define RS_I2C_DATA_CMD_OFFSET UINT32_C(0x28)
|
||||
#define RS_I2C_RXDATA_OFFSET UINT32_C(0x2C)
|
||||
#define RS_I2C_STATUS_OFFSET UINT32_C(0x30)
|
||||
#define RS_I2C_FIFO_LEVEL_OFFSET UINT32_C(0x34)
|
||||
#define RS_I2C_COMMAND_OFFSET UINT32_C(0x38)
|
||||
#define RS_I2C_CMD_WATERMARK_OFFSET UINT32_C(0x3C)
|
||||
#define RS_I2C_RX_WATERMARK_OFFSET UINT32_C(0x40)
|
||||
#define RS_I2C_ERROR_STATUS_OFFSET UINT32_C(0x44)
|
||||
#define RS_I2C_INTR_STATE_OFFSET UINT32_C(0x48)
|
||||
#define RS_I2C_INTR_ENABLE_OFFSET UINT32_C(0x4C)
|
||||
#define RS_I2C_INTR_TEST_OFFSET UINT32_C(0x54)
|
||||
|
||||
#define RS_I2C_REG(bus, offset) RS_SOC_REG32(rs_i2c_base((bus)), (offset))
|
||||
|
||||
#define RS_I2C_CTRL_ENABLE UINT32_C(0x001)
|
||||
#define RS_I2C_STATUS_ENABLE UINT32_C(0x001)
|
||||
#define RS_I2C_STATUS_BUSY UINT32_C(0x002)
|
||||
#define RS_I2C_STATUS_CMD_FULL UINT32_C(0x010)
|
||||
#define RS_I2C_COMMAND_ABORT UINT32_C(0x001)
|
||||
#define RS_I2C_COMMAND_RECOVER UINT32_C(0x002)
|
||||
#define RS_I2C_COMMAND_FLUSH_ALL UINT32_C(0x00C)
|
||||
#define RS_I2C_DATA_CMD_READ UINT32_C(0x100)
|
||||
#define RS_I2C_DATA_CMD_RESTART UINT32_C(0x200)
|
||||
#define RS_I2C_DATA_CMD_STOP UINT32_C(0x400)
|
||||
#define RS_I2C_DATA_CMD_NACK_LAST UINT32_C(0x800)
|
||||
#define RS_I2C_TARGET_TEN_BIT UINT32_C(0x400)
|
||||
#define RS_I2C_FIFO_COMMAND_MASK UINT32_C(0x0FF)
|
||||
#define RS_I2C_FIFO_RX_SHIFT 16U
|
||||
#define RS_I2C_FIFO_RX_MASK UINT32_C(0x0FF)
|
||||
#define RS_I2C_FIFO_DEPTH UINT32_C(16)
|
||||
#define RS_I2C_TIMEOUT_MAX_CYCLES UINT32_C(0xFFFFFF)
|
||||
|
||||
static uintptr_t rs_i2c_base(rs_i2c_bus_t bus) {
|
||||
return (bus == RS_I2C_BUS_0) ? (uintptr_t)RS_SOC_RIBP_I2C0_BASE
|
||||
: (uintptr_t)RS_SOC_RIBP_I2C1_BASE;
|
||||
}
|
||||
|
||||
static bool rs_i2c_bus_valid(rs_i2c_bus_t bus) {
|
||||
return (bus == RS_I2C_BUS_0) || (bus == RS_I2C_BUS_1);
|
||||
}
|
||||
|
||||
static bool rs_i2c_address_valid(uint16_t address, bool ten_bit_address) {
|
||||
return ten_bit_address ? (address <= UINT16_C(0x03FF)) : (address <= UINT16_C(0x007F));
|
||||
}
|
||||
|
||||
static rs_status_t rs_i2c_timeout_cycles(uint32_t source_clock_hz, uint32_t timeout_us,
|
||||
uint32_t *cycles) {
|
||||
uint64_t value;
|
||||
|
||||
if (cycles == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
if (timeout_us == 0U) {
|
||||
*cycles = 0U;
|
||||
return RS_OK;
|
||||
}
|
||||
value =
|
||||
(((uint64_t)source_clock_hz * (uint64_t)timeout_us) + UINT64_C(999999)) / UINT64_C(1000000);
|
||||
if ((value == 0U) || (value > RS_I2C_TIMEOUT_MAX_CYCLES)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
*cycles = (uint32_t)value;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
static rs_status_t rs_i2c_gpio_configure(rs_i2c_bus_t bus) {
|
||||
const rs_gpio_config_t pin_config = {
|
||||
.mode = (bus == RS_I2C_BUS_0) ? RS_GPIO_MODE_ALT0 : RS_GPIO_MODE_ALT1,
|
||||
.pull = RS_GPIO_PULL_NONE,
|
||||
.trigger = RS_GPIO_TRIGGER_NONE,
|
||||
.output_high = true,
|
||||
.open_drain = true,
|
||||
.input_cmos = false,
|
||||
.filter_enable = false,
|
||||
.interrupt_enable = false,
|
||||
};
|
||||
const uint32_t scl_pin = (bus == RS_I2C_BUS_0) ? UINT32_C(7) : UINT32_C(3);
|
||||
const uint32_t sda_pin = (bus == RS_I2C_BUS_0) ? UINT32_C(8) : UINT32_C(4);
|
||||
rs_status_t status = rs_gpio_configure(scl_pin, &pin_config);
|
||||
|
||||
if (status == RS_OK) {
|
||||
status = rs_gpio_configure(sda_pin, &pin_config);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static rs_status_t rs_i2c_wait_idle(rs_i2c_bus_t bus, rs_timeout_t timeout) {
|
||||
while ((RS_I2C_REG(bus, RS_I2C_STATUS_OFFSET) & RS_I2C_STATUS_BUSY) != 0U) {
|
||||
if (timeout == 0U) {
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
timeout--;
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
static rs_status_t rs_i2c_prepare(rs_i2c_bus_t bus, uint16_t address, bool ten_bit_address,
|
||||
rs_timeout_t timeout) {
|
||||
rs_status_t status;
|
||||
|
||||
if (!rs_i2c_bus_valid(bus) || !rs_i2c_address_valid(address, ten_bit_address)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
if ((RS_I2C_REG(bus, RS_I2C_STATUS_OFFSET) & RS_I2C_STATUS_ENABLE) == 0U) {
|
||||
return RS_EIO;
|
||||
}
|
||||
status = rs_i2c_wait_idle(bus, timeout);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
RS_I2C_REG(bus, RS_I2C_COMMAND_OFFSET) = RS_I2C_COMMAND_FLUSH_ALL;
|
||||
RS_I2C_REG(bus, RS_I2C_ERROR_STATUS_OFFSET) = RS_I2C_ERROR_ALL;
|
||||
RS_I2C_REG(bus, RS_I2C_INTR_STATE_OFFSET) = RS_I2C_INTR_ALL;
|
||||
RS_I2C_REG(bus, RS_I2C_TARGET_ADDR_OFFSET) =
|
||||
(uint32_t)address | (ten_bit_address ? RS_I2C_TARGET_TEN_BIT : 0U);
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
static uint32_t rs_i2c_command(const uint8_t *prefix, size_t prefix_length, const uint8_t *tx_data,
|
||||
size_t tx_length, size_t rx_length, size_t index) {
|
||||
const size_t write_length = prefix_length + tx_length;
|
||||
const size_t total_length = write_length + rx_length;
|
||||
uint32_t command;
|
||||
|
||||
if (index < write_length) {
|
||||
command = (index < prefix_length) ? (uint32_t)prefix[index]
|
||||
: (uint32_t)tx_data[index - prefix_length];
|
||||
} else {
|
||||
command = RS_I2C_DATA_CMD_READ;
|
||||
if ((index == write_length) && (write_length != 0U)) {
|
||||
command |= RS_I2C_DATA_CMD_RESTART;
|
||||
}
|
||||
}
|
||||
if ((index + 1U) == total_length) {
|
||||
command |= RS_I2C_DATA_CMD_STOP;
|
||||
if (index >= write_length) {
|
||||
command |= RS_I2C_DATA_CMD_NACK_LAST;
|
||||
}
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
static rs_status_t rs_i2c_execute(rs_i2c_bus_t bus, uint16_t address, bool ten_bit_address,
|
||||
const uint8_t *prefix, size_t prefix_length,
|
||||
const uint8_t *tx_data, size_t tx_length, uint8_t *rx_data,
|
||||
size_t rx_length, rs_timeout_t timeout) {
|
||||
size_t command_index = 0U;
|
||||
size_t rx_index = 0U;
|
||||
size_t total_length;
|
||||
rs_status_t status;
|
||||
|
||||
if ((prefix_length > (SIZE_MAX - tx_length)) ||
|
||||
((prefix_length + tx_length) > (SIZE_MAX - rx_length))) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
total_length = prefix_length + tx_length + rx_length;
|
||||
if ((total_length == 0U) || ((prefix_length != 0U) && (prefix == NULL)) ||
|
||||
((tx_length != 0U) && (tx_data == NULL)) || ((rx_length != 0U) && (rx_data == NULL))) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
status = rs_i2c_prepare(bus, address, ten_bit_address, timeout);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
while (timeout != 0U) {
|
||||
uint32_t levels;
|
||||
uint32_t errors;
|
||||
|
||||
errors = RS_I2C_REG(bus, RS_I2C_ERROR_STATUS_OFFSET);
|
||||
if (errors != 0U) {
|
||||
return RS_EIO;
|
||||
}
|
||||
levels = RS_I2C_REG(bus, RS_I2C_FIFO_LEVEL_OFFSET);
|
||||
if ((command_index < total_length) &&
|
||||
((levels & RS_I2C_FIFO_COMMAND_MASK) < RS_I2C_FIFO_DEPTH)) {
|
||||
RS_I2C_REG(bus, RS_I2C_DATA_CMD_OFFSET) =
|
||||
rs_i2c_command(prefix, prefix_length, tx_data, tx_length, rx_length, command_index);
|
||||
command_index++;
|
||||
}
|
||||
if ((rx_index < rx_length) &&
|
||||
(((levels >> RS_I2C_FIFO_RX_SHIFT) & RS_I2C_FIFO_RX_MASK) != 0U)) {
|
||||
rx_data[rx_index] = (uint8_t)RS_I2C_REG(bus, RS_I2C_RXDATA_OFFSET);
|
||||
rx_index++;
|
||||
}
|
||||
if (((RS_I2C_REG(bus, RS_I2C_INTR_STATE_OFFSET) & RS_I2C_INTR_DONE) != 0U) &&
|
||||
(command_index == total_length) && (rx_index == rx_length)) {
|
||||
RS_I2C_REG(bus, RS_I2C_INTR_STATE_OFFSET) = RS_I2C_INTR_DONE;
|
||||
return RS_OK;
|
||||
}
|
||||
timeout--;
|
||||
}
|
||||
(void)rs_i2c_abort(bus, RS_TIMEOUT_DEFAULT);
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
|
||||
static rs_status_t rs_i2c_wait_done(rs_i2c_bus_t bus, rs_timeout_t timeout) {
|
||||
while (timeout != 0U) {
|
||||
if (RS_I2C_REG(bus, RS_I2C_ERROR_STATUS_OFFSET) != 0U) {
|
||||
return RS_EIO;
|
||||
}
|
||||
if ((RS_I2C_REG(bus, RS_I2C_INTR_STATE_OFFSET) & RS_I2C_INTR_DONE) != 0U) {
|
||||
RS_I2C_REG(bus, RS_I2C_INTR_STATE_OFFSET) = RS_I2C_INTR_DONE;
|
||||
return RS_OK;
|
||||
}
|
||||
timeout--;
|
||||
}
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_configure(rs_i2c_bus_t bus, const rs_i2c_config_t *config,
|
||||
rs_timeout_t timeout) {
|
||||
rs_i2c_timing_t timing;
|
||||
uint32_t stretch_timeout;
|
||||
uint32_t bus_idle_timeout;
|
||||
uint32_t command_timeout;
|
||||
rs_status_t status;
|
||||
|
||||
if (!rs_i2c_bus_valid(bus) || (config == NULL) || (config->scl_filter_cycles > 15U) ||
|
||||
(config->sda_filter_cycles > 15U) || (config->command_watermark >= 16U) ||
|
||||
(config->rx_watermark == 0U) || (config->rx_watermark > 16U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
status = rs_i2c_timing_calculate(config->source_clock_hz, config->bus_hz, &timing);
|
||||
if (status == RS_OK) {
|
||||
status = rs_i2c_timeout_cycles(config->source_clock_hz, config->stretch_timeout_us,
|
||||
&stretch_timeout);
|
||||
}
|
||||
if (status == RS_OK) {
|
||||
status = rs_i2c_timeout_cycles(config->source_clock_hz, config->bus_idle_timeout_us,
|
||||
&bus_idle_timeout);
|
||||
}
|
||||
if (status == RS_OK) {
|
||||
status = rs_i2c_timeout_cycles(config->source_clock_hz, config->command_timeout_us,
|
||||
&command_timeout);
|
||||
}
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
status = rs_i2c_wait_idle(bus, timeout);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
RS_I2C_REG(bus, RS_I2C_CTRL_OFFSET) = 0U;
|
||||
status = rs_i2c_gpio_configure(bus);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
RS_I2C_REG(bus, RS_I2C_COMMAND_OFFSET) = RS_I2C_COMMAND_FLUSH_ALL;
|
||||
RS_I2C_REG(bus, RS_I2C_ERROR_STATUS_OFFSET) = RS_I2C_ERROR_ALL;
|
||||
RS_I2C_REG(bus, RS_I2C_INTR_STATE_OFFSET) = RS_I2C_INTR_ALL;
|
||||
RS_I2C_REG(bus, RS_I2C_SCL_TIMING_OFFSET) =
|
||||
((uint32_t)timing.scl_high_cycles << 16U) | (uint32_t)timing.scl_low_cycles;
|
||||
RS_I2C_REG(bus, RS_I2C_START_TIMING_OFFSET) =
|
||||
((uint32_t)timing.start_setup_cycles << 16U) | (uint32_t)timing.start_hold_cycles;
|
||||
RS_I2C_REG(bus, RS_I2C_DATA_TIMING_OFFSET) =
|
||||
((uint32_t)timing.data_setup_cycles << 16U) | (uint32_t)timing.data_hold_cycles;
|
||||
RS_I2C_REG(bus, RS_I2C_STOP_TIMING_OFFSET) =
|
||||
((uint32_t)timing.bus_free_cycles << 16U) | (uint32_t)timing.stop_setup_cycles;
|
||||
RS_I2C_REG(bus, RS_I2C_FILTER_OFFSET) =
|
||||
((uint32_t)config->sda_filter_cycles << 8U) | (uint32_t)config->scl_filter_cycles;
|
||||
RS_I2C_REG(bus, RS_I2C_STRETCH_TIMEOUT_OFFSET) = stretch_timeout;
|
||||
RS_I2C_REG(bus, RS_I2C_BUS_IDLE_TIMEOUT_OFFSET) = bus_idle_timeout;
|
||||
RS_I2C_REG(bus, RS_I2C_COMMAND_TIMEOUT_OFFSET) = command_timeout;
|
||||
RS_I2C_REG(bus, RS_I2C_CMD_WATERMARK_OFFSET) = config->command_watermark;
|
||||
RS_I2C_REG(bus, RS_I2C_RX_WATERMARK_OFFSET) = config->rx_watermark;
|
||||
RS_I2C_REG(bus, RS_I2C_CTRL_OFFSET) = RS_I2C_CTRL_ENABLE;
|
||||
return ((RS_I2C_REG(bus, RS_I2C_STATUS_OFFSET) & RS_I2C_STATUS_ENABLE) != 0U) ? RS_OK : RS_EIO;
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_init(rs_i2c_bus_t bus, uint32_t source_clock_hz, uint32_t bus_hz) {
|
||||
const rs_i2c_config_t config = {
|
||||
.source_clock_hz = source_clock_hz,
|
||||
.bus_hz = bus_hz,
|
||||
.stretch_timeout_us = UINT32_C(25000),
|
||||
.bus_idle_timeout_us = UINT32_C(25000),
|
||||
.command_timeout_us = UINT32_C(100000),
|
||||
.scl_filter_cycles = UINT8_C(2),
|
||||
.sda_filter_cycles = UINT8_C(2),
|
||||
.command_watermark = UINT8_C(4),
|
||||
.rx_watermark = UINT8_C(8),
|
||||
};
|
||||
return rs_i2c_configure(bus, &config, RS_TIMEOUT_DEFAULT);
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_transfer(rs_i2c_bus_t bus, const rs_i2c_transfer_t *transfer,
|
||||
rs_timeout_t timeout) {
|
||||
if (transfer == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
return rs_i2c_execute(bus, transfer->address, transfer->ten_bit_address, NULL, 0U,
|
||||
transfer->tx_data, transfer->tx_length, transfer->rx_data,
|
||||
transfer->rx_length, timeout);
|
||||
}
|
||||
|
||||
static rs_status_t rs_i2c_register_prefix(const rs_i2c_register_access_t *access, uint8_t prefix[2],
|
||||
size_t *prefix_length) {
|
||||
if ((access == NULL) || (prefix == NULL) || (prefix_length == NULL)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
|
||||
switch (access->register_address_width) {
|
||||
case RS_I2C_REGISTER_ADDRESS_8_BIT:
|
||||
if (access->register_address > UINT8_MAX) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
prefix[0] = (uint8_t)access->register_address;
|
||||
*prefix_length = 1U;
|
||||
break;
|
||||
case RS_I2C_REGISTER_ADDRESS_16_BIT:
|
||||
prefix[0] = (uint8_t)(access->register_address >> 8U);
|
||||
prefix[1] = (uint8_t)access->register_address;
|
||||
*prefix_length = 2U;
|
||||
break;
|
||||
default:
|
||||
return RS_EINVAL;
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c0_init(uint8_t clock_divider) {
|
||||
reg_i2c0_clkdiv = clock_divider;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c0_write(uint8_t device_address, uint16_t register_address, uint8_t address_width,
|
||||
uint8_t count, const uint8_t *data, rs_timeout_t timeout) {
|
||||
rs_status_t status = rs_i2c0_validate(address_width, count, data);
|
||||
rs_status_t rs_i2c_register_write(rs_i2c_bus_t bus, const rs_i2c_register_access_t *access,
|
||||
const uint8_t *data, size_t length, rs_timeout_t timeout) {
|
||||
uint8_t prefix[2];
|
||||
size_t prefix_length;
|
||||
rs_status_t status;
|
||||
|
||||
if ((data == NULL) || (length == 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
status = rs_i2c_register_prefix(access, prefix, &prefix_length);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
reg_i2c0_devaddr = device_address;
|
||||
reg_i2c0_cfg = address_width;
|
||||
for (uint8_t index = 0U; index < count; ++index) {
|
||||
reg_i2c0_regaddr = (uint32_t)register_address + index;
|
||||
reg_i2c0_txdata = data[index];
|
||||
reg_i2c0_xfer = RS_I2C_XFER_WRITE;
|
||||
status = rs_wait_mask(®_i2c0_status, UINT32_MAX, 1U, timeout);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return RS_OK;
|
||||
return rs_i2c_execute(bus, access->address, access->ten_bit_address, prefix, prefix_length,
|
||||
data, length, NULL, 0U, timeout);
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c0_read(uint8_t device_address, uint16_t register_address, uint8_t address_width,
|
||||
uint8_t count, uint8_t *data, rs_timeout_t timeout) {
|
||||
rs_status_t status = rs_i2c0_validate(address_width, count, data);
|
||||
rs_status_t rs_i2c_register_read(rs_i2c_bus_t bus, const rs_i2c_register_access_t *access,
|
||||
uint8_t *data, size_t length, rs_timeout_t timeout) {
|
||||
uint8_t prefix[2];
|
||||
size_t prefix_length;
|
||||
rs_status_t status;
|
||||
|
||||
if ((data == NULL) || (length == 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
status = rs_i2c_register_prefix(access, prefix, &prefix_length);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
reg_i2c0_devaddr = device_address;
|
||||
reg_i2c0_cfg = address_width;
|
||||
for (uint8_t index = 0U; index < count; ++index) {
|
||||
reg_i2c0_regaddr = (uint32_t)register_address + index;
|
||||
reg_i2c0_xfer = RS_I2C_XFER_READ;
|
||||
status = rs_wait_mask(®_i2c0_status, UINT32_MAX, 1U, timeout);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
data[index] = (uint8_t)reg_i2c0_rxdata;
|
||||
return rs_i2c_execute(bus, access->address, access->ten_bit_address, prefix, prefix_length,
|
||||
NULL, 0U, data, length, timeout);
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_abort(rs_i2c_bus_t bus, rs_timeout_t timeout) {
|
||||
if (!rs_i2c_bus_valid(bus)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
if ((RS_I2C_REG(bus, RS_I2C_STATUS_OFFSET) & RS_I2C_STATUS_BUSY) == 0U) {
|
||||
return RS_OK;
|
||||
}
|
||||
RS_I2C_REG(bus, RS_I2C_COMMAND_OFFSET) = RS_I2C_COMMAND_ABORT;
|
||||
return rs_i2c_wait_idle(bus, timeout);
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_recover(rs_i2c_bus_t bus, rs_timeout_t timeout) {
|
||||
rs_status_t status;
|
||||
|
||||
if (!rs_i2c_bus_valid(bus)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
status = rs_i2c_wait_idle(bus, timeout);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
RS_I2C_REG(bus, RS_I2C_ERROR_STATUS_OFFSET) = RS_I2C_ERROR_ALL;
|
||||
RS_I2C_REG(bus, RS_I2C_INTR_STATE_OFFSET) = RS_I2C_INTR_ALL;
|
||||
RS_I2C_REG(bus, RS_I2C_COMMAND_OFFSET) = RS_I2C_COMMAND_RECOVER;
|
||||
while (timeout != 0U) {
|
||||
if (RS_I2C_REG(bus, RS_I2C_ERROR_STATUS_OFFSET) != 0U) {
|
||||
return RS_EIO;
|
||||
}
|
||||
if ((RS_I2C_REG(bus, RS_I2C_INTR_STATE_OFFSET) & RS_I2C_INTR_RECOVERY_DONE) != 0U) {
|
||||
RS_I2C_REG(bus, RS_I2C_INTR_STATE_OFFSET) = RS_I2C_INTR_RECOVERY_DONE;
|
||||
return RS_OK;
|
||||
}
|
||||
timeout--;
|
||||
}
|
||||
return RS_ETIMEOUT;
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_get_status(rs_i2c_bus_t bus, rs_i2c_status_t *status) {
|
||||
uint32_t levels;
|
||||
|
||||
if (!rs_i2c_bus_valid(bus) || (status == NULL)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
levels = RS_I2C_REG(bus, RS_I2C_FIFO_LEVEL_OFFSET);
|
||||
status->flags = RS_I2C_REG(bus, RS_I2C_STATUS_OFFSET);
|
||||
status->command_level = levels & RS_I2C_FIFO_COMMAND_MASK;
|
||||
status->rx_level = (levels >> RS_I2C_FIFO_RX_SHIFT) & RS_I2C_FIFO_RX_MASK;
|
||||
status->errors = RS_I2C_REG(bus, RS_I2C_ERROR_STATUS_OFFSET);
|
||||
status->interrupt_state = RS_I2C_REG(bus, RS_I2C_INTR_STATE_OFFSET);
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_irq_enable(rs_i2c_bus_t bus, uint32_t mask) {
|
||||
if (!rs_i2c_bus_valid(bus) || ((mask & ~RS_I2C_INTR_ALL) != 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
RS_I2C_REG(bus, RS_I2C_INTR_ENABLE_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_irq_ack(rs_i2c_bus_t bus, uint32_t mask) {
|
||||
if (!rs_i2c_bus_valid(bus) || (mask == 0U) || ((mask & ~RS_I2C_INTR_ALL) != 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
RS_I2C_REG(bus, RS_I2C_INTR_STATE_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_irq_test(rs_i2c_bus_t bus, uint32_t mask) {
|
||||
if (!rs_i2c_bus_valid(bus) || (mask == 0U) || ((mask & ~RS_I2C_INTR_ALL) != 0U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
RS_I2C_REG(bus, RS_I2C_INTR_TEST_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_write_dma(rs_i2c_bus_t bus, uint16_t address, bool ten_bit_address,
|
||||
const uint8_t *data, size_t length, rs_i2c_dma_workspace_t *workspace,
|
||||
rs_timeout_t timeout) {
|
||||
rs_status_t status;
|
||||
size_t index;
|
||||
const uint32_t mode = (bus == RS_I2C_BUS_0) ? RS_DMA_MODE_I2C0_TX : RS_DMA_MODE_I2C1_TX;
|
||||
|
||||
if (!rs_i2c_bus_valid(bus) || (data == NULL) || (workspace == NULL) || (length == 0U) ||
|
||||
(length > RS_I2C_DMA_MAX_BYTES)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
status = rs_i2c_prepare(bus, address, ten_bit_address, timeout);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
for (index = 0U; index < length; index++) {
|
||||
workspace->words[index] = (uint32_t)data[index];
|
||||
}
|
||||
workspace->words[length - 1U] |= RS_I2C_DATA_CMD_STOP;
|
||||
status = rs_dma_config(mode, (uintptr_t)&workspace->words[0], 1U,
|
||||
rs_i2c_base(bus) + RS_I2C_DATA_CMD_OFFSET, 0U, (uint32_t)length);
|
||||
if (status == RS_OK) {
|
||||
status = rs_dma_start();
|
||||
}
|
||||
if (status == RS_OK) {
|
||||
status = rs_dma_wait(timeout);
|
||||
}
|
||||
if (status == RS_OK) {
|
||||
status = rs_i2c_wait_done(bus, timeout);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_read_dma(rs_i2c_bus_t bus, uint16_t address, bool ten_bit_address, uint8_t *data,
|
||||
size_t length, rs_i2c_dma_workspace_t *workspace,
|
||||
rs_timeout_t timeout) {
|
||||
rs_status_t status;
|
||||
size_t index;
|
||||
const uint32_t mode = (bus == RS_I2C_BUS_0) ? RS_DMA_MODE_I2C0_RX : RS_DMA_MODE_I2C1_RX;
|
||||
|
||||
if (!rs_i2c_bus_valid(bus) || (data == NULL) || (workspace == NULL) || (length == 0U) ||
|
||||
(length > RS_I2C_DMA_MAX_BYTES)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
status = rs_i2c_prepare(bus, address, ten_bit_address, timeout);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
status = rs_dma_config(mode, rs_i2c_base(bus) + RS_I2C_RXDATA_OFFSET, 0U,
|
||||
(uintptr_t)&workspace->words[0], 1U, (uint32_t)length);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
for (index = 0U; index < length; index++) {
|
||||
uint32_t command = RS_I2C_DATA_CMD_READ;
|
||||
|
||||
workspace->words[index] = 0U;
|
||||
if ((index + 1U) == length) {
|
||||
command |= RS_I2C_DATA_CMD_STOP | RS_I2C_DATA_CMD_NACK_LAST;
|
||||
}
|
||||
RS_I2C_REG(bus, RS_I2C_DATA_CMD_OFFSET) = command;
|
||||
}
|
||||
status = rs_dma_start();
|
||||
if (status == RS_OK) {
|
||||
status = rs_dma_wait(timeout);
|
||||
}
|
||||
if (status == RS_OK) {
|
||||
status = rs_i2c_wait_done(bus, timeout);
|
||||
}
|
||||
if (status == RS_OK) {
|
||||
for (index = 0U; index < length; index++) {
|
||||
data[index] = (uint8_t)workspace->words[index];
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include <retrosoc/hal/i2c.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t maximum_hz;
|
||||
uint32_t low_ns;
|
||||
uint32_t high_ns;
|
||||
uint32_t start_hold_ns;
|
||||
uint32_t start_setup_ns;
|
||||
uint32_t data_setup_ns;
|
||||
uint32_t stop_setup_ns;
|
||||
uint32_t bus_free_ns;
|
||||
} rs_i2c_mode_t;
|
||||
|
||||
static uint64_t rs_i2c_divide_ceil(uint64_t dividend, uint64_t divisor) {
|
||||
return (dividend + divisor - UINT64_C(1)) / divisor;
|
||||
}
|
||||
|
||||
static uint64_t rs_i2c_cycles_from_ns(uint32_t source_clock_hz, uint32_t period_ns) {
|
||||
return rs_i2c_divide_ceil((uint64_t)source_clock_hz * (uint64_t)period_ns,
|
||||
UINT64_C(1000000000));
|
||||
}
|
||||
|
||||
static rs_i2c_mode_t rs_i2c_mode_for_rate(uint32_t bus_hz) {
|
||||
rs_i2c_mode_t mode;
|
||||
|
||||
if (bus_hz <= UINT32_C(100000)) {
|
||||
mode = (rs_i2c_mode_t){UINT32_C(100000), UINT32_C(4700), UINT32_C(4000), UINT32_C(4000),
|
||||
UINT32_C(4700), UINT32_C(250), UINT32_C(4000), UINT32_C(4700)};
|
||||
} else if (bus_hz <= UINT32_C(400000)) {
|
||||
mode = (rs_i2c_mode_t){UINT32_C(400000), UINT32_C(1300), UINT32_C(600), UINT32_C(600),
|
||||
UINT32_C(600), UINT32_C(100), UINT32_C(600), UINT32_C(1300)};
|
||||
} else {
|
||||
mode = (rs_i2c_mode_t){UINT32_C(1000000), UINT32_C(500), UINT32_C(260), UINT32_C(260),
|
||||
UINT32_C(260), UINT32_C(50), UINT32_C(260), UINT32_C(500)};
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
rs_status_t rs_i2c_timing_calculate(uint32_t source_clock_hz, uint32_t bus_hz,
|
||||
rs_i2c_timing_t *timing) {
|
||||
rs_i2c_mode_t mode;
|
||||
uint64_t low_cycles;
|
||||
uint64_t high_cycles;
|
||||
uint64_t target_cycles;
|
||||
uint64_t start_hold_cycles;
|
||||
uint64_t start_setup_cycles;
|
||||
uint64_t data_setup_cycles;
|
||||
uint64_t stop_setup_cycles;
|
||||
uint64_t bus_free_cycles;
|
||||
|
||||
if ((source_clock_hz == 0U) || (bus_hz == 0U) || (bus_hz > UINT32_C(1000000)) ||
|
||||
(timing == NULL)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
mode = rs_i2c_mode_for_rate(bus_hz);
|
||||
if (bus_hz > mode.maximum_hz) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
low_cycles = rs_i2c_cycles_from_ns(source_clock_hz, mode.low_ns);
|
||||
high_cycles = rs_i2c_cycles_from_ns(source_clock_hz, mode.high_ns);
|
||||
target_cycles = rs_i2c_divide_ceil((uint64_t)source_clock_hz, (uint64_t)bus_hz);
|
||||
if ((low_cycles + high_cycles) < target_cycles) {
|
||||
low_cycles += target_cycles - (low_cycles + high_cycles);
|
||||
}
|
||||
start_hold_cycles = rs_i2c_cycles_from_ns(source_clock_hz, mode.start_hold_ns);
|
||||
start_setup_cycles = rs_i2c_cycles_from_ns(source_clock_hz, mode.start_setup_ns);
|
||||
data_setup_cycles = rs_i2c_cycles_from_ns(source_clock_hz, mode.data_setup_ns);
|
||||
stop_setup_cycles = rs_i2c_cycles_from_ns(source_clock_hz, mode.stop_setup_ns);
|
||||
bus_free_cycles = rs_i2c_cycles_from_ns(source_clock_hz, mode.bus_free_ns);
|
||||
if ((low_cycles == 0U) || (high_cycles == 0U) || (start_hold_cycles == 0U) ||
|
||||
(start_setup_cycles == 0U) || (data_setup_cycles == 0U) || (stop_setup_cycles == 0U) ||
|
||||
(bus_free_cycles == 0U) || (low_cycles > UINT16_MAX) || (high_cycles > UINT16_MAX) ||
|
||||
(start_hold_cycles > UINT16_MAX) || (start_setup_cycles > UINT16_MAX) ||
|
||||
(data_setup_cycles > UINT16_MAX) || (stop_setup_cycles > UINT16_MAX) ||
|
||||
(bus_free_cycles > UINT16_MAX)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
timing->scl_low_cycles = (uint16_t)low_cycles;
|
||||
timing->scl_high_cycles = (uint16_t)high_cycles;
|
||||
timing->start_hold_cycles = (uint16_t)start_hold_cycles;
|
||||
timing->start_setup_cycles = (uint16_t)start_setup_cycles;
|
||||
timing->data_hold_cycles = 0U;
|
||||
timing->data_setup_cycles = (uint16_t)data_setup_cycles;
|
||||
timing->stop_setup_cycles = (uint16_t)stop_setup_cycles;
|
||||
timing->bus_free_cycles = (uint16_t)bus_free_cycles;
|
||||
return RS_OK;
|
||||
}
|
||||
@@ -103,7 +103,8 @@ void rs_app_info(void) {
|
||||
(void *)(uintptr_t)RS_SOC_RIBP_TIM0_BASE, (void *)(uintptr_t)RS_SOC_RIBP_TIM1_BASE);
|
||||
printf(" 1 x PSRAM @%p\n", (void *)®_psram_wait);
|
||||
printf(" 1 x SPISD @%p\n", (void *)®_spisd_mode);
|
||||
printf(" 1 x I2C0 @%p\n", (void *)®_i2c0_clkdiv);
|
||||
printf(" 1 x I2C0 @%p\n",
|
||||
(void *)(uintptr_t)RS_SOC_RIBP_I2C0_BASE);
|
||||
printf(" 1 x I2S @%p\n", (void *)®_i2s_mode);
|
||||
printf(" 1 x WS2812 @%p\n", (void *)®_ws2812_bit_cycles);
|
||||
printf(" 1 x XPI @%p\n", (void *)®_xpi_cfgidx);
|
||||
@@ -113,7 +114,8 @@ void rs_app_info(void) {
|
||||
(void *)(uintptr_t)RS_SOC_RIBP_CLINT_BASE);
|
||||
printf(" 1 x SDRAM @%p\n", (void *)®_sdram_clkdiv);
|
||||
printf(" 1 x DVP @%p\n", (void *)®_dvp_recven);
|
||||
printf(" 1 x I2C1 @%p\n", (void *)®_i2c1_clkdiv);
|
||||
printf(" 1 x I2C1 @%p\n",
|
||||
(void *)(uintptr_t)RS_SOC_RIBP_I2C1_BASE);
|
||||
printf(" 1 x ARCHINFO @%p\n", (void *)®_archinfo_sys);
|
||||
printf(" 1 x RNG @%p\n", (void *)®_rng_ctrl);
|
||||
printf(" 1 x UART1(ADV) @%p\n", (void *)®_uart1_lcr);
|
||||
|
||||
@@ -30,6 +30,8 @@ the root README and subsystem guides.
|
||||
filtering, interrupts, PDK capabilities, HAL, and verification contract.
|
||||
- [ip/uart.md](ip/uart.md) defines the UART V2 framing, FIFO, error, interrupt,
|
||||
DMA, HAL, and verification contracts.
|
||||
- [ip/i2c.md](ip/i2c.md) defines the dual I2C V2 command, timing, error,
|
||||
recovery, DMA, HAL, and verification contracts.
|
||||
- [soc-integration-wiring.md](soc-integration-wiring.md) defines the generated
|
||||
pin-map workflow and SoC integration boundary.
|
||||
- [mini-soc-block-diagram.svg](mini-soc-block-diagram.svg) is the Mini SoC
|
||||
|
||||
+12
-3
@@ -131,10 +131,11 @@ Verilator regressions.
|
||||
`make CONFIG=configs/ci/ihp130.mk formal` proves selected
|
||||
protocol invariants with SymbiYosys, Yosys, `sv2v`, and Bitwuzla. The current
|
||||
targets are `bus`, `rib_adapter`, `rib2apb`, `sysctrl`, `pll_rcu`, `gpio`,
|
||||
`ws2812`, `uart`, `timer`, and `clint`; each uses the SBY `prove` task for bounded model
|
||||
`ws2812`, `uart`, `i2c`, `timer`, and `clint`; each uses the SBY `prove` task for bounded model
|
||||
checking and k-induction, plus a `cover` task. The default depth is 20;
|
||||
`ws2812` uses depth 120 and a 120-second per-task limit to cover a complete
|
||||
serialized word and reset path. `sysctrl` checks register side effects, sticky terminal-test status, PLL request
|
||||
serialized word and reset path. `i2c` uses depth 80 and a 300-second per-task
|
||||
limit to reach a complete receive path and export its witness. `sysctrl` checks register side effects, sticky terminal-test status, PLL request
|
||||
handling, and fault reporting. `pll_rcu` checks the clock-switch controller
|
||||
state machine. `gpio` checks dual-window access isolation, fixed user-GPIO
|
||||
ownership, locks, handoff, open-drain safety, and mux behavior. `rib_adapter`
|
||||
@@ -142,12 +143,20 @@ checks both single-word compatibility adapters
|
||||
under backpressure. `ws2812` checks RIBP response stability, FIFO bounds,
|
||||
waveform idle safety, sticky error and interrupt propagation, abort, and
|
||||
underflow preconditions. `uart` checks FIFO bounds, interrupt composition,
|
||||
DMA gating, and idle/break line safety. Direct Common utility proofs, including `spill_register`,
|
||||
DMA gating, and idle/break line safety. `i2c` checks FIFO bounds, interrupt
|
||||
composition, valid command consumption, open-drain idle safety, and recovery
|
||||
state consistency. Direct Common utility proofs, including `spill_register`,
|
||||
are maintained in the Common repository.
|
||||
`FORMAL_DEPTH` and `FORMAL_TIMEOUT` set the proof bound and per-task
|
||||
wall-clock limit. Use `make CONFIG=<profile> formal-doctor` before a local
|
||||
proof to verify that the required tools are available.
|
||||
|
||||
The I2C cover task stores the compact Yosys witness, constraints, and Verilog
|
||||
testbench but disables direct VCD output. Expanding the 70-cycle receive cover
|
||||
to VCD produces hundreds of MiB and can exceed the task limit on networked
|
||||
filesystems; the witness remains available for an explicit trace conversion
|
||||
when waveform inspection is required.
|
||||
|
||||
The locked Bitwuzla 0.9.1 CLI uses `--lang smt2`, while the selected Yosys
|
||||
version invokes legacy Bitwuzla options. `scripts/bitwuzla_smt2.py` is the
|
||||
single compatibility adapter used by SBY; it translates only solver startup
|
||||
|
||||
@@ -8,6 +8,7 @@ verification documentation for self-owned retroSoC peripheral IP.
|
||||
- [clint.md](clint.md) defines the management-hart software and timer interrupt block.
|
||||
- [gpio.md](gpio.md) defines the dual-window GPIO controller.
|
||||
- [uart.md](uart.md) defines the RIBP UART V2 controller.
|
||||
- [i2c.md](i2c.md) defines the dual RIBP I2C V2 controllers.
|
||||
|
||||
The corresponding RTL and HAL implementations remain the executable sources
|
||||
of truth. Update the affected document whenever an IP interface or register ABI
|
||||
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
# RIBP I2C V2
|
||||
|
||||
The Mini SoC provides two independent controller-mode I2C instances. I2C V2
|
||||
implements 7-bit and 10-bit addressing, queued write and read commands,
|
||||
repeated START, clock stretching, multi-controller arbitration detection,
|
||||
programmable digital input filtering, bounded waits, bus recovery, interrupts,
|
||||
and generic-DMA pacing. The register ABI is directly encoded in RTL and C; a
|
||||
register generator is intentionally not used in this version.
|
||||
|
||||
The electrical and timing behavior follows the controller requirements in the
|
||||
[NXP UM10204 I2C-bus specification](https://www.nxp.com/docs/en/user-guide/UM10204.pdf).
|
||||
The FIFO command model and explicit error, timeout, and recovery reporting
|
||||
follow common commercial controller practice without copying another IP ABI.
|
||||
|
||||
## Integration
|
||||
|
||||
| Property | I2C0 | I2C1 |
|
||||
| --- | --- | --- |
|
||||
| RIBP base address | `0x10006000` | `0x10011000` |
|
||||
| Command / RX FIFO depth | 16 / 16 | 16 / 16 |
|
||||
| GPIO alternate function | GPIO7/8 ALT0 | GPIO3/4 ALT1 |
|
||||
| RIBP interrupt group bit | 7 | 12 |
|
||||
| Management-core interrupt | 7 | 19 |
|
||||
| DMA TX/RX modes | 7 / 8 | 9 / 10 |
|
||||
|
||||
Both instances and the generic DMA run in the SoC clock domain. Each pad uses
|
||||
open-drain signaling: the controller output value is permanently zero and its
|
||||
output enable means pull the line low. External pull-ups are required. The GPIO
|
||||
HAL selects the corresponding alternate function and open-drain mode during
|
||||
I2C configuration.
|
||||
|
||||
## Architecture
|
||||
|
||||
`ribp_i2c` composes four implementation blocks:
|
||||
|
||||
- `i2c_reg` owns the RIBP ABI, command and receive FIFOs, sticky error and
|
||||
interrupt state, capability discovery, and DMA pacing.
|
||||
- `i2c_filter` synchronizes SCL and SDA with the Common `cdc_sync` component
|
||||
and changes each filtered value only after its programmed stability period.
|
||||
- `i2c_core` executes START, address, data, ACK/NACK, repeated START, STOP, and
|
||||
nine-clock recovery sequences. Common register components hold all protocol
|
||||
state.
|
||||
- `i2c_if` remains the ClusterIP boundary between controller logic and GPIO
|
||||
alternate-function integration.
|
||||
|
||||
Software queues one 12-bit command per transferred byte. The engine owns the
|
||||
bus across adjacent commands and enters a bounded hold state when the command
|
||||
FIFO temporarily empties. A direction change or explicit `RESTART` emits a
|
||||
repeated START without an intervening STOP. A read command pushes one byte into
|
||||
the receive FIFO. The last read before STOP must set `NACK_LAST`.
|
||||
|
||||
## Register ABI
|
||||
|
||||
All registers are 32-bit and naturally aligned. Unmapped, unaligned,
|
||||
direction-invalid, reserved-field, and semantically illegal accesses complete
|
||||
with `resp_err`. RW configuration registers support byte strobes. Timing,
|
||||
filter, and timeout registers can change only while the controller is disabled
|
||||
and idle.
|
||||
|
||||
| Offset | Name | Access | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `0x000` | `CTRL` | RW | Bit 0 enables the controller after valid timing is installed. |
|
||||
| `0x004` | `SCL_TIMING` | RW | SCL low cycles at 15:0 and high cycles at 31:16. |
|
||||
| `0x008` | `START_TIMING` | RW | START hold cycles at 15:0 and setup cycles at 31:16. |
|
||||
| `0x00C` | `DATA_TIMING` | RW | Data hold cycles at 15:0 and setup cycles at 31:16. |
|
||||
| `0x010` | `STOP_TIMING` | RW | STOP setup cycles at 15:0 and bus-free cycles at 31:16. |
|
||||
| `0x014` | `FILTER` | RW | SCL filter cycles at 3:0 and SDA filter cycles at 11:8. |
|
||||
| `0x018` | `STRETCH_TIMEOUT` | RW | Maximum SCL-low stretch wait in SoC clocks; zero disables. |
|
||||
| `0x01C` | `BUS_IDLE_TIMEOUT` | RW | Maximum bus-idle or bus-free wait; zero disables. |
|
||||
| `0x020` | `COMMAND_TIMEOUT` | RW | Maximum active-command time; zero disables. |
|
||||
| `0x024` | `TARGET_ADDR` | RW | Address at 9:0; bit 10 selects 10-bit addressing. |
|
||||
| `0x028` | `DATA_CMD` | WO/push | Data at 7:0; READ, RESTART, STOP, NACK_LAST at bits 8 through 11. |
|
||||
| `0x02C` | `RXDATA` | RO/pop | Pop one received byte; an empty read returns `resp_err`. |
|
||||
| `0x030` | `STATUS` | RO | Enable, activity, FIFO, line, configuration, recovery, and DMA state. |
|
||||
| `0x034` | `FIFO_LEVEL` | RO | Command count at 7:0 and receive count at 23:16. |
|
||||
| `0x038` | `COMMAND` | WO | Bits 0 through 3 request abort, recovery, command flush, and RX flush. |
|
||||
| `0x03C` | `CMD_WATERMARK` | RW | Command low-water threshold, 0 through 15; reset value 4. |
|
||||
| `0x040` | `RX_WATERMARK` | RW | Receive high-water threshold, 1 through 16; reset value 8. |
|
||||
| `0x044` | `ERROR_STATUS` | RW1C | Sticky protocol, timeout, overflow, configuration, abort, and recovery errors. |
|
||||
| `0x048` | `INTR_STATE` | RW1C | Sticky raw interrupt state; active watermarks reassert after clear. |
|
||||
| `0x04C` | `INTR_ENABLE` | RW | Interrupt enable mask. |
|
||||
| `0x050` | `INTR_STATUS` | RO | `INTR_STATE & INTR_ENABLE`. |
|
||||
| `0x054` | `INTR_TEST` | WO | Write-one interrupt injection. |
|
||||
| `0x058` | `LINE_STATE` | RO | Filtered SCL, SDA, and bus-free state at bits 0 through 2. |
|
||||
| `0x0F8` | `IP_VERSION` | RO | `0x00020000`, ABI 2.0. |
|
||||
| `0x0FC` | `CAPABILITY` | RO | `0x007F1010`, feature mask and FIFO depths. |
|
||||
|
||||
`STATUS` bits 0 through 12 report enable, controller busy, external bus busy,
|
||||
command empty/full, RX empty/full, valid configuration, recovery active, SCL,
|
||||
SDA, TX DMA request, and RX DMA request.
|
||||
|
||||
`ERROR_STATUS` bits 0 through 10 report address NACK, data NACK, arbitration
|
||||
loss, stretch timeout, bus timeout, command timeout, malformed command, RX
|
||||
overflow, invalid configuration, abort, and failed recovery. Error and event
|
||||
state is sticky, with a newly observed event taking priority over a concurrent
|
||||
software clear.
|
||||
|
||||
`INTR_STATE` bits 0 through 7 report transfer done, command watermark, RX
|
||||
watermark, NACK, arbitration loss, timeout, aggregate error, and recovery done.
|
||||
The external interrupt is the reduction OR of enabled state.
|
||||
|
||||
## Protocol and failure behavior
|
||||
|
||||
For 7-bit transfers, the engine sends the target address and direction bit.
|
||||
For 10-bit writes it sends the write header and low address byte. A 10-bit read
|
||||
first sends that write-form address, issues a repeated START, then sends the
|
||||
read header. Arbitration is checked whenever the controller releases SDA for a
|
||||
transmitted one; observing low ends the transfer, releases both lines, flushes
|
||||
pending commands, and records `ARB_LOST`.
|
||||
|
||||
The engine waits for synchronized SCL high, so target clock stretching is
|
||||
honored on address, data, ACK, STOP, and recovery phases. Independent stretch,
|
||||
bus, and active-command watchdogs prevent a faulty target or missing command
|
||||
from holding the controller indefinitely. Software can abort an active
|
||||
transfer. Recovery generates nine SCL pulses followed by STOP and reports
|
||||
success only after both lines remain high for the programmed bus-free period.
|
||||
|
||||
## Timing, DMA, and software
|
||||
|
||||
`rs_i2c_timing_calculate()` converts the source clock and requested bus rate
|
||||
into integer cycle constraints using 64-bit ceiling arithmetic. It supports
|
||||
Standard-mode through 100 kHz, Fast-mode through 400 kHz, and Fast-mode Plus
|
||||
through 1 MHz. It enforces the mode-specific minimum low, high, START, data,
|
||||
STOP, and bus-free intervals rather than programming only a nominal divider.
|
||||
|
||||
The public HAL exposes structured configuration, 7-bit and 10-bit combined
|
||||
transfers, abort, nine-clock recovery, status, interrupt control, and bounded
|
||||
waits. Register-oriented devices use `rs_i2c_register_read()` and
|
||||
`rs_i2c_register_write()` with an `rs_i2c_register_access_t` descriptor. The
|
||||
descriptor explicitly selects I2C target address width and 8-bit or 16-bit
|
||||
register addressing, while the API selects I2C0 or I2C1 independently. The
|
||||
retired fixed-I2C0 compatibility API is not retained. All operations that can
|
||||
wait take a timeout and return `rs_status_t`.
|
||||
|
||||
DMA moves one 32-bit word per command or received byte through the fixed
|
||||
`DATA_CMD` and `RXDATA` addresses. The initial DMA API deliberately limits a
|
||||
transfer to 16 bytes because one generic DMA channel cannot refill commands or
|
||||
drain RX concurrently beyond the hardware FIFO proof boundary. Longer and
|
||||
combined transfers use the bounded CPU streaming API. Removing this limit
|
||||
requires scatter/gather or linked DMA descriptors and an end-to-end overflow
|
||||
proof.
|
||||
|
||||
## Verification and current scope
|
||||
|
||||
The self-checking RTL test covers ABI discovery and access errors, 7-bit write,
|
||||
7-bit combined write/repeated-START read, 10-bit read, clock stretching, address NACK,
|
||||
arbitration loss, and nine-clock recovery. The SBY target proves FIFO bounds,
|
||||
IRQ composition, valid command consumption, idle open-drain release, and
|
||||
recovery/busy consistency; 80-cycle covers reach RIBP errors, TX and RX data
|
||||
paths, DMA pacing, activity, recovery, interrupt, and error state. Deep cover
|
||||
results retain a compact Yosys witness instead of automatically expanding a
|
||||
hundreds-of-MiB VCD. Host C tests cover exact timing conversion and invalid
|
||||
timing ranges.
|
||||
|
||||
Target/peripheral mode, SMBus/PMBus extensions, High-speed mode, wakeup from a
|
||||
separate low-power clock, and multi-controller fairness policy are outside I2C
|
||||
V2. Adding one requires a versioned ABI, explicit clock/reset and pad review,
|
||||
and dedicated protocol verification.
|
||||
@@ -128,12 +128,16 @@ digraph mini_soc_block_diagram {
|
||||
];
|
||||
ribp_targets [
|
||||
fillcolor="#F9E1E7",
|
||||
label="RIBP target wrapper\nXPI/Flash, SDRAM, PSRAM, SPI-SD and DVP\nI2C and I2S"
|
||||
label="RIBP target wrapper\nXPI/Flash, SDRAM, PSRAM, SPI-SD and DVP\nI2S"
|
||||
];
|
||||
uart0 [
|
||||
fillcolor="#F9E1E7",
|
||||
label="UART0 V2\n64-byte TX/RX FIFOs, fractional baud\nframing/errors, IRQ2, DMA-paced"
|
||||
];
|
||||
i2c_controllers [
|
||||
fillcolor="#F9E1E7",
|
||||
label="I2C0 / I2C1 V2\n16-entry command/RX FIFOs, Sm/Fm/Fm+\n7/10-bit, IRQ7/19, DMA-paced"
|
||||
];
|
||||
gpio_controller [
|
||||
fillcolor="#F9E1E7",
|
||||
label="GPIO V2\nuser + management RIBP windows\natomic I/O, filter, locks, IRQ18"
|
||||
@@ -165,7 +169,7 @@ digraph mini_soc_block_diagram {
|
||||
{ rank=same; user_core; dma; }
|
||||
{ rank=same; fault; fabric; sram; }
|
||||
{ rank=same; ribp_adapter; apb_adapter; }
|
||||
{ rank=same; sysctrl; clint; ribp_targets; uart0; gpio_controller; timers; ws2812; apb_targets; }
|
||||
{ rank=same; sysctrl; clint; ribp_targets; uart0; i2c_controllers; gpio_controller; timers; ws2812; apb_targets; }
|
||||
{ rank=same; gpio_bridge; irq; }
|
||||
|
||||
ext_clock -> rcu [label="clock / reset"];
|
||||
@@ -191,6 +195,7 @@ digraph mini_soc_block_diagram {
|
||||
ribp_adapter -> clint [label="RIBP"];
|
||||
ribp_adapter -> ribp_targets [label="RIBP"];
|
||||
ribp_adapter -> uart0 [label="RIBP"];
|
||||
ribp_adapter -> i2c_controllers [label="RIBP"];
|
||||
ribp_adapter -> gpio_controller [label="RIBP\nuser/admin"];
|
||||
ribp_adapter -> timers [label="RIBP"];
|
||||
ribp_adapter -> ws2812 [label="RIBP"];
|
||||
@@ -206,6 +211,9 @@ digraph mini_soc_block_diagram {
|
||||
ws2812 -> irq [label="IRQ17"];
|
||||
dma -> uart0 [label="TX/RX data", style=dashed];
|
||||
uart0 -> irq [label="IRQ2"];
|
||||
i2c_controllers -> gpio_controller [label="GPIO3/4 ALT1\nGPIO7/8 ALT0"];
|
||||
dma -> i2c_controllers [label="DATA_CMD / RXDATA", style=dashed];
|
||||
i2c_controllers -> irq [label="IRQ7 / IRQ19"];
|
||||
apb_targets -> gpio_controller [label="user_gpio"];
|
||||
ribp_targets -> ext_io [dir=both, label="device interfaces"];
|
||||
uart0 -> ext_io [dir=both, label="UART pads"];
|
||||
|
||||
+253
-216
@@ -4,19 +4,19 @@
|
||||
<!-- Generated by graphviz version 2.43.0 (0)
|
||||
-->
|
||||
<!-- Title: mini_soc_block_diagram Pages: 1 -->
|
||||
<svg width="2197pt" height="896pt"
|
||||
viewBox="0.00 0.00 2197.00 896.48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<svg width="2433pt" height="896pt"
|
||||
viewBox="0.00 0.00 2433.00 896.48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 892.48)">
|
||||
<title>mini_soc_block_diagram</title>
|
||||
<text text-anchor="middle" x="132" y="-870.08" font-family="Arial" font-size="18.00">retroSoC Mini SoC Architecture</text>
|
||||
<g id="clust1" class="cluster">
|
||||
<title>cluster_asic</title>
|
||||
<path fill="transparent" stroke="#111827" d="M160,-85C160,-85 2169,-85 2169,-85 2175,-85 2181,-91 2181,-97 2181,-97 2181,-772.48 2181,-772.48 2181,-778.48 2175,-784.48 2169,-784.48 2169,-784.48 160,-784.48 160,-784.48 154,-784.48 148,-778.48 148,-772.48 148,-772.48 148,-97 148,-97 148,-91 154,-85 160,-85"/>
|
||||
<path fill="transparent" stroke="#111827" d="M160,-85C160,-85 2405,-85 2405,-85 2411,-85 2417,-91 2417,-97 2417,-97 2417,-772.48 2417,-772.48 2417,-778.48 2411,-784.48 2405,-784.48 2405,-784.48 160,-784.48 160,-784.48 154,-784.48 148,-778.48 148,-772.48 148,-772.48 148,-97 148,-97 148,-91 154,-85 160,-85"/>
|
||||
<text text-anchor="middle" x="196.5" y="-769.28" font-family="Arial" font-size="14.00" fill="#111827">retrosoc_asic</text>
|
||||
</g>
|
||||
<g id="clust2" class="cluster">
|
||||
<title>cluster_soc</title>
|
||||
<path fill="transparent" stroke="#94a3b8" stroke-dasharray="5,2" d="M390,-103C390,-103 2151,-103 2151,-103 2157,-103 2163,-109 2163,-115 2163,-115 2163,-729.48 2163,-729.48 2163,-735.48 2157,-741.48 2151,-741.48 2151,-741.48 390,-741.48 390,-741.48 384,-741.48 378,-735.48 378,-729.48 378,-729.48 378,-115 378,-115 378,-109 384,-103 390,-103"/>
|
||||
<path fill="transparent" stroke="#94a3b8" stroke-dasharray="5,2" d="M390,-103C390,-103 2387,-103 2387,-103 2393,-103 2399,-109 2399,-115 2399,-115 2399,-729.48 2399,-729.48 2399,-735.48 2393,-741.48 2387,-741.48 2387,-741.48 390,-741.48 390,-741.48 384,-741.48 378,-735.48 378,-729.48 378,-729.48 378,-115 378,-115 378,-109 384,-103 390,-103"/>
|
||||
<text text-anchor="middle" x="407.5" y="-727.88" font-family="Arial" font-size="12.00" fill="#334155">retrosoc</text>
|
||||
</g>
|
||||
<!-- ext_clock -->
|
||||
@@ -44,46 +44,46 @@
|
||||
<!-- ext_io -->
|
||||
<g id="node2" class="node">
|
||||
<title>ext_io</title>
|
||||
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M1678,-45C1678,-45 1486,-45 1486,-45 1480,-45 1474,-39 1474,-33 1474,-33 1474,-12 1474,-12 1474,-6 1480,0 1486,0 1486,0 1678,0 1678,0 1684,0 1690,-6 1690,-12 1690,-12 1690,-33 1690,-33 1690,-39 1684,-45 1678,-45"/>
|
||||
<text text-anchor="middle" x="1582" y="-31" font-family="Arial" font-size="10.00" fill="#111827">External I/O and memory</text>
|
||||
<text text-anchor="middle" x="1582" y="-20" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, XPI Flash, SDRAM, PSRAM</text>
|
||||
<text text-anchor="middle" x="1582" y="-9" font-family="Arial" font-size="10.00" fill="#111827">SD card, I2C, I2S, DVP and WS2812</text>
|
||||
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M2045,-45C2045,-45 1853,-45 1853,-45 1847,-45 1841,-39 1841,-33 1841,-33 1841,-12 1841,-12 1841,-6 1847,0 1853,0 1853,0 2045,0 2045,0 2051,0 2057,-6 2057,-12 2057,-12 2057,-33 2057,-33 2057,-39 2051,-45 2045,-45"/>
|
||||
<text text-anchor="middle" x="1949" y="-31" font-family="Arial" font-size="10.00" fill="#111827">External I/O and memory</text>
|
||||
<text text-anchor="middle" x="1949" y="-20" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, XPI Flash, SDRAM, PSRAM</text>
|
||||
<text text-anchor="middle" x="1949" y="-9" font-family="Arial" font-size="10.00" fill="#111827">SD card, I2C, I2S, DVP and WS2812</text>
|
||||
</g>
|
||||
<!-- ext_jtag -->
|
||||
<g id="node3" class="node">
|
||||
<title>ext_jtag</title>
|
||||
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M777.5,-860.48C777.5,-860.48 646.5,-860.48 646.5,-860.48 640.5,-860.48 634.5,-854.48 634.5,-848.48 634.5,-848.48 634.5,-836.48 634.5,-836.48 634.5,-830.48 640.5,-824.48 646.5,-824.48 646.5,-824.48 777.5,-824.48 777.5,-824.48 783.5,-824.48 789.5,-830.48 789.5,-836.48 789.5,-836.48 789.5,-848.48 789.5,-848.48 789.5,-854.48 783.5,-860.48 777.5,-860.48"/>
|
||||
<text text-anchor="middle" x="712" y="-845.48" font-family="Arial" font-size="10.00" fill="#111827">Management JTAG</text>
|
||||
<text text-anchor="middle" x="712" y="-834.48" font-family="Arial" font-size="10.00" fill="#111827">TCK, TMS, TDI, TRST_n, TDO</text>
|
||||
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M700.5,-860.48C700.5,-860.48 569.5,-860.48 569.5,-860.48 563.5,-860.48 557.5,-854.48 557.5,-848.48 557.5,-848.48 557.5,-836.48 557.5,-836.48 557.5,-830.48 563.5,-824.48 569.5,-824.48 569.5,-824.48 700.5,-824.48 700.5,-824.48 706.5,-824.48 712.5,-830.48 712.5,-836.48 712.5,-836.48 712.5,-848.48 712.5,-848.48 712.5,-854.48 706.5,-860.48 700.5,-860.48"/>
|
||||
<text text-anchor="middle" x="635" y="-845.48" font-family="Arial" font-size="10.00" fill="#111827">Management JTAG</text>
|
||||
<text text-anchor="middle" x="635" y="-834.48" font-family="Arial" font-size="10.00" fill="#111827">TCK, TMS, TDI, TRST_n, TDO</text>
|
||||
</g>
|
||||
<!-- jtag_dtm -->
|
||||
<g id="node6" class="node">
|
||||
<title>jtag_dtm</title>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M787,-678.98C787,-678.98 637,-678.98 637,-678.98 631,-678.98 625,-672.98 625,-666.98 625,-666.98 625,-654.98 625,-654.98 625,-648.98 631,-642.98 637,-642.98 637,-642.98 787,-642.98 787,-642.98 793,-642.98 799,-648.98 799,-654.98 799,-654.98 799,-666.98 799,-666.98 799,-672.98 793,-678.98 787,-678.98"/>
|
||||
<text text-anchor="middle" x="712" y="-663.98" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 JTAG DTM</text>
|
||||
<text text-anchor="middle" x="712" y="-652.98" font-family="Arial" font-size="10.00" fill="#111827">10 MHz asynchronous TCK domain</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M710,-678.98C710,-678.98 560,-678.98 560,-678.98 554,-678.98 548,-672.98 548,-666.98 548,-666.98 548,-654.98 548,-654.98 548,-648.98 554,-642.98 560,-642.98 560,-642.98 710,-642.98 710,-642.98 716,-642.98 722,-648.98 722,-654.98 722,-654.98 722,-666.98 722,-666.98 722,-672.98 716,-678.98 710,-678.98"/>
|
||||
<text text-anchor="middle" x="635" y="-663.98" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 JTAG DTM</text>
|
||||
<text text-anchor="middle" x="635" y="-652.98" font-family="Arial" font-size="10.00" fill="#111827">10 MHz asynchronous TCK domain</text>
|
||||
</g>
|
||||
<!-- ext_jtag->jtag_dtm -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>ext_jtag->jtag_dtm</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M712,-824.27C712,-792.24 712,-723.39 712,-686.51"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="714.45,-686.14 712,-679.14 709.55,-686.14 714.45,-686.14"/>
|
||||
<text text-anchor="middle" x="732" y="-795.08" font-family="Arial" font-size="8.00" fill="#374151">JTAG pads</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M635,-824.27C635,-792.24 635,-723.39 635,-686.51"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="637.45,-686.14 635,-679.14 632.55,-686.14 637.45,-686.14"/>
|
||||
<text text-anchor="middle" x="655" y="-795.08" font-family="Arial" font-size="8.00" fill="#374151">JTAG pads</text>
|
||||
</g>
|
||||
<!-- fabric -->
|
||||
<g id="node11" class="node">
|
||||
<title>fabric</title>
|
||||
<path fill="#dcecf8" stroke="#4b5563" stroke-width="1.1" d="M1083.66,-451.31C1083.66,-451.31 1015.98,-479.16 1015.98,-479.16 1010.43,-481.45 998.88,-483.73 992.88,-483.73 992.88,-483.73 837.12,-483.73 837.12,-483.73 831.12,-483.73 819.57,-481.45 814.02,-479.16 814.02,-479.16 746.34,-451.31 746.34,-451.31 740.79,-449.03 740.79,-444.46 746.34,-442.18 746.34,-442.18 814.02,-414.32 814.02,-414.32 819.57,-412.04 831.12,-409.76 837.12,-409.76 837.12,-409.76 992.88,-409.76 992.88,-409.76 998.88,-409.76 1010.43,-412.04 1015.98,-414.32 1015.98,-414.32 1083.66,-442.18 1083.66,-442.18 1089.21,-444.46 1089.21,-449.03 1083.66,-451.31"/>
|
||||
<text text-anchor="middle" x="915" y="-455.24" font-family="Arial" font-size="10.00" fill="#111827">RIB fabric</text>
|
||||
<text text-anchor="middle" x="915" y="-444.24" font-family="Arial" font-size="10.00" fill="#111827">3-master round-robin arbitration</text>
|
||||
<text text-anchor="middle" x="915" y="-433.24" font-family="Arial" font-size="10.00" fill="#111827">INCR1 / INCR4, access policy, fault reporting</text>
|
||||
<path fill="#dcecf8" stroke="#4b5563" stroke-width="1.1" d="M1327.66,-451.31C1327.66,-451.31 1259.98,-479.16 1259.98,-479.16 1254.43,-481.45 1242.88,-483.73 1236.88,-483.73 1236.88,-483.73 1081.12,-483.73 1081.12,-483.73 1075.12,-483.73 1063.57,-481.45 1058.02,-479.16 1058.02,-479.16 990.34,-451.31 990.34,-451.31 984.79,-449.03 984.79,-444.46 990.34,-442.18 990.34,-442.18 1058.02,-414.32 1058.02,-414.32 1063.57,-412.04 1075.12,-409.76 1081.12,-409.76 1081.12,-409.76 1236.88,-409.76 1236.88,-409.76 1242.88,-409.76 1254.43,-412.04 1259.98,-414.32 1259.98,-414.32 1327.66,-442.18 1327.66,-442.18 1333.21,-444.46 1333.21,-449.03 1327.66,-451.31"/>
|
||||
<text text-anchor="middle" x="1159" y="-455.24" font-family="Arial" font-size="10.00" fill="#111827">RIB fabric</text>
|
||||
<text text-anchor="middle" x="1159" y="-444.24" font-family="Arial" font-size="10.00" fill="#111827">3-master round-robin arbitration</text>
|
||||
<text text-anchor="middle" x="1159" y="-433.24" font-family="Arial" font-size="10.00" fill="#111827">INCR1 / INCR4, access policy, fault reporting</text>
|
||||
</g>
|
||||
<!-- rcu->fabric -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>rcu->fabric</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M362.03,-540.47C368.2,-539.24 372,-538.48 372,-538.48 372,-538.48 731,-483.48 731,-483.48 731,-483.48 755.75,-478.68 787.1,-472.59"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="787.92,-474.92 794.32,-471.18 786.98,-470.11 787.92,-474.92"/>
|
||||
<text text-anchor="middle" x="607" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">system clock / reset</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M362.03,-540.47C368.2,-539.24 372,-538.48 372,-538.48 372,-538.48 939,-483.48 939,-483.48 939,-483.48 978.82,-477.02 1024.57,-469.58"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1025.15,-471.97 1031.66,-468.43 1024.36,-467.13 1025.15,-471.97"/>
|
||||
<text text-anchor="middle" x="724" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">system clock / reset</text>
|
||||
</g>
|
||||
<!-- clint -->
|
||||
<g id="node17" class="node">
|
||||
@@ -96,273 +96,295 @@
|
||||
<!-- rcu->clint -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>rcu->clint</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M286.04,-538.33C353.25,-472.3 551,-278 551,-278 551,-278 590.26,-266.94 629.65,-255.85"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="630.4,-258.18 636.47,-253.93 629.07,-253.47 630.4,-258.18"/>
|
||||
<text text-anchor="middle" x="464.5" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">1 MHz tick</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M293.54,-538.31C372.58,-480.32 588.63,-321.81 673.81,-259.32"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="675.27,-261.28 679.47,-255.17 672.37,-257.33 675.27,-261.28"/>
|
||||
<text text-anchor="middle" x="525.5" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">1 MHz tick</text>
|
||||
</g>
|
||||
<!-- mgmt_core -->
|
||||
<g id="node5" class="node">
|
||||
<title>mgmt_core</title>
|
||||
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M992,-683.48C992,-683.48 838,-683.48 838,-683.48 832,-683.48 826,-677.48 826,-671.48 826,-671.48 826,-650.48 826,-650.48 826,-644.48 832,-638.48 838,-638.48 838,-638.48 992,-638.48 992,-638.48 998,-638.48 1004,-644.48 1004,-650.48 1004,-650.48 1004,-671.48 1004,-671.48 1004,-677.48 998,-683.48 992,-683.48"/>
|
||||
<text text-anchor="middle" x="915" y="-669.48" font-family="Arial" font-size="10.00" fill="#111827">Management core</text>
|
||||
<text text-anchor="middle" x="915" y="-658.48" font-family="Arial" font-size="10.00" fill="#111827">Fixed Hazard3, branch predictor</text>
|
||||
<text text-anchor="middle" x="915" y="-647.48" font-family="Arial" font-size="10.00" fill="#111827">JTAG Debug Module always present</text>
|
||||
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1295,-683.48C1295,-683.48 1141,-683.48 1141,-683.48 1135,-683.48 1129,-677.48 1129,-671.48 1129,-671.48 1129,-650.48 1129,-650.48 1129,-644.48 1135,-638.48 1141,-638.48 1141,-638.48 1295,-638.48 1295,-638.48 1301,-638.48 1307,-644.48 1307,-650.48 1307,-650.48 1307,-671.48 1307,-671.48 1307,-677.48 1301,-683.48 1295,-683.48"/>
|
||||
<text text-anchor="middle" x="1218" y="-669.48" font-family="Arial" font-size="10.00" fill="#111827">Management core</text>
|
||||
<text text-anchor="middle" x="1218" y="-658.48" font-family="Arial" font-size="10.00" fill="#111827">Fixed Hazard3, branch predictor</text>
|
||||
<text text-anchor="middle" x="1218" y="-647.48" font-family="Arial" font-size="10.00" fill="#111827">JTAG Debug Module always present</text>
|
||||
</g>
|
||||
<!-- mgmt_adapter -->
|
||||
<g id="node8" class="node">
|
||||
<title>mgmt_adapter</title>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M935.5,-578.98C935.5,-578.98 894.5,-578.98 894.5,-578.98 888.5,-578.98 882.5,-572.98 882.5,-566.98 882.5,-566.98 882.5,-554.98 882.5,-554.98 882.5,-548.98 888.5,-542.98 894.5,-542.98 894.5,-542.98 935.5,-542.98 935.5,-542.98 941.5,-542.98 947.5,-548.98 947.5,-554.98 947.5,-554.98 947.5,-566.98 947.5,-566.98 947.5,-572.98 941.5,-578.98 935.5,-578.98"/>
|
||||
<text text-anchor="middle" x="915" y="-558.48" font-family="Arial" font-size="10.00" fill="#111827">RIBP2RIB</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1179.5,-578.98C1179.5,-578.98 1138.5,-578.98 1138.5,-578.98 1132.5,-578.98 1126.5,-572.98 1126.5,-566.98 1126.5,-566.98 1126.5,-554.98 1126.5,-554.98 1126.5,-548.98 1132.5,-542.98 1138.5,-542.98 1138.5,-542.98 1179.5,-542.98 1179.5,-542.98 1185.5,-542.98 1191.5,-548.98 1191.5,-554.98 1191.5,-554.98 1191.5,-566.98 1191.5,-566.98 1191.5,-572.98 1185.5,-578.98 1179.5,-578.98"/>
|
||||
<text text-anchor="middle" x="1159" y="-558.48" font-family="Arial" font-size="10.00" fill="#111827">RIBP2RIB</text>
|
||||
</g>
|
||||
<!-- mgmt_core->mgmt_adapter -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>mgmt_core->mgmt_adapter</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M915,-638.24C915,-622.92 915,-602.4 915,-586.51"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="917.45,-586.12 915,-579.12 912.55,-586.12 917.45,-586.12"/>
|
||||
<text text-anchor="middle" x="924.5" y="-609.08" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1204.91,-638.24C1195.44,-622.5 1182.66,-601.28 1172.99,-585.22"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1175.02,-583.85 1169.31,-579.12 1170.83,-586.38 1175.02,-583.85"/>
|
||||
<text text-anchor="middle" x="1199.5" y="-609.08" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- debug_module -->
|
||||
<g id="node7" class="node">
|
||||
<title>debug_module</title>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M1282.5,-683.48C1282.5,-683.48 1161.5,-683.48 1161.5,-683.48 1155.5,-683.48 1149.5,-677.48 1149.5,-671.48 1149.5,-671.48 1149.5,-650.48 1149.5,-650.48 1149.5,-644.48 1155.5,-638.48 1161.5,-638.48 1161.5,-638.48 1282.5,-638.48 1282.5,-638.48 1288.5,-638.48 1294.5,-644.48 1294.5,-650.48 1294.5,-650.48 1294.5,-671.48 1294.5,-671.48 1294.5,-677.48 1288.5,-683.48 1282.5,-683.48"/>
|
||||
<text text-anchor="middle" x="1222" y="-669.48" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 Debug Module</text>
|
||||
<text text-anchor="middle" x="1222" y="-658.48" font-family="Arial" font-size="10.00" fill="#111827">abstract commands, no SBA</text>
|
||||
<text text-anchor="middle" x="1222" y="-647.48" font-family="Arial" font-size="10.00" fill="#111827">management-hart-only reset</text>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M971.5,-683.48C971.5,-683.48 850.5,-683.48 850.5,-683.48 844.5,-683.48 838.5,-677.48 838.5,-671.48 838.5,-671.48 838.5,-650.48 838.5,-650.48 838.5,-644.48 844.5,-638.48 850.5,-638.48 850.5,-638.48 971.5,-638.48 971.5,-638.48 977.5,-638.48 983.5,-644.48 983.5,-650.48 983.5,-650.48 983.5,-671.48 983.5,-671.48 983.5,-677.48 977.5,-683.48 971.5,-683.48"/>
|
||||
<text text-anchor="middle" x="911" y="-669.48" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 Debug Module</text>
|
||||
<text text-anchor="middle" x="911" y="-658.48" font-family="Arial" font-size="10.00" fill="#111827">abstract commands, no SBA</text>
|
||||
<text text-anchor="middle" x="911" y="-647.48" font-family="Arial" font-size="10.00" fill="#111827">management-hart-only reset</text>
|
||||
</g>
|
||||
<!-- jtag_dtm->debug_module -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>jtag_dtm->debug_module</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M730.06,-679.13C759.11,-708.33 813,-762.48 813,-762.48 813,-762.48 1018,-762.48 1018,-762.48 1018,-762.48 1109.81,-716.8 1170.25,-686.73"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1171.55,-688.82 1176.73,-683.51 1169.37,-684.44 1171.55,-688.82"/>
|
||||
<text text-anchor="middle" x="974" y="-795.08" font-family="Arial" font-size="8.00" fill="#374151">DMI, asynchronous CDC</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M722.33,-660.98C757.12,-660.98 796.91,-660.98 830.95,-660.98"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="831.12,-663.43 838.12,-660.98 831.12,-658.53 831.12,-663.43"/>
|
||||
<text text-anchor="middle" x="780.25" y="-666.58" font-family="Arial" font-size="8.00" fill="#374151">DMI, asynchronous CDC</text>
|
||||
</g>
|
||||
<!-- debug_module->mgmt_core -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>debug_module->mgmt_core</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1149.11,-660.98C1107.89,-660.98 1055.84,-660.98 1011.29,-660.98"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1011.21,-658.53 1004.21,-660.98 1011.21,-663.43 1011.21,-658.53"/>
|
||||
<text text-anchor="middle" x="1076.75" y="-666.58" font-family="Arial" font-size="8.00" fill="#374151">halt, resume, abstract commands</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M983.75,-660.98C1024.99,-660.98 1077.09,-660.98 1121.69,-660.98"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1121.77,-663.43 1128.77,-660.98 1121.77,-658.53 1121.77,-663.43"/>
|
||||
<text text-anchor="middle" x="1056.25" y="-666.58" font-family="Arial" font-size="8.00" fill="#374151">halt, resume, abstract commands</text>
|
||||
</g>
|
||||
<!-- debug_module->mgmt_adapter -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>debug_module->mgmt_adapter</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1149.23,-638.57C1072.31,-615.94 962,-583.48 962,-583.48 962,-583.48 958.87,-582.05 954.22,-579.93"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="955.03,-577.6 947.64,-576.92 952.99,-582.06 955.03,-577.6"/>
|
||||
<text text-anchor="middle" x="1106" y="-609.08" font-family="Arial" font-size="8.00" fill="#374151">reset after bridge idle</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M965.42,-638.48C1012.02,-620.06 1078,-593.99 1119.63,-577.54"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1120.74,-579.74 1126.35,-574.89 1118.94,-575.18 1120.74,-579.74"/>
|
||||
<text text-anchor="middle" x="1080" y="-609.08" font-family="Arial" font-size="8.00" fill="#374151">reset after bridge idle</text>
|
||||
</g>
|
||||
<!-- timers -->
|
||||
<g id="node21" class="node">
|
||||
<g id="node22" class="node">
|
||||
<title>timers</title>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1923.5,-255C1923.5,-255 1742.5,-255 1742.5,-255 1736.5,-255 1730.5,-249 1730.5,-243 1730.5,-243 1730.5,-222 1730.5,-222 1730.5,-216 1736.5,-210 1742.5,-210 1742.5,-210 1923.5,-210 1923.5,-210 1929.5,-210 1935.5,-216 1935.5,-222 1935.5,-222 1935.5,-243 1935.5,-243 1935.5,-249 1929.5,-255 1923.5,-255"/>
|
||||
<text text-anchor="middle" x="1833" y="-241" font-family="Arial" font-size="10.00" fill="#111827">General timers 0/1</text>
|
||||
<text text-anchor="middle" x="1833" y="-230" font-family="Arial" font-size="10.00" fill="#111827">32-bit counter, 16-bit prescaler</text>
|
||||
<text text-anchor="middle" x="1833" y="-219" font-family="Arial" font-size="10.00" fill="#111827">periodic / one-shot, compare, debug freeze</text>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1001.5,-255C1001.5,-255 820.5,-255 820.5,-255 814.5,-255 808.5,-249 808.5,-243 808.5,-243 808.5,-222 808.5,-222 808.5,-216 814.5,-210 820.5,-210 820.5,-210 1001.5,-210 1001.5,-210 1007.5,-210 1013.5,-216 1013.5,-222 1013.5,-222 1013.5,-243 1013.5,-243 1013.5,-249 1007.5,-255 1001.5,-255"/>
|
||||
<text text-anchor="middle" x="911" y="-241" font-family="Arial" font-size="10.00" fill="#111827">General timers 0/1</text>
|
||||
<text text-anchor="middle" x="911" y="-230" font-family="Arial" font-size="10.00" fill="#111827">32-bit counter, 16-bit prescaler</text>
|
||||
<text text-anchor="middle" x="911" y="-219" font-family="Arial" font-size="10.00" fill="#111827">periodic / one-shot, compare, debug freeze</text>
|
||||
</g>
|
||||
<!-- debug_module->timers -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>debug_module->timers</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1294.55,-648.31C1456.04,-622.32 1831,-561.98 1831,-561.98 1831,-561.98 1831,-561.98 1831,-336 1831,-336 1831.85,-292.57 1832.44,-262.25"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1834.89,-262.28 1832.58,-255.24 1829.99,-262.19 1834.89,-262.28"/>
|
||||
<text text-anchor="middle" x="1842" y="-444.84" font-family="Arial" font-size="8.00" fill="#374151">halted</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M911,-638.24C911,-609.36 911,-561.98 911,-561.98 911,-561.98 911,-561.98 911,-336 911,-336 911,-292.57 911,-262.25"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="913.45,-262.24 911,-255.24 908.55,-262.24 913.45,-262.24"/>
|
||||
<text text-anchor="middle" x="922" y="-444.84" font-family="Arial" font-size="8.00" fill="#374151">halted</text>
|
||||
</g>
|
||||
<!-- mgmt_adapter->fabric -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>mgmt_adapter->fabric</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M915,-542.94C915,-529.08 915,-508.91 915,-490.69"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="917.45,-490.57 915,-483.57 912.55,-490.57 917.45,-490.57"/>
|
||||
<text text-anchor="middle" x="922" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1159,-542.94C1159,-529.08 1159,-508.91 1159,-490.69"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1161.45,-490.57 1159,-483.57 1156.55,-490.57 1161.45,-490.57"/>
|
||||
<text text-anchor="middle" x="1166" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
</g>
|
||||
<!-- user_core -->
|
||||
<g id="node9" class="node">
|
||||
<title>user_core</title>
|
||||
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1063,-583.48C1063,-583.48 987,-583.48 987,-583.48 981,-583.48 975,-577.48 975,-571.48 975,-571.48 975,-550.48 975,-550.48 975,-544.48 981,-538.48 987,-538.48 987,-538.48 1063,-538.48 1063,-538.48 1069,-538.48 1075,-544.48 1075,-550.48 1075,-550.48 1075,-571.48 1075,-571.48 1075,-577.48 1069,-583.48 1063,-583.48"/>
|
||||
<text text-anchor="middle" x="1025" y="-569.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text>
|
||||
<text text-anchor="middle" x="1025" y="-558.48" font-family="Arial" font-size="10.00" fill="#111827">C0-C5, one active</text>
|
||||
<text text-anchor="middle" x="1025" y="-547.48" font-family="Arial" font-size="10.00" fill="#111827">PicoRV32 at C5</text>
|
||||
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1489,-583.48C1489,-583.48 1413,-583.48 1413,-583.48 1407,-583.48 1401,-577.48 1401,-571.48 1401,-571.48 1401,-550.48 1401,-550.48 1401,-544.48 1407,-538.48 1413,-538.48 1413,-538.48 1489,-538.48 1489,-538.48 1495,-538.48 1501,-544.48 1501,-550.48 1501,-550.48 1501,-571.48 1501,-571.48 1501,-577.48 1495,-583.48 1489,-583.48"/>
|
||||
<text text-anchor="middle" x="1451" y="-569.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text>
|
||||
<text text-anchor="middle" x="1451" y="-558.48" font-family="Arial" font-size="10.00" fill="#111827">C0-C5, one active</text>
|
||||
<text text-anchor="middle" x="1451" y="-547.48" font-family="Arial" font-size="10.00" fill="#111827">PicoRV32 at C5</text>
|
||||
</g>
|
||||
<!-- user_core->fabric -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>user_core->fabric</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1003.79,-538.34C990.1,-524.37 971.85,-505.75 955.45,-489.02"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="957.08,-487.18 950.43,-483.89 953.58,-490.61 957.08,-487.18"/>
|
||||
<text text-anchor="middle" x="986" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1438.39,-538.22C1429.81,-523.41 1420,-506.48 1420,-506.48 1420,-506.48 1348.85,-490.47 1280.85,-475.17"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1281.23,-472.74 1273.86,-473.59 1280.15,-477.52 1281.23,-472.74"/>
|
||||
<text text-anchor="middle" x="1432" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
</g>
|
||||
<!-- dma -->
|
||||
<g id="node10" class="node">
|
||||
<title>dma</title>
|
||||
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1544,-578.98C1544,-578.98 1426,-578.98 1426,-578.98 1420,-578.98 1414,-572.98 1414,-566.98 1414,-566.98 1414,-554.98 1414,-554.98 1414,-548.98 1420,-542.98 1426,-542.98 1426,-542.98 1544,-542.98 1544,-542.98 1550,-542.98 1556,-548.98 1556,-554.98 1556,-554.98 1556,-566.98 1556,-566.98 1556,-572.98 1550,-578.98 1544,-578.98"/>
|
||||
<text text-anchor="middle" x="1485" y="-563.98" font-family="Arial" font-size="10.00" fill="#111827">DMA</text>
|
||||
<text text-anchor="middle" x="1485" y="-552.98" font-family="Arial" font-size="10.00" fill="#111827">RIB master and RIBP target</text>
|
||||
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M2046,-578.98C2046,-578.98 1928,-578.98 1928,-578.98 1922,-578.98 1916,-572.98 1916,-566.98 1916,-566.98 1916,-554.98 1916,-554.98 1916,-548.98 1922,-542.98 1928,-542.98 1928,-542.98 2046,-542.98 2046,-542.98 2052,-542.98 2058,-548.98 2058,-554.98 2058,-554.98 2058,-566.98 2058,-566.98 2058,-572.98 2052,-578.98 2046,-578.98"/>
|
||||
<text text-anchor="middle" x="1987" y="-563.98" font-family="Arial" font-size="10.00" fill="#111827">DMA</text>
|
||||
<text text-anchor="middle" x="1987" y="-552.98" font-family="Arial" font-size="10.00" fill="#111827">RIB master and RIBP target</text>
|
||||
</g>
|
||||
<!-- dma->fabric -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>dma->fabric</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1413.75,-545.15C1337.69,-529.32 1228,-506.48 1228,-506.48 1228,-506.48 1130.17,-488.12 1043.89,-471.93"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1044.24,-469.51 1036.91,-470.62 1043.34,-474.32 1044.24,-469.51"/>
|
||||
<text text-anchor="middle" x="1278" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1915.77,-551.02C1755.21,-530.82 1379,-483.48 1379,-483.48 1379,-483.48 1339.18,-477.02 1293.43,-469.58"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1293.64,-467.13 1286.34,-468.43 1292.85,-471.97 1293.64,-467.13"/>
|
||||
<text text-anchor="middle" x="1635" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
</g>
|
||||
<!-- uart0 -->
|
||||
<g id="node19" class="node">
|
||||
<title>uart0</title>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M2135,-255C2135,-255 1975,-255 1975,-255 1969,-255 1963,-249 1963,-243 1963,-243 1963,-222 1963,-222 1963,-216 1969,-210 1975,-210 1975,-210 2135,-210 2135,-210 2141,-210 2147,-216 2147,-222 2147,-222 2147,-243 2147,-243 2147,-249 2141,-255 2135,-255"/>
|
||||
<text text-anchor="middle" x="2055" y="-241" font-family="Arial" font-size="10.00" fill="#111827">UART0 V2</text>
|
||||
<text text-anchor="middle" x="2055" y="-230" font-family="Arial" font-size="10.00" fill="#111827">64-byte TX/RX FIFOs, fractional baud</text>
|
||||
<text text-anchor="middle" x="2055" y="-219" font-family="Arial" font-size="10.00" fill="#111827">framing/errors, IRQ2, DMA-paced</text>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M2371,-255C2371,-255 2211,-255 2211,-255 2205,-255 2199,-249 2199,-243 2199,-243 2199,-222 2199,-222 2199,-216 2205,-210 2211,-210 2211,-210 2371,-210 2371,-210 2377,-210 2383,-216 2383,-222 2383,-222 2383,-243 2383,-243 2383,-249 2377,-255 2371,-255"/>
|
||||
<text text-anchor="middle" x="2291" y="-241" font-family="Arial" font-size="10.00" fill="#111827">UART0 V2</text>
|
||||
<text text-anchor="middle" x="2291" y="-230" font-family="Arial" font-size="10.00" fill="#111827">64-byte TX/RX FIFOs, fractional baud</text>
|
||||
<text text-anchor="middle" x="2291" y="-219" font-family="Arial" font-size="10.00" fill="#111827">framing/errors, IRQ2, DMA-paced</text>
|
||||
</g>
|
||||
<!-- dma->uart0 -->
|
||||
<g id="edge33" class="edge">
|
||||
<g id="edge34" class="edge">
|
||||
<title>dma->uart0</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1512.85,-542.86C1586.53,-497.56 1781,-378 1781,-378 1781,-378 1929.1,-299.9 2007.53,-258.53"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2008.93,-260.57 2013.98,-255.13 2006.64,-256.23 2008.93,-260.57"/>
|
||||
<text text-anchor="middle" x="1802.5" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">TX/RX data</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M2002.92,-542.89C2052.59,-489.55 2205.03,-325.83 2265.7,-260.67"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2267.62,-262.2 2270.6,-255.41 2264.04,-258.86 2267.62,-262.2"/>
|
||||
<text text-anchor="middle" x="2174.5" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">TX/RX data</text>
|
||||
</g>
|
||||
<!-- i2c_controllers -->
|
||||
<g id="node20" class="node">
|
||||
<title>i2c_controllers</title>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1974.5,-255C1974.5,-255 1789.5,-255 1789.5,-255 1783.5,-255 1777.5,-249 1777.5,-243 1777.5,-243 1777.5,-222 1777.5,-222 1777.5,-216 1783.5,-210 1789.5,-210 1789.5,-210 1974.5,-210 1974.5,-210 1980.5,-210 1986.5,-216 1986.5,-222 1986.5,-222 1986.5,-243 1986.5,-243 1986.5,-249 1980.5,-255 1974.5,-255"/>
|
||||
<text text-anchor="middle" x="1882" y="-241" font-family="Arial" font-size="10.00" fill="#111827">I2C0 / I2C1 V2</text>
|
||||
<text text-anchor="middle" x="1882" y="-230" font-family="Arial" font-size="10.00" fill="#111827">16-entry command/RX FIFOs, Sm/Fm/Fm+</text>
|
||||
<text text-anchor="middle" x="1882" y="-219" font-family="Arial" font-size="10.00" fill="#111827">7/10-bit, IRQ7/19, DMA-paced</text>
|
||||
</g>
|
||||
<!-- dma->i2c_controllers -->
|
||||
<g id="edge37" class="edge">
|
||||
<title>dma->i2c_controllers</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1981.5,-542.89C1964.48,-489.98 1912.54,-328.45 1891.25,-262.26"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1893.52,-261.32 1889.05,-255.41 1888.86,-262.82 1893.52,-261.32"/>
|
||||
<text text-anchor="middle" x="1971" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">DATA_CMD / RXDATA</text>
|
||||
</g>
|
||||
<!-- ws2812 -->
|
||||
<g id="node22" class="node">
|
||||
<g id="node23" class="node">
|
||||
<title>ws2812</title>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1478,-255C1478,-255 1344,-255 1344,-255 1338,-255 1332,-249 1332,-243 1332,-243 1332,-222 1332,-222 1332,-216 1338,-210 1344,-210 1344,-210 1478,-210 1478,-210 1484,-210 1490,-216 1490,-222 1490,-222 1490,-243 1490,-243 1490,-249 1484,-255 1478,-255"/>
|
||||
<text text-anchor="middle" x="1411" y="-241" font-family="Arial" font-size="10.00" fill="#111827">WS2812 TX</text>
|
||||
<text text-anchor="middle" x="1411" y="-230" font-family="Arial" font-size="10.00" fill="#111827">24-bit MSB-first serializer</text>
|
||||
<text text-anchor="middle" x="1411" y="-219" font-family="Arial" font-size="10.00" fill="#111827">16-word FIFO, IRQ17, DMA-fed</text>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M2160,-255C2160,-255 2026,-255 2026,-255 2020,-255 2014,-249 2014,-243 2014,-243 2014,-222 2014,-222 2014,-216 2020,-210 2026,-210 2026,-210 2160,-210 2160,-210 2166,-210 2172,-216 2172,-222 2172,-222 2172,-243 2172,-243 2172,-249 2166,-255 2160,-255"/>
|
||||
<text text-anchor="middle" x="2093" y="-241" font-family="Arial" font-size="10.00" fill="#111827">WS2812 TX</text>
|
||||
<text text-anchor="middle" x="2093" y="-230" font-family="Arial" font-size="10.00" fill="#111827">24-bit MSB-first serializer</text>
|
||||
<text text-anchor="middle" x="2093" y="-219" font-family="Arial" font-size="10.00" fill="#111827">16-word FIFO, IRQ17, DMA-fed</text>
|
||||
</g>
|
||||
<!-- dma->ws2812 -->
|
||||
<g id="edge31" class="edge">
|
||||
<g id="edge32" class="edge">
|
||||
<title>dma->ws2812</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1484.69,-542.77C1483.61,-481.55 1480,-278 1480,-278 1480,-278 1466.13,-269.06 1450.83,-259.19"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1451.9,-256.96 1444.69,-255.23 1449.25,-261.08 1451.9,-256.96"/>
|
||||
<text text-anchor="middle" x="1508.5" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">TXDATA writes</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1992.55,-542.89C2009.73,-489.98 2062.17,-328.45 2083.66,-262.26"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2086.05,-262.83 2085.89,-255.41 2081.39,-261.31 2086.05,-262.83"/>
|
||||
<text text-anchor="middle" x="2071.5" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">TXDATA writes</text>
|
||||
</g>
|
||||
<!-- fault -->
|
||||
<g id="node12" class="node">
|
||||
<title>fault</title>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M1295.5,-464.74C1295.5,-464.74 1186.5,-464.74 1186.5,-464.74 1180.5,-464.74 1174.5,-458.74 1174.5,-452.74 1174.5,-452.74 1174.5,-440.74 1174.5,-440.74 1174.5,-434.74 1180.5,-428.74 1186.5,-428.74 1186.5,-428.74 1295.5,-428.74 1295.5,-428.74 1301.5,-428.74 1307.5,-434.74 1307.5,-440.74 1307.5,-440.74 1307.5,-452.74 1307.5,-452.74 1307.5,-458.74 1301.5,-464.74 1295.5,-464.74"/>
|
||||
<text text-anchor="middle" x="1241" y="-449.74" font-family="Arial" font-size="10.00" fill="#111827">Error slave</text>
|
||||
<text text-anchor="middle" x="1241" y="-438.74" font-family="Arial" font-size="10.00" fill="#111827">access and protocol faults</text>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M1662.5,-464.74C1662.5,-464.74 1553.5,-464.74 1553.5,-464.74 1547.5,-464.74 1541.5,-458.74 1541.5,-452.74 1541.5,-452.74 1541.5,-440.74 1541.5,-440.74 1541.5,-434.74 1547.5,-428.74 1553.5,-428.74 1553.5,-428.74 1662.5,-428.74 1662.5,-428.74 1668.5,-428.74 1674.5,-434.74 1674.5,-440.74 1674.5,-440.74 1674.5,-452.74 1674.5,-452.74 1674.5,-458.74 1668.5,-464.74 1662.5,-464.74"/>
|
||||
<text text-anchor="middle" x="1608" y="-449.74" font-family="Arial" font-size="10.00" fill="#111827">Error slave</text>
|
||||
<text text-anchor="middle" x="1608" y="-438.74" font-family="Arial" font-size="10.00" fill="#111827">access and protocol faults</text>
|
||||
</g>
|
||||
<!-- fabric->fault -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>fabric->fault</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1101.98,-446.74C1124.93,-446.74 1147.24,-446.74 1167.02,-446.74"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1101.69,-444.29 1094.69,-446.74 1101.69,-449.19 1101.69,-444.29"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1167.19,-449.19 1174.19,-446.74 1167.19,-444.29 1167.19,-449.19"/>
|
||||
<text text-anchor="middle" x="1134.56" y="-452.34" font-family="Arial" font-size="8.00" fill="#374151">invalid / denied</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1272.37,-478.99C1320.41,-492.66 1365.5,-505.48 1365.5,-505.48 1365.5,-505.48 1418.5,-505.48 1418.5,-505.48 1418.5,-505.48 1528,-483.48 1528,-483.48 1528,-483.48 1544.11,-476.08 1561.88,-467.93"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1272.98,-476.62 1265.58,-477.06 1271.64,-481.33 1272.98,-476.62"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1563.13,-470.05 1568.47,-464.9 1561.08,-465.59 1563.13,-470.05"/>
|
||||
<text text-anchor="middle" x="1392" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">invalid / denied</text>
|
||||
</g>
|
||||
<!-- sram -->
|
||||
<g id="node13" class="node">
|
||||
<title>sram</title>
|
||||
<path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="M1445,-464.74C1445,-464.74 1347,-464.74 1347,-464.74 1341,-464.74 1335,-458.74 1335,-452.74 1335,-452.74 1335,-440.74 1335,-440.74 1335,-434.74 1341,-428.74 1347,-428.74 1347,-428.74 1445,-428.74 1445,-428.74 1451,-428.74 1457,-434.74 1457,-440.74 1457,-440.74 1457,-452.74 1457,-452.74 1457,-458.74 1451,-464.74 1445,-464.74"/>
|
||||
<text text-anchor="middle" x="1396" y="-449.74" font-family="Arial" font-size="10.00" fill="#111827">On-chip SRAM</text>
|
||||
<text text-anchor="middle" x="1396" y="-438.74" font-family="Arial" font-size="10.00" fill="#111827">optional RIB2RAM path</text>
|
||||
<path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="M1502,-464.74C1502,-464.74 1404,-464.74 1404,-464.74 1398,-464.74 1392,-458.74 1392,-452.74 1392,-452.74 1392,-440.74 1392,-440.74 1392,-434.74 1398,-428.74 1404,-428.74 1404,-428.74 1502,-428.74 1502,-428.74 1508,-428.74 1514,-434.74 1514,-440.74 1514,-440.74 1514,-452.74 1514,-452.74 1514,-458.74 1508,-464.74 1502,-464.74"/>
|
||||
<text text-anchor="middle" x="1453" y="-449.74" font-family="Arial" font-size="10.00" fill="#111827">On-chip SRAM</text>
|
||||
<text text-anchor="middle" x="1453" y="-438.74" font-family="Arial" font-size="10.00" fill="#111827">optional RIB2RAM path</text>
|
||||
</g>
|
||||
<!-- fabric->sram -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>fabric->sram</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1036.29,-471.06C1116.9,-487.22 1208,-505.48 1208,-505.48 1208,-505.48 1222,-505.48 1222,-505.48 1222,-505.48 1321,-483.48 1321,-483.48 1321,-483.48 1335.84,-476.21 1352.32,-468.14"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1353.73,-470.18 1358.94,-464.9 1351.58,-465.78 1353.73,-470.18"/>
|
||||
<text text-anchor="middle" x="1215" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1338.91,-446.74C1354.95,-446.74 1370.44,-446.74 1384.56,-446.74"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1384.81,-449.19 1391.81,-446.74 1384.81,-444.29 1384.81,-449.19"/>
|
||||
<text text-anchor="middle" x="1365.31" y="-452.34" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
</g>
|
||||
<!-- ribp_adapter -->
|
||||
<g id="node14" class="node">
|
||||
<title>ribp_adapter</title>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1253.5,-355C1253.5,-355 1212.5,-355 1212.5,-355 1206.5,-355 1200.5,-349 1200.5,-343 1200.5,-343 1200.5,-331 1200.5,-331 1200.5,-325 1206.5,-319 1212.5,-319 1212.5,-319 1253.5,-319 1253.5,-319 1259.5,-319 1265.5,-325 1265.5,-331 1265.5,-331 1265.5,-343 1265.5,-343 1265.5,-349 1259.5,-355 1253.5,-355"/>
|
||||
<text text-anchor="middle" x="1233" y="-334.5" font-family="Arial" font-size="10.00" fill="#111827">RIB2RIBP</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1442.5,-355C1442.5,-355 1401.5,-355 1401.5,-355 1395.5,-355 1389.5,-349 1389.5,-343 1389.5,-343 1389.5,-331 1389.5,-331 1389.5,-325 1395.5,-319 1401.5,-319 1401.5,-319 1442.5,-319 1442.5,-319 1448.5,-319 1454.5,-325 1454.5,-331 1454.5,-331 1454.5,-343 1454.5,-343 1454.5,-349 1448.5,-355 1442.5,-355"/>
|
||||
<text text-anchor="middle" x="1422" y="-334.5" font-family="Arial" font-size="10.00" fill="#111827">RIB2RIBP</text>
|
||||
</g>
|
||||
<!-- fabric->ribp_adapter -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>fabric->ribp_adapter</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1012.57,-412.68C1073.53,-392.03 1148.71,-366.56 1193.65,-351.33"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1194.49,-353.64 1200.33,-349.07 1192.91,-349 1194.49,-353.64"/>
|
||||
<text text-anchor="middle" x="1118" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1246.58,-409.87C1292.52,-391.04 1346.56,-368.91 1382.39,-354.23"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1383.76,-356.31 1389.31,-351.39 1381.9,-351.78 1383.76,-356.31"/>
|
||||
<text text-anchor="middle" x="1328" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
</g>
|
||||
<!-- apb_adapter -->
|
||||
<g id="node15" class="node">
|
||||
<title>apb_adapter</title>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M662,-355C662,-355 592,-355 592,-355 586,-355 580,-349 580,-343 580,-343 580,-331 580,-331 580,-325 586,-319 592,-319 592,-319 662,-319 662,-319 668,-319 674,-325 674,-331 674,-331 674,-343 674,-343 674,-349 668,-355 662,-355"/>
|
||||
<text text-anchor="middle" x="627" y="-340" font-family="Arial" font-size="10.00" fill="#111827">RIB2APB</text>
|
||||
<text text-anchor="middle" x="627" y="-329" font-family="Arial" font-size="10.00" fill="#111827">direct APB bridge</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1107,-355C1107,-355 1037,-355 1037,-355 1031,-355 1025,-349 1025,-343 1025,-343 1025,-331 1025,-331 1025,-325 1031,-319 1037,-319 1037,-319 1107,-319 1107,-319 1113,-319 1119,-325 1119,-331 1119,-331 1119,-343 1119,-343 1119,-349 1113,-355 1107,-355"/>
|
||||
<text text-anchor="middle" x="1072" y="-340" font-family="Arial" font-size="10.00" fill="#111827">RIB2APB</text>
|
||||
<text text-anchor="middle" x="1072" y="-329" font-family="Arial" font-size="10.00" fill="#111827">direct APB bridge</text>
|
||||
</g>
|
||||
<!-- fabric->apb_adapter -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>fabric->apb_adapter</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M846.72,-409.89C815.78,-393.64 786,-378 786,-378 786,-378 727.32,-363.24 681.26,-351.65"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="681.66,-349.22 674.27,-349.89 680.47,-353.98 681.66,-349.22"/>
|
||||
<text text-anchor="middle" x="808" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1130.03,-409.87C1116.97,-393.69 1101.93,-375.07 1090.44,-360.83"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1092.05,-358.93 1085.74,-355.02 1088.24,-362.01 1092.05,-358.93"/>
|
||||
<text text-anchor="middle" x="1117" y="-380.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
</g>
|
||||
<!-- sysctrl -->
|
||||
<g id="node16" class="node">
|
||||
<title>sysctrl</title>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1691.5,-255C1691.5,-255 1528.5,-255 1528.5,-255 1522.5,-255 1516.5,-249 1516.5,-243 1516.5,-243 1516.5,-222 1516.5,-222 1516.5,-216 1522.5,-210 1528.5,-210 1528.5,-210 1691.5,-210 1691.5,-210 1697.5,-210 1703.5,-216 1703.5,-222 1703.5,-222 1703.5,-243 1703.5,-243 1703.5,-249 1697.5,-255 1691.5,-255"/>
|
||||
<text text-anchor="middle" x="1610" y="-241" font-family="Arial" font-size="10.00" fill="#111827">SYSCTRL</text>
|
||||
<text text-anchor="middle" x="1610" y="-230" font-family="Arial" font-size="10.00" fill="#111827">PLL, user-core select/reset/bus enable</text>
|
||||
<text text-anchor="middle" x="1610" y="-219" font-family="Arial" font-size="10.00" fill="#111827">fault and performance control</text>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1738.5,-255C1738.5,-255 1575.5,-255 1575.5,-255 1569.5,-255 1563.5,-249 1563.5,-243 1563.5,-243 1563.5,-222 1563.5,-222 1563.5,-216 1569.5,-210 1575.5,-210 1575.5,-210 1738.5,-210 1738.5,-210 1744.5,-210 1750.5,-216 1750.5,-222 1750.5,-222 1750.5,-243 1750.5,-243 1750.5,-249 1744.5,-255 1738.5,-255"/>
|
||||
<text text-anchor="middle" x="1657" y="-241" font-family="Arial" font-size="10.00" fill="#111827">SYSCTRL</text>
|
||||
<text text-anchor="middle" x="1657" y="-230" font-family="Arial" font-size="10.00" fill="#111827">PLL, user-core select/reset/bus enable</text>
|
||||
<text text-anchor="middle" x="1657" y="-219" font-family="Arial" font-size="10.00" fill="#111827">fault and performance control</text>
|
||||
</g>
|
||||
<!-- ribp_adapter->sysctrl -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>ribp_adapter->sysctrl</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1265.56,-320C1300.48,-302.83 1351,-278 1351,-278 1351,-278 1504,-255 1504,-255 1504,-255 1505.94,-254.61 1509.28,-253.93"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1509.79,-256.33 1516.16,-252.53 1508.81,-251.52 1509.79,-256.33"/>
|
||||
<text text-anchor="middle" x="1360.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1454.67,-324.54C1488.35,-312.72 1536,-296 1536,-296 1536,-296 1575.31,-275.69 1609.12,-258.23"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1610.26,-260.4 1615.36,-255.01 1608.01,-256.04 1610.26,-260.4"/>
|
||||
<text text-anchor="middle" x="1577.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- ribp_adapter->clint -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>ribp_adapter->clint</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1200.18,-333.65C1080.57,-325.07 675,-296 675,-296 675,-296 675,-278 675,-278 675,-278 681.01,-270.13 687.98,-261.01"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="690.1,-262.28 692.4,-255.23 686.2,-259.3 690.1,-262.28"/>
|
||||
<text text-anchor="middle" x="684.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1389.25,-333.22C1282.44,-324.15 951,-296 951,-296 951,-296 859.3,-272.32 788.79,-254.11"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="789,-251.63 781.61,-252.25 787.77,-256.37 789,-251.63"/>
|
||||
<text text-anchor="middle" x="960.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- ribp_targets -->
|
||||
<g id="node18" class="node">
|
||||
<title>ribp_targets</title>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1292.5,-255C1292.5,-255 1087.5,-255 1087.5,-255 1081.5,-255 1075.5,-249 1075.5,-243 1075.5,-243 1075.5,-222 1075.5,-222 1075.5,-216 1081.5,-210 1087.5,-210 1087.5,-210 1292.5,-210 1292.5,-210 1298.5,-210 1304.5,-216 1304.5,-222 1304.5,-222 1304.5,-243 1304.5,-243 1304.5,-249 1298.5,-255 1292.5,-255"/>
|
||||
<text text-anchor="middle" x="1190" y="-241" font-family="Arial" font-size="10.00" fill="#111827">RIBP target wrapper</text>
|
||||
<text text-anchor="middle" x="1190" y="-230" font-family="Arial" font-size="10.00" fill="#111827">XPI/Flash, SDRAM, PSRAM, SPI-SD and DVP</text>
|
||||
<text text-anchor="middle" x="1190" y="-219" font-family="Arial" font-size="10.00" fill="#111827">I2C and I2S</text>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1524.5,-255C1524.5,-255 1319.5,-255 1319.5,-255 1313.5,-255 1307.5,-249 1307.5,-243 1307.5,-243 1307.5,-222 1307.5,-222 1307.5,-216 1313.5,-210 1319.5,-210 1319.5,-210 1524.5,-210 1524.5,-210 1530.5,-210 1536.5,-216 1536.5,-222 1536.5,-222 1536.5,-243 1536.5,-243 1536.5,-249 1530.5,-255 1524.5,-255"/>
|
||||
<text text-anchor="middle" x="1422" y="-241" font-family="Arial" font-size="10.00" fill="#111827">RIBP target wrapper</text>
|
||||
<text text-anchor="middle" x="1422" y="-230" font-family="Arial" font-size="10.00" fill="#111827">XPI/Flash, SDRAM, PSRAM, SPI-SD and DVP</text>
|
||||
<text text-anchor="middle" x="1422" y="-219" font-family="Arial" font-size="10.00" fill="#111827">I2S</text>
|
||||
</g>
|
||||
<!-- ribp_adapter->ribp_targets -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>ribp_adapter->ribp_targets</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1225.71,-318.61C1219.18,-303.05 1209.48,-279.94 1201.84,-261.72"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1204.1,-260.77 1199.13,-255.26 1199.58,-262.66 1204.1,-260.77"/>
|
||||
<text text-anchor="middle" x="1224.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1422,-318.61C1422,-303.32 1422,-280.75 1422,-262.69"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1424.45,-262.26 1422,-255.26 1419.55,-262.26 1424.45,-262.26"/>
|
||||
<text text-anchor="middle" x="1431.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- ribp_adapter->uart0 -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>ribp_adapter->uart0</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1265.81,-331C1358.23,-316.94 1614,-278 1614,-278 1614,-278 1949,-255 1949,-255 1949,-255 1951.57,-254.48 1955.91,-253.6"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1956.48,-255.98 1962.86,-252.19 1955.51,-251.18 1956.48,-255.98"/>
|
||||
<text text-anchor="middle" x="1623.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1454.82,-332.96C1555.64,-323.63 1854,-296 1854,-296 1854,-296 2186,-255 2186,-255 2186,-255 2188.16,-254.56 2191.87,-253.8"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2192.51,-256.17 2198.88,-252.36 2191.53,-251.37 2192.51,-256.17"/>
|
||||
<text text-anchor="middle" x="1999.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- ribp_adapter->i2c_controllers -->
|
||||
<g id="edge21" class="edge">
|
||||
<title>ribp_adapter->i2c_controllers</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1454.71,-328.71C1521.23,-313.89 1674.71,-279.69 1778.43,-256.58"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1779.2,-258.92 1785.5,-255 1778.13,-254.13 1779.2,-258.92"/>
|
||||
<text text-anchor="middle" x="1688.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- gpio_controller -->
|
||||
<g id="node20" class="node">
|
||||
<g id="node21" class="node">
|
||||
<title>gpio_controller</title>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M971,-255C971,-255 821,-255 821,-255 815,-255 809,-249 809,-243 809,-243 809,-222 809,-222 809,-216 815,-210 821,-210 821,-210 971,-210 971,-210 977,-210 983,-216 983,-222 983,-222 983,-243 983,-243 983,-249 977,-255 971,-255"/>
|
||||
<text text-anchor="middle" x="896" y="-241" font-family="Arial" font-size="10.00" fill="#111827">GPIO V2</text>
|
||||
<text text-anchor="middle" x="896" y="-230" font-family="Arial" font-size="10.00" fill="#111827">user + management RIBP windows</text>
|
||||
<text text-anchor="middle" x="896" y="-219" font-family="Arial" font-size="10.00" fill="#111827">atomic I/O, filter, locks, IRQ18</text>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1203,-255C1203,-255 1053,-255 1053,-255 1047,-255 1041,-249 1041,-243 1041,-243 1041,-222 1041,-222 1041,-216 1047,-210 1053,-210 1053,-210 1203,-210 1203,-210 1209,-210 1215,-216 1215,-222 1215,-222 1215,-243 1215,-243 1215,-249 1209,-255 1203,-255"/>
|
||||
<text text-anchor="middle" x="1128" y="-241" font-family="Arial" font-size="10.00" fill="#111827">GPIO V2</text>
|
||||
<text text-anchor="middle" x="1128" y="-230" font-family="Arial" font-size="10.00" fill="#111827">user + management RIBP windows</text>
|
||||
<text text-anchor="middle" x="1128" y="-219" font-family="Arial" font-size="10.00" fill="#111827">atomic I/O, filter, locks, IRQ18</text>
|
||||
</g>
|
||||
<!-- ribp_adapter->gpio_controller -->
|
||||
<g id="edge21" class="edge">
|
||||
<g id="edge22" class="edge">
|
||||
<title>ribp_adapter->gpio_controller</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1200.46,-333.56C1084.74,-324.87 700,-296 700,-296 700,-296 700,-278 700,-278 700,-278 751.58,-266.29 801.82,-254.88"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="802.61,-257.22 808.89,-253.28 801.52,-252.44 802.61,-257.22"/>
|
||||
<text text-anchor="middle" x="720" y="-289.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<text text-anchor="middle" x="720" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">user/admin</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1389.41,-324.64C1343.13,-308.5 1257.25,-278.56 1196.57,-257.41"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1197.09,-254.99 1189.68,-255 1195.48,-259.62 1197.09,-254.99"/>
|
||||
<text text-anchor="middle" x="1321" y="-289.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<text text-anchor="middle" x="1321" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">user/admin</text>
|
||||
</g>
|
||||
<!-- ribp_adapter->timers -->
|
||||
<g id="edge22" class="edge">
|
||||
<g id="edge23" class="edge">
|
||||
<title>ribp_adapter->timers</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1265.59,-326.62C1306.67,-314.8 1372,-296 1372,-296 1372,-296 1406,-278 1406,-278 1406,-278 1717,-255 1717,-255 1717,-255 1719.33,-254.57 1723.33,-253.83"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1723.87,-256.22 1730.31,-252.53 1722.98,-251.4 1723.87,-256.22"/>
|
||||
<text text-anchor="middle" x="1415.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1389.26,-329.43C1316.31,-314.8 1137.66,-278.96 1020.55,-255.47"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1020.97,-253.06 1013.63,-254.09 1020.01,-257.86 1020.97,-253.06"/>
|
||||
<text text-anchor="middle" x="1221.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- ribp_adapter->ws2812 -->
|
||||
<g id="edge23" class="edge">
|
||||
<g id="edge24" class="edge">
|
||||
<title>ribp_adapter->ws2812</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1250.38,-318.91C1267.79,-301.8 1292,-278 1292,-278 1292,-278 1318.5,-268.09 1346.5,-257.62"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1347.54,-259.84 1353.24,-255.1 1345.83,-255.26 1347.54,-259.84"/>
|
||||
<text text-anchor="middle" x="1301.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1454.73,-331.41C1577,-314.28 2000,-255 2000,-255 2000,-255 2002.58,-254.4 2006.88,-253.41"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2007.45,-255.79 2013.72,-251.83 2006.35,-251.02 2007.45,-255.79"/>
|
||||
<text text-anchor="middle" x="1838.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- apb_targets -->
|
||||
<g id="node23" class="node">
|
||||
<g id="node24" class="node">
|
||||
<title>apb_targets</title>
|
||||
<path fill="#e6f4ea" stroke="#4b5563" stroke-width="1.1" d="M597.5,-255C597.5,-255 406.5,-255 406.5,-255 400.5,-255 394.5,-249 394.5,-243 394.5,-243 394.5,-222 394.5,-222 394.5,-216 400.5,-210 406.5,-210 406.5,-210 597.5,-210 597.5,-210 603.5,-210 609.5,-216 609.5,-222 609.5,-222 609.5,-243 609.5,-243 609.5,-249 603.5,-255 597.5,-255"/>
|
||||
<text text-anchor="middle" x="502" y="-241" font-family="Arial" font-size="10.00" fill="#111827">APB target wrapper</text>
|
||||
@@ -370,112 +392,127 @@
|
||||
<text text-anchor="middle" x="502" y="-219" font-family="Arial" font-size="10.00" fill="#111827">watchdog, CRC, advanced timer and user IP</text>
|
||||
</g>
|
||||
<!-- apb_adapter->apb_targets -->
|
||||
<g id="edge24" class="edge">
|
||||
<g id="edge25" class="edge">
|
||||
<title>apb_adapter->apb_targets</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M606.08,-318.84C586.47,-302.77 556.88,-278.5 534.25,-259.95"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="535.63,-257.9 528.66,-255.36 532.52,-261.69 535.63,-257.9"/>
|
||||
<text text-anchor="middle" x="583" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">APB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1024.87,-327.52C936.06,-311.55 741.64,-276.59 616.52,-254.09"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="616.82,-251.66 609.5,-252.83 615.96,-256.48 616.82,-251.66"/>
|
||||
<text text-anchor="middle" x="846" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">APB</text>
|
||||
</g>
|
||||
<!-- irq -->
|
||||
<g id="node25" class="node">
|
||||
<g id="node26" class="node">
|
||||
<title>irq</title>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M1515,-155C1515,-155 1309,-155 1309,-155 1303,-155 1297,-149 1297,-143 1297,-143 1297,-131 1297,-131 1297,-125 1303,-119 1309,-119 1309,-119 1515,-119 1515,-119 1521,-119 1527,-125 1527,-131 1527,-131 1527,-143 1527,-143 1527,-149 1521,-155 1515,-155"/>
|
||||
<text text-anchor="middle" x="1412" y="-140" font-family="Arial" font-size="10.00" fill="#111827">Interrupt aggregation</text>
|
||||
<text text-anchor="middle" x="1412" y="-129" font-family="Arial" font-size="10.00" fill="#111827">RIBP and APB target IRQs to management core</text>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M1502,-155C1502,-155 1296,-155 1296,-155 1290,-155 1284,-149 1284,-143 1284,-143 1284,-131 1284,-131 1284,-125 1290,-119 1296,-119 1296,-119 1502,-119 1502,-119 1508,-119 1514,-125 1514,-131 1514,-131 1514,-143 1514,-143 1514,-149 1508,-155 1502,-155"/>
|
||||
<text text-anchor="middle" x="1399" y="-140" font-family="Arial" font-size="10.00" fill="#111827">Interrupt aggregation</text>
|
||||
<text text-anchor="middle" x="1399" y="-129" font-family="Arial" font-size="10.00" fill="#111827">RIBP and APB target IRQs to management core</text>
|
||||
</g>
|
||||
<!-- clint->irq -->
|
||||
<g id="edge29" class="edge">
|
||||
<g id="edge30" class="edge">
|
||||
<title>clint->irq</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M781.63,-213.55C790.22,-211.43 796,-210 796,-210 796,-210 960,-178 960,-178 960,-178 1284,-155 1284,-155 1284,-155 1286.1,-154.72 1289.77,-154.23"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1290.12,-156.66 1296.74,-153.31 1289.48,-151.8 1290.12,-156.66"/>
|
||||
<text text-anchor="middle" x="998.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">machine IRQ0 / IRQ1</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M781.56,-213.36C789.62,-211.34 795,-210 795,-210 795,-210 1100.51,-173.58 1276.97,-152.55"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1277.31,-154.97 1283.97,-151.71 1276.73,-150.11 1277.31,-154.97"/>
|
||||
<text text-anchor="middle" x="1098.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">machine IRQ0 / IRQ1</text>
|
||||
</g>
|
||||
<!-- ribp_targets->ext_io -->
|
||||
<g id="edge36" class="edge">
|
||||
<g id="edge40" class="edge">
|
||||
<title>ribp_targets->ext_io</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1311.9,-211.18C1316.39,-210.44 1319,-210 1319,-210 1319,-210 1564,-187 1564,-187 1564,-187 1573.65,-99.32 1578.82,-52.38"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1311.2,-208.82 1304.7,-212.38 1312.01,-213.65 1311.2,-208.82"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1581.28,-52.44 1579.61,-45.21 1576.41,-51.9 1581.28,-52.44"/>
|
||||
<text text-anchor="middle" x="1605" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">device interfaces</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1543.73,-211.05C1547.71,-210.39 1550,-210 1550,-210 1550,-210 1931,-187 1931,-187 1931,-187 1940.65,-99.32 1945.82,-52.38"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1543.28,-208.64 1536.78,-212.22 1544.09,-213.48 1543.28,-208.64"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1948.28,-52.44 1946.61,-45.21 1943.41,-51.9 1948.28,-52.44"/>
|
||||
<text text-anchor="middle" x="1972" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">device interfaces</text>
|
||||
</g>
|
||||
<!-- ribp_targets->gpio_controller -->
|
||||
<g id="edge25" class="edge">
|
||||
<g id="edge26" class="edge">
|
||||
<title>ribp_targets->gpio_controller</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1075.39,-232.5C1047.19,-232.5 1017.32,-232.5 990.21,-232.5"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="990.02,-230.05 983.02,-232.5 990.02,-234.95 990.02,-230.05"/>
|
||||
<text text-anchor="middle" x="1029.25" y="-238.1" font-family="Arial" font-size="8.00" fill="#374151">alternate functions</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1307.39,-232.5C1279.19,-232.5 1249.32,-232.5 1222.21,-232.5"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1222.02,-230.05 1215.02,-232.5 1222.02,-234.95 1222.02,-230.05"/>
|
||||
<text text-anchor="middle" x="1261.25" y="-238.1" font-family="Arial" font-size="8.00" fill="#374151">alternate functions</text>
|
||||
</g>
|
||||
<!-- uart0->ext_io -->
|
||||
<g id="edge37" class="edge">
|
||||
<g id="edge41" class="edge">
|
||||
<title>uart0->ext_io</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1999.17,-206.95C1908.15,-166.92 1728.85,-88.08 1637.83,-48.05"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1998.33,-209.25 2005.72,-209.83 2000.3,-204.77 1998.33,-209.25"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1638.56,-45.7 1631.17,-45.12 1636.59,-50.18 1638.56,-45.7"/>
|
||||
<text text-anchor="middle" x="1901" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">UART pads</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M2249,-205.95C2183.15,-165.91 2056.38,-88.81 1990.71,-48.87"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="2248.11,-208.28 2255.37,-209.83 2250.66,-204.1 2248.11,-208.28"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1991.81,-46.67 1984.55,-45.12 1989.26,-50.85 1991.81,-46.67"/>
|
||||
<text text-anchor="middle" x="2186" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">UART pads</text>
|
||||
</g>
|
||||
<!-- uart0->irq -->
|
||||
<g id="edge34" class="edge">
|
||||
<g id="edge35" class="edge">
|
||||
<title>uart0->irq</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1962.86,-212.81C1954.44,-211.1 1949,-210 1949,-210 1949,-210 1692.67,-175.63 1534.2,-154.38"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1534.46,-151.95 1527.2,-153.45 1533.81,-156.8 1534.46,-151.95"/>
|
||||
<text text-anchor="middle" x="1784.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ2</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M2198.88,-212.64C2191.02,-211.03 2186,-210 2186,-210 2186,-210 1879,-178 1879,-178 1879,-178 1663.63,-160.05 1521.42,-148.2"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1521.46,-145.75 1514.28,-147.61 1521.05,-150.63 1521.46,-145.75"/>
|
||||
<text text-anchor="middle" x="1970.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ2</text>
|
||||
</g>
|
||||
<!-- i2c_controllers->gpio_controller -->
|
||||
<g id="edge36" class="edge">
|
||||
<title>i2c_controllers->gpio_controller</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1777.08,-252.51C1769.06,-254.04 1764,-255 1764,-255 1764,-255 1530,-287 1530,-287 1530,-287 1478,-287 1478,-287 1478,-287 1326.14,-263.35 1222.48,-247.21"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1222.71,-244.77 1215.42,-246.11 1221.96,-249.61 1222.71,-244.77"/>
|
||||
<text text-anchor="middle" x="1504" y="-289.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO3/4 ALT1</text>
|
||||
<text text-anchor="middle" x="1504" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO7/8 ALT0</text>
|
||||
</g>
|
||||
<!-- i2c_controllers->irq -->
|
||||
<g id="edge38" class="edge">
|
||||
<title>i2c_controllers->irq</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1777.08,-212.38C1769.06,-210.92 1764,-210 1764,-210 1764,-210 1609,-187 1609,-187 1609,-187 1538.37,-170.52 1479.03,-156.67"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1479.23,-154.21 1471.86,-155 1478.12,-158.98 1479.23,-154.21"/>
|
||||
<text text-anchor="middle" x="1633.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ7 / IRQ19</text>
|
||||
</g>
|
||||
<!-- gpio_bridge -->
|
||||
<g id="node24" class="node">
|
||||
<g id="node25" class="node">
|
||||
<title>gpio_bridge</title>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1258.5,-155C1258.5,-155 1123.5,-155 1123.5,-155 1117.5,-155 1111.5,-149 1111.5,-143 1111.5,-143 1111.5,-131 1111.5,-131 1111.5,-125 1117.5,-119 1123.5,-119 1123.5,-119 1258.5,-119 1258.5,-119 1264.5,-119 1270.5,-125 1270.5,-131 1270.5,-131 1270.5,-143 1270.5,-143 1270.5,-149 1264.5,-155 1258.5,-155"/>
|
||||
<text text-anchor="middle" x="1191" y="-140" font-family="Arial" font-size="10.00" fill="#111827">GPIO pad bridge</text>
|
||||
<text text-anchor="middle" x="1191" y="-129" font-family="Arial" font-size="10.00" fill="#111827">PDK capability-adapted controls</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1882.5,-155C1882.5,-155 1747.5,-155 1747.5,-155 1741.5,-155 1735.5,-149 1735.5,-143 1735.5,-143 1735.5,-131 1735.5,-131 1735.5,-125 1741.5,-119 1747.5,-119 1747.5,-119 1882.5,-119 1882.5,-119 1888.5,-119 1894.5,-125 1894.5,-131 1894.5,-131 1894.5,-143 1894.5,-143 1894.5,-149 1888.5,-155 1882.5,-155"/>
|
||||
<text text-anchor="middle" x="1815" y="-140" font-family="Arial" font-size="10.00" fill="#111827">GPIO pad bridge</text>
|
||||
<text text-anchor="middle" x="1815" y="-129" font-family="Arial" font-size="10.00" fill="#111827">PDK capability-adapted controls</text>
|
||||
</g>
|
||||
<!-- gpio_controller->gpio_bridge -->
|
||||
<g id="edge26" class="edge">
|
||||
<g id="edge27" class="edge">
|
||||
<title>gpio_controller->gpio_bridge</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M964.05,-209.93C1014.27,-194.02 1082,-172.55 1130.36,-157.22"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1131.12,-159.55 1137.06,-155.1 1129.64,-154.88 1131.12,-159.55"/>
|
||||
<text text-anchor="middle" x="1081" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1215.38,-220.18C1255.37,-215 1294,-210 1294,-210 1294,-210 1721,-187 1721,-187 1721,-187 1750.1,-171.83 1775.91,-158.37"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1777.31,-160.41 1782.39,-155 1775.05,-156.06 1777.31,-160.41"/>
|
||||
<text text-anchor="middle" x="1756" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
|
||||
</g>
|
||||
<!-- gpio_controller->irq -->
|
||||
<g id="edge27" class="edge">
|
||||
<g id="edge28" class="edge">
|
||||
<title>gpio_controller->irq</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M983.24,-215.69C1073.8,-199.28 1215.3,-173.64 1310.73,-156.35"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1311.35,-158.73 1317.8,-155.07 1310.48,-153.91 1311.35,-158.73"/>
|
||||
<text text-anchor="middle" x="1196" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ18</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1190.51,-209.93C1236.46,-194.08 1298.35,-172.72 1342.75,-157.41"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1343.63,-159.7 1349.45,-155.1 1342.03,-155.06 1343.63,-159.7"/>
|
||||
<text text-anchor="middle" x="1291" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ18</text>
|
||||
</g>
|
||||
<!-- timers->irq -->
|
||||
<g id="edge28" class="edge">
|
||||
<g id="edge29" class="edge">
|
||||
<title>timers->irq</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1730.31,-212.47C1722.16,-210.96 1717,-210 1717,-210 1717,-210 1466,-187 1466,-187 1466,-187 1450.5,-172.93 1436.11,-159.88"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1437.72,-158.03 1430.89,-155.14 1434.42,-161.66 1437.72,-158.03"/>
|
||||
<text text-anchor="middle" x="1488.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ3 / IRQ4</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1013.6,-211.84C1098.98,-195.48 1219.64,-172.37 1303.1,-156.37"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1303.64,-158.77 1310.05,-155.04 1302.71,-153.95 1303.64,-158.77"/>
|
||||
<text text-anchor="middle" x="1206.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ3 / IRQ4</text>
|
||||
</g>
|
||||
<!-- ws2812->gpio_bridge -->
|
||||
<g id="edge30" class="edge">
|
||||
<g id="edge31" class="edge">
|
||||
<title>ws2812->gpio_bridge</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1360.25,-209.93C1323.34,-194.24 1273.74,-173.16 1237.78,-157.88"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1238.63,-155.58 1231.23,-155.1 1236.71,-160.09 1238.63,-155.58"/>
|
||||
<text text-anchor="middle" x="1323.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO2 ALT1</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M2013.72,-213.17C2005.45,-211.26 2000,-210 2000,-210 2000,-210 1832,-187 1832,-187 1832,-187 1827.62,-174.38 1823.31,-161.94"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1825.55,-160.95 1820.95,-155.14 1820.93,-162.55 1825.55,-160.95"/>
|
||||
<text text-anchor="middle" x="1854.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO2 ALT1</text>
|
||||
</g>
|
||||
<!-- ws2812->irq -->
|
||||
<g id="edge32" class="edge">
|
||||
<g id="edge33" class="edge">
|
||||
<title>ws2812->irq</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1410.51,-209.77C1410.26,-198.48 1410,-187 1410,-187 1410,-187 1410,-178 1410,-178 1410,-178 1410.37,-170.7 1410.78,-162.33"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1413.24,-162.31 1411.14,-155.2 1408.34,-162.06 1413.24,-162.31"/>
|
||||
<text text-anchor="middle" x="1422" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ17</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M2013.72,-213.17C2005.45,-211.26 2000,-210 2000,-210 2000,-210 1691,-187 1691,-187 1691,-187 1660,-178 1660,-178 1660,-178 1586.26,-166.7 1517.16,-156.11"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1517.36,-153.66 1510.07,-155.02 1516.61,-158.5 1517.36,-153.66"/>
|
||||
<text text-anchor="middle" x="1703" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ17</text>
|
||||
</g>
|
||||
<!-- apb_targets->gpio_controller -->
|
||||
<g id="edge35" class="edge">
|
||||
<g id="edge39" class="edge">
|
||||
<title>apb_targets->gpio_controller</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M609.73,-254.58C675.1,-267.97 746,-282.5 746,-282.5 746,-282.5 782,-282.5 782,-282.5 782,-282.5 809.78,-270.32 837.91,-257.98"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="839.24,-260.07 844.67,-255.01 837.27,-255.58 839.24,-260.07"/>
|
||||
<text text-anchor="middle" x="764" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">user_gpio</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M609.59,-252.51C617.81,-254.04 623,-255 623,-255 623,-255 976,-282.5 976,-282.5 976,-282.5 1012,-282.5 1012,-282.5 1012,-282.5 1040.5,-270.21 1069.25,-257.82"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1070.31,-260.03 1075.77,-255.01 1068.37,-255.53 1070.31,-260.03"/>
|
||||
<text text-anchor="middle" x="994" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">user_gpio</text>
|
||||
</g>
|
||||
<!-- gpio_bridge->ext_io -->
|
||||
<g id="edge38" class="edge">
|
||||
<g id="edge42" class="edge">
|
||||
<title>gpio_bridge->ext_io</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1228.68,-115.34C1254.46,-101.2 1284,-85 1284,-85 1284,-85 1386.02,-63.94 1470.68,-46.47"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1227.19,-113.36 1222.23,-118.88 1229.54,-117.66 1227.19,-113.36"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1471.41,-48.82 1477.77,-45.01 1470.42,-44.03 1471.41,-48.82"/>
|
||||
<text text-anchor="middle" x="1383" y="-70.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1839,-113.95C1860.61,-94.09 1889,-68 1889,-68 1889,-68 1900.85,-59.21 1914.01,-49.45"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1837.17,-112.3 1833.67,-118.84 1840.49,-115.91 1837.17,-112.3"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1915.54,-51.37 1919.7,-45.23 1912.62,-47.43 1915.54,-51.37"/>
|
||||
<text text-anchor="middle" x="1909" y="-70.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 43 KiB |
@@ -26,6 +26,16 @@ SoC wrappers use the existing clusterIP interfaces for protocol boundaries.
|
||||
`apb4_if_bridge` only adapts `apb4_pure_if` to `apb4_if`, and `gpio_pad_bridge`
|
||||
only exposes the pad-side subset of `gpio_if`; neither module contains state.
|
||||
|
||||
## I2C alternate functions
|
||||
|
||||
The two I2C V2 controllers reuse GPIO pads rather than dedicated package pins.
|
||||
I2C0 uses GPIO7 for SCL and GPIO8 for SDA on ALT0. I2C1 uses GPIO3 for SCL and
|
||||
GPIO4 for SDA on ALT1. Both controller outputs are constant zero; the GPIO
|
||||
alternate-function output enable pulls a line low and releases it for high.
|
||||
Board-level pull-ups are therefore required. I2C0 uses management-core IRQ7
|
||||
and generic-DMA modes 7/8; I2C1 uses IRQ19 and DMA modes 9/10. See
|
||||
[i2c.md](ip/i2c.md) for the register and transfer contract.
|
||||
|
||||
## WS2812 output
|
||||
|
||||
The single-channel WS2812 transmitter occupies RIBP address `0x10008000` and
|
||||
|
||||
@@ -34,6 +34,10 @@ interface dma_hw_trg_if ();
|
||||
logic qspi_rx_proc;
|
||||
logic uart_tx_proc;
|
||||
logic uart_rx_proc;
|
||||
logic i2c0_tx_proc;
|
||||
logic i2c0_rx_proc;
|
||||
logic i2c1_tx_proc;
|
||||
logic i2c1_rx_proc;
|
||||
|
||||
modport dut(
|
||||
input i2s_tx_proc,
|
||||
@@ -41,7 +45,11 @@ interface dma_hw_trg_if ();
|
||||
input qspi_tx_proc,
|
||||
input qspi_rx_proc,
|
||||
input uart_tx_proc,
|
||||
input uart_rx_proc
|
||||
input uart_rx_proc,
|
||||
input i2c0_tx_proc,
|
||||
input i2c0_rx_proc,
|
||||
input i2c1_tx_proc,
|
||||
input i2c1_rx_proc
|
||||
);
|
||||
endinterface
|
||||
|
||||
@@ -49,12 +57,12 @@ endinterface
|
||||
|
||||
module ribp_dma (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
output logic dma_xfer_done_o,
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
output logic dma_xfer_done_o,
|
||||
dma_hw_trg_if.dut hw_trg,
|
||||
ribp_if.slave ribp,
|
||||
rib_if.master rib
|
||||
ribp_if.slave ribp,
|
||||
rib_if.master rib
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
@@ -64,7 +72,7 @@ module ribp_dma (
|
||||
logic [31:0] s_ribp_rdata_d, s_ribp_rdata_q;
|
||||
|
||||
logic s_dma_mode_en;
|
||||
logic [2:0] s_dma_mode_d, s_dma_mode_q;
|
||||
logic [3:0] s_dma_mode_d, s_dma_mode_q;
|
||||
logic s_dma_srcaddr_en;
|
||||
logic [31:0] s_dma_srcaddr_d, s_dma_srcaddr_q;
|
||||
logic s_dma_srcincr_en;
|
||||
@@ -97,13 +105,13 @@ module ribp_dma (
|
||||
|
||||
|
||||
assign s_dma_mode_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_DMA_MODE;
|
||||
assign s_dma_mode_d = ribp.wdata[2:0];
|
||||
dffer #(3) u_dma_mode_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_dma_mode_en,
|
||||
s_dma_mode_d,
|
||||
s_dma_mode_q
|
||||
assign s_dma_mode_d = ribp.wdata[3:0];
|
||||
dffer #(4) u_dma_mode_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_dma_mode_en),
|
||||
.dat_i (s_dma_mode_d),
|
||||
.dat_o (s_dma_mode_q)
|
||||
);
|
||||
|
||||
|
||||
@@ -116,22 +124,22 @@ module ribp_dma (
|
||||
if (ribp.wstrb[3]) s_dma_srcaddr_d[31:24] = ribp.wdata[31:24];
|
||||
end
|
||||
dffer #(32) u_dma_srcaddr_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_dma_srcaddr_en,
|
||||
s_dma_srcaddr_d,
|
||||
s_dma_srcaddr_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_dma_srcaddr_en),
|
||||
.dat_i (s_dma_srcaddr_d),
|
||||
.dat_o (s_dma_srcaddr_q)
|
||||
);
|
||||
|
||||
|
||||
assign s_dma_srcincr_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_DMA_SRCINCR;
|
||||
assign s_dma_srcincr_d = ribp.wdata[0];
|
||||
dffer #(1) u_dma_srcincr_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_dma_srcincr_en,
|
||||
s_dma_srcincr_d,
|
||||
s_dma_srcincr_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_dma_srcincr_en),
|
||||
.dat_i (s_dma_srcincr_d),
|
||||
.dat_o (s_dma_srcincr_q)
|
||||
);
|
||||
|
||||
|
||||
@@ -144,21 +152,21 @@ module ribp_dma (
|
||||
if (ribp.wstrb[3]) s_dma_dstaddr_d[31:24] = ribp.wdata[31:24];
|
||||
end
|
||||
dffer #(32) u_dma_dstaddr_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_dma_dstaddr_en,
|
||||
s_dma_dstaddr_d,
|
||||
s_dma_dstaddr_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_dma_dstaddr_en),
|
||||
.dat_i (s_dma_dstaddr_d),
|
||||
.dat_o (s_dma_dstaddr_q)
|
||||
);
|
||||
|
||||
assign s_dma_dstincr_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_DMA_DSTINCR;
|
||||
assign s_dma_dstincr_d = ribp.wdata[0];
|
||||
dffer #(1) u_dma_dstincr_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_dma_dstincr_en,
|
||||
s_dma_dstincr_d,
|
||||
s_dma_dstincr_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_dma_dstincr_en),
|
||||
.dat_i (s_dma_dstincr_d),
|
||||
.dat_o (s_dma_dstincr_q)
|
||||
);
|
||||
|
||||
assign s_dma_xferlen_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_DMA_XFERLEN;
|
||||
@@ -170,11 +178,11 @@ module ribp_dma (
|
||||
if (ribp.wstrb[3]) s_dma_xferlen_d[31:24] = ribp.wdata[31:24];
|
||||
end
|
||||
dffer #(32) u_dma_xferlen_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_dma_xferlen_en,
|
||||
s_dma_xferlen_d,
|
||||
s_dma_xferlen_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_dma_xferlen_en),
|
||||
.dat_i (s_dma_xferlen_d),
|
||||
.dat_o (s_dma_xferlen_q)
|
||||
);
|
||||
|
||||
|
||||
@@ -192,10 +200,10 @@ module ribp_dma (
|
||||
end
|
||||
end
|
||||
dffr #(1) u_dma_status_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_dma_status_d,
|
||||
s_dma_status_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_dma_status_d),
|
||||
.dat_o (s_dma_status_q)
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
@@ -208,42 +216,42 @@ module ribp_dma (
|
||||
end
|
||||
end
|
||||
dffr #(1) u_dma_error_status_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_dma_error_status_d,
|
||||
s_dma_error_status_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_dma_error_status_d),
|
||||
.dat_o (s_dma_error_status_q)
|
||||
);
|
||||
assign s_dma_error_code_d = s_xfer_error_code;
|
||||
dffer #(3) u_dma_error_code_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_xfer_error,
|
||||
s_dma_error_code_d,
|
||||
s_dma_error_code_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_xfer_error),
|
||||
.dat_i (s_dma_error_code_d),
|
||||
.dat_o (s_dma_error_code_q)
|
||||
);
|
||||
assign s_dma_error_addr_d = s_xfer_error_addr;
|
||||
dffer #(32) u_dma_error_addr_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_xfer_error,
|
||||
s_dma_error_addr_d,
|
||||
s_dma_error_addr_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_xfer_error),
|
||||
.dat_i (s_dma_error_addr_d),
|
||||
.dat_o (s_dma_error_addr_q)
|
||||
);
|
||||
|
||||
|
||||
assign s_ribp_ready_d = ribp.valid && (~s_ribp_ready_q);
|
||||
dffr #(1) u_ribp_ready_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_ribp_ready_d,
|
||||
s_ribp_ready_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_ribp_ready_d),
|
||||
.dat_o (s_ribp_ready_q)
|
||||
);
|
||||
|
||||
assign s_ribp_rdata_en = s_ribp_rd_hdshk;
|
||||
always_comb begin
|
||||
s_ribp_rdata_d = s_ribp_rdata_q;
|
||||
unique case (ribp.addr[7:0])
|
||||
`RIBP_DMA_MODE: s_ribp_rdata_d = {29'd0, s_dma_mode_q};
|
||||
`RIBP_DMA_MODE: s_ribp_rdata_d = {28'd0, s_dma_mode_q};
|
||||
`RIBP_DMA_SRCADDR: s_ribp_rdata_d = s_dma_srcaddr_q;
|
||||
`RIBP_DMA_SRCINCR: s_ribp_rdata_d = {31'd0, s_dma_srcincr_q};
|
||||
`RIBP_DMA_DSTADDR: s_ribp_rdata_d = s_dma_dstaddr_q;
|
||||
@@ -257,11 +265,11 @@ module ribp_dma (
|
||||
endcase
|
||||
end
|
||||
dffer #(32) u_ribp_rdata_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_ribp_rdata_en,
|
||||
s_ribp_rdata_d,
|
||||
s_ribp_rdata_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_ribp_rdata_en),
|
||||
.dat_i (s_ribp_rdata_d),
|
||||
.dat_o (s_ribp_rdata_q)
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -13,34 +13,38 @@
|
||||
|
||||
module dma_core (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic [2:0] mode_i,
|
||||
input logic [31:0] srcaddr_i,
|
||||
input logic srcincr_i,
|
||||
input logic [31:0] dstaddr_i,
|
||||
input logic dstincr_i,
|
||||
input logic [31:0] xferlen_i,
|
||||
input logic start_i,
|
||||
input logic stop_i,
|
||||
input logic reset_i,
|
||||
output logic done_o,
|
||||
output logic error_o,
|
||||
output logic [2:0] error_code_o,
|
||||
output logic [31:0] error_addr_o,
|
||||
output logic [1:0] fsm_o,
|
||||
dma_hw_trg_if.dut hw_trg,
|
||||
rib_if.master rib
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic [3:0] mode_i,
|
||||
input logic [31:0] srcaddr_i,
|
||||
input logic srcincr_i,
|
||||
input logic [31:0] dstaddr_i,
|
||||
input logic dstincr_i,
|
||||
input logic [31:0] xferlen_i,
|
||||
input logic start_i,
|
||||
input logic stop_i,
|
||||
input logic reset_i,
|
||||
output logic done_o,
|
||||
output logic error_o,
|
||||
output logic [2:0] error_code_o,
|
||||
output logic [31:0] error_addr_o,
|
||||
output logic [1:0] fsm_o,
|
||||
dma_hw_trg_if.dut hw_trg,
|
||||
rib_if.master rib
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
localparam logic [2:0] SFT_TRG = 3'd0;
|
||||
localparam logic [2:0] HWT_I2S_TX_TRG = 3'd1;
|
||||
localparam logic [2:0] HWT_I2S_RX_TRG = 3'd2;
|
||||
localparam logic [2:0] HWT_QSPI_TX_TRG = 3'd3;
|
||||
localparam logic [2:0] HWT_QSPI_RX_TRG = 3'd4;
|
||||
localparam logic [2:0] HWT_UART_TX_TRG = 3'd5;
|
||||
localparam logic [2:0] HWT_UART_RX_TRG = 3'd6;
|
||||
localparam logic [3:0] SFT_TRG = 4'd0;
|
||||
localparam logic [3:0] HWT_I2S_TX_TRG = 4'd1;
|
||||
localparam logic [3:0] HWT_I2S_RX_TRG = 4'd2;
|
||||
localparam logic [3:0] HWT_QSPI_TX_TRG = 4'd3;
|
||||
localparam logic [3:0] HWT_QSPI_RX_TRG = 4'd4;
|
||||
localparam logic [3:0] HWT_UART_TX_TRG = 4'd5;
|
||||
localparam logic [3:0] HWT_UART_RX_TRG = 4'd6;
|
||||
localparam logic [3:0] HWT_I2C0_TX_TRG = 4'd7;
|
||||
localparam logic [3:0] HWT_I2C0_RX_TRG = 4'd8;
|
||||
localparam logic [3:0] HWT_I2C1_TX_TRG = 4'd9;
|
||||
localparam logic [3:0] HWT_I2C1_RX_TRG = 4'd10;
|
||||
|
||||
localparam logic [2:0] FSM_IDLE = 3'd0;
|
||||
localparam logic [2:0] FSM_RD_CMD = 3'd1;
|
||||
@@ -89,6 +93,8 @@ module dma_core (
|
||||
HWT_I2S_RX_TRG: s_read_trigger = hw_trg.i2s_rx_proc;
|
||||
HWT_QSPI_RX_TRG: s_read_trigger = hw_trg.qspi_rx_proc;
|
||||
HWT_UART_RX_TRG: s_read_trigger = hw_trg.uart_rx_proc;
|
||||
HWT_I2C0_RX_TRG: s_read_trigger = hw_trg.i2c0_rx_proc;
|
||||
HWT_I2C1_RX_TRG: s_read_trigger = hw_trg.i2c1_rx_proc;
|
||||
default: s_read_trigger = 1'b1;
|
||||
endcase
|
||||
end
|
||||
@@ -99,6 +105,8 @@ module dma_core (
|
||||
HWT_I2S_TX_TRG: s_write_trigger = hw_trg.i2s_tx_proc;
|
||||
HWT_QSPI_TX_TRG: s_write_trigger = hw_trg.qspi_tx_proc;
|
||||
HWT_UART_TX_TRG: s_write_trigger = hw_trg.uart_tx_proc;
|
||||
HWT_I2C0_TX_TRG: s_write_trigger = hw_trg.i2c0_tx_proc;
|
||||
HWT_I2C1_TX_TRG: s_write_trigger = hw_trg.i2c1_tx_proc;
|
||||
default: s_write_trigger = 1'b1;
|
||||
endcase
|
||||
end
|
||||
@@ -231,34 +239,34 @@ module dma_core (
|
||||
end
|
||||
|
||||
dffr #(3) u_fsm_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_fsm_d,
|
||||
s_fsm_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_fsm_d),
|
||||
.dat_o (s_fsm_q)
|
||||
);
|
||||
dffr #(32) u_xfer_cnt_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_xfer_cnt_d,
|
||||
s_xfer_cnt_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_xfer_cnt_d),
|
||||
.dat_o (s_xfer_cnt_q)
|
||||
);
|
||||
dffr #(32) u_src_addr_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_src_addr_d,
|
||||
s_src_addr_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_src_addr_d),
|
||||
.dat_o (s_src_addr_q)
|
||||
);
|
||||
dffr #(32) u_dst_addr_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_dst_addr_d,
|
||||
s_dst_addr_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_dst_addr_d),
|
||||
.dat_o (s_dst_addr_q)
|
||||
);
|
||||
dffr #(2) u_wr_beat_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_wr_beat_d,
|
||||
s_wr_beat_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_wr_beat_d),
|
||||
.dat_o (s_wr_beat_q)
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
@@ -267,10 +275,10 @@ module dma_core (
|
||||
if (reset_i) s_ctrl_stop_d = 1'b0;
|
||||
end
|
||||
dffr #(1) u_ctrl_stop_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_ctrl_stop_d,
|
||||
s_ctrl_stop_q
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_ctrl_stop_d),
|
||||
.dat_o (s_ctrl_stop_q)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -1,222 +0,0 @@
|
||||
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
// You may obtain a copy of Mulan PSL v2 at:
|
||||
// http://license.coscl.org.cn/MulanPSL2
|
||||
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
// See the Mulan PSL v2 for more details.
|
||||
|
||||
`ifndef RIBP_I2C_DEF_SV
|
||||
`define RIBP_I2C_DEF_SV
|
||||
|
||||
// verilog_format: off
|
||||
`define RIBP_I2C_CLKDIV 8'h00
|
||||
`define RIBP_I2C_DEVADDR 8'h04
|
||||
`define RIBP_I2C_REGADDR 8'h08
|
||||
`define RIBP_I2C_TXDATA 8'h0C
|
||||
`define RIBP_I2C_RXDATA 8'h10
|
||||
`define RIBP_I2C_XFER 8'h14
|
||||
`define RIBP_I2C_CFG 8'h18
|
||||
`define RIBP_I2C_STATUS 8'h1C
|
||||
// verilog_format: on
|
||||
|
||||
`endif
|
||||
|
||||
module ribp_i2c (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
ribp_if.slave ribp,
|
||||
i2c_if.dut i2c
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
logic s_ribp_wr_hdshk, s_ribp_rd_hdshk;
|
||||
logic s_ribp_ready_d, s_ribp_ready_q;
|
||||
logic s_ribp_rdata_en;
|
||||
logic [31:0] s_ribp_rdata_d, s_ribp_rdata_q;
|
||||
|
||||
//2^7=128
|
||||
logic s_i2c_clkdiv_en;
|
||||
logic [6:0] s_i2c_clkdiv_d, s_i2c_clkdiv_q;
|
||||
logic s_i2c_devaddr_en;
|
||||
logic [6:0] s_i2c_devaddr_d, s_i2c_devaddr_q;
|
||||
logic s_i2c_regaddr_en;
|
||||
logic [15:0] s_i2c_regaddr_d, s_i2c_regaddr_q;
|
||||
logic s_i2c_txdata_en;
|
||||
logic [7:0] s_i2c_txdata_d, s_i2c_txdata_q;
|
||||
logic [7:0] s_i2c_rxdata;
|
||||
logic [1:0] s_i2c_xfer_d, s_i2c_xfer_q;
|
||||
logic s_i2c_cfg_en;
|
||||
logic s_i2c_cfg_d, s_i2c_cfg_q;
|
||||
logic s_i2c_status_d, s_i2c_status_q;
|
||||
|
||||
logic s_bit_rdwr, s_bit_start;
|
||||
logic s_bit_end, s_bit_end_re;
|
||||
logic s_bit_extn_addr;
|
||||
|
||||
logic s_oper_clk_pos;
|
||||
|
||||
assign s_bit_rdwr = s_i2c_xfer_q[0];
|
||||
assign s_bit_start = s_i2c_xfer_q[1];
|
||||
assign s_bit_extn_addr = s_i2c_cfg_q;
|
||||
|
||||
assign s_ribp_wr_hdshk = ribp.valid && (~s_ribp_ready_q) && (|ribp.wstrb);
|
||||
assign s_ribp_rd_hdshk = ribp.valid && (~s_ribp_ready_q) && (~(|ribp.wstrb));
|
||||
assign ribp.ready = s_ribp_ready_q;
|
||||
assign ribp.resp_err = 1'b0;
|
||||
assign ribp.rdata = s_ribp_rdata_q;
|
||||
|
||||
|
||||
assign s_i2c_clkdiv_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_I2C_CLKDIV;
|
||||
assign s_i2c_clkdiv_d = ribp.wdata[6:0];
|
||||
dffer #(7) u_i2c_clkdiv_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_i2c_clkdiv_en,
|
||||
s_i2c_clkdiv_d,
|
||||
s_i2c_clkdiv_q
|
||||
);
|
||||
|
||||
assign s_i2c_devaddr_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_I2C_DEVADDR;
|
||||
assign s_i2c_devaddr_d = ribp.wdata[6:0];
|
||||
dffer #(7) u_i2c_devaddr_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_i2c_devaddr_en,
|
||||
s_i2c_devaddr_d,
|
||||
s_i2c_devaddr_q
|
||||
);
|
||||
|
||||
|
||||
assign s_i2c_regaddr_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_I2C_REGADDR;
|
||||
always_comb begin
|
||||
s_i2c_regaddr_d = s_i2c_regaddr_q;
|
||||
if (ribp.wstrb[0]) s_i2c_regaddr_d[7:0] = ribp.wdata[7:0];
|
||||
if (ribp.wstrb[1]) s_i2c_regaddr_d[15:8] = ribp.wdata[15:8];
|
||||
end
|
||||
dffer #(16) u_i2c_regaddr_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_i2c_regaddr_en,
|
||||
s_i2c_regaddr_d,
|
||||
s_i2c_regaddr_q
|
||||
);
|
||||
|
||||
|
||||
assign s_i2c_txdata_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_I2C_TXDATA;
|
||||
assign s_i2c_txdata_d = ribp.wdata[7:0];
|
||||
dffer #(8) u_i2c_txdata_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_i2c_txdata_en,
|
||||
s_i2c_txdata_d,
|
||||
s_i2c_txdata_q
|
||||
);
|
||||
|
||||
|
||||
always_comb begin
|
||||
s_i2c_xfer_d = s_i2c_xfer_q;
|
||||
if (s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_I2C_XFER) begin
|
||||
s_i2c_xfer_d = ribp.wdata[1:0];
|
||||
end else if (s_oper_clk_pos && (|s_i2c_xfer_q)) begin
|
||||
s_i2c_xfer_d = '0;
|
||||
end
|
||||
end
|
||||
dffr #(2) u_i2c_xfer_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_i2c_xfer_d,
|
||||
s_i2c_xfer_q
|
||||
);
|
||||
|
||||
|
||||
assign s_i2c_cfg_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_I2C_CFG;
|
||||
assign s_i2c_cfg_d = ribp.wdata[0];
|
||||
dffer #(1) u_i2c_cfg_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_i2c_cfg_en,
|
||||
s_i2c_cfg_d,
|
||||
s_i2c_cfg_q
|
||||
);
|
||||
|
||||
|
||||
edge_det_sync_re #(1) u_i2c_end_edge_det_sync_re (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_bit_end,
|
||||
s_bit_end_re
|
||||
);
|
||||
always_comb begin
|
||||
s_i2c_status_d = s_i2c_status_q;
|
||||
if (s_bit_end_re) s_i2c_status_d = 1'b1;
|
||||
else if (s_ribp_rd_hdshk && ribp.addr[7:0] == `RIBP_I2C_STATUS) begin
|
||||
s_i2c_status_d = 1'b0;
|
||||
end
|
||||
end
|
||||
dffr #(1) u_i2c_status_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_i2c_status_d,
|
||||
s_i2c_status_q
|
||||
);
|
||||
|
||||
|
||||
assign s_ribp_ready_d = ribp.valid && (~s_ribp_ready_q);
|
||||
dffr #(1) u_ribp_ready_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_ribp_ready_d,
|
||||
s_ribp_ready_q
|
||||
);
|
||||
|
||||
assign s_ribp_rdata_en = s_ribp_rd_hdshk;
|
||||
always_comb begin
|
||||
s_ribp_rdata_d = s_ribp_rdata_q;
|
||||
unique case (ribp.addr[7:0])
|
||||
`RIBP_I2C_CLKDIV: s_ribp_rdata_d = {25'd0, s_i2c_clkdiv_q};
|
||||
`RIBP_I2C_DEVADDR: s_ribp_rdata_d = {25'd0, s_i2c_devaddr_q};
|
||||
`RIBP_I2C_REGADDR: s_ribp_rdata_d = {16'd0, s_i2c_regaddr_q};
|
||||
`RIBP_I2C_TXDATA: s_ribp_rdata_d = {24'd0, s_i2c_txdata_q};
|
||||
`RIBP_I2C_RXDATA: s_ribp_rdata_d = {24'd0, s_i2c_rxdata};
|
||||
`RIBP_I2C_XFER: s_ribp_rdata_d = {30'd0, s_i2c_xfer_q};
|
||||
`RIBP_I2C_CFG: s_ribp_rdata_d = {31'd0, s_i2c_cfg_q};
|
||||
`RIBP_I2C_STATUS: s_ribp_rdata_d = {31'd0, s_i2c_status_q};
|
||||
default: s_ribp_rdata_d = s_ribp_rdata_q;
|
||||
endcase
|
||||
end
|
||||
dffer #(32) u_ribp_rdata_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_ribp_rdata_en,
|
||||
s_ribp_rdata_d,
|
||||
s_ribp_rdata_q
|
||||
);
|
||||
|
||||
|
||||
assign i2c.scl_oe_o = 1'b1;
|
||||
assign i2c.irq_o = 1'b0;
|
||||
i2c_core u_i2c_core (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.clk_div_i (s_i2c_clkdiv_q),
|
||||
.dev_addr_i (s_i2c_devaddr_q),
|
||||
.rdwr_i (s_bit_rdwr),
|
||||
.start_i (s_bit_start),
|
||||
.end_o (s_bit_end),
|
||||
.extn_addr_i (s_bit_extn_addr),
|
||||
.reg_addr_i (s_i2c_regaddr_q),
|
||||
.wr_data_i (s_i2c_txdata_q),
|
||||
.rd_data_o (s_i2c_rxdata),
|
||||
.oper_clk_pos_o(s_oper_clk_pos),
|
||||
.scl_o (i2c.scl_o),
|
||||
.sda_oe_o (i2c.sda_oe_o),
|
||||
.sda_o (i2c.sda_o),
|
||||
.sda_i (i2c.sda_i)
|
||||
);
|
||||
|
||||
|
||||
endmodule
|
||||
+755
-351
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,98 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module i2c_filter (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic [3:0] scl_filter_cycles_i,
|
||||
input logic [3:0] sda_filter_cycles_i,
|
||||
input logic scl_async_i,
|
||||
input logic sda_async_i,
|
||||
output logic scl_o,
|
||||
output logic sda_o
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
logic [1:0] s_line_sync;
|
||||
logic [3:0] s_scl_count_d, s_scl_count_q;
|
||||
logic [3:0] s_sda_count_d, s_sda_count_q;
|
||||
logic s_scl_d, s_scl_q;
|
||||
logic s_sda_d, s_sda_q;
|
||||
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(2)
|
||||
) u_line_cdc_sync (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i ({sda_async_i, scl_async_i}),
|
||||
.dat_o (s_line_sync)
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
s_scl_d = s_scl_q;
|
||||
s_scl_count_d = s_scl_count_q;
|
||||
if (s_line_sync[0] == s_scl_q) begin
|
||||
s_scl_count_d = '0;
|
||||
end else if ((scl_filter_cycles_i == 4'd0) ||
|
||||
(s_scl_count_q >= (scl_filter_cycles_i - 1'b1))) begin
|
||||
s_scl_d = s_line_sync[0];
|
||||
s_scl_count_d = '0;
|
||||
end else begin
|
||||
s_scl_count_d = s_scl_count_q + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
s_sda_d = s_sda_q;
|
||||
s_sda_count_d = s_sda_count_q;
|
||||
if (s_line_sync[1] == s_sda_q) begin
|
||||
s_sda_count_d = '0;
|
||||
end else if ((sda_filter_cycles_i == 4'd0) ||
|
||||
(s_sda_count_q >= (sda_filter_cycles_i - 1'b1))) begin
|
||||
s_sda_d = s_line_sync[1];
|
||||
s_sda_count_d = '0;
|
||||
end else begin
|
||||
s_sda_count_d = s_sda_count_q + 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
dffrc #(
|
||||
.DATA_WIDTH(1),
|
||||
.RESET_VAL (1'b1)
|
||||
) u_scl_dffrc (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_scl_d),
|
||||
.dat_o (s_scl_q)
|
||||
);
|
||||
|
||||
dffrc #(
|
||||
.DATA_WIDTH(1),
|
||||
.RESET_VAL (1'b1)
|
||||
) u_sda_dffrc (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_sda_d),
|
||||
.dat_o (s_sda_q)
|
||||
);
|
||||
|
||||
dffr #(4) u_scl_count_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_scl_count_d),
|
||||
.dat_o (s_scl_count_q)
|
||||
);
|
||||
|
||||
dffr #(4) u_sda_count_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_sda_count_d),
|
||||
.dat_o (s_sda_count_q)
|
||||
);
|
||||
|
||||
assign scl_o = s_scl_q;
|
||||
assign sda_o = s_sda_q;
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,718 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
`include "ribp_i2c_define.svh"
|
||||
|
||||
module i2c_reg #(
|
||||
parameter int CMD_FIFO_DEPTH = 16,
|
||||
parameter int RX_FIFO_DEPTH = 16,
|
||||
parameter int CMD_FIFO_LOG_DEPTH = $clog2(CMD_FIFO_DEPTH),
|
||||
parameter int RX_FIFO_LOG_DEPTH = $clog2(RX_FIFO_DEPTH)
|
||||
) (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
ribp_if.slave ribp,
|
||||
output logic enable_o,
|
||||
output logic [15:0] scl_low_cycles_o,
|
||||
output logic [15:0] scl_high_cycles_o,
|
||||
output logic [15:0] start_hold_cycles_o,
|
||||
output logic [15:0] start_setup_cycles_o,
|
||||
output logic [15:0] data_hold_cycles_o,
|
||||
output logic [15:0] data_setup_cycles_o,
|
||||
output logic [15:0] stop_setup_cycles_o,
|
||||
output logic [15:0] bus_free_cycles_o,
|
||||
output logic [ 3:0] scl_filter_cycles_o,
|
||||
output logic [ 3:0] sda_filter_cycles_o,
|
||||
output logic [23:0] stretch_timeout_o,
|
||||
output logic [23:0] bus_idle_timeout_o,
|
||||
output logic [23:0] command_timeout_o,
|
||||
output logic [ 9:0] target_addr_o,
|
||||
output logic ten_bit_o,
|
||||
output logic abort_o,
|
||||
output logic recover_o,
|
||||
output logic cmd_valid_o,
|
||||
output logic [11:0] cmd_data_o,
|
||||
input logic cmd_pop_i,
|
||||
input logic core_cmd_flush_i,
|
||||
input logic rx_push_i,
|
||||
input logic [ 7:0] rx_data_i,
|
||||
output logic rx_full_o,
|
||||
input logic busy_i,
|
||||
input logic recovery_active_i,
|
||||
input logic scl_i,
|
||||
input logic sda_i,
|
||||
input logic done_event_i,
|
||||
input logic addr_nack_event_i,
|
||||
input logic data_nack_event_i,
|
||||
input logic arb_lost_event_i,
|
||||
input logic stretch_timeout_event_i,
|
||||
input logic bus_timeout_event_i,
|
||||
input logic command_timeout_event_i,
|
||||
input logic command_error_event_i,
|
||||
input logic rx_overflow_event_i,
|
||||
input logic aborted_event_i,
|
||||
input logic recovery_done_event_i,
|
||||
input logic recovery_failed_event_i,
|
||||
output logic dma_tx_stall_o,
|
||||
output logic dma_rx_stall_o,
|
||||
output logic irq_o
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
localparam logic [31:0] IP_VERSION = 32'h0002_0000;
|
||||
localparam logic [7:0] CMD_DEPTH_INFO = 8'(CMD_FIFO_DEPTH);
|
||||
localparam logic [7:0] RX_DEPTH_INFO = 8'(RX_FIFO_DEPTH);
|
||||
localparam logic [31:0] CAPABILITY = {9'd0, 7'h7F, RX_DEPTH_INFO, CMD_DEPTH_INFO};
|
||||
localparam logic [31:0] CMD_WATERMARK_RESET = (CMD_FIFO_DEPTH > 4) ? 32'd4 : CMD_FIFO_DEPTH - 1;
|
||||
localparam logic [31:0] RX_WATERMARK_RESET = (RX_FIFO_DEPTH > 8) ? 32'd8 : RX_FIFO_DEPTH;
|
||||
|
||||
logic s_req;
|
||||
logic s_write;
|
||||
logic s_req_accept;
|
||||
logic s_access_error;
|
||||
logic s_ribp_ready_d, s_ribp_ready_q;
|
||||
logic s_ribp_resp_err_d, s_ribp_resp_err_q;
|
||||
logic [31:0] s_ribp_rdata_d, s_ribp_rdata_q;
|
||||
|
||||
logic s_enable_en;
|
||||
logic s_enable_d, s_enable_q;
|
||||
logic s_scl_timing_en;
|
||||
logic [31:0] s_scl_timing_d, s_scl_timing_q;
|
||||
logic s_start_timing_en;
|
||||
logic [31:0] s_start_timing_d, s_start_timing_q;
|
||||
logic s_data_timing_en;
|
||||
logic [31:0] s_data_timing_d, s_data_timing_q;
|
||||
logic s_stop_timing_en;
|
||||
logic [31:0] s_stop_timing_d, s_stop_timing_q;
|
||||
logic s_filter_en;
|
||||
logic [11:0] s_filter_d, s_filter_q;
|
||||
logic s_stretch_timeout_en;
|
||||
logic [23:0] s_stretch_timeout_d, s_stretch_timeout_q;
|
||||
logic s_bus_idle_timeout_en;
|
||||
logic [23:0] s_bus_idle_timeout_d, s_bus_idle_timeout_q;
|
||||
logic s_command_timeout_en;
|
||||
logic [23:0] s_command_timeout_d, s_command_timeout_q;
|
||||
logic s_target_addr_en;
|
||||
logic [10:0] s_target_addr_d, s_target_addr_q;
|
||||
logic s_cmd_watermark_en;
|
||||
logic [7:0] s_cmd_watermark_d, s_cmd_watermark_q;
|
||||
logic s_rx_watermark_en;
|
||||
logic [7:0] s_rx_watermark_d, s_rx_watermark_q;
|
||||
logic s_intr_enable_en;
|
||||
logic [7:0] s_intr_enable_d, s_intr_enable_q;
|
||||
|
||||
logic s_cmd_push;
|
||||
logic s_cmd_flush_cmd;
|
||||
logic s_cmd_empty;
|
||||
logic s_cmd_full;
|
||||
logic [ 11:0] s_cmd_pop_data;
|
||||
logic [CMD_FIFO_LOG_DEPTH:0] s_cmd_count;
|
||||
logic s_rx_pop;
|
||||
logic s_rx_flush_cmd;
|
||||
logic s_rx_empty;
|
||||
logic s_rx_full;
|
||||
logic [ 7:0] s_rx_pop_data;
|
||||
logic [ RX_FIFO_LOG_DEPTH:0] s_rx_count;
|
||||
|
||||
logic [10:0] s_error_status_d, s_error_status_q;
|
||||
logic [7:0] s_intr_state_d, s_intr_state_q;
|
||||
logic [10:0] s_error_clear;
|
||||
logic [ 7:0] s_intr_clear;
|
||||
logic [ 7:0] s_intr_test;
|
||||
logic s_config_error_event;
|
||||
logic s_sw_command_error_event;
|
||||
logic s_timeout_event;
|
||||
logic s_error_event;
|
||||
logic s_cmd_watermark_active;
|
||||
logic s_rx_watermark_active;
|
||||
logic s_tx_dma_req;
|
||||
logic s_rx_dma_req;
|
||||
logic s_config_valid;
|
||||
logic [31:0] s_status;
|
||||
logic [31:0] s_fifo_level;
|
||||
logic [31:0] s_line_state;
|
||||
logic [31:0] s_merge_value;
|
||||
|
||||
function automatic logic [31:0] merge_wstrb(input logic [31:0] current, input logic [31:0] value,
|
||||
input logic [3:0] strobe);
|
||||
logic [31:0] merged;
|
||||
integer byte_index;
|
||||
begin
|
||||
merged = current;
|
||||
for (byte_index = 0; byte_index < 4; byte_index = byte_index + 1) begin
|
||||
if (strobe[byte_index]) begin
|
||||
merged[byte_index*8+:8] = value[byte_index*8+:8];
|
||||
end
|
||||
end
|
||||
return merged;
|
||||
end
|
||||
endfunction
|
||||
|
||||
initial begin
|
||||
if ((CMD_FIFO_DEPTH > 255) || (RX_FIFO_DEPTH > 255)) begin
|
||||
$fatal(1, "i2c_reg: FIFO depths must fit CAPABILITY fields");
|
||||
end
|
||||
end
|
||||
|
||||
assign s_req = ribp.valid && !s_ribp_ready_q;
|
||||
assign s_write = |ribp.wstrb;
|
||||
assign ribp.ready = s_ribp_ready_q;
|
||||
assign ribp.resp_err = s_ribp_resp_err_q;
|
||||
assign ribp.rdata = s_ribp_rdata_q;
|
||||
assign enable_o = s_enable_q;
|
||||
assign scl_low_cycles_o = s_scl_timing_q[15:0];
|
||||
assign scl_high_cycles_o = s_scl_timing_q[31:16];
|
||||
assign start_hold_cycles_o = s_start_timing_q[15:0];
|
||||
assign start_setup_cycles_o = s_start_timing_q[31:16];
|
||||
assign data_hold_cycles_o = s_data_timing_q[15:0];
|
||||
assign data_setup_cycles_o = s_data_timing_q[31:16];
|
||||
assign stop_setup_cycles_o = s_stop_timing_q[15:0];
|
||||
assign bus_free_cycles_o = s_stop_timing_q[31:16];
|
||||
assign scl_filter_cycles_o = s_filter_q[3:0];
|
||||
assign sda_filter_cycles_o = s_filter_q[11:8];
|
||||
assign stretch_timeout_o = s_stretch_timeout_q;
|
||||
assign bus_idle_timeout_o = s_bus_idle_timeout_q;
|
||||
assign command_timeout_o = s_command_timeout_q;
|
||||
assign target_addr_o = s_target_addr_q[9:0];
|
||||
assign ten_bit_o = s_target_addr_q[10];
|
||||
assign cmd_valid_o = !s_cmd_empty;
|
||||
assign cmd_data_o = s_cmd_pop_data;
|
||||
assign rx_full_o = s_rx_full;
|
||||
|
||||
assign s_config_valid = (s_scl_timing_q[15:0] != 16'd0) &&
|
||||
(s_scl_timing_q[31:16] != 16'd0) &&
|
||||
(s_start_timing_q[15:0] != 16'd0) &&
|
||||
(s_start_timing_q[31:16] != 16'd0) &&
|
||||
(s_data_timing_q[15:0] < s_scl_timing_q[15:0]) &&
|
||||
(s_data_timing_q[31:16] != 16'd0) &&
|
||||
(s_data_timing_q[31:16] <= s_scl_timing_q[15:0]) &&
|
||||
(s_stop_timing_q[15:0] != 16'd0) &&
|
||||
(s_stop_timing_q[31:16] != 16'd0) &&
|
||||
(s_target_addr_q[10] || (s_target_addr_q[9:7] == 3'd0));
|
||||
assign s_cmd_watermark_active = s_enable_q && (8'(s_cmd_count) <= s_cmd_watermark_q);
|
||||
assign s_rx_watermark_active = s_enable_q && (8'(s_rx_count) >= s_rx_watermark_q);
|
||||
assign s_tx_dma_req = s_enable_q && s_config_valid && !s_cmd_full;
|
||||
assign s_rx_dma_req = s_enable_q && !s_rx_empty;
|
||||
assign dma_tx_stall_o = !s_tx_dma_req;
|
||||
assign dma_rx_stall_o = !s_rx_dma_req;
|
||||
assign irq_o = |(s_intr_state_q & s_intr_enable_q);
|
||||
|
||||
always_comb begin
|
||||
s_status = '0;
|
||||
s_status[`I2C_STATUS_ENABLE] = s_enable_q;
|
||||
s_status[`I2C_STATUS_BUSY] = busy_i;
|
||||
s_status[`I2C_STATUS_BUS_BUSY] = !(scl_i && sda_i);
|
||||
s_status[`I2C_STATUS_CMD_EMPTY] = s_cmd_empty;
|
||||
s_status[`I2C_STATUS_CMD_FULL] = s_cmd_full;
|
||||
s_status[`I2C_STATUS_RX_EMPTY] = s_rx_empty;
|
||||
s_status[`I2C_STATUS_RX_FULL] = s_rx_full;
|
||||
s_status[`I2C_STATUS_CONFIG_VALID] = s_config_valid;
|
||||
s_status[`I2C_STATUS_RECOVERY_ACTIVE] = recovery_active_i;
|
||||
s_status[`I2C_STATUS_SCL] = scl_i;
|
||||
s_status[`I2C_STATUS_SDA] = sda_i;
|
||||
s_status[`I2C_STATUS_TX_DMA_REQ] = s_tx_dma_req;
|
||||
s_status[`I2C_STATUS_RX_DMA_REQ] = s_rx_dma_req;
|
||||
s_fifo_level = '0;
|
||||
s_fifo_level[7:0] = 8'(s_cmd_count);
|
||||
s_fifo_level[23:16] = 8'(s_rx_count);
|
||||
s_line_state = '0;
|
||||
s_line_state[`I2C_LINE_SCL] = scl_i;
|
||||
s_line_state[`I2C_LINE_SDA] = sda_i;
|
||||
s_line_state[`I2C_LINE_BUS_FREE] = scl_i && sda_i;
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
s_req_accept = s_req;
|
||||
s_access_error = 1'b0;
|
||||
s_enable_en = 1'b0;
|
||||
s_scl_timing_en = 1'b0;
|
||||
s_start_timing_en = 1'b0;
|
||||
s_data_timing_en = 1'b0;
|
||||
s_stop_timing_en = 1'b0;
|
||||
s_filter_en = 1'b0;
|
||||
s_stretch_timeout_en = 1'b0;
|
||||
s_bus_idle_timeout_en = 1'b0;
|
||||
s_command_timeout_en = 1'b0;
|
||||
s_target_addr_en = 1'b0;
|
||||
s_cmd_watermark_en = 1'b0;
|
||||
s_rx_watermark_en = 1'b0;
|
||||
s_intr_enable_en = 1'b0;
|
||||
s_enable_d = s_enable_q;
|
||||
s_scl_timing_d = s_scl_timing_q;
|
||||
s_start_timing_d = s_start_timing_q;
|
||||
s_data_timing_d = s_data_timing_q;
|
||||
s_stop_timing_d = s_stop_timing_q;
|
||||
s_filter_d = s_filter_q;
|
||||
s_stretch_timeout_d = s_stretch_timeout_q;
|
||||
s_bus_idle_timeout_d = s_bus_idle_timeout_q;
|
||||
s_command_timeout_d = s_command_timeout_q;
|
||||
s_target_addr_d = s_target_addr_q;
|
||||
s_cmd_watermark_d = s_cmd_watermark_q;
|
||||
s_rx_watermark_d = s_rx_watermark_q;
|
||||
s_intr_enable_d = s_intr_enable_q;
|
||||
s_cmd_push = 1'b0;
|
||||
s_rx_pop = 1'b0;
|
||||
s_cmd_flush_cmd = 1'b0;
|
||||
s_rx_flush_cmd = 1'b0;
|
||||
abort_o = 1'b0;
|
||||
recover_o = 1'b0;
|
||||
s_error_clear = '0;
|
||||
s_intr_clear = '0;
|
||||
s_intr_test = '0;
|
||||
s_config_error_event = 1'b0;
|
||||
s_sw_command_error_event = 1'b0;
|
||||
s_ribp_rdata_d = '0;
|
||||
s_merge_value = '0;
|
||||
|
||||
if (s_req) begin
|
||||
if ((ribp.addr[11:8] != 4'd0) || (ribp.addr[1:0] != 2'b00)) begin
|
||||
s_access_error = 1'b1;
|
||||
end else if (s_write) begin
|
||||
unique case (ribp.addr[7:0])
|
||||
`RIBP_I2C_CTRL: begin
|
||||
s_merge_value = merge_wstrb({31'd0, s_enable_q}, ribp.wdata, ribp.wstrb);
|
||||
if ((s_merge_value[31:1] != 31'd0) ||
|
||||
(s_merge_value[0] && !s_config_valid) ||
|
||||
(!s_merge_value[0] && (busy_i || recovery_active_i))) begin
|
||||
s_access_error = 1'b1;
|
||||
s_config_error_event = 1'b1;
|
||||
end else begin
|
||||
s_enable_en = 1'b1;
|
||||
s_enable_d = s_merge_value[0];
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_SCL_TIMING: begin
|
||||
if (s_enable_q || busy_i || recovery_active_i) begin
|
||||
s_access_error = 1'b1;
|
||||
s_config_error_event = 1'b1;
|
||||
end else begin
|
||||
s_scl_timing_en = 1'b1;
|
||||
s_scl_timing_d = merge_wstrb(s_scl_timing_q, ribp.wdata, ribp.wstrb);
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_START_TIMING: begin
|
||||
if (s_enable_q || busy_i || recovery_active_i) begin
|
||||
s_access_error = 1'b1;
|
||||
s_config_error_event = 1'b1;
|
||||
end else begin
|
||||
s_start_timing_en = 1'b1;
|
||||
s_start_timing_d = merge_wstrb(s_start_timing_q, ribp.wdata, ribp.wstrb);
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_DATA_TIMING: begin
|
||||
if (s_enable_q || busy_i || recovery_active_i) begin
|
||||
s_access_error = 1'b1;
|
||||
s_config_error_event = 1'b1;
|
||||
end else begin
|
||||
s_data_timing_en = 1'b1;
|
||||
s_data_timing_d = merge_wstrb(s_data_timing_q, ribp.wdata, ribp.wstrb);
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_STOP_TIMING: begin
|
||||
if (s_enable_q || busy_i || recovery_active_i) begin
|
||||
s_access_error = 1'b1;
|
||||
s_config_error_event = 1'b1;
|
||||
end else begin
|
||||
s_stop_timing_en = 1'b1;
|
||||
s_stop_timing_d = merge_wstrb(s_stop_timing_q, ribp.wdata, ribp.wstrb);
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_FILTER: begin
|
||||
s_merge_value = merge_wstrb({20'd0, s_filter_q}, ribp.wdata, ribp.wstrb);
|
||||
if (s_enable_q || busy_i || recovery_active_i ||
|
||||
(s_merge_value[31:12] != 20'd0) || (s_merge_value[7:4] != 4'd0)) begin
|
||||
s_access_error = 1'b1;
|
||||
s_config_error_event = 1'b1;
|
||||
end else begin
|
||||
s_filter_en = 1'b1;
|
||||
s_filter_d = s_merge_value[11:0];
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_STRETCH_TIMEOUT: begin
|
||||
s_merge_value = merge_wstrb({8'd0, s_stretch_timeout_q}, ribp.wdata, ribp.wstrb);
|
||||
if (s_enable_q || busy_i || recovery_active_i || (s_merge_value[31:24] != 8'd0)) begin
|
||||
s_access_error = 1'b1;
|
||||
s_config_error_event = 1'b1;
|
||||
end else begin
|
||||
s_stretch_timeout_en = 1'b1;
|
||||
s_stretch_timeout_d = s_merge_value[23:0];
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_BUS_IDLE_TIMEOUT: begin
|
||||
s_merge_value = merge_wstrb({8'd0, s_bus_idle_timeout_q}, ribp.wdata, ribp.wstrb);
|
||||
if (s_enable_q || busy_i || recovery_active_i || (s_merge_value[31:24] != 8'd0)) begin
|
||||
s_access_error = 1'b1;
|
||||
s_config_error_event = 1'b1;
|
||||
end else begin
|
||||
s_bus_idle_timeout_en = 1'b1;
|
||||
s_bus_idle_timeout_d = s_merge_value[23:0];
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_COMMAND_TIMEOUT: begin
|
||||
s_merge_value = merge_wstrb({8'd0, s_command_timeout_q}, ribp.wdata, ribp.wstrb);
|
||||
if (s_enable_q || busy_i || recovery_active_i || (s_merge_value[31:24] != 8'd0)) begin
|
||||
s_access_error = 1'b1;
|
||||
s_config_error_event = 1'b1;
|
||||
end else begin
|
||||
s_command_timeout_en = 1'b1;
|
||||
s_command_timeout_d = s_merge_value[23:0];
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_TARGET_ADDR: begin
|
||||
s_merge_value = merge_wstrb({21'd0, s_target_addr_q}, ribp.wdata, ribp.wstrb);
|
||||
if (busy_i || recovery_active_i || !s_cmd_empty ||
|
||||
(s_merge_value[31:11] != 21'd0) ||
|
||||
(!s_merge_value[10] && (s_merge_value[9:7] != 3'd0))) begin
|
||||
s_access_error = 1'b1;
|
||||
s_config_error_event = 1'b1;
|
||||
end else begin
|
||||
s_target_addr_en = 1'b1;
|
||||
s_target_addr_d = s_merge_value[10:0];
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_DATA_CMD: begin
|
||||
if ((ribp.wstrb != 4'hF) || (ribp.wdata[31:12] != 20'd0) ||
|
||||
(!ribp.wdata[`I2C_DATA_CMD_READ] &&
|
||||
ribp.wdata[`I2C_DATA_CMD_NACK_LAST]) ||
|
||||
(ribp.wdata[`I2C_DATA_CMD_READ] && ribp.wdata[`I2C_DATA_CMD_STOP] &&
|
||||
!ribp.wdata[`I2C_DATA_CMD_NACK_LAST])) begin
|
||||
s_access_error = 1'b1;
|
||||
s_sw_command_error_event = 1'b1;
|
||||
end else if (s_cmd_full && s_enable_q && s_config_valid) begin
|
||||
s_req_accept = 1'b0;
|
||||
end else if (s_cmd_full) begin
|
||||
s_access_error = 1'b1;
|
||||
s_sw_command_error_event = 1'b1;
|
||||
end else begin
|
||||
s_cmd_push = 1'b1;
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_COMMAND: begin
|
||||
if (!ribp.wstrb[0] || (ribp.wdata[31:4] != 28'd0) || (ribp.wdata[3:0] == 4'd0)) begin
|
||||
s_access_error = 1'b1;
|
||||
s_sw_command_error_event = 1'b1;
|
||||
end else if (ribp.wdata[`I2C_COMMAND_ABORT]) begin
|
||||
if ((ribp.wdata[3:0] != 4'b0001) || (!busy_i && !recovery_active_i)) begin
|
||||
s_access_error = 1'b1;
|
||||
s_sw_command_error_event = 1'b1;
|
||||
end else begin
|
||||
abort_o = 1'b1;
|
||||
end
|
||||
end else if (ribp.wdata[`I2C_COMMAND_RECOVER]) begin
|
||||
if ((ribp.wdata[3:0] != 4'b0010) || !s_enable_q || !s_config_valid ||
|
||||
busy_i || recovery_active_i || !s_cmd_empty) begin
|
||||
s_access_error = 1'b1;
|
||||
s_sw_command_error_event = 1'b1;
|
||||
end else begin
|
||||
recover_o = 1'b1;
|
||||
end
|
||||
end else if (busy_i || recovery_active_i || (ribp.wdata[1:0] != 2'd0)) begin
|
||||
s_access_error = 1'b1;
|
||||
s_sw_command_error_event = 1'b1;
|
||||
end else begin
|
||||
s_cmd_flush_cmd = ribp.wdata[`I2C_COMMAND_CMD_FLUSH];
|
||||
s_rx_flush_cmd = ribp.wdata[`I2C_COMMAND_RX_FLUSH];
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_CMD_WATERMARK: begin
|
||||
s_merge_value = merge_wstrb({24'd0, s_cmd_watermark_q}, ribp.wdata, ribp.wstrb);
|
||||
if ((s_merge_value[31:8] != 24'd0) || (s_merge_value[7:0] >= CMD_DEPTH_INFO)) begin
|
||||
s_access_error = 1'b1;
|
||||
s_sw_command_error_event = 1'b1;
|
||||
end else begin
|
||||
s_cmd_watermark_en = 1'b1;
|
||||
s_cmd_watermark_d = s_merge_value[7:0];
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_RX_WATERMARK: begin
|
||||
s_merge_value = merge_wstrb({24'd0, s_rx_watermark_q}, ribp.wdata, ribp.wstrb);
|
||||
if ((s_merge_value[31:8] != 24'd0) || (s_merge_value[7:0] == 8'd0) ||
|
||||
(s_merge_value[7:0] > RX_DEPTH_INFO)) begin
|
||||
s_access_error = 1'b1;
|
||||
s_sw_command_error_event = 1'b1;
|
||||
end else begin
|
||||
s_rx_watermark_en = 1'b1;
|
||||
s_rx_watermark_d = s_merge_value[7:0];
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_ERROR_STATUS: begin
|
||||
if (!ribp.wstrb[0] || (ribp.wdata[31:11] != 21'd0)) begin
|
||||
s_access_error = 1'b1;
|
||||
end else begin
|
||||
s_error_clear = ribp.wdata[10:0];
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_INTR_STATE: begin
|
||||
if (!ribp.wstrb[0] || (ribp.wdata[31:8] != 24'd0)) begin
|
||||
s_access_error = 1'b1;
|
||||
end else begin
|
||||
s_intr_clear = ribp.wdata[7:0];
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_INTR_ENABLE: begin
|
||||
s_merge_value = merge_wstrb({24'd0, s_intr_enable_q}, ribp.wdata, ribp.wstrb);
|
||||
if (s_merge_value[31:8] != 24'd0) begin
|
||||
s_access_error = 1'b1;
|
||||
end else begin
|
||||
s_intr_enable_en = 1'b1;
|
||||
s_intr_enable_d = s_merge_value[7:0];
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_INTR_TEST: begin
|
||||
if (!ribp.wstrb[0] || (ribp.wdata[31:8] != 24'd0)) begin
|
||||
s_access_error = 1'b1;
|
||||
end else begin
|
||||
s_intr_test = ribp.wdata[7:0];
|
||||
end
|
||||
end
|
||||
default: s_access_error = 1'b1;
|
||||
endcase
|
||||
end else begin
|
||||
unique case (ribp.addr[7:0])
|
||||
`RIBP_I2C_CTRL: s_ribp_rdata_d = {31'd0, s_enable_q};
|
||||
`RIBP_I2C_SCL_TIMING: s_ribp_rdata_d = s_scl_timing_q;
|
||||
`RIBP_I2C_START_TIMING: s_ribp_rdata_d = s_start_timing_q;
|
||||
`RIBP_I2C_DATA_TIMING: s_ribp_rdata_d = s_data_timing_q;
|
||||
`RIBP_I2C_STOP_TIMING: s_ribp_rdata_d = s_stop_timing_q;
|
||||
`RIBP_I2C_FILTER: s_ribp_rdata_d = {20'd0, s_filter_q};
|
||||
`RIBP_I2C_STRETCH_TIMEOUT: s_ribp_rdata_d = {8'd0, s_stretch_timeout_q};
|
||||
`RIBP_I2C_BUS_IDLE_TIMEOUT: s_ribp_rdata_d = {8'd0, s_bus_idle_timeout_q};
|
||||
`RIBP_I2C_COMMAND_TIMEOUT: s_ribp_rdata_d = {8'd0, s_command_timeout_q};
|
||||
`RIBP_I2C_TARGET_ADDR: s_ribp_rdata_d = {21'd0, s_target_addr_q};
|
||||
`RIBP_I2C_RXDATA: begin
|
||||
if (s_rx_empty) begin
|
||||
s_access_error = 1'b1;
|
||||
s_sw_command_error_event = 1'b1;
|
||||
end else begin
|
||||
s_ribp_rdata_d = {24'd0, s_rx_pop_data};
|
||||
s_rx_pop = 1'b1;
|
||||
end
|
||||
end
|
||||
`RIBP_I2C_STATUS: s_ribp_rdata_d = s_status;
|
||||
`RIBP_I2C_FIFO_LEVEL: s_ribp_rdata_d = s_fifo_level;
|
||||
`RIBP_I2C_CMD_WATERMARK: s_ribp_rdata_d = {24'd0, s_cmd_watermark_q};
|
||||
`RIBP_I2C_RX_WATERMARK: s_ribp_rdata_d = {24'd0, s_rx_watermark_q};
|
||||
`RIBP_I2C_ERROR_STATUS: s_ribp_rdata_d = {21'd0, s_error_status_q};
|
||||
`RIBP_I2C_INTR_STATE: s_ribp_rdata_d = {24'd0, s_intr_state_q};
|
||||
`RIBP_I2C_INTR_ENABLE: s_ribp_rdata_d = {24'd0, s_intr_enable_q};
|
||||
`RIBP_I2C_INTR_STATUS: s_ribp_rdata_d = {24'd0, (s_intr_state_q & s_intr_enable_q)};
|
||||
`RIBP_I2C_LINE_STATE: s_ribp_rdata_d = s_line_state;
|
||||
`RIBP_I2C_IP_VERSION: s_ribp_rdata_d = IP_VERSION;
|
||||
`RIBP_I2C_CAPABILITY: s_ribp_rdata_d = CAPABILITY;
|
||||
default: begin
|
||||
s_access_error = 1'b1;
|
||||
s_ribp_rdata_d = '0;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign s_ribp_ready_d = s_req_accept;
|
||||
assign s_ribp_resp_err_d = s_access_error;
|
||||
|
||||
dffr #(1) u_ribp_ready_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_ribp_ready_d),
|
||||
.dat_o (s_ribp_ready_q)
|
||||
);
|
||||
dffer #(1) u_ribp_resp_err_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_req_accept),
|
||||
.dat_i (s_ribp_resp_err_d),
|
||||
.dat_o (s_ribp_resp_err_q)
|
||||
);
|
||||
dffer #(32) u_ribp_rdata_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_req_accept),
|
||||
.dat_i (s_ribp_rdata_d),
|
||||
.dat_o (s_ribp_rdata_q)
|
||||
);
|
||||
|
||||
dffer #(1) u_enable_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_enable_en),
|
||||
.dat_i (s_enable_d),
|
||||
.dat_o (s_enable_q)
|
||||
);
|
||||
dffer #(32) u_scl_timing_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_scl_timing_en),
|
||||
.dat_i (s_scl_timing_d),
|
||||
.dat_o (s_scl_timing_q)
|
||||
);
|
||||
dffer #(32) u_start_timing_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_start_timing_en),
|
||||
.dat_i (s_start_timing_d),
|
||||
.dat_o (s_start_timing_q)
|
||||
);
|
||||
dffer #(32) u_data_timing_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_data_timing_en),
|
||||
.dat_i (s_data_timing_d),
|
||||
.dat_o (s_data_timing_q)
|
||||
);
|
||||
dffer #(32) u_stop_timing_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_stop_timing_en),
|
||||
.dat_i (s_stop_timing_d),
|
||||
.dat_o (s_stop_timing_q)
|
||||
);
|
||||
dfferc #(
|
||||
.DATA_WIDTH(12),
|
||||
.RESET_VAL (12'h202)
|
||||
) u_filter_dfferc (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_filter_en),
|
||||
.dat_i (s_filter_d),
|
||||
.dat_o (s_filter_q)
|
||||
);
|
||||
dffer #(24) u_stretch_timeout_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_stretch_timeout_en),
|
||||
.dat_i (s_stretch_timeout_d),
|
||||
.dat_o (s_stretch_timeout_q)
|
||||
);
|
||||
dffer #(24) u_bus_idle_timeout_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_bus_idle_timeout_en),
|
||||
.dat_i (s_bus_idle_timeout_d),
|
||||
.dat_o (s_bus_idle_timeout_q)
|
||||
);
|
||||
dffer #(24) u_command_timeout_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_command_timeout_en),
|
||||
.dat_i (s_command_timeout_d),
|
||||
.dat_o (s_command_timeout_q)
|
||||
);
|
||||
dffer #(11) u_target_addr_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_target_addr_en),
|
||||
.dat_i (s_target_addr_d),
|
||||
.dat_o (s_target_addr_q)
|
||||
);
|
||||
dfferc #(
|
||||
.DATA_WIDTH(8),
|
||||
.RESET_VAL (8'(CMD_WATERMARK_RESET))
|
||||
) u_cmd_watermark_dfferc (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_cmd_watermark_en),
|
||||
.dat_i (s_cmd_watermark_d),
|
||||
.dat_o (s_cmd_watermark_q)
|
||||
);
|
||||
dfferc #(
|
||||
.DATA_WIDTH(8),
|
||||
.RESET_VAL (8'(RX_WATERMARK_RESET))
|
||||
) u_rx_watermark_dfferc (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_rx_watermark_en),
|
||||
.dat_i (s_rx_watermark_d),
|
||||
.dat_o (s_rx_watermark_q)
|
||||
);
|
||||
dffer #(8) u_intr_enable_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_intr_enable_en),
|
||||
.dat_i (s_intr_enable_d),
|
||||
.dat_o (s_intr_enable_q)
|
||||
);
|
||||
|
||||
fifo #(
|
||||
.DATA_WIDTH (12),
|
||||
.BUFFER_DEPTH (CMD_FIFO_DEPTH),
|
||||
.LOG_BUFFER_DEPTH(CMD_FIFO_LOG_DEPTH)
|
||||
) u_cmd_fifo (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.flush_i(s_cmd_flush_cmd || core_cmd_flush_i),
|
||||
.push_i (s_cmd_push),
|
||||
.full_o (s_cmd_full),
|
||||
.dat_i (ribp.wdata[11:0]),
|
||||
.pop_i (cmd_pop_i),
|
||||
.empty_o(s_cmd_empty),
|
||||
.dat_o (s_cmd_pop_data),
|
||||
.cnt_o (s_cmd_count)
|
||||
);
|
||||
|
||||
fifo #(
|
||||
.DATA_WIDTH (8),
|
||||
.BUFFER_DEPTH (RX_FIFO_DEPTH),
|
||||
.LOG_BUFFER_DEPTH(RX_FIFO_LOG_DEPTH)
|
||||
) u_rx_fifo (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.flush_i(s_rx_flush_cmd),
|
||||
.push_i (rx_push_i && !s_rx_full),
|
||||
.full_o (s_rx_full),
|
||||
.dat_i (rx_data_i),
|
||||
.pop_i (s_rx_pop),
|
||||
.empty_o(s_rx_empty),
|
||||
.dat_o (s_rx_pop_data),
|
||||
.cnt_o (s_rx_count)
|
||||
);
|
||||
|
||||
assign s_timeout_event = stretch_timeout_event_i || bus_timeout_event_i ||
|
||||
command_timeout_event_i;
|
||||
assign s_error_event = addr_nack_event_i || data_nack_event_i || arb_lost_event_i ||
|
||||
s_timeout_event || command_error_event_i ||
|
||||
s_sw_command_error_event || rx_overflow_event_i ||
|
||||
s_config_error_event || aborted_event_i || recovery_failed_event_i;
|
||||
|
||||
always_comb begin
|
||||
s_error_status_d = s_error_status_q & ~s_error_clear;
|
||||
if (addr_nack_event_i) s_error_status_d[`I2C_ERROR_ADDR_NACK] = 1'b1;
|
||||
if (data_nack_event_i) s_error_status_d[`I2C_ERROR_DATA_NACK] = 1'b1;
|
||||
if (arb_lost_event_i) s_error_status_d[`I2C_ERROR_ARB_LOST] = 1'b1;
|
||||
if (stretch_timeout_event_i) s_error_status_d[`I2C_ERROR_STRETCH_TIMEOUT] = 1'b1;
|
||||
if (bus_timeout_event_i) s_error_status_d[`I2C_ERROR_BUS_TIMEOUT] = 1'b1;
|
||||
if (command_timeout_event_i) s_error_status_d[`I2C_ERROR_COMMAND_TIMEOUT] = 1'b1;
|
||||
if (command_error_event_i || s_sw_command_error_event)
|
||||
s_error_status_d[`I2C_ERROR_COMMAND] = 1'b1;
|
||||
if (rx_overflow_event_i) s_error_status_d[`I2C_ERROR_RX_OVERFLOW] = 1'b1;
|
||||
if (s_config_error_event) s_error_status_d[`I2C_ERROR_CONFIG] = 1'b1;
|
||||
if (aborted_event_i) s_error_status_d[`I2C_ERROR_ABORTED] = 1'b1;
|
||||
if (recovery_failed_event_i) s_error_status_d[`I2C_ERROR_RECOVERY_FAILED] = 1'b1;
|
||||
end
|
||||
dffr #(11) u_error_status_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_error_status_d),
|
||||
.dat_o (s_error_status_q)
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
s_intr_state_d = (s_intr_state_q & ~s_intr_clear) | s_intr_test;
|
||||
if (done_event_i) s_intr_state_d[`I2C_INTR_DONE] = 1'b1;
|
||||
if (s_cmd_watermark_active) s_intr_state_d[`I2C_INTR_CMD_WATERMARK] = 1'b1;
|
||||
if (s_rx_watermark_active) s_intr_state_d[`I2C_INTR_RX_WATERMARK] = 1'b1;
|
||||
if (addr_nack_event_i || data_nack_event_i) s_intr_state_d[`I2C_INTR_NACK] = 1'b1;
|
||||
if (arb_lost_event_i) s_intr_state_d[`I2C_INTR_ARB_LOST] = 1'b1;
|
||||
if (s_timeout_event) s_intr_state_d[`I2C_INTR_TIMEOUT] = 1'b1;
|
||||
if (s_error_event) s_intr_state_d[`I2C_INTR_ERROR] = 1'b1;
|
||||
if (recovery_done_event_i) s_intr_state_d[`I2C_INTR_RECOVERY_DONE] = 1'b1;
|
||||
end
|
||||
dffr #(8) u_intr_state_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_intr_state_d),
|
||||
.dat_o (s_intr_state_q)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,177 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module ribp_i2c #(
|
||||
parameter int CMD_FIFO_DEPTH = 16,
|
||||
parameter int RX_FIFO_DEPTH = 16
|
||||
) (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
output logic dma_tx_stall_o,
|
||||
output logic dma_rx_stall_o,
|
||||
ribp_if.slave ribp,
|
||||
i2c_if.dut i2c
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
logic s_enable;
|
||||
logic [15:0] s_scl_low_cycles;
|
||||
logic [15:0] s_scl_high_cycles;
|
||||
logic [15:0] s_start_hold_cycles;
|
||||
logic [15:0] s_start_setup_cycles;
|
||||
logic [15:0] s_data_hold_cycles;
|
||||
logic [15:0] s_data_setup_cycles;
|
||||
logic [15:0] s_stop_setup_cycles;
|
||||
logic [15:0] s_bus_free_cycles;
|
||||
logic [ 3:0] s_scl_filter_cycles;
|
||||
logic [ 3:0] s_sda_filter_cycles;
|
||||
logic [23:0] s_stretch_timeout;
|
||||
logic [23:0] s_bus_idle_timeout;
|
||||
logic [23:0] s_command_timeout;
|
||||
logic [ 9:0] s_target_addr;
|
||||
logic s_ten_bit;
|
||||
logic s_abort;
|
||||
logic s_recover;
|
||||
logic s_cmd_valid;
|
||||
logic [11:0] s_cmd_data;
|
||||
logic s_cmd_pop;
|
||||
logic s_rx_push;
|
||||
logic [ 7:0] s_rx_data;
|
||||
logic s_rx_full;
|
||||
logic s_busy;
|
||||
logic s_recovery_active;
|
||||
logic s_scl_filtered;
|
||||
logic s_sda_filtered;
|
||||
logic s_scl_pull_low;
|
||||
logic s_sda_pull_low;
|
||||
logic s_done_event;
|
||||
logic s_addr_nack_event;
|
||||
logic s_data_nack_event;
|
||||
logic s_arb_lost_event;
|
||||
logic s_stretch_timeout_event;
|
||||
logic s_bus_timeout_event;
|
||||
logic s_command_timeout_event;
|
||||
logic s_command_error_event;
|
||||
logic s_rx_overflow_event;
|
||||
logic s_aborted_event;
|
||||
logic s_recovery_done_event;
|
||||
logic s_recovery_failed_event;
|
||||
logic s_core_cmd_flush;
|
||||
|
||||
assign i2c.scl_o = 1'b0;
|
||||
assign i2c.sda_o = 1'b0;
|
||||
assign i2c.scl_oe_o = s_scl_pull_low;
|
||||
assign i2c.sda_oe_o = s_sda_pull_low;
|
||||
|
||||
i2c_filter u_i2c_filter (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.scl_filter_cycles_i(s_scl_filter_cycles),
|
||||
.sda_filter_cycles_i(s_sda_filter_cycles),
|
||||
.scl_async_i (i2c.scl_i),
|
||||
.sda_async_i (i2c.sda_i),
|
||||
.scl_o (s_scl_filtered),
|
||||
.sda_o (s_sda_filtered)
|
||||
);
|
||||
|
||||
i2c_reg #(
|
||||
.CMD_FIFO_DEPTH(CMD_FIFO_DEPTH),
|
||||
.RX_FIFO_DEPTH (RX_FIFO_DEPTH)
|
||||
) u_i2c_reg (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.ribp (ribp),
|
||||
.enable_o (s_enable),
|
||||
.scl_low_cycles_o (s_scl_low_cycles),
|
||||
.scl_high_cycles_o (s_scl_high_cycles),
|
||||
.start_hold_cycles_o (s_start_hold_cycles),
|
||||
.start_setup_cycles_o (s_start_setup_cycles),
|
||||
.data_hold_cycles_o (s_data_hold_cycles),
|
||||
.data_setup_cycles_o (s_data_setup_cycles),
|
||||
.stop_setup_cycles_o (s_stop_setup_cycles),
|
||||
.bus_free_cycles_o (s_bus_free_cycles),
|
||||
.scl_filter_cycles_o (s_scl_filter_cycles),
|
||||
.sda_filter_cycles_o (s_sda_filter_cycles),
|
||||
.stretch_timeout_o (s_stretch_timeout),
|
||||
.bus_idle_timeout_o (s_bus_idle_timeout),
|
||||
.command_timeout_o (s_command_timeout),
|
||||
.target_addr_o (s_target_addr),
|
||||
.ten_bit_o (s_ten_bit),
|
||||
.abort_o (s_abort),
|
||||
.recover_o (s_recover),
|
||||
.cmd_valid_o (s_cmd_valid),
|
||||
.cmd_data_o (s_cmd_data),
|
||||
.cmd_pop_i (s_cmd_pop),
|
||||
.core_cmd_flush_i (s_core_cmd_flush),
|
||||
.rx_push_i (s_rx_push),
|
||||
.rx_data_i (s_rx_data),
|
||||
.rx_full_o (s_rx_full),
|
||||
.busy_i (s_busy),
|
||||
.recovery_active_i (s_recovery_active),
|
||||
.scl_i (s_scl_filtered),
|
||||
.sda_i (s_sda_filtered),
|
||||
.done_event_i (s_done_event),
|
||||
.addr_nack_event_i (s_addr_nack_event),
|
||||
.data_nack_event_i (s_data_nack_event),
|
||||
.arb_lost_event_i (s_arb_lost_event),
|
||||
.stretch_timeout_event_i(s_stretch_timeout_event),
|
||||
.bus_timeout_event_i (s_bus_timeout_event),
|
||||
.command_timeout_event_i(s_command_timeout_event),
|
||||
.command_error_event_i (s_command_error_event),
|
||||
.rx_overflow_event_i (s_rx_overflow_event),
|
||||
.aborted_event_i (s_aborted_event),
|
||||
.recovery_done_event_i (s_recovery_done_event),
|
||||
.recovery_failed_event_i(s_recovery_failed_event),
|
||||
.dma_tx_stall_o (dma_tx_stall_o),
|
||||
.dma_rx_stall_o (dma_rx_stall_o),
|
||||
.irq_o (i2c.irq_o)
|
||||
);
|
||||
|
||||
i2c_core u_i2c_core (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.enable_i (s_enable),
|
||||
.scl_low_cycles_i (s_scl_low_cycles),
|
||||
.scl_high_cycles_i (s_scl_high_cycles),
|
||||
.start_hold_cycles_i (s_start_hold_cycles),
|
||||
.start_setup_cycles_i (s_start_setup_cycles),
|
||||
.data_hold_cycles_i (s_data_hold_cycles),
|
||||
.data_setup_cycles_i (s_data_setup_cycles),
|
||||
.stop_setup_cycles_i (s_stop_setup_cycles),
|
||||
.bus_free_cycles_i (s_bus_free_cycles),
|
||||
.stretch_timeout_i (s_stretch_timeout),
|
||||
.bus_idle_timeout_i (s_bus_idle_timeout),
|
||||
.command_timeout_i (s_command_timeout),
|
||||
.target_addr_i (s_target_addr),
|
||||
.ten_bit_i (s_ten_bit),
|
||||
.abort_i (s_abort),
|
||||
.recover_i (s_recover),
|
||||
.cmd_valid_i (s_cmd_valid),
|
||||
.cmd_data_i (s_cmd_data),
|
||||
.cmd_pop_o (s_cmd_pop),
|
||||
.cmd_flush_o (s_core_cmd_flush),
|
||||
.rx_full_i (s_rx_full),
|
||||
.rx_push_o (s_rx_push),
|
||||
.rx_data_o (s_rx_data),
|
||||
.scl_i (s_scl_filtered),
|
||||
.sda_i (s_sda_filtered),
|
||||
.scl_pull_low_o (s_scl_pull_low),
|
||||
.sda_pull_low_o (s_sda_pull_low),
|
||||
.busy_o (s_busy),
|
||||
.recovery_active_o (s_recovery_active),
|
||||
.done_event_o (s_done_event),
|
||||
.addr_nack_event_o (s_addr_nack_event),
|
||||
.data_nack_event_o (s_data_nack_event),
|
||||
.arb_lost_event_o (s_arb_lost_event),
|
||||
.stretch_timeout_event_o(s_stretch_timeout_event),
|
||||
.bus_timeout_event_o (s_bus_timeout_event),
|
||||
.command_timeout_event_o(s_command_timeout_event),
|
||||
.command_error_event_o (s_command_error_event),
|
||||
.rx_overflow_event_o (s_rx_overflow_event),
|
||||
.aborted_event_o (s_aborted_event),
|
||||
.recovery_done_event_o (s_recovery_done_event),
|
||||
.recovery_failed_event_o(s_recovery_failed_event)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
`ifndef RETROSOC_RIBP_I2C_DEFINE_SVH
|
||||
`define RETROSOC_RIBP_I2C_DEFINE_SVH
|
||||
|
||||
// verilog_format: off
|
||||
`define RIBP_I2C_CTRL 8'h00
|
||||
`define RIBP_I2C_SCL_TIMING 8'h04
|
||||
`define RIBP_I2C_START_TIMING 8'h08
|
||||
`define RIBP_I2C_DATA_TIMING 8'h0C
|
||||
`define RIBP_I2C_STOP_TIMING 8'h10
|
||||
`define RIBP_I2C_FILTER 8'h14
|
||||
`define RIBP_I2C_STRETCH_TIMEOUT 8'h18
|
||||
`define RIBP_I2C_BUS_IDLE_TIMEOUT 8'h1C
|
||||
`define RIBP_I2C_COMMAND_TIMEOUT 8'h20
|
||||
`define RIBP_I2C_TARGET_ADDR 8'h24
|
||||
`define RIBP_I2C_DATA_CMD 8'h28
|
||||
`define RIBP_I2C_RXDATA 8'h2C
|
||||
`define RIBP_I2C_STATUS 8'h30
|
||||
`define RIBP_I2C_FIFO_LEVEL 8'h34
|
||||
`define RIBP_I2C_COMMAND 8'h38
|
||||
`define RIBP_I2C_CMD_WATERMARK 8'h3C
|
||||
`define RIBP_I2C_RX_WATERMARK 8'h40
|
||||
`define RIBP_I2C_ERROR_STATUS 8'h44
|
||||
`define RIBP_I2C_INTR_STATE 8'h48
|
||||
`define RIBP_I2C_INTR_ENABLE 8'h4C
|
||||
`define RIBP_I2C_INTR_STATUS 8'h50
|
||||
`define RIBP_I2C_INTR_TEST 8'h54
|
||||
`define RIBP_I2C_LINE_STATE 8'h58
|
||||
`define RIBP_I2C_IP_VERSION 8'hF8
|
||||
`define RIBP_I2C_CAPABILITY 8'hFC
|
||||
|
||||
`define I2C_CTRL_ENABLE 0
|
||||
|
||||
`define I2C_DATA_CMD_READ 8
|
||||
`define I2C_DATA_CMD_RESTART 9
|
||||
`define I2C_DATA_CMD_STOP 10
|
||||
`define I2C_DATA_CMD_NACK_LAST 11
|
||||
|
||||
`define I2C_COMMAND_ABORT 0
|
||||
`define I2C_COMMAND_RECOVER 1
|
||||
`define I2C_COMMAND_CMD_FLUSH 2
|
||||
`define I2C_COMMAND_RX_FLUSH 3
|
||||
|
||||
`define I2C_STATUS_ENABLE 0
|
||||
`define I2C_STATUS_BUSY 1
|
||||
`define I2C_STATUS_BUS_BUSY 2
|
||||
`define I2C_STATUS_CMD_EMPTY 3
|
||||
`define I2C_STATUS_CMD_FULL 4
|
||||
`define I2C_STATUS_RX_EMPTY 5
|
||||
`define I2C_STATUS_RX_FULL 6
|
||||
`define I2C_STATUS_CONFIG_VALID 7
|
||||
`define I2C_STATUS_RECOVERY_ACTIVE 8
|
||||
`define I2C_STATUS_SCL 9
|
||||
`define I2C_STATUS_SDA 10
|
||||
`define I2C_STATUS_TX_DMA_REQ 11
|
||||
`define I2C_STATUS_RX_DMA_REQ 12
|
||||
|
||||
`define I2C_ERROR_ADDR_NACK 0
|
||||
`define I2C_ERROR_DATA_NACK 1
|
||||
`define I2C_ERROR_ARB_LOST 2
|
||||
`define I2C_ERROR_STRETCH_TIMEOUT 3
|
||||
`define I2C_ERROR_BUS_TIMEOUT 4
|
||||
`define I2C_ERROR_COMMAND_TIMEOUT 5
|
||||
`define I2C_ERROR_COMMAND 6
|
||||
`define I2C_ERROR_RX_OVERFLOW 7
|
||||
`define I2C_ERROR_CONFIG 8
|
||||
`define I2C_ERROR_ABORTED 9
|
||||
`define I2C_ERROR_RECOVERY_FAILED 10
|
||||
|
||||
`define I2C_INTR_DONE 0
|
||||
`define I2C_INTR_CMD_WATERMARK 1
|
||||
`define I2C_INTR_RX_WATERMARK 2
|
||||
`define I2C_INTR_NACK 3
|
||||
`define I2C_INTR_ARB_LOST 4
|
||||
`define I2C_INTR_TIMEOUT 5
|
||||
`define I2C_INTR_ERROR 6
|
||||
`define I2C_INTR_RECOVERY_DONE 7
|
||||
|
||||
`define I2C_LINE_SCL 0
|
||||
`define I2C_LINE_SDA 1
|
||||
`define I2C_LINE_BUS_FREE 2
|
||||
// verilog_format: on
|
||||
|
||||
`endif
|
||||
@@ -11,8 +11,10 @@
|
||||
/ip/ribp/storage/spisd_data.sv
|
||||
/ip/ribp/storage/spisd.sv
|
||||
/ip/ribp/storage/sdio.sv
|
||||
/ip/ribp/serial/i2c_filter.sv
|
||||
/ip/ribp/serial/i2c_core.sv
|
||||
/ip/ribp/serial/i2c.sv
|
||||
/ip/ribp/serial/i2c_reg.sv
|
||||
/ip/ribp/serial/ribp_i2c.sv
|
||||
/ip/ribp/serial/i2s_reg.sv
|
||||
/ip/ribp/serial/i2s_clkgen.sv
|
||||
/ip/ribp/serial/i2s_recv.sv
|
||||
|
||||
@@ -121,6 +121,19 @@ def source_files(target: str) -> list[Path]:
|
||||
SERIAL / "ribp_uart.sv",
|
||||
SCRIPT_DIR / "uart_formal.sv",
|
||||
]
|
||||
if target == "i2c":
|
||||
return [
|
||||
COMMON_RTL / "interface/ribp_if.sv",
|
||||
COMMON_RTL / "utils/register.sv",
|
||||
COMMON_RTL / "utils/fifo.sv",
|
||||
COMMON_RTL / "cdc/cdc_sync.sv",
|
||||
ROOT / "rtl/managed/clusterip/i2c/rtl/i2c_if.sv",
|
||||
SERIAL / "i2c_filter.sv",
|
||||
SERIAL / "i2c_core.sv",
|
||||
SERIAL / "i2c_reg.sv",
|
||||
SERIAL / "ribp_i2c.sv",
|
||||
SCRIPT_DIR / "i2c_formal.sv",
|
||||
]
|
||||
if target == "timer":
|
||||
return [
|
||||
COMMON_RTL / "interface/ribp_if.sv",
|
||||
@@ -184,6 +197,7 @@ def parse_args() -> argparse.Namespace:
|
||||
"gpio",
|
||||
"ws2812",
|
||||
"uart",
|
||||
"i2c",
|
||||
"timer",
|
||||
"clint",
|
||||
),
|
||||
|
||||
@@ -14,12 +14,21 @@ sys.path.insert(0, str(ROOT))
|
||||
from scripts.setup_helpers import atomic_write # noqa: E402
|
||||
|
||||
|
||||
def render(top: str, design: Path, properties: Path, solver: str, mode: str, depth: int) -> str:
|
||||
def render(
|
||||
top: str,
|
||||
design: Path,
|
||||
properties: Path,
|
||||
solver: str,
|
||||
mode: str,
|
||||
depth: int,
|
||||
vcd: bool = True,
|
||||
) -> str:
|
||||
options = ["[options]", f"mode {mode}", f"depth {depth}"]
|
||||
if not vcd:
|
||||
options.append("vcd off")
|
||||
return "\n".join(
|
||||
(
|
||||
"[options]",
|
||||
f"mode {mode}",
|
||||
f"depth {depth}",
|
||||
tuple(options)
|
||||
+ (
|
||||
"",
|
||||
"[engines]",
|
||||
f"smtbmc --presat --nounroll {solver}",
|
||||
@@ -55,6 +64,7 @@ def parse_args() -> argparse.Namespace:
|
||||
parser.add_argument("--solver", required=True)
|
||||
parser.add_argument("--mode", choices=("prove", "cover"), required=True)
|
||||
parser.add_argument("--depth", type=positive_int, required=True)
|
||||
parser.add_argument("--no-vcd", action="store_false", dest="vcd")
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
return parser.parse_args()
|
||||
|
||||
@@ -63,7 +73,7 @@ def main() -> int:
|
||||
args = parse_args()
|
||||
atomic_write(
|
||||
args.output.resolve(),
|
||||
render(args.top, args.input, args.properties, args.solver, args.mode, args.depth),
|
||||
render(args.top, args.input, args.properties, args.solver, args.mode, args.depth, args.vcd),
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module i2c_formal_design (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
output logic rst_n_i,
|
||||
output logic f_past_valid,
|
||||
output logic rib_valid,
|
||||
output logic [31:0] rib_addr,
|
||||
output logic [31:0] rib_wdata,
|
||||
output logic [ 3:0] rib_wstrb,
|
||||
output logic rib_ready,
|
||||
output logic rib_resp_err,
|
||||
output logic [ 4:0] command_count,
|
||||
output logic [ 4:0] rx_count,
|
||||
output logic [10:0] error_status,
|
||||
output logic [ 7:0] intr_state,
|
||||
output logic [ 7:0] intr_enable,
|
||||
output logic command_valid,
|
||||
output logic command_pop,
|
||||
output logic rx_full,
|
||||
output logic rx_push,
|
||||
output logic busy,
|
||||
output logic recovery_active,
|
||||
output logic scl_o,
|
||||
output logic sda_o,
|
||||
output logic scl_oe,
|
||||
output logic sda_oe,
|
||||
output logic tx_dma_stall,
|
||||
output logic rx_dma_stall,
|
||||
output logic irq
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
ribp_if ribp ();
|
||||
i2c_if i2c ();
|
||||
|
||||
(* anyseq *)logic f_rib_valid;
|
||||
(* anyseq *)logic [31:0] f_rib_addr;
|
||||
(* anyseq *)logic [31:0] f_rib_wdata;
|
||||
(* anyseq *)logic [ 3:0] f_rib_wstrb;
|
||||
(* anyseq *)logic f_scl;
|
||||
(* anyseq *)logic f_sda;
|
||||
|
||||
assign ribp.valid = f_rib_valid;
|
||||
assign ribp.addr = f_rib_addr;
|
||||
assign ribp.wdata = f_rib_wdata;
|
||||
assign ribp.wstrb = f_rib_wstrb;
|
||||
assign i2c.scl_i = f_scl;
|
||||
assign i2c.sda_i = f_sda;
|
||||
|
||||
assign rib_valid = ribp.valid;
|
||||
assign rib_addr = ribp.addr;
|
||||
assign rib_wdata = ribp.wdata;
|
||||
assign rib_wstrb = ribp.wstrb;
|
||||
assign rib_ready = ribp.ready;
|
||||
assign rib_resp_err = ribp.resp_err;
|
||||
assign command_count = u_dut.u_i2c_reg.s_cmd_count;
|
||||
assign rx_count = u_dut.u_i2c_reg.s_rx_count;
|
||||
assign error_status = u_dut.u_i2c_reg.s_error_status_q;
|
||||
assign intr_state = u_dut.u_i2c_reg.s_intr_state_q;
|
||||
assign intr_enable = u_dut.u_i2c_reg.s_intr_enable_q;
|
||||
assign command_valid = u_dut.s_cmd_valid;
|
||||
assign command_pop = u_dut.s_cmd_pop;
|
||||
assign rx_full = u_dut.s_rx_full;
|
||||
assign rx_push = u_dut.s_rx_push;
|
||||
assign busy = u_dut.s_busy;
|
||||
assign recovery_active = u_dut.s_recovery_active;
|
||||
assign scl_o = i2c.scl_o;
|
||||
assign sda_o = i2c.sda_o;
|
||||
assign scl_oe = i2c.scl_oe_o;
|
||||
assign sda_oe = i2c.sda_oe_o;
|
||||
assign irq = i2c.irq_o;
|
||||
|
||||
ribp_i2c u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.dma_tx_stall_o(tx_dma_stall),
|
||||
.dma_rx_stall_o(rx_dma_stall),
|
||||
.ribp (ribp),
|
||||
.i2c (i2c)
|
||||
);
|
||||
|
||||
initial begin
|
||||
rst_n_i = 1'b0;
|
||||
f_past_valid = 1'b0;
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i) begin
|
||||
rst_n_i <= 1'b1;
|
||||
f_past_valid <= 1'b1;
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module i2c_formal;
|
||||
(* anyseq, gclk *) logic clk_i;
|
||||
wire rst_n_i;
|
||||
wire f_past_valid;
|
||||
wire rib_valid;
|
||||
wire [31:0] rib_addr;
|
||||
wire [31:0] rib_wdata;
|
||||
wire [ 3:0] rib_wstrb;
|
||||
wire rib_ready;
|
||||
wire rib_resp_err;
|
||||
wire [ 4:0] command_count;
|
||||
wire [ 4:0] rx_count;
|
||||
wire [10:0] error_status;
|
||||
wire [ 7:0] intr_state;
|
||||
wire [ 7:0] intr_enable;
|
||||
wire command_valid;
|
||||
wire command_pop;
|
||||
wire rx_full;
|
||||
wire rx_push;
|
||||
wire busy;
|
||||
wire recovery_active;
|
||||
wire scl_o;
|
||||
wire sda_o;
|
||||
wire scl_oe;
|
||||
wire sda_oe;
|
||||
wire tx_dma_stall;
|
||||
wire rx_dma_stall;
|
||||
wire irq;
|
||||
|
||||
i2c_formal_design u_design (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.f_past_valid (f_past_valid),
|
||||
.rib_valid (rib_valid),
|
||||
.rib_addr (rib_addr),
|
||||
.rib_wdata (rib_wdata),
|
||||
.rib_wstrb (rib_wstrb),
|
||||
.rib_ready (rib_ready),
|
||||
.rib_resp_err (rib_resp_err),
|
||||
.command_count (command_count),
|
||||
.rx_count (rx_count),
|
||||
.error_status (error_status),
|
||||
.intr_state (intr_state),
|
||||
.intr_enable (intr_enable),
|
||||
.command_valid (command_valid),
|
||||
.command_pop (command_pop),
|
||||
.rx_full (rx_full),
|
||||
.rx_push (rx_push),
|
||||
.busy (busy),
|
||||
.recovery_active(recovery_active),
|
||||
.scl_o (scl_o),
|
||||
.sda_o (sda_o),
|
||||
.scl_oe (scl_oe),
|
||||
.sda_oe (sda_oe),
|
||||
.tx_dma_stall (tx_dma_stall),
|
||||
.rx_dma_stall (rx_dma_stall),
|
||||
.irq (irq)
|
||||
);
|
||||
|
||||
always @(posedge clk_i) begin
|
||||
if (f_past_valid && $past(rst_n_i && rib_valid && !rib_ready)) begin
|
||||
assume (rib_valid);
|
||||
assume (rib_addr == $past(rib_addr));
|
||||
assume (rib_wdata == $past(rib_wdata));
|
||||
assume (rib_wstrb == $past(rib_wstrb));
|
||||
end
|
||||
|
||||
if (rst_n_i) begin
|
||||
assert (command_count <= 5'd16);
|
||||
assert (rx_count <= 5'd16);
|
||||
assert (!scl_o);
|
||||
assert (!sda_o);
|
||||
assert (irq == |(intr_state & intr_enable));
|
||||
if (command_pop) assert (command_valid);
|
||||
if (!busy) begin
|
||||
assert (!scl_oe);
|
||||
assert (!sda_oe);
|
||||
end
|
||||
if (recovery_active) assert (busy);
|
||||
|
||||
cover (rib_ready && rib_resp_err);
|
||||
cover (command_count != 5'd0);
|
||||
cover (rx_count != 5'd0);
|
||||
cover (busy && scl_oe);
|
||||
cover (busy && sda_oe);
|
||||
cover (recovery_active);
|
||||
cover (irq);
|
||||
cover (error_status != 11'd0);
|
||||
cover (!tx_dma_stall);
|
||||
cover (!rx_dma_stall);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -46,6 +46,7 @@ COMPATIBILITY_IRQ_BINDINGS = (
|
||||
("reserved", "apb", 6, 16, "1'b0"),
|
||||
("ws2812", "ribp", 10, 17, "ws2812.irq_o"),
|
||||
("gpio", "ribp", 11, 18, "gpio.irq_o"),
|
||||
("i2c1", "ribp", 12, 19, "i2c1.irq_o"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"gpio_pins": 32,
|
||||
"irq_vector_width": 32,
|
||||
"irq_groups": [
|
||||
{"name": "ribp", "width": 12, "top_signal": "s_ribp_irq"},
|
||||
{"name": "ribp", "width": 13, "top_signal": "s_ribp_irq"},
|
||||
{"name": "apb", "width": 7, "top_signal": "s_apb_irq"}
|
||||
],
|
||||
"interrupts": [
|
||||
@@ -25,7 +25,8 @@
|
||||
{"name": "advanced_timer", "description": "APB advanced timer interrupt", "group": "apb", "group_bit": 5, "core_bit": 15, "signal": "u_tmr_if.irq_o"},
|
||||
{"name": "reserved", "description": "Reserved interrupt slot", "group": "apb", "group_bit": 6, "core_bit": 16, "signal": "1'b0"},
|
||||
{"name": "ws2812", "description": "WS2812 transmitter interrupt", "group": "ribp", "group_bit": 10, "core_bit": 17, "signal": "ws2812.irq_o"},
|
||||
{"name": "gpio", "description": "RIBP GPIO combined interrupt", "group": "ribp", "group_bit": 11, "core_bit": 18, "signal": "gpio.irq_o"}
|
||||
{"name": "gpio", "description": "RIBP GPIO combined interrupt", "group": "ribp", "group_bit": 11, "core_bit": 18, "signal": "gpio.irq_o"},
|
||||
{"name": "i2c1", "description": "RIBP I2C1 interrupt", "group": "ribp", "group_bit": 12, "core_bit": 19, "signal": "i2c1.irq_o"}
|
||||
],
|
||||
"ribp_targets": [
|
||||
{"slot": 0, "name": "uart0", "interface": "u_uart_ribp_if", "regions": ["RIBP_UART0"]},
|
||||
|
||||
+18
-6
@@ -6,10 +6,12 @@ FORMAL_SOLVER_DIR := $(FORMAL_DIR)/bin
|
||||
FORMAL_SOLVER_WRAPPER := $(FORMAL_SOLVER_DIR)/bitwuzla
|
||||
FORMAL_DEPTH ?= 20
|
||||
FORMAL_WS2812_DEPTH ?= 120
|
||||
FORMAL_I2C_DEPTH ?= 80
|
||||
FORMAL_CLINT_DEPTH ?= 32
|
||||
FORMAL_TIMEOUT ?= 60
|
||||
FORMAL_WS2812_TIMEOUT ?= 120
|
||||
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio ws2812 uart timer clint
|
||||
FORMAL_I2C_TIMEOUT ?= 300
|
||||
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio ws2812 uart i2c timer clint
|
||||
FORMAL_FILELIST_GENERATOR := $(RTL_PATH)/formal/generate_formal_filelist.py
|
||||
FORMAL_SBY_GENERATOR := $(RTL_PATH)/formal/generate_sby_config.py
|
||||
FORMAL_RESULT_GENERATOR := $(RTL_PATH)/formal/formal_results.py
|
||||
@@ -29,6 +31,8 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
|
||||
$(RTL_PATH)/formal/ws2812_formal_props.sv \
|
||||
$(RTL_PATH)/formal/uart_formal.sv \
|
||||
$(RTL_PATH)/formal/uart_formal_props.sv \
|
||||
$(RTL_PATH)/formal/i2c_formal.sv \
|
||||
$(RTL_PATH)/formal/i2c_formal_props.sv \
|
||||
$(RTL_PATH)/formal/timer_formal.sv \
|
||||
$(RTL_PATH)/formal/timer_formal_props.sv \
|
||||
$(RTL_PATH)/formal/clint_formal.sv \
|
||||
@@ -59,6 +63,11 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/serial/uart_reg.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/serial/ribp_uart.sv \
|
||||
$(ROOT_PATH)/rtl/managed/clusterip/uart/rtl/uart_if.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/serial/i2c_filter.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/serial/i2c_core.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/serial/i2c_reg.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/serial/ribp_i2c.sv \
|
||||
$(ROOT_PATH)/rtl/managed/clusterip/i2c/rtl/i2c_if.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/timer_core.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/timer_define.svh \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/timer_reg.sv \
|
||||
@@ -107,13 +116,14 @@ $(FORMAL_DIR)/%/prove.sby: $(FORMAL_DIR)/%/design.v $(RTL_PATH)/formal/%_formal_
|
||||
$(FORMAL_SBY_GENERATOR)
|
||||
python3 $(FORMAL_SBY_GENERATOR) --top $*_formal --input $< \
|
||||
--properties $(RTL_PATH)/formal/$*_formal_props.sv --solver $(FORMAL_SOLVER) \
|
||||
--mode prove --depth $(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(FORMAL_DEPTH))) --output $@
|
||||
--mode prove --depth $(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter i2c,$*),$(FORMAL_I2C_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(FORMAL_DEPTH)))) --output $@
|
||||
|
||||
$(FORMAL_DIR)/%/cover.sby: $(FORMAL_DIR)/%/design.v $(RTL_PATH)/formal/%_formal_props.sv \
|
||||
$(FORMAL_SBY_GENERATOR)
|
||||
python3 $(FORMAL_SBY_GENERATOR) --top $*_formal --input $< \
|
||||
--properties $(RTL_PATH)/formal/$*_formal_props.sv --solver $(FORMAL_SOLVER) \
|
||||
--mode cover --depth $(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(FORMAL_DEPTH))) --output $@
|
||||
--mode cover --depth $(if $(filter ws2812,$*),$(FORMAL_WS2812_DEPTH),$(if $(filter i2c,$*),$(FORMAL_I2C_DEPTH),$(if $(filter clint,$*),$(FORMAL_CLINT_DEPTH),$(FORMAL_DEPTH)))) \
|
||||
$(if $(filter i2c,$*),--no-vcd) --output $@
|
||||
|
||||
$(FORMAL_SOLVER_WRAPPER): $(ROOT_PATH)/scripts/bitwuzla_smt2.py
|
||||
@mkdir -p $(@D)
|
||||
@@ -125,7 +135,7 @@ $(FORMAL_DIR)/%/prove.stamp: $(FORMAL_DIR)/%/prove.sby $(FORMAL_SOLVER_WRAPPER)
|
||||
--log $(@D)/prove.log --result $(@D)/result-prove.json \
|
||||
--env RETROSOC_BITWUZLA=$(FORMAL_BITWUZLA) \
|
||||
--env PATH=$(FORMAL_SOLVER_DIR):$(PATH) \
|
||||
-- timeout --foreground --kill-after=5s $(if $(filter ws2812,$*),$(FORMAL_WS2812_TIMEOUT),$(FORMAL_TIMEOUT))s $(FORMAL_SBY) \
|
||||
-- timeout --foreground --kill-after=5s $(if $(filter ws2812,$*),$(FORMAL_WS2812_TIMEOUT),$(if $(filter i2c,$*),$(FORMAL_I2C_TIMEOUT),$(FORMAL_TIMEOUT)))s $(FORMAL_SBY) \
|
||||
-f -d $(@D)/prove $<
|
||||
@test "$$(awk '{print $$1}' $(@D)/prove/status)" = PASS
|
||||
@touch $@
|
||||
@@ -135,7 +145,7 @@ $(FORMAL_DIR)/%/cover.stamp: $(FORMAL_DIR)/%/cover.sby $(FORMAL_SOLVER_WRAPPER)
|
||||
--log $(@D)/cover.log --result $(@D)/result-cover.json \
|
||||
--env RETROSOC_BITWUZLA=$(FORMAL_BITWUZLA) \
|
||||
--env PATH=$(FORMAL_SOLVER_DIR):$(PATH) \
|
||||
-- timeout --foreground --kill-after=5s $(if $(filter ws2812,$*),$(FORMAL_WS2812_TIMEOUT),$(FORMAL_TIMEOUT))s $(FORMAL_SBY) \
|
||||
-- timeout --foreground --kill-after=5s $(if $(filter ws2812,$*),$(FORMAL_WS2812_TIMEOUT),$(if $(filter i2c,$*),$(FORMAL_I2C_TIMEOUT),$(FORMAL_TIMEOUT)))s $(FORMAL_SBY) \
|
||||
-f -d $(@D)/cover $<
|
||||
@test "$$(awk '{print $$1}' $(@D)/cover/status)" = PASS
|
||||
@touch $@
|
||||
@@ -165,6 +175,8 @@ formal-ws2812: $(FORMAL_DIR)/ws2812/.stamp | manifest
|
||||
|
||||
formal-uart: $(FORMAL_DIR)/uart/.stamp | manifest
|
||||
|
||||
formal-i2c: $(FORMAL_DIR)/i2c/.stamp | manifest
|
||||
|
||||
formal-timer: $(FORMAL_DIR)/timer/.stamp | manifest
|
||||
|
||||
formal-clint: $(FORMAL_DIR)/clint/.stamp | manifest
|
||||
@@ -175,4 +187,4 @@ formal-doctor:
|
||||
formal-clean:
|
||||
python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(FORMAL_DIR)
|
||||
|
||||
.PHONY: formal formal-bus formal-rib-adapter formal-rib2apb formal-sysctrl formal-pll-rcu formal-gpio formal-ws2812 formal-uart formal-timer formal-clint formal-doctor formal-clean
|
||||
.PHONY: formal formal-bus formal-rib-adapter formal-rib2apb formal-sysctrl formal-pll-rcu formal-gpio formal-ws2812 formal-uart formal-i2c formal-timer formal-clint formal-doctor formal-clean
|
||||
@@ -81,6 +81,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
|
||||
$(ROOT_PATH)/crt/src/hal/advanced_timer.c \
|
||||
$(ROOT_PATH)/crt/src/hal/hpuart.c \
|
||||
$(ROOT_PATH)/crt/src/hal/ps2.c \
|
||||
$(ROOT_PATH)/crt/src/hal/i2c_math.c \
|
||||
$(ROOT_PATH)/crt/src/hal/i2c.c \
|
||||
$(ROOT_PATH)/crt/src/hal/ws2812_math.c \
|
||||
$(ROOT_PATH)/crt/src/hal/ws2812.c \
|
||||
|
||||
@@ -59,6 +59,8 @@ module ip_ribp_wrapper (
|
||||
logic s_dma_i2s_tx_stall, s_dma_i2s_rx_stall;
|
||||
logic s_dma_xpi_tx_stall, s_dma_xpi_rx_stall;
|
||||
logic s_dma_uart_tx_stall, s_dma_uart_rx_stall;
|
||||
logic s_dma_i2c0_tx_stall, s_dma_i2c0_rx_stall;
|
||||
logic s_dma_i2c1_tx_stall, s_dma_i2c1_rx_stall;
|
||||
logic s_dma_xfer_done;
|
||||
logic s_tim0_irq, s_tim1_irq;
|
||||
|
||||
@@ -96,6 +98,10 @@ module ip_ribp_wrapper (
|
||||
assign u_dma_hw_trg_if.qspi_rx_proc = ~s_dma_xpi_rx_stall;
|
||||
assign u_dma_hw_trg_if.uart_tx_proc = ~s_dma_uart_tx_stall;
|
||||
assign u_dma_hw_trg_if.uart_rx_proc = ~s_dma_uart_rx_stall;
|
||||
assign u_dma_hw_trg_if.i2c0_tx_proc = ~s_dma_i2c0_tx_stall;
|
||||
assign u_dma_hw_trg_if.i2c0_rx_proc = ~s_dma_i2c0_rx_stall;
|
||||
assign u_dma_hw_trg_if.i2c1_tx_proc = ~s_dma_i2c1_tx_stall;
|
||||
assign u_dma_hw_trg_if.i2c1_rx_proc = ~s_dma_i2c1_rx_stall;
|
||||
|
||||
// Uses ClusterIP common ribp_if and register.sv dffr through generated bindings.
|
||||
`include "ribp_routes.svh"
|
||||
@@ -159,10 +165,12 @@ module ip_ribp_wrapper (
|
||||
);
|
||||
|
||||
ribp_i2c u_rib_i2c0 (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.ribp (u_i2c0_ribp_if),
|
||||
.i2c (i2c0)
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.dma_tx_stall_o(s_dma_i2c0_tx_stall),
|
||||
.dma_rx_stall_o(s_dma_i2c0_rx_stall),
|
||||
.ribp (u_i2c0_ribp_if),
|
||||
.i2c (i2c0)
|
||||
);
|
||||
|
||||
ribp_i2s u_rib_i2s (
|
||||
@@ -251,10 +259,12 @@ module ip_ribp_wrapper (
|
||||
);
|
||||
|
||||
ribp_i2c u_rib_i2c1 (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.ribp (u_i2c1_ribp_if),
|
||||
.i2c (i2c1)
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.dma_tx_stall_o(s_dma_i2c1_tx_stall),
|
||||
.dma_rx_stall_o(s_dma_i2c1_rx_stall),
|
||||
.ribp (u_i2c1_ribp_if),
|
||||
.i2c (i2c1)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -21,6 +21,7 @@ TEST_SOURCES = (
|
||||
"crt/src/lib/stdlib.c",
|
||||
"crt/src/lib/string.c",
|
||||
"crt/src/hal/gpio_math.c",
|
||||
"crt/src/hal/i2c_math.c",
|
||||
"crt/src/hal/ws2812_math.c",
|
||||
"crt/src/hal/uart_math.c",
|
||||
"crt/src/hal/timer_math.c",
|
||||
|
||||
+28
-4
@@ -4,6 +4,7 @@
|
||||
#include <retrosoc/core/status.h>
|
||||
#include <retrosoc/core/wait.h>
|
||||
#include <retrosoc/hal/gpio.h>
|
||||
#include <retrosoc/hal/i2c.h>
|
||||
#include <retrosoc/hal/lcd.h>
|
||||
#include <retrosoc/hal/spisd.h>
|
||||
#include <retrosoc/hal/timer.h>
|
||||
@@ -211,6 +212,30 @@ static int test_uart_helpers(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_i2c_helpers(void) {
|
||||
rs_i2c_timing_t timing;
|
||||
|
||||
if ((rs_i2c_timing_calculate(72000000U, 400000U, &timing) != RS_OK) ||
|
||||
(timing.scl_low_cycles != 136U) || (timing.scl_high_cycles != 44U) ||
|
||||
(timing.start_hold_cycles != 44U) || (timing.start_setup_cycles != 44U) ||
|
||||
(timing.data_setup_cycles != 8U) || (timing.stop_setup_cycles != 44U) ||
|
||||
(timing.bus_free_cycles != 94U)) {
|
||||
return 1;
|
||||
}
|
||||
if ((rs_i2c_timing_calculate(72000000U, 1000000U, &timing) != RS_OK) ||
|
||||
(timing.scl_low_cycles != 53U) || (timing.scl_high_cycles != 19U) ||
|
||||
(timing.data_setup_cycles != 4U)) {
|
||||
return 2;
|
||||
}
|
||||
if ((rs_i2c_timing_calculate(0U, 400000U, &timing) != RS_EINVAL) ||
|
||||
(rs_i2c_timing_calculate(72000000U, 0U, &timing) != RS_EINVAL) ||
|
||||
(rs_i2c_timing_calculate(72000000U, 1000001U, &timing) != RS_EINVAL) ||
|
||||
(rs_i2c_timing_calculate(72000000U, 400000U, NULL) != RS_EINVAL)) {
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_gpio_helpers(void) {
|
||||
rs_gpio_filter_timing_t timing;
|
||||
|
||||
@@ -271,10 +296,9 @@ static int test_video_parser(void) {
|
||||
|
||||
int main(void) {
|
||||
const int results[] = {
|
||||
test_string_helpers(), test_formatter(), test_compiler_helpers(),
|
||||
test_wait_helper(), test_ws2812_helpers(), test_timer_helpers(),
|
||||
test_uart_helpers(), test_gpio_helpers(), test_wav_parser(),
|
||||
test_video_parser(),
|
||||
test_string_helpers(), test_formatter(), test_compiler_helpers(), test_wait_helper(),
|
||||
test_ws2812_helpers(), test_timer_helpers(), test_uart_helpers(), test_i2c_helpers(),
|
||||
test_gpio_helpers(), test_wav_parser(), test_video_parser(),
|
||||
};
|
||||
|
||||
for (size_t index = 0U; index < (sizeof(results) / sizeof(results[0])); ++index) {
|
||||
|
||||
@@ -7,7 +7,7 @@ module dma_error_tb;
|
||||
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic [ 2:0] mode_i = 3'd0;
|
||||
logic [ 3:0] mode_i = 4'd0;
|
||||
logic [31:0] srcaddr_i = 32'h3800_1000;
|
||||
logic srcincr_i = 1'b1;
|
||||
logic [31:0] dstaddr_i = 32'h4000_1000;
|
||||
@@ -145,6 +145,10 @@ module dma_error_tb;
|
||||
hw_trg.qspi_rx_proc = 1'b0;
|
||||
hw_trg.uart_tx_proc = 1'b0;
|
||||
hw_trg.uart_rx_proc = 1'b0;
|
||||
hw_trg.i2c0_tx_proc = 1'b0;
|
||||
hw_trg.i2c0_rx_proc = 1'b0;
|
||||
hw_trg.i2c1_tx_proc = 1'b0;
|
||||
hw_trg.i2c1_rx_proc = 1'b0;
|
||||
repeat (2) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
`include "ribp_i2c_define.svh"
|
||||
|
||||
module i2c_tb;
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic dma_tx_stall;
|
||||
logic dma_rx_stall;
|
||||
logic slave_scl_low = 1'b0;
|
||||
logic slave_sda_low = 1'b0;
|
||||
logic scl_line;
|
||||
logic sda_line;
|
||||
ribp_if ribp ();
|
||||
i2c_if i2c ();
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
assign scl_line = (i2c.scl_oe_o || slave_scl_low) ? 1'b0 : 1'b1;
|
||||
assign sda_line = (i2c.sda_oe_o || slave_sda_low) ? 1'b0 : 1'b1;
|
||||
assign i2c.scl_i = scl_line;
|
||||
assign i2c.sda_i = sda_line;
|
||||
|
||||
ribp_i2c u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.dma_tx_stall_o(dma_tx_stall),
|
||||
.dma_rx_stall_o(dma_rx_stall),
|
||||
.ribp (ribp),
|
||||
.i2c (i2c)
|
||||
);
|
||||
|
||||
task automatic ribp_write(input logic [31:0] address, input logic [31:0] data,
|
||||
input logic expected_error);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
ribp.addr = address;
|
||||
ribp.wdata = data;
|
||||
ribp.wstrb = 4'hF;
|
||||
ribp.valid = 1'b1;
|
||||
while (!ribp.ready) begin
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
end
|
||||
if (ribp.resp_err !== expected_error) begin
|
||||
$fatal(1, "I2C write %h error=%b expected=%b", address, ribp.resp_err, expected_error);
|
||||
end
|
||||
@(negedge clk_i);
|
||||
ribp.valid = 1'b0;
|
||||
ribp.wstrb = '0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic ribp_read(input logic [31:0] address, input logic expected_error,
|
||||
output logic [31:0] data);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
ribp.addr = address;
|
||||
ribp.wdata = '0;
|
||||
ribp.wstrb = '0;
|
||||
ribp.valid = 1'b1;
|
||||
while (!ribp.ready) begin
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
end
|
||||
if (ribp.resp_err !== expected_error) begin
|
||||
$fatal(1, "I2C read %h error=%b expected=%b", address, ribp.resp_err, expected_error);
|
||||
end
|
||||
data = ribp.rdata;
|
||||
@(negedge clk_i);
|
||||
ribp.valid = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic wait_start;
|
||||
begin
|
||||
@(negedge sda_line);
|
||||
while (!scl_line) begin
|
||||
@(negedge sda_line);
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic receive_byte(output logic [7:0] data, input integer stretch_cycles);
|
||||
integer bit_index;
|
||||
begin
|
||||
for (bit_index = 7; bit_index >= 0; bit_index = bit_index - 1) begin
|
||||
@(posedge scl_line);
|
||||
data[bit_index] = sda_line;
|
||||
end
|
||||
@(negedge scl_line);
|
||||
slave_sda_low = 1'b1;
|
||||
if (stretch_cycles != 0) begin
|
||||
slave_scl_low = 1'b1;
|
||||
repeat (stretch_cycles) @(posedge clk_i);
|
||||
slave_scl_low = 1'b0;
|
||||
end
|
||||
@(posedge scl_line);
|
||||
@(negedge scl_line);
|
||||
slave_sda_low = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic send_byte(input logic [7:0] data, output logic nack);
|
||||
integer bit_index;
|
||||
begin
|
||||
for (bit_index = 7; bit_index >= 0; bit_index = bit_index - 1) begin
|
||||
slave_sda_low = !data[bit_index];
|
||||
@(posedge scl_line);
|
||||
@(negedge scl_line);
|
||||
end
|
||||
slave_sda_low = 1'b0;
|
||||
@(posedge scl_line);
|
||||
nack = sda_line;
|
||||
@(negedge scl_line);
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic wait_done;
|
||||
logic [31:0] value;
|
||||
logic [31:0] error_value;
|
||||
logic [31:0] status_value;
|
||||
integer attempts;
|
||||
begin
|
||||
value = '0;
|
||||
for (attempts = 0; attempts < 4000; attempts = attempts + 1) begin
|
||||
ribp_read(`RIBP_I2C_INTR_STATE, 1'b0, value);
|
||||
if (value[`I2C_INTR_DONE]) begin
|
||||
attempts = 4000;
|
||||
end
|
||||
end
|
||||
if (!value[`I2C_INTR_DONE]) begin
|
||||
ribp_read(`RIBP_I2C_ERROR_STATUS, 1'b0, error_value);
|
||||
ribp_read(`RIBP_I2C_STATUS, 1'b0, status_value);
|
||||
$fatal(1, "I2C transaction did not complete: error=%h status=%h fsm=%0d", error_value,
|
||||
status_value, u_dut.u_i2c_core.s_fsm_q);
|
||||
end
|
||||
ribp_write(`RIBP_I2C_INTR_STATE, 32'hFF, 1'b0);
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic clear_state;
|
||||
begin
|
||||
ribp_write(`RIBP_I2C_ERROR_STATUS, 32'h7FF, 1'b0);
|
||||
ribp_write(`RIBP_I2C_INTR_STATE, 32'hFF, 1'b0);
|
||||
ribp_write(`RIBP_I2C_COMMAND, 32'hC, 1'b0);
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
logic [31:0] value;
|
||||
logic [ 7:0] byte_value;
|
||||
logic nack;
|
||||
integer pulse_count;
|
||||
|
||||
ribp.valid = 1'b0;
|
||||
ribp.addr = '0;
|
||||
ribp.wdata = '0;
|
||||
ribp.wstrb = '0;
|
||||
repeat (4) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
repeat (4) @(posedge clk_i);
|
||||
|
||||
ribp_read(`RIBP_I2C_IP_VERSION, 1'b0, value);
|
||||
if (value != 32'h0002_0000) $fatal(1, "I2C version mismatch");
|
||||
ribp_read(`RIBP_I2C_CAPABILITY, 1'b0, value);
|
||||
if (value != 32'h007F_1010) $fatal(1, "I2C capability mismatch: %h", value);
|
||||
ribp_read(32'h2, 1'b1, value);
|
||||
|
||||
ribp_write(`RIBP_I2C_SCL_TIMING, 32'h0008_0008, 1'b0);
|
||||
ribp_write(`RIBP_I2C_START_TIMING, 32'h0002_0002, 1'b0);
|
||||
ribp_write(`RIBP_I2C_DATA_TIMING, 32'h0001_0000, 1'b0);
|
||||
ribp_write(`RIBP_I2C_STOP_TIMING, 32'h0002_0002, 1'b0);
|
||||
ribp_write(`RIBP_I2C_FILTER, 0, 1'b0);
|
||||
ribp_write(`RIBP_I2C_STRETCH_TIMEOUT, 200, 1'b0);
|
||||
ribp_write(`RIBP_I2C_BUS_IDLE_TIMEOUT, 200, 1'b0);
|
||||
ribp_write(`RIBP_I2C_COMMAND_TIMEOUT, 2000, 1'b0);
|
||||
ribp_write(`RIBP_I2C_TARGET_ADDR, 7'h50, 1'b0);
|
||||
ribp_write(`RIBP_I2C_CTRL, 1, 1'b0);
|
||||
|
||||
fork
|
||||
begin
|
||||
wait_start();
|
||||
receive_byte(byte_value, 0);
|
||||
if (byte_value != 8'hA0) $fatal(1, "write address mismatch: %h", byte_value);
|
||||
receive_byte(byte_value, 0);
|
||||
if (byte_value != 8'hA5) $fatal(1, "write data mismatch: %h", byte_value);
|
||||
end
|
||||
begin
|
||||
ribp_write(`RIBP_I2C_DATA_CMD, 32'h4A5, 1'b0);
|
||||
wait_done();
|
||||
end
|
||||
join
|
||||
|
||||
clear_state();
|
||||
ribp_write(`RIBP_I2C_TARGET_ADDR, 32'h0000_06AA, 1'b0);
|
||||
fork
|
||||
begin
|
||||
wait_start();
|
||||
receive_byte(byte_value, 0);
|
||||
if (byte_value != 8'hF4) $fatal(1, "10-bit write header mismatch: %h", byte_value);
|
||||
receive_byte(byte_value, 0);
|
||||
if (byte_value != 8'hAA) $fatal(1, "10-bit low address mismatch: %h", byte_value);
|
||||
wait_start();
|
||||
receive_byte(byte_value, 0);
|
||||
if (byte_value != 8'hF5) $fatal(1, "10-bit read header mismatch: %h", byte_value);
|
||||
send_byte(8'hC3, nack);
|
||||
if (!nack) $fatal(1, "final 10-bit read byte was not NACKed");
|
||||
end
|
||||
begin
|
||||
ribp_write(`RIBP_I2C_DATA_CMD, 32'hD00, 1'b0);
|
||||
wait_done();
|
||||
ribp_read(`RIBP_I2C_RXDATA, 1'b0, value);
|
||||
if (value[7:0] != 8'hC3) $fatal(1, "10-bit read data mismatch: %h", value);
|
||||
end
|
||||
join
|
||||
|
||||
clear_state();
|
||||
ribp_write(`RIBP_I2C_TARGET_ADDR, 7'h50, 1'b0);
|
||||
fork
|
||||
begin
|
||||
wait_start();
|
||||
receive_byte(byte_value, 0);
|
||||
if (byte_value != 8'hA0) $fatal(1, "combined write address mismatch");
|
||||
receive_byte(byte_value, 0);
|
||||
if (byte_value != 8'h12) $fatal(1, "combined register byte mismatch");
|
||||
wait_start();
|
||||
receive_byte(byte_value, 0);
|
||||
if (byte_value != 8'hA1) $fatal(1, "combined read address mismatch");
|
||||
send_byte(8'h5A, nack);
|
||||
if (!nack) $fatal(1, "final read byte was not NACKed");
|
||||
end
|
||||
begin
|
||||
ribp_write(`RIBP_I2C_DATA_CMD, 32'h012, 1'b0);
|
||||
ribp_write(`RIBP_I2C_DATA_CMD, 32'hF00, 1'b0);
|
||||
wait_done();
|
||||
ribp_read(`RIBP_I2C_RXDATA, 1'b0, value);
|
||||
if (value[7:0] != 8'h5A) $fatal(1, "read data mismatch: %h", value);
|
||||
end
|
||||
join
|
||||
|
||||
clear_state();
|
||||
fork
|
||||
begin
|
||||
wait_start();
|
||||
receive_byte(byte_value, 12);
|
||||
receive_byte(byte_value, 0);
|
||||
end
|
||||
begin
|
||||
ribp_write(`RIBP_I2C_DATA_CMD, 32'h45C, 1'b0);
|
||||
wait_done();
|
||||
end
|
||||
join
|
||||
|
||||
clear_state();
|
||||
ribp_write(`RIBP_I2C_TARGET_ADDR, 7'h51, 1'b0);
|
||||
ribp_write(`RIBP_I2C_DATA_CMD, 32'h455, 1'b0);
|
||||
repeat (300) @(posedge clk_i);
|
||||
ribp_read(`RIBP_I2C_ERROR_STATUS, 1'b0, value);
|
||||
if (!value[`I2C_ERROR_ADDR_NACK]) $fatal(1, "address NACK was not reported");
|
||||
|
||||
clear_state();
|
||||
ribp_write(`RIBP_I2C_TARGET_ADDR, 7'h7F, 1'b0);
|
||||
fork
|
||||
begin
|
||||
wait_start();
|
||||
@(negedge scl_line);
|
||||
#1 slave_sda_low = 1'b1;
|
||||
@(posedge scl_line);
|
||||
repeat (4) @(posedge clk_i);
|
||||
slave_sda_low = 1'b0;
|
||||
end
|
||||
begin
|
||||
ribp_write(`RIBP_I2C_DATA_CMD, 32'h400, 1'b0);
|
||||
end
|
||||
join
|
||||
repeat (20) @(posedge clk_i);
|
||||
ribp_read(`RIBP_I2C_ERROR_STATUS, 1'b0, value);
|
||||
if (!value[`I2C_ERROR_ARB_LOST]) $fatal(1, "arbitration loss was not reported");
|
||||
|
||||
clear_state();
|
||||
slave_sda_low = 1'b1;
|
||||
fork
|
||||
begin
|
||||
pulse_count = 0;
|
||||
while (pulse_count < 9) begin
|
||||
@(posedge scl_line);
|
||||
pulse_count = pulse_count + 1;
|
||||
end
|
||||
slave_sda_low = 1'b0;
|
||||
end
|
||||
begin
|
||||
ribp_write(`RIBP_I2C_COMMAND, 32'h2, 1'b0);
|
||||
end
|
||||
join
|
||||
repeat (80) @(posedge clk_i);
|
||||
ribp_read(`RIBP_I2C_INTR_STATE, 1'b0, value);
|
||||
if (!value[`I2C_INTR_RECOVERY_DONE] || (pulse_count != 9)) begin
|
||||
$fatal(1, "bus recovery failed: intr=%h pulses=%0d", value, pulse_count);
|
||||
end
|
||||
|
||||
if (i2c.scl_o !== 1'b0 || i2c.sda_o !== 1'b0) begin
|
||||
$fatal(1, "I2C pads are not open-drain constants");
|
||||
end
|
||||
$display("I2C V2 transfer, error, stretch, arbitration, and recovery test passed");
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin
|
||||
repeat (50000) @(posedge clk_i);
|
||||
$fatal(1, "I2C test timeout");
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -127,7 +127,7 @@ module ws2812_dma_tb;
|
||||
dma_core u_dma_core (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.mode_i (3'd0),
|
||||
.mode_i (4'd0),
|
||||
.srcaddr_i (SOURCE_BASE + 32'd4),
|
||||
.srcincr_i (1'b1),
|
||||
.dstaddr_i (WS2812_TXDATA),
|
||||
@@ -219,6 +219,10 @@ module ws2812_dma_tb;
|
||||
hw_trg.qspi_rx_proc = 1'b0;
|
||||
hw_trg.uart_tx_proc = 1'b0;
|
||||
hw_trg.uart_rx_proc = 1'b0;
|
||||
hw_trg.i2c0_tx_proc = 1'b0;
|
||||
hw_trg.i2c0_rx_proc = 1'b0;
|
||||
hw_trg.i2c1_tx_proc = 1'b0;
|
||||
hw_trg.i2c1_rx_proc = 1'b0;
|
||||
|
||||
repeat (3) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
"""Directed I2C V2 controller, FIFO, error, timeout, and recovery tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def test_i2c_v2_controller_and_recovery_contract(tmp_path: Path) -> None:
|
||||
iverilog = shutil.which("iverilog")
|
||||
vvp = shutil.which("vvp")
|
||||
if iverilog is None or vvp is None:
|
||||
return
|
||||
|
||||
common = ROOT / "rtl/managed/clusterip/common/rtl"
|
||||
serial = ROOT / "rtl/ip/ribp/serial"
|
||||
cluster_i2c = ROOT / "rtl/managed/clusterip/i2c/rtl"
|
||||
source_list = tmp_path / "i2c.fl"
|
||||
source_list.write_text(
|
||||
"\n".join(
|
||||
[
|
||||
"+define+SV_ASSRT_DISABLE",
|
||||
f"+incdir+{common}",
|
||||
f"+incdir+{common / 'interface'}",
|
||||
f"+incdir+{common / 'utils'}",
|
||||
f"+incdir+{common / 'cdc'}",
|
||||
f"+incdir+{serial}",
|
||||
str(common / "interface/ribp_if.sv"),
|
||||
str(common / "utils/register.sv"),
|
||||
str(common / "utils/fifo.sv"),
|
||||
str(common / "cdc/cdc_sync.sv"),
|
||||
str(cluster_i2c / "i2c_if.sv"),
|
||||
str(serial / "i2c_filter.sv"),
|
||||
str(serial / "i2c_core.sv"),
|
||||
str(serial / "i2c_reg.sv"),
|
||||
str(serial / "ribp_i2c.sv"),
|
||||
str(ROOT / "tests/rtl/i2c_tb.sv"),
|
||||
"",
|
||||
]
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
converted = tmp_path / "i2c_tb.v"
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
str(ROOT / "rtl/mini/script/convt_sv2v.py"),
|
||||
"-f",
|
||||
str(source_list),
|
||||
"--output",
|
||||
str(converted),
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
simulation = tmp_path / "i2c_tb"
|
||||
subprocess.run(
|
||||
[iverilog, "-g2012", "-s", "i2c_tb", "-o", str(simulation), str(converted)],
|
||||
check=True,
|
||||
)
|
||||
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
|
||||
assert "I2C V2 transfer, error, stretch, arbitration, and recovery test passed" in result.stdout
|
||||
@@ -205,6 +205,7 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
|
||||
pll_rcu_filelist = tmp_path / "pll_rcu.fl"
|
||||
gpio_filelist = tmp_path / "gpio.fl"
|
||||
ws2812_filelist = tmp_path / "ws2812.fl"
|
||||
i2c_filelist = tmp_path / "i2c.fl"
|
||||
clint_filelist = tmp_path / "clint.fl"
|
||||
assert generate_formal_filelist("bus", bus_filelist, memory_map, topology, user_extensions)
|
||||
assert generate_formal_filelist(
|
||||
@@ -225,6 +226,7 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
|
||||
assert generate_formal_filelist(
|
||||
"ws2812", ws2812_filelist, memory_map, topology, user_extensions
|
||||
)
|
||||
assert generate_formal_filelist("i2c", i2c_filelist, memory_map, topology, user_extensions)
|
||||
assert generate_formal_filelist(
|
||||
"clint", clint_filelist, memory_map, topology, user_extensions
|
||||
)
|
||||
@@ -236,6 +238,7 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
|
||||
pll_rcu = parse_filelists([pll_rcu_filelist], require_files=False)
|
||||
gpio = parse_filelists([gpio_filelist], require_files=False)
|
||||
ws2812 = parse_filelists([ws2812_filelist], require_files=False)
|
||||
i2c = parse_filelists([i2c_filelist], require_files=False)
|
||||
clint = parse_filelists([clint_filelist], require_files=False)
|
||||
assert "+define+SV_ASSRT_DISABLE" in bus.defines
|
||||
assert ROOT / "rtl/mini/top/bus.sv" in bus.files
|
||||
@@ -262,6 +265,9 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
|
||||
assert ROOT / "rtl/ip/ribp/serial/ribp_ws2812.sv" in ws2812.files
|
||||
assert ROOT / "rtl/managed/clusterip/common/rtl/utils/fifo.sv" in ws2812.files
|
||||
assert ROOT / "rtl/mini/formal/ws2812_formal.sv" in ws2812.files
|
||||
assert ROOT / "rtl/ip/ribp/serial/ribp_i2c.sv" in i2c.files
|
||||
assert ROOT / "rtl/ip/ribp/serial/i2c_filter.sv" in i2c.files
|
||||
assert ROOT / "rtl/mini/formal/i2c_formal.sv" in i2c.files
|
||||
assert ROOT / "rtl/ip/ribp/peripheral/ribp_clint.sv" in clint.files
|
||||
assert ROOT / "rtl/mini/formal/clint_formal.sv" in clint.files
|
||||
|
||||
@@ -284,6 +290,9 @@ def test_sby_config_uses_prove_and_cover_with_bitwuzla(tmp_path: Path) -> None:
|
||||
properties = tmp_path / "properties.v"
|
||||
prove_config = render_sby_config("bus_formal", design, properties, "bitwuzla", "prove", 20)
|
||||
cover_config = render_sby_config("bus_formal", design, properties, "bitwuzla", "cover", 20)
|
||||
compact_cover_config = render_sby_config(
|
||||
"i2c_formal", design, properties, "bitwuzla", "cover", 80, vcd=False
|
||||
)
|
||||
|
||||
assert "mode prove" in prove_config
|
||||
assert "mode cover" in cover_config
|
||||
@@ -291,6 +300,8 @@ def test_sby_config_uses_prove_and_cover_with_bitwuzla(tmp_path: Path) -> None:
|
||||
assert "smtbmc --presat --nounroll bitwuzla" in prove_config
|
||||
assert f"design.v {design.resolve()}" in prove_config
|
||||
assert f"properties.v {properties.resolve()}" in prove_config
|
||||
assert "vcd off" not in cover_config
|
||||
assert "vcd off" in compact_cover_config
|
||||
|
||||
|
||||
def test_bitwuzla_wrapper_translates_yosys_legacy_arguments() -> None:
|
||||
|
||||
@@ -97,12 +97,13 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) -
|
||||
assert ".apb_rib(u_apb_rib_if)" in bus_fabric
|
||||
assert ".rib(u_rib_if)" in bus_fabric
|
||||
assert "`define SOC_IRQ_VECTOR_WIDTH 32" in irq_config
|
||||
assert "`define SOC_USER_IRQ_MASK 32'h0007FFFC" in irq_config
|
||||
assert "`define SOC_IRQ_RIBP_WIDTH 12" in irq_config
|
||||
assert "`define SOC_USER_IRQ_MASK 32'h000FFFFC" in irq_config
|
||||
assert "`define SOC_IRQ_RIBP_WIDTH 13" in irq_config
|
||||
assert "`define SOC_IRQ_APB_WIDTH 7" in irq_config
|
||||
assert "assign irq_o[0] = u_clint_if.software_irq_o[0];" in rib_irq
|
||||
assert "assign irq_o[10] = ws2812.irq_o;" in rib_irq
|
||||
assert "assign irq_o[11] = gpio.irq_o;" in rib_irq
|
||||
assert "assign irq_o[12] = i2c1.irq_o;" in rib_irq
|
||||
assert "assign irq_o[5] = u_tmr_if.irq_o;" in apb_irq
|
||||
assert "s_irq[16] = s_apb_irq[6];" in irq_wiring
|
||||
assert "irq_i[31] == 1'b0" in irq_sva
|
||||
@@ -123,7 +124,7 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
|
||||
)
|
||||
for interrupt in document["interrupts"]
|
||||
]
|
||||
assert mappings[:19] == [
|
||||
assert mappings[:20] == [
|
||||
("clint_software", "ribp", 0, 0, "u_clint_if.software_irq_o[0]"),
|
||||
("clint_timer", "ribp", 1, 1, "u_clint_if.timer_irq_o[0]"),
|
||||
("uart0", "ribp", 2, 2, "uart.irq_o"),
|
||||
@@ -143,8 +144,9 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
|
||||
("reserved", "apb", 6, 16, "1'b0"),
|
||||
("ws2812", "ribp", 10, 17, "ws2812.irq_o"),
|
||||
("gpio", "ribp", 11, 18, "gpio.irq_o"),
|
||||
("i2c1", "ribp", 12, 19, "i2c1.irq_o"),
|
||||
]
|
||||
assert all(mapping[3] >= 19 for mapping in mappings[19:])
|
||||
assert all(mapping[3] >= 20 for mapping in mappings[20:])
|
||||
|
||||
|
||||
def test_topology_always_adds_the_user_apb_target(tmp_path: Path) -> None:
|
||||
|
||||
Reference in new issue
Block a user