jtag-mpsse

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

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:
Ahdl/axidebugmaster.v | 222+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahdl/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