diff --git a/.gitmodules b/.gitmodules
index 9928787c6a9a1ee668c29a4e61c9258fc23dab22..7b976f39980c01495c7fb90d883f0bc2b6fe6e6f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -49,3 +49,6 @@
 [submodule "fpga/src/apb_timer"]
 	path = fpga/src/apb_timer
 	url = https://github.com/pulp-platform/apb_timer.git
+[submodule "tb/dromajo"]
+	path = tb/dromajo
+	url = https://github.com/kabylkas/dromajo.git
diff --git a/Flist.ariane b/Flist.ariane
index 31205ca74b750ebc5014dc918736a40a1abc19d1..bfe434c2bdbf02e9c4219e4b9dfc54ea7b3b4001 100644
--- a/Flist.ariane
+++ b/Flist.ariane
@@ -71,6 +71,7 @@ src/util/axi_master_connect_rev.sv
 src/util/axi_slave_connect.sv
 src/util/axi_slave_connect_rev.sv
 src/fpga-support/rtl/SyncSpRamBeNx64.sv
+src/dromajo_ram.sv
 src/axi_mem_if/src/axi2mem.sv
 src/tech_cells_generic/src/pulp_clock_gating.sv
 src/tech_cells_generic/src/cluster_clock_inverter.sv
diff --git a/Makefile b/Makefile
index 93fbeb92ad2a153d147339ed391d48bb147a0694..0d45a3c1151df20a604acc6b1f08d4d6cc833eea 100644
--- a/Makefile
+++ b/Makefile
@@ -114,8 +114,10 @@ dpi_hdr := $(wildcard tb/dpi/*.h)
 dpi_hdr := $(addprefix $(root-dir), $(dpi_hdr))
 CFLAGS := -I$(QUESTASIM_HOME)/include         \
           -I$(RISCV)/include                  \
+          $(if $(DROMAJO), -I../tb/dromajo/src,) \
           -std=c++11 -I../tb/dpi
 
+
 ifdef spike-tandem
     CFLAGS += -Itb/riscv-isa-sim/install/include/spike
 endif
@@ -385,17 +387,78 @@ verilate_command := $(verilator)
                     -Wno-UNOPTFLAT                                                                               \
                     -Wno-BLKANDNBLK                                                                              \
                     -Wno-style                                                                                   \
+                    $(if $(DROMAJO), -DDROMAJO=1,)                                                               \
                     $(if $(PROFILE),--stats --stats-vars --profile-cfuncs,)                                      \
                     $(if $(DEBUG),--trace --trace-structs,)                                                      \
-                    -LDFLAGS "-L$(RISCV)/lib -Wl,-rpath,$(RISCV)/lib -lfesvr$(if $(PROFILE), -g -pg,) -lpthread" \
-                    -CFLAGS "$(CFLAGS)$(if $(PROFILE), -g -pg,)" -Wall --cc  --vpi                               \
+                    -LDFLAGS "-L$(RISCV)/lib -Wl,-rpath,$(RISCV)/lib -lfesvr$(if $(PROFILE), -g -pg,) $(if $(DROMAJO), -L../tb/dromajo/src -ldromajo_cosim,) -lpthread" \
+                    -CFLAGS "$(CFLAGS)$(if $(PROFILE), -g -pg,) $(if $(DROMAJO), -DDROMAJO=1,)" -Wall --cc  --vpi \
                     $(list_incdir) --top-module ariane_testharness                                               \
                     --Mdir $(ver-library) -O3                                                                    \
                     --exe tb/ariane_tb.cpp tb/dpi/SimDTM.cc tb/dpi/SimJTAG.cc                                    \
-					tb/dpi/remote_bitbang.cc tb/dpi/msim_helper.cc
+					tb/dpi/remote_bitbang.cc tb/dpi/msim_helper.cc $(if $(DROMAJO), tb/dpi/dromajo_cosim_dpi.cc,)
+
+dromajo:
+	cd ./tb/dromajo/src && make
+
+run-dromajo-verilator:
+	$(if $(BIN), $(MAKE) checkpoint_dromajo, $(error "Please provide absolute path to the binary. Usage: make run_dromajo BIN=/absolute/path/to/binary"))
+
+checkpoint_dromajo:
+	cd ./tb/dromajo/run/checkpoints/ && \
+	rm -rf $(notdir $(BIN)) && mkdir $(notdir $(BIN)) && cd $(notdir $(BIN)) && \
+  cp $(BIN) . && \
+	echo -e "\
+	{\n\
+    \"version\":1,\n\
+    \"machine\":\"riscv64\",\n\
+    \"memory_size\":256,\n\
+    \"bios\":\"$(shell pwd)/tb/dromajo/run/checkpoints/$(notdir $(BIN))/$(notdir $(BIN))\",\n\
+    \"memory_base_addr\":0x80000000,\n\
+    \"missing_csrs\": [0x323, 0x324, 0x325, 0x326, //mhpmevent csrs\n\
+                     0x327, 0x328, 0x329, 0x32a,\n\
+                     0x32b, 0x32c, 0x32d, 0x32e,\n\
+                     0x32f, 0x330, 0x331, 0x332,\n\
+                     0x333, 0x334, 0x335, 0x336,\n\
+                     0x337, 0x338, 0x339, 0x33a,\n\
+                     0x33b, 0x33c, 0x33d, 0x33e,\n\
+                     0x33f,\n\
+                     0x3a0, 0x3a1, 0x3a2, 0x3a3, //pmp csrs\n\
+                     0x3b0, 0x3b1, 0x3b2, 0x3b3,\n\
+                     0x3b4, 0x3b5, 0x3b6, 0x3b7,\n\
+                     0x3b8, 0x3b9, 0x3ba, 0x3bb,\n\
+                     0x3bc, 0x3bd, 0x3be, 0x3bf,\n\
+                     0x320], //mcountinhibit\n\
+    \"maxinsns\": 100,\n\
+		\"clint_base_addr\": 0x02000000,\n\
+	  \"clint_size\": 0xC0000,\n\
+	  \"plic_base_addr\": 0x0C000000,\n\
+	  \"plic_size\": 0x3FFFFFF,\n\
+	  \"uart_base_addr\": 0x10000000,\n\
+	  \"uart_size\": 0x1000\n\
+  }" > "$(notdir $(BIN))_boot.cfg" && \
+	echo -e "\
+	{\n\
+    \"version\":1,\n\
+    \"machine\":\"riscv64\",\n\
+    \"memory_size\":256,\n\
+    \"bios\":\"$(shell pwd)/tb/dromajo/run/checkpoints/$(notdir $(BIN))/$(notdir $(BIN))\",\n\
+    \"load\":\"$(shell pwd)/tb/dromajo/run/checkpoints/$(notdir $(BIN))/$(notdir $(BIN))\",\n\
+    \"skip_commit\": [0x73, 0x9002, 0x100073],\n\
+    \"memory_base_addr\":0x80000000,\n\
+		\"clint_base_addr\": 0x02000000,\n\
+	  \"clint_size\": 0xC0000,\n\
+	  \"plic_base_addr\": 0x0C000000,\n\
+	  \"plic_size\": 0x3FFFFFF,\n\
+	  \"uart_base_addr\": 0x10000000,\n\
+	  \"uart_size\": 0x1000\n\
+  }" > "$(notdir $(BIN)).cfg" && \
+  ../../../src/dromajo --save=$(notdir $(BIN)) --save_format=1 ./$(notdir $(BIN))_boot.cfg && \
+  cd ../../../../../ && \
+	./work-ver/Variane_testharness +checkpoint=$(shell pwd)/tb/dromajo/run/checkpoints/$(notdir $(BIN))/$(notdir $(BIN))
+
 
 # User Verilator, at some point in the future this will be auto-generated
-verilate:
+verilate: $(if $(DROMAJO), dromajo,)
 	@echo "[Verilator] Building Model$(if $(PROFILE), for Profiling,)"
 	$(verilate_command)
 	cd $(ver-library) && $(MAKE) -j${NUM_JOBS} -f Variane_testharness.mk
diff --git a/README.md b/README.md
index 61a307e19cca0a98b46021318f38afc1d8505486..806994035db93e9ba0102f9be39f3fa5f963e20b 100644
--- a/README.md
+++ b/README.md
@@ -44,6 +44,7 @@ Table of Contents
       * [Going Beyond](#going-beyond)
          * [CI Testsuites and Randomized Constrained Testing with Torture](#ci-testsuites-and-randomized-constrained-testing-with-torture)
          * [Re-generating the Bootcode (ZSBL)](#re-generating-the-bootcode-zsbl)
+         * [Co-simulation with Dromajo](#co-simulation-with-dromajo)
    * [Contributing](#contributing)
    * [Acknowledgements](#acknowledgements)
 
@@ -337,6 +338,22 @@ The zero stage bootloader (ZSBL) for RTL simulation lives in `bootrom/` while th
 
 To re-generate the bootcode you can use the existing makefile within those directories. To generate the SystemVerilog files you will need the `bitstring` python package installed on your system.
 
+### Co-simulation with Dromajo
+Ariane can be co-simulated with [Dromajo](https://github.com/chipsalliance/dromajo) (currently in the verilator model). 
+
+```
+make verilate DROMAJO=1
+make run-dromajo-verilator BIN=/path/to/elf
+```
+
+The co-simulation flow is depicted in the figure below.
+![image](https://user-images.githubusercontent.com/8511359/84510824-7ceb3b80-ac7a-11ea-9530-24c428ee87d9.png)
+1. Load the binary of interest into Dromajo.
+2. Run Dromajo stand alone and let a couple of instructions to complete.
+3. Dump the checkpoint. This is the whole architectural state of the reference model. Dromajo dumps the main and boot memories. In addition, it generates a boot code. If you were to run that code it will restore the whole architectural state. This means that you can bring any two or more cores into complete synced architectural state by running this piece of code.
+4. Load the checkpoint into the RTL memory and the instance of Dromajo in RTL. Dromajo gets linked to a simulator as a shared library. RTL communicates to Dromajo through set of DPI calls.
+5. Run the RTL simulation and perform co-simulation.
+
 # Contributing
 
 Check out the [contribution guide](CONTRIBUTING.md)
diff --git a/bootrom/dromajo_bootrom.sv b/bootrom/dromajo_bootrom.sv
new file mode 100644
index 0000000000000000000000000000000000000000..1d61580c704fef7824cabb5cd61543ce4bbd66d0
--- /dev/null
+++ b/bootrom/dromajo_bootrom.sv
@@ -0,0 +1,62 @@
+/* Copyright 2020 ETH Zurich and University of Bologna.
+ * Copyright and related rights are licensed under the Solderpad Hardware
+ * License, Version 0.51 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ * http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+ * or agreed to in writing, software, hardware and materials distributed under
+ * this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ * File: dromajo_bootrom.sv
+ *
+ * Author: Nursultan Kabylkas, UCSC
+ * Description: bootrom that gets synced with dromajo for
+ * cosimulation purposes.
+ */
+
+module dromajo_bootrom (
+   input  logic         clk_i,
+   input  logic         req_i,
+   input  logic [63:0]  addr_i,
+   output logic [63:0]  rdata_o
+);
+    localparam int RomSize = 4096;
+    logic [63:0] mem[RomSize-1:0];
+
+    initial begin
+      integer hex_file, num_bytes;
+      longint address, value;
+      string f_name;
+      // init to 0
+      for (int k=0; k<RomSize; k++) begin
+        mem[k] = 0;
+      end
+
+      // sync with dromajo
+      if ($value$plusargs("checkpoint=%s", f_name)) begin
+        hex_file = $fopen({f_name,".bootram.hex"}, "r");
+        while (!$feof(hex_file)) begin
+          num_bytes = $fscanf(hex_file, "%d %h\n", address, value);
+          //$display("%d %h", address, value);
+          mem[address] = value;
+        end
+        $display("Done syncing boot ROM with dromajo...\n");
+      end else begin
+        $display("Failed syncing boot ROM: provide path to a checkpoint.\n");
+      end
+
+    end
+
+    logic [$clog2(RomSize)-1:0] addr_q;
+
+    always_ff @(posedge clk_i) begin
+        if (req_i) begin
+            addr_q <= addr_i[$clog2(RomSize)-1+3:3];
+        end
+    end
+
+    // this prevents spurious Xes from propagating into
+    // the speculative fetch stage of the core
+    assign rdata_o = (addr_q < RomSize) ? mem[addr_q] : '0;
+endmodule
diff --git a/src/ariane.sv b/src/ariane.sv
index e306c3bff96f6dbaefc5378f59aed6c5edb989f6..bd6b384b7f7fe2833a6b895140f8c762a04d713c 100644
--- a/src/ariane.sv
+++ b/src/ariane.sv
@@ -12,6 +12,16 @@
 // Date: 19.03.2017
 // Description: Ariane Top-level module
 
+`ifdef DROMAJO
+import "DPI-C" function void dromajo_trap(int     hart_id,
+                                          longint cause);
+import "DPI-C" function void dromajo_step(int     hart_id,
+                                          longint pc,
+                                          int     insn,
+                                          longint wdata, longint cycle);
+import "DPI-C" function void init_dromajo(string cfg_f_name);
+`endif
+
 import ariane_pkg::*;
 
 module ariane #(
@@ -781,10 +791,51 @@ module ariane #(
   int f;
   logic [63:0] cycles;
 
+`ifdef DROMAJO
+  initial begin
+    string f_name;
+    if ($value$plusargs("checkpoint=%s", f_name)) begin
+      init_dromajo({f_name, ".cfg"});
+      $display("Done initing dromajo...");
+    end else begin
+      $display("Failed initing dromajo. Provide checkpoint name.");
+    end
+  end
+`endif
+
   initial begin
     f = $fopen("trace_hart_00.dasm", "w");
   end
 
+`ifdef DROMAJO
+  always_ff @(posedge clk_i) begin
+      for (int i = 0; i < NR_COMMIT_PORTS; i++) begin
+        if (commit_instr_id_commit[i].ex.valid) begin
+          dromajo_trap(hart_id_i,
+                       commit_instr_id_commit[i].ex.cause);
+        end
+      end
+  end
+
+  always_ff @(posedge clk_i) begin
+    for (int i = 0; i < NR_COMMIT_PORTS; i++) begin
+      if (commit_ack[i] && !commit_instr_id_commit[i].ex.valid) begin
+        if (csr_op_commit_csr == 0) begin
+          dromajo_step(hart_id_i,
+                       commit_instr_id_commit[i].pc,
+                       commit_instr_id_commit[i].ex.tval[31:0],
+                       commit_instr_id_commit[i].result, cycles);
+        end else begin
+          dromajo_step(hart_id_i,
+                       commit_instr_id_commit[i].pc,
+                       commit_instr_id_commit[i].ex.tval[31:0],
+                       csr_rdata_csr_commit, cycles);
+        end
+      end
+    end
+  end
+`endif
+
   always_ff @(posedge clk_i or negedge rst_ni) begin
     if (~rst_ni) begin
       cycles <= 0;
diff --git a/src/csr_regfile.sv b/src/csr_regfile.sv
index 15d665d9fec5577a3d47a627d9a7452edd1ef617..cdfc27379a4467a99afa2cc7e5acc8f053491437 100644
--- a/src/csr_regfile.sv
+++ b/src/csr_regfile.sv
@@ -400,8 +400,6 @@ module csr_regfile #(
                     dcsr_d = csr_wdata[31:0];
                     // debug is implemented
                     dcsr_d.xdebugver = 4'h4;
-                    // privilege level
-                    dcsr_d.prv = priv_lvl_q;
                     // currently not supported
                     dcsr_d.nmip      = 1'b0;
                     dcsr_d.stopcount = 1'b0;
@@ -662,6 +660,7 @@ module csr_regfile #(
 
             // caused by a breakpoint
             if (ex_i.valid && ex_i.cause == riscv::BREAKPOINT) begin
+                dcsr_d.prv = priv_lvl_o;
                 // check that we actually want to enter debug depending on the privilege level we are currently in
                 unique case (priv_lvl_o)
                     riscv::PRIV_LVL_M: begin
@@ -685,6 +684,7 @@ module csr_regfile #(
 
             // we've got a debug request
             if (ex_i.valid && ex_i.cause == riscv::DEBUG_REQUEST) begin
+                dcsr_d.prv = priv_lvl_o;
                 // save the PC
                 dpc_d = {{64-riscv::VLEN{pc_i[riscv::VLEN-1]}},pc_i};
                 // enter debug mode
@@ -697,6 +697,7 @@ module csr_regfile #(
 
             // single step enable and we just retired an instruction
             if (dcsr_q.step && commit_ack_i[0]) begin
+                dcsr_d.prv = priv_lvl_o;
                 // valid CTRL flow change
                 if (commit_instr_i[0].fu == CTRL_FLOW) begin
                     // we saved the correct target address during execute
@@ -989,7 +990,11 @@ module csr_regfile #(
             // floating-point registers
             fcsr_q                 <= 64'b0;
             // debug signals
+`ifdef DROMAJO
+            debug_mode_q           <= 1'b1;
+`else
             debug_mode_q           <= 1'b0;
+`endif
             dcsr_q                 <= '0;
             dcsr_q.prv             <= riscv::PRIV_LVL_M;
             dpc_q                  <= 64'b0;
diff --git a/src/dromajo_ram.sv b/src/dromajo_ram.sv
new file mode 100644
index 0000000000000000000000000000000000000000..2983801d79c4f4edab8fca825f5a108153bb8e6e
--- /dev/null
+++ b/src/dromajo_ram.sv
@@ -0,0 +1,129 @@
+// Copyright 2014 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License.  You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+/**
+ * This is the copied and modified version of Inferable, Synchronous Single
+ * -Port N x 64bit RAM with Byte-Wise Enable to support dromajo cosimulation
+ * 
+ * Current Maintainers:
+ * - Nursultan Kabylkas
+ */
+
+module dromajo_ram
+#(
+  parameter ADDR_WIDTH = 10,
+  parameter DATA_DEPTH = 1024, // usually 2**ADDR_WIDTH, but can be lower
+  parameter OUT_REGS   = 0     // set to 1 to enable outregs
+)(
+  input  logic                  Clk_CI,
+  input  logic                  Rst_RBI,
+  input  logic                  CSel_SI,
+  input  logic                  WrEn_SI,
+  input  logic [7:0]            BEn_SI,
+  input  logic [63:0]           WrData_DI,
+  input  logic [ADDR_WIDTH-1:0] Addr_DI,
+  output logic [63:0]           RdData_DO
+);
+
+  ////////////////////////////
+  // signals, localparams
+  ////////////////////////////
+
+  // needs to be consistent with the Altera implemenation below
+  localparam DATA_BYTES = 8;
+
+  logic [DATA_BYTES*8-1:0] RdData_DN;
+  logic [DATA_BYTES*8-1:0] RdData_DP;
+
+  logic [DATA_BYTES*8-1:0] Mem_DP[DATA_DEPTH-1:0];
+
+  ////////////////////////////
+  // DROMAJO COSIM OPTION
+  // sync rams
+  ////////////////////////////\
+  initial begin
+    integer hex_file, num_bytes;
+    longint address, value;
+    string f_name;
+    // init to 0
+    for (int k=0; k<DATA_DEPTH; k++) begin
+      Mem_DP[k] = 0;
+    end
+
+    // sync with dromajo
+    if ($value$plusargs("checkpoint=%s", f_name)) begin
+      hex_file = $fopen({f_name,".mainram.hex"}, "r");
+      while (!$feof(hex_file)) begin
+        num_bytes = $fscanf(hex_file, "%d %h\n", address, value);
+        //$display("%d %h", address, value);
+        Mem_DP[address] = value;
+      end
+      $display("Done syncing RAM with dromajo...\n");
+    end else begin
+      $display("Failed syncing RAM: provide path to a checkpoint.\n");
+    end
+  end
+
+  always_ff @(posedge Clk_CI) begin
+    if(CSel_SI) begin
+      if(WrEn_SI) begin
+        if(BEn_SI[0]) Mem_DP[Addr_DI][7:0]   <= WrData_DI[7:0];
+        if(BEn_SI[1]) Mem_DP[Addr_DI][15:8]  <= WrData_DI[15:8];
+        if(BEn_SI[2]) Mem_DP[Addr_DI][23:16] <= WrData_DI[23:16];
+        if(BEn_SI[3]) Mem_DP[Addr_DI][31:24] <= WrData_DI[31:24];
+        if(BEn_SI[4]) Mem_DP[Addr_DI][39:32] <= WrData_DI[39:32];
+        if(BEn_SI[5]) Mem_DP[Addr_DI][47:40] <= WrData_DI[47:40];
+        if(BEn_SI[6]) Mem_DP[Addr_DI][55:48] <= WrData_DI[55:48];
+        if(BEn_SI[7]) Mem_DP[Addr_DI][63:56] <= WrData_DI[63:56];
+      end
+      RdData_DN <= Mem_DP[Addr_DI];
+    end
+  end
+
+  ////////////////////////////
+  // optional output regs
+  ////////////////////////////
+
+  // output regs
+  generate
+    if (OUT_REGS>0) begin : g_outreg
+      always_ff @(posedge Clk_CI or negedge Rst_RBI) begin
+        if(Rst_RBI == 1'b0)
+        begin
+          RdData_DP  <= 0;
+        end
+        else
+        begin
+          RdData_DP  <= RdData_DN;
+        end
+      end
+    end
+  endgenerate // g_outreg
+
+  // output reg bypass
+  generate
+    if (OUT_REGS==0) begin : g_oureg_byp
+      assign RdData_DP  = RdData_DN;
+    end
+  endgenerate// g_oureg_byp
+
+  assign RdData_DO = RdData_DP;
+
+  ////////////////////////////
+  // assertions
+  ////////////////////////////
+
+  // pragma translate_off
+  assert property
+    (@(posedge Clk_CI) (longint'(2)**longint'(ADDR_WIDTH) >= longint'(DATA_DEPTH)))
+    else $error("depth out of bounds");
+  // pragma translate_on
+
+endmodule //dromajo_ram
diff --git a/src/util/sram.sv b/src/util/sram.sv
index 8d425827de84d8f1cabb0a2c7323fda9b466c566..4943cfc910f0a22a6c46a0d533bef49ca60b1fb9 100644
--- a/src/util/sram.sv
+++ b/src/util/sram.sv
@@ -21,7 +21,8 @@
 module sram #(
     parameter DATA_WIDTH = 64,
     parameter NUM_WORDS  = 1024,
-    parameter OUT_REGS   = 0    // enables output registers in FPGA macro (read lat = 2)
+    parameter OUT_REGS   = 0,    // enables output registers in FPGA macro (read lat = 2)
+    parameter DROMAJO_RAM  = 0
 )(
    input  logic                          clk_i,
    input  logic                          rst_ni,
@@ -53,6 +54,22 @@ end
 genvar k;
 generate
     for (k = 0; k<(DATA_WIDTH+63)/64; k++) begin
+      if (DROMAJO_RAM) begin
+        dromajo_ram #(
+          .ADDR_WIDTH($clog2(NUM_WORDS)),
+          .DATA_DEPTH(NUM_WORDS),
+          .OUT_REGS (0)
+        ) i_ram (
+           .Clk_CI    ( clk_i                     ),
+           .Rst_RBI   ( rst_ni                    ),
+           .CSel_SI   ( req_i                     ),
+           .WrEn_SI   ( we_i                      ),
+           .BEn_SI    ( be_aligned[k*8 +: 8]      ),
+           .WrData_DI ( wdata_aligned[k*64 +: 64] ),
+           .Addr_DI   ( addr_i                    ),
+           .RdData_DO ( rdata_aligned[k*64 +: 64] )
+        );
+      end else begin
         // unused byte-enable segments (8bits) are culled by the tool
         SyncSpRamBeNx64 #(
           .ADDR_WIDTH($clog2(NUM_WORDS)),
@@ -71,7 +88,7 @@ generate
            .Addr_DI   ( addr_i                    ),
            .RdData_DO ( rdata_aligned[k*64 +: 64] )
         );
+      end
     end
 endgenerate
-
 endmodule : sram
diff --git a/tb/ariane_tb.cpp b/tb/ariane_tb.cpp
index c64c4db6b03345dd14d97a815166066ba0772a4a..33ce024bccfe765bba6c18dbf4461dcc756582ab 100644
--- a/tb/ariane_tb.cpp
+++ b/tb/ariane_tb.cpp
@@ -44,12 +44,14 @@ static vluint64_t main_time = 0;
 
 static const char *verilog_plusargs[] = {"jtag_rbb_enable"};
 
+#ifndef DROMAJO
 extern dtm_t* dtm;
 extern remote_bitbang_t * jtag;
 
 void handle_sigterm(int sig) {
   dtm->stop();
 }
+#endif
 
 // Called by $time in Verilog converts to double, to match what SystemC does
 double sc_time_stamp () {
@@ -150,6 +152,9 @@ int main(int argc, char **argv) {
       case 'r': rbb_port = atoi(optarg);    break;
       case 'V': verbose = true;             break;
       case 'p': perf = true;                break;
+#ifdef DROMAJO
+			case 'D': break;
+#endif
 #if VM_TRACE
       case 'v': {
         vcdfile = strcmp(optarg, "-") == 0 ? stdout : fopen(optarg, "w");
@@ -175,6 +180,12 @@ int main(int argc, char **argv) {
           c = 'm';
           optarg = optarg+12;
         }
+#ifdef DROMAJO
+        else if (arg.substr(0, 12) == "+checkpoint=") {
+          c = 'D';
+          optarg = optarg+12;
+        }
+#endif
 #if VM_TRACE
         else if (arg.substr(0, 12) == "+dump-start=") {
           c = 'x';
@@ -233,11 +244,15 @@ int main(int argc, char **argv) {
   }
 
 done_processing:
+// allow proceeding without a binary if DROMAJO set,
+// binary will be loaded through checkpoint
+#ifndef DROMAJO
   if (optind == argc) {
     std::cerr << "No binary specified for emulator\n";
     usage(argv[0]);
     return 1;
   }
+#endif
   int htif_argc = 1 + argc - optind;
   htif_argv = (char **) malloc((htif_argc) * sizeof (char *));
   htif_argv[0] = argv[0];
@@ -246,9 +261,11 @@ done_processing:
   const char *vcd_file = NULL;
   Verilated::commandArgs(argc, argv);
 
+#ifndef DROMAJO
   jtag = new remote_bitbang_t(rbb_port);
   dtm = new dtm_t(htif_argc, htif_argv);
   signal(SIGTERM, handle_sigterm);
+#endif
 
   std::unique_ptr<Variane_testharness> top(new Variane_testharness);
 
@@ -279,7 +296,12 @@ done_processing:
   }
   top->rst_ni = 1;
 
+#ifndef DROMAJO
   while (!dtm->done() && !jtag->done()) {
+#else
+  // the simulation gets killed by dromajo
+  while (true) {
+#endif
     top->clk_i = 0;
     top->eval();
 #if VM_TRACE
@@ -308,6 +330,7 @@ done_processing:
     fclose(vcdfile);
 #endif
 
+#ifndef DROMAJO
   if (dtm->exit_code()) {
     fprintf(stderr, "%s *** FAILED *** (code = %d) after %ld cycles\n", htif_argv[1], dtm->exit_code(), main_time);
     ret = dtm->exit_code();
@@ -320,6 +343,7 @@ done_processing:
 
   if (dtm) delete dtm;
   if (jtag) delete jtag;
+#endif
 
   std::clock_t c_end = std::clock();
   auto t_end = std::chrono::high_resolution_clock::now();
diff --git a/tb/ariane_testharness.sv b/tb/ariane_testharness.sv
index fa6fe60cda988d275e17b58b77a5b894b2892f48..24ef549a3139a17d1ff972582853edaaf3c338be 100644
--- a/tb/ariane_testharness.sv
+++ b/tb/ariane_testharness.sv
@@ -17,7 +17,11 @@ module ariane_testharness #(
   parameter int unsigned AXI_USER_WIDTH    = 1,
   parameter int unsigned AXI_ADDRESS_WIDTH = 64,
   parameter int unsigned AXI_DATA_WIDTH    = 64,
+`ifdef DROMAJO
+  parameter bit          InclSimDTM        = 1'b0,
+`else
   parameter bit          InclSimDTM        = 1'b1,
+`endif
   parameter int unsigned NUM_WORDS         = 2**25,         // memory size
   parameter bit          StallRandomOutput = 1'b0,
   parameter bit          StallRandomInput  = 1'b0
@@ -319,13 +323,21 @@ module ariane_testharness #(
     .data_i ( rom_rdata               )
   );
 
+`ifdef DROMAJO
+  dromajo_bootrom i_bootrom (
+    .clk_i      ( clk_i     ),
+    .req_i      ( rom_req   ),
+    .addr_i     ( rom_addr  ),
+    .rdata_o    ( rom_rdata )
+  );
+`else
   bootrom i_bootrom (
     .clk_i      ( clk_i     ),
     .req_i      ( rom_req   ),
     .addr_i     ( rom_addr  ),
     .rdata_o    ( rom_rdata )
   );
-
+`endif
   // ------------------------------
   // Memory + Exclusive Access
   // ------------------------------
@@ -514,6 +526,9 @@ module ariane_testharness #(
 
   sram #(
     .DATA_WIDTH ( AXI_DATA_WIDTH ),
+`ifdef DROMAJO
+    .DROMAJO_RAM (1),
+`endif
     .NUM_WORDS  ( NUM_WORDS      )
   ) i_sram (
     .clk_i      ( clk_i                                                                       ),
diff --git a/tb/dpi/dromajo_cosim_dpi.cc b/tb/dpi/dromajo_cosim_dpi.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5a3d9bed34c2f699360f251f4359950fe429a937
--- /dev/null
+++ b/tb/dpi/dromajo_cosim_dpi.cc
@@ -0,0 +1,102 @@
+// Copyright 2017-2020 ETH Zurich and University of Bologna.
+// Copyright and related rights are licensed under the Solderpad Hardware
+// License, Version 0.51 (the "License"); you may not use this file except in
+// compliance with the License.  You may obtain a copy of the License at
+// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
+// or agreed to in writing, software, hardware and materials distributed under
+// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+//
+// Author: Nursultan Kabylkas, UCSC
+// Date: Jun 15, 2020
+// Description: DPI wrappers to interface with Dromajo RISC-V emulator
+
+#include <svdpi.h>
+#include <iostream>
+#include "dromajo_cosim.h"
+#include "stdlib.h"
+#include <string>
+#include <vector>
+
+/**
+ * pointer to the dromajo emulator this pointer gets
+ * accessed from RTL
+ */
+dromajo_cosim_state_t* dromajo_pointer;
+
+/**
+ * set the counter variable to number of instructions
+ * you want to commit after the cosim failure. This is 
+ * sometimes useful when debugging to see waveform 
+ * activity post failure
+ */
+bool kill_soon = false;
+uint32_t counter = 0;
+
+/**
+ * Initialize dromajo emulator
+ *
+ * This function should usually be called from the initial
+ * block in RTL.
+ *
+ * @param config (.cfg) file with the configurations
+ */
+extern "C" void init_dromajo(char* cfg_f_name) {
+  char *argv[] = {(char*)"Variane", cfg_f_name};
+
+  dromajo_pointer = dromajo_cosim_init(2, argv);
+}
+
+/**
+ * Progress the emulator
+ *
+ * This function progresses the emulator by one instruction
+ * and compares the results by the committed instruction
+ * in RTL. The following parameters are passed from RTL to 
+ * dromajo for comparison purposes.
+ *
+ * @param hart_id - id of the HART that is commiting instruction
+ * @param pc      - pc of the instruction being committed
+ * @param insn    - RISCV instruction being committed
+ * @param wdata   - the value being committed (what's going to destination register)
+ * @param cycle   - clock cycle number (optional, this is not compared)
+ */
+extern "C" void dromajo_step(int      hart_id,
+                             uint64_t pc,
+                             uint32_t insn,
+                             uint64_t wdata,
+                             uint64_t cycle) {
+  int exit_code;
+  do {
+    exit_code = dromajo_cosim_step(dromajo_pointer, hart_id, pc, insn, wdata, 0, true);
+  } while (exit_code == 0x3);
+
+  if (exit_code > 3) {
+    kill_soon = true;
+  } else if (exit_code == 0x2){
+    exit(0);
+  }
+
+  if (kill_soon) {
+    if (counter == 0) {
+      std::cout << "Cosim failed!" << std::endl;
+      exit(1);
+    } else {
+      std::cout << "Let's let it run for a couple of instructions" << std::endl;
+    }
+    counter--;
+  }
+}
+
+/**
+ * Redirects dromajo's execution flow on exception/interrupt
+ *
+ * @param hart_id - id of the HART that is trapping
+ * @param cause   - exception or interrupt cause
+ */
+extern "C" void dromajo_trap(int      hart_id,
+                             uint64_t cause) {
+  std::cout << "Dromajo trapping. Cause = " << cause << std::endl;
+  dromajo_cosim_raise_trap(dromajo_pointer, hart_id, cause);
+}
diff --git a/tb/dromajo b/tb/dromajo
new file mode 160000
index 0000000000000000000000000000000000000000..8acade8725d5e6cbf373304b348a8d77e0a5c713
--- /dev/null
+++ b/tb/dromajo
@@ -0,0 +1 @@
+Subproject commit 8acade8725d5e6cbf373304b348a8d77e0a5c713