---
# System prepended metadata

title: SoC Laboratory Assignment W6
tags: [Assignment, SoC Laboratory]

---

# SoC Laboratory Assignment W6

> [TOC]

## HK_GPIO_SPI_MMIO

#### a) Explain the Caravel RISC-V firmware code update, and boot-up sequence. It involves
1. Using passthru-mode to update spiflash
(1) MPRJ\[1-4\] first sends pass through mode command to SPI
(2) SPI-flash then selects MPRJ\[1-4\]

2. CPU code fetch from spi-flash
CPU accesses instruction from 0x26000000. 

---

#### b) 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
`0x2600_0000`
2. Which bit is used to set the MPRJ used by the management core or the user
bit `0`
3. illustrate by code  (reference the firmware code)
* MMIO address
```
// firmware/caravel.h
// Line 25-75

#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_2 (*(volatile uint32_t*)0x2600002c)
#define reg_mprj_io_3 (*(volatile uint32_t*)0x26000030)
#define reg_mprj_io_4 (*(volatile uint32_t*)0x26000034)
#define reg_mprj_io_5 (*(volatile uint32_t*)0x26000038)
#define reg_mprj_io_6 (*(volatile uint32_t*)0x2600003c)

#define reg_mprj_io_7 (*(volatile uint32_t*)0x26000040)
#define reg_mprj_io_8 (*(volatile uint32_t*)0x26000044)
#define reg_mprj_io_9 (*(volatile uint32_t*)0x26000048)
#define reg_mprj_io_10 (*(volatile uint32_t*)0x2600004c)

#define reg_mprj_io_11 (*(volatile uint32_t*)0x26000050)
#define reg_mprj_io_12 (*(volatile uint32_t*)0x26000054)
#define reg_mprj_io_13 (*(volatile uint32_t*)0x26000058)
#define reg_mprj_io_14 (*(volatile uint32_t*)0x2600005c)

#define reg_mprj_io_15 (*(volatile uint32_t*)0x26000060)
#define reg_mprj_io_16 (*(volatile uint32_t*)0x26000064)
#define reg_mprj_io_17 (*(volatile uint32_t*)0x26000068)
#define reg_mprj_io_18 (*(volatile uint32_t*)0x2600006c)

#define reg_mprj_io_19 (*(volatile uint32_t*)0x26000070)
#define reg_mprj_io_20 (*(volatile uint32_t*)0x26000074)
#define reg_mprj_io_21 (*(volatile uint32_t*)0x26000078)
#define reg_mprj_io_22 (*(volatile uint32_t*)0x2600007c)

#define reg_mprj_io_23 (*(volatile uint32_t*)0x26000080)
#define reg_mprj_io_24 (*(volatile uint32_t*)0x26000084)
#define reg_mprj_io_25 (*(volatile uint32_t*)0x26000088)
#define reg_mprj_io_26 (*(volatile uint32_t*)0x2600008c)

#define reg_mprj_io_27 (*(volatile uint32_t*)0x26000090)
#define reg_mprj_io_28 (*(volatile uint32_t*)0x26000094)
#define reg_mprj_io_29 (*(volatile uint32_t*)0x26000098)
#define reg_mprj_io_30 (*(volatile uint32_t*)0x2600009c)
#define reg_mprj_io_31 (*(volatile uint32_t*)0x260000a0)

#define reg_mprj_io_32 (*(volatile uint32_t*)0x260000a4)
#define reg_mprj_io_33 (*(volatile uint32_t*)0x260000a8)
#define reg_mprj_io_34 (*(volatile uint32_t*)0x260000ac)
#define reg_mprj_io_35 (*(volatile uint32_t*)0x260000b0)
#define reg_mprj_io_36 (*(volatile uint32_t*)0x260000b4)
#define reg_mprj_io_37 (*(volatile uint32_t*)0x260000b8)
```

* Management control enable
```
// firmware/caravel.h 
// Line 113

#define MGMT_ENABLE	  0x0001
```
---

## INTR_SRAM_WB_USRPRJ_Firmware

#### c) Explain the procedure/code to move code from spiflash to DFF

The fisrt part of the code `data_init` is moving the global variable from SPI flash to DFF. `a0` address of flash and `a3` is the address of DFF.

The second part `bss_init` is allocating space for unitialized global values.

```
// firmware crt0_vex.S

data_init:
  la a0, _fdata
  la a1, _edata
  la a2, _fdata_rom
data_loop:
  beq a0,a1,data_done
  lw a3,0(a2)
  sw a3,0(a0)
  add a0,a0,4
  add a2,a2,4
  j data_loop
data_done:

bss_init:
  la a0, _fbss
  la a1, _ebss
bss_loop:
  beq a0,a1,bss_done
  sw zero,0(a0)
  add a0,a0,4
#ifndef SIM
  j bss_loop
#endif
bss_done:
```

---

#### d) List the user project interface signals (ref: the user_project wrapper.v). What memory address is used to access the user project?

User project interface signals:
* Wishbone
```
input wb_clk_i,
input wb_rst_i,
input wbs_stb_i,
input wbs_cyc_i,
input wbs_we_i,
input [3:0] wbs_sel_i,
input [31:0] wbs_dat_i,
input [31:0] wbs_adr_i,
output wbs_ack_o,
output [31:0] wbs_dat_o,
```

* Logic Analyzer
```
input  [127:0] la_data_in,
output [127:0] la_data_out,
input  [127:0] la_oenb,
```

* GPIO
```
input  [`MPRJ_IO_PADS-1:0] io_in,
output [`MPRJ_IO_PADS-1:0] io_out,
output [`MPRJ_IO_PADS-1:0] io_oeb,
inout [`MPRJ_IO_PADS-10:0] analog_io,
```

* Clock
```
input   user_clock2,
```

* Interrupt
```
output [2:0] user_irq
```

According to memory mapping, the memory address for user project:
* `mprj`: `0x3000_0000` to `0x300F_FFFF`
* `mprjram`: `0x3800_0000` to `0x303F_FFFF`

```
MEMORY {
	vexriscv_debug : ORIGIN = 0xf00f0000, LENGTH = 0x00000100
	dff : ORIGIN = 0x00000000, LENGTH = 0x00000400
	dff2 : ORIGIN = 0x00000400, LENGTH = 0x00000200
	flash : ORIGIN = 0x10000000, LENGTH = 0x01000000
	mprj : ORIGIN = 0x30000000, LENGTH = 0x00100000
	mprjram : ORIGIN = 0x38000000, LENGTH = 0x00400000
	hk : ORIGIN = 0x26000000, LENGTH = 0x00100000
	csr : ORIGIN = 0xf0000000, LENGTH = 0x00010000
}
```

---

#### e) Explain the counter_WB example, Verilog testbench, and firmware C code.

* counter_WB_example
```
// ...

// Wishbone
assign valid = wbs_cyc_i && wbs_stb_i; 
assign wstrb = wbs_sel_i & {4{wbs_we_i}};
assign wbs_dat_o = rdata;
assign wdata = wbs_dat_i;

// LA
assign la_data_out = {{(127-BITS){1'b0}}, count};
// LA [63:32]: set counter
assign la_write = ~la_oenb[63:32] & ~{BITS{valid}};
// LA[64]: clk, LA[65]: rst
assign clk = (~la_oenb[64]) ? la_data_in[64]: wb_clk_i;
assign rst = (~la_oenb[65]) ? la_data_in[65]: wb_rst_i;

// ...

module counter #(
    parameter BITS = 32
)(
    input clk,
    input reset,
    input valid,
    input [3:0] wstrb,
    input [BITS-1:0] wdata,
    input [BITS-1:0] la_write,
    input [BITS-1:0] la_input,
    output reg ready,
    output reg [BITS-1:0] rdata,
    output reg [BITS-1:0] count
);
    //reg ready;
    //reg [BITS-1:0] count;
    //reg [BITS-1:0] rdata;

    always @(posedge clk) begin
        if (reset) begin
            count <= 0;
            ready <= 0;
        end else begin
            ready <= 1'b0;
            // Count
            if (~|la_write) begin
                count <= count + 1;
            end
            // Wishbone read & write
            if (valid && !ready) begin
                ready <= 1'b1;
                rdata <= count;
                if (wstrb[0]) count[7:0]   <= wdata[7:0];
                if (wstrb[1]) count[15:8]  <= wdata[15:8];
                if (wstrb[2]) count[23:16] <= wdata[23:16];
                if (wstrb[3]) count[31:24] <= wdata[31:24];
            // LA write
            end else if (|la_write) begin
                count <= la_write & la_input;
            end
        end
    end
endmodule
```

* C code
```
// Configuration

reg_spi_enable = 1;
reg_wb_enable = 1;

reg_mprj_io_31 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_30 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_29 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_28 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_27 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_26 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_25 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_24 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_23 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_22 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_21 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_20 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_19 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_18 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_17 = GPIO_MODE_MGMT_STD_OUTPUT;
reg_mprj_io_16 = GPIO_MODE_MGMT_STD_OUTPUT;

// Apply configuration

reg_mprj_xfer = 1;
while (reg_mprj_xfer == 1);

reg_la2_oenb = reg_la2_iena = 0x00000000;

// Start of the test
reg_mprj_datal = 0xAB600000;

// set conter value
reg_mprj_slave = 0x00002710;

// keep counting
while (1) {
    // if count to 0x2B30, stop the counter
    if (reg_mprj_slave == 0x2B3D) {
        reg_mprj_datal = 0xAB610000;
        break;
    }
}
```

* Testbench
Only check the start and end flags. If timeout, report the error.
```
initial begin
    wait(checkbits == 16'hAB60);
    $display("Monitor: MPRJ-Logic WB Started");
    wait(checkbits == 16'hAB61);
    `ifdef GL
        $display("Monitor: Mega-Project WB (GL) Passed");
    `else
        $display("Monitor: Mega-Project WB (RTL) Passed");
    `endif
    $finish;
end
```

