From 5d7f889102cf25ed18d003e6511496fe7bf1b2dc Mon Sep 17 00:00:00 2001
From: Daniel Newbrook <dwn1c21@soton.ac.uk>
Date: Thu, 23 Jan 2025 14:33:25 +0000
Subject: [PATCH] Design verified in Gate simulations

---
 .gitignore                                    |  14 ++
 README.md                                     |  17 +-
 asic/TSMC28nm/ahb_qspi_constraints.sdc        |  11 +
 asic/TSMC28nm/dc_synthesis.tcl                |  22 ++
 flist/Top/ahb_QSPI.flist                      |   1 +
 flist/Top/ahb_QSPI_ASIC.flist                 |  15 ++
 flist/Top/ahb_QSPI_ASIC_sv.flist              |   3 +
 flist/Top/ahb_QSPI_SIM_GATES.flist            |   4 +
 flows/makefile.asic                           |  13 ++
 logical/apb_qspi_regs/logical/apb_qspi_regs.v |  10 +-
 .../qspi_controller/logical/qspi_clock_div.v  |  36 ++++
 .../logical/qspi_controller.sv                | 188 ++++++++++--------
 logical/top_ahb_qspi/logical/top_ahb_qspi.v   |   2 +-
 makefile                                      |   8 +-
 verif/cocotb/ahb_qspi_cocotb.v                |  11 +
 verif/cocotb/ahb_qspi_tests.py                | 114 ++++++++---
 verif/cocotb/makefile                         |   7 +
 17 files changed, 361 insertions(+), 115 deletions(-)
 create mode 100644 asic/TSMC28nm/ahb_qspi_constraints.sdc
 create mode 100644 asic/TSMC28nm/dc_synthesis.tcl
 create mode 100644 flist/Top/ahb_QSPI_ASIC.flist
 create mode 100644 flist/Top/ahb_QSPI_ASIC_sv.flist
 create mode 100644 flist/Top/ahb_QSPI_SIM_GATES.flist
 create mode 100644 flows/makefile.asic
 create mode 100644 logical/qspi_controller/logical/qspi_clock_div.v

diff --git a/.gitignore b/.gitignore
index 02d8c92..48df0b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,5 +8,19 @@ verif/cocotb/ahb_qspi.vcd
 verif/cocotb/transcript
 verif/cocotb/sim_build/
 verif/cocotb/__pycache__/
+verif/cocotb/verdiLog
+verif/cocotb/novas*
+verif/cocotb/vsim.wlf
+verif/cocotb/wlft6jORYn
+verif/cocotb/inter.fsdb
 
 verif/VIP/SST26VF064B.v
+
+asic/TSMC28nm/*.mr
+asic/TSMC28nm/*pvl
+asic/TSMC28nm/*.syn
+asic/TSMC28nm/command.log
+asic/TSMC28nm/default.svf
+asic/TSMC28nm/*.log
+
+imp
\ No newline at end of file
diff --git a/README.md b/README.md
index 5a8c4cf..18bf7e7 100644
--- a/README.md
+++ b/README.md
@@ -31,4 +31,19 @@ Read bandwidth with 4 KB cache for 512x 32 bit reads, and system clock of 200 MH
 
 - Using APB: 5.8 MB/s
 - Using AHB(uncached, prefetch enabled): 32 MB/s
-- Using AHB(cached): 400 MB/s
\ No newline at end of file
+- Using AHB(cached): 400 MB/s
+
+## ToDo
+- Add programmable clock divider for QSPI
+- Add programmable op codes for AHB interface
+- Improve writing method over APB? (see below)
+- Add interrupts for QSPI finish
+
+## Writing over APB
+Currently the method for writing over APB to the flash is to write up to 4x 32 bit words to the APB registers and then tell the QSPI controller to write. However as there is a long latency after writing over QSPI for the flash to finish, this is not optimal. 
+
+The flash device we are targeting is a SST26VF064B device which allows up to 256 bytes to be written in a single SPI transaction (currently only writing 16 bytes per transaction). So proposals for improving this are as follows
+
+1. Just simply add an extra 240 bytes of registers to the APB controller. This is the simplest to do but I think that this will inflate the overall area of the IP by too much, however this makes the software side fairly simple. (i.e. write 256 bytes to APB-> send command to QSPI controller-> wait for QSPI transaction to finish-> poll QSPI status until write is complete)
+2. Add write fifo. This will be a lot smaller in terms of area. But will have to keep track of how many bytes get written over QSPI to limit to 256. This requires a bit of an overhaul in how the write transaction works but it means we can fully utilise the page program command. Software then becomes a little more complicated (i.e. write N bytes to APB-> send command to QSPI controller-> check if FIFO not full and send more data-> repeat last step 256/N times-> QSPI checks if FIFO is empty whilst the happens and stops transaction when empty-> poll QSPI status until write is complete). 
+
diff --git a/asic/TSMC28nm/ahb_qspi_constraints.sdc b/asic/TSMC28nm/ahb_qspi_constraints.sdc
new file mode 100644
index 0000000..a0f491c
--- /dev/null
+++ b/asic/TSMC28nm/ahb_qspi_constraints.sdc
@@ -0,0 +1,11 @@
+
+set HCLK "HCLK"
+set PCLK "PCLK"
+
+set HCLK_PERIOD 10
+set PCLK_PERIOD 10
+
+create_clock -name "$HCLK" -period $HCLK_PERIOD [get_ports HCLK]
+create_clock -name "$PCLK" -period $PCLK_PERIOD [get_ports PCLK]
+create_generated_clock -name "QSPI_SCLK" -source [get_ports HCLK] -divide_by 2 [get_pins u_qspi_controller/u_qspi_clock_div/QSPI_SCLK_i]
+set_max_fanout 10 [all_inputs]
diff --git a/asic/TSMC28nm/dc_synthesis.tcl b/asic/TSMC28nm/dc_synthesis.tcl
new file mode 100644
index 0000000..f241b8f
--- /dev/null
+++ b/asic/TSMC28nm/dc_synthesis.tcl
@@ -0,0 +1,22 @@
+set_host_options -max_cores 8
+set top_module top_ahb_qspi
+
+set search_path [list . $search_path /home/dwn1c21/SoC-Labs/phys_ip/arm/tsmc/cln28ht/sc12mcpp140z_base_svt_c35/r2p0/db]
+
+set target_library "sc12mcpp140z_cln28ht_base_svt_c35_ssg_cworstt_max_0p81v_125c.db"
+set link_library "sc12mcpp140z_cln28ht_base_svt_c35_ssg_cworstt_max_0p81v_125c.db"
+
+source $env(SOCLABS_AHB_QSPI_DIR)/imp/ASIC/flist/dc_flist.tcl
+elaborate $top_module
+current_design $top_module
+
+link
+
+read_sdc ./ahb_qspi_constraints.sdc
+
+compile_ultra 
+
+write -format verilog -hierarchy -output $env(SOCLABS_AHB_QSPI_DIR)/imp/ASIC/top_ahb_qspi_gates.v
+write_sdf -version 2.1 $env(SOCLABS_AHB_QSPI_DIR)/imp/ASIC/top_ahb_qspi.sdf
+
+exit
\ No newline at end of file
diff --git a/flist/Top/ahb_QSPI.flist b/flist/Top/ahb_QSPI.flist
index c8b0400..23607c2 100644
--- a/flist/Top/ahb_QSPI.flist
+++ b/flist/Top/ahb_QSPI.flist
@@ -6,6 +6,7 @@ $(SOCLABS_AHB_QSPI_DIR)/logical/ahb_qspi_interface/logical/ahb_qspi_interface.sv
 
 $(SOCLABS_AHB_QSPI_DIR)/logical/qspi_controller/logical/qspi_controller.sv
 $(SOCLABS_AHB_QSPI_DIR)/logical/qspi_controller/logical/qspi_controller_mux.v
+$(SOCLABS_AHB_QSPI_DIR)/logical/qspi_controller/logical/qspi_clock_div.v
 
 $(SOCLABS_AHB_QSPI_DIR)/logical/cache_subsytem/logical/cache_subsystem.v
 -f $(SOCLABS_AHB_QSPI_DIR)/flist/IP/CG092_cache.flist
diff --git a/flist/Top/ahb_QSPI_ASIC.flist b/flist/Top/ahb_QSPI_ASIC.flist
new file mode 100644
index 0000000..e930349
--- /dev/null
+++ b/flist/Top/ahb_QSPI_ASIC.flist
@@ -0,0 +1,15 @@
+
+$(SOCLABS_AHB_QSPI_DIR)/logical/top_ahb_qspi/logical/top_ahb_qspi.v
+$(SOCLABS_AHB_QSPI_DIR)/logical/apb_qspi_regs/logical/apb_qspi_regs.v
+
+$(SOCLABS_AHB_QSPI_DIR)/logical/qspi_controller/logical/qspi_controller_mux.v
+$(SOCLABS_AHB_QSPI_DIR)/logical/qspi_controller/logical/qspi_clock_div.v
+
+$(SOCLABS_AHB_QSPI_DIR)/logical/cache_subsytem/logical/cache_subsystem.v
+-f $(SOCLABS_AHB_QSPI_DIR)/flist/Top/ahb_QSPI_ASIC_sv.flist
+-f $(SOCLABS_AHB_QSPI_DIR)/flist/IP/CG092_cache.flist
+-f $(SOCLABS_AHB_QSPI_DIR)/flist/IP/corstone_101_ip.flist
+
+$(SOCLABS_AHB_QSPI_DIR)/logical/cache_models/generic/cache_ram.v
+
+$(ARM_IP_LIBRARY_PATH)/CG092/CG092-BU-50000-r2p0-00rel0/p_flash_cache_f0/logical/testbench/execution_tb/verilog/p_flash_cache_f0_sp_ram.v
\ No newline at end of file
diff --git a/flist/Top/ahb_QSPI_ASIC_sv.flist b/flist/Top/ahb_QSPI_ASIC_sv.flist
new file mode 100644
index 0000000..4d75241
--- /dev/null
+++ b/flist/Top/ahb_QSPI_ASIC_sv.flist
@@ -0,0 +1,3 @@
+$(SOCLABS_AHB_QSPI_DIR)/logical/ahb_qspi_interface/logical/ahb_qspi_interface.sv
+
+$(SOCLABS_AHB_QSPI_DIR)/logical/qspi_controller/logical/qspi_controller.sv
diff --git a/flist/Top/ahb_QSPI_SIM_GATES.flist b/flist/Top/ahb_QSPI_SIM_GATES.flist
new file mode 100644
index 0000000..c9fc784
--- /dev/null
+++ b/flist/Top/ahb_QSPI_SIM_GATES.flist
@@ -0,0 +1,4 @@
+-f $(SOCLABS_AHB_QSPI_DIR)/flist/VIP/ahb_QSPI_VIP.flist
+$(SOCLABS_AHB_QSPI_DIR)/imp/ASIC/top_ahb_qspi_gates.v
+
+/home/dwn1c21/SoC-Labs/phys_ip/arm/tsmc/cln28ht/sc12mcpp140z_base_svt_c35/r2p0/verilog/sc12mcpp140z_cln28ht_base_svt_c35.v
\ No newline at end of file
diff --git a/flows/makefile.asic b/flows/makefile.asic
new file mode 100644
index 0000000..8bb1ca0
--- /dev/null
+++ b/flows/makefile.asic
@@ -0,0 +1,13 @@
+# Location to build ASIC files
+IMP_ASIC_DIR := $(SOCLABS_AHB_QSPI_DIR)/imp/ASIC/
+
+
+
+TCL_ASIC_FLIST_DIR        := $(IMP_ASIC_DIR)/flist
+DC_OUTPUT_FILELIST := $(TCL_ASIC_FLIST_DIR)/dc_flist.tcl
+
+flist_synopsys: 
+	@mkdir -p $(TCL_ASIC_FLIST_DIR)
+	@(cd $(TCL_ASIC_FLIST_DIR); \
+    $(SOCLABS_SOCTOOLS_FLOW_DIR)/bin/filelist_compile.py -t -s -a -f $(DESIGN_VC) -o $(DC_OUTPUT_FILELIST) -i $(FLIST_INCLUDES) -r $(IMP_NANOSOC_ASIC_DIR)/src;)
+
diff --git a/logical/apb_qspi_regs/logical/apb_qspi_regs.v b/logical/apb_qspi_regs/logical/apb_qspi_regs.v
index fefe5b7..458e8c3 100644
--- a/logical/apb_qspi_regs/logical/apb_qspi_regs.v
+++ b/logical/apb_qspi_regs/logical/apb_qspi_regs.v
@@ -34,11 +34,11 @@ module apb_qspi_regs(
 );   
 // Registers
 // reg0 Control 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
-//      QSPI_QIO_MODE[0]                                                            |               |--> QSPI_QIO_MODE [0]
-//     XIP_ACTIVE [8]                                                               |------------------> XIP_ACTIVE [8]
-//  QSPI_MODE_CODE[23:16]
-//  QSPI_CONT_READ[24]
-//  QSPI_NO_CMD[25]
+//      QSPI_QIO_MODE[0]           |  |  |                    |                     |               |--> QSPI_QIO_MODE [0]
+//     XIP_ACTIVE [8]              |  |  |                    |                     |------------------> XIP_ACTIVE [8]
+//  QSPI_MODE_CODE[23:16]          |  |  |<------------------>|----------------------------------------> QSPI_MODE_CODE[23:16] 
+//  QSPI_CONT_READ[24]             |  |----------------------------------------------------------------> QSPI_CONT_READ[24] 
+//  QSPI_NO_CMD[25]                |-------------------------------------------------------------------> QSPI_NO_CMD[25]
 
 // reg1 Status
 
diff --git a/logical/qspi_controller/logical/qspi_clock_div.v b/logical/qspi_controller/logical/qspi_clock_div.v
new file mode 100644
index 0000000..40b2025
--- /dev/null
+++ b/logical/qspi_controller/logical/qspi_clock_div.v
@@ -0,0 +1,36 @@
+module qspi_clock_div(
+    input  wire         HCLK,
+    input  wire         HRESETn,
+    input  wire [7:0]   QSPI_CLK_DIV,
+    input  wire [1:0]   QSPI_SPI_MODE,
+    output wire         QSPI_SCLK_i
+);
+
+reg [7:0] QSPI_CLK_DIV_COUNTER;
+reg     QSPI_SCLK_reg;
+assign QSPI_SCLK_i = (QSPI_CLK_DIV==8'h00) ? HCLK : QSPI_SCLK_reg;
+
+// Clock Divider for SCLK
+always @(posedge HCLK or negedge HRESETn) begin
+    if(~HRESETn) begin
+        QSPI_CLK_DIV_COUNTER<=8'h00;
+        QSPI_SCLK_reg <= 1'b0;
+    end else begin 
+        if(QSPI_CLK_DIV==8'h01) begin 
+            QSPI_SCLK_reg <= ~QSPI_SCLK_reg;
+        end else if(QSPI_CLK_DIV!=8'h00) begin 
+            if(QSPI_CLK_DIV_COUNTER==QSPI_CLK_DIV-1'b1) begin 
+                QSPI_CLK_DIV_COUNTER <= 8'h00;
+            end else begin 
+                QSPI_SCLK_reg <= ~QSPI_SCLK_reg;
+                QSPI_CLK_DIV_COUNTER <= QSPI_CLK_DIV_COUNTER + 1;
+            end
+        end else begin 
+            QSPI_SCLK_reg <= QSPI_SPI_MODE[1];
+        end
+    end
+end
+
+
+
+endmodule
\ No newline at end of file
diff --git a/logical/qspi_controller/logical/qspi_controller.sv b/logical/qspi_controller/logical/qspi_controller.sv
index 30fee94..94c1127 100644
--- a/logical/qspi_controller/logical/qspi_controller.sv
+++ b/logical/qspi_controller/logical/qspi_controller.sv
@@ -13,7 +13,7 @@ module qspi_controller (
     input  wire         QSPI_WRITE,
     input  wire         QSPI_ADDR_EN,
     input  wire [3:0]   QSPI_DUMMY_CYCLES,
-    input  wire [3:0]   QSPI_N_RW_BYTES,
+    input  wire [4:0]   QSPI_N_RW_BYTES,
     input  wire [21:0]  QSPI_ADDR,
     input  wire [127:0] QSPI_WDATA,
     output reg  [127:0] QSPI_RDATA,
@@ -31,34 +31,19 @@ module qspi_controller (
 
 );
 
-reg [7:0] QSPI_CLK_DIV_COUNTER;
-reg     QSPI_SCLK_reg;
 wire    QSPI_SCLK_i;
 reg     QSPI_SCLK_e;
 
-assign QSPI_SCLK_i = (QSPI_CLK_DIV==8'h00) ? HCLK : QSPI_SCLK_reg;
-assign QSPI_SCLK = (QSPI_SCLK_e==1'b1) ? QSPI_SCLK_i : QSPI_SPI_MODE[1];
+qspi_clock_div u_qspi_clock_div(
+    .HCLK(HCLK),
+    .HRESETn(HRESETn),
+    .QSPI_CLK_DIV(QSPI_CLK_DIV),
+    .QSPI_SPI_MODE(QSPI_SPI_MODE),
+    .QSPI_SCLK_i(QSPI_SCLK_i)
+);
 
-// Clock Divider for SCLK
-always @(posedge HCLK or negedge HRESETn) begin
-    if(~HRESETn) begin
-        QSPI_CLK_DIV_COUNTER<=8'h00;
-        QSPI_SCLK_reg <= 1'b0;
-    end else begin 
-        if(QSPI_CLK_DIV==8'h01) begin 
-            QSPI_SCLK_reg <= ~QSPI_SCLK_reg;
-        end else if(QSPI_CLK_DIV!=8'h00) begin 
-            if(QSPI_CLK_DIV_COUNTER==QSPI_CLK_DIV-1'b1) begin 
-                QSPI_CLK_DIV_COUNTER <= 8'h00;
-            end else begin 
-                QSPI_SCLK_reg <= ~QSPI_SCLK_reg;
-                QSPI_CLK_DIV_COUNTER <= QSPI_CLK_DIV_COUNTER + 1'b1;
-            end
-        end else begin 
-            QSPI_SCLK_reg <= QSPI_SPI_MODE[1];
-        end
-    end
-end
+
+assign QSPI_SCLK = (QSPI_SCLK_e==1'b1) ? QSPI_SCLK_i : QSPI_SPI_MODE[1];
 
 enum {IDLE, NO_FETCH, OP, ADDR, MODE, DUMMY, DATA_O, DATA_I} current_state, next_state;
 
@@ -67,7 +52,7 @@ reg [4:0]   addr_counter;
 reg         mode_counter;
 reg [2:0]   data_counter;
 reg [3:0]   dummy_counter;
-reg [3:0]   byte_counter;
+reg [4:0]   byte_counter;
 reg [7:0]   op_code;
 reg [23:0]  addr_code;
 reg [7:0]   qspi_mode_reg;
@@ -110,11 +95,12 @@ always @(*) begin
         end
         OP: begin
             QSPI_ENABLE_ACK = 1'b1;
+            next_state = OP;
             if(QSPI_QIO_MODE==1'b1 & op_counter==3'h1) begin
                 QSPI_ENABLE_ACK = 1'b0;
                 if(QSPI_ADDR_EN)
                     next_state = ADDR;
-                else if(QSPI_DUMMY_CYCLES>4'h0)
+                else if(QSPI_DUMMY_CYCLES!=4'h0)
                     next_state = DUMMY;
                 else if(QSPI_READ)
                     next_state = DATA_I;
@@ -127,7 +113,7 @@ always @(*) begin
                 QSPI_ENABLE_ACK = 1'b0;
                 if(QSPI_ADDR_EN)
                     next_state = ADDR;
-                else if(QSPI_DUMMY_CYCLES>4'h0)
+                else if(QSPI_DUMMY_CYCLES!=4'h0)
                     next_state = DUMMY;
                 else if(QSPI_READ)
                     next_state = DATA_I;
@@ -135,6 +121,8 @@ always @(*) begin
                     next_state = DATA_O;
                 else
                     next_state = IDLE;
+            end else begin 
+                next_state = OP;
             end
         end     
         ADDR: begin
@@ -144,7 +132,7 @@ always @(*) begin
                 last_QSPI_ADDR = QSPI_ADDR;
                 if(QSPI_CONT_READ)
                     next_state = MODE;
-                else if(QSPI_DUMMY_CYCLES>4'h0)
+                else if(QSPI_DUMMY_CYCLES!=4'h0)
                     next_state = DUMMY;
                 else if(QSPI_READ)
                     next_state = DATA_I;
@@ -155,7 +143,7 @@ always @(*) begin
             end 
             else if(QSPI_QIO_MODE==1'b0 & addr_counter==5'h15) begin
                 QSPI_ENABLE_ACK = 1'b0;
-                if(QSPI_DUMMY_CYCLES>4'h0)
+                if(QSPI_DUMMY_CYCLES!=4'h0)
                     next_state = DUMMY;
                 else if(QSPI_READ)
                     next_state = DATA_I;
@@ -163,11 +151,13 @@ always @(*) begin
                     next_state = DATA_O;
                 else
                     next_state = IDLE;
+            end else begin 
+                next_state = ADDR;
             end
         end 
         MODE: begin 
             if(QSPI_QIO_MODE==1'b1 & mode_counter == 1'b0) begin 
-                if(QSPI_DUMMY_CYCLES>4'h0)
+                if(QSPI_DUMMY_CYCLES!=4'h0)
                     next_state = DUMMY;
                 else if(QSPI_READ)
                     next_state = DATA_I;
@@ -181,35 +171,57 @@ always @(*) begin
             end
         end
         DUMMY: begin
-            if(dummy_counter >= QSPI_DUMMY_CYCLES - 1'b1) begin
+            if(dummy_counter >= (QSPI_DUMMY_CYCLES - 1)) begin
                 if(QSPI_WRITE)
                     next_state = DATA_O;
                 else if(QSPI_READ)
                     next_state = DATA_I;
                 else
                     next_state = IDLE;
-            end 
+            end else begin
+                next_state = DUMMY;
+            end
         end 
         DATA_O: begin
-            if(QSPI_QIO_MODE==1'b0) begin 
-
-            end else begin 
-                if(byte_counter==QSPI_N_RW_BYTES) begin
-                    if(data_counter==3'h0)
-                        next_state = IDLE;
+            if(byte_counter==5'h1F) begin 
+                next_state = DATA_O;
+            end else begin
+                if(QSPI_QIO_MODE==1'b0) begin 
+                    if(byte_counter==QSPI_N_RW_BYTES) begin 
+                        if(data_counter == 3'h7)
+                            next_state = IDLE;
+                        else 
+                            next_state = DATA_O;
+                    end else begin 
+                        next_state = DATA_O;
+                    end 
+                end else begin 
+                    if(byte_counter==QSPI_N_RW_BYTES) begin
+                        if(data_counter==3'h0)
+                            next_state = IDLE;
+                        else
+                            next_state = DATA_O;
+                    end else begin 
+                        next_state = DATA_O;
+                    end
                 end
             end
         end 
         DATA_I: begin 
+            next_state = DATA_I;
             if(QSPI_QIO_MODE==1'b0) begin 
-                if((byte_counter==QSPI_N_RW_BYTES)) begin
-                    if(data_counter==3'h6)
+                if((byte_counter[3:0]==QSPI_N_RW_BYTES)) begin
+                    if(data_counter==3'h7)
                         next_state = IDLE;
+                    else 
+                        next_state = DATA_I;
                 end
             end else begin
-                if((byte_counter==QSPI_N_RW_BYTES)) begin
-                    if(data_counter==3'h1)
+                if((byte_counter==QSPI_N_RW_BYTES+1)) begin
+                    if(data_counter==3'h0)
                         next_state = IDLE;
+                    else 
+                        next_state = DATA_I;
                 end
             end
         end
@@ -220,6 +232,7 @@ reg QSPI_IO_e_int;
 
 always @(negedge QSPI_SCLK_i) begin
     if(current_state==OP) begin 
+        data_in_reg <= 128'd0;
         QSPI_IO_e_int <= 1'b1;
         QSPI_SCLK_e <= 1'b1;
         if(QSPI_QIO_MODE==1'b1) begin
@@ -256,7 +269,6 @@ always @(negedge QSPI_SCLK_i) begin
     end else if(current_state == DUMMY) begin 
         QSPI_IO_e_int <= 1'b1;
         QSPI_SCLK_e <= 1'b1;
-        dummy_counter <= dummy_counter + 1'b1;
     end else if(current_state == MODE) begin 
         QSPI_IO_e_int <=1'b1;
         QSPI_SCLK_e <= 1'b1;
@@ -272,57 +284,69 @@ always @(negedge QSPI_SCLK_i) begin
         QSPI_IO_o_reg<=4'hF;
         QSPI_IO_e_int <= 1'b1;
     end
+    if(current_state == DATA_I) begin
+        if(QSPI_QIO_MODE==1'b1) begin 
+            if(byte_counter!=QSPI_N_RW_BYTES+1)
+                data_in_reg <= {data_in_reg[123:0], QSPI_IO_i};
+        end else begin 
+            if(byte_counter!=QSPI_N_RW_BYTES+1)
+                data_in_reg <= {data_in_reg[126:0], QSPI_IO_i[1]};
+        end
+    end  
+        
 
     if(current_state != DATA_O) begin 
         QSPI_WDATA_reg <= QSPI_WDATA;
     end
 
-    if(current_state != DUMMY) begin 
-        dummy_counter <= 4'h0;
-    end
-
-
 end
-always @(posedge QSPI_SCLK_i) begin 
-    if(current_state==OP) begin 
-        data_in_reg <= 128'd0;
-        op_counter<=op_counter+1'b1;
-    end else begin 
+always @(posedge QSPI_SCLK_i or negedge HRESETn) begin 
+    if(~HRESETn) begin 
         op_counter <= 3'h0;
-    end
-    if(current_state==DATA_I || current_state ==DATA_O) begin
-        data_counter <= data_counter + 1'b1;
-        if(QSPI_QIO_MODE==1'b0 && data_counter == 3'h7) begin 
-            byte_counter <= byte_counter+1'b1;
-            data_counter <= 3'h0;
-        end else if (QSPI_QIO_MODE==1'b1 && data_counter >= 3'h1) begin
-            byte_counter <= byte_counter+1'b1;
-            data_counter <= 3'h0;
-        end
-    end else begin 
         data_counter <= 3'h7;
-        byte_counter <= 4'hF;
-    end
-    if(current_state == DATA_I) begin
-        if(QSPI_QIO_MODE==1'b1) begin 
-            data_in_reg <= {data_in_reg[123:0], QSPI_IO_i};
+        byte_counter <= 5'h1F;
+        dummy_counter <= 4'h0;
+        addr_counter <= 5'h00;
+        mode_counter <= 1'b1;
+    end else begin 
+        if(current_state==OP) begin 
+            op_counter<=op_counter+1;
         end else begin 
-            data_in_reg <= {data_in_reg[126:0], QSPI_IO_i[1]};
+            op_counter <= 3'h0;
         end
-    end
 
-    if(current_state == ADDR) begin 
-        addr_counter <= addr_counter + 1'b1;
-    end else begin 
-        addr_counter <= 5'h00;
-    end
+        if(current_state==DATA_I || current_state ==DATA_O) begin
+            data_counter <= data_counter + 1;
+            if(QSPI_QIO_MODE==1'b0 && data_counter == 3'h7) begin 
+                byte_counter <= byte_counter+1;
+                data_counter <= 3'h0;
+            end else if (QSPI_QIO_MODE==1'b1 && data_counter >= 3'h1) begin
+                byte_counter <= byte_counter+1;
+                data_counter <= 3'h0;
+            end
+        end else begin 
+            data_counter <= 3'h7;
+            byte_counter <= 5'h1F;
+        end
 
-    if(current_state == MODE) begin 
-        mode_counter <= mode_counter + 1'b1;
-    end else begin 
-        mode_counter <= 1'b1;
-    end
+        if(current_state == DUMMY) begin 
+            dummy_counter <= dummy_counter + 1;
+        end else begin 
+            dummy_counter <= 4'h0;
+        end
+
+        if(current_state == ADDR) begin 
+            addr_counter <= addr_counter + 1;
+        end else begin 
+            addr_counter <= 5'h00;
+        end
 
+        if(current_state == MODE) begin 
+            mode_counter <= mode_counter + 1;
+        end else begin 
+            mode_counter <= 1'b1;
+        end
+    end
 end
 
 // RDATA latch
diff --git a/logical/top_ahb_qspi/logical/top_ahb_qspi.v b/logical/top_ahb_qspi/logical/top_ahb_qspi.v
index ab151f6..735d925 100644
--- a/logical/top_ahb_qspi/logical/top_ahb_qspi.v
+++ b/logical/top_ahb_qspi/logical/top_ahb_qspi.v
@@ -407,7 +407,7 @@ qspi_controller u_qspi_controller(
     .QSPI_WRITE(QSPI_WRITE),
     .QSPI_ADDR_EN(QSPI_ADDR_EN),
     .QSPI_DUMMY_CYCLES(QSPI_DUMMY_CYCLES),
-    .QSPI_N_RW_BYTES(QSPI_N_RW_BYTES),
+    .QSPI_N_RW_BYTES({1'b0,QSPI_N_RW_BYTES}),
     .QSPI_ADDR(QSPI_ADDR),
     .QSPI_QIO_MODE(QSPI_QIO_MODE),
     .QSPI_WDATA(QSPI_WDATA),
diff --git a/makefile b/makefile
index 6cf9f96..652c61c 100644
--- a/makefile
+++ b/makefile
@@ -4,8 +4,9 @@ include $(SOCLABS_AHB_QSPI_DIR)/make.cfg
 # - Commonly Overloaded Variables
 #-------------------------------------
 # Simulator type (mti/vcs/xm)
-SIMULATOR   = mti
-
+SIMULATOR   = vcs
+GATE_SIMS  ?= no
+export GATE_SIMS
 #-------------------------------------
 # - Directory Setups
 #-------------------------------------
@@ -16,6 +17,8 @@ SIM_DIR ?= $(SIM_TOP_DIR)
 
 ifeq ($(ASIC),yes)
 	DESIGN_VC ?= $(SOCLABS_AHB_QSPI_DIR)/flist/Top/ahb_QSPI_ASIC.flist
+else ifeq ($(GATE_SIMS),yes)
+	DESIGN_VC ?= $(SOCLABS_AHB_QSPI_DIR)/flist/Top/ahb_QSPI_SIM_GATES.flist
 else
 	DESIGN_VC ?= $(SOCLABS_AHB_QSPI_DIR)/flist/Top/ahb_QSPI_SIM.flist
 endif
@@ -28,4 +31,5 @@ get_flash_model:
 #Include flows
 include ./flows/makefile.simulate
 include ./flows/makefile.lint
+include ./flows/makefile.asic
 export BP210_DIR
\ No newline at end of file
diff --git a/verif/cocotb/ahb_qspi_cocotb.v b/verif/cocotb/ahb_qspi_cocotb.v
index 119ef53..4a35390 100644
--- a/verif/cocotb/ahb_qspi_cocotb.v
+++ b/verif/cocotb/ahb_qspi_cocotb.v
@@ -128,6 +128,12 @@ top_ahb_qspi u_top_ahb_qspi(
     .QSPI_IO_e(QSPI_IO_e)
 );
 
+`ifdef GATE_SIMS
+initial begin
+    $sdf_annotate("/home/dwn1c21/SoC-Labs/ahb_qspi/imp/ASIC/top_ahb_qspi.sdf", u_top_ahb_qspi);
+end
+`endif 
+
 assign QSPI_IO[0] = QSPI_IO_e[0] ? QSPI_IO_o[0] : 1'bz;
 assign QSPI_IO[1] = QSPI_IO_e[1] ? QSPI_IO_o[1] : 1'bz;
 assign QSPI_IO[2] = QSPI_IO_e[2] ? QSPI_IO_o[2] : 1'bz;
@@ -143,5 +149,10 @@ sst26vf064b u_sst26vf064b(
     .SIO(QSPI_IO),
     .CEb(QSPI_nCS)
 );
+defparam u_sst26vf064b.I0.Tbe = 1_000; 
+defparam u_sst26vf064b.I0.Tse = 1_000; 
+defparam u_sst26vf064b.I0.Tsce = 1_000;
+defparam u_sst26vf064b.I0.Tpp = 1_000; 
+defparam u_sst26vf064b.I0.Tws = 1000;   
 
 endmodule 
\ No newline at end of file
diff --git a/verif/cocotb/ahb_qspi_tests.py b/verif/cocotb/ahb_qspi_tests.py
index 660fd77..3f2488e 100644
--- a/verif/cocotb/ahb_qspi_tests.py
+++ b/verif/cocotb/ahb_qspi_tests.py
@@ -22,13 +22,17 @@ class TB:
         
         self.log = logging.getLogger("cocotb.tb")
         self.log.setLevel(logging.DEBUG)
-        cocotb.start_soon(Clock(dut.HCLK, 5, units="ns").start())
+        self.dut.HRESETn.setimmediatevalue(0)
+        cocotb.start_soon(Clock(dut.HCLK, 10, units="ns").start())
         self.config_ahb_master = AHBLiteMaster(AHBBus.from_prefix(dut,"config", optional_signals = {"hsel":"HSEL", "hready_in":"HREADY_IN", "hburst":"HBURST"}), dut.HCLK, dut.HRESETn)
         self.data_ahb_master = AHBLiteMaster(AHBBus.from_prefix(dut,"data", optional_signals = {"hsel":"HSEL", "hready_in":"HREADY_IN", "hburst":"HBURST"}), dut.HCLK, dut.HRESETn)
 
     async def cycle_reset(self):
+        await ClockCycles(self.dut.HCLK,1)
+        await Timer(time=4.5, units='ns')
         self.dut.HRESETn.setimmediatevalue(0)
-        await ClockCycles(self.dut.HCLK,20)
+        await ClockCycles(self.dut.HCLK,40)
+        await Timer(time=4.5, units='ns')
         self.dut.HRESETn.setimmediatevalue(1)
         await ClockCycles(self.dut.HCLK,10)
             
@@ -84,8 +88,8 @@ async def LEAVE_QPI_MODE(dut, tb):
         data = await tb.config_ahb_master.read(0x04,4)
 
 async def QPI_READ_JEDIC(dut, tb):
-    await tb.config_ahb_master.write(0x08, 0x000210AF)
-    await tb.config_ahb_master.write(0x08, 0x000213AF)
+    await tb.config_ahb_master.write(0x08, 0x000220AF)
+    await tb.config_ahb_master.write(0x08, 0x000223AF)
     data = await tb.config_ahb_master.read(0x04,4)
     while(int(data[0]['data'],16)&1):
         await ClockCycles(dut.HCLK,10)
@@ -146,8 +150,18 @@ async def SPI_BLOCK_ERASE(dut, tb):
         await Timer(time=1, units='ms')
    
 async def SPI_READ_STAT_REG(dut,tb):
-    await tb.config_ahb_master.write(0x08, 0x00001005)
-    await tb.config_ahb_master.write(0x08, 0x00001305)
+    await tb.config_ahb_master.write(0x08, 0x00002005)
+    await tb.config_ahb_master.write(0x08, 0x00002305)
+    data = await tb.config_ahb_master.read(0x04,4)
+    while(int(data[0]['data'],16)&1):
+        await ClockCycles(dut.HCLK,10)
+        data = await tb.config_ahb_master.read(0x04,4)
+    data = await tb.config_ahb_master.read(0x10,4)
+    return (int(data[0]['data'],16))
+
+async def QPI_READ_STAT_REG(dut,tb):
+    await tb.config_ahb_master.write(0x08, 0x00002005)
+    await tb.config_ahb_master.write(0x08, 0x00002305)
     data = await tb.config_ahb_master.read(0x04,4)
     while(int(data[0]['data'],16)&1):
         await ClockCycles(dut.HCLK,10)
@@ -155,6 +169,7 @@ async def SPI_READ_STAT_REG(dut,tb):
     data = await tb.config_ahb_master.read(0x10,4)
     return (int(data[0]['data'],16))
 
+
 async def SPI_READ_SLOW(dut, tb):
     # Write Adress
     await tb.config_ahb_master.write(0x0C, 0x000000)
@@ -243,10 +258,10 @@ async def QPI_PAGE_PROGRAM(dut, tb, addr = 0, words=0, n_words = 1):
     while(int(data[0]['data'],16)&1):
         await ClockCycles(dut.HCLK,10)
         data = await tb.config_ahb_master.read(0x04,4)
-    SPI_STAT = await SPI_READ_STAT_REG(dut, tb)
+    SPI_STAT = await QPI_READ_STAT_REG(dut, tb)
     while(SPI_STAT&(1<<24)):
-        SPI_STAT = await SPI_READ_STAT_REG(dut, tb)
-        await Timer(time=100, units='us')
+        SPI_STAT = await QPI_READ_STAT_REG(dut, tb)
+        await Timer(time=1, units='us')
 
 
 
@@ -256,65 +271,82 @@ async def QSPI_TESTS(dut):
     tb = TB(dut)
     await tb.cycle_reset()
     
+    tb.log.info("Reset SPI")
     await SPI_RESET(dut, tb)
     
+    tb.log.info("Reading JEDIC in SPI mode")
     ID = 0x4326BF00
     rID = await SPI_READ_JEDIC(dut, tb)
     print(rID)
     assert rID == ID
     
+    tb.log.info("Setting QPI mode")
     await SET_QPI_MODE(dut, tb)
     await tb.config_ahb_master.write(0x00,0x1)
+    
+    tb.log.info("Reading JEDIC in QPI mode")
     rID = await QPI_READ_JEDIC(dut, tb)
     print(rID)
     assert rID == ID
-    
+
+    tb.log.info("Enable Write")
     await SPI_WRITE_ENABLE(dut, tb)
-    SPI_STAT = await SPI_READ_STAT_REG(dut, tb)
+    SPI_STAT = await QPI_READ_STAT_REG(dut, tb)
     WEL = SPI_STAT & (1<<25)
     assert WEL != 0
     
+    tb.log.info("Clear Protection and enable Write")
     await SPI_CLR_PROTECTION(dut, tb)
     await SPI_WRITE_ENABLE(dut, tb)
-    SPI_STAT = await SPI_READ_STAT_REG(dut, tb)
+    SPI_STAT = await QPI_READ_STAT_REG(dut, tb)
     WEL = SPI_STAT & (1<<25)
     assert WEL != 0
     
     # Write and read 32-bit word
+    tb.log.info("Page program 4x bytes")
     data = [0x18273456]
     await QPI_PAGE_PROGRAM(dut, tb, words=data, n_words=1)
     
+    tb.log.info("Read 4x bytes")
+
     await SPI_WRITE_DISABLE(dut,tb)
     rdata = await QPI_READ_WORDS(dut, tb, n_words=1)
     assert rdata == data
         
     # Write and read 2x 32=bit words
+    tb.log.info("Page program 8x bytes")
     data = [0x01234567, 0x89ABCDEF]
     await SPI_WRITE_ENABLE(dut, tb)
     await QPI_PAGE_PROGRAM(dut, tb, addr=0x100, words=data, n_words=2)
     
+    tb.log.info("Read 8x bytes")
     await SPI_WRITE_DISABLE(dut,tb)
     rdata = await QPI_READ_WORDS(dut, tb, addr=0x100, n_words=2)
     assert rdata == data
 
     # Write and read 3x 32=bit words
+    tb.log.info("Page program 12x bytes")
     data = [0x13243546, 0x97867564, 0x01234567]
     await SPI_WRITE_ENABLE(dut, tb)
     await QPI_PAGE_PROGRAM(dut, tb, addr=0x200, words=data, n_words=3)
     
     await SPI_WRITE_DISABLE(dut,tb)
+    tb.log.info("Read 12x bytes")
     rdata = await QPI_READ_WORDS(dut, tb, addr=0x200, n_words=3)
     assert rdata == data
 
     # Write and read 4x 32=bit words
+    tb.log.info("Page program 16x bytes")
     data = [0x13243546, 0x97867564, 0x89ABCDEF, 0x01234567]
     await SPI_WRITE_ENABLE(dut, tb)
     await QPI_PAGE_PROGRAM(dut, tb, addr=0x300, words=data, n_words=4)
     
+    tb.log.info("Read 16x bytes")
     await SPI_WRITE_DISABLE(dut,tb)
     rdata = await QPI_READ_WORDS(dut, tb, addr=0x300, n_words=4)
     assert rdata == data
-    
+
+    tb.log.info("Exit QPI MODE")
     await LEAVE_QPI_MODE(dut, tb)
     await tb.config_ahb_master.write(0x00,0x1)
 
@@ -323,42 +355,74 @@ async def QSPI_TESTS(dut):
 
 @cocotb.test()
 async def QSPI_READ_TESTS(dut):  
+    n_reads = 64
+
+
     tb = TB(dut)
     await tb.cycle_reset()
     
-
+    tb.log.info("Reset SPI")
     await SPI_RESET(dut, tb)
     
+    tb.log.info("Reading JEDIC in SPI mode")
     ID = 0x4326BF00
     rID = await SPI_READ_JEDIC(dut, tb)
-    print(rID)
     assert rID == ID
     
+    tb.log.info("Setting QPI mode")
     await SET_QPI_MODE(dut, tb)
     await tb.config_ahb_master.write(0x00,0x1)
+    
+    tb.log.info("Reading JEDIC in QPI mode")
     rID = await QPI_READ_JEDIC(dut, tb)
-    print(rID)
     assert rID == ID
     
+    await SPI_WRITE_ENABLE(dut, tb)
+    tb.log.info("Clear Protection and enable Write")
+    await SPI_CLR_PROTECTION(dut, tb)
+    await SPI_WRITE_ENABLE(dut, tb)
+    SPI_STAT = await QPI_READ_STAT_REG(dut, tb)
+    WEL = SPI_STAT & (1<<25)
+    assert WEL != 0
+    
+    tb.log.info("Page program 512x 16-bytes")
+    data = [0x13243546, 0x97867564, 0x89ABCDEF, 0x01234567]
+    for i in range(0,n_reads):
+        addr = i*16
+        await QPI_PAGE_PROGRAM(dut, tb, addr=addr, words=data, n_words=4)
+        await SPI_WRITE_ENABLE(dut, tb)
+        tb.log.info("Programmed %d words", i)
+    
+    await SPI_WRITE_DISABLE(dut,tb)
+
+    tb.log.info("Read 16x bytes over APB")
     rDATA = await QPI_READ_WORDS(dut, tb, addr=0x10000, n_words=4, cont_read=True)
+    
+    tb.log.info("Set Continuous Read mode")
     QSPI_CTRL_REG = await tb.config_ahb_master.read(0x00,4)
     QSPI_CTRL_REG = int(QSPI_CTRL_REG[0]['data'],16)
     QSPI_CTRL_REG = QSPI_CTRL_REG | (1<<25)
-    await tb.config_ahb_master.write(0x00, QSPI_CTRL_REG)
-    
-    n_reads = 512
+    await tb.config_ahb_master.write(0x00, QSPI_CTRL_REG)    
     
+    tb.log.info("Read %d x 16-bytes over APB in continous read mode",n_reads)
     start_time = cocotb.utils.get_sim_time(units='ns')
     for i in range(0,n_reads):
-        rDATA = await QPI_READ_WORDS(dut, tb, addr=0x10000, n_words=4, cont_read=True)
+        addr = i*16
+        rDATA = await QPI_READ_WORDS(dut, tb, addr=addr, n_words=4, cont_read=True)
+        assert rDATA==data
+        tb.log.info("Read %d words", i)
+
     end_time = cocotb.utils.get_sim_time(units='ns')
     dt= end_time-start_time
+
     
+    tb.log.info("Set AHB Mode")
     QSPI_CTRL_REG = await tb.config_ahb_master.read(0x00,4)
     QSPI_CTRL_REG = int(QSPI_CTRL_REG[0]['data'],16)
     QSPI_CTRL_REG = QSPI_CTRL_REG | (1<<8)
     await tb.config_ahb_master.write(0x00, QSPI_CTRL_REG)
-    
+
+    tb.log.info("Configure Cache")
     CACHE_STATUS_tmp = await tb.config_ahb_master.read(CACHE_CONFIG_ADDR+0x04,4)
     CACHE_STATUS = int(CACHE_STATUS_tmp[0]['data'],16)
     assert CACHE_STATUS==0  
@@ -377,15 +441,17 @@ async def QSPI_READ_TESTS(dut):
 
     
     
-    
+    tb.log.info("Read %d x 16-bytes over AHB (uncached)",n_reads)
     start_time_uncached = cocotb.utils.get_sim_time(units='ns')
-    for i in range(0,n_reads):
+    for i in range(0,n_reads*4):
         data = await tb.data_ahb_master.read(i*4,4)
     end_time_uncached = cocotb.utils.get_sim_time(units='ns')
     dt_uncached = end_time_uncached - start_time_uncached
     await Timer(time=10, units='us')
+    
+    tb.log.info("Read 512x 16-bytes over AHB (cached)")
     start_time_cached = cocotb.utils.get_sim_time(units='ns')
-    for i in range(0,n_reads):
+    for i in range(0,n_reads*4):
         data = await tb.data_ahb_master.read(i*4,4)
     end_time_cached = cocotb.utils.get_sim_time(units='ns')
     dt_cached = end_time_cached - start_time_cached
diff --git a/verif/cocotb/makefile b/verif/cocotb/makefile
index 6db4f36..c4a1c90 100644
--- a/verif/cocotb/makefile
+++ b/verif/cocotb/makefile
@@ -33,6 +33,11 @@ MODULE   = ahb_qspi_tests
 
 VERILOG_SOURCES += $(SOCLABS_AHB_QSPI_DIR)/verif/cocotb/ahb_qspi_cocotb.v
 
+ifeq ($(GATE_SIMS),yes)
+	EXTRA_ARGS += +define+ARM_UD_MODEL
+	EXTRA_ARGS += +define+GATE_SIMS
+endif
+
 ifeq ($(SIM), icarus)
 	PLUSARGS += -fst
 
@@ -53,6 +58,8 @@ else ifeq ($(SIM), verilator)
 	endif
 else ifeq ($(SIM), questa)
 	COMPILE_ARGS += +acc
+else ifeq ($(SIM), vcs)
+	COMPILE_ARGS += -kdb +neg_tchk
 endif
 include $(SOCLABS_AHB_QSPI_DIR)/simulate/sim/cocotb/makefile.flist
 include $(shell cocotb-config --makefiles)/Makefile.sim
-- 
GitLab