Browse Source

vjtag: require a synchronization prefix to write to memory

Streaming data in the shift_DR state doesn't actually give us any
indication of when data really starts. Since it is obviously not
practical to hold all data until we get to the UDR state, require a
synchronization prefix (0xABC80FED) before the data to be written.
H. Peter Anvin 3 years ago
parent
commit
47300bdbed

+ 2 - 2
fpga/max80.qpf

@@ -19,12 +19,12 @@
 #
 # Quartus Prime
 # Version 21.1.0 Build 842 10/21/2021 SJ Lite Edition
-# Date created = 17:04:28  February 09, 2022
+# Date created = 18:38:47  February 09, 2022
 #
 # -------------------------------------------------------------------------- #
 
 QUARTUS_VERSION = "21.1"
-DATE = "17:04:28  February 09, 2022"
+DATE = "18:38:47  February 09, 2022"
 
 # Revisions
 

+ 3 - 3
fpga/output/sram.mif

@@ -1750,9 +1750,9 @@ CONTENT BEGIN
 06CF : 6557002F;
 06D0 : 65462064;
 06D1 : 39202062;
-06D2 : 3A373120;
-06D3 : 313A3230;
-06D4 : 53502030;
+06D2 : 3A383120;
+06D3 : 333A3633;
+06D4 : 53502031;
 06D5 : 30322054;
 06D6 : 003232;
 [06D7..1FFF] : 00;

BIN
fpga/output/v1.jic


BIN
fpga/output/v1.rbf.gz


BIN
fpga/output/v1.rpd.gz


BIN
fpga/output/v1.sof


BIN
fpga/output/v1.svf.gz


BIN
fpga/output/v1.xsvf.gz


BIN
fpga/output/v2.jic


BIN
fpga/output/v2.rbf.gz


BIN
fpga/output/v2.rpd.gz


BIN
fpga/output/v2.sof


BIN
fpga/output/v2.svf.gz


BIN
fpga/output/v2.xsvf.gz


BIN
fpga/output/v2boot.rbf.gz


BIN
fpga/output/v2boot.sof


BIN
fpga/output/v2boot.svf.gz


BIN
fpga/output/v2boot.xsvf.gz


+ 93 - 66
fpga/vjtag_max80.sv

@@ -18,7 +18,9 @@
 //
 // 1001x - address register (only bits [24:2] settable)
 // 1010x - read data from memory
+//         returns address before streaming 32-bit data words
 // 1011x - write data to memory
+//         send VJTAG_WRITE_PREFIX before streaming 32-bit data words
 // 1100x - command register to CPU
 // 1101x - command register to CPU, trigger IRQ on update_DR
 // 1110x - info register from CPU
@@ -34,40 +36,41 @@
 //    2 - CPU status register (rw)
 //    3 - CPU status register set bits (rw1)
 //
-module vjtag_max80 
+module vjtag_max80
 #(
-   parameter [31:0] sdram_base_addr,
-   parameter        sdram_bits
+  parameter [31:0] sdram_base_addr,
+  parameter        sdram_bits,
+  parameter [31:0] VJTAG_WRITE_PREFIX = 32'hABC80FED
 ) (
-   input 	 rst_n,
-   input 	 sys_clk,
-		 
+   input	 rst_n,
+   input	 sys_clk,
+
    dram_bus.dstr sdram,
 
-   input 	 cpu_valid,
+   input	 cpu_valid,
    input   [6:2] cpu_addr,
    input  [31:0] cpu_wdata,
    input  [ 3:0] cpu_wstrb,
    output [31:0] cpu_rdata,
-   output  	 cpu_irq,
-   output  	 cpu_halt,
+   output	 cpu_irq,
+   output	 cpu_halt,
 
-   output reg 	 reset_cmd
+   output reg	 reset_cmd
 		);
 
-   wire 	  v_tdi;
+   wire		  v_tdi;
    wire		  v_tdo;
-   wire [4:0] 	  v_ir;
-   wire 	  v_tck;
-   wire 	  v_st_cdr;
-   wire 	  v_st_sdr;
-   wire 	  v_st_e1dr;
-   wire 	  v_st_pdr;
-   wire 	  v_st_e2dr;
-   wire 	  v_st_udr;
-   wire 	  v_st_cir;
-   wire 	  v_st_uir;
-   
+   wire [4:0]	  v_ir;
+   wire		  v_tck;
+   wire		  v_st_cdr;
+   wire		  v_st_sdr;
+   wire		  v_st_e1dr;
+   wire		  v_st_pdr;
+   wire		  v_st_e2dr;
+   wire		  v_st_udr;
+   wire		  v_st_cir;
+   wire		  v_st_uir;
+
    vjtag vjtag (
 		.tdi    ( v_tdi ),
 		.tdo    ( v_tdo ),
@@ -100,19 +103,19 @@ module vjtag_max80
    localparam cmd_cpuinfo    = 4'b1110;
    localparam cmd_cpustatus  = 4'b1111;
 
-   reg 	       jtag_bypass;
+   reg	       jtag_bypass;
    reg  [31:0] jtag_shr;
    reg	       tdi_s;
 
    // Latched information for use in the synchronous state machine
    reg [3:0]   ir_cmd;		// Command part of IR
-   reg 	       ir_ro;		// Readonly (update suppress)
-   reg 	       st_cdr_s;
-   reg 	       st_sdr_s;
-   reg 	       st_xdr_s;	// Any state between CDR and UDR, exclusively
-   reg 	       st_udr_s;
-   reg 	       st_uir_s;
-   
+   reg	       ir_ro;		// Readonly (update suppress)
+   reg	       st_cdr_s;
+   reg	       st_sdr_s;
+   reg	       st_xdr_s;	// Any state between CDR and UDR, exclusively
+   reg	       st_udr_s;
+   reg	       st_uir_s;
+
    always @(posedge v_tck)
      begin
 	jtag_bypass <= v_ir == cmd_bypass;
@@ -147,10 +150,10 @@ module vjtag_max80
    function logic [31:0] maskaddr (input [31:0] addr);
       maskaddr = (addr & memaddr_mask) | sdram_base_addr;
    endfunction
-   
-   reg 	      jtag_cpu_irq   = 1'b0;
-   reg 	      jtag_cpu_halt  = 1'b0;
-   reg 	      jtag_reset_cmd = 1'b0;
+
+   reg	      jtag_cpu_irq   = 1'b0;
+   reg	      jtag_cpu_halt  = 1'b0;
+   reg	      jtag_reset_cmd = 1'b0;
 
    assign cpu_irq   = jtag_cpu_irq;
    assign cpu_halt  = jtag_cpu_halt;
@@ -161,34 +164,36 @@ module vjtag_max80
    reg [31:0]  jtag_cpuinfo;
    reg [ 7:0]  jtag_cpustatus;
 
-   reg 	       mem_valid;
+   reg	       mem_valid;
    reg	       mem_write;
    reg  [31:0] mem_addr;
    wire [31:0] mem_addr_next = maskaddr(mem_addr + 3'h4);
    wire [31:0] mem_rdata;
    reg  [31:0] mem_wdata;
    wire        mem_ready;
-   reg 	       mem_done;
-   reg 	       mem_error;	// Memory underrun
+   reg	       mem_done;
+   reg	       mem_error;	// Memory underrun
+   reg	       advance_mem_addr;
+   reg	       mem_header_done;
 
-   reg 	       tck_q;
-   reg 	       tck_stb;
+   reg	       tck_q;
+   reg	       tck_stb;
    always @(posedge sys_clk)
      begin
 	tck_q   <= tck_s;
 	tck_stb <= tck_s & ~tck_q;
      end
-   
+
    // Keep a counter to keep track of SDRAM data bit count; this is to
    // allow streaming of data to/from SDRAM without leaving the
    // SDR state.
    reg [4:0] sdr_ctr;
-   
+
    always @(posedge sys_clk)
      begin
 	if ( ~rst_n )
 	  jtag_reset_cmd <= 1'b0;
-	
+
 	jtag_cpu_irq <= 1'b0;
 
 	if ( tck_stb )
@@ -200,7 +205,7 @@ module vjtag_max80
 		  else
 		    jtag_shr <= { 30'bx, tdi_s, jtag_shr[1] };
 	       end
-	     
+
 	     if ( st_cdr_s )
 	       case ( ir_cmd )
 		 cmd_halt:      jtag_shr[0] <= jtag_cpu_halt;
@@ -216,7 +221,7 @@ module vjtag_max80
 		 cmd_cpustatus:  jtag_shr    <= jtag_cpustatus;
 		 default:       ;
 	       endcase // case ( ir_cmd )
-	     
+
 	     // For performance, the SDRAM data can be streamed
 	     // without exiting the shift_DR state, so this is
 	     // based on a counter rather than going to the DR_update
@@ -236,38 +241,57 @@ module vjtag_max80
 		       mem_done           <= 1'b0;
 		       mem_valid          <= 1'b0;
 		       mem_write          <= ir_cmd[0];
+		       advance_mem_addr   <= 1'b0;
+		       mem_addr           <= jtag_memaddr;
 		    end
 
 		  if ( ~st_xdr_s )
 		    begin
+		       mem_header_done    <= 1'b0;
 		       sdr_ctr            <= 5'b0;
-		       mem_addr           <= jtag_memaddr;
 		    end
 
-		  if ( st_sdr_s )
+		  if ( st_sdr_s | st_udr_s )
 		    begin
 		       sdr_ctr <= sdr_ctr + 1'b1;
 
-		       // Applicable to both read and write
-		       case ( sdr_ctr )
-			 5'd31: begin
-			    if ( mem_valid )
-			      mem_error <= 1'b1; // Underrun!
+		       if ( ~mem_header_done )
+			 begin
+			    if ( ~mem_write )
+			      begin
+				 // Read
+				 mem_header_done <= &sdr_ctr;
+			      end
+			    else
+			      begin
+				 // Write
+				 if ( jtag_shr == VJTAG_WRITE_PREFIX )
+				   mem_header_done <= 1'b1;
+				 sdr_ctr <= 5'b0;
+			      end
 			 end
-			 default: ;
-		       endcase // case ( sdr_ctr )
+
+		       // Memory access underrun?
+		       if ( &sdr_ctr )
+			 mem_error <= mem_error | mem_valid;
 
 		       if ( ~mem_write )
 			 // Read
 			 case ( sdr_ctr )
-			   5'd1: begin
+			   5'd2: begin
 			      // For a read, make sure we are committed
 			      // to reading the new word
 			      if ( ~ir_ro )
 				jtag_memaddr     <= mem_addr;
-			      mem_valid          <= 1'b1;
-			      mem_done           <= 1'b0;
+
+			      advance_mem_addr   <= mem_header_done;
 			   end
+			   5'd3:
+			     begin
+				// After mem_addr advanced
+				mem_valid          <= 1'b1;
+				mem_done           <= 1'b0;
+			     end
 			   5'd31: begin
 			      jtag_shr <= mem_rdata;
 			   end
@@ -275,16 +299,15 @@ module vjtag_max80
 			 endcase // case ( sdr_ctr )
 		       else
 			 // Write
-			 case ( sdr_ctr )
-			   5'd31: begin
+			 if ( &sdr_ctr )
+			   begin
 			      mem_wdata          <= jtag_shr;
 			      mem_valid          <= 1'b1;
 			      mem_done           <= 1'b0;
+			      advance_mem_addr   <= 1'b1;
 			      if ( ~ir_ro )
 				jtag_memaddr     <= mem_addr_next;
 			   end
-			   default: ;
-			 endcase // case ( sdr_ctr )
 		    end // if ( st_sdr_s )
 	       end // if ( ir_cmd[3:1] == cmd_memwr )
 
@@ -295,7 +318,7 @@ module vjtag_max80
 
 	     if ( st_uir_s )
 	       jtag_reset_cmd <= jtag_reset_cmd | (ir_cmd == cmd_reset);
-	     
+
 	     if ( st_udr_s & ~ir_ro )
 	       case ( ir_cmd )
 		 cmd_halt:    jtag_cpu_halt  <= jtag_shr[0];
@@ -312,10 +335,14 @@ module vjtag_max80
 	  begin
 	     mem_valid <= 1'b0;
 	     mem_done  <= 1'b1;
-	     mem_addr  <= mem_addr_next;
+	  end
+	if ( advance_mem_addr & ~mem_valid )
+	  begin
+	     mem_addr <= mem_addr_next;
+	     advance_mem_addr <= 1'b0;
 	  end
      end
-   
+
    dram_port #(32) mem
      (
       .bus   ( sdram ),
@@ -331,7 +358,7 @@ module vjtag_max80
    wire [7:0] cpustatus_new =
 	      ( tck_stb & st_cdr_s & ~ir_ro & (ir_cmd == cmd_cpustatus) )
 	      ? 'b0 : jtag_cpustatus;
-   
+
    always @(negedge rst_n or posedge sys_clk)
      if (~rst_n)
        begin
@@ -341,7 +368,7 @@ module vjtag_max80
      else
        begin
 	  jtag_cpustatus <= cpustatus_new;
-	  
+
 	  if ( cpu_valid )
 	    begin
 	       case ( cpu_addr )
@@ -363,7 +390,7 @@ module vjtag_max80
 	       endcase // case ( cpu_addr[1:0] )
 	    end // if ( cpu_valid )
        end
-	  
+
    always @(*)
      casez ( cpu_addr )
        5'b00000: cpu_rdata = jtag_cpucmd;