From 16a7a47a31f07926475cb6b7fadbd07b5ce13a4d Mon Sep 17 00:00:00 2001
From: cnlohr <lohr85@gmail.com>
Date: Tue, 14 Mar 2023 07:21:17 -0400
Subject: [PATCH]  * Add self-modifying code example.  * Add ability to wait
 for debugger to attach

---
 ch32v003fun/ch32v003fun.c                    |  6 ++
 ch32v003fun/ch32v003fun.h                    |  3 +
 examples/self_modify_code/Makefile           | 46 +++++++++++++
 examples/self_modify_code/self_modify_code.c | 71 ++++++++++++++++++++
 4 files changed, 126 insertions(+)
 create mode 100644 examples/self_modify_code/Makefile
 create mode 100644 examples/self_modify_code/self_modify_code.c

diff --git a/ch32v003fun/ch32v003fun.c b/ch32v003fun/ch32v003fun.c
index a97d1f8..72f14f2 100644
--- a/ch32v003fun/ch32v003fun.c
+++ b/ch32v003fun/ch32v003fun.c
@@ -896,6 +896,7 @@ int _write(int fd, const char *buf, int size)
 
 		while( ((*DMDATA0) & 0x80) )
 			if( timeout-- == 0 ) return place;
+		timeout = 160000;
 
 		uint32_t d;
 		int t = 3;
@@ -925,8 +926,13 @@ void SetupDebugPrintf()
 {
 	// Clear out the sending flag.
 	*DMDATA1 = 0x0;
+	*DMDATA0 = 0x80;
 }
 
+void WaitForDebuggerToAttach()
+{
+	while( ((*DMDATA0) & 0x80) );
+}
 
 void DelaySysTick( uint32_t n )
 {
diff --git a/ch32v003fun/ch32v003fun.h b/ch32v003fun/ch32v003fun.h
index 3115d7c..34ee9b1 100644
--- a/ch32v003fun/ch32v003fun.h
+++ b/ch32v003fun/ch32v003fun.h
@@ -4851,6 +4851,9 @@ void SetupUART( int uartBRR );
 
 void SetupDebugPrintf();
 
+void WaitForDebuggerToAttach();
+
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/examples/self_modify_code/Makefile b/examples/self_modify_code/Makefile
new file mode 100644
index 0000000..ebe3d0b
--- /dev/null
+++ b/examples/self_modify_code/Makefile
@@ -0,0 +1,46 @@
+TARGET:=self_modify_code
+
+all : flash
+
+PREFIX:=riscv64-unknown-elf
+
+GPIO_Toggle:=EXAM/GPIO/GPIO_Toggle/User
+
+CH32V003FUN:=../../ch32v003fun
+MINICHLINK:=../../minichlink
+
+CFLAGS:= \
+	-g -Os -flto -ffunction-sections \
+	-static-libgcc -lgcc \
+	-march=rv32ec \
+	-mabi=ilp32e \
+	-I/usr/include/newlib \
+	-I$(CH32V003FUN) \
+	-nostdlib \
+	-I.
+
+LDFLAGS:=-T $(CH32V003FUN)/ch32v003fun.ld -Wl,--gc-sections
+
+SYSTEM_C:=$(CH32V003FUN)/ch32v003fun.c
+
+$(TARGET).elf : $(SYSTEM_C) $(TARGET).c
+	$(PREFIX)-gcc -o $@ $^ $(CFLAGS) $(LDFLAGS)
+
+$(TARGET).bin : $(TARGET).elf
+	$(PREFIX)-size $^
+	$(PREFIX)-objdump -S $^ > $(TARGET).lst
+	$(PREFIX)-objdump -t $^ > $(TARGET).map
+	$(PREFIX)-objcopy -O binary $< $(TARGET).bin
+	$(PREFIX)-objcopy -O ihex $< $(TARGET).hex
+
+flash : $(TARGET).bin
+	make -C $(MINICHLINK) all
+	$(MINICHLINK)/minichlink -w $< flash -b
+
+monitor : flash
+	$(MINICHLINK)/minichlink -T
+	
+
+clean :
+	rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).hex $(TARGET).lst $(TARGET).map $(TARGET).hex
+
diff --git a/examples/self_modify_code/self_modify_code.c b/examples/self_modify_code/self_modify_code.c
new file mode 100644
index 0000000..40f0940
--- /dev/null
+++ b/examples/self_modify_code/self_modify_code.c
@@ -0,0 +1,71 @@
+/* Small example showing how to use the SWIO programming pin to 
+   do printf through the debug interface */
+
+#define SYSTEM_CORE_CLOCK 24000000
+#include "ch32v003fun.h"
+#include <stdio.h>
+
+uint32_t count;
+
+
+
+uint32_t ReadCSRSelfModify( uint16_t whichcsr ) __attribute__(( section(".data"))) __attribute__((noinline));
+uint32_t ReadCSRSelfModify( uint16_t whichcsr )
+{
+	uint32_t ret;
+
+	// Tricky: GCC will make this variable "point to" the opcode
+	// of the csrr instruction below.
+	volatile extern uint32_t readCSRLabel;
+
+	// We have to put this here to "force" the compiler to order the
+	// instructions in this way.  Otherwise, the compiler will try
+	// to optimize the code and inline the assembly int something where
+	// our global handle into assembly code becomes meaningless.
+	asm volatile( "nop" );
+
+	// 000026f3 is csrrs a3, 0x000, x0; So, we modify it, placing the
+	// CSR we want to read in the top 12 bits of the instruction.
+
+	readCSRLabel = 0x000026f3 | (whichcsr << 20);
+
+	// The actual assembly block inserted into the C function.  This
+	// defines the local label, globally, so the linker will be able to
+	// pick it up.  We also need to used a fixed register, a3, so we
+	// can know what opcode we want to use, then we can let C tell us
+	// what register it would like the value in.
+	//
+	// The constraints are "ret" is a "write" register, and register a3
+	// is going to be clobbered by the assembly code.
+	asm volatile( 
+		".global readCSRLabel   \n"
+		"readCSRLabel:          \n"
+		"	csrrs a3, 0x000, x0 \n"
+		"	addi %[ret], a3, 0  \n"
+		 : [ret]"=r"(ret) : : "a3" );
+
+	return ret;
+}
+
+
+int main()
+{
+	SystemInit48HSI();
+	SetupDebugPrintf();
+
+	WaitForDebuggerToAttach();
+
+	// Enable GPIOs
+	RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC;
+	puts( "Print all non-zero CSRs:" );
+	int i;
+	for( i = 0x000; i < 0x1000; i++ )
+	{
+		uint32_t rv =  ReadCSRSelfModify( i );
+		if( rv )
+			printf( "%03x = %08x\n", i, rv );
+	}
+	printf( "Done\n" );
+	for(;;);
+}
+
-- 
GitLab