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