diff --git a/ch32v003fun/ch32v003fun.mk b/ch32v003fun/ch32v003fun.mk index 0f24e3ff..81e0347c 100644 --- a/ch32v003fun/ch32v003fun.mk +++ b/ch32v003fun/ch32v003fun.mk @@ -212,6 +212,9 @@ unbrick : gdbserver : -$(MINICHLINK)/minichlink -baG +gdbclient : + gdb-multiarch $(TARGET).elf -ex "target remote :2000" + clangd : make clean bear -- make build diff --git a/examples/debugprintfdemo/.vscode/c_cpp_properties.json b/examples/debugprintfdemo/.vscode/c_cpp_properties.json index b52c5f52..92c840b3 100644 --- a/examples/debugprintfdemo/.vscode/c_cpp_properties.json +++ b/examples/debugprintfdemo/.vscode/c_cpp_properties.json @@ -8,13 +8,28 @@ ], "defines": [], "compilerPath": "/usr/bin/clang", - "cppStandard": "c++14", + "cppStandard": "c++20", "intelliSenseMode": "linux-clang-x64", "compilerArgs": [ "-DCH32V003FUN_BASE" ], "configurationProvider": "ms-vscode.makefile-tools" + }, + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/../../ch32v003fun" + ], + "defines": [], + "compilerPath": "riscv64-unknown-elf-gcc-10.1.0.exe", + "cppStandard": "c++20", + "compilerArgs": [ + "-DCH32V003FUN_BASE" + ], + "configurationProvider": "ms-vscode.makefile-tools" } ], - "version": 4 + "version": 4, + "enableConfigurationSquiggles": true } \ No newline at end of file diff --git a/examples/debugprintfdemo/.vscode/launch.json b/examples/debugprintfdemo/.vscode/launch.json index beab4027..f0b578dd 100644 --- a/examples/debugprintfdemo/.vscode/launch.json +++ b/examples/debugprintfdemo/.vscode/launch.json @@ -1,23 +1,17 @@ { "configurations": [ { - "name": "GDB Debug Target", + "name": "Debug Target", "type": "cppdbg", "request": "launch", - "program": "debugprintfdemo.elf", + "program": "${workspaceFolder}/debugprintfdemo.elf", "args": [], "stopAtEntry": true, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": false, "MIMode": "gdb", - "deploySteps": [ - { - "type": "shell", - "continueOn": "GDBServer", - "command": "make --directory=${workspaceFolder} closechlink flash gdbserver" - }, - ], + "preLaunchTask": "run_flash_and_gdbserver", "setupCommands": [ { "description": "Enable pretty-printing for gdb", @@ -25,15 +19,30 @@ "ignoreFailures": true } ], + "svdPath": "${workspaceFolder}/../../misc/CH32V003xx.svd", // extension 'Peripheral Viewer' by mcu-debug (cortex-debug) "miDebuggerPath": "gdb-multiarch", - "miDebuggerServerAddress": "127.0.0.1:2000" + "miDebuggerServerAddress": "127.0.0.1:2000", }, { - "name": "Run Only (In Terminal)", + "name": "Flash and run in terminal", + "type": "node-terminal", + "request": "launch", + "internalConsoleOptions": "neverOpen", + "command": "make closechlink clean; make flash monitor", + }, + { + "name": "Compile and Flash", "type": "node", "request": "launch", - "program": "", - "preLaunchTask": "run_flash_and_gdbserver", - } - ] -} + "internalConsoleOptions": "neverOpen", + "preLaunchTask" : "kill_all_tasks", + "postDebugTask": "run_flash", + "presentation": { + "hidden": false, + "group": "terminaloutput", + "order": 1 + }, + "runtimeExecutable": "echo" + } + ] +} \ No newline at end of file diff --git a/examples/debugprintfdemo/.vscode/settings.json b/examples/debugprintfdemo/.vscode/settings.json index e81e0118..321e3cd9 100644 --- a/examples/debugprintfdemo/.vscode/settings.json +++ b/examples/debugprintfdemo/.vscode/settings.json @@ -3,7 +3,7 @@ "makefile.launchConfigurations": [ { "cwd": "", - "sbinaryPath": "debugprintfdemo.elf", + "sbinaryPath": "debugprintf.elf", "binaryArgs": [] } ], @@ -11,5 +11,5 @@ "editor.tabSize": 4, "files.associations": { "ch32v003fun.h": "c" - } -} + }, +} \ No newline at end of file diff --git a/examples/debugprintfdemo/.vscode/tasks.json b/examples/debugprintfdemo/.vscode/tasks.json index d086ce20..3f9ea798 100644 --- a/examples/debugprintfdemo/.vscode/tasks.json +++ b/examples/debugprintfdemo/.vscode/tasks.json @@ -3,54 +3,130 @@ "tasks": [ { "type": "shell", - "label": "flash", "presentation": { "echo": true, "focus": false, "group": "build", "panel": "shared", + "close": true, "showReuseMessage" : false }, - "command": "make closechlink flash", + "command": "make closechlink clean; make flash monitor", + "label": "run_flash_and_monitor", + "group": { + "kind": "build", + "isDefault": true + }, + "runOptions": { + "instanceLimit": 1, + }, + "isBackground": true, + "problemMatcher": { // https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher + "owner": "cpp", + "fileLocation": [ + "relative", + "${workspaceFolder}" + ], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + }, + "background": { + "activeOnStart": false, + "beginsPattern": "^.*Image written.*", + "endsPattern": "^.*GDBServer*" + }, + } }, { "type": "shell", "label": "run_flash_and_gdbserver", - "command": "make closechlink flash gdbserver", - + "command": "make clean closechlink; make flash gdbserver", "presentation": { "echo": true, - "focus": false, + "focus": true, "group": "build", "panel": "shared", + "reveal": "always", "close": true, - "showReuseMessage" : false + "showReuseMessage": false }, - "isBackground": true, "options": { "cwd": "${workspaceFolder}", }, "runOptions": { - "instanceLimit": 2, - }, + "instanceLimit": 1, + }, "group": "build", - "problemMatcher": { - "pattern": [ - { - "regexp": ".", - "file": 1, - "location": 2, - "message": 3 - } + "problemMatcher": { // https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher + "owner": "cpp", + "fileLocation": [ + "relative", + "${workspaceFolder}" ], - + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + }, "background": { "activeOnStart": false, "beginsPattern": "^.*Image written.*", "endsPattern": "^.*GDBServer*" - } + }, + } + }, + { + "type": "shell", + "label": "run_flash", + "command": "make clean closechlink; make flash", + "presentation": { + "echo": true, + "focus": true, + "group": "build", + "panel": "shared", + "close": true, + "reveal": "always", + "showReuseMessage": true }, + "isBackground": false, + "options": { + "cwd": "${workspaceFolder}", + }, + "runOptions": { + "instanceLimit": 1, + }, + "group": "build", + "problemMatcher": { // https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher + "owner": "cpp", + "fileLocation": [ + "relative", + "${workspaceFolder}" + ], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + }, + } + }, + { + "type": "process", + "label" : "kill_all_tasks", + "command":[ + "${command:workbench.action.tasks.terminate} terminateAll", + ] } ] -} +} \ No newline at end of file diff --git a/examples/template/.vscode/c_cpp_properties.json b/examples/template/.vscode/c_cpp_properties.json index 938ea5e9..92c840b3 100644 --- a/examples/template/.vscode/c_cpp_properties.json +++ b/examples/template/.vscode/c_cpp_properties.json @@ -1,26 +1,35 @@ { "configurations": [ { - "name": "RISCV32EC", + "name": "Linux", "includePath": [ "${workspaceFolder}/**", - "${workspaceFolder}/../../ch32v003fun", - "${workspaceFolder}/../../extralibs", - "/usr/include/newlib" //why? the configurationProvider ought to find this + "${workspaceFolder}/../../ch32v003fun" ], - "defines": [ - "CH32V003", - "__riscv", - "USE_SIGNALS", - "CH32V003FUN_BASE" + "defines": [], + "compilerPath": "/usr/bin/clang", + "cppStandard": "c++20", + "intelliSenseMode": "linux-clang-x64", + "compilerArgs": [ + "-DCH32V003FUN_BASE" + ], + "configurationProvider": "ms-vscode.makefile-tools" + }, + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/../../ch32v003fun" + ], + "defines": [], + "compilerPath": "riscv64-unknown-elf-gcc-10.1.0.exe", + "cppStandard": "c++20", + "compilerArgs": [ + "-DCH32V003FUN_BASE" ], - "compilerPath": "/usr/bin/riscv64-unknown-elf-gcc", - "cStandard": "gnu11", - "cppStandard": "gnu++17", - "intelliSenseMode": "gcc-x86", //works. Someday, intellisense might get riscv modes - "compilerArgs": [], "configurationProvider": "ms-vscode.makefile-tools" } ], - "version": 4 -} + "version": 4, + "enableConfigurationSquiggles": true +} \ No newline at end of file diff --git a/examples/template/.vscode/launch.json b/examples/template/.vscode/launch.json index de280e44..e86da74b 100644 --- a/examples/template/.vscode/launch.json +++ b/examples/template/.vscode/launch.json @@ -1,7 +1,7 @@ { "configurations": [ { - "name": "cppdbg GDB Debug Target", + "name": "Debug Target", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/template.elf", @@ -11,37 +11,38 @@ "environment": [], "externalConsole": false, "MIMode": "gdb", - "deploySteps": [ // 'make ...gdbserver' doesn't seem to work here. The Makefile calls 'minichlink -baG'... Needs -aG. Easier to add minichlink as a seperate step below - { - "type": "shell", //isn't there some way to call a task from tasks.json? - "command": "make --directory=${workspaceFolder} -j 1 closechlink flash", - }, - { - "type": "shell", - "command": "${workspaceFolder}/../../minichlink/minichlink -aG", - "continueOn": "gdbserver running" - }, - ], + "preLaunchTask": "run_flash_and_gdbserver", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", - "ignoreFailures": true, - }, + "ignoreFailures": true + } ], "svdPath": "${workspaceFolder}/../../misc/CH32V003xx.svd", // extension 'Peripheral Viewer' by mcu-debug (cortex-debug) "miDebuggerPath": "gdb-multiarch", - "miDebuggerServerAddress": "localhost:2000", - "logging": { - "engineLogging": false - }, + "miDebuggerServerAddress": "127.0.0.1:2000", }, { - "name": "Run Only (In Terminal)", + "name": "Flash and run in terminal", + "type": "node-terminal", + "request": "launch", + "internalConsoleOptions": "neverOpen", + "command": "make closechlink clean; make flash monitor", + }, + { + "name": "Compile and Flash", "type": "node", "request": "launch", - "program": "", - "preLaunchTask": "run_flash_and_gdbserver", + "internalConsoleOptions": "neverOpen", + "preLaunchTask" : "kill_all_tasks", + "postDebugTask": "run_flash", + "presentation": { + "hidden": false, + "group": "terminaloutput", + "order": 1 + }, + "runtimeExecutable": "echo" } ] } \ No newline at end of file diff --git a/examples/template/.vscode/tasks.json b/examples/template/.vscode/tasks.json index 006c40c5..3f9ea798 100644 --- a/examples/template/.vscode/tasks.json +++ b/examples/template/.vscode/tasks.json @@ -3,19 +3,24 @@ "tasks": [ { "type": "shell", - "label": "build", "presentation": { "echo": true, "focus": false, "group": "build", "panel": "shared", - "showReuseMessage": false + "close": true, + "showReuseMessage" : false }, + "command": "make closechlink clean; make flash monitor", + "label": "run_flash_and_monitor", "group": { "kind": "build", "isDefault": true }, - "command": "make closechlink clean; make", + "runOptions": { + "instanceLimit": 1, + }, + "isBackground": true, "problemMatcher": { // https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher "owner": "cpp", "fileLocation": [ @@ -30,17 +35,24 @@ "severity": 4, "message": 5 }, - }, + "background": { + "activeOnStart": false, + "beginsPattern": "^.*Image written.*", + "endsPattern": "^.*GDBServer*" + }, + } }, { "type": "shell", "label": "run_flash_and_gdbserver", - "command": "make closechlink flash gdbserver", + "command": "make clean closechlink; make flash gdbserver", "presentation": { "echo": true, - "focus": false, + "focus": true, "group": "build", "panel": "shared", + "reveal": "always", + "close": true, "showReuseMessage": false }, "isBackground": true, @@ -48,24 +60,73 @@ "cwd": "${workspaceFolder}", }, "runOptions": { - "instanceLimit": 2, + "instanceLimit": 1, }, "group": "build", - "problemMatcher": { - "pattern": [ - { - "regexp": ".", - "file": 1, - "location": 2, - "message": 3 - } + "problemMatcher": { // https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher + "owner": "cpp", + "fileLocation": [ + "relative", + "${workspaceFolder}" ], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + }, "background": { "activeOnStart": false, "beginsPattern": "^.*Image written.*", "endsPattern": "^.*GDBServer*" - } + }, + } + }, + { + "type": "shell", + "label": "run_flash", + "command": "make clean closechlink; make flash", + "presentation": { + "echo": true, + "focus": true, + "group": "build", + "panel": "shared", + "close": true, + "reveal": "always", + "showReuseMessage": true }, + "isBackground": false, + "options": { + "cwd": "${workspaceFolder}", + }, + "runOptions": { + "instanceLimit": 1, + }, + "group": "build", + "problemMatcher": { // https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher + "owner": "cpp", + "fileLocation": [ + "relative", + "${workspaceFolder}" + ], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + }, + } }, + { + "type": "process", + "label" : "kill_all_tasks", + "command":[ + "${command:workbench.action.tasks.terminate} terminateAll", + ] + } ] } \ No newline at end of file diff --git a/minichlink/microgdbstub.h b/minichlink/microgdbstub.h index 1b3db002..e0608f07 100644 --- a/minichlink/microgdbstub.h +++ b/minichlink/microgdbstub.h @@ -20,6 +20,13 @@ #ifndef _MICROGDBSTUB_H #define _MICROGDBSTUB_H +enum HaltResetResumeType +{ + HALT_TYPE_SINGLE_STEP = 9, + HALT_TYPE_CONTINUE = 2, + HALT_TYPE_CONTINUE_WITH_SIGNAL = 4, +}; + // You must write these for your processor. void RVNetPoll(void * dev ); int RVSendGDBHaltReason( void * dev ); @@ -27,13 +34,14 @@ void RVNetConnect( void * dev ); int RVGetNumRegisters( void * dev ); int RVReadCPURegister( void * dev, int regno, uint32_t * regret ); int RVWriteCPURegister( void * dev, int regno, uint32_t value ); -void RVDebugExec( void * dev, int halt_reset_or_resume ); +int RVDebugExec( void * dev, enum HaltResetResumeType halt_reset_or_resume, int resume_from_other_address, uint32_t address ); int RVReadMem( void * dev, uint32_t memaddy, uint8_t * payload, int len ); int RVHandleBreakpoint( void * dev, int set, uint32_t address ); int RVWriteRAM(void * dev, uint32_t memaddy, uint32_t length, uint8_t * payload ); void RVCommandResetPart( void * dev, int mode ); void RVHandleDisconnect( void * dev ); void RVHandleGDBBreakRequest( void * dev ); +void RVHandleUnsolicitedGDBBreakRequest( void * dev ); void RVHandleKillRequest( void * dev ); int RVErase( void * dev, uint32_t memaddy, uint32_t length ); int RVWriteFlash( void * dev, uint32_t memaddy, uint32_t length, uint8_t * payload ); @@ -91,6 +99,7 @@ uint8_t gdbchecksum = 0; int gdbbufferplace = 0; int gdbbufferstate = 0; int gdbrunningcsum = 0; +int gdbqnoackmode = 0; static inline char ToHEXNibble( int i ) { @@ -203,13 +212,16 @@ void HandleGDBPacket( void * dev, char * data, int len ) data++; char cmd = *(data++); + //printf( "DATA: [%c] %c%c%c%c%c%c%c%c%c%c%c%c\n",cmd, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11] ); + switch( cmd ) { case 'q': + case 'Q': if( StringMatch( data, "Attached" ) ) SendReplyFull( "1" ); //Attached to an existing process. - else if( StringMatch( data, "Supported" ) ) - SendReplyFull( "PacketSize=f000;qXfer:memory-map:read+" ); + else if( StringMatch( data, "Supported" ) ) // qXfer:threads: + SendReplyFull( "PacketSize=f000;hwbreak+;vContSupported+;qXfer:memory-map:read+;read+;QStartNoAckMode+" ); else if( StringMatch( data, "C") ) // Get Current Thread ID. (Can't be -1 or 0. Those are special) SendReplyFull( "QC1" ); else if( StringMatch( data, "fThreadInfo" ) ) // Query all active thread IDs (Can't be 0 or 1) @@ -221,6 +233,11 @@ void HandleGDBPacket( void * dev, char * data, int len ) SendReplyFull( "" ); else if( StringMatch( data, "Symbol" ) ) // Trace-Status SendReplyFull( "" ); + else if( StringMatch( data, "StartNoAckMode" ) ) + { + gdbqnoackmode = 1; + SendReplyFull( "OK" ); + } else if( StringMatch( data, "TStatus" ) ) // Trace-Status SendReplyFull( "" ); else if( StringMatch( data, "Rcmd," ) ) // "monitor " @@ -237,7 +254,7 @@ void HandleGDBPacket( void * dev, char * data, int len ) SendReplyFull( "" ); break; } - printf("Got monitor command: %s\n", cmd); + //printf("Got monitor command: %s\n", cmd); // Support commands that OpenOCD also does: // https://openocd.org/doc/html/General-Commands.html if(StringMatch(cmd, "halt")) { @@ -273,8 +290,8 @@ void HandleGDBPacket( void * dev, char * data, int len ) SendReplyFull( "+" ); } else { - printf("Unknown monitor command '%s', use 'monitor help'.\n", cmd); - MakeGDBPrintText("Unknown monitor command, use 'monitor help'\n"); + fprintf( stderr, "Unknown monitor command '%s', use 'monitor help'.\n", cmd ); + MakeGDBPrintText( "Unknown monitor command, use 'monitor help'\n" ); SendReplyFull( "-" ); } } else { @@ -290,26 +307,40 @@ void HandleGDBPacket( void * dev, char * data, int len ) snprintf( map, mslen, MICROGDBSTUB_MEMORY_MAP, iss->flash_size, iss->sector_size, iss->ram_size ); SendReplyFull( map ); } + else if( StringMatch( data, "Xfer:threads" ) ) + { + static const char * emptyxml = "l\n\n"; + SendReplyFull( emptyxml ); + } + else if( StringMatch( data, "ThreadExtraInfo" ) ) + SendReplyFull( "4E2F41" ); + else if( data[0] == 'P' ) + SendReplyFull( "m1" ); // Archaic threadid. else { - printf( "Unknown command: %s\n", data ); + fprintf( stderr, "Unknown q command: q%s\n", data ); SendReplyFull( "" ); } break; case 'c': case 'C': - RVDebugExec( dev, (cmd == 's' )?9:(cmd == 'C')?4:2 ); - SendReplyFull( "OK" ); + // TODO: Support continue-from-another-address + RVDebugExec( dev, (cmd == 'C')?HALT_TYPE_CONTINUE_WITH_SIGNAL:HALT_TYPE_CONTINUE, 0, 0 ); + //The real reply will be sent from RVNetPoll break; case 's': - RVDebugExec( dev, 4 ); - SendReplyFull( "OK" ); - //RVHandleGDBBreakRequest( dev ); + case 'S': + // TODO: Support step-with-signal. + RVDebugExec( dev, HALT_TYPE_SINGLE_STEP, 0, 0 ); + //SendReplyFull( "T05" ); + //SendReplyFull( "OK" ); // Will be sent from RVNetPoll + RVHandleGDBBreakRequest( dev ); RVSendGDBHaltReason( dev ); break; case 'D': // Handle disconnect. RVHandleDisconnect( dev ); + //SendReplyFull( "OK" ); break; case 'k': RVHandleKillRequest( dev ); // no reply. @@ -320,7 +351,6 @@ void HandleGDBPacket( void * dev, char * data, int len ) if( ReadHex( &data, -1, ® ) < 0 ) goto err; if( *(data++) != ',' ) goto err; if( ReadHex( &data, -1, &value ) < 0 ) goto err; - printf( "REG: %02x = %08x\n", reg, value ); RVWriteCPURegister( dev, reg, value ); break; } @@ -401,9 +431,62 @@ void HandleGDBPacket( void * dev, char * data, int len ) case 'v': if( StringMatch( data, "Cont" ) ) // vCont? { - // Request a list of actions supported by the ‘vCont’ packet. - // We don't support vCont - SendReplyFull( "vCont;s;c;;" ); //no ;t because we don't implement them. + //printf( "CONT: %s\n", data ); + char * de = data + 4; + char de0; + if( (de0 = *(de++)) ) // was while? + { + //printf( "DE0: %c\n", de0 ); + if( de0 == '?' ) + { + // Request a list of actions supported by the ‘vCont’ packet. + // We don't support vCont + SendReplyFull( "vCont;c;C;s;S" ); //no ;t because we don't implement them. + break; + } + else if( de0 == ';' ) + { + //printf( "de[0] = %c\n", de[0] ); + switch( de[0] ) + { + case 'c': + case 'C': + // TODO: Support continue-from-another-address + RVDebugExec( dev, (cmd == 'C')?HALT_TYPE_CONTINUE_WITH_SIGNAL:HALT_TYPE_CONTINUE, 0, 0 ); + //The real reply will be sent from RVNetPoll + break; + case 's': + case 'S': + // TODO: Support step-with-signal. + RVDebugExec( dev, HALT_TYPE_SINGLE_STEP, 0, 0 ); + //SendReplyFull( "T05" ); + //SendReplyFull( "OK" ); // Will be sent from RVNetPoll + RVHandleGDBBreakRequest( dev ); + RVSendGDBHaltReason( dev ); + fprintf( stderr, "Step.\n" ); + break; + default: + SendReplyFull( "E 98" ); + break; + } + de++; + } + else if( de0 == ':' ) + { + // Parse off thread number and throw it away. + uint32_t signalnumber; + if( ReadHex( &de, -1, &signalnumber ) < 0 ) goto err; + } + else if( de0 == '#' ) + { + // We're done. + break; + } + else + { + SendReplyFull( "E 99" ); + } + } } else if( StringMatch( data, "MustReplyEmpty" ) ) //vMustReplyEmpty { @@ -413,6 +496,12 @@ void HandleGDBPacket( void * dev, char * data, int len ) { SendReplyFull( "OK" ); } + else if( StringMatch( data, "Kill" ) ) //vKill + { + SendReplyFull( "OK" ); + fprintf( stderr, "Received Kill command. Exiting\n" ); + exit( 0 ); + } else if( StringMatch( data, "FlashErase" ) ) //vFlashErase { data += 10; // FlashErase @@ -432,16 +521,15 @@ void HandleGDBPacket( void * dev, char * data, int len ) { data += 10; // FlashWrite - printf( "Write\n" ); if( *(data++) != ':' ) goto err; uint32_t address_to_write = 0; if( ReadHex( &data, -1, &address_to_write ) < 0 ) goto err; if( *(data++) != ':' ) goto err; int toflash = len - (data - odata) - 1; -printf( "LEN: %08x %d %d %c\n", address_to_write, len, toflash, data[0] ); - if( RVWriteFlash( dev, address_to_write, len, (uint8_t*)data ) == 0 ) + fprintf( stderr, "Writing flash: %08x len %d\n", address_to_write, toflash ); + if( RVWriteFlash( dev, address_to_write, toflash, (uint8_t*)data ) == 0 ) { - printf( "Write OK\n" ); + fprintf( stderr, "Write OK\n" ); SendReplyFull( "OK" ); } else @@ -449,7 +537,7 @@ printf( "LEN: %08x %d %d %c\n", address_to_write, len, toflash, data[0] ); } else { - printf( "Warning: Unknown v command %s\n", data ); + fprintf( stderr, "Warning: Unknown v command %s\n", data ); SendReplyFull( "E 01" ); } break; @@ -493,12 +581,12 @@ printf( "LEN: %08x %d %d %c\n", address_to_write, len, toflash, data[0] ); SendReplyFull( "" ); break; default: - printf( "UNKNOWN PACKET: %d (%s)\n", len, data-1 ); + fprintf( stderr, "UNKNOWN PACKET: %d (%s)\n", len, data-1 ); for( i = 0; i < len; i++ ) { - printf( "%02x ", data[i] ); + fprintf( stderr, "%02x ", data[i] ); } - printf( "\n" ); + fprintf( stderr, "\n" ); goto err; break; } @@ -521,7 +609,7 @@ void MicroGDBStubHandleClientData( void * dev, const uint8_t * rxdata, int len ) } if( c == 3 && gdbbufferstate == 0 ) { - RVHandleGDBBreakRequest( dev ); + RVHandleUnsolicitedGDBBreakRequest( dev ); continue; } switch( gdbbufferstate ) @@ -543,7 +631,7 @@ void MicroGDBStubHandleClientData( void * dev, const uint8_t * rxdata, int len ) { char escaped = c ^ 0x20; gdbbuffer[gdbbufferplace++] = escaped; - printf( "ESCAPED @ %02x -> %c [%d]\n", gdbbufferplace, escaped, escaped ); + fprintf( stderr, "ESCAPED @ %02x -> %c [%d]\n", gdbbufferplace, escaped, escaped ); gdbbufferstate = 1; } break; @@ -570,15 +658,15 @@ void MicroGDBStubHandleClientData( void * dev, const uint8_t * rxdata, int len ) } else { - printf( "Checksum Error: Got %02x expected %02x / len: %d\n", gdbrunningcsum, gdbchecksum, gdbbufferplace ); + fprintf( stderr, "Checksum Error: Got %02x expected %02x / len: %d\n", gdbrunningcsum, gdbchecksum, gdbbufferplace ); int i; for( i = 0; i < gdbbufferplace; i++ ) { int c = ((uint8_t*)gdbbuffer)[i]; - printf( "%02x [%c] ", c, (c>=32 && c < 128)?c:' '); - if( ( i & 0xf ) == 0xf ) printf( "\n" ); + fprintf( stderr, "%02x [%c] ", c, (c>=32 && c < 128)?c:' '); + if( ( i & 0xf ) == 0xf ) fprintf( stderr, "\n" ); } - printf( "\n" ); + fprintf( stderr, "\n" ); MicroGDBStubSendReply( "-", -1, 0 ); } @@ -693,7 +781,7 @@ int MicroGDBPollServer( void * dev ) if( r < 0 ) { - printf( "R: %d\n", r ); + fprintf( stderr, "R poll(...): %d\n", r ); } //If there's faults, bail. @@ -792,7 +880,7 @@ void MicroGDBStubSendReply( const void * data, int len, int docs ) if( listenMode == 2 ) { - //printf( ">>>>%s<<<<(%d)\n", data ); + //printf( ">>>>%s<<<<\n", data ); send( serverSocket, data, len, MSG_NOSIGNAL ); } } diff --git a/minichlink/minichgdb.c b/minichlink/minichgdb.c index 5d4e7666..31c8d4b8 100644 --- a/minichlink/minichgdb.c +++ b/minichlink/minichgdb.c @@ -1,7 +1,8 @@ // This file is loosely based on aappleby's GDBServer. // Connect in with: -// gdb-multiarch -ex 'target remote :2000' ./blink.elf +// gdb-multiarch -ex "set debug remote 1" -ex "target extended-remote :2000" ./blink.elf +// gdb-multiarch -ex "target extended-remote :2000" ./blink.elf #include "minichlink.h" @@ -21,6 +22,9 @@ const char* MICROGDBSTUB_MEMORY_MAP = "l" " " " 4" " " +" " +" 4" +" " ""; #include "microgdbstub.h" @@ -34,6 +38,7 @@ void SendReplyFull( const char * replyMessage ); int shadow_running_state = 1; int last_halt_reason = 5; uint32_t backup_regs[33]; //0..15 + PC, or 0..32 + PC +int gdbasserting_break = 0; #define MAX_SOFTWARE_BREAKPOINTS 128 int num_software_breakpoints = 0; @@ -87,8 +92,15 @@ void RVNetConnect( void * dev ) } int RVSendGDBHaltReason( void * dev ) -{ +{ char st[5]; + if( gdbasserting_break ) + { + gdbasserting_break = 0; + sprintf( st, "T%02x", 2 ); + SendReplyFull( st ); + return 0; + } sprintf( st, "T%02x", last_halt_reason ); SendReplyFull( st ); return 0; @@ -109,7 +121,7 @@ void RVNetPoll(void * dev ) return; } int statusrunning = ((status & (1<<10))); - + static int laststatus; if( status != laststatus ) { @@ -125,6 +137,11 @@ void RVNetPoll(void * dev ) last_halt_reason = 5;//((dscr>>6)&3)+5; RVSendGDBHaltReason( dev ); } + else + { + // this is the reply to 's' or 'c' packets. + SendReplyFull( "OK" ); + } shadow_running_state = statusrunning; } } @@ -201,7 +218,7 @@ int RVWriteCPURegister( void * dev, int regno, uint32_t value ) return 0; } -void RVDebugExec( void * dev, int halt_reset_or_resume ) +int RVDebugExec( void * dev, enum HaltResetResumeType halt_reset_or_resume, int resume_from_other_address, uint32_t address ) { struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); int nrregs = iss->nr_registers_for_debug; @@ -211,9 +228,21 @@ void RVDebugExec( void * dev, int halt_reset_or_resume ) fprintf( stderr, "Error: Can't alter halt mode with this programmer.\n" ); exit( -6 ); } + + if( halt_reset_or_resume == HALT_TYPE_SINGLE_STEP ) + { + MCF.SetEnableBreakpoints( dev, 1, 1 ); + RVCommandEpilogue( dev ); + MCF.HaltMode( dev, HALT_MODE_RESUME ); + MCF.HaltMode( dev, HALT_MODE_HALT_BUT_NO_RESET ); + RVCommandPrologue( dev ); + MCF.SetEnableBreakpoints( dev, 1, 0 ); + //printf( "STEP PC: %08x\n", backup_regs[iss->nr_registers_for_debug] ); + return 0; + } // Special case halt_reset_or_resume = 4: Skip instruction and resume. - if( halt_reset_or_resume == 4 || halt_reset_or_resume == 2 ) + if( halt_reset_or_resume == HALT_TYPE_CONTINUE_WITH_SIGNAL || halt_reset_or_resume == HALT_TYPE_CONTINUE ) { // First see if we already know about this breakpoint int matchingbreakpoint = -1; @@ -259,7 +288,7 @@ void RVDebugExec( void * dev, int halt_reset_or_resume ) else ; //No change, it is a normal instruction. - if( halt_reset_or_resume == 4 ) + if( halt_reset_or_resume == HALT_TYPE_CONTINUE_WITH_SIGNAL ) { MCF.SetEnableBreakpoints( dev, 1, 1 ); } @@ -268,9 +297,9 @@ void RVDebugExec( void * dev, int halt_reset_or_resume ) halt_reset_or_resume = HALT_MODE_RESUME; } - if( shadow_running_state != ( halt_reset_or_resume >= 2 ) ) + if( shadow_running_state != ( halt_reset_or_resume >= HALT_TYPE_CONTINUE ) ) { - if( halt_reset_or_resume < 2 ) + if( halt_reset_or_resume < HALT_TYPE_CONTINUE ) { RVCommandPrologue( dev ); } @@ -278,10 +307,12 @@ void RVDebugExec( void * dev, int halt_reset_or_resume ) { RVCommandEpilogue( dev ); } + MCF.HaltMode( dev, halt_reset_or_resume ); } - shadow_running_state = halt_reset_or_resume >= 2; + shadow_running_state = halt_reset_or_resume >= HALT_TYPE_CONTINUE; + return 0; } int RVReadMem( void * dev, uint32_t memaddy, uint8_t * payload, int len ) @@ -292,6 +323,13 @@ int RVReadMem( void * dev, uint32_t memaddy, uint8_t * payload, int len ) exit( -6 ); } int ret = MCF.ReadBinaryBlob( dev, memaddy, len, payload ); + //printf( "Read Mem: %08x %d\n", memaddy, len ); + //int i; + //for( i = 0; i < len; i++ ) + //{ + // printf( "%02x%c", payload[i], ((i&15)==15)?'\n':' ' ); + //} + //printf( "\n" ); if( ret < 0 ) { fprintf( stderr, "Error reading binary blob at %08x\n", memaddy ); @@ -465,12 +503,15 @@ void RVHandleDisconnect( void * dev ) void RVHandleGDBBreakRequest( void * dev ) { - if( shadow_running_state ) - { - MCF.HaltMode( dev, 5 ); - } + MCF.HaltMode( dev, 5 ); } +void RVHandleUnsolicitedGDBBreakRequest( void * dev ) +{ + fprintf( stderr, "Invoke Unsolicited Break\n" ); + MCF.HaltMode( dev, 5 ); + gdbasserting_break = 1; +} int PollGDBServer( void * dev ) { diff --git a/minichlink/minichlink.c b/minichlink/minichlink.c index 270862c3..1e570be7 100644 --- a/minichlink/minichlink.c +++ b/minichlink/minichlink.c @@ -159,6 +159,8 @@ int main( int argc, char ** argv ) int must_be_end = 0; int skip_startup = + (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e' ) | + (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'A' ) | (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'u' ) | (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'h' ) | (argc > 1 && argv[1][0] == '-' && argv[1][1] == 't' ) | @@ -700,7 +702,7 @@ int main( int argc, char ** argv ) if( MCF.FlushLLCommands ) MCF.FlushLLCommands( dev ); - if( MCF.Exit ) + if( MCF.Exit && !skip_startup ) MCF.Exit( dev ); return 0; @@ -1273,10 +1275,11 @@ static int DefaultWriteWord( void * dev, uint32_t address_to_write, uint32_t dat return ret; } -int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob_size, uint8_t * blob ) +int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob_size, const uint8_t * blob ) { // NOTE IF YOU FIX SOMETHING IN THIS FUNCTION PLEASE ALSO UPDATE THE PROGRAMMERS. // this is only fallback functionality for really realy basic programmers. + // it is also used in unbrick. uint32_t rw; struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); @@ -1320,31 +1323,32 @@ int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob uint32_t temp; MCF.ReadWord( dev, 0x4002200c, &temp ); - if( temp & 0x8000 ) + //STATR & BOOT only exists on the 003 and x03x + // No issue if we force an unlock anyway. + //if( temp & 0x8000 ) { MCF.WriteWord( dev, 0x40022004, 0x45670123 ); // KEYR MCF.WriteWord( dev, 0x40022004, 0xCDEF89AB ); + + // These registers are not on or required on the v20x / v30x, but no harm in writing. MCF.WriteWord( dev, 0x40022008, 0x45670123 ); // OBWRE MCF.WriteWord( dev, 0x40022008, 0xCDEF89AB ); MCF.WriteWord( dev, 0x40022028, 0x45670123 ); //(FLASH_BOOT_MODEKEYP) MCF.WriteWord( dev, 0x40022028, 0xCDEF89AB ); //(FLASH_BOOT_MODEKEYP) - MCF.ReadWord( dev, 0x40022010, &temp ); - MCF.ReadWord( dev, 0x4002200c, &temp ); } MCF.ReadWord( dev, 0x4002200c, &temp ); if( temp & 0x8000 ) { fprintf( stderr, "Error: Critical memory zone is still locked out\n" ); - return -10; } if( MCF.WaitForFlash ) MCF.WaitForFlash( dev ); MCF.ReadWord( dev, 0x40022010, &temp ); + if( !(temp & (1<<9)) ) // Check OBWRE { - fprintf( stderr, "Error: Option Byte Unlock Failed\n" ); - return -10; + fprintf( stderr, "Error: Option Byte Unlock Failed (FLASH_CTRL=%08x)\n", temp ); } // Perform erase. @@ -1363,11 +1367,19 @@ int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob int i; for( i = 0; i < 8; i++ ) { + // OBPG = FLASH_CTLR_OPTPG MCF.WriteWord( dev, 0x40022010, FLASH_CTLR_OPTPG | FLASH_CTLR_OPTWRE ); MCF.WriteWord( dev, 0x40022010, FLASH_CTLR_OPTPG | FLASH_CTLR_STRT | FLASH_CTLR_OPTWRE ); - MCF.WriteHalfWord( dev, i*2+base, block[i*2+0] | (block[i*2+1]<<8) ); - + uint32_t writeaddy = i*2+base; + uint16_t writeword = block[i*2+0] | (block[i*2+1]<<8); + MCF.WriteHalfWord( dev, writeaddy, writeword ); if( MCF.WaitForFlash ) MCF.WaitForFlash( dev ); + uint16_t verify = 0; + MCF.ReadHalfWord( dev, writeaddy, &verify ); + if( verify != writeword ) + { + fprintf( stderr, "Warning when writing option bytes at %08x, %04x != %04x\n", writeaddy, writeword, verify ); + } MCF.ReadWord( dev, 0x4002200c, &temp ); if( temp & 0x10 ) { @@ -1375,8 +1387,9 @@ int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob return -9; } } - if( MCF.WaitForFlash ) MCF.WaitForFlash( dev ); + // Turn off OPTPG, OPTWRE. MCF.WriteWord( dev, 0x40022010, 0 ); + if( MCF.WaitForFlash ) MCF.WaitForFlash( dev ); return 0; } @@ -1428,13 +1441,13 @@ int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob for( i = 0; i < sectorsize/64; i++ ) { int r = MCF.BlockWrite64( dev, base + i*64, blob + rsofar+i*64 ); - rsofar += 64; if( r ) { fprintf( stderr, "Error writing block at memory %08x (error = %d)\n", base, r ); return r; } } + rsofar += sectorsize; } else // Block Write not avaialble { @@ -1536,7 +1549,6 @@ int DefaultWriteBinaryBlob( void * dev, uint32_t address_to_write, uint32_t blob MCF.WriteWord( dev, j*4+base, *(uint32_t*)(tempblock + j * 4) ); // On the v2xx, v3xx, you also need to make sure FLASH->STATR & 2 is not set. This is only an issue when running locally. - rsofar += 4; } if( iss->target_chip_type == CHIP_CH32V20x || iss->target_chip_type == CHIP_CH32V30x ) @@ -2128,14 +2140,14 @@ int DefaultWriteAllCPURegisters( void * dev, uint32_t * regret ) int i; for( i = 0; i < iss->nr_registers_for_debug; i++ ) { - MCF.WriteReg32( dev, DMCOMMAND, 0x00230000 | 0x1000 | i ); // Read xN into DATA0. if( MCF.WriteReg32( dev, DMDATA0, regret[i] ) ) { return -5; } + MCF.WriteReg32( dev, DMCOMMAND, 0x00230000 | 0x1000 | i ); // Read xN into DATA0. } - MCF.WriteReg32( dev, DMCOMMAND, 0x00230000 | 0x7b1 ); // Read xN into DATA0. int r = MCF.WriteReg32( dev, DMDATA0, regret[i] ); + MCF.WriteReg32( dev, DMCOMMAND, 0x00230000 | 0x7b1 ); // Read xN into DATA0. return r; } @@ -2172,7 +2184,6 @@ int DefaultSetEnableBreakpoints( void * dev, int is_enabled, int single_step ) else DCSR &=~4; - //printf( "Setting DCSR: %08x\n", DCSR ); if( MCF.WriteCPURegister( dev, 0x7b0, DCSR ) ) fprintf( stderr, "Error: DCSR could not be read\n" ); @@ -2298,11 +2309,11 @@ int DefaultUnbrick( void * dev ) MCF.DelayUS( dev, 60000 ); MCF.DelayUS( dev, 60000 ); MCF.Control3v3( dev, 1 ); - MCF.DelayUS( dev, 100 ); - MCF.FlushLLCommands( dev ); printf( "Connection starting\n" ); + MCF.FlushLLCommands( dev ); + int timeout = 0; - int max_timeout = 500; + int max_timeout = 50000; // An absurdly long time. uint32_t ds = 0; for( timeout = 0; timeout < max_timeout; timeout++ ) { @@ -2324,37 +2335,48 @@ int DefaultUnbrick( void * dev ) if( ds != 0xffffffff && ds != 0x00000000 ) break; } - // Make sure we are in halt. - MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Make the debug module work properly. - MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Initiate a halt request. - MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // No, really make sure. - MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); + if( timeout == max_timeout ) + { + fprintf( stderr, "Timed out trying to unbrick\n" ); + return -5; + } + + int i; + for( i = 0; i < 10; i++ ) + { + // Make sure we are in halt. + MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Make the debug module work properly. + MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // Initiate a halt request. + MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); // No, really make sure. + MCF.WriteReg32( dev, DMCONTROL, 0x80000001 ); + + // After more experimentation, it appaers to work best by not clearing the halt request. + MCF.FlushLLCommands( dev ); + } + + MCF.WriteReg32( dev, DMABSTRACTCS, 0x00000700 ); // Clear out possible abstractcs errors. int r = MCF.ReadReg32( dev, DMSTATUS, &ds ); printf( "DMStatus After Halt: /%d/%08x\n", r, ds ); -// Many times we would clear the halt request, but in this case, we want to just leave it here, to prevent it from booting. -// TODO: Experiment and see if this is needed/wanted in cases. NOTE: If you don't clear halt request, progarmmers can get stuck. -// MCF.WriteReg32( dev, DMCONTROL, 0x00000001 ); // Clear Halt Request. - - // After more experimentation, it appaers to work best by not clearing the halt request. - MCF.FlushLLCommands( dev ); + DefaultDetermineChipType( dev ); + struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); + printf( "Chip Type: %d\n", iss->target_chip_type ); // Override all option bytes and reset to factory settings, unlocking all flash sections. - uint8_t option_data[] = { 0xa5, 0x5a, 0x97, 0x68, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00 }; - if( MCF.WriteBinaryBlob != DefaultWriteBinaryBlob ) - { - fprintf( stderr, "Warning, using nonstandard WriteBinaryBlob. Unbrick may not work.\n" ); - } - MCF.WriteBinaryBlob(dev, 0x1ffff800, sizeof( option_data ), option_data ); + static const uint8_t option_data_003_x03x[] = { 0xa5, 0x5a, 0x97, 0x68, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00 }; + static const uint8_t option_data_20x_30x[] = { 0xa5, 0x5a, 0x3f, 0xc0, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00 }; + + InternalUnlockFlash(dev, iss); + + const uint8_t * option_data = + ( iss->target_chip_type == CHIP_CH32X03x || iss->target_chip_type == CHIP_CH32V003 ) ? + option_data_003_x03x : option_data_20x_30x; + + DefaultWriteBinaryBlob(dev, 0x1ffff800, 16, option_data ); MCF.DelayUS( dev, 20000 ); - if( timeout == max_timeout ) - { - fprintf( stderr, "Timed out trying to unbrick\n" ); - return -5; - } MCF.Erase( dev, 0, 0, 1); MCF.FlushLLCommands( dev ); return -5; diff --git a/minichlink/minichlink.exe b/minichlink/minichlink.exe old mode 100644 new mode 100755 index b1fe776a..4ac8f28a Binary files a/minichlink/minichlink.exe and b/minichlink/minichlink.exe differ diff --git a/minichlink/minichlink.h b/minichlink/minichlink.h index 362fa278..0ed4a2f9 100644 --- a/minichlink/minichlink.h +++ b/minichlink/minichlink.h @@ -31,7 +31,7 @@ struct MiniChlinkFunctions int (*SetSplit)( void * dev, enum RAMSplit split ); // No boundary or limit rules. Must support any combination of alignment and size. - int (*WriteBinaryBlob)( void * dev, uint32_t address_to_write, uint32_t blob_size, uint8_t * blob ); + int (*WriteBinaryBlob)( void * dev, uint32_t address_to_write, uint32_t blob_size, const uint8_t * blob ); int (*ReadBinaryBlob)( void * dev, uint32_t address_to_read_from, uint32_t read_size, uint8_t * blob ); int (*Erase)( void * dev, uint32_t address, uint32_t length, int type ); //type = 0 for fast, 1 for whole-chip @@ -62,7 +62,7 @@ struct MiniChlinkFunctions int (*PrintChipInfo)( void * dev ); // Geared for flash, but could be anything. Note: If in flash, must also erase. - int (*BlockWrite64)( void * dev, uint32_t address_to_write, uint8_t * data ); + int (*BlockWrite64)( void * dev, uint32_t address_to_write, const uint8_t * data ); // Returns positive if received text. // Returns negative if error. diff --git a/minichlink/pgm-b003fun.c b/minichlink/pgm-b003fun.c index a84f4be6..ce9cebf8 100644 --- a/minichlink/pgm-b003fun.c +++ b/minichlink/pgm-b003fun.c @@ -232,7 +232,7 @@ static int B003FunDelayUS( void * dev, int microseconds ) } // Does not handle erasing -static int InternalB003FunWriteBinaryBlob( void * dev, uint32_t address_to_write_to, uint32_t write_size, uint8_t * blob ) +static int InternalB003FunWriteBinaryBlob( void * dev, uint32_t address_to_write_to, uint32_t write_size, const uint8_t * blob ) { struct B003FunProgrammerStruct * eps = (struct B003FunProgrammerStruct *)dev; @@ -436,7 +436,7 @@ static int B003FunReadWord( void * dev, uint32_t address_to_read, uint32_t * dat return B003FunReadBinaryBlob( dev, address_to_read, 4, (uint8_t*)data ); } -static int B003FunBlockWrite64( void * dev, uint32_t address_to_write, uint8_t * data ) +static int B003FunBlockWrite64( void * dev, uint32_t address_to_write, const uint8_t * data ) { struct B003FunProgrammerStruct * eps = (struct B003FunProgrammerStruct*) dev; struct InternalState * iss = eps->internal; diff --git a/minichlink/pgm-esp32s2-ch32xx.c b/minichlink/pgm-esp32s2-ch32xx.c index fb4b87ed..54f2a6ac 100644 --- a/minichlink/pgm-esp32s2-ch32xx.c +++ b/minichlink/pgm-esp32s2-ch32xx.c @@ -91,6 +91,119 @@ int ESPReadReg32( void * dev, uint8_t reg_7_bit, uint32_t * commandresp ) } } +int ESPReadAllCPURegisters( void * dev, uint32_t * regret ) +{ + struct InternalState * iss = (struct InternalState*)(((struct ProgrammerStructBase*)dev)->internal); + struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev; + ESPFlushLLCommands( dev ); + + Write2LE( eps, 0x05fe ); // Void ESP's internal high level state. + iss->statetag = STTAG( "RER2" ); // Void local high level state. + + ESPWriteReg32( dev, DMABSTRACTAUTO, 0x00000000 ); // Disable Autoexec. + MCF.DetermineChipType( dev ); + int i; + for( i = 0; i < iss->nr_registers_for_debug; i++ ) + { + ESPWriteReg32( dev, DMCOMMAND, 0x00220000 | 0x1000 | i ); // Read xN into DATA0. + Write1( eps, (DMDATA0<<1) | 0 ); + } + ESPWriteReg32( dev, DMCOMMAND, 0x00220000 | 0x7b1 ); // Read xN into DATA0. + Write1( eps, (DMDATA0<<1) | 0 ); + ESPFlushLLCommands( eps ); + if( eps->replylen - 1 != (iss->nr_registers_for_debug+1)*5 ) + { + fprintf( stderr, "Error: Weird reply trying to read all CPU registers (%d/%d)\n", eps->replylen - 1, (iss->nr_registers_for_debug+1)*5 ); + return -1; + } + uint8_t * e = eps->reply + 1; + for( i = 0; i < iss->nr_registers_for_debug + 1; i++ ) + { + if( *e ) + { + fprintf( stderr, "Error reading reg at %d %d\n", i, *e ); + return -2; + } + e++; + memcpy( regret + i, e, 4 ); + e += 4; + } + return 0; +} + +int DefaultReadBinaryBlob( void * dev, uint32_t address_to_read_from, uint32_t read_size, uint8_t * blob ); +int ESPReadBinaryBlob( void * dev, uint32_t address_to_read_from, uint32_t read_size_in, uint8_t * blob ) +{ + int read_size = read_size_in; + struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev; + uint32_t address_to_read_from_2 = address_to_read_from; + uint8_t * blob_2 = blob; + int r = 0; + + if( read_size == 0 ) + { + return 0; + } + + if( address_to_read_from_2 & 3 ) + { + // We have to read out the first few bits. + int nrb2r = 4 - (address_to_read_from_2 & 3); + if( nrb2r < read_size ) nrb2r = read_size; + r = DefaultReadBinaryBlob( dev, address_to_read_from_2, read_size, blob_2 ); + if( r ) return r; + address_to_read_from_2 += nrb2r; + blob_2 += nrb2r; + read_size -= nrb2r; + } + + if( read_size <= 0 ) + { + return 0; + } + + int words = read_size / 4; + + ESPFlushLLCommands( dev ); + int w = 0; + int words_this_group = 0; + while( w <= words ) + { + if( w < words ) + { + Write2LE( eps, 0x09fe ); + Write4LE( eps, address_to_read_from_2 ); + address_to_read_from_2 += 4; + read_size -= 4; + words_this_group++; + } + if( ( SRemain( eps ) < 8 ) || ( words_this_group * 5 > eps->replysize - 4 ) || w == words ) + { + ESPFlushLLCommands( dev ); + uint8_t * resp = eps->reply + 1; + int i; + for( i = 0; i < words_this_group; i++ ) + { + if( resp[0] ) return resp[0]; + memcpy( blob_2, resp + 1, 4 ); + resp += 5; + blob_2 += 4; + } + words_this_group = 0; + } + w++; + } + + if( read_size > 0 ) + { + r = DefaultReadBinaryBlob( dev, address_to_read_from_2, read_size, blob_2 ); + if( r ) return r; + } + + return 0; +} + + int ESPFlushLLCommands( void * dev ) { struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev; @@ -106,7 +219,7 @@ int ESPFlushLLCommands( void * dev ) int r; eps->commandbuffer[0] = 0xad; // Key report ID - eps->commandbuffer[eps->commandplace] = 0xff; + memset( eps->commandbuffer + eps->commandplace, 0xff, eps->commandbuffersize - eps->commandplace - 1 ); #if 0 int i; @@ -240,7 +353,7 @@ int ESPExit( void * dev ) return 0; } -int ESPBlockWrite64( void * dev, uint32_t address_to_write, uint8_t * data ) +int ESPBlockWrite64( void * dev, uint32_t address_to_write, const uint8_t * data ) { int writeretry = 0; struct ESP32ProgrammerStruct * eps = (struct ESP32ProgrammerStruct *)dev; @@ -448,6 +561,8 @@ void * TryInit_ESP32S2CHFUN() MCF.WaitForFlash = ESPWaitForFlash; MCF.WaitForDoneOp = ESPWaitForDoneOp; MCF.BlockWrite64 = ESPBlockWrite64; + MCF.ReadBinaryBlob = ESPReadBinaryBlob; + MCF.ReadAllCPURegisters = ESPReadAllCPURegisters; // Reset internal programmer state. Write2LE( eps, 0x0afe ); diff --git a/minichlink/pgm-wch-linke.c b/minichlink/pgm-wch-linke.c index cab605e6..9b2ea655 100644 --- a/minichlink/pgm-wch-linke.c +++ b/minichlink/pgm-wch-linke.c @@ -69,7 +69,7 @@ static int checkChip(enum RiscVChip chip) { // For non-ch32v003 chips. //static int LEReadBinaryBlob( void * d, uint32_t offset, uint32_t amount, uint8_t * readbuff ); static int InternalLinkEHaltMode( void * d, int mode ); -static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, uint8_t * blob ); +static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, const uint8_t * blob ); #define WCHTIMEOUT 5000 #define WCHCHECK(x) if( (status = x) ) { fprintf( stderr, "Bad USB Operation on " __FILE__ ":%d (%d)\n", __LINE__, status ); exit( status ); } @@ -518,6 +518,8 @@ static int LEControl5v( void * d, int bOn ) return 0; } +// Official unbrick unreliable on x-series devices. +/* static int LEUnbrick( void * d ) { printf( "Sending unbrick\n" ); @@ -526,7 +528,7 @@ static int LEUnbrick( void * d ) printf( "Done unbrick\n" ); return 0; } - +*/ static int LEConfigureNRSTAsGPIO( void * d, int one_if_yes_gpio ) { @@ -584,7 +586,7 @@ void * TryInit_WCHLinkE() MCF.SetupInterface = LESetupInterface; MCF.Control3v3 = LEControl3v3; MCF.Control5v = LEControl5v; - MCF.Unbrick = LEUnbrick; + //MCF.Unbrick = LEUnbrick; // MCF.ConfigureNRSTAsGPIO = LEConfigureNRSTAsGPIO; MCF.ConfigureReadProtection = LEConfigureReadProtection; @@ -765,7 +767,7 @@ static int LEReadBinaryBlob( void * d, uint32_t offset, uint32_t amount, uint8_t } #endif -static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, uint8_t * blob ) +static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, const uint8_t * blob ) { libusb_device_handle * dev = ((struct LinkEProgrammerStruct*)d)->devh; struct InternalState * iss = (struct InternalState*)(((struct LinkEProgrammerStruct*)d)->internal); @@ -833,7 +835,7 @@ static int LEWriteBinaryBlob( void * d, uint32_t address_to_write, uint32_t len, } else { - WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, blob+pplace, iss->sector_size, &transferred, WCHTIMEOUT ) ); + WCHCHECK( libusb_bulk_transfer( (libusb_device_handle *)dev, 0x02, ((uint8_t*)blob)+pplace, iss->sector_size, &transferred, WCHTIMEOUT ) ); } }