# Caravel soc - storage ###### tags: `caravel` https://github.com/bol-edu/caravel-soc ## SRAM ![](https://i.imgur.com/gBi4hOh.png) ```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`). ![](https://i.imgur.com/uoirOvx.png) ![](https://i.imgur.com/vm5wXB3.png) | | Firmware | Hardware | | -------| -------- | -------- | | &a | 0x0004 | 0x01(ram256)| | &b | 0x0008 | 0x02(ram256)| | &c | 0x05e8 | 0x7a(ram128)| | &d | 0x05ec | 0x7b(ram128)| 0x7a = (0x5e8 - 0x400) / 0x04; ## Flash ![](https://i.imgur.com/lpbwcVP.png) ### 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.) ![](https://i.imgur.com/9BF5LxG.png) ![](https://i.imgur.com/cKkp5Sc.png) #### 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 ![](https://i.imgur.com/JYQYIhm.png) Just keep read data state ![](https://i.imgur.com/8Et2nwu.png) #### Check timing to fetch next bit Clock for flash is not wired directly ![](https://i.imgur.com/sjQARhI.png) ## Reference https://github.com/YosysHQ/picorv32/blob/master/picosoc/spiflash.v http://www.cypress.com/file/316661/download