# SOC Spring Lab 4-0: report ## 1. spiflash access & code execution (observe CPU trace ) ### i. Show waveform with related signals. ![Screenshot from 2025-04-03 05-29-22](https://hackmd.io/_uploads/By0QH0sTkl.png) ### ii. Correspond the waveform with the firmware code and testbench code. ```= @00000000 6F 00 00 0B 13 00 00 00 13 00 00 00 13 00 00 00 13 00 00 00 13 00 00 00 13 00 00 00 13 00 00 00 23 2E 11 FE 23 2C 51 FE 23 2A 61 FE 23 28 71 FE ``` Observe the firmware code, we can found the machine code of first instruction is `0B 00 00 6F`. The caravel soc will fetch the instruction in the `spi-flash` from the lower address to higher address. The first 8-bit fetch from spi-flash will be `8'h6F = 8'b0110_1111`. You can observe the `io1(SPI MISO)` signal to find the corresponding waveform. From `spi_addr = 0004~0007` the caravel fetch `6F 00 00 0B` from spi-flash. After the instruction fetch from `spi-flash`, the instruction will go through `CPU iBus` as following waveform. ![Screenshot from 2025-04-03 09-25-55](https://hackmd.io/_uploads/rJiY3-26yl.png) >instruction fetch `0B 00 00 6F` in iBus. ## 2. cpu wb cycles interaction with user project area. ### i. Show waveform with related signals. ![Screenshot from 2025-04-04 04-37-17](https://hackmd.io/_uploads/rJlD5GaT1g.png) ### ii. Correspond the waveform with the firmware code and testbench code. Refer to the waveform, it execute nine instruction as following: ```assembly= #machine code|instruction |explanation 0x02C78793 addi a5, a5, 44 #get address 0x0007A703 lw a4, 0(a5) #a4 = a5 = reg_la0_data_in 0x1F400793 addi a5, zero, 500 #a5 = 500 0xFEE7F8E3 bgeu a5, a4, -2 #if (500 >= reg_la0_data_in) 0x260007B7 lui a5, 0x26000 #a5 = 0x26000_500 0x00C78793 addi a5, a5, 12 #a5 = 0x26000_00C 0xAB410737 lui a4, 0xAB410 #a4 = 0xAB410000 0x00E7A023 sw a4, 0(a5) #a5 = a4 0x00000013 addi x0, x0, 0 #nop ``` ## 3. cpu interface with user project with la ### i. Show waveform with related signals. ![Screenshot from 2025-04-03 10-26-51](https://hackmd.io/_uploads/S1uyjMh61e.png) ### ii. Correspond the waveform with the firmware code and testbench code. From `user_proj_example.counter.v`, we can found that when `la_write == 1(la_oenb[63:32] == 32'hFFFF_FFFF)`, `count` is written by `la_data_in[63:32]`. #### user_proj_example.counter.v ```verilog= //...order code 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; // IO assign io_out = count; assign io_oeb = {(`MPRJ_IO_PADS-1){rst}}; // IRQ assign irq = 3'b000; // Unused // LA assign la_data_out = {{(127-BITS){1'b0}}, count}; // Assuming LA probes [63:32] are for controlling the count register assign la_write = ~la_oenb[63:32] & ~{BITS{valid}}; // Assuming LA probes [65:64] are for controlling the count clk & reset assign clk = (~la_oenb[64]) ? la_data_in[64]: wb_clk_i; assign rst = (~la_oenb[65]) ? la_data_in[65]: wb_rst_i; counter #( .BITS(BITS) ) counter( .clk(clk), .reset(rst), .ready(wbs_ack_o), .valid(valid), .rdata(rdata), .wdata(wbs_dat_i), .wstrb(wstrb), .la_write(la_write), .la_input(la_data_in[63:32]), //view the counter_la.c(firmware) define la[63:32] as output from CPU .count(count) ); endmodule 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; if (~|la_write) begin count <= count + 1; end 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]; end else if (|la_write) begin count <= la_write & la_input; end end end endmodule `default_nettype wire ``` ## 4. User project/RISC-V uses mprj pin, and interacts with Testbench ### i. Show waveform with related signals. ![Screenshot from 2025-04-03 12-20-22](https://hackmd.io/_uploads/S1KKrE2TJl.png) ### ii. Correspond the waveform with the firmware code and testbench code. The `mprj_io[31:16]` pins is program by CPU. CPU program these GPIO through `dBus(Wishbone Bus)`, as shown in firmware code. How would CPU program `mprj` depends on the value of counter `count`. It would transmit to CPU throgh `Logic analyzer(reg_la0_data_in)`. The value of these `mpjr` pins will determine the flow testbench. #### counter_la.c(firmware) ```c= // This include is relative to $CARAVEL_PATH (see Makefile) #include <defs.h> #include <stub.c> // -------------------------------------------------------- /* MPRJ Logic Analyzer Test: - Observes counter value through LA probes [31:0] - Sets counter initial value through LA probes [63:32] - Flags when counter value exceeds 500 through the management SoC gpio - Outputs message to the UART when the test concludes successfuly */ void main() { int j; //Set mprj pin to management soc 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; //Set mprj pin to User project area reg_mprj_io_15 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_14 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_13 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_12 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_11 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_10 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_9 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_8 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_7 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_5 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_4 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_3 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_2 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_1 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_0 = GPIO_MODE_USER_STD_OUTPUT; reg_mprj_io_6 = GPIO_MODE_MGMT_STD_OUTPUT; // Set UART clock to 64 kbaud (enable before I/O configuration) // reg_uart_clkdiv = 625; reg_uart_enable = 1; // Now, apply the configuration reg_mprj_xfer = 1; while (reg_mprj_xfer == 1); // Configure LA probes [31:0], [127:64] as inputs to the cpu // Configure LA probes [63:32] as outputs from the cpu reg_la0_oenb = reg_la0_iena = 0x00000000; // [31:0] reg_la1_oenb = reg_la1_iena = 0xFFFFFFFF; // [63:32] reg_la2_oenb = reg_la2_iena = 0x00000000; // [95:64] reg_la3_oenb = reg_la3_iena = 0x00000000; // [127:96] // Flag start of the test reg_mprj_datal = 0xAB400000; // Set Counter value to zero through LA probes [63:32] reg_la1_data = 0x00000000; // Configure LA probes from [63:32] as inputs to disable counter write reg_la1_oenb = reg_la1_iena = 0x00000000; while (1) { if (reg_la0_data_in > 0x1F4) { reg_mprj_datal = 0xAB410000; break; } } //print("\n"); //print("Monitor: Test 1 Passed\n\n"); // Makes simulation very long! reg_mprj_datal = 0xAB510000; } ``` ```c= #define reg_mprj_datal (*(volatile uint32_t*)0x2600000c) #define reg_mprj_datah (*(volatile uint32_t*)0x26000010) ``` >caravel.h `reg_mprj_datal` used to write `mprj_io[31:0]`. `reg_mprj_datah` used to write `mprj_io[37:32]`. so that these `mprj_io` pin have value. ```c= #define reg_la3_data_in (*(volatile uint32_t*) CSR_LA_IN_ADDR) #define reg_la2_data_in (*(volatile uint32_t*) (CSR_LA_IN_ADDR + 4)) #define reg_la1_data_in (*(volatile uint32_t*) (CSR_LA_IN_ADDR + 8)) #define reg_la0_data_in (*(volatile uint32_t*) (CSR_LA_IN_ADDR + 12)) ``` >firmware/defs.h >There is four 32-bit MMIO register, corresponding to 128-bit input of LA. >**Question:** It seems unclear how the logic analyzer (LA) is connected to the counter—I couldn’t find the definition? ```verilog= //...order code initial begin wait(checkbits == 16'hAB40); $display("LA Test 1 started"); wait(checkbits == 16'hAB41); wait(checkbits == 16'hAB51); $display("LA Test 2 passed"); #10000; $finish; end ``` >tb.v >The value of `mprj[31:16] = checkbits` will affect testbench execution flow.