---
# System prepended metadata

title: Week 6- Questions

---

## 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**
![image](https://hackmd.io/_uploads/SyeIxatxZlg.png)
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?
![image](https://hackmd.io/_uploads/r1I4wjpmxg.png)
**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 
![image](https://hackmd.io/_uploads/By6uJB1-lg.png)

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?
![image](https://hackmd.io/_uploads/H175kBJble.png)

**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
![image](https://hackmd.io/_uploads/HkFskry-gx.png)

**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
![image](https://hackmd.io/_uploads/S1Mi3wtmel.png)

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