# Caravel soc - storage
###### tags: `caravel`
https://github.com/bol-edu/caravel-soc
## SRAM

```verilog=
// Housekeeping
`ifdef USE_SRAM_RO_INTERFACE
output sram_ro_clk,
output sram_ro_csb,
output [7:0] sram_ro_addr,
input [31:0] sram_ro_data,
`endif
```
https://github.com/bol-edu/caravel-soc/blob/main/rtl/soc/housekeeping.v#L218
The 4 signals are not wired.
## RAM
### RAM128/256
```verilog=
module RAM128 #( parameter COLS=1)
localparam A_WIDTH = 7+$clog2(COLS);
input wire [(A_WIDTH - 1): 0] A0;
reg [31:0] RAM[(256*COLS)-1 : 0];
always @(posedge CLK)
if(EN0) begin
Do0 <= RAM[A0];
if(WE0[0]) RAM[A0][ 7: 0] <= Di0[7:0];
if(WE0[1]) RAM[A0][15:8] <= Di0[15:8];
if(WE0[2]) RAM[A0][23:16] <= Di0[23:16];
if(WE0[3]) RAM[A0][31:24] <= Di0[31:24];
end
else
Do0 <= 32'b0;
endmodule
module RAM256 #( parameter COLS=1)
localparam A_WIDTH = 8+$clog2(COLS);
input wire [(A_WIDTH - 1): 0] A0;
reg [31:0] RAM[(256*COLS)-1 : 0];
always @(posedge CLK)
if(EN0) begin
Do0 <= RAM[A0];
if(WE0[0]) RAM[A0][ 7: 0] <= Di0[7:0];
if(WE0[1]) RAM[A0][15:8] <= Di0[15:8];
if(WE0[2]) RAM[A0][23:16] <= Di0[23:16];
if(WE0[3]) RAM[A0][31:24] <= Di0[31:24];
end
else
Do0 <= 32'b0;
endmodule
```
https://github.com/bol-edu/caravel-soc/blob/main/vip/RAM128.v
https://github.com/bol-edu/caravel-soc/blob/main/vip/RAM256.v
The only difference is address width.
### Usage
```verilog=
RAM256 RAM256(
.A0(dff_bus_adr[7:0]),
.CLK(sys_clk),
.Di0(dff_di),
.EN0(dff_en),
.WE0(dff_we),
.Do0(dff_do)
);
RAM128 RAM128(
.A0(dff2_bus_adr[6:0]),
.CLK(sys_clk),
.Di0(dff2_di),
.EN0(dff2_en),
.WE0(dff2_we),
.Do0(dff2_do)
);
```
https://github.com/bol-edu/caravel-soc/blob/main/rtl/soc/mgmt_core.v#L8374
```
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
hk : ORIGIN = 0x26000000, LENGTH = 0x00100000
csr : ORIGIN = 0xf0000000, LENGTH = 0x00010000
}
// dff => RAM256
// dff2 => RAM128
```
https://github.com/bol-edu/caravel-soc/blob/main/firmware/sections.lds#L11
### Slave select
```verilog=
wire [29:0] shared_adr; // Shift left 2 bit from 32 bits address
always @(*) begin
slave_sel = 7'd0;
slave_sel[0] = (shared_adr[29:6] == 24'd15732480);
slave_sel[1] = (shared_adr[29:8] == 1'd0);
slave_sel[2] = (shared_adr[29:7] == 2'd2);
slave_sel[3] = (shared_adr[29:22] == 5'd16);
slave_sel[4] = (shared_adr[29:26] == 2'd3);
slave_sel[5] = (shared_adr[29:20] == 8'd152);
// 641440 << 2 = 0x3c000
// 0x3c000 << 14 = 0xf0000000
slave_sel[6] = (shared_adr[29:14] == 16'd61440);
end
assign mgmtsoc_vexriscv_debug_bus_cyc = (shared_cyc & slave_sel[0]);
assign dff_bus_cyc = (shared_cyc & slave_sel[1]);
assign dff2_bus_cyc = (shared_cyc & slave_sel[2]);
assign mgmtsoc_litespimmap_bus_cyc = (shared_cyc & slave_sel[3]);
assign mprj_cyc = (shared_cyc & slave_sel[4]);
assign hk_cyc = (shared_cyc & slave_sel[5]);
assign mgmtsoc_wishbone_cyc = (shared_cyc & slave_sel[6]);
```
https://github.com/bol-edu/caravel-soc/blob/main/rtl/soc/mgmt_core.v#L4827
https://github.com/bol-edu/caravel-soc/blob/main/rtl/soc/mgmt_core.v#L4886
### Test
```cpp=
int a, b;
int main (int argc, char **argv)
{
a = 0x1234;
b = (int)&a;
int c = 0x5566;
int d = (int)&c;
return 0;
}
```
```
MEMORY {
dff : ORIGIN = 0x00000000, LENGTH = 0x00000400
dff2 : ORIGIN = 0x00000400, LENGTH = 0x00000200
}
SECTIONS
{
.bss :
{
} > dff
}
PROVIDE(_fstack = ORIGIN(dff2) + LENGTH(dff2));
```
https://github.com/bol-edu/caravel-soc/blob/main/firmware/sections.lds#L58
Expect global variables(`a, b`) locate in `dff` region and local variables(`c`,`d`) locate near top of stack(`dff2`).


| | Firmware | Hardware |
| -------| -------- | -------- |
| &a | 0x0004 | 0x01(ram256)|
| &b | 0x0008 | 0x02(ram256)|
| &c | 0x05e8 | 0x7a(ram128)|
| &d | 0x05ec | 0x7b(ram128)|
0x7a = (0x5e8 - 0x400) / 0x04;
## Flash

### Simulator
* [PicoSoC](https://github.com/bol-edu/caravel-soc/blob/main/vip/spiflash.v#L5) - A simple example SoC using PicoRV32
* Cypress S25FL064L
* 128 Mbits
* No write protect or reset pin
#### Supported Commands
| Function | Hex |
| -------| --------|
| Release from Deep Power down | AB |
| Deep Power-down | B9 |
| Mode Bit Reset | FF |
| Read | 03 |
| Dual I/O Read | BB |
| Quad I/O Read | EB |
| DDR Quad I/O Read | ED |
The only command we used is `Read`.
[The SPI protocol does not specify whether the most-significant bit (MSb) or least-significant bit (LSb) is transmitted or received first during an SPI transfer.](http://quanser-update.azurewebsites.net/quarc/documentation/spi_protocol.html#:~:text=The%20SPI%20protocol%20does%20not,order%20of%20the%20SPI%20transfer.)


#### Dummy cycle
* Only for daul/quad read, single read and write do not need dummy cycle
* Can be configured in
* flash(CR3NV/CR3V register)
* [flash simulator](https://github.com/bol-edu/caravel-soc/blob/main/vip/spiflash.v#L51)
* flash controller
* https://github.com/bol-edu/caravel-soc/blob/main/firmware/csr.h#L102
* https://github.com/bol-edu/caravel-soc/blob/main/rtl/soc/mgmt_core.v#L4997
* [Document is wrong](https://caravel-harness.readthedocs.io/en/latest/qspi-flash.html#reg-spictrl-access-mode-values)
#### Implementation
```verilog=
always @(posedge clk) begin
if (!csb) begin
case (mode)
mode_spi: begin
buffer = {buffer, io0};
bitcount = bitcount + 1;
if (bitcount == 8) begin
bitcount = 0;
bytecount = bytecount + 1;
spi_action;
end
end
endcase
end
end
if (powered_up && spi_cmd == 'h 03) begin
if (bytecount == 2)
spi_addr[23:16] = buffer;
if (bytecount == 3)
spi_addr[15:8] = buffer;
if (bytecount == 4)
spi_addr[7:0] = buffer;
if (bytecount >= 4) begin
buffer = memory[spi_addr];
spi_addr = spi_addr + 1;
end
end
```
https://github.com/bol-edu/caravel-soc/blob/main/vip/spiflash.v#L405
https://github.com/bol-edu/caravel-soc/blob/main/vip/spiflash.v#L121
### Controller
#### Data & length
```verilog=
mgmtsoc_litespimmap_source_payload_data = 32'd0;
case (litespi_state)
1'd1: begin
mgmtsoc_litespimmap_source_payload_data = 2'd3; // Read command
end
2'd3: begin
mgmtsoc_litespimmap_source_payload_data = {mgmtsoc_litespimmap_bus_adr, mgmtsoc_litespimmap}; // shared_addr << 2
end
3'd4: begin
end
3'd5: begin
mgmtsoc_litespimmap_source_payload_data = mgmtsoc_litespimmap_dummy;
end
default: begin
end
endcase
// ...
mgmtsoc_litespimmap_source_payload_len = 6'd0;
case (litespi_state)
1'd1: begin
mgmtsoc_litespimmap_source_payload_len = 4'd8; // Cmd length
end
2'd3: begin
mgmtsoc_litespimmap_source_payload_len = 5'd24; // Address length
end
3'd5: begin
mgmtsoc_litespimmap_source_payload_len = mgmtsoc_litespimmap_spi_dummy_bits;
end
3'd7: begin
mgmtsoc_litespimmap_source_payload_len = 6'd32; // Data length
end
default: begin
end
endcase
```
https://github.com/bol-edu/caravel-soc/blob/main/rtl/soc/mgmt_core.v#L2608
#### Data source selected
Just like Wishbone, spi out to padframe has different source.
```=verilog
assign litespi_request = {mgmtsoc_port_master_request, mgmtsoc_port_mmap_request};
// ...
case (litespi_grant)
1'd0: begin
if ((~litespi_request[0])) begin
if (litespi_request[1]) begin
litespi_grant <= 1'd1;
end
end
end
1'd1: begin
if ((~litespi_request[1])) begin
if (litespi_request[0]) begin
litespi_grant <= 1'd0;
end
end
end
endcase
// ...
assign litespi_tx_mux_sel = litespi_grant;
// ...
always @(*) begin
litespi_tx_mux_source_payload_data = 32'd0;
case (litespi_tx_mux_sel)
1'd0: begin
litespi_tx_mux_source_payload_data = litespi_tx_mux_endpoint0_sink_payload_data;
end
1'd1: begin
litespi_tx_mux_source_payload_data = litespi_tx_mux_endpoint1_sink_payload_data;
end
endcase
end
```
#### Send data bit by bit
```=verilog
if (mgmtsoc_litespisdrphycore_sr_out_load) begin
mgmtsoc_litespisdrphycore_sr_out <= (mgmtsoc_litespisdrphycore_sink_payload_data <<< (6'd32 - mgmtsoc_litespisdrphycore_sink_payload_len));
end
if (mgmtsoc_litespisdrphycore_sr_out_shift) begin
case (mgmtsoc_litespisdrphycore_sink_payload_width)
1'd1: begin
mgmtsoc_litespisdrphycore_sr_out <= {mgmtsoc_litespisdrphycore_sr_out, mgmtsoc_litespisdrphycore0};
end
2'd2: begin
mgmtsoc_litespisdrphycore_sr_out <= {mgmtsoc_litespisdrphycore_sr_out, mgmtsoc_litespisdrphycore1};
end
3'd4: begin
mgmtsoc_litespisdrphycore_sr_out <= {mgmtsoc_litespisdrphycore_sr_out, mgmtsoc_litespisdrphycore2};
end
4'd8: begin
mgmtsoc_litespisdrphycore_sr_out <= {mgmtsoc_litespisdrphycore_sr_out, mgmtsoc_litespisdrphycore3};
end
endcase
end
```
https://github.com/bol-edu/caravel-soc/blob/main/rtl/soc/mgmt_core.v#L2179
https://github.com/bol-edu/caravel-soc/blob/main/rtl/soc/mgmt_core.v#L2249
https://github.com/bol-edu/caravel-soc/blob/main/rtl/soc/mgmt_core.v#L6805
#### Check state machine
No dummy state

Just keep read data state

#### Check timing to fetch next bit
Clock for flash is not wired directly

## Reference
https://github.com/YosysHQ/picorv32/blob/master/picosoc/spiflash.v
http://www.cypress.com/file/316661/download