---
# System prepended metadata

title: 'SOC Spring Lab 4-0: report'

---

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





