## Week-6 Questions
### Topic 1 : Caravel_hk_gpio_spi_mmio
#### Question : Explain the Caravel RISC-V firmware code update, and boot-up sequence
This is typically the **front-door onboard SPI** flash flow, which the **SPI interface** connected to the **padframe** through **MPRJ GPIO** pins.
**1. Using passthru-mode to update spiflash**

In **passthru mode**, external SPI signals are passed through **mprj io pins** to the **housekeeping**. This connects the SPI Flash to an external programmer, allowing firmware updates without CPU involvement.
**2. CPU code fetch from spi-flash**
On reset, the CPU fetches instructions directly from **SPI Flash** via **iBus**. This enables autonomous boot-up using the stored firmware.
---
#### Question: GPIO(MPRJ) can be used for management core or user-project, explain how to program mprj?

**1. What is the MMIO address to configure each MPRJ pin?**
`caravel-soc_fpga-main\firmware\caravel.h`
```C =
// User Project Control (0x2300_0000)
#define reg_mprj_xfer (*(volatile uint32_t*)0x26000000)
#define reg_mprj_pwr (*(volatile uint32_t*)0x26000004)
#define reg_mprj_irq (*(volatile uint32_t*)0x26100014)
#define reg_mprj_datal (*(volatile uint32_t*)0x2600000c)
#define reg_mprj_datah (*(volatile uint32_t*)0x26000010)
#define reg_mprj_io_0 (*(volatile uint32_t*)0x26000024)
#define reg_mprj_io_1 (*(volatile uint32_t*)0x26000028)
// ...
#define reg_mprj_io_36 (*(volatile uint32_t*)0x260000b4)
#define reg_mprj_io_37 (*(volatile uint32_t*)0x260000b8)
```
**2. Which bit is used to set the MPRJ used by the management core or the user**
This is controlled via **bit 0**, named `MGMT_ENABLE`:
```C=
#define MGMT_ENABLE 0x0001
```
* If **bit 0 = 1**, the GPIO is controlled by the **management core**
* If **bit 0 = 0**, the GPIO is controlled by the **user project**
**3. illustrate by code (reference the firmware code)**
In the firmware code `caravel-soc_fpga-main\testbench\counter_la\counter_la.c`, we configure each MPRJ GPIO pin to be either controlled by the management SoC or the user project using predefined macros:
```C=
// Management SoC
reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
// ...
reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;
// User project
reg_mprj_io_15 = GPIO_MODE_USER_STD_OUTPUT;
// ...
reg_mprj_io_0 = GPIO_MODE_USER_STD_OUTPUT;
// Apply the configuration
reg_mprj_xfer = 1;
while (reg_mprj_xfer == 1);
```
The macros like `GPIO_MODE_USER_STD_OUTPUT` are defined in `caravel-soc_fpga-main\rtl\header\user_defines.v` as:
```verilog=
`define GPIO_MODE_USER_STD_OUTPUT 13'h1808
`define GPIO_MODE_MGMT_STD_OUTPUT 13'h1809
```
These values determine whether the pin is driven by the **user project** or the **management core**, and its behavior (input/output...).
---
### Topic 2 : Caravel_intr_sram_wb_usrprj_firmware
#### Question : Explain the procedure/code to move code from spiflash to dff

To move program data from **SPI Flash** to **DFF (RAM)**, the boot process follows the logic defined in both the linker script and the startup assembly code.
**1. Entry Point & Startup Code**
In the linker file `sections.lds` , the entry point is defined as:
```ld=
ENTRY(_start)
```
So the boot process begins at the `_start` label in `crt0_vex.s`:
```.s=
_start:
j crt_init # Jump to the initialization routine
```
**2. Initialization**
In `crt0_vex.S`, copy `.data` section from Flash to RAM (DFF)
```.s=
data_init:
la a0, _fdata # RAM start of .data
la a1, _edata # RAM end of .data
la a2, _fdata_rom # Flash address where .data is stored
data_loop:
beq a0,a1,data_done
lw a3,0(a2) # Load data from Flash
sw a3,0(a0) # Store data to RAM
add a0,a0,4
add a2,a2,4
j data_loop
data_done:
```
This part transfers each 32-bit word from Flash (_fdata_rom) to RAM (_fdata~_edata).
**3. Memory mapping**
In `sections.lds`, the linker script do the memory mapping:
```.ld=
.data :
{
. = ALIGN(8);
_fdata = .;
*(.data .data.* .gnu.linkonce.d.*)
*(.data1)
_gp = ALIGN(16);
*(.sdata .sdata.* .gnu.linkonce.s.*)
. = ALIGN(8);
_edata = .;
} > dff AT > flash
PROVIDE(_fdata_rom = LOADADDR(.data));
```
* `.data` section is loaded into DFF at runtime, but its content is originally stored in Flash.
* `AT > flash` means the initial values are stored in flash.
* `PROVIDE(_fdata_rom = LOADADDR(.data));` gives the linker a symbol to access the flash address of `.data`.
---
#### Question : List the user project interface signals (ref: the user_project wrapper.v). What memory address is used to access the user project?

**1. User project interface signals**
From the `user_project_wrapper.v`, the following signals are user project interface signals:
(1) Wishbone Bus Interface
```verilog=
input wb_clk_i, // Clock
input wb_rst_i, // Reset
input wbs_stb_i, // Strobe
input wbs_cyc_i, // Cycle
input wbs_we_i, // Write enable
input [3:0] wbs_sel_i, // Byte enables
input [31:0] wbs_dat_i, // Write data
input [31:0] wbs_adr_i, // Address
output wbs_ack_o, // Acknowledge
output [31:0] wbs_dat_o // Read data
```
This is how the management SoC reads/writes registers inside the user project.
(2) Logic Analyzer Interface
```verilog=
input [127:0] la_data_in,
output [127:0] la_data_out,
input [127:0] la_oenb
```
Used for debugging or controlling internal signals from the testbench or firmware.
(3) IO Pads
```verilog=
input [`MPRJ_IO_PADS-1:0] io_in,
output [`MPRJ_IO_PADS-1:0] io_out,
output [`MPRJ_IO_PADS-1:0] io_oeb
```
Used for external communication (GPIO, UART, SPI...).
(4) Clock
```verilog=
input user_clock2
```
An user-defined clock.
(5) User Interrupts
```verilog=
output [2:0] user_irq
```
Interrupt signals sent from the user project to the management SoC.
**2. Address used to access the user project?**
From `section.lds`:
```verilog=
mprj : ORIGIN = 0x30000000, LENGTH = 0x00100000
```
The user project is memory-mapped to the address range: **0x3000_0000 ~ 0x300F_FFFF**
---
#### Question : Explain the counter_WB example, Verilog testbench, and firmware C code

**1. Memory Mapping and Address Decoding**
In `section.lds`, the mprj region is defined:
```.ld=
mprj : ORIGIN = 0x30000000, LENGTH = 0x00100000
```
This means that writing or reading from address `0x30000000` in firmware will access the `user_proj_example` via the Wishbone bus.
In firmware:
```c=
#define reg_mprj_slave (*(volatile uint32_t*)0x30000000)
```
`reg_mprj_slave` maps to the address `0x30000000`.
**2. Firmware C Code : counter_wb.c**
In `counter_wb.c`
```C=
reg_mprj_slave = 0x00002710; // Write to counter
if (reg_mprj_slave == 0x2B3D) // Read counter value
```
* Write operation(`wbs_we_i = 1`) : The value is sent via `wbs_dat_i`
* Read operation (`wbs_we_i = 0`): The result is received via `wbs_dat_o`
The Wishbone interface selects between input (`wbs_dat_i`) and output (`wbs_dat_o`) depending on whether it's a write (`sw`) or read (`lw`) operation.
| Operation | `wbs_we_i` | Data Path |
| --------- | ---------- | --------------------------- |
| Write | `1` | CPU → `wbs_dat_i` → counter |
| Read | `0` | counter → `wbs_dat_o` → CPU |
**3. RTL code : user_proj_example.v**
```verilog=
assign wbs_dat_o = rdata;
assign wdata = wbs_dat_i;
```
* Data from CPU (`wbs_dat_i`) is forwarded to the internal counter.
* Output from the counter (`rdata`) is sent via `wbs_dat_o`.
---
### Topic 3 : Caravel soc - lab4-0
#### Observe Caravel SoC simulation, show waveforms with related signals

Reference to [Lab4-0 Caravel Simulation](https://hackmd.io/LwFmZAwjTfy8uPvenTmelQ)