commit 8152cec13aebf086270a99e916faab83575c05b4
parent 939ecce404d16e23af69873837ed58a8de530e7d
Author: Brian Swetland <swetland@frotz.net>
Date: Sun, 11 May 2014 19:08:05 -0700
verilog for the fpga side of the mem command
tested on xilinx zynq 010
Diffstat:
A | hdl/axidebugmaster.v | | | 222 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | hdl/debugport.v | | | 142 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 364 insertions(+), 0 deletions(-)
diff --git a/hdl/axidebugmaster.v b/hdl/axidebugmaster.v
@@ -0,0 +1,222 @@
+/* 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 axidebugmaster #(
+ parameter integer C_M00_AXI_ADDR_WIDTH = 32,
+ parameter integer C_M00_AXI_DATA_WIDTH = 32
+ ) (
+ input wire m00_axi_aclk,
+ output wire [C_M00_AXI_ADDR_WIDTH-1 : 0] m00_axi_awaddr,
+ output wire m00_axi_awlock,
+ output wire [3 : 0] m00_axi_awcache,
+ output wire [2 : 0] m00_axi_awprot,
+ output reg m00_axi_awvalid,
+ input wire m00_axi_awready,
+ output wire [C_M00_AXI_DATA_WIDTH-1 : 0] m00_axi_wdata,
+ output wire [C_M00_AXI_DATA_WIDTH/8-1 : 0] m00_axi_wstrb,
+ output reg m00_axi_wvalid,
+ input wire m00_axi_wready,
+ input wire [1 : 0] m00_axi_bresp,
+ input wire m00_axi_bvalid,
+ output reg m00_axi_bready,
+ output wire [C_M00_AXI_ADDR_WIDTH-1 : 0] m00_axi_araddr,
+ output wire m00_axi_arlock,
+ output wire [3 : 0] m00_axi_arcache,
+ output wire [2 : 0] m00_axi_arprot,
+ output reg m00_axi_arvalid,
+ input wire m00_axi_arready,
+ input wire [C_M00_AXI_DATA_WIDTH-1 : 0] m00_axi_rdata,
+ input wire [1 : 0] m00_axi_rresp,
+ input wire m00_axi_rvalid,
+ output reg m00_axi_rready
+ );
+
+wire clk;
+assign clk = m00_axi_aclk;
+
+assign m00_axi_awlock = 0;
+assign m00_axi_awcache = 0;
+assign m00_axi_awprot = 0;
+assign m00_axi_arlock = 0;
+assign m00_axi_arcache = 0;
+assign m00_axi_arprot = 0;
+assign m00_axi_wstrb = 4'b1111;
+
+reg [31:0]txn_addr;
+reg [31:0]txn_addr_next;
+
+reg [31:0]txn_data;
+reg [31:0]txn_data_next;
+
+localparam STATE_IDLE = 3'd0;
+localparam STATE_WADDR = 3'd1;
+localparam STATE_WDATA = 3'd2;
+localparam STATE_WACK = 3'd3;
+localparam STATE_RADDR = 3'd4;
+localparam STATE_RDATA = 3'd5;
+
+localparam DBG_IDCODE = 32'h4158494d;
+
+localparam DBG_R_IDCODE = 3'd0;
+localparam DBG_R_GETDATA = 3'd1;
+localparam DBG_R_GETADDR = 3'd2;
+localparam DBG_R_STATUS = 3'd7;
+
+localparam DBG_W_SETADDR_READ = 3'd1;
+localparam DBG_W_SETADDR = 3'd2;
+localparam DBG_W_SETDATA_WRITE = 3'd3;
+localparam DBG_W_SETDATA_INCADDR_WRITE = 3'd4;
+
+reg [2:0]state = STATE_IDLE;
+reg [2:0]state_next;
+
+reg txn_done = 0;
+reg txn_done_next;
+
+reg awvalid_next;
+reg wvalid_next;
+reg bready_next;
+reg arvalid_next;
+reg rready_next;
+
+assign m00_axi_awaddr = txn_addr;
+assign m00_axi_araddr = txn_addr;
+assign m00_axi_wdata = txn_data;
+
+wire dbg_rd, dbg_wr;
+wire [2:0]dbg_addr;
+wire [31:0]dbg_wdata;
+reg [31:0]dbg_rdata;
+
+always @(posedge clk) begin
+ state <= state_next;
+ txn_addr <= txn_addr_next;
+ txn_data <= txn_data_next;
+ txn_done <= txn_done_next;
+ m00_axi_awvalid = awvalid_next;
+ m00_axi_wvalid = wvalid_next;
+ m00_axi_bready = bready_next;
+ m00_axi_arvalid = arvalid_next;
+ m00_axi_rready = rready_next;
+end
+
+always @(*) begin
+ state_next = state;
+ txn_addr_next = txn_addr;
+ txn_data_next = txn_data;
+ txn_done_next = 0;
+ awvalid_next = 0;
+ wvalid_next = 0;
+ bready_next = 0;
+ arvalid_next = 0;
+ rready_next = 0;
+ case (state)
+ STATE_IDLE: begin
+ if (dbg_wr) begin
+ case (dbg_addr)
+ DBG_W_SETADDR: begin
+ txn_addr_next = dbg_wdata;
+ end
+ DBG_W_SETADDR_READ: begin
+ state_next = STATE_RADDR;
+ txn_addr_next = dbg_wdata;
+ arvalid_next = 1;
+ end
+ DBG_W_SETDATA_WRITE: begin
+ state_next = STATE_WADDR;
+ txn_data_next = dbg_wdata;
+ awvalid_next = 1;
+ end
+ DBG_W_SETDATA_INCADDR_WRITE: begin
+ state_next = STATE_WADDR;
+ txn_data_next = dbg_wdata;
+ txn_addr_next = txn_addr + 4;
+ awvalid_next = 1;
+ end
+ default: ;
+ endcase
+ end else begin
+ txn_done_next = 1;
+ end
+ end
+ STATE_WADDR: begin
+ if (m00_axi_awready) begin
+ state_next = STATE_WDATA;
+ wvalid_next = 1;
+ end else begin
+ awvalid_next = 1;
+ end
+ end
+ STATE_WDATA: begin
+ if (m00_axi_wready) begin
+ state_next = STATE_WACK;
+ bready_next = 1;
+ end else begin
+ wvalid_next = 1;
+ end
+ end
+ STATE_WACK: begin
+ if (m00_axi_bvalid) begin
+ state_next = STATE_IDLE;
+ txn_done_next = 1;
+ end else begin
+ bready_next = 1;
+ end
+ end
+ STATE_RADDR: begin
+ if (m00_axi_arready) begin
+ state_next = STATE_RDATA;
+ rready_next = 1;
+ end else begin
+ arvalid_next = 1;
+ end
+ end
+ STATE_RDATA: begin
+ if (m00_axi_rvalid) begin
+ state_next = STATE_IDLE;
+ txn_done_next = 1;
+ txn_data_next = m00_axi_rdata;
+ end else begin
+ rready_next = 1;
+ end
+ end
+ default: begin
+ state_next = STATE_IDLE;
+ end
+ endcase
+end
+
+always @(*) begin
+ case (dbg_addr)
+ DBG_R_IDCODE: dbg_rdata = DBG_IDCODE;
+ DBG_R_GETDATA: dbg_rdata = txn_data;
+ DBG_R_GETADDR: dbg_rdata = txn_addr;
+ DBG_R_STATUS: dbg_rdata = { 31'd0, txn_done };
+ default: dbg_rdata = 32'hFFFFFFFF;
+ endcase
+end
+
+debugport jtag(
+ .o_rd(dbg_rd),
+ .o_wr(dbg_wr),
+ .o_addr(dbg_addr),
+ .o_wdata(dbg_wdata),
+ .i_rdata(dbg_rdata),
+ .clk(clk)
+ );
+
+endmodule
diff --git a/hdl/debugport.v b/hdl/debugport.v
@@ -0,0 +1,142 @@
+/* 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
+ *
+ * - 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
+ *
+ */
+module debugport(
+ output o_rd,
+ output o_wr,
+ output [2:0]o_addr,
+ output [31:0]o_wdata,
+ input [31:0]i_rdata,
+ input clk
+ );
+
+wire capture, sel, shift;
+wire tck, tdi, update;
+
+(* KEEP = "TRUE" *) reg [31:0] io = 32'd0;
+(* KEEP = "TRUE" *) reg [35:0] data = 36'd0;
+
+wire do_txn;
+reg do_rd, do_wr;
+
+assign o_wdata = io;
+assign o_wr = do_wr;
+
+assign o_addr = data[34:32];
+assign o_rd = do_txn & (~data[35]);
+
+`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[0])
+ );
+`endif
+
+reg [31:0]io_next;
+reg do_wr_next;
+reg do_rd_next;
+
+always @(*) begin
+ io_next = io;
+ do_wr_next = 1'b0;
+ do_rd_next = 1'b0;
+ if (do_txn) begin
+ io_next = data[31:0];
+ if (data[35])
+ do_wr_next = 1'b1;
+ else
+ do_rd_next = 1'b1;
+ end else if(do_rd) begin
+ io_next = i_rdata;
+ end
+end
+
+always @(posedge clk) begin
+ io <= io_next;
+ do_wr <= do_wr_next;
+ do_rd <= do_rd_next;
+end
+
+wire do_capture = sel & capture;
+wire do_update = sel & update;
+wire do_shift = sel & shift;
+
+always @(posedge tck)
+ if (do_capture)
+ data <= { 4'h0, io };
+ else if (do_shift)
+ data <= { tdi, data[35: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