Swadge 2024 2.0.0
APIs to develop games for the Magfest Swadge
Loading...
Searching...
No Matches
ch32v003_swio.h
Go to the documentation of this file.
1// CH32V003 SWIO minimal reference implementation for bit banged IO
2// on the ESP32-S2.
3//
4// Copyright 2023 Charles Lohr, May be licensed under the MIT/x11 or NewBSD
5// licenses. You choose. (Can be included in commercial and copyleft work)
6//
7// This file is original work.
8//
9// Mostly tested, though, not perfect. Expect to tweak some things.
10// DoSongAndDanceToEnterPgmMode is almost completely untested.
11// This is the weird song-and-dance that the WCH LinkE does when
12// connecting to a CH32V003 part with unknown state. This is probably
13// incorrect, but isn't really needed unless things get really cursed.
14//
15// SWD Code based on:
16// https://github.com/fxsheep/openocd_wchlink-rv/wiki/WCH-RVSWD-protocol
17// https://github.com/perigoso/sigrok-rvswd
18
19#ifndef _CH32V003_SWIO_H
20#define _CH32V003_SWIO_H
21
22// This is a hacky thing, but if you are laaaaazzzyyyy and don't want to add a 10k
23// resistor, youcan do this. It glitches the line high very, very briefly.
24// Enable for when you don't have a 10k pull-upand are relying on the internal pull-up.
25// WARNING: If you set this, you should set the drive current to 5mA.
26#define R_GLITCH_HIGH
27
28// You should interface to this file via these functions
29
42
44{
45 // Set these before calling any functions
49 int opmode; // 0 for SWIO, 1 for SWD
52
53 // Zero the rest of the structure.
54 uint32_t statetag;
58 uint32_t autoincrement;
59};
60
61#define STTAG(x) (*((uint32_t*)(x)))
62
63#define IRAM IRAM_ATTR
64
65// You may need to rewrite, depending on your architecture.
66static inline void Send1BitSWIO(int t1coeff, int pinmaskD) IRAM;
67static inline void Send0BitSWIO(int t1coeff, int pinmaskD) IRAM;
68static inline int ReadBitSWIO(struct SWIOState* state) IRAM;
69static inline void SendBitRVSWD(int t1coeff, int pinmaskD, int pinmaskC, int val) IRAM;
70static inline int ReadBitRVSWD(int t1coeff, int pinmaskD, int pinmaskC) IRAM;
71
72// Provided Basic functions
73static void MCFWriteReg32(struct SWIOState* state, uint8_t command, uint32_t value) IRAM;
74static int MCFReadReg32(struct SWIOState* state, uint8_t command, uint32_t* value) IRAM;
75
76// More advanced functions built on lower level PHY.
77static int InitializeSWDSWIO(struct SWIOState* state);
78static int ReadWord(struct SWIOState* state, uint32_t word, uint32_t* ret);
79static int WriteWord(struct SWIOState* state, uint32_t word, uint32_t val);
80static int WaitForFlash(struct SWIOState* state);
81static int WaitForDoneOp(struct SWIOState* state);
82static int Write64Block(struct SWIOState* iss, uint32_t address_to_write, const uint8_t* data);
83static int UnlockFlash(struct SWIOState* iss);
84static int EraseFlash(struct SWIOState* iss, uint32_t address, uint32_t length, int type);
85static void ResetInternalProgrammingState(struct SWIOState* iss);
86static int PollTerminal(struct SWIOState* iss, uint8_t* buffer, int maxlen, uint32_t leavevalA, uint32_t leavevalB);
87
88#define DMDATA0 0x04
89#define DMDATA1 0x05
90#define DMCONTROL 0x10
91#define DMSTATUS 0x11
92#define DMHARTINFO 0x12
93#define DMABSTRACTCS 0x16
94#define DMCOMMAND 0x17
95#define DMABSTRACTAUTO 0x18
96#define DMPROGBUF0 0x20
97#define DMPROGBUF1 0x21
98#define DMPROGBUF2 0x22
99#define DMPROGBUF3 0x23
100#define DMPROGBUF4 0x24
101#define DMPROGBUF5 0x25
102#define DMPROGBUF6 0x26
103#define DMPROGBUF7 0x27
104
105#define DMCPBR 0x7C
106#define DMCFGR 0x7D
107#define DMSHDWCFGR 0x7E
108
109#define FLASH_STATR_WRPRTERR ((uint8_t)0x10)
110#define CR_PAGE_PG ((uint32_t)0x00010000)
111#define CR_BUF_LOAD ((uint32_t)0x00040000)
112#define FLASH_CTLR_MER ((uint16_t)0x0004) /* Mass Erase */
113#define CR_STRT_Set ((uint32_t)0x00000040)
114#define CR_PAGE_ER ((uint32_t)0x00020000)
115#define CR_BUF_RST ((uint32_t)0x00080000)
116
117static inline void PrecDelay(int delay)
118{
119 asm volatile("1: addi %[delay], %[delay], -1\n"
120 " bbci %[delay], 31, 1b\n"
121 : [delay] "+r"(delay));
122}
123
124// TODO: Add continuation (bypass) functions.
125// TODO: Consider adding parity bit (though it seems rather useless)
126
127// All three bit functions assume bus state will be in
128// GPIO.out_w1ts = pinmask;
129// GPIO.enable_w1ts = pinmask;
130// when they are called.
131
132static inline void Send1BitSWIO(int t1coeff, int pinmaskD)
133{
134 // Low for a nominal period of time.
135 // High for a nominal period of time.
136
137 GPIO_VAR_W1TC = pinmaskD;
138 PrecDelay(t1coeff);
139 GPIO_VAR_W1TS = pinmaskD;
140 PrecDelay(t1coeff + 1);
141}
142
143static inline void Send0BitSWIO(int t1coeff, int pinmaskD)
144{
145 // Low for a LONG period of time.
146 // High for a nominal period of time.
147 int longwait = t1coeff * 4;
148 GPIO_VAR_W1TC = pinmaskD;
149 PrecDelay(longwait + 2);
150 GPIO_VAR_W1TS = pinmaskD;
151 PrecDelay(t1coeff + 1);
152}
153
154// returns 0 if 0
155// returns 1 if 1
156// returns 2 if timeout.
157static inline int ReadBitSWIO(struct SWIOState* state)
158{
159 int t1coeff = state->t1coeff;
160 int pinmaskD = state->pinmaskD;
161
162 // Drive low, very briefly. Let drift high.
163 // See if CH32V003 is holding low.
164
165 int timeout = 0;
166 int ret = 0;
167 int medwait = t1coeff * 2;
168 GPIO_VAR_W1TC = pinmaskD;
169 PrecDelay(t1coeff);
170 GPIO_VAR_ENABLE_W1TC = pinmaskD;
171 GPIO_VAR_W1TS = pinmaskD;
172#ifdef R_GLITCH_HIGH
173 int halfwait = t1coeff / 2;
174 PrecDelay(halfwait - 3);
175 GPIO_VAR_ENABLE_W1TS = pinmaskD;
176 GPIO_VAR_ENABLE_W1TC = pinmaskD;
177 PrecDelay(halfwait + 1);
178#else
179 PrecDelay(medwait);
180#endif
181 ret = GPIO_VAR_IN;
182
183#ifdef R_GLITCH_HIGH
184 if (!(ret & pinmaskD))
185 {
186 // Wait if still low.
187 PrecDelay(medwait);
188 GPIO_VAR_ENABLE_W1TS = pinmaskD;
189 GPIO_VAR_ENABLE_W1TC = pinmaskD;
190 }
191#endif
192 for (timeout = 0; timeout < MAX_IN_TIMEOUT; timeout++)
193 {
194 if (GPIO_VAR_IN & pinmaskD)
195 {
196 GPIO_VAR_ENABLE_W1TS = pinmaskD;
197 int fastwait = t1coeff / 2;
198 PrecDelay(fastwait);
199 return !!(ret & pinmaskD);
200 }
201 }
202
203 // Force high anyway so, though hazarded, we can still move along.
204 GPIO_VAR_ENABLE_W1TS = pinmaskD;
205 return 2;
206}
207
208static inline void SendBitRVSWD(int t1coeff, int pinmaskD, int pinmaskC, int val)
209{
210 // Assume:
211 // SWD is in indeterminte state.
212 // SWC is HIGH
213 GPIO_VAR_W1TC = pinmaskC;
214 if (val)
215 GPIO_VAR_W1TS = pinmaskD;
216 else
217 GPIO_VAR_W1TC = pinmaskD;
218 GPIO_VAR_ENABLE_W1TS = pinmaskD;
219 PrecDelay(t1coeff);
220 GPIO_VAR_W1TS = pinmaskC;
221 PrecDelay(t1coeff);
222}
223
224static inline int ReadBitRVSWD(int t1coeff, int pinmaskD, int pinmaskC)
225{
226 GPIO_VAR_ENABLE_W1TC = pinmaskD;
227 GPIO_VAR_W1TC = pinmaskC;
228 GPIO_VAR_W1TS = pinmaskD;
229 PrecDelay(t1coeff);
230 int r = !!(GPIO_VAR_IN & pinmaskD);
231 GPIO_VAR_W1TS = pinmaskC;
232 PrecDelay(t1coeff);
233 return r;
234}
235
236static void MCFWriteReg32(struct SWIOState* state, uint8_t command, uint32_t value)
237{
238 int t1coeff = state->t1coeff;
239 int pinmaskD = state->pinmaskD;
240 int pinmaskC = state->pinmaskC;
241 GPIO_VAR_W1TS = pinmaskC;
242 GPIO_VAR_ENABLE_W1TS = pinmaskC;
243 GPIO_VAR_W1TS = pinmaskD;
244 GPIO_VAR_ENABLE_W1TS = pinmaskD;
245 // uprintf( "CO: (%08x=>%08x) %08x %08x %d %d\n", command, value, pinmaskD, pinmaskC, t1coeff, state->opmode );
246 if (state->opmode == 0)
247 {
248 DisableISR();
249 Send1BitSWIO(t1coeff, pinmaskD);
250 uint32_t mask;
251 for (mask = 1 << 6; mask; mask >>= 1)
252 {
253 if (command & mask)
254 Send1BitSWIO(t1coeff, pinmaskD);
255 else
256 Send0BitSWIO(t1coeff, pinmaskD);
257 }
258 Send1BitSWIO(t1coeff, pinmaskD);
259 for (mask = 1 << 31; mask; mask >>= 1)
260 {
261 if (value & mask)
262 Send1BitSWIO(t1coeff, pinmaskD);
263 else
264 Send0BitSWIO(t1coeff, pinmaskD);
265 }
266 EnableISR();
267 esp_rom_delay_us(8); // Sometimes 2 is too short.
268 }
269 else
270 {
271 uint32_t mask;
272 DisableISR();
273 GPIO_VAR_W1TC = pinmaskD;
274 PrecDelay(t1coeff);
275 int parity = 1;
276 for (mask = 1 << 6; mask; mask >>= 1)
277 {
278 int v = !!(command & mask);
279 parity ^= v;
280 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, v);
281 }
282 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, 1); // Write = Set high
283 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, parity);
284 ReadBitRVSWD(t1coeff, pinmaskD, pinmaskC); // ???
285 ReadBitRVSWD(t1coeff, pinmaskD,
286 pinmaskC); // Seems only need to be set for first transaction (We are ignoring that though)
287 ReadBitRVSWD(t1coeff, pinmaskD, pinmaskC); // ???
288 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, 0); // 0 for register, 1 for value.
289 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, 0); // ??? Seems to have something to do with halting.
290
291 parity = 0;
292 for (mask = 1 << 31; mask; mask >>= 1)
293 {
294 int v = !!(value & mask);
295 parity ^= v;
296 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, v);
297 }
298 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, parity);
299 ReadBitRVSWD(t1coeff, pinmaskD, pinmaskC); // ???
300 ReadBitRVSWD(t1coeff, pinmaskD, pinmaskC); // ???
301 ReadBitRVSWD(t1coeff, pinmaskD, pinmaskC); // ???
302 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, 1); // 0 for register, 1 for value
303 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, 0); // ??? Seems to have something to do with halting?
304
305 GPIO_VAR_W1TC = pinmaskC;
306 PrecDelay(t1coeff);
307 GPIO_VAR_W1TC = pinmaskD;
308 GPIO_VAR_ENABLE_W1TS = pinmaskD;
309 PrecDelay(t1coeff);
310 GPIO_VAR_W1TS = pinmaskC;
311 PrecDelay(t1coeff);
312 GPIO_VAR_W1TS = pinmaskD;
313
314 EnableISR();
315 esp_rom_delay_us(8); // Sometimes 2 is too short.
316 }
317}
318
319// returns 0 if no error, otherwise error.
320static int MCFReadReg32(struct SWIOState* state, uint8_t command, uint32_t* value)
321{
322 int t1coeff = state->t1coeff;
323 int pinmaskD = state->pinmaskD;
324 int pinmaskC = state->pinmaskC;
325 GPIO_VAR_W1TS = pinmaskC;
326 GPIO_VAR_ENABLE_W1TS = pinmaskC;
327 GPIO_VAR_W1TS = pinmaskD;
328 GPIO_VAR_ENABLE_W1TS = pinmaskD;
329
330 if (state->opmode == 0)
331 {
332 DisableISR();
333 Send1BitSWIO(t1coeff, pinmaskD);
334 int i;
335 uint32_t mask;
336 for (mask = 1 << 6; mask; mask >>= 1)
337 {
338 if (command & mask)
339 Send1BitSWIO(t1coeff, pinmaskD);
340 else
341 Send0BitSWIO(t1coeff, pinmaskD);
342 }
343 Send0BitSWIO(t1coeff, pinmaskD);
344 uint32_t rval = 0;
345 for (i = 0; i < 32; i++)
346 {
347 rval <<= 1;
348 int r = ReadBitSWIO(state);
349 if (r == 1)
350 rval |= 1;
351 if (r == 2)
352 {
353 EnableISR();
354 return -1;
355 }
356 }
357 *value = rval;
358 EnableISR();
359 esp_rom_delay_us(8); // Sometimes 2 is too short.
360 }
361 else
362 {
363 int mask;
364 DisableISR();
365 GPIO_VAR_W1TC = pinmaskD;
366 PrecDelay(t1coeff);
367 int parity = 0;
368 for (mask = 1 << 6; mask; mask >>= 1)
369 {
370 int v = !!(command & mask);
371 parity ^= v;
372 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, v);
373 }
374 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, 0); // Read = Set low
375 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, parity);
376 ReadBitRVSWD(t1coeff, pinmaskD, pinmaskC); // ???
377 ReadBitRVSWD(t1coeff, pinmaskD, pinmaskC); // ???
378 ReadBitRVSWD(t1coeff, pinmaskD, pinmaskC); // ???
379 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, 0); // 0 for register, 1 for value
380 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, 0); // ??? Seems to have something to do with halting?
381
382 uint32_t rval = 0;
383 int i;
384 parity = 0;
385 for (i = 0; i < 32; i++)
386 {
387 rval <<= 1;
388 int r = ReadBitRVSWD(t1coeff, pinmaskD, pinmaskC);
389 if (r == 1)
390 {
391 rval |= 1;
392 parity ^= 1;
393 }
394 if (r == 2)
395 {
396 EnableISR();
397 return -1;
398 }
399 }
400 *value = rval;
401
402 if (ReadBitRVSWD(t1coeff, pinmaskD, pinmaskC) != parity)
403 {
404 uprintf("PARITY FAILED\n");
405 EnableISR();
406 return -1;
407 }
408
409 ReadBitRVSWD(t1coeff, pinmaskD, pinmaskC); // ???
410 ReadBitRVSWD(t1coeff, pinmaskD, pinmaskC); // ???
411 ReadBitRVSWD(t1coeff, pinmaskD, pinmaskC); // ???
412 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, 1); // 1 for data
413 SendBitRVSWD(t1coeff, pinmaskD, pinmaskC, 0); // ??? Seems to have something to do with halting?
414
415 GPIO_VAR_W1TC = pinmaskC;
416 PrecDelay(t1coeff);
417 GPIO_VAR_W1TC = pinmaskD;
418 GPIO_VAR_ENABLE_W1TS = pinmaskD;
419 PrecDelay(t1coeff);
420 GPIO_VAR_W1TS = pinmaskC;
421 PrecDelay(t1coeff);
422 GPIO_VAR_W1TS = pinmaskD;
423
424 EnableISR();
425 esp_rom_delay_us(8); // Sometimes 2 is too short.
426 }
427 return 0;
428}
429
431// High level functions
433
434static int InitializeSWDSWIO(struct SWIOState* state)
435{
436 // Careful - don't halt the part, we might just want to attach for a debug printf or something.
437
438 state->opmode = 0; // Try SWIO first
439 // First try to see if there is an 003.
440 MCFWriteReg32(state, DMSHDWCFGR, 0x5aa50000 | (1 << 10)); // Shadow Config Reg
441 MCFWriteReg32(state, DMCFGR, 0x5aa50000 | (1 << 10)); // CFGR (1<<10 == Allow output from slave)
442 MCFWriteReg32(state, DMSHDWCFGR, 0x5aa50000 | (1 << 10)); // Try twice just in case
443 MCFWriteReg32(state, DMCFGR, 0x5aa50000 | (1 << 10));
444
445 MCFWriteReg32(state, DMCONTROL, 0x00000001);
446 MCFWriteReg32(state, DMCONTROL, 0x00000001);
447
448 // See if we can see a chip here...
449 uint32_t value;
450 int readdm = MCFReadReg32(state, DMCFGR, &value);
451 uprintf("DMCFGR (SWD): %d: %08x\n", (int)readdm, (unsigned)value);
452 if (readdm == 0 && (value & 0xffff0000) == (0x5aa50000))
453 {
454 uprintf("TEST: Read reg passed. Check value: %08x TODO: MAKE SURE THESE MATCH\n", (unsigned)value);
455 return 0;
456 }
457
458 GPIO_VAR_W1TS = state->pinmaskC;
460
461 // Otherwise Maybe it's SWD?
462 state->opmode = 1;
463
464 MCFWriteReg32(state, DMCONTROL, 0x00000001);
465 MCFWriteReg32(state, DMCONTROL, 0x00000001);
466
467 uint32_t dmstatus, dmcontrol;
468 if (MCFReadReg32(state, DMSTATUS, &dmstatus) != 0 || MCFReadReg32(state, DMCONTROL, &dmcontrol) != 0)
469 {
470 uprintf("Could not read from RVSWD connection\n");
471 return -1;
472 }
473
474 // See if we can see a chip here...
475 uprintf("DMSTATUS: %08x\n", (unsigned)dmstatus);
476 uprintf("DMCONTROL: %08x\n", (unsigned)dmcontrol);
477
478 if ((((dmstatus >> 8) & 0xf) != 0x0c && ((dmstatus >> 8) & 0xf) != 0x03) || dmcontrol != 1)
479 {
480 uprintf("DMSTATUS invalid (Probably no RVSWD chip)\n");
481 return -1;
482 }
483
484 MCFWriteReg32(state, DMABSTRACTCS, 0x08000302); // Clear out abstractcs register.
485 uprintf("Found RVSWD interface\n");
486
487 return 0;
488}
489
490static int DetermineChipTypeAndSectorInfo(struct SWIOState* iss)
491{
492 if (iss->target_chip_type == CHIP_UNKNOWN)
493 {
494 uint32_t rr;
495 if (MCFReadReg32(iss, DMHARTINFO, &rr))
496 {
497 uprintf("Error: Could not get hart info.\n");
498 return -1;
499 }
500
501 uint32_t data0offset = 0xe0000000 | (rr & 0x7ff);
502
503 MCFWriteReg32(iss, DMCONTROL, 0x80000001); // Make the debug module work properly.
504 MCFWriteReg32(iss, DMCONTROL, 0x80000001); // Make the debug module work properly.
505
506 // Tricky, this function needs to clean everything up because it may be used entering debugger.
507 uint32_t old_data0;
508 MCFReadReg32(iss, DMDATA0, &old_data0);
509 MCFWriteReg32(iss, DMCOMMAND, 0x00221008); // Copy data from x8.
510 uint32_t old_x8;
511 MCFReadReg32(iss, DMDATA0, &old_x8);
512
513 uint32_t vendorid = 0;
514 uint32_t marchid = 0;
515
516 MCFWriteReg32(iss, DMABSTRACTCS, 0x08000700); // Clear out any dmabstractcs errors.
517
518 MCFWriteReg32(iss, DMABSTRACTAUTO, 0x00000000);
519 MCFWriteReg32(iss, DMCOMMAND, 0x00220000 | 0xf12);
520 MCFWriteReg32(iss, DMCOMMAND, 0x00220000 | 0xf12); // Need to double-read, not sure why.
521 MCFReadReg32(iss, DMDATA0, &marchid);
522
523 MCFWriteReg32(iss, DMPROGBUF0, 0x90024000); // c.ebreak <<== c.lw x8, 0(x8)
524 MCFWriteReg32(iss, DMDATA0, 0x1ffff704); // Special chip ID location.
525 MCFWriteReg32(iss, DMCOMMAND, 0x00271008); // Copy data to x8, and execute.
526 WaitForDoneOp(iss);
527
528 MCFWriteReg32(iss, DMCOMMAND, 0x00221008); // Copy data from x8.
529 MCFReadReg32(iss, DMDATA0, &vendorid);
530
531 // Cleanup
532 MCFWriteReg32(iss, DMDATA0, old_x8);
533 MCFWriteReg32(iss, DMCOMMAND, 0x00231008); // Copy data to x8
534 MCFWriteReg32(iss, DMDATA0, old_data0);
535
536 if (data0offset == 0xe00000f4)
537 {
538 // Only known processor with this signature is a CH32V003.
540 iss->sectorsize = 64;
541 }
542 else if (data0offset == 0xe0000380)
543 {
544 // All other known chips.
545 uint32_t chip_type = (vendorid & 0xfff00000) >> 20;
546 switch (chip_type)
547 {
548 case 0x103:
550 iss->sectorsize = 256; // test me!
551 break;
552 case 0x035:
553 case 0x033:
555 iss->sectorsize = 256; // Should be 128, but, doesn't work with 128, only 256
556 break;
557 case 0x203:
558 case 0x205:
559 case 0x208:
561 iss->sectorsize = 256;
562 break;
563 case 0x303:
564 case 0x305:
565 case 0x307:
567 iss->sectorsize = 256;
568 break;
569 }
570 }
571 uprintf("Detected %d / %d\n", iss->target_chip_type, iss->sectorsize);
572 uprintf("Vendored: %08x\n", (unsigned)vendorid);
573 uprintf("marchid : %08x\n", (unsigned)marchid);
574 uprintf("HARTINFO: %08x\n", (unsigned)rr);
575
576 iss->statetag = STTAG("XXXX");
577 }
578 return 0;
579}
580
581static int WaitForFlash(struct SWIOState* iss)
582{
583 struct SWIOState* dev = iss;
584
585 if (DetermineChipTypeAndSectorInfo(iss))
586 return -9;
587
588 uint32_t rw, timeout = 0;
589 do
590 {
591 rw = 0;
592 ReadWord(dev, 0x4002200C, &rw); // FLASH_STATR => 0x4002200C
593 } while ((rw & 1) && timeout++ < 200); // BSY flag.
594
595 WriteWord(dev, 0x4002200C, 0);
596
597 if (rw & FLASH_STATR_WRPRTERR)
598 return -44;
599
600 if (rw & 1)
601 return -5;
602
603 return 0;
604}
605
606static int WaitForDoneOp(struct SWIOState* iss)
607{
608 int r;
609 uint32_t rrv;
610 int ret = 0;
611 struct SWIOState* dev = iss;
612 do
613 {
614 r = MCFReadReg32(dev, DMABSTRACTCS, &rrv);
615 if (r)
616 return r;
617 } while (rrv & (1 << 12));
618 if ((rrv >> 8) & 7)
619 {
620 MCFWriteReg32(dev, DMABSTRACTCS, 0x00000700);
621 ret = -33;
622 }
623 return ret;
624}
625
626static void StaticUpdatePROGBUFRegs(struct SWIOState* dev)
627{
628 if (DetermineChipTypeAndSectorInfo(dev))
629 return;
630
631 MCFWriteReg32(dev, DMABSTRACTAUTO, 0); // Disable Autoexec.
632 MCFWriteReg32(dev, DMDATA0, 0xe00000f4); // DATA0's location in memory.
633 MCFWriteReg32(dev, DMCOMMAND, 0x0023100a); // Copy data to x10
634 MCFWriteReg32(dev, DMDATA0, 0xe00000f8); // DATA1's location in memory.
635 MCFWriteReg32(dev, DMCOMMAND, 0x0023100b); // Copy data to x11
636 MCFWriteReg32(dev, DMDATA0, 0x40022010); // FLASH->CTLR
637 MCFWriteReg32(dev, DMCOMMAND, 0x0023100c); // Copy data to x12
638
640 {
641 // This is not even needed on these chips, but we have to put something here.
642 MCFWriteReg32(dev, DMDATA0, 0x00010000);
643 }
644 else
645 {
646 // v003 requires bufload every word.
647 // x035 requires bufload every word in spite of what the datasheet says.
648 MCFWriteReg32(dev, DMDATA0,
649 0x00010000 | 0x00040000); // CR_PAGE_PG = FTPG = 0x00010000 | CR_BUF_LOAD = 0x00040000
650 }
651 MCFWriteReg32(dev, DMCOMMAND, 0x0023100d); // Copy data to x13
652}
653
654static void ResetInternalProgrammingState(struct SWIOState* iss)
655{
656 iss->statetag = 0;
657 iss->lastwriteflags = 0;
658 iss->currentstateval = 0;
659 iss->flash_unlocked = 0;
660 iss->autoincrement = 0;
661}
662
663static int ReadWord(struct SWIOState* iss, uint32_t address_to_read, uint32_t* data)
664{
665 struct SWIOState* dev = iss;
666 int autoincrement = 1;
667 if (address_to_read == 0x40022010 || address_to_read == 0x4002200C) // Don't autoincrement when checking flash flag.
668 autoincrement = 0;
669
670 if (iss->statetag != STTAG("RDSQ") || address_to_read != iss->currentstateval
671 || autoincrement != iss->autoincrement)
672 {
673 if (iss->statetag != STTAG("RDSQ") || autoincrement != iss->autoincrement)
674 {
675 if (iss->statetag != STTAG("WRSQ"))
676 {
677 StaticUpdatePROGBUFRegs(dev);
678 }
679
680 MCFWriteReg32(dev, DMABSTRACTAUTO, 0); // Disable Autoexec.
681
682 // c.lw x8,0(x11) // Pull the address from DATA1
683 // c.lw x9,0(x8) // Read the data at that location.
684 MCFWriteReg32(dev, DMPROGBUF0, 0x40044180);
685 if (autoincrement)
686 {
687 // c.addi x8, 4
688 // c.sw x9, 0(x10) // Write back to DATA0
689
690 MCFWriteReg32(dev, DMPROGBUF1, 0xc1040411);
691 }
692 else
693 {
694 // c.nop
695 // c.sw x9, 0(x10) // Write back to DATA0
696
697 MCFWriteReg32(dev, DMPROGBUF1, 0xc1040001);
698 }
699 // c.sw x8, 0(x11) // Write addy to DATA1
700 // c.ebreak
701 MCFWriteReg32(dev, DMPROGBUF2, 0x9002c180);
702
703 MCFWriteReg32(dev, DMABSTRACTAUTO, 1); // Enable Autoexec (not autoincrement)
705 }
706
707 MCFWriteReg32(dev, DMDATA1, address_to_read);
708 MCFWriteReg32(dev, DMCOMMAND, 0x00240000); // Only execute.
709
710 iss->statetag = STTAG("RDSQ");
711 iss->currentstateval = address_to_read;
712
713 WaitForDoneOp(dev);
714 }
715
716 if (iss->autoincrement)
717 iss->currentstateval += 4;
718
719 int r = MCFReadReg32(dev, DMDATA0, data);
720
721 return r;
722}
723
724static int WriteWord(struct SWIOState* iss, uint32_t address_to_write, uint32_t data)
725{
726 struct SWIOState* dev = iss;
727
728 int ret = 0;
729
730 int is_flash = 0;
731 if ((address_to_write & 0xff000000) == 0x08000000 || (address_to_write & 0x1FFFF800) == 0x1FFFF000)
732 {
733 // Is flash.
734 is_flash = 1;
735 }
736
737 if (iss->statetag != STTAG("WRSQ") || is_flash != iss->lastwriteflags)
738 {
739 int did_disable_req = 0;
740 if (iss->statetag != STTAG("WRSQ"))
741 {
742 if (iss->statetag != STTAG("RDSQ"))
743 {
744 StaticUpdatePROGBUFRegs(dev);
745 }
746
747 MCFWriteReg32(dev, DMABSTRACTAUTO, 0x00000000); // Disable Autoexec.
748 did_disable_req = 1;
749 // Different address, so we don't need to re-write all the program regs.
750 // c.lw x9,0(x11) // Get the address to write to.
751 // c.sw x8,0(x9) // Write to the address.
752 MCFWriteReg32(dev, DMPROGBUF0, 0xc0804184);
753 // c.addi x9, 4
754 // c.sw x9,0(x11)
755 MCFWriteReg32(dev, DMPROGBUF1, 0xc1840491);
756 }
757
758 if (iss->lastwriteflags != is_flash || iss->statetag != STTAG("WRSQ"))
759 {
760 // If we are doing flash, we have to ack, otherwise we don't want to ack.
761 if (is_flash)
762 {
763 // After writing to memory, also hit up page load flag.
764 // c.sw x13,0(x12) // Acknowledge the page write.
765 // c.ebreak
766 MCFWriteReg32(dev, DMPROGBUF2, 0x9002c214);
767 }
768 else
769 {
770 MCFWriteReg32(dev, DMPROGBUF2, 0x00019002); // c.ebreak
771 }
772 }
773
774 MCFWriteReg32(dev, DMDATA1, address_to_write);
775 MCFWriteReg32(dev, DMDATA0, data);
776
777 if (did_disable_req)
778 {
779 MCFWriteReg32(dev, DMCOMMAND, 0x00271008); // Copy data to x8, and execute program.
780 MCFWriteReg32(dev, DMABSTRACTAUTO, 1); // Enable Autoexec.
781 }
782 iss->lastwriteflags = is_flash;
783
784 iss->statetag = STTAG("WRSQ");
785 iss->currentstateval = address_to_write;
786
787 if (is_flash)
788 ret |= WaitForDoneOp(dev);
789 }
790 else
791 {
792 if (address_to_write != iss->currentstateval)
793 {
794 MCFWriteReg32(dev, DMABSTRACTAUTO, 0); // Disable Autoexec.
795 MCFWriteReg32(dev, DMDATA1, address_to_write);
796 MCFWriteReg32(dev, DMABSTRACTAUTO, 1); // Enable Autoexec.
797 }
798 MCFWriteReg32(dev, DMDATA0, data);
799 if (is_flash)
800 {
801 // XXX TODO: This likely can be a very short delay.
802 // XXX POSSIBLE OPTIMIZATION REINVESTIGATE.
803 ret |= WaitForDoneOp(dev);
804 }
805 else
806 {
807 ret |= WaitForDoneOp(dev);
808 }
809 }
810
811 iss->currentstateval += 4;
812
813 return 0;
814}
815
816static int UnlockFlash(struct SWIOState* iss)
817{
818 struct SWIOState* dev = iss;
819
820 if (DetermineChipTypeAndSectorInfo(iss))
821 return -9;
822
823 uint32_t rw;
824 ReadWord(dev, 0x40022010, &rw); // FLASH->CTLR = 0x40022010
825 if (rw & 0x8080)
826 {
827 WriteWord(dev, 0x40022004, 0x45670123); // FLASH->KEYR = 0x40022004
828 WriteWord(dev, 0x40022004, 0xCDEF89AB);
829 WriteWord(dev, 0x40022008, 0x45670123); // OBKEYR = 0x40022008
830 WriteWord(dev, 0x40022008, 0xCDEF89AB);
831 WriteWord(dev, 0x40022024, 0x45670123); // MODEKEYR = 0x40022024
832 WriteWord(dev, 0x40022024, 0xCDEF89AB);
833
834 ReadWord(dev, 0x40022010, &rw); // FLASH->CTLR = 0x40022010
835 if (rw & 0x8080)
836 {
837 return -9;
838 }
839 }
840 iss->flash_unlocked = 1;
841 return 0;
842}
843
844static int EraseFlash(struct SWIOState* iss, uint32_t address, uint32_t length, int type)
845{
846 struct SWIOState* dev = iss;
847
848 uint32_t rw;
849
850 if (!iss->flash_unlocked)
851 {
852 if ((rw = UnlockFlash(iss)))
853 return rw;
854 }
855
856 if (type == 1)
857 {
858 // Whole-chip flash
859 iss->statetag = STTAG("XXXX");
860 printf("Whole-chip erase\n");
861 WriteWord(dev, 0x40022010, 0); // FLASH->CTLR = 0x40022010
862 WriteWord(dev, 0x40022010, FLASH_CTLR_MER);
863 WriteWord(dev, 0x40022010, CR_STRT_Set | FLASH_CTLR_MER);
864 if (WaitForFlash(dev))
865 return -13;
866 WriteWord(dev, 0x40022010, 0); // FLASH->CTLR = 0x40022010
867 }
868 else
869 {
870 // 16.4.7, Step 3: Check the BSY bit of the FLASH_STATR register to confirm that there are no other programming
871 // operations in progress. skip (we make sure at the end)
872
873 int chunk_to_erase = address;
874
875 while (chunk_to_erase < address + length)
876 {
877 if (WaitForFlash(dev))
878 return -14;
879
880 // Step 4: set PAGE_ER of FLASH_CTLR(0x40022010)
881 WriteWord(dev, 0x40022010, CR_PAGE_ER); // Actually FTER // FLASH->CTLR = 0x40022010
882
883 // Step 5: Write the first address of the fast erase page to the FLASH_ADDR register.
884 WriteWord(dev, 0x40022014, chunk_to_erase); // FLASH->ADDR = 0x40022014
885
886 // Step 6: Set the STAT bit of FLASH_CTLR register to '1' to initiate a fast page erase (64 bytes) action.
887 WriteWord(dev, 0x40022010, CR_STRT_Set | CR_PAGE_ER); // FLASH->CTLR = 0x40022010
888 if (WaitForFlash(dev))
889 return -15;
890
891 WriteWord(dev, 0x40022010, 0); // FLASH->CTLR = 0x40022010 (Disable any pending ops)
892 chunk_to_erase += 64;
893 }
894 }
895 return 0;
896}
897
898static int Write64Block(struct SWIOState* iss, uint32_t address_to_write, const uint8_t* blob)
899{
900 struct SWIOState* dev = iss;
901
902 if (DetermineChipTypeAndSectorInfo(iss))
903 return -9;
904
905 const int blob_size = 64;
906 uint32_t wp = address_to_write;
907 uint32_t ew = wp + blob_size;
908 int group = -1;
909 int is_flash = 0;
910 int rw = 0;
911
912 if ((address_to_write & 0xff000000) == 0x08000000 || (address_to_write & 0xff000000) == 0x00000000
913 || (address_to_write & 0x1FFFF800) == 0x1FFFF000)
914 {
915 // Need to unlock flash.
916 // Flash reg base = 0x40022000,
917 // FLASH_MODEKEYR => 0x40022024
918 // FLASH_KEYR => 0x40022004
919
920 if (!iss->flash_unlocked)
921 {
922 if ((rw = UnlockFlash(dev)))
923 return rw;
924 }
925
926 is_flash = 1;
927 rw = EraseFlash(dev, address_to_write, blob_size, 0);
928 if (rw)
929 return rw;
930 // 16.4.6 Main memory fast programming, Step 5
931 // if( WaitForFlash( dev ) ) return -11;
932 // WriteWord( dev, 0x40022010, FLASH_CTLR_BUF_RST );
933 // if( WaitForFlash( dev ) ) return -11;
934 }
935
936 /* General Note:
937 Most flash operations take about 3ms to complete :(
938 */
939
940 while (wp < ew)
941 {
942 if (is_flash)
943 {
944 group = (wp & 0xffffffc0);
945
946 int block_in_sector = (group & (iss->sectorsize - 1)) / blob_size;
947 int is_first_block = block_in_sector == 0;
948 int is_last_block = block_in_sector == (iss->sectorsize / blob_size - 1);
949
950 if (is_first_block)
951 {
953 {
954 // No bufrst on v20x, v30x
955 // V003, x035, maybe more.
956 WriteWord(dev, 0x40022010, CR_PAGE_PG); // THIS IS REQUIRED, (intptr_t)&FLASH->CTLR = 0x40022010
957 WriteWord(dev, 0x40022010, CR_BUF_RST | CR_PAGE_PG); // (intptr_t)&FLASH->CTLR = 0x40022010
958 }
959 else
960 {
961 WaitForFlash(dev);
962 WriteWord(dev, 0x40022010, CR_PAGE_PG); // THIS IS REQUIRED, (intptr_t)&FLASH->CTLR = 0x40022010
963 // FTPG == CR_PAGE_PG == ((uint32_t)0x00010000)
964 }
965 }
966
967 int j;
968 for (j = 0; j < 16; j++)
969 {
970 int index = (wp - address_to_write);
971 uint32_t data = 0xffffffff;
972 if (index + 3 < blob_size)
973 data = ((uint32_t*)blob)[index / 4];
974 else if ((int32_t)(blob_size - index) > 0)
975 {
976 memcpy(&data, &blob[index], blob_size - index);
977 }
978 WriteWord(dev, wp, data);
979 // if( (rw = WaitForFlash( dev ) ) ) return rw;
980 wp += 4;
981 }
982
983 if (is_last_block)
984 {
986 {
987 WriteWord(dev, 0x40022010, 1 << 21); // Page Start
988 }
989 else
990 {
991 WriteWord(dev, 0x40022014, group); // 0x40022014 -> FLASH->ADDR
992 // if( MCF.PrepForLongOp ) MCF.PrepForLongOp( dev ); // Give the programmer a headsup this next
993 // operation could take a while.
994 WriteWord(dev, 0x40022010, CR_PAGE_PG | CR_STRT_Set); // 0x40022010 -> FLASH->CTLR
995 }
996
997 if ((rw = WaitForFlash(dev)))
998 return rw;
999 }
1000 }
1001 else
1002 {
1003 int index = (wp - address_to_write);
1004 uint32_t data = 0xffffffff;
1005 if (index + 3 < blob_size)
1006 data = ((uint32_t*)blob)[index / 4];
1007 else if ((int32_t)(blob_size - index) > 0)
1008 memcpy(&data, &blob[index], blob_size - index);
1009 WriteWord(dev, wp, data);
1010 wp += 4;
1011 }
1012 }
1013
1014 return 0;
1015}
1016
1017// Polls up to 7 bytes of printf, and can leave a 7-bit flag for the CH32V003.
1018static int PollTerminal(struct SWIOState* iss, uint8_t* buffer, int maxlen, uint32_t leavevalA, uint32_t leavevalB)
1019{
1020 struct SWIOState* dev = iss;
1021
1022 int r;
1023 uint32_t rr;
1024 if (iss->statetag != STTAG("TERM"))
1025 {
1026 MCFWriteReg32(dev, DMABSTRACTAUTO, 0x00000000); // Disable Autoexec.
1027 iss->statetag = STTAG("TERM");
1028 }
1029 r = MCFReadReg32(dev, DMDATA0, &rr);
1030 if (r < 0)
1031 return r;
1032
1033 if (maxlen < 8)
1034 return -9;
1035
1036 // DMDATA1:
1037 // bit 7 = host-acknowledge.
1038 if (rr & 0x80)
1039 {
1040 int ret = 0;
1041 int num_printf_chars = (rr & 0xf) - 4;
1042
1043 if (num_printf_chars > 0 && num_printf_chars <= 7)
1044 {
1045 if (num_printf_chars > 3)
1046 {
1047 uint32_t r2;
1048 r = MCFReadReg32(dev, DMDATA1, &r2);
1049 memcpy(buffer + 3, &r2, num_printf_chars - 3);
1050 }
1051 int firstrem = num_printf_chars;
1052 if (firstrem > 3)
1053 firstrem = 3;
1054 memcpy(buffer, ((uint8_t*)&rr) + 1, firstrem);
1055 buffer[num_printf_chars] = 0;
1056 ret = num_printf_chars;
1057 }
1058 if (leavevalA)
1059 {
1060 MCFWriteReg32(dev, DMDATA1, leavevalB);
1061 }
1062 MCFWriteReg32(dev, DMDATA0, leavevalA); // Write that we acknowledge the data.
1063 return ret;
1064 }
1065 else
1066 {
1067 return 0;
1068 }
1069}
1070
1071#endif // _CH32V003_SWIO_H
uint32_t autoincrement
Definition ch32v003_swio.h:58
#define DMCOMMAND
Definition ch32v003_swio.h:94
#define CR_STRT_Set
Definition ch32v003_swio.h:113
#define FLASH_CTLR_MER
Definition ch32v003_swio.h:112
#define DMDATA1
Definition ch32v003_swio.h:89
int sectorsize
Definition ch32v003_swio.h:51
RiscVChip
Definition ch32v003_swio.h:31
@ CHIP_CH32V30x
Definition ch32v003_swio.h:37
@ CHIP_CH32V10x
Definition ch32v003_swio.h:33
@ CHIP_CH32V20x
Definition ch32v003_swio.h:36
@ CHIP_CH56x
Definition ch32v003_swio.h:35
@ CHIP_CH58x
Definition ch32v003_swio.h:38
@ CHIP_CH57x
Definition ch32v003_swio.h:34
@ CHIP_CH32X03x
Definition ch32v003_swio.h:40
@ CHIP_UNKNOWN
Definition ch32v003_swio.h:32
@ CHIP_CH32V003
Definition ch32v003_swio.h:39
#define FLASH_STATR_WRPRTERR
Definition ch32v003_swio.h:109
#define DMHARTINFO
Definition ch32v003_swio.h:92
uint32_t currentstateval
Definition ch32v003_swio.h:56
#define CR_PAGE_PG
Definition ch32v003_swio.h:110
#define DMCONTROL
Definition ch32v003_swio.h:90
int pinmaskC
Definition ch32v003_swio.h:48
#define DMPROGBUF2
Definition ch32v003_swio.h:98
uint32_t flash_unlocked
Definition ch32v003_swio.h:57
#define DMSTATUS
Definition ch32v003_swio.h:91
enum RiscVChip target_chip_type
Definition ch32v003_swio.h:50
int pinmaskD
Definition ch32v003_swio.h:47
uint32_t statetag
Definition ch32v003_swio.h:54
uint32_t lastwriteflags
Definition ch32v003_swio.h:55
#define CR_BUF_RST
Definition ch32v003_swio.h:115
#define DMPROGBUF0
Definition ch32v003_swio.h:96
#define CR_PAGE_ER
Definition ch32v003_swio.h:114
#define DMABSTRACTAUTO
Definition ch32v003_swio.h:95
#define DMABSTRACTCS
Definition ch32v003_swio.h:93
#define DMPROGBUF1
Definition ch32v003_swio.h:97
#define DMSHDWCFGR
Definition ch32v003_swio.h:107
#define DMDATA0
Definition ch32v003_swio.h:88
#define IRAM
Definition ch32v003_swio.h:63
#define DMCFGR
Definition ch32v003_swio.h:106
int opmode
Definition ch32v003_swio.h:49
#define STTAG(x)
Definition ch32v003_swio.h:61
int t1coeff
Definition ch32v003_swio.h:46
Definition ch32v003_swio.h:44
#define GPIO_VAR_ENABLE_W1TC
Definition hdw-ch32v003.c:38
#define EnableISR()
Definition hdw-ch32v003.c:27
#define MAX_IN_TIMEOUT
Definition hdw-ch32v003.c:20
#define GPIO_VAR_W1TS
Definition hdw-ch32v003.c:37
#define GPIO_VAR_ENABLE_W1TS
Definition hdw-ch32v003.c:39
#define GPIO_VAR_W1TC
Definition hdw-ch32v003.c:36
#define DisableISR()
Definition hdw-ch32v003.c:21
int uprintf(const char *fmt,...)
vaprintf stand-in for USB logging.
Definition advanced_usb_control.c:118
#define GPIO_VAR_IN
Definition hdw-ch32v003.c:40