From 068c05bf66d4721acbe5bf3a686749fe40caba0a Mon Sep 17 00:00:00 2001 From: maksyuki Date: Tue, 11 Aug 2026 07:35:06 +0800 Subject: [PATCH] feat: add PWM V2 support and update GPIO configurations - Introduced PWM V2 alternate functions in the documentation, detailing the GPIO mappings and fault handling. - Updated the filelist to include new PWM RTL files for the PWM V2 implementation. - Modified the SOC topology JSON to reflect new GPIO alternate functions for PWM, including synchronization and capture inputs. - Updated software makefile to include PWM source and header files. - Enhanced the APB wrapper to integrate the PWM module with proper parameters. - Updated the ASIC top-level module to include new GPIO mappings for PWM functionality. - Added tests to validate the new GPIO and PWM connections in the topology. --- README.md | 4 +- app/apps/shell/main.c | 2 +- config/dependencies.lock.json | 2 +- crt/include/retrosoc/core/soc.h | 10 - crt/include/retrosoc/hal/pwm.h | 74 ++- crt/src/hal/pwm.c | 238 +++++++-- crt/src/service/booter.c | 3 +- docs/README.md | 3 + docs/mini-soc-block-diagram.dot | 13 +- docs/mini-soc-block-diagram.svg | 694 +++++++++++++------------ docs/soc-integration-wiring.md | 17 + rtl/mini/filelist/clusterip.fl | 9 + rtl/mini/integration/soc_topology.json | 16 +- rtl/mini/mk/software.mk | 4 + rtl/mini/top/ip_apb_wrapper.sv | 9 +- rtl/mini/top/retrosoc_asic.sv | 39 ++ tests/test_soc_topology.py | 6 + 17 files changed, 749 insertions(+), 394 deletions(-) diff --git a/README.md b/README.md index d26049d5..adb10b36 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,9 @@ under the [Mulan Permissive Software License, Version 2](LICENSE). - Configurable GF180, SKY130, IHP130, and ICS55 implementation targets with open-source CI coverage. - A memory-mapped peripheral subsystem with GPIO, UART, - [dual general timers](docs/ip/timer.md), PWM, [dual I2C controllers](docs/ip/i2c.md), I2S, + [dual general timers](docs/ip/timer.md), + [PWM V2](rtl/managed/clusterip/pwm/doc/datasheet.md), + [dual I2C controllers](docs/ip/i2c.md), I2S, [bidirectional PS/2 V2](docs/ip/ps2.md), WS2812, SPI/QSPI, SDIO, PSRAM/OPI-PSRAM, SDRAM, DMA, LCD, RTC, an independent-clock window watchdog, CRC, and a diff --git a/app/apps/shell/main.c b/app/apps/shell/main.c index f4c7ae0e..24cb6a5f 100644 --- a/app/apps/shell/main.c +++ b/app/apps/shell/main.c @@ -59,7 +59,7 @@ int main(void) { (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, rs_gpio_shell_test); - (void)rs_shell_register("pwm", "pwm test", true, ip_pwm_test); + (void)rs_shell_register("pwm", "pwm test", true, rs_pwm_shell_test); (void)rs_shell_register("rtc", "rtc test", true, rs_rtc_shell_test); (void)rs_shell_register("wdg", "wdg test", true, ip_wdg_test); (void)rs_shell_register("rng", "rng test", true, rs_rng_shell_test); diff --git a/config/dependencies.lock.json b/config/dependencies.lock.json index 63f80fcc..915c077d 100644 --- a/config/dependencies.lock.json +++ b/config/dependencies.lock.json @@ -68,7 +68,7 @@ "cluster_i2s": {"url": "https://github.com/retroSoC/i2s.git", "revision": "bd0978e8b45e4cf4c1335a1fa7311385d2a4e805", "destination": "rtl/managed/clusterip/i2s", "license": "NOASSERTION"}, "cluster_plic": {"url": "https://github.com/retroSoC/plic.git", "revision": "c851d93829d2e75b224003a058e718925855c0cc", "destination": "rtl/managed/clusterip/plic", "license": "NOASSERTION"}, "cluster_ps2": {"url": "https://github.com/retroSoC/ps2.git", "revision": "2097a0d41b07573ff0453d65ba9a1670b3df7b9c", "destination": "rtl/managed/clusterip/ps2", "license": "MulanPSL-2.0"}, - "cluster_pwm": {"url": "https://github.com/retroSoC/pwm.git", "revision": "c631ede87506d34f714167313ba69b196c0bea72", "destination": "rtl/managed/clusterip/pwm", "license": "NOASSERTION"}, + "cluster_pwm": {"url": "https://github.com/retroSoC/pwm.git", "revision": "79ae32f725e848a1e7f6134847b3fb032ed64006", "destination": "rtl/managed/clusterip/pwm", "license": "MulanPSL-2.0"}, "cluster_rng": {"url": "https://github.com/retroSoC/rng.git", "revision": "36f3e0774d8f3c4b597d3db8a96ca3992532b61e", "destination": "rtl/managed/clusterip/rng", "license": "MulanPSL-2.0"}, "cluster_rtc": {"url": "https://github.com/retroSoC/rtc.git", "revision": "32548c5cbcdf39e09d0880fb611f9dd47940ea88", "destination": "rtl/managed/clusterip/rtc", "license": "NOASSERTION"}, "cluster_spi": {"url": "https://github.com/retroSoC/spi.git", "revision": "515cb408806584525605b4747db5e890dbdf1928", "destination": "rtl/managed/clusterip/spi", "license": "NOASSERTION"}, diff --git a/crt/include/retrosoc/core/soc.h b/crt/include/retrosoc/core/soc.h index 9bcca9b3..f50497bb 100644 --- a/crt/include/retrosoc/core/soc.h +++ b/crt/include/retrosoc/core/soc.h @@ -192,16 +192,6 @@ #define reg_uart1_trx RS_SOC_REG32(RS_SOC_APB_UART1_BASE, UINT32_C(0x08)) #define reg_uart1_fcr RS_SOC_REG32(RS_SOC_APB_UART1_BASE, UINT32_C(0x0C)) #define reg_uart1_lsr RS_SOC_REG32(RS_SOC_APB_UART1_BASE, UINT32_C(0x10)) -// pwm -#define reg_pwm_ctrl RS_SOC_REG32(RS_SOC_APB_PWM_BASE, UINT32_C(0x00)) -#define reg_pwm_pscr RS_SOC_REG32(RS_SOC_APB_PWM_BASE, UINT32_C(0x04)) -#define reg_pwm_cnt RS_SOC_REG32(RS_SOC_APB_PWM_BASE, UINT32_C(0x08)) -#define reg_pwm_cmp RS_SOC_REG32(RS_SOC_APB_PWM_BASE, UINT32_C(0x0C)) -#define reg_pwm_cr0 RS_SOC_REG32(RS_SOC_APB_PWM_BASE, UINT32_C(0x10)) -#define reg_pwm_cr1 RS_SOC_REG32(RS_SOC_APB_PWM_BASE, UINT32_C(0x14)) -#define reg_pwm_cr2 RS_SOC_REG32(RS_SOC_APB_PWM_BASE, UINT32_C(0x18)) -#define reg_pwm_cr3 RS_SOC_REG32(RS_SOC_APB_PWM_BASE, UINT32_C(0x1C)) -#define reg_pwm_stat RS_SOC_REG32(RS_SOC_APB_PWM_BASE, UINT32_C(0x20)) // tim3 #define reg_tim3_ctrl RS_SOC_REG32(RS_SOC_APB_TMR_BASE, UINT32_C(0x00)) #define reg_tim3_pscr RS_SOC_REG32(RS_SOC_APB_TMR_BASE, UINT32_C(0x04)) diff --git a/crt/include/retrosoc/hal/pwm.h b/crt/include/retrosoc/hal/pwm.h index ab71112d..67f5b322 100644 --- a/crt/include/retrosoc/hal/pwm.h +++ b/crt/include/retrosoc/hal/pwm.h @@ -1,5 +1,77 @@ #ifndef RETROSOC_PWM_H #define RETROSOC_PWM_H -void ip_pwm_test(int argc, char **argv); +#include +#include + +#include + +typedef pwm_timer_config_t rs_pwm_timer_config_t; +typedef pwm_channel_config_t rs_pwm_channel_config_t; +typedef pwm_operator_config_t rs_pwm_operator_config_t; +typedef pwm_fade_segment_t rs_pwm_fade_segment_t; +typedef pwm_fault_config_t rs_pwm_fault_config_t; +typedef pwm_capture_config_t rs_pwm_capture_config_t; +typedef pwm_snapshot_t rs_pwm_snapshot_t; +typedef pwm_count_mode_t rs_pwm_count_mode_t; +typedef pwm_load_mode_t rs_pwm_load_mode_t; +typedef pwm_safe_state_t rs_pwm_safe_state_t; + +#define RS_PWM_COUNT_MODE_UP PWM_COUNT_MODE_UP +#define RS_PWM_COUNT_MODE_DOWN PWM_COUNT_MODE_DOWN +#define RS_PWM_COUNT_MODE_UP_DOWN PWM_COUNT_MODE_UP_DOWN +#define RS_PWM_LOAD_ON_ZERO PWM_LOAD_ON_ZERO +#define RS_PWM_LOAD_ON_PERIOD PWM_LOAD_ON_PERIOD +#define RS_PWM_LOAD_ON_ZERO_OR_SYNC PWM_LOAD_ON_ZERO_OR_SYNC +#define RS_PWM_LOAD_ON_SYNC PWM_LOAD_ON_SYNC +#define RS_PWM_SAFE_LOW PWM_SAFE_LOW +#define RS_PWM_SAFE_HIGH PWM_SAFE_HIGH +#define RS_PWM_SAFE_HIGH_Z PWM_SAFE_HIGH_Z +#define RS_PWM_ACTION_HOLD PWM_ACTION_HOLD +#define RS_PWM_ACTION_LOW PWM_ACTION_LOW +#define RS_PWM_ACTION_HIGH PWM_ACTION_HIGH +#define RS_PWM_ACTION_TOGGLE PWM_ACTION_TOGGLE +#define RS_PWM_EVENT_TIMER0_ZERO PWM_INTR_TIMER0_ZERO_MASK +#define RS_PWM_EVENT_TIMER1_ZERO PWM_INTR_TIMER1_ZERO_MASK +#define RS_PWM_EVENT_TIMER0_PERIOD PWM_INTR_TIMER0_PERIOD_MASK +#define RS_PWM_EVENT_TIMER1_PERIOD PWM_INTR_TIMER1_PERIOD_MASK +#define RS_PWM_EVENT_FADE0_DONE PWM_INTR_FADE0_DONE_MASK +#define RS_PWM_EVENT_FADE1_DONE PWM_INTR_FADE1_DONE_MASK +#define RS_PWM_EVENT_FADE2_DONE PWM_INTR_FADE2_DONE_MASK +#define RS_PWM_EVENT_FADE3_DONE PWM_INTR_FADE3_DONE_MASK +#define RS_PWM_EVENT_FAULT PWM_INTR_FAULT_MASK +#define RS_PWM_EVENT_CAPTURE0 PWM_INTR_CAPTURE0_MASK +#define RS_PWM_EVENT_CAPTURE1 PWM_INTR_CAPTURE1_MASK +#define RS_PWM_EVENT_CAPTURE0_OVERFLOW PWM_INTR_CAPTURE0_OVERFLOW_MASK +#define RS_PWM_EVENT_CAPTURE1_OVERFLOW PWM_INTR_CAPTURE1_OVERFLOW_MASK +#define RS_PWM_EVENT_ALL PWM_INTR_ALL_MASK + +rs_status_t rs_pwm_probe(void); +rs_status_t rs_pwm_timer_configure(uint8_t timer, const rs_pwm_timer_config_t *config); +rs_status_t rs_pwm_channel_configure(uint8_t channel, const rs_pwm_channel_config_t *config); +rs_status_t rs_pwm_operator_configure(uint8_t operator_id, const rs_pwm_operator_config_t *config); +rs_status_t rs_pwm_fault_configure(const rs_pwm_fault_config_t *config); +rs_status_t rs_pwm_capture_configure(const rs_pwm_capture_config_t *config); +rs_status_t rs_pwm_enable(bool debug_freeze); +rs_status_t rs_pwm_disable(void); +rs_status_t rs_pwm_apply_update(rs_timeout_t timeout); +rs_status_t rs_pwm_software_sync(void); +rs_status_t rs_pwm_set_duty(uint8_t channel, uint32_t duty, rs_timeout_t timeout); +rs_status_t rs_pwm_fade_configure(uint8_t channel, const rs_pwm_fade_segment_t *segment); +rs_status_t rs_pwm_fade_start(uint8_t channel); +rs_status_t rs_pwm_fade_pause(uint8_t channel); +rs_status_t rs_pwm_fade_resume(uint8_t channel); +rs_status_t rs_pwm_fade_stop(uint8_t channel); +rs_status_t rs_pwm_gamma_program(uint8_t channel, const rs_pwm_fade_segment_t *segments, + uint8_t count); +rs_status_t rs_pwm_gamma_start(uint8_t channel, uint8_t count); +rs_status_t rs_pwm_fault_clear(void); +rs_status_t rs_pwm_fault_test(void); +rs_status_t rs_pwm_capture_read(uint8_t channel, uint32_t *timestamp, rs_timeout_t timeout); +rs_status_t rs_pwm_interrupt_enable(uint32_t mask); +rs_status_t rs_pwm_interrupt_clear(uint32_t mask); +rs_status_t rs_pwm_interrupt_test(uint32_t mask); +rs_status_t rs_pwm_get_status(rs_pwm_snapshot_t *snapshot); +void rs_pwm_shell_test(int argc, char **argv); + #endif diff --git a/crt/src/hal/pwm.c b/crt/src/hal/pwm.c index 7d7303a4..a2f9242d 100644 --- a/crt/src/hal/pwm.c +++ b/crt/src/hal/pwm.c @@ -1,41 +1,211 @@ -#include -#include -#include #include -void ip_pwm_test(int argc, char **argv) { +#include +#include + +static rs_status_t rs_pwm_status(pwm_status_t status) { + rs_status_t result; + + switch (status) { + case PWM_STATUS_OK: + result = RS_OK; + break; + case PWM_STATUS_INVALID_ARGUMENT: + result = RS_EINVAL; + break; + case PWM_STATUS_TIMEOUT: + result = RS_ETIMEOUT; + break; + case PWM_STATUS_EMPTY: + result = RS_ENOSPC; + break; + case PWM_STATUS_LOCKED: + result = RS_ENOTSUP; + break; + case PWM_STATUS_INCOMPATIBLE: + result = RS_EFORMAT; + break; + case PWM_STATUS_BUSY: + default: + result = RS_EIO; + break; + } + return result; +} + +rs_status_t rs_pwm_probe(void) { + return rs_pwm_status(pwm_probe((uintptr_t)RS_SOC_APB_PWM_BASE)); +} + +rs_status_t rs_pwm_timer_configure(uint8_t timer, const rs_pwm_timer_config_t *config) { + return rs_pwm_status(pwm_timer_configure((uintptr_t)RS_SOC_APB_PWM_BASE, timer, config)); +} + +rs_status_t rs_pwm_channel_configure(uint8_t channel, const rs_pwm_channel_config_t *config) { + return rs_pwm_status(pwm_channel_configure((uintptr_t)RS_SOC_APB_PWM_BASE, channel, config)); +} + +rs_status_t rs_pwm_operator_configure(uint8_t operator_id, const rs_pwm_operator_config_t *config) { + return rs_pwm_status( + pwm_operator_configure((uintptr_t)RS_SOC_APB_PWM_BASE, operator_id, config)); +} + +rs_status_t rs_pwm_fault_configure(const rs_pwm_fault_config_t *config) { + return rs_pwm_status(pwm_fault_configure((uintptr_t)RS_SOC_APB_PWM_BASE, config)); +} + +rs_status_t rs_pwm_capture_configure(const rs_pwm_capture_config_t *config) { + return rs_pwm_status(pwm_capture_configure((uintptr_t)RS_SOC_APB_PWM_BASE, config)); +} + +rs_status_t rs_pwm_enable(bool debug_freeze) { + return rs_pwm_status(pwm_enable((uintptr_t)RS_SOC_APB_PWM_BASE, debug_freeze)); +} + +rs_status_t rs_pwm_disable(void) { + return rs_pwm_status(pwm_disable((uintptr_t)RS_SOC_APB_PWM_BASE)); +} + +rs_status_t rs_pwm_apply_update(rs_timeout_t timeout) { + return rs_pwm_status(pwm_apply_update((uintptr_t)RS_SOC_APB_PWM_BASE, timeout)); +} + +rs_status_t rs_pwm_software_sync(void) { + return rs_pwm_status(pwm_software_sync((uintptr_t)RS_SOC_APB_PWM_BASE)); +} + +rs_status_t rs_pwm_set_duty(uint8_t channel, uint32_t duty, rs_timeout_t timeout) { + return rs_pwm_status(pwm_set_duty((uintptr_t)RS_SOC_APB_PWM_BASE, channel, duty, timeout)); +} + +rs_status_t rs_pwm_fade_configure(uint8_t channel, const rs_pwm_fade_segment_t *segment) { + return rs_pwm_status(pwm_fade_configure((uintptr_t)RS_SOC_APB_PWM_BASE, channel, segment)); +} + +rs_status_t rs_pwm_fade_start(uint8_t channel) { + return rs_pwm_status(pwm_fade_start((uintptr_t)RS_SOC_APB_PWM_BASE, channel)); +} + +rs_status_t rs_pwm_fade_pause(uint8_t channel) { + return rs_pwm_status(pwm_fade_pause((uintptr_t)RS_SOC_APB_PWM_BASE, channel)); +} + +rs_status_t rs_pwm_fade_resume(uint8_t channel) { + return rs_pwm_status(pwm_fade_resume((uintptr_t)RS_SOC_APB_PWM_BASE, channel)); +} + +rs_status_t rs_pwm_fade_stop(uint8_t channel) { + return rs_pwm_status(pwm_fade_stop((uintptr_t)RS_SOC_APB_PWM_BASE, channel)); +} + +rs_status_t rs_pwm_gamma_program(uint8_t channel, const rs_pwm_fade_segment_t *segments, + uint8_t count) { + return rs_pwm_status( + pwm_gamma_program((uintptr_t)RS_SOC_APB_PWM_BASE, channel, segments, count)); +} + +rs_status_t rs_pwm_gamma_start(uint8_t channel, uint8_t count) { + return rs_pwm_status(pwm_gamma_start((uintptr_t)RS_SOC_APB_PWM_BASE, channel, count)); +} + +rs_status_t rs_pwm_fault_clear(void) { + return rs_pwm_status(pwm_fault_clear((uintptr_t)RS_SOC_APB_PWM_BASE)); +} + +rs_status_t rs_pwm_fault_test(void) { + return rs_pwm_status(pwm_fault_test((uintptr_t)RS_SOC_APB_PWM_BASE)); +} + +rs_status_t rs_pwm_capture_read(uint8_t channel, uint32_t *timestamp, rs_timeout_t timeout) { + return rs_pwm_status( + pwm_capture_read((uintptr_t)RS_SOC_APB_PWM_BASE, channel, timestamp, timeout)); +} + +rs_status_t rs_pwm_interrupt_enable(uint32_t mask) { + return rs_pwm_status(pwm_interrupt_enable((uintptr_t)RS_SOC_APB_PWM_BASE, mask)); +} + +rs_status_t rs_pwm_interrupt_clear(uint32_t mask) { + return rs_pwm_status(pwm_interrupt_clear((uintptr_t)RS_SOC_APB_PWM_BASE, mask)); +} + +rs_status_t rs_pwm_interrupt_test(uint32_t mask) { + return rs_pwm_status(pwm_interrupt_test((uintptr_t)RS_SOC_APB_PWM_BASE, mask)); +} + +rs_status_t rs_pwm_get_status(rs_pwm_snapshot_t *snapshot) { + return rs_pwm_status(pwm_get_status((uintptr_t)RS_SOC_APB_PWM_BASE, snapshot)); +} + +void rs_pwm_shell_test(int argc, char **argv) { + static const rs_pwm_timer_config_t timer = { + .divider_q16_8 = UINT32_C(0x00000100), + .period = UINT32_C(72000), + .phase = 0U, + .count_mode = RS_PWM_COUNT_MODE_UP, + .load_mode = RS_PWM_LOAD_ON_ZERO, + .sync_enable = true, + .enable = true, + }; + static const rs_pwm_channel_config_t channel = { + .phase = 0U, + .duty = UINT32_C(36000), + .action = UINT16_C(0x0042), + .timer = 0U, + .invert = false, + .enable = true, + }; + static const rs_pwm_operator_config_t operator_config = { + .rising_deadtime = 0U, + .falling_deadtime = 0U, + .carrier_period = 0U, + .carrier_duty = 0U, + .carrier_invert = false, + .complementary = false, + .carrier_enable = false, + }; + static const rs_pwm_fault_config_t fault = { + .filter_cycles = 2U, + .safe_state = {RS_PWM_SAFE_LOW, RS_PWM_SAFE_LOW, RS_PWM_SAFE_LOW, RS_PWM_SAFE_LOW}, + .active_high = true, + .one_shot = false, + .enable = true, + .lock = false, + }; + rs_pwm_snapshot_t snapshot; + rs_status_t status; + (void)argc; (void)argv; - printf("[APB IP] pwm test\n"); - - reg_pwm_ctrl = (uint32_t)0; - reg_pwm_pscr = (uint32_t)(CPU_FREQ - 1); // 'CPU_FREQ' MHz for 1MHz - reg_pwm_cmp = (uint32_t)(1000 - 1); // 1KHz - printf("reg_pwm_ctrl: %d reg_pwm_pscr: %d reg_pwm_cmp: %d\n", reg_pwm_ctrl, reg_pwm_pscr, - reg_pwm_cmp); - for (int i = 0; i < 6; i++) { - for (int j = 10; j <= 990; ++j) { - reg_pwm_ctrl = (uint32_t)4; - reg_pwm_cr0 = j; - reg_pwm_ctrl = (uint32_t)3; - reg_pwm_pscr = 49; - if (rs_timer_delay_ms(RS_TIMER_0, 1U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) { - printf("timer delay failed\n"); - return; - } - } - - for (int j = 990; j >= 10; --j) { - reg_pwm_ctrl = (uint32_t)4; - reg_pwm_cr0 = j; - reg_pwm_ctrl = (uint32_t)3; - reg_pwm_pscr = 49; - if (rs_timer_delay_ms(RS_TIMER_0, 1U, RS_TIMER_DELAY_TIMEOUT) != RS_OK) { - printf("timer delay failed\n"); - return; - } - } - printf("[PWM]: %d/6\n", i + 1); + status = rs_pwm_probe(); + if (status == RS_OK) { + status = rs_pwm_disable(); } + if (status == RS_OK) { + status = rs_pwm_fault_configure(&fault); + } + if (status == RS_OK) { + status = rs_pwm_operator_configure(0U, &operator_config); + } + if (status == RS_OK) { + status = rs_pwm_timer_configure(0U, &timer); + } + if (status == RS_OK) { + status = rs_pwm_channel_configure(0U, &channel); + } + if (status == RS_OK) { + status = rs_pwm_apply_update(RS_TIMEOUT_DEFAULT); + } + if (status == RS_OK) { + status = rs_pwm_enable(true); + } + if (status == RS_OK) { + status = rs_pwm_get_status(&snapshot); + } + if (status != RS_OK) { + printf("[PWM] V2 test failed: %d\n", status); + return; + } + printf("[APB IP] PWM V2 status=%x outputs=%x\n", snapshot.status, snapshot.output_status); } diff --git a/crt/src/service/booter.c b/crt/src/service/booter.c index 2db9f49f..3406c8f6 100644 --- a/crt/src/service/booter.c +++ b/crt/src/service/booter.c @@ -121,7 +121,8 @@ void rs_app_info(void) { printf(" 1 x RNG @%p\n", (void *)(uintptr_t)RS_SOC_APB_RNG_BASE); printf(" 1 x UART1(ADV) @%p\n", (void *)®_uart1_lcr); - printf(" 1 x PWM(4CHNL) @%p\n", (void *)®_pwm_ctrl); + printf(" 1 x PWM V2(4CH) @%p\n", + (void *)(uintptr_t)RS_SOC_APB_PWM_BASE); printf(" 1 x PS2 @%p\n", (void *)(uintptr_t)RS_SOC_APB_PS2_BASE); printf(" 1 x RTC @%p\n", diff --git a/docs/README.md b/docs/README.md index 0424692d..3ca4b97f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -38,6 +38,9 @@ the root README and subsystem guides. defines Epoch time, alarms, periodic wake, calibration, CDC, and software. - The managed [CRC V2 datasheet](../rtl/managed/clusterip/crc/doc/datasheet.md) defines the programmable streaming CRC engine, APB ABI, errors, and software. +- The managed [PWM V2 datasheet](../rtl/managed/clusterip/pwm/doc/datasheet.md) + defines the dual-timer/four-channel LED and motor PWM controller, fault, + synchronization, dead-time, carrier, fade, and capture contracts. - [soc-integration-wiring.md](soc-integration-wiring.md) defines the generated pin-map workflow and SoC integration boundary. - [mini-soc-block-diagram.svg](mini-soc-block-diagram.svg) is the Mini SoC diff --git a/docs/mini-soc-block-diagram.dot b/docs/mini-soc-block-diagram.dot index 761dde2a..c6aa2366 100644 --- a/docs/mini-soc-block-diagram.dot +++ b/docs/mini-soc-block-diagram.dot @@ -43,7 +43,7 @@ digraph mini_soc_block_diagram { ]; ext_io [ fillcolor="#F3F4F6", - label="External I/O and memory\nGPIO, UART0, PS/2, XPI Flash, SDRAM, PSRAM\nSD card, I2C, I2S, DVP and WS2812" + label="External I/O and memory\nGPIO, UART0, PS/2, XPI Flash, SDRAM, PSRAM\nSD card, I2C, I2S, DVP, WS2812 and PWM V2" ]; ext_jtag [ fillcolor="#F3F4F6", @@ -152,7 +152,11 @@ digraph mini_soc_block_diagram { ]; apb_targets [ fillcolor="#E6F4EA", - label="APB target wrapper\nUART1, PWM, advanced timer\nand user IP" + label="APB target wrapper\nUART1, advanced timer\nand user IP" + ]; + pwm [ + fillcolor="#E6F4EA", + label="PWM V2\n2 timers, 4 action channels, 2 operators\nfades, dead time, carrier, fault and capture, IRQ11" ]; wdg [ fillcolor="#FDE68A", @@ -193,7 +197,7 @@ digraph mini_soc_block_diagram { { rank=same; user_core; dma; } { rank=same; fault; fabric; sram; } { rank=same; ribp_adapter; apb_adapter; } - { rank=same; sysctrl; clint; ribp_targets; uart0; i2c_controllers; gpio_controller; timers; ws2812; archinfo; rng; ps2; rtc; wdg; crc; apb_targets; } + { rank=same; sysctrl; clint; ribp_targets; uart0; i2c_controllers; gpio_controller; timers; ws2812; archinfo; rng; ps2; rtc; wdg; crc; pwm; apb_targets; } { rank=same; gpio_bridge; irq; } ext_clock -> rcu [label="clock / reset"]; @@ -229,6 +233,7 @@ digraph mini_soc_block_diagram { apb_adapter -> rtc [label="APB"]; apb_adapter -> wdg [label="APB"]; apb_adapter -> crc [label="APB"]; + apb_adapter -> pwm [label="APB"]; apb_adapter -> apb_targets [label="APB"]; ribp_targets -> gpio_controller [label="alternate functions"]; @@ -247,6 +252,8 @@ digraph mini_soc_block_diagram { rng -> irq [label="IRQ16"]; ps2 -> gpio_controller [label="GPIO0/1 ALT1\nopen drain"]; ps2 -> irq [label="IRQ12"]; + pwm -> gpio_controller [dir=both, label="GPIO3-6 output\nGPIO2 sync, GPIO9 fault\nGPIO30/31 capture"]; + pwm -> irq [label="IRQ11"]; rcu -> rtc [label="18.432 MHz audio clock", style=dashed]; rtc -> irq [label="IRQ13"]; rtc -> sysctrl [label="wake live / sticky", style=dashed]; diff --git a/docs/mini-soc-block-diagram.svg b/docs/mini-soc-block-diagram.svg index e01dd475..885aebc4 100644 --- a/docs/mini-soc-block-diagram.svg +++ b/docs/mini-soc-block-diagram.svg @@ -4,104 +4,104 @@ - - + + mini_soc_block_diagram -retroSoC Mini SoC Architecture +retroSoC Mini SoC Architecture cluster_asic - -retrosoc_asic + +retrosoc_asic cluster_soc - -retrosoc + +retrosoc ext_clock - -External clocks and reset -ext_clk, aud_clk, reset + +External clocks and reset +ext_clk, aud_clk, reset rcu - -RCU -clock buffering and reset synchronization -PLL CDC and fixed 1 MHz timebase + +RCU +clock buffering and reset synchronization +PLL CDC and fixed 1 MHz timebase ext_clock->rcu - - -clock / reset + + +clock / reset ext_io - -External I/O and memory -GPIO, UART0, PS/2, XPI Flash, SDRAM, PSRAM -SD card, I2C, I2S, DVP and WS2812 + +External I/O and memory +GPIO, UART0, PS/2, XPI Flash, SDRAM, PSRAM +SD card, I2C, I2S, DVP, WS2812 and PWM V2 ext_jtag - -Management JTAG -TCK, TMS, TDI, TRST_n, TDO + +Management JTAG +TCK, TMS, TDI, TRST_n, TDO jtag_dtm - -Hazard3 JTAG DTM -10 MHz asynchronous TCK domain + +Hazard3 JTAG DTM +10 MHz asynchronous TCK domain ext_jtag->jtag_dtm - - -JTAG pads + + +JTAG pads fabric - -RIB fabric -3-master round-robin arbitration -INCR1 / INCR4, access policy, fault reporting + +RIB fabric +3-master round-robin arbitration +INCR1 / INCR4, access policy, fault reporting rcu->fabric - - -system clock / reset + + +system clock / reset clint - -CLINT -standard 64 KiB register map -mtime, mtimecmp and MSIP + +CLINT +standard 64 KiB register map +mtime, mtimecmp and MSIP rcu->clint - - -1 MHz tick + + +1 MHz tick - + wdg WDG V2 @@ -109,564 +109,596 @@ early IRQ14, retained cause/count - + rcu->wdg - - -independent 18.432 MHz clock + + +independent 18.432 MHz clock - + rtc - -RTC V2 -64-bit Epoch + 1/256-second time -dual alarm, periodic wake, calibration, IRQ13 + +RTC V2 +64-bit Epoch + 1/256-second time +dual alarm, periodic wake, calibration, IRQ13 - + rcu->rtc - - -18.432 MHz audio clock + + +18.432 MHz audio clock mgmt_core - -Management core -Fixed Hazard3, branch predictor -JTAG Debug Module always present + +Management core +Fixed Hazard3, branch predictor +JTAG Debug Module always present mgmt_adapter - -RIBP2RIB + +RIBP2RIB mgmt_core->mgmt_adapter - - -RIBP + + +RIBP debug_module - -Hazard3 Debug Module -abstract commands, no SBA -management-hart-only reset + +Hazard3 Debug Module +abstract commands, no SBA +management-hart-only reset jtag_dtm->debug_module - - -DMI, asynchronous CDC + + +DMI, asynchronous CDC debug_module->mgmt_core - - -halt, resume, abstract commands + + +halt, resume, abstract commands debug_module->mgmt_adapter - - -reset after bridge idle + + +reset after bridge idle timers - -General timers 0/1 -32-bit counter, 16-bit prescaler -periodic / one-shot, compare, debug freeze + +General timers 0/1 +32-bit counter, 16-bit prescaler +periodic / one-shot, compare, debug freeze debug_module->timers - - -halted + + +halted mgmt_adapter->fabric - - -RIB + + +RIB user_core - -Selected user core -C0-C5, one active -PicoRV32 at C5 + +Selected user core +C0-C5, one active +PicoRV32 at C5 user_core->fabric - - -RIB + + +RIB dma - -DMA -RIB master and RIBP target + +DMA +RIB master and RIBP target dma->fabric - - -RIB + + +RIB uart0 - -UART0 V2 -64-byte TX/RX FIFOs, fractional baud -framing/errors, IRQ2, DMA-paced + +UART0 V2 +64-byte TX/RX FIFOs, fractional baud +framing/errors, IRQ2, DMA-paced - + dma->uart0 - - -TX/RX data + + +TX/RX data i2c_controllers - -I2C0 / I2C1 V2 -16-entry command/RX FIFOs, Sm/Fm/Fm+ -7/10-bit, IRQ7/19, DMA-paced + +I2C0 / I2C1 V2 +16-entry command/RX FIFOs, Sm/Fm/Fm+ +7/10-bit, IRQ7/19, DMA-paced - + dma->i2c_controllers - - -DATA_CMD / RXDATA + + +DATA_CMD / RXDATA ws2812 - -WS2812 TX -24-bit MSB-first serializer -16-word FIFO, IRQ17, DMA-fed + +WS2812 TX +24-bit MSB-first serializer +16-word FIFO, IRQ17, DMA-fed - + dma->ws2812 - - -TXDATA writes + + +TXDATA writes fault - -Error slave -access and protocol faults + +Error slave +access and protocol faults fabric->fault - - - -invalid / denied + + + +invalid / denied sram - -On-chip SRAM -optional RIB2RAM path + +On-chip SRAM +optional RIB2RAM path fabric->sram - - -RIB + + +RIB ribp_adapter - -RIB2RIBP + +RIB2RIBP fabric->ribp_adapter - - -RIB + + +RIB apb_adapter - -RIB2APB -direct APB bridge + +RIB2APB +direct APB bridge fabric->apb_adapter - - -RIB + + +RIB sysctrl - -SYSCTRL -PLL, user-core select/reset/bus enable -fault and performance control + +SYSCTRL +PLL, user-core select/reset/bus enable +fault and performance control ribp_adapter->sysctrl - - -RIBP + + +RIBP ribp_adapter->clint - - -RIBP + + +RIBP ribp_targets - -RIBP target wrapper -XPI/Flash, SDRAM, PSRAM, SPI-SD and DVP -I2S + +RIBP target wrapper +XPI/Flash, SDRAM, PSRAM, SPI-SD and DVP +I2S ribp_adapter->ribp_targets - - -RIBP + + +RIBP ribp_adapter->uart0 - - -RIBP + + +RIBP ribp_adapter->i2c_controllers - - -RIBP + + +RIBP gpio_controller - -GPIO V2 -user + management RIBP windows -atomic I/O, filter, locks, IRQ18 + +GPIO V2 +user + management RIBP windows +atomic I/O, filter, locks, IRQ18 ribp_adapter->gpio_controller - - -RIBP -user/admin + + +RIBP +user/admin ribp_adapter->timers - - -RIBP + + +RIBP ribp_adapter->ws2812 - - -RIBP + + +RIBP apb_targets - -APB target wrapper -UART1, PWM, advanced timer -and user IP + +APB target wrapper +UART1, advanced timer +and user IP - + apb_adapter->apb_targets - - -APB + + +APB + + + +pwm + +PWM V2 +2 timers, 4 action channels, 2 operators +fades, dead time, carrier, fault and capture, IRQ11 + + + +apb_adapter->pwm + + +APB apb_adapter->wdg - + -APB +APB - + crc - -CRC V2 -programmable 7/8/16/32-bit streaming CRC -byte, halfword and word APB feed + +CRC V2 +programmable 7/8/16/32-bit streaming CRC +byte, halfword and word APB feed apb_adapter->crc - - -APB + + +APB apb_adapter->rtc - - -APB + + +APB - + archinfo - -ARCHINFO V2 -read-only build, topology and technology identity -lifecycle-gated 128-bit device ID + +ARCHINFO V2 +read-only build, topology and technology identity +lifecycle-gated 128-bit device ID apb_adapter->archinfo - - -APB + + +APB - + rng - -RNG V2 entropy controller -8-word FIFO, fail-closed monitoring, IRQ16 -management-only, deterministic source unqualified + +RNG V2 entropy controller +8-word FIFO, fail-closed monitoring, IRQ16 +management-only, deterministic source unqualified apb_adapter->rng - - -APB + + +APB - + ps2 - -PS/2 host V2 -bidirectional open-drain transport -16-byte RX/TX FIFOs, errors, IRQ12 + +PS/2 host V2 +bidirectional open-drain transport +16-byte RX/TX FIFOs, errors, IRQ12 apb_adapter->ps2 - - -APB + + +APB - + irq - -Interrupt aggregation -RIBP and APB target IRQs to management core + +Interrupt aggregation +RIBP and APB target IRQs to management core - + clint->irq - - -machine IRQ0 / IRQ1 + + +machine IRQ0 / IRQ1 - + ribp_targets->ext_io - - - -device interfaces + + + +device interfaces - + ribp_targets->gpio_controller - - -alternate functions + + +alternate functions - + uart0->ext_io - - - -UART pads + + + +UART pads - + uart0->irq - - -IRQ2 + + +IRQ2 - + i2c_controllers->gpio_controller - - -GPIO3/4 ALT1 -GPIO7/8 ALT0 + + +GPIO3/4 ALT1 +GPIO7/8 ALT0 - + i2c_controllers->irq - - -IRQ7 / IRQ19 + + +IRQ7 / IRQ19 - + gpio_bridge - -GPIO pad bridge -PDK capability-adapted controls + +GPIO pad bridge +PDK capability-adapted controls - + gpio_controller->gpio_bridge - - -pad control + + +pad control - + gpio_controller->irq - - -IRQ18 + + +IRQ18 - + timers->irq - - -IRQ3 / IRQ4 + + +IRQ3 / IRQ4 - + ws2812->gpio_bridge - - -GPIO2 ALT1 + + +GPIO2 ALT1 - + ws2812->irq - - -IRQ17 + + +IRQ17 - + apb_targets->gpio_controller - - -user_gpio + + +user_gpio + + + +pwm->gpio_controller + + + +GPIO3-6 output +GPIO2 sync, GPIO9 fault +GPIO30/31 capture + + + +pwm->irq + + +IRQ11 - + wdg->rcu - - -system reset request + + +system reset request - + wdg->irq - - -early warning IRQ14 + + +early warning IRQ14 - + rtc->sysctrl - - -wake live / sticky + + +wake live / sticky - + rtc->irq - - -IRQ13 + + +IRQ13 - + rng->irq - - -IRQ16 + + +IRQ16 - + ps2->gpio_controller - - -GPIO0/1 ALT1 -open drain + + +GPIO0/1 ALT1 +open drain - + ps2->irq - - -IRQ12 + + +IRQ12 - + gpio_bridge->ext_io - - - -pad control + + + +pad control diff --git a/docs/soc-integration-wiring.md b/docs/soc-integration-wiring.md index 380ca48e..ac309aa5 100644 --- a/docs/soc-integration-wiring.md +++ b/docs/soc-integration-wiring.md @@ -36,6 +36,23 @@ Board-level pull-ups are therefore required. I2C0 uses management-core IRQ7 and generic-DMA modes 7/8; I2C1 uses IRQ19 and DMA modes 9/10. See [i2c.md](ip/i2c.md) for the register and transfer contract. +## PWM V2 alternate functions + +The APB PWM V2 controller drives GPIO3 through GPIO6 on ALT0. Both output data +and output enable come from the PWM interface, so a fault-configured high-Z +state reaches the GPIO pad bridge instead of being overridden by a constant +enable. PWM uses management-core IRQ11. + +GPIO2 ALT0 feeds the external synchronization input while retaining its +existing advanced-timer capture binding. GPIO9 ALT0 feeds the asynchronous +fault input. GPIO30 and GPIO31 ALT1 feed capture channels 0 and 1. Software must +select the corresponding alternate function and input mode before relying on +these paths. GPIO9 fault shutdown includes an immediate asynchronous safe-state +path plus synchronized filtering/status inside the IP; technology sign-off must +verify external pulse width and pad-disable latency. The complete programming, +safety, and verification contract is in the managed +[PWM V2 datasheet](../rtl/managed/clusterip/pwm/doc/datasheet.md). + ## WS2812 output The single-channel WS2812 transmitter occupies RIBP address `0x10008000` and diff --git a/rtl/mini/filelist/clusterip.fl b/rtl/mini/filelist/clusterip.fl index 25373471..39123875 100644 --- a/rtl/mini/filelist/clusterip.fl +++ b/rtl/mini/filelist/clusterip.fl @@ -9,6 +9,15 @@ /clusterip/uart/rtl/uart_rx.sv /clusterip/uart/rtl/uart_irq.sv /clusterip/uart/rtl/apb4_uart.sv +/clusterip/pwm/rtl/pwm_pkg.sv +/clusterip/pwm/rtl/pwm_tickgen.sv +/clusterip/pwm/rtl/pwm_timer.sv +/clusterip/pwm/rtl/pwm_channel.sv +/clusterip/pwm/rtl/pwm_deadtime.sv +/clusterip/pwm/rtl/pwm_carrier.sv +/clusterip/pwm/rtl/pwm_capture.sv +/clusterip/pwm/rtl/pwm_core.sv +/clusterip/pwm/rtl/pwm_reg.sv /clusterip/pwm/rtl/pwm_if.sv /clusterip/pwm/rtl/apb4_pwm.sv /clusterip/ps2/rtl/ps2_filter.sv diff --git a/rtl/mini/integration/soc_topology.json b/rtl/mini/integration/soc_topology.json index a7a9425e..7d245248 100644 --- a/rtl/mini/integration/soc_topology.json +++ b/rtl/mini/integration/soc_topology.json @@ -73,14 +73,14 @@ "gpio_alt_functions": [ {"pin": 0, "alt0": {"inputs": ["u_uart1_if.rx_i"], "do": "1'b0", "oe": "1'b0"}, "alt1": {"inputs": ["u_ps2_if.ps2_clk_i"], "do": "u_ps2_if.ps2_clk_o", "oe": "u_ps2_if.ps2_clk_oe_o"}}, {"pin": 1, "alt0": {"inputs": [], "do": "u_uart1_if.tx_o", "oe": "1'b1"}, "alt1": {"inputs": ["u_ps2_if.ps2_dat_i"], "do": "u_ps2_if.ps2_dat_o", "oe": "u_ps2_if.ps2_dat_oe_o"}}, - {"pin": 2, "alt0": {"inputs": ["s_tmr_capch"], "do": "1'b0", "oe": "1'b0"}, "alt1": {"inputs": [], "do": "u_ws2812_if.dat_o", "oe": "1'b1"}}, - {"pin": 3, "alt0": {"inputs": [], "do": "u_pwm_if.do_o[0]", "oe": "1'b1"}, "alt1": {"inputs": ["u_i2c1_if.scl_i"], "do": "u_i2c1_if.scl_o", "oe": "u_i2c1_if.scl_oe_o"}}, - {"pin": 4, "alt0": {"inputs": [], "do": "u_pwm_if.do_o[1]", "oe": "1'b1"}, "alt1": {"inputs": ["u_i2c1_if.sda_i"], "do": "u_i2c1_if.sda_o", "oe": "u_i2c1_if.sda_oe_o"}}, - {"pin": 5, "alt0": {"inputs": [], "do": "u_pwm_if.do_o[2]", "oe": "1'b1"}, "alt1": {"inputs": [], "do": "clkdiv4_i", "oe": "1'b1"}}, - {"pin": 6, "alt0": {"inputs": [], "do": "u_pwm_if.do_o[3]", "oe": "1'b1"}, "alt1": {"inputs": [], "do": "u_spisd_if.sck_o", "oe": "1'b1"}}, + {"pin": 2, "alt0": {"inputs": ["s_tmr_capch", "u_pwm_if.sync_i"], "do": "1'b0", "oe": "1'b0"}, "alt1": {"inputs": [], "do": "u_ws2812_if.dat_o", "oe": "1'b1"}}, + {"pin": 3, "alt0": {"inputs": [], "do": "u_pwm_if.pwm_o[0]", "oe": "u_pwm_if.oe_o[0]"}, "alt1": {"inputs": ["u_i2c1_if.scl_i"], "do": "u_i2c1_if.scl_o", "oe": "u_i2c1_if.scl_oe_o"}}, + {"pin": 4, "alt0": {"inputs": [], "do": "u_pwm_if.pwm_o[1]", "oe": "u_pwm_if.oe_o[1]"}, "alt1": {"inputs": ["u_i2c1_if.sda_i"], "do": "u_i2c1_if.sda_o", "oe": "u_i2c1_if.sda_oe_o"}}, + {"pin": 5, "alt0": {"inputs": [], "do": "u_pwm_if.pwm_o[2]", "oe": "u_pwm_if.oe_o[2]"}, "alt1": {"inputs": [], "do": "clkdiv4_i", "oe": "1'b1"}}, + {"pin": 6, "alt0": {"inputs": [], "do": "u_pwm_if.pwm_o[3]", "oe": "u_pwm_if.oe_o[3]"}, "alt1": {"inputs": [], "do": "u_spisd_if.sck_o", "oe": "1'b1"}}, {"pin": 7, "alt0": {"inputs": ["u_i2c0_if.scl_i"], "do": "u_i2c0_if.scl_o", "oe": "u_i2c0_if.scl_oe_o"}, "alt1": {"inputs": [], "do": "u_spisd_if.nss_o", "oe": "1'b1"}}, {"pin": 8, "alt0": {"inputs": ["u_i2c0_if.sda_i"], "do": "u_i2c0_if.sda_o", "oe": "u_i2c0_if.sda_oe_o"}, "alt1": {"inputs": [], "do": "u_spisd_if.mosi_o", "oe": "1'b1"}}, - {"pin": 9, "alt0": {"inputs": [], "do": "1'b0", "oe": "1'b0"}, "alt1": {"inputs": ["u_spisd_if.miso_i"], "do": "1'b0", "oe": "1'b0"}}, + {"pin": 9, "alt0": {"inputs": ["u_pwm_if.fault_i"], "do": "1'b0", "oe": "1'b0"}, "alt1": {"inputs": ["u_spisd_if.miso_i"], "do": "1'b0", "oe": "1'b0"}}, {"pin": 10, "alt0": {"inputs": [], "do": "u_i2s_if.mclk_o", "oe": "1'b1"}, "alt1": {"inputs": ["u_dvp_if.pclk_i"], "do": "1'b0", "oe": "1'b0"}}, {"pin": 11, "alt0": {"inputs": [], "do": "u_i2s_if.sclk_o", "oe": "1'b1"}, "alt1": {"inputs": ["u_dvp_if.href_i"], "do": "1'b0", "oe": "1'b0"}}, {"pin": 12, "alt0": {"inputs": [], "do": "u_i2s_if.lrck_o", "oe": "1'b1"}, "alt1": {"inputs": ["u_dvp_if.vsync_i"], "do": "1'b0", "oe": "1'b0"}}, @@ -101,7 +101,7 @@ {"pin": 27, "alt0": {"inputs": ["u_opipsram_if.io_di_i[4]"], "do": "u_opipsram_if.io_do_o[4]", "oe": "u_opipsram_if.io_oe_o[4]"}, "alt1": {"inputs": [], "do": "u_psram_if.nss_o[1]", "oe": "1'b1"}}, {"pin": 28, "alt0": {"inputs": ["u_opipsram_if.io_di_i[5]"], "do": "u_opipsram_if.io_do_o[5]", "oe": "u_opipsram_if.io_oe_o[5]"}, "alt1": {"inputs": [], "do": "u_psram_if.nss_o[2]", "oe": "1'b1"}}, {"pin": 29, "alt0": {"inputs": ["u_opipsram_if.io_di_i[6]"], "do": "u_opipsram_if.io_do_o[6]", "oe": "u_opipsram_if.io_oe_o[6]"}, "alt1": {"inputs": [], "do": "u_psram_if.nss_o[3]", "oe": "1'b1"}}, - {"pin": 30, "alt0": {"inputs": ["u_opipsram_if.io_di_i[7]"], "do": "u_opipsram_if.io_do_o[7]", "oe": "u_opipsram_if.io_oe_o[7]"}, "alt1": {"inputs": [], "do": "1'b0", "oe": "1'b0"}}, - {"pin": 31, "alt0": {"inputs": ["u_opipsram_if.dqs_di_i"], "do": "u_opipsram_if.dqs_do_o", "oe": "u_opipsram_if.dqs_oe_o"}, "alt1": {"inputs": [], "do": "1'b0", "oe": "1'b0"}} + {"pin": 30, "alt0": {"inputs": ["u_opipsram_if.io_di_i[7]"], "do": "u_opipsram_if.io_do_o[7]", "oe": "u_opipsram_if.io_oe_o[7]"}, "alt1": {"inputs": ["u_pwm_if.capture_i[0]"], "do": "1'b0", "oe": "1'b0"}}, + {"pin": 31, "alt0": {"inputs": ["u_opipsram_if.dqs_di_i"], "do": "u_opipsram_if.dqs_do_o", "oe": "u_opipsram_if.dqs_oe_o"}, "alt1": {"inputs": ["u_pwm_if.capture_i[1]"], "do": "1'b0", "oe": "1'b0"}} ] } diff --git a/rtl/mini/mk/software.mk b/rtl/mini/mk/software.mk index 06ae3921..10533255 100644 --- a/rtl/mini/mk/software.mk +++ b/rtl/mini/mk/software.mk @@ -67,6 +67,7 @@ CRT_SRCS := $(ROOT_PATH)/crt/arch/riscv/startup.S \ $(ROOT_PATH)/rtl/managed/clusterip/rng/sw/src/rng.c \ $(ROOT_PATH)/rtl/managed/clusterip/rtc/sw/src/rtc.c \ $(ROOT_PATH)/rtl/managed/clusterip/wdg/sw/src/wdg.c \ + $(ROOT_PATH)/rtl/managed/clusterip/pwm/sw/src/pwm.c \ $(ROOT_PATH)/rtl/managed/clusterip/ps2/sw/src/ps2.c \ $(ROOT_PATH)/rtl/managed/clusterip/ps2/sw/src/ps2_keyboard.c \ $(ROOT_PATH)/rtl/managed/clusterip/ps2/sw/src/ps2_mouse.c \ @@ -141,6 +142,7 @@ INC_PATH := -I$(SW_BUILD_DIR)/include \ -I$(ROOT_PATH)/rtl/managed/clusterip/rng/sw/include \ -I$(ROOT_PATH)/rtl/managed/clusterip/rtc/sw/include \ -I$(ROOT_PATH)/rtl/managed/clusterip/wdg/sw/include \ + -I$(ROOT_PATH)/rtl/managed/clusterip/pwm/sw/include \ -I$(ROOT_PATH)/rtl/managed/clusterip/ps2/sw/include \ -I$(ROOT_PATH)/crt/include \ $(addprefix -I,$(APP_INC_DIRS)) @@ -162,6 +164,8 @@ SW_HEADERS += $(shell find $(ROOT_PATH)/rtl/managed/clusterip/rtc/sw/incl -type f -name '*.h' 2>/dev/null) SW_HEADERS += $(shell find $(ROOT_PATH)/rtl/managed/clusterip/wdg/sw/include \ -type f -name '*.h' 2>/dev/null) +SW_HEADERS += $(shell find $(ROOT_PATH)/rtl/managed/clusterip/pwm/sw/include \ + -type f -name '*.h' 2>/dev/null) SW_HEADERS += $(shell find $(ROOT_PATH)/rtl/managed/clusterip/ps2/sw/include \ -type f -name '*.h' 2>/dev/null) diff --git a/rtl/mini/top/ip_apb_wrapper.sv b/rtl/mini/top/ip_apb_wrapper.sv index b21d792e..5ca935c5 100644 --- a/rtl/mini/top/ip_apb_wrapper.sv +++ b/rtl/mini/top/ip_apb_wrapper.sv @@ -156,9 +156,12 @@ module ip_apb_wrapper ( .uart(uart) ); - apb4_pwm u_apb4_pwm ( - .apb4(u_pwm_apb_if), - .pwm (pwm) + apb4_pwm #( + .PCLK_HZ(`SOC_EXT_CLK_HZ) + ) u_apb4_pwm ( + .debug_halted_i(debug_halted_i), + .apb4 (u_pwm_apb_if), + .pwm (pwm) ); apb4_ps2 #( diff --git a/rtl/mini/top/retrosoc_asic.sv b/rtl/mini/top/retrosoc_asic.sv index a85d220a..c33a6448 100644 --- a/rtl/mini/top/retrosoc_asic.sv +++ b/rtl/mini/top/retrosoc_asic.sv @@ -12,6 +12,45 @@ `include "soc_clock_config.svh" `include "user_extensions.svh" +// GPIO mux reference. The executable source of truth is +// rtl/mini/integration/soc_topology.json. ALT_ENABLE selects the alternate +// path, ALT_SELECT chooses ALT0/ALT1, and USER_SELECT gives the pin to User IP. +// +// GPIO ALT0 DIR ALT1 DIR +// ------ --------------------------- ------ ---------------------- ------ +// GPIO00 UART1_RX IN PS2_CLK BIDI +// GPIO01 UART1_TX OUT PS2_DATA BIDI +// GPIO02 TMR_CAPTURE + PWM_SYNC IN WS2812_DATA OUT +// GPIO03 PWM0 OUT I2C1_SCL BIDI +// GPIO04 PWM1 OUT I2C1_SDA BIDI +// GPIO05 PWM2 OUT CLKDIV4 OUT +// GPIO06 PWM3 OUT SPISD_SCK OUT +// GPIO07 I2C0_SCL BIDI SPISD_NSS OUT +// GPIO08 I2C0_SDA BIDI SPISD_MOSI OUT +// GPIO09 PWM_FAULT IN SPISD_MISO IN +// GPIO10 I2S_MCLK OUT DVP_PCLK IN +// GPIO11 I2S_SCLK OUT DVP_HREF IN +// GPIO12 I2S_LRCK OUT DVP_VSYNC IN +// GPIO13 I2S_DAC_DATA OUT DVP_DATA0 IN +// GPIO14 I2S_ADC_DATA IN DVP_DATA1 IN +// GPIO15 SDIO_SCK OUT DVP_DATA2 IN +// GPIO16 SDIO_CMD BIDI DVP_DATA3 IN +// GPIO17 SDIO_DATA0 BIDI DVP_DATA4 IN +// GPIO18 SDIO_DATA1 BIDI DVP_DATA5 IN +// GPIO19 SDIO_DATA2 BIDI DVP_DATA6 IN +// GPIO20 SDIO_DATA3 BIDI DVP_DATA7 IN +// GPIO21 OPI_PSRAM_SCK OUT QSPI_PSRAM_SCK OUT +// GPIO22 OPI_PSRAM_CE OUT QSPI_PSRAM_NSS0 OUT +// GPIO23 OPI_PSRAM_IO0 BIDI QSPI_PSRAM_IO0 BIDI +// GPIO24 OPI_PSRAM_IO1 BIDI QSPI_PSRAM_IO1 BIDI +// GPIO25 OPI_PSRAM_IO2 BIDI QSPI_PSRAM_IO2 BIDI +// GPIO26 OPI_PSRAM_IO3 BIDI QSPI_PSRAM_IO3 BIDI +// GPIO27 OPI_PSRAM_IO4 BIDI QSPI_PSRAM_NSS1 OUT +// GPIO28 OPI_PSRAM_IO5 BIDI QSPI_PSRAM_NSS2 OUT +// GPIO29 OPI_PSRAM_IO6 BIDI QSPI_PSRAM_NSS3 OUT +// GPIO30 OPI_PSRAM_IO7 BIDI PWM_CAPTURE0 IN +// GPIO31 OPI_PSRAM_DQS BIDI PWM_CAPTURE1 IN + module retrosoc_asic ( `include "retrosoc_asic_ports.svh" ); diff --git a/tests/test_soc_topology.py b/tests/test_soc_topology.py index 5629e0c6..aa195337 100644 --- a/tests/test_soc_topology.py +++ b/tests/test_soc_topology.py @@ -88,6 +88,12 @@ def test_topology_generates_complete_rib_apb_and_gpio_bindings(tmp_path: Path) - assert "assign u_gpio_if.alt1_do_i[1] = u_ps2_if.ps2_dat_o;" in gpio assert "assign u_gpio_if.alt1_oe_i[1] = u_ps2_if.ps2_dat_oe_o;" in gpio assert "assign u_gpio_if.alt1_do_i[2] = u_ws2812_if.dat_o;" in gpio + assert "assign u_pwm_if.sync_i = u_gpio_if.di_i[2];" in gpio + assert "assign u_gpio_if.alt0_do_i[3] = u_pwm_if.pwm_o[0];" in gpio + assert "assign u_gpio_if.alt0_oe_i[3] = u_pwm_if.oe_o[0];" in gpio + assert "assign u_pwm_if.fault_i = u_gpio_if.di_i[9];" in gpio + assert "assign u_pwm_if.capture_i[0] = u_gpio_if.di_i[30];" in gpio + assert "assign u_pwm_if.capture_i[1] = u_gpio_if.di_i[31];" in gpio assert "assign u_gpio_if.alt1_do_i[22] = u_psram_if.nss_o[0];" in gpio assert apb_interfaces.count("apb4_if u_") == 10 assert "apb4_pure_if u_archinfo_apb_pure_if ();" in apb_interfaces