stm8loader add exec

This commit is contained in:
2025-12-22 00:30:10 +08:00
parent c0ade721c5
commit a0f940af72
4 changed files with 308 additions and 234 deletions

View File

@@ -42,7 +42,7 @@ CFLAGS += --stack-auto --noinduction --use-non-free
LDFLAGS = -m$(ARCH) -l$(ARCH) --out-fmt-ihx LDFLAGS = -m$(ARCH) -l$(ARCH) --out-fmt-ihx
OPTION_BOOT := 0x480D OPTION_BOOT := 0x480D
RAM_BOOT := 0x0232 RAM_BOOT := 0x023E
OPTFLAGS = -Wl-bOPTION=0x4800 -Wl-bOPTION_BOOT=$(OPTION_BOOT) OPTFLAGS = -Wl-bOPTION=0x4800 -Wl-bOPTION_BOOT=$(OPTION_BOOT)
B2FLAGS = -Wl-bRAM_BOOT=$(RAM_BOOT) B2FLAGS = -Wl-bRAM_BOOT=$(RAM_BOOT)

Binary file not shown.

View File

@@ -96,15 +96,15 @@ _main_loop:
_invalid_cmd_error: _invalid_cmd_error:
; 未知命令,发送错误响应 ; 未知命令,发送错误响应
mov tx_state, #ERR_INVCMD ld A, #ERR_INVCMD
_ack_then_back:
call send_ack_state_response call send_ack_state_response
jra _main_loop jra _main_loop
_checksum_error: _checksum_error:
; 校验和错误响应 ; 校验和错误响应
mov tx_state, #ERR_CHECKSUM ld A, #ERR_CHECKSUM
call send_ack_state_response jra _ack_then_back
jra _main_loop
_cmd_read: _cmd_read:
; 读取内存命令 ; 读取内存命令
@@ -127,7 +127,8 @@ _cmd_exec:
ld A, #0x81 ; ret code ld A, #0x81 ; ret code
ld (X), A ; X point to checksum already ld (X), A ; X point to checksum already
call rx_buffer call rx_buffer
jra _main_loop ld A, #SUCCESS_CODE
jra _ack_then_back
receive_frame: receive_frame:
; 初始化接收状态 ; 初始化接收状态
@@ -204,12 +205,18 @@ _verify_loop:
ret ret
send_response_pkg: send_response_pkg:
clr calc_checksum ; set header
ldw X, #tx_buffer ldw X, #tx_buffer
ld A, #ACK_HEADER
ld (X), A
; tx_data_length += 5
ld A, tx_data_length ld A, tx_data_length
add A, #5 add A, #5
ld temp_var1, A ld temp_var1, A
; send data ; send data
clr calc_checksum
_send_loop: _send_loop:
ld A, (X) ld A, (X)
ld UART1_DR, A ld UART1_DR, A
@@ -222,49 +229,39 @@ _wait_tx1:
incw X incw X
dec temp_var1 dec temp_var1
jrne _send_loop jrne _send_loop
; send checksum ; send checksum
ld A, calc_checksum ld A, calc_checksum
ld UART1_DR, A ld UART1_DR, A
_wait_tx2: _wait_tx2:
btjf UART1_SR, #7, _wait_tx2 btjf UART1_SR, #7, _wait_tx2
; finish ; finish
ret ret
; 发送应答状态帧 ; 发送应答状态帧
send_ack_state_response: send_ack_state_response:
; set header ; set data
ldw X, #tx_buffer ldw X, #tx_buffer+5
ld A, #ACK_HEADER
ld (X), A ld (X), A
; set length ; set length
addw X, #4 decw X
ld A, #1 ld A, #1
ld (X), A ld (X), A
ld tx_data_length, A ld tx_data_length, A
; set data
incw X
ld A, tx_state
ld (X), A
callr send_response_pkg callr send_response_pkg
ret ret
; 发送应答数据帧 ; 发送应答数据帧
send_ack_data_response: send_ack_data_response:
; set header
ldw X, #tx_buffer
ld A, #ACK_HEADER
ld (X), A
; set length ; set length
addw X, #4 ldw X, #tx_buffer+4
ld A, tx_data_length ld A, tx_data_length
ld (X), A ld (X), A
; already set data ; already set data
callr send_response_pkg callr send_response_pkg
ret ret
@@ -333,6 +330,7 @@ _mem_write:
incw Y incw Y
dec temp_var1 dec temp_var1
jrne _mem_write jrne _mem_write
ld A, #SUCCESS_CODE
callr send_ack_state_response callr send_ack_state_response
ret ret
@@ -378,6 +376,7 @@ _write_end:
mov FLASH_NCR2, #0xFF mov FLASH_NCR2, #0xFF
; lock FLASH/DATA ; lock FLASH/DATA
callr lock_flash callr lock_flash
ld A, tx_state
call send_ack_state_response call send_ack_state_response
ret ret

View File

@@ -17,6 +17,7 @@ from typing import Optional, List, Tuple, Union, BinaryIO
CMD_READ = 0xF1 # Read memory command CMD_READ = 0xF1 # Read memory command
CMD_WRITE = 0xF2 # Write memory command CMD_WRITE = 0xF2 # Write memory command
CMD_GO = 0xF3 # Jump execution command CMD_GO = 0xF3 # Jump execution command
CMD_EXEC = 0xF4 # Execute machine code command
CMD_HEADER = 0x5A # Frame header sent to MCU CMD_HEADER = 0x5A # Frame header sent to MCU
ACK_HEADER = 0xA5 # MCU response frame header ACK_HEADER = 0xA5 # MCU response frame header
@@ -259,6 +260,17 @@ class STM8Bootloader:
self.serial.write(reversed_data) self.serial.write(reversed_data)
self.serial.flush() self.serial.flush()
# Log sent data in hex format
if self.verbose:
# Show first and last 64 bytes to avoid too much output
if len(reversed_data) <= 128:
self.log(f"Sent data (hex): {reversed_data.hex()}", "DEBUG")
else:
first_part = reversed_data[:64].hex()
last_part = reversed_data[-64:].hex()
self.log(f"Sent data (first 64 bytes): {first_part}", "DEBUG")
self.log(f"Sent data (last 64 bytes): {last_part}", "DEBUG")
self.log(f"Sent {len(data)} bytes (reversed)", "DEBUG") self.log(f"Sent {len(data)} bytes (reversed)", "DEBUG")
return True return True
@@ -389,6 +401,11 @@ class STM8Bootloader:
# Create and send command frame # Create and send command frame
frame = self.create_command_frame(cmd, addr, data) frame = self.create_command_frame(cmd, addr, data)
# Log sent frame in hex format
if self.verbose:
self.log(f"Sending command frame (hex): {frame.hex()}", "DEBUG")
self.serial.write(frame) self.serial.write(frame)
self.serial.flush() self.serial.flush()
@@ -401,6 +418,10 @@ class STM8Bootloader:
if not response: if not response:
raise STM8BootloaderError("No response received") raise STM8BootloaderError("No response received")
# Log received response in hex format
if self.verbose:
self.log(f"Received response (hex): {response.hex()}", "DEBUG")
return self.parse_response_frame(response) return self.parse_response_frame(response)
def check_boot2(self) -> bool: def check_boot2(self) -> bool:
@@ -590,6 +611,31 @@ class STM8Bootloader:
return True return True
def exec_machine_code(self, addr: int, machine_code: bytes) -> bool:
"""
Execute machine code at specified address
Args:
addr: Execution address
machine_code: Machine code to execute
Returns:
True: Command sent successfully
"""
if not self.in_boot2:
raise STM8BootloaderError("Not in boot2 mode")
if len(machine_code) > MAX_DATA_SIZE:
raise STM8BootloaderError(f"Machine code length exceeds {MAX_DATA_SIZE} byte limit")
try:
# exec command doesn't care wait for response
self.send_command(CMD_EXEC, addr, machine_code, wait_response=True)
self.log(f"Sent execute machine code at 0x{addr:04X} command", "DEBUG")
return True
except Exception as e:
raise STM8BootloaderError(f"Failed to send execute command: {e}")
def go_execute(self, addr: int) -> bool: def go_execute(self, addr: int) -> bool:
""" """
Jump to specified address for execution Jump to specified address for execution
@@ -711,7 +757,7 @@ class STM8Bootloader:
def interactive_mode(self): def interactive_mode(self):
"""Interactive mode""" """Interactive mode"""
self.log("\n=== STM8 Bootloader Interactive Mode ===", "INFO") self.log("\n=== STM8 Bootloader Interactive Mode ===", "INFO")
self.log("Available commands: read, write, go, info, ls, reload, help, exit", "INFO") self.log("Available commands: read, write, exec, go, info, ls, reload, help, exit", "INFO")
self.log("Type 'help' for detailed usage\n", "INFO") self.log("Type 'help' for detailed usage\n", "INFO")
while True: while True:
@@ -808,6 +854,32 @@ class STM8Bootloader:
except Exception as e: except Exception as e:
self.log(f"Error: {e}", "ERROR") self.log(f"Error: {e}", "ERROR")
elif cmd == 'exec':
if len(args) < 2:
self.log("Usage: exec <hex_string>", "ERROR")
self.log("Example: exec 4F9D (CLR A; NOP)", "INFO")
continue
try:
addr = 0 # run in #boot2.rx_buffer
hex_str = args[1]
# Parse hex string
hex_str = hex_str.replace('0x', '').replace(' ', '')
if len(hex_str) % 2 != 0:
raise ValueError("Hex string length must be even")
machine_code = bytes.fromhex(hex_str)
if len(machine_code) > MAX_DATA_SIZE:
self.log(f"Error: Machine code too long (max {MAX_DATA_SIZE} bytes)", "ERROR")
continue
if self.exec_machine_code(addr, machine_code):
self.log(f"Execute command sent: {len(machine_code)} bytes at 0x{addr:04X}", "INFO")
except Exception as e:
self.log(f"Error: {e}", "ERROR")
elif cmd == 'go': elif cmd == 'go':
if len(args) < 2: if len(args) < 2:
self.log("Usage: go <addr>", "ERROR") self.log("Usage: go <addr>", "ERROR")
@@ -851,6 +923,9 @@ Command List:
Example: write 0x8000 firmware.bin Example: write 0x8000 firmware.bin
Example: write 0x8000 AABBCCDDEEFF Example: write 0x8000 AABBCCDDEEFF
exec <hex_str> - Execute machine code at specified address
Example: exec 4F9D (CLR A; NOP;)
go <addr> - Jump to specified address for execution go <addr> - Jump to specified address for execution
Example: go 0x8000 Example: go 0x8000
@@ -925,7 +1000,7 @@ Examples:
parser.add_argument('-i', '--interactive', action='store_true', parser.add_argument('-i', '--interactive', action='store_true',
help='Enter interactive mode after executing command') help='Enter interactive mode after executing command')
parser.add_argument('-v', '--verbose', action='store_true', parser.add_argument('-v', '--verbose', action='store_true',
help='Display detailed debug information') help='Display detailed debug information including serial data hex dumps')
args = parser.parse_args() args = parser.parse_args()