Skip to content

Commit 92fe249

Browse files
committed
Continued initial SWD implementation
1 parent 57120a3 commit 92fe249

File tree

5 files changed

+153
-17
lines changed

5 files changed

+153
-17
lines changed

ARMDebugPort.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,22 @@ class ARMDebugPort : public DebuggerInterface
6363
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
6464
// AP register access
6565

66+
//Well-defined DP registers (superset of supported registers for all ADI versions)
67+
enum DpReg
68+
{
69+
REG_ABORT = 0x00, //write only
70+
REG_DP_IDR = 0x00, //read only
71+
72+
REG_CTRL_STAT = 0x01, //BANKSEL = 0
73+
REG_TARGETID = 0x01, //BANKSEL = 2
74+
75+
REG_RESEND = 0x02, //read only
76+
REG_AP_SELECT = 0x02, //write only
77+
78+
REG_RDBUFF = 0x03,
79+
REG_TARGETSEL = 0x03
80+
};
81+
6682
//Well-defined AP registers
6783
enum ApReg
6884
{
@@ -80,6 +96,10 @@ class ARMDebugPort : public DebuggerInterface
8096
//need to be a friend so that the Mem-AP can poke registers
8197
//TODO: try to find a cleaner way to expose this?
8298
friend class ARMDebugMemAccessPort;
99+
100+
//these use register numbers, not addresses
101+
virtual uint32_t DPRegisterRead(DpReg addr) =0;
102+
virtual void DPRegisterWrite(DpReg addr, uint32_t wdata) =0;
83103
virtual uint32_t APRegisterRead(uint8_t ap, ApReg addr) =0;
84104
virtual void APRegisterWrite(uint8_t ap, ApReg addr, uint32_t wdata) =0;
85105

ARMJtagDebugPort.h

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,6 @@ class ARMJtagDebugPort : public ARMDebugPort
181181
OP_READ = 1
182182
};
183183

184-
//Well-defined DP registers
185-
enum DpReg
186-
{
187-
REG_CTRL_STAT = 1,
188-
REG_AP_SELECT = 2,
189-
REG_RDBUFF = 3
190-
};
191-
192184
public:
193185
ARMJtagDebugPortStatusRegister GetStatusRegister();
194186
void PrintStatusRegister(ARMJtagDebugPortStatusRegister reg, bool children = true);
@@ -198,14 +190,14 @@ class ARMJtagDebugPort : public ARMDebugPort
198190
protected:
199191
void ClearStatusRegisterErrors();
200192

201-
uint32_t DPRegisterRead(DpReg addr);
202-
void DPRegisterWrite(DpReg addr, uint32_t wdata);
193+
virtual uint32_t DPRegisterRead(DpReg addr);
194+
virtual void DPRegisterWrite(DpReg addr, uint32_t wdata);
203195

204196
//need to be a friend so that the Mem-AP can poke registers
205197
//TODO: try to find a cleaner way to expose this?
206198
friend class ARMDebugMemAccessPort;
207-
uint32_t APRegisterRead(uint8_t ap, ApReg addr);
208-
void APRegisterWrite(uint8_t ap, ApReg addr, uint32_t wdata);
199+
virtual uint32_t APRegisterRead(uint8_t ap, ApReg addr);
200+
virtual void APRegisterWrite(uint8_t ap, ApReg addr, uint32_t wdata);
209201

210202
void EnableDebugging();
211203

FTDISWDInterface.cpp

Lines changed: 95 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ void FTDISWDInterface::ResetInterface()
124124

125125
/**
126126
@brief Performs a SW-DP write transaction
127+
128+
TODO: optimize to 1 transaction using overrun detection?
127129
*/
128130
void FTDISWDInterface::WriteWord(uint8_t reg_addr, bool ap, uint32_t wdata)
129131
{
@@ -163,7 +165,7 @@ void FTDISWDInterface::WriteWord(uint8_t reg_addr, bool ap, uint32_t wdata)
163165
(m_gpioDirection[1] << 5) |
164166
(m_gpioDirection[2] << 6) |
165167
(m_gpioDirection[3] << 7) |
166-
0x0B
168+
0x0B;
167169

168170
//Calculate the parity for the data
169171
uint32_t dpartmp = (wdata >> 16) | (wdata >> 8) | (wdata >> 4) | (wdata >> 2) | (wdata >> 1) | wdata;
@@ -246,16 +248,104 @@ uint32_t FTDISWDInterface::ReadWord(uint8_t reg_addr, bool ap)
246248
{
247249
//Host to target: 8 bit header
248250
//LSB first: 1, AP / #DP, 1, A[2:3], Parity, 0, 1
251+
uint8_t header = 0x85;
252+
bool parity = true;
253+
if(ap)
254+
{
255+
header |= 0x02;
256+
parity ^= 1;
257+
}
258+
if(reg_addr & 4)
259+
{
260+
header |= 0x08;
261+
parity ^= 1;
262+
}
263+
if(reg_addr & 8)
264+
{
265+
header |= 0x10;
266+
parity ^= 1;
267+
}
268+
if(parity)
269+
header |= 0x20;
249270

250-
//1 bit bus turnaround (tristate)
271+
//We need to switch the TDO/SWDIO pin back and forth from output to tristate a couple of times.
272+
//It's also a GPIO bitbang pin, though - so we need to reconfigure the low GPIO bank a bunch.
273+
//Bit 1 = TDI = output (1) by default
274+
unsigned char value_low =
275+
(m_gpioValue[0] << 4) |
276+
(m_gpioValue[1] << 5) |
277+
(m_gpioValue[2] << 6) |
278+
(m_gpioValue[3] << 7) |
279+
0x08;
280+
unsigned char dir_low =
281+
(m_gpioDirection[0] << 4) |
282+
(m_gpioDirection[1] << 5) |
283+
(m_gpioDirection[2] << 6) |
284+
(m_gpioDirection[3] << 7) |
285+
0x0B;
251286

252-
//3 bit ACK from target
287+
uint8_t cmdbuf[] =
288+
{
289+
//The header
290+
header,
253291

254-
//Read data from target to host: 32 bits, LSB first
292+
//Tristate TDI
293+
MPSSE_SET_DATA_LOW,
294+
value_low,
295+
dir_low ^ 0x2, //flip TDI to an input
255296

256-
//1 bit parity
297+
//Send a 1-bit bus turnaround as tristate
298+
MPSSE_DUMMY_CLOCK_BITS,
299+
0x00,
257300

301+
//Read the three-bit ACK from the target
302+
MPSSE_TXRX_BYTES,
303+
0x02,
304+
0x00,
305+
0x00 //TDI is tristated so send data doesn't matter
306+
};
307+
WriteDataRaw(cmdbuf, sizeof(cmdbuf));
308+
309+
//Send everything up to the ACK then see what comes back (should be a single byte)
310+
uint8_t ack = 0;
311+
ReadData(&ack, 1);
312+
313+
//WAIT request? TODO
314+
if(ack == 2)
315+
{
316+
LogError("TODO: Handle WAIT request from SW-DP\n");
317+
return 0;
318+
}
319+
320+
//Some strange response that isn't what we expect
321+
else if(ack != 1)
322+
{
323+
LogError("Weird - we got something other than ACK or WAIT\n");
324+
return 0;
325+
}
326+
327+
//Read data from target to host: 32 bits, LSB first
328+
//1 bit parity
258329
//1 bit bus turnaround (tristate)
330+
uint8_t rxd[5];
331+
uint8_t databuf[] =
332+
{
333+
//Read the data plus parity bits
334+
MPSSE_TXRX_BITS,
335+
0x20, //33 total bits
336+
0x00, 0x00, 0x00, 0x00, 0x00,
337+
338+
//Send a bus turnaround cycle so the target can tristate the bus
339+
MPSSE_DUMMY_CLOCK_BITS,
340+
0x00, //1 bit
341+
342+
//Reconfigure TDI to actually drive again
343+
MPSSE_SET_DATA_LOW,
344+
value_low,
345+
dir_low
346+
};
347+
WriteDataRaw(databuf, sizeof(databuf));
348+
ReadData(&rxd, 5);
259349
}
260350

261351
#endif

SWDInterface.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,36 @@ SWDInterface::~SWDInterface()
4646
{
4747
}
4848

49+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
50+
// AP/DP register access
51+
52+
uint32_t SWDInterface::DPRegisterRead(DpReg addr)
53+
{
54+
return ReadWord(addr * 4, false); //convert from register ID to actual address offset
55+
}
56+
57+
void SWDInterface::DPRegisterWrite(DpReg addr, uint32_t wdata)
58+
{
59+
WriteWord(addr*4, wdata); //convert from register ID to actual address offset
60+
}
61+
62+
uint32_t SWDInterface::APRegisterRead(uint8_t ap, ApReg addr)
63+
{
64+
//TODO: select the AP we're using
65+
return ReadWord(addr * 4, true); //convert from register ID to actual address offset
66+
}
67+
68+
void SWDInterface::APRegisterWrite(uint8_t ap, ApReg addr, uint32_t wdata)
69+
{
70+
//TODO: select the AP we're using
71+
72+
WriteWord(addr*4, wdata); //convert from register ID to actual address offset
73+
}
74+
4975
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
5076
// Autodetection
5177

5278
void SWDInterface::InitializeDevice()
5379
{
80+
//Read the
5481
}

SWDInterface.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
4646
A SWD adapter provides access to a single SW-DP (TODO: or SWJ-DP) on a single ARM SoC.
4747
48+
Note that there is no ARMSWDDebugPort class; this class contains both the adapter and DP logic.
49+
4850
In order to support a new "dumb" SWD adapter without any higher level protocol offload, create a new derived class
4951
and implement each of the following functions:
5052
@@ -72,6 +74,11 @@ class SWDInterface : public ARMDebugPort
7274

7375
//Raw SWD read/write
7476
protected:
77+
virtual uint32_t DPRegisterRead(DpReg addr);
78+
virtual void DPRegisterWrite(DpReg addr, uint32_t wdata);
79+
virtual uint32_t APRegisterRead(uint8_t ap, ApReg addr);
80+
virtual void APRegisterWrite(uint8_t ap, ApReg addr, uint32_t wdata);
81+
7582
/**
7683
@brief Performs a SW-DP write transaction
7784
*/

0 commit comments

Comments
 (0)