<<<
:sectnums:
=== Custom Functions Unit (CFU)

The Custom Functions Unit (CFU) is a NEORV32-specific ISA extension (<<_xcfu_isa_extension, `Xcfu`>>)
providing a generic hardware module that can be used to implement **custom RISC-V instructions**.

.CFU vs. Other Customization Options
[NOTE]
The CFU is _not_ intended for complex and **CPU-independent** functional units that implement complete accelerators
(like full block-based AES encryption). These kind of accelerators should be implemented as stream- or memory-mapped
co-processor (e.g. <<_custom_functions_subsystem_cfs>>) to allow CPU-independent operation. A comparative survey of all
NEORV32-specific hardware extension/customization options is provided in the user guide section
https://stnolting.github.io/neorv32/ug/#_adding_custom_hardware_modules[Adding Custom Hardware Modules].

.Default CFU Hardware/Software Example
[TIP]
The default CFU module (`rtl/core/neorv32_cpu_alu_cfu.vhd`) implements the _Extended Tiny Encryption Algorithm (XTEA)_
as example application. The according demo program is located in `sw/example/demo_cfu`.


:sectnums:
==== CFU Instruction Formats

The CFU instructions can utilize a limited set of RISC-V OPCODES in `rv32` 32-bit instruction encoding space for
custom purpose. It is up to the designer to decide exactly what function these opcodes serve and what type of instruction
type/format they use. So far, four OPCODES are supported. Two of them ("custom-0" and "custom-1") have been explicitly
reserved by the RISC-V ISA spec. for user-defined extensions ("Guaranteed Non-Standard Encoding Space"). These should be
the first choice for implementing custom CFU instruction.

The other two OPCODES ("op-32" and "op-imm-32") are reserved by the RISC-V spec. for extended operations and future
ISA extensions. Note that the support/handling of the latter two OPCODES in NEORV32 might change in future.

.Available CFU OPCODES (defined in `sw/lib/include/neorv32_intrinsics.h`)
[source,c]
----
#define RISCV_OPCODE_CUSTOM0 0b0001011 // RISC-V "CUSTOM-0"
#define RISCV_OPCODE_CUSTOM1 0b0101011 // RISC-V "CUSTOM-1"
#define RISCV_OPCODE_OP32    0b0111011 // RISC-V "OP-32"
#define RISCV_OPCODE_OPIMM32 0b0011011 // RISC-V "OP-IMM-32"
----

.Default CFU Example
[TIP]
For the provided XTEA CFU example, the "custom-0" opcode is used to implement custom <<_risc_v_r_type_instructions>>
while the "custom-1" is used to implement custom <<_risc_v_i_type_instructions>>.


:sectnums:
===== RISC-V R-Type Instructions

The R-type instructions operate on two source registers `rs1` and `rs2` and return the processing result via
the destination register `rd`. The actual operation can be defined by using the `funct7` and `funct3` bit fields.
These immediates can also be used to pass additional data to the CFU like offsets, look-up-tables addresses or
shift-amounts. However, the actual functionality is entirely user-defined. Note that all immediate values are
always compile-time-static.

.R-Type Instruction Format
[wavedrom, format="png", align="center"]
----
{reg: [
  {bits: 7, name: 'opcode', type: 1},
  {bits: 5, name: 'rd'      },
  {bits: 3, name: 'funct3', type: 1},
  {bits: 5, name: 'rs1'     },
  {bits: 5, name: 'rs2'     },
  {bits: 7, name: 'funct7', type: 1}
]}
----


:sectnums:
===== RISC-V I-Type Instructions

The I-type instructions operate on one source registers `rs1` and a 12-bit immediate operand `im12` and return
the processing result via the destination register `rd`. The actual operation can be defined by using the `funct3`
bit field. Alternatively, this immediate can also be used to pass additional data to the CFU like offsets,
look-up-tables addresses or shift-amounts. However, the actual functionality is entirely user-defined. Note that
all immediate values are always compile-time-static.

.I-Type Instruction Format
[wavedrom, format="png", align="center"]
----
{reg: [
  {bits:  7, name: 'opcode', type: 1},
  {bits:  5, name: 'rd'      },
  {bits:  3, name: 'funct3', type: 1},
  {bits:  5, name: 'rs1'     },
  {bits: 12, name: 'imm12',  type: 1}
]}
----


:sectnums:
==== Using Custom Instructions in Software

The custom instructions provided by the CFU can be utilized in plain C-code using **intrinsics**. Intrinsics
behave like normal C-functions but under the hood they substitute a sequence of assembly instruction for the
original function call. For now, the NEORV32 software framework provides two pre-defined prototypes for custom
instructions:

.RISC-V Instruction Prototypes (simplified; defined in `sw/lib/include/neorv32_intrinsics.h`)
[source,c]
----
uint32_t RISCV_INSTR_R_TYPE(int opcode, int funct3, int funct7, uint32_t rs1, uint32_t rs2);
uint32_t RISCV_INSTR_I_TYPE(int opcode, int funct3, uint32_t rs1, int imm12);
----

These intrinsics always return a 32-bit value of type `uint32_t` (the processing result) which can be
discarded if not needed. The `funct3`, `funct7` and `im12` bit-fields are used to pass compile-time-static
literals to the CFU. The `rs1` and `rs2` arguments pass actual runtime data to the CFU via register addresses.
These register arguments can be populated with variables or literals; the compiler will add the required code
to move the data into a register before passing it to the CFU.

.CFU Instruction Examples
[source,c]
----
uint32_t foo = 12345;
uint32_t res = RISCV_INSTR_I_TYPE(RISCV_OPCODE_CUSTOM1, 0b001, foo, 0xABC);
res = RISCV_INSTR_R_TYPE(RISCV_OPCODE_CUSTOM0, 0b101, 0b1100110, res, foo);
----


:sectnums:
==== Custom Instructions Hardware

The CFU hardware module (`rtl/core/neorv32_cpu_alu_cfu.vhd`) is tightly integrated into to CPU and coupled as ALU
co-processor. A simple interface is used to communicate operands, operation definition and the processing result.

.CFU Interface
[cols="^2,^1,^1,<8"]
[options="header",grid="rows"]
|=======================
| Signal | Direction | Width | Description
4+^| **Global**
| `clk_i`    |  in |  1 | CPU clock, registers trigger on a rising-edge
| `rstn_i`   |  in |  1 | CPU reset, low-active, asynchronous
4+^| **Request**
| `start_i`  |  in |  1 | Trigger CFU operation; high for exactly one cycle
| `inst_i`   |  in | 32 | CFU instruction word
| `rs1_i`    |  in | 32 | Register operand 1 read from the CPU register file
| `rs2_i`    |  in | 32 | Register operand 2 read from the CPU register file
4+^| **Response**
| `result_o` | out |  1 | Processing result that is written to the destination register (`rd`)
| `valid_o`  | out | 32 | High for exactly one cycle when the CFU operation is done an `result` is valid
|=======================

CFU operations can be entirely combinatorial (e.g. for simple operation like bit-reversal) so the result is already
valid at the end of the current clock cycle. CFU operations can also take several clock cycles to complete (like an
iterative multiplications) and may also include internal states and memories. However, the CFU has to complete
its operation within a **bound time window** (default = 512 clock cycles). Otherwise, an illegal instruction
exception is raised. See section <<_cpu_arithmetic_logic_unit>> for more information.

.CFU Exception
[NOTE]
The CFU can intentionally raise an illegal instruction exception by not asserting the `valid` signal at all which
will cause an execution timeout. For example this can be used to signal invalid configurations/operations to the
runtime environment. See the documentation in the CFU's HDL source file for more information.

The following figure shows two timing sequences for CFU operations. The first one (orange) resembles a pure
combinatorial operation that completes within the same cycle in which it was triggered. The second (blue)
one performs a multi-cycle operation and is completed after several clock cycles.

.CFU Interface Timing Examples
[wavedrom, format="png", align="center"]
----
{signal: [
  {name: 'clk_i',    wave: 'p....|..'},
  {name: 'start_i',  wave: '01010|..', node: '.a.c'},
  {name: 'inst_i',   wave: 'x4x5.|.0'},
  {name: 'rs1_i',    wave: 'x4x5.|.x'},
  {name: 'rs2_i',    wave: 'x4x5.|.x'},
  {},
  {name: 'result_o', wave: 'x4x..|5x'},
  {name: 'valid_o',  wave: '010..|10', node: '.b....d'},
],
  edge: ['a~>b', 'c~>d']
}
----
