mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: add GPIO V2 support and related tests
- Updated to include for testing. - Modified to include GPIO header and added tests for GPIO functionality. - Created a new testbench for GPIO V2, covering register and pad-control contracts. - Removed obsolete and its associated test. - Updated to include GPIO admin base routing. - Added a new Python test for GPIO V2 register and pad-control contract. - Removed as its functionality is now covered in . - Updated memory map tests to ensure GPIO admin base is correctly referenced. - Adjusted formal filelist generation to reflect changes in GPIO handling. - Enhanced SOC topology tests to include GPIO interrupt handling.
This commit is contained in:
53 files changed
+2512
-1200
No files matched your search
@@ -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-ws2812 formal-timer formal-clean formal-doctor
|
||||
formal formal-bus formal-rib-adapter formal-rib2apb formal-gpio formal-ws2812 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-user | formal-ws2812 | formal-timer | formal-clint run peripheral proofs' \
|
||||
' formal-sysctrl | formal-pll-rcu | formal-gpio | formal-ws2812 | 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' \
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/hal/clint.h>
|
||||
#include <retrosoc/hal/gpio.h>
|
||||
#include <retrosoc/hal/timer.h>
|
||||
#include <retrosoc/hal/uart.h>
|
||||
#include <retrosoc/lib/printf.h>
|
||||
@@ -111,23 +112,54 @@ static bool rs_ci_smoke_timer_periodic(void) {
|
||||
return passed;
|
||||
}
|
||||
|
||||
static bool rs_ci_smoke_gpio_v2(void) {
|
||||
const rs_gpio_config_t config = {
|
||||
.mode = RS_GPIO_MODE_OUTPUT,
|
||||
.pull = RS_GPIO_PULL_NONE,
|
||||
.trigger = RS_GPIO_TRIGGER_NONE,
|
||||
.output_high = false,
|
||||
.open_drain = false,
|
||||
.input_cmos = false,
|
||||
.filter_enable = false,
|
||||
.interrupt_enable = false,
|
||||
};
|
||||
rs_gpio_capabilities_t capabilities;
|
||||
|
||||
if ((rs_gpio_get_capabilities(&capabilities) != RS_OK) ||
|
||||
(capabilities.version != UINT32_C(0x00020000)) ||
|
||||
((capabilities.features & UINT32_C(0xFF)) != RS_GPIO_PIN_COUNT) ||
|
||||
((capabilities.features & RS_GPIO_CAP_ATOMIC_OUT) == 0U) ||
|
||||
(rs_gpio_configure(31U, &config) != RS_OK) || (rs_gpio_write(31U, true) != RS_OK) ||
|
||||
(rs_gpio_toggle(31U) != RS_OK)) {
|
||||
return false;
|
||||
}
|
||||
return rs_gpio_write(31U, false) == RS_OK;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
uart0_init(CPU_FREQ, UART_BPS);
|
||||
|
||||
if (!rs_ci_smoke_archinfo_matches_reset_values()) {
|
||||
rs_test_finish(RS_TEST_FAILED, 1U);
|
||||
}
|
||||
printf("ci_smoke: archinfo passed\n");
|
||||
if (!rs_ci_smoke_clint_standard_map()) {
|
||||
rs_test_finish(RS_TEST_FAILED, 2U);
|
||||
}
|
||||
printf("ci_smoke: CLINT passed\n");
|
||||
if (!rs_ci_smoke_timer_one_shot()) {
|
||||
rs_test_finish(RS_TEST_FAILED, 3U);
|
||||
}
|
||||
printf("ci_smoke: timer0 passed\n");
|
||||
if (!rs_ci_smoke_timer_periodic()) {
|
||||
rs_test_finish(RS_TEST_FAILED, 4U);
|
||||
}
|
||||
printf("ci_smoke: timer1 passed\n");
|
||||
if (!rs_ci_smoke_gpio_v2()) {
|
||||
rs_test_finish(RS_TEST_FAILED, 5U);
|
||||
}
|
||||
|
||||
printf("ci_smoke: archinfo, CLINT, and timer tests passed\n");
|
||||
printf("ci_smoke: archinfo, CLINT, timer, and GPIO tests passed\n");
|
||||
rs_test_finish(RS_TEST_PASSED, 0U);
|
||||
return 0;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ int main(void) {
|
||||
(void)rs_shell_register("arch", "archinfo test", true, ip_archinfo_test);
|
||||
(void)rs_shell_register("ws2812", "ws2812 test", true, ip_ws2812_test);
|
||||
(void)rs_shell_register("tim", "timer test", true, rs_timer_shell_test);
|
||||
(void)rs_shell_register("gpio", "gpio test", true, ip_gpio_test);
|
||||
(void)rs_shell_register("gpio", "gpio test", true, rs_gpio_shell_test);
|
||||
(void)rs_shell_register("pwm", "pwm test", true, ip_pwm_test);
|
||||
(void)rs_shell_register("rtc", "rtc test", true, ip_rtc_test);
|
||||
(void)rs_shell_register("wdg", "wdg test", true, ip_wdg_test);
|
||||
|
||||
+11
-10
@@ -2,19 +2,20 @@
|
||||
|
||||
GCC = riscv32-unknown-elf-
|
||||
|
||||
AS = $(GCC)as
|
||||
LD = $(GCC)ld
|
||||
OBJDUMP = $(GCC)objdump
|
||||
OBJCOPY = $(GCC)objcopy
|
||||
AS_FLAGS = -fno-pic -march=rv32im -mabi=ilp32
|
||||
LDFLAGS = -T flash.ld -melf32lriscv
|
||||
APP ?= hello
|
||||
OUT_DIR ?= .
|
||||
APP_ALL = $(OUT_DIR)/$(APP)-asm
|
||||
AS = $(GCC)gcc
|
||||
LD = $(GCC)ld
|
||||
OBJDUMP = $(GCC)objdump
|
||||
OBJCOPY = $(GCC)objcopy
|
||||
AS_FLAGS = -x assembler-with-cpp -fno-pic -march=rv32im -mabi=ilp32
|
||||
GENERATED_INCLUDE ?= .
|
||||
LDFLAGS = -T flash.ld -melf32lriscv
|
||||
APP ?= hello
|
||||
OUT_DIR ?= .
|
||||
APP_ALL = $(OUT_DIR)/$(APP)-asm
|
||||
|
||||
all: $(APP).s
|
||||
@mkdir -p $(OUT_DIR)
|
||||
$(AS) $(AS_FLAGS) $(APP).s -o $(APP_ALL).o
|
||||
$(AS) $(AS_FLAGS) -I$(GENERATED_INCLUDE) -c $(APP).s -o $(APP_ALL).o
|
||||
$(LD) $(LDFLAGS) $(APP_ALL).o -o $(APP_ALL).elf
|
||||
$(OBJDUMP) -d $(APP_ALL).elf > $(APP_ALL).txt
|
||||
$(OBJCOPY) -S -O binary $(APP_ALL).elf $(APP_ALL).bin
|
||||
|
||||
+8
-6
@@ -1,3 +1,5 @@
|
||||
#include "retrosoc/generated/memory_map.h"
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
UART_INIT:
|
||||
@@ -30,17 +32,17 @@ CHECK:
|
||||
ble t1, t2, APP_LOOP
|
||||
|
||||
|
||||
.equ GPIO_IOFCFG, 0x10000028
|
||||
.equ GPIO_PINMUX, 0x1000002C
|
||||
.equ BIT_MASK, 0x3FE00000 # Bits 21 to 29 set to 1
|
||||
.equ PSRAM_INIT, 0x10004008
|
||||
.equ GPIO_ALT_ENABLE, RS_SOC_RIBP_GPIO_ADMIN_BASE + 0x34
|
||||
.equ GPIO_ALT_SELECT, RS_SOC_RIBP_GPIO_ADMIN_BASE + 0x38
|
||||
.equ BIT_MASK, 0x3FE00000 # Bits 21 to 29 set to 1
|
||||
.equ PSRAM_INIT, RS_SOC_RIBP_PSRAM_BASE + 0x08
|
||||
PINMUX_PSRAM:
|
||||
li t0, GPIO_IOFCFG
|
||||
li t0, GPIO_ALT_ENABLE
|
||||
lw t1, 0(t0)
|
||||
li t2, BIT_MASK
|
||||
or t1, t1, t2
|
||||
sw t1, 0(t0)
|
||||
li t0, GPIO_PINMUX
|
||||
li t0, GPIO_ALT_SELECT
|
||||
lw t1, 0(t0)
|
||||
or t1, t1, t2
|
||||
sw t1, 0(t0)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
.type _start,@function
|
||||
|
||||
#include "retrosoc/arch/riscv/system_csr.h"
|
||||
#include "retrosoc/generated/memory_map.h"
|
||||
|
||||
_start:
|
||||
#ifdef CSR_ENABLE
|
||||
@@ -68,18 +69,18 @@ wait_psram_reset:
|
||||
# test: using psram before loading
|
||||
|
||||
# Define the addresses
|
||||
.equ GPIO_IOFCFG, 0x10000028
|
||||
.equ GPIO_PINMUX, 0x1000002C
|
||||
.equ BIT_MASK, 0x3FE00000 # Bits 21 to 29 set to 1
|
||||
.equ PSRAM_INIT, 0x10004008
|
||||
.equ GPIO_ALT_ENABLE, RS_SOC_RIBP_GPIO_ADMIN_BASE + 0x34
|
||||
.equ GPIO_ALT_SELECT, RS_SOC_RIBP_GPIO_ADMIN_BASE + 0x38
|
||||
.equ BIT_MASK, 0x3FE00000 # Bits 21 to 29 set to 1
|
||||
.equ PSRAM_INIT, RS_SOC_RIBP_PSRAM_BASE + 0x08
|
||||
|
||||
PINMUX_PSRAM:
|
||||
li t0, GPIO_IOFCFG
|
||||
li t0, GPIO_ALT_ENABLE
|
||||
lw t1, 0(t0)
|
||||
li t2, BIT_MASK
|
||||
or t1, t1, t2
|
||||
sw t1, 0(t0)
|
||||
li t0, GPIO_PINMUX
|
||||
li t0, GPIO_ALT_SELECT
|
||||
lw t1, 0(t0)
|
||||
or t1, t1, t2
|
||||
sw t1, 0(t0)
|
||||
|
||||
@@ -31,22 +31,6 @@
|
||||
|
||||
#define RS_SOC_REG32(base, offset) (*(volatile uint32_t *)(uintptr_t)((base) + (offset)))
|
||||
|
||||
// gpio
|
||||
#define reg_gpio_oe RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x00))
|
||||
#define reg_gpio_cs RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x04))
|
||||
#define reg_gpio_pu RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x08))
|
||||
#define reg_gpio_pd RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x0C))
|
||||
#define reg_gpio_do RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x10))
|
||||
#define reg_gpio_di RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x14))
|
||||
#define reg_gpio_ien RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x18))
|
||||
#define reg_gpio_itype0 RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x1C))
|
||||
#define reg_gpio_itype1 RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x20))
|
||||
#define reg_gpio_istat RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x24))
|
||||
#define reg_gpio_iofcfg RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x28))
|
||||
#define reg_gpio_pinmux RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x2C))
|
||||
#define reg_gpio_user_sel RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x30))
|
||||
#define reg_gpio_user_lock RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x34))
|
||||
#define reg_gpio_user_status RS_SOC_REG32(RS_SOC_RIBP_GPIO_BASE, UINT32_C(0x38))
|
||||
// uart0
|
||||
#define reg_uart0_clkdiv RS_SOC_REG32(RS_SOC_RIBP_UART0_BASE, UINT32_C(0x00))
|
||||
#define reg_uart0_data RS_SOC_REG32(RS_SOC_RIBP_UART0_BASE, UINT32_C(0x04))
|
||||
|
||||
@@ -1,6 +1,91 @@
|
||||
#ifndef RETROSOC_GPIO_H
|
||||
#define RETROSOC_GPIO_H
|
||||
#ifndef RETROSOC_HAL_GPIO_H
|
||||
#define RETROSOC_HAL_GPIO_H
|
||||
|
||||
void ip_gpio_test(int argc, char **argv);
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/core/status.h>
|
||||
|
||||
#define RS_GPIO_PIN_COUNT 32U
|
||||
#define RS_GPIO_IRQ 18U
|
||||
|
||||
#define RS_GPIO_CAP_OPEN_DRAIN (UINT32_C(1) << 16U)
|
||||
#define RS_GPIO_CAP_FILTER (UINT32_C(1) << 17U)
|
||||
#define RS_GPIO_CAP_USER_HANDOFF (UINT32_C(1) << 18U)
|
||||
#define RS_GPIO_CAP_CONFIG_LOCK (UINT32_C(1) << 19U)
|
||||
#define RS_GPIO_CAP_ATOMIC_OUT (UINT32_C(1) << 20U)
|
||||
#define RS_GPIO_CAP_ATOMIC_OE (UINT32_C(1) << 21U)
|
||||
#define RS_GPIO_CAP_BOTH_EDGE_IRQ (UINT32_C(1) << 22U)
|
||||
|
||||
#define RS_GPIO_PAD_CAP_INPUT_CMOS (UINT32_C(1) << 0U)
|
||||
#define RS_GPIO_PAD_CAP_PULL_UP (UINT32_C(1) << 1U)
|
||||
#define RS_GPIO_PAD_CAP_PULL_DOWN (UINT32_C(1) << 2U)
|
||||
|
||||
typedef enum {
|
||||
RS_GPIO_MODE_INPUT = 0,
|
||||
RS_GPIO_MODE_OUTPUT = 1,
|
||||
RS_GPIO_MODE_ALT0 = 2,
|
||||
RS_GPIO_MODE_ALT1 = 3,
|
||||
RS_GPIO_MODE_USER_IP = 4,
|
||||
} rs_gpio_mode_t;
|
||||
|
||||
typedef enum {
|
||||
RS_GPIO_PULL_NONE = 0,
|
||||
RS_GPIO_PULL_UP = 1,
|
||||
RS_GPIO_PULL_DOWN = 2,
|
||||
} rs_gpio_pull_t;
|
||||
|
||||
typedef enum {
|
||||
RS_GPIO_TRIGGER_NONE = 0,
|
||||
RS_GPIO_TRIGGER_RISING = 1,
|
||||
RS_GPIO_TRIGGER_FALLING = 2,
|
||||
RS_GPIO_TRIGGER_BOTH = 3,
|
||||
RS_GPIO_TRIGGER_HIGH = 4,
|
||||
RS_GPIO_TRIGGER_LOW = 5,
|
||||
} rs_gpio_trigger_t;
|
||||
|
||||
typedef struct {
|
||||
rs_gpio_mode_t mode;
|
||||
rs_gpio_pull_t pull;
|
||||
rs_gpio_trigger_t trigger;
|
||||
bool output_high;
|
||||
bool open_drain;
|
||||
bool input_cmos;
|
||||
bool filter_enable;
|
||||
bool interrupt_enable;
|
||||
} rs_gpio_config_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t divider;
|
||||
uint8_t stable_samples;
|
||||
} rs_gpio_filter_timing_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
uint32_t features;
|
||||
uint32_t pad_features;
|
||||
} rs_gpio_capabilities_t;
|
||||
|
||||
rs_status_t rs_gpio_filter_timing_from_us(uint32_t source_clock_hz, uint32_t sample_period_us,
|
||||
uint8_t stable_samples, rs_gpio_filter_timing_t *timing);
|
||||
rs_status_t rs_gpio_get_capabilities(rs_gpio_capabilities_t *capabilities);
|
||||
rs_status_t rs_gpio_configure(uint32_t pin, const rs_gpio_config_t *config);
|
||||
rs_status_t rs_gpio_read(uint32_t pin, bool *high);
|
||||
rs_status_t rs_gpio_write(uint32_t pin, bool high);
|
||||
rs_status_t rs_gpio_toggle(uint32_t pin);
|
||||
rs_status_t rs_gpio_port_read(uint32_t *value);
|
||||
rs_status_t rs_gpio_port_set(uint32_t mask);
|
||||
rs_status_t rs_gpio_port_clear(uint32_t mask);
|
||||
rs_status_t rs_gpio_port_toggle(uint32_t mask);
|
||||
rs_status_t rs_gpio_interrupt_state(uint32_t *state);
|
||||
rs_status_t rs_gpio_interrupt_enable(uint32_t mask, bool enable);
|
||||
rs_status_t rs_gpio_interrupt_clear(uint32_t mask);
|
||||
rs_status_t rs_gpio_interrupt_test(uint32_t mask);
|
||||
rs_status_t rs_gpio_filter_configure(uint32_t enable_mask, const rs_gpio_filter_timing_t *timing);
|
||||
rs_status_t rs_gpio_user_access_set(uint32_t mask);
|
||||
rs_status_t rs_gpio_user_ip_select(uint32_t mask, bool enable);
|
||||
rs_status_t rs_gpio_user_ip_lock(uint32_t mask);
|
||||
rs_status_t rs_gpio_configuration_lock(uint32_t mask);
|
||||
void rs_gpio_shell_test(int argc, char **argv);
|
||||
|
||||
#endif
|
||||
@@ -3,9 +3,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define lcd_dc_clr (reg_gpio_do = (uint32_t)0b000)
|
||||
#define lcd_dc_set (reg_gpio_do = (uint32_t)0b100)
|
||||
|
||||
#define USE_HORIZONTAL 2
|
||||
|
||||
#if USE_HORIZONTAL == 0 || USE_HORIZONTAL == 1
|
||||
|
||||
+261
-50
@@ -1,60 +1,271 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/lib/printf.h>
|
||||
#include <retrosoc/hal/timer.h>
|
||||
#include <retrosoc/hal/gpio.h>
|
||||
#include <retrosoc/hal/timer.h>
|
||||
#include <retrosoc/lib/printf.h>
|
||||
|
||||
void ip_gpio_test(int argc, char **argv) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
#define RS_GPIO_DATA_IN_OFFSET UINT32_C(0x000)
|
||||
#define RS_GPIO_DATA_OUT_OFFSET UINT32_C(0x004)
|
||||
#define RS_GPIO_OUT_SET_OFFSET UINT32_C(0x008)
|
||||
#define RS_GPIO_OUT_CLEAR_OFFSET UINT32_C(0x00C)
|
||||
#define RS_GPIO_OUT_TOGGLE_OFFSET UINT32_C(0x010)
|
||||
#define RS_GPIO_OUTPUT_ENABLE_OFFSET UINT32_C(0x014)
|
||||
#define RS_GPIO_OE_SET_OFFSET UINT32_C(0x018)
|
||||
#define RS_GPIO_OE_CLEAR_OFFSET UINT32_C(0x01C)
|
||||
#define RS_GPIO_OPEN_DRAIN_OFFSET UINT32_C(0x024)
|
||||
#define RS_GPIO_INPUT_CMOS_OFFSET UINT32_C(0x028)
|
||||
#define RS_GPIO_PULL_UP_OFFSET UINT32_C(0x02C)
|
||||
#define RS_GPIO_PULL_DOWN_OFFSET UINT32_C(0x030)
|
||||
#define RS_GPIO_ALT_ENABLE_OFFSET UINT32_C(0x034)
|
||||
#define RS_GPIO_ALT_SELECT_OFFSET UINT32_C(0x038)
|
||||
#define RS_GPIO_USER_SELECT_OFFSET UINT32_C(0x03C)
|
||||
#define RS_GPIO_USER_LOCK_OFFSET UINT32_C(0x040)
|
||||
#define RS_GPIO_USER_ACCESS_MASK_OFFSET UINT32_C(0x048)
|
||||
#define RS_GPIO_INTR_RISE_ENABLE_OFFSET UINT32_C(0x04C)
|
||||
#define RS_GPIO_INTR_FALL_ENABLE_OFFSET UINT32_C(0x050)
|
||||
#define RS_GPIO_INTR_HIGH_ENABLE_OFFSET UINT32_C(0x054)
|
||||
#define RS_GPIO_INTR_LOW_ENABLE_OFFSET UINT32_C(0x058)
|
||||
#define RS_GPIO_INTR_ENABLE_OFFSET UINT32_C(0x05C)
|
||||
#define RS_GPIO_INTR_STATE_OFFSET UINT32_C(0x060)
|
||||
#define RS_GPIO_INTR_TEST_OFFSET UINT32_C(0x068)
|
||||
#define RS_GPIO_FILTER_ENABLE_OFFSET UINT32_C(0x06C)
|
||||
#define RS_GPIO_FILTER_DIV_OFFSET UINT32_C(0x070)
|
||||
#define RS_GPIO_FILTER_COUNT_OFFSET UINT32_C(0x074)
|
||||
#define RS_GPIO_CONFIG_LOCK_OFFSET UINT32_C(0x078)
|
||||
#define RS_GPIO_PAD_CAPABILITY_OFFSET UINT32_C(0x0F4)
|
||||
#define RS_GPIO_IP_VERSION_OFFSET UINT32_C(0x0F8)
|
||||
#define RS_GPIO_CAPABILITY_OFFSET UINT32_C(0x0FC)
|
||||
|
||||
printf("[RIB IP] gpio test\n");
|
||||
#define RS_GPIO_REG(offset) RS_SOC_REG32(RS_SOC_RIBP_GPIO_ADMIN_BASE, (offset))
|
||||
|
||||
printf("[GPIO OE] %x\n", reg_gpio_oe);
|
||||
reg_gpio_oe = (uint32_t)0b1111;
|
||||
printf("[GPIO OE] %x\n", reg_gpio_oe);
|
||||
static void rs_gpio_update_bits(uint32_t offset, uint32_t mask, bool set) {
|
||||
uint32_t value = RS_GPIO_REG(offset);
|
||||
|
||||
printf("[GPIO DATA] %x\n", reg_gpio_do);
|
||||
reg_gpio_do = (uint32_t)0xffff;
|
||||
printf("[GPIO DATA] %x\n", reg_gpio_do);
|
||||
|
||||
reg_gpio_do = (uint32_t)0x0000;
|
||||
printf("[GPIO DATA] %x\n", reg_gpio_do);
|
||||
|
||||
printf("led output test\n");
|
||||
for (int i = 0; i < 50; ++i) {
|
||||
if (rs_timer_delay_ms(RS_TIMER_0, 300U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
|
||||
printf("timer delay failed\n");
|
||||
return;
|
||||
}
|
||||
if (reg_gpio_do == 0b00)
|
||||
reg_gpio_do = (uint32_t)0b01;
|
||||
else
|
||||
reg_gpio_do = (uint32_t)0b00;
|
||||
if (set) {
|
||||
value |= mask;
|
||||
} else {
|
||||
value &= ~mask;
|
||||
}
|
||||
RS_GPIO_REG(offset) = value;
|
||||
}
|
||||
|
||||
reg_gpio_do = (uint32_t)0b00;
|
||||
printf("key input test\n"); // need extn board
|
||||
reg_gpio_oe = (uint32_t)0b1101;
|
||||
printf("[GPIO OE] %x\n", reg_gpio_oe);
|
||||
printf("[GPIO DATA] %x\n", reg_gpio_do);
|
||||
return;
|
||||
for (int i = 0; i < 60; ++i) {
|
||||
uint32_t led_val = 0b00;
|
||||
if (((reg_gpio_do & 0b10) >> 1) == 0b0) {
|
||||
if (rs_timer_delay_ms(RS_TIMER_0, 100U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
|
||||
printf("timer delay failed\n");
|
||||
return;
|
||||
}
|
||||
if (((reg_gpio_do & 0b10) >> 1) == 0b0) {
|
||||
printf("key detect\n");
|
||||
if (led_val == 0b00) {
|
||||
led_val = 0b01;
|
||||
reg_gpio_do = led_val;
|
||||
} else {
|
||||
led_val = 0b00;
|
||||
reg_gpio_do = led_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
static bool rs_gpio_config_valid(const rs_gpio_config_t *config) {
|
||||
return (config != NULL) && (config->mode <= RS_GPIO_MODE_USER_IP) &&
|
||||
(config->pull <= RS_GPIO_PULL_DOWN) && (config->trigger <= RS_GPIO_TRIGGER_LOW);
|
||||
}
|
||||
|
||||
static rs_status_t rs_gpio_check_pad_capabilities(const rs_gpio_config_t *config) {
|
||||
const uint32_t capability = RS_GPIO_REG(RS_GPIO_PAD_CAPABILITY_OFFSET);
|
||||
|
||||
if ((config->input_cmos && ((capability & RS_GPIO_PAD_CAP_INPUT_CMOS) == 0U)) ||
|
||||
((config->pull == RS_GPIO_PULL_UP) && ((capability & RS_GPIO_PAD_CAP_PULL_UP) == 0U)) ||
|
||||
((config->pull == RS_GPIO_PULL_DOWN) && ((capability & RS_GPIO_PAD_CAP_PULL_DOWN) == 0U))) {
|
||||
return RS_ENOTSUP;
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
static void rs_gpio_configure_trigger(uint32_t mask, rs_gpio_trigger_t trigger) {
|
||||
rs_gpio_update_bits(RS_GPIO_INTR_RISE_ENABLE_OFFSET, mask, false);
|
||||
rs_gpio_update_bits(RS_GPIO_INTR_FALL_ENABLE_OFFSET, mask, false);
|
||||
rs_gpio_update_bits(RS_GPIO_INTR_HIGH_ENABLE_OFFSET, mask, false);
|
||||
rs_gpio_update_bits(RS_GPIO_INTR_LOW_ENABLE_OFFSET, mask, false);
|
||||
if ((trigger == RS_GPIO_TRIGGER_RISING) || (trigger == RS_GPIO_TRIGGER_BOTH)) {
|
||||
rs_gpio_update_bits(RS_GPIO_INTR_RISE_ENABLE_OFFSET, mask, true);
|
||||
}
|
||||
if ((trigger == RS_GPIO_TRIGGER_FALLING) || (trigger == RS_GPIO_TRIGGER_BOTH)) {
|
||||
rs_gpio_update_bits(RS_GPIO_INTR_FALL_ENABLE_OFFSET, mask, true);
|
||||
}
|
||||
if (trigger == RS_GPIO_TRIGGER_HIGH) {
|
||||
rs_gpio_update_bits(RS_GPIO_INTR_HIGH_ENABLE_OFFSET, mask, true);
|
||||
}
|
||||
if (trigger == RS_GPIO_TRIGGER_LOW) {
|
||||
rs_gpio_update_bits(RS_GPIO_INTR_LOW_ENABLE_OFFSET, mask, true);
|
||||
}
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_get_capabilities(rs_gpio_capabilities_t *capabilities) {
|
||||
if (capabilities == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
capabilities->version = RS_GPIO_REG(RS_GPIO_IP_VERSION_OFFSET);
|
||||
capabilities->features = RS_GPIO_REG(RS_GPIO_CAPABILITY_OFFSET);
|
||||
capabilities->pad_features = RS_GPIO_REG(RS_GPIO_PAD_CAPABILITY_OFFSET);
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_configure(uint32_t pin, const rs_gpio_config_t *config) {
|
||||
uint32_t mask;
|
||||
rs_status_t status;
|
||||
|
||||
if ((pin >= RS_GPIO_PIN_COUNT) || !rs_gpio_config_valid(config)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
status = rs_gpio_check_pad_capabilities(config);
|
||||
if (status != RS_OK) {
|
||||
return status;
|
||||
}
|
||||
mask = UINT32_C(1) << pin;
|
||||
|
||||
RS_GPIO_REG(config->output_high ? RS_GPIO_OUT_SET_OFFSET : RS_GPIO_OUT_CLEAR_OFFSET) = mask;
|
||||
rs_gpio_update_bits(RS_GPIO_OPEN_DRAIN_OFFSET, mask, config->open_drain);
|
||||
rs_gpio_update_bits(RS_GPIO_INPUT_CMOS_OFFSET, mask, config->input_cmos);
|
||||
rs_gpio_update_bits(RS_GPIO_PULL_UP_OFFSET, mask, false);
|
||||
rs_gpio_update_bits(RS_GPIO_PULL_DOWN_OFFSET, mask, false);
|
||||
if (config->pull == RS_GPIO_PULL_UP) {
|
||||
rs_gpio_update_bits(RS_GPIO_PULL_UP_OFFSET, mask, true);
|
||||
} else if (config->pull == RS_GPIO_PULL_DOWN) {
|
||||
rs_gpio_update_bits(RS_GPIO_PULL_DOWN_OFFSET, mask, true);
|
||||
} else {
|
||||
/* No pull requested. */
|
||||
}
|
||||
|
||||
rs_gpio_configure_trigger(mask, config->trigger);
|
||||
rs_gpio_update_bits(RS_GPIO_FILTER_ENABLE_OFFSET, mask, config->filter_enable);
|
||||
rs_gpio_update_bits(RS_GPIO_INTR_ENABLE_OFFSET, mask, config->interrupt_enable);
|
||||
|
||||
rs_gpio_update_bits(RS_GPIO_USER_SELECT_OFFSET, mask, config->mode == RS_GPIO_MODE_USER_IP);
|
||||
rs_gpio_update_bits(RS_GPIO_ALT_SELECT_OFFSET, mask, config->mode == RS_GPIO_MODE_ALT1);
|
||||
rs_gpio_update_bits(RS_GPIO_ALT_ENABLE_OFFSET, mask,
|
||||
(config->mode == RS_GPIO_MODE_ALT0) || (config->mode == RS_GPIO_MODE_ALT1));
|
||||
|
||||
if (config->mode == RS_GPIO_MODE_OUTPUT) {
|
||||
RS_GPIO_REG(RS_GPIO_OE_SET_OFFSET) = mask;
|
||||
} else {
|
||||
RS_GPIO_REG(RS_GPIO_OE_CLEAR_OFFSET) = mask;
|
||||
}
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_read(uint32_t pin, bool *high) {
|
||||
if ((pin >= RS_GPIO_PIN_COUNT) || (high == NULL)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
*high = (RS_GPIO_REG(RS_GPIO_DATA_IN_OFFSET) & (UINT32_C(1) << pin)) != 0U;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_write(uint32_t pin, bool high) {
|
||||
if (pin >= RS_GPIO_PIN_COUNT) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
RS_GPIO_REG(high ? RS_GPIO_OUT_SET_OFFSET : RS_GPIO_OUT_CLEAR_OFFSET) = UINT32_C(1) << pin;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_toggle(uint32_t pin) {
|
||||
if (pin >= RS_GPIO_PIN_COUNT) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
RS_GPIO_REG(RS_GPIO_OUT_TOGGLE_OFFSET) = UINT32_C(1) << pin;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_port_read(uint32_t *value) {
|
||||
if (value == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
*value = RS_GPIO_REG(RS_GPIO_DATA_IN_OFFSET);
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_port_set(uint32_t mask) {
|
||||
RS_GPIO_REG(RS_GPIO_OUT_SET_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_port_clear(uint32_t mask) {
|
||||
RS_GPIO_REG(RS_GPIO_OUT_CLEAR_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_port_toggle(uint32_t mask) {
|
||||
RS_GPIO_REG(RS_GPIO_OUT_TOGGLE_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_interrupt_state(uint32_t *state) {
|
||||
if (state == NULL) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
*state = RS_GPIO_REG(RS_GPIO_INTR_STATE_OFFSET);
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_interrupt_enable(uint32_t mask, bool enable) {
|
||||
rs_gpio_update_bits(RS_GPIO_INTR_ENABLE_OFFSET, mask, enable);
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_interrupt_clear(uint32_t mask) {
|
||||
RS_GPIO_REG(RS_GPIO_INTR_STATE_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_interrupt_test(uint32_t mask) {
|
||||
RS_GPIO_REG(RS_GPIO_INTR_TEST_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_filter_configure(uint32_t enable_mask, const rs_gpio_filter_timing_t *timing) {
|
||||
if ((timing == NULL) || (timing->stable_samples == 0U) || (timing->stable_samples > 15U)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
RS_GPIO_REG(RS_GPIO_FILTER_ENABLE_OFFSET) = 0U;
|
||||
RS_GPIO_REG(RS_GPIO_FILTER_DIV_OFFSET) = timing->divider;
|
||||
RS_GPIO_REG(RS_GPIO_FILTER_COUNT_OFFSET) = timing->stable_samples;
|
||||
RS_GPIO_REG(RS_GPIO_FILTER_ENABLE_OFFSET) = enable_mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_user_access_set(uint32_t mask) {
|
||||
RS_GPIO_REG(RS_GPIO_USER_ACCESS_MASK_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_user_ip_select(uint32_t mask, bool enable) {
|
||||
rs_gpio_update_bits(RS_GPIO_USER_SELECT_OFFSET, mask, enable);
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_user_ip_lock(uint32_t mask) {
|
||||
RS_GPIO_REG(RS_GPIO_USER_LOCK_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
rs_status_t rs_gpio_configuration_lock(uint32_t mask) {
|
||||
RS_GPIO_REG(RS_GPIO_CONFIG_LOCK_OFFSET) = mask;
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
void rs_gpio_shell_test(int argc, char **argv) {
|
||||
const rs_gpio_config_t config = {
|
||||
RS_GPIO_MODE_OUTPUT,
|
||||
RS_GPIO_PULL_NONE,
|
||||
RS_GPIO_TRIGGER_NONE,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
};
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
printf("gpio test\n");
|
||||
if (rs_gpio_configure(0U, &config) != RS_OK) {
|
||||
printf("gpio configuration failed\n");
|
||||
return;
|
||||
}
|
||||
for (uint32_t iteration = 0U; iteration < 10U; ++iteration) {
|
||||
(void)rs_gpio_toggle(0U);
|
||||
if (rs_timer_delay_ms(RS_TIMER_0, 300U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) {
|
||||
printf("gpio timer delay failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
(void)rs_gpio_write(0U, false);
|
||||
printf("gpio test passed\n");
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <retrosoc/hal/gpio.h>
|
||||
|
||||
#define RS_GPIO_MICROSECONDS_PER_SECOND UINT64_C(1000000)
|
||||
#define RS_GPIO_MAX_SAMPLE_CYCLES UINT64_C(65536)
|
||||
|
||||
rs_status_t rs_gpio_filter_timing_from_us(uint32_t source_clock_hz, uint32_t sample_period_us,
|
||||
uint8_t stable_samples, rs_gpio_filter_timing_t *timing) {
|
||||
uint64_t product;
|
||||
uint64_t cycles;
|
||||
|
||||
if ((source_clock_hz == 0U) || (sample_period_us == 0U) || (stable_samples == 0U) ||
|
||||
(stable_samples > 15U) || (timing == NULL)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
product = (uint64_t)source_clock_hz * (uint64_t)sample_period_us;
|
||||
cycles = (product + RS_GPIO_MICROSECONDS_PER_SECOND - 1U) / RS_GPIO_MICROSECONDS_PER_SECOND;
|
||||
if ((cycles == 0U) || (cycles > RS_GPIO_MAX_SAMPLE_CYCLES)) {
|
||||
return RS_EINVAL;
|
||||
}
|
||||
timing->divider = (uint16_t)(cycles - 1U);
|
||||
timing->stable_samples = stable_samples;
|
||||
return RS_OK;
|
||||
}
|
||||
+5
-5
@@ -55,22 +55,22 @@ static bool rs_lcd_region_valid(uint16_t x_start, uint16_t y_start, uint16_t x_e
|
||||
}
|
||||
|
||||
static void lcd_wr_dc_cmd(uint8_t cmd) {
|
||||
lcd_dc_clr;
|
||||
(void)rs_gpio_port_clear(UINT32_C(1) << 2U);
|
||||
qspi0_wr_dat8(cmd);
|
||||
}
|
||||
|
||||
static void lcd_wr_dc_data8(uint8_t dat) {
|
||||
lcd_dc_set;
|
||||
(void)rs_gpio_port_set(UINT32_C(1) << 2U);
|
||||
qspi0_wr_dat8(dat);
|
||||
}
|
||||
|
||||
static void lcd_wr_dc_data16(uint16_t dat) {
|
||||
lcd_dc_set;
|
||||
(void)rs_gpio_port_set(UINT32_C(1) << 2U);
|
||||
qspi0_wr_dat16(dat);
|
||||
}
|
||||
|
||||
static void lcd_wr_data32(uint32_t *dat, uint32_t len) {
|
||||
lcd_dc_set;
|
||||
(void)rs_gpio_port_set(UINT32_C(1) << 2U);
|
||||
qspi0_wr_data32(dat, len);
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ void lcd_fill_image(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend,
|
||||
uint32_t total_pixels = (uint32_t)(xend - xsta) * (uint32_t)(yend - ysta);
|
||||
|
||||
#ifdef USE_QSPI0_DMA
|
||||
lcd_dc_set;
|
||||
(void)rs_gpio_port_set(UINT32_C(1) << 2U);
|
||||
uintptr_t addr = (uintptr_t)data;
|
||||
// printf("addr: %x\n\n", addr);
|
||||
qspi0_dma_xfer(addr, total_pixels / 2U); // every xfer contains two RGB565 pixels
|
||||
|
||||
+13
-1
@@ -1,5 +1,6 @@
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/core/wait.h>
|
||||
#include <retrosoc/hal/gpio.h>
|
||||
#include <retrosoc/hal/timer.h>
|
||||
#include <retrosoc/hal/qspi.h>
|
||||
#include <retrosoc/hal/dma.h>
|
||||
@@ -16,7 +17,18 @@ static bool rs_qspi_wait(uint32_t mask, uint32_t expected) {
|
||||
}
|
||||
|
||||
void qspi0_init(QSPI0_InitStruct_t val) {
|
||||
reg_gpio_oe = (uint32_t)0b100;
|
||||
const rs_gpio_config_t gpio_config = {
|
||||
.mode = RS_GPIO_MODE_OUTPUT,
|
||||
.pull = RS_GPIO_PULL_NONE,
|
||||
.trigger = RS_GPIO_TRIGGER_NONE,
|
||||
.output_high = false,
|
||||
.open_drain = false,
|
||||
.input_cmos = false,
|
||||
.filter_enable = false,
|
||||
.interrupt_enable = false,
|
||||
};
|
||||
|
||||
(void)rs_gpio_configure(2U, &gpio_config);
|
||||
reg_xpi_mode = val.mode;
|
||||
reg_xpi_nss = val.nss;
|
||||
reg_xpi_clkdiv = val.clkdiv;
|
||||
|
||||
+12
-6
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <retrosoc/core/soc.h>
|
||||
#include <retrosoc/hal/dma.h>
|
||||
#include <retrosoc/hal/gpio.h>
|
||||
#include <retrosoc/hal/ws2812.h>
|
||||
#include <retrosoc/lib/printf.h>
|
||||
|
||||
@@ -18,8 +19,6 @@
|
||||
#define RS_WS2812_IP_FIFO_DEPTH_MASK UINT32_C(0xFF)
|
||||
#define RS_WS2812_PIXEL_MASK UINT32_C(0x00FFFFFF)
|
||||
#define RS_WS2812_DMA_SOFTWARE_MODE UINT32_C(0)
|
||||
#define RS_WS2812_GPIO_MASK (UINT32_C(1) << 2U)
|
||||
|
||||
static uint32_t rs_ws2812_fifo_depth(void) {
|
||||
return (reg_ws2812_ip_info >> RS_WS2812_IP_FIFO_DEPTH_SHIFT) & RS_WS2812_IP_FIFO_DEPTH_MASK;
|
||||
}
|
||||
@@ -253,14 +252,21 @@ void ip_ws2812_test(int argc, char **argv) {
|
||||
rs_ws2812_pack_grb(0x00U, 0x00U, 0x20U),
|
||||
rs_ws2812_pack_grb(0x10U, 0x10U, 0x10U),
|
||||
};
|
||||
const rs_gpio_config_t gpio_config = {
|
||||
.mode = RS_GPIO_MODE_ALT1,
|
||||
.pull = RS_GPIO_PULL_NONE,
|
||||
.trigger = RS_GPIO_TRIGGER_NONE,
|
||||
.output_high = false,
|
||||
.open_drain = false,
|
||||
.input_cmos = false,
|
||||
.filter_enable = false,
|
||||
.interrupt_enable = false,
|
||||
};
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
printf("ws2812 test\n");
|
||||
reg_gpio_user_sel &= ~RS_WS2812_GPIO_MASK;
|
||||
reg_gpio_pinmux |= RS_WS2812_GPIO_MASK;
|
||||
reg_gpio_iofcfg |= RS_WS2812_GPIO_MASK;
|
||||
if ((rs_ws2812_init(&config) != RS_OK) ||
|
||||
if ((rs_gpio_configure(2U, &gpio_config) != RS_OK) || (rs_ws2812_init(&config) != RS_OK) ||
|
||||
(rs_ws2812_write(pixels, sizeof(pixels) / sizeof(pixels[0]), RS_TIMEOUT_DEFAULT) !=
|
||||
RS_OK)) {
|
||||
printf("ws2812 transfer failed\n");
|
||||
|
||||
@@ -95,7 +95,8 @@ void rs_app_info(void) {
|
||||
TF_CARD_START + TF_CARD_OFFST - 1, TF_CARD_OFFST / 1024 / 1024 / 1024);
|
||||
|
||||
printf("Memory Map IO Device:\n");
|
||||
printf(" 1 x GPIO(32PIN) @%p\n", (void *)®_gpio_oe);
|
||||
printf(" 1 x GPIO(32PIN) @%p\n",
|
||||
(void *)(uintptr_t)RS_SOC_RIBP_GPIO_ADMIN_BASE);
|
||||
printf(" 1 x UART0 @%p\n", (void *)®_uart0_clkdiv);
|
||||
printf(" 2 x TIMER(0,1) @%p,%p\n",
|
||||
(void *)(uintptr_t)RS_SOC_RIBP_TIM0_BASE, (void *)(uintptr_t)RS_SOC_RIBP_TIM1_BASE);
|
||||
|
||||
@@ -26,6 +26,8 @@ the root README and subsystem guides.
|
||||
counting modes, interrupt, debug-freeze, HAL, and verification contracts.
|
||||
- [ip/clint.md](ip/clint.md) defines the standard CLINT register map, fixed
|
||||
timebase, RV32 access rules, interrupt behavior, and verification contract.
|
||||
- [ip/gpio.md](ip/gpio.md) defines the GPIO V2 dual-window ABI, pad ownership,
|
||||
filtering, interrupts, PDK capabilities, HAL, and verification contract.
|
||||
- [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
|
||||
|
||||
+5
-4
@@ -130,14 +130,15 @@ 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_user`, and `ws2812`; each uses the SBY `prove` task for bounded model
|
||||
targets are `bus`, `rib_adapter`, `rib2apb`, `sysctrl`, `pll_rcu`, `gpio`,
|
||||
and `ws2812`; 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
|
||||
handling, and fault reporting. `pll_rcu` checks the clock-switch controller
|
||||
state machine. `gpio_user` checks fixed user-GPIO ownership, lock, handoff,
|
||||
and mux safety. `rib_adapter` checks both single-word compatibility adapters
|
||||
state machine. `gpio` checks dual-window access isolation, fixed user-GPIO
|
||||
ownership, locks, handoff, open-drain safety, and mux behavior. `rib_adapter`
|
||||
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. Direct Common utility proofs, including `spill_register`,
|
||||
|
||||
@@ -6,6 +6,7 @@ verification documentation for self-owned retroSoC peripheral IP.
|
||||
- [timer.md](timer.md) defines the dual RIBP general timer.
|
||||
- [ws2812.md](ws2812.md) defines the WS2812 transmitter.
|
||||
- [clint.md](clint.md) defines the management-hart software and timer interrupt block.
|
||||
- [gpio.md](gpio.md) defines the dual-window GPIO controller.
|
||||
|
||||
The corresponding RTL and HAL implementations remain the executable sources
|
||||
of truth. Update the affected document whenever an IP interface or register ABI
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
# GPIO Controller
|
||||
|
||||
The Mini SoC GPIO V2 block controls 32 bidirectional pads. It provides
|
||||
software, alternate-function, and user-IP ownership modes, atomic output and
|
||||
output-enable commands, open-drain operation, synchronized and optionally
|
||||
filtered inputs, per-pin interrupts, irreversible configuration locks, and
|
||||
capability discovery. The register ABI is directly encoded in RTL and C; a
|
||||
register generator is intentionally not used in this version.
|
||||
|
||||
## Integration
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| User-core RIBP window | `0x10000000`, user access `rw` |
|
||||
| Management RIBP window | `0x10014000`, user access `none` |
|
||||
| Pins | 32 |
|
||||
| RIBP interrupt group | Bit 11 |
|
||||
| Core interrupt | 18 |
|
||||
| Input synchronizer | Two stages in the SoC clock domain |
|
||||
| ABI version | `0x00020000` |
|
||||
|
||||
The two windows reach one register block. The user window exposes only data
|
||||
and interrupt operations selected by `USER_ACCESS_MASK`; this mask resets to
|
||||
zero. The management window owns pin mode, pad controls, filters, interrupt
|
||||
trigger configuration, user-IP handoff, access policy, and locks. The existing
|
||||
SoC bus firewall rejects user-core transactions to the management window, so
|
||||
the peripheral does not infer privilege from request timing or address alone.
|
||||
|
||||
## User window
|
||||
|
||||
All registers are 32 bits and naturally aligned. Unmapped, unaligned, and
|
||||
direction-invalid accesses complete with `resp_err`. User data returned from
|
||||
the block is ANDed with `USER_ACCESS_MASK`; writes can affect only mask bits
|
||||
that are one.
|
||||
|
||||
| Offset | Name | Access | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `0x000` | `DATA_IN` | RO | Synchronized and filtered pin inputs. |
|
||||
| `0x004` | `DATA_OUT` | RW | Software output latch. |
|
||||
| `0x008` | `OUT_SET` | WO | Atomically set output-latch bits. |
|
||||
| `0x00C` | `OUT_CLEAR` | WO | Atomically clear output-latch bits. |
|
||||
| `0x010` | `OUT_TOGGLE` | WO | Atomically toggle output-latch bits. |
|
||||
| `0x014` | `INTR_STATE` | RW1C | Sticky raw interrupt state. |
|
||||
| `0x018` | `INTR_STATUS` | RO | `INTR_STATE & INTR_ENABLE`. |
|
||||
| `0x01C` | `INTR_ENABLE` | RW | Per-pin interrupt enable. |
|
||||
| `0x020` | `INTR_ENABLE_SET` | WO | Atomically set interrupt-enable bits. |
|
||||
| `0x024` | `INTR_ENABLE_CLEAR` | WO | Atomically clear interrupt-enable bits. |
|
||||
| `0x0F8` | `IP_VERSION` | RO | ABI version. |
|
||||
| `0x0FC` | `CAPABILITY` | RO | Implemented digital feature summary. |
|
||||
|
||||
## Management window
|
||||
|
||||
| Offset | Name | Access | Reset | Description |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `0x000` | `DATA_IN` | RO | `0` | Synchronized and filtered inputs. |
|
||||
| `0x004` | `DATA_OUT` | RW | `0` | Software output latch. |
|
||||
| `0x008` | `OUT_SET` | WO | - | Atomic output set. |
|
||||
| `0x00C` | `OUT_CLEAR` | WO | - | Atomic output clear. |
|
||||
| `0x010` | `OUT_TOGGLE` | WO | - | Atomic output toggle. |
|
||||
| `0x014` | `OUTPUT_ENABLE` | RW | `0` | Software output-enable latch. |
|
||||
| `0x018` | `OE_SET` | WO | - | Atomic output-enable set. |
|
||||
| `0x01C` | `OE_CLEAR` | WO | - | Atomic output-enable clear. |
|
||||
| `0x020` | `OE_TOGGLE` | WO | - | Atomic output-enable toggle. |
|
||||
| `0x024` | `OPEN_DRAIN` | RW | `0` | Drive zero for output low and release for output high. |
|
||||
| `0x028` | `INPUT_CMOS` | RW | `0` | Select the PDK CMOS input characteristic when supported. |
|
||||
| `0x02C` | `PULL_UP` | RW | `0` | Enable pad pull-up when supported. |
|
||||
| `0x030` | `PULL_DOWN` | RW | `0` | Enable pad pull-down when supported. |
|
||||
| `0x034` | `ALT_ENABLE` | RW | `0` | Select an alternate function instead of software output. |
|
||||
| `0x038` | `ALT_SELECT` | RW | `0` | Select ALT1 when set and ALT0 when clear. |
|
||||
| `0x03C` | `USER_SELECT` | RW | `0` | Select user-IP pad ownership. |
|
||||
| `0x040` | `USER_LOCK` | W1S/RO | `0` | Permanently lock `USER_SELECT` bits until reset. |
|
||||
| `0x044` | `USER_STATUS` | RO | `0` | Active user ownership after the handoff guard cycle. |
|
||||
| `0x048` | `USER_ACCESS_MASK` | RW | `0` | Permit user-window data and interrupt bits. |
|
||||
| `0x04C` | `INTR_RISE_ENABLE` | RW | `0` | Rising-edge event selection. |
|
||||
| `0x050` | `INTR_FALL_ENABLE` | RW | `0` | Falling-edge event selection. |
|
||||
| `0x054` | `INTR_HIGH_ENABLE` | RW | `0` | High-level event selection. |
|
||||
| `0x058` | `INTR_LOW_ENABLE` | RW | `0` | Low-level event selection. |
|
||||
| `0x05C` | `INTR_ENABLE` | RW | `0` | Per-pin interrupt output enable. |
|
||||
| `0x060` | `INTR_STATE` | RW1C | `0` | Sticky raw interrupt state. Events win over clear. |
|
||||
| `0x064` | `INTR_STATUS` | RO | `0` | Enabled interrupt state. |
|
||||
| `0x068` | `INTR_TEST` | WO | - | Write-one software interrupt test. |
|
||||
| `0x06C` | `FILTER_ENABLE` | RW | `0` | Enable the digital stability filter per pin. |
|
||||
| `0x070` | `FILTER_DIV` | RW | `0` | Sample every `FILTER_DIV + 1` clocks. |
|
||||
| `0x074` | `FILTER_COUNT` | RW | `0` | Required stable samples, valid range 1 through 15. |
|
||||
| `0x078` | `CONFIG_LOCK` | W1S/RO | `0` | Permanently lock per-pin configuration until reset. |
|
||||
| `0x0F4` | `PAD_CAPABILITY` | RO | PDK-specific | CMOS, pull-up, and pull-down support. |
|
||||
| `0x0F8` | `IP_VERSION` | RO | `0x00020000` | ABI version 2.0. |
|
||||
| `0x0FC` | `CAPABILITY` | RO | `0x007F4220` | Digital feature, filter width, ABI, and pin count. |
|
||||
|
||||
`CONFIG_LOCK` protects output enable, open-drain, input mode, pulls, alternate
|
||||
selection, user access, interrupt trigger selection, and filter enable.
|
||||
`USER_LOCK` independently protects user-IP ownership. Both are write-one-set
|
||||
and clear only on peripheral reset. Writes that request an unsupported pad
|
||||
feature, simultaneous pull-up and pull-down, conflicting edge and level
|
||||
triggers, a zero filter count, a timing change while any filter is active, or
|
||||
a change to a locked bit complete with `resp_err` and do not update state.
|
||||
|
||||
## Pin and interrupt behavior
|
||||
|
||||
Software output and output-enable aliases avoid read-modify-write races. ALT0
|
||||
and ALT1 outputs are selected per pin. Setting `USER_SELECT` changes the source
|
||||
to `user_gpio_if`; every ownership transition forces the physical output
|
||||
enable low for one complete SoC clock before the new owner can drive. Open
|
||||
drain is applied after this mux: logical zero drives low, while logical one
|
||||
releases the pad.
|
||||
|
||||
The raw pad input passes through a two-stage synchronizer. When filtering is
|
||||
disabled, the synchronized value feeds `DATA_IN`, the interrupt detector, and
|
||||
the user IP. When enabled, the input must disagree with the current filtered
|
||||
value for `FILTER_COUNT` samples before changing. Alternate peripheral inputs
|
||||
continue to receive the raw pad signal because each peripheral owns its CDC
|
||||
requirements, for example the DVP pixel clock.
|
||||
|
||||
Each pin supports rising, falling, both-edge, high-level, or low-level
|
||||
interrupt operation. Edge and level modes cannot be combined for one pin, and
|
||||
high plus low is invalid. Level events reassert sticky state while the level
|
||||
remains active. The output interrupt is the reduction OR of
|
||||
`INTR_STATE & INTR_ENABLE`.
|
||||
|
||||
## Pad capabilities
|
||||
|
||||
Digital functionality is identical for every PDK, but pad electrical controls
|
||||
are reported rather than emulated when a technology lacks a matching cell.
|
||||
|
||||
| PDK | CMOS input select | Pull-up | Pull-down |
|
||||
| --- | --- | --- | --- |
|
||||
| GF180 | Yes | Yes | Yes |
|
||||
| ICS55 | Yes | Yes | Yes |
|
||||
| SKY130 | Yes | No | No |
|
||||
| IHP130 | No | No | No |
|
||||
| S110 / generic behavioral | No | No | No |
|
||||
|
||||
Drive strength, slew rate, sleep retention, and wakeup are deliberately not
|
||||
implemented as generic GPIO bits. They require qualified PDK pad cells,
|
||||
power-domain state, and UPF/physical-design ownership before a portable ABI is
|
||||
safe.
|
||||
|
||||
## Software and verification
|
||||
|
||||
`<retrosoc/hal/gpio.h>` exposes structured pin configuration, atomic data
|
||||
operations, interrupt control, user ownership and access policy, lock
|
||||
commands, capability discovery, and integer filter timing conversion. The HAL
|
||||
returns `RS_ENOTSUP` before requesting unsupported electrical features.
|
||||
|
||||
The self-checking RTL test covers reset values, access errors, atomic output
|
||||
and OE, user-window masking, guarded user-IP handoff, open drain, pull
|
||||
conflicts, edge interrupt state, W1C, interrupt test, trigger conflicts,
|
||||
filtering, and configuration lock. The SBY target checks RIBP request
|
||||
stability, lock monotonicity, user-window isolation, handoff high impedance,
|
||||
and open-drain safety, with covers for ownership, error, and interrupt paths.
|
||||
Host C tests cover filter timing limits, and `ci_smoke` checks capability
|
||||
discovery and public HAL output operations in full-SoC simulation.
|
||||
@@ -128,7 +128,11 @@ digraph mini_soc_block_diagram {
|
||||
];
|
||||
ribp_targets [
|
||||
fillcolor="#F9E1E7",
|
||||
label="RIBP target wrapper\nXPI/Flash, SDRAM, PSRAM, SPI-SD and DVP\nGPIO, UART0, I2C and I2S"
|
||||
label="RIBP target wrapper\nXPI/Flash, SDRAM, PSRAM, SPI-SD and DVP\nUART0, I2C and I2S"
|
||||
];
|
||||
gpio_controller [
|
||||
fillcolor="#F9E1E7",
|
||||
label="GPIO V2\nuser + management RIBP windows\natomic I/O, filter, locks, IRQ18"
|
||||
];
|
||||
timers [
|
||||
fillcolor="#F9E1E7",
|
||||
@@ -144,7 +148,7 @@ digraph mini_soc_block_diagram {
|
||||
];
|
||||
gpio_bridge [
|
||||
fillcolor="#E5E7EB",
|
||||
label="GPIO pad bridge\nsoftware, alternate and user modes"
|
||||
label="GPIO pad bridge\nPDK capability-adapted controls"
|
||||
];
|
||||
irq [
|
||||
fillcolor="#FCE7F3",
|
||||
@@ -157,7 +161,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; timers; ws2812; apb_targets; }
|
||||
{ rank=same; sysctrl; clint; ribp_targets; gpio_controller; timers; ws2812; apb_targets; }
|
||||
{ rank=same; gpio_bridge; irq; }
|
||||
|
||||
ext_clock -> rcu [label="clock / reset"];
|
||||
@@ -182,17 +186,20 @@ digraph mini_soc_block_diagram {
|
||||
ribp_adapter -> sysctrl [label="RIBP"];
|
||||
ribp_adapter -> clint [label="RIBP"];
|
||||
ribp_adapter -> ribp_targets [label="RIBP"];
|
||||
ribp_adapter -> gpio_controller [label="RIBP\nuser/admin"];
|
||||
ribp_adapter -> timers [label="RIBP"];
|
||||
ribp_adapter -> ws2812 [label="RIBP"];
|
||||
apb_adapter -> apb_targets [label="APB"];
|
||||
|
||||
ribp_targets -> gpio_bridge [label="GPIO alternate functions"];
|
||||
ribp_targets -> gpio_controller [label="alternate functions"];
|
||||
gpio_controller -> gpio_bridge [label="pad control"];
|
||||
gpio_controller -> irq [label="IRQ18"];
|
||||
timers -> irq [label="IRQ3 / IRQ4"];
|
||||
clint -> irq [label="machine IRQ0 / IRQ1"];
|
||||
ws2812 -> gpio_bridge [label="GPIO2 ALT1"];
|
||||
dma -> ws2812 [label="TXDATA writes", style=dashed];
|
||||
ws2812 -> irq [label="IRQ17"];
|
||||
apb_targets -> gpio_bridge [label="user_gpio"];
|
||||
apb_targets -> gpio_controller [label="user_gpio"];
|
||||
ribp_targets -> ext_io [dir=both, label="device interfaces"];
|
||||
gpio_bridge -> ext_io [dir=both, label="pad control"];
|
||||
}
|
||||
+230
-200
@@ -4,86 +4,86 @@
|
||||
<!-- Generated by graphviz version 2.43.0 (0)
|
||||
-->
|
||||
<!-- Title: mini_soc_block_diagram Pages: 1 -->
|
||||
<svg width="1719pt" height="887pt"
|
||||
viewBox="0.00 0.00 1719.00 887.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 883.48)">
|
||||
<svg width="1986pt" height="896pt"
|
||||
viewBox="0.00 0.00 1986.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="-861.08" font-family="Arial" font-size="18.00">retroSoC Mini SoC Architecture</text>
|
||||
<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 1691,-85 1691,-85 1697,-85 1703,-91 1703,-97 1703,-97 1703,-763.48 1703,-763.48 1703,-769.48 1697,-775.48 1691,-775.48 1691,-775.48 160,-775.48 160,-775.48 154,-775.48 148,-769.48 148,-763.48 148,-763.48 148,-97 148,-97 148,-91 154,-85 160,-85"/>
|
||||
<text text-anchor="middle" x="196.5" y="-760.28" font-family="Arial" font-size="14.00" fill="#111827">retrosoc_asic</text>
|
||||
<path fill="transparent" stroke="#111827" d="M160,-85C160,-85 1958,-85 1958,-85 1964,-85 1970,-91 1970,-97 1970,-97 1970,-772.48 1970,-772.48 1970,-778.48 1964,-784.48 1958,-784.48 1958,-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 1673,-103 1673,-103 1679,-103 1685,-109 1685,-115 1685,-115 1685,-720.48 1685,-720.48 1685,-726.48 1679,-732.48 1673,-732.48 1673,-732.48 390,-732.48 390,-732.48 384,-732.48 378,-726.48 378,-720.48 378,-720.48 378,-115 378,-115 378,-109 384,-103 390,-103"/>
|
||||
<text text-anchor="middle" x="407.5" y="-718.88" font-family="Arial" font-size="12.00" fill="#334155">retrosoc</text>
|
||||
<path fill="transparent" stroke="#94a3b8" stroke-dasharray="5,2" d="M390,-103C390,-103 1940,-103 1940,-103 1946,-103 1952,-109 1952,-115 1952,-115 1952,-729.48 1952,-729.48 1952,-735.48 1946,-741.48 1940,-741.48 1940,-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 -->
|
||||
<g id="node1" class="node">
|
||||
<title>ext_clock</title>
|
||||
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M118,-669.98C118,-669.98 12,-669.98 12,-669.98 6,-669.98 0,-663.98 0,-657.98 0,-657.98 0,-645.98 0,-645.98 0,-639.98 6,-633.98 12,-633.98 12,-633.98 118,-633.98 118,-633.98 124,-633.98 130,-639.98 130,-645.98 130,-645.98 130,-657.98 130,-657.98 130,-663.98 124,-669.98 118,-669.98"/>
|
||||
<text text-anchor="middle" x="65" y="-654.98" font-family="Arial" font-size="10.00" fill="#111827">External clocks and reset</text>
|
||||
<text text-anchor="middle" x="65" y="-643.98" font-family="Arial" font-size="10.00" fill="#111827">ext_clk, aud_clk, reset</text>
|
||||
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M118,-678.98C118,-678.98 12,-678.98 12,-678.98 6,-678.98 0,-672.98 0,-666.98 0,-666.98 0,-654.98 0,-654.98 0,-648.98 6,-642.98 12,-642.98 12,-642.98 118,-642.98 118,-642.98 124,-642.98 130,-648.98 130,-654.98 130,-654.98 130,-666.98 130,-666.98 130,-672.98 124,-678.98 118,-678.98"/>
|
||||
<text text-anchor="middle" x="65" y="-663.98" font-family="Arial" font-size="10.00" fill="#111827">External clocks and reset</text>
|
||||
<text text-anchor="middle" x="65" y="-652.98" font-family="Arial" font-size="10.00" fill="#111827">ext_clk, aud_clk, reset</text>
|
||||
</g>
|
||||
<!-- rcu -->
|
||||
<g id="node4" class="node">
|
||||
<title>rcu</title>
|
||||
<path fill="#ede9fe" stroke="#4b5563" stroke-width="1.1" d="M350,-574.48C350,-574.48 178,-574.48 178,-574.48 172,-574.48 166,-568.48 166,-562.48 166,-562.48 166,-541.48 166,-541.48 166,-535.48 172,-529.48 178,-529.48 178,-529.48 350,-529.48 350,-529.48 356,-529.48 362,-535.48 362,-541.48 362,-541.48 362,-562.48 362,-562.48 362,-568.48 356,-574.48 350,-574.48"/>
|
||||
<text text-anchor="middle" x="264" y="-560.48" font-family="Arial" font-size="10.00" fill="#111827">RCU</text>
|
||||
<text text-anchor="middle" x="264" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">clock buffering and reset synchronization</text>
|
||||
<text text-anchor="middle" x="264" y="-538.48" font-family="Arial" font-size="10.00" fill="#111827">PLL CDC and fixed 1 MHz timebase</text>
|
||||
<path fill="#ede9fe" stroke="#4b5563" stroke-width="1.1" d="M350,-583.48C350,-583.48 178,-583.48 178,-583.48 172,-583.48 166,-577.48 166,-571.48 166,-571.48 166,-550.48 166,-550.48 166,-544.48 172,-538.48 178,-538.48 178,-538.48 350,-538.48 350,-538.48 356,-538.48 362,-544.48 362,-550.48 362,-550.48 362,-571.48 362,-571.48 362,-577.48 356,-583.48 350,-583.48"/>
|
||||
<text text-anchor="middle" x="264" y="-569.48" font-family="Arial" font-size="10.00" fill="#111827">RCU</text>
|
||||
<text text-anchor="middle" x="264" y="-558.48" font-family="Arial" font-size="10.00" fill="#111827">clock buffering and reset synchronization</text>
|
||||
<text text-anchor="middle" x="264" y="-547.48" font-family="Arial" font-size="10.00" fill="#111827">PLL CDC and fixed 1 MHz timebase</text>
|
||||
</g>
|
||||
<!-- ext_clock->rcu -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>ext_clock->rcu</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M99.66,-633.91C131.11,-618.43 177.87,-595.4 213.48,-577.87"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="214.79,-579.95 219.99,-574.66 212.63,-575.55 214.79,-579.95"/>
|
||||
<text text-anchor="middle" x="191.5" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">clock / reset</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M99.66,-642.91C131.11,-627.43 177.87,-604.4 213.48,-586.87"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="214.79,-588.95 219.99,-583.66 212.63,-584.55 214.79,-588.95"/>
|
||||
<text text-anchor="middle" x="191.5" y="-609.08" font-family="Arial" font-size="8.00" fill="#374151">clock / reset</text>
|
||||
</g>
|
||||
<!-- ext_io -->
|
||||
<g id="node2" class="node">
|
||||
<title>ext_io</title>
|
||||
<path fill="#f3f4f6" stroke="#4b5563" stroke-width="1.1" d="M1557,-45C1557,-45 1365,-45 1365,-45 1359,-45 1353,-39 1353,-33 1353,-33 1353,-12 1353,-12 1353,-6 1359,0 1365,0 1365,0 1557,0 1557,0 1563,0 1569,-6 1569,-12 1569,-12 1569,-33 1569,-33 1569,-39 1563,-45 1557,-45"/>
|
||||
<text text-anchor="middle" x="1461" y="-31" font-family="Arial" font-size="10.00" fill="#111827">External I/O and memory</text>
|
||||
<text text-anchor="middle" x="1461" y="-20" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, XPI Flash, SDRAM, PSRAM</text>
|
||||
<text text-anchor="middle" x="1461" 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="M1063,-45C1063,-45 871,-45 871,-45 865,-45 859,-39 859,-33 859,-33 859,-12 859,-12 859,-6 865,0 871,0 871,0 1063,0 1063,0 1069,0 1075,-6 1075,-12 1075,-12 1075,-33 1075,-33 1075,-39 1069,-45 1063,-45"/>
|
||||
<text text-anchor="middle" x="967" y="-31" font-family="Arial" font-size="10.00" fill="#111827">External I/O and memory</text>
|
||||
<text text-anchor="middle" x="967" y="-20" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, XPI Flash, SDRAM, PSRAM</text>
|
||||
<text text-anchor="middle" x="967" 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="M678.5,-851.48C678.5,-851.48 547.5,-851.48 547.5,-851.48 541.5,-851.48 535.5,-845.48 535.5,-839.48 535.5,-839.48 535.5,-827.48 535.5,-827.48 535.5,-821.48 541.5,-815.48 547.5,-815.48 547.5,-815.48 678.5,-815.48 678.5,-815.48 684.5,-815.48 690.5,-821.48 690.5,-827.48 690.5,-827.48 690.5,-839.48 690.5,-839.48 690.5,-845.48 684.5,-851.48 678.5,-851.48"/>
|
||||
<text text-anchor="middle" x="613" y="-836.48" font-family="Arial" font-size="10.00" fill="#111827">Management JTAG</text>
|
||||
<text text-anchor="middle" x="613" y="-825.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="M1078.5,-860.48C1078.5,-860.48 947.5,-860.48 947.5,-860.48 941.5,-860.48 935.5,-854.48 935.5,-848.48 935.5,-848.48 935.5,-836.48 935.5,-836.48 935.5,-830.48 941.5,-824.48 947.5,-824.48 947.5,-824.48 1078.5,-824.48 1078.5,-824.48 1084.5,-824.48 1090.5,-830.48 1090.5,-836.48 1090.5,-836.48 1090.5,-848.48 1090.5,-848.48 1090.5,-854.48 1084.5,-860.48 1078.5,-860.48"/>
|
||||
<text text-anchor="middle" x="1013" y="-845.48" font-family="Arial" font-size="10.00" fill="#111827">Management JTAG</text>
|
||||
<text text-anchor="middle" x="1013" 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="M688,-669.98C688,-669.98 538,-669.98 538,-669.98 532,-669.98 526,-663.98 526,-657.98 526,-657.98 526,-645.98 526,-645.98 526,-639.98 532,-633.98 538,-633.98 538,-633.98 688,-633.98 688,-633.98 694,-633.98 700,-639.98 700,-645.98 700,-645.98 700,-657.98 700,-657.98 700,-663.98 694,-669.98 688,-669.98"/>
|
||||
<text text-anchor="middle" x="613" y="-654.98" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 JTAG DTM</text>
|
||||
<text text-anchor="middle" x="613" y="-643.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="M1088,-678.98C1088,-678.98 938,-678.98 938,-678.98 932,-678.98 926,-672.98 926,-666.98 926,-666.98 926,-654.98 926,-654.98 926,-648.98 932,-642.98 938,-642.98 938,-642.98 1088,-642.98 1088,-642.98 1094,-642.98 1100,-648.98 1100,-654.98 1100,-654.98 1100,-666.98 1100,-666.98 1100,-672.98 1094,-678.98 1088,-678.98"/>
|
||||
<text text-anchor="middle" x="1013" y="-663.98" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 JTAG DTM</text>
|
||||
<text text-anchor="middle" x="1013" 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="M613,-815.27C613,-783.24 613,-714.39 613,-677.51"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="615.45,-677.14 613,-670.14 610.55,-677.14 615.45,-677.14"/>
|
||||
<text text-anchor="middle" x="633" y="-786.08" font-family="Arial" font-size="8.00" fill="#374151">JTAG pads</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1013,-824.27C1013,-792.24 1013,-723.39 1013,-686.51"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1015.45,-686.14 1013,-679.14 1010.55,-686.14 1015.45,-686.14"/>
|
||||
<text text-anchor="middle" x="1033" 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="M1066.66,-442.31C1066.66,-442.31 998.98,-470.16 998.98,-470.16 993.43,-472.45 981.88,-474.73 975.88,-474.73 975.88,-474.73 820.12,-474.73 820.12,-474.73 814.12,-474.73 802.57,-472.45 797.02,-470.16 797.02,-470.16 729.34,-442.31 729.34,-442.31 723.79,-440.03 723.79,-435.46 729.34,-433.18 729.34,-433.18 797.02,-405.32 797.02,-405.32 802.57,-403.04 814.12,-400.76 820.12,-400.76 820.12,-400.76 975.88,-400.76 975.88,-400.76 981.88,-400.76 993.43,-403.04 998.98,-405.32 998.98,-405.32 1066.66,-433.18 1066.66,-433.18 1072.21,-435.46 1072.21,-440.03 1066.66,-442.31"/>
|
||||
<text text-anchor="middle" x="898" y="-446.24" font-family="Arial" font-size="10.00" fill="#111827">RIB fabric</text>
|
||||
<text text-anchor="middle" x="898" y="-435.24" font-family="Arial" font-size="10.00" fill="#111827">3-master round-robin arbitration</text>
|
||||
<text text-anchor="middle" x="898" y="-424.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="M1086.66,-451.31C1086.66,-451.31 1018.98,-479.16 1018.98,-479.16 1013.43,-481.45 1001.88,-483.73 995.88,-483.73 995.88,-483.73 840.12,-483.73 840.12,-483.73 834.12,-483.73 822.57,-481.45 817.02,-479.16 817.02,-479.16 749.34,-451.31 749.34,-451.31 743.79,-449.03 743.79,-444.46 749.34,-442.18 749.34,-442.18 817.02,-414.32 817.02,-414.32 822.57,-412.04 834.12,-409.76 840.12,-409.76 840.12,-409.76 995.88,-409.76 995.88,-409.76 1001.88,-409.76 1013.43,-412.04 1018.98,-414.32 1018.98,-414.32 1086.66,-442.18 1086.66,-442.18 1092.21,-444.46 1092.21,-449.03 1086.66,-451.31"/>
|
||||
<text text-anchor="middle" x="918" y="-455.24" font-family="Arial" font-size="10.00" fill="#111827">RIB fabric</text>
|
||||
<text text-anchor="middle" x="918" y="-444.24" font-family="Arial" font-size="10.00" fill="#111827">3-master round-robin arbitration</text>
|
||||
<text text-anchor="middle" x="918" 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,-531.47C368.2,-530.24 372,-529.48 372,-529.48 372,-529.48 697,-474.48 697,-474.48 697,-474.48 728.7,-468.85 766.93,-462.05"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="767.67,-464.41 774.14,-460.77 766.82,-459.58 767.67,-464.41"/>
|
||||
<text text-anchor="middle" x="588" y="-500.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 734,-483.48 734,-483.48 734,-483.48 758.75,-478.68 790.1,-472.59"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="790.92,-474.92 797.32,-471.18 789.98,-470.11 790.92,-474.92"/>
|
||||
<text text-anchor="middle" x="609" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">system clock / reset</text>
|
||||
</g>
|
||||
<!-- clint -->
|
||||
<g id="node17" class="node">
|
||||
@@ -96,319 +96,349 @@
|
||||
<!-- 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="M277.95,-529.16C313.89,-472.95 409.6,-323.28 449.33,-261.14"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="451.51,-262.27 453.22,-255.05 447.38,-259.63 451.51,-262.27"/>
|
||||
<text text-anchor="middle" x="397.5" y="-371.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="M277.48,-538.31C313.09,-481.03 409.7,-325.66 449.5,-261.65"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="451.78,-262.62 453.4,-255.38 447.62,-260.03 451.78,-262.62"/>
|
||||
<text text-anchor="middle" x="392.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="M1273,-674.48C1273,-674.48 1119,-674.48 1119,-674.48 1113,-674.48 1107,-668.48 1107,-662.48 1107,-662.48 1107,-641.48 1107,-641.48 1107,-635.48 1113,-629.48 1119,-629.48 1119,-629.48 1273,-629.48 1273,-629.48 1279,-629.48 1285,-635.48 1285,-641.48 1285,-641.48 1285,-662.48 1285,-662.48 1285,-668.48 1279,-674.48 1273,-674.48"/>
|
||||
<text text-anchor="middle" x="1196" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Management core</text>
|
||||
<text text-anchor="middle" x="1196" y="-649.48" font-family="Arial" font-size="10.00" fill="#111827">Fixed Hazard3, branch predictor</text>
|
||||
<text text-anchor="middle" x="1196" y="-638.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="M1293,-683.48C1293,-683.48 1139,-683.48 1139,-683.48 1133,-683.48 1127,-677.48 1127,-671.48 1127,-671.48 1127,-650.48 1127,-650.48 1127,-644.48 1133,-638.48 1139,-638.48 1139,-638.48 1293,-638.48 1293,-638.48 1299,-638.48 1305,-644.48 1305,-650.48 1305,-650.48 1305,-671.48 1305,-671.48 1305,-677.48 1299,-683.48 1293,-683.48"/>
|
||||
<text text-anchor="middle" x="1216" y="-669.48" font-family="Arial" font-size="10.00" fill="#111827">Management core</text>
|
||||
<text text-anchor="middle" x="1216" y="-658.48" font-family="Arial" font-size="10.00" fill="#111827">Fixed Hazard3, branch predictor</text>
|
||||
<text text-anchor="middle" x="1216" 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="M1216.5,-569.98C1216.5,-569.98 1175.5,-569.98 1175.5,-569.98 1169.5,-569.98 1163.5,-563.98 1163.5,-557.98 1163.5,-557.98 1163.5,-545.98 1163.5,-545.98 1163.5,-539.98 1169.5,-533.98 1175.5,-533.98 1175.5,-533.98 1216.5,-533.98 1216.5,-533.98 1222.5,-533.98 1228.5,-539.98 1228.5,-545.98 1228.5,-545.98 1228.5,-557.98 1228.5,-557.98 1228.5,-563.98 1222.5,-569.98 1216.5,-569.98"/>
|
||||
<text text-anchor="middle" x="1196" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">RIBP2RIB</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1236.5,-578.98C1236.5,-578.98 1195.5,-578.98 1195.5,-578.98 1189.5,-578.98 1183.5,-572.98 1183.5,-566.98 1183.5,-566.98 1183.5,-554.98 1183.5,-554.98 1183.5,-548.98 1189.5,-542.98 1195.5,-542.98 1195.5,-542.98 1236.5,-542.98 1236.5,-542.98 1242.5,-542.98 1248.5,-548.98 1248.5,-554.98 1248.5,-554.98 1248.5,-566.98 1248.5,-566.98 1248.5,-572.98 1242.5,-578.98 1236.5,-578.98"/>
|
||||
<text text-anchor="middle" x="1216" 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="M1196,-629.24C1196,-613.92 1196,-593.4 1196,-577.51"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1198.45,-577.12 1196,-570.12 1193.55,-577.12 1198.45,-577.12"/>
|
||||
<text text-anchor="middle" x="1205.5" y="-600.08" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1216,-638.24C1216,-622.92 1216,-602.4 1216,-586.51"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1218.45,-586.12 1216,-579.12 1213.55,-586.12 1218.45,-586.12"/>
|
||||
<text text-anchor="middle" x="1225.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="M949.5,-674.48C949.5,-674.48 828.5,-674.48 828.5,-674.48 822.5,-674.48 816.5,-668.48 816.5,-662.48 816.5,-662.48 816.5,-641.48 816.5,-641.48 816.5,-635.48 822.5,-629.48 828.5,-629.48 828.5,-629.48 949.5,-629.48 949.5,-629.48 955.5,-629.48 961.5,-635.48 961.5,-641.48 961.5,-641.48 961.5,-662.48 961.5,-662.48 961.5,-668.48 955.5,-674.48 949.5,-674.48"/>
|
||||
<text text-anchor="middle" x="889" y="-660.48" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 Debug Module</text>
|
||||
<text text-anchor="middle" x="889" y="-649.48" font-family="Arial" font-size="10.00" fill="#111827">abstract commands, no SBA</text>
|
||||
<text text-anchor="middle" x="889" y="-638.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="M1583.5,-683.48C1583.5,-683.48 1462.5,-683.48 1462.5,-683.48 1456.5,-683.48 1450.5,-677.48 1450.5,-671.48 1450.5,-671.48 1450.5,-650.48 1450.5,-650.48 1450.5,-644.48 1456.5,-638.48 1462.5,-638.48 1462.5,-638.48 1583.5,-638.48 1583.5,-638.48 1589.5,-638.48 1595.5,-644.48 1595.5,-650.48 1595.5,-650.48 1595.5,-671.48 1595.5,-671.48 1595.5,-677.48 1589.5,-683.48 1583.5,-683.48"/>
|
||||
<text text-anchor="middle" x="1523" y="-669.48" font-family="Arial" font-size="10.00" fill="#111827">Hazard3 Debug Module</text>
|
||||
<text text-anchor="middle" x="1523" y="-658.48" font-family="Arial" font-size="10.00" fill="#111827">abstract commands, no SBA</text>
|
||||
<text text-anchor="middle" x="1523" 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="M700.33,-651.98C735.12,-651.98 774.91,-651.98 808.95,-651.98"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="809.12,-654.43 816.12,-651.98 809.12,-649.53 809.12,-654.43"/>
|
||||
<text text-anchor="middle" x="758.25" y="-657.58" font-family="Arial" font-size="8.00" fill="#374151">DMI, asynchronous CDC</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1031.06,-679.13C1060.11,-708.33 1114,-762.48 1114,-762.48 1114,-762.48 1319,-762.48 1319,-762.48 1319,-762.48 1410.81,-716.8 1471.25,-686.73"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1472.55,-688.82 1477.73,-683.51 1470.37,-684.44 1472.55,-688.82"/>
|
||||
<text text-anchor="middle" x="1275" y="-795.08" 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="M961.75,-651.98C1002.99,-651.98 1055.09,-651.98 1099.69,-651.98"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1099.77,-654.43 1106.77,-651.98 1099.77,-649.53 1099.77,-654.43"/>
|
||||
<text text-anchor="middle" x="1034.25" y="-657.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="M1450.11,-660.98C1408.89,-660.98 1356.84,-660.98 1312.29,-660.98"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1312.21,-658.53 1305.21,-660.98 1312.21,-663.43 1312.21,-658.53"/>
|
||||
<text text-anchor="middle" x="1377.75" 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="M961.7,-629.68C1038.93,-607.04 1150,-574.48 1150,-574.48 1150,-574.48 1152.57,-573.29 1156.49,-571.45"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1157.75,-573.56 1163.06,-568.38 1155.68,-569.13 1157.75,-573.56"/>
|
||||
<text text-anchor="middle" x="1103" y="-600.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="M1450.23,-638.57C1373.31,-615.94 1263,-583.48 1263,-583.48 1263,-583.48 1259.87,-582.05 1255.22,-579.93"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1256.03,-577.6 1248.64,-576.92 1253.99,-582.06 1256.03,-577.6"/>
|
||||
<text text-anchor="middle" x="1407" y="-609.08" font-family="Arial" font-size="8.00" fill="#374151">reset after bridge idle</text>
|
||||
</g>
|
||||
<!-- timers -->
|
||||
<g id="node19" class="node">
|
||||
<g id="node20" class="node">
|
||||
<title>timers</title>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M759.5,-255C759.5,-255 578.5,-255 578.5,-255 572.5,-255 566.5,-249 566.5,-243 566.5,-243 566.5,-222 566.5,-222 566.5,-216 572.5,-210 578.5,-210 578.5,-210 759.5,-210 759.5,-210 765.5,-210 771.5,-216 771.5,-222 771.5,-222 771.5,-243 771.5,-243 771.5,-249 765.5,-255 759.5,-255"/>
|
||||
<text text-anchor="middle" x="669" y="-241" font-family="Arial" font-size="10.00" fill="#111827">General timers 0/1</text>
|
||||
<text text-anchor="middle" x="669" y="-230" font-family="Arial" font-size="10.00" fill="#111827">32-bit counter, 16-bit prescaler</text>
|
||||
<text text-anchor="middle" x="669" 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="M1681.5,-255C1681.5,-255 1500.5,-255 1500.5,-255 1494.5,-255 1488.5,-249 1488.5,-243 1488.5,-243 1488.5,-222 1488.5,-222 1488.5,-216 1494.5,-210 1500.5,-210 1500.5,-210 1681.5,-210 1681.5,-210 1687.5,-210 1693.5,-216 1693.5,-222 1693.5,-222 1693.5,-243 1693.5,-243 1693.5,-249 1687.5,-255 1681.5,-255"/>
|
||||
<text text-anchor="middle" x="1591" y="-241" font-family="Arial" font-size="10.00" fill="#111827">General timers 0/1</text>
|
||||
<text text-anchor="middle" x="1591" y="-230" font-family="Arial" font-size="10.00" fill="#111827">32-bit counter, 16-bit prescaler</text>
|
||||
<text text-anchor="middle" x="1591" 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="M840.72,-629.48C775.96,-600.63 669,-552.98 669,-552.98 669,-552.98 669,-552.98 669,-327 669,-327 669,-289.76 669,-262.28"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="671.45,-262.19 669,-255.19 666.55,-262.19 671.45,-262.19"/>
|
||||
<text text-anchor="middle" x="680" y="-435.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="M1530.32,-638.24C1540.05,-609.36 1556,-561.98 1556,-561.98 1556,-561.98 1556,-561.98 1556,-336 1556,-336 1570.96,-292.2 1581.31,-261.86"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1583.63,-262.65 1583.58,-255.24 1579,-261.07 1583.63,-262.65"/>
|
||||
<text text-anchor="middle" x="1567" 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="M1177.65,-533.76C1160.99,-518.12 1139,-497.48 1139,-497.48 1139,-497.48 1077.55,-482.51 1016.71,-467.68"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1017.06,-465.24 1009.68,-465.96 1015.9,-470 1017.06,-465.24"/>
|
||||
<text text-anchor="middle" x="1155" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1197.65,-542.76C1180.99,-527.12 1159,-506.48 1159,-506.48 1159,-506.48 1097.55,-491.51 1036.71,-476.68"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1037.06,-474.24 1029.68,-474.96 1035.9,-479 1037.06,-474.24"/>
|
||||
<text text-anchor="middle" x="1175" 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="M1124,-574.48C1124,-574.48 1048,-574.48 1048,-574.48 1042,-574.48 1036,-568.48 1036,-562.48 1036,-562.48 1036,-541.48 1036,-541.48 1036,-535.48 1042,-529.48 1048,-529.48 1048,-529.48 1124,-529.48 1124,-529.48 1130,-529.48 1136,-535.48 1136,-541.48 1136,-541.48 1136,-562.48 1136,-562.48 1136,-568.48 1130,-574.48 1124,-574.48"/>
|
||||
<text text-anchor="middle" x="1086" y="-560.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text>
|
||||
<text text-anchor="middle" x="1086" y="-549.48" font-family="Arial" font-size="10.00" fill="#111827">C0-C5, one active</text>
|
||||
<text text-anchor="middle" x="1086" y="-538.48" font-family="Arial" font-size="10.00" fill="#111827">PicoRV32 at C5</text>
|
||||
<path fill="#ddf2e3" stroke="#4b5563" stroke-width="1.1" d="M1364,-583.48C1364,-583.48 1288,-583.48 1288,-583.48 1282,-583.48 1276,-577.48 1276,-571.48 1276,-571.48 1276,-550.48 1276,-550.48 1276,-544.48 1282,-538.48 1288,-538.48 1288,-538.48 1364,-538.48 1364,-538.48 1370,-538.48 1376,-544.48 1376,-550.48 1376,-550.48 1376,-571.48 1376,-571.48 1376,-577.48 1370,-583.48 1364,-583.48"/>
|
||||
<text text-anchor="middle" x="1326" y="-569.48" font-family="Arial" font-size="10.00" fill="#111827">Selected user core</text>
|
||||
<text text-anchor="middle" x="1326" y="-558.48" font-family="Arial" font-size="10.00" fill="#111827">C0-C5, one active</text>
|
||||
<text text-anchor="middle" x="1326" 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="M1102.11,-529.26C1110.49,-517.96 1119,-506.48 1119,-506.48 1119,-506.48 1119,-497.48 1119,-497.48 1119,-497.48 1066.59,-483.55 1012.81,-469.26"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1013.3,-466.86 1005.91,-467.43 1012.05,-471.59 1013.3,-466.86"/>
|
||||
<text text-anchor="middle" x="1126" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1275.79,-540.52C1236.33,-525.22 1188,-506.48 1188,-506.48 1188,-506.48 1112.22,-490 1040.95,-474.49"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1041.43,-472.09 1034.07,-473 1040.39,-476.88 1041.43,-472.09"/>
|
||||
<text text-anchor="middle" x="1218" 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="M1487,-569.98C1487,-569.98 1369,-569.98 1369,-569.98 1363,-569.98 1357,-563.98 1357,-557.98 1357,-557.98 1357,-545.98 1357,-545.98 1357,-539.98 1363,-533.98 1369,-533.98 1369,-533.98 1487,-533.98 1487,-533.98 1493,-533.98 1499,-539.98 1499,-545.98 1499,-545.98 1499,-557.98 1499,-557.98 1499,-563.98 1493,-569.98 1487,-569.98"/>
|
||||
<text text-anchor="middle" x="1428" y="-554.98" font-family="Arial" font-size="10.00" fill="#111827">DMA</text>
|
||||
<text text-anchor="middle" x="1428" y="-543.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="M957,-578.98C957,-578.98 839,-578.98 839,-578.98 833,-578.98 827,-572.98 827,-566.98 827,-566.98 827,-554.98 827,-554.98 827,-548.98 833,-542.98 839,-542.98 839,-542.98 957,-542.98 957,-542.98 963,-542.98 969,-548.98 969,-554.98 969,-554.98 969,-566.98 969,-566.98 969,-572.98 963,-578.98 957,-578.98"/>
|
||||
<text text-anchor="middle" x="898" y="-563.98" font-family="Arial" font-size="10.00" fill="#111827">DMA</text>
|
||||
<text text-anchor="middle" x="898" 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="M1356.8,-535.91C1271.31,-517.8 1126.48,-487.13 1022.39,-465.08"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1022.63,-462.63 1015.28,-463.58 1021.62,-467.43 1022.63,-462.63"/>
|
||||
<text text-anchor="middle" x="1217" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M969,-546.87C1040.09,-533.75 1139,-515.48 1139,-515.48 1139,-515.48 1139,-506.48 1139,-506.48 1139,-506.48 1086.59,-492.55 1032.81,-478.26"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1033.3,-475.86 1025.91,-476.43 1032.05,-480.59 1033.3,-475.86"/>
|
||||
<text text-anchor="middle" x="1146" y="-509.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
</g>
|
||||
<!-- ws2812 -->
|
||||
<g id="node20" class="node">
|
||||
<g id="node21" class="node">
|
||||
<title>ws2812</title>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1400,-255C1400,-255 1266,-255 1266,-255 1260,-255 1254,-249 1254,-243 1254,-243 1254,-222 1254,-222 1254,-216 1260,-210 1266,-210 1266,-210 1400,-210 1400,-210 1406,-210 1412,-216 1412,-222 1412,-222 1412,-243 1412,-243 1412,-249 1406,-255 1400,-255"/>
|
||||
<text text-anchor="middle" x="1333" y="-241" font-family="Arial" font-size="10.00" fill="#111827">WS2812 TX</text>
|
||||
<text text-anchor="middle" x="1333" y="-230" font-family="Arial" font-size="10.00" fill="#111827">24-bit MSB-first serializer</text>
|
||||
<text text-anchor="middle" x="1333" 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="M713,-255C713,-255 579,-255 579,-255 573,-255 567,-249 567,-243 567,-243 567,-222 567,-222 567,-216 573,-210 579,-210 579,-210 713,-210 713,-210 719,-210 725,-216 725,-222 725,-222 725,-243 725,-243 725,-249 719,-255 713,-255"/>
|
||||
<text text-anchor="middle" x="646" y="-241" font-family="Arial" font-size="10.00" fill="#111827">WS2812 TX</text>
|
||||
<text text-anchor="middle" x="646" y="-230" font-family="Arial" font-size="10.00" fill="#111827">24-bit MSB-first serializer</text>
|
||||
<text text-anchor="middle" x="646" y="-219" font-family="Arial" font-size="10.00" fill="#111827">16-word FIFO, IRQ17, DMA-fed</text>
|
||||
</g>
|
||||
<!-- dma->ws2812 -->
|
||||
<g id="edge27" class="edge">
|
||||
<g id="edge30" class="edge">
|
||||
<title>dma->ws2812</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" stroke-dasharray="5,2" d="M1433.9,-533.63C1441.57,-511.05 1454,-474.48 1454,-474.48 1454,-474.48 1454,-401 1454,-401 1454,-401 1387.1,-308.39 1352.79,-260.89"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1354.66,-259.29 1348.57,-255.05 1350.68,-262.16 1354.66,-259.29"/>
|
||||
<text text-anchor="middle" x="1463.5" y="-371.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="M859.18,-542.82C808.17,-520.26 725,-483.48 725,-483.48 725,-483.48 689,-278 689,-278 689,-278 681.11,-269.83 672.08,-260.49"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="673.62,-258.56 667,-255.23 670.1,-261.96 673.62,-258.56"/>
|
||||
<text text-anchor="middle" x="734.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="M1278.5,-455.74C1278.5,-455.74 1169.5,-455.74 1169.5,-455.74 1163.5,-455.74 1157.5,-449.74 1157.5,-443.74 1157.5,-443.74 1157.5,-431.74 1157.5,-431.74 1157.5,-425.74 1163.5,-419.74 1169.5,-419.74 1169.5,-419.74 1278.5,-419.74 1278.5,-419.74 1284.5,-419.74 1290.5,-425.74 1290.5,-431.74 1290.5,-431.74 1290.5,-443.74 1290.5,-443.74 1290.5,-449.74 1284.5,-455.74 1278.5,-455.74"/>
|
||||
<text text-anchor="middle" x="1224" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">Error slave</text>
|
||||
<text text-anchor="middle" x="1224" y="-429.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="M1298.5,-464.74C1298.5,-464.74 1189.5,-464.74 1189.5,-464.74 1183.5,-464.74 1177.5,-458.74 1177.5,-452.74 1177.5,-452.74 1177.5,-440.74 1177.5,-440.74 1177.5,-434.74 1183.5,-428.74 1189.5,-428.74 1189.5,-428.74 1298.5,-428.74 1298.5,-428.74 1304.5,-428.74 1310.5,-434.74 1310.5,-440.74 1310.5,-440.74 1310.5,-452.74 1310.5,-452.74 1310.5,-458.74 1304.5,-464.74 1298.5,-464.74"/>
|
||||
<text text-anchor="middle" x="1244" y="-449.74" font-family="Arial" font-size="10.00" fill="#111827">Error slave</text>
|
||||
<text text-anchor="middle" x="1244" 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="M1084.98,-437.74C1107.93,-437.74 1130.24,-437.74 1150.02,-437.74"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1084.69,-435.29 1077.69,-437.74 1084.69,-440.19 1084.69,-435.29"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1150.19,-440.19 1157.19,-437.74 1150.19,-435.29 1150.19,-440.19"/>
|
||||
<text text-anchor="middle" x="1117.56" y="-443.34" font-family="Arial" font-size="8.00" fill="#374151">invalid / denied</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1104.98,-446.74C1127.93,-446.74 1150.24,-446.74 1170.02,-446.74"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1104.69,-444.29 1097.69,-446.74 1104.69,-449.19 1104.69,-444.29"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1170.19,-449.19 1177.19,-446.74 1170.19,-444.29 1170.19,-449.19"/>
|
||||
<text text-anchor="middle" x="1137.56" y="-452.34" 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="M1428,-455.74C1428,-455.74 1330,-455.74 1330,-455.74 1324,-455.74 1318,-449.74 1318,-443.74 1318,-443.74 1318,-431.74 1318,-431.74 1318,-425.74 1324,-419.74 1330,-419.74 1330,-419.74 1428,-419.74 1428,-419.74 1434,-419.74 1440,-425.74 1440,-431.74 1440,-431.74 1440,-443.74 1440,-443.74 1440,-449.74 1434,-455.74 1428,-455.74"/>
|
||||
<text text-anchor="middle" x="1379" y="-440.74" font-family="Arial" font-size="10.00" fill="#111827">On-chip SRAM</text>
|
||||
<text text-anchor="middle" x="1379" y="-429.74" font-family="Arial" font-size="10.00" fill="#111827">optional RIB2RAM path</text>
|
||||
<path fill="#fff3c9" stroke="#4b5563" stroke-width="1.1" d="M1448,-464.74C1448,-464.74 1350,-464.74 1350,-464.74 1344,-464.74 1338,-458.74 1338,-452.74 1338,-452.74 1338,-440.74 1338,-440.74 1338,-434.74 1344,-428.74 1350,-428.74 1350,-428.74 1448,-428.74 1448,-428.74 1454,-428.74 1460,-434.74 1460,-440.74 1460,-440.74 1460,-452.74 1460,-452.74 1460,-458.74 1454,-464.74 1448,-464.74"/>
|
||||
<text text-anchor="middle" x="1399" y="-449.74" font-family="Arial" font-size="10.00" fill="#111827">On-chip SRAM</text>
|
||||
<text text-anchor="middle" x="1399" 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="M1004.32,-468.06C1054.69,-482.42 1104,-496.48 1104,-496.48 1104,-496.48 1118,-496.48 1118,-496.48 1118,-496.48 1304,-474.48 1304,-474.48 1304,-474.48 1318.84,-467.21 1335.32,-459.14"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1336.73,-461.18 1341.94,-455.9 1334.58,-456.78 1336.73,-461.18"/>
|
||||
<text text-anchor="middle" x="1111" y="-500.08" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1024.32,-477.06C1074.69,-491.42 1124,-505.48 1124,-505.48 1124,-505.48 1138,-505.48 1138,-505.48 1138,-505.48 1324,-483.48 1324,-483.48 1324,-483.48 1338.84,-476.21 1355.32,-468.14"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1356.73,-470.18 1361.94,-464.9 1354.58,-465.78 1356.73,-470.18"/>
|
||||
<text text-anchor="middle" x="1131" y="-509.08" 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="M1060.5,-346C1060.5,-346 1019.5,-346 1019.5,-346 1013.5,-346 1007.5,-340 1007.5,-334 1007.5,-334 1007.5,-322 1007.5,-322 1007.5,-316 1013.5,-310 1019.5,-310 1019.5,-310 1060.5,-310 1060.5,-310 1066.5,-310 1072.5,-316 1072.5,-322 1072.5,-322 1072.5,-334 1072.5,-334 1072.5,-340 1066.5,-346 1060.5,-346"/>
|
||||
<text text-anchor="middle" x="1040" y="-325.5" font-family="Arial" font-size="10.00" fill="#111827">RIB2RIBP</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M938.5,-355C938.5,-355 897.5,-355 897.5,-355 891.5,-355 885.5,-349 885.5,-343 885.5,-343 885.5,-331 885.5,-331 885.5,-325 891.5,-319 897.5,-319 897.5,-319 938.5,-319 938.5,-319 944.5,-319 950.5,-325 950.5,-331 950.5,-331 950.5,-343 950.5,-343 950.5,-349 944.5,-355 938.5,-355"/>
|
||||
<text text-anchor="middle" x="918" 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="M945.28,-400.87C967.36,-384.11 992.9,-364.73 1011.89,-350.33"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1013.47,-352.2 1017.57,-346.02 1010.51,-348.3 1013.47,-352.2"/>
|
||||
<text text-anchor="middle" x="992" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M918,-409.87C918,-394.27 918,-376.39 918,-362.38"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="920.45,-362.02 918,-355.02 915.55,-362.02 920.45,-362.02"/>
|
||||
<text text-anchor="middle" x="925" 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="M938,-346C938,-346 868,-346 868,-346 862,-346 856,-340 856,-334 856,-334 856,-322 856,-322 856,-316 862,-310 868,-310 868,-310 938,-310 938,-310 944,-310 950,-316 950,-322 950,-322 950,-334 950,-334 950,-340 944,-346 938,-346"/>
|
||||
<text text-anchor="middle" x="903" y="-331" font-family="Arial" font-size="10.00" fill="#111827">RIB2APB</text>
|
||||
<text text-anchor="middle" x="903" y="-320" font-family="Arial" font-size="10.00" fill="#111827">direct APB bridge</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1395,-355C1395,-355 1325,-355 1325,-355 1319,-355 1313,-349 1313,-343 1313,-343 1313,-331 1313,-331 1313,-325 1319,-319 1325,-319 1325,-319 1395,-319 1395,-319 1401,-319 1407,-325 1407,-331 1407,-331 1407,-343 1407,-343 1407,-349 1401,-355 1395,-355"/>
|
||||
<text text-anchor="middle" x="1360" y="-340" font-family="Arial" font-size="10.00" fill="#111827">RIB2APB</text>
|
||||
<text text-anchor="middle" x="1360" 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="M899.66,-400.87C900.39,-385.27 901.22,-367.39 901.87,-353.38"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="904.33,-353.13 902.21,-346.02 899.44,-352.9 904.33,-353.13"/>
|
||||
<text text-anchor="middle" x="908" y="-371.6" font-family="Arial" font-size="8.00" fill="#374151">RIB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1029.54,-418.55C1117.93,-397.01 1237.57,-367.84 1306,-351.16"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1306.64,-353.53 1312.86,-349.49 1305.48,-348.77 1306.64,-353.53"/>
|
||||
<text text-anchor="middle" x="1198" 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="M1215.5,-255C1215.5,-255 1052.5,-255 1052.5,-255 1046.5,-255 1040.5,-249 1040.5,-243 1040.5,-243 1040.5,-222 1040.5,-222 1040.5,-216 1046.5,-210 1052.5,-210 1052.5,-210 1215.5,-210 1215.5,-210 1221.5,-210 1227.5,-216 1227.5,-222 1227.5,-222 1227.5,-243 1227.5,-243 1227.5,-249 1221.5,-255 1215.5,-255"/>
|
||||
<text text-anchor="middle" x="1134" y="-241" font-family="Arial" font-size="10.00" fill="#111827">SYSCTRL</text>
|
||||
<text text-anchor="middle" x="1134" y="-230" font-family="Arial" font-size="10.00" fill="#111827">PLL, user-core select/reset/bus enable</text>
|
||||
<text text-anchor="middle" x="1134" 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="M1449.5,-255C1449.5,-255 1286.5,-255 1286.5,-255 1280.5,-255 1274.5,-249 1274.5,-243 1274.5,-243 1274.5,-222 1274.5,-222 1274.5,-216 1280.5,-210 1286.5,-210 1286.5,-210 1449.5,-210 1449.5,-210 1455.5,-210 1461.5,-216 1461.5,-222 1461.5,-222 1461.5,-243 1461.5,-243 1461.5,-249 1455.5,-255 1449.5,-255"/>
|
||||
<text text-anchor="middle" x="1368" y="-241" font-family="Arial" font-size="10.00" fill="#111827">SYSCTRL</text>
|
||||
<text text-anchor="middle" x="1368" y="-230" font-family="Arial" font-size="10.00" fill="#111827">PLL, user-core select/reset/bus enable</text>
|
||||
<text text-anchor="middle" x="1368" 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="M1057.24,-309.85C1071.15,-296.02 1090.95,-276.32 1106.96,-260.39"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1109,-261.82 1112.24,-255.15 1105.54,-258.35 1109,-261.82"/>
|
||||
<text text-anchor="middle" x="1096.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M950.67,-331.33C1024.53,-320.78 1198,-296 1198,-296 1198,-296 1254.85,-275.1 1302.8,-257.47"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1303.77,-259.72 1309.5,-255.01 1302.08,-255.12 1303.77,-259.72"/>
|
||||
<text text-anchor="middle" x="1252.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="M1007.33,-319.69C986.73,-315.08 964,-310 964,-310 964,-310 553,-255 553,-255 553,-255 550.57,-254.39 546.54,-253.38"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="546.95,-250.96 539.56,-251.64 545.76,-255.72 546.95,-250.96"/>
|
||||
<text text-anchor="middle" x="792.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M885.32,-320.57C883.27,-319.6 882,-319 882,-319 882,-319 740,-296 740,-296 740,-296 708,-278 708,-278 708,-278 554,-255 554,-255 554,-255 551.14,-254.29 546.46,-253.14"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="547.02,-250.75 539.63,-251.45 545.84,-255.51 547.02,-250.75"/>
|
||||
<text text-anchor="middle" x="749.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="M1656.5,-255C1656.5,-255 1451.5,-255 1451.5,-255 1445.5,-255 1439.5,-249 1439.5,-243 1439.5,-243 1439.5,-222 1439.5,-222 1439.5,-216 1445.5,-210 1451.5,-210 1451.5,-210 1656.5,-210 1656.5,-210 1662.5,-210 1668.5,-216 1668.5,-222 1668.5,-222 1668.5,-243 1668.5,-243 1668.5,-249 1662.5,-255 1656.5,-255"/>
|
||||
<text text-anchor="middle" x="1554" y="-241" font-family="Arial" font-size="10.00" fill="#111827">RIBP target wrapper</text>
|
||||
<text text-anchor="middle" x="1554" 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="1554" y="-219" font-family="Arial" font-size="10.00" fill="#111827">GPIO, UART0, I2C and I2S</text>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M1235.5,-255C1235.5,-255 1030.5,-255 1030.5,-255 1024.5,-255 1018.5,-249 1018.5,-243 1018.5,-243 1018.5,-222 1018.5,-222 1018.5,-216 1024.5,-210 1030.5,-210 1030.5,-210 1235.5,-210 1235.5,-210 1241.5,-210 1247.5,-216 1247.5,-222 1247.5,-222 1247.5,-243 1247.5,-243 1247.5,-249 1241.5,-255 1235.5,-255"/>
|
||||
<text text-anchor="middle" x="1133" y="-241" font-family="Arial" font-size="10.00" fill="#111827">RIBP target wrapper</text>
|
||||
<text text-anchor="middle" x="1133" 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="1133" y="-219" font-family="Arial" font-size="10.00" fill="#111827">UART0, I2C and 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="M1072.54,-321.08C1143.35,-308.2 1314.49,-277.07 1432.4,-255.62"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1432.94,-258.01 1439.39,-254.35 1432.06,-253.19 1432.94,-258.01"/>
|
||||
<text text-anchor="middle" x="1306.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M950.65,-320.43C985.33,-303.9 1040.64,-277.53 1081.26,-258.17"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1082.38,-260.35 1087.65,-255.12 1080.28,-255.92 1082.38,-260.35"/>
|
||||
<text text-anchor="middle" x="1047.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- gpio_controller -->
|
||||
<g id="node19" class="node">
|
||||
<title>gpio_controller</title>
|
||||
<path fill="#f9e1e7" stroke="#4b5563" stroke-width="1.1" d="M914,-255C914,-255 764,-255 764,-255 758,-255 752,-249 752,-243 752,-243 752,-222 752,-222 752,-216 758,-210 764,-210 764,-210 914,-210 914,-210 920,-210 926,-216 926,-222 926,-222 926,-243 926,-243 926,-249 920,-255 914,-255"/>
|
||||
<text text-anchor="middle" x="839" y="-241" font-family="Arial" font-size="10.00" fill="#111827">GPIO V2</text>
|
||||
<text text-anchor="middle" x="839" y="-230" font-family="Arial" font-size="10.00" fill="#111827">user + management RIBP windows</text>
|
||||
<text text-anchor="middle" x="839" 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="edge20" class="edge">
|
||||
<title>ribp_adapter->gpio_controller</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M904.6,-318.61C892.5,-302.91 874.48,-279.53 860.38,-261.25"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="861.98,-259.31 855.77,-255.26 858.1,-262.3 861.98,-259.31"/>
|
||||
<text text-anchor="middle" x="905" y="-289.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<text text-anchor="middle" x="905" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">user/admin</text>
|
||||
</g>
|
||||
<!-- ribp_adapter->timers -->
|
||||
<g id="edge20" class="edge">
|
||||
<g id="edge21" class="edge">
|
||||
<title>ribp_adapter->timers</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1007.42,-318.91C960.37,-307.22 879,-287 879,-287 879,-287 817,-271.21 760.38,-256.78"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="760.9,-254.38 753.51,-255.03 759.69,-259.13 760.9,-254.38"/>
|
||||
<text text-anchor="middle" x="888.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M950.61,-332.27C1037.5,-322.34 1268,-296 1268,-296 1268,-296 1387.71,-272.84 1481.38,-254.71"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1481.95,-257.1 1488.36,-253.36 1481.02,-252.29 1481.95,-257.1"/>
|
||||
<text text-anchor="middle" x="1363.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- ribp_adapter->ws2812 -->
|
||||
<g id="edge21" class="edge">
|
||||
<g id="edge22" class="edge">
|
||||
<title>ribp_adapter->ws2812</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1072.76,-316.55C1117.4,-302.3 1198.65,-276.37 1258.52,-257.27"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1259.42,-259.55 1265.35,-255.09 1257.93,-254.88 1259.42,-259.55"/>
|
||||
<text text-anchor="middle" x="1195.5" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M885.46,-323.74C842.24,-307.45 764.93,-278.32 709.85,-257.56"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="710.66,-255.25 703.25,-255.07 708.94,-259.84 710.66,-255.25"/>
|
||||
<text text-anchor="middle" x="815.5" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">RIBP</text>
|
||||
</g>
|
||||
<!-- apb_targets -->
|
||||
<g id="node21" class="node">
|
||||
<g id="node22" class="node">
|
||||
<title>apb_targets</title>
|
||||
<path fill="#e6f4ea" stroke="#4b5563" stroke-width="1.1" d="M1001.5,-255C1001.5,-255 810.5,-255 810.5,-255 804.5,-255 798.5,-249 798.5,-243 798.5,-243 798.5,-222 798.5,-222 798.5,-216 804.5,-210 810.5,-210 810.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="906" y="-241" font-family="Arial" font-size="10.00" fill="#111827">APB target wrapper</text>
|
||||
<text text-anchor="middle" x="906" y="-230" font-family="Arial" font-size="10.00" fill="#111827">Archinfo, RNG, UART1, PWM, PS/2, RTC</text>
|
||||
<text text-anchor="middle" x="906" y="-219" font-family="Arial" font-size="10.00" fill="#111827">watchdog, CRC, advanced timer and user IP</text>
|
||||
<path fill="#e6f4ea" stroke="#4b5563" stroke-width="1.1" d="M1923.5,-255C1923.5,-255 1732.5,-255 1732.5,-255 1726.5,-255 1720.5,-249 1720.5,-243 1720.5,-243 1720.5,-222 1720.5,-222 1720.5,-216 1726.5,-210 1732.5,-210 1732.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="1828" y="-241" font-family="Arial" font-size="10.00" fill="#111827">APB target wrapper</text>
|
||||
<text text-anchor="middle" x="1828" y="-230" font-family="Arial" font-size="10.00" fill="#111827">Archinfo, RNG, UART1, PWM, PS/2, RTC</text>
|
||||
<text text-anchor="middle" x="1828" 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="edge22" class="edge">
|
||||
<g id="edge23" class="edge">
|
||||
<title>apb_adapter->apb_targets</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M903.55,-309.85C903.97,-296.62 904.57,-278.02 905.07,-262.49"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="907.53,-262.22 905.31,-255.15 902.63,-262.07 907.53,-262.22"/>
|
||||
<text text-anchor="middle" x="912" y="-280.6" font-family="Arial" font-size="8.00" fill="#374151">APB</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1407.02,-325.7C1480.36,-309.64 1623.83,-278.22 1722.74,-256.55"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1723.47,-258.9 1729.78,-255.01 1722.42,-254.12 1723.47,-258.9"/>
|
||||
<text text-anchor="middle" x="1630" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">APB</text>
|
||||
</g>
|
||||
<!-- irq -->
|
||||
<g id="node23" class="node">
|
||||
<g id="node24" class="node">
|
||||
<title>irq</title>
|
||||
<path fill="#fce7f3" stroke="#4b5563" stroke-width="1.1" d="M772,-155C772,-155 566,-155 566,-155 560,-155 554,-149 554,-143 554,-143 554,-131 554,-131 554,-125 560,-119 566,-119 566,-119 772,-119 772,-119 778,-119 784,-125 784,-131 784,-131 784,-143 784,-143 784,-149 778,-155 772,-155"/>
|
||||
<text text-anchor="middle" x="669" y="-140" font-family="Arial" font-size="10.00" fill="#111827">Interrupt aggregation</text>
|
||||
<text text-anchor="middle" x="669" 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="M749,-155C749,-155 543,-155 543,-155 537,-155 531,-149 531,-143 531,-143 531,-131 531,-131 531,-125 537,-119 543,-119 543,-119 749,-119 749,-119 755,-119 761,-125 761,-131 761,-131 761,-143 761,-143 761,-149 755,-155 749,-155"/>
|
||||
<text text-anchor="middle" x="646" y="-140" font-family="Arial" font-size="10.00" fill="#111827">Interrupt aggregation</text>
|
||||
<text text-anchor="middle" x="646" 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="edge25" class="edge">
|
||||
<g id="edge28" class="edge">
|
||||
<title>clint->irq</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M513.6,-209.93C547.35,-194.31 592.66,-173.34 625.64,-158.07"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="626.74,-160.26 632.06,-155.1 624.68,-155.81 626.74,-160.26"/>
|
||||
<text text-anchor="middle" x="618.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="M505.77,-209.89C532.41,-195.05 563,-178 563,-178 563,-178 583.39,-168.18 603.95,-158.26"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="605.08,-160.44 610.32,-155.2 602.95,-156.03 605.08,-160.44"/>
|
||||
<text text-anchor="middle" x="601.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">machine IRQ0 / IRQ1</text>
|
||||
</g>
|
||||
<!-- ribp_targets->ext_io -->
|
||||
<g id="edge30" class="edge">
|
||||
<g id="edge33" class="edge">
|
||||
<title>ribp_targets->ext_io</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1541.78,-203.07C1536.28,-190.28 1531,-178 1531,-178 1531,-178 1494.07,-96.48 1473.85,-51.87"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1539.63,-204.28 1544.65,-209.74 1544.13,-202.34 1539.63,-204.28"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1476,-50.67 1470.88,-45.31 1471.54,-52.7 1476,-50.67"/>
|
||||
<text text-anchor="middle" x="1550" 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="M1111.03,-203.97C1079.15,-164.03 1020.42,-90.44 988.7,-50.69"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1109.27,-205.69 1115.55,-209.63 1113.1,-202.63 1109.27,-205.69"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="990.5,-49.02 984.22,-45.07 986.67,-52.07 990.5,-49.02"/>
|
||||
<text text-anchor="middle" x="1101" y="-135.1" font-family="Arial" font-size="8.00" fill="#374151">device interfaces</text>
|
||||
</g>
|
||||
<!-- ribp_targets->gpio_controller -->
|
||||
<g id="edge24" class="edge">
|
||||
<title>ribp_targets->gpio_controller</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1018.39,-232.5C990.19,-232.5 960.32,-232.5 933.21,-232.5"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="933.02,-230.05 926.02,-232.5 933.02,-234.95 933.02,-230.05"/>
|
||||
<text text-anchor="middle" x="972.25" y="-238.1" font-family="Arial" font-size="8.00" fill="#374151">alternate functions</text>
|
||||
</g>
|
||||
<!-- gpio_bridge -->
|
||||
<g id="node22" class="node">
|
||||
<g id="node23" class="node">
|
||||
<title>gpio_bridge</title>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M1448,-155C1448,-155 1300,-155 1300,-155 1294,-155 1288,-149 1288,-143 1288,-143 1288,-131 1288,-131 1288,-125 1294,-119 1300,-119 1300,-119 1448,-119 1448,-119 1454,-119 1460,-125 1460,-131 1460,-131 1460,-143 1460,-143 1460,-149 1454,-155 1448,-155"/>
|
||||
<text text-anchor="middle" x="1374" y="-140" font-family="Arial" font-size="10.00" fill="#111827">GPIO pad bridge</text>
|
||||
<text text-anchor="middle" x="1374" y="-129" font-family="Arial" font-size="10.00" fill="#111827">software, alternate and user modes</text>
|
||||
<path fill="#e5e7eb" stroke="#4b5563" stroke-width="1.1" d="M935.5,-155C935.5,-155 800.5,-155 800.5,-155 794.5,-155 788.5,-149 788.5,-143 788.5,-143 788.5,-131 788.5,-131 788.5,-125 794.5,-119 800.5,-119 800.5,-119 935.5,-119 935.5,-119 941.5,-119 947.5,-125 947.5,-131 947.5,-131 947.5,-143 947.5,-143 947.5,-149 941.5,-155 935.5,-155"/>
|
||||
<text text-anchor="middle" x="868" y="-140" font-family="Arial" font-size="10.00" fill="#111827">GPIO pad bridge</text>
|
||||
<text text-anchor="middle" x="868" y="-129" font-family="Arial" font-size="10.00" fill="#111827">PDK capability-adapted controls</text>
|
||||
</g>
|
||||
<!-- ribp_targets->gpio_bridge -->
|
||||
<g id="edge23" class="edge">
|
||||
<title>ribp_targets->gpio_bridge</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1499.16,-209.9C1470.36,-198.56 1441,-187 1441,-187 1441,-187 1421.43,-172.69 1403.44,-159.53"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1404.53,-157.29 1397.43,-155.14 1401.64,-161.25 1404.53,-157.29"/>
|
||||
<text text-anchor="middle" x="1485" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO alternate functions</text>
|
||||
<!-- gpio_controller->gpio_bridge -->
|
||||
<g id="edge25" class="edge">
|
||||
<title>gpio_controller->gpio_bridge</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M845.73,-209.81C850.15,-195.54 855.96,-176.83 860.53,-162.09"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="862.93,-162.62 862.66,-155.2 858.25,-161.16 862.93,-162.62"/>
|
||||
<text text-anchor="middle" x="875" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
|
||||
</g>
|
||||
<!-- gpio_controller->irq -->
|
||||
<g id="edge26" class="edge">
|
||||
<title>gpio_controller->irq</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M780.27,-209.9C749.44,-198.56 718,-187 718,-187 718,-187 696.6,-172.44 677.14,-159.19"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="678.35,-157.05 671.18,-155.14 675.59,-161.1 678.35,-157.05"/>
|
||||
<text text-anchor="middle" x="730" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ18</text>
|
||||
</g>
|
||||
<!-- timers->irq -->
|
||||
<g id="edge24" class="edge">
|
||||
<g id="edge27" class="edge">
|
||||
<title>timers->irq</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M669,-209.81C669,-195.66 669,-177.17 669,-162.49"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="671.45,-162.2 669,-155.2 666.55,-162.2 671.45,-162.2"/>
|
||||
<text text-anchor="middle" x="691.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="M1488.31,-212.47C1480.16,-210.96 1475,-210 1475,-210 1475,-210 775,-155 775,-155 775,-155 772.48,-154.67 768.16,-154.1"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="768.45,-151.67 761.19,-153.18 767.81,-156.52 768.45,-151.67"/>
|
||||
<text text-anchor="middle" x="1188.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ3 / IRQ4</text>
|
||||
</g>
|
||||
<!-- ws2812->gpio_bridge -->
|
||||
<g id="edge26" class="edge">
|
||||
<g id="edge29" class="edge">
|
||||
<title>ws2812->gpio_bridge</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1341.95,-209.74C1348.04,-194.93 1355,-178 1355,-178 1355,-178 1358.68,-170.25 1362.8,-161.58"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1365.04,-162.57 1365.83,-155.2 1360.62,-160.47 1365.04,-162.57"/>
|
||||
<text text-anchor="middle" x="1377.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="M697.21,-209.93C734.46,-194.24 784.51,-173.16 820.8,-157.88"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="821.91,-160.07 827.41,-155.1 820,-155.56 821.91,-160.07"/>
|
||||
<text text-anchor="middle" x="792.5" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">GPIO2 ALT1</text>
|
||||
</g>
|
||||
<!-- ws2812->irq -->
|
||||
<g id="edge28" class="edge">
|
||||
<g id="edge31" class="edge">
|
||||
<title>ws2812->irq</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1253.79,-212.99C1246.05,-211.18 1241,-210 1241,-210 1241,-210 959.53,-174.57 791.48,-153.42"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="791.32,-150.93 784.06,-152.48 790.7,-155.79 791.32,-150.93"/>
|
||||
<text text-anchor="middle" x="1067" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ17</text>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M646,-209.81C646,-195.66 646,-177.17 646,-162.49"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="648.45,-162.2 646,-155.2 643.55,-162.2 648.45,-162.2"/>
|
||||
<text text-anchor="middle" x="658" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">IRQ17</text>
|
||||
</g>
|
||||
<!-- apb_targets->gpio_bridge -->
|
||||
<g id="edge29" class="edge">
|
||||
<title>apb_targets->gpio_bridge</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1013.66,-209.99C1094.75,-193.79 1204.75,-171.81 1281.8,-156.42"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1282.3,-158.82 1288.69,-155.04 1281.34,-154.01 1282.3,-158.82"/>
|
||||
<text text-anchor="middle" x="1186" y="-180.6" font-family="Arial" font-size="8.00" fill="#374151">user_gpio</text>
|
||||
<!-- apb_targets->gpio_controller -->
|
||||
<g id="edge32" class="edge">
|
||||
<title>apb_targets->gpio_controller</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1720.41,-252.51C1712.19,-254.04 1707,-255 1707,-255 1707,-255 1192,-282.5 1192,-282.5 1192,-282.5 1156,-282.5 1156,-282.5 1156,-282.5 1026.45,-262.07 932.99,-247.32"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="933.34,-244.9 926.04,-246.23 932.57,-249.74 933.34,-244.9"/>
|
||||
<text text-anchor="middle" x="1174" y="-285.1" font-family="Arial" font-size="8.00" fill="#374151">user_gpio</text>
|
||||
</g>
|
||||
<!-- gpio_bridge->ext_io -->
|
||||
<g id="edge31" class="edge">
|
||||
<g id="edge34" class="edge">
|
||||
<title>gpio_bridge->ext_io</title>
|
||||
<path fill="none" stroke="#4b5563" stroke-width="1.2" d="M1391.54,-113.32C1405.42,-95.37 1424.86,-70.24 1439.64,-51.12"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1389.56,-111.88 1387.21,-118.91 1393.43,-114.88 1389.56,-111.88"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="1441.73,-52.43 1444.07,-45.39 1437.85,-49.43 1441.73,-52.43"/>
|
||||
<text text-anchor="middle" x="1445" 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="M887.73,-113.58C903.67,-95.47 926.16,-69.91 943.11,-50.65"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="885.82,-112.04 883.04,-118.91 889.5,-115.28 885.82,-112.04"/>
|
||||
<polygon fill="#4b5563" stroke="#4b5563" stroke-width="1.2" points="944.95,-52.26 947.74,-45.39 941.27,-49.03 944.95,-52.26"/>
|
||||
<text text-anchor="middle" x="946" y="-70.6" font-family="Arial" font-size="8.00" fill="#374151">pad control</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 37 KiB |
@@ -56,17 +56,24 @@ them to the local remote-bitbang server used by the debug acceptance flow.
|
||||
|
||||
The fixed user-IP integration does not add dedicated user GPIO pads. A user IP
|
||||
can instead drive any of the 32 rib GPIO pads through `user_gpio_if`. Software
|
||||
selects an owner per pin with the rib GPIO `USER_SEL` register at offset
|
||||
`0x30`; clear selects the existing software/alternate GPIO path and set selects
|
||||
the user IP. `USER_LOCK` at `0x34` is write-one-set and prevents a selected
|
||||
owner bit from changing until reset. `USER_STATUS` at `0x38` reports the user
|
||||
IP pins that are actively connected.
|
||||
selects an owner per pin with `USER_SELECT` at management-window offset
|
||||
`0x03C`; clear selects the existing software/alternate GPIO path and set
|
||||
selects the user IP. `USER_LOCK` at `0x040` is write-one-set and prevents a
|
||||
selected owner bit from changing until reset. `USER_STATUS` at `0x044` reports
|
||||
the user-IP pins that are actively connected.
|
||||
|
||||
On every accepted ownership change, the pad output enable is forced low for one
|
||||
full system clock. The rib GPIO block retains `CS`, `PU`, and `PD` control
|
||||
in all modes. User IPs provide only output data, output enable, and sampled pad
|
||||
input. Configure the target output data and enable before writing `USER_SEL`,
|
||||
then program `USER_LOCK` after the handoff when the assignment is permanent.
|
||||
full system clock. The GPIO block retains input-mode, pull, open-drain, filter,
|
||||
and interrupt control in all modes. User IPs provide only output data, output
|
||||
enable, and synchronized/filtered pad input. Configure the target output data
|
||||
and enable before writing `USER_SELECT`, then program `USER_LOCK` after the
|
||||
handoff when the assignment is permanent.
|
||||
|
||||
The user core accesses only the data and interrupt window at `0x10000000`, and
|
||||
only bits permitted by management `USER_ACCESS_MASK`. Configuration remains in
|
||||
the management-only window at `0x10014000`; the SoC access firewall denies user
|
||||
transactions to that region. See [gpio.md](ip/gpio.md) for the complete ABI,
|
||||
PDK capabilities, and lock semantics.
|
||||
|
||||
User-IP RTL must declare its GPIO port as `user_gpio_if.user_ip gpio`; the only
|
||||
signals available through that port are `do_o`, `oe_o`, and `di_i`. The MPW
|
||||
|
||||
@@ -1,386 +0,0 @@
|
||||
/*
|
||||
* Ravenna - A full example SoC using PicoRV32 in ASIC
|
||||
*
|
||||
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
|
||||
* Copyright (C) 2018,2019 Tim Edwards <tim@efabless.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
// -- Adaptable modifications are redistributed under compatible License --
|
||||
//
|
||||
// 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.
|
||||
|
||||
`include "gpio_define.svh"
|
||||
|
||||
interface gpio_if #(
|
||||
parameter int DATA_WIDTH = `RIBP_GPIO_NUM
|
||||
) ();
|
||||
logic [DATA_WIDTH-1:0] oe_o;
|
||||
logic [DATA_WIDTH-1:0] cs_o;
|
||||
logic [DATA_WIDTH-1:0] pu_o;
|
||||
logic [DATA_WIDTH-1:0] pd_o;
|
||||
logic [DATA_WIDTH-1:0] do_o;
|
||||
logic [DATA_WIDTH-1:0] di_i;
|
||||
logic [DATA_WIDTH-1:0] alt0_do_i;
|
||||
logic [DATA_WIDTH-1:0] alt0_oe_i;
|
||||
logic [DATA_WIDTH-1:0] alt1_do_i;
|
||||
logic [DATA_WIDTH-1:0] alt1_oe_i;
|
||||
logic irq_o;
|
||||
|
||||
modport dut(
|
||||
output oe_o,
|
||||
output cs_o,
|
||||
output pu_o,
|
||||
output pd_o,
|
||||
output do_o,
|
||||
input di_i,
|
||||
input alt0_do_i,
|
||||
input alt0_oe_i,
|
||||
input alt1_do_i,
|
||||
input alt1_oe_i,
|
||||
output irq_o
|
||||
);
|
||||
|
||||
modport pad(input oe_o, input cs_o, input pu_o, input pd_o, input do_o, output di_i);
|
||||
|
||||
modport soc_pad(output oe_o, output cs_o, output pu_o, output pd_o, output do_o, input di_i);
|
||||
endinterface
|
||||
|
||||
interface user_gpio_if #(
|
||||
parameter int DATA_WIDTH = `RIBP_GPIO_NUM
|
||||
) ();
|
||||
logic [DATA_WIDTH-1:0] do_o;
|
||||
logic [DATA_WIDTH-1:0] oe_o;
|
||||
logic [DATA_WIDTH-1:0] di_i;
|
||||
|
||||
modport user_ip(output do_o, output oe_o, input di_i);
|
||||
modport padctrl(input do_o, input oe_o, output di_i);
|
||||
endinterface
|
||||
|
||||
module ribp_gpio (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
ribp_if.slave ribp,
|
||||
gpio_if.dut gpio,
|
||||
user_gpio_if.padctrl user_gpio
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
// ribp
|
||||
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;
|
||||
// reg
|
||||
logic s_gpio_oe_en;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_oe_d, s_gpio_oe_q;
|
||||
logic s_gpio_cs_en;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_cs_d, s_gpio_cs_q;
|
||||
logic s_gpio_pu_en;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_pu_d, s_gpio_pu_q;
|
||||
logic s_gpio_pd_en;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_pd_d, s_gpio_pd_q;
|
||||
logic s_gpio_do_en;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_do_d, s_gpio_do_q;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_di;
|
||||
logic s_gpio_ien_en;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_ien_d, s_gpio_ien_q;
|
||||
logic s_gpio_itype0_en;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_itype0_d, s_gpio_itype0_q;
|
||||
logic s_gpio_itype1_en;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_itype1_d, s_gpio_itype1_q;
|
||||
logic s_gpio_istat_en;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_istat_d, s_gpio_istat_q;
|
||||
logic s_gpio_iofcfg_en;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_iofcfg_d, s_gpio_iofcfg_q;
|
||||
logic s_gpio_pinmux_en;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_pinmux_d, s_gpio_pinmux_q;
|
||||
logic s_gpio_user_sel_en;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_user_sel_d, s_gpio_user_sel_q;
|
||||
logic s_gpio_user_lock_en;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_user_lock_d, s_gpio_user_lock_q;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_user_handoff_d, s_gpio_user_handoff_q;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_user_status;
|
||||
// irq
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_di_re, s_gpio_di_fe, s_gpio_irq;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_irq_rise, s_irq_fall;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_irq_lev0, s_irq_lev1;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_irq_masked;
|
||||
logic s_irq_trg, s_irq_stat;
|
||||
// alt
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_alt_out, s_gpio_alt_oe;
|
||||
logic [`RIBP_GPIO_NUM-1:0] s_gpio_native_out, s_gpio_native_oe;
|
||||
|
||||
// shake
|
||||
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;
|
||||
// gpio
|
||||
assign gpio.cs_o = s_gpio_cs_q; // 1: CMOS 0: SCHMI
|
||||
assign gpio.pu_o = s_gpio_pu_q;
|
||||
assign gpio.pd_o = s_gpio_pd_q;
|
||||
for (genvar i = 0; i < `RIBP_GPIO_NUM; i++) begin : ALT_PINMUX_BLOCK
|
||||
assign s_gpio_alt_oe[i] = s_gpio_pinmux_q[i] ? gpio.alt1_oe_i[i] : gpio.alt0_oe_i[i];
|
||||
assign s_gpio_alt_out[i] = s_gpio_pinmux_q[i] ? gpio.alt1_do_i[i] : gpio.alt0_do_i[i];
|
||||
end
|
||||
for (genvar i = 0; i < `RIBP_GPIO_NUM; i++) begin : IOF_PINMUX_BLOCK
|
||||
assign s_gpio_native_oe[i] = s_gpio_iofcfg_q[i] ? s_gpio_alt_oe[i] : s_gpio_oe_q[i];
|
||||
assign s_gpio_native_out[i] = s_gpio_iofcfg_q[i] ? s_gpio_alt_out[i] : s_gpio_do_q[i];
|
||||
end
|
||||
assign user_gpio.di_i = gpio.di_i;
|
||||
for (genvar i = 0; i < `RIBP_GPIO_NUM; i++) begin : USER_GPIO_MUX_BLOCK
|
||||
assign gpio.oe_o[i] = s_gpio_user_handoff_q[i]
|
||||
? 1'b0
|
||||
: (s_gpio_user_sel_q[i] ? user_gpio.oe_o[i] : s_gpio_native_oe[i]);
|
||||
assign gpio.do_o[i] = s_gpio_user_sel_q[i] ? user_gpio.do_o[i] : s_gpio_native_out[i];
|
||||
end
|
||||
assign s_irq_stat = |s_gpio_istat_q;
|
||||
assign gpio.irq_o = s_irq_stat;
|
||||
|
||||
// verilog_format: off
|
||||
// irq
|
||||
assign s_irq_rise = (~s_gpio_itype1_q & ~s_gpio_itype0_q) & s_gpio_di_re;
|
||||
assign s_irq_fall = (~s_gpio_itype1_q & s_gpio_itype0_q) & s_gpio_di_fe;
|
||||
assign s_irq_lev0 = (s_gpio_itype1_q & ~s_gpio_itype0_q) & ~s_gpio_di;
|
||||
assign s_irq_lev1 = (s_gpio_itype1_q & s_gpio_itype0_q) & s_gpio_di;
|
||||
assign s_gpio_irq = s_irq_rise | s_irq_fall | s_irq_lev0 | s_irq_lev1;
|
||||
assign s_irq_masked = s_gpio_ien_q & s_gpio_irq;
|
||||
assign s_irq_trg = |s_irq_masked;
|
||||
// verilog_format: on
|
||||
|
||||
edge_det #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(`RIBP_GPIO_NUM)
|
||||
) u_gpio_di_edge_det (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (gpio.di_i),
|
||||
.dat_o (s_gpio_di),
|
||||
.re_o (s_gpio_di_re),
|
||||
.fe_o (s_gpio_di_fe)
|
||||
);
|
||||
|
||||
// register
|
||||
assign s_gpio_oe_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_GPIO_OE;
|
||||
assign s_gpio_oe_d = ribp.wdata[`RIBP_GPIO_NUM-1:0];
|
||||
dffer #(`RIBP_GPIO_NUM) u_gpio_oe_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_oe_en,
|
||||
s_gpio_oe_d,
|
||||
s_gpio_oe_q
|
||||
);
|
||||
|
||||
|
||||
assign s_gpio_cs_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_GPIO_CS;
|
||||
assign s_gpio_cs_d = ribp.wdata[`RIBP_GPIO_NUM-1:0];
|
||||
dffer #(`RIBP_GPIO_NUM) u_gpio_cs_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_cs_en,
|
||||
s_gpio_cs_d,
|
||||
s_gpio_cs_q
|
||||
);
|
||||
|
||||
|
||||
assign s_gpio_pu_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_GPIO_PU;
|
||||
assign s_gpio_pu_d = ribp.wdata[`RIBP_GPIO_NUM-1:0];
|
||||
dffer #(`RIBP_GPIO_NUM) u_gpio_pu_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_pu_en,
|
||||
s_gpio_pu_d,
|
||||
s_gpio_pu_q
|
||||
);
|
||||
|
||||
|
||||
assign s_gpio_pd_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_GPIO_PD;
|
||||
assign s_gpio_pd_d = ribp.wdata[`RIBP_GPIO_NUM-1:0];
|
||||
dffer #(`RIBP_GPIO_NUM) u_gpio_pd_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_pd_en,
|
||||
s_gpio_pd_d,
|
||||
s_gpio_pd_q
|
||||
);
|
||||
|
||||
|
||||
assign s_gpio_do_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_GPIO_DO;
|
||||
assign s_gpio_do_d = ribp.wdata[`RIBP_GPIO_NUM-1:0];
|
||||
dffer #(`RIBP_GPIO_NUM) u_gpio_do_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_do_en,
|
||||
s_gpio_do_d,
|
||||
s_gpio_do_q
|
||||
);
|
||||
|
||||
|
||||
assign s_gpio_ien_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_GPIO_IEN;
|
||||
assign s_gpio_ien_d = ribp.wdata[`RIBP_GPIO_NUM-1:0];
|
||||
dffer #(`RIBP_GPIO_NUM) u_gpio_ien_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_ien_en,
|
||||
s_gpio_ien_d,
|
||||
s_gpio_ien_q
|
||||
);
|
||||
|
||||
|
||||
assign s_gpio_itype0_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_GPIO_ITYPE0;
|
||||
assign s_gpio_itype0_d = ribp.wdata[`RIBP_GPIO_NUM-1:0];
|
||||
dffer #(`RIBP_GPIO_NUM) u_gpio_itype0_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_itype0_en,
|
||||
s_gpio_itype0_d,
|
||||
s_gpio_itype0_q
|
||||
);
|
||||
|
||||
|
||||
assign s_gpio_itype1_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_GPIO_ITYPE1;
|
||||
assign s_gpio_itype1_d = ribp.wdata[`RIBP_GPIO_NUM-1:0];
|
||||
dffer #(`RIBP_GPIO_NUM) u_gpio_itype1_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_itype1_en,
|
||||
s_gpio_itype1_d,
|
||||
s_gpio_itype1_q
|
||||
);
|
||||
|
||||
|
||||
assign s_gpio_iofcfg_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_GPIO_IOFCFG;
|
||||
assign s_gpio_iofcfg_d = ribp.wdata[`RIBP_GPIO_NUM-1:0];
|
||||
dffer #(`RIBP_GPIO_NUM) u_gpio_iocfg_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_iofcfg_en,
|
||||
s_gpio_iofcfg_d,
|
||||
s_gpio_iofcfg_q
|
||||
);
|
||||
|
||||
|
||||
always_comb begin
|
||||
s_gpio_istat_en = 1'b0;
|
||||
s_gpio_istat_d = s_gpio_istat_q;
|
||||
if (s_irq_stat && s_ribp_rd_hdshk && ribp.addr[7:0] == `RIBP_GPIO_ISTAT) begin
|
||||
s_gpio_istat_en = 1'b1;
|
||||
// HACK: clear all irq
|
||||
s_gpio_istat_d = '0;
|
||||
end else if (~s_irq_stat && s_irq_trg) begin
|
||||
s_gpio_istat_en = 1'b1;
|
||||
s_gpio_istat_d = s_irq_masked;
|
||||
end
|
||||
end
|
||||
dffer #(`RIBP_GPIO_NUM) u_gpio_istat_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_istat_en,
|
||||
s_gpio_istat_d,
|
||||
s_gpio_istat_q
|
||||
);
|
||||
|
||||
|
||||
assign s_gpio_pinmux_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_GPIO_PINMUX;
|
||||
assign s_gpio_pinmux_d = ribp.wdata[`RIBP_GPIO_NUM-1:0];
|
||||
dffer #(`RIBP_GPIO_NUM) u_gpio_pinmux_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_pinmux_en,
|
||||
s_gpio_pinmux_d,
|
||||
s_gpio_pinmux_q
|
||||
);
|
||||
|
||||
assign s_gpio_user_sel_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_GPIO_USER_SEL;
|
||||
assign s_gpio_user_sel_d = (s_gpio_user_sel_q & s_gpio_user_lock_q) |
|
||||
(ribp.wdata[`RIBP_GPIO_NUM-1:0] & ~s_gpio_user_lock_q);
|
||||
dffer #(`RIBP_GPIO_NUM) u_gpio_user_sel_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_user_sel_en,
|
||||
s_gpio_user_sel_d,
|
||||
s_gpio_user_sel_q
|
||||
);
|
||||
|
||||
assign s_gpio_user_lock_en = s_ribp_wr_hdshk && ribp.addr[7:0] == `RIBP_GPIO_USER_LOCK;
|
||||
assign s_gpio_user_lock_d = s_gpio_user_lock_q | ribp.wdata[`RIBP_GPIO_NUM-1:0];
|
||||
dffer #(`RIBP_GPIO_NUM) u_gpio_user_lock_dffer (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_user_lock_en,
|
||||
s_gpio_user_lock_d,
|
||||
s_gpio_user_lock_q
|
||||
);
|
||||
|
||||
assign s_gpio_user_handoff_d = s_gpio_user_sel_en ? (s_gpio_user_sel_d ^ s_gpio_user_sel_q) : '0;
|
||||
dffr #(`RIBP_GPIO_NUM) u_gpio_user_handoff_dffr (
|
||||
clk_i,
|
||||
rst_n_i,
|
||||
s_gpio_user_handoff_d,
|
||||
s_gpio_user_handoff_q
|
||||
);
|
||||
assign s_gpio_user_status = s_gpio_user_sel_q & ~s_gpio_user_handoff_q;
|
||||
|
||||
|
||||
// ribp resp
|
||||
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_GPIO_OE: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_oe_q};
|
||||
`RIBP_GPIO_CS: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_cs_q};
|
||||
`RIBP_GPIO_PU: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_pu_q};
|
||||
`RIBP_GPIO_PD: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_pd_q};
|
||||
`RIBP_GPIO_DO: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_do_q};
|
||||
`RIBP_GPIO_DI: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_di};
|
||||
`RIBP_GPIO_IEN: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_ien_q};
|
||||
`RIBP_GPIO_ITYPE0: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_itype0_q};
|
||||
`RIBP_GPIO_ITYPE1: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_itype1_q};
|
||||
`RIBP_GPIO_ISTAT: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_istat_q};
|
||||
`RIBP_GPIO_IOFCFG: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_iofcfg_q};
|
||||
`RIBP_GPIO_PINMUX: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_pinmux_q};
|
||||
`RIBP_GPIO_USER_SEL: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_user_sel_q};
|
||||
`RIBP_GPIO_USER_LOCK: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_user_lock_q};
|
||||
`RIBP_GPIO_USER_STATUS: s_ribp_rdata_d = {{(32 - `RIBP_GPIO_NUM) {1'b0}}, s_gpio_user_status};
|
||||
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
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,147 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module gpio_core #(
|
||||
parameter int PIN_NUM = 32
|
||||
) (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
input logic [PIN_NUM-1:0] data_out_i,
|
||||
input logic [PIN_NUM-1:0] output_enable_i,
|
||||
input logic [PIN_NUM-1:0] open_drain_i,
|
||||
input logic [PIN_NUM-1:0] input_cmos_i,
|
||||
input logic [PIN_NUM-1:0] pull_up_i,
|
||||
input logic [PIN_NUM-1:0] pull_down_i,
|
||||
input logic [PIN_NUM-1:0] alt_enable_i,
|
||||
input logic [PIN_NUM-1:0] alt_select_i,
|
||||
input logic [PIN_NUM-1:0] user_select_i,
|
||||
input logic [PIN_NUM-1:0] user_handoff_i,
|
||||
input logic [PIN_NUM-1:0] filter_enable_i,
|
||||
input logic [15:0] filter_div_i,
|
||||
input logic [3:0] filter_count_i,
|
||||
input logic [PIN_NUM-1:0] intr_rise_enable_i,
|
||||
input logic [PIN_NUM-1:0] intr_fall_enable_i,
|
||||
input logic [PIN_NUM-1:0] intr_high_enable_i,
|
||||
input logic [PIN_NUM-1:0] intr_low_enable_i,
|
||||
input logic irq_i,
|
||||
output logic [PIN_NUM-1:0] data_in_o,
|
||||
output logic [PIN_NUM-1:0] intr_event_o,
|
||||
gpio_if.dut gpio,
|
||||
user_gpio_if.padctrl user_gpio
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
logic [ 15:0] s_sample_count;
|
||||
logic s_sample_tick;
|
||||
logic s_sample_overflow;
|
||||
logic [PIN_NUM-1:0] s_input_sync;
|
||||
logic [PIN_NUM-1:0] s_input_filtered_d, s_input_filtered_q;
|
||||
logic [3:0] s_stable_count_d[0:PIN_NUM-1];
|
||||
logic [3:0] s_stable_count_q[0:PIN_NUM-1];
|
||||
logic [PIN_NUM-1:0] s_input_rise, s_input_fall;
|
||||
logic [PIN_NUM-1:0] s_alt_data, s_alt_oe;
|
||||
logic [PIN_NUM-1:0] s_native_data, s_native_oe;
|
||||
logic [PIN_NUM-1:0] s_selected_data, s_selected_oe;
|
||||
|
||||
initial begin
|
||||
if ((PIN_NUM < 1) || (PIN_NUM > 32)) begin
|
||||
$fatal(1, "gpio_core: PIN_NUM must be between 1 and 32");
|
||||
end
|
||||
end
|
||||
|
||||
cdc_sync #(
|
||||
.STAGE (2),
|
||||
.DATA_WIDTH(PIN_NUM)
|
||||
) u_input_cdc_sync (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (gpio.di_i),
|
||||
.dat_o (s_input_sync)
|
||||
);
|
||||
|
||||
assign s_sample_tick = (s_sample_count == 16'd0) && !s_sample_overflow;
|
||||
rs_counter #(
|
||||
.DATA_WIDTH(16)
|
||||
) u_filter_sample_counter (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.clr_i (1'b0),
|
||||
.en_i (!s_sample_tick),
|
||||
.load_i (s_sample_tick),
|
||||
.down_i (1'b1),
|
||||
.dat_i (filter_div_i),
|
||||
.dat_o (s_sample_count),
|
||||
.ovf_o (s_sample_overflow)
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
s_input_filtered_d = s_input_filtered_q;
|
||||
for (int pin = 0; pin < PIN_NUM; pin++) begin
|
||||
s_stable_count_d[pin] = s_stable_count_q[pin];
|
||||
if (!filter_enable_i[pin]) begin
|
||||
s_input_filtered_d[pin] = s_input_sync[pin];
|
||||
s_stable_count_d[pin] = 4'd0;
|
||||
end else if (s_sample_tick) begin
|
||||
if (s_input_sync[pin] == s_input_filtered_q[pin]) begin
|
||||
s_stable_count_d[pin] = 4'd0;
|
||||
end else if ((s_stable_count_q[pin] + 1'b1) >= filter_count_i) begin
|
||||
s_input_filtered_d[pin] = s_input_sync[pin];
|
||||
s_stable_count_d[pin] = 4'd0;
|
||||
end else begin
|
||||
s_stable_count_d[pin] = s_stable_count_q[pin] + 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
dffr #(PIN_NUM) u_input_filtered_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_input_filtered_d),
|
||||
.dat_o (s_input_filtered_q)
|
||||
);
|
||||
for (genvar pin = 0; pin < PIN_NUM; pin++) begin : gen_stable_count
|
||||
dffr #(4) u_stable_count_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_stable_count_d[pin]),
|
||||
.dat_o (s_stable_count_q[pin])
|
||||
);
|
||||
end
|
||||
|
||||
edge_det_sync #(
|
||||
.DATA_WIDTH(PIN_NUM)
|
||||
) u_filtered_edge_det (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_input_filtered_q),
|
||||
.re_o (s_input_rise),
|
||||
.fe_o (s_input_fall)
|
||||
);
|
||||
|
||||
assign data_in_o = s_input_filtered_q;
|
||||
assign user_gpio.di_i = s_input_filtered_q;
|
||||
assign intr_event_o = (s_input_rise & intr_rise_enable_i) |
|
||||
(s_input_fall & intr_fall_enable_i) |
|
||||
(s_input_filtered_q & intr_high_enable_i) |
|
||||
(~s_input_filtered_q & intr_low_enable_i);
|
||||
|
||||
for (genvar pin = 0; pin < PIN_NUM; pin++) begin : gen_output_mux
|
||||
assign s_alt_data[pin] = alt_select_i[pin] ? gpio.alt1_do_i[pin] : gpio.alt0_do_i[pin];
|
||||
assign s_alt_oe[pin] = alt_select_i[pin] ? gpio.alt1_oe_i[pin] : gpio.alt0_oe_i[pin];
|
||||
assign s_native_data[pin] = alt_enable_i[pin] ? s_alt_data[pin] : data_out_i[pin];
|
||||
assign s_native_oe[pin] = alt_enable_i[pin] ? s_alt_oe[pin] : output_enable_i[pin];
|
||||
assign s_selected_data[pin] = user_select_i[pin] ? user_gpio.do_o[pin] : s_native_data[pin];
|
||||
assign s_selected_oe[pin] = user_select_i[pin] ? user_gpio.oe_o[pin] : s_native_oe[pin];
|
||||
assign gpio.do_o[pin] = open_drain_i[pin] ? 1'b0 : s_selected_data[pin];
|
||||
assign gpio.oe_o[pin] = !user_handoff_i[pin] && s_selected_oe[pin] &&
|
||||
!(open_drain_i[pin] && s_selected_data[pin]);
|
||||
end
|
||||
|
||||
assign gpio.cs_o = input_cmos_i;
|
||||
assign gpio.pu_o = pull_up_i;
|
||||
assign gpio.pd_o = pull_down_i;
|
||||
assign gpio.irq_o = irq_i;
|
||||
|
||||
endmodule
|
||||
@@ -1,32 +1,69 @@
|
||||
// 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_GPIO_DEF_SV
|
||||
`define RIBP_GPIO_DEF_SV
|
||||
`ifndef RIBP_GPIO_DEFINE_SVH
|
||||
`define RIBP_GPIO_DEFINE_SVH
|
||||
|
||||
// verilog_format: off
|
||||
`define RIBP_GPIO_NUM 32
|
||||
`define RIBP_GPIO_OE 8'h00 // rw
|
||||
`define RIBP_GPIO_CS 8'h04 // rw
|
||||
`define RIBP_GPIO_PU 8'h08 // rw
|
||||
`define RIBP_GPIO_PD 8'h0C // rw
|
||||
`define RIBP_GPIO_DO 8'h10 // rw
|
||||
`define RIBP_GPIO_DI 8'h14 // ro
|
||||
`define RIBP_GPIO_IEN 8'h18 // rw
|
||||
`define RIBP_GPIO_ITYPE0 8'h1c // rw
|
||||
`define RIBP_GPIO_ITYPE1 8'h20 // rw
|
||||
`define RIBP_GPIO_ISTAT 8'h24 // ro
|
||||
`define RIBP_GPIO_IOFCFG 8'h28 // rw
|
||||
`define RIBP_GPIO_PINMUX 8'h2c // rw
|
||||
`define RIBP_GPIO_USER_SEL 8'h30 // rw
|
||||
`define RIBP_GPIO_USER_LOCK 8'h34 // rw1s
|
||||
`define RIBP_GPIO_USER_STATUS 8'h38 // ro
|
||||
`define RIBP_GPIO_NUM 32
|
||||
|
||||
`define RIBP_GPIO_USER_DATA_IN 12'h000
|
||||
`define RIBP_GPIO_USER_DATA_OUT 12'h004
|
||||
`define RIBP_GPIO_USER_OUT_SET 12'h008
|
||||
`define RIBP_GPIO_USER_OUT_CLEAR 12'h00C
|
||||
`define RIBP_GPIO_USER_OUT_TOGGLE 12'h010
|
||||
`define RIBP_GPIO_USER_INTR_STATE 12'h014
|
||||
`define RIBP_GPIO_USER_INTR_STATUS 12'h018
|
||||
`define RIBP_GPIO_USER_INTR_ENABLE 12'h01C
|
||||
`define RIBP_GPIO_USER_INTR_ENABLE_SET 12'h020
|
||||
`define RIBP_GPIO_USER_INTR_ENABLE_CLEAR 12'h024
|
||||
|
||||
`define RIBP_GPIO_ADMIN_DATA_IN 12'h000
|
||||
`define RIBP_GPIO_ADMIN_DATA_OUT 12'h004
|
||||
`define RIBP_GPIO_ADMIN_OUT_SET 12'h008
|
||||
`define RIBP_GPIO_ADMIN_OUT_CLEAR 12'h00C
|
||||
`define RIBP_GPIO_ADMIN_OUT_TOGGLE 12'h010
|
||||
`define RIBP_GPIO_ADMIN_OUTPUT_ENABLE 12'h014
|
||||
`define RIBP_GPIO_ADMIN_OE_SET 12'h018
|
||||
`define RIBP_GPIO_ADMIN_OE_CLEAR 12'h01C
|
||||
`define RIBP_GPIO_ADMIN_OE_TOGGLE 12'h020
|
||||
`define RIBP_GPIO_ADMIN_OPEN_DRAIN 12'h024
|
||||
`define RIBP_GPIO_ADMIN_INPUT_CMOS 12'h028
|
||||
`define RIBP_GPIO_ADMIN_PULL_UP 12'h02C
|
||||
`define RIBP_GPIO_ADMIN_PULL_DOWN 12'h030
|
||||
`define RIBP_GPIO_ADMIN_ALT_ENABLE 12'h034
|
||||
`define RIBP_GPIO_ADMIN_ALT_SELECT 12'h038
|
||||
`define RIBP_GPIO_ADMIN_USER_SELECT 12'h03C
|
||||
`define RIBP_GPIO_ADMIN_USER_LOCK 12'h040
|
||||
`define RIBP_GPIO_ADMIN_USER_STATUS 12'h044
|
||||
`define RIBP_GPIO_ADMIN_USER_ACCESS_MASK 12'h048
|
||||
`define RIBP_GPIO_ADMIN_INTR_RISE_ENABLE 12'h04C
|
||||
`define RIBP_GPIO_ADMIN_INTR_FALL_ENABLE 12'h050
|
||||
`define RIBP_GPIO_ADMIN_INTR_HIGH_ENABLE 12'h054
|
||||
`define RIBP_GPIO_ADMIN_INTR_LOW_ENABLE 12'h058
|
||||
`define RIBP_GPIO_ADMIN_INTR_ENABLE 12'h05C
|
||||
`define RIBP_GPIO_ADMIN_INTR_STATE 12'h060
|
||||
`define RIBP_GPIO_ADMIN_INTR_STATUS 12'h064
|
||||
`define RIBP_GPIO_ADMIN_INTR_TEST 12'h068
|
||||
`define RIBP_GPIO_ADMIN_FILTER_ENABLE 12'h06C
|
||||
`define RIBP_GPIO_ADMIN_FILTER_DIV 12'h070
|
||||
`define RIBP_GPIO_ADMIN_FILTER_COUNT 12'h074
|
||||
`define RIBP_GPIO_ADMIN_CONFIG_LOCK 12'h078
|
||||
`define RIBP_GPIO_PAD_CAPABILITY 12'h0F4
|
||||
`define RIBP_GPIO_IP_VERSION 12'h0F8
|
||||
`define RIBP_GPIO_CAPABILITY 12'h0FC
|
||||
|
||||
`define GPIO_PAD_CAP_INPUT_CMOS 0
|
||||
`define GPIO_PAD_CAP_PULL_UP 1
|
||||
`define GPIO_PAD_CAP_PULL_DOWN 2
|
||||
|
||||
`define GPIO_CAP_OPEN_DRAIN 16
|
||||
`define GPIO_CAP_FILTER 17
|
||||
`define GPIO_CAP_USER_HANDOFF 18
|
||||
`define GPIO_CAP_CONFIG_LOCK 19
|
||||
`define GPIO_CAP_ATOMIC_OUT 20
|
||||
`define GPIO_CAP_ATOMIC_OE 21
|
||||
`define GPIO_CAP_BOTH_EDGE_IRQ 22
|
||||
// verilog_format: on
|
||||
|
||||
`endif
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
`include "gpio_define.svh"
|
||||
|
||||
interface gpio_if #(
|
||||
parameter int DATA_WIDTH = `RIBP_GPIO_NUM
|
||||
) ();
|
||||
logic [DATA_WIDTH-1:0] oe_o;
|
||||
logic [DATA_WIDTH-1:0] cs_o;
|
||||
logic [DATA_WIDTH-1:0] pu_o;
|
||||
logic [DATA_WIDTH-1:0] pd_o;
|
||||
logic [DATA_WIDTH-1:0] do_o;
|
||||
logic [DATA_WIDTH-1:0] di_i;
|
||||
logic [DATA_WIDTH-1:0] alt0_do_i;
|
||||
logic [DATA_WIDTH-1:0] alt0_oe_i;
|
||||
logic [DATA_WIDTH-1:0] alt1_do_i;
|
||||
logic [DATA_WIDTH-1:0] alt1_oe_i;
|
||||
logic irq_o;
|
||||
|
||||
modport dut(
|
||||
output oe_o,
|
||||
output cs_o,
|
||||
output pu_o,
|
||||
output pd_o,
|
||||
output do_o,
|
||||
input di_i,
|
||||
input alt0_do_i,
|
||||
input alt0_oe_i,
|
||||
input alt1_do_i,
|
||||
input alt1_oe_i,
|
||||
output irq_o
|
||||
);
|
||||
|
||||
modport pad(input oe_o, input cs_o, input pu_o, input pd_o, input do_o, output di_i);
|
||||
modport soc_pad(output oe_o, output cs_o, output pu_o, output pd_o, output do_o, input di_i);
|
||||
endinterface
|
||||
@@ -0,0 +1,649 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
`include "gpio_define.svh"
|
||||
|
||||
module gpio_reg #(
|
||||
parameter int PIN_NUM = 32,
|
||||
parameter logic [31:0] USER_BASE_ADDR = 32'h1000_0000,
|
||||
parameter logic [31:0] ADMIN_BASE_ADDR = 32'h1001_4000,
|
||||
parameter bit HAS_INPUT_CMOS = 1'b0,
|
||||
parameter bit HAS_PULL_UP = 1'b0,
|
||||
parameter bit HAS_PULL_DOWN = 1'b0
|
||||
) (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
ribp_if.slave ribp,
|
||||
input logic [PIN_NUM-1:0] data_in_i,
|
||||
input logic [PIN_NUM-1:0] intr_event_i,
|
||||
output logic [PIN_NUM-1:0] data_out_o,
|
||||
output logic [PIN_NUM-1:0] output_enable_o,
|
||||
output logic [PIN_NUM-1:0] open_drain_o,
|
||||
output logic [PIN_NUM-1:0] input_cmos_o,
|
||||
output logic [PIN_NUM-1:0] pull_up_o,
|
||||
output logic [PIN_NUM-1:0] pull_down_o,
|
||||
output logic [PIN_NUM-1:0] alt_enable_o,
|
||||
output logic [PIN_NUM-1:0] alt_select_o,
|
||||
output logic [PIN_NUM-1:0] user_select_o,
|
||||
output logic [PIN_NUM-1:0] user_handoff_o,
|
||||
output logic [PIN_NUM-1:0] filter_enable_o,
|
||||
output logic [15:0] filter_div_o,
|
||||
output logic [3:0] filter_count_o,
|
||||
output logic [PIN_NUM-1:0] intr_rise_enable_o,
|
||||
output logic [PIN_NUM-1:0] intr_fall_enable_o,
|
||||
output logic [PIN_NUM-1:0] intr_high_enable_o,
|
||||
output logic [PIN_NUM-1:0] intr_low_enable_o,
|
||||
output logic irq_o
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
localparam logic [31:0] IP_VERSION = 32'h0002_0000;
|
||||
localparam logic [31:0] CAPABILITY = 32'h007F_0000 | (32'(4) << 12) |
|
||||
(32'(2) << 8) | 32'(PIN_NUM);
|
||||
localparam logic [31:0] PAD_CAPABILITY = {29'd0, HAS_PULL_DOWN, HAS_PULL_UP, HAS_INPUT_CMOS};
|
||||
|
||||
logic s_req, s_write, s_req_accept;
|
||||
logic s_public_window, s_admin_window, s_aligned;
|
||||
logic [ 11:0] s_offset;
|
||||
logic [ 31:0] s_byte_mask;
|
||||
logic [ 31:0] s_write_word;
|
||||
logic [PIN_NUM-1:0] s_write_bits;
|
||||
logic s_access_error;
|
||||
logic [31:0] s_ribp_rdata_d, s_ribp_rdata_q;
|
||||
logic s_ribp_ready_q;
|
||||
logic s_ribp_resp_err_d, s_ribp_resp_err_q;
|
||||
|
||||
logic [PIN_NUM-1:0] s_data_out_d, s_data_out_q;
|
||||
logic [PIN_NUM-1:0] s_output_enable_d, s_output_enable_q;
|
||||
logic [PIN_NUM-1:0] s_open_drain_d, s_open_drain_q;
|
||||
logic [PIN_NUM-1:0] s_input_cmos_d, s_input_cmos_q;
|
||||
logic [PIN_NUM-1:0] s_pull_up_d, s_pull_up_q;
|
||||
logic [PIN_NUM-1:0] s_pull_down_d, s_pull_down_q;
|
||||
logic [PIN_NUM-1:0] s_alt_enable_d, s_alt_enable_q;
|
||||
logic [PIN_NUM-1:0] s_alt_select_d, s_alt_select_q;
|
||||
logic [PIN_NUM-1:0] s_user_select_d, s_user_select_q;
|
||||
logic [PIN_NUM-1:0] s_user_lock_d, s_user_lock_q;
|
||||
logic [PIN_NUM-1:0] s_user_handoff_d, s_user_handoff_q;
|
||||
logic [PIN_NUM-1:0] s_user_access_d, s_user_access_q;
|
||||
logic [PIN_NUM-1:0] s_intr_rise_d, s_intr_rise_q;
|
||||
logic [PIN_NUM-1:0] s_intr_fall_d, s_intr_fall_q;
|
||||
logic [PIN_NUM-1:0] s_intr_high_d, s_intr_high_q;
|
||||
logic [PIN_NUM-1:0] s_intr_low_d, s_intr_low_q;
|
||||
logic [PIN_NUM-1:0] s_intr_enable_d, s_intr_enable_q;
|
||||
logic [PIN_NUM-1:0] s_intr_state_d, s_intr_state_q;
|
||||
logic [PIN_NUM-1:0] s_filter_enable_d, s_filter_enable_q;
|
||||
logic [PIN_NUM-1:0] s_config_lock_d, s_config_lock_q;
|
||||
logic [15:0] s_filter_div_d, s_filter_div_q;
|
||||
logic [3:0] s_filter_count_d, s_filter_count_q;
|
||||
|
||||
logic s_data_out_en, s_output_enable_en, s_open_drain_en, s_input_cmos_en;
|
||||
logic s_pull_up_en, s_pull_down_en, s_alt_enable_en, s_alt_select_en;
|
||||
logic s_user_select_en, s_user_lock_en, s_user_access_en;
|
||||
logic s_intr_rise_en, s_intr_fall_en, s_intr_high_en, s_intr_low_en;
|
||||
logic s_intr_enable_en, s_intr_state_en, s_filter_enable_en, s_config_lock_en;
|
||||
logic s_filter_div_en, s_filter_count_en;
|
||||
logic [PIN_NUM-1:0] s_intr_clear, s_intr_test;
|
||||
|
||||
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] mask;
|
||||
begin
|
||||
mask = {{8{strobe[3]}}, {8{strobe[2]}}, {8{strobe[1]}}, {8{strobe[0]}}};
|
||||
return (current & ~mask) | (value & mask);
|
||||
end
|
||||
endfunction
|
||||
|
||||
function automatic logic [PIN_NUM-1:0] merge_pins(
|
||||
input logic [PIN_NUM-1:0] current, input logic [31:0] value, input logic [3:0] strobe);
|
||||
logic [31:0] current_word;
|
||||
logic [31:0] merged_word;
|
||||
begin
|
||||
current_word = '0;
|
||||
current_word[PIN_NUM-1:0] = current;
|
||||
merged_word = merge_wstrb(current_word, value, strobe);
|
||||
return merged_word[PIN_NUM-1:0];
|
||||
end
|
||||
endfunction
|
||||
|
||||
function automatic logic [31:0] extend_pins(input logic [PIN_NUM-1:0] value);
|
||||
logic [31:0] result;
|
||||
begin
|
||||
result = '0;
|
||||
result[PIN_NUM-1:0] = value;
|
||||
return result;
|
||||
end
|
||||
endfunction
|
||||
|
||||
function automatic logic irq_config_valid(
|
||||
input logic [PIN_NUM-1:0] rise, input logic [PIN_NUM-1:0] fall,
|
||||
input logic [PIN_NUM-1:0] high, input logic [PIN_NUM-1:0] low);
|
||||
logic [PIN_NUM-1:0] edge_mode;
|
||||
logic [PIN_NUM-1:0] level_mode;
|
||||
begin
|
||||
edge_mode = rise | fall;
|
||||
level_mode = high | low;
|
||||
return !((|(high & low)) || (|(edge_mode & level_mode)));
|
||||
end
|
||||
endfunction
|
||||
|
||||
initial begin
|
||||
if ((PIN_NUM < 1) || (PIN_NUM > 32)) begin
|
||||
$fatal(1, "gpio_reg: PIN_NUM must be between 1 and 32");
|
||||
end
|
||||
if ((USER_BASE_ADDR[11:0] != 12'd0) || (ADMIN_BASE_ADDR[11:0] != 12'd0) ||
|
||||
(USER_BASE_ADDR == ADMIN_BASE_ADDR)) begin
|
||||
$fatal(1, "gpio_reg: register window bases must be distinct and 4 KiB aligned");
|
||||
end
|
||||
end
|
||||
|
||||
assign s_req = ribp.valid && !s_ribp_ready_q;
|
||||
assign s_write = |ribp.wstrb;
|
||||
assign s_req_accept = s_req;
|
||||
assign s_public_window = ribp.addr[31:12] == USER_BASE_ADDR[31:12];
|
||||
assign s_admin_window = ribp.addr[31:12] == ADMIN_BASE_ADDR[31:12];
|
||||
assign s_aligned = ribp.addr[1:0] == 2'b00;
|
||||
assign s_offset = ribp.addr[11:0];
|
||||
assign s_byte_mask = {
|
||||
{8{ribp.wstrb[3]}}, {8{ribp.wstrb[2]}}, {8{ribp.wstrb[1]}}, {8{ribp.wstrb[0]}}
|
||||
};
|
||||
assign s_write_word = ribp.wdata & s_byte_mask;
|
||||
assign s_write_bits = s_write_word[PIN_NUM-1:0];
|
||||
|
||||
assign ribp.ready = s_ribp_ready_q;
|
||||
assign ribp.rdata = s_ribp_rdata_q;
|
||||
assign ribp.resp_err = s_ribp_resp_err_q;
|
||||
assign irq_o = |(s_intr_state_q & s_intr_enable_q);
|
||||
|
||||
always_comb begin
|
||||
s_access_error = !s_aligned || !(s_public_window || s_admin_window);
|
||||
s_ribp_rdata_d = '0;
|
||||
s_data_out_en = 1'b0;
|
||||
s_output_enable_en = 1'b0;
|
||||
s_open_drain_en = 1'b0;
|
||||
s_input_cmos_en = 1'b0;
|
||||
s_pull_up_en = 1'b0;
|
||||
s_pull_down_en = 1'b0;
|
||||
s_alt_enable_en = 1'b0;
|
||||
s_alt_select_en = 1'b0;
|
||||
s_user_select_en = 1'b0;
|
||||
s_user_lock_en = 1'b0;
|
||||
s_user_access_en = 1'b0;
|
||||
s_intr_rise_en = 1'b0;
|
||||
s_intr_fall_en = 1'b0;
|
||||
s_intr_high_en = 1'b0;
|
||||
s_intr_low_en = 1'b0;
|
||||
s_intr_enable_en = 1'b0;
|
||||
s_filter_enable_en = 1'b0;
|
||||
s_config_lock_en = 1'b0;
|
||||
s_filter_div_en = 1'b0;
|
||||
s_filter_count_en = 1'b0;
|
||||
s_intr_clear = '0;
|
||||
s_intr_test = '0;
|
||||
|
||||
s_data_out_d = s_data_out_q;
|
||||
s_output_enable_d = s_output_enable_q;
|
||||
s_open_drain_d = s_open_drain_q;
|
||||
s_input_cmos_d = s_input_cmos_q;
|
||||
s_pull_up_d = s_pull_up_q;
|
||||
s_pull_down_d = s_pull_down_q;
|
||||
s_alt_enable_d = s_alt_enable_q;
|
||||
s_alt_select_d = s_alt_select_q;
|
||||
s_user_select_d = s_user_select_q;
|
||||
s_user_lock_d = s_user_lock_q;
|
||||
s_user_access_d = s_user_access_q;
|
||||
s_intr_rise_d = s_intr_rise_q;
|
||||
s_intr_fall_d = s_intr_fall_q;
|
||||
s_intr_high_d = s_intr_high_q;
|
||||
s_intr_low_d = s_intr_low_q;
|
||||
s_intr_enable_d = s_intr_enable_q;
|
||||
s_filter_enable_d = s_filter_enable_q;
|
||||
s_config_lock_d = s_config_lock_q;
|
||||
s_filter_div_d = s_filter_div_q;
|
||||
s_filter_count_d = s_filter_count_q;
|
||||
|
||||
if (s_req && !s_access_error) begin
|
||||
if (s_public_window) begin
|
||||
if (s_write) begin
|
||||
unique case (s_offset)
|
||||
`RIBP_GPIO_USER_DATA_OUT: begin
|
||||
s_data_out_en = 1'b1;
|
||||
s_data_out_d = (s_data_out_q & ~s_user_access_q) |
|
||||
(merge_pins(s_data_out_q, ribp.wdata, ribp.wstrb) & s_user_access_q);
|
||||
end
|
||||
`RIBP_GPIO_USER_OUT_SET: begin
|
||||
s_data_out_en = 1'b1;
|
||||
s_data_out_d = s_data_out_q | (s_write_bits & s_user_access_q);
|
||||
end
|
||||
`RIBP_GPIO_USER_OUT_CLEAR: begin
|
||||
s_data_out_en = 1'b1;
|
||||
s_data_out_d = s_data_out_q & ~(s_write_bits & s_user_access_q);
|
||||
end
|
||||
`RIBP_GPIO_USER_OUT_TOGGLE: begin
|
||||
s_data_out_en = 1'b1;
|
||||
s_data_out_d = s_data_out_q ^ (s_write_bits & s_user_access_q);
|
||||
end
|
||||
`RIBP_GPIO_USER_INTR_STATE: begin
|
||||
s_intr_clear = s_write_bits & s_user_access_q;
|
||||
end
|
||||
`RIBP_GPIO_USER_INTR_ENABLE: begin
|
||||
s_intr_enable_en = 1'b1;
|
||||
s_intr_enable_d = (s_intr_enable_q & ~s_user_access_q) |
|
||||
(merge_pins(s_intr_enable_q, ribp.wdata, ribp.wstrb) & s_user_access_q);
|
||||
end
|
||||
`RIBP_GPIO_USER_INTR_ENABLE_SET: begin
|
||||
s_intr_enable_en = 1'b1;
|
||||
s_intr_enable_d = s_intr_enable_q | (s_write_bits & s_user_access_q);
|
||||
end
|
||||
`RIBP_GPIO_USER_INTR_ENABLE_CLEAR: begin
|
||||
s_intr_enable_en = 1'b1;
|
||||
s_intr_enable_d = s_intr_enable_q & ~(s_write_bits & s_user_access_q);
|
||||
end
|
||||
default: s_access_error = 1'b1;
|
||||
endcase
|
||||
end else begin
|
||||
unique case (s_offset)
|
||||
`RIBP_GPIO_USER_DATA_IN: s_ribp_rdata_d = extend_pins(data_in_i & s_user_access_q);
|
||||
`RIBP_GPIO_USER_DATA_OUT: s_ribp_rdata_d = extend_pins(s_data_out_q & s_user_access_q);
|
||||
`RIBP_GPIO_USER_INTR_STATE:
|
||||
s_ribp_rdata_d = extend_pins(s_intr_state_q & s_user_access_q);
|
||||
`RIBP_GPIO_USER_INTR_STATUS:
|
||||
s_ribp_rdata_d = extend_pins(s_intr_state_q & s_intr_enable_q & s_user_access_q);
|
||||
`RIBP_GPIO_USER_INTR_ENABLE:
|
||||
s_ribp_rdata_d = extend_pins(s_intr_enable_q & s_user_access_q);
|
||||
`RIBP_GPIO_IP_VERSION: s_ribp_rdata_d = IP_VERSION;
|
||||
`RIBP_GPIO_CAPABILITY: s_ribp_rdata_d = CAPABILITY;
|
||||
default: s_access_error = 1'b1;
|
||||
endcase
|
||||
end
|
||||
end else if (s_write) begin
|
||||
unique case (s_offset)
|
||||
`RIBP_GPIO_ADMIN_DATA_OUT: begin
|
||||
s_data_out_en = 1'b1;
|
||||
s_data_out_d = merge_pins(s_data_out_q, ribp.wdata, ribp.wstrb);
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_OUT_SET: begin
|
||||
s_data_out_en = 1'b1;
|
||||
s_data_out_d = s_data_out_q | s_write_bits;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_OUT_CLEAR: begin
|
||||
s_data_out_en = 1'b1;
|
||||
s_data_out_d = s_data_out_q & ~s_write_bits;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_OUT_TOGGLE: begin
|
||||
s_data_out_en = 1'b1;
|
||||
s_data_out_d = s_data_out_q ^ s_write_bits;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_OUTPUT_ENABLE,
|
||||
`RIBP_GPIO_ADMIN_OE_SET,
|
||||
`RIBP_GPIO_ADMIN_OE_CLEAR,
|
||||
`RIBP_GPIO_ADMIN_OE_TOGGLE: begin
|
||||
if (s_offset == `RIBP_GPIO_ADMIN_OUTPUT_ENABLE) begin
|
||||
s_output_enable_d = merge_pins(s_output_enable_q, ribp.wdata, ribp.wstrb);
|
||||
end else if (s_offset == `RIBP_GPIO_ADMIN_OE_SET) begin
|
||||
s_output_enable_d = s_output_enable_q | s_write_bits;
|
||||
end else if (s_offset == `RIBP_GPIO_ADMIN_OE_CLEAR) begin
|
||||
s_output_enable_d = s_output_enable_q & ~s_write_bits;
|
||||
end else begin
|
||||
s_output_enable_d = s_output_enable_q ^ s_write_bits;
|
||||
end
|
||||
if (|((s_output_enable_d ^ s_output_enable_q) & s_config_lock_q)) begin
|
||||
s_access_error = 1'b1;
|
||||
end else s_output_enable_en = 1'b1;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_OPEN_DRAIN: begin
|
||||
s_open_drain_d = merge_pins(s_open_drain_q, ribp.wdata, ribp.wstrb);
|
||||
if (|((s_open_drain_d ^ s_open_drain_q) & s_config_lock_q)) s_access_error = 1'b1;
|
||||
else s_open_drain_en = 1'b1;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_INPUT_CMOS: begin
|
||||
s_input_cmos_d = merge_pins(s_input_cmos_q, ribp.wdata, ribp.wstrb);
|
||||
if ((!HAS_INPUT_CMOS && (|s_input_cmos_d)) ||
|
||||
(|((s_input_cmos_d ^ s_input_cmos_q) & s_config_lock_q))) begin
|
||||
s_access_error = 1'b1;
|
||||
end else s_input_cmos_en = 1'b1;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_PULL_UP: begin
|
||||
s_pull_up_d = merge_pins(s_pull_up_q, ribp.wdata, ribp.wstrb);
|
||||
if ((!HAS_PULL_UP && (|s_pull_up_d)) || (|(s_pull_up_d & s_pull_down_q)) ||
|
||||
(|((s_pull_up_d ^ s_pull_up_q) & s_config_lock_q))) begin
|
||||
s_access_error = 1'b1;
|
||||
end else s_pull_up_en = 1'b1;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_PULL_DOWN: begin
|
||||
s_pull_down_d = merge_pins(s_pull_down_q, ribp.wdata, ribp.wstrb);
|
||||
if ((!HAS_PULL_DOWN && (|s_pull_down_d)) || (|(s_pull_down_d & s_pull_up_q)) ||
|
||||
(|((s_pull_down_d ^ s_pull_down_q) & s_config_lock_q))) begin
|
||||
s_access_error = 1'b1;
|
||||
end else s_pull_down_en = 1'b1;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_ALT_ENABLE: begin
|
||||
s_alt_enable_d = merge_pins(s_alt_enable_q, ribp.wdata, ribp.wstrb);
|
||||
if (|((s_alt_enable_d ^ s_alt_enable_q) & s_config_lock_q)) s_access_error = 1'b1;
|
||||
else s_alt_enable_en = 1'b1;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_ALT_SELECT: begin
|
||||
s_alt_select_d = merge_pins(s_alt_select_q, ribp.wdata, ribp.wstrb);
|
||||
if (|((s_alt_select_d ^ s_alt_select_q) & s_config_lock_q)) s_access_error = 1'b1;
|
||||
else s_alt_select_en = 1'b1;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_USER_SELECT: begin
|
||||
s_user_select_d = merge_pins(s_user_select_q, ribp.wdata, ribp.wstrb);
|
||||
if (|((s_user_select_d ^ s_user_select_q) & s_user_lock_q)) s_access_error = 1'b1;
|
||||
else s_user_select_en = 1'b1;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_USER_LOCK: begin
|
||||
s_user_lock_en = 1'b1;
|
||||
s_user_lock_d = s_user_lock_q | s_write_bits;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_USER_ACCESS_MASK: begin
|
||||
s_user_access_d = merge_pins(s_user_access_q, ribp.wdata, ribp.wstrb);
|
||||
if (|((s_user_access_d ^ s_user_access_q) & s_config_lock_q)) s_access_error = 1'b1;
|
||||
else s_user_access_en = 1'b1;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_INTR_RISE_ENABLE,
|
||||
`RIBP_GPIO_ADMIN_INTR_FALL_ENABLE,
|
||||
`RIBP_GPIO_ADMIN_INTR_HIGH_ENABLE,
|
||||
`RIBP_GPIO_ADMIN_INTR_LOW_ENABLE: begin
|
||||
if (s_offset == `RIBP_GPIO_ADMIN_INTR_RISE_ENABLE) begin
|
||||
s_intr_rise_d = merge_pins(s_intr_rise_q, ribp.wdata, ribp.wstrb);
|
||||
end else if (s_offset == `RIBP_GPIO_ADMIN_INTR_FALL_ENABLE) begin
|
||||
s_intr_fall_d = merge_pins(s_intr_fall_q, ribp.wdata, ribp.wstrb);
|
||||
end else if (s_offset == `RIBP_GPIO_ADMIN_INTR_HIGH_ENABLE) begin
|
||||
s_intr_high_d = merge_pins(s_intr_high_q, ribp.wdata, ribp.wstrb);
|
||||
end else begin
|
||||
s_intr_low_d = merge_pins(s_intr_low_q, ribp.wdata, ribp.wstrb);
|
||||
end
|
||||
if (!irq_config_valid(
|
||||
s_intr_rise_d, s_intr_fall_d, s_intr_high_d, s_intr_low_d
|
||||
) || (|(((s_intr_rise_d ^ s_intr_rise_q) | (s_intr_fall_d ^ s_intr_fall_q) |
|
||||
(s_intr_high_d ^ s_intr_high_q) | (s_intr_low_d ^ s_intr_low_q)) &
|
||||
s_config_lock_q))) begin
|
||||
s_access_error = 1'b1;
|
||||
end else begin
|
||||
s_intr_rise_en = s_offset == `RIBP_GPIO_ADMIN_INTR_RISE_ENABLE;
|
||||
s_intr_fall_en = s_offset == `RIBP_GPIO_ADMIN_INTR_FALL_ENABLE;
|
||||
s_intr_high_en = s_offset == `RIBP_GPIO_ADMIN_INTR_HIGH_ENABLE;
|
||||
s_intr_low_en = s_offset == `RIBP_GPIO_ADMIN_INTR_LOW_ENABLE;
|
||||
end
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_INTR_ENABLE: begin
|
||||
s_intr_enable_en = 1'b1;
|
||||
s_intr_enable_d = merge_pins(s_intr_enable_q, ribp.wdata, ribp.wstrb);
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_INTR_STATE: s_intr_clear = s_write_bits;
|
||||
`RIBP_GPIO_ADMIN_INTR_TEST: s_intr_test = s_write_bits;
|
||||
`RIBP_GPIO_ADMIN_FILTER_ENABLE: begin
|
||||
s_filter_enable_d = merge_pins(s_filter_enable_q, ribp.wdata, ribp.wstrb);
|
||||
if (((|s_filter_enable_d) && (s_filter_count_q == 4'd0)) ||
|
||||
(|((s_filter_enable_d ^ s_filter_enable_q) & s_config_lock_q))) begin
|
||||
s_access_error = 1'b1;
|
||||
end else s_filter_enable_en = 1'b1;
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_FILTER_DIV: begin
|
||||
if (|s_filter_enable_q) begin
|
||||
s_access_error = 1'b1;
|
||||
end else begin
|
||||
s_ribp_rdata_d = merge_wstrb({16'd0, s_filter_div_q}, ribp.wdata, ribp.wstrb);
|
||||
if (|s_ribp_rdata_d[31:16]) s_access_error = 1'b1;
|
||||
else begin
|
||||
s_filter_div_en = 1'b1;
|
||||
s_filter_div_d = s_ribp_rdata_d[15:0];
|
||||
end
|
||||
end
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_FILTER_COUNT: begin
|
||||
if (|s_filter_enable_q) begin
|
||||
s_access_error = 1'b1;
|
||||
end else begin
|
||||
s_ribp_rdata_d = merge_wstrb({28'd0, s_filter_count_q}, ribp.wdata, ribp.wstrb);
|
||||
if ((|s_ribp_rdata_d[31:4]) || (s_ribp_rdata_d[3:0] == 4'd0)) begin
|
||||
s_access_error = 1'b1;
|
||||
end else begin
|
||||
s_filter_count_en = 1'b1;
|
||||
s_filter_count_d = s_ribp_rdata_d[3:0];
|
||||
end
|
||||
end
|
||||
end
|
||||
`RIBP_GPIO_ADMIN_CONFIG_LOCK: begin
|
||||
s_config_lock_en = 1'b1;
|
||||
s_config_lock_d = s_config_lock_q | s_write_bits;
|
||||
end
|
||||
default: s_access_error = 1'b1;
|
||||
endcase
|
||||
end else begin
|
||||
unique case (s_offset)
|
||||
`RIBP_GPIO_ADMIN_DATA_IN: s_ribp_rdata_d = extend_pins(data_in_i);
|
||||
`RIBP_GPIO_ADMIN_DATA_OUT: s_ribp_rdata_d = extend_pins(s_data_out_q);
|
||||
`RIBP_GPIO_ADMIN_OUTPUT_ENABLE: s_ribp_rdata_d = extend_pins(s_output_enable_q);
|
||||
`RIBP_GPIO_ADMIN_OPEN_DRAIN: s_ribp_rdata_d = extend_pins(s_open_drain_q);
|
||||
`RIBP_GPIO_ADMIN_INPUT_CMOS: s_ribp_rdata_d = extend_pins(s_input_cmos_q);
|
||||
`RIBP_GPIO_ADMIN_PULL_UP: s_ribp_rdata_d = extend_pins(s_pull_up_q);
|
||||
`RIBP_GPIO_ADMIN_PULL_DOWN: s_ribp_rdata_d = extend_pins(s_pull_down_q);
|
||||
`RIBP_GPIO_ADMIN_ALT_ENABLE: s_ribp_rdata_d = extend_pins(s_alt_enable_q);
|
||||
`RIBP_GPIO_ADMIN_ALT_SELECT: s_ribp_rdata_d = extend_pins(s_alt_select_q);
|
||||
`RIBP_GPIO_ADMIN_USER_SELECT: s_ribp_rdata_d = extend_pins(s_user_select_q);
|
||||
`RIBP_GPIO_ADMIN_USER_LOCK: s_ribp_rdata_d = extend_pins(s_user_lock_q);
|
||||
`RIBP_GPIO_ADMIN_USER_STATUS:
|
||||
s_ribp_rdata_d = extend_pins(s_user_select_q & ~s_user_handoff_q);
|
||||
`RIBP_GPIO_ADMIN_USER_ACCESS_MASK: s_ribp_rdata_d = extend_pins(s_user_access_q);
|
||||
`RIBP_GPIO_ADMIN_INTR_RISE_ENABLE: s_ribp_rdata_d = extend_pins(s_intr_rise_q);
|
||||
`RIBP_GPIO_ADMIN_INTR_FALL_ENABLE: s_ribp_rdata_d = extend_pins(s_intr_fall_q);
|
||||
`RIBP_GPIO_ADMIN_INTR_HIGH_ENABLE: s_ribp_rdata_d = extend_pins(s_intr_high_q);
|
||||
`RIBP_GPIO_ADMIN_INTR_LOW_ENABLE: s_ribp_rdata_d = extend_pins(s_intr_low_q);
|
||||
`RIBP_GPIO_ADMIN_INTR_ENABLE: s_ribp_rdata_d = extend_pins(s_intr_enable_q);
|
||||
`RIBP_GPIO_ADMIN_INTR_STATE: s_ribp_rdata_d = extend_pins(s_intr_state_q);
|
||||
`RIBP_GPIO_ADMIN_INTR_STATUS:
|
||||
s_ribp_rdata_d = extend_pins(s_intr_state_q & s_intr_enable_q);
|
||||
`RIBP_GPIO_ADMIN_FILTER_ENABLE: s_ribp_rdata_d = extend_pins(s_filter_enable_q);
|
||||
`RIBP_GPIO_ADMIN_FILTER_DIV: s_ribp_rdata_d = {16'd0, s_filter_div_q};
|
||||
`RIBP_GPIO_ADMIN_FILTER_COUNT: s_ribp_rdata_d = {28'd0, s_filter_count_q};
|
||||
`RIBP_GPIO_ADMIN_CONFIG_LOCK: s_ribp_rdata_d = extend_pins(s_config_lock_q);
|
||||
`RIBP_GPIO_PAD_CAPABILITY: s_ribp_rdata_d = PAD_CAPABILITY;
|
||||
`RIBP_GPIO_IP_VERSION: s_ribp_rdata_d = IP_VERSION;
|
||||
`RIBP_GPIO_CAPABILITY: s_ribp_rdata_d = CAPABILITY;
|
||||
default: s_access_error = 1'b1;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign s_user_handoff_d = s_user_select_en ? (s_user_select_d ^ s_user_select_q) : '0;
|
||||
assign s_intr_state_d = (s_intr_state_q & ~s_intr_clear) | intr_event_i | s_intr_test;
|
||||
assign s_intr_state_en = (|s_intr_clear) || (|intr_event_i) || (|s_intr_test);
|
||||
|
||||
dffer #(PIN_NUM) u_data_out_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_data_out_en),
|
||||
.dat_i (s_data_out_d),
|
||||
.dat_o (s_data_out_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_output_enable_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_output_enable_en),
|
||||
.dat_i (s_output_enable_d),
|
||||
.dat_o (s_output_enable_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_open_drain_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_open_drain_en),
|
||||
.dat_i (s_open_drain_d),
|
||||
.dat_o (s_open_drain_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_input_cmos_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_input_cmos_en),
|
||||
.dat_i (s_input_cmos_d),
|
||||
.dat_o (s_input_cmos_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_pull_up_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_pull_up_en),
|
||||
.dat_i (s_pull_up_d),
|
||||
.dat_o (s_pull_up_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_pull_down_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_pull_down_en),
|
||||
.dat_i (s_pull_down_d),
|
||||
.dat_o (s_pull_down_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_alt_enable_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_alt_enable_en),
|
||||
.dat_i (s_alt_enable_d),
|
||||
.dat_o (s_alt_enable_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_alt_select_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_alt_select_en),
|
||||
.dat_i (s_alt_select_d),
|
||||
.dat_o (s_alt_select_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_user_select_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_user_select_en),
|
||||
.dat_i (s_user_select_d),
|
||||
.dat_o (s_user_select_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_user_lock_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_user_lock_en),
|
||||
.dat_i (s_user_lock_d),
|
||||
.dat_o (s_user_lock_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_user_access_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_user_access_en),
|
||||
.dat_i (s_user_access_d),
|
||||
.dat_o (s_user_access_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_intr_rise_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_intr_rise_en),
|
||||
.dat_i (s_intr_rise_d),
|
||||
.dat_o (s_intr_rise_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_intr_fall_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_intr_fall_en),
|
||||
.dat_i (s_intr_fall_d),
|
||||
.dat_o (s_intr_fall_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_intr_high_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_intr_high_en),
|
||||
.dat_i (s_intr_high_d),
|
||||
.dat_o (s_intr_high_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_intr_low_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_intr_low_en),
|
||||
.dat_i (s_intr_low_d),
|
||||
.dat_o (s_intr_low_q)
|
||||
);
|
||||
dffer #(PIN_NUM) 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)
|
||||
);
|
||||
dffer #(PIN_NUM) u_intr_state_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_intr_state_en),
|
||||
.dat_i (s_intr_state_d),
|
||||
.dat_o (s_intr_state_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_filter_enable_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_filter_enable_en),
|
||||
.dat_i (s_filter_enable_d),
|
||||
.dat_o (s_filter_enable_q)
|
||||
);
|
||||
dffer #(PIN_NUM) u_config_lock_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_config_lock_en),
|
||||
.dat_i (s_config_lock_d),
|
||||
.dat_o (s_config_lock_q)
|
||||
);
|
||||
dffer #(16) u_filter_div_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_filter_div_en),
|
||||
.dat_i (s_filter_div_d),
|
||||
.dat_o (s_filter_div_q)
|
||||
);
|
||||
dffer #(4) u_filter_count_dffer (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.en_i (s_filter_count_en),
|
||||
.dat_i (s_filter_count_d),
|
||||
.dat_o (s_filter_count_q)
|
||||
);
|
||||
|
||||
dffr #(PIN_NUM) u_user_handoff_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_user_handoff_d),
|
||||
.dat_o (s_user_handoff_q)
|
||||
);
|
||||
|
||||
dffr #(1) u_ribp_ready_dffr (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
.dat_i (s_req_accept),
|
||||
.dat_o (s_ribp_ready_q)
|
||||
);
|
||||
assign s_ribp_resp_err_d = s_access_error;
|
||||
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)
|
||||
);
|
||||
|
||||
assign data_out_o = s_data_out_q;
|
||||
assign output_enable_o = s_output_enable_q;
|
||||
assign open_drain_o = s_open_drain_q;
|
||||
assign input_cmos_o = s_input_cmos_q;
|
||||
assign pull_up_o = s_pull_up_q;
|
||||
assign pull_down_o = s_pull_down_q;
|
||||
assign alt_enable_o = s_alt_enable_q;
|
||||
assign alt_select_o = s_alt_select_q;
|
||||
assign user_select_o = s_user_select_q;
|
||||
assign user_handoff_o = s_user_handoff_q;
|
||||
assign filter_enable_o = s_filter_enable_q;
|
||||
assign filter_div_o = s_filter_div_q;
|
||||
assign filter_count_o = s_filter_count_q;
|
||||
assign intr_rise_enable_o = s_intr_rise_q;
|
||||
assign intr_fall_enable_o = s_intr_fall_q;
|
||||
assign intr_high_enable_o = s_intr_high_q;
|
||||
assign intr_low_enable_o = s_intr_low_q;
|
||||
endmodule
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module ribp_gpio #(
|
||||
parameter int PIN_NUM = 32,
|
||||
parameter logic [31:0] USER_BASE_ADDR = 32'h1000_0000,
|
||||
parameter logic [31:0] ADMIN_BASE_ADDR = 32'h1001_4000,
|
||||
parameter bit HAS_INPUT_CMOS = 1'b0,
|
||||
parameter bit HAS_PULL_UP = 1'b0,
|
||||
parameter bit HAS_PULL_DOWN = 1'b0
|
||||
) (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
input logic rst_n_i,
|
||||
ribp_if.slave ribp,
|
||||
gpio_if.dut gpio,
|
||||
user_gpio_if.padctrl user_gpio
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
logic [PIN_NUM-1:0] s_data_in;
|
||||
logic [PIN_NUM-1:0] s_data_out;
|
||||
logic [PIN_NUM-1:0] s_output_enable;
|
||||
logic [PIN_NUM-1:0] s_open_drain;
|
||||
logic [PIN_NUM-1:0] s_input_cmos;
|
||||
logic [PIN_NUM-1:0] s_pull_up;
|
||||
logic [PIN_NUM-1:0] s_pull_down;
|
||||
logic [PIN_NUM-1:0] s_alt_enable;
|
||||
logic [PIN_NUM-1:0] s_alt_select;
|
||||
logic [PIN_NUM-1:0] s_user_select;
|
||||
logic [PIN_NUM-1:0] s_user_handoff;
|
||||
logic [PIN_NUM-1:0] s_filter_enable;
|
||||
logic [ 15:0] s_filter_div;
|
||||
logic [ 3:0] s_filter_count;
|
||||
logic [PIN_NUM-1:0] s_intr_rise_enable;
|
||||
logic [PIN_NUM-1:0] s_intr_fall_enable;
|
||||
logic [PIN_NUM-1:0] s_intr_high_enable;
|
||||
logic [PIN_NUM-1:0] s_intr_low_enable;
|
||||
logic [PIN_NUM-1:0] s_intr_event;
|
||||
logic s_irq;
|
||||
|
||||
gpio_reg #(
|
||||
.PIN_NUM (PIN_NUM),
|
||||
.USER_BASE_ADDR (USER_BASE_ADDR),
|
||||
.ADMIN_BASE_ADDR(ADMIN_BASE_ADDR),
|
||||
.HAS_INPUT_CMOS (HAS_INPUT_CMOS),
|
||||
.HAS_PULL_UP (HAS_PULL_UP),
|
||||
.HAS_PULL_DOWN (HAS_PULL_DOWN)
|
||||
) u_gpio_reg (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.ribp (ribp),
|
||||
.data_in_i (s_data_in),
|
||||
.intr_event_i (s_intr_event),
|
||||
.data_out_o (s_data_out),
|
||||
.output_enable_o (s_output_enable),
|
||||
.open_drain_o (s_open_drain),
|
||||
.input_cmos_o (s_input_cmos),
|
||||
.pull_up_o (s_pull_up),
|
||||
.pull_down_o (s_pull_down),
|
||||
.alt_enable_o (s_alt_enable),
|
||||
.alt_select_o (s_alt_select),
|
||||
.user_select_o (s_user_select),
|
||||
.user_handoff_o (s_user_handoff),
|
||||
.filter_enable_o (s_filter_enable),
|
||||
.filter_div_o (s_filter_div),
|
||||
.filter_count_o (s_filter_count),
|
||||
.intr_rise_enable_o(s_intr_rise_enable),
|
||||
.intr_fall_enable_o(s_intr_fall_enable),
|
||||
.intr_high_enable_o(s_intr_high_enable),
|
||||
.intr_low_enable_o (s_intr_low_enable),
|
||||
.irq_o (s_irq)
|
||||
);
|
||||
|
||||
gpio_core #(
|
||||
.PIN_NUM(PIN_NUM)
|
||||
) u_gpio_core (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.data_out_i (s_data_out),
|
||||
.output_enable_i (s_output_enable),
|
||||
.open_drain_i (s_open_drain),
|
||||
.input_cmos_i (s_input_cmos),
|
||||
.pull_up_i (s_pull_up),
|
||||
.pull_down_i (s_pull_down),
|
||||
.alt_enable_i (s_alt_enable),
|
||||
.alt_select_i (s_alt_select),
|
||||
.user_select_i (s_user_select),
|
||||
.user_handoff_i (s_user_handoff),
|
||||
.filter_enable_i (s_filter_enable),
|
||||
.filter_div_i (s_filter_div),
|
||||
.filter_count_i (s_filter_count),
|
||||
.intr_rise_enable_i(s_intr_rise_enable),
|
||||
.intr_fall_enable_i(s_intr_fall_enable),
|
||||
.intr_high_enable_i(s_intr_high_enable),
|
||||
.intr_low_enable_i (s_intr_low_enable),
|
||||
.irq_i (s_irq),
|
||||
.data_in_o (s_data_in),
|
||||
.intr_event_o (s_intr_event),
|
||||
.gpio (gpio),
|
||||
.user_gpio (user_gpio)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
`include "gpio_define.svh"
|
||||
|
||||
interface user_gpio_if #(
|
||||
parameter int DATA_WIDTH = `RIBP_GPIO_NUM
|
||||
) ();
|
||||
logic [DATA_WIDTH-1:0] do_o;
|
||||
logic [DATA_WIDTH-1:0] oe_o;
|
||||
logic [DATA_WIDTH-1:0] di_i;
|
||||
|
||||
modport user_ip(output do_o, output oe_o, input di_i);
|
||||
modport padctrl(input do_o, input oe_o, output di_i);
|
||||
endinterface
|
||||
@@ -207,7 +207,11 @@ def render_c(
|
||||
"#ifndef RETROSOC_GENERATED_MEMORY_MAP_H",
|
||||
"#define RETROSOC_GENERATED_MEMORY_MAP_H",
|
||||
"",
|
||||
"#ifdef __ASSEMBLER__",
|
||||
"#define UINT32_C(value) value",
|
||||
"#else",
|
||||
"#include <stdint.h>",
|
||||
"#endif",
|
||||
"",
|
||||
f"#define RS_SOC_CPU_RESET_ADDR {c_hex32(cpu_reset)}",
|
||||
f"#define RS_SOC_HAS_SRAM {1 if have_sram_if == 'YES' else 0}U",
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
{"symbol": "RIBP_I2C1", "base": "0x10011000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "rw"},
|
||||
{"symbol": "RIBP_GA", "base": "0x10012000", "size": "0x00001000", "route": "reserved", "kind": "reserved", "public": false, "user_access": "none"},
|
||||
{"symbol": "RIBP_APU", "base": "0x10013000", "size": "0x00001000", "route": "reserved", "kind": "reserved", "public": false, "user_access": "none"},
|
||||
{"symbol": "RIBP_GPIO_ADMIN", "base": "0x10014000", "size": "0x00001000", "route": "ribp", "kind": "active", "public": true, "user_access": "none"},
|
||||
{"symbol": "APB_ARCHINFO", "base": "0x20000000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "ro"},
|
||||
{"symbol": "APB_RNG", "base": "0x20001000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"},
|
||||
{"symbol": "APB_UART1", "base": "0x20002000", "size": "0x00001000", "route": "apb", "kind": "active", "public": true, "user_access": "rw"},
|
||||
|
||||
@@ -136,30 +136,40 @@ module soc_gpio_user_handoff_sva #(
|
||||
input logic [DATA_WIDTH-1:0] user_do_i,
|
||||
input logic [DATA_WIDTH-1:0] native_oe_i,
|
||||
input logic [DATA_WIDTH-1:0] native_do_i,
|
||||
input logic [DATA_WIDTH-1:0] open_drain_i,
|
||||
input logic [DATA_WIDTH-1:0] selected_oe_i,
|
||||
input logic [DATA_WIDTH-1:0] selected_do_i,
|
||||
input logic [DATA_WIDTH-1:0] gpio_oe_i,
|
||||
input logic [DATA_WIDTH-1:0] gpio_do_i
|
||||
);
|
||||
|
||||
// A changing owner first drives output-enable low for a full handoff cycle.
|
||||
assert property (@(posedge clk_i) disable iff (!rst_n_i)
|
||||
gpio_oe_i == ((~user_handoff_i & user_sel_i & user_oe_i) |
|
||||
(~user_handoff_i & ~user_sel_i & native_oe_i)));
|
||||
selected_oe_i == ((user_sel_i & user_oe_i) | (~user_sel_i & native_oe_i)));
|
||||
assert property (@(posedge clk_i) disable iff (!rst_n_i)
|
||||
gpio_do_i == ((user_sel_i & user_do_i) | (~user_sel_i & native_do_i)));
|
||||
selected_do_i == ((user_sel_i & user_do_i) | (~user_sel_i & native_do_i)));
|
||||
assert property (@(posedge clk_i) disable iff (!rst_n_i)
|
||||
gpio_do_i == (selected_do_i & ~open_drain_i));
|
||||
assert property (@(posedge clk_i) disable iff (!rst_n_i)
|
||||
gpio_oe_i == (~user_handoff_i & selected_oe_i &
|
||||
~(open_drain_i & selected_do_i)));
|
||||
|
||||
endmodule
|
||||
|
||||
bind ribp_gpio soc_gpio_user_handoff_sva #(
|
||||
.DATA_WIDTH(`RIBP_GPIO_NUM)
|
||||
bind gpio_core soc_gpio_user_handoff_sva #(
|
||||
.DATA_WIDTH(PIN_NUM)
|
||||
) u_soc_gpio_user_handoff_sva (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.user_sel_i (s_gpio_user_sel_q),
|
||||
.user_handoff_i(s_gpio_user_handoff_q),
|
||||
.user_sel_i (user_select_i),
|
||||
.user_handoff_i(user_handoff_i),
|
||||
.user_oe_i (user_gpio.oe_o),
|
||||
.user_do_i (user_gpio.do_o),
|
||||
.native_oe_i (s_gpio_native_oe),
|
||||
.native_do_i (s_gpio_native_out),
|
||||
.native_oe_i (s_native_oe),
|
||||
.native_do_i (s_native_data),
|
||||
.open_drain_i (open_drain_i),
|
||||
.selected_oe_i (s_selected_oe),
|
||||
.selected_do_i (s_selected_data),
|
||||
.gpio_oe_i (gpio.oe_o),
|
||||
.gpio_do_i (gpio.do_o)
|
||||
);
|
||||
|
||||
@@ -47,7 +47,11 @@
|
||||
/ip/ribp/peripheral/timer_reg.sv
|
||||
/ip/ribp/peripheral/ribp_timer.sv
|
||||
/ip/ribp/serial/uart.sv
|
||||
/ip/ribp/peripheral/gpio.sv
|
||||
/ip/ribp/peripheral/gpio_if.sv
|
||||
/ip/ribp/peripheral/user_gpio_if.sv
|
||||
/ip/ribp/peripheral/gpio_core.sv
|
||||
/ip/ribp/peripheral/gpio_reg.sv
|
||||
/ip/ribp/peripheral/ribp_gpio.sv
|
||||
/top/ahbl2ribp.sv
|
||||
/ip/ribp/interconnect/axi4l2ribp.sv
|
||||
/ip/ribp/util/async_fifo.sv
|
||||
|
||||
@@ -82,14 +82,19 @@ def source_files(target: str) -> list[Path]:
|
||||
TOP / "rcu.sv",
|
||||
SCRIPT_DIR / "pll_rcu_formal.sv",
|
||||
]
|
||||
if target == "gpio_user":
|
||||
if target == "gpio":
|
||||
return [
|
||||
*common,
|
||||
COMMON_RTL / "cdc/cdc_sync.sv",
|
||||
COMMON_RTL / "cdc/cdc_rst_ctrlr.sv",
|
||||
COMMON_RTL / "clkrst/counter.sv",
|
||||
COMMON_RTL / "utils/edge_det.sv",
|
||||
PERIPHERAL / "gpio.sv",
|
||||
SCRIPT_DIR / "gpio_user_formal.sv",
|
||||
PERIPHERAL / "gpio_if.sv",
|
||||
PERIPHERAL / "user_gpio_if.sv",
|
||||
PERIPHERAL / "gpio_core.sv",
|
||||
PERIPHERAL / "gpio_reg.sv",
|
||||
PERIPHERAL / "ribp_gpio.sv",
|
||||
SCRIPT_DIR / "gpio_formal.sv",
|
||||
]
|
||||
if target == "ws2812":
|
||||
return [
|
||||
@@ -162,7 +167,7 @@ def parse_args() -> argparse.Namespace:
|
||||
"rib2apb",
|
||||
"sysctrl",
|
||||
"pll_rcu",
|
||||
"gpio_user",
|
||||
"gpio",
|
||||
"ws2812",
|
||||
"timer",
|
||||
"clint",
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module gpio_formal_design (
|
||||
// verilog_format: off
|
||||
input logic clk_i,
|
||||
output logic rst_n_i,
|
||||
output logic f_past_valid,
|
||||
output logic ribp_valid,
|
||||
output logic ribp_ready,
|
||||
output logic ribp_resp_err,
|
||||
output logic [31:0] ribp_addr,
|
||||
output logic [31:0] ribp_wdata,
|
||||
output logic [3:0] ribp_wstrb,
|
||||
output logic [3:0] gpio_oe,
|
||||
output logic [3:0] gpio_do,
|
||||
output logic [3:0] user_oe,
|
||||
output logic [3:0] user_do,
|
||||
output logic [3:0] user_select,
|
||||
output logic [3:0] user_lock,
|
||||
output logic [3:0] user_handoff,
|
||||
output logic [3:0] user_access,
|
||||
output logic [3:0] config_lock,
|
||||
output logic [3:0] data_out,
|
||||
output logic [3:0] output_enable,
|
||||
output logic [3:0] open_drain,
|
||||
output logic [3:0] selected_data,
|
||||
output logic [3:0] intr_state,
|
||||
output logic irq
|
||||
// verilog_format: on
|
||||
);
|
||||
|
||||
ribp_if ribp ();
|
||||
gpio_if #(4) gpio ();
|
||||
user_gpio_if #(4) user_gpio ();
|
||||
|
||||
(* anyseq *)logic f_ribp_valid;
|
||||
(* anyseq *)logic [31:0] f_ribp_addr;
|
||||
(* anyseq *)logic [31:0] f_ribp_wdata;
|
||||
(* anyseq *)logic [ 3:0] f_ribp_wstrb;
|
||||
(* anyseq *)logic [ 3:0] f_gpio_di;
|
||||
(* anyseq *)logic [ 3:0] f_alt0_do;
|
||||
(* anyseq *)logic [ 3:0] f_alt0_oe;
|
||||
(* anyseq *)logic [ 3:0] f_alt1_do;
|
||||
(* anyseq *)logic [ 3:0] f_alt1_oe;
|
||||
(* anyseq *)logic [ 3:0] f_user_do;
|
||||
(* anyseq *)logic [ 3:0] f_user_oe;
|
||||
|
||||
assign ribp.valid = f_ribp_valid;
|
||||
assign ribp.addr = f_ribp_addr;
|
||||
assign ribp.wdata = f_ribp_wdata;
|
||||
assign ribp.wstrb = f_ribp_wstrb;
|
||||
assign gpio.di_i = f_gpio_di;
|
||||
assign gpio.alt0_do_i = f_alt0_do;
|
||||
assign gpio.alt0_oe_i = f_alt0_oe;
|
||||
assign gpio.alt1_do_i = f_alt1_do;
|
||||
assign gpio.alt1_oe_i = f_alt1_oe;
|
||||
assign user_gpio.do_o = f_user_do;
|
||||
assign user_gpio.oe_o = f_user_oe;
|
||||
|
||||
assign ribp_valid = ribp.valid;
|
||||
assign ribp_ready = ribp.ready;
|
||||
assign ribp_resp_err = ribp.resp_err;
|
||||
assign ribp_addr = ribp.addr;
|
||||
assign ribp_wdata = ribp.wdata;
|
||||
assign ribp_wstrb = ribp.wstrb;
|
||||
assign gpio_oe = gpio.oe_o;
|
||||
assign gpio_do = gpio.do_o;
|
||||
assign user_oe = user_gpio.oe_o;
|
||||
assign user_do = user_gpio.do_o;
|
||||
assign user_select = u_dut.u_gpio_reg.s_user_select_q;
|
||||
assign user_lock = u_dut.u_gpio_reg.s_user_lock_q;
|
||||
assign user_handoff = u_dut.u_gpio_reg.s_user_handoff_q;
|
||||
assign user_access = u_dut.u_gpio_reg.s_user_access_q;
|
||||
assign config_lock = u_dut.u_gpio_reg.s_config_lock_q;
|
||||
assign data_out = u_dut.u_gpio_reg.s_data_out_q;
|
||||
assign output_enable = u_dut.u_gpio_reg.s_output_enable_q;
|
||||
assign open_drain = u_dut.u_gpio_reg.s_open_drain_q;
|
||||
assign selected_data = u_dut.u_gpio_core.s_selected_data;
|
||||
assign intr_state = u_dut.u_gpio_reg.s_intr_state_q;
|
||||
assign irq = gpio.irq_o;
|
||||
|
||||
ribp_gpio #(
|
||||
.PIN_NUM (4),
|
||||
.USER_BASE_ADDR (32'h1000_0000),
|
||||
.ADMIN_BASE_ADDR(32'h1001_4000),
|
||||
.HAS_INPUT_CMOS (1'b1),
|
||||
.HAS_PULL_UP (1'b1),
|
||||
.HAS_PULL_DOWN (1'b1)
|
||||
) u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.ribp (ribp),
|
||||
.gpio (gpio),
|
||||
.user_gpio(user_gpio)
|
||||
);
|
||||
|
||||
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,88 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module gpio_formal;
|
||||
|
||||
(* anyseq *) (* gclk *)reg clk_i;
|
||||
wire rst_n_i;
|
||||
wire f_past_valid;
|
||||
wire ribp_valid;
|
||||
wire ribp_ready;
|
||||
wire ribp_resp_err;
|
||||
wire [31:0] ribp_addr;
|
||||
wire [31:0] ribp_wdata;
|
||||
wire [ 3:0] ribp_wstrb;
|
||||
wire [ 3:0] gpio_oe;
|
||||
wire [ 3:0] gpio_do;
|
||||
wire [ 3:0] user_oe;
|
||||
wire [ 3:0] user_do;
|
||||
wire [ 3:0] user_select;
|
||||
wire [ 3:0] user_lock;
|
||||
wire [ 3:0] user_handoff;
|
||||
wire [ 3:0] user_access;
|
||||
wire [ 3:0] config_lock;
|
||||
wire [ 3:0] data_out;
|
||||
wire [ 3:0] output_enable;
|
||||
wire [ 3:0] open_drain;
|
||||
wire [ 3:0] selected_data;
|
||||
wire [ 3:0] intr_state;
|
||||
wire irq;
|
||||
|
||||
gpio_formal_design u_design (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.f_past_valid (f_past_valid),
|
||||
.ribp_valid (ribp_valid),
|
||||
.ribp_ready (ribp_ready),
|
||||
.ribp_resp_err(ribp_resp_err),
|
||||
.ribp_addr (ribp_addr),
|
||||
.ribp_wdata (ribp_wdata),
|
||||
.ribp_wstrb (ribp_wstrb),
|
||||
.gpio_oe (gpio_oe),
|
||||
.gpio_do (gpio_do),
|
||||
.user_oe (user_oe),
|
||||
.user_do (user_do),
|
||||
.user_select (user_select),
|
||||
.user_lock (user_lock),
|
||||
.user_handoff (user_handoff),
|
||||
.user_access (user_access),
|
||||
.config_lock (config_lock),
|
||||
.data_out (data_out),
|
||||
.output_enable(output_enable),
|
||||
.open_drain (open_drain),
|
||||
.selected_data(selected_data),
|
||||
.intr_state (intr_state),
|
||||
.irq (irq)
|
||||
);
|
||||
|
||||
always @(posedge clk_i) begin
|
||||
if (f_past_valid && $past(rst_n_i && ribp_valid && !ribp_ready)) begin
|
||||
assume (ribp_valid);
|
||||
assume (ribp_addr == $past(ribp_addr));
|
||||
assume (ribp_wdata == $past(ribp_wdata));
|
||||
assume (ribp_wstrb == $past(ribp_wstrb));
|
||||
end
|
||||
|
||||
if (rst_n_i) begin
|
||||
assert ((gpio_oe & user_handoff) == 4'd0);
|
||||
assert ((gpio_do & open_drain) == 4'd0);
|
||||
assert ((gpio_oe & open_drain & selected_data) == 4'd0);
|
||||
if (f_past_valid) begin
|
||||
assert (user_handoff == (user_select ^ $past(user_select)));
|
||||
assert ((user_lock & $past(user_lock)) == $past(user_lock));
|
||||
assert ((config_lock & $past(config_lock)) == $past(config_lock));
|
||||
assert ((user_select & $past(user_lock)) == ($past(user_select) & $past(user_lock)));
|
||||
if ($past(ribp_valid && !ribp_ready && (ribp_addr[31:12] == 20'h10000))) begin
|
||||
assert ((data_out & ~$past(user_access)) == ($past(data_out) & ~$past(user_access)));
|
||||
assert (user_access == $past(user_access));
|
||||
assert (config_lock == $past(config_lock));
|
||||
end
|
||||
end
|
||||
cover (|user_handoff);
|
||||
cover (|user_lock && |user_select);
|
||||
cover (irq && |intr_state);
|
||||
cover (ribp_ready && ribp_resp_err);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -1,91 +0,0 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module gpio_user_formal_design (
|
||||
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 [31:0] gpio_di,
|
||||
output logic [31:0] gpio_oe,
|
||||
output logic [31:0] gpio_do,
|
||||
output logic [31:0] user_di,
|
||||
output logic [31:0] user_oe,
|
||||
output logic [31:0] user_do,
|
||||
output logic [31:0] user_sel,
|
||||
output logic [31:0] user_lock,
|
||||
output logic [31:0] user_handoff,
|
||||
output logic [31:0] user_status,
|
||||
output logic [31:0] native_oe,
|
||||
output logic [31:0] native_do
|
||||
);
|
||||
|
||||
ribp_if rib ();
|
||||
gpio_if gpio ();
|
||||
user_gpio_if user_gpio ();
|
||||
|
||||
(* 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 [31:0] f_gpio_di;
|
||||
(* anyseq *)logic [31:0] f_alt0_do;
|
||||
(* anyseq *)logic [31:0] f_alt0_oe;
|
||||
(* anyseq *)logic [31:0] f_alt1_do;
|
||||
(* anyseq *)logic [31:0] f_alt1_oe;
|
||||
(* anyseq *)logic [31:0] f_user_do;
|
||||
(* anyseq *)logic [31:0] f_user_oe;
|
||||
|
||||
assign rib.valid = f_rib_valid;
|
||||
assign rib.addr = f_rib_addr;
|
||||
assign rib.wdata = f_rib_wdata;
|
||||
assign rib.wstrb = f_rib_wstrb;
|
||||
assign gpio.di_i = f_gpio_di;
|
||||
assign gpio.alt0_do_i = f_alt0_do;
|
||||
assign gpio.alt0_oe_i = f_alt0_oe;
|
||||
assign gpio.alt1_do_i = f_alt1_do;
|
||||
assign gpio.alt1_oe_i = f_alt1_oe;
|
||||
assign user_gpio.do_o = f_user_do;
|
||||
assign user_gpio.oe_o = f_user_oe;
|
||||
|
||||
assign rib_valid = rib.valid;
|
||||
assign rib_addr = rib.addr;
|
||||
assign rib_wdata = rib.wdata;
|
||||
assign rib_wstrb = rib.wstrb;
|
||||
assign rib_ready = rib.ready;
|
||||
assign gpio_di = gpio.di_i;
|
||||
assign gpio_oe = gpio.oe_o;
|
||||
assign gpio_do = gpio.do_o;
|
||||
assign user_di = user_gpio.di_i;
|
||||
assign user_oe = user_gpio.oe_o;
|
||||
assign user_do = user_gpio.do_o;
|
||||
assign user_sel = u_dut.s_gpio_user_sel_q;
|
||||
assign user_lock = u_dut.s_gpio_user_lock_q;
|
||||
assign user_handoff = u_dut.s_gpio_user_handoff_q;
|
||||
assign user_status = u_dut.s_gpio_user_status;
|
||||
assign native_oe = u_dut.s_gpio_native_oe;
|
||||
assign native_do = u_dut.s_gpio_native_out;
|
||||
|
||||
ribp_gpio u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.ribp (rib),
|
||||
.gpio (gpio),
|
||||
.user_gpio(user_gpio)
|
||||
);
|
||||
|
||||
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
|
||||
@@ -1,77 +0,0 @@
|
||||
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
||||
// retroSoC is licensed under Mulan PSL v2.
|
||||
|
||||
module gpio_user_formal;
|
||||
|
||||
(* anyseq *) (* gclk *)reg 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 [31:0] gpio_di;
|
||||
wire [31:0] gpio_oe;
|
||||
wire [31:0] gpio_do;
|
||||
wire [31:0] user_di;
|
||||
wire [31:0] user_oe;
|
||||
wire [31:0] user_do;
|
||||
wire [31:0] user_sel;
|
||||
wire [31:0] user_lock;
|
||||
wire [31:0] user_handoff;
|
||||
wire [31:0] user_status;
|
||||
wire [31:0] native_oe;
|
||||
wire [31:0] native_do;
|
||||
|
||||
gpio_user_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),
|
||||
.gpio_di (gpio_di),
|
||||
.gpio_oe (gpio_oe),
|
||||
.gpio_do (gpio_do),
|
||||
.user_di (user_di),
|
||||
.user_oe (user_oe),
|
||||
.user_do (user_do),
|
||||
.user_sel (user_sel),
|
||||
.user_lock (user_lock),
|
||||
.user_handoff(user_handoff),
|
||||
.user_status (user_status),
|
||||
.native_oe (native_oe),
|
||||
.native_do (native_do)
|
||||
);
|
||||
|
||||
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 (user_di == gpio_di);
|
||||
assert(gpio_oe == ((~user_handoff & user_sel & user_oe) |
|
||||
(~user_handoff & ~user_sel & native_oe)));
|
||||
assert (gpio_do == ((user_sel & user_do) | (~user_sel & native_do)));
|
||||
assert (user_status == (user_sel & ~user_handoff));
|
||||
if (f_past_valid) begin
|
||||
assert (user_handoff == (user_sel ^ $past(user_sel)));
|
||||
if ($past(user_lock)) begin
|
||||
assert (user_lock);
|
||||
assert ((user_sel & $past(user_lock)) == ($past(user_sel) & $past(user_lock)));
|
||||
end
|
||||
end
|
||||
cover (|user_handoff);
|
||||
cover (|user_lock && |user_sel);
|
||||
cover (|user_status && |gpio_oe);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -45,6 +45,7 @@ COMPATIBILITY_IRQ_BINDINGS = (
|
||||
("advanced_timer", "apb", 5, 15, "u_tmr_if.irq_o"),
|
||||
("reserved", "apb", 6, 16, "1'b0"),
|
||||
("ws2812", "ribp", 10, 17, "ws2812.irq_o"),
|
||||
("gpio", "ribp", 11, 18, "gpio.irq_o"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"gpio_pins": 32,
|
||||
"irq_vector_width": 32,
|
||||
"irq_groups": [
|
||||
{"name": "ribp", "width": 11, "top_signal": "s_ribp_irq"},
|
||||
{"name": "ribp", "width": 12, "top_signal": "s_ribp_irq"},
|
||||
{"name": "apb", "width": 7, "top_signal": "s_apb_irq"}
|
||||
],
|
||||
"interrupts": [
|
||||
@@ -24,11 +24,12 @@
|
||||
{"name": "watchdog_reset", "description": "APB watchdog reset request", "group": "apb", "group_bit": 4, "core_bit": 14, "signal": "u_wdg_if.rst_o"},
|
||||
{"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": "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"}
|
||||
],
|
||||
"ribp_targets": [
|
||||
{"slot": 0, "name": "uart0", "interface": "u_uart_ribp_if", "regions": ["RIBP_UART0"]},
|
||||
{"slot": 1, "name": "gpio", "interface": "u_gpio_ribp_if", "regions": ["RIBP_GPIO"]},
|
||||
{"slot": 1, "name": "gpio", "interface": "u_gpio_ribp_if", "regions": ["RIBP_GPIO", "RIBP_GPIO_ADMIN"]},
|
||||
{"slot": 2, "name": "tim0", "interface": "u_tim0_ribp_if", "regions": ["RIBP_TIM0"]},
|
||||
{"slot": 3, "name": "tim1", "interface": "u_tim1_ribp_if", "regions": ["RIBP_TIM1"]},
|
||||
{"slot": 4, "name": "psram", "interface": "u_psram_ribp_if", "regions": ["RIBP_PSRAM", "PSRAM"]},
|
||||
|
||||
+10
-6
@@ -9,7 +9,7 @@ FORMAL_WS2812_DEPTH ?= 120
|
||||
FORMAL_CLINT_DEPTH ?= 32
|
||||
FORMAL_TIMEOUT ?= 60
|
||||
FORMAL_WS2812_TIMEOUT ?= 120
|
||||
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio_user ws2812 timer clint
|
||||
FORMAL_TARGETS := bus rib_adapter rib2apb sysctrl pll_rcu gpio ws2812 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
|
||||
@@ -23,8 +23,8 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
|
||||
$(RTL_PATH)/formal/sysctrl_formal_props.sv \
|
||||
$(RTL_PATH)/formal/pll_rcu_formal.sv \
|
||||
$(RTL_PATH)/formal/pll_rcu_formal_props.sv \
|
||||
$(RTL_PATH)/formal/gpio_user_formal.sv \
|
||||
$(RTL_PATH)/formal/gpio_user_formal_props.sv \
|
||||
$(RTL_PATH)/formal/gpio_formal.sv \
|
||||
$(RTL_PATH)/formal/gpio_formal_props.sv \
|
||||
$(RTL_PATH)/formal/ws2812_formal.sv \
|
||||
$(RTL_PATH)/formal/ws2812_formal_props.sv \
|
||||
$(RTL_PATH)/formal/timer_formal.sv \
|
||||
@@ -39,7 +39,11 @@ FORMAL_SOURCE_FILES := $(RTL_PATH)/formal/bus_formal.sv \
|
||||
$(RTL_PATH)/top/rib2apb.sv \
|
||||
$(RTL_PATH)/top/ribp2rib.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/interconnect/ribp_regslice.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/gpio.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/gpio_if.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/user_gpio_if.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/gpio_core.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/gpio_reg.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/ribp_gpio.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/pll_ctrl_if.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/peripheral/sysctrl.sv \
|
||||
$(ROOT_PATH)/rtl/ip/ribp/serial/ws2812_if.sv \
|
||||
@@ -146,7 +150,7 @@ formal-sysctrl: $(FORMAL_DIR)/sysctrl/.stamp | manifest
|
||||
|
||||
formal-pll-rcu: $(FORMAL_DIR)/pll_rcu/.stamp | manifest
|
||||
|
||||
formal-gpio-user: $(FORMAL_DIR)/gpio_user/.stamp | manifest
|
||||
formal-gpio: $(FORMAL_DIR)/gpio/.stamp | manifest
|
||||
|
||||
formal-ws2812: $(FORMAL_DIR)/ws2812/.stamp | manifest
|
||||
|
||||
@@ -160,4 +164,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-user formal-ws2812 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-timer formal-clint formal-doctor formal-clean
|
||||
@@ -68,6 +68,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \
|
||||
$(ROOT_PATH)/crt/src/hal/clint.c \
|
||||
$(ROOT_PATH)/crt/src/hal/clock.c \
|
||||
$(ROOT_PATH)/crt/src/hal/uart.c \
|
||||
$(ROOT_PATH)/crt/src/hal/gpio_math.c \
|
||||
$(ROOT_PATH)/crt/src/hal/gpio.c \
|
||||
$(ROOT_PATH)/crt/src/hal/timer_math.c \
|
||||
$(ROOT_PATH)/crt/src/hal/timer.c \
|
||||
@@ -142,9 +143,10 @@ FORCE_VERSION:
|
||||
|
||||
upd_ver_info: $(VERSION_HEADER)
|
||||
|
||||
asm: $(MPW_VARIANT_STAMP)
|
||||
asm: $(MPW_VARIANT_STAMP) $(MEMORY_MAP_STAMP)
|
||||
@mkdir -p $(SW_BUILD_DIR)/asm
|
||||
$(MAKE) -C $(ROOT_PATH)/app/asm OUT_DIR=$(SW_BUILD_DIR)/asm
|
||||
$(MAKE) -C $(ROOT_PATH)/app/asm OUT_DIR=$(SW_BUILD_DIR)/asm \
|
||||
GENERATED_INCLUDE=$(MEMORY_MAP_C_DIR)
|
||||
cp $(SW_BUILD_DIR)/asm/hello-asm.flash $(SW_BUILD_DIR)/$(ASM_FIRMWARE_NAME).hex
|
||||
cp $(SW_BUILD_DIR)/asm/hello-asm.bin $(SW_BUILD_DIR)/$(ASM_FIRMWARE_NAME).bin
|
||||
cp $(SW_BUILD_DIR)/asm/hello-asm.txt $(SW_BUILD_DIR)/$(ASM_FIRMWARE_NAME)_all.txt
|
||||
|
||||
@@ -61,6 +61,24 @@ module ip_ribp_wrapper (
|
||||
logic s_dma_xfer_done;
|
||||
logic s_tim0_irq, s_tim1_irq;
|
||||
|
||||
`ifdef PDK_GF180
|
||||
localparam bit GPIO_HAS_INPUT_CMOS = 1'b1;
|
||||
localparam bit GPIO_HAS_PULL_UP = 1'b1;
|
||||
localparam bit GPIO_HAS_PULL_DOWN = 1'b1;
|
||||
`elsif PDK_ICS55
|
||||
localparam bit GPIO_HAS_INPUT_CMOS = 1'b1;
|
||||
localparam bit GPIO_HAS_PULL_UP = 1'b1;
|
||||
localparam bit GPIO_HAS_PULL_DOWN = 1'b1;
|
||||
`elsif PDK_SKY130
|
||||
localparam bit GPIO_HAS_INPUT_CMOS = 1'b1;
|
||||
localparam bit GPIO_HAS_PULL_UP = 1'b0;
|
||||
localparam bit GPIO_HAS_PULL_DOWN = 1'b0;
|
||||
`else
|
||||
localparam bit GPIO_HAS_INPUT_CMOS = 1'b0;
|
||||
localparam bit GPIO_HAS_PULL_UP = 1'b0;
|
||||
localparam bit GPIO_HAS_PULL_DOWN = 1'b0;
|
||||
`endif
|
||||
|
||||
rib2ribp u_rib2ribp (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i(rst_n_i),
|
||||
@@ -83,12 +101,18 @@ module ip_ribp_wrapper (
|
||||
// Generated IRQ ownership and core-vector bit assignments are topology checked.
|
||||
`include "ribp_irq_bindings.svh"
|
||||
|
||||
ribp_gpio u_rib_gpio (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.ribp(u_gpio_ribp_if),
|
||||
.gpio (gpio),
|
||||
.user_gpio(user_gpio)
|
||||
ribp_gpio #(
|
||||
.USER_BASE_ADDR (`SOC_ADDR_RIBP_GPIO_BASE),
|
||||
.ADMIN_BASE_ADDR(`SOC_ADDR_RIBP_GPIO_ADMIN_BASE),
|
||||
.HAS_INPUT_CMOS (GPIO_HAS_INPUT_CMOS),
|
||||
.HAS_PULL_UP (GPIO_HAS_PULL_UP),
|
||||
.HAS_PULL_DOWN (GPIO_HAS_PULL_DOWN)
|
||||
) u_rib_gpio (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.ribp (u_gpio_ribp_if),
|
||||
.gpio (gpio),
|
||||
.user_gpio (user_gpio)
|
||||
);
|
||||
// verilog_format: on
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ TEST_SOURCES = (
|
||||
"crt/src/lib/printf.c",
|
||||
"crt/src/lib/stdlib.c",
|
||||
"crt/src/lib/string.c",
|
||||
"crt/src/hal/gpio_math.c",
|
||||
"crt/src/hal/ws2812_math.c",
|
||||
"crt/src/hal/timer_math.c",
|
||||
"app/media/src/video_player.c",
|
||||
|
||||
+57
-64
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <retrosoc/core/status.h>
|
||||
#include <retrosoc/core/wait.h>
|
||||
#include <retrosoc/hal/gpio.h>
|
||||
#include <retrosoc/hal/lcd.h>
|
||||
#include <retrosoc/hal/spisd.h>
|
||||
#include <retrosoc/hal/timer.h>
|
||||
@@ -24,17 +25,12 @@ unsigned long long __umoddi3(unsigned long long dividend, unsigned long long div
|
||||
static uint8_t storage[32];
|
||||
static uint32_t image_call_count;
|
||||
|
||||
void putch(char ch)
|
||||
{
|
||||
void putch(char ch) {
|
||||
(void)ch;
|
||||
}
|
||||
|
||||
void lcd_fill_image(uint16_t x_start,
|
||||
uint16_t y_start,
|
||||
uint16_t x_end,
|
||||
uint16_t y_end,
|
||||
uint32_t *data)
|
||||
{
|
||||
void lcd_fill_image(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end,
|
||||
uint32_t *data) {
|
||||
(void)x_start;
|
||||
(void)y_start;
|
||||
(void)x_end;
|
||||
@@ -43,8 +39,7 @@ void lcd_fill_image(uint16_t x_start,
|
||||
++image_call_count;
|
||||
}
|
||||
|
||||
rs_status_t rs_spisd_read_bytes(void *buffer, size_t byte_count, uintptr_t address)
|
||||
{
|
||||
rs_status_t rs_spisd_read_bytes(void *buffer, size_t byte_count, uintptr_t address) {
|
||||
size_t offset;
|
||||
|
||||
if ((buffer == NULL) || (address < TEST_STORAGE_ADDRESS)) {
|
||||
@@ -60,11 +55,8 @@ rs_status_t rs_spisd_read_bytes(void *buffer, size_t byte_count, uintptr_t addre
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
static rs_status_t test_reader_read(void *context,
|
||||
uint32_t offset,
|
||||
void *buffer,
|
||||
size_t byte_count)
|
||||
{
|
||||
static rs_status_t test_reader_read(void *context, uint32_t offset, void *buffer,
|
||||
size_t byte_count) {
|
||||
const uint8_t *bytes = context;
|
||||
|
||||
if ((bytes == NULL) || (buffer == NULL)) {
|
||||
@@ -76,8 +68,7 @@ static rs_status_t test_reader_read(void *context,
|
||||
return RS_OK;
|
||||
}
|
||||
|
||||
static int test_string_helpers(void)
|
||||
{
|
||||
static int test_string_helpers(void) {
|
||||
char buffer[8] = {'x', '\0'};
|
||||
int32_t value;
|
||||
|
||||
@@ -87,12 +78,10 @@ static int test_string_helpers(void)
|
||||
if (strncmp("left", "right", 0U) != 0) {
|
||||
return 2;
|
||||
}
|
||||
if (rs_strlcpy(buffer, "abcdefghi", sizeof(buffer)) != 9U ||
|
||||
strcmp(buffer, "abcdefg") != 0) {
|
||||
if (rs_strlcpy(buffer, "abcdefghi", sizeof(buffer)) != 9U || strcmp(buffer, "abcdefg") != 0) {
|
||||
return 3;
|
||||
}
|
||||
if (rs_strlcat(buffer, "x", sizeof(buffer)) != 8U ||
|
||||
strcmp(buffer, "abcdefg") != 0) {
|
||||
if (rs_strlcat(buffer, "x", sizeof(buffer)) != 8U || strcmp(buffer, "abcdefg") != 0) {
|
||||
return 4;
|
||||
}
|
||||
if (rs_strtoi32("-2147483648", &value) != RS_OK || value != INT32_MIN ||
|
||||
@@ -103,12 +92,11 @@ static int test_string_helpers(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_formatter(void)
|
||||
{
|
||||
static int test_formatter(void) {
|
||||
char buffer[32];
|
||||
|
||||
if (rs_snprintf(buffer, sizeof(buffer), "%#08x:%lld:%zu", 0x2AU, -42LL,
|
||||
(size_t)7U) != 14 || strcmp(buffer, "0x00002a:-42:7") != 0) {
|
||||
if (rs_snprintf(buffer, sizeof(buffer), "%#08x:%lld:%zu", 0x2AU, -42LL, (size_t)7U) != 14 ||
|
||||
strcmp(buffer, "0x00002a:-42:7") != 0) {
|
||||
return 1;
|
||||
}
|
||||
if (rs_snprintf(buffer, 4U, "abcdef") != 6 || strcmp(buffer, "abc") != 0) {
|
||||
@@ -124,29 +112,25 @@ static int test_formatter(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_compiler_helpers(void)
|
||||
{
|
||||
static int test_compiler_helpers(void) {
|
||||
if ((__clzsi2(0U) != 32) || (__clzsi2(1U) != 31) || (__ffssi2(0U) != 0) ||
|
||||
(__ffssi2(1U) != 1) || (__ffssi2(0x10U) != 5)) {
|
||||
return 1;
|
||||
}
|
||||
if ((__udivdi3(UINT64_MAX, 3U) != 6148914691236517205ULL) ||
|
||||
(__umoddi3(UINT64_MAX, 3U) != 0U) ||
|
||||
(__udivdi3(UINT64_MAX, UINT64_MAX) != 1U) ||
|
||||
(__umoddi3(UINT64_MAX, 3U) != 0U) || (__udivdi3(UINT64_MAX, UINT64_MAX) != 1U) ||
|
||||
(__umoddi3(100U, 7U) != 2U) || (__divdi3(-100LL, 7LL) != -14LL)) {
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_wait_helper(void)
|
||||
{
|
||||
static int test_wait_helper(void) {
|
||||
volatile uint32_t value = 0x30U;
|
||||
|
||||
if (rs_wait_mask(&value, 0x30U, 0x30U, 1U) != RS_OK ||
|
||||
rs_wait_mask(&value, 0x40U, 0x40U, 1U) != RS_ETIMEOUT ||
|
||||
rs_wait_mask(NULL, 1U, 1U, 1U) != RS_EINVAL ||
|
||||
rs_wait_value(&value, 0x30U, 1U) != RS_OK ||
|
||||
rs_wait_mask(NULL, 1U, 1U, 1U) != RS_EINVAL || rs_wait_value(&value, 0x30U, 1U) != RS_OK ||
|
||||
rs_wait_not_value(&value, 0U, 1U) != RS_OK ||
|
||||
rs_wait_not_value(&value, 0x30U, 1U) != RS_ETIMEOUT) {
|
||||
return 1;
|
||||
@@ -154,8 +138,7 @@ static int test_wait_helper(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_ws2812_helpers(void)
|
||||
{
|
||||
static int test_ws2812_helpers(void) {
|
||||
const rs_ws2812_config_t config = {
|
||||
72000000U,
|
||||
RS_WS2812_DEFAULT_BIT_PERIOD_NS,
|
||||
@@ -168,9 +151,9 @@ static int test_ws2812_helpers(void)
|
||||
rs_ws2812_timing_t timing;
|
||||
|
||||
if ((rs_ws2812_pack_grb(0x12U, 0x34U, 0x56U) != UINT32_C(0x341256)) ||
|
||||
(rs_ws2812_timing_from_ns(&config, &timing) != RS_OK) ||
|
||||
(timing.bit_cycles != 90U) || (timing.t0h_cycles != 25U) ||
|
||||
(timing.t1h_cycles != 50U) || (timing.reset_cycles != 21600U)) {
|
||||
(rs_ws2812_timing_from_ns(&config, &timing) != RS_OK) || (timing.bit_cycles != 90U) ||
|
||||
(timing.t0h_cycles != 25U) || (timing.t1h_cycles != 50U) ||
|
||||
(timing.reset_cycles != 21600U)) {
|
||||
return 1;
|
||||
}
|
||||
invalid.t0h_ns = invalid.t1h_ns;
|
||||
@@ -187,16 +170,15 @@ static int test_ws2812_helpers(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_timer_helpers(void)
|
||||
{
|
||||
static int test_timer_helpers(void) {
|
||||
rs_timer_period_t period;
|
||||
|
||||
if ((rs_timer_period_from_ms(72000000U, 1U, &period) != RS_OK) ||
|
||||
(period.prescale != 0U) || (period.load != 71999U)) {
|
||||
if ((rs_timer_period_from_ms(72000000U, 1U, &period) != RS_OK) || (period.prescale != 0U) ||
|
||||
(period.load != 71999U)) {
|
||||
return 1;
|
||||
}
|
||||
if ((rs_timer_period_from_ms(72000000U, 1000U, &period) != RS_OK) ||
|
||||
(period.prescale != 0U) || (period.load != 71999999U)) {
|
||||
if ((rs_timer_period_from_ms(72000000U, 1000U, &period) != RS_OK) || (period.prescale != 0U) ||
|
||||
(period.load != 71999999U)) {
|
||||
return 2;
|
||||
}
|
||||
if ((rs_timer_period_from_ms(0U, 1U, &period) != RS_EINVAL) ||
|
||||
@@ -208,13 +190,32 @@ static int test_timer_helpers(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_wav_parser(void)
|
||||
{
|
||||
static int test_gpio_helpers(void) {
|
||||
rs_gpio_filter_timing_t timing;
|
||||
|
||||
if ((rs_gpio_filter_timing_from_us(72000000U, 2U, 3U, &timing) != RS_OK) ||
|
||||
(timing.divider != 143U) || (timing.stable_samples != 3U)) {
|
||||
return 1;
|
||||
}
|
||||
if ((rs_gpio_filter_timing_from_us(1U, 1U, 1U, &timing) != RS_OK) || (timing.divider != 0U)) {
|
||||
return 2;
|
||||
}
|
||||
if ((rs_gpio_filter_timing_from_us(0U, 1U, 1U, &timing) != RS_EINVAL) ||
|
||||
(rs_gpio_filter_timing_from_us(72000000U, 0U, 1U, &timing) != RS_EINVAL) ||
|
||||
(rs_gpio_filter_timing_from_us(72000000U, 2U, 0U, &timing) != RS_EINVAL) ||
|
||||
(rs_gpio_filter_timing_from_us(72000000U, 2U, 16U, &timing) != RS_EINVAL) ||
|
||||
(rs_gpio_filter_timing_from_us(72000000U, 1000U, 3U, &timing) != RS_EINVAL) ||
|
||||
(rs_gpio_filter_timing_from_us(72000000U, 2U, 3U, NULL) != RS_EINVAL)) {
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_wav_parser(void) {
|
||||
static const uint8_t wav[] = {
|
||||
'R', 'I', 'F', 'F', 40U, 0U, 0U, 0U, 'W', 'A', 'V', 'E',
|
||||
'f', 'm', 't', ' ', 16U, 0U, 0U, 0U, 1U, 0U, 1U, 0U,
|
||||
0x40U, 0x1FU, 0U, 0U, 0x80U, 0x3EU, 0U, 0U, 2U, 0U, 16U, 0U,
|
||||
'd', 'a', 't', 'a', 4U, 0U, 0U, 0U, 0U, 1U, 2U, 3U,
|
||||
'R', 'I', 'F', 'F', 40U, 0U, 0U, 0U, 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ',
|
||||
16U, 0U, 0U, 0U, 1U, 0U, 1U, 0U, 0x40U, 0x1FU, 0U, 0U, 0x80U, 0x3EU, 0U, 0U,
|
||||
2U, 0U, 16U, 0U, 'd', 'a', 't', 'a', 4U, 0U, 0U, 0U, 0U, 1U, 2U, 3U,
|
||||
};
|
||||
rs_wav_info_t info;
|
||||
const rs_wav_reader_t reader = {test_reader_read, (void *)wav, sizeof(wav)};
|
||||
@@ -223,15 +224,13 @@ static int test_wav_parser(void)
|
||||
info.block_align != 2U || info.data_offset != 44U || info.data_size != 4U) {
|
||||
return 1;
|
||||
}
|
||||
if (rs_wav_parse(&(rs_wav_reader_t){test_reader_read, (void *)wav, 12U}, &info) !=
|
||||
RS_EFORMAT) {
|
||||
if (rs_wav_parse(&(rs_wav_reader_t){test_reader_read, (void *)wav, 12U}, &info) != RS_EFORMAT) {
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_video_parser(void)
|
||||
{
|
||||
static int test_video_parser(void) {
|
||||
rs_video_info_t info;
|
||||
|
||||
(void)memset(storage, 0, sizeof(storage));
|
||||
@@ -249,17 +248,11 @@ static int test_video_parser(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(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_wav_parser(),
|
||||
test_video_parser(),
|
||||
test_string_helpers(), test_formatter(), test_compiler_helpers(),
|
||||
test_wait_helper(), test_ws2812_helpers(), test_timer_helpers(),
|
||||
test_gpio_helpers(), test_wav_parser(), test_video_parser(),
|
||||
};
|
||||
|
||||
for (size_t index = 0U; index < (sizeof(results) / sizeof(results[0])); ++index) {
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
`include "gpio_define.svh"
|
||||
|
||||
module gpio_tb;
|
||||
localparam int PIN_NUM = 4;
|
||||
localparam logic [31:0] USER_BASE = 32'h1000_0000;
|
||||
localparam logic [31:0] ADMIN_BASE = 32'h1001_4000;
|
||||
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
ribp_if ribp ();
|
||||
gpio_if #(PIN_NUM) gpio ();
|
||||
user_gpio_if #(PIN_NUM) user_gpio ();
|
||||
logic [31:0] read_data;
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
ribp_gpio #(
|
||||
.PIN_NUM (PIN_NUM),
|
||||
.USER_BASE_ADDR (USER_BASE),
|
||||
.ADMIN_BASE_ADDR(ADMIN_BASE),
|
||||
.HAS_INPUT_CMOS (1'b1),
|
||||
.HAS_PULL_UP (1'b1),
|
||||
.HAS_PULL_DOWN (1'b1)
|
||||
) dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.ribp (ribp),
|
||||
.gpio (gpio),
|
||||
.user_gpio(user_gpio)
|
||||
);
|
||||
|
||||
task automatic write_register(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;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if (!ribp.ready || (ribp.resp_err !== expected_error)) begin
|
||||
$fatal(1, "write response mismatch at %08x", address);
|
||||
end
|
||||
@(negedge clk_i);
|
||||
ribp.valid = 1'b0;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic read_register(input logic [31:0] address, output logic [31:0] data,
|
||||
input logic expected_error);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
ribp.addr = address;
|
||||
ribp.wdata = '0;
|
||||
ribp.wstrb = '0;
|
||||
ribp.valid = 1'b1;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if (!ribp.ready || (ribp.resp_err !== expected_error)) begin
|
||||
$fatal(1, "read response mismatch at %08x", address);
|
||||
end
|
||||
data = ribp.rdata;
|
||||
@(negedge clk_i);
|
||||
ribp.valid = 1'b0;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
ribp.valid = 1'b0;
|
||||
ribp.addr = '0;
|
||||
ribp.wdata = '0;
|
||||
ribp.wstrb = '0;
|
||||
gpio.di_i = '0;
|
||||
gpio.alt0_do_i = '0;
|
||||
gpio.alt0_oe_i = '0;
|
||||
gpio.alt1_do_i = '0;
|
||||
gpio.alt1_oe_i = '0;
|
||||
user_gpio.do_o = '0;
|
||||
user_gpio.oe_o = '0;
|
||||
|
||||
repeat (3) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
repeat (3) @(posedge clk_i);
|
||||
|
||||
read_register(ADMIN_BASE + `RIBP_GPIO_CAPABILITY, read_data, 1'b0);
|
||||
if (read_data !== 32'h007F_4204) $fatal(1, "capability register mismatch");
|
||||
read_register(ADMIN_BASE + `RIBP_GPIO_PAD_CAPABILITY, read_data, 1'b0);
|
||||
if (read_data !== 32'h0000_0007) $fatal(1, "pad capability register mismatch");
|
||||
read_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_OUTPUT_ENABLE, read_data, 1'b0);
|
||||
if (read_data !== 32'd0) $fatal(1, "output enable reset value mismatch");
|
||||
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_OUT_SET, 32'h1, 1'b0);
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_OE_SET, 32'h1, 1'b0);
|
||||
if ({gpio.oe_o[0], gpio.do_o[0]} !== 2'b11) $fatal(1, "software output failed");
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_OUT_TOGGLE, 32'h1, 1'b0);
|
||||
if (gpio.do_o[0] !== 1'b0) $fatal(1, "atomic output toggle failed");
|
||||
read_register(ADMIN_BASE + 32'h2, read_data, 1'b1);
|
||||
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_USER_ACCESS_MASK, 32'h2, 1'b0);
|
||||
write_register(USER_BASE + `RIBP_GPIO_USER_OUT_SET, 32'h6, 1'b0);
|
||||
read_register(USER_BASE + `RIBP_GPIO_USER_DATA_OUT, read_data, 1'b0);
|
||||
if (read_data !== 32'h2) $fatal(1, "user access mask did not isolate output data");
|
||||
|
||||
user_gpio.do_o[2] = 1'b1;
|
||||
user_gpio.oe_o[2] = 1'b1;
|
||||
@(negedge clk_i);
|
||||
ribp.addr = ADMIN_BASE + `RIBP_GPIO_ADMIN_USER_SELECT;
|
||||
ribp.wdata = 32'h4;
|
||||
ribp.wstrb = 4'hF;
|
||||
ribp.valid = 1'b1;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if (gpio.oe_o[2] !== 1'b0) $fatal(1, "user handoff did not force high impedance");
|
||||
@(negedge clk_i);
|
||||
ribp.valid = 1'b0;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if ({gpio.oe_o[2], gpio.do_o[2]} !== 2'b11) $fatal(1, "user output was not selected");
|
||||
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_OE_SET, 32'h2, 1'b0);
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_OPEN_DRAIN, 32'h2, 1'b0);
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_OUT_SET, 32'h2, 1'b0);
|
||||
if ({gpio.oe_o[1], gpio.do_o[1]} !== 2'b00) $fatal(1, "open-drain release failed");
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_OUT_CLEAR, 32'h2, 1'b0);
|
||||
if ({gpio.oe_o[1], gpio.do_o[1]} !== 2'b10) $fatal(1, "open-drain low drive failed");
|
||||
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_PULL_UP, 32'h8, 1'b0);
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_PULL_DOWN, 32'h8, 1'b1);
|
||||
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_INTR_RISE_ENABLE, 32'h1, 1'b0);
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_INTR_ENABLE, 32'h1, 1'b0);
|
||||
gpio.di_i[0] = 1'b1;
|
||||
repeat (5) @(posedge clk_i);
|
||||
read_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_INTR_STATE, read_data, 1'b0);
|
||||
if ((read_data & 32'h1) == 0) $fatal(1, "rising edge interrupt was not latched");
|
||||
if (!gpio.irq_o) $fatal(1, "combined GPIO interrupt was not asserted");
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_INTR_STATE, 32'h1, 1'b0);
|
||||
if (gpio.irq_o) $fatal(1, "W1C did not clear the interrupt");
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_INTR_TEST, 32'h1, 1'b0);
|
||||
if (!gpio.irq_o) $fatal(1, "software interrupt test failed");
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_INTR_STATE, 32'h1, 1'b0);
|
||||
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_INTR_RISE_ENABLE, 32'h9, 1'b0);
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_INTR_HIGH_ENABLE, 32'h8, 1'b1);
|
||||
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_FILTER_DIV, 32'h0, 1'b0);
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_FILTER_COUNT, 32'h4, 1'b0);
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_FILTER_ENABLE, 32'h8, 1'b0);
|
||||
gpio.di_i[3] = 1'b1;
|
||||
@(posedge clk_i);
|
||||
gpio.di_i[3] = 1'b0;
|
||||
repeat (5) @(posedge clk_i);
|
||||
read_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_DATA_IN, read_data, 1'b0);
|
||||
if ((read_data & 32'h8) != 0) $fatal(1, "input filter accepted a short pulse");
|
||||
gpio.di_i[3] = 1'b1;
|
||||
repeat (8) @(posedge clk_i);
|
||||
read_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_DATA_IN, read_data, 1'b0);
|
||||
if ((read_data & 32'h8) == 0) $fatal(1, "input filter rejected a stable input");
|
||||
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_CONFIG_LOCK, 32'h1, 1'b0);
|
||||
write_register(ADMIN_BASE + `RIBP_GPIO_ADMIN_OE_CLEAR, 32'h1, 1'b1);
|
||||
if (gpio.oe_o[0] !== 1'b1) $fatal(1, "configuration lock did not protect OE");
|
||||
|
||||
$display("GPIO V2 directed test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -1,127 +0,0 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module gpio_user_mux_tb;
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
ribp_if rib ();
|
||||
gpio_if gpio ();
|
||||
user_gpio_if user_gpio ();
|
||||
logic [31:0] read_data;
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
ribp_gpio dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.ribp (rib),
|
||||
.gpio (gpio),
|
||||
.user_gpio(user_gpio)
|
||||
);
|
||||
|
||||
task automatic write_register(input logic [7:0] address, input logic [31:0] data);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
rib.addr = {24'd0, address};
|
||||
rib.wdata = data;
|
||||
rib.wstrb = 4'hF;
|
||||
rib.valid = 1'b1;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
@(negedge clk_i);
|
||||
rib.valid = 1'b0;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic read_register(input logic [7:0] address, output logic [31:0] data);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
rib.addr = {24'd0, address};
|
||||
rib.wdata = '0;
|
||||
rib.wstrb = '0;
|
||||
rib.valid = 1'b1;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
data = rib.rdata;
|
||||
@(negedge clk_i);
|
||||
rib.valid = 1'b0;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic select_user_gpio(input logic [31:0] selection);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
rib.addr = 32'h0000_0030;
|
||||
rib.wdata = selection;
|
||||
rib.wstrb = 4'hF;
|
||||
rib.valid = 1'b1;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
if (gpio.oe_o[0] !== 1'b0) $fatal(1, "GPIO handoff did not drive high impedance");
|
||||
@(negedge clk_i);
|
||||
rib.valid = 1'b0;
|
||||
@(posedge clk_i);
|
||||
#1;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
rib.valid = 1'b0;
|
||||
rib.addr = '0;
|
||||
rib.wdata = '0;
|
||||
rib.wstrb = '0;
|
||||
gpio.di_i = '0;
|
||||
gpio.alt0_do_i = '0;
|
||||
gpio.alt0_oe_i = '0;
|
||||
gpio.alt1_do_i = '0;
|
||||
gpio.alt1_oe_i = '0;
|
||||
user_gpio.do_o = '0;
|
||||
user_gpio.oe_o = '0;
|
||||
|
||||
repeat (2) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
repeat (2) @(posedge clk_i);
|
||||
|
||||
write_register(8'h00, 32'h0000_0001);
|
||||
write_register(8'h10, 32'h0000_0001);
|
||||
if ({gpio.oe_o[0], gpio.do_o[0]} !== 2'b11) $fatal(1, "rib software GPIO is not active");
|
||||
|
||||
user_gpio.do_o[0] = 1'b0;
|
||||
user_gpio.oe_o[0] = 1'b1;
|
||||
select_user_gpio(32'h0000_0001);
|
||||
if ({gpio.oe_o[0], gpio.do_o[0]} !== 2'b10) $fatal(1, "user GPIO was not selected");
|
||||
read_register(8'h30, read_data);
|
||||
if (read_data !== 32'h0000_0001) $fatal(1, "USER_SEL readback is incorrect");
|
||||
read_register(8'h38, read_data);
|
||||
if (read_data !== 32'h0000_0001) $fatal(1, "USER_STATUS is not active after handoff");
|
||||
|
||||
gpio.di_i[0] = 1'b1;
|
||||
#1;
|
||||
if (user_gpio.di_i[0] !== 1'b1) $fatal(1, "user GPIO input path is disconnected");
|
||||
|
||||
write_register(8'h34, 32'h0000_0001);
|
||||
read_register(8'h34, read_data);
|
||||
if (read_data !== 32'h0000_0001) $fatal(1, "USER_LOCK is not write-one-set");
|
||||
write_register(8'h30, '0);
|
||||
if ({gpio.oe_o[0], gpio.do_o[0]} !== 2'b10) $fatal(1, "USER_LOCK did not preserve ownership");
|
||||
read_register(8'h30, read_data);
|
||||
if (read_data !== 32'h0000_0001) $fatal(1, "locked USER_SEL changed");
|
||||
|
||||
gpio.alt0_do_i[1] = 1'b1;
|
||||
gpio.alt0_oe_i[1] = 1'b1;
|
||||
write_register(8'h28, 32'h0000_0002);
|
||||
if ({gpio.oe_o[1], gpio.do_o[1]} !== 2'b11) $fatal(1, "alternate GPIO mode regressed");
|
||||
|
||||
write_register(8'h04, 32'h0000_0001);
|
||||
write_register(8'h08, 32'h0000_0001);
|
||||
write_register(8'h0C, 32'h0000_0001);
|
||||
if ({gpio.cs_o[0], gpio.pu_o[0], gpio.pd_o[0]} !== 3'b111)
|
||||
$fatal(1, "rib GPIO electrical controls changed under user ownership");
|
||||
|
||||
$display("GPIO user ownership test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -140,6 +140,7 @@ module ribp_topology_tb;
|
||||
rst_n_i = 1'b1;
|
||||
|
||||
expect_route(`SOC_ADDR_RIBP_GPIO_BASE, 1, 32'h1111_1111);
|
||||
expect_route(`SOC_ADDR_RIBP_GPIO_ADMIN_BASE, 1, 32'h1111_1111);
|
||||
expect_route(`SOC_ADDR_PSRAM_BASE, 4, 32'h4444_4444);
|
||||
expect_route(`SOC_ADDR_FLASH_BASE, 9, 32'h9999_9999);
|
||||
expect_route(`SOC_ADDR_RIBP_I2C1_BASE, 17, 32'h1234_5678);
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
"""Directed RTL tests for the GPIO V2 register and pad-control contract."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def test_gpio_v2_register_pad_interrupt_and_filter_contract(tmp_path: Path) -> None:
|
||||
iverilog = shutil.which("iverilog")
|
||||
sv2v = shutil.which("sv2v")
|
||||
vvp = shutil.which("vvp")
|
||||
if iverilog is None or sv2v is None or vvp is None:
|
||||
return
|
||||
|
||||
peripheral = ROOT / "rtl/ip/ribp/peripheral"
|
||||
common = ROOT / "rtl/managed/clusterip/common/rtl"
|
||||
source_list = tmp_path / "gpio.fl"
|
||||
source_list.write_text(
|
||||
"\n".join(
|
||||
[
|
||||
"+define+SV_ASSRT_DISABLE",
|
||||
f"+incdir+{peripheral}",
|
||||
f"+incdir+{common}",
|
||||
str(common / "interface/ribp_if.sv"),
|
||||
str(common / "utils/register.sv"),
|
||||
str(common / "clkrst/counter.sv"),
|
||||
str(common / "cdc/cdc_sync.sv"),
|
||||
str(common / "utils/edge_det.sv"),
|
||||
str(peripheral / "gpio_if.sv"),
|
||||
str(peripheral / "user_gpio_if.sv"),
|
||||
str(peripheral / "gpio_core.sv"),
|
||||
str(peripheral / "gpio_reg.sv"),
|
||||
str(peripheral / "ribp_gpio.sv"),
|
||||
str(ROOT / "tests/rtl/gpio_tb.sv"),
|
||||
"",
|
||||
]
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
converted = tmp_path / "gpio_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 / "gpio_tb"
|
||||
subprocess.run(
|
||||
[iverilog, "-g2012", "-s", "gpio_tb", "-o", str(simulation), str(converted)],
|
||||
check=True,
|
||||
)
|
||||
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
|
||||
|
||||
assert "GPIO V2 directed test passed" in result.stdout
|
||||
@@ -1,58 +0,0 @@
|
||||
"""RTL tests for user-IP ownership of the rib GPIO pad bank."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def test_user_ip_can_own_rib_gpio_pads_with_a_safe_handoff(tmp_path: Path) -> None:
|
||||
iverilog = shutil.which("iverilog")
|
||||
sv2v = shutil.which("sv2v")
|
||||
vvp = shutil.which("vvp")
|
||||
if iverilog is None or sv2v is None or vvp is None:
|
||||
return
|
||||
|
||||
source_list = tmp_path / "gpio_user_mux.fl"
|
||||
source_list.write_text(
|
||||
"\n".join(
|
||||
[
|
||||
"+define+SV_ASSRT_DISABLE",
|
||||
f"+incdir+{ROOT / 'rtl/ip/ribp/peripheral'}",
|
||||
f"+incdir+{ROOT / 'rtl/managed/clusterip/common/rtl'}",
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/interface/ribp_if.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/register.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_sync.sv"),
|
||||
str(ROOT / "rtl/managed/clusterip/common/rtl/utils/edge_det.sv"),
|
||||
str(ROOT / "rtl/ip/ribp/peripheral/gpio.sv"),
|
||||
str(ROOT / "tests/rtl/gpio_user_mux_tb.sv"),
|
||||
"",
|
||||
]
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
converted = tmp_path / "gpio_user_mux_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 / "gpio_user_mux_tb"
|
||||
subprocess.run(
|
||||
[iverilog, "-g2012", "-s", "gpio_user_mux_tb", "-o", str(simulation), str(converted)],
|
||||
check=True,
|
||||
)
|
||||
result = subprocess.run([vvp, str(simulation)], text=True, capture_output=True, check=True)
|
||||
|
||||
assert "GPIO user ownership test passed" in result.stdout
|
||||
@@ -58,6 +58,8 @@ def test_generated_artifacts_share_the_capacity_baseline(tmp_path: Path) -> None
|
||||
assert "RS_SOC_PSRAM_SIZE UINT32_C(0x00800000)" in header
|
||||
assert "RS_SOC_SDRAM_SIZE UINT32_C(0x02000000)" in header
|
||||
assert "RS_SOC_SPISD_SIZE UINT32_C(0x40000000)" in header
|
||||
assert "#ifdef __ASSEMBLER__" in header
|
||||
assert "#define UINT32_C(value) value" in header
|
||||
assert "RS_SOC_RIBP_SDIO_BASE" not in header
|
||||
assert "RS_SOC_NMI_" not in header
|
||||
assert "RS_SOC_OPIPSRAM_BASE" not in header
|
||||
@@ -83,6 +85,17 @@ def test_user_ip_is_always_emitted_for_the_fixed_platform(tmp_path: Path) -> Non
|
||||
assert "RS_SOC_APB_USER_IP_BASE" in header
|
||||
|
||||
|
||||
def test_bootstrap_assembly_uses_the_generated_gpio_admin_base() -> None:
|
||||
for source in (ROOT / "crt/arch/riscv/startup.S", ROOT / "app/asm/hello.s"):
|
||||
text = source.read_text(encoding="utf-8")
|
||||
assert '#include "retrosoc/generated/memory_map.h"' in text
|
||||
assert "RS_SOC_RIBP_GPIO_ADMIN_BASE + 0x34" in text
|
||||
assert "RS_SOC_RIBP_GPIO_ADMIN_BASE + 0x38" in text
|
||||
assert "RS_SOC_RIBP_PSRAM_BASE + 0x08" in text
|
||||
assert "0x10000028" not in text
|
||||
assert "0x1000002c" not in text
|
||||
|
||||
|
||||
def test_map_validation_rejects_overlaps(tmp_path: Path) -> None:
|
||||
document = json.loads(MEMORY_MAP.read_text(encoding="utf-8"))
|
||||
document["regions"][1]["base"] = document["regions"][0]["base"]
|
||||
|
||||
@@ -203,7 +203,7 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
|
||||
rib2apb_filelist = tmp_path / "rib2apb.fl"
|
||||
sysctrl_filelist = tmp_path / "sysctrl.fl"
|
||||
pll_rcu_filelist = tmp_path / "pll_rcu.fl"
|
||||
gpio_user_filelist = tmp_path / "gpio_user.fl"
|
||||
gpio_filelist = tmp_path / "gpio.fl"
|
||||
ws2812_filelist = tmp_path / "ws2812.fl"
|
||||
clint_filelist = tmp_path / "clint.fl"
|
||||
assert generate_formal_filelist("bus", bus_filelist, memory_map, topology, user_extensions)
|
||||
@@ -220,7 +220,7 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
|
||||
"pll_rcu", pll_rcu_filelist, memory_map, topology, user_extensions
|
||||
)
|
||||
assert generate_formal_filelist(
|
||||
"gpio_user", gpio_user_filelist, memory_map, topology, user_extensions
|
||||
"gpio", gpio_filelist, memory_map, topology, user_extensions
|
||||
)
|
||||
assert generate_formal_filelist(
|
||||
"ws2812", ws2812_filelist, memory_map, topology, user_extensions
|
||||
@@ -234,7 +234,7 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
|
||||
rib2apb = parse_filelists([rib2apb_filelist], require_files=False)
|
||||
sysctrl = parse_filelists([sysctrl_filelist], require_files=False)
|
||||
pll_rcu = parse_filelists([pll_rcu_filelist], require_files=False)
|
||||
gpio_user = parse_filelists([gpio_user_filelist], require_files=False)
|
||||
gpio = parse_filelists([gpio_filelist], require_files=False)
|
||||
ws2812 = parse_filelists([ws2812_filelist], require_files=False)
|
||||
clint = parse_filelists([clint_filelist], require_files=False)
|
||||
assert "+define+SV_ASSRT_DISABLE" in bus.defines
|
||||
@@ -253,9 +253,12 @@ def test_formal_filelists_are_scoped_to_the_protocol_duts(tmp_path: Path) -> Non
|
||||
assert ROOT / "rtl/mini/top/rcu.sv" in pll_rcu.files
|
||||
assert ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_2phase.sv" in pll_rcu.files
|
||||
assert ROOT / "rtl/managed/clusterip/common/rtl/clkrst/rst_sync.sv" in pll_rcu.files
|
||||
assert ROOT / "rtl/ip/ribp/peripheral/gpio.sv" in gpio_user.files
|
||||
assert ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_sync.sv" in gpio_user.files
|
||||
assert ROOT / "rtl/mini/formal/gpio_user_formal.sv" in gpio_user.files
|
||||
assert ROOT / "rtl/ip/ribp/peripheral/gpio_core.sv" in gpio.files
|
||||
assert ROOT / "rtl/ip/ribp/peripheral/gpio_reg.sv" in gpio.files
|
||||
assert ROOT / "rtl/ip/ribp/peripheral/ribp_gpio.sv" in gpio.files
|
||||
assert ROOT / "rtl/ip/ribp/peripheral/user_gpio_if.sv" in gpio.files
|
||||
assert ROOT / "rtl/managed/clusterip/common/rtl/cdc/cdc_sync.sv" in gpio.files
|
||||
assert ROOT / "rtl/mini/formal/gpio_formal.sv" in gpio.files
|
||||
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
|
||||
@@ -306,7 +309,7 @@ def test_fatfs_release_script_uses_the_locked_archive_contract() -> None:
|
||||
|
||||
|
||||
def test_formal_result_summary_requires_every_passing_step(tmp_path: Path) -> None:
|
||||
proofs = ("bus", "rib2apb", "sysctrl", "pll_rcu", "gpio_user", "ws2812")
|
||||
proofs = ("bus", "rib2apb", "sysctrl", "pll_rcu", "gpio", "ws2812")
|
||||
for proof in proofs:
|
||||
directory = tmp_path / proof
|
||||
directory.mkdir()
|
||||
@@ -334,7 +337,7 @@ def test_formal_result_summary_requires_every_passing_step(tmp_path: Path) -> No
|
||||
"--proof",
|
||||
f"pll_rcu={tmp_path / 'pll_rcu'}",
|
||||
"--proof",
|
||||
f"gpio_user={tmp_path / 'gpio_user'}",
|
||||
f"gpio={tmp_path / 'gpio'}",
|
||||
"--proof",
|
||||
f"ws2812={tmp_path / 'ws2812'}",
|
||||
)
|
||||
|
||||
@@ -97,11 +97,12 @@ 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'h0003FFFC" in irq_config
|
||||
assert "`define SOC_IRQ_RIBP_WIDTH 11" 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_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[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
|
||||
@@ -122,7 +123,7 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
|
||||
)
|
||||
for interrupt in document["interrupts"]
|
||||
]
|
||||
assert mappings[:18] == [
|
||||
assert mappings[:19] == [
|
||||
("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"),
|
||||
@@ -141,8 +142,9 @@ def test_topology_preserves_default_irq_compatibility_mapping() -> None:
|
||||
("advanced_timer", "apb", 5, 15, "u_tmr_if.irq_o"),
|
||||
("reserved", "apb", 6, 16, "1'b0"),
|
||||
("ws2812", "ribp", 10, 17, "ws2812.irq_o"),
|
||||
("gpio", "ribp", 11, 18, "gpio.irq_o"),
|
||||
]
|
||||
assert all(mapping[3] >= 18 for mapping in mappings[18:])
|
||||
assert all(mapping[3] >= 19 for mapping in mappings[19:])
|
||||
|
||||
|
||||
def test_topology_always_adds_the_user_apb_target(tmp_path: Path) -> None:
|
||||
|
||||
Reference in new issue
Block a user