stm8loader add exec
This commit is contained in:
2
Makefile
2
Makefile
@@ -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.
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user