On 28/02/11 01:54 PM, Sebastien Bourdeauducq wrote:
Michael, what do you think of the JTAG modifications below (I have not
touched this part and I quite don't know how it works) ?

Ok, I've improved on that last patch for the JTAG interface.

I found (while getting openocd working) that my JTAG could sometimes hang. I didn't see this bug with my own firmware loading tool because it always runs a JTAG drscan after each operation to determine the resulting status. This masked the following problem:

Altera JTAG sometimes stops driving the JTAG clock once it asserts update (confirmed with signal tap). Thus, when the old code waited for the negative edge of update, it could stop indefinitely---or at least until the next JTAG operation.

Like the previous patch, this patch also fixes a race condition. The old code latched the shift register (jtag_cores) concurrently with flipping the rx_toggle on update (lm32_jtag). This caused JTAG instability on Altera chips, where commands could got lost or repeated, depending on the synthesizers mood.

For me, now, the JTAG runs rock solid on my Cyclone3: it never screws up or loses synchronization and it always executes commands immediately.

I can't test the spartan6 changes, but I believe/hope I've updated the verilog file appropriately.

diff -ru /home/terpstra/lm32/milkymist/cores/lm32/rtl/jtag_cores.v rtl/jtag_cores.v
--- /home/terpstra/lm32/milkymist/cores/lm32/rtl/jtag_cores.v	2011-02-28 14:00:53.000000000 +0100
+++ rtl/jtag_cores.v	2011-03-01 14:50:03.000000000 +0100
@@ -1,3 +1,5 @@
+// Modified by GSI to use simple positive edge clocking and the JTAG capture state
+
 module jtag_cores (
     input [7:0] reg_d,
     input [2:0] reg_addr_d,
@@ -11,15 +13,19 @@
 wire tck;
 wire tdi;
 wire tdo;
+wire capture;
 wire shift;
 wire update;
+wire e1dr;
 wire reset;
 
 jtag_tap jtag_tap (
 	.tck(tck),
 	.tdi(tdi),
 	.tdo(tdo),
+	.capture(capture),
 	.shift(shift),
+	.e1dr(e1dr),
 	.update(update),
 	.reset(reset)
 );
@@ -27,26 +33,28 @@
 reg [10:0] jtag_shift;
 reg [10:0] jtag_latched;
 
-always @(posedge tck or posedge reset)
+always @(posedge tck)
 begin
 	if(reset)
 		jtag_shift <= 11'b0;
 	else begin
-		if(shift)
+		if (shift)
 			jtag_shift <= {tdi, jtag_shift[10:1]};
-		else
+		else if (capture)
 			jtag_shift <= {reg_d, reg_addr_d};
 	end
 end
 
 assign tdo = jtag_shift[0];
 
-always @(posedge reg_update or posedge reset)
+always @(posedge tck)
 begin
 	if(reset)
 		jtag_latched <= 11'b0;
-	else
-		jtag_latched <= jtag_shift;
+	else begin
+	   if (e1dr)
+		   jtag_latched <= jtag_shift;
+	end
 end
 
 assign reg_update = update;
diff -ru /home/terpstra/lm32/milkymist/cores/lm32/rtl/lm32_jtag.v rtl/lm32_jtag.v
--- /home/terpstra/lm32/milkymist/cores/lm32/rtl/lm32_jtag.v	2011-02-28 14:00:53.000000000 +0100
+++ rtl/lm32_jtag.v	2011-03-01 14:50:03.000000000 +0100
@@ -170,13 +170,15 @@
 // Internal nets and registers 
 /////////////////////////////////////////////////////
 
-reg rx_toggle;                          // Clock-domain crossing registers
-reg rx_toggle_r;                        // Registered version of rx_toggle
-reg rx_toggle_r_r;                      // Registered version of rx_toggle_r
-reg rx_toggle_r_r_r;                    // Registered version of rx_toggle_r_r
-
-reg [`LM32_BYTE_RNG] rx_byte;   
-reg [2:0] rx_addr;
+reg rx_update;                          // Clock-domain crossing registers
+reg rx_update_r;                        // Registered version of rx_update
+reg rx_update_r_r;                      // Registered version of rx_update_r
+reg rx_update_r_r_r;                    // Registered version of rx_update_r_r
+
+// These wires come from the JTAG clock domain.
+// They have been held unchanged for an entire JTAG clock cycle before the jtag_update toggle flips
+wire [`LM32_BYTE_RNG] rx_byte;   
+wire [2:0] rx_addr;
 
 `ifdef CFG_JTAG_UART_ENABLED                 
 reg [`LM32_BYTE_RNG] uart_tx_byte;      // UART TX data
@@ -229,36 +231,26 @@
 // Sequential Logic
 /////////////////////////////////////////////////////
 
-// Toggle a flag when a JTAG write occurs
- 
-always @(negedge jtag_update `CFG_RESET_SENSITIVITY)
-begin
-if (rst_i == `TRUE)
-  rx_toggle <= 1'b0;
-else 
-  rx_toggle <= ~rx_toggle;
-end
-
-always @(*)
-begin
-    rx_byte = jtag_reg_q;
-    rx_addr = jtag_reg_addr_q;
-end
+assign rx_byte = jtag_reg_q;
+assign rx_addr = jtag_reg_addr_q;
 
-// Clock domain crossing from JTAG clock domain to CPU clock domain
+// The JTAG latched jtag_reg[_addr]_q at least one JTCK before jtag_update is raised
+// Thus, they are stable (and safe to sample) when jtag_update is high
 always @(posedge clk_i `CFG_RESET_SENSITIVITY)
 begin
     if (rst_i == `TRUE)
     begin
-        rx_toggle_r <= 1'b0;
-        rx_toggle_r_r <= 1'b0;
-        rx_toggle_r_r_r <= 1'b0;
+        rx_update <= 1'b0;
+        rx_update_r <= 1'b0;
+        rx_update_r_r <= 1'b0;
+        rx_update_r_r_r <= 1'b0;
     end
     else
     begin
-        rx_toggle_r <= rx_toggle;
-        rx_toggle_r_r <= rx_toggle_r;
-        rx_toggle_r_r_r <= rx_toggle_r_r;
+        rx_update <= jtag_update;
+        rx_update_r <= rx_update;
+        rx_update_r_r <= rx_update_r;
+        rx_update_r_r_r <= rx_update_r_r;
     end
 end
 
@@ -319,7 +311,7 @@
         `LM32_JTAG_STATE_READ_COMMAND:
         begin
             // Wait for rx register to toggle which indicates new data is available
-            if (rx_toggle_r_r != rx_toggle_r_r_r)
+            if ((~rx_update_r_r_r & rx_update_r_r) == `TRUE)
             begin
                 command <= rx_byte[7:4];                
                 case (rx_addr)
@@ -384,7 +376,7 @@
 `ifdef CFG_HW_DEBUG_ENABLED
         `LM32_JTAG_STATE_READ_BYTE_0:
         begin
-            if (rx_toggle_r_r != rx_toggle_r_r_r)
+            if ((~rx_update_r_r_r & rx_update_r_r) == `TRUE)
             begin
                 jtag_byte_0 <= rx_byte;
                 state <= `LM32_JTAG_STATE_READ_BYTE_1;
@@ -392,7 +384,7 @@
         end
         `LM32_JTAG_STATE_READ_BYTE_1:
         begin
-            if (rx_toggle_r_r != rx_toggle_r_r_r)
+            if ((~rx_update_r_r_r & rx_update_r_r) == `TRUE)
             begin
                 jtag_byte_1 <= rx_byte;
                 state <= `LM32_JTAG_STATE_READ_BYTE_2;
@@ -400,7 +392,7 @@
         end
         `LM32_JTAG_STATE_READ_BYTE_2:
         begin
-            if (rx_toggle_r_r != rx_toggle_r_r_r)
+            if ((~rx_update_r_r_r & rx_update_r_r) == `TRUE)
             begin
                 jtag_byte_2 <= rx_byte;
                 state <= `LM32_JTAG_STATE_READ_BYTE_3;
@@ -408,7 +400,7 @@
         end
         `LM32_JTAG_STATE_READ_BYTE_3:
         begin
-            if (rx_toggle_r_r != rx_toggle_r_r_r)
+            if ((~rx_update_r_r_r & rx_update_r_r) == `TRUE)
             begin
                 jtag_byte_3 <= rx_byte;
                 if (command == `LM32_DP_READ_MEMORY)
@@ -419,7 +411,7 @@
         end
         `LM32_JTAG_STATE_READ_BYTE_4:
         begin
-            if (rx_toggle_r_r != rx_toggle_r_r_r)
+            if ((~rx_update_r_r_r & rx_update_r_r) == `TRUE)
             begin
                 jtag_byte_4 <= rx_byte;
                 state <= `LM32_JTAG_STATE_PROCESS_COMMAND;
module jtag_tap(
  output tck,
  output tdi,
  input tdo,
  output capture,
  output shift,
  output e1dr,
  output update,
  output reset
);

assign reset = 0;
wire nil1, nil2, nil3, nil4;

sld_virtual_jtag altera_jtag(
  .ir_in                (),
  .ir_out               (),
  .tck                  (tck),
  .tdo                  (tdo),
  .tdi                  (tdi),
  .virtual_state_cdr    (capture),
  .virtual_state_sdr    (shift),
  .virtual_state_e1dr   (e1dr),
  .virtual_state_pdr    (nil1),
  .virtual_state_e2dr   (nil2),
  .virtual_state_udr    (update),
  .virtual_state_cir    (nil3),
  .virtual_state_uir    (nil4)
  // synopsys translate_off
  ,
  .jtag_state_cdr       (),
  .jtag_state_cir       (),
  .jtag_state_e1dr      (),
  .jtag_state_e1ir      (),
  .jtag_state_e2dr      (),
  .jtag_state_e2ir      (),
  .jtag_state_pdr       (),
  .jtag_state_pir       (),
  .jtag_state_rti       (),
  .jtag_state_sdr       (),
  .jtag_state_sdrs      (),
  .jtag_state_sir       (),
  .jtag_state_sirs      (),
  .jtag_state_tlr       (),
  .jtag_state_udr       (),
  .jtag_state_uir       (),
  .tms                  ()
  // synopsys translate_on
  );

defparam
   altera_jtag.sld_auto_instance_index = "YES",
   altera_jtag.sld_instance_index = 0,
   altera_jtag.sld_ir_width = 1,
   altera_jtag.sld_sim_action = "",
   altera_jtag.sld_sim_n_scan = 0,
   altera_jtag.sld_sim_total_length = 0;

endmodule
module jtag_tap(
        output tck,
        output tdi,
        input tdo,
        output capture,
        output shift,
        output e1dr,
        output update,
        output reset
);

// Unfortunately the exit1 state for DR (e1dr) is mising
// We can simulate it by interpretting 'update' as e1dr and delaying 'update'
wire g_capture;
wire g_shift;
wire g_update;
reg update_delay;

assign capture = g_capture & sel;
assign shift = g_shift & sel;
assign e1dr = g_update & sel;
assign update = update_delay;

BSCAN_SPARTAN6 #(
        .JTAG_CHAIN(1)
) bscan (
        .CAPTURE(g_capture),
        .DRCK(tck),
        .RESET(reset),
        .RUNTEST(),
        .SEL(sel),
        .SHIFT(g_shift),
        .TCK(),
        .TDI(tdi),
        .TMS(),
        .UPDATE(g_update),
        .TDO(tdo)
);

update_delay <= g_update;

endmodule
_______________________________________________
http://lists.milkymist.org/listinfo.cgi/devel-milkymist.org
IRC: #milkymist@Freenode
Twitter: www.twitter.com/milkymistvj
Ideas? http://milkymist.uservoice.com

Reply via email to