用户工具

站点工具


协议学习:arm_dap

这是本文档旧的修订版!


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.

1. JTAG DP IR command

2. DPACC & APACC TDR

通过DPACC TDR去访问DP & 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

在操作APACC时,会发起对应的AP操作,一般分为AP写和AP读操作,以下是AP读需要注意的地方。

如果是AP读的话,需要再读一次TDR,但是如果IR还是指定为APACC的话,就会再触发一次AP操作,所以此时可以临时用IR切换为DPACC,这样读结果不会重新AP操作。

3. DP register summary

4. AP register summary

4.1 AHB-AP register summary

  • AP的地址[7:4]来自于 DP.SELECT寄存器的[7:4]
  • AP的地址[3:2]来自于APACC TDR里面的A[3:2]地址

5. 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]);
        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]);
        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;
 
    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)
    shift_dr(35, {{8'h02,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 [31:0] xpacc_data;
    reg [2:0] ack;
 
    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)
    shift_dr(35, {{8'h02,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;
    repeat(10) begin
        shift_dr(35, {32'h0 , 2'h0, 1'b0}); // for read ap buffer only, (ret data is in [34:3])
        xpacc_data = shift_ret[34:3];
        ack = shift_ret[2:0];
        $display("----xpacc_data ret = %8h, ack = ", xpacc_data, ack);
        if (ack == 3'h2) break;
    end
    #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
 
task ahb_read;
    input [31:0] ahb_addr;
    reg [31:0] ahb_data;
    begin
    //    // idcode
    //    shift_ir(4, 4'he);
    //    #1000;
    //    shift_dr(32, 32'h0);
    //    #1000;
        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
 
endmodule
协议学习/arm_dap.1702014498.txt.gz · 最后更改: 2023/12/08 13:48 由 zhangguo

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki