diff options
Diffstat (limited to 'firmware/zpu/bin')
| -rwxr-xr-x | firmware/zpu/bin/bin_to_mif.py | 29 | ||||
| -rwxr-xr-x | firmware/zpu/bin/bin_to_ram_macro_init.py | 39 | ||||
| -rwxr-xr-x | firmware/zpu/bin/divisors.py | 34 | ||||
| -rwxr-xr-x | firmware/zpu/bin/elf_to_sbf | 142 | ||||
| -rwxr-xr-x | firmware/zpu/bin/sbf.py | 134 | ||||
| -rwxr-xr-x | firmware/zpu/bin/serial_loader | 363 | ||||
| -rwxr-xr-x | firmware/zpu/bin/uart_ihex_flash_loader.py | 138 | ||||
| -rwxr-xr-x | firmware/zpu/bin/uart_ihex_ram_loader.py | 70 | 
8 files changed, 949 insertions, 0 deletions
| diff --git a/firmware/zpu/bin/bin_to_mif.py b/firmware/zpu/bin/bin_to_mif.py new file mode 100755 index 000000000..cefce4e92 --- /dev/null +++ b/firmware/zpu/bin/bin_to_mif.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +import struct +import sys + +hextab = ('0000', '0001', '0010', '0011', +          '0100', '0101', '0110', '0111', +          '1000', '1001', '1010', '1011', +          '1100', '1101', '1110', '1111') + +def w_to_binary_ascii(w): +    return ''.join([hextab[(w >> 4*i) & 0xf] for i in range(7,-1,-1)]) + +def bin_to_mif(bin_input_file, mif_output_file): +    ifile = open(bin_input_file, 'rb') +    ofile = open(mif_output_file, 'w') +    idata = ifile.read() +    fmt = ">%dI" % ((len(idata) / 4),) +    words = struct.unpack(fmt, idata) +    for w in words: +        ofile.write(w_to_binary_ascii(w)) +        ofile.write('\n') + +if __name__ == '__main__': +    if len(sys.argv) != 3: +        sys.stderr.write("usage: bin_to_mif bin_input_file mif_output_file\n") +        raise SystemExit, 1 +     +    bin_to_mif(sys.argv[1], sys.argv[2]) diff --git a/firmware/zpu/bin/bin_to_ram_macro_init.py b/firmware/zpu/bin/bin_to_ram_macro_init.py new file mode 100755 index 000000000..bf8abb19a --- /dev/null +++ b/firmware/zpu/bin/bin_to_ram_macro_init.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +import struct +import sys + +BOOTRAM_SIZE = 16384 + +def do_8_words(ofile, which_ram, row, words): +    ofile.write("defparam bootram.RAM%d.INIT_%02X=256'h" % (which_ram, row)) +    ofile.write("%08x_%08x_%08x_%08x_%08x_%08x_%08x_%08x;\n" % ( +        words[7], words[6], words[5], words[4], words[3], words[2], words[1], words[0])) + +def bin_to_ram_macro_init(bin_input_file, ram_init_output_file): +    ifile = open(bin_input_file, 'rb') +    ofile = open(ram_init_output_file, 'w') +    idata = ifile.read() +    idata_words = len(idata) / 4 +    fmt = ">%dI"%idata_words +    words = struct.unpack(fmt, idata[:idata_words*4]) + +    # pad to a multiple of 8 words +    r = len(words) % 8 +    if r != 0: +        words += (8 - r) * (0,) + +    if len(words) > (BOOTRAM_SIZE / 4): +        sys.stderr.write("bin_to_macro_init: error: input file %s is > %dKiB\n" % (bin_input_file,BOOTRAM_SIZE)) +        sys.exit(1) + +    for q in range(0, BOOTRAM_SIZE/4, 512): +        for i in range(q, min(q+512, len(words)), 8): +            do_8_words(ofile, int(q / 512), (i/8) % 64, words[i:i+8]) + +if __name__ == '__main__': +    if len(sys.argv) != 3: +        sys.stderr.write("usage: bin_to_ram_macro_init bin_input_file ram_init_output_file\n") +        sys.exit(1) +     +    bin_to_ram_macro_init(sys.argv[1], sys.argv[2]) diff --git a/firmware/zpu/bin/divisors.py b/firmware/zpu/bin/divisors.py new file mode 100755 index 000000000..d31bd4dad --- /dev/null +++ b/firmware/zpu/bin/divisors.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +speeds = (9600, 19200, 38400, 57600, 115200, 230400) + +master_clk = 100e6 +wb_clk = master_clk / 2 + +def divisor(speed): +    div0 = wb_clk // (speed * 16) +    div1 = div0 + 1 +    actual0 = actual_speed(div0) +    actual1 = actual_speed(div1) +    if abs(actual0 - speed) < abs(actual1 - speed): +        return div0 +    else: +        return div1 + +def actual_speed(divisor): +    return (wb_clk // divisor) / 16 + +def doit(speed): +    div = divisor(speed) +    actual = actual_speed(div) +    rel_error = (actual - speed) / speed +    print "target: %6d  divisor: %6d  actual: %11.4f  %6.3f%%" % (speed, div, actual, rel_error*100) + +def main(): +    print "wb_clk = %f" % (wb_clk,) +    for s in speeds: +        doit(s) + +if __name__ == '__main__': +    main() +     diff --git a/firmware/zpu/bin/elf_to_sbf b/firmware/zpu/bin/elf_to_sbf new file mode 100755 index 000000000..d1be10c0d --- /dev/null +++ b/firmware/zpu/bin/elf_to_sbf @@ -0,0 +1,142 @@ +#!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +import sys +import struct +from optparse import OptionParser +from pprint import pprint + +import sbf + +# see /usr/include/elf.h for the various magic values + + +_ehdr_fmt = ">16sHH5I6H" +_ehdr_fmt_size = struct.calcsize(_ehdr_fmt) +_phdr_fmt = ">8I" +_phdr_fmt_size = struct.calcsize(_phdr_fmt) + +class elf32_ehdr(object): +    def __init__(self, s): +        (self.ident, self.type, self.machine, self.version, self.entry, +         self.phoff, self.shoff, self.flags, self.ehsize, +         self.phentsize, self.phnum, self.shentsize, self.shnum, +         self.shstrndx) = struct.unpack(_ehdr_fmt, s) + +class elf32_phdr(object): +    def __init__(self, s): +        (self.type, self.offset, self.vaddr, self.paddr, +         self.filesz, self.memsz, +         self.flags, self.align) = struct.unpack(_phdr_fmt, s) + +    def __repr__(self): +        return "<elf32_phdr %s offset=%d paddr=0x%x, filesz=%d>" % ( +            p_type_str(self.type), self.offset, self.paddr, self.filesz) + + +def p_type_str(t): +    if t <= 8: +        return ('NULL', 'LOAD', 'DYNAMIC', 'INTERP', 'NOTE', 'SHLIB', 'PHDR', 'TLS', 'NUM')[t] +    return "0x%x" % (t,) + + + +def _get_ehdr(f): +    if len(f) < _ehdr_fmt_size: +        return False +    ehdr = elf32_ehdr(f[0:_ehdr_fmt_size]) +    return ehdr + +     +def elf32_big_endian_exec_p(f): +    ehdr = _get_ehdr(f) +    if not ehdr: +        return False +     +    #pprint(ehdr, sys.stderr) +    e_ident = ehdr.ident +    if not e_ident.startswith('\177ELF'): +        return False +    if (ord(e_ident[4]) != 1            # EI_CLASS == CLASS32 +        or ord(e_ident[5]) != 2         # EI_DATA == DATA2MSB +        or ord(e_ident[6]) != 1         # EI_VERSION == EV_CURRENT +        ): +        return False + +    if ehdr.type != 2:                  # e_type == ET_EXEC +        return False + +    return True + + + +# return (entry, (phdr, ...)) + +def get_elf32_prog_headers(f): +    ehdr = _get_ehdr(f) +    entry = ehdr.entry +    phoff = ehdr.phoff +    phentsize = ehdr.phentsize +    phnum = ehdr.phnum + +    def extract(i): +        start = phoff + i * phentsize +        end = start + phentsize +        return f[start:end] +     +    return (entry, [elf32_phdr(extract(i)) for i in range(phnum)]) +     + +def main(): +    usage = "%prog: [options] elf_file" +    parser = OptionParser() +    parser.add_option("-o", "--output", default=None, +                      help="specify output filename [default=stdout]") +    (options, args) = parser.parse_args() +    if len(args) != 1: +        parser.print_help() +        sys.exit(1) + +    elf_file = open(args[0], 'rb') + +    elf_contents = elf_file.read() +    if not elf32_big_endian_exec_p(elf_contents): +        sys.stderr.write("%s: not a big-endian 32-bit ELF executable\n" % (args[0],)) +        sys.exit(1) +         +    if options.output is None: +        sbf_file = sys.stdout +    else: +        sbf_file = open(options.output, 'wb') + +    (entry, phdrs) = get_elf32_prog_headers(elf_contents) +    #pprint(phdrs, sys.stderr) + +    def phdr_to_sec_desc(phdr): +        target_addr = phdr.paddr +        data = elf_contents[phdr.offset:phdr.offset+phdr.filesz] +        #print >>sys.stderr, "pdhr_to_sec_desc:", (target_addr, data) +        return sbf.sec_desc(target_addr, data) + +    sections = map(phdr_to_sec_desc, phdrs) +    # pprint(sections, sys.stderr) +    sbf.write_sbf(sbf_file, sbf.header(entry, sections)) + + +if __name__ == '__main__': +    main() diff --git a/firmware/zpu/bin/sbf.py b/firmware/zpu/bin/sbf.py new file mode 100755 index 000000000..8e2c868a5 --- /dev/null +++ b/firmware/zpu/bin/sbf.py @@ -0,0 +1,134 @@ +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +_SBF_MAGIC = 'SBF!' +_SBF_DONT_EXECUTE = 0x1 +_SBF_MAX_SECTIONS = 14 +_SBF_HEADER_LEN = 128 + +import struct +import sys +from pprint import pprint + +def dump_data(f, offset, data): +    L = len(data) // 4 +    for i in range(L): +        f.write('%08x:  %08x\n' % (offset + 4 * i, struct.unpack('>I', data[4*i:4*(i+1)])[0])) +    remainder = len(data) - L * 4 +    if remainder != 0: +        f.write('%08x:  ' % (offset + L*4,)) +        i = 0 +        while i < remainder: +            f.write('%02x' % ((ord(data[L*4 + i]),))) +            i += 1 +        f.write('\n') + + + +class sec_desc(object): +    def __init__(self, target_addr, data): +        self.target_addr = target_addr +        self.data = data + +    def __repr__(self): +        #print >>sys.stderr, "target_addr:", self.target_addr +        #print >>sys.stderr, "data:", self.data +        return "<sec_desc target_addr=0x%x len=%d>" % ( +            self.target_addr, len(self.data)) + + +class header(object): +    def __init__(self, entry, sections): +        self.entry = entry +        self.section = sections + +    def dump(self, f): +        if self.entry == _SBF_DONT_EXECUTE: +            f.write("Entry: DONT_EXECUTE\n") +        else: +            f.write("Entry: 0x%x\n" % (self.entry,)) +        for i in range(len(self.section)): +            s = self.section[i] +            f.write("Section[%d]: target_addr = 0x%x  length = %d\n" % (i, +                                                                        s.target_addr, +                                                                        len(s.data))) +            dump_data(f, s.target_addr, s.data) + +    # +    # Returns an iterator.  Each yield returns (target_addr, data) +    # +    def iterator(self, max_piece=512): +        for s in self.section: +            offset = 0 +            L = len(s.data) +            while offset < L: +                n = min(max_piece, L - offset) +                yield (s.target_addr + offset, +                       s.data[offset:offset+n]) +                offset += n + + + +def read_sbf(input_file): +    """Parse an SBF file""" +     +    f = input_file.read(_SBF_HEADER_LEN) +    #if len(f) < _SBF_HEADER_LEN or not f.startswith(_SBF_MAGIC): +        #raise ValueError, '%s: not an SBF file' % (input_file.name,) +     +    def extract(i): +        start = 16+8*i +        stop = start+8 +        return struct.unpack('>2I', f[start:stop]) + +    def get_data(ss): +        L = ss[1] +        s = input_file.read(L) +        #if len(s) != L: +            #raise ValueError, '%s: file is too short' % (input_file.name(),) +        return s +         +    (magic, entry, nsections, reserved) = struct.unpack('>4s3I', f[0:16]) +    assert nsections <= _SBF_MAX_SECTIONS +    descs = [extract(i) for i in range(nsections)] +    #pprint(descs, sys.stderr) +    data = map(get_data, descs) +    secs = map(lambda ss, data: sec_desc(ss[0], data), descs, data) +    return header(entry, secs) + + +def write_sbf(output_file, sbf_header): +    assert(len(sbf_header.section) <= _SBF_MAX_SECTIONS) +    sbf_header.nsections = len(sbf_header.section) +    f = output_file + +    # write the file header +    f.write(struct.pack('>4s3I', _SBF_MAGIC, sbf_header.entry, sbf_header.nsections, 0)) + +    # write the section headers +    for i in range(sbf_header.nsections): +        f.write(struct.pack('>2I',  +                            sbf_header.section[i].target_addr, +                            len(sbf_header.section[i].data))) +    for i in range(_SBF_MAX_SECTIONS - sbf_header.nsections): +        f.write(struct.pack('>2I', 0, 0)) + +    # write the section data +    for i in range(sbf_header.nsections): +        f.write(sbf_header.section[i].data) + +    return True diff --git a/firmware/zpu/bin/serial_loader b/firmware/zpu/bin/serial_loader new file mode 100755 index 000000000..9bd5aada7 --- /dev/null +++ b/firmware/zpu/bin/serial_loader @@ -0,0 +1,363 @@ +#!/usr/bin/env python +# +# Copyright 2009 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +import termios +import tty +import os +import sys +import threading +import Queue +from optparse import OptionParser +import time + +import sbf + +GDB_ESCAPE = chr(0x7d) + +# Indexes for termios list. +IFLAG = 0 +OFLAG = 1 +CFLAG = 2 +LFLAG = 3 +ISPEED = 4 +OSPEED = 5 +CC = 6 + +class terminal(object): +    def __init__(self, device, speed_bits): +        fd = os.open(device, os.O_RDWR) +        if not os.isatty(fd): +            raise ValueError(device + " is not a tty") + +        self.read_file = os.fdopen(fd, "rb", 0) +        self.write_file = os.fdopen(os.dup(fd), "wb", 0) +        self.old_attrs = termios.tcgetattr(self.write_file.fileno()) +        #print "old_attrs: ", self.old_attrs +        attrs = list(self.old_attrs)    # copy of attributes +        attrs[ISPEED] = speed_bits      # set input and output speed +        attrs[OSPEED] = speed_bits +        termios.tcsetattr(self.write_file.fileno(), termios.TCSAFLUSH, attrs) +        tty.setraw(self.write_file.fileno())     # enable raw mode +        attrs = termios.tcgetattr(self.write_file.fileno()) +        attrs[CC][termios.VMIN] = 1     # minimim of 1 char +        attrs[CC][termios.VTIME] = 1    # wait no longer than 1/10 +        termios.tcsetattr(self.write_file.fileno(), termios.TCSAFLUSH, attrs) + +    def __del__(self): +        termios.tcsetattr(self.write_file.fileno(), termios.TCSAFLUSH, self.old_attrs) +        self.read_file.close() +        self.write_file.close() + +    def read(self, n): +        """Read at most n bytes from tty""" +        return self.read_file.read(n) + +    def write(self, str): +        """Write str to tty.""" +        return self.write_file.write(str) + + +def hexnibble(i): +    return "0123456789abcdef"[i & 0xf] + +def build_pkt(payload): +    s = ['$'] +    checksum = 0 + +    for p in payload: +        if p in ('$', '#', GDB_ESCAPE): +            s.append(GDB_ESCAPE) +        s.append(p) +        checksum += ord(p) + +    checksum &= 0xff +    s.append('#') +    s.append(hexnibble(checksum >> 4)) +    s.append(hexnibble(checksum)) + +    return ''.join(s) + + +def build_memory_read_pkt(addr, len): +    return build_pkt(('m%x,%x' % (addr, len))) + +def build_memory_write_hex_pkt(addr, s): +    hexdata = ''.join(["%02x" % (ord(c),) for c in s]) +    return build_pkt(('M%x,%x:' % (addr, len(s))) + hexdata) + +def build_memory_write_pkt(addr, s): +    return build_pkt(('X%x,%x:' % (addr, len(s))) + s) + +def build_goto_pkt(addr): +    return build_pkt(('c%x' % (addr,))) + + +def get_packet(f): +    """Return a valid packet, or None on EOF or timeout""" +    LOOKING_FOR_DOLLAR = 0 +    LOOKING_FOR_HASH = 1 +    CSUM1 = 2 +    CSUM2 = 3 + +    fd = f.fileno() +     +    state = LOOKING_FOR_DOLLAR +    buf = [] + +    while True: +        ch = os.read(fd, 1) +        sys.stdout.write(ch) +        if len(ch) == 0: +            print("Returning None") +            return(None) +         +        if state == LOOKING_FOR_DOLLAR: +            if ch == '$': +                buf = [] +                state = LOOKING_FOR_HASH +            elif ch == '#': +                state = LOOKING_FOR_DOLLAR + +        elif state == LOOKING_FOR_HASH: +            if ch == '$': +                state = LOOKING_FOR_DOLLAR +            elif ch == '#': +                state = CSUM1 +            else: +                if ch == GDB_ESCAPE: +                    ch = getc() +                buf.append(ch) + +        elif state == CSUM1: +            chksum1 = ch +            state = CSUM2 + +        elif state == CSUM2: +            chksum2 = ch +            r = ''.join(buf) +            if chksum1 == '.' and chksum2 == '.': +                return r + +            expected_checksum = int(chksum1 + chksum2, 16) +            checksum = 0 +            for c in buf: +                checksum += ord(c) + +            checksum &= 0xff +            if checksum == expected_checksum: +                return r + +            state = LOOKING_FOR_DOLLAR + +        else: +            raise ValueError( "Invalid state") + + +class packet_reader_thread(threading.Thread): +    def __init__(self, tty_in, q): +        threading.Thread.__init__(self) +        self.setDaemon(1) +        self.tty_in = tty_in +        self.q = q +        self._keep_running = True +        self.start() + +    def run(self): +        while self._keep_running == True: +            p = get_packet(self.tty_in) +            if p is not None: +                self.q.put(('pkt', p)) + + +def _make_tr_table(): +    table = [] +    for c in range(256): +        if c < ord(' ') or c > ord('~'): +            table.append('.') +        else: +            table.append(chr(c)) +    return ''.join(table) +         + +class controller(object): +    def __init__(self, tty): +        self.tty = tty +        self.q = Queue.Queue(0) +        self.timers = {} +        self.next_tid = 1 +        self.current_tid = 0 +        self.ntimeouts = 0 +        self.packet_reader = packet_reader_thread(tty.read_file, self.q) +        self.state = None +        self.debug = False +        self.tt = _make_tr_table() + +        self.done = False +        self.addr = None +        self.bits = None + +    def shutdown(self): +        self.packet_reader._keep_running = False + +    def start_timeout(self, timeout_in_secs): +        def callback(tid): +            if self.timers.has_key(tid): +                del self.timers[tid] +            self.q.put(('timeout', tid)) +        self.next_tid += 1 +        tid = self.next_tid +        timer = threading.Timer(timeout_in_secs, callback, (tid,)) +        self.timers[tid] = timer +        timer.start() +        return tid + +    def cancel_timeout(self, tid): +        if self.timers.has_key(tid): +            self.timers[tid].cancel() +            del self.timers[tid] + +    def send_packet(self, pkt): +        if self.debug: +            if len(pkt) > 64: +                s = pkt[0:64] + '...' +            else: +                s = pkt +            sys.stdout.write('-> ' +  s.translate(self.tt) + '\n') +        self.tty.write(pkt); + +    def send_packet_start_timeout(self, pkt, secs): +        self.send_packet(pkt) +        self.current_tid = self.start_timeout(secs) +         +    def upload_code(self, sbf): +        MAX_PIECE = 512                 # biggest piece to send +        MWRITE_TIMEOUT = 0.1 + +        IDLE = 0 +        WAIT_FOR_ACK = 1 +        UPLOAD_DONE = 2 +        DONE = 3 +        FAILED = 4 + +        self.done = False +        it = sbf.iterator(MAX_PIECE) +        entry_addr = sbf.entry + +        def get_next_bits(): +            try: +                (self.addr, self.bits) = it.next() +            except StopIteration: +                self.done = True +             +        def is_done(): +            return self.done +         +        def send_piece(): +            pkt = build_memory_write_pkt(self.addr, self.bits) +            #pkt = build_memory_write_hex_pkt(self.addr, self.bits) +            self.send_packet_start_timeout(pkt, MWRITE_TIMEOUT) +            state = WAIT_FOR_ACK + +        def advance(): +            get_next_bits() +            if is_done(): +                self.state = DONE +                self.send_packet(build_goto_pkt(entry_addr)) +                 +            else: +                self.ntimeouts = 0 +                send_piece() + +        get_next_bits() +        if is_done():                   # empty file +            return True +         +        send_piece()                    # initial transition +         +        while 1: +            (event, value) = self.q.get() + +            if event == 'timeout' and value == self.current_tid: +                self.ntimeouts += 1 +                if self.ntimeouts >= 5: +                    return False        # say we failed +                send_piece()            # resend +                 + +            elif event == 'pkt': +                if value == 'OK': +                    self.cancel_timeout(self.current_tid) +                    advance() +                    if self.state == DONE: +                        return True +                else: +                    print("Error returned from firmware: " + value) +                    return False + +            else: +                print("Unknown event:", (event, value)) + +def main(): +    usage="%prog: [options] filename" +    parser = OptionParser(usage=usage) +    parser.add_option("-t", "--tty", type="string", default="/dev/ttyS0", +                      help="select serial port [default=%default]") + +    (options, args) = parser.parse_args() +    if len(args) != 1: +        parser.print_help() +        raise SystemExit(1) + + +    filename = args[0] +    f = open(filename, "rb") +    try: +        # Try to open the file as an SBF file +        sbf_header = sbf.read_sbf(f) +    except: +        # If that fails, build an SBF from the binary, assuming default +        # load address and entry point +        f.seek(0) +        t = f.read() +        if t.startswith('\177ELF'): +            sys.stderr.write("Can't load an ELF file.  Please use an SBF file instead.\n") +            raise SystemExit( 1) +        sbf_header = sbf.header(0x8000, [sbf.sec_desc(0x8000, t)]) +         + +    tty = terminal(options.tty, termios.B115200) +    ctrl = controller(tty) +    ok = ctrl.upload_code(sbf_header) +     +    if ok: +        print("OK") +        try: +            raw_input("Press Enter to exit: ") +        except KeyboardInterrupt: +            pass +        ctrl.shutdown() +        time.sleep(0.2) +         +    else: +        print("Upload failed") +        ctrl.shutdown() +     +     +     +if __name__ == "__main__": +    main() diff --git a/firmware/zpu/bin/uart_ihex_flash_loader.py b/firmware/zpu/bin/uart_ihex_flash_loader.py new file mode 100755 index 000000000..5a3300f34 --- /dev/null +++ b/firmware/zpu/bin/uart_ihex_flash_loader.py @@ -0,0 +1,138 @@ +#!/usr/bin/python + +import serial +from optparse import OptionParser +import os, sys + +#TODO: pull everything but parser out of main() and put it in a separate function we can call from another script. lets us automate loading RAM+FLASH to produce a fully-loaded image. +#TODO: make it fail gracefully -- if it gets a NOK or times out, do at least one retry. +#TODO: put hooks in (eventually) to allow verifying a firmware image so the user can more safely update the "safe" image +#TODO: how about a progress indicator? FPGA images take FOREVER. you can use wc -l to get the number of lines, or do it with file i/o. + +def main(): +	usage="%prog: [options] filename" +	parser = OptionParser(usage=usage) +	parser.add_option("-t", "--tty", type="string", default="/dev/ttyUSB0", +                     help="select serial port [default=%default]") +	parser.add_option("-b", "--baudrate", type=int, default=115200, +										 help="set baudrate [default=%default]") +	parser.add_option("-F", "--write-safe-firmware", action="store_const", const=1, dest="image", +										 help="write to safe firmware image") +	parser.add_option("-f", "--write-production-firmware", action="store_const", const=2, dest="image", +										 help="write to production firmware image") +	parser.add_option("-P", "--write-safe-fpga", action="store_const", const=3, dest="image", +										 help="write to safe FPGA image") +	parser.add_option("-p", "--write-production-fpga", action="store_const", const=4, dest="image", +										 help="write to production FPGA image") + +	(options, args) = parser.parse_args() + +	if(options.image is None): +		print("At least one of -f, -F, -p, -P must be specified.\n") +		parser.print_help() +		raise SystemExit(1) +	 +	if len(args) != 1: +		parser.print_help() +		raise SystemExit(1) + +	if(options.image == 3): +		print "Are you *really* sure you want to write to the failsafe FPGA image? If you mess this up your USRP2+ will become a brick. Press 'y' to continue, any other key to abort." +		if(raw_input().rstrip() is not "y"): +			print "Good choice." +			raise SystemExit(0) + +	elif(options.image == 1): +		print "Are you *really* sure you want to write to the failsafe firmware image? If you mess this up your USRP2+ will only be able to be reprogrammed via the UART RAM loader.\nPress 'y' to continue, any other key to abort." +		if(raw_input().rstrip() is not "y"): +			print "Good choice." +			raise SystemExit(0) + +	filename = args[0] +	f = open(filename, "r") + +	#now we start doing things... +	if(os.path.exists(options.tty) is False): +		sys.stderr.write("No serial port found at %s\n" % options.tty) +		raise SystemExit(1) +	 +	try: +		ser = serial.Serial(port=options.tty, timeout=1, baudrate=options.baudrate, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, rtscts=0, xonxoff=0) +	except serial.SerialException: +		sys.stderr.write("Unable to open serial port\n") +		raise SystemExit(1) + +	ser.open() + +#test to see if a valid USRP2+ in flash load mode is connected +	ser.write("garbage\n") +	ser.readline() +	ser.write("!SECTORSIZE\n") +	reply = ser.readline().rstrip() +	if("NOK" in reply): +		sys.stderr.write("Error writing to USRP2+. Try again.\n") +		raise SystemExit(1) +	elif("OK" in reply): +		sectorsize = int(reply[3:5], 16) +		print("USRP2+ found with sector size %i. Erasing old image." % 2**sectorsize) +	else: +		sys.stderr.write("Invalid response or no USRP2+ connected.\n") +		raise SystemExit(1) + +	if(options.image == 1): +		sectors = range(127, 128) +		runcmd = "!RUNSFD\n" +	elif(options.image == 2): +		sectors = range(64, 65) +		runcmd = "!RUNPFD\n" +	elif(options.image == 3): +		sectors = range(0,32) +		runcmd = "!RUNSFPGA\n" +	elif(options.image == 4): +		sectors = range(32,64) +		runcmd = "!RUNPFPGA\n" + +	writeaddr = sectors[0] << sectorsize +	if(options.image < 3): +		writeaddr -= 0x8000 #i know this is awkward, but we subtract 0x8000 from the address for firmware loads. the reason we do this is that the IHX files are located at 0x8000 (RAM_BASE), and +												#doing this here allows us to use the same IHX files for RAM load as for Flash load, without relocating in objcopy or relinking with another ld script. +												#this limits us to writing above 32K for our firmware images. since the safe FPGA image located at 0x00000000 takes up 2MB of space this isn't really a worry. +												#FPGA images (.mcs) always start at 0x00000000 so they don't need this relocation. + +	for sector in sectors: +		print "Erasing sector %i" % sector +		ser.write("!ERASE %i\n" % sector) +		reply = ser.readline() +		if("NOK" in reply): +			sys.stderr.write("Error erasing sector %i" % sector) +			raise SystemExit(1) +	 +	print "Setting start address to %i" % writeaddr +	ser.write("!SETADDR %i\n" % writeaddr) +	if("NOK" in reply): +		sys.stderr.write("Error setting address\n") +		raise SystemExit(1) +	else: +		print reply + + +	for line in f: +		ser.write(line.rstrip()+'\n') +		reply = ser.readline() +		if("NOK" in reply): #TODO: simplify this logic, use (reply.rstrip() is "NOK") +			print("Received NOK reply during data write") +			raise SystemExit(1) +		elif("DONE" in reply): +			print("Finished writing program. Loading...\n") +			ser.write(runcmd) +		elif("OK" not in reply): +			print("Received invalid reply %s during data write" % reply) +			raise SystemExit(1) +		else: +			print reply.rstrip() + '\t' + line.rstrip() + +	print ser.readline() + + +if __name__ == '__main__': +	main() diff --git a/firmware/zpu/bin/uart_ihex_ram_loader.py b/firmware/zpu/bin/uart_ihex_ram_loader.py new file mode 100755 index 000000000..c90fbe1d8 --- /dev/null +++ b/firmware/zpu/bin/uart_ihex_ram_loader.py @@ -0,0 +1,70 @@ +#!/usr/bin/python + +import serial +from optparse import OptionParser +import os, sys + +def main(): +	usage="%prog: [options] filename" +	parser = OptionParser(usage=usage) +	parser.add_option("-t", "--tty", type="string", default="/dev/ttyUSB0", +                     help="select serial port [default=%default]") +	parser.add_option("-b", "--baudrate", type=int, default=115200, +										 help="set baudrate [default=%default]") + +	(options, args) = parser.parse_args() +	if len(args) != 1: +		parser.print_help() +		raise SystemExit(1) + +	filename = args[0] +	f = open(filename, "r") + +	#all we have to do is load the IHX file and attempt to spit it out to the serial port. +	if(os.path.exists(options.tty) is False): +		sys.stderr.write("No serial port found at %s\n" % options.tty) +		raise SystemExit(1) +	 +	try: +		ser = serial.Serial(port=options.tty, timeout=1, baudrate=options.baudrate, bytesize=8, parity=serial.PARITY_NONE, stopbits=1, rtscts=0, xonxoff=0) +	except serial.SerialException: +		sys.stderr.write("Unable to open serial port\n") +		raise SystemExit(1) + +	ser.open() + +#test to see if a valid USRP2+ in RAM load mode is connected + +	ser.write("WOOOOO\n"); +	reply = ser.readline() +	if("NOK" not in reply): +		sys.stderr.write("Valid USRP2+ not connected or no response received\n") +		raise SystemExit(1) +	else: +		print("USRP2+ found.") + +	for line in f: +		ser.write(line.rstrip() + '\n') +		reply = ser.readline() +		if("NOK" in reply): #blocks to wait for response +			print("Received NOK reply from USRP2+") +			raise SystemExit(1) +		elif("OK" not in reply): +			print("Received invalid reply!") +			raise SystemExit(1) +#		else: +#			print("OK received") + +	print "USRP2+ RAM programmed.\nLoading program." + +	#at this point it should have sent the end line of the file, which starts the program! +	#we'll just act like a dumb terminal now +#	ser.timeout = 0 +#	try: +#		while 1: +#			print ser.readline() +#	except KeyboardInterrupt: +#		raise SystemExit(0) + +if __name__ == '__main__': +	main() | 
