====== ARM DAP ====== ARM DAP分为DP(debug port)和AP (access port), DP一般和串口DP或JTAG口DP AP一般有AHB-AP, AXI-AP, APB-AP, JTAG-AP, mem-ap等 一般来讲,AXI-AP、AHB-AP、APB-AP是执行MEM-AP结构,访问对应总线的memory system. {{:协议学习:pasted:20231106-152200.png?nolink}} ===== - JTAG DP IR command ===== {{:协议学习:pasted:20231106-151642.png?nolink}} ===== - DPACC & APACC TDR ===== 通过DPACC TDR去访问DP register,通过APACC TDR去访问AP register \\ 其定义如下: TDR length为35bit, 低bit数据先传。 TDI输入数据格式定义如下: * bit[34:3]传32bit写数据, * bit[2:1]传DP或AP的地址A[3:2] * bit[0] 表示读(1)或者写操作(0) TDO输出数据格式定义如下: * bit[34:3]传32bit读结果数据, * bit[2:0]表示读响应ACK, 0b010 - OK/FAULT, 0b001 - WAIT {{:协议学习:pasted:20231201-135644.png?nolink}} {{:协议学习:pasted:20231106-151724.png?nolink}} 在操作APACC时,会发起对应的AP操作,一般分为AP写和AP读操作,以下是AP读需要注意的地方。 如果是AP读的话,需要再读一次TDR,但是如果IR还是指定为APACC的话,就会再触发一次AP操作,所以此时可以临时用IR切换为DPACC,这样读结果不会重新AP操作。 通过DP.RDBUFF将AP读数据取出。\\ {{:协议学习:pasted:20241212-090848.png?nolink}} ===== - DP register summary ===== {{:协议学习:pasted:20231201-135514.png?nolink}} SELECT:\\ {{:协议学习:pasted:20241212-102752.png?nolink}} ===== - AP register summary ===== ==== - AHB-AP register summary ==== * AP的地址[7:4]来自于 DP.SELECT寄存器的[7:4] * AP的地址[3:2]来自于APACC TDR里面的A[3:2]地址 {{:协议学习:pasted:20231201-133608.png?nolink}} {{:协议学习:pasted:20231201-133630.png?nolink}} ===== - verilog example code ===== AHB-AP只能生成32bit的ahb地址, AXI-AP可以生成64bit的axi地址。 具体的APSEL可根据实际的dap与ap间的连接关系确定 当然也可以进行APSEL扫描,然后去读AP的0xFC地址,通过读出的Identification Register值来确认AP类型或AP是否存在。 module dap(/*autoarg*/ ); task tck_cycle; input t_tms; input t_tdi; begin #1ns; // sample tdo sample_tdo = tdo; force tck_r = 1'b1; #20ns; force tms_r = t_tms; force tdi_r = t_tdi; force tck_r = 1'b0; #19ns; end endtask task tms5; begin repeat(5) tck_cycle(1'b1,1'b0); end tck_cycle(1'b0, 1'b0); // rti endtask task shift_ir; input [7:0] len; input [255:0] data; integer i=0; begin tck_cycle(1'b1, 1'b0); tck_cycle(1'b1, 1'b0); tck_cycle(1'b0, 1'b0); tck_cycle(1'b0, 1'b0); shift_ret = 0; i=0; repeat(len-1) begin tck_cycle(1'b0, data[i]); shift_ret[i] = sample_tdo; i = i+1; end tck_cycle(1'b1, data[i]); shift_ret[i] = sample_tdo; i = i+1; tck_cycle(1'b1, 1'b0); tck_cycle(1'b0, 1'b0); // rti tck_cycle(1'b0, 1'b0); // rti end endtask task shift_dr; input [7:0] len; input [255:0] data; integer i=0; begin tck_cycle(1'b1, 1'b0); tck_cycle(1'b0, 1'b0); tck_cycle(1'b0, 1'b0); shift_ret = 0; i=0; repeat(len-1) begin tck_cycle(1'b0, data[i]); shift_ret[i] = sample_tdo; i = i+1; end tck_cycle(1'b1, data[i]); shift_ret[i] = sample_tdo; i = i+1; tck_cycle(1'b1, 1'b0); tck_cycle(1'b0, 1'b0); // rti tck_cycle(1'b0, 1'b0); // rti $display("shift_dr ret = %h", shift_ret); end endtask task ahbap_write; input [7:0] ap_addr; input [31:0] ap_data; reg [7:0] ap_sel; begin // dpacc.sel ahb-ap shift_ir(4, 4'ha); #1000; //shift_dr(35, 35'h0); // 32b data, 2b A[3:2] (1:ctrl, 2:ap-sel, 3:read-buffer), 1b RnW (0:write) ap_sel = 8'h0; shift_dr(35, {{ap_sel,16'h0, ap_addr[7:4],4'h0} , 2'h2, 1'b0}); // ap_sel = select ahb-ap (31:24 ap_sel, 7:4 ap_banksel) #1000; // dpacc.ctrl shift_ir(4, 4'ha); #1000; //shift_dr(35, 35'h0); // 32b data, 2b A[3:2] (1:ctrl, 2:ap-sel, 3:read-buffer), 1b RnW (0:write) shift_dr(35, {32'h10000000 , 2'h1, 1'b0}); // CTRL/STAT.CDBGPWRUPREQ #1000; // apacc.read-buffer shift_ir(4, 4'hb); #1000; //shift_dr(35, 35'h0); // 32b data, 2b A[3:2] (dp_addr), 1b RnW (0:write) shift_dr(35, {ap_data, ap_addr[3:2], 1'b0}); // read-buffer #1000; end endtask task ahbap_read; input [7:0] ap_addr; input [31:0] ap_data; reg [7:0] ap_sel; begin // dpacc.sel ahb-ap shift_ir(4, 4'ha); #1000; //shift_dr(35, 35'h0); // 32b data, 2b A[3:2] (1:ctrl, 2:ap-sel, 3:read-buffer), 1b RnW (0:write) ap_sel = 8'h0; shift_dr(35, {{ap_sel,16'h0, ap_addr[7:4],4'h0} , 2'h2, 1'b0}); // ap_sel = select ahb-ap (31:24 ap_sel, 7:4 ap_banksel) #1000; // dpacc.ctrl shift_ir(4, 4'ha); #1000; //shift_dr(35, 35'h0); // 32b data, 2b A[3:2] (1:ctrl, 2:ap-sel, 3:read-buffer), 1b RnW (0:write) shift_dr(35, {32'h10000000 , 2'h1, 1'b0}); // CTRL/STAT.CDBGPWRUPREQ #1000; // apacc.read-buffer shift_ir(4, 4'hb); #1000; //shift_dr(35, 35'h0); // 32b data, 2b A[3:2] (dp_addr), 1b RnW (0:write) shift_dr(35, {ap_data, ap_addr[3:2], 1'b1}); // read-buffer #1000; // dpacc.reserved shift_ir(4, 4'ha); #1000; shift_dr(35, {32'h0 , 2'h0, 1'b0}); // for read ap buffer only, (ret data is in [34:3]) #1000; end endtask task ahb_write; input [31:0] ahb_addr; input [31:0] ahb_data; begin ahbap_write(8'h4, ahb_addr); ahbap_write(8'hc, ahb_data); end endtask task ahb_read; input [31:0] ahb_addr; reg [31:0] ahb_data; begin ahbap_write(8'h4, ahb_addr); ahbap_read(8'hc, 32'h0); ahb_data = shift_ret[34:3]; $display("ahb_read ret = %8h", ahb_data); end endtask initial begin #10000; trstn_r = 1'b1; #1000; tms5; // // idcode // shift_ir(4, 4'he); // #1000; // shift_dr(32, 32'h0); // #1000; ahb_write(32'h0680, 32'h3344); ahb_read(32'h0680); ahb_write(32'h0684, 32'h5566); ahb_read(32'h0684); end endmodule