From cf1dc0b6cbd8485c106d9b6421d4fa17fdbeda1d Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Sat, 17 Sep 2016 13:21:34 -0700 Subject: [PATCH] Implement hardware triggers that match spec. It's basically working, but the following corner cases are failing: TriggerDmode TriggerLoadAddressInstant TriggerStoreAddressInstant --- src/target/riscv/encoding.h | 433 +++++++++++++++++++++----- src/target/riscv/riscv.c | 585 ++++++++++++++++++++++++++---------- 2 files changed, 779 insertions(+), 239 deletions(-) diff --git a/src/target/riscv/encoding.h b/src/target/riscv/encoding.h index 032626ea9..35e0f9fe0 100644 --- a/src/target/riscv/encoding.h +++ b/src/target/riscv/encoding.h @@ -18,6 +18,7 @@ #define MSTATUS_XS 0x00018000 #define MSTATUS_MPRV 0x00020000 #define MSTATUS_PUM 0x00040000 +#define MSTATUS_MXR 0x00080000 #define MSTATUS_VM 0x1F000000 #define MSTATUS32_SD 0x80000000 #define MSTATUS64_SD 0x8000000000000000 @@ -36,7 +37,6 @@ #define DCSR_XDEBUGVER (3U<<30) #define DCSR_NDRESET (1<<29) #define DCSR_FULLRESET (1<<28) -#define DCSR_HWBPCOUNT (0xfff<<16) #define DCSR_EBREAKM (1<<15) #define DCSR_EBREAKH (1<<14) #define DCSR_EBREAKS (1<<13) @@ -56,6 +56,39 @@ #define DCSR_CAUSE_STEP 4 #define DCSR_CAUSE_HALT 5 +#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4)) +#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5)) +#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11)) + +#define MCONTROL_SELECT (1<<19) +#define MCONTROL_TIMING (1<<18) +#define MCONTROL_ACTION (0x3f<<12) +#define MCONTROL_CHAIN (1<<11) +#define MCONTROL_MATCH (0xf<<7) +#define MCONTROL_M (1<<6) +#define MCONTROL_H (1<<5) +#define MCONTROL_S (1<<4) +#define MCONTROL_U (1<<3) +#define MCONTROL_EXECUTE (1<<2) +#define MCONTROL_STORE (1<<1) +#define MCONTROL_LOAD (1<<0) + +#define MCONTROL_TYPE_NONE 0 +#define MCONTROL_TYPE_MATCH 2 + +#define MCONTROL_ACTION_DEBUG_EXCEPTION 0 +#define MCONTROL_ACTION_DEBUG_MODE 1 +#define MCONTROL_ACTION_TRACE_START 2 +#define MCONTROL_ACTION_TRACE_STOP 3 +#define MCONTROL_ACTION_TRACE_EMIT 4 + +#define MCONTROL_MATCH_EQUAL 0 +#define MCONTROL_MATCH_NAPOT 1 +#define MCONTROL_MATCH_GE 2 +#define MCONTROL_MATCH_LT 3 +#define MCONTROL_MATCH_MASK_LOW 4 +#define MCONTROL_MATCH_MASK_HIGH 5 + #define MIP_SSIP (1 << IRQ_S_SOFT) #define MIP_HSIP (1 << IRQ_H_SOFT) #define MIP_MSIP (1 << IRQ_M_SOFT) @@ -102,42 +135,18 @@ // page table entry (PTE) fields #define PTE_V 0x001 // Valid -#define PTE_TYPE 0x01E // Type -#define PTE_R 0x020 // Referenced -#define PTE_D 0x040 // Dirty -#define PTE_SOFT 0x380 // Reserved for Software - -#define PTE_TYPE_TABLE 0x00 -#define PTE_TYPE_TABLE_GLOBAL 0x02 -#define PTE_TYPE_URX_SR 0x04 -#define PTE_TYPE_URWX_SRW 0x06 -#define PTE_TYPE_UR_SR 0x08 -#define PTE_TYPE_URW_SRW 0x0A -#define PTE_TYPE_URX_SRX 0x0C -#define PTE_TYPE_URWX_SRWX 0x0E -#define PTE_TYPE_SR 0x10 -#define PTE_TYPE_SRW 0x12 -#define PTE_TYPE_SRX 0x14 -#define PTE_TYPE_SRWX 0x16 -#define PTE_TYPE_SR_GLOBAL 0x18 -#define PTE_TYPE_SRW_GLOBAL 0x1A -#define PTE_TYPE_SRX_GLOBAL 0x1C -#define PTE_TYPE_SRWX_GLOBAL 0x1E +#define PTE_R 0x002 // Read +#define PTE_W 0x004 // Write +#define PTE_X 0x008 // Execute +#define PTE_U 0x010 // User +#define PTE_G 0x020 // Global +#define PTE_A 0x040 // Accessed +#define PTE_D 0x080 // Dirty +#define PTE_SOFT 0x300 // Reserved for Software #define PTE_PPN_SHIFT 10 -#define PTE_TABLE(PTE) ((0x0000000AU >> ((PTE) & 0x1F)) & 1) -#define PTE_UR(PTE) ((0x0000AAA0U >> ((PTE) & 0x1F)) & 1) -#define PTE_UW(PTE) ((0x00008880U >> ((PTE) & 0x1F)) & 1) -#define PTE_UX(PTE) ((0x0000A0A0U >> ((PTE) & 0x1F)) & 1) -#define PTE_SR(PTE) ((0xAAAAAAA0U >> ((PTE) & 0x1F)) & 1) -#define PTE_SW(PTE) ((0x88888880U >> ((PTE) & 0x1F)) & 1) -#define PTE_SX(PTE) ((0xA0A0A000U >> ((PTE) & 0x1F)) & 1) - -#define PTE_CHECK_PERM(PTE, SUPERVISOR, STORE, FETCH) \ - ((STORE) ? ((SUPERVISOR) ? PTE_SW(PTE) : PTE_UW(PTE)) : \ - (FETCH) ? ((SUPERVISOR) ? PTE_SX(PTE) : PTE_UX(PTE)) : \ - ((SUPERVISOR) ? PTE_SR(PTE) : PTE_UR(PTE))) +#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V) #ifdef __riscv @@ -666,6 +675,35 @@ #define CSR_CYCLE 0xc00 #define CSR_TIME 0xc01 #define CSR_INSTRET 0xc02 +#define CSR_HPMCOUNTER3 0xc03 +#define CSR_HPMCOUNTER4 0xc04 +#define CSR_HPMCOUNTER5 0xc05 +#define CSR_HPMCOUNTER6 0xc06 +#define CSR_HPMCOUNTER7 0xc07 +#define CSR_HPMCOUNTER8 0xc08 +#define CSR_HPMCOUNTER9 0xc09 +#define CSR_HPMCOUNTER10 0xc0a +#define CSR_HPMCOUNTER11 0xc0b +#define CSR_HPMCOUNTER12 0xc0c +#define CSR_HPMCOUNTER13 0xc0d +#define CSR_HPMCOUNTER14 0xc0e +#define CSR_HPMCOUNTER15 0xc0f +#define CSR_HPMCOUNTER16 0xc10 +#define CSR_HPMCOUNTER17 0xc11 +#define CSR_HPMCOUNTER18 0xc12 +#define CSR_HPMCOUNTER19 0xc13 +#define CSR_HPMCOUNTER20 0xc14 +#define CSR_HPMCOUNTER21 0xc15 +#define CSR_HPMCOUNTER22 0xc16 +#define CSR_HPMCOUNTER23 0xc17 +#define CSR_HPMCOUNTER24 0xc18 +#define CSR_HPMCOUNTER25 0xc19 +#define CSR_HPMCOUNTER26 0xc1a +#define CSR_HPMCOUNTER27 0xc1b +#define CSR_HPMCOUNTER28 0xc1c +#define CSR_HPMCOUNTER29 0xc1d +#define CSR_HPMCOUNTER30 0xc1e +#define CSR_HPMCOUNTER31 0xc1f #define CSR_SSTATUS 0x100 #define CSR_SIE 0x104 #define CSR_STVEC 0x105 @@ -675,11 +713,8 @@ #define CSR_SBADADDR 0x143 #define CSR_SIP 0x144 #define CSR_SPTBR 0x180 -#define CSR_SASID 0x181 -#define CSR_SCYCLE 0xd00 -#define CSR_STIME 0xd01 -#define CSR_SINSTRET 0xd02 #define CSR_MSTATUS 0x300 +#define CSR_MISA 0x301 #define CSR_MEDELEG 0x302 #define CSR_MIDELEG 0x303 #define CSR_MIE 0x304 @@ -689,38 +724,142 @@ #define CSR_MCAUSE 0x342 #define CSR_MBADADDR 0x343 #define CSR_MIP 0x344 -#define CSR_MUCOUNTEREN 0x310 -#define CSR_MSCOUNTEREN 0x311 -#define CSR_MUCYCLE_DELTA 0x700 -#define CSR_MUTIME_DELTA 0x701 -#define CSR_MUINSTRET_DELTA 0x702 -#define CSR_MSCYCLE_DELTA 0x704 -#define CSR_MSTIME_DELTA 0x705 -#define CSR_MSINSTRET_DELTA 0x706 +#define CSR_TSELECT 0x7a0 +#define CSR_TDATA1 0x7a1 +#define CSR_TDATA2 0x7a2 +#define CSR_TDATA3 0x7a3 #define CSR_DCSR 0x7b0 #define CSR_DPC 0x7b1 #define CSR_DSCRATCH 0x7b2 -#define CSR_MCYCLE 0xf00 -#define CSR_MTIME 0xf01 -#define CSR_MINSTRET 0xf02 -#define CSR_MISA 0xf10 +#define CSR_MCYCLE 0xb00 +#define CSR_MINSTRET 0xb02 +#define CSR_MHPMCOUNTER3 0xb03 +#define CSR_MHPMCOUNTER4 0xb04 +#define CSR_MHPMCOUNTER5 0xb05 +#define CSR_MHPMCOUNTER6 0xb06 +#define CSR_MHPMCOUNTER7 0xb07 +#define CSR_MHPMCOUNTER8 0xb08 +#define CSR_MHPMCOUNTER9 0xb09 +#define CSR_MHPMCOUNTER10 0xb0a +#define CSR_MHPMCOUNTER11 0xb0b +#define CSR_MHPMCOUNTER12 0xb0c +#define CSR_MHPMCOUNTER13 0xb0d +#define CSR_MHPMCOUNTER14 0xb0e +#define CSR_MHPMCOUNTER15 0xb0f +#define CSR_MHPMCOUNTER16 0xb10 +#define CSR_MHPMCOUNTER17 0xb11 +#define CSR_MHPMCOUNTER18 0xb12 +#define CSR_MHPMCOUNTER19 0xb13 +#define CSR_MHPMCOUNTER20 0xb14 +#define CSR_MHPMCOUNTER21 0xb15 +#define CSR_MHPMCOUNTER22 0xb16 +#define CSR_MHPMCOUNTER23 0xb17 +#define CSR_MHPMCOUNTER24 0xb18 +#define CSR_MHPMCOUNTER25 0xb19 +#define CSR_MHPMCOUNTER26 0xb1a +#define CSR_MHPMCOUNTER27 0xb1b +#define CSR_MHPMCOUNTER28 0xb1c +#define CSR_MHPMCOUNTER29 0xb1d +#define CSR_MHPMCOUNTER30 0xb1e +#define CSR_MHPMCOUNTER31 0xb1f +#define CSR_MUCOUNTEREN 0x320 +#define CSR_MSCOUNTEREN 0x321 +#define CSR_MHPMEVENT3 0x323 +#define CSR_MHPMEVENT4 0x324 +#define CSR_MHPMEVENT5 0x325 +#define CSR_MHPMEVENT6 0x326 +#define CSR_MHPMEVENT7 0x327 +#define CSR_MHPMEVENT8 0x328 +#define CSR_MHPMEVENT9 0x329 +#define CSR_MHPMEVENT10 0x32a +#define CSR_MHPMEVENT11 0x32b +#define CSR_MHPMEVENT12 0x32c +#define CSR_MHPMEVENT13 0x32d +#define CSR_MHPMEVENT14 0x32e +#define CSR_MHPMEVENT15 0x32f +#define CSR_MHPMEVENT16 0x330 +#define CSR_MHPMEVENT17 0x331 +#define CSR_MHPMEVENT18 0x332 +#define CSR_MHPMEVENT19 0x333 +#define CSR_MHPMEVENT20 0x334 +#define CSR_MHPMEVENT21 0x335 +#define CSR_MHPMEVENT22 0x336 +#define CSR_MHPMEVENT23 0x337 +#define CSR_MHPMEVENT24 0x338 +#define CSR_MHPMEVENT25 0x339 +#define CSR_MHPMEVENT26 0x33a +#define CSR_MHPMEVENT27 0x33b +#define CSR_MHPMEVENT28 0x33c +#define CSR_MHPMEVENT29 0x33d +#define CSR_MHPMEVENT30 0x33e +#define CSR_MHPMEVENT31 0x33f #define CSR_MVENDORID 0xf11 #define CSR_MARCHID 0xf12 #define CSR_MIMPID 0xf13 #define CSR_MHARTID 0xf14 -#define CSR_MRESET 0x7c2 #define CSR_CYCLEH 0xc80 #define CSR_TIMEH 0xc81 #define CSR_INSTRETH 0xc82 -#define CSR_MUCYCLE_DELTAH 0x780 -#define CSR_MUTIME_DELTAH 0x781 -#define CSR_MUINSTRET_DELTAH 0x782 -#define CSR_MSCYCLE_DELTAH 0x784 -#define CSR_MSTIME_DELTAH 0x785 -#define CSR_MSINSTRET_DELTAH 0x786 -#define CSR_MCYCLEH 0xf80 -#define CSR_MTIMEH 0xf81 -#define CSR_MINSTRETH 0xf82 +#define CSR_HPMCOUNTER3H 0xc83 +#define CSR_HPMCOUNTER4H 0xc84 +#define CSR_HPMCOUNTER5H 0xc85 +#define CSR_HPMCOUNTER6H 0xc86 +#define CSR_HPMCOUNTER7H 0xc87 +#define CSR_HPMCOUNTER8H 0xc88 +#define CSR_HPMCOUNTER9H 0xc89 +#define CSR_HPMCOUNTER10H 0xc8a +#define CSR_HPMCOUNTER11H 0xc8b +#define CSR_HPMCOUNTER12H 0xc8c +#define CSR_HPMCOUNTER13H 0xc8d +#define CSR_HPMCOUNTER14H 0xc8e +#define CSR_HPMCOUNTER15H 0xc8f +#define CSR_HPMCOUNTER16H 0xc90 +#define CSR_HPMCOUNTER17H 0xc91 +#define CSR_HPMCOUNTER18H 0xc92 +#define CSR_HPMCOUNTER19H 0xc93 +#define CSR_HPMCOUNTER20H 0xc94 +#define CSR_HPMCOUNTER21H 0xc95 +#define CSR_HPMCOUNTER22H 0xc96 +#define CSR_HPMCOUNTER23H 0xc97 +#define CSR_HPMCOUNTER24H 0xc98 +#define CSR_HPMCOUNTER25H 0xc99 +#define CSR_HPMCOUNTER26H 0xc9a +#define CSR_HPMCOUNTER27H 0xc9b +#define CSR_HPMCOUNTER28H 0xc9c +#define CSR_HPMCOUNTER29H 0xc9d +#define CSR_HPMCOUNTER30H 0xc9e +#define CSR_HPMCOUNTER31H 0xc9f +#define CSR_MCYCLEH 0xb80 +#define CSR_MINSTRETH 0xb82 +#define CSR_MHPMCOUNTER3H 0xb83 +#define CSR_MHPMCOUNTER4H 0xb84 +#define CSR_MHPMCOUNTER5H 0xb85 +#define CSR_MHPMCOUNTER6H 0xb86 +#define CSR_MHPMCOUNTER7H 0xb87 +#define CSR_MHPMCOUNTER8H 0xb88 +#define CSR_MHPMCOUNTER9H 0xb89 +#define CSR_MHPMCOUNTER10H 0xb8a +#define CSR_MHPMCOUNTER11H 0xb8b +#define CSR_MHPMCOUNTER12H 0xb8c +#define CSR_MHPMCOUNTER13H 0xb8d +#define CSR_MHPMCOUNTER14H 0xb8e +#define CSR_MHPMCOUNTER15H 0xb8f +#define CSR_MHPMCOUNTER16H 0xb90 +#define CSR_MHPMCOUNTER17H 0xb91 +#define CSR_MHPMCOUNTER18H 0xb92 +#define CSR_MHPMCOUNTER19H 0xb93 +#define CSR_MHPMCOUNTER20H 0xb94 +#define CSR_MHPMCOUNTER21H 0xb95 +#define CSR_MHPMCOUNTER22H 0xb96 +#define CSR_MHPMCOUNTER23H 0xb97 +#define CSR_MHPMCOUNTER24H 0xb98 +#define CSR_MHPMCOUNTER25H 0xb99 +#define CSR_MHPMCOUNTER26H 0xb9a +#define CSR_MHPMCOUNTER27H 0xb9b +#define CSR_MHPMCOUNTER28H 0xb9c +#define CSR_MHPMCOUNTER29H 0xb9d +#define CSR_MHPMCOUNTER30H 0xb9e +#define CSR_MHPMCOUNTER31H 0xb9f #define CAUSE_MISALIGNED_FETCH 0x0 #define CAUSE_FAULT_FETCH 0x1 #define CAUSE_ILLEGAL_INSTRUCTION 0x2 @@ -972,6 +1111,35 @@ DECLARE_CSR(fcsr, CSR_FCSR) DECLARE_CSR(cycle, CSR_CYCLE) DECLARE_CSR(time, CSR_TIME) DECLARE_CSR(instret, CSR_INSTRET) +DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) +DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) +DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) +DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) +DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) +DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) +DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) +DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) +DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) +DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) +DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) +DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) +DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) +DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) +DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) +DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) +DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) +DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) +DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) +DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) +DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) +DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) +DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) +DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) +DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) +DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) +DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) +DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) +DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) DECLARE_CSR(sstatus, CSR_SSTATUS) DECLARE_CSR(sie, CSR_SIE) DECLARE_CSR(stvec, CSR_STVEC) @@ -981,11 +1149,8 @@ DECLARE_CSR(scause, CSR_SCAUSE) DECLARE_CSR(sbadaddr, CSR_SBADADDR) DECLARE_CSR(sip, CSR_SIP) DECLARE_CSR(sptbr, CSR_SPTBR) -DECLARE_CSR(sasid, CSR_SASID) -DECLARE_CSR(scycle, CSR_SCYCLE) -DECLARE_CSR(stime, CSR_STIME) -DECLARE_CSR(sinstret, CSR_SINSTRET) DECLARE_CSR(mstatus, CSR_MSTATUS) +DECLARE_CSR(misa, CSR_MISA) DECLARE_CSR(medeleg, CSR_MEDELEG) DECLARE_CSR(mideleg, CSR_MIDELEG) DECLARE_CSR(mie, CSR_MIE) @@ -995,38 +1160,142 @@ DECLARE_CSR(mepc, CSR_MEPC) DECLARE_CSR(mcause, CSR_MCAUSE) DECLARE_CSR(mbadaddr, CSR_MBADADDR) DECLARE_CSR(mip, CSR_MIP) -DECLARE_CSR(mucounteren, CSR_MUCOUNTEREN) -DECLARE_CSR(mscounteren, CSR_MSCOUNTEREN) -DECLARE_CSR(mucycle_delta, CSR_MUCYCLE_DELTA) -DECLARE_CSR(mutime_delta, CSR_MUTIME_DELTA) -DECLARE_CSR(muinstret_delta, CSR_MUINSTRET_DELTA) -DECLARE_CSR(mscycle_delta, CSR_MSCYCLE_DELTA) -DECLARE_CSR(mstime_delta, CSR_MSTIME_DELTA) -DECLARE_CSR(msinstret_delta, CSR_MSINSTRET_DELTA) +DECLARE_CSR(tselect, CSR_TSELECT) +DECLARE_CSR(tdata1, CSR_TDATA1) +DECLARE_CSR(tdata2, CSR_TDATA2) +DECLARE_CSR(tdata3, CSR_TDATA3) DECLARE_CSR(dcsr, CSR_DCSR) DECLARE_CSR(dpc, CSR_DPC) DECLARE_CSR(dscratch, CSR_DSCRATCH) DECLARE_CSR(mcycle, CSR_MCYCLE) -DECLARE_CSR(mtime, CSR_MTIME) DECLARE_CSR(minstret, CSR_MINSTRET) -DECLARE_CSR(misa, CSR_MISA) +DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) +DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) +DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) +DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) +DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) +DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) +DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) +DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) +DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) +DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) +DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) +DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) +DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) +DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) +DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) +DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) +DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) +DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) +DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) +DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) +DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) +DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) +DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) +DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) +DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) +DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) +DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) +DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) +DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) +DECLARE_CSR(mucounteren, CSR_MUCOUNTEREN) +DECLARE_CSR(mscounteren, CSR_MSCOUNTEREN) +DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) +DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) +DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) +DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) +DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) +DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) +DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) +DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) +DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) +DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) +DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) +DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) +DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) +DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) +DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) +DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) +DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) +DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) +DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) +DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) +DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) +DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) +DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) +DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) +DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) +DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) +DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) +DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) +DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) DECLARE_CSR(mvendorid, CSR_MVENDORID) DECLARE_CSR(marchid, CSR_MARCHID) DECLARE_CSR(mimpid, CSR_MIMPID) DECLARE_CSR(mhartid, CSR_MHARTID) -DECLARE_CSR(mreset, CSR_MRESET) DECLARE_CSR(cycleh, CSR_CYCLEH) DECLARE_CSR(timeh, CSR_TIMEH) DECLARE_CSR(instreth, CSR_INSTRETH) -DECLARE_CSR(mucycle_deltah, CSR_MUCYCLE_DELTAH) -DECLARE_CSR(mutime_deltah, CSR_MUTIME_DELTAH) -DECLARE_CSR(muinstret_deltah, CSR_MUINSTRET_DELTAH) -DECLARE_CSR(mscycle_deltah, CSR_MSCYCLE_DELTAH) -DECLARE_CSR(mstime_deltah, CSR_MSTIME_DELTAH) -DECLARE_CSR(msinstret_deltah, CSR_MSINSTRET_DELTAH) +DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) +DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) +DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) +DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) +DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) +DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) +DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) +DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) +DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) +DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) +DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) +DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) +DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) +DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) +DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) +DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) +DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) +DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) +DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) +DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) +DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) +DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) +DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) +DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) +DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) +DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) +DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) +DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) +DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) DECLARE_CSR(mcycleh, CSR_MCYCLEH) -DECLARE_CSR(mtimeh, CSR_MTIMEH) DECLARE_CSR(minstreth, CSR_MINSTRETH) +DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) +DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) +DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) +DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) +DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) +DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) +DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) +DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) +DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) +DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) +DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) +DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) +DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) +DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) +DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) +DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) +DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) +DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) +DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) +DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) +DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) +DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) +DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) +DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) +DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) +DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) +DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) +DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) +DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) #endif #ifdef DECLARE_CAUSE DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 42ef14af0..d2b0e4cbf 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -26,11 +26,7 @@ #define DIM(x) (sizeof(x)/sizeof(*x)) -#define CSR_TDRSELECT 0x7a0 -#define CSR_TDRDATA1 0x7a1 -#define CSR_TDRDATA2 0x7a2 -#define CSR_TDRDATA3 0x7a3 - +// Constants for legacy SiFive hardware breakpoints. #define CSR_BPCONTROL_X (1<<0) #define CSR_BPCONTROL_W (1<<1) #define CSR_BPCONTROL_R (1<<2) @@ -131,6 +127,15 @@ enum { #define MAX_HWBPS 16 #define DRAM_CACHE_SIZE 16 +struct trigger { + uint64_t address; + uint32_t length; + uint64_t mask; + uint64_t value; + bool read, write, execute; + int unique_id; +}; + struct memory_cache_line { uint32_t data; bool valid; @@ -146,6 +151,9 @@ typedef struct { unsigned int dramsize; uint64_t dcsr; uint64_t dpc; + uint64_t misa; + uint64_t tselect; + bool tselect_dirty; struct memory_cache_line dram_cache[DRAM_CACHE_SIZE]; @@ -156,9 +164,9 @@ typedef struct { /* Single buffer that contains all register values. */ void *reg_values; - // For each physical hwbp, contains ~0 if the hwbp is available, or the - // unique_id of the breakpoint that is using it. - uint32_t hwbp_unique_id[MAX_HWBPS]; + // For each physical trigger, contains -1 if the hwbp is available, or the + // unique_id of the breakpoint/watchpoint that is using it. + int trigger_unique_id[MAX_HWBPS]; // This value is incremented every time a dbus access comes back as "busy". // It's used to determine how many run-test/idle cycles to feed the target @@ -173,6 +181,8 @@ typedef struct { // This cache is write-through, and always valid when the target is halted. uint64_t gpr_cache[32]; + + bool need_strict_step; } riscv_info_t; typedef struct { @@ -183,6 +193,7 @@ typedef struct { /*** Necessary prototypes. ***/ static int riscv_poll(struct target *target); +static int poll_target(struct target *target, bool announce); /*** Utility functions. ***/ @@ -501,7 +512,7 @@ static int dram_check32(struct target *target, unsigned int index, static void cache_set32(struct target *target, unsigned int index, uint32_t data) { riscv_info_t *info = (riscv_info_t *) target->arch_info; - if (info->dram_cache[index].valid && + if (false && info->dram_cache[index].valid && info->dram_cache[index].data == data) { // This is already preset on the target. LOG_DEBUG("cache[0x%x] = 0x%x (hit)", index, data); @@ -817,28 +828,41 @@ static int write_gpr(struct target *target, unsigned int gpr, uint64_t value) return ERROR_OK; } -static int resume(struct target *target, int current, uint32_t address, - int handle_breakpoints, int debug_execution, bool step) +static int maybe_read_tselect(struct target *target) { riscv_info_t *info = (riscv_info_t *) target->arch_info; - if (!current) { - if (info->xlen > 32) { - LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.", - info->xlen); - } - LOG_ERROR("TODO: current is false"); - return ERROR_FAIL; + + if (info->tselect_dirty) { + int result = read_csr(target, &info->tselect, CSR_TSELECT); + if (result != ERROR_OK) + return result; + info->tselect_dirty = false; } - if (handle_breakpoints) { - LOG_ERROR("TODO: handle_breakpoints is true"); - return ERROR_FAIL; + return ERROR_OK; +} + +static int maybe_write_tselect(struct target *target) +{ + riscv_info_t *info = (riscv_info_t *) target->arch_info; + + if (!info->tselect_dirty) { + int result = write_csr(target, CSR_TSELECT, info->tselect); + if (result != ERROR_OK) + return result; + info->tselect_dirty = true; } - if (debug_execution) { - LOG_ERROR("TODO: debug_execution is true"); - return ERROR_FAIL; - } + return ERROR_OK; +} + +static int execute_resume(struct target *target, bool step) +{ + riscv_info_t *info = (riscv_info_t *) target->arch_info; + + LOG_DEBUG("resume(step=%d)", step); + + maybe_write_tselect(target); // TODO: check if dpc is dirty (which also is true if an exception was hit // at any time) @@ -883,6 +907,54 @@ static int resume(struct target *target, int current, uint32_t address, return ERROR_OK; } +// Execute a step, and wait for reentry into Debug Mode. +static int full_step(struct target *target, bool announce) +{ + int result = execute_resume(target, true); + if (result != ERROR_OK) + return result; + time_t start = time(NULL); + while (1) { + result = poll_target(target, announce); + if (result != ERROR_OK) + return result; + if (target->state != TARGET_DEBUG_RUNNING) + break; + if (time(NULL) - start > 2) { + LOG_ERROR("Timed out waiting for step to complete."); + return ERROR_FAIL; + } + } + return ERROR_OK; +} + +static int resume(struct target *target, int current, uint32_t address, + int handle_breakpoints, int debug_execution, bool step) +{ + riscv_info_t *info = (riscv_info_t *) target->arch_info; + + if (!current) { + if (info->xlen > 32) { + LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.", + info->xlen); + } + LOG_ERROR("TODO: current is false"); + return ERROR_FAIL; + } + + if (handle_breakpoints) { + LOG_ERROR("TODO: handle_breakpoints is true"); + return ERROR_FAIL; + } + + if (debug_execution) { + LOG_ERROR("TODO: debug_execution is true"); + return ERROR_FAIL; + } + + return execute_resume(target, step); +} + /** Update register sizes based on xlen. */ static void update_reg_list(struct target *target) { @@ -1024,6 +1096,8 @@ static int register_get(struct reg *reg) struct target *target = (struct target *) reg->arch_info; riscv_info_t *info = (riscv_info_t *) target->arch_info; + maybe_write_tselect(target); + if (reg->number <= REG_XPR31) { buf_set_u64(reg->value, 0, info->xlen, info->gpr_cache[reg->number]); LOG_DEBUG("%s=0x%" PRIx64, reg->name, info->gpr_cache[reg->number]); @@ -1078,6 +1152,8 @@ static int register_write(struct target *target, unsigned int number, { riscv_info_t *info = (riscv_info_t *) target->arch_info; + maybe_write_tselect(target); + if (number == S0) { cache_set_load(target, 0, S0, SLOT0); cache_set32(target, 1, csrw(S0, CSR_DSCRATCH)); @@ -1184,7 +1260,7 @@ static int riscv_init_target(struct command_context *cmd_ctx, } update_reg_list(target); - memset(info->hwbp_unique_id, 0xff, sizeof(info->hwbp_unique_id)); + memset(info->trigger_unique_id, 0xff, sizeof(info->trigger_unique_id)); return ERROR_OK; } @@ -1215,11 +1291,299 @@ static int riscv_halt(struct target *target) return ERROR_OK; } +static int add_trigger(struct target *target, struct trigger *trigger) +{ + riscv_info_t *info = (riscv_info_t *) target->arch_info; + + maybe_read_tselect(target); + + int i; + for (i = 0; i < MAX_HWBPS; i++) { + if (info->trigger_unique_id[i] != -1) { + continue; + } + + uint64_t tselect = i; + write_csr(target, CSR_TSELECT, tselect); + uint64_t tselect_rb; + read_csr(target, &tselect_rb, CSR_TSELECT); + if (tselect_rb != tselect) { + // We've run out of breakpoints. + LOG_ERROR("Couldn't find an available hardware trigger. " + "(0x%" PRIx64 " != 0x%" PRIx64 ")", tselect, + tselect_rb); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + uint64_t tdata1; + read_csr(target, &tdata1, CSR_TDATA1); + int type = get_field(tdata1, MCONTROL_TYPE(info->xlen)); + + if (type != 2) { + continue; + } + + if (tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD)) { + // Trigger is already in use, presumably by user code. + continue; + } + + // address/data match trigger + tdata1 |= MCONTROL_DMODE(info->xlen); + tdata1 = set_field(tdata1, MCONTROL_ACTION, + MCONTROL_ACTION_DEBUG_MODE); + tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL); + tdata1 |= MCONTROL_M; + if (info->misa & (1 << ('H' - 'A'))) + tdata1 |= MCONTROL_H; + if (info->misa & (1 << ('S' - 'A'))) + tdata1 |= MCONTROL_S; + if (info->misa & (1 << ('U' - 'A'))) + tdata1 |= MCONTROL_U; + + if (trigger->execute) + tdata1 |= MCONTROL_EXECUTE; + if (trigger->read) + tdata1 |= MCONTROL_LOAD; + if (trigger->write) + tdata1 |= MCONTROL_STORE; + + write_csr(target, CSR_TDATA1, tdata1); + + uint64_t tdata1_rb; + read_csr(target, &tdata1_rb, CSR_TDATA1); + LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); + + if (tdata1 != tdata1_rb) { + LOG_DEBUG("Trigger %d doesn't support what we need; After writing 0x%" + PRIx64 " to tdata1 it contains 0x%" PRIx64, + i, tdata1, tdata1_rb); + write_csr(target, CSR_TDATA1, 0); + continue; + } + + write_csr(target, CSR_TDATA2, trigger->address); + + LOG_DEBUG("Using resource %d for bp %d", i, + trigger->unique_id); + info->trigger_unique_id[i] = trigger->unique_id; + break; + } + if (i >= MAX_HWBPS) { + LOG_ERROR("Couldn't find an available hardware trigger."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + return ERROR_OK; +} + +static int remove_trigger(struct target *target, struct trigger *trigger) +{ + riscv_info_t *info = (riscv_info_t *) target->arch_info; + + maybe_read_tselect(target); + + int i; + for (i = 0; i < MAX_HWBPS; i++) { + if (info->trigger_unique_id[i] == trigger->unique_id) { + break; + } + } + if (i >= MAX_HWBPS) { + LOG_ERROR("Couldn't find the hardware resources used by hardware " + "trigger."); + return ERROR_FAIL; + } + LOG_DEBUG("Stop using resource %d for bp %d", i, trigger->unique_id); + write_csr(target, CSR_TSELECT, i); + write_csr(target, CSR_TDATA1, 0); + info->trigger_unique_id[i] = -1; + + return ERROR_OK; +} + +static void trigger_from_breakpoint(struct trigger *trigger, + const struct breakpoint *breakpoint) +{ + trigger->address = breakpoint->address; + trigger->length = breakpoint->length; + trigger->mask = ~0LL; + trigger->read = false; + trigger->write = false; + trigger->execute = true; + // unique_id is unique across both breakpoints and watchpoints. + trigger->unique_id = breakpoint->unique_id; +} + +static void trigger_from_watchpoint(struct trigger *trigger, + const struct watchpoint *watchpoint) +{ + trigger->address = watchpoint->address; + trigger->length = watchpoint->length; + trigger->mask = watchpoint->mask; + trigger->value = watchpoint->value; + trigger->read = (watchpoint->rw == WPT_READ || watchpoint->rw == WPT_ACCESS); + trigger->write = (watchpoint->rw == WPT_WRITE || watchpoint->rw == WPT_ACCESS); + trigger->execute = false; + // unique_id is unique across both breakpoints and watchpoints. + trigger->unique_id = watchpoint->unique_id; +} + +static int riscv_add_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + if (breakpoint->type == BKPT_SOFT) { + if (target_read_memory(target, breakpoint->address, breakpoint->length, 1, + breakpoint->orig_instr) != ERROR_OK) { + LOG_ERROR("Failed to read original instruction at 0x%x", + breakpoint->address); + return ERROR_FAIL; + } + + int retval; + if (breakpoint->length == 4) { + retval = target_write_u32(target, breakpoint->address, ebreak()); + } else { + retval = target_write_u16(target, breakpoint->address, ebreak_c()); + } + if (retval != ERROR_OK) { + LOG_ERROR("Failed to write %d-byte breakpoint instruction at 0x%x", + breakpoint->length, breakpoint->address); + return ERROR_FAIL; + } + + } else if (breakpoint->type == BKPT_HARD) { + struct trigger trigger; + trigger_from_breakpoint(&trigger, breakpoint); + int result = add_trigger(target, &trigger); + if (result != ERROR_OK) { + return result; + } + + } else { + LOG_INFO("OpenOCD only supports hardware and software breakpoints."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + breakpoint->set = true; + + return ERROR_OK; +} + +static int riscv_remove_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + if (breakpoint->type == BKPT_SOFT) { + if (target_write_memory(target, breakpoint->address, breakpoint->length, 1, + breakpoint->orig_instr) != ERROR_OK) { + LOG_ERROR("Failed to restore instruction for %d-byte breakpoint at " + "0x%x", breakpoint->length, breakpoint->address); + return ERROR_FAIL; + } + + } else if (breakpoint->type == BKPT_HARD) { + struct trigger trigger; + trigger_from_breakpoint(&trigger, breakpoint); + int result = remove_trigger(target, &trigger); + if (result != ERROR_OK) { + return result; + } + + } else { + LOG_INFO("OpenOCD only supports hardware and software breakpoints."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + breakpoint->set = false; + + return ERROR_OK; +} + +static int riscv_add_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + struct trigger trigger; + trigger_from_watchpoint(&trigger, watchpoint); + + int result = add_trigger(target, &trigger); + if (result != ERROR_OK) { + return result; + } + watchpoint->set = true; + + return ERROR_OK; +} + +static int riscv_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + struct trigger trigger; + trigger_from_watchpoint(&trigger, watchpoint); + + int result = remove_trigger(target, &trigger); + if (result != ERROR_OK) { + return result; + } + watchpoint->set = false; + + return ERROR_OK; +} + +static int strict_step(struct target *target, bool announce) +{ + riscv_info_t *info = (riscv_info_t *) target->arch_info; + + LOG_DEBUG("enter"); + + struct breakpoint *breakpoint = target->breakpoints; + while (breakpoint) { + riscv_remove_breakpoint(target, breakpoint); + breakpoint = breakpoint->next; + } + + struct watchpoint *watchpoint = target->watchpoints; + while (watchpoint) { + riscv_remove_watchpoint(target, watchpoint); + watchpoint = watchpoint->next; + } + + int result = full_step(target, announce); + if (result != ERROR_OK) + return result; + + breakpoint = target->breakpoints; + while (breakpoint) { + riscv_add_breakpoint(target, breakpoint); + breakpoint = breakpoint->next; + } + + watchpoint = target->watchpoints; + while (watchpoint) { + riscv_add_watchpoint(target, watchpoint); + watchpoint = watchpoint->next; + } + + info->need_strict_step = false; + + return ERROR_OK; +} + static int riscv_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { + riscv_info_t *info = (riscv_info_t *) target->arch_info; + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); - return resume(target, current, address, handle_breakpoints, 0, true); + + if (info->need_strict_step) { + int result = strict_step(target, true); + if (result != ERROR_OK) + return result; + } else { + return resume(target, current, address, handle_breakpoints, 0, true); + } + + return ERROR_OK; } static int riscv_examine(struct target *target) @@ -1322,10 +1686,10 @@ static int riscv_examine(struct target *target) target_set_examined(target); - //write_constants(target); - //light_leds(target); - //dram_test(target); - //test_s1(target); + if (read_csr(target, &info->misa, CSR_MISA) != ERROR_OK) { + LOG_ERROR("Failed to read misa."); + return ERROR_FAIL; + } return ERROR_OK; } @@ -1386,9 +1750,11 @@ static riscv_error_t handle_halt_routine(struct target *target) // The first scan result is the result from something old we don't care // about. for (unsigned int i = 1; i < scans->next_scan && dbus_busy == 0; i++) { - dbus_status_t status = scans_get_u32(scans, i, DBUS_OP_START, DBUS_OP_SIZE); + dbus_status_t status = scans_get_u32(scans, i, DBUS_OP_START, + DBUS_OP_SIZE); uint64_t data = scans_get_u64(scans, i, DBUS_DATA_START, DBUS_DATA_SIZE); - uint32_t address = scans_get_u32(scans, i, DBUS_ADDRESS_START, info->addrbits); + uint32_t address = scans_get_u32(scans, i, DBUS_ADDRESS_START, + info->addrbits); LOG_DEBUG("read scan=%d result=%d data=%09" PRIx64 " address=%02x", i, status, data, address); switch (status) { @@ -1483,7 +1849,7 @@ error: return RE_FAIL; } -static int handle_halt(struct target *target) +static int handle_halt(struct target *target, bool announce) { riscv_info_t *info = (riscv_info_t *) target->arch_info; target->state = TARGET_HALTED; @@ -1501,9 +1867,14 @@ static int handle_halt(struct target *target) LOG_DEBUG("halt cause is %d; dcsr=0x%" PRIx64, cause, info->dcsr); switch (cause) { case DCSR_CAUSE_SWBP: - case DCSR_CAUSE_HWBP: target->debug_reason = DBG_REASON_BREAKPOINT; break; + case DCSR_CAUSE_HWBP: + target->debug_reason = DBG_REASON_WPTANDBKPT; + // If we halted because of a data trigger, gdb doesn't know to do + // the disable-breakpoints-step-enable-breakpoints dance. + info->need_strict_step = true; + break; case DCSR_CAUSE_DEBUGINT: target->debug_reason = DBG_REASON_DBGRQ; break; @@ -1516,14 +1887,16 @@ static int handle_halt(struct target *target) cause, info->dcsr); } - target_call_event_callbacks(target, TARGET_EVENT_HALTED); + if (announce) { + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } LOG_DEBUG("halted at 0x%" PRIx64, info->dpc); return ERROR_OK; } -static int riscv_poll(struct target *target) +static int poll_target(struct target *target, bool announce) { jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); bits_t bits = read_bits(target); @@ -1533,7 +1906,7 @@ static int riscv_poll(struct target *target) LOG_DEBUG("debug running"); } else if (bits.haltnot && !bits.interrupt) { if (target->state != TARGET_HALTED) { - return handle_halt(target); + return handle_halt(target, announce); } } else if (!bits.haltnot && bits.interrupt) { // Target is halting. There is no state for that, so don't change anything. @@ -1546,10 +1919,24 @@ static int riscv_poll(struct target *target) return ERROR_OK; } +static int riscv_poll(struct target *target) +{ + return poll_target(target, true); +} + static int riscv_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { + riscv_info_t *info = (riscv_info_t *) target->arch_info; + jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + + if (info->need_strict_step) { + int result = strict_step(target, false); + if (result != ERROR_OK) + return result; + } + return resume(target, current, address, handle_breakpoints, debug_execution, false); } @@ -1953,125 +2340,6 @@ static int riscv_get_gdb_reg_list(struct target *target, return ERROR_OK; } -int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) -{ - riscv_info_t *info = (riscv_info_t *) target->arch_info; - if (breakpoint->type == BKPT_SOFT) { - if (target_read_memory(target, breakpoint->address, breakpoint->length, 1, - breakpoint->orig_instr) != ERROR_OK) { - LOG_ERROR("Failed to read original instruction at 0x%x", - breakpoint->address); - return ERROR_FAIL; - } - - int retval; - if (breakpoint->length == 4) { - retval = target_write_u32(target, breakpoint->address, ebreak()); - } else { - retval = target_write_u16(target, breakpoint->address, ebreak_c()); - } - if (retval != ERROR_OK) { - LOG_ERROR("Failed to write %d-byte breakpoint instruction at 0x%x", - breakpoint->length, breakpoint->address); - return ERROR_FAIL; - } - - } else if (breakpoint->type == BKPT_HARD) { - int i; - uint64_t tdrdata1; - uint64_t tdrselect, tdrselect_rb; - for (i = 0; i < MAX_HWBPS; i++) { - if (info->hwbp_unique_id[i] == ~0U) { - // TODO 0x80000000 is a hack until the core supports proper - // debug hwbps. - tdrselect = 0x80000000 | i; - write_csr(target, CSR_TDRSELECT, tdrselect); - read_csr(target, &tdrselect_rb, CSR_TDRSELECT); - if (tdrselect_rb != tdrselect) { - // We've run out of breakpoints. - LOG_ERROR("Couldn't find an available hardware breakpoint. " - "(0x%" PRIx64 " != 0x%" PRIx64 ")", tdrselect, - tdrselect_rb); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - read_csr(target, &tdrdata1, CSR_TDRDATA1); - if ((tdrdata1 >> (info->xlen - 4)) == 1) { - break; - } - } - } - if (i >= MAX_HWBPS) { - LOG_ERROR("Couldn't find an available hardware breakpoint."); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - LOG_DEBUG("Start using resource %d for bp %d", i, breakpoint->unique_id); - - tdrdata1 |= CSR_BPCONTROL_X; - tdrdata1 |= CSR_BPCONTROL_U; - tdrdata1 |= CSR_BPCONTROL_S; - tdrdata1 |= CSR_BPCONTROL_H; - tdrdata1 |= CSR_BPCONTROL_M; - write_csr(target, CSR_TDRDATA1, tdrdata1); - write_csr(target, CSR_TDRDATA2, breakpoint->address); - - uint64_t tdrdata1_rb; - read_csr(target, &tdrdata1_rb, CSR_TDRDATA1); - LOG_DEBUG("tdrdata1=0x%" PRIx64, tdrdata1_rb); - - if (!(tdrdata1_rb & CSR_BPCONTROL_X)) { - LOG_ERROR("Breakpoint %d doesn't support execute", i); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - info->hwbp_unique_id[i] = breakpoint->unique_id; - } else { - LOG_INFO("OpenOCD only supports hardware and software breakpoints."); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - breakpoint->set = true; - - return ERROR_OK; -} - -static int riscv_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) -{ - riscv_info_t *info = (riscv_info_t *) target->arch_info; - - if (breakpoint->type == BKPT_SOFT) { - if (target_write_memory(target, breakpoint->address, breakpoint->length, 1, - breakpoint->orig_instr) != ERROR_OK) { - LOG_ERROR("Failed to restore instruction for %d-byte breakpoint at 0x%x", - breakpoint->length, breakpoint->address); - return ERROR_FAIL; - } - - } else if (breakpoint->type == BKPT_HARD) { - int i; - for (i = 0; i < MAX_HWBPS; i++) { - if (info->hwbp_unique_id[i] == breakpoint->unique_id) { - break; - } - } - if (i >= MAX_HWBPS) { - LOG_ERROR("Couldn't find the hardware resources used by hardware breakpoint."); - return ERROR_FAIL; - } - LOG_DEBUG("Stop using resource %d for bp %d", i, breakpoint->unique_id); - write_csr(target, CSR_TDRSELECT, 0x80000000 | i); - write_csr(target, CSR_TDRDATA1, 0); - info->hwbp_unique_id[i] = ~0U; - - } else { - LOG_INFO("OpenOCD only supports hardware and software breakpoints."); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - breakpoint->set = false; - - return ERROR_OK; -} - int riscv_arch_state(struct target *target) { return ERROR_OK; @@ -2103,5 +2371,8 @@ struct target_type riscv_target = .add_breakpoint = riscv_add_breakpoint, .remove_breakpoint = riscv_remove_breakpoint, + .add_watchpoint = riscv_add_watchpoint, + .remove_watchpoint = riscv_remove_watchpoint, + .arch_state = riscv_arch_state, };