commit 2d4310d44446df6949a5707abe0683e805b49fd4
parent 4fcfd480baf7e35fc0e6e0c126c0cb485d613fee
Author: Brian Swetland <swetland@frotz.net>
Date: Thu, 3 Jul 2014 23:07:21 -0700
jtag_debug_port and jtag_axi_trace_port
Some tools for inspecting designs via JTAG build on top of the
Xilinx BSCANE2 macro.
Diffstat:
2 files changed, 268 insertions(+), 0 deletions(-)
diff --git a/hdl/jtag_axi_trace_port.sv b/hdl/jtag_axi_trace_port.sv
@@ -0,0 +1,95 @@
+// Copyright 2014 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+`timescale 1ns / 1ps
+
+module jtag_axi_trace_port(
+ axi_ifc.debug axi
+ );
+
+wire clk = axi.aclk;
+
+wire dbg_rd;
+wire dbg_wr;
+wire [2:0]dbg_addr;
+wire [31:0]dbg_wdata;
+reg [31:0]dbg_rdata = 0;
+
+jtag_debug_port port0(
+ .clk(clk),
+ .o_rd(dbg_rd),
+ .o_wr(dbg_wr),
+ .o_addr(dbg_addr),
+ .o_wdata(dbg_wdata),
+ .i_rdata(dbg_rdata)
+ );
+
+wire [63:0]capture_wr = {
+ axi.awaddr, // 63-32
+ axi.awcache, axi.awlen, // 31-24
+ axi.awburst, axi.awsize, axi.awlock, 2'b01, // 23-16
+ axi.awqos, axi.awid // 15-0
+};
+
+wire [63:0]capture_rd = {
+ axi.araddr, // 63-32
+ axi.arcache, axi.arlen, // 31-24
+ axi.arburst, axi.arsize, axi.arlock, 2'b00, // 23-16
+ axi.arqos, axi.arid // 15-0
+};
+
+reg [63:0]trace[0:511];
+reg [8:0]t_wptr = 0;
+reg [8:0]t_rptr = 0;
+
+always_ff @(posedge clk) begin
+ if (axi.awvalid & axi.awready) begin
+ trace[t_wptr] <= capture_wr;
+ if (t_wptr != 511)
+ t_wptr <= t_wptr + 1;
+ end else if (axi.arvalid & axi.arready) begin
+ trace[t_wptr] <= capture_rd;
+ if (t_wptr != 511)
+ t_wptr <= t_wptr + 1;
+ end else if (dbg_wr) begin
+ t_wptr <= 0;
+ t_rptr <= 0;
+ end
+ if (dbg_rd) begin
+ case (dbg_addr)
+ 0: begin
+ dbg_rdata <= 32'hAABBCCDD;
+ end
+ 1: begin
+ dbg_rdata <= trace[t_rptr][31:0];
+ end
+ 2: begin
+ dbg_rdata <= trace[t_rptr][63:32];
+ t_rptr <= t_rptr + 1;
+ end
+ 3: begin
+ dbg_rdata <= { 23'd0, t_wptr };
+ end
+ 4: begin
+ dbg_rdata <= 0;
+ t_rptr <= 0;
+ end
+ default: begin
+ dbg_rdata <= 0;
+ end
+ endcase
+ end
+end
+
+endmodule
diff --git a/hdl/jtag_debug_port.sv b/hdl/jtag_debug_port.sv
@@ -0,0 +1,173 @@
+// Copyright 2014 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+`timescale 1ns / 1ps
+
+/* Exposes a 36bit register on JTAG USER4:
+ *
+ * 35 0
+ * CAAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
+ * | | |
+ * | addr data
+ * commit
+ *
+ * - on JTAG UPDATE
+ * - if commit bit is set:
+ * bits 34:32 are presented on o_addr,
+ * 31:0 are presented on o_wdata,
+ * and o_wr is strobed
+ * - otherwise bits 34:32 are presented on o_addr,
+ * o_rd is strobed, and i_rdata is captured on the next clock
+ *
+ * - to write a register via JTAG:
+ * - shift in {1, addr, data}, UPDATE
+ *
+ * - to read a register via JTAG:
+ * - shift in {0, addr, dontcare}, UPDATE
+ * - data will be returned on next read or write
+ *
+ * - data read back via JTAG will be {1, addr, data}
+ * - addr is the last address read or written
+ * - data is the data that was read or written
+ * - high bit is one
+ */
+
+module jtag_debug_port(
+ output reg o_rd,
+ output reg o_wr,
+ output [RBITS-1:0]o_addr,
+ output [31:0]o_wdata,
+ input [31:0]i_rdata,
+ input clk
+ );
+
+parameter RBITS = 3;
+
+wire capture, sel, shift;
+wire tck, tdi, update;
+
+reg [RBITS+32:0]data_sr; // JTAG shift register
+reg [RBITS+32:0]data_to_jtag; // captured on CAPTURE by sr
+reg [RBITS+32:0]data_to_port; // captured on UPDATE from sr
+reg [RBITS+32:0]data_to_jtag_next;
+reg [RBITS+32:0]data_to_port_next;
+reg o_rd_next;
+reg o_wr_next;
+
+assign o_wdata = data_to_port[31:0];
+assign o_addr = data_to_port[RBITS+31:32];
+
+wire do_txn;
+
+`ifndef verilator
+BSCANE2 #(
+ .JTAG_CHAIN(4)
+ ) bscan (
+ .CAPTURE(capture),
+ .DRCK(),
+ .RESET(),
+ .RUNTEST(),
+ .SEL(sel),
+ .SHIFT(shift),
+ .TCK(tck),
+ .TDI(tdi),
+ .TMS(),
+ .UPDATE(update),
+ .TDO(data_sr[0])
+ );
+`endif
+
+localparam STATE_IDLE = 0;
+localparam STATE_READ = 1;
+localparam STATE_READ2 = 2;
+localparam STATE_WRITE = 3;
+
+reg [1:0]state = STATE_IDLE;
+reg [1:0]state_next;
+
+always @(*) begin
+ state_next = state;
+ data_to_port_next = data_to_port;
+ data_to_jtag_next = data_to_jtag;
+ o_rd_next = 0;
+ o_wr_next = 0;
+
+ case (state)
+ STATE_IDLE: begin
+ if (do_txn) begin
+ data_to_port_next = data_sr;
+ if (data_sr[RBITS+32]) begin
+ state_next = STATE_WRITE;
+ o_wr_next = 1;
+ end else begin
+ state_next = STATE_READ;
+ o_rd_next = 1;
+ end
+ end
+ end
+ STATE_READ: begin
+ state_next = STATE_READ2;
+ end
+ STATE_READ2: begin
+ state_next = STATE_IDLE;
+ data_to_jtag_next = { 1'b1, data_to_port[RBITS+31:32], i_rdata };
+ end
+ STATE_WRITE: begin
+ state_next = STATE_IDLE;
+ data_to_jtag_next = { 1'b1, data_to_port[RBITS+31:0] };
+ end
+ endcase
+end
+
+always @(posedge clk) begin
+ state <= state_next;
+ data_to_port <= data_to_port_next;
+ data_to_jtag <= data_to_jtag_next;
+ o_rd <= o_rd_next;
+ o_wr <= o_wr_next;
+end
+
+wire do_capture = sel & capture;
+wire do_update = sel & update;
+wire do_shift = sel & shift;
+
+always @(posedge tck)
+ if (do_capture)
+ data_sr <= data_to_jtag;
+ else if (do_shift)
+ data_sr <= { tdi, data_sr[RBITS+32:1] };
+
+sync s0(
+ .clk_in(tck),
+ .in(do_update),
+ .clk_out(clk),
+ .out(do_txn)
+ );
+
+endmodule
+
+module sync(
+ input clk_in,
+ input clk_out,
+ input in,
+ output out
+ );
+reg toggle = 1'b0;
+reg [2:0] sync = 3'b0;
+always @(posedge clk_in)
+ if (in) toggle <= ~toggle;
+always @(posedge clk_out)
+ sync <= { sync[1:0], toggle };
+assign out = (sync[2] ^ sync[1]);
+endmodule