Rtos API example

Committer:
marcozecchini
Date:
Sat Feb 23 12:13:36 2019 +0000
Revision:
0:9fca2b23d0ba
final commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
marcozecchini 0:9fca2b23d0ba 1 """
marcozecchini 0:9fca2b23d0ba 2 Realtek Semiconductor Corp.
marcozecchini 0:9fca2b23d0ba 3
marcozecchini 0:9fca2b23d0ba 4 RTL8195A elf2bin script
marcozecchini 0:9fca2b23d0ba 5 """
marcozecchini 0:9fca2b23d0ba 6
marcozecchini 0:9fca2b23d0ba 7 import sys, array, struct, os, re, subprocess
marcozecchini 0:9fca2b23d0ba 8 import hashlib
marcozecchini 0:9fca2b23d0ba 9 import shutil
marcozecchini 0:9fca2b23d0ba 10
marcozecchini 0:9fca2b23d0ba 11 from tools.paths import TOOLS_BOOTLOADERS
marcozecchini 0:9fca2b23d0ba 12 from tools.toolchains import TOOLCHAIN_PATHS
marcozecchini 0:9fca2b23d0ba 13 from datetime import datetime
marcozecchini 0:9fca2b23d0ba 14
marcozecchini 0:9fca2b23d0ba 15 # Constant Variables
marcozecchini 0:9fca2b23d0ba 16 RAM2_RSVD = 0x00000000
marcozecchini 0:9fca2b23d0ba 17 RAM2_VER = 0x8195FFFF00000000
marcozecchini 0:9fca2b23d0ba 18 RAM2_TAG = 0x81950001
marcozecchini 0:9fca2b23d0ba 19 RAM2_SHA = '0'
marcozecchini 0:9fca2b23d0ba 20
marcozecchini 0:9fca2b23d0ba 21 def write_fixed_width_string(value, width, output):
marcozecchini 0:9fca2b23d0ba 22 # cut string to list & reverse
marcozecchini 0:9fca2b23d0ba 23 line = [value[i:i+2] for i in range(0, len(value), 2)]
marcozecchini 0:9fca2b23d0ba 24 output.write("".join([chr(long(b, 16)) for b in line]))
marcozecchini 0:9fca2b23d0ba 25
marcozecchini 0:9fca2b23d0ba 26 def write_fixed_width_value(value, width, output):
marcozecchini 0:9fca2b23d0ba 27 # convert to string
marcozecchini 0:9fca2b23d0ba 28 line = format(value, '0%dx' % (width))
marcozecchini 0:9fca2b23d0ba 29 if len(line) > width:
marcozecchini 0:9fca2b23d0ba 30 print "[ERROR] value 0x%s cannot fit width %d" % (line, width)
marcozecchini 0:9fca2b23d0ba 31 sys.exit(-1)
marcozecchini 0:9fca2b23d0ba 32 # cut string to list & reverse
marcozecchini 0:9fca2b23d0ba 33 line = [line[i:i+2] for i in range(0, len(line), 2)]
marcozecchini 0:9fca2b23d0ba 34 line.reverse()
marcozecchini 0:9fca2b23d0ba 35 # convert to write buffer
marcozecchini 0:9fca2b23d0ba 36 output.write("".join([chr(long(b, 16)) for b in line]))
marcozecchini 0:9fca2b23d0ba 37
marcozecchini 0:9fca2b23d0ba 38 def append_image_file(image, output):
marcozecchini 0:9fca2b23d0ba 39 input = open(image, "rb")
marcozecchini 0:9fca2b23d0ba 40 output.write(input.read())
marcozecchini 0:9fca2b23d0ba 41 input.close()
marcozecchini 0:9fca2b23d0ba 42
marcozecchini 0:9fca2b23d0ba 43 def write_padding_bytes(output_name, size):
marcozecchini 0:9fca2b23d0ba 44 current_size = os.stat(output_name).st_size
marcozecchini 0:9fca2b23d0ba 45 padcount = size - current_size
marcozecchini 0:9fca2b23d0ba 46 if padcount < 0:
marcozecchini 0:9fca2b23d0ba 47 print "[ERROR] image is larger than expected size"
marcozecchini 0:9fca2b23d0ba 48 sys.exit(-1)
marcozecchini 0:9fca2b23d0ba 49 output = open(output_name, "ab")
marcozecchini 0:9fca2b23d0ba 50 output.write('\377' * padcount)
marcozecchini 0:9fca2b23d0ba 51 output.close()
marcozecchini 0:9fca2b23d0ba 52
marcozecchini 0:9fca2b23d0ba 53 def sha256_checksum(filename, block_size=65536):
marcozecchini 0:9fca2b23d0ba 54 sha256 = hashlib.sha256()
marcozecchini 0:9fca2b23d0ba 55 with open(filename, 'rb') as f:
marcozecchini 0:9fca2b23d0ba 56 for block in iter(lambda: f.read(block_size), b''):
marcozecchini 0:9fca2b23d0ba 57 sha256.update(block)
marcozecchini 0:9fca2b23d0ba 58 return sha256.hexdigest()
marcozecchini 0:9fca2b23d0ba 59
marcozecchini 0:9fca2b23d0ba 60 def get_version_by_time():
marcozecchini 0:9fca2b23d0ba 61 secs = int((datetime.now()-datetime(2016,11,1)).total_seconds())
marcozecchini 0:9fca2b23d0ba 62 return RAM2_VER + secs
marcozecchini 0:9fca2b23d0ba 63
marcozecchini 0:9fca2b23d0ba 64 # ----------------------------
marcozecchini 0:9fca2b23d0ba 65 # main function
marcozecchini 0:9fca2b23d0ba 66 # ----------------------------
marcozecchini 0:9fca2b23d0ba 67 def prepend(image, entry, segment, image_ram2, image_ota):
marcozecchini 0:9fca2b23d0ba 68
marcozecchini 0:9fca2b23d0ba 69 # parse input arguments
marcozecchini 0:9fca2b23d0ba 70 output = open(image_ram2, "wb")
marcozecchini 0:9fca2b23d0ba 71
marcozecchini 0:9fca2b23d0ba 72 write_fixed_width_value(os.stat(image).st_size, 8, output)
marcozecchini 0:9fca2b23d0ba 73 write_fixed_width_value(int(entry), 8, output)
marcozecchini 0:9fca2b23d0ba 74 write_fixed_width_value(int(segment), 8, output)
marcozecchini 0:9fca2b23d0ba 75
marcozecchini 0:9fca2b23d0ba 76 RAM2_SHA = sha256_checksum(image)
marcozecchini 0:9fca2b23d0ba 77 write_fixed_width_value(RAM2_TAG, 8, output)
marcozecchini 0:9fca2b23d0ba 78 write_fixed_width_value(get_version_by_time(), 16, output)
marcozecchini 0:9fca2b23d0ba 79 write_fixed_width_string(RAM2_SHA, 64, output)
marcozecchini 0:9fca2b23d0ba 80 write_fixed_width_value(RAM2_RSVD, 8, output)
marcozecchini 0:9fca2b23d0ba 81
marcozecchini 0:9fca2b23d0ba 82 append_image_file(image, output)
marcozecchini 0:9fca2b23d0ba 83 output.close()
marcozecchini 0:9fca2b23d0ba 84
marcozecchini 0:9fca2b23d0ba 85 ota = open(image_ota, "wb")
marcozecchini 0:9fca2b23d0ba 86 write_fixed_width_value(os.stat(image).st_size, 8, ota)
marcozecchini 0:9fca2b23d0ba 87 write_fixed_width_value(int(entry), 8, ota)
marcozecchini 0:9fca2b23d0ba 88 write_fixed_width_value(int(segment), 8, ota)
marcozecchini 0:9fca2b23d0ba 89 write_fixed_width_value(0xFFFFFFFF, 8, ota)
marcozecchini 0:9fca2b23d0ba 90 write_fixed_width_value(get_version_by_time(), 16, ota)
marcozecchini 0:9fca2b23d0ba 91 write_fixed_width_string(RAM2_SHA, 64, ota)
marcozecchini 0:9fca2b23d0ba 92 write_fixed_width_value(RAM2_RSVD, 8, ota)
marcozecchini 0:9fca2b23d0ba 93
marcozecchini 0:9fca2b23d0ba 94 append_image_file(image, ota)
marcozecchini 0:9fca2b23d0ba 95 ota.close()
marcozecchini 0:9fca2b23d0ba 96
marcozecchini 0:9fca2b23d0ba 97 def find_symbol(toolchain, mapfile, symbol):
marcozecchini 0:9fca2b23d0ba 98 ret = None
marcozecchini 0:9fca2b23d0ba 99
marcozecchini 0:9fca2b23d0ba 100 HEX = '0x0{,8}(?P<addr>[0-9A-Fa-f]{8})'
marcozecchini 0:9fca2b23d0ba 101 if toolchain == "GCC_ARM":
marcozecchini 0:9fca2b23d0ba 102 SYM = re.compile(r'^\s+' + HEX + r'\s+' + symbol + '\r?$')
marcozecchini 0:9fca2b23d0ba 103 elif toolchain in ["ARM_STD", "ARM", "ARM_MICRO"]:
marcozecchini 0:9fca2b23d0ba 104 SYM = re.compile(r'^\s+' + HEX + r'\s+0x[0-9A-Fa-f]{8}\s+Code.*\s+i\.' + symbol + r'\s+.*$')
marcozecchini 0:9fca2b23d0ba 105 elif toolchain == "IAR":
marcozecchini 0:9fca2b23d0ba 106 SYM = re.compile(r'^' + symbol + r'\s+' + HEX + '\s+.*$')
marcozecchini 0:9fca2b23d0ba 107
marcozecchini 0:9fca2b23d0ba 108 with open(mapfile, 'r') as infile:
marcozecchini 0:9fca2b23d0ba 109 for line in infile:
marcozecchini 0:9fca2b23d0ba 110 match = re.match(SYM, line)
marcozecchini 0:9fca2b23d0ba 111 if match:
marcozecchini 0:9fca2b23d0ba 112 ret = match.group("addr")
marcozecchini 0:9fca2b23d0ba 113
marcozecchini 0:9fca2b23d0ba 114 if not ret:
marcozecchini 0:9fca2b23d0ba 115 print "[ERROR] cannot find the address of symbol " + symbol
marcozecchini 0:9fca2b23d0ba 116 return 0
marcozecchini 0:9fca2b23d0ba 117
marcozecchini 0:9fca2b23d0ba 118 return int(ret,16) | 1
marcozecchini 0:9fca2b23d0ba 119
marcozecchini 0:9fca2b23d0ba 120 def parse_load_segment_gcc(image_elf):
marcozecchini 0:9fca2b23d0ba 121 # Program Headers:
marcozecchini 0:9fca2b23d0ba 122 # Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
marcozecchini 0:9fca2b23d0ba 123 # LOAD 0x000034 0x10006000 0x10006000 0x026bc 0x026bc RW 0x8
marcozecchini 0:9fca2b23d0ba 124 # LOAD 0x0026f0 0x30000000 0x30000000 0x06338 0x06338 RWE 0x4
marcozecchini 0:9fca2b23d0ba 125 segment_list = []
marcozecchini 0:9fca2b23d0ba 126 cmd = os.path.join(TOOLCHAIN_PATHS['GCC_ARM'], 'arm-none-eabi-readelf')
marcozecchini 0:9fca2b23d0ba 127 cmd = '"' + cmd + '"' + ' -l ' + image_elf
marcozecchini 0:9fca2b23d0ba 128 for line in subprocess.check_output(cmd, shell=True, universal_newlines=True).split("\n"):
marcozecchini 0:9fca2b23d0ba 129 if not line.startswith(" LOAD"):
marcozecchini 0:9fca2b23d0ba 130 continue
marcozecchini 0:9fca2b23d0ba 131 segment = line.split()
marcozecchini 0:9fca2b23d0ba 132 if len(segment) != 8:
marcozecchini 0:9fca2b23d0ba 133 continue
marcozecchini 0:9fca2b23d0ba 134 offset = int(segment[1][2:], 16)
marcozecchini 0:9fca2b23d0ba 135 addr = int(segment[2][2:], 16)
marcozecchini 0:9fca2b23d0ba 136 size = int(segment[4][2:], 16)
marcozecchini 0:9fca2b23d0ba 137 if addr != 0 and size != 0:
marcozecchini 0:9fca2b23d0ba 138 segment_list.append((offset, addr, size))
marcozecchini 0:9fca2b23d0ba 139 return segment_list
marcozecchini 0:9fca2b23d0ba 140
marcozecchini 0:9fca2b23d0ba 141 def parse_load_segment_armcc(image_elf):
marcozecchini 0:9fca2b23d0ba 142 # ====================================
marcozecchini 0:9fca2b23d0ba 143 #
marcozecchini 0:9fca2b23d0ba 144 # ** Program header #2
marcozecchini 0:9fca2b23d0ba 145 #
marcozecchini 0:9fca2b23d0ba 146 # Type : PT_LOAD (1)
marcozecchini 0:9fca2b23d0ba 147 # File Offset : 52 (0x34)
marcozecchini 0:9fca2b23d0ba 148 # Virtual Addr : 0x30000000
marcozecchini 0:9fca2b23d0ba 149 # Physical Addr : 0x30000000
marcozecchini 0:9fca2b23d0ba 150 # Size in file : 27260 bytes (0x6a7c)
marcozecchini 0:9fca2b23d0ba 151 # Size in memory: 42168 bytes (0xa4b8)
marcozecchini 0:9fca2b23d0ba 152 # Flags : PF_X + PF_W + PF_R + PF_ARM_ENTRY (0x80000007)
marcozecchini 0:9fca2b23d0ba 153 # Alignment : 8
marcozecchini 0:9fca2b23d0ba 154 #
marcozecchini 0:9fca2b23d0ba 155 (offset, addr, size) = (0, 0, 0)
marcozecchini 0:9fca2b23d0ba 156 segment_list = []
marcozecchini 0:9fca2b23d0ba 157 in_segment = False
marcozecchini 0:9fca2b23d0ba 158 cmd = os.path.join(TOOLCHAIN_PATHS['ARM'], 'bin', 'fromelf')
marcozecchini 0:9fca2b23d0ba 159 cmd = '"' + cmd + '"' + ' --text -v --only=none ' + image_elf
marcozecchini 0:9fca2b23d0ba 160 for line in subprocess.check_output(cmd, shell=True, universal_newlines=True).split("\n"):
marcozecchini 0:9fca2b23d0ba 161 if line == "":
marcozecchini 0:9fca2b23d0ba 162 pass
marcozecchini 0:9fca2b23d0ba 163 elif line.startswith("** Program header"):
marcozecchini 0:9fca2b23d0ba 164 in_segment = True
marcozecchini 0:9fca2b23d0ba 165 elif in_segment == False:
marcozecchini 0:9fca2b23d0ba 166 pass
marcozecchini 0:9fca2b23d0ba 167 elif line.startswith("============"):
marcozecchini 0:9fca2b23d0ba 168 if addr != 0 and size != 0:
marcozecchini 0:9fca2b23d0ba 169 segment_list.append((offset, addr, size))
marcozecchini 0:9fca2b23d0ba 170 in_segment = False
marcozecchini 0:9fca2b23d0ba 171 (offset, addr, size) = (0, 0, 0)
marcozecchini 0:9fca2b23d0ba 172 elif line.startswith(" Type"):
marcozecchini 0:9fca2b23d0ba 173 if not re.match(r'\s+Type\s+:\s+PT_LOAD\s.*$', line):
marcozecchini 0:9fca2b23d0ba 174 in_segment = False
marcozecchini 0:9fca2b23d0ba 175 elif line.startswith(" File Offset"):
marcozecchini 0:9fca2b23d0ba 176 match = re.match(r'^\s+File Offset\s+:\s+(?P<offset>\d+).*$', line)
marcozecchini 0:9fca2b23d0ba 177 if match:
marcozecchini 0:9fca2b23d0ba 178 offset = int(match.group("offset"))
marcozecchini 0:9fca2b23d0ba 179 elif line.startswith(" Virtual Addr"):
marcozecchini 0:9fca2b23d0ba 180 match = re.match(r'^\s+Virtual Addr\s+:\s+0x(?P<addr>[0-9a-f]+).*$', line)
marcozecchini 0:9fca2b23d0ba 181 if match:
marcozecchini 0:9fca2b23d0ba 182 addr = int(match.group("addr"), 16)
marcozecchini 0:9fca2b23d0ba 183 elif line.startswith(" Size in file"):
marcozecchini 0:9fca2b23d0ba 184 match = re.match(r'^\s+Size in file\s+:.*\(0x(?P<size>[0-9a-f]+)\).*$', line)
marcozecchini 0:9fca2b23d0ba 185 if match:
marcozecchini 0:9fca2b23d0ba 186 size = int(match.group("size"), 16)
marcozecchini 0:9fca2b23d0ba 187 return segment_list
marcozecchini 0:9fca2b23d0ba 188
marcozecchini 0:9fca2b23d0ba 189
marcozecchini 0:9fca2b23d0ba 190 def parse_load_segment_iar(image_elf):
marcozecchini 0:9fca2b23d0ba 191 # SEGMENTS:
marcozecchini 0:9fca2b23d0ba 192 #
marcozecchini 0:9fca2b23d0ba 193 # Type Offset Virtual Physical File Sz Mem Sz Flags Align
marcozecchini 0:9fca2b23d0ba 194 # ---- ------ ------- -------- ------- ------ ----- -----
marcozecchini 0:9fca2b23d0ba 195 # 0: load 0x34 0x10006000 0x10006000 0x26bc 0x26bc 0x6 WR 0x8
marcozecchini 0:9fca2b23d0ba 196 # 1: load 0x26f0 0x30000000 0x30000000 0x6338 0x6338 0x7 XWR 0x4
marcozecchini 0:9fca2b23d0ba 197 #
marcozecchini 0:9fca2b23d0ba 198 # SECTIONS:
marcozecchini 0:9fca2b23d0ba 199 #
marcozecchini 0:9fca2b23d0ba 200 # Name Type Addr Offset Size Aln Lnk Inf ESz Flags
marcozecchini 0:9fca2b23d0ba 201 # ---- ---- ---- ------ ---- --- --- --- --- -----
marcozecchini 0:9fca2b23d0ba 202 # 1: .shstrtab strtab 0xfc4d8 0x60 0x4
marcozecchini 0:9fca2b23d0ba 203 # 2: .strtab strtab 0xfc538 0xbb3f 0x4
marcozecchini 0:9fca2b23d0ba 204
marcozecchini 0:9fca2b23d0ba 205 segment_list = []
marcozecchini 0:9fca2b23d0ba 206 in_segment = False
marcozecchini 0:9fca2b23d0ba 207 cmd = os.path.join(TOOLCHAIN_PATHS['IAR'], 'bin', 'ielfdumparm')
marcozecchini 0:9fca2b23d0ba 208 cmd = '"' + cmd + '"' + ' ' + image_elf
marcozecchini 0:9fca2b23d0ba 209 for line in subprocess.check_output(cmd, shell=True, universal_newlines=True).split("\n"):
marcozecchini 0:9fca2b23d0ba 210 if line.startswith(" SEGMENTS:"):
marcozecchini 0:9fca2b23d0ba 211 in_segment = True
marcozecchini 0:9fca2b23d0ba 212 elif in_segment == False:
marcozecchini 0:9fca2b23d0ba 213 pass
marcozecchini 0:9fca2b23d0ba 214 elif line.startswith(" SECTIONS:"):
marcozecchini 0:9fca2b23d0ba 215 break
marcozecchini 0:9fca2b23d0ba 216 elif re.match(r'^\s+\w+:\s+load\s+.*$', line):
marcozecchini 0:9fca2b23d0ba 217 segment = line.split()
marcozecchini 0:9fca2b23d0ba 218 offset = int(segment[2][2:], 16)
marcozecchini 0:9fca2b23d0ba 219 addr = int(segment[3][2:], 16)
marcozecchini 0:9fca2b23d0ba 220 size = int(segment[5][2:], 16)
marcozecchini 0:9fca2b23d0ba 221 if addr < 0x10007000:
marcozecchini 0:9fca2b23d0ba 222 continue
marcozecchini 0:9fca2b23d0ba 223 if addr != 0 and size != 0:
marcozecchini 0:9fca2b23d0ba 224 segment_list.append((offset, addr, size))
marcozecchini 0:9fca2b23d0ba 225 return segment_list
marcozecchini 0:9fca2b23d0ba 226
marcozecchini 0:9fca2b23d0ba 227 def parse_load_segment(toolchain, image_elf):
marcozecchini 0:9fca2b23d0ba 228 if toolchain == "GCC_ARM":
marcozecchini 0:9fca2b23d0ba 229 return parse_load_segment_gcc(image_elf)
marcozecchini 0:9fca2b23d0ba 230 elif toolchain in ["ARM_STD", "ARM", "ARM_MICRO"]:
marcozecchini 0:9fca2b23d0ba 231 return parse_load_segment_armcc(image_elf)
marcozecchini 0:9fca2b23d0ba 232 elif toolchain == "IAR":
marcozecchini 0:9fca2b23d0ba 233 return parse_load_segment_iar(image_elf)
marcozecchini 0:9fca2b23d0ba 234 else:
marcozecchini 0:9fca2b23d0ba 235 return []
marcozecchini 0:9fca2b23d0ba 236
marcozecchini 0:9fca2b23d0ba 237 def write_load_segment(image_elf, image_bin, segment):
marcozecchini 0:9fca2b23d0ba 238 file_elf = open(image_elf, "rb")
marcozecchini 0:9fca2b23d0ba 239 file_bin = open(image_bin, "wb")
marcozecchini 0:9fca2b23d0ba 240 for (offset, addr, size) in segment:
marcozecchini 0:9fca2b23d0ba 241 file_elf.seek(offset)
marcozecchini 0:9fca2b23d0ba 242 # write image header - size & addr
marcozecchini 0:9fca2b23d0ba 243 write_fixed_width_value(addr, 8, file_bin)
marcozecchini 0:9fca2b23d0ba 244 write_fixed_width_value(size, 8, file_bin)
marcozecchini 0:9fca2b23d0ba 245 # write load segment
marcozecchini 0:9fca2b23d0ba 246 file_bin.write(file_elf.read(size))
marcozecchini 0:9fca2b23d0ba 247 delta = size % 4
marcozecchini 0:9fca2b23d0ba 248 if delta != 0:
marcozecchini 0:9fca2b23d0ba 249 padding = 4 - delta
marcozecchini 0:9fca2b23d0ba 250 write_fixed_width_value(0x0, padding * 2, file_bin)
marcozecchini 0:9fca2b23d0ba 251 file_bin.close()
marcozecchini 0:9fca2b23d0ba 252 file_elf.close()
marcozecchini 0:9fca2b23d0ba 253
marcozecchini 0:9fca2b23d0ba 254 # ----------------------------
marcozecchini 0:9fca2b23d0ba 255 # main function
marcozecchini 0:9fca2b23d0ba 256 # ----------------------------
marcozecchini 0:9fca2b23d0ba 257 def rtl8195a_elf2bin(t_self, image_elf, image_bin):
marcozecchini 0:9fca2b23d0ba 258 # remove target binary file/path
marcozecchini 0:9fca2b23d0ba 259 if os.path.isfile(image_bin):
marcozecchini 0:9fca2b23d0ba 260 os.remove(image_bin)
marcozecchini 0:9fca2b23d0ba 261 else:
marcozecchini 0:9fca2b23d0ba 262 shutil.rmtree(image_bin)
marcozecchini 0:9fca2b23d0ba 263
marcozecchini 0:9fca2b23d0ba 264 segment = parse_load_segment(t_self.name, image_elf)
marcozecchini 0:9fca2b23d0ba 265 write_load_segment(image_elf, image_bin, segment)
marcozecchini 0:9fca2b23d0ba 266
marcozecchini 0:9fca2b23d0ba 267 image_name = os.path.splitext(image_elf)[0]
marcozecchini 0:9fca2b23d0ba 268 image_map = image_name + '.map'
marcozecchini 0:9fca2b23d0ba 269
marcozecchini 0:9fca2b23d0ba 270 ram2_ent = find_symbol(t_self.name, image_map, "PLAT_Start")
marcozecchini 0:9fca2b23d0ba 271 ram1_bin = os.path.join(TOOLS_BOOTLOADERS, "REALTEK_RTL8195AM", "ram_1.bin")
marcozecchini 0:9fca2b23d0ba 272 ram2_bin = image_name + '-ram_2.bin'
marcozecchini 0:9fca2b23d0ba 273 ota_bin = image_name + '-ota.bin'
marcozecchini 0:9fca2b23d0ba 274 prepend(image_bin, ram2_ent, len(segment), ram2_bin, ota_bin)
marcozecchini 0:9fca2b23d0ba 275
marcozecchini 0:9fca2b23d0ba 276 # write output file
marcozecchini 0:9fca2b23d0ba 277 output = open(image_bin, "wb")
marcozecchini 0:9fca2b23d0ba 278 append_image_file(ram1_bin, output)
marcozecchini 0:9fca2b23d0ba 279 append_image_file(ram2_bin, output)
marcozecchini 0:9fca2b23d0ba 280 output.close()