Browse Source

fpga: virtual JTAG interface

Add a "virtual JTAG port" via Altera's FPGA hub.
This can read and write from SDRAM, and do some basic control
functions including sending an IRQ to the CPU, a system reset, and
halt the CPU. With a few more extensions this could be a great debug
tool.

Bugs so far:
- Reading increments the address one time too many. Why?!
- Writing seems to be offset from the proper address... by a byte?!

However, the basic functionality seems to be there, and I would
consider the concept validated.

The script ub.tcl (for USB-Blaster) contains a couple of useful macros
while trying it out.
H. Peter Anvin 3 years ago
parent
commit
2ec75f1807

+ 11 - 3
fpga/iodevs.vh

@@ -69,6 +69,11 @@
 	wire [ 0:0] iodev_valid_random = iodev_valid[8:8];
 	wire [ 0:0] iodev_valid_random = iodev_valid[8:8];
 	tri1 [ 0:0] iodev_wait_n_random;
 	tri1 [ 0:0] iodev_wait_n_random;
 
 
+	wire [31:0] iodev_rdata_vjtag;
+	wire [ 0:0] iodev_irq_vjtag;
+	wire [ 0:0] iodev_valid_vjtag = iodev_valid[9:9];
+	tri1 [ 0:0] iodev_wait_n_vjtag;
+
 	// I/O input MUX
 	// I/O input MUX
 	always_comb
 	always_comb
 		case (cpu_mem_addr[29:28])
 		case (cpu_mem_addr[29:28])
@@ -85,6 +90,7 @@
 				4'd6:	 iodev_rdata = iodev_rdata_i2c;
 				4'd6:	 iodev_rdata = iodev_rdata_i2c;
 				4'd7:	 iodev_rdata = iodev_rdata_esp;
 				4'd7:	 iodev_rdata = iodev_rdata_esp;
 				4'd8:	 iodev_rdata = iodev_rdata_random;
 				4'd8:	 iodev_rdata = iodev_rdata_random;
+				4'd9:	 iodev_rdata = iodev_rdata_vjtag;
 				default: iodev_rdata = 32'hxxxxxxxx;
 				default: iodev_rdata = 32'hxxxxxxxx;
 			endcase
 			endcase
 			default: iodev_rdata = 32'hxxxxxxxx;
 			default: iodev_rdata = 32'hxxxxxxxx;
@@ -102,9 +108,10 @@
 	assign sys_irq[11] = iodev_irq_i2c[0];
 	assign sys_irq[11] = iodev_irq_i2c[0];
 	assign sys_irq[12] = iodev_irq_esp[0];
 	assign sys_irq[12] = iodev_irq_esp[0];
 	assign sys_irq[13] = iodev_irq_random[0];
 	assign sys_irq[13] = iodev_irq_random[0];
+	assign sys_irq[14] = iodev_irq_vjtag[0];
 
 
-	localparam [31:0] irq_edge_mask =  32'h00000010;
-	localparam [31:0] irq_masked    = ~32'h00003fff;
+	localparam [31:0] irq_edge_mask =  32'h00004010;
+	localparam [31:0] irq_masked    = ~32'h00007fff;
 
 
 	wire iodev_wait_n = (&iodev_wait_n_sys) & 
 	wire iodev_wait_n = (&iodev_wait_n_sys) & 
 		(&iodev_wait_n_abc) & 
 		(&iodev_wait_n_abc) & 
@@ -116,4 +123,5 @@
 		(&iodev_wait_n_sdcard) & 
 		(&iodev_wait_n_sdcard) & 
 		(&iodev_wait_n_i2c) & 
 		(&iodev_wait_n_i2c) & 
 		(&iodev_wait_n_esp) & 
 		(&iodev_wait_n_esp) & 
-		(&iodev_wait_n_random);
+		(&iodev_wait_n_random) & 
+		(&iodev_wait_n_vjtag);

+ 40 - 0
fpga/ip/vjtag/synthesis/vjtag.qip

@@ -0,0 +1,40 @@
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_TOOL_NAME "Qsys"
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_TOOL_VERSION "21.1"
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_TOOL_ENV "Qsys"
+set_global_assignment -library "vjtag" -name SOPCINFO_FILE [file join $::quartus(qip_path) "../../vjtag.sopcinfo"]
+set_global_assignment -entity "vjtag" -library "vjtag" -name SLD_INFO "QSYS_NAME vjtag HAS_SOPCINFO 1 GENERATION_ID 1644142626"
+set_global_assignment -library "vjtag" -name MISC_FILE [file join $::quartus(qip_path) "../vjtag.cmp"]
+set_global_assignment -library "vjtag" -name SLD_FILE [file join $::quartus(qip_path) "vjtag.debuginfo"]
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_TARGETED_DEVICE_FAMILY "Cyclone IV E"
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}"
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_QSYS_MODE "STANDALONE"
+set_global_assignment -name SYNTHESIS_ONLY_QIP ON
+set_global_assignment -library "vjtag" -name MISC_FILE [file join $::quartus(qip_path) "../../vjtag.qsys"]
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_COMPONENT_NAME "dmp0YWc="
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_COMPONENT_DISPLAY_NAME "dmp0YWc="
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_COMPONENT_REPORT_HIERARCHY "On"
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_COMPONENT_INTERNAL "Off"
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_COMPONENT_VERSION "MS4w"
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_COMPONENT_PARAMETER "QVVUT19HRU5FUkFUSU9OX0lE::MTY0NDE0MjYyNg==::QXV0byBHRU5FUkFUSU9OX0lE"
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_COMPONENT_PARAMETER "QVVUT19ERVZJQ0VfRkFNSUxZ::Q3ljbG9uZSBJViBF::QXV0byBERVZJQ0VfRkFNSUxZ"
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_COMPONENT_PARAMETER "QVVUT19ERVZJQ0U=::RVA0Q0UxNUYxN0M4::QXV0byBERVZJQ0U="
+set_global_assignment -entity "vjtag" -library "vjtag" -name IP_COMPONENT_PARAMETER "QVVUT19ERVZJQ0VfU1BFRURHUkFERQ==::OA==::QXV0byBERVZJQ0VfU1BFRURHUkFERQ=="
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_COMPONENT_NAME "c2xkX3ZpcnR1YWxfanRhZw=="
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFZpcnR1YWwgSlRBRw=="
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_COMPONENT_REPORT_HIERARCHY "Off"
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_COMPONENT_INTERNAL "Off"
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u"
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_COMPONENT_VERSION "MjEuMQ=="
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_COMPONENT_DESCRIPTION "VmlydHVhbCBKVEFHIEludGVyZmFjZSAoVkpJKSBtZWdhZnVuY3Rpb24uIFRoaXMgbWVnYWZ1bmN0aW9uIHByb3ZpZGVzIGFjY2VzcyB0byB0aGUgUExEIHNvdXJjZSB0aHJvdWdoIHRoZSBKVEFHIGludGVyZmFjZS4KVGhlIFF1YXJ0dXMgUHJpbWUgc29mdHdhcmUgb3IgSlRBRyBjb250cm9sIGhvc3QgaWRlbnRpZmllcyBlYWNoIGluc3RhbmNlIG9mIHRoaXMgbWVnYWZ1bmN0aW9uIGJ5IGEgdW5pcXVlIGluZGV4LiBFYWNoIG1lZ2FmdW5jdGlvbiBpbnN0YW5jZQpmdW5jdGlvbnMgaW4gYSBmbG93IHRoYXQgcmVzZW1ibGVzIHRoZSBKVEFHIG9wZXJhdGlvbiBvZiBhIGRldmljZS4gVGhlIGxvZ2ljIHRoYXQgdXNlcyB0aGlzIGludGVyZmFjZSBtdXN0IG1haW50YWluIHRoZSBjb250aW51aXR5IG9mCnRoZSBKVEFHIGNoYWluIG9uIGJlaGFsZiB0aGUgUExEIGRldmljZSB3aGVuIHRoaXMgaW5zdGFuY2UgYmVjb21lcyBhY3RpdmUu"
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_COMPONENT_PARAMETER "ZGV2aWNlX2ZhbWlseQ==::Q3ljbG9uZSBJViBF::ZGV2aWNlX2ZhbWlseQ=="
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_COMPONENT_PARAMETER "Z3VpX3VzZV9hdXRvX2luZGV4::ZmFsc2U=::QXV0b21hdGljIEluc3RhbmNlIEluZGV4IEFzc2lnbm1lbnQ="
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_COMPONENT_PARAMETER "c2xkX2F1dG9faW5zdGFuY2VfaW5kZXg=::Tk8=::c2xkX2F1dG9faW5zdGFuY2VfaW5kZXg="
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_COMPONENT_PARAMETER "c2xkX2luc3RhbmNlX2luZGV4::NA==::SW5zdGFuY2UgSW5kZXg="
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_COMPONENT_PARAMETER "c2xkX2lyX3dpZHRo::NA==::SW5zdHJ1Y3Rpb24gUmVnaXN0ZXIgV2lkdGggWzEuLjI0XQ=="
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_COMPONENT_PARAMETER "Q1JFQVRFX1BSSU1JVElWRV9KVEFHX1NUQVRFX1NJR05BTF9QT1JUUw==::ZmFsc2U=::Q3JlYXRlIHByaW1pdGl2ZSBKVEFHIHN0YXRlIHNpZ25hbCBwb3J0cw=="
+
+set_global_assignment -library "vjtag" -name VERILOG_FILE [file join $::quartus(qip_path) "vjtag.v"]
+
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_TOOL_NAME "altera_virtual_jtag"
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_TOOL_VERSION "21.1"
+set_global_assignment -entity "sld_virtual_jtag" -library "vjtag" -name IP_TOOL_ENV "Qsys"

+ 42 - 0
fpga/ip/vjtag/synthesis/vjtag.v

@@ -0,0 +1,42 @@
+// vjtag.v
+
+// Generated using ACDS version 21.1 842
+
+`timescale 1 ps / 1 ps
+module vjtag (
+		output wire       tdi,                // jtag.tdi
+		input  wire       tdo,                //     .tdo
+		output wire [4:0] ir_in,              //     .ir_in
+		input  wire [4:0] ir_out,             //     .ir_out
+		output wire       virtual_state_cdr,  //     .virtual_state_cdr
+		output wire       virtual_state_sdr,  //     .virtual_state_sdr
+		output wire       virtual_state_e1dr, //     .virtual_state_e1dr
+		output wire       virtual_state_pdr,  //     .virtual_state_pdr
+		output wire       virtual_state_e2dr, //     .virtual_state_e2dr
+		output wire       virtual_state_udr,  //     .virtual_state_udr
+		output wire       virtual_state_cir,  //     .virtual_state_cir
+		output wire       virtual_state_uir,  //     .virtual_state_uir
+		output wire       tck                 //  tck.clk
+	);
+
+	sld_virtual_jtag #(
+		.sld_auto_instance_index ("YES"),
+		.sld_instance_index      (0),
+		.sld_ir_width            (5)
+	) virtual_jtag_0 (
+		.tdi                (tdi),                // jtag.tdi
+		.tdo                (tdo),                //     .tdo
+		.ir_in              (ir_in),              //     .ir_in
+		.ir_out             (ir_out),             //     .ir_out
+		.virtual_state_cdr  (virtual_state_cdr),  //     .virtual_state_cdr
+		.virtual_state_sdr  (virtual_state_sdr),  //     .virtual_state_sdr
+		.virtual_state_e1dr (virtual_state_e1dr), //     .virtual_state_e1dr
+		.virtual_state_pdr  (virtual_state_pdr),  //     .virtual_state_pdr
+		.virtual_state_e2dr (virtual_state_e2dr), //     .virtual_state_e2dr
+		.virtual_state_udr  (virtual_state_udr),  //     .virtual_state_udr
+		.virtual_state_cir  (virtual_state_cir),  //     .virtual_state_cir
+		.virtual_state_uir  (virtual_state_uir),  //     .virtual_state_uir
+		.tck                (tck)                 //  tck.clk
+	);
+
+endmodule

+ 3 - 3
fpga/max80.qpf

@@ -19,15 +19,15 @@
 #
 #
 # Quartus Prime
 # Quartus Prime
 # Version 21.1.0 Build 842 10/21/2021 SJ Lite Edition
 # Version 21.1.0 Build 842 10/21/2021 SJ Lite Edition
-# Date created = 00:12:52  February 06, 2022
+# Date created = 05:31:19  February 07, 2022
 #
 #
 # -------------------------------------------------------------------------- #
 # -------------------------------------------------------------------------- #
 
 
 QUARTUS_VERSION = "21.1"
 QUARTUS_VERSION = "21.1"
-DATE = "00:12:52  February 06, 2022"
+DATE = "05:31:19  February 07, 2022"
 
 
 # Revisions
 # Revisions
 
 
 PROJECT_REVISION = "v1"
 PROJECT_REVISION = "v1"
-PROJECT_REVISION = "v2"
 PROJECT_REVISION = "v2boot"
 PROJECT_REVISION = "v2boot"
+PROJECT_REVISION = "v2"

+ 3 - 0
fpga/max80.qsf

@@ -243,5 +243,8 @@ set_global_assignment -name VERILOG_FILE ip/cdc_txfifo.v
 set_global_assignment -name VERILOG_FILE ip/cdc_rxfifo.v
 set_global_assignment -name VERILOG_FILE ip/cdc_rxfifo.v
 set_global_assignment -name QIP_FILE ip/cdc_txfifo.qip
 set_global_assignment -name QIP_FILE ip/cdc_txfifo.qip
 set_global_assignment -name QIP_FILE ip/cdc_rxfifo.qip
 set_global_assignment -name QIP_FILE ip/cdc_rxfifo.qip
+set_global_assignment -name SYSTEMVERILOG_FILE vjtag_max80.sv
+set_global_assignment -name VERILOG_FILE ip/vjtag/synthesis/vjtag.v
+set_global_assignment -name QIP_FILE ip/vjtag/synthesis/vjtag.qip
 
 
 set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
 set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

+ 38 - 8
fpga/max80.sv

@@ -306,7 +306,7 @@ module max80
    //
    //
    // SDRAM
    // SDRAM
    //
    //
-   localparam dram_port_count = 2;
+   localparam dram_port_count = 3;
    dram_bus sr_bus[1:dram_port_count] ( );
    dram_bus sr_bus[1:dram_port_count] ( );
 
 
    // ABC interface
    // ABC interface
@@ -352,7 +352,7 @@ module max80
 
 
    dram_port #(32)
    dram_port #(32)
    cpu_dram_port (
    cpu_dram_port (
-		  .bus   ( sr_bus[2] ),
+		  .bus   ( sr_bus[3] ),
 		  .prio  ( 2'd1 ),
 		  .prio  ( 2'd1 ),
 		  .addr  ( cpu_mem_addr[24:0] ),
 		  .addr  ( cpu_mem_addr[24:0] ),
 		  .rd    ( sdram_mem_rdata ),
 		  .rd    ( sdram_mem_rdata ),
@@ -469,6 +469,9 @@ module max80
    // CPU permanently hung?
    // CPU permanently hung?
    wire	       cpu_trap;
    wire	       cpu_trap;
 
 
+   // Request to halt the CPU on the next instruction boundary
+   wire        cpu_halt;
+
    always @(negedge rst_n or posedge sys_clk)
    always @(negedge rst_n or posedge sys_clk)
      if (~rst_n)
      if (~rst_n)
        begin
        begin
@@ -485,6 +488,7 @@ module max80
 	    | (cpu_irq & irq_edge_mask & ~(cpu_eoi & ~cpu_eoi_q));
 	    | (cpu_irq & irq_edge_mask & ~(cpu_eoi & ~cpu_eoi_q));
        end
        end
 
 
+   
    picorv32 #(
    picorv32 #(
 	      .ENABLE_COUNTERS ( 1 ),
 	      .ENABLE_COUNTERS ( 1 ),
 	      .ENABLE_COUNTERS64 ( 1 ),
 	      .ENABLE_COUNTERS64 ( 1 ),
@@ -506,11 +510,10 @@ module max80
 	      .LATCHED_IRQ ( 32'h0000_0007 ),
 	      .LATCHED_IRQ ( 32'h0000_0007 ),
 	      .REGS_INIT_ZERO ( 1 ),
 	      .REGS_INIT_ZERO ( 1 ),
 	      .STACKADDR ( 32'h4 << cpu_fast_mem_bits )
 	      .STACKADDR ( 32'h4 << cpu_fast_mem_bits )
-	      )
-
-   cpu (
+   ) cpu (
 	.clk ( sys_clk ),
 	.clk ( sys_clk ),
 	.resetn ( rst_n ),
 	.resetn ( rst_n ),
+	.halt ( cpu_halt ),
 	.trap ( cpu_trap ),
 	.trap ( cpu_trap ),
 
 
 	.progaddr_reset ( _PC_RESET ),
 	.progaddr_reset ( _PC_RESET ),
@@ -605,8 +608,9 @@ module max80
 			      max80_minor, max80_fixes };
 			      max80_minor, max80_fixes };
 
 
    // System reset
    // System reset
-   wire	       usb_rxd_break_rst; // Break due to USB serial port BREAK
-   wire	       tty_rxd_break_rst; // Break due to TTY serial port BREAK
+   wire	       usb_rxd_break_rst; // Reset due to USB serial port BREAK
+   wire	       tty_rxd_break_rst; // Reset due to TTY serial port BREAK
+   wire        vjtag_reset_cmd;	  // Reset due to virtual JTAG request
 
 
    // Reset control. Note that CPU reset command 0 is a noop.
    // Reset control. Note that CPU reset command 0 is a noop.
    wire [3:0] cpu_reset_io_cmd =
    wire [3:0] cpu_reset_io_cmd =
@@ -620,9 +624,11 @@ module max80
    //  - CPU reset command 1
    //  - CPU reset command 1
    //  - CPU entering TRAP state (irrecoverable error)
    //  - CPU entering TRAP state (irrecoverable error)
    //  - BREAK received on console
    //  - BREAK received on console
+   //  - VJTAG request
    //
    //
    assign cpu_reset_cmd[1] = cpu_reset_io_cmd[1] | cpu_trap;
    assign cpu_reset_cmd[1] = cpu_reset_io_cmd[1] | cpu_trap;
-   assign aux_reset_cmd[1] = usb_rxd_break_rst | tty_rxd_break_rst;
+   assign aux_reset_cmd[1] = usb_rxd_break_rst | tty_rxd_break_rst |
+			     vjtag_reset_cmd;
 
 
    //
    //
    // Hard system reset: FPGA not reloaded, PLLs reset, all hw units reset
    // Hard system reset: FPGA not reloaded, PLLs reset, all hw units reset
@@ -874,6 +880,30 @@ module max80
 	    .i2c_sda ( i2c_sda )
 	    .i2c_sda ( i2c_sda )
 	    );
 	    );
 
 
+   // Virtual JTAG interface
+   wire        vjtag_cpu_halt;
+   
+   vjtag_max80 #(.sdram_base_addr(SDRAM_ADDR),
+		 .sdram_bits(SDRAM_BITS))
+   vjtag (
+	  .rst_n	( rst_n ),
+	  .sys_clk      ( sdram_clk ),
+	  
+	  .sdram	( sr_bus[2].dstr ),
+	  
+	  .cpu_valid    ( iodev_valid_vjtag ),
+	  .cpu_addr     ( cpu_mem_addr[6:2] ),
+	  .cpu_wdata    ( cpu_mem_wdata ),
+	  .cpu_wstrb    ( cpu_mem_wstrb ),
+	  .cpu_rdata    ( iodev_rdata_vjtag ),
+	  .cpu_irq      ( iodev_irq_vjtag ),
+	  .cpu_halt     ( vjtag_cpu_halt ),
+ 
+	  .reset_cmd    ( vjtag_reset_cmd )
+	  );
+
+   assign cpu_halt = vjtag_cpu_halt;
+   
    //
    //
    // Registering of I/O data and handling of iodev_mem_ready
    // Registering of I/O data and handling of iodev_mem_ready
    //
    //

+ 20 - 20
fpga/output/sram.mif

@@ -6,7 +6,7 @@ DATA_RADIX = HEX;
 CONTENT BEGIN
 CONTENT BEGIN
 0000 : 00000000;
 0000 : 00000000;
 0001 : 00000000;
 0001 : 00000000;
-0002 : ECD81CE9;
+0002 : F0181CE9;
 0003 : 00200000;
 0003 : 00200000;
 0004 : C0102473;
 0004 : C0102473;
 0005 : 00008137;
 0005 : 00008137;
@@ -62,14 +62,14 @@ CONTENT BEGIN
 0037 : 0F70006F;
 0037 : 0F70006F;
 0038 : 0F30006F;
 0038 : 0F30006F;
 0039 : 0EF0006F;
 0039 : 0EF0006F;
-003A : 00000000;
-003B : 7C5C2D2F;
-003C : 4101D0A0;
-003D : FFFFFFFF;
+003A : 0EB0006F;
+003B : 00000000;
+003C : 7C5C2D2F;
+003D : 4101D0A0;
 003E : FFFFFFFF;
 003E : FFFFFFFF;
-003F : 00001AD0;
-0040 : 00000040;
-0041 : 00000000;
+003F : FFFFFFFF;
+0040 : 00001AD0;
+0041 : 00000040;
 0042 : 00000000;
 0042 : 00000000;
 0043 : 00000000;
 0043 : 00000000;
 0044 : 00000000;
 0044 : 00000000;
@@ -414,7 +414,7 @@ CONTENT BEGIN
 0197 : 02039163;
 0197 : 02039163;
 0198 : 00535513;
 0198 : 00535513;
 0199 : 00357593;
 0199 : 00357593;
-019A : 0EC00693;
+019A : 0F000693;
 019B : 00B68833;
 019B : 00B68833;
 019C : 00084883;
 019C : 00084883;
 019D : 00234E21;
 019D : 00234E21;
@@ -813,7 +813,7 @@ CONTENT BEGIN
 0326 : 19000813;
 0326 : 19000813;
 0327 : 012808B3;
 0327 : 012808B3;
 0328 : 0008A403;
 0328 : 0008A403;
-0329 : 11400023;
+0329 : 11400223;
 032A : 0080A023;
 032A : 0080A023;
 032B : 08200313;
 032B : 08200313;
 032C : 2E03C015;
 032C : 2E03C015;
@@ -839,8 +839,8 @@ CONTENT BEGIN
 0340 : 61054A22;
 0340 : 61054A22;
 0341 : 05138082;
 0341 : 05138082;
 0342 : 4A030400;
 0342 : 4A030400;
-0343 : A0231000;
-0344 : 00230000;
+0343 : A0231040;
+0344 : 02230000;
 0345 : 061310A0;
 0345 : 061310A0;
 0346 : 15230820;
 0346 : 15230820;
 0347 : 2A2388C0;
 0347 : 2A2388C0;
@@ -954,14 +954,14 @@ CONTENT BEGIN
 03B3 : DD62DF5E;
 03B3 : DD62DF5E;
 03B4 : D96ADB66;
 03B4 : D96ADB66;
 03B5 : 0093D76E;
 03B5 : 0093D76E;
-03B6 : 2B030F40;
+03B6 : 2B030F80;
 03B7 : A2831240;
 03B7 : A2831240;
 03B8 : 24830000;
 03B8 : 24830000;
 03B9 : F4138800;
 03B9 : F4138800;
 03BA : 80630054;
 03BA : 80630054;
 03BB : 63091762;
 03BB : 63091762;
 03BC : A1834383;
 03BC : A1834383;
-03BD : 0F400B93;
+03BD : 0F800B93;
 03BE : 0013F513;
 03BE : 0013F513;
 03BF : 1097C171;
 03BF : 1097C171;
 03C0 : 80E74000;
 03C0 : 80E74000;
@@ -1023,7 +1023,7 @@ CONTENT BEGIN
 03F8 : 01682023;
 03F8 : 01682023;
 03F9 : 4A054A81;
 03F9 : 4A054A81;
 03FA : 016BA023;
 03FA : 016BA023;
-03FB : 0F800093;
+03FB : 0FC00093;
 03FC : 0000A703;
 03FC : 0000A703;
 03FD : 0014FB93;
 03FD : 0014FB93;
 03FE : C002C25E;
 03FE : C002C25E;
@@ -1747,12 +1747,12 @@ CONTENT BEGIN
 06CC : 6362612F;
 06CC : 6362612F;
 06CD : 6B736964;
 06CD : 6B736964;
 06CE : 3030382E;
 06CE : 3030382E;
-06CF : 7553002F;
+06CF : 6F4D002F;
 06D0 : 6546206E;
 06D0 : 6546206E;
-06D1 : 36202062;
-06D2 : 3A303020;
-06D3 : 353A3231;
-06D4 : 53502030;
+06D1 : 37202062;
+06D2 : 3A353020;
+06D3 : 353A3532;
+06D4 : 53502031;
 06D5 : 30322054;
 06D5 : 30322054;
 06D6 : 003232;
 06D6 : 003232;
 [06D7..1FFF] : 00;
 [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


+ 33 - 27
fpga/picorv32.v

@@ -102,49 +102,50 @@ module picorv32 #(
 	parameter [ 4:0] RA_IRQ_REG   = ENABLE_IRQ_QREGS ? 26 : 3,
 	parameter [ 4:0] RA_IRQ_REG   = ENABLE_IRQ_QREGS ? 26 : 3,
 	parameter [ 4:0] MASK_IRQ_REG = ENABLE_IRQ_QREGS ? 27 : 4
 	parameter [ 4:0] MASK_IRQ_REG = ENABLE_IRQ_QREGS ? 27 : 4
 ) (
 ) (
-	input		  clk, resetn,
-	output reg	  trap,
+	input 		  clk, resetn,
+	input 		  halt,
+	output reg 	  trap,
 
 
-	input [31:0]	  progaddr_reset,
-        input [31:0]	  progaddr_irq,
+	input [31:0] 	  progaddr_reset,
+        input [31:0] 	  progaddr_irq,
 
 
-	output reg	  mem_valid,
-	output reg	  mem_instr,
-	input		  mem_ready,
+	output reg 	  mem_valid,
+	output reg 	  mem_instr,
+	input 		  mem_ready,
 
 
 	output reg [31:0] mem_addr,
 	output reg [31:0] mem_addr,
 	output reg [31:0] mem_wdata,
 	output reg [31:0] mem_wdata,
 	output reg [ 3:0] mem_wstrb,
 	output reg [ 3:0] mem_wstrb,
-	input [31:0]	  mem_rdata,
+	input [31:0] 	  mem_rdata,
 
 
 	// Look-Ahead Interface
 	// Look-Ahead Interface
-	output		  mem_la_read,
-	output		  mem_la_write,
-	output [31:0]	  mem_la_addr,
+	output 		  mem_la_read,
+	output 		  mem_la_write,
+	output [31:0] 	  mem_la_addr,
 	output reg [31:0] mem_la_wdata,
 	output reg [31:0] mem_la_wdata,
 	output reg [ 3:0] mem_la_wstrb,
 	output reg [ 3:0] mem_la_wstrb,
 
 
 	// Pico Co-Processor Interface (PCPI)
 	// Pico Co-Processor Interface (PCPI)
-	output reg	  pcpi_valid,
+	output reg 	  pcpi_valid,
 	output reg [31:0] pcpi_insn,
 	output reg [31:0] pcpi_insn,
-	output [31:0]	  pcpi_rs1,
-	output [31:0]	  pcpi_rs2,
-	input		  pcpi_wr,
-	input [31:0]	  pcpi_rd,
-	input		  pcpi_wait,
-	input		  pcpi_ready,
+	output [31:0] 	  pcpi_rs1,
+	output [31:0] 	  pcpi_rs2,
+	input 		  pcpi_wr,
+	input [31:0] 	  pcpi_rd,
+	input 		  pcpi_wait,
+	input 		  pcpi_ready,
 
 
 	// IRQ Interface
 	// IRQ Interface
-	input [31:0]	  irq,
+	input [31:0] 	  irq,
 	output reg [31:0] eoi,
 	output reg [31:0] eoi,
 
 
 `ifdef RISCV_FORMAL
 `ifdef RISCV_FORMAL
-	output reg	  rvfi_valid,
+	output reg 	  rvfi_valid,
 	output reg [63:0] rvfi_order,
 	output reg [63:0] rvfi_order,
 	output reg [31:0] rvfi_insn,
 	output reg [31:0] rvfi_insn,
-	output reg	  rvfi_trap,
-	output reg	  rvfi_halt,
-	output reg	  rvfi_intr,
+	output reg 	  rvfi_trap,
+	output reg 	  rvfi_halt,
+	output reg 	  rvfi_intr,
 	output reg [ 1:0] rvfi_mode,
 	output reg [ 1:0] rvfi_mode,
 	output reg [ 1:0] rvfi_ixl,
 	output reg [ 1:0] rvfi_ixl,
 	output reg [ 4:0] rvfi_rs1_addr,
 	output reg [ 4:0] rvfi_rs1_addr,
@@ -173,7 +174,7 @@ module picorv32 #(
 `endif
 `endif
 
 
 	// Trace Interface
 	// Trace Interface
-	output reg	  trace_valid,
+	output reg 	  trace_valid,
 	output reg [35:0] trace_data
 	output reg [35:0] trace_data
 );
 );
 	localparam integer irq_timer = 0;
 	localparam integer irq_timer = 0;
@@ -415,7 +416,7 @@ module picorv32 #(
 		if (!resetn) begin
 		if (!resetn) begin
 			mem_la_firstword_reg <= 0;
 			mem_la_firstword_reg <= 0;
 			last_mem_valid <= 0;
 			last_mem_valid <= 0;
-		end else begin
+		end else if (~halt) begin
 			if (!last_mem_valid)
 			if (!last_mem_valid)
 				mem_la_firstword_reg <= mem_la_firstword;
 				mem_la_firstword_reg <= mem_la_firstword;
 			last_mem_valid <= mem_valid && !mem_ready;
 			last_mem_valid <= mem_valid && !mem_ready;
@@ -1438,7 +1439,9 @@ module picorv32 #(
 	end
 	end
 `endif
 `endif
 
 
-	assign launch_next_insn = cpu_state == cpu_state_fetch && decoder_trigger && (!ENABLE_IRQ || irq_delay || irq_active || !(irq_pending & ~irq_mask));
+	assign launch_next_insn = cpu_state == cpu_state_fetch &&
+				  decoder_trigger &&
+				  (!ENABLE_IRQ || irq_delay || irq_active || !(irq_pending & ~irq_mask));
 
 
 	always @(posedge clk) begin
 	always @(posedge clk) begin
 		trap <= 0;
 		trap <= 0;
@@ -1530,7 +1533,7 @@ module picorv32 #(
 			end
 			end
 
 
 			cpu_state_fetch: begin
 			cpu_state_fetch: begin
-				mem_do_rinst <= !decoder_trigger && !do_waitirq;
+			        mem_do_rinst <= !decoder_trigger && !do_waitirq && !(halt && !irq_state);
 				mem_wordsize <= 0;
 				mem_wordsize <= 0;
 
 
 				current_pc = reg_next_pc;
 				current_pc = reg_next_pc;
@@ -1576,6 +1579,9 @@ module picorv32 #(
 				latched_rd <= decoded_rd;
 				latched_rd <= decoded_rd;
 				latched_compr <= compressed_instr;
 				latched_compr <= compressed_instr;
 
 
+			        if (halt && !irq_state) begin
+				        // Do nothing, but allow an already started instruction or IRQ to complete
+				end else
 				if (ENABLE_IRQ && ((decoder_trigger && !irq_active && !irq_delay && |(irq_pending & ~irq_mask)) || irq_state)) begin
 				if (ENABLE_IRQ && ((decoder_trigger && !irq_active && !irq_delay && |(irq_pending & ~irq_mask)) || irq_state)) begin
 					irq_state <=
 					irq_state <=
 						irq_state == 2'b00 ? 2'b01 :
 						irq_state == 2'b00 ? 2'b01 :

+ 54 - 0
fpga/ub.tcl

@@ -0,0 +1,54 @@
+# -*- tcl -*-
+
+# List all available programming hardwares, and select the USBBlaster.
+# (Note: this example assumes only one USBBlaster connected.)
+puts "Programming Hardwares:"
+foreach hardware_name [get_hardware_names] {
+        puts $hardware_name
+        if { [string match "USB-Blaster*" $hardware_name] } {
+                set usbblaster_name $hardware_name
+        }
+}
+puts "\nSelect JTAG chain connected to $usbblaster_name.\n";
+
+# List all devices on the chain, and select the first device on the chain.
+puts "\nDevices on the JTAG chain:"
+foreach device_name [get_device_names -hardware_name $usbblaster_name] {
+        puts $device_name
+        if { [string match "@1*" $device_name] } {
+                set test_device $device_name
+        }
+}
+puts "\nSelect device: $test_device.\n";
+
+# Virtual JTAG commands
+set vjtag_index 0
+proc vdr {length {value ""}} {
+    upvar vjtag_index ix
+    set opad [string repeat 0 [expr ($length+3)/4 - [string length $value]]]
+    return [device_virtual_dr_shift -instance_index $ix \
+		-show_equivalent_device_ir_dr_shift \
+		-value_in_hex -length $length -dr_value "$opad$value"]
+}
+proc vir {cmd} {
+    upvar vjtag_index ix
+    return [device_virtual_ir_shift -instance_index $ix \
+		-show_equivalent_device_ir_dr_shift \
+		-ir_value $cmd -no_captured_ir_value]
+}
+
+# Device JTAG commands
+proc ddr {length {value ""}} {
+    set opad [string repeat 0 [expr ($length+3)/4 - [string length $value]]]
+    return [device_dr_shift -value_in_hex -length $length \
+		-dr_value "$opad$value"]
+}
+proc dir {cmd} {
+    return [device_ir_shift -ir_value $cmd -no_captured_ir_value]
+}
+
+# Open device 
+open_device -hardware_name $usbblaster_name -device_name $test_device
+
+# Lock device
+device_lock -timeout 100000

+ 10 - 0
fpga/v2.qsf

@@ -8,3 +8,13 @@ set_global_assignment -name SOURCE_TCL_SCRIPT_FILE v2_common.qsf
 
 
 # Quartus insists on this line...
 # Quartus insists on this line...
 set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
 set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
+
+set_global_assignment -name EDA_SIMULATION_TOOL "Questa Intel FPGA (SystemVerilog)"
+set_global_assignment -name EDA_MAP_ILLEGAL_CHARACTERS ON -section_id eda_simulation
+set_global_assignment -name EDA_TIME_SCALE "1 ps" -section_id eda_simulation
+set_global_assignment -name EDA_OUTPUT_DATA_FORMAT "SYSTEMVERILOG HDL" -section_id eda_simulation
+set_global_assignment -name EDA_WRITE_NODES_FOR_POWER_ESTIMATION ALL_NODES -section_id eda_simulation
+set_global_assignment -name EDA_TEST_BENCH_ENABLE_STATUS TEST_BENCH_MODE -section_id eda_simulation
+set_global_assignment -name EDA_NATIVELINK_SIMULATION_TEST_BENCH testclk -section_id eda_simulation
+set_global_assignment -name EDA_TEST_BENCH_DESIGN_INSTANCE_NAME max80 -section_id eda_simulation
+set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

+ 3 - 1
iodevs.conf

@@ -41,5 +41,7 @@ our @iodevs = (
     { -name => 'sdcard',    -irq => 'l' },
     { -name => 'sdcard',    -irq => 'l' },
     { -name => 'i2c',       -irq => 'l' },
     { -name => 'i2c',       -irq => 'l' },
     { -name => 'esp',       -irq => 'l' },
     { -name => 'esp',       -irq => 'l' },
-    { -name => 'random',    -irq => 'l' }
+    { -name => 'random',    -irq => 'l' },
+
+    { -name => 'vjtag',     -irq => 'e' }
 );
 );

+ 1 - 1
rv32/checksum.h

@@ -1,4 +1,4 @@
 #ifndef CHECKSUM_H
 #ifndef CHECKSUM_H
 #define CHECKSUM_H
 #define CHECKSUM_H
-#define SDRAM_SUM 0xecd81ce9
+#define SDRAM_SUM 0xf0181ce9
 #endif
 #endif

+ 5 - 0
rv32/ioregs.h

@@ -151,6 +151,11 @@
 
 
 #define RANDOM_DATA		IODEVRL(RANDOM,0)
 #define RANDOM_DATA		IODEVRL(RANDOM,0)
 
 
+#define VJTAG_CPUCMD		IODEVRL(VJTAG,0)
+#define VJTAG_CPUINFO		IODEVL(VJTAG,1)
+#define VJTAG_CPUSTATUS		IODEVL(VJTAG,2)
+#define VJTAG_CPUSTATUS_SET	IODEVL(VJTAG,3)
+
 #define USBDESC_ROM		IODEVL(USBDESC,0)
 #define USBDESC_ROM		IODEVL(USBDESC,0)
 #define usbdesc_rom		PTR(USBDESC_ROM)
 #define usbdesc_rom		PTR(USBDESC_ROM)