From 55704f5c6582dcaa986f4cbb57017b6fa83b828b Mon Sep 17 00:00:00 2001
From: Daniel Newbrook <dwn1c21@soton.ac.uk>
Date: Wed, 11 Jun 2025 21:49:45 +0100
Subject: [PATCH] Fix CDC issues when clock div greater than 2

---
 .../logical/ahb_qspi_interface.sv             |  6 ++--
 .../qspi_controller/logical/qspi_clock_div.v  |  2 +-
 .../logical/qspi_controller.sv                | 18 +++++++---
 verif/cocotb/ahb_qspi_tests.py                | 36 ++++++++++++++++---
 4 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/logical/ahb_qspi_interface/logical/ahb_qspi_interface.sv b/logical/ahb_qspi_interface/logical/ahb_qspi_interface.sv
index e45a804..8f73eb9 100644
--- a/logical/ahb_qspi_interface/logical/ahb_qspi_interface.sv
+++ b/logical/ahb_qspi_interface/logical/ahb_qspi_interface.sv
@@ -120,11 +120,12 @@ always @(posedge HCLK or negedge HRESETn) begin
             if(AHB_QSPI_BUSY!=1'b1) begin
                 if(qspi_started==1'b0) begin
                     AHB_QSPI_ENABLE <= 1'b1;
-                    qspi_started <= 1'b1;
                 end
             end
-            if(AHB_QSPI_ENABLE_ACK)
+            if(AHB_QSPI_ENABLE_ACK) begin
                 AHB_QSPI_ENABLE <= 1'b0;
+                qspi_started <= 1'b1;
+            end
             if(qspi_started==1'b1) begin
                 if(AHB_QSPI_BUSY==1'b0) begin
                     HRDATA <= AHB_QSPI_RDATA_i;
@@ -132,6 +133,7 @@ always @(posedge HCLK or negedge HRESETn) begin
                 end
             end
         end else begin
+            AHB_QSPI_ENABLE <= 1'b0;
             qspi_started <= 1'b0;
             qspi_ready <=1'b0;
             AHB_QSPI_ADDR <= {HADDR[ADDR_W-1:4],4'b0000};
diff --git a/logical/qspi_controller/logical/qspi_clock_div.v b/logical/qspi_controller/logical/qspi_clock_div.v
index 7ece179..d4761af 100644
--- a/logical/qspi_controller/logical/qspi_clock_div.v
+++ b/logical/qspi_controller/logical/qspi_clock_div.v
@@ -21,8 +21,8 @@ always @(posedge HCLK or negedge HRESETn) begin
         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;
+            end else begin
                 QSPI_CLK_DIV_COUNTER <= QSPI_CLK_DIV_COUNTER + 1;
             end
         end else begin
diff --git a/logical/qspi_controller/logical/qspi_controller.sv b/logical/qspi_controller/logical/qspi_controller.sv
index 6e239ef..628079d 100644
--- a/logical/qspi_controller/logical/qspi_controller.sv
+++ b/logical/qspi_controller/logical/qspi_controller.sv
@@ -52,6 +52,16 @@ reg [3:0]   QSPI_IO_o_reg;
 reg [127:0] data_in_reg;
 reg [21:0]  last_QSPI_ADDR;
 
+reg QSPI_enable_sync;
+
+always @(posedge QSPI_SCLK_i or negedge HRESETn) begin
+    if(~HRESETn)begin
+        QSPI_enable_sync <= 1'b0;
+    end else begin 
+        QSPI_enable_sync <= QSPI_ENABLE;
+    end 
+end
+
 reg [127:0]   QSPI_WDATA_reg;
 
 assign QSPI_IO_o = QSPI_IO_o_reg;
@@ -67,9 +77,9 @@ end
 always_comb begin
     case(current_state)
         IDLE: begin
-            if(QSPI_ENABLE==1'b1 && QSPI_NO_CMD==1'b0) begin
+            if(QSPI_enable_sync==1'b1 && QSPI_NO_CMD==1'b0) begin
                 next_state = OP;
-            end else if(QSPI_ENABLE==1'b1 && QSPI_NO_CMD==1'b1) begin
+            end else if(QSPI_enable_sync==1'b1 && QSPI_NO_CMD==1'b1) begin
                 if(last_QSPI_ADDR==QSPI_ADDR)
                     next_state = NO_FETCH;
                 else
@@ -82,7 +92,7 @@ always_comb begin
         end
         NO_FETCH: begin
             QSPI_ENABLE_ACK = 1'b1;
-            if(QSPI_ENABLE==1'b0)
+            if(QSPI_enable_sync==1'b0)
                 next_state = IDLE;
         end
         OP: begin
@@ -374,7 +384,7 @@ always_comb begin
     end
 end
 
-assign QSPI_nCS = ((QSPI_ENABLE==1'b1) ||(current_state!=IDLE) || (QSPI_SCLK_e==1'b1))?1'b0:1'b1;
+assign QSPI_nCS = ((QSPI_enable_sync==1'b1) ||(current_state!=IDLE) || (QSPI_SCLK_e==1'b1))?1'b0:1'b1;
 //assign QSPI_SCLK_e = (current_state!=IDLE)?1'b1:1'b0;w
 
 assign QSPI_IO_e[3] = (QSPI_QIO_MODE==1'b1)?QSPI_IO_e_int:1'b1;
diff --git a/verif/cocotb/ahb_qspi_tests.py b/verif/cocotb/ahb_qspi_tests.py
index 9fd5858..e756259 100644
--- a/verif/cocotb/ahb_qspi_tests.py
+++ b/verif/cocotb/ahb_qspi_tests.py
@@ -27,8 +27,8 @@ class TB:
         self.log.setLevel(logging.DEBUG)
         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)
+        self.config_ahb_master = AHBLiteMaster(AHBBus.from_prefix(dut,"config", optional_signals = {"hsel":"HSEL", "hready_in":"HREADY_IN", "hburst":"HBURST"}), dut.HCLK, dut.HRESETn, 500)
+        self.data_ahb_master = AHBLiteMaster(AHBBus.from_prefix(dut,"data", optional_signals = {"hsel":"HSEL", "hready_in":"HREADY_IN", "hburst":"HBURST"}), dut.HCLK, dut.HRESETn, 500)
 
     async def cycle_reset(self):
         await ClockCycles(self.dut.HCLK,1)
@@ -228,7 +228,6 @@ 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*4):
-        tb.log.info("Read %d ",i)
         rdata = await tb.data_ahb_master.read(i*4 + base_addr,4)
         assert int(rdata[0]['data'],16)==data[i%4]
     end_time_uncached = cocotb.utils.get_sim_time(units='ns')
@@ -243,6 +242,32 @@ async def QSPI_READ_TESTS(dut):
     end_time_cached = cocotb.utils.get_sim_time(units='ns')
     dt_cached = end_time_cached - start_time_cached
 
+    await tb.config_ahb_master.write(0x34, 0x05)
+    tb.log.info("Clock divider changed")
+
+    await tb.config_ahb_master.write(CACHE_CONFIG_ADDR, 0x0)
+    tb.log.info("Disable Cache")
+    CACHE_CONFIG_tmp = await tb.config_ahb_master.read(CACHE_CONFIG_ADDR,4)
+    CACHE_CONFIG = int(CACHE_CONFIG_tmp[0]['data'],16)
+    assert CACHE_CONFIG == 0x0
+
+    CACHE_STATUS_tmp = await tb.config_ahb_master.read(CACHE_CONFIG_ADDR+0x04,4)
+    CACHE_STATUS = int(CACHE_STATUS_tmp[0]['data'],16)
+    while((CACHE_STATUS&(0x3))!=0):
+        CACHE_STATUS_tmp = await tb.config_ahb_master.read(CACHE_CONFIG_ADDR+0x00,4)
+        CACHE_STATUS_tmp = await tb.config_ahb_master.read(CACHE_CONFIG_ADDR+0x04,4)
+        CACHE_STATUS = int(CACHE_STATUS_tmp[0]['data'],16)
+        await Timer(time=10, units='us')
+
+
+    tb.log.info("Read 512x 16-bytes over AHB (uncached)")
+    start_time_slow = cocotb.utils.get_sim_time(units='ns')
+    for i in range(0,n_reads*4):
+        rdata = await tb.data_ahb_master.read(i*4+ base_addr,4)
+        assert int(rdata[0]['data'],16)==data[i%4]
+    end_time_slow = cocotb.utils.get_sim_time(units='ns')
+    dt_slow = end_time_slow - start_time_slow
+
 
     await tb.config_ahb_master.write(0x00, 0x01)
 
@@ -254,15 +279,18 @@ async def QSPI_READ_TESTS(dut):
     BW = n_reads*4/(dt*1e-3)
     BW_uncached = n_reads*4/(dt_uncached*1e-3)
     BW_cached = n_reads*4/(dt_cached*1e-3)
-
+    BW_slow = n_reads*4/(dt_slow*1e-3)
+    
     tb.log.info("dt APB: %f ns", dt)
     tb.log.info("dt caching: %f ns", dt_uncached)
     tb.log.info("dt cached: %f ns", dt_cached)
+    tb.log.info("dt slow: %f ns", dt_slow)
 
 
     tb.log.info("Bandwidth APB: %f MB/s", BW)
     tb.log.info("Bandwidth caching: %f MB/s", BW_uncached)
     tb.log.info("Bandwidth cached: %f MB/s", BW_cached)
+    tb.log.info("Bandwidth slow: %f MB/s", BW_slow)
 
 
 @cocotb.test()
-- 
GitLab