従来に公開していたSHマイコンのフラッシュライターでは、Windows7以降の環境やUbuntu18以降の環境では動作しないケースがありました。
このような環境でも動作するように新規にPython3でフラッシュライターを開発しました。

対象となるマイコンは、SH3/SH4/SH4A、SH7084、SH7216、SH7124となっており、Ubuntu21とWIndows10で動作確認をしました。

import serial
import sys
import os
import struct
from sys import exit

BIT_RATE_SET_MAX = 256
BIT_SET_RES = 0xaa
BIT_RATE_SET_MAX_INTER = 30
BIT_SET_RES_INTER = 0xe6
BIT_SET_RES_NG = 0xff
BIT_SET_CODE = 0x00
BIT_SET_CHECK = 0x55
BIT_SET_FIN = 0x00
QUERY_DEV_CMD = 0x20
QUERY_DEV_RES = 0x30
QUERY_DEV_SIZE = 4
SELECT_DEV_CMD = 0x10
SELECT_DEV_RES = 0x06
SELECT_DEV_ERROR_RES = 0x90
SELECT_DEV_ERROR_SUM = 0x11
SELECT_DEV_ERROR_CODE = 0x21
QUERY_CLOCK_CMD = 0x21
QUERY_CLOCK_RES = 0x31
SELECT_CLOCK_CMD = 0x11
SELECT_CLOCK_RES = 0x06
SELECT_CLOCK_ERROR_RES = 0x91
SELECT_CLOCK_ERROR_SUM = 0x11
SELECT_CLOCK_ERROR_MODE = 0x22
SELECT_CLOCK_SIZE = 1
SELECT_CLOCK_MODE0 = 0
SELECT_CLOCK_MODE1 = 1
QUERY_SCALE_CMD = 0x22
QUERY_SCALE_RES = 0x32
QUERY_FREQ_CMD = 0x23
QUERY_FREQ_RES = 0x33
QUERY_PAGE_SIZE_CMD = 0x27
QUERY_PAGE_SIZE_RES = 0x37
SET_RATE_CMD = 0x3f
SET_RATE_RES = 0x06
SET_RATE_ERROR_RES = 0xbf
SET_RATE_ERROR_SUM = 0x11
SET_RATE_ERROR_RATE = 0x24
SET_RATE_ERROR_NEW_FREQ = 0x25
SET_RATE_ERROR_PLL = 0x26
SET_RATE_ERROR_FREQ = 0x27
SET_RATE_CHECK_CMD = 0x06
SET_RATE_SIZE = 7
QUERY_AREA_CMD = 0x25
QUERY_AREA_RES = 0x35
SWITCH_TO_ERASE_CMD = 0x40
SELECT_WRITE_FORMAT = 0x43
QUERY_ERROR_RES	= 0x80
NON_ERROR_RES = 0x06
WRITE_CMD = 0x50
WRITE_ERROR_ADDRESS = 0x2a
WRITE_ERROR_WRITE = 0x53

argc = len(sys.argv)
if argc >= 3:
	if sys.argv[1] != '-p':
		argc = 1
if argc < 4:
	print('Usage: flush -p port file')
	exit()
filename = sys.argv[argc - 1]
port = sys.argv[2]
osc = 0
baud = 19200
if not os.path.isfile(filename):
	print('File not found.\n')
try:
	ser = serial.Serial(port, baud, timeout=0.05)
except:
	print('Serial port not found\n')
	exit()
for i in range(10):
	for j in range(BIT_RATE_SET_MAX_INTER):
		ser.write(b'\x00')
	c = ser.read()
	if c != b'':
		break
if c != b'\x00':
	ser.close()
	ser = serial.Serial(port, 115200, timeout=0.2)
	for i in range(8):
		ser.write(b'\x5a')
		c = ser.read()
		if c != b'':
			break
	if i == 7:
		print('Serial port not found')
		exit()
	for i in range(255):
		c1 = struct.pack('B', i)
		if c1 != B'E':
			ser.write(c1)
			c2 = ser.read()
			if c1 != c2:
				print('Serial port not found')
				exit()
	cpu = 'SH3/4/4A'
	flushsize = 0x80000
	pagesize = 256
	ser.timeout = 5
	ser.write(b'E')
	c = ser.read()
	print('CPU is', cpu)
	print('Flush erase', end='', flush=True)
	while c != b'S':
		c = ser.read()
		if c == b'.':
			print('.', end='', flush=True)
		if c != b'S' and c != b'.':
			print('Flush earse fail')
			exit()
	print('.', flush=True)
else:
	ser.write(struct.pack('B', BIT_SET_CHECK))
	while True:
		stat = int.from_bytes(ser.read(),'big')
		if stat == BIT_SET_RES_NG:
			print('Bit set check error')
			exit()
		if stat == BIT_SET_RES_INTER:
			break
	ser.write(struct.pack('B', QUERY_DEV_CMD))
	stat = int.from_bytes(ser.read(),'big')
	sum1 = stat
	if stat != QUERY_DEV_RES:
		print('Query device error')
		exit()
	size = int.from_bytes(ser.read(),'big')
	sum1 = sum1 + size
	devnum = int.from_bytes(ser.read(),'big')
	sum1 = sum1 + devnum
	status = bytearray(size - 1)
	for i in range(size - 1):
		status[i] = int.from_bytes(ser.read(),'big')
		sum1 = sum1 + status[i]
	sum1 = sum1 + int.from_bytes(ser.read(),'big')
	sum1 = sum1 % 0x100
	if sum1 != 0:
		print('Query device error')
		exit()
	devcode = bytearray(QUERY_DEV_SIZE)
	for i in range(QUERY_DEV_SIZE):
		devcode[i] = status[i + 1]
	length = status[0] - QUERY_DEV_SIZE;
	devname = bytearray(length)
	for i in range(length):
		devname[i] = status[i + QUERY_DEV_SIZE + 1]
	cpu = devname.decode()
	if cpu == 'R5F7084':
		if osc == 0:
			osc = 1000
	elif cpu == 'R5F7216':
		if osc == 0:
			osc = 1200
	elif cpu == 'R5F7124':
		if osc == 0:
			osc = 1250
	else:
		print('This is a unknown cpu')
		exit()
	print('CPU is', cpu)
	c = SELECT_DEV_CMD
	sum1 = c
	ser.write(struct.pack('B', c))
	c = QUERY_DEV_SIZE
	sum1 = sum1 + c
	ser.write(struct.pack('B', c))
	for i in range(QUERY_DEV_SIZE):
		c = devcode[i]
		ser.write(struct.pack('B', c))
		sum1 = sum1 + c
	sum1 = sum1 % 0x100
	sum1 = (0x100 - sum1) % 0x100
	ser.write(struct.pack('B', sum1))
	c = int.from_bytes(ser.read(),'big')
	if c != SELECT_DEV_RES:
		print('Select device error')
		exit()
	ser.write(struct.pack('B', QUERY_CLOCK_CMD))
	c = int.from_bytes(ser.read(),'big')
	sum1 = c;
	if c != QUERY_CLOCK_RES:
		print('Query clock error')
		exit()
	size = int.from_bytes(ser.read(),'big')
	sum1 = sum1 + size
	status = bytearray(size)
	for i in range(size):
		status[i] = int.from_bytes(ser.read(),'big')
		sum1 = sum1 + status[i];
	sum1 = sum1 + int.from_bytes(ser.read(),'big')
	sum1 = sum1 % 0x100
	if sum1 != 0:
		print('Query clock error')
		exit()
	c = SELECT_CLOCK_CMD
	sum1 = c;
	ser.write(struct.pack('B', c))
	c = SELECT_CLOCK_SIZE
	sum1 = sum1 + c
	ser.write(struct.pack('B', c))
	if cpu == 'R5F7216':
		c = SELECT_CLOCK_MODE1
	else:
		c = SELECT_CLOCK_MODE0
	sum1 = sum1 + c;
	ser.write(struct.pack('B', c))
	sum1 = sum1 % 0x100
	sum1 = (0x100 - sum1) % 0x100
	ser.write(struct.pack('B', sum1))
	c = int.from_bytes(ser.read(),'big')
	if c != SELECT_CLOCK_RES:
		print('Select clock error')
		exit()
	gain = 6
	speed = baud * gain
	bitrate = speed // 100
	c = SET_RATE_CMD
	sum1 = c
	ser.write(struct.pack('B', c))
	c = SET_RATE_SIZE
	sum1 = sum1 + c
	ser.write(struct.pack('B', c))
	c = bitrate // 0x100
	sum1 = sum1 + c
	ser.write(struct.pack('B', c))
	c = bitrate % 0x100
	sum1 = sum1 + c
	ser.write(struct.pack('B', c))
	c = osc // 0x100
	sum1 = sum1 + c
	ser.write(struct.pack('B', c))
	c = osc % 0x100
	sum1 = sum1 + c;
	ser.write(struct.pack('B', c))
	pll = bytearray(3)
	if cpu == 'R5F7084':
		pll[0] = 2
		pll[1] = 4
		pll[2] = 4
	elif cpu == 'R5F7216':
		pll[0] = 2
		pll[1] = 8
		pll[2] = 4
	elif cpu == 'R5F7124':
		pll[0] = 2
		pll[1] = 4
		pll[2] = 2
	for i in range(3):
		c = pll[i]
		sum1 = sum1 + c
		ser.write(struct.pack('B', c))
	sum1 = sum1 % 0x100
	sum1 = (0x100 - sum1) % 0x100
	ser.write(struct.pack('B', sum1))
	c = int.from_bytes(ser.read(),'big')
	if c != SET_RATE_RES:
		c = int.from_bytes(ser.read(),'big')
		if c == SET_RATE_ERROR_SUM:
			print('Set rate checksum error')
		elif c == SET_RATE_ERROR_RATE:
			print('Set rate speed error')
		elif c == SET_RATE_ERROR_NEW_FREQ:
			print('Set rate new freq error')
		elif c == SET_RATE_ERROR_PLL:
			print('Set rate pll error')
		elif c == SET_RATE_ERROR_FREQ:
			print('Set rate new freq error')
		else:
			print('Set rate unknown error')
		exit()
	ser.close()
	ser = serial.Serial(port, speed, timeout=0.05)
	ser.write(struct.pack('B', SET_RATE_CHECK_CMD))
	c = int.from_bytes(ser.read(),'big')
	if c != NON_ERROR_RES:
		print('Set rate clock error')
		exit()
	ser.write(struct.pack('B', QUERY_AREA_CMD))
	c = int.from_bytes(ser.read(),'big')
	sum1 = c;
	if c != QUERY_AREA_RES:
		print('Query area error')
		exit()
	size = int.from_bytes(ser.read(),'big')
	sum1 = sum1 + size
	num = int.from_bytes(ser.read(),'big')
	sum1 = sum1 + num
	saddr = list(range(num))
	taddr = list(range(num))
	for i in range(num):
		saddr[i] = 0
		for j in range(4):
			c = int.from_bytes(ser.read(),'big')
			sum1 = sum1 + c
			saddr[i] = saddr[i] * 0x100
			saddr[i] = saddr[i] + c
		taddr[i] = 0
		for j in range(4):
			c = int.from_bytes(ser.read(),'big')
			sum1 = sum1 + c;
			taddr[i] = taddr[i] * 0x100
			taddr[i] = taddr[i] + c
	sum1 = sum1 % 0x100
	sum1 = (0x100 - sum1) % 0x100
	c = int.from_bytes(ser.read(),'big')
	if sum1 != c:
		print('Query area error')
		exit()
	flushsize = taddr[0] + 1;
	ser.write(struct.pack('B', QUERY_PAGE_SIZE_CMD))
	c = int.from_bytes(ser.read(),'big')
	sum1 = c
	if c != QUERY_PAGE_SIZE_RES:
		print('Query page size error')
		exit()
	size = int.from_bytes(ser.read(),'big')
	sum1 = sum1 + size;
	pagesize = 0;
	for i in range(size):
		c = int.from_bytes(ser.read(),'big')
		sum1 = sum1 + c;
		pagesize = pagesize * 0x100;
		pagesize = pagesize + c;
	sum1 = sum1 % 0x100
	sum1 = (0x100 - sum1) % 0x100
	c = int.from_bytes(ser.read(),'big')
	if sum1 != c:
		print('Query page size error')
		exit()
	print('Flush erase', flush=True)
	ser.timeout = 5
	ser.write(struct.pack('B', SWITCH_TO_ERASE_CMD))
	c = int.from_bytes(ser.read(),'big')
	if c != NON_ERROR_RES:
		print('Switch to erase error')
		exit()
	ser.timeout = 0.05
	ser.write(struct.pack('B', SELECT_WRITE_FORMAT))
	c = int.from_bytes(ser.read(),'big')
	if c != NON_ERROR_RES:
		print('Select write format error')
		exit()
print('Flush write ready')
buff = bytearray(flushsize)
for i in range(flushsize):
	buff[i] = 255
verify = bytearray(pagesize)
nopgm = bytearray(pagesize)
for i in range(pagesize):
	nopgm[i] = 255
with open(filename) as f:
	while True:
		s_line = f.readline()
		if not s_line:
			break
		s_line = s_line.replace('\n','')
		if s_line[0] != 'S':
			print('File format error')
			f.close()
			exit()
		linesize = int(s_line[2:4],16)
		length2 = linesize * 2 + 4
		length1 = len(s_line)
		if length1 != length2:
			print('File format error')
			f.close()
			exit()
		addrsize = (int(s_line[1:2],16) + 1) * 2
		if addrsize >= 4 and addrsize <= 8:
			address = int(s_line[4:addrsize + 4], 16)
			datasize = linesize - (addrsize // 2) - 1
			data = s_line[addrsize + 4:addrsize + 4 + datasize * 2]
			if (address + datasize) > flushsize:
				print('Flush address is overflow')
				f.close()
				exit()
			for i in range(datasize):
				buff[address + i] = int(data[i * 2:i * 2 + 2], 16)
f.close()
count = 0;
for address in range(0, flushsize, pagesize):
	for i in range(pagesize):
		if buff[address + i] != 255:
			break
	if i < (pagesize - 1):
		if cpu == 'SH3/4/4A':
			ser.writetimeout = 0.24
			c2 = struct.pack('B',(address // 0x10000) % 0x100)
			ser.write(c2)
			c1 = struct.pack('B',(address // 0x100) % 0x100)
			ser.write(c1)
			ser.write(buff[address:address+pagesize])
			verify = ser.read(pagesize)
			c = ser.read()
			if c != b'S':
				print(c, 'Flush write error')
				exit()
			if buff[address:address+pagesize] != verify:
				print(address, 'Verify error')
				exit()
		else:
			c = WRITE_CMD;
			ser.write(struct.pack('B', c))
			sum1 = c
			ser.write(b'\x00')
			c = (address // 0x10000) % 0x100
			ser.write(struct.pack('B', c))
			sum1 = sum1 + c;
			c = (address // 0x100) % 0x100
			ser.write(struct.pack('B', c))
			sum1 = sum1 + c;
			c = address % 0x100
			ser.write(struct.pack('B', c))
			sum1 = sum1 + c;
			for j in range(pagesize):
				c = buff[address + j]
				ser.write(struct.pack('B', c))
				sum1 = sum1 + c;
			sum1 = sum1 % 0x100
			sum1 = (0x100 - sum1) % 0x100
			ser.write(struct.pack('B', sum1))
			c = int.from_bytes(ser.read(),'big')
			if c != NON_ERROR_RES:
				c = int.from_bytes(ser.read(),'big')
				print('Flush write error')
				exit()
	count = count + 1
	if (count % 10) == 0:
		print('.', end='', flush=True)
	if (count % 800) == 0:
		print('\n', end='', flush=True)

ser.close()
print('\nFlush write complete')