transport select swd
adapter speed 32000
reset_config srst_only srst_nogate connect_assert_srst
gdb_breakpoint_override hard

set _CHIP_NAME DP32G0xx
# Create a new dap, with name chip and role CPU, -enable let's OpenOCD to know to add it to the scan
swd newdap $_CHIP_NAME cpu -enable

# Create the DAP instance, this must be explicitly created according to the OpenOCD docs
dap create $_CHIP_NAME.dap -chain-position $_CHIP_NAME.cpu

# Set up the GDB target for the CPU, cortex_m is the CPU type, 
target create $_CHIP_NAME.cpu cortex_m -dap $_CHIP_NAME.dap

set _SECTOR_SIZE 512
proc uv_clear_flash_sector {sector_number} {
	echo [format "Erasing sector 0x%02x = offset 0x%04x" [expr {$sector_number}]  [expr {$sector_number*256}]  ]
	write_memory 0x4006F000 32 {0x09}                           ;#set erasing mode
	write_memory 0x4006F004 32 [expr {$sector_number << 6}]
	write_memory 0x4006F01c 32 {0xAA}                           ;#unlock flash
	write_memory 0x4006F010 32 {0x01}                           ;#set OPSTART=1
	read_memory 0x4006F014 32 1                                 ;#check status for 0x02
	uv_wait_busy
	write_memory 0x4006F018 32 {0x55}                           ;#lock flash
}

proc uv_clear_whole_flash {} {
	for {set i 0} {$i < 0x100} {incr i} {
		uv_clear_flash_sector $i
	}
}

proc uv_clear_sectors {sectors_count} {
	for {set i 0} {$i < $sectors_count} {incr i} {
		uv_clear_flash_sector $i
	}
}

proc uv_flash_unlock {} {
	write_memory 0x4006F01c 32 {0xAA}     ;#unlock flash
	uv_wait_busy
}

proc uv_flash_lock {} {
	write_memory 0x4006F018 32 {0x55}     ;#lock flash
	uv_wait_busy
}

proc uv_flash_write {address value} {
	write_memory 0x4006F000 32 {0x05}                          ;#set writing mode
	write_memory 0x4006F004 32 [expr {($address>>2)+0xC000}]   ;#set address in flash
	write_memory 0x4006F008 32 $value                          ;#set data
	write_memory 0x4006F010 32 {0x01}                          ;#set OPSTART=1
	while {1} {
		set status [read_memory 0x4006F014 32 1]
		if {($status & 0x4) != 0} {
			break
		}
	}
	uv_wait_busy
}

proc uv_wait_busy {} {
	while {1} {
		set status [read_memory 0x4006F014 32 1]
		if {($status & 0x2) == 0} {
			break
		}
	}
}

proc write_image {filename address} {
	global _SECTOR_SIZE 

	set fs [file size $filename]
	set fd [open $filename "rb"]

	echo "Checking mask"
	set status [read_memory 0x4006F020 32 1]
	if {$status != 6} {
		echo "Changing mask"
		write_memory 0x4006F020 32 0
		uv_wait_busy
		write_memory 0x4006F020 32 6
		uv_wait_busy
		set status [read_memory 0x4006F020 32 1]
		if {$status != 6} {
			echo [format "Cannot set flash mask %d!" $status]
			close $fd
			return
		}
	}
	uv_clear_sectors [expr {(($fs+$_SECTOR_SIZE-1)&(0x10000000-$_SECTOR_SIZE))/($_SECTOR_SIZE/2)}]
	uv_flash_unlock
	
	set addr $address
	while {![eof $fd]} {
		set data [read $fd 4]
		if {[string length $data] == 4} {
			set b0 [scan [string index $data 0] %c]
			set b1 [scan [string index $data 1] %c]
			set b2 [scan [string index $data 2] %c]
			set b3 [scan [string index $data 3] %c]
			set i_data [expr {$b0 | $b1 << 8 | $b2 << 16 | $b3 << 24}]

			echo [format "Writing 0x%04x to address 0x%04x (%02d %%)" $i_data $addr [expr {(100*($addr+4)/$fs)}]]
			uv_flash_write $addr $i_data
			incr addr 4
		}
	}
	uv_flash_lock
	
	close $fd
}

# dap init
init
halt
# reset halt