diff --git a/ch32v003fun/ch32v003fun.h b/ch32v003fun/ch32v003fun.h index 1634bcb8e1d59b10b564fba9e94370168f4dddee..ba320ecf0082e95111d7f9ee4ab39ab5bf0f5223 100644 --- a/ch32v003fun/ch32v003fun.h +++ b/ch32v003fun/ch32v003fun.h @@ -5082,6 +5082,68 @@ int _write(int fd, const char *buf, int size); #endif +// xw_ext.inc, thanks to @macyler, @jnk0le, @duk for this reverse engineering. + +/* +Encoder for some of the proprietary 'XW' RISC-V instructions present on the QingKe RV32 processor. +Examples: + XW_C_LBU(a3, a1, 27); // c.xw.lbu a3, 27(a1) + XW_C_SB(a0, s0, 13); // c.xw.sb a0, 13(s0) + + XW_C_LHU(a5, a5, 38); // c.xw.lhu a5, 38(a5) + XW_C_SH(a2, s1, 14); // c.xw.sh a2, 14(s1) +*/ + +// Let us do some compile-time error checking. +#define ASM_ASSERT(COND) .if (!(COND)); .err; .endif + +// Integer encodings of the possible compressed registers. +#define C_s0 0 +#define C_s1 1 +#define C_a0 2 +#define C_a1 3 +#define C_a2 4 +#define C_a3 5 +#define C_a4 6 +#define C_a5 7 + +// register to encoding +#define REG2I(X) (C_ ## X) + +// XW opcodes +#define XW_OP_LBUSP 0b1000000000000000 +#define XW_OP_STSP 0b1000000001000000 + +#define XW_OP_LHUSP 0b1000000000100000 +#define XW_OP_SHSP 0b1000000001100000 + +#define XW_OP_LBU 0b0010000000000000 +#define XW_OP_SB 0b1010000000000000 + +#define XW_OP_LHU 0b0010000000000010 +#define XW_OP_SH 0b1010000000000010 + +// The two different XW encodings supported at the moment. +#define XW_ENCODE1(OP, R1, R2, IMM) ASM_ASSERT((IMM) >= 0 && (IMM) < 32); .2byte ((OP) | (REG2I(R1) << 2) | (REG2I(R2) << 7) | \ + (((IMM) & 0b1) << 12) | (((IMM) & 0b110) << (5 - 1)) | (((IMM) & 0b11000) << (10 - 3))) + +#define XW_ENCODE2(OP, R1, R2, IMM) ASM_ASSERT((IMM) >= 0 && (IMM) < 32); .2byte ((OP) | (REG2I(R1) << 2) | (REG2I(R2) << 7) | \ + (((IMM) & 0b11) << 5) | (((IMM) & 0b11100) << (10 - 2)) + +// Compressed load byte, zero-extend result +#define XW_C_LBU(RD, RS, IMM) XW_ENCODE1(XW_OP_LBU, RD, RS, IMM) + +// Compressed store byte +#define XW_C_SB(RS1, RS2, IMM) XW_ENCODE1(XW_OP_SB, RS1, RS2, IMM) + +// Compressed load half, zero-extend result +#define XW_C_LHU(RD, RS, IMM) ASM_ASSERT(((IMM) & 1) == 0); XW_ENCODE2(XW_OP_LHU, RD, RS, ((IMM) >> 1))) + +// Compressed store half +#define XW_C_SH(RS1, RS2, IMM) ASM_ASSERT(((IMM) & 1) == 0); XW_ENCODE2(XW_OP_SH, RS1, RS2, ((IMM) >> 1))) + + + #ifdef __cplusplus }; #endif diff --git a/ch32v003fun/xw_ext.inc b/ch32v003fun/xw_ext.inc deleted file mode 100644 index ca210702fc69d9d31b87d9f69ddaf004c17e0b0c..0000000000000000000000000000000000000000 --- a/ch32v003fun/xw_ext.inc +++ /dev/null @@ -1,57 +0,0 @@ -/* -Encoder for some of the proprietary 'XW' RISC-V instructions present on the QingKe RV32 processor. -Examples: - XW_C_LBU(a3, a1, 27); // c.xw.lbu a3, 27(a1) - XW_C_SB(a0, s0, 13); // c.xw.sb a0, 13(s0) - - XW_C_LHU(a5, a5, 38); // c.xw.lhu a5, 38(a5) - XW_C_SH(a2, s1, 14); // c.xw.sh a2, 14(s1) -*/ - -// Let us do some compile-time error checking. -#define ASM_ASSERT(COND) .if (!(COND)); .err; .endif - -// Integer encodings of the possible compressed registers. -#define C_s0 0 -#define C_s1 1 -#define C_a0 2 -#define C_a1 3 -#define C_a2 4 -#define C_a3 5 -#define C_a4 6 -#define C_a5 7 - -// register to encoding -#define REG2I(X) (C_ ## X) - -// XW opcodes -#define XW_OP_LBUSP 0b1000000000000000 -#define XW_OP_STSP 0b1000000001000000 - -#define XW_OP_LHUSP 0b1000000000100000 -#define XW_OP_SHSP 0b1000000001100000 - -#define XW_OP_LBU 0b0010000000000000 -#define XW_OP_SB 0b1010000000000000 - -#define XW_OP_LHU 0b0010000000000010 -#define XW_OP_SH 0b1010000000000010 - -// The two different XW encodings supported at the moment. -#define XW_ENCODE1(OP, R1, R2, IMM) ASM_ASSERT((IMM) >= 0 && (IMM) < 32); .2byte ((OP) | (REG2I(R1) << 2) | (REG2I(R2) << 7) | \ - (((IMM) & 0b1) << 12) | (((IMM) & 0b110) << (5 - 1)) | (((IMM) & 0b11000) << (10 - 3))) - -#define XW_ENCODE2(OP, R1, R2, IMM) ASM_ASSERT((IMM) >= 0 && (IMM) < 32); .2byte ((OP) | (REG2I(R1) << 2) | (REG2I(R2) << 7) | \ - (((IMM) & 0b11) << 5) | (((IMM) & 0b11100) << (10 - 2)) - -// Compressed load byte, zero-extend result -#define XW_C_LBU(RD, RS, IMM) XW_ENCODE1(XW_OP_LBU, RD, RS, IMM) - -// Compressed store byte -#define XW_C_SB(RS1, RS2, IMM) XW_ENCODE1(XW_OP_SB, RS1, RS2, IMM) - -// Compressed load half, zero-extend result -#define XW_C_LHU(RD, RS, IMM) ASM_ASSERT(((IMM) & 1) == 0); XW_ENCODE2(XW_OP_LHU, RD, RS, ((IMM) >> 1))) - -// Compressed store half -#define XW_C_SH(RS1, RS2, IMM) ASM_ASSERT(((IMM) & 1) == 0); XW_ENCODE2(XW_OP_SH, RS1, RS2, ((IMM) >> 1))) diff --git a/minichlink/Makefile b/minichlink/Makefile index 15d3c1a5a3f680519403ae26d9bdb8883b348351..964341c11b51b66accf732be82639d887df7c0cd 100644 --- a/minichlink/Makefile +++ b/minichlink/Makefile @@ -1,7 +1,7 @@ TOOLS:=minichlink minichlink.so CFLAGS:=-O0 -g3 -Wall -C_S:=minichlink.c pgm-wch-linke.c pgm-esp32s2-ch32xx.c nhc-link042.c ardulink.c serial_dev.c minichgdb.c +C_S:=minichlink.c pgm-wch-linke.c pgm-esp32s2-ch32xx.c nhc-link042.c ardulink.c serial_dev.c pgm-b003fun.c minichgdb.c # General Note: To use with GDB, gdb-multiarch # gdb-multilib {file} diff --git a/minichlink/minichlink.c b/minichlink/minichlink.c index 191237b6a124779b5501355605dce8edbc06d705..592839d50ed12a6efeae5f34c3a278c5046bc807 100644 --- a/minichlink/minichlink.c +++ b/minichlink/minichlink.c @@ -41,6 +41,10 @@ void * MiniCHLinkInitAsDLL( struct MiniChlinkFunctions ** MCFO ) { fprintf( stderr, "Found NHC-Link042 Programmer\n" ); } + else if ((dev = TryInit_B003Fun())) + { + fprintf( stderr, "Found B003Fun Bootloader\n" ); + } else if ((dev = TryInit_Ardulink())) { fprintf( stderr, "Found Ardulink Programmer\n" ); diff --git a/minichlink/minichlink.h b/minichlink/minichlink.h index 6a974ff230635fa24a2a769512d61c356dc3013c..37960eacafe4751fdb2424adb80129134697a714 100644 --- a/minichlink/minichlink.h +++ b/minichlink/minichlink.h @@ -150,9 +150,10 @@ extern struct MiniChlinkFunctions MCF; // Returns 'dev' on success, else 0. -void * TryInit_WCHLinkE(); -void * TryInit_ESP32S2CHFUN(); +void * TryInit_WCHLinkE(void); +void * TryInit_ESP32S2CHFUN(void); void * TryInit_NHCLink042(void); +void * TryInit_B003Fun(void); void * TryInit_Ardulink(); // Returns 0 if ok, populated, 1 if not populated. diff --git a/minichlink/pgm-b003fun.c b/minichlink/pgm-b003fun.c new file mode 100644 index 0000000000000000000000000000000000000000..5e37aea3fc5b653577934ccb4fa626c0865592a9 --- /dev/null +++ b/minichlink/pgm-b003fun.c @@ -0,0 +1,150 @@ +#if 0 +#include <stdint.h> +#include "hidapi.h" +#include "minichlink.h" + + +struct B003FunProgrammerStruct +{ + void * internal; + hid_device * hd; + uint8_t commandbuffer[128]; + int commandplace; + +/* + uint32_t state; + uint8_t reply[256]; + int replylen; +*/ +}; + + +static int B003FunFlushLLCommands( void * dev ) +{ + return 0; +} + +static int B003FunDelayUS( void * dev, int microseconds ) +{ + usleep( microseconds ); + return 0; +} + +static int B003FunSetupInterface( void * dev ) +{ + return 0; +} + +static int B003FunExit( void * dev ) +{ + return 0; +} + +// MUST be 4-byte-aligned. +static int B003FunWriteWord( void * dev, uint32_t address_to_write, uint32_t data ) +{ + return 0; +} + +static int B003FunReadWord( void * dev, uint32_t address_to_read, uint32_t * data ) +{ + return 0; +} + +static int B003FunWaitForDoneOp( void * dev, int ignore ) +{ + // ... Need this. + return 0; +} + + +static int B003FunBlockWrite64( void * dev, uint32_t address_to_write, uint8_t * data ) +{ + return 0; +} + +static int B003FunWriteHalfWord( void * dev, uint32_t address_to_write, uint16_t data ) +{ +} + +static int B003FunReadHalfWord( void * dev, uint32_t address_to_read, uint16_t * data ) +{ +} + +static int B003FunWriteByte( void * dev, uint32_t address_to_write, uint8_t data ) +{ +} + +static int B003FunReadByte( void * dev, uint32_t address_to_read, uint8_t * data ) +{ +} + + +static void ResetOp( struct B003FunProgrammerStruct * eps ) +{ + memcpy( eps->commandbuffer, "\xaa\x00\x00\x00", 4 ); + eps->commandplace = 4; +} + +static void WriteOp4( struct B003FunProgrammerStruct * eps, uint32_t opsend ) +{ + int place = eps->commandplace; + int newend = place + 4; + if( newend < sizeof( eps->commandbuffer ) ) + { + memcpy( eps->commandbuffer + place, &opsend, 4 ); + } + eps->commandplace = newend; +} + +static void CommitOp( struct B003FunProgrammerStruct * eps ) +{ +} + CommitOp( eps ); + + + +void * TryInit_B003Fun() +{ + #define VID 0x1209 + #define PID 0xb003 + hid_init(); + hid_device * hd = hid_open( VID, PID, 0); // third parameter is "serial" + if( !hd ) return 0; + + struct B003FunProgrammerStruct * eps = malloc( sizeof( struct B003FunProgrammerStruct ) ); + memset( eps, 0, sizeof( *eps ) ); + eps->hd = hd; + eps->commandplace = 1; + + memset( &MCF, 0, sizeof( MCF ) ); + MCF.WriteReg32 = 0; + MCF.ReadReg32 = 0; + MCF.FlushLLCommands = B003FunFlushLLCommands; + MCF.DelayUS = B003FunDelayUS; + MCF.Control3v3 = 0; + MCF.SetupInterface = B003FunSetupInterface; + MCF.Exit = B003FunExit; + MCF.HaltMode = 0; + MCF.VoidHighLevelState = 0; + MCF.PollTerminal = 0; + + // These are optional. Disabling these is a good mechanismto make sure the core functions still work. + MCF.WriteWord = B003FunWriteWord; + MCF.ReadWord = B003FunReadWord; + + MCF.WaitForDoneOp = B003FunWaitForDoneOp; + + MCF.BlockWrite64 = B003FunBlockWrite64; + + // Alert programmer. + ResetOp( eps ) + WriteOp4( eps, 0x00b02023 ); //sw a1, 0 ; stop execution + WriteOp4( eps, 0x00008067 ); //jalr x0, x1, 0 ; ret + CommitOp( eps ); + + return eps; +} +#else +void * TryInit_B003Fun() { return 0; } +#endif