# 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
```