Merge pull request #26 from Manarabdelaty/add_ext_storage

Add external storage area
diff --git a/verilog/dv/caravel/defs.h b/verilog/dv/caravel/defs.h
index c9c0714..0aba014 100644
--- a/verilog/dv/caravel/defs.h
+++ b/verilog/dv/caravel/defs.h
@@ -12,8 +12,13 @@
 extern uint32_t flashio_worker_begin;
 extern uint32_t flashio_worker_end;
 
-// SYNTH_MEM (0x0100_0000)
-#define reg_synth_mem (*(volatile uint32_t*)0x01000000)
+// Storage area (MGMT: 0x0100_0000, User: 0x0200_0000)
+#define reg_mgmt_block0  (*(volatile uint32_t*)0x01000000)
+#define reg_mgmt_block1  (*(volatile uint32_t*)0x01100000)
+#define reg_user_block0  (*(volatile uint32_t*)0x02000000)
+#define reg_user_block1  (*(volatile uint32_t*)0x02100000)
+#define reg_user_block2  (*(volatile uint32_t*)0x02200000)
+#define reg_user_block3  (*(volatile uint32_t*)0x02300000)
 
 // UART (0x2000_0000)
 #define reg_uart_clkdiv (*(volatile uint32_t*)0x20000000)
diff --git a/verilog/dv/caravel/mgmt_soc/storage/Makefile b/verilog/dv/caravel/mgmt_soc/storage/Makefile
new file mode 100644
index 0000000..c7ee607
--- /dev/null
+++ b/verilog/dv/caravel/mgmt_soc/storage/Makefile
@@ -0,0 +1,42 @@
+FIRMWARE_PATH = ../..
+RTL_PATH = ../../../../rtl
+IP_PATH = ../../../../ip
+BEHAVIOURAL_MODELS = ../../ 
+
+GCC_PATH?=/ef/apps/bin
+PDK_PATH?=/ef/tech/SW/sky130A
+
+.SUFFIXES:
+
+PATTERN = storage
+
+all:  ${PATTERN:=.vcd}
+
+hex:  ${PATTERN:=.hex}
+
+%.vvp: %_tb.v %.hex
+	iverilog -DFUNCTIONAL -I $(PDK_PATH) -I $(BEHAVIOURAL_MODELS) \
+	-I $(IP_PATH) -I $(RTL_PATH) \
+	$< -o $@
+
+%.vcd: %.vvp
+	vvp $<
+
+%.elf: %.c $(FIRMWARE_PATH)/sections.lds $(FIRMWARE_PATH)/start.s
+	${GCC_PATH}/riscv32-unknown-elf-gcc -march=rv32imc -Wl,-Bstatic,-T,$(FIRMWARE_PATH)/sections.lds,--strip-debug -ffreestanding -nostdlib -o $@ $(FIRMWARE_PATH)/start.s $<
+
+%.hex: %.elf
+	${GCC_PATH}/riscv32-unknown-elf-objcopy -O verilog $< $@ 
+	# to fix flash base address
+	sed -i 's/@10000000/@00000000/g' $@
+
+%.bin: %.elf
+	${GCC_PATH}/riscv32-unknown-elf-objcopy -O binary $< /dev/stdout | tail -c +1048577 > $@
+
+# ---- Clean ----
+
+clean:
+	rm -f *.elf *.hex *.bin *.vvp *.vcd *.log
+
+.PHONY: clean hex all
+
diff --git a/verilog/dv/caravel/mgmt_soc/storage/storage.c b/verilog/dv/caravel/mgmt_soc/storage/storage.c
new file mode 100644
index 0000000..62a9428
--- /dev/null
+++ b/verilog/dv/caravel/mgmt_soc/storage/storage.c
@@ -0,0 +1,70 @@
+#include "../../defs.h"
+
+// --------------------------------------------------------
+
+/*
+	Storage area Test
+	It uses GPIO to flag the success or failure of the test
+*/
+
+void main()
+{
+    int i;
+    volatile uint32_t* ram_addr; 
+    /* Upper 16 user area pins are configured to be GPIO output */
+
+    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);
+
+    // start test
+    reg_mprj_datal = 0xA0400000;
+
+    // Test Management R/W block0
+    for (i=0; i<10; i++){
+        ram_addr = &reg_mgmt_block0 + i;
+        *ram_addr = i*5000 + 10000;
+    }
+	
+    for (i=0; i<10; i++){
+        ram_addr = &reg_mgmt_block0 + i;
+        if ((i*5000+10000) != *ram_addr) 
+	    reg_mprj_datal = 0xAB400000;
+    }
+	
+    reg_mprj_datal = 0xAB410000;
+	
+    // Test Management R/W block1
+    reg_mprj_datal = 0xA0200000;
+    for (i=0; i<10; i++){
+        ram_addr = &reg_mgmt_block1 + i;
+        *ram_addr = i*5000 + 10000;
+    }
+	
+    for (i=0; i<10; i++){
+        ram_addr = &reg_mgmt_block1 + i;
+        if ((i*5000+10000) != *ram_addr) 
+	    reg_mprj_datal = 0xAB200000;
+    }
+    
+    reg_mprj_datal = 0xAB210000;
+}
+
diff --git a/verilog/dv/caravel/mgmt_soc/storage/storage_tb.v b/verilog/dv/caravel/mgmt_soc/storage/storage_tb.v
new file mode 100644
index 0000000..e664641
--- /dev/null
+++ b/verilog/dv/caravel/mgmt_soc/storage/storage_tb.v
@@ -0,0 +1,154 @@
+/*
+ *  StriVe - A full example SoC using PicoRV32 in SkyWater s8
+ *
+ *  Copyright (C) 2017  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2018  Tim Edwards <tim@efabless.com>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+`timescale 1 ns / 1 ps
+
+`include "caravel.v"
+`include "spiflash.v"
+
+module storage_tb;
+	reg clock;
+	reg RSTB;
+	reg power1, power2;
+
+	wire gpio;
+    wire [15:0] checkbits;
+	wire [37:0] mprj_io;
+	wire flash_csb;
+	wire flash_clk;
+	wire flash_io0;
+	wire flash_io1;
+
+	assign checkbits = mprj_io[31:16];
+
+	// External clock is used by default.  Make this artificially fast for the
+	// simulation.  Normally this would be a slow clock and the digital PLL
+	// would be the fast clock.
+
+	always #10 clock <= (clock === 1'b0);
+
+	initial begin
+		clock = 0;
+	end
+
+	initial begin
+		$dumpfile("storage.vcd");
+		$dumpvars(0, storage_tb);
+
+		// Repeat cycles of 1000 clock edges as needed to complete testbench
+		repeat (100) begin
+			repeat (1000) @(posedge clock);
+			//$display("+1000 cycles");
+		end
+		$display("%c[1;31m",27);
+		$display ("Monitor: Timeout, Test Storage (RTL) Failed");
+		$display("%c[0m",27);
+		$finish;
+	end
+
+	initial begin
+		RSTB <= 1'b0;
+		#1000;
+		RSTB <= 1'b1;	    // Release reset
+		#2000;
+	end
+
+	initial begin		// Power-up sequence
+		power1 <= 1'b0;
+		power2 <= 1'b0;
+		#200;
+		power1 <= 1'b1;
+		#200;
+		power2 <= 1'b1;
+	end
+
+	always @(checkbits) begin
+		if(checkbits == 16'hA040) begin
+			$display("Mem Test storage MGMT block0 (RTL) [word rw] started");
+		end
+		else if(checkbits == 16'hAB40) begin
+			$display("%c[1;31m",27);
+			$display("Monitor: Test storage MGMT block0 (RTL) [word rw] failed");
+			$display("%c[0m",27);
+			$finish;
+		end
+		else if(checkbits == 16'hAB41) begin
+			$display("Monitor: Test storage MGMT block0 (RTL) [word rw]  passed");
+		end
+		else if(checkbits == 16'hA020) begin
+			$display("Mem Test storage MGMT block1 (RTL) [word rw] started");
+		end
+		else if(checkbits == 16'hAB20) begin
+			$display("%c[1;31m",27);
+			$display("Monitor: Test storage MGMT block1 (RTL) [word rw] failed");
+			$display("%c[0m",27);
+			$finish;
+		end
+		else if(checkbits == 16'hAB21) begin
+			$display("Monitor: Test storage MGMT block1 (RTL) [word rw]  passed");
+            $finish;
+		end
+	end
+
+	wire VDD3V3;
+	wire VDD1V8;
+	wire VSS;
+
+	assign VSS = 1'b0;
+	assign VDD3V3 = power1;
+	assign VDD1V8 = power2;
+
+	caravel uut (
+		.vddio	  (VDD3V3),
+		.vssio	  (VSS),
+		.vdda	  (VDD3V3),
+		.vssa	  (VSS),
+		.vccd	  (VDD1V8),
+		.vssd	  (VSS),
+		.vdda1    (VDD3V3),
+		.vdda2    (VDD3V3),
+		.vssa1	  (VSS),
+		.vssa2	  (VSS),
+		.vccd1	  (VDD1V8),
+		.vccd2	  (VDD1V8),
+		.vssd1	  (VSS),
+		.vssd2	  (VSS),
+		.clock	  (clock),
+		.gpio     (gpio),
+		.mprj_io  (mprj_io),
+		.flash_csb(flash_csb),
+		.flash_clk(flash_clk),
+		.flash_io0(flash_io0),
+		.flash_io1(flash_io1),
+		.resetb	  (RSTB)
+	);
+
+	spiflash #(
+		.FILENAME("storage.hex")
+	) spiflash (
+		.csb(flash_csb),
+		.clk(flash_clk),
+		.io0(flash_io0),
+		.io1(flash_io1),
+		.io2(),			// not used
+		.io3()			// not used
+	);
+
+endmodule
diff --git a/verilog/dv/wb_utests/storage_wb/Makefile b/verilog/dv/wb_utests/storage_wb/Makefile
new file mode 100644
index 0000000..4ff890f
--- /dev/null
+++ b/verilog/dv/wb_utests/storage_wb/Makefile
@@ -0,0 +1,17 @@
+.SUFFIXES:
+
+PATTERN = storage_wb
+
+all:  ${PATTERN:=.vcd}
+
+%.vvp: %_tb.v
+	iverilog  -I ../../../rtl \
+	$< -o $@
+
+%.vcd: %.vvp
+	vvp $<
+
+clean:
+	rm -f *.vvp *.vcd *.log
+
+.PHONY: clean all
\ No newline at end of file
diff --git a/verilog/dv/wb_utests/storage_wb/storage_wb_tb.v b/verilog/dv/wb_utests/storage_wb/storage_wb_tb.v
new file mode 100644
index 0000000..4d86f29
--- /dev/null
+++ b/verilog/dv/wb_utests/storage_wb/storage_wb_tb.v
@@ -0,0 +1,339 @@
+
+`define MGMT_BLOCKS 2
+`define USER_BLOCKS 4
+`define MGMT_BASE_ADR 32'h 0100_0000
+`define USER_BASE_ADR 32'h 0200_0000
+
+`define MGMT_BLOCKS_ADR { \
+    {24'h 10_0000}, \     
+    {24'h 00_0000} \   
+}\
+
+`define USER_BLOCKS_ADR { \
+    {24'h 00_0000}, \
+    {24'h 10_0000}, \
+    {24'h 20_0000}, \
+    {24'h 30_0000} \    
+}\
+
+// `define DBG
+`include "sram_1rw1r_32_256_8_sky130.v"
+`include "storage.v"
+`include "storage_bridge_wb.v"
+
+module storage_tb;
+
+    reg wb_clk_i;
+    reg wb_rst_i;
+
+    reg [31:0] wb_adr_i;
+    reg [31:0] wb_dat_i;
+    reg [3:0]  wb_sel_i;
+    reg wb_we_i;
+    reg wb_cyc_i;
+    reg  [1:0] wb_stb_i;
+    wire [1:0] wb_ack_o;
+    wire [31:0] wb_mgmt_dat_o;
+
+    // MGMT_AREA RO WB Interface (USER_BLOCKS)  
+    wire [31:0] wb_user_dat_o;
+
+    wire [`MGMT_BLOCKS-1:0] mgmt_ena;
+    wire [(`MGMT_BLOCKS*4)-1:0] mgmt_wen_mask;
+    wire [`MGMT_BLOCKS-1:0] mgmt_wen;
+    wire [31:0] mgmt_wdata;
+    wire [7:0] mgmt_addr;
+    wire [(`MGMT_BLOCKS*32)-1:0] mgmt_rdata;
+    wire [`USER_BLOCKS-1:0] mgmt_user_ena;
+    wire [7:0] mgmt_user_addr;
+    wire [(`USER_BLOCKS*32)-1:0] mgmt_user_rdata;
+
+    // USER_AREA R/W Interface (USER_BLOCKS)
+    reg user_clk;
+    reg [`USER_BLOCKS-1:0] user_ena;
+    reg [`USER_BLOCKS-1:0] user_wen;
+    reg [(`USER_BLOCKS*4)-1:0] user_wen_mask;
+    reg [7:0] user_addr;
+    reg [31:0] user_wdata;
+    wire [(`USER_BLOCKS*32)-1:0] user_rdata;
+
+    // USER_AREA RO Interface (MGMT_BLOCS)
+    reg [`MGMT_BLOCKS-1:0] user_mgmt_ena;
+    reg [7:0] user_mgmt_addr;
+    wire [(`MGMT_BLOCKS*32)-1:0] user_mgmt_rdata;
+
+    initial begin
+        // MGMT Ports
+        wb_clk_i = 0;
+        wb_rst_i = 0;
+        wb_stb_i = 0; 
+        wb_cyc_i = 0;  
+        wb_sel_i = 0;  
+        wb_we_i  = 0;  
+        wb_dat_i = 0; 
+        wb_adr_i = 0; 
+        // User Ports
+        user_clk = 0;
+        user_ena = {`USER_BLOCKS{1'b1}};
+        user_wen = {`USER_BLOCKS{1'b1}};
+        user_addr = 0;
+        user_wdata = 0;
+        user_mgmt_ena = {`MGMT_BLOCKS{1'b1}};
+        user_mgmt_addr = 0;
+    end
+
+    always #1 wb_clk_i = ~wb_clk_i;
+    always #1 user_clk = ~user_clk;
+
+    initial begin
+        $dumpfile("storage_tb.vcd");
+        $dumpvars(0, storage_tb);
+        repeat (100) begin
+            repeat (1000) @(posedge wb_clk_i);
+        end
+        $display("%c[1;31m",27);
+        $display ("Monitor: Timeout, Test Storage Area Failed");
+        $display("%c[0m",27);
+        $finish;
+    end
+
+    reg [31:0] ref_data [255: 0];
+    reg [24*(`MGMT_BLOCKS)-1:0] mgmt_blocks_adr = `MGMT_BLOCKS_ADR;
+    reg [24*(`USER_BLOCKS)-1:0] user_blocks_adr = `USER_BLOCKS_ADR;
+
+
+    reg [31:0] block_adr;
+    integer i,j;
+
+    initial begin
+        // Reset Operation
+        wb_rst_i = 1;
+        #2;
+        wb_rst_i = 0;
+        #2;
+
+        // Test MGMT R/W port and user RO port
+        for (i = 0; i< `MGMT_BLOCKS; i = i +1) begin
+            for ( j = 0; j < 100; j = j + 1) begin 
+                if (i == 0) begin
+                    ref_data[j] = $urandom_range(0, 2**30);
+                end
+                block_adr = mgmt_blocks_adr[24*i+:24] + j | `MGMT_BASE_ADR;
+                mgmt_write(block_adr, ref_data[j]);
+                #2;
+            end
+        end
+        
+        for (i = 0; i< `MGMT_BLOCKS; i = i +1) begin
+            for ( j = 0; j < 100; j = j + 1) begin 
+                block_adr = mgmt_blocks_adr[24*i+:24] + j | `MGMT_BASE_ADR;
+                mgmt_read(block_adr, 0);
+                if (wb_mgmt_dat_o !== ref_data[j]) begin
+                    $display("Monitor: MGMT R/W Operation Failed");
+                    $finish;
+                end
+                
+                user_mgmt_read(j,i);
+                if (user_mgmt_rdata[32*i+:32] !== ref_data[j]) begin
+                    $display("Monitor: User RO Operation Failed");
+                    $finish;
+                end
+                #2;
+            end
+        end
+
+        // Test user R/W port & MGMT RO port
+        for (i = 0; i<`USER_BLOCKS; i = i +1) begin
+            for ( j = 0; j < 100; j = j + 1) begin 
+                if (i == 0) begin
+                    ref_data[j] = $urandom_range(0, 2**30);
+                end
+                user_write(j, ref_data[j], i);
+                #2;
+            end
+        end
+
+        for (i = 0; i< `USER_BLOCKS; i = i +1) begin
+            for ( j = 0; j < 100; j = j + 1) begin 
+                user_read(j,i);
+                if (user_rdata[32*i+:32] !== ref_data[j]) begin
+                    $display("Monitor: User R/W Operation Failed");
+                    $finish;
+                end
+
+                block_adr = user_blocks_adr[24*i+:24] + j | `USER_BASE_ADR;
+                mgmt_read(block_adr,1);
+                if(wb_user_dat_o !== ref_data[j])begin
+                    $display("Monitor: MGMT RO Operation Failed");
+                    $finish;
+                end
+                #2;
+            end
+        end
+
+        $display("Success");
+        $finish;
+    end
+    
+    task user_write;
+        input [32:0] addr;
+        input [32:0] data;
+        input integer block;
+        begin
+            @(posedge user_clk) begin
+                user_ena[block] = 0;
+                user_wen[block] = 0;
+                user_wen_mask[(block*4)+:4] = 4'b1111;
+                user_wdata = data;
+                user_addr = addr[7:0];
+                $display("Write Cycle Started.");
+            end
+            #4;
+            user_ena[block] = 1;
+            user_wen_mask[(block*4)+:4] = 4'b0000;
+            user_wen[block] = 1;
+            $display("Write Cycle Ended.");
+        end
+    endtask
+
+    task user_read;
+        input [32:0] addr;
+        input integer block;
+        begin
+            @(posedge user_clk) begin
+                user_ena[block] = 0;
+                user_addr = addr[7:0];
+                $display("Read Cycle Started.");
+            end
+            #8;
+            user_ena[block] = 1;
+            $display("Read Cycle Ended.");
+        end
+    endtask
+
+    task user_mgmt_read;
+        input [32:0] addr;
+        input integer block;
+        begin
+            @(posedge user_clk) begin
+                user_mgmt_ena[block] = 0;
+                user_mgmt_addr = addr[7:0];
+                $display("Read Cycle Started.");
+            end
+            #8;
+            $display("Read Cycle Ended.");
+        end
+    endtask
+
+    task mgmt_write;
+        input [32:0] addr;
+        input [32:0] data;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i[0] = 1;
+                wb_cyc_i = 1;
+                wb_sel_i = 4'hF; 
+                wb_we_i = 1;     
+                wb_adr_i = addr;
+                wb_dat_i = data;
+                $display("Write Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o[0] == 1);
+            wait(wb_ack_o[0] == 0);
+            wb_cyc_i = 0;
+            wb_stb_i[0] = 0;
+            $display("Write Cycle Ended.");
+        end
+    endtask
+    
+    task mgmt_read;
+        input [32:0] addr;
+        input integer block;
+        begin 
+            @(posedge wb_clk_i) begin
+                wb_stb_i[block] = 1;
+                wb_cyc_i = 1;
+                wb_we_i = 0;
+                wb_adr_i = addr;
+                $display("Read Cycle Started.");
+            end
+            // Wait for an ACK
+            wait(wb_ack_o[block] == 1);
+            wait(wb_ack_o[block] == 0);
+            wb_cyc_i = 0;
+            wb_stb_i[block] = 0;
+            $display("Read Cycle Ended.");
+        end
+    endtask
+
+    storage_bridge_wb #(
+        .USER_BLOCKS(`USER_BLOCKS),
+        .MGMT_BLOCKS(`MGMT_BLOCKS),
+        .MGMT_BASE_ADR(`MGMT_BASE_ADR),
+        .USER_BASE_ADR(`USER_BASE_ADR),
+        .MGMT_BLOCKS_ADR(`MGMT_BLOCKS_ADR),
+        .USER_BLOCKS_ADR(`USER_BLOCKS_ADR)
+    ) wb_bridge (
+        .wb_clk_i(wb_clk_i),
+        .wb_rst_i(wb_rst_i),
+
+        .wb_adr_i(wb_adr_i),
+        .wb_dat_i(wb_dat_i),
+        .wb_sel_i(wb_sel_i),
+        .wb_we_i(wb_we_i),
+        .wb_cyc_i(wb_cyc_i),
+        .wb_stb_i(wb_stb_i),
+        .wb_ack_o(wb_ack_o),
+        .wb_mgmt_dat_o(wb_mgmt_dat_o),
+
+    // MGMT_AREA RO WB Interface (USER_BLOCKS)  
+        .wb_user_dat_o(wb_user_dat_o),
+
+    // MGMT Area native memory interface
+        .mgmt_ena(mgmt_ena), 
+        .mgmt_wen_mask(mgmt_wen_mask),
+        .mgmt_wen(mgmt_wen),
+        .mgmt_addr(mgmt_addr),
+        .mgmt_wdata(mgmt_wdata),
+        .mgmt_rdata(mgmt_rdata),
+
+    // MGMT_AREA RO Interface (USER_BLOCKS)
+        .mgmt_user_ena(mgmt_user_ena),
+        .mgmt_user_addr(mgmt_user_addr),
+        .mgmt_user_rdata(mgmt_user_rdata)
+    );
+
+
+    storage  #(
+        .MGMT_BLOCKS(`MGMT_BLOCKS),
+        .USER_BLOCKS(`USER_BLOCKS)  
+    ) uut (
+        // Management R/W WB interface
+        .mgmt_clk(wb_clk_i),
+        .mgmt_ena(mgmt_ena),
+        .mgmt_wen(mgmt_wen),
+        .mgmt_wen_mask(mgmt_wen_mask),
+        .mgmt_addr(mgmt_addr),
+        .mgmt_wdata(mgmt_wdata),
+        .mgmt_rdata(mgmt_rdata),
+        // Management RO interface  
+        .mgmt_user_ena(mgmt_user_ena),
+        .mgmt_user_addr(mgmt_user_addr),
+        .mgmt_user_rdata(mgmt_user_rdata),
+        // User R/W interface
+        .user_clk(user_clk),
+        .user_ena(user_ena),
+        .user_wen(user_wen),
+        .user_wen_mask(user_wen_mask),
+        .user_addr(user_addr), 
+        .user_wdata(user_wdata),
+        .user_rdata(user_rdata),
+        // User RO interface
+        .user_mgmt_ena(user_mgmt_ena),
+        .user_mgmt_addr(user_mgmt_addr),
+        .user_mgmt_rdata(user_mgmt_rdata)
+    );
+
+
+endmodule
\ No newline at end of file
diff --git a/verilog/rtl/caravel.v b/verilog/rtl/caravel.v
index 4aba1fe..d7c123f 100644
--- a/verilog/rtl/caravel.v
+++ b/verilog/rtl/caravel.v
@@ -41,15 +41,18 @@
 `include "gpio_control_block.v"
 `include "clock_div.v"
 `include "simple_por.v"
+`include "storage_bridge_wb.v"
+`include "sram_1rw1r_32_256_8_sky130.v"
+`include "storage.v"
 
 /*------------------------------*/
 /* Include user project here	*/
 /*------------------------------*/
 `include "user_proj_example.v"
 
-`ifdef USE_OPENRAM
-    `include "sram_1rw1r_32_256_8_sky130.v"
-`endif
+// `ifdef USE_OPENRAM
+//     `include "sram_1rw1r_32_256_8_sky130.v"
+// `endif
 
 module caravel (
     inout vddio,	// Common 3.3V padframe/ESD power
@@ -313,6 +316,30 @@
 	wire	    mprj_vdd_pwrgood;
 	wire	    mprj2_vdd_pwrgood;
 
+	// Storage area
+	// Management R/W interface 
+	wire [`MGMT_BLOCKS-1:0] mgmt_ena; 
+    wire [`MGMT_BLOCKS-1:0] mgmt_wen;
+    wire [(`MGMT_BLOCKS*4)-1:0] mgmt_wen_mask;
+    wire [7:0] mgmt_addr;
+    wire [31:0] mgmt_wdata;
+    wire [(`MGMT_BLOCKS*32)-1:0] mgmt_rdata;
+	// Management RO interface
+	wire [`USER_BLOCKS-1:0] mgmt_user_ena; 
+    wire [7:0] mgmt_user_addr;
+    wire [(`USER_BLOCKS*32)-1:0] mgmt_user_rdata;
+	// User R/W interface
+	wire [`USER_BLOCKS-1:0] user_ena;
+    wire [`USER_BLOCKS-1:0] user_wen;
+    wire [(`USER_BLOCKS*4)-1:0] user_wen_mask;
+    wire [7:0] user_addr;
+    wire [31:0] user_wdata;
+    wire [(`USER_BLOCKS*32)-1:0] user_rdata;
+    // User RO interface
+    wire [`MGMT_BLOCKS-1:0] user_mgmt_ena;
+    wire [7:0] user_mgmt_addr;
+    wire [(`MGMT_BLOCKS*32)-1:0] user_mgmt_rdata;
+
     mgmt_core soc (
 	`ifdef LVS
 		.vdd(vccd),
@@ -377,7 +404,18 @@
 		.mprj_ack_i(mprj_ack_i_core),
 		.mprj_dat_i(mprj_dat_i_core),
 		// mask data
-		.mask_rev(mask_rev)
+		.mask_rev(mask_rev),
+		// MGMT area R/W interface for mgmt RAM
+    	.mgmt_ena(mgmt_ena), 
+    	.mgmt_wen_mask(mgmt_wen_mask),
+    	.mgmt_wen(mgmt_wen),
+    	.mgmt_addr(mgmt_addr),
+    	.mgmt_wdata(mgmt_wdata),
+    	.mgmt_rdata(mgmt_rdata),
+    	// MGMT area RO interface for user RAM 
+    	.user_ena(mgmt_user_ena),
+    	.user_addr(mgmt_user_addr),
+    	.user_rdata(mgmt_user_rdata)
     	);
 
 	/* Clock and reset to user space are passed through a tristate	*/
@@ -600,4 +638,35 @@
 		.X(rstb_l)
     );
 
+	// Storage area
+	storage #(
+		.MGMT_BLOCKS(`MGMT_BLOCKS),
+		.USER_BLOCKS(`USER_BLOCKS)
+	) storage(
+		.mgmt_clk(caravel_clk),
+        .mgmt_ena(mgmt_ena),
+        .mgmt_wen(mgmt_wen),
+        .mgmt_wen_mask(mgmt_wen_mask),
+        .mgmt_addr(mgmt_addr),
+        .mgmt_wdata(mgmt_wdata),
+        .mgmt_rdata(mgmt_rdata),
+        // Management RO interface  
+        .mgmt_user_ena(mgmt_user_ena),
+        .mgmt_user_addr(mgmt_user_addr),
+        .mgmt_user_rdata(mgmt_user_rdata),
+       
+	    // User R/W interface
+        .user_clk(caravel_clk2),
+        .user_ena(user_ena),
+        .user_wen(user_wen),
+        .user_wen_mask(user_wen_mask),
+        .user_addr(user_addr), 
+        .user_wdata(user_wdata),
+        .user_rdata(user_rdata),
+        // User RO interface
+        .user_mgmt_ena(user_mgmt_ena),
+        .user_mgmt_addr(user_mgmt_addr),
+        .user_mgmt_rdata(user_mgmt_rdata)
+	);
+
 endmodule
diff --git a/verilog/rtl/defines.v b/verilog/rtl/defines.v
index e2f457a..f9356c0 100644
--- a/verilog/rtl/defines.v
+++ b/verilog/rtl/defines.v
@@ -8,3 +8,7 @@
 // Type and size of soc_mem
 // `define USE_OPENRAM
 `define MEM_WORDS 256
+
+// Number of RAM blocks for the mgmt_core
+`define MGMT_BLOCKS 2
+`define USER_BLOCKS 4
\ No newline at end of file
diff --git a/verilog/rtl/mgmt_core.v b/verilog/rtl/mgmt_core.v
index 863bd98..3e42f3e 100644
--- a/verilog/rtl/mgmt_core.v
+++ b/verilog/rtl/mgmt_core.v
@@ -65,7 +65,20 @@
     	output core_rstn,
 
 	// Metal programmed user ID / mask revision vector
-	input [31:0] mask_rev
+	input [31:0] mask_rev,
+	
+    // MGMT area R/W interface for mgmt RAM
+    output [`MGMT_BLOCKS-1:0] mgmt_ena, 
+    output [(`MGMT_BLOCKS*4)-1:0] mgmt_wen_mask,
+    output [`MGMT_BLOCKS-1:0] mgmt_wen,
+    output [7:0] mgmt_addr,
+    output [31:0] mgmt_wdata,
+    input  [(`MGMT_BLOCKS*32)-1:0] mgmt_rdata,
+
+    // MGMT area RO interface for user RAM 
+    output [`USER_BLOCKS-1:0] user_ena,
+    output [7:0] user_addr,
+    input  [(`USER_BLOCKS*32)-1:0] user_rdata
 );
     	wire ext_clk_sel;
     	wire pll_clk, pll_clk90;
@@ -212,7 +225,18 @@
 		.mprj_adr_o(mprj_adr_o),
 		.mprj_dat_o(mprj_dat_o),
 		.mprj_ack_i(mprj_ack_i),
-		.mprj_dat_i(mprj_dat_i)
+		.mprj_dat_i(mprj_dat_i),
+    	// MGMT area R/W interface for mgmt RAM
+    	.mgmt_ena(mgmt_ena), 
+    	.mgmt_wen_mask(mgmt_wen_mask),
+    	.mgmt_wen(mgmt_wen),
+    	.mgmt_addr(mgmt_addr),
+    	.mgmt_wdata(mgmt_wdata),
+    	.mgmt_rdata(mgmt_rdata),
+    	// MGMT area RO interface for user RAM 
+    	.user_ena(user_ena),
+    	.user_addr(user_addr),
+    	.user_rdata(user_rdata)
     	);
     
     	digital_pll pll (
diff --git a/verilog/rtl/mgmt_soc.v b/verilog/rtl/mgmt_soc.v
index 1139f1d..0183909 100644
--- a/verilog/rtl/mgmt_soc.v
+++ b/verilog/rtl/mgmt_soc.v
@@ -137,7 +137,20 @@
     output mprj_we_o,
     output [3:0] mprj_sel_o,
     output [31:0] mprj_adr_o,
-    output [31:0] mprj_dat_o
+    output [31:0] mprj_dat_o,
+
+    // MGMT area R/W interface for mgmt RAM
+    output [`MGMT_BLOCKS-1:0] mgmt_ena, 
+    output [(`MGMT_BLOCKS*4)-1:0] mgmt_wen_mask,
+    output [`MGMT_BLOCKS-1:0] mgmt_wen,
+    output [7:0] mgmt_addr,
+    output [31:0] mgmt_wdata,
+    input  [(`MGMT_BLOCKS*32)-1:0] mgmt_rdata,
+
+    // MGMT area RO interface for user RAM 
+    output [`USER_BLOCKS-1:0] user_ena,
+    output [7:0] user_addr,
+    input  [(`USER_BLOCKS*32)-1:0] user_rdata
 );
     /* Memory reverted back to 256 words while memory has to be synthesized */
     parameter [31:0] STACKADDR = (4*(`MEM_WORDS));       // end of memory
@@ -146,6 +159,8 @@
 
     // Slaves Base Addresses
     parameter RAM_BASE_ADR    = 32'h 0000_0000;
+    parameter EXT_MRAM_BASE_ADR = 32'h 0100_0000;
+    parameter EXT_URAM_BASE_ADR = 32'h 0200_0000;
     parameter FLASH_BASE_ADR  = 32'h 1000_0000;
     parameter UART_BASE_ADR   = 32'h 2000_0000;
     parameter GPIO_BASE_ADR   = 32'h 2100_0000;
@@ -157,7 +172,7 @@
     parameter FLASH_CTRL_CFG  = 32'h 2D00_0000;
     parameter SYS_BASE_ADR    = 32'h 2F00_0000;
     parameter MPRJ_BASE_ADR   = 32'h 3000_0000;   // WB MI A
-
+    
     // UART
     parameter UART_CLK_DIV = 8'h00;
     parameter UART_DATA    = 8'h04;
@@ -198,10 +213,23 @@
     parameter TRAP_OUT      = 8'h08;
     parameter IRQ_SRC       = 8'h0c;
 
+    // Storage area RAM blocks
+    parameter [(`MGMT_BLOCKS*24)-1:0] MGMT_BLOCKS_ADR = {
+        {24'h 10_0000},
+        {24'h 00_0000}
+    };
+
+    parameter [(`USER_BLOCKS*24)-1:0] USER_BLOCKS_ADR = {
+        {24'h 30_0000},
+        {24'h 20_0000},
+        {24'h 10_0000},
+        {24'h 00_0000}
+    };
+
     // Wishbone Interconnect 
     localparam ADR_WIDTH = 32;
     localparam DAT_WIDTH = 32;
-    localparam NUM_SLAVES = 12;
+    localparam NUM_SLAVES = 14;
 
     parameter [NUM_SLAVES*ADR_WIDTH-1: 0] ADR_MASK = {
         {8'hFF, {ADR_WIDTH-8{1'b0}}},
@@ -215,6 +243,8 @@
         {8'hFF, {ADR_WIDTH-8{1'b0}}},
         {8'hFF, {ADR_WIDTH-8{1'b0}}},
         {8'hFF, {ADR_WIDTH-8{1'b0}}},
+        {8'hFF, {ADR_WIDTH-8{1'b0}}},
+        {8'hFF, {ADR_WIDTH-8{1'b0}}},
         {8'hFF, {ADR_WIDTH-8{1'b0}}}
     };
 
@@ -230,6 +260,8 @@
         {GPIO_BASE_ADR},
         {UART_BASE_ADR},
         {FLASH_BASE_ADR},
+        {EXT_URAM_BASE_ADR},
+        {EXT_MRAM_BASE_ADR},
         {RAM_BASE_ADR}
     };
 
@@ -713,6 +745,51 @@
         .wb_dat_o(mem_dat_o)
     );
 
+    wire uram_stb_i;
+    wire mram_stb_i;
+    wire uram_ack_o;
+    wire mram_ack_o;
+    wire [31:0] mram_dat_o;
+    wire [31:0] uram_dat_o;
+
+    // Storage area wishbone brige
+    storage_bridge_wb #(
+        .USER_BLOCKS(`USER_BLOCKS),
+        .MGMT_BLOCKS(`MGMT_BLOCKS),
+        .MGMT_BASE_ADR(EXT_MRAM_BASE_ADR),
+        .USER_BASE_ADR(EXT_URAM_BASE_ADR),
+        .MGMT_BLOCKS_ADR(MGMT_BLOCKS_ADR),
+        .USER_BLOCKS_ADR(USER_BLOCKS_ADR)
+    ) wb_bridge (
+        .wb_clk_i(wb_clk_i),
+        .wb_rst_i(wb_rst_i),
+
+        .wb_adr_i(cpu_adr_o),
+        .wb_dat_i(cpu_dat_o),
+        .wb_sel_i(cpu_sel_o),
+        .wb_we_i(cpu_we_o),
+        .wb_cyc_i(cpu_cyc_o),
+        .wb_stb_i({uram_stb_i, mram_stb_i}),
+        .wb_ack_o({uram_ack_o, mram_ack_o}),
+        .wb_mgmt_dat_o(mram_dat_o),
+
+        // MGMT_AREA RO WB Interface  
+        .wb_user_dat_o(uram_dat_o),
+
+        // MGMT Area native memory interface
+        .mgmt_ena(mgmt_ena), 
+        .mgmt_wen_mask(mgmt_wen_mask),
+        .mgmt_wen(mgmt_wen),
+        .mgmt_addr(mgmt_addr),
+        .mgmt_wdata(mgmt_wdata),
+        .mgmt_rdata(mgmt_rdata),
+
+        // MGMT_AREA RO interface 
+        .mgmt_user_ena(user_ena),
+        .mgmt_user_addr(user_addr),
+        .mgmt_user_rdata(user_rdata)
+    );
+
     // Wishbone intercon logic
     wb_intercon #(
         .AW(ADR_WIDTH),
@@ -732,17 +809,17 @@
 		mprj_stb_o, mprj_ctrl_stb_i, la_stb_i, 
 		spi_master_stb_i, counter_timer1_stb_i, counter_timer0_stb_i,
 		gpio_stb_i, uart_stb_i,
-		spimemio_flash_stb_i, mem_stb_i }), 
+		spimemio_flash_stb_i,uram_stb_i, mram_stb_i, mem_stb_i }), 
         .wbs_dat_i({ sys_dat_o, spimemio_cfg_dat_o,
 		mprj_dat_i, mprj_ctrl_dat_o, la_dat_o,
 		spi_master_dat_o, counter_timer1_dat_o, counter_timer0_dat_o,
 		gpio_dat_o, uart_dat_o,
-		spimemio_flash_dat_o, mem_dat_o }),
+		spimemio_flash_dat_o, uram_dat_o, mram_dat_o, mem_dat_o }),
         .wbs_ack_i({ sys_ack_o, spimemio_cfg_ack_o,
 		mprj_ack_i, mprj_ctrl_ack_o, la_ack_o,
 		spi_master_ack_o, counter_timer1_ack_o, counter_timer0_ack_o,
 		gpio_ack_o, uart_ack_o,
-		spimemio_flash_ack_o,  mem_ack_o })
+		spimemio_flash_ack_o, uram_ack_o, mram_ack_o, mem_ack_o })
     );
 
 endmodule
diff --git a/verilog/rtl/storage.v b/verilog/rtl/storage.v
new file mode 100644
index 0000000..b773158
--- /dev/null
+++ b/verilog/rtl/storage.v
@@ -0,0 +1,70 @@
+ 
+/* User area has R/W access for USER_BLOCKS and RO access for MGMT_BLOCKS 
+   Management area has R/W access for MGMT_BLOCKS and RO access for USER_BLOCKS */
+
+module storage #(
+    parameter USER_BLOCKS = 4,  // R/W access
+    parameter MGMT_BLOCKS = 2   // R/W access
+) (
+    // MGMT_AREA R/W Interface (MGMT_BLOCKS)
+    input mgmt_clk,
+    input [MGMT_BLOCKS-1:0] mgmt_ena, 
+    input [MGMT_BLOCKS-1:0] mgmt_wen, // not shared 
+    input [(MGMT_BLOCKS*4)-1:0] mgmt_wen_mask, // not shared 
+    input [7:0] mgmt_addr,
+    input [31:0] mgmt_wdata,
+    output [(MGMT_BLOCKS*32)-1:0] mgmt_rdata,
+
+    // MGMT_AREA RO Interface (USER_BLOCKS)
+    input [USER_BLOCKS-1:0] mgmt_user_ena,
+    input [7:0] mgmt_user_addr,
+    output [(USER_BLOCKS*32)-1:0] mgmt_user_rdata,
+    
+    // USER_AREA R/W Interface (USER_BLOCKS)
+    input user_clk,
+    input [USER_BLOCKS-1:0] user_ena, 
+    input [USER_BLOCKS-1:0] user_wen,
+    input [(USER_BLOCKS*4)-1:0] user_wen_mask,
+    input [7:0] user_addr,
+    input [31:0] user_wdata,
+    output [(USER_BLOCKS*32)-1:0] user_rdata,
+
+    // USER_AREA RO Interface (MGMT_BLOCS)
+    input [MGMT_BLOCKS-1:0] user_mgmt_ena,
+    input [7:0] user_mgmt_addr,
+    output  [(MGMT_BLOCKS*32)-1:0] user_mgmt_rdata
+);
+
+    sram_1rw1r_32_256_8_sky130 SRAM_0 [MGMT_BLOCKS-1:0] (
+        // MGMT R/W port
+        .clk0(mgmt_clk), 
+        .csb0(mgmt_ena),   
+        .web0(mgmt_wen),  
+        .wmask0(mgmt_wen_mask),
+        .addr0(mgmt_addr[7:0]),
+        .din0(mgmt_wdata),
+        .dout0(mgmt_rdata),
+        // User RO port
+        .clk1(user_clk),
+        .csb1(user_mgmt_ena), 
+        .addr1(user_mgmt_addr),
+        .dout1(user_mgmt_rdata)
+    );    
+
+    sram_1rw1r_32_256_8_sky130 SRAM_1 [USER_BLOCKS-1:0](
+        // User R/W port
+        .clk0(user_clk), 
+        .csb0(user_ena), 
+        .web0(user_wen),
+        .wmask0(user_wen_mask),
+        .addr0(user_addr),
+        .din0(user_wdata),
+        .dout0(user_rdata),
+        // MGMT RO port
+        .clk1(mgmt_clk),
+        .csb1(mgmt_user_ena),
+        .addr1(mgmt_user_addr),
+        .dout1(mgmt_user_rdata)
+    );
+    
+endmodule
\ No newline at end of file
diff --git a/verilog/rtl/storage_bridge_wb.v b/verilog/rtl/storage_bridge_wb.v
new file mode 100644
index 0000000..b8bf2c8
--- /dev/null
+++ b/verilog/rtl/storage_bridge_wb.v
@@ -0,0 +1,115 @@
+module storage_bridge_wb #(
+    parameter USER_BLOCKS = 4, 
+    parameter MGMT_BLOCKS = 2,
+    parameter MGMT_BASE_ADR = 32'h 0100_0000,
+    parameter USER_BASE_ADR = 32'h 0200_0000
+) (
+    // MGMT_AREA R/W WB Interface
+    input wb_clk_i,
+    input wb_rst_i,
+
+    input [31:0] wb_adr_i,
+    input [31:0] wb_dat_i,
+    input [3:0]  wb_sel_i,
+    input wb_we_i,
+    input wb_cyc_i,
+    input [1:0] wb_stb_i,
+    output reg [1:0] wb_ack_o,
+    output reg [31:0] wb_mgmt_dat_o,
+
+    // MGMT_AREA RO WB Interface   
+    output reg [31:0] wb_user_dat_o,
+
+    // MGMT Area native memory interface
+    output [MGMT_BLOCKS-1:0] mgmt_ena, 
+    output [(MGMT_BLOCKS*4)-1:0] mgmt_wen_mask,
+    output [MGMT_BLOCKS-1:0] mgmt_wen,
+    output [7:0] mgmt_addr,
+    output [31:0] mgmt_wdata,
+    input  [(MGMT_BLOCKS*32)-1:0] mgmt_rdata,
+
+    // MGMT_AREA RO Interface 
+    output [USER_BLOCKS-1:0] mgmt_user_ena,
+    output [7:0] mgmt_user_addr,
+    input  [(USER_BLOCKS*32)-1:0] mgmt_user_rdata
+);
+
+    parameter [(MGMT_BLOCKS*24)-1:0] MGMT_BLOCKS_ADR = {
+        {24'h 10_0000},
+        {24'h 00_0000}
+    };
+
+    parameter [(USER_BLOCKS*24)-1:0] USER_BLOCKS_ADR = {
+        {24'h 30_0000},
+        {24'h 20_0000},
+        {24'h 10_0000},
+        {24'h 00_0000}
+    };
+
+    parameter ADR_MASK = 24'h FF_0000;
+
+    wire [1:0] valid;
+    wire [1:0] wen;
+    wire [7:0] wen_mask;
+
+    assign valid = {2{wb_cyc_i}} & wb_stb_i;
+    assign wen   = wb_we_i & valid;    
+    assign wen_mask = wb_sel_i & {{4{wen[1]}}, {4{wen[0]}}};
+
+    // Ack generation
+    reg [1:0] wb_ack_read;
+
+    always @(posedge wb_clk_i) begin
+        if (wb_rst_i == 1'b 1) begin
+            wb_ack_read <= 2'b0;
+            wb_ack_o <= 2'b0;
+        end else begin
+            wb_ack_o <= wb_we_i? (valid & ~wb_ack_o): wb_ack_read;
+            wb_ack_read <= (valid & ~wb_ack_o) & ~wb_ack_read;
+        end
+    end
+    
+    // Address decoding
+    wire [MGMT_BLOCKS-1: 0] mgmt_sel;
+    wire [USER_BLOCKS-1: 0] user_sel;
+
+    wire [23:0] test = (wb_adr_i[23:0] & ADR_MASK);
+    wire iste = test ==  MGMT_BLOCKS_ADR[23:0];
+    genvar iS;
+    generate
+        for (iS = 0; iS < MGMT_BLOCKS; iS = iS + 1) begin
+            assign mgmt_sel[iS] = 
+                ((wb_adr_i[23:0] & ADR_MASK) == MGMT_BLOCKS_ADR[(iS+1)*24-1:iS*24]);
+        end
+        for (iS = 0; iS < USER_BLOCKS; iS = iS + 1) begin
+            assign user_sel[iS] = 
+                ((wb_adr_i[23:0] & ADR_MASK) == USER_BLOCKS_ADR[(iS+1)*24-1:iS*24]);
+        end
+    endgenerate
+
+    // Management SoC interface
+    assign mgmt_ena = valid[0] ? ~mgmt_sel : {MGMT_BLOCKS{1'b1}}; 
+    assign mgmt_wen = ~{MGMT_BLOCKS{wen[0]}};
+    assign mgmt_wen_mask = {MGMT_BLOCKS{wen_mask[3:0]}};
+    assign mgmt_addr = wb_adr_i[7:0];
+    assign mgmt_wdata = wb_dat_i[31:0];
+
+    integer i;
+    always @(*) begin
+        wb_mgmt_dat_o = {32{1'b0}};
+        for (i=0; i<(MGMT_BLOCKS*32); i=i+1)
+            wb_mgmt_dat_o[i%32] = wb_mgmt_dat_o[i%32] | (mgmt_sel[i/32] & mgmt_rdata[i]);
+    end
+
+    // User Interface
+    assign mgmt_user_ena = valid[1] ? ~user_sel : {USER_BLOCKS{1'b1}}; 
+    assign mgmt_user_addr = wb_adr_i[7:0];
+    
+    integer j;
+    always @(*) begin
+        wb_user_dat_o = {32{1'b0}};
+        for (j=0; j<(USER_BLOCKS*32); j=j+1)
+            wb_user_dat_o[j%32] = wb_user_dat_o[j%32] | (user_sel[j/32] & mgmt_user_rdata[j]);
+    end
+
+endmodule
\ No newline at end of file