Browse Source

FPGA: rework shared memory access FSM

Maximilian Rehkopf 12 years ago
parent
commit
7df6909266
4 changed files with 322 additions and 281 deletions
  1. 127 109
      verilog/sd2snes/main.v
  2. 1 0
      verilog/sd2snes_cx4/cx4.v
  3. 181 155
      verilog/sd2snes_cx4/main.v
  4. 13 17
      verilog/sd2sneslite/main.v

+ 127 - 109
verilog/sd2snes/main.v

@@ -472,16 +472,20 @@ parameter ST_MCU_WR_WAIT  = 18'b000100000000000000;
 parameter ST_MCU_WR_WAIT2 = 18'b001000000000000000;
 parameter ST_MCU_WR_END   = 18'b010000000000000000;
 
-parameter ROM_RD_WAIT = 4'h4;
+parameter ROM_RD_WAIT = 4'h0;
 parameter ROM_RD_WAIT_MCU = 4'h6;
+parameter ROM_WR_WAIT = 4'h4;
 parameter ROM_WR_WAIT1 = 4'h2;
-parameter ROM_WR_WAIT2 = 4'h3;
-parameter ROM_WR_WAIT_MCU = 4'h6;
+parameter ROM_WR_WAIT2 = 4'h1;
+parameter ROM_WR_WAIT_MCU = 4'h5;
+
+parameter SNES_DEAD_TIMEOUT = 17'd88000; // 1ms
 
 reg [17:0] STATE;
 initial STATE = ST_IDLE;
 
 reg [7:0] SNES_DINr;
+reg [7:0] SNES_DOUTr;
 reg [7:0] ROM_DOUTr;
 
 assign DSPX_SNES_DATA_IN = SNES_DATA;
@@ -508,7 +512,7 @@ assign SNES_DATA = (snescmd_rd_enable & ~SNES_PARD) ? snescmd_regs[SNES_ADDR[3:0
                                   :dspx_dp_enable ? DSPX_SNES_DATA_OUT
                                   :msu_enable ? MSU_SNES_DATA_OUT
                                   :bsx_data_ovr ? BSX_SNES_DATA_OUT
-                                  :SNES_DINr /*(ROM_ADDR0 ? ROM_DATA[7:0] : ROM_DATA[15:8])*/) : 8'bZ;
+                                  :SNES_DOUTr /*(ROM_ADDR0 ? ROM_DATA[7:0] : ROM_DATA[15:8])*/) : 8'bZ;
 
 reg [3:0] ST_MEM_DELAYr;
 reg MCU_RD_PENDr;
@@ -520,25 +524,35 @@ always @(posedge CLK2) begin
   else if(STATE & (ST_SNES_RD_END | ST_SNES_WR_END)) NEED_SNES_ADDRr <= 1'b0;
 end
 
-wire ASSERT_SNES_ADDR = SNES_CPU_CLK & NEED_SNES_ADDRr;
+reg RQ_MCU_RDYr;
+initial RQ_MCU_RDYr = 1'b1;
+assign MCU_RDY = RQ_MCU_RDYr;
+
+reg ROM_SAr;
+initial ROM_SAr = 1'b1;
+//wire ROM_SA = SNES_FAKE_CLK | ((STATE == ST_IDLE) ^ (~RQ_MCU_RDYr & SNES_cycle_end));
+wire ROM_SA = ROM_SAr;
 
-assign ROM_ADDR  = (SD_DMA_TO_ROM) ? MCU_ADDR[23:1] : (ASSERT_SNES_ADDR) ? MAPPED_SNES_ADDR[23:1] : ROM_ADDRr[23:1];
-assign ROM_ADDR0 = (SD_DMA_TO_ROM) ? MCU_ADDR[0] : (ASSERT_SNES_ADDR) ? MAPPED_SNES_ADDR[0] : ROM_ADDRr[0];
+assign ROM_ADDR  = (SD_DMA_TO_ROM) ? MCU_ADDR[23:1] : (ROM_SA) ? MAPPED_SNES_ADDR[23:1] : ROM_ADDRr[23:1];
+assign ROM_ADDR0 = (SD_DMA_TO_ROM) ? MCU_ADDR[0] : (ROM_SA) ? MAPPED_SNES_ADDR[0] : ROM_ADDRr[0];
 
 reg ROM_WEr;
 initial ROM_WEr = 1'b1;
+reg ROM_DOUT_ENr;
+initial ROM_DOUT_ENr = 1'b0;
 
-reg RQ_MCU_RDYr;
-initial RQ_MCU_RDYr = 1'b1;
-assign MCU_RDY = RQ_MCU_RDYr;
+reg[17:0] SNES_DEAD_CNTr;
+initial SNES_DEAD_CNTr = 0;
 
 always @(posedge CLK2) begin
   if(MCU_RRQ) begin
     MCU_RD_PENDr <= 1'b1;
     RQ_MCU_RDYr <= 1'b0;
+    ROM_ADDRr <= MCU_ADDR;
   end else if(MCU_WRQ) begin
     MCU_WR_PENDr <= 1'b1;
     RQ_MCU_RDYr <= 1'b0;
+    ROM_ADDRr <= MCU_ADDR;
   end else if(STATE & (ST_MCU_RD_END | ST_MCU_WR_END)) begin
     MCU_RD_PENDr <= 1'b0;
     MCU_WR_PENDr <= 1'b0;
@@ -546,115 +560,119 @@ always @(posedge CLK2) begin
   end
 end
 
+always @(posedge CLK2) begin
+  if(~SNES_CPU_CLK) SNES_DEAD_CNTr <= SNES_DEAD_CNTr + 1;
+  else SNES_DEAD_CNTr <= 17'h0;
+end
+
+always @(posedge CLK2) begin
+  if(SNES_DEAD_CNTr > SNES_DEAD_TIMEOUT) SNES_DEADr <= 1'b1;
+  else if(SNES_CPU_CLK) SNES_DEADr <= 1'b0;
+end
+
 reg snes_wr_cycle;
 
 always @(posedge CLK2) begin
-  if(SNES_cycle_start & ~SNES_WR_start) begin
-    STATE <= ST_SNES_RD_ADDR;
-  end else if(SNES_WR_start) begin
-    STATE <= ST_SNES_WR_ADDR;
-  end else begin
-    case(STATE)
-	   ST_IDLE: begin
-		  ROM_ADDRr <= MAPPED_SNES_ADDR;
-		  if(MCU_RD_PENDr) STATE <= ST_MCU_RD_ADDR;
-		  else if(MCU_WR_PENDr) STATE <= ST_MCU_WR_ADDR;
-      else STATE <= ST_IDLE;
-		end
-		ST_SNES_RD_ADDR: begin
-		  STATE <= ST_SNES_RD_WAIT;
-		  ST_MEM_DELAYr <= ROM_RD_WAIT;
+  if(SNES_DEADr & SNES_CPU_CLK) STATE <= ST_IDLE; // interrupt+restart an ongoing MCU access when the SNES comes alive
+  else
+  case(STATE)
+    ST_IDLE: begin
+	   ROM_SAr <= 1'b1;
+		ROM_DOUT_ENr <= 1'b0;
+	   if(SNES_cycle_start & ~SNES_WRITE) begin
+		  STATE <= ST_SNES_WR_ADDR;
+		  if(IS_SAVERAM | IS_WRITABLE | IS_FLASHWR) begin
+		    ROM_WEr <= 1'b0;
+          ROM_DOUT_ENr <= 1'b1;
+        end
+		end else if(SNES_cycle_start) begin
+//		  STATE <= ST_SNES_RD_ADDR;		  
+        STATE <= ST_SNES_RD_END;
+        SNES_DOUTr <= (ROM_ADDR0 ? ROM_DATA[7:0] : ROM_DATA[15:8]);
+		end else if(SNES_DEADr & MCU_RD_PENDr) begin
+		  STATE <= ST_MCU_RD_ADDR;
+		end else if(SNES_DEADr & MCU_WR_PENDr) begin
+		  STATE <= ST_MCU_WR_ADDR;
 		end
-		ST_SNES_RD_WAIT: begin
-		  ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-		  if(ST_MEM_DELAYr == 4'h0) STATE <= ST_SNES_RD_END;
-		  else STATE <= ST_SNES_RD_WAIT;
-		  if(ROM_ADDR0) SNES_DINr <= ROM_DATA[7:0];
-		  else SNES_DINr <= ROM_DATA[15:8];
-		end
-		ST_SNES_RD_END: begin
-		  STATE <= ST_IDLE;
-		  if(ROM_ADDR0) SNES_DINr <= ROM_DATA[7:0];
-		  else SNES_DINr <= ROM_DATA[15:8];
-		end
-      ST_SNES_WR_ADDR: begin
-        ROM_WEr <= (!IS_FLASHWR & !IS_WRITABLE);
-        snes_wr_cycle <= 1'b1;
-		  STATE <= ST_SNES_WR_WAIT1;
-		  ST_MEM_DELAYr <= ROM_WR_WAIT1;
-		end
-		ST_SNES_WR_WAIT1: begin
-		  ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-		  if(ST_MEM_DELAYr == 4'h0) STATE <= ST_SNES_WR_DATA;
-		  else STATE <= ST_SNES_WR_WAIT1;
-		end
-		ST_SNES_WR_DATA: begin
-        ROM_DOUTr <= SNES_DATA;
+	 end
+	 ST_SNES_RD_ADDR: begin
+	   ST_MEM_DELAYr <= ROM_RD_WAIT;
+		STATE <= ST_SNES_RD_WAIT;
+	 end
+	 ST_SNES_RD_WAIT: begin
+	   ST_MEM_DELAYr <= ST_MEM_DELAYr - 1;
+//		if(ST_MEM_DELAYr == 0) begin
+//		end
+//		else STATE <= ST_SNES_RD_WAIT;
+	 end
+	 
+	 ST_SNES_WR_ADDR: begin
+	   ST_MEM_DELAYr <= ROM_WR_WAIT1;
+	   STATE <= ST_SNES_WR_WAIT1;
+	 end
+	 ST_SNES_WR_WAIT1: begin
+	   ST_MEM_DELAYr <= ST_MEM_DELAYr - 1;
+		if(ST_MEM_DELAYr == 0) begin
 		  ST_MEM_DELAYr <= ROM_WR_WAIT2;
-		  STATE <= ST_SNES_WR_WAIT2;
+        STATE <= ST_SNES_WR_WAIT2;
+		  ROM_DOUTr <= SNES_DATA;
 		end
-      ST_SNES_WR_WAIT2: begin
-		  ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-		  if(ST_MEM_DELAYr == 4'h0) STATE <= ST_SNES_WR_END;
-		  else STATE <= ST_SNES_WR_WAIT2;
-		end
-		ST_SNES_WR_END: begin
-		  STATE <= ST_IDLE;
+		else STATE <= ST_SNES_WR_WAIT1;
+	 end
+	 ST_SNES_WR_WAIT2: begin
+	   ST_MEM_DELAYr <= ST_MEM_DELAYr - 1;
+		if(ST_MEM_DELAYr == 0) begin
+        STATE <= ST_SNES_WR_END;
 		  ROM_WEr <= 1'b1;
-		  snes_wr_cycle <= 1'b0;
-		end
-		ST_MCU_RD_ADDR: begin
-		  ROM_ADDRr <= MCU_ADDR;
-		  STATE <= ST_MCU_RD_WAIT;
-		  ST_MEM_DELAYr <= ROM_RD_WAIT_MCU;
-		end
-		ST_MCU_RD_WAIT: begin
-		  ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-		  if(ST_MEM_DELAYr == 4'h0) begin
-		    STATE <= ST_MCU_RD_WAIT2;
-			 ST_MEM_DELAYr <= 4'h2;
-		  end
-		  else STATE <= ST_MCU_RD_WAIT;
-		  if(ROM_ADDR0) MCU_DINr <= ROM_DATA[7:0];
-		  else MCU_DINr <= ROM_DATA[15:8];
-      end
-		ST_MCU_RD_WAIT2: begin
-		  ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-		  if(ST_MEM_DELAYr == 4'h0) begin
-		    STATE <= ST_MCU_RD_END;
-		  end else STATE <= ST_MCU_RD_WAIT2;
 		end
-		ST_MCU_RD_END: begin
-		  STATE <= ST_IDLE;
-		end
-		ST_MCU_WR_ADDR: begin
-		  ROM_ADDRr <= MCU_ADDR;
-		  STATE <= ST_MCU_WR_WAIT;
-		  ST_MEM_DELAYr <= ROM_WR_WAIT_MCU;
-		  ROM_DOUTr <= MCU_DOUT;
-		  ROM_WEr <= 1'b0;
-		end
-		ST_MCU_WR_WAIT: begin
-		  ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-		  if(ST_MEM_DELAYr == 4'h0) begin
-          ROM_WEr <= 1'b1;
-		    STATE <= ST_MCU_WR_WAIT2;
-			 ST_MEM_DELAYr <= 4'h2;
-		  end
-		  else STATE <= ST_MCU_WR_WAIT;
-      end
-		ST_MCU_WR_WAIT2: begin
-		  ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-		  if(ST_MEM_DELAYr == 4'h0) begin
-		    STATE <= ST_MCU_WR_END;
-        end else STATE <= ST_MCU_WR_WAIT2;
+		else STATE <= ST_SNES_WR_WAIT2;
+    end
+	 ST_SNES_RD_END, ST_SNES_WR_END: begin
+	   ROM_DOUT_ENr <= 1'b0;		
+      if(MCU_RD_PENDr) begin
+        STATE <= ST_MCU_RD_ADDR;
+      end else if(MCU_WR_PENDr) begin
+        STATE <= ST_MCU_WR_ADDR;
+      end else STATE <= ST_IDLE;
+    end
+    ST_MCU_RD_ADDR: begin
+      ROM_SAr <= 1'b0;
+		ST_MEM_DELAYr <= ROM_RD_WAIT_MCU;
+		STATE <= ST_MCU_RD_WAIT;
+	 end
+	 ST_MCU_RD_WAIT: begin
+	   ST_MEM_DELAYr <= ST_MEM_DELAYr - 1;
+		if(ST_MEM_DELAYr == 0) begin
+        STATE <= ST_MCU_RD_END;
 		end
-		ST_MCU_WR_END: begin
-		  STATE <= ST_IDLE;
+		else STATE <= ST_MCU_RD_WAIT;
+	 end
+	 ST_MCU_RD_END: begin
+      MCU_DINr <= ROM_ADDRr[0] ? ROM_DATA[7:0] : ROM_DATA[15:8];
+	   STATE <= ST_IDLE;
+	 end
+	 
+	 ST_MCU_WR_ADDR: begin
+      ROM_DOUTr <= MCU_DOUT;
+      ROM_SAr <= 1'b0;
+	   ST_MEM_DELAYr <= ROM_WR_WAIT_MCU;
+		STATE <= ST_MCU_WR_WAIT;
+		ROM_DOUT_ENr <= 1'b1;
+		ROM_WEr <= 1'b0;
+	 end
+	 ST_MCU_WR_WAIT: begin
+	   ST_MEM_DELAYr <= ST_MEM_DELAYr - 1;
+		if(ST_MEM_DELAYr == 0) begin
+		  ROM_WEr <= 1'b1;
+		  STATE <= ST_MCU_WR_END;
 		end
-
-    endcase
-  end
+		else STATE <= ST_MCU_WR_WAIT;	 
+	 end
+	 ST_MCU_WR_END: begin
+		ROM_DOUT_ENr <= 1'b0;
+	   STATE <= ST_IDLE;
+	 end
+  endcase
 end
 
 always @(posedge SYSCLK2) begin

+ 1 - 0
verilog/sd2snes_cx4/cx4.v

@@ -334,6 +334,7 @@ always @(posedge CLK) begin
         CACHE_ST <= ST_CACHE_START;
         cache_pgmpage <= cx4_mmio_pgmpage;
         cache_cachepage <= cx4_mmio_cachepage;
+		  cx4_busy[BUSY_CACHE] <= 1'b1;
       end else if(cpu_cache_en
          & (~cachevalid[~cpu_page]
             | |(cachetag[~cpu_page] ^ cpu_p))) begin

+ 181 - 155
verilog/sd2snes_cx4/main.v

@@ -87,6 +87,9 @@ always @(posedge CLK2) begin
 end
 wire [23:0] SNES_ADDR = SNES_ADDR_r[2] & SNES_ADDR_r[1];
 
+wire [7:0] CX4_SNES_DATA_IN;
+wire [7:0] CX4_SNES_DATA_OUT;
+
 wire [7:0] spi_cmd_data;
 wire [7:0] spi_param_data;
 wire [7:0] spi_input_data;
@@ -114,9 +117,6 @@ wire [7:0] MSU_SNES_DATA_OUT;
 wire [5:0] msu_status_reset_bits;
 wire [5:0] msu_status_set_bits;
 
-wire [7:0] CX4_SNES_DATA_IN;
-wire [7:0] CX4_SNES_DATA_OUT;
-
 wire [23:0] MAPPED_SNES_ADDR;
 wire ROM_ADDR0;
 
@@ -369,25 +369,28 @@ parameter ST_MCU_WR_WAIT2 = 21'b000001000000000000000;
 parameter ST_MCU_WR_END   = 21'b000010000000000000000;
 parameter ST_CX4_RD_ADDR  = 21'b000100000000000000000;
 parameter ST_CX4_RD_WAIT  = 21'b001000000000000000000;
-parameter ST_CX4_RD_WAIT2 = 21'b010000000000000000000;
-parameter ST_CX4_RD_END   = 21'b100000000000000000000;
+parameter ST_CX4_RD_END   = 21'b010000000000000000000;
 
-parameter ROM_RD_WAIT = 4'h4;
+parameter ROM_RD_WAIT = 4'h0;
 parameter ROM_RD_WAIT_MCU = 4'h6;
+parameter ROM_WR_WAIT = 4'h4;
 parameter ROM_WR_WAIT1 = 4'h2;
-parameter ROM_WR_WAIT2 = 4'h3;
-parameter ROM_WR_WAIT_MCU = 4'h6;
+parameter ROM_WR_WAIT2 = 4'h1;
+parameter ROM_WR_WAIT_MCU = 4'h5;
 parameter ROM_RD_WAIT_CX4 = 4'h6;
 
+parameter SNES_DEAD_TIMEOUT = 17'd88000; // 1ms
+
 reg [20:0] STATE;
 initial STATE = ST_IDLE;
 
-assign MSU_SNES_DATA_IN = SNES_DATA;
-assign CX4_SNES_DATA_IN = SNES_DATA;
-
 reg [7:0] SNES_DINr;
+reg [7:0] SNES_DOUTr;
 reg [7:0] ROM_DOUTr;
 
+assign MSU_SNES_DATA_IN = SNES_DATA;
+assign CX4_SNES_DATA_IN = SNES_DATA;
+
 reg [7:0] r213fr;
 reg r213f_forceread;
 reg [2:0] r213f_delay;
@@ -419,25 +422,61 @@ always @(posedge CLK2) begin
 end
 
 wire IS_CART = IS_ROM | IS_SAVERAM | IS_WRITABLE;
-wire ASSERT_SNES_ADDR = SNES_CPU_CLK & NEED_SNES_ADDRr & IS_CART & ~cx4_active;
 
-assign ROM_ADDR  = (SD_DMA_TO_ROM) ? MCU_ADDR[23:1] : (ASSERT_SNES_ADDR) ? MAPPED_SNES_ADDR[23:1] : ROM_ADDRr[23:1];
-assign ROM_ADDR0 = (SD_DMA_TO_ROM) ? MCU_ADDR[0] : (ASSERT_SNES_ADDR) ? MAPPED_SNES_ADDR[0] : ROM_ADDRr[0];
+reg RQ_MCU_RDYr;
+initial RQ_MCU_RDYr = 1'b1;
+assign MCU_RDY = RQ_MCU_RDYr;
+
+reg RQ_CX4_RDYr;
+initial RQ_CX4_RDYr = 1'b1;
+assign CX4_RDY = RQ_CX4_RDYr;
+
+reg ROM_SAr;
+initial ROM_SAr = 1'b1;
+wire ROM_SA = ROM_SAr;
+
+reg ROM_CAr;
+initial ROM_CAr = 1'b0;
+wire ROM_CA = ROM_CAr;
+
+reg [23:0] CX4_ADDRr;
+
+assign ROM_ADDR  = (SD_DMA_TO_ROM) ? MCU_ADDR[23:1] : ROM_CA ? CX4_ADDRr[23:1] : ROM_SA ? MAPPED_SNES_ADDR[23:1] : ROM_ADDRr[23:1];
+assign ROM_ADDR0 = (SD_DMA_TO_ROM) ? MCU_ADDR[0] : ROM_CA ? CX4_ADDRr[0] : ROM_SA ? MAPPED_SNES_ADDR[0] : ROM_ADDRr[0];
 
 reg ROM_WEr;
 initial ROM_WEr = 1'b1;
+reg ROM_DOUT_ENr;
+initial ROM_DOUT_ENr = 1'b0;
 
-reg RQ_MCU_RDYr;
-initial RQ_MCU_RDYr = 1'b1;
-assign MCU_RDY = RQ_MCU_RDYr;
+reg[17:0] SNES_DEAD_CNTr;
+initial SNES_DEAD_CNTr = 0;
+
+always @(posedge CLK2) begin
+  if(cx4_active) begin
+    if(CX4_RRQ) begin
+	   CX4_RD_PENDr <= 1'b1;
+		RQ_CX4_RDYr <= 1'b0;
+		CX4_ADDRr <= CX4_ADDR;
+	 end else if(STATE == ST_CX4_RD_END) begin
+	   CX4_RD_PENDr <= 1'b0;
+		RQ_CX4_RDYr <= 1'b1;
+	 end
+  end else begin
+    CX4_RD_PENDr <= 1'b0;
+	 RQ_CX4_RDYr <= 1'b1;
+  end
+end
 
 always @(posedge CLK2) begin
   if(MCU_RRQ) begin
     MCU_RD_PENDr <= 1'b1;
     RQ_MCU_RDYr <= 1'b0;
+    ROM_ADDRr <= MCU_ADDR;
   end else if(MCU_WRQ) begin
     MCU_WR_PENDr <= 1'b1;
     RQ_MCU_RDYr <= 1'b0;
+    ROM_ADDRr <= MCU_ADDR;
   end else if(STATE & (ST_MCU_RD_END | ST_MCU_WR_END)) begin
     MCU_RD_PENDr <= 1'b0;
     MCU_WR_PENDr <= 1'b0;
@@ -445,151 +484,138 @@ always @(posedge CLK2) begin
   end
 end
 
-reg RQ_CX4_RDYr;
-initial RQ_CX4_RDYr = 1'b1;
-assign CX4_RDY = RQ_CX4_RDYr;
-
 always @(posedge CLK2) begin
-  if(CX4_RRQ) begin
-    CX4_RD_PENDr <= 1'b1;
-    RQ_CX4_RDYr <= 1'b0;
-  end else if(STATE == ST_CX4_RD_WAIT && ST_MEM_DELAYr == 4'h0) begin
-    CX4_RD_PENDr <= 1'b0;
-    RQ_CX4_RDYr <= 1'b1;
-  end
+  if(~SNES_CPU_CLK) SNES_DEAD_CNTr <= SNES_DEAD_CNTr + 1;
+  else SNES_DEAD_CNTr <= 17'h0;
 end
 
-reg snes_wr_cycle;
+always @(posedge CLK2) begin
+  if(SNES_DEAD_CNTr > SNES_DEAD_TIMEOUT) SNES_DEADr <= 1'b1;
+  else if(SNES_CPU_CLK) SNES_DEADr <= 1'b0;
+end
 
 always @(posedge CLK2) begin
-  if(SNES_cycle_start & IS_CART & ~cx4_active) begin
-    STATE <= ST_SNES_RD_ADDR;
-  end else if(SNES_WR_start & IS_CART & ~cx4_active) begin
-    STATE <= ST_SNES_WR_ADDR;
-  end else begin
-    case(STATE)
-      ST_IDLE: begin
-        ROM_ADDRr <= MAPPED_SNES_ADDR;
-        if(CX4_RD_PENDr) begin
-          STATE <= ST_CX4_RD_WAIT;
-          ROM_ADDRr <= CX4_ADDR;
-          ST_MEM_DELAYr <= ROM_RD_WAIT_CX4;
-        end else if(~cx4_active && ~ASSERT_SNES_ADDR) begin
-          if(MCU_RD_PENDr) STATE <= ST_MCU_RD_ADDR;
-          else if(MCU_WR_PENDr) STATE <= ST_MCU_WR_ADDR;
-          else STATE <= ST_IDLE;
+  if(SNES_DEADr & SNES_CPU_CLK) STATE <= ST_IDLE; // interrupt+restart an ongoing MCU access when the SNES comes alive
+  else
+  case(STATE)
+    ST_IDLE: begin
+	   ROM_SAr <= 1'b1;
+		ROM_CAr <= 1'b0;
+		ROM_DOUT_ENr <= 1'b0;
+		if(cx4_active) begin
+        if(CX4_RD_PENDr) STATE <= ST_CX4_RD_ADDR;
+		end else if(SNES_cycle_start & ~SNES_WRITE) begin
+		  STATE <= ST_SNES_WR_ADDR;
+		  if(IS_SAVERAM | IS_WRITABLE) begin
+		    ROM_WEr <= 1'b0;
+          ROM_DOUT_ENr <= 1'b1;
         end
-        else STATE <= ST_IDLE;
-      end
-      ST_SNES_RD_ADDR: begin
-        STATE <= ST_SNES_RD_WAIT;
-        ST_MEM_DELAYr <= ROM_RD_WAIT;
-      end
-      ST_SNES_RD_WAIT: begin
-        ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-        if(ST_MEM_DELAYr == 4'h0) STATE <= ST_SNES_RD_END;
-        else STATE <= ST_SNES_RD_WAIT;
-        if(ROM_ADDR0) SNES_DINr <= ROM_DATA[7:0];
-        else SNES_DINr <= ROM_DATA[15:8];
-      end
-      ST_SNES_RD_END: begin
-        STATE <= ST_IDLE;
-        if(ROM_ADDR0) SNES_DINr <= ROM_DATA[7:0];
-        else SNES_DINr <= ROM_DATA[15:8];
-      end
-      ST_SNES_WR_ADDR: begin
-        ROM_WEr <= (!IS_WRITABLE);
-        snes_wr_cycle <= 1'b1;
-        STATE <= ST_SNES_WR_WAIT1;
-        ST_MEM_DELAYr <= ROM_WR_WAIT1;
-      end
-      ST_SNES_WR_WAIT1: begin
-        ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-        if(ST_MEM_DELAYr == 4'h0) STATE <= ST_SNES_WR_DATA;
-        else STATE <= ST_SNES_WR_WAIT1;
-      end
-      ST_SNES_WR_DATA: begin
-        ROM_DOUTr <= SNES_DATA;
-        ST_MEM_DELAYr <= ROM_WR_WAIT2;
+		end else if(SNES_cycle_start) begin
+//		  STATE <= ST_SNES_RD_ADDR;		  
+        STATE <= ST_SNES_RD_END;
+        SNES_DOUTr <= (ROM_ADDR0 ? ROM_DATA[7:0] : ROM_DATA[15:8]);
+		end else if(SNES_DEADr & MCU_RD_PENDr) begin
+		  STATE <= ST_MCU_RD_ADDR;
+		end else if(SNES_DEADr & MCU_WR_PENDr) begin
+		  STATE <= ST_MCU_WR_ADDR;
+		end
+	 end
+	 ST_SNES_RD_ADDR: begin
+	   ST_MEM_DELAYr <= ROM_RD_WAIT;
+		STATE <= ST_SNES_RD_WAIT;
+	 end
+	 ST_SNES_RD_WAIT: begin
+	   ST_MEM_DELAYr <= ST_MEM_DELAYr - 1;
+//		if(ST_MEM_DELAYr == 0) begin
+//		end
+//		else STATE <= ST_SNES_RD_WAIT;
+	 end
+	 
+	 ST_SNES_WR_ADDR: begin
+	   ST_MEM_DELAYr <= ROM_WR_WAIT1;
+	   STATE <= ST_SNES_WR_WAIT1;
+	 end
+	 ST_SNES_WR_WAIT1: begin
+	   ST_MEM_DELAYr <= ST_MEM_DELAYr - 1;
+		if(ST_MEM_DELAYr == 0) begin
+		  ST_MEM_DELAYr <= ROM_WR_WAIT2;
         STATE <= ST_SNES_WR_WAIT2;
-      end
-      ST_SNES_WR_WAIT2: begin
-        ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-        if(ST_MEM_DELAYr == 4'h0) STATE <= ST_SNES_WR_END;
-        else STATE <= ST_SNES_WR_WAIT2;
-      end
-      ST_SNES_WR_END: begin
-        STATE <= ST_IDLE;
-        ROM_WEr <= 1'b1;
-        snes_wr_cycle <= 1'b0;
-      end
-      ST_MCU_RD_ADDR: begin
-        ROM_ADDRr <= MCU_ADDR;
-        STATE <= ST_MCU_RD_WAIT;
-        ST_MEM_DELAYr <= ROM_RD_WAIT_MCU;
-      end
-      ST_MCU_RD_WAIT: begin
-        ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-        if(ST_MEM_DELAYr == 4'h0) begin
-          STATE <= ST_MCU_RD_WAIT2;
-          ST_MEM_DELAYr <= 4'h2;
-          if(ROM_ADDR0) MCU_DINr <= ROM_DATA[7:0];
-          else MCU_DINr <= ROM_DATA[15:8];
-        end
-        else STATE <= ST_MCU_RD_WAIT;
-      end
-      ST_MCU_RD_WAIT2: begin
-        ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-        if(ST_MEM_DELAYr == 4'h0) begin
-          STATE <= ST_MCU_RD_END;
-        end else STATE <= ST_MCU_RD_WAIT2;
-      end
-      ST_MCU_RD_END: begin
-        STATE <= ST_IDLE;
-      end
-      ST_MCU_WR_ADDR: begin
-        ROM_ADDRr <= MCU_ADDR;
-        STATE <= ST_MCU_WR_WAIT;
-        ST_MEM_DELAYr <= ROM_WR_WAIT_MCU;
-        ROM_DOUTr <= MCU_DOUT;
-        ROM_WEr <= 1'b0;
-      end
-      ST_MCU_WR_WAIT: begin
-        ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-        if(ST_MEM_DELAYr == 4'h0) begin
-          ROM_WEr <= 1'b1;
-          STATE <= ST_MCU_WR_WAIT2;
-          ST_MEM_DELAYr <= 4'h2;
-        end
-        else STATE <= ST_MCU_WR_WAIT;
-      end
-      ST_MCU_WR_WAIT2: begin
-        ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-        if(ST_MEM_DELAYr == 4'h0) begin
-          STATE <= ST_MCU_WR_END;
-        end else STATE <= ST_MCU_WR_WAIT2;
-      end
-      ST_MCU_WR_END: begin
-        STATE <= ST_IDLE;
-      end
-
-      ST_CX4_RD_ADDR: begin
-        ROM_ADDRr <= CX4_ADDR;
-        STATE <= ST_CX4_RD_WAIT;
-        ST_MEM_DELAYr <= ROM_RD_WAIT_CX4;
-      end
-      ST_CX4_RD_WAIT: begin
-        ST_MEM_DELAYr <= ST_MEM_DELAYr - 4'h1;
-        if(ST_MEM_DELAYr == 4'h0) STATE <= ST_IDLE;
-        else STATE <= ST_CX4_RD_WAIT;
-        if(ROM_ADDR0) CX4_DINr <= ROM_DATA[7:0];
-        else CX4_DINr <= ROM_DATA[15:8];
-      end
-      ST_CX4_RD_END: begin
-        STATE <= ST_IDLE;
-      end
-    endcase
-  end
+		  ROM_DOUTr <= SNES_DATA;
+		end
+		else STATE <= ST_SNES_WR_WAIT1;
+	 end
+	 ST_SNES_WR_WAIT2: begin
+	   ST_MEM_DELAYr <= ST_MEM_DELAYr - 1;
+		if(ST_MEM_DELAYr == 0) begin
+        STATE <= ST_SNES_WR_END;
+		  ROM_WEr <= 1'b1;
+		end
+		else STATE <= ST_SNES_WR_WAIT2;
+    end
+	 ST_SNES_RD_END, ST_SNES_WR_END: begin
+	   ROM_DOUT_ENr <= 1'b0;		
+      if(MCU_RD_PENDr) begin
+        STATE <= ST_MCU_RD_ADDR;
+      end else if(MCU_WR_PENDr) begin
+        STATE <= ST_MCU_WR_ADDR;
+      end else STATE <= ST_IDLE;
+    end
+    ST_MCU_RD_ADDR: begin
+      ROM_SAr <= 1'b0;
+		ST_MEM_DELAYr <= ROM_RD_WAIT_MCU;
+		STATE <= ST_MCU_RD_WAIT;
+	 end
+	 ST_MCU_RD_WAIT: begin
+	   ST_MEM_DELAYr <= ST_MEM_DELAYr - 1;
+		if(ST_MEM_DELAYr == 0) begin
+        STATE <= ST_MCU_RD_END;
+		end
+		else STATE <= ST_MCU_RD_WAIT;
+	 end
+	 ST_MCU_RD_END: begin
+      MCU_DINr <= ROM_ADDRr[0] ? ROM_DATA[7:0] : ROM_DATA[15:8];
+	   STATE <= ST_IDLE;
+	 end
+	 
+	 ST_MCU_WR_ADDR: begin
+      ROM_DOUTr <= MCU_DOUT;
+      ROM_SAr <= 1'b0;
+	   ST_MEM_DELAYr <= ROM_WR_WAIT_MCU;
+		STATE <= ST_MCU_WR_WAIT;
+		ROM_DOUT_ENr <= 1'b1;
+		ROM_WEr <= 1'b0;
+	 end
+	 ST_MCU_WR_WAIT: begin
+	   ST_MEM_DELAYr <= ST_MEM_DELAYr - 1;
+		if(ST_MEM_DELAYr == 0) begin
+		  ROM_WEr <= 1'b1;
+		  STATE <= ST_MCU_WR_END;
+		end
+		else STATE <= ST_MCU_WR_WAIT;	 
+	 end
+	 ST_MCU_WR_END: begin
+		ROM_DOUT_ENr <= 1'b0;
+	   STATE <= ST_IDLE;
+	 end
+	 ST_CX4_RD_ADDR: begin
+	   ROM_CAr <= 1'b1;
+	   ST_MEM_DELAYr <= ROM_RD_WAIT_CX4;
+		STATE <= ST_CX4_RD_WAIT;
+	 end
+	 ST_CX4_RD_WAIT: begin
+	   ST_MEM_DELAYr <= ST_MEM_DELAYr - 1;
+		if(ST_MEM_DELAYr == 0) begin
+		  STATE <= ST_CX4_RD_END;
+		end
+		else STATE <= ST_CX4_RD_WAIT;
+	 end
+	 ST_CX4_RD_END: begin
+	   ROM_CAr <= 1'b0;
+	   CX4_DINr <= CX4_ADDRr[0] ? ROM_DATA[7:0] : ROM_DATA[15:8];
+	   STATE <= ST_IDLE;
+	 end
+	 
+  endcase
 end
 
 always @(posedge SYSCLK2) begin

+ 13 - 17
verilog/sd2sneslite/main.v

@@ -35,6 +35,10 @@ module main(
   output SNES_DATABUS_DIR,
   input SNES_SYSCLK,
 
+  input [7:0] SNES_PA,
+  input SNES_PARD,
+  input SNES_PAWR,
+  
   /* SRAM signals */
   /* Bus 1: PSRAM, 128Mbit, 16bit, 70ns */
   inout [15:0] ROM_DATA,
@@ -93,8 +97,6 @@ wire [7:0] spi_input_data;
 wire [31:0] spi_byte_cnt;
 wire [2:0] spi_bit_cnt;
 wire [23:0] MCU_ADDR;
-wire [7:0] mcu_data_in;
-wire [7:0] mcu_data_out;
 wire [23:0] SAVERAM_MASK;
 wire [23:0] ROM_MASK;
 
@@ -125,7 +127,6 @@ mcu_cmd snes_mcu_cmd(
   .param_ready(spi_param_ready),
   .cmd_data(spi_cmd_data),
   .param_data(spi_param_data),
-  .mcu_write(MCU_WRITE),
   .mcu_data_in(MCU_DINr),
   .mcu_data_out(MCU_DOUT),
   .spi_byte_cnt(spi_byte_cnt),
@@ -140,7 +141,6 @@ mcu_cmd snes_mcu_cmd(
 );
 
 wire [7:0] DCM_STATUS;
-
 // dcm1: dfs 4x
 my_dcm snes_dcm(
   .CLKIN(CLKIN),
@@ -194,11 +194,6 @@ address snes_addr(
   .ROM_MASK(ROM_MASK)
 );
 
-wire SNES_READ_CYCLEw;
-wire SNES_WRITE_CYCLEw;
-wire MCU_READ_CYCLEw;
-wire MCU_WRITE_CYCLEw;
-
 parameter MODE_SNES = 1'b0;
 parameter MODE_MCU = 1'b1;
 
@@ -220,23 +215,24 @@ parameter ST_MCU_WR_WAIT  = 18'b000100000000000000;
 parameter ST_MCU_WR_WAIT2 = 18'b001000000000000000;
 parameter ST_MCU_WR_END   = 18'b010000000000000000;
 
-parameter ROM_RD_WAIT = 4'h4;
+parameter ROM_RD_WAIT = 4'h0;
 parameter ROM_RD_WAIT_MCU = 4'h6;
+parameter ROM_WR_WAIT = 4'h4;
 parameter ROM_WR_WAIT1 = 4'h2;
-parameter ROM_WR_WAIT2 = 4'h3;
-parameter ROM_WR_WAIT_MCU = 4'h6;
+parameter ROM_WR_WAIT2 = 4'h1;
+parameter ROM_WR_WAIT_MCU = 4'h5;
+
+parameter SNES_DEAD_TIMEOUT = 17'd88000; // 1ms
 
 reg [17:0] STATE;
 initial STATE = ST_IDLE;
 
-reg [1:0] CYCLE_RESET;
-reg ROM_WE_MASK;
-reg ROM_OE_MASK;
-
 reg [7:0] SNES_DINr;
+reg [7:0] SNES_DOUTr;
 reg [7:0] ROM_DOUTr;
 
-assign SNES_DATA = (!SNES_READ) ? SNES_DINr : 8'bZ;
+assign SNES_DATA = ~SNES_READ ? SNES_DOUTr
+						 : 8'bZ;
 
 reg [3:0] ST_MEM_DELAYr;
 reg MCU_RD_PENDr;