Merge branch 'main' into linty_test

This commit is contained in:
stnolting 2024-10-06 21:09:59 +02:00 committed by GitHub
commit 450a1662b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
50 changed files with 413 additions and 344 deletions

View file

@ -4,11 +4,11 @@ on:
push:
paths:
- 'docs/**'
- '.github/workflows/**'
- '.github/workflows/Documentation.yml'
pull_request:
paths:
- 'docs/**'
- '.github/workflows/**'
- '.github/workflows/Documentation.yml'
workflow_dispatch:
jobs:

View file

@ -6,13 +6,13 @@ on:
- 'rtl/**'
- 'sw/**'
- 'sim/**'
- '.github/workflows/**'
- '.github/workflows/Processor.yml'
pull_request:
paths:
- 'rtl/**'
- 'sw/**'
- 'sim/**'
- '.github/workflows/**'
- '.github/workflows/Processor.yml'
workflow_dispatch:
jobs:

View file

@ -29,6 +29,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12
| Date | Version | Comment | Ticket |
|:----:|:-------:|:--------|:------:|
| 06.10.2024 | 1.10.5.4 | :warning: rework PWM module | [#1049](https://github.com/stnolting/neorv32/pull/1049) |
| 05.10.2024 | 1.10.5.3 | upgrade neoTRNG to version 3.2 | [#1048](https://github.com/stnolting/neorv32/pull/1048) |
| 03.10.2024 | 1.10.5.2 | :warning: remove `A` ISA extensions; replaced by new `Zalrsc` ISA extension | [#1047](https://github.com/stnolting/neorv32/pull/1047) |
| 02.10.2024 | 1.10.5.1 | :warning: rework CFU interface; reduce minimal latency of CFU instructions from 4 cycles to 3 cycles | [#1046](https://github.com/stnolting/neorv32/pull/1046) |
@ -57,7 +58,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12
| 05.09.2024 | 1.10.3.1 | minor CPU RTL cleanups and optimizations | [#1004](https://github.com/stnolting/neorv32/pull/1004) |
| 03.09.2024 | [**:rocket:1.10.3**](https://github.com/stnolting/neorv32/releases/tag/v1.10.3) | **New release** | |
| 30.08.2024 | 1.10.2.9 | :bug: fix PC reset bug (introduced in v1.10.2.8); minor RTL optimizations (size and critical path) | [#998](https://github.com/stnolting/neorv32/pull/998) |
| 25.08.2024 | 1.10.2.8 | :warning: remove user-mode HPM counters; add individual `mocuntern` bits (`CY` and `IR`) rework Vivado IP module; minor RTL cleanups and optimization | [#996](https://github.com/stnolting/neorv32/pull/996) |
| 25.08.2024 | 1.10.2.8 | :warning: remove user-mode HPM counters; add individual `mocunteren` bits (`CY` and `IR`) rework Vivado IP module; minor RTL cleanups and optimization | [#996](https://github.com/stnolting/neorv32/pull/996) |
| 16.08.2024 | 1.10.2.7 | minor CPU area and critical path optimizations; minor code cleanups | [#990](https://github.com/stnolting/neorv32/pull/990) |
| 09.08.2024 | 1.10.2.6 | :warning: re-organize RTL files; all core files are now located in `rtl/core`; remove `mem` sub-folder | [#985](https://github.com/stnolting/neorv32/pull/985) |
| 09.08.2024 | 1.10.2.5 | minor HDL edits | [#984](https://github.com/stnolting/neorv32/pull/984) |

View file

@ -98,8 +98,8 @@ setup according to your needs. Note that all of the following SoC modules are en
**CPU Core**
* [![RISCV-ARCHID](https://img.shields.io/badge/RISC--V%20Architecture%20ID-19-000000.svg?longCache=true&style=flat-square&logo=riscv&colorA=273274&colorB=fbb517)](https://github.com/riscv/riscv-isa-manual/blob/master/marchid.md)
* 32-bit little-endian RISC-V single-core, pipelined/multi-cycle modified Harvard architecture
* configurable ISA extensions:
* RISC-V 32-bit little-endian single-core pipelined/multi-cycle modified Harvard architecture
* configurable [instruction sets and extensions](https://stnolting.github.io/neorv32/#_instruction_sets_and_extensions):
\
`RV32`
[[`I`](https://stnolting.github.io/neorv32/#_i_isa_extension)/[`E`](https://stnolting.github.io/neorv32/#_e_isa_extension)]

View file

@ -425,38 +425,38 @@ This chapter gives a brief overview of all available ISA extensions.
|=======================
| Name | Description | <<_processor_top_entity_generics, Enabled by Generic>>
| <<_b_isa_extension,`B`>> | Bit manipulation instructions | _Implicitly_ enabled
| <<_c_isa_extension,`C`>> | Compressed (16-bit) instructions | `RISCV_ISA_C`
| <<_e_isa_extension,`E`>> | Embedded CPU extension (reduced register file size) | `RISCV_ISA_E`
| <<_c_isa_extension,`C`>> | Compressed (16-bit) instructions | <<_processor_top_entity_generics, `RISCV_ISA_C`>>
| <<_e_isa_extension,`E`>> | Embedded CPU extension (reduced register file size) | <<_processor_top_entity_generics, `RISCV_ISA_E`>>
| <<_i_isa_extension,`I`>> | Integer base ISA | Enabled if `RISCV_ISA_E` is **not** enabled
| <<_m_isa_extension,`M`>> | Integer multiplication and division instructions | `RISCV_ISA_M`
| <<_u_isa_extension,`U`>> | Less-privileged _user_ mode extension | `RISCV_ISA_U`
| <<_m_isa_extension,`M`>> | Integer multiplication and division instructions | <<_processor_top_entity_generics, `RISCV_ISA_M`>>
| <<_u_isa_extension,`U`>> | Less-privileged _user_ mode extension | <<_processor_top_entity_generics, `RISCV_ISA_U`>>
| <<_x_isa_extension,`X`>> | Platform-specific / NEORV32-specific extension | Always enabled
| <<_zalrsc_isa_extension,`Zalrsc`>> | Atomic reservation-set instructions | `RISCV_ISA_Zalrsc`
| <<_zba_isa_extension,`Zba`>> | Shifted-add bit manipulation instructions | `RISCV_ISA_Zba`
| <<_zbb_isa_extension,`Zbb`>> | Basic bit manipulation instructions | `RISCV_ISA_Zbb`
| <<_zbkb_isa_extension,`Zbkb`>> | Scalar cryptographic bit manipulation instructions | `RISCV_ISA_Zbkb`
| <<_zbkc_isa_extension,`Zbkc`>> | Scalar cryptographic carry-less multiplication instructions | `RISCV_ISA_Zbkc`
| <<_zbkx_isa_extension,`Zbkx`>> | Scalar cryptographic crossbar permutation instructions | `RISCV_ISA_Zbkx`
| <<_zbs_isa_extension,`Zbs`>> | Single-bit bit manipulation instructions | `RISCV_ISA_Zbs`
| <<_zfinx_isa_extension,`Zfinx`>> | Floating-point instructions using integer registers | `RISCV_ISA_Zfinx`
| <<_zalrsc_isa_extension,`Zalrsc`>> | Atomic reservation-set instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zalrsc`>>
| <<_zba_isa_extension,`Zba`>> | Shifted-add bit manipulation instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zba`>>
| <<_zbb_isa_extension,`Zbb`>> | Basic bit manipulation instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zbb`>>
| <<_zbkb_isa_extension,`Zbkb`>> | Scalar cryptographic bit manipulation instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zbkb`>>
| <<_zbkc_isa_extension,`Zbkc`>> | Scalar cryptographic carry-less multiplication instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zbkc`>>
| <<_zbkx_isa_extension,`Zbkx`>> | Scalar cryptographic crossbar permutation instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zbkx`>>
| <<_zbs_isa_extension,`Zbs`>> | Single-bit bit manipulation instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zbs`>>
| <<_zfinx_isa_extension,`Zfinx`>> | Floating-point instructions using integer registers | <<_processor_top_entity_generics, `RISCV_ISA_Zfinx`>>
| <<_zifencei_isa_extension,`Zifencei`>> | Instruction stream synchronization instruction | Always enabled
| <<_zicntr_isa_extension,`Zicntr`>> | Base counters extension | `RISCV_ISA_Zicntr`
| <<_zicond_isa_extension,`Zicond`>> | Integer conditional operations | `RISCV_ISA_Zicond`
| <<_zicntr_isa_extension,`Zicntr`>> | Base counters extension | <<_processor_top_entity_generics, `RISCV_ISA_Zicntr`>>
| <<_zicond_isa_extension,`Zicond`>> | Integer conditional operations | <<_processor_top_entity_generics, `RISCV_ISA_Zicond`>>
| <<_zicsr_isa_extension,`Zicsr`>> | Control and status register access instructions | Always enabled
| <<_zihpm_isa_extension,`Zihpm`>> | Hardware performance monitors extension | `RISCV_ISA_Zihpm`
| <<_zihpm_isa_extension,`Zihpm`>> | Hardware performance monitors extension | <<_processor_top_entity_generics, `RISCV_ISA_Zihpm`>>
| <<_zkn_isa_extension,`Zkn`>> | Scalar cryptographic NIST algorithm suite | _Implicitly_ enabled
| <<_zknd_isa_extension,`Zknd`>> | Scalar cryptographic NIST AES decryption instructions | `RISCV_ISA_Zknd`
| <<_zkne_isa_extension,`Zkne`>> | Scalar cryptographic NIST AES encryption instructions | `RISCV_ISA_Zkne`
| <<_zknh_isa_extension,`Zknh`>> | Scalar cryptographic NIST hash function instructions | `RISCV_ISA_Zknh`
| <<_zknd_isa_extension,`Zknd`>> | Scalar cryptographic NIST AES decryption instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zknd`>>
| <<_zkne_isa_extension,`Zkne`>> | Scalar cryptographic NIST AES encryption instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zkne`>>
| <<_zknh_isa_extension,`Zknh`>> | Scalar cryptographic NIST hash function instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zknh`>>
| <<_zkt_isa_extension,`Zkt`>> | Data independent execution time (of cryptographic operations) | _Implicitly_ enabled
| <<_zks_isa_extension,`Zks`>> | Scalar cryptographic ShangMi algorithm suite | _Implicitly_ enabled
| <<_zksed_isa_extension,`Zksed`>> | Scalar cryptographic ShangMi block cypher instructions | `RISCV_ISA_Zksed`
| <<_zksh_isa_extension,`Zksh`>> | Scalar cryptographic ShangMi hash instructions | `RISCV_ISA_Zksh`
| <<_zmmul_isa_extension,`Zmmul`>> | Integer multiplication-only instructions | `RISCV_ISA_Zmmul`
| <<_zxcfu_isa_extension,`Zcfu`>> | Custom / user-defined instructions | `RISCV_ISA_Zxcfu`
| <<_smpmp_isa_extension,`Smpmp`>> | Physical memory protection (PMP) extension | `RISCV_ISA_Smpmp`
| <<_sdext_isa_extension,`Sdext`>> | External debug support extension | `ON_CHIP_DEBUGGER_EN`
| <<_sdtrig_isa_extension,`Sdtrig`>> | Trigger module extension | `ON_CHIP_DEBUGGER_EN`
| <<_zksed_isa_extension,`Zksed`>> | Scalar cryptographic ShangMi block cypher instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zksed`>>
| <<_zksh_isa_extension,`Zksh`>> | Scalar cryptographic ShangMi hash instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zksh`>>
| <<_zmmul_isa_extension,`Zmmul`>> | Integer multiplication-only instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zmmul`>>
| <<_zxcfu_isa_extension,`Zcfu`>> | Custom / user-defined instructions | <<_processor_top_entity_generics, `RISCV_ISA_Zxcfu`>>
| <<_smpmp_isa_extension,`Smpmp`>> | Physical memory protection (PMP) extension | <<_processor_top_entity_generics, `RISCV_ISA_Smpmp`>>
| <<_sdext_isa_extension,`Sdext`>> | External debug support extension | <<_processor_top_entity_generics, `ON_CHIP_DEBUGGER_EN`>>
| <<_sdtrig_isa_extension,`Sdtrig`>> | Trigger module extension | <<_processor_top_entity_generics, `ON_CHIP_DEBUGGER_EN`>>
|=======================
.RISC-V ISA Specification
@ -603,7 +603,7 @@ RISC-V specs. Also, custom trap codes for <<_mcause>> are implemented.
The `Zalrsc` ISA extension is a sub-extension of the RISC-V _atomic memory access_ (`A`) ISA extension and includes
instructions for reservation-set operations (load-reservate `lr` and store-conditional `sc`) only.
It is enabled by the top's `RISCV_ISA_Zalrsc` generic.
It is enabled by the top's <<_processor_top_entity_generics, `RISCV_ISA_Zalrsc`>> generic.
.AMO / `A` Emulation
[NOTE]
@ -712,7 +712,7 @@ User-level access to the counter CSRs can be constrained by the <<_mcounteren>>
==== `Zicond` ISA Extension
The `Zicond` ISA extension adds integer conditional move primitives that allow to implement branch-less
control flows. It is enabled by the top's `RISCV_ISA_Zicond` generic.
control flows. It is enabled by the top's <<_processor_top_entity_generics, `RISCV_ISA_Zicond`>> generic.
This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neorv32_cpu_cp_cond.vhd`).
.Instructions and Timing
@ -768,8 +768,9 @@ The event-driven increment of the HPMs can be deactivated individually via the <
==== `Zba` ISA Extension
The `Zba` sub-extension is part of the _RISC-V bit manipulation_ ISA specification (<<_b_isa_extension>>)
and adds shifted-add / address-generation instructions. It is enabled by the top's `RISCV_ISA_Zba` generic.
This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neorv32_cpu_cp_bitmanip.vhd`).
and adds shifted-add / address-generation instructions. It is enabled by the top's
<<_processor_top_entity_generics, `RISCV_ISA_Zba`>> generic. This ISA extension is implemented as multi-cycle
ALU co-processor (`rtl/core/neorv32_cpu_cp_bitmanip.vhd`).
.Instructions and Timing
[cols="<2,<4,<3"]
@ -783,8 +784,8 @@ This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neo
==== `Zbb` ISA Extension
The `Zbb` sub-extension is part of the _RISC-V bit manipulation_ ISA specification (<<_b_isa_extension>>)
and adds the basic bit manipulation instructions. It is enabled by the top's `RISCV_ISA_Zbb` generic.
This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neorv32_cpu_cp_bitmanip.vhd`).
and adds the basic bit manipulation instructions. It is enabled by the top's <<_processor_top_entity_generics, `RISCV_ISA_Zbb`>>
generic. This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neorv32_cpu_cp_bitmanip.vhd`).
.Instructions and Timing
[cols="<5,<4,<5"]
@ -810,7 +811,7 @@ configuration option that will replace the (time-variant) bit-serial shifter by
==== `Zbs` ISA Extension
The `Zbs` sub-extension is part of the _RISC-V bit manipulation_ ISA specification (<<_b_isa_extension>>)
and adds single-bit operations. It is enabled by the top's `RISCV_ISA_Zbs` generic.
and adds single-bit operations. It is enabled by the top's <<_processor_top_entity_generics, `RISCV_ISA_Zbs`>> generic.
This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neorv32_cpu_cp_bitmanip.vhd`).
.Instructions and Timing
@ -824,7 +825,7 @@ This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neo
==== `Zbkb` ISA Extension
The `Zbkb` sub-extension is part of the _RISC-V scalar cryptography_ ISA specification and extends the _RISC-V bit manipulation_
ISA extension with additional instructions. It is enabled by the top's `RISCV_ISA_Zbkb` generic.
ISA extension with additional instructions. It is enabled by the top's <<_processor_top_entity_generics, `RISCV_ISA_Zbkb`>> generic.
Note that enabling this extension will also enable the `Zbb` basic bit-manipulation ISA extension (which is extended by `Zknb`).
This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neorv32_cpu_cp_bitmanip.vhd`).
@ -842,7 +843,7 @@ This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neo
==== `Zbkc` ISA Extension
The `Zbkc` sub-extension is part of the _RISC-V scalar cryptography_ ISA extension and adds carry-less multiplication instruction.
ISA extension with additional instructions. It is enabled by the top's `RISCV_ISA_Zbkc` generic.
ISA extension with additional instructions. It is enabled by the top's <<_processor_top_entity_generics, `RISCV_ISA_Zbkc`>> generic.
This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neorv32_cpu_cp_bitmanip.vhd`).
.Instructions and Timing
@ -857,7 +858,7 @@ This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neo
==== `Zbkx` ISA Extension
The `Zbkx` sub-extension is part of the _RISC-V scalar cryptography_ ISA specification and adds crossbar permutation instructions.
It is enabled by the top's `RISCV_ISA_Zbkx` generic.
It is enabled by the top's <<_processor_top_entity_generics, `RISCV_ISA_Zbkx`>> generic.
This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neorv32_cpu_cp_crypto.vhd`).
.Instructions and Timing
@ -890,7 +891,7 @@ A processor configuration which implements `Zkn` must implement all of the above
==== `Zknd` ISA Extension
The `Zknd` sub-extension is part of the _RISC-V scalar cryptography_ ISA specification and adds NIST AES decryption instructions.
It is enabled by the top's `RISCV_ISA_Zknd` generic.
It is enabled by the top's <<_processor_top_entity_generics, `RISCV_ISA_Zknd`>> generic.
This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neorv32_cpu_cp_crypto.vhd`).
.Instructions and Timing
@ -905,7 +906,7 @@ This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neo
==== `Zkne` ISA Extension
The `Zkne` sub-extension is part of the _RISC-V scalar cryptography_ ISA specification and adds NIST AES encryption instructions.
It is enabled by the top's `RISCV_ISA_Zkne` generic.
It is enabled by the top's <<_processor_top_entity_generics, `RISCV_ISA_Zkne`>> generic.
This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neorv32_cpu_cp_crypto.vhd`).
.Instructions and Timing
@ -920,7 +921,7 @@ This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neo
==== `Zknh` ISA Extension
The `Zknh` sub-extension is part of the _RISC-V scalar cryptography_ ISA specification and adds NIST hash function instructions.
It is enabled by the top's `RISCV_ISA_Zknh` generic.
It is enabled by the top's <<_processor_top_entity_generics, `RISCV_ISA_Zknh`>> generic.
This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neorv32_cpu_cp_crypto.vhd`).
.Instructions and Timing
@ -953,7 +954,7 @@ A processor configuration which implements `Zks` must implement all of the above
==== `Zksed` ISA Extension
The `Zksed` sub-extension is part of the _RISC-V scalar cryptography_ ISA specification and adds ShangMi block cypher
and key schedule instructions. It is enabled by the top's `RISCV_ISA_Zksed` generic.
and key schedule instructions. It is enabled by the top's <<_processor_top_entity_generics, `RISCV_ISA_Zksed`>> generic.
This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neorv32_cpu_cp_crypto.vhd`).
.Instructions and Timing
@ -969,7 +970,7 @@ This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neo
==== `Zksh` ISA Extension
The `Zksh` sub-extension is part of the _RISC-V scalar cryptography_ ISA specification and adds ShangMi hash function instructions.
It is enabled by the top's `RISCV_ISA_Zksh` generic.
It is enabled by the top's <<_processor_top_entity_generics, `RISCV_ISA_Zksh`>> generic.
This ISA extension is implemented as multi-cycle ALU co-processor (`rtl/core/neorv32_cpu_cp_crypto.vhd`).
.Instructions and Timing

View file

@ -211,7 +211,7 @@ of the register file by 50%.
.CFU Execution Time
[NOTE]
The CFU has to complete computation within a **bound time window** (default = 512 clock cycles). Otherwise,
the CFU operation is terminated by the hardware and an illegal instruction exception is raised. See section
the CFU operation is terminated by the CPU execution logic and an illegal instruction exception is raised. See section
<<_cpu_arithmetic_logic_unit>> for more information.
.CFU Exception

View file

@ -762,8 +762,8 @@ caused by a fence instruction, a control flow transfer or a instruction fetch bu
| 5 | `HPMCNT_EVENT_WAIT_ALU` | r/w | any delay/wait cycle caused by a _multi-cycle_ <<_cpu_arithmetic_logic_unit>> operation
| 6 | `HPMCNT_EVENT_BRANCH` | r/w | any executed branch instruction (unconditional, conditional-taken or conditional-not-taken)
| 7 | `HPMCNT_EVENT_BRANCHED` | r/w | any control transfer operation (unconditional jump, taken conditional branch or trap entry/exit)
| 8 | `HPMCNT_EVENT_LOAD` | r/w | any executed load operation (including atomic memory operations, <<_a_isa_extension>>)
| 9 | `HPMCNT_EVENT_STORE` | r/w | any executed store operation (including atomic memory operations, <<_a_isa_extension>>)
| 8 | `HPMCNT_EVENT_LOAD` | r/w | any executed load operation (including atomic memory operations, <<_zalrsc_isa_extension>>)
| 9 | `HPMCNT_EVENT_STORE` | r/w | any executed store operation (including atomic memory operations, <<_zalrsc_isa_extension>>)
| 10 | `HPMCNT_EVENT_WAIT_LSU` | r/w | any memory/bus/cache/etc. delay/wait cycle while executing any load or store operation (caused by a data bus wait cycle))
| 11 | `HPMCNT_EVENT_TRAP` | r/w | starting processing of any trap (<<_traps_exceptions_and_interrupts>>)
|=======================

View file

@ -20,7 +20,8 @@ image::neorv32_processor.png[align=center]
**Key Features**
* _optional_ processor-internal data and instruction memories (<<_data_memory_dmem,**DMEM**>>/<<_instruction_memory_imem,**IMEM**>>)
* _optional_ caches (<<_processor_internal_instruction_cache_icache,**iCACHE**>>, <<_processor_internal_data_cache_dcache,**dCACHE**>>, <<_execute_in_place_module_xip,**xipCACHE**>>, <<_processor_external_bus_interface_xbus,**xCACHE**>>)
* _optional_ caches (<<_processor_internal_instruction_cache_icache,**I-CACHE**>>, <<_processor_internal_data_cache_dcache,**D-CACHE**>>,
<<_execute_in_place_module_xip,**XIP-CACHE**>>, <<_processor_external_bus_interface_xbus,**XBUS-CACHE**>>)
* _optional_ internal bootloader (<<_bootloader_rom_bootrom,**BOOTROM**>>) with UART console & SPI flash boot option
* _optional_ machine system timer (<<_machine_system_timer_mtime,**MTIME**>>), RISC-V-compatible
* _optional_ two independent universal asynchronous receivers and transmitters (<<_primary_universal_asynchronous_receiver_and_transmitter_uart0,**UART0**>>,
@ -31,11 +32,11 @@ image::neorv32_processor.png[align=center]
* _optional_ general purpose parallel IO port (<<_general_purpose_input_and_output_port_gpio,**GPIO**>>), 64xOut, 64xIn
* _optional_ 32-bit external bus interface, Wishbone b4 / AXI4-Lite compatible (<<_processor_external_bus_interface_xbus,**XBUS**>>)
* _optional_ watchdog timer (<<_watchdog_timer_wdt,**WDT**>>)
* _optional_ PWM controller with up to 12 channels & 8-bit duty cycle resolution (<<_pulse_width_modulation_controller_pwm,**PWM**>>)
* _optional_ PWM controller with up to 16 individual channels (<<_pulse_width_modulation_controller_pwm,**PWM**>>)
* _optional_ ring-oscillator-based true random number generator (<<_true_random_number_generator_trng,**TRNG**>>)
* _optional_ custom functions subsystem for custom co-processor extensions (<<_custom_functions_subsystem_cfs,**CFS**>>)
* _optional_ NeoPixel(TM)/WS2812-compatible smart LED interface (<<_smart_led_interface_neoled,**NEOLED**>>)
* _optional_ external interrupt controller with up to 32 channels (<<_external_interrupt_controller_xirq,**XIRQ**>>)
* _optional_ external interrupt controller with up to 32 channels and programmable interrupt triggers (<<_external_interrupt_controller_xirq,**XIRQ**>>)
* _optional_ general purpose 32-bit timer (<<_general_purpose_timer_gptmr,**GPTMR**>>)
* _optional_ execute in-place module (<<_execute_in_place_module_xip,**XIP**>>)
* _optional_ 1-wire serial interface controller (<<_one_wire_serial_interface_controller_onewire,**ONEWIRE**>>), compatible to the 1-wire standard
@ -43,7 +44,7 @@ image::neorv32_processor.png[align=center]
* _optional_ stream link interface (<<_stream_link_interface_slink,**SLINK**>>), AXI4-Stream compatible
* _optional_ cyclic redundancy check unit (<<_cyclic_redundancy_check_crc,**CRC**>>)
* _optional_ on-chip debugger with JTAG TAP (<<_on_chip_debugger_ocd,**OCD**>>)
* (optional) system configuration information memory to check HW configuration via software (<<_system_configuration_information_memory_sysinfo,**SYSINFO**>>)
* _optional_ system configuration information memory to determine hardware configuration via software (<<_system_configuration_information_memory_sysinfo,**SYSINFO**>>)
<<<
@ -72,7 +73,7 @@ bits/channels are hardwired to zero.
Some interfaces (like the TWI and the 1-Wire bus) require explicit tri-state drivers in the final top module.
.Input/Output Registers
[NOTE]
[NOTE]
By default all output signals are driven by register and all input signals are synchronized into the processor's
clock domain also using registers. However, for ASIC implementations it is recommended to add another register state
to all inputs and output so the synthesis tool can insert an explicit IO (boundary) scan chain.
@ -149,7 +150,7 @@ to all inputs and output so the synthesis tool can insert an explicit IO (bounda
| `onewire_i` | 1 | in | `'H'` | 1-wire bus sense input
| `onewire_o` | 1 | out | - | 1-wire bus output (pull low only)
5+^| **<<_pulse_width_modulation_controller_pwm>>**
| `pwm_o` | 12 | out | - | pulse-width modulated channels
| `pwm_o` | 16 | out | - | pulse-width modulated channels
5+^| **<<_custom_functions_subsystem_cfs>>**
| `cfs_in_i` | 32 | in | `'L'` | custom CFS input signal conduit
| `cfs_out_o` | 32 | out | - | custom CFS output signal conduit
@ -289,7 +290,7 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt
| `IO_SDI_FIFO` | natural | 1 | Depth of the <<_serial_data_interface_controller_sdi>> FIFO. Has to be a power of two, min 1, max 32768.
| `IO_TWI_EN` | boolean | false | Implement the <<_two_wire_serial_interface_controller_twi>>.
| `IO_TWI_FIFO` | natural | 1 | Depth of the <<_two_wire_serial_interface_controller_twi>> FIFO. Has to be a power of two, min 1, max 32768.
| `IO_PWM_NUM_CH` | natural | 0 | Number of channels of the <<_pulse_width_modulation_controller_pwm>> to implement (0..12).
| `IO_PWM_NUM_CH` | natural | 0 | Number of channels of the <<_pulse_width_modulation_controller_pwm>> to implement (0..16).
| `IO_WDT_EN` | boolean | false | Implement the <<_watchdog_timer_wdt>>.
| `IO_TRNG_EN` | boolean | false | Implement the <<_true_random_number_generator_trng>>.
| `IO_TRNG_FIFO` | natural | 1 | Depth of the TRNG data FIFO. Has to be a power of two, min 1, max 32768.
@ -585,7 +586,7 @@ explicit specific processor generic. See section <<_processor_external_bus_inter
==== Reservation Set Controller
The reservation set controller is responsible for handling the load-reservate and store-conditional bus transaction that
are triggered by the `lr.w` (LR) and `sc.w` (SC) instructions from the CPU's <<_a_isa_extension>>.
are triggered by the `lr.w` (LR) and `sc.w` (SC) instructions from the CPU's <<_zalrsc_isa_extension>>.
A "reservation" defines an address or address range that provides a guarding mechanism to support atomic accesses. A new
reservation is registered by the LR instruction. The address provided by this instruction defines the memory location

View file

@ -28,7 +28,7 @@ The data cache provides direct accesses (= uncached) to memory in order to acces
processor-internal IO/peripheral modules). All accesses that target the address range from `0xF0000000` to `0xFFFFFFFF`
will not be cached at all (see section <<_address_space>>). Direct/uncached accesses have **lower** priority than
cache block operations to allow continuous burst transfer and also to maintain logical instruction forward
progress / data coherency. Furthermore, atomic load-reservate and store-conditional instructions (<<_a_isa_extension>>)
progress / data coherency. Furthermore, atomic load-reservate and store-conditional instructions (<<_zalrsc_isa_extension>>)
will always **bypass** the cache.
.Caching Internal Memories

View file

@ -28,7 +28,7 @@ The data cache provides direct accesses (= uncached) to memory in order to acces
processor-internal IO/peripheral modules). All accesses that target the address range from `0xF0000000` to `0xFFFFFFFF`
will not be cached at all (see section <<_address_space>>). Direct/uncached accesses have **lower** priority than
cache block operations to allow continuous burst transfer and also to maintain logical instruction forward
progress / data coherency. Furthermore, atomic load-reservate and store-conditional instructions (<<_a_isa_extension>>)
progress / data coherency. Furthermore, atomic load-reservate and store-conditional instructions (<<_zalrsc_isa_extension>>)
will always **bypass** the cache.
.Caching Internal Memories

View file

@ -8,8 +8,8 @@
| Hardware source files: | neorv32_pwm.vhd |
| Software driver files: | neorv32_pwm.c |
| | neorv32_pwm.h |
| Top entity ports: | `pwm_o` | PWM output channels (12-bit)
| Configuration generics: | `IO_PWM_NUM_CH` | number of PWM channels to implement (0..12)
| Top entity ports: | `pwm_o` | PWM output channels (16-bit)
| Configuration generics: | `IO_PWM_NUM_CH` | number of PWM channels to implement (0..16)
| CPU interrupts: | none |
| Access restrictions: 2+| privileged access only, non-32-bit write accesses are ignored
|=======================
@ -17,47 +17,45 @@
**Overview**
The PWM module implements a pulse-width modulation controller with up to 12 independent channels providing
8-bit resolution per channel. The actual number of implemented channels is defined by the `IO_PWM_NUM_CH` generic.
Setting this generic to zero will completely remove the PWM controller from the design.
[NOTE]
The `pwm_o` has a static size of 12-bit. If less than 12 PWM channels are configured, only the LSB-aligned channel
bits are used while the remaining bits are hardwired to zero.
The PWM module implements a pulse-width modulation controller with up to 16 independent channels. Duty cycle and
carrier frequency can be programmed individually for each channel.The total number of implemented channels is
defined by the `IO_PWM_NUM_CH` generic. The PWM output signal `pwm_o` has a static size of 16-bit. Channel 0
corresponds to bit 0, channel 1 to bit 1 and so on. If less than 16 channels are configured, only the LSB-aligned
channel bits are connected while the remaining ones are hardwired to zero.
**Theory of Operation**
The PWM controller is activated by setting the `PWM_CTRL_EN` bit in the module's control register `CTRL`. When this
bit is cleared, the unit is reset and all PWM output channels are set to zero. The module
provides three duty cycle registers `DC[0]` to `DC[2]`. Each register contains the duty cycle configuration for four
consecutive channels. For example, the duty cycle of channel 0 is defined via bits 7:0 in `DC[0]`. The duty cycle of
channel 2 is defined via bits 15:0 in `DC[0]` and so on.
Depending on the configured number channels, the PWM module provides 16 configuration registers `CHANNEL_CFG[0]` to
`CHANNEL_CFG[15]` - one for each channel. Regardless of the configuration of `IO_PWM_NUM_CH` all channel registers can
be accessed without raising an exception. However, registers above `IO_PWM_NUM_CH-1` are read-only and hardwired to
all-zero.
[NOTE]
Regardless of the configuration of `IO_PWM_NUM_CH` all module registers can be accessed without raising an exception.
Software can discover the number of available channels by writing 0xff to all duty cycle configuration bytes and
reading those values back. The duty-cycle of channels that were not implemented always reads as zero.
Each configuration provides a 1-bit enable flag to enable/disable the according channel, an 8-bit register for setting
the duty cycle and a 3-bit clock prescaler select as well as a 10-bit clock diver for _coarse_ and _fine_ tuning of the
carrier frequency, respectively.
Based on the configured duty cycle the according intensity of the channel can be computed by the following formula:
A channel is enabled by setting the `PWM_CFG_EN` bit. If this bit is cleared the according PWM output is set to zero.
The duty cycle is programmed via the 8 `PWM_CFG_DUTY` bits. Based on the value programmed to this bits the duty cycle
the resulting duty cycle of the according channel can be computed by the following formula:
_**Intensity~x~**_ = `DC[y](i*8+7 downto i*8)` / (2^8^)
_Duty Cycle_[%] = `PWM_CFG_DUTY` / 2^8^
The base frequency of the generated PWM signals is defined by the PWM core clock. This clock is derived
from the main processor clock and divided by a prescaler via the 3-bit `PWM_CTRL_PRSCx` in the unit's control
register.
The PWM period (carrier frequency) is derived from the processor's main clock (_f~main~_). The `PWM_CFG_PRSC` register
bits allow to select one out of eight pre-defined clock prescalers for a coarse clock scaling. The 10 `PWM_CFG_CDIV` register
bits can be used to apply another fine clock scaling.
.PWM prescaler configuration
[cols="<4,^1,^1,^1,^1,^1,^1,^1,^1"]
[options="header",grid="rows"]
|=======================
| **`PWM_CTRL_PRSCx`** | `0b000` | `0b001` | `0b010` | `0b011` | `0b100` | `0b101` | `0b110` | `0b111`
| **`PWM_CFG_PRSC`** | `0b000` | `0b001` | `0b010` | `0b011` | `0b100` | `0b101` | `0b110` | `0b111`
| Resulting `clock_prescaler` | 2 | 4 | 8 | 64 | 128 | 1024 | 2048 | 4096
|=======================
The resulting PWM carrier frequency is defined by:
_**f~PWM~**_ = _f~main~[Hz]_ / (2^8^ * `clock_prescaler`)
_f~PWM~_[Hz] = _f~main~_[Hz] / (2^8^ * `clock_prescaler` * (1 + `PWM_CFG_CDIV`))
**Register Map**
@ -67,19 +65,15 @@ _**f~PWM~**_ = _f~main~[Hz]_ / (2^8^ * `clock_prescaler`)
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.3+<| `0xfffff000` .3+<| `CTRL` <|`0` `PWM_CTRL_EN` ^| r/w <| PWM enable
<|`3:1` `PWM_CTRL_PRSC2 : PWM_CTRL_PRSC0` ^| r/w <| 3-bit clock prescaler select
<|`31:4` - ^| r/- <| _reserved_, read as zero
.4+<| `0xfffff004` .4+<| `DC[0]` <|`7:0` ^| r/w <| 8-bit duty cycle for channel 0
<|`15:8` ^| r/w <| 8-bit duty cycle for channel 1
<|`23:16` ^| r/w <| 8-bit duty cycle for channel 2
<|`31:24` ^| r/w <| 8-bit duty cycle for channel 3
.4+<| `0xfffff008` .4+<| `DC[1]` <|`7:0` ^| r/w <| 8-bit duty cycle for channel 4
<|`15:8` ^| r/w <| 8-bit duty cycle for channel 5
<|`23:16` ^| r/w <| 8-bit duty cycle for channel 6
<|`31:24` ^| r/w <| 8-bit duty cycle for channel 7
.4+<| `0xfffff00c` .4+<| `DC[2]` <|`7:0` ^| r/w <| 8-bit duty cycle for channel 8
<|`15:8` ^| r/w <| 8-bit duty cycle for channel 9
<|`23:16` ^| r/w <| 8-bit duty cycle for channel 10
<|`31:24` ^| r/w <| 8-bit duty cycle for channel 11
.5+<| `0xfffff000` .5+<| `CHANNEL_CFG[0]` <|`31` - `PWM_CFG_EN` ^| r/w <| Channel 0: channel enabled when set
<|`30:28` - `PWM_CFG_PRSC_MSB:PWM_CFG_PRSC_LSB` ^| r/w <| Channel 0: 3-bit clock prescaler select
<|`27:18` ^| r/- <| Channel 0: _reserved_, hardwired to zero
<|`17:8` - `PWM_CFG_CDIV_MSB:PWM_CFG_CDIV_LSB` ^| r/w <| Channel 0: 10-bit clock divider
<|`7:0` - `PWM_CFG_DUTY_MSB:PWM_CFG_DUTY_LSB` ^| r/w <| Channel 0: 8-bit duty cycle
| `0xfffff004` ... `0xfffff038` | `CHANNEL_CFG[1]` ... `CHANNEL_CFG[14]` | ... | r/w <| Channels 1 to 14
.5+<| `0xfffff03C` .5+<| `CHANNEL_CFG[15]` <|`31` - `PWM_CFG_EN` ^| r/w <| Channel 15: channel enabled when set
<|`30:28` - `PWM_CFG_PRSC_MSB:PWM_CFG_PRSC_LSB` ^| r/w <| Channel 15: 3-bit clock prescaler select
<|`27:18` ^| r/- <| Channel 15: _reserved_, hardwired to zero
<|`17:8` - `PWM_CFG_CDIV_MSB:PWM_CFG_CDIV_LSB` ^| r/w <| Channel 15: 10-bit clock divider
<|`7:0` - `PWM_CFG_DUTY_MSB:PWM_CFG_DUTY_LSB` ^| r/w <| Channel 15: 8-bit duty cycle
|=======================

View file

@ -141,5 +141,5 @@ The data cache provides direct accesses (= uncached) to memory in order to acces
All accesses that target the address range from `0xF0000000` to `0xFFFFFFFF`
will not be cached at all (see section <<_address_space>>). Direct/uncached accesses have **lower** priority than
cache block operations to allow continuous burst transfer and also to maintain logical instruction forward
progress / data coherency. Furthermore, atomic load-reservate and store-conditional instructions (<<_a_isa_extension>>)
progress / data coherency. Furthermore, atomic load-reservate and store-conditional instructions (<<_zalrsc_isa_extension>>)
will always **bypass** the cache.

View file

@ -87,7 +87,7 @@ The NEORV32 project provides a set of pre-defined C libraries that allow an easy
| `neorv32_cfs.c` | `neorv32_cfs.h` | <<_custom_functions_subsystem_cfs>> HAL
| `neorv32_crc.c` | `neorv32_crc.h` | <<_cyclic_redundancy_check_crc>> HAL
| `neorv32_cpu.c` | `neorv32_cpu.h` | <<_neorv32_central_processing_unit_cpu>> HAL
| `neorv32_cpu_amo.c` | `neorv32_cpu_amo.h` | Emulation functions for the read-modify-write <<_a_isa_extension>> instructions
| `neorv32_cpu_amo.c` | `neorv32_cpu_amo.h` | Emulation functions for the read-modify-write <<_zalrsc_isa_extension>> / `A` instructions
| | `neorv32_cpu_csr.h` | <<_control_and_status_registers_csrs>> definitions
| `neorv32_cpu_cfu.c` | `neorv32_cpu_cfu.h` | <<_custom_functions_unit_cfu>> HAL
| `neorv32_dma.c` | `neorv32_dma.h` | <<_direct_memory_access_controller_dma>> HAL

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Before After
Before After

View file

@ -29,7 +29,7 @@ package neorv32_package is
-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100503"; -- hardware version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100504"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width
@ -755,7 +755,7 @@ package neorv32_package is
IO_SDI_FIFO : natural range 1 to 2**15 := 1;
IO_TWI_EN : boolean := false;
IO_TWI_FIFO : natural range 1 to 2**15 := 1;
IO_PWM_NUM_CH : natural range 0 to 12 := 0;
IO_PWM_NUM_CH : natural range 0 to 16 := 0;
IO_WDT_EN : boolean := false;
IO_TRNG_EN : boolean := false;
IO_TRNG_FIFO : natural range 1 to 2**15 := 1;
@ -841,7 +841,7 @@ package neorv32_package is
onewire_i : in std_ulogic := 'H';
onewire_o : out std_ulogic;
-- PWM (available if IO_PWM_NUM_CH > 0) --
pwm_o : out std_ulogic_vector(11 downto 0); -- pwm channels
pwm_o : out std_ulogic_vector(15 downto 0); -- pwm channels
-- Custom Functions Subsystem IO --
cfs_in_i : in std_ulogic_vector(IO_CFS_IN_SIZE-1 downto 0) := (others => 'L');
cfs_out_o : out std_ulogic_vector(IO_CFS_OUT_SIZE-1 downto 0);

View file

@ -1,6 +1,10 @@
-- ================================================================================ --
-- NEORV32 SoC - Pulse Width Modulation Controller (PWM) --
-- -------------------------------------------------------------------------------- --
-- Providing up to 16 individual PWM channels; each channel features an individual --
-- enable flag, an 8-bit duty-cycle configuration, a 3-bit prescaler (for coarse --
-- clock configuration) and a 16-bit clock divider (for fine clock configuration). --
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
@ -17,7 +21,7 @@ use neorv32.neorv32_package.all;
entity neorv32_pwm is
generic (
NUM_CHANNELS : natural range 0 to 12 -- number of PWM channels (0..12)
NUM_CHANNELS : natural range 0 to 16 -- number of PWM channels (0..16)
);
port (
clk_i : in std_ulogic; -- global clock line
@ -26,32 +30,32 @@ entity neorv32_pwm is
bus_rsp_o : out bus_rsp_t; -- bus response
clkgen_en_o : out std_ulogic; -- enable clock generator
clkgen_i : in std_ulogic_vector(7 downto 0); -- clock divider input
pwm_o : out std_ulogic_vector(11 downto 0) -- PWM output
pwm_o : out std_ulogic_vector(15 downto 0) -- PWM output
);
end neorv32_pwm;
architecture neorv32_pwm_rtl of neorv32_pwm is
-- Control register bits --
constant ctrl_enable_c : natural := 0; -- r/w: PWM enable
constant ctrl_prsc0_bit_c : natural := 1; -- r/w: prescaler select bit 0
constant ctrl_prsc1_bit_c : natural := 2; -- r/w: prescaler select bit 1
constant ctrl_prsc2_bit_c : natural := 3; -- r/w: prescaler select bit 2
-- pwm channel controller --
component neorv32_pwm_channel
port (
clk_i : in std_ulogic; -- global clock line
rstn_i : in std_ulogic; -- global reset line, low-active, async
we_i : in std_ulogic; -- write enable
re_i : in std_ulogic; -- read enable
wdata_i : in std_ulogic_vector(31 downto 0); -- write data
rdata_o : out std_ulogic_vector(31 downto 0); -- read data
clkgen_i : in std_ulogic_vector(7 downto 0); -- clock divider input
clkgen_en_o : out std_ulogic; -- enable clock generator
pwm_o : out std_ulogic -- PWM output
);
end component;
-- accessible regs --
type pwm_ch_t is array (0 to 11) of std_ulogic_vector(7 downto 0);
signal pwm_ch : pwm_ch_t; -- duty cycle (r/w)
signal enable : std_ulogic; -- enable unit (r/w)
signal prsc : std_ulogic_vector(2 downto 0); -- clock prescaler (r/w)
type pwm_ch_rd_t is array (0 to 11) of std_ulogic_vector(7 downto 0);
signal pwm_ch_rd : pwm_ch_rd_t; -- duty cycle read-back
-- prescaler clock generator --
signal prsc_tick : std_ulogic;
-- pwm core counter --
signal pwm_cnt : std_ulogic_vector(7 downto 0);
-- wiring --
type rdata_t is array (0 to NUM_CHANNELS-1) of std_ulogic_vector(31 downto 0);
signal rdata : rdata_t;
signal rdata_sum : std_ulogic_vector(31 downto 0);
signal sel, we, re, ce, pwm : std_ulogic_vector(NUM_CHANNELS-1 downto 0);
begin
@ -61,99 +65,173 @@ begin
begin
if (rstn_i = '0') then
bus_rsp_o <= rsp_terminate_c;
enable <= '0';
prsc <= (others => '0');
pwm_ch <= (others => (others => '0'));
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
-- control register --
if (bus_req_i.addr(3 downto 2) = "00") then
enable <= bus_req_i.data(ctrl_enable_c);
prsc <= bus_req_i.data(ctrl_prsc2_bit_c downto ctrl_prsc0_bit_c);
end if;
-- duty cycle register 0 --
if (bus_req_i.addr(3 downto 2) = "01") then
pwm_ch(00) <= bus_req_i.data(07 downto 00);
pwm_ch(01) <= bus_req_i.data(15 downto 08);
pwm_ch(02) <= bus_req_i.data(23 downto 16);
pwm_ch(03) <= bus_req_i.data(31 downto 24);
end if;
-- duty cycle register 1 --
if (bus_req_i.addr(3 downto 2) = "10") then
pwm_ch(04) <= bus_req_i.data(07 downto 00);
pwm_ch(05) <= bus_req_i.data(15 downto 08);
pwm_ch(06) <= bus_req_i.data(23 downto 16);
pwm_ch(07) <= bus_req_i.data(31 downto 24);
end if;
-- duty cycle register 2 --
if (bus_req_i.addr(3 downto 2) = "11") then
pwm_ch(08) <= bus_req_i.data(07 downto 00);
pwm_ch(09) <= bus_req_i.data(15 downto 08);
pwm_ch(10) <= bus_req_i.data(23 downto 16);
pwm_ch(11) <= bus_req_i.data(31 downto 24);
end if;
-- read access --
else
case bus_req_i.addr(3 downto 2) is
when "00" => bus_rsp_o.data(ctrl_enable_c) <= enable; bus_rsp_o.data(ctrl_prsc2_bit_c downto ctrl_prsc0_bit_c) <= prsc;
when "01" => bus_rsp_o.data <= pwm_ch_rd(03) & pwm_ch_rd(02) & pwm_ch_rd(01) & pwm_ch_rd(00);
when "10" => bus_rsp_o.data <= pwm_ch_rd(07) & pwm_ch_rd(06) & pwm_ch_rd(05) & pwm_ch_rd(04);
when "11" => bus_rsp_o.data <= pwm_ch_rd(11) & pwm_ch_rd(10) & pwm_ch_rd(09) & pwm_ch_rd(08);
when others => bus_rsp_o.data <= (others => '0');
end case;
end if;
bus_rsp_o.data <= rdata_sum;
bus_rsp_o.ack <= '1';
else
bus_rsp_o.data <= (others => '0');
bus_rsp_o.ack <= '0';
end if;
bus_rsp_o.err <= '0'; -- no errors
end if;
end process bus_access;
-- duty cycle read-back --
pwm_dc_rd_gen: process(pwm_ch)
-- data read-back (large OR) --
read_back: process(rdata)
variable tmp_v : std_ulogic_vector(31 downto 0);
begin
pwm_ch_rd <= (others => (others => '0'));
for i in 0 to NUM_CHANNELS-1 loop -- only implement the actually configured number of channel register
pwm_ch_rd(i) <= pwm_ch(i);
tmp_v := (others => '0');
for i in 0 to NUM_CHANNELS-1 loop
tmp_v := tmp_v or rdata(i);
end loop;
end process pwm_dc_rd_gen;
rdata_sum <= tmp_v;
end process read_back;
-- Channel Controllers --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
pwm_channel_gen:
for i in 0 to NUM_CHANNELS-1 generate
neorv32_pwm_channel_inst: neorv32_pwm_channel
port map (
clk_i => clk_i,
rstn_i => rstn_i,
we_i => we(i),
re_i => re(i),
wdata_i => bus_req_i.data,
rdata_o => rdata(i),
clkgen_i => clkgen_i,
clkgen_en_o => ce(i),
pwm_o => pwm(i)
);
-- access enable --
sel(i) <= '1' when (bus_req_i.addr(5 downto 2) = std_ulogic_vector(to_unsigned(i, 4))) else '0';
we(i) <= sel(i) and bus_req_i.stb and ( bus_req_i.rw);
re(i) <= sel(i) and bus_req_i.stb and (not bus_req_i.rw);
end generate;
pwm_channel_connect: process(pwm)
begin
pwm_o <= (others => '0');
pwm_o(pwm'range) <= pwm(pwm'range);
end process pwm_channel_connect;
-- any clock requests? --
clkgen_en_o <= or_reduce_f(ce);
end neorv32_pwm_rtl;
-- ================================================================================ --
-- NEORV32 SoC - PWM - Channel Controller --
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
-- Licensed under the BSD-3-Clause license, see LICENSE for details. --
-- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ --
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library neorv32;
use neorv32.neorv32_package.all;
entity neorv32_pwm_channel is
port (
clk_i : in std_ulogic; -- global clock line
rstn_i : in std_ulogic; -- global reset line, low-active, async
we_i : in std_ulogic; -- write enable
re_i : in std_ulogic; -- read enable
wdata_i : in std_ulogic_vector(31 downto 0); -- write data
rdata_o : out std_ulogic_vector(31 downto 0); -- read data
clkgen_i : in std_ulogic_vector(7 downto 0); -- clock divider input
clkgen_en_o : out std_ulogic; -- enable clock generator
pwm_o : out std_ulogic -- PWM output
);
end neorv32_pwm_channel;
architecture neorv32_pwm_channel_rtl of neorv32_pwm_channel is
-- configuration register --
signal cfg_en : std_ulogic; -- channel enable
signal cfg_prsc : std_ulogic_vector(2 downto 0); -- (course) clock prescaler select
signal cfg_cdiv : std_ulogic_vector(9 downto 0); -- (fine) clock divider
signal cfg_duty : std_ulogic_vector(7 downto 0); -- duty cycle
-- pwm core --
signal cnt_cdiv : std_ulogic_vector(9 downto 0);
signal cnt_tick : std_ulogic;
signal cnt_duty : std_ulogic_vector(7 downto 0);
begin
-- Configuration --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
config_write: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
cfg_en <= '0';
cfg_prsc <= (others => '0');
cfg_cdiv <= (others => '0');
cfg_duty <= (others => '0');
elsif rising_edge(clk_i) then
if (we_i = '1') then
cfg_en <= wdata_i(31);
cfg_prsc <= wdata_i(30 downto 28);
cfg_cdiv <= wdata_i(17 downto 8);
cfg_duty <= wdata_i(7 downto 0);
end if;
end if;
end process config_write;
-- read access --
rdata_o <= cfg_en & cfg_prsc & "0000000000" & cfg_cdiv & cfg_duty when (re_i = '1') else (others => '0');
-- enable global clock generator --
clkgen_en_o <= cfg_en;
-- PWM Core -------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
pwm_core: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
pwm_cnt <= (others => '0');
pwm_o <= (others => '0');
cnt_cdiv <= (others => '0');
cnt_duty <= (others => '0');
pwm_o <= '0';
elsif rising_edge(clk_i) then
-- pwm base counter --
if (enable = '0') then
pwm_cnt <= (others => '0');
elsif (prsc_tick = '1') then
pwm_cnt <= std_ulogic_vector(unsigned(pwm_cnt) + 1);
end if;
-- channels --
pwm_o <= (others => '0');
for i in 0 to NUM_CHANNELS-1 loop
if (unsigned(pwm_cnt) >= unsigned(pwm_ch(i))) or (enable = '0') then
pwm_o(i) <= '0';
-- clock divider --
if (cfg_en = '0') then
cnt_cdiv <= (others => '0');
elsif (clkgen_i(to_integer(unsigned(cfg_prsc))) = '1') then -- pre-scaled clock (coarse)
if (cnt_tick = '1') then -- fine-tuned clock
cnt_cdiv <= (others => '0');
else
pwm_o(i) <= '1';
cnt_cdiv <= std_ulogic_vector(unsigned(cnt_cdiv) + 1);
end if;
end loop;
end if;
-- duty cycle counter --
if (cfg_en = '0') then
cnt_duty <= (others => '0');
elsif (cnt_tick = '1') then
cnt_duty <= std_ulogic_vector(unsigned(cnt_duty) + 1);
end if;
-- pwm output --
if (cfg_en = '0') or (unsigned(cnt_duty) >= unsigned(cfg_duty)) then
pwm_o <= '0';
else
pwm_o <= '1';
end if;
end if;
end process pwm_core;
-- PWM clock select --
clkgen_en_o <= enable; -- enable clock generator
prsc_tick <= clkgen_i(to_integer(unsigned(prsc)));
-- fine-tuned clock tick --
cnt_tick <= '1' when (cnt_cdiv = cfg_cdiv) else '0';
end neorv32_pwm_rtl;
end neorv32_pwm_channel_rtl;

View file

@ -122,7 +122,7 @@ entity neorv32_top is
IO_SDI_FIFO : natural range 1 to 2**15 := 1; -- RTX fifo depth, has to be zero or a power of two, min 1
IO_TWI_EN : boolean := false; -- implement two-wire interface (TWI)?
IO_TWI_FIFO : natural range 1 to 2**15 := 1; -- RTX fifo depth, has to be zero or a power of two, min 1
IO_PWM_NUM_CH : natural range 0 to 12 := 0; -- number of PWM channels to implement (0..12); 0 = disabled
IO_PWM_NUM_CH : natural range 0 to 16 := 0; -- number of PWM channels to implement (0..16)
IO_WDT_EN : boolean := false; -- implement watch dog timer (WDT)?
IO_TRNG_EN : boolean := false; -- implement true random number generator (TRNG)?
IO_TRNG_FIFO : natural range 1 to 2**15 := 1; -- data fifo depth, has to be a power of two, min 1
@ -220,7 +220,7 @@ entity neorv32_top is
onewire_o : out std_ulogic; -- 1-wire bus output (pull low only)
-- PWM (available if IO_PWM_NUM_CH > 0) --
pwm_o : out std_ulogic_vector(11 downto 0); -- pwm channels
pwm_o : out std_ulogic_vector(15 downto 0); -- pwm channels
-- Custom Functions Subsystem IO (available if IO_CFS_EN = true) --
cfs_in_i : in std_ulogic_vector(IO_CFS_IN_SIZE-1 downto 0) := (others => 'L'); -- custom CFS inputs conduit

View file

@ -25,7 +25,7 @@ entity neorv32_ProcessorTop_Minimal is
MEM_INT_DMEM_EN : boolean := true; -- implement processor-internal data memory
MEM_INT_DMEM_SIZE : natural := 64*1024; -- size of processor-internal data memory in bytes
-- Processor peripherals --
IO_PWM_NUM_CH : natural := 3 -- number of PWM channels to implement (0..12); 0 = disabled
IO_PWM_NUM_CH : natural := 3 -- number of PWM channels to implement (0..16)
);
port (
-- Global control --
@ -39,7 +39,7 @@ end entity;
architecture neorv32_ProcessorTop_Minimal_rtl of neorv32_ProcessorTop_Minimal is
-- internal IO connection --
signal con_pwm_o : std_ulogic_vector(11 downto 0);
signal con_pwm_o : std_ulogic_vector(15 downto 0);
begin

View file

@ -26,7 +26,7 @@ entity neorv32_ProcessorTop_MinimalBoot is
MEM_INT_DMEM_SIZE : natural := 64*1024; -- size of processor-internal data memory in bytes
-- Processor peripherals --
IO_GPIO_NUM : natural := 0; -- number of GPIO input/output pairs (0..64)
IO_PWM_NUM_CH : natural := 3 -- number of PWM channels to implement (0..12); 0 = disabled
IO_PWM_NUM_CH : natural := 3 -- number of PWM channels to implement (0..16)
);
port (
-- Global control --
@ -46,7 +46,7 @@ architecture neorv32_ProcessorTop_MinimalBoot_rtl of neorv32_ProcessorTop_Minima
-- internal IO connection --
signal con_gpio_o : std_ulogic_vector(63 downto 0);
signal con_pwm_o : std_ulogic_vector(11 downto 0);
signal con_pwm_o : std_ulogic_vector(15 downto 0);
begin

View file

@ -26,7 +26,7 @@ entity neorv32_ProcessorTop_UP5KDemo is
MEM_INT_DMEM_SIZE : natural := 64*1024; -- size of processor-internal data memory in bytes
-- Processor peripherals --
IO_GPIO_NUM : natural := 64; -- number of GPIO input/output pairs (0..64)
IO_PWM_NUM_CH : natural := 3 -- number of PWM channels to implement (0..12); 0 = disabled
IO_PWM_NUM_CH : natural := 3 -- number of PWM channels to implement (0..16)
);
port (
-- Global control --
@ -61,7 +61,7 @@ architecture neorv32_ProcessorTop_UP5KDemo_rtl of neorv32_ProcessorTop_UP5KDemo
-- internal IO connection --
signal con_gpio_o : std_ulogic_vector(63 downto 0);
signal con_gpio_i : std_ulogic_vector(63 downto 0);
signal con_pwm_o : std_ulogic_vector(11 downto 0);
signal con_pwm_o : std_ulogic_vector(15 downto 0);
signal con_spi_sck : std_ulogic;
signal con_spi_sdi : std_ulogic;
signal con_spi_sdo : std_ulogic;

View file

@ -114,7 +114,7 @@ entity neorv32_vivado_ip is
IO_TWI_EN : boolean := false;
IO_TWI_FIFO : natural range 1 to 2**15 := 1;
IO_PWM_EN : boolean := false;
IO_PWM_NUM_CH : natural range 1 to 12 := 1; -- variable-sized ports must be at least 0 downto 0; #974
IO_PWM_NUM_CH : natural range 1 to 16 := 1; -- variable-sized ports must be at least 0 downto 0; #974
IO_WDT_EN : boolean := false;
IO_TRNG_EN : boolean := false;
IO_TRNG_FIFO : natural range 1 to 2**15 := 1;
@ -274,7 +274,7 @@ architecture neorv32_vivado_ip_rtl of neorv32_vivado_ip is
-- constrained size ports --
signal gpio_o_aux : std_ulogic_vector(63 downto 0);
signal gpio_i_aux : std_ulogic_vector(63 downto 0);
signal pwm_o_aux : std_ulogic_vector(11 downto 0);
signal pwm_o_aux : std_ulogic_vector(15 downto 0);
signal xirq_i_aux : std_ulogic_vector(31 downto 0);
-- internal wishbone bus --

View file

@ -273,7 +273,7 @@ begin
IO_SDI_FIFO => 4, -- SDI RTX fifo depth, has to be zero or a power of two
IO_TWI_EN => true, -- implement two-wire interface (TWI)?
IO_TWI_FIFO => 4, -- RTX fifo depth, has to be zero or a power of two, min 1
IO_PWM_NUM_CH => 12, -- number of PWM channels to implement (0..12); 0 = disabled
IO_PWM_NUM_CH => 8, -- number of PWM channels to implement (0..16)
IO_WDT_EN => true, -- implement watch dog timer (WDT)?
IO_TRNG_EN => true, -- implement true random number generator (TRNG)?
IO_TRNG_FIFO => 4, -- TRNG fifo depth, has to be a power of two, min 1

View file

@ -249,7 +249,7 @@ begin
IO_SDI_FIFO => 4, -- SDI RTX fifo depth, has to be zero or a power of two
IO_TWI_EN => true, -- implement two-wire interface (TWI)?
IO_TWI_FIFO => 4, -- RTX fifo depth, has to be zero or a power of two, min 1
IO_PWM_NUM_CH => 12, -- number of PWM channels to implement (0..12); 0 = disabled
IO_PWM_NUM_CH => 8, -- number of PWM channels to implement (0..16)
IO_WDT_EN => true, -- implement watch dog timer (WDT)?
IO_TRNG_EN => true, -- implement true random number generator (TRNG)?
IO_TRNG_FIFO => 4, -- TRNG fifo depth, has to be a power of two, min 1

View file

@ -22,8 +22,8 @@
/**@{*/
/** UART BAUD rate */
#define BAUD_RATE 19200
/** Maximum PWM output intensity (8-bit) */
#define PWM_MAX 200
/** Maximum PWM output intensity (8-bit duty cycle) */
#define MAX_DUTY 200
/**@}*/
@ -61,49 +61,61 @@ int main() {
int num_pwm_channels = neorv32_pmw_get_num_channels();
// check number of PWM channels
// get number of implemented PWM channels
if (neorv32_uart0_available()) {
neorv32_uart0_printf("Implemented PWM channels: %i\n\n", num_pwm_channels);
}
// deactivate all PWM channels
// deactivate/clear all available channels
int i;
for (i=0; i<num_pwm_channels; i++) {
neorv32_pwm_set(i, 0);
neorv32_pwm_ch_disable(i);
neorv32_pwm_ch_set_clock(i, 0, 0);
neorv32_pwm_ch_set_duty(i, 0);
}
// configure and enable PWM
neorv32_pwm_setup(CLK_PRSC_64);
// configure all available channels
for (i=0; i<num_pwm_channels; i++) {
neorv32_pwm_ch_set_clock(i, CLK_PRSC_64, 0);
neorv32_pwm_ch_enable(i);
}
uint8_t pwm = 0;
uint8_t up = 1;
uint8_t ch = 0;
// simple animation: "pulse" channels one by one
neorv32_uart0_printf("Starting animation...\n");
// animate!
while(1) {
int dc = 0; // current duty cycle
int up = 1; // up/down (increase/decrease)
int ch = 0; // current channel
while (1) {
// update duty cycle
if (up) {
if (pwm == PWM_MAX) {
if (dc >= (int)(MAX_DUTY)) { // maximum intensity reached?
up = 0;
}
else {
pwm++;
dc++;
}
}
else {
if (pwm == 0) {
ch = (ch + 1) & 3; // goto next channel
if (dc == 0) {
// goto next channel
if ((ch + 1) >= num_pwm_channels) {
ch = 0;
}
else {
ch++;
}
up = 1;
}
else {
pwm--;
dc--;
}
}
neorv32_pwm_set(ch, pwm); // output new duty cycle
neorv32_cpu_delay_ms(3); // wait ~3ms
neorv32_pwm_ch_set_duty(ch, dc); // set new duty cycle for channel
neorv32_cpu_delay_ms(3); // wait ~3ms using busy-wait
}
return 0;

View file

@ -27,19 +27,22 @@
/**@{*/
/** PWM module prototype */
typedef volatile struct __attribute__((packed,aligned(4))) {
uint32_t CTRL; /**< offset 0: control register (#NEORV32_PWM_CTRL_enum) */
uint32_t DC[3]; /**< offset 4..12: duty cycle register 0..2 */
uint32_t CHANNEL_CFG[16]; /**< offset 0..64: channel configuration 0..15 (#CHANNEL_CFG_enum) */
} neorv32_pwm_t;
/** PWM module hardware access (#neorv32_pwm_t) */
#define NEORV32_PWM ((neorv32_pwm_t*) (NEORV32_PWM_BASE))
/** PWM control register bits */
enum NEORV32_PWM_CTRL_enum {
PWM_CTRL_EN = 0, /**< PWM control register(0) (r/w): PWM controller enable */
PWM_CTRL_PRSC0 = 1, /**< PWM control register(1) (r/w): Clock prescaler select bit 0 */
PWM_CTRL_PRSC1 = 2, /**< PWM control register(2) (r/w): Clock prescaler select bit 1 */
PWM_CTRL_PRSC2 = 3 /**< PWM control register(3) (r/w): Clock prescaler select bit 2 */
/** PWM channel configuration bits */
enum CHANNEL_CFG_enum {
PWM_CFG_DUTY_LSB = 0, /**< PWM configuration register(0) (r/w): Duty cycle (8-bit), LSB */
PWM_CFG_DUTY_MSB = 7, /**< PWM configuration register(7) (r/w): Duty cycle (8-bit), MSB */
PWM_CFG_CDIV_LSB = 8, /**< PWM configuration register(8) (r/w): Clock divider (10-bit), LSB */
PWM_CFG_CDIV_MSB = 17, /**< PWM configuration register(17) (r/w): Clock divider (10-bit), MSB */
PWM_CFG_PRSC_LSB = 28, /**< PWM configuration register(28) (r/w): Clock prescaler select (3-bit), LSB */
PWM_CFG_PRSC_MSB = 30, /**< PWM configuration register(30) (r/w): Clock prescaler select (3-bit), MSB */
PWM_CFG_EN = 31 /**< PWM configuration register(31) (r/w): channel enable */
};
/**@}*/
@ -48,13 +51,12 @@ enum NEORV32_PWM_CTRL_enum {
* @name Prototypes
**************************************************************************/
/**@{*/
int neorv32_pwm_available(void);
void neorv32_pwm_setup(int prsc);
void neorv32_pwm_disable(void);
void neorv32_pwm_enable(void);
int neorv32_pmw_get_num_channels(void);
void neorv32_pwm_set(int channel, uint8_t dc);
uint8_t neorv32_pwm_get(int channel);
int neorv32_pwm_available(void);
int neorv32_pmw_get_num_channels(void);
void neorv32_pwm_ch_enable(int channel);
void neorv32_pwm_ch_disable(int channel);
void neorv32_pwm_ch_set_clock(int channel, int prsc, int cdiv);
void neorv32_pwm_ch_set_duty(int channel, int duty);
/**@}*/
#endif // neorv32_pwm_h

View file

@ -12,7 +12,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -18,7 +18,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -13,7 +13,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -13,7 +13,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -13,7 +13,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -16,7 +16,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
#include <newlib.h>
#include <sys/stat.h>
#include <sys/timeb.h>

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**
@ -35,59 +35,19 @@ int neorv32_pwm_available(void) {
/**********************************************************************//**
* Enable and configure pulse width modulation controller.
* The PWM control register bits are listed in #NEORV32_PWM_CTRL_enum.
* Get number of implemented PWM channels.
* @warning This function will override all channel configuration registers.
*
* @param[in] prsc Clock prescaler select (0..7). See #NEORV32_CLOCK_PRSC_enum.
**************************************************************************/
void neorv32_pwm_setup(int prsc) {
NEORV32_PWM->CTRL = 0; // reset
uint32_t ct_enable = 1;
ct_enable = ct_enable << PWM_CTRL_EN;
uint32_t ct_prsc = (uint32_t)(prsc & 0x07);
ct_prsc = ct_prsc << PWM_CTRL_PRSC0;
NEORV32_PWM->CTRL = ct_enable | ct_prsc;
}
/**********************************************************************//**
* Disable pulse width modulation controller.
**************************************************************************/
void neorv32_pwm_disable(void) {
NEORV32_PWM->CTRL &= ~((uint32_t)(1 << PWM_CTRL_EN));
}
/**********************************************************************//**
* Enable pulse width modulation controller.
**************************************************************************/
void neorv32_pwm_enable(void) {
NEORV32_PWM->CTRL |= ((uint32_t)(1 << PWM_CTRL_EN));
}
/**********************************************************************//**
* Get number of implemented channels.
* @warning This function will override all duty cycle configuration registers.
*
* @return Number of implemented channels.
* @return Number of implemented PWM channels.
**************************************************************************/
int neorv32_pmw_get_num_channels(void) {
neorv32_pwm_disable();
int i = 0;
uint32_t cnt = 0;
for (i=0; i<12; i++) {
neorv32_pwm_set(i, 1);
cnt += neorv32_pwm_get(i);
for (i=0; i<16; i++) {
NEORV32_PWM->CHANNEL_CFG[i] = 1;
cnt += NEORV32_PWM->CHANNEL_CFG[i];
}
return (int)cnt;
@ -95,42 +55,62 @@ int neorv32_pmw_get_num_channels(void) {
/**********************************************************************//**
* Set duty cycle for channel.
* Enable PWM channel.
*
* @param[in] channel Channel select (0..11).
* @param[in] dc Duty cycle (8-bit, LSB-aligned).
* @param[in] channel Channel select (0..15).
**************************************************************************/
void neorv32_pwm_set(int channel, uint8_t dc) {
void neorv32_pwm_ch_enable(int channel) {
if (channel > 11) {
return; // out-of-range
}
channel &= 0xf; // constrain range
const uint32_t dc_mask = 0xff;
uint32_t dc_new = (uint32_t)dc;
uint32_t tmp = NEORV32_PWM->DC[channel/4];
tmp &= ~(dc_mask << ((channel % 4) * 8)); // clear previous duty cycle
tmp |= dc_new << ((channel % 4) * 8); // set new duty cycle
NEORV32_PWM->DC[channel/4] = tmp;
NEORV32_PWM->CHANNEL_CFG[channel] |= ((uint32_t)(1 << PWM_CFG_EN));
}
/**********************************************************************//**
* Get duty cycle from channel.
* Disable PWM channel.
*
* @param[in] channel Channel select (0..11).
* @return Duty cycle (8-bit, LSB-aligned) of channel 'channel'.
* @param[in] channel Channel select (0..15).
**************************************************************************/
uint8_t neorv32_pwm_get(int channel) {
void neorv32_pwm_ch_disable(int channel) {
if (channel > 11) {
return 0; // out of range
}
channel &= 0xf; // constrain range
uint32_t rd = NEORV32_PWM->DC[channel/4] >> (((channel % 4) * 8));
return (uint8_t)rd;
NEORV32_PWM->CHANNEL_CFG[channel] &= ~((uint32_t)(1 << PWM_CFG_EN));
}
/**********************************************************************//**
* Set PWM channel's clock configuration.
*
* @param[in] channel Channel select (0..15).
* @param[in] prsc Coarse clock prescaler select (3-bit, LSB-aligned). See #NEORV32_CLOCK_PRSC_enum.
* @param[in] cdiv Fine clock divider value (10-bit, LSB-aligned).
**************************************************************************/
void neorv32_pwm_ch_set_clock(int channel, int prsc, int cdiv) {
channel &= 0xf; // constrain range
uint32_t tmp = NEORV32_PWM->CHANNEL_CFG[channel];
tmp &= 0x800000ffU; // clear current prsc and cdiv, keep enable and duty
tmp |= ((uint32_t)(prsc & 0x7U)) << PWM_CFG_PRSC_LSB;
tmp |= ((uint32_t)(cdiv & 0x3ffU)) << PWM_CFG_CDIV_LSB;
NEORV32_PWM->CHANNEL_CFG[channel] = tmp;
}
/**********************************************************************//**
* Set PWM channel's duty cycle.
*
* @param[in] channel Channel select (0..15).
* @param[in] duty Duty cycle (8-bit, LSB-aligned).
**************************************************************************/
void neorv32_pwm_ch_set_duty(int channel, int duty) {
channel &= 0xf; // constrain range
uint32_t tmp = NEORV32_PWM->CHANNEL_CFG[channel];
tmp &= 0xffffff00U; // clear current duty cycle configuration
tmp |= (uint32_t)(duty & 0x000000ffU); // set new configuration
NEORV32_PWM->CHANNEL_CFG[channel] = tmp;
}

View file

@ -13,7 +13,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -13,7 +13,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -15,7 +15,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**

View file

@ -41,7 +41,7 @@
* @see https://stnolting.github.io/neorv32/sw/files.html
*/
#include "neorv32.h"
#include <neorv32.h>
/**********************************************************************//**